@@ -12,8 +12,8 @@ foo ()
{
int32_t index = 0;
- for (index; index <= 10; index--) /* { dg-warning "iteration \[0-9\]+ invokes undefined behavior" } */
+ for (index; index <= 10; index--) // expected warning here
/* Result of the following multiply will overflow
when converted to signed int32_t. */
- bar ((0xcafe + index) * 0xdead);
+ bar ((0xcafe + index) * 0xdead); /* { dg-warning "iteration \[0-9\]+ invokes undefined behavior" } */
}
@@ -38,8 +38,6 @@ along with GCC; see the file COPYING3. If not see
#include "gimple.h"
#include "tree-ssa-loop.h"
#include "dumpfile.h"
-#include "value-range.h"
-#include "value-query.h"
#include "tree-scalar-evolution.h"
/* Extended folder for chrecs. */
@@ -475,41 +473,36 @@ chrec_fold_multiply (tree type,
/* When overflow is undefined and CHREC_LEFT/RIGHT do not have the
same sign or CHREC_LEFT is zero then folding the multiply into
- the addition does not have the same behavior on overflow. Use
- unsigned arithmetic in that case. */
- value_range rl, rr;
- if (!ANY_INTEGRAL_TYPE_P (type)
- || TYPE_OVERFLOW_WRAPS (type)
- || integer_zerop (CHREC_LEFT (op0))
- || (TREE_CODE (CHREC_LEFT (op0)) == INTEGER_CST
- && TREE_CODE (CHREC_RIGHT (op0)) == INTEGER_CST
- && (tree_int_cst_sgn (CHREC_LEFT (op0))
- == tree_int_cst_sgn (CHREC_RIGHT (op0))))
- || (get_range_query (cfun)->range_of_expr (rl, CHREC_LEFT (op0))
- && !rl.undefined_p ()
- && (rl.nonpositive_p () || rl.nonnegative_p ())
- && get_range_query (cfun)->range_of_expr (rr,
- CHREC_RIGHT (op0))
- && !rr.undefined_p ()
- && ((rl.nonpositive_p () && rr.nonpositive_p ())
- || (rl.nonnegative_p () && rr.nonnegative_p ()))))
- {
- tree left = chrec_fold_multiply (type, CHREC_LEFT (op0), op1);
- tree right = chrec_fold_multiply (type, CHREC_RIGHT (op0), op1);
- return build_polynomial_chrec (CHREC_VARIABLE (op0), left, right);
- }
- else
+ the addition does not have the same behavior on overflow.
+ Using unsigned arithmetic in that case causes too many performance
+ regressions, but catch the constant case where the multiplication
+ of the step overflows. */
+ if (INTEGRAL_TYPE_P (type)
+ && TYPE_OVERFLOW_UNDEFINED (type)
+ && !integer_zerop (CHREC_LEFT (op0))
+ && TREE_CODE (op1) == INTEGER_CST
+ && TREE_CODE (CHREC_RIGHT (op0)) == INTEGER_CST)
{
- tree utype = unsigned_type_for (type);
- tree uop1 = chrec_convert_rhs (utype, op1);
- tree uleft0 = chrec_convert_rhs (utype, CHREC_LEFT (op0));
- tree uright0 = chrec_convert_rhs (utype, CHREC_RIGHT (op0));
- tree left = chrec_fold_multiply (utype, uleft0, uop1);
- tree right = chrec_fold_multiply (utype, uright0, uop1);
- tree tem = build_polynomial_chrec (CHREC_VARIABLE (op0),
- left, right);
- return chrec_convert_rhs (type, tem);
+ wi::overflow_type ovf = wi::OVF_NONE;
+ wide_int res
+ = wi::mul (wi::to_wide (CHREC_RIGHT (op0)),
+ wi::to_wide (op1), TYPE_SIGN (type), &ovf);
+ if (ovf != wi::OVF_NONE)
+ {
+ tree utype = unsigned_type_for (type);
+ tree uop1 = chrec_convert_rhs (utype, op1);
+ tree uleft0 = chrec_convert_rhs (utype, CHREC_LEFT (op0));
+ tree uright0 = chrec_convert_rhs (utype, CHREC_RIGHT (op0));
+ tree left = chrec_fold_multiply (utype, uleft0, uop1);
+ tree right = chrec_fold_multiply (utype, uright0, uop1);
+ tree tem = build_polynomial_chrec (CHREC_VARIABLE (op0),
+ left, right);
+ return chrec_convert_rhs (type, tem);
+ }
}
+ tree left = chrec_fold_multiply (type, CHREC_LEFT (op0), op1);
+ tree right = chrec_fold_multiply (type, CHREC_RIGHT (op0), op1);
+ return build_polynomial_chrec (CHREC_VARIABLE (op0), left, right);
}
CASE_CONVERT: