1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-01 16:33:37 +01:00
llvm-mirror/include/llvm/ConstantRangesSet.h
2012-05-08 08:33:21 +00:00

273 lines
9.3 KiB
C++

//===-- llvm/ConstantRangesSet.h - The constant set of ranges ---*- 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>]. Mainly, this set is used by SwitchInst and
/// represents case value that may contain multiple ranges for a single
/// successor.
///
//
//===----------------------------------------------------------------------===//
#ifndef CONSTANTRANGESSET_H_
#define CONSTANTRANGESSET_H_
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
namespace llvm {
class ConstantRangesSet;
template <bool IsReadonly> struct CRSConstantTypes {
typedef ConstantInt ConstantIntTy;
typedef ConstantRangesSet ConstantRangesSetTy;
};
template <>
struct CRSConstantTypes<true> {
typedef const ConstantInt ConstantIntTy;
typedef const ConstantRangesSet ConstantRangesSetTy;
};
//===----------------------------------------------------------------------===//
/// ConstantRangesSet - class that implements constant set of ranges.
/// It is a wrapper for some real "holder" class (currently ConstantArray).
/// It contains functions, that allows to parse "holder" like a set of ranges.
/// Note: It is assumed that "holder" is inherited from Constant object.
/// ConstantRangesSet may be converted to and from Constant* pointer.
///
class ConstantRangesSet {
Constant *Array;
public:
// implicit
ConstantRangesSet(Constant *V) : Array(V) {}
operator Constant*() { return Array; }
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;
/// 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();
for (unsigned i = 0, e = getNumItems(); i < e; ++i) {
const Constant *CV = Array->getAggregateElement(i);
unsigned VecSize = cast<VectorType>(CV->getType())->getNumElements();
switch (VecSize) {
case 1:
if (cast<const ConstantInt>(CV->getAggregateElement(0U))->getValue() ==
CheckingVal)
return true;
break;
case 2: {
const APInt &Lo =
cast<const ConstantInt>(CV->getAggregateElement(0U))->getValue();
const APInt &Hi =
cast<const ConstantInt>(CV->getAggregateElement(1))->getValue();
if (Lo.uge(CheckingVal) && Hi.ule(CheckingVal))
return true;
}
break;
default:
assert(0 && "Only pairs and single numbers are allowed here.");
break;
}
}
return false;
}
/// Returns set's item with given index.
Range getItem(unsigned idx) {
Constant *CV = Array->getAggregateElement(idx);
unsigned NumEls = cast<VectorType>(CV->getType())->getNumElements();
switch (NumEls) {
case 1:
return Range(cast<ConstantInt>(CV->getAggregateElement(0U)),
cast<ConstantInt>(CV->getAggregateElement(0U)));
case 2:
return Range(cast<ConstantInt>(CV->getAggregateElement(0U)),
cast<ConstantInt>(CV->getAggregateElement(1)));
default:
assert(0 && "Only pairs and single numbers are allowed here.");
return Range();
}
}
const Range getItem(unsigned idx) const {
const Constant *CV = Array->getAggregateElement(idx);
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))));
case 2:
return Range(cast<ConstantInt>(
const_cast<Constant*>(CV->getAggregateElement(0U))),
cast<ConstantInt>(
const_cast<Constant*>(CV->getAggregateElement(1))));
default:
assert(0 && "Only pairs and single numbers are allowed here.");
return Range();
}
}
/// Return number of items (ranges) stored in set.
unsigned getNumItems() const {
return cast<ArrayType>(Array->getType())->getNumElements();
}
/// 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(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();
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(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();
APInt oldSz = sz;
sz += S;
if (oldSz.uge(i) && sz.ult(i)) {
APInt Res = getItem(i).Low->getValue();
APInt Offset(oldSz.getBitWidth(), i);
Offset -= oldSz;
Res += Offset;
return Res;
}
}
assert(0 && "Index exceeds high border.");
return sz;
}
};
}
#endif /* CONSTANTRANGESSET_H_ */