Commit d3a923ee by Richard Henderson Committed by Richard Henderson

Makefile.in (flow.o): Depend on TREE_H.

	* Makefile.in (flow.o): Depend on TREE_H.
	* basic-block.h (REG_SET_EQUAL_P): New.
	(XOR_REG_SET): New.
	(n_edges): Declare.
	(free_regset_vector): Remove declaration.
	(flow_delete_insn_chain): Declare.
	(enum update_life_extent): New.
	(update_life_info, count_or_remove_death_notes): Declare.
	* combine.c (distribute_notes) [REG_DEAD]: Stop search at bb->head.
	Verify register live at bb->global_live_at_start before adding USE.
	* flow.c (HAVE_epilogue, HAVE_prologue): Provide default.
	(CLEAN_ALLOCA): New.
	(n_edges): New.
	(PROP_*): New flags.
	(find_basic_blocks_1): Use alloc_EXPR_LIST.
	(clear_edges): Zero n_edges.
	(make_edge): Increment n_edges.
	(split_edge): Don't allocate bb->local_set.  Increment n_edges.
	(flow_delete_insn_chain): Export.
	(delete_block): Decrement n_edges.
	(merge_blocks_nomove): Likewise.
	(life_analysis): Give life_analysis_1 PROP flags.
	(verify_wide_reg_1, verify_wide_reg): New.
	(verify_local_live_at_start): New.
	(update_life_info): Rewrite to call into propogate_block.
	(mark_reg): New.
	(mark_regs_live_at_end): After reload, if epilogue as rtl,
	always mark stack pointer.  Conditionally mark PIC register.
	After reload, mark call-saved registers, return regsiters.
	(life_analysis_1): Accept PROP flags not remove_dead_code.
	Call mark_regs_live_at_end before zeroing regs_ever_live.
	Use calculate_global_regs_live.  Copy global_live_at_end before
	calling final propagate_block.  Zero reg_next_use on exit.
	(calculate_global_regs_live): New.
	(allocate_bb_life_data): Don't allocate bb->local_set.
	(init_regset_vector, free_regset_vector): Remove.
	(propagate_block): Accept FLAGS not FINAL or REMOVE_DEAD_CODE.
	Test flags before every operation.  Warn if prologue/epilogue insn
	would have been deleted.
	(mark_set_regs, mark_set_1): Accept and use FLAGS.
	Use alloc_EXPR_LIST.
	(mark_used_regs): Accept and use FLAGS, not FINAL.
	Remove special handling for RETURN.
	(try_pre_increment): Use alloc_EXPR_LIST.
	(dump_flow_info): Dump n_edges.
	(unlink_insn_chain, split_hard_reg_notes): Remove.
	(maybe_add_dead_note, maybe_add_dead_note_use): Remove.
	(find_insn_with_note, new_insn_dead_notes): Remove.
	(update_n_sets, sets_reg_or_subreg_1, sets_reg_or_subreg): Remove.
	(maybe_remove_dead_notes, prepend_reg_notes): Remove.
	(replace_insns): Remove.
	(count_or_remove_death_notes): New.
	(verify_flow_info): Abort on error after all checks.
	(remove_edge): Decrement n_edges.
	(remove_fake_edges): Tweek format.
	* haifa-sched.c (schedule_insns): Use split_all_insns.
	* output.h (update_life_info): Remove declaration.
	* recog.c (split_all_insns): From the corpse of split_block_insns,
	do the whole function block by block.  Use update_life_info.
	(recog_last_allowed_insn): New.
	(recog_next_insn): Mind it.
	(peephole2_optimize): Set it.  Walk backwards through blocks.
	Use update_life_info.
	* rtl.h (update_flow_info, replace_insns): Remove declarations.
	(split_all_insns): Declare.
	* toplev.c (rest_of_compilation): Thread prologue before flow2.
	Use split_all_insns.

	* i386.md (or -1 peep2s): Disable.

