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