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]

Inliner heuristics fixes 3/4


Hi,
this patch solves another part of CSiBE regression.  Inliner heruistics makes
optimistic assumption about loads/stores to/from arguments, return value and
memory pointed to by expecting SRA to happen after inlining.  This is very
important for sane output on C++, but it is also sometimes too optimistic.  In
particular simple constructors are then expected to have cost of 0 and are
inlined regardless of their size, see the attached testcases.

This patch makes us bit less optimistic about the optimization setting it to
50% of probability. This makes us to get bound on size of
constructors/destructors while it is not reducing C++ code quality (in fact it
reduces size noticeably too).  I tested the patch in combination with change
bumping early-inlining-insns to 10 that is needed to keep tramp3d happy.
With this setting it gets quite consistent improvements on C++ and CSiBE.

Bootstrapped/regtested x86_64-linux, will commit it shortly and will follow
with the cost update once testers picks up this change.

LLVM has logic predicting optimization to happen when static vairable or
address of it is passed to function. With little help of jump functions we could
do that too, perhaps in 4.7.

Honza
	PR tree-optimize/40436
	* gcc.dg/tree-ssa/inline-5.c: New testcase.
	* gcc.dg/tree-ssa/inline-6.c: New testcase.

	* ipa-inline.c (likely_eliminated_by_inlining_p): Rename to ...
	(eliminated_by_inlining_prob): ... this one; return 50% probability for
	SRA.
	(estimate_function_body_sizes): Update use of eliminated_by_inlining_prob;
	estimate static function size for 2 instructions.
Index: testsuite/gcc.dg/tree-ssa/inline-6.c
===================================================================
*** testsuite/gcc.dg/tree-ssa/inline-6.c	(revision 0)
--- testsuite/gcc.dg/tree-ssa/inline-6.c	(revision 0)
***************
*** 0 ****
--- 1,36 ----
+ /* { dg-do compile } */
+ /* { dg-options "-Os -fdump-tree-optimize" } */
+ struct a {int a,b,c,d,e,f;};
+ 
+ do_inc (struct a *a)
+ {
+   a->a=1;
+   a->b=2;
+   a->c=3;
+   a->e=4;
+   a->f=5;
+ }
+ 
+ test(struct a *a)
+ {
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+ }
+ /* { dg-final { scan-tree-dump-times "do_inc.*;" 10 "optimized" } } */
+ /* { dg-final { cleanup-tree-dump "optimized" } } */
Index: testsuite/gcc.dg/tree-ssa/inline-5.c
===================================================================
*** testsuite/gcc.dg/tree-ssa/inline-5.c	(revision 0)
--- testsuite/gcc.dg/tree-ssa/inline-5.c	(revision 0)
***************
*** 0 ****
--- 1,35 ----
+ /* { dg-do compile } */
+ /* { dg-options "-Os -fdump-tree-optimize" } */
+ struct a {int a,b,c,d,e,f;};
+ 
+ do_inc (struct a *a)
+ {
+   a->a=a->b;
+   a->b=a->c;
+   a->c=a->d;
+   a->e=a->f;
+ }
+ 
+ test(struct a *a)
+ {
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+   do_inc (a);
+   do_something (a);
+ }
+ /* { dg-final { scan-tree-dump-times "do_inc.*;" 10 "optimized" } } */
+ /* { dg-final { cleanup-tree-dump "optimized" } } */
Index: ipa-inline.c
===================================================================
*** ipa-inline.c	(revision 166616)
--- ipa-inline.c	(working copy)
*************** struct gimple_opt_pass pass_early_inline
*** 1861,1884 ****
  };
  
  
! /* See if statement might disappear after inlining.  We are not terribly
!    sophisficated, basically looking for simple abstraction penalty wrappers.  */
  
