Commit 3fccbb9e by Jakub Jelinek Committed by Jakub Jelinek

re PR middle-end/82694 (Linux kernel miscompiled since r250765)

	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
parent 2aa89839
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> 2018-01-15 Richard Biener <rguenther@suse.de>
PR lto/83804 PR lto/83804
......
...@@ -2411,8 +2411,8 @@ Common Report Var(flag_strict_aliasing) Optimization ...@@ -2411,8 +2411,8 @@ Common Report Var(flag_strict_aliasing) Optimization
Assume strict aliasing rules apply. Assume strict aliasing rules apply.
fstrict-overflow fstrict-overflow
Common NegativeAlias Alias(fwrapv) Common Report
Treat signed overflow as undefined. Negated as -fwrapv. Treat signed overflow as undefined. Negated as -fwrapv -fwrapv-pointer.
fsync-libcalls fsync-libcalls
Common Report Var(flag_sync_libcalls) Init(1) Common Report Var(flag_sync_libcalls) Init(1)
...@@ -2860,6 +2860,10 @@ fwhole-program ...@@ -2860,6 +2860,10 @@ fwhole-program
Common Report Var(flag_whole_program) Init(0) Common Report Var(flag_whole_program) Init(0)
Perform whole program optimizations. Perform whole program optimizations.
fwrapv-pointer
Common Report Var(flag_wrapv_pointer) Optimization
Assume pointer overflow wraps around.
fwrapv fwrapv
Common Report Var(flag_wrapv) Optimization Common Report Var(flag_wrapv) Optimization
Assume signed arithmetic overflow wraps around. Assume signed arithmetic overflow wraps around.
......
...@@ -12581,6 +12581,18 @@ The options @option{-ftrapv} and @option{-fwrapv} override each other, so using ...@@ -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 using @option{-ftrapv} @option{-fwrapv} @option{-fno-wrapv} on the command-line
results in @option{-ftrapv} being effective. 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 @item -fexceptions
@opindex fexceptions @opindex fexceptions
Enable exception handling. Generates extra code needed to propagate Enable exception handling. Generates extra code needed to propagate
...@@ -8551,9 +8551,13 @@ fold_comparison (location_t loc, enum tree_code code, tree type, ...@@ -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 /* We can fold this expression to a constant if the non-constant
offset parts are equal. */ offset parts are equal. */
if (offset0 == offset1 if ((offset0 == offset1
|| (offset0 && offset1 || (offset0 && offset1
&& operand_equal_p (offset0, offset1, 0))) && 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 if (!equality_code
&& maybe_ne (bitpos0, bitpos1) && maybe_ne (bitpos0, bitpos1)
...@@ -8612,7 +8616,11 @@ fold_comparison (location_t loc, enum tree_code code, tree type, ...@@ -8612,7 +8616,11 @@ fold_comparison (location_t loc, enum tree_code code, tree type,
because pointer arithmetic is restricted to retain within an because pointer arithmetic is restricted to retain within an
object and overflow on pointer differences is undefined as of object and overflow on pointer differences is undefined as of
6.5.6/8 and /9 with respect to the signed ptrdiff_t. */ 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 /* By converting to signed sizetype we cover middle-end pointer
arithmetic which operates on unsigned pointer types of size 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, ...@@ -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 /* With undefined overflow prefer doing association in a type
which wraps on overflow, if that is one of the operand types. */ which wraps on overflow, if that is one of the operand types. */
if (POINTER_TYPE_P (type) if ((POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type))
|| (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_WRAPS (type))) && !TYPE_OVERFLOW_WRAPS (type))
{ {
if (INTEGRAL_TYPE_P (TREE_TYPE (arg0)) if (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
&& TYPE_OVERFLOW_WRAPS (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, ...@@ -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 /* With undefined overflow we can only associate constants with one
variable, and constants whose association doesn't overflow. */ variable, and constants whose association doesn't overflow. */
if (POINTER_TYPE_P (atype) if ((POINTER_TYPE_P (atype) || INTEGRAL_TYPE_P (atype))
|| (INTEGRAL_TYPE_P (atype) && !TYPE_OVERFLOW_WRAPS (atype))) && !TYPE_OVERFLOW_WRAPS (atype))
{ {
if ((var0 && var1) || (minus_var0 && minus_var1)) if ((var0 && var1) || (minus_var0 && minus_var1))
{ {
......
...@@ -3610,7 +3610,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) ...@@ -3610,7 +3610,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
|| TREE_CODE (base1) == STRING_CST)) || TREE_CODE (base1) == STRING_CST))
equal = (base0 == base1); 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 (switch
(if (cmp == EQ_EXPR && (known_eq (off0, off1) || known_ne (off0, off1))) (if (cmp == EQ_EXPR && (known_eq (off0, off1) || known_ne (off0, off1)))
{ constant_boolean_node (known_eq (off0, off1), type); }) { constant_boolean_node (known_eq (off0, off1), type); })
......
...@@ -2465,6 +2465,13 @@ common_handle_option (struct gcc_options *opts, ...@@ -2465,6 +2465,13 @@ common_handle_option (struct gcc_options *opts,
opts->x_flag_wrapv = 0; opts->x_flag_wrapv = 0;
break; 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: case OPT_fipa_icf:
opts->x_flag_ipa_icf_functions = value; opts->x_flag_ipa_icf_functions = value;
opts->x_flag_ipa_icf_variables = value; opts->x_flag_ipa_icf_variables = value;
......
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> 2018-01-10 Martin Sebor <msebor@redhat.com>
PR other/83508 PR other/83508
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
/* Source: Ian Lance Taylor. Dual of strict-overflow-6.c. */ /* Source: Ian Lance Taylor. Dual of strict-overflow-6.c. */
/* We can simplify the conditional because pointer overflow always has /* We can only simplify the conditional when using strict overflow
undefined semantics. */ semantics. */
int int
foo (char* p) foo (char* p)
...@@ -12,4 +12,4 @@ foo (char* p) ...@@ -12,4 +12,4 @@ foo (char* p)
return p + 1000 < p; return p + 1000 < p;
} }
/* { dg-final { scan-tree-dump "return 0" "optimized" } } */ /* { dg-final { scan-tree-dump "\[+\]\[ \]*1000" "optimized" } } */
/* { dg-do compile } */ /* { 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 bar();
void foo(char *dst) void foo(char *dst)
...@@ -11,6 +11,4 @@ void foo(char *dst) ...@@ -11,6 +11,4 @@ void foo(char *dst)
} while (dst < end); } while (dst < end);
} }
/* The loop only iterates once because pointer overflow always has undefined /* { dg-final { scan-tree-dump " zero if " "ivcanon" } } */
semantics. As a result, call to bar becomes tail call. */
/* { dg-final { scan-tree-dump-times "Found tail call " 1 "tailc" } } */
...@@ -829,13 +829,16 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, ...@@ -829,13 +829,16 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
/* Same as TYPE_UNSIGNED but converted to SIGNOP. */ /* Same as TYPE_UNSIGNED but converted to SIGNOP. */
#define TYPE_SIGN(NODE) ((signop) TYPE_UNSIGNED (NODE)) #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. */ is, TYPE_MAX + 1 == TYPE_MIN. */
#define TYPE_OVERFLOW_WRAPS(TYPE) \ #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 /* True if overflow is undefined for the given integral or pointer type.
optimize on the assumption that values in the type never overflow. We may optimize on the assumption that values in the type never overflow.
IMPORTANT NOTE: Any optimization based on TYPE_OVERFLOW_UNDEFINED IMPORTANT NOTE: Any optimization based on TYPE_OVERFLOW_UNDEFINED
must issue a warning based on warn_strict_overflow. In some cases 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, ...@@ -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 other cases it will be appropriate to simply set a flag and let the
caller decide whether a warning is appropriate or not. */ caller decide whether a warning is appropriate or not. */
#define TYPE_OVERFLOW_UNDEFINED(TYPE) \ #define TYPE_OVERFLOW_UNDEFINED(TYPE) \
(!ANY_INTEGRAL_TYPE_CHECK(TYPE)->base.u.bits.unsigned_flag \ (POINTER_TYPE_P (TYPE) \
&& !flag_wrapv && !flag_trapv) ? !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 /* True if overflow for the given integral type should issue a
trap. */ trap. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment