blob: 1092b636e023a2c31aab13fe57e29fb722e7ac9d [file] [log] [blame]
//===- 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 <cstddef>
#include <cstdint>
#include <iterator>
namespace llvm {
template <typename ItTy = User::const_op_iterator>
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<StructType *, VectorType *, Type *> 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<Type *>(CurTy))
return T;
if (auto *VT = dyn_cast_if_present<VectorType *>(CurTy))
return VT->getElementType();
return cast<StructType *>(CurTy)->getTypeAtIndex(getOperand());
}
Value *getOperand() const { return const_cast<Value *>(&**OpIt); }
generic_gep_type_iterator &operator++() { // Preincrement
Type *Ty = getIndexedType();
if (auto *ATy = dyn_cast<ArrayType>(Ty))
CurTy = ATy->getElementType();
else if (auto *VTy = dyn_cast<VectorType>(Ty))
CurTy = VTy;
else
CurTy = dyn_cast<StructType>(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<StructType *>(CurTy); }
bool isVector() const { return isa<VectorType *>(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<StructType *>(CurTy); }
StructType *getStructTypeOrNull() const {
return dyn_cast_if_present<StructType *>(CurTy);
}
};
using gep_type_iterator = generic_gep_type_iterator<>;
inline gep_type_iterator gep_type_begin(const User *GEP) {
auto *GEPOp = cast<GEPOperator>(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<GEPOperator>(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<typename T>
inline generic_gep_type_iterator<const T *>
gep_type_begin(Type *Op0, ArrayRef<T> A) {
return generic_gep_type_iterator<const T *>::begin(Op0, A.begin());
}
template<typename T>
inline generic_gep_type_iterator<const T *>
gep_type_end(Type * /*Op0*/, ArrayRef<T> A) {
return generic_gep_type_iterator<const T *>::end(A.end());
}
} // end namespace llvm
#endif // LLVM_IR_GETELEMENTPTRTYPEITERATOR_H