/* 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.
#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
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;
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;
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)++;
}
static void
gen_conditions_for_domain (tree arg, inp_domain domain,
- VEC (gimple, heap) *conds,
+ vec<gimple> conds,
unsigned *nconds)
{
if (domain.has_lb)
{
/* 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
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;
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,
static void
gen_conditions_for_pow_int_base (tree base, tree expn,
- VEC (gimple, heap) *conds,
+ vec<gimple> conds,
unsigned *nconds)
{
gimple base_def;
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);
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).
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;
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;
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;
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
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;
/* 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;
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;
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;
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;
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);
}
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. */
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)
{
/* 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
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);
+}