diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c index 39d04ab..4752fe5 100644 --- a/gcc/tree-ssa-phiopt.c +++ b/gcc/tree-ssa-phiopt.c @@ -725,6 +725,80 @@ jump_function_from_stmt (tree *arg, gimple stmt) return false; } +static int +operand_equal_for_phi_arg_p_1 (const_tree arg0, const_tree arg1, + enum tree_code *code, gimple cond) +{ + gimple def; + tree rhs, lhs; + + if ((operand_equal_for_phi_arg_p (arg0, gimple_cond_lhs (cond)) + && operand_equal_for_phi_arg_p (arg1, gimple_cond_rhs (cond))) + || (operand_equal_for_phi_arg_p (arg1, gimple_cond_lhs (cond)) + && operand_equal_for_phi_arg_p (arg0, gimple_cond_rhs (cond)))) + return 1; + + /* It handles case like + + if (a == 0 && b > c) + return 0; + return a; + + In gimple, the COND is like + + t1 = a == 0 + t2 = b > c + t3 = t1 & t2 + if (t3 != 0) + */ + lhs = gimple_cond_lhs (cond); + rhs = gimple_cond_rhs (cond); + if (*code != NE_EXPR || !integer_zerop (rhs) + || TREE_CODE (lhs) != SSA_NAME) + return 0; + + def = SSA_NAME_DEF_STMT (lhs); + if (!is_gimple_assign (def) || gimple_assign_rhs_code (def) != BIT_AND_EXPR) + return 0; + + if (TREE_CODE (gimple_assign_rhs1 (def)) == SSA_NAME) + { + gimple def1 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (def)); + if (is_gimple_assign (def1) && gimple_assign_rhs_code (def1) == EQ_EXPR) + { + tree op0 = gimple_assign_rhs1 (def1); + tree op1 = gimple_assign_rhs2 (def1); + if ((operand_equal_for_phi_arg_p (arg0, op0) + && operand_equal_for_phi_arg_p (arg1, op1)) + || (operand_equal_for_phi_arg_p (arg0, op1) + && operand_equal_for_phi_arg_p (arg1, op0))) + { + *code = gimple_assign_rhs_code (def1); + return 1; + } + } + } + if (TREE_CODE (gimple_assign_rhs2 (def)) == SSA_NAME) + { + gimple def2 = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (def)); + if (is_gimple_assign (def2) && gimple_assign_rhs_code (def2) == EQ_EXPR) + { + tree op0 = gimple_assign_rhs1 (def2); + tree op1 = gimple_assign_rhs2 (def2); + if ((operand_equal_for_phi_arg_p (arg0, op0) + && operand_equal_for_phi_arg_p (arg1, op1)) + || (operand_equal_for_phi_arg_p (arg0, op1) + && operand_equal_for_phi_arg_p (arg1, op0))) + { + *code = gimple_assign_rhs_code (def2); + return 1; + } + } + } + + return 0; +} + /* The function value_replacement does the main work of doing the value replacement. Return non-zero if the replacement is done. Otherwise return 0. If we remove the middle basic block, return 2. @@ -794,10 +868,7 @@ value_replacement (basic_block cond_bb, basic_block middle_bb, We now need to verify that the two arguments in the PHI node match the two arguments to the equality comparison. */ - if ((operand_equal_for_phi_arg_p (arg0, gimple_cond_lhs (cond)) - && operand_equal_for_phi_arg_p (arg1, gimple_cond_rhs (cond))) - || (operand_equal_for_phi_arg_p (arg1, gimple_cond_lhs (cond)) - && operand_equal_for_phi_arg_p (arg0, gimple_cond_rhs (cond)))) + if (operand_equal_for_phi_arg_p_1 (arg0, arg1, &code, cond)) { edge e; tree arg; diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-11.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-11.c new file mode 100644 index 0000000..ced1fc2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-11.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-optimized" } */ + +int f(int a, int b, int c) +{ + if (a == 0 && b > c) + return 0; + return a; +} + +/* { dg-final { scan-tree-dump-times "if" 0 "optimized"} } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */