[llvm] r341269 - [Constant Hoisting] Hoisting Constant GEP Expressions

Chandler Carruth via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 4 06:41:32 PDT 2018


Redirecting to Eli as Zhaoshi's email is bouncing now and maybe Eli knows
who can take a look at this....

On Tue, Sep 4, 2018 at 3:38 PM Chandler Carruth <chandlerc at gmail.com> wrote:

> On Sat, Sep 1, 2018 at 2:05 AM Zhaoshi Zheng via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
>> Author: zzheng
>> Date: Fri Aug 31 17:04:56 2018
>> New Revision: 341269
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=341269&view=rev
>> Log:
>> [Constant Hoisting] Hoisting Constant GEP Expressions
>>
>> Leverage existing logic in constant hoisting pass to transform constant
>> GEP
>> expressions sharing the same base global variable. Multi-dimensional GEPs
>> are
>> rewritten into single-dimensional GEPs.
>>
>> Differential Revision: https://reviews.llvm.org/D51396
>>
>> Added:
>>     llvm/trunk/test/CodeGen/AArch64/consthoist-gep.ll
>>     llvm/trunk/test/Transforms/ConstantHoisting/AArch64/const-hoist-gep.ll
>>     llvm/trunk/test/Transforms/ConstantHoisting/ARM/const-hoist-gep.ll
>>
>> llvm/trunk/test/Transforms/ConstantHoisting/ARM/same-offset-multi-types.ll
>>
>
> This last test fails about 50% of the time when expensive checks are
> enabled. An example flaky failure:
>
> http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-checks-win/builds/12224/steps/test-check-all/logs/stdio
>
> You should be able to reproduce it locally though, I did immediately when
> I enabled expensive checks.
>
> I've reverted this temporarily in r341365 so the bots stop failing
> randomly until you or someone else can look into what the issue is and how
> to fix it.
>
>
>> Modified:
>>     llvm/trunk/include/llvm/Transforms/Scalar/ConstantHoisting.h
>>     llvm/trunk/lib/Transforms/Scalar/ConstantHoisting.cpp
>>
>> Modified: llvm/trunk/include/llvm/Transforms/Scalar/ConstantHoisting.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Scalar/ConstantHoisting.h?rev=341269&r1=341268&r2=341269&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/Transforms/Scalar/ConstantHoisting.h
>> (original)
>> +++ llvm/trunk/include/llvm/Transforms/Scalar/ConstantHoisting.h Fri Aug
>> 31 17:04:56 2018
>> @@ -38,6 +38,7 @@
>>  #define LLVM_TRANSFORMS_SCALAR_CONSTANTHOISTING_H
>>
>>  #include "llvm/ADT/DenseMap.h"
>> +#include "llvm/ADT/PointerUnion.h"
>>  #include "llvm/ADT/SmallPtrSet.h"
>>  #include "llvm/ADT/SmallVector.h"
>>  #include "llvm/IR/PassManager.h"
>> @@ -50,8 +51,10 @@ class BasicBlock;
>>  class BlockFrequencyInfo;
>>  class Constant;
>>  class ConstantInt;
>> +class ConstantExpr;
>>  class DominatorTree;
>>  class Function;
>> +class GlobalVariable;
>>  class Instruction;
>>  class TargetTransformInfo;
>>
>> @@ -74,10 +77,15 @@ using ConstantUseListType = SmallVector<
>>  /// Keeps track of a constant candidate and its uses.
>>  struct ConstantCandidate {
>>    ConstantUseListType Uses;
>> +  // If the candidate is a ConstantExpr (currely only constant GEP
>> expressions
>> +  // whose base pointers are GlobalVariables are supported), ConstInt
>> records
>> +  // its offset from the base GV, ConstExpr tracks the candidate GEP
>> expr.
>>    ConstantInt *ConstInt;
>> +  ConstantExpr *ConstExpr;
>>    unsigned CumulativeCost = 0;
>>
>> -  ConstantCandidate(ConstantInt *ConstInt) : ConstInt(ConstInt) {}
>> +  ConstantCandidate(ConstantInt *ConstInt, ConstantExpr
>> *ConstExpr=nullptr) :
>> +      ConstInt(ConstInt), ConstExpr(ConstExpr) {}
>>
>>    /// Add the user to the use list and update the cost.
>>    void addUser(Instruction *Inst, unsigned Idx, unsigned Cost) {
>> @@ -91,16 +99,21 @@ struct ConstantCandidate {
>>  struct RebasedConstantInfo {
>>    ConstantUseListType Uses;
>>    Constant *Offset;
>> +  Type *Ty;
>>
>> -  RebasedConstantInfo(ConstantUseListType &&Uses, Constant *Offset)
>> -    : Uses(std::move(Uses)), Offset(Offset) {}
>> +  RebasedConstantInfo(ConstantUseListType &&Uses, Constant *Offset,
>> +      Type *Ty=nullptr) : Uses(std::move(Uses)), Offset(Offset), Ty(Ty)
>> {}
>>  };
>>
>>  using RebasedConstantListType = SmallVector<RebasedConstantInfo, 4>;
>>
>>  /// A base constant and all its rebased constants.
>>  struct ConstantInfo {
>> -  ConstantInt *BaseConstant;
>> +  // If the candidate is a ConstantExpr (currely only constant GEP
>> expressions
>> +  // whose base pointers are GlobalVariables are supported), ConstInt
>> records
>> +  // its offset from the base GV, ConstExpr tracks the candidate GEP
>> expr.
>> +  ConstantInt *BaseInt;
>> +  ConstantExpr *BaseExpr;
>>    RebasedConstantListType RebasedConstants;
>>  };
>>
>> @@ -115,29 +128,43 @@ public:
>>                 BlockFrequencyInfo *BFI, BasicBlock &Entry);
>>
>>    void releaseMemory() {
>> -    ConstantVec.clear();
>>      ClonedCastMap.clear();
>> -    ConstCandVec.clear();
>> +    ConstIntCandVec.clear();
>> +    for (auto MapEntry : ConstGEPCandMap)
>> +      MapEntry.second.clear();
>> +    ConstGEPCandMap.clear();
>> +    ConstIntInfoVec.clear();
>> +    for (auto MapEntry : ConstGEPInfoMap)
>> +      MapEntry.second.clear();
>> +    ConstGEPInfoMap.clear();
>>    }
>>
>>  private:
>> -  using ConstCandMapType = DenseMap<ConstantInt *, unsigned>;
>> -  using ConstCandVecType = std::vector<consthoist::ConstantCandidate>;
>> +  using ConstPtrUnionType = PointerUnion<ConstantInt *, ConstantExpr *>;
>> +  using ConstCandMapType = DenseMap<ConstPtrUnionType, unsigned>;
>>
>>    const TargetTransformInfo *TTI;
>>    DominatorTree *DT;
>>    BlockFrequencyInfo *BFI;
>> +  LLVMContext *Ctx;
>> +  const DataLayout *DL;
>>    BasicBlock *Entry;
>>
>>    /// Keeps track of constant candidates found in the function.
>> -  ConstCandVecType ConstCandVec;
>> +  using ConstCandVecType = std::vector<consthoist::ConstantCandidate>;
>> +  using GVCandVecMapType = DenseMap<GlobalVariable *, ConstCandVecType>;
>> +  ConstCandVecType ConstIntCandVec;
>> +  GVCandVecMapType ConstGEPCandMap;
>> +
>> +  /// These are the final constants we decided to hoist.
>> +  using ConstInfoVecType = SmallVector<consthoist::ConstantInfo, 8>;
>> +  using GVInfoVecMapType = DenseMap<GlobalVariable *, ConstInfoVecType>;
>> +  ConstInfoVecType ConstIntInfoVec;
>> +  GVInfoVecMapType ConstGEPInfoMap;
>>
>>    /// Keep track of cast instructions we already cloned.
>>    SmallDenseMap<Instruction *, Instruction *> ClonedCastMap;
>>
>> -  /// These are the final constants we decided to hoist.
>> -  SmallVector<consthoist::ConstantInfo, 8> ConstantVec;
>> -
>>    Instruction *findMatInsertPt(Instruction *Inst, unsigned Idx = ~0U)
>> const;
>>    SmallPtrSet<Instruction *, 8>
>>    findConstantInsertionPoint(const consthoist::ConstantInfo &ConstInfo)
>> const;
>> @@ -145,19 +172,27 @@ private:
>>                                   Instruction *Inst, unsigned Idx,
>>                                   ConstantInt *ConstInt);
>>    void collectConstantCandidates(ConstCandMapType &ConstCandMap,
>> +                                 Instruction *Inst, unsigned Idx,
>> +                                 ConstantExpr *ConstExpr);
>> +  void collectConstantCandidates(ConstCandMapType &ConstCandMap,
>>                                   Instruction *Inst, unsigned Idx);
>>    void collectConstantCandidates(ConstCandMapType &ConstCandMap,
>>                                   Instruction *Inst);
>>    void collectConstantCandidates(Function &Fn);
>>    void findAndMakeBaseConstant(ConstCandVecType::iterator S,
>> -                               ConstCandVecType::iterator E);
>> +                               ConstCandVecType::iterator E,
>> +      SmallVectorImpl<consthoist::ConstantInfo> &ConstInfoVec);
>>    unsigned maximizeConstantsInRange(ConstCandVecType::iterator S,
>>                                      ConstCandVecType::iterator E,
>>                                      ConstCandVecType::iterator
>> &MaxCostItr);
>> -  void findBaseConstants();
>> -  void emitBaseConstants(Instruction *Base, Constant *Offset,
>> +  // If BaseGV is nullptr, find base among Constant Integer candidates;
>> +  // otherwise find base among constant GEPs sharing BaseGV as base
>> pointer.
>> +  void findBaseConstants(GlobalVariable *BaseGV);
>> +  void emitBaseConstants(Instruction *Base, Constant *Offset, Type *Ty,
>>                           const consthoist::ConstantUser &ConstUser);
>> -  bool emitBaseConstants();
>> +  // If BaseGV is nullptr, emit Constant Integer base; otherwise emit
>> +  // constant GEP base.
>> +  bool emitBaseConstants(GlobalVariable *BaseGV);
>>    void deleteDeadCastInst() const;
>>    bool optimizeConstants(Function &Fn);
>>  };
>>
>> Modified: llvm/trunk/lib/Transforms/Scalar/ConstantHoisting.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/ConstantHoisting.cpp?rev=341269&r1=341268&r2=341269&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/Transforms/Scalar/ConstantHoisting.cpp (original)
>> +++ llvm/trunk/lib/Transforms/Scalar/ConstantHoisting.cpp Fri Aug 31
>> 17:04:56 2018
>> @@ -82,6 +82,10 @@ static cl::opt<bool> ConstHoistWithBlock
>>               "chance to execute const materialization more frequently
>> than "
>>               "without hoisting."));
>>
>> +static cl::opt<bool> ConstHoistGEP(
>> +    "consthoist-gep", cl::init(false), cl::Hidden,
>> +    cl::desc("Try hoisting constant gep expressions"));
>> +
>>  namespace {
>>
>>  /// The constant hoisting pass.
>> @@ -340,7 +344,7 @@ SmallPtrSet<Instruction *, 8> ConstantHo
>>  ///
>>  /// The operand at index Idx is not necessarily the constant integer
>> itself. It
>>  /// could also be a cast instruction or a constant expression that uses
>> the
>> -// constant integer.
>> +/// constant integer.
>>  void ConstantHoistingPass::collectConstantCandidates(
>>      ConstCandMapType &ConstCandMap, Instruction *Inst, unsigned Idx,
>>      ConstantInt *ConstInt) {
>> @@ -358,12 +362,13 @@ void ConstantHoistingPass::collectConsta
>>    if (Cost > TargetTransformInfo::TCC_Basic) {
>>      ConstCandMapType::iterator Itr;
>>      bool Inserted;
>> -    std::tie(Itr, Inserted) =
>> ConstCandMap.insert(std::make_pair(ConstInt, 0));
>> +    ConstPtrUnionType Cand = ConstInt;
>> +    std::tie(Itr, Inserted) = ConstCandMap.insert(std::make_pair(Cand,
>> 0));
>>      if (Inserted) {
>> -      ConstCandVec.push_back(ConstantCandidate(ConstInt));
>> -      Itr->second = ConstCandVec.size() - 1;
>> +      ConstIntCandVec.push_back(ConstantCandidate(ConstInt));
>> +      Itr->second = ConstIntCandVec.size() - 1;
>>      }
>> -    ConstCandVec[Itr->second].addUser(Inst, Idx, Cost);
>> +    ConstIntCandVec[Itr->second].addUser(Inst, Idx, Cost);
>>      LLVM_DEBUG(if (isa<ConstantInt>(Inst->getOperand(Idx))) dbgs()
>>                     << "Collect constant " << *ConstInt << " from " <<
>> *Inst
>>                     << " with cost " << Cost << '\n';
>> @@ -374,6 +379,48 @@ void ConstantHoistingPass::collectConsta
>>    }
>>  }
>>
>> +/// Record constant GEP expression for instruction Inst at operand index
>> Idx.
>> +void ConstantHoistingPass::collectConstantCandidates(
>> +    ConstCandMapType &ConstCandMap, Instruction *Inst, unsigned Idx,
>> +    ConstantExpr *ConstExpr) {
>> +  // TODO: Handle vector GEPs
>> +  if (ConstExpr->getType()->isVectorTy())
>> +    return;
>> +
>> +  GlobalVariable *BaseGV =
>> dyn_cast<GlobalVariable>(ConstExpr->getOperand(0));
>> +  if (!BaseGV)
>> +    return;
>> +
>> +  // Get offset from the base GV.
>> +  PointerType *GVPtrTy = dyn_cast<PointerType>(BaseGV->getType());
>> +  IntegerType *PtrIntTy = DL->getIntPtrType(*Ctx,
>> GVPtrTy->getAddressSpace());
>> +  APInt Offset(DL->getTypeSizeInBits(PtrIntTy), /*val*/0,
>> /*isSigned*/true);
>> +  auto *GEPO = cast<GEPOperator>(ConstExpr);
>> +  if (!GEPO->accumulateConstantOffset(*DL, Offset))
>> +    return;
>> +
>> +  if (!Offset.isIntN(32))
>> +    return;
>> +
>> +  // A constant GEP expression that has a GlobalVariable as base pointer
>> is
>> +  // usually lowered to a load from constant pool. Such operation is
>> unlikely
>> +  // to be cheaper than compute it by <Base + Offset>, which can be
>> lowered to
>> +  // an ADD instruction or folded into Load/Store instruction.
>> +  int Cost = TTI->getIntImmCost(Instruction::Add, 1, Offset, PtrIntTy);
>> +  ConstCandVecType &ExprCandVec = ConstGEPCandMap[BaseGV];
>> +  ConstCandMapType::iterator Itr;
>> +  bool Inserted;
>> +  ConstPtrUnionType Cand = ConstExpr;
>> +  std::tie(Itr, Inserted) = ConstCandMap.insert(std::make_pair(Cand, 0));
>> +  if (Inserted) {
>> +    ExprCandVec.push_back(ConstantCandidate(
>> +        ConstantInt::get(Type::getInt32Ty(*Ctx),
>> Offset.getLimitedValue()),
>> +        ConstExpr));
>> +    Itr->second = ExprCandVec.size() - 1;
>> +  }
>> +  ExprCandVec[Itr->second].addUser(Inst, Idx, Cost);
>> +}
>> +
>>  /// Check the operand for instruction Inst at index Idx.
>>  void ConstantHoistingPass::collectConstantCandidates(
>>      ConstCandMapType &ConstCandMap, Instruction *Inst, unsigned Idx) {
>> @@ -402,6 +449,10 @@ void ConstantHoistingPass::collectConsta
>>
>>    // Visit constant expressions that have constant integers.
>>    if (auto ConstExpr = dyn_cast<ConstantExpr>(Opnd)) {
>> +    // Handle constant gep expressions.
>> +    if (ConstHoistGEP && ConstExpr->isGEPWithNoNotionalOverIndexing())
>> +      collectConstantCandidates(ConstCandMap, Inst, Idx, ConstExpr);
>> +
>>      // Only visit constant cast expressions.
>>      if (!ConstExpr->isCast())
>>        return;
>> @@ -544,7 +595,8 @@ ConstantHoistingPass::maximizeConstantsI
>>  /// Find the base constant within the given range and rebase all other
>>  /// constants with respect to the base constant.
>>  void ConstantHoistingPass::findAndMakeBaseConstant(
>> -    ConstCandVecType::iterator S, ConstCandVecType::iterator E) {
>> +    ConstCandVecType::iterator S, ConstCandVecType::iterator E,
>> +    SmallVectorImpl<consthoist::ConstantInfo> &ConstInfoVec) {
>>    auto MaxCostItr = S;
>>    unsigned NumUses = maximizeConstantsInRange(S, E, MaxCostItr);
>>
>> @@ -552,24 +604,35 @@ void ConstantHoistingPass::findAndMakeBa
>>    if (NumUses <= 1)
>>      return;
>>
>> +  ConstantInt *ConstInt = MaxCostItr->ConstInt;
>> +  ConstantExpr *ConstExpr = MaxCostItr->ConstExpr;
>>    ConstantInfo ConstInfo;
>> -  ConstInfo.BaseConstant = MaxCostItr->ConstInt;
>> -  Type *Ty = ConstInfo.BaseConstant->getType();
>> +  ConstInfo.BaseInt = ConstInt;
>> +  ConstInfo.BaseExpr = ConstExpr;
>> +  Type *Ty = ConstInt->getType();
>>
>>    // Rebase the constants with respect to the base constant.
>>    for (auto ConstCand = S; ConstCand != E; ++ConstCand) {
>> -    APInt Diff = ConstCand->ConstInt->getValue() -
>> -                 ConstInfo.BaseConstant->getValue();
>> +    APInt Diff = ConstCand->ConstInt->getValue() - ConstInt->getValue();
>>      Constant *Offset = Diff == 0 ? nullptr : ConstantInt::get(Ty, Diff);
>> +    Type *ConstTy =
>> +        ConstCand->ConstExpr ? ConstCand->ConstExpr->getType() : nullptr;
>>      ConstInfo.RebasedConstants.push_back(
>> -      RebasedConstantInfo(std::move(ConstCand->Uses), Offset));
>> +      RebasedConstantInfo(std::move(ConstCand->Uses), Offset, ConstTy));
>>    }
>> -  ConstantVec.push_back(std::move(ConstInfo));
>> +  ConstInfoVec.push_back(std::move(ConstInfo));
>>  }
>>
>>  /// Finds and combines constant candidates that can be easily
>>  /// rematerialized with an add from a common base constant.
>> -void ConstantHoistingPass::findBaseConstants() {
>> +void ConstantHoistingPass::findBaseConstants(GlobalVariable *BaseGV) {
>> +  // If BaseGV is nullptr, find base among candidate constant integers;
>> +  // Otherwise find base among constant GEPs that share the same BaseGV.
>> +  ConstCandVecType &ConstCandVec = BaseGV ?
>> +      ConstGEPCandMap[BaseGV] : ConstIntCandVec;
>> +  ConstInfoVecType &ConstInfoVec = BaseGV ?
>> +      ConstGEPInfoMap[BaseGV] : ConstIntInfoVec;
>> +
>>    // Sort the constants by value and type. This invalidates the mapping!
>>    llvm::sort(ConstCandVec.begin(), ConstCandVec.end(),
>>               [](const ConstantCandidate &LHS, const ConstantCandidate
>> &RHS) {
>> @@ -613,12 +676,12 @@ void ConstantHoistingPass::findBaseConst
>>      }
>>      // We either have now a different constant type or the constant is
>> not in
>>      // range of an add with immediate anymore.
>> -    findAndMakeBaseConstant(MinValItr, CC);
>> +    findAndMakeBaseConstant(MinValItr, CC, ConstInfoVec);
>>      // Start a new base constant search.
>>      MinValItr = CC;
>>    }
>>    // Finalize the last base constant search.
>> -  findAndMakeBaseConstant(MinValItr, ConstCandVec.end());
>> +  findAndMakeBaseConstant(MinValItr, ConstCandVec.end(), ConstInfoVec);
>>  }
>>
>>  /// Updates the operand at Idx in instruction Inst with the result of
>> @@ -653,12 +716,28 @@ static bool updateOperand(Instruction *I
>>  /// users.
>>  void ConstantHoistingPass::emitBaseConstants(Instruction *Base,
>>                                               Constant *Offset,
>> +                                             Type *Ty,
>>                                               const ConstantUser
>> &ConstUser) {
>>    Instruction *Mat = Base;
>> +
>> +  // The same offset can be dereferenced to different types in nested
>> struct.
>> +  if (!Offset && Ty && Ty != Base->getType())
>> +    Offset = ConstantInt::get(Type::getInt32Ty(*Ctx), 0);
>> +
>>    if (Offset) {
>>      Instruction *InsertionPt = findMatInsertPt(ConstUser.Inst,
>>                                                 ConstUser.OpndIdx);
>> -    Mat = BinaryOperator::Create(Instruction::Add, Base, Offset,
>> +    if (Ty) {
>> +      // Constant being rebased is a ConstantExpr.
>> +      PointerType *Int8PtrTy = Type::getInt8PtrTy(*Ctx,
>> +          cast<PointerType>(Ty)->getAddressSpace());
>> +      Base = new BitCastInst(Base, Int8PtrTy, "base_bitcast",
>> InsertionPt);
>> +      Mat = GetElementPtrInst::Create(Int8PtrTy->getElementType(), Base,
>> +          Offset, "mat_gep", InsertionPt);
>> +      Mat = new BitCastInst(Mat, Ty, "mat_bitcast", InsertionPt);
>> +    } else
>> +      // Constant being rebased is a ConstantInt.
>> +      Mat = BinaryOperator::Create(Instruction::Add, Base, Offset,
>>                                   "const_mat", InsertionPt);
>>
>>      LLVM_DEBUG(dbgs() << "Materialize constant (" << *Base->getOperand(0)
>> @@ -702,6 +781,14 @@ void ConstantHoistingPass::emitBaseConst
>>
>>    // Visit constant expression.
>>    if (auto ConstExpr = dyn_cast<ConstantExpr>(Opnd)) {
>> +    if (ConstExpr->isGEPWithNoNotionalOverIndexing()) {
>> +      // Operand is a ConstantGEP, replace it.
>> +      updateOperand(ConstUser.Inst, ConstUser.OpndIdx, Mat);
>> +      return;
>> +    }
>> +
>> +    // Aside from constant GEPs, only constant cast expressions are
>> collected.
>> +    assert(ConstExpr->isCast() && "ConstExpr should be a cast");
>>      Instruction *ConstExprInst = ConstExpr->getAsInstruction();
>>      ConstExprInst->setOperand(0, Mat);
>>      ConstExprInst->insertBefore(findMatInsertPt(ConstUser.Inst,
>> @@ -725,23 +812,31 @@ void ConstantHoistingPass::emitBaseConst
>>
>>  /// Hoist and hide the base constant behind a bitcast and emit
>>  /// materialization code for derived constants.
>> -bool ConstantHoistingPass::emitBaseConstants() {
>> +bool ConstantHoistingPass::emitBaseConstants(GlobalVariable *BaseGV) {
>>    bool MadeChange = false;
>> -  for (auto const &ConstInfo : ConstantVec) {
>> -    // Hoist and hide the base constant behind a bitcast.
>> +  SmallVectorImpl<consthoist::ConstantInfo> &ConstInfoVec =
>> +      BaseGV ? ConstGEPInfoMap[BaseGV] : ConstIntInfoVec;
>> +  for (auto const &ConstInfo : ConstInfoVec) {
>>      SmallPtrSet<Instruction *, 8> IPSet =
>> findConstantInsertionPoint(ConstInfo);
>>      assert(!IPSet.empty() && "IPSet is empty");
>>
>>      unsigned UsesNum = 0;
>>      unsigned ReBasesNum = 0;
>>      for (Instruction *IP : IPSet) {
>> -      IntegerType *Ty = ConstInfo.BaseConstant->getType();
>> -      Instruction *Base =
>> -          new BitCastInst(ConstInfo.BaseConstant, Ty, "const", IP);
>> +      Instruction *Base = nullptr;
>> +      // Hoist and hide the base constant behind a bitcast.
>> +      if (ConstInfo.BaseExpr) {
>> +        assert(BaseGV && "A base constant expression must have an base
>> GV");
>> +        Type *Ty = ConstInfo.BaseExpr->getType();
>> +        Base = new BitCastInst(ConstInfo.BaseExpr, Ty, "const", IP);
>> +      } else {
>> +        IntegerType *Ty = ConstInfo.BaseInt->getType();
>> +        Base = new BitCastInst(ConstInfo.BaseInt, Ty, "const", IP);
>> +      }
>>
>>        Base->setDebugLoc(IP->getDebugLoc());
>>
>> -      LLVM_DEBUG(dbgs() << "Hoist constant (" << *ConstInfo.BaseConstant
>> +      LLVM_DEBUG(dbgs() << "Hoist constant (" << *ConstInfo.BaseInt
>>                          << ") to BB " << IP->getParent()->getName() <<
>> '\n'
>>                          << *Base << '\n');
>>
>> @@ -756,11 +851,12 @@ bool ConstantHoistingPass::emitBaseConst
>>            // generate rebase for U using the Base dominating U.
>>            if (IPSet.size() == 1 ||
>>                DT->dominates(Base->getParent(), OrigMatInsertBB)) {
>> -            emitBaseConstants(Base, RCI.Offset, U);
>> +            emitBaseConstants(Base, RCI.Offset, RCI.Ty, U);
>>              ReBasesNum++;
>>            }
>>
>> -
>> Base->setDebugLoc(DILocation::getMergedLocation(Base->getDebugLoc(),
>> U.Inst->getDebugLoc()));
>> +          Base->setDebugLoc(DILocation::getMergedLocation(
>> +              Base->getDebugLoc(), U.Inst->getDebugLoc()));
>>          }
>>        }
>>        UsesNum = Uses;
>> @@ -779,7 +875,7 @@ bool ConstantHoistingPass::emitBaseConst
>>
>>      // Base constant is also included in ConstInfo.RebasedConstants, so
>>      // deduct 1 from ConstInfo.RebasedConstants.size().
>> -    NumConstantsRebased = ConstInfo.RebasedConstants.size() - 1;
>> +    NumConstantsRebased += ConstInfo.RebasedConstants.size() - 1;
>>
>>      MadeChange = true;
>>    }
>> @@ -801,25 +897,29 @@ bool ConstantHoistingPass::runImpl(Funct
>>    this->TTI = &TTI;
>>    this->DT = &DT;
>>    this->BFI = BFI;
>> +  this->DL = &Fn.getParent()->getDataLayout();
>> +  this->Ctx = &Fn.getContext();
>>    this->Entry = &Entry;
>>    // Collect all constant candidates.
>>    collectConstantCandidates(Fn);
>>
>> -  // There are no constant candidates to worry about.
>> -  if (ConstCandVec.empty())
>> -    return false;
>> -
>>    // Combine constants that can be easily materialized with an add from
>> a common
>>    // base constant.
>> -  findBaseConstants();
>> -
>> -  // There are no constants to emit.
>> -  if (ConstantVec.empty())
>> -    return false;
>> +  if (!ConstIntCandVec.empty())
>> +    findBaseConstants(nullptr);
>> +  for (auto &MapEntry : ConstGEPCandMap)
>> +    if (!MapEntry.second.empty())
>> +      findBaseConstants(MapEntry.first);
>>
>>    // Finally hoist the base constant and emit materialization code for
>> dependent
>>    // constants.
>> -  bool MadeChange = emitBaseConstants();
>> +  bool MadeChange = false;
>> +  if (!ConstIntInfoVec.empty())
>> +    MadeChange = emitBaseConstants(nullptr);
>> +  for (auto MapEntry : ConstGEPInfoMap)
>> +    if (!MapEntry.second.empty())
>> +      MadeChange |= emitBaseConstants(MapEntry.first);
>> +
>>
>>    // Cleanup dead instructions.
>>    deleteDeadCastInst();
>>
>> Added: llvm/trunk/test/CodeGen/AArch64/consthoist-gep.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/consthoist-gep.ll?rev=341269&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/CodeGen/AArch64/consthoist-gep.ll (added)
>> +++ llvm/trunk/test/CodeGen/AArch64/consthoist-gep.ll Fri Aug 31 17:04:56
>> 2018
>> @@ -0,0 +1,100 @@
>> +; RUN: llc -mtriple=aarch64-none-unknown-linuxeabi -consthoist-gep %s -o
>> - | FileCheck %s
>> +
>> +; CHECK-NOT: adrp    x10, global+332
>> +; CHECK-NOT: add     x10, x10, :lo12:global+332
>> +; CHECK: adrp    x10, global+528
>> +; CHECK-NEXT: add     x10, x10, :lo12:global+528
>> +
>> +%struct.blam = type { %struct.bar, %struct.bar.0, %struct.wobble,
>> %struct.wombat, i8, i16, %struct.snork.2, %struct.foo, %struct.snork.3,
>> %struct.wobble.4, %struct.quux, [9 x i16], %struct.spam, %struct.zot }
>> +%struct.bar = type { i8, i8, %struct.snork }
>> +%struct.snork = type { i16, i8, i8 }
>> +%struct.bar.0 = type { i8, i8, i16, i8, i8, %struct.barney }
>> +%struct.barney = type { i8, i8, i8, i8 }
>> +%struct.wobble = type { i8, i8, %struct.eggs, %struct.bar.1 }
>> +%struct.eggs = type { i8, i8, i8 }
>> +%struct.bar.1 = type { i8, i8, i8, i8 }
>> +%struct.wombat = type { i8, i8, i16, i32, i32, i32, i32 }
>> +%struct.snork.2 = type { i8, i8, i8 }
>> +%struct.foo = type { [12 x i32], [12 x i32], [4 x i32], i8, i8, i8, i8,
>> i8, i8, i8, i8 }
>> +%struct.snork.3 = type { i16, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8,
>> i8, i8, i8, i8, i16 }
>> +%struct.wobble.4 = type { i32, i32, i32, i32, i32, i32, i16, i16, i8,
>> i8, i16, i32, i32, i16, i8, i8 }
>> +%struct.quux = type { i32, %struct.foo.5, i8, i8, i8, i8, i32,
>> %struct.snork.6, %struct.foo.7, [16 x i8], i16, i16, i8, i8, i8, i8, i32,
>> i32, i32 }
>> +%struct.foo.5 = type { i16, i8, i8 }
>> +%struct.snork.6 = type { i16, i8, i8 }
>> +%struct.foo.7 = type { i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8,
>> i8, i8, i8, i8 }
>> +%struct.spam = type { i8, i8 }
>> +%struct.zot = type { [5 x i32], [3 x i32], [6 x i32], [3 x i32], [2 x
>> i32], [4 x i32], [3 x i32], [2 x i32], [4 x i32], [5 x i32], [3 x i32], [6
>> x i32], [1 x i32], i32, i32, i32, i32, i32, i32 }
>> +
>> + at global = external dso_local local_unnamed_addr global %struct.blam,
>> align 4
>> +
>> +; Function Attrs: norecurse nounwind optsize ssp
>> +define dso_local void @blam() local_unnamed_addr #0 {
>> +bb:
>> +  %tmp = load i8, i8* getelementptr inbounds (%struct.blam,
>> %struct.blam* @global, i32 0, i32 7, i32 9), align 2, !tbaa !3
>> +  %tmp1 = and i8 %tmp, 1
>> +  %tmp2 = icmp eq i8 %tmp1, 0
>> +  br i1 %tmp2, label %bb3, label %bb19
>> +
>> +bb3:                                              ; preds = %bb
>> +  %tmp4 = load volatile i32, i32* inttoptr (i32 805874688 to i32*),
>> align 1024, !tbaa !23
>> +  store i32 %tmp4, i32* getelementptr inbounds (%struct.blam,
>> %struct.blam* @global, i32 0, i32 13, i32 0, i32 0), align 4, !tbaa !23
>> +  %tmp5 = load volatile i32, i32* inttoptr (i32 805874692 to i32*),
>> align 4, !tbaa !23
>> +  %tmp6 = and i32 %tmp5, 65535
>> +  store i32 %tmp6, i32* getelementptr inbounds (%struct.blam,
>> %struct.blam* @global, i32 0, i32 13, i32 0, i32 1), align 4, !tbaa !23
>> +  %tmp7 = load volatile i32, i32* inttoptr (i32 805874696 to i32*),
>> align 8, !tbaa !23
>> +  %tmp8 = and i32 %tmp7, 522133279
>> +  store i32 %tmp8, i32* getelementptr inbounds (%struct.blam,
>> %struct.blam* @global, i32 0, i32 13, i32 0, i32 2), align 4, !tbaa !23
>> +  %tmp9 = load volatile i32, i32* inttoptr (i32 805874700 to i32*),
>> align 4, !tbaa !23
>> +  %tmp10 = and i32 %tmp9, 522133279
>> +  store i32 %tmp10, i32* getelementptr inbounds (%struct.blam,
>> %struct.blam* @global, i32 0, i32 13, i32 0, i32 3), align 4, !tbaa !23
>> +  %tmp11 = load volatile i32, i32* inttoptr (i32 805874860 to i32*),
>> align 4, !tbaa !23
>> +  %tmp12 = and i32 %tmp11, 16777215
>> +  store i32 %tmp12, i32* getelementptr inbounds (%struct.blam,
>> %struct.blam* @global, i32 0, i32 13, i32 15), align 4, !tbaa !24
>> +  %tmp13 = load volatile i32, i32* inttoptr (i32 805874864 to i32*),
>> align 16, !tbaa !23
>> +  %tmp14 = and i32 %tmp13, 16777215
>> +  store i32 %tmp14, i32* getelementptr inbounds (%struct.blam,
>> %struct.blam* @global, i32 0, i32 13, i32 16), align 4, !tbaa !25
>> +  %tmp15 = load volatile i32, i32* inttoptr (i32 805874868 to i32*),
>> align 4, !tbaa !23
>> +  %tmp16 = and i32 %tmp15, 16777215
>> +  store i32 %tmp16, i32* getelementptr inbounds (%struct.blam,
>> %struct.blam* @global, i32 0, i32 13, i32 17), align 4, !tbaa !26
>> +  %tmp17 = load volatile i32, i32* inttoptr (i32 805874872 to i32*),
>> align 8, !tbaa !23
>> +  %tmp18 = and i32 %tmp17, 16777215
>> +  store i32 %tmp18, i32* getelementptr inbounds (%struct.blam,
>> %struct.blam* @global, i32 0, i32 13, i32 18), align 4, !tbaa !27
>> +  br label %bb19
>> +
>> +bb19:                                             ; preds = %bb3, %bb
>> +  ret void
>> +}
>> +
>> +attributes #0 = { norecurse nounwind optsize ssp
>> "correctly-rounded-divide-sqrt-fp-math"="false"
>> "disable-tail-calls"="false" "less-precise-fpmad"="false"
>> "no-frame-pointer-elim"="false" "no-infs-fp-math"="false"
>> "no-jump-tables"="false" "no-nans-fp-math"="false"
>> "no-signed-zeros-fp-math"="false" "no-trapping-math"="false"
>> "stack-protector-buffer-size"="8" "unsafe-fp-math"="false"
>> "use-soft-float"="false" }
>> +
>> +!llvm.module.flags = !{!0, !1}
>> +!llvm.ident = !{!2}
>> +
>> +!0 = !{i32 1, !"wchar_size", i32 4}
>> +!1 = !{i32 1, !"min_enum_size", i32 1}
>> +!2 = !{!"Snapdragon LLVM ARM Compiler 8.0.0 (based on LLVM 8.0.0)"}
>> +!3 = !{!4, !6, i64 174}
>> +!4 = !{!"", !5, i64 0, !10, i64 6, !12, i64 16, !14, i64 28, !6, i64 48,
>> !9, i64 50, !13, i64 52, !16, i64 56, !17, i64 176, !18, i64 196, !19, i64
>> 240, !6, i64 312, !21, i64 330, !22, i64 332}
>> +!5 = !{!"", !6, i64 0, !6, i64 1, !8, i64 2}
>> +!6 = !{!"omnipotent char", !7, i64 0}
>> +!7 = !{!"Simple C/C++ TBAA"}
>> +!8 = !{!"", !9, i64 0, !6, i64 2, !6, i64 3}
>> +!9 = !{!"short", !6, i64 0}
>> +!10 = !{!"", !6, i64 0, !6, i64 1, !9, i64 2, !6, i64 4, !6, i64 5, !11,
>> i64 6}
>> +!11 = !{!"", !6, i64 0, !6, i64 1, !6, i64 2, !6, i64 3}
>> +!12 = !{!"", !6, i64 0, !6, i64 1, !13, i64 2, !11, i64 5}
>> +!13 = !{!"", !6, i64 0, !6, i64 1, !6, i64 2}
>> +!14 = !{!"", !6, i64 0, !6, i64 1, !9, i64 2, !15, i64 4, !15, i64 8,
>> !15, i64 12, !15, i64 16}
>> +!15 = !{!"long", !6, i64 0}
>> +!16 = !{!"", !6, i64 0, !6, i64 48, !6, i64 96, !6, i64 112, !6, i64
>> 113, !6, i64 114, !6, i64 115, !6, i64 116, !6, i64 117, !6, i64 118, !6,
>> i64 119}
>> +!17 = !{!"", !9, i64 0, !6, i64 2, !6, i64 3, !6, i64 4, !6, i64 5, !6,
>> i64 6, !6, i64 7, !6, i64 8, !6, i64 9, !6, i64 10, !6, i64 11, !6, i64 12,
>> !6, i64 13, !6, i64 14, !6, i64 15, !9, i64 16}
>> +!18 = !{!"", !15, i64 0, !15, i64 4, !15, i64 8, !15, i64 12, !15, i64
>> 16, !15, i64 20, !9, i64 24, !9, i64 26, !6, i64 28, !6, i64 29, !9, i64
>> 30, !15, i64 32, !15, i64 36, !9, i64 40, !6, i64 42, !6, i64 43}
>> +!19 = !{!"", !15, i64 0, !8, i64 4, !6, i64 8, !6, i64 9, !6, i64 10,
>> !6, i64 11, !15, i64 12, !8, i64 16, !20, i64 20, !6, i64 36, !9, i64 52,
>> !9, i64 54, !6, i64 56, !6, i64 57, !6, i64 58, !6, i64 59, !15, i64 60,
>> !15, i64 64, !15, i64 68}
>> +!20 = !{!"", !6, i64 0, !6, i64 1, !6, i64 2, !6, i64 3, !6, i64 4, !6,
>> i64 5, !6, i64 6, !6, i64 7, !6, i64 8, !6, i64 9, !6, i64 10, !6, i64 11,
>> !6, i64 12, !6, i64 13, !6, i64 14, !6, i64 15}
>> +!21 = !{!"", !6, i64 0, !6, i64 1}
>> +!22 = !{!"", !6, i64 0, !6, i64 20, !6, i64 32, !6, i64 56, !6, i64 68,
>> !6, i64 76, !6, i64 92, !6, i64 104, !6, i64 112, !6, i64 128, !6, i64 148,
>> !6, i64 160, !6, i64 184, !15, i64 188, !15, i64 192, !15, i64 196, !15,
>> i64 200, !15, i64 204, !15, i64 208}
>> +!23 = !{!15, !15, i64 0}
>> +!24 = !{!4, !15, i64 528}
>> +!25 = !{!4, !15, i64 532}
>> +!26 = !{!4, !15, i64 536}
>> +!27 = !{!4, !15, i64 540}
>>
>> Added:
>> llvm/trunk/test/Transforms/ConstantHoisting/AArch64/const-hoist-gep.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ConstantHoisting/AArch64/const-hoist-gep.ll?rev=341269&view=auto
>>
>> ==============================================================================
>> ---
>> llvm/trunk/test/Transforms/ConstantHoisting/AArch64/const-hoist-gep.ll
>> (added)
>> +++
>> llvm/trunk/test/Transforms/ConstantHoisting/AArch64/const-hoist-gep.ll Fri
>> Aug 31 17:04:56 2018
>> @@ -0,0 +1,44 @@
>> +; RUN: opt -consthoist -consthoist-gep -S -o - %s | FileCheck %s
>> +
>> +target triple = "aarch64-none--musleabi"
>> +
>> +; Check that constant GEP expressions are rewritten to one-dimensional
>> +; (single-index) GEPs, whose base poiner is a multi-dimensional GEP.
>> +; CHECK:  %const = bitcast i32* getelementptr inbounds (%0, %0* @global,
>> i32 0, i32 4, i32 0, i32 0) to i32*
>> +; CHECK-NEXT:  store i32 undef, i32* %const, align 4
>> +
>> +; CHECK-NEXT:  %[[BC1:[a-z0-9_]+]] = bitcast i32* %const to i8*
>> +; CHECK-NEXT:  %[[M1:[a-z0-9_]+]] = getelementptr i8, i8* %[[BC1]], i32 4
>> +; CHECK-NEXT:  %[[BC2:[a-z0-9_]+]] = bitcast i8* %[[M1]] to i32*
>> +; CHECK-NEXT:  store i32 undef, i32* %[[BC2]], align 4
>> +
>> +; CHECK-NEXT:  %[[BC3:[a-z0-9_]+]] = bitcast i32* %const to i8*
>> +; CHECK-NEXT:  %[[M2:[a-z0-9_]+]] = getelementptr i8, i8* %[[BC3]], i32
>> 160
>> +; CHECK-NEXT:  %[[BC4:[a-z0-9_]+]] = bitcast i8* %[[M2]] to i32*
>> +; CHECK-NEXT:  store i32 undef, i32* %[[BC4]], align 4
>> +
>> +; CHECK-NEXT:  %[[BC5:[a-z0-9_]+]] = bitcast i32* %const to i8*
>> +; CHECK-NEXT:  %[[M3:[a-z0-9_]+]] = getelementptr i8, i8* %[[BC5]], i32
>> 164
>> +; CHECK-NEXT:  %[[BC6:[a-z0-9_]+]] = bitcast i8* %[[M3]] to i32*
>> +; CHECK-NEXT:  store i32 undef, i32* %[[BC6]], align 4
>> +
>> +%0 = type { %1, %2, [9 x i16], %6, %7 }
>> +%1 = type { i32, i32, i32, i32, i32, i32, i16, i16, i8, i8, i16, i32,
>> i32, i16, i8, i8 }
>> +%2 = type { i32, %3, i8, i8, i8, i8, i32, %4, %5, [16 x i8], i16, i16,
>> i8, i8, i8, i8, i32, i32, i32 }
>> +%3 = type { i16, i8, i8 }
>> +%4 = type { i16, i8, i8 }
>> +%5 = type { i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8,
>> i8 }
>> +%6 = type { i8, i8 }
>> +%7 = type { [5 x i32], [3 x i32], [6 x i32], [3 x i32], [2 x i32], [4 x
>> i32], [3 x i32], [2 x i32], [4 x i32], [5 x i32], [3 x i32], [6 x i32], [1
>> x i32], i32, i32, i32, i32, i32, i32 }
>> +
>> + at global = external dso_local local_unnamed_addr global %0, align 4
>> +
>> +define dso_local void @zot() {
>> +bb:
>> +  store i32 undef, i32* getelementptr inbounds (%0, %0* @global, i32 0,
>> i32 4, i32 0, i32 0), align 4
>> +  store i32 undef, i32* getelementptr inbounds (%0, %0* @global, i32 0,
>> i32 4, i32 0, i32 1), align 4
>> +  store i32 undef, i32* getelementptr inbounds (%0, %0* @global, i32 0,
>> i32 4, i32 11, i32 0), align 4
>> +  store i32 undef, i32* getelementptr inbounds (%0, %0* @global, i32 0,
>> i32 4, i32 11, i32 1), align 4
>> +  ret void
>> +}
>> +
>>
>> Added: llvm/trunk/test/Transforms/ConstantHoisting/ARM/const-hoist-gep.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ConstantHoisting/ARM/const-hoist-gep.ll?rev=341269&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/Transforms/ConstantHoisting/ARM/const-hoist-gep.ll
>> (added)
>> +++ llvm/trunk/test/Transforms/ConstantHoisting/ARM/const-hoist-gep.ll
>> Fri Aug 31 17:04:56 2018
>> @@ -0,0 +1,42 @@
>> +; RUN: opt -consthoist -consthoist-gep -S -o - %s | FileCheck %s
>> +
>> +target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
>> +target triple = "thumbv6m-none--musleabi"
>> +
>> +; Check that constant GEP expressions are rewritten to one-dimensional
>> +; (single-index) GEPs, whose base poiner is a multi-dimensional GEP.
>> +; CHECK-DAG:  %[[C1:const[0-9]?]] = bitcast i32* getelementptr inbounds
>> (%0, %0* @global, i32 0, i32 4, i32 11, i32 0) to i32*
>> +; CHECK-DAG:  %[[C2:const[0-9]?]] = bitcast i32* getelementptr inbounds
>> (%0, %0* @global, i32 0, i32 4, i32 0, i32 0) to i32*
>> +
>> +; CHECK:  store i32 undef, i32* %[[C2]], align 4
>> +; CHECK-NEXT:  %[[BC1:[a-z0-9_]+]] = bitcast i32* %[[C2]] to i8*
>> +; CHECK-NEXT:  %[[M1:[a-z0-9_]+]] = getelementptr i8, i8* %[[BC1]], i32 4
>> +; CHECK-NEXT:  %[[BC2:[a-z0-9_]+]] = bitcast i8* %[[M1]] to i32*
>> +; CHECK-NEXT:  store i32 undef, i32* %[[BC2]], align 4
>> +
>> +; CHECK-NEXT:  store i32 undef, i32* %[[C1]], align 4
>> +; CHECK-NEXT:  %[[BC3:[a-z0-9_]+]] = bitcast i32* %[[C1]] to i8*
>> +; CHECK-NEXT:  %[[M2:[a-z0-9_]+]] = getelementptr i8, i8* %[[BC3]], i32 4
>> +; CHECK-NEXT:  %[[BC4:[a-z0-9_]+]] = bitcast i8* %[[M2]] to i32*
>> +; CHECK-NEXT:  store i32 undef, i32* %[[BC4]], align 4
>> +
>> +%0 = type { %1, %2, [9 x i16], %6, %7 }
>> +%1 = type { i32, i32, i32, i32, i32, i32, i16, i16, i8, i8, i16, i32,
>> i32, i16, i8, i8 }
>> +%2 = type { i32, %3, i8, i8, i8, i8, i32, %4, %5, [16 x i8], i16, i16,
>> i8, i8, i8, i8, i32, i32, i32 }
>> +%3 = type { i16, i8, i8 }
>> +%4 = type { i16, i8, i8 }
>> +%5 = type { i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8,
>> i8 }
>> +%6 = type { i8, i8 }
>> +%7 = type { [5 x i32], [3 x i32], [6 x i32], [3 x i32], [2 x i32], [4 x
>> i32], [3 x i32], [2 x i32], [4 x i32], [5 x i32], [3 x i32], [6 x i32], [1
>> x i32], i32, i32, i32, i32, i32, i32 }
>> +
>> + at global = external dso_local local_unnamed_addr global %0, align 4
>> +
>> +define dso_local void @zot() {
>> +bb:
>> +  store i32 undef, i32* getelementptr inbounds (%0, %0* @global, i32 0,
>> i32 4, i32 0, i32 0), align 4
>> +  store i32 undef, i32* getelementptr inbounds (%0, %0* @global, i32 0,
>> i32 4, i32 0, i32 1), align 4
>> +  store i32 undef, i32* getelementptr inbounds (%0, %0* @global, i32 0,
>> i32 4, i32 11, i32 0), align 4
>> +  store i32 undef, i32* getelementptr inbounds (%0, %0* @global, i32 0,
>> i32 4, i32 11, i32 1), align 4
>> +  ret void
>> +}
>> +
>>
>> Added:
>> llvm/trunk/test/Transforms/ConstantHoisting/ARM/same-offset-multi-types.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ConstantHoisting/ARM/same-offset-multi-types.ll?rev=341269&view=auto
>>
>> ==============================================================================
>> ---
>> llvm/trunk/test/Transforms/ConstantHoisting/ARM/same-offset-multi-types.ll
>> (added)
>> +++
>> llvm/trunk/test/Transforms/ConstantHoisting/ARM/same-offset-multi-types.ll
>> Fri Aug 31 17:04:56 2018
>> @@ -0,0 +1,44 @@
>> +; RUN: opt -consthoist -consthoist-gep -S -o - %s | FileCheck %s
>> +
>> +target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
>> +target triple = "thumbv6m-none--musleabi"
>> +
>> +; Check that for the same offset from the base constant, different types
>> are materialized separately.
>> +; CHECK:  %const = bitcast %5** getelementptr inbounds (%0, %0* @global,
>> i32 0, i32 2, i32 0) to %5**
>> +; CHECK:  %tmp = load %5*, %5** %const, align 4
>> +; CHECK:  %base_bitcast = bitcast %5** %const to i8*
>> +; CHECK:  %mat_gep = getelementptr i8, i8* %base_bitcast, i32 0
>> +; CHECK:  %mat_bitcast = bitcast i8* %mat_gep to %4*
>> +; CHECK:  tail call void undef(%5* nonnull %tmp, %4* %mat_bitcast)
>> +
>> +%0 = type { [16 x %1], %2, %4, [16 x %5], %6, %7, i32, [4 x i32], [8 x
>> %3], i8, i8, i8, i8, i8, i8, i8, %8, %11, %11*, i32, i16, i8, i8, i8, i8,
>> i8, i8, [15 x i16], i8, i8, [23 x %12], i8, i8*, i8, %13, i8, i8 }
>> +%1 = type { i32, i32, i8, i8, i8, i8, i8, i8, i8, i8 }
>> +%2 = type { %3*, i16, i16, i16 }
>> +%3 = type { [4 x i32] }
>> +%4 = type { %5*, %5*, i8 }
>> +%5 = type { [4 x i32], i8*, i8, i8 }
>> +%6 = type { i8, [4 x i32] }
>> +%7 = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }
>> +%8 = type { [16 x %9], %9*, %9*, %9*, %9*, %11, %11, %11, i8, i8, i8, i8
>> }
>> +%9 = type { %1, %11, %11, %9*, %9*, %10, i8, i8, i8, i8 }
>> +%10 = type { i32, i16 }
>> +%11 = type { %11*, %11* }
>> +%12 = type { i8, i16, i32 }
>> +%13 = type { i32, i32, i8 }
>> +
>> + at global = external dso_local global %0, align 4
>> +
>> +; Function Attrs: nounwind optsize ssp
>> +define dso_local void @zot() {
>> +bb:
>> +  br i1 undef, label %bb2, label %bb1
>> +
>> +bb1:                                              ; preds = %bb
>> +  %tmp = load %5*, %5** getelementptr inbounds (%0, %0* @global, i32 0,
>> i32 2, i32 0), align 4
>> +  tail call void undef(%5* nonnull %tmp, %4* getelementptr inbounds (%0,
>> %0* @global, i32 0, i32 2))
>> +  unreachable
>> +
>> +bb2:                                              ; preds = %bb
>> +  ret void
>> +}
>> +
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20180904/e02c8ac5/attachment.html>


More information about the llvm-commits mailing list