From: hubicka Date: Mon, 5 Nov 2001 15:38:01 +0000 (+0000) Subject: * Makefile.in (bb-reoder.o): Add depdendency on cfglayout.h; X-Git-Tag: upstream/4.9.2~91132 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=521a4359f7f50790563d9b5a8fc83c09ad433c63;p=platform%2Fupstream%2Flinaro-gcc.git * Makefile.in (bb-reoder.o): Add depdendency on cfglayout.h; remove unneded depdendencies; (cfglayout.o): New. * cfglayout.c, cfglayout.h: New files; break out from ... * bb-reorder.c: ... here; Remove unneeded includes; git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@46786 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 639fb48..4117491 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +Mon Nov 5 16:15:25 CET 2001 Jan Hubicka + + * Makefile.in (bb-reoder.o): Add depdendency on cfglayout.h; + remove unneded depdendencies; + (cfglayout.o): New. + * cfglayout.c, cfglayout.h: New files; break out from ... + * bb-reorder.c: ... here; Remove unneeded includes; + 2001-11-04 Alan Modra * config/rs6000/rs6000.md (load_toc_aix_{si,di}): Mark r2 as used. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 34433f1..8cb7fe4 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -742,7 +742,7 @@ OBJS = alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o \ sbitmap.o sched-deps.o sched-ebb.o sched-rgn.o sched-vis.o sdbout.o \ sibcall.o simplify-rtx.o splay-tree.o ssa.o ssa-ccp.o ssa-dce.o stmt.o \ stor-layout.o stringpool.o timevar.o toplev.o tree.o tree-inline.o \ - unroll.o varasm.o varray.o version.o xcoffout.o \ + unroll.o varasm.o varray.o version.o xcoffout.o cfglayout.o \ $(GGC) $(out_object_file) $(EXTRA_OBJS) BACKEND = main.o libbackend.a @@ -1578,8 +1578,10 @@ predict.o: predict.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \ $(RECOG_H) function.h except.h $(EXPR_H) $(TM_P_H) $(PREDICT_H) lists.o: lists.c $(CONFIG_H) $(SYSTEM_H) toplev.h $(RTL_H) $(GGC_H) bb-reorder.o : bb-reorder.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \ - insn-config.h $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h \ - $(RECOG_H) function.h except.h $(EXPR_H) $(TM_P_H) + $(BASIC_BLOCK_H) hard-reg-set.h output.h cfglayout.h +cfglayout.o : cfglayout.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) \ + insn-config.h $(BASIC_BLOCK_H) hard-reg-set.h output.h function.h \ + cfglayout.h timevar.o : timevar.c $(CONFIG_H) $(SYSTEM_H) $(TIMEVAR_H) flags.h intl.h regrename.o : regrename.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) insn-config.h \ $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h $(RECOG_H) function.h \ diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c index aa30315..72cf90c 100644 --- a/gcc/bb-reorder.c +++ b/gcc/bb-reorder.c @@ -84,234 +84,20 @@ #include "system.h" #include "tree.h" #include "rtl.h" -#include "tm_p.h" #include "hard-reg-set.h" #include "basic-block.h" -#include "insn-config.h" -#include "regs.h" #include "flags.h" #include "output.h" -#include "function.h" -#include "toplev.h" -#include "recog.h" -#include "expr.h" -#include "obstack.h" - +#include "cfglayout.h" #ifndef HAVE_epilogue #define HAVE_epilogue 0 #endif - -/* The contents of the current function definition are allocated - in this obstack, and all are freed at the end of the function. - For top-level functions, this is temporary_obstack. - Separate obstacks are made for nested functions. */ - -extern struct obstack flow_obstack; - - -/* Structure to hold information about lexical scopes. */ -typedef struct scope_def -{ - int level; - - /* The NOTE_INSN_BLOCK_BEG that started this scope. */ - rtx note_beg; - - /* The NOTE_INSN_BLOCK_END that ended this scope. */ - rtx note_end; - - /* The bb containing note_beg (if any). */ - basic_block bb_beg; - - /* The bb containing note_end (if any). */ - basic_block bb_end; - - /* List of basic blocks contained within this scope. */ - basic_block *bbs; - - /* Number of blocks contained within this scope. */ - int num_bbs; - - /* The outer scope or NULL if outermost scope. */ - struct scope_def *outer; - - /* The first inner scope or NULL if innermost scope. */ - struct scope_def *inner; - - /* The last inner scope or NULL if innermost scope. */ - struct scope_def *inner_last; - - /* Link to the next (sibling) scope. */ - struct scope_def *next; -} *scope; - - -/* Structure to hold information about the scope forest. */ -typedef struct -{ - /* Number of trees in forest. */ - int num_trees; - - /* List of tree roots. */ - scope *trees; -} scope_forest_info; - -/* Structure to hold information about the blocks during reordering. */ -typedef struct reorder_block_def -{ - rtx eff_head; - rtx eff_end; - scope scope; - basic_block next; - int visited; -} *reorder_block_def; - -#define RBI(BB) ((reorder_block_def) (BB)->aux) - -/* Holds the interesting trailing notes for the function. */ -static rtx function_tail_eff_head; - - /* Local function prototypes. */ -static rtx skip_insns_after_block PARAMS ((basic_block)); -static void record_effective_endpoints PARAMS ((void)); static void make_reorder_chain PARAMS ((void)); static basic_block make_reorder_chain_1 PARAMS ((basic_block, basic_block)); -static rtx label_for_bb PARAMS ((basic_block)); -static void fixup_reorder_chain PARAMS ((void)); -static void relate_bbs_with_scopes PARAMS ((scope)); -static scope make_new_scope PARAMS ((int, rtx)); -static void build_scope_forest PARAMS ((scope_forest_info *)); -static void remove_scope_notes PARAMS ((void)); -static void insert_intra_1 PARAMS ((scope, rtx *, basic_block)); -static void insert_intra_bb_scope_notes PARAMS ((basic_block)); -static void insert_inter_bb_scope_notes PARAMS ((basic_block, basic_block)); -static void rebuild_scope_notes PARAMS ((scope_forest_info *)); -static void free_scope_forest_1 PARAMS ((scope)); -static void free_scope_forest PARAMS ((scope_forest_info *)); -void dump_scope_forest PARAMS ((scope_forest_info *)); -static void dump_scope_forest_1 PARAMS ((scope, int)); -static rtx get_next_bb_note PARAMS ((rtx)); -static rtx get_prev_bb_note PARAMS ((rtx)); - -void verify_insn_chain PARAMS ((void)); -/* Skip over inter-block insns occurring after BB which are typically - associated with BB (e.g., barriers). If there are any such insns, - we return the last one. Otherwise, we return the end of BB. */ - -static rtx -skip_insns_after_block (bb) - basic_block bb; -{ - rtx insn, last_insn, next_head, prev; - - next_head = NULL_RTX; - if (bb->index + 1 != n_basic_blocks) - next_head = BASIC_BLOCK (bb->index + 1)->head; - - for (last_insn = insn = bb->end; (insn = NEXT_INSN (insn)); ) - { - if (insn == next_head) - break; - - switch (GET_CODE (insn)) - { - case BARRIER: - last_insn = insn; - continue; - - case NOTE: - switch (NOTE_LINE_NUMBER (insn)) - { - case NOTE_INSN_LOOP_END: - case NOTE_INSN_BLOCK_END: - last_insn = insn; - continue; - case NOTE_INSN_DELETED: - case NOTE_INSN_DELETED_LABEL: - continue; - - default: - continue; - break; - } - break; - - case CODE_LABEL: - if (NEXT_INSN (insn) - && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN - && (GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_VEC - || GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_DIFF_VEC)) - { - insn = NEXT_INSN (insn); - last_insn = insn; - continue; - } - break; - - default: - break; - } - - break; - } - /* It is possible to hit contradicting sequence. For instance: - - jump_insn - NOTE_INSN_LOOP_BEG - barrier - - Where barrier belongs to jump_insn, but the note does not. - This can be created by removing the basic block originally - following NOTE_INSN_LOOP_BEG. - - In such case reorder the notes. */ - for (insn = last_insn; insn != bb->end; insn = prev) - { - prev = PREV_INSN (insn); - if (GET_CODE (insn) == NOTE) - switch (NOTE_LINE_NUMBER (insn)) - { - case NOTE_INSN_LOOP_END: - case NOTE_INSN_BLOCK_END: - case NOTE_INSN_DELETED: - case NOTE_INSN_DELETED_LABEL: - continue; - default: - reorder_insns (insn, insn, last_insn); - } - } - - return last_insn; -} - - -/* Locate the effective beginning and end of the insn chain for each - block, as defined by skip_insns_after_block above. */ - -static void -record_effective_endpoints () -{ - rtx next_insn = get_insns (); - int i; - - for (i = 0; i < n_basic_blocks; ++i) - { - basic_block bb = BASIC_BLOCK (i); - rtx end; - - RBI (bb)->eff_head = next_insn; - end = skip_insns_after_block (bb); - RBI (bb)->eff_end = end; - next_insn = NEXT_INSN (end); - } - function_tail_eff_head = next_insn; -} - - /* Compute an ordering for a subgraph beginning with block BB. Record the ordering in RBI()->index and chained through RBI()->next. */ @@ -489,872 +275,20 @@ make_reorder_chain_1 (bb, prev) return prev; } - -/* Locate or create a label for a given basic block. */ - -static rtx -label_for_bb (bb) - basic_block bb; -{ - rtx label = bb->head; - - if (GET_CODE (label) != CODE_LABEL) - { - if (rtl_dump_file) - fprintf (rtl_dump_file, "Emitting label for block %d\n", - bb->index); - - label = block_label (bb); - if (bb->head == PREV_INSN (RBI (bb)->eff_head)) - RBI (bb)->eff_head = label; - } - - return label; -} - - -/* Given a reorder chain, rearrange the code to match. */ - -static void -fixup_reorder_chain () -{ - basic_block bb, last_bb; - int index; - rtx insn; - int old_n_basic_blocks = n_basic_blocks; - - /* First do the bulk reordering -- rechain the blocks without regard to - the needed changes to jumps and labels. */ - - last_bb = BASIC_BLOCK (0); - bb = RBI (last_bb)->next; - index = 1; - while (bb) - { - rtx last_e = RBI (last_bb)->eff_end; - rtx curr_h = RBI (bb)->eff_head; - - NEXT_INSN (last_e) = curr_h; - PREV_INSN (curr_h) = last_e; - - last_bb = bb; - bb = RBI (bb)->next; - index++; - } - - if (index != n_basic_blocks) - abort (); - - insn = RBI (last_bb)->eff_end; - - NEXT_INSN (insn) = function_tail_eff_head; - if (function_tail_eff_head) - PREV_INSN (function_tail_eff_head) = insn; - - while (NEXT_INSN (insn)) - insn = NEXT_INSN (insn); - set_last_insn (insn); -#ifdef ENABLE_CHECKING - verify_insn_chain (); -#endif - - /* Now add jumps and labels as needed to match the blocks new - outgoing edges. */ - - for (bb = BASIC_BLOCK (0); bb ; bb = RBI (bb)->next) - { - edge e_fall, e_taken, e; - rtx bb_end_insn; - basic_block nb; - - if (bb->succ == NULL) - continue; - - /* Find the old fallthru edge, and another non-EH edge for - a taken jump. */ - e_taken = e_fall = NULL; - for (e = bb->succ; e ; e = e->succ_next) - if (e->flags & EDGE_FALLTHRU) - e_fall = e; - else if (! (e->flags & EDGE_EH)) - e_taken = e; - - bb_end_insn = bb->end; - if (GET_CODE (bb_end_insn) == JUMP_INSN) - { - if (any_condjump_p (bb_end_insn)) - { - /* If the old fallthru is still next, nothing to do. */ - if (RBI (bb)->next == e_fall->dest - || (!RBI (bb)->next - && e_fall->dest == EXIT_BLOCK_PTR)) - continue; - - /* There is one special case: if *neither* block is next, - such as happens at the very end of a function, then we'll - need to add a new unconditional jump. Choose the taken - edge based on known or assumed probability. */ - if (RBI (bb)->next != e_taken->dest) - { - rtx note = find_reg_note (bb_end_insn, REG_BR_PROB, 0); - if (note - && INTVAL (XEXP (note, 0)) < REG_BR_PROB_BASE / 2 - && invert_jump (bb_end_insn, - label_for_bb (e_fall->dest), 0)) - { - e_fall->flags &= ~EDGE_FALLTHRU; - e_taken->flags |= EDGE_FALLTHRU; - e = e_fall, e_fall = e_taken, e_taken = e; - } - } - - /* Otherwise we can try to invert the jump. This will - basically never fail, however, keep up the pretense. */ - else if (invert_jump (bb_end_insn, - label_for_bb (e_fall->dest), 0)) - { - e_fall->flags &= ~EDGE_FALLTHRU; - e_taken->flags |= EDGE_FALLTHRU; - continue; - } - } - else if (returnjump_p (bb_end_insn)) - continue; - else - { - /* Otherwise we have some switch or computed jump. In the - 99% case, there should not have been a fallthru edge. */ - if (! e_fall) - continue; -#ifdef CASE_DROPS_THROUGH - /* Except for VAX. Since we didn't have predication for the - tablejump, the fallthru block should not have moved. */ - if (RBI (bb)->next == e_fall->dest) - continue; - bb_end_insn = skip_insns_after_block (bb); -#else - abort (); -#endif - } - } - else - { - /* No fallthru implies a noreturn function with EH edges, or - something similarly bizarre. In any case, we don't need to - do anything. */ - if (! e_fall) - continue; - - /* If the fallthru block is still next, nothing to do. */ - if (RBI (bb)->next == e_fall->dest) - continue; - - /* An fallthru to exit block. */ - if (!RBI (bb)->next && e_fall->dest == EXIT_BLOCK_PTR) - continue; - } - - /* We got here if we need to add a new jump insn. */ - - nb = force_nonfallthru (e_fall); - - if (nb) - { - alloc_aux_for_block (nb, sizeof (struct reorder_block_def)); - RBI (nb)->eff_head = nb->head; - RBI (nb)->eff_end = NEXT_INSN (nb->end); - RBI (nb)->scope = RBI (bb)->scope; - RBI (nb)->visited = 1; - RBI (nb)->next = RBI (bb)->next; - RBI (bb)->next = nb; - /* Don't process this new block. */ - bb = nb; - } - } - - /* Put basic_block_info in the new order. */ - bb = BASIC_BLOCK (0); - index = 0; - - if (rtl_dump_file) - fprintf (rtl_dump_file, "Reordered sequence:\n"); - while (bb) - { - if (rtl_dump_file) - fprintf (rtl_dump_file, " %i %sbb %i freq %i\n", index, - bb->index >= old_n_basic_blocks ? "compensation " : "", - bb->index, - bb->frequency); - bb->index = index; - BASIC_BLOCK (index) = bb; - - bb = RBI (bb)->next; - index++; - } -} - - -/* Perform sanity checks on the insn chain. - 1. Check that next/prev pointers are consistent in both the forward and - reverse direction. - 2. Count insns in chain, going both directions, and check if equal. - 3. Check that get_last_insn () returns the actual end of chain. */ - -void -verify_insn_chain () -{ - rtx x, - prevx, - nextx; - int insn_cnt1, - insn_cnt2; - - prevx = NULL; - insn_cnt1 = 1; - for (x = get_insns (); x; x = NEXT_INSN (x)) - { - if (PREV_INSN (x) != prevx) - { - fprintf (stderr, "Forward traversal: insn chain corrupt.\n"); - fprintf (stderr, "previous insn:\n"); - debug_rtx (prevx); - fprintf (stderr, "current insn:\n"); - debug_rtx (x); - abort (); - } - ++insn_cnt1; - prevx = x; - } - - if (prevx != get_last_insn ()) - { - fprintf (stderr, "last_insn corrupt.\n"); - abort (); - } - - nextx = NULL; - insn_cnt2 = 1; - for (x = get_last_insn (); x; x = PREV_INSN (x)) - { - if (NEXT_INSN (x) != nextx) - { - fprintf (stderr, "Reverse traversal: insn chain corrupt.\n"); - fprintf (stderr, "current insn:\n"); - debug_rtx (x); - fprintf (stderr, "next insn:\n"); - debug_rtx (nextx); - abort (); - } - ++insn_cnt2; - nextx = x; - } - - if (insn_cnt1 != insn_cnt2) - { - fprintf (stderr, "insn_cnt1 (%d) not equal to insn_cnt2 (%d).\n", - insn_cnt1, insn_cnt2); - abort (); - } -} - -static rtx -get_next_bb_note (x) - rtx x; -{ - while (x) - { - if (NOTE_INSN_BASIC_BLOCK_P (x)) - return x; - x = NEXT_INSN (x); - } - return NULL; -} - - -static rtx -get_prev_bb_note (x) - rtx x; -{ - while (x) - { - if (NOTE_INSN_BASIC_BLOCK_P (x)) - return x; - x = PREV_INSN (x); - } - return NULL; -} - - -/* Determine and record the relationships between basic blocks and - scopes in scope tree S. */ - -static void -relate_bbs_with_scopes (s) - scope s; -{ - scope p; - int i, bbi1, bbi2, bbs_spanned; - rtx bbnote; - - for (p = s->inner; p; p = p->next) - relate_bbs_with_scopes (p); - - bbi1 = bbi2 = -1; - bbs_spanned = 0; - - /* If the begin and end notes are both inside the same basic block, - or if they are both outside of basic blocks, then we know immediately - how they are related. Otherwise, we need to poke around to make the - determination. */ - if (s->bb_beg != s->bb_end) - { - if (s->bb_beg && s->bb_end) - { - /* Both notes are in different bbs. This implies that all the - basic blocks spanned by the pair of notes are contained in - this scope. */ - bbi1 = s->bb_beg->index; - bbi2 = s->bb_end->index; - bbs_spanned = 1; - } - else if (! s->bb_beg) - { - /* First note is outside of a bb. If the scope spans more than - one basic block, then they all are contained within this - scope. Otherwise, this scope is contained within the basic - block. */ - bbnote = get_next_bb_note (s->note_beg); - if (! bbnote) - abort (); - if (NOTE_BASIC_BLOCK (bbnote) == s->bb_end) - { - bbs_spanned = 0; - s->bb_beg = NOTE_BASIC_BLOCK (bbnote); - } - else - { - bbi1 = NOTE_BASIC_BLOCK (bbnote)->index; - bbi2 = s->bb_end->index; - s->bb_end = NULL; - bbs_spanned = 1; - } - } - else /* ! s->bb_end */ - { - /* Second note is outside of a bb. If the scope spans more than - one basic block, then they all are contained within this - scope. Otherwise, this scope is contained within the basic - block. */ - bbnote = get_prev_bb_note (s->note_end); - if (! bbnote) - abort (); - if (NOTE_BASIC_BLOCK (bbnote) == s->bb_beg) - { - bbs_spanned = 0; - s->bb_end = NOTE_BASIC_BLOCK (bbnote); - } - else - { - bbi1 = s->bb_beg->index; - bbi2 = NOTE_BASIC_BLOCK (bbnote)->index; - s->bb_beg = NULL; - bbs_spanned = 1; - } - } - } - else - { - if (s->bb_beg) - /* Both notes are in the same bb, which implies the block - contains this scope. */ - bbs_spanned = 0; - else - { - rtx x1, x2; - /* Both notes are outside of any bbs. This implies that all the - basic blocks spanned by the pair of notes are contained in - this scope. - There is a degenerate case to consider. If the notes do not - span any basic blocks, then it is an empty scope that can - safely be deleted or ignored. Mark these with level = -1. */ - - x1 = get_next_bb_note (s->note_beg); - x2 = get_prev_bb_note (s->note_end); - if (! (x1 && x2)) - { - s->level = -1; - bbs_spanned = 0; - } - else - { - bbi1 = NOTE_BASIC_BLOCK (x1)->index; - bbi2 = NOTE_BASIC_BLOCK (x2)->index; - bbs_spanned = 1; - } - } - } - - /* If the scope spans one or more basic blocks, we record them. We - only record the bbs that are immediately contained within this - scope. Note that if a scope is contained within a bb, we can tell - by checking that bb_beg = bb_end and that they are non-null. */ - if (bbs_spanned) - { - int j = 0; - - s->num_bbs = 0; - for (i = bbi1; i <= bbi2; i++) - if (! RBI (BASIC_BLOCK (i))->scope) - s->num_bbs++; - - s->bbs = xmalloc (s->num_bbs * sizeof (basic_block)); - for (i = bbi1; i <= bbi2; i++) - { - basic_block curr_bb = BASIC_BLOCK (i); - if (! RBI (curr_bb)->scope) - { - s->bbs[j++] = curr_bb; - RBI (curr_bb)->scope = s; - } - } - } - else - s->num_bbs = 0; -} - - -/* Allocate and initialize a new scope structure with scope level LEVEL, - and record the NOTE beginning the scope. */ - -static scope -make_new_scope (level, note) - int level; - rtx note; -{ - scope new_scope = xcalloc (1, sizeof (struct scope_def)); - new_scope->level = level; - new_scope->note_beg = note; - return new_scope; -} - - -/* Build a forest representing the scope structure of the function. - Return a pointer to a structure describing the forest. */ - -static void -build_scope_forest (forest) - scope_forest_info *forest; -{ - rtx x; - int level, bbi, i; - basic_block curr_bb; - scope root, curr_scope = 0; - - forest->num_trees = 0; - forest->trees = NULL; - level = -1; - root = NULL; - curr_bb = NULL; - bbi = 0; - for (x = get_insns (); x; x = NEXT_INSN (x)) - { - if (bbi < n_basic_blocks && x == BASIC_BLOCK (bbi)->head) - curr_bb = BASIC_BLOCK (bbi); - - if (GET_CODE (x) == NOTE) - { - if (NOTE_LINE_NUMBER (x) == NOTE_INSN_BLOCK_BEG) - { - if (root) - { - scope new_scope; - if (! curr_scope) - abort(); - level++; - new_scope = make_new_scope (level, x); - new_scope->outer = curr_scope; - new_scope->next = NULL; - if (! curr_scope->inner) - { - curr_scope->inner = new_scope; - curr_scope->inner_last = new_scope; - } - else - { - curr_scope->inner_last->next = new_scope; - curr_scope->inner_last = new_scope; - } - curr_scope = curr_scope->inner_last; - } - else - { - int ntrees = forest->num_trees; - level++; - curr_scope = make_new_scope (level, x); - root = curr_scope; - forest->trees = xrealloc (forest->trees, - sizeof (scope) * (ntrees + 1)); - forest->trees[forest->num_trees++] = root; - } - curr_scope->bb_beg = curr_bb; - } - else if (NOTE_LINE_NUMBER (x) == NOTE_INSN_BLOCK_END) - { - curr_scope->bb_end = curr_bb; - curr_scope->note_end = x; - level--; - curr_scope = curr_scope->outer; - if (level == -1) - root = NULL; - } - } /* if note */ - - if (curr_bb && curr_bb->end == x) - { - curr_bb = NULL; - bbi++; - } - - } /* for */ - - for (i = 0; i < forest->num_trees; i++) - relate_bbs_with_scopes (forest->trees[i]); -} - - -/* Remove all the NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes from - the insn chain. */ - -static void -remove_scope_notes () -{ - rtx x, next; - basic_block currbb = NULL; - - for (x = get_insns (); x; x = next) - { - next = NEXT_INSN (x); - if (NOTE_INSN_BASIC_BLOCK_P (x)) - currbb = NOTE_BASIC_BLOCK (x); - - if (GET_CODE (x) == NOTE - && (NOTE_LINE_NUMBER (x) == NOTE_INSN_BLOCK_BEG - || NOTE_LINE_NUMBER (x) == NOTE_INSN_BLOCK_END)) - { - /* Check if the scope note happens to be the end of a bb. */ - if (currbb && x == currbb->end) - currbb->end = PREV_INSN (x); - if (currbb && x == currbb->head) - abort (); - - if (PREV_INSN (x)) - { - NEXT_INSN (PREV_INSN (x)) = next; - PREV_INSN (next) = PREV_INSN (x); - - NEXT_INSN (x) = NULL; - PREV_INSN (x) = NULL; - } - else - abort (); - } - } -} - - -/* Insert scope note pairs for a contained scope tree S after insn IP. */ - -static void -insert_intra_1 (s, ip, bb) - scope s; - rtx *ip; - basic_block bb; -{ - scope p; - - if (NOTE_BLOCK (s->note_beg)) - { - *ip = emit_note_after (NOTE_INSN_BLOCK_BEG, *ip); - NOTE_BLOCK (*ip) = NOTE_BLOCK (s->note_beg); - } - - for (p = s->inner; p; p = p->next) - insert_intra_1 (p, ip, bb); - - if (NOTE_BLOCK (s->note_beg)) - { - *ip = emit_note_after (NOTE_INSN_BLOCK_END, *ip); - NOTE_BLOCK (*ip) = NOTE_BLOCK (s->note_end); - } -} - - -/* Insert NOTE_INSN_BLOCK_END notes and NOTE_INSN_BLOCK_BEG notes for - scopes that are contained within BB. */ - -static void -insert_intra_bb_scope_notes (bb) - basic_block bb; -{ - scope s = RBI (bb)->scope; - scope p; - rtx ip; - - if (! s) - return; - - ip = bb->head; - if (GET_CODE (ip) == CODE_LABEL) - ip = NEXT_INSN (ip); - - for (p = s->inner; p; p = p->next) - { - if (p->bb_beg != NULL && p->bb_beg == p->bb_end && p->bb_beg == bb) - insert_intra_1 (p, &ip, bb); - } -} - - -/* Given two consecutive basic blocks BB1 and BB2 with different scopes, - insert NOTE_INSN_BLOCK_END notes after BB1 and NOTE_INSN_BLOCK_BEG - notes before BB2 such that the notes are correctly balanced. If BB1 or - BB2 is NULL, we are inserting scope notes for the first and last basic - blocks, respectively. */ - -static void -insert_inter_bb_scope_notes (bb1, bb2) - basic_block bb1; - basic_block bb2; -{ - rtx ip; - scope com; - - /* It is possible that a basic block is not contained in any scope. - In that case, we either open or close a scope but not both. */ - if (bb1 && bb2) - { - scope s1 = RBI (bb1)->scope; - scope s2 = RBI (bb2)->scope; - if (! s1 && ! s2) - return; - if (! s1) - bb1 = NULL; - else if (! s2) - bb2 = NULL; - } - - /* Find common ancestor scope. */ - if (bb1 && bb2) - { - scope s1 = RBI (bb1)->scope; - scope s2 = RBI (bb2)->scope; - while (s1 != s2) - { - if (! (s1 && s2)) - abort (); - if (s1->level > s2->level) - s1 = s1->outer; - else if (s2->level > s1->level) - s2 = s2->outer; - else - { - s1 = s1->outer; - s2 = s2->outer; - } - } - com = s1; - } - else - com = NULL; - - /* Close scopes. */ - if (bb1) - { - rtx end = bb1->end; - - scope s = RBI (bb1)->scope; - ip = RBI (bb1)->eff_end; - while (s != com) - { - if (NOTE_BLOCK (s->note_beg)) - { - ip = emit_note_after (NOTE_INSN_BLOCK_END, ip); - NOTE_BLOCK (ip) = NOTE_BLOCK (s->note_end); - } - s = s->outer; - } - /* Emitting note may move the end of basic block to unwanted place. */ - bb1->end = end; - } - - /* Open scopes. */ - if (bb2) - { - scope s = RBI (bb2)->scope; - ip = bb2->head; - while (s != com) - { - if (NOTE_BLOCK (s->note_beg)) - { - ip = emit_note_before (NOTE_INSN_BLOCK_BEG, ip); - NOTE_BLOCK (ip) = NOTE_BLOCK (s->note_beg); - } - s = s->outer; - } - } -} - - -/* Rebuild all the NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes based - on the scope forest and the newly reordered basic blocks. */ - -static void -rebuild_scope_notes (forest) - scope_forest_info *forest; -{ - int i; - - if (forest->num_trees == 0) - return; - - /* Start by opening the scopes before the first basic block. */ - insert_inter_bb_scope_notes (NULL, BASIC_BLOCK (0)); - - /* Then, open and close scopes as needed between blocks. */ - for (i = 0; i < n_basic_blocks - 1; i++) - { - basic_block bb1 = BASIC_BLOCK (i); - basic_block bb2 = BASIC_BLOCK (i + 1); - if (RBI (bb1)->scope != RBI (bb2)->scope) - insert_inter_bb_scope_notes (bb1, bb2); - insert_intra_bb_scope_notes (bb1); - } - - /* Finally, close the scopes after the last basic block. */ - insert_inter_bb_scope_notes (BASIC_BLOCK (n_basic_blocks - 1), NULL); - insert_intra_bb_scope_notes (BASIC_BLOCK (n_basic_blocks - 1)); -} - - -/* Free the storage associated with the scope tree at S. */ - -static void -free_scope_forest_1 (s) - scope s; -{ - scope p, next; - - for (p = s->inner; p; p = next) - { - next = p->next; - free_scope_forest_1 (p); - } - - if (s->bbs) - free (s->bbs); - free (s); -} - - -/* Free the storage associated with the scope forest. */ - -static void -free_scope_forest (forest) - scope_forest_info *forest; -{ - int i; - for (i = 0; i < forest->num_trees; i++) - free_scope_forest_1 (forest->trees[i]); -} - - -/* Visualize the scope forest. */ - -void -dump_scope_forest (forest) - scope_forest_info *forest; -{ - if (forest->num_trees == 0) - fprintf (stderr, "\n< Empty scope forest >\n"); - else - { - int i; - fprintf (stderr, "\n< Scope forest >\n"); - for (i = 0; i < forest->num_trees; i++) - dump_scope_forest_1 (forest->trees[i], 0); - } -} - - -/* Recursive portion of dump_scope_forest. */ - -static void -dump_scope_forest_1 (s, indent) - scope s; - int indent; -{ - scope p; - int i; - - if (s->bb_beg != NULL && s->bb_beg == s->bb_end - && RBI (s->bb_beg)->scope - && RBI (s->bb_beg)->scope->level + 1 == s->level) - { - fprintf (stderr, "%*s", indent, ""); - fprintf (stderr, "BB%d:\n", s->bb_beg->index); - } - - fprintf (stderr, "%*s", indent, ""); - fprintf (stderr, "{ level %d (block %p)\n", s->level, - (PTR) NOTE_BLOCK (s->note_beg)); - - fprintf (stderr, "%*s%s", indent, "", "bbs:"); - for (i = 0; i < s->num_bbs; i++) - fprintf (stderr, " %d", s->bbs[i]->index); - fprintf (stderr, "\n"); - - for (p = s->inner; p; p = p->next) - dump_scope_forest_1 (p, indent + 2); - - fprintf (stderr, "%*s", indent, ""); - fprintf (stderr, "}\n"); -} - - /* Reorder basic blocks. The main entry point to this file. */ void reorder_basic_blocks () { - scope_forest_info forest; - if (n_basic_blocks <= 1) return; - alloc_aux_for_blocks (sizeof (struct reorder_block_def)); + cfg_layout_initialize (); - build_scope_forest (&forest); - remove_scope_notes (); - - record_effective_endpoints (); make_reorder_chain (); if (rtl_dump_file) dump_flow_info (rtl_dump_file); - fixup_reorder_chain (); - -#ifdef ENABLE_CHECKING - verify_insn_chain (); -#endif - - rebuild_scope_notes (&forest); - free_scope_forest (&forest); - reorder_blocks (); - - free_aux_for_blocks (); - -#ifdef ENABLE_CHECKING - verify_flow_info (); -#endif + cfg_layout_finalize (); } diff --git a/gcc/cfglayout.c b/gcc/cfglayout.c new file mode 100644 index 0000000..896eda6 --- /dev/null +++ b/gcc/cfglayout.c @@ -0,0 +1,1079 @@ +/* Basic block reordering routines for the GNU compiler. + Copyright (C) 2000 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "rtl.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "insn-config.h" +#include "output.h" +#include "function.h" +#include "obstack.h" +#include "cfglayout.h" + +/* The contents of the current function definition are allocated + in this obstack, and all are freed at the end of the function. + For top-level functions, this is temporary_obstack. + Separate obstacks are made for nested functions. */ + +extern struct obstack flow_obstack; + +/* Structure to hold information about lexical scopes. */ +struct scope_def +{ + int level; + + /* The NOTE_INSN_BLOCK_BEG that started this scope. */ + rtx note_beg; + + /* The NOTE_INSN_BLOCK_END that ended this scope. */ + rtx note_end; + + /* The bb containing note_beg (if any). */ + basic_block bb_beg; + + /* The bb containing note_end (if any). */ + basic_block bb_end; + + /* List of basic blocks contained within this scope. */ + basic_block *bbs; + + /* Number of blocks contained within this scope. */ + int num_bbs; + + /* The outer scope or NULL if outermost scope. */ + struct scope_def *outer; + + /* The first inner scope or NULL if innermost scope. */ + struct scope_def *inner; + + /* The last inner scope or NULL if innermost scope. */ + struct scope_def *inner_last; + + /* Link to the next (sibling) scope. */ + struct scope_def *next; +}; + +/* Structure to hold information about the scope forest. */ +typedef struct +{ + /* Number of trees in forest. */ + int num_trees; + + /* List of tree roots. */ + scope *trees; +} scope_forest_info; + +/* Holds the interesting trailing notes for the function. */ +static rtx function_tail_eff_head; + +/* The scope forst of current function. */ +static scope_forest_info forest; + +static rtx skip_insns_after_block PARAMS ((basic_block)); +static void record_effective_endpoints PARAMS ((void)); +static rtx label_for_bb PARAMS ((basic_block)); +static void fixup_reorder_chain PARAMS ((void)); + +static void relate_bbs_with_scopes PARAMS ((scope)); +static scope make_new_scope PARAMS ((int, rtx)); +static void build_scope_forest PARAMS ((scope_forest_info *)); +static void remove_scope_notes PARAMS ((void)); +static void insert_intra_1 PARAMS ((scope, rtx *, basic_block)); +static void insert_intra_bb_scope_notes PARAMS ((basic_block)); +static void insert_inter_bb_scope_notes PARAMS ((basic_block, basic_block)); +static void rebuild_scope_notes PARAMS ((scope_forest_info *)); +static void free_scope_forest_1 PARAMS ((scope)); +static void free_scope_forest PARAMS ((scope_forest_info *)); +void dump_scope_forest PARAMS ((scope_forest_info *)); +static void dump_scope_forest_1 PARAMS ((scope, int)); + +static rtx get_next_bb_note PARAMS ((rtx)); +static rtx get_prev_bb_note PARAMS ((rtx)); + +void verify_insn_chain PARAMS ((void)); + +/* Skip over inter-block insns occurring after BB which are typically + associated with BB (e.g., barriers). If there are any such insns, + we return the last one. Otherwise, we return the end of BB. */ + +static rtx +skip_insns_after_block (bb) + basic_block bb; +{ + rtx insn, last_insn, next_head, prev; + + next_head = NULL_RTX; + if (bb->index + 1 != n_basic_blocks) + next_head = BASIC_BLOCK (bb->index + 1)->head; + + for (last_insn = insn = bb->end; (insn = NEXT_INSN (insn)); ) + { + if (insn == next_head) + break; + + switch (GET_CODE (insn)) + { + case BARRIER: + last_insn = insn; + continue; + + case NOTE: + switch (NOTE_LINE_NUMBER (insn)) + { + case NOTE_INSN_LOOP_END: + case NOTE_INSN_BLOCK_END: + last_insn = insn; + continue; + case NOTE_INSN_DELETED: + case NOTE_INSN_DELETED_LABEL: + continue; + + default: + continue; + break; + } + break; + + case CODE_LABEL: + if (NEXT_INSN (insn) + && GET_CODE (NEXT_INSN (insn)) == JUMP_INSN + && (GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_VEC + || GET_CODE (PATTERN (NEXT_INSN (insn))) == ADDR_DIFF_VEC)) + { + insn = NEXT_INSN (insn); + last_insn = insn; + continue; + } + break; + + default: + break; + } + + break; + } + /* It is possible to hit contradicting sequence. For instance: + + jump_insn + NOTE_INSN_LOOP_BEG + barrier + + Where barrier belongs to jump_insn, but the note does not. + This can be created by removing the basic block originally + following NOTE_INSN_LOOP_BEG. + + In such case reorder the notes. */ + for (insn = last_insn; insn != bb->end; insn = prev) + { + prev = PREV_INSN (insn); + if (GET_CODE (insn) == NOTE) + switch (NOTE_LINE_NUMBER (insn)) + { + case NOTE_INSN_LOOP_END: + case NOTE_INSN_BLOCK_END: + case NOTE_INSN_DELETED: + case NOTE_INSN_DELETED_LABEL: + continue; + default: + reorder_insns (insn, insn, last_insn); + } + } + + return last_insn; +} + +/* Locate or create a label for a given basic block. */ + +static rtx +label_for_bb (bb) + basic_block bb; +{ + rtx label = bb->head; + + if (GET_CODE (label) != CODE_LABEL) + { + if (rtl_dump_file) + fprintf (rtl_dump_file, "Emitting label for block %d\n", + bb->index); + + label = block_label (bb); + if (bb->head == PREV_INSN (RBI (bb)->eff_head)) + RBI (bb)->eff_head = label; + } + + return label; +} + +/* Locate the effective beginning and end of the insn chain for each + block, as defined by skip_insns_after_block above. */ + +static void +record_effective_endpoints () +{ + rtx next_insn = get_insns (); + int i; + + for (i = 0; i < n_basic_blocks; ++i) + { + basic_block bb = BASIC_BLOCK (i); + rtx end; + + RBI (bb)->eff_head = next_insn; + end = skip_insns_after_block (bb); + RBI (bb)->eff_end = end; + next_insn = NEXT_INSN (end); + } + function_tail_eff_head = next_insn; +} + +static rtx +get_next_bb_note (x) + rtx x; +{ + while (x) + { + if (NOTE_INSN_BASIC_BLOCK_P (x)) + return x; + x = NEXT_INSN (x); + } + return NULL; +} + +static rtx +get_prev_bb_note (x) + rtx x; +{ + while (x) + { + if (NOTE_INSN_BASIC_BLOCK_P (x)) + return x; + x = PREV_INSN (x); + } + return NULL; +} + +/* Determine and record the relationships between basic blocks and + scopes in scope tree S. */ + +static void +relate_bbs_with_scopes (s) + scope s; +{ + scope p; + int i, bbi1, bbi2, bbs_spanned; + rtx bbnote; + + for (p = s->inner; p; p = p->next) + relate_bbs_with_scopes (p); + + bbi1 = bbi2 = -1; + bbs_spanned = 0; + + /* If the begin and end notes are both inside the same basic block, + or if they are both outside of basic blocks, then we know immediately + how they are related. Otherwise, we need to poke around to make the + determination. */ + if (s->bb_beg != s->bb_end) + { + if (s->bb_beg && s->bb_end) + { + /* Both notes are in different bbs. This implies that all the + basic blocks spanned by the pair of notes are contained in + this scope. */ + bbi1 = s->bb_beg->index; + bbi2 = s->bb_end->index; + bbs_spanned = 1; + } + else if (! s->bb_beg) + { + /* First note is outside of a bb. If the scope spans more than + one basic block, then they all are contained within this + scope. Otherwise, this scope is contained within the basic + block. */ + bbnote = get_next_bb_note (s->note_beg); + if (! bbnote) + abort (); + if (NOTE_BASIC_BLOCK (bbnote) == s->bb_end) + { + bbs_spanned = 0; + s->bb_beg = NOTE_BASIC_BLOCK (bbnote); + } + else + { + bbi1 = NOTE_BASIC_BLOCK (bbnote)->index; + bbi2 = s->bb_end->index; + s->bb_end = NULL; + bbs_spanned = 1; + } + } + else /* ! s->bb_end */ + { + /* Second note is outside of a bb. If the scope spans more than + one basic block, then they all are contained within this + scope. Otherwise, this scope is contained within the basic + block. */ + bbnote = get_prev_bb_note (s->note_end); + if (! bbnote) + abort (); + if (NOTE_BASIC_BLOCK (bbnote) == s->bb_beg) + { + bbs_spanned = 0; + s->bb_end = NOTE_BASIC_BLOCK (bbnote); + } + else + { + bbi1 = s->bb_beg->index; + bbi2 = NOTE_BASIC_BLOCK (bbnote)->index; + s->bb_beg = NULL; + bbs_spanned = 1; + } + } + } + else + { + if (s->bb_beg) + /* Both notes are in the same bb, which implies the block + contains this scope. */ + bbs_spanned = 0; + else + { + rtx x1, x2; + /* Both notes are outside of any bbs. This implies that all the + basic blocks spanned by the pair of notes are contained in + this scope. + There is a degenerate case to consider. If the notes do not + span any basic blocks, then it is an empty scope that can + safely be deleted or ignored. Mark these with level = -1. */ + + x1 = get_next_bb_note (s->note_beg); + x2 = get_prev_bb_note (s->note_end); + if (! (x1 && x2)) + { + s->level = -1; + bbs_spanned = 0; + } + else + { + bbi1 = NOTE_BASIC_BLOCK (x1)->index; + bbi2 = NOTE_BASIC_BLOCK (x2)->index; + bbs_spanned = 1; + } + } + } + + /* If the scope spans one or more basic blocks, we record them. We + only record the bbs that are immediately contained within this + scope. Note that if a scope is contained within a bb, we can tell + by checking that bb_beg = bb_end and that they are non-null. */ + if (bbs_spanned) + { + int j = 0; + + s->num_bbs = 0; + for (i = bbi1; i <= bbi2; i++) + if (! RBI (BASIC_BLOCK (i))->scope) + s->num_bbs++; + + s->bbs = xmalloc (s->num_bbs * sizeof (basic_block)); + for (i = bbi1; i <= bbi2; i++) + { + basic_block curr_bb = BASIC_BLOCK (i); + if (! RBI (curr_bb)->scope) + { + s->bbs[j++] = curr_bb; + RBI (curr_bb)->scope = s; + } + } + } + else + s->num_bbs = 0; +} + +/* Allocate and initialize a new scope structure with scope level LEVEL, + and record the NOTE beginning the scope. */ + +static scope +make_new_scope (level, note) + int level; + rtx note; +{ + scope new_scope = xcalloc (1, sizeof (struct scope_def)); + new_scope->level = level; + new_scope->note_beg = note; + return new_scope; +} + + +/* Build a forest representing the scope structure of the function. + Return a pointer to a structure describing the forest. */ + +static void +build_scope_forest (forest) + scope_forest_info *forest; +{ + rtx x; + int level, bbi, i; + basic_block curr_bb; + scope root, curr_scope = 0; + + forest->num_trees = 0; + forest->trees = NULL; + level = -1; + root = NULL; + curr_bb = NULL; + bbi = 0; + for (x = get_insns (); x; x = NEXT_INSN (x)) + { + if (bbi < n_basic_blocks && x == BASIC_BLOCK (bbi)->head) + curr_bb = BASIC_BLOCK (bbi); + + if (GET_CODE (x) == NOTE) + { + if (NOTE_LINE_NUMBER (x) == NOTE_INSN_BLOCK_BEG) + { + if (root) + { + scope new_scope; + if (! curr_scope) + abort(); + level++; + new_scope = make_new_scope (level, x); + new_scope->outer = curr_scope; + new_scope->next = NULL; + if (! curr_scope->inner) + { + curr_scope->inner = new_scope; + curr_scope->inner_last = new_scope; + } + else + { + curr_scope->inner_last->next = new_scope; + curr_scope->inner_last = new_scope; + } + curr_scope = curr_scope->inner_last; + } + else + { + int ntrees = forest->num_trees; + level++; + curr_scope = make_new_scope (level, x); + root = curr_scope; + forest->trees = xrealloc (forest->trees, + sizeof (scope) * (ntrees + 1)); + forest->trees[forest->num_trees++] = root; + } + curr_scope->bb_beg = curr_bb; + } + else if (NOTE_LINE_NUMBER (x) == NOTE_INSN_BLOCK_END) + { + curr_scope->bb_end = curr_bb; + curr_scope->note_end = x; + level--; + curr_scope = curr_scope->outer; + if (level == -1) + root = NULL; + } + } /* if note */ + + if (curr_bb && curr_bb->end == x) + { + curr_bb = NULL; + bbi++; + } + + } /* for */ + + for (i = 0; i < forest->num_trees; i++) + relate_bbs_with_scopes (forest->trees[i]); +} + +/* Remove all the NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes from + the insn chain. */ + +static void +remove_scope_notes () +{ + rtx x, next; + basic_block currbb = NULL; + + for (x = get_insns (); x; x = next) + { + next = NEXT_INSN (x); + if (NOTE_INSN_BASIC_BLOCK_P (x)) + currbb = NOTE_BASIC_BLOCK (x); + + if (GET_CODE (x) == NOTE + && (NOTE_LINE_NUMBER (x) == NOTE_INSN_BLOCK_BEG + || NOTE_LINE_NUMBER (x) == NOTE_INSN_BLOCK_END)) + { + /* Check if the scope note happens to be the end of a bb. */ + if (currbb && x == currbb->end) + currbb->end = PREV_INSN (x); + if (currbb && x == currbb->head) + abort (); + + if (PREV_INSN (x)) + { + NEXT_INSN (PREV_INSN (x)) = next; + PREV_INSN (next) = PREV_INSN (x); + + NEXT_INSN (x) = NULL; + PREV_INSN (x) = NULL; + } + else + abort (); + } + } +} + +/* Insert scope note pairs for a contained scope tree S after insn IP. */ + +static void +insert_intra_1 (s, ip, bb) + scope s; + rtx *ip; + basic_block bb; +{ + scope p; + + if (NOTE_BLOCK (s->note_beg)) + { + *ip = emit_note_after (NOTE_INSN_BLOCK_BEG, *ip); + NOTE_BLOCK (*ip) = NOTE_BLOCK (s->note_beg); + } + + for (p = s->inner; p; p = p->next) + insert_intra_1 (p, ip, bb); + + if (NOTE_BLOCK (s->note_beg)) + { + *ip = emit_note_after (NOTE_INSN_BLOCK_END, *ip); + NOTE_BLOCK (*ip) = NOTE_BLOCK (s->note_end); + } +} + + +/* Insert NOTE_INSN_BLOCK_END notes and NOTE_INSN_BLOCK_BEG notes for + scopes that are contained within BB. */ + +static void +insert_intra_bb_scope_notes (bb) + basic_block bb; +{ + scope s = RBI (bb)->scope; + scope p; + rtx ip; + + if (! s) + return; + + ip = bb->head; + if (GET_CODE (ip) == CODE_LABEL) + ip = NEXT_INSN (ip); + + for (p = s->inner; p; p = p->next) + { + if (p->bb_beg != NULL && p->bb_beg == p->bb_end && p->bb_beg == bb) + insert_intra_1 (p, &ip, bb); + } +} + + +/* Given two consecutive basic blocks BB1 and BB2 with different scopes, + insert NOTE_INSN_BLOCK_END notes after BB1 and NOTE_INSN_BLOCK_BEG + notes before BB2 such that the notes are correctly balanced. If BB1 or + BB2 is NULL, we are inserting scope notes for the first and last basic + blocks, respectively. */ + +static void +insert_inter_bb_scope_notes (bb1, bb2) + basic_block bb1; + basic_block bb2; +{ + rtx ip; + scope com; + + /* It is possible that a basic block is not contained in any scope. + In that case, we either open or close a scope but not both. */ + if (bb1 && bb2) + { + scope s1 = RBI (bb1)->scope; + scope s2 = RBI (bb2)->scope; + if (! s1 && ! s2) + return; + if (! s1) + bb1 = NULL; + else if (! s2) + bb2 = NULL; + } + + /* Find common ancestor scope. */ + if (bb1 && bb2) + { + scope s1 = RBI (bb1)->scope; + scope s2 = RBI (bb2)->scope; + while (s1 != s2) + { + if (! (s1 && s2)) + abort (); + if (s1->level > s2->level) + s1 = s1->outer; + else if (s2->level > s1->level) + s2 = s2->outer; + else + { + s1 = s1->outer; + s2 = s2->outer; + } + } + com = s1; + } + else + com = NULL; + + /* Close scopes. */ + if (bb1) + { + rtx end = bb1->end; + + scope s = RBI (bb1)->scope; + ip = RBI (bb1)->eff_end; + while (s != com) + { + if (NOTE_BLOCK (s->note_beg)) + { + ip = emit_note_after (NOTE_INSN_BLOCK_END, ip); + NOTE_BLOCK (ip) = NOTE_BLOCK (s->note_end); + } + s = s->outer; + } + /* Emitting note may move the end of basic block to unwanted place. */ + bb1->end = end; + } + + /* Open scopes. */ + if (bb2) + { + scope s = RBI (bb2)->scope; + ip = bb2->head; + while (s != com) + { + if (NOTE_BLOCK (s->note_beg)) + { + ip = emit_note_before (NOTE_INSN_BLOCK_BEG, ip); + NOTE_BLOCK (ip) = NOTE_BLOCK (s->note_beg); + } + s = s->outer; + } + } +} + + +/* Rebuild all the NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes based + on the scope forest and the newly reordered basic blocks. */ + +static void +rebuild_scope_notes (forest) + scope_forest_info *forest; +{ + int i; + + if (forest->num_trees == 0) + return; + + /* Start by opening the scopes before the first basic block. */ + insert_inter_bb_scope_notes (NULL, BASIC_BLOCK (0)); + + /* Then, open and close scopes as needed between blocks. */ + for (i = 0; i < n_basic_blocks - 1; i++) + { + basic_block bb1 = BASIC_BLOCK (i); + basic_block bb2 = BASIC_BLOCK (i + 1); + if (RBI (bb1)->scope != RBI (bb2)->scope) + insert_inter_bb_scope_notes (bb1, bb2); + insert_intra_bb_scope_notes (bb1); + } + + /* Finally, close the scopes after the last basic block. */ + insert_inter_bb_scope_notes (BASIC_BLOCK (n_basic_blocks - 1), NULL); + insert_intra_bb_scope_notes (BASIC_BLOCK (n_basic_blocks - 1)); +} + +/* Free the storage associated with the scope tree at S. */ + +static void +free_scope_forest_1 (s) + scope s; +{ + scope p, next; + + for (p = s->inner; p; p = next) + { + next = p->next; + free_scope_forest_1 (p); + } + + if (s->bbs) + free (s->bbs); + free (s); +} + +/* Free the storage associated with the scope forest. */ + +static void +free_scope_forest (forest) + scope_forest_info *forest; +{ + int i; + for (i = 0; i < forest->num_trees; i++) + free_scope_forest_1 (forest->trees[i]); +} + +/* Visualize the scope forest. */ + +void +dump_scope_forest (forest) + scope_forest_info *forest; +{ + if (forest->num_trees == 0) + fprintf (stderr, "\n< Empty scope forest >\n"); + else + { + int i; + fprintf (stderr, "\n< Scope forest >\n"); + for (i = 0; i < forest->num_trees; i++) + dump_scope_forest_1 (forest->trees[i], 0); + } +} + +/* Recursive portion of dump_scope_forest. */ + +static void +dump_scope_forest_1 (s, indent) + scope s; + int indent; +{ + scope p; + int i; + + if (s->bb_beg != NULL && s->bb_beg == s->bb_end + && RBI (s->bb_beg)->scope + && RBI (s->bb_beg)->scope->level + 1 == s->level) + { + fprintf (stderr, "%*s", indent, ""); + fprintf (stderr, "BB%d:\n", s->bb_beg->index); + } + + fprintf (stderr, "%*s", indent, ""); + fprintf (stderr, "{ level %d (block %p)\n", s->level, + (PTR) NOTE_BLOCK (s->note_beg)); + + fprintf (stderr, "%*s%s", indent, "", "bbs:"); + for (i = 0; i < s->num_bbs; i++) + fprintf (stderr, " %d", s->bbs[i]->index); + fprintf (stderr, "\n"); + + for (p = s->inner; p; p = p->next) + dump_scope_forest_1 (p, indent + 2); + + fprintf (stderr, "%*s", indent, ""); + fprintf (stderr, "}\n"); +} + +/* Given a reorder chain, rearrange the code to match. */ + +static void +fixup_reorder_chain () +{ + basic_block bb, last_bb; + int index; + rtx insn; + int old_n_basic_blocks = n_basic_blocks; + + /* First do the bulk reordering -- rechain the blocks without regard to + the needed changes to jumps and labels. */ + + last_bb = BASIC_BLOCK (0); + bb = RBI (last_bb)->next; + index = 1; + while (bb) + { + rtx last_e = RBI (last_bb)->eff_end; + rtx curr_h = RBI (bb)->eff_head; + + NEXT_INSN (last_e) = curr_h; + PREV_INSN (curr_h) = last_e; + + last_bb = bb; + bb = RBI (bb)->next; + index++; + } + + if (index != n_basic_blocks) + abort (); + + insn = RBI (last_bb)->eff_end; + + NEXT_INSN (insn) = function_tail_eff_head; + if (function_tail_eff_head) + PREV_INSN (function_tail_eff_head) = insn; + + while (NEXT_INSN (insn)) + insn = NEXT_INSN (insn); + set_last_insn (insn); +#ifdef ENABLE_CHECKING + verify_insn_chain (); +#endif + + /* Now add jumps and labels as needed to match the blocks new + outgoing edges. */ + + for (bb = BASIC_BLOCK (0); bb ; bb = RBI (bb)->next) + { + edge e_fall, e_taken, e; + rtx bb_end_insn; + basic_block nb; + + if (bb->succ == NULL) + continue; + + /* Find the old fallthru edge, and another non-EH edge for + a taken jump. */ + e_taken = e_fall = NULL; + for (e = bb->succ; e ; e = e->succ_next) + if (e->flags & EDGE_FALLTHRU) + e_fall = e; + else if (! (e->flags & EDGE_EH)) + e_taken = e; + + bb_end_insn = bb->end; + if (GET_CODE (bb_end_insn) == JUMP_INSN) + { + if (any_condjump_p (bb_end_insn)) + { + /* If the old fallthru is still next, nothing to do. */ + if (RBI (bb)->next == e_fall->dest + || (!RBI (bb)->next + && e_fall->dest == EXIT_BLOCK_PTR)) + continue; + + /* There is one special case: if *neither* block is next, + such as happens at the very end of a function, then we'll + need to add a new unconditional jump. Choose the taken + edge based on known or assumed probability. */ + if (RBI (bb)->next != e_taken->dest) + { + rtx note = find_reg_note (bb_end_insn, REG_BR_PROB, 0); + if (note + && INTVAL (XEXP (note, 0)) < REG_BR_PROB_BASE / 2 + && invert_jump (bb_end_insn, + label_for_bb (e_fall->dest), 0)) + { + e_fall->flags &= ~EDGE_FALLTHRU; + e_taken->flags |= EDGE_FALLTHRU; + e = e_fall, e_fall = e_taken, e_taken = e; + } + } + + /* Otherwise we can try to invert the jump. This will + basically never fail, however, keep up the pretense. */ + else if (invert_jump (bb_end_insn, + label_for_bb (e_fall->dest), 0)) + { + e_fall->flags &= ~EDGE_FALLTHRU; + e_taken->flags |= EDGE_FALLTHRU; + continue; + } + } + else if (returnjump_p (bb_end_insn)) + continue; + else + { + /* Otherwise we have some switch or computed jump. In the + 99% case, there should not have been a fallthru edge. */ + if (! e_fall) + continue; +#ifdef CASE_DROPS_THROUGH + /* Except for VAX. Since we didn't have predication for the + tablejump, the fallthru block should not have moved. */ + if (RBI (bb)->next == e_fall->dest) + continue; + bb_end_insn = skip_insns_after_block (bb); +#else + abort (); +#endif + } + } + else + { + /* No fallthru implies a noreturn function with EH edges, or + something similarly bizarre. In any case, we don't need to + do anything. */ + if (! e_fall) + continue; + + /* If the fallthru block is still next, nothing to do. */ + if (RBI (bb)->next == e_fall->dest) + continue; + + /* An fallthru to exit block. */ + if (!RBI (bb)->next && e_fall->dest == EXIT_BLOCK_PTR) + continue; + } + + /* We got here if we need to add a new jump insn. */ + + nb = force_nonfallthru (e_fall); + + if (nb) + { + alloc_aux_for_block (nb, sizeof (struct reorder_block_def)); + RBI (nb)->eff_head = nb->head; + RBI (nb)->eff_end = NEXT_INSN (nb->end); + RBI (nb)->scope = RBI (bb)->scope; + RBI (nb)->visited = 1; + RBI (nb)->next = RBI (bb)->next; + RBI (bb)->next = nb; + /* Don't process this new block. */ + bb = nb; + } + } + + /* Put basic_block_info in the new order. */ + bb = BASIC_BLOCK (0); + index = 0; + + if (rtl_dump_file) + fprintf (rtl_dump_file, "Reordered sequence:\n"); + while (bb) + { + if (rtl_dump_file) + fprintf (rtl_dump_file, " %i %sbb %i freq %i\n", index, + bb->index >= old_n_basic_blocks ? "compensation " : "", + bb->index, + bb->frequency); + bb->index = index; + BASIC_BLOCK (index) = bb; + + bb = RBI (bb)->next; + index++; + } +} + +/* Perform sanity checks on the insn chain. + 1. Check that next/prev pointers are consistent in both the forward and + reverse direction. + 2. Count insns in chain, going both directions, and check if equal. + 3. Check that get_last_insn () returns the actual end of chain. */ + +void +verify_insn_chain () +{ + rtx x, + prevx, + nextx; + int insn_cnt1, + insn_cnt2; + + prevx = NULL; + insn_cnt1 = 1; + for (x = get_insns (); x; x = NEXT_INSN (x)) + { + if (PREV_INSN (x) != prevx) + { + fprintf (stderr, "Forward traversal: insn chain corrupt.\n"); + fprintf (stderr, "previous insn:\n"); + debug_rtx (prevx); + fprintf (stderr, "current insn:\n"); + debug_rtx (x); + abort (); + } + ++insn_cnt1; + prevx = x; + } + + if (prevx != get_last_insn ()) + { + fprintf (stderr, "last_insn corrupt.\n"); + abort (); + } + + nextx = NULL; + insn_cnt2 = 1; + for (x = get_last_insn (); x; x = PREV_INSN (x)) + { + if (NEXT_INSN (x) != nextx) + { + fprintf (stderr, "Reverse traversal: insn chain corrupt.\n"); + fprintf (stderr, "current insn:\n"); + debug_rtx (x); + fprintf (stderr, "next insn:\n"); + debug_rtx (nextx); + abort (); + } + ++insn_cnt2; + nextx = x; + } + + if (insn_cnt1 != insn_cnt2) + { + fprintf (stderr, "insn_cnt1 (%d) not equal to insn_cnt2 (%d).\n", + insn_cnt1, insn_cnt2); + abort (); + } +} + +/* Main entry point to this module - initialize the datastructures for + CFG layout changes. */ + +void +cfg_layout_initialize () +{ + alloc_aux_for_blocks (sizeof (struct reorder_block_def)); + + build_scope_forest (&forest); + remove_scope_notes (); + + record_effective_endpoints (); +} + +/* Finalize the changes - reorder insn list according to the sequence, + enter compensation code, rebuild scope forest. */ + +void +cfg_layout_finalize () +{ + fixup_reorder_chain (); +#ifdef ENABLE_CHECKING + verify_insn_chain (); +#endif + + rebuild_scope_notes (&forest); + free_scope_forest (&forest); + reorder_blocks (); + + free_aux_for_blocks (); + +#ifdef ENABLE_CHECKING + verify_flow_info (); +#endif +} diff --git a/gcc/cfglayout.h b/gcc/cfglayout.h new file mode 100644 index 0000000..3c59e42 --- /dev/null +++ b/gcc/cfglayout.h @@ -0,0 +1,37 @@ +/* Basic block reordering routines for the GNU compiler. + Copyright (C) 2000 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +struct scope_def; +typedef struct scope_def *scope; + +/* Structure to hold information about the blocks during reordering. */ +typedef struct reorder_block_def +{ + rtx eff_head; + rtx eff_end; + scope scope; + basic_block next; + int visited; +} *reorder_block_def; + +#define RBI(BB) ((reorder_block_def) (BB)->aux) + +extern void cfg_layout_initialize PARAMS ((void)); +extern void cfg_layout_finalize PARAMS ((void));