//===- GetElementPtrTypeIterator.h ------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements an iterator for walking through the types indexed by // getelementptr instructions. // //===----------------------------------------------------------------------===// #ifndef LLVM_IR_GETELEMENTPTRTYPEITERATOR_H #define LLVM_IR_GETELEMENTPTRTYPEITERATOR_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Operator.h" #include "llvm/IR/User.h" #include "llvm/Support/Casting.h" #include #include #include namespace llvm { template class generic_gep_type_iterator { ItTy OpIt; // We use two different mechanisms to store the type a GEP index applies to. // In some cases, we need to know the outer aggregate type the index is // applied within, e.g. a struct. In such cases, we store the aggregate type // in the iterator, and derive the element type on the fly. // // However, this is not always possible, because for the outermost index there // is no containing type. In such cases, or if the containing type is not // relevant, e.g. for arrays, the element type is stored as Type* in CurTy. // // If CurTy contains a Type* value, this does not imply anything about the // type itself, because it is the element type and not the outer type. // In particular, Type* can be a struct type. // // Consider this example: // // %my.struct = type { i32, [ 4 x float ] } // [...] // %gep = getelementptr %my.struct, ptr %ptr, i32 10, i32 1, 32 3 // // Iterating over the indices of this GEP, CurTy will contain the following // values: // * i32 10: The outer index always operates on the GEP value type. // CurTy contains a Type* pointing at `%my.struct`. // * i32 1: This index is within a struct. // CurTy contains a StructType* pointing at `%my.struct`. // * i32 3: This index is within an array. We reuse the "flat" indexing // for arrays which is also used in the top level GEP index. // CurTy contains a Type* pointing at `float`. // // Vectors are handled separately because the layout of vectors is different // for overaligned elements: Vectors are always bit-packed, whereas arrays // respect ABI alignment of the elements. PointerUnion CurTy; generic_gep_type_iterator() = default; public: using iterator_category = std::forward_iterator_tag; using value_type = Type *; using difference_type = std::ptrdiff_t; using pointer = value_type *; using reference = value_type &; static generic_gep_type_iterator begin(Type *Ty, ItTy It) { generic_gep_type_iterator I; I.CurTy = Ty; I.OpIt = It; return I; } static generic_gep_type_iterator end(ItTy It) { generic_gep_type_iterator I; I.OpIt = It; return I; } bool operator==(const generic_gep_type_iterator &x) const { return OpIt == x.OpIt; } bool operator!=(const generic_gep_type_iterator &x) const { return !operator==(x); } // FIXME: Make this the iterator's operator*() after the 4.0 release. // operator*() had a different meaning in earlier releases, so we're // temporarily not giving this iterator an operator*() to avoid a subtle // semantics break. Type *getIndexedType() const { if (auto *T = dyn_cast_if_present(CurTy)) return T; if (auto *VT = dyn_cast_if_present(CurTy)) return VT->getElementType(); return cast(CurTy)->getTypeAtIndex(getOperand()); } Value *getOperand() const { return const_cast(&**OpIt); } generic_gep_type_iterator &operator++() { // Preincrement Type *Ty = getIndexedType(); if (auto *ATy = dyn_cast(Ty)) CurTy = ATy->getElementType(); else if (auto *VTy = dyn_cast(Ty)) CurTy = VTy; else CurTy = dyn_cast(Ty); ++OpIt; return *this; } generic_gep_type_iterator operator++(int) { // Postincrement generic_gep_type_iterator tmp = *this; ++*this; return tmp; } // All of the below API is for querying properties of the "outer type", i.e. // the type that contains the indexed type. Most of the time this is just // the type that was visited immediately prior to the indexed type, but for // the first element this is an unbounded array of the GEP's source element // type, for which there is no clearly corresponding IR type (we've // historically used a pointer type as the outer type in this case, but // pointers will soon lose their element type). // // FIXME: Most current users of this class are just interested in byte // offsets (a few need to know whether the outer type is a struct because // they are trying to replace a constant with a variable, which is only // legal for arrays, e.g. canReplaceOperandWithVariable in SimplifyCFG.cpp); // we should provide a more minimal API here that exposes not much more than // that. bool isStruct() const { return isa(CurTy); } bool isVector() const { return isa(CurTy); } bool isSequential() const { return !isStruct(); } // For sequential GEP indices (all except those into structs), the index value // can be translated into a byte offset by multiplying with an element stride. // This function returns this stride, which both depends on the element type, // and the containing aggregate type, as vectors always tightly bit-pack their // elements. TypeSize getSequentialElementStride(const DataLayout &DL) const { assert(isSequential()); Type *ElemTy = getIndexedType(); if (isVector()) { assert(DL.typeSizeEqualsStoreSize(ElemTy) && "Not byte-addressable"); return DL.getTypeStoreSize(ElemTy); } return DL.getTypeAllocSize(ElemTy); } StructType *getStructType() const { return cast(CurTy); } StructType *getStructTypeOrNull() const { return dyn_cast_if_present(CurTy); } }; using gep_type_iterator = generic_gep_type_iterator<>; inline gep_type_iterator gep_type_begin(const User *GEP) { auto *GEPOp = cast(GEP); return gep_type_iterator::begin( GEPOp->getSourceElementType(), GEP->op_begin() + 1); } inline gep_type_iterator gep_type_end(const User *GEP) { return gep_type_iterator::end(GEP->op_end()); } inline gep_type_iterator gep_type_begin(const User &GEP) { auto &GEPOp = cast(GEP); return gep_type_iterator::begin( GEPOp.getSourceElementType(), GEP.op_begin() + 1); } inline gep_type_iterator gep_type_end(const User &GEP) { return gep_type_iterator::end(GEP.op_end()); } template inline generic_gep_type_iterator gep_type_begin(Type *Op0, ArrayRef A) { return generic_gep_type_iterator::begin(Op0, A.begin()); } template inline generic_gep_type_iterator gep_type_end(Type * /*Op0*/, ArrayRef A) { return generic_gep_type_iterator::end(A.end()); } } // end namespace llvm #endif // LLVM_IR_GETELEMENTPTRTYPEITERATOR_H