[compiler-rt] 2f4043e - [compiler-rt][pgo] Add profile instrumentation test for coroutines (#213801)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 6 00:33:44 PDT 2026
Author: Jin Huang
Date: 2026-08-06T00:33:40-07:00
New Revision: 2f4043eb92f789541b483dec8c794ecd67d167c1
URL: https://github.com/llvm/llvm-project/commit/2f4043eb92f789541b483dec8c794ecd67d167c1
DIFF: https://github.com/llvm/llvm-project/commit/2f4043eb92f789541b483dec8c794ecd67d167c1.diff
LOG: [compiler-rt][pgo] Add profile instrumentation test for coroutines (#213801)
This PR adds a compiler-rt test (`instrprof-coroutine-profile.cpp`) to
verify PGO profile counter generation and ingestion for C++20
coroutines.
During investigating the iFDO profile ingested for coroutine pass, we
found that the profile data contains entry counts for the original
coroutine function (`foo`), but lacks the entry counters for the split
`foo.resume` function.
After inspecting
[PassBuilderPipelines.cpp](https://github.com/llvm/llvm-project/blob/f7b7ec8d5542dcede1ae607aa74dfe36d7a3c530/llvm/lib/Passes/PassBuilderPipelines.cpp#L1273)
confirms that `PGOInstrumentationGen` runs before `CoroSplitPass`.
Therefore,
- 1) the iFDO profile correctly ingests and associates profile counters
with coroutine function `foo`.
- 2) Separate function entry counters for `foo.resume` are not expected
in the iFDO profile.
Added `compiler-rt/test/profile/instrprof-coroutine-profile.cpp` and use
`llvm-profdata show` verify coroutine profile data. The IR dump after
`PGOInstrumentationGen` confirms that the function entry count is
tracking by counter[6] in the 8-element counter for `foo`.
```llvm
coro.alloc: ; preds = %entry
call void @llvm.instrprof.increment(ptr @__profn__Z3fooi, i64 650973721613012168, i32 8, i32 6)
%2 = call i64 @llvm.coro.size.i64()
%call = call noalias noundef nonnull ptr @_Znwm(i64 noundef %2) #14
br label %coro.init
coro.init: ; preds = %coro.alloc, %entry
```
Co-authored-by: Jin Huang <jingold at google.com>
Added:
compiler-rt/test/profile/instrprof-coroutine-profile.cpp
Modified:
Removed:
################################################################################
diff --git a/compiler-rt/test/profile/instrprof-coroutine-profile.cpp b/compiler-rt/test/profile/instrprof-coroutine-profile.cpp
new file mode 100644
index 0000000000000..e4c8bd47ceca5
--- /dev/null
+++ b/compiler-rt/test/profile/instrprof-coroutine-profile.cpp
@@ -0,0 +1,46 @@
+// RUN: %clangxx_pgogen -std=c++20 -O2 -o %t %s
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata show -function=foo -counts %t.profraw | FileCheck %s
+
+#include <coroutine>
+
+struct State {
+ struct promise_type {
+ std::suspend_never initial_suspend() noexcept { return {}; }
+ std::suspend_never final_suspend() noexcept { return {}; }
+ State get_return_object() noexcept {
+ return State{std::coroutine_handle<promise_type>::from_promise(*this)};
+ }
+ void return_void() noexcept {}
+ void unhandled_exception() noexcept {}
+ };
+ std::coroutine_handle<promise_type> handle;
+};
+
+struct Awaitable {
+ bool await_ready() noexcept { return false; }
+ void await_suspend(std::coroutine_handle<> h) noexcept { h.resume(); }
+ void await_resume() noexcept {}
+};
+
+__attribute__((noinline)) State foo(int x) {
+ for (int i = 0; i < x; ++i) {
+ co_await Awaitable{};
+ }
+ co_return;
+}
+
+int main() {
+ foo(5);
+ return 0;
+}
+
+// Note: Index 6 in Block counts (the 7th value '1') represents the function entry count of foo(5).
+// CHECK: Counters:
+// CHECK-NEXT: {{.*foo.*}}:
+// CHECK-NEXT: Hash: {{.*}}
+// CHECK-NEXT: Counters: 8
+// CHECK-NEXT: Block counts: [0, 5, 5, 5, 1, 1, 1, 1]
+// CHECK-NOT: .resume
+// CHECK-NOT: .destroy
+// CHECK-NOT: .cleanup
More information about the llvm-commits
mailing list