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