aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2018-01-15 10:05:59 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2018-01-15 10:05:59 +0100
commit3fccbb9ecec7daa3b6468f72379c0bd1fb5bb8d9 (patch)
tree08c17fa7abe77e42e46b0fdf6d49c9bdf48fc9a0 /gcc
parent2aa89839f557b7467704ddffa4dc43a130e8d027 (diff)
downloadgcc-3fccbb9ecec7daa3b6468f72379c0bd1fb5bb8d9.zip
gcc-3fccbb9ecec7daa3b6468f72379c0bd1fb5bb8d9.tar.gz
gcc-3fccbb9ecec7daa3b6468f72379c0bd1fb5bb8d9.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/common.opt8
-rw-r--r--gcc/doc/invoke.texi12
-rw-r--r--gcc/fold-const.c24
-rw-r--r--gcc/match.pd9
-rw-r--r--gcc/opts.c7
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.dg/no-strict-overflow-7.c6
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr81388-1.c6
-rw-r--r--gcc/tree.h17
10 files changed, 87 insertions, 24 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 43c9cfa..76977e0 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,19 @@
+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
diff --git a/gcc/common.opt b/gcc/common.opt
index a07cfdb..b20a9aa 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -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.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index f57c058..98b73db 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index cfb1b3d..f3749db 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -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))
{
diff --git a/gcc/match.pd b/gcc/match.pd
index 435125a..3f6e009 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -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); })
diff --git a/gcc/opts.c b/gcc/opts.c
index e9df6f6..b1b6a32 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -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;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 37f54de..546fc82 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+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
diff --git a/gcc/testsuite/gcc.dg/no-strict-overflow-7.c b/gcc/testsuite/gcc.dg/no-strict-overflow-7.c
index 0e73d48..19e1b55 100644
--- a/gcc/testsuite/gcc.dg/no-strict-overflow-7.c
+++ b/gcc/testsuite/gcc.dg/no-strict-overflow-7.c
@@ -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" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81388-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81388-1.c
index 0beb510..85c00e5 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr81388-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr81388-1.c
@@ -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" } } */
diff --git a/gcc/tree.h b/gcc/tree.h
index f47e233..af8a6fb 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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. */