This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Introduce -fwrapp and make -fno-strict-overflow imply it (PR middle-end/82694)


Hi!

Apparently Linux kernel contains various UB code that has been worked around
through -fno-strict-overflow in 7.x and before, but when
POINTER_TYPE_OVERFLOW_UNDEFINED has been removed it now fails to boot.

The following patch follows the comments in the PR, essentially reverts
Bin's removal of that, except that it is now controlled by a separate option
and is included in TYPE_OVERFLOW_{WRAPS,UNDEFINED} macros.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2018-01-12  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/82694
	* common.opt (fstrict-overflow): No longer an alias.
	(fwrapp): New option.
	* tree.h (TYPE_OVERFLOW_WRAPS, TYPE_OVERFLOW_UNDEFINED): Define
	also for pointer types based on flag_wrapp.
	* opts.c (common_handle_option) <case OPT_fstrict_overflow>: Set
	opts->x_flag_wrap[pv] to !value, clear opts->x_flag_trapv if
	opts->x_flag_wrapv got set.
	* fold-const.c (fold_comparison, fold_binary_loc): Revert 2017-08-01
	changes, just use TYPE_OVERFLOW_UNDEFINED on pointer type instead of
	POINTER_TYPE_OVERFLOW_UNDEFINED.
	* match.pd: Likewise in address comparison pattern.
	* doc/invoke.texi: Document -fwrapv and -fstrict-overflow.

	* gcc.dg/no-strict-overflow-7.c: Revert 2017-08-01 changes.
	* gcc.dg/tree-ssa/pr81388-1.c: Likewise.

--- gcc/common.opt.jj	2018-01-03 10:19:54.936533922 +0100
+++ gcc/common.opt	2018-01-12 14:53:28.254485349 +0100
@@ -2411,8 +2411,8 @@ Common Report Var(flag_strict_aliasing)
 Assume strict aliasing rules apply.
 
 fstrict-overflow
-Common NegativeAlias Alias(fwrapv)
-Treat signed overflow as undefined.  Negated as -fwrapv.
+Common Report
+Treat signed overflow as undefined.  Negated as -fwrapv -fwrapp.
 
 fsync-libcalls
 Common Report Var(flag_sync_libcalls) Init(1)
@@ -2860,6 +2860,10 @@ fwhole-program
 Common Report Var(flag_whole_program) Init(0)
 Perform whole program optimizations.
 
+fwrapp
+Common Report Var(flag_wrapp) Optimization
+Assume pointer overflow wraps around.
+
 fwrapv
 Common Report Var(flag_wrapv) Optimization
 Assume signed arithmetic overflow wraps around.
--- gcc/tree.h.jj	2018-01-11 18:58:50.993392760 +0100
+++ gcc/tree.h	2018-01-12 15:04:14.480526788 +0100
@@ -829,13 +829,16 @@ extern void omp_clause_range_check_faile
 /* Same as TYPE_UNSIGNED but converted to SIGNOP.  */
 #define TYPE_SIGN(NODE) ((signop) TYPE_UNSIGNED (NODE))
 
-/* True if overflow wraps around for the given integral type.  That
+/* True if overflow wraps around for the given integral or pointer type.  That
    is, TYPE_MAX + 1 == TYPE_MIN.  */
 #define TYPE_OVERFLOW_WRAPS(TYPE) \
-  (ANY_INTEGRAL_TYPE_CHECK(TYPE)->base.u.bits.unsigned_flag || flag_wrapv)
+  (POINTER_TYPE_P (TYPE)					\
+   ? flag_wrapp							\
+   : (ANY_INTEGRAL_TYPE_CHECK(TYPE)->base.u.bits.unsigned_flag	\
+      || flag_wrapv))
 
