[Mlir-commits] [mlir] [mlir][llvmir] Add new support for strict fp handling (PR #205158)

Andy Kaylor llvmlistbot at llvm.org
Thu Jun 25 15:50:17 PDT 2026


================
@@ -1790,4 +1790,183 @@ def LLVM_AnyMDAttr : AnyAttrOf<[
     LLVM_MDStringAttr, LLVM_MDConstantAttr, LLVM_MDFuncAttr, LLVM_MDNodeAttr],
     "LLVM metadata attribute (md_string, md_const, md_func, or md_node)">;
 
+//===----------------------------------------------------------------------===//
+// FenvAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_FenvAttr : LLVM_Attr<"Fenv", "fenv"> {
+  let summary = "Describes floating-point environment constraints";
+  let description = [{
+    The `#llvm.fenv` attribute describes constraints on the floating-point
+    handling of a floating-point operation. It can be attached to
+    floating-point operations to capture rounding and exception behavior. All
+    of its parameters are optional.
+
+    - `rounding_mode`: the rounding mode to use. Every value other than
+      `dynamic` specifies a static rounding mode.
+    - `dynamic_rounding_mode`: the known dynamic rounding mode at the point the
+      instruction is executed. Otherwise the behavior is undefined.
+    - `except_mode`: the known exception mode at the point the instruction is
+      executed. Otherwise the behavior is undefined.
+    - `strict_snan`: whether to handle sNaN according to IEEE rules (`true`) or
+      LLVM's relaxed NaN propagation rules (`false`). This flag is only
+      meaningful when `except_mode` is `unmasked` or `unknown`, where it
+      defaults to `true`; when `except_mode` is `masked` the flag is ignored.
+    - `strict_except`: if `false`, any case that would produce an FP exception
+      produces it non-deterministically instead (i.e. it may or may not occur).
+      This means the FP status is written non-deterministically, and, if
+      exceptions are unmasked, the instruction traps non-deterministically.
+      This flag is only meaningful when `except_mode` is `unmasked` or
+      `unknown`, where it defaults to `true`; when `except_mode` is `masked`
+      the flag is ignored.
+
+    When this attribute is present on an operation, the operation is lowered to
+    the corresponding `llvm.experimental.constrained.*` intrinsic during
+    translation to LLVM IR.
+
+    The default setting for each parameter (`dynamic` rounding mode, `unknown`
+    dynamic rounding mode, `masked` exception mode, and, when exceptions are not
+    masked, `true` for both `strict_snan` and `strict_except`) is canonically
+    represented as an unset parameter. Constructing an attribute whose
+    parameters are all set to their defaults therefore yields the same
+    canonical, empty attribute as `#llvm.fenv<>`.
+
+    Carrying the (possibly empty) attribute is *not* the same as having no
+    attribute at all. An operation that carries the attribute is lowered to the
+    corresponding constrained intrinsic, even when every parameter is at its
----------------
andykaylor wrote:

It's not quite harmless. The point of forcing the use of constrained intrinsics when the default environment is specified is to provide a way to generate constrained intrinsics for all FP operations in a function when the environment may be changed anywhere in the function. The purpose of this is to provide a way to prevent instructions with default enviornment assumptions from migrating across instruction that may change the environment or read status flags. Without the intrinsic, the `fcmp` instruction could be hoisted into a region that was translated with fenv access enabled, potentially migrating above some operation that reads the status flags. This would be incorrect.

I'll fix that.

https://github.com/llvm/llvm-project/pull/205158


More information about the Mlir-commits mailing list