diff options
author | Stepan Dyatkovskiy <stpworld@narod.ru> | 2012-06-01 10:06:14 +0000 |
---|---|---|
committer | Stepan Dyatkovskiy <stpworld@narod.ru> | 2012-06-01 10:06:14 +0000 |
commit | f8d14c4ca3874890cfd8867d9557efca9511c98f (patch) | |
tree | 21b0099b59128b3823d22eac911a39896fdc530e | |
parent | 14f094bb2b1d72266d8d29daddb27ec3b1be5e14 (diff) |
PR1255: case ranges.
IntItem cleanup. IntItemBase, IntItemConstantIntImp and IntItem merged into IntItem. All arithmetic operators was propogated from APInt. Also added comparison operators <,>,<=,>=. Currently you will find set of macros that propogates operators from APInt to IntItem in the beginning of IntegerSubset. Note that THESE MACROS WILL REMOVED after all passes will case-ranges compatible. Also note that these macros much smaller pain that something like this:
if (V->getValue().ugt(AnotherV->getValue()) { ... }
These changes made IntItem full featured integer object. It allows to make IntegerSubset class generic (move out all ConstantInt references inside and add unit-tests) in next commits.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@157810 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/llvm/Instructions.h | 4 | ||||
-rw-r--r-- | include/llvm/Support/IntegersSubset.h | 222 | ||||
-rw-r--r-- | include/llvm/Support/IntegersSubsetMapping.h | 6 | ||||
-rw-r--r-- | lib/ExecutionEngine/Interpreter/Execution.cpp | 4 | ||||
-rw-r--r-- | lib/VMCore/Verifier.cpp | 4 |
5 files changed, 142 insertions, 98 deletions
diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h index 89a5a307f2..99186f5f50 100644 --- a/include/llvm/Instructions.h +++ b/include/llvm/Instructions.h @@ -2552,13 +2552,13 @@ public: /// that it is handled by the default handler. CaseIt findCaseValue(const ConstantInt *C) { for (CaseIt i = case_begin(), e = case_end(); i != e; ++i) - if (i.getCaseValueEx().isSatisfies(C->getValue())) + if (i.getCaseValueEx().isSatisfies(IntItem::fromConstantInt(C))) return i; return case_default(); } ConstCaseIt findCaseValue(const ConstantInt *C) const { for (ConstCaseIt i = case_begin(), e = case_end(); i != e; ++i) - if (i.getCaseValueEx().isSatisfies(C->getValue())) + if (i.getCaseValueEx().isSatisfies(IntItem::fromConstantInt(C))) return i; return case_default(); } diff --git a/include/llvm/Support/IntegersSubset.h b/include/llvm/Support/IntegersSubset.h index 894b104da9..b0cfd85a9b 100644 --- a/include/llvm/Support/IntegersSubset.h +++ b/include/llvm/Support/IntegersSubset.h @@ -25,88 +25,143 @@ namespace llvm { -template <class ImplTy> -class IntItemBase { -protected: - ImplTy Implementation; - typedef IntItemBase<ImplTy> self; -public: - - IntItemBase() {} - - IntItemBase(const ImplTy &impl) : Implementation(impl) {} + // 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. - // implicit - IntItemBase(const APInt& src) : Implementation(src) {} - - operator const APInt&() const { - return (const APInt&)Implementation; + // 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 ConstantIntVal->getValue().func(RHS); \ } - bool operator<(const self& RHS) const { - return ((const APInt&)*this).ult(RHS); + +#define INT_ITEM_DEFINE_UNARY_OP(op) \ + IntItem operator op () const { \ + APInt res = op(ConstantIntVal->getValue()); \ + Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \ + return IntItem(cast<ConstantInt>(NewVal)); \ } - bool operator==(const self& RHS) const { - return (const APInt&)*this == (const APInt&)RHS; + +#define INT_ITEM_DEFINE_BINARY_OP(op) \ + IntItem operator op (const APInt& RHS) const { \ + APInt res = ConstantIntVal->getValue() op RHS; \ + Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \ + return IntItem(cast<ConstantInt>(NewVal)); \ } - bool operator!=(const self& RHS) const { - return (const APInt&)*this != (const APInt&)RHS; + +#define INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(op) \ + IntItem& operator op (const APInt& RHS) {\ + APInt res = ConstantIntVal->getValue();\ + res op RHS; \ + Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \ + ConstantIntVal = cast<ConstantInt>(NewVal); \ + return *this; \ } - self& operator=(const ImplTy& RHS) { - Implementation = RHS; - return *this; - } - const APInt* operator->() const { - return &((const APInt&)Implementation); - } - const APInt& operator*() const { - return ((const APInt&)Implementation); - } - // FIXME: Hack. Will removed. - ImplTy& getImplementation() { - return Implementation; - } -}; - -class IntItemConstantIntImpl { - const ConstantInt *ConstantIntVal; -public: - IntItemConstantIntImpl() : ConstantIntVal(0) {} - IntItemConstantIntImpl(const ConstantInt *Val) : ConstantIntVal(Val) {} - IntItemConstantIntImpl(LLVMContext &Ctx, const APInt& src) { - ConstantIntVal = cast<ConstantInt>(ConstantInt::get(Ctx, src)); - } - explicit IntItemConstantIntImpl(const APInt& src) { - ConstantIntVal = - cast<ConstantInt>(ConstantInt::get(llvm::getGlobalContext(), src)); - } - operator const APInt&() const { - return ConstantIntVal->getValue(); + +#define INT_ITEM_DEFINE_PREINCDEC(op) \ + IntItem& operator op () { \ + APInt res = ConstantIntVal->getValue(); \ + 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 = ConstantIntVal->getValue();\ + 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(ConstantIntVal->getValue().getBitWidth(), RHS); \ } - operator const ConstantInt*() { - return ConstantIntVal; - } -}; -class IntItem : public IntItemBase<IntItemConstantIntImpl> { - typedef IntItemBase<IntItemConstantIntImpl> ParentTy; - IntItem(const IntItemConstantIntImpl& Impl) : ParentTy(Impl) {} +class IntItem { + ConstantInt *ConstantIntVal; + IntItem(const ConstantInt *V) : ConstantIntVal(const_cast<ConstantInt*>(V)) {} public: IntItem() {} - // implicit - IntItem(const APInt& src) : ParentTy(src) {} + operator const APInt&() const { + return (const APInt&)ConstantIntVal->getValue(); + } + + // Propogate 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_COMPARISON(!=, ne); + + 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 = ConstantIntVal->getValue(); + 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) { - IntItemConstantIntImpl Impl(V); - return IntItem(Impl); + 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() { - return const_cast<ConstantInt*>((const ConstantInt*)Implementation); + return ConstantIntVal; } }; @@ -145,24 +200,19 @@ struct IntRange { bool operator<(const IntRange &RHS) const { assert(!IsEmpty && "Left range is empty."); assert(!RHS.IsEmpty && "Right range is empty."); - if (Low->getBitWidth() == RHS.Low->getBitWidth()) { - if (Low->eq(RHS.Low)) { - if (High->ult(RHS.High)) - return true; - return false; - } - if (Low->ult(RHS.Low)) + if (Low == RHS.Low) { + if (High > RHS.High) return true; return false; - } else - return Low->getBitWidth() < RHS.Low->getBitWidth(); + } + if (Low < RHS.Low) + return true; + return false; } bool operator==(const IntRange &RHS) const { assert(!IsEmpty && "Left range is empty."); assert(!RHS.IsEmpty && "Right range is empty."); - if (Low->getBitWidth() != RHS.Low->getBitWidth()) - return false; return Low == RHS.Low && High == RHS.High; } @@ -171,18 +221,12 @@ struct IntRange { } static bool LessBySize(const IntRange &LHS, const IntRange &RHS) { - assert(LHS.Low->getBitWidth() == RHS.Low->getBitWidth() && - "This type of comparison requires equal bit width for LHS and RHS"); - APInt LSize = *LHS.High - *LHS.Low; - APInt RSize = *RHS.High - *RHS.Low; - return LSize.ult(RSize); + return (LHS.High - LHS.Low) < (RHS.High - RHS.Low); } - bool isInRange(const APInt &IntVal) const { + bool isInRange(const IntItem &IntVal) const { assert(!IsEmpty && "Range is empty."); - if (IntVal.getBitWidth() != Low->getBitWidth()) - return false; - return IntVal.uge(Low) && IntVal.ule(High); + return IntVal >= Low && IntVal <= High; } SubRes sub(const IntRange &RHS) const { @@ -200,14 +244,14 @@ struct IntRange { return Res; } - if (Low->ult(RHS.Low)) { + if (Low < RHS.Low) { Res.first.Low = Low; - APInt NewHigh = RHS.Low; + IntItem NewHigh = RHS.Low; --NewHigh; Res.first.High = NewHigh; } - if (High->ugt(RHS.High)) { - APInt NewLow = RHS.High; + if (High > RHS.High) { + IntItem NewLow = RHS.High; ++NewLow; Res.second.Low = NewLow; Res.second.High = High; @@ -332,7 +376,7 @@ public: /// 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); + APInt sz(((const APInt&)getItem(0).Low).getBitWidth(), 0); for (unsigned i = 0, e = getNumItems(); i != e; ++i) { const APInt &Low = getItem(i).Low; const APInt &High = getItem(i).High; @@ -347,7 +391,7 @@ public: /// [<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); + APInt sz(((const APInt&)getItem(0).Low).getBitWidth(), 0); for (unsigned i = 0, e = getNumItems(); i != e; ++i) { const APInt &Low = getItem(i).Low; const APInt &High = getItem(i).High; diff --git a/include/llvm/Support/IntegersSubsetMapping.h b/include/llvm/Support/IntegersSubsetMapping.h index eaa2f5be2f..374a68772e 100644 --- a/include/llvm/Support/IntegersSubsetMapping.h +++ b/include/llvm/Support/IntegersSubsetMapping.h @@ -67,7 +67,7 @@ protected: bool Sorted; bool isIntersected(CaseItemIt& LItem, CaseItemIt& RItem) { - return LItem->first.High->uge(RItem->first.Low); + return LItem->first.High >= RItem->first.Low; } bool isJoinable(CaseItemIt& LItem, CaseItemIt& RItem) { @@ -79,7 +79,7 @@ protected: APInt RLow = RItem->first.Low; if (RLow != APInt::getNullValue(RLow.getBitWidth())) --RLow; - return LItem->first.High->uge(RLow); + return LItem->first.High >= RLow; } void sort() { @@ -159,7 +159,7 @@ public: if (isJoinable(i, j)) { IntItem *CurHigh = &j->first.High; ++Weight; - if ((*CurHigh)->ugt(*High)) + if (*CurHigh > *High) High = CurHigh; } else { RangeEx R(*Low, *High, Weight); diff --git a/lib/ExecutionEngine/Interpreter/Execution.cpp b/lib/ExecutionEngine/Interpreter/Execution.cpp index d54010195d..d4b6ed0003 100644 --- a/lib/ExecutionEngine/Interpreter/Execution.cpp +++ b/lib/ExecutionEngine/Interpreter/Execution.cpp @@ -655,8 +655,8 @@ void Interpreter::visitSwitchInst(SwitchInst &I) { for (unsigned n = 0, en = Case.getNumItems(); n != en; ++n) { IntegersSubset::Range r = Case.getItem(n); // FIXME: Currently work with ConstantInt based numbers. - const ConstantInt *LowCI = r.Low.getImplementation(); - const ConstantInt *HighCI = r.High.getImplementation(); + const ConstantInt *LowCI = r.Low.toConstantInt(); + const ConstantInt *HighCI = r.High.toConstantInt(); GenericValue Low = getOperandValue(const_cast<ConstantInt*>(LowCI), SF); GenericValue High = getOperandValue(const_cast<ConstantInt*>(HighCI), SF); if (executeICMP_ULE(Low, CondVal, ElTy).IntVal != 0 && diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp index e093c52f99..7afe342899 100644 --- a/lib/VMCore/Verifier.cpp +++ b/lib/VMCore/Verifier.cpp @@ -813,9 +813,9 @@ void Verifier::visitSwitchInst(SwitchInst &SI) { IntegersSubset CaseRanges = i.getCaseValueEx(); for (unsigned ri = 0, rie = CaseRanges.getNumItems(); ri < rie; ++ri) { IntegersSubset::Range r = CaseRanges.getItem(ri); - Assert1(r.Low->getBitWidth() == IntTy->getBitWidth(), + Assert1(((const APInt&)r.Low).getBitWidth() == IntTy->getBitWidth(), "Switch constants must all be same type as switch value!", &SI); - Assert1(r.High->getBitWidth() == IntTy->getBitWidth(), + Assert1(((const APInt&)r.High).getBitWidth() == IntTy->getBitWidth(), "Switch constants must all be same type as switch value!", &SI); Mapping.add(r); RangeSetMap[r] = i.getCaseIndex(); |