- Edge redirection with updating and optimizing of insn chain
block_label, redirect_edge_and_branch,
redirect_edge_and_branch_force, tidy_fallthru_edge, force_nonfallthru
- - Edge splitting and commiting to edges
+ - Edge splitting and committing to edges
split_edge, insert_insn_on_edge, commit_edge_insertions
- Dumping and debugging
print_rtl_with_bb, dump_bb, debug_bb, debug_bb_n
\f
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "hard-reg-set.h"
#define gen_return() NULL_RTX
#endif
-/* The basic block structure for every insn, indexed by uid. */
-varray_type basic_block_for_insn;
-
/* The labels mentioned in non-jump rtl. Valid during find_basic_blocks. */
/* ??? Should probably be using LABEL_NUSES instead. It would take a
bit of surgery to be able to use or co-opt the routines in jump. */
rtx x;
bool purge = false;
- if (basic_block_for_insn
- && INSN_P (insn)
- && (unsigned int)INSN_UID (insn) < basic_block_for_insn->num_elements
+ if (INSN_P (insn)
&& BLOCK_FOR_INSN (insn)
&& BLOCK_FOR_INSN (insn)->end == insn)
purge = true;
{
bool purge = false;
- if (basic_block_for_insn
- && INSN_P (last)
- && (unsigned int)INSN_UID (last) < basic_block_for_insn->num_elements
+ if (INSN_P (last)
&& BLOCK_FOR_INSN (last)
&& BLOCK_FOR_INSN (last)->end == last)
purge = true;
AFTER is the basic block we should be put after. */
basic_block
-create_basic_block_structure (index, head, end, bb_note, after)
- int index;
+create_basic_block_structure (head, end, bb_note, after)
rtx head, end, bb_note;
basic_block after;
{
}
if (after != bb_note && NEXT_INSN (after) != bb_note)
- reorder_insns (bb_note, bb_note, after);
+ reorder_insns_nobb (bb_note, bb_note, after);
}
else
{
bb->head = head;
bb->end = end;
- bb->index = index;
+ bb->index = last_basic_block++;
bb->flags = BB_NEW;
link_block (bb, after);
- BASIC_BLOCK (index) = bb;
- if (basic_block_for_insn)
- update_bb_for_insn (bb);
+ BASIC_BLOCK (bb->index) = bb;
+ update_bb_for_insn (bb);
/* Tag the block so that we know it has been used when considering
other basic block notes. */
basic_block after;
{
basic_block bb;
- int i;
- int index = after->index + 1;
-
- /* Place the new block just after the block being split. */
- VARRAY_GROW (basic_block_info, ++n_basic_blocks);
- /* Some parts of the compiler expect blocks to be number in
- sequential order so insert the new block immediately after the
- block being split.. */
- for (i = n_basic_blocks - 1; i > index; --i)
- {
- basic_block tmp = BASIC_BLOCK (i - 1);
+ /* Place the new block just after the end. */
+ VARRAY_GROW (basic_block_info, last_basic_block+1);
- BASIC_BLOCK (i) = tmp;
- tmp->index = i;
- }
+ n_basic_blocks++;
- bb = create_basic_block_structure (index, head, end, NULL, after);
+ bb = create_basic_block_structure (head, end, NULL, after);
bb->aux = NULL;
return bb;
}
and remove the associated NOTE_INSN_EH_REGION_BEG and
NOTE_INSN_EH_REGION_END notes. */
- /* Get rid of all NOTE_INSN_PREDICTIONs hanging before the block. */
+ /* Get rid of all NOTE_INSN_PREDICTIONs and NOTE_INSN_LOOP_CONTs
+ hanging before the block. */
for (insn = PREV_INSN (b->head); insn; insn = PREV_INSN (insn))
{
if (GET_CODE (insn) != NOTE)
break;
- if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PREDICTION)
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PREDICTION
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT)
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
}
{
int deleted_handler = flow_delete_block_noexpunge (b);
- /* Remove the basic block from the array, and compact behind it. */
+ /* Remove the basic block from the array. */
expunge_block (b);
return deleted_handler;
}
\f
-/* Records the basic block struct in BB_FOR_INSN, for every instruction
- indexed by INSN_UID. MAX is the size of the array. */
+/* Records the basic block struct in BLOCK_FOR_INSN for every insn. */
void
-compute_bb_for_insn (max)
- int max;
+compute_bb_for_insn ()
{
basic_block bb;
- if (basic_block_for_insn)
- VARRAY_FREE (basic_block_for_insn);
-
- VARRAY_BB_INIT (basic_block_for_insn, max, "basic_block_for_insn");
-
FOR_EACH_BB (bb)
{
rtx end = bb->end;
for (insn = bb->head; ; insn = NEXT_INSN (insn))
{
- if (INSN_UID (insn) < max)
- VARRAY_BB (basic_block_for_insn, INSN_UID (insn)) = bb;
-
+ BLOCK_FOR_INSN (insn) = bb;
if (insn == end)
break;
}
void
free_bb_for_insn ()
{
- if (basic_block_for_insn)
- VARRAY_FREE (basic_block_for_insn);
-
- basic_block_for_insn = 0;
+ rtx insn;
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) != BARRIER)
+ BLOCK_FOR_INSN (insn) = NULL;
}
/* Update insns block within BB. */
{
rtx insn;
- if (! basic_block_for_insn)
- return;
-
for (insn = bb->head; ; insn = NEXT_INSN (insn))
{
set_block_for_insn (insn, bb);
break;
}
}
-
-/* Record INSN's block as BB. */
-
-void
-set_block_for_insn (insn, bb)
- rtx insn;
- basic_block bb;
-{
- size_t uid = INSN_UID (insn);
-
- if (uid >= basic_block_for_insn->num_elements)
- {
- /* Add one-eighth the size so we don't keep calling xrealloc. */
- size_t new_size = uid + (uid + 7) / 8;
-
- VARRAY_GROW (basic_block_for_insn, new_size);
- }
-
- VARRAY_BB (basic_block_for_insn, uid) = bb;
-}
\f
/* Split a block BB after insn INSN creating a new fallthru edge.
Return the new edge. Note that to keep other parts of the compiler happy,
/* Reassociate the insns of B with A. */
if (!b_empty)
{
- if (basic_block_for_insn)
- {
- rtx x;
+ rtx x;
- for (x = a_end; x != b_end; x = NEXT_INSN (x))
- set_block_for_insn (x, a);
+ for (x = a_end; x != b_end; x = NEXT_INSN (x))
+ set_block_for_insn (x, a);
- set_block_for_insn (b_end, a);
- }
+ set_block_for_insn (b_end, a);
a_end = b_end;
}
if (GET_CODE (block->head) != CODE_LABEL)
{
block->head = emit_label_before (gen_label_rtx (), block->head);
- if (basic_block_for_insn)
- set_block_for_insn (block->head, block);
}
return block->head;
/* Return last loop_beg note appearing after INSN, before start of next
basic block. Return INSN if there are no such notes.
- When emitting jump to redirect an fallthru edge, it should always appear
+ When emitting jump to redirect a fallthru edge, it should always appear
after the LOOP_BEG notes, as loop optimizer expect loop to either start by
fallthru edge or jump following the LOOP_BEG note jumping to the loop exit
test. */
edge e;
basic_block target;
{
- basic_block jump_block, new_bb = NULL;
+ basic_block jump_block, new_bb = NULL, src = e->src;
rtx note;
edge new_edge;
+ int abnormal_edge_flags = 0;
if (e->flags & EDGE_ABNORMAL)
- abort ();
+ {
+ /* Irritating special case - fallthru edge to the same block as abnormal
+ edge.
+ We can't redirect abnormal edge, but we still can split the fallthru
+ one and create separate abnormal edge to original destination.
+ This allows bb-reorder to make such edge non-fallthru. */
+ if (e->dest != target)
+ abort ();
+ abnormal_edge_flags = e->flags & ~(EDGE_FALLTHRU | EDGE_CAN_FALLTHRU);
+ e->flags &= EDGE_FALLTHRU | EDGE_CAN_FALLTHRU;
+ }
else if (!(e->flags & EDGE_FALLTHRU))
abort ();
else if (e->src == ENTRY_BLOCK_PTR)
make_single_succ_edge (ENTRY_BLOCK_PTR, bb, EDGE_FALLTHRU);
}
- if (e->src->succ->succ_next)
+ if (e->src->succ->succ_next || abnormal_edge_flags)
{
/* Create the new structures. */
+
+ /* Position the new block correctly relative to loop notes. */
note = last_loop_beg_note (e->src->end);
- jump_block
- = create_basic_block (NEXT_INSN (note), NULL, e->src);
+ note = NEXT_INSN (note);
+
+ /* ... and ADDR_VECs. */
+ if (note != NULL
+ && GET_CODE (note) == CODE_LABEL
+ && NEXT_INSN (note)
+ && GET_CODE (NEXT_INSN (note)) == JUMP_INSN
+ && (GET_CODE (PATTERN (NEXT_INSN (note))) == ADDR_DIFF_VEC
+ || GET_CODE (PATTERN (NEXT_INSN (note))) == ADDR_VEC))
+ note = NEXT_INSN (NEXT_INSN (note));
+
+ jump_block = create_basic_block (note, NULL, e->src);
jump_block->count = e->count;
jump_block->frequency = EDGE_FREQUENCY (e);
jump_block->loop_depth = target->loop_depth;
emit_barrier_after (jump_block->end);
redirect_edge_succ_nodup (e, target);
+ if (abnormal_edge_flags)
+ make_edge (src, target, abnormal_edge_flags);
+
return new_bb;
}
{
rtx insn;
int count = 0;
+ basic_block bb;
- if (bb1->index > bb2->index)
- return false;
- else if (bb1->index == bb2->index)
+ if (bb1 == bb2)
return true;
+ /* ??? Could we guarantee that bb indices are monotone, so that we could
+ just compare them? */
+ for (bb = bb1; bb && bb != bb2; bb = bb->next_bb)
+ continue;
+
+ if (!bb)
+ return false;
+
for (insn = bb1->end; insn != bb2->head && count >= 0;
insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE)
edge edge_in;
{
basic_block bb;
- edge edge_out;
rtx before;
/* Abnormal edges cannot be split. */
edge_in->dest->global_live_at_start);
}
- edge_out = make_single_succ_edge (bb, edge_in->dest, EDGE_FALLTHRU);
+ make_single_succ_edge (bb, edge_in->dest, EDGE_FALLTHRU);
/* For non-fallthry edges, we must adjust the predecessor's
jump instruction to target our new block. */
int watch_calls;
{
rtx before = NULL_RTX, after = NULL_RTX, insns, tmp, last;
- basic_block bb;
+ basic_block bb = NULL;
/* Pull the insns off the edge now since the edge might go away. */
insns = e->insns;
if (before)
{
- emit_insns_before (insns, before);
+ emit_insn_before (insns, before);
last = prev_nonnote_insn (before);
}
else
- last = emit_insns_after (insns, after);
+ last = emit_insn_after (insns, after);
if (returnjump_p (last))
{
basic_block *bb_info, *last_visited;
size_t *edge_checksum;
rtx x;
- int i, num_bb_notes, err = 0;
+ int num_bb_notes, err = 0;
basic_block bb, last_bb_seen;
bb_info = (basic_block *) xcalloc (max_uid, sizeof (basic_block));
err = 1;
}
- /* For now, also check that we didn't change the order. */
- if (bb != EXIT_BLOCK_PTR && bb->index != last_bb_seen->index + 1)
- {
- error ("Wrong order of blocks %d and %d",
- last_bb_seen->index, bb->index);
- err = 1;
- }
-
- if (bb == EXIT_BLOCK_PTR && last_bb_seen->index != n_basic_blocks - 1)
- {
- error ("Only %d of %d blocks in chain",
- last_bb_seen->index + 1, n_basic_blocks);
- err = 1;
- }
-
last_bb_seen = bb;
}
if (e->flags & EDGE_FALLTHRU)
n_fallthru++;
- if ((e->flags & ~EDGE_DFS_BACK) == 0)
+ if ((e->flags & ~(EDGE_DFS_BACK | EDGE_CAN_FALLTHRU)) == 0)
n_branch++;
if (e->flags & EDGE_ABNORMAL_CALL)
}
for (x = bb->head; x != NEXT_INSN (bb->end); x = NEXT_INSN (x))
- if (basic_block_for_insn && BLOCK_FOR_INSN (x) != bb)
+ if (BLOCK_FOR_INSN (x) != bb)
{
debug_rtx (x);
if (! BLOCK_FOR_INSN (x))
if (x == bb->end)
break;
- if (GET_CODE (x) == JUMP_INSN
- || GET_CODE (x) == CODE_LABEL
- || GET_CODE (x) == BARRIER)
+ if (control_flow_insn_p (x))
{
error ("in basic block %d:", bb->index);
fatal_insn ("flow control insn inside a basic block", x);
edge_checksum[e->dest->index + 2] -= (size_t) e;
}
- for (i = -2; i < n_basic_blocks; ++i)
- if (edge_checksum[i + 2])
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+ if (edge_checksum[bb->index + 2])
{
- error ("basic block %i edge lists are corrupted", i);
+ error ("basic block %i edge lists are corrupted", bb->index);
err = 1;
}
{
if (NOTE_INSN_BASIC_BLOCK_P (x))
{
- basic_block bb = NOTE_BASIC_BLOCK (x);
+ bb = NOTE_BASIC_BLOCK (x);
num_bb_notes++;
if (bb != last_bb_seen->next_bb)