https://github.com/andykaylor created 
https://github.com/llvm/llvm-project/pull/212880

This adds the #cir.fenv attribute to the CIR_UnaryFPToIntBuiltinOp and 
CIR_TernaryFPToFPBuiltinOp base classes, and through them to the cir.lround, 
cir.llround, cir.lrint, cir.llrint, and cir.fma operations.

This attribute is still missing from various cast and compare operations. Those 
will be added in a follow-up change.

Assisted-by: Cursor / various models

>From 6afee7613fefafbc91e452373c4d143fb2e9a43b Mon Sep 17 00:00:00 2001
From: Andy Kaylor <[email protected]>
Date: Wed, 29 Jul 2026 14:47:24 -0700
Subject: [PATCH] [CIR] Add fenv attribute to more builtins

This adds the #cir.fenv attribute to the CIR_UnaryFPToIntBuiltinOp and
CIR_TernaryFPToFPBuiltinOp base classes, and through them to the
cir.lround, cir.llround, cir.lrint, cir.llrint, and cir.fma operations.

This attribute is still missing from various cast and compare operations.
Those will be added in a follow-up change.

Assisted-by: Cursor / various models
---
 clang/include/clang/CIR/Dialect/IR/CIROps.td | 28 +++++++++++++++-----
 clang/test/CIR/IR/fenv.cir                   | 24 +++++++++++++++++
 clang/unittests/CIR/FenvOpTest.cpp           | 21 ++++++++++++++-
 3 files changed, 66 insertions(+), 7 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 7d6e250c09e02..8592d2e9bdc16 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -7236,9 +7236,10 @@ def CIR_FloorOp : CIR_UnaryFPToFPBuiltinOp<"floor", 
"FFloorOp"> {
 }
 
 class CIR_UnaryFPToIntBuiltinOp<string mnemonic, string llvmOpName>
-    : CIR_Op<mnemonic, [Pure]>
+    : CIR_Op<mnemonic, CIR_FenvOpTraits>
 {
-  let arguments = (ins CIR_AnyFloatType:$src);
+  let arguments = (ins CIR_AnyFloatType:$src,
+                       OptionalAttr<CIR_FenvAttr>:$fenv);
   let results = (outs CIR_IntType:$result);
 
   let summary = [{
@@ -7250,6 +7251,12 @@ class CIR_UnaryFPToIntBuiltinOp<string mnemonic, string 
llvmOpName>
     $src `:` type($src) `->` type($result) attr-dict
   }];
 
+  let builders = [
+    OpBuilder<(ins "mlir::Type":$result, "mlir::Value":$src), [{
+      build($_builder, $_state, result, src, cir::FenvAttr{});
+    }]>
+  ];
+
   let llvmOp = llvmOpName;
 }
 
@@ -7425,18 +7432,27 @@ def CIR_ModfOp : CIR_Op<"modf", [Pure]> {
 }
 
 class CIR_TernaryFPToFPBuiltinOp<string mnemonic, string llvmOpName>
