[InlineCost] InlineCostAnnotationWriterPass introduced

This class allows to see the inliner's decisions for better
optimization verifications and tests. To use, use flag
"-passes="print<inline-cost>"".

Reviewers: apilipenko, mtrofin, davidxl, fedor.sergeev

Reviewed By: mtrofin

Differential revision: https://reviews.llvm.org/D81743
This commit is contained in:
Kirill Naumov 2020-06-11 22:24:10 +00:00
parent ccd127008a
commit 37e06e8f5c
6 changed files with 93 additions and 49 deletions

View File

@ -269,6 +269,18 @@ Optional<int> getInliningCostEstimate(
/// Minimal filter to detect invalid constructs for inlining.
InlineResult isInlineViable(Function &Callee);
// This pass is used to annotate instructions during the inline process for
// debugging and analysis. The main purpose of the pass is to see and test
// inliner's decisions when creating new optimizations to InlineCost.
struct InlineCostAnnotationPrinterPass
: PassInfoMixin<InlineCostAnnotationPrinterPass> {
raw_ostream &OS;
public:
explicit InlineCostAnnotationPrinterPass(raw_ostream &OS) : OS(OS) {}
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
};
} // namespace llvm
#endif

View File

@ -2509,3 +2509,40 @@ InlineParams llvm::getInlineParams(unsigned OptLevel, unsigned SizeOptLevel) {
Params.LocallyHotCallSiteThreshold = LocallyHotCallSiteThreshold;
return Params;
}
PreservedAnalyses
InlineCostAnnotationPrinterPass::run(Function &F,
FunctionAnalysisManager &FAM) {
PrintInstructionComments = true;
std::function<AssumptionCache &(Function &)> GetAssumptionCache = [&](
Function &F) -> AssumptionCache & {
return FAM.getResult<AssumptionAnalysis>(F);
};
Module *M = F.getParent();
ProfileSummaryInfo PSI(*M);
DataLayout DL(M);
TargetTransformInfo TTI(DL);
// FIXME: Redesign the usage of InlineParams to expand the scope of this pass.
// In the current implementation, the type of InlineParams doesn't matter as
// the pass serves only for verification of inliner's decisions.
// We can add a flag which determines InlineParams for this run. Right now,
// the default InlineParams are used.
const InlineParams Params = llvm::getInlineParams();
for (BasicBlock &BB : F) {
for (Instruction &I : BB) {
if (CallInst *CI = dyn_cast<CallInst>(&I)) {
Function *CalledFunction = CI->getCalledFunction();
if (!CalledFunction || CalledFunction->isDeclaration())
continue;
OptimizationRemarkEmitter ORE(CalledFunction);
InlineCostCallAnalyzer ICCA(*CalledFunction, *CI, Params, TTI,
GetAssumptionCache, nullptr, &PSI, &ORE);
ICCA.analyze();
OS << " Analyzing call of " << CalledFunction->getName()
<< "... (caller:" << CI->getCaller()->getName() << ")\n";
ICCA.dump();
}
}
}
return PreservedAnalyses::all();
}

View File

@ -233,6 +233,7 @@ FUNCTION_PASS("print<domtree>", DominatorTreePrinterPass(dbgs()))
FUNCTION_PASS("print<postdomtree>", PostDominatorTreePrinterPass(dbgs()))
FUNCTION_PASS("print<demanded-bits>", DemandedBitsPrinterPass(dbgs()))
FUNCTION_PASS("print<domfrontier>", DominanceFrontierPrinterPass(dbgs()))
FUNCTION_PASS("print<inline-cost>", InlineCostAnnotationPrinterPass(dbgs()))
FUNCTION_PASS("print<loops>", LoopPrinterPass(dbgs()))
FUNCTION_PASS("print<memoryssa>", MemorySSAPrinterPass(dbgs()))
FUNCTION_PASS("print<phi-values>", PhiValuesPrinterPass(dbgs()))

View File

