From d53651aca3e2e4714979ad8254964b395ce1d5ab Mon Sep 17 00:00:00 2001 From: Adam Nemet Date: Thu, 1 Dec 2016 16:40:32 +0000 Subject: [PATCH] [GVN] Basic optimization remark support [recommitting after the fix in r288307] Follow-on patches will add more interesting cases. The goal of this patch-set is to get the GVN messages printed in opt-viewer from Dhrystone as was presented in my Dev Meeting talk. This is the optimization view for the function (the last remark in the function has a bug which is fixed in this series): http://lab.llvm.org:8080/artifacts/opt-view_test-suite/build/SingleSource/Benchmarks/Dhrystone/CMakeFiles/dry.dir/html/_org_test-suite_SingleSource_Benchmarks_Dhrystone_dry.c.html#L430 Differential Revision: https://reviews.llvm.org/D26488 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@288370 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/DiagnosticInfo.h | 1 + include/llvm/Transforms/Scalar/GVN.h | 5 ++- lib/IR/DiagnosticInfo.cpp | 6 ++++ lib/Transforms/Scalar/GVN.cpp | 23 ++++++++++++-- test/Transforms/GVN/opt-remarks.ll | 59 ++++++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 test/Transforms/GVN/opt-remarks.ll diff --git a/include/llvm/IR/DiagnosticInfo.h b/include/llvm/IR/DiagnosticInfo.h index 62732abe024..e739dfbd673 100644 --- a/include/llvm/IR/DiagnosticInfo.h +++ b/include/llvm/IR/DiagnosticInfo.h @@ -392,6 +392,7 @@ public: explicit Argument(StringRef Str = "") : Key("String"), Val(Str) {} Argument(StringRef Key, Value *V); + Argument(StringRef Key, Type *T); Argument(StringRef Key, int N); Argument(StringRef Key, unsigned N); Argument(StringRef Key, bool B) : Key(Key), Val(B ? "true" : "false") {} diff --git a/include/llvm/Transforms/Scalar/GVN.h b/include/llvm/Transforms/Scalar/GVN.h index 5492ba2c1d4..8f05e8cdb23 100644 --- a/include/llvm/Transforms/Scalar/GVN.h +++ b/include/llvm/Transforms/Scalar/GVN.h @@ -29,6 +29,7 @@ #include "llvm/IR/PassManager.h" namespace llvm { +class OptimizationRemarkEmitter; /// A private "module" namespace for types and utilities used by GVN. These /// are implementation details and should not be used by clients. @@ -110,6 +111,7 @@ private: const TargetLibraryInfo *TLI; AssumptionCache *AC; SetVector DeadBlocks; + OptimizationRemarkEmitter *ORE; ValueTable VN; @@ -135,7 +137,8 @@ private: bool runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT, const TargetLibraryInfo &RunTLI, AAResults &RunAA, - MemoryDependenceResults *RunMD, LoopInfo *LI); + MemoryDependenceResults *RunMD, LoopInfo *LI, + OptimizationRemarkEmitter *ORE); /// Push a new Value to the LeaderTable onto the list for its value number. void addToLeaderTable(uint32_t N, Value *V, const BasicBlock *BB) { diff --git a/lib/IR/DiagnosticInfo.cpp b/lib/IR/DiagnosticInfo.cpp index 5618de8f602..6a3fdcff233 100644 --- a/lib/IR/DiagnosticInfo.cpp +++ b/lib/IR/DiagnosticInfo.cpp @@ -180,6 +180,12 @@ DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, Value *V) DLoc = I->getDebugLoc(); } +DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, Type *T) + : Key(Key) { + raw_string_ostream OS(Val); + OS << *T; +} + DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, int N) : Key(Key), Val(itostr(N)) {} diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp index 79afff2fe3b..050cc2ecc89 100644 --- a/lib/Transforms/Scalar/GVN.cpp +++ b/lib/Transforms/Scalar/GVN.cpp @@ -33,6 +33,7 @@ #include "llvm/Analysis/Loads.h" #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/MemoryDependenceAnalysis.h" +#include "llvm/Analysis/OptimizationDiagnosticInfo.h" #include "llvm/Analysis/PHITransAddr.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" @@ -587,7 +588,8 @@ PreservedAnalyses GVN::run(Function &F, FunctionAnalysisManager &AM) { auto &AA = AM.getResult(F); auto &MemDep = AM.getResult(F); auto *LI = AM.getCachedResult(F); - bool Changed = runImpl(F, AC, DT, TLI, AA, &MemDep, LI); + auto &ORE = AM.getResult(F); + bool Changed = runImpl(F, AC, DT, TLI, AA, &MemDep, LI, &ORE); if (!Changed) return PreservedAnalyses::all(); PreservedAnalyses PA; @@ -1583,10 +1585,18 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock, if (V->getType()->getScalarType()->isPointerTy()) MD->invalidateCachedPointerInfo(V); markInstructionForDeletion(LI); + ORE->emit(OptimizationRemark(DEBUG_TYPE, "LoadPRE", LI) + << "load eliminated by PRE"); ++NumPRELoad; return true; } +static void reportLoadElim(LoadInst *LI, OptimizationRemarkEmitter *ORE) { + ORE->emit(OptimizationRemark(DEBUG_TYPE, "LoadElim", LI) + << "load of type " << ore::NV("Type", LI->getType()) + << " eliminated"); +} + /// Attempt to eliminate a load whose dependencies are /// non-local by performing PHI construction. bool GVN::processNonLocalLoad(LoadInst *LI) { @@ -1657,6 +1667,7 @@ bool GVN::processNonLocalLoad(LoadInst *LI) { MD->invalidateCachedPointerInfo(V); markInstructionForDeletion(LI); ++NumGVNLoad; + reportLoadElim(LI, ORE); return true; } @@ -1803,6 +1814,7 @@ bool GVN::processLoad(LoadInst *L) { patchAndReplaceAllUsesWith(L, AvailableValue); markInstructionForDeletion(L); ++NumGVNLoad; + reportLoadElim(L, ORE); // Tell MDA to rexamine the reused pointer since we might have more // information after forwarding it. if (MD && AvailableValue->getType()->getScalarType()->isPointerTy()) @@ -2180,7 +2192,8 @@ bool GVN::processInstruction(Instruction *I) { /// runOnFunction - This is the main transformation entry point for a function. bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT, const TargetLibraryInfo &RunTLI, AAResults &RunAA, - MemoryDependenceResults *RunMD, LoopInfo *LI) { + MemoryDependenceResults *RunMD, LoopInfo *LI, + OptimizationRemarkEmitter *RunORE) { AC = &RunAC; DT = &RunDT; VN.setDomTree(DT); @@ -2188,6 +2201,7 @@ bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT, VN.setAliasAnalysis(&RunAA); MD = RunMD; VN.setMemDep(MD); + ORE = RunORE; bool Changed = false; bool ShouldContinue = true; @@ -2703,7 +2717,8 @@ public: getAnalysis().getAAResults(), NoLoads ? nullptr : &getAnalysis().getMemDep(), - LIWP ? &LIWP->getLoopInfo() : nullptr); + LIWP ? &LIWP->getLoopInfo() : nullptr, + &getAnalysis().getORE()); } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -2716,6 +2731,7 @@ public: AU.addPreserved(); AU.addPreserved(); + AU.addRequired(); } private: @@ -2737,4 +2753,5 @@ INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass) +INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass) INITIALIZE_PASS_END(GVNLegacyPass, "gvn", "Global Value Numbering", false, false) diff --git a/test/Transforms/GVN/opt-remarks.ll b/test/Transforms/GVN/opt-remarks.ll new file mode 100644 index 00000000000..c451833f765 --- /dev/null +++ b/test/Transforms/GVN/opt-remarks.ll @@ -0,0 +1,59 @@ +; RUN: opt < %s -gvn -o /dev/null -pass-remarks-output=%t -S -pass-remarks=gvn \ +; RUN: 2>&1 | FileCheck %s +; RUN: cat %t | FileCheck -check-prefix=YAML %s + +; CHECK: remark: :0:0: load of type i32 eliminated{{$}} +; CHECK-NEXT: remark: :0:0: load of type i32 eliminated{{$}} +; CHECK-NEXT: remark: :0:0: load of type i32 eliminated{{$}} +; CHECK-NOT: remark: + +; YAML: --- !Passed +; YAML-NEXT: Pass: gvn +; YAML-NEXT: Name: LoadElim +; YAML-NEXT: Function: arg +; YAML-NEXT: Args: +; YAML-NEXT: - String: 'load of type ' +; YAML-NEXT: - Type: i32 +; YAML-NEXT: - String: ' eliminated' +; YAML-NEXT: ... +; YAML-NEXT: --- !Passed +; YAML-NEXT: Pass: gvn +; YAML-NEXT: Name: LoadElim +; YAML-NEXT: Function: const +; YAML-NEXT: Args: +; YAML-NEXT: - String: 'load of type ' +; YAML-NEXT: - Type: i32 +; YAML-NEXT: - String: ' eliminated' +; YAML-NEXT: ... +; YAML-NEXT: --- !Passed +; YAML-NEXT: Pass: gvn +; YAML-NEXT: Name: LoadElim +; YAML-NEXT: Function: inst +; YAML-NEXT: Args: +; YAML-NEXT: - String: 'load of type ' +; YAML-NEXT: - Type: i32 +; YAML-NEXT: - String: ' eliminated' +; YAML-NEXT: ... + + +define i32 @arg(i32* %p, i32 %i) { +entry: + store i32 %i, i32* %p + %load = load i32, i32* %p + ret i32 %load +} + +define i32 @const(i32* %p) { +entry: + store i32 4, i32* %p + %load = load i32, i32* %p + ret i32 %load +} + +define i32 @inst(i32* %p) { +entry: + %load1 = load i32, i32* %p + %load = load i32, i32* %p + %add = add i32 %load1, %load + ret i32 %add +} -- 2.11.0