1239310Sdim//===-- llvm/IntegersSubset.h - The subset of integers ----------*- C++ -*-===//
2239310Sdim//
3239310Sdim//                     The LLVM Compiler Infrastructure
4239310Sdim//
5239310Sdim// This file is distributed under the University of Illinois Open Source
6239310Sdim// License. See LICENSE.TXT for details.
7239310Sdim//
8239310Sdim//===----------------------------------------------------------------------===//
9239310Sdim//
10239310Sdim/// @file
11239310Sdim/// This file contains class that implements constant set of ranges:
12239310Sdim/// [<Low0,High0>,...,<LowN,HighN>]. Initially, this class was created for
13239310Sdim/// SwitchInst and was used for case value representation that may contain
14239310Sdim/// multiple ranges for a single successor.
15239310Sdim//
16239310Sdim//===----------------------------------------------------------------------===//
17239310Sdim
18249423Sdim#ifndef LLVM_SUPPORT_INTEGERSSUBSET_H
19249423Sdim#define LLVM_SUPPORT_INTEGERSSUBSET_H
20239310Sdim
21249423Sdim#include "llvm/IR/Constants.h"
22249423Sdim#include "llvm/IR/DerivedTypes.h"
23249423Sdim#include "llvm/IR/LLVMContext.h"
24239310Sdim#include <list>
25239310Sdim
26239310Sdimnamespace llvm {
27239310Sdim
28239310Sdim  // The IntItem is a wrapper for APInt.
29239310Sdim  // 1. It determines sign of integer, it allows to use
30239310Sdim  //    comparison operators >,<,>=,<=, and as result we got shorter and cleaner
31239310Sdim  //    constructions.
32239310Sdim  // 2. It helps to implement PR1255 (case ranges) as a series of small patches.
33239310Sdim  // 3. Currently we can interpret IntItem both as ConstantInt and as APInt.
34239310Sdim  //    It allows to provide SwitchInst methods that works with ConstantInt for
35239310Sdim  //    non-updated passes. And it allows to use APInt interface for new methods.
36239310Sdim  // 4. IntItem can be easily replaced with APInt.
37239310Sdim
38239310Sdim  // The set of macros that allows to propagate APInt operators to the IntItem.
39239310Sdim
40239310Sdim#define INT_ITEM_DEFINE_COMPARISON(op,func) \
41239310Sdim  bool operator op (const APInt& RHS) const { \
42239310Sdim    return getAPIntValue().func(RHS); \
43239310Sdim  }
44239310Sdim
45239310Sdim#define INT_ITEM_DEFINE_UNARY_OP(op) \
46239310Sdim  IntItem operator op () const { \
47239310Sdim    APInt res = op(getAPIntValue()); \
48239310Sdim    Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \
49239310Sdim    return IntItem(cast<ConstantInt>(NewVal)); \
50239310Sdim  }
51239310Sdim
52239310Sdim#define INT_ITEM_DEFINE_BINARY_OP(op) \
53239310Sdim  IntItem operator op (const APInt& RHS) const { \
54239310Sdim    APInt res = getAPIntValue() op RHS; \
55239310Sdim    Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \
56239310Sdim    return IntItem(cast<ConstantInt>(NewVal)); \
57239310Sdim  }
58239310Sdim
59239310Sdim#define INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(op) \
60239310Sdim  IntItem& operator op (const APInt& RHS) {\
61239310Sdim    APInt res = getAPIntValue();\
62239310Sdim    res op RHS; \
63239310Sdim    Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \
64239310Sdim    ConstantIntVal = cast<ConstantInt>(NewVal); \
65239310Sdim    return *this; \
66239310Sdim  }
67239310Sdim
68239310Sdim#define INT_ITEM_DEFINE_PREINCDEC(op) \
69239310Sdim    IntItem& operator op () { \
70239310Sdim      APInt res = getAPIntValue(); \
71239310Sdim      op(res); \
72239310Sdim      Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \
73239310Sdim      ConstantIntVal = cast<ConstantInt>(NewVal); \
74239310Sdim      return *this; \
75239310Sdim    }
76239310Sdim
77239310Sdim#define INT_ITEM_DEFINE_POSTINCDEC(op) \
78239310Sdim    IntItem& operator op (int) { \
79239310Sdim      APInt res = getAPIntValue();\
80239310Sdim      op(res); \
81239310Sdim      Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res); \
82239310Sdim      OldConstantIntVal = ConstantIntVal; \
83239310Sdim      ConstantIntVal = cast<ConstantInt>(NewVal); \
84239310Sdim      return IntItem(OldConstantIntVal); \
85239310Sdim    }
86239310Sdim
87239310Sdim#define INT_ITEM_DEFINE_OP_STANDARD_INT(RetTy, op, IntTy) \
88239310Sdim  RetTy operator op (IntTy RHS) const { \
89239310Sdim    return (*this) op APInt(getAPIntValue().getBitWidth(), RHS); \
90239310Sdim  }
91239310Sdim
92239310Sdimclass IntItem {
93239310Sdim  ConstantInt *ConstantIntVal;
94239310Sdim  const APInt* APIntVal;
95239310Sdim  IntItem(const ConstantInt *V) :
96239310Sdim    ConstantIntVal(const_cast<ConstantInt*>(V)),
97239310Sdim    APIntVal(&ConstantIntVal->getValue()){}
98239310Sdim  const APInt& getAPIntValue() const {
99239310Sdim    return *APIntVal;
100239310Sdim  }
101239310Sdimpublic:
102239310Sdim
103239310Sdim  IntItem() {}
104239310Sdim
105239310Sdim  operator const APInt&() const {
106239310Sdim    return getAPIntValue();
107239310Sdim  }
108239310Sdim
109239310Sdim  // Propagate APInt operators.
110239310Sdim  // Note, that
111239310Sdim  // /,/=,>>,>>= are not implemented in APInt.
112239310Sdim  // <<= is implemented for unsigned RHS, but not implemented for APInt RHS.
113239310Sdim
114239310Sdim  INT_ITEM_DEFINE_COMPARISON(<, ult)
115239310Sdim  INT_ITEM_DEFINE_COMPARISON(>, ugt)
116239310Sdim  INT_ITEM_DEFINE_COMPARISON(<=, ule)
117239310Sdim  INT_ITEM_DEFINE_COMPARISON(>=, uge)
118239310Sdim
119239310Sdim  INT_ITEM_DEFINE_COMPARISON(==, eq)
120239310Sdim  INT_ITEM_DEFINE_OP_STANDARD_INT(bool,==,uint64_t)
121239310Sdim
122239310Sdim  INT_ITEM_DEFINE_COMPARISON(!=, ne)
123239310Sdim  INT_ITEM_DEFINE_OP_STANDARD_INT(bool,!=,uint64_t)
124239310Sdim
125239310Sdim  INT_ITEM_DEFINE_BINARY_OP(*)
126239310Sdim  INT_ITEM_DEFINE_BINARY_OP(+)
127239310Sdim  INT_ITEM_DEFINE_OP_STANDARD_INT(IntItem,+,uint64_t)
128239310Sdim  INT_ITEM_DEFINE_BINARY_OP(-)
129239310Sdim  INT_ITEM_DEFINE_OP_STANDARD_INT(IntItem,-,uint64_t)
130239310Sdim  INT_ITEM_DEFINE_BINARY_OP(<<)
131239310Sdim  INT_ITEM_DEFINE_OP_STANDARD_INT(IntItem,<<,unsigned)
132239310Sdim  INT_ITEM_DEFINE_BINARY_OP(&)
133239310Sdim  INT_ITEM_DEFINE_BINARY_OP(^)
134239310Sdim  INT_ITEM_DEFINE_BINARY_OP(|)
135239310Sdim
136239310Sdim  INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(*=)
137239310Sdim  INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(+=)
138239310Sdim  INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(-=)
139239310Sdim  INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(&=)
140239310Sdim  INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(^=)
141239310Sdim  INT_ITEM_DEFINE_ASSIGNMENT_BY_OP(|=)
142239310Sdim
143239310Sdim  // Special case for <<=
144239310Sdim  IntItem& operator <<= (unsigned RHS) {
145239310Sdim    APInt res = getAPIntValue();
146239310Sdim    res <<= RHS;
147239310Sdim    Constant *NewVal = ConstantInt::get(ConstantIntVal->getContext(), res);
148239310Sdim    ConstantIntVal = cast<ConstantInt>(NewVal);
149239310Sdim    return *this;
150239310Sdim  }
151239310Sdim
152239310Sdim  INT_ITEM_DEFINE_UNARY_OP(-)
153239310Sdim  INT_ITEM_DEFINE_UNARY_OP(~)
154239310Sdim
155239310Sdim  INT_ITEM_DEFINE_PREINCDEC(++)
156239310Sdim  INT_ITEM_DEFINE_PREINCDEC(--)
157239310Sdim
158239310Sdim  // The set of workarounds, since currently we use ConstantInt implemented
159239310Sdim  // integer.
160239310Sdim
161239310Sdim  static IntItem fromConstantInt(const ConstantInt *V) {
162239310Sdim    return IntItem(V);
163239310Sdim  }
164239310Sdim  static IntItem fromType(Type* Ty, const APInt& V) {
165239310Sdim    ConstantInt *C = cast<ConstantInt>(ConstantInt::get(Ty, V));
166239310Sdim    return fromConstantInt(C);
167239310Sdim  }
168239310Sdim  static IntItem withImplLikeThis(const IntItem& LikeThis, const APInt& V) {
169239310Sdim    ConstantInt *C = cast<ConstantInt>(ConstantInt::get(
170239310Sdim        LikeThis.ConstantIntVal->getContext(), V));
171239310Sdim    return fromConstantInt(C);
172239310Sdim  }
173239310Sdim  ConstantInt *toConstantInt() const {
174239310Sdim    return ConstantIntVal;
175239310Sdim  }
176239310Sdim};
177239310Sdim
178239310Sdimtemplate<class IntType>
179239310Sdimclass IntRange {
180239310Sdimprotected:
181239310Sdim    IntType Low;
182239310Sdim    IntType High;
183239310Sdim    bool IsEmpty : 1;
184239310Sdim    bool IsSingleNumber : 1;
185239310Sdim
186239310Sdimpublic:
187239310Sdim    typedef IntRange<IntType> self;
188239310Sdim    typedef std::pair<self, self> SubRes;
189239310Sdim
190239310Sdim    IntRange() : IsEmpty(true) {}
191239310Sdim    IntRange(const self &RHS) :
192239310Sdim      Low(RHS.Low), High(RHS.High),
193239310Sdim      IsEmpty(RHS.IsEmpty), IsSingleNumber(RHS.IsSingleNumber) {}
194239310Sdim    IntRange(const IntType &C) :
195239310Sdim      Low(C), High(C), IsEmpty(false), IsSingleNumber(true) {}
196239310Sdim
197239310Sdim    IntRange(const IntType &L, const IntType &H) : Low(L), High(H),
198239310Sdim      IsEmpty(false), IsSingleNumber(Low == High) {}
199239310Sdim
200239310Sdim    bool isEmpty() const { return IsEmpty; }
201239310Sdim    bool isSingleNumber() const { return IsSingleNumber; }
202239310Sdim
203239310Sdim    const IntType& getLow() const {
204239310Sdim      assert(!IsEmpty && "Range is empty.");
205239310Sdim      return Low;
206239310Sdim    }
207239310Sdim    const IntType& getHigh() const {
208239310Sdim      assert(!IsEmpty && "Range is empty.");
209239310Sdim      return High;
210239310Sdim    }
211239310Sdim
212239310Sdim    bool operator<(const self &RHS) const {
213239310Sdim      assert(!IsEmpty && "Left range is empty.");
214239310Sdim      assert(!RHS.IsEmpty && "Right range is empty.");
215239310Sdim      if (Low == RHS.Low) {
216239310Sdim        if (High > RHS.High)
217239310Sdim          return true;
218239310Sdim        return false;
219239310Sdim      }
220239310Sdim      if (Low < RHS.Low)
221239310Sdim        return true;
222239310Sdim      return false;
223239310Sdim    }
224239310Sdim
225239310Sdim    bool operator==(const self &RHS) const {
226239310Sdim      assert(!IsEmpty && "Left range is empty.");
227239310Sdim      assert(!RHS.IsEmpty && "Right range is empty.");
228239310Sdim      return Low == RHS.Low && High == RHS.High;
229239310Sdim    }
230239310Sdim
231239310Sdim    bool operator!=(const self &RHS) const {
232239310Sdim      return !operator ==(RHS);
233239310Sdim    }
234239310Sdim
235239310Sdim    static bool LessBySize(const self &LHS, const self &RHS) {
236239310Sdim      return (LHS.High - LHS.Low) < (RHS.High - RHS.Low);
237239310Sdim    }
238239310Sdim
239239310Sdim    bool isInRange(const IntType &IntVal) const {
240239310Sdim      assert(!IsEmpty && "Range is empty.");
241239310Sdim      return IntVal >= Low && IntVal <= High;
242239310Sdim    }
243239310Sdim
244239310Sdim    SubRes sub(const self &RHS) const {
245239310Sdim      SubRes Res;
246239310Sdim
247239310Sdim      // RHS is either more global and includes this range or
248239310Sdim      // if it doesn't intersected with this range.
249239310Sdim      if (!isInRange(RHS.Low) && !isInRange(RHS.High)) {
250239310Sdim
251239310Sdim        // If RHS more global (it is enough to check
252239310Sdim        // only one border in this case.
253239310Sdim        if (RHS.isInRange(Low))
254239310Sdim          return std::make_pair(self(Low, High), self());
255239310Sdim
256239310Sdim        return Res;
257239310Sdim      }
258239310Sdim
259239310Sdim      if (Low < RHS.Low) {
260239310Sdim        Res.first.Low = Low;
261239310Sdim        IntType NewHigh = RHS.Low;
262239310Sdim        --NewHigh;
263239310Sdim        Res.first.High = NewHigh;
264239310Sdim      }
265239310Sdim      if (High > RHS.High) {
266239310Sdim        IntType NewLow = RHS.High;
267239310Sdim        ++NewLow;
268239310Sdim        Res.second.Low = NewLow;
269239310Sdim        Res.second.High = High;
270239310Sdim      }
271239310Sdim      return Res;
272239310Sdim    }
273239310Sdim  };
274239310Sdim
275239310Sdim//===----------------------------------------------------------------------===//
276239310Sdim/// IntegersSubsetGeneric - class that implements the subset of integers. It
277239310Sdim/// consists from ranges and single numbers.
278239310Sdimtemplate <class IntTy>
279239310Sdimclass IntegersSubsetGeneric {
280239310Sdimpublic:
281239310Sdim  // Use Chris Lattner idea, that was initially described here:
282239310Sdim  // http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20120213/136954.html
283239310Sdim  // In short, for more compact memory consumption we can store flat
284239310Sdim  // numbers collection, and define range as pair of indices.
285239310Sdim  // In that case we can safe some memory on 32 bit machines.
286239310Sdim  typedef std::vector<IntTy> FlatCollectionTy;
287239310Sdim  typedef std::pair<IntTy*, IntTy*> RangeLinkTy;
288239310Sdim  typedef std::vector<RangeLinkTy> RangeLinksTy;
289239310Sdim  typedef typename RangeLinksTy::const_iterator RangeLinksConstIt;
290239310Sdim
291239310Sdim  typedef IntegersSubsetGeneric<IntTy> self;
292239310Sdim
293239310Sdimprotected:
294239310Sdim
295239310Sdim  FlatCollectionTy FlatCollection;
296239310Sdim  RangeLinksTy RangeLinks;
297239310Sdim
298239310Sdim  bool IsSingleNumber;
299239310Sdim  bool IsSingleNumbersOnly;
300239310Sdim
301239310Sdimpublic:
302239310Sdim
303239310Sdim  template<class RangesCollectionTy>
304239310Sdim  explicit IntegersSubsetGeneric(const RangesCollectionTy& Links) {
305239310Sdim    assert(Links.size() && "Empty ranges are not allowed.");
306239310Sdim
307239310Sdim    // In case of big set of single numbers consumes additional RAM space,
308239310Sdim    // but allows to avoid additional reallocation.
309239310Sdim    FlatCollection.reserve(Links.size() * 2);
310239310Sdim    RangeLinks.reserve(Links.size());
311239310Sdim    IsSingleNumbersOnly = true;
312239310Sdim    for (typename RangesCollectionTy::const_iterator i = Links.begin(),
313239310Sdim         e = Links.end(); i != e; ++i) {
314239310Sdim      RangeLinkTy RangeLink;
315239310Sdim      FlatCollection.push_back(i->getLow());
316239310Sdim      RangeLink.first = &FlatCollection.back();
317239310Sdim      if (i->getLow() != i->getHigh()) {
318239310Sdim        FlatCollection.push_back(i->getHigh());
319239310Sdim        IsSingleNumbersOnly = false;
320239310Sdim      }
321239310Sdim      RangeLink.second = &FlatCollection.back();
322239310Sdim      RangeLinks.push_back(RangeLink);
323239310Sdim    }
324239310Sdim    IsSingleNumber = IsSingleNumbersOnly && RangeLinks.size() == 1;
325239310Sdim  }
326239310Sdim
327239310Sdim  IntegersSubsetGeneric(const self& RHS) {
328239310Sdim    *this = RHS;
329239310Sdim  }
330239310Sdim
331239310Sdim  self& operator=(const self& RHS) {
332239310Sdim    FlatCollection.clear();
333239310Sdim    RangeLinks.clear();
334239310Sdim    FlatCollection.reserve(RHS.RangeLinks.size() * 2);
335239310Sdim    RangeLinks.reserve(RHS.RangeLinks.size());
336239310Sdim    for (RangeLinksConstIt i = RHS.RangeLinks.begin(), e = RHS.RangeLinks.end();
337239310Sdim         i != e; ++i) {
338239310Sdim      RangeLinkTy RangeLink;
339239310Sdim      FlatCollection.push_back(*(i->first));
340239310Sdim      RangeLink.first = &FlatCollection.back();
341239310Sdim      if (i->first != i->second)
342239310Sdim        FlatCollection.push_back(*(i->second));
343239310Sdim      RangeLink.second = &FlatCollection.back();
344239310Sdim      RangeLinks.push_back(RangeLink);
345239310Sdim    }
346239310Sdim    IsSingleNumber = RHS.IsSingleNumber;
347239310Sdim    IsSingleNumbersOnly = RHS.IsSingleNumbersOnly;
348239310Sdim    return *this;
349239310Sdim  }
350239310Sdim
351239310Sdim  typedef IntRange<IntTy> Range;
352239310Sdim
353239310Sdim  /// Checks is the given constant satisfies this case. Returns
354239310Sdim  /// true if it equals to one of contained values or belongs to the one of
355239310Sdim  /// contained ranges.
356239310Sdim  bool isSatisfies(const IntTy &CheckingVal) const {
357239310Sdim    if (IsSingleNumber)
358239310Sdim      return FlatCollection.front() == CheckingVal;
359239310Sdim    if (IsSingleNumbersOnly)
360239310Sdim      return std::find(FlatCollection.begin(),
361239310Sdim                       FlatCollection.end(),
362239310Sdim                       CheckingVal) != FlatCollection.end();
363239310Sdim
364239310Sdim    for (unsigned i = 0, e = getNumItems(); i < e; ++i) {
365239310Sdim      if (RangeLinks[i].first == RangeLinks[i].second) {
366239310Sdim        if (*RangeLinks[i].first == CheckingVal)
367239310Sdim          return true;
368239310Sdim      } else if (*RangeLinks[i].first <= CheckingVal &&
369239310Sdim                 *RangeLinks[i].second >= CheckingVal)
370239310Sdim        return true;
371239310Sdim    }
372239310Sdim    return false;
373239310Sdim  }
374239310Sdim
375239310Sdim  /// Returns set's item with given index.
376239310Sdim  Range getItem(unsigned idx) const {
377239310Sdim    const RangeLinkTy &Link = RangeLinks[idx];
378239310Sdim    if (Link.first != Link.second)
379239310Sdim      return Range(*Link.first, *Link.second);
380239310Sdim    else
381239310Sdim      return Range(*Link.first);
382239310Sdim  }
383239310Sdim
384239310Sdim  /// Return number of items (ranges) stored in set.
385239310Sdim  unsigned getNumItems() const {
386239310Sdim    return RangeLinks.size();
387239310Sdim  }
388239310Sdim
389239310Sdim  /// Returns true if whole subset contains single element.
390239310Sdim  bool isSingleNumber() const {
391239310Sdim    return IsSingleNumber;
392239310Sdim  }
393239310Sdim
394239310Sdim  /// Returns true if whole subset contains only single numbers, no ranges.
395239310Sdim  bool isSingleNumbersOnly() const {
396239310Sdim    return IsSingleNumbersOnly;
397239310Sdim  }
398239310Sdim
399239310Sdim  /// Does the same like getItem(idx).isSingleNumber(), but
400239310Sdim  /// works faster, since we avoid creation of temporary range object.
401239310Sdim  bool isSingleNumber(unsigned idx) const {
402239310Sdim    return RangeLinks[idx].first == RangeLinks[idx].second;
403239310Sdim  }
404239310Sdim
405239310Sdim  /// Returns set the size, that equals number of all values + sizes of all
406239310Sdim  /// ranges.
407239310Sdim  /// Ranges set is considered as flat numbers collection.
408239310Sdim  /// E.g.: for range [<0>, <1>, <4,8>] the size will 7;
409239310Sdim  ///       for range [<0>, <1>, <5>] the size will 3
410239310Sdim  unsigned getSize() const {
411239310Sdim    APInt sz(((const APInt&)getItem(0).getLow()).getBitWidth(), 0);
412239310Sdim    for (unsigned i = 0, e = getNumItems(); i != e; ++i) {
413243830Sdim      const APInt Low = getItem(i).getLow();
414243830Sdim      const APInt High = getItem(i).getHigh();
415239310Sdim      APInt S = High - Low + 1;
416239310Sdim      sz += S;
417239310Sdim    }
418239310Sdim    return sz.getZExtValue();
419239310Sdim  }
420239310Sdim
421239310Sdim  /// Allows to access single value even if it belongs to some range.
422239310Sdim  /// Ranges set is considered as flat numbers collection.
423239310Sdim  /// [<1>, <4,8>] is considered as [1,4,5,6,7,8]
424239310Sdim  /// For range [<1>, <4,8>] getSingleValue(3) returns 6.
425239310Sdim  APInt getSingleValue(unsigned idx) const {
426239310Sdim    APInt sz(((const APInt&)getItem(0).getLow()).getBitWidth(), 0);
427239310Sdim    for (unsigned i = 0, e = getNumItems(); i != e; ++i) {
428243830Sdim      const APInt Low = getItem(i).getLow();
429243830Sdim      const APInt High = getItem(i).getHigh();
430239310Sdim      APInt S = High - Low + 1;
431239310Sdim      APInt oldSz = sz;
432239310Sdim      sz += S;
433239310Sdim      if (sz.ugt(idx)) {
434239310Sdim        APInt Res = Low;
435239310Sdim        APInt Offset(oldSz.getBitWidth(), idx);
436239310Sdim        Offset -= oldSz;
437239310Sdim        Res += Offset;
438239310Sdim        return Res;
439239310Sdim      }
440239310Sdim    }
441239310Sdim    assert(0 && "Index exceeds high border.");
442239310Sdim    return sz;
443239310Sdim  }
444239310Sdim
445239310Sdim  /// Does the same as getSingleValue, but works only if subset contains
446239310Sdim  /// single numbers only.
447239310Sdim  const IntTy& getSingleNumber(unsigned idx) const {
448239310Sdim    assert(IsSingleNumbersOnly && "This method works properly if subset "
449239310Sdim                                  "contains single numbers only.");
450239310Sdim    return FlatCollection[idx];
451239310Sdim  }
452239310Sdim};
453239310Sdim
454239310Sdim//===----------------------------------------------------------------------===//
455239310Sdim/// IntegersSubset - currently is extension of IntegersSubsetGeneric
456239310Sdim/// that also supports conversion to/from Constant* object.
457239310Sdimclass IntegersSubset : public IntegersSubsetGeneric<IntItem> {
458239310Sdim
459239310Sdim  typedef IntegersSubsetGeneric<IntItem> ParentTy;
460239310Sdim
461239310Sdim  Constant *Holder;
462239310Sdim
463239310Sdim  static unsigned getNumItemsFromConstant(Constant *C) {
464239310Sdim    return cast<ArrayType>(C->getType())->getNumElements();
465239310Sdim  }
466239310Sdim
467239310Sdim  static Range getItemFromConstant(Constant *C, unsigned idx) {
468239310Sdim    const Constant *CV = C->getAggregateElement(idx);
469239310Sdim
470239310Sdim    unsigned NumEls = cast<VectorType>(CV->getType())->getNumElements();
471239310Sdim    switch (NumEls) {
472239310Sdim    case 1:
473239310Sdim      return Range(IntItem::fromConstantInt(
474239310Sdim                     cast<ConstantInt>(CV->getAggregateElement(0U))),
475239310Sdim                   IntItem::fromConstantInt(cast<ConstantInt>(
476239310Sdim                     cast<ConstantInt>(CV->getAggregateElement(0U)))));
477239310Sdim    case 2:
478239310Sdim      return Range(IntItem::fromConstantInt(
479239310Sdim                     cast<ConstantInt>(CV->getAggregateElement(0U))),
480239310Sdim                   IntItem::fromConstantInt(
481239310Sdim                   cast<ConstantInt>(CV->getAggregateElement(1))));
482239310Sdim    default:
483239310Sdim      assert(0 && "Only pairs and single numbers are allowed here.");
484239310Sdim      return Range();
485239310Sdim    }
486239310Sdim  }
487239310Sdim
488239310Sdim  std::vector<Range> rangesFromConstant(Constant *C) {
489239310Sdim    unsigned NumItems = getNumItemsFromConstant(C);
490239310Sdim    std::vector<Range> r;
491239310Sdim    r.reserve(NumItems);
492239310Sdim    for (unsigned i = 0, e = NumItems; i != e; ++i)
493239310Sdim      r.push_back(getItemFromConstant(C, i));
494239310Sdim    return r;
495239310Sdim  }
496239310Sdim
497239310Sdimpublic:
498239310Sdim
499239310Sdim  explicit IntegersSubset(Constant *C) : ParentTy(rangesFromConstant(C)),
500239310Sdim                          Holder(C) {}
501239310Sdim
502239310Sdim  IntegersSubset(const IntegersSubset& RHS) :
503239310Sdim    ParentTy(*(const ParentTy *)&RHS), // FIXME: tweak for msvc.
504239310Sdim    Holder(RHS.Holder) {}
505239310Sdim
506239310Sdim  template<class RangesCollectionTy>
507239310Sdim  explicit IntegersSubset(const RangesCollectionTy& Src) : ParentTy(Src) {
508239310Sdim    std::vector<Constant*> Elts;
509239310Sdim    Elts.reserve(Src.size());
510239310Sdim    for (typename RangesCollectionTy::const_iterator i = Src.begin(),
511239310Sdim         e = Src.end(); i != e; ++i) {
512239310Sdim      const Range &R = *i;
513239310Sdim      std::vector<Constant*> r;
514239310Sdim      if (R.isSingleNumber()) {
515239310Sdim        r.reserve(2);
516239310Sdim        // FIXME: Since currently we have ConstantInt based numbers
517239310Sdim        // use hack-conversion of IntItem to ConstantInt
518239310Sdim        r.push_back(R.getLow().toConstantInt());
519239310Sdim        r.push_back(R.getHigh().toConstantInt());
520239310Sdim      } else {
521239310Sdim        r.reserve(1);
522239310Sdim        r.push_back(R.getLow().toConstantInt());
523239310Sdim      }
524239310Sdim      Constant *CV = ConstantVector::get(r);
525239310Sdim      Elts.push_back(CV);
526239310Sdim    }
527239310Sdim    ArrayType *ArrTy =
528239310Sdim        ArrayType::get(Elts.front()->getType(), (uint64_t)Elts.size());
529239310Sdim    Holder = ConstantArray::get(ArrTy, Elts);
530239310Sdim  }
531239310Sdim
532239310Sdim  operator Constant*() { return Holder; }
533239310Sdim  operator const Constant*() const { return Holder; }
534239310Sdim  Constant *operator->() { return Holder; }
535239310Sdim  const Constant *operator->() const { return Holder; }
536239310Sdim};
537239310Sdim
538239310Sdim}
539239310Sdim
540249423Sdim#endif /* CLLVM_SUPPORT_INTEGERSSUBSET_H */
541