Fix high level prediction wrt early inlining

Jan Hubicka jh@suse.cz
Sat Aug 30 14:02:00 GMT 2008


Hi,
early inlining disturbs high level predictors (__builtin_expect, cold
function attribute and continue prediction) since already processed
functions with hints removed are being inlined into unprocessed and thus
hints are lost.  This patch makes them to be kept till late compilation.

I also noticed that C++ frontend was not yet updated for PRED_CONTINUE.

Bootstrapped/regtested i686-linux, comitted.

	* tree-pass.h (pass_strip_predict_hints): Declare.
	* predict.c (strip_builtin_expect): Rename to ...
	(strip_predict_hints): ... this one; strip also GIMPLE_PREDICT.
	(tree_bb_level_predictions): Do not remove GIMPLE_PREDICT.
	(tree_estimate_probability): Do not strip builtin_expect.
	(pass_strip_predict_hints): New pass.
	* tree-inline.c (expand_call_inline): When inlining cold function, predict
	it as unlikely.
	* passes.c (init_optimization_passes): Add pass_strip_predict_hints.
	
	* cp-gimplify.c (cp_gimplify_expr): Add PRED_CONTINUE heuristic.
Index: tree-pass.h
===================================================================
*** tree-pass.h	(revision 139736)
--- tree-pass.h	(working copy)
*************** extern struct gimple_opt_pass pass_merge
*** 346,351 ****
--- 346,352 ----
  extern struct gimple_opt_pass pass_split_crit_edges;
  extern struct gimple_opt_pass pass_pre;
  extern struct gimple_opt_pass pass_profile;
+ extern struct gimple_opt_pass pass_strip_predict_hints;
  extern struct gimple_opt_pass pass_lower_complex_O0;
  extern struct gimple_opt_pass pass_lower_complex;
  extern struct gimple_opt_pass pass_lower_vector;
Index: cp/cp-gimplify.c
===================================================================
*** cp/cp-gimplify.c	(revision 139736)
--- cp/cp-gimplify.c	(working copy)
*************** cp_gimplify_expr (tree *expr_p, gimple_s
*** 610,615 ****
--- 610,616 ----
        break;
  
      case CONTINUE_STMT:
+       gimple_seq_add_stmt (pre_p, gimple_build_predict (PRED_CONTINUE, NOT_TAKEN));
        gimple_seq_add_stmt (pre_p, gimple_build_goto (get_bc_label (bc_continue)));
        *expr_p = NULL_TREE;
        ret = GS_ALL_DONE;
Index: predict.c
===================================================================
*** predict.c	(revision 139737)
--- predict.c	(working copy)
*************** expr_expected_value (tree expr, bitmap v
*** 1176,1184 ****
  }
  
  
! /* Get rid of all builtin_expect calls we no longer need.  */
! static void
! strip_builtin_expect (void)
  {
    basic_block bb;
    gimple ass_stmt;
--- 1176,1185 ----
  }
  
  
! /* Get rid of all builtin_expect calls and GIMPLE_PREDICT statements
!    we no longer need.  */
! static unsigned int
! strip_predict_hints (void)
  {
    basic_block bb;
    gimple ass_stmt;
*************** strip_builtin_expect (void)
*** 1187,1214 ****
    FOR_EACH_BB (bb)
      {
        gimple_stmt_iterator bi;
!       for (bi = gsi_start_bb (bb); !gsi_end_p (bi); gsi_next (&bi))
  	{
  	  gimple stmt = gsi_stmt (bi);
- 	  tree fndecl;
- 
- 	  if (gimple_code (stmt) != GIMPLE_CALL)
- 	    continue;
- 
- 	  fndecl = gimple_call_fndecl (stmt);
  
! 	  if (fndecl
! 	      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
! 	      && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
! 	      && gimple_call_num_args (stmt) == 2)
  	    {
! 	      var = gimple_call_lhs (stmt);
! 	      ass_stmt = gimple_build_assign (var, gimple_call_arg (stmt, 0));
  
! 	      gsi_replace (&bi, ass_stmt, true);
  	    }
  	}
      }
  }
  
  /* Predict using opcode of the last statement in basic block.  */
--- 1188,1221 ----
    FOR_EACH_BB (bb)
      {
        gimple_stmt_iterator bi;
!       for (bi = gsi_start_bb (bb); !gsi_end_p (bi);)
  	{
  	  gimple stmt = gsi_stmt (bi);
  
! 	  if (gimple_code (stmt) == GIMPLE_PREDICT)
! 	    {
! 	      gsi_remove (&bi, true);
! 	      continue;
! 	    }
! 	  else if (gimple_code (stmt) == GIMPLE_CALL)
  	    {
! 	      tree fndecl = gimple_call_fndecl (stmt);
  
! 	      if (fndecl
! 		  && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
! 		  && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
! 		  && gimple_call_num_args (stmt) == 2)
! 		{
! 		  var = gimple_call_lhs (stmt);
! 		  ass_stmt = gimple_build_assign (var, gimple_call_arg (stmt, 0));
! 
! 		  gsi_replace (&bi, ass_stmt, true);
! 		}
  	    }
+ 	  gsi_next (&bi);
  	}
      }
+   return 0;
  }
  
  /* Predict using opcode of the last statement in basic block.  */
