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]

i386 prologue/epilogue code cleanups


Hi
This patch contains some cleanups to i386 stack frame handling code. Basically
it converts the large macro INITIAL_ELIMINATION_OFFSET to function, breaks out
some functionality from ix86_expand_prologue and ix86_expand_epilogue and
removes some code duplication.

There are no changes in the behaviour of code.
It is only the preparation work for my frame pointer elimination patches.

Wed Jan 19 12:18:11 CET 2000  Jan Hubicka  <jh@suse.cz>

	* i386-protos.h (ix86_compute_frame_size): Remove prototype.
	(ix86_initial_elimination_offset): Declare.
	* i386.c (ix86_nsaved_regs): Break out from ...
	(ix86_can_use_return_insn_p): ... here.
	(ix86_emit_save_regs): Break out from ...
	(ix86_expand_prologue): ... here.
	(ix86_emit_esp_adjustment, ix86_emit_restore_regs): Break out from ...
	(ix86_expand_epilogue): ... here.
	(ix86_compute_frame_size): Make static, add prototype.
	(ix86_initial_elimination_offset): Break out from ...
	* i386.h (INITIAL_ELIMINATION_OFFSET): ... here.

diff -Nrc3p i386.new1/i386-protos.h i386/i386-protos.h
*** i386.new1/i386-protos.h	Wed Jan 19 00:05:50 2000
--- i386/i386-protos.h	Wed Jan 19 11:28:25 2000
*************** extern int ix86_can_use_return_insn_p PR
*** 27,33 ****
  
  extern void asm_output_function_prefix PARAMS((FILE *, char *));
  extern void load_pic_register PARAMS((void));
! extern HOST_WIDE_INT ix86_compute_frame_size PARAMS((HOST_WIDE_INT, int *));
  extern void ix86_expand_prologue PARAMS((void));
  extern void ix86_expand_epilogue PARAMS((void));
  
--- 27,33 ----
  
  extern void asm_output_function_prefix PARAMS((FILE *, char *));
  extern void load_pic_register PARAMS((void));
! extern HOST_WIDE_INT ix86_initial_elimination_offset PARAMS((int, int));
  extern void ix86_expand_prologue PARAMS((void));
  extern void ix86_expand_epilogue PARAMS((void));
  
diff -Nrc3p i386.new1/i386.c i386/i386.c
*** i386.new1/i386.c	Wed Jan 19 00:05:50 2000
--- i386/i386.c	Wed Jan 19 12:28:00 2000
*************** static void ix86_init_machine_status PRO
*** 325,330 ****
--- 325,335 ----
  static void ix86_mark_machine_status PARAMS ((struct function *));
  static void ix86_split_to_parts PARAMS ((rtx, rtx *, enum machine_mode));
  static int ix86_safe_length_prefix PARAMS ((rtx));
+ static HOST_WIDE_INT ix86_compute_frame_size PARAMS((HOST_WIDE_INT, int *));
+ static int ix86_nsaved_regs PARAMS((void));
+ static void ix86_emit_save_regs PARAMS((void));
+ static void ix86_emit_restore_regs PARAMS((void));
+ static void ix86_emit_esp_adjustment PARAMS((int));
  
  struct ix86_address
  {
*************** symbolic_reference_mentioned_p (op)
*** 1434,1446 ****
  int
  ix86_can_use_return_insn_p ()
  {
-   int regno;
-   int nregs = 0;
-   int reglimit = (frame_pointer_needed
- 		  ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
-   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
- 				  || current_function_uses_const_pool);
- 
  #ifdef NON_SAVING_SETJMP
    if (NON_SAVING_SETJMP && current_function_calls_setjmp)
      return 0;
--- 1439,1444 ----
*************** ix86_can_use_return_insn_p ()
*** 1449,1460 ****
    if (! reload_completed)
      return 0;
  
!   for (regno = reglimit - 1; regno >= 0; regno--)
!     if ((regs_ever_live[regno] && ! call_used_regs[regno])
! 	|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
!       nregs++;
! 
!   return nregs == 0 || ! frame_pointer_needed;
  }
  
  static char *pic_label_name;
--- 1447,1453 ----
    if (! reload_completed)
      return 0;
  
!   return ix86_nsaved_regs () == 0 || ! frame_pointer_needed;
  }
  
  static char *pic_label_name;
*************** gen_push (arg)
*** 1547,1552 ****
--- 1540,1600 ----
  		      arg);
  }
  
