OSDN Git Service

2006-09-28 Steven G. Kargl <kargl@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-ccp.c
index c428ef0..8c31a86 100644 (file)
@@ -1,5 +1,5 @@
 /* Conditional constant propagation pass for the GNU compiler.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
    Adapted from original RTL SSA-CCP by Daniel Berlin <dberlin@dberlin.org>
    Adapted to GIMPLE trees by Diego Novillo <dnovillo@redhat.com>
@@ -855,11 +855,19 @@ ccp_fold (tree stmt)
       /* If the RHS is a memory load, see if the VUSEs associated with
         it are a valid constant for that memory load.  */
       prop_value_t *val = get_value_loaded_by (stmt, const_val);
-      if (val && val->mem_ref
-         && operand_equal_p (val->mem_ref, rhs, 0))
-       return val->value;
-      else
-       return NULL_TREE;
+      if (val && val->mem_ref)
+       {
+         if (operand_equal_p (val->mem_ref, rhs, 0))
+           return val->value;
+
+         /* If RHS is extracting REALPART_EXPR or IMAGPART_EXPR of a
+            complex type with a known constant value, return it.  */
+         if ((TREE_CODE (rhs) == REALPART_EXPR
+              || TREE_CODE (rhs) == IMAGPART_EXPR)
+             && operand_equal_p (val->mem_ref, TREE_OPERAND (rhs, 0), 0))
+           return fold_build1 (TREE_CODE (rhs), TREE_TYPE (rhs), val->value);
+       }
+      return NULL_TREE;
     }
 
   /* Unary operators.  Note that we know the single operand must
@@ -1003,7 +1011,8 @@ fold_const_aggregate_ref (tree t)
        }
 
       if (ctor == NULL_TREE
-         || TREE_CODE (ctor) != CONSTRUCTOR
+         || (TREE_CODE (ctor) != CONSTRUCTOR
+             && TREE_CODE (ctor) != STRING_CST)
          || !TREE_STATIC (ctor))
        return NULL_TREE;
 
@@ -1028,6 +1037,20 @@ fold_const_aggregate_ref (tree t)
          return NULL_TREE;
        }
 
+      /* Fold read from constant string.  */
+      if (TREE_CODE (ctor) == STRING_CST)
+       {
+         if ((TYPE_MODE (TREE_TYPE (t))
+              == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
+             && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
+                 == MODE_INT)
+             && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1
+             && compare_tree_int (idx, TREE_STRING_LENGTH (ctor)) < 0)
+           return build_int_cst (TREE_TYPE (t), (TREE_STRING_POINTER (ctor)
+                                                 [TREE_INT_CST_LOW (idx)]));
+         return NULL_TREE;
+       }
+
       /* Whoo-hoo!  I'll fold ya baby.  Yeah!  */
       FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval)
        if (tree_int_cst_equal (cfield, idx))
@@ -1096,7 +1119,7 @@ static prop_value_t
 evaluate_stmt (tree stmt)
 {
   prop_value_t val;
-  tree simplified;
+  tree simplified = NULL_TREE;
   ccp_lattice_t likelyvalue = likely_value (stmt);
 
   val.mem_ref = NULL_TREE;
@@ -1107,14 +1130,14 @@ evaluate_stmt (tree stmt)
     simplified = ccp_fold (stmt);
   /* If the statement is likely to have a VARYING result, then do not
      bother folding the statement.  */
-  else if (likelyvalue == VARYING)
+  if (likelyvalue == VARYING)
     simplified = get_rhs (stmt);
   /* If the statement is an ARRAY_REF or COMPONENT_REF into constant
      aggregates, extract the referenced constant.  Otherwise the
      statement is likely to have an UNDEFINED value, and there will be
      nothing to do.  Note that fold_const_aggregate_ref returns
      NULL_TREE if the first case does not match.  */
-  else
+  else if (!simplified)
     simplified = fold_const_aggregate_ref (get_rhs (stmt));
 
   if (simplified && is_gimple_min_invariant (simplified))
@@ -1191,9 +1214,9 @@ visit_assignment (tree stmt, tree *output_p)
     if (TREE_CODE (orig_lhs) == VIEW_CONVERT_EXPR
        && val.lattice_val == CONSTANT)
       {
-       tree w = fold_build1 (VIEW_CONVERT_EXPR,
-                             TREE_TYPE (TREE_OPERAND (orig_lhs, 0)),
-                             val.value);
+       tree w = fold_unary (VIEW_CONVERT_EXPR,
+                            TREE_TYPE (TREE_OPERAND (orig_lhs, 0)),
+                            val.value);
 
        orig_lhs = TREE_OPERAND (orig_lhs, 0);
        if (w && is_gimple_min_invariant (w))
@@ -1370,10 +1393,11 @@ execute_ssa_ccp (bool store_ccp)
 }
 
 
-static void
+static unsigned int
 do_ssa_ccp (void)
 {
   execute_ssa_ccp (false);
+  return 0;
 }
 
 
@@ -1395,20 +1419,21 @@ struct tree_opt_pass pass_ccp =
   TV_TREE_CCP,                         /* tv_id */
   PROP_cfg | PROP_ssa | PROP_alias,    /* properties_required */
   0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
+  PROP_smt_usage,                      /* properties_destroyed */
   0,                                   /* todo_flags_start */
   TODO_cleanup_cfg | TODO_dump_func | TODO_update_ssa
     | TODO_ggc_collect | TODO_verify_ssa
-    | TODO_verify_stmts,               /* todo_flags_finish */
+    | TODO_verify_stmts | TODO_update_smt_usage, /* todo_flags_finish */
   0                                    /* letter */
 };
 
 
