[PATCH] D14148: [GlobalOpt] Demote globals to locals more aggressively
Duncan P. N. Exon Smith via llvm-commits
llvm-commits at lists.llvm.org
Sun Nov 15 14:04:42 PST 2015
> On 2015-Nov-13, at 04:38, James Molloy <james.molloy at arm.com> wrote:
>
> jmolloy updated this revision to Diff 40137.
> jmolloy added a comment.
>
> Hi Mehdi, Duncan, Manman,
>
> I've updated the patch following all your comments. Implementing Mehdi's suggestion made the code look significantly neater and will also catch more cases.
>
> I've also undone the reordering of optimizations in ProcessInternalGlobal, as I don't think this is now needed now that "main" isn't implicitly norecurse. It was only done to pacify tests in the first place, and they all pass now without modification.
>
> Cheers,
>
> James
>
>
> Repository:
> rL LLVM
>
> http://reviews.llvm.org/D14148
>
> Files:
> lib/Transforms/IPO/GlobalOpt.cpp
> test/Transforms/GlobalOpt/global-demotion.ll
> test/Transforms/GlobalOpt/metadata.ll
> test/Transforms/MergeFunc/crash2.ll
>
> <D14148.40137.patch>
This patch looks way cleaner.
Just a few more nitpicks; otherwise LGTM once Manman and Mehdi are happy.
> Index: lib/Transforms/IPO/GlobalOpt.cpp
> ===================================================================
> --- lib/Transforms/IPO/GlobalOpt.cpp
> +++ lib/Transforms/IPO/GlobalOpt.cpp
> @@ -28,6 +28,7 @@
> #include "llvm/IR/Constants.h"
> #include "llvm/IR/DataLayout.h"
> #include "llvm/IR/DerivedTypes.h"
> +#include "llvm/IR/Dominators.h"
> #include "llvm/IR/GetElementPtrTypeIterator.h"
> #include "llvm/IR/Instructions.h"
> #include "llvm/IR/IntrinsicInst.h"
> @@ -69,6 +70,7 @@
> struct GlobalOpt : public ModulePass {
> void getAnalysisUsage(AnalysisUsage &AU) const override {
> AU.addRequired<TargetLibraryInfoWrapperPass>();
> + AU.addRequired<DominatorTreeWrapperPass>();
> }
> static char ID; // Pass identification, replacement for typeid
> GlobalOpt() : ModulePass(ID) {
> @@ -85,7 +87,9 @@
> bool ProcessInternalGlobal(GlobalVariable *GV,Module::global_iterator &GVI,
> const GlobalStatus &GS);
> bool OptimizeEmptyGlobalCXXDtors(Function *CXAAtExitFn);
> -
> +
There are spaces on the new version of this empty line. clang-format?
> + bool isPointerValueDeadOnEntryToFunction(const Function *F, GlobalValue *GV);
> +
There are spaces on this empty line too.
> TargetLibraryInfo *TLI;
> SmallSet<const Comdat *, 8> NotDiscardableComdats;
> };
> @@ -95,6 +99,7 @@
> INITIALIZE_PASS_BEGIN(GlobalOpt, "globalopt",
> "Global Variable Optimizer", false, false)
> INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
> +INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
> INITIALIZE_PASS_END(GlobalOpt, "globalopt",
> "Global Variable Optimizer", false, false)
>
> @@ -1718,26 +1723,90 @@
> return ProcessInternalGlobal(GV, GVI, GS);
> }
>
> +bool GlobalOpt::isPointerValueDeadOnEntryToFunction(const Function *F, GlobalValue *GV) {
> + // Find all uses of GV. We expect them all to be in F, and if we can't
> + // identify any of the uses we bail out.
> + //
> + // On each of these uses, identify if the memory that GV points to is
> + // used/required/live at the start of the function. If it is not, for example
> + // if the first thing the function does is store to the GV, the GV can
> + // possibly be demoted.
> + //
> + // We don't do an exhaustive search for memory operations - simply look
> + // through bitcasts as they're quite common and benign.
> + const DataLayout &DL = GV->getParent()->getDataLayout();
> + SmallVector<LoadInst *, 4> Loads;
> + SmallVector<StoreInst *, 4> Stores;
> + for (auto *U : GV->users()) {
> + if (Operator::getOpcode(U) == Instruction::BitCast) {
> + for (auto *UU : U->users()) {
> + if (auto *LI = dyn_cast<LoadInst>(UU))
> + Loads.push_back(LI);
> + else if (auto *SI = dyn_cast<StoreInst>(UU))
> + Stores.push_back(SI);
> + else
> + return false;
> + }
> + continue;
> + }
> +
> + Instruction *I = dyn_cast<Instruction>(U);
> + if (!I)
> + return false;
> + assert(I->getParent()->getParent() == F);
> +
> + if (auto *LI = dyn_cast<LoadInst>(I))
> + Loads.push_back(LI);
> + else if (auto *SI = dyn_cast<StoreInst>(I))
> + Stores.push_back(SI);
> + else
> + return false;
> + }
> +
> + // We have identified all uses of GV into loads and stores. Now check if all
> + // of them are known not to depend on the value of the global at the function
> + // entry point. We do this by ensuring that every load is dominated by at
> + // least one store.
> + auto &DT = getAnalysis<DominatorTreeWrapperPass>(*const_cast<Function *>(F))
> + .getDomTree();
> +
> + for (auto *L : Loads) {
> + auto *LTy = L->getType();
> + if (!std::any_of(Stores.begin(), Stores.end(), [&](StoreInst *S) {
This looks quadratic. Should we give up if there are too many loads and
stores?
> + auto *STy = S->getValueOperand()->getType();
> + // The load is only dominated by the store if DomTree says so
> + // and the number of bits loaded in L is less than or equal to
> + // the number of bits stored in S.
> + return DT.dominates(S, L) &&
> + DL.getTypeStoreSize(LTy) <= DL.getTypeStoreSize(STy);
> + }))
> + return false;
> + }
> + // All loads have known dependences inside F, so the global can be localized.
> + return true;
> +}
More information about the llvm-commits
mailing list