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

Reply via email to