#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"
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<uint64_t> getInstWeight(const Instruction &I);
/// 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 {
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
Function &F, DenseSet<GlobalValue::GUID> &ImportGUIDs) {
DenseSet<Instruction *> PromotedInsns;
bool Changed = false;
- LLVMContext &Ctx = F.getContext();
std::function<AssumptionCache &(Function &)> GetAssumptionCache = [&](
Function &F) -> AssumptionCache & { return ACT->getAssumptionCache(F); };
while (true) {
// We set the probability to 80% taken to indicate that the static
// call is likely taken.
DI = dyn_cast<Instruction>(
- promoteIndirectCall(I, CalledFunction, 80, 100, false)
+ promoteIndirectCall(I, CalledFunction, 80, 100, false, ORE)
->stripPointerCasts());
PromotedInsns.insert(I);
} else {
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() + "'");
+ // The call to InlineFunction erases DI, so we can't pass it here.
+ ORE->emit(OptimizationRemark(DEBUG_TYPE, "HotInline", DLoc, BB)
+ << "inlined hot callee '"
+ << ore::NV("Callee", CalledFunction) << "' into '"
+ << ore::NV("Caller", &F) << "'");
}
}
if (LocalChanged) {
<< ".\n");
SmallVector<uint32_t, 4> 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);
if (Weight != 0) {
if (Weight > MaxWeight) {
MaxWeight = Weight;
- MaxDestLoc = Succ->getFirstNonPHIOrDbgOrLifetime()->getDebugLoc();
+ MaxDestInst = Succ->getFirstNonPHIOrDbgOrLifetime();
}
}
}
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("<UNKNOWN LOCATION>")));
+ ORE->emit(OptimizationRemark(DEBUG_TYPE, "PopularDest", MaxDestInst)
+ << "most popular destination for conditional branches at "
+ << ore::NV("CondBranchesLoc", BranchLoc));
} else {
DEBUG(dbgs() << "SKIPPED. All branch weights are zero.\n");
}
return new SampleProfileLoaderLegacyPass(Name);
}
-bool SampleProfileLoader::runOnModule(Module &M) {
+bool SampleProfileLoader::runOnModule(Module &M, ModuleAnalysisManager *AM) {
if (!ProfileIsValid)
return false;
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()));
bool SampleProfileLoaderLegacyPass::runOnModule(Module &M) {
// FIXME: pass in AssumptionCache correctly for the new pass manager.
SampleLoader.setACT(&getAnalysis<AssumptionCacheTracker>());
- return SampleLoader.runOnModule(M);
+ return SampleLoader.runOnModule(M, nullptr);
}
-bool SampleProfileLoader::runOnFunction(Function &F) {
+bool SampleProfileLoader::runOnFunction(Function &F, ModuleAnalysisManager *AM) {
F.setEntryCount(0);
+ std::unique_ptr<OptimizationRemarkEmitter> OwnedORE;
+ if (AM) {
+ auto &FAM =
+ AM->getResult<FunctionAnalysisManagerModuleProxy>(*F.getParent())
+ .getManager();
+ ORE = &FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
+ } else {
+ OwnedORE = make_unique<OptimizationRemarkEmitter>(&F);
+ ORE = OwnedORE.get();
+ }
Samples = Reader->getSamplesFor(F);
if (Samples && !Samples->empty())
return emitAnnotations(F);
SampleLoader.doInitialization(M);
- if (!SampleLoader.runOnModule(M))
+ if (!SampleLoader.runOnModule(M, &AM))
return PreservedAnalyses::all();
return PreservedAnalyses::none();
-; 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: FileCheck %s -check-prefix=YAML < %t.opt.yaml
; Original test case.
;
; 1 #include <stdlib.h>
; 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
+; 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: DebugLoc: { File: remarks.cc, Line: 3, Column: 0 }
+;YAML-NEXT: - String: ''' into '''
+;YAML-NEXT: - Caller: main
+;YAML-NEXT: DebugLoc: { File: remarks.cc, Line: 13, Column: 0 }
+;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: - String: 'most popular destination for conditional branches at '
+;YAML-NEXT: - CondBranchesLoc: 'remarks.cc:5:3'
+;YAML-NEXT: DebugLoc: { File: remarks.cc, Line: 5, Column: 3 }
+;YAML-NEXT: ...
+
; Function Attrs: nounwind uwtable
define i64 @_Z3foov() #0 !dbg !4 {
entry: