[llvm-dev] Floating point semantic modes

Kaylor, Andrew via llvm-dev
Wed, 29 Jan 2020 23:54:46 -0000

> ... math errno ...

I wouldn't recommend to anyone that they should rely on math errno (because
I don't trust libraries to correctly support it). My goal here was to
incorporate our existing support for it into the rest of what I'm trying to
document.

My understanding is that for clang this primarily controls whether or not we
feel free to substitute intrinsics for recognized math library calls. I
don't know if we have any code in the optimizer that introduces access to or
modification of errno in the user's program. The library calls that test
should always act as barriers to one another.


> ideally there would be a way to support snan too. (e.g. isnan(x) cannot be
turned into x!=x then)

The except_behavior mode is supposed to handle this. The LLVM support for
constrained intrinsics is considering all manner of FP exceptions that could be
raised, including the distinction between QNaN and SNaN. The default LLVM IR
definition does not support this distinction.

We seem to have an issue with isnan() in clang though. If you call isnan() you
get a call to __isnan() which should be fine (assuming the library does the
right thing), but we're translating __builtin_isnan() to x!=x. That's
not what we should be doing if except_behavior isn't "ignore".


> excess precision handling is missing from this list which matters for x87
and m68k fpu support and may matter for _Float16 implementations that fall back
to _Float32 arithmetic.

Yeah, we don't currently have any support for controlling that, at least in
the x87 case. I think our current strategy is nothing more than setting
FLT_EVAL_METHOD to reflect that we might not be using source precision for
intermediate results. This is something we should consider adding.


> the granularity of these knobs is also interesting (expression, code block,
function or translation unit), iso c pragmas work on code block level.

I'd have to defer to someone more familiar with the front end to say how
that is handled.


> -ftrapping-math vs -ffp-exception-behaviour=maytrap is unclear.

The "maytrap" setting is supposed to prevent the optimizer from
introducing spurious exceptions (e.g. speculative execution) while still
allowing it to optimize away potential exceptions (e.g. dce operations whose
results are never used).


> FLT_ROUNDS, FLT_EVAL_METHOD and math_errhandling are controlled by the c
runtime, so a compiler has no business changing them, the compiler can define
its own __FLT_ROUNDS, etc macros and the libc may or may not use those, but e.g.
in case of FLT_ROUNDS it makes no sense for the compiler to try to do anything:
the mode changes at runtime, the libc macro will expand to a function call that
determines the current rounding mode. (same problem arises if you can change the
other modes on a per function or code block granularity.)

I don't think I understand what you're saying here. FLT_ROUNDS, in
particular, I thought was supposed to be implemented without reference to the
runtime library. In clang we're mapping this to an intrinsic that gets a
target-specific inline expansion. For example: https://godbolt.org/z/uQD-AF

And FLT_EVAL_METHOD I take to be an indicator of how the compiler is handling
intermediate results.



-----Original Message-----
From: Szabolcs Nagy <nsz at port70.net>
Sent: Tuesday, January 28, 2020 5:09 AM
To: Kaylor, Andrew <andrew.kaylor at intel.com>
Cc: cfe-dev at lists.llvm.org; LLVM Developers Mailing List <llvm-dev at
lists.llvm.org>; Ristow, Warren <warren.ristow at sony.com>; Ulrich
Weigand (Ulrich.Weigand at de.ibm.com) <Ulrich.Weigand at de.ibm.com>;
Cameron McInally <cameron.mcinally at nyu.edu>; Kevin Neal <Kevin.Neal
at sas.com>; Blower, Melanie I <melanie.blower at intel.com>; sepavloff
at gmail.com; hfinkel at anl.gov; Sanjay Patel <spatel at
rotateright.com>; Wang, Pengfei <pengfei.wang at intel.com>
Subject: Re: [llvm-dev] Floating point semantic modes

* Kaylor, Andrew via llvm-dev <llvm-dev at lists.llvm.org> [2020-01-27
23:24:10 +0000]:
> Hi all,
>
> I'm trying to put together a set of rules for how the various floating
point semantic modes should be handled in clang. A lot of this information will
be relevant to other front ends, but the details are necessarily bound to a
front end implementation so I'm framing the discussion here in terms of
clang. Other front ends can choose to follow clang or not. The existence of this
set of semantics is an LLVM property that applies to all front ends, but the
front ends will have to do something to initialize them.
>
> I will eventually do something to convert this into an RST document and
find a home for it in the clang documentation, but I'd like to start by
getting input on whether everyone agrees with my judgment on how these things
should work and whether I've missed anything.
>
> Here's what I've got.
>

i'm not an llvm/clang dev, i hope this mail wont bounce.

