diff --git a/llvm/lib/Analysis/MLInlineAdvisor.cpp b/llvm/lib/Analysis/MLInlineAdvisor.cpp index f90717d3085eb..1d1a5560be478 100644 --- a/llvm/lib/Analysis/MLInlineAdvisor.cpp +++ b/llvm/lib/Analysis/MLInlineAdvisor.cpp @@ -61,6 +61,9 @@ static cl::opt SkipPolicy( static cl::opt ModelSelector("ml-inliner-model-selector", cl::Hidden, cl::init("")); +static cl::opt StopImmediatelyForTest("ml-inliner-stop-immediately", + cl::Hidden); + #if defined(LLVM_HAVE_TF_AOT_INLINERSIZEMODEL) // codegen-ed file #include "InlinerSizeModel.h" // NOLINT @@ -214,6 +217,7 @@ MLInlineAdvisor::MLInlineAdvisor( return; } ModelRunner->switchContext(""); + ForceStop = StopImmediatelyForTest; } unsigned MLInlineAdvisor::getInitialFunctionLevel(const Function &F) const { @@ -379,9 +383,17 @@ std::unique_ptr MLInlineAdvisor::getAdviceImpl(CallBase &CB) { auto &ORE = FAM.getResult(Caller); if (SkipPolicy == SkipMLPolicyCriteria::IfCallerIsNotCold) { - if (!PSI.isFunctionEntryCold(&Caller)) - return std::make_unique(this, CB, ORE, - GetDefaultAdvice(CB)); + if (!PSI.isFunctionEntryCold(&Caller)) { + // Return a MLInlineAdvice, despite delegating to the default advice, + // because we need to keep track of the internal state. This is different + // from the other instances where we return a "default" InlineAdvice, + // which happen at points we won't come back to the MLAdvisor for + // decisions requiring that state. + return ForceStop ? std::make_unique(this, CB, ORE, + GetDefaultAdvice(CB)) + : std::make_unique(this, CB, ORE, + GetDefaultAdvice(CB)); + } } auto MandatoryKind = InlineAdvisor::getMandatoryKind(CB, FAM, ORE); // If this is a "never inline" case, there won't be any changes to internal diff --git a/llvm/test/Transforms/Inline/ML/state-accounting-skip-non-cold.ll b/llvm/test/Transforms/Inline/ML/state-accounting-skip-non-cold.ll new file mode 100644 index 0000000000000..0887f5e29187d --- /dev/null +++ b/llvm/test/Transforms/Inline/ML/state-accounting-skip-non-cold.ll @@ -0,0 +1,55 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; REQUIRES: llvm_inliner_model_autogenerated && asserts +; RUN: opt -passes='default' -enable-ml-inliner=release -ml-inliner-skip-policy=if-caller-not-cold -S %s -o - | FileCheck %s +; RUN: opt -passes='default' -ml-inliner-stop-immediately -enable-ml-inliner=release -ml-inliner-skip-policy=if-caller-not-cold -S %s -o - | FileCheck %s + +declare ptr @f() + +define void @e() #0 { +; CHECK-LABEL: define void @e( +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] { +; CHECK-NEXT: tail call void @d() +; CHECK-NEXT: tail call void @g() +; CHECK-NEXT: tail call void @d() +; CHECK-NEXT: tail call void @g() +; CHECK-NEXT: tail call void @d() +; CHECK-NEXT: tail call void @g() +; CHECK-NEXT: ret void +; + call void @h() + call void @h() + call void @h() + ret void +} + +define void @d() { +; CHECK-LABEL: define void @d() local_unnamed_addr { +; CHECK-NEXT: tail call void @f() +; CHECK-NEXT: ret void +; + call void @f() + ret void +} + +define void @g() { +; CHECK-LABEL: define void @g() local_unnamed_addr { +; CHECK-NEXT: tail call void @f() +; CHECK-NEXT: ret void +; + call void @f() + ret void +} + +define void @h() #0 { +; CHECK-LABEL: define void @h( +; CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] { +; CHECK-NEXT: tail call void @d() +; CHECK-NEXT: tail call void @g() +; CHECK-NEXT: ret void +; + call void @d() + call void @g() + ret void +} + +attributes #0 = { "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" }