Index: lib/Transforms/IPO/SampleProfile.cpp =================================================================== --- lib/Transforms/IPO/SampleProfile.cpp +++ lib/Transforms/IPO/SampleProfile.cpp @@ -29,6 +29,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/OptimizationDiagnosticInfo.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" @@ -148,16 +149,16 @@ SampleProfileLoader(StringRef Name = SampleProfileFile) : DT(nullptr), PDT(nullptr), LI(nullptr), ACT(nullptr), Reader(), Samples(nullptr), Filename(Name), ProfileIsValid(false), - TotalCollectedSamples(0) {} + TotalCollectedSamples(0), ORE(nullptr) {} bool doInitialization(Module &M); - bool runOnModule(Module &M); + bool runOnModule(Module &M, ModuleAnalysisManager *AM); void setACT(AssumptionCacheTracker *A) { ACT = A; } void dump() { Reader->dump(); } protected: - bool runOnFunction(Function &F); + bool runOnFunction(Function &F, ModuleAnalysisManager *AM); unsigned getFunctionLoc(Function &F); bool emitAnnotations(Function &F); ErrorOr getInstWeight(const Instruction &I); @@ -249,6 +250,9 @@ /// This is the sum of all the samples collected in all the functions executed /// at runtime. uint64_t TotalCollectedSamples; + + /// \brief Optimization Remark Emitter used to emit diagnostic remarks + OptimizationRemarkEmitter *ORE; }; class SampleProfileLoaderLegacyPass : public ModulePass { @@ -497,13 +501,17 @@ bool FirstMark = CoverageTracker.markSamplesUsed(FS, LineOffset, Discriminator, R.get()); if (FirstMark) { - const Function *F = Inst.getParent()->getParent(); - LLVMContext &Ctx = F->getContext(); - emitOptimizationRemark( - Ctx, DEBUG_TYPE, *F, DLoc, - Twine("Applied ") + Twine(*R) + - " samples from profile (offset: " + Twine(LineOffset) + - ((Discriminator) ? Twine(".") + Twine(Discriminator) : "") + ")"); + if (Discriminator) + ORE->emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "AppliedSamples", &Inst) + << "Applied " << ore::NV("NumSamples", *R) + << " samples from profile (offset: " + << ore::NV("LineOffset", LineOffset) << "." + << ore::NV("Discriminator", Discriminator) << ")"); + else + ORE->emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "AppliedSamples", &Inst) + << "Applied " << ore::NV("NumSamples", *R) + << " samples from profile (offset: " + << ore::NV("LineOffset", LineOffset) << ")"); } DEBUG(dbgs() << " " << DLoc.getLine() << "." << DIL->getBaseDiscriminator() << ":" << Inst @@ -669,7 +677,6 @@ Function &F, DenseSet &ImportGUIDs) { DenseSet PromotedInsns; bool Changed = false; - LLVMContext &Ctx = F.getContext(); std::function GetAssumptionCache = [&]( Function &F) -> AssumptionCache & { return ACT->getAssumptionCache(F); }; while (true) { @@ -720,7 +727,7 @@ // We set the probability to 80% taken to indicate that the static // call is likely taken. DI = dyn_cast( - promoteIndirectCall(I, CalledFunction, 80, 100, false) + promoteIndirectCall(I, CalledFunction, 80, 100, false, ORE) ->stripPointerCasts()); PromotedInsns.insert(I); } else { @@ -737,12 +744,13 @@ continue; } DebugLoc DLoc = I->getDebugLoc(); + BasicBlock *BB = I->getParent(); if (InlineFunction(CallSite(DI), IFI)) { LocalChanged = true; - emitOptimizationRemark(Ctx, DEBUG_TYPE, F, DLoc, - Twine("inlined hot callee '") + - CalledFunction->getName() + "' into '" + - F.getName() + "'"); + ORE->emit(OptimizationRemark(DEBUG_TYPE, "HotInline", DLoc, BB) + << "inlined hot callee '" + << ore::NV("Callee", CalledFunction->getName()) << "' into '" + << ore::NV("Caller", F.getName()) << "'"); } } if (LocalChanged) { @@ -1213,7 +1221,7 @@ << ".\n"); SmallVector Weights; uint32_t MaxWeight = 0; - DebugLoc MaxDestLoc; + Instruction *MaxDestInst; for (unsigned I = 0; I < TI->getNumSuccessors(); ++I) { BasicBlock *Succ = TI->getSuccessor(I); Edge E = std::make_pair(BB, Succ); @@ -1232,7 +1240,7 @@ if (Weight != 0) { if (Weight > MaxWeight) { MaxWeight = Weight; - MaxDestLoc = Succ->getFirstNonPHIOrDbgOrLifetime()->getDebugLoc(); + MaxDestInst = Succ->getFirstNonPHIOrDbgOrLifetime(); } } } @@ -1247,13 +1255,18 @@ DEBUG(dbgs() << "SUCCESS. Found non-zero weights.\n"); TI->setMetadata(llvm::LLVMContext::MD_prof, MDB.createBranchWeights(Weights)); - emitOptimizationRemark( - Ctx, DEBUG_TYPE, F, MaxDestLoc, - Twine("most popular destination for conditional branches at ") + - ((BranchLoc) ? Twine(BranchLoc->getFilename() + ":" + - Twine(BranchLoc.getLine()) + ":" + - Twine(BranchLoc.getCol())) - : Twine(""))); + if (BranchLoc) + ORE->emit(OptimizationRemark(DEBUG_TYPE, "PopularDest", MaxDestInst) + << ore::NV("PopularInstruction", MaxDestInst) + << " is the most popular destination for conditional branches at " + << ore::NV("Location", BranchLoc->getFilename()) << ":" + << ore::NV("LineNum", BranchLoc.getLine()) << ":" + << ore::NV("ColNum", BranchLoc.getCol())); + else + ORE->emit(OptimizationRemark(DEBUG_TYPE, "PopularDest", MaxDestInst) + << ore::NV("PopularInstruction", MaxDestInst) + << " is the most popular destination for conditional branches at " + << ore::NV("Unknown", StringRef(""))); } else { DEBUG(dbgs() << "SKIPPED. All branch weights are zero.\n"); } @@ -1433,7 +1446,7 @@ return new SampleProfileLoaderLegacyPass(Name); } -bool SampleProfileLoader::runOnModule(Module &M) { +bool SampleProfileLoader::runOnModule(Module &M, ModuleAnalysisManager *AM = nullptr) { if (!ProfileIsValid) return false; @@ -1465,7 +1478,7 @@ for (auto &F : M) if (!F.isDeclaration()) { clearFunctionData(); - retval |= runOnFunction(F); + retval |= runOnFunction(F, AM); } if (M.getProfileSummary() == nullptr) M.setProfileSummary(Reader->getSummary().getMD(M.getContext())); @@ -1478,8 +1491,19 @@ return SampleLoader.runOnModule(M); } -bool SampleProfileLoader::runOnFunction(Function &F) { +bool SampleProfileLoader::runOnFunction(Function &F, + ModuleAnalysisManager *AM = nullptr) { F.setEntryCount(0); + std::unique_ptr OwnedORE; + if (AM) { + auto &FAM = + AM->getResult(*F.getParent()) + .getManager(); + ORE = &FAM.getResult(F); + } else { + OwnedORE = make_unique(&F); + ORE = OwnedORE.get(); + } Samples = Reader->getSamplesFor(F); if (Samples && !Samples->empty()) return emitAnnotations(F); @@ -1494,7 +1518,7 @@ SampleLoader.doInitialization(M); - if (!SampleLoader.runOnModule(M)) + if (!SampleLoader.runOnModule(M, &AM)) return PreservedAnalyses::all(); return PreservedAnalyses::none(); Index: test/Transforms/SampleProfile/cov-zero-samples.ll =================================================================== --- test/Transforms/SampleProfile/cov-zero-samples.ll +++ test/Transforms/SampleProfile/cov-zero-samples.ll @@ -1,5 +1,5 @@ -; RUN: opt < %s -instcombine -sample-profile -sample-profile-file=%S/Inputs/cov-zero-samples.prof -sample-profile-check-record-coverage=100 -pass-remarks=sample-profile -o /dev/null 2>&1 | FileCheck %s -; RUN: opt < %s -passes="function(instcombine),sample-profile" -sample-profile-file=%S/Inputs/cov-zero-samples.prof -sample-profile-check-record-coverage=100 -pass-remarks=sample-profile -o /dev/null 2>&1 | FileCheck %s +; RUN: opt < %s -instcombine -sample-profile -sample-profile-file=%S/Inputs/cov-zero-samples.prof -sample-profile-check-record-coverage=100 -pass-remarks=sample-profile -pass-remarks-analysis=sample-profile -o /dev/null 2>&1 | FileCheck %s +; RUN: opt < %s -passes="function(instcombine),sample-profile" -sample-profile-file=%S/Inputs/cov-zero-samples.prof -sample-profile-check-record-coverage=100 -pass-remarks=sample-profile -pass-remarks-analysis=sample-profile -o /dev/null 2>&1 | FileCheck %s ; ; CHECK: remark: cov-zero-samples.cc:9:29: Applied 404065 samples from profile (offset: 2.1) ; CHECK: remark: cov-zero-samples.cc:10:9: Applied 443089 samples from profile (offset: 3) @@ -7,8 +7,8 @@ ; CHECK: remark: cov-zero-samples.cc:11:12: Applied 404066 samples from profile (offset: 4) ; CHECK: remark: cov-zero-samples.cc:13:25: Applied 0 samples from profile (offset: 6) ; CHECK: remark: cov-zero-samples.cc:14:3: Applied 0 samples from profile (offset: 7) -; CHECK: remark: cov-zero-samples.cc:10:9: most popular destination for conditional branches at cov-zero-samples.cc:9:3 -; CHECK: remark: cov-zero-samples.cc:11:12: most popular destination for conditional branches at cov-zero-samples.cc:10:9 +; CHECK: remark: cov-zero-samples.cc:10:9: load is the most popular destination for conditional branches at cov-zero-samples.cc:9:3 +; CHECK: remark: cov-zero-samples.cc:11:12: load is the most popular destination for conditional branches at cov-zero-samples.cc:10:9 ; ; Coverage for this profile should be 100% ; CHECK-NOT: warning: cov-zero-samples.cc:1: Index: test/Transforms/SampleProfile/inline-coverage.ll =================================================================== --- test/Transforms/SampleProfile/inline-coverage.ll +++ test/Transforms/SampleProfile/inline-coverage.ll @@ -1,5 +1,5 @@ -; RUN: opt < %s -instcombine -sample-profile -sample-profile-file=%S/Inputs/inline-coverage.prof -sample-profile-check-record-coverage=100 -sample-profile-check-sample-coverage=110 -pass-remarks=sample-profile -o /dev/null 2>&1 | FileCheck %s -; RUN: opt < %s -passes="function(instcombine),sample-profile" -sample-profile-file=%S/Inputs/inline-coverage.prof -sample-profile-check-record-coverage=100 -sample-profile-check-sample-coverage=110 -pass-remarks=sample-profile -o /dev/null 2>&1 | FileCheck %s +; RUN: opt < %s -instcombine -sample-profile -sample-profile-file=%S/Inputs/inline-coverage.prof -sample-profile-check-record-coverage=100 -sample-profile-check-sample-coverage=110 -pass-remarks=sample-profile -pass-remarks-analysis=sample-profile -o /dev/null 2>&1 | FileCheck %s +; RUN: opt < %s -passes="function(instcombine),sample-profile" -sample-profile-file=%S/Inputs/inline-coverage.prof -sample-profile-check-record-coverage=100 -sample-profile-check-sample-coverage=110 -pass-remarks=sample-profile -pass-remarks-analysis=sample-profile -o /dev/null 2>&1 | FileCheck %s ; ; Original code: ; @@ -21,7 +21,7 @@ ; CHECK: remark: coverage.cc:10:16: Applied 23478 samples from profile (offset: 3) ; CHECK: remark: coverage.cc:4:10: Applied 31878 samples from profile (offset: 1) ; CHECK: remark: coverage.cc:11:10: Applied 0 samples from profile (offset: 4) -; CHECK: remark: coverage.cc:10:16: most popular destination for conditional branches at coverage.cc:9:3 +; CHECK: remark: coverage.cc:10:16: load is the most popular destination for conditional branches at coverage.cc:9:3 ; ; There is one sample record with 0 samples at offset 4 in main() that we never ; use: Index: test/Transforms/SampleProfile/nolocinfo.ll =================================================================== --- test/Transforms/SampleProfile/nolocinfo.ll +++ test/Transforms/SampleProfile/nolocinfo.ll @@ -10,7 +10,7 @@ ; Remarks for conditional branches need debug location information for the ; referring branch. When that is not present, the compiler should not abort. ; -; CHECK: remark: nolocinfo.c:3:5: most popular destination for conditional branches at +; CHECK: remark: nolocinfo.c:3:5: ret is the most popular destination for conditional branches at br i1 %cmp, label %if.then, label %if.end if.then: Index: test/Transforms/SampleProfile/remarks.ll =================================================================== --- test/Transforms/SampleProfile/remarks.ll +++ test/Transforms/SampleProfile/remarks.ll @@ -1,6 +1,6 @@ -; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/remarks.prof -S -pass-remarks=sample-profile 2>&1 | FileCheck %s +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/remarks.prof -S -pass-remarks=sample-profile -pass-remarks-output=%t.opt.yaml 2>&1 | FileCheck %s ; RUN: opt < %s -passes=sample-profile -sample-profile-file=%S/Inputs/remarks.prof -S -pass-remarks=sample-profile 2>&1 | FileCheck %s -; +; RUN: cat %t.opt.yaml | FileCheck %s -check-prefix=YAML ; Original test case. ; ; 1 #include @@ -22,10 +22,51 @@ ; CHECK: remark: remarks.cc:13:21: inlined hot callee '_Z3foov' into 'main' ; The back edge for the loop is the hottest edge in the loop subgraph. -; CHECK: remark: remarks.cc:6:9: most popular destination for conditional branches at remarks.cc:5:3 +; CHECK: remark: remarks.cc:6:9: load is the most popular destination for conditional branches at remarks.cc:5:3 ; The predicate almost always chooses the 'else' branch. -; CHECK: remark: remarks.cc:9:15: most popular destination for conditional branches at remarks.cc:6:9 +; CHECK: remark: remarks.cc:9:15: load is the most popular destination for conditional branches at remarks.cc:6:9 + +; Checking to see if YAML file is generated and contains remarks +;YAML: --- !Passed +;YAML-NEXT: Pass: sample-profile +;YAML-NEXT: Name: HotInline +;YAML-NEXT: DebugLoc: { File: remarks.cc, Line: 13, Column: 21 } +;YAML-NEXT: Function: main +;YAML-NEXT: Args: +;YAML-NEXT: - String: 'inlined hot callee ''' +;YAML-NEXT: - Callee: _Z3foov +;YAML-NEXT: - String: ''' into ''' +;YAML-NEXT: - Caller: main +;YAML-NEXT: - String: '''' +;YAML-NEXT: ... +;YAML: --- !Analysis +;YAML-NEXT: Pass: sample-profile +;YAML-NEXT: Name: AppliedSamples +;YAML-NEXT: DebugLoc: { File: remarks.cc, Line: 5, Column: 8 } +;YAML-NEXT: Function: main +;YAML-NEXT: Args: +;YAML-NEXT: - String: 'Applied ' +;YAML-NEXT: - NumSamples: '18305' +;YAML-NEXT: - String: ' samples from profile (offset: ' +;YAML-NEXT: - LineOffset: '2' +;YAML-NEXT: - String: ')' +;YAML-NEXT: ... +;YAML: --- !Passed +;YAML-NEXT: Pass: sample-profile +;YAML-NEXT: Name: PopularDest +;YAML-NEXT: DebugLoc: { File: remarks.cc, Line: 6, Column: 9 } +;YAML-NEXT: Function: main +;YAML-NEXT: Args: +;YAML-NEXT: - PopularInstruction: load +;YAML-NEXT: DebugLoc: { File: remarks.cc, Line: 6, Column: 9 } +;YAML-NEXT: - String: ' is the most popular destination for conditional branches at ' +;YAML-NEXT: - Location: remarks.cc +;YAML-NEXT: - String: ':' +;YAML-NEXT: - LineNum: '5' +;YAML-NEXT: - String: ':' +;YAML-NEXT: - ColNum: '3' +;YAML-NEXT: ... ; Function Attrs: nounwind uwtable define i64 @_Z3foov() #0 !dbg !4 {