llvm / llvm/llvm-project

`const`/`constexpr` INFINITY can cause clang to make a different result from `inf/inf` or `inf-inf`

Open
#165,989 5 comments 0 reactions 0 assignees View on GitHub
clang:frontend
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

_Title_.

The usual result from `inf/inf` or `inf-inf` is a negative NaN, but when I use a `const` infinity clang calculates it in compile-time and saves a positive NaN for runtime use

`Ubuntu GCC 13.3.0`(`gcc -std=gnu2x minimal.c -lm`) didn't have the issue but `Ubuntu clang 18` and `Ubuntu clang 20` showed the symptom.

The CPU I use is Haswell.

I think you can reproduce the symptom with the code below ( `clang minimal.c -std=gnu23 -lm` )
```c
#include
#include
#include

/*
* \brief for little endian systems
*/
union ieee754_binary32 {
struct {
uint32_t fraction: 23;
uint16_t exponent: 8;
uint8_t sign: 1;
};
float whole;
};

int main(int argc, char * argv[])
{
float inf = INFINITY;
float nan = NAN;

#if __clang_major__ <= 18
const float cinf = INFINITY;
const float cnan = NAN;
#else
constexpr float cinf = INFINITY;
constexpr float cnan = NAN;
#endif

fprintf( stdout, "inf - inf = %f\n", (inf - inf) );
fprintf( stdout, "const_inf - const_inf = %f\n", (cinf - cinf) );
union ieee754_binary32 inspector = {.whole=(cinf - cinf)};
fprintf( stdout, "inspector = {.whole=(const_inf - const_inf)}; inspector.sign = %u\n", inspector.sign );

fprintf( stdout, "inf / inf = %f\n", (inf / inf) );
inspector.whole = (inf / inf);
fprintf( stdout, "inspector = {.whole=(inf / inf)}; inspector.sign = %u\n", inspector.sign );
fprintf( stdout, "const_inf / const_inf = %f\n", (cinf / cinf) );

inspector.whole = (cinf / cinf);
fprintf( stdout, "inspector = {.whole=(const_inf / const_inf)}; inspector.sign = %u\n", inspector.sign );

return 0;
}
```

The output from clang-built binaries:
```c
inf - inf = -nan
const_inf - const_inf = nan
inspector = {.whole=(const_inf - const_inf)}; inspector.sign = 0
inf / inf = -nan
inspector = {.whole=(inf / inf)}; inspector.sign = 1
const_inf / const_inf = nan
inspector = {.whole=(const_inf / const_inf)}; inspector.sign = 0
```

The output from a GCC-built binary:
```c
inf - inf = -nan
const_inf - const_inf = -nan
inspector = {.whole=(const_inf - const_inf)}; inspector.sign = 1
inf / inf = -nan
inspector = {.whole=(inf / inf)}; inspector.sign = 1
const_inf / const_inf = -nan
inspector = {.whole=(const_inf / const_inf)}; inspector.sign = 1
```

Thank you so much!

Contributor guide

Open the contributing guide

Research direction

Start by compiling the provided minimal.c reproducer with Ubuntu clang 18 or 20 using the shown clang -std=gnu23 -lm command, then compare its const/constexpr results with runtime inf-inf and inf/inf. The issue is resolved when the relevant constant-folded results match the expected IEEE sign behavior demonstrated by the GCC output.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.