+ /* Return number of registers to be saved on the stack.  */
+ 
+ static int
+ ix86_nsaved_regs ()
+ {
+   int nregs = 0;
+   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
+ 				  || current_function_uses_const_pool);
+   int limit = (frame_pointer_needed
+ 	       ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
+   int regno;
+ 
+   for (regno = limit - 1; regno >= 0; regno--)
+     if ((regs_ever_live[regno] && ! call_used_regs[regno])
+ 	|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
+       {
+ 	nregs ++;
+       }
+   return nregs;
+ }
+ 
+ /* Return the offset between two registers, one to be eliminated, and the other
+    its replacement, at the start of a routine.  */
+ 
+ HOST_WIDE_INT
+ ix86_initial_elimination_offset (from, to)
+      int from;
+      int to;
+ {
+   if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
+     return 8;			/* Skip saved PC and previous frame pointer */
+   else
+     {
+       int nregs;
+       int poffset;
+       int offset;
+       int preferred_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
+       HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (),
+ 						     &nregs);
+ 
+       offset = (tsize + nregs * UNITS_PER_WORD);
+ 
+       poffset = 4;
+       if (frame_pointer_needed)
+ 	poffset += UNITS_PER_WORD;
+ 
+       if (from == ARG_POINTER_REGNUM)
+ 	offset += poffset;
+       else
+ 	offset -= ((poffset + preferred_alignment - 1)
+ 		   & -preferred_alignment) - poffset;
+       return offset;
+     }
+ }
+ 
  /* Compute the size of local storage taking into consideration the
     desired stack alignment which is to be maintained.  Also determine
     the number of registers saved below the local storage.  */
*************** ix86_compute_frame_size (size, nregs_on_
*** 1608,1620 ****
    return size + padding;
  }
  
  /* Expand the prologue into a bunch of separate insns. */
  
  void
  ix86_expand_prologue ()
  {
-   register int regno;
-   int limit;
    int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
  				  || current_function_uses_const_pool);
    HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), (int *)0);
--- 1656,1688 ----
    return size + padding;
  }
  
+ /* Emit code to save registers in the prologue.  */
+ 
+ static void
+ ix86_emit_save_regs ()
+ {
+   register int regno;
+   int limit;
+   rtx insn;
+   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
+ 				  || current_function_uses_const_pool);
+   limit = (frame_pointer_needed
+ 	   ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
+ 
+   for (regno = limit - 1; regno >= 0; regno--)
+     if ((regs_ever_live[regno] && !call_used_regs[regno])
+ 	|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
+       {
+ 	insn = emit_insn (gen_push (gen_rtx_REG (SImode, regno)));
+ 	RTX_FRAME_RELATED_P (insn) = 1;
+       }
+ }
+ 
  /* Expand the prologue into a bunch of separate insns. */
  
  void
  ix86_expand_prologue ()
  {
    int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
  				  || current_function_uses_const_pool);
    HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), (int *)0);
*************** ix86_expand_prologue ()
*** 1664,1678 ****
  			     CALL_INSN_FUNCTION_USAGE (insn));
      }
  
!   limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
!   for (regno = limit - 1; regno >= 0; regno--)
!     if ((regs_ever_live[regno] && ! call_used_regs[regno])
! 	|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
!       {
! 	insn = emit_insn (gen_push (gen_rtx_REG (SImode, regno)));
! 	RTX_FRAME_RELATED_P (insn) = 1;
!       }
! 
  #ifdef SUBTARGET_PROLOGUE
    SUBTARGET_PROLOGUE;
  #endif  
--- 1732,1738 ----
  			     CALL_INSN_FUNCTION_USAGE (insn));
      }
  
