[llvm] [AMDGPU] Fix SIPeepholeSDWA crash on OR with VOPC SDWA operand (PR #217084)
Arseniy Obolenskiy via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 18 10:08:28 PDT 2026
https://github.com/aobolensk created https://github.com/llvm/llvm-project/pull/217084
VOPC SDWA instructions have no dst_sel operand, but the OR folding pattern assumed that one existed
>From ee45cb1aada1c81e9230b2462357e7b9197eadeb Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Tue, 18 Aug 2026 19:07:33 +0200
Subject: [PATCH] [AMDGPU] Fix SIPeepholeSDWA crash on OR with VOPC SDWA
operand
VOPC SDWA instructions have no dst_sel operand, but the OR folding pattern assumed that one existed
---
llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp | 12 ++++++++--
.../AMDGPU/sdwa-peephole-instr-gfx10.mir | 22 +++++++++++++++++++
.../CodeGen/AMDGPU/sdwa-peephole-or-vopc.ll | 20 +++++++++++++++++
3 files changed, 52 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/CodeGen/AMDGPU/sdwa-peephole-or-vopc.ll
diff --git a/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp b/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp
index cbb1efee7e559..f8a28983d3e11 100644
--- a/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp
+++ b/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp
@@ -64,6 +64,9 @@ class SIPeepholeSDWA {
std::optional<std::pair<MachineOperand *, AMDGPU::SDWA::SdwaSel>>
matchAndMask(MachineInstr &MI) const;
+ // VOPC SDWA instructions carry the SDWA TSFlag but have no dst_sel operand.
+ bool isSDWAWithDstSel(const MachineInstr &Inst) const;
+
void matchSDWAOperands(MachineBasicBlock &MBB);
std::unique_ptr<SDWAOperand> matchSDWAOperand(MachineInstr &MI);
void pseudoOpConvertToVOP2(MachineInstr &MI,
@@ -693,6 +696,11 @@ SIPeepholeSDWA::matchAndMask(MachineInstr &MI) const {
return std::make_pair(ValSrc, *Imm == 0x0000ffff ? WORD_0 : BYTE_0);
}
+bool SIPeepholeSDWA::isSDWAWithDstSel(const MachineInstr &Inst) const {
+ return TII->isSDWA(Inst) &&
+ AMDGPU::hasNamedOperand(Inst.getOpcode(), AMDGPU::OpName::dst_sel);
+}
+
std::unique_ptr<SDWAOperand>
SIPeepholeSDWA::matchSDWAOperand(MachineInstr &MI) {
unsigned Opcode = MI.getOpcode();
@@ -870,7 +878,7 @@ SIPeepholeSDWA::matchSDWAOperand(MachineInstr &MI) {
return CheckRetType(std::nullopt);
MachineInstr *Op1Inst = Op1Def->getParent();
- if (!TII->isSDWA(*Op1Inst))
+ if (!isSDWAWithDstSel(*Op1Inst))
return CheckRetType(std::nullopt);
MachineOperand *Op2Def = findSingleRegDef(Op2, MRI);
@@ -920,7 +928,7 @@ SIPeepholeSDWA::matchSDWAOperand(MachineInstr &MI) {
// For now this only works with SDWA instructions. For regular instructions
// there is no way to determine if the instruction writes only 8/16/24-bit
// out of full register size and all registers are at min 32-bit wide.
- if (!TII->isSDWA(*OtherInst))
+ if (!isSDWAWithDstSel(*OtherInst))
break;
SdwaSel DstSel = static_cast<SdwaSel>(
diff --git a/llvm/test/CodeGen/AMDGPU/sdwa-peephole-instr-gfx10.mir b/llvm/test/CodeGen/AMDGPU/sdwa-peephole-instr-gfx10.mir
index ef374678894b5..ef62e88d17fcf 100644
--- a/llvm/test/CodeGen/AMDGPU/sdwa-peephole-instr-gfx10.mir
+++ b/llvm/test/CodeGen/AMDGPU/sdwa-peephole-instr-gfx10.mir
@@ -291,3 +291,25 @@ body: |
S_SETPC_B64_return $sgpr30_sgpr31
...
+
+# GCN-LABEL: {{^}}name: or_of_vopc_sdwa
+
+# VOPC SDWA has no dst_sel, so neither OR order matches dst_unused:UNUSED_PRESERVE.
+# GCN: %{{[0-9]+}}:sreg_32_xm0_xexec = V_CMP_EQ_U32_sdwa 0, %{{[0-9]+}}, 0, %{{[0-9]+}}, 0, 6, 6, implicit $exec
+# GCN: %{{[0-9]+}}:vgpr_32 = V_OR_B32_e64 %{{[0-9]+}}, %{{[0-9]+}}, implicit $exec
+# GCN: %{{[0-9]+}}:vgpr_32 = V_OR_B32_e64 %{{[0-9]+}}, %{{[0-9]+}}, implicit $exec
+
+---
+name: or_of_vopc_sdwa
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0, $vgpr1
+ %0:vgpr_32 = COPY $vgpr0
+ %1:vgpr_32 = COPY $vgpr1
+ %2:vgpr_32 = V_ADD_F16_sdwa 0, %0, 0, %1, 0, 0, 5, 0, 4, 5, implicit $mode, implicit $exec
+ %3:sreg_32_xm0_xexec = V_CMP_EQ_U32_sdwa 0, %0, 0, %1, 0, 6, 6, implicit $exec
+ %4:vgpr_32 = V_OR_B32_e64 %2, %3, implicit $exec
+ %5:vgpr_32 = V_OR_B32_e64 %3, %2, implicit $exec
+ S_ENDPGM 0, implicit %4, implicit %5
+...
diff --git a/llvm/test/CodeGen/AMDGPU/sdwa-peephole-or-vopc.ll b/llvm/test/CodeGen/AMDGPU/sdwa-peephole-or-vopc.ll
new file mode 100644
index 0000000000000..21b2f091ff0d6
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/sdwa-peephole-or-vopc.ll
@@ -0,0 +1,20 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=amdgpu10.30 < %s | FileCheck -check-prefix=GFX1030 %s
+
+; E2e companion to or_of_vopc_sdwa in sdwa-peephole-instr-gfx10.mir (missing dst_sel on VOPC SDWA).
+
+define i32 @or_of_vopc_sdwa(i32 %a, i32 %b) {
+; GFX1030-LABEL: or_of_vopc_sdwa:
+; GFX1030: ; %bb.0:
+; GFX1030-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX1030-NEXT: v_add_nc_u32_sdwa v2, v0, v1 dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:WORD_1
+; GFX1030-NEXT: v_cmp_eq_u32_sdwa s4, v0, v1 src0_sel:WORD_1 src1_sel:WORD_1
+; GFX1030-NEXT: v_or_b32_e32 v0, s4, v2
+; GFX1030-NEXT: s_setpc_b64 s[30:31]
+ %ah = lshr i32 %a, 16
+ %bh = lshr i32 %b, 16
+ %sum = add i32 %ah, %bh
+ %mask = call i32 @llvm.amdgcn.icmp.i32.i32(i32 %ah, i32 %bh, i32 32)
+ %r = or i32 %sum, %mask
+ ret i32 %r
+}
More information about the llvm-commits
mailing list