diff options
author | CoprDistGit <infra@openeuler.org> | 2025-02-28 10:03:49 +0000 |
---|---|---|
committer | CoprDistGit <infra@openeuler.org> | 2025-02-28 10:03:49 +0000 |
commit | 73127104a245052cd5cf29cdaaca3e5c32c70348 (patch) | |
tree | 8e28b63e478c43c252f18b49836dff7313affe54 /0098-CHREC-multiplication-and-undefined-overflow.patch | |
parent | 49d3feaf4665cdb07576fc1a2382a4d82a612d35 (diff) |
automatic import of gccopeneuler24.03_LTS_SP1
Diffstat (limited to '0098-CHREC-multiplication-and-undefined-overflow.patch')
-rw-r--r-- | 0098-CHREC-multiplication-and-undefined-overflow.patch | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/0098-CHREC-multiplication-and-undefined-overflow.patch b/0098-CHREC-multiplication-and-undefined-overflow.patch new file mode 100644 index 0000000..9f9a6b7 --- /dev/null +++ b/0098-CHREC-multiplication-and-undefined-overflow.patch @@ -0,0 +1,265 @@ +From c4e4fef145c1e402f0558cc35f6c1ed0a08beffb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=E9=83=91=E6=99=A8=E5=8D=89?= <zhengchenhui1@huawei.com> +Date: Thu, 25 Jul 2024 20:16:52 +0800 +Subject: [PATCH] CHREC multiplication and undefined overflow + +This optimization is brought from https://gcc.gnu.org/pipermail/gcc-patches/2024-February/646531.html + +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. +--- + gcc/common.opt | 4 ++ + gcc/testsuite/gcc.dg/pr68317.c | 6 +- + gcc/testsuite/gcc.dg/torture/pr114074.c | 31 ++++++++++ + gcc/tree-chrec.cc | 81 +++++++++++++++++++++---- + gcc/tree-chrec.h | 2 +- + gcc/value-range.cc | 12 ++++ + gcc/value-range.h | 2 + + 7 files changed, 123 insertions(+), 15 deletions(-) + create mode 100644 gcc/testsuite/gcc.dg/torture/pr114074.c + +diff --git a/gcc/common.opt b/gcc/common.opt +index b18f0b944..d3af3ba39 100644 +--- a/gcc/common.opt ++++ b/gcc/common.opt +@@ -1771,6 +1771,10 @@ floop-interchange + Common Var(flag_loop_interchange) Optimization + Enable loop interchange on trees. + ++fchrec-mul-fold-strict-overflow ++Common Var(flag_chrec_mul_fold_strict_overflow) Init(0) ++Enable strict overflow handling during constant folding of multiply CHRECs. ++ + floop-block + Common Alias(floop-nest-optimize) + Enable loop nest transforms. Same as -floop-nest-optimize. +diff --git a/gcc/testsuite/gcc.dg/pr68317.c b/gcc/testsuite/gcc.dg/pr68317.c +index bd053a752..671a67d95 100644 +--- a/gcc/testsuite/gcc.dg/pr68317.c ++++ b/gcc/testsuite/gcc.dg/pr68317.c +@@ -1,5 +1,5 @@ + /* { dg-do compile } */ +-/* { dg-options "-O2 -fdisable-tree-ethread" } */ ++/* { dg-options "-O2 -fdisable-tree-ethread -fchrec-mul-fold-strict-overflow" } */ + + /* Note: Threader will collapse loop. */ + +@@ -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 000000000..9a383d8fc +--- /dev/null ++++ b/gcc/testsuite/gcc.dg/torture/pr114074.c +@@ -0,0 +1,31 @@ ++/* { dg-do run } */ ++<<<<<<< HEAD ++/* { dg-options "-fchrec-mul-fold-strict-overflow" } */ ++======= ++/* { dg-options "-fchrec-mul-fold-strict-overflow"" } */ ++>>>>>>> 47092575e7696f5a21cf75284fe3d4feb0c813ab ++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/tree-chrec.cc b/gcc/tree-chrec.cc +index c44cea754..3323901bc 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,13 @@ chrec_fold_multiply (tree type, + || automatically_generated_chrec_p (op1)) + return chrec_fold_automatically_generated_operands (op0, op1); + ++ if (flag_chrec_mul_fold_strict_overflow) ++ { ++ if (TREE_CODE (op0) != POLYNOMIAL_CHREC ++ && TREE_CODE (op1) == POLYNOMIAL_CHREC) ++ std::swap (op0, op1); ++ } ++ + switch (TREE_CODE (op0)) + { + case POLYNOMIAL_CHREC: +@@ -428,10 +437,53 @@ 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)); ++ if (flag_chrec_mul_fold_strict_overflow) ++ { ++ /* 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); ++ } ++ } ++ else ++ { ++ return build_polynomial_chrec ++ (CHREC_VARIABLE (op0), ++ chrec_fold_multiply (type, CHREC_LEFT (op0), op1), ++ chrec_fold_multiply (type, CHREC_RIGHT (op0), op1)); ++ } + } + + CASE_CONVERT: +@@ -449,13 +501,20 @@ 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)); ++ if (flag_chrec_mul_fold_strict_overflow) ++ { ++ gcc_unreachable (); ++ } ++ else ++ { ++ 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)); ++ } + + CASE_CONVERT: + if (tree_contains_chrecs (op1, NULL)) +diff --git a/gcc/tree-chrec.h b/gcc/tree-chrec.h +index fcf41710d..cdc97d5d9 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. */ +diff --git a/gcc/value-range.cc b/gcc/value-range.cc +index 000bbcf89..a1dc10a24 100644 +--- a/gcc/value-range.cc ++++ b/gcc/value-range.cc +@@ -656,6 +656,18 @@ irange::contains_p (tree cst) const + + return false; + } ++bool ++irange::nonnegative_p () const ++{ ++ return wi::ge_p (lower_bound (), 0, TYPE_SIGN (type ())); ++} ++ ++bool ++irange::nonpositive_p () const ++{ ++ return wi::le_p (upper_bound (), 0, TYPE_SIGN (type ())); ++} ++ + + + /* Normalize addresses into constants. */ +diff --git a/gcc/value-range.h b/gcc/value-range.h +index d4cba22d5..2dc0907de 100644 +--- a/gcc/value-range.h ++++ b/gcc/value-range.h +@@ -69,6 +69,8 @@ public: + bool varying_p () const; + bool singleton_p (tree *result = NULL) const; + bool contains_p (tree) const; ++ bool nonnegative_p () const; ++ bool nonpositive_p () const; + + // In-place operators. + void union_ (const irange &); +-- +2.33.0 + |