Projects
openEuler:24.03:SP1:Everything
gcc
_service:tar_scm:0098-CHREC-multiplication-and-...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:0098-CHREC-multiplication-and-undefined-overflow.patch of Package gcc
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
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2