Flow rewrite to use basic block structures and edge lists.

From-SVN: r25450
This commit is contained in:
Richard Henderson 1999-02-25 15:45:42 -08:00 committed by Richard Henderson
parent 001e880a26
commit e881bb1b1b
26 changed files with 2530 additions and 1234 deletions

View File

@ -1,3 +1,156 @@
Thu Feb 25 23:43:59 1999 Richard Henderson <rth@cygnus.com>
Flow rewrite to use basic block structures and edge lists:
* basic-block.h (x_basic_block_head, x_basic_block_end): Kill.
(basic_block_computed_jump_target, basic_block_live_at_start): Kill.
(struct edge_def): New.
(struct basic_block_def): New.
(basic_block_info): New.
(BLOCK_HEAD, BLOCK_END): Update.
(ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR): New.
(uid_block_number): Kill.
(basic_block_for_insn, BLOCK_FOR_INSN): New.
(BLOCK_NUM): Update.
* flow.c (XNMALLOC): Kill.
(max_uid_for_flow): Kill.
(uid_block_number): Kill.
(uid_volatile): Turn into a bitmap.
(SET_INSN_VOLATILE): New.
(basic_block_info): New.
(entry_exit_blocks): New.
(x_basic_block_head, x_basic_block_end): Kill.
(basic_block_computed_jump_target, basic_block_live_at_start): Kill.
(flow_int_list_blocks, basic_block_succ, basic_block_pred): Kill.
(basic_block_loop_depth): Kill.
(basic_block_for_insn): New.
(find_basic_blocks): Split out initial block counting into
count_basic_blocks. Call functions split out of find_basic_blocks_1.
(count_basic_blocks): New.
(find_basic_blocks_1): Split out edge recognition, unreachable
block deletion.
(create_basic_block): New.
(compute_bb_for_insn): New.
(clear_edges): New.
(free_bb_memory): Kill.
(add_edge, add_edge_to_label): Kill.
(mark_label_ref): Kill.
(make_edges): Rewrite to use edge lists.
(make_edge, make_label_edge): New.
(mark_critical_edges): New.
(split_edge, insert_insn_on_edge): New.
(commit_one_edge_insertion, commit_edge_insertions): New.
(delete_unreachable_blocks): Rewrite to use edge lists.
Split out EH region manipulation into delete_eh_regions.
Call tidy_fallthru_edge and merge_blocks.
(delete_eh_regions): New.
(delete_note_p): New.
(delete_insn_chain): New.
(delete_block): Split out code into delete_insn_chain and
tidy_fallthru_edge. Update edge lists.
(expunge_block): New.
(flow_delete_insn): New?
(can_delete_label_p): New?
(merge_blocks_nomove, merge_blocks): New.
(tidy_fallthru_edge): New.
(calculate_loop_depth): New.
(life_analysis): Allocate and free uid_volatile.
(free_basic_block_vars): Update for new structures.
(record_volatile_insns): Use SET_INSN_VOLATILE.
(mark_regs_live_at_end): Tidy EXIT_IGNORE_STACK usage.
(mark_used_regs): Likewise.
(life_analysis_1): Use bb global_live_at_start, global_live_at_end,
local_set regsets. Use bb->aux to store new_live_at_end. Begin
life propagation from EXIT_BLOCK rather than last block. Clear
regs_ever_live after mark_regs_live_at_end.
(allocate_for_life_analysis): Update for new structures.
(propagate_block): Split out loop depth calculation to
calculate_loop_depth.
(regno_uninitialized): Use bb->global_live_at_start.
(regno_clobbered_at_setjmp): Likewise.
(dump_bb_data): Likewise.
(find_auto_inc): Use BLOCK_FOR_INSN instead of BLOCK_NUM.
(dump_flow_info): Update for new structures.
(dump_edge_info): New.
(print_rtl_with_bb): Update for new structues.
(compute_preds_succs): Do no work -- convert edge lists.
(set_block_for_insn): From corpse of old set_block_num.
(set_block_num): Call it.
* rtl.c (note_insn_name): Add NOTE_INSN_BASIC_BLOCK.
* rtl.h (rtunion_def): Add bb entry.
(NOTE_BASIC_BLOCK): New.
(NOTE_INSN_BASIC_BLOCK): New.
* varray.h (varray_data_tag): Add bb entry.
(VARRAY_BB_INIT, VARRAY_BB): New.
* emit-rtl.c (emit_label_before): New.
* except.c (expand_rethrow): Delete insns following the call to
rethrow. Put the REG_EH_RETHROW on the call.
* jump.c (returnjump_p, returnjump_p_1): New.
* expr.h (nonlocal_goto_handler_labels): New declaration.
* function.c (nonlocal_goto_handler_labels): Define it.
(push_function_context_to): Save it.
(pop_function_context_from): Restore it.
(init_function_start): Clear it.
(nonlocal_label_rtx_list): Kill.
* function.h (struct function): Add storage space for it.
* stmt.c (expand_nl_handler_label): Return the new label.
(expand_nl_goto_receivers): Collect a list of them in
nonlocal_goto_handler_labels.
* Makefile.in (print-rtl.o): Depend on basic-block.h.
(flow.o): Depend on tree.h and insn-flags.h.
(sched.o): Depend on tree.h and expr.h.
* function.c (thread_prologue_and_epilogue_insns): Do not
half-heartedly update bb structures.
* toplev.c: Add flow2 dump as -dw.
(rest_of_compilation): Finish .greg before flow2.
* graph.c (draw_edge): Handle class 3.
(print_rtl_graph_with_bb): Make abnormal edges red class 2,
change non-fall-thru but adjacent to green class 3. Update
to use new structures.
* print-rtl.c (print_rtx): Handle NOTE_INSN_BASIC_BLOCK.
* reg-stack.c (BLOCK_NUM): Convert to function. Abort if
block_number is -1.
(reg_to_stack): Initialize block_num to -1.
* combine.c (set_nonzero_bits_and_sign_copies): Update reference
to basic_block_live_at_start to bb->global_live_at_start.
(try_combine): Likewise.
(reg_dead_at_p): Likewise.
* global.c (global_conflicts): Likewise.
Handle stack regs on all abnormal edges, not just computed jumps.
(mark_elimination): Update reference to basic_block_live_at_start.
(build_insn_chain): Likewise.
* haifa-sched.c (haifa_edge): Rename from edge for conflict.
(is_cfg_nonregular): Look at nonlocal_goto_handler_labels instead
of nonlocal_label_rtx_list.
(check_live_1): Update reference to basic_block_live_at_start.
(update_live_1): Likewise.
(find_pre_sched_live): Likewise.
(find_post_sched_live): Likewise.
* local-alloc.c (update_equiv_regs): Likewise.
(block_alloc): Likewise.
* reload1.c (reload, reload_combine): Likewise.
* regmove.c (mark_flags_life_zones): Likewise.
* resource.c (mark_target_live_regs): Likewise.
* sched.c (schedule_block): Likewise.
* regclass.c (regset_release_memory): Don't free
basic_block_live_at_start.
* unroll.c (copy_loop_body): Don't duplicate NOTE_INSN_BASIC_BLOCK.
Thu Feb 25 21:32:34 1999 Jason Merrill <jason@yorick.cygnus.com>
* fixinc.wrap: Also handle struct queue in sys/stream.h.

View File

