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 : public std::iterator<std::forward_iterator_tag, Type *, ptrdiff_t> { 33 using super = std::iterator<std::forward_iterator_tag, Type *, ptrdiff_t>; 34 35 ItTy OpIt; 36 PointerUnion<StructType *, Type *> CurTy; 37 enum : uint64_t { Unbounded = -1ull }; 38 uint64_t NumElements = Unbounded; 39 40 generic_gep_type_iterator() = default; 41 42 public: begin(Type * Ty,ItTy It)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; 48 } 49 end(ItTy It)50 static generic_gep_type_iterator end(ItTy It) { 51 generic_gep_type_iterator I; 52 I.OpIt = It; 53 return I; 54 } 55 56 bool operator==(const generic_gep_type_iterator& x) const { 57 return OpIt == x.OpIt; 58 } 59 60 bool operator!=(const generic_gep_type_iterator& x) const { 61 return !operator==(x); 62 } 63 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. getIndexedType()68 Type *getIndexedType() const { 69 if (auto *T = CurTy.dyn_cast<Type *>()) 70 return T; 71 return CurTy.get<StructType *>()->getTypeAtIndex(getOperand()); 72 } 73 getOperand()74 Value *getOperand() const { return const_cast<Value *>(&**OpIt); } 75 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; 85 } 86 87 generic_gep_type_iterator operator++(int) { // Postincrement 88 generic_gep_type_iterator tmp = *this; ++*this; return tmp; 89 } 90 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). 98 // 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. 105 isStruct()106 bool isStruct() const { return CurTy.is<StructType *>(); } isSequential()107 bool isSequential() const { return CurTy.is<Type *>(); } 108 getStructType()109 StructType *getStructType() const { return CurTy.get<StructType *>(); } 110 getStructTypeOrNull()111 StructType *getStructTypeOrNull() const { 112 return CurTy.dyn_cast<StructType *>(); 113 } 114 isBoundedSequential()115 bool isBoundedSequential() const { 116 return isSequential() && NumElements != Unbounded; 117 } 118 getSequentialNumElements()119 uint64_t getSequentialNumElements() const { 120 assert(isBoundedSequential()); 121 return NumElements; 122 } 123 }; 124 125 using gep_type_iterator = generic_gep_type_iterator<>; 126 gep_type_begin(const User * GEP)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); 132 } 133 gep_type_end(const User * GEP)134 inline gep_type_iterator gep_type_end(const User *GEP) { 135 return gep_type_iterator::end(GEP->op_end()); 136 } 137 gep_type_begin(const User & GEP)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); 143 } 144 gep_type_end(const User & GEP)145 inline gep_type_iterator gep_type_end(const User &GEP) { 146 return gep_type_iterator::end(GEP.op_end()); 147 } 148 149 template<typename T> 150 inline generic_gep_type_iterator<const T *> gep_type_begin(Type * Op0,ArrayRef<T> A)151 gep_type_begin(Type *Op0, ArrayRef<T> A) { 152 return generic_gep_type_iterator<const T *>::begin(Op0, A.begin()); 153 } 154 155 template<typename T> 156 inline generic_gep_type_iterator<const T *> gep_type_end(Type *,ArrayRef<T> A)157 gep_type_end(Type * /*Op0*/, ArrayRef<T> A) { 158 return generic_gep_type_iterator<const T *>::end(A.end()); 159 } 160 161 } // end namespace llvm 162 163 #endif // LLVM_IR_GETELEMENTPTRTYPEITERATOR_H 164