[llvm] [SPIR-V] Sign extend narrow ints feeding sitofp (PR #222969)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 29 00:55:44 PDT 2026


https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/222969

>From 63c5fb4a6ff92fa60e917fc224e235fb87dbb9b3 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Fri, 11 Sep 2026 17:31:58 +0200
Subject: [PATCH 1/2] [SPIRV] Sign extend narrow ints feeding sitofp

---
 llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp   | 36 ++++++++-----------
 .../SPIRV/legalization/signed-narrow-int.ll   | 33 ++++++++++++++---
 2 files changed, 43 insertions(+), 26 deletions(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index e383e70ccf05b..30aff9860ae10 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -516,6 +516,7 @@ static bool isSignSensitiveOp(const MachineInstr &MI) {
   case TargetOpcode::G_ASHR:
   case TargetOpcode::G_SDIV:
   case TargetOpcode::G_SREM:
+  case TargetOpcode::G_SITOFP:
     return true;
   case TargetOpcode::G_ICMP:
     return CmpInst::isSigned(
@@ -554,14 +555,9 @@ recordSignSensitiveOperandWidths(MachineFunction &MF,
     for (MachineInstr &MI : MBB) {
       if (!isSignSensitiveOp(MI))
         continue;
-      // Value operands are the trailing two, past any def or predicate.
-      unsigned N = MI.getNumOperands();
-      const MachineOperand &LHS = MI.getOperand(N - 2);
-      const MachineOperand &RHS = MI.getOperand(N - 1);
-      // Sign-sensitive opcodes carry register operands only.
-      assert(LHS.isReg() && RHS.isReg());
-      bool NeedsRewrite = RecordIfNarrow(LHS.getReg());
-      NeedsRewrite = RecordIfNarrow(RHS.getReg()) || NeedsRewrite;
+      bool NeedsRewrite = false;
+      for (const MachineOperand &MO : MI.all_uses())
+        NeedsRewrite = RecordIfNarrow(MO.getReg()) || NeedsRewrite;
       if (NeedsRewrite)
         Info.Worklist.push_back(&MI);
     }
@@ -601,22 +597,18 @@ static void widenSignSensitiveOps(MachineFunction &MF, SPIRVGlobalRegistry *GR,
   // TODO: when the same narrow vreg feeds multiple sign-sensitive ops (e.g.
   // sdiv %x, %y and srem %x, %y), emit one shared G_SEXT_INREG instead of one
   // per use.
+  const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();
   for (MachineInstr *MI : Info.Worklist) {
-    unsigned N = MI->getNumOperands();
-    MachineOperand &LHS = MI->getOperand(N - 2);
-    MachineOperand &RHS = MI->getOperand(N - 1);
-    Register LHSReg = LHS.getReg();
-    Register RHSReg = RHS.getReg();
-    if (auto It = Info.OrigWidth.find(LHSReg); It != Info.OrigWidth.end())
-      LHS.setReg(SignExtendReg(LHSReg, It->second, *MI));
-    // Same vreg on both sides (e.g. G_ICMP slt %x, %x): reuse the sext just
-    // emitted for LHS instead of emitting a second one.
-    if (RHSReg == LHSReg) {
-      RHS.setReg(LHS.getReg());
-      continue;
+    for (MachineOperand &MO : MI->all_uses()) {
+      Register Reg = MO.getReg();
+      auto It = Info.OrigWidth.find(Reg);
+      if (It == Info.OrigWidth.end())
+        continue;
+      // substituteRegister fills every slot holding Reg at once: SignExtendReg
+      // retypes Reg in place, so a second sext would read the widened width.
+      MI->substituteRegister(Reg, SignExtendReg(Reg, It->second, *MI),
+                             /*SubIdx=*/0, TRI);
     }
-    if (auto It = Info.OrigWidth.find(RHSReg); It != Info.OrigWidth.end())
-      RHS.setReg(SignExtendReg(RHSReg, It->second, *MI));
   }
 }
 
diff --git a/llvm/test/CodeGen/SPIRV/legalization/signed-narrow-int.ll b/llvm/test/CodeGen/SPIRV/legalization/signed-narrow-int.ll
index c2d9974939c21..e98c81642d978 100644
--- a/llvm/test/CodeGen/SPIRV/legalization/signed-narrow-int.ll
+++ b/llvm/test/CodeGen/SPIRV/legalization/signed-narrow-int.ll
@@ -6,10 +6,10 @@
 
 ; SPIR-V (without sub-byte int extensions) widens sub-pow2 scalars to the next
 ; legal width by relabeling the LLT only, without inserting any sign-extension.
-; Sign-sensitive ops (icmp slt/sle/sgt/sge, ashr, sdiv, srem) on such operands
-; would then read the sign bit at the wrong position. The pre-legalizer must
-; emit a sign-extend-in-register before the widening so the wide-width signed
-; op observes the correct sign bit.
+; Sign-sensitive ops (icmp slt/sle/sgt/sge, ashr, sdiv, srem, sitofp) on such
+; operands would then read the sign bit at the wrong position. The pre-legalizer
+; must emit a sign-extend-in-register before the widening so the wide-width
+; signed op observes the correct sign bit.
 
 ; CHECK-DAG: %[[#I8:]] = OpTypeInt 8 0
 ; CHECK-DAG: %[[#I32:]] = OpTypeInt 32 0
@@ -270,6 +270,31 @@ define spir_kernel void @sdiv_i24_from_globals() {
   ret void
 }
 
+; ----------------------------------------------------------------------------
+; sitofp has a single value operand, so the def must not be mistaken for one.
+; CHECK: OpFunction
+; CHECK: %[[#XF:]] = OpFunctionParameter
+; CHECK: OpFunctionParameter
+; CHECK: %[[#SHLF:]] = OpShiftLeftLogical %[[#I8]] %[[#XF]] %[[#K4]]
+; CHECK: %[[#SXF:]] = OpShiftRightArithmetic %[[#I8]] %[[#SHLF]] %[[#K4]]
+; CHECK: OpConvertSToF {{%[0-9]+}} %[[#SXF]]
+define spir_kernel void @sitofp_i4(i4 %x, ptr addrspace(1) %out) {
+  %r = sitofp i4 %x to float
+  store float %r, ptr addrspace(1) %out
+  ret void
+}
+
+; ----------------------------------------------------------------------------
+; Negative test: uitofp must NOT emit sign-extension shifts.
+; CHECK: OpFunction
+; CHECK-NOT: OpShiftRightArithmetic
+; CHECK: OpConvertUToF
+define spir_kernel void @uitofp_i4(i4 %x, ptr addrspace(1) %out) {
+  %r = uitofp i4 %x to float
+  store float %r, ptr addrspace(1) %out
+  ret void
+}
+
 ; ----------------------------------------------------------------------------
 ; Negative test: unsigned compare must NOT emit sign-extension shifts.
 ; CHECK: OpFunction

>From 36ad5def57e62ead5c4960f21d870ed2e06e56c3 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <gooddoog at student.su>
Date: Mon, 28 Sep 2026 13:48:46 +0200
Subject: [PATCH 2/2] Update llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp

Co-authored-by: Marcos Maronas <mmaronas at amd.com>
---
 llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
index 5d4480b763a49..ecd5825db5089 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
@@ -632,7 +632,7 @@ static void widenSignSensitiveOps(MachineFunction &MF, SPIRVGlobalRegistry *GR,
   // per use.
   const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();
   for (MachineInstr *MI : Info.SignSensitiveWorklist) {
-    for (MachineOperand &MO : MI->all_uses()) {
+    for (const MachineOperand &MO : MI->all_uses()) {
       Register Reg = MO.getReg();
       auto It = Info.OrigWidth.find(Reg);
       if (It == Info.OrigWidth.end())



More information about the llvm-commits mailing list