Skip to content

Conversation

@SubashBoopathi
Copy link
Contributor

Added SPIR-V support for constrained arithmetic intrinsic fmuladd, lowered as a sequence of OpFMul and OpFAdd with roundingmode, consistent with the SPIR-V translator.

@SubashBoopathi SubashBoopathi marked this pull request as draft December 2, 2025 10:01
@SubashBoopathi SubashBoopathi changed the title Constrained fmuladd intrinsic [SPIRV] Added support for the constrained arithmetic(Fmuladd) intrinsic Dec 2, 2025
@SubashBoopathi SubashBoopathi marked this pull request as ready for review December 2, 2025 10:03
@github-actions
Copy link

github-actions bot commented Dec 2, 2025

🐧 Linux x64 Test Results

  • 186879 tests passed
  • 4916 tests skipped

✅ The build succeeded and all tests passed.

@llvmbot
Copy link
Member

llvmbot commented Dec 3, 2025

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

Author: Subash B (SubashBoopathi)

Changes

Added SPIR-V support for constrained arithmetic intrinsic fmuladd, lowered as a sequence of OpFMul and OpFAdd with roundingmode, consistent with the SPIR-V translator.


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

2 Files Affected:

  • (modified) llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp (+22)
  • (added) llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-fmuladd.ll (+64)
diff --git a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp
index be88f334d2171..01670d8cb4c6b 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPrepareFunctions.cpp
@@ -393,6 +393,24 @@ static bool toSpvLifetimeIntrinsic(IntrinsicInst *II, Intrinsic::ID NewID) {
   return true;
 }
 
+static void
+lowerConstrainedFmuladd(IntrinsicInst *II,
+                        SmallVector<Instruction *> &EraseFromParent) {
+  auto *FPI = cast<ConstrainedFPIntrinsic>(II);
+  Value *A = FPI->getArgOperand(0);
+  Value *Mul = FPI->getArgOperand(1);
+  Value *Add = FPI->getArgOperand(2);
+  IRBuilder<> Builder(II->getParent());
+  Builder.SetInsertPoint(II);
+  std::optional<RoundingMode> Rounding = FPI->getRoundingMode();
+  Value *Product = Builder.CreateFMul(A, Mul, II->getName() + ".mul");
+  Value *Result = Builder.CreateConstrainedFPBinOp(
+      Intrinsic::experimental_constrained_fadd, Product, Add, {},
+      II->getName() + ".add", nullptr, Rounding);
+  II->replaceAllUsesWith(Result);
+  EraseFromParent.push_back(II);
+}
+
 // Substitutes calls to LLVM intrinsics with either calls to SPIR-V intrinsics
 // or calls to proper generated functions. Returns True if F was modified.
 bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) {
@@ -446,6 +464,10 @@ bool SPIRVPrepareFunctions::substituteIntrinsicCalls(Function *F) {
         lowerPtrAnnotation(II);
         Changed = true;
         break;
+      case Intrinsic::experimental_constrained_fmuladd:
+        lowerConstrainedFmuladd(II, EraseFromParent);
+        Changed = true;
+        break;
       case Intrinsic::experimental_constrained_fcmp:
       case Intrinsic::experimental_constrained_fcmps:
         lowerConstrainedFPCmpIntrinsic(dyn_cast<ConstrainedFPCmpIntrinsic>(II),
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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants