[PATCH] Remove -fstrict-overflow, default to undefined signed integer and pointer overflow

Richard Biener rguenther@suse.de
Wed Apr 26 12:03:00 GMT 2017


The following removes the third state we had apart from signed integer
overflow wrapping and being undefined.  It makes signed integer overflow
undefined, consistently at all optimization levels.  -fno-strict-overflow
stays as a backward compatible way to avoid optimizations that rely on
signed integer overflow being undefined by making it wrapping
(this is also the reason of using !flag_wrapv in 
POINTER_TYPE_OVERFLOW_UNDEFINED rather than a new option, for now).

Surprisingly there's no UBSAN integer overflow testsuite fallout,
foldings that happen before instrumentation (which is done after
into-SSA) and rely on signed integer overflow being undefined will
cause false negatives.  If that turns out to be a problem the
flag_strict_overflow flag can be re-introduced (not that this would
be my preference) and it can be unset after UBSAN instrumentation
is finished.

The main motivation for aliasing -fstrict-overflow to -f[no-]wrapv
is that with -fno-strict-overflow (and thus -O1 at the moment) you get
the worst of both worlds, you can't optimize based on the undefinedness
but you also cannot rely on wrapping behavior (to know that 
re-association will not introduce undefined behavior).  Using -fwrapv
for -fno-strict-overflow makes it clear what the semantics are.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

I opened PR80525 for the appearant mishandling of (a + 1) && (a + 1)
with -Wlogical-op when overflow is undefined.

If there are no further comments I plan to install this after 7.1
is released.  I consider the Ada FE change obvious.

The next step is to get rid of all that ugly -Wstrict-overflow code
in VRP.  strict-overflow warnings from folding were already
detoriating with moving stuff to match.pd where it isn't easy to
preserve those.  Ripping those out can be done later, it's not
blocking other stuff, and eventually somebody picks up -Wstrict-overflow
to warn for some cases from the FEs.

changes.html/porting_to.html will need to have instructions how to
use ubsan to get at the real problems in code.

Thanks,
Richard.

2017-04-26  Richard Biener  <rguenther@suse.de>

	* common.opt (fstrict-overflow): Alias negative to fwrapv.
	* doc/invoke.texi (fstrict-overflow): Remove all traces of
	-fstrict-overflow documentation.
	* tree.h (TYPE_OVERFLOW_UNDEFINED): Do not test flag_strict_overflow.
	(POINTER_TYPE_OVERFLOW_UNDEFINED): Test !flag_wrapv instead of
	flag_strict_overflow.
	* ipa-inline.c (can_inline_edge_p): Do not test flag_strict_overflow.
	* lto-opts.c (lto_write_options): Do not stream it.
	* lto-wrapper.c (merge_and_complain): Do not handle it.
	* opts.c (default_options_table): Do not set -fstrict-overflow.
	(finish_options): Likewise do not clear it when sanitizing.
	* simplify-rtx.c (simplify_const_relational_operation): Do not
	test flag_strict_overflow.

	ada/
	* gcc-interface/misc.c (gnat_post_options): Do not set
	-fstrict-overflow.

	* c-c++-common/Wlogical-op-1.c: Add -fwrapv to restore previous
	behavior.
	* gcc.target/i386/pr46253.c: Make i unsigned to avoid warning.

Index: gcc/ada/gcc-interface/misc.c
===================================================================
--- gcc/ada/gcc-interface/misc.c	(revision 247273)
+++ gcc/ada/gcc-interface/misc.c	(working copy)
@@ -266,10 +266,6 @@ gnat_post_options (const char **pfilenam
   if (!global_options_set.x_flag_diagnostics_show_caret)
     global_dc->show_caret = false;
 
-  /* Set strict overflow by default for Ada.  */
-  if (!global_options_set.x_flag_strict_overflow)
-    global_options.x_flag_strict_overflow = true;
-
   /* Warn only if STABS is not the default: we don't want to emit a warning if
      the user did not use a -gstabs option.  */
   if (PREFERRED_DEBUGGING_TYPE != DBX_DEBUG && write_symbols == DBX_DEBUG)
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 247273)
+++ gcc/common.opt	(working copy)
@@ -2342,8 +2342,8 @@ Common Report Var(flag_strict_aliasing)
 Assume strict aliasing rules apply.
 
 fstrict-overflow
