[InstCombine] Signed saturation tests. NFC
[llvm-complete.git] / include / llvm / IR / GetElementPtrTypeIterator.h
blob9b257abc7c1f1ea1ff631ee3a14a9e754e7a5118
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.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_IR_GETELEMENTPTRTYPEITERATOR_H
15 #define LLVM_IR_GETELEMENTPTRTYPEITERATOR_H
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>
28 namespace llvm {
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>;
35 ItTy OpIt;
36 PointerUnion<StructType *, Type *> CurTy;
37 enum : uint64_t { Unbounded = -1ull };
38 uint64_t NumElements = Unbounded;
40 generic_gep_type_iterator() = default;
42 public:
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;
50 static generic_gep_type_iterator end(ItTy It) {
51 generic_gep_type_iterator I;
52 I.OpIt = It;
53 return I;
56 bool operator==(const generic_gep_type_iterator& x) const {
57 return OpIt == x.OpIt;
60 bool operator!=(const generic_gep_type_iterator& x) const {
61 return !operator==(x);
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.
68 Type *getIndexedType() const {
69 if (auto *T = CurTy.dyn_cast<Type *>())
70 return T;
71 return CurTy.get<StructType *>()->getTypeAtIndex(getOperand());
74 Value *getOperand() const { return const_cast<Value *>(&**OpIt); }
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;
87 generic_gep_type_iterator operator++(int) { // Postincrement
88 generic_gep_type_iterator tmp = *this; ++*this; return tmp;
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).
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.
106 bool isStruct() const { return CurTy.is<StructType *>(); }
107 bool isSequential() const { return CurTy.is<Type *>(); }
109 StructType *getStructType() const { return CurTy.get<StructType *>(); }
111 StructType *getStructTypeOrNull() const {
112 return CurTy.dyn_cast<StructType *>();
115 bool isBoundedSequential() const {
116 return isSequential() && NumElements != Unbounded;
119 uint64_t getSequentialNumElements() const {
120 assert(isBoundedSequential());
121 return NumElements;
125 using gep_type_iterator = generic_gep_type_iterator<>;
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);
134 inline gep_type_iterator gep_type_end(const User *GEP) {
135 return gep_type_iterator::end(GEP->op_end());
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);
145 inline gep_type_iterator gep_type_end(const User &GEP) {
146 return gep_type_iterator::end(GEP.op_end());
149 template<typename T>
150 inline generic_gep_type_iterator<const T *>
151 gep_type_begin(Type *Op0, ArrayRef<T> A) {
152 return generic_gep_type_iterator<const T *>::begin(Op0, A.begin());
155 template<typename T>
156 inline generic_gep_type_iterator<const T *>
157 gep_type_end(Type * /*Op0*/, ArrayRef<T> A) {
158 return generic_gep_type_iterator<const T *>::end(A.end());
161 } // end namespace llvm
163 #endif // LLVM_IR_GETELEMENTPTRTYPEITERATOR_H