mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-23 14:25:07 +00:00
PR1255: Case Ranges
Implemented IntItem - the wrapper around APInt. Why not to use APInt item directly right now? 1. It will very difficult to implement case ranges as series of small patches. We got several large and heavy patches. Each patch will about 90-120 kb. If you replace ConstantInt with APInt in SwitchInst you will need to changes at the same time all Readers,Writers and absolutely all passes that uses SwitchInst. 2. We can implement APInt pool inside and save memory space. E.g. we use several switches that works with 256 bit items (switch on signatures, or strings). We can avoid value duplicates in this case. 3. IntItem can be easyly easily replaced with APInt. 4. Currenly we can interpret IntItem both as ConstantInt and as APInt. It allows to provide SwitchInst methods that works with ConstantInt for non-updated passes. Why I need it right now? Currently I need to update SimplifyCFG pass (EqualityComparisons). I need to work with APInts directly a lot, so peaces of code ConstantInt *V = ...; if (V->getValue().ugt(AnotherV->getValue()) { ... } will look awful. Much more better this way: IntItem V = ConstantIntVal->getValue(); if (AnotherV < V) { } Of course any reviews are welcome. P.S.: I'm also going to rename ConstantRangesSet to IntegersSubset, and CRSBuilder to IntegersSubsetMapping (allows to map individual subsets of integers to the BasicBlocks). Since in future these classes will founded on APInt, it will possible to use them in more generic ways. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@157576 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -21,22 +21,201 @@
|
||||
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/LLVMContext.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class ConstantRangesSet;
|
||||
template <class ImplTy>
|
||||
class IntItemBase {
|
||||
protected:
|
||||
ImplTy Implementation;
|
||||
typedef IntItemBase<ImplTy> self;
|
||||
public:
|
||||
|
||||
template <bool IsReadonly> struct CRSConstantTypes {
|
||||
typedef ConstantInt ConstantIntTy;
|
||||
typedef ConstantRangesSet ConstantRangesSetTy;
|
||||
IntItemBase() {}
|
||||
|
||||
IntItemBase(const ImplTy &impl) : Implementation(impl) {}
|
||||
|
||||
// implicit
|
||||
IntItemBase(const APInt& src) : Implementation(src) {}
|
||||
|
||||
operator const APInt&() const {
|
||||
return (const APInt&)Implementation;
|
||||
}
|
||||
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 {
|
||||
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();
|
||||
}
|
||||
operator const ConstantInt*() {
|
||||
return ConstantIntVal;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct CRSConstantTypes<true> {
|
||||
typedef const ConstantInt ConstantIntTy;
|
||||
typedef const ConstantRangesSet ConstantRangesSetTy;
|
||||
};
|
||||
class IntItem : public IntItemBase<IntItemConstantIntImpl> {
|
||||
typedef IntItemBase<IntItemConstantIntImpl> ParentTy;
|
||||
IntItem(const IntItemConstantIntImpl& Impl) : ParentTy(Impl) {}
|
||||
public:
|
||||
|
||||
IntItem() {}
|
||||
|
||||
// implicit
|
||||
IntItem(const APInt& src) : ParentTy(src) {}
|
||||
|
||||
static IntItem fromConstantInt(const ConstantInt *V) {
|
||||
IntItemConstantIntImpl Impl(V);
|
||||
return IntItem(Impl);
|
||||
}
|
||||
static IntItem fromType(Type* Ty, const APInt& V) {
|
||||
ConstantInt *C = cast<ConstantInt>(ConstantInt::get(Ty, V));
|
||||
return fromConstantInt(C);
|
||||
}
|
||||
ConstantInt *toConstantInt() {
|
||||
return const_cast<ConstantInt*>((const ConstantInt*)Implementation);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: it should be a class in next commit.
|
||||
struct IntRange {
|
||||
|
||||
IntItem Low;
|
||||
IntItem High;
|
||||
bool IsEmpty : 1;
|
||||
bool IsSingleNumber : 1;
|
||||
// TODO:
|
||||
// public:
|
||||
|
||||
typedef std::pair<IntRange, IntRange> SubRes;
|
||||
|
||||
IntRange() : IsEmpty(true) {}
|
||||
IntRange(const IntRange &RHS) :
|
||||
Low(RHS.Low), High(RHS.High), IsEmpty(false), IsSingleNumber(false) {}
|
||||
IntRange(const IntItem &C) :
|
||||
Low(C), High(C), IsEmpty(false), IsSingleNumber(true) {}
|
||||
IntRange(const IntItem &L, const IntItem &H) : Low(L), High(H),
|
||||
IsEmpty(false), IsSingleNumber(false) {}
|
||||
|
||||
bool isEmpty() const { return IsEmpty; }
|
||||
bool isSingleNumber() const { return IsSingleNumber; }
|
||||
|
||||
const IntItem& getLow() {
|
||||
assert(!IsEmpty && "Range is empty.");
|
||||
return Low;
|
||||
}
|
||||
const IntItem& getHigh() {
|
||||
assert(!IsEmpty && "Range is empty.");
|
||||
return High;
|
||||
}
|
||||
|
||||
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))
|
||||
return true;
|
||||
return false;
|
||||
} else
|
||||
return Low->getBitWidth() < RHS.Low->getBitWidth();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool operator!=(const IntRange &RHS) const {
|
||||
return !operator ==(RHS);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool isInRange(const APInt &IntVal) const {
|
||||
assert(!IsEmpty && "Range is empty.");
|
||||
if (IntVal.getBitWidth() != Low->getBitWidth())
|
||||
return false;
|
||||
return IntVal.uge(Low) && IntVal.ule(High);
|
||||
}
|
||||
|
||||
SubRes sub(const IntRange &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(IntRange(Low, High), IntRange());
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
if (Low->ult(RHS.Low)) {
|
||||
Res.first.Low = Low;
|
||||
APInt NewHigh = RHS.Low;
|
||||
--NewHigh;
|
||||
Res.first.High = NewHigh;
|
||||
}
|
||||
if (High->ugt(RHS.High)) {
|
||||
APInt NewLow = RHS.High;
|
||||
++NewLow;
|
||||
Res.second.Low = NewLow;
|
||||
Res.second.High = High;
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// ConstantRangesSet - class that implements constant set of ranges.
|
||||
/// It is a wrapper for some real "holder" class (currently ConstantArray).
|
||||
@@ -62,112 +241,13 @@ public:
|
||||
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;
|
||||
typedef IntRange 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();
|
||||
bool isSatisfies(const IntItem &CheckingVal) const {
|
||||
for (unsigned i = 0, e = getNumItems(); i < e; ++i) {
|
||||
const Constant *CV = Array->getAggregateElement(i);
|
||||
unsigned VecSize = cast<VectorType>(CV->getType())->getNumElements();
|
||||
@@ -200,11 +280,13 @@ public:
|
||||
unsigned NumEls = cast<VectorType>(CV->getType())->getNumElements();
|
||||
switch (NumEls) {
|
||||
case 1:
|
||||
return Range(cast<ConstantInt>(CV->getAggregateElement(0U)),
|
||||
cast<ConstantInt>(CV->getAggregateElement(0U)));
|
||||
return Range(IntItem::fromConstantInt(
|
||||
cast<ConstantInt>(CV->getAggregateElement(0U))));
|
||||
case 2:
|
||||
return Range(cast<ConstantInt>(CV->getAggregateElement(0U)),
|
||||
cast<ConstantInt>(CV->getAggregateElement(1)));
|
||||
return Range(IntItem::fromConstantInt(
|
||||
cast<ConstantInt>(CV->getAggregateElement(0U))),
|
||||
IntItem::fromConstantInt(
|
||||
cast<ConstantInt>(CV->getAggregateElement(1U))));
|
||||
default:
|
||||
assert(0 && "Only pairs and single numbers are allowed here.");
|
||||
return Range();
|
||||
@@ -217,15 +299,15 @@ public:
|
||||
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))));
|
||||
return Range(IntItem::fromConstantInt(
|
||||
cast<ConstantInt>(CV->getAggregateElement(0U))),
|
||||
IntItem::fromConstantInt(cast<ConstantInt>(
|
||||
cast<ConstantInt>(CV->getAggregateElement(0U)))));
|
||||
case 2:
|
||||
return Range(cast<ConstantInt>(
|
||||
const_cast<Constant*>(CV->getAggregateElement(0U))),
|
||||
cast<ConstantInt>(
|
||||
const_cast<Constant*>(CV->getAggregateElement(1))));
|
||||
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();
|
||||
@@ -252,7 +334,9 @@ public:
|
||||
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();
|
||||
const APInt &Low = getItem(i).Low;
|
||||
const APInt &High = getItem(i).High;
|
||||
const APInt &S = High - Low;
|
||||
sz += S;
|
||||
}
|
||||
return sz.getZExtValue();
|
||||
@@ -265,11 +349,13 @@ public:
|
||||
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();
|
||||
const APInt &Low = getItem(i).Low;
|
||||
const APInt &High = getItem(i).High;
|
||||
const APInt& S = High - Low;
|
||||
APInt oldSz = sz;
|
||||
sz += S;
|
||||
if (oldSz.uge(i) && sz.ult(i)) {
|
||||
APInt Res = getItem(i).Low->getValue();
|
||||
APInt Res = Low;
|
||||
APInt Offset(oldSz.getBitWidth(), i);
|
||||
Offset -= oldSz;
|
||||
Res += Offset;
|
||||
|
Reference in New Issue
Block a user