The conditions for which Clang emits the unsafe-fp-math function
attribute has been modified as part of
84a9ec2ff1ee97fd7e8ed988f5e7b197aab84a7.
In the backend code generators "unsafe-fp-math"="true" enable floating
point contraction for the whole function.
The intent of the change in 84a9ec2ff1ee97fd7e8ed988f5e7b197aab84a7
was to prevent backend code generators performing contractions when that
is not expected.
However the change is inaccurate and incomplete because it allows
unsafe-fp-math to be set also when only in-statement contraction is
allowed.
Consider the following example
float foo(float a, float b, float c) { float tmp = a * b; return tmp + c; }
and compile it with the command line
clang -fno-math-errno -funsafe-math-optimizations -ffp-contract=on \ -O2 -mavx512f -S -o -
The resulting assembly has a vfmadd213ss instruction which corresponds
to a fused multiply-add. From the user perspective there shouldn't be
any contraction because the multiplication and the addition are not in
the same statement.
The optimized IR is:
define float @test(float noundef %a, float noundef %b, float noundef %c) #0 { %mul = fmul reassoc nsz arcp afn float %b, %a %add = fadd reassoc nsz arcp afn float %mul, %c ret float %add } attributes #0 = { [...] "no-signed-zeros-fp-math"="true" "no-trapping-math"="true" [...] "unsafe-fp-math"="true" }
The "unsafe-fp-math"="true" function attribute allows the backend code
generator to perform (fadd (fmul a, b), c) -> (fmadd a, b, c).
In the current IR representation there is no way to determine the
statement boundaries from the original source code.
Because of this for in-statement only contraction the generated IR
doesn't have instructions with the contract fast-math flag and
llvm.fmuladd is being used to represent contractions opportunities
that occur within a single statement.
Therefore "unsafe-fp-math"="true" can only be emitted when contraction
across statements is allowed.
Moreover the change in 84a9ec2ff1ee97fd7e8ed988f5e7b197aab84a7 doesn't
take into account that the floating point math function attributes can
be refined during IR code generation of a function to handle the cases
where the floating point math options are modified within a compound
statement via pragmas (see CGFPOptionsRAII).
For consistency unsafe-fp-math needs to be disabled if the contraction
mode for any scope/operation is not fast.
Similarly for consistency reason the initialization of UnsafeFPMath of
in TargetOptions for the backend code generation should take into
account the contraction mode as well.
I've found quite confusing the (FastMath || (!FastMath && ... )).
Using directly UnsafeFPMath seems more compact, however it also causes to taking into account the value for MathErrno -- which it might be not relevant.
If MathErrno shouldn't affect this, then I would rewrite this as:
so that only the relevant options are considered and there is no need to think about what is implied by FastMath.