i386.h (FIRST_PSEUDO_REGISTER): Set to 21.
authorJan Hubicka <jh@suse.cz>
Mon, 24 Jan 2000 16:39:07 +0000 (17:39 +0100)
committerJan Hubicka <hubicka@gcc.gnu.org>
Mon, 24 Jan 2000 16:39:07 +0000 (16:39 +0000)
* i386.h (FIRST_PSEUDO_REGISTER): Set to 21.
(FIXED_REGISTERS, CALL_USED_REGISTERS,
 REG_ALLOC_ORDER): Add frame pointer
(FRAME_POINTER_REGNUM): Set to 20
(HARD_FRAME_POINTER_REGNUM): New macro.
(ELIMINABLE_REGS): Eliminate ARG_POINTER and FRAME_POINTER
to HARD_FRAME_POINTER.
(REGNO_OK_FOR_BASE_P): Accept FRAME_POINTER_REGNUM
(REG_OK_FOR_INDEX_NONSTRICT_P): Likewise.
(REG_OK_FOR_BASE_NONSTRICT_P): Likewise.
(HI_REGISTER_NAMES): Add "frame".
(CAN_ELIMINATE): Handle FRAME_POINTER_REGNUM elimination.
(debug_reg): Handle FRAME_POINTER_REGNUM.
(reg_class): Add arg pointer and frame pointer to NON_Q_REGS,
GENERAL_REGS and INDEX_REGS.
* i386.c (SAVED_REGS_FIRST): new macro.
(AT_BP): Use hard_frame_pointer_rtx instead of frame_pointer_rtx
(ix86_decompose_address, memory_address_length): Likewise.
(regclass_map): Add frame pointer.
(call_insn_operand): Handle frame_pointer_rtx.
(reg_no_sp_operand): Likewise.
(ix86_decompose_address): Handle frame_pointer_rtx as stack_pointer_rtx.
(print_operand, legitimize_pic_address): Fix formating.
(ix86_compute_frame_size): Make static, update prototype, new
parameters padding1, padding2, use ix86_nsaved_regs, use
stack_alignment_needed.
(ix86_initial_elimination_offset): Handle FRAME_POINTER_REGNUM
to HARD_FRAME_POINTER_REGNUM conversions.
(ix86_expand_prologue): Handle SAVED_REGS_FIRST prologues.
(ix86_expand_epilogue): Handle SAVED_REGS_FIRST epilogues.
(print_reg): Abort on FRAME_POINTER_REGNUM

From-SVN: r31587

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

index 4005344..5b4d3ea 100644 (file)
@@ -1,3 +1,37 @@
+Mon Jan 24 17:37:31 MET 2000  Jan Hubicka  <jh@suse.cz>
+
+       * i386.h (FIRST_PSEUDO_REGISTER): Set to 21.
+       (FIXED_REGISTERS, CALL_USED_REGISTERS,
+        REG_ALLOC_ORDER): Add frame pointer
+       (FRAME_POINTER_REGNUM): Set to 20
+       (HARD_FRAME_POINTER_REGNUM): New macro.
+       (ELIMINABLE_REGS): Eliminate ARG_POINTER and FRAME_POINTER
+       to HARD_FRAME_POINTER.
+       (REGNO_OK_FOR_BASE_P): Accept FRAME_POINTER_REGNUM
+       (REG_OK_FOR_INDEX_NONSTRICT_P): Likewise.
+       (REG_OK_FOR_BASE_NONSTRICT_P): Likewise.
+       (HI_REGISTER_NAMES): Add "frame".
+       (CAN_ELIMINATE): Handle FRAME_POINTER_REGNUM elimination.
+       (debug_reg): Handle FRAME_POINTER_REGNUM.
+       (reg_class): Add arg pointer and frame pointer to NON_Q_REGS,
+       GENERAL_REGS and INDEX_REGS.
+       * i386.c (SAVED_REGS_FIRST): new macro.
+       (AT_BP): Use hard_frame_pointer_rtx instead of frame_pointer_rtx
+       (ix86_decompose_address, memory_address_length): Likewise.
+       (regclass_map): Add frame pointer.
+       (call_insn_operand): Handle frame_pointer_rtx.
+       (reg_no_sp_operand): Likewise.
+       (ix86_decompose_address): Handle frame_pointer_rtx as stack_pointer_rtx.
+       (print_operand, legitimize_pic_address): Fix formating.
+       (ix86_compute_frame_size): Make static, update prototype, new
+       parameters padding1, padding2, use ix86_nsaved_regs, use
+       stack_alignment_needed.
+       (ix86_initial_elimination_offset): Handle FRAME_POINTER_REGNUM
+       to HARD_FRAME_POINTER_REGNUM conversions.
+       (ix86_expand_prologue): Handle SAVED_REGS_FIRST prologues.
+       (ix86_expand_epilogue): Handle SAVED_REGS_FIRST epilogues.
+       (print_reg): Abort on FRAME_POINTER_REGNUM
+
 Mon Jan 24 16:50:08 MET 2000  Jan Hubicka  <jh@suse.cz>
 
        * i386.h (PREDICATE_CODES): Add aligned_operand.
index 320237e..2ea0fb7 100644 (file)
@@ -41,6 +41,16 @@ Boston, MA 02111-1307, USA. */
 #include "basic-block.h"
 #include "ggc.h"
 
+/* True when we want to do pushes before allocating stack to get better
+   scheduling.
+
+   Saving registers first is win in the most cases except for LEAVE
+   instruction.  Macro is 0 iff we will use LEAVE.  */
+
+#define SAVED_REGS_FIRST \
+  (!frame_pointer_needed || (!TARGET_USE_LEAVE && !optimize_size))
+
+
 #ifdef EXTRA_CONSTRAINT
 /* If EXTRA_CONSTRAINT is defined, then the 'S'
    constraint in REG_CLASS_FROM_LETTER will no longer work, and various
@@ -214,7 +224,7 @@ const int x86_split_long_moves = m_PPRO;
 const int x86_promote_QImode = m_K6 | m_PENT | m_386 | m_486;
 const int x86_single_stringop = m_386;
 
-#define AT_BP(mode) (gen_rtx_MEM ((mode), frame_pointer_rtx))
+#define AT_BP(mode) (gen_rtx_MEM ((mode), hard_frame_pointer_rtx))
 
 const char * const hi_reg_name[] = HI_REGISTER_NAMES;
 const char * const qi_reg_name[] = QI_REGISTER_NAMES;
@@ -234,8 +244,8 @@ enum reg_class const regclass_map[FIRST_PSEUDO_REGISTER] =
   FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
   /* arg pointer */
   NON_Q_REGS,
-  /* flags, fpsr, dirflag */
-  NO_REGS, NO_REGS, NO_REGS
+  /* flags, fpsr, dirflag, frame */
+  NO_REGS, NO_REGS, NO_REGS, NON_Q_REGS
 };
 
 /* The "default" register map.  */
@@ -397,7 +407,8 @@ static void ix86_init_machine_status PARAMS ((struct function *));
 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 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 PARAMS((void));
@@ -1051,6 +1062,7 @@ call_insn_operand (op, mode)
      compiler aborts when trying to eliminate them.  */
   if (GET_CODE (op) == REG
       && (op == arg_pointer_rtx
+         || op == frame_pointer_rtx
          || (REGNO (op) >= FIRST_PSEUDO_REGISTER
              && REGNO (op) <= LAST_VIRTUAL_REGISTER)))
     return 0;
@@ -1150,7 +1162,7 @@ reg_no_sp_operand (op, mode)
   rtx t = op;
   if (GET_CODE (t) == SUBREG)
     t = SUBREG_REG (t);
-  if (t == stack_pointer_rtx || t == arg_pointer_rtx)
+  if (t == stack_pointer_rtx || t == arg_pointer_rtx || t == frame_pointer_rtx)
     return 0;
 
   return register_operand (op, mode);
@@ -1644,91 +1656,133 @@ 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 */
+  int padding1;
+  int nregs;
+
+  /* Stack grows downward:
+    
+     [arguments]
+                                               <- ARG_POINTER
+     saved pc
+
+     saved frame pointer if frame_pointer_needed
+                                               <- HARD_FRAME_POINTER
+     [saved regs if SAVED_REGS_FIRST]
+
+     [padding1]   \
+                  |                            <- FRAME_POINTER
+     [frame]      > tsize
+                  |
+     [padding2]   /
+
+     [saved regs if !SAVED_REGS_FIRST]
+                                               <- STACK_POINTER
+    */
+
+  if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
+    /* Skip saved PC and previous frame pointer.
+       Executed only when frame_pointer_needed.  */
+    return 8;
+  else if (from == FRAME_POINTER_REGNUM
+          && to == HARD_FRAME_POINTER_REGNUM)
+    {
+      ix86_compute_frame_size (get_frame_size (), &nregs, &padding1, (int *)0);
+      if (SAVED_REGS_FIRST)
+       padding1 += nregs * UNITS_PER_WORD;
+      return -padding1;
+    }
   else
     {
-      int nregs;
-      int poffset;
-      int offset;
-      int preferred_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
+      /* ARG_POINTER or FRAME_POINTER to STACK_POINTER elimination.  */
+      int frame_size = frame_pointer_needed ? 8 : 4;
       HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (),
-                                                    &nregs);
-
-      offset = (tsize + nregs * UNITS_PER_WORD);
+                                                    &nregs, &padding1, (int *)0);
 
-      poffset = 4;
-      if (frame_pointer_needed)
-       poffset += UNITS_PER_WORD;
 
-      if (from == ARG_POINTER_REGNUM)
-       offset += poffset;
+      if (to != STACK_POINTER_REGNUM)
+       abort ();
+      else if (from == ARG_POINTER_REGNUM)
+       return tsize + nregs * UNITS_PER_WORD + frame_size;
+      else if (from != FRAME_POINTER_REGNUM)
+       abort ();
+      else if (SAVED_REGS_FIRST)
+       return tsize - padding1;
       else
-       offset -= ((poffset + preferred_alignment - 1)
-                  & -preferred_alignment) - poffset;
-      return offset;
+       return tsize + nregs * UNITS_PER_WORD - padding1;
     }
 }
 
 /* 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.  */
-
-HOST_WIDE_INT
-ix86_compute_frame_size (size, nregs_on_stack)
+   the number of registers saved below the local storage.  
+   PADDING1 returns padding before stack frame and PADDING2 returns
+   padding after stack frame;
+ */
+
+static HOST_WIDE_INT
+ix86_compute_frame_size (size, nregs_on_stack, rpadding1, rpadding2)
      HOST_WIDE_INT size;
      int *nregs_on_stack;
+     int *rpadding1;
+     int *rpadding2;
 {
-  int limit;
   int nregs;
-  int regno;
-  int padding;
-  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
-                                 || current_function_uses_const_pool);
+  int padding1 = 0;
+  int padding2 = 0;
   HOST_WIDE_INT total_size;
+  int stack_alignment_needed = cfun->stack_alignment_needed / BITS_PER_UNIT;
 
-  limit = frame_pointer_needed
-         ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM;
+  nregs = ix86_nsaved_regs ();
 
-  nregs = 0;
-
-  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++;
-
-  padding = 0;
-  total_size = size + (nregs * UNITS_PER_WORD);
+  total_size = size;
 
 #ifdef PREFERRED_STACK_BOUNDARY
   {
     int offset;
     int preferred_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
 
-    offset = 4;
-    if (frame_pointer_needed)
-      offset += UNITS_PER_WORD;
+    offset = frame_pointer_needed ? 8 : 4;
+
+    /* When frame is not empty we ought to have recorded the alignment.  */
+    if (size && !stack_alignment_needed)
+      abort ();
+
+    if (stack_alignment_needed < 4)
+      stack_alignment_needed = 4;
+
+    if (stack_alignment_needed > preferred_alignment)
+      abort ();
+
+    if (SAVED_REGS_FIRST)
+      offset += nregs * UNITS_PER_WORD;
+    else
+      total_size += nregs * UNITS_PER_WORD;
 
     total_size += offset;
-    
-    padding = ((total_size + preferred_alignment - 1)
-              & -preferred_alignment) - total_size;
 
-    if (padding < (((offset + preferred_alignment - 1)
-                   & -preferred_alignment) - offset))
-      padding += preferred_alignment;
+    /* Align start of frame for local function.  */
+    padding1 = ((offset + stack_alignment_needed - 1)
+               & -stack_alignment_needed) - offset;
+    total_size += padding1;
 
-    /* Don't bother aligning the stack of a leaf function
-       which doesn't allocate any stack slots.  */
-    if (size == 0 && current_function_is_leaf)
-      padding = 0;
+    /* Align stack boundary. */
+    if (!current_function_is_leaf)
+      padding2 = ((total_size + preferred_alignment - 1)
+                 & -preferred_alignment) - total_size;
   }
 #endif
 
   if (nregs_on_stack)
     *nregs_on_stack = nregs;
 
