llvm / llvm/llvm-project

[AMDGPU] SILoadStoreOptimizer misses adjacent raw buffer stores with masked-select offsets

Open
#218,200 5 comments 0 reactions 0 assignees View on GitHub
backend:AMDGPU missed-optimization
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.