!   ix86_emit_save_regs ();
  #ifdef SUBTARGET_PROLOGUE
    SUBTARGET_PROLOGUE;
  #endif  
*************** ix86_expand_prologue ()
*** 1687,1700 ****
      emit_insn (gen_blockage ());
  }
  
  /* Restore function stack, frame, and registers. */
  
  void
  ix86_expand_epilogue ()
  {
!   register int regno;
!   register int limit;
    int nregs;
    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;
--- 1747,1826 ----
      emit_insn (gen_blockage ());
  }
  
+ /* Emit code to pop all registers from stack.  */
+ 
+ static void
+ ix86_emit_restore_regs ()
+ {
+   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
+ 				  || current_function_uses_const_pool);
+   int limit = (frame_pointer_needed
+ 	       ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
+   int regno;
+ 
+   for (regno = 0; regno < limit; regno++)
+     if ((regs_ever_live[regno] && !call_used_regs[regno])
+ 	|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
+       {
+ 	emit_insn (gen_popsi1 (gen_rtx_REG (SImode, regno)));
+       }
+ }
+ 
+ /* Emit code substract TSIZE from esp value.  Use PUSH instruction when
+    profitable.  */
+ 
+ static void
+ ix86_emit_esp_adjustment (tsize)
+      int tsize;
+ {
+   /* Intel's docs say that for 4 or 8 bytes of stack frame one should
+      use `pop' and not `add'.  */
+   int use_pop = tsize == 4;
+   rtx edx = 0, ecx;
+ 
+   /* Use two pops only for the Pentium processors.  */
+   if (tsize == 8 && !TARGET_386 && !TARGET_486)
+     {
+       rtx retval = current_function_return_rtx;
+ 
+       edx = gen_rtx_REG (SImode, 1);
+ 
+       /* This case is a bit more complex.  Since we cannot pop into
+          %ecx twice we need a second register.  But this is only
+          available if the return value is not of DImode in which
+          case the %edx register is not available.  */
+       use_pop = (retval == NULL
+ 		 || !reg_overlap_mentioned_p (edx, retval));
+     }
+ 
+   if (use_pop)
+     {
+       ecx = gen_rtx_REG (SImode, 2);
+ 
+       /* We have to prevent the two pops here from being scheduled.
+          GCC otherwise would try in some situation to put other
+          instructions in between them which has a bad effect.  */
+       emit_insn (gen_blockage ());
+       emit_insn (gen_popsi1 (ecx));
+       if (tsize == 8)
+ 	emit_insn (gen_popsi1 (edx));
+     }
+   else
+     {
+       /* If there is no frame pointer, we must still release the frame. */
+       emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ 			     GEN_INT (tsize)));
+     }
+ }
+ 
  /* Restore function stack, frame, and registers. */
  
  void
  ix86_expand_epilogue ()
  {
!   int regno;
    int nregs;
+   int limit;
    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;
*************** ix86_expand_epilogue ()
*** 1710,1718 ****
       less work than reloading sp and popping the register.  Otherwise,
       restore sp (if necessary) and pop the registers. */
  
-   limit = (frame_pointer_needed
- 	   ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
- 
    if (nregs > 1 || sp_valid)
      {
        if ( !sp_valid )
--- 1836,1841 ----
*************** ix86_expand_epilogue ()
*** 1724,1738 ****
  	  emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, addr_offset));
  	}
  
!       for (regno = 0; regno < limit; regno++)
! 	if ((regs_ever_live[regno] && ! call_used_regs[regno])
! 	    || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
! 	  {
! 	    emit_insn (gen_popsi1 (gen_rtx_REG (SImode, regno)));
! 	  }
      }
    else
      {
        for (regno = 0; regno < limit; regno++)
  	if ((regs_ever_live[regno] && ! call_used_regs[regno])
  	    || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
--- 1847,1858 ----
  	  emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx, addr_offset));
  	}
  