-/* True if overflow is undefined for the given integral type.  We may
-   optimize on the assumption that values in the type never overflow.
+/* True if overflow is undefined for the given integral or pointer type.
+   We may optimize on the assumption that values in the type never overflow.
 
    IMPORTANT NOTE: Any optimization based on TYPE_OVERFLOW_UNDEFINED
    must issue a warning based on warn_strict_overflow.  In some cases
@@ -843,8 +846,10 @@ extern void omp_clause_range_check_faile
    other cases it will be appropriate to simply set a flag and let the
    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)
+  (POINTER_TYPE_P (TYPE)					\
+   ? !flag_wrapp						\
+   : (!ANY_INTEGRAL_TYPE_CHECK(TYPE)->base.u.bits.unsigned_flag	\
+      && !flag_wrapv && !flag_trapv))
 
 /* True if overflow for the given integral type should issue a
    trap.  */
--- gcc/opts.c.jj	2018-01-03 10:19:56.142534113 +0100
+++ gcc/opts.c	2018-01-12 14:55:06.670494955 +0100
@@ -2465,6 +2465,13 @@ common_handle_option (struct gcc_options
 	opts->x_flag_wrapv = 0;
       break;
 
+    case OPT_fstrict_overflow:
+      opts->x_flag_wrapv = !value;
+      opts->x_flag_wrapp = !value;
+      if (!value)
+	opts->x_flag_trapv = 0;
+      break;
+
     case OPT_fipa_icf:
       opts->x_flag_ipa_icf_functions = value;
       opts->x_flag_ipa_icf_variables = value;
--- gcc/fold-const.c.jj	2018-01-04 22:08:04.394684734 +0100
+++ gcc/fold-const.c	2018-01-12 15:06:20.040532446 +0100
@@ -8551,9 +8551,13 @@ fold_comparison (location_t loc, enum tr
 	{
 	  /* We can fold this expression to a constant if the non-constant
 	     offset parts are equal.  */
-	  if (offset0 == offset1
-	      || (offset0 && offset1
-		  && operand_equal_p (offset0, offset1, 0)))
+	  if ((offset0 == offset1
+	       || (offset0 && offset1
+		   && operand_equal_p (offset0, offset1, 0)))
+	      && (equality_code
+		  || (indirect_base0
+		      && (DECL_P (base0) || CONSTANT_CLASS_P (base0)))
+		  || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))))
 	    {
 	      if (!equality_code
 		  && maybe_ne (bitpos0, bitpos1)
@@ -8612,7 +8616,11 @@ fold_comparison (location_t loc, enum tr
 	     because pointer arithmetic is restricted to retain within an
 	     object and overflow on pointer differences is undefined as of
 	     6.5.6/8 and /9 with respect to the signed ptrdiff_t.  */
-	  else if (known_eq (bitpos0, bitpos1))
+	  else if (known_eq (bitpos0, bitpos1)
+		   && (equality_code
+		       || (indirect_base0
+			   && (DECL_P (base0) || CONSTANT_CLASS_P (base0)))
+		       || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))))
 	    {
 	      /* By converting to signed sizetype we cover middle-end pointer
 	         arithmetic which operates on unsigned pointer types of size
@@ -9721,8 +9729,8 @@ fold_binary_loc (location_t loc, enum tr
 
 	  /* With undefined overflow prefer doing association in a type
 	     which wraps on overflow, if that is one of the operand types.  */
-	  if (POINTER_TYPE_P (type)
-	      || (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_WRAPS (type)))
+	  if ((POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type))
+	      && !TYPE_OVERFLOW_WRAPS (type))
 	    {
 	      if (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
 		  && TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0)))
@@ -9735,8 +9743,8 @@ fold_binary_loc (location_t loc, enum tr
 
 	  /* With undefined overflow we can only associate constants with one
 	     variable, and constants whose association doesn't overflow.  */
-	  if (POINTER_TYPE_P (atype)
-	      || (INTEGRAL_TYPE_P (atype) && !TYPE_OVERFLOW_WRAPS (atype)))
+	  if ((POINTER_TYPE_P (atype) || INTEGRAL_TYPE_P (atype))
+	      && !TYPE_OVERFLOW_WRAPS (atype))
 	    {
 	      if ((var0 && var1) || (minus_var0 && minus_var1))
 		{
--- gcc/match.pd.jj	2018-01-09 21:53:38.366577609 +0100
+++ gcc/match.pd	2018-01-12 16:17:01.677944553 +0100
@@ -3610,7 +3610,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 		    || TREE_CODE (base1) == STRING_CST))
          equal = (base0 == base1);
      }
-     (if (equal == 1)
+     (if (equal == 1
+	  && (cmp == EQ_EXPR || cmp == NE_EXPR
+	      /* If the offsets are equal we can ignore overflow.  */
+	      || known_eq (off0, off1)
+	      || TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
+		 /* Or if we compare using pointers to decls or strings.  */
+	      || (POINTER_TYPE_P (TREE_TYPE (@2))
+		  && (DECL_P (base0) || TREE_CODE (base0) == STRING_CST))))
       (switch
        (if (cmp == EQ_EXPR && (known_eq (off0, off1) || known_ne (off0, off1)))
 	{ constant_boolean_node (known_eq (off0, off1), type); })
--- gcc/doc/invoke.texi.jj	2018-01-12 11:36:20.115225557 +0100
+++ gcc/doc/invoke.texi	2018-01-12 16:14:11.369911474 +0100
@@ -12576,6 +12576,18 @@ The options @option{-ftrapv} and @option
 using @option{-ftrapv} @option{-fwrapv} @option{-fno-wrapv} on the command-line
 results in @option{-ftrapv} being effective.
 
+@item -fwrapp
+@opindex fwrapp
+This option instructs the compiler to assume that pointer arithmetic
+overflow on addition and subtraction wraps around using twos-complement
+representation.  This flag disables some optimizations which assume
+pointer overflow is invalid.
+
+@item -fstrict-overflow
+@opindex fstrict-overflow
+This option implies @option{-fno-wrapv} @option{-fno-wrapp} and when negated
+implies @option{-fwrapv} @option{-fwrapp}.
+
 @item -fexceptions
 @opindex fexceptions
 Enable exception handling.  Generates extra code needed to propagate
--- gcc/testsuite/gcc.dg/tree-ssa/pr81388-1.c.jj	2017-08-01 12:14:27.740533590 +0200
+++ gcc/testsuite/gcc.dg/tree-ssa/pr81388-1.c	2018-01-12 16:22:34.427009184 +0100
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fno-strict-overflow -fdump-tree-tailc-details" } */
+/* { dg-options "-O2 -fno-strict-overflow -fdump-tree-ivcanon-details" } */
 
 void bar();
 void foo(char *dst)
@@ -11,6 +11,4 @@ void foo(char *dst)
   } while (dst < end);
 }
 
-/* The loop only iterates once because pointer overflow always has undefined
-   semantics.  As a result, call to bar becomes tail call.  */
-/* { dg-final { scan-tree-dump-times "Found tail call " 1 "tailc" } } */
+/* { dg-final { scan-tree-dump " zero if " "ivcanon" } } */
--- gcc/testsuite/gcc.dg/no-strict-overflow-7.c.jj	2017-08-01 12:14:27.941531251 +0200
+++ gcc/testsuite/gcc.dg/no-strict-overflow-7.c	2018-01-12 16:19:55.224978262 +0100
@@ -3,8 +3,8 @@
 
 /* Source: Ian Lance Taylor.  Dual of strict-overflow-6.c.  */
 
-/* We can simplify the conditional because pointer overflow always has
-   undefined semantics.  */
+/* We can only simplify the conditional when using strict overflow
+   semantics.  */
 
 int
 foo (char* p)
@@ -12,4 +12,4 @@ foo (char* p)
   return p + 1000 < p;
 }
 
-/* { dg-final { scan-tree-dump "return 0" "optimized" } } */
+/* { dg-final { scan-tree-dump "\[+\]\[ \]*1000" "optimized" } } */

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]