On Fri, 12 Jan 2018, Jakub Jelinek wrote:

> 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?

This is ok with the name of the option/flag changed as suggested
by Martin.

Thanks,
Richard.

> 2018-01-12  Jakub Jelinek  <ja...@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
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 
21284 (AG Nuernberg)

Reply via email to