Author: Konstantinos Parasyris
Date: 2026-08-10T13:01:46-07:00
New Revision: 025458b32a86364dd793c3a47f972364cbb2dad4

URL: 
https://github.com/llvm/llvm-project/commit/025458b32a86364dd793c3a47f972364cbb2dad4
DIFF: 
https://github.com/llvm/llvm-project/commit/025458b32a86364dd793c3a47f972364cbb2dad4.diff

LOG: [CIR] Add cir.fmuladd op lowering to llvm.fmuladd (#215329)

Adds a new `cir.fmuladd` operation to the CIR dialect, modeling the
contractable fused multiply-add — `(a * b) + c` where the backend may
fuse into a single rounding step or not, at its discretion.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>

Added: 
    

Modified: 
    clang/include/clang/CIR/Dialect/IR/CIROps.td
    clang/test/CIR/IR/fenv.cir
    clang/test/CIR/Lowering/fenv.cir

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index d0f3c9ee6715f..88e869f7c2c4d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -7757,6 +7757,35 @@ def CIR_FMAOp : CIR_TernaryFPToFPBuiltinOp<"fma", 
"FMAOp"> {
   }];
 }
 
+def CIR_FMulAddOp : CIR_TernaryFPToFPBuiltinOp<"fmuladd", "FMulAddOp"> {
+  let summary = "Contractable fused multiply-add operation";
+
+  let description = [{
+    Computes `(a * b) + c`, allowing the multiply and add to be fused (or not)
+    into a single rounding step at the target's discretion. It lowers to the
+    `llvm.fmuladd` intrinsic (or its constrained variant when an `fenv`
+    attribute is present).
+
+    Unlike `cir.fma`, which maps to `llvm.fma` and guarantees a single
+    rounding, `cir.fmuladd` expresses the FP-contraction relaxation used for
+    `a * b + c` under `-ffp-contract=on` / `fast`, where the backend is free to
+    emit either a fused or an unfused sequence.
+
+    The inputs must be either:
+      • floating-point scalar types, or
+      • vectors whose element type is floating-point.
+
+    The result type must match the input type exactly.
+
+    Examples:
+      // scalar
+      %r = cir.fmuladd %a, %b, %c : !cir.float
+
+      // vector
+      %v = cir.fmuladd %a, %b, %c : !cir.vector<4 x !cir.float>
+  }];
+}
+
 
//===----------------------------------------------------------------------===//
 // Variadic Operations
 
//===----------------------------------------------------------------------===//

diff  --git a/clang/test/CIR/IR/fenv.cir b/clang/test/CIR/IR/fenv.cir
index 5602212ea1de1..cb0a9287deb44 100644
--- a/clang/test/CIR/IR/fenv.cir
+++ b/clang/test/CIR/IR/fenv.cir
@@ -82,12 +82,27 @@ cir.func @unary_fp_to_int_builtin_fenv(%a: !cir.float) -> 
!s32i {
 }
 
 // CHECK-LABEL: cir.func @ternary_fp_builtin_fenv
