Bug 81876 - [7 Regression] bogus -Wstrict-overflow warning with -O3
Summary: [7 Regression] bogus -Wstrict-overflow warning with -O3
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 7.1.0
: P2 normal
Target Milestone: 8.0
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
: 79877 (view as bug list)
Depends on:
Blocks:
 
Reported: 2017-08-17 08:42 UTC by Adrian Bunk
Modified: 2021-08-13 08:45 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work: 6.4.0, 8.1.0
Known to fail: 7.5.0
Last reconfirmed: 2017-12-05 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Adrian Bunk 2017-08-17 08:42:20 UTC
Testcase based on an xbubble build error on Debian:

$ cat test.c
struct _Bubble {
  int color;
};
typedef struct _Bubble * Bubble;

typedef enum {
  EAST=0,
  NORTH_EAST,
  NORTH_WEST,
  WEST,
  SOUTH_WEST,
  SOUTH_EAST
} Quadrant;

struct _CellArray {
  Bubble cell[(8 * 12)];
  int first_row;
};
typedef struct _CellArray * CellArray;

void cell_array_lower( CellArray ca ) {
  int i;

  for ( i = ( ca->first_row*8 ); i < ( ca->first_row*8 ) + 8; i++ )
    ca->cell[i] = ((void *)0);
}
$ gcc-6 -O2 -Wall -Werror -c test.c
$ gcc-6 -O3 -Wall -Werror -c test.c
$ gcc -O2 -Wall -Werror -c test.c
$ gcc -O3 -Wall -Werror -c test.c
test.c: In function ‘cell_array_lower’:
test.c:25:17: error: assuming signed overflow does not occur when assuming that (X + c) >= X is always true [-Werror=strict-overflow]
     ca->cell[i] = ((void *)0);
     ~~~~~~~~~~~~^~~~~~~~~~~~~
cc1: all warnings being treated as errors
$


It works when replacing the "+ 8" in the loop condition with a variable whose value is not known at compile time.
Comment 1 Richard Biener 2017-08-17 09:09:08 UTC
This is the loop distribution generated size argument to memcpy:

  <bb 2> [15.00%]:
  _1 = ca_7(D)->first_row;
  i_8 = _1 * 8;
  _13 = _1 + 1;
  _14 = _13 * 8;
  _17 = (unsigned int) _14;
  _2 = (unsigned int) i_8;
  _3 = _17 - _2;
  _5 = _3 + 4294967295;
  _4 = (sizetype) _5;
  _12 = _4 + 1;
  _11 = _12 * 8;
  _18 = i_8 < _14 ? _11 : 8;
  _19 = _1 * 8;
  _20 = (sizetype) _19;
  _21 = _20 * 8;
  _22 = ca_7(D) + _21;
  __builtin_memset (_22, 0, _18);

which later during forwprop which sees

  <bb 2> [15.00%]:
  _1 = ca_7(D)->first_row;
  i_8 = _1 * 8;
  _14 = i_8 + 8;
  _18 = i_8 < _14 ? 64 : 8;
  _19 = _14 - 8;
  _20 = (sizetype) _19;
  _21 = _20 * 8;
  _22 = ca_7(D) + _21;
  __builtin_memset (_22, 0, _18);

is optimized i_8 < i_8 + 8 -> 1 to

  <bb 2> [15.00%]:
  _1 = ca_7(D)->first_row;
  i_8 = _1 * 8;
  _14 = i_8 + 8;
  _18 = 64;
  _19 = i_8;
  _20 = (sizetype) i_8;
  _21 = _20 * 8;
  _22 = ca_7(D) + _21;
  __builtin_memset (_22, 0, _18);

this warning is somewhat fragile in that it triggers quite randomly and also
on compiler-generated intermediate code in case it gets a location.

Also warns on trunk.

I suppose we should look into niter analysis why it generates that conditional
and/or make sure niter generated GENERIC ends up with TREE_NO_WARNING set
and/or no location.
Comment 2 Jeffrey A. Law 2017-12-04 23:38:48 UTC
I'm a bit unsure how you want to proceed here Richi.

Marc's changes to move key folding patterns from fold-const.c into match.pd means the x + 1 > x  -> 1 simplification happens earlier/more often.  So the problematical sequence gets wiped out by VRP2.   That's probably a good thing.  

However, that bit of match.pd does not warn when it makes that assumption.   One could argue it should.  Of course if it warns, then we end up in situations like this BZ where the warning spit out by GCC bears no resemblance to the actual source code because of ldist or other significant code transformations.

So I could make an argument to drop the 8 from the regression marker.  I could make an argument we should open a new BZ for the missed warning and/or a BZ for getting the code coming out of ldist sane.

Thoughts?
Comment 3 Richard Biener 2017-12-05 08:22:59 UTC
The warning no longer occurs on trunk, re-confirmed on the branch.

I think there's two sides generally

 1) the strict-overflow warnings out of middle-end folding code are just too fragile, we're getting rid of them

 2) the question is what location stmts should have for code generated by GCC
