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 | |
33 | ItTy OpIt; |
34 | PointerUnion<StructType *, Type *> CurTy; |
35 | enum : uint64_t { Unbounded = -1ull }; |
36 | uint64_t NumElements = Unbounded; |
37 | |
38 | generic_gep_type_iterator() = default; |
39 | |
40 | public: |
41 | using iterator_category = std::forward_iterator_tag; |
42 | using value_type = Type *; |
43 | using difference_type = std::ptrdiff_t; |
44 | using pointer = value_type *; |
45 | using reference = value_type &; |
46 | |
47 | static generic_gep_type_iterator begin(Type *Ty, ItTy It) { |
48 | generic_gep_type_iterator I; |
49 | I.CurTy = Ty; |
50 | I.OpIt = It; |
51 | return I; |
52 | } |
53 | |
54 | static generic_gep_type_iterator end(ItTy It) { |
55 | generic_gep_type_iterator I; |
56 | I.OpIt = It; |
57 | return I; |
58 | } |
59 | |
60 | bool operator==(const generic_gep_type_iterator &x) const { |
61 | return OpIt == x.OpIt; |
62 | } |
63 | |
64 | bool operator!=(const generic_gep_type_iterator &x) const { |
65 | return !operator==(x); |
66 | } |
67 | |
68 | // FIXME: Make this the iterator's operator*() after the 4.0 release. |
69 | // operator*() had a different meaning in earlier releases, so we're |
70 | // temporarily not giving this iterator an operator*() to avoid a subtle |
71 | // semantics break. |
72 | Type *getIndexedType() const { |
73 | if (auto *T = CurTy.dyn_cast<Type *>()) |
74 | return T; |
75 | return CurTy.get<StructType *>()->getTypeAtIndex(getOperand()); |
76 | } |
77 | |
78 | Value *getOperand() const { return const_cast<Value *>(&**OpIt); } |
79 | |
80 | generic_gep_type_iterator &operator++() { // Preincrement |
81 | Type *Ty = getIndexedType(); |
82 | if (auto *ATy = dyn_cast<ArrayType>(Ty)) { |
83 | CurTy = ATy->getElementType(); |
84 | NumElements = ATy->getNumElements(); |
85 | } else if (auto *VTy = dyn_cast<VectorType>(Ty)) { |
86 | CurTy = VTy->getElementType(); |
87 | if (isa<ScalableVectorType>(VTy)) |
88 | NumElements = Unbounded; |
89 | else |
90 | NumElements = cast<FixedVectorType>(VTy)->getNumElements(); |
91 | } else |
92 | CurTy = dyn_cast<StructType>(Ty); |
93 | ++OpIt; |
94 | return *this; |
95 | } |
96 | |
97 | generic_gep_type_iterator operator++(int) { // Postincrement |
98 | generic_gep_type_iterator tmp = *this; |
99 | ++*this; |
100 | return tmp; |
101 | } |
102 | |
103 | // All of the below API is for querying properties of the "outer type", i.e. |
104 | // the type that contains the indexed type. Most of the time this is just |
105 | // the type that was visited immediately prior to the indexed type, but for |
106 | // the first element this is an unbounded array of the GEP's source element |
107 | // type, for which there is no clearly corresponding IR type (we've |
108 | // historically used a pointer type as the outer type in this case, but |
109 | // pointers will soon lose their element type). |
110 | // |
111 | // FIXME: Most current users of this class are just interested in byte |
112 | // offsets (a few need to know whether the outer type is a struct because |
113 | // they are trying to replace a constant with a variable, which is only |
114 | // legal for arrays, e.g. canReplaceOperandWithVariable in SimplifyCFG.cpp); |
115 | // we should provide a more minimal API here that exposes not much more than |
116 | // that. |
117 | |
118 | bool isStruct() const { return CurTy.is<StructType *>(); } |
119 | bool isSequential() const { return CurTy.is<Type *>(); } |
120 | |
121 | StructType *getStructType() const { return CurTy.get<StructType *>(); } |
122 | |
123 | StructType *getStructTypeOrNull() const { |
124 | return CurTy.dyn_cast<StructType *>(); |
125 | } |
126 | |
127 | bool isBoundedSequential() const { |
128 | return isSequential() && NumElements != Unbounded; |
129 | } |
130 | |
131 | uint64_t getSequentialNumElements() const { |
132 | assert(isBoundedSequential()); |
133 | return NumElements; |
134 | } |
135 | }; |
136 | |
137 | using gep_type_iterator = generic_gep_type_iterator<>; |
138 | |
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 | |
146 | inline gep_type_iterator gep_type_end(const User *GEP) { |
147 | return gep_type_iterator::end(GEP->op_end()); |
148 | } |
149 | |
150 | inline gep_type_iterator gep_type_begin(const User &GEP) { |
151 | auto &GEPOp = cast<GEPOperator>(GEP); |
152 | return gep_type_iterator::begin( |
153 | GEPOp.getSourceElementType(), |
154 | GEP.op_begin() + 1); |
155 | } |
156 | |
157 | inline gep_type_iterator gep_type_end(const User &GEP) { |
158 | return gep_type_iterator::end(GEP.op_end()); |
159 | } |
160 | |
161 | template<typename T> |
162 | inline generic_gep_type_iterator<const T *> |
163 | gep_type_begin(Type *Op0, ArrayRef<T> A) { |
164 | return generic_gep_type_iterator<const T *>::begin(Op0, A.begin()); |
165 | } |
166 | |
167 | template<typename T> |
168 | inline generic_gep_type_iterator<const T *> |
169 | gep_type_end(Type * /*Op0*/, ArrayRef<T> A) { |
170 | return generic_gep_type_iterator<const T *>::end(A.end()); |
171 | } |
172 | |
173 | } // end namespace llvm |
174 | |
175 | #endif // LLVM_IR_GETELEMENTPTRTYPEITERATOR_H |
176 | |