From 8a0904b8d5b9a7904e8285ddb3932248bbffa75c Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Tue, 7 Oct 2025 11:12:27 +0000 Subject: [PATCH 1/5] [Coroutines] Conditional elide coroutines based on hot/cold information Unconditionally eliding all `[[clang::coro_await_elidable]]` coroutines is not good. For example, ``` Task bar(); Task foo(bool b) { if (b) [[unlikely]] { co_await bar(); } } ``` Assume Task is marked with [[clang::coro_await_elidable]], now we will always elide the call to bar() into the frame of foo(). But this may be a regression instead of an optimization if b is always false. This patch tries to mitigate the problem by leveraging hot/cold information. This can be optimized further in the future but at least this patch makes things better. This patch was originally written by ChuanqiXu9, but stalled during PR review because the diagnostics were not integrated with the existing optimization remarks. I rebased the original patch, integrated it with the optimization remarks, and did a couple of smaller cosmetic changes (e.g., made the test case expectations more targetted, etc.) Co-Authored-by: Chuanqi Xu --- .../Coroutines/CoroAnnotationElide.cpp | 77 ++++++++++++++++++ llvm/lib/Transforms/IPO/PartialInlining.cpp | 2 +- .../Coroutines/coro-conditional-elide.ll | 79 +++++++++++++++++++ 3 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Transforms/Coroutines/coro-conditional-elide.ll diff --git a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp index 9115946d205a4..d4d0c0f0895bb 100644 --- a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp @@ -24,6 +24,9 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" +#include "llvm/Support/BranchProbability.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Transforms/Utils/CallGraphUpdater.h" #include "llvm/Transforms/Utils/Cloning.h" @@ -33,6 +36,49 @@ using namespace llvm; #define DEBUG_TYPE "coro-annotation-elide" +static cl::opt CoroElideBranchRatio( + "coro-elide-branch-ratio", cl::init(0.55), cl::Hidden, + cl::desc("Minimum BranchProbability to consider a elide a coroutine.")); +extern cl::opt MinBlockCounterExecution; + +static cl::opt + PrintElidedCoroutine("print-elided-coroutine-stats", cl::init(false), + cl::Hidden, + cl::desc("Print stats for elided coroutine")); + +static cl::opt + ElideStatOutput("coro-elide-stat-output", cl::init(""), cl::Hidden, + cl::desc("Output file for -print-elided-coroutine-stats. " + "Defaults to standard error output.")); + +// The return value is used to indicate the owner of the resources. The users +// should use the output parameter. +static std::unique_ptr +getCoroElidedStatsOStream(llvm::raw_ostream *&OS) { + if (!PrintElidedCoroutine) { + OS = &llvm::nulls(); + return nullptr; + } + + if (ElideStatOutput.empty()) { + OS = &llvm::errs(); + return nullptr; + } + + std::error_code EC; + auto ret = std::make_unique(ElideStatOutput, EC, + sys::fs::OF_Append); + + if (EC) { + llvm::errs() << "llvm cannot open file: " << EC.message() << "\n"; + OS = &llvm::nulls(); + return nullptr; + } + + OS = ret.get(); + return ret; +} + static Instruction *getFirstNonAllocaInTheEntryBlock(Function *F) { for (Instruction &I : F->getEntryBlock()) if (!isa(&I)) @@ -145,6 +191,37 @@ PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C, bool IsCallerPresplitCoroutine = Caller->isPresplitCoroutine(); bool HasAttr = CB->hasFnAttr(llvm::Attribute::CoroElideSafe); if (IsCallerPresplitCoroutine && HasAttr) { + + llvm::raw_ostream *OS = nullptr; + auto _ = getCoroElidedStatsOStream(OS); + assert(OS && "At least we should able to get access to standard error"); + + auto &BFI = FAM.getResult(*Caller); + if (BFI.getBlockFreq(CB->getParent()) < + BFI.getEntryFreq()) { + static BranchProbability MinBranchProbability( + static_cast(CoroElideBranchRatio * MinBlockCounterExecution), + MinBlockCounterExecution); + + auto Prob = BranchProbability::getBranchProbability( + BFI.getBlockFreq(CB->getParent()).getFrequency(), + BFI.getEntryFreq().getFrequency()); + + if (Prob < MinBranchProbability) { + *OS << "Not eliding " << *CB + << " with estimated probability: " << Prob << "\n"; + continue; + } + + *OS << "BB Prob: \t" << Prob << "\n"; + } else { + *OS << "BB Freq: \t" + << BFI.getBlockFreq(CB->getParent()).getFrequency() << "\n"; + *OS << "Entry Freq: \t" << BFI.getEntryFreq().getFrequency() << "\n"; + } + + *OS << "eliding " << *CB << "\n"; + auto *CallerN = CG.lookup(*Caller); auto *CallerC = CallerN ? CG.lookupSCC(*CallerN) : nullptr; // If CallerC is nullptr, it means LazyCallGraph hasn't visited Caller diff --git a/llvm/lib/Transforms/IPO/PartialInlining.cpp b/llvm/lib/Transforms/IPO/PartialInlining.cpp index 2583249e65484..1a00d173d3ae0 100644 --- a/llvm/lib/Transforms/IPO/PartialInlining.cpp +++ b/llvm/lib/Transforms/IPO/PartialInlining.cpp @@ -109,7 +109,7 @@ static cl::opt MinRegionSizeRatio( "outline candidate and original function")); // Used to tune the minimum number of execution counts needed in the predecessor // block to the cold edge. ie. confidence interval. -static cl::opt +cl::opt MinBlockCounterExecution("min-block-execution", cl::init(100), cl::Hidden, cl::desc("Minimum block executions to consider " "its BranchProbabilityInfo valid")); diff --git a/llvm/test/Transforms/Coroutines/coro-conditional-elide.ll b/llvm/test/Transforms/Coroutines/coro-conditional-elide.ll new file mode 100644 index 0000000000000..04c5bf0494278 --- /dev/null +++ b/llvm/test/Transforms/Coroutines/coro-conditional-elide.ll @@ -0,0 +1,79 @@ +; Testing elide performed its job for calls to coroutines marked safe. +; RUN: opt < %s -S -passes='cgscc(coro-annotation-elide)' -coro-elide-branch-ratio=0.55 | FileCheck %s + +%struct.Task = type { ptr } + +declare void @print(i32) nounwind + +; resume part of the coroutine +define fastcc void @callee.resume(ptr dereferenceable(1)) { + tail call void @print(i32 0) + ret void +} + +; destroy part of the coroutine +define fastcc void @callee.destroy(ptr) { + tail call void @print(i32 1) + ret void +} + +; cleanup part of the coroutine +define fastcc void @callee.cleanup(ptr) { + tail call void @print(i32 2) + ret void +} + +@callee.resumers = internal constant [3 x ptr] [ + ptr @callee.resume, ptr @callee.destroy, ptr @callee.cleanup] + +declare void @alloc(i1) nounwind + +; CHECK-LABEL: define ptr @callee +define ptr @callee(i8 %arg) { +entry: + %task = alloca %struct.Task, align 8 + %id = call token @llvm.coro.id(i32 0, ptr null, + ptr @callee, + ptr @callee.resumers) + %alloc = call i1 @llvm.coro.alloc(token %id) + %hdl = call ptr @llvm.coro.begin(token %id, ptr null) + store ptr %hdl, ptr %task + ret ptr %task +} + +; CHECK-LABEL: define ptr @callee.noalloc +define ptr @callee.noalloc(i8 %arg, ptr dereferenceable(32) align(8) %frame) { + entry: + %task = alloca %struct.Task, align 8 + %id = call token @llvm.coro.id(i32 0, ptr null, + ptr @callee, + ptr @callee.resumers) + %hdl = call ptr @llvm.coro.begin(token %id, ptr null) + store ptr %hdl, ptr %task + ret ptr %task +} + +; CHECK-LABEL: define ptr @caller(i1 %cond) +; Function Attrs: presplitcoroutine +define ptr @caller(i1 %cond) #0 { +entry: + br i1 %cond, label %call, label %ret + +call: + %task = call ptr @callee(i8 0) #1 + br label %ret + +ret: + %retval = phi ptr [ %task, %call ], [ null, %entry ] + ret ptr %retval + ; CHECK-NOT: alloca +} + +declare token @llvm.coro.id(i32, ptr, ptr, ptr) +declare ptr @llvm.coro.begin(token, ptr) +declare ptr @llvm.coro.frame() +declare ptr @llvm.coro.subfn.addr(ptr, i8) +declare i1 @llvm.coro.alloc(token) + +attributes #0 = { presplitcoroutine } +attributes #1 = { coro_elide_safe } From c1cb5d9f68f97b256f40745185e5ca5e416bd7cd Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Tue, 7 Oct 2025 11:50:08 +0000 Subject: [PATCH 2/5] Integrate with Optimization Remarks --- llvm/include/llvm/IR/DiagnosticInfo.h | 2 + llvm/lib/IR/DiagnosticInfo.cpp | 7 ++ .../Coroutines/CoroAnnotationElide.cpp | 82 ++++--------------- 3 files changed, 26 insertions(+), 65 deletions(-) diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h index 5f7225e878eb1..a426fb079ec04 100644 --- a/llvm/include/llvm/IR/DiagnosticInfo.h +++ b/llvm/include/llvm/IR/DiagnosticInfo.h @@ -20,6 +20,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DebugLoc.h" +#include "llvm/Support/BranchProbability.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" @@ -555,6 +556,7 @@ class LLVM_ABI DiagnosticInfoOptimizationBase Argument(StringRef Key, bool B) : Key(Key), Val(B ? "true" : "false") {} LLVM_ABI Argument(StringRef Key, DebugLoc dl); LLVM_ABI Argument(StringRef Key, InstructionCost C); + LLVM_ABI Argument(StringRef Key, BranchProbability P); }; /// \p PassName is the name of the pass emitting this diagnostic. \p diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp index 4f3762427e012..44574362e3405 100644 --- a/llvm/lib/IR/DiagnosticInfo.cpp +++ b/llvm/lib/IR/DiagnosticInfo.cpp @@ -273,6 +273,13 @@ DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, C.print(OS); } +DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, + BranchProbability P) +: Key(std::string(Key)) { + raw_string_ostream OS(Val); + P.print(OS); +} + DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, DebugLoc Loc) : Key(std::string(Key)), Loc(Loc) { if (Loc) { diff --git a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp index d4d0c0f0895bb..6cbda6b38768d 100644 --- a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp @@ -41,44 +41,6 @@ static cl::opt CoroElideBranchRatio( cl::desc("Minimum BranchProbability to consider a elide a coroutine.")); extern cl::opt MinBlockCounterExecution; -static cl::opt - PrintElidedCoroutine("print-elided-coroutine-stats", cl::init(false), - cl::Hidden, - cl::desc("Print stats for elided coroutine")); - -static cl::opt - ElideStatOutput("coro-elide-stat-output", cl::init(""), cl::Hidden, - cl::desc("Output file for -print-elided-coroutine-stats. " - "Defaults to standard error output.")); - -// The return value is used to indicate the owner of the resources. The users -// should use the output parameter. -static std::unique_ptr -getCoroElidedStatsOStream(llvm::raw_ostream *&OS) { - if (!PrintElidedCoroutine) { - OS = &llvm::nulls(); - return nullptr; - } - - if (ElideStatOutput.empty()) { - OS = &llvm::errs(); - return nullptr; - } - - std::error_code EC; - auto ret = std::make_unique(ElideStatOutput, EC, - sys::fs::OF_Append); - - if (EC) { - llvm::errs() << "llvm cannot open file: " << EC.message() << "\n"; - OS = &llvm::nulls(); - return nullptr; - } - - OS = ret.get(); - return ret; -} - static Instruction *getFirstNonAllocaInTheEntryBlock(Function *F) { for (Instruction &I : F->getEntryBlock()) if (!isa(&I)) @@ -191,37 +153,27 @@ PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C, bool IsCallerPresplitCoroutine = Caller->isPresplitCoroutine(); bool HasAttr = CB->hasFnAttr(llvm::Attribute::CoroElideSafe); if (IsCallerPresplitCoroutine && HasAttr) { - - llvm::raw_ostream *OS = nullptr; - auto _ = getCoroElidedStatsOStream(OS); - assert(OS && "At least we should able to get access to standard error"); + static BranchProbability MinBranchProbability( + static_cast(CoroElideBranchRatio * MinBlockCounterExecution), + MinBlockCounterExecution); auto &BFI = FAM.getResult(*Caller); - if (BFI.getBlockFreq(CB->getParent()) < - BFI.getEntryFreq()) { - static BranchProbability MinBranchProbability( - static_cast(CoroElideBranchRatio * MinBlockCounterExecution), - MinBlockCounterExecution); - auto Prob = BranchProbability::getBranchProbability( - BFI.getBlockFreq(CB->getParent()).getFrequency(), - BFI.getEntryFreq().getFrequency()); - - if (Prob < MinBranchProbability) { - *OS << "Not eliding " << *CB - << " with estimated probability: " << Prob << "\n"; - continue; - } - - *OS << "BB Prob: \t" << Prob << "\n"; - } else { - *OS << "BB Freq: \t" - << BFI.getBlockFreq(CB->getParent()).getFrequency() << "\n"; - *OS << "Entry Freq: \t" << BFI.getEntryFreq().getFrequency() << "\n"; + auto Prob = BranchProbability::getBranchProbability( + BFI.getBlockFreq(CB->getParent()).getFrequency(), + BFI.getEntryFreq().getFrequency()); + + if (Prob < MinBranchProbability) { + ORE.emit([&]() { + return OptimizationRemarkMissed(DEBUG_TYPE, "CoroAnnotationElideUnlikely", Caller) + << "'" << ore::NV("callee", Callee->getName()) + << "' not elided in '" << ore::NV("caller", Caller->getName()) + << "' because of low probability: " << ore::NV("probability", Prob) + << " (threshold: " << ore::NV("threshold", MinBranchProbability) << ")"; + }); + continue; } - *OS << "eliding " << *CB << "\n"; - auto *CallerN = CG.lookup(*Caller); auto *CallerC = CallerN ? CG.lookupSCC(*CallerN) : nullptr; // If CallerC is nullptr, it means LazyCallGraph hasn't visited Caller @@ -233,7 +185,7 @@ PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C, return OptimizationRemark(DEBUG_TYPE, "CoroAnnotationElide", Caller) << "'" << ore::NV("callee", Callee->getName()) << "' elided in '" << ore::NV("caller", Caller->getName()) - << "'"; + << "' (probability: " << ore::NV("probability", Prob) << ")"; }); FAM.invalidate(*Caller, PreservedAnalyses::none()); From 1304785a1197dffbbeeea66b6faf41233b171e8a Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Tue, 7 Oct 2025 11:59:40 +0000 Subject: [PATCH 3/5] Change test case --- .../Coroutines/coro-conditional-elide.ll | 79 ------------------- ...sform-must-elide.ll => coro-elide-safe.ll} | 28 ++++++- 2 files changed, 25 insertions(+), 82 deletions(-) delete mode 100644 llvm/test/Transforms/Coroutines/coro-conditional-elide.ll rename llvm/test/Transforms/Coroutines/{coro-transform-must-elide.ll => coro-elide-safe.ll} (74%) diff --git a/llvm/test/Transforms/Coroutines/coro-conditional-elide.ll b/llvm/test/Transforms/Coroutines/coro-conditional-elide.ll deleted file mode 100644 index 04c5bf0494278..0000000000000 --- a/llvm/test/Transforms/Coroutines/coro-conditional-elide.ll +++ /dev/null @@ -1,79 +0,0 @@ -; Testing elide performed its job for calls to coroutines marked safe. -; RUN: opt < %s -S -passes='cgscc(coro-annotation-elide)' -coro-elide-branch-ratio=0.55 | FileCheck %s - -%struct.Task = type { ptr } - -declare void @print(i32) nounwind - -; resume part of the coroutine -define fastcc void @callee.resume(ptr dereferenceable(1)) { - tail call void @print(i32 0) - ret void -} - -; destroy part of the coroutine -define fastcc void @callee.destroy(ptr) { - tail call void @print(i32 1) - ret void -} - -; cleanup part of the coroutine -define fastcc void @callee.cleanup(ptr) { - tail call void @print(i32 2) - ret void -} - -@callee.resumers = internal constant [3 x ptr] [ - ptr @callee.resume, ptr @callee.destroy, ptr @callee.cleanup] - -declare void @alloc(i1) nounwind - -; CHECK-LABEL: define ptr @callee -define ptr @callee(i8 %arg) { -entry: - %task = alloca %struct.Task, align 8 - %id = call token @llvm.coro.id(i32 0, ptr null, - ptr @callee, - ptr @callee.resumers) - %alloc = call i1 @llvm.coro.alloc(token %id) - %hdl = call ptr @llvm.coro.begin(token %id, ptr null) - store ptr %hdl, ptr %task - ret ptr %task -} - -; CHECK-LABEL: define ptr @callee.noalloc -define ptr @callee.noalloc(i8 %arg, ptr dereferenceable(32) align(8) %frame) { - entry: - %task = alloca %struct.Task, align 8 - %id = call token @llvm.coro.id(i32 0, ptr null, - ptr @callee, - ptr @callee.resumers) - %hdl = call ptr @llvm.coro.begin(token %id, ptr null) - store ptr %hdl, ptr %task - ret ptr %task -} - -; CHECK-LABEL: define ptr @caller(i1 %cond) -; Function Attrs: presplitcoroutine -define ptr @caller(i1 %cond) #0 { -entry: - br i1 %cond, label %call, label %ret - -call: - %task = call ptr @callee(i8 0) #1 - br label %ret - -ret: - %retval = phi ptr [ %task, %call ], [ null, %entry ] - ret ptr %retval - ; CHECK-NOT: alloca -} - -declare token @llvm.coro.id(i32, ptr, ptr, ptr) -declare ptr @llvm.coro.begin(token, ptr) -declare ptr @llvm.coro.frame() -declare ptr @llvm.coro.subfn.addr(ptr, i8) -declare i1 @llvm.coro.alloc(token) - -attributes #0 = { presplitcoroutine } -attributes #1 = { coro_elide_safe } diff --git a/llvm/test/Transforms/Coroutines/coro-transform-must-elide.ll b/llvm/test/Transforms/Coroutines/coro-elide-safe.ll similarity index 74% rename from llvm/test/Transforms/Coroutines/coro-transform-must-elide.ll rename to llvm/test/Transforms/Coroutines/coro-elide-safe.ll index 4eec7edad8b0f..722693d4caafd 100644 --- a/llvm/test/Transforms/Coroutines/coro-transform-must-elide.ll +++ b/llvm/test/Transforms/Coroutines/coro-elide-safe.ll @@ -1,4 +1,8 @@ -; Testing elide performed its job for calls to coroutines marked safe. +; Coroutine calls marked with `coro_elide_safe` should be elided. +; Inside `caller`, we expect the `callee` coroutine to be elided. +; Inside `caller_conditional`, `callee` is only called on an unlikely +; path, hence we expect the `callee` coroutine NOT to be elided. +; ; RUN: opt < %s -S -passes='cgscc(coro-annotation-elide)' | FileCheck %s %struct.Task = type { ptr } @@ -57,7 +61,7 @@ define ptr @callee.noalloc(i8 %arg, ptr dereferenceable(32) align(8) %frame) { ; Function Attrs: presplitcoroutine define ptr @caller() #0 { entry: - %task = call ptr @callee(i8 0) #1 + %task = call ptr @callee(i8 0) coro_elide_safe ret ptr %task ; CHECK: %[[TASK:.+]] = alloca %struct.Task, align 8 ; CHECK-NEXT: %[[FRAME:.+]] = alloca [32 x i8], align 8 @@ -69,6 +73,25 @@ entry: ; CHECK-NEXT: ret ptr %[[TASK]] } +; CHECK-LABEL: define ptr @caller_conditional(i1 %cond) +; Function Attrs: presplitcoroutine +define ptr @caller_conditional(i1 %cond) #0 { +entry: + br i1 %cond, label %call, label %ret + +call: + ; CHECK-NOT: alloca + ; CHECK-NOT: @llvm.coro.id({{.*}}, ptr @callee, {{.*}}) + ; CHECK: %task = call ptr @callee(i8 0) + ; CHECK-NEXT: br label %ret + %task = call ptr @callee(i8 0) coro_elide_safe + br label %ret + +ret: + %retval = phi ptr [ %task, %call ], [ null, %entry ] + ret ptr %retval +} + declare token @llvm.coro.id(i32, ptr, ptr, ptr) declare ptr @llvm.coro.begin(token, ptr) declare ptr @llvm.coro.frame() @@ -76,4 +99,3 @@ declare ptr @llvm.coro.subfn.addr(ptr, i8) declare i1 @llvm.coro.alloc(token) attributes #0 = { presplitcoroutine } -attributes #1 = { coro_elide_safe } From b2ac353139444af7d5482f70d87e53e918a34fc2 Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Tue, 7 Oct 2025 12:38:27 +0000 Subject: [PATCH 4/5] Fix formatting --- llvm/lib/IR/DiagnosticInfo.cpp | 2 +- .../Coroutines/CoroAnnotationElide.cpp | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp index 44574362e3405..8e6d654f6afb3 100644 --- a/llvm/lib/IR/DiagnosticInfo.cpp +++ b/llvm/lib/IR/DiagnosticInfo.cpp @@ -275,7 +275,7 @@ DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, DiagnosticInfoOptimizationBase::Argument::Argument(StringRef Key, BranchProbability P) -: Key(std::string(Key)) { + : Key(std::string(Key)) { raw_string_ostream OS(Val); P.print(OS); } diff --git a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp index 6cbda6b38768d..120ffc489fa68 100644 --- a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp @@ -154,8 +154,8 @@ PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C, bool HasAttr = CB->hasFnAttr(llvm::Attribute::CoroElideSafe); if (IsCallerPresplitCoroutine && HasAttr) { static BranchProbability MinBranchProbability( - static_cast(CoroElideBranchRatio * MinBlockCounterExecution), - MinBlockCounterExecution); + static_cast(CoroElideBranchRatio * MinBlockCounterExecution), + MinBlockCounterExecution); auto &BFI = FAM.getResult(*Caller); @@ -165,11 +165,14 @@ PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C, if (Prob < MinBranchProbability) { ORE.emit([&]() { - return OptimizationRemarkMissed(DEBUG_TYPE, "CoroAnnotationElideUnlikely", Caller) - << "'" << ore::NV("callee", Callee->getName()) - << "' not elided in '" << ore::NV("caller", Caller->getName()) - << "' because of low probability: " << ore::NV("probability", Prob) - << " (threshold: " << ore::NV("threshold", MinBranchProbability) << ")"; + return OptimizationRemarkMissed( + DEBUG_TYPE, "CoroAnnotationElideUnlikely", Caller) + << "'" << ore::NV("callee", Callee->getName()) + << "' not elided in '" + << ore::NV("caller", Caller->getName()) + << "' because of low probability: " + << ore::NV("probability", Prob) << " (threshold: " + << ore::NV("threshold", MinBranchProbability) << ")"; }); continue; } From b95b6a4ced77ed44d262618d574d192c7a88d76b Mon Sep 17 00:00:00 2001 From: Adrian Vogelsgesang Date: Thu, 9 Oct 2025 13:46:17 +0000 Subject: [PATCH 5/5] Remove static --- llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp index 120ffc489fa68..f166fef74941e 100644 --- a/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroAnnotationElide.cpp @@ -153,7 +153,7 @@ PreservedAnalyses CoroAnnotationElidePass::run(LazyCallGraph::SCC &C, bool IsCallerPresplitCoroutine = Caller->isPresplitCoroutine(); bool HasAttr = CB->hasFnAttr(llvm::Attribute::CoroElideSafe); if (IsCallerPresplitCoroutine && HasAttr) { - static BranchProbability MinBranchProbability( + BranchProbability MinBranchProbability( static_cast(CoroElideBranchRatio * MinBlockCounterExecution), MinBlockCounterExecution);