[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