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
This commit is contained in:
Stepan Dyatkovskiy
2012-06-01 10:06:14 +00:00
parent 14f094bb2b
commit f8d14c4ca3
5 changed files with 147 additions and 103 deletions

View File

@ -2552,13 +2552,13 @@ public:
/// that it is handled by the default handler. /// that it is handled by the default handler.
CaseIt findCaseValue(const ConstantInt *C) { CaseIt findCaseValue(const ConstantInt *C) {
for (CaseIt i = case_begin(), e = case_end(); i != e; ++i) 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 i;
return case_default(); return case_default();
} }
ConstCaseIt findCaseValue(const ConstantInt *C) const { ConstCaseIt findCaseValue(const ConstantInt *C) const {
for (ConstCaseIt i = case_begin(), e = case_end(); i != e; ++i) 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 i;
return case_default(); return case_default();
} }

View File

@ -25,88 +25,143 @@
namespace llvm { namespace llvm {
template <class ImplTy> // The IntItem is a wrapper for APInt.
class IntItemBase { // 1. It determines sign of integer, it allows to use
protected: // comparison operators >,<,>=,<=, and as result we got shorter and cleaner
ImplTy Implementation; // constructions.
typedef IntItemBase<ImplTy> self; // 2. It helps to implement PR1255 (case ranges) as a series of small patches.
public: // 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.
IntItemBase() {} // The set of macros that allows to propagate APInt operators to the IntItem.
IntItemBase(const ImplTy &impl) : Implementation(impl) {} #define INT_ITEM_DEFINE_COMPARISON(op,func) \
bool operator op (const APInt& RHS) const { \
return ConstantIntVal->getValue().func(RHS); \
}
// implicit #define INT_ITEM_DEFINE_UNARY_OP(op) \
IntItemBase(const APInt& src) : Implementation(src) {} IntItem operator op () const { \
APInt res = op(ConstantIntVal->getValue()); \
Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \
return IntItem(cast<ConstantInt>(NewVal)); \
}
operator const APInt&() const { #define INT_ITEM_DEFINE_BINARY_OP(op) \
return (const APInt&)Implementation; 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).ult(RHS);
}
bool operator==(const self& RHS) const {
return (const APInt&)*this == (const APInt&)RHS;
}
bool operator!=(const self& RHS) const {
return (const APInt&)*this != (const APInt&)RHS;
}
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 { #define INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(op) \
const ConstantInt *ConstantIntVal; IntItem& operator op (const APInt& RHS) {\
public: APInt res = ConstantIntVal->getValue();\
IntItemConstantIntImpl() : ConstantIntVal(0) {} res op RHS; \
IntItemConstantIntImpl(const ConstantInt *Val) : ConstantIntVal(Val) {} Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \
IntItemConstantIntImpl(LLVMContext &Ctx, const APInt& src) { ConstantIntVal = cast<ConstantInt>(NewVal); \
ConstantIntVal = cast<ConstantInt>(ConstantInt::get(Ctx, src)); return *this; \
} }
explicit IntItemConstantIntImpl(const APInt& src) {
ConstantIntVal =
cast<ConstantInt>(ConstantInt::get(llvm::getGlobalContext(), src));
}
operator const APInt&() const {
return ConstantIntVal->getValue();
}
operator const ConstantInt*() {
return ConstantIntVal;
}
};
class IntItem : public IntItemBase<IntItemConstantIntImpl> { #define INT_ITEM_DEFINE_PREINCDEC(op) \
typedef IntItemBase<IntItemConstantIntImpl> ParentTy; IntItem& operator op () { \
IntItem(const IntItemConstantIntImpl& Impl) : ParentTy(Impl) {} 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); \
}
class IntItem {
ConstantInt *ConstantIntVal;
IntItem(const ConstantInt *V) : ConstantIntVal(const_cast<ConstantInt*>(V)) {}
public: public:
IntItem() {} IntItem() {}
// implicit operator const APInt&() const {
IntItem(const APInt& src) : ParentTy(src) {} 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) { static IntItem fromConstantInt(const ConstantInt *V) {
IntItemConstantIntImpl Impl(V); return IntItem(V);
return IntItem(Impl);
} }
static IntItem fromType(Type* Ty, const APInt& V) { static IntItem fromType(Type* Ty, const APInt& V) {
ConstantInt *C = cast<ConstantInt>(ConstantInt::get(Ty, V)); ConstantInt *C = cast<ConstantInt>(ConstantInt::get(Ty, V));
return fromConstantInt(C); 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() { ConstantInt *toConstantInt() {
return const_cast<ConstantInt*>((const ConstantInt*)Implementation); return ConstantIntVal;
} }
}; };
@ -145,24 +200,19 @@ struct IntRange {
bool operator<(const IntRange &RHS) const { bool operator<(const IntRange &RHS) const {
assert(!IsEmpty && "Left range is empty."); assert(!IsEmpty && "Left range is empty.");
assert(!RHS.IsEmpty && "Right range is empty."); assert(!RHS.IsEmpty && "Right range is empty.");
if (Low->getBitWidth() == RHS.Low->getBitWidth()) { if (Low == RHS.Low) {
if (Low->eq(RHS.Low)) { if (High > RHS.High)
if (High->ult(RHS.High))
return true; return true;
return false; return false;
} }
if (Low->ult(RHS.Low)) if (Low < RHS.Low)
return true; return true;
return false; return false;
} else
return Low->getBitWidth() < RHS.Low->getBitWidth();
} }
bool operator==(const IntRange &RHS) const { bool operator==(const IntRange &RHS) const {
assert(!IsEmpty && "Left range is empty."); assert(!IsEmpty && "Left range is empty.");
assert(!RHS.IsEmpty && "Right 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; return Low == RHS.Low && High == RHS.High;
} }
@ -171,18 +221,12 @@ struct IntRange {
} }
static bool LessBySize(const IntRange &LHS, const IntRange &RHS) { static bool LessBySize(const IntRange &LHS, const IntRange &RHS) {
assert(LHS.Low->getBitWidth() == RHS.Low->getBitWidth() && return (LHS.High - LHS.Low) < (RHS.High - RHS.Low);
"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);
} }
bool isInRange(const APInt &IntVal) const { bool isInRange(const IntItem &IntVal) const {
assert(!IsEmpty && "Range is empty."); assert(!IsEmpty && "Range is empty.");
if (IntVal.getBitWidth() != Low->getBitWidth()) return IntVal >= Low && IntVal <= High;
return false;
return IntVal.uge(Low) && IntVal.ule(High);
} }
SubRes sub(const IntRange &RHS) const { SubRes sub(const IntRange &RHS) const {
@ -200,14 +244,14 @@ struct IntRange {
return Res; return Res;
} }
if (Low->ult(RHS.Low)) { if (Low < RHS.Low) {
Res.first.Low = Low; Res.first.Low = Low;
APInt NewHigh = RHS.Low; IntItem NewHigh = RHS.Low;
--NewHigh; --NewHigh;
Res.first.High = NewHigh; Res.first.High = NewHigh;
} }
if (High->ugt(RHS.High)) { if (High > RHS.High) {
APInt NewLow = RHS.High; IntItem NewLow = RHS.High;
++NewLow; ++NewLow;
Res.second.Low = NewLow; Res.second.Low = NewLow;
Res.second.High = High; Res.second.High = High;
@ -332,7 +376,7 @@ public:
/// E.g.: for range [<0>, <1>, <4,8>] the size will 7; /// E.g.: for range [<0>, <1>, <4,8>] the size will 7;
/// for range [<0>, <1>, <5>] the size will 3 /// for range [<0>, <1>, <5>] the size will 3
unsigned getSize() const { 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) { for (unsigned i = 0, e = getNumItems(); i != e; ++i) {
const APInt &Low = getItem(i).Low; const APInt &Low = getItem(i).Low;
const APInt &High = getItem(i).High; const APInt &High = getItem(i).High;
@ -347,7 +391,7 @@ public:
/// [<1>, <4,8>] is considered as [1,4,5,6,7,8] /// [<1>, <4,8>] is considered as [1,4,5,6,7,8]
/// For range [<1>, <4,8>] getSingleValue(3) returns 6. /// For range [<1>, <4,8>] getSingleValue(3) returns 6.
APInt getSingleValue(unsigned idx) const { 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) { for (unsigned i = 0, e = getNumItems(); i != e; ++i) {
const APInt &Low = getItem(i).Low; const APInt &Low = getItem(i).Low;
const APInt &High = getItem(i).High; const APInt &High = getItem(i).High;

View File

@ -67,7 +67,7 @@ protected:
bool Sorted; bool Sorted;
bool isIntersected(CaseItemIt& LItem, CaseItemIt& RItem) { 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) { bool isJoinable(CaseItemIt& LItem, CaseItemIt& RItem) {
@ -79,7 +79,7 @@ protected:
APInt RLow = RItem->first.Low; APInt RLow = RItem->first.Low;
if (RLow != APInt::getNullValue(RLow.getBitWidth())) if (RLow != APInt::getNullValue(RLow.getBitWidth()))
--RLow; --RLow;
return LItem->first.High->uge(RLow); return LItem->first.High >= RLow;
} }
void sort() { void sort() {
@ -159,7 +159,7 @@ public:
if (isJoinable(i, j)) { if (isJoinable(i, j)) {
IntItem *CurHigh = &j->first.High; IntItem *CurHigh = &j->first.High;
++Weight; ++Weight;
if ((*CurHigh)->ugt(*High)) if (*CurHigh > *High)
High = CurHigh; High = CurHigh;
} else { } else {
RangeEx R(*Low, *High, Weight); RangeEx R(*Low, *High, Weight);

View File

@ -655,8 +655,8 @@ void Interpreter::visitSwitchInst(SwitchInst &I) {
for (unsigned n = 0, en = Case.getNumItems(); n != en; ++n) { for (unsigned n = 0, en = Case.getNumItems(); n != en; ++n) {
IntegersSubset::Range r = Case.getItem(n); IntegersSubset::Range r = Case.getItem(n);
// FIXME: Currently work with ConstantInt based numbers. // FIXME: Currently work with ConstantInt based numbers.
const ConstantInt *LowCI = r.Low.getImplementation(); const ConstantInt *LowCI = r.Low.toConstantInt();
const ConstantInt *HighCI = r.High.getImplementation(); const ConstantInt *HighCI = r.High.toConstantInt();
GenericValue Low = getOperandValue(const_cast<ConstantInt*>(LowCI), SF); GenericValue Low = getOperandValue(const_cast<ConstantInt*>(LowCI), SF);
GenericValue High = getOperandValue(const_cast<ConstantInt*>(HighCI), SF); GenericValue High = getOperandValue(const_cast<ConstantInt*>(HighCI), SF);
if (executeICMP_ULE(Low, CondVal, ElTy).IntVal != 0 && if (executeICMP_ULE(Low, CondVal, ElTy).IntVal != 0 &&

View File

@ -813,9 +813,9 @@ void Verifier::visitSwitchInst(SwitchInst &SI) {
IntegersSubset CaseRanges = i.getCaseValueEx(); IntegersSubset CaseRanges = i.getCaseValueEx();
for (unsigned ri = 0, rie = CaseRanges.getNumItems(); ri < rie; ++ri) { for (unsigned ri = 0, rie = CaseRanges.getNumItems(); ri < rie; ++ri) {
IntegersSubset::Range r = CaseRanges.getItem(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); "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); "Switch constants must all be same type as switch value!", &SI);
Mapping.add(r); Mapping.add(r);
RangeSetMap[r] = i.getCaseIndex(); RangeSetMap[r] = i.getCaseIndex();