This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Introduce -fwrapp and make -fno-strict-overflow imply it (PR middle-end/82694)
- From: Richard Biener <rguenther at suse dot de>
- To: Jakub Jelinek <jakub at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Mon, 15 Jan 2018 09:41:10 +0100 (CET)
- Subject: Re: [PATCH] Introduce -fwrapp and make -fno-strict-overflow imply it (PR middle-end/82694)
- Authentication-results: sourceware.org; auth=none
- References: <20180112205144.GK2063@tucnak>
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 <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
>
>
--
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)