https://gcc.gnu.org/g:2fcbe075ec3b32f4a523ebae68a8a32381bb46a9
commit r17-2412-g2fcbe075ec3b32f4a523ebae68a8a32381bb46a9 Author: Richard Biener <[email protected]> Date: Wed Jul 15 10:04:18 2026 +0200 tree-optimization/126171 - SCEV and minus of INT_MIN The following fixes the existing mitigation against UB for handling of subtraction of the most negative value in a type. We've only guarded the negation itself which is effective for avoiding UB in that but it does not help in fixing a wrong scev_direction that results from flipping the operation from minus to plus. So the patch, instead of only promoting the negation to unsigned, promotes the whole operation. PR tree-optimization/126171 * tree-scalar-evolution.cc (scev_dfs::add_to_evolution): Remove code argument. Remove MINUS_EXPR handling here. (scev_dfs::follow_ssa_edge_binary): Likewise. (scev_dfs::follow_ssa_edge_expr): Handle MINUS_EXPR separately here, promoting the whole operation to unsigned instead of just the addend. * gcc.dg/pr126171-1.c: New testcase. * gcc.dg/torture/pr126171-2.c: Likewise. Diff: --- gcc/testsuite/gcc.dg/pr126171-1.c | 107 ++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/torture/pr126171-2.c | 52 +++++++++++++++ gcc/tree-scalar-evolution.cc | 92 +++++++++++++------------ 3 files changed, 209 insertions(+), 42 deletions(-) diff --git a/gcc/testsuite/gcc.dg/pr126171-1.c b/gcc/testsuite/gcc.dg/pr126171-1.c new file mode 100644 index 000000000000..4ac67c87c7d5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr126171-1.c @@ -0,0 +1,107 @@ +/* { dg-do run } */ +/* { dg-require-effective-target int32plus } */ +/* { dg-options "-O2 -fgimple" } */ + +static int o; + +__attribute__((noipa)) +int +n () +{ + return 129105662; +} + + +int __GIMPLE (ssa,startwith("vrp1"),guessed_local(1073741824)) +main () +{ + int am; + int ak; + int ay; + int D_3044; + int tem[1]; + int _10; + int _11; + int _12; + int _21; + int _23; + int _24; + int _25; + int _26; + int _27; + int _29; + + __BB(2,guessed_local(1073741824)): + tem[0ul] = _Literal (int) -1; + o = 2147483645; + goto __BB6(precise(134217728)); + + __BB(10,guessed_local(17434151171)): + goto __BB3(precise(134217728)); + + __BB(3,loop_header(2),guessed_local(19522579055)): + ak_20 = __PHI (__BB10: ak_22, __BB6: ak_30); + am_7 = __PHI (__BB10: am_9, __BB6: am_31); + ay_16 = __PHI (__BB10: ay_17, __BB6: ay_32); +be: + am_9 = am_7 + 1; + _10 = n (); + _11 = _10 + _Literal (int) -129105632; + _12 = am_9 << _11; + if (_12 == 0) + goto __BB4(guessed(126835753)); + else + goto __BB5(guessed(7381975)); + + __BB(4,guessed_local(18448837212)): + ay_17 = ay_16 - _Literal (int) -2147483648; + _21 = ak_20 + _Literal (int) -1; + ak_22 = _21 + 2147483647; + if (ak_22 != 0) + goto __BB10(guessed(126835753)); + else + goto __BB9(guessed(7381975)); + + __BB(5,guessed_local(1073741842)): + _23 = o; + _24 = _Literal (int) -2 - _23; + o = _24; + _25 = ak_20 + _Literal (int) -1; + __MEM <int> ((int *)&tem) = _25; + _26 = ay_16 >> 31; + _27 = ak_20 + _26; + if (_27 != 2147483645) + goto __BB7(guessed(67108864)); + else + goto __BB8(guessed(67108864)); + + __BB(9,guessed_local(1014686041)): + goto __BB6(precise(134217728)); + + __BB(6,loop_header(1),guessed_local(2088427865)): + ak_30 = __PHI (__BB2: _Literal (int) -1, __BB9: 0); + am_31 = __PHI (__BB2: _Literal (int) -1, __BB9: am_9); + ay_32 = __PHI (__BB2: _Literal (int) -1782460880, __BB9: 3); +az: + goto __BB3(precise(134217728)); + + __BB(7,guessed_local(536870921)): + goto __BB8(precise(134217728)); + + __BB(8,guessed_local(1073741842)): + _29 = __PHI (__BB5: 0, __BB7: 1); + if (_29 != 0) + goto __BB11; + else + goto __BB12; + + __BB(11): + __builtin_abort (); + + __BB(12): + return _29; + +} + + + diff --git a/gcc/testsuite/gcc.dg/torture/pr126171-2.c b/gcc/testsuite/gcc.dg/torture/pr126171-2.c new file mode 100644 index 000000000000..82df6bfef9b3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr126171-2.c @@ -0,0 +1,52 @@ +/* { dg-do run } */ +/* { dg-require-effective-target int32plus } */ + +int ah, o, t, q, aq, as, at; + +int __attribute__ ((noipa)) n () { + return 129105662; +} + +int a (int ak, int al[1], int am, int bj) { + int ay = as = -1782460880; + at = -28702851; + o = 0 % al[0] + -1 + bj - 1; + goto az; +ba: + al[0] = ak - 1; + am = -1; + goto bb; +bc: + t = -(bj - 2147483646); + ay = ay - (-1 % bj - 2147483647); + goto bd; +be: + aq = -1704571560; + am = am + bj - 2147483646; + if (am << (n () - 129105632) == 0) + goto bc; + goto bf; +bd: + ak = (-1 ^ al[0]) - 1 + ak + 2147483647; + if (ak) + goto be; + goto bg; +bf: + bj = -1 - am - 1 + 2147483647; + o = -1 - o - 1; + goto ba; +bg: + ay = 3; +az: + goto be; +bb: + q = (ay >> 31) - -ak - 2147483646; + if (q != -1) return 1; + return 0; +} + +int main () { + if (a (-1, (int[]) { -1 }, -1, 2147483647) != 0) + __builtin_abort (); + return 0; +} diff --git a/gcc/tree-scalar-evolution.cc b/gcc/tree-scalar-evolution.cc index 279ff46474e4..cd99cbe86ce5 100644 --- a/gcc/tree-scalar-evolution.cc +++ b/gcc/tree-scalar-evolution.cc @@ -607,8 +607,7 @@ private: tree *evolution_of_loop, int limit); t_bool follow_ssa_edge_inner_loop_phi (gphi *loop_phi_node, tree *evolution_of_loop, int limit); - tree add_to_evolution (tree chrec_before, enum tree_code code, - tree to_add, gimple *at_stmt); + tree add_to_evolution (tree chrec_before, tree to_add, gimple *at_stmt); tree add_to_evolution_1 (tree chrec_before, tree to_add, gimple *at_stmt); class loop *loop; @@ -853,10 +852,8 @@ scev_dfs::add_to_evolution_1 (tree chrec_before, tree to_add, gimple *at_stmt) */ tree -scev_dfs::add_to_evolution (tree chrec_before, enum tree_code code, - tree to_add, gimple *at_stmt) +scev_dfs::add_to_evolution (tree chrec_before, tree to_add, gimple *at_stmt) { - tree type = chrec_type (to_add); tree res = NULL_TREE; if (to_add == NULL_TREE) @@ -879,25 +876,6 @@ scev_dfs::add_to_evolution (tree chrec_before, enum tree_code code, fprintf (dump_file, ")\n"); } - if (code == MINUS_EXPR) - { - if (INTEGRAL_TYPE_P (type) - && TYPE_OVERFLOW_UNDEFINED (type) - && !expr_not_equal_to (to_add, - wi::to_wide (TYPE_MIN_VALUE (type)))) - { - tree utype = unsigned_type_for (type); - to_add = chrec_convert_rhs (utype, to_add); - to_add = chrec_fold_multiply (utype, to_add, - build_int_cst_type (utype, -1)); - to_add = chrec_convert_rhs (type, to_add); - } - else - to_add = chrec_fold_multiply (type, to_add, SCALAR_FLOAT_TYPE_P (type) - ? build_real (type, dconstm1) - : build_int_cst_type (type, -1)); - } - res = add_to_evolution_1 (chrec_before, to_add, at_stmt); if (dump_file && (dump_flags & TDF_SCEV)) @@ -942,7 +920,7 @@ scev_dfs::follow_ssa_edge_binary (gimple *at_stmt, tree type, tree rhs0, res = follow_ssa_edge_expr (at_stmt, rhs0, &evol, limit); if (res == t_true) *evolution_of_loop = add_to_evolution - (chrec_convert (type, evol, at_stmt), code, rhs1, at_stmt); + (chrec_convert (type, evol, at_stmt), rhs1, at_stmt); else if (res == t_false) { res = follow_ssa_edge_expr @@ -950,7 +928,7 @@ scev_dfs::follow_ssa_edge_binary (gimple *at_stmt, tree type, tree rhs0, if (res == t_true) *evolution_of_loop = add_to_evolution (chrec_convert (type, *evolution_of_loop, at_stmt), - code, rhs0, at_stmt); + rhs0, at_stmt); } } @@ -966,7 +944,7 @@ scev_dfs::follow_ssa_edge_binary (gimple *at_stmt, tree type, tree rhs0, if (res == t_true) *evolution_of_loop = add_to_evolution (chrec_convert (type, *evolution_of_loop, at_stmt), - code, rhs0, at_stmt); + rhs0, at_stmt); } else @@ -976,17 +954,6 @@ scev_dfs::follow_ssa_edge_binary (gimple *at_stmt, tree type, tree rhs0, res = t_false; break; - case MINUS_EXPR: - /* This case is under the form "opnd0 = rhs0 - rhs1". */ - if (TREE_CODE (rhs0) == SSA_NAME) - gcc_unreachable (); /* Handled in caller. */ - else - /* Otherwise, match an assignment under the form: - "a = ... - ...". */ - /* And there is nothing to do. */ - res = t_false; - break; - default: res = t_false; } @@ -1283,10 +1250,8 @@ scev_dfs::follow_ssa_edge_expr (gimple *at_stmt, tree expr, /* Fallthru. */ case POINTER_PLUS_EXPR: case PLUS_EXPR: - case MINUS_EXPR: /* This case is under the form "rhs0 +- rhs1". */ - if (TREE_CODE (rhs0) == SSA_NAME - && (TREE_CODE (rhs1) != SSA_NAME || code == MINUS_EXPR)) + if (TREE_CODE (rhs0) == SSA_NAME && TREE_CODE (rhs1) != SSA_NAME) { /* Match an assignment under the form: "a = b +- ...". */ @@ -1295,13 +1260,56 @@ scev_dfs::follow_ssa_edge_expr (gimple *at_stmt, tree expr, if (res == t_true) *evolution_of_loop = add_to_evolution (chrec_convert (type, *evolution_of_loop, at_stmt), - code, rhs1, at_stmt); + rhs1, at_stmt); return res; } /* Else search for the SCC in both rhs0 and rhs1. */ return follow_ssa_edge_binary (at_stmt, type, rhs0, code, rhs1, evolution_of_loop, limit); + + case MINUS_EXPR: + /* This case is under the form "rhs0 - rhs1". */ + if (TREE_CODE (rhs0) == SSA_NAME) + { + /* Match an assignment under the form: + "a = b +- ...". */ + t_bool res = follow_ssa_edge_expr (at_stmt, rhs0, + evolution_of_loop, limit); + if (res != t_true) + return res; + /* We have to avoid negating INT_MIN given that a) invokes UB, + b) results in a wrong scev_direction. See PR126171. */ + if (INTEGRAL_TYPE_P (type) + && TYPE_OVERFLOW_UNDEFINED (type) + && !expr_not_equal_to (rhs1, + wi::to_wide (TYPE_MIN_VALUE (type)))) + { + tree utype = unsigned_type_for (type); + tree to_add = chrec_convert_rhs (utype, rhs1); + to_add = chrec_fold_multiply (utype, to_add, + build_int_cst_type (utype, -1)); + *evolution_of_loop + = chrec_convert (utype, *evolution_of_loop, at_stmt); + *evolution_of_loop = add_to_evolution (*evolution_of_loop, + to_add, at_stmt); + *evolution_of_loop + = chrec_convert (type, *evolution_of_loop, at_stmt); + } + else + { + tree to_add = chrec_fold_multiply (type, rhs1, + build_minus_one_cst (type)); + *evolution_of_loop + = add_to_evolution (chrec_convert (type, *evolution_of_loop, + at_stmt), + to_add, at_stmt); + } + return res; + } + /* There is nothing to do. */ + return t_false; + default: return t_false; }
