https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122770
Bug ID: 122770
Summary: gcc doesn't trigger FE_INVALID when the
arithmetic/logical operation is considered INVALID in
compliance with IEEE-754 Section-7.2
Product: gcc
Version: 14.1.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: mohamed.selim at dxc dot com
Target Milestone: ---
GCC doesn't seem to comply with IEEE-754 Section 7.2 on INVALID operation.
The section 7.2 according to IEEE-754, found in:
(https://www.gnu.org/software/libc/manual/html_node/FP-Exceptions.html)
(https://www-users.cse.umn.edu/~vinals/tspot_files/phys4041/2020/IEEE%20Standard%20754-2019.pdf)
The exceptions defined in IEEE 754 are:
‘Invalid Operation’
This exception is raised if the given operands are invalid for the operation to
be performed. Examples are (see IEEE 754, section 7):
1-Addition or subtraction: ∞ - ∞. (But ∞ + ∞ = ∞).
2-Multiplication: 0 · ∞.
3-Division: 0/0 or ∞/∞.
4-Remainder: x REM y, where y is zero or x is infinite.
5-Square root if the operand is less than zero. More generally, any
mathematical function evaluated outside its domain produces this exception.
6-Conversion of a floating-point number to an integer or decimal string,
when the number cannot be represented in the target format (due to overflow,
infinity, or NaN).
7-Conversion of an unrecognizable input string.
8-Comparison via predicates involving < or >, when one or other of the
operands is NaN. You can prevent this exception by using the unordered
comparison functions instead.
It seems that GCC 14.1.0 deosn't raise the FE_INVALID on points 6 and 8, with
the following results:
(pinf >= qnan): 0
No Exception reported
(zero <= snan): 0
No Exception reported
static_cast<std::int32_t>(some_finite_large_double): 2147483647
No Exception reported
for the program
```
const auto pinf = std::numeric_limits<double>::infinity();
const auto ninf = std::copysign(pinf, -1.0);
const auto qnan = std::numeric_limits<double>::quiet_NaN();
const auto snan = std::numeric_limits<double>::signaling_NaN();
constexpr auto some_finite_large_double{
598008216632976371697735644702348584536405246902083247220875921706093794716375762404103004004990504111786204800430166155026589905240121409306972824498630058082565445957748647537262486126146850127872.0};
const double zero{0.0};
// see point 8
{
volatile auto result = (pinf >= qnan);
fe_status = check_fe();
std::cout << "\n";
std::cout << "(pinf >= qnan): " << result << "\n";
std::cout << fe_status << "\n";
}
// see point 8
{
volatile auto result = (zero <= snan);
fe_status = check_fe();
std::cout << "\n";
std::cout << "(zero <= snan): " << result << "\n";
std::cout << fe_status << "\n";
}
// see point 6
{
volatile auto result =
static_cast<std::int32_t>(some_finite_large_double);
fe_status = check_fe();
std::cout << "\n";
std::cout << "static_cast<std::int32_t>(double): " << result << "\n";
std::cout << fe_status << "\n";
}
```
gcc command:
`g++-14 -o test -std=c++17 fe_invalid.cpp -O2 -frounding-math -fsignaling-nans
-ftrapping-math -fno-builtin -fno-strict-aliasing -fwrapv`
So, for comaparison of NaNs and quantization for finite large numbers, e.g.
casting to smaller int32_t. The gcc is not reporting/triggering FE_INVALID
While with clang using `-ffp-exception-behavior=strict`, all of the them report
FE_INVALID as expected.
```
clang++-19 -o test -std=c++20 fe_invalid.cpp -O2 -ffp-exception-behavior=strict
&& ./test
...
(pinf >= qnan): 0
FE_INVALID
(zero <= snan): 0
FE_INVALID
static_cast<std::int32_t>(double): -2147483648
FE_INVALID
```
Using clang command:
`clang++-19 -o test -std=c++20 fe_invalid.cpp -O2
-ffp-exception-behavior=strict`
The results are consistent between x86-64, armv8.1-a and armv9.2-a