OSDN Git Service

* i386.c (ix86_emit_restore_regs_using_mov): Break out from ...
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 12 Feb 2000 00:49:11 +0000 (00:49 +0000)
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 12 Feb 2000 00:49:11 +0000 (00:49 +0000)
(ix86_expand_epilogue): ... here. Use mov instead of add to restore
stack pointer in functions w/o saved registers, output LEAVE more often
on TARGET_USE_LEAVE machines.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@31941 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/i386/i386.c

index 8799dba..e7698d5 100644 (file)
@@ -1,3 +1,10 @@
+Sat Feb 12 01:44:26 MET 2000  Jan Hubicka  <jh@suse.cz>
+
+       * i386.c (ix86_emit_restore_regs_using_mov): Break out from ...
+       (ix86_expand_epilogue): ... here. Use mov instead of add to restore
+       stack pointer in functions w/o saved registers, output LEAVE more often
+       on TARGET_USE_LEAVE machines.
+
 2000-02-07  Dmitri Makarov  <dim@wrs.com> & Bernd Schmidt <bernds@redhat.com>
 
        * config/arm/arm.c (arm_init_cumulative_args); New function:
index 730594a..18128b7 100644 (file)
@@ -401,6 +401,7 @@ static HOST_WIDE_INT ix86_compute_frame_size PARAMS((HOST_WIDE_INT,
                                                     int *, int *, int *));
 static int ix86_nsaved_regs PARAMS((void));
 static void ix86_emit_save_regs PARAMS((void));
+static void ix86_emit_restore_regs_using_mov PARAMS ((rtx, int));
 static void ix86_emit_epilogue_esp_adjustment PARAMS((int));
 static void ix86_sched_reorder_pentium PARAMS((rtx *, rtx *));
 static void ix86_sched_reorder_ppro PARAMS((rtx *, rtx *));
@@ -1963,6 +1964,31 @@ ix86_emit_epilogue_esp_adjustment (tsize)
     }
 }
 
+/* Emit code to restore saved registers using MOV insns.  First register
+   is restored from POINTER + OFFSET.  */
+static void
+ix86_emit_restore_regs_using_mov (pointer, offset)
+       rtx pointer;
+       int offset;
+{
+  int regno;
+  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);
+
+  for (regno = 0; regno < limit; regno++)
+    if ((regs_ever_live[regno] && !call_used_regs[regno])
+       || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
+      {
+       emit_move_insn (gen_rtx_REG (SImode, regno),
+                       adj_offsettable_operand (gen_rtx_MEM (SImode,
+                                                             pointer),
+                                                offset));
+       offset += 4;
+      }
+}
+
 /* Restore function stack, frame, and registers. */
 
 void
@@ -1991,23 +2017,34 @@ ix86_expand_epilogue ()
 
   /* 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.  */
-  if (!sp_valid && nregs <= 1)
-    {
-      if (!frame_pointer_needed)
-       abort();
-
-      for (regno = 0; regno < HARD_FRAME_POINTER_REGNUM; regno++)
-       if ((regs_ever_live[regno] && ! call_used_regs[regno])
-           || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
-         {
-           emit_move_insn (gen_rtx_REG (SImode, regno),
-                           adj_offsettable_operand (AT_BP (Pmode), offset));
-           offset += 4;
-         }
+     less work than reloading sp and popping the register.  
+
+     The default code result in stack adjustment using add/lea instruction,
+     while this code results in LEAVE instruction (or discrete equivalent),
+     so it is profitable in some other cases as well.  Especially when there
+     are no registers to restore.  We also use this code when TARGET_USE_LEAVE
+     and there is exactly one register to pop. This heruistic may need some
+     tuning in future.  */
+  if ((!sp_valid && nregs <= 1)
+      || (frame_pointer_needed && !nregs && tsize)
+      || (frame_pointer_needed && TARGET_USE_LEAVE && !optimize_size
+         && nregs == 1))
+    {
+      /* Restore registers.  We can use ebp or esp to address the memory
+        locations.  If both are available, default to ebp, since offsets
+        are known to be small.  Only exception is esp pointing directly to the
+        end of block of saved registers, where we may simplify addressing
+        mode.  */
+
+      if (!frame_pointer_needed || (sp_valid && !tsize))
+       ix86_emit_restore_regs_using_mov (stack_pointer_rtx, tsize);
+      else
+       ix86_emit_restore_regs_using_mov (hard_frame_pointer_rtx, offset);
 
+      if (!frame_pointer_needed)
+       ix86_emit_epilogue_esp_adjustment (tsize + nregs * UNITS_PER_WORD);
       /* If not an i386, mov & pop is faster than "leave". */
-      if (TARGET_USE_LEAVE || optimize_size)
+      else if (TARGET_USE_LEAVE || optimize_size)
        emit_insn (gen_leave ());
       else
        {