aboutsummaryrefslogtreecommitdiff
path: root/gcc/cfgexpand.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cfgexpand.cc')
-rw-r--r--gcc/cfgexpand.cc129
1 files changed, 97 insertions, 32 deletions
diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc
index 8919cc3..f288a54 100644
--- a/gcc/cfgexpand.cc
+++ b/gcc/cfgexpand.cc
@@ -74,6 +74,7 @@ along with GCC; see the file COPYING3. If not see
#include "output.h"
#include "builtins.h"
#include "opts.h"
+#include "gimple-range.h"
/* Some systems use __main in a way incompatible with its use in gcc, in these
cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
@@ -2771,6 +2772,10 @@ maybe_dump_rtl_for_gimple_stmt (gimple *stmt, rtx_insn *since)
}
}
+/* Temporary storage for BB_HEAD and BB_END of bbs until they are converted
+ to BB_RTL. */
+static vec<std::pair <rtx_insn *, rtx_insn *>> head_end_for_bb;
+
/* Maps the blocks that do not contain tree labels to rtx labels. */
static hash_map<basic_block, rtx_code_label *> *lab_rtx_for_bb;
@@ -2778,11 +2783,23 @@ static hash_map<basic_block, rtx_code_label *> *lab_rtx_for_bb;
/* Returns the label_rtx expression for a label starting basic block BB. */
static rtx_code_label *
-label_rtx_for_bb (basic_block bb ATTRIBUTE_UNUSED)
+label_rtx_for_bb (basic_block bb)
{
if (bb->flags & BB_RTL)
return block_label (bb);
+ if ((unsigned) bb->index < head_end_for_bb.length ()
+ && head_end_for_bb[bb->index].first)
+ {
+ if (!LABEL_P (head_end_for_bb[bb->index].first))
+ {
+ head_end_for_bb[bb->index].first
+ = emit_label_before (gen_label_rtx (),
+ head_end_for_bb[bb->index].first);
+ }
+ return as_a <rtx_code_label *> (head_end_for_bb[bb->index].first);
+ }
+
rtx_code_label **elt = lab_rtx_for_bb->get (bb);
if (elt)
return *elt;
@@ -2801,6 +2818,19 @@ label_rtx_for_bb (basic_block bb ATTRIBUTE_UNUSED)
}
+/* Wrapper around remove_edge during expansion. */
+
+void
+expand_remove_edge (edge e)
+{
+ if (current_ir_type () != IR_GIMPLE
+ && (e->dest->flags & BB_RTL) == 0
+ && !gimple_seq_empty_p (phi_nodes (e->dest)))
+ remove_phi_args (e);
+ remove_edge (e);
+}
+
+
/* A subroutine of expand_gimple_cond. Given E, a fallthrough edge
of a basic block where we just expanded the conditional at the end,
possibly clean up the CFG and instruction sequence. LAST is the
@@ -2823,7 +2853,7 @@ maybe_cleanup_end_of_block (edge e, rtx_insn *last)
if (BARRIER_P (get_last_insn ()))
{
rtx_insn *insn;
- remove_edge (e);
+ expand_remove_edge (e);
/* Now, we have a single successor block, if we have insns to
insert on the remaining edge we potentially will insert
it at the end of this block (if the dest block isn't feasible)
@@ -2942,10 +2972,6 @@ expand_gimple_cond (basic_block bb, gcond *stmt)
extract_true_false_edges_from_block (bb, &true_edge, &false_edge);
set_curr_insn_location (gimple_location (stmt));
- /* These flags have no purpose in RTL land. */
- true_edge->flags &= ~EDGE_TRUE_VALUE;
- false_edge->flags &= ~EDGE_FALSE_VALUE;
-
/* We can either have a pure conditional jump with one fallthru edge or
two-way jump that needs to be decomposed into two basic blocks. */
if (false_edge->dest == bb->next_bb)
@@ -2978,13 +3004,16 @@ expand_gimple_cond (basic_block bb, gcond *stmt)
set_curr_insn_location (false_edge->goto_locus);
emit_jump (label_rtx_for_bb (false_edge->dest));
- BB_END (bb) = last;
- if (BARRIER_P (BB_END (bb)))
- BB_END (bb) = PREV_INSN (BB_END (bb));
- update_bb_for_insn (bb);
+ head_end_for_bb[bb->index].second = last;
+ if (BARRIER_P (head_end_for_bb[bb->index].second))
+ head_end_for_bb[bb->index].second
+ = PREV_INSN (head_end_for_bb[bb->index].second);
+ update_bb_for_insn_chain (head_end_for_bb[bb->index].first,
+ head_end_for_bb[bb->index].second, bb);
new_bb = create_basic_block (NEXT_INSN (last), get_last_insn (), bb);
dest = false_edge->dest;
+ unsigned int dest_idx = false_edge->dest_idx;
redirect_edge_succ (false_edge, new_bb);
false_edge->flags |= EDGE_FALLTHRU;
new_bb->count = false_edge->count ();
@@ -2993,7 +3022,19 @@ expand_gimple_cond (basic_block bb, gcond *stmt)
if (loop->latch == bb
&& loop->header == dest)
loop->latch = new_bb;
- make_single_succ_edge (new_bb, dest, 0);
+ edge e = make_single_succ_edge (new_bb, dest, 0);
+ if ((dest->flags & BB_RTL) == 0
+ && phi_nodes (dest)
+ && e->dest_idx != dest_idx)
+ {
+ /* If there are any PHI nodes on dest, swap the new succ edge
+ with the one moved into false_edge's former position, so that
+ PHI arguments don't need adjustment. */
+ edge e2 = EDGE_PRED (dest, dest_idx);
+ std::swap (e->dest_idx, e2->dest_idx);
+ std::swap (EDGE_PRED (dest, e->dest_idx),
+ EDGE_PRED (dest, e2->dest_idx));
+ }
if (BARRIER_P (BB_END (new_bb)))
BB_END (new_bb) = PREV_INSN (BB_END (new_bb));
update_bb_for_insn (new_bb);
@@ -4445,7 +4486,7 @@ expand_gimple_tailcall (basic_block bb, gcall *stmt, bool *can_fallthru)
if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
e->dest->count -= e->count ();
probability += e->probability;
- remove_edge (e);
+ expand_remove_edge (e);
}
else
ei_next (&ei);
@@ -4473,8 +4514,9 @@ expand_gimple_tailcall (basic_block bb, gcall *stmt, bool *can_fallthru)
e = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_ABNORMAL
| EDGE_SIBCALL);
e->probability = probability;
- BB_END (bb) = last;
- update_bb_for_insn (bb);
+ head_end_for_bb[bb->index].second = last;
+ update_bb_for_insn_chain (head_end_for_bb[bb->index].first,
+ head_end_for_bb[bb->index].second, bb);
if (NEXT_INSN (last))
{
@@ -6092,7 +6134,6 @@ static basic_block
expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
{
gimple_stmt_iterator gsi;
- gimple_seq stmts;
gimple *stmt = NULL;
rtx_note *note = NULL;
rtx_insn *last;
@@ -6110,18 +6151,12 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
access the BB sequence directly. */
if (optimize)
reorder_operands (bb);
- stmts = bb_seq (bb);
- bb->il.gimple.seq = NULL;
- bb->il.gimple.phi_nodes = NULL;
rtl_profile_for_bb (bb);
- init_rtl_bb_info (bb);
- bb->flags |= BB_RTL;
/* Remove the RETURN_EXPR if we may fall though to the exit
instead. */
- gsi = gsi_last (stmts);
- if (!gsi_end_p (gsi)
- && gimple_code (gsi_stmt (gsi)) == GIMPLE_RETURN)
+ gsi = gsi_last_bb (bb);
+ if (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_RETURN)
{
greturn *ret_stmt = as_a <greturn *> (gsi_stmt (gsi));
@@ -6136,7 +6171,7 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
}
}
- gsi = gsi_start (stmts);
+ gsi = gsi_start_bb (bb);
if (!gsi_end_p (gsi))
{
stmt = gsi_stmt (gsi);
@@ -6145,6 +6180,8 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
}
rtx_code_label **elt = lab_rtx_for_bb->get (bb);
+ if ((unsigned) bb->index >= head_end_for_bb.length ())
+ head_end_for_bb.safe_grow_cleared (bb->index + 1);
if (stmt || elt)
{
@@ -6160,16 +6197,18 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
if (elt)
emit_label (*elt);
- BB_HEAD (bb) = NEXT_INSN (last);
- if (NOTE_P (BB_HEAD (bb)))
- BB_HEAD (bb) = NEXT_INSN (BB_HEAD (bb));
- gcc_assert (LABEL_P (BB_HEAD (bb)));
- note = emit_note_after (NOTE_INSN_BASIC_BLOCK, BB_HEAD (bb));
+ head_end_for_bb[bb->index].first = NEXT_INSN (last);
+ if (NOTE_P (head_end_for_bb[bb->index].first))
+ head_end_for_bb[bb->index].first
+ = NEXT_INSN (head_end_for_bb[bb->index].first);
+ gcc_assert (LABEL_P (head_end_for_bb[bb->index].first));
+ note = emit_note_after (NOTE_INSN_BASIC_BLOCK,
+ head_end_for_bb[bb->index].first);
maybe_dump_rtl_for_gimple_stmt (stmt, last);
}
else
- BB_HEAD (bb) = note = emit_note (NOTE_INSN_BASIC_BLOCK);
+ head_end_for_bb[bb->index].first = note = emit_note (NOTE_INSN_BASIC_BLOCK);
if (note)
NOTE_BASIC_BLOCK (note) = bb;
@@ -6485,9 +6524,10 @@ expand_gimple_basic_block (basic_block bb, bool disable_tail_calls)
last = PREV_INSN (PREV_INSN (last));
if (BARRIER_P (last))
last = PREV_INSN (last);
- BB_END (bb) = last;
+ head_end_for_bb[bb->index].second = last;
- update_bb_for_insn (bb);
+ update_bb_for_insn_chain (head_end_for_bb[bb->index].first,
+ head_end_for_bb[bb->index].second, bb);
return bb;
}
@@ -7175,10 +7215,35 @@ pass_expand::execute (function *fun)
>= param_max_debug_marker_count)
cfun->debug_nonbind_markers = false;
+ enable_ranger (fun);
lab_rtx_for_bb = new hash_map<basic_block, rtx_code_label *>;
+ head_end_for_bb.create (last_basic_block_for_fn (fun));
FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),
next_bb)
bb = expand_gimple_basic_block (bb, var_ret_seq != NULL_RTX);
+ disable_ranger (fun);
+ FOR_BB_BETWEEN (bb, init_block->next_bb, EXIT_BLOCK_PTR_FOR_FN (fun),
+ next_bb)
+ {
+ if ((bb->flags & BB_RTL) == 0)
+ {
+ bb->il.gimple.seq = NULL;
+ bb->il.gimple.phi_nodes = NULL;
+ init_rtl_bb_info (bb);
+ bb->flags |= BB_RTL;
+ BB_HEAD (bb) = head_end_for_bb[bb->index].first;
+ BB_END (bb) = head_end_for_bb[bb->index].second;
+ }
+ /* These flags have no purpose in RTL land. */
+ if (EDGE_COUNT (bb->succs) == 2)
+ {
+ EDGE_SUCC (bb, 0)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
+ EDGE_SUCC (bb, 1)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
+ }
+ else if (single_succ_p (bb))
+ single_succ_edge (bb)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
+ }
+ head_end_for_bb.release ();
if (MAY_HAVE_DEBUG_BIND_INSNS)
expand_debug_locations ();