https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94981
Bug ID: 94981 Summary: Wrong casts on Power machines dealing with fctiwuz instruction Product: gcc Version: 9.3.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: tony.reix at atos dot net Target Milestone: --- There are several issues dealing with GCC 8.30 and 9.3.0 (and also 10), for C and C++, on AIX and Fedora/PPC64LE . This appears when casting a float/double/long-double to an unsigned type, with different cases. This is related to the assembly instruction fctiwuz . Here are 3 programs showing all the cases, with a reference to Fedora/x86_64. Also, it looks like there are missing tests in GCC. # cat double.c #include <stdio.h> int main() { double d = -2; char c = (char)d; signed char sc = (signed char)d; printf("%d\n", (int)c); printf("%d\n", (int)sc); return 0; } # cat vector.cc #include <vector> #include <iostream> double const dbl[4] = { 10, -1, -2, 4 }; int main() { double d = -2; char c = (char)d; std::cout << (int)c << std::endl; std::vector<char> v(&dbl[0], &dbl[4]); for (auto it = begin (v); it != end (v); ++it) { std::cout << (int)*it << std::endl; } return 0; } Bug is same if "char" is replaced by "unsigned short" or "unsigned int". So, the issue seems to appear on: - AIX when converting a "double", a "float", or a long double" toward: char, unsigned char, unsigned short, unsigned int, unsigned long in 32-bit and 64-bit. - Linux/Power when converting a "double" or a "float" toward an "unsigned" type. On AIX and Linux/Power. double -2 --> char float -2 --> char C | C++ --------------|-----------|---------------|-----------------|-----------|---------------|-----------------| | Default | -fsigned-char | -funsigned-char | Default | -fsigned-char | -funsigned-char | --------------|-----------|---------------|-----------------|-----------|---------------|-----------------| Fedora/x86_64 | signed | signed | 9.3.1 20200408| -2 | -2 | 254 | -2 | -2 | 254 | --------------|-----------|---------------|-----------------|-----------|---------------|-----------------| Fedora/Power | signed, but: neg zeroed | signed, but: neg zeroed | 9.3.1 20200408| 0 | -2 | 0 | 0 | -2 | 0 | BUG --------------|-----------|---------------|-----------------|-----------|---------------|-----------------| AIX | | | 6.3.0 | unsigned | unsigned | | 254 | -2 | 254 | 254 | -2 | 254 | 8.4.0 & 9.3.0 | signed, but: neg zeroed | signed, but: neg zeroed | | 0 | -2 | 0 | 0 | -2 | 0 | BUG !! --------------|-----------|---------------|-----------------|-----------|---------------|-----------------| long double -2 --> char C | C++ --------------|-----------|---------------|-----------------|-----------|---------------|-----------------| | Default | -fsigned-char | -funsigned-char | Default | -fsigned-char | -funsigned-char | --------------|-----------|---------------|-----------------|-----------|---------------|-----------------| Fedora/x86_64 | signed | signed | 9.3.1 20200408| -2 | -2 | 254 | -2 | -2 | 254 | --------------|-----------|---------------|-----------------|-----------|---------------|-----------------| Fedora/Power | unsigned | unsigned | 9.3.1 20200408| 254 | -2 | 254 | 254 | -2 | 254 | BUG ?? --------------|-----------|---------------|-----------------|-----------|---------------|-----------------| AIX | | | 6.3.0 | unsigned | unsigned | | 254 | -2 | 254 | 254 | -2 | 254 | 8.4.0 & 9.3.0 | signed, but: neg zeroed | signed, but: neg zeroed | | 0 | -2 | 0 | 0 | -2 | 0 | BUG ! --------------|-----------|---------------|-----------------|-----------|---------------|-----------------| # cat cast.c #include <stdio.h> int main() { float f = -2; double d = -2; long double ld = -2; char c; unsigned char uc; unsigned short us; unsigned int ui; unsigned long ul; printf(" %5s %5s %5s %5s %5s\n", "c", "uc", "us", "ui", "ul"); c = (char)f; uc = (unsigned char)f; us = (unsigned short)f; ui = (unsigned int)f; ul = (unsigned long)f; printf("float: %5d %5d %5d %5d %5d\n", (int)c, (int)uc, (int)us, (int)ui, (int)ul); c = (char)d; uc = (unsigned char)d; us = (unsigned short)d; ui = (unsigned int)d; ul = (unsigned long)d; printf("double: %5d %5d %5d %5d %5d\n", (int)c, (int)uc, (int)us, (int)ui, (int)ul); c = (char)ld; uc = (unsigned char)ld; us = (unsigned short)ld; ui = (unsigned int)ld; ul = (unsigned long)ld; printf("long double: %5d %5d %5d %5d %5d\n", (int)c, (int)uc, (int)us, (int)ui, (int)ul); return 0; } Fedora/x86_64 : OK c uc us ui ul float: -2 254 65534 -2 -2 double: -2 254 65534 -2 -2 long double: -2 254 65534 -2 -2 Fedora/Power : KO c uc us ui ul float: 0 0 0 0 0 double: 0 0 0 0 0 long double: 254 254 65534 -2 0 AIX GCC 6.3.0 : OK c uc us ui ul float: 254 254 65534 -2 -2 double: 254 254 65534 -2 -2 long double: 254 254 65534 -2 -2 AIX GCC 8.4.0 & 9.3.0 32bit or 64bit : KO c uc us ui ul float: 0 0 0 0 0 double: 0 0 0 0 0 long double: 0 0 0 0 0