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.
Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed.
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.
---
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(-)
create mode 100644 gcc/testsuite/gcc.dg/pr126171-1.c
create mode 100644 gcc/testsuite/gcc.dg/torture/pr126171-2.c
diff --git a/gcc/testsuite/gcc.dg/pr126171-1.c
b/gcc/testsuite/gcc.dg/pr126171-1.c
new file mode 100644
index 00000000000..4ac67c87c7d
--- /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 00000000000..82df6bfef9b
--- /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 279ff46474e..cd99cbe86ce 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;
}
--
2.51.0