forked from OSchip/llvm-project
[inliner] Mandatory inlining decisions produce remarks
This also removes the need to disable the mandatory inlining phase in tests. In a departure from the previous remark, we don't output a 'cost' in this case, because there's no such thing. We just report that inlining happened because of the attribute. Differential Revision: https://reviews.llvm.org/D110891
This commit is contained in:
parent
7c9d9e4e64
commit
7d541eb4d4
|
@ -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; }
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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 @@ void bar(int x) {
|
|||
// 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -263,10 +263,17 @@ shouldInline(CallBase &CB, function_ref<InlineCost(CallBase &CB)> GetInlineCost,
|
|||
/// 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<void(OptimizationRemark &)> 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);
|
||||
|
||||
|
|
|
@ -49,6 +49,42 @@ static cl::opt<int>
|
|||
|
||||
extern cl::opt<InlinerFunctionImportStatsOpts> 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::recordUnsuccessfulInliningImpl(
|
|||
|
||||
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<llvm::InlineCost> static getDefaultInlineAdvice(
|
||||
|
@ -435,25 +471,38 @@ void llvm::addLocationToRemarks(OptimizationRemark &Remark, DebugLoc DLoc) {
|
|||
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<void(OptimizationRemark &)> 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 @@ InlineAdvisor::~InlineAdvisor() {
|
|||
|
||||
std::unique_ptr<InlineAdvice> InlineAdvisor::getMandatoryAdvice(CallBase &CB,
|
||||
bool Advice) {
|
||||
return std::make_unique<InlineAdvice>(this, CB, getCallerORE(CB), Advice);
|
||||
return std::make_unique<MandatoryInlineAdvice>(this, CB, getCallerORE(CB),
|
||||
Advice);
|
||||
}
|
||||
|
||||
InlineAdvisor::MandatoryInliningKind
|
||||
|
|
|
@ -73,8 +73,8 @@ PreservedAnalyses AlwaysInlinerPass::run(Module &M,
|
|||
},
|
||||
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,
|
||||
|
|
|
@ -464,7 +464,7 @@ inlineCallsImpl(CallGraphSCC &SCC, CallGraph &CG,
|
|||
}
|
||||
++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.
|
||||
|
|
|
@ -1204,8 +1204,8 @@ bool SampleProfileLoader::tryInlineCandidate(
|
|||
*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) {
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
; RUN: opt -passes="cgscc(inline<only-mandatory>)" -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
|
||||
|
Loading…
Reference in New Issue