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
28namespace llvm {
29
30template <typename ItTy = User::const_op_iterator>
31class 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
40public:
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