Skip to content

Commit

Permalink
PR1255: case ranges.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
kaomoneus committed Jun 1, 2012
1 parent 14f094b commit f8d14c4
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 98 deletions.
4 changes: 2 additions & 2 deletions include/llvm/Instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -2552,13 +2552,13 @@ class SwitchInst : public TerminatorInst {
/// 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();
}
Expand Down
222 changes: 133 additions & 89 deletions include/llvm/Support/IntegersSubset.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
};

Expand Down Expand Up @@ -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;
}

Expand All @@ -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 {
Expand All @@ -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;
Expand Down Expand Up @@ -332,7 +376,7 @@ class IntegersSubset {
/// 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;
Expand All @@ -347,7 +391,7 @@ class IntegersSubset {
/// [<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;
Expand Down
6 changes: 3 additions & 3 deletions include/llvm/Support/IntegersSubsetMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class IntegersSubsetMapping {
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) {
Expand All @@ -79,7 +79,7 @@ class IntegersSubsetMapping {
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() {
Expand Down Expand Up @@ -159,7 +159,7 @@ class IntegersSubsetMapping {
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);
Expand Down
4 changes: 2 additions & 2 deletions lib/ExecutionEngine/Interpreter/Execution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 &&
Expand Down
4 changes: 2 additions & 2 deletions lib/VMCore/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit f8d14c4

Please sign in to comment.