diff --git a/clang/test/Frontend/optimization-remark-line-directive.c b/clang/test/Frontend/optimization-remark-line-directive.c --- a/clang/test/Frontend/optimization-remark-line-directive.c +++ b/clang/test/Frontend/optimization-remark-line-directive.c @@ -6,7 +6,7 @@ // The new PM inliner is not added to the default pipeline at O0, so we add // some optimizations to trigger it. -// RUN: %clang_cc1 %s -Rpass=inline -fexperimental-new-pass-manager -O1 -debug-info-kind=line-tables-only -emit-llvm-only -mllvm -mandatory-inlining-first=false -verify +// RUN: %clang_cc1 %s -Rpass=inline -fexperimental-new-pass-manager -O1 -debug-info-kind=line-tables-only -emit-llvm-only -verify int foo(int x, int y) __attribute__((always_inline)); int foo(int x, int y) { return x + y; } diff --git a/clang/test/Frontend/optimization-remark-new-pm.c b/clang/test/Frontend/optimization-remark-new-pm.c --- a/clang/test/Frontend/optimization-remark-new-pm.c +++ b/clang/test/Frontend/optimization-remark-new-pm.c @@ -1,8 +1,8 @@ // Verify that remarks for the inliner appear. The remarks under the new PM will // be slightly different than those emitted by the legacy PM. The new PM inliner // also doesnot appear to be added at O0, so we test at O1. -// RUN: %clang_cc1 %s -Rpass=inline -Rpass-analysis=inline -Rpass-missed=inline -O1 -fexperimental-new-pass-manager -emit-llvm-only -mllvm -mandatory-inlining-first=false -verify -// RUN: %clang_cc1 %s -Rpass=inline -Rpass-analysis=inline -Rpass-missed=inline -O1 -fexperimental-new-pass-manager -emit-llvm-only -debug-info-kind=line-tables-only -mllvm -mandatory-inlining-first=false -verify +// RUN: %clang_cc1 %s -Rpass=inline -Rpass-analysis=inline -Rpass-missed=inline -O1 -fexperimental-new-pass-manager -emit-llvm-only -verify +// RUN: %clang_cc1 %s -Rpass=inline -Rpass-analysis=inline -Rpass-missed=inline -O1 -fexperimental-new-pass-manager -emit-llvm-only -debug-info-kind=line-tables-only -verify int foo(int x, int y) __attribute__((always_inline)); int foo(int x, int y) { return x + y; } diff --git a/clang/test/Frontend/optimization-remark-with-hotness-new-pm.c b/clang/test/Frontend/optimization-remark-with-hotness-new-pm.c --- a/clang/test/Frontend/optimization-remark-with-hotness-new-pm.c +++ b/clang/test/Frontend/optimization-remark-with-hotness-new-pm.c @@ -18,47 +18,47 @@ // RUN: -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ // RUN: -fexperimental-new-pass-manager -O1 \ // RUN: -Rpass-analysis=inline -Rpass-missed=inline \ -// RUN: -fdiagnostics-show-hotness -verify -mllvm -mandatory-inlining-first=false +// RUN: -fdiagnostics-show-hotness -verify // The clang version of the previous test. // RUN: %clang -target x86_64-apple-macosx10.9 %s -c -emit-llvm -o /dev/null \ // RUN: -fprofile-instr-use=%t.profdata -Rpass=inline \ // RUN: -fexperimental-new-pass-manager -O1 \ // RUN: -Rpass-analysis=inline -Rpass-missed=inline \ -// RUN: -fdiagnostics-show-hotness -Xclang -verify -mllvm -mandatory-inlining-first=false +// RUN: -fdiagnostics-show-hotness -Xclang -verify // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \ // RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \ // RUN: -fprofile-sample-use=%t-sample.profdata -Rpass=inline \ // RUN: -fexperimental-new-pass-manager -O1 \ // RUN: -Rpass-analysis=inline -Rpass-missed=inline \ // RUN: -fdiagnostics-show-hotness -fdiagnostics-hotness-threshold=10 \ -// RUN: -verify -mllvm -mandatory-inlining-first=false +// RUN: -verify // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \ // RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \ // RUN: -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ // RUN: -fexperimental-new-pass-manager -O1 \ // RUN: -Rpass-analysis=inline -Rpass-missed=inline \ -// RUN: -fdiagnostics-show-hotness -fdiagnostics-hotness-threshold=10 -verify -mllvm -mandatory-inlining-first=false +// RUN: -fdiagnostics-show-hotness -fdiagnostics-hotness-threshold=10 -verify // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \ // RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \ // RUN: -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ // RUN: -fexperimental-new-pass-manager -O1 \ -// RUN: -Rpass-analysis=inline -mllvm -mandatory-inlining-first=false 2>&1 | FileCheck -check-prefix=HOTNESS_OFF %s +// RUN: -Rpass-analysis=inline 2>&1 | FileCheck -check-prefix=HOTNESS_OFF %s // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \ // RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \ // RUN: -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ // RUN: -fexperimental-new-pass-manager -O1 \ -// RUN: -Rpass-analysis=inline -Rno-pass-with-hotness -mllvm -mandatory-inlining-first=false 2>&1 | FileCheck \ +// RUN: -Rpass-analysis=inline -Rno-pass-with-hotness 2>&1 | FileCheck \ // RUN: -check-prefix=HOTNESS_OFF %s // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \ // RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \ // RUN: -fprofile-instrument-use-path=%t.profdata -Rpass=inline \ // RUN: -Rpass-analysis=inline -fdiagnostics-show-hotness \ -// RUN: -fdiagnostics-hotness-threshold=100 -mllvm -mandatory-inlining-first=false 2>&1 \ +// RUN: -fdiagnostics-hotness-threshold=100 2>&1 \ // RUN: | FileCheck -allow-empty -check-prefix=THRESHOLD %s // RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \ // RUN: optimization-remark-with-hotness.c %s -emit-llvm-only \ // RUN: -Rpass=inline -Rpass-analysis=inline \ -// RUN: -fdiagnostics-show-hotness -fdiagnostics-hotness-threshold=10 -mllvm -mandatory-inlining-first=false 2>&1 \ +// RUN: -fdiagnostics-show-hotness -fdiagnostics-hotness-threshold=10 2>&1 \ // RUN: | FileCheck -check-prefix=NO_PGO %s int foo(int x, int y) __attribute__((always_inline)); @@ -73,7 +73,7 @@ // THRESHOLD-NOT: hotness // NO_PGO: '-fdiagnostics-show-hotness' requires profile-guided optimization information // NO_PGO: '-fdiagnostics-hotness-threshold=' requires profile-guided optimization information - // expected-remark@+1 {{'foo' inlined into 'bar' with (cost=always): always inline attribute at callsite bar:8:10; (hotness:}} + // expected-remark@+1 {{'foo' inlined into 'bar': always inline attribute at callsite bar:8:10; (hotness:}} sum += foo(x, x - 2); } diff --git a/clang/test/Frontend/optimization-remark.c b/clang/test/Frontend/optimization-remark.c --- a/clang/test/Frontend/optimization-remark.c +++ b/clang/test/Frontend/optimization-remark.c @@ -20,12 +20,12 @@ // // The inliner for the new PM does not seem to be enabled at O0, but we still // get the same remarks with at least O1. -// RUN: %clang_cc1 %s -Rpass=inline -fexperimental-new-pass-manager -O1 -emit-llvm -mllvm -mandatory-inlining-first=false -o - 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS -// RUN: %clang_cc1 %s -Rpass=inline -fexperimental-new-pass-manager -O1 -Rno-everything -Reverything -emit-llvm -mllvm -mandatory-inlining-first=false -o - 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS +// RUN: %clang_cc1 %s -Rpass=inline -fexperimental-new-pass-manager -O1 -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS +// RUN: %clang_cc1 %s -Rpass=inline -fexperimental-new-pass-manager -O1 -Rno-everything -Reverything -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS // // Check that -w doesn't disable remarks. // RUN: %clang_cc1 %s -Rpass=inline -fno-experimental-new-pass-manager -w -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS -// RUN: %clang_cc1 %s -Rpass=inline -fexperimental-new-pass-manager -O1 -w -emit-llvm -mllvm -mandatory-inlining-first=false -o - 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS +// RUN: %clang_cc1 %s -Rpass=inline -fexperimental-new-pass-manager -O1 -w -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS // // -Reverything implies -Rpass=.*. // RUN: %clang_cc1 %s -Reverything -emit-llvm -o - 2>&1 | FileCheck %s --check-prefix=CHECK-REMARKS diff --git a/llvm/include/llvm/Analysis/InlineAdvisor.h b/llvm/include/llvm/Analysis/InlineAdvisor.h --- a/llvm/include/llvm/Analysis/InlineAdvisor.h +++ b/llvm/include/llvm/Analysis/InlineAdvisor.h @@ -263,10 +263,17 @@ /// Emit ORE message. void emitInlinedInto(OptimizationRemarkEmitter &ORE, DebugLoc DLoc, const BasicBlock *Block, const Function &Callee, - const Function &Caller, const InlineCost &IC, - bool ForProfileContext = false, + const Function &Caller, bool IsMandatory, + function_ref ExtraContext = {}, const char *PassName = nullptr); +/// Emit ORE message based in cost (default heuristic). +void emitInlinedIntoBasedOnCost(OptimizationRemarkEmitter &ORE, DebugLoc DLoc, + const BasicBlock *Block, const Function &Callee, + const Function &Caller, const InlineCost &IC, + bool ForProfileContext = false, + const char *PassName = nullptr); + /// get call site location as string std::string getCallSiteLocation(DebugLoc DLoc); diff --git a/llvm/lib/Analysis/InlineAdvisor.cpp b/llvm/lib/Analysis/InlineAdvisor.cpp --- a/llvm/lib/Analysis/InlineAdvisor.cpp +++ b/llvm/lib/Analysis/InlineAdvisor.cpp @@ -49,6 +49,42 @@ extern cl::opt InlinerFunctionImportStats; +namespace { +using namespace llvm::ore; +class MandatoryInlineAdvice : public InlineAdvice { +public: + MandatoryInlineAdvice(InlineAdvisor *Advisor, CallBase &CB, + OptimizationRemarkEmitter &ORE, + bool IsInliningMandatory) + : InlineAdvice(Advisor, CB, ORE, IsInliningMandatory) {} + +private: + void recordInliningWithCalleeDeletedImpl() override { recordInliningImpl(); } + + void recordInliningImpl() override { + if (IsInliningRecommended) + emitInlinedInto(ORE, DLoc, Block, *Callee, *Caller, IsInliningRecommended, + [&](OptimizationRemark &Remark) { + Remark << ": always inline attribute"; + }); + } + + void recordUnsuccessfulInliningImpl(const InlineResult &Result) override { + if (IsInliningRecommended) + ORE.emit([&]() { + return OptimizationRemarkMissed(DEBUG_TYPE, "NotInlined", DLoc, Block) + << "'" << NV("Callee", Callee) << "' is not AlwaysInline into '" + << NV("Caller", Caller) + << "': " << NV("Reason", Result.getFailureReason()); + }); + } + + void recordUnattemptedInliningImpl() override { + assert(!IsInliningRecommended && "Expected to attempt inlining"); + } +}; +} // namespace + void DefaultInlineAdvice::recordUnsuccessfulInliningImpl( const InlineResult &Result) { using namespace ore; @@ -64,12 +100,12 @@ void DefaultInlineAdvice::recordInliningWithCalleeDeletedImpl() { if (EmitRemarks) - emitInlinedInto(ORE, DLoc, Block, *Callee, *Caller, *OIC); + emitInlinedIntoBasedOnCost(ORE, DLoc, Block, *Callee, *Caller, *OIC); } void DefaultInlineAdvice::recordInliningImpl() { if (EmitRemarks) - emitInlinedInto(ORE, DLoc, Block, *Callee, *Caller, *OIC); + emitInlinedIntoBasedOnCost(ORE, DLoc, Block, *Callee, *Caller, *OIC); } llvm::Optional static getDefaultInlineAdvice( @@ -435,25 +471,38 @@ Remark << ";"; } -void llvm::emitInlinedInto(OptimizationRemarkEmitter &ORE, DebugLoc DLoc, - const BasicBlock *Block, const Function &Callee, - const Function &Caller, const InlineCost &IC, - bool ForProfileContext, const char *PassName) { +void llvm::emitInlinedInto( + OptimizationRemarkEmitter &ORE, DebugLoc DLoc, const BasicBlock *Block, + const Function &Callee, const Function &Caller, bool AlwaysInline, + function_ref ExtraContext, + const char *PassName) { ORE.emit([&]() { - bool AlwaysInline = IC.isAlways(); StringRef RemarkName = AlwaysInline ? "AlwaysInline" : "Inlined"; OptimizationRemark Remark(PassName ? PassName : DEBUG_TYPE, RemarkName, DLoc, Block); Remark << "'" << ore::NV("Callee", &Callee) << "' inlined into '" << ore::NV("Caller", &Caller) << "'"; - if (ForProfileContext) - Remark << " to match profiling context"; - Remark << " with " << IC; + if (ExtraContext) + ExtraContext(Remark); addLocationToRemarks(Remark, DLoc); return Remark; }); } +void llvm::emitInlinedIntoBasedOnCost( + OptimizationRemarkEmitter &ORE, DebugLoc DLoc, const BasicBlock *Block, + const Function &Callee, const Function &Caller, const InlineCost &IC, + bool ForProfileContext, const char *PassName) { + llvm::emitInlinedInto( + ORE, DLoc, Block, Callee, Caller, IC.isAlways(), + [&](OptimizationRemark &Remark) { + if (ForProfileContext) + Remark << " to match profiling context"; + Remark << " with " << IC; + }, + PassName); +} + InlineAdvisor::InlineAdvisor(Module &M, FunctionAnalysisManager &FAM) : M(M), FAM(FAM) { if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No) { @@ -475,7 +524,8 @@ std::unique_ptr InlineAdvisor::getMandatoryAdvice(CallBase &CB, bool Advice) { - return std::make_unique(this, CB, getCallerORE(CB), Advice); + return std::make_unique(this, CB, getCallerORE(CB), + Advice); } InlineAdvisor::MandatoryInliningKind diff --git a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp --- a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp +++ b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp @@ -73,8 +73,8 @@ }, ORE); assert(OIC); - emitInlinedInto(ORE, CB->getDebugLoc(), CB->getParent(), F, *Caller, - *OIC, false, DEBUG_TYPE); + emitInlinedIntoBasedOnCost(ORE, CB->getDebugLoc(), CB->getParent(), F, + *Caller, *OIC, false, DEBUG_TYPE); InlineFunctionInfo IFI( /*cg=*/nullptr, GetAssumptionCache, &PSI, diff --git a/llvm/lib/Transforms/IPO/Inliner.cpp b/llvm/lib/Transforms/IPO/Inliner.cpp --- a/llvm/lib/Transforms/IPO/Inliner.cpp +++ b/llvm/lib/Transforms/IPO/Inliner.cpp @@ -464,7 +464,7 @@ } ++NumInlined; - emitInlinedInto(ORE, DLoc, Block, *Callee, *Caller, *OIC); + emitInlinedIntoBasedOnCost(ORE, DLoc, Block, *Callee, *Caller, *OIC); // If inlining this function gave us any new call sites, throw them // onto our worklist to process. They are useful inline candidates. diff --git a/llvm/lib/Transforms/IPO/SampleProfile.cpp b/llvm/lib/Transforms/IPO/SampleProfile.cpp --- a/llvm/lib/Transforms/IPO/SampleProfile.cpp +++ b/llvm/lib/Transforms/IPO/SampleProfile.cpp @@ -1204,8 +1204,8 @@ *CalledFunction); // The call to InlineFunction erases I, so we can't pass it here. - emitInlinedInto(*ORE, DLoc, BB, *CalledFunction, *BB->getParent(), Cost, - true, CSINLINE_DEBUG); + emitInlinedIntoBasedOnCost(*ORE, DLoc, BB, *CalledFunction, + *BB->getParent(), Cost, true, CSINLINE_DEBUG); // Now populate the list of newly exposed call sites. if (InlinedCallSites) { diff --git a/llvm/test/Transforms/Inline/inline-remark-mandatory.ll b/llvm/test/Transforms/Inline/inline-remark-mandatory.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Inline/inline-remark-mandatory.ll @@ -0,0 +1,16 @@ +; RUN: opt -passes="cgscc(inline)" -pass-remarks-missed=inline -S < %s 2>&1 | FileCheck %s + +declare void @personalityFn1(); +declare void @personalityFn2(); + +define i32 @a() personality void ()* @personalityFn1 { + ret i32 1 +} + +define i32 @b() personality void ()* @personalityFn2 { + %r = call i32 @a() alwaysinline + ret i32 %r +} + +; CHECK: remark: {{.*}} 'a' is not AlwaysInline into 'b': incompatible personality +