diff options
author | Stepan Dyatkovskiy <stpworld@narod.ru> | 2012-05-11 10:34:23 +0000 |
---|---|---|
committer | Stepan Dyatkovskiy <stpworld@narod.ru> | 2012-05-11 10:34:23 +0000 |
commit | cb7a5f5f577e9477f6d5e3d0fa1558c4f229c1a6 (patch) | |
tree | 9db67410d277d95947e1586d8293883f51ee7218 /include/llvm/Support | |
parent | 12447575dc1f78a0abcfe31bd4f45562e450e26a (diff) | |
download | external_llvm-cb7a5f5f577e9477f6d5e3d0fa1558c4f229c1a6.zip external_llvm-cb7a5f5f577e9477f6d5e3d0fa1558c4f229c1a6.tar.gz external_llvm-cb7a5f5f577e9477f6d5e3d0fa1558c4f229c1a6.tar.bz2 |
PR1255: ConstantRangesSet and CRSBuilder classes moved from include/llvm to include/llvm/Support.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@156613 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include/llvm/Support')
-rw-r--r-- | include/llvm/Support/CRSBuilder.h | 252 | ||||
-rw-r--r-- | include/llvm/Support/ConstantRangesSet.h | 272 |
2 files changed, 524 insertions, 0 deletions
diff --git a/include/llvm/Support/CRSBuilder.h b/include/llvm/Support/CRSBuilder.h new file mode 100644 index 0000000..1fd1683 --- /dev/null +++ b/include/llvm/Support/CRSBuilder.h @@ -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/Support/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_ */ diff --git a/include/llvm/Support/ConstantRangesSet.h b/include/llvm/Support/ConstantRangesSet.h new file mode 100644 index 0000000..2d3ee8b --- /dev/null +++ b/include/llvm/Support/ConstantRangesSet.h @@ -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_ */ |