aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr96272.c37
-rw-r--r--gcc/tree-ssa-math-opts.c95
2 files changed, 111 insertions, 21 deletions
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96272.c b/gcc/testsuite/gcc.dg/tree-ssa/pr96272.c
new file mode 100644
index 0000000..4c9fa63
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr96272.c
@@ -0,0 +1,37 @@
+/* PR tree-optimization/96272 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-widening_mul" } */
+
+unsigned
+foo (unsigned a, unsigned b)
+{
+ if (a > ~0U - b)
+ return ~0U;
+ return a + b;
+}
+
+unsigned
+bar (unsigned a, unsigned b)
+{
+ if (a <= ~0U - b)
+ return ~0U;
+ return a + b;
+}
+
+unsigned
+baz (unsigned a, unsigned b)
+{
+ if (~0U - b < a)
+ return ~0U;
+ return a + b;
+}
+
+unsigned
+qux (unsigned a, unsigned b)
+{
+ if (~0U - b >= a)
+ return ~0U;
+ return a + b;
+}
+
+/* { dg-final { scan-tree-dump-times "ADD_OVERFLOW" 4 "widening_mul" { target { i?86-*-* x86_64-*-* } } } } */
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index 4ade0b6..b8cdce9 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -3457,7 +3457,8 @@ convert_mult_to_fma (gimple *mul_stmt, tree op1, tree op2,
and 0 otherwise. */
static int
-uaddsub_overflow_check_p (gimple *stmt, gimple *use_stmt, tree maxval)
+uaddsub_overflow_check_p (gimple *stmt, gimple *use_stmt, tree maxval,
+ tree *other)
{
enum tree_code ccode = ERROR_MARK;
tree crhs1 = NULL_TREE, crhs2 = NULL_TREE;
@@ -3520,6 +3521,13 @@ uaddsub_overflow_check_p (gimple *stmt, gimple *use_stmt, tree maxval)
|| (code == PLUS_EXPR && (crhs1 == rhs1 || crhs1 == rhs2)
&& crhs2 == lhs))
return ccode == GT_EXPR ? 1 : -1;
+ /* r = ~a; b > r or b <= r. */
+ if (code == BIT_NOT_EXPR && crhs2 == lhs)
+ {
+ if (other)
+ *other = crhs1;
+ return ccode == GT_EXPR ? 1 : -1;
+ }
break;
case LT_EXPR:
case GE_EXPR:
@@ -3531,6 +3539,13 @@ uaddsub_overflow_check_p (gimple *stmt, gimple *use_stmt, tree maxval)
|| (code == PLUS_EXPR && crhs1 == lhs
&& (crhs2 == rhs1 || crhs2 == rhs2)))
return ccode == LT_EXPR ? 1 : -1;
+ /* r = ~a; r < b or r >= b. */
+ if (code == BIT_NOT_EXPR && crhs1 == lhs)
+ {
+ if (other)
+ *other = crhs2;
+ return ccode == LT_EXPR ? 1 : -1;
+ }
break;
default:
break;
@@ -3560,7 +3575,15 @@ uaddsub_overflow_check_p (gimple *stmt, gimple *use_stmt, tree maxval)
_9 = REALPART_EXPR <_7>;
_8 = IMAGPART_EXPR <_8>;
if (_8)
- and replace (utype) x with _9. */
+ and replace (utype) x with _9.
+
+ Also recognize:
+ x = ~z;
+ if (y > x)
+ and replace it with
+ _7 = ADD_OVERFLOW (y, z);
+ _8 = IMAGPART_EXPR <_8>;
+ if (_8) */
static bool
match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
@@ -3576,34 +3599,49 @@ match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
gimple *add_stmt = NULL;
bool add_first = false;
- gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR);
+ gcc_checking_assert (code == PLUS_EXPR
+ || code == MINUS_EXPR
+ || code == BIT_NOT_EXPR);
if (!INTEGRAL_TYPE_P (type)
|| !TYPE_UNSIGNED (type)
|| has_zero_uses (lhs)
- || (code == MINUS_EXPR
- && optab_handler (usubv4_optab,
+ || (code != PLUS_EXPR
+ && optab_handler (code == MINUS_EXPR ? usubv4_optab : uaddv4_optab,
TYPE_MODE (type)) == CODE_FOR_nothing))
return false;
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ tree rhs2 = gimple_assign_rhs2 (stmt);
FOR_EACH_IMM_USE_FAST (use_p, iter, lhs)
{
use_stmt = USE_STMT (use_p);
if (is_gimple_debug (use_stmt))
continue;
- if (uaddsub_overflow_check_p (stmt, use_stmt, NULL_TREE))
- ovf_use_seen = true;
+ tree other = NULL_TREE;
+ if (uaddsub_overflow_check_p (stmt, use_stmt, NULL_TREE, &other))
+ {
+ if (code == BIT_NOT_EXPR)
+ {
+ gcc_assert (other);
+ if (TREE_CODE (other) != SSA_NAME)
+ return false;
+ if (rhs2 == NULL)
+ rhs2 = other;
+ else if (rhs2 != other)
+ return false;
+ }
+ ovf_use_seen = true;
+ }
else
use_seen = true;
if (ovf_use_seen && use_seen)
break;
}
- tree rhs1 = gimple_assign_rhs1 (stmt);
- tree rhs2 = gimple_assign_rhs2 (stmt);
tree maxval = NULL_TREE;
if (!ovf_use_seen
- || !use_seen
+ || (code == BIT_NOT_EXPR ? use_seen : !use_seen)
|| (code == PLUS_EXPR
&& optab_handler (uaddv4_optab,
TYPE_MODE (type)) == CODE_FOR_nothing))
@@ -3664,7 +3702,7 @@ match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
if (is_gimple_debug (use_stmt))
continue;
- if (uaddsub_overflow_check_p (stmt, use_stmt, maxval))
+ if (uaddsub_overflow_check_p (stmt, use_stmt, maxval, NULL))
{
ovf_use_seen = true;
use_bb = gimple_bb (use_stmt);
@@ -3781,23 +3819,27 @@ match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
}
tree ctype = build_complex_type (type);
- gcall *g = gimple_build_call_internal (code == PLUS_EXPR
+ gcall *g = gimple_build_call_internal (code != MINUS_EXPR
? IFN_ADD_OVERFLOW : IFN_SUB_OVERFLOW,
2, rhs1, rhs2);
tree ctmp = make_ssa_name (ctype);
gimple_call_set_lhs (g, ctmp);
gsi_insert_before (gsi, g, GSI_SAME_STMT);
tree new_lhs = maxval ? make_ssa_name (type) : lhs;
- gassign *g2 = gimple_build_assign (new_lhs, REALPART_EXPR,
- build1 (REALPART_EXPR, type, ctmp));
- if (maxval)
+ gassign *g2;
+ if (code != BIT_NOT_EXPR)
{
- gsi_insert_before (gsi, g2, GSI_SAME_STMT);
- if (add_first)
- *gsi = gsi_for_stmt (stmt);
+ g2 = gimple_build_assign (new_lhs, REALPART_EXPR,
+ build1 (REALPART_EXPR, type, ctmp));
+ if (maxval)
+ {
+ gsi_insert_before (gsi, g2, GSI_SAME_STMT);
+ if (add_first)
+ *gsi = gsi_for_stmt (stmt);
+ }
+ else
+ gsi_replace (gsi, g2, true);
}
- else
- gsi_replace (gsi, g2, true);
tree ovf = make_ssa_name (type);
g2 = gimple_build_assign (ovf, IMAGPART_EXPR,
build1 (IMAGPART_EXPR, type, ctmp));
@@ -3808,9 +3850,10 @@ match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
if (is_gimple_debug (use_stmt))
continue;
- int ovf_use = uaddsub_overflow_check_p (stmt, use_stmt, maxval);
+ int ovf_use = uaddsub_overflow_check_p (stmt, use_stmt, maxval, NULL);
if (ovf_use == 0)
{
+ gcc_assert (code != BIT_NOT_EXPR);
if (maxval)
{
tree use_lhs = gimple_assign_lhs (use_stmt);
@@ -3863,6 +3906,12 @@ match_uaddsub_overflow (gimple_stmt_iterator *gsi, gimple *stmt,
gsi_replace (&gsi2, g, true);
}
}
+ else if (code == BIT_NOT_EXPR)
+ {
+ gimple_stmt_iterator gsi2 = gsi_for_stmt (stmt);
+ gsi_remove (&gsi2, true);
+ release_ssa_name (lhs);
+ }
return true;
}
@@ -4188,6 +4237,10 @@ math_opts_dom_walker::after_dom_children (basic_block bb)
match_uaddsub_overflow (&gsi, stmt, code);
break;
+ case BIT_NOT_EXPR:
+ match_uaddsub_overflow (&gsi, stmt, code);
+ break;
+
case TRUNC_MOD_EXPR:
convert_to_divmod (as_a<gassign *> (stmt));
break;