mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-24 20:42:10 +08:00
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
This commit is contained in:
parent
1640ef3802
commit
d3a923ee2e
@ -1,3 +1,75 @@
|
||||
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>
|
||||
|
||||
* 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 \
|
||||
function.h toplev.h varray.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
|
||||
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 \
|
||||
insn-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. */
|
||||
/* Copy a register set to another register set. */
|
||||
#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. */
|
||||
#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. */
|
||||
/* Inclusive or a register set with a second register set. */
|
||||
#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. */
|
||||
#define IOR_AND_COMPL_REG_SET(TO, FROM1, FROM2) \
|
||||
bitmap_ior_and_compl (TO, FROM1, FROM2)
|
||||
@ -153,6 +159,10 @@ typedef struct basic_block_def {
|
||||
|
||||
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. */
|
||||
|
||||
extern varray_type basic_block_info;
|
||||
@ -229,9 +239,6 @@ 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])
|
||||
|
||||
/* 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)
|
||||
@ -249,6 +256,7 @@ extern void insert_insn_on_edge PROTO ((rtx, edge));
|
||||
extern void commit_edge_insertions PROTO ((void));
|
||||
extern void remove_fake_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. */
|
||||
struct edge_list
|
||||
@ -291,6 +299,15 @@ extern void compute_dominators PROTO ((sbitmap *, sbitmap *,
|
||||
extern void compute_flow_dominators PROTO ((sbitmap *, 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 */
|
||||
extern void pre_lcm PROTO ((int, int, int_list_ptr *,
|
||||
int_list_ptr *,
|
||||
|
112
gcc/combine.c
112
gcc/combine.c
@ -11721,11 +11721,17 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
|
||||
|
||||
if (place == 0)
|
||||
{
|
||||
for (tem = prev_nonnote_insn (i3);
|
||||
place == 0 && tem
|
||||
&& (GET_CODE (tem) == INSN || GET_CODE (tem) == CALL_INSN);
|
||||
tem = prev_nonnote_insn (tem))
|
||||
basic_block bb = BASIC_BLOCK (this_basic_block);
|
||||
|
||||
for (tem = PREV_INSN (i3); place == 0; tem = PREV_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
|
||||
TEM is doing. If so, delete TEM. Otherwise, make this
|
||||
into a REG_UNUSED note instead. */
|
||||
@ -11740,8 +11746,8 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
|
||||
if (set != 0)
|
||||
for (inner_dest = SET_DEST (set);
|
||||
GET_CODE (inner_dest) == STRICT_LOW_PART
|
||||
|| GET_CODE (inner_dest) == SUBREG
|
||||
|| GET_CODE (inner_dest) == ZERO_EXTRACT;
|
||||
|| GET_CODE (inner_dest) == SUBREG
|
||||
|| GET_CODE (inner_dest) == ZERO_EXTRACT;
|
||||
inner_dest = XEXP (inner_dest, 0))
|
||||
;
|
||||
|
||||
@ -11789,7 +11795,8 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
|
||||
distribute_links (LOG_LINKS (cc0_setter));
|
||||
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
@ -11818,48 +11825,64 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
|
||||
REGNO (XEXP (note, 0))))
|
||||
place = tem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (reg_referenced_p (XEXP (note, 0), PATTERN (tem))
|
||||
|| (GET_CODE (tem) == CALL_INSN
|
||||
&& find_reg_fusage (tem, USE, XEXP (note, 0))))
|
||||
{
|
||||
place = tem;
|
||||
}
|
||||
}
|
||||
else if (reg_referenced_p (XEXP (note, 0), PATTERN (tem))
|
||||
|| (GET_CODE (tem) == CALL_INSN
|
||||
&& find_reg_fusage (tem, USE, XEXP (note, 0))))
|
||||
{
|
||||
place = tem;
|
||||
|
||||
/* If we are doing a 3->2 combination, and we have a
|
||||
register which formerly died in i3 and was not used
|
||||
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
|
||||
and i3, then we may need to move a link from place to
|
||||
i2. */
|
||||
if (i2 && INSN_UID (place) <= max_uid_cuid
|
||||
&& INSN_CUID (place) > INSN_CUID (i2)
|
||||
&& from_insn && INSN_CUID (from_insn) > INSN_CUID (i2)
|
||||
&& reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
|
||||
{
|
||||
rtx links = LOG_LINKS (place);
|
||||
LOG_LINKS (place) = 0;
|
||||
distribute_links (links);
|
||||
}
|
||||
/* If we are doing a 3->2 combination, and we have a
|
||||
register which formerly died in i3 and was not used
|
||||
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
|
||||
and i3, then we may need to move a link from place to
|
||||
i2. */
|
||||
if (i2 && INSN_UID (place) <= max_uid_cuid
|
||||
&& INSN_CUID (place) > INSN_CUID (i2)
|
||||
&& from_insn && INSN_CUID (from_insn) > INSN_CUID (i2)
|
||||
&& reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
|
||||
{
|
||||
rtx links = LOG_LINKS (place);
|
||||
LOG_LINKS (place) = 0;
|
||||
distribute_links (links);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (tem == bb->head)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If 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,
|
||||
insert a USE insn for the register at that label and
|
||||
put the death node there. This prevents problems with
|
||||
call-state tracking in caller-save.c. */
|
||||
if (REG_NOTE_KIND (note) == REG_DEAD && place == 0 && tem != 0)
|
||||
{
|
||||
place
|
||||
= emit_insn_after (gen_rtx_USE (VOIDmode, XEXP (note, 0)),
|
||||
tem);
|
||||
/* We haven't found an insn for the death note and it
|
||||
is still a REG_DEAD note, but we have hit the beginning
|
||||
of the block. If the existing life info says the reg
|
||||
was dead, there's nothing left to do.
|
||||
|
||||
/* If this insn was emitted between blocks, then update
|
||||
BLOCK_HEAD of the current block to include it. */
|
||||
if (BLOCK_END (this_basic_block - 1) == tem)
|
||||
BLOCK_HEAD (this_basic_block) = place;
|
||||
??? 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)
|
||||
{
|
||||
int regno = REGNO (XEXP (note, 0));
|
||||
|
||||
if (REGNO_REG_SET_P (bb->global_live_at_start, regno))
|
||||
{
|
||||
rtx die = gen_rtx_USE (VOIDmode, XEXP (note, 0));
|
||||
|
||||
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)
|
||||
which is what `dead_or_set_p' checks, so also check for it being
|
||||
set partially. */
|
||||
|
||||
|
||||
if (place && REG_NOTE_KIND (note) == REG_DEAD)
|
||||
{
|
||||
int regno = REGNO (XEXP (note, 0));
|
||||
|
@ -8146,11 +8146,14 @@
|
||||
(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.
|
||||
(define_peephole2
|
||||
[(set (match_operand:SI 0 "register_operand" "")
|
||||
(const_int -1))]
|
||||
"(optimize_size || TARGET_PENTIUM)
|
||||
"0 && (optimize_size || TARGET_PENTIUM)
|
||||
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
|
||||
[(parallel [(set (match_dup 0)
|
||||
(ior:SI (match_dup 0) (const_int -1)))
|
||||
@ -8160,7 +8163,7 @@
|
||||
(define_peephole2
|
||||
[(set (match_operand:HI 0 "register_operand" "")
|
||||
(const_int -1))]
|
||||
"(optimize_size || TARGET_PENTIUM)
|
||||
"0 && (optimize_size || TARGET_PENTIUM)
|
||||
&& reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
|
||||
[(parallel [(set (match_dup 0)
|
||||
(ior:HI (match_dup 0) (const_int -1)))
|
||||
|
2266
gcc/flow.c
2266
gcc/flow.c
File diff suppressed because it is too large
Load Diff
@ -7773,9 +7773,7 @@ schedule_insns (dump_file)
|
||||
/* Initialize issue_rate. */
|
||||
issue_rate = ISSUE_RATE;
|
||||
|
||||
/* Do the splitting first for all blocks. */
|
||||
for (b = 0; b < n_basic_blocks; b++)
|
||||
split_block_insns (b, 1);
|
||||
split_all_insns (1);
|
||||
|
||||
max_uid = (get_max_uid () + 1);
|
||||
|
||||
|
@ -135,7 +135,6 @@ extern void find_basic_blocks PROTO((rtx, int, FILE *, int));
|
||||
extern void free_basic_block_vars PROTO((int));
|
||||
extern void set_block_num PROTO((rtx, int));
|
||||
extern void life_analysis PROTO((rtx, int, FILE *, int));
|
||||
extern void update_life_info PROTO((rtx, rtx, rtx, rtx, rtx));
|
||||
#endif
|
||||
|
||||
/* Functions in varasm.c. */
|
||||
|
233
gcc/recog.c
233
gcc/recog.c
@ -2562,88 +2562,104 @@ reg_fits_class_p (operand, class, offset, mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do the splitting of insns in the block B. Only try to actually split if
|
||||
DO_SPLIT is true; otherwise, just remove nops. */
|
||||
/* Split all insns in the function. If UPD_LIFE, update life info after. */
|
||||
|
||||
void
|
||||
split_block_insns (b, do_split)
|
||||
int b;
|
||||
int do_split;
|
||||
split_all_insns (upd_life)
|
||||
int upd_life;
|
||||
{
|
||||
rtx insn, next;
|
||||
sbitmap blocks;
|
||||
int changed;
|
||||
int i;
|
||||
|
||||
for (insn = BLOCK_HEAD (b);; insn = next)
|
||||
blocks = sbitmap_alloc (n_basic_blocks);
|
||||
sbitmap_zero (blocks);
|
||||
changed = 0;
|
||||
|
||||
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
|
||||
might go across CODE_LABELS and short-out basic blocks. */
|
||||
next = NEXT_INSN (insn);
|
||||
if (GET_CODE (insn) != INSN)
|
||||
for (insn = bb->head; insn ; insn = next)
|
||||
{
|
||||
if (insn == BLOCK_END (b))
|
||||
break;
|
||||
rtx set;
|
||||
|
||||
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
|
||||
later in final. Splitting such insns would 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;
|
||||
/* 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. */
|
||||
|
||||
/* Nops get in the way while scheduling, so delete them now if
|
||||
register allocation has already been done. It is too risky
|
||||
to try to do this before register allocation, and there are
|
||||
unlikely to be very many nops then anyways. */
|
||||
if (reload_completed)
|
||||
else if ((set = single_set (insn)) != NULL
|
||||
&& rtx_equal_p (SET_SRC (set), SET_DEST (set)))
|
||||
{
|
||||
|
||||
PUT_CODE (insn, NOTE);
|
||||
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
|
||||
NOTE_SOURCE_FILE (insn) = 0;
|
||||
}
|
||||
|
||||
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. */
|
||||
first = NEXT_INSN (first);
|
||||
#ifdef INSN_SCHEDULING
|
||||
update_life_info (notes, first, last, insn, insn);
|
||||
#endif
|
||||
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))
|
||||
/* Nops get in the way while scheduling, so delete them
|
||||
now if register allocation has already been done. It
|
||||
is too risky to try to do this before register
|
||||
allocation, and there are unlikely to be very many
|
||||
nops then anyways. */
|
||||
if (reload_completed)
|
||||
{
|
||||
BLOCK_END (b) = last;
|
||||
break;
|
||||
PUT_CODE (insn, NOTE);
|
||||
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
|
||||
NOTE_SOURCE_FILE (insn) = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Split insns here to get max fine-grain parallelism. */
|
||||
rtx first = PREV_INSN (insn);
|
||||
rtx last = try_split (PATTERN (insn), insn, 1);
|
||||
|
||||
if (last != insn)
|
||||
{
|
||||
SET_BIT (blocks, i);
|
||||
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))
|
||||
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
|
||||
/* 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
|
||||
not exist. Used by the recognizer to find the next insn to match in a
|
||||
multi-insn pattern. */
|
||||
@ -2652,17 +2668,20 @@ recog_next_insn (insn, n)
|
||||
rtx insn;
|
||||
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;
|
||||
|
||||
if (insn == NULL_RTX)
|
||||
return insn;
|
||||
insn = NEXT_INSN (insn);
|
||||
if (insn == NULL_RTX)
|
||||
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;
|
||||
@ -2673,38 +2692,64 @@ void
|
||||
peephole2_optimize (dump_file)
|
||||
FILE *dump_file ATTRIBUTE_UNUSED;
|
||||
{
|
||||
rtx insn;
|
||||
rtx epilogue_insn = 0;
|
||||
rtx insn, prev;
|
||||
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
|
||||
way we'll not need to keep searching forward from the beginning of
|
||||
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)
|
||||
{
|
||||
if (GET_CODE (insn) == NOTE
|
||||
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
|
||||
basic_block bb = BASIC_BLOCK (i);
|
||||
|
||||
/* 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. */
|
||||
|
||||
recog_last_allowed_insn = bb->end;
|
||||
for (insn = bb->end; ; insn = prev)
|
||||
{
|
||||
epilogue_insn = insn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
init_resource_info (epilogue_insn);
|
||||
|
||||
for (insn = get_insns (); insn != NULL;
|
||||
insn = next_nonnote_insn (insn))
|
||||
{
|
||||
if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
|
||||
{
|
||||
rtx last_insn;
|
||||
rtx before = PREV_INSN (insn);
|
||||
|
||||
rtx try = peephole2_insns (PATTERN (insn), insn, &last_insn);
|
||||
if (try != NULL)
|
||||
prev = PREV_INSN (insn);
|
||||
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
|
||||
{
|
||||
replace_insns (insn, last_insn, try, NULL_RTX);
|
||||
insn = NEXT_INSN (before);
|
||||
rtx try, last_insn;
|
||||
|
||||
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 ();
|
||||
|
||||
count_or_remove_death_notes (blocks, 1);
|
||||
update_life_info (blocks, UPDATE_LIFE_LOCAL);
|
||||
}
|
||||
#endif
|
||||
|
@ -1168,8 +1168,7 @@ extern enum reg_class reg_alternate_class PROTO((int));
|
||||
|
||||
extern rtx get_first_nonparm_insn PROTO((void));
|
||||
|
||||
extern void split_block_insns PROTO((int, int));
|
||||
extern void update_flow_info PROTO((rtx, rtx, rtx, rtx));
|
||||
extern void split_all_insns PROTO((int));
|
||||
|
||||
#define MAX_SAVED_CONST_INT 64
|
||||
extern rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
|
||||
@ -1542,7 +1541,6 @@ extern void print_rtl_with_bb PROTO ((FILE *, rtx));
|
||||
extern void dump_flow_info PROTO ((FILE *));
|
||||
#endif
|
||||
extern void free_bb_mem PROTO ((void));
|
||||
extern void replace_insns PROTO ((rtx, rtx, rtx, rtx));
|
||||
|
||||
/* In expmed.c */
|
||||
extern void init_expmed PROTO ((void));
|
||||
|
35
gcc/toplev.c
35
gcc/toplev.c
@ -4149,6 +4149,13 @@ rest_of_compilation (decl)
|
||||
if (rebuild_label_notes_after_reload)
|
||||
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
|
||||
reload, then go ahead and split insns now since we are about to
|
||||
recompute flow information anyway.
|
||||
@ -4156,26 +4163,7 @@ rest_of_compilation (decl)
|
||||
reload_cse_regs may expose more splitting opportunities, expecially
|
||||
for double-word operations. */
|
||||
if (optimize > 0 && flag_schedule_insns_after_reload)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
split_all_insns (0);
|
||||
|
||||
if (global_reg_dump)
|
||||
{
|
||||
@ -4204,13 +4192,6 @@ rest_of_compilation (decl)
|
||||
|
||||
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)
|
||||
{
|
||||
close_dump_file (print_rtl_with_bb, insns);
|
||||
|
Loading…
x
Reference in New Issue
Block a user