This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[cfg-branch] highlevel branch prediction bits
- From: Jan Hubicka <jh at suse dot cz>
- To: gcc-pdo at atrey dot karlin dot mff dot cuni dot cz, gcc-patches at gcc dot gnu dot org
- Date: Fri, 23 Nov 2001 15:09:07 +0100
- Subject: [cfg-branch] highlevel branch prediction bits
Hi,
I am going to install the attached patch, done by Zdenek, to the cfg branch
tree. It's purpose is to allow propagation of branch predictions from frontend
to RTL via NOTE_INSN_PREDICTION note. These notes are taken by simple pass
that do predict all conditionals causing control flow to reach the note by
given prediction.
Currently the patch implements heuristics claiming that "goto" statement is
unlikely - this should help kernel code at least that use goto to get into cold
regions of code and that predicts NULL/negative return values to be unlikely -
I hope this to work better than current return heuristics we have.
I am open for future suggestions.
I am also considering __builtin_unlikely builtin function that will drop such
note. While this looks redundant with __buildin_expect, it should work
together. For instance one can get error diagnostics function to macro calling
the builtin even when he don't have control over conditional that preceedes
it (like is the gcc case).
I am just running i386 testing.
Thu Nov 15 11:29:10 CET 2001 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
* Makefile.in (stmt.o): Add predict.h dependency.
* basic-block.h (CLEANUP_UNREACHABLE_ONLY): New constant.
(note_prediction_to_br_prob): Declare.
* cfgcleanup.c (cleanup_cfg): Allow to only delete unreachable blocks.
* predict.c (process_note_prediction, process_note_predictions,
is_last_basic_block): New static functions.
(estimate_probability): Moved noreturn blocks handling to
process_note_predictions.
(note_prediction_to_br_prob): New function.
* predict.def (PRED_GOTO, PRED_CONST_RETURN, PRED_NIL_RETURN):
New predictions.
* predict.h (IS_TAKEN, IGNORE_IN_LAST): New constants.
* print-rtl.c (print_rtx): Printing of NOTE_INSN_PREDICTION.
* rtl.h (NOTE_INSN_PREDICTION, NOTE_INSN_RETURN): New.
(NOTE_PREDICTION, NOTE_PREDICTION_ALG, NOTE_PREDICTION_FLAGS,
NOTE_PREDICT): New.
* rtl.c (note_insn_name): Names for them.
* stmt.c: Include predict.h.
(maybe_error_return): New static function.
(expand_goto): Emit prediction note.
(expand_null_return, expand_value_return): Emit prediction and return
notes.
* toplev.c (rest_of_compilation): Call note_prediction_to_br_prob.
* cfgrtl.c (can_delete_note_p, flow_delete_block): Removing our notes
when their block disappear.
Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.775.2.2
diff -c -3 -p -r1.775.2.2 Makefile.in
*** Makefile.in 2001/11/12 17:57:39 1.775.2.2
--- Makefile.in 2001/11/16 02:05:11
*************** function.o : function.c $(CONFIG_H) $(SY
*** 1398,1404 ****
insn-config.h $(RECOG_H) output.h toplev.h except.h hash.h $(GGC_H) $(TM_P_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)
except.o : except.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
except.h function.h $(EXPR_H) libfuncs.h integrate.h \
insn-config.h hard-reg-set.h $(BASIC_BLOCK_H) output.h \
--- 1398,1404 ----
insn-config.h $(RECOG_H) output.h toplev.h except.h hash.h $(GGC_H) $(TM_P_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) predict.h $(RECOG_H) toplev.h output.h varray.h $(GGC_H) $(TM_P_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 \
insn-config.h hard-reg-set.h $(BASIC_BLOCK_H) output.h \
*************** check-g++: $(TESTSUITEDIR)/site.exp
*** 2922,2927 ****
--- 2922,2928 ----
check-gcc: $(TESTSUITEDIR)/site.exp
-(rootme=`pwd`; export rootme; \
srcdir=`cd ${srcdir}; pwd` ; export srcdir ; \
+ compiler="${srcdir}/xgcc -B ${srcdir}"; export compiler ; \
cd $(TESTSUITEDIR); \
EXPECT=${EXPECT} ; export EXPECT ; \
if [ -f $${rootme}/../expect/expect ] ; then \
Index: basic-block.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/basic-block.h,v
retrieving revision 1.127.2.1
diff -c -3 -p -r1.127.2.1 basic-block.h
*** basic-block.h 2001/11/12 17:57:41 1.127.2.1
--- basic-block.h 2001/11/16 02:05:11
*************** enum update_life_extent
*** 575,581 ****
--- 575,585 ----
#define CLEANUP_PRE_LOOP 16 /* Take care to preserve syntactic loop
notes. */
#define CLEANUP_UPDATE_LIFE 32 /* Keep life information up to date. */
+
#define CLEANUP_THREADING 64 /* Do jump threading. */
+
+ #define CLEANUP_UNREACHABLE_ONLY 128 /* Only delete unreachable bbs */
+
/* Flags for loop discovery. */
#define LOOP_TREE 1 /* Build loop hierarchy tree. */
*************** extern rtx emit_block_insn_before PARAMS
*** 619,624 ****
--- 623,629 ----
/* In predict.c */
extern void estimate_probability PARAMS ((struct loops *));
extern void expected_value_to_br_prob PARAMS ((void));
+ extern void note_prediction_to_br_prob PARAMS ((void));
/* In flow.c */
extern void init_flow PARAMS ((void));
Index: cfgcleanup.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgcleanup.c,v
retrieving revision 1.18.2.4
diff -c -3 -p -r1.18.2.4 cfgcleanup.c
*** cfgcleanup.c 2001/11/14 11:17:56 1.18.2.4
--- cfgcleanup.c 2001/11/16 02:05:11
*************** cleanup_cfg (mode)
*** 1511,1518 ****
timevar_push (TV_CLEANUP_CFG);
changed = delete_unreachable_blocks ();
! if (try_optimize_cfg (mode))
! delete_unreachable_blocks (), changed = true;
/* Kill the data we won't maintain. */
free_EXPR_LIST_list (&label_value_list);
--- 1511,1522 ----
timevar_push (TV_CLEANUP_CFG);
changed = delete_unreachable_blocks ();
!
! if (! (mode & CLEANUP_UNREACHABLE_ONLY))
! {
! if (try_optimize_cfg (mode))
! delete_unreachable_blocks (), changed = true;
! }
/* Kill the data we won't maintain. */
free_EXPR_LIST_list (&label_value_list);
Index: cfgrtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgrtl.c,v
retrieving revision 1.10.2.1
diff -c -3 -p -r1.10.2.1 cfgrtl.c
*** cfgrtl.c 2001/11/14 11:17:56 1.10.2.1
--- cfgrtl.c 2001/11/16 02:05:11
*************** can_delete_note_p (note)
*** 90,96 ****
rtx note;
{
return (NOTE_LINE_NUMBER (note) == NOTE_INSN_DELETED
! || NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK);
}
/* True if a given label can be deleted. */
--- 90,98 ----
rtx note;
{
return (NOTE_LINE_NUMBER (note) == NOTE_INSN_DELETED
! || NOTE_LINE_NUMBER (note) == NOTE_INSN_BASIC_BLOCK
! || NOTE_LINE_NUMBER (note) == NOTE_INSN_PREDICTION
! || NOTE_LINE_NUMBER (note) == NOTE_INSN_RETURN);
}
/* True if a given label can be deleted. */
*************** flow_delete_block (b)
*** 343,348 ****
--- 345,362 ----
We need to remove the label from the exception_handler_label list
and remove the associated NOTE_INSN_EH_REGION_BEG and
NOTE_INSN_EH_REGION_END notes. */
+
+ /* Get rid of all NOTE_INSN_PREDICTIONs and NOTE_INSN_RETURNs hanging
+ before the block. This really is not very clean. */
+
+ 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_RETURN)
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ }
insn = b->head;
Index: predict.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/predict.c,v
retrieving revision 1.44.2.2
diff -c -3 -p -r1.44.2.2 predict.c
*** predict.c 2001/11/15 15:54:05 1.44.2.2
--- predict.c 2001/11/16 02:05:12
*************** static void estimate_loops_at_level PAR
*** 64,69 ****
--- 64,74 ----
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 int is_last_basic_block PARAMS ((basic_block));
/* Information we hold about each branch predictor.
Filled using information from predict.def. */
*************** estimate_probability (loops_info)
*** 317,323 ****
{
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);
--- 322,327 ----
*************** estimate_probability (loops_info)
*** 371,394 ****
/* 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))
--- 375,380 ----
*************** expected_value_to_br_prob ()
*** 594,599 ****
--- 580,777 ----
predict_insn_def (insn, PRED_BUILTIN_EXPECT,
cond == const_true_rtx ? TAKEN : NOT_TAKEN);
}
+ }
+
+ /* Checks whether the basic block is the last one in "normal" flow */
+ static int
+ is_last_basic_block (bb)
+ basic_block bb;
+ {
+ rtx insn;
+
+ for (insn = NEXT_INSN (bb->end); insn; insn = NEXT_INSN (insn))
+ {
+ if (GET_CODE (insn) == BARRIER)
+ continue;
+ if (GET_CODE (insn) == NOTE)
+ return (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END);
+ return 0;
+ }
+
+ return 0;
+ }
+
+ /* 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;
+ int taken, ignore_in_last;
+
+ taken = flags & IS_TAKEN;
+ ignore_in_last = flags & IGNORE_IN_LAST;
+
+ /* Prediction that should be ignored in last block? */
+ if (ignore_in_last && is_last_basic_block (bb)) return;
+
+ 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, next_ai = dominators[bb->index], 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_return = 0;
+ 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));
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ }
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_RETURN)
+ {
+ /* Record that block is noreturn due to return. */
+ contained_return = 1;
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ }
+ }
+ for (e = bb->succ; e; e = e->succ_next)
+ if (!(e->flags & EDGE_FAKE))
+ noreturn_block = 0;
+ if (noreturn_block && !contained_return)
+ {
+ /* 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,
+ contained_noreturn_call ? PRED_NORETURN : PRED_ERROR_RETURN,
+ 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
Index: predict.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/predict.def,v
retrieving revision 1.12
diff -c -3 -p -r1.12 predict.def
*** predict.def 2001/10/28 20:09:15 1.12
--- predict.def 2001/11/16 02:05:12
*************** DEF_PREDICTOR (PRED_CALL, "call", HITRAT
*** 96,98 ****
--- 96,108 ----
/* Branch causing function to terminate is probably not taken. */
DEF_PREDICTOR (PRED_ERROR_RETURN, "error return", PROB_LIKELY, 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 (70), 0)
+
+ /* Branch ending with return; is probably not taken */
+ DEF_PREDICTOR (PRED_NIL_RETURN, "nil return", HITRATE (70), 0)
+
Index: predict.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/predict.h,v
retrieving revision 1.5
diff -c -3 -p -r1.5 predict.h
*** predict.h 2001/10/28 20:09:15 1.5
--- predict.h 2001/11/16 02:05:12
*************** enum prediction
*** 34,39 ****
--- 34,43 ----
TAKEN
};
+ /* FLAGS FOR NOTE_PREDICTION */
+ #define IS_TAKEN 1
+ #define IGNORE_IN_LAST 2
+
extern void predict_insn_def PARAMS ((rtx, enum br_predictor,
enum prediction));
extern void predict_insn PARAMS ((rtx, enum br_predictor, int));
Index: print-rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/print-rtl.c,v
retrieving revision 1.71
diff -c -3 -p -r1.71 print-rtl.c
*** print-rtl.c 2001/10/24 16:38:51 1.71
--- print-rtl.c 2001/11/16 02:05:12
*************** print_rtx (in_rtx)
*** 258,263 ****
--- 258,272 ----
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);
Index: rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.c,v
retrieving revision 1.103
diff -c -3 -p -r1.103 rtl.c
*** rtl.c 2001/11/03 16:28:33 1.103
--- rtl.c 2001/11/16 02:05:12
*************** const char * const note_insn_name[NOTE_I
*** 269,275 ****
"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"
};
const char * const reg_note_name[] =
--- 269,276 ----
"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_PREDICTION", "NOTE_INSN_RETURN"
};
const char * const reg_note_name[] =
Index: rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.312.2.2
diff -c -3 -p -r1.312.2.2 rtl.h
*** rtl.h 2001/11/12 17:57:43 1.312.2.2
--- rtl.h 2001/11/16 02:05:12
*************** extern const char * const reg_note_name[
*** 629,635 ****
--- 629,636 ----
#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. */
#define NOTE_LINE_NUMBER(INSN) XCINT(INSN, 4, NOTE)
*************** extern const char * const reg_note_name[
*** 639,644 ****
--- 641,651 ----
(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.
*************** enum insn_note
*** 720,725 ****
--- 727,738 ----
/* Record the expected value of a register at a location. Uses
NOTE_EXPECTED_VALUE; stored as (eq (reg) (const_int)). */
NOTE_INSN_EXPECTED_VALUE,
+
+ /* Record a prediction. Uses NOTE_PREDICTION. */
+ NOTE_INSN_PREDICTION,
+
+ /* Mark return invocation. */
+ NOTE_INSN_RETURN,
NOTE_INSN_MAX
};
Index: stmt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stmt.c,v
retrieving revision 1.226
diff -c -3 -p -r1.226 stmt.c
*** stmt.c 2001/11/11 11:02:26 1.226
--- stmt.c 2001/11/16 02:05:12
*************** Software Foundation, 59 Temple Place - S
*** 48,53 ****
--- 48,54 ----
#include "hard-reg-set.h"
#include "obstack.h"
#include "loop.h"
+ #include "predict.h"
#include "recog.h"
#include "machmode.h"
#include "toplev.h"
*************** static tree resolve_operand_names PARAMS
*** 410,415 ****
--- 411,417 ----
const char **));
static char *resolve_operand_name_1 PARAMS ((char *, tree, tree));
static void expand_null_return_1 PARAMS ((rtx));
+ static int maybe_error_return 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));
*************** expand_goto (label)
*** 786,792 ****
--- 788,801 ----
tree label;
{
tree context;
+ rtx note;
+ /* Emit information for branch prediction. */
+
+ note = emit_note (NULL, NOTE_INSN_PREDICTION);
+
+ NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_GOTO, NOT_TAKEN);
+
/* Check for a nonlocal goto to a containing function. */
context = decl_function_context (label);
if (context != 0 && context != current_function_decl)
*************** expand_goto (label)
*** 863,868 ****
--- 872,878 ----
}
else
expand_goto_internal (label, label_rtx (label), NULL_RTX);
+
}
/* Generate RTL code for a `goto' statement with target label BODY.
*************** expand_exit_something ()
*** 3035,3042 ****
void
expand_null_return ()
{
! rtx 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
propogated live to the rest of the function. */
--- 3045,3063 ----
void
expand_null_return ()
{
! rtx last_insn;
!
! rtx note;
!
! /* Emit information for branch prediction. */
!
! note = emit_note (NULL, NOTE_INSN_PREDICTION);
! NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_NIL_RETURN, NOT_TAKEN | IGNORE_IN_LAST);
!
! emit_note (NULL, NOTE_INSN_RETURN);
+ 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
propogated live to the rest of the function. */
*************** expand_null_return ()
*** 3045,3058 ****
expand_null_return_1 (last_insn);
}
/* 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));
/* Copy the value to the return location
unless it's already there. */
--- 3066,3111 ----
expand_null_return_1 (last_insn);
}
+ /* Try to guess whether the value of return means error code. */
+ static int
+ maybe_error_return (val)
+ rtx val;
+ {
+ /* Non-constant value is unlikely to be an error code. */
+ if (!CONSTANT_P (val))
+ return 0;
+
+ /* Zero/one often mean booleans. */
+ if (val == const0_rtx || val == const1_rtx)
+ return 0;
+
+ /* Other constants. We should probably handle pointers specially too? */
+ return 1;
+ }
+
/* Generate RTL to return from the current function, with value VAL. */
static void
expand_value_return (val)
rtx val;
{
! rtx last_insn;
! rtx return_reg;
!
! if (maybe_error_return (val))
! {
! /* Emit information for branch prediction. */
! rtx note;
!
! note = emit_note (NULL, NOTE_INSN_PREDICTION);
!
! NOTE_PREDICTION (note) = NOTE_PREDICT (PRED_CONST_RETURN, NOT_TAKEN | IGNORE_IN_LAST);
!
! }
! emit_note (NULL, NOTE_INSN_RETURN);
!
! 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. */
Index: toplev.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.c,v
retrieving revision 1.537.2.7
diff -c -3 -p -r1.537.2.7 toplev.c
*** toplev.c 2001/11/15 15:54:06 1.537.2.7
--- toplev.c 2001/11/16 02:05:12
*************** rest_of_compilation (decl)
*** 2815,2820 ****
--- 2815,2832 ----
if ((rtl_dump_and_exit || flag_syntax_only) && !warn_return_type)
goto exit_rest_of_compilation;
+ /* Build CFG -- for predictions based on source code. */
+ insns = get_insns ();
+ rebuild_jump_labels (insns);
+ find_basic_blocks (insns, max_reg_num (), rtl_dump_file);
+
+ cleanup_cfg (CLEANUP_PRE_SIBCALL | CLEANUP_UNREACHABLE_ONLY);
+
+ /* Turn NOTE_INSN_PREDICTIONs into branch predictions. */
+ note_prediction_to_br_prob ();
+
+ free_bb_for_insn ();
+
/* We may have potential sibling or tail recursion sites. Select one
(of possibly multiple) methods of performing the call. */
if (flag_optimize_sibling_calls)