> =====================> FP semantic modes
> =====================> except_behavior { ignore, strict, may_trap }
fenv_access { on, off }
> rounding_mode { dynamic, tonearest, downward, upward, towardzero }
> contract { on, off, fast } denormal_fp_math { IEEE, PreserveSign,
> PositiveZero } denormal_fp32_math { IEEE, PreserveSign, PositiveZero }
> support_math_errno { on, off }

note that math errno handling can be

1) errno is set,
2) errno may be set and
3) errno is guaranteed to be untouched

iso c math_errhandling can select between 1 and 2, (user can or cannot rely on
errno) but for optimizing math calls as side-effect-free pure functions, 3 is
needed.

-f(no-)math-errno selects between 1 and 3.
with 3, moving math calls across errno checks or calls that set errno can break
semantics depending on how libm is implemented (e.g. glibc will set errno
independently of how you compiled your code).

> no_honor_nans { on, off }

ideally there would be a way to support snan too.
(e.g. isnan(x) cannot be turned into x!=x then)

> no_honor_infinities { on, off }
> no_signed_zeros { on, off }
> allow_reciprocal { on, off }
> allow_approximate_fns { on, off }
> allow_reassociation { on, off }

excess precision handling is missing from this list which matters for x87 and
m68k fpu support and may matter for _Float16 implementations that fall back to
_Float32 arithmetic.

the granularity of these knobs is also interesting (expression, code block,
function or translation unit), iso c pragmas work on code block level.

> =====================> FP models
> =====================> -----------------------
> precise (default)
> -----------------------
> except_behavior { ignore }
> fenv_access { off }
> rounding_mode { tonearest }
> contract { on }
> denormal_fp_math { IEEE }
> denormal_fp32_math { IEEE }
> support_math_errno { on }
> no_honor_nans { off }
> no_honor_infinities { off }
> no_signed_zeros { off }
> allow_reciprocal { off }
> allow_approximate_fns { off }
> allow_reassociation { off }
>
> ------------------
> strict
> ------------------
> except_behavior { strict }
> fenv_access { on }
> rounding_mode { dynamic }
> contract { off }
> denormal_fp_math { IEEE }
> denormal_fp32_math { IEEE }
> support_math_errno { on }
> no_honor_nans { off }
> no_honor_infinities { off }
> no_signed_zeros { off }
> allow_reciprocal { off }
> allow_approximate_fns { off }
> allow_reassociation { off }
>
> ------------------
> fast
> ------------------
> except_behavior { ignore }
> fenv_access { off }
> rounding_mode { tonearest }
> contract { fast }
> denormal_fp_math { PreserveSign }
> denormal_fp32_math { PreserveSign }
> support_math_errno { off }
> no_honor_nans { on }
> no_honor_infinities { on }
> no_signed_zeros { on }
> allow_reciprocal { on }
> allow_approximate_fns { on }
> allow_reassociation { on }
>
> =====================> Command-line options
> =====================> -ffp-model={precise|strict|fast}
>   Sets all semantic modes as described above.
>
> -ffast-math
>   Equivalent to -ffp-model=fast. (I'm not sure that's currently
true.)
>
> -f[no-]math-errno
> -ffp-contract={on|off|fast}
> -f[no-]honor-infinities
> -f[no-]honor-nans
> -f[no-]associative-math
> -f[no-]reciprocal-math
> -f[no-]signed-zeros
> -f[no-]trapping-math
> -f[no-]rounding-math
> -fdenormal-fp-math={ieee, preservesign, positivezero}
> -fdenormal-fp-math-fp32={ieee, preservesign, positivezero}
> -ffp-exception-behavior={ignore,maytrap,strict}
>   Each of these has a 1-to-1 correspondance to an FP semantic mode.
>   (I think several of these should set "except_behavior" to
"ignore".)

-ftrapping-math vs -ffp-exception-behaviour=maytrap is unclear.

(-ftrapping-math is weird in gcc, it does not handle all fp exception cases, not
sure what clang plans to do with that)

