cfglayout.c (function_tail_eff_head): Rename to ...
* cfglayout.c (function_tail_eff_head): Rename to ... (function_footer): ... this one. (unlink_insn_chain): New functions. (label_for_bb): Only call block_label and emit debug message. (record_effective_endpoints): Actually unlink the headers and footers. (fixup_reorder_cahin): Re-insert the unlinked sequences. (cfg_layout_duplicate_bb): Use duplicate_insn_chain. * cfglayout.h (struct reorder_block_def): New fields footer/header; remove eff_head/eff_end. * rtl.h (set_first_insn): Declare. * emit-rtl.c (set_first_insn): New function. * cfglayout.c (fixup_reorder_chain): Dump duplicated (cfg_layout_can_duplicate_bb_p, cfg_layout_rerirect_edge, cfg_layout_duplicate_bb): New global function. (duplicate_insn_chain): New static function. * cfglayout.h (cfg_layout_can_duplicate_bb_p, cfg_layout_rerirect_edge, cfg_layout_duplicate_bb): Declare. (struct reorder_block_def): Add "original" field. * emit-rtl.c (emit_copy_of_insn_after): New function. * rtl.h (emit_copy_of_insn_after): Declare. * cfglayout.c (fixup_fallthru_exit_predecessor): Kill. (fixup_reorder_chain): properly handle edges to exit block. Wed May 8 11:10:31 CEST 2002 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz> Jan Hubicka <jh@suse.cz> * basic-block.h (note_prediction_to_br_prob): declare. * c-semantics.c: Inlucde predit.h (expand_stmt): predict GOTO_STMT as not taken. * cfgcleanup.c: (delete_unreachable_blocks): Make global. (cleanup_cfg): Do not free tail_recursion_list. * cfgrtl.c (can_delete_note_p): Delete NOTE_INSN_PREDICTION. (flow_delete_block): Kill predictions past end of basic block. * output.h (delete_unreachable_blocks): Declare. * predict.c (predicted_by_p, process_note_predictions, process_note_prediction, last_block_p): New function. (estimate_probability): Bypass loop on PRED_CONTINUE; do not handle noreturn heuristics; kill PRED_RETURN; add PRED_EARLY_RETURN. * predict.def (PRED_CONTINUE, PRED_EARLY_RETURN, PRED_GOTO, PRED_CONST_RETURN, PRED_NEGATIVE_RETURN, PRED_NULL_RETURN): New. * predict.h (IS_TAKEN): New constant. * print-rtl.c (print_rtx): Pretty print NOTE_INSN_PREDICTION. * rtl.c (NOTE_INSN_PREDICTION): New. * rtl.h (NOTE_PREDICTION, NOTE_PREDICTION_ALG, NOTE_PREDICTION_FLAGS): New macro. (insn_note): add NOTE_INSN_PREDICTION. * sibcall.c (optimize_sibling_and_tail_recursive_call): Do not build CFG; free tail_recursion_label_list. * stmt.c: Include predict.h; (return_prediction): New. (expand_value_return): Use it. * toplev.c: Lower NOTE_INSN_PREDICTION before sibcall. From-SVN: r53285
This commit is contained in:
parent
41f8d041be
commit
969d70ca57
@ -1,3 +1,61 @@
|
||||
Wed May 8 11:08:50 CEST 2002 Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* cfglayout.c (function_tail_eff_head): Rename to ...
|
||||
(function_footer): ... this one.
|
||||
(unlink_insn_chain): New functions.
|
||||
(label_for_bb): Only call block_label and emit debug message.
|
||||
(record_effective_endpoints): Actually unlink the headers and footers.
|
||||
(fixup_reorder_cahin): Re-insert the unlinked sequences.
|
||||
(cfg_layout_duplicate_bb): Use duplicate_insn_chain.
|
||||
* cfglayout.h (struct reorder_block_def): New fields footer/header;
|
||||
remove eff_head/eff_end.
|
||||
* rtl.h (set_first_insn): Declare.
|
||||
* emit-rtl.c (set_first_insn): New function.
|
||||
|
||||
* cfglayout.c (fixup_reorder_chain): Dump duplicated
|
||||
(cfg_layout_can_duplicate_bb_p, cfg_layout_rerirect_edge,
|
||||
cfg_layout_duplicate_bb): New global function.
|
||||
(duplicate_insn_chain): New static function.
|
||||
* cfglayout.h (cfg_layout_can_duplicate_bb_p, cfg_layout_rerirect_edge,
|
||||
cfg_layout_duplicate_bb): Declare.
|
||||
(struct reorder_block_def): Add "original" field.
|
||||
* emit-rtl.c (emit_copy_of_insn_after): New function.
|
||||
* rtl.h (emit_copy_of_insn_after): Declare.
|
||||
|
||||
* cfglayout.c (fixup_fallthru_exit_predecessor): Kill.
|
||||
(fixup_reorder_chain): properly handle edges to exit block.
|
||||
|
||||
Wed May 8 11:10:31 CEST 2002 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
|
||||
Jan Hubicka <jh@suse.cz>
|
||||
|
||||
* basic-block.h (note_prediction_to_br_prob): declare.
|
||||
* c-semantics.c: Inlucde predit.h
|
||||
(expand_stmt): predict GOTO_STMT as not taken.
|
||||
* cfgcleanup.c: (delete_unreachable_blocks): Make global.
|
||||
(cleanup_cfg): Do not free tail_recursion_list.
|
||||
* cfgrtl.c (can_delete_note_p): Delete NOTE_INSN_PREDICTION.
|
||||
(flow_delete_block): Kill predictions past end of basic block.
|
||||
* output.h (delete_unreachable_blocks): Declare.
|
||||
* predict.c (predicted_by_p, process_note_predictions,
|
||||
process_note_prediction, last_block_p): New function.
|
||||
(estimate_probability): Bypass loop on PRED_CONTINUE;
|
||||
do not handle noreturn heuristics; kill PRED_RETURN; add
|
||||
PRED_EARLY_RETURN.
|
||||
* predict.def (PRED_CONTINUE, PRED_EARLY_RETURN, PRED_GOTO,
|
||||
PRED_CONST_RETURN, PRED_NEGATIVE_RETURN, PRED_NULL_RETURN): New.
|
||||
* predict.h (IS_TAKEN): New constant.
|
||||
* print-rtl.c (print_rtx): Pretty print NOTE_INSN_PREDICTION.
|
||||
* rtl.c (NOTE_INSN_PREDICTION): New.
|
||||
* rtl.h (NOTE_PREDICTION, NOTE_PREDICTION_ALG, NOTE_PREDICTION_FLAGS):
|
||||
New macro.
|
||||
(insn_note): add NOTE_INSN_PREDICTION.
|
||||
* sibcall.c (optimize_sibling_and_tail_recursive_call): Do not build
|
||||
CFG; free tail_recursion_label_list.
|
||||
* stmt.c: Include predict.h;
|
||||
(return_prediction): New.
|
||||
(expand_value_return): Use it.
|
||||
* toplev.c: Lower NOTE_INSN_PREDICTION before sibcall.
|
||||
|
||||
2002-05-08 Richard Sandiford <rsandifo@redhat.com>
|
||||
|
||||
* config/mips/mips.md: Name the unspecs with define_constant.
|
||||
|
@ -1227,7 +1227,7 @@ c-format.o : c-format.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) langhooks.h \
|
||||
|
||||
c-semantics.o : c-semantics.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(C_TREE_H) \
|
||||
c-lex.h flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \
|
||||
$(EXPR_H)
|
||||
$(EXPR_H) predict.h
|
||||
|
||||
# Language-independent files.
|
||||
|
||||
@ -1389,7 +1389,7 @@ function.o : function.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
|
||||
stmt.o : stmt.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h function.h \
|
||||
insn-config.h hard-reg-set.h $(EXPR_H) libfuncs.h except.h \
|
||||
$(LOOP_H) $(RECOG_H) toplev.h output.h varray.h $(GGC_H) $(TM_P_H) \
|
||||
langhooks.h
|
||||
langhooks.h predict.h
|
||||
except.o : except.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
|
||||
except.h function.h $(EXPR_H) libfuncs.h integrate.h langhooks.h \
|
||||
insn-config.h hard-reg-set.h $(BASIC_BLOCK_H) output.h \
|
||||
|
@ -625,6 +625,7 @@ extern rtx emit_block_insn_before PARAMS ((rtx, rtx, basic_block));
|
||||
|
||||
/* In predict.c */
|
||||
extern void estimate_probability PARAMS ((struct loops *));
|
||||
extern void note_prediction_to_br_prob PARAMS ((void));
|
||||
extern void expected_value_to_br_prob PARAMS ((void));
|
||||
|
||||
/* In flow.c */
|
||||
|
@ -36,6 +36,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "expr.h"
|
||||
#include "output.h"
|
||||
#include "timevar.h"
|
||||
#include "predict.h"
|
||||
|
||||
/* If non-NULL, the address of a language-specific function for
|
||||
expanding statements. */
|
||||
@ -834,6 +835,14 @@ expand_stmt (t)
|
||||
break;
|
||||
|
||||
case GOTO_STMT:
|
||||
/* Emit information for branch prediction. */
|
||||
if (!GOTO_FAKE_P (t)
|
||||
&& TREE_CODE (GOTO_DESTINATION (t)) == LABEL_DECL)
|
||||
{
|
||||
rtx note = emit_note (NULL, NOTE_INSN_PREDICTION);
|
||||
|
||||
NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_GOTO, NOT_TAKEN);
|
||||
}
|
||||
genrtl_goto_stmt (GOTO_DESTINATION (t));
|
||||
break;
|
||||
|
||||
|
@ -74,7 +74,7 @@ static int flow_find_cross_jump PARAMS ((int, basic_block, basic_block,
|
||||
rtx *, rtx *));
|
||||
static bool insns_match_p PARAMS ((int, rtx, rtx));
|
||||
|
||||
static bool delete_unreachable_blocks PARAMS ((void));
|
||||
bool delete_unreachable_blocks PARAMS ((void));
|
||||
static bool label_is_jump_target_p PARAMS ((rtx, rtx));
|
||||
static bool tail_recursion_label_p PARAMS ((rtx));
|
||||
static void merge_blocks_move_predecessor_nojumps PARAMS ((basic_block,
|
||||
@ -1748,7 +1748,7 @@ try_optimize_cfg (mode)
|
||||
|
||||
/* Delete all unreachable basic blocks. */
|
||||
|
||||
static bool
|
||||
bool
|
||||
delete_unreachable_blocks ()
|
||||
{
|
||||
int i, j;
|
||||
@ -1829,7 +1829,6 @@ cleanup_cfg (mode)
|
||||
|
||||
/* Kill the data we won't maintain. */
|
||||
free_EXPR_LIST_list (&label_value_list);
|
||||
free_EXPR_LIST_list (&tail_recursion_label_list);
|
||||
timevar_pop (TV_CLEANUP_CFG);
|
||||
|
||||
return changed;
|
||||
|
380
gcc/cfglayout.c
380
gcc/cfglayout.c
@ -35,7 +35,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
extern struct obstack flow_obstack;
|
||||
|
||||
/* Holds the interesting trailing notes for the function. */
|
||||
static rtx function_tail_eff_head;
|
||||
static rtx function_footer;
|
||||
|
||||
static rtx skip_insns_after_block PARAMS ((basic_block));
|
||||
static void record_effective_endpoints PARAMS ((void));
|
||||
@ -47,10 +47,33 @@ static void change_scope PARAMS ((rtx, tree, tree));
|
||||
|
||||
void verify_insn_chain PARAMS ((void));
|
||||
static void fixup_fallthru_exit_predecessor PARAMS ((void));
|
||||
static rtx unlink_insn_chain PARAMS ((rtx, rtx));
|
||||
static rtx duplicate_insn_chain PARAMS ((rtx, rtx));
|
||||
|
||||
/* Map insn uid to lexical block. */
|
||||
static varray_type insn_scopes;
|
||||
|
||||
static rtx
|
||||
unlink_insn_chain (first, last)
|
||||
rtx first;
|
||||
rtx last;
|
||||
{
|
||||
rtx prevfirst = PREV_INSN (first);
|
||||
rtx nextlast = NEXT_INSN (last);
|
||||
|
||||
PREV_INSN (first) = NULL;
|
||||
NEXT_INSN (last) = NULL;
|
||||
if (prevfirst)
|
||||
NEXT_INSN (prevfirst) = nextlast;
|
||||
if (nextlast)
|
||||
PREV_INSN (nextlast) = prevfirst;
|
||||
else
|
||||
set_last_insn (prevfirst);
|
||||
if (!prevfirst)
|
||||
set_first_insn (nextlast);
|
||||
return first;
|
||||
}
|
||||
|
||||
/* Skip over inter-block insns occurring after BB which are typically
|
||||
associated with BB (e.g., barriers). If there are any such insns,
|
||||
we return the last one. Otherwise, we return the end of BB. */
|
||||
@ -155,8 +178,6 @@ label_for_bb (bb)
|
||||
fprintf (rtl_dump_file, "Emitting label for block %d\n", bb->index);
|
||||
|
||||
label = block_label (bb);
|
||||
if (bb->head == PREV_INSN (RBI (bb)->eff_head))
|
||||
RBI (bb)->eff_head = label;
|
||||
}
|
||||
|
||||
return label;
|
||||
@ -176,13 +197,18 @@ record_effective_endpoints ()
|
||||
basic_block bb = BASIC_BLOCK (i);
|
||||
rtx end;
|
||||
|
||||
RBI (bb)->eff_head = next_insn;
|
||||
if (PREV_INSN (bb->head) && next_insn != bb->head)
|
||||
RBI (bb)->header = unlink_insn_chain (next_insn,
|
||||
PREV_INSN (bb->head));
|
||||
end = skip_insns_after_block (bb);
|
||||
RBI (bb)->eff_end = end;
|
||||
next_insn = NEXT_INSN (end);
|
||||
if (NEXT_INSN (bb->end) && bb->end != end)
|
||||
RBI (bb)->footer = unlink_insn_chain (NEXT_INSN (bb->end), end);
|
||||
next_insn = NEXT_INSN (bb->end);
|
||||
}
|
||||
|
||||
function_tail_eff_head = next_insn;
|
||||
function_footer = next_insn;
|
||||
if (function_footer)
|
||||
function_footer = unlink_insn_chain (function_footer, get_last_insn ());
|
||||
}
|
||||
|
||||
/* Build a varray mapping INSN_UID to lexical block. Return it. */
|
||||
@ -237,7 +263,7 @@ set_block_levels (block, level)
|
||||
block = BLOCK_CHAIN (block);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Emit lexical block notes needed to change scope from S1 to S2. */
|
||||
|
||||
static void
|
||||
@ -330,32 +356,49 @@ scope_to_insns_finalize ()
|
||||
static void
|
||||
fixup_reorder_chain ()
|
||||
{
|
||||
basic_block bb, last_bb;
|
||||
basic_block bb;
|
||||
int index;
|
||||
rtx insn;
|
||||
int old_n_basic_blocks = n_basic_blocks;
|
||||
rtx insn = NULL;
|
||||
|
||||
/* First do the bulk reordering -- rechain the blocks without regard to
|
||||
the needed changes to jumps and labels. */
|
||||
|
||||
for (last_bb = BASIC_BLOCK (0), bb = RBI (last_bb)->next, index = 1;
|
||||
for (bb = BASIC_BLOCK (0), index = 0;
|
||||
bb != 0;
|
||||
last_bb = bb, bb = RBI (bb)->next, index++)
|
||||
bb = RBI (bb)->next, index++)
|
||||
{
|
||||
rtx last_e = RBI (last_bb)->eff_end;
|
||||
rtx curr_h = RBI (bb)->eff_head;
|
||||
|
||||
NEXT_INSN (last_e) = curr_h;
|
||||
PREV_INSN (curr_h) = last_e;
|
||||
if (RBI (bb)->header)
|
||||
{
|
||||
if (insn)
|
||||
NEXT_INSN (insn) = RBI (bb)->header;
|
||||
else
|
||||
set_first_insn (RBI (bb)->header);
|
||||
PREV_INSN (RBI (bb)->header) = insn;
|
||||
insn = RBI (bb)->header;
|
||||
while (NEXT_INSN (insn))
|
||||
insn = NEXT_INSN (insn);
|
||||
}
|
||||
if (insn)
|
||||
NEXT_INSN (insn) = bb->head;
|
||||
else
|
||||
set_first_insn (bb->head);
|
||||
PREV_INSN (bb->head) = insn;
|
||||
insn = bb->end;
|
||||
if (RBI (bb)->footer)
|
||||
{
|
||||
NEXT_INSN (insn) = RBI (bb)->footer;
|
||||
PREV_INSN (RBI (bb)->footer) = insn;
|
||||
while (NEXT_INSN (insn))
|
||||
insn = NEXT_INSN (insn);
|
||||
}
|
||||
}
|
||||
|
||||
if (index != n_basic_blocks)
|
||||
abort ();
|
||||
|
||||
insn = RBI (last_bb)->eff_end;
|
||||
NEXT_INSN (insn) = function_tail_eff_head;
|
||||
if (function_tail_eff_head)
|
||||
PREV_INSN (function_tail_eff_head) = insn;
|
||||
NEXT_INSN (insn) = function_footer;
|
||||
if (function_footer)
|
||||
PREV_INSN (function_footer) = insn;
|
||||
|
||||
while (NEXT_INSN (insn))
|
||||
insn = NEXT_INSN (insn);
|
||||
@ -470,8 +513,6 @@ fixup_reorder_chain ()
|
||||
if (nb)
|
||||
{
|
||||
alloc_aux_for_block (nb, sizeof (struct reorder_block_def));
|
||||
RBI (nb)->eff_head = nb->head;
|
||||
RBI (nb)->eff_end = NEXT_INSN (nb->end);
|
||||
RBI (nb)->visited = 1;
|
||||
RBI (nb)->next = RBI (bb)->next;
|
||||
RBI (bb)->next = nb;
|
||||
@ -481,20 +522,26 @@ fixup_reorder_chain ()
|
||||
}
|
||||
|
||||
/* Put basic_block_info in the new order. */
|
||||
bb = BASIC_BLOCK (0);
|
||||
index = 0;
|
||||
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, "Reordered sequence:\n");
|
||||
|
||||
for (; bb; bb = RBI (bb)->next, index++)
|
||||
{
|
||||
if (rtl_dump_file)
|
||||
fprintf (rtl_dump_file, " %i %sbb %i freq %i\n", index,
|
||||
bb->index >= old_n_basic_blocks ? "compensation " : "",
|
||||
bb->index,
|
||||
bb->frequency);
|
||||
fprintf (rtl_dump_file, "Reordered sequence:\n");
|
||||
for (bb = BASIC_BLOCK (0), index = 0; bb; bb = RBI (bb)->next, index ++)
|
||||
{
|
||||
fprintf (rtl_dump_file, " %i ", index);
|
||||
if (RBI (bb)->original)
|
||||
fprintf (rtl_dump_file, "duplicate of %i ",
|
||||
RBI (bb)->original->index);
|
||||
else if (forwarder_block_p (bb) && GET_CODE (bb->head) != CODE_LABEL)
|
||||
fprintf (rtl_dump_file, "compensation ");
|
||||
else
|
||||
fprintf (rtl_dump_file, "bb %i ", bb->index);
|
||||
fprintf (rtl_dump_file, " [%i]\n", bb->frequency);
|
||||
}
|
||||
}
|
||||
|
||||
for (bb = BASIC_BLOCK (0), index = 0; bb; bb = RBI (bb)->next, index ++)
|
||||
{
|
||||
bb->index = index;
|
||||
BASIC_BLOCK (index) = bb;
|
||||
}
|
||||
@ -530,10 +577,9 @@ verify_insn_chain ()
|
||||
if (insn_cnt1 != insn_cnt2)
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* The block falling through to exit must be the last one in the reordered
|
||||
chain. Ensure it is. */
|
||||
|
||||
|
||||
/* The block falling through to exit must be the last one in the
|
||||
reordered chain. Ensure that this condition is met. */
|
||||
static void
|
||||
fixup_fallthru_exit_predecessor ()
|
||||
{
|
||||
@ -560,12 +606,266 @@ fixup_fallthru_exit_predecessor ()
|
||||
}
|
||||
}
|
||||
|
||||
/* Main entry point to this module: initialize the datastructures for CFG
|
||||
layout changes. */
|
||||
/* Return true in case it is possible to duplicate the basic block BB. */
|
||||
|
||||
bool
|
||||
cfg_layout_can_duplicate_bb_p (bb)
|
||||
basic_block bb;
|
||||
{
|
||||
rtx next;
|
||||
edge s;
|
||||
|
||||
if (bb == EXIT_BLOCK_PTR || bb == ENTRY_BLOCK_PTR)
|
||||
return false;
|
||||
|
||||
/* Duplicating fallthru block to exit would require adding an jump
|
||||
and splitting the real last BB. */
|
||||
for (s = bb->succ; s; s = s->succ_next)
|
||||
if (s->dest == EXIT_BLOCK_PTR && s->flags & EDGE_FALLTHRU)
|
||||
return false;
|
||||
|
||||
/* Do not attempt to duplicate tablejumps, as we need to unshare
|
||||
the dispatch table. This is dificult to do, as the instructions
|
||||
computing jump destination may be hoisted outside the basic block. */
|
||||
if (GET_CODE (bb->end) == JUMP_INSN && JUMP_LABEL (bb->end)
|
||||
&& (next = next_nonnote_insn (JUMP_LABEL (bb->end)))
|
||||
&& GET_CODE (next) == JUMP_INSN
|
||||
&& (GET_CODE (PATTERN (next)) == ADDR_VEC
|
||||
|| GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static rtx
|
||||
duplicate_insn_chain (from, to)
|
||||
rtx from, to;
|
||||
{
|
||||
rtx insn, last;
|
||||
|
||||
/* Avoid updating of boundaries of previous basic block. The
|
||||
note will get removed from insn stream in fixup. */
|
||||
last = emit_note (NULL, NOTE_INSN_DELETED);
|
||||
|
||||
/* Create copy at the end of INSN chain. The chain will
|
||||
be reordered later. */
|
||||
for (insn = from; insn != NEXT_INSN (to); insn = NEXT_INSN (insn))
|
||||
{
|
||||
rtx new;
|
||||
switch (GET_CODE (insn))
|
||||
{
|
||||
case INSN:
|
||||
case CALL_INSN:
|
||||
case JUMP_INSN:
|
||||
/* Avoid copying of dispatch tables. We never duplicate
|
||||
tablejumps, so this can hit only in case the table got
|
||||
moved far from original jump. */
|
||||
if (GET_CODE (PATTERN (insn)) == ADDR_VEC
|
||||
|| GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
|
||||
break;
|
||||
new = emit_copy_of_insn_after (insn, get_last_insn ());
|
||||
/* Record the INSN_SCOPE. */
|
||||
VARRAY_GROW (insn_scopes, INSN_UID (new) + 1);
|
||||
VARRAY_TREE (insn_scopes, INSN_UID (new))
|
||||
= VARRAY_TREE (insn_scopes, INSN_UID (insn));
|
||||
break;
|
||||
|
||||
case CODE_LABEL:
|
||||
break;
|
||||
|
||||
case BARRIER:
|
||||
emit_barrier ();
|
||||
break;
|
||||
|
||||
case NOTE:
|
||||
switch (NOTE_LINE_NUMBER (insn))
|
||||
{
|
||||
/* In case prologue is empty and function contain label
|
||||
in first BB, we may want to copy the block. */
|
||||
case NOTE_INSN_PROLOGUE_END:
|
||||
|
||||
case NOTE_INSN_LOOP_VTOP:
|
||||
case NOTE_INSN_LOOP_CONT:
|
||||
case NOTE_INSN_LOOP_BEG:
|
||||
case NOTE_INSN_LOOP_END:
|
||||
/* Strip down the loop notes - we don't really want to keep
|
||||
them consistent in loop copies. */
|
||||
case NOTE_INSN_DELETED:
|
||||
case NOTE_INSN_DELETED_LABEL:
|
||||
/* No problem to strip these. */
|
||||
case NOTE_INSN_EPILOGUE_BEG:
|
||||
case NOTE_INSN_FUNCTION_END:
|
||||
/* Debug code expect these notes to exist just once.
|
||||
Keep them in the master copy.
|
||||
??? It probably makes more sense to duplicate them for each
|
||||
epilogue copy. */
|
||||
case NOTE_INSN_FUNCTION_BEG:
|
||||
/* There is always just single entry to function. */
|
||||
case NOTE_INSN_BASIC_BLOCK:
|
||||
break;
|
||||
|
||||
/* There is no purpose to duplicate prologue. */
|
||||
case NOTE_INSN_BLOCK_BEG:
|
||||
case NOTE_INSN_BLOCK_END:
|
||||
/* The BLOCK_BEG/BLOCK_END notes should be eliminated when BB
|
||||
reordering is in the progress. */
|
||||
case NOTE_INSN_EH_REGION_BEG:
|
||||
case NOTE_INSN_EH_REGION_END:
|
||||
case NOTE_INSN_RANGE_BEG:
|
||||
case NOTE_INSN_RANGE_END:
|
||||
/* Should never exist at BB duplication time. */
|
||||
abort ();
|
||||
break;
|
||||
case NOTE_INSN_REPEATED_LINE_NUMBER:
|
||||
emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
|
||||
break;
|
||||
|
||||
default:
|
||||
if (NOTE_LINE_NUMBER (insn) < 0)
|
||||
abort ();
|
||||
/* It is possible that no_line_number is set and the note
|
||||
won't be emitted. */
|
||||
emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
}
|
||||
insn = NEXT_INSN (last);
|
||||
delete_insn (last);
|
||||
return insn;
|
||||
}
|
||||
|
||||
/* Redirect Edge to DEST. */
|
||||
void
|
||||
cfg_layout_redirect_edge (e, dest)
|
||||
edge e;
|
||||
basic_block dest;
|
||||
{
|
||||
int old_index = dest->index;
|
||||
basic_block src = e->src;
|
||||
|
||||
/* Redirect_edge_and_branch may decide to turn branch into fallthru edge
|
||||
in the case the basic block appears to be in sequence. Avoid this
|
||||
transformation. */
|
||||
|
||||
dest->index = n_basic_blocks + 1;
|
||||
if (e->flags & EDGE_FALLTHRU)
|
||||
{
|
||||
/* In case we are redirecting fallthru edge to the branch edge
|
||||
of conditional jump, remove it. */
|
||||
if (src->succ->succ_next
|
||||
&& !src->succ->succ_next->succ_next)
|
||||
{
|
||||
edge s = e->succ_next ? e->succ_next : src->succ;
|
||||
if (s->dest == dest
|
||||
&& any_condjump_p (src->end)
|
||||
&& onlyjump_p (src->end))
|
||||
delete_insn (src->end);
|
||||
}
|
||||
redirect_edge_succ_nodup (e, dest);
|
||||
}
|
||||
else
|
||||
redirect_edge_and_branch (e, dest);
|
||||
dest->index = old_index;
|
||||
}
|
||||
|
||||
/* Create an duplicate of the basic block BB and redirect edge E into it. */
|
||||
|
||||
basic_block
|
||||
cfg_layout_duplicate_bb (bb, e)
|
||||
basic_block bb;
|
||||
edge e;
|
||||
{
|
||||
rtx insn;
|
||||
edge s, n;
|
||||
basic_block new_bb;
|
||||
gcov_type new_count = e ? e->count : 0;
|
||||
|
||||
if (bb->count < new_count)
|
||||
new_count = bb->count;
|
||||
if (!bb->pred)
|
||||
abort ();
|
||||
#ifdef ENABLE_CHECKING
|
||||
if (!cfg_layout_can_duplicate_bb_p (bb))
|
||||
abort ();
|
||||
#endif
|
||||
|
||||
insn = duplicate_insn_chain (bb->head, bb->end);
|
||||
new_bb = create_basic_block (n_basic_blocks, insn,
|
||||
insn ? get_last_insn () : NULL);
|
||||
alloc_aux_for_block (new_bb, sizeof (struct reorder_block_def));
|
||||
|
||||
if (RBI (bb)->header)
|
||||
{
|
||||
insn = RBI (bb)->header;
|
||||
while (NEXT_INSN (insn))
|
||||
insn = NEXT_INSN (insn);
|
||||
insn = duplicate_insn_chain (RBI (bb)->header, insn);
|
||||
if (insn)
|
||||
RBI (new_bb)->header = unlink_insn_chain (insn, get_last_insn ());
|
||||
}
|
||||
|
||||
if (RBI (bb)->footer)
|
||||
{
|
||||
insn = RBI (bb)->footer;
|
||||
while (NEXT_INSN (insn))
|
||||
insn = NEXT_INSN (insn);
|
||||
insn = duplicate_insn_chain (RBI (bb)->footer, insn);
|
||||
if (insn)
|
||||
RBI (new_bb)->footer = unlink_insn_chain (insn, get_last_insn ());
|
||||
}
|
||||
|
||||
if (bb->global_live_at_start)
|
||||
{
|
||||
new_bb->global_live_at_start = OBSTACK_ALLOC_REG_SET (&flow_obstack);
|
||||
new_bb->global_live_at_end = OBSTACK_ALLOC_REG_SET (&flow_obstack);
|
||||
COPY_REG_SET (new_bb->global_live_at_start, bb->global_live_at_start);
|
||||
COPY_REG_SET (new_bb->global_live_at_end, bb->global_live_at_end);
|
||||
}
|
||||
|
||||
new_bb->loop_depth = bb->loop_depth;
|
||||
new_bb->flags = bb->flags;
|
||||
for (s = bb->succ; s; s = s->succ_next)
|
||||
{
|
||||
n = make_edge (new_bb, s->dest, s->flags);
|
||||
n->probability = s->probability;
|
||||
if (new_count)
|
||||
/* Take care for overflows! */
|
||||
n->count = s->count * (new_count * 10000 / bb->count) / 10000;
|
||||
else
|
||||
n->count = 0;
|
||||
s->count -= n->count;
|
||||
}
|
||||
|
||||
new_bb->count = new_count;
|
||||
bb->count -= new_count;
|
||||
|
||||
if (e)
|
||||
{
|
||||
new_bb->frequency = EDGE_FREQUENCY (e);
|
||||
bb->frequency -= EDGE_FREQUENCY (e);
|
||||
|
||||
cfg_layout_redirect_edge (e, new_bb);
|
||||
}
|
||||
|
||||
if (bb->count < 0)
|
||||
bb->count = 0;
|
||||
if (bb->frequency < 0)
|
||||
bb->frequency = 0;
|
||||
|
||||
RBI (new_bb)->original = bb;
|
||||
return new_bb;
|
||||
}
|
||||
|
||||
/* Main entry point to this module - initialize the datastructures for
|
||||
CFG layout changes. It keeps LOOPS up-to-date if not null. */
|
||||
|
||||
void
|
||||
cfg_layout_initialize ()
|
||||
{
|
||||
/* Our algorithm depends on fact that there are now dead jumptables
|
||||
around the code. */
|
||||
alloc_aux_for_blocks (sizeof (struct reorder_block_def));
|
||||
|
||||
scope_to_insns_initialize ();
|
||||
|
@ -21,9 +21,12 @@
|
||||
/* Structure to hold information about the blocks during reordering. */
|
||||
typedef struct reorder_block_def
|
||||
{
|
||||
rtx eff_head;
|
||||
rtx eff_end;
|
||||
rtx header;
|
||||
rtx footer;
|
||||
basic_block next;
|
||||
basic_block original;
|
||||
|
||||
/* These fields are used by bb-reorder pass. */
|
||||
int visited;
|
||||
} *reorder_block_def;
|
||||
|
||||
@ -31,6 +34,8 @@ typedef struct reorder_block_def
|
||||
|
||||
extern void cfg_layout_initialize PARAMS ((void));
|
||||
extern void cfg_layout_finalize PARAMS ((void));
|
||||
|
||||
extern bool cfg_layout_can_duplicate_bb_p PARAMS ((basic_block));
|
||||
extern basic_block cfg_layout_duplicate_bb PARAMS ((basic_block, edge));
|
||||
extern void scope_to_insns_initialize PARAMS ((void));
|
||||
extern void scope_to_insns_finalize PARAMS ((void));
|
||||
extern void cfg_layout_redirect_edge PARAMS ((edge, basic_block));
|
||||
|
13
gcc/cfgrtl.c
13
gcc/cfgrtl.c
@ -89,7 +89,8 @@ can_delete_note_p (note)
|
||||
rtx note;
|
||||
{
|
||||
return (NOTE_LINE_NUMBER (note) == NOTE_INSN_DELETED
|
||||
|| NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK);
|
||||
|| NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK
|
||||
|| NOTE_LINE_NUMBER (note) == NOTE_INSN_PREDICTION);
|
||||
}
|
||||
|
||||
/* True if a given label can be deleted. */
|
||||
@ -375,6 +376,16 @@ flow_delete_block_noexpunge (b)
|
||||
and remove the associated NOTE_INSN_EH_REGION_BEG and
|
||||
NOTE_INSN_EH_REGION_END notes. */
|
||||
|
||||
/* Get rid of all NOTE_INSN_PREDICTIONs hanging before the block. */
|
||||
|
||||
for (insn = PREV_INSN (b->head); insn; insn = PREV_INSN (insn))
|
||||
{
|
||||
if (GET_CODE (insn) != NOTE)
|
||||
break;
|
||||
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PREDICTION)
|
||||
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
|
||||
}
|
||||
|
||||
insn = b->head;
|
||||
|
||||
never_reached_warning (insn, b->end);
|
||||
|
@ -3731,6 +3731,27 @@ emit_call_insn_before (pattern, before)
|
||||
return insn;
|
||||
}
|
||||
|
||||
/* Make an instruction with body PATTERN and code CALL_INSN
|
||||
and output it before the instruction BEFORE. */
|
||||
|
||||
rtx
|
||||
emit_call_insn_after (pattern, before)
|
||||
rtx pattern, before;
|
||||
{
|
||||
rtx insn;
|
||||
|
||||
if (GET_CODE (pattern) == SEQUENCE)
|
||||
insn = emit_insn_after (pattern, before);
|
||||
else
|
||||
{
|
||||
insn = make_call_insn_raw (pattern);
|
||||
add_insn_after (insn, before);
|
||||
PUT_CODE (insn, CALL_INSN);
|
||||
}
|
||||
|
||||
return insn;
|
||||
}
|
||||
|
||||
/* Make an insn of code BARRIER
|
||||
and output it before the insn BEFORE. */
|
||||
|
||||
@ -5052,3 +5073,68 @@ restore_line_number_status (old_value)
|
||||
{
|
||||
no_line_numbers = old_value;
|
||||
}
|
||||
|
||||
/* Produce exact duplicate of insn INSN after AFTER.
|
||||
Care updating of libcall regions if present. */
|
||||
|
||||
rtx
|
||||
emit_copy_of_insn_after (insn, after)
|
||||
rtx insn, after;
|
||||
{
|
||||
rtx new;
|
||||
rtx note1, note2, link;
|
||||
|
||||
switch (GET_CODE (insn))
|
||||
{
|
||||
case INSN:
|
||||
new = emit_insn_after (copy_insn (PATTERN (insn)), after);
|
||||
break;
|
||||
|
||||
case JUMP_INSN:
|
||||
new = emit_jump_insn_after (copy_insn (PATTERN (insn)), after);
|
||||
break;
|
||||
|
||||
case CALL_INSN:
|
||||
new = emit_call_insn_after (copy_insn (PATTERN (insn)), after);
|
||||
if (CALL_INSN_FUNCTION_USAGE (insn))
|
||||
CALL_INSN_FUNCTION_USAGE (new)
|
||||
= copy_insn (CALL_INSN_FUNCTION_USAGE (insn));
|
||||
SIBLING_CALL_P (new) = SIBLING_CALL_P (insn);
|
||||
CONST_OR_PURE_CALL_P (new) = CONST_OR_PURE_CALL_P (insn);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* Update LABEL_NUSES. */
|
||||
mark_jump_label (PATTERN (new), new, 0);
|
||||
|
||||
/* Copy all REG_NOTES except REG_LABEL since mark_jump_label will
|
||||
make them. */
|
||||
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
|
||||
if (REG_NOTE_KIND (link) != REG_LABEL)
|
||||
{
|
||||
if (GET_CODE (link) == EXPR_LIST)
|
||||
REG_NOTES (new)
|
||||
= copy_insn_1 (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
|
||||
XEXP (link, 0),
|
||||
REG_NOTES (new)));
|
||||
else
|
||||
REG_NOTES (new)
|
||||
= copy_insn_1 (gen_rtx_INSN_LIST (REG_NOTE_KIND (link),
|
||||
XEXP (link, 0),
|
||||
REG_NOTES (new)));
|
||||
}
|
||||
|
||||
/* Fix the libcall sequences. */
|
||||
if ((note1 = find_reg_note (new, REG_RETVAL, NULL_RTX)) != NULL)
|
||||
{
|
||||
rtx p = new;
|
||||
while ((note2 = find_reg_note (p, REG_LIBCALL, NULL_RTX)) == NULL)
|
||||
p = PREV_INSN (p);
|
||||
XEXP (note1, 0) = p;
|
||||
XEXP (note2, 0) = new;
|
||||
}
|
||||
return new;
|
||||
}
|
||||
|
@ -145,6 +145,7 @@ extern int regno_uninitialized PARAMS ((unsigned int));
|
||||
extern int regno_clobbered_at_setjmp PARAMS ((int));
|
||||
extern void find_basic_blocks PARAMS ((rtx, int, FILE *));
|
||||
extern bool cleanup_cfg PARAMS ((int));
|
||||
extern bool delete_unreachable_blocks PARAMS ((void));
|
||||
extern void check_function_return_warnings PARAMS ((void));
|
||||
#endif
|
||||
|
||||
|
247
gcc/predict.c
247
gcc/predict.c
@ -61,6 +61,8 @@ static REAL_VALUE_TYPE real_zero, real_one, real_almost_one, real_br_prob_base,
|
||||
#define PROB_VERY_LIKELY (REG_BR_PROB_BASE - PROB_VERY_UNLIKELY)
|
||||
#define PROB_ALWAYS (REG_BR_PROB_BASE)
|
||||
|
||||
static bool predicted_by_p PARAMS ((basic_block,
|
||||
enum br_predictor));
|
||||
static void combine_predictions_for_insn PARAMS ((rtx, basic_block));
|
||||
static void dump_prediction PARAMS ((enum br_predictor, int,
|
||||
basic_block, int));
|
||||
@ -68,6 +70,11 @@ static void estimate_loops_at_level PARAMS ((struct loop *loop));
|
||||
static void propagate_freq PARAMS ((basic_block));
|
||||
static void estimate_bb_frequencies PARAMS ((struct loops *));
|
||||
static void counts_to_freqs PARAMS ((void));
|
||||
static void process_note_predictions PARAMS ((basic_block, int *, int *,
|
||||
sbitmap *));
|
||||
static void process_note_prediction PARAMS ((basic_block, int *, int *,
|
||||
sbitmap *, int, int));
|
||||
static bool last_basic_block_p PARAMS ((basic_block));
|
||||
|
||||
/* Information we hold about each branch predictor.
|
||||
Filled using information from predict.def. */
|
||||
@ -96,6 +103,23 @@ static const struct predictor_info predictor_info[]= {
|
||||
{NULL, 0, 0}
|
||||
};
|
||||
#undef DEF_PREDICTOR
|
||||
/* Return true if the one of outgoing edges is already predicted by
|
||||
PREDICTOR. */
|
||||
|
||||
static bool
|
||||
predicted_by_p (bb, predictor)
|
||||
basic_block bb;
|
||||
enum br_predictor predictor;
|
||||
{
|
||||
rtx note;
|
||||
if (!INSN_P (bb->end))
|
||||
return false;
|
||||
for (note = REG_NOTES (bb->end); note; note = XEXP (note, 1))
|
||||
if (REG_NOTE_KIND (note) == REG_BR_PRED
|
||||
&& INTVAL (XEXP (XEXP (note, 0), 0)) == (int)predictor)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
predict_insn (insn, predictor, probability)
|
||||
@ -333,7 +357,6 @@ estimate_probability (loops_info)
|
||||
{
|
||||
sbitmap *dominators, *post_dominators;
|
||||
int i;
|
||||
int found_noreturn = 0;
|
||||
|
||||
dominators = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
|
||||
post_dominators = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
|
||||
@ -357,6 +380,13 @@ estimate_probability (loops_info)
|
||||
int header_found = 0;
|
||||
edge e;
|
||||
|
||||
/* Bypass loop heuristics on continue statement. These
|
||||
statements construct loops via "non-loop" constructs
|
||||
in the source language and are better to be handled
|
||||
separately. */
|
||||
if (predicted_by_p (BASIC_BLOCK (j), PRED_CONTINUE))
|
||||
continue;
|
||||
|
||||
/* Loop branch heuristics - predict an edge back to a
|
||||
loop's head as taken. */
|
||||
for (e = BASIC_BLOCK(j)->succ; e; e = e->succ_next)
|
||||
@ -389,37 +419,22 @@ estimate_probability (loops_info)
|
||||
rtx cond, earliest;
|
||||
edge e;
|
||||
|
||||
/* If block has no successor, predict all possible paths to it as
|
||||
improbable, as the block contains a call to a noreturn function and
|
||||
thus can be executed only once. */
|
||||
if (bb->succ == NULL && !found_noreturn)
|
||||
{
|
||||
int y;
|
||||
|
||||
/* ??? Postdominator claims each noreturn block to be postdominated
|
||||
by each, so we need to run only once. This needs to be changed
|
||||
once postdominace algorithm is updated to say something more
|
||||
sane. */
|
||||
found_noreturn = 1;
|
||||
for (y = 0; y < n_basic_blocks; y++)
|
||||
if (!TEST_BIT (post_dominators[y], i))
|
||||
for (e = BASIC_BLOCK (y)->succ; e; e = e->succ_next)
|
||||
if (e->dest->index >= 0
|
||||
&& TEST_BIT (post_dominators[e->dest->index], i))
|
||||
predict_edge_def (e, PRED_NORETURN, NOT_TAKEN);
|
||||
}
|
||||
|
||||
if (GET_CODE (last_insn) != JUMP_INSN || ! any_condjump_p (last_insn))
|
||||
continue;
|
||||
|
||||
for (e = bb->succ; e; e = e->succ_next)
|
||||
{
|
||||
/* Predict edges to blocks that return immediately to be
|
||||
improbable. These are usually used to signal error states. */
|
||||
if (e->dest == EXIT_BLOCK_PTR
|
||||
|| (e->dest->succ && !e->dest->succ->succ_next
|
||||
&& e->dest->succ->dest == EXIT_BLOCK_PTR))
|
||||
predict_edge_def (e, PRED_ERROR_RETURN, NOT_TAKEN);
|
||||
/* Predict early returns to be probable, as we've already taken
|
||||
care for error returns and other are often used for fast paths
|
||||
trought function. */
|
||||
if ((e->dest == EXIT_BLOCK_PTR
|
||||
|| (e->dest->succ && !e->dest->succ->succ_next
|
||||
&& e->dest->succ->dest == EXIT_BLOCK_PTR))
|
||||
&& !predicted_by_p (bb, PRED_NULL_RETURN)
|
||||
&& !predicted_by_p (bb, PRED_CONST_RETURN)
|
||||
&& !predicted_by_p (bb, PRED_NEGATIVE_RETURN)
|
||||
&& !last_basic_block_p (e->dest))
|
||||
predict_edge_def (e, PRED_EARLY_RETURN, TAKEN);
|
||||
|
||||
/* Look for block we are guarding (ie we dominate it,
|
||||
but it doesn't postdominate us). */
|
||||
@ -538,7 +553,8 @@ estimate_probability (loops_info)
|
||||
/* Attach the combined probability to each conditional jump. */
|
||||
for (i = 0; i < n_basic_blocks; i++)
|
||||
if (GET_CODE (BLOCK_END (i)) == JUMP_INSN
|
||||
&& any_condjump_p (BLOCK_END (i)))
|
||||
&& any_condjump_p (BLOCK_END (i))
|
||||
&& BASIC_BLOCK (i)->succ->succ_next != NULL)
|
||||
combine_predictions_for_insn (BLOCK_END (i), BASIC_BLOCK (i));
|
||||
|
||||
sbitmap_vector_free (post_dominators);
|
||||
@ -620,6 +636,181 @@ expected_value_to_br_prob ()
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether this is the last basic block of function. Commonly tehre
|
||||
is one extra common cleanup block. */
|
||||
static bool
|
||||
last_basic_block_p (bb)
|
||||
basic_block bb;
|
||||
{
|
||||
return (bb->index == n_basic_blocks - 1
|
||||
|| (bb->index == n_basic_blocks - 2
|
||||
&& bb->succ && !bb->succ->succ_next
|
||||
&& bb->succ->dest->index == n_basic_blocks - 1));
|
||||
}
|
||||
|
||||
/* Sets branch probabilities according to PREDiction and FLAGS. HEADS[bb->index]
|
||||
should be index of basic block in that we need to alter branch predictions
|
||||
(i.e. the first of our dominators such that we do not post-dominate it)
|
||||
(but we fill this information on demand, so -1 may be there in case this
|
||||
was not needed yet). */
|
||||
|
||||
static void
|
||||
process_note_prediction (bb, heads, dominators, post_dominators, pred, flags)
|
||||
basic_block bb;
|
||||
int *heads;
|
||||
int *dominators;
|
||||
sbitmap *post_dominators;
|
||||
int pred;
|
||||
int flags;
|
||||
{
|
||||
edge e;
|
||||
int y;
|
||||
bool taken;
|
||||
|
||||
taken = flags & IS_TAKEN;
|
||||
|
||||
if (heads[bb->index] < 0)
|
||||
{
|
||||
/* This is first time we need this field in heads array; so
|
||||
find first dominator that we do not post-dominate (we are
|
||||
using already known members of heads array). */
|
||||
int ai = bb->index;
|
||||
int next_ai = dominators[bb->index];
|
||||
int head;
|
||||
|
||||
while (heads[next_ai] < 0)
|
||||
{
|
||||
if (!TEST_BIT (post_dominators[next_ai], bb->index))
|
||||
break;
|
||||
heads[next_ai] = ai;
|
||||
ai = next_ai;
|
||||
next_ai = dominators[next_ai];
|
||||
}
|
||||
if (!TEST_BIT (post_dominators[next_ai], bb->index))
|
||||
head = next_ai;
|
||||
else
|
||||
head = heads[next_ai];
|
||||
while (next_ai != bb->index)
|
||||
{
|
||||
next_ai = ai;
|
||||
ai = heads[ai];
|
||||
heads[next_ai] = head;
|
||||
}
|
||||
}
|
||||
y = heads[bb->index];
|
||||
|
||||
/* Now find the edge that leads to our branch and aply the prediction. */
|
||||
|
||||
if (y == n_basic_blocks)
|
||||
return;
|
||||
for (e = BASIC_BLOCK (y)->succ; e; e = e->succ_next)
|
||||
if (e->dest->index >= 0
|
||||
&& TEST_BIT (post_dominators[e->dest->index], bb->index))
|
||||
predict_edge_def (e, pred, taken);
|
||||
}
|
||||
|
||||
/* Gathers NOTE_INSN_PREDICTIONs in given basic block and turns them
|
||||
into branch probabilities. For description of heads array, see
|
||||
process_note_prediction. */
|
||||
|
||||
static void
|
||||
process_note_predictions (bb, heads, dominators, post_dominators)
|
||||
basic_block bb;
|
||||
int *heads;
|
||||
int *dominators;
|
||||
sbitmap *post_dominators;
|
||||
{
|
||||
rtx insn;
|
||||
edge e;
|
||||
|
||||
/* Additionaly, we check here for blocks with no successors. */
|
||||
int contained_noreturn_call = 0;
|
||||
int was_bb_head = 0;
|
||||
int noreturn_block = 1;
|
||||
|
||||
for (insn = bb->end; insn;
|
||||
was_bb_head |= (insn == bb->head), insn = PREV_INSN (insn))
|
||||
{
|
||||
if (GET_CODE (insn) != NOTE)
|
||||
{
|
||||
if (was_bb_head)
|
||||
break;
|
||||
else
|
||||
{
|
||||
/* Noreturn calls cause program to exit, therefore they are
|
||||
always predicted as not taken. */
|
||||
if (GET_CODE (insn) == CALL_INSN
|
||||
&& find_reg_note (insn, REG_NORETURN, NULL))
|
||||
contained_noreturn_call = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PREDICTION)
|
||||
{
|
||||
int alg = (int) NOTE_PREDICTION_ALG (insn);
|
||||
/* Process single prediction note. */
|
||||
process_note_prediction (bb,
|
||||
heads,
|
||||
dominators,
|
||||
post_dominators,
|
||||
alg, (int) NOTE_PREDICTION_FLAGS (insn));
|
||||
delete_insn (insn);
|
||||
}
|
||||
}
|
||||
for (e = bb->succ; e; e = e->succ_next)
|
||||
if (!(e->flags & EDGE_FAKE))
|
||||
noreturn_block = 0;
|
||||
if (contained_noreturn_call)
|
||||
{
|
||||
/* This block ended from other reasons than because of return.
|
||||
If it is because of noreturn call, this should certainly not
|
||||
be taken. Otherwise it is probably some error recovery. */
|
||||
process_note_prediction (bb,
|
||||
heads,
|
||||
dominators,
|
||||
post_dominators, PRED_NORETURN, NOT_TAKEN);
|
||||
}
|
||||
}
|
||||
|
||||
/* Gathers NOTE_INSN_PREDICTIONs and turns them into
|
||||
branch probabilities. */
|
||||
|
||||
void
|
||||
note_prediction_to_br_prob ()
|
||||
{
|
||||
int i;
|
||||
sbitmap *post_dominators;
|
||||
int *dominators, *heads;
|
||||
|
||||
/* To enable handling of noreturn blocks. */
|
||||
add_noreturn_fake_exit_edges ();
|
||||
connect_infinite_loops_to_exit ();
|
||||
|
||||
dominators = xmalloc (sizeof (int) * n_basic_blocks);
|
||||
memset (dominators, -1, sizeof (int) * n_basic_blocks);
|
||||
post_dominators = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
|
||||
calculate_dominance_info (NULL, post_dominators, CDI_POST_DOMINATORS);
|
||||
calculate_dominance_info (dominators, NULL, CDI_DOMINATORS);
|
||||
|
||||
heads = xmalloc (sizeof (int) * n_basic_blocks);
|
||||
memset (heads, -1, sizeof (int) * n_basic_blocks);
|
||||
heads[0] = n_basic_blocks;
|
||||
|
||||
/* Process all prediction notes. */
|
||||
|
||||
for (i = 0; i < n_basic_blocks; ++i)
|
||||
{
|
||||
basic_block bb = BASIC_BLOCK (i);
|
||||
process_note_predictions (bb, heads, dominators, post_dominators);
|
||||
}
|
||||
|
||||
sbitmap_vector_free (post_dominators);
|
||||
free (dominators);
|
||||
free (heads);
|
||||
|
||||
remove_fake_edges ();
|
||||
}
|
||||
|
||||
/* This is used to carry information about basic blocks. It is
|
||||
attached to the AUX field of the standard CFG block. */
|
||||
|
||||
|
@ -63,6 +63,9 @@ DEF_PREDICTOR (PRED_LOOP_ITERATIONS, "loop iterations", PROB_ALWAYS,
|
||||
DEF_PREDICTOR (PRED_BUILTIN_EXPECT, "__builtin_expect", PROB_VERY_LIKELY,
|
||||
PRED_FLAG_FIRST_MATCH)
|
||||
|
||||
/* Branch containing goto is probably not taken. */
|
||||
DEF_PREDICTOR (PRED_CONTINUE, "continue", HITRATE (56), 0)
|
||||
|
||||
/* Branch to basic block containing call marked by noreturn attribute. */
|
||||
DEF_PREDICTOR (PRED_NORETURN, "noreturn call", HITRATE (99),
|
||||
PRED_FLAG_FIRST_MATCH)
|
||||
@ -97,4 +100,16 @@ DEF_PREDICTOR (PRED_FPOPCODE, "fp_opcode", HITRATE (90), 0)
|
||||
DEF_PREDICTOR (PRED_CALL, "call", HITRATE (70), 0)
|
||||
|
||||
/* Branch causing function to terminate is probably not taken. */
|
||||
DEF_PREDICTOR (PRED_ERROR_RETURN, "error return", HITRATE (52), 0)
|
||||
DEF_PREDICTOR (PRED_EARLY_RETURN, "early return", HITRATE (67), 0)
|
||||
|
||||
/* Branch containing goto is probably not taken. */
|
||||
DEF_PREDICTOR (PRED_GOTO, "goto", HITRATE (70), 0)
|
||||
|
||||
/* Branch ending with return constant is probably not taken. */
|
||||
DEF_PREDICTOR (PRED_CONST_RETURN, "const return", HITRATE (95), 0)
|
||||
|
||||
/* Branch ending with return negative constant is probably not taken. */
|
||||
DEF_PREDICTOR (PRED_NEGATIVE_RETURN, "negative return", HITRATE (96), 0)
|
||||
|
||||
/* Branch ending with return; is probably not taken */
|
||||
DEF_PREDICTOR (PRED_NULL_RETURN, "null return", HITRATE (90), 0)
|
||||
|
@ -34,6 +34,9 @@ enum prediction
|
||||
TAKEN
|
||||
};
|
||||
|
||||
/* Flags for NOTE_PREDICTION */
|
||||
#define IS_TAKEN 1 /* Predict edges to the block as taken. */
|
||||
|
||||
extern void predict_insn_def PARAMS ((rtx, enum br_predictor,
|
||||
enum prediction));
|
||||
extern void predict_insn PARAMS ((rtx, enum br_predictor, int));
|
||||
|
@ -284,6 +284,15 @@ print_rtx (in_rtx)
|
||||
fprintf (outfile, " \"\"");
|
||||
break;
|
||||
|
||||
case NOTE_INSN_PREDICTION:
|
||||
if (NOTE_PREDICTION (in_rtx))
|
||||
fprintf (outfile, " [ %d %d ] ",
|
||||
(int)NOTE_PREDICTION_ALG (in_rtx),
|
||||
(int) NOTE_PREDICTION_FLAGS (in_rtx));
|
||||
else
|
||||
fprintf (outfile, " [ ERROR ]");
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
const char * const str = X0STR (in_rtx, i);
|
||||
|
@ -216,7 +216,8 @@ const char * const note_insn_name[NOTE_INSN_MAX - NOTE_INSN_BIAS] =
|
||||
"NOTE_INSN_EH_REGION_BEG", "NOTE_INSN_EH_REGION_END",
|
||||
"NOTE_INSN_REPEATED_LINE_NUMBER", "NOTE_INSN_RANGE_BEG",
|
||||
"NOTE_INSN_RANGE_END", "NOTE_INSN_LIVE",
|
||||
"NOTE_INSN_BASIC_BLOCK", "NOTE_INSN_EXPECTED_VALUE"
|
||||
"NOTE_INSN_BASIC_BLOCK", "NOTE_INSN_EXPECTED_VALUE",
|
||||
"NOTE_INSN_PREDICTION"
|
||||
};
|
||||
|
||||
const char * const reg_note_name[] =
|
||||
|
11
gcc/rtl.h
11
gcc/rtl.h
@ -740,6 +740,7 @@ extern const char * const reg_note_name[];
|
||||
#define NOTE_LIVE_INFO(INSN) XCEXP (INSN, 3, NOTE)
|
||||
#define NOTE_BASIC_BLOCK(INSN) XCBBDEF (INSN, 3, NOTE)
|
||||
#define NOTE_EXPECTED_VALUE(INSN) XCEXP (INSN, 3, NOTE)
|
||||
#define NOTE_PREDICTION(INSN) XCINT (INSN, 3, NOTE)
|
||||
|
||||
/* In a NOTE that is a line number, this is the line number.
|
||||
Other kinds of NOTEs are identified by negative numbers here. */
|
||||
@ -750,6 +751,11 @@ extern const char * const reg_note_name[];
|
||||
(GET_CODE (INSN) == NOTE \
|
||||
&& NOTE_LINE_NUMBER (INSN) == NOTE_INSN_BASIC_BLOCK)
|
||||
|
||||
/* Algorithm and flags for prediction. */
|
||||
#define NOTE_PREDICTION_ALG(INSN) (XCINT(INSN, 3, NOTE)>>8)
|
||||
#define NOTE_PREDICTION_FLAGS(INSN) (XCINT(INSN, 3, NOTE)&0xff)
|
||||
#define NOTE_PREDICT(ALG,FLAGS) ((ALG<<8)+(FLAGS))
|
||||
|
||||
/* Codes that appear in the NOTE_LINE_NUMBER field
|
||||
for kinds of notes that are not line numbers.
|
||||
|
||||
@ -838,6 +844,9 @@ enum insn_note
|
||||
NOTE_EXPECTED_VALUE; stored as (eq (reg) (const_int)). */
|
||||
NOTE_INSN_EXPECTED_VALUE,
|
||||
|
||||
/* Record a prediction. Uses NOTE_PREDICTION. */
|
||||
NOTE_INSN_PREDICTION,
|
||||
|
||||
NOTE_INSN_MAX
|
||||
};
|
||||
|
||||
@ -1349,6 +1358,7 @@ extern rtx copy_insn_1 PARAMS ((rtx));
|
||||
extern rtx copy_insn PARAMS ((rtx));
|
||||
extern rtx gen_int_mode PARAMS ((HOST_WIDE_INT,
|
||||
enum machine_mode));
|
||||
extern rtx emit_copy_of_insn_after PARAMS ((rtx, rtx));
|
||||
|
||||
/* In rtl.c */
|
||||
extern rtx rtx_alloc PARAMS ((RTX_CODE));
|
||||
@ -1437,6 +1447,7 @@ extern rtx emit_label_before PARAMS ((rtx, rtx));
|
||||
extern rtx emit_note_before PARAMS ((int, rtx));
|
||||
extern rtx emit_insn_after PARAMS ((rtx, rtx));
|
||||
extern rtx emit_jump_insn_after PARAMS ((rtx, rtx));
|
||||
extern rtx emit_call_insn_after PARAMS ((rtx, rtx));
|
||||
extern rtx emit_barrier_after PARAMS ((rtx));
|
||||
extern rtx emit_label_after PARAMS ((rtx, rtx));
|
||||
extern rtx emit_note_after PARAMS ((int, rtx));
|
||||
|
@ -580,16 +580,6 @@ optimize_sibling_and_tail_recursive_calls ()
|
||||
|
||||
insns = get_insns ();
|
||||
|
||||
/* We do not perform these calls when flag_exceptions is true, so this
|
||||
is probably a NOP at the current time. However, we may want to support
|
||||
sibling and tail recursion optimizations in the future, so let's plan
|
||||
ahead and find all the EH labels. */
|
||||
find_exception_handler_labels ();
|
||||
|
||||
rebuild_jump_labels (insns);
|
||||
/* We need cfg information to determine which blocks are succeeded
|
||||
only by the epilogue. */
|
||||
find_basic_blocks (insns, max_reg_num (), 0);
|
||||
cleanup_cfg (CLEANUP_PRE_SIBCALL | CLEANUP_PRE_LOOP);
|
||||
|
||||
/* If there are no basic blocks, then there is nothing to do. */
|
||||
@ -776,4 +766,5 @@ optimize_sibling_and_tail_recursive_calls ()
|
||||
|
||||
/* This information will be invalid after inline expansion. Kill it now. */
|
||||
free_basic_block_vars (0);
|
||||
free_EXPR_LIST_list (&tail_recursion_label_list);
|
||||
}
|
||||
|
59
gcc/stmt.c
59
gcc/stmt.c
@ -54,6 +54,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
#include "output.h"
|
||||
#include "ggc.h"
|
||||
#include "langhooks.h"
|
||||
#include "predict.h"
|
||||
|
||||
#define obstack_chunk_alloc xmalloc
|
||||
#define obstack_chunk_free free
|
||||
@ -414,6 +415,7 @@ static tree resolve_operand_names PARAMS ((tree, tree, tree,
|
||||
const char **));
|
||||
static char *resolve_operand_name_1 PARAMS ((char *, tree, tree));
|
||||
static void expand_null_return_1 PARAMS ((rtx));
|
||||
static enum br_predictor return_prediction PARAMS ((rtx));
|
||||
static void expand_value_return PARAMS ((rtx));
|
||||
static int tail_recursion_args PARAMS ((tree, tree));
|
||||
static void expand_cleanups PARAMS ((tree, tree, int, int));
|
||||
@ -2824,6 +2826,11 @@ int
|
||||
expand_continue_loop (whichloop)
|
||||
struct nesting *whichloop;
|
||||
{
|
||||
/* Emit information for branch prediction. */
|
||||
rtx note;
|
||||
|
||||
note = emit_note (NULL, NOTE_INSN_PREDICTION);
|
||||
NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_CONTINUE, IS_TAKEN);
|
||||
last_expr_type = 0;
|
||||
if (whichloop == 0)
|
||||
whichloop = loop_stack;
|
||||
@ -2965,7 +2972,9 @@ expand_exit_something ()
|
||||
void
|
||||
expand_null_return ()
|
||||
{
|
||||
rtx last_insn = get_last_insn ();
|
||||
rtx last_insn;
|
||||
|
||||
last_insn = get_last_insn ();
|
||||
|
||||
/* If this function was declared to return a value, but we
|
||||
didn't, clobber the return registers so that they are not
|
||||
@ -2975,14 +2984,58 @@ expand_null_return ()
|
||||
expand_null_return_1 (last_insn);
|
||||
}
|
||||
|
||||
/* Try to guess whether the value of return means error code. */
|
||||
static enum br_predictor
|
||||
return_prediction (val)
|
||||
rtx val;
|
||||
{
|
||||
/* Different heuristics for pointers and scalars. */
|
||||
if (POINTER_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl))))
|
||||
{
|
||||
/* NULL is usually not returned. */
|
||||
if (val == const0_rtx)
|
||||
return PRED_NULL_RETURN;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Negative return values are often used to indicate
|
||||
errors. */
|
||||
if (GET_CODE (val) == CONST_INT
|
||||
&& INTVAL (val) < 0)
|
||||
return PRED_NEGATIVE_RETURN;
|
||||
/* Constant return values are also usually erors,
|
||||
zero/one often mean booleans so exclude them from the
|
||||
heuristics. */
|
||||
if (CONSTANT_P (val)
|
||||
&& (val != const0_rtx && val != const1_rtx))
|
||||
return PRED_CONST_RETURN;
|
||||
}
|
||||
return PRED_NO_PREDICTION;
|
||||
}
|
||||
|
||||
/* Generate RTL to return from the current function, with value VAL. */
|
||||
|
||||
static void
|
||||
expand_value_return (val)
|
||||
rtx val;
|
||||
{
|
||||
rtx last_insn = get_last_insn ();
|
||||
rtx return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
|
||||
rtx last_insn;
|
||||
rtx return_reg;
|
||||
enum br_predictor pred;
|
||||
|
||||
if ((pred = return_prediction (val)) != PRED_NO_PREDICTION)
|
||||
{
|
||||
/* Emit information for branch prediction. */
|
||||
rtx note;
|
||||
|
||||
note = emit_note (NULL, NOTE_INSN_PREDICTION);
|
||||
|
||||
NOTE_PREDICTION (note) = NOTE_PREDICT (pred, NOT_TAKEN);
|
||||
|
||||
}
|
||||
|
||||
last_insn = get_last_insn ();
|
||||
return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
|
||||
|
||||
/* Copy the value to the return location
|
||||
unless it's already there. */
|
||||
|
30
gcc/toplev.c
30
gcc/toplev.c
@ -2492,18 +2492,38 @@ rest_of_compilation (decl)
|
||||
|| errorcount || sorrycount)
|
||||
goto exit_rest_of_compilation;
|
||||
|
||||
timevar_push (TV_JUMP);
|
||||
open_dump_file (DFI_sibling, decl);
|
||||
insns = get_insns ();
|
||||
rebuild_jump_labels (insns);
|
||||
find_exception_handler_labels ();
|
||||
find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
|
||||
|
||||
delete_unreachable_blocks ();
|
||||
|
||||
/* Turn NOTE_INSN_PREDICTIONs into branch predictions. */
|
||||
note_prediction_to_br_prob ();
|
||||
|
||||
/* We may have potential sibling or tail recursion sites. Select one
|
||||
(of possibly multiple) methods of performing the call. */
|
||||
if (flag_optimize_sibling_calls)
|
||||
{
|
||||
timevar_push (TV_JUMP);
|
||||
open_dump_file (DFI_sibling, decl);
|
||||
|
||||
rtx insn;
|
||||
optimize_sibling_and_tail_recursive_calls ();
|
||||
|
||||
close_dump_file (DFI_sibling, print_rtl, get_insns ());
|
||||
timevar_pop (TV_JUMP);
|
||||
/* There is pass ordering problem - we must lower NOTE_INSN_PREDICTION
|
||||
notes before simplifying cfg and we must do lowering after sibcall
|
||||
that unhides parts of RTL chain and cleans up the CFG.
|
||||
|
||||
Until sibcall is replaced by tree-level optimizer, lets just
|
||||
sweep away the NOTE_INSN_PREDICTION notes that leaked out. */
|
||||
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
|
||||
if (GET_CODE (insn) == NOTE
|
||||
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_PREDICTION)
|
||||
delete_insn (insn);
|
||||
}
|
||||
close_dump_file (DFI_sibling, print_rtl, get_insns ());
|
||||
timevar_pop (TV_JUMP);
|
||||
|
||||
/* Complete generation of exception handling code. */
|
||||
find_exception_handler_labels ();
|
||||
|
Loading…
Reference in New Issue
Block a user