summaryrefslogtreecommitdiff
path: root/include/llvm/ConstantRangesSet.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/ConstantRangesSet.h')
-rw-r--r--include/llvm/ConstantRangesSet.h272
1 files changed, 272 insertions, 0 deletions
diff --git a/include/llvm/ConstantRangesSet.h b/include/llvm/ConstantRangesSet.h
new file mode 100644
index 00000000000..2d3ee8bafaf
--- /dev/null
+++ b/include/llvm/ConstantRangesSet.h
@@ -0,0 +1,272 @@
+//===-- 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_ */