[llvm] [SPIR-V] Implement selection for llvm.canonicalize(x) as fmul(x, 1.0) (PR #178439)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 28 06:53:44 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-spir-v

Author: Mészáros Gergely (Maetveis)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/178439.diff


3 Files Affected:

- (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+32) 
- (modified) llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp (+3) 
- (modified) llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll (+45) 


``````````diff
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 915db6824d7c6..8bd3a7ce73ff2 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -339,6 +339,8 @@ class SPIRVInstructionSelector : public InstructionSelector {
                    MachineInstr &I) const;
   bool selectDerivativeInst(Register ResVReg, const SPIRVType *ResType,
                             MachineInstr &I, const unsigned DPdOpCode) const;
+  bool selectFCanonicalize(Register ResVReg, const SPIRVType *ResType,
+                           MachineInstr &I) const;
   // Utilities
   std::pair<Register, bool>
   buildI32Constant(uint32_t Val, MachineInstr &I,
@@ -987,6 +989,9 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
   case TargetOpcode::G_FMAXIMUM:
     return selectExtInst(ResVReg, ResType, I, CL::fmax, GL::NMax);
 
+  case TargetOpcode::G_FCANONICALIZE:
+    return selectFCanonicalize(ResVReg, ResType, I);
+
   case TargetOpcode::G_FCOPYSIGN:
     return selectExtInst(ResVReg, ResType, I, CL::copysign);
 
@@ -3007,6 +3012,33 @@ SPIRVInstructionSelector::buildI32Constant(uint32_t Val, MachineInstr &I,
   return {NewReg, Result};
 }
 
+bool SPIRVInstructionSelector::selectFCanonicalize(Register ResVReg,
+                                                   const SPIRVType *ResType,
+                                                   MachineInstr &I) const {
+  // There is no native fcanonicalize instruction in SPIRV. We can lower it to:
+  // - fmin(x, x) or
+  // - fmul(x, 1.0)
+  //
+  // We use fmul(x, 1.0) here, because:
+  // - llvm-spirv translates fmin to a function call, whereas
+  //   fmul is translated to the LLVM fmul instruction.
+  // - fmin requires either OpenCL or GLSL extended instruction set, whereas
+  //   fmul does not.
+
+  // fcanonicalize(x) -> fmul(x, 1.0)
+  SPIRVType *SpirvScalarType = GR.getScalarOrVectorComponentType(ResType);
+  auto Opcode = ResType->getOpcode() == SPIRV::OpTypeVector
+                    ? SPIRV::OpVectorTimesScalar
+                    : SPIRV::OpFMulS;
+
+  return BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode))
+      .addDef(ResVReg)
+      .addUse(GR.getSPIRVTypeID(ResType))
+      .addUse(I.getOperand(1).getReg())
+      .addUse(buildOnesValF(SpirvScalarType, I))
+      .constrainAllUses(TII, TRI, RBI);
+}
+
 bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
                                           const SPIRVType *ResType,
                                           MachineInstr &I) const {
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index 03d846cb90b4c..fcfb2f33b88c3 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -467,6 +467,9 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
                                G_INTRINSIC_ROUNDEVEN})
       .legalFor(allFloatScalarsAndVectors);
 
+  getActionDefinitionsBuilder(G_FCANONICALIZE)
+      .legalFor(allFloatScalarsAndVectors);
+
   getActionDefinitionsBuilder(G_FCOPYSIGN)
       .legalForCartesianProduct(allFloatScalarsAndVectors,
                                 allFloatScalarsAndVectors);
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
index 70030ca1a0316..41a69f3dfd6b3 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
@@ -8,6 +8,11 @@
 ; CHECK: %[[#var2:]] = OpTypeFloat 64
 ; CHECK: %[[#var3:]] = OpTypeVector %[[#var1]] 4
 
+; 15360 = 0x3c00 = 1.0 (bf16)
+; CHECK: %[[#one_f16:]] = OpConstant %[[#var0]] 15360
+; CHECK: %[[#one_f32:]] = OpConstant %[[#var1]] 1
+; CHECK: %[[#one_f64:]] = OpConstant %[[#var2]] 1
+
 ; CHECK: OpFunction
 ; CHECK: %[[#]] = OpExtInst %[[#var0]] %[[#extinst_id]] fabs
 ; CHECK: OpFunctionEnd
@@ -403,3 +408,43 @@ return:
 }
 
 declare { double, double } @llvm.modf.f64(double)
+
+; CHECK: OpFunction
+; CHECK: %[[#x:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#]] = OpFMul %[[#var0]] %[[#x]] %[[#one_f16]]
+; CHECK: OpFunctionEnd
+define dso_local half @TestCanonicalizeF16(half %x) {
+entry:
+  %t = tail call half @llvm.canonicalize.f16(half %x)
+  ret half %t
+}
+
+; CHECK: OpFunction
+; CHECK: %[[#x:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#]] = OpFMul %[[#var1]] %[[#x]] %[[#one_f32]]
+; CHECK: OpFunctionEnd
+define dso_local float @TestCanonicalizeF32(float %x) {
+entry:
+  %t = tail call float @llvm.canonicalize.f32(float %x)
+  ret float %t
+}
+
+; CHECK: OpFunction
+; CHECK: %[[#x:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#]] = OpFMul %[[#var2]] %[[#x]] %[[#one_f64]]
+; CHECK: OpFunctionEnd
+define dso_local double @TestCanonicalizeF64(double %x) {
+entry:
+  %t = tail call double @llvm.canonicalize.f64(double %x)
+  ret double %t
+}
+
+; CHECK: OpFunction
+; CHECK: %[[#x:]] = OpFunctionParameter %[[#]]
+; CHECK: %[[#]] = OpVectorTimesScalar %[[#var3]] %[[#x]] %[[#one_f32]]
+; CHECK: OpFunctionEnd
+define dso_local <4 x float> @TestCanonicalizeVec(<4 x float> %x) {
+entry:
+  %t = tail call <4 x float> @llvm.canonicalize.v4f32(<4 x float> %x)
+  ret <4 x float> %t
+}
\ No newline at end of file

``````````

</details>


https://github.com/llvm/llvm-project/pull/178439


More information about the llvm-commits mailing list