+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
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)
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.
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
{
/* 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)
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
/* 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)))
/* 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))
{
|| 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); })
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
/* 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)
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)
} 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" } } */
/* 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
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. */