[llvm] [AMDGPU] Fix XNACK alignment check in SILoadStoreOptimizer merges (PR #219886)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 30 22:55:06 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-amdgpu
Author: Arseniy Obolenskiy (aobolensk)
<details>
<summary>Changes</summary>
Alignment of a merged scalar load depends on the lower offset load, not whichever load comes first in program order, so checking the first load could miss cases needing the constrained opcode
---
Full diff: https://github.com/llvm/llvm-project/pull/219886.diff
2 Files Affected:
- (modified) llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp (+5-12)
- (modified) llvm/test/CodeGen/AMDGPU/merge-s-load.mir (+44)
``````````diff
diff --git a/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp b/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp
index d86a3c62f63c3..a730e9cd44b32 100644
--- a/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp
+++ b/llvm/lib/Target/AMDGPU/SILoadStoreOptimizer.cpp
@@ -1877,6 +1877,11 @@ static bool needsConstrainedOpcode(const GCNSubtarget &STM,
unsigned SILoadStoreOptimizer::getNewOpcode(const CombineInfo &CI,
const CombineInfo &Paired) {
const unsigned Width = CI.Width + Paired.Width;
+ const CombineInfo &Leading = Paired < CI ? Paired : CI;
+ // If XNACK is enabled, use the constrained opcodes when the first load is
+ // under-aligned.
+ const bool NeedsConstrainedOpc =
+ needsConstrainedOpcode(*STM, Leading.I->memoperands(), Width);
switch (getCommonInstClass(CI, Paired)) {
default:
@@ -1892,10 +1897,6 @@ unsigned SILoadStoreOptimizer::getNewOpcode(const CombineInfo &CI,
case UNKNOWN:
llvm_unreachable("Unknown instruction class");
case S_BUFFER_LOAD_IMM: {
- // If XNACK is enabled, use the constrained opcodes when the first load is
- // under-aligned.
- bool NeedsConstrainedOpc =
- needsConstrainedOpcode(*STM, CI.I->memoperands(), Width);
switch (Width) {
default:
return 0;
@@ -1914,10 +1915,6 @@ unsigned SILoadStoreOptimizer::getNewOpcode(const CombineInfo &CI,
}
}
case S_BUFFER_LOAD_SGPR_IMM: {
- // If XNACK is enabled, use the constrained opcodes when the first load is
- // under-aligned.
- bool NeedsConstrainedOpc =
- needsConstrainedOpcode(*STM, CI.I->memoperands(), Width);
switch (Width) {
default:
return 0;
@@ -1936,10 +1933,6 @@ unsigned SILoadStoreOptimizer::getNewOpcode(const CombineInfo &CI,
}
}
case S_LOAD_IMM: {
- // If XNACK is enabled, use the constrained opcodes when the first load is
- // under-aligned.
- bool NeedsConstrainedOpc =
- needsConstrainedOpcode(*STM, CI.I->memoperands(), Width);
switch (Width) {
default:
return 0;
diff --git a/llvm/test/CodeGen/AMDGPU/merge-s-load.mir b/llvm/test/CodeGen/AMDGPU/merge-s-load.mir
index bc47cf53c0f47..d26337d8d74ce 100644
--- a/llvm/test/CodeGen/AMDGPU/merge-s-load.mir
+++ b/llvm/test/CodeGen/AMDGPU/merge-s-load.mir
@@ -480,3 +480,47 @@ body: |
early-clobber %1:sgpr_128 = S_LOAD_DWORDX4_IMM_ec %0:sgpr_64, 0, 0 :: (dereferenceable invariant load (s128))
early-clobber %2:sgpr_128 = S_LOAD_DWORDX4_IMM_ec %0:sgpr_64, 16, 0 :: (dereferenceable invariant load (s128))
...
+
+---
+# Merged offset 4/align 4 needs the constrained opcode, though the higher-offset
+# (more aligned) load comes first in program order.
+name: merge_s_load_x1_x1_high_offset_first_underaligned
+body: |
+ bb.0:
+ ; GFX10-LABEL: name: merge_s_load_x1_x1_high_offset_first_underaligned
+ ; GFX10: [[DEF:%[0-9]+]]:sgpr_64 = IMPLICIT_DEF
+ ; GFX10-NEXT: early-clobber %3:sreg_64_xexec = S_LOAD_DWORDX2_IMM_ec [[DEF]], 4, 0 :: (dereferenceable invariant load (s64), align 4)
+ ; GFX10-NEXT: [[COPY:%[0-9]+]]:sreg_32_xm0_xexec = COPY %3.sub1
+ ; GFX10-NEXT: [[COPY1:%[0-9]+]]:sreg_32_xm0_xexec = COPY killed %3.sub0
+ ;
+ ; GFX11-LABEL: name: merge_s_load_x1_x1_high_offset_first_underaligned
+ ; GFX11: [[DEF:%[0-9]+]]:sgpr_64 = IMPLICIT_DEF
+ ; GFX11-NEXT: [[S_LOAD_DWORDX2_IMM:%[0-9]+]]:sreg_64_xexec = S_LOAD_DWORDX2_IMM [[DEF]], 4, 0 :: (dereferenceable invariant load (s64), align 4)
+ ; GFX11-NEXT: [[COPY:%[0-9]+]]:sreg_32_xm0_xexec = COPY [[S_LOAD_DWORDX2_IMM]].sub1
+ ; GFX11-NEXT: [[COPY1:%[0-9]+]]:sreg_32_xm0_xexec = COPY killed [[S_LOAD_DWORDX2_IMM]].sub0
+ ;
+ ; GFX12-LABEL: name: merge_s_load_x1_x1_high_offset_first_underaligned
+ ; GFX12: [[DEF:%[0-9]+]]:sgpr_64 = IMPLICIT_DEF
+ ; GFX12-NEXT: [[S_LOAD_DWORDX2_IMM:%[0-9]+]]:sreg_64_xexec = S_LOAD_DWORDX2_IMM [[DEF]], 4, 0 :: (dereferenceable invariant load (s64), align 4)
+ ; GFX12-NEXT: [[COPY:%[0-9]+]]:sreg_32_xm0_xexec = COPY [[S_LOAD_DWORDX2_IMM]].sub1
+ ; GFX12-NEXT: [[COPY1:%[0-9]+]]:sreg_32_xm0_xexec = COPY killed [[S_LOAD_DWORDX2_IMM]].sub0
+ %0:sgpr_64 = IMPLICIT_DEF
+ %1:sreg_32_xm0_xexec = S_LOAD_DWORD_IMM %0:sgpr_64, 8, 0 :: (dereferenceable invariant load (s32), align 8)
+ %2:sreg_32_xm0_xexec = S_LOAD_DWORD_IMM %0:sgpr_64, 4, 0 :: (dereferenceable invariant load (s32), align 4)
+...
+
+---
+# Merged offset 8/align 8 is naturally aligned, though the first load in
+# program order is under-aligned.
+name: merge_s_load_x1_x1_high_offset_first_aligned
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: merge_s_load_x1_x1_high_offset_first_aligned
+ ; CHECK: [[DEF:%[0-9]+]]:sgpr_64 = IMPLICIT_DEF
+ ; CHECK-NEXT: [[S_LOAD_DWORDX2_IMM:%[0-9]+]]:sreg_64_xexec = S_LOAD_DWORDX2_IMM [[DEF]], 8, 0 :: (dereferenceable invariant load (s64))
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:sreg_32_xm0_xexec = COPY [[S_LOAD_DWORDX2_IMM]].sub1
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:sreg_32_xm0_xexec = COPY killed [[S_LOAD_DWORDX2_IMM]].sub0
+ %0:sgpr_64 = IMPLICIT_DEF
+ %1:sreg_32_xm0_xexec = S_LOAD_DWORD_IMM %0:sgpr_64, 12, 0 :: (dereferenceable invariant load (s32), align 4)
+ %2:sreg_32_xm0_xexec = S_LOAD_DWORD_IMM %0:sgpr_64, 8, 0 :: (dereferenceable invariant load (s32), align 8)
+...
``````````
</details>
https://github.com/llvm/llvm-project/pull/219886
More information about the llvm-commits
mailing list