* 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
+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.
#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
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;
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. */
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));
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;
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);
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. */
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])
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)
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)));
CALL_INSN_FUNCTION_USAGE (insn));
}
- ix86_emit_save_regs ();
+ if (!SAVED_REGS_FIRST)
+ ix86_emit_save_regs ();
+
#ifdef SUBTARGET_PROLOGUE
SUBTARGET_PROLOGUE;
#endif
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++)
|| 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);
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))
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
/* 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;
}
/* 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.
/* Check that the unspec is one of the ones we generate? */
}
else if (GET_CODE (addr) != PLUS)
- abort();
+ abort ();
}
if (GET_CODE (addr) == PLUS)
{
FILE *file;
{
if (REGNO (x) == ARG_POINTER_REGNUM
+ || REGNO (x) == FRAME_POINTER_REGNUM
|| REGNO (x) == FLAGS_REG
|| REGNO (x) == FPSR_REG)
abort ();
case 8: size = "QWORD"; break;
case 12: size = "XWORD"; break;
default:
- abort();
+ abort ();
}
fputs (size, file);
fputs (" PTR ", file);
hi_half[num] = change_address (op, SImode, hi_addr);
}
else
- abort();
+ abort ();
}
}
\f
/* 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;
}
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. */
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
#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
#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
#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
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) */
{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:
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.
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
#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)
#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) \
#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
{ 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)) \