mips.h (GLOBAL_POINTER_REGNUM): New macro.
* config/mips/mips.h (GLOBAL_POINTER_REGNUM): New macro. (PIC_OFFSET_TABLE_REGNUM): Look at pic_offset_table_rtx after reload. (STARTING_FRAME_OFFSET): Don't allocate a cprestore slot for n32/64 PIC. (MUST_SAVE_REGISTERS): Delete. * config/mips/mips.c (mips_frame_info): Remove extra_size field. (machine_function): Add global_pointer field. (mips_classify_constant): Check for (const $gp) using pointer equality with pic_offset_table_rtx. (mips_classify_constant): Handle RELOC_LOADGP_HI and RELOC_LOADGP_LO. (mips_restore_gp): Use current_function_outgoing_args_size. (print_operand): Use PIC_OFFSET_TABLE_REGNUM instead of GP_REG_FIRST + 28. Handle relocation strings that have more than one '('. (mips_reloc_string): Handle RELOC_LOADGP_HI and RELOC_LOADGP_LO. (mips_global_pointer): New function. (mips_save_reg_p): New function, mostly split out from... (compute_frame_size): ...here. Remove handling of extra_size. Reclaim args_size if no variables depend on it. Don't treat gp as a special case: handle it in the main GPR loop. (mips_initial_elimination_offset): Fix comment. (save_restore_insns): Save every register in the GPR mask, removing distinction between mask and real_mask. (mips_output_function_prologue): Update .frame psuedo-op after the removal of extra_size. Move the SVR4 PIC stack allocation and cprestore instructions to mips_expand_prologue. (mips_gp_insn): New function. (mips_expand_prologue): Set REGNO (pic_offset_table_rtx) to the chosen global pointer. Handle SVR4 PIC stack allocation in the same way as other ABIs. Adjust varargs code accordingly. Emit a cprestore insn after allocating the stack. Use mips_gp_insn to emit the loadgp sequence. Follow it with a loadgp_blockage if not using explicit relocs. (mips_output_function_epilogue): Reinstate the default gp register. (mips16_gp_pseudo_reg): Use pic_offset_table_rtx. (mips16_optimize_gp): Likewise. * config/mips/mips.md (UNSPEC_LOADGP): Remove. (UNSPEC_SETJMP, UNSPEC_LONGJMP): Remove. (UNSPEC_CPRESTORE, RELOC_LOADGP_HI, RELOC_LOADGP_LO): New. (loadgp): Remove. (loadgp_blockage, cprestore): New instructions. (builtin_setjmp_setup): Implement using emit_move_insn. Use pic_offset_table_rtx. (builtin_setjmp_setup_32, builtin_setjmp_setup_64): Remove. (builtin_longjmp): Use gen_raw_REG to force use of $28. Co-Authored-By: Alexandre Oliva <aoliva@redhat.com> From-SVN: r67656
This commit is contained in:
parent
32ad6a47f7
commit
f833ffd421
@ -1,3 +1,52 @@
|
||||
2003-06-09 Richard Sandiford <rsandifo@redhat.com>
|
||||
Alexandre Oliva <aoliva@redhat.com>
|
||||
|
||||
* config/mips/mips.h (GLOBAL_POINTER_REGNUM): New macro.
|
||||
(PIC_OFFSET_TABLE_REGNUM): Look at pic_offset_table_rtx after reload.
|
||||
(STARTING_FRAME_OFFSET): Don't allocate a cprestore slot for
|
||||
n32/64 PIC.
|
||||
(MUST_SAVE_REGISTERS): Delete.
|
||||
* config/mips/mips.c (mips_frame_info): Remove extra_size field.
|
||||
(machine_function): Add global_pointer field.
|
||||
(mips_classify_constant): Check for (const $gp) using pointer equality
|
||||
with pic_offset_table_rtx.
|
||||
(mips_classify_constant): Handle RELOC_LOADGP_HI and RELOC_LOADGP_LO.
|
||||
(mips_restore_gp): Use current_function_outgoing_args_size.
|
||||
(print_operand): Use PIC_OFFSET_TABLE_REGNUM instead of
|
||||
GP_REG_FIRST + 28. Handle relocation strings that have
|
||||
more than one '('.
|
||||
(mips_reloc_string): Handle RELOC_LOADGP_HI and RELOC_LOADGP_LO.
|
||||
(mips_global_pointer): New function.
|
||||
(mips_save_reg_p): New function, mostly split out from...
|
||||
(compute_frame_size): ...here. Remove handling of extra_size.
|
||||
Reclaim args_size if no variables depend on it. Don't treat gp
|
||||
as a special case: handle it in the main GPR loop.
|
||||
(mips_initial_elimination_offset): Fix comment.
|
||||
(save_restore_insns): Save every register in the GPR mask,
|
||||
removing distinction between mask and real_mask.
|
||||
(mips_output_function_prologue): Update .frame psuedo-op after
|
||||
the removal of extra_size. Move the SVR4 PIC stack allocation
|
||||
and cprestore instructions to mips_expand_prologue.
|
||||
(mips_gp_insn): New function.
|
||||
(mips_expand_prologue): Set REGNO (pic_offset_table_rtx) to
|
||||
the chosen global pointer. Handle SVR4 PIC stack allocation
|
||||
in the same way as other ABIs. Adjust varargs code accordingly.
|
||||
Emit a cprestore insn after allocating the stack. Use mips_gp_insn
|
||||
to emit the loadgp sequence. Follow it with a loadgp_blockage
|
||||
if not using explicit relocs.
|
||||
(mips_output_function_epilogue): Reinstate the default gp register.
|
||||
(mips16_gp_pseudo_reg): Use pic_offset_table_rtx.
|
||||
(mips16_optimize_gp): Likewise.
|
||||
* config/mips/mips.md (UNSPEC_LOADGP): Remove.
|
||||
(UNSPEC_SETJMP, UNSPEC_LONGJMP): Remove.
|
||||
(UNSPEC_CPRESTORE, RELOC_LOADGP_HI, RELOC_LOADGP_LO): New.
|
||||
(loadgp): Remove.
|
||||
(loadgp_blockage, cprestore): New instructions.
|
||||
(builtin_setjmp_setup): Implement using emit_move_insn. Use
|
||||
pic_offset_table_rtx.
|
||||
(builtin_setjmp_setup_32, builtin_setjmp_setup_64): Remove.
|
||||
(builtin_longjmp): Use gen_raw_REG to force use of $28.
|
||||
|
||||
2003-06-09 Richard Sandiford <rsandifo@redhat.com>
|
||||
|
||||
* config/mips/mips-protos.h (mips_output_division): Declare.
|
||||
|
@ -231,12 +231,15 @@ static void mips_arg_info PARAMS ((const CUMULATIVE_ARGS *,
|
||||
struct mips_arg_info *));
|
||||
static bool mips_get_unaligned_mem PARAMS ((rtx *, unsigned int,
|
||||
int, rtx *, rtx *));
|
||||
static unsigned int mips_global_pointer PARAMS ((void));
|
||||
static bool mips_save_reg_p PARAMS ((unsigned int));
|
||||
static rtx mips_add_large_offset_to_sp PARAMS ((HOST_WIDE_INT));
|
||||
static void mips_set_frame_expr PARAMS ((rtx));
|
||||
static rtx mips_frame_set PARAMS ((rtx, int));
|
||||
static void mips_emit_frame_related_store PARAMS ((rtx, rtx,
|
||||
HOST_WIDE_INT));
|
||||
static void save_restore_insns PARAMS ((int, rtx, long));
|
||||
static void mips_gp_insn PARAMS ((rtx, rtx));
|
||||
static void mips16_fp_args PARAMS ((FILE *, int, int));
|
||||
static void build_mips16_function_stub PARAMS ((FILE *));
|
||||
static void mips16_optimize_gp PARAMS ((rtx));
|
||||
@ -298,7 +301,6 @@ struct mips_frame_info GTY(())
|
||||
long total_size; /* # bytes that the entire frame takes up */
|
||||
long var_size; /* # bytes that variables take up */
|
||||
long args_size; /* # bytes that outgoing arguments take up */
|
||||
long extra_size; /* # bytes of extra gunk */
|
||||
int gp_reg_size; /* # bytes needed to store gp regs */
|
||||
int fp_reg_size; /* # bytes needed to store fp regs */
|
||||
long mask; /* mask of saved gp registers */
|
||||
@ -327,6 +329,9 @@ struct machine_function GTY(()) {
|
||||
|
||||
/* Length of instructions in function; mips16 only. */
|
||||
long insns_len;
|
||||
|
||||
/* The register to use as the global pointer within this function. */
|
||||
unsigned int global_pointer;
|
||||
};
|
||||
|
||||
/* Information about a single argument. */
|
||||
@ -890,7 +895,7 @@ mips_classify_constant (info, x)
|
||||
{
|
||||
x = XEXP (x, 0);
|
||||
|
||||
if (GET_CODE (x) == REG && REGNO (x) == GP_REG_FIRST + 28)
|
||||
if (x == pic_offset_table_rtx)
|
||||
return CONSTANT_GP;
|
||||
|
||||
while (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
|
||||
@ -913,6 +918,8 @@ mips_classify_constant (info, x)
|
||||
case RELOC_CALL16:
|
||||
case RELOC_CALL_HI:
|
||||
case RELOC_CALL_LO:
|
||||
case RELOC_LOADGP_HI:
|
||||
case RELOC_LOADGP_LO:
|
||||
/* These relocations should be applied to bare symbols only. */
|
||||
return (info->offset == 0 ? CONSTANT_RELOC : CONSTANT_NONE);
|
||||
}
|
||||
@ -3033,7 +3040,7 @@ mips_restore_gp (operands)
|
||||
loc = hard_frame_pointer_rtx;
|
||||
else
|
||||
loc = stack_pointer_rtx;
|
||||
loc = plus_constant (loc, cfun->machine->frame.args_size);
|
||||
loc = plus_constant (loc, current_function_outgoing_args_size);
|
||||
operands[1] = gen_rtx_MEM (ptr_mode, loc);
|
||||
|
||||
return mips_output_move (operands[0], operands[1]);
|
||||
@ -5861,7 +5868,7 @@ mips_debugger_offset (addr, offset)
|
||||
'.' Print the name of the register with a hard-wired zero (zero or $0).
|
||||
'^' Print the name of the pic call-through register (t9 or $25).
|
||||
'$' Print the name of the stack pointer register (sp or $29).
|
||||
'+' Print the name of the gp register (gp or $28).
|
||||
'+' Print the name of the gp register (usually gp or $28).
|
||||
'~' Output a branch alignment to LABEL_ALIGN(NULL). */
|
||||
|
||||
void
|
||||
@ -5872,6 +5879,7 @@ print_operand (file, op, letter)
|
||||
{
|
||||
register enum rtx_code code;
|
||||
struct mips_constant_info c;
|
||||
const char *reloc;
|
||||
|
||||
if (PRINT_OPERAND_PUNCT_VALID_P (letter))
|
||||
{
|
||||
@ -5899,7 +5907,7 @@ print_operand (file, op, letter)
|
||||
break;
|
||||
|
||||
case '+':
|
||||
fputs (reg_names[GP_REG_FIRST + 28], file);
|
||||
fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file);
|
||||
break;
|
||||
|
||||
case '&':
|
||||
@ -6159,15 +6167,17 @@ print_operand (file, op, letter)
|
||||
break;
|
||||
|
||||
case CONSTANT_GP:
|
||||
fputs (reg_names[GP_REG_FIRST + 28], file);
|
||||
fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file);
|
||||
break;
|
||||
|
||||
case CONSTANT_RELOC:
|
||||
fputs (mips_reloc_string (XINT (c.symbol, 1)), file);
|
||||
reloc = mips_reloc_string (XINT (c.symbol, 1));
|
||||
fputs (reloc, file);
|
||||
output_addr_const (file, plus_constant (XVECEXP (c.symbol, 0, 0),
|
||||
c.offset));
|
||||
fputc (')', file);
|
||||
break;
|
||||
while (*reloc != 0)
|
||||
if (*reloc++ == '(')
|
||||
fputc (')', file);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6187,6 +6197,8 @@ mips_reloc_string (reloc)
|
||||
case RELOC_CALL16: return "%call16(";
|
||||
case RELOC_CALL_HI: return "%call_hi(";
|
||||
case RELOC_CALL_LO: return "%call_lo(";
|
||||
case RELOC_LOADGP_HI: return "%hi(%neg(%gp_rel(";
|
||||
case RELOC_LOADGP_LO: return "%lo(%neg(%gp_rel(";
|
||||
}
|
||||
abort ();
|
||||
}
|
||||
@ -6615,6 +6627,117 @@ mips_declare_object (stream, name, init_string, final_string, size)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the register that should be used as the global pointer
|
||||
within this function. Return 0 if the function doesn't need
|
||||
a global pointer. */
|
||||
|
||||
static unsigned int
|
||||
mips_global_pointer ()
|
||||
{
|
||||
unsigned int regno;
|
||||
|
||||
/* $gp is always available in non-abicalls code. */
|
||||
if (!TARGET_ABICALLS)
|
||||
return GLOBAL_POINTER_REGNUM;
|
||||
|
||||
/* We must always provide $gp when it is used implicitly. */
|
||||
if (!TARGET_EXPLICIT_RELOCS)
|
||||
return GLOBAL_POINTER_REGNUM;
|
||||
|
||||
/* FUNCTION_PROFILER includes a jal macro, so we need to give it
|
||||
a valid gp. */
|
||||
if (current_function_profile)
|
||||
return GLOBAL_POINTER_REGNUM;
|
||||
|
||||
/* If the gp is never referenced, there's no need to initialize it.
|
||||
Note that reload can sometimes introduce constant pool references
|
||||
into a function that otherwise didn't need them. For example,
|
||||
suppose we have an instruction like:
|
||||
|
||||
(set (reg:DF R1) (float:DF (reg:SI R2)))
|
||||
|
||||
If R2 turns out to be constant such as 1, the instruction may have a
|
||||
REG_EQUAL note saying that R1 == 1.0. Reload then has the option of
|
||||
using this constant if R2 doesn't get allocated to a register.
|
||||
|
||||
In cases like these, reload will have added the constant to the pool
|
||||
but no instruction will yet refer to it. */
|
||||
if (!regs_ever_live[GLOBAL_POINTER_REGNUM]
|
||||
&& !current_function_uses_const_pool)
|
||||
return 0;
|
||||
|
||||
/* We need a global pointer, but perhaps we can use a call-clobbered
|
||||
register instead of $gp. */
|
||||
if (TARGET_NEWABI && current_function_is_leaf)
|
||||
for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
|
||||
if (!regs_ever_live[regno]
|
||||
&& call_used_regs[regno]
|
||||
&& !fixed_regs[regno])
|
||||
return regno;
|
||||
|
||||
return GLOBAL_POINTER_REGNUM;
|
||||
}
|
||||
|
||||
|
||||
/* Return true if the current function must save REGNO. */
|
||||
|
||||
static bool
|
||||
mips_save_reg_p (regno)
|
||||
unsigned int regno;
|
||||
{
|
||||
/* We only need to save $gp for NewABI PIC. */
|
||||
if (regno == GLOBAL_POINTER_REGNUM)
|
||||
return (TARGET_ABICALLS && TARGET_NEWABI
|
||||
&& cfun->machine->global_pointer == regno);
|
||||
|
||||
/* Check call-saved registers. */
|
||||
if (regs_ever_live[regno] && !call_used_regs[regno])
|
||||
return true;
|
||||
|
||||
/* We need to save the old frame pointer before setting up a new one. */
|
||||
if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
|
||||
return true;
|
||||
|
||||
/* We need to save the incoming return address if it is ever clobbered
|
||||
within the function. */
|
||||
if (regno == GP_REG_FIRST + 31 && regs_ever_live[regno])
|
||||
return true;
|
||||
|
||||
if (TARGET_MIPS16)
|
||||
{
|
||||
tree return_type;
|
||||
|
||||
return_type = DECL_RESULT (current_function_decl);
|
||||
|
||||
/* $18 is a special case in mips16 code. It may be used to call
|
||||
a function which returns a floating point value, but it is
|
||||
marked in call_used_regs. */
|
||||
if (regno == GP_REG_FIRST + 18 && regs_ever_live[regno])
|
||||
return true;
|
||||
|
||||
/* $31 is also a special case. When not using -mentry, it will be
|
||||
used to copy a return value into the floating point registers if
|
||||
the return value is floating point. */
|
||||
if (regno == GP_REG_FIRST + 31
|
||||
&& mips16_hard_float
|
||||
&& !mips_entry
|
||||
&& !aggregate_value_p (return_type)
|
||||
&& GET_MODE_CLASS (DECL_MODE (return_type)) == MODE_FLOAT
|
||||
&& GET_MODE_SIZE (DECL_MODE (return_type)) <= UNITS_PER_FPVALUE)
|
||||
return true;
|
||||
|
||||
/* The entry and exit pseudo instructions can not save $17
|
||||
without also saving $16. */
|
||||
if (mips_entry
|
||||
&& regno == GP_REG_FIRST + 16
|
||||
&& mips_save_reg_p (GP_REG_FIRST + 17))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Return the bytes needed to compute the frame pointer from the current
|
||||
stack pointer.
|
||||
|
||||
@ -6676,21 +6799,26 @@ compute_frame_size (size)
|
||||
HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up */
|
||||
HOST_WIDE_INT var_size; /* # bytes that variables take up */
|
||||
HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up */
|
||||
HOST_WIDE_INT extra_size; /* # extra bytes */
|
||||
HOST_WIDE_INT gp_reg_rounded; /* # bytes needed to store gp after rounding */
|
||||
HOST_WIDE_INT gp_reg_size; /* # bytes needed to store gp regs */
|
||||
HOST_WIDE_INT fp_reg_size; /* # bytes needed to store fp regs */
|
||||
long mask; /* mask of saved gp registers */
|
||||
long fmask; /* mask of saved fp registers */
|
||||
tree return_type;
|
||||
|
||||
cfun->machine->global_pointer = mips_global_pointer ();
|
||||
|
||||
gp_reg_size = 0;
|
||||
fp_reg_size = 0;
|
||||
mask = 0;
|
||||
fmask = 0;
|
||||
extra_size = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0));
|
||||
var_size = MIPS_STACK_ALIGN (size);
|
||||
args_size = MIPS_STACK_ALIGN (current_function_outgoing_args_size);
|
||||
args_size = MIPS_STACK_ALIGN (STARTING_FRAME_OFFSET);
|
||||
|
||||
/* The space set aside by STARTING_FRAME_OFFSET isn't needed in leaf
|
||||
functions. If the function has local variables, we're committed
|
||||
to allocating it anyway. Otherwise reclaim it here. */
|
||||
if (var_size == 0 && current_function_is_leaf)
|
||||
args_size = 0;
|
||||
|
||||
/* The MIPS 3.0 linker does not like functions that dynamically
|
||||
allocate the stack and have 0 for STACK_DYNAMIC_OFFSET, since it
|
||||
@ -6700,44 +6828,15 @@ compute_frame_size (size)
|
||||
if (args_size == 0 && current_function_calls_alloca)
|
||||
args_size = 4 * UNITS_PER_WORD;
|
||||
|
||||
total_size = var_size + args_size + extra_size;
|
||||
return_type = DECL_RESULT (current_function_decl);
|
||||
total_size = var_size + args_size;
|
||||
|
||||
/* Calculate space needed for gp registers. */
|
||||
for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
|
||||
{
|
||||
/* $18 is a special case on the mips16. It may be used to call
|
||||
a function which returns a floating point value, but it is
|
||||
marked in call_used_regs. $31 is also a special case. When
|
||||
not using -mentry, it will be used to copy a return value
|
||||
into the floating point registers if the return value is
|
||||
floating point. */
|
||||
if (MUST_SAVE_REGISTER (regno)
|
||||
|| (TARGET_MIPS16
|
||||
&& regno == GP_REG_FIRST + 18
|
||||
&& regs_ever_live[regno])
|
||||
|| (TARGET_MIPS16
|
||||
&& regno == GP_REG_FIRST + 31
|
||||
&& mips16_hard_float
|
||||
&& ! mips_entry
|
||||
&& ! aggregate_value_p (return_type)
|
||||
&& GET_MODE_CLASS (DECL_MODE (return_type)) == MODE_FLOAT
|
||||
&& GET_MODE_SIZE (DECL_MODE (return_type)) <= UNITS_PER_FPVALUE))
|
||||
{
|
||||
gp_reg_size += GET_MODE_SIZE (gpr_mode);
|
||||
mask |= 1L << (regno - GP_REG_FIRST);
|
||||
|
||||
/* The entry and exit pseudo instructions can not save $17
|
||||
without also saving $16. */
|
||||
if (mips_entry
|
||||
&& regno == GP_REG_FIRST + 17
|
||||
&& ! MUST_SAVE_REGISTER (GP_REG_FIRST + 16))
|
||||
{
|
||||
gp_reg_size += UNITS_PER_WORD;
|
||||
mask |= 1L << 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mips_save_reg_p (regno))
|
||||
{
|
||||
gp_reg_size += GET_MODE_SIZE (gpr_mode);
|
||||
mask |= 1L << (regno - GP_REG_FIRST);
|
||||
}
|
||||
|
||||
/* We need to restore these for the handler. */
|
||||
if (current_function_calls_eh_return)
|
||||
@ -6759,7 +6858,7 @@ compute_frame_size (size)
|
||||
regno >= FP_REG_FIRST;
|
||||
regno -= FP_INC)
|
||||
{
|
||||
if (regs_ever_live[regno] && !call_used_regs[regno])
|
||||
if (mips_save_reg_p (regno))
|
||||
{
|
||||
fp_reg_size += FP_INC * UNITS_PER_FPREG;
|
||||
fmask |= ((1 << FP_INC) - 1) << (regno - FP_REG_FIRST);
|
||||
@ -6769,25 +6868,6 @@ compute_frame_size (size)
|
||||
gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size);
|
||||
total_size += gp_reg_rounded + MIPS_STACK_ALIGN (fp_reg_size);
|
||||
|
||||
/* The gp reg is caller saved in the 32 bit ABI, so there is no need
|
||||
for leaf routines (total_size == extra_size) to save the gp reg.
|
||||
The gp reg is callee saved in the 64 bit ABI, so all routines must
|
||||
save the gp reg. This is not a leaf routine if -p, because of the
|
||||
call to mcount. */
|
||||
if (total_size == extra_size
|
||||
&& (mips_abi == ABI_32 || mips_abi == ABI_O64 || mips_abi == ABI_EABI)
|
||||
&& ! current_function_profile)
|
||||
total_size = extra_size = 0;
|
||||
else if (TARGET_ABICALLS)
|
||||
{
|
||||
/* Add the context-pointer to the saved registers. */
|
||||
gp_reg_size += UNITS_PER_WORD;
|
||||
mask |= 1L << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST);
|
||||
total_size -= gp_reg_rounded;
|
||||
gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size);
|
||||
total_size += gp_reg_rounded;
|
||||
}
|
||||
|
||||
/* Add in space reserved on the stack by the callee for storing arguments
|
||||
passed in registers. */
|
||||
if (mips_abi != ABI_32 && mips_abi != ABI_O64)
|
||||
@ -6801,7 +6881,6 @@ compute_frame_size (size)
|
||||
cfun->machine->frame.total_size = total_size;
|
||||
cfun->machine->frame.var_size = var_size;
|
||||
cfun->machine->frame.args_size = args_size;
|
||||
cfun->machine->frame.extra_size = extra_size;
|
||||
cfun->machine->frame.gp_reg_size = gp_reg_size;
|
||||
cfun->machine->frame.fp_reg_size = fp_reg_size;
|
||||
cfun->machine->frame.mask = mask;
|
||||
@ -6817,8 +6896,7 @@ compute_frame_size (size)
|
||||
/* When using mips_entry, the registers are always saved at the
|
||||
top of the stack. */
|
||||
if (! mips_entry)
|
||||
offset = (args_size + extra_size + var_size
|
||||
+ gp_reg_size - GET_MODE_SIZE (gpr_mode));
|
||||
offset = args_size + var_size + gp_reg_size - GET_MODE_SIZE (gpr_mode);
|
||||
else
|
||||
offset = total_size - GET_MODE_SIZE (gpr_mode);
|
||||
|
||||
@ -6833,7 +6911,7 @@ compute_frame_size (size)
|
||||
|
||||
if (fmask)
|
||||
{
|
||||
unsigned long offset = (args_size + extra_size + var_size
|
||||
unsigned long offset = (args_size + var_size
|
||||
+ gp_reg_rounded + fp_reg_size
|
||||
- FP_INC * UNITS_PER_FPREG);
|
||||
cfun->machine->frame.fp_sp_offset = offset;
|
||||
@ -6850,8 +6928,8 @@ compute_frame_size (size)
|
||||
}
|
||||
|
||||
/* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
|
||||
pointer, argument pointer, or return address pointer. TO is either
|
||||
the stack pointer or hard frame pointer. */
|
||||
pointer or argument pointer. TO is either the stack pointer or
|
||||
hard frame pointer. */
|
||||
|
||||
int
|
||||
mips_initial_elimination_offset (from, to)
|
||||
@ -6995,7 +7073,6 @@ save_restore_insns (store_p, large_reg, large_offset)
|
||||
{
|
||||
long mask = cfun->machine->frame.mask;
|
||||
long fmask = cfun->machine->frame.fmask;
|
||||
long real_mask = mask;
|
||||
int regno;
|
||||
rtx base_reg_rtx;
|
||||
HOST_WIDE_INT base_offset;
|
||||
@ -7007,12 +7084,6 @@ save_restore_insns (store_p, large_reg, large_offset)
|
||||
&& ! BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
|
||||
abort ();
|
||||
|
||||
/* Do not restore GP under certain conditions. */
|
||||
if (! store_p
|
||||
&& TARGET_ABICALLS
|
||||
&& (mips_abi == ABI_32 || mips_abi == ABI_O64))
|
||||
mask &= ~(1L << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST));
|
||||
|
||||
if (mask == 0 && fmask == 0)
|
||||
return;
|
||||
|
||||
@ -7124,11 +7195,8 @@ save_restore_insns (store_p, large_reg, large_offset)
|
||||
emit_move_insn (gen_rtx (REG, gpr_mode, regno),
|
||||
reg_rtx);
|
||||
}
|
||||
gp_offset -= GET_MODE_SIZE (gpr_mode);
|
||||
}
|
||||
/* If the restore is being supressed, still take into account
|
||||
the offset at which it is stored. */
|
||||
if (BITSET_P (real_mask, regno - GP_REG_FIRST))
|
||||
gp_offset -= GET_MODE_SIZE (gpr_mode);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -7252,7 +7320,7 @@ mips_output_function_prologue (file, size)
|
||||
{
|
||||
/* .frame FRAMEREG, FRAMESIZE, RETREG */
|
||||
fprintf (file,
|
||||
"\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d/%d, args= %d, extra= %ld\n",
|
||||
"\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d/%d, args= %d, gp= %ld\n",
|
||||
(reg_names[(frame_pointer_needed)
|
||||
? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
|
||||
((frame_pointer_needed && TARGET_MIPS16)
|
||||
@ -7263,7 +7331,8 @@ mips_output_function_prologue (file, size)
|
||||
cfun->machine->frame.num_gp,
|
||||
cfun->machine->frame.num_fp,
|
||||
current_function_outgoing_args_size,
|
||||
cfun->machine->frame.extra_size);
|
||||
cfun->machine->frame.args_size
|
||||
- current_function_outgoing_args_size);
|
||||
|
||||
/* .mask MASK, GPOFFSET; .fmask FPOFFSET */
|
||||
fprintf (file, "\t.mask\t0x%08lx,%ld\n\t.fmask\t0x%08lx,%ld\n",
|
||||
@ -7392,25 +7461,33 @@ mips_output_function_prologue (file, size)
|
||||
fprintf (file, "\n");
|
||||
}
|
||||
|
||||
if (TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64))
|
||||
{
|
||||
const char *const sp_str = reg_names[STACK_POINTER_REGNUM];
|
||||
|
||||
fprintf (file, "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n",
|
||||
reg_names[PIC_FUNCTION_ADDR_REGNUM]);
|
||||
if (tsize > 0)
|
||||
{
|
||||
fprintf (file, "\t%s\t%s,%s,%ld\n",
|
||||
(ptr_mode == DImode ? "dsubu" : "subu"),
|
||||
sp_str, sp_str, (long) tsize);
|
||||
fprintf (file, "\t.cprestore %ld\n", cfun->machine->frame.args_size);
|
||||
}
|
||||
|
||||
if (dwarf2out_do_frame ())
|
||||
dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, tsize);
|
||||
}
|
||||
/* Handle the initialization of $gp for SVR4 PIC. */
|
||||
if (TARGET_ABICALLS && !TARGET_NEWABI && cfun->machine->global_pointer > 0)
|
||||
fprintf (file, "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n",
|
||||
reg_names[PIC_FUNCTION_ADDR_REGNUM]);
|
||||
}
|
||||
|
||||
/* Emit an instruction to move SRC into DEST. When generating
|
||||
explicit reloc code, mark the instruction as potentially dead. */
|
||||
|
||||
static void
|
||||
mips_gp_insn (dest, src)
|
||||
rtx dest, src;
|
||||
{
|
||||
rtx insn;
|
||||
|
||||
insn = emit_insn (gen_rtx_SET (VOIDmode, dest, src));
|
||||
if (TARGET_EXPLICIT_RELOCS)
|
||||
{
|
||||
/* compute_frame_size assumes that any function which uses the
|
||||
constant pool will need a gp. However, all constant
|
||||
pool references could be eliminated, in which case
|
||||
it is OK for flow to delete the gp load as well. */
|
||||
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx,
|
||||
REG_NOTES (insn));
|
||||
}
|
||||
}
|
||||
|
||||
/* Expand the prologue into a bunch of separate insns. */
|
||||
|
||||
void
|
||||
@ -7432,6 +7509,9 @@ mips_expand_prologue ()
|
||||
int store_args_on_stack = (mips_abi == ABI_32 || mips_abi == ABI_O64)
|
||||
&& (! mips_entry || mips_can_use_return_insn ());
|
||||
|
||||
if (cfun->machine->global_pointer > 0)
|
||||
REGNO (pic_offset_table_rtx) = cfun->machine->global_pointer;
|
||||
|
||||
/* If struct value address is treated as the first argument, make it so. */
|
||||
if (aggregate_value_p (DECL_RESULT (fndecl))
|
||||
&& ! current_function_returns_pcc_struct
|
||||
@ -7558,10 +7638,6 @@ mips_expand_prologue ()
|
||||
int offset = (regno - GP_ARG_FIRST) * UNITS_PER_WORD;
|
||||
rtx ptr = stack_pointer_rtx;
|
||||
|
||||
/* If we are doing svr4-abi, sp has already been decremented by tsize. */
|
||||
if (TARGET_ABICALLS)
|
||||
offset += tsize;
|
||||
|
||||
for (; regno <= GP_ARG_LAST; regno++)
|
||||
{
|
||||
if (offset != 0)
|
||||
@ -7657,8 +7733,7 @@ mips_expand_prologue ()
|
||||
/* If we are doing svr4-abi, sp move is done by
|
||||
function_prologue. In mips16 mode with a large frame, we
|
||||
save the registers before adjusting the stack. */
|
||||
if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
|
||||
&& (!TARGET_MIPS16 || tsize <= 32767))
|
||||
if (!TARGET_MIPS16 || tsize <= 32767)
|
||||
{
|
||||
rtx adjustment_rtx;
|
||||
|
||||
@ -7687,9 +7762,11 @@ mips_expand_prologue ()
|
||||
else if (reg_18_save != NULL_RTX)
|
||||
emit_insn (reg_18_save);
|
||||
|
||||
if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
|
||||
&& TARGET_MIPS16
|
||||
&& tsize > 32767)
|
||||
if (TARGET_ABICALLS && !TARGET_NEWABI && !current_function_is_leaf)
|
||||
emit_insn (gen_cprestore
|
||||
(GEN_INT (current_function_outgoing_args_size)));
|
||||
|
||||
if (TARGET_MIPS16 && tsize > 32767)
|
||||
{
|
||||
rtx reg_rtx;
|
||||
|
||||
@ -7718,9 +7795,7 @@ mips_expand_prologue ()
|
||||
instructions when using the frame pointer by pointing the
|
||||
frame pointer ahead of the argument space allocated on
|
||||
the stack. */
|
||||
if ((! TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64))
|
||||
&& TARGET_MIPS16
|
||||
&& tsize > 32767)
|
||||
if (TARGET_MIPS16 && tsize > 32767)
|
||||
{
|
||||
/* In this case, we have already copied the stack
|
||||
pointer into the frame pointer, above. We need only
|
||||
@ -7760,10 +7835,24 @@ mips_expand_prologue ()
|
||||
if (insn)
|
||||
RTX_FRAME_RELATED_P (insn) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (TARGET_ABICALLS && (mips_abi != ABI_32 && mips_abi != ABI_O64))
|
||||
emit_insn (gen_loadgp (XEXP (DECL_RTL (current_function_decl), 0),
|
||||
gen_rtx_REG (DImode, 25)));
|
||||
if (TARGET_ABICALLS && TARGET_NEWABI && cfun->machine->global_pointer > 0)
|
||||
{
|
||||
rtx temp, fnsymbol, fnaddr;
|
||||
|
||||
temp = gen_rtx_REG (Pmode, MIPS_TEMP1_REGNUM);
|
||||
fnsymbol = XEXP (DECL_RTL (current_function_decl), 0);
|
||||
fnaddr = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
|
||||
|
||||
mips_gp_insn (temp, mips_lui_reloc (fnsymbol, RELOC_LOADGP_HI));
|
||||
mips_gp_insn (temp, gen_rtx_PLUS (Pmode, temp, fnaddr));
|
||||
mips_gp_insn (pic_offset_table_rtx,
|
||||
gen_rtx_PLUS (Pmode, temp,
|
||||
mips_reloc (fnsymbol, RELOC_LOADGP_LO)));
|
||||
|
||||
if (!TARGET_EXPLICIT_RELOCS)
|
||||
emit_insn (gen_loadgp_blockage ());
|
||||
}
|
||||
|
||||
/* If we are profiling, make sure no instructions are scheduled before
|
||||
@ -7824,6 +7913,9 @@ mips_output_function_epilogue (file, size)
|
||||
for (string = mips16_strings; string != 0; string = XEXP (string, 1))
|
||||
SYMBOL_REF_FLAG (XEXP (string, 0)) = 0;
|
||||
free_EXPR_LIST_list (&mips16_strings);
|
||||
|
||||
/* Reinstate the normal $gp. */
|
||||
REGNO (pic_offset_table_rtx) = GLOBAL_POINTER_REGNUM;
|
||||
}
|
||||
|
||||
/* Expand the epilogue into a bunch of separate insns. SIBCALL_P is true
|
||||
@ -8680,9 +8772,7 @@ mips16_gp_pseudo_reg ()
|
||||
|
||||
/* We want to initialize this to a value which gcc will believe
|
||||
is constant. */
|
||||
const_gp = gen_rtx (CONST, Pmode,
|
||||
gen_rtx (REG, Pmode, GP_REG_FIRST + 28));
|
||||
|
||||
const_gp = gen_rtx_CONST (Pmode, pic_offset_table_rtx);
|
||||
start_sequence ();
|
||||
emit_move_insn (cfun->machine->mips16_gp_pseudo_rtx,
|
||||
const_gp);
|
||||
@ -9223,8 +9313,7 @@ mips16_optimize_gp (first)
|
||||
|
||||
if (gpcopy == NULL_RTX
|
||||
&& GET_CODE (SET_SRC (set)) == CONST
|
||||
&& GET_CODE (XEXP (SET_SRC (set), 0)) == REG
|
||||
&& REGNO (XEXP (SET_SRC (set), 0)) == GP_REG_FIRST + 28
|
||||
&& XEXP (SET_SRC (set), 0) == pic_offset_table_rtx
|
||||
&& GET_CODE (SET_DEST (set)) == REG)
|
||||
gpcopy = SET_DEST (set);
|
||||
else if (slot == NULL_RTX
|
||||
@ -9249,9 +9338,7 @@ mips16_optimize_gp (first)
|
||||
&& (GET_CODE (SET_DEST (set)) != REG
|
||||
|| REGNO (SET_DEST (set)) != REGNO (gpcopy)
|
||||
|| ((GET_CODE (SET_SRC (set)) != CONST
|
||||
|| GET_CODE (XEXP (SET_SRC (set), 0)) != REG
|
||||
|| (REGNO (XEXP (SET_SRC (set), 0))
|
||||
!= GP_REG_FIRST + 28))
|
||||
|| XEXP (SET_SRC (set), 0) != pic_offset_table_rtx)
|
||||
&& ! rtx_equal_p (SET_SRC (set), slot))))
|
||||
break;
|
||||
else if (slot != NULL_RTX
|
||||
@ -9324,8 +9411,7 @@ mips16_optimize_gp (first)
|
||||
|
||||
if (GET_CODE (SET_DEST (set1)) == REG
|
||||
&& GET_CODE (SET_SRC (set1)) == CONST
|
||||
&& GET_CODE (XEXP (SET_SRC (set1), 0)) == REG
|
||||
&& REGNO (XEXP (SET_SRC (set1), 0)) == GP_REG_FIRST + 28
|
||||
&& XEXP (SET_SRC (set1), 0) == pic_offset_table_rtx
|
||||
&& rtx_equal_p (SET_DEST (set1), SET_DEST (set2))
|
||||
&& GET_CODE (SET_SRC (set2)) == PLUS
|
||||
&& rtx_equal_p (SET_DEST (set1), XEXP (SET_SRC (set2), 0))
|
||||
@ -9387,13 +9473,11 @@ mips16_optimize_gp (first)
|
||||
&& rtx_equal_p (SET_SRC (set), slot))
|
||||
{
|
||||
enum machine_mode mode;
|
||||
rtx src;
|
||||
|
||||
mode = GET_MODE (SET_DEST (set));
|
||||
emit_insn_after (gen_rtx (SET, VOIDmode, SET_DEST (set),
|
||||
gen_rtx (CONST, mode,
|
||||
gen_rtx (REG, mode,
|
||||
GP_REG_FIRST + 28))),
|
||||
insn);
|
||||
src = gen_rtx_CONST (mode, pic_offset_table_rtx);
|
||||
emit_insn_after (gen_rtx_SET (VOIDmode, SET_DEST (set), src), insn);
|
||||
PUT_CODE (insn, NOTE);
|
||||
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
|
||||
NOTE_SOURCE_FILE (insn) = 0;
|
||||
|
@ -1945,14 +1945,20 @@ extern char mips_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER];
|
||||
kept in a register. */
|
||||
#define NO_RECURSIVE_FUNCTION_CSE 1
|
||||
|
||||
/* The register number of the register used to address a table of
|
||||
static data addresses in memory. In some cases this register is
|
||||
defined by a processor's "application binary interface" (ABI).
|
||||
When this macro is defined, RTL is generated for this register
|
||||
once, as with the stack pointer and frame pointer registers. If
|
||||
this macro is not defined, it is up to the machine-dependent
|
||||
files to allocate such a register (if necessary). */
|
||||
#define PIC_OFFSET_TABLE_REGNUM (GP_REG_FIRST + 28)
|
||||
/* The ABI-defined global pointer. Sometimes we use a different
|
||||
register in leaf functions: see PIC_OFFSET_TABLE_REGNUM. */
|
||||
#define GLOBAL_POINTER_REGNUM (GP_REG_FIRST + 28)
|
||||
|
||||
/* We normally use $28 as the global pointer. However, when generating
|
||||
n32/64 PIC, it is better for leaf functions to use a call-clobbered
|
||||
register instead. They can then avoid saving and restoring $28
|
||||
and perhaps avoid using a frame at all.
|
||||
|
||||
When a leaf function uses something other than $28, mips_expand_prologue
|
||||
will modify pic_offset_table_rtx in place. Take the register number
|
||||
from there after reload. */
|
||||
#define PIC_OFFSET_TABLE_REGNUM \
|
||||
(reload_completed ? REGNO (pic_offset_table_rtx) : GLOBAL_POINTER_REGNUM)
|
||||
|
||||
#define PIC_FUNCTION_ADDR_REGNUM (GP_REG_FIRST + 25)
|
||||
|
||||
@ -2353,23 +2359,14 @@ extern enum reg_class mips_char_to_class[256];
|
||||
|
||||
/* Stack layout; function entry, exit and calling. */
|
||||
|
||||
/* Define this if pushing a word on the stack
|
||||
makes the stack pointer a smaller address. */
|
||||
#define STACK_GROWS_DOWNWARD
|
||||
|
||||
/* Define this if the nominal address of the stack frame
|
||||
is at the high-address end of the local variables;
|
||||
that is, each additional local variable allocated
|
||||
goes at a more negative offset in the frame. */
|
||||
/* #define FRAME_GROWS_DOWNWARD */
|
||||
|
||||
/* Offset within stack frame to start allocating local variables at.
|
||||
If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
|
||||
first local allocated. Otherwise, it is the offset to the BEGINNING
|
||||
of the first local allocated. */
|
||||
/* The offset of the first local variable from the beginning of the frame.
|
||||
See compute_frame_size for details about the frame layout. */
|
||||
#define STARTING_FRAME_OFFSET \
|
||||
(current_function_outgoing_args_size \
|
||||
+ (TARGET_ABICALLS ? MIPS_STACK_ALIGN (UNITS_PER_WORD) : 0))
|
||||
+ (TARGET_ABICALLS && !TARGET_NEWABI \
|
||||
? MIPS_STACK_ALIGN (UNITS_PER_WORD) : 0))
|
||||
|
||||
/* Offset from the stack pointer register to an item dynamically
|
||||
allocated on the stack, e.g., by `alloca'.
|
||||
@ -2837,13 +2834,6 @@ typedef struct mips_args {
|
||||
(mips_abi == ABI_EABI && UNITS_PER_FPVALUE >= UNITS_PER_DOUBLE)
|
||||
|
||||
|
||||
/* Tell prologue and epilogue if register REGNO should be saved / restored. */
|
||||
|
||||
#define MUST_SAVE_REGISTER(regno) \
|
||||
((regs_ever_live[regno] && !call_used_regs[regno]) \
|
||||
|| (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \
|
||||
|| (regno == (GP_REG_FIRST + 31) && regs_ever_live[GP_REG_FIRST + 31]))
|
||||
|
||||
/* Say that the epilogue uses the return address register. Note that
|
||||
in the case of sibcalls, the values "used by the epilogue" are
|
||||
considered live at the start of the called function. */
|
||||
|
@ -32,9 +32,7 @@
|
||||
(UNSPEC_STORE_DF_HIGH 2)
|
||||
(UNSPEC_GET_FNADDR 4)
|
||||
(UNSPEC_BLOCKAGE 6)
|
||||
(UNSPEC_LOADGP 7)
|
||||
(UNSPEC_SETJMP 8)
|
||||
(UNSPEC_LONGJMP 9)
|
||||
(UNSPEC_CPRESTORE 8)
|
||||
(UNSPEC_EH_RECEIVER 10)
|
||||
(UNSPEC_EH_RETURN 11)
|
||||
(UNSPEC_CONSTTABLE_QI 12)
|
||||
@ -67,7 +65,9 @@
|
||||
(RELOC_GOT_DISP 104)
|
||||
(RELOC_CALL16 105)
|
||||
(RELOC_CALL_HI 106)
|
||||
(RELOC_CALL_LO 107)])
|
||||
(RELOC_CALL_LO 107)
|
||||
(RELOC_LOADGP_HI 108)
|
||||
(RELOC_LOADGP_LO 109)])
|
||||
|
||||
|
||||
;; ....................
|
||||
@ -5428,21 +5428,28 @@ move\\t%0,%z4\\n\\
|
||||
(set_attr "mode" "SF")
|
||||
(set_attr "length" "4")])
|
||||
|
||||
;; Instructions to load the global pointer register.
|
||||
;; This is volatile to make sure that the scheduler won't move any symbol_ref
|
||||
;; uses in front of it. All symbol_refs implicitly use the gp reg.
|
||||
|
||||
(define_insn "loadgp"
|
||||
[(set (reg:DI 28)
|
||||
(unspec_volatile:DI [(match_operand 0 "immediate_operand" "")
|
||||
(match_operand:DI 1 "register_operand" "")]
|
||||
UNSPEC_LOADGP))
|
||||
(clobber (reg:DI 1))]
|
||||
;; The use of gp is hidden when not using explicit relocations.
|
||||
;; This blockage instruction prevents the gp load from being
|
||||
;; scheduled after an implicit use of gp. It also prevents
|
||||
;; the load from being deleted as dead.
|
||||
(define_insn "loadgp_blockage"
|
||||
[(unspec_volatile [(reg:DI 28)] UNSPEC_BLOCKAGE)]
|
||||
""
|
||||
"%[lui\\t$1,%%hi(%%neg(%%gp_rel(%0)))\\n\\taddiu\\t$1,$1,%%lo(%%neg(%%gp_rel(%0)))\\n\\tdaddu\\t$gp,$1,%1%]"
|
||||
[(set_attr "type" "move")
|
||||
(set_attr "mode" "DI")
|
||||
(set_attr "length" "12")])
|
||||
""
|
||||
[(set_attr "type" "unknown")
|
||||
(set_attr "mode" "none")
|
||||
(set_attr "length" "0")])
|
||||
|
||||
;; Emit a .cprestore directive, which expands to a single store instruction.
|
||||
;; Note that we continue to use .cprestore for explicit reloc code so that
|
||||
;; jals inside inlines asms will work correctly.
|
||||
(define_insn "cprestore"
|
||||
[(unspec_volatile [(match_operand 0 "const_int_operand" "")]
|
||||
UNSPEC_CPRESTORE)]
|
||||
""
|
||||
".cprestore\t%0"
|
||||
[(set_attr "type" "store")
|
||||
(set_attr "length" "4")])
|
||||
|
||||
;; Block moves, see mips.c for more details.
|
||||
;; Argument 0 is the destination
|
||||
@ -8776,55 +8783,45 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2"
|
||||
(set_attr "mode" "none")
|
||||
(set_attr "length" "24")])
|
||||
|
||||
;; For o32/n32/n64, we save the gp in the jmp_buf as well. While it is
|
||||
;; possible to either pull it off the stack (in the o32 case) or recalculate
|
||||
;; it given t9 and our target label, it takes 3 or 4 insns to do so, and
|
||||
;; this is easy.
|
||||
;; For TARGET_ABICALLS, we save the gp in the jmp_buf as well.
|
||||
;; While it is possible to either pull it off the stack (in the
|
||||
;; o32 case) or recalculate it given t9 and our target label,
|
||||
;; it takes 3 or 4 insns to do so.
|
||||
|
||||
(define_expand "builtin_setjmp_setup"
|
||||
[(unspec [(match_operand 0 "register_operand" "r")] UNSPEC_SETJMP)]
|
||||
[(use (match_operand 0 "register_operand" ""))]
|
||||
"TARGET_ABICALLS"
|
||||
"
|
||||
{
|
||||
if (Pmode == DImode)
|
||||
emit_insn (gen_builtin_setjmp_setup_64 (operands[0]));
|
||||
else
|
||||
emit_insn (gen_builtin_setjmp_setup_32 (operands[0]));
|
||||
DONE;
|
||||
}")
|
||||
{
|
||||
rtx addr;
|
||||
|
||||
(define_expand "builtin_setjmp_setup_32"
|
||||
[(set (mem:SI (plus:SI (match_operand:SI 0 "register_operand" "r")
|
||||
(const_int 12)))
|
||||
(reg:SI 28))]
|
||||
"TARGET_ABICALLS && ! (Pmode == DImode)"
|
||||
"")
|
||||
addr = plus_constant (operands[0], GET_MODE_SIZE (Pmode) * 3);
|
||||
emit_move_insn (gen_rtx_MEM (Pmode, addr), pic_offset_table_rtx);
|
||||
DONE;
|
||||
})
|
||||
|
||||
(define_expand "builtin_setjmp_setup_64"
|
||||
[(set (mem:DI (plus:DI (match_operand:DI 0 "register_operand" "r")
|
||||
(const_int 24)))
|
||||
(reg:DI 28))]
|
||||
"TARGET_ABICALLS && Pmode == DImode"
|
||||
"")
|
||||
|
||||
;; For o32/n32/n64, we need to arrange for longjmp to put the
|
||||
;; target address in t9 so that we can use it for loading $gp.
|
||||
;; Restore the gp that we saved above. Despite the comment, it seems that
|
||||
;; older code did recalculate the gp from $25. Continue to jump through
|
||||
;; $25 for compatibility (we lose nothing by doing so).
|
||||
|
||||
(define_expand "builtin_longjmp"
|
||||
[(unspec_volatile [(match_operand 0 "register_operand" "r")] UNSPEC_LONGJMP)]
|
||||
[(use (match_operand 0 "register_operand" "r"))]
|
||||
"TARGET_ABICALLS"
|
||||
"
|
||||
{
|
||||
/* The elements of the buffer are, in order: */
|
||||
int W = (Pmode == DImode ? 8 : 4);
|
||||
int W = GET_MODE_SIZE (Pmode);
|
||||
rtx fp = gen_rtx_MEM (Pmode, operands[0]);
|
||||
rtx lab = gen_rtx_MEM (Pmode, plus_constant (operands[0], 1*W));
|
||||
rtx stack = gen_rtx_MEM (Pmode, plus_constant (operands[0], 2*W));
|
||||
rtx gpv = gen_rtx_MEM (Pmode, plus_constant (operands[0], 3*W));
|
||||
rtx pv = gen_rtx_REG (Pmode, 25);
|
||||
rtx gp = gen_rtx_REG (Pmode, 28);
|
||||
rtx pv = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
|
||||
/* Use gen_raw_REG to avoid being given pic_offset_table_rtx.
|
||||
The target is bound to be using $28 as the global pointer
|
||||
but the current function might not be. */
|
||||
rtx gp = gen_raw_REG (Pmode, GLOBAL_POINTER_REGNUM);
|
||||
|
||||
/* This bit is the same as expand_builtin_longjmp. */
|
||||
/* This bit is similar to expand_builtin_longjmp except that it
|
||||
restores $gp as well. */
|
||||
emit_move_insn (hard_frame_pointer_rtx, fp);
|
||||
emit_move_insn (pv, lab);
|
||||
emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
|
||||
|
Loading…
x
Reference in New Issue
Block a user