/// 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
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();
+}
\ No newline at end of file
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()))
-; 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)
--- /dev/null
+; 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
+}
+++ /dev/null
-; 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
-}