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


[ This version is in principle identical to version 5.  It has
  been updated to match the current source tree and to include
  some suggestions by Jeff. ]

This change allows gcc to skip the loading of the stack pointer
when it is already known to contain the proper value.

ChangeLog:

Sun Oct 11 16:49:15 EDT 1998  John Wehle  (john@feith.com)

	* flow.c: Update comment.
	(notice_stack_pointer_modification): New static function.
	(record_volatile_insns): Use it.
	(mark_regs_live_at_end): Mark the stack pointer as alive
	at the end of the function if current_function_sp_is_unchanging
	is set.
	(life_analysis_1): Set current_function_sp_is_unchanging.
	* function.c: Define it.
	(init_function_start): Initialize it.
	* output.h: Declare it.
	* reorg.c (fill_simple_delay_slots, dbr_schedule): Mark
	the stack pointer as alive at the end of the function if
	current_function_sp_is_unchanging is set.
	* i386.c (ix86_epilogue): Optimize the restoring
	of the stack pointer.

Enjoy!

-- John Wehle
------------------8<------------------------8<------------------------
*** gcc/flow.c.ORIGINAL	Sun Oct 11 13:56:47 1998
--- gcc/flow.c	Sun Oct 11 16:48:22 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_sp_is_unchanging if the function
!    doesn't modify the stack pointer.  */
  
  #include "config.h"
  #include "system.h"
*************** noop_move_p (insn)
*** 1221,1229 ****
    return 0;
  }
  
  /* 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.  */
  static void
  record_volatile_insns (f)
       rtx f;
--- 1224,1251 ----
    return 0;
  }
  
+ static void
+ notice_stack_pointer_modification (x, pat)
+      rtx x;
+      rtx pat ATTRIBUTE_UNUSED;
+ {
+   if (x == stack_pointer_rtx
+       /* The stack pointer is only modified indirectly as the result
+ 	 of a push until later in flow.  See the comments in rtl.texi
+ 	 regarding Embedded Side-Effects on Addresses.  */
+       || (GET_CODE (x) == MEM
+ 	  && (GET_CODE (XEXP (x, 0)) == PRE_DEC
+ 	      || GET_CODE (XEXP (x, 0)) == PRE_INC
+ 	      || GET_CODE (XEXP (x, 0)) == POST_DEC
+ 	      || GET_CODE (XEXP (x, 0)) == POST_INC)
+ 	  && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx))
+     current_function_sp_is_unchanging = 0;
+ }
+ 
  /* 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.
!    And see if the stack pointer is modified.  */
  static void
  record_volatile_insns (f)
       rtx f;
*************** record_volatile_insns (f)
*** 1264,1269 ****
--- 1286,1296 ----
  	      NOTE_SOURCE_FILE (insn) = 0;
  	    }
  	}
+ 
+       /* Check if insn modifies the stack pointer.  */
+       if ( current_function_sp_is_unchanging
+ 	   && GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ 	note_stores (PATTERN (insn), notice_stack_pointer_modification);
      }
  }
  
*************** mark_regs_live_at_end (set)
*** 1279,1285 ****
    if (! EXIT_IGNORE_STACK
        || (! FRAME_POINTER_REQUIRED
  	  && ! current_function_calls_alloca
! 	  && flag_omit_frame_pointer))
  #endif
      /* If exiting needs the right stack value,
         consider the stack pointer live at the end of the function.  */
--- 1306,1313 ----
    if (! EXIT_IGNORE_STACK
        || (! FRAME_POINTER_REQUIRED
  	  && ! current_function_calls_alloca
! 	  && flag_omit_frame_pointer)
!       || current_function_sp_is_unchanging)
  #endif
      /* If exiting needs the right stack value,
         consider the stack pointer live at the end of the function.  */
*************** life_analysis_1 (f, nregs)
*** 1375,1380 ****
--- 1403,1413 ----
    basic_block_significant
      = (regset *) alloca (n_basic_blocks * sizeof (regset));
    init_regset_vector (basic_block_significant, n_basic_blocks, &flow_obstack);
