aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2007-02-13 22:34:45 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2007-02-13 22:34:45 +0000
commit6ac015100fa98539d577a6c04b69693aefce35dc (patch)
tree120377355d73c96495ca9008ae2e8dd5c40948af /gcc
parent30d18db4847eb0995d65531e117c7fe75d1fc428 (diff)
downloadgcc-6ac015100fa98539d577a6c04b69693aefce35dc.zip
gcc-6ac015100fa98539d577a6c04b69693aefce35dc.tar.gz
gcc-6ac015100fa98539d577a6c04b69693aefce35dc.tar.bz2
common.opt: Add Wstrict-overflow and Wstrict-overflow=.
./: * common.opt: Add Wstrict-overflow and Wstrict-overflow=. * flags.h (warn_strict_overflow): Declare. (enum warn_strict_overflow_code): Define. (issue_strict_overflow_warning): New static inline function. * opts.c (warn_strict_overflow): New variable. (common_handle_option): Handle OPT_Wstrict_overflow and OPT_Wstrict_overflow_. * c-opts.c (c_common_handle_option): Set warn_strict_overflow for OPT_Wall. * fold-const.c: Include intl.h. (fold_deferring_overflow_warnings): New static variable. (fold_deferred_overflow_warning): New static variable. (fold_deferred_overflow_code): New static variable. (fold_defer_overflow_warnings): New function. (fold_undefer_overflow_warnings): New function. (fold_undefer_and_ignore_overflow_warnings): New function. (fold_deferring_overflow_warnings_p): New function. (fold_overflow_warning): New static function. (make_range): Add strict_overflow_p parameter. Change all callers. (extract_muldiv, extract_muldiv_1): Likewise. (fold_unary) [ABS_EXPR]: Check ABS_EXPR before calling tree_expr_nonnegative_p. (fold_negate_expr): Call fold_overflow_warning. (fold_range_test): Likewise. (fold_comparison): Likewise. (fold_binary): Likewise. Call tree_expr_nonnegative_warnv_p instead of tree_expr_nonnegative_p. (tree_expr_nonnegative_warnv_p): Rename from tree_expr_nonnegative_p, add strict_overflow_p parameter. (tree_expr_nonnegative_p): New function. (tree_expr_nonzero_warnv_p): Rename from tree_expr_nonzero_p, add strict_overflow_p parameter. (tree_expr_nonzero_p): New function. * passes.c (verify_interpass_invariants): New static function. (execute_one_pass): Call it. * tree-ssa-loop-niter.c (expand_simple_operations): Ignore fold warnings. (number_of_iterations_exit, loop_niter_by_eval): Likewise. (estimate_numbers_of_iterations): Likewise. (scev_probably_wraps_p): Likewise. * tree-ssa-ccp.c: Include "toplev.h". (evaluate_stmt): Defer fold overflow warnings until we know we are going to optimize. (struct fold_stmt_r_data): Add stmt field. (fold_stmt_r): Defer fold overflow warnings until we know we optimized. (fold_stmt): Initialize stmt field of fold_stmt_r_data. (fold_stmt_inplace): Likewise. * tree-cfgcleanup.c: Include "toplev.h" rather than "errors.h". (cleanup_control_expr_graph): Defer fold overflow warnings until we know we are going to optimize. * tree-cfg.c (fold_cond_expr_cond): Likewise. * tree-ssa-threadedge.c (simplify_control_stmt_condition): Likewise. * tree-vrp.c (vrp_expr_computes_nonnegative): Call tree_expr_nonnegative_warnv_p instead of tree_expr_nonnegative_p. * tree-ssa-loop-manip.c (create_iv): Likewise. * c-typeck.c (build_conditional_expr): Likewise. (build_binary_op): Likewise. * tree-vrp.c (vrp_expr_computes_nonzero): Call tree_expr_nonzero_warnv_p instead of tree_expr_nonzero_p. (extract_range_from_unary_expr): Likewise. * simplify-rtx.c (simplify_const_relational_operation): Warn when assuming that signed overflow does not occur. * c-common.c (pointer_int_sum): Ignore fold overflow warnings. * tree.h (tree_expr_nonnegative_warnv_p): Declare. (fold_defer_overflow_warnings): Declare. (fold_undefer_overflow_warnings): Declare. (fold_undefer_and_ignore_overflow_warnings): Declare. (fold_deferring_overflow_warnings_p): Declare. (tree_expr_nonzero_warnv_p): Declare. * doc/invoke.texi (Option Summary): Add -Wstrict-overflow to list of warning options. (Warning Options): Document -Wstrict-overflow. * Makefile.in (tree-ssa-threadedge.o): Depend on toplev.h. (tree-ssa-ccp.o): Likewise. (tree-cfgcleanup.o): Change errors.h dependency to toplev.h. (fold-const.o): Depend on intl.h. testsuite/: * gcc.dg/Wstrict-overflow-1.c: New test. * gcc.dg/Wstrict-overflow-2.c: New test. * gcc.dg/Wstrict-overflow-3.c: New test. * gcc.dg/Wstrict-overflow-4.c: New test. * gcc.dg/Wstrict-overflow-5.c: New test. * gcc.dg/Wstrict-overflow-6.c: New test. * gcc.dg/Wstrict-overflow-7.c: New test. * gcc.dg/Wstrict-overflow-8.c: New test. * gcc.dg/Wstrict-overflow-9.c: New test. * gcc.dg/Wstrict-overflow-10.c: New test. From-SVN: r121895
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog82
-rw-r--r--gcc/Makefile.in6
-rw-r--r--gcc/c-common.c14
-rw-r--r--gcc/c-opts.c4
-rw-r--r--gcc/c-typeck.c11
-rw-r--r--gcc/common.opt8
-rw-r--r--gcc/doc/invoke.texi51
-rw-r--r--gcc/flags.h47
-rw-r--r--gcc/fold-const.c758
-rw-r--r--gcc/opts.c9
-rw-r--r--gcc/passes.c12
-rw-r--r--gcc/simplify-rtx.c20
-rw-r--r--gcc/testsuite/ChangeLog13
-rw-r--r--gcc/testsuite/gcc.dg/Wstrict-overflow-1.c13
-rw-r--r--gcc/testsuite/gcc.dg/Wstrict-overflow-10.c10
-rw-r--r--gcc/testsuite/gcc.dg/Wstrict-overflow-2.c13
-rw-r--r--gcc/testsuite/gcc.dg/Wstrict-overflow-3.c13
-rw-r--r--gcc/testsuite/gcc.dg/Wstrict-overflow-4.c13
-rw-r--r--gcc/testsuite/gcc.dg/Wstrict-overflow-5.c13
-rw-r--r--gcc/testsuite/gcc.dg/Wstrict-overflow-6.c13
-rw-r--r--gcc/testsuite/gcc.dg/Wstrict-overflow-7.c10
-rw-r--r--gcc/testsuite/gcc.dg/Wstrict-overflow-8.c10
-rw-r--r--gcc/testsuite/gcc.dg/Wstrict-overflow-9.c10
-rw-r--r--gcc/tree-cfg.c14
-rw-r--r--gcc/tree-cfgcleanup.c28
-rw-r--r--gcc/tree-ssa-ccp.c37
-rw-r--r--gcc/tree-ssa-loop-manip.c6
-rw-r--r--gcc/tree-ssa-loop-niter.c50
-rw-r--r--gcc/tree-ssa-threadedge.c9
-rw-r--r--gcc/tree-vrp.c15
-rw-r--r--gcc/tree.h6
31 files changed, 1139 insertions, 179 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d504109..4c6f084 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,87 @@
2007-02-13 Ian Lance Taylor <iant@google.com>
+ * common.opt: Add Wstrict-overflow and Wstrict-overflow=.
+ * flags.h (warn_strict_overflow): Declare.
+ (enum warn_strict_overflow_code): Define.
+ (issue_strict_overflow_warning): New static inline function.
+ * opts.c (warn_strict_overflow): New variable.
+ (common_handle_option): Handle OPT_Wstrict_overflow and
+ OPT_Wstrict_overflow_.
+ * c-opts.c (c_common_handle_option): Set warn_strict_overflow for
+ OPT_Wall.
+ * fold-const.c: Include intl.h.
+ (fold_deferring_overflow_warnings): New static variable.
+ (fold_deferred_overflow_warning): New static variable.
+ (fold_deferred_overflow_code): New static variable.
+ (fold_defer_overflow_warnings): New function.
+ (fold_undefer_overflow_warnings): New function.
+ (fold_undefer_and_ignore_overflow_warnings): New function.
+ (fold_deferring_overflow_warnings_p): New function.
+ (fold_overflow_warning): New static function.
+ (make_range): Add strict_overflow_p parameter. Change all
+ callers.
+ (extract_muldiv, extract_muldiv_1): Likewise.
+ (fold_unary) [ABS_EXPR]: Check ABS_EXPR before calling
+ tree_expr_nonnegative_p.
+ (fold_negate_expr): Call fold_overflow_warning.
+ (fold_range_test): Likewise.
+ (fold_comparison): Likewise.
+ (fold_binary): Likewise. Call tree_expr_nonnegative_warnv_p
+ instead of tree_expr_nonnegative_p.
+ (tree_expr_nonnegative_warnv_p): Rename from
+ tree_expr_nonnegative_p, add strict_overflow_p parameter.
+ (tree_expr_nonnegative_p): New function.
+ (tree_expr_nonzero_warnv_p): Rename from tree_expr_nonzero_p, add
+ strict_overflow_p parameter.
+ (tree_expr_nonzero_p): New function.
+ * passes.c (verify_interpass_invariants): New static function.
+ (execute_one_pass): Call it.
+ * tree-ssa-loop-niter.c (expand_simple_operations): Ignore fold
+ warnings.
+ (number_of_iterations_exit, loop_niter_by_eval): Likewise.
+ (estimate_numbers_of_iterations): Likewise.
+ (scev_probably_wraps_p): Likewise.
+ * tree-ssa-ccp.c: Include "toplev.h".
+ (evaluate_stmt): Defer fold overflow warnings until we know we are
+ going to optimize.
+ (struct fold_stmt_r_data): Add stmt field.
+ (fold_stmt_r): Defer fold overflow warnings until we know we
+ optimized.
+ (fold_stmt): Initialize stmt field of fold_stmt_r_data.
+ (fold_stmt_inplace): Likewise.
+ * tree-cfgcleanup.c: Include "toplev.h" rather than "errors.h".
+ (cleanup_control_expr_graph): Defer fold overflow warnings until
+ we know we are going to optimize.
+ * tree-cfg.c (fold_cond_expr_cond): Likewise.
+ * tree-ssa-threadedge.c (simplify_control_stmt_condition):
+ Likewise.
+ * tree-vrp.c (vrp_expr_computes_nonnegative): Call
+ tree_expr_nonnegative_warnv_p instead of tree_expr_nonnegative_p.
+ * tree-ssa-loop-manip.c (create_iv): Likewise.
+ * c-typeck.c (build_conditional_expr): Likewise.
+ (build_binary_op): Likewise.
+ * tree-vrp.c (vrp_expr_computes_nonzero): Call
+ tree_expr_nonzero_warnv_p instead of tree_expr_nonzero_p.
+ (extract_range_from_unary_expr): Likewise.
+ * simplify-rtx.c (simplify_const_relational_operation): Warn when
+ assuming that signed overflow does not occur.
+ * c-common.c (pointer_int_sum): Ignore fold overflow warnings.
+ * tree.h (tree_expr_nonnegative_warnv_p): Declare.
+ (fold_defer_overflow_warnings): Declare.
+ (fold_undefer_overflow_warnings): Declare.
+ (fold_undefer_and_ignore_overflow_warnings): Declare.
+ (fold_deferring_overflow_warnings_p): Declare.
+ (tree_expr_nonzero_warnv_p): Declare.
+ * doc/invoke.texi (Option Summary): Add -Wstrict-overflow to list
+ of warning options.
+ (Warning Options): Document -Wstrict-overflow.
+ * Makefile.in (tree-ssa-threadedge.o): Depend on toplev.h.
+ (tree-ssa-ccp.o): Likewise.
+ (tree-cfgcleanup.o): Change errors.h dependency to toplev.h.
+ (fold-const.o): Depend on intl.h.
+
+2007-02-13 Ian Lance Taylor <iant@google.com>
+
PR middle-end/30751
* lower-subreg.c (resolve_simple_move): Decompose subregs in
addresses.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 7bb1434..6ea4280 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -2059,7 +2059,7 @@ tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
tree-ssa-propagate.h
tree-cfgcleanup.o : tree-cfgcleanup.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
$(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \
- $(DIAGNOSTIC_H) errors.h $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
+ $(DIAGNOSTIC_H) toplev.h $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
$(TREE_DUMP_H) except.h langhooks.h $(CFGLOOP_H) tree-pass.h \
$(CFGLAYOUT_H) $(BASIC_BLOCK_H) hard-reg-set.h $(HASHTAB_H) toplev.h \
tree-ssa-propagate.h
@@ -2256,7 +2256,7 @@ tree-pretty-print.o : tree-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \
value-prof.h
fold-const.o : fold-const.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) $(FLAGS_H) $(REAL_H) toplev.h $(HASHTAB_H) $(EXPR_H) $(RTL_H) \
- $(GGC_H) $(TM_P_H) langhooks.h $(MD5_H)
+ $(GGC_H) $(TM_P_H) langhooks.h $(MD5_H) intl.h
diagnostic.o : diagnostic.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) version.h $(TM_P_H) $(FLAGS_H) input.h toplev.h intl.h \
$(DIAGNOSTIC_H) langhooks.h $(LANGHOOKS_DEF_H) diagnostic.def opts.h
@@ -2507,7 +2507,7 @@ tree-ssa-ccp.o : tree-ssa-ccp.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h \
$(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
$(TREE_DUMP_H) $(BASIC_BLOCK_H) tree-pass.h langhooks.h \
- tree-ssa-propagate.h $(FLAGS_H) $(TARGET_H)
+ tree-ssa-propagate.h $(FLAGS_H) $(TARGET_H) toplev.h
tree-sra.o : tree-sra.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(RTL_H) \
$(TM_P_H) $(TREE_FLOW_H) $(DIAGNOSTIC_H) $(TREE_INLINE_H) \
$(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_GIMPLE_H) \
diff --git a/gcc/c-common.c b/gcc/c-common.c
index cfd3829..0bbb439 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -2543,7 +2543,7 @@ shorten_compare (tree *op0_ptr, tree *op1_ptr, tree *restype_ptr,
tree
pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
{
- tree size_exp;
+ tree size_exp, ret;
/* The result is a pointer of the same type that is being added. */
@@ -2570,6 +2570,12 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
else
size_exp = size_in_bytes (TREE_TYPE (result_type));
+ /* We are manipulating pointer values, so we don't need to warn
+ about relying on undefined signed overflow. We disable the
+ warning here because we use integer types so fold won't know that
+ they are really pointers. */
+ fold_defer_overflow_warnings ();
+
/* If what we are about to multiply by the size of the elements
contains a constant term, apply distributive law
and multiply that constant term separately.
@@ -2618,7 +2624,11 @@ pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop)
convert (TREE_TYPE (intop), size_exp), 1));
/* Create the sum or difference. */
- return fold_build2 (resultcode, result_type, ptrop, intop);
+ ret = fold_build2 (resultcode, result_type, ptrop, intop);
+
+ fold_undefer_and_ignore_overflow_warnings ();
+
+ return ret;
}
/* Return whether EXPR is a declaration whose address can never be
diff --git a/gcc/c-opts.c b/gcc/c-opts.c
index 2b0bc5f..9ac433a 100644
--- a/gcc/c-opts.c
+++ b/gcc/c-opts.c
@@ -1,5 +1,6 @@
/* C/ObjC/C++ command line option handling.
- Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
Contributed by Neil Booth.
This file is part of GCC.
@@ -394,6 +395,7 @@ c_common_handle_option (size_t scode, const char *arg, int value)
warn_sign_compare = value;
warn_switch = value;
warn_strict_aliasing = value;
+ warn_strict_overflow = value;
warn_string_literal_comparison = value;
warn_always_true = value;
warn_array_bounds = value;
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index c807a7e..28ce2ba 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -3270,6 +3270,8 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
if (unsigned_op1 ^ unsigned_op2)
{
+ bool ovf;
+
/* Do not warn if the result type is signed, since the
signed type will only be chosen if it can represent
all the values of the unsigned type. */
@@ -3278,8 +3280,10 @@ build_conditional_expr (tree ifexp, tree op1, tree op2)
/* Do not warn if the signed quantity is an unsuffixed
integer literal (or some static constant expression
involving such literals) and it is non-negative. */
- else if ((unsigned_op2 && tree_expr_nonnegative_p (op1))
- || (unsigned_op1 && tree_expr_nonnegative_p (op2)))
+ else if ((unsigned_op2
+ && tree_expr_nonnegative_warnv_p (op1, &ovf))
+ || (unsigned_op1
+ && tree_expr_nonnegative_warnv_p (op2, &ovf)))
/* OK */;
else
warning (0, "signed and unsigned type in conditional expression");
@@ -8303,6 +8307,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
else
{
tree sop, uop;
+ bool ovf;
if (op0_signed)
sop = xop0, uop = xop1;
@@ -8314,7 +8319,7 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1,
constant expression involving such literals or a
conditional expression involving such literals)
and it is non-negative. */
- if (tree_expr_nonnegative_p (sop))
+ if (tree_expr_nonnegative_warnv_p (sop, &ovf))
/* OK */;
/* Do not warn if the comparison is an equality operation,
the unsigned quantity is an integral constant, and it
diff --git a/gcc/common.opt b/gcc/common.opt
index dd3deb3..c6a9557 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -158,6 +158,14 @@ Wstrict-aliasing=
Common Joined UInteger Warning
Warn about code which might break strict aliasing rules
+Wstrict-overflow
+Common
+Warn about optimizations that assume that signed overflow is undefined
+
+Wstrict-overflow=
+Common Joined UInteger
+Warn about optimizations that assume that signed overflow is undefined
+
Wstring-literal-comparison
Common Var(warn_string_literal_comparison) Warning
Warn about comparisons to constant string literals
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 8274d74..8e81193 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -248,6 +248,7 @@ Objective-C and Objective-C++ Dialects}.
-Wreturn-type -Wsequence-point -Wshadow @gol
-Wsign-compare -Wstack-protector @gol
-Wstrict-aliasing -Wstrict-aliasing=2 @gol
+-Wstrict-overflow -Wstrict-overflow=@var{n} @gol
-Wstring-literal-comparison @gol
-Wswitch -Wswitch-default -Wswitch-enum @gol
-Wsystem-headers -Wtrigraphs -Wundef -Wuninitialized @gol
@@ -2972,6 +2973,56 @@ compiler is using for optimization. This warning catches more cases than
@option{-Wstrict-aliasing}, but it will also give a warning for some ambiguous
cases that are safe.
+@item -Wstrict-overflow
+@item -Wstrict-overflow=@var{n}
+@opindex -Wstrict-overflow
+This option is only active when @option{-fstrict-overflow} is active.
+It warns about cases where the compiler optimizes based on the
+assumption that signed overflow does not occur. Note that it does not
+warn about all cases where the code might overflow: it only warns
+about cases where the compiler implements some optimization. Thus
+this warning depends on the optimization level.
+
+An optimization which assumes that signed overflow does not occur is
+perfectly safe if the values of the variables involved are such that
+overflow never does, in fact, occur. Therefore this warning can
+easily give a false positive: a warning about code which is not
+actually a problem. To help focus on important issues, several
+warning levels are defined.
+
+@table @option
+@item -Wstrict-overflow=1
+Warn about cases which are both questionable and easy to avoid. For
+example: @code{x + 1 > x}; with @option{-fstrict-overflow}, the
+compiler will simplify this to @code{1}. @option{-Wstrict-overflow}
+(with no level) is the same as @option{-Wstrict-overflow=1}. This
+level of @option{-Wstrict-overflow} is enabled by @option{-Wall};
+higher levels are not, and must be explicitly requested.
+
+@item -Wstrict-overflow=2
+Also warn about other cases where a comparison is simplified to a
+constant. For example: @code{abs (x) >= 0}. This can only be
+simplified when @option{-fstrict-overflow} is in effect, because
+@code{abs (INT_MIN)} overflows to @code{INT_MIN}, which is less than
+zero.
+
+@item -Wstrict-overflow=3
+Also warn about other cases where a comparison is simplified. For
+example: @code{x + 1 > 1} will be simplified to @code{x > 0}.
+
+@item -Wstrict-overflow=4
+Also warn about other simplifications not covered by the above cases.
+For example: @code{(x * 10) / 5} will be simplified to @code{x * 2}.
+
+@item -Wstrict-overflow=5
+Also warn about cases where the compiler reduces the magnitude of a
+constant involved in a comparison. For example: @code{x + 2 > y} will
+be simplified to @code{x + 1 >= y}. This is reported only at the
+highest warning level because this simplification applies to many
+comparisons, so this warning level will give a very large number of
+false positives.
+@end table
+
@item -Warray-bounds
@opindex Wno-array-bounds
@opindex Warray-bounds
diff --git a/gcc/flags.h b/gcc/flags.h
index 2671ec3..1996bd1 100644
--- a/gcc/flags.h
+++ b/gcc/flags.h
@@ -114,6 +114,11 @@ extern HOST_WIDE_INT larger_than_size;
extern int warn_strict_aliasing;
+/* Nonzero means warn about optimizations which rely on undefined
+ signed overflow. */
+
+extern int warn_strict_overflow;
+
/* Temporarily suppress certain warnings.
This is set while reading code from a system header file. */
@@ -289,8 +294,13 @@ extern const char *flag_random_seed;
(TYPE_UNSIGNED (TYPE) || 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. */
+ 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
+ it will be appropriate to issue the warning immediately, and in
+ 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) \
(!TYPE_UNSIGNED (TYPE) && !flag_wrapv && !flag_trapv && flag_strict_overflow)
@@ -299,4 +309,37 @@ extern const char *flag_random_seed;
#define TYPE_OVERFLOW_TRAPS(TYPE) \
(!TYPE_UNSIGNED (TYPE) && flag_trapv)
+/* Names for the different levels of -Wstrict-overflow=N. The numeric
+ values here correspond to N. */
+
+enum warn_strict_overflow_code
+{
+ /* Overflow warning that should be issued with -Wall: a questionable
+ construct that is easy to avoid even when using macros. Example:
+ folding (x + CONSTANT > x) to 1. */
+ WARN_STRICT_OVERFLOW_ALL = 1,
+ /* Overflow warning about folding a comparison to a constant because
+ of undefined signed overflow, other than cases covered by
+ WARN_STRICT_OVERFLOW_ALL. Example: folding (abs (x) >= 0) to 1
+ (this is false when x == INT_MIN). */
+ WARN_STRICT_OVERFLOW_CONDITIONAL = 2,
+ /* Overflow warning about changes to comparisons other than folding
+ them to a constant. Example: folding (x + 1 > 1) to (x > 0). */
+ WARN_STRICT_OVERFLOW_COMPARISON = 3,
+ /* Overflow warnings not covered by the above cases. Example:
+ folding ((x * 10) / 5) to (x * 2). */
+ WARN_STRICT_OVERFLOW_MISC = 4,
+ /* Overflow warnings about reducing magnitude of constants in
+ comparison. Example: folding (x + 2 > y) to (x + 1 >= y). */
+ WARN_STRICT_OVERFLOW_MAGNITUDE = 5
+};
+
+/* Whether to emit an overflow warning whose code is C. */
+
+static inline bool
+issue_strict_overflow_warning (enum warn_strict_overflow_code c)
+{
+ return warn_strict_overflow >= (int) c;
+}
+
#endif /* ! GCC_FLAGS_H */
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index d20d78f..7d66736 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -59,6 +59,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "expr.h"
#include "tm_p.h"
#include "toplev.h"
+#include "intl.h"
#include "ggc.h"
#include "hashtab.h"
#include "langhooks.h"
@@ -119,7 +120,7 @@ static int simple_operand_p (tree);
static tree range_binop (enum tree_code, tree, tree, int, tree, int);
static tree range_predecessor (tree);
static tree range_successor (tree);
-static tree make_range (tree, int *, tree *, tree *);
+static tree make_range (tree, int *, tree *, tree *, bool *);
static tree build_range_check (tree, tree, int, tree, tree);
static int merge_ranges (int *, tree *, tree *, int, tree, tree, int, tree,
tree);
@@ -128,8 +129,8 @@ static tree fold_cond_expr_with_comparison (tree, tree, tree, tree);
static tree unextend (tree, int, int, tree);
static tree fold_truthop (enum tree_code, tree, tree, tree);
static tree optimize_minmax_comparison (enum tree_code, tree, tree, tree);
-static tree extract_muldiv (tree, tree, enum tree_code, tree);
-static tree extract_muldiv_1 (tree, tree, enum tree_code, tree);
+static tree extract_muldiv (tree, tree, enum tree_code, tree, bool *);
+static tree extract_muldiv_1 (tree, tree, enum tree_code, tree, bool *);
static int multiple_of_p (tree, tree, tree);
static tree fold_binary_op_with_conditional_arg (enum tree_code, tree,
tree, tree,
@@ -901,6 +902,122 @@ div_if_zero_remainder (enum tree_code code, tree arg1, tree arg2)
return build_int_cst_wide (type, quol, quoh);
}
+/* This is non-zero if we should defer warnings about undefined
+ overflow. This facility exists because these warnings are a
+ special case. The code to estimate loop iterations does not want
+ to issue any warnings, since it works with expressions which do not
+ occur in user code. Various bits of cleanup code call fold(), but
+ only use the result if it has certain characteristics (e.g., is a
+ constant); that code only wants to issue a warning if the result is
+ used. */
+
+static int fold_deferring_overflow_warnings;
+
+/* If a warning about undefined overflow is deferred, this is the
+ warning. Note that this may cause us to turn two warnings into
+ one, but that is fine since it is sufficient to only give one
+ warning per expression. */
+
+static const char* fold_deferred_overflow_warning;
+
+/* If a warning about undefined overflow is deferred, this is the
+ level at which the warning should be emitted. */
+
+static enum warn_strict_overflow_code fold_deferred_overflow_code;
+
+/* Start deferring overflow warnings. We could use a stack here to
+ permit nested calls, but at present it is not necessary. */
+
+void
+fold_defer_overflow_warnings (void)
+{
+ ++fold_deferring_overflow_warnings;
+}
+
+/* Stop deferring overflow warnings. If there is a pending warning,
+ and ISSUE is true, then issue the warning if appropriate. STMT is
+ the statement with which the warning should be associated (used for
+ location information); STMT may be NULL. CODE is the level of the
+ warning--a warn_strict_overflow_code value. This function will use
+ the smaller of CODE and the deferred code when deciding whether to
+ issue the warning. CODE may be zero to mean to always use the
+ deferred code. */
+
+void
+fold_undefer_overflow_warnings (bool issue, tree stmt, int code)
+{
+ const char *warnmsg;
+ location_t locus;
+
+ gcc_assert (fold_deferring_overflow_warnings > 0);
+ --fold_deferring_overflow_warnings;
+ if (fold_deferring_overflow_warnings > 0)
+ {
+ if (fold_deferred_overflow_warning != NULL
+ && code != 0
+ && code < (int) fold_deferred_overflow_code)
+ fold_deferred_overflow_code = code;
+ return;
+ }
+
+ warnmsg = fold_deferred_overflow_warning;
+ fold_deferred_overflow_warning = NULL;
+
+ if (!issue || warnmsg == NULL)
+ return;
+
+ /* Use the smallest code level when deciding to issue the
+ warning. */
+ if (code == 0 || code > (int) fold_deferred_overflow_code)
+ code = fold_deferred_overflow_code;
+
+ if (!issue_strict_overflow_warning (code))
+ return;
+
+ if (stmt == NULL_TREE || !expr_has_location (stmt))
+ locus = input_location;
+ else
+ locus = expr_location (stmt);
+ warning (OPT_Wstrict_overflow, "%H%s", &locus, warnmsg);
+}
+
+/* Stop deferring overflow warnings, ignoring any deferred
+ warnings. */
+
+void
+fold_undefer_and_ignore_overflow_warnings (void)
+{
+ fold_undefer_overflow_warnings (false, NULL_TREE, 0);
+}
+
+/* Whether we are deferring overflow warnings. */
+
+bool
+fold_deferring_overflow_warnings_p (void)
+{
+ return fold_deferring_overflow_warnings > 0;
+}
+
+/* This is called when we fold something based on the fact that signed
+ overflow is undefined. */
+
+static void
+fold_overflow_warning (const char* gmsgid, enum warn_strict_overflow_code wc)
+{
+ gcc_assert (!flag_wrapv && !flag_trapv);
+ if (fold_deferring_overflow_warnings > 0)
+ {
+ if (fold_deferred_overflow_warning == NULL
+ || wc < fold_deferred_overflow_code)
+ {
+ fold_deferred_overflow_warning = gmsgid;
+ fold_deferred_overflow_code = wc;
+ }
+ }
+ else if (issue_strict_overflow_warning (wc))
+ warning (OPT_Wstrict_overflow, gmsgid);
+}
+
/* Return true if the built-in mathematical function specified by CODE
is odd, i.e. -f(x) == f(-x). */
@@ -1054,6 +1171,11 @@ negate_expr_p (tree t)
case FLOOR_DIV_EXPR:
case CEIL_DIV_EXPR:
case EXACT_DIV_EXPR:
+ /* In general we can't negate A / B, because if A is INT_MIN and
+ B is 1, we may turn this into INT_MIN / -1 which is undefined
+ and actually traps on some architectures. But if overflow is
+ undefined, we can negate, because - (INT_MIN / 1) is an
+ overflow. */
if (INTEGRAL_TYPE_P (TREE_TYPE (t))
&& !TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t)))
break;
@@ -1215,16 +1337,35 @@ fold_negate_expr (tree t)
case FLOOR_DIV_EXPR:
case CEIL_DIV_EXPR:
case EXACT_DIV_EXPR:
+ /* In general we can't negate A / B, because if A is INT_MIN and
+ B is 1, we may turn this into INT_MIN / -1 which is undefined
+ and actually traps on some architectures. But if overflow is
+ undefined, we can negate, because - (INT_MIN / 1) is an
+ overflow. */
if (!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type))
{
+ const char * const warnmsg = G_("assuming signed overflow does not "
+ "occur when negating a division");
tem = TREE_OPERAND (t, 1);
if (negate_expr_p (tem))
- return fold_build2 (TREE_CODE (t), type,
- TREE_OPERAND (t, 0), negate_expr (tem));
+ {
+ if (INTEGRAL_TYPE_P (type)
+ && (TREE_CODE (tem) != INTEGER_CST
+ || integer_onep (tem)))
+ fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MISC);
+ return fold_build2 (TREE_CODE (t), type,
+ TREE_OPERAND (t, 0), negate_expr (tem));
+ }
tem = TREE_OPERAND (t, 0);
if (negate_expr_p (tem))
- return fold_build2 (TREE_CODE (t), type,
- negate_expr (tem), TREE_OPERAND (t, 1));
+ {
+ if (INTEGRAL_TYPE_P (type)
+ && (TREE_CODE (tem) != INTEGER_CST
+ || tree_int_cst_equal (tem, TYPE_MIN_VALUE (type))))
+ fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MISC);
+ return fold_build2 (TREE_CODE (t), type,
+ negate_expr (tem), TREE_OPERAND (t, 1));
+ }
}
break;
@@ -3861,12 +4002,16 @@ range_binop (enum tree_code code, tree type, tree arg0, int upper0_p,
/* Given EXP, a logical expression, set the range it is testing into
variables denoted by PIN_P, PLOW, and PHIGH. Return the expression
- actually being tested. *PLOW and *PHIGH will be made of the same type
- as the returned expression. If EXP is not a comparison, we will most
- likely not be returning a useful value and range. */
+ actually being tested. *PLOW and *PHIGH will be made of the same
+ type as the returned expression. If EXP is not a comparison, we
+ will most likely not be returning a useful value and range. Set
+ *STRICT_OVERFLOW_P to true if the return value is only valid
+ because signed overflow is undefined; otherwise, do not change
+ *STRICT_OVERFLOW_P. */
static tree
-make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
+make_range (tree exp, int *pin_p, tree *plow, tree *phigh,
+ bool *strict_overflow_p)
{
enum tree_code code;
tree arg0 = NULL_TREE, arg1 = NULL_TREE;
@@ -4015,6 +4160,9 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh)
|| (n_high != 0 && TREE_OVERFLOW (n_high)))
break;
+ if (TYPE_OVERFLOW_UNDEFINED (arg0_type))
+ *strict_overflow_p = true;
+
/* Check for an unsigned range which has wrapped around the maximum
value thus making n_high < n_low, and normalize it. */
if (n_low && n_high && tree_int_cst_lt (n_high, n_low))
@@ -4796,9 +4944,12 @@ fold_range_test (enum tree_code code, tree type, tree op0, tree op1)
|| code == TRUTH_OR_EXPR);
int in0_p, in1_p, in_p;
tree low0, low1, low, high0, high1, high;
- tree lhs = make_range (op0, &in0_p, &low0, &high0);
- tree rhs = make_range (op1, &in1_p, &low1, &high1);
+ bool strict_overflow_p = false;
+ tree lhs = make_range (op0, &in0_p, &low0, &high0, &strict_overflow_p);
+ tree rhs = make_range (op1, &in1_p, &low1, &high1, &strict_overflow_p);
tree tem;
+ const char * const warnmsg = G_("assuming signed overflow does not occur "
+ "when simplifying range test");
/* If this is an OR operation, invert both sides; we will invert
again at the end. */
@@ -4816,7 +4967,11 @@ fold_range_test (enum tree_code code, tree type, tree op0, tree op1)
lhs != 0 ? lhs
: rhs != 0 ? rhs : integer_zero_node,
in_p, low, high))))
- return or_op ? invert_truthvalue (tem) : tem;
+ {
+ if (strict_overflow_p)
+ fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON);
+ return or_op ? invert_truthvalue (tem) : tem;
+ }
/* On machines where the branch cost is expensive, if this is a
short-circuited branch and the underlying object on both sides
@@ -4846,9 +5001,14 @@ fold_range_test (enum tree_code code, tree type, tree op0, tree op1)
&& (0 != (rhs = build_range_check (type, common,
or_op ? ! in1_p : in1_p,
low1, high1))))
- return build2 (code == TRUTH_ANDIF_EXPR
- ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
- type, lhs, rhs);
+ {
+ if (strict_overflow_p)
+ fold_overflow_warning (warnmsg,
+ WARN_STRICT_OVERFLOW_COMPARISON);
+ return build2 (code == TRUTH_ANDIF_EXPR
+ ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
+ type, lhs, rhs);
+ }
}
}
@@ -5447,10 +5607,15 @@ optimize_minmax_comparison (enum tree_code code, tree type, tree op0, tree op1)
addressing calculation.
If we return a non-null expression, it is an equivalent form of the
- original computation, but need not be in the original type. */
+ original computation, but need not be in the original type.
+
+ We set *STRICT_OVERFLOW_P to true if the return values depends on
+ signed overflow being undefined. Otherwise we do not change
+ *STRICT_OVERFLOW_P. */
static tree
-extract_muldiv (tree t, tree c, enum tree_code code, tree wide_type)
+extract_muldiv (tree t, tree c, enum tree_code code, tree wide_type,
+ bool *strict_overflow_p)
{
/* To avoid exponential search depth, refuse to allow recursion past
three levels. Beyond that (1) it's highly unlikely that we'll find
@@ -5464,14 +5629,15 @@ extract_muldiv (tree t, tree c, enum tree_code code, tree wide_type)
return NULL;
depth++;
- ret = extract_muldiv_1 (t, c, code, wide_type);
+ ret = extract_muldiv_1 (t, c, code, wide_type, strict_overflow_p);
depth--;
return ret;
}
static tree
-extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
+extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
+ bool *strict_overflow_p)
{
tree type = TREE_TYPE (t);
enum tree_code tcode = TREE_CODE (t);
@@ -5481,6 +5647,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
tree t1, t2;
int same_p = tcode == code;
tree op0 = NULL_TREE, op1 = NULL_TREE;
+ bool sub_strict_overflow_p;
/* Don't deal with constants of zero here; they confuse the code below. */
if (integer_zerop (c))
@@ -5537,7 +5704,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
&& !TREE_OVERFLOW (t2)
&& (0 != (t1 = extract_muldiv (op0, t2, code,
code == MULT_EXPR
- ? ctype : NULL_TREE))))
+ ? ctype : NULL_TREE,
+ strict_overflow_p))))
return t1;
break;
@@ -5547,7 +5715,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
if (TYPE_UNSIGNED (ctype) && !TYPE_UNSIGNED (type))
{
tree cstype = (*lang_hooks.types.signed_type) (ctype);
- if ((t1 = extract_muldiv (op0, c, code, cstype)) != 0)
+ if ((t1 = extract_muldiv (op0, c, code, cstype, strict_overflow_p))
+ != 0)
{
t1 = fold_build1 (tcode, cstype, fold_convert (cstype, t1));
return fold_convert (ctype, t1);
@@ -5556,7 +5725,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
}
/* FALLTHROUGH */
case NEGATE_EXPR:
- if ((t1 = extract_muldiv (op0, c, code, wide_type)) != 0)
+ if ((t1 = extract_muldiv (op0, c, code, wide_type, strict_overflow_p))
+ != 0)
return fold_build1 (tcode, ctype, fold_convert (ctype, t1));
break;
@@ -5567,12 +5737,16 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
break;
/* MIN (a, b) / 5 -> MIN (a / 5, b / 5) */
- if ((t1 = extract_muldiv (op0, c, code, wide_type)) != 0
- && (t2 = extract_muldiv (op1, c, code, wide_type)) != 0)
+ sub_strict_overflow_p = false;
+ if ((t1 = extract_muldiv (op0, c, code, wide_type,
+ &sub_strict_overflow_p)) != 0
+ && (t2 = extract_muldiv (op1, c, code, wide_type,
+ &sub_strict_overflow_p)) != 0)
{
if (tree_int_cst_sgn (c) < 0)
tcode = (tcode == MIN_EXPR ? MAX_EXPR : MIN_EXPR);
-
+ if (sub_strict_overflow_p)
+ *strict_overflow_p = true;
return fold_build2 (tcode, ctype, fold_convert (ctype, t1),
fold_convert (ctype, t2));
}
@@ -5599,7 +5773,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
return extract_muldiv (build2 (tcode == LSHIFT_EXPR
? MULT_EXPR : FLOOR_DIV_EXPR,
ctype, fold_convert (ctype, op0), t1),
- c, code, wide_type);
+ c, code, wide_type, strict_overflow_p);
break;
case PLUS_EXPR: case MINUS_EXPR:
@@ -5607,16 +5781,21 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
can return a new PLUS or MINUS. If we can't, the only remaining
cases where we can do anything are if the second operand is a
constant. */
- t1 = extract_muldiv (op0, c, code, wide_type);
- t2 = extract_muldiv (op1, c, code, wide_type);
+ sub_strict_overflow_p = false;
+ t1 = extract_muldiv (op0, c, code, wide_type, &sub_strict_overflow_p);
+ t2 = extract_muldiv (op1, c, code, wide_type, &sub_strict_overflow_p);
if (t1 != 0 && t2 != 0
&& (code == MULT_EXPR
/* If not multiplication, we can only do this if both operands
are divisible by c. */
|| (multiple_of_p (ctype, op0, c)
&& multiple_of_p (ctype, op1, c))))
- return fold_build2 (tcode, ctype, fold_convert (ctype, t1),
- fold_convert (ctype, t2));
+ {
+ if (sub_strict_overflow_p)
+ *strict_overflow_p = true;
+ return fold_build2 (tcode, ctype, fold_convert (ctype, t1),
+ fold_convert (ctype, t2));
+ }
/* If this was a subtraction, negate OP1 and set it to be an addition.
This simplifies the logic below. */
@@ -5697,11 +5876,13 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
new operation. Likewise for the RHS from a MULT_EXPR. Otherwise,
do something only if the second operand is a constant. */
if (same_p
- && (t1 = extract_muldiv (op0, c, code, wide_type)) != 0)
+ && (t1 = extract_muldiv (op0, c, code, wide_type,
+ strict_overflow_p)) != 0)
return fold_build2 (tcode, ctype, fold_convert (ctype, t1),
fold_convert (ctype, op1));
else if (tcode == MULT_EXPR && code == MULT_EXPR
- && (t1 = extract_muldiv (op1, c, code, wide_type)) != 0)
+ && (t1 = extract_muldiv (op1, c, code, wide_type,
+ strict_overflow_p)) != 0)
return fold_build2 (tcode, ctype, fold_convert (ctype, op0),
fold_convert (ctype, t1));
else if (TREE_CODE (op1) != INTEGER_CST)
@@ -5731,15 +5912,23 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type)
&& code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR)))
{
if (integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0)))
- return fold_build2 (tcode, ctype, fold_convert (ctype, op0),
- fold_convert (ctype,
- const_binop (TRUNC_DIV_EXPR,
- op1, c, 0)));
+ {
+ if (TYPE_OVERFLOW_UNDEFINED (ctype))
+ *strict_overflow_p = true;
+ return fold_build2 (tcode, ctype, fold_convert (ctype, op0),
+ fold_convert (ctype,
+ const_binop (TRUNC_DIV_EXPR,
+ op1, c, 0)));
+ }
else if (integer_zerop (const_binop (TRUNC_MOD_EXPR, c, op1, 0)))
- return fold_build2 (code, ctype, fold_convert (ctype, op0),
- fold_convert (ctype,
- const_binop (TRUNC_DIV_EXPR,
- c, op1, 0)));
+ {
+ if (TYPE_OVERFLOW_UNDEFINED (ctype))
+ *strict_overflow_p = true;
+ return fold_build2 (code, ctype, fold_convert (ctype, op0),
+ fold_convert (ctype,
+ const_binop (TRUNC_DIV_EXPR,
+ c, op1, 0)));
+ }
}
break;
@@ -7667,7 +7856,9 @@ fold_unary (enum tree_code code, tree type, tree op0)
targ0));
}
/* ABS_EXPR<ABS_EXPR<x>> = ABS_EXPR<x> even if flag_wrapv is on. */
- else if (tree_expr_nonnegative_p (arg0) || TREE_CODE (arg0) == ABS_EXPR)
+ else if (TREE_CODE (arg0) == ABS_EXPR)
+ return arg0;
+ else if (tree_expr_nonnegative_p (arg0))
return arg0;
/* Strip sign ops from argument. */
@@ -7884,11 +8075,14 @@ fold_minmax (enum tree_code code, tree type, tree op0, tree op1)
by changing CODE to reduce the magnitude of constants involved in
ARG0 of the comparison.
Returns a canonicalized comparison tree if a simplification was
- possible, otherwise returns NULL_TREE. */
+ possible, otherwise returns NULL_TREE.
+ Set *STRICT_OVERFLOW_P to true if the canonicalization is only
+ valid if signed overflow is undefined. */
static tree
maybe_canonicalize_comparison_1 (enum tree_code code, tree type,
- tree arg0, tree arg1)
+ tree arg0, tree arg1,
+ bool *strict_overflow_p)
{
enum tree_code code0 = TREE_CODE (arg0);
tree t, cst0 = NULL_TREE;
@@ -7955,6 +8149,7 @@ maybe_canonicalize_comparison_1 (enum tree_code code, tree type,
code = GT_EXPR;
else
return NULL_TREE;
+ *strict_overflow_p = true;
}
/* Now build the constant reduced in magnitude. */
@@ -7981,6 +8176,9 @@ maybe_canonicalize_comparison (enum tree_code code, tree type,
tree arg0, tree arg1)
{
tree t;
+ bool strict_overflow_p;
+ const char * const warnmsg = G_("assuming signed overflow does not occur "
+ "when reducing constant in comparison");
/* In principle pointers also have undefined overflow behavior,
but that causes problems elsewhere. */
@@ -7989,14 +8187,25 @@ maybe_canonicalize_comparison (enum tree_code code, tree type,
return NULL_TREE;
/* Try canonicalization by simplifying arg0. */
- t = maybe_canonicalize_comparison_1 (code, type, arg0, arg1);
+ strict_overflow_p = false;
+ t = maybe_canonicalize_comparison_1 (code, type, arg0, arg1,
+ &strict_overflow_p);
if (t)
- return t;
+ {
+ if (strict_overflow_p)
+ fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MAGNITUDE);
+ return t;
+ }
/* Try canonicalization by simplifying arg1 using the swapped
comparison. */
code = swap_tree_comparison (code);
- return maybe_canonicalize_comparison_1 (code, type, arg1, arg0);
+ strict_overflow_p = false;
+ t = maybe_canonicalize_comparison_1 (code, type, arg1, arg0,
+ &strict_overflow_p);
+ if (t && strict_overflow_p)
+ fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MAGNITUDE);
+ return t;
}
/* Subroutine of fold_binary. This routine performs all of the
@@ -8080,7 +8289,13 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
if (TREE_CODE (lhs) == TREE_CODE (arg1)
&& (TREE_CODE (lhs) != INTEGER_CST
|| !TREE_OVERFLOW (lhs)))
- return fold_build2 (code, type, variable, lhs);
+ {
+ fold_overflow_warning (("assuming signed overflow does not occur "
+ "when changing X +- C1 cmp C2 to "
+ "X cmp C1 +- C2"),
+ WARN_STRICT_OVERFLOW_COMPARISON);
+ return fold_build2 (code, type, variable, lhs);
+ }
}
/* For comparisons of pointers we can decompose it to a compile time
@@ -8245,6 +8460,9 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
tree variable1 = TREE_OPERAND (arg0, 0);
tree variable2 = TREE_OPERAND (arg1, 0);
tree cst;
+ const char * const warnmsg = G_("assuming signed overflow does not "
+ "occur when combining constants around "
+ "a comparison");
/* Put the constant on the side where it doesn't overflow and is
of lower absolute value than before. */
@@ -8253,20 +8471,26 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
const2, const1, 0);
if (!TREE_OVERFLOW (cst)
&& tree_int_cst_compare (const2, cst) == tree_int_cst_sgn (const2))
- return fold_build2 (code, type,
- variable1,
- fold_build2 (TREE_CODE (arg1), TREE_TYPE (arg1),
- variable2, cst));
+ {
+ fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON);
+ return fold_build2 (code, type,
+ variable1,
+ fold_build2 (TREE_CODE (arg1), TREE_TYPE (arg1),
+ variable2, cst));
+ }
cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1)
? MINUS_EXPR : PLUS_EXPR,
const1, const2, 0);
if (!TREE_OVERFLOW (cst)
&& tree_int_cst_compare (const1, cst) == tree_int_cst_sgn (const1))
- return fold_build2 (code, type,
- fold_build2 (TREE_CODE (arg0), TREE_TYPE (arg0),
- variable1, cst),
- variable2);
+ {
+ fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON);
+ return fold_build2 (code, type,
+ fold_build2 (TREE_CODE (arg0), TREE_TYPE (arg0),
+ variable1, cst),
+ variable2);
+ }
}
/* Transform comparisons of the form X * C1 CMP 0 to X CMP 0 in the
@@ -8286,6 +8510,11 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
gcc_assert (!integer_zerop (const1));
+ fold_overflow_warning (("assuming signed overflow does not occur when "
+ "eliminating multiplication in comparison "
+ "with zero"),
+ WARN_STRICT_OVERFLOW_COMPARISON);
+
/* If const1 is negative we swap the sense of the comparison. */
if (tree_int_cst_sgn (const1) < 0)
cmp_code = swap_tree_comparison (cmp_code);
@@ -8721,6 +8950,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
enum tree_code_class kind = TREE_CODE_CLASS (code);
tree arg0, arg1, tem;
tree t1 = NULL_TREE;
+ bool strict_overflow_p;
gcc_assert ((IS_EXPR_CODE_CLASS (kind)
|| IS_GIMPLE_STMT_CODE_CLASS (kind))
@@ -9468,11 +9698,20 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
return fold_build2 (LSHIFT_EXPR, type, arg1,
TREE_OPERAND (arg0, 1));
+ strict_overflow_p = false;
if (TREE_CODE (arg1) == INTEGER_CST
&& 0 != (tem = extract_muldiv (op0,
fold_convert (type, arg1),
- code, NULL_TREE)))
- return fold_convert (type, tem);
+ code, NULL_TREE,
+ &strict_overflow_p)))
+ {
+ if (strict_overflow_p)
+ fold_overflow_warning (("assuming signed overflow does not "
+ "occur when simplifying "
+ "multiplication"),
+ WARN_STRICT_OVERFLOW_MISC);
+ return fold_convert (type, tem);
+ }
/* Optimize z * conj(z) for integer complex numbers. */
if (TREE_CODE (arg0) == CONJ_EXPR
@@ -10372,8 +10611,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
case FLOOR_DIV_EXPR:
/* Simplify A / (B << N) where A and B are positive and B is
a power of 2, to A >> (N + log2(B)). */
+ strict_overflow_p = false;
if (TREE_CODE (arg1) == LSHIFT_EXPR
- && (TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (arg0)))
+ && (TYPE_UNSIGNED (type)
+ || tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p)))
{
tree sval = TREE_OPERAND (arg1, 0);
if (integer_pow2p (sval) && tree_int_cst_sgn (sval) > 0)
@@ -10381,6 +10622,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
tree sh_cnt = TREE_OPERAND (arg1, 1);
unsigned long pow2 = exact_log2 (TREE_INT_CST_LOW (sval));
+ if (strict_overflow_p)
+ fold_overflow_warning (("assuming signed overflow does not "
+ "occur when simplifying A / (B << N)"),
+ WARN_STRICT_OVERFLOW_MISC);
+
sh_cnt = fold_build2 (PLUS_EXPR, TREE_TYPE (sh_cnt),
sh_cnt, build_int_cst (NULL_TREE, pow2));
return fold_build2 (RSHIFT_EXPR, type,
@@ -10408,13 +10654,27 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type))
&& TREE_CODE (arg0) == NEGATE_EXPR
&& negate_expr_p (arg1))
- return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
- negate_expr (arg1));
+ {
+ if (INTEGRAL_TYPE_P (type))
+ fold_overflow_warning (("assuming signed overflow does not occur "
+ "when distributing negation across "
+ "division"),
+ WARN_STRICT_OVERFLOW_MISC);
+ return fold_build2 (code, type, TREE_OPERAND (arg0, 0),
+ negate_expr (arg1));
+ }
if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type))
&& TREE_CODE (arg1) == NEGATE_EXPR
&& negate_expr_p (arg0))
- return fold_build2 (code, type, negate_expr (arg0),
- TREE_OPERAND (arg1, 0));
+ {
+ if (INTEGRAL_TYPE_P (type))
+ fold_overflow_warning (("assuming signed overflow does not occur "
+ "when distributing negation across "
+ "division"),
+ WARN_STRICT_OVERFLOW_MISC);
+ return fold_build2 (code, type, negate_expr (arg0),
+ TREE_OPERAND (arg1, 0));
+ }
/* If arg0 is a multiple of arg1, then rewrite to the fastest div
operation, EXACT_DIV_EXPR.
@@ -10426,9 +10686,17 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
&& multiple_of_p (type, arg0, arg1))
return fold_build2 (EXACT_DIV_EXPR, type, arg0, arg1);
+ strict_overflow_p = false;
if (TREE_CODE (arg1) == INTEGER_CST
- && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE)))
- return fold_convert (type, tem);
+ && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE,
+ &strict_overflow_p)))
+ {
+ if (strict_overflow_p)
+ fold_overflow_warning (("assuming signed overflow does not occur "
+ "when simplifying division"),
+ WARN_STRICT_OVERFLOW_MISC);
+ return fold_convert (type, tem);
+ }
return NULL_TREE;
@@ -10460,8 +10728,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
/* Optimize TRUNC_MOD_EXPR by a power of two into a BIT_AND_EXPR,
i.e. "X % C" into "X & (C - 1)", if X and C are positive. */
+ strict_overflow_p = false;
if ((code == TRUNC_MOD_EXPR || code == FLOOR_MOD_EXPR)
- && (TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (arg0)))
+ && (TYPE_UNSIGNED (type)
+ || tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p)))
{
tree c = arg1;
/* Also optimize A % (C << N) where C is a power of 2,
@@ -10473,6 +10743,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
{
tree mask = fold_build2 (MINUS_EXPR, TREE_TYPE (arg1), arg1,
build_int_cst (TREE_TYPE (arg1), 1));
+ if (strict_overflow_p)
+ fold_overflow_warning (("assuming signed overflow does not "
+ "occur when simplifying "
+ "X % (power of two)"),
+ WARN_STRICT_OVERFLOW_MISC);
return fold_build2 (BIT_AND_EXPR, type,
fold_convert (type, arg0),
fold_convert (type, mask));
@@ -10500,8 +10775,15 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
fold_convert (type, TREE_OPERAND (arg1, 0)));
if (TREE_CODE (arg1) == INTEGER_CST
- && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE)))
- return fold_convert (type, tem);
+ && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE,
+ &strict_overflow_p)))
+ {
+ if (strict_overflow_p)
+ fold_overflow_warning (("assuming signed overflow does not occur "
+ "when simplifying modulos"),
+ WARN_STRICT_OVERFLOW_MISC);
+ return fold_convert (type, tem);
+ }
return NULL_TREE;
@@ -11330,27 +11612,59 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
if (code == GT_EXPR
&& ((code0 == MINUS_EXPR && is_positive >= 0)
|| (code0 == PLUS_EXPR && is_positive <= 0)))
- return constant_boolean_node (0, type);
+ {
+ if (TREE_CODE (arg01) == INTEGER_CST
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
+ fold_overflow_warning (("assuming signed overflow does not "
+ "occur when assuming that (X - c) > X "
+ "is always false"),
+ WARN_STRICT_OVERFLOW_ALL);
+ return constant_boolean_node (0, type);
+ }
/* Likewise (X + c) < X becomes false. */
if (code == LT_EXPR
&& ((code0 == PLUS_EXPR && is_positive >= 0)
|| (code0 == MINUS_EXPR && is_positive <= 0)))
- return constant_boolean_node (0, type);
+ {
+ if (TREE_CODE (arg01) == INTEGER_CST
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
+ fold_overflow_warning (("assuming signed overflow does not "
+ "occur when assuming that "
+ "(X + c) < X is always false"),
+ WARN_STRICT_OVERFLOW_ALL);
+ return constant_boolean_node (0, type);
+ }
/* Convert (X - c) <= X to true. */
if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))
&& code == LE_EXPR
&& ((code0 == MINUS_EXPR && is_positive >= 0)
|| (code0 == PLUS_EXPR && is_positive <= 0)))
- return constant_boolean_node (1, type);
+ {
+ if (TREE_CODE (arg01) == INTEGER_CST
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
+ fold_overflow_warning (("assuming signed overflow does not "
+ "occur when assuming that "
+ "(X - c) <= X is always true"),
+ WARN_STRICT_OVERFLOW_ALL);
+ return constant_boolean_node (1, type);
+ }
/* Convert (X + c) >= X to true. */
if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1)))
&& code == GE_EXPR
&& ((code0 == PLUS_EXPR && is_positive >= 0)
|| (code0 == MINUS_EXPR && is_positive <= 0)))
- return constant_boolean_node (1, type);
+ {
+ if (TREE_CODE (arg01) == INTEGER_CST
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
+ fold_overflow_warning (("assuming signed overflow does not "
+ "occur when assuming that "
+ "(X + c) >= X is always true"),
+ WARN_STRICT_OVERFLOW_ALL);
+ return constant_boolean_node (1, type);
+ }
if (TREE_CODE (arg01) == INTEGER_CST)
{
@@ -11358,23 +11672,51 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
if (code == GT_EXPR
&& ((code0 == PLUS_EXPR && is_positive > 0)
|| (code0 == MINUS_EXPR && is_positive < 0)))
- return constant_boolean_node (1, type);
+ {
+ if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
+ fold_overflow_warning (("assuming signed overflow does "
+ "not occur when assuming that "
+ "(X + c) > X is always true"),
+ WARN_STRICT_OVERFLOW_ALL);
+ return constant_boolean_node (1, type);
+ }
if (code == LT_EXPR
&& ((code0 == MINUS_EXPR && is_positive > 0)
|| (code0 == PLUS_EXPR && is_positive < 0)))
- return constant_boolean_node (1, type);
+ {
+ if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
+ fold_overflow_warning (("assuming signed overflow does "
+ "not occur when assuming that "
+ "(X - c) < X is always true"),
+ WARN_STRICT_OVERFLOW_ALL);
+ return constant_boolean_node (1, type);
+ }
/* Convert X + c <= X and X - c >= X to false for integers. */
if (code == LE_EXPR
&& ((code0 == PLUS_EXPR && is_positive > 0)
|| (code0 == MINUS_EXPR && is_positive < 0)))
- return constant_boolean_node (0, type);
+ {
+ if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
+ fold_overflow_warning (("assuming signed overflow does "
+ "not occur when assuming that "
+ "(X + c) <= X is always false"),
+ WARN_STRICT_OVERFLOW_ALL);
+ return constant_boolean_node (0, type);
+ }
if (code == GE_EXPR
&& ((code0 == MINUS_EXPR && is_positive > 0)
|| (code0 == PLUS_EXPR && is_positive < 0)))
- return constant_boolean_node (0, type);
+ {
+ if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
+ fold_overflow_warning (("assuming signed overflow does "
+ "not occur when assuming that "
+ "(X - c) >= X is always true"),
+ WARN_STRICT_OVERFLOW_ALL);
+ return constant_boolean_node (0, type);
+ }
}
}
@@ -11575,18 +11917,34 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
TREE_OPERAND (arg0, 0), arg1));
/* Convert ABS_EXPR<x> >= 0 to true. */
+ strict_overflow_p = false;
if (code == GE_EXPR
- && tree_expr_nonnegative_p (arg0)
&& (integer_zerop (arg1)
|| (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
- && real_zerop (arg1))))
- return omit_one_operand (type, integer_one_node, arg0);
+ && real_zerop (arg1)))
+ && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))
+ {
+ if (strict_overflow_p)
+ fold_overflow_warning (("assuming signed overflow does not occur "
+ "when simplifying comparison of "
+ "absolute value and zero"),
+ WARN_STRICT_OVERFLOW_CONDITIONAL);
+ return omit_one_operand (type, integer_one_node, arg0);
+ }
/* Convert ABS_EXPR<x> < 0 to false. */
+ strict_overflow_p = false;
if (code == LT_EXPR
- && tree_expr_nonnegative_p (arg0)
- && (integer_zerop (arg1) || real_zerop (arg1)))
- return omit_one_operand (type, integer_zero_node, arg0);
+ && (integer_zerop (arg1) || real_zerop (arg1))
+ && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))
+ {
+ if (strict_overflow_p)
+ fold_overflow_warning (("assuming signed overflow does not occur "
+ "when simplifying comparison of "
+ "absolute value and zero"),
+ WARN_STRICT_OVERFLOW_CONDITIONAL);
+ return omit_one_operand (type, integer_zero_node, arg0);
+ }
/* If X is unsigned, convert X < (1 << Y) into X >> Y == 0
and similarly for >= into !=. */
@@ -12662,10 +13020,13 @@ multiple_of_p (tree type, tree top, tree bottom)
}
}
-/* Return true if `t' is known to be non-negative. */
+/* Return true if `t' is known to be non-negative. If the return
+ value is based on the assumption that signed overflow is undefined,
+ set *STRICT_OVERFLOW_P to true; otherwise, don't change
+ *STRICT_OVERFLOW_P. */
bool
-tree_expr_nonnegative_p (tree t)
+tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
{
if (t == error_mark_node)
return false;
@@ -12686,7 +13047,10 @@ tree_expr_nonnegative_p (tree t)
if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
return true;
if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t)))
- return true;
+ {
+ *strict_overflow_p = true;
+ return true;
+ }
break;
case INTEGER_CST:
@@ -12697,8 +13061,10 @@ tree_expr_nonnegative_p (tree t)
case PLUS_EXPR:
if (FLOAT_TYPE_P (TREE_TYPE (t)))
- return tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
- && tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
+ return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p)
+ && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
+ strict_overflow_p));
/* zero_extend(x) + zero_extend(y) is non-negative if x and y are
both unsigned and at least 2 bits shorter than the result. */
@@ -12724,8 +13090,10 @@ tree_expr_nonnegative_p (tree t)
/* x * x for floating point x is always non-negative. */
if (operand_equal_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1), 0))
return true;
- return tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
- && tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
+ return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p)
+ && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
+ strict_overflow_p));
}
/* zero_extend(x) * zero_extend(y) is non-negative if x and y are
@@ -12745,8 +13113,10 @@ tree_expr_nonnegative_p (tree t)
case BIT_AND_EXPR:
case MAX_EXPR:
- return tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
- || tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
+ return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p)
+ || tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
+ strict_overflow_p));
case BIT_IOR_EXPR:
case BIT_XOR_EXPR:
@@ -12756,8 +13126,10 @@ tree_expr_nonnegative_p (tree t)
case CEIL_DIV_EXPR:
case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR:
- return tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
- && tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
+ return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p)
+ && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
+ strict_overflow_p));
case TRUNC_MOD_EXPR:
case CEIL_MOD_EXPR:
@@ -12766,19 +13138,24 @@ tree_expr_nonnegative_p (tree t)
case SAVE_EXPR:
case NON_LVALUE_EXPR:
case FLOAT_EXPR:
- return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
+ return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p);
case COMPOUND_EXPR:
case MODIFY_EXPR:
case GIMPLE_MODIFY_STMT:
- return tree_expr_nonnegative_p (GENERIC_TREE_OPERAND (t, 1));
+ return tree_expr_nonnegative_warnv_p (GENERIC_TREE_OPERAND (t, 1),
+ strict_overflow_p);
case BIND_EXPR:
- return tree_expr_nonnegative_p (expr_last (TREE_OPERAND (t, 1)));
+ return tree_expr_nonnegative_warnv_p (expr_last (TREE_OPERAND (t, 1)),
+ strict_overflow_p);
case COND_EXPR:
- return tree_expr_nonnegative_p (TREE_OPERAND (t, 1))
- && tree_expr_nonnegative_p (TREE_OPERAND (t, 2));
+ return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
+ strict_overflow_p)
+ && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 2),
+ strict_overflow_p));
case NOP_EXPR:
{
@@ -12788,18 +13165,21 @@ tree_expr_nonnegative_p (tree t)
if (TREE_CODE (outer_type) == REAL_TYPE)
{
if (TREE_CODE (inner_type) == REAL_TYPE)
- return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
+ return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p);
if (TREE_CODE (inner_type) == INTEGER_TYPE)
{
if (TYPE_UNSIGNED (inner_type))
return true;
- return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
+ return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p);
}
}
else if (TREE_CODE (outer_type) == INTEGER_TYPE)
{
if (TREE_CODE (inner_type) == REAL_TYPE)
- return tree_expr_nonnegative_p (TREE_OPERAND (t,0));
+ return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t,0),
+ strict_overflow_p);
if (TREE_CODE (inner_type) == INTEGER_TYPE)
return TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type)
&& TYPE_UNSIGNED (inner_type);
@@ -12815,7 +13195,7 @@ tree_expr_nonnegative_p (tree t)
/* If the initializer is non-void, then it's a normal expression
that will be assigned to the slot. */
if (!VOID_TYPE_P (t))
- return tree_expr_nonnegative_p (t);
+ return tree_expr_nonnegative_warnv_p (t, strict_overflow_p);
/* Otherwise, the initializer sets the slot in some way. One common
way is an assignment statement at the end of the initializer. */
@@ -12834,7 +13214,8 @@ tree_expr_nonnegative_p (tree t)
if ((TREE_CODE (t) == MODIFY_EXPR
|| TREE_CODE (t) == GIMPLE_MODIFY_STMT)
&& GENERIC_TREE_OPERAND (t, 0) == temp)
- return tree_expr_nonnegative_p (GENERIC_TREE_OPERAND (t, 1));
+ return tree_expr_nonnegative_warnv_p (GENERIC_TREE_OPERAND (t, 1),
+ strict_overflow_p);
return false;
}
@@ -12870,7 +13251,8 @@ tree_expr_nonnegative_p (tree t)
/* sqrt(-0.0) is -0.0. */
if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (t))))
return true;
- return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+ return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist),
+ strict_overflow_p);
CASE_FLT_FN (BUILT_IN_ASINH):
CASE_FLT_FN (BUILT_IN_ATAN):
@@ -12900,21 +13282,30 @@ tree_expr_nonnegative_p (tree t)
CASE_FLT_FN (BUILT_IN_TANH):
CASE_FLT_FN (BUILT_IN_TRUNC):
/* True if the 1st argument is nonnegative. */
- return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+ return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist),
+ strict_overflow_p);
CASE_FLT_FN (BUILT_IN_FMAX):
/* True if the 1st OR 2nd arguments are nonnegative. */
- return tree_expr_nonnegative_p (TREE_VALUE (arglist))
- || tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist)));
+ return (tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist),
+ strict_overflow_p)
+ || (tree_expr_nonnegative_warnv_p
+ (TREE_VALUE (TREE_CHAIN (arglist)),
+ strict_overflow_p)));
CASE_FLT_FN (BUILT_IN_FMIN):
/* True if the 1st AND 2nd arguments are nonnegative. */
- return tree_expr_nonnegative_p (TREE_VALUE (arglist))
- && tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist)));
+ return (tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist),
+ strict_overflow_p)
+ && (tree_expr_nonnegative_warnv_p
+ (TREE_VALUE (TREE_CHAIN (arglist)),
+ strict_overflow_p)));
CASE_FLT_FN (BUILT_IN_COPYSIGN):
/* True if the 2nd argument is nonnegative. */
- return tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist)));
+ return (tree_expr_nonnegative_warnv_p
+ (TREE_VALUE (TREE_CHAIN (arglist)),
+ strict_overflow_p));
CASE_FLT_FN (BUILT_IN_POWI):
/* True if the 1st argument is nonnegative or the second
@@ -12925,7 +13316,8 @@ tree_expr_nonnegative_p (tree t)
if ((TREE_INT_CST_LOW (arg1) & 1) == 0)
return true;
}
- return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+ return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist),
+ strict_overflow_p);
CASE_FLT_FN (BUILT_IN_POW):
/* True if the 1st argument is nonnegative or the second
@@ -12946,7 +13338,8 @@ tree_expr_nonnegative_p (tree t)
return true;
}
}
- return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+ return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist),
+ strict_overflow_p);
default:
break;
@@ -12965,14 +13358,37 @@ tree_expr_nonnegative_p (tree t)
return false;
}
+/* Return true if `t' is known to be non-negative. Handle warnings
+ about undefined signed overflow. */
+
+bool
+tree_expr_nonnegative_p (tree t)
+{
+ bool ret, strict_overflow_p;
+
+ strict_overflow_p = false;
+ ret = tree_expr_nonnegative_warnv_p (t, &strict_overflow_p);
+ if (strict_overflow_p)
+ fold_overflow_warning (("assuming signed overflow does not occur when "
+ "determining that expression is always "
+ "non-negative"),
+ WARN_STRICT_OVERFLOW_MISC);
+ return ret;
+}
+
/* Return true when T is an address and is known to be nonzero.
For floating point we further ensure that T is not denormal.
- Similar logic is present in nonzero_address in rtlanal.h. */
+ Similar logic is present in nonzero_address in rtlanal.h.
+
+ If the return value is based on the assumption that signed overflow
+ is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't
+ change *STRICT_OVERFLOW_P. */
bool
-tree_expr_nonzero_p (tree t)
+tree_expr_nonzero_warnv_p (tree t, bool *strict_overflow_p)
{
tree type = TREE_TYPE (t);
+ bool sub_strict_overflow_p;
/* Doing something useful for floating point would need more work. */
if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type))
@@ -12986,7 +13402,8 @@ tree_expr_nonzero_p (tree t)
return ssa_name_nonzero_p (t);
case ABS_EXPR:
- return tree_expr_nonzero_p (TREE_OPERAND (t, 0));
+ return tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p);
case INTEGER_CST:
return !integer_zerop (t);
@@ -12996,20 +13413,34 @@ tree_expr_nonzero_p (tree t)
{
/* With the presence of negative values it is hard
to say something. */
- if (!tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
- || !tree_expr_nonnegative_p (TREE_OPERAND (t, 1)))
+ sub_strict_overflow_p = false;
+ if (!tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
+ &sub_strict_overflow_p)
+ || !tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
+ &sub_strict_overflow_p))
return false;
/* One of operands must be positive and the other non-negative. */
- return (tree_expr_nonzero_p (TREE_OPERAND (t, 0))
- || tree_expr_nonzero_p (TREE_OPERAND (t, 1)));
+ /* We don't set *STRICT_OVERFLOW_P here: even if this value
+ overflows, on a twos-complement machine the sum of two
+ nonnegative numbers can never be zero. */
+ return (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p)
+ || tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1),
+ strict_overflow_p));
}
break;
case MULT_EXPR:
if (TYPE_OVERFLOW_UNDEFINED (type))
{
- return (tree_expr_nonzero_p (TREE_OPERAND (t, 0))
- && tree_expr_nonzero_p (TREE_OPERAND (t, 1)));
+ if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p)
+ && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1),
+ strict_overflow_p))
+ {
+ *strict_overflow_p = true;
+ return true;
+ }
}
break;
@@ -13019,7 +13450,8 @@ tree_expr_nonzero_p (tree t)
tree outer_type = TREE_TYPE (t);
return (TYPE_PRECISION (outer_type) >= TYPE_PRECISION (inner_type)
- && tree_expr_nonzero_p (TREE_OPERAND (t, 0)));
+ && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p));
}
break;
@@ -13042,42 +13474,76 @@ tree_expr_nonzero_p (tree t)
}
case COND_EXPR:
- return (tree_expr_nonzero_p (TREE_OPERAND (t, 1))
- && tree_expr_nonzero_p (TREE_OPERAND (t, 2)));
+ sub_strict_overflow_p = false;
+ if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1),
+ &sub_strict_overflow_p)
+ && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 2),
+ &sub_strict_overflow_p))
+ {
+ if (sub_strict_overflow_p)
+ *strict_overflow_p = true;
+ return true;
+ }
+ break;
case MIN_EXPR:
- return (tree_expr_nonzero_p (TREE_OPERAND (t, 0))
- && tree_expr_nonzero_p (TREE_OPERAND (t, 1)));
+ sub_strict_overflow_p = false;
+ if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0),
+ &sub_strict_overflow_p)
+ && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1),
+ &sub_strict_overflow_p))
+ {
+ if (sub_strict_overflow_p)
+ *strict_overflow_p = true;
+ }
+ break;
case MAX_EXPR:
- if (tree_expr_nonzero_p (TREE_OPERAND (t, 0)))
+ sub_strict_overflow_p = false;
+ if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0),
+ &sub_strict_overflow_p))
{
+ if (sub_strict_overflow_p)
+ *strict_overflow_p = true;
+
/* When both operands are nonzero, then MAX must be too. */
- if (tree_expr_nonzero_p (TREE_OPERAND (t, 1)))
+ if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1),
+ strict_overflow_p))
return true;
/* MAX where operand 0 is positive is positive. */
- return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
+ return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p);
}
/* MAX where operand 1 is positive is positive. */
- else if (tree_expr_nonzero_p (TREE_OPERAND (t, 1))
- && tree_expr_nonnegative_p (TREE_OPERAND (t, 1)))
- return true;
+ else if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1),
+ &sub_strict_overflow_p)
+ && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
+ &sub_strict_overflow_p))
+ {
+ if (sub_strict_overflow_p)
+ *strict_overflow_p = true;
+ return true;
+ }
break;
case COMPOUND_EXPR:
case MODIFY_EXPR:
case GIMPLE_MODIFY_STMT:
case BIND_EXPR:
- return tree_expr_nonzero_p (GENERIC_TREE_OPERAND (t, 1));
+ return tree_expr_nonzero_warnv_p (GENERIC_TREE_OPERAND (t, 1),
+ strict_overflow_p);
case SAVE_EXPR:
case NON_LVALUE_EXPR:
- return tree_expr_nonzero_p (TREE_OPERAND (t, 0));
+ return tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p);
case BIT_IOR_EXPR:
- return tree_expr_nonzero_p (TREE_OPERAND (t, 1))
- || tree_expr_nonzero_p (TREE_OPERAND (t, 0));
+ return (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1),
+ strict_overflow_p)
+ || tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0),
+ strict_overflow_p));
case CALL_EXPR:
return alloca_call_p (t);
@@ -13088,6 +13554,24 @@ tree_expr_nonzero_p (tree t)
return false;
}
+/* Return true when T is an address and is known to be nonzero.
+ Handle warnings about undefined signed overflow. */
+
+bool
+tree_expr_nonzero_p (tree t)
+{
+ bool ret, strict_overflow_p;
+
+ strict_overflow_p = false;
+ ret = tree_expr_nonzero_warnv_p (t, &strict_overflow_p);
+ if (strict_overflow_p)
+ fold_overflow_warning (("assuming signed overflow does not occur when "
+ "determining that expression is always "
+ "non-zero"),
+ WARN_STRICT_OVERFLOW_MISC);
+ return ret;
+}
+
/* Given the components of a binary expression CODE, TYPE, OP0 and OP1,
attempt to fold the expression to a constant without modifying TYPE,
OP0 or OP1.
diff --git a/gcc/opts.c b/gcc/opts.c
index daa9c9e..1361eb7 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -61,6 +61,10 @@ HOST_WIDE_INT larger_than_size;
strict-aliasing safe. */
int warn_strict_aliasing;
+/* Nonzero means warn about optimizations which rely on undefined
+ signed overflow. */
+int warn_strict_overflow;
+
/* Hack for cooperation between set_Wunused and set_Wextra. */
static bool maybe_warn_unused_parameter;
@@ -1104,6 +1108,11 @@ common_handle_option (size_t scode, const char *arg, int value,
warn_strict_aliasing = value;
break;
+ case OPT_Wstrict_overflow:
+ case OPT_Wstrict_overflow_:
+ warn_strict_overflow = value;
+ break;
+
case OPT_Wunused:
set_Wunused (value);
break;
diff --git a/gcc/passes.c b/gcc/passes.c
index 35e4164..6f1a99d 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -952,6 +952,17 @@ execute_todo (unsigned int flags)
}
}
+/* Verify invariants that should hold between passes. This is a place
+ to put simple sanity checks. */
+
+static void
+verify_interpass_invariants (void)
+{
+#ifdef ENABLE_CHECKING
+ gcc_assert (!fold_deferring_overflow_warnings_p ());
+#endif
+}
+
/* Clear the last verified flag. */
static void
@@ -1063,6 +1074,7 @@ execute_one_pass (struct tree_opt_pass *pass)
/* Run post-pass cleanup and verification. */
execute_todo (todo_after | pass->todo_flags_finish);
+ verify_interpass_invariants ();
if (!current_function_decl)
cgraph_process_new_functions ();
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index f8e613d..cb1c4f6 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -4086,7 +4086,15 @@ simplify_const_relational_operation (enum rtx_code code,
tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
: trueop0;
if (GET_CODE (tem) == ABS)
- return const0_rtx;
+ {
+ if (INTEGRAL_MODE_P (mode)
+ && (issue_strict_overflow_warning
+ (WARN_STRICT_OVERFLOW_CONDITIONAL)))
+ warning (OPT_Wstrict_overflow,
+ ("assuming signed overflow does not occur when "
+ "assuming abs (x) < 0 is false"));
+ return const0_rtx;
+ }
}
/* Optimize popcount (x) < 0. */
@@ -4104,7 +4112,15 @@ simplify_const_relational_operation (enum rtx_code code,
tem = GET_CODE (trueop0) == FLOAT_EXTEND ? XEXP (trueop0, 0)
: trueop0;
if (GET_CODE (tem) == ABS)
- return const_true_rtx;
+ {
+ if (INTEGRAL_MODE_P (mode)
+ && (issue_strict_overflow_warning
+ (WARN_STRICT_OVERFLOW_CONDITIONAL)))
+ warning (OPT_Wstrict_overflow,
+ ("assuming signed overflow does not occur when "
+ "assuming abs (x) >= 0 is true"));
+ return const_true_rtx;
+ }
}
/* Optimize popcount (x) >= 0. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 0137d21..f5e9922 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,16 @@
+2007-02-13 Ian Lance Taylor <iant@google.com>
+
+ * gcc.dg/Wstrict-overflow-1.c: New test.
+ * gcc.dg/Wstrict-overflow-2.c: New test.
+ * gcc.dg/Wstrict-overflow-3.c: New test.
+ * gcc.dg/Wstrict-overflow-4.c: New test.
+ * gcc.dg/Wstrict-overflow-5.c: New test.
+ * gcc.dg/Wstrict-overflow-6.c: New test.
+ * gcc.dg/Wstrict-overflow-7.c: New test.
+ * gcc.dg/Wstrict-overflow-8.c: New test.
+ * gcc.dg/Wstrict-overflow-9.c: New test.
+ * gcc.dg/Wstrict-overflow-10.c: New test.
+
2007-02-13 Roger Sayle <roger@eyesopen.com>
* gcc.target/ia64/builtin-bswap-2.c: New test case.
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-1.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-1.c
new file mode 100644
index 0000000..068bfe4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-1.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=3" } */
+
+/* Source: Ian Lance Taylor. Based on strict-overflow-1.c. */
+
+/* We can only simplify the conditional when using strict overflow
+ semantics. */
+
+int
+foo (int i)
+{
+ return i - 5 < 10; /* { dg-warning "assuming signed overflow does not occur" "correct warning" } */
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-10.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-10.c
new file mode 100644
index 0000000..d2c2597
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-10.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=1" } */
+
+/* Source: Ian Lance Taylor. */
+
+int
+foo (int i)
+{
+ return __builtin_abs (i) >= 0;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-2.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-2.c
new file mode 100644
index 0000000..2112571
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-2.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=2" } */
+
+/* Source: Ian Lance Taylor. Based on strict-overflow-1.c. */
+
+/* We can only simplify the conditional when using strict overflow
+ semantics. */
+
+int
+foo (int i)
+{
+ return i - 5 < 10;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-3.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-3.c
new file mode 100644
index 0000000..22f6a56
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-3.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=4" } */
+
+/* Source: Ian Lance Taylor. Based on strict-overflow-2.c. */
+
+/* We can only simplify the division when using strict overflow
+ semantics. */
+
+int
+foo (int i)
+{
+ return (i * 100) / 10; /* { dg-warning "assuming signed overflow does not occur" "correct warning" } */
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-4.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-4.c
new file mode 100644
index 0000000..e880bef
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-4.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=3" } */
+
+/* Source: Ian Lance Taylor. Based on strict-overflow-2.c. */
+
+/* We can only simplify the division when using strict overflow
+ semantics. */
+
+int
+foo (int i)
+{
+ return (i * 100) / 10;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-5.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-5.c
new file mode 100644
index 0000000..9af0adb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-5.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=3" } */
+
+/* Source: Ian Lance Taylor. Based on strict-overflow-3.c. */
+
+/* We can only simplify the conditional when using strict overflow
+ semantics. */
+
+int
+foo (int i, int j)
+{
+ return i + 100 < j + 1000; /* { dg-warning "assuming signed overflow does not occur" "correct warning" } */
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-6.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-6.c
new file mode 100644
index 0000000..c3a160c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-6.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=2" } */
+
+/* Source: Ian Lance Taylor. Based on strict-overflow-3.c. */
+
+/* We can only simplify the conditional when using strict overflow
+ semantics. */
+
+int
+foo (int i, int j)
+{
+ return i + 100 < j + 1000;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-7.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-7.c
new file mode 100644
index 0000000..5bf7b60
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-7.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow" } */
+
+/* Source: Ian Lance Taylor. */
+
+int
+foo (int i)
+{
+ return i + 10 > i; /* { dg-warning "assuming signed overflow does not occur" "correct warning" } */
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-8.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-8.c
new file mode 100644
index 0000000..566729f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-8.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wall -Wno-strict-overflow" } */
+
+/* Source: Ian Lance Taylor. */
+
+int
+foo (int i)
+{
+ return i + 10 > i;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-9.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-9.c
new file mode 100644
index 0000000..425a121
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-9.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fstrict-overflow -O2 -Wstrict-overflow=2" } */
+
+/* Source: Ian Lance Taylor. */
+
+int
+foo (int i)
+{
+ return __builtin_abs (i) >= 0; /* { dg-warning "assuming signed overflow does not occur" "correct warning" } */
+}
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index e3e2134..7d28aa9 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -408,10 +408,18 @@ fold_cond_expr_cond (void)
if (stmt
&& TREE_CODE (stmt) == COND_EXPR)
{
- tree cond = fold (COND_EXPR_COND (stmt));
- if (integer_zerop (cond))
+ tree cond;
+ bool zerop, onep;
+
+ fold_defer_overflow_warnings ();
+ cond = fold (COND_EXPR_COND (stmt));
+ zerop = integer_zerop (cond);
+ onep = integer_onep (cond);
+ fold_undefer_overflow_warnings (zerop || onep, stmt,
+ WARN_STRICT_OVERFLOW_CONDITIONAL);
+ if (zerop)
COND_EXPR_COND (stmt) = boolean_false_node;
- else if (integer_onep (cond))
+ else if (onep)
COND_EXPR_COND (stmt) = boolean_true_node;
}
}
diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c
index f78be8e..8cf66cb 100644
--- a/gcc/tree-cfgcleanup.c
+++ b/gcc/tree-cfgcleanup.c
@@ -1,5 +1,6 @@
/* CFG cleanup for trees.
- Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
This file is part of GCC.
@@ -28,7 +29,7 @@ Boston, MA 02110-1301, USA. */
#include "hard-reg-set.h"
#include "basic-block.h"
#include "output.h"
-#include "errors.h"
+#include "toplev.h"
#include "flags.h"
#include "function.h"
#include "expr.h"
@@ -78,6 +79,9 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
{
edge e;
edge_iterator ei;
+ bool warned;
+
+ fold_defer_overflow_warnings ();
switch (TREE_CODE (expr))
{
@@ -88,7 +92,10 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
case SWITCH_EXPR:
val = fold (SWITCH_COND (expr));
if (TREE_CODE (val) != INTEGER_CST)
- return false;
+ {
+ fold_undefer_and_ignore_overflow_warnings ();
+ return false;
+ }
break;
default:
@@ -97,13 +104,24 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
taken_edge = find_taken_edge (bb, val);
if (!taken_edge)
- return false;
+ {
+ fold_undefer_and_ignore_overflow_warnings ();
+ return false;
+ }
/* Remove all the edges except the one that is always executed. */
+ warned = false;
for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
{
if (e != taken_edge)
{
+ if (!warned)
+ {
+ fold_undefer_overflow_warnings
+ (true, expr, WARN_STRICT_OVERFLOW_CONDITIONAL);
+ warned = true;
+ }
+
taken_edge->probability += e->probability;
taken_edge->count += e->count;
remove_edge (e);
@@ -112,6 +130,8 @@ cleanup_control_expr_graph (basic_block bb, block_stmt_iterator bsi)
else
ei_next (&ei);
}
+ if (!warned)
+ fold_undefer_and_ignore_overflow_warnings ();
if (taken_edge->probability > REG_BR_PROB_BASE)
taken_edge->probability = REG_BR_PROB_BASE;
}
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index b6c3599..459894b 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -1,5 +1,5 @@
/* Conditional constant propagation pass for the GNU compiler.
- Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
Adapted from original RTL SSA-CCP by Daniel Berlin <dberlin@dberlin.org>
Adapted to GIMPLE trees by Diego Novillo <dnovillo@redhat.com>
@@ -207,6 +207,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "tree-ssa-propagate.h"
#include "langhooks.h"
#include "target.h"
+#include "toplev.h"
/* Possible lattice values. */
@@ -1132,9 +1133,12 @@ evaluate_stmt (tree stmt)
prop_value_t val;
tree simplified = NULL_TREE;
ccp_lattice_t likelyvalue = likely_value (stmt);
+ bool is_constant;
val.mem_ref = NULL_TREE;
+ fold_defer_overflow_warnings ();
+
/* If the statement is likely to have a CONSTANT result, then try
to fold the statement to determine the constant value. */
if (likelyvalue == CONSTANT)
@@ -1151,7 +1155,11 @@ evaluate_stmt (tree stmt)
else if (!simplified)
simplified = fold_const_aggregate_ref (get_rhs (stmt));
- if (simplified && is_gimple_min_invariant (simplified))
+ is_constant = simplified && is_gimple_min_invariant (simplified);
+
+ fold_undefer_overflow_warnings (is_constant, stmt, 0);
+
+ if (is_constant)
{
/* The statement produced a constant value. */
val.lattice_val = CONSTANT;
@@ -1966,8 +1974,9 @@ maybe_fold_stmt_addition (tree expr)
struct fold_stmt_r_data
{
- bool *changed_p;
- bool *inside_addr_expr_p;
+ tree stmt;
+ bool *changed_p;
+ bool *inside_addr_expr_p;
};
/* Subroutine of fold_stmt called via walk_tree. We perform several
@@ -2063,10 +2072,16 @@ fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data)
if (COMPARISON_CLASS_P (TREE_OPERAND (expr, 0)))
{
tree op0 = TREE_OPERAND (expr, 0);
- tree tem = fold_binary (TREE_CODE (op0), TREE_TYPE (op0),
- TREE_OPERAND (op0, 0),
- TREE_OPERAND (op0, 1));
- if (tem && set_rhs (expr_p, tem))
+ tree tem;
+ bool set;
+
+ fold_defer_overflow_warnings ();
+ tem = fold_binary (TREE_CODE (op0), TREE_TYPE (op0),
+ TREE_OPERAND (op0, 0),
+ TREE_OPERAND (op0, 1));
+ set = tem && set_rhs (expr_p, tem);
+ fold_undefer_overflow_warnings (set, fold_stmt_r_data->stmt, 0);
+ if (set)
{
t = *expr_p;
break;
@@ -2373,11 +2388,12 @@ fold_stmt (tree *stmt_p)
bool changed = false;
bool inside_addr_expr = false;
+ stmt = *stmt_p;
+
+ fold_stmt_r_data.stmt = stmt;
fold_stmt_r_data.changed_p = &changed;
fold_stmt_r_data.inside_addr_expr_p = &inside_addr_expr;
- stmt = *stmt_p;
-
/* If we replaced constants and the statement makes pointer dereferences,
then we may need to fold instances of *&VAR into VAR, etc. */
if (walk_tree (stmt_p, fold_stmt_r, &fold_stmt_r_data, NULL))
@@ -2472,6 +2488,7 @@ fold_stmt_inplace (tree stmt)
bool changed = false;
bool inside_addr_expr = false;
+ fold_stmt_r_data.stmt = stmt;
fold_stmt_r_data.changed_p = &changed;
fold_stmt_r_data.inside_addr_expr_p = &inside_addr_expr;
diff --git a/gcc/tree-ssa-loop-manip.c b/gcc/tree-ssa-loop-manip.c
index 6b220e9..715c412 100644
--- a/gcc/tree-ssa-loop-manip.c
+++ b/gcc/tree-ssa-loop-manip.c
@@ -1,5 +1,5 @@
/* High-level loop manipulation functions.
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of GCC.
@@ -86,7 +86,9 @@ create_iv (tree base, tree step, tree var, struct loop *loop,
}
else
{
- if (!tree_expr_nonnegative_p (step)
+ bool ovf;
+
+ if (!tree_expr_nonnegative_warnv_p (step, &ovf)
&& may_negate_without_overflow_p (step))
{
incr_op = MINUS_EXPR;
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index c2a9f9c..95a9e46 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -705,7 +705,13 @@ expand_simple_operations (tree expr)
TREE_OPERAND (ret, i) = ee;
}
- return (ret ? fold (ret) : expr);
+ if (!ret)
+ return expr;
+
+ fold_defer_overflow_warnings ();
+ ret = fold (ret);
+ fold_undefer_and_ignore_overflow_warnings ();
+ return ret;
}
if (TREE_CODE (expr) != SSA_NAME)
@@ -1053,11 +1059,18 @@ number_of_iterations_exit (struct loop *loop, edge exit,
if (!simple_iv (loop, stmt, op1, &iv1, false))
return false;
+ /* We don't want to see undefined signed overflow warnings while
+ computing the nmber of iterations. */
+ fold_defer_overflow_warnings ();
+
iv0.base = expand_simple_operations (iv0.base);
iv1.base = expand_simple_operations (iv1.base);
if (!number_of_iterations_cond (type, &iv0, code, &iv1, niter,
loop_only_exit_p (loop, exit)))
- return false;
+ {
+ fold_undefer_and_ignore_overflow_warnings ();
+ return false;
+ }
if (optimize >= 3)
{
@@ -1078,6 +1091,8 @@ number_of_iterations_exit (struct loop *loop, edge exit,
niter->may_be_zero,
&niter->additional_info);
+ fold_undefer_and_ignore_overflow_warnings ();
+
if (integer_onep (niter->assumptions))
return true;
@@ -1376,6 +1391,9 @@ loop_niter_by_eval (struct loop *loop, edge exit)
}
}
+ /* Don't issue signed overflow warnings. */
+ fold_defer_overflow_warnings ();
+
for (i = 0; i < MAX_ITERATIONS_TO_TRACK; i++)
{
for (j = 0; j < 2; j++)
@@ -1384,6 +1402,7 @@ loop_niter_by_eval (struct loop *loop, edge exit)
acnd = fold_binary (cmp, boolean_type_node, aval[0], aval[1]);
if (acnd && integer_zerop (acnd))
{
+ fold_undefer_and_ignore_overflow_warnings ();
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file,
"Proved that loop %d iterates %d times using brute force.\n",
@@ -1395,10 +1414,15 @@ loop_niter_by_eval (struct loop *loop, edge exit)
{
val[j] = get_val_for (next[j], val[j]);
if (!is_gimple_min_invariant (val[j]))
- return chrec_dont_know;
+ {
+ fold_undefer_and_ignore_overflow_warnings ();
+ return chrec_dont_know;
+ }
}
}
+ fold_undefer_and_ignore_overflow_warnings ();
+
return chrec_dont_know;
}
@@ -1994,10 +2018,16 @@ estimate_numbers_of_iterations (void)
loop_iterator li;
struct loop *loop;
+ /* We don't want to issue signed overflow warnings while getting
+ loop iteration estimates. */
+ fold_defer_overflow_warnings ();
+
FOR_EACH_LOOP (li, loop, 0)
{
estimate_numbers_of_iterations_loop (loop);
}
+
+ fold_undefer_and_ignore_overflow_warnings ();
}
/* Returns true if statement S1 dominates statement S2. */
@@ -2153,6 +2183,9 @@ scev_probably_wraps_p (tree base, tree step,
if (use_overflow_semantics && nowrap_type_p (type))
return false;
+ /* Don't issue signed overflow warnings. */
+ fold_defer_overflow_warnings ();
+
/* Otherwise, compute the number of iterations before we reach the
bound of the type, and verify that the loop is exited before this
occurs. */
@@ -2179,8 +2212,15 @@ scev_probably_wraps_p (tree base, tree step,
estimate_numbers_of_iterations_loop (loop);
for (bound = loop->bounds; bound; bound = bound->next)
- if (n_of_executions_at_most (at_stmt, bound, valid_niter))
- return false;
+ {
+ if (n_of_executions_at_most (at_stmt, bound, valid_niter))
+ {
+ fold_undefer_and_ignore_overflow_warnings ();
+ return false;
+ }
+ }
+
+ fold_undefer_and_ignore_overflow_warnings ();
/* At this point we still don't have a proof that the iv does not
overflow: give up. */
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c
index e48cd65..72018c0 100644
--- a/gcc/tree-ssa-threadedge.c
+++ b/gcc/tree-ssa-threadedge.c
@@ -1,5 +1,5 @@
/* SSA Jump Threading
- Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
Contributed by Jeff Law <law@redhat.com>
This file is part of GCC.
@@ -425,12 +425,17 @@ simplify_control_stmt_condition (edge e,
/* We absolutely do not care about any type conversions
we only care about a zero/nonzero value. */
+ fold_defer_overflow_warnings ();
+
cached_lhs = fold (COND_EXPR_COND (dummy_cond));
while (TREE_CODE (cached_lhs) == NOP_EXPR
|| TREE_CODE (cached_lhs) == CONVERT_EXPR
|| TREE_CODE (cached_lhs) == NON_LVALUE_EXPR)
cached_lhs = TREE_OPERAND (cached_lhs, 0);
-
+
+ fold_undefer_overflow_warnings (is_gimple_min_invariant (cached_lhs),
+ stmt, WARN_STRICT_OVERFLOW_CONDITIONAL);
+
/* If we have not simplified the condition down to an invariant,
then use the pass specific callback to simplify the condition. */
if (! is_gimple_min_invariant (cached_lhs))
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 2babe1a..fffeefc 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -414,7 +414,10 @@ symbolic_range_p (value_range_t *vr)
static bool
vrp_expr_computes_nonnegative (tree expr)
{
- return tree_expr_nonnegative_p (expr);
+ bool ovf;
+
+ /* FIXME: May need to record overflow information here. */
+ return tree_expr_nonnegative_warnv_p (expr, &ovf);
}
/* Like tree_expr_nonzero_p, but this function uses value ranges
@@ -423,7 +426,10 @@ vrp_expr_computes_nonnegative (tree expr)
static bool
vrp_expr_computes_nonzero (tree expr)
{
- if (tree_expr_nonzero_p (expr))
+ bool ovf;
+
+ /* FIXME: May need to record overflow information here. */
+ if (tree_expr_nonzero_warnv_p (expr, &ovf))
return true;
/* If we have an expression of the form &X->a, then the expression
@@ -1697,7 +1703,10 @@ extract_range_from_unary_expr (value_range_t *vr, tree expr)
determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]). */
if (POINTER_TYPE_P (TREE_TYPE (expr)) || POINTER_TYPE_P (TREE_TYPE (op0)))
{
- if (range_is_nonnull (&vr0) || tree_expr_nonzero_p (expr))
+ bool ovf;
+
+ /* FIXME: May need to record overflow information here. */
+ if (range_is_nonnull (&vr0) || tree_expr_nonzero_warnv_p (expr, &ovf))
set_value_range_to_nonnull (vr, TREE_TYPE (expr));
else if (range_is_null (&vr0))
set_value_range_to_null (vr, TREE_TYPE (expr));
diff --git a/gcc/tree.h b/gcc/tree.h
index 50b0149..ed0379c 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -3735,6 +3735,7 @@ extern int tree_int_cst_msb (tree);
extern int tree_int_cst_sgn (tree);
extern int tree_int_cst_sign_bit (tree);
extern bool tree_expr_nonnegative_p (tree);
+extern bool tree_expr_nonnegative_warnv_p (tree, bool *);
extern bool may_negate_without_overflow_p (tree);
extern tree get_inner_array_type (tree);
@@ -4333,6 +4334,10 @@ extern tree fold_single_bit_test (enum tree_code, tree, tree, tree);
extern tree fold_ignored_result (tree);
extern tree fold_abs_const (tree, tree);
extern tree fold_indirect_ref_1 (tree, tree);
+extern void fold_defer_overflow_warnings (void);
+extern void fold_undefer_overflow_warnings (bool, tree, int);
+extern void fold_undefer_and_ignore_overflow_warnings (void);
+extern bool fold_deferring_overflow_warnings_p (void);
extern tree force_fit_type_double (tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT,
int, bool);
@@ -4405,6 +4410,7 @@ extern bool ptr_difference_const (tree, tree, HOST_WIDE_INT *);
extern enum tree_code invert_tree_comparison (enum tree_code, bool);
extern bool tree_expr_nonzero_p (tree);
+extern bool tree_expr_nonzero_warnv_p (tree, bool *);
/* In builtins.c */
extern tree fold_builtin (tree, tree, bool);