@ -21,6 +21,7 @@ Boston, MA 02111-1307, USA. */
#include "bitmap.h"
#include "sbitmap.h"
#include "varray.h"
typedef bitmap regset; /* Head of register set linked list. */
@ -95,29 +96,65 @@ do { \
/* Grow any tables needed when the number of registers is calculated
or extended. For the linked list allocation, nothing needs to
be done, other than zero the statistics on the first allocation. */
#define MAX_REGNO_REG_SET(NUM_REGS, NEW_P, RENUMBER_P)
#define MAX_REGNO_REG_SET(NUM_REGS, NEW_P, RENUMBER_P)
/* Control flow edge information. */
typedef struct edge_def {
/* Links through the predecessor and successor lists. */
struct edge_def *pred_next, *succ_next;
/* The two blocks at the ends of the edge. */
struct basic_block_def *src, *dest;
/* Instructions queued on the edge. */
rtx insns;
/* Auxiliary info specific to a pass. */
void *aux;
int flags; /* see EDGE_* below */
int probability; /* biased by REG_BR_PROB_BASE */
} *edge;
#define EDGE_FALLTHRU 1
#define EDGE_CRITICAL 2
#define EDGE_ABNORMAL 4
#define EDGE_ABNORMAL_CALL 8
#define EDGE_EH 16
#define EDGE_FAKE 32
/* Basic block information indexed by block number. */
typedef struct basic_block_def {
/* The first and last insns of the block. */
rtx head, end;
/* The edges into and out of the block. */
edge pred, succ;
/* Liveness info. */
regset local_set;
regset global_live_at_start;
regset global_live_at_end;
/* Auxiliary info specific to a pass. */
void *aux;
/* The index of this block. */
int index;
/* The loop depth of this block plus one. */
int loop_depth;
} *basic_block;
/* Number of basic blocks in the current function. */
extern int n_basic_blocks;
/* Index by basic block number, get first insn in the block. */
/* Index by basic block number, get basic block struct info. */
extern rtx *x_basic_block_head;
extern varray_type basic_block_info;
/* Index by basic block number, get last insn in the block. */
extern rtx *x_basic_block_end;
/* Index by basic block number, determine whether the block can be reached
through a computed jump. */
extern char *basic_block_computed_jump_target;
/* Index by basic block number, get address of regset
describing the registers live at the start of that block. */
extern regset *basic_block_live_at_start;
#define BASIC_BLOCK(N) (VARRAY_BB (basic_block_info, (N)))
/* What registers are live at the setjmp call. */
@ -177,24 +214,38 @@ extern void free_int_list PROTO ((int_list_block **));
/* Stuff for recording basic block info. */
#define BLOCK_HEAD(B) x_basic_block_head[(B)]
#define BLOCK_END(B) x_basic_block_end[(B)]
#define BLOCK_HEAD(B) (BASIC_BLOCK (B)->head)
#define BLOCK_END(B) (BASIC_BLOCK (B)->end)
/* Special block numbers [markers] for entry and exit. */
#define ENTRY_BLOCK (-1)
#define EXIT_BLOCK (-2)
/* from flow.c */
extern void free_regset_vector PROTO ((regset *, int nelts));
extern int *uid_block_number;
#define BLOCK_NUM(INSN) uid_block_number[INSN_UID (INSN)]
/* Similarly, block pointers for the edge list. */
extern struct basic_block_def entry_exit_blocks[2];
#define ENTRY_BLOCK_PTR (&entry_exit_blocks[0])
#define EXIT_BLOCK_PTR (&entry_exit_blocks[1])
extern void dump_bb_data PROTO ((FILE *, int_list_ptr *, int_list_ptr *,
int));
extern void free_bb_mem PROTO ((void));
/* from flow.c */
extern void free_regset_vector PROTO ((regset *, int nelts));
extern varray_type basic_block_for_insn;
#define BLOCK_FOR_INSN(INSN) VARRAY_BB (basic_block_for_insn, INSN_UID (INSN))
#define BLOCK_NUM(INSN) (BLOCK_FOR_INSN (INSN)->index + 0)
extern void set_block_for_insn PROTO ((rtx, basic_block));
extern void dump_bb_data PROTO ((FILE *, int_list_ptr *,
int_list_ptr *, int));
extern void free_bb_mem PROTO ((void));
extern void free_basic_block_vars PROTO ((int));
extern void compute_preds_succs PROTO ((int_list_ptr *, int_list_ptr *,
int *, int *));
extern void compute_dominators PROTO ((sbitmap *, sbitmap *,
int_list_ptr *, int_list_ptr *));
extern basic_block split_edge PROTO ((edge));
extern void insert_insn_on_edge PROTO ((rtx, edge));
extern void commit_edge_insertions PROTO ((void));
extern void compute_preds_succs PROTO ((int_list_ptr *, int_list_ptr *,
int *, int *));
extern void compute_dominators PROTO ((sbitmap *, sbitmap *,
int_list_ptr *,
int_list_ptr *));

View File

@ -744,7 +744,7 @@ set_nonzero_bits_and_sign_copies (x, set)
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
/* If this register is undefined at the start of the file, we can't
say what its contents were. */
&& ! REGNO_REG_SET_P (basic_block_live_at_start[0], REGNO (x))
&& ! REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start, REGNO (x))
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
{
if (set == 0 || GET_CODE (set) == CLOBBER)
@ -2490,7 +2490,8 @@ try_combine (i3, i2, i1)
regno = REGNO (i2dest);
REG_N_SETS (regno)--;
if (REG_N_SETS (regno) == 0
&& ! REGNO_REG_SET_P (basic_block_live_at_start[0], regno))
&& ! REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start,
regno))
REG_N_REFS (regno) = 0;
}
}
@ -2512,7 +2513,8 @@ try_combine (i3, i2, i1)
{
REG_N_SETS (regno)--;
if (REG_N_SETS (regno) == 0
&& ! REGNO_REG_SET_P (basic_block_live_at_start[0], regno))
&& ! REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start,
regno))
REG_N_REFS (regno) = 0;
}
}
@ -11038,7 +11040,7 @@ reg_dead_at_p (reg, insn)
}
for (i = reg_dead_regno; i < reg_dead_endregno; i++)
if (REGNO_REG_SET_P (basic_block_live_at_start[block], i))
if (REGNO_REG_SET_P (BASIC_BLOCK (block)->global_live_at_start, i))
return 0;
return 1;

View File

@ -2710,7 +2710,7 @@ emit_call_insn_before (pattern, before)
}
/* Make an insn of code BARRIER
and output it before the insn AFTER. */
and output it before the insn BEFORE. */
rtx
emit_barrier_before (before)
@ -2724,6 +2724,23 @@ emit_barrier_before (before)
return insn;
}
/* Emit the label LABEL before the insn BEFORE. */
rtx
emit_label_before (label, before)
rtx label, before;
{
/* This can be called twice for the same label as a result of the
confusion that follows a syntax error! So make it harmless. */
if (INSN_UID (label) == 0)
{
INSN_UID (label) = cur_insn_uid++;
add_insn_before (label, before);
}
return label;
}
/* Emit a note of subtype SUBTYPE before the insn BEFORE. */
rtx

View File

@ -1967,11 +1967,17 @@ expand_rethrow (label)
label = last_rethrow_symbol;
emit_library_call (rethrow_libfunc, 0, VOIDmode, 1, label, Pmode);
SYMBOL_REF_USED (label) = 1;
/* Search backwards for the actual call insn. */
insn = get_last_insn ();
val = GEN_INT (eh_region_from_symbol (label));
while (GET_CODE (insn) != CALL_INSN)
insn = PREV_INSN (insn);
delete_insns_since (insn);
/* Mark the label/symbol on the call. */
val = GEN_INT (eh_region_from_symbol (label));
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_RETHROW, val,
REG_NOTES (insn));
REG_NOTES (insn));
emit_barrier ();
}
else

