aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-if-conv.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-if-conv.cc')
-rw-r--r--gcc/tree-if-conv.cc186
1 files changed, 186 insertions, 0 deletions
diff --git a/gcc/tree-if-conv.cc b/gcc/tree-if-conv.cc
index 366e959..ba25c19 100644
--- a/gcc/tree-if-conv.cc
+++ b/gcc/tree-if-conv.cc
@@ -2114,6 +2114,187 @@ gen_phi_arg_condition (gphi *phi, ifcvt_arg_entry_t &arg,
return cond;
}
+/* Find the operand which is different between ARG0_OP and ARG1_OP.
+ Returns the operand num where the difference is.
+ Set NEWARG0 and NEWARG1 from the different argument.
+ Returns -1 if none is found.
+ If ARG0_OP/ARG1_OP is commutative also try swapping the
+ two commutative operands and return the operand number where
+ the difference happens in ARG0_OP. */
+
+static int
+find_different_opnum (const gimple_match_op &arg0_op,
+ const gimple_match_op &arg1_op,
+ tree *new_arg0, tree *new_arg1)
+{
+ unsigned opnum = -1;
+ unsigned first;
+ first = first_commutative_argument (arg1_op.code, arg1_op.type);
+ for (unsigned i = 0; i < arg0_op.num_ops; i++)
+ {
+ if (!operand_equal_for_phi_arg_p (arg0_op.ops[i],
+ arg1_op.ops[i]))
+ {
+ /* Can handle only one non equal operand. */
+ if (opnum != -1u)
+ {
+ /* Though if opnum is right before i and opnum is equal
+ to the first communtative argument, handle communtative
+ specially. */
+ if (i == opnum + 1 && opnum == first)
+ goto commutative;
+ return -1;
+ }
+ opnum = i;
+ }
+ }
+ /* If all operands are equal only do this is there was single
+ operand. */
+ if (opnum == -1u)
+ {
+ if (arg0_op.num_ops != 1)
+ return -1;
+ opnum = 0;
+ }
+ *new_arg0 = arg0_op.ops[opnum];
+ *new_arg1 = arg1_op.ops[opnum];
+ return opnum;
+
+/* Handle commutative operations. */
+commutative:
+ gcc_assert (first != -1u);
+
+ /* Check the rest of the arguments to make sure they are the same. */
+ for (unsigned i = first + 2; i < arg0_op.num_ops; i++)
+ if (!operand_equal_for_phi_arg_p (arg0_op.ops[i],
+ arg1_op.ops[i]))
+ return -1;
+
+ /* If the arg0[first+1] and arg1[first] are the same
+ then the one which is different is arg0[first] and arg1[first+1]
+ return first since this is based on arg0. */
+ if (operand_equal_for_phi_arg_p (arg0_op.ops[first + 1],
+ arg1_op.ops[first]))
+ {
+ *new_arg0 = arg0_op.ops[first];
+ *new_arg1 = arg1_op.ops[first + 1];
+ return first;
+ }
+ /* If the arg0[first] and arg1[first+1] are the same
+ then the one which is different is arg0[first+1] and arg1[first]
+ return first+1 since this is based on arg0. */
+ if (operand_equal_for_phi_arg_p (arg0_op.ops[first],
+ arg1_op.ops[first + 1]))
+ {
+ *new_arg0 = arg0_op.ops[first + 1];
+ *new_arg1 = arg1_op.ops[first];
+ return first + 1;
+ }
+ return -1;
+}
+
+/* Factors out an operation from *ARG0 and *ARG1 and
+ create the new statement at GSI. *RES is the
+ result of that new statement. Update *ARG0 and *ARG1
+ and *RES to the new values if the factoring happened.
+ Loops until all of the factoring is completed. */
+
+static void
+factor_out_operators (tree *res, gimple_stmt_iterator *gsi,
+ tree *arg0, tree *arg1, gphi *phi)
+{
+ gimple_match_op arg0_op, arg1_op;
+ bool repeated = false;
+
+again:
+ if (TREE_CODE (*arg0) != SSA_NAME || TREE_CODE (*arg1) != SSA_NAME)
+ return;
+
+ if (operand_equal_p (*arg0, *arg1))
+ return;
+
+ /* If either args have > 1 use, then this transformation actually
+ increases the number of expressions evaluated at runtime. */
+ if (repeated
+ ? (!has_zero_uses (*arg0) || !has_zero_uses (*arg1))
+ : (!has_single_use (*arg0) || !has_single_use (*arg1)))
+ return;
+
+ gimple *arg0_def_stmt = SSA_NAME_DEF_STMT (*arg0);
+ if (!gimple_extract_op (arg0_def_stmt, &arg0_op))
+ return;
+
+ /* At this point there should be no ssa names occuring in abnormals. */
+ gcc_assert (!arg0_op.operands_occurs_in_abnormal_phi ());
+
+ gimple *arg1_def_stmt = SSA_NAME_DEF_STMT (*arg1);
+ if (!gimple_extract_op (arg1_def_stmt, &arg1_op))
+ return;
+
+ /* At this point there should be no ssa names occuring in abnormals. */
+ gcc_assert (!arg1_op.operands_occurs_in_abnormal_phi ());
+
+ /* No factoring can happen if the codes are different
+ or the number operands. */
+ if (arg1_op.code != arg0_op.code
+ || arg1_op.num_ops != arg0_op.num_ops)
+ return;
+
+ tree new_arg0, new_arg1;
+ int opnum = find_different_opnum (arg0_op, arg1_op, &new_arg0, &new_arg1);
+ if (opnum == -1)
+ return;
+
+ if (!types_compatible_p (TREE_TYPE (new_arg0), TREE_TYPE (new_arg1)))
+ return;
+ tree new_res = make_ssa_name (TREE_TYPE (new_arg0), NULL);
+
+ /* Create the operation stmt if possible and insert it. */
+
+ gimple_match_op new_op = arg0_op;
+ new_op.ops[opnum] = new_res;
+ gimple_seq seq = NULL;
+ tree result = *res;
+ result = maybe_push_res_to_seq (&new_op, &seq, result);
+
+ /* If we can't create the new statement, release the temp name
+ and return back. */
+ if (!result)
+ {
+ release_ssa_name (new_res);
+ return;
+ }
+ gsi_insert_seq_before (gsi, seq, GSI_CONTINUE_LINKING);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "PHI ");
+ print_generic_expr (dump_file, gimple_phi_result (phi));
+ fprintf (dump_file,
+ " changed to factor operation out from COND_EXPR.\n");
+ fprintf (dump_file, "New stmt with OPERATION that defines ");
+ print_generic_expr (dump_file, result);
+ fprintf (dump_file, ".\n");
+ }
+
+ /* Remove the old operation(s) that has single use. */
+ gimple_stmt_iterator gsi_for_def;
+
+ gsi_for_def = gsi_for_stmt (arg0_def_stmt);
+ gsi_remove (&gsi_for_def, true);
+ release_defs (arg0_def_stmt);
+ gsi_for_def = gsi_for_stmt (arg1_def_stmt);
+ gsi_remove (&gsi_for_def, true);
+ release_defs (arg1_def_stmt);
+
+ /* Update the arguments and try again. */
+ *arg0 = new_arg0;
+ *arg1 = new_arg1;
+ *res = new_res;
+ repeated = true;
+ goto again;
+}
+
/* Create the smallest nested conditional possible. On pre-order we record
which conditionals are live, and on post-order rewrite the chain by removing
already active conditions.
@@ -2293,6 +2474,11 @@ predicate_scalar_phi (gphi *phi, gimple_stmt_iterator *gsi, bool loop_versioned)
arg0 = gimple_phi_arg_def (phi, 0);
arg1 = gimple_phi_arg_def (phi, 1);
}
+
+ /* Factor out operand if possible. This can only be done easily
+ for PHI with 2 elements. */
+ factor_out_operators (&res, gsi, &arg0, &arg1, phi);
+
if (is_cond_scalar_reduction (phi, &reduc, arg0, arg1,
&op0, &op1, false, &has_nop,
&nop_reduc))