[amdgpu] SIInsertWaitcnts repeats vmcnt(0) for same VMEM loaded VGPR base
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
I came across the following in Triton (i can produce this if this is helpful), but please consider the following minimal repro:
```llvm
target triple = "amdgcn-amd-amdhsa"
define amdgpu_kernel void @waitcnt_pointer_table_loop_store_vgprbase_min(
ptr addrspace(1) %out,
ptr addrspace(1) %ptr_table,
i32 %n,
i32 %my_pe) #0 {
entry:
%tid = call i32 @llvm.amdgcn.workitem.id.x()
%lane = and i32 %tid, 127
%active = icmp ult i32 %lane, %n
%off0 = zext i32 %lane to i64
%lane_plus_1 = add nuw nsw i32 %lane, 1
%off1 = zext i32 %lane_plus_1 to i64
%peer_base = add i32 %my_pe, 1
br label %loop
loop:
%i = phi i32 [ 0, %entry ], [ %i.next, %join1 ]
%peer_raw = add i32 %peer_base, %i
%peer_lane = add i32 %peer_raw, %lane
%peer = and i32 %peer_lane, 7
%peer64 = zext i32 %peer to i64
%table_ptr = getelementptr i64, ptr addrspace(1) %ptr_table, i64 %peer64
%base_i64 = load i64, ptr addrspace(1) %table_ptr, align 8
%base = inttoptr i64 %base_i64 to ptr addrspace(1)
br i1 %active, label %then0, label %join0
then0:
%payload_ptr0 = getelementptr half, ptr addrspace(1) %base, i64 %off0
%payload0 = load half, ptr addrspace(1) %payload_ptr0, align 2
%out_ptr0 = getelementptr half, ptr addrspace(1) %out, i64 %off0
store half %payload0, ptr addrspace(1) %out_ptr0, align 2
br label %join0
join0:
br i1 %active, label %then1, label %join1
then1:
%payload_ptr1 = getelementptr half, ptr addrspace(1) %base, i64 %off1
%payload1 = load half, ptr addrspace(1) %payload_ptr1, align 2
%out_ptr1 = getelementptr half, ptr addrspace(1) %out, i64 %off1
store half %payload1, ptr addrspace(1) %out_ptr1, align 2
br label %join1
join1:
%i.next = add nuw nsw i32 %i, 1
%done = icmp eq i32 %i.next, 7
br i1 %done, label %exit, label %loop
exit:
ret void
}
declare i32 @llvm.amdgcn.workitem.id.x() #1
attributes #0 = { nounwind "amdgpu-flat-work-group-size"="1,256" }
attributes #1 = { nounwind readnone speculatable }
```
`%base` dominates both load address computations but when we insert `waitcnts`, the loads become serialized, roughly:
Before `SIInsertWaitcnts`:
```asm
vgpr4_vgpr5 = GLOBAL_LOAD_DWORDX2 ... ; lowered %base_i64 load
S_AND_SAVEEXEC_B64 ...
S_CBRANCH ...
vgpr8_vgpr9 = V_LSHL_ADD_U64 vgpr4_vgpr5, ...
vgpr7 = GLOBAL_LOAD_USHORT vgpr8_vgpr9
GLOBAL_STORE_SHORT ...
S_AND_SAVEEXEC_B64 ...
S_CBRANCH ...
vgpr4_vgpr5 = V_LSHL_ADD_U64 vgpr4_vgpr5, ...
vgpr4 = GLOBAL_LOAD_USHORT vgpr4_vgpr5
GLOBAL_STORE_SHORT ...
```
But after, we see the following:
```asm
vgpr4_vgpr5 = GLOBAL_LOAD_DWORDX2 ...
S_WAITCNT vmcnt(0)
V_LSHL_ADD_U64 ..., vgpr4_vgpr5
GLOBAL_LOAD_USHORT ...
S_WAITCNT vmcnt(0)
V_LSHL_ADD_U64 ..., vgpr4_vgpr5
GLOBAL_LOAD_USHORT ...
```
which kills performance. Can we instead place one dominating wait before the blocks, satisfying all dominated address calculation uses of the same base pointer?
Commands:
```
llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx942 -O3 repro.ll -o out.s
llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx942 -O3 -stop-before=si-insert-waitcnts repro.ll -o before.mir
llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx942 -O3 -stop-after=si-insert-waitcnts repro.ll -o after.mir
```
Contributor guide
Research direction
Start by reproducing the issue with the provided llc commands and compare before.mir with after.mir around SIInsertWaitcnts. Trace how the repeated vmcnt(0) waits are inserted for the shared %base address computation. Done means the generated wait placement avoids serializing the two loads while preserving correct waitcnt behavior.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100