Since we have the alias oracle we no longer optimize the testcase below
because I initially restricted the stmt walking to give up for PHIs
with more than 2 arguments because of compile-time complexity issues.
But it's easy to see that compile-time is not an issue when we
reduce PHI args pairwise to a single dominating operand.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.

Richard.

2011-10-11  Richard Guenther  <rguent...@suse.de>

        PR tree-optimization/50204
        * tree-ssa-alias.c (get_continuation_for_phi_1): Split out
        two argument handling from ...
        (get_continuation_for_phi): ... here.  Handle arbitrary number
        of PHI args.

        * gcc.dg/tree-ssa/ssa-fre-36.c: New testcase.

Index: gcc/tree-ssa-alias.c
===================================================================
*** gcc/tree-ssa-alias.c        (revision 179794)
--- gcc/tree-ssa-alias.c        (working copy)
*************** maybe_skip_until (gimple phi, tree targe
*** 1875,1880 ****
--- 1875,1934 ----
    return true;
  }
  
+ /* For two PHI arguments ARG0 and ARG1 try to skip non-aliasing code
+    until we hit the phi argument definition that dominates the other one.
+    Return that, or NULL_TREE if there is no such definition.  */
+ 
+ static tree
+ get_continuation_for_phi_1 (gimple phi, tree arg0, tree arg1,
+                           ao_ref *ref, bitmap *visited)
+ {
+   gimple def0 = SSA_NAME_DEF_STMT (arg0);
+   gimple def1 = SSA_NAME_DEF_STMT (arg1);
+   tree common_vuse;
+ 
+   if (arg0 == arg1)
+     return arg0;
+   else if (gimple_nop_p (def0)
+          || (!gimple_nop_p (def1)
+              && dominated_by_p (CDI_DOMINATORS,
+                                 gimple_bb (def1), gimple_bb (def0))))
+     {
+       if (maybe_skip_until (phi, arg0, ref, arg1, visited))
+       return arg0;
+     }
+   else if (gimple_nop_p (def1)
+          || dominated_by_p (CDI_DOMINATORS,
+                             gimple_bb (def0), gimple_bb (def1)))
+     {
+       if (maybe_skip_until (phi, arg1, ref, arg0, visited))
+       return arg1;
+     }
+   /* Special case of a diamond:
+        MEM_1 = ...
+        goto (cond) ? L1 : L2
+        L1: store1 = ...    #MEM_2 = vuse(MEM_1)
+          goto L3
+        L2: store2 = ...    #MEM_3 = vuse(MEM_1)
+        L3: MEM_4 = PHI<MEM_2, MEM_3>
+      We were called with the PHI at L3, MEM_2 and MEM_3 don't
+      dominate each other, but still we can easily skip this PHI node
+      if we recognize that the vuse MEM operand is the same for both,
+      and that we can skip both statements (they don't clobber us).
+      This is still linear.  Don't use maybe_skip_until, that might
+      potentially be slow.  */
+   else if ((common_vuse = gimple_vuse (def0))
+          && common_vuse == gimple_vuse (def1))
+     {
+       if (!stmt_may_clobber_ref_p_1 (def0, ref)
+         && !stmt_may_clobber_ref_p_1 (def1, ref))
+       return common_vuse;
+     }
+ 
+   return NULL_TREE;
+ }
+ 
+ 
  /* Starting from a PHI node for the virtual operand of the memory reference
     REF find a continuation virtual operand that allows to continue walking
     statements dominating PHI skipping only statements that cannot possibly
*************** get_continuation_for_phi (gimple phi, ao
*** 1890,1942 ****
    if (nargs == 1)
      return PHI_ARG_DEF (phi, 0);
  
!   /* For two arguments try to skip non-aliasing code until we hit
!      the phi argument definition that dominates the other one.  */
!   if (nargs == 2)
      {
        tree arg0 = PHI_ARG_DEF (phi, 0);
!       tree arg1 = PHI_ARG_DEF (phi, 1);
!       gimple def0 = SSA_NAME_DEF_STMT (arg0);
!       gimple def1 = SSA_NAME_DEF_STMT (arg1);
!       tree common_vuse;
! 
!       if (arg0 == arg1)
!       return arg0;
!       else if (gimple_nop_p (def0)
!              || (!gimple_nop_p (def1)
!                  && dominated_by_p (CDI_DOMINATORS,
!                                     gimple_bb (def1), gimple_bb (def0))))
!       {
!         if (maybe_skip_until (phi, arg0, ref, arg1, visited))
!           return arg0;
!       }
!       else if (gimple_nop_p (def1)
!              || dominated_by_p (CDI_DOMINATORS,
!                                 gimple_bb (def0), gimple_bb (def1)))
!       {
!         if (maybe_skip_until (phi, arg1, ref, arg0, visited))
!           return arg1;
!       }
!       /* Special case of a diamond:
!          MEM_1 = ...
!          goto (cond) ? L1 : L2
!          L1: store1 = ...    #MEM_2 = vuse(MEM_1)
!              goto L3
!          L2: store2 = ...    #MEM_3 = vuse(MEM_1)
!          L3: MEM_4 = PHI<MEM_2, MEM_3>
!        We were called with the PHI at L3, MEM_2 and MEM_3 don't
!        dominate each other, but still we can easily skip this PHI node
!        if we recognize that the vuse MEM operand is the same for both,
!        and that we can skip both statements (they don't clobber us).
!        This is still linear.  Don't use maybe_skip_until, that might
!        potentially be slow.  */
!       else if ((common_vuse = gimple_vuse (def0))
!              && common_vuse == gimple_vuse (def1))
        {
!         if (!stmt_may_clobber_ref_p_1 (def0, ref)
!             && !stmt_may_clobber_ref_p_1 (def1, ref))
!           return common_vuse;
        }
      }
  
    return NULL_TREE;
--- 1944,1967 ----
    if (nargs == 1)
      return PHI_ARG_DEF (phi, 0);
  
!   /* For two or more arguments try to pairwise skip non-aliasing code
!      until we hit the phi argument definition that dominates the other one.  
*/
!   else if (nargs >= 2)
      {
        tree arg0 = PHI_ARG_DEF (phi, 0);
!       tree arg1;
!       unsigned i = 1;
!       do
        {
!         arg1 = PHI_ARG_DEF (phi, i);
!         arg0 = get_continuation_for_phi_1 (phi, arg0, arg1, ref, visited);
!         if (!arg0)
!           return NULL_TREE;
! 
        }
+       while (++i < nargs);
+ 
+       return arg0;
      }
  
    return NULL_TREE;
Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-36.c
===================================================================
*** gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-36.c  (revision 0)
--- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-36.c  (revision 0)
***************
*** 0 ****
--- 1,26 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O -fdump-tree-fre1-details" } */
+ 
+ extern int opening;
+ extern int middle_game;
+ int s;
+ extern int d[1];
+ void PreEvaluate(int wtm)
+ {
+   int i, j;
+   if (opening) {
+       d[0]=1;
+   }
+   else if (middle_game) {
+       d[0]=-1;
+   }
+   if (4 != opening) {
+       return;
+   }
+   s = 1;
+ }
+ 
+ /* We should be able to CSE the second load of opening.  */
+ 
+ /* { dg-final { scan-tree-dump "Replaced opening" "fre1" } } */
+ /* { dg-final { cleanup-tree-dump "fre1" } } */

Reply via email to