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)