OSDN Git Service

* config/rs6000/rs6000.md (andsi3): Add attribute "compare" for
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-ccp.c
index ddde45d..3e8fa7b 100644 (file)
@@ -135,7 +135,14 @@ get_default_value (tree var)
   val.lattice_val = UNDEFINED;
   val.const_val = NULL_TREE;
 
-  if (TREE_CODE (sym) == PARM_DECL || TREE_THIS_VOLATILE (sym))
+  if (TREE_CODE (var) == SSA_NAME
+      && SSA_NAME_VALUE (var)
+      && is_gimple_min_invariant (SSA_NAME_VALUE (var)))
+    {
+      val.lattice_val = CONSTANT;
+      val.const_val = SSA_NAME_VALUE (var);
+    }
+  else if (TREE_CODE (sym) == PARM_DECL || TREE_THIS_VOLATILE (sym))
     {
       /* Function arguments and volatile variables are considered VARYING.  */
       val.lattice_val = VARYING;
@@ -219,8 +226,8 @@ set_lattice_value (tree var, value val)
   else if (val.lattice_val == CONSTANT)
     /* VARYING -> CONSTANT is an invalid state transition, except
        for objects which start off in a VARYING state.  */
-    gcc_assert (old->lattice_val == VARYING
-               || get_default_value (var).lattice_val != VARYING);
+    gcc_assert (old->lattice_val != VARYING
+               || get_default_value (var).lattice_val == VARYING);
 
   /* If the constant for VAR has changed, then this VAR is really varying.  */
   if (old->lattice_val == CONSTANT
@@ -447,16 +454,21 @@ replace_uses_in (tree stmt, bool *replaced_addresses_p)
 
   FOR_EACH_SSA_USE_OPERAND (use, stmt, iter, SSA_OP_USE)
     {
-      value *val = get_value (USE_FROM_PTR (use));
+      tree tuse = USE_FROM_PTR (use);
+      value *val = get_value (tuse);
 
-      if (val->lattice_val == CONSTANT)
-       {
-         SET_USE (use, val->const_val);
-         replaced = true;
-         if (POINTER_TYPE_P (TREE_TYPE (USE_FROM_PTR (use))) 
-             && replaced_addresses_p)
-           *replaced_addresses_p = true;
-       }
+      if (val->lattice_val != CONSTANT)
+       continue;
+
+      if (TREE_CODE (stmt) == ASM_EXPR
+         && !may_propagate_copy_into_asm (tuse))
+       continue;
+
+      SET_USE (use, val->const_val);
+
+      replaced = true;
+      if (POINTER_TYPE_P (TREE_TYPE (tuse)) && replaced_addresses_p)
+       *replaced_addresses_p = true;
     }
 
   return replaced;
@@ -512,6 +524,7 @@ static void
 substitute_and_fold (void)
 {
   basic_block bb;
+  unsigned int i;
 
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file,
@@ -586,6 +599,25 @@ substitute_and_fold (void)
            }
        }
     }
+
+  /* And transfer what we learned from VALUE_VECTOR into the
+     SSA_NAMEs themselves.  This probably isn't terribly important
+     since we probably constant propagated the values to their
+     use sites above.  */
+  for (i = 0; i < num_ssa_names; i++)
+    {
+      tree name = ssa_name (i);
+      value *value;
+
+      if (!name)
+       continue;
+
+      value = get_value (name);
+      if (value->lattice_val == CONSTANT
+          && is_gimple_reg (name)
+         && is_gimple_min_invariant (value->const_val))
+       SSA_NAME_VALUE (name) = value->const_val;
+    }
 }
 
 
