Bug 112305 - [12/13 Regression] Wrong code at -O1/2/3/s on x86_64-pc-linux-gnu
Summary: [12/13 Regression] Wrong code at -O1/2/3/s on x86_64-pc-linux-gnu
Status: ASSIGNED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 14.0
: P2 normal
Target Milestone: 13.4
Assignee: Richard Biener
URL:
Keywords: wrong-code
Depends on: 112320
Blocks:
  Show dependency treegraph
 
Reported: 2023-10-31 06:51 UTC by Junwei Zeng
Modified: 2024-07-19 12:49 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work: 14.0, 8.1.0
Known to fail: 11.4.0, 9.1.0
Last reconfirmed: 2023-10-31 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Junwei Zeng 2023-10-31 06:51:04 UTC
I compiled the following code with gcc at -O1/2/3/s, and it produces the wrong code. The correct output result should be -1560359471, but -486617677 was output under -O1/2/3/s.
I found this bug was introduced starting from gcc-13.1

Compiler explorer: https://godbolt.org/z/s7K9z5166

```c
$ cat test.c
int printf(const char *, ...);
int a;
void b() {
  long c = 3;
  unsigned int d = 50253292;
  int e = 2147483648;
  for (; a < 5; a++)
    do {
      e += 4;
      d -= c;
    } while (e < 20);
  printf("%d\n", d);
}
int main() { b(); }
$
$ gcc-tk test.c -O0; ./test.c
-1560359471
$ gcc-tk test.c -O1; ./test.c
-486617677
$ gcc-tk test.c -O2; ./test.c
-486617677
$ gcc-tk test.c -O3; ./test.c
-486617677
$ gcc-tk test.c -Os; ./test.c
-486617677
$ ccomp test.c -O1; ./a.out
-1560359471
$
$ gcc-tk --version
gcc (GCC) 14.0.0 20231028 (experimental) [master r14-4987-g7f974c5fd4]
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$
$ ccomp --version
The CompCert C verified compiler, version 3.12
```
Comment 1 Andrew Pinski 2023-10-31 07:02:24 UTC
Confirmed, -ftree-scev-cprop seems like is introducing the "undefined" signed integer overflow code ...
Comment 2 Andrew Pinski 2023-10-31 07:07:47 UTC
For -O2, the bug has been present since at least 9.1.0. -O1 started to expose it in GCC 12 though.

-fwrapv works around the issue.
-fno-tree-scev-cprop does too.
Comment 3 Andrew Pinski 2023-10-31 07:08:57 UTC
Just mention that -fsanitize=undefined is clean with GCC and clang too.
Comment 4 Richard Biener 2023-10-31 09:10:20 UTC
final value replacement introduces

   <bb 5> [local count: 118111600]:
-  # e_14 = PHI <e_10(4)>
-  # d_23 = PHI <d_11(4)>
+  _7 = e_20 + 4;
+  _12 = e_20 <= 19;
+  _25 = (unsigned int) e_20;
+  _26 = 19 - _25;
+  _27 = _26 / 4;
+  _28 = (int) _27;
+  _29 = _28 * 4;
+  _30 = _12 ? _29 : 0;
+  e_14 = _7 + _30;
+  _31 = e_20 <= 19;
+  _32 = (unsigned int) e_20;
+  _33 = 19 - _32;
+  _34 = _33 / 4;
+  _35 = _34 * 4294967293;
+  _36 = _31 ? _35 : 0;
+  _37 = d_19 + _36;
+  d_23 = _37 + 4294967293;

which is e_20 + 4 + (e_20 <= 19 ? 4 * (int)((19 - (unsigned int) e_20) / 4): 0)
and ((e_20 <= 19 ? ((19 - (unsigned int) e_20) / 4) * 4294967293 : 0) + d_19) + 4294967293

I think there's another bug noting that final value replacement with
COND_EXPRs should eventually materialize control-flow.

I have a patch to do more rewriting to unsigned instead.
Comment 5 GCC Commits 2023-10-31 12:10:21 UTC
The master branch has been updated by Richard Biener <rguenth@gcc.gnu.org>:

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

commit r14-5032-ge3da1d7bb288c8c864f0284bc4bc5877b466a2f7
Author: Richard Biener <rguenther@suse.de>
Date:   Tue Oct 31 10:13:13 2023 +0100

    tree-optimization/112305 - SCEV cprop and conditional undefined overflow
    
    The following adjusts final value replacement to also rewrite the
    replacement to defined overflow behavior if there's conditionally
    evaluated stmts (with possibly undefined overflow), not only when
    we "folded casts".  The patch hooks into expression_expensive for
    this.
    
            PR tree-optimization/112305
            * tree-scalar-evolution.h (expression_expensive): Adjust.
            * tree-scalar-evolution.cc (expression_expensive): Record
            when we see a COND_EXPR.
            (final_value_replacement_loop): When the replacement contains
            a COND_EXPR, rewrite it to defined overflow.
            * tree-ssa-loop-ivopts.cc (may_eliminate_iv): Adjust.
    
            * gcc.dg/torture/pr112305.c: New testcase.
Comment 6 Jakub Jelinek 2024-05-21 09:18:07 UTC
GCC 13.3 is being released, retargeting bugs to GCC 13.4.