*************** tree_bb_level_predictions (void)
*** 1434,1440 ****
      {
        gimple_stmt_iterator gsi;
  
!       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
  	{
  	  gimple stmt = gsi_stmt (gsi);
  	  tree decl;
--- 1441,1447 ----
      {
        gimple_stmt_iterator gsi;
  
!       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
  	{
  	  gimple stmt = gsi_stmt (gsi);
  	  tree decl;
*************** tree_bb_level_predictions (void)
*** 1455,1465 ****
  	    {
  	      predict_paths_leading_to (bb, gimple_predict_predictor (stmt),
  					gimple_predict_outcome (stmt));
! 	      gsi_remove (&gsi, true);
! 	      continue;
  	    }
- 
- 	  gsi_next (&gsi);
  	}
      }
  }
--- 1462,1470 ----
  	    {
  	      predict_paths_leading_to (bb, gimple_predict_predictor (stmt),
  					gimple_predict_outcome (stmt));
! 	      /* Keep GIMPLE_PREDICT around so early inlining will propagate
! 	         hints to callers.  */
  	    }
  	}
      }
  }
*************** tree_estimate_probability (void)
*** 1587,1593 ****
    pointer_map_destroy (bb_predictions);
    bb_predictions = NULL;
  
-   strip_builtin_expect ();
    estimate_bb_frequencies ();
    free_dominance_info (CDI_POST_DOMINATORS);
    remove_fake_exit_edges ();
--- 1592,1597 ----
*************** struct gimple_opt_pass pass_profile = 
*** 2084,2086 ****
--- 2088,2109 ----
    TODO_ggc_collect | TODO_verify_ssa			/* todo_flags_finish */
   }
  };
+ 
+ struct gimple_opt_pass pass_strip_predict_hints = 
+ {
+  {
+   GIMPLE_PASS,
+   "",					/* name */
+   NULL,					/* gate */
+   strip_predict_hints,			/* execute */
+   NULL,					/* sub */
+   NULL,					/* next */
+   0,					/* static_pass_number */
+   TV_BRANCH_PROB,			/* tv_id */
+   PROP_cfg,				/* properties_required */
+   0,					/* properties_provided */
+   0,					/* properties_destroyed */
+   0,					/* todo_flags_start */
+   TODO_ggc_collect | TODO_verify_ssa			/* todo_flags_finish */
+  }
+ };
Index: tree-inline.c
===================================================================
*** tree-inline.c	(revision 139736)
--- tree-inline.c	(working copy)
*************** expand_call_inline (basic_block bb, gimp
*** 3209,3214 ****
--- 3209,3221 ----
    gcc_assert (!id->src_cfun->after_inlining);
  
    id->entry_bb = bb;
+   if (lookup_attribute ("cold", DECL_ATTRIBUTES (fn)))
+     {
+       gimple_stmt_iterator si = gsi_last_bb (bb);
+       gsi_insert_after (&si, gimple_build_predict (PRED_COLD_FUNCTION,
+       						   NOT_TAKEN),
+ 			GSI_NEW_STMT);
+     }
    initialize_inlined_parameters (id, stmt, fn, bb);
  
    if (DECL_INITIAL (fn))
Index: passes.c
===================================================================
*** passes.c	(revision 139736)
--- passes.c	(working copy)
*************** init_optimization_passes (void)
*** 585,590 ****
--- 585,591 ----
        struct opt_pass **p = &pass_all_optimizations.pass.sub;
        /* Initial scalar cleanups before alias computation.
  	 They ensure memory accesses are not indirect wherever possible.  */
+       NEXT_PASS (pass_strip_predict_hints);
        NEXT_PASS (pass_update_address_taken);
        NEXT_PASS (pass_rename_ssa_copies);
        NEXT_PASS (pass_complete_unrolli);



More information about the Gcc-patches mailing list