[llvm-commits] [llvm] r155464 - in /llvm/trunk/include/llvm: CRSBuilder.h ConstantRangesSet.h

Stepan Dyatkovskiy stpworld at narod.ru
Tue Apr 24 11:31:10 PDT 2012


Author: dyatkovskiy
Date: Tue Apr 24 13:31:10 2012
New Revision: 155464

URL: http://llvm.org/viewvc/llvm-project?rev=155464&view=rev
Log:
Related to PR1255. Let's begin. I'll commit classes that corresponds to our latest PR1255 discussion posts in llvm-commits.

Strategy.
0. Implement new classes. Classes doesn't affect anything. They still work with ConstantInt base values at this stage.
1. Fictitious replacement of current ConstantInt case values with ConstantRangesSet. Case ranges set will still hold single value, and ConstantInt *getCaseValue() will return it. But additionally implement new method in SwitchInst that allows to work with case ranges. Currenly I think it should be some wrapper that returns either single value or ConstantRangesSet object.
2. Step-by-step replacement of old "ConstantInt* getCaseValue()" with new alternative. Modify algorithms for all passes that works with SwitchInst. But don't modify LLParser and BitcodeReader/Writer. Still hold single value in each ConstantRangesSet object. On this stage some parts of LLVM will use old-style methods, and some ones new-style.
3. After all getCaseValue() usages will removed and whole LLVM and its clients will work in new style - modify LLParser, Reader and Writer. Remove getCaseValue().
4. Replace ConstantInt*-based case ranges set items with APInt ones.

