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