diff options
author | Richard Biener <rguenther@suse.de> | 2024-02-26 13:33:21 +0100 |
---|---|---|
committer | Richard Biener <rguenther@suse.de> | 2024-02-27 10:54:56 +0100 |
commit | a0b1798042d033fd2cc2c806afbb77875dd2909b (patch) | |
tree | d0ab495e1bc7966c45c330384ea800d5c8c3983a /gcc | |
parent | c3c44c01d20b00ab5228f32596153b7f4cbc6036 (diff) | |
download | gcc-a0b1798042d033fd2cc2c806afbb77875dd2909b.zip gcc-a0b1798042d033fd2cc2c806afbb77875dd2909b.tar.gz gcc-a0b1798042d033fd2cc2c806afbb77875dd2909b.tar.bz2 |
tree-optimization/114074 - CHREC multiplication and undefined overflow
When folding a multiply CHRECs are handled like {a, +, b} * c
is {a*c, +, b*c} but that isn't generally correct when overflow
invokes undefined behavior. The following uses unsigned arithmetic
unless either a is zero or a and b have the same sign.
I've used simple early outs for INTEGER_CSTs and otherwise use
a range-query since we lack a tree_expr_nonpositive_p and
get_range_pos_neg isn't a good fit.
PR tree-optimization/114074
* tree-chrec.h (chrec_convert_rhs): Default at_stmt arg to NULL.
* tree-chrec.cc (chrec_fold_multiply): Canonicalize inputs.
Handle poly vs. non-poly multiplication correctly with respect
to undefined behavior on overflow.
* gcc.dg/torture/pr114074.c: New testcase.
* gcc.dg/pr68317.c: Adjust expected location of diagnostic.
* gcc.dg/vect/vect-early-break_119-pr114068.c: Do not expect
loop to be vectorized.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/testsuite/gcc.dg/pr68317.c | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/pr114074.c | 27 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/vect/vect-early-break_119-pr114068.c | 2 | ||||
-rw-r--r-- | gcc/tree-chrec.cc | 55 | ||||
-rw-r--r-- | gcc/tree-chrec.h | 2 |
5 files changed, 74 insertions, 16 deletions
diff --git a/gcc/testsuite/gcc.dg/pr68317.c b/gcc/testsuite/gcc.dg/pr68317.c index bd053a7..06cd2e1 100644 --- a/gcc/testsuite/gcc.dg/pr68317.c +++ b/gcc/testsuite/gcc.dg/pr68317.c @@ -12,8 +12,8 @@ foo () { int32_t index = 0; - for (index; index <= 10; index--) // expected warning here + for (index; index <= 10; index--) /* { dg-warning "iteration \[0-9\]+ invokes undefined behavior" } */ /* Result of the following multiply will overflow when converted to signed int32_t. */ - bar ((0xcafe + index) * 0xdead); /* { dg-warning "iteration \[0-9\]+ invokes undefined behavior" } */ + bar ((0xcafe + index) * 0xdead); } diff --git a/gcc/testsuite/gcc.dg/torture/pr114074.c b/gcc/testsuite/gcc.dg/torture/pr114074.c new file mode 100644 index 0000000..336e976 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr114074.c @@ -0,0 +1,27 @@ +/* { dg-do run } */ + +int a, b, d; + +__attribute__((noipa)) void +foo (void) +{ + ++d; +} + +int +main () +{ + for (a = 0; a > -3; a -= 2) + { + int c = a; + b = __INT_MAX__ - 3000; + a = ~c * b; + foo (); + if (!a) + break; + a = c; + } + if (d != 2) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_119-pr114068.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_119-pr114068.c index a65ef7b..2063979 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-early-break_119-pr114068.c +++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_119-pr114068.c @@ -4,8 +4,6 @@ /* { dg-require-effective-target vect_int } */ /* { dg-additional-options "-O3" } */ -/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" } } */ - struct h { int b; int c; diff --git a/gcc/tree-chrec.cc b/gcc/tree-chrec.cc index 61456fe..2e6c735 100644 --- a/gcc/tree-chrec.cc +++ b/gcc/tree-chrec.cc @@ -38,6 +38,8 @@ 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. */ @@ -404,6 +406,10 @@ chrec_fold_multiply (tree type, || automatically_generated_chrec_p (op1)) return chrec_fold_automatically_generated_operands (op0, op1); + if (TREE_CODE (op0) != POLYNOMIAL_CHREC + && TREE_CODE (op1) == POLYNOMIAL_CHREC) + std::swap (op0, op1); + switch (TREE_CODE (op0)) { case POLYNOMIAL_CHREC: @@ -428,10 +434,43 @@ chrec_fold_multiply (tree type, if (integer_zerop (op1)) return build_int_cst (type, 0); - return build_polynomial_chrec - (CHREC_VARIABLE (op0), - chrec_fold_multiply (type, CHREC_LEFT (op0), op1), - chrec_fold_multiply (type, CHREC_RIGHT (op0), op1)); + /* 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 + { + 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); + } } CASE_CONVERT: @@ -449,13 +488,7 @@ chrec_fold_multiply (tree type, switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: - gcc_checking_assert - (!chrec_contains_symbols_defined_in_loop (op1, - CHREC_VARIABLE (op1))); - return build_polynomial_chrec - (CHREC_VARIABLE (op1), - chrec_fold_multiply (type, CHREC_LEFT (op1), op0), - chrec_fold_multiply (type, CHREC_RIGHT (op1), op0)); + gcc_unreachable (); CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) diff --git a/gcc/tree-chrec.h b/gcc/tree-chrec.h index e3a5ba5..8003eb5 100644 --- a/gcc/tree-chrec.h +++ b/gcc/tree-chrec.h @@ -63,7 +63,7 @@ extern tree chrec_fold_plus (tree, tree, tree); extern tree chrec_fold_minus (tree, tree, tree); extern tree chrec_fold_multiply (tree, tree, tree); extern tree chrec_convert (tree, tree, gimple *, bool = true, tree = NULL); -extern tree chrec_convert_rhs (tree, tree, gimple *); +extern tree chrec_convert_rhs (tree, tree, gimple * = NULL); extern tree chrec_convert_aggressive (tree, tree, bool *); /* Operations. */ |