[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