[llvm] [SPIRV] Added support for the constrained arithmetic intrinsic (PR #157441)

Subash B via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 8 22:50:45 PDT 2025


https://github.com/SubashBoopathi updated https://github.com/llvm/llvm-project/pull/157441

>From b2c1390ef35652c5e387f9f21cadcedd04d0e52c Mon Sep 17 00:00:00 2001
From: Subash B <subash.boopathi at multicorewareinc.com>
Date: Wed, 20 Aug 2025 18:01:14 +0530
Subject: [PATCH] Added Support for the Constrained fmuladd

---
 llvm/include/llvm/Support/TargetOpcodes.def   |  1 +
 llvm/include/llvm/Target/GenericOpcodes.td    |  1 +
 llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp  |  2 +
 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 37 +++++++++++
 llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp  |  2 +-
 .../llvm-intrinsics/constrained-fmuladd.ll    | 64 +++++++++++++++++++
 6 files changed, 106 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-fmuladd.ll

diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def
index b905576b61791..dcf80c56c47b3 100644
--- a/llvm/include/llvm/Support/TargetOpcodes.def
+++ b/llvm/include/llvm/Support/TargetOpcodes.def
@@ -643,6 +643,7 @@ HANDLE_TARGET_OPCODE(G_FMA)
 
 /// Generic FP multiply and add. Behaves as separate fmul and fadd.
 HANDLE_TARGET_OPCODE(G_FMAD)
+HANDLE_TARGET_OPCODE(G_STRICT_FMULADD)
 
 /// Generic FP division.
 HANDLE_TARGET_OPCODE(G_FDIV)
diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td
index ce4750db88c9a..08fbd2253edf2 100644
--- a/llvm/include/llvm/Target/GenericOpcodes.td
+++ b/llvm/include/llvm/Target/GenericOpcodes.td
@@ -1716,6 +1716,7 @@ def G_STRICT_FREM : ConstrainedInstruction<G_FREM>;
 def G_STRICT_FMA : ConstrainedInstruction<G_FMA>;
 def G_STRICT_FSQRT : ConstrainedInstruction<G_FSQRT>;
 def G_STRICT_FLDEXP : ConstrainedInstruction<G_FLDEXP>;
+def G_STRICT_FMULADD : ConstrainedInstruction<G_FMAD>;
 
 //------------------------------------------------------------------------------
 // Memory intrinsics
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index d7280eaba2440..3742df2f1732b 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -2061,6 +2061,8 @@ static unsigned getConstrainedOpcode(Intrinsic::ID ID) {
     return TargetOpcode::G_STRICT_FSQRT;
   case Intrinsic::experimental_constrained_ldexp:
     return TargetOpcode::G_STRICT_FLDEXP;
+  case Intrinsic::experimental_constrained_fmuladd:
+    return TargetOpcode::G_STRICT_FMULADD;
   default:
     return 0;
   }
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 6608b3f2cbefd..d352457b3c9e8 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -227,6 +227,9 @@ class SPIRVInstructionSelector : public InstructionSelector {
   bool selectExt(Register ResVReg, const SPIRVType *ResType, MachineInstr &I,
                  bool IsSigned) const;
 
+  bool selectStrictFMulAdd(Register ResVReg, const SPIRVType *ResType,
+                           MachineInstr &I) const;
+
   bool selectTrunc(Register ResVReg, const SPIRVType *ResType,
                    MachineInstr &I) const;
 
@@ -689,6 +692,9 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
   case TargetOpcode::G_FMA:
     return selectExtInst(ResVReg, ResType, I, CL::fma, GL::Fma);
 
+  case TargetOpcode::G_STRICT_FMULADD:
+    return selectStrictFMulAdd(ResVReg, ResType, I);
+
   case TargetOpcode::G_STRICT_FLDEXP:
     return selectExtInst(ResVReg, ResType, I, CL::ldexp);
 
@@ -1038,6 +1044,37 @@ bool SPIRVInstructionSelector::selectOpWithSrcs(Register ResVReg,
   return MIB.constrainAllUses(TII, TRI, RBI);
 }
 
+bool SPIRVInstructionSelector::selectStrictFMulAdd(Register ResVReg,
+                                                   const SPIRVType *ResType,
+                                                   MachineInstr &I) const {
+  MachineBasicBlock &BB = *I.getParent();
+  Register MulLHS = I.getOperand(1).getReg();
+  Register MulRHS = I.getOperand(2).getReg();
+  Register AddRHS = I.getOperand(3).getReg();
+  SPIRVType *MulLHSType = GR.getSPIRVTypeForVReg(MulLHS);
+  unsigned MulOpcode, AddOpcode;
+  if (MulLHSType->getOpcode() == SPIRV::OpTypeFloat) {
+    MulOpcode = SPIRV::OpFMulS;
+    AddOpcode = SPIRV::OpFAddS;
+  } else {
+    MulOpcode = SPIRV::OpFMulV;
+    AddOpcode = SPIRV::OpFAddV;
+  }
+  Register MulTemp = MRI->createVirtualRegister(MRI->getRegClass(MulLHS));
+  BuildMI(BB, I, I.getDebugLoc(), TII.get(MulOpcode))
+      .addDef(MulTemp)
+      .addUse(GR.getSPIRVTypeID(ResType))
+      .addUse(MulLHS)
+      .addUse(MulRHS)
+      .constrainAllUses(TII, TRI, RBI);
+  return BuildMI(BB, I, I.getDebugLoc(), TII.get(AddOpcode))
+      .addDef(ResVReg)
+      .addUse(GR.getSPIRVTypeID(ResType))
+      .addUse(MulTemp)
+      .addUse(AddRHS)
+      .constrainAllUses(TII, TRI, RBI);
+}
+
 bool SPIRVInstructionSelector::selectUnOp(Register ResVReg,
                                           const SPIRVType *ResType,
                                           MachineInstr &I,
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index 721f64a329d31..8041ef67cfa56 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -193,7 +193,7 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
       .legalFor(allIntScalarsAndVectors)
       .legalIf(extendedScalarsAndVectors);
 
-  getActionDefinitionsBuilder({G_FMA, G_STRICT_FMA})
+  getActionDefinitionsBuilder({G_FMA, G_STRICT_FMA, G_STRICT_FMULADD})
       .legalFor(allFloatScalarsAndVectors);
 
   getActionDefinitionsBuilder(G_STRICT_FLDEXP)
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-fmuladd.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-fmuladd.ll
new file mode 100644
index 0000000000000..340f2d78fc21b
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-fmuladd.ll
@@ -0,0 +1,64 @@
+; RUN: llc -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: OpDecorate %[[#]] FPRoundingMode RTE
+; CHECK-DAG: OpDecorate %[[#]] FPRoundingMode RTZ
+; CHECK-DAG: OpDecorate %[[#]] FPRoundingMode RTP
+; CHECK-DAG: OpDecorate %[[#]] FPRoundingMode RTN
+; CHECK-DAG: OpDecorate %[[#]] FPRoundingMode RTE
+
+; CHECK: OpFMul %[[#]] %[[#]] %[[#]]
+; CHECK: OpFAdd %[[#]] %[[#]] %[[#]]
+define spir_kernel void @test_f32(float %a) {
+entry:
+  %r = tail call float @llvm.experimental.constrained.fmuladd.f32(
+              float %a, float %a, float %a,
+              metadata !"round.tonearest", metadata !"fpexcept.strict")
+  ret void
+}
+
+; CHECK: OpFMul %[[#]] %[[#]] %[[#]] 
+; CHECK: OpFAdd %[[#]] %[[#]] %[[#]]
+define spir_kernel void @test_f64(double %a) {
+entry:
+  %r = tail call double @llvm.experimental.constrained.fmuladd.f64(
+              double %a, double %a, double %a,
+              metadata !"round.towardzero", metadata !"fpexcept.strict")
+  ret void
+}
+
+; CHECK: OpFMul %[[#]] %[[#]] %[[#]]
+; CHECK: OpFAdd %[[#]] %[[#]] %[[#]]
+define spir_kernel void @test_v2f32(<2 x float> %a) {
+entry:
+  %r = tail call <2 x float> @llvm.experimental.constrained.fmuladd.v2f32(
+              <2 x float> %a, <2 x float> %a, <2 x float> %a,
+              metadata !"round.upward", metadata !"fpexcept.strict")
+  ret void
+}
+
+; CHECK: OpFMul %[[#]] %[[#]] %[[#]]
+; CHECK: OpFAdd %[[#]] %[[#]] %[[#]]
+define spir_kernel void @test_v4f32(<4 x float> %a) {
+entry:
+  %r = tail call <4 x float> @llvm.experimental.constrained.fmuladd.v4f32(
+              <4 x float> %a, <4 x float> %a, <4 x float> %a,
+              metadata !"round.downward", metadata !"fpexcept.strict")
+  ret void
+}
+
+; CHECK: OpFMul %[[#]] %[[#]] %[[#]]
+; CHECK: OpFAdd %[[#]] %[[#]] %[[#]]
+define spir_kernel void @test_v2f64(<2 x double> %a) {
+entry:
+  %r = tail call <2 x double> @llvm.experimental.constrained.fmuladd.v2f64(
+              <2 x double> %a, <2 x double> %a, <2 x double> %a,
+              metadata !"round.tonearest", metadata !"fpexcept.strict")
+  ret void
+}
+
+declare float  @llvm.experimental.constrained.fmuladd.f32(float, float, float, metadata, metadata)
+declare double @llvm.experimental.constrained.fmuladd.f64(double, double, double, metadata, metadata)
+declare <2 x float> @llvm.experimental.constrained.fmuladd.v2f32(<2 x float>, <2 x float>, <2 x float>, metadata, metadata)
+declare <4 x float> @llvm.experimental.constrained.fmuladd.v4f32(<4 x float>, <4 x float>, <4 x float>, metadata, metadata)
+declare <2 x double> @llvm.experimental.constrained.fmuladd.v2f64(<2 x double>, <2 x double>, <2 x double>, metadata, metadata)



More information about the llvm-commits mailing list