2887
gcc/flow.c

File diff suppressed because it is too large Load Diff

View File

@ -262,6 +262,11 @@ tree nonlocal_labels;
rtx nonlocal_goto_handler_slots;
/* List (chain of EXPR_LIST) of labels heading the current handlers for
nonlocal gotos. */
rtx nonlocal_goto_handler_labels;
/* RTX for stack slot that holds the stack pointer value to restore
for a nonlocal goto.
Zero when function does not have nonlocal labels. */
@ -559,6 +564,7 @@ push_function_context_to (context)
p->outgoing_args_size = current_function_outgoing_args_size;
p->return_rtx = current_function_return_rtx;
p->nonlocal_goto_handler_slots = nonlocal_goto_handler_slots;
p->nonlocal_goto_handler_labels = nonlocal_goto_handler_labels;
p->nonlocal_goto_stack_level = nonlocal_goto_stack_level;
p->nonlocal_labels = nonlocal_labels;
p->cleanup_label = cleanup_label;
@ -644,6 +650,7 @@ pop_function_context_from (context)
current_function_outgoing_args_size = p->outgoing_args_size;
current_function_return_rtx = p->return_rtx;
nonlocal_goto_handler_slots = p->nonlocal_goto_handler_slots;
nonlocal_goto_handler_labels = p->nonlocal_goto_handler_labels;
nonlocal_goto_stack_level = p->nonlocal_goto_stack_level;
nonlocal_labels = p->nonlocal_labels;
cleanup_label = p->cleanup_label;
@ -3852,21 +3859,6 @@ delete_handlers ()
}
}
}
/* Return a list (chain of EXPR_LIST nodes) for the nonlocal labels
of the current function. */
rtx
nonlocal_label_rtx_list ()
{
tree t;
rtx x = 0;
for (t = nonlocal_labels; t; t = TREE_CHAIN (t))
x = gen_rtx_EXPR_LIST (VOIDmode, label_rtx (TREE_VALUE (t)), x);
return x;
}
/* Output a USE for any register use in RTL.
This is used with -noreg to mark the extent of lifespan
@ -5644,6 +5636,7 @@ init_function_start (subr, filename, line)
/* No labels have been declared for nonlocal use. */
nonlocal_labels = 0;
nonlocal_goto_handler_labels = 0;
/* No function calls so far in this function. */
function_call_count = 0;
@ -6438,100 +6431,172 @@ contains (insn, vec)
void
thread_prologue_and_epilogue_insns (f)
rtx f ATTRIBUTE_UNUSED;
rtx f;
{
int insertted = 0;
prologue = 0;
#ifdef HAVE_prologue
if (HAVE_prologue)
{
rtx head, seq;
rtx seq;
/* The first insn (a NOTE_INSN_DELETED) is followed by zero or more
prologue insns and a NOTE_INSN_PROLOGUE_END. */
emit_note_after (NOTE_INSN_PROLOGUE_END, f);
seq = gen_prologue ();
head = emit_insn_after (seq, f);
/* Include the new prologue insns in the first block. Ignore them
if they form a basic block unto themselves. */
if (x_basic_block_head && n_basic_blocks
&& GET_CODE (BLOCK_HEAD (0)) != CODE_LABEL)
BLOCK_HEAD (0) = NEXT_INSN (f);
start_sequence ();
seq = gen_prologue();
emit_insn (seq);
/* Retain a map of the prologue insns. */
prologue = record_insns (GET_CODE (seq) == SEQUENCE ? seq : head);
}
else
#endif
prologue = 0;
if (GET_CODE (seq) != SEQUENCE)
seq = get_insns ();
prologue = record_insns (seq);
emit_note (NULL, NOTE_INSN_PROLOGUE_END);
seq = gen_sequence ();
end_sequence ();
/* If optimization is off, and perhaps in an empty function,
the entry block will have no successors. */
if (ENTRY_BLOCK_PTR->succ)
{
/* Can't deal with multiple successsors of the entry block. */
if (ENTRY_BLOCK_PTR->succ->succ_next)
abort ();
insert_insn_on_edge (seq, ENTRY_BLOCK_PTR->succ);
insertted = 1;
}
else
emit_insn_after (seq, f);
}
#endif
epilogue = 0;
#ifdef HAVE_epilogue
if (HAVE_epilogue)
{
rtx insn = get_last_insn ();
rtx prev = prev_nonnote_insn (insn);
edge e;
basic_block bb = 0;
rtx tail = get_last_insn ();
/* If we end with a BARRIER, we don't need an epilogue. */
if (! (prev && GET_CODE (prev) == BARRIER))
/* ??? This is gastly. If function returns were not done via uses,
but via mark_regs_live_at_end, we could use insert_insn_on_edge
and all of this uglyness would go away. */
switch (optimize)
{
rtx tail, seq, tem;
rtx first_use = 0;
rtx last_use = 0;
default:
/* If the exit block has no non-fake predecessors, we don't
need an epilogue. Furthermore, only pay attention to the
fallthru predecessors; if (conditional) return insns were
generated, by definition we do not need to emit epilogue
insns. */
/* The last basic block ends with a NOTE_INSN_EPILOGUE_BEG, the
epilogue insns, the USE insns at the end of a function,
the jump insn that returns, and then a BARRIER. */
for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
if ((e->flags & EDGE_FAKE) == 0
&& (e->flags & EDGE_FALLTHRU) != 0)
break;
if (e == NULL)
break;
/* Move the USE insns at the end of a function onto a list. */
while (prev
&& GET_CODE (prev) == INSN
&& GET_CODE (PATTERN (prev)) == USE)
{
tem = prev;
/* We can't handle multiple epilogues -- if one is needed,
we won't be able to place it multiple times.
??? Fix epilogue expanders to not assume they are the
last thing done compiling the function. Either that
or copy_rtx each insn.
??? Blah, it's not a simple expression to assert that
we've exactly one fallthru exit edge. */
bb = e->src;
tail = bb->end;
/* ??? If the last insn of the basic block is a jump, then we
are creating a new basic block. Wimp out and leave these
insns outside any block. */
if (GET_CODE (tail) == JUMP_INSN)
bb = 0;
/* FALLTHRU */
case 0:
{
rtx prev, seq, first_use;
/* Move the USE insns at the end of a function onto a list. */
prev = tail;
if (GET_CODE (prev) == BARRIER
|| GET_CODE (prev) == NOTE)
prev = prev_nonnote_insn (prev);
NEXT_INSN (PREV_INSN (tem)) = NEXT_INSN (tem);
PREV_INSN (NEXT_INSN (tem)) = PREV_INSN (tem);
if (first_use)
{
NEXT_INSN (tem) = first_use;
PREV_INSN (first_use) = tem;
}
first_use = tem;
if (!last_use)
last_use = tem;
}
first_use = 0;
if (prev
&& GET_CODE (prev) == INSN
&& GET_CODE (PATTERN (prev)) == USE)
{
/* If the end of the block is the use, grab hold of something
else so that we emit barriers etc in the right place. */
if (prev == tail)
{
do
tail = PREV_INSN (tail);
while (GET_CODE (tail) == INSN
&& GET_CODE (PATTERN (tail)) == USE);
}
emit_barrier_after (insn);
do
{
rtx use = prev;
prev = prev_nonnote_insn (prev);
seq = gen_epilogue ();
tail = emit_jump_insn_after (seq, insn);
remove_insn (use);
if (first_use)
{
NEXT_INSN (use) = first_use;
PREV_INSN (first_use) = use;
}
else
NEXT_INSN (use) = NULL_RTX;
first_use = use;
}
while (prev
&& GET_CODE (prev) == INSN
&& GET_CODE (PATTERN (prev)) == USE);
}
/* Insert the USE insns immediately before the return insn, which
must be the first instruction before the final barrier. */
if (first_use)
{
tem = prev_nonnote_insn (get_last_insn ());
NEXT_INSN (PREV_INSN (tem)) = first_use;
PREV_INSN (first_use) = PREV_INSN (tem);
PREV_INSN (tem) = last_use;
NEXT_INSN (last_use) = tem;
}
/* The last basic block ends with a NOTE_INSN_EPILOGUE_BEG, the
epilogue insns, the USE insns at the end of a function,
the jump insn that returns, and then a BARRIER. */
emit_note_after (NOTE_INSN_EPILOGUE_BEG, insn);
if (GET_CODE (tail) != BARRIER)
{
prev = next_nonnote_insn (tail);
if (!prev || GET_CODE (prev) != BARRIER)
emit_barrier_after (tail);
}
/* Include the new epilogue insns in the last block. Ignore
them if they form a basic block unto themselves. */
if (x_basic_block_end && n_basic_blocks
&& GET_CODE (BLOCK_END (n_basic_blocks - 1)) != JUMP_INSN)
BLOCK_END (n_basic_blocks - 1) = tail;
seq = gen_epilogue ();
prev = tail;
tail = emit_jump_insn_after (seq, tail);
/* Retain a map of the epilogue insns. */
epilogue = record_insns (GET_CODE (seq) == SEQUENCE ? seq : tail);
return;
/* Insert the USE insns immediately before the return insn, which
must be the last instruction emitted in the sequence. */
if (first_use)
emit_insns_before (first_use, tail);
emit_note_after (NOTE_INSN_EPILOGUE_BEG, prev);
/* Update the tail of the basic block. */
if (bb)
bb->end = tail;
/* Retain a map of the epilogue insns. */
epilogue = record_insns (GET_CODE (seq) == SEQUENCE ? seq : tail);
}
}
}
#endif
epilogue = 0;
if (insertted)
commit_edge_insertions ();
}
/* Reposition the prologue-end and epilogue-begin notes after instruction

View File

@ -83,6 +83,7 @@ struct function
int has_computed_jump;
int is_thunk;
rtx nonlocal_goto_handler_slots;
rtx nonlocal_goto_handler_labels;
rtx nonlocal_goto_stack_level;
tree nonlocal_labels;
int args_size;

View File

@ -648,7 +648,7 @@ global_conflicts ()
are explicitly marked in basic_block_live_at_start. */
{
register regset old = basic_block_live_at_start[b];
register regset old = BASIC_BLOCK (b)->global_live_at_start;
int ax = 0;
REG_SET_TO_HARD_REG_SET (hard_regs_live, old);
@ -671,12 +671,22 @@ global_conflicts ()
record_conflicts (block_start_allocnos, ax);
#ifdef STACK_REGS
/* Pseudos can't go in stack regs at the start of a basic block
that can be reached through a computed goto, since reg-stack
can't handle computed gotos. */
if (basic_block_computed_jump_target[b])
for (ax = FIRST_STACK_REG; ax <= LAST_STACK_REG; ax++)
record_one_conflict (ax);
{
/* Pseudos can't go in stack regs at the start of a basic block
that can be reached through a computed goto, since reg-stack
can't handle computed gotos. */
/* ??? Seems more likely that reg-stack can't handle any abnormal
edges, critical or not, computed goto or otherwise. */
edge e;
for (e = BASIC_BLOCK (b)->pred; e ; e = e->pred_next)
if (e->flags & EDGE_ABNORMAL)
break;
if (e != NULL)
for (ax = FIRST_STACK_REG; ax <= LAST_STACK_REG; ax++)
record_one_conflict (ax);
}
#endif
}
@ -1598,11 +1608,14 @@ mark_elimination (from, to)
int i;
for (i = 0; i < n_basic_blocks; i++)
if (REGNO_REG_SET_P (basic_block_live_at_start[i], from))
{
CLEAR_REGNO_REG_SET (basic_block_live_at_start[i], from);
SET_REGNO_REG_SET (basic_block_live_at_start[i], to);
}
{
register regset r = BASIC_BLOCK (i)->global_live_at_start;
if (REGNO_REG_SET_P (r, from))
{
CLEAR_REGNO_REG_SET (r, from);
SET_REGNO_REG_SET (r, to);
}
}
}
/* Used for communication between the following functions. Holds the
@ -1672,13 +1685,13 @@ build_insn_chain (first)
int i;
CLEAR_REG_SET (live_relevant_regs);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (REGNO_REG_SET_P (basic_block_live_at_start[b], i)
if (REGNO_REG_SET_P (BASIC_BLOCK (b)->global_live_at_start, i)
&& ! TEST_HARD_REG_BIT (eliminable_regset, i))
SET_REGNO_REG_SET (live_relevant_regs, i);
for (; i < max_regno; i++)
if (reg_renumber[i] >= 0
&& REGNO_REG_SET_P (basic_block_live_at_start[b], i))
&& REGNO_REG_SET_P (BASIC_BLOCK (b)->global_live_at_start, i))
SET_REGNO_REG_SET (live_relevant_regs, i);
}

View File

@ -160,7 +160,8 @@ darkgrey\n shape: ellipse" : "white",
"repeated_line_number",
"range_start",
"range_end",
"live"
"live",
"basic_block"
};
fprintf (fp, " %s",
@ -191,14 +192,21 @@ draw_edge (fp, from, to, bb_edge, class)
int bb_edge;
int class;
{
char * color;
switch (graph_dump_format)
{
case vcg:
color = "";
if (class == 2)
color = "color: red ";
else if (bb_edge)
color = "color: blue ";
else if (class == 3)
color = "color: green ";
fprintf (fp,
"edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s",
current_function_name, from,
current_function_name, to,
bb_edge ? "color: blue " : class ? "color: red " : "");
current_function_name, to, color);
if (class)
fprintf (fp, "class: %d ", class);
fputs ("}\n", fp);
@ -253,8 +261,8 @@ print_rtl_graph_with_bb (base, suffix, rtx_first)
char *buf = (char *) alloca (namelen + suffixlen + extlen);
FILE *fp;
/* Regenerate the basic block information. */
find_basic_blocks (rtx_first, max_reg_num (), NULL);
if (basic_block_info == NULL)
return;
memcpy (buf, base, namelen);
memcpy (buf + namelen, suffix, suffixlen);
@ -268,20 +276,14 @@ print_rtl_graph_with_bb (base, suffix, rtx_first)
fprintf (fp, "(nil)\n");
else
{
int i, bb;
int i;
enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
int max_uid = get_max_uid ();
int *start = (int *) alloca (max_uid * sizeof (int));
int *end = (int *) alloca (max_uid * sizeof (int));
enum bb_state *in_bb_p = (enum bb_state *)
alloca (max_uid * sizeof (enum bb_state));
/* Element I is a list of I's predecessors/successors. */
int_list_ptr *s_preds;
int_list_ptr *s_succs;
/* Element I is the number of predecessors/successors of basic
block I. */
int *num_preds;
int *num_succs;
basic_block bb;
for (i = 0; i < max_uid; ++i)
{
@ -292,28 +294,19 @@ print_rtl_graph_with_bb (base, suffix, rtx_first)
for (i = n_basic_blocks - 1; i >= 0; --i)
{
rtx x;
start[INSN_UID (BLOCK_HEAD (i))] = i;
end[INSN_UID (BLOCK_END (i))] = i;
for (x = BLOCK_HEAD (i); x != NULL_RTX; x = NEXT_INSN (x))
bb = BASIC_BLOCK (i);
start[INSN_UID (bb->head)] = i;
end[INSN_UID (bb->end)] = i;
for (x = bb->head; x != NULL_RTX; x = NEXT_INSN (x))
{
in_bb_p[INSN_UID (x)]
= (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
? IN_ONE_BB : IN_MULTIPLE_BB;
if (x == BLOCK_END (i))
if (x == bb->end)
break;
}
}
/* Get the information about the basic blocks predecessors and
successors. */
s_preds = (int_list_ptr *) alloca (n_basic_blocks
* sizeof (int_list_ptr));
s_succs = (int_list_ptr *) alloca (n_basic_blocks
* sizeof (int_list_ptr));
num_preds = (int *) alloca (n_basic_blocks * sizeof (int));
num_succs = (int *) alloca (n_basic_blocks * sizeof (int));
compute_preds_succs (s_preds, s_succs, num_preds, num_succs);
/* Tell print-rtl that we want graph output. */
dump_for_graph = 1;
@ -336,12 +329,12 @@ print_rtl_graph_with_bb (base, suffix, rtx_first)
continue;
}
if ((bb = start[INSN_UID (tmp_rtx)]) >= 0)
if ((i = start[INSN_UID (tmp_rtx)]) >= 0)
{
/* We start a subgraph for each basic block. */
start_bb (fp, bb);
start_bb (fp, i);
if (bb == 0)
if (i == 0)
draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0);
}
@ -349,40 +342,40 @@ print_rtl_graph_with_bb (base, suffix, rtx_first)
did_output = node_data (fp, tmp_rtx);
next_insn = next_nonnote_insn (tmp_rtx);
if ((bb = end[INSN_UID (tmp_rtx)]) >= 0)
if ((i = end[INSN_UID (tmp_rtx)]) >= 0)
{
int_list_ptr p;
edge e;
bb = BASIC_BLOCK (i);
/* End of the basic block. */
end_bb (fp, bb);
/* Now specify the edges to all the successors of this
basic block. */
for (p = s_succs[bb]; p != NULL; p = p->next)
for (e = bb->succ; e ; e = e->succ_next)
{
int bb_succ = INT_LIST_VAL (p);
if (bb_succ >= 0)
if (e->dest != EXIT_BLOCK_PTR)
{
rtx block_head = BLOCK_HEAD (bb_succ);
rtx block_head = e->dest->head;
draw_edge (fp, INSN_UID (tmp_rtx),
INSN_UID (block_head),
next_insn != block_head, 0);
next_insn != block_head,
(e->flags & EDGE_ABNORMAL ? 2 : 0));
if (BLOCK_HEAD (bb_succ) == next_insn)
if (block_head == next_insn)
edge_printed = 1;
}
else if (bb_succ == EXIT_BLOCK)
else
{
draw_edge (fp, INSN_UID (tmp_rtx), 999999,
next_insn != 0, 0);
next_insn != 0,
(e->flags & EDGE_ABNORMAL ? 2 : 0));
if (next_insn == 0)
edge_printed = 1;
}
else
abort ();
}
}
@ -395,8 +388,8 @@ print_rtl_graph_with_bb (base, suffix, rtx_first)
next_insn ? INSN_UID (next_insn) : 999999, 0, 0);
else
{
/* We draw the remaining edges in class 2. We have
to skip oevr the barrier since these nodes are
/* We draw the remaining edges in class 3. We have
to skip over the barrier since these nodes are
not printed at all. */
do
next_insn = NEXT_INSN (next_insn);
@ -405,7 +398,7 @@ print_rtl_graph_with_bb (base, suffix, rtx_first)
|| GET_CODE (next_insn) == BARRIER));
draw_edge (fp, XINT (tmp_rtx, 0),
next_insn ? INSN_UID (next_insn) : 999999, 0, 2);
next_insn ? INSN_UID (next_insn) : 999999, 0, 3);
}
}
}

View File

@ -472,8 +472,8 @@ typedef struct
int next_in;
int next_out;
}
edge;
static edge *edge_table;
haifa_edge;
static haifa_edge *edge_table;
#define NEXT_IN(edge) (edge_table[edge].next_in)
#define NEXT_OUT(edge) (edge_table[edge].next_out)
@ -1082,7 +1082,7 @@ is_cfg_nonregular ()
/* If we have a label that could be the target of a nonlocal goto, then
the cfg is not well structured. */
if (nonlocal_label_rtx_list () != NULL)
if (nonlocal_goto_handler_labels)
return 1;
/* If we have any forced labels, then the cfg is not well structured. */
@ -1169,8 +1169,8 @@ build_control_flow (s_preds, s_succs, num_preds, num_succs)
bzero ((char *) in_edges, n_basic_blocks * sizeof (int));
bzero ((char *) out_edges, n_basic_blocks * sizeof (int));
edge_table = (edge *) xmalloc ((nr_edges) * sizeof (edge));
bzero ((char *) edge_table, ((nr_edges) * sizeof (edge)));
edge_table = (haifa_edge *) xmalloc ((nr_edges) * sizeof (haifa_edge));
bzero ((char *) edge_table, ((nr_edges) * sizeof (haifa_edge)));
nr_edges = 0;
for (i = 0; i < n_basic_blocks; i++)
@ -2153,7 +2153,8 @@ check_live_1 (src, x)
{
int b = candidate_table[src].split_bbs.first_member[i];
if (REGNO_REG_SET_P (basic_block_live_at_start[b], regno + j))
if (REGNO_REG_SET_P (BASIC_BLOCK (b)->global_live_at_start,
regno + j))
{
return 0;
}
@ -2167,7 +2168,7 @@ check_live_1 (src, x)
{
int b = candidate_table[src].split_bbs.first_member[i];
if (REGNO_REG_SET_P (basic_block_live_at_start[b], regno))
if (REGNO_REG_SET_P (BASIC_BLOCK (b)->global_live_at_start, regno))
{
return 0;
}
@ -2227,7 +2228,8 @@ update_live_1 (src, x)
{
int b = candidate_table[src].update_bbs.first_member[i];
SET_REGNO_REG_SET (basic_block_live_at_start[b], regno + j);
SET_REGNO_REG_SET (BASIC_BLOCK (b)->global_live_at_start,
regno + j);
}
}
}
@ -2237,7 +2239,7 @@ update_live_1 (src, x)
{
int b = candidate_table[src].update_bbs.first_member[i];
SET_REGNO_REG_SET (basic_block_live_at_start[b], regno);
SET_REGNO_REG_SET (BASIC_BLOCK (b)->global_live_at_start, regno);
}
}
}
@ -5135,7 +5137,7 @@ finish_sometimes_live (regs_sometimes_live, sometimes_max)
/* functions for computation of registers live/usage info */
/* It is assumed that prior to scheduling basic_block_live_at_start (b)
/* It is assumed that prior to scheduling BASIC_BLOCK (b)->global_live_at_start
contains the registers that are alive at the entry to b.
Two passes follow: The first pass is performed before the scheduling
@ -5165,7 +5167,7 @@ find_pre_sched_live (bb)
int b = BB_TO_BLOCK (bb);
get_block_head_tail (bb, &head, &tail);
COPY_REG_SET (bb_live_regs, basic_block_live_at_start[b]);
COPY_REG_SET (bb_live_regs, BASIC_BLOCK (b)->global_live_at_start);
next_tail = NEXT_INSN (tail);
for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
@ -5303,7 +5305,8 @@ find_post_sched_live (bb)
int b_succ;
b_succ = TO_BLOCK (e);
IOR_REG_SET (bb_live_regs, basic_block_live_at_start[b_succ]);
IOR_REG_SET (bb_live_regs,
BASIC_BLOCK (b_succ)->global_live_at_start);
e = NEXT_OUT (e);
}
while (e != first_edge);
@ -5325,7 +5328,7 @@ find_post_sched_live (bb)
&& (GET_RTX_CLASS (GET_CODE (tail)) != 'i'))
{
if (current_nr_blocks > 1)
COPY_REG_SET (basic_block_live_at_start[b], bb_live_regs);
COPY_REG_SET (BASIC_BLOCK (b)->global_live_at_start, bb_live_regs);
return;
}
@ -5448,9 +5451,9 @@ find_post_sched_live (bb)
finish_sometimes_live (regs_sometimes_live, sometimes_max);
/* In interblock scheduling, basic_block_live_at_start may have changed. */
/* In interblock scheduling, global_live_at_start may have changed. */
if (current_nr_blocks > 1)
COPY_REG_SET (basic_block_live_at_start[b], bb_live_regs);
COPY_REG_SET (BASIC_BLOCK (b)->global_live_at_start, bb_live_regs);
FREE_REG_SET (old_live_regs);
@ -5522,7 +5525,7 @@ update_reg_usage ()
pseudos which are live in more than one block.
This is because combine might have made an optimization which
invalidated basic_block_live_at_start and reg_n_calls_crossed,
invalidated global_live_at_start and reg_n_calls_crossed,
but it does not update them. If we update reg_n_calls_crossed
here, the two variables are now inconsistent, and this might
confuse the caller-save code into saving a register that doesn't
@ -8530,7 +8533,7 @@ schedule_insns (dump_file)
/* The scheduler runs after flow; therefore, we can't blindly call
back into find_basic_blocks since doing so could invalidate the
info in basic_block_live_at_start.
info in global_live_at_start.
Consider a block consisting entirely of dead stores; after life
analysis it would be a block of NOTE_INSN_DELETED notes. If

View File

@ -3429,6 +3429,24 @@ condjump_label (insn)
return NULL_RTX;
}
/* Return true if INSN is a (possibly conditional) return insn. */
static int
returnjump_p_1 (loc, data)
rtx *loc;
void *data ATTRIBUTE_UNUSED;
{
rtx x = *loc;
return GET_CODE (x) == RETURN;
}
int
returnjump_p (insn)
rtx insn;
{
return for_each_rtx (&PATTERN (insn), returnjump_p_1, NULL);
}
#ifdef HAVE_cc0
/* Return 1 if X is an RTX that does nothing but set the condition codes

View File

@ -966,7 +966,8 @@ update_equiv_regs ()
BLOCK_HEAD (block) = PREV_INSN (insn);
for (l = 0; l < n_basic_blocks; l++)
CLEAR_REGNO_REG_SET (basic_block_live_at_start[l], regno);
CLEAR_REGNO_REG_SET (BASIC_BLOCK (l)->global_live_at_start,
regno);
}
}
}
@ -1039,7 +1040,7 @@ block_alloc (b)
/* Initialize table of hardware registers currently live. */
REG_SET_TO_HARD_REG_SET (regs_live, basic_block_live_at_start[b]);
REG_SET_TO_HARD_REG_SET (regs_live, BASIC_BLOCK (b)->global_live_at_start);
/* This loop scans the instructions of the basic block
and assigns quantities to registers.

View File

@ -22,9 +22,9 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
#include "system.h"
#include "rtl.h"
#include "bitmap.h"
#include "real.h"
#include "flags.h"
#include "basic-block.h"
/* How to print out a register name.
@ -170,6 +170,14 @@ print_rtx (in_rtx)
break;
}
if (i == 3 && GET_CODE (in_rtx) == NOTE
&& NOTE_LINE_NUMBER (in_rtx) == NOTE_INSN_BASIC_BLOCK)
{
basic_block bb = NOTE_BASIC_BLOCK (in_rtx);
fprintf (outfile, " [bb %d]", bb->index);
break;
}
if (XSTR (in_rtx, i) == 0)
fputs (dump_for_graph ? " \\\"\\\"" : " \"\"", outfile);
else

View File

@ -229,9 +229,23 @@ static rtx
/* Get the basic block number of an insn. See note at block_number
definition are validity of this information. */
#define BLOCK_NUM(INSN) \
((INSN_UID (INSN) > max_uid) \
? (abort() , -1) : block_number[INSN_UID (INSN)])
static int BLOCK_NUM PROTO((rtx));
#ifdef __GNUC__
__inline__
#endif
static int
BLOCK_NUM(insn)
rtx insn;
{
int tmp = INSN_UID (insn);
if (tmp > max_uid)
abort ();
tmp = block_number[tmp];
if (tmp < 0)
abort ();
return tmp;
}
extern rtx forced_labels;
@ -502,6 +516,7 @@ reg_to_stack (first, file)
bzero ((char *) block_out_reg_set, blocks * sizeof (HARD_REG_SET));
block_number = (int *) alloca ((max_uid + 1) * sizeof (int));
memset (block_number, -1, (max_uid + 1) * sizeof (int));
find_blocks (first);
stack_reg_life_analysis (first, &stackentry);

