OSDN Git Service

* tree-ssa.c (find_released_ssa_name): Handle NULL wi.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-ccp.c
index 5e30588..76ea0e4 100644 (file)
@@ -229,6 +229,7 @@ typedef enum
 static prop_value_t *const_val;
 
 static void canonicalize_float_value (prop_value_t *);
+static bool ccp_fold_stmt (gimple_stmt_iterator *);
 
 /* Dump constant propagation value VAL to file OUTF prefixed by PREFIX.  */
 
@@ -724,7 +725,7 @@ ccp_finalize (void)
 
   do_dbg_cnt ();
   /* Perform substitutions based on the known constant values.  */
-  something_changed = substitute_and_fold (const_val, NULL);
+  something_changed = substitute_and_fold (const_val, ccp_fold_stmt);
 
   free (const_val);
   const_val = NULL;
@@ -1423,8 +1424,8 @@ evaluate_stmt (gimple stmt)
       else if (code == GIMPLE_SWITCH)
         simplified = gimple_switch_index (stmt);
       else
-        /* These cannot satisfy is_gimple_min_invariant without folding.  */
-        gcc_assert (code == GIMPLE_CALL || code == GIMPLE_COND);
+       /* These cannot satisfy is_gimple_min_invariant without folding.  */
+       gcc_assert (code == GIMPLE_CALL || code == GIMPLE_COND);
     }
 
   is_constant = simplified && is_gimple_min_invariant (simplified);
@@ -1472,6 +1473,34 @@ evaluate_stmt (gimple stmt)
   return val;
 }
 
+/* Fold the stmt at *GSI with CCP specific information that propagating
+   and regular folding does not catch.  */
+
+static bool
+ccp_fold_stmt (gimple_stmt_iterator *gsi)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  prop_value_t val;
+
+  if (gimple_code (stmt) != GIMPLE_COND)
+    return false;
+
+  /* Statement evaluation will handle type mismatches in constants
+     more gracefully than the final propagation.  This allows us to
+     fold more conditionals here.  */
+  val = evaluate_stmt (stmt);
+  if (val.lattice_val != CONSTANT
+      || TREE_CODE (val.value) != INTEGER_CST)
+    return false;
+
+  if (integer_zerop (val.value))
+    gimple_cond_make_false (stmt);
+  else 
+    gimple_cond_make_true (stmt);
+
+  return true;
+}
+
 /* Visit the assignment statement STMT.  Set the value of its LHS to the
    value computed by the RHS and store LHS in *OUTPUT_P.  If STMT
    creates virtual definitions, set the value of each new name to that
@@ -2866,6 +2895,7 @@ fold_gimple_cond (gimple stmt)
   return false;
 }
 
+static void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree);
 
 /* Attempt to fold a call statement referenced by the statement iterator GSI.
    The statement may be replaced by another statement, e.g., if the call
@@ -2886,7 +2916,11 @@ fold_gimple_call (gimple_stmt_iterator *gsi)
       tree result = ccp_fold_builtin (stmt);
 
       if (result)
-        return update_call_from_tree (gsi, result);
+       {
+          if (!update_call_from_tree (gsi, result))
+           gimplify_and_update_call_from_tree (gsi, result);
+         return true;
+       }
     }
   else
     {
@@ -3060,9 +3094,8 @@ fold_stmt_inplace (gimple stmt)
 static tree
 optimize_stack_restore (gimple_stmt_iterator i)
 {
-  tree callee, rhs;
-  gimple stmt, stack_save;
-  gimple_stmt_iterator stack_save_gsi;
+  tree callee;
+  gimple stmt;
 
   basic_block bb = gsi_bb (i);
   gimple call = gsi_stmt (i);
@@ -3086,32 +3119,49 @@ optimize_stack_restore (gimple_stmt_iterator i)
        return NULL_TREE;
 
       if (DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_RESTORE)
-       break;
+       goto second_stack_restore;
     }
 
-  if (gsi_end_p (i)
-      && (! single_succ_p (bb)
-         || single_succ_edge (bb)->dest != EXIT_BLOCK_PTR))
+  if (!gsi_end_p (i))
     return NULL_TREE;
 
-  stack_save = SSA_NAME_DEF_STMT (gimple_call_arg (call, 0));
-  if (gimple_code (stack_save) != GIMPLE_CALL
-      || gimple_call_lhs (stack_save) != gimple_call_arg (call, 0)
-      || stmt_could_throw_p (stack_save)
-      || !has_single_use (gimple_call_arg (call, 0)))
-    return NULL_TREE;
+  /* Allow one successor of the exit block, or zero successors.  */
+  switch (EDGE_COUNT (bb->succs))
+    {
+    case 0:
+      break;
+    case 1:
+      if (single_succ_edge (bb)->dest != EXIT_BLOCK_PTR)
+       return NULL_TREE;
+      break;
+    default:
+      return NULL_TREE;
+    }
+ second_stack_restore:
 
-  callee = gimple_call_fndecl (stack_save);
-  if (!callee
-      || DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL
-      || DECL_FUNCTION_CODE (callee) != BUILT_IN_STACK_SAVE
-      || gimple_call_num_args (stack_save) != 0)
-    return NULL_TREE;
+  /* If there's exactly one use, then zap the call to __builtin_stack_save.
+     If there are multiple uses, then the last one should remove the call.
+     In any case, whether the call to __builtin_stack_save can be removed
+     or not is irrelevant to removing the call to __builtin_stack_restore.  */
+  if (has_single_use (gimple_call_arg (call, 0)))
+    {
+      gimple stack_save = SSA_NAME_DEF_STMT (gimple_call_arg (call, 0));
+      if (is_gimple_call (stack_save))
+       {
+         callee = gimple_call_fndecl (stack_save);
+         if (callee
+             && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
+             && DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_SAVE)
+           {
+             gimple_stmt_iterator stack_save_gsi;
+             tree rhs;
 
-  stack_save_gsi = gsi_for_stmt (stack_save);
-  rhs = build_int_cst (TREE_TYPE (gimple_call_arg (call, 0)), 0);
-  if (!update_call_from_tree (&stack_save_gsi, rhs))
-    return NULL_TREE;
+             stack_save_gsi = gsi_for_stmt (stack_save);
+             rhs = build_int_cst (TREE_TYPE (gimple_call_arg (call, 0)), 0);
+             update_call_from_tree (&stack_save_gsi, rhs);
+           }
+       }
+    }
 
   /* No effect, so the statement will be deleted.  */
   return integer_zero_node;