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 36 generic_gep_type_iterator() = default; 37 38 public: 39 using iterator_category = std::forward_iterator_tag; 40 using value_type = Type *; 41 using difference_type = std::ptrdiff_t; 42 using pointer = value_type *; 43 using reference = value_type &; 44 45 static generic_gep_type_iterator begin(Type *Ty, ItTy It) { 46 generic_gep_type_iterator I; 47 I.CurTy = Ty; 48 I.OpIt = It; 49 return I; 50 } 51 52 static generic_gep_type_iterator end(ItTy It) { 53 generic_gep_type_iterator I; 54 I.OpIt = It; 55 return I; 56 } 57 58 bool operator==(const generic_gep_type_iterator &x) const { 59 return OpIt == x.OpIt; 60 } 61 62 bool operator!=(const generic_gep_type_iterator &x) const { 63 return !operator==(x); 64 } 65 66 // FIXME: Make this the iterator's operator*() after the 4.0 release. 67 // operator*() had a different meaning in earlier releases, so we're 68 // temporarily not giving this iterator an operator*() to avoid a subtle 69 // semantics break. 70 Type *getIndexedType() const { 71 if (auto *T = CurTy.dyn_cast<Type *>()) 72 return T; 73 return CurTy.get<StructType *>()->getTypeAtIndex(getOperand()); 74 } 75 76 Value *getOperand() const { return const_cast<Value *>(&**OpIt); } 77 78 generic_gep_type_iterator &operator++() { // Preincrement 79 Type *Ty = getIndexedType(); 80 if (auto *ATy = dyn_cast<ArrayType>(Ty)) 81 CurTy = ATy->getElementType(); 82 else if (auto *VTy = dyn_cast<VectorType>(Ty)) 83 CurTy = VTy->getElementType(); 84 else 85 CurTy = dyn_cast<StructType>(Ty); 86 ++OpIt; 87 return *this; 88 } 89 90 generic_gep_type_iterator operator++(int) { // Postincrement 91 generic_gep_type_iterator tmp = *this; 92 ++*this; 93 return tmp; 94 } 95 96 // All of the below API is for querying properties of the "outer type", i.e. 97 // the type that contains the indexed type. Most of the time this is just 98 // the type that was visited immediately prior to the indexed type, but for 99 // the first element this is an unbounded array of the GEP's source element 100 // type, for which there is no clearly corresponding IR type (we've 101 // historically used a pointer type as the outer type in this case, but 102 // pointers will soon lose their element type). 103 // 104 // FIXME: Most current users of this class are just interested in byte 105 // offsets (a few need to know whether the outer type is a struct because 106 // they are trying to replace a constant with a variable, which is only 107 // legal for arrays, e.g. canReplaceOperandWithVariable in SimplifyCFG.cpp); 108 // we should provide a more minimal API here that exposes not much more than 109 // that. 110 111 bool isStruct() const { return CurTy.is<StructType *>(); } 112 bool isSequential() const { return CurTy.is<Type *>(); } 113 114 StructType *getStructType() const { return CurTy.get<StructType *>(); } 115 116 StructType *getStructTypeOrNull() const { 117 return CurTy.dyn_cast<StructType *>(); 118 } 119 }; 120 121 using gep_type_iterator = generic_gep_type_iterator<>; 122 123 inline gep_type_iterator gep_type_begin(const User *GEP) { 124 auto *GEPOp = cast<GEPOperator>(GEP); 125 return gep_type_iterator::begin( 126 GEPOp->getSourceElementType(), 127 GEP->op_begin() + 1); 128 } 129 130 inline gep_type_iterator gep_type_end(const User *GEP) { 131 return gep_type_iterator::end(GEP->op_end()); 132 } 133 134 inline gep_type_iterator gep_type_begin(const User &GEP) { 135 auto &GEPOp = cast<GEPOperator>(GEP); 136 return gep_type_iterator::begin( 137 GEPOp.getSourceElementType(), 138 GEP.op_begin() + 1); 139 } 140 141 inline gep_type_iterator gep_type_end(const User &GEP) { 142 return gep_type_iterator::end(GEP.op_end()); 143 } 144 145 template<typename T> 146 inline generic_gep_type_iterator<const T *> 147 gep_type_begin(Type *Op0, ArrayRef<T> A) { 148 return generic_gep_type_iterator<const T *>::begin(Op0, A.begin()); 149 } 150 151 template<typename T> 152 inline generic_gep_type_iterator<const T *> 153 gep_type_end(Type * /*Op0*/, ArrayRef<T> A) { 154 return generic_gep_type_iterator<const T *>::end(A.end()); 155 } 156 157 } // end namespace llvm 158 159 #endif // LLVM_IR_GETELEMENTPTRTYPEITERATOR_H 160