View File

@ -2208,12 +2208,5 @@ reg_classes_intersect_p (c1, c2)
void
regset_release_memory ()
{
if (basic_block_live_at_start)
{
free_regset_vector (basic_block_live_at_start, n_basic_blocks);
basic_block_live_at_start = 0;
}
FREE_REG_SET (regs_live_at_setjmp);
bitmap_release_memory ();
}

View File

@ -267,7 +267,7 @@ mark_flags_life_zones (flags)
{
int i;
for (i = 0; i < flags_nregs; ++i)
live |= REGNO_REG_SET_P (basic_block_live_at_start[block],
live |= REGNO_REG_SET_P (BASIC_BLOCK (block)->global_live_at_start,
flags_regno + i);
}
#endif

View File

@ -538,9 +538,9 @@ compute_use_by_pseudos (to, from)
if (r < 0)
{
/* reload_combine uses the information from
basic_block_live_at_start, which might still contain registers
that have not actually been allocated since they have an
equivalence. */
BASIC_BLOCK->global_live_at_start, which might still
contain registers that have not actually been allocated
since they have an equivalence. */
if (! reload_completed)
abort ();
}
@ -1060,7 +1060,7 @@ reload (first, global, dumpfile)
if (! frame_pointer_needed)
for (i = 0; i < n_basic_blocks; i++)
CLEAR_REGNO_REG_SET (basic_block_live_at_start[i],
CLEAR_REGNO_REG_SET (BASIC_BLOCK (i)->global_live_at_start,
HARD_FRAME_POINTER_REGNUM);
/* Come here (with failure set nonzero) if we can't get enough spill regs
@ -9494,8 +9494,8 @@ reload_combine ()
{
HARD_REG_SET live;
REG_SET_TO_HARD_REG_SET (live, basic_block_live_at_start[i]);
compute_use_by_pseudos (&live, basic_block_live_at_start[i]);
REG_SET_TO_HARD_REG_SET (live, BASIC_BLOCK (i)->global_live_at_start);
compute_use_by_pseudos (&live, BASIC_BLOCK (i)->global_live_at_start);
COPY_HARD_REG_SET (LABEL_LIVE (insn), live);
IOR_HARD_REG_SET (ever_live_at_start, live);
}

View File

@ -875,7 +875,7 @@ mark_target_live_regs (insns, target, res)
TARGET. Otherwise, we must assume everything is live. */
if (b != -1)
{
regset regs_live = basic_block_live_at_start[b];
regset regs_live = BASIC_BLOCK (b)->global_live_at_start;
int j;
int regno;
rtx start_insn, stop_insn;

View File

@ -184,7 +184,8 @@ char *note_insn_name[] = { 0 , "NOTE_INSN_DELETED",
"NOTE_INSN_DELETED_LABEL", "NOTE_INSN_FUNCTION_BEG",
"NOTE_INSN_EH_REGION_BEG", "NOTE_INSN_EH_REGION_END",
"NOTE_REPEATED_LINE_NUMBER", "NOTE_INSN_RANGE_START",
"NOTE_INSN_RANGE_END", "NOTE_INSN_LIVE" };
"NOTE_INSN_RANGE_END", "NOTE_INSN_LIVE",
"NOTE_INSN_BASIC_BLOCK" };
char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0",
"REG_EQUAL", "REG_RETVAL", "REG_LIBCALL",

View File

@ -91,6 +91,7 @@ typedef union rtunion_def
addr_diff_vec_flags rt_addr_diff_vec_flags;
struct bitmap_head_def *rtbit;
union tree_node *rttree;
struct basic_block_def *bb;
} rtunion;
/* RTL expression ("rtx"). */
@ -404,6 +405,7 @@ extern char *reg_note_name[];
#define NOTE_BLOCK_NUMBER(INSN) ((INSN)->fld[3].rtint)
#define NOTE_RANGE_INFO(INSN) ((INSN)->fld[3].rtx)
#define NOTE_LIVE_INFO(INSN) ((INSN)->fld[3].rtx)
#define NOTE_BASIC_BLOCK(INSN) ((INSN)->fld[3].bb)
/* If the NOTE_BLOCK_NUMBER field gets a -1, it means create a new
block node for a live range block. */
@ -469,6 +471,8 @@ extern char *reg_note_name[];
#define NOTE_INSN_RANGE_END -18
/* Record which registers are currently live. */
#define NOTE_INSN_LIVE -19
/* Record the struct for the following basic block. */
#define NOTE_INSN_BASIC_BLOCK -20
#if 0 /* These are not used, and I don't know what they were for. --rms. */
#define NOTE_DECL_NAME(INSN) ((INSN)->fld[3].rtstr)
@ -932,6 +936,7 @@ extern rtx emit_insn_before PROTO((rtx, rtx));
extern rtx emit_jump_insn_before PROTO((rtx, rtx));
extern rtx emit_call_insn_before PROTO((rtx, rtx));
extern rtx emit_barrier_before PROTO((rtx));
extern rtx emit_label_before PROTO((rtx, rtx));
extern rtx emit_note_before PROTO((int, rtx));
extern rtx emit_insn_after PROTO((rtx, rtx));
extern rtx emit_jump_insn_after PROTO((rtx, rtx));
@ -982,7 +987,6 @@ extern rtx simplify_unary_operation PROTO((enum rtx_code, enum machine_mode, rtx
extern rtx simplify_binary_operation PROTO((enum rtx_code, enum machine_mode, rtx, rtx));
extern rtx simplify_ternary_operation PROTO((enum rtx_code, enum machine_mode, enum machine_mode, rtx, rtx, rtx));
extern rtx simplify_relational_operation PROTO((enum rtx_code, enum machine_mode, rtx, rtx));
extern rtx nonlocal_label_rtx_list PROTO((void));
extern rtx gen_move_insn PROTO((rtx, rtx));
extern rtx gen_jump PROTO((rtx));
extern rtx gen_beq PROTO((rtx));
@ -1300,6 +1304,7 @@ extern int comparison_dominates_p PROTO ((enum rtx_code, enum rtx_code));
extern int condjump_p PROTO ((rtx));
extern rtx condjump_label PROTO ((rtx));
extern int simplejump_p PROTO ((rtx));
extern int returnjump_p PROTO ((rtx));
extern int sets_cc0_p PROTO ((rtx));
extern int invert_jump PROTO ((rtx, rtx));
extern int rtx_renumbered_equal_p PROTO ((rtx, rtx));
@ -1415,6 +1420,10 @@ extern void expand_null_return PROTO((void));
extern void emit_jump PROTO ((rtx));
extern int preserve_subexpressions_p PROTO ((void));
/* List (chain of EXPR_LIST) of labels heading the current handlers for
nonlocal gotos. */
extern rtx nonlocal_goto_handler_labels;
/* In expr.c */
extern void init_expr_once PROTO ((void));
extern void move_by_pieces PROTO ((rtx, rtx, int, int));

View File

@ -2879,7 +2879,7 @@ schedule_block (b, file)
if (reload_completed == 0)
{
COPY_REG_SET (bb_live_regs, basic_block_live_at_start[b]);
COPY_REG_SET (bb_live_regs, BASIC_BLOCK (b)->global_live_at_start);
CLEAR_REG_SET (bb_dead_regs);
if (b == 0)

View File

@ -428,7 +428,7 @@ static int using_eh_for_cleanups_p = 0;
static int n_occurrences PROTO((int, char *));
static void expand_goto_internal PROTO((tree, rtx, rtx));
static int expand_fixup PROTO((tree, rtx, rtx));
static void expand_nl_handler_label PROTO((rtx, rtx));
static rtx expand_nl_handler_label PROTO((rtx, rtx));
static void expand_nl_goto_receiver PROTO((void));
static void expand_nl_goto_receivers PROTO((struct nesting *));
static void fixup_gotos PROTO((struct nesting *, rtx, tree,
@ -3169,7 +3169,7 @@ remember_end_note (block)
/* Emit a handler label for a nonlocal goto handler.
Also emit code to store the handler label in SLOT before BEFORE_INSN. */
static void
static rtx
expand_nl_handler_label (slot, before_insn)
rtx slot, before_insn;
{
@ -3186,6 +3186,8 @@ expand_nl_handler_label (slot, before_insn)
emit_insns_before (insns, before_insn);
emit_label (handler_label);
return handler_label;
}
/* Emit code to restore vital registers at the beginning of a nonlocal goto
@ -3260,6 +3262,7 @@ expand_nl_goto_receivers (thisblock)
tree link;
rtx afterward = gen_label_rtx ();
rtx insns, slot;
rtx label_list;
int any_invalid;
/* Record the handler address in the stack slot for that purpose,
@ -3283,14 +3286,18 @@ expand_nl_goto_receivers (thisblock)
/* Make a separate handler for each label. */
link = nonlocal_labels;
slot = nonlocal_goto_handler_slots;
label_list = NULL_RTX;
for (; link; link = TREE_CHAIN (link), slot = XEXP (slot, 1))
/* Skip any labels we shouldn't be able to jump to from here,
we generate one special handler for all of them below which just calls
abort. */
if (! DECL_TOO_LATE (TREE_VALUE (link)))
{
expand_nl_handler_label (XEXP (slot, 0),
thisblock->data.block.first_insn);
rtx lab;
lab = expand_nl_handler_label (XEXP (slot, 0),
thisblock->data.block.first_insn);
label_list = gen_rtx_EXPR_LIST (VOIDmode, lab, label_list);
expand_nl_goto_receiver ();
/* Jump to the "real" nonlocal label. */
@ -3305,8 +3312,10 @@ expand_nl_goto_receivers (thisblock)
for (; link; link = TREE_CHAIN (link), slot = XEXP (slot, 1))
if (DECL_TOO_LATE (TREE_VALUE (link)))
{
expand_nl_handler_label (XEXP (slot, 0),
thisblock->data.block.first_insn);
rtx lab;
lab = expand_nl_handler_label (XEXP (slot, 0),
thisblock->data.block.first_insn);
label_list = gen_rtx_EXPR_LIST (VOIDmode, lab, label_list);
any_invalid = 1;
}
@ -3318,6 +3327,7 @@ expand_nl_goto_receivers (thisblock)
emit_barrier ();
}
nonlocal_goto_handler_labels = label_list;
emit_label (afterward);
}

View File

@ -292,6 +292,7 @@ int regmove_dump = 0;
int sched_dump = 0;
int local_reg_dump = 0;
int global_reg_dump = 0;
int flow2_dump = 0;
int sched2_dump = 0;
int jump2_opt_dump = 0;
#ifdef DELAY_SLOTS
@ -1286,6 +1287,7 @@ int regmove_time;
int sched_time;
int local_alloc_time;
int global_alloc_time;
int flow2_time;
int sched2_time;
#ifdef DELAY_SLOTS
int dbr_sched_time;
@ -2642,6 +2644,7 @@ compile_file (name)
sched_time = 0;
local_alloc_time = 0;
global_alloc_time = 0;
flow2_time = 0;
sched2_time = 0;
#ifdef DELAY_SLOTS
dbr_sched_time = 0;
@ -2759,6 +2762,12 @@ compile_file (name)
if (graph_dump_format != no_graph)
clean_graph_dump_file (dump_base_name, ".greg");
}
if (flow2_dump)
{
clean_dump_file (".flow2");
if (graph_dump_format != no_graph)
clean_graph_dump_file (dump_base_name, ".flow2");
}
if (sched2_dump)
{
clean_dump_file (".sched2");
@ -3303,6 +3312,8 @@ compile_file (name)
finish_graph_dump_file (dump_base_name, ".lreg");
if (global_reg_dump)
finish_graph_dump_file (dump_base_name, ".greg");
if (flow_dump)
finish_graph_dump_file (dump_base_name, ".flow2");
if (sched2_dump)
finish_graph_dump_file (dump_base_name, ".sched2");
if (jump2_opt_dump)
@ -3346,6 +3357,7 @@ compile_file (name)
print_time ("sched", sched_time);
print_time ("local-alloc", local_alloc_time);
print_time ("global-alloc", global_alloc_time);
print_time ("flow2", flow2_time);
print_time ("sched2", sched2_time);
#ifdef DELAY_SLOTS
print_time ("dbranch", dbr_sched_time);
@ -4079,14 +4091,27 @@ rest_of_compilation (decl)
}
}
if (global_reg_dump)
{
TIMEVAR (dump_time, dump_global_regs (rtl_dump_file));
close_dump_file (print_rtl_with_bb, insns);
if (graph_dump_format != no_graph)
print_rtl_graph_with_bb (dump_base_name, ".greg", insns);
}
/* Re-create the death notes which were deleted during reload. */
if (flow2_dump)
open_dump_file (".flow2", decl_printable_name (decl, 2));
if (optimize)
TIMEVAR
(flow_time,
{
find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
life_analysis (insns, max_reg_num (), rtl_dump_file);
});
{
TIMEVAR
(flow2_time,
{
find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
life_analysis (insns, max_reg_num (), rtl_dump_file);
});
}
flow2_completed = 1;
@ -4097,13 +4122,13 @@ rest_of_compilation (decl)
thread_prologue_and_epilogue_insns (insns);
if (global_reg_dump)
if (flow2_dump)
{
TIMEVAR (dump_time, dump_global_regs (rtl_dump_file));
close_dump_file (print_rtl_with_bb, insns);
if (graph_dump_format != no_graph)
print_rtl_graph_with_bb (dump_base_name, ".greg", insns);
print_rtl_graph_with_bb (dump_base_name, ".flow2", insns);
}
if (optimize > 0 && flag_schedule_insns_after_reload)
{
if (sched2_dump)
@ -4227,6 +4252,9 @@ rest_of_compilation (decl)
if (! quiet_flag)
fflush (asm_out_file);
/* Release all memory allocated by flow. */
free_basic_block_vars (0);
/* Release all memory held by regsets now */
regset_release_memory ();
});
@ -4258,7 +4286,7 @@ rest_of_compilation (decl)
exit_rest_of_compilation:
free_bb_memory ();
free_bb_mem ();
/* In case the function was not output,
don't leave any temporary anonymous types
@ -4770,6 +4798,7 @@ main (argc, argv)
dbr_sched_dump = 1;
#endif
flow_dump = 1;
flow2_dump = 1;
global_reg_dump = 1;
jump_opt_dump = 1;
addressof_dump = 1;
@ -4864,6 +4893,9 @@ main (argc, argv)
case 'v':
graph_dump_format = vcg;
break;
case 'w':
flow2_dump = 1;
break;
case 'y':
set_yydebug (1);
break;

View File

@ -2129,8 +2129,12 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
case NOTE:
/* VTOP notes are valid only before the loop exit test. If placed
anywhere else, loop may generate bad code. */
/* BASIC_BLOCK notes exist to stabilize basic block structures with
the associated rtl. We do not want to share the structure in
this new block. */
if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK
&& (NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_VTOP
|| (last_iteration && unroll_type != UNROLL_COMPLETELY)))
copy = emit_note (NOTE_SOURCE_FILE (insn),
@ -2175,7 +2179,8 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
for (insn = copy_notes_from; insn != loop_end; insn = NEXT_INSN (insn))
{
if (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED)
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)
emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
}
}