@ -1,32 +1,16 @@
; Require asserts for -debug-only
; REQUIRES: asserts
; RUN: opt < %s -inline -debug-only=inline-cost -disable-output -print-instruction-comments 2>&1 | FileCheck %s
; RUN: opt < %s -passes="print<inline-cost>" 2>&1 | FileCheck %s
; CHECK: Analyzing call of callee1... (caller:foo)
; CHECK: define i32 @callee1(i32 %x) {
; CHECK: ; cost before = {{.*}}, cost after = {{.*}}, threshold before = {{.*}}, threshold after = {{.*}}, cost delta = 5
; CHECK: %x1 = add i32 %x, 1
; CHECK: ; cost before = {{.*}}, cost after = {{.*}}, threshold before = {{.*}}, threshold after = {{.*}}, cost delta = 5
; CHECK: %x2 = add i32 %x1, 1
; CHECK: ; cost before = {{.*}}, cost after = {{.*}}, threshold before = {{.*}}, threshold after = {{.*}}, cost delta = 5
; CHECK: %x3 = add i32 %x2, 1
; CHECK: ; cost before = {{.*}}, cost after = {{.*}}, threshold before = {{.*}}, threshold after = {{.*}}, cost delta = 0
; CHECK: ret i32 %x3
; CHECK: }
; CHECK: NumConstantArgs: 0
; CHECK: NumConstantOffsetPtrArgs: 0
; CHECK: NumAllocaArgs: 0
; CHECK: NumConstantPtrCmps: 0
; CHECK: NumConstantPtrDiffs: 0
; CHECK: NumInstructionsSimplified: 1
; CHECK: NumInstructions: 4
; CHECK: SROACostSavings: 0
; CHECK: SROACostSavingsLost: 0
; CHECK: LoadEliminationCost: 0
; CHECK: ContainsNoDuplicateCall: 0
; CHECK: Cost: {{.*}}
; CHECK: Threshold: {{.*}}
; CHECK-NEXT: define i32 @callee1(i32 %x) {
; CHECK-NEXT: cost before = {{.*}}, cost after = {{.*}}, threshold before = {{.*}}, threshold after = {{.*}}, cost delta = {{.*}}
; CHECK-NEXT: %x1 = add i32 %x, 1
; CHECK-NEXT: cost before = {{.*}}, cost after = {{.*}}, threshold before = {{.*}}, threshold after = {{.*}}, cost delta = {{.*}}
; CHECK-NEXT: %x2 = add i32 %x1, 1
; CHECK-NEXT: cost before = {{.*}}, cost after = {{.*}}, threshold before = {{.*}}, threshold after = {{.*}}, cost delta = {{.*}}
; CHECK-NEXT: %x3 = add i32 %x2, 1
; CHECK-NEXT: cost before = {{.*}}, cost after = {{.*}}, threshold before = {{.*}}, threshold after = {{.*}}, cost delta = {{.*}}
; CHECK-NEXT: ret i32 %x3
; CHECK-NEXT: }
define i32 @foo(i32 %y) {
%x = call i32 @callee1(i32 %y)

View File

@ -0,0 +1,32 @@
; RUN: opt < %s -passes="print<inline-cost>" 2>&1 | FileCheck %s
; CHECK: Analyzing call of foo... (caller:main)
; CHECK: define i8 addrspace(1)** @foo() {
; CHECK: cost before = {{.*}}, cost after = {{.*}}, threshold before = {{.*}}, threshold after = {{.*}}, cost delta = {{.*}}
; CHECK: %1 = inttoptr i64 754974720 to i8 addrspace(1)**
; CHECK: cost before = {{.*}}, cost after = {{.*}}, threshold before = {{.*}}, threshold after = {{.*}}, cost delta = {{.*}}
; CHECK: ret i8 addrspace(1)** %1
; CHECK: }
; CHECK: NumConstantArgs: {{.*}}
; CHECK: NumConstantOffsetPtrArgs: {{.*}}
; CHECK: NumAllocaArgs: {{.*}}
; CHECK: NumConstantPtrCmps: {{.*}}
; CHECK: NumConstantPtrDiffs: {{.*}}
; CHECK: NumInstructionsSimplified: {{.*}}
; CHECK: NumInstructions: {{.*}}
; CHECK: SROACostSavings: {{.*}}
; CHECK: SROACostSavingsLost: {{.*}}
; CHECK: LoadEliminationCost: {{.*}}
; CHECK: ContainsNoDuplicateCall: {{.*}}
; CHECK: Cost: {{.*}}
; CHECK: Threshold: {{.*}}
define i8 addrspace(1)** @foo() {
%1 = inttoptr i64 754974720 to i8 addrspace(1)**
ret i8 addrspace(1)** %1
}
define i8 addrspace(1)** @main() {
%1 = call i8 addrspace(1)** @foo()
ret i8 addrspace(1)** %1
}

View File

@ -1,22 +0,0 @@
; Require asserts for -debug-only
; REQUIRES: asserts
; This test ensures that the hadling of instructions which were not analyzed by
; '-print-instruction-deltas' flag due to the early exit was done correctly.
; RUN: opt < %s -inline -debug-only=inline-cost -disable-output -print-instruction-comments -inline-threshold=0 2>&1 | FileCheck %s
; CHECK: No analysis for the instruction
; CHECK: ret void
declare void @callee1()
define void @bar() {
call void @callee1()
ret void
}
define void @foo() {
call void @bar()
ret void
}