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>
PR lto/83804
......
......@@ -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.
......
......@@ -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
......@@ -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))
{
......
......@@ -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); })
......
......@@ -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;
......
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
......
......@@ -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" } } */
/* { 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" } } */
......@@ -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. */
......
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