From add6ee5ee2f592a9021df6536766552e97b987fe Mon Sep 17 00:00:00 2001 From: ian Date: Tue, 13 Feb 2007 22:34:45 +0000 Subject: [PATCH] ./: * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@121895 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 82 ++++ gcc/Makefile.in | 6 +- gcc/c-common.c | 14 +- gcc/c-opts.c | 4 +- gcc/c-typeck.c | 11 +- gcc/common.opt | 8 + gcc/doc/invoke.texi | 51 ++ gcc/flags.h | 47 +- gcc/fold-const.c | 758 +++++++++++++++++++++++------ gcc/opts.c | 9 + gcc/passes.c | 12 + gcc/simplify-rtx.c | 20 +- gcc/testsuite/ChangeLog | 13 + gcc/testsuite/gcc.dg/Wstrict-overflow-1.c | 13 + gcc/testsuite/gcc.dg/Wstrict-overflow-10.c | 10 + gcc/testsuite/gcc.dg/Wstrict-overflow-2.c | 13 + gcc/testsuite/gcc.dg/Wstrict-overflow-3.c | 13 + gcc/testsuite/gcc.dg/Wstrict-overflow-4.c | 13 + gcc/testsuite/gcc.dg/Wstrict-overflow-5.c | 13 + gcc/testsuite/gcc.dg/Wstrict-overflow-6.c | 13 + gcc/testsuite/gcc.dg/Wstrict-overflow-7.c | 10 + gcc/testsuite/gcc.dg/Wstrict-overflow-8.c | 10 + gcc/testsuite/gcc.dg/Wstrict-overflow-9.c | 10 + gcc/tree-cfg.c | 14 +- gcc/tree-cfgcleanup.c | 28 +- gcc/tree-ssa-ccp.c | 37 +- gcc/tree-ssa-loop-manip.c | 6 +- gcc/tree-ssa-loop-niter.c | 50 +- gcc/tree-ssa-threadedge.c | 9 +- gcc/tree-vrp.c | 15 +- gcc/tree.h | 6 + 31 files changed, 1139 insertions(+), 179 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Wstrict-overflow-1.c create mode 100644 gcc/testsuite/gcc.dg/Wstrict-overflow-10.c create mode 100644 gcc/testsuite/gcc.dg/Wstrict-overflow-2.c create mode 100644 gcc/testsuite/gcc.dg/Wstrict-overflow-3.c create mode 100644 gcc/testsuite/gcc.dg/Wstrict-overflow-4.c create mode 100644 gcc/testsuite/gcc.dg/Wstrict-overflow-5.c create mode 100644 gcc/testsuite/gcc.dg/Wstrict-overflow-6.c create mode 100644 gcc/testsuite/gcc.dg/Wstrict-overflow-7.c create mode 100644 gcc/testsuite/gcc.dg/Wstrict-overflow-8.c create mode 100644 gcc/testsuite/gcc.dg/Wstrict-overflow-9.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d504109f8c6..4c6f08466c6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,87 @@ 2007-02-13 Ian Lance Taylor + * 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 + 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 7bb1434b0e9..6ea4280d8b9 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 cfd382991d3..0bbb439324b 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 2b0bc5f7d55..9ac433a4f3a 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 c807a7edfe9..28ce2baf163 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 dd3deb386a3..c6a95574be9 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 8274d74ef0a..8e811936fef 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 2671ec38a09..1996bd1514b 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 d20d78f5956..7d66736b13b 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 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 >= 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 < 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 daa9c9eb65c..1361eb77922 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 35e4164f4d3..6f1a99d0601 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 f8e613d98be..cb1c4f62a36 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 0137d210af7..f5e99223b4d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2007-02-13 Ian Lance Taylor + + * 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 * 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 00000000000..068bfe49446 --- /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 00000000000..d2c259728cb --- /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 00000000000..2112571cabe --- /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 00000000000..22f6a56a99e --- /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 00000000000..e880bef45ff --- /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 00000000000..9af0adb9934 --- /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 00000000000..c3a160c6002 --- /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 00000000000..5bf7b6005ca --- /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 00000000000..566729fe308 --- /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 00000000000..425a121d5c0 --- /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 e3e21342b00..7d28aa941a7 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 f78be8ecf68..8cf66cb4a27 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 b6c3599f9d9..459894b24f0 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 Adapted to GIMPLE trees by Diego Novillo @@ -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 6b220e9d3e6..715c412c790 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 c2a9f9c2039..95a9e46c4a8 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 e48cd650d17..72018c02ede 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 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 2babe1a25b7..fffeefc83bd 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 50b014962ad..ed0379c7a87 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); -- 2.11.4.GIT