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. */
...@@ -11740,8 +11746,8 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1) ...@@ -11740,8 +11746,8 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
if (set != 0) if (set != 0)
for (inner_dest = SET_DEST (set); for (inner_dest = SET_DEST (set);
GET_CODE (inner_dest) == STRICT_LOW_PART GET_CODE (inner_dest) == STRICT_LOW_PART
|| GET_CODE (inner_dest) == SUBREG || GET_CODE (inner_dest) == SUBREG
|| GET_CODE (inner_dest) == ZERO_EXTRACT; || GET_CODE (inner_dest) == ZERO_EXTRACT;
inner_dest = XEXP (inner_dest, 0)) inner_dest = XEXP (inner_dest, 0))
; ;
...@@ -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
...@@ -11818,48 +11825,64 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1) ...@@ -11818,48 +11825,64 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
REGNO (XEXP (note, 0)))) REGNO (XEXP (note, 0))))
place = tem; place = tem;
break; break;
} }
} }
else if (reg_referenced_p (XEXP (note, 0), PATTERN (tem)) else if (reg_referenced_p (XEXP (note, 0), PATTERN (tem))
|| (GET_CODE (tem) == CALL_INSN || (GET_CODE (tem) == CALL_INSN
&& find_reg_fusage (tem, USE, XEXP (note, 0)))) && find_reg_fusage (tem, USE, XEXP (note, 0))))
{ {
place = tem; place = tem;
/* If we are doing a 3->2 combination, and we have a /* If we are doing a 3->2 combination, and we have a
register which formerly died in i3 and was not used register which formerly died in i3 and was not used
by i2, which now no longer dies in i3 and is used in by i2, which now no longer dies in i3 and is used in
i2 but does not die in i2, and place is between i2 i2 but does not die in i2, and place is between i2
and i3, then we may need to move a link from place to and i3, then we may need to move a link from place to
i2. */ i2. */
if (i2 && INSN_UID (place) <= max_uid_cuid if (i2 && INSN_UID (place) <= max_uid_cuid
&& INSN_CUID (place) > INSN_CUID (i2) && INSN_CUID (place) > INSN_CUID (i2)
&& from_insn && INSN_CUID (from_insn) > INSN_CUID (i2) && from_insn && INSN_CUID (from_insn) > INSN_CUID (i2)
&& reg_referenced_p (XEXP (note, 0), PATTERN (i2))) && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
{ {
rtx links = LOG_LINKS (place); rtx links = LOG_LINKS (place);
LOG_LINKS (place) = 0; LOG_LINKS (place) = 0;
distribute_links (links); distribute_links (links);
} }
break;
}
if (tem == bb->head)
break; 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 (REGNO_REG_SET_P (bb->global_live_at_start, regno))
{
/* If this insn was emitted between blocks, then update rtx die = gen_rtx_USE (VOIDmode, XEXP (note, 0));
BLOCK_HEAD of the current block to include it. */
if (BLOCK_END (this_basic_block - 1) == tem) place = bb->head;
BLOCK_HEAD (this_basic_block) = place; 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;
{ {
rtx insn, next; sbitmap blocks;
int changed;
int i;
blocks = sbitmap_alloc (n_basic_blocks);
sbitmap_zero (blocks);
changed = 0;
for (insn = BLOCK_HEAD (b);; insn = next) for (i = n_basic_blocks - 1; i >= 0; --i)
{ {
rtx set; basic_block bb = BASIC_BLOCK (i);
rtx insn, next;
/* Can't use `next_real_insn' because that for (insn = bb->head; insn ; insn = next)
might go across CODE_LABELS and short-out basic blocks. */
next = NEXT_INSN (insn);
if (GET_CODE (insn) != INSN)
{ {
if (insn == BLOCK_END (b)) rtx set;
break;
continue; /* Can't use `next_real_insn' because that might go across
} CODE_LABELS and short-out basic blocks. */
next = NEXT_INSN (insn);
if (GET_CODE (insn) != INSN)
;
/* Don't split no-op move insns. These should silently disappear /* Don't split no-op move insns. These should silently
later in final. Splitting such insns would break the code disappear later in final. Splitting such insns would
that handles REG_NO_CONFLICT blocks. */ break the code 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))
break;
/* Nops get in the way while scheduling, so delete them now if else if ((set = single_set (insn)) != NULL
register allocation has already been done. It is too risky && rtx_equal_p (SET_SRC (set), SET_DEST (set)))
to try to do this before register allocation, and there are
unlikely to be very many nops then anyways. */
if (reload_completed)
{ {
/* Nops get in the way while scheduling, so delete them
PUT_CODE (insn, NOTE); now if register allocation has already been done. It
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; is too risky to try to do this before register
NOTE_SOURCE_FILE (insn) = 0; allocation, and there are unlikely to be very many
nops then anyways. */
if (reload_completed)
{
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
}
} }
else
continue;
}
if (do_split)
{
/* Split insns here to get max fine-grain parallelism. */
rtx first = PREV_INSN (insn);
rtx notes = REG_NOTES (insn);
rtx last = try_split (PATTERN (insn), insn, 1);
if (last != insn)
{ {
/* try_split returns the NOTE that INSN became. */ /* Split insns here to get max fine-grain parallelism. */
first = NEXT_INSN (first); rtx first = PREV_INSN (insn);
#ifdef INSN_SCHEDULING rtx last = try_split (PATTERN (insn), insn, 1);
update_life_info (notes, first, last, insn, insn);
#endif if (last != insn)
PUT_CODE (insn, NOTE);
NOTE_SOURCE_FILE (insn) = 0;
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
if (insn == BLOCK_HEAD (b))
BLOCK_HEAD (b) = first;
if (insn == BLOCK_END (b))
{ {
BLOCK_END (b) = last; SET_BIT (blocks, i);
break; changed = 1;
/* try_split returns the NOTE that INSN became. */
first = NEXT_INSN (first);
PUT_CODE (insn, NOTE);
NOTE_SOURCE_FILE (insn) = 0;
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
if (insn == bb->end)
{
bb->end = last;
break;
}
} }
} }
if (insn == bb->end)
break;
} }
if (insn == BLOCK_END (b)) /* ??? When we're called from just after reload, the CFG is in bad
break; 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 == NULL_RTX) if (insn == recog_last_allowed_insn)
return insn; return NULL_RTX;
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') insn = NEXT_INSN (insn);
return NULL_RTX; if (insn == NULL_RTX)
break;
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. */
{
epilogue_insn = insn;
break;
}
}
init_resource_info (epilogue_insn); init_resource_info (NULL);
for (insn = get_insns (); insn != NULL; blocks = sbitmap_alloc (n_basic_blocks);
insn = next_nonnote_insn (insn)) sbitmap_zero (blocks);
changed = 0;
for (i = n_basic_blocks - 1; i >= 0; --i)
{ {
if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN) basic_block bb = BASIC_BLOCK (i);
{
rtx last_insn; /* Since we don't update life info until the very end, we can't
rtx before = PREV_INSN (insn); 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. */
rtx try = peephole2_insns (PATTERN (insn), insn, &last_insn); recog_last_allowed_insn = bb->end;
if (try != NULL) for (insn = bb->end; ; insn = prev)
{
prev = PREV_INSN (insn);
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{ {
replace_insns (insn, last_insn, try, NULL_RTX); rtx try, last_insn;
insn = NEXT_INSN (before);
try = peephole2_insns (PATTERN (insn), insn, &last_insn);
if (try != NULL)
{
flow_delete_insn_chain (insn, last_insn);
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