Currently we are on Zero Stage: New classes.
ConstantRangesSet.
I selected ConstantArrays as case ranges set "holder" object (it is a temporary decision, I'll explain why below). The array items are may be ConstantVectors with single item, and ConstantVectors with two items (that means single number and range respectively).
The ConstantInt will used as basic value representation. It will replaced with APInt then. Of course ConstantArray and ConstantVector will go away after ConstantInt => APInt replacement.

New class mandatory features:
- bool isSatisfies(ConstantInt *V) method (need better name?). Returns true if the given value satisfies this case.
- Case's ranges and values enumeration. In some passes we need to analize each case (SwitchLowering for example).

Factory + unified clusterify.
I also propose to implement the factory that allows to build case object with user friendly way. I called it CRSBuilder by now.
Currenly I implemented the factory that allows add,remove pairs of range+successor. It also allows add existing ConstantRangesSet decompiling it to separated ranges. Factory can emit either clusters set (single case range + successor) or the set of "ConstantRangesSet + Successor" pairs.
So you can use it either as builder for new cases set for SwitchInst, or for clusterification of existing cases set.
Just call Factory.optimize() and it emits optimized and sorted clusters collection for you!
I tested clusterification on SelectionDAGBuilder - it works fine. Don't worry it was not included in this patch. Just new classes.
Factory is a template. There are two params: SuccessorClass and IsReadonly. So you can specify what successor you need (BB or MBB). And you can also restrict your factory to use values in read-only mode (SelectionDAGBuilder need IsReadonly=true). Read-only factory couldn't build the cases ranges.



Added:
    llvm/trunk/include/llvm/CRSBuilder.h
    llvm/trunk/include/llvm/ConstantRangesSet.h

Added: llvm/trunk/include/llvm/CRSBuilder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CRSBuilder.h?rev=155464&view=auto
==============================================================================
--- llvm/trunk/include/llvm/CRSBuilder.h (added)
+++ llvm/trunk/include/llvm/CRSBuilder.h Tue Apr 24 13:31:10 2012
@@ -0,0 +1,252 @@
+//===- CRSBuilder.h - ConstantRangesSet Builder -----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// @file
+/// CRSBuilder allows to build and parse ConstantRangesSet objects.
+/// There is such features like add/remove range, or combine
+/// Two ConstantRangesSet object with neighboring ranges merging.
+/// Set IsReadonly=true if you want to operate with "const ConstantInt" and
+/// "const ConstantRangesSet" objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CRSBUILDER_H_
+#define CRSBUILDER_H_
+
+#include "llvm/ConstantRangesSet.h"
+#include <list>
+#include <map>
+#include <vector>
+
+namespace llvm {
+
+template <class SuccessorClass, bool IsReadonly>
+class CRSBuilderBase {
+public:
+  
+  typedef ConstantRangesSet::RangeT<IsReadonly> RangeTy;
+  
+  struct RangeEx : public RangeTy {
+    typedef ConstantRangesSet::RangeT<IsReadonly> RangeTy;
+    typedef typename RangeTy::ConstantIntTy ConstantIntTy;
+    RangeEx() : Weight(1) {}
+    RangeEx(const RangeTy &R) : RangeTy(R.Low, R.High), Weight(1) {}
+    RangeEx(ConstantIntTy *C) : RangeTy(C), Weight(1) {}
+    RangeEx(ConstantIntTy *L, ConstantIntTy *H) : RangeTy(L, H), Weight(1) {}
+    RangeEx(ConstantIntTy *L, ConstantIntTy *H, unsigned W) :
+      RangeTy(L, H), Weight(W) {}
+    unsigned Weight;
+  };
+
+  typedef std::pair<RangeEx, SuccessorClass*> Cluster;
+
+protected:
+
+  typedef std::vector<Cluster> CaseItems;
+  typedef typename CaseItems::iterator CaseItemIt;
+  typedef typename CaseItems::const_iterator CaseItemConstIt;
+
+  struct ClustersCmp {
+    bool operator()(const Cluster &C1, const Cluster &C2) {
+      return C1.first < C2.first;
+    }
+  };
+  
+  CaseItems Items;
+  bool Sorted;
+  
+  bool isIntersected(CaseItemIt& LItem, CaseItemIt& RItem) {
+    return LItem->first.High->getValue().uge(RItem->first.Low->getValue());
+  }
+
+  bool isJoinable(CaseItemIt& LItem, CaseItemIt& RItem) {
+    if (LItem->second != RItem->second) {
+      assert(!isIntersected(LItem, RItem) &&
+             "Intersected items with different successors!");
+      return false;
+    }
+    APInt RLow = RItem->first.Low->getValue();
+    if (RLow != APInt::getNullValue(RLow.getBitWidth()))
+      --RLow;
+    return LItem->first.High->getValue().uge(RLow);
+  }
+  
+  void sort() {
+    if (!Sorted) {
+      std::sort(Items.begin(), Items.end(), ClustersCmp());
+      Sorted = true;
+    }
+  }
+  
+public:
+  
+  typedef typename CRSConstantTypes<IsReadonly>::ConstantIntTy ConstantIntTy;
+  typedef typename CRSConstantTypes<IsReadonly>::ConstantRangesSetTy ConstantRangesSetTy;
+  
+  // Don't public CaseItems itself. Don't allow edit the Items directly. 
+  // Just present the user way to iterate over the internal collection
+  // sharing iterator, begin() and end(). Editing should be controlled by
+  // factory.
+  typedef CaseItemIt RangeIterator;
+  
+  CRSBuilderBase() {
+    Items.reserve(32);
+    Sorted = false;
+  }
+  
+  bool verify() {
+    if (Items.empty())
+      return true;
+    sort();
+    for (CaseItemIt i = Items.begin(), j = i+1, e = Items.end();
+         j != e; i = j++) {
+      if (isIntersected(j, i) && j->second != i->second)
+        return false;
+    }
+    return true;
+  }
+  
+  void optimize() {
+    if (Items.size() < 2)
+      return;
+    sort();
+    CaseItems OldItems = Items;
+    Items.clear();
+    ConstantIntTy *Low = OldItems.begin()->first.Low;
+    ConstantIntTy *High = OldItems.begin()->first.High;
+    unsigned Weight = 1;
+    SuccessorClass *Successor = OldItems.begin()->second;
+    for (CaseItemIt i = OldItems.begin(), j = i+1, e = OldItems.end();
+        j != e; i = j++) {
+      if (isJoinable(i, j)) {
+        ConstantIntTy *CurHigh = j->first.High;
+        ++Weight;
+        if (CurHigh->getValue().ugt(High->getValue()))
+          High = CurHigh;
+      } else {
+        RangeEx R(Low, High, Weight);
+        add(R, Successor);
+        Low = j->first.Low;
+        High = j->first.High; 
+        Weight = 1;
+        Successor = j->second;
+      }
+    }
+    RangeEx R(Low, High, Weight);
+    add(R, Successor);
+    // We recollected the Items, but we kept it sorted.
+    Sorted = true;
+  }
+  
+  /// Adds a constant value.
+  void add(ConstantIntTy *C, SuccessorClass *S = 0) {
+    RangeTy R(C);
+    add(R, S);
+  }
+  
+  /// Adds a range.
+  void add(ConstantIntTy *Low, ConstantIntTy *High, SuccessorClass *S = 0) {
+    RangeTy R(Low, High);
+    add(R, S);
+  }
+  void add(RangeTy &R, SuccessorClass *S = 0) {
+    RangeEx REx = R;
+    add(REx, S);
+  }   
+  void add(RangeEx &R, SuccessorClass *S = 0) {
+    Items.push_back(std::make_pair(R, S));
+    Sorted = false;
+  }  
+  
+  /// Adds all ranges and values from given ranges set to the current
+  /// CRSBuilder object.
+  void add(ConstantRangesSetTy &CRS, SuccessorClass *S = 0) {
+    for (unsigned i = 0, e = CRS.getNumItems(); i < e; ++i) {
+      RangeTy R = CRS.getItem(i);
+      add(R, S);
+    }
+  }
+  
+  /// Removes items from set.
+  void removeItem(RangeIterator i) { Items.erase(i); }
+  
+  /// Returns true if there is no ranges and values inside.
+  bool empty() const { return Items.empty(); }
+  
+  RangeIterator begin() { return Items.begin(); }
+  RangeIterator end() { return Items.end(); }
+};
+
+template <class SuccessorClass>
+class CRSBuilderT : public CRSBuilderBase<SuccessorClass, false> {
+  
+  typedef typename CRSBuilderBase<SuccessorClass, false>::RangeTy RangeTy;
+  typedef typename CRSBuilderBase<SuccessorClass, false>::RangeIterator
+      RangeIterator;
+  
+  typedef std::list<RangeTy> RangesCollection;
+  typedef typename RangesCollection::iterator RangesCollectionIt;
+  
+  typedef std::map<SuccessorClass*, RangesCollection > CRSMap;
+  typedef typename CRSMap::iterator CRSMapIt;
+  
+  ConstantRangesSet getCase(RangesCollection& Src) {
+    std::vector<Constant*> Elts;
+    Elts.reserve(Src.size());
+    for (RangesCollectionIt i = Src.begin(), e = Src.end(); i != e; ++i) {
+      const RangeTy &R = *i;
+      std::vector<Constant*> r;
+      if (R.Low != R.High) {
+        r.reserve(2);
+        r.push_back(R.Low);
+        r.push_back(R.High);
+      } else {
+        r.reserve(1);
+        r.push_back(R.Low);
+      }
+      Constant *CV = ConstantVector::get(r);
+      Elts.push_back(CV);    
+    }
+    ArrayType *ArrTy =
+        ArrayType::get(Elts.front()->getType(), (uint64_t)Elts.size());
+    Constant *Array = ConstantArray::get(ArrTy, Elts);
+    return ConstantRangesSet(Array);     
+  }
+
+public:
+  
+  typedef std::pair<SuccessorClass*, ConstantRangesSet> Case;
+  typedef std::list<Case> Cases;
+  
+  /// Builds the finalized case objects.
+  void getCases(Cases& TheCases) {
+    CRSMap TheCRSMap;
+    for (RangeIterator i = this->begin(); i != this->end(); ++i)
+      TheCRSMap[i->second].push_back(i->first);
+    for (CRSMapIt i = TheCRSMap.begin(), e = TheCRSMap.end(); i != e; ++i)
+      TheCases.push_back(std::make_pair(i->first, getCase(i->second)));
+  }
+  
+  /// Builds the finalized case objects ignoring successor values, as though
+  /// all ranges belongs to the same successor.
+  ConstantRangesSet getCase() {
+    RangesCollection Ranges;
+    for (RangeIterator i = this->begin(); i != this->end(); ++i)
+      Ranges.push_back(i->first);
+    return getCase(Ranges);
+  }
+};
+
+class BasicBlock;
+typedef CRSBuilderT<BasicBlock> CRSBuilder;
+typedef CRSBuilderBase<BasicBlock, true> CRSBuilderConst;  
+
+}
+
+#endif /* CRSBUILDER_H_ */

Added: llvm/trunk/include/llvm/ConstantRangesSet.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ConstantRangesSet.h?rev=155464&view=auto
==============================================================================
--- llvm/trunk/include/llvm/ConstantRangesSet.h (added)
+++ llvm/trunk/include/llvm/ConstantRangesSet.h Tue Apr 24 13:31:10 2012
@@ -0,0 +1,272 @@
+//===-- llvm/ConstantRangesSet.h - The constant set of ranges ---*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// @file
+/// This file contains class that implements constant set of ranges:
+/// [<Low0,High0>,...,<LowN,HighN>]. Mainly, this set is used by SwitchInst and
+/// represents case value that may contain multiple ranges for a single
+/// successor.
+///
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CONSTANTRANGESSET_H_
+#define CONSTANTRANGESSET_H_
+
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+
+namespace llvm {
+  
+class ConstantRangesSet;  
+  
+template <bool IsReadonly> struct CRSConstantTypes {
+  typedef ConstantInt ConstantIntTy;
+  typedef ConstantRangesSet ConstantRangesSetTy;  
+};
+
+template <>
+struct CRSConstantTypes<true> {
+  typedef const ConstantInt ConstantIntTy;
+  typedef const ConstantRangesSet ConstantRangesSetTy;
+};  
+  
+//===----------------------------------------------------------------------===//
+/// ConstantRangesSet - class that implements constant set of ranges.
+/// It is a wrapper for some real "holder" class (currently ConstantArray).
+/// It contains functions, that allows to parse "holder" like a set of ranges.
+/// Note: It is assumed that "holder" is inherited from Constant object.
+///       ConstantRangesSet may be converted to and from Constant* pointer.
+///
+class ConstantRangesSet {
+  Constant *Array;
+public:
+  
+  // implicit
+  ConstantRangesSet(Constant *V) : Array(V) {}
+  
+  operator Constant*() { return Array; }
+  operator const Constant*() const { return Array; }
+  Constant *operator->() { return Array; }
+  const Constant *operator->() const { return Array; }
+   
+  template <bool IsReadonly>
+  struct RangeT {
+    
+    typedef typename CRSConstantTypes<IsReadonly>::ConstantIntTy ConstantIntTy;
+    typedef std::pair<RangeT, RangeT> SubRes;
+    
+    ConstantIntTy *Low;
+    ConstantIntTy *High;
+   
+    RangeT() : Low(0), High(0) {}
+    RangeT(const RangeT<false> &RHS) : Low(RHS.Low), High(RHS.High) {}
+    RangeT(ConstantIntTy *C) : Low(C), High(C) {}
+    RangeT(ConstantIntTy *L, ConstantIntTy *H) : Low(L), High(H) {}
+   
+    bool operator<(const RangeT &RHS) const {
+      assert(Low && High && "Case range is not initialized.");
+      assert(RHS.Low && RHS.High && "Right case range is not initialized.");
+      const APInt &LowInt = Low->getValue();
+      const APInt &HighInt = High->getValue();
+      const APInt &RHSLowInt = RHS.Low->getValue();
+      const APInt &RHSHighInt = RHS.High->getValue();
+      if (LowInt.getBitWidth() == RHSLowInt.getBitWidth()) {
+        if (LowInt.eq(RHSLowInt)) {
+          if (HighInt.ult(RHSHighInt))
+            return true;
+          return false;
+        }
+        if (LowInt.ult(RHSLowInt))
+          return true;
+        return false;
+      } else
+        return LowInt.getBitWidth() < RHSLowInt.getBitWidth();      
+    }
+
+    bool operator==(const RangeT &RHS) const {
+      assert(Low && High && "Case range is not initialized.");
+      assert(RHS.Low && RHS.High && "Right case range is not initialized.");
+      if (Low->getValue().getBitWidth() != RHS.Low->getValue().getBitWidth())
+        return false;
+      return Low->getValue() == RHS.Low->getValue() &&
+             High->getValue() == RHS.High->getValue();      
+    }
+ 
+    bool operator!=(const RangeT &RHS) const {
+      return !operator ==(RHS);      
+    }
+ 
+    static bool LessBySize(const RangeT &LHS, const RangeT &RHS) {
+      assert(LHS.Low->getBitWidth() == RHS.Low->getBitWidth() && 
+          "This type of comparison requires equal bit width for LHS and RHS");
+      APInt LSize = LHS.High->getValue() - LHS.Low->getValue();
+      APInt RSize = RHS.High->getValue() - RHS.Low->getValue();;
+      return LSize.ult(RSize);      
+    }
+ 
+    bool isInRange(const APInt &IntVal) const {
+      assert(Low && High && "Case range is not initialized.");
+      if (IntVal.getBitWidth() != Low->getValue().getBitWidth())
+        return false;
+      return IntVal.uge(Low->getValue()) && IntVal.ule(High->getValue());      
+    }    
+  
+    bool isInRange(const ConstantIntTy *CI) const {
+      const APInt& IntVal = CI->getValue();
+      return isInRange(IntVal);
+    }
+  
+    SubRes sub(const RangeT &RHS) const {
+      SubRes Res;
+      
+      // RHS is either more global and includes this range or
+      // if it doesn't intersected with this range.
+      if (!isInRange(RHS.Low) && !isInRange(RHS.High)) {
+        
+        // If RHS more global (it is enough to check
+        // only one border in this case.
+        if (RHS.isInRange(Low))
+          return std::make_pair(RangeT(Low, High), RangeT()); 
+        
+        return Res;
+      }
+      
+      const APInt& LoInt = Low->getValue();
+      const APInt& HiInt = High->getValue();
+      APInt RHSLoInt = RHS.Low->getValue();
+      APInt RHSHiInt = RHS.High->getValue();
+      if (LoInt.ult(RHSLoInt)) {
+        Res.first.Low = Low;
+        Res.first.High = ConstantIntTy::get(RHS.Low->getContext(), --RHSLoInt);
+      }
+      if (HiInt.ugt(RHSHiInt)) {
+        Res.second.Low = ConstantIntTy::get(RHS.High->getContext(), ++RHSHiInt);
+        Res.second.High = High;
+      }
+      return Res;      
+    }
+  };      
+
+  typedef RangeT<false> Range;
+ 
+  /// Checks is the given constant satisfies this case. Returns
+  /// true if it equals to one of contained values or belongs to the one of
+  /// contained ranges.
+  bool isSatisfies(const ConstantInt *C) const {
+    const APInt &CheckingVal = C->getValue();
+    for (unsigned i = 0, e = getNumItems(); i < e; ++i) {
+      const Constant *CV = Array->getAggregateElement(i);
+      unsigned VecSize = cast<VectorType>(CV->getType())->getNumElements();
+      switch (VecSize) {
+      case 1:
+        if (cast<const ConstantInt>(CV->getAggregateElement(0U))->getValue() ==
+            CheckingVal)
+          return true;
+        break;
+      case 2: {
+        const APInt &Lo =
+            cast<const ConstantInt>(CV->getAggregateElement(0U))->getValue();
+        const APInt &Hi =
+            cast<const ConstantInt>(CV->getAggregateElement(1))->getValue();
+        if (Lo.uge(CheckingVal) && Hi.ule(CheckingVal))
+          return true;
+      }
+        break;
+      default:
+        assert(0 && "Only pairs and single numbers are allowed here.");
+        break;
+      }
+    }
+    return false;    
+  }
+  
+  /// Returns set's item with given index.
+  Range getItem(unsigned idx) {
+    Constant *CV = Array->getAggregateElement(idx);
+    unsigned NumEls = cast<VectorType>(CV->getType())->getNumElements();
+    switch (NumEls) {
+    case 1:
+      return Range(cast<ConstantInt>(CV->getAggregateElement(0U)),
+                   cast<ConstantInt>(CV->getAggregateElement(0U)));
+    case 2:
+      return Range(cast<ConstantInt>(CV->getAggregateElement(0U)),
+                   cast<ConstantInt>(CV->getAggregateElement(1)));
+    default:
+      assert(0 && "Only pairs and single numbers are allowed here.");
+      return Range();
+    }    
+  }
+  
+  const Range getItem(unsigned idx) const {
+    const Constant *CV = Array->getAggregateElement(idx);
+    
+    unsigned NumEls = cast<VectorType>(CV->getType())->getNumElements();
+    switch (NumEls) {
+    case 1:
+      return Range(cast<ConstantInt>(
+                     const_cast<Constant*>(CV->getAggregateElement(0U))),
+                   cast<ConstantInt>(
+                     const_cast<Constant*>(CV->getAggregateElement(0U))));
+    case 2:
+      return Range(cast<ConstantInt>(
+                     const_cast<Constant*>(CV->getAggregateElement(0U))),
+                   cast<ConstantInt>(
+                     const_cast<Constant*>(CV->getAggregateElement(1))));
+    default:
+      assert(0 && "Only pairs and single numbers are allowed here.");
+      return Range();
+    }    
+  }
+  
+  /// Return number of items (ranges) stored in set.
+  unsigned getNumItems() const {
+    return cast<ArrayType>(Array->getType())->getNumElements();
+  }
+  
+  /// Returns set the size, that equals number of all values + sizes of all
+  /// ranges.
+  /// Ranges set is considered as flat numbers collection.
+  /// E.g.: for range [<0>, <1>, <4,8>] the size will 7;
+  ///       for range [<0>, <1>, <5>] the size will 3
+  unsigned getSize() const {
+    APInt sz(getItem(0).Low->getBitWidth(), 0);
+    for (unsigned i = 0, e = getNumItems(); i != e; ++i) {
+      const APInt &S = getItem(i).High->getValue() - getItem(i).Low->getValue();
+      sz += S;
+    }
+    return sz.getZExtValue();    
+  }
+  
+  /// Allows to access single value even if it belongs to some range.
+  /// Ranges set is considered as flat numbers collection.
+  /// [<1>, <4,8>] is considered as [1,4,5,6,7,8] 
+  /// For range [<1>, <4,8>] getSingleValue(3) returns 6.
+  APInt getSingleValue(unsigned idx) const {
+    APInt sz(getItem(0).Low->getBitWidth(), 0);
+    for (unsigned i = 0, e = getNumItems(); i != e; ++i) {
+      const APInt& S = getItem(i).High->getValue() - getItem(i).Low->getValue();
+      APInt oldSz = sz;
+      sz += S;
+      if (oldSz.uge(i) && sz.ult(i)) {
+        APInt Res = getItem(i).Low->getValue();
+        APInt Offset(oldSz.getBitWidth(), i);
+        Offset -= oldSz;
+        Res += Offset;
+        return Res;
+      }
+    }
+    assert(0 && "Index exceeds high border.");
+    return sz;    
+  }
+};  
+
+}
+
+#endif /* CONSTANTRANGESSET_H_ */





More information about the llvm-commits mailing list