+ 
+   /* Assume that the stack pointer is unchanging if alloca hasn't been used.
+      This will be cleared by record_volatile_insns if it encounters an insn
+      which modifies the stack pointer.  */
+   current_function_sp_is_unchanging = !current_function_calls_alloca;
  
    record_volatile_insns (f);
  
*** gcc/function.c.ORIGINAL	Sun Oct 11 13:56:47 1998
--- gcc/function.c	Sun Oct 11 15:50:08 1998
*************** int current_function_has_computed_jump;
*** 138,143 ****
--- 138,149 ----
  
  int current_function_contains_functions;
  
+ /* Nonzero if function being compiled doesn't modify the stack pointer
+    (ignoring the prologue and epilogue).  This is only valid after
+    life_analysis has run. */
+ 
+ int current_function_sp_is_unchanging;
+ 
  /* 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
*** 5426,5431 ****
--- 5432,5438 ----
    current_function_has_nonlocal_label = 0;
    current_function_has_nonlocal_goto = 0;
    current_function_contains_functions = 0;
+   current_function_sp_is_unchanging = 0;
    current_function_is_thunk = 0;
  
    current_function_returns_pcc_struct = 0;
*** gcc/output.h.ORIGINAL	Sun Oct 11 13:56:48 1998
--- gcc/output.h	Sun Oct 11 15:49:58 1998
*************** extern int current_function_has_nonlocal
*** 380,385 ****
--- 380,391 ----
  
  extern int current_function_contains_functions;
  
+ /* Nonzero if function being compiled doesn't modify the stack pointer
+    (ignoring the prologue and epilogue).  This is only valid after
+    life_analysis has run. */
+ 
+ extern int current_function_sp_is_unchanging;
+ 
  /* Nonzero if the current function returns a pointer type */
  
  extern int current_function_returns_pointer;
*** gcc/reorg.c.ORIGINAL	Fri Oct  9 22:41:36 1998
--- gcc/reorg.c	Sun Oct 11 15:56:56 1998
*************** fill_simple_delay_slots (non_jumps_p)
*** 3452,3458 ****
        SET_HARD_REG_BIT (needed.regs, HARD_FRAME_POINTER_REGNUM);
  #endif
  #ifdef EXIT_IGNORE_STACK
!       if (! EXIT_IGNORE_STACK)
  #endif
  	SET_HARD_REG_BIT (needed.regs, STACK_POINTER_REGNUM);
      }
--- 3452,3459 ----
        SET_HARD_REG_BIT (needed.regs, HARD_FRAME_POINTER_REGNUM);
  #endif
  #ifdef EXIT_IGNORE_STACK
!       if (! EXIT_IGNORE_STACK
! 	  || current_function_sp_is_unchanging)
  #endif
  	SET_HARD_REG_BIT (needed.regs, STACK_POINTER_REGNUM);
      }
*************** dbr_schedule (first, file)
*** 4602,4608 ****
        SET_HARD_REG_BIT (end_of_function_needs.regs, HARD_FRAME_POINTER_REGNUM);
  #endif
  #ifdef EXIT_IGNORE_STACK
!       if (! EXIT_IGNORE_STACK)
  #endif
  	SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM);
      }
--- 4603,4610 ----
        SET_HARD_REG_BIT (end_of_function_needs.regs, HARD_FRAME_POINTER_REGNUM);
  #endif
  #ifdef EXIT_IGNORE_STACK
!       if (! EXIT_IGNORE_STACK
! 	  || current_function_sp_is_unchanging)
  #endif
  	SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM);
      }
*** gcc/config/i386/i386.c.ORIGINAL	Fri Oct  9 22:42:20 1998
--- gcc/config/i386/i386.c	Sun Oct 11 15:49:22 1998
*************** ix86_epilogue (do_rtl)
*** 2294,2299 ****
--- 2294,2300 ----
    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_sp_is_unchanging;
    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);
  
--- 2308,2314 ----
  	|| (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)
--- 2325,2338 ----
    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]