Home | History | Annotate | Download | only in IR
      1 //===- GetElementPtrTypeIterator.h ------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file implements an iterator for walking through the types indexed by
     11 // getelementptr instructions.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #ifndef LLVM_IR_GETELEMENTPTRTYPEITERATOR_H
     16 #define LLVM_IR_GETELEMENTPTRTYPEITERATOR_H
     17 
     18 #include "llvm/ADT/ArrayRef.h"
     19 #include "llvm/ADT/PointerUnion.h"
     20 #include "llvm/IR/DerivedTypes.h"
     21 #include "llvm/IR/Operator.h"
     22 #include "llvm/IR/User.h"
     23 #include "llvm/Support/Casting.h"
     24 #include <cassert>
     25 #include <cstddef>
     26 #include <cstdint>
     27 #include <iterator>
     28 
     29 namespace llvm {
     30 
     31   template<typename ItTy = User::const_op_iterator>
     32   class generic_gep_type_iterator
     33     : public std::iterator<std::forward_iterator_tag, Type *, ptrdiff_t> {
     34     using super = std::iterator<std::forward_iterator_tag, Type *, ptrdiff_t>;
     35 
     36     ItTy OpIt;
     37     PointerUnion<StructType *, Type *> CurTy;
     38     enum : uint64_t { Unbounded = -1ull };
     39     uint64_t NumElements = Unbounded;
     40 
     41     generic_gep_type_iterator() = default;
     42 
     43   public:
     44     static generic_gep_type_iterator begin(Type *Ty, ItTy It) {
     45       generic_gep_type_iterator I;
     46       I.CurTy = Ty;
     47       I.OpIt = It;
     48       return I;
     49     }
     50 
     51     static generic_gep_type_iterator end(ItTy It) {
     52       generic_gep_type_iterator I;
     53       I.OpIt = It;
     54       return I;
     55     }
     56 
     57     bool operator==(const generic_gep_type_iterator& x) const {
     58       return OpIt == x.OpIt;
     59     }
     60 
     61     bool operator!=(const generic_gep_type_iterator& x) const {
     62       return !operator==(x);
     63     }
     64 
     65     // FIXME: Make this the iterator's operator*() after the 4.0 release.
     66     // operator*() had a different meaning in earlier releases, so we're
     67     // temporarily not giving this iterator an operator*() to avoid a subtle
     68     // semantics break.
     69     Type *getIndexedType() const {
     70       if (auto *T = CurTy.dyn_cast<Type *>())
     71         return T;
     72       return CurTy.get<StructType *>()->getTypeAtIndex(getOperand());
     73     }
     74 
     75     Value *getOperand() const { return const_cast<Value *>(&**OpIt); }
     76 
     77     generic_gep_type_iterator& operator++() {   // Preincrement
     78       Type *Ty = getIndexedType();
     79       if (auto *STy = dyn_cast<SequentialType>(Ty)) {
     80         CurTy = STy->getElementType();
     81         NumElements = STy->getNumElements();
     82       } else
     83         CurTy = dyn_cast<StructType>(Ty);
     84       ++OpIt;
     85       return *this;
     86     }
     87 
     88     generic_gep_type_iterator operator++(int) { // Postincrement
     89       generic_gep_type_iterator tmp = *this; ++*this; return tmp;
     90     }
     91 
     92     // All of the below API is for querying properties of the "outer type", i.e.
     93     // the type that contains the indexed type. Most of the time this is just
     94     // the type that was visited immediately prior to the indexed type, but for
     95     // the first element this is an unbounded array of the GEP's source element
     96     // type, for which there is no clearly corresponding IR type (we've
     97     // historically used a pointer type as the outer type in this case, but
     98     // pointers will soon lose their element type).
     99     //
    100     // FIXME: Most current users of this class are just interested in byte
    101     // offsets (a few need to know whether the outer type is a struct because
    102     // they are trying to replace a constant with a variable, which is only
    103     // legal for arrays, e.g. canReplaceOperandWithVariable in SimplifyCFG.cpp);
    104     // we should provide a more minimal API here that exposes not much more than
    105     // that.
    106 
    107     bool isStruct() const { return CurTy.is<StructType *>(); }
    108     bool isSequential() const { return CurTy.is<Type *>(); }
    109 
    110     StructType *getStructType() const { return CurTy.get<StructType *>(); }
    111 
    112     StructType *getStructTypeOrNull() const {
    113       return CurTy.dyn_cast<StructType *>();
    114     }
    115 
    116     bool isBoundedSequential() const {
    117       return isSequential() && NumElements != Unbounded;
    118     }
    119 
    120     uint64_t getSequentialNumElements() const {
    121       assert(isBoundedSequential());
    122       return NumElements;
    123     }
    124   };
    125 
    126   using gep_type_iterator = generic_gep_type_iterator<>;
    127 
    128   inline gep_type_iterator gep_type_begin(const User *GEP) {
    129     auto *GEPOp = cast<GEPOperator>(GEP);
    130     return gep_type_iterator::begin(
    131         GEPOp->getSourceElementType(),
    132         GEP->op_begin() + 1);
    133   }
    134 
    135   inline gep_type_iterator gep_type_end(const User *GEP) {
    136     return gep_type_iterator::end(GEP->op_end());
    137   }
    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   template<typename T>
    151   inline generic_gep_type_iterator<const T *>
    152   gep_type_begin(Type *Op0, ArrayRef<T> A) {
    153     return generic_gep_type_iterator<const T *>::begin(Op0, A.begin());
    154   }
    155 
    156   template<typename T>
    157   inline generic_gep_type_iterator<const T *>
    158   gep_type_end(Type * /*Op0*/, ArrayRef<T> A) {
    159     return generic_gep_type_iterator<const T *>::end(A.end());
    160   }
    161 
    162 } // end namespace llvm
    163 
    164 #endif // LLVM_IR_GETELEMENTPTRTYPEITERATOR_H
    165