This is a small improvement to the code where we allow factoring
out loads even with stores (or calls) before hand, this will allow
for store elimination (store factoring) to happen too.
factor_op_phi-load-stores-1.c is one such example.
Also adds the cost model to factoring out loads.

Bootstrapped and tested on x86_64-linux-gnu.

gcc/ChangeLog:

        * tree-ssa-phiopt.cc (is_factor_profitable): Change arg_op
        to operands and opcount.
        (factor_out_conditional_operation): Update call to
        is_factor_profitable.
        (factor_out_conditional_load): Support when merge has
        a virtual phi. The load's vuse needs to be the arguments
        to the virtual phi. Call is_factor_profitable on the new phi
        arguments. Update the vuse on the new load to the virtual phi.

gcc/testsuite/ChangeLog:

        * gcc.dg/tree-ssa/factor_op_phi-load-stores-1.c: New test.

Signed-off-by: Andrew Pinski <[email protected]>
---
 .../tree-ssa/factor_op_phi-load-stores-1.c    | 21 +++++++++
 gcc/tree-ssa-phiopt.cc                        | 45 ++++++++++++-------
 2 files changed, 50 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-stores-1.c

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-stores-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-stores-1.c
new file mode 100644
index 00000000000..34164a0ebc6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/factor_op_phi-load-stores-1.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-phiopt-details" } */
+int f(int *a, int *c, int *d, int e)
+{
+  int t;
+  if (e)
+  {
+    *a = 1;
+    t = *c;
+  }
+  else
+  {
+    *a = 0;
+    t = *d;
+  }
+  return t;
+}
+
+/* { dg-final { scan-tree-dump-times "changed to factor out load from" 1 
"phiopt2" } } */
+/* { dg-final { scan-tree-dump-times "factoring out stores" 1 "phiopt2" } } */
+
diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
index ff44ae51e36..c6289c03758 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -222,11 +222,11 @@ replace_phi_edge_with_variable (basic_block cond_block,
              bb->index);
 }
 
-/* Returns true if the operands of arg_op defined from DEF_STMT is profitable 
to move
+/* Returns true if the OPERANDS (OPCOUNTED) defined from DEF_STMT is 
profitable to move
    to the usage into the basic block MERGE where the new statement
    will be located.  */
 static bool
-is_factor_profitable (gimple *def_stmt, basic_block merge, const 
gimple_match_op &arg_op)
+is_factor_profitable (gimple *def_stmt, basic_block merge, tree *operands, 
unsigned opcount)
 {
   /* The defining statement should be conditional.  */
   if (dominated_by_p (CDI_DOMINATORS, merge,
@@ -284,9 +284,9 @@ is_factor_profitable (gimple *def_stmt, basic_block merge, 
const gimple_match_op
     return true;
 
   /* Loop over all of the operands to see if all are used after anyways.  */
-  for (unsigned i = 0; i < arg_op.num_ops; i++)
+  for (unsigned i = 0; i < opcount; i++)
     {
-      tree arg = arg_op.ops[i];
+      tree arg = operands[i];
       /* If the arg is invariant, then there is
         no extending of the live range. */
       if (is_gimple_min_invariant (arg))
@@ -422,9 +422,11 @@ factor_out_conditional_operation (edge e0, edge e1, 
basic_block merge,
        return false;
 
       /* Check to make sure extending the lifetimes of all operands is ok.  */
-      if (!is_factor_profitable (arg0_def_stmt, merge, arg0_op))
+      if (!is_factor_profitable (arg0_def_stmt, merge,
+                                arg0_op.ops, arg0_op.num_ops))
        return false;
-      if (!is_factor_profitable (arg1_def_stmt, merge, arg1_op))
+      if (!is_factor_profitable (arg1_def_stmt, merge,
+                                arg1_op.ops, arg1_op.num_ops))
        return false;
 
       /* If this was a division and the operand is the divisor
@@ -493,7 +495,7 @@ factor_out_conditional_operation (edge e0, edge e1, 
basic_block merge,
       /* TODO: handle more than just casts here. */
       if (!gimple_assign_cast_p (arg0_def_stmt))
        return false;
-      if (!is_factor_profitable (arg0_def_stmt, merge, arg0_op))
+      if (!is_factor_profitable (arg0_def_stmt, merge, arg0_op.ops, 
arg0_op.num_ops))
        return false;
 
       /* If arg1 is an INTEGER_CST, fold it to new type if it fits, or else
@@ -3679,10 +3681,7 @@ factor_out_conditional_load (edge e0, edge e1, 
basic_block merge, gphi *phi,
   /* Not a virtual operand. */
   if (virtual_operand_p (gimple_phi_result (phi))
       /* can only handle the merge bb having 2 predecessors.  */
-      || gimple_phi_num_args (phi) != 2
-      /* No calls nor stores in the middle bbs.
-        FIXME: handle the case where there are stores before the load.  */
-      || get_virtual_phi (merge))
+      || gimple_phi_num_args (phi) != 2)
     return false;
 
   tree arg0 = gimple_phi_arg_def (phi, e0->dest_idx);
@@ -3703,12 +3702,19 @@ factor_out_conditional_load (edge e0, edge e1, 
basic_block merge, gphi *phi,
 
   /* The load needs to be a load with NO volatile ops.  */
   if (!gimple_assign_load_p (load0) || !gimple_assign_load_p (load1)
-      || gimple_has_volatile_ops (load0) || gimple_has_volatile_ops (load1)
-      /* Assert that the vuse is the same, this will be true since there
-        are no stores either bb.  */
-      || gimple_vuse (load0) != gimple_vuse (load1))
+      || gimple_has_volatile_ops (load0) || gimple_has_volatile_ops (load1))
     return false;
 
+  /* Allow for stores/calls before the load.  */
+  if (gphi *vphi = get_virtual_phi (merge))
+    {
+      if (gimple_vuse (load0) != gimple_phi_arg_def (vphi, e0->dest_idx)
+         || gimple_vuse (load1) != gimple_phi_arg_def (vphi, e1->dest_idx))
+       return false;
+    }
+  else
+    gcc_assert (gimple_vuse (load0) == gimple_vuse (load1));
+
   tree ref0 = gimple_assign_rhs1 (load0);
   tree ref1 = gimple_assign_rhs1 (load1);
 
@@ -3727,6 +3733,10 @@ factor_out_conditional_load (edge e0, edge e1, 
basic_block merge, gphi *phi,
 
   tree p0 = TREE_OPERAND (ref0, 0);
   tree p1 = TREE_OPERAND (ref1, 0);
+  if (!is_factor_profitable (load0, merge, &p0, 1))
+    return false;
+  if (!is_factor_profitable (load1, merge, &p1, 1))
+    return false;
 
   tree newptr;
   if (p0 != p1)
@@ -3773,7 +3783,10 @@ factor_out_conditional_load (edge e0, edge e1, 
basic_block merge, gphi *phi,
   MR_DEPENDENCE_BASE (nref) = base;
   tree res = gimple_phi_result (phi);
   gassign *load = gimple_build_assign (res, nref);
-  gimple_set_vuse (load, gimple_vuse (load0));
+  if (gphi *vphi = get_virtual_phi (merge))
+    gimple_set_vuse (load, gimple_phi_result (vphi));
+  else
+    gimple_set_vuse (load, gimple_vuse (load0));
   gimple_stmt_iterator gsi = gsi_after_labels (merge);
   gsi_insert_before (&gsi, load, GSI_SAME_STMT);
 
-- 
2.43.0

Reply via email to