i386.h (FIRST_PSEUDO_REGISTER): Set to 21.

* 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
This commit is contained in:
Jan Hubicka 2000-01-24 17:39:07 +01:00 committed by Jan Hubicka
parent 2247f6ed8d
commit 564d80f490
3 changed files with 234 additions and 101 deletions

View 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.

View 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);
&nregs, &padding1, (int *)0);
offset = (tsize + nregs * UNITS_PER_WORD);
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. */
the number of registers saved below the local storage.
PADDING1 returns padding before stack frame and PADDING2 returns
padding after stack frame;
*/
HOST_WIDE_INT
ix86_compute_frame_size (size, nregs_on_stack)
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 ();
}
}
@ -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;
}

View 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)) \