View File

@ -75,6 +75,7 @@ typedef union varray_data_tag {
struct sched_info_tag *sched[1];
struct reg_info_def *reg[1];
struct const_equiv_data const_equiv[1];
struct basic_block_def *bb[1];
} varray_data;
/* Virtual array of pointers header. */
@ -146,6 +147,9 @@ extern varray_type varray_init PROTO ((size_t, size_t, const char *));
#define VARRAY_CONST_EQUIV_INIT(va, num, name) \
va = varray_init (num, sizeof (struct const_equiv_data), name)
#define VARRAY_BB_INIT(va, num, name) \
va = varray_init (num, sizeof (struct basic_block_def *), name)
/* Free up memory allocated by the virtual array, but do not free any of the
elements involved. */
#define VARRAY_FREE(vp) \
@ -189,6 +193,7 @@ extern varray_type varray_grow PROTO((varray_type, size_t));
#define VARRAY_BITMAP(VA, N) ((VA)->data.bitmap[ VARRAY_CHECK (VA, N) ])
#define VARRAY_SCHED(VA, N) ((VA)->data.sched[ VARRAY_CHECK (VA, N) ])
#define VARRAY_REG(VA, N) ((VA)->data.reg[ VARRAY_CHECK (VA, N) ])
#define VARRAY_CONST_EQUIV(VA, N) ((VA)->data.const_equiv[ VARRAY_CHECK (VA, N) ])
#define VARRAY_CONST_EQUIV(VA, N) ((VA)->data.const_equiv[VARRAY_CHECK (VA, N)])
#define VARRAY_BB(VA, N) ((VA)->data.bb[ VARRAY_CHECK (VA, N) ])
#endif /* _VARRAY_H_ */