-Common Report Var(flag_strict_overflow) Optimization
-Treat signed overflow as undefined.
+Common NegativeAlias Alias(fwrapv)
+Treat signed overflow as undefined.  Negated as -fwrapv.
 
 fsync-libcalls
 Common Report Var(flag_sync_libcalls) Init(1)
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 247273)
+++ gcc/doc/invoke.texi	(working copy)
@@ -420,7 +420,7 @@ Objective-C and Objective-C++ Dialects}.
 -fsplit-paths @gol
 -fsplit-wide-types  -fssa-backprop  -fssa-phiopt @gol
 -fstdarg-opt  -fstore-merging  -fstrict-aliasing @gol
--fstrict-overflow  -fthread-jumps  -ftracer  -ftree-bit-ccp @gol
+-fthread-jumps  -ftracer  -ftree-bit-ccp @gol
 -ftree-builtin-call-dce  -ftree-ccp  -ftree-ch @gol
 -ftree-coalesce-vars  -ftree-copy-prop  -ftree-dce  -ftree-dominator-opts @gol
 -ftree-dse  -ftree-forwprop  -ftree-fre  -fcode-hoisting @gol
@@ -4937,7 +4937,7 @@ Does not warn about incomplete types.
 @itemx -Wstrict-overflow=@var{n}
 @opindex Wstrict-overflow
 @opindex Wno-strict-overflow
-This option is only active when @option{-fstrict-overflow} is active.
+This option is only active when signed overflow is undefined.
 It warns about cases where the compiler optimizes based on the
 assumption that signed overflow does not occur.  Note that it does not
 warn about all cases where the code might overflow: it only warns
@@ -4957,7 +4957,7 @@ executed at all.
 @table @gcctabopt
 @item -Wstrict-overflow=1
 Warn about cases that are both questionable and easy to avoid.  For
-example,  with @option{-fstrict-overflow}, the compiler simplifies
+example the compiler simplifies
 @code{x + 1 > x} to @code{1}.  This level of
 @option{-Wstrict-overflow} is enabled by @option{-Wall}; higher levels
 are not, and must be explicitly requested.
@@ -4965,7 +4965,7 @@ are not, and must be explicitly requeste
 @item -Wstrict-overflow=2
 Also warn about other cases where a comparison is simplified to a
 constant.  For example: @code{abs (x) >= 0}.  This can only be
-simplified when @option{-fstrict-overflow} is in effect, because
+simplified when signed integer overflow is undefined, because
 @code{abs (INT_MIN)} overflows to @code{INT_MIN}, which is less than
 zero.  @option{-Wstrict-overflow} (with no level) is the same as
 @option{-Wstrict-overflow=2}.
@@ -7113,7 +7113,7 @@ also turns on the following optimization
 -fsched-interblock  -fsched-spec @gol
 -fschedule-insns  -fschedule-insns2 @gol
 -fstore-merging @gol
--fstrict-aliasing -fstrict-overflow @gol
+-fstrict-aliasing @gol
 -ftree-builtin-call-dce @gol
 -ftree-switch-conversion -ftree-tail-merge @gol
 -fcode-hoisting @gol
