OSDN Git Service

2009-05-29 Kai Tietz <kai.tietz@onevision.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-pre.c
index c1cbe0c..fc311bc 100644 (file)
@@ -1252,12 +1252,12 @@ do_unary:
 
 static tree
 translate_vuse_through_block (VEC (vn_reference_op_s, heap) *operands,
-                             tree vuse,
+                             alias_set_type set, tree type, tree vuse,
                              basic_block phiblock,
                              basic_block block)
 {
   gimple phi = SSA_NAME_DEF_STMT (vuse);
-  tree ref;
+  ao_ref ref;
 
   if (gimple_bb (phi) != phiblock)
     return vuse;
@@ -1268,13 +1268,13 @@ translate_vuse_through_block (VEC (vn_reference_op_s, heap) *operands,
       return PHI_ARG_DEF (phi, e->dest_idx);
     }
 
-  if (!(ref = get_ref_from_reference_ops (operands)))
+  if (!ao_ref_init_from_vn_reference (&ref, set, type, operands))
     return NULL_TREE;
 
   /* Use the alias-oracle to find either the PHI node in this block,
      the first VUSE used in this block that is equivalent to vuse or
      the first VUSE which definition in this block kills the value.  */
-  while (!stmt_may_clobber_ref_p (phi, ref))
+  while (!stmt_may_clobber_ref_p_1 (phi, &ref))
     {
       vuse = gimple_vuse (phi);
       phi = SSA_NAME_DEF_STMT (vuse);
@@ -1317,23 +1317,7 @@ get_expr_type (const pre_expr e)
     case CONSTANT:
       return TREE_TYPE (PRE_EXPR_CONSTANT (e));
     case REFERENCE:
-      {
-       vn_reference_op_t vro;
-
-       gcc_assert (PRE_EXPR_REFERENCE (e)->operands);
-       vro = VEC_index (vn_reference_op_s,
-                        PRE_EXPR_REFERENCE (e)->operands,
-                        0);
-       /* We don't store type along with COMPONENT_REF because it is
-          always the same as FIELD_DECL's type.  */
-       if (!vro->type)
-         {
-           gcc_assert (vro->opcode == COMPONENT_REF);
-           return TREE_TYPE (vro->op0);
-         }
-       return vro->type;
-      }
-
+      return PRE_EXPR_REFERENCE (e)->type;
     case NARY:
       return PRE_EXPR_NARY (e)->type;
     }
@@ -1563,11 +1547,12 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
        tree newvuse = vuse;
        VEC (vn_reference_op_s, heap) *newoperands = NULL;
        bool changed = false;
-       unsigned int i;
+       unsigned int i, j;
        vn_reference_op_t operand;
        vn_reference_t newref;
 
-       for (i = 0; VEC_iterate (vn_reference_op_s, operands, i, operand); i++)
+       for (i = 0, j = 0;
+            VEC_iterate (vn_reference_op_s, operands, i, operand); i++, j++)
          {
            pre_expr opresult;
            pre_expr leader;
@@ -1642,7 +1627,13 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
            newop.op0 = op0;
            newop.op1 = op1;
            newop.op2 = op2;
-           VEC_replace (vn_reference_op_s, newoperands, i, &newop);
+           VEC_replace (vn_reference_op_s, newoperands, j, &newop);
+           /* If it transforms from an SSA_NAME to an address, fold with
+              a preceding indirect reference.  */
+           if (j > 0 && op0 && TREE_CODE (op0) == ADDR_EXPR
+               && VEC_index (vn_reference_op_s,
+                             newoperands, j - 1)->opcode == INDIRECT_REF)
+             vn_reference_fold_indirect (&newoperands, &j);
          }
        if (i != VEC_length (vn_reference_op_s, operands))
          {
@@ -1654,6 +1645,7 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
        if (vuse)
          {
            newvuse = translate_vuse_through_block (newoperands,
+                                                   ref->set, ref->type,
                                                    vuse, phiblock, pred);
            if (newvuse == NULL_TREE)
              {
@@ -1668,7 +1660,8 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
            unsigned int new_val_id;
            pre_expr constant;
 
-           tree result = vn_reference_lookup_pieces (newvuse,
+           tree result = vn_reference_lookup_pieces (newvuse, ref->set,
+                                                     ref->type,
                                                      newoperands,
                                                      &newref, true);
            if (newref)
@@ -1699,7 +1692,8 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
                new_val_id = get_next_value_id ();
                VEC_safe_grow_cleared (bitmap_set_t, heap, value_expressions,
                                       get_max_value_id() + 1);
-               newref = vn_reference_insert_pieces (newvuse,
+               newref = vn_reference_insert_pieces (newvuse, ref->set,
+                                                    ref->type,
                                                     newoperands,
                                                     result, new_val_id);
                newoperands = NULL;
@@ -1877,10 +1871,10 @@ value_dies_in_block_x (pre_expr expr, basic_block block)
   tree vuse = PRE_EXPR_REFERENCE (expr)->vuse;
   vn_reference_t refx = PRE_EXPR_REFERENCE (expr);
   gimple def;
-  tree ref = NULL_TREE;
   gimple_stmt_iterator gsi;
   unsigned id = get_expression_id (expr);
   bool res = false;
+  ao_ref ref;
 
   if (!vuse)
     return false;
@@ -1895,6 +1889,7 @@ value_dies_in_block_x (pre_expr expr, basic_block block)
      top of the basic block, a statement uses VUSE there can be no kill
      inbetween that use and the original statement that loaded {e, VUSE},
      so we can stop walking.  */
+  ref.base = NULL_TREE;
   for (gsi = gsi_start_bb (block); !gsi_end_p (gsi); gsi_next (&gsi))
     {
       tree def_vuse, def_vdef;
@@ -1917,16 +1912,15 @@ value_dies_in_block_x (pre_expr expr, basic_block block)
        }
 
       /* Init ref only if we really need it.  */
-      if (ref == NULL_TREE)
+      if (ref.base == NULL_TREE
+         && !ao_ref_init_from_vn_reference (&ref, refx->set, refx->type,
+                                            refx->operands))
        {
-         if (!(ref = get_ref_from_reference_ops (refx->operands)))
-           {
-             res = true;
-             break;
-           }
+         res = true;
+         break;
        }
       /* If the statement may clobber expr, it dies.  */
-      if (stmt_may_clobber_ref_p (def, ref))
+      if (stmt_may_clobber_ref_p_1 (def, &ref))
        {
          res = true;
          break;
@@ -2590,6 +2584,7 @@ can_PRE_operation (tree op)
    for performing quick dead code elimination of insertions we made
    that didn't turn out to be necessary.   */
 static VEC(gimple,heap) *inserted_exprs;
+static bitmap inserted_phi_names;
 
 /* Pool allocated fake store expressions are placed onto this
    worklist, which, after performing dead code elimination, is walked
@@ -2639,6 +2634,36 @@ create_component_ref_by_pieces_1 (basic_block block, vn_reference_t ref,
        return folded;
       }
       break;
+    case TARGET_MEM_REF:
+      {
+       vn_reference_op_t nextop = VEC_index (vn_reference_op_s, ref->operands,
+                                             *operand);
+       pre_expr op0expr;
+       tree genop0 = NULL_TREE;
+       tree baseop = create_component_ref_by_pieces_1 (block, ref, operand,
+                                                       stmts, domstmt);
+       if (!baseop)
+         return NULL_TREE;
+       if (currop->op0)
+         {
+           op0expr = get_or_alloc_expr_for (currop->op0);
+           genop0 = find_or_generate_expression (block, op0expr,
+                                                 stmts, domstmt);
+           if (!genop0)
+             return NULL_TREE;
+         }
+       if (DECL_P (baseop))
+         return build6 (TARGET_MEM_REF, currop->type,
+                        baseop, NULL_TREE,
+                        genop0, currop->op1, currop->op2,
+                        unshare_expr (nextop->op1));
+       else
+         return build6 (TARGET_MEM_REF, currop->type,
+                        NULL_TREE, baseop,
+                        genop0, currop->op1, currop->op2,
+                        unshare_expr (nextop->op1));
+      }
+      break;
     case ADDR_EXPR:
       if (currop->op0)
        {
@@ -2894,8 +2919,8 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
                             gimple_seq *stmts, gimple domstmt, tree type)
 {
   tree temp, name;
-  tree folded, newexpr;
-  gimple_seq forced_stmts;
+  tree folded;
+  gimple_seq forced_stmts = NULL;
   unsigned int value_id;
   gimple_stmt_iterator gsi;
   tree exprtype = type ? type : get_expr_type (expr);
@@ -2967,13 +2992,16 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
     default:
       return NULL_TREE;
     }
-  folded = fold_convert (exprtype, folded);
+
+  if (!useless_type_conversion_p (exprtype, TREE_TYPE (folded)))
+    folded = fold_convert (exprtype, folded);
+
   /* Force the generated expression to be a sequence of GIMPLE
      statements.
      We have to call unshare_expr because force_gimple_operand may
      modify the tree we pass to it.  */
-  newexpr = force_gimple_operand (unshare_expr (folded), &forced_stmts,
-                                 false, NULL);
+  folded = force_gimple_operand (unshare_expr (folded), &forced_stmts,
+                                false, NULL);
 
   /* If we have any intermediate expressions to the value sets, add them
      to the value sets and chain them in the instruction stream.  */
@@ -3017,7 +3045,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
       || TREE_CODE (exprtype) == VECTOR_TYPE)
     DECL_GIMPLE_REG_P (temp) = 1;
 
-  newstmt = gimple_build_assign (temp, newexpr);
+  newstmt = gimple_build_assign (temp, folded);
   name = make_ssa_name (temp, newstmt);
   gimple_assign_set_lhs (newstmt, name);
   gimple_set_plf (newstmt, NECESSARY, false);
@@ -3235,6 +3263,8 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
   VN_INFO_GET (gimple_phi_result (phi))->valnum = gimple_phi_result (phi);
   VN_INFO (gimple_phi_result (phi))->value_id = val;
   VEC_safe_push (gimple, heap, inserted_exprs, phi);
+  bitmap_set_bit (inserted_phi_names,
+                 SSA_NAME_VERSION (gimple_phi_result (phi)));
   FOR_EACH_EDGE (pred, ei, block->preds)
     {
       pre_expr ae = avail[pred->src->index];
@@ -3750,7 +3780,8 @@ compute_avail (void)
                  continue;
 
                copy_reference_ops_from_call (stmt, &ops);
-               vn_reference_lookup_pieces (gimple_vuse (stmt),
+               vn_reference_lookup_pieces (gimple_vuse (stmt), 0,
+                                           gimple_expr_type (stmt),
                                            ops, &ref, false);
                VEC_free (vn_reference_op_s, heap, ops);
                if (!ref)
@@ -3971,8 +4002,10 @@ eliminate (void)
                 value is constant, use that constant.  */
              if (!sprime && is_gimple_min_invariant (VN_INFO (lhs)->valnum))
                {
-                 sprime = fold_convert (TREE_TYPE (lhs),
-                                        VN_INFO (lhs)->valnum);
+                 sprime = VN_INFO (lhs)->valnum;
+                 if (!useless_type_conversion_p (TREE_TYPE (lhs),
+                                                 TREE_TYPE (sprime)))
+                   sprime = fold_convert (TREE_TYPE (lhs), sprime);
 
                  if (dump_file && (dump_flags & TDF_DETAILS))
                    {
@@ -4098,17 +4131,128 @@ eliminate (void)
                  todo = TODO_cleanup_cfg;
                }
            }
+         /* Visit indirect calls and turn them into direct calls if
+            possible.  */
+         if (gimple_code (stmt) == GIMPLE_CALL
+             && TREE_CODE (gimple_call_fn (stmt)) == SSA_NAME)
+           {
+             tree fn = VN_INFO (gimple_call_fn (stmt))->valnum;
+             if (TREE_CODE (fn) == ADDR_EXPR
+                 && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL)
+               {
+                 if (dump_file && (dump_flags & TDF_DETAILS))
+                   {
+                     fprintf (dump_file, "Replacing call target with ");
+                     print_generic_expr (dump_file, fn, 0);
+                     fprintf (dump_file, " in ");
+                     print_gimple_stmt (dump_file, stmt, 0, 0);
+                   }
+
+                 gimple_call_set_fn (stmt, fn);
+                 update_stmt (stmt);
+                 if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
+                   gimple_purge_dead_eh_edges (b);
+
+                 /* Changing an indirect call to a direct call may
+                    have exposed different semantics.  This may
+                    require an SSA update.  */
+                 todo |= TODO_update_ssa_only_virtuals;
+               }
+           }
+       }
+
+      for (gsi = gsi_start_phis (b); !gsi_end_p (gsi);)
+       {
+         gimple stmt, phi = gsi_stmt (gsi);
+         tree sprime = NULL_TREE, res = PHI_RESULT (phi);
+         pre_expr sprimeexpr, resexpr;
+         gimple_stmt_iterator gsi2;
+
+         /* We want to perform redundant PHI elimination.  Do so by
+            replacing the PHI with a single copy if possible.
+            Do not touch inserted, single-argument or virtual PHIs.  */
+         if (gimple_phi_num_args (phi) == 1
+             || !is_gimple_reg (res)
+             || bitmap_bit_p (inserted_phi_names, SSA_NAME_VERSION (res)))
+           {
+             gsi_next (&gsi);
+             continue;
+           }
+
+         resexpr = get_or_alloc_expr_for_name (res);
+         sprimeexpr = bitmap_find_leader (AVAIL_OUT (b),
+                                          get_expr_value_id (resexpr), NULL);
+         if (sprimeexpr)
+           {
+             if (sprimeexpr->kind == CONSTANT)
+               sprime = PRE_EXPR_CONSTANT (sprimeexpr);
+             else if (sprimeexpr->kind == NAME)
+               sprime = PRE_EXPR_NAME (sprimeexpr);
+             else
+               gcc_unreachable ();
+           }
+         if (!sprimeexpr
+             || sprime == res)
+           {
+             gsi_next (&gsi);
+             continue;
+           }
+
+         if (dump_file && (dump_flags & TDF_DETAILS))
+           {
+             fprintf (dump_file, "Replaced redundant PHI node defining ");
+             print_generic_expr (dump_file, res, 0);
+             fprintf (dump_file, " with ");
+             print_generic_expr (dump_file, sprime, 0);
+             fprintf (dump_file, "\n");
+           }
+
+         remove_phi_node (&gsi, false);
+
+         if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime)))
+           sprime = fold_convert (TREE_TYPE (res), sprime);
+         stmt = gimple_build_assign (res, sprime);
+         SSA_NAME_DEF_STMT (res) = stmt;
+         if (TREE_CODE (sprime) == SSA_NAME)
+           gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
+                           NECESSARY, true);
+         gsi2 = gsi_after_labels (b);
+         gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
+         /* Queue the copy for eventual removal.  */
+         VEC_safe_push (gimple, heap, to_remove, stmt);
+         pre_stats.eliminations++;
        }
     }
 
   /* We cannot remove stmts during BB walk, especially not release SSA
-     names there as this confuses the VN machinery.  */
+     names there as this confuses the VN machinery.  The stmts ending
+     up in to_remove are either stores or simple copies.  */
   for (i = 0; VEC_iterate (gimple, to_remove, i, stmt); ++i)
     {
-      gsi = gsi_for_stmt (stmt);
-      unlink_stmt_vdef (stmt);
-      gsi_remove (&gsi, true);
-      release_defs (stmt);
+      tree lhs = gimple_assign_lhs (stmt);
+      use_operand_p use_p;
+      gimple use_stmt;
+
+      /* If there is a single use only, propagate the equivalency
+        instead of keeping the copy.  */
+      if (TREE_CODE (lhs) == SSA_NAME
+         && single_imm_use (lhs, &use_p, &use_stmt)
+         && may_propagate_copy (USE_FROM_PTR (use_p),
+                                gimple_assign_rhs1 (stmt)))
+       {
+         SET_USE (use_p, gimple_assign_rhs1 (stmt));
+         update_stmt (use_stmt);
+       }
+
+      /* If this is a store or a now unused copy, remove it.  */
+      if (TREE_CODE (lhs) != SSA_NAME
+         || has_zero_uses (lhs))
+       {
+         gsi = gsi_for_stmt (stmt);
+         unlink_stmt_vdef (stmt);
+         gsi_remove (&gsi, true);
+         release_defs (stmt);
+       }
     }
   VEC_free (gimple, heap, to_remove);
 
@@ -4266,6 +4410,7 @@ init_pre (bool do_fre)
   calculate_dominance_info (CDI_DOMINATORS);
 
   bitmap_obstack_initialize (&grand_bitmap_obstack);
+  inserted_phi_names = BITMAP_ALLOC (&grand_bitmap_obstack);
   phi_translate_table = htab_create (5110, expr_pred_trans_hash,
                                     expr_pred_trans_eq, free);
   expression_to_id = htab_create (num_ssa_names * 3,
@@ -4434,7 +4579,7 @@ struct gimple_opt_pass pass_pre =
   0,                                   /* static_pass_number */
   TV_TREE_PRE,                         /* tv_id */
   PROP_no_crit_edges | PROP_cfg
-    | PROP_ssa | PROP_alias,           /* properties_required */
+    | PROP_ssa,                                /* properties_required */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   TODO_rebuild_alias,                  /* todo_flags_start */
@@ -4469,7 +4614,7 @@ struct gimple_opt_pass pass_fre =
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
   TV_TREE_FRE,                         /* tv_id */
-  PROP_cfg | PROP_ssa | PROP_alias,    /* properties_required */
+  PROP_cfg | PROP_ssa,                 /* properties_required */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */