From d512507ab33f3c0438873d5736e9f603874d3ef6 Mon Sep 17 00:00:00 2001 From: Subash B Date: Wed, 20 Aug 2025 18:01:14 +0530 Subject: [PATCH 1/4] 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; def G_STRICT_FMA : ConstrainedInstruction; def G_STRICT_FSQRT : ConstrainedInstruction; def G_STRICT_FLDEXP : ConstrainedInstruction; +def G_STRICT_FMULADD : ConstrainedInstruction; //------------------------------------------------------------------------------ // Memory intrinsics diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 768e3713f78e2..01e55dea4ce40 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -2080,6 +2080,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 3ad5528fab061..01551d9738f03 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -232,6 +232,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; @@ -713,6 +716,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); @@ -1062,6 +1068,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 170bddd507e3b..6ca9b71305155 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) From 61dad88fc9c0e9f01f79fad78df0e9493173e51a Mon Sep 17 00:00:00 2001 From: Subash B Date: Mon, 13 Oct 2025 09:22:34 +0530 Subject: [PATCH 2/4] Removed the legalization of the Opcode and used lower() --- llvm/include/llvm/Support/TargetOpcodes.def | 2 +- llvm/include/llvm/Target/GenericOpcodes.td | 2 +- llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp | 2 +- .../CodeGen/GlobalISel/LegalizerHelper.cpp | 1 + .../Target/SPIRV/SPIRVInstructionSelector.cpp | 37 ------------------- llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 5 ++- 6 files changed, 8 insertions(+), 41 deletions(-) diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def index dcf80c56c47b3..7c2fd8e30873b 100644 --- a/llvm/include/llvm/Support/TargetOpcodes.def +++ b/llvm/include/llvm/Support/TargetOpcodes.def @@ -643,7 +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) +HANDLE_TARGET_OPCODE(G_STRICT_FMAD) /// 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 08fbd2253edf2..e81e0b9a1b90b 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -1716,7 +1716,7 @@ def G_STRICT_FREM : ConstrainedInstruction; def G_STRICT_FMA : ConstrainedInstruction; def G_STRICT_FSQRT : ConstrainedInstruction; def G_STRICT_FLDEXP : ConstrainedInstruction; -def G_STRICT_FMULADD : ConstrainedInstruction; +def G_STRICT_FMAD : ConstrainedInstruction; //------------------------------------------------------------------------------ // Memory intrinsics diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 01e55dea4ce40..302f8ed653233 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -2081,7 +2081,7 @@ static unsigned getConstrainedOpcode(Intrinsic::ID ID) { case Intrinsic::experimental_constrained_ldexp: return TargetOpcode::G_STRICT_FLDEXP; case Intrinsic::experimental_constrained_fmuladd: - return TargetOpcode::G_STRICT_FMULADD; + return TargetOpcode::G_STRICT_FMAD; default: return 0; } diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index f3e036ed1b947..7e3dfca365147 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -4523,6 +4523,7 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) { return Legalized; } case TargetOpcode::G_FMAD: + case TargetOpcode::G_STRICT_FMAD: return lowerFMad(MI); case TargetOpcode::G_FFLOOR: return lowerFFloor(MI); diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index 01551d9738f03..3ad5528fab061 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -232,9 +232,6 @@ 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; @@ -716,9 +713,6 @@ 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); @@ -1068,37 +1062,6 @@ 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 6ca9b71305155..75451b14bd388 100644 --- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp @@ -193,9 +193,12 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) { .legalFor(allIntScalarsAndVectors) .legalIf(extendedScalarsAndVectors); - getActionDefinitionsBuilder({G_FMA, G_STRICT_FMA, G_STRICT_FMULADD}) + getActionDefinitionsBuilder({G_FMA, G_STRICT_FMA}) .legalFor(allFloatScalarsAndVectors); + getActionDefinitionsBuilder(G_STRICT_FMAD) + .lower(); + getActionDefinitionsBuilder(G_STRICT_FLDEXP) .legalForCartesianProduct(allFloatScalarsAndVectors, allIntScalars); From 082c8aa5ef82e6360b24012fd14081fa2cbd6374 Mon Sep 17 00:00:00 2001 From: Subash B Date: Mon, 13 Oct 2025 09:31:23 +0530 Subject: [PATCH 3/4] Slight changes in the format of legalizerinfo --- llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp index 75451b14bd388..8b9fadbfaeb1b 100644 --- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp @@ -197,6 +197,7 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) { .legalFor(allFloatScalarsAndVectors); getActionDefinitionsBuilder(G_STRICT_FMAD) + .legalFor(allFloatScalarsAndVectors) .lower(); getActionDefinitionsBuilder(G_STRICT_FLDEXP) From b9d3905ef4eaa3f5465af7ec789fabd60580dd6f Mon Sep 17 00:00:00 2001 From: Subash B Date: Wed, 12 Nov 2025 14:38:12 +0530 Subject: [PATCH 4/4] Modified the legalization conditions to lower the instruction directly --- llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp index 8b9fadbfaeb1b..8c0c9de690483 100644 --- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp @@ -196,9 +196,7 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) { getActionDefinitionsBuilder({G_FMA, G_STRICT_FMA}) .legalFor(allFloatScalarsAndVectors); - getActionDefinitionsBuilder(G_STRICT_FMAD) - .legalFor(allFloatScalarsAndVectors) - .lower(); + getActionDefinitionsBuilder(G_STRICT_FMAD).lower(); getActionDefinitionsBuilder(G_STRICT_FLDEXP) .legalForCartesianProduct(allFloatScalarsAndVectors, allIntScalars);