https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128460
Bug ID: 128460
Summary: wrong code at -O1: (float)(_Decimal32)f is folded to
f, losing the decimal rounding
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: middle-end
Assignee: unassigned at gcc dot gnu.org
Reporter: jeffchen006 at gmail dot com
Target Milestone: ---
Target: x86_64-pc-linux-gnu
int printf(const char *, ...);
float f = 16777215;
int main(void)
{
_Decimal32 d = f;
float r = d;
printf("%f\n", r);
return 0;
}
$ gcc -O0 t.c && ./a.out
16777220.000000
$ gcc -O1 t.c && ./a.out
16777215.000000
-O1, -O2, -O3 all fail.
Expected: 16777220.000000. 16777215 has 8 significant digits. Converting it to
_Decimal32 (7 digits) gives 1.677722E+7 (tie, round to even), and converting
that back to float gives 16777220.
The conversion-chain rule in match.pd ("(inter_float && inside_float) ...
inter_prec >= inside_prec") treats float and _Decimal32 as the same precision
(32), so the round trip looks like a no-op. FLOAT_TYPE_P is true for decimal
types and the rule has no DECIMAL_FLOAT_TYPE_P check. Requiring
DECIMAL_FLOAT_TYPE_P (inter_type) == DECIMAL_FLOAT_TYPE_P (type), and the same
for inside_type, fixes it. Written as one expression, (float)(_Decimal32)f is
wrong at -O0 too.
Wrong on 8.5.0, 10.5.0, 12.5.0, 13.4.0, 14.3.0, 15.2.0, 16.2.0, trunk.
-O0 -fsanitize=undefined,address is clean.
gcc version 17.0.0 20261029 (experimental), r17-5747-g85867b0c935,
x86_64-pc-linux-gnu
Configured with: --enable-languages=c,c++ --disable-multilib
--disable-bootstrap --enable-checking=release