As seen in [Proposed breaking change/RFC] Remove min and max from -arith-expand-ops, the history of ⚙ D140856 [mlir][Arith] Remove expansions of integer min and max ops, and ⚙ D137786 Lower arith.min/max to llvm.intr.minimum/maximum, there is much headache to be had from how various platforms implement floating-point min and max, and, more specifically, their behavior with regards to NaN and signed zero.
Currently, arith.minf
and arith.maxf
specify they will propagate NaN and leave signed zero behavior undefined.
However, not all the lowerings (for instance, -arith-to-llvm
) actually implement these semantics.
Ideally, MLIR would be able to
- Not generate NaN checks that users don’t need/don’t care about and
- Support multiple different NaN/signed zero semantics when the user does care
I propose adding the following two enums (that’ll probably go in Arith
, but since other dialects may want them for their ops, a more general location might make sense)
(preserved for continuity of discussion, see [RFC] Explicitly specifying NaN and signed zero semantics for minf and maxf - #16 by krzysz00 for new proposal)
enum NaNSemantics {
Any = 0,
Platform = 1,
PropagateNaN = 2,
PropagateOther = 3
}
~~
and
enum SignedZeroSemantics {
Any = 0,
Platform = 1,
Compare = 2
}
(end preserved bits)
and corresponding attributes. These attributes will become arguments to arith.minf
and arith.maxf
.
In both enums, Any
means that the user is willing to accept any reasonable semantics for NaN or signed zero and allows us, to, for example, constant-fold min(NaN, 5) -> NaN
even if that’s not what the fmin
instruction on their target would do.
On the other hand, Platform
means that the user wants their min and max operations lowered to some target-specific operation. Since this means that the user expects some consistent semantics (but we don’t know what they are), Platform
semantics impede constant folding away min and max involving NaN or stuff like min(-0, +0)
.
Lowerings of arith.minf/maxf
will use these attributes to select appropriate operations on their target.
Lowerings may use fast math flags to, for example, skip NaN checks when the operation is tagged as being NaN-free.
Higher-level dialects like vector
or tosa
that have some notion of floating-point min and max will
- Set particular values for these attributes if they have defined the NaN and signed zero semantics of their ops or
- Expose these attributes themselves, allowing dialects further up the chain to choose them or
- Do both, having an overridable default NaN/signed zero sematics
This work could also be a good time to pull fastmath flags up through those dialects.