re PR middle-end/82694 (Linux kernel miscompiled since r250765)
authorJakub Jelinek <jakub@redhat.com>
Mon, 15 Jan 2018 09:05:59 +0000 (10:05 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 15 Jan 2018 09:05:59 +0000 (10:05 +0100)
PR middle-end/82694
* common.opt (fstrict-overflow): No longer an alias.
(fwrapv-pointer): New option.
* tree.h (TYPE_OVERFLOW_WRAPS, TYPE_OVERFLOW_UNDEFINED): Define
also for pointer types based on flag_wrapv_pointer.
* 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.

From-SVN: r256686

gcc/ChangeLog
gcc/common.opt
gcc/doc/invoke.texi
gcc/fold-const.c
gcc/match.pd
gcc/opts.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/no-strict-overflow-7.c
gcc/testsuite/gcc.dg/tree-ssa/pr81388-1.c
gcc/tree.h

index 43c9cfa0ee83f9b79afc98444c54380cdfa808b7..76977e0d053556e6ffbf3c2f198ee2c80283a035 100644 (file)
@@ -1,3 +1,19 @@
+2018-01-15  Jakub Jelinek  <jakub@redhat.com>
+
+       PR middle-end/82694
+       * common.opt (fstrict-overflow): No longer an alias.
+       (fwrapv-pointer): New option.
+       * tree.h (TYPE_OVERFLOW_WRAPS, TYPE_OVERFLOW_UNDEFINED): Define
+       also for pointer types based on flag_wrapv_pointer.
+       * 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.
+
 2018-01-15  Richard Biener  <rguenther@suse.de>
 
        PR lto/83804
index a07cfdb8409249a8b7169435196417d97ff23d82..b20a9aac82e1c82c1a55c8bc67ecfdd1fe9d85bc 100644 (file)
@@ -2411,8 +2411,8 @@ Common Report Var(flag_strict_aliasing) Optimization
 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 -fwrapv-pointer.
 
 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.
 
+fwrapv-pointer
+Common Report Var(flag_wrapv_pointer) Optimization
+Assume pointer overflow wraps around.
+
 fwrapv
 Common Report Var(flag_wrapv) Optimization
 Assume signed arithmetic overflow wraps around.
index f57c05844631079df1594eb92069b40242085d85..98b73db17afb6e39b4e1ae585223df87a6655139 100644 (file)
@@ -12581,6 +12581,18 @@ The options @option{-ftrapv} and @option{-fwrapv} override each other, so using
 using @option{-ftrapv} @option{-fwrapv} @option{-fno-wrapv} on the command-line
 results in @option{-ftrapv} being effective.
 
+@item -fwrapv-pointer
+@opindex fwrapv-pointer
+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-wrapv-pointer} and when
+negated implies @option{-fwrapv} @option{-fwrapv-pointer}.
+
 @item -fexceptions
 @opindex fexceptions
 Enable exception handling.  Generates extra code needed to propagate
index cfb1b3d0614c35629651978fc4cb79ff70bae2f1..f3749db7ed65489eb91cf2313325efa26869b88c 100644 (file)
@@ -8551,9 +8551,13 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
        {
          /* 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 tree_code code, tree type,
             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 tree_code code, tree type,
 
          /* 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 tree_code code, tree type,
 
          /* 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))
                {
index 435125a317275527661fba011a9d26e507d293a6..3f6e0094bf503696fa65d4d3b50ca1a41df3dcab 100644 (file)
@@ -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); })
index e9df6f6a6ae7a6c62b0ca1fdf6a57554916586b8..b1b6a325d092c9c602c720e9f2cab8ba6a2dec0c 100644 (file)
@@ -2465,6 +2465,13 @@ common_handle_option (struct gcc_options *opts,
        opts->x_flag_wrapv = 0;
       break;
 
+    case OPT_fstrict_overflow:
+      opts->x_flag_wrapv = !value;
+      opts->x_flag_wrapv_pointer = !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;
index 37f54de8146ec18ecb2c57b753cd8182597c7e0b..546fc82c9f00f06721af2bf714f76f93f9b7f8ad 100644 (file)
@@ -1,3 +1,9 @@
+2018-01-15  Jakub Jelinek  <jakub@redhat.com>
+
+       PR middle-end/82694
+       * gcc.dg/no-strict-overflow-7.c: Revert 2017-08-01 changes.
+       * gcc.dg/tree-ssa/pr81388-1.c: Likewise.
+
 2018-01-10  Martin Sebor  <msebor@redhat.com>
 
        PR other/83508
index 0e73d486f22f1d6b5d8993c47b1f80861884840e..19e1b55bb12f8f530efbb3dcb5d1400c543ba1aa 100644 (file)
@@ -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" } } */
index 0beb5109d403ba53a5cf556e80f49208add106e1..85c00e56144d542cc52e8687717f2667af33fefb 100644 (file)
@@ -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" } } */
index f47e2338d2d9ac9dc949d5ce863cba5d065a843d..af8a6fb380c515a44a660f218b0229c07517b413 100644 (file)
@@ -829,13 +829,16 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
 /* 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_wrapv_pointer                                                \
+   : (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_failed (const_tree, const char *, int,
    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_wrapv_pointer                                       \
+   : (!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.  */