• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- GetElementPtrTypeIterator.h ------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements an iterator for walking through the types indexed by
11 // getelementptr instructions.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_IR_GETELEMENTPTRTYPEITERATOR_H
16 #define LLVM_IR_GETELEMENTPTRTYPEITERATOR_H
17 
18 #include "llvm/ADT/ArrayRef.h"
19 #include "llvm/ADT/PointerUnion.h"
20 #include "llvm/IR/DerivedTypes.h"
21 #include "llvm/IR/Operator.h"
22 #include "llvm/IR/User.h"
23 #include "llvm/Support/Casting.h"
24 #include <cassert>
25 #include <cstddef>
26 #include <cstdint>
27 #include <iterator>
28 
29 namespace llvm {
30 
31   template<typename ItTy = User::const_op_iterator>
32   class generic_gep_type_iterator
33     : public std::iterator<std::forward_iterator_tag, Type *, ptrdiff_t> {
34     using super = std::iterator<std::forward_iterator_tag, Type *, ptrdiff_t>;
35 
36     ItTy OpIt;
37     PointerUnion<StructType *, Type *> CurTy;
38     enum : uint64_t { Unbounded = -1ull };
39     uint64_t NumElements = Unbounded;
40 
41     generic_gep_type_iterator() = default;
42 
43   public:
begin(Type * Ty,ItTy It)44     static generic_gep_type_iterator begin(Type *Ty, ItTy It) {
45       generic_gep_type_iterator I;
46       I.CurTy = Ty;
47       I.OpIt = It;
48       return I;
49     }
50 
end(ItTy It)51     static generic_gep_type_iterator end(ItTy It) {
52       generic_gep_type_iterator I;
53       I.OpIt = It;
54       return I;
55     }
56 
57     bool operator==(const generic_gep_type_iterator& x) const {
58       return OpIt == x.OpIt;
59     }
60 
61     bool operator!=(const generic_gep_type_iterator& x) const {
62       return !operator==(x);
63     }
64 
65     // FIXME: Make this the iterator's operator*() after the 4.0 release.
66     // operator*() had a different meaning in earlier releases, so we're
67     // temporarily not giving this iterator an operator*() to avoid a subtle
68     // semantics break.
getIndexedType()69     Type *getIndexedType() const {
70       if (auto *T = CurTy.dyn_cast<Type *>())
71         return T;
72       return CurTy.get<StructType *>()->getTypeAtIndex(getOperand());
73     }
74 
getOperand()75     Value *getOperand() const { return const_cast<Value *>(&**OpIt); }
76 
77     generic_gep_type_iterator& operator++() {   // Preincrement
78       Type *Ty = getIndexedType();
79       if (auto *STy = dyn_cast<SequentialType>(Ty)) {
80         CurTy = STy->getElementType();
81         NumElements = STy->getNumElements();
82       } else
83         CurTy = dyn_cast<StructType>(Ty);
84       ++OpIt;
85       return *this;
86     }
87 
88     generic_gep_type_iterator operator++(int) { // Postincrement
89       generic_gep_type_iterator tmp = *this; ++*this; return tmp;
90     }
91 
92     // All of the below API is for querying properties of the "outer type", i.e.
93     // the type that contains the indexed type. Most of the time this is just
94     // the type that was visited immediately prior to the indexed type, but for
95     // the first element this is an unbounded array of the GEP's source element
96     // type, for which there is no clearly corresponding IR type (we've
97     // historically used a pointer type as the outer type in this case, but
98     // pointers will soon lose their element type).
99     //
100     // FIXME: Most current users of this class are just interested in byte
101     // offsets (a few need to know whether the outer type is a struct because
102     // they are trying to replace a constant with a variable, which is only
103     // legal for arrays, e.g. canReplaceOperandWithVariable in SimplifyCFG.cpp);
104     // we should provide a more minimal API here that exposes not much more than
105     // that.
106 
isStruct()107     bool isStruct() const { return CurTy.is<StructType *>(); }
isSequential()108     bool isSequential() const { return CurTy.is<Type *>(); }
109 
getStructType()110     StructType *getStructType() const { return CurTy.get<StructType *>(); }
111 
getStructTypeOrNull()112     StructType *getStructTypeOrNull() const {
113       return CurTy.dyn_cast<StructType *>();
114     }
115 
isBoundedSequential()116     bool isBoundedSequential() const {
117       return isSequential() && NumElements != Unbounded;
118     }
119 
getSequentialNumElements()120     uint64_t getSequentialNumElements() const {
121       assert(isBoundedSequential());
122       return NumElements;
123     }
124   };
125 
126   using gep_type_iterator = generic_gep_type_iterator<>;
127 
gep_type_begin(const User * GEP)128   inline gep_type_iterator gep_type_begin(const User *GEP) {
129     auto *GEPOp = cast<GEPOperator>(GEP);
130     return gep_type_iterator::begin(
131         GEPOp->getSourceElementType(),
132         GEP->op_begin() + 1);
133   }
134 
gep_type_end(const User * GEP)135   inline gep_type_iterator gep_type_end(const User *GEP) {
136     return gep_type_iterator::end(GEP->op_end());
137   }
138 
gep_type_begin(const User & GEP)139   inline gep_type_iterator gep_type_begin(const User &GEP) {
140     auto &GEPOp = cast<GEPOperator>(GEP);
141     return gep_type_iterator::begin(
142         GEPOp.getSourceElementType(),
143         GEP.op_begin() + 1);
144   }
145 
gep_type_end(const User & GEP)146   inline gep_type_iterator gep_type_end(const User &GEP) {
147     return gep_type_iterator::end(GEP.op_end());
148   }
149 
150   template<typename T>
151   inline generic_gep_type_iterator<const T *>
gep_type_begin(Type * Op0,ArrayRef<T> A)152   gep_type_begin(Type *Op0, ArrayRef<T> A) {
153     return generic_gep_type_iterator<const T *>::begin(Op0, A.begin());
154   }
155 
156   template<typename T>
157   inline generic_gep_type_iterator<const T *>
gep_type_end(Type *,ArrayRef<T> A)158   gep_type_end(Type * /*Op0*/, ArrayRef<T> A) {
159     return generic_gep_type_iterator<const T *>::end(A.end());
160   }
161 
162 } // end namespace llvm
163 
164 #endif // LLVM_IR_GETELEMENTPTRTYPEITERATOR_H
165