[AMDGPU] SILoadStoreOptimizer misses adjacent raw buffer stores with masked-select offsets
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
### Summary
`SILoadStoreOptimizer` does not combine two adjacent raw buffer stores when
their `voffset`s are selected independently against the same OOB sentinel.
The canonical same-vaddr form already combines to `buffer_store_dwordx2`, but
the masked form remains two `buffer_store_dword` instructions because the two
selects become different vaddr registers.
### Reproducer
```llvm
; RUN: llc -O3 -global-isel=0 -mtriple=amdgcn-amd-amdhsa \
; RUN: -mcpu=gfx942 < %s | FileCheck %s
; RUN: llc -O3 -global-isel=1 -global-isel-abort=2 \
; RUN: -mtriple=amdgcn-amd-amdhsa -mcpu=gfx942 < %s | FileCheck %s
target triple = "amdgcn-amd-amdhsa"
; CHECK-LABEL: masked_adjacent_stores:
; CHECK-NOT: buffer_store_dword{{[ \t]}}
; CHECK: buffer_store_dwordx2
; CHECK-NOT: buffer_store_dword{{[ \t]}}
; CHECK: s_setpc_b64
define void @masked_adjacent_stores(
ptr addrspace(8) inreg %resource,
i32 %offset,
i1 %active,
i32 %first,
i32 %second) {
entry:
%offset0 = select i1 %active, i32 %offset, i32 -2147483648
call void @llvm.amdgcn.raw.ptr.buffer.store.i32(
i32 %first, ptr addrspace(8) %resource,
i32 %offset0, i32 0, i32 0)
%next = add i32 %offset, 4
%offset1 = select i1 %active, i32 %next, i32 -2147483648
call void @llvm.amdgcn.raw.ptr.buffer.store.i32(
i32 %second, ptr addrspace(8) %resource,
i32 %offset1, i32 0, i32 0)
ret void
}
declare void @llvm.amdgcn.raw.ptr.buffer.store.i32(
i32,
ptr addrspace(8) writeonly captures(none),
i32,
i32,
i32 immarg)
!llvm.module.flags = !{!0}
!0 = !{i32 7, !"amdgpu.buffer.oob.mode", i32 1}
```
### Actual result
Both SelectionDAG and GlobalISel emit two scalar stores:
```asm
buffer_store_dword v2, v1, s[0:3], 0 offen
buffer_store_dword v3, v0, s[0:3], 0 offen
```
The result reproduces on `gfx90a`, `gfx942`, and `gfx1200`.
### Expected result
```asm
buffer_store_dwordx2
```
The stores use the same resource, `soffset`, cache policy, predicate, and OOB
sentinel, and their active offsets are adjacent. The reproducer enables relaxed
buffer OOB mode.
### Likely cause
The two selects lower to distinct vaddr registers, so
`CombineInfo::hasSameBaseAddress` does not put the stores in the same merge
candidate list.
### Version
```text
LLVM version 24.0.0git
Git revision b010a18d2b648cab83c83967ff26b8fde11acdc6
Target: amdgcn-amd-amdhsa
CPU: gfx942
```
Contributor guide
Research direction
Start with SILoadStoreOptimizer and the CombineInfo::hasSameBaseAddress path described in the issue. Run the provided llc and FileCheck reproducer for SelectionDAG and GlobalISel on the listed AMDGPU targets. Done means the masked adjacent stores combine into buffer_store_dwordx2 without the separate scalar stores.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100