diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 | 
| commit | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch) | |
| tree | 4adf86a776049cbf7f69a1929c4babcbbef925eb /llvm/lib/Transforms/IPO/GlobalOpt.cpp | |
| parent | 7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff) | |
Notes
Diffstat (limited to 'llvm/lib/Transforms/IPO/GlobalOpt.cpp')
| -rw-r--r-- | llvm/lib/Transforms/IPO/GlobalOpt.cpp | 155 | 
1 files changed, 86 insertions, 69 deletions
| diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp index 819715b9f8da..0fd966457ece 100644 --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -25,7 +25,6 @@  #include "llvm/Analysis/MemoryBuiltins.h"  #include "llvm/Analysis/TargetLibraryInfo.h"  #include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/Transforms/Utils/Local.h"  #include "llvm/BinaryFormat/Dwarf.h"  #include "llvm/IR/Attributes.h"  #include "llvm/IR/BasicBlock.h" @@ -53,6 +52,7 @@  #include "llvm/IR/User.h"  #include "llvm/IR/Value.h"  #include "llvm/IR/ValueHandle.h" +#include "llvm/InitializePasses.h"  #include "llvm/Pass.h"  #include "llvm/Support/AtomicOrdering.h"  #include "llvm/Support/Casting.h" @@ -65,6 +65,7 @@  #include "llvm/Transforms/Utils/CtorUtils.h"  #include "llvm/Transforms/Utils/Evaluator.h"  #include "llvm/Transforms/Utils/GlobalStatus.h" +#include "llvm/Transforms/Utils/Local.h"  #include <cassert>  #include <cstdint>  #include <utility> @@ -432,6 +433,20 @@ static bool GlobalUsersSafeToSRA(GlobalValue *GV) {    return true;  } +static bool CanDoGlobalSRA(GlobalVariable *GV) { +  Constant *Init = GV->getInitializer(); + +  if (isa<StructType>(Init->getType())) { +    // nothing to check +  } else if (SequentialType *STy = dyn_cast<SequentialType>(Init->getType())) { +    if (STy->getNumElements() > 16 && GV->hasNUsesOrMore(16)) +      return false; // It's not worth it. +  } else +    return false; + +  return GlobalUsersSafeToSRA(GV); +} +  /// Copy over the debug info for a variable to its SRA replacements.  static void transferSRADebugInfo(GlobalVariable *GV, GlobalVariable *NGV,                                   uint64_t FragmentOffsetInBits, @@ -461,88 +476,94 @@ static void transferSRADebugInfo(GlobalVariable *GV, GlobalVariable *NGV,  /// insert so that the caller can reprocess it.  static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) {    // Make sure this global only has simple uses that we can SRA. -  if (!GlobalUsersSafeToSRA(GV)) +  if (!CanDoGlobalSRA(GV))      return nullptr;    assert(GV->hasLocalLinkage());    Constant *Init = GV->getInitializer();    Type *Ty = Init->getType(); -  std::vector<GlobalVariable *> NewGlobals; -  Module::GlobalListType &Globals = GV->getParent()->getGlobalList(); +  std::map<unsigned, GlobalVariable *> NewGlobals;    // Get the alignment of the global, either explicit or target-specific.    unsigned StartAlignment = GV->getAlignment();    if (StartAlignment == 0)      StartAlignment = DL.getABITypeAlignment(GV->getType()); -  if (StructType *STy = dyn_cast<StructType>(Ty)) { -    unsigned NumElements = STy->getNumElements(); -    NewGlobals.reserve(NumElements); -    const StructLayout &Layout = *DL.getStructLayout(STy); -    for (unsigned i = 0, e = NumElements; i != e; ++i) { -      Constant *In = Init->getAggregateElement(i); -      assert(In && "Couldn't get element of initializer?"); -      GlobalVariable *NGV = new GlobalVariable(STy->getElementType(i), false, -                                               GlobalVariable::InternalLinkage, -                                               In, GV->getName()+"."+Twine(i), -                                               GV->getThreadLocalMode(), -                                              GV->getType()->getAddressSpace()); -      NGV->setExternallyInitialized(GV->isExternallyInitialized()); -      NGV->copyAttributesFrom(GV); -      Globals.push_back(NGV); -      NewGlobals.push_back(NGV); +  // Loop over all users and create replacement variables for used aggregate +  // elements. +  for (User *GEP : GV->users()) { +    assert(((isa<ConstantExpr>(GEP) && cast<ConstantExpr>(GEP)->getOpcode() == +                                           Instruction::GetElementPtr) || +            isa<GetElementPtrInst>(GEP)) && +           "NonGEP CE's are not SRAable!"); + +    // Ignore the 1th operand, which has to be zero or else the program is quite +    // broken (undefined).  Get the 2nd operand, which is the structure or array +    // index. +    unsigned ElementIdx = cast<ConstantInt>(GEP->getOperand(2))->getZExtValue(); +    if (NewGlobals.count(ElementIdx) == 1) +      continue; // we`ve already created replacement variable +    assert(NewGlobals.count(ElementIdx) == 0); + +    Type *ElTy = nullptr; +    if (StructType *STy = dyn_cast<StructType>(Ty)) +      ElTy = STy->getElementType(ElementIdx); +    else if (SequentialType *STy = dyn_cast<SequentialType>(Ty)) +      ElTy = STy->getElementType(); +    assert(ElTy); + +    Constant *In = Init->getAggregateElement(ElementIdx); +    assert(In && "Couldn't get element of initializer?"); + +    GlobalVariable *NGV = new GlobalVariable( +        ElTy, false, GlobalVariable::InternalLinkage, In, +        GV->getName() + "." + Twine(ElementIdx), GV->getThreadLocalMode(), +        GV->getType()->getAddressSpace()); +    NGV->setExternallyInitialized(GV->isExternallyInitialized()); +    NGV->copyAttributesFrom(GV); +    NewGlobals.insert(std::make_pair(ElementIdx, NGV)); + +    if (StructType *STy = dyn_cast<StructType>(Ty)) { +      const StructLayout &Layout = *DL.getStructLayout(STy);        // Calculate the known alignment of the field.  If the original aggregate        // had 256 byte alignment for example, something might depend on that:        // propagate info to each field. -      uint64_t FieldOffset = Layout.getElementOffset(i); +      uint64_t FieldOffset = Layout.getElementOffset(ElementIdx);        Align NewAlign(MinAlign(StartAlignment, FieldOffset)); -      if (NewAlign > Align(DL.getABITypeAlignment(STy->getElementType(i)))) +      if (NewAlign > +          Align(DL.getABITypeAlignment(STy->getElementType(ElementIdx))))          NGV->setAlignment(NewAlign);        // Copy over the debug info for the variable.        uint64_t Size = DL.getTypeAllocSizeInBits(NGV->getValueType()); -      uint64_t FragmentOffsetInBits = Layout.getElementOffsetInBits(i); -      transferSRADebugInfo(GV, NGV, FragmentOffsetInBits, Size, NumElements); -    } -  } else if (SequentialType *STy = dyn_cast<SequentialType>(Ty)) { -    unsigned NumElements = STy->getNumElements(); -    if (NumElements > 16 && GV->hasNUsesOrMore(16)) -      return nullptr; // It's not worth it. -    NewGlobals.reserve(NumElements); -    auto ElTy = STy->getElementType(); -    uint64_t EltSize = DL.getTypeAllocSize(ElTy); -    Align EltAlign(DL.getABITypeAlignment(ElTy)); -    uint64_t FragmentSizeInBits = DL.getTypeAllocSizeInBits(ElTy); -    for (unsigned i = 0, e = NumElements; i != e; ++i) { -      Constant *In = Init->getAggregateElement(i); -      assert(In && "Couldn't get element of initializer?"); - -      GlobalVariable *NGV = new GlobalVariable(STy->getElementType(), false, -                                               GlobalVariable::InternalLinkage, -                                               In, GV->getName()+"."+Twine(i), -                                               GV->getThreadLocalMode(), -                                              GV->getType()->getAddressSpace()); -      NGV->setExternallyInitialized(GV->isExternallyInitialized()); -      NGV->copyAttributesFrom(GV); -      Globals.push_back(NGV); -      NewGlobals.push_back(NGV); +      uint64_t FragmentOffsetInBits = Layout.getElementOffsetInBits(ElementIdx); +      transferSRADebugInfo(GV, NGV, FragmentOffsetInBits, Size, +                           STy->getNumElements()); +    } else if (SequentialType *STy = dyn_cast<SequentialType>(Ty)) { +      uint64_t EltSize = DL.getTypeAllocSize(ElTy); +      Align EltAlign(DL.getABITypeAlignment(ElTy)); +      uint64_t FragmentSizeInBits = DL.getTypeAllocSizeInBits(ElTy);        // Calculate the known alignment of the field.  If the original aggregate        // had 256 byte alignment for example, something might depend on that:        // propagate info to each field. -      Align NewAlign(MinAlign(StartAlignment, EltSize * i)); +      Align NewAlign(MinAlign(StartAlignment, EltSize * ElementIdx));        if (NewAlign > EltAlign)          NGV->setAlignment(NewAlign); -      transferSRADebugInfo(GV, NGV, FragmentSizeInBits * i, FragmentSizeInBits, -                           NumElements); +      transferSRADebugInfo(GV, NGV, FragmentSizeInBits * ElementIdx, +                           FragmentSizeInBits, STy->getNumElements());      }    }    if (NewGlobals.empty())      return nullptr; +  Module::GlobalListType &Globals = GV->getParent()->getGlobalList(); +  for (auto NewGlobalVar : NewGlobals) +    Globals.push_back(NewGlobalVar.second); +    LLVM_DEBUG(dbgs() << "PERFORMING GLOBAL SRA ON: " << *GV << "\n");    Constant *NullInt =Constant::getNullValue(Type::getInt32Ty(GV->getContext())); @@ -558,11 +579,11 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) {      // Ignore the 1th operand, which has to be zero or else the program is quite      // broken (undefined).  Get the 2nd operand, which is the structure or array      // index. -    unsigned Val = cast<ConstantInt>(GEP->getOperand(2))->getZExtValue(); -    if (Val >= NewGlobals.size()) Val = 0; // Out of bound array access. +    unsigned ElementIdx = cast<ConstantInt>(GEP->getOperand(2))->getZExtValue(); +    assert(NewGlobals.count(ElementIdx) == 1); -    Value *NewPtr = NewGlobals[Val]; -    Type *NewTy = NewGlobals[Val]->getValueType(); +    Value *NewPtr = NewGlobals[ElementIdx]; +    Type *NewTy = NewGlobals[ElementIdx]->getValueType();      // Form a shorter GEP if needed.      if (GEP->getNumOperands() > 3) { @@ -580,7 +601,8 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) {          for (unsigned i = 3, e = GEPI->getNumOperands(); i != e; ++i)            Idxs.push_back(GEPI->getOperand(i));          NewPtr = GetElementPtrInst::Create( -            NewTy, NewPtr, Idxs, GEPI->getName() + "." + Twine(Val), GEPI); +            NewTy, NewPtr, Idxs, GEPI->getName() + "." + Twine(ElementIdx), +            GEPI);        }      }      GEP->replaceAllUsesWith(NewPtr); @@ -595,17 +617,8 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) {    Globals.erase(GV);    ++NumSRA; -  // Loop over the new globals array deleting any globals that are obviously -  // dead.  This can arise due to scalarization of a structure or an array that -  // has elements that are dead. -  unsigned FirstGlobal = 0; -  for (unsigned i = 0, e = NewGlobals.size(); i != e; ++i) -    if (NewGlobals[i]->use_empty()) { -      Globals.erase(NewGlobals[i]); -      if (FirstGlobal == i) ++FirstGlobal; -    } - -  return FirstGlobal != NewGlobals.size() ? NewGlobals[FirstGlobal] : nullptr; +  assert(NewGlobals.size() > 0); +  return NewGlobals.begin()->second;  }  /// Return true if all users of the specified value will trap if the value is @@ -2285,10 +2298,14 @@ OptimizeFunctions(Module &M,      // So, remove unreachable blocks from the function, because a) there's      // no point in analyzing them and b) GlobalOpt should otherwise grow      // some more complicated logic to break these cycles. +    // Removing unreachable blocks might invalidate the dominator so we +    // recalculate it.      if (!F->isDeclaration()) { -      auto &DT = LookupDomTree(*F); -      DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy); -      Changed |= removeUnreachableBlocks(*F, &DTU); +      if (removeUnreachableBlocks(*F)) { +        auto &DT = LookupDomTree(*F); +        DT.recalculate(*F); +        Changed = true; +      }      }      Changed |= processGlobal(*F, GetTLI, LookupDomTree); | 