-    : CIR_Op<mnemonic, [Pure, SameOperandsAndResultType]>
+    : CIR_Op<mnemonic,
+             !listconcat([SameOperandsAndResultType], CIR_FenvOpTraits)>
 {
-  let arguments = (ins 
+  let arguments = (ins
     CIR_AnyFloatOrVecOfFloatType:$a,
     CIR_AnyFloatOrVecOfFloatType:$b,
-    CIR_AnyFloatOrVecOfFloatType:$c
+    CIR_AnyFloatOrVecOfFloatType:$c,
+    OptionalAttr<CIR_FenvAttr>:$fenv
   );
-  
+
   let results = (outs CIR_AnyFloatOrVecOfFloatType:$result);
 
   let assemblyFormat = "$a `,` $b `,` $c `:` type($a) attr-dict";
 
+  let builders = [
+    OpBuilder<(ins "mlir::Type":$result, "mlir::Value":$a, "mlir::Value":$b,
+                   "mlir::Value":$c), [{
+      build($_builder, $_state, result, a, b, c, cir::FenvAttr{});
+    }]>
+  ];
+
   let llvmOp = llvmOpName;
 }
 
diff --git a/clang/test/CIR/IR/fenv.cir b/clang/test/CIR/IR/fenv.cir
index fad82abdb43dc..d6817484b4feb 100644
--- a/clang/test/CIR/IR/fenv.cir
+++ b/clang/test/CIR/IR/fenv.cir
@@ -66,3 +66,27 @@ cir.func @binary_fp_builtin_fenv(%a: !cir.float, %b: 
!cir.float) {
   %2 = cir.atan2 %a, %b : !cir.float
   cir.return
 }
+
+// CHECK-LABEL: cir.func @unary_fp_to_int_builtin_fenv
+cir.func @unary_fp_to_int_builtin_fenv(%a: !cir.float) -> !s32i {
+  // CHECK: cir.lround %{{.*}} : !cir.float -> !s32i {fenv = 
#cir.fenv<dynamic_rounding_mode = tonearest>}
+  %0 = cir.lround %a : !cir.float -> !s32i {fenv = 
#cir.fenv<dynamic_rounding_mode = tonearest>}
+  // CHECK: cir.llround %{{.*}} : !cir.float -> !s32i {fenv = 
#cir.fenv<except_mode = unmasked>}
+  %1 = cir.llround %a : !cir.float -> !s32i {fenv = #cir.fenv<except_mode = 
unmasked>}
+  // CHECK: cir.lrint %{{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<>}
+  %2 = cir.lrint %a : !cir.float -> !s32i {fenv = #cir.fenv<>}
+  // CHECK: cir.llrint %{{.*}} : !cir.float -> !s32i
+  // CHECK-NOT: fenv
+  %3 = cir.llrint %a : !cir.float -> !s32i
+  cir.return %3 : !s32i
+}
+
+// CHECK-LABEL: cir.func @ternary_fp_builtin_fenv
+cir.func @ternary_fp_builtin_fenv(%a: !cir.float, %b: !cir.float, %c: 
!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
+  cir.return
+}
diff --git a/clang/unittests/CIR/FenvOpTest.cpp 
b/clang/unittests/CIR/FenvOpTest.cpp
index 6a3a89b264e14..2588203971c7c 100644
--- a/clang/unittests/CIR/FenvOpTest.cpp
+++ b/clang/unittests/CIR/FenvOpTest.cpp
@@ -63,11 +63,16 @@ class CIRFenvOpTest : public ::testing::Test {
 
 TEST_F(CIRFenvOpTest, MemoryEffects) {
   OwningOpRef<ModuleOp> module = parse(R"CIR(
-    cir.func @f(%a: !cir.float, %b: !cir.float) {
+    !s32i = !cir.int<s, 32>
+    cir.func @f(%a: !cir.float, %b: !cir.float, %c: !cir.float) {
       %0 = cir.fadd %a, %b : !cir.float
       %1 = cir.fadd %a, %b : !cir.float {fenv = #cir.fenv<>}
       %2 = cir.sqrt %a : !cir.float {fenv = #cir.fenv<>}
       %3 = cir.pow %a, %b : !cir.float {fenv = #cir.fenv<>}
+      %4 = cir.fma %a, %b, %c : !cir.float
+      %5 = cir.fma %a, %b, %c : !cir.float {fenv = #cir.fenv<>}
+      %6 = cir.lround %a : !cir.float -> !s32i
+      %7 = cir.lround %a : !cir.float -> !s32i {fenv = #cir.fenv<>}
       cir.return
     }
   )CIR");
@@ -87,6 +92,20 @@ TEST_F(CIRFenvOpTest, MemoryEffects) {
   SmallVector<cir::PowOp> powOps = findOps<cir::PowOp>(*module);
   ASSERT_EQ(powOps.size(), 1u);
   expectFenvReadAndWrite(powOps[0]);
+
+  SmallVector<cir::FMAOp> fmaOps = findOps<cir::FMAOp>(*module);
+  ASSERT_EQ(fmaOps.size(), 2u);
+  EXPECT_TRUE(getEffects(fmaOps[0]).empty());
+  EXPECT_TRUE(isMemoryEffectFree(fmaOps[0]));
+  expectFenvReadAndWrite(fmaOps[1]);
+  EXPECT_FALSE(isMemoryEffectFree(fmaOps[1]));
+
+  SmallVector<cir::LroundOp> lroundOps = findOps<cir::LroundOp>(*module);
+  ASSERT_EQ(lroundOps.size(), 2u);
+  EXPECT_TRUE(getEffects(lroundOps[0]).empty());
+  EXPECT_TRUE(isMemoryEffectFree(lroundOps[0]));
+  expectFenvReadAndWrite(lroundOps[1]);
+  EXPECT_FALSE(isMemoryEffectFree(lroundOps[1]));
 }
 
 TEST_F(CIRFenvOpTest, Speculatability) {

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

Reply via email to