@@ -787,7 +819,7 @@ ccp_fold (tree stmt)
 {
   tree rhs = get_rhs (stmt);
   enum tree_code code = TREE_CODE (rhs);
-  int kind = TREE_CODE_CLASS (code);
+  enum tree_code_class kind = TREE_CODE_CLASS (code);
   tree retval = NULL_TREE;
   vuse_optype vuses;
   
@@ -805,7 +837,7 @@ ccp_fold (tree stmt)
   /* Unary operators.  Note that we know the single operand must
      be a constant.  So this should almost always return a
      simplified RHS.  */
-  if (kind == '1')
+  if (kind == tcc_unary)
     {
       /* Handle unary operators which can appear in GIMPLE form.  */
       tree op0 = TREE_OPERAND (rhs, 0);
@@ -845,8 +877,8 @@ ccp_fold (tree stmt)
 
   /* Binary and comparison operators.  We know one or both of the
      operands are constants.  */
-  else if (kind == '2'
-           || kind == '<'
+  else if (kind == tcc_binary
+           || kind == tcc_comparison
            || code == TRUTH_AND_EXPR
            || code == TRUTH_OR_EXPR
            || code == TRUTH_XOR_EXPR)
@@ -1368,7 +1400,7 @@ static tree
 maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset,
                                    tree orig_type, bool base_is_ptr)
 {
-  tree f, t, field_type, tail_array_field;
+  tree f, t, field_type, tail_array_field, field_offset;
 
   if (TREE_CODE (record_type) != RECORD_TYPE
       && TREE_CODE (record_type) != UNION_TYPE
@@ -1388,7 +1420,9 @@ maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset,
        continue;
       if (DECL_BIT_FIELD (f))
        continue;
-      if (TREE_CODE (DECL_FIELD_OFFSET (f)) != INTEGER_CST)
+
+      field_offset = byte_position (f);
+      if (TREE_CODE (field_offset) != INTEGER_CST)
        continue;
 
       /* ??? Java creates "interesting" fields for representing base classes.
@@ -1401,7 +1435,7 @@ maybe_fold_offset_to_component_ref (tree record_type, tree base, tree offset,
       tail_array_field = NULL_TREE;
 
       /* Check to see if this offset overlaps with the field.  */
-      cmp = tree_int_cst_compare (DECL_FIELD_OFFSET (f), offset);
+      cmp = tree_int_cst_compare (field_offset, offset);
       if (cmp > 0)
        continue;
 
@@ -2035,7 +2069,8 @@ fold_stmt (tree *stmt_p)
          if (TREE_CODE (callee) == OBJ_TYPE_REF
              && lang_hooks.fold_obj_type_ref
              && TREE_CODE (OBJ_TYPE_REF_OBJECT (callee)) == ADDR_EXPR
-             && DECL_P (TREE_OPERAND (OBJ_TYPE_REF_OBJECT (callee), 0)))
+             && DECL_P (TREE_OPERAND
+                        (OBJ_TYPE_REF_OBJECT (callee), 0)))
            {
              tree t;
 
@@ -2071,12 +2106,44 @@ fold_stmt (tree *stmt_p)
 }
 
 \f
+/* Convert EXPR into a GIMPLE value suitable for substitution on the
+   RHS of an assignment.  Insert the necessary statements before
+   iterator *SI_P.  */
+
+static tree
+convert_to_gimple_builtin (block_stmt_iterator *si_p, tree expr)
+{
+  tree_stmt_iterator ti;
+  tree stmt = bsi_stmt (*si_p);
+  tree tmp, stmts = NULL;
+
+  push_gimplify_context ();
+  tmp = get_initialized_tmp_var (expr, &stmts, NULL);
+  pop_gimplify_context (NULL);
+
+  /* The replacement can expose previously unreferenced variables.  */
+  for (ti = tsi_start (stmts); !tsi_end_p (ti); tsi_next (&ti))
+    {
+      find_new_referenced_vars (tsi_stmt_ptr (ti));
+      mark_new_vars_to_rename (tsi_stmt (ti), vars_to_rename);
+    }
+
+  if (EXPR_HAS_LOCATION (stmt))
+    annotate_all_with_locus (&stmts, EXPR_LOCATION (stmt));
+
+  bsi_insert_before (si_p, stmts, BSI_SAME_STMT);
+
+  return tmp;
+}
+
+
 /* A simple pass that attempts to fold all builtin functions.  This pass
    is run after we've propagated as many constants as we can.  */
 
 static void
 execute_fold_all_builtins (void)
 {
+  bool cfg_changed = false;
   basic_block bb;
   FOR_EACH_BB (bb)
     {
@@ -2114,8 +2181,16 @@ execute_fold_all_builtins (void)
              print_generic_stmt (dump_file, *stmtp, dump_flags);
            }
 
-         if (set_rhs (stmtp, result))
-           modify_stmt (*stmtp);
+         if (!set_rhs (stmtp, result))
+           {
+             result = convert_to_gimple_builtin (&i, result);
+             if (result && !set_rhs (stmtp, result))
+               abort ();
+           }
+         modify_stmt (*stmtp);
+         if (maybe_clean_eh_stmt (*stmtp)
+             && tree_purge_dead_eh_edges (bb))
+           cfg_changed = true;
 
          if (dump_file && (dump_flags & TDF_DETAILS))
            {
@@ -2125,6 +2200,10 @@ execute_fold_all_builtins (void)
            }
        }
     }
+
+  /* Delete unreachable blocks.  */
+  if (cfg_changed)
+    cleanup_tree_cfg ();
 }
 
 
@@ -2141,6 +2220,8 @@ struct tree_opt_pass pass_fold_builtins =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_verify_ssa,    /* todo_flags_finish */
+  TODO_dump_func
+    | TODO_verify_ssa
+    | TODO_rename_vars,                        /* todo_flags_finish */
   0                                    /* letter */
 };