diff options
Diffstat (limited to 'gcc/cfgexpand.cc')
-rw-r--r-- | gcc/cfgexpand.cc | 129 |
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 (); |