@@ -8649,41 +8649,6 @@ int f() @{
 The @option{-fstrict-aliasing} option is enabled at levels
 @option{-O2}, @option{-O3}, @option{-Os}.
 
-@item -fstrict-overflow
-@opindex fstrict-overflow
-Allow the compiler to assume strict signed overflow rules, depending
-on the language being compiled.  For C (and C++) this means that
-overflow when doing arithmetic with signed numbers is undefined, which
-means that the compiler may assume that it does not happen.  This
-permits various optimizations.  For example, the compiler assumes
-that an expression like @code{i + 10 > i} is always true for
-signed @code{i}.  This assumption is only valid if signed overflow is
-undefined, as the expression is false if @code{i + 10} overflows when
-using twos complement arithmetic.  When this option is in effect any
-attempt to determine whether an operation on signed numbers 
-overflows must be written carefully to not actually involve overflow.
-
-This option also allows the compiler to assume strict pointer
-semantics: given a pointer to an object, if adding an offset to that
-pointer does not produce a pointer to the same object, the addition is
-undefined.  This permits the compiler to conclude that @code{p + u >
-p} is always true for a pointer @code{p} and unsigned integer
-@code{u}.  This assumption is only valid because pointer wraparound is
-undefined, as the expression is false if @code{p + u} overflows using
-twos complement arithmetic.
-
-See also the @option{-fwrapv} option.  Using @option{-fwrapv} means
-that integer signed overflow is fully defined: it wraps.  When
-@option{-fwrapv} is used, there is no difference between
-@option{-fstrict-overflow} and @option{-fno-strict-overflow} for
-integers.  With @option{-fwrapv} certain types of overflow are
-permitted.  For example, if the compiler gets an overflow when doing
-arithmetic on constants, the overflowed value can still be used with
-@option{-fwrapv}, but not otherwise.
-
-The @option{-fstrict-overflow} option is enabled at levels
-@option{-O2}, @option{-O3}, @option{-Os}.
-
 @item -falign-functions
 @itemx -falign-functions=@var{n}
 @opindex falign-functions
Index: gcc/ipa-inline.c
===================================================================
--- gcc/ipa-inline.c	(revision 247273)
+++ gcc/ipa-inline.c	(working copy)
@@ -404,14 +404,7 @@ can_inline_edge_p (struct cgraph_edge *e
       /* There are some options that change IL semantics which means
          we cannot inline in these cases for correctness reason.
 	 Not even for always_inline declared functions.  */
-      /* Strictly speaking only when the callee contains signed integer
-         math where overflow is undefined.  */
-     else if ((check_maybe_up (flag_strict_overflow)
-	       /* this flag is set by optimize.  Allow inlining across
-		  optimize boundary.  */
-	       && (!opt_for_fn (caller->decl, optimize)
-		   == !opt_for_fn (callee->decl, optimize) || !always_inline))
-	      || check_match (flag_wrapv)
+     else if (check_match (flag_wrapv)
 	      || check_match (flag_trapv)
 	      /* When caller or callee does FP math, be sure FP codegen flags
 		 compatible.  */
Index: gcc/lto-opts.c
===================================================================
--- gcc/lto-opts.c	(revision 247273)
+++ gcc/lto-opts.c	(working copy)
@@ -133,10 +133,6 @@ lto_write_options (void)
   if (!global_options_set.x_flag_trapv
       && !global_options.x_flag_trapv)
     append_to_collect_gcc_options (&temporary_obstack, &first_p, "-fno-trapv");
-  if (!global_options_set.x_flag_strict_overflow
-      && !global_options.x_flag_strict_overflow)
-    append_to_collect_gcc_options (&temporary_obstack, &first_p,
-			       "-fno-strict-overflow");
 
   if (!global_options_set.x_flag_openmp
       && !global_options.x_flag_openmp)
Index: gcc/lto-wrapper.c
===================================================================
--- gcc/lto-wrapper.c	(revision 247273)
+++ gcc/lto-wrapper.c	(working copy)
@@ -258,7 +258,6 @@ merge_and_complain (struct cl_decoded_op
 	  break;
 
 	case OPT_ftrapv:
-	case OPT_fstrict_overflow:
 	case OPT_ffp_contract_:
 	  /* For selected options we can merge conservatively.  */
 	  for (j = 0; j < *decoded_options_count; ++j)
@@ -522,7 +521,6 @@ append_compiler_options (obstack *argv_o
 	case OPT_fopenacc_dim_:
 	case OPT_fcilkplus:
 	case OPT_ftrapv:
-	case OPT_fstrict_overflow:
 	case OPT_foffload_abi_:
 	case OPT_O:
 	case OPT_Ofast:
Index: gcc/opts.c
===================================================================
--- gcc/opts.c	(revision 247273)
+++ gcc/opts.c	(working copy)
@@ -496,7 +496,6 @@ static const struct default_options defa
     { OPT_LEVELS_2_PLUS, OPT_fschedule_insns2, NULL, 1 },
 #endif
     { OPT_LEVELS_2_PLUS, OPT_fstrict_aliasing, NULL, 1 },
-    { OPT_LEVELS_2_PLUS, OPT_fstrict_overflow, NULL, 1 },
     { OPT_LEVELS_2_PLUS_SPEED_ONLY, OPT_freorder_blocks_algorithm_, NULL,
       REORDER_BLOCKS_ALGORITHM_STC },
     { OPT_LEVELS_2_PLUS, OPT_freorder_functions, NULL, 1 },
@@ -984,10 +983,7 @@ finish_options (struct gcc_options *opts
 
   /* Aggressive compiler optimizations may cause false negatives.  */
   if (opts->x_flag_sanitize & ~(SANITIZE_LEAK | SANITIZE_UNREACHABLE))
-    {
-      opts->x_flag_aggressive_loop_optimizations = 0;
-      opts->x_flag_strict_overflow = 0;
-    }
+    opts->x_flag_aggressive_loop_optimizations = 0;
 
   /* Enable -fsanitize-address-use-after-scope if address sanitizer is
      enabled.  */
Index: gcc/simplify-rtx.c
===================================================================
--- gcc/simplify-rtx.c	(revision 247273)
+++ gcc/simplify-rtx.c	(working copy)
@@ -5316,7 +5316,7 @@ simplify_const_relational_operation (enu
 	  /* Optimize abs(x) < 0.0.  */
 	  if (!HONOR_SNANS (mode)
 	      && (!INTEGRAL_MODE_P (mode)
-		  || (!flag_wrapv && !flag_trapv && flag_strict_overflow)))
+		  || (!flag_wrapv && !flag_trapv)))
 	    {
 	      if (INTEGRAL_MODE_P (mode)
 		  && (issue_strict_overflow_warning
@@ -5332,7 +5332,7 @@ simplify_const_relational_operation (enu
 	  /* Optimize abs(x) >= 0.0.  */
 	  if (!HONOR_NANS (mode)
 	      && (!INTEGRAL_MODE_P (mode)
-		  || (!flag_wrapv && !flag_trapv && flag_strict_overflow)))
+		  || (!flag_wrapv && !flag_trapv)))
 	    {
 	      if (INTEGRAL_MODE_P (mode)
 	          && (issue_strict_overflow_warning
Index: gcc/testsuite/c-c++-common/Wlogical-op-1.c
===================================================================
--- gcc/testsuite/c-c++-common/Wlogical-op-1.c	(revision 247273)
+++ gcc/testsuite/c-c++-common/Wlogical-op-1.c	(working copy)
@@ -1,6 +1,8 @@
 /* PR c/63357 */
 /* { dg-do compile } */
-/* { dg-options "-Wlogical-op" } */
+/* For -fwrapv see PR80525, xfailing the subtest isn't possible as it passes
+   with the C++ FE which doesn't have maybe_const_expr.  */
+/* { dg-options "-fwrapv -Wlogical-op" } */
 
 #ifndef __cplusplus
 # define bool _Bool
Index: gcc/testsuite/gcc.target/i386/pr46253.c
===================================================================
--- gcc/testsuite/gcc.target/i386/pr46253.c	(revision 247273)
+++ gcc/testsuite/gcc.target/i386/pr46253.c	(working copy)
@@ -6,7 +6,7 @@ typedef int __m256i __attribute__ ((__ve
 __m256i bar (void);
 void foo (void)
 {
-  int i = 0;
+  unsigned int i = 0;
   bar ();
   __builtin_ia32_vzeroupper ();
   while (++i);
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 247273)
+++ gcc/tree.h	(working copy)
@@ -846,7 +846,7 @@ extern void omp_clause_range_check_faile
    caller decide whether a warning is appropriate or not.  */
 #define TYPE_OVERFLOW_UNDEFINED(TYPE)				\
   (!ANY_INTEGRAL_TYPE_CHECK(TYPE)->base.u.bits.unsigned_flag	\
-   && !flag_wrapv && !flag_trapv && flag_strict_overflow)
+   && !flag_wrapv && !flag_trapv)
 
 /* True if overflow for the given integral type should issue a
    trap.  */
@@ -860,7 +860,7 @@ extern void omp_clause_range_check_faile
    && (flag_sanitize & SANITIZE_SI_OVERFLOW))
 
 /* True if pointer types have undefined overflow.  */
-#define POINTER_TYPE_OVERFLOW_UNDEFINED (flag_strict_overflow)
+#define POINTER_TYPE_OVERFLOW_UNDEFINED (!flag_wrapv)
 
 /* Nonzero in a VAR_DECL or STRING_CST means assembler code has been written.
    Nonzero in a FUNCTION_DECL means that the function has been compiled.



More information about the Gcc-patches mailing list