public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
From: "matz at gcc dot gnu.org" <gcc-bugzilla@gcc.gnu.org>
To: gcc-bugs@gcc.gnu.org
Subject: [Bug middle-end/108742] New: Incorrect constant folding with (or exposed by) -fexcess-precision=standard
Date: Thu, 09 Feb 2023 15:50:25 +0000	[thread overview]
Message-ID: <bug-108742-4@http.gcc.gnu.org/bugzilla/> (raw)

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108742

            Bug ID: 108742
           Summary: Incorrect constant folding with (or exposed by)
                    -fexcess-precision=standard
           Product: gcc
           Version: 12.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: matz at gcc dot gnu.org
  Target Milestone: ---

This came from a discussion about a user wondering why g++ behaved different
between GCC 12 and GCC 13, regarding equality comparisons of floating point
values on x87, i.e. -m32, which ultimately was because GCC 13 activated
-fexcess-precision=standard with -std=c++17.  Now this is not in itself
surprising, but I think something is still wrong.  From commit
98e341130f87984af07c884fea773c0bb3cc8821 (adding this to c++17):

...
    The existing testcases tweaks were for cases on i686-linux where excess
    precision breaks those tests, e.g. if we have
      double d = 4.2;
      if (d == 4.2)
    then it does the expected thing only with -fexcess-precision=fast,
    because with -fexcess-precision=standard it is actually
      double d = 4.2;
      if ((long double) d == 4.2L)
    where 4.2L is different from 4.2.
...

And indeed a simple testcase about this (for C, but it demonstrates the same
thing): 
% cat float.c
#define bool _Bool
int main()
{
  double d = 4.2;

  bool eq1 = (long double)d == (long double)4.2;
  bool eq2 = (long double)d == 4.2L;
  bool eq3 = (long double)d == (long double)(double)4.2;

  __builtin_printf ("equal: %d/%d/%d\n", eq1, eq2, eq3);
  __builtin_printf ("1: %La\n", 4.2L);
  __builtin_printf ("2: %La\n", (long double)4.2);
  __builtin_printf ("3: %La\n", (long double)(double)4.2);

  return 0;
}
% gcc -m32 -O0 -fexcess-precision=fast -o fast float.c
% gcc -m32 -O0 -fexcess-precision=standard -o standard float.c
% ./fast
equal: 1/0/1
1: 0x8.666666666666666p-1
2: 0x8.6666666666668p-1
3: 0x8.6666666666668p-1
% ./standard
equal: 0/0/1
1: 0x8.666666666666666p-1
2: 0x8.666666666666666p-1
3: 0x8.6666666666668p-1


The bug I think exists is that also with =standard the first comparison
should yield 'true' and that irrespective of the excess-prec setting result (2)
should always be the same as (3).  As the comment for the commit correctly
says:
   (long double)4.2 != 4.2L
hence, even with -fexcess-precision=standard the former should _not_ be
const-folded into the latter, but rather into the exact long double value that
corresponds to (double)4.2.  Namely:

(gdb) p/x (long double)4.2
$1 = 0x40018666666666666800
(gdb) p/x (long double)4.2L
$2 = 0x40018666666666666666

The former is the correct long double value to use for the casted double
literal, not the latter.

IOW: it's fine that -fexcess-precision=standard tries to emulate the excess
precision on the hardware by doing all arithmetics in the larger type.  But
then
also the constants need to be folded exactly as the hardware would be doing.

In still other words: I think we have a bug in our constant folders and I don't
think it has anything directly to do with -fexcess-precision=standard, but is
merely exposed by it.  The wrong value is already present in 005t.original:

  __builtin_printf ((const char *) "1: %La\n",
4.19999999999999999982652765240231929055880755186080932617e+0);
  __builtin_printf ((const char *) "2: %La\n",
4.19999999999999999982652765240231929055880755186080932617e+0);
  __builtin_printf ((const char *) "3: %La\n",
4.20000000000000017763568394002504646778106689453125e+0);

             reply	other threads:[~2023-02-09 15:50 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-09 15:50 matz at gcc dot gnu.org [this message]
2023-02-09 15:56 ` [Bug middle-end/108742] " marxin at gcc dot gnu.org
2023-02-09 16:06 ` [Bug target/108742] " jakub at gcc dot gnu.org
2023-02-09 16:10 ` jakub at gcc dot gnu.org
2023-02-09 16:19 ` matz at gcc dot gnu.org
2023-02-09 16:25 ` jakub at gcc dot gnu.org
2023-02-09 16:31 ` jakub at gcc dot gnu.org
2023-02-09 16:34 ` jakub at gcc dot gnu.org
2023-02-09 16:52 ` matz at gcc dot gnu.org
2023-02-09 17:00 ` matz at gcc dot gnu.org
2023-02-09 17:01 ` jakub at gcc dot gnu.org
2023-02-09 17:13 ` matz at gcc dot gnu.org
2023-02-09 17:26 ` joseph at codesourcery dot com
2023-06-29  8:04 ` pinskia at gcc dot gnu.org
2023-06-29 10:59 ` pdimov at gmail dot com
2023-06-30  7:28 ` mkretz at gcc dot gnu.org
2023-06-30  7:36 ` jakub at gcc dot gnu.org

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=bug-108742-4@http.gcc.gnu.org/bugzilla/ \
    --to=gcc-bugzilla@gcc.gnu.org \
    --cc=gcc-bugs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).