[llvm] [AMDGPU] Fix a wave.reduce crash on a move of a non-immediate (PR #228819)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Oct 3 21:15:55 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-amdgpu
Author: Mian Miftah (mmiftahx)
<details>
<summary>Changes</summary>
lowerWaveReduce checks whether a uniform source is the constant 1 by
looking at the move that defines it (#<!-- -->212755), and reads the move's
operand with getImm() without checking that it is an immediate. A source
defined by a move of a register, a frame index or a global address hits
the assertion in getImm(). An add reduction of a uniform umin's result
does this, since the umin is lowered to a move of its source.
Use getImmOrMaterializedImm, which returns nothing unless the operand is
an immediate.
---
Full diff: https://github.com/llvm/llvm-project/pull/228819.diff
2 Files Affected:
- (modified) llvm/lib/Target/AMDGPU/SIISelLowering.cpp (+24-34)
- (added) llvm/test/CodeGen/AMDGPU/wave-reduce-move-source.ll (+109)
``````````diff
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index 4012992d3f1d6a3..eefcaf9c5c9120c 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -6128,21 +6128,18 @@ static MachineBasicBlock *lowerWaveReduce(MachineInstr &MI,
.addImm(1)
.setOperandDead(3); // Dead scc
// Check if Src is a known identity constant.
- MachineInstr *SrcDef = MRI.getVRegDef(SrcReg);
- if (SrcDef && SrcDef->isMoveImmediate()) {
- int64_t Imm = SrcDef->getOperand(1).getImm();
- if (Imm == 1) { // 1 * parity(exec) = parity(exec)
- if (Opc == AMDGPU::S_XOR_B32) {
- BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MOV_B32), DstReg)
- .addReg(ParityRegister);
- } else {
- Register DstHi =
- MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);
- BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MOV_B32), DstHi).addImm(0);
- BuildRegSequence(BB, MI, DstReg, ParityRegister, DstHi);
- }
- break;
+ if (TII->getImmOrMaterializedImm(MRI, SrcReg) == 1) {
+ // 1 * parity(exec) = parity(exec)
+ if (Opc == AMDGPU::S_XOR_B32) {
+ BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MOV_B32), DstReg)
+ .addReg(ParityRegister);
+ } else {
+ Register DstHi =
+ MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);
+ BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MOV_B32), DstHi).addImm(0);
+ BuildRegSequence(BB, MI, DstReg, ParityRegister, DstHi);
}
+ break;
}
if (Opc == AMDGPU::S_XOR_B32) {
BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), DstReg)
@@ -6179,14 +6176,11 @@ static MachineBasicBlock *lowerWaveReduce(MachineInstr &MI,
}
case AMDGPU::S_ADD_I32: {
// Check if Src is a known identity constant.
- MachineInstr *SrcDef = MRI.getVRegDef(SrcReg);
- if (SrcDef && SrcDef->isMoveImmediate()) {
- int64_t Imm = SrcDef->getOperand(1).getImm();
- if (Imm == 1) { // 1 * bitcount(exec) = bitcount(exec)
- BuildMI(BB, MI, DL, TII->get(AMDGPU::COPY), DstReg)
- .addReg(NewAccumulator->getOperand(0).getReg());
- break;
- }
+ if (TII->getImmOrMaterializedImm(MRI, SrcReg) == 1) {
+ // 1 * bitcount(exec) = bitcount(exec)
+ BuildMI(BB, MI, DL, TII->get(AMDGPU::COPY), DstReg)
+ .addReg(NewAccumulator->getOperand(0).getReg());
+ break;
}
BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MUL_I32), DstReg)
.addReg(SrcReg)
@@ -6211,18 +6205,14 @@ static MachineBasicBlock *lowerWaveReduce(MachineInstr &MI,
auto [Op1L, Op1H] = ExtractSubRegs(MI, MI.getOperand(1),
MRI.getRegClass(SrcReg), ST, MRI);
// Check if Src is a known identity constant.
- MachineInstr *SrcDef = MRI.getVRegDef(SrcReg);
- if (SrcDef && SrcDef->isMoveImmediate()) {
- int64_t Imm = SrcDef->getOperand(1).getImm();
- if (Imm == 1 && Opc == AMDGPU::S_ADD_U64_PSEUDO) {
- // 1 * bitcount(exec) = bitcount(exec)
- Register DstHi =
- MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);
- BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MOV_B32), DstHi).addImm(0);
- BuildRegSequence(BB, MI, DstReg,
- NewAccumulator->getOperand(0).getReg(), DstHi);
- break;
- }
+ if (Opc == AMDGPU::S_ADD_U64_PSEUDO &&
+ TII->getImmOrMaterializedImm(MRI, SrcReg) == 1) {
+ // 1 * bitcount(exec) = bitcount(exec)
+ Register DstHi = MRI.createVirtualRegister(&AMDGPU::SReg_32RegClass);
+ BuildMI(BB, MI, DL, TII->get(AMDGPU::S_MOV_B32), DstHi).addImm(0);
+ BuildRegSequence(BB, MI, DstReg,
+ NewAccumulator->getOperand(0).getReg(), DstHi);
+ break;
}
if (Opc == AMDGPU::S_SUB_U64_PSEUDO) {
BuildMI(BB, MI, DL, TII->get(AMDGPU::S_SUB_I32), NegatedValLo)
diff --git a/llvm/test/CodeGen/AMDGPU/wave-reduce-move-source.ll b/llvm/test/CodeGen/AMDGPU/wave-reduce-move-source.ll
new file mode 100644
index 000000000000000..d68acc96c43f22e
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/wave-reduce-move-source.ll
@@ -0,0 +1,109 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=amdgpu12.50-amd-amdpal -global-isel=0 < %s | FileCheck %s
+; RUN: llc -mtriple=amdgpu12.50-amd-amdpal -global-isel=1 < %s | FileCheck %s
+
+; Uniform wave.reduce sources defined by a move of something other than an
+; immediate: a register (the uniform lowering of wave.reduce.umin and
+; wave.reduce.and), a frame index and a global address.
+; gfx1250 with PAL moves the 64-bit address of @gv with one s_mov_b64.
+
+ at gv = addrspace(4) global i32 0
+
+define i32 @add_of_umin(i32 inreg %x) {
+; CHECK-LABEL: add_of_umin:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_wait_loadcnt_dscnt 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_mov_b32 s1, exec_lo
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; CHECK-NEXT: s_bcnt1_i32_b32 s1, s1
+; CHECK-NEXT: s_mul_i32 s0, s0, s1
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_1)
+; CHECK-NEXT: v_mov_b32_e32 v0, s0
+; CHECK-NEXT: s_set_pc_i64 s[30:31]
+ %m = call i32 @llvm.amdgcn.wave.reduce.umin.i32(i32 %x, i32 1)
+ %r = call i32 @llvm.amdgcn.wave.reduce.add.i32(i32 %m, i32 1)
+ ret i32 %r
+}
+
+define i32 @add_frame_index() {
+; CHECK-LABEL: add_frame_index:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_wait_loadcnt_dscnt 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_mov_b32 s0, exec_lo
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; CHECK-NEXT: s_bcnt1_i32_b32 s0, s0
+; CHECK-NEXT: s_mul_i32 s0, s0, s32
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_1)
+; CHECK-NEXT: v_mov_b32_e32 v0, s0
+; CHECK-NEXT: s_set_pc_i64 s[30:31]
+ %a = alloca i32, align 4, addrspace(5)
+ %p = ptrtoint ptr addrspace(5) %a to i32
+ %r = call i32 @llvm.amdgcn.wave.reduce.add.i32(i32 %p, i32 1)
+ ret i32 %r
+}
+
+define i32 @xor_frame_index() {
+; CHECK-LABEL: xor_frame_index:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_wait_loadcnt_dscnt 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_mov_b32 s0, exec_lo
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; CHECK-NEXT: s_bcnt1_i32_b32 s0, s0
+; CHECK-NEXT: s_and_b32 s0, s0, 1
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; CHECK-NEXT: s_mul_i32 s0, s0, s32
+; CHECK-NEXT: v_mov_b32_e32 v0, s0
+; CHECK-NEXT: s_set_pc_i64 s[30:31]
+ %a = alloca i32, align 4, addrspace(5)
+ %p = ptrtoint ptr addrspace(5) %a to i32
+ %r = call i32 @llvm.amdgcn.wave.reduce.xor.i32(i32 %p, i32 1)
+ ret i32 %r
+}
+
+define i64 @add_global_address_i64() {
+; CHECK-LABEL: add_global_address_i64:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_wait_loadcnt_dscnt 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_mov_b32 s2, exec_lo
+; CHECK-NEXT: s_mov_b64 s[0:1], gv at abs64
+; CHECK-NEXT: s_bcnt1_i32_b32 s2, s2
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(SKIP_3) | instid1(SALU_CYCLE_1)
+; CHECK-NEXT: s_mul_hi_u32 s3, s0, s2
+; CHECK-NEXT: s_mul_i32 s1, s1, s2
+; CHECK-NEXT: s_mul_i32 s0, s0, s2
+; CHECK-NEXT: s_add_co_u32 s1, s3, s1
+; CHECK-NEXT: v_dual_mov_b32 v0, s0 :: v_dual_mov_b32 v1, s1
+; CHECK-NEXT: s_set_pc_i64 s[30:31]
+ %p = ptrtoint ptr addrspace(4) @gv to i64
+ %r = call i64 @llvm.amdgcn.wave.reduce.add.i64(i64 %p, i32 1)
+ ret i64 %r
+}
+
+define i64 @sub_of_and_i64(i64 inreg %x) {
+; CHECK-LABEL: sub_of_and_i64:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: s_wait_loadcnt_dscnt 0x0
+; CHECK-NEXT: s_wait_kmcnt 0x0
+; CHECK-NEXT: s_mov_b32 s2, exec_lo
+; CHECK-NEXT: s_mov_b64 s[0:1], s[0:1]
+; CHECK-NEXT: s_bcnt1_i32_b32 s2, s2
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; CHECK-NEXT: s_sub_co_i32 s2, 0, s2
+; CHECK-NEXT: s_ashr_i32 s3, s2, 31
+; CHECK-NEXT: s_mul_hi_u32 s4, s0, s2
+; CHECK-NEXT: s_mul_i32 s1, s1, s2
+; CHECK-NEXT: s_mul_i32 s3, s0, s3
+; CHECK-NEXT: s_add_co_u32 s1, s4, s1
+; CHECK-NEXT: s_mul_i32 s0, s0, s2
+; CHECK-NEXT: s_add_co_u32 s1, s1, s3
+; CHECK-NEXT: s_delay_alu instid0(SALU_CYCLE_1)
+; CHECK-NEXT: v_dual_mov_b32 v0, s0 :: v_dual_mov_b32 v1, s1
+; CHECK-NEXT: s_set_pc_i64 s[30:31]
+ %m = call i64 @llvm.amdgcn.wave.reduce.and.i64(i64 %x, i32 1)
+ %r = call i64 @llvm.amdgcn.wave.reduce.sub.i64(i64 %m, i32 1)
+ ret i64 %r
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/228819
More information about the llvm-commits
mailing list