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]

patch to improve i386 epilogue (version 4)


[ This version uses life_analysis to determine if the function
  contains calls to other functions. ]

This change allows gcc to skip the loading of the stack pointer
when it is already known to contain the proper value.  This
optimization is currently only implemented for leaf functions.

ChangeLog:

Thu Oct  8 01:43:29 EDT 1998  John Wehle  (john@feith.com)

	* flow.c: Update comment.
	(life_analysis_1): Set current_function_has_no_calls.
	* function.c: Define it.
	(init_function_start): Initialize it.
	* output.h: Declare it.
	* i386.c (ix86_epilogue): Optimize the restoring
	of the stack pointer for leaf functions.

Enjoy!

-- John Wehle
------------------8<------------------------8<------------------------
*** gcc/flow.c.ORIGINAL	Wed Oct  7 23:04:50 1998
--- gcc/flow.c	Thu Oct  8 00:33:35 1998
*************** Boston, MA 02111-1307, USA.  */
*** 106,112 ****
  
     life_analysis fills in certain vectors containing information about
     register usage: reg_n_refs, reg_n_deaths, reg_n_sets, reg_live_length,
!    reg_n_calls_crosses and reg_basic_block.  */
  
  #include "config.h"
  #include "system.h"
--- 106,115 ----
  
     life_analysis fills in certain vectors containing information about
     register usage: reg_n_refs, reg_n_deaths, reg_n_sets, reg_live_length,
!    reg_n_calls_crosses and reg_basic_block.
! 
!    life_analysis sets current_function_has_no_calls if the function doesn't
!    contains calls to other functions.  */
  
  #include "config.h"
  #include "system.h"
*************** life_analysis_1 (f, nregs)
*** 1154,1159 ****
--- 1157,1167 ----
      = (regset *) alloca (n_basic_blocks * sizeof (regset));
    init_regset_vector (basic_block_significant, n_basic_blocks, &flow_obstack);
  
+   /* Assume that the function has no calls.  This will be reset if we
+      encounter a call. */
+ 
+   current_function_has_no_calls = 1;
+ 
    /* Record which insns refer to any volatile memory
       or for any reason can't be deleted just because they are dead stores.
       Also, delete any insns that copy a register to itself.  */
*************** life_analysis_1 (f, nregs)
*** 1162,1168 ****
      {
        enum rtx_code code1 = GET_CODE (insn);
        if (code1 == CALL_INSN)
! 	INSN_VOLATILE (insn) = 1;
        else if (code1 == INSN || code1 == JUMP_INSN)
  	{
  	  /* Delete (in effect) any obvious no-op moves.  */
--- 1170,1179 ----
      {
        enum rtx_code code1 = GET_CODE (insn);
        if (code1 == CALL_INSN)
! 	{
! 	  INSN_VOLATILE (insn) = 1;
! 	  current_function_has_no_calls = 0;
! 	}
        else if (code1 == INSN || code1 == JUMP_INSN)
  	{
  	  /* Delete (in effect) any obvious no-op moves.  */
*** gcc/function.c.ORIGINAL	Tue Oct  6 11:03:35 1998
--- gcc/function.c	Thu Oct  8 00:33:35 1998
*************** int current_function_has_computed_jump;
*** 138,143 ****
--- 138,149 ----
  
  int current_function_contains_functions;
  
+ /* Nonzero if function being compiled doesn't call other functions
+    (ignoring calls that may exist in the prologue).  This is only
+    valid after life_analysis has run. */
+ 
+ int current_function_has_no_calls;
+ 
  /* Nonzero if the current function is a thunk (a lightweight function that
     just adjusts one of its arguments and forwards to another function), so
     we should try to cut corners where we can.  */
*************** init_function_start (subr, filename, lin
*** 5431,5436 ****
--- 5437,5443 ----
    current_function_has_nonlocal_label = 0;
    current_function_has_nonlocal_goto = 0;
    current_function_contains_functions = 0;
+   current_function_has_no_calls = 0;
    current_function_is_thunk = 0;
  
    current_function_returns_pcc_struct = 0;
*** gcc/output.h.ORIGINAL	Sun Sep 20 15:11:12 1998
--- gcc/output.h	Thu Oct  8 00:33:35 1998
*************** extern int current_function_has_nonlocal
*** 380,385 ****
--- 380,391 ----
  
  extern int current_function_contains_functions;
  
+ /* Nonzero if function being compiled doesn't call other functions
+    (ignoring calls that may exist in the prologue).  This is only
+    valid after life_analysis has run.  */
+ 
+ extern int current_function_has_no_calls;
+ 
  /* Nonzero if the current function returns a pointer type */
  
  extern int current_function_returns_pointer;
*** gcc/config/i386/i386.c.ORIGINAL	Sun Sep  6 01:52:05 1998
--- gcc/config/i386/i386.c	Thu Oct  8 00:33:36 1998
*************** ix86_epilogue (do_rtl)
*** 2294,2299 ****
--- 2294,2301 ----
    rtx xops[3];
    int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
  				  || current_function_uses_const_pool);
+   int sp_valid = !frame_pointer_needed || (current_function_has_no_calls
+ 					   && !current_function_calls_alloca);
    long tsize = get_frame_size ();
  
    /* Compute the number of registers to pop */
*************** ix86_epilogue (do_rtl)
*** 2307,2318 ****
  	|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
        nregs++;
  
!   /* sp is often  unreliable so we must go off the frame pointer.
! 
!      In reality, we may not care if sp is unreliable, because we can restore
!      the register relative to the frame pointer.  In theory, since each move
!      is the same speed as a pop, and we don't need the leal, this is faster.
!      For now restore multiple registers the old way. */
  
    offset = - tsize - (nregs * UNITS_PER_WORD);
  
--- 2309,2315 ----
  	|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
        nregs++;
  
!   /* sp is often unreliable so we may have to go off the frame pointer. */
  
    offset = - tsize - (nregs * UNITS_PER_WORD);
  
*************** ix86_epilogue (do_rtl)
*** 2329,2337 ****
    if (flag_pic || profile_flag || profile_block_flag)
      emit_insn (gen_blockage ());
  
!   if (nregs > 1 || ! frame_pointer_needed)
      {
!       if (frame_pointer_needed)
  	{
  	  xops[0] = adj_offsettable_operand (AT_BP (QImode), offset);
  	  if (do_rtl)
--- 2326,2339 ----
    if (flag_pic || profile_flag || profile_block_flag)
      emit_insn (gen_blockage ());
  
!   /* If we're only restoring one register and sp is not valid then
!      using a move instruction to restore the register since it's
!      less work than reloading sp and popping the register.  Otherwise,
!      restore sp (if necessary) and pop the registers. */
! 
!   if (nregs > 1 || sp_valid)
      {
!       if ( !sp_valid )
  	{
  	  xops[0] = adj_offsettable_operand (AT_BP (QImode), offset);
  	  if (do_rtl)
-------------------------------------------------------------------------
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: john@feith.com  |
|    John Wehle    |     Fax: 1-215-540-5495  |                         |
-------------------------------------------------------------------------



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