[llvm] [AMDGPU] Fix dropped Asyncmarks when new AsyncScore is empty (PR #191894)
Frederick Vu via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 13 14:51:36 PDT 2026
https://github.com/FrederickVu created https://github.com/llvm/llvm-project/pull/191894
If we have, say, two consecutive async marks with no intermediate async operations, then waiting on the second async mark would produce no s_waitcnts, potentially leaving async operations before the first async mark outstanding.
>From 646ee87213b35dfdd7c0322035e49e5c9083bc88 Mon Sep 17 00:00:00 2001
From: Frederick Vu <100011202+FrederickVu at users.noreply.github.com>
Date: Mon, 13 Apr 2026 21:38:41 +0000
Subject: [PATCH] Merge current AsyncScore with previous score
---
llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp | 8 ++-
.../test/CodeGen/AMDGPU/asyncmark-pregfx12.ll | 51 +++++++++++++++++--
2 files changed, 54 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
index 7eb97ca4bf885..0b57f17dfe1a1 100644
--- a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
+++ b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
@@ -1301,7 +1301,13 @@ void WaitcntBrackets::recordAsyncMark(MachineInstr &Inst) {
// limit every time we push a new mark, but that seems like unnecessary work
// in practical cases. We do separately truncate the array when processing a
// loop, which should be sufficient.
- AsyncMarks.push_back(AsyncScore);
+ CounterValueArray MergedScore = AsyncScore;
+ if (!AsyncMarks.empty()) {
+ const auto &PrevMark = AsyncMarks.back();
+ for (auto T : inst_counter_types(Context->MaxCounter))
+ MergedScore[T] = std::max(AsyncScore[T], PrevMark[T]);
+ }
+ AsyncMarks.push_back(MergedScore);
AsyncScore = {};
LLVM_DEBUG({
dbgs() << "recordAsyncMark:\n" << Inst;
diff --git a/llvm/test/CodeGen/AMDGPU/asyncmark-pregfx12.ll b/llvm/test/CodeGen/AMDGPU/asyncmark-pregfx12.ll
index b32e883b2b535..24d2344552557 100644
--- a/llvm/test/CodeGen/AMDGPU/asyncmark-pregfx12.ll
+++ b/llvm/test/CodeGen/AMDGPU/asyncmark-pregfx12.ll
@@ -486,6 +486,49 @@ epilog:
ret void
}
+define void @double_asyncmark(ptr addrspace(1) %src, ptr addrspace(3) %lds, ptr addrspace(1) %out) {
+; SDAG-LABEL: double_asyncmark:
+; SDAG: ; %bb.0:
+; SDAG-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SDAG-NEXT: v_readfirstlane_b32 s4, v2
+; SDAG-NEXT: s_mov_b32 m0, s4
+; SDAG-NEXT: s_nop 0
+; SDAG-NEXT: global_load_dword v[0:1], off lds
+; SDAG-NEXT: ; asyncmark
+; SDAG-NEXT: ; asyncmark
+; SDAG-NEXT: ; wait_asyncmark(0)
+; SDAG-NEXT: s_waitcnt vmcnt(0)
+; SDAG-NEXT: ds_read_b32 v0, v2
+; SDAG-NEXT: s_waitcnt lgkmcnt(0)
+; SDAG-NEXT: global_store_dword v[3:4], v0, off
+; SDAG-NEXT: s_waitcnt vmcnt(0)
+; SDAG-NEXT: s_setpc_b64 s[30:31]
+;
+; GISEL-LABEL: double_asyncmark:
+; GISEL: ; %bb.0:
+; GISEL-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GISEL-NEXT: v_readfirstlane_b32 s4, v2
+; GISEL-NEXT: s_mov_b32 m0, s4
+; GISEL-NEXT: s_nop 0
+; GISEL-NEXT: global_load_dword v[0:1], off lds
+; GISEL-NEXT: ; asyncmark
+; GISEL-NEXT: ; asyncmark
+; GISEL-NEXT: ; wait_asyncmark(0)
+; GISEL-NEXT: s_waitcnt vmcnt(0)
+; GISEL-NEXT: ds_read_b32 v0, v2
+; GISEL-NEXT: s_waitcnt lgkmcnt(0)
+; GISEL-NEXT: global_store_dword v[3:4], v0, off
+; GISEL-NEXT: s_waitcnt vmcnt(0)
+; GISEL-NEXT: s_setpc_b64 s[30:31]
+ call void @llvm.amdgcn.global.load.async.lds(ptr addrspace(1) %src, ptr addrspace(3) %lds, i32 4, i32 0, i32 0)
+ call void @llvm.amdgcn.asyncmark()
+ call void @llvm.amdgcn.asyncmark()
+ call void @llvm.amdgcn.wait.asyncmark(i16 0)
+ %val = load i32, ptr addrspace(3) %lds
+ store i32 %val, ptr addrspace(1) %out
+ ret void
+}
+
; Software pipelined loop with async global-to-LDS and global loads
define void @test_pipelined_loop_with_global(ptr addrspace(1) %foo, ptr addrspace(3) %lds, ptr addrspace(1) %bar, ptr addrspace(1) %out, i32 %n) {
@@ -509,7 +552,7 @@ define void @test_pipelined_loop_with_global(ptr addrspace(1) %foo, ptr addrspac
; SDAG-NEXT: v_mov_b32_e32 v13, v8
; SDAG-NEXT: s_waitcnt vmcnt(1)
; SDAG-NEXT: v_mov_b32_e32 v15, v9
-; SDAG-NEXT: .LBB5_1: ; %loop_body
+; SDAG-NEXT: .LBB6_1: ; %loop_body
; SDAG-NEXT: ; =>This Inner Loop Header: Depth=1
; SDAG-NEXT: v_readfirstlane_b32 s7, v2
; SDAG-NEXT: s_waitcnt vmcnt(1)
@@ -529,7 +572,7 @@ define void @test_pipelined_loop_with_global(ptr addrspace(1) %foo, ptr addrspac
; SDAG-NEXT: ; asyncmark
; SDAG-NEXT: ; wait_asyncmark(2)
; SDAG-NEXT: s_andn2_b64 exec, exec, s[4:5]
-; SDAG-NEXT: s_cbranch_execnz .LBB5_1
+; SDAG-NEXT: s_cbranch_execnz .LBB6_1
; SDAG-NEXT: ; %bb.2: ; %epilog
; SDAG-NEXT: s_or_b64 exec, exec, s[4:5]
; SDAG-NEXT: ds_read_b32 v0, v2
@@ -571,7 +614,7 @@ define void @test_pipelined_loop_with_global(ptr addrspace(1) %foo, ptr addrspac
; GISEL-NEXT: v_mov_b32_e32 v13, v8
; GISEL-NEXT: s_waitcnt vmcnt(1)
; GISEL-NEXT: v_mov_b32_e32 v15, v9
-; GISEL-NEXT: .LBB5_1: ; %loop_body
+; GISEL-NEXT: .LBB6_1: ; %loop_body
; GISEL-NEXT: ; =>This Inner Loop Header: Depth=1
; GISEL-NEXT: v_readfirstlane_b32 s6, v2
; GISEL-NEXT: s_waitcnt vmcnt(1)
@@ -591,7 +634,7 @@ define void @test_pipelined_loop_with_global(ptr addrspace(1) %foo, ptr addrspac
; GISEL-NEXT: ; asyncmark
; GISEL-NEXT: ; wait_asyncmark(2)
; GISEL-NEXT: s_andn2_b64 exec, exec, s[4:5]
-; GISEL-NEXT: s_cbranch_execnz .LBB5_1
+; GISEL-NEXT: s_cbranch_execnz .LBB6_1
; GISEL-NEXT: ; %bb.2: ; %epilog
; GISEL-NEXT: s_or_b64 exec, exec, s[4:5]
; GISEL-NEXT: ds_read_b32 v0, v2
More information about the llvm-commits
mailing list