This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]