-  return size + padding;
+  if (rpadding1)
+    *rpadding1 = padding1;
+
+  if (rpadding2)
+    *rpadding2 = padding2;
+
+  return size + padding1 + padding2;
 }
 
 /* Emit code to save registers in the prologue.  */
@@ -1742,7 +1796,7 @@ ix86_emit_save_regs ()
   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);
+          ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
 
   for (regno = limit - 1; regno >= 0; regno--)
     if ((regs_ever_live[regno] && !call_used_regs[regno])
@@ -1758,23 +1812,27 @@ ix86_emit_save_regs ()
 void
 ix86_expand_prologue ()
 {
+  HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), (int *)0, (int *)0,
+                                                (int *)0);
+  rtx insn;
   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);
-  rtx insn;
 
   /* Note: AT&T enter does NOT have reversed args.  Enter is probably
      slower on all targets.  Also sdb doesn't like it.  */
 
   if (frame_pointer_needed)
     {
-      insn = emit_insn (gen_push (frame_pointer_rtx));
+      insn = emit_insn (gen_push (hard_frame_pointer_rtx));
       RTX_FRAME_RELATED_P (insn) = 1;
 
-      insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+      insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
+  if (SAVED_REGS_FIRST)
+    ix86_emit_save_regs ();
+
   if (tsize == 0)
     ;
   else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT)
@@ -1783,7 +1841,7 @@ ix86_expand_prologue ()
        insn = emit_insn (gen_prologue_allocate_stack (stack_pointer_rtx,
                                                       stack_pointer_rtx,
                                                       GEN_INT (-tsize),
-                                                      frame_pointer_rtx));
+                                                      hard_frame_pointer_rtx));
       else
         insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
                                      GEN_INT (-tsize)));
@@ -1807,7 +1865,9 @@ ix86_expand_prologue ()
                             CALL_INSN_FUNCTION_USAGE (insn));
     }
 
-  ix86_emit_save_regs ();
+  if (!SAVED_REGS_FIRST)
+    ix86_emit_save_regs ();
+
 #ifdef SUBTARGET_PROLOGUE
   SUBTARGET_PROLOGUE;
 #endif  
@@ -1830,7 +1890,7 @@ 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);
+              ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
   int regno;
 
   for (regno = 0; regno < limit; regno++)
@@ -1900,20 +1960,38 @@ ix86_expand_epilogue ()
                                  || current_function_uses_const_pool);
   int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging;
   HOST_WIDE_INT offset;
-  HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), &nregs);
+  HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), &nregs, (int *)0,
+                                                (int *)0);
 
   /* SP is often unreliable so we may have to go off the frame pointer. */
 
   offset = -(tsize + nregs * UNITS_PER_WORD);
 
+  if (SAVED_REGS_FIRST)
+    {
+      if (!sp_valid)
+        {
+         if (nregs)
+           emit_insn (gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                                   gen_rtx_PLUS (SImode, hard_frame_pointer_rtx,
+                                                 GEN_INT (- nregs * UNITS_PER_WORD))));
+         else
+           emit_insn (gen_epilogue_deallocate_stack (stack_pointer_rtx,
+                                                  hard_frame_pointer_rtx));
+       }
+      else if (tsize)
+       ix86_emit_epilogue_esp_adjustment (tsize);
+      ix86_emit_restore_regs ();
+    }
+
   /* 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)
+  else if (nregs > 1 || sp_valid)
     {
-      if ( !sp_valid )
+      if (!sp_valid)
        {
          rtx addr_offset;
          addr_offset = adj_offsettable_operand (AT_BP (QImode), offset);
@@ -1927,7 +2005,7 @@ ix86_expand_epilogue ()
   else
     {
       limit = (frame_pointer_needed
-              ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
+              ? 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))
@@ -1941,16 +2019,17 @@ ix86_expand_epilogue ()
   if (frame_pointer_needed)
     {
       /* If not an i386, mov & pop is faster than "leave". */
-      if (TARGET_USE_LEAVE)
-       emit_insn (gen_leave());
+      if (TARGET_USE_LEAVE || optimize_size)
+       emit_insn (gen_leave ());
       else
        {
-         emit_insn (gen_epilogue_deallocate_stack (stack_pointer_rtx,
-                                                   frame_pointer_rtx));
-         emit_insn (gen_popsi1 (frame_pointer_rtx));
+         if (!SAVED_REGS_FIRST)
+           emit_insn (gen_epilogue_deallocate_stack (stack_pointer_rtx,
+                                                  hard_frame_pointer_rtx));
+         emit_insn (gen_popsi1 (hard_frame_pointer_rtx));
        }
     }
-  else if (tsize)
+  else if (!SAVED_REGS_FIRST && tsize)
     ix86_emit_epilogue_esp_adjustment (tsize);
 
 #ifdef FUNCTION_BLOCK_PROFILER_EXIT
@@ -2071,7 +2150,8 @@ ix86_decompose_address (addr, out)
 
   /* Allow arg pointer and stack pointer as index if there is not scaling */
   if (base && index && scale == 1
-      && (index == arg_pointer_rtx || index == stack_pointer_rtx))
+      && (index == arg_pointer_rtx || index == frame_pointer_rtx
+          || index == stack_pointer_rtx))
     {
       rtx tmp = base;
       base = index;
@@ -2079,7 +2159,9 @@ ix86_decompose_address (addr, out)
     }
 
   /* Special case: %ebp cannot be encoded as a base without a displacement.  */
-  if (base == frame_pointer_rtx && !disp)
+  if ((base == hard_frame_pointer_rtx
+       || base == frame_pointer_rtx
+       || base == arg_pointer_rtx) && !disp)
     disp = const0_rtx;
 
   /* Special case: on K6, [%esi] makes the instruction vector decoded.
@@ -2388,7 +2470,7 @@ legitimize_pic_address (orig, reg)
              /* Check that the unspec is one of the ones we generate?  */
            }
          else if (GET_CODE (addr) != PLUS)
-           abort();
+           abort ();
        }
       if (GET_CODE (addr) == PLUS)
        {
@@ -2807,6 +2889,7 @@ print_reg (x, code, file)
      FILE *file;
 {
   if (REGNO (x) == ARG_POINTER_REGNUM
+      || REGNO (x) == FRAME_POINTER_REGNUM
       || REGNO (x) == FLAGS_REG
       || REGNO (x) == FPSR_REG)
     abort ();
@@ -3029,7 +3112,7 @@ print_operand (file, x, code)
            case 8: size = "QWORD"; break;
            case 12: size = "XWORD"; break;
            default:
-             abort();
+             abort ();
            }
          fputs (size, file);
          fputs (" PTR ", file);
@@ -3251,7 +3334,7 @@ split_di (operands, num, lo_half, hi_half)
          hi_half[num] = change_address (op, SImode, hi_addr);
        }
       else
-       abort();
+       abort ();
     }
 }
 \f
@@ -5580,7 +5663,8 @@ memory_address_length (addr)
       /* Special cases: ebp and esp need the two-byte modrm form.  */
       if (addr == stack_pointer_rtx
          || addr == arg_pointer_rtx
-         || addr == frame_pointer_rtx)
+         || addr == frame_pointer_rtx
+         || addr == hard_frame_pointer_rtx)
        len = 1;
     }
 
index 74cd5d6..0dddfaf 100644 (file)
@@ -619,7 +619,7 @@ extern int ix86_arch;
    eliminated during reloading in favor of either the stack or frame
    pointer. */
 
-#define FIRST_PSEUDO_REGISTER 20
+#define FIRST_PSEUDO_REGISTER 21
 
 /* Number of hardware registers that go into the DWARF-2 unwind info.
    If not defined, equals FIRST_PSEUDO_REGISTER.  */
@@ -631,7 +631,9 @@ extern int ix86_arch;
    On the 80386, the stack pointer is such, as is the arg pointer. */
 #define FIXED_REGISTERS \
 /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg,flags,fpsr, dir*/ \
-{  0, 0, 0, 0, 0, 0, 0, 1, 0,  0,  0,  0,  0,  0,  0,  0,  1,    0,   0,   0 }
+{  0, 0, 0, 0, 0, 0, 0, 1, 0,  0,  0,  0,  0,  0,  0,  0,  1,    0,   0,   0,  \
+/*frame                                                                            */ \
+   1}
 
 /* 1 for registers not available across function calls.
    These must include the FIXED_REGISTERS and also any
@@ -642,7 +644,9 @@ extern int ix86_arch;
 
 #define CALL_USED_REGISTERS \
 /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg,flags,fpsr, dir*/ \
-{  1, 1, 1, 0, 0, 0, 0, 1, 1,  1,  1,  1,  1,  1,  1,  1,  1,    1,   1,   1 }
+{  1, 1, 1, 0, 0, 0, 0, 1, 1,  1,  1,  1,  1,  1,  1,  1,  1,    1,   1,   1,  \
+/*frame                                                                            */ \
+   1}
 
 /* Order in which to allocate registers.  Each register must be
    listed once, even those in FIXED_REGISTERS.  List frame pointer
@@ -665,7 +669,9 @@ extern int ix86_arch;
 
 #define REG_ALLOC_ORDER \
 /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7,arg,cc,fpsr, dir*/ \
-{  0, 1, 2, 3, 4, 5, 6, 7, 8,  9, 10, 11, 12, 13, 14, 15, 16,17,  18,  19 }
+{  0, 1, 2, 3, 4, 5, 6, 7, 8,  9, 10, 11, 12, 13, 14, 15, 16,17,  18,  19,  \
+/*frame                                                                         */ \
+  20}
 
 /* A C statement (sans semicolon) to choose the order in which to
    allocate hard registers for pseudo-registers local to a basic
@@ -762,7 +768,10 @@ extern int ix86_arch;
 #define STACK_POINTER_REGNUM 7
 
 /* Base register for access to local variables of the function.  */
-#define FRAME_POINTER_REGNUM 6
+#define HARD_FRAME_POINTER_REGNUM 6
+
+/* Base register for access to local variables of the function.  */
+#define FRAME_POINTER_REGNUM 20
 
 /* First floating point reg */
 #define FIRST_FLOAT_REG 8
@@ -853,7 +862,7 @@ enum reg_class
   AREG, DREG, CREG, BREG, SIREG, DIREG,
   AD_REGS,                     /* %eax/%edx for DImode */
   Q_REGS,                      /* %eax %ebx %ecx %edx */
-  NON_Q_REGS,                  /* %esi %edi %ebp %esi */
+  NON_Q_REGS,                  /* %esi %edi %ebp %esp */
   INDEX_REGS,                  /* %eax %ebx %ecx %edx %esi %edi %ebp */
   GENERAL_REGS,                        /* %eax %ebx %ecx %edx %esi %edi %ebp %esp */
   FP_TOP_REG, FP_SECOND_REG,   /* %st(0) %st(1) */
@@ -893,13 +902,13 @@ enum reg_class
     {0x10},   {0x20},          /* SIREG, DIREG */              \
      {0x3},                    /* AD_REGS */                   \
      {0xf},                    /* Q_REGS */                    \
-    {0xf0},                    /* NON_Q_REGS */                \
+{0x1100f0},                    /* NON_Q_REGS */                \
     {0x7f},                    /* INDEX_REGS */                \
