summaryrefslogtreecommitdiff
path: root/gcc/recog.c
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>1999-10-09 19:47:18 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>1999-10-09 19:47:18 +0000
commit2d9b9dfea029c646d489d11eb327a0e72d31051c (patch)
tree979c66605d3637bf2f02aa8e816c05810e05aa54 /gcc/recog.c
parent053352b4aa2b1d19c92c926d174856bbb809ae7b (diff)
downloadgcc-2d9b9dfea029c646d489d11eb327a0e72d31051c.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@29877 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/recog.c')
-rw-r--r--gcc/recog.c225
1 files changed, 135 insertions, 90 deletions
diff --git a/gcc/recog.c b/gcc/recog.c
index 5a29920350d..1d277304e2a 100644
--- a/gcc/recog.c
+++ b/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;
+
+ 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
- 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;
+ /* 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)
+ {
+ 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)
+ else
{
- /* 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))
+ /* 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)
{
- BLOCK_END (b) = last;
- break;
+ 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);
-
- if (insn == NULL_RTX)
- return insn;
+ while (n > 0)
+ {
+ if (insn == recog_last_allowed_insn)
+ return NULL_RTX;
- if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
- return NULL_RTX;
+ insn = NEXT_INSN (insn);
+ if (insn == NULL_RTX)
+ break;
- 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))
- {
- if (GET_CODE (insn) == NOTE
- && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EPILOGUE_BEG)
- {
- epilogue_insn = insn;
- break;
- }
- }
+ /* ??? 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 (epilogue_insn);
+ init_resource_info (NULL);
- for (insn = get_insns (); insn != NULL;
- insn = next_nonnote_insn (insn))
+ blocks = sbitmap_alloc (n_basic_blocks);
+ sbitmap_zero (blocks);
+ changed = 0;
+
+ for (i = n_basic_blocks - 1; i >= 0; --i)
{
- if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
- {
- rtx last_insn;
- rtx before = PREV_INSN (insn);
+ 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. */
- rtx try = peephole2_insns (PATTERN (insn), insn, &last_insn);
- if (try != NULL)
+ recog_last_allowed_insn = bb->end;
+ 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);
- 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