From-SVN: r29877
parent 1640ef38
Sat Oct 9 12:18:16 1999 Richard Henderson <rth@cygnus.com>
* Makefile.in (flow.o): Depend on TREE_H.
* basic-block.h (REG_SET_EQUAL_P): New.
(XOR_REG_SET): New.
(n_edges): Declare.
(free_regset_vector): Remove declaration.
(flow_delete_insn_chain): Declare.
(enum update_life_extent): New.
(update_life_info, count_or_remove_death_notes): Declare.
* combine.c (distribute_notes) [REG_DEAD]: Stop search at bb->head.
Verify register live at bb->global_live_at_start before adding USE.
* flow.c (HAVE_epilogue, HAVE_prologue): Provide default.
(CLEAN_ALLOCA): New.
(n_edges): New.
(PROP_*): New flags.
(find_basic_blocks_1): Use alloc_EXPR_LIST.
(clear_edges): Zero n_edges.
(make_edge): Increment n_edges.
(split_edge): Don't allocate bb->local_set. Increment n_edges.
(flow_delete_insn_chain): Export.
(delete_block): Decrement n_edges.
(merge_blocks_nomove): Likewise.
(life_analysis): Give life_analysis_1 PROP flags.
(verify_wide_reg_1, verify_wide_reg): New.
(verify_local_live_at_start): New.
(update_life_info): Rewrite to call into propogate_block.
(mark_reg): New.
(mark_regs_live_at_end): After reload, if epilogue as rtl,
always mark stack pointer. Conditionally mark PIC register.
After reload, mark call-saved registers, return regsiters.
(life_analysis_1): Accept PROP flags not remove_dead_code.
Call mark_regs_live_at_end before zeroing regs_ever_live.
Use calculate_global_regs_live. Copy global_live_at_end before
calling final propagate_block. Zero reg_next_use on exit.
(calculate_global_regs_live): New.
(allocate_bb_life_data): Don't allocate bb->local_set.
(init_regset_vector, free_regset_vector): Remove.
(propagate_block): Accept FLAGS not FINAL or REMOVE_DEAD_CODE.
Test flags before every operation. Warn if prologue/epilogue insn
would have been deleted.
(mark_set_regs, mark_set_1): Accept and use FLAGS.
Use alloc_EXPR_LIST.
(mark_used_regs): Accept and use FLAGS, not FINAL.
Remove special handling for RETURN.
(try_pre_increment): Use alloc_EXPR_LIST.
(dump_flow_info): Dump n_edges.
(unlink_insn_chain, split_hard_reg_notes): Remove.
(maybe_add_dead_note, maybe_add_dead_note_use): Remove.
(find_insn_with_note, new_insn_dead_notes): Remove.
(update_n_sets, sets_reg_or_subreg_1, sets_reg_or_subreg): Remove.
(maybe_remove_dead_notes, prepend_reg_notes): Remove.
(replace_insns): Remove.
(count_or_remove_death_notes): New.
(verify_flow_info): Abort on error after all checks.
(remove_edge): Decrement n_edges.
(remove_fake_edges): Tweek format.
* haifa-sched.c (schedule_insns): Use split_all_insns.
* output.h (update_life_info): Remove declaration.
* recog.c (split_all_insns): From the corpse of split_block_insns,
do the whole function block by block. Use update_life_info.
(recog_last_allowed_insn): New.
(recog_next_insn): Mind it.
(peephole2_optimize): Set it. Walk backwards through blocks.
Use update_life_info.
* rtl.h (update_flow_info, replace_insns): Remove declarations.
(split_all_insns): Declare.
* toplev.c (rest_of_compilation): Thread prologue before flow2.
Use split_all_insns.
* i386.md (or -1 peep2s): Disable.
Fri Oct 8 17:49:08 1999 Richard Henderson <rth@cygnus.com> Fri Oct 8 17:49:08 1999 Richard Henderson <rth@cygnus.com>
* config/mips/mips.md (movstrsi+[123]) : Combine these into * config/mips/mips.md (movstrsi+[123]) : Combine these into
......
...@@ -1549,7 +1549,7 @@ loop.o : loop.c $(CONFIG_H) system.h $(RTL_H) flags.h loop.h insn-config.h \ ...@@ -1549,7 +1549,7 @@ loop.o : loop.c $(CONFIG_H) system.h $(RTL_H) flags.h loop.h insn-config.h \
function.h toplev.h varray.h function.h toplev.h varray.h
unroll.o : unroll.c $(CONFIG_H) system.h $(RTL_H) insn-config.h function.h \ unroll.o : unroll.c $(CONFIG_H) system.h $(RTL_H) insn-config.h function.h \
integrate.h $(REGS_H) $(RECOG_H) flags.h $(EXPR_H) loop.h toplev.h varray.h integrate.h $(REGS_H) $(RECOG_H) flags.h $(EXPR_H) loop.h toplev.h varray.h
flow.o : flow.c $(CONFIG_H) system.h $(RTL_H) flags.h insn-config.h \ flow.o : flow.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 \ $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h recog.h \
insn-flags.h function.h insn-flags.h function.h
combine.o : combine.c $(CONFIG_H) system.h $(RTL_H) flags.h function.h \ combine.o : combine.c $(CONFIG_H) system.h $(RTL_H) flags.h function.h \
......
...@@ -31,6 +31,9 @@ typedef bitmap regset; /* Head of register set linked list. */ ...@@ -31,6 +31,9 @@ typedef bitmap regset; /* Head of register set linked list. */
/* Copy a register set to another register set. */ /* Copy a register set to another register set. */
#define COPY_REG_SET(TO, FROM) bitmap_copy (TO, FROM) #define COPY_REG_SET(TO, FROM) bitmap_copy (TO, FROM)
/* Compare two register sets. */
#define REG_SET_EQUAL_P(A, B) bitmap_equal_p (A, B)
/* `and' a register set with a second register set. */ /* `and' a register set with a second register set. */
#define AND_REG_SET(TO, FROM) bitmap_operation (TO, TO, FROM, BITMAP_AND) #define AND_REG_SET(TO, FROM) bitmap_operation (TO, TO, FROM, BITMAP_AND)
...@@ -41,6 +44,9 @@ typedef bitmap regset; /* Head of register set linked list. */ ...@@ -41,6 +44,9 @@ typedef bitmap regset; /* Head of register set linked list. */
/* Inclusive or a register set with a second register set. */ /* Inclusive or a register set with a second register set. */
#define IOR_REG_SET(TO, FROM) bitmap_operation (TO, TO, FROM, BITMAP_IOR) #define IOR_REG_SET(TO, FROM) bitmap_operation (TO, TO, FROM, BITMAP_IOR)
/* Exclusive or a register set with a second register set. */
#define XOR_REG_SET(TO, FROM) bitmap_operation (TO, TO, FROM, BITMAP_XOR)
/* Or into TO the register set FROM1 `and'ed with the complement of FROM2. */ /* Or into TO the register set FROM1 `and'ed with the complement of FROM2. */
#define IOR_AND_COMPL_REG_SET(TO, FROM1, FROM2) \ #define IOR_AND_COMPL_REG_SET(TO, FROM1, FROM2) \
bitmap_ior_and_compl (TO, FROM1, FROM2) bitmap_ior_and_compl (TO, FROM1, FROM2)
...@@ -153,6 +159,10 @@ typedef struct basic_block_def { ...@@ -153,6 +159,10 @@ typedef struct basic_block_def {
extern int n_basic_blocks; extern int n_basic_blocks;
/* Number of edges in the current function. */
extern int n_edges;
/* Index by basic block number, get basic block struct info. */ /* Index by basic block number, get basic block struct info. */
extern varray_type basic_block_info; extern varray_type basic_block_info;
...@@ -229,9 +239,6 @@ extern struct basic_block_def entry_exit_blocks[2]; ...@@ -229,9 +239,6 @@ extern struct basic_block_def entry_exit_blocks[2];
#define ENTRY_BLOCK_PTR (&entry_exit_blocks[0]) #define ENTRY_BLOCK_PTR (&entry_exit_blocks[0])
#define EXIT_BLOCK_PTR (&entry_exit_blocks[1]) #define EXIT_BLOCK_PTR (&entry_exit_blocks[1])
/* from flow.c */
extern void free_regset_vector PROTO ((regset *, int nelts));
extern varray_type basic_block_for_insn; extern varray_type basic_block_for_insn;
#define BLOCK_FOR_INSN(INSN) VARRAY_BB (basic_block_for_insn, INSN_UID (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) #define BLOCK_NUM(INSN) (BLOCK_FOR_INSN (INSN)->index + 0)
...@@ -249,6 +256,7 @@ extern void insert_insn_on_edge PROTO ((rtx, edge)); ...@@ -249,6 +256,7 @@ extern void insert_insn_on_edge PROTO ((rtx, edge));
extern void commit_edge_insertions PROTO ((void)); extern void commit_edge_insertions PROTO ((void));
extern void remove_fake_edges PROTO ((void)); extern void remove_fake_edges PROTO ((void));
extern void add_noreturn_fake_exit_edges PROTO ((void)); extern void add_noreturn_fake_exit_edges PROTO ((void));
extern void flow_delete_insn_chain PROTO((rtx, rtx));
/* This structure maintains an edge list vector. */ /* This structure maintains an edge list vector. */
struct edge_list struct edge_list
...@@ -291,6 +299,15 @@ extern void compute_dominators PROTO ((sbitmap *, sbitmap *, ...@@ -291,6 +299,15 @@ extern void compute_dominators PROTO ((sbitmap *, sbitmap *,
extern void compute_flow_dominators PROTO ((sbitmap *, sbitmap *)); extern void compute_flow_dominators PROTO ((sbitmap *, sbitmap *));
extern void compute_immediate_dominators PROTO ((int *, sbitmap *)); extern void compute_immediate_dominators PROTO ((int *, sbitmap *));
enum update_life_extent
{
UPDATE_LIFE_GLOBAL = 0,
UPDATE_LIFE_LOCAL = 1
};
extern void update_life_info PROTO ((sbitmap, enum update_life_extent));
extern int count_or_remove_death_notes PROTO ((sbitmap, int));
/* In lcm.c */ /* In lcm.c */
extern void pre_lcm PROTO ((int, int, int_list_ptr *, extern void pre_lcm PROTO ((int, int, int_list_ptr *,
int_list_ptr *, int_list_ptr *,
......
...@@ -11721,11 +11721,17 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1) ...@@ -11721,11 +11721,17 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
if (place == 0) if (place == 0)
{ {
for (tem = prev_nonnote_insn (i3); basic_block bb = BASIC_BLOCK (this_basic_block);
place == 0 && tem
&& (GET_CODE (tem) == INSN || GET_CODE (tem) == CALL_INSN); for (tem = PREV_INSN (i3); place == 0; tem = PREV_INSN (tem))
tem = prev_nonnote_insn (tem)) {
if (GET_RTX_CLASS (GET_CODE (tem)) != 'i')
{ {
if (tem == bb->head)
break;
continue;
}
/* If the register is being set at TEM, see if that is all /* If the register is being set at TEM, see if that is all
TEM is doing. If so, delete TEM. Otherwise, make this TEM is doing. If so, delete TEM. Otherwise, make this
into a REG_UNUSED note instead. */ into a REG_UNUSED note instead. */
...@@ -11789,7 +11795,8 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1) ...@@ -11789,7 +11795,8 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
distribute_links (LOG_LINKS (cc0_setter)); distribute_links (LOG_LINKS (cc0_setter));
PUT_CODE (cc0_setter, NOTE); PUT_CODE (cc0_setter, NOTE);
NOTE_LINE_NUMBER (cc0_setter) = NOTE_INSN_DELETED; NOTE_LINE_NUMBER (cc0_setter)
= NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (cc0_setter) = 0; NOTE_SOURCE_FILE (cc0_setter) = 0;
} }
#endif #endif
...@@ -11843,23 +11850,39 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1) ...@@ -11843,23 +11850,39 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
} }
break; break;
} }
if (tem == bb->head)
break;
} }
/* If we haven't found an insn for the death note and it /* We haven't found an insn for the death note and it
is still a REG_DEAD note, but we have hit a CODE_LABEL, is still a REG_DEAD note, but we have hit the beginning
insert a USE insn for the register at that label and of the block. If the existing life info says the reg
put the death node there. This prevents problems with was dead, there's nothing left to do.
call-state tracking in caller-save.c. */
if (REG_NOTE_KIND (note) == REG_DEAD && place == 0 && tem != 0) ??? If the register was live, we ought to mark for later
global life update. Cop out like the previous code and
just add a hook for the death note to live on. */
if (REG_NOTE_KIND (note) == REG_DEAD && place == 0)
{ {
place int regno = REGNO (XEXP (note, 0));
= emit_insn_after (gen_rtx_USE (VOIDmode, XEXP (note, 0)),
tem);
/* If this insn was emitted between blocks, then update if (REGNO_REG_SET_P (bb->global_live_at_start, regno))
BLOCK_HEAD of the current block to include it. */ {
if (BLOCK_END (this_basic_block - 1) == tem) rtx die = gen_rtx_USE (VOIDmode, XEXP (note, 0));
BLOCK_HEAD (this_basic_block) = place;
place = bb->head;
if (GET_CODE (place) != CODE_LABEL
&& GET_CODE (place) != NOTE)
{
place = emit_insn_before (die, place);
bb->head = place;
}
else
{
place = emit_insn_after (die, place);
}
}
} }
} }
...@@ -11869,7 +11892,6 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1) ...@@ -11869,7 +11892,6 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
which is what `dead_or_set_p' checks, so also check for it being which is what `dead_or_set_p' checks, so also check for it being
set partially. */ set partially. */
if (place && REG_NOTE_KIND (note) == REG_DEAD) if (place && REG_NOTE_KIND (note) == REG_DEAD)
{ {
int regno = REGNO (XEXP (note, 0)); int regno = REGNO (XEXP (note, 0));
......
...@@ -8146,11 +8146,14 @@ ...@@ -8146,11 +8146,14 @@
(clobber (reg:CC 17))])] (clobber (reg:CC 17))])]
"") "")
;; ??? Rewrite these to not introduce the false dependancy.
;; Currently they'll trip update_life_info's sanity checks.
;; For HI and SI modes, or $-1,reg is smaller than mov $-1,reg. ;; For HI and SI modes, or $-1,reg is smaller than mov $-1,reg.
(define_peephole2 (define_peephole2
[(set (match_operand:SI 0 "register_operand" "") [(set (match_operand:SI 0 "register_operand" "")
(const_int -1))] (const_int -1))]
"(optimize_size || TARGET_PENTIUM) "0 && (optimize_size || TARGET_PENTIUM)
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))" && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
[(parallel [(set (match_dup 0) [(parallel [(set (match_dup 0)
(ior:SI (match_dup 0) (const_int -1))) (ior:SI (match_dup 0) (const_int -1)))
...@@ -8160,7 +8163,7 @@ ...@@ -8160,7 +8163,7 @@
(define_peephole2 (define_peephole2
[(set (match_operand:HI 0 "register_operand" "") [(set (match_operand:HI 0 "register_operand" "")
(const_int -1))] (const_int -1))]
"(optimize_size || TARGET_PENTIUM) "0 && (optimize_size || TARGET_PENTIUM)
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))" && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
[(parallel [(set (match_dup 0) [(parallel [(set (match_dup 0)
(ior:HI (match_dup 0) (const_int -1))) (ior:HI (match_dup 0) (const_int -1)))
......
...@@ -7773,9 +7773,7 @@ schedule_insns (dump_file) ...@@ -7773,9 +7773,7 @@ schedule_insns (dump_file)
/* Initialize issue_rate. */ /* Initialize issue_rate. */
issue_rate = ISSUE_RATE; issue_rate = ISSUE_RATE;
/* Do the splitting first for all blocks. */ split_all_insns (1);
for (b = 0; b < n_basic_blocks; b++)
split_block_insns (b, 1);
max_uid = (get_max_uid () + 1); max_uid = (get_max_uid () + 1);
......
...@@ -135,7 +135,6 @@ extern void find_basic_blocks PROTO((rtx, int, FILE *, int)); ...@@ -135,7 +135,6 @@ extern void find_basic_blocks PROTO((rtx, int, FILE *, int));
extern void free_basic_block_vars PROTO((int)); extern void free_basic_block_vars PROTO((int));
extern void set_block_num PROTO((rtx, int)); extern void set_block_num PROTO((rtx, int));
extern void life_analysis PROTO((rtx, int, FILE *, int)); extern void life_analysis PROTO((rtx, int, FILE *, int));
extern void update_life_info PROTO((rtx, rtx, rtx, rtx, rtx));
#endif #endif
/* Functions in varasm.c. */ /* Functions in varasm.c. */
......
...@@ -2562,88 +2562,104 @@ reg_fits_class_p (operand, class, offset, mode) ...@@ -2562,88 +2562,104 @@ reg_fits_class_p (operand, class, offset, mode)
return 0; return 0;
} }
/* Do the splitting of insns in the block B. Only try to actually split if /* Split all insns in the function. If UPD_LIFE, update life info after. */
DO_SPLIT is true; otherwise, just remove nops. */
void void
split_block_insns (b, do_split) split_all_insns (upd_life)
int b; int upd_life;
int do_split;
{ {
sbitmap blocks;
int changed;
int i;
blocks = sbitmap_alloc (n_basic_blocks);
sbitmap_zero (blocks);
changed = 0;
for (i = n_basic_blocks - 1; i >= 0; --i)
{
basic_block bb = BASIC_BLOCK (i);
rtx insn, next; rtx insn, next;
for (insn = BLOCK_HEAD (b);; insn = next) for (insn = bb->head; insn ; insn = next)
{ {
rtx set; rtx set;
/* Can't use `next_real_insn' because that /* Can't use `next_real_insn' because that might go across
might go across CODE_LABELS and short-out basic blocks. */ CODE_LABELS and short-out basic blocks. */
next = NEXT_INSN (insn); next = NEXT_INSN (insn);
if (GET_CODE (insn) != INSN) if (GET_CODE (insn) != INSN)
{ ;
if (insn == BLOCK_END (b))
break;
continue; /* Don't split no-op move insns. These should silently
} disappear later in final. Splitting such insns would
break the code that handles REG_NO_CONFLICT blocks. */
/* Don't split no-op move insns. These should silently disappear else if ((set = single_set (insn)) != NULL
later in final. Splitting such insns would break the code && rtx_equal_p (SET_SRC (set), SET_DEST (set)))
that handles REG_NO_CONFLICT blocks. */
set = single_set (insn);
if (set && rtx_equal_p (SET_SRC (set), SET_DEST (set)))
{ {
if (insn == BLOCK_END (b)) /* Nops get in the way while scheduling, so delete them
break; now if register allocation has already been done. It
is too risky to try to do this before register
/* Nops get in the way while scheduling, so delete them now if allocation, and there are unlikely to be very many
register allocation has already been done. It is too risky nops then anyways. */
to try to do this before register allocation, and there are
unlikely to be very many nops then anyways. */
if (reload_completed) if (reload_completed)
{ {
PUT_CODE (insn, NOTE); PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0; NOTE_SOURCE_FILE (insn) = 0;
} }
continue;
} }
else
if (do_split)
{ {
/* Split insns here to get max fine-grain parallelism. */ /* Split insns here to get max fine-grain parallelism. */
rtx first = PREV_INSN (insn); rtx first = PREV_INSN (insn);
rtx notes = REG_NOTES (insn);
rtx last = try_split (PATTERN (insn), insn, 1); rtx last = try_split (PATTERN (insn), insn, 1);
if (last != insn) if (last != insn)
{ {
SET_BIT (blocks, i);
changed = 1;
/* try_split returns the NOTE that INSN became. */ /* try_split returns the NOTE that INSN became. */
first = NEXT_INSN (first); first = NEXT_INSN (first);
#ifdef INSN_SCHEDULING
update_life_info (notes, first, last, insn, insn);
#endif
PUT_CODE (insn, NOTE); PUT_CODE (insn, NOTE);
NOTE_SOURCE_FILE (insn) = 0; NOTE_SOURCE_FILE (insn) = 0;
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
if (insn == BLOCK_HEAD (b))
BLOCK_HEAD (b) = first; if (insn == bb->end)
if (insn == BLOCK_END (b))
{ {
BLOCK_END (b) = last; bb->end = last;
break; break;
} }
} }
} }
if (insn == BLOCK_END (b)) if (insn == bb->end)
break; break;
} }
/* ??? When we're called from just after reload, the CFG is in bad
shape, and we may have fallen off the end. This could be fixed
by having reload not try to delete unreachable code. Otherwise
assert we found the end insn. */
if (insn == NULL && upd_life)
abort ();
}
if (changed && upd_life)
{
count_or_remove_death_notes (blocks, 1);
update_life_info (blocks, UPDATE_LIFE_LOCAL);
}
sbitmap_free (blocks);
} }
#ifdef HAVE_peephole2 #ifdef HAVE_peephole2
/* This is the last insn we'll allow recog_next_insn to consider. */
static rtx recog_last_allowed_insn;
/* Return the Nth non-note insn after INSN, or return NULL_RTX if it does /* Return the Nth non-note insn after INSN, or return NULL_RTX if it does
not exist. Used by the recognizer to find the next insn to match in a not exist. Used by the recognizer to find the next insn to match in a
multi-insn pattern. */ multi-insn pattern. */
...@@ -2652,17 +2668,20 @@ recog_next_insn (insn, n) ...@@ -2652,17 +2668,20 @@ recog_next_insn (insn, n)
rtx insn; rtx insn;
int n; int n;
{ {
while (insn != NULL_RTX && n > 0) if (insn != NULL_RTX)
{ {
insn = next_nonnote_insn (insn); while (n > 0)
{
if (insn == recog_last_allowed_insn)
return NULL_RTX;
insn = NEXT_INSN (insn);
if (insn == NULL_RTX) if (insn == NULL_RTX)
return insn; break;
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
return NULL_RTX;
n--; if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
n -= 1;
}
} }
return insn; return insn;
...@@ -2673,38 +2692,64 @@ void ...@@ -2673,38 +2692,64 @@ void
peephole2_optimize (dump_file) peephole2_optimize (dump_file)
FILE *dump_file ATTRIBUTE_UNUSED; FILE *dump_file ATTRIBUTE_UNUSED;
{ {
rtx insn; rtx insn, prev;
rtx epilogue_insn = 0; int i, changed;
sbitmap blocks;
for (insn = get_last_insn (); insn != NULL_RTX; insn = PREV_INSN (insn)) /* ??? TODO: Arrange with resource.c to start at bb->global_live_at_end
{ and backtrack insn by insn as we proceed through the block. In this
if (GET_CODE (insn) == NOTE way we'll not need to keep searching forward from the beginning of
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG) basic blocks to find register life info. */
init_resource_info (NULL);
blocks = sbitmap_alloc (n_basic_blocks);
sbitmap_zero (blocks);
changed = 0;
for (i = n_basic_blocks - 1; i >= 0; --i)
{ {
epilogue_insn = insn; basic_block bb = BASIC_BLOCK (i);
break;
}
}
init_resource_info (epilogue_insn); /* Since we don't update life info until the very end, we can't
allow matching instructions that we've replaced before. Walk
backward through the basic block so that we don't have to
care about subsequent life info; recog_last_allowed_insn to
restrict how far forward we will allow the match to proceed. */
for (insn = get_insns (); insn != NULL; recog_last_allowed_insn = bb->end;
insn = next_nonnote_insn (insn)) for (insn = bb->end; ; insn = prev)
{ {
if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN) prev = PREV_INSN (insn);
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{ {
rtx last_insn; rtx try, last_insn;
rtx before = PREV_INSN (insn);
rtx try = peephole2_insns (PATTERN (insn), insn, &last_insn); try = peephole2_insns (PATTERN (insn), insn, &last_insn);
if (try != NULL) if (try != NULL)
{ {
replace_insns (insn, last_insn, try, NULL_RTX); flow_delete_insn_chain (insn, last_insn);
insn = NEXT_INSN (before); try = emit_insn_after (try, prev);
if (last_insn == bb->end)
bb->end = try;
if (insn == bb->head)
bb->head = NEXT_INSN (prev);
recog_last_allowed_insn = prev;
SET_BIT (blocks, i);
changed = 1;
}
} }
if (insn == bb->head)
break;
} }
} }
free_resource_info (); free_resource_info ();
count_or_remove_death_notes (blocks, 1);
update_life_info (blocks, UPDATE_LIFE_LOCAL);
} }
#endif #endif
...@@ -1168,8 +1168,7 @@ extern enum reg_class reg_alternate_class PROTO((int)); ...@@ -1168,8 +1168,7 @@ extern enum reg_class reg_alternate_class PROTO((int));
extern rtx get_first_nonparm_insn PROTO((void)); extern rtx get_first_nonparm_insn PROTO((void));
extern void split_block_insns PROTO((int, int)); extern void split_all_insns PROTO((int));
extern void update_flow_info PROTO((rtx, rtx, rtx, rtx));
#define MAX_SAVED_CONST_INT 64 #define MAX_SAVED_CONST_INT 64
extern rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1]; extern rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
...@@ -1542,7 +1541,6 @@ extern void print_rtl_with_bb PROTO ((FILE *, rtx)); ...@@ -1542,7 +1541,6 @@ extern void print_rtl_with_bb PROTO ((FILE *, rtx));
extern void dump_flow_info PROTO ((FILE *)); extern void dump_flow_info PROTO ((FILE *));
#endif #endif
extern void free_bb_mem PROTO ((void)); extern void free_bb_mem PROTO ((void));
extern void replace_insns PROTO ((rtx, rtx, rtx, rtx));
/* In expmed.c */ /* In expmed.c */
extern void init_expmed PROTO ((void)); extern void init_expmed PROTO ((void));
......
...@@ -4149,6 +4149,13 @@ rest_of_compilation (decl) ...@@ -4149,6 +4149,13 @@ rest_of_compilation (decl)
if (rebuild_label_notes_after_reload) if (rebuild_label_notes_after_reload)
TIMEVAR (jump_time, rebuild_jump_labels (insns)); TIMEVAR (jump_time, rebuild_jump_labels (insns));
/* On some machines, the prologue and epilogue code, or parts thereof,
can be represented as RTL. Doing so lets us schedule insns between
it and the rest of the code and also allows delayed branch
scheduling to operate in the epilogue. */
thread_prologue_and_epilogue_insns (insns);
/* If optimizing and we are performing instruction scheduling after /* If optimizing and we are performing instruction scheduling after
reload, then go ahead and split insns now since we are about to reload, then go ahead and split insns now since we are about to
recompute flow information anyway. recompute flow information anyway.
...@@ -4156,26 +4163,7 @@ rest_of_compilation (decl) ...@@ -4156,26 +4163,7 @@ rest_of_compilation (decl)
reload_cse_regs may expose more splitting opportunities, expecially reload_cse_regs may expose more splitting opportunities, expecially
for double-word operations. */ for double-word operations. */
if (optimize > 0 && flag_schedule_insns_after_reload) if (optimize > 0 && flag_schedule_insns_after_reload)
{ split_all_insns (0);
rtx insn;
for (insn = insns; insn; insn = NEXT_INSN (insn))
{
rtx last;
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
continue;
last = try_split (PATTERN (insn), insn, 1);
if (last != insn)
{
PUT_CODE (insn, NOTE);
NOTE_SOURCE_FILE (insn) = 0;
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
}
}
}
if (global_reg_dump) if (global_reg_dump)
{ {
...@@ -4204,13 +4192,6 @@ rest_of_compilation (decl) ...@@ -4204,13 +4192,6 @@ rest_of_compilation (decl)
flow2_completed = 1; flow2_completed = 1;
/* On some machines, the prologue and epilogue code, or parts thereof,
can be represented as RTL. Doing so lets us schedule insns between
it and the rest of the code and also allows delayed branch
scheduling to operate in the epilogue. */
thread_prologue_and_epilogue_insns (insns);
if (flow2_dump) if (flow2_dump)
{ {
close_dump_file (print_rtl_with_bb, insns); close_dump_file (print_rtl_with_bb, insns);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment