OSDN Git Service

2010-04-08 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-forwprop.c
index 6ba800d..f729506 100644 (file)
@@ -1,5 +1,6 @@
 /* Forward propagation of expressions for single use variables.
-   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -21,13 +22,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "ggc.h"
 #include "tree.h"
-#include "rtl.h"
 #include "tm_p.h"
 #include "basic-block.h"
 #include "timevar.h"
 #include "diagnostic.h"
+#include "tree-pretty-print.h"
 #include "tree-flow.h"
 #include "tree-pass.h"
 #include "tree-dump.h"
@@ -41,7 +41,7 @@ along with GCC; see the file COPYING3.  If not see
    when we have a generalized tree combiner.
 
    One class of common cases we handle is forward propagating a single use
-   variable into a COND_EXPR.  
+   variable into a COND_EXPR.
 
      bb0:
        x = a COND b;
@@ -51,13 +51,13 @@ along with GCC; see the file COPYING3.  If not see
 
      bb0:
        if (a COND b) goto ... else goto ...
+
    Similarly for the tests (x == 0), (x != 0), (x == 1) and (x != 1).
 
    Or (assuming c1 and c2 are constants):
 
      bb0:
-       x = a + c1;  
+       x = a + c1;
        if (x EQ/NEQ c2) goto ... else goto ...
 
    Will be transformed into:
@@ -66,7 +66,7 @@ along with GCC; see the file COPYING3.  If not see
         if (a EQ/NEQ (c2 - c1)) goto ... else goto ...
 
    Similarly for x = a - c1.
-    
+
    Or
 
      bb0:
@@ -331,7 +331,7 @@ remove_prop_source_from_use (tree name, gimple up_to_stmt)
 
 /* Return the rhs of a gimple_assign STMT in a form of a single tree,
    converted to type TYPE.
-   
+
    This should disappear, but is needed so we can combine expressions and use
    the fold() interfaces. Long term, we need to develop folding and combine
    routines that deal with gimple exclusively . */
