OSDN Git Service

2009-05-12 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-sccvn.c
index 8abc306..b101aeb 100644 (file)
@@ -257,9 +257,10 @@ vn_get_expr_for (tree name)
   switch (TREE_CODE_CLASS (gimple_assign_rhs_code (def_stmt)))
     {
     case tcc_reference:
-      if (gimple_assign_rhs_code (def_stmt) == VIEW_CONVERT_EXPR
-         || gimple_assign_rhs_code (def_stmt) == REALPART_EXPR
-         || gimple_assign_rhs_code (def_stmt) == IMAGPART_EXPR)
+      if ((gimple_assign_rhs_code (def_stmt) == VIEW_CONVERT_EXPR
+          || gimple_assign_rhs_code (def_stmt) == REALPART_EXPR
+          || gimple_assign_rhs_code (def_stmt) == IMAGPART_EXPR)
+         && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME)
        expr = fold_build1 (gimple_assign_rhs_code (def_stmt),
                            gimple_expr_type (def_stmt),
                            TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0));
@@ -744,37 +745,70 @@ create_reference_ops_from_call (gimple call)
   return result;
 }
 
-static VEC(vn_reference_op_s, heap) *shared_lookup_references;
-
-/* Create a vector of vn_reference_op_s structures from REF, a
-   REFERENCE_CLASS_P tree.  The vector is shared among all callers of
-   this function.  */
-
-static VEC(vn_reference_op_s, heap) *
-shared_reference_ops_from_ref (tree ref)
+/* Fold *& at position *I_P in a vn_reference_op_s vector *OPS.  Updates
+   *I_P to point to the last element of the replacement.  */
+void
+vn_reference_fold_indirect (VEC (vn_reference_op_s, heap) **ops,
+                           unsigned int *i_p)
 {
-  if (!ref)
-    return NULL;
-  VEC_truncate (vn_reference_op_s, shared_lookup_references, 0);
-  copy_reference_ops_from_ref (ref, &shared_lookup_references);
-  return shared_lookup_references;
-}
-
-/* Create a vector of vn_reference_op_s structures from CALL, a
-   call statement.  The vector is shared among all callers of
-   this function.  */
+  VEC(vn_reference_op_s, heap) *mem = NULL;
+  vn_reference_op_t op;
+  unsigned int i = *i_p;
+  unsigned int j;
+
+  /* Get ops for the addressed object.  */
+  op = VEC_index (vn_reference_op_s, *ops, i);
+  /* ???  If this is our usual typeof &ARRAY vs. &ARRAY[0] problem, work
+     around it to avoid later ICEs.  */
+  if (TREE_CODE (TREE_TYPE (TREE_OPERAND (op->op0, 0))) == ARRAY_TYPE
+      && TREE_CODE (TREE_TYPE (TREE_TYPE (op->op0))) != ARRAY_TYPE)
+    {
+      vn_reference_op_s aref;
+      tree dom;
+      aref.type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (op->op0)));
+      aref.opcode = ARRAY_REF;
+      aref.op0 = integer_zero_node;
+      if ((dom = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (op->op0, 0))))
+         && TYPE_MIN_VALUE (dom))
+       aref.op0 = TYPE_MIN_VALUE (dom);
+      aref.op1 = NULL_TREE;
+      aref.op2 = NULL_TREE;
+      VEC_safe_push (vn_reference_op_s, heap, mem, &aref);
+    }
+  copy_reference_ops_from_ref (TREE_OPERAND (op->op0, 0), &mem);
+
+  /* Do the replacement - we should have at least one op in mem now.  */
+  if (VEC_length (vn_reference_op_s, mem) == 1)
+    {
+      VEC_replace (vn_reference_op_s, *ops, i - 1,
+                  VEC_index (vn_reference_op_s, mem, 0));
+      VEC_ordered_remove (vn_reference_op_s, *ops, i);
+      i--;
+    }
+  else if (VEC_length (vn_reference_op_s, mem) == 2)
+    {
+      VEC_replace (vn_reference_op_s, *ops, i - 1,
+                  VEC_index (vn_reference_op_s, mem, 0));
+      VEC_replace (vn_reference_op_s, *ops, i,
+                  VEC_index (vn_reference_op_s, mem, 1));
+    }
+  else if (VEC_length (vn_reference_op_s, mem) > 2)
+    {
+      VEC_replace (vn_reference_op_s, *ops, i - 1,
+                  VEC_index (vn_reference_op_s, mem, 0));
+      VEC_replace (vn_reference_op_s, *ops, i,
+                  VEC_index (vn_reference_op_s, mem, 1));
+      /* ???  There is no VEC_splice.  */
+      for (j = 2; VEC_iterate (vn_reference_op_s, mem, j, op); j++)
+       VEC_safe_insert (vn_reference_op_s, heap, *ops, ++i, op);
+    }
+  else
+    gcc_unreachable ();
 
