Bug 109934 - [14 Regression] Wrong code at -O3 on x86_64-linux-gnu
Summary: [14 Regression] Wrong code at -O3 on x86_64-linux-gnu
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 14.0
: P1 normal
Target Milestone: 14.0
Assignee: Aldy Hernandez
URL:
Keywords: wrong-code
: 121144 (view as bug list)
Depends on:
Blocks: 117100
  Show dependency treegraph
 
Reported: 2023-05-22 19:39 UTC by Shaohua Li
Modified: 2025-07-17 10:43 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2023-05-22 00:00:00


Attachments
untested patch in testing (1.05 KB, patch)
2023-05-23 10:42 UTC, Aldy Hernandez
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Shaohua Li 2023-05-22 19:39:44 UTC
For the following code, gcc trunk at -O3 emits wrong code.

Compiler explorer: https://godbolt.org/z/3E8xf69rP

$ cat a.c
int printf(const char *, ...);
short a;
long b = 3, c;
int d(int e) {
  switch (e)
  case 111:
  case 222:
  case 44:
    return 0;
  return e;
}
int main() {
  for (; a >= 0; --a)
    if (d(c + 23) - 23)
      b = 0;
  printf("%d\n", (int)b);
}
$
$ gcc-tk -O0 a.c && ./a.out
3
$ gcc-tk -O3 a.c && ./a.out
0
$
$ gcc-tk -v
Using built-in specs.
COLLECT_GCC=gcc-tk
COLLECT_LTO_WRAPPER=/zdata/shaoli/compilers/ccbuilder-compilers/gcc-c09471fbc7588db2480f036aa56a2403d3c03ae5/libexec/gcc/x86_64-pc-linux-gnu/14.0.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../configure --disable-multilib --disable-bootstrap --enable-languages=c,c++ --prefix=/zdata/shaoli/compilers/ccbuilder-compilers/gcc-c09471fbc7588db2480f036aa56a2403d3c03ae5
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 14.0.0 20230521 (experimental) (GCC)
$
Comment 1 Jakub Jelinek 2023-05-22 20:19:03 UTC
Started with r14-862-g76e11280e79c5dd5089c17d5726cae9a5a21bc2e
Comment 2 Aldy Hernandez 2023-05-23 10:41:15 UTC
Woah...this is a latent bug in irange::invert that seems to have been here for a very long time.

In the loop unswitching code we do:

    false_range = true_range;
    if (!false_range.varying_p ()
	&& !false_range.undefined_p ())
      false_range.invert ();

...and get the false_range all wrong:

(gdb) p debug(false_range)
[irange] unsigned int [44, 44][111, 111][222, 222] NONZERO 0xff
$40 = void
(gdb) n
(gdb) n
(gdb) n
(gdb) n
(gdb) p debug(false_range)
[irange] unsigned int [44, +INF]

In no universe is the inverse of the false_range equal to [44, +INF].  Whoops.

This craziness happens here:

  if (m_num_ranges == m_max_ranges
      && lower_bound () != type_min
      && upper_bound () != type_max)
    {
      m_base[1] = type_max;
      m_num_ranges = 1;
      return;
    }

I have no idea what we were trying to do here, but it's clearly wrong.  This probably never triggered because the old legacy code didn't use this code, and the new code used int_range<255> (int_range_max) which made it extremely unlikely this would ever trigger.
Comment 3 Aldy Hernandez 2023-05-23 10:42:30 UTC
Created attachment 55140 [details]
untested patch in testing
Comment 4 GCC Commits 2023-05-23 12:56:48 UTC
The master branch has been updated by Aldy Hernandez <aldyh@gcc.gnu.org>:

https://gcc.gnu.org/g:8d5f050dabbf6dd3b992c3b46661848dbcf30d9e

commit r14-1133-g8d5f050dabbf6dd3b992c3b46661848dbcf30d9e
Author: Aldy Hernandez <aldyh@redhat.com>
Date:   Tue May 23 12:34:45 2023 +0200

    Remove buggy special case in irange::invert [PR109934].
    
    This patch removes a buggy special case in irange::invert which seems
    to have been broken for a while, and probably never triggered because
    the legacy code was handled elsewhere, and the non-legacy code was
    using an int_range_max of int_range<255> which made it extremely
    likely for num_ranges == 255.  However, with auto-resizing ranges,
    int_range_max will start off at 3 and can hit this bogus code in the
    unswitching code.
    
            PR tree-optimization/109934
    
    gcc/ChangeLog:
    
            * value-range.cc (irange::invert): Remove buggy special case.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/pr109934.c: New test.
Comment 5 Aldy Hernandez 2023-05-23 12:59:13 UTC
fixed.  Thanks for reporting.
Comment 6 GCC Commits 2024-10-14 17:54:35 UTC
The releases/gcc-13 branch has been updated by Sam James <sjames@gcc.gnu.org>:

https://gcc.gnu.org/g:a987affa2b10cd8a0b1d244d9f010746837e031c

commit r13-9114-ga987affa2b10cd8a0b1d244d9f010746837e031c
Author: Aldy Hernandez <aldyh@redhat.com>
Date:   Tue May 23 12:34:45 2023 +0200

    Remove buggy special case in irange::invert [PR109934].
    
    This patch removes a buggy special case in irange::invert which seems
    to have been broken for a while, and probably never triggered because
    the legacy code was handled elsewhere, and the non-legacy code was
    using an int_range_max of int_range<255> which made it extremely
    likely for num_ranges == 255.  However, with auto-resizing ranges,
    int_range_max will start off at 3 and can hit this bogus code in the
    unswitching code.
    
            PR tree-optimization/109934
    
    gcc/ChangeLog:
    
            * value-range.cc (irange::invert): Remove buggy special case.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/pr109934.c: New test.
    
    (cherry picked from commit 8d5f050dabbf6dd3b992c3b46661848dbcf30d9e)
Comment 7 GCC Commits 2024-10-14 18:09:42 UTC
The releases/gcc-12 branch has been updated by Sam James <sjames@gcc.gnu.org>:

https://gcc.gnu.org/g:ea7d7818fdc7a49be3d35acd441ce122e8bb477e

commit r12-10766-gea7d7818fdc7a49be3d35acd441ce122e8bb477e
Author: Aldy Hernandez <aldyh@redhat.com>
Date:   Tue May 23 12:34:45 2023 +0200

    Remove buggy special case in irange::invert [PR109934].
    
    This patch removes a buggy special case in irange::invert which seems
    to have been broken for a while, and probably never triggered because
    the legacy code was handled elsewhere, and the non-legacy code was
    using an int_range_max of int_range<255> which made it extremely
    likely for num_ranges == 255.  However, with auto-resizing ranges,
    int_range_max will start off at 3 and can hit this bogus code in the
    unswitching code.
    
            PR tree-optimization/109934
    
    gcc/ChangeLog:
    
            * value-range.cc (irange::invert): Remove buggy special case.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/pr109934.c: New test.
    
    (cherry picked from commit 8d5f050dabbf6dd3b992c3b46661848dbcf30d9e)
Comment 8 Fangrui Song 2025-07-06 19:44:37 UTC
(In reply to GCC Commits from comment #6)
> The releases/gcc-13 branch has been updated by Sam James
> <sjames@gcc.gnu.org>:
> 
> https://gcc.gnu.org/g:a987affa2b10cd8a0b1d244d9f010746837e031c
> 
> commit r13-9114-ga987affa2b10cd8a0b1d244d9f010746837e031c
> Author: Aldy Hernandez <aldyh@redhat.com>
> Date:   Tue May 23 12:34:45 2023 +0200
> 
>     Remove buggy special case in irange::invert [PR109934].
>     
>     This patch removes a buggy special case in irange::invert which seems
>     to have been broken for a while, and probably never triggered because
>     the legacy code was handled elsewhere, and the non-legacy code was
>     using an int_range_max of int_range<255> which made it extremely
>     likely for num_ranges == 255.  However, with auto-resizing ranges,
>     int_range_max will start off at 3 and can hit this bogus code in the
>     unswitching code.
>     
>             PR tree-optimization/109934
>     
>     gcc/ChangeLog:
>     
>             * value-range.cc (irange::invert): Remove buggy special case.
>     
>     gcc/testsuite/ChangeLog:
>     
>             * gcc.dg/tree-ssa/pr109934.c: New test.
>     
>     (cherry picked from commit 8d5f050dabbf6dd3b992c3b46661848dbcf30d9e)

This commit in releases/gcc-13 but not in 13.3.0 has resolved a miscompile I've seen in LLVM llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp.

Worked around in
https://github.com/llvm/llvm-project/commit/6d67794d164ebeedbd287816e1541964fb5d6c99

Requires a -O3 build of llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp (CMAKE_BUILD_TYPE=Release;   RelWithDebInfo uses -O2 and doesn't reproduce)

```
% ninja -C /tmp/out/custom-gcc-13 llc && /tmp/out/custom-gcc-13/bin/llc llvm/test/CodeGen/X86/2008-08-06-RewriterBug.ll -mtriple=i686
ninja: Entering directory `/tmp/out/custom-gcc-13'
ninja: no work to do.
Unknown immediate size
UNREACHABLE executed at /home/ray/llvm/llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h:904!
```

I am curious when the regression started to happen.
Comment 9 Sam James 2025-07-06 19:45:14 UTC
(In reply to Fangrui Song from comment #8)
> I am curious when the regression started to happen.

I think it's probably the same as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117100#c1 (it got broken by a backport that is in 13.3).
Comment 10 Jakub Jelinek 2025-07-17 10:43:23 UTC
*** Bug 121144 has been marked as a duplicate of this bug. ***