[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