-static void
+static unsigned int
 do_ssa_store_ccp (void)
 {
   /* If STORE-CCP is not enabled, we just run regular CCP.  */
   execute_ssa_ccp (flag_tree_store_ccp != 0);
+  return 0;
 }
 
 static bool
@@ -1432,12 +1457,12 @@ struct tree_opt_pass pass_store_ccp =
   TV_TREE_STORE_CCP,                   /* tv_id */
   PROP_cfg | PROP_ssa | PROP_alias,    /* properties_required */
   0,                                   /* properties_provided */
-  0,                                   /* properties_destroyed */
+  PROP_smt_usage,                      /* properties_destroyed */
   0,                                   /* todo_flags_start */
   TODO_dump_func | TODO_update_ssa
     | TODO_ggc_collect | TODO_verify_ssa
     | TODO_cleanup_cfg
-    | TODO_verify_stmts,               /* todo_flags_finish */
+    | TODO_verify_stmts | TODO_update_smt_usage, /* todo_flags_finish */
   0                                    /* letter */
 };
 
@@ -1869,7 +1894,7 @@ maybe_fold_stmt_addition (tree expr)
              if (TREE_CODE (min_idx) != INTEGER_CST)
                break;
 
-             array_idx = convert (TREE_TYPE (min_idx), array_idx);
+             array_idx = fold_convert (TREE_TYPE (min_idx), array_idx);
              if (!integer_zerop (min_idx))
                array_idx = int_const_binop (MINUS_EXPR, array_idx,
                                             min_idx, 0);
@@ -1877,7 +1902,7 @@ maybe_fold_stmt_addition (tree expr)
        }
 
       /* Convert the index to a byte offset.  */
-      array_idx = convert (sizetype, array_idx);
+      array_idx = fold_convert (sizetype, array_idx);
       array_idx = int_const_binop (MULT_EXPR, array_idx, elt_size, 0);
 
       /* Update the operands for the next round, or for folding.  */
@@ -1901,9 +1926,9 @@ maybe_fold_stmt_addition (tree expr)
     {
       if (TYPE_UNSIGNED (TREE_TYPE (op1)))
        return NULL;
-      op1 = fold_build1 (NEGATE_EXPR, TREE_TYPE (op1), op1);
+      op1 = fold_unary (NEGATE_EXPR, TREE_TYPE (op1), op1);
       /* ??? In theory fold should always produce another integer.  */
-      if (TREE_CODE (op1) != INTEGER_CST)
+      if (op1 == NULL || TREE_CODE (op1) != INTEGER_CST)
        return NULL;
     }
 
@@ -2018,6 +2043,18 @@ fold_stmt_r (tree *expr_p, int *walk_subtrees, void *data)
       t = maybe_fold_tmr (expr);
       break;
 
+    case COND_EXPR:
+      if (COMPARISON_CLASS_P (TREE_OPERAND (expr, 0)))
+        {
+         tree op0 = TREE_OPERAND (expr, 0);
+          tree tem = fold_binary (TREE_CODE (op0), TREE_TYPE (op0),
+                                 TREE_OPERAND (op0, 0), TREE_OPERAND (op0, 1));
+         if (tem && is_gimple_condexpr (tem))
+           TREE_OPERAND (expr, 0) = tem;
+         t = expr;
+          break;
+        }
+
     default:
       return NULL_TREE;
     }
@@ -2350,7 +2387,9 @@ fold_stmt (tree *stmt_p)
          /* ??? Should perhaps do this in fold proper.  However, doing it
             there requires that we create a new CALL_EXPR, and that requires
             copying EH region info to the new node.  Easier to just do it
-            here where we can just smash the call operand.  */
+            here where we can just smash the call operand. Also
+            CALL_EXPR_RETURN_SLOT_OPT needs to be handled correctly and
+            copied, fold_ternary does not have not information. */
          callee = TREE_OPERAND (rhs, 0);
          if (TREE_CODE (callee) == OBJ_TYPE_REF
              && lang_hooks.fold_obj_type_ref
@@ -2459,7 +2498,7 @@ convert_to_gimple_builtin (block_stmt_iterator *si_p, tree expr)
 /* 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
+static unsigned int
 execute_fold_all_builtins (void)
 {
   bool cfg_changed = false;
@@ -2551,6 +2590,7 @@ execute_fold_all_builtins (void)
   /* Delete unreachable blocks.  */
   if (cfg_changed)
     cleanup_tree_cfg ();
+  return 0;
 }