! static bool
! likely_eliminated_by_inlining_p (gimple stmt)
  {
    enum gimple_code code = gimple_code (stmt);
    switch (code)
      {
        case GIMPLE_RETURN:
!         return true;
        case GIMPLE_ASSIGN:
  	if (gimple_num_ops (stmt) != 2)
! 	  return false;
  
  	/* Casts of parameters, loads from parameters passed by reference
! 	   and stores to return value or parameters are probably free after
! 	   inlining.  */
  	if (gimple_assign_rhs_code (stmt) == CONVERT_EXPR
  	    || gimple_assign_rhs_code (stmt) == NOP_EXPR
  	    || gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR
--- 1861,1889 ----
  };
  
  
! /* See if statement might disappear after inlining.
!    0 - means not eliminated
!    1 - half of statements goes away
!    2 - for sure it is eliminated.
!    We are not terribly sophisficated, basically looking for simple abstraction
!    penalty wrappers.  */
  
! static int
! eliminated_by_inlining_prob (gimple stmt)
  {
    enum gimple_code code = gimple_code (stmt);
    switch (code)
      {
        case GIMPLE_RETURN:
!         return 2;
        case GIMPLE_ASSIGN:
  	if (gimple_num_ops (stmt) != 2)
! 	  return 0;
  
  	/* Casts of parameters, loads from parameters passed by reference
! 	   and stores to return value or parameters are often free after
! 	   inlining dua to SRA and further combining.
! 	   Assume that half of statements goes away.  */
  	if (gimple_assign_rhs_code (stmt) == CONVERT_EXPR
  	    || gimple_assign_rhs_code (stmt) == NOP_EXPR
  	    || gimple_assign_rhs_code (stmt) == VIEW_CONVERT_EXPR
*************** likely_eliminated_by_inlining_p (gimple 
*** 1920,1930 ****
  		&& (is_gimple_reg (rhs) || is_gimple_min_invariant (rhs)))
  	      rhs_free = true;
  	    if (lhs_free && rhs_free)
! 	      return true;
  	  }
! 	return false;
        default:
! 	return false;
      }
  }
  
--- 1925,1935 ----
  		&& (is_gimple_reg (rhs) || is_gimple_min_invariant (rhs)))
  	      rhs_free = true;
  	    if (lhs_free && rhs_free)
! 	      return 1;
  	  }
! 	return 0;
        default:
! 	return 0;
      }
  }
  
*************** estimate_function_body_sizes (struct cgr
*** 1935,1942 ****
  {
    gcov_type time = 0;
    gcov_type time_inlining_benefit = 0;
!   int size = 0;
!   int size_inlining_benefit = 0;
    basic_block bb;
    gimple_stmt_iterator bsi;
    struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
--- 1940,1950 ----
  {
    gcov_type time = 0;
    gcov_type time_inlining_benefit = 0;
!   /* Estimate static overhead for function prologue/epilogue and alignment. */
!   int size = 2;
!   /* Benefits are scaled by probability of elimination that is in range
!      <0,2>.  */
!   int size_inlining_benefit = 2 * 2;
    basic_block bb;
    gimple_stmt_iterator bsi;
    struct function *my_function = DECL_STRUCT_FUNCTION (node->decl);
*************** estimate_function_body_sizes (struct cgr
*** 1957,1962 ****
--- 1965,1971 ----
  	  gimple stmt = gsi_stmt (bsi);
  	  int this_size = estimate_num_insns (stmt, &eni_size_weights);
  	  int this_time = estimate_num_insns (stmt, &eni_time_weights);
+ 	  int prob;
  
  	  if (dump_file && (dump_flags & TDF_DETAILS))
  	    {
*************** estimate_function_body_sizes (struct cgr
*** 1967,1986 ****
  	  this_time *= freq;
  	  time += this_time;
  	  size += this_size;
! 	  if (likely_eliminated_by_inlining_p (stmt))
! 	    {
! 	      size_inlining_benefit += this_size;
! 	      time_inlining_benefit += this_time;
! 	      if (dump_file && (dump_flags & TDF_DETAILS))
! 		fprintf (dump_file, "    Likely eliminated\n");
! 	    }
  	  gcc_assert (time >= 0);
  	  gcc_assert (size >= 0);
  	}
      }
    time = (time + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
!   time_inlining_benefit = ((time_inlining_benefit + CGRAPH_FREQ_BASE / 2)
!   			   / CGRAPH_FREQ_BASE);
    if (dump_file)
      fprintf (dump_file, "Overall function body time: %i-%i size: %i-%i\n",
  	     (int)time, (int)time_inlining_benefit,
--- 1976,1996 ----
  	  this_time *= freq;
  	  time += this_time;
  	  size += this_size;
! 	  prob = eliminated_by_inlining_prob (stmt);
! 	  if (prob == 1 && dump_file && (dump_flags & TDF_DETAILS))
! 	    fprintf (dump_file, "    50%% will be eliminated by inlining\n");
! 	  if (prob == 2 && dump_file && (dump_flags & TDF_DETAILS))
! 	    fprintf (dump_file, "    will eliminated by inlining\n");
! 	  size_inlining_benefit += this_size * prob;
! 	  time_inlining_benefit += this_time * prob;
  	  gcc_assert (time >= 0);
  	  gcc_assert (size >= 0);
  	}
      }
    time = (time + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
!   time_inlining_benefit = ((time_inlining_benefit + CGRAPH_FREQ_BASE)
!   			   / (CGRAPH_FREQ_BASE * 2));
!   size_inlining_benefit = (size_inlining_benefit + 1) / 2;
    if (dump_file)
      fprintf (dump_file, "Overall function body time: %i-%i size: %i-%i\n",
  	     (int)time, (int)time_inlining_benefit,


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