Home | History | Annotate | Line # | Download | only in IR
      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