>
> -f[no-]finite-math-only
>   Controls no_honor_nans and no_honor_infinities.
>
> -f[no-]unsafe-math-optimizations
>   Turns no_signed_zeros, allow_reciprocal, allow_approximate_fns, and
allow_reassociation on or off.
>   Also, sets except_behavior to "on" for
-funsafe-math-optimizations.
>   (Currently, -fno-]unsafe-math-optimizations clears except_behavior,
> but I regard this as a bug.)
>
> All command line options will override any previous values of all settings
they control with options taking effect in a left-to-right manner.
>
> =====================> pragmas
> =====================> STDC FENV_ACCESS {ON|OFF}
>   Patch in progress. I think ON should force the following:
>
>     except_behavior { strict }
>     fenv_access { on }
>     rounding_mode { dynamic }
>     denormal_fp_math { IEEE }
>     denormal_fp32_math { IEEE }
>     no_signed_zeros { off }
>     allow_reciprocal { off }
>     allow_approximate_fns { off }
>     allow_reassociation { off }
>
>   And OFF should set fenv_access to off, except_behavior to ignore, and
rounding_mode to tonearest. Other modes should be reset to their command line
defined settings.
>
>   I don't think this pragma should have any effect on contract,
support_math_errno, no_honor_nans, or no_honor_infinities.
>
> STDC FP_CONTRACT {ON|OFF|DEFAULT}
>   This pragma controls the contract FP semantic mode. No other FP semantic
modes are effected.
>
> float_control ({precise|except}, {on|off}[, push]) float_control (pop)
>   Patch in progress. These are tricky.
>   I think they should have the following effects:
>
> float_control (precise, on[, push])
>   contract { on }
>   denormal_fp_math { IEEE }
>   denormal_fp32_math { IEEE }
>   no_signed_zeros { off }
>   allow_reciprocal { off }
>   allow_approximate_fns { off }
>   allow_reassociation { off }
>
> float_control (precise, off[, push])
>   contract { fast }
>   denormal_fp_math { preservesign }
>   denormal_fp32_math { preservesign }
>   no_signed_zeros { on }
>   allow_reciprocal { on }
>   allow_approximate_fns { on }
>   allow_reassociation { on }
>
> Note, this is less than what the -ffp-model=precise control does. Should
this override support_math_errno, no_honor_nans, or no_honor_infinities?
>
> float_control (except, on[, push])
>   except_behavior { strict }
>
> float_control (except, off[, push])
>   except_behavior { ignore }
>
> The MSVC documentation says you can only use the float_control pragma to
turn exception semantics on when precise semantics are enabled. For us, this
would mean:
>   denormal_fp_math { IEEE }
>   denormal_fp32_math { IEEE }
>   no_signed_zeros { off }
>   allow_reciprocal { off }
>   allow_approximate_fns { off }
>   allow_reassociation { off }
>
> The MSVC documentation also says you can't use the float_control pragma
to turn excpetion semantics off when precise semantics are enabled, and you
can't use the float_control pragma to turn precise off when fenv_access is
on.
>
> I believe we should follow the MSVC restrictions.
>
> ========================> Code-visible identifiers
> ========================> __FAST_MATH__
>
> This symbol will only be defined if and only if all of the following are
set (before pragmas are applied):
>   except_behavior { ignore }
>   fenv_access { off }
>   rounding_mode { tonearest }
>   contract { fast }
>   denormal_fp_math { PreserveSign }
>   denormal_fp32_math { PreserveSign }
>   support_math_errno { off }
>   no_honor_nans { on }
>   no_honor_infinities { on }
>   no_signed_zeros { on }
>   allow_reciprocal { on }
>   allow_approximate_fns { on }
>   allow_reassociation { on }
>
> __FINITE_MATH_ONLY__
>
> This symbol will only be defined if and only if all of the following are
set (before pragmas are applied):
>   no_honor_nans { on }
>   no_honor_infinities { on }
>
> FLT_ROUNDS
>
> Should be set to -1 (indeterminable) if rounding_mode() is dynamic or 1
(tonearest) if rounding_mode is tonearest. There are values for other rounding
modes, but clang offers no way to set those rounding modes.
>
> FLT_EVAL_METHOD
>
> Should be set to -1 if any of allow_reciprocal, allow_approximate_fns, or
allow_reassociation is set. Should any other flags also make this -1? Otherwise,
the setting is target-defined.
>
> math_errhandling
>
> The MATH_ERRNO bit will be set or cleared based on the setting of
support_math_errno. Should MATH_ERREXCEPT be set or cleared based on
except_behavior?


FLT_ROUNDS, FLT_EVAL_METHOD and math_errhandling

are controlled by the c runtime, so a compiler has no business changing them,
the compiler can define its own __FLT_ROUNDS, etc macros and the libc may or may
not use those, but e.g.
in case of FLT_ROUNDS it makes no sense for the compiler to try to do anything:
the mode changes at runtime, the libc macro will expand to a function call that
determines the current rounding mode. (same problem arises if you can change the
other modes on a per function or code block granularity.)

and i don't think it's a good idea to change FLT_EVAL_METHOD with
non-precise arithmetic modes, because it is used to decide if excess range and
precision is available, but arithmetic changes don't affect that. (e.g.
float_t is still same as float).

>
>
> Thanks in advance for any opinions and suggestions.
>
> -Andy

> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev