#include "system.h"
#include "coretypes.h"
#include "backend.h"
-#include "cfghooks.h"
+#include "target.h"
+#include "rtl.h"
#include "tree.h"
#include "gimple.h"
-#include "rtl.h"
+#include "cfghooks.h"
+#include "tree-pass.h"
#include "ssa.h"
+#include "expmed.h"
+#include "insn-config.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "diagnostic-core.h"
#include "alias.h"
#include "fold-const.h"
#include "flags.h"
-#include "insn-config.h"
-#include "expmed.h"
#include "dojump.h"
#include "explow.h"
#include "calls.h"
-#include "emit-rtl.h"
#include "varasm.h"
#include "stmt.h"
#include "expr.h"
#include "internal-fn.h"
#include "tree-eh.h"
#include "gimple-iterator.h"
-#include "cgraph.h"
#include "tree-cfg.h"
#include "tree-into-ssa.h"
#include "tree-ssa.h"
#include "tree-inline.h"
-#include "tree-pass.h"
#include "langhooks.h"
-#include "diagnostic-core.h"
-#include "target.h"
#include "cfgloop.h"
#include "gimple-low.h"
/* In some instances a tree and a gimple need to be stored in a same table,
i.e. in hash tables. This is a structure to do this. */
-typedef union {tree *tp; tree t; gimple g;} treemple;
+typedef union {tree *tp; tree t; gimple *g;} treemple;
/* Misc functions used in this file. */
/* Add statement T in function IFUN to landing pad NUM. */
static void
-add_stmt_to_eh_lp_fn (struct function *ifun, gimple t, int num)
+add_stmt_to_eh_lp_fn (struct function *ifun, gimple *t, int num)
{
gcc_assert (num != 0);
if (!get_eh_throw_stmt_table (ifun))
- set_eh_throw_stmt_table (ifun, hash_map<gimple, int>::create_ggc (31));
+ set_eh_throw_stmt_table (ifun, hash_map<gimple *, int>::create_ggc (31));
gcc_assert (!get_eh_throw_stmt_table (ifun)->put (t, num));
}
/* Add statement T in the current function (cfun) to EH landing pad NUM. */
void
-add_stmt_to_eh_lp (gimple t, int num)
+add_stmt_to_eh_lp (gimple *t, int num)
{
add_stmt_to_eh_lp_fn (cfun, t, num);
}
/* Add statement T to the single EH landing pad in REGION. */
static void
-record_stmt_eh_region (eh_region region, gimple t)
+record_stmt_eh_region (eh_region region, gimple *t)
{
if (region == NULL)
return;
/* Remove statement T in function IFUN from its EH landing pad. */
bool
-remove_stmt_from_eh_lp_fn (struct function *ifun, gimple t)
+remove_stmt_from_eh_lp_fn (struct function *ifun, gimple *t)
{
if (!get_eh_throw_stmt_table (ifun))
return false;
EH landing pad. */
bool
-remove_stmt_from_eh_lp (gimple t)
+remove_stmt_from_eh_lp (gimple *t)
{
return remove_stmt_from_eh_lp_fn (cfun, t);
}
statement is not recorded in the region table. */
int
-lookup_stmt_eh_lp_fn (struct function *ifun, gimple t)
+lookup_stmt_eh_lp_fn (struct function *ifun, gimple *t)
{
if (ifun->eh->throw_stmt_table == NULL)
return 0;
/* Likewise, but always use the current function. */
int
-lookup_stmt_eh_lp (gimple t)
+lookup_stmt_eh_lp (gimple *t)
{
/* We can get called from initialized data when -fnon-call-exceptions
is on; prevent crash. */
}
static void
-collect_finally_tree (gimple stmt, gtry *region);
+collect_finally_tree (gimple *stmt, gtry *region);
/* Go through the gimple sequence. Works with collect_finally_tree to
record all GIMPLE_LABEL and GIMPLE_TRY statements. */
}
static void
-collect_finally_tree (gimple stmt, gtry *region)
+collect_finally_tree (gimple *stmt, gtry *region)
{
treemple temp;
would leave the try_finally node that START lives in. */
static bool
-outside_finally_tree (treemple start, gimple target)
+outside_finally_tree (treemple start, gimple *target)
{
struct finally_tree_node n, *p;
indexed by EH region number. */
static bitmap eh_region_may_contain_throw_map;
-/* The GOTO_QUEUE is is an array of GIMPLE_GOTO and GIMPLE_RETURN
+/* The GOTO_QUEUE is an array of GIMPLE_GOTO and GIMPLE_RETURN
statements that are seen to escape this GIMPLE_TRY_FINALLY node.
The idea is to record a gimple statement for everything except for
the conditionals, which get their labels recorded. Since labels are
treemple stmt;
location_t location;
gimple_seq repl_stmt;
- gimple cont_stmt;
+ gimple *cont_stmt;
int index;
/* This is used when index >= 0 to indicate that stmt is a label (as
opposed to a goto stmt). */
size_t goto_queue_active;
/* Pointer map to help in searching goto_queue when it is large. */
- hash_map<gimple, goto_queue_node *> *goto_queue_map;
+ hash_map<gimple *, goto_queue_node *> *goto_queue_map;
/* The set of unique labels seen as entries in the goto queue. */
vec<tree> dest_array;
if (!tf->goto_queue_map)
{
- tf->goto_queue_map = new hash_map<gimple, goto_queue_node *>;
+ tf->goto_queue_map = new hash_map<gimple *, goto_queue_node *>;
for (i = 0; i < tf->goto_queue_active; i++)
{
bool existed = tf->goto_queue_map->put (tf->goto_queue[i].stmt.g,
static void replace_goto_queue_stmt_list (gimple_seq *, struct leh_tf_state *);
static void
-replace_goto_queue_1 (gimple stmt, struct leh_tf_state *tf,
+replace_goto_queue_1 (gimple *stmt, struct leh_tf_state *tf,
gimple_stmt_iterator *gsi)
{
gimple_seq seq;
try_finally node. */
static void
-maybe_record_in_goto_queue (struct leh_state *state, gimple stmt)
+maybe_record_in_goto_queue (struct leh_state *state, gimple *stmt)
{
struct leh_tf_state *tf = state->tf;
treemple new_stmt;
}
-#ifdef ENABLE_CHECKING
+#if CHECKING_P
/* We do not process GIMPLE_SWITCHes for now. As long as the original source
was in fact structured, and we've not yet done jump threading, then none
of the labels will leave outer GIMPLE_TRY_FINALLY nodes. Verify this. */
static void
do_return_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod)
{
- gimple x;
+ gimple *x;
/* In the case of a return, the queue node must be a gimple statement. */
gcc_assert (!q->is_label);
static gimple_seq
frob_into_branch_around (gtry *tp, eh_region region, tree over)
{
- gimple x;
+ gimple *x;
gimple_seq cleanup, result;
location_t loc = gimple_location (tp);
for (gsi = gsi_start (new_seq); !gsi_end_p (gsi); gsi_next (&gsi))
{
- gimple stmt = gsi_stmt (gsi);
- if (LOCATION_LOCUS (gimple_location (stmt)) == UNKNOWN_LOCATION)
+ gimple *stmt = gsi_stmt (gsi);
+ /* We duplicate __builtin_stack_restore at -O0 in the hope of eliminating
+ it on the EH paths. When it is not eliminated, make it transparent in
+ the debug info. */
+ if (gimple_call_builtin_p (stmt, BUILT_IN_STACK_RESTORE))
+ gimple_set_location (stmt, UNKNOWN_LOCATION);
+ else if (LOCATION_LOCUS (gimple_location (stmt)) == UNKNOWN_LOCATION)
{
tree block = gimple_block (stmt);
gimple_set_location (stmt, loc);
static inline geh_else *
get_eh_else (gimple_seq finally)
{
- gimple x = gimple_seq_first_stmt (finally);
+ gimple *x = gimple_seq_first_stmt (finally);
if (gimple_code (x) == GIMPLE_EH_ELSE)
{
gcc_assert (gimple_seq_singleton_p (finally));
gimple_stmt_iterator gsi;
bool finally_may_fallthru;
gimple_seq finally;
- gimple x;
+ gimple *x;
geh_mnt *eh_mnt;
gtry *try_stmt;
geh_else *eh_else;
struct leh_tf_state *tf)
{
tree lab;
- gimple x;
+ gimple *x;
geh_else *eh_else;
gimple_seq finally;
struct goto_queue_node *q, *qe;
struct goto_queue_node *q, *qe;
geh_else *eh_else;
glabel *label_stmt;
- gimple x;
+ gimple *x;
gimple_seq finally;
gimple_stmt_iterator gsi;
tree finally_label;
for (gsi = gsi_start (finally); !gsi_end_p (gsi); gsi_next (&gsi))
{
- gimple stmt = gsi_stmt (gsi);
+ gimple *stmt = gsi_stmt (gsi);
if (LOCATION_LOCUS (gimple_location (stmt)) == UNKNOWN_LOCATION)
{
tree block = gimple_block (stmt);
gimple_seq finally;
gimple_seq new_stmt;
gimple_seq seq;
- gimple x;
+ gimple *x;
geh_else *eh_else;
tree tmp;
location_t tf_loc = gimple_location (tf->try_finally_expr);
tree last_case;
vec<tree> case_label_vec;
gimple_seq switch_body = NULL;
- gimple x;
+ gimple *x;
geh_else *eh_else;
tree tmp;
- gimple switch_stmt;
+ gimple *switch_stmt;
gimple_seq finally;
- hash_map<tree, gimple> *cont_map = NULL;
+ hash_map<tree, gimple *> *cont_map = NULL;
/* The location of the TRY_FINALLY stmt. */
location_t tf_loc = gimple_location (tf->try_finally_expr);
/* The location of the finally block. */
/* We store the cont_stmt in the pointer map, so that we can recover
it in the loop below. */
if (!cont_map)
- cont_map = new hash_map<tree, gimple>;
+ cont_map = new hash_map<tree, gimple *>;
cont_map->put (case_lab, q->cont_stmt);
case_label_vec.quick_push (case_lab);
}
}
for (j = last_case_index; j < last_case_index + nlabels; j++)
{
- gimple cont_stmt;
+ gimple *cont_stmt;
last_case = case_label_vec[j];
for (gsi = gsi_start (finally); !gsi_end_p (gsi); gsi_next (&gsi))
{
- gimple stmt = gsi_stmt (gsi);
- if (!is_gimple_debug (stmt) && !gimple_clobber_p (stmt))
+ /* Duplicate __builtin_stack_restore in the hope of eliminating it
+ on the EH paths and, consequently, useless cleanups. */
+ gimple *stmt = gsi_stmt (gsi);
+ if (!is_gimple_debug (stmt)
+ && !gimple_clobber_p (stmt)
+ && !gimple_call_builtin_p (stmt, BUILT_IN_STACK_RESTORE))
return false;
}
return true;
}
/* Finally estimate N times, plus N gotos. */
- f_estimate = count_insns_seq (finally, &eni_size_weights);
+ f_estimate = estimate_num_insns_seq (finally, &eni_size_weights);
f_estimate = (f_estimate + 1) * ndests;
/* Switch statement (cost 10), N variable assignments, N gotos. */
if (this_tf.fallthru_label)
{
/* This must be reached only if ndests == 0. */
- gimple x = gimple_build_label (this_tf.fallthru_label);
+ gimple *x = gimple_build_label (this_tf.fallthru_label);
gimple_seq_add_stmt (&this_tf.top_p_seq, x);
}
gimple_stmt_iterator gsi;
tree out_label;
gimple_seq new_seq, cleanup;
- gimple x;
+ gimple *x;
location_t try_catch_loc = gimple_location (tp);
if (flag_exceptions)
{
struct leh_state this_state = *state;
eh_region this_region = NULL;
- gimple inner, x;
+ gimple *inner, *x;
gimple_seq new_seq;
inner = gimple_seq_first_stmt (gimple_try_cleanup (tp));
if (flag_exceptions)
{
- gimple inner = gimple_seq_first_stmt (gimple_try_cleanup (tp));
+ gimple *inner = gimple_seq_first_stmt (gimple_try_cleanup (tp));
eh_region this_region;
this_region = gen_eh_region_must_not_throw (state->cur_region);
result = gimple_try_eval (tp);
if (fake_tf.fallthru_label)
{
- gimple x = gimple_build_label (fake_tf.fallthru_label);
+ gimple *x = gimple_build_label (fake_tf.fallthru_label);
gimple_seq_add_stmt (&result, x);
}
}
lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
{
gimple_seq replace;
- gimple x;
- gimple stmt = gsi_stmt (*gsi);
+ gimple *x;
+ gimple *stmt = gsi_stmt (*gsi);
switch (gimple_code (stmt))
{
{
tree lhs = gimple_get_lhs (stmt);
tree tmp = create_tmp_var (TREE_TYPE (lhs));
- gimple s = gimple_build_assign (lhs, tmp);
+ gimple *s = gimple_build_assign (lhs, tmp);
gimple_set_location (s, gimple_location (stmt));
gimple_set_block (s, gimple_block (stmt));
gimple_set_lhs (stmt, tmp);
if there is such a landing pad within the current function. */
void
-make_eh_edges (gimple stmt)
+make_eh_edges (gimple *stmt)
{
basic_block src, dst;
eh_landing_pad lp;
{
eh_landing_pad old_lp, new_lp;
basic_block old_bb;
- gimple throw_stmt;
+ gimple *throw_stmt;
int old_lp_nr, new_lp_nr;
tree old_label, new_label;
edge_iterator ei;
an assignment or a conditional) may throw. */
static bool
-stmt_could_throw_1_p (gimple stmt)
+stmt_could_throw_1_p (gimple *stmt)
{
enum tree_code code = gimple_expr_code (stmt);
bool honor_nans = false;
/* Return true if statement STMT could throw an exception. */
bool
-stmt_could_throw_p (gimple stmt)
+stmt_could_throw_p (gimple *stmt)
{
if (!flag_exceptions)
return false;
the current function (CFUN). */
bool
-stmt_can_throw_external (gimple stmt)
+stmt_can_throw_external (gimple *stmt)
{
int lp_nr;
the current function (CFUN). */
bool
-stmt_can_throw_internal (gimple stmt)
+stmt_can_throw_internal (gimple *stmt)
{
int lp_nr;
any change was made. */
bool
-maybe_clean_eh_stmt_fn (struct function *ifun, gimple stmt)
+maybe_clean_eh_stmt_fn (struct function *ifun, gimple *stmt)
{
if (stmt_could_throw_p (stmt))
return false;
/* Likewise, but always use the current function. */
bool
-maybe_clean_eh_stmt (gimple stmt)
+maybe_clean_eh_stmt (gimple *stmt)
{
return maybe_clean_eh_stmt_fn (cfun, stmt);
}
done that my require an EH edge purge. */
bool
-maybe_clean_or_replace_eh_stmt (gimple old_stmt, gimple new_stmt)
+maybe_clean_or_replace_eh_stmt (gimple *old_stmt, gimple *new_stmt)
{
int lp_nr = lookup_stmt_eh_lp (old_stmt);
operand is the return value of duplicate_eh_regions. */
bool
-maybe_duplicate_eh_stmt_fn (struct function *new_fun, gimple new_stmt,
- struct function *old_fun, gimple old_stmt,
+maybe_duplicate_eh_stmt_fn (struct function *new_fun, gimple *new_stmt,
+ struct function *old_fun, gimple *old_stmt,
hash_map<void *, void *> *map,
int default_lp_nr)
{
and thus no remapping is required. */
bool
-maybe_duplicate_eh_stmt (gimple new_stmt, gimple old_stmt)
+maybe_duplicate_eh_stmt (gimple *new_stmt, gimple *old_stmt)
{
int lp_nr;
same_handler_p (gimple_seq oneh, gimple_seq twoh)
{
gimple_stmt_iterator gsi;
- gimple ones, twos;
+ gimple *ones, *twos;
unsigned int ai;
gsi = gsi_start (oneh);
static void
optimize_double_finally (gtry *one, gtry *two)
{
- gimple oneh;
+ gimple *oneh;
gimple_stmt_iterator gsi;
gimple_seq cleanup;
refactor_eh_r (gimple_seq seq)
{
gimple_stmt_iterator gsi;
- gimple one, two;
+ gimple *one, *two;
one = NULL;
two = NULL;
int lp_nr;
eh_region src_r, dst_r;
gimple_stmt_iterator gsi;
- gimple x;
+ gimple *x;
tree fn, src_nr;
bool ret = false;
FOR_EACH_BB_FN (bb, fun)
{
- gimple last = last_stmt (bb);
+ gimple *last = last_stmt (bb);
if (last && is_gimple_resx (last))
{
dominance_invalidated |=
call, and has an incoming EH edge. */
for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
{
- gimple stmt = gsi_stmt (gsi);
+ gimple *stmt = gsi_stmt (gsi);
if (is_gimple_debug (stmt))
continue;
if (gimple_clobber_p (stmt))
gsi = gsi_last_bb (bb);
for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
{
- gimple stmt = gsi_stmt (gsi);
+ gimple *stmt = gsi_stmt (gsi);
if (!gimple_clobber_p (stmt))
continue;
unlink_stmt_vdef (stmt);
gsi = gsi_last_bb (bb);
for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
{
- gimple stmt = gsi_stmt (gsi);
+ gimple *stmt = gsi_stmt (gsi);
if (is_gimple_debug (stmt))
continue;
if (gimple_code (stmt) == GIMPLE_LABEL)
gsi = gsi_last_bb (bb);
for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi))
{
- gimple stmt = gsi_stmt (gsi);
+ gimple *stmt = gsi_stmt (gsi);
tree lhs;
if (is_gimple_debug (stmt))
continue;
/* But adjust virtual operands if we sunk across a PHI node. */
if (vuse)
{
- gimple use_stmt;
+ gimple *use_stmt;
imm_use_iterator iter;
use_operand_p use_p;
FOR_EACH_IMM_USE_STMT (use_stmt, iter, vuse)
int region_nr;
eh_region r;
tree filter, fn;
- gimple x;
+ gimple *x;
bool redirected = false;
region_nr = gimple_eh_dispatch_region (stmt);
FOR_EACH_BB_FN (bb, fun)
{
- gimple last = last_stmt (bb);
+ gimple *last = last_stmt (bb);
if (last == NULL)
continue;
if (gimple_code (last) == GIMPLE_EH_DISPATCH)
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
- gimple stmt = gsi_stmt (gsi);
+ gimple *stmt = gsi_stmt (gsi);
if (mark_landing_pads)
{
tree rt = gimple_call_arg (stmt, i);
HOST_WIDE_INT ri = tree_to_shwi (rt);
- gcc_assert (ri = (int)ri);
+ gcc_assert (ri == (int)ri);
bitmap_set_bit (r_reachable, ri);
}
break;
sbitmap_free (r_reachable);
sbitmap_free (lp_reachable);
-#ifdef ENABLE_CHECKING
- verify_eh_tree (cfun);
-#endif
+ if (flag_checking)
+ verify_eh_tree (cfun);
}
/* Remove unreachable handlers if any landing pads have been removed after
{
for (gphi_iterator gpi = gsi_start_phis (bb); !gsi_end_p (gpi); )
{
- gimple use_stmt;
+ gimple *use_stmt;
gphi *phi = gpi.phi ();
tree lhs = gimple_phi_result (phi);
tree rhs = gimple_phi_arg_def (phi, 0);
{
basic_block bb = label_to_block (lp->post_landing_pad);
gimple_stmt_iterator gsi;
- gimple resx;
+ gimple *resx;
eh_region new_region;
edge_iterator ei;
edge e, e_out;
for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
if (e->flags & EDGE_EH)
{
- gimple stmt = last_stmt (e->src);
+ gimple *stmt = last_stmt (e->src);
remove_stmt_from_eh_lp (stmt);
remove_edge (e);
}
for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
if (e->flags & EDGE_EH)
{
- gimple stmt = last_stmt (e->src);
+ gimple *stmt = last_stmt (e->src);
remove_stmt_from_eh_lp (stmt);
add_stmt_to_eh_lp (stmt, new_lp_nr);
remove_edge (e);
edge that make_eh_edges would create. */
DEBUG_FUNCTION bool
-verify_eh_edges (gimple stmt)
+verify_eh_edges (gimple *stmt)
{
basic_block bb = gimple_bb (stmt);
eh_landing_pad lp = NULL;