- {0x100ff},                    /* GENERAL_REGS */              \
+{0x1100ff},                    /* GENERAL_REGS */              \
   {0x0100}, {0x0200},          /* FP_TOP_REG, FP_SECOND_REG */ \
   {0xff00},                    /* FLOAT_REGS */                \
-  {0x1ffff},                   /* FLOAT_INT_REGS */            \
- {0x7ffff}                                                     \
+{0x11ffff},                    /* FLOAT_INT_REGS */            \
+{0x17ffff}                                                     \
 }
 
 /* The same information, inverted:
@@ -1392,15 +1401,16 @@ do {                                                            \
    followed by "to".  Eliminations of the same "from" register are listed
    in order of preference.
 
-   We have two registers that can be eliminated on the i386.  First, the
-   frame pointer register can often be eliminated in favor of the stack
-   pointer register.  Secondly, the argument pointer register can always be
-   eliminated; it is replaced with either the stack or frame pointer. */
+   We have three registers that can be eliminated on the i386.  First, the
+   hard frame pointer register can often be eliminated in favor of the stack
+   pointer register.  Secondly, the argument and frame pointer register can
+   always be eliminated; They are replaced with either the stack or frame pointer. */
 
-#define ELIMINABLE_REGS                                \
-{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},  \
- { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM},   \
- { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
+#define ELIMINABLE_REGS                                        \
+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},          \
+ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM},     \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM},                \
+ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}   \
 
 /* Given FROM and TO register numbers, say whether this elimination is allowed.
    Frame pointer elimination is automatically handled.
@@ -1410,9 +1420,10 @@ do {                                                             \
 
    All other eliminations are valid.  */
 
-#define CAN_ELIMINATE(FROM, TO)                                        \
- ((FROM) == ARG_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM \
-  ? ! frame_pointer_needed                                     \
+#define CAN_ELIMINATE(FROM, TO)                                                \
+ ((((FROM) == ARG_POINTER_REGNUM || (FROM) == FRAME_POINTER_REGNUM)    \
+   && (TO) == STACK_POINTER_REGNUM)                                    \
+  ? ! frame_pointer_needed                                             \
   : 1)
 
 /* Define the offset between two registers, one to be eliminated, and the other
@@ -1444,6 +1455,7 @@ do {                                                              \
 #define REGNO_OK_FOR_BASE_P(REGNO) \
   ((REGNO) <= STACK_POINTER_REGNUM \
    || (REGNO) == ARG_POINTER_REGNUM \
+   || (REGNO) == FRAME_POINTER_REGNUM \
    || (unsigned) reg_renumber[REGNO] <= STACK_POINTER_REGNUM)
 
 #define REGNO_OK_FOR_SIREG_P(REGNO) ((REGNO) == 4 || reg_renumber[REGNO] == 4)
@@ -1471,6 +1483,7 @@ do {                                                              \
 #define REG_OK_FOR_BASE_NONSTRICT_P(X)                                 \
   (REGNO (X) <= STACK_POINTER_REGNUM                                   \
    || REGNO (X) == ARG_POINTER_REGNUM                                  \
+   || REGNO (X) == FRAME_POINTER_REGNUM \
    || REGNO (X) >= FIRST_PSEUDO_REGISTER)
 
 #define REG_OK_FOR_STRREG_NONSTRICT_P(X)                               \
@@ -2153,7 +2166,7 @@ while (0)
 #define HI_REGISTER_NAMES                                              \
 {"ax","dx","cx","bx","si","di","bp","sp",                              \
  "st","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)","",      \
- "flags","fpsr", "dirflag" }
+ "flags","fpsr", "dirflag", "frame" }
 
 #define REGISTER_NAMES HI_REGISTER_NAMES
 
@@ -2365,6 +2378,8 @@ do { long l;                                              \
         { fputs ("fpsr", FILE); break; }               \
        if (REGNO (X) == ARG_POINTER_REGNUM)            \
         { fputs ("argp", FILE); break; }               \
+       if (REGNO (X) == FRAME_POINTER_REGNUM)          \
+        { fputs ("frame", FILE); break; }              \
        if (STACK_TOP_P (X))                            \
         { fputs ("st(0)", FILE); break; }              \
        if (FP_REG_P (X))                               \