!       ix86_emit_restore_regs ();
      }
    else
      {
+       limit = (frame_pointer_needed
+ 	       ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
        for (regno = 0; regno < limit; regno++)
  	if ((regs_ever_live[regno] && ! call_used_regs[regno])
  	    || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
*************** ix86_expand_epilogue ()
*** 1756,1801 ****
  	}
      }
    else if (tsize)
!     {
!       /* Intel's docs say that for 4 or 8 bytes of stack frame one should
! 	 use `pop' and not `add'.  */
!       int use_pop = tsize == 4;
!       rtx edx = 0, ecx;
! 
!       /* Use two pops only for the Pentium processors.  */
!       if (tsize == 8 && !TARGET_386 && !TARGET_486)
! 	{
! 	  rtx retval = current_function_return_rtx;
! 
! 	  edx = gen_rtx_REG (SImode, 1);
! 
! 	  /* This case is a bit more complex.  Since we cannot pop into
! 	     %ecx twice we need a second register.  But this is only
! 	     available if the return value is not of DImode in which
! 	     case the %edx register is not available.  */
! 	  use_pop = (retval == NULL
! 		     || ! reg_overlap_mentioned_p (edx, retval));
! 	}
! 
!       if (use_pop)
! 	{
! 	  ecx = gen_rtx_REG (SImode, 2);
! 
! 	  /* We have to prevent the two pops here from being scheduled.
! 	     GCC otherwise would try in some situation to put other
! 	     instructions in between them which has a bad effect.  */
! 	  emit_insn (gen_blockage ());
! 	  emit_insn (gen_popsi1 (ecx));
! 	  if (tsize == 8)
! 	    emit_insn (gen_popsi1 (edx));
! 	}
!       else
! 	{
! 	  /* If there is no frame pointer, we must still release the frame. */
! 	  emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
! 				 GEN_INT (tsize)));
! 	}
!     }
  
  #ifdef FUNCTION_BLOCK_PROFILER_EXIT
    if (profile_block_flag == 2)
--- 1876,1882 ----
  	}
      }
    else if (tsize)
!     ix86_emit_esp_adjustment (tsize);
  
  #ifdef FUNCTION_BLOCK_PROFILER_EXIT
    if (profile_block_flag == 2)
diff -Nrc3p i386.new1/i386.h i386/i386.h
*** i386.new1/i386.h	Wed Jan 19 00:05:50 2000
--- i386/i386.h	Wed Jan 19 12:11:31 2000
*************** do {								\
*** 1419,1448 ****
     its replacement, at the start of a routine.  */
  
  #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)			\
! {									\
!   if ((FROM) == ARG_POINTER_REGNUM && (TO) == FRAME_POINTER_REGNUM)	\
!     (OFFSET) = 8;	/* Skip saved PC and previous frame pointer */	\
!   else									\
!     {									\
!       int nregs;							\
!       int offset;							\
!       int preferred_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT; \
!       HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (),	\
! 						     &nregs);		\
! 									\
!       (OFFSET) = (tsize + nregs * UNITS_PER_WORD);			\
! 									\
!       offset = 4;							\
!       if (frame_pointer_needed)						\
! 	offset += UNITS_PER_WORD;					\
! 									\
!       if ((FROM) == ARG_POINTER_REGNUM)					\
! 	(OFFSET) += offset;						\
!       else								\
! 	(OFFSET) -= ((offset + preferred_alignment - 1)			\
! 		     & -preferred_alignment) - offset;			\
!     }									\
! }
  
  /* Addressing modes, and classification of registers for them.  */
  
--- 1419,1425 ----
     its replacement, at the start of a routine.  */
  
  #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)			\
!   (OFFSET) = ix86_initial_elimination_offset (FROM, TO)
  
  /* Addressing modes, and classification of registers for them.  */
  

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