diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 40053440e88..5b4d3ea42d9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,37 @@ +Mon Jan 24 17:37:31 MET 2000 Jan Hubicka + + * 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 * i386.h (PREDICATE_CODES): Add aligned_operand. diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 320237e8a7a..2ea0fb7e99e 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -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; } diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 74cd5d69399..0dddfafe222 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -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)) \