-static VEC(vn_reference_op_s, heap) *
-shared_reference_ops_from_call (gimple call)
-{
-  if (!call)
-    return NULL;
-  VEC_truncate (vn_reference_op_s, shared_lookup_references, 0);
-  copy_reference_ops_from_call (call, &shared_lookup_references);
-  return shared_lookup_references;
+  VEC_free (vn_reference_op_s, heap, mem);
+  *i_p = i;
 }
 
-
 /* Transform any SSA_NAME's in a vector of vn_reference_op_s
    structures into their value numbers.  This is done in-place, and
    the vector passed in is returned.  */
@@ -783,7 +817,7 @@ static VEC (vn_reference_op_s, heap) *
 valueize_refs (VEC (vn_reference_op_s, heap) *orig)
 {
   vn_reference_op_t vro;
-  int i;
+  unsigned int i;
 
   for (i = 0; VEC_iterate (vn_reference_op_s, orig, i, vro); i++)
     {
@@ -795,15 +829,57 @@ valueize_refs (VEC (vn_reference_op_s, heap) *orig)
             the opcode.  */
          if (TREE_CODE (vro->op0) != SSA_NAME && vro->opcode == SSA_NAME)
            vro->opcode = TREE_CODE (vro->op0);
+         /* If it transforms from an SSA_NAME to an address, fold with
+            a preceding indirect reference.  */
+         if (i > 0 && TREE_CODE (vro->op0) == ADDR_EXPR
+             && VEC_index (vn_reference_op_s,
+                           orig, i - 1)->opcode == INDIRECT_REF)
+           {
+             vn_reference_fold_indirect (&orig, &i);
+             continue;
+           }
        }
-      /* TODO: Do we want to valueize op2 and op1 of
-        ARRAY_REF/COMPONENT_REF for Ada */
-      
+      if (vro->op1 && TREE_CODE (vro->op1) == SSA_NAME)
+       vro->op1 = SSA_VAL (vro->op1);
+      if (vro->op2 && TREE_CODE (vro->op2) == SSA_NAME)
+       vro->op2 = SSA_VAL (vro->op2);
     }
 
   return orig;
 }
 
+static VEC(vn_reference_op_s, heap) *shared_lookup_references;
+
+/* Create a vector of vn_reference_op_s structures from REF, a
+   REFERENCE_CLASS_P tree.  The vector is shared among all callers of
+   this function.  */
+
+static VEC(vn_reference_op_s, heap) *
+valueize_shared_reference_ops_from_ref (tree ref)
+{
+  if (!ref)
+    return NULL;
+  VEC_truncate (vn_reference_op_s, shared_lookup_references, 0);
+  copy_reference_ops_from_ref (ref, &shared_lookup_references);
+  shared_lookup_references = valueize_refs (shared_lookup_references);
+  return shared_lookup_references;
+}
+
+/* Create a vector of vn_reference_op_s structures from CALL, a
+   call statement.  The vector is shared among all callers of
+   this function.  */
+
+static VEC(vn_reference_op_s, heap) *
+valueize_shared_reference_ops_from_call (gimple call)
+{
+  if (!call)
+    return NULL;
+  VEC_truncate (vn_reference_op_s, shared_lookup_references, 0);
+  copy_reference_ops_from_call (call, &shared_lookup_references);
+  shared_lookup_references = valueize_refs (shared_lookup_references);
+  return shared_lookup_references;
+}
+
 /* Lookup a SCCVN reference operation VR in the current hash table.
    Returns the resulting value number if it exists in the hash table,
    NULL_TREE otherwise.  VNRESULT will be filled in with the actual
@@ -914,7 +990,7 @@ vn_reference_lookup (tree op, tree vuse, bool maywalk,
     *vnresult = NULL;
 
   vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
-  vr1.operands = valueize_refs (shared_reference_ops_from_ref (op));
+  vr1.operands = valueize_shared_reference_ops_from_ref (op);
   vr1.hashcode = vn_reference_compute_hash (&vr1);
 
   if (maywalk
@@ -1585,7 +1661,7 @@ visit_reference_op_call (tree lhs, gimple stmt)
   tree vuse = gimple_vuse (stmt);
 
   vr1.vuse = vuse ? SSA_VAL (vuse) : NULL_TREE;
-  vr1.operands = valueize_refs (shared_reference_ops_from_call (stmt));
+  vr1.operands = valueize_shared_reference_ops_from_call (stmt);
   vr1.hashcode = vn_reference_compute_hash (&vr1);
   result = vn_reference_lookup_1 (&vr1, NULL);
   if (result)
@@ -2810,7 +2886,8 @@ run_scc_vn (bool may_insert_arg)
       if (!name)
        continue;
       info = VN_INFO (name);
-      if (info->valnum == name)
+      if (info->valnum == name
+         || info->valnum == VN_TOP)
        info->value_id = get_next_value_id ();
       else if (is_gimple_min_invariant (info->valnum))
        info->value_id = get_or_alloc_constant_value_id (info->valnum);