@@ -387,36 +387,38 @@ combine_cond_expr_cond (location_t loc, enum tree_code code, tree type,
    in GIMPLE_COND statement STMT into the conditional if that simplifies it.
    Returns zero if no statement was changed, one if there were
    changes and two if cfg_cleanup needs to run.
-   
+
    This must be kept in sync with forward_propagate_into_cond.  */
 
 static int
 forward_propagate_into_gimple_cond (gimple stmt)
 {
   int did_something = 0;
-  location_t loc = gimple_location (stmt); 
+  location_t loc = gimple_location (stmt);
 
   do {
     tree tmp = NULL_TREE;
-    tree name, rhs0 = NULL_TREE, rhs1 = NULL_TREE;
+    tree name = NULL_TREE, rhs0 = NULL_TREE, rhs1 = NULL_TREE;
     gimple def_stmt;
     bool single_use0_p = false, single_use1_p = false;
     enum tree_code code = gimple_cond_code (stmt);
 
     /* We can do tree combining on SSA_NAME and comparison expressions.  */
-    if (TREE_CODE_CLASS (gimple_cond_code (stmt)) == tcc_comparison
-        && TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME)
+    if (TREE_CODE_CLASS (gimple_cond_code (stmt)) == tcc_comparison)
       {
        /* For comparisons use the first operand, that is likely to
           simplify comparisons against constants.  */
-       name = gimple_cond_lhs (stmt);
-       def_stmt = get_prop_source_stmt (name, false, &single_use0_p);
-       if (def_stmt && can_propagate_from (def_stmt))
+       if (TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME)
          {
-           tree op1 = gimple_cond_rhs (stmt);
-           rhs0 = rhs_to_tree (TREE_TYPE (op1), def_stmt);
-           tmp = combine_cond_expr_cond (loc, code, boolean_type_node, rhs0,
-                                         op1, !single_use0_p);
+           name = gimple_cond_lhs (stmt);
+           def_stmt = get_prop_source_stmt (name, false, &single_use0_p);
+           if (def_stmt && can_propagate_from (def_stmt))
+             {
+               tree op1 = gimple_cond_rhs (stmt);
+               rhs0 = rhs_to_tree (TREE_TYPE (op1), def_stmt);
+               tmp = combine_cond_expr_cond (loc, code, boolean_type_node,
+                                             rhs0, op1, !single_use0_p);
+             }
          }
        /* If that wasn't successful, try the second operand.  */
        if (tmp == NULL_TREE
@@ -590,7 +592,7 @@ forward_propagate_into_cond (gimple_stmt_iterator *gsi_p)
   return did_something;
 }
 
-/* We've just substituted an ADDR_EXPR into stmt.  Update all the 
+/* We've just substituted an ADDR_EXPR into stmt.  Update all the
    relevant data structures to match.  */
 
 static void
@@ -657,7 +659,7 @@ forward_propagate_addr_into_variable_array_index (tree offset,
        return false;
 
       /* The RHS of the statement which defines OFFSET must be a
-        multiplication of an object by the size of the array elements. 
+        multiplication of an object by the size of the array elements.
         This implicitly verifies that the size of the array elements
         is constant.  */
      if (gimple_assign_rhs_code (offset_def) == MULT_EXPR
@@ -728,6 +730,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
   gimple use_stmt = gsi_stmt (*use_stmt_gsi);
   enum tree_code rhs_code;
   bool res = true;
+  bool addr_p = false;
 
   gcc_assert (TREE_CODE (def_rhs) == ADDR_EXPR);
 
@@ -765,14 +768,14 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
       return true;
     }
 
-  /* Now strip away any outer COMPONENT_REF/ARRAY_REF nodes from the LHS. 
+  /* Now strip away any outer COMPONENT_REF/ARRAY_REF nodes from the LHS.
      ADDR_EXPR will not appear on the LHS.  */
   lhsp = gimple_assign_lhs_ptr (use_stmt);
   while (handled_component_p (*lhsp))
     lhsp = &TREE_OPERAND (*lhsp, 0);
   lhs = *lhsp;
 
-  /* Now see if the LHS node is an INDIRECT_REF using NAME.  If so, 
+  /* Now see if the LHS node is an INDIRECT_REF using NAME.  If so,
      propagate the ADDR_EXPR into the use of NAME and fold the result.  */
   if (TREE_CODE (lhs) == INDIRECT_REF
       && TREE_OPERAND (lhs, 0) == name)
@@ -800,8 +803,12 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
   /* Strip away any outer COMPONENT_REF, ARRAY_REF or ADDR_EXPR
      nodes from the RHS.  */
   rhsp = gimple_assign_rhs1_ptr (use_stmt);
-  while (handled_component_p (*rhsp)
-        || TREE_CODE (*rhsp) == ADDR_EXPR)
+  if (TREE_CODE (*rhsp) == ADDR_EXPR)
+    {
+      rhsp = &TREE_OPERAND (*rhsp, 0);
+      addr_p = true;
+    }
+  while (handled_component_p (*rhsp))
     rhsp = &TREE_OPERAND (*rhsp, 0);
   rhs = *rhsp;
 
@@ -817,7 +824,7 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
       return res;
     }
 
-  /* Now see if the RHS node is an INDIRECT_REF using NAME.  If so, 
+  /* Now see if the RHS node is an INDIRECT_REF using NAME.  If so,
      propagate the ADDR_EXPR into the use of NAME and try to
      create a VCE and fold the result.  */
   if (TREE_CODE (rhs) == INDIRECT_REF
@@ -850,11 +857,14 @@ forward_propagate_addr_expr_1 (tree name, tree def_rhs,
         return res;
        }
      /* If the defining rhs comes from an indirect reference, then do not
-        convert into a VIEW_CONVERT_EXPR.  */
+        convert into a VIEW_CONVERT_EXPR.  Likewise if we'll end up taking
+       the address of a V_C_E of a constant.  */
      def_rhs_base = TREE_OPERAND (def_rhs, 0);
      while (handled_component_p (def_rhs_base))
        def_rhs_base = TREE_OPERAND (def_rhs_base, 0);
-     if (!INDIRECT_REF_P (def_rhs_base))
+     if (!INDIRECT_REF_P (def_rhs_base)
+        && (!addr_p
+            || !is_gimple_min_invariant (def_rhs)))
        {
         /* We may have arbitrary VIEW_CONVERT_EXPRs in a nested component
            reference.  Place it there and fold the thing.  */
@@ -955,9 +965,10 @@ forward_propagate_addr_expr (tree name, tree rhs)
        }
 
       /* If the use is in a deeper loop nest, then we do not want
-        to propagate the ADDR_EXPR into the loop as that is likely
-        adding expression evaluations into the loop.  */
-      if (gimple_bb (use_stmt)->loop_depth > stmt_loop_depth)
+        to propagate non-invariant ADDR_EXPRs into the loop as that
+        is likely adding expression evaluations into the loop.  */
+      if (gimple_bb (use_stmt)->loop_depth > stmt_loop_depth
+         && !is_gimple_min_invariant (rhs))
        {
          all = false;
          continue;
@@ -1107,9 +1118,9 @@ forward_propagate_comparison (gimple stmt)
 
 /* If we have lhs = ~x (STMT), look and see if earlier we had x = ~y.
    If so, we can change STMT into lhs = y which can later be copy
-   propagated.  Similarly for negation. 
+   propagated.  Similarly for negation.
 
-   This could trivially be formulated as a forward propagation 
+   This could trivially be formulated as a forward propagation
    to immediate uses.  However, we already had an implementation
    from DOM which used backward propagation via the use-def links.
 
@@ -1372,7 +1383,7 @@ gate_forwprop (void)
   return flag_tree_forwprop;
 }
 
-struct gimple_opt_pass pass_forwprop = 
+struct gimple_opt_pass pass_forwprop =
 {
  {
   GIMPLE_PASS,