[clang] [CIR] Attach FenvAttr when strictfp mode is in effect (PR #213368)

Andy Kaylor via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 31 14:54:35 PDT 2026


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

This change adds tracking of floating-point constraints via the CIRGenFPOptionsRAII object, deriving the state from the FP features in effect tracking in the Clang AST. When we are about to generate an operation that may require floating point constraints, a CIRGenFPOptionsRAII object is used to get the effective floating-point state from the expression for which we are generating the operations. This object in turn sets the floating-point state of the CIRGenBuilder which uses these settings to determine whether a cir::FenvAttr should be attached to generated objects and, if so, what its state should be.

This does not cover complex operations, AArch64 builtins, or global constructors. Those will be updated in follow-up changes.

Assisted-by: Cursor / various models

>From b628152f487849a59750fa41a2a45a82eeaadd0f Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Tue, 26 May 2026 15:07:35 -0700
Subject: [PATCH] [CIR] Attach FenvAttr when strictfp mode is in effect

This change adds tracking of floating-point constraints via the
CIRGenFPOptionsRAII object, deriving the state from the FP features
in effect tracking in the Clang AST. When we are about to generate an
operation that may require floating point constraints, a
CIRGenFPOptionsRAII object is used to get the effective floating-point
state from the expression for which we are generating the operations.
This object in turn sets the floating-point state of the CIRGenBuilder
which uses these settings to determine whether a cir::FenvAttr
should be attached to generated objects and, if so, what its state should
be.

This does not cover complex operations, AArch64 builtins, or global
constructors. Those will be updated in follow-up changes.

Assisted-by: Cursor / various models
---
 .../CIR/Dialect/Builder/CIRBaseBuilder.h      |  126 +-
 .../clang/CIR/Dialect/IR/CIRDialect.td        |    1 +
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |    1 +
 clang/lib/CIR/CodeGen/CIRGenBuilder.h         |   45 +-
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       |   32 +-
 clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp    |    3 +-
 clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp    |   30 +-
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp      |   59 +-
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |   29 +-
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |   12 +
 clang/test/CIR/CodeGen/pragma-fenv_access.c   | 1716 +++++++++++++++++
 clang/test/CIR/Lowering/fenv.cir              |   15 +-
 clang/test/CIR/Lowering/strictfp.cir          |   28 +
 13 files changed, 1976 insertions(+), 121 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/pragma-fenv_access.c
 create mode 100644 clang/test/CIR/Lowering/strictfp.cir

diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
index fbbf54314191c..45cb18a50eeee 100644
--- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
+++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h
@@ -11,6 +11,7 @@
 
 #include "clang/AST/CharUnits.h"
 #include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/LangOptions.h"
 #include "clang/CIR/Dialect/IR/CIRAttrs.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
@@ -68,6 +69,12 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
       : mlir::OpBuilder(&mlirContext) {}
   CIRBaseBuilderTy(mlir::OpBuilder &builder) : mlir::OpBuilder(builder) {}
 
+  bool isFPConstrained = false;
+  clang::LangOptions::FPExceptionModeKind defaultConstrainedExcept =
+      clang::LangOptions::FPE_Ignore;
+  llvm::RoundingMode defaultConstrainedRounding =
+      llvm::RoundingMode::NearestTiesToEven;
+
   mlir::Value getConstAPInt(mlir::Location loc, mlir::Type typ,
                             const llvm::APInt &val) {
     return cir::ConstantOp::create(*this, loc, cir::IntAttr::get(typ, val));
@@ -203,6 +210,96 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
   cir::BoolAttr getTrueAttr() { return getCIRBoolAttr(true); }
   cir::BoolAttr getFalseAttr() { return getCIRBoolAttr(false); }
 
+  //
+  // Floating point specific helpers
+  // -------------------------------
+  //
+
+  /// Enable/Disable use of constrained floating point math. When enabled the
+  /// CreateF<op>() calls instead create constrained floating point intrinsic
+  /// calls. Fast math flags are unaffected by this setting.
+  void setIsFPConstrained(bool isCon) { isFPConstrained = isCon; }
+
+  /// Query for the use of constrained floating point math
+  bool getIsFPConstrained() const { return isFPConstrained; }
+
+  /// Set the exception handling to be used with constrained floating point
+  void setDefaultConstrainedExcept(
+      clang::LangOptions::FPExceptionModeKind newExcept) {
+    defaultConstrainedExcept = newExcept;
+  }
+
+  /// Get the exception handling used with constrained floating point
+  clang::LangOptions::FPExceptionModeKind getDefaultConstrainedExcept() const {
+    return defaultConstrainedExcept;
+  }
+
+  /// Set the rounding mode handling to be used with constrained floating point
+  void setDefaultConstrainedRounding(llvm::RoundingMode newRounding) {
+    defaultConstrainedRounding = newRounding;
+  }
+
+  /// Get the rounding mode handling used with constrained floating point
+  llvm::RoundingMode getDefaultConstrainedRounding() const {
+    return defaultConstrainedRounding;
+  }
+
+  /// Build the `#cir.fenv` attribute describing the constrained floating-point
+  /// environment currently in effect. This is attached to floating-point
+  /// operations that support it to capture the rounding and exception
+  /// behavior. Returns a null attribute when constrained floating-point is not
+  /// enabled, in which case no attribute should be attached.
+  cir::FenvAttr getConstrainedFPAttr() {
+    if (!isFPConstrained)
+      return {};
+
+    cir::FPDynamicRoundingMode roundingMode;
+    switch (defaultConstrainedRounding) {
+    case llvm::RoundingMode::NearestTiesToEven:
+      roundingMode = cir::FPDynamicRoundingMode::ToNearest;
+      break;
+    case llvm::RoundingMode::TowardNegative:
+      roundingMode = cir::FPDynamicRoundingMode::Downward;
+      break;
+    case llvm::RoundingMode::TowardPositive:
+      roundingMode = cir::FPDynamicRoundingMode::Upward;
+      break;
+    case llvm::RoundingMode::TowardZero:
+      roundingMode = cir::FPDynamicRoundingMode::UpwardZero;
+      break;
+    case llvm::RoundingMode::NearestTiesToAway:
+      roundingMode = cir::FPDynamicRoundingMode::ToNearestAway;
+      break;
+    case llvm::RoundingMode::Dynamic:
+      roundingMode = cir::FPDynamicRoundingMode::Unknown;
+      break;
+    default:
+      llvm_unreachable("unexpected constrained rounding mode");
+    }
+
+    cir::FPExceptionMode exceptMode;
+    bool strictExcept;
+    switch (defaultConstrainedExcept) {
+    case clang::LangOptions::FPE_Ignore:
+      exceptMode = cir::FPExceptionMode::Masked;
+      strictExcept = false;
+      break;
+    case clang::LangOptions::FPE_MayTrap:
+      exceptMode = cir::FPExceptionMode::Unknown;
+      strictExcept = false;
+      break;
+    case clang::LangOptions::FPE_Strict:
+      exceptMode = cir::FPExceptionMode::Unknown;
+      strictExcept = true;
+      break;
+    default:
+      llvm_unreachable("unexpected constrained exception mode");
+    }
+
+    return cir::FenvAttr::get(getContext(), roundingMode, exceptMode,
+                              mlir::BoolAttr::get(getContext(), strictExcept));
+  }
+
   mlir::Value createComplexCreate(mlir::Location loc, mlir::Value real,
                                   mlir::Value imag) {
     auto resultComplexTy = cir::ComplexType::get(real.getType());
@@ -744,45 +841,41 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
 
   mlir::Value createFAdd(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
     assert(!cir::MissingFeatures::metaDataNode());
-    assert(!cir::MissingFeatures::fpConstraints());
     assert(!cir::MissingFeatures::fastMathFlags());
-    return cir::FAddOp::create(*this, loc, lhs, rhs);
+    return cir::FAddOp::create(*this, loc, lhs, rhs, getConstrainedFPAttr());
   }
 
   mlir::Value createFSub(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
     assert(!cir::MissingFeatures::metaDataNode());
-    assert(!cir::MissingFeatures::fpConstraints());
     assert(!cir::MissingFeatures::fastMathFlags());
-    return cir::FSubOp::create(*this, loc, lhs, rhs);
+    return cir::FSubOp::create(*this, loc, lhs, rhs, getConstrainedFPAttr());
   }
 
   mlir::Value createFMul(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
     assert(!cir::MissingFeatures::metaDataNode());
-    assert(!cir::MissingFeatures::fpConstraints());
     assert(!cir::MissingFeatures::fastMathFlags());
-    return cir::FMulOp::create(*this, loc, lhs, rhs);
+    return cir::FMulOp::create(*this, loc, lhs, rhs, getConstrainedFPAttr());
   }
 
   mlir::Value createFDiv(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
     assert(!cir::MissingFeatures::metaDataNode());
-    assert(!cir::MissingFeatures::fpConstraints());
     assert(!cir::MissingFeatures::fastMathFlags());
-    return cir::FDivOp::create(*this, loc, lhs, rhs);
+    return cir::FDivOp::create(*this, loc, lhs, rhs, getConstrainedFPAttr());
   }
 
   mlir::Value createFRem(mlir::Location loc, mlir::Value lhs, mlir::Value rhs) {
     assert(!cir::MissingFeatures::metaDataNode());
-    assert(!cir::MissingFeatures::fpConstraints());
     assert(!cir::MissingFeatures::fastMathFlags());
-    return cir::FRemOp::create(*this, loc, lhs, rhs);
+    return cir::FRemOp::create(*this, loc, lhs, rhs, getConstrainedFPAttr());
   }
 
   mlir::Value createFNeg(mlir::Location loc, mlir::Value operand) {
     assert(cir::isFPOrVectorOfFPType(operand.getType()) &&
            "expected floating-point or vector-of-float type");
     assert(!cir::MissingFeatures::metaDataNode());
-    assert(!cir::MissingFeatures::fpConstraints());
     assert(!cir::MissingFeatures::fastMathFlags());
+    // fneg does not raise FP exceptions or depend on the rounding mode, so it
+    // never carries an fenv attribute.
     return cir::FNegOp::create(*this, loc, operand);
   }
 
@@ -796,7 +889,10 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
 
   cir::CmpOp createCompare(mlir::Location loc, cir::CmpOpKind kind,
                            mlir::Value lhs, mlir::Value rhs) {
-    return cir::CmpOp::create(*this, loc, kind, lhs, rhs);
+    cir::FenvAttr fenv;
+    if (cir::isAnyFloatingPointType(lhs.getType()))
+      fenv = getConstrainedFPAttr();
+    return cir::CmpOp::create(*this, loc, kind, lhs, rhs, fenv);
   }
 
   cir::VecCmpOp createVecCompare(mlir::Location loc, cir::CmpOpKind kind,
@@ -806,7 +902,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
         getSIntNTy(getCIRIntOrFloatBitWidth(vecCast.getElementType()));
     VectorType integralVecTy =
         cir::VectorType::get(integralTy, vecCast.getSize());
-    return cir::VecCmpOp::create(*this, loc, integralVecTy, kind, lhs, rhs);
+    cir::FenvAttr fenv;
+    if (cir::isFPOrVectorOfFPType(lhs.getType()))
+      fenv = getConstrainedFPAttr();
+    return cir::VecCmpOp::create(*this, loc, integralVecTy, kind, lhs, rhs,
+                                 fenv);
   }
 
   mlir::Value createIsNaN(mlir::Location loc, mlir::Value operand) {
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index d340a9061310f..de90fed45f170 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -44,6 +44,7 @@ def CIR_Dialect : Dialect {
     static llvm::StringRef getReturnsTwiceAttrName() { return "returns_twice"; }
     static llvm::StringRef getColdAttrName() { return "cold"; }
     static llvm::StringRef getHotAttrName() { return "hot"; }
+    static llvm::StringRef getStrictFPAttrName() { return "strictfp"; }
     static llvm::StringRef getNoDuplicatesAttrName() { return "noduplicate"; }
     static llvm::StringRef getConvergentAttrName() { return "convergent"; }
     static llvm::StringRef getNoUnwindAttrName() { return "nounwind"; }
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 591b5dc9acf1c..ba8011e03f638 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -7619,6 +7619,7 @@ class CIR_TernaryFPToFPBuiltinOp<string mnemonic, string llvmOpName>
   ];
 
   let llvmOp = llvmOpName;
+  let constrainedLLVMIntrinsic = mnemonic;
 }
 
 def CIR_FMAOp : CIR_TernaryFPToFPBuiltinOp<"fma", "FMAOp"> {
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 074233050bee7..c906e65a132c2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -30,9 +30,6 @@ namespace clang::CIRGen {
 
 class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
   const CIRGenTypeCache &typeCache;
-  bool isFPConstrained = false;
-  llvm::fp::ExceptionBehavior defaultConstrainedExcept = llvm::fp::ebStrict;
-  llvm::RoundingMode defaultConstrainedRounding = llvm::RoundingMode::Dynamic;
 
   llvm::StringMap<unsigned> recordNames;
   llvm::StringMap<unsigned> globalsVersioning;
@@ -120,43 +117,6 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
     return baseName + "." + std::to_string(recordNames[baseName]++);
   }
 
-  //
-  // Floating point specific helpers
-  // -------------------------------
-  //
-
-  /// Enable/Disable use of constrained floating point math. When enabled the
-  /// CreateF<op>() calls instead create constrained floating point intrinsic
-  /// calls. Fast math flags are unaffected by this setting.
-  void setIsFPConstrained(bool isCon) { isFPConstrained = isCon; }
-
-  /// Query for the use of constrained floating point math
-  bool getIsFPConstrained() const { return isFPConstrained; }
-
-  /// Set the exception handling to be used with constrained floating point
-  void setDefaultConstrainedExcept(llvm::fp::ExceptionBehavior newExcept) {
-    assert(llvm::convertExceptionBehaviorToStr(newExcept) &&
-           "Garbage strict exception behavior!");
-    defaultConstrainedExcept = newExcept;
-  }
-
-  /// Get the exception handling used with constrained floating point
-  llvm::fp::ExceptionBehavior getDefaultConstrainedExcept() const {
-    return defaultConstrainedExcept;
-  }
-
-  /// Set the rounding mode handling to be used with constrained floating point
-  void setDefaultConstrainedRounding(llvm::RoundingMode newRounding) {
-    assert(llvm::convertRoundingModeToStr(newRounding) &&
-           "Garbage strict rounding mode!");
-    defaultConstrainedRounding = newRounding;
-  }
-
-  /// Get the rounding mode handling used with constrained floating point
-  llvm::RoundingMode getDefaultConstrainedRounding() const {
-    return defaultConstrainedRounding;
-  }
-
   cir::LongDoubleType getLongDoubleTy(const llvm::fltSemantics &format) const {
     if (&format == &llvm::APFloat::IEEEdouble())
       return cir::LongDoubleType::get(getContext(), typeCache.doubleTy);
@@ -497,10 +457,9 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
   // TODO: split this to createFPExt/createFPTrunc when we have dedicated cast
   // operations.
   mlir::Value createFloatingCast(mlir::Value v, mlir::Type destType) {
-    assert(!cir::MissingFeatures::fpConstraints());
-
     return cir::CastOp::create(*this, v.getLoc(), destType,
-                               cir::CastKind::floating, v);
+                               cir::CastKind::floating, v,
+                               getConstrainedFPAttr());
   }
 
   mlir::Value createDynCast(mlir::Location loc, mlir::Value src,
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 874f5188ae009..beb3082f48537 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -356,10 +356,9 @@ static RValue emitUnaryMaybeConstrainedFPBuiltin(CIRGenFunction &cgf,
   mlir::Value arg = cgf.emitScalarExpr(e.getArg(0));
 
   CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, &e);
-  assert(!cir::MissingFeatures::fpConstraints());
 
-  auto call =
-      Operation::create(cgf.getBuilder(), arg.getLoc(), arg.getType(), arg);
+  auto call = Operation::create(cgf.getBuilder(), arg.getLoc(), arg.getType(),
+                                arg, cgf.getBuilder().getConstrainedFPAttr());
   return RValue::get(call->getResult(0));
 }
 
@@ -377,9 +376,10 @@ static RValue emitUnaryMaybeConstrainedFPToIntBuiltin(CIRGenFunction &cgf,
   mlir::Type resultType = cgf.convertType(e.getType());
   mlir::Value src = cgf.emitScalarExpr(e.getArg(0));
 
-  assert(!cir::MissingFeatures::fpConstraints());
+  CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, &e);
 
-  auto call = Op::create(cgf.getBuilder(), src.getLoc(), resultType, src);
+  auto call = Op::create(cgf.getBuilder(), src.getLoc(), resultType, src,
+                         cgf.getBuilder().getConstrainedFPAttr());
   return RValue::get(call->getResult(0));
 }
 
@@ -398,6 +398,8 @@ static RValue emitBinaryFPBuiltin(CIRGenFunction &cgf, const CallExpr &e) {
 template <typename Op>
 static RValue emitTernaryMaybeConstrainedFPBuiltin(CIRGenFunction &cgf,
                                                    const CallExpr &e) {
+  CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, &e);
+
   mlir::Value arg0 = cgf.emitScalarExpr(e.getArg(0));
   mlir::Value arg1 = cgf.emitScalarExpr(e.getArg(1));
   mlir::Value arg2 = cgf.emitScalarExpr(e.getArg(2));
@@ -405,9 +407,8 @@ static RValue emitTernaryMaybeConstrainedFPBuiltin(CIRGenFunction &cgf,
   mlir::Location loc = cgf.getLoc(e.getExprLoc());
   mlir::Type ty = cgf.convertType(e.getType());
 
-  assert(!cir::MissingFeatures::fpConstraints());
-
-  auto call = Op::create(cgf.getBuilder(), loc, ty, arg0, arg1, arg2);
+  auto call = Op::create(cgf.getBuilder(), loc, ty, arg0, arg1, arg2,
+                         cgf.getBuilder().getConstrainedFPAttr());
   return RValue::get(call->getResult(0));
 }
 
@@ -417,12 +418,13 @@ static mlir::Value emitBinaryMaybeConstrainedFPBuiltin(CIRGenFunction &cgf,
   mlir::Value arg0 = cgf.emitScalarExpr(e.getArg(0));
   mlir::Value arg1 = cgf.emitScalarExpr(e.getArg(1));
 
+  CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, &e);
+
   mlir::Location loc = cgf.getLoc(e.getExprLoc());
   mlir::Type ty = cgf.convertType(e.getType());
 
-  assert(!cir::MissingFeatures::fpConstraints());
-
-  auto call = Op::create(cgf.getBuilder(), loc, ty, arg0, arg1);
+  auto call = Op::create(cgf.getBuilder(), loc, ty, arg0, arg1,
+                         cgf.getBuilder().getConstrainedFPAttr());
   return call->getResult(0);
 }
 
@@ -1587,7 +1589,6 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
   case Builtin::BI__builtin_isnan: {
     CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
     mlir::Value v = emitScalarExpr(e->getArg(0));
-    assert(!cir::MissingFeatures::fpConstraints());
     mlir::Location loc = getLoc(e->getBeginLoc());
     return RValue::get(builder.createBoolToInt(
         builder.createIsFPClass(loc, v, cir::FPClassTest::Nan),
@@ -1606,7 +1607,6 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
   case Builtin::BI__builtin_isinf: {
     CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
     mlir::Value v = emitScalarExpr(e->getArg(0));
-    assert(!cir::MissingFeatures::fpConstraints());
     mlir::Location loc = getLoc(e->getBeginLoc());
     return RValue::get(builder.createBoolToInt(
         builder.createIsFPClass(loc, v, cir::FPClassTest::Infinity),
@@ -1619,9 +1619,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
   case Builtin::BIfinitel:
   case Builtin::BI__finitel:
   case Builtin::BI__builtin_isfinite: {
-    CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
     mlir::Value v = emitScalarExpr(e->getArg(0));
-    assert(!cir::MissingFeatures::fpConstraints());
     mlir::Location loc = getLoc(e->getBeginLoc());
     return RValue::get(builder.createBoolToInt(
         builder.createIsFPClass(loc, v, cir::FPClassTest::Finite),
@@ -1629,7 +1627,6 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
   }
 
   case Builtin::BI__builtin_isnormal: {
-    CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
     mlir::Value v = emitScalarExpr(e->getArg(0));
     mlir::Location loc = getLoc(e->getBeginLoc());
     return RValue::get(builder.createBoolToInt(
@@ -1638,7 +1635,6 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
   }
 
   case Builtin::BI__builtin_issubnormal: {
-    CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
     mlir::Value v = emitScalarExpr(e->getArg(0));
     mlir::Location loc = getLoc(e->getBeginLoc());
     return RValue::get(builder.createBoolToInt(
@@ -1647,7 +1643,6 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
   }
 
   case Builtin::BI__builtin_iszero: {
-    CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e);
     mlir::Value v = emitScalarExpr(e->getArg(0));
     mlir::Location loc = getLoc(e->getBeginLoc());
     return RValue::get(builder.createBoolToInt(
@@ -1663,7 +1658,6 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
     mlir::Value v = emitScalarExpr(e->getArg(0));
     uint64_t test = result.Val.getInt().getLimitedValue();
     mlir::Location loc = getLoc(e->getBeginLoc());
-    //
     return RValue::get(builder.createBoolToInt(
         builder.createIsFPClass(loc, v, cir::FPClassTest(test)),
         convertType(e->getType())));
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
index 9c98f4bc55daa..9228367fdd44f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
@@ -58,11 +58,10 @@ static mlir::Value emitVectorFCmp(CIRGenFunction &cgf, const CallExpr &expr,
                                   llvm::SmallVector<mlir::Value> &ops,
                                   cir::CmpOpKind pred, bool shouldInvert) {
   CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, &expr);
-  // TODO(cir): Add isSignaling boolean once emitConstrainedFPCall implemented
-  assert(!cir::MissingFeatures::emitConstrainedFPCall());
   clang::CIRGen::CIRGenBuilderTy &builder = cgf.getBuilder();
   mlir::Value cmp = builder.createVecCompare(cgf.getLoc(expr.getExprLoc()),
                                              pred, ops[0], ops[1]);
+  // TODO(cir): Add dedicated predicates to avoid the need to invert this.
   mlir::Value bitCast = builder.createBitcast(
       shouldInvert ? builder.createNot(cmp) : cmp, ops[0].getType());
   return bitCast;
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 7ed01ecdf27ff..8d660a0a2c721 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -522,32 +522,40 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
 
     std::optional<cir::CastKind> castKind;
 
+    // Start with a null fenv attr. If this is a floating point cast, we will
+    // get the attribute from the builder.
+    cir::FenvAttr fenvAttr;
+
     if (mlir::isa<cir::BoolType>(srcTy)) {
       if (opts.treatBooleanAsSigned)
         cgf.getCIRGenModule().errorNYI("signed bool");
-      if (cgf.getBuilder().isInt(dstTy))
+      if (cgf.getBuilder().isInt(dstTy)) {
         castKind = cir::CastKind::bool_to_int;
-      else if (mlir::isa<cir::FPTypeInterface>(dstTy))
+      } else if (mlir::isa<cir::FPTypeInterface>(dstTy)) {
+        fenvAttr = cgf.getBuilder().getConstrainedFPAttr();
         castKind = cir::CastKind::bool_to_float;
-      else
+      } else {
         llvm_unreachable("Internal error: Cast to unexpected type");
+      }
     } else if (cgf.getBuilder().isInt(srcTy)) {
-      if (cgf.getBuilder().isInt(dstTy))
+      if (cgf.getBuilder().isInt(dstTy)) {
         castKind = cir::CastKind::integral;
-      else if (mlir::isa<cir::FPTypeInterface>(dstTy))
+      } else if (mlir::isa<cir::FPTypeInterface>(dstTy)) {
+        fenvAttr = cgf.getBuilder().getConstrainedFPAttr();
         castKind = cir::CastKind::int_to_float;
-      else if (mlir::isa<cir::BoolType>(dstTy))
+      } else if (mlir::isa<cir::BoolType>(dstTy)) {
         castKind = cir::CastKind::int_to_bool;
-      else
+      } else {
         llvm_unreachable("Internal error: Cast to unexpected type");
+      }
     } else if (mlir::isa<cir::FPTypeInterface>(srcTy)) {
+      fenvAttr = cgf.getBuilder().getConstrainedFPAttr();
       if (cgf.getBuilder().isInt(dstTy)) {
         // If we can't recognize overflow as undefined behavior, assume that
         // overflow saturates. This protects against normal optimizations if we
         // are compiling with non-standard FP semantics.
         if (!cgf.cgm.getCodeGenOpts().StrictFloatCastOverflow)
           cgf.getCIRGenModule().errorNYI("strict float cast overflow");
-        assert(!cir::MissingFeatures::fpConstraints());
         castKind = cir::CastKind::float_to_int;
       } else if (mlir::isa<cir::FPTypeInterface>(dstTy)) {
         // TODO: split this to createFPExt/createFPTrunc
@@ -563,7 +571,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
 
     assert(castKind.has_value() && "Internal error: CastKind not set.");
     return builder.createOrFold<cir::CastOp>(src.getLoc(), fullDstTy, *castKind,
-                                             src);
+                                             src, fenvAttr);
   }
 
   mlir::Value
@@ -1059,8 +1067,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
       result.compType = vecType->getElementType();
     result.opcode = e->getOpcode();
     result.loc = e->getSourceRange();
-    // TODO(cir): Result.FPFeatures
-    CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, e);
+    result.fpFeatures = e->getFPFeaturesInEffect(cgf.getLangOpts());
     result.e = e;
     return result;
   }
@@ -2192,6 +2199,7 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
   Expr *subExpr = ce->getSubExpr();
   QualType destTy = ce->getType();
   CastKind kind = ce->getCastKind();
+  CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(cgf, ce);
 
   // These cases are generally not written to ignore the result of evaluating
   // their sub-expressions, so we clear this now.
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 16e66b143d232..66e7b6d5061df 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -30,7 +30,8 @@ namespace clang::CIRGen {
 
 CIRGenFunction::CIRGenFunction(CIRGenModule &cgm, CIRGenBuilderTy &builder,
                                bool suppressNewContext)
-    : CIRGenTypeCache(cgm), cgm{cgm}, builder(builder) {
+    : CIRGenTypeCache(cgm), cgm{cgm}, builder(builder),
+      curFPFeatures(cgm.getLangOpts()) {
   ehStack.setCGF(this);
 }
 
@@ -484,6 +485,24 @@ void CIRGenFunction::startFunction(GlobalDecl gd, QualType returnType,
   const auto *fd = dyn_cast_or_null<FunctionDecl>(d);
   curFuncDecl = (d ? d->getNonClosureContext() : nullptr);
 
+  // This is an artifact of the legacy handling of constrained floating-point
+  // modes. The rounding mode and exception behavior tracked in
+  // clang::LangOptions don't correspond directly to the representation we
+  // use in CIR, but the CIR settings can be derived from them. We track the
+  // default state using the legacy settings because it keeps the tracking in
+  // sync with classic codegen.
+  llvm::RoundingMode rm = getLangOpts().getDefaultRoundingMode();
+  LangOptions::FPExceptionModeKind eb = getLangOpts().getDefaultExceptionMode();
+  builder.setDefaultConstrainedRounding(rm);
+  builder.setDefaultConstrainedExcept(eb);
+  builder.setIsFPConstrained(false);
+  if ((fd && (fd->UsesFPIntrin() || fd->hasAttr<StrictFPAttr>())) ||
+      (!fd && (eb != LangOptions::FPExceptionModeKind::FPE_Ignore ||
+               rm != llvm::RoundingMode::NearestTiesToEven))) {
+    builder.setIsFPConstrained(true);
+    fn->setAttr(cir::CIRDialect::getStrictFPAttrName(),
+                mlir::UnitAttr::get(fn.getContext()));
+  }
   prologueCleanupDepth = ehStack.stable_begin();
 
   mlir::Block *entryBB = &fn.getBlocks().front();
@@ -721,10 +740,6 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
 
     // Emit the standard function prologue.
     startFunction(gd, retTy, fn, funcType, args, loc, bodyRange.getBegin());
-    if (funcDecl->UsesFPIntrin() || funcDecl->hasAttr<StrictFPAttr>()) {
-      cgm.errorNYI(loc, "STDC FENV_ACCESS");
-      return fn;
-    }
 
     // Save parameters for coroutine function.
     if (body && isa_and_nonnull<CoroutineBodyStmt>(body))
@@ -963,23 +978,6 @@ LValue CIRGenFunction::makeNaturalAlignAddrLValue(mlir::Value val,
   return makeAddrLValue(addr, ty, baseInfo);
 }
 
-// Map the LangOption for exception behavior into the corresponding enum in
-// the IR.
-static llvm::fp::ExceptionBehavior
-toConstrainedExceptMd(LangOptions::FPExceptionModeKind kind) {
-  switch (kind) {
-  case LangOptions::FPE_Ignore:
-    return llvm::fp::ebIgnore;
-  case LangOptions::FPE_MayTrap:
-    return llvm::fp::ebMayTrap;
-  case LangOptions::FPE_Strict:
-    return llvm::fp::ebStrict;
-  case LangOptions::FPE_Default:
-    llvm_unreachable("expected explicitly initialized exception behavior");
-  }
-  llvm_unreachable("unsupported FP exception behavior");
-}
-
 clang::QualType CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd,
                                                      FunctionArgList &args) {
   const auto *fd = cast<FunctionDecl>(gd.getDecl());
@@ -1389,13 +1387,12 @@ void CIRGenFunction::CIRGenFPOptionsRAII::ConstructorHelper(
   // TODO(cir): create guard to restore fast math configurations.
   assert(!cir::MissingFeatures::fastMathGuard());
 
-  [[maybe_unused]] llvm::RoundingMode newRoundingBehavior =
-      fpFeatures.getRoundingMode();
-  // TODO(cir): override rounding behaviour once FM configs are guarded.
-  [[maybe_unused]] llvm::fp::ExceptionBehavior newExceptionBehavior =
-      toConstrainedExceptMd(static_cast<LangOptions::FPExceptionModeKind>(
-          fpFeatures.getExceptionMode()));
-  // TODO(cir): override exception behaviour once FM configs are guarded.
+  llvm::RoundingMode newRoundingMode = fpFeatures.getRoundingMode();
+  LangOptions::FPExceptionModeKind newExceptionBehavior =
+      fpFeatures.getExceptionMode();
+
+  cgf.builder.setDefaultConstrainedRounding(newRoundingMode);
+  cgf.builder.setDefaultConstrainedExcept(newExceptionBehavior);
 
   // TODO(cir): override FP flags once FM configs are guarded.
   assert(!cir::MissingFeatures::fastMathFlags());
@@ -1403,8 +1400,8 @@ void CIRGenFunction::CIRGenFPOptionsRAII::ConstructorHelper(
   assert((cgf.curFuncDecl == nullptr || cgf.builder.getIsFPConstrained() ||
           isa<CXXConstructorDecl>(cgf.curFuncDecl) ||
           isa<CXXDestructorDecl>(cgf.curFuncDecl) ||
-          (newExceptionBehavior == llvm::fp::ebIgnore &&
-           newRoundingBehavior == llvm::RoundingMode::NearestTiesToEven)) &&
+          (newExceptionBehavior == LangOptions::FPE_Ignore &&
+           newRoundingMode == llvm::RoundingMode::NearestTiesToEven)) &&
          "FPConstrained should be enabled on entire function");
 
   // TODO(cir): mark CIR function with fast math attributes.
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 4ba3ee59f49b0..521672206f78f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -63,6 +63,33 @@ class CIRGenFunction : public CIRGenTypeCache {
   /// is where the next operations will be introduced.
   CIRGenBuilderTy &builder;
 
+  /// Saves the builder's constrained floating-point configuration on
+  /// construction and restores it on destruction. The builder is shared
+  /// across all functions in the module, so its constrained-FP state must be
+  /// scoped to each function's emission.
+  ///
+  /// Note that the similarly named CIRGenFunction::CIRGenFPOptionsRAII
+  /// intentionally avoids restoring the "isFPConstrained" state because that
+  /// state is function-wide, but this object does restore the state so that
+  /// any CIRGenFunction instance created while we are in the process of
+  /// emitting another function cannot corrupt the prior functions state.
+  struct ConstrainedFPRAII {
+    CIRGenBuilderTy &builder;
+    bool savedIsFPConstrained;
+    LangOptions::FPExceptionModeKind savedExcept;
+    llvm::RoundingMode savedRounding;
+
+    explicit ConstrainedFPRAII(CIRGenBuilderTy &builder)
+        : builder(builder), savedIsFPConstrained(builder.getIsFPConstrained()),
+          savedExcept(builder.getDefaultConstrainedExcept()),
+          savedRounding(builder.getDefaultConstrainedRounding()) {}
+    ~ConstrainedFPRAII() {
+      builder.setIsFPConstrained(savedIsFPConstrained);
+      builder.setDefaultConstrainedExcept(savedExcept);
+      builder.setDefaultConstrainedRounding(savedRounding);
+    }
+  } constrainedFPState{builder};
+
 public:
   /// The GlobalDecl for the current function being compiled or the global
   /// variable currently being initialized.
@@ -243,7 +270,7 @@ class CIRGenFunction : public CIRGenTypeCache {
     void ConstructorHelper(clang::FPOptions FPFeatures);
     CIRGenFunction &cgf;
     clang::FPOptions oldFPFeatures;
-    llvm::fp::ExceptionBehavior oldExcept;
+    LangOptions::FPExceptionModeKind oldExcept;
     llvm::RoundingMode oldRounding;
   };
   clang::FPOptions curFPFeatures;
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 3660c86378a9c..e9836b9010197 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -509,6 +509,9 @@ static llvm::StringRef getConstrainedRoundingMetadata(cir::FenvAttr fenv) {
 }
 
 static llvm::StringRef getConstrainedExceptMetadata(cir::FenvAttr fenv) {
+  std::optional<cir::FPExceptionMode> exceptMode = fenv.getExceptMode();
+  if (exceptMode && *exceptMode == cir::FPExceptionMode::Masked)
+    return "fpexcept.ignore";
   mlir::BoolAttr strictExcept = fenv.getStrictExcept();
   if (!strictExcept)
     return "fpexcept.ignore";
@@ -2559,6 +2562,7 @@ void CIRToLLVMFuncOpLowering::lowerFuncAttributes(
         attr.getName() == func.getInlineKindAttrName() ||
         attr.getName() == func.getSideEffectAttrName() ||
         attr.getName() == CIRDialect::getNoReturnAttrName() ||
+        attr.getName() == CIRDialect::getStrictFPAttrName() ||
         attr.getName() == func.getAnnotationsAttrName() ||
         (filterArgAndResAttrs &&
          (attr.getName() == func.getArgAttrsAttrName() ||
@@ -2684,6 +2688,14 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
   if (op->hasAttr(CIRDialect::getNoReturnAttrName()))
     fn.setNoreturn(true);
 
+  // The LLVM dialect's LLVMFuncOp has no dedicated field for the `strictfp`
+  // function attribute, so route it through the `passthrough` array. The MLIR
+  // LLVM IR translator forwards `passthrough` entries to LLVM IR as function
+  // attributes.
+  if (op->hasAttr(CIRDialect::getStrictFPAttrName()))
+    fn.setPassthroughAttr(rewriter.getArrayAttr(
+        {rewriter.getStringAttr(CIRDialect::getStrictFPAttrName())}));
+
   if (std::optional<cir::InlineKind> inlineKind = op.getInlineKind()) {
     fn.setNoInline(*inlineKind == cir::InlineKind::NoInline);
     fn.setInlineHint(*inlineKind == cir::InlineKind::InlineHint);
diff --git a/clang/test/CIR/CodeGen/pragma-fenv_access.c b/clang/test/CIR/CodeGen/pragma-fenv_access.c
new file mode 100644
index 0000000000000..cc2eaebdc085e
--- /dev/null
+++ b/clang/test/CIR/CodeGen/pragma-fenv_access.c
@@ -0,0 +1,1716 @@
+// --- STRICT: -ffp-exception-behavior=strict ---
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir \
+// RUN:   -fexperimental-strict-floating-point -ffp-exception-behavior=strict \
+// RUN:   -emit-cir %s -o %t-strict.cir
+// RUN: FileCheck --check-prefixes=CIR,CIR-STRICT --input-file=%t-strict.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir \
+// RUN:   -fexperimental-strict-floating-point -ffp-exception-behavior=strict \
+// RUN:   -emit-llvm %s -o %t-strict-cir.ll
+// RUN: FileCheck --check-prefixes=LLVM,LLVM-STRICT \
+// RUN:   --input-file=%t-strict-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu \
+// RUN:   -fexperimental-strict-floating-point -ffp-exception-behavior=strict \
+// RUN:   -emit-llvm %s -o %t-strict.ll
+// RUN: FileCheck --check-prefixes=LLVM,LLVM-STRICT \
+// RUN:   --input-file=%t-strict.ll %s
+
+// --- STRICT-RND: -frounding-math -ffp-exception-behavior=strict ---
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir \
+// RUN:   -fexperimental-strict-floating-point -frounding-math \
+// RUN:   -ffp-exception-behavior=strict -emit-cir %s -o %t-strict-rnd.cir
+// RUN: FileCheck --check-prefixes=CIR,CIR-STRICT-RND --input-file=%t-strict-rnd.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir \
+// RUN:   -fexperimental-strict-floating-point -frounding-math \
+// RUN:   -ffp-exception-behavior=strict -emit-llvm %s -o %t-strict-rnd-cir.ll
+// RUN: FileCheck --check-prefixes=LLVM,LLVM-STRICT-RND \
+// RUN:   --input-file=%t-strict-rnd-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu \
+// RUN:   -fexperimental-strict-floating-point -frounding-math \
+// RUN:   -ffp-exception-behavior=strict -emit-llvm %s -o %t-strict-rnd.ll
+// RUN: FileCheck --check-prefixes=LLVM,LLVM-STRICT-RND \
+// RUN:   --input-file=%t-strict-rnd.ll %s
+
+// --- DEFAULT: pragma-only constrained FP ---
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir \
+// RUN:   -fexperimental-strict-floating-point -emit-cir %s -o %t-default.cir
+// RUN: FileCheck --check-prefixes=CIR,CIR-DEFAULT --input-file=%t-default.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir \
+// RUN:   -fexperimental-strict-floating-point -emit-llvm %s -o %t-default-cir.ll
+// RUN: FileCheck --check-prefixes=LLVM,LLVM-DEFAULT \
+// RUN:   --input-file=%t-default-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu \
+// RUN:   -fexperimental-strict-floating-point -emit-llvm %s -o %t-default.ll
+// RUN: FileCheck --check-prefixes=LLVM,LLVM-DEFAULT \
+// RUN:   --input-file=%t-default.ll %s
+
+// --- DEFAULT-RND: -frounding-math, pragma-only exceptions ---
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir \
+// RUN:   -fexperimental-strict-floating-point -frounding-math \
+// RUN:   -emit-cir %s -o %t-default-rnd.cir
+// RUN: FileCheck --check-prefixes=CIR,CIR-DEFAULT-RND --input-file=%t-default-rnd.cir %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir \
+// RUN:   -fexperimental-strict-floating-point -frounding-math \
+// RUN:   -emit-llvm %s -o %t-default-rnd-cir.ll
+// RUN: FileCheck --check-prefixes=LLVM,LLVM-DEFAULT-RND \
+// RUN:   --input-file=%t-default-rnd-cir.ll %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu \
+// RUN:   -fexperimental-strict-floating-point -frounding-math \
+// RUN:   -emit-llvm %s -o %t-default-rnd.ll
+// RUN: FileCheck --check-prefixes=LLVM,LLVM-DEFAULT-RND \
+// RUN:   --input-file=%t-default-rnd.ll %s
+
+void test_cmdline_defaults(float x, float y, float z, int i, double d) {
+// CIR-LABEL: cir.func {{.*}}@test_cmdline_defaults(
+// CIR-STRICT-SAME: strictfp
+// CIR-STRICT-RND-SAME: strictfp
+// CIR-DEFAULT-RND-SAME: strictfp
+// CIR-DEFAULT-NOT: strictfp
+// LLVM-LABEL: define {{.*}}@test_cmdline_defaults(
+// LLVM-STRICT-SAME: #[[$STRICT_ATTR:[0-9]+]]
+// LLVM-STRICT-RND-SAME: #[[$STRICT_ATTR:[0-9]+]]
+// LLVM-DEFAULT-RND-SAME: #[[$STRICT_ATTR:[0-9]+]]
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR-STRICT: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fadd {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fadd float
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+  sf = x - y;
+// CIR-STRICT: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fsub {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fsub float
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+  sf = x * y;
+// CIR-STRICT: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fmul {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fmul float
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+  sf = x / y;
+// CIR-STRICT: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fdiv {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fdiv float
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR-STRICT: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cmp lt {{.*}} : !cir.float
+// CIR-DEFAULT-RND: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fcmp olt float
+// LLVM-DEFAULT-RND: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.ignore")
+  sf = (float)i;
+// CIR-STRICT: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cast int_to_float {{.*}} : !s32i -> !cir.float
+// CIR-DEFAULT-RND: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: sitofp i32 {{.*}} to float
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+  si = (int)x;
+// CIR-STRICT: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cast float_to_int {{.*}} : !cir.float -> !s32i
+// CIR-DEFAULT-RND: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fptosi float {{.*}} to i32
+// LLVM-DEFAULT-RND: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.ignore")
+  sd = (double)x;
+// CIR-STRICT: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cast floating {{.*}} : !cir.float -> !cir.double
+// CIR-DEFAULT-RND: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fpext float {{.*}} to double
+// LLVM-DEFAULT-RND: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.ignore")
+  sf = (float)d;
+// CIR-STRICT: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cast floating {{.*}} : !cir.double -> !cir.float
+// CIR-DEFAULT-RND: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fptrunc double {{.*}} to float
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+  sf = __builtin_sqrtf(x);
+// CIR-STRICT: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.sqrt {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.sqrt.f32
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+  sf = __builtin_powf(x, y);
+// CIR-STRICT: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.pow {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.pow.f32
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+  sf = __builtin_fmaf(x, y, z);
+// CIR-STRICT: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fma {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.fma.f32
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+  sl = __builtin_lroundf(x);
+// CIR-STRICT: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.lround {{.*}} : !cir.float -> !s64i
+// CIR-DEFAULT-RND: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call i64 @llvm.lround.i64.f32
+// LLVM-DEFAULT-RND: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.ignore")
+  sf = __builtin_fmodf(x, y);
+// CIR-STRICT: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fmod {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: frem float
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.ignore")
+}
+
+#pragma STDC FENV_ACCESS ON
+
+void test_global_fenv_access_on(float x, float y, float z, int i, double d) {
+// CIR-LABEL: cir.func {{.*}}@test_global_fenv_access_on(
+// LLVM-LABEL: define {{.*}}@test_global_fenv_access_on(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x - y;
+// CIR: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x * y;
+// CIR: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x / y;
+// CIR: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+  sf = (float)i;
+// CIR: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  si = (int)x;
+// CIR: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+  sd = (double)x;
+// CIR: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = (float)d;
+// CIR: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_sqrtf(x);
+// CIR: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_powf(x, y);
+// CIR: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_fmaf(x, y, z);
+// CIR: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sl = __builtin_lroundf(x);
+// CIR: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = __builtin_fmodf(x, y);
+// CIR: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+}
+
+void test_except_off_fenv_access_off(float x, float y, float z, int i, double d) {
+#pragma float_control(except, off)
+#pragma STDC FENV_ACCESS OFF
+// CIR-LABEL: cir.func {{.*}}@test_except_off_fenv_access_off(
+// LLVM-LABEL: define {{.*}}@test_except_off_fenv_access_off(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = x - y;
+// CIR: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = x * y;
+// CIR: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = x / y;
+// CIR: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.ignore")
+  sf = (float)i;
+// CIR: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  si = (int)x;
+// CIR: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.ignore")
+  sd = (double)x;
+// CIR: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.ignore")
+  sf = (float)d;
+// CIR: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = __builtin_sqrtf(x);
+// CIR: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = __builtin_powf(x, y);
+// CIR: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = __builtin_fmaf(x, y, z);
+// CIR: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sl = __builtin_lroundf(x);
+// CIR: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.ignore")
+  sf = __builtin_fmodf(x, y);
+// CIR: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+}
+
+void test_fenv_access_on_after_local_off(float x, float y, float z, int i, double d) {
+// CIR-LABEL: cir.func {{.*}}@test_fenv_access_on_after_local_off(
+// LLVM-LABEL: define {{.*}}@test_fenv_access_on_after_local_off(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x - y;
+// CIR: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x * y;
+// CIR: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x / y;
+// CIR: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+  sf = (float)i;
+// CIR: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  si = (int)x;
+// CIR: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+  sd = (double)x;
+// CIR: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = (float)d;
+// CIR: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_sqrtf(x);
+// CIR: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_powf(x, y);
+// CIR: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_fmaf(x, y, z);
+// CIR: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sl = __builtin_lroundf(x);
+// CIR: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = __builtin_fmodf(x, y);
+// CIR: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+}
+
+#pragma STDC FENV_ACCESS OFF
+
+void test_float_control_except_off(float x, float y, float z, int i, double d) {
+#pragma float_control(except, off)
+// CIR-LABEL: cir.func {{.*}}@test_float_control_except_off(
+// LLVM-LABEL: define {{.*}}@test_float_control_except_off(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR-STRICT: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fadd {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fadd {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fadd float
+// LLVM-DEFAULT-RND: fadd float
+  sf = x - y;
+// CIR-STRICT: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fsub {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fsub {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fsub float
+// LLVM-DEFAULT-RND: fsub float
+  sf = x * y;
+// CIR-STRICT: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fmul {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fmul {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fmul float
+// LLVM-DEFAULT-RND: fmul float
+  sf = x / y;
+// CIR-STRICT: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fdiv {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fdiv {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fdiv float
+// LLVM-DEFAULT-RND: fdiv float
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR-STRICT: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cmp lt {{.*}} : !cir.float
+// CIR-DEFAULT-RND: cir.cmp lt {{.*}} : !cir.float
+// LLVM-STRICT: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fcmp olt float
+// LLVM-DEFAULT-RND: fcmp olt float
+  sf = (float)i;
+// CIR-STRICT: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cast int_to_float {{.*}} : !s32i -> !cir.float
+// CIR-DEFAULT-RND: cir.cast int_to_float {{.*}} : !s32i -> !cir.float
+// LLVM-STRICT: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: sitofp i32 {{.*}} to float
+// LLVM-DEFAULT-RND: sitofp i32 {{.*}} to float
+  si = (int)x;
+// CIR-STRICT: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cast float_to_int {{.*}} : !cir.float -> !s32i
+// CIR-DEFAULT-RND: cir.cast float_to_int {{.*}} : !cir.float -> !s32i
+// LLVM-STRICT: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fptosi float {{.*}} to i32
+// LLVM-DEFAULT-RND: fptosi float {{.*}} to i32
+  sd = (double)x;
+// CIR-STRICT: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cast floating {{.*}} : !cir.float -> !cir.double
+// CIR-DEFAULT-RND: cir.cast floating {{.*}} : !cir.float -> !cir.double
+// LLVM-STRICT: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fpext float {{.*}} to double
+// LLVM-DEFAULT-RND: fpext float {{.*}} to double
+  sf = (float)d;
+// CIR-STRICT: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cast floating {{.*}} : !cir.double -> !cir.float
+// CIR-DEFAULT-RND: cir.cast floating {{.*}} : !cir.double -> !cir.float
+// LLVM-STRICT: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fptrunc double {{.*}} to float
+// LLVM-DEFAULT-RND: fptrunc double {{.*}} to float
+  sf = __builtin_sqrtf(x);
+// CIR-STRICT: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.sqrt {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.sqrt {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call float @llvm.sqrt.f32
+// LLVM-DEFAULT-RND: call float @llvm.sqrt.f32
+  sf = __builtin_powf(x, y);
+// CIR-STRICT: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.pow {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.pow {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call float @llvm.pow.f32
+// LLVM-DEFAULT-RND: call float @llvm.pow.f32
+  sf = __builtin_fmaf(x, y, z);
+// CIR-STRICT: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fma {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fma {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call float @llvm.fma.f32
+// LLVM-DEFAULT-RND: call float @llvm.fma.f32
+  sl = __builtin_lroundf(x);
+// CIR-STRICT: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.lround {{.*}} : !cir.float -> !s64i
+// CIR-DEFAULT-RND: cir.lround {{.*}} : !cir.float -> !s64i
+// LLVM-STRICT: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call i64 @llvm.lround.i64.f32
+// LLVM-DEFAULT-RND: call i64 @llvm.lround.i64.f32
+  sf = __builtin_fmodf(x, y);
+// CIR-STRICT: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fmod {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fmod {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: frem float
+// LLVM-DEFAULT-RND: frem float
+}
+
+void test_float_control_except_on(float x, float y, float z, int i, double d) {
+#pragma float_control(except, on)
+// CIR-LABEL: cir.func {{.*}}@test_float_control_except_on(
+// LLVM-LABEL: define {{.*}}@test_float_control_except_on(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = x - y;
+// CIR: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = x * y;
+// CIR: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = x / y;
+// CIR: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+  sf = (float)i;
+// CIR: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  si = (int)x;
+// CIR: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+  sd = (double)x;
+// CIR: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = (float)d;
+// CIR: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = __builtin_sqrtf(x);
+// CIR: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = __builtin_powf(x, y);
+// CIR: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = __builtin_fmaf(x, y, z);
+// CIR: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sl = __builtin_lroundf(x);
+// CIR: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = __builtin_fmodf(x, y);
+// CIR: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+}
+
+void test_local_fenv_access_on(float x, float y, float z, int i, double d) {
+#pragma STDC FENV_ACCESS ON
+// CIR-LABEL: cir.func {{.*}}@test_local_fenv_access_on(
+// LLVM-LABEL: define {{.*}}@test_local_fenv_access_on(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x - y;
+// CIR: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x * y;
+// CIR: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x / y;
+// CIR: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+  sf = (float)i;
+// CIR: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  si = (int)x;
+// CIR: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+  sd = (double)x;
+// CIR: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = (float)d;
+// CIR: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_sqrtf(x);
+// CIR: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_powf(x, y);
+// CIR: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_fmaf(x, y, z);
+// CIR: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sl = __builtin_lroundf(x);
+// CIR: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = __builtin_fmodf(x, y);
+// CIR: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+}
+
+void test_float_control_except_off_after_on(float x, float y, float z, int i, double d) {
+#pragma float_control(except, off)
+// CIR-LABEL: cir.func {{.*}}@test_float_control_except_off_after_on(
+// LLVM-LABEL: define {{.*}}@test_float_control_except_off_after_on(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR-STRICT: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fadd {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fadd {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fadd float
+// LLVM-DEFAULT-RND: fadd float
+  sf = x - y;
+// CIR-STRICT: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fsub {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fsub {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fsub float
+// LLVM-DEFAULT-RND: fsub float
+  sf = x * y;
+// CIR-STRICT: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fmul {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fmul {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fmul float
+// LLVM-DEFAULT-RND: fmul float
+  sf = x / y;
+// CIR-STRICT: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fdiv {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fdiv {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fdiv float
+// LLVM-DEFAULT-RND: fdiv float
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR-STRICT: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cmp lt {{.*}} : !cir.float
+// CIR-DEFAULT-RND: cir.cmp lt {{.*}} : !cir.float
+// LLVM-STRICT: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fcmp olt float
+// LLVM-DEFAULT-RND: fcmp olt float
+  sf = (float)i;
+// CIR-STRICT: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cast int_to_float {{.*}} : !s32i -> !cir.float
+// CIR-DEFAULT-RND: cir.cast int_to_float {{.*}} : !s32i -> !cir.float
+// LLVM-STRICT: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: sitofp i32 {{.*}} to float
+// LLVM-DEFAULT-RND: sitofp i32 {{.*}} to float
+  si = (int)x;
+// CIR-STRICT: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cast float_to_int {{.*}} : !cir.float -> !s32i
+// CIR-DEFAULT-RND: cir.cast float_to_int {{.*}} : !cir.float -> !s32i
+// LLVM-STRICT: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fptosi float {{.*}} to i32
+// LLVM-DEFAULT-RND: fptosi float {{.*}} to i32
+  sd = (double)x;
+// CIR-STRICT: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cast floating {{.*}} : !cir.float -> !cir.double
+// CIR-DEFAULT-RND: cir.cast floating {{.*}} : !cir.float -> !cir.double
+// LLVM-STRICT: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fpext float {{.*}} to double
+// LLVM-DEFAULT-RND: fpext float {{.*}} to double
+  sf = (float)d;
+// CIR-STRICT: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cast floating {{.*}} : !cir.double -> !cir.float
+// CIR-DEFAULT-RND: cir.cast floating {{.*}} : !cir.double -> !cir.float
+// LLVM-STRICT: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fptrunc double {{.*}} to float
+// LLVM-DEFAULT-RND: fptrunc double {{.*}} to float
+  sf = __builtin_sqrtf(x);
+// CIR-STRICT: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.sqrt {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.sqrt {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call float @llvm.sqrt.f32
+// LLVM-DEFAULT-RND: call float @llvm.sqrt.f32
+  sf = __builtin_powf(x, y);
+// CIR-STRICT: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.pow {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.pow {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call float @llvm.pow.f32
+// LLVM-DEFAULT-RND: call float @llvm.pow.f32
+  sf = __builtin_fmaf(x, y, z);
+// CIR-STRICT: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fma {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fma {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call float @llvm.fma.f32
+// LLVM-DEFAULT-RND: call float @llvm.fma.f32
+  sl = __builtin_lroundf(x);
+// CIR-STRICT: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.lround {{.*}} : !cir.float -> !s64i
+// CIR-DEFAULT-RND: cir.lround {{.*}} : !cir.float -> !s64i
+// LLVM-STRICT: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call i64 @llvm.lround.i64.f32
+// LLVM-DEFAULT-RND: call i64 @llvm.lround.i64.f32
+  sf = __builtin_fmodf(x, y);
+// CIR-STRICT: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fmod {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fmod {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: frem float
+// LLVM-DEFAULT-RND: frem float
+}
+
+void test_scoped_fenv_access_on(float x, float y) {
+// CIR-LABEL: cir.func {{.*}}@test_scoped_fenv_access_on(
+// LLVM-LABEL: define {{.*}}@test_scoped_fenv_access_on(
+  float sf;
+  if (x) {
+#pragma STDC FENV_ACCESS ON
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  }
+}
+
+void test_fenv_round_upward(float x, float y, float z, int i, double d) {
+#pragma STDC FENV_ROUND FE_UPWARD
+#pragma STDC FENV_ACCESS ON
+// CIR-LABEL: cir.func {{.*}}@test_fenv_round_upward(
+// LLVM-LABEL: define {{.*}}@test_fenv_round_upward(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+  sf = x - y;
+// CIR: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+  sf = x * y;
+// CIR: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+  sf = x / y;
+// CIR: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+  sf = (float)i;
+// CIR: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+  si = (int)x;
+// CIR: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+  sd = (double)x;
+// CIR: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = (float)d;
+// CIR: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+  sf = __builtin_sqrtf(x);
+// CIR: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+  sf = __builtin_powf(x, y);
+// CIR: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+  sf = __builtin_fmaf(x, y, z);
+// CIR: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+  sl = __builtin_lroundf(x);
+// CIR: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = __builtin_fmodf(x, y);
+// CIR: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.strict")
+}
+
+void test_fenv_round_tonearest(float x, float y, float z, int i, double d) {
+#pragma STDC FENV_ROUND FE_TONEAREST
+#pragma STDC FENV_ACCESS ON
+// CIR-LABEL: cir.func {{.*}}@test_fenv_round_tonearest(
+// LLVM-LABEL: define {{.*}}@test_fenv_round_tonearest(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = x - y;
+// CIR: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = x * y;
+// CIR: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = x / y;
+// CIR: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+  sf = (float)i;
+// CIR: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  si = (int)x;
+// CIR: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+  sd = (double)x;
+// CIR: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = (float)d;
+// CIR: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = __builtin_sqrtf(x);
+// CIR: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = __builtin_powf(x, y);
+// CIR: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sf = __builtin_fmaf(x, y, z);
+// CIR: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  sl = __builtin_lroundf(x);
+// CIR: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = __builtin_fmodf(x, y);
+// CIR: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+}
+
+void test_fenv_round_tonearest_except_ignore(float x, float y, float z, int i, double d) {
+#pragma STDC FENV_ROUND FE_TONEAREST
+#pragma clang fp exceptions(ignore)
+#pragma STDC FENV_ACCESS ON
+// CIR-LABEL: cir.func {{.*}}@test_fenv_round_tonearest_except_ignore(
+// LLVM-LABEL: define {{.*}}@test_fenv_round_tonearest_except_ignore(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = x - y;
+// CIR: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = x * y;
+// CIR: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = x / y;
+// CIR: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.ignore")
+  sf = (float)i;
+// CIR: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  si = (int)x;
+// CIR: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.ignore")
+  sd = (double)x;
+// CIR: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.ignore")
+  sf = (float)d;
+// CIR: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = __builtin_sqrtf(x);
+// CIR: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = __builtin_powf(x, y);
+// CIR: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sf = __builtin_fmaf(x, y, z);
+// CIR: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  sl = __builtin_lroundf(x);
+// CIR: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.ignore")
+  sf = __builtin_fmodf(x, y);
+// CIR: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+}
+
+void test_fenv_round_tonearest_except_ignore_fenv_off(float x, float y, float z, int i, double d) {
+#pragma STDC FENV_ROUND FE_TONEAREST
+#pragma clang fp exceptions(ignore)
+#pragma STDC FENV_ACCESS OFF
+// CIR-LABEL: cir.func {{.*}}@test_fenv_round_tonearest_except_ignore_fenv_off(
+// LLVM-LABEL: define {{.*}}@test_fenv_round_tonearest_except_ignore_fenv_off(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR-STRICT: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fadd {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fadd {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fadd float
+// LLVM-DEFAULT-RND: fadd float
+  sf = x - y;
+// CIR-STRICT: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fsub {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fsub {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fsub float
+// LLVM-DEFAULT-RND: fsub float
+  sf = x * y;
+// CIR-STRICT: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fmul {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fmul {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fmul float
+// LLVM-DEFAULT-RND: fmul float
+  sf = x / y;
+// CIR-STRICT: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fdiv {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fdiv {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fdiv float
+// LLVM-DEFAULT-RND: fdiv float
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR-STRICT: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cmp lt {{.*}} : !cir.float
+// CIR-DEFAULT-RND: cir.cmp lt {{.*}} : !cir.float
+// LLVM-STRICT: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fcmp olt float
+// LLVM-DEFAULT-RND: fcmp olt float
+  sf = (float)i;
+// CIR-STRICT: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cast int_to_float {{.*}} : !s32i -> !cir.float
+// CIR-DEFAULT-RND: cir.cast int_to_float {{.*}} : !s32i -> !cir.float
+// LLVM-STRICT: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: sitofp i32 {{.*}} to float
+// LLVM-DEFAULT-RND: sitofp i32 {{.*}} to float
+  si = (int)x;
+// CIR-STRICT: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cast float_to_int {{.*}} : !cir.float -> !s32i
+// CIR-DEFAULT-RND: cir.cast float_to_int {{.*}} : !cir.float -> !s32i
+// LLVM-STRICT: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fptosi float {{.*}} to i32
+// LLVM-DEFAULT-RND: fptosi float {{.*}} to i32
+  sd = (double)x;
+// CIR-STRICT: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cast floating {{.*}} : !cir.float -> !cir.double
+// CIR-DEFAULT-RND: cir.cast floating {{.*}} : !cir.float -> !cir.double
+// LLVM-STRICT: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fpext float {{.*}} to double
+// LLVM-DEFAULT-RND: fpext float {{.*}} to double
+  sf = (float)d;
+// CIR-STRICT: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.cast floating {{.*}} : !cir.double -> !cir.float
+// CIR-DEFAULT-RND: cir.cast floating {{.*}} : !cir.double -> !cir.float
+// LLVM-STRICT: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: fptrunc double {{.*}} to float
+// LLVM-DEFAULT-RND: fptrunc double {{.*}} to float
+  sf = __builtin_sqrtf(x);
+// CIR-STRICT: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.sqrt {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.sqrt {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call float @llvm.sqrt.f32
+// LLVM-DEFAULT-RND: call float @llvm.sqrt.f32
+  sf = __builtin_powf(x, y);
+// CIR-STRICT: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.pow {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.pow {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call float @llvm.pow.f32
+// LLVM-DEFAULT-RND: call float @llvm.pow.f32
+  sf = __builtin_fmaf(x, y, z);
+// CIR-STRICT: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fma {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fma {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call float @llvm.fma.f32
+// LLVM-DEFAULT-RND: call float @llvm.fma.f32
+  sl = __builtin_lroundf(x);
+// CIR-STRICT: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.lround {{.*}} : !cir.float -> !s64i
+// CIR-DEFAULT-RND: cir.lround {{.*}} : !cir.float -> !s64i
+// LLVM-STRICT: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: call i64 @llvm.lround.i64.f32
+// LLVM-DEFAULT-RND: call i64 @llvm.lround.i64.f32
+  sf = __builtin_fmodf(x, y);
+// CIR-STRICT: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-STRICT-RND: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT: cir.fmod {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fmod {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT: frem float
+// LLVM-DEFAULT-RND: frem float
+}
+
+void test_fp_exceptions_maytrap(float x, float y, float z, int i, double d) {
+#pragma clang fp exceptions(maytrap)
+#pragma STDC FENV_ACCESS ON
+// CIR-LABEL: cir.func {{.*}}@test_fp_exceptions_maytrap(
+// LLVM-LABEL: define {{.*}}@test_fp_exceptions_maytrap(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+  sf = x - y;
+// CIR: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+  sf = x * y;
+// CIR: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+  sf = x / y;
+// CIR: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.maytrap")
+  sf = (float)i;
+// CIR: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+  si = (int)x;
+// CIR: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.maytrap")
+  sd = (double)x;
+// CIR: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.maytrap")
+  sf = (float)d;
+// CIR: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+  sf = __builtin_sqrtf(x);
+// CIR: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+  sf = __builtin_powf(x, y);
+// CIR: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+  sf = __builtin_fmaf(x, y, z);
+// CIR: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+  sl = __builtin_lroundf(x);
+// CIR: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.maytrap")
+  sf = __builtin_fmodf(x, y);
+// CIR: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.maytrap")
+}
+
+void test_fp_exceptions_maytrap_round_upward(float x, float y, float z, int i, double d) {
+#pragma clang fp exceptions(maytrap)
+#pragma STDC FENV_ROUND FE_UPWARD
+#pragma STDC FENV_ACCESS ON
+// CIR-LABEL: cir.func {{.*}}@test_fp_exceptions_maytrap_round_upward(
+// LLVM-LABEL: define {{.*}}@test_fp_exceptions_maytrap_round_upward(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+  sf = x - y;
+// CIR: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+  sf = x * y;
+// CIR: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+  sf = x / y;
+// CIR: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.maytrap")
+  sf = (float)i;
+// CIR: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+  si = (int)x;
+// CIR: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.maytrap")
+  sd = (double)x;
+// CIR: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.maytrap")
+  sf = (float)d;
+// CIR: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+  sf = __builtin_sqrtf(x);
+// CIR: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+  sf = __builtin_powf(x, y);
+// CIR: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+  sf = __builtin_fmaf(x, y, z);
+// CIR: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+  sl = __builtin_lroundf(x);
+// CIR: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.maytrap")
+  sf = __builtin_fmodf(x, y);
+// CIR: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upward, except_mode = unknown, strict_except = false>}
+// LLVM: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.upward", metadata !"fpexcept.maytrap")
+}
+
+void test_nested_fenv_access_off(float x, float y) {
+#pragma STDC FENV_ACCESS ON
+// CIR-LABEL: cir.func {{.*}}@test_nested_fenv_access_off(
+// LLVM-LABEL: define {{.*}}@test_nested_fenv_access_off(
+  float sf;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  {
+#pragma STDC FENV_ACCESS OFF
+  sf = x + y;
+// CIR-STRICT: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT-RND: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  }
+}
+
+void test_fenv_round_towardzero_nested_fenv_off(float x, float y) {
+#pragma STDC FENV_ROUND FE_TOWARDZERO
+#pragma STDC FENV_ACCESS ON
+// CIR-LABEL: cir.func {{.*}}@test_fenv_round_towardzero_nested_fenv_off(
+// LLVM-LABEL: define {{.*}}@test_fenv_round_towardzero_nested_fenv_off(
+  float sf;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upwardzero, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.strict")
+  {
+#pragma STDC FENV_ACCESS OFF
+  sf = x + y;
+// CIR-STRICT: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upwardzero, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upwardzero, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upwardzero, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT-RND: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = upwardzero, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.towardzero", metadata !"fpexcept.ignore")
+  }
+}
+
+void test_nested_fenv_round_then_fenv_access(float x, float y) {
+// CIR-LABEL: cir.func {{.*}}@test_nested_fenv_round_then_fenv_access(
+// LLVM-LABEL: define {{.*}}@test_nested_fenv_round_then_fenv_access(
+  float sf;
+  sf = x + y;
+// CIR-STRICT: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// CIR-DEFAULT-RND: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = masked, strict_except = false>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+  {
+#pragma STDC FENV_ROUND FE_TONEAREST
+#pragma STDC FENV_ACCESS ON
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+  }
+  {
+#pragma STDC FENV_ACCESS ON
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  }
+}
+
+void test_fenv_round_dynamic_with_fenv_access(float x, float y, float z, int i, double d) {
+#pragma STDC FENV_ROUND FE_DYNAMIC
+#pragma STDC FENV_ACCESS ON
+// CIR-LABEL: cir.func {{.*}}@test_fenv_round_dynamic_with_fenv_access(
+// LLVM-LABEL: define {{.*}}@test_fenv_round_dynamic_with_fenv_access(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x - y;
+// CIR: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x * y;
+// CIR: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x / y;
+// CIR: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+  sf = (float)i;
+// CIR: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  si = (int)x;
+// CIR: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+  sd = (double)x;
+// CIR: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = (float)d;
+// CIR: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_sqrtf(x);
+// CIR: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_powf(x, y);
+// CIR: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_fmaf(x, y, z);
+// CIR: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sl = __builtin_lroundf(x);
+// CIR: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = __builtin_fmodf(x, y);
+// CIR: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+}
+
+void test_fenv_round_dynamic_without_fenv_access(float x, float y, float z, int i, double d) {
+#pragma STDC FENV_ROUND FE_DYNAMIC
+// CIR-LABEL: cir.func {{.*}}@test_fenv_round_dynamic_without_fenv_access(
+// LLVM-LABEL: define {{.*}}@test_fenv_round_dynamic_without_fenv_access(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR-STRICT: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fadd {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fadd {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fadd float
+// LLVM-DEFAULT-RND: fadd float
+  sf = x - y;
+// CIR-STRICT: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fsub {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fsub {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fsub float
+// LLVM-DEFAULT-RND: fsub float
+  sf = x * y;
+// CIR-STRICT: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fmul {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fmul {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fmul float
+// LLVM-DEFAULT-RND: fmul float
+  sf = x / y;
+// CIR-STRICT: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fdiv {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fdiv {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fdiv float
+// LLVM-DEFAULT-RND: fdiv float
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR-STRICT: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cmp lt {{.*}} : !cir.float
+// CIR-DEFAULT-RND: cir.cmp lt {{.*}} : !cir.float
+// LLVM-STRICT: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fcmp olt float
+// LLVM-DEFAULT-RND: fcmp olt float
+  sf = (float)i;
+// CIR-STRICT: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cast int_to_float {{.*}} : !s32i -> !cir.float
+// CIR-DEFAULT-RND: cir.cast int_to_float {{.*}} : !s32i -> !cir.float
+// LLVM-STRICT: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: sitofp i32 {{.*}} to float
+// LLVM-DEFAULT-RND: sitofp i32 {{.*}} to float
+  si = (int)x;
+// CIR-STRICT: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cast float_to_int {{.*}} : !cir.float -> !s32i
+// CIR-DEFAULT-RND: cir.cast float_to_int {{.*}} : !cir.float -> !s32i
+// LLVM-STRICT: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fptosi float {{.*}} to i32
+// LLVM-DEFAULT-RND: fptosi float {{.*}} to i32
+  sd = (double)x;
+// CIR-STRICT: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cast floating {{.*}} : !cir.float -> !cir.double
+// CIR-DEFAULT-RND: cir.cast floating {{.*}} : !cir.float -> !cir.double
+// LLVM-STRICT: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fpext float {{.*}} to double
+// LLVM-DEFAULT-RND: fpext float {{.*}} to double
+  sf = (float)d;
+// CIR-STRICT: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cast floating {{.*}} : !cir.double -> !cir.float
+// CIR-DEFAULT-RND: cir.cast floating {{.*}} : !cir.double -> !cir.float
+// LLVM-STRICT: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fptrunc double {{.*}} to float
+// LLVM-DEFAULT-RND: fptrunc double {{.*}} to float
+  sf = __builtin_sqrtf(x);
+// CIR-STRICT: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.sqrt {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.sqrt {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.sqrt.f32
+// LLVM-DEFAULT-RND: call float @llvm.sqrt.f32
+  sf = __builtin_powf(x, y);
+// CIR-STRICT: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.pow {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.pow {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.pow.f32
+// LLVM-DEFAULT-RND: call float @llvm.pow.f32
+  sf = __builtin_fmaf(x, y, z);
+// CIR-STRICT: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fma {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fma {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.fma.f32
+// LLVM-DEFAULT-RND: call float @llvm.fma.f32
+  sl = __builtin_lroundf(x);
+// CIR-STRICT: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.lround {{.*}} : !cir.float -> !s64i
+// CIR-DEFAULT-RND: cir.lround {{.*}} : !cir.float -> !s64i
+// LLVM-STRICT: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call i64 @llvm.lround.i64.f32
+// LLVM-DEFAULT-RND: call i64 @llvm.lround.i64.f32
+  sf = __builtin_fmodf(x, y);
+// CIR-STRICT: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fmod {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fmod {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: frem float
+// LLVM-DEFAULT-RND: frem float
+}
+
+#pragma STDC FENV_ACCESS ON
+void test_file_scope_fenv_access_on(float x, float y, float z, int i, double d) {
+// CIR-LABEL: cir.func {{.*}}@test_file_scope_fenv_access_on(
+// LLVM-LABEL: define {{.*}}@test_file_scope_fenv_access_on(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x - y;
+// CIR: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x * y;
+// CIR: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = x / y;
+// CIR: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+  sf = (float)i;
+// CIR: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  si = (int)x;
+// CIR: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+  sd = (double)x;
+// CIR: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = (float)d;
+// CIR: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_sqrtf(x);
+// CIR: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_powf(x, y);
+// CIR: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sf = __builtin_fmaf(x, y, z);
+// CIR: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+// LLVM-DEFAULT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+  sl = __builtin_lroundf(x);
+// CIR: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+  sf = __builtin_fmodf(x, y);
+// CIR: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = unknown, except_mode = unknown, strict_except = true>}
+// LLVM: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.dynamic", metadata !"fpexcept.strict")
+}
+
+#pragma STDC FENV_ACCESS OFF
+void test_file_scope_fenv_access_off(float x, float y, float z, int i, double d) {
+// CIR-LABEL: cir.func {{.*}}@test_file_scope_fenv_access_off(
+// LLVM-LABEL: define {{.*}}@test_file_scope_fenv_access_off(
+  float sf;
+  double sd;
+  int si;
+  long sl;
+  _Bool sb;
+  sf = x + y;
+// CIR-STRICT: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fadd {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fadd {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fadd {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fadd.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fadd float
+// LLVM-DEFAULT-RND: fadd float
+  sf = x - y;
+// CIR-STRICT: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fsub {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fsub {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fsub {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fsub.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fsub float
+// LLVM-DEFAULT-RND: fsub float
+  sf = x * y;
+// CIR-STRICT: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fmul {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fmul {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fmul {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fmul.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fmul float
+// LLVM-DEFAULT-RND: fmul float
+  sf = x / y;
+// CIR-STRICT: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fdiv {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fdiv {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fdiv {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fdiv.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fdiv float
+// LLVM-DEFAULT-RND: fdiv float
+  sf = -x;
+// CIR: cir.fneg {{.*}} : !cir.float loc
+// LLVM: fneg float
+  sb = x < y;
+// CIR-STRICT: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cmp lt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cmp lt {{.*}} : !cir.float
+// CIR-DEFAULT-RND: cir.cmp lt {{.*}} : !cir.float
+// LLVM-STRICT: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call i1 @llvm.experimental.constrained.fcmps.f32({{.*}}, metadata !"olt", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fcmp olt float
+// LLVM-DEFAULT-RND: fcmp olt float
+  sf = (float)i;
+// CIR-STRICT: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cast int_to_float {{.*}} : !s32i -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cast int_to_float {{.*}} : !s32i -> !cir.float
+// CIR-DEFAULT-RND: cir.cast int_to_float {{.*}} : !s32i -> !cir.float
+// LLVM-STRICT: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.sitofp.f32.i32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: sitofp i32 {{.*}} to float
+// LLVM-DEFAULT-RND: sitofp i32 {{.*}} to float
+  si = (int)x;
+// CIR-STRICT: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cast float_to_int {{.*}} : !cir.float -> !s32i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cast float_to_int {{.*}} : !cir.float -> !s32i
+// CIR-DEFAULT-RND: cir.cast float_to_int {{.*}} : !cir.float -> !s32i
+// LLVM-STRICT: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call i32 @llvm.experimental.constrained.fptosi.i32.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fptosi float {{.*}} to i32
+// LLVM-DEFAULT-RND: fptosi float {{.*}} to i32
+  sd = (double)x;
+// CIR-STRICT: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cast floating {{.*}} : !cir.float -> !cir.double {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cast floating {{.*}} : !cir.float -> !cir.double
+// CIR-DEFAULT-RND: cir.cast floating {{.*}} : !cir.float -> !cir.double
+// LLVM-STRICT: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call double @llvm.experimental.constrained.fpext.f64.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fpext float {{.*}} to double
+// LLVM-DEFAULT-RND: fpext float {{.*}} to double
+  sf = (float)d;
+// CIR-STRICT: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.cast floating {{.*}} : !cir.double -> !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.cast floating {{.*}} : !cir.double -> !cir.float
+// CIR-DEFAULT-RND: cir.cast floating {{.*}} : !cir.double -> !cir.float
+// LLVM-STRICT: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fptrunc.f32.f64({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: fptrunc double {{.*}} to float
+// LLVM-DEFAULT-RND: fptrunc double {{.*}} to float
+  sf = __builtin_sqrtf(x);
+// CIR-STRICT: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.sqrt {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.sqrt {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.sqrt {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.sqrt.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.sqrt.f32
+// LLVM-DEFAULT-RND: call float @llvm.sqrt.f32
+  sf = __builtin_powf(x, y);
+// CIR-STRICT: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.pow {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.pow {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.pow {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.pow.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.pow.f32
+// LLVM-DEFAULT-RND: call float @llvm.pow.f32
+  sf = __builtin_fmaf(x, y, z);
+// CIR-STRICT: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fma {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fma {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fma {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.fma.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call float @llvm.fma.f32
+// LLVM-DEFAULT-RND: call float @llvm.fma.f32
+  sl = __builtin_lroundf(x);
+// CIR-STRICT: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.lround {{.*}} : !cir.float -> !s64i {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.lround {{.*}} : !cir.float -> !s64i
+// CIR-DEFAULT-RND: cir.lround {{.*}} : !cir.float -> !s64i
+// LLVM-STRICT: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call i64 @llvm.experimental.constrained.lround.i64.f32({{.*}}, metadata !"fpexcept.strict")
+// LLVM-DEFAULT: call i64 @llvm.lround.i64.f32
+// LLVM-DEFAULT-RND: call i64 @llvm.lround.i64.f32
+  sf = __builtin_fmodf(x, y);
+// CIR-STRICT: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-STRICT-RND: cir.fmod {{.*}} : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest, except_mode = unknown, strict_except = true>}
+// CIR-DEFAULT: cir.fmod {{.*}} : !cir.float loc
+// CIR-DEFAULT-RND: cir.fmod {{.*}} : !cir.float loc
+// LLVM-STRICT: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-STRICT-RND: call float @llvm.experimental.constrained.frem.f32({{.*}}, metadata !"round.tonearest", metadata !"fpexcept.strict")
+// LLVM-DEFAULT: frem float
+// LLVM-DEFAULT-RND: frem float
+}
+
+// LLVM-STRICT: attributes #[[$STRICT_ATTR]] = { {{.*}}strictfp{{.*}} }
+// LLVM-STRICT-RND: attributes #[[$STRICT_ATTR]] = { {{.*}}strictfp{{.*}} }
+// LLVM-DEFAULT-RND: attributes #[[$STRICT_ATTR]] = { {{.*}}strictfp{{.*}} }
diff --git a/clang/test/CIR/Lowering/fenv.cir b/clang/test/CIR/Lowering/fenv.cir
index 14f334a09d11c..282d51d2e73a7 100644
--- a/clang/test/CIR/Lowering/fenv.cir
+++ b/clang/test/CIR/Lowering/fenv.cir
@@ -54,7 +54,10 @@ module {
     %1 = cir.fadd %a, %b : !cir.float {fenv = #cir.fenv<strict_except = false>}
     // CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.ignore">
     // CHECK: llvm.call_intrinsic "llvm.experimental.constrained.fadd"
-    %2 = cir.fadd %a, %b : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest>}
+    %2 = cir.fadd %a, %b : !cir.float {fenv = #cir.fenv<except_mode = masked, strict_except = false>}
+    // CHECK: llvm.mlir.metadata_as_value #llvm.md_string<"fpexcept.ignore">
+    // CHECK: llvm.call_intrinsic "llvm.experimental.constrained.fadd"
+    %3 = cir.fadd %a, %b : !cir.float {fenv = #cir.fenv<dynamic_rounding_mode = tonearest>}
     cir.return
   }
 
@@ -114,6 +117,16 @@ module {
     cir.return
   }
 
+  // CHECK-LABEL: llvm.func @ternary_fp_builtins
+  cir.func @ternary_fp_builtins(%a: !cir.double, %b: !cir.double,
+                                %c: !cir.double) {
+    // CHECK: llvm.call_intrinsic "llvm.experimental.constrained.fma"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (f64, f64, f64, !llvm.metadata, !llvm.metadata) -> f64
+    %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
+    cir.return
+  }
+
   // CHECK-LABEL: llvm.func @minmax_num
   cir.func @minmax_num(%a: !cir.double, %b: !cir.double) {
     // CHECK: llvm.call_intrinsic "llvm.experimental.constrained.maxnum"(%{{.*}}, %{{.*}}, %{{.*}}) {fastmathFlags = #llvm.fastmath<nsz>} : (f64, f64, !llvm.metadata) -> f64
diff --git a/clang/test/CIR/Lowering/strictfp.cir b/clang/test/CIR/Lowering/strictfp.cir
new file mode 100644
index 0000000000000..66caa04ca9a9c
--- /dev/null
+++ b/clang/test/CIR/Lowering/strictfp.cir
@@ -0,0 +1,28 @@
+// RUN: cir-opt %s -cir-to-llvm -o - | FileCheck %s -check-prefix=MLIR
+// RUN: cir-translate %s -cir-to-llvmir --disable-cc-lowering | FileCheck %s -check-prefix=LLVM
+
+// Functions tagged with the `strictfp` CIR function attribute should be
+// lowered to `llvm.func` operations whose `passthrough` array contains
+// `"strictfp"`, and then translated to LLVM IR functions carrying the
+// `strictfp` attribute.
+
+module {
+  cir.func @strict_fn() attributes {strictfp} {
+    cir.return
+  }
+
+  cir.func @plain_fn() {
+    cir.return
+  }
+}
+
+// MLIR-LABEL: llvm.func @strict_fn()
+// MLIR-SAME:    passthrough = ["strictfp"]
+// MLIR-LABEL: llvm.func @plain_fn()
+// MLIR-NOT:     passthrough
+// MLIR-NOT:     strictfp
+
+// LLVM:       define void @strict_fn() #[[STRICT:[0-9]+]]
+// LLVM-LABEL: define void @plain_fn()
+// LLVM-NOT:     #[[STRICT]]
+// LLVM:       attributes #[[STRICT]] = {{.*}}strictfp



More information about the cfe-commits mailing list