-cir.func @ternary_fp_builtin_fenv(%a: !cir.float, %b: !cir.float, %c: 
!cir.float) {
+cir.func @ternary_fp_builtin_fenv(%a: !cir.float, %b: !cir.float, %c: 
!cir.float,
+                                  %va: !cir.vector<4 x !cir.float>,
+                                  %vb: !cir.vector<4 x !cir.float>,
+                                  %vc: !cir.vector<4 x !cir.float>) {
   // CHECK: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.float {fenv = 
#cir.fenv<dynamic_rounding_mode = downward, strict_except = true>}
   %0 = cir.fma %a, %b, %c : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode 
= downward, strict_except = true>}
   // CHECK: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.float
   // CHECK-NOT: fenv
   %1 = cir.fma %a, %b, %c : !cir.float
+  // CHECK: cir.fmuladd %{{.*}}, %{{.*}}, %{{.*}} : !cir.float {fenv = 
#cir.fenv<dynamic_rounding_mode = downward, strict_except = true>}
+  %2 = cir.fmuladd %a, %b, %c : !cir.float {fenv = 
#cir.fenv<dynamic_rounding_mode = downward, strict_except = true>}
+  // CHECK: cir.fmuladd %{{.*}}, %{{.*}}, %{{.*}} : !cir.float
+  // CHECK-NOT: fenv
+  %3 = cir.fmuladd %a, %b, %c : !cir.float
+  // CHECK: cir.fma %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<4 x !cir.float> 
{fenv = #cir.fenv<strict_except = true>}
+  %4 = cir.fma %va, %vb, %vc : !cir.vector<4 x !cir.float> {fenv = 
#cir.fenv<strict_except = true>}
+  // CHECK: cir.fmuladd %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<4 x 
!cir.float> {fenv = #cir.fenv<strict_except = true>}
+  %5 = cir.fmuladd %va, %vb, %vc : !cir.vector<4 x !cir.float> {fenv = 
#cir.fenv<strict_except = true>}
+  // CHECK: cir.fmuladd %{{.*}}, %{{.*}}, %{{.*}} : !cir.vector<4 x !cir.float>
+  // CHECK-NOT: fenv
+  %6 = cir.fmuladd %va, %vb, %vc : !cir.vector<4 x !cir.float>
   cir.return
 }
 

diff  --git a/clang/test/CIR/Lowering/fenv.cir 
b/clang/test/CIR/Lowering/fenv.cir
index 282d51d2e73a7..cdb0c3f30bc62 100644
--- a/clang/test/CIR/Lowering/fenv.cir
+++ b/clang/test/CIR/Lowering/fenv.cir
@@ -124,6 +124,25 @@ module {
     %0 = cir.fma %a, %b, %c : !cir.double {fenv = #cir.fenv<strict_except = 
true>}
     // CHECK: llvm.intr.fma(%{{.*}}, %{{.*}}, %{{.*}}) : (f64, f64, f64) -> f64
     %1 = cir.fma %a, %b, %c : !cir.double
+    // CHECK: llvm.call_intrinsic 
"llvm.experimental.constrained.fmuladd"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, 
%{{.*}}) : (f64, f64, f64, !llvm.metadata, !llvm.metadata) -> f64
+    %2 = cir.fmuladd %a, %b, %c : !cir.double {fenv = #cir.fenv<strict_except 
= true>}
+    // CHECK: llvm.intr.fmuladd(%{{.*}}, %{{.*}}, %{{.*}}) : (f64, f64, f64) 
-> f64
+    %3 = cir.fmuladd %a, %b, %c : !cir.double
+    cir.return
+  }
+
+  // CHECK-LABEL: llvm.func @ternary_fp_vec_builtins
+  cir.func @ternary_fp_vec_builtins(%a: !cir.vector<4 x !cir.float>,
+                                    %b: !cir.vector<4 x !cir.float>,
+                                    %c: !cir.vector<4 x !cir.float>) {
+    // CHECK: llvm.call_intrinsic "llvm.experimental.constrained.fma"(%{{.*}}, 
%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (vector<4xf32>, vector<4xf32>, 
vector<4xf32>, !llvm.metadata, !llvm.metadata) -> vector<4xf32>
+    %0 = cir.fma %a, %b, %c : !cir.vector<4 x !cir.float> {fenv = 
#cir.fenv<strict_except = true>}
+    // CHECK: llvm.intr.fma(%{{.*}}, %{{.*}}, %{{.*}}) : (vector<4xf32>, 
vector<4xf32>, vector<4xf32>) -> vector<4xf32>
+    %1 = cir.fma %a, %b, %c : !cir.vector<4 x !cir.float>
+    // CHECK: llvm.call_intrinsic 
"llvm.experimental.constrained.fmuladd"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, 
%{{.*}}) : (vector<4xf32>, vector<4xf32>, vector<4xf32>, !llvm.metadata, 
!llvm.metadata) -> vector<4xf32>
+    %2 = cir.fmuladd %a, %b, %c : !cir.vector<4 x !cir.float> {fenv = 
#cir.fenv<strict_except = true>}
+    // CHECK: llvm.intr.fmuladd(%{{.*}}, %{{.*}}, %{{.*}}) : (vector<4xf32>, 
vector<4xf32>, vector<4xf32>) -> vector<4xf32>
+    %3 = cir.fmuladd %a, %b, %c : !cir.vector<4 x !cir.float>
     cir.return
   }
 


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to