[llvm] [AMDGPU] Reject image load merges with mismatched dim (PR #219923)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 31 02:31:44 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-amdgpu
Author: Arseniy Obolenskiy (aobolensk)
<details>
<summary>Changes</summary>
dim was missing from the operand equality check, so loads with different dim could wrongly get merged into one
---
Full diff: https://github.com/llvm/llvm-project/pull/219923.diff
5 Files Affected:
- (modified) llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp (+2-1)
- (added) llvm/test/CodeGen/AMDGPU/merge-image-load-dim.ll (+90)
- (modified) llvm/test/CodeGen/AMDGPU/merge-image-load-gfx10.mir (+18)
- (modified) llvm/test/CodeGen/AMDGPU/merge-image-load-gfx11.mir (+18)
- (modified) llvm/test/CodeGen/AMDGPU/merge-image-load-gfx12.mir (+20)
``````````diff
diff --git a/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp b/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp
index d86a3c62f63c3..e8fd711505af5 100644
--- a/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp
+++ b/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp
@@ -1022,7 +1022,8 @@ bool SILoadStoreOptimizer::dmasksCanBeCombined(const CombineInfo &CI,
// Check other optional immediate operands for equality.
AMDGPU::OpName OperandsToMatch[] = {
AMDGPU::OpName::cpol, AMDGPU::OpName::d16, AMDGPU::OpName::unorm,
- AMDGPU::OpName::da, AMDGPU::OpName::r128, AMDGPU::OpName::a16};
+ AMDGPU::OpName::da, AMDGPU::OpName::r128, AMDGPU::OpName::a16,
+ AMDGPU::OpName::dim};
for (AMDGPU::OpName op : OperandsToMatch) {
int Idx = AMDGPU::getNamedOperandIdx(CI.I->getOpcode(), op);
diff --git a/llvm/test/CodeGen/AMDGPU/merge-image-load-dim.ll b/llvm/test/CodeGen/AMDGPU/merge-image-load-dim.ll
new file mode 100644
index 0000000000000..223c702402f39
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/merge-image-load-dim.ll
@@ -0,0 +1,90 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=amdgpu10.10 < %s | FileCheck -check-prefix=GFX10 %s
+; RUN: llc -mtriple=amdgpu11.00 -amdgpu-enable-delay-alu=0 < %s | FileCheck -check-prefix=GFX11 %s
+; RUN: llc -mtriple=amdgpu12.00 -amdgpu-enable-delay-alu=0 < %s | FileCheck -check-prefix=GFX12 %s
+
+; Mismatched dim must block merging: would reinterpret the array slice as y.
+
+define amdgpu_ps <4 x float> @load_2d_1darray_dim_mismatch(<8 x i32> inreg %rsrc, i32 %s, i32 %t) {
+; GFX10-LABEL: load_2d_1darray_dim_mismatch:
+; GFX10: ; %bb.0: ; %main_body
+; GFX10-NEXT: v_mov_b32_e32 v4, v1
+; GFX10-NEXT: s_clause 0x1
+; GFX10-NEXT: image_load v5, v[0:1], s[0:7] dmask:0x1 dim:SQ_RSRC_IMG_2D unorm
+; GFX10-NEXT: image_load v[1:3], v[0:1], s[0:7] dmask:0xe dim:SQ_RSRC_IMG_1D_ARRAY unorm
+; GFX10-NEXT: ; kill: killed $vgpr4
+; GFX10-NEXT: s_waitcnt vmcnt(1)
+; GFX10-NEXT: v_mov_b32_e32 v0, v5
+; GFX10-NEXT: s_waitcnt vmcnt(0)
+; GFX10-NEXT: ; return to shader part epilog
+;
+; GFX11-LABEL: load_2d_1darray_dim_mismatch:
+; GFX11: ; %bb.0: ; %main_body
+; GFX11-NEXT: s_clause 0x1
+; GFX11-NEXT: image_load v4, v[0:1], s[0:7] dmask:0x1 dim:SQ_RSRC_IMG_2D unorm
+; GFX11-NEXT: image_load v[1:3], v[0:1], s[0:7] dmask:0xe dim:SQ_RSRC_IMG_1D_ARRAY unorm
+; GFX11-NEXT: s_waitcnt vmcnt(1)
+; GFX11-NEXT: v_mov_b32_e32 v0, v4
+; GFX11-NEXT: s_waitcnt vmcnt(0)
+; GFX11-NEXT: ; return to shader part epilog
+;
+; GFX12-LABEL: load_2d_1darray_dim_mismatch:
+; GFX12: ; %bb.0: ; %main_body
+; GFX12-NEXT: s_clause 0x1
+; GFX12-NEXT: image_load v4, [v0, v1], s[0:7] dmask:0x1 dim:SQ_RSRC_IMG_2D
+; GFX12-NEXT: image_load v[1:3], [v0, v1], s[0:7] dmask:0xe dim:SQ_RSRC_IMG_1D_ARRAY
+; GFX12-NEXT: s_wait_loadcnt 0x1
+; GFX12-NEXT: v_mov_b32_e32 v0, v4
+; GFX12-NEXT: s_wait_loadcnt 0x0
+; GFX12-NEXT: ; return to shader part epilog
+main_body:
+ %v1 = call float @llvm.amdgcn.image.load.2d.f32.i32(i32 1, i32 %s, i32 %t, <8 x i32> %rsrc, i32 0, i32 0)
+ %v2 = call <3 x float> @llvm.amdgcn.image.load.1darray.v3f32.i32(i32 14, i32 %s, i32 %t, <8 x i32> %rsrc, i32 0, i32 0)
+ %e0 = extractelement <3 x float> %v2, i32 0
+ %e1 = extractelement <3 x float> %v2, i32 1
+ %e2 = extractelement <3 x float> %v2, i32 2
+ %r0 = insertelement <4 x float> poison, float %v1, i32 0
+ %r1 = insertelement <4 x float> %r0, float %e0, i32 1
+ %r2 = insertelement <4 x float> %r1, float %e1, i32 2
+ %r3 = insertelement <4 x float> %r2, float %e2, i32 3
+ ret <4 x float> %r3
+}
+
+; Matching dim: merging still expected.
+
+define amdgpu_ps <4 x float> @load_2d_2d_merged(<8 x i32> inreg %rsrc, i32 %s, i32 %t) {
+; GFX10-LABEL: load_2d_2d_merged:
+; GFX10: ; %bb.0: ; %main_body
+; GFX10-NEXT: image_load v[0:3], v[0:1], s[0:7] dmask:0xf dim:SQ_RSRC_IMG_2D unorm
+; GFX10-NEXT: s_waitcnt vmcnt(0)
+; GFX10-NEXT: ; return to shader part epilog
+;
+; GFX11-LABEL: load_2d_2d_merged:
+; GFX11: ; %bb.0: ; %main_body
+; GFX11-NEXT: image_load v[0:3], v[0:1], s[0:7] dmask:0xf dim:SQ_RSRC_IMG_2D unorm
+; GFX11-NEXT: s_waitcnt vmcnt(0)
+; GFX11-NEXT: ; return to shader part epilog
+;
+; GFX12-LABEL: load_2d_2d_merged:
+; GFX12: ; %bb.0: ; %main_body
+; GFX12-NEXT: image_load v[0:3], [v0, v1], s[0:7] dmask:0xf dim:SQ_RSRC_IMG_2D
+; GFX12-NEXT: s_wait_loadcnt 0x0
+; GFX12-NEXT: ; return to shader part epilog
+main_body:
+ %v1 = call float @llvm.amdgcn.image.load.2d.f32.i32(i32 1, i32 %s, i32 %t, <8 x i32> %rsrc, i32 0, i32 0)
+ %v2 = call <3 x float> @llvm.amdgcn.image.load.2d.v3f32.i32(i32 14, i32 %s, i32 %t, <8 x i32> %rsrc, i32 0, i32 0)
+ %e0 = extractelement <3 x float> %v2, i32 0
+ %e1 = extractelement <3 x float> %v2, i32 1
+ %e2 = extractelement <3 x float> %v2, i32 2
+ %r0 = insertelement <4 x float> poison, float %v1, i32 0
+ %r1 = insertelement <4 x float> %r0, float %e0, i32 1
+ %r2 = insertelement <4 x float> %r1, float %e1, i32 2
+ %r3 = insertelement <4 x float> %r2, float %e2, i32 3
+ ret <4 x float> %r3
+}
+
+declare float @llvm.amdgcn.image.load.2d.f32.i32(i32, i32, i32, <8 x i32>, i32, i32) #0
+declare <3 x float> @llvm.amdgcn.image.load.2d.v3f32.i32(i32, i32, i32, <8 x i32>, i32, i32) #0
+declare <3 x float> @llvm.amdgcn.image.load.1darray.v3f32.i32(i32, i32, i32, <8 x i32>, i32, i32) #0
+
+attributes #0 = { nounwind readonly }
diff --git a/llvm/test/CodeGen/AMDGPU/merge-image-load-gfx10.mir b/llvm/test/CodeGen/AMDGPU/merge-image-load-gfx10.mir
index 687c27d16ed3a..1d57e36c7046a 100644
--- a/llvm/test/CodeGen/AMDGPU/merge-image-load-gfx10.mir
+++ b/llvm/test/CodeGen/AMDGPU/merge-image-load-gfx10.mir
@@ -189,6 +189,24 @@ body: |
...
---
+# GFX10-LABEL: name: image_load_dim_mismatch_not_merged
+# GFX10: %{{[0-9]+}}:vgpr_32 = IMAGE_LOAD_V1_V2_gfx10 %5, %3, 1, 1, -1, 0, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s32), addrspace 4)
+# GFX10: %{{[0-9]+}}:vreg_96 = IMAGE_LOAD_V3_V2_gfx10 %5, %3, 14, 4, -1, 0, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s96), align 16, addrspace 4)
+
+name: image_load_dim_mismatch_not_merged
+body: |
+ bb.0.entry:
+ %0:sgpr_64 = COPY $sgpr0_sgpr1
+ %1:sreg_64_xexec = S_LOAD_DWORDX2_IMM %0, 36, 0
+ %2:sgpr_128 = COPY $sgpr96_sgpr97_sgpr98_sgpr99
+ %3:sgpr_256 = S_LOAD_DWORDX8_IMM %1, 208, 0
+ %4:vgpr_32 = COPY %2.sub3
+ %5:vreg_64 = BUFFER_LOAD_DWORDX2_OFFSET %2:sgpr_128, 0, 0, 0, 0, implicit $exec :: (dereferenceable invariant load (s128))
+ %6:vgpr_32 = IMAGE_LOAD_V1_V2_gfx10 %5:vreg_64, %3:sgpr_256, 1, 1, -1, 0, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s32), addrspace 4)
+ %7:vreg_96 = IMAGE_LOAD_V3_V2_gfx10 %5:vreg_64, %3:sgpr_256, 14, 4, -1, 0, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s96), align 16, addrspace 4)
+...
+---
+
# GFX10-LABEL: name: image_load_not_merged_0
# GFX10: %{{[0-9]+}}:vgpr_32 = IMAGE_LOAD_V1_V2_gfx10 %5, %3, 8, 1, -1, 0, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s32), addrspace 4)
# GFX10: %{{[0-9]+}}:vreg_96 = IMAGE_LOAD_V3_V2_gfx10 %6, %3, 7, 1, -1, 0, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s96), align 16, addrspace 4)
diff --git a/llvm/test/CodeGen/AMDGPU/merge-image-load-gfx11.mir b/llvm/test/CodeGen/AMDGPU/merge-image-load-gfx11.mir
index 2edfdbef9974d..7343ab22bc0a6 100644
--- a/llvm/test/CodeGen/AMDGPU/merge-image-load-gfx11.mir
+++ b/llvm/test/CodeGen/AMDGPU/merge-image-load-gfx11.mir
@@ -189,6 +189,24 @@ body: |
...
---
+# GFX11-LABEL: name: image_load_dim_mismatch_not_merged
+# GFX11: %{{[0-9]+}}:vgpr_32 = IMAGE_LOAD_V1_V2_gfx11 %5, %3, 1, 1, -1, 0, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s32), addrspace 4)
+# GFX11: %{{[0-9]+}}:vreg_96 = IMAGE_LOAD_V3_V2_gfx11 %5, %3, 14, 4, -1, 0, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s96), align 16, addrspace 4)
+
+name: image_load_dim_mismatch_not_merged
+body: |
+ bb.0.entry:
+ %0:sgpr_64 = COPY $sgpr0_sgpr1
+ %1:sreg_64_xexec = S_LOAD_DWORDX2_IMM %0, 36, 0
+ %2:sgpr_128 = COPY $sgpr96_sgpr97_sgpr98_sgpr99
+ %3:sgpr_256 = S_LOAD_DWORDX8_IMM %1, 208, 0
+ %4:vgpr_32 = COPY %2.sub3
+ %5:vreg_64 = BUFFER_LOAD_DWORDX2_OFFSET %2:sgpr_128, 0, 0, 0, 0, implicit $exec :: (dereferenceable invariant load 16)
+ %6:vgpr_32 = IMAGE_LOAD_V1_V2_gfx11 %5:vreg_64, %3:sgpr_256, 1, 1, -1, 0, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load 4, addrspace 4)
+ %7:vreg_96 = IMAGE_LOAD_V3_V2_gfx11 %5:vreg_64, %3:sgpr_256, 14, 4, -1, 0, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load 12, align 16, addrspace 4)
+...
+---
+
# GFX11-LABEL: name: image_load_not_merged_0
# GFX11: %{{[0-9]+}}:vgpr_32 = IMAGE_LOAD_V1_V2_gfx11 %5, %3, 8, 1, -1, 0, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s32), addrspace 4)
# GFX11: %{{[0-9]+}}:vreg_96 = IMAGE_LOAD_V3_V2_gfx11 %6, %3, 7, 1, -1, 0, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s96), align 16, addrspace 4)
diff --git a/llvm/test/CodeGen/AMDGPU/merge-image-load-gfx12.mir b/llvm/test/CodeGen/AMDGPU/merge-image-load-gfx12.mir
index a9d4033e72527..a5172e4f446de 100644
--- a/llvm/test/CodeGen/AMDGPU/merge-image-load-gfx12.mir
+++ b/llvm/test/CodeGen/AMDGPU/merge-image-load-gfx12.mir
@@ -212,6 +212,26 @@ body: |
...
---
+# GFX12-LABEL: name: image_load_dim_mismatch_not_merged
+# GFX12: %{{[0-9]+}}:vgpr_32 = IMAGE_LOAD_V1_V2_gfx12 %6, %7, %3, 1, 1, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s32), addrspace 4)
+# GFX12: %{{[0-9]+}}:vreg_96 = IMAGE_LOAD_V3_V2_gfx12 %6, %7, %3, 14, 4, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s96), align 16, addrspace 4)
+
+name: image_load_dim_mismatch_not_merged
+body: |
+ bb.0.entry:
+ %0:sgpr_64 = COPY $sgpr0_sgpr1
+ %1:sreg_64_xexec = S_LOAD_DWORDX2_IMM %0, 36, 0
+ %2:sgpr_128 = COPY $sgpr96_sgpr97_sgpr98_sgpr99
+ %3:sgpr_256 = S_LOAD_DWORDX8_IMM %1, 208, 0
+ %4:vgpr_32 = COPY %2.sub3
+ %5:vreg_64 = BUFFER_LOAD_DWORDX2_OFFSET %2:sgpr_128, 0, 0, 0, 0, implicit $exec :: (dereferenceable invariant load 16)
+ %6:vgpr_32 = COPY %5.sub0
+ %7:vgpr_32 = COPY %5.sub1
+ %8:vgpr_32 = IMAGE_LOAD_V1_V2_gfx12 %6:vgpr_32, %7:vgpr_32, %3:sgpr_256, 1, 1, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load 4, addrspace 4)
+ %9:vreg_96 = IMAGE_LOAD_V3_V2_gfx12 %6:vgpr_32, %7:vgpr_32, %3:sgpr_256, 14, 4, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load 12, align 16, addrspace 4)
+...
+---
+
# GFX12-LABEL: name: image_load_not_merged_0
# GFX12: %{{[0-9]+}}:vgpr_32 = IMAGE_LOAD_V1_V2_gfx12 %6, %7, %3, 8, 1, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s32), addrspace 4)
# GFX12: %{{[0-9]+}}:vreg_96 = IMAGE_LOAD_V3_V2_gfx12 %9, %10, %3, 7, 1, 0, 0, 0, 0, 0, implicit $exec :: (dereferenceable load (s96), align 16, addrspace 4)
``````````
</details>
https://github.com/llvm/llvm-project/pull/219923
More information about the llvm-commits
mailing list