Motivation
The current implementation of strictfp functions uses the same unified model for almost all cases that deviate from the default mode. These include, in particular:
• Code that executes with a non-default rounding mode,
• Code that inspects the FP exception status,
• Cases where FP exception trapping is enabled,
• Situations where a user wants to distinguish between quiet and signaling NaNs.
These cases impose different limitations on code transformations, so a single model suitable for all use cases is possible only at the cost of severe performance loss. This is a challenge, since many (if not most) practical applications of a non-default FP environment also require maximal performance.
The problem could be mitigated if a user specified which behavior is needed. Such a possibility exists, as there are a number of options that do exactly this, - -frounding-math, -ftrapping-math and some others. So if no -ftrapping-math is specified, the compiler could assume that FP trapping does not happen and generate more efficient code. Currently, this is not possible because these options in Clang do not specify any special behavior - they are implemented as setting up strict exception behavior.
A more flexible implementation would use information about user’s intentions, deduced from the options like -ftrapping-math and others, to generate more efficient code. To reach that, the command-line options must be implemented as separate independent features, which would determine a particular aspect of FP model, and a user could combine these options to reach desired behavior.
As a first step in this direction could be the implementation of support for signaling NaN as a separate feature, which is the simplest case as it does not involve interaction between instructions. Currently, this support is tightly coupled with the strictfp implementation, which does not look as a best decision.
Problems
This code represents a correct function, provided that the compiler and hardware are IEEE 754 compliant:
void quiet_SNAN(float *ptr, unsigned num) {
for (unsigned i = 0; i < num; ++i) {
*ptr *= 1.0;
}
}
Thus, a user might expect that this code would compile and work as expected on X86. Indeed, Clang can compile this code, but only with an option like -ffp-model=strict. This is strange because the code does not use non-default control modes or read FP status.
Because signaling NaN support in Clang is tightly coupled with the strictfp function attribute, it is difficult to document how to use it. The strictfp attribute is an internal detail, end users need not be aware of it. So how a user could enable this support on? There are several pragmas and half a dozen of command-line options that enable sNaN support, but none of them have a clear connection to sNaNs. Unsurprisingly, the Clang User Manual does not mention signaling NaN support, making it an undocumented feature.
The coupling two unrelated thing - sNaN support and the strictfp attribute - creates problems in other places too. For example, #pragma STDC FENV_ROUND in general does not require access to the FP environment and can be used in the default mode, where sNaNs are unsupported. On a target that does not have static rounding support, this pragma is implemented using dynamic rounding, which requires the strictfp attribute on the function. As a result, using the pragma would unexpectedly turns on sNaN support.
Another problem arises from targets that do not support sNaNs. On such a target, the compiler would try to honor sNaNs, producing less efficient code. This is especially bad, as such targets are often represented by ML or graphic cores, where performance is particularly important.
Control over sNaN support has a strong influence on the optimization of strictfp code. If the user does not use sNaNs, or if they are unsupported by the hardware, this knowledge can assist in producing efficient code in strictfp functions. Many operations in this case do not raise exceptions or are even pure functions.
Proposal
Support for signaling NaNs should be untied from the strictfp attribute. A new special attribute would represent this support, and it could be used in both strictfp and default mode functions. A special command-line option should be available to users to manage thise support. It could be -fsignaling-nans, an option available in GCC for this purpose.
The attempt to introduce the dedicated control over sNaN support is taken in https://github.com/llvm/llvm-project/pull/193055.
Any feedback is appreciated.