]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/tree-call-cdce.c
Merge from trunk.
[thirdparty/gcc.git] / gcc / tree-call-cdce.c
index be020dab8099c838da280a5062750446904a189f..4c6aae7c484b0aaf09e4199fecede9e44c54e573 100644 (file)
@@ -1,6 +1,5 @@
 /* Conditional Dead Call Elimination pass for the GNU compiler.
-   Copyright (C) 2008, 2009, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 2008-2013 Free Software Foundation, Inc.
    Contributed by Xinliang David Li <davidxl@google.com>
 
 This file is part of GCC.
@@ -25,9 +24,15 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm.h"
 #include "basic-block.h"
 #include "tree.h"
+#include "stor-layout.h"
 #include "gimple-pretty-print.h"
-#include "tree-flow.h"
 #include "gimple.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include "tree-cfg.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
+#include "tree-into-ssa.h"
 #include "tree-pass.h"
 #include "flags.h"
 \f
@@ -196,7 +201,7 @@ check_pow (gimple pow_call)
         return false;
       if (REAL_VALUES_LESS (bcv, dconst1))
         return false;
-      real_from_integer (&mv, TYPE_MODE (TREE_TYPE (base)), 256, 0, 1);
+      real_from_integer (&mv, TYPE_MODE (TREE_TYPE (base)), 256, UNSIGNED);
       if (REAL_VALUES_LESS (mv, bcv))
         return false;
       return true;
@@ -318,7 +323,7 @@ gen_one_condition (tree arg, int lbub,
                    enum tree_code tcode,
                    const char *temp_name1,
                   const char *temp_name2,
-                   VEC (gimple, heap) *conds,
+                   vec<gimple> conds,
                    unsigned *nconds)
 {
   tree lbub_real_cst, lbub_cst, float_type;
@@ -343,9 +348,9 @@ gen_one_condition (tree arg, int lbub,
   gimple_assign_set_lhs (stmt2, tempcn);
 
   stmt3 = gimple_build_cond_from_tree (tempcn, NULL_TREE, NULL_TREE);
-  VEC_quick_push (gimple, conds, stmt1);
-  VEC_quick_push (gimple, conds, stmt2);
-  VEC_quick_push (gimple, conds, stmt3);
+  conds.quick_push (stmt1);
+  conds.quick_push (stmt2);
+  conds.quick_push (stmt3);
   (*nconds)++;
 }
 
@@ -360,7 +365,7 @@ gen_one_condition (tree arg, int lbub,
 
 static void
 gen_conditions_for_domain (tree arg, inp_domain domain,
-                           VEC (gimple, heap) *conds,
+                           vec<gimple> conds,
                            unsigned *nconds)
 {
   if (domain.has_lb)
@@ -374,7 +379,7 @@ gen_conditions_for_domain (tree arg, inp_domain domain,
     {
       /* Now push a separator.  */
       if (domain.has_lb)
-        VEC_quick_push (gimple, conds, (gimple)NULL);
+        conds.quick_push (NULL);
 
       gen_one_condition (arg, domain.ub,
                          (domain.is_ub_inclusive
@@ -403,7 +408,7 @@ gen_conditions_for_domain (tree arg, inp_domain domain,
 
 static void
 gen_conditions_for_pow_cst_base (tree base, tree expn,
-                                 VEC (gimple, heap) *conds,
+                                 vec<gimple> conds,
                                  unsigned *nconds)
 {
   inp_domain exp_domain;
@@ -413,7 +418,7 @@ gen_conditions_for_pow_cst_base (tree base, tree expn,
   REAL_VALUE_TYPE bcv = TREE_REAL_CST (base);
   gcc_assert (!REAL_VALUES_EQUAL (bcv, dconst1)
               && !REAL_VALUES_LESS (bcv, dconst1));
-  real_from_integer (&mv, TYPE_MODE (TREE_TYPE (base)), 256, 0, 1);
+  real_from_integer (&mv, TYPE_MODE (TREE_TYPE (base)), 256, UNSIGNED);
   gcc_assert (!REAL_VALUES_LESS (mv, bcv));
 
   exp_domain = get_domain (0, false, false,
@@ -439,7 +444,7 @@ gen_conditions_for_pow_cst_base (tree base, tree expn,
 
 static void
 gen_conditions_for_pow_int_base (tree base, tree expn,
-                                 VEC (gimple, heap) *conds,
+                                 vec<gimple> conds,
                                  unsigned *nconds)
 {
   gimple base_def;
@@ -496,7 +501,7 @@ gen_conditions_for_pow_int_base (tree base, tree expn,
      type is integer.  */
 
   /* Push a separator.  */
-  VEC_quick_push (gimple, conds, (gimple)NULL);
+  conds.quick_push (NULL);
 
   temp = create_tmp_var (int_type, "DCE_COND1");
   cst0 = build_int_cst (int_type, 0);
@@ -505,15 +510,15 @@ gen_conditions_for_pow_int_base (tree base, tree expn,
   gimple_assign_set_lhs (stmt1, tempn);
   stmt2 = gimple_build_cond (LE_EXPR, tempn, cst0, NULL_TREE, NULL_TREE);
 
-  VEC_quick_push (gimple, conds, stmt1);
-  VEC_quick_push (gimple, conds, stmt2);
+  conds.quick_push (stmt1);
+  conds.quick_push (stmt2);
   (*nconds)++;
 }
 
 /* Method to generate conditional statements for guarding conditionally
    dead calls to pow.  One or more statements can be generated for
    each logical condition.  Statement groups of different conditions
-   are separated by a NULL tree and they are stored in the VEC
+   are separated by a NULL tree and they are stored in the vec
    conds.  The number of logical conditions are stored in *nconds.
 
    See C99 standard, 7.12.7.4:2, for description of pow (x, y).
@@ -528,7 +533,7 @@ gen_conditions_for_pow_int_base (tree base, tree expn,
    and *NCONDS is the number of logical conditions.  */
 
 static void
-gen_conditions_for_pow (gimple pow_call, VEC (gimple, heap) *conds,
+gen_conditions_for_pow (gimple pow_call, vec<gimple> conds,
                         unsigned *nconds)
 {
   tree base, expn;
@@ -664,15 +669,15 @@ get_no_error_domain (enum built_in_function fnc)
    condition are separated by NULL tree in the vector.  */
 
 static void
-gen_shrink_wrap_conditions (gimple bi_call, VEC (gimple, heap) *conds,
+gen_shrink_wrap_conditions (gimple bi_call, vec<gimple> conds,
                             unsigned int *nconds)
 {
   gimple call;
   tree fn;
   enum built_in_function fnc;
 
-  gcc_assert (nconds && conds);
-  gcc_assert (VEC_length (gimple, conds) == 0);
+  gcc_assert (nconds && conds.exists ());
+  gcc_assert (conds.length () == 0);
   gcc_assert (is_gimple_call (bi_call));
 
   call = bi_call;
@@ -711,7 +716,6 @@ shrink_wrap_one_built_in_call (gimple bi_call)
   basic_block bi_call_bb, join_tgt_bb, guard_bb, guard_bb0;
   edge join_tgt_in_edge_from_call, join_tgt_in_edge_fall_thru;
   edge bi_call_in_edge0, guard_bb_in_edge;
-  VEC (gimple, heap) *conds;
   unsigned tn_cond_stmts, nconds;
   unsigned ci;
   gimple cond_expr = NULL;
@@ -719,7 +723,7 @@ shrink_wrap_one_built_in_call (gimple bi_call)
   tree bi_call_label_decl;
   gimple bi_call_label;
 
-  conds = VEC_alloc (gimple, heap, 12);
+  stack_vec<gimple, 12> conds;
   gen_shrink_wrap_conditions (bi_call, conds, &nconds);
 
   /* This can happen if the condition generator decides
@@ -731,11 +735,18 @@ shrink_wrap_one_built_in_call (gimple bi_call)
 
   bi_call_bb = gimple_bb (bi_call);
 
-  /* Now find the join target bb -- split
-     bi_call_bb if needed.  */
-  bi_call_bsi = gsi_for_stmt (bi_call);
+  /* Now find the join target bb -- split bi_call_bb if needed.  */
+  if (stmt_ends_bb_p (bi_call))
+    {
+      /* If the call must be the last in the bb, don't split the block,
+        it could e.g. have EH edges.  */
+      join_tgt_in_edge_from_call = find_fallthru_edge (bi_call_bb->succs);
+      if (join_tgt_in_edge_from_call == NULL)
+        return false;
+    }
+  else
+    join_tgt_in_edge_from_call = split_block (bi_call_bb, bi_call);
 
-  join_tgt_in_edge_from_call = split_block (bi_call_bb, bi_call);
   bi_call_bsi = gsi_for_stmt (bi_call);
 
   join_tgt_bb = join_tgt_in_edge_from_call->dest;
@@ -743,12 +754,12 @@ shrink_wrap_one_built_in_call (gimple bi_call)
   /* Now it is time to insert the first conditional expression
      into bi_call_bb and split this bb so that bi_call is
      shrink-wrapped.  */
-  tn_cond_stmts = VEC_length (gimple, conds);
+  tn_cond_stmts = conds.length ();
   cond_expr = NULL;
-  cond_expr_start = VEC_index (gimple, conds, 0);
+  cond_expr_start = conds[0];
   for (ci = 0; ci < tn_cond_stmts; ci++)
     {
-      gimple c = VEC_index (gimple, conds, ci);
+      gimple c = conds[ci];
       gcc_assert (c || ci != 0);
       if (!c)
         break;
@@ -773,8 +784,13 @@ shrink_wrap_one_built_in_call (gimple bi_call)
                                           EDGE_FALSE_VALUE);
 
   bi_call_in_edge0->probability = REG_BR_PROB_BASE * ERR_PROB;
+  bi_call_in_edge0->count =
+      apply_probability (guard_bb0->count,
+                        bi_call_in_edge0->probability);
   join_tgt_in_edge_fall_thru->probability =
-      REG_BR_PROB_BASE - bi_call_in_edge0->probability;
+      inverse_probability (bi_call_in_edge0->probability);
+  join_tgt_in_edge_fall_thru->count =
+      guard_bb0->count - bi_call_in_edge0->count;
 
   /* Code generation for the rest of the conditions  */
   guard_bb = guard_bb0;
@@ -784,10 +800,10 @@ shrink_wrap_one_built_in_call (gimple bi_call)
       edge bi_call_in_edge;
       gimple_stmt_iterator guard_bsi = gsi_for_stmt (cond_expr_start);
       ci0 = ci;
-      cond_expr_start = VEC_index (gimple, conds, ci0);
+      cond_expr_start = conds[ci0];
       for (; ci < tn_cond_stmts; ci++)
         {
-          gimple c = VEC_index (gimple, conds, ci);
+          gimple c = conds[ci];
           gcc_assert (c || ci != ci0);
           if (!c)
             break;
@@ -804,11 +820,14 @@ shrink_wrap_one_built_in_call (gimple bi_call)
       bi_call_in_edge = make_edge (guard_bb, bi_call_bb, EDGE_TRUE_VALUE);
 
       bi_call_in_edge->probability = REG_BR_PROB_BASE * ERR_PROB;
+      bi_call_in_edge->count =
+         apply_probability (guard_bb->count,
+                            bi_call_in_edge->probability);
       guard_bb_in_edge->probability =
-          REG_BR_PROB_BASE - bi_call_in_edge->probability;
+          inverse_probability (bi_call_in_edge->probability);
+      guard_bb_in_edge->count = guard_bb->count - bi_call_in_edge->count;
     }
 
-  VEC_free (gimple, heap, conds);
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       location_t loc;
@@ -826,18 +845,18 @@ shrink_wrap_one_built_in_call (gimple bi_call)
    wrapping transformation.  */
 
 static bool
-shrink_wrap_conditional_dead_built_in_calls (VEC (gimple, heap) *calls)
+shrink_wrap_conditional_dead_built_in_calls (vec<gimple> calls)
 {
   bool changed = false;
   unsigned i = 0;
 
-  unsigned n = VEC_length (gimple, calls);
+  unsigned n = calls.length ();
   if (n == 0)
     return false;
 
   for (; i < n ; i++)
     {
-      gimple bi_call = VEC_index (gimple, calls, i);
+      gimple bi_call = calls[i];
       changed |= shrink_wrap_one_built_in_call (bi_call);
     }
 
@@ -852,7 +871,7 @@ tree_call_cdce (void)
   basic_block bb;
   gimple_stmt_iterator i;
   bool something_changed = false;
-  VEC (gimple, heap) *cond_dead_built_in_calls = NULL;
+  vec<gimple> cond_dead_built_in_calls = vNULL;
   FOR_EACH_BB (bb)
     {
       /* Collect dead call candidates.  */
@@ -868,20 +887,20 @@ tree_call_cdce (void)
                   print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
                   fprintf (dump_file, "\n");
                 }
-             if (cond_dead_built_in_calls == NULL)
-               cond_dead_built_in_calls = VEC_alloc (gimple, heap, 64);
-             VEC_safe_push (gimple, heap, cond_dead_built_in_calls, stmt);
+             if (!cond_dead_built_in_calls.exists ())
+               cond_dead_built_in_calls.create (64);
+             cond_dead_built_in_calls.safe_push (stmt);
             }
        }
     }
 
-  if (cond_dead_built_in_calls == NULL)
+  if (!cond_dead_built_in_calls.exists ())
     return 0;
 
   something_changed
     = shrink_wrap_conditional_dead_built_in_calls (cond_dead_built_in_calls);
 
-  VEC_free (gimple, heap, cond_dead_built_in_calls);
+  cond_dead_built_in_calls.release ();
 
   if (something_changed)
     {
@@ -890,11 +909,10 @@ tree_call_cdce (void)
       /* As we introduced new control-flow we need to insert PHI-nodes
          for the call-clobbers of the remaining call.  */
       mark_virtual_operands_for_renaming (cfun);
-      return (TODO_update_ssa | TODO_cleanup_cfg | TODO_ggc_collect
-              | TODO_remove_unused_locals);
+      return TODO_update_ssa;
     }
-  else
-    return 0;
+
+  return 0;
 }
 
 static bool
@@ -906,21 +924,40 @@ gate_call_cdce (void)
   return flag_tree_builtin_call_dce != 0 && optimize_function_for_speed_p (cfun);
 }
 
-struct gimple_opt_pass pass_call_cdce =
+namespace {
+
+const pass_data pass_data_call_cdce =
 {
- {
-  GIMPLE_PASS,
-  "cdce",                               /* name */
-  gate_call_cdce,                       /* gate */
-  tree_call_cdce,                       /* execute */
-  NULL,                                 /* sub */
-  NULL,                                 /* next */
-  0,                                    /* static_pass_number */
-  TV_TREE_CALL_CDCE,                    /* tv_id */
-  PROP_cfg | PROP_ssa,                  /* properties_required */
-  0,                                    /* properties_provided */
-  0,                                    /* properties_destroyed */
-  0,                                    /* todo_flags_start */
-  TODO_verify_ssa                       /* todo_flags_finish */
- }
+  GIMPLE_PASS, /* type */
+  "cdce", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  true, /* has_gate */
+  true, /* has_execute */
+  TV_TREE_CALL_CDCE, /* tv_id */
+  ( PROP_cfg | PROP_ssa ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_verify_ssa, /* todo_flags_finish */
 };
+
+class pass_call_cdce : public gimple_opt_pass
+{
+public:
+  pass_call_cdce (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_call_cdce, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  bool gate () { return gate_call_cdce (); }
+  unsigned int execute () { return tree_call_cdce (); }
+
+}; // class pass_call_cdce
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_call_cdce (gcc::context *ctxt)
+{
+  return new pass_call_cdce (ctxt);
+}