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