(like that stmts to compute the memset size).  We currently assign a location
near the emission place but one could argue it should be UNKNOWN_LOCATION
(or ARTIFICIAL_LOCATION if there would be sth like this).  We'd then simply
avoid emitting warnings with no good location, aka treating the stmts as
artificial (compiler-generated).

Index: gcc/tree-loop-distribution.c
===================================================================
--- gcc/tree-loop-distribution.c        (revision 255402)
+++ gcc/tree-loop-distribution.c        (working copy)
@@ -813,7 +813,7 @@ generate_memset_builtin (struct loop *lo
   /* The new statements will be placed before LOOP.  */
   gsi = gsi_last_bb (loop_preheader_edge (loop)->src);
 
-  nb_bytes = build_size_arg_loc (loc, partition->main_dr, partition->niter,
+  nb_bytes = build_size_arg_loc (UNKNOWN_LOCATION, partition->main_dr, partition->niter,
                                 partition->plus_one);
   nb_bytes = force_gimple_operand_gsi (&gsi, nb_bytes, true, NULL_TREE,
                                       false, GSI_CONTINUE_LINKING);

changes the warning to

> ./cc1 -quiet t.c -O3 -Wall -Wstrict-overflow
t.c: In function ‘cell_array_lower’:
cc1: warning: assuming signed overflow does not occur when assuming that (X + c) >= X is always true [-Wstrict-overflow]

which shows we also need sth to prune such useless warnings:

Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c    (revision 255402)
+++ gcc/fold-const.c    (working copy)
@@ -265,7 +265,8 @@ fold_undefer_overflow_warnings (bool iss
     locus = input_location;
   else
     locus = gimple_location (stmt);
-  warning_at (locus, OPT_Wstrict_overflow, "%s", warnmsg);
+  if (locus != UNKNOWN_LOCATION)
+    warning_at (locus, OPT_Wstrict_overflow, "%s", warnmsg);
 }
 
 /* Stop deferring overflow warnings, ignoring any deferred

another side-effect might be that we avoid some jumping in gdb if we don't
assign line info to this kind of stmts.
Comment 4 Jeffrey A. Law 2017-12-05 19:05:15 UTC
Richi.

I do worry about cases where we exploit strict-overflow semantics.  It'd be nice to be able to warn about them, but I certainly agree that stability is a problem.  With instability, messaging to and expectations of the user community become serious concerns.  I won't object to moving them out of the middle end.

WRT locations/diagnostics for things like ldist where GCC conjures up code that has little resemblance to what the user wrote.  It's a real issue once we issue the warning -- the user has no clue what it meant.

On the other hand those warnings (particularly those that result from ldist) are highlighting real issues.  Bogus user code, poor optimization, even under-specified language from ISO.  Examples of all can be found in BZ.
Comment 5 rguenther@suse.de 2017-12-06 10:04:45 UTC
On Tue, 5 Dec 2017, law at redhat dot com wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81876
> 
> --- Comment #4 from Jeffrey A. Law <law at redhat dot com> ---
> Richi.
> 
> I do worry about cases where we exploit strict-overflow semantics.  It'd be
> nice to be able to warn about them, but I certainly agree that stability is a
> problem.

The main issue with this warning is that it warns about perfectly valid
code...  IMHO warning about simplifying a_1 + 1 > a_1 is not about
strict-overflow but is in the "comparison is always true" class.  But
suggesting that there's a overflow issue in the code is misleading.

> On the other hand those warnings (particularly those that result from ldist)
> are highlighting real issues.  Bogus user code, poor optimization, even
> under-specified language from ISO.  Examples of all can be found in BZ.

Well...  see above.  Optimization is never perfect and passes doing
code-generation do rely on followup passes to optimize things.
Comment 6 Adrian Bunk 2017-12-06 10:35:50 UTC
(In reply to Jeffrey A. Law from comment #4)
> WRT locations/diagnostics for things like ldist where GCC conjures up code
> that has little resemblance to what the user wrote.  It's a real issue once
> we issue the warning -- the user has no clue what it meant.
> 
> On the other hand those warnings (particularly those that result from ldist)
> are highlighting real issues.  Bogus user code, poor optimization, even
> under-specified language from ISO.  Examples of all can be found in BZ.

If in doubt, don't issue any warning to the user.

As far as I am aware, the testcase in this bug does not warrant any warning in that line - even "comparison is always true" would be wrong.

If a warning option sometimes generates bogus warnings for issues not present in the code, the only reasonable option for a user would be to always disable this warning.
Comment 7 Richard Biener 2018-01-25 08:26:58 UTC
GCC 7.3 is being released, adjusting target milestone.
Comment 8 Richard Biener 2019-11-14 10:17:39 UTC
Doesn't occur with GCC 8.
Comment 9 Andrew Pinski 2021-08-13 08:45:43 UTC
*** Bug 79877 has been marked as a duplicate of this bug. ***