| //===-- llvm/IntegersSubset.h - The subset of integers ----------*- 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>]. Initially, this class was created for |
| /// SwitchInst and was used for case value representation that may contain |
| /// multiple ranges for a single successor. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_SUPPORT_INTEGERSSUBSET_H |
| #define LLVM_SUPPORT_INTEGERSSUBSET_H |
| |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/DerivedTypes.h" |
| #include "llvm/IR/LLVMContext.h" |
| #include <list> |
| |
| namespace llvm { |
| |
| // The IntItem is a wrapper for APInt. |
| // 1. It determines sign of integer, it allows to use |
| // comparison operators >,<,>=,<=, and as result we got shorter and cleaner |
| // constructions. |
| // 2. It helps to implement PR1255 (case ranges) as a series of small patches. |
| // 3. Currently we can interpret IntItem both as ConstantInt and as APInt. |
| // It allows to provide SwitchInst methods that works with ConstantInt for |
| // non-updated passes. And it allows to use APInt interface for new methods. |
| // 4. IntItem can be easily replaced with APInt. |
| |
| // The set of macros that allows to propagate APInt operators to the IntItem. |
| |
| #define INT_ITEM_DEFINE_COMPARISON(op,func) \ |
| bool operator op (const APInt& RHS) const { \ |
| return getAPIntValue().func(RHS); \ |
| } |
| |
| #define INT_ITEM_DEFINE_UNARY_OP(op) \ |
| IntItem operator op () const { \ |
| APInt res = op(getAPIntValue()); \ |
| Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \ |
| return IntItem(cast<ConstantInt>(NewVal)); \ |
| } |
| |
| #define INT_ITEM_DEFINE_BINARY_OP(op) \ |
| IntItem operator op (const APInt& RHS) const { \ |
| APInt res = getAPIntValue() op RHS; \ |
| Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \ |
| return IntItem(cast<ConstantInt>(NewVal)); \ |
| } |
| |
| #define INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(op) \ |
| IntItem& operator op (const APInt& RHS) {\ |
| APInt res = getAPIntValue();\ |
| res op RHS; \ |
| Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \ |
| ConstantIntVal = cast<ConstantInt>(NewVal); \ |
| return *this; \ |
| } |
| |
| #define INT_ITEM_DEFINE_PREINCDEC(op) \ |
| IntItem& operator op () { \ |
| APInt res = getAPIntValue(); \ |
| op(res); \ |
| Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \ |
| ConstantIntVal = cast<ConstantInt>(NewVal); \ |
| return *this; \ |
| } |
| |
| #define INT_ITEM_DEFINE_POSTINCDEC(op) \ |
| IntItem& operator op (int) { \ |
| APInt res = getAPIntValue();\ |
| op(res); \ |
| Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \ |
| OldConstantIntVal = ConstantIntVal; \ |
| ConstantIntVal = cast<ConstantInt>(NewVal); \ |
| return IntItem(OldConstantIntVal); \ |
| } |
| |
| #define INT_ITEM_DEFINE_OP_STANDARD_INT(RetTy, op, IntTy) \ |
| RetTy operator op (IntTy RHS) const { \ |
| return (*this) op APInt(getAPIntValue().getBitWidth(), RHS); \ |
| } |
| |
| class IntItem { |
| ConstantInt *ConstantIntVal; |
| const APInt* APIntVal; |
| IntItem(const ConstantInt *V) : |
| ConstantIntVal(const_cast<ConstantInt*>(V)), |
| APIntVal(&ConstantIntVal->getValue()){} |
| const APInt& getAPIntValue() const { |
| return *APIntVal; |
| } |
| public: |
| |
| IntItem() {} |
| |
| operator const APInt&() const { |
| return getAPIntValue(); |
| } |
| |
| // Propagate APInt operators. |
| // Note, that |
| // /,/=,>>,>>= are not implemented in APInt. |
| // <<= is implemented for unsigned RHS, but not implemented for APInt RHS. |
| |
| INT_ITEM_DEFINE_COMPARISON(<, ult) |
| INT_ITEM_DEFINE_COMPARISON(>, ugt) |
| INT_ITEM_DEFINE_COMPARISON(<=, ule) |
| INT_ITEM_DEFINE_COMPARISON(>=, uge) |
| |
| INT_ITEM_DEFINE_COMPARISON(==, eq) |
| INT_ITEM_DEFINE_OP_STANDARD_INT(bool,==,uint64_t) |
| |
| INT_ITEM_DEFINE_COMPARISON(!=, ne) |
| INT_ITEM_DEFINE_OP_STANDARD_INT(bool,!=,uint64_t) |
| |
| INT_ITEM_DEFINE_BINARY_OP(*) |
| INT_ITEM_DEFINE_BINARY_OP(+) |
| INT_ITEM_DEFINE_OP_STANDARD_INT(IntItem,+,uint64_t) |
| INT_ITEM_DEFINE_BINARY_OP(-) |
| INT_ITEM_DEFINE_OP_STANDARD_INT(IntItem,-,uint64_t) |
| INT_ITEM_DEFINE_BINARY_OP(<<) |
| INT_ITEM_DEFINE_OP_STANDARD_INT(IntItem,<<,unsigned) |
| INT_ITEM_DEFINE_BINARY_OP(&) |
| INT_ITEM_DEFINE_BINARY_OP(^) |
| INT_ITEM_DEFINE_BINARY_OP(|) |
| |
| INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(*=) |
| INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(+=) |
| INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(-=) |
| INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(&=) |
| INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(^=) |
| INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(|=) |
| |
| // Special case for <<= |
| IntItem& operator <<= (unsigned RHS) { |
| APInt res = getAPIntValue(); |
| res <<= RHS; |
| Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); |
| ConstantIntVal = cast<ConstantInt>(NewVal); |
| return *this; |
| } |
| |
| INT_ITEM_DEFINE_UNARY_OP(-) |
| INT_ITEM_DEFINE_UNARY_OP(~) |
| |
| INT_ITEM_DEFINE_PREINCDEC(++) |
| INT_ITEM_DEFINE_PREINCDEC(--) |
| |
| // The set of workarounds, since currently we use ConstantInt implemented |
| // integer. |
| |
| static IntItem fromConstantInt(const ConstantInt *V) { |
| return IntItem(V); |
| } |
| static IntItem fromType(Type* Ty, const APInt& V) { |
| ConstantInt *C = cast<ConstantInt>(ConstantInt::get(Ty, V)); |
| return fromConstantInt(C); |
| } |
| static IntItem withImplLikeThis(const IntItem& LikeThis, const APInt& V) { |
| ConstantInt *C = cast<ConstantInt>(ConstantInt::get( |
| LikeThis.ConstantIntVal->getContext(), V)); |
| return fromConstantInt(C); |
| } |
| ConstantInt *toConstantInt() const { |
| return ConstantIntVal; |
| } |
| }; |
| |
| template<class IntType> |
| class IntRange { |
| protected: |
| IntType Low; |
| IntType High; |
| bool IsEmpty : 1; |
| bool IsSingleNumber : 1; |
| |
| public: |
| typedef IntRange<IntType> self; |
| typedef std::pair<self, self> SubRes; |
| |
| IntRange() : IsEmpty(true) {} |
| IntRange(const self &RHS) : |
| Low(RHS.Low), High(RHS.High), |
| IsEmpty(RHS.IsEmpty), IsSingleNumber(RHS.IsSingleNumber) {} |
| IntRange(const IntType &C) : |
| Low(C), High(C), IsEmpty(false), IsSingleNumber(true) {} |
| |
| IntRange(const IntType &L, const IntType &H) : Low(L), High(H), |
| IsEmpty(false), IsSingleNumber(Low == High) {} |
| |
| bool isEmpty() const { return IsEmpty; } |
| bool isSingleNumber() const { return IsSingleNumber; } |
| |
| const IntType& getLow() const { |
| assert(!IsEmpty && "Range is empty."); |
| return Low; |
| } |
| const IntType& getHigh() const { |
| assert(!IsEmpty && "Range is empty."); |
| return High; |
| } |
| |
| bool operator<(const self &RHS) const { |
| assert(!IsEmpty && "Left range is empty."); |
| assert(!RHS.IsEmpty && "Right range is empty."); |
| if (Low == RHS.Low) { |
| if (High > RHS.High) |
| return true; |
| return false; |
| } |
| if (Low < RHS.Low) |
| return true; |
| return false; |
| } |
| |
| bool operator==(const self &RHS) const { |
| assert(!IsEmpty && "Left range is empty."); |
| assert(!RHS.IsEmpty && "Right range is empty."); |
| return Low == RHS.Low && High == RHS.High; |
| } |
| |
| bool operator!=(const self &RHS) const { |
| return !operator ==(RHS); |
| } |
| |
| static bool LessBySize(const self &LHS, const self &RHS) { |
| return (LHS.High - LHS.Low) < (RHS.High - RHS.Low); |
| } |
| |
| bool isInRange(const IntType &IntVal) const { |
| assert(!IsEmpty && "Range is empty."); |
| return IntVal >= Low && IntVal <= High; |
| } |
| |
| SubRes sub(const self &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(self(Low, High), self()); |
| |
| return Res; |
| } |
| |
| if (Low < RHS.Low) { |
| Res.first.Low = Low; |
| IntType NewHigh = RHS.Low; |
| --NewHigh; |
| Res.first.High = NewHigh; |
| } |
| if (High > RHS.High) { |
| IntType NewLow = RHS.High; |
| ++NewLow; |
| Res.second.Low = NewLow; |
| Res.second.High = High; |
| } |
| return Res; |
| } |
| }; |
| |
| //===----------------------------------------------------------------------===// |
| /// IntegersSubsetGeneric - class that implements the subset of integers. It |
| /// consists from ranges and single numbers. |
| template <class IntTy> |
| class IntegersSubsetGeneric { |
| public: |
| // Use Chris Lattner idea, that was initially described here: |
| // http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20120213/136954.html |
| // In short, for more compact memory consumption we can store flat |
| // numbers collection, and define range as pair of indices. |
| // In that case we can safe some memory on 32 bit machines. |
| typedef std::vector<IntTy> FlatCollectionTy; |
| typedef std::pair<IntTy*, IntTy*> RangeLinkTy; |
| typedef std::vector<RangeLinkTy> RangeLinksTy; |
| typedef typename RangeLinksTy::const_iterator RangeLinksConstIt; |
| |
| typedef IntegersSubsetGeneric<IntTy> self; |
| |
| protected: |
| |
| FlatCollectionTy FlatCollection; |
| RangeLinksTy RangeLinks; |
| |
| bool IsSingleNumber; |
| bool IsSingleNumbersOnly; |
| |
| public: |
| |
| template<class RangesCollectionTy> |
| explicit IntegersSubsetGeneric(const RangesCollectionTy& Links) { |
| assert(Links.size() && "Empty ranges are not allowed."); |
| |
| // In case of big set of single numbers consumes additional RAM space, |
| // but allows to avoid additional reallocation. |
| FlatCollection.reserve(Links.size() * 2); |
| RangeLinks.reserve(Links.size()); |
| IsSingleNumbersOnly = true; |
| for (typename RangesCollectionTy::const_iterator i = Links.begin(), |
| e = Links.end(); i != e; ++i) { |
| RangeLinkTy RangeLink; |
| FlatCollection.push_back(i->getLow()); |
| RangeLink.first = &FlatCollection.back(); |
| if (i->getLow() != i->getHigh()) { |
| FlatCollection.push_back(i->getHigh()); |
| IsSingleNumbersOnly = false; |
| } |
| RangeLink.second = &FlatCollection.back(); |
| RangeLinks.push_back(RangeLink); |
| } |
| IsSingleNumber = IsSingleNumbersOnly && RangeLinks.size() == 1; |
| } |
| |
| IntegersSubsetGeneric(const self& RHS) { |
| *this = RHS; |
| } |
| |
| self& operator=(const self& RHS) { |
| FlatCollection.clear(); |
| RangeLinks.clear(); |
| FlatCollection.reserve(RHS.RangeLinks.size() * 2); |
| RangeLinks.reserve(RHS.RangeLinks.size()); |
| for (RangeLinksConstIt i = RHS.RangeLinks.begin(), e = RHS.RangeLinks.end(); |
| i != e; ++i) { |
| RangeLinkTy RangeLink; |
| FlatCollection.push_back(*(i->first)); |
| RangeLink.first = &FlatCollection.back(); |
| if (i->first != i->second) |
| FlatCollection.push_back(*(i->second)); |
| RangeLink.second = &FlatCollection.back(); |
| RangeLinks.push_back(RangeLink); |
| } |
| IsSingleNumber = RHS.IsSingleNumber; |
| IsSingleNumbersOnly = RHS.IsSingleNumbersOnly; |
| return *this; |
| } |
| |
| typedef IntRange<IntTy> 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 IntTy &CheckingVal) const { |
| if (IsSingleNumber) |
| return FlatCollection.front() == CheckingVal; |
| if (IsSingleNumbersOnly) |
| return std::find(FlatCollection.begin(), |
| FlatCollection.end(), |
| CheckingVal) != FlatCollection.end(); |
| |
| for (unsigned i = 0, e = getNumItems(); i < e; ++i) { |
| if (RangeLinks[i].first == RangeLinks[i].second) { |
| if (*RangeLinks[i].first == CheckingVal) |
| return true; |
| } else if (*RangeLinks[i].first <= CheckingVal && |
| *RangeLinks[i].second >= CheckingVal) |
| return true; |
| } |
| return false; |
| } |
| |
| /// Returns set's item with given index. |
| Range getItem(unsigned idx) const { |
| const RangeLinkTy &Link = RangeLinks[idx]; |
| if (Link.first != Link.second) |
| return Range(*Link.first, *Link.second); |
| else |
| return Range(*Link.first); |
| } |
| |
| /// Return number of items (ranges) stored in set. |
| unsigned getNumItems() const { |
| return RangeLinks.size(); |
| } |
| |
| /// Returns true if whole subset contains single element. |
| bool isSingleNumber() const { |
| return IsSingleNumber; |
| } |
| |
| /// Returns true if whole subset contains only single numbers, no ranges. |
| bool isSingleNumbersOnly() const { |
| return IsSingleNumbersOnly; |
| } |
| |
| /// Does the same like getItem(idx).isSingleNumber(), but |
| /// works faster, since we avoid creation of temporary range object. |
| bool isSingleNumber(unsigned idx) const { |
| return RangeLinks[idx].first == RangeLinks[idx].second; |
| } |
| |
| /// 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(((const APInt&)getItem(0).getLow()).getBitWidth(), 0); |
| for (unsigned i = 0, e = getNumItems(); i != e; ++i) { |
| const APInt Low = getItem(i).getLow(); |
| const APInt High = getItem(i).getHigh(); |
| APInt S = High - Low + 1; |
| 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(((const APInt&)getItem(0).getLow()).getBitWidth(), 0); |
| for (unsigned i = 0, e = getNumItems(); i != e; ++i) { |
| const APInt Low = getItem(i).getLow(); |
| const APInt High = getItem(i).getHigh(); |
| APInt S = High - Low + 1; |
| APInt oldSz = sz; |
| sz += S; |
| if (sz.ugt(idx)) { |
| APInt Res = Low; |
| APInt Offset(oldSz.getBitWidth(), idx); |
| Offset -= oldSz; |
| Res += Offset; |
| return Res; |
| } |
| } |
| assert(0 && "Index exceeds high border."); |
| return sz; |
| } |
| |
| /// Does the same as getSingleValue, but works only if subset contains |
| /// single numbers only. |
| const IntTy& getSingleNumber(unsigned idx) const { |
| assert(IsSingleNumbersOnly && "This method works properly if subset " |
| "contains single numbers only."); |
| return FlatCollection[idx]; |
| } |
| }; |
| |
| //===----------------------------------------------------------------------===// |
| /// IntegersSubset - currently is extension of IntegersSubsetGeneric |
| /// that also supports conversion to/from Constant* object. |
| class IntegersSubset : public IntegersSubsetGeneric<IntItem> { |
| |
| typedef IntegersSubsetGeneric<IntItem> ParentTy; |
| |
| Constant *Holder; |
| |
| static unsigned getNumItemsFromConstant(Constant *C) { |
| return cast<ArrayType>(C->getType())->getNumElements(); |
| } |
| |
| static Range getItemFromConstant(Constant *C, unsigned idx) { |
| const Constant *CV = C->getAggregateElement(idx); |
| |
| unsigned NumEls = cast<VectorType>(CV->getType())->getNumElements(); |
| switch (NumEls) { |
| case 1: |
| return Range(IntItem::fromConstantInt( |
| cast<ConstantInt>(CV->getAggregateElement(0U))), |
| IntItem::fromConstantInt(cast<ConstantInt>( |
| cast<ConstantInt>(CV->getAggregateElement(0U))))); |
| case 2: |
| return Range(IntItem::fromConstantInt( |
| cast<ConstantInt>(CV->getAggregateElement(0U))), |
| IntItem::fromConstantInt( |
| cast<ConstantInt>(CV->getAggregateElement(1)))); |
| default: |
| assert(0 && "Only pairs and single numbers are allowed here."); |
| return Range(); |
| } |
| } |
| |
| std::vector<Range> rangesFromConstant(Constant *C) { |
| unsigned NumItems = getNumItemsFromConstant(C); |
| std::vector<Range> r; |
| r.reserve(NumItems); |
| for (unsigned i = 0, e = NumItems; i != e; ++i) |
| r.push_back(getItemFromConstant(C, i)); |
| return r; |
| } |
| |
| public: |
| |
| explicit IntegersSubset(Constant *C) : ParentTy(rangesFromConstant(C)), |
| Holder(C) {} |
| |
| IntegersSubset(const IntegersSubset& RHS) : |
| ParentTy(*(const ParentTy *)&RHS), // FIXME: tweak for msvc. |
| Holder(RHS.Holder) {} |
| |
| template<class RangesCollectionTy> |
| explicit IntegersSubset(const RangesCollectionTy& Src) : ParentTy(Src) { |
| std::vector<Constant*> Elts; |
| Elts.reserve(Src.size()); |
| for (typename RangesCollectionTy::const_iterator i = Src.begin(), |
| e = Src.end(); i != e; ++i) { |
| const Range &R = *i; |
| std::vector<Constant*> r; |
| if (R.isSingleNumber()) { |
| r.reserve(2); |
| // FIXME: Since currently we have ConstantInt based numbers |
| // use hack-conversion of IntItem to ConstantInt |
| r.push_back(R.getLow().toConstantInt()); |
| r.push_back(R.getHigh().toConstantInt()); |
| } else { |
| r.reserve(1); |
| r.push_back(R.getLow().toConstantInt()); |
| } |
| Constant *CV = ConstantVector::get(r); |
| Elts.push_back(CV); |
| } |
| ArrayType *ArrTy = |
| ArrayType::get(Elts.front()->getType(), (uint64_t)Elts.size()); |
| Holder = ConstantArray::get(ArrTy, Elts); |
| } |
| |
| operator Constant*() { return Holder; } |
| operator const Constant*() const { return Holder; } |
| Constant *operator->() { return Holder; } |
| const Constant *operator->() const { return Holder; } |
| }; |
| |
| } |
| |
| #endif /* CLLVM_SUPPORT_INTEGERSSUBSET_H */ |