aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr104645.c28
-rw-r--r--gcc/tree-ssa-phiopt.cc63
2 files changed, 77 insertions, 14 deletions
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr104645.c b/gcc/testsuite/gcc.dg/tree-ssa/pr104645.c
new file mode 100644
index 0000000..83c1dd4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr104645.c
@@ -0,0 +1,28 @@
+/* PR tree-optimization/104645 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-not " = PHI <" "optimized" } } */
+
+int
+foo (unsigned i)
+{
+ return i ? i % 2 : 0;
+}
+
+int
+bar (unsigned i)
+{
+ int b = 0;
+ if (i)
+ {
+ unsigned a = i & 1;
+ b = a;
+ }
+ return b;
+}
+
+int
+baz (unsigned i)
+{
+ return i ? i + 4 : 4;
+}
diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
index 562468b..4a0c9dd 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -1395,11 +1395,22 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
gimple *assign = gsi_stmt (gsi);
if (!is_gimple_assign (assign)
- || gimple_assign_rhs_class (assign) != GIMPLE_BINARY_RHS
|| (!INTEGRAL_TYPE_P (TREE_TYPE (arg0))
&& !POINTER_TYPE_P (TREE_TYPE (arg0))))
return 0;
+ if (gimple_assign_rhs_class (assign) != GIMPLE_BINARY_RHS)
+ {
+ /* If last stmt of the middle_bb is a conversion, handle it like
+ a preparation statement through constant evaluation with
+ checking for UB. */
+ enum tree_code sc = gimple_assign_rhs_code (assign);
+ if (CONVERT_EXPR_CODE_P (sc))
+ assign = NULL;
+ else
+ return 0;
+ }
+
/* Punt if there are (degenerate) PHIs in middle_bb, there should not be. */
if (!gimple_seq_empty_p (phi_nodes (middle_bb)))
return 0;
@@ -1430,7 +1441,8 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
int prep_cnt;
for (prep_cnt = 0; ; prep_cnt++)
{
- gsi_prev_nondebug (&gsi);
+ if (prep_cnt || assign)
+ gsi_prev_nondebug (&gsi);
if (gsi_end_p (gsi))
break;
@@ -1450,7 +1462,8 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
|| !INTEGRAL_TYPE_P (TREE_TYPE (lhs))
|| !INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
|| !single_imm_use (lhs, &use_p, &use_stmt)
- || use_stmt != (prep_cnt ? prep_stmt[prep_cnt - 1] : assign))
+ || ((prep_cnt || assign)
+ && use_stmt != (prep_cnt ? prep_stmt[prep_cnt - 1] : assign)))
return 0;
switch (gimple_assign_rhs_code (g))
{
@@ -1483,10 +1496,6 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
>= 3 * estimate_num_insns (cond, &eni_time_weights))
return 0;
- tree lhs = gimple_assign_lhs (assign);
- tree rhs1 = gimple_assign_rhs1 (assign);
- tree rhs2 = gimple_assign_rhs2 (assign);
- enum tree_code code_def = gimple_assign_rhs_code (assign);
tree cond_lhs = gimple_cond_lhs (cond);
tree cond_rhs = gimple_cond_rhs (cond);
@@ -1516,16 +1525,39 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
return 0;
}
+ tree lhs, rhs1, rhs2;
+ enum tree_code code_def;
+ if (assign)
+ {
+ lhs = gimple_assign_lhs (assign);
+ rhs1 = gimple_assign_rhs1 (assign);
+ rhs2 = gimple_assign_rhs2 (assign);
+ code_def = gimple_assign_rhs_code (assign);
+ }
+ else
+ {
+ gcc_assert (prep_cnt > 0);
+ lhs = cond_lhs;
+ rhs1 = NULL_TREE;
+ rhs2 = NULL_TREE;
+ code_def = ERROR_MARK;
+ }
+
if (((code == NE_EXPR && e1 == false_edge)
|| (code == EQ_EXPR && e1 == true_edge))
&& arg0 == lhs
- && ((arg1 == rhs1
- && operand_equal_for_phi_arg_p (rhs2, cond_lhs)
- && neutral_element_p (code_def, cond_rhs, true))
- || (arg1 == rhs2
+ && ((assign == NULL
+ && operand_equal_for_phi_arg_p (arg1, cond_rhs))
+ || (assign
+ && arg1 == rhs1
+ && operand_equal_for_phi_arg_p (rhs2, cond_lhs)
+ && neutral_element_p (code_def, cond_rhs, true))
+ || (assign
+ && arg1 == rhs2
&& operand_equal_for_phi_arg_p (rhs1, cond_lhs)
&& neutral_element_p (code_def, cond_rhs, false))
- || (operand_equal_for_phi_arg_p (arg1, cond_rhs)
+ || (assign
+ && operand_equal_for_phi_arg_p (arg1, cond_rhs)
&& ((operand_equal_for_phi_arg_p (rhs2, cond_lhs)
&& absorbing_element_p (code_def, cond_rhs, true, rhs2))
|| (operand_equal_for_phi_arg_p (rhs1, cond_lhs)
@@ -1555,8 +1587,11 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
gsi_from = gsi_for_stmt (prep_stmt[i]);
gsi_move_before (&gsi_from, &gsi);
}
- gsi_from = gsi_for_stmt (assign);
- gsi_move_before (&gsi_from, &gsi);
+ if (assign)
+ {
+ gsi_from = gsi_for_stmt (assign);
+ gsi_move_before (&gsi_from, &gsi);
+ }
replace_phi_edge_with_variable (cond_bb, e1, phi, lhs);
return 2;
}