Commit f833ffd4 by Richard Sandiford Committed by Richard Sandiford

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
parent 32ad6a47
2003-06-09 Richard Sandiford <rsandifo@redhat.com> 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. * config/mips/mips-protos.h (mips_output_division): Declare.
* config/mips/mips.h (MASK_CHECK_RANGE_DIV): Remove. * config/mips/mips.h (MASK_CHECK_RANGE_DIV): Remove.
......
...@@ -231,12 +231,15 @@ static void mips_arg_info PARAMS ((const CUMULATIVE_ARGS *, ...@@ -231,12 +231,15 @@ static void mips_arg_info PARAMS ((const CUMULATIVE_ARGS *,
struct mips_arg_info *)); struct mips_arg_info *));
static bool mips_get_unaligned_mem PARAMS ((rtx *, unsigned int, static bool mips_get_unaligned_mem PARAMS ((rtx *, unsigned int,
int, rtx *, rtx *)); 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 rtx mips_add_large_offset_to_sp PARAMS ((HOST_WIDE_INT));
static void mips_set_frame_expr PARAMS ((rtx)); static void mips_set_frame_expr PARAMS ((rtx));
static rtx mips_frame_set PARAMS ((rtx, int)); static rtx mips_frame_set PARAMS ((rtx, int));
static void mips_emit_frame_related_store PARAMS ((rtx, rtx, static void mips_emit_frame_related_store PARAMS ((rtx, rtx,
HOST_WIDE_INT)); HOST_WIDE_INT));
static void save_restore_insns PARAMS ((int, rtx, long)); 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 mips16_fp_args PARAMS ((FILE *, int, int));
static void build_mips16_function_stub PARAMS ((FILE *)); static void build_mips16_function_stub PARAMS ((FILE *));
static void mips16_optimize_gp PARAMS ((rtx)); static void mips16_optimize_gp PARAMS ((rtx));
...@@ -298,7 +301,6 @@ struct mips_frame_info GTY(()) ...@@ -298,7 +301,6 @@ struct mips_frame_info GTY(())
long total_size; /* # bytes that the entire frame takes up */ long total_size; /* # bytes that the entire frame takes up */
long var_size; /* # bytes that variables take up */ long var_size; /* # bytes that variables take up */
long args_size; /* # bytes that outgoing arguments 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 gp_reg_size; /* # bytes needed to store gp regs */
int fp_reg_size; /* # bytes needed to store fp regs */ int fp_reg_size; /* # bytes needed to store fp regs */
long mask; /* mask of saved gp registers */ long mask; /* mask of saved gp registers */
...@@ -327,6 +329,9 @@ struct machine_function GTY(()) { ...@@ -327,6 +329,9 @@ struct machine_function GTY(()) {
/* Length of instructions in function; mips16 only. */ /* Length of instructions in function; mips16 only. */
long insns_len; long insns_len;
/* The register to use as the global pointer within this function. */
unsigned int global_pointer;
}; };
/* Information about a single argument. */ /* Information about a single argument. */
...@@ -890,7 +895,7 @@ mips_classify_constant (info, x) ...@@ -890,7 +895,7 @@ mips_classify_constant (info, x)
{ {
x = XEXP (x, 0); x = XEXP (x, 0);
if (GET_CODE (x) == REG && REGNO (x) == GP_REG_FIRST + 28) if (x == pic_offset_table_rtx)
return CONSTANT_GP; return CONSTANT_GP;
while (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT) while (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
...@@ -913,6 +918,8 @@ mips_classify_constant (info, x) ...@@ -913,6 +918,8 @@ mips_classify_constant (info, x)
case RELOC_CALL16: case RELOC_CALL16:
case RELOC_CALL_HI: case RELOC_CALL_HI:
case RELOC_CALL_LO: case RELOC_CALL_LO:
case RELOC_LOADGP_HI:
case RELOC_LOADGP_LO:
/* These relocations should be applied to bare symbols only. */ /* These relocations should be applied to bare symbols only. */
return (info->offset == 0 ? CONSTANT_RELOC : CONSTANT_NONE); return (info->offset == 0 ? CONSTANT_RELOC : CONSTANT_NONE);
} }
...@@ -3033,7 +3040,7 @@ mips_restore_gp (operands) ...@@ -3033,7 +3040,7 @@ mips_restore_gp (operands)
loc = hard_frame_pointer_rtx; loc = hard_frame_pointer_rtx;
else else
loc = stack_pointer_rtx; 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); operands[1] = gen_rtx_MEM (ptr_mode, loc);
return mips_output_move (operands[0], operands[1]); return mips_output_move (operands[0], operands[1]);
...@@ -5861,7 +5868,7 @@ mips_debugger_offset (addr, offset) ...@@ -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 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 pic call-through register (t9 or $25).
'$' Print the name of the stack pointer register (sp or $29). '$' 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). */ '~' Output a branch alignment to LABEL_ALIGN(NULL). */
void void
...@@ -5872,6 +5879,7 @@ print_operand (file, op, letter) ...@@ -5872,6 +5879,7 @@ print_operand (file, op, letter)
{ {
register enum rtx_code code; register enum rtx_code code;
struct mips_constant_info c; struct mips_constant_info c;
const char *reloc;
if (PRINT_OPERAND_PUNCT_VALID_P (letter)) if (PRINT_OPERAND_PUNCT_VALID_P (letter))
{ {
...@@ -5899,7 +5907,7 @@ print_operand (file, op, letter) ...@@ -5899,7 +5907,7 @@ print_operand (file, op, letter)
break; break;
case '+': case '+':
fputs (reg_names[GP_REG_FIRST + 28], file); fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file);
break; break;
case '&': case '&':
...@@ -6159,15 +6167,17 @@ print_operand (file, op, letter) ...@@ -6159,15 +6167,17 @@ print_operand (file, op, letter)
break; break;
case CONSTANT_GP: case CONSTANT_GP:
fputs (reg_names[GP_REG_FIRST + 28], file); fputs (reg_names[PIC_OFFSET_TABLE_REGNUM], file);
break; break;
case CONSTANT_RELOC: 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), output_addr_const (file, plus_constant (XVECEXP (c.symbol, 0, 0),
c.offset)); c.offset));
fputc (')', file); while (*reloc != 0)
break; if (*reloc++ == '(')
fputc (')', file);
} }
} }
...@@ -6187,6 +6197,8 @@ mips_reloc_string (reloc) ...@@ -6187,6 +6197,8 @@ mips_reloc_string (reloc)
case RELOC_CALL16: return "%call16("; case RELOC_CALL16: return "%call16(";
case RELOC_CALL_HI: return "%call_hi("; case RELOC_CALL_HI: return "%call_hi(";
case RELOC_CALL_LO: return "%call_lo("; 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 (); abort ();
} }
...@@ -6615,6 +6627,117 @@ mips_declare_object (stream, name, init_string, final_string, size) ...@@ -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 /* Return the bytes needed to compute the frame pointer from the current
stack pointer. stack pointer.
...@@ -6676,21 +6799,26 @@ compute_frame_size (size) ...@@ -6676,21 +6799,26 @@ compute_frame_size (size)
HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up */ 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 var_size; /* # bytes that variables take up */
HOST_WIDE_INT args_size; /* # bytes that outgoing arguments 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_rounded; /* # bytes needed to store gp after rounding */
HOST_WIDE_INT gp_reg_size; /* # bytes needed to store gp regs */ HOST_WIDE_INT gp_reg_size; /* # bytes needed to store gp regs */
HOST_WIDE_INT fp_reg_size; /* # bytes needed to store fp regs */ HOST_WIDE_INT fp_reg_size; /* # bytes needed to store fp regs */
long mask; /* mask of saved gp registers */ long mask; /* mask of saved gp registers */
long fmask; /* mask of saved fp registers */ long fmask; /* mask of saved fp registers */
tree return_type;
cfun->machine->global_pointer = mips_global_pointer ();
gp_reg_size = 0; gp_reg_size = 0;
fp_reg_size = 0; fp_reg_size = 0;
mask = 0; mask = 0;
fmask = 0; fmask = 0;
extra_size = MIPS_STACK_ALIGN (((TARGET_ABICALLS) ? UNITS_PER_WORD : 0));
var_size = MIPS_STACK_ALIGN (size); 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 /* The MIPS 3.0 linker does not like functions that dynamically
allocate the stack and have 0 for STACK_DYNAMIC_OFFSET, since it allocate the stack and have 0 for STACK_DYNAMIC_OFFSET, since it
...@@ -6700,44 +6828,15 @@ compute_frame_size (size) ...@@ -6700,44 +6828,15 @@ compute_frame_size (size)
if (args_size == 0 && current_function_calls_alloca) if (args_size == 0 && current_function_calls_alloca)
args_size = 4 * UNITS_PER_WORD; args_size = 4 * UNITS_PER_WORD;
total_size = var_size + args_size + extra_size; total_size = var_size + args_size;
return_type = DECL_RESULT (current_function_decl);
/* Calculate space needed for gp registers. */ /* Calculate space needed for gp registers. */
for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
{ if (mips_save_reg_p (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 gp_reg_size += GET_MODE_SIZE (gpr_mode);
marked in call_used_regs. $31 is also a special case. When mask |= 1L << (regno - GP_REG_FIRST);
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;
}
}
}
/* We need to restore these for the handler. */ /* We need to restore these for the handler. */
if (current_function_calls_eh_return) if (current_function_calls_eh_return)
...@@ -6759,7 +6858,7 @@ compute_frame_size (size) ...@@ -6759,7 +6858,7 @@ compute_frame_size (size)
regno >= FP_REG_FIRST; regno >= FP_REG_FIRST;
regno -= FP_INC) 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; fp_reg_size += FP_INC * UNITS_PER_FPREG;
fmask |= ((1 << FP_INC) - 1) << (regno - FP_REG_FIRST); fmask |= ((1 << FP_INC) - 1) << (regno - FP_REG_FIRST);
...@@ -6769,25 +6868,6 @@ compute_frame_size (size) ...@@ -6769,25 +6868,6 @@ compute_frame_size (size)
gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size); gp_reg_rounded = MIPS_STACK_ALIGN (gp_reg_size);
total_size += gp_reg_rounded + MIPS_STACK_ALIGN (fp_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 /* Add in space reserved on the stack by the callee for storing arguments
passed in registers. */ passed in registers. */
if (mips_abi != ABI_32 && mips_abi != ABI_O64) if (mips_abi != ABI_32 && mips_abi != ABI_O64)
...@@ -6801,7 +6881,6 @@ compute_frame_size (size) ...@@ -6801,7 +6881,6 @@ compute_frame_size (size)
cfun->machine->frame.total_size = total_size; cfun->machine->frame.total_size = total_size;
cfun->machine->frame.var_size = var_size; cfun->machine->frame.var_size = var_size;
cfun->machine->frame.args_size = args_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.gp_reg_size = gp_reg_size;
cfun->machine->frame.fp_reg_size = fp_reg_size; cfun->machine->frame.fp_reg_size = fp_reg_size;
cfun->machine->frame.mask = mask; cfun->machine->frame.mask = mask;
...@@ -6817,8 +6896,7 @@ compute_frame_size (size) ...@@ -6817,8 +6896,7 @@ compute_frame_size (size)
/* When using mips_entry, the registers are always saved at the /* When using mips_entry, the registers are always saved at the
top of the stack. */ top of the stack. */
if (! mips_entry) if (! mips_entry)
offset = (args_size + extra_size + var_size offset = args_size + var_size + gp_reg_size - GET_MODE_SIZE (gpr_mode);
+ gp_reg_size - GET_MODE_SIZE (gpr_mode));
else else
offset = total_size - GET_MODE_SIZE (gpr_mode); offset = total_size - GET_MODE_SIZE (gpr_mode);
...@@ -6833,7 +6911,7 @@ compute_frame_size (size) ...@@ -6833,7 +6911,7 @@ compute_frame_size (size)
if (fmask) if (fmask)
{ {
unsigned long offset = (args_size + extra_size + var_size unsigned long offset = (args_size + var_size
+ gp_reg_rounded + fp_reg_size + gp_reg_rounded + fp_reg_size
- FP_INC * UNITS_PER_FPREG); - FP_INC * UNITS_PER_FPREG);
cfun->machine->frame.fp_sp_offset = offset; cfun->machine->frame.fp_sp_offset = offset;
...@@ -6850,8 +6928,8 @@ compute_frame_size (size) ...@@ -6850,8 +6928,8 @@ compute_frame_size (size)
} }
/* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame /* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
pointer, argument pointer, or return address pointer. TO is either pointer or argument pointer. TO is either the stack pointer or
the stack pointer or hard frame pointer. */ hard frame pointer. */
int int
mips_initial_elimination_offset (from, to) mips_initial_elimination_offset (from, to)
...@@ -6995,7 +7073,6 @@ save_restore_insns (store_p, large_reg, large_offset) ...@@ -6995,7 +7073,6 @@ save_restore_insns (store_p, large_reg, large_offset)
{ {
long mask = cfun->machine->frame.mask; long mask = cfun->machine->frame.mask;
long fmask = cfun->machine->frame.fmask; long fmask = cfun->machine->frame.fmask;
long real_mask = mask;
int regno; int regno;
rtx base_reg_rtx; rtx base_reg_rtx;
HOST_WIDE_INT base_offset; HOST_WIDE_INT base_offset;
...@@ -7007,12 +7084,6 @@ save_restore_insns (store_p, large_reg, large_offset) ...@@ -7007,12 +7084,6 @@ save_restore_insns (store_p, large_reg, large_offset)
&& ! BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST)) && ! BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
abort (); 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) if (mask == 0 && fmask == 0)
return; return;
...@@ -7124,11 +7195,8 @@ save_restore_insns (store_p, large_reg, large_offset) ...@@ -7124,11 +7195,8 @@ save_restore_insns (store_p, large_reg, large_offset)
emit_move_insn (gen_rtx (REG, gpr_mode, regno), emit_move_insn (gen_rtx (REG, gpr_mode, regno),
reg_rtx); 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 else
...@@ -7252,7 +7320,7 @@ mips_output_function_prologue (file, size) ...@@ -7252,7 +7320,7 @@ mips_output_function_prologue (file, size)
{ {
/* .frame FRAMEREG, FRAMESIZE, RETREG */ /* .frame FRAMEREG, FRAMESIZE, RETREG */
fprintf (file, 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) (reg_names[(frame_pointer_needed)
? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]), ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM]),
((frame_pointer_needed && TARGET_MIPS16) ((frame_pointer_needed && TARGET_MIPS16)
...@@ -7263,7 +7331,8 @@ mips_output_function_prologue (file, size) ...@@ -7263,7 +7331,8 @@ mips_output_function_prologue (file, size)
cfun->machine->frame.num_gp, cfun->machine->frame.num_gp,
cfun->machine->frame.num_fp, cfun->machine->frame.num_fp,
current_function_outgoing_args_size, 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 */ /* .mask MASK, GPOFFSET; .fmask FPOFFSET */
fprintf (file, "\t.mask\t0x%08lx,%ld\n\t.fmask\t0x%08lx,%ld\n", fprintf (file, "\t.mask\t0x%08lx,%ld\n\t.fmask\t0x%08lx,%ld\n",
...@@ -7392,25 +7461,33 @@ mips_output_function_prologue (file, size) ...@@ -7392,25 +7461,33 @@ mips_output_function_prologue (file, size)
fprintf (file, "\n"); fprintf (file, "\n");
} }
if (TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64)) /* Handle the initialization of $gp for SVR4 PIC. */
{ if (TARGET_ABICALLS && !TARGET_NEWABI && cfun->machine->global_pointer > 0)
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]);
}
/* Emit an instruction to move SRC into DEST. When generating
explicit reloc code, mark the instruction as potentially dead. */
fprintf (file, "\t.set\tnoreorder\n\t.cpload\t%s\n\t.set\treorder\n", static void
reg_names[PIC_FUNCTION_ADDR_REGNUM]); mips_gp_insn (dest, src)
if (tsize > 0) rtx dest, src;
{ {
fprintf (file, "\t%s\t%s,%s,%ld\n", rtx insn;
(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 ()) insn = emit_insn (gen_rtx_SET (VOIDmode, dest, src));
dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, tsize); 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. */ /* Expand the prologue into a bunch of separate insns. */
void void
...@@ -7432,6 +7509,9 @@ mips_expand_prologue () ...@@ -7432,6 +7509,9 @@ mips_expand_prologue ()
int store_args_on_stack = (mips_abi == ABI_32 || mips_abi == ABI_O64) int store_args_on_stack = (mips_abi == ABI_32 || mips_abi == ABI_O64)
&& (! mips_entry || mips_can_use_return_insn ()); && (! 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 struct value address is treated as the first argument, make it so. */
if (aggregate_value_p (DECL_RESULT (fndecl)) if (aggregate_value_p (DECL_RESULT (fndecl))
&& ! current_function_returns_pcc_struct && ! current_function_returns_pcc_struct
...@@ -7558,10 +7638,6 @@ mips_expand_prologue () ...@@ -7558,10 +7638,6 @@ mips_expand_prologue ()
int offset = (regno - GP_ARG_FIRST) * UNITS_PER_WORD; int offset = (regno - GP_ARG_FIRST) * UNITS_PER_WORD;
rtx ptr = stack_pointer_rtx; 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++) for (; regno <= GP_ARG_LAST; regno++)
{ {
if (offset != 0) if (offset != 0)
...@@ -7657,8 +7733,7 @@ mips_expand_prologue () ...@@ -7657,8 +7733,7 @@ mips_expand_prologue ()
/* If we are doing svr4-abi, sp move is done by /* If we are doing svr4-abi, sp move is done by
function_prologue. In mips16 mode with a large frame, we function_prologue. In mips16 mode with a large frame, we
save the registers before adjusting the stack. */ save the registers before adjusting the stack. */
if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64)) if (!TARGET_MIPS16 || tsize <= 32767)
&& (!TARGET_MIPS16 || tsize <= 32767))
{ {
rtx adjustment_rtx; rtx adjustment_rtx;
...@@ -7687,9 +7762,11 @@ mips_expand_prologue () ...@@ -7687,9 +7762,11 @@ mips_expand_prologue ()
else if (reg_18_save != NULL_RTX) else if (reg_18_save != NULL_RTX)
emit_insn (reg_18_save); emit_insn (reg_18_save);
if ((!TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64)) if (TARGET_ABICALLS && !TARGET_NEWABI && !current_function_is_leaf)
&& TARGET_MIPS16 emit_insn (gen_cprestore
&& tsize > 32767) (GEN_INT (current_function_outgoing_args_size)));
if (TARGET_MIPS16 && tsize > 32767)
{ {
rtx reg_rtx; rtx reg_rtx;
...@@ -7718,9 +7795,7 @@ mips_expand_prologue () ...@@ -7718,9 +7795,7 @@ mips_expand_prologue ()
instructions when using the frame pointer by pointing the instructions when using the frame pointer by pointing the
frame pointer ahead of the argument space allocated on frame pointer ahead of the argument space allocated on
the stack. */ the stack. */
if ((! TARGET_ABICALLS || (mips_abi != ABI_32 && mips_abi != ABI_O64)) if (TARGET_MIPS16 && tsize > 32767)
&& TARGET_MIPS16
&& tsize > 32767)
{ {
/* In this case, we have already copied the stack /* In this case, we have already copied the stack
pointer into the frame pointer, above. We need only pointer into the frame pointer, above. We need only
...@@ -7760,10 +7835,24 @@ mips_expand_prologue () ...@@ -7760,10 +7835,24 @@ mips_expand_prologue ()
if (insn) if (insn)
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
} }
}
if (TARGET_ABICALLS && TARGET_NEWABI && cfun->machine->global_pointer > 0)
{
rtx temp, fnsymbol, fnaddr;
if (TARGET_ABICALLS && (mips_abi != ABI_32 && mips_abi != ABI_O64)) temp = gen_rtx_REG (Pmode, MIPS_TEMP1_REGNUM);
emit_insn (gen_loadgp (XEXP (DECL_RTL (current_function_decl), 0), fnsymbol = XEXP (DECL_RTL (current_function_decl), 0);
gen_rtx_REG (DImode, 25))); 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 /* If we are profiling, make sure no instructions are scheduled before
...@@ -7824,6 +7913,9 @@ mips_output_function_epilogue (file, size) ...@@ -7824,6 +7913,9 @@ mips_output_function_epilogue (file, size)
for (string = mips16_strings; string != 0; string = XEXP (string, 1)) for (string = mips16_strings; string != 0; string = XEXP (string, 1))
SYMBOL_REF_FLAG (XEXP (string, 0)) = 0; SYMBOL_REF_FLAG (XEXP (string, 0)) = 0;
free_EXPR_LIST_list (&mips16_strings); 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 /* Expand the epilogue into a bunch of separate insns. SIBCALL_P is true
...@@ -8680,9 +8772,7 @@ mips16_gp_pseudo_reg () ...@@ -8680,9 +8772,7 @@ mips16_gp_pseudo_reg ()
/* We want to initialize this to a value which gcc will believe /* We want to initialize this to a value which gcc will believe
is constant. */ is constant. */
const_gp = gen_rtx (CONST, Pmode, const_gp = gen_rtx_CONST (Pmode, pic_offset_table_rtx);
gen_rtx (REG, Pmode, GP_REG_FIRST + 28));
start_sequence (); start_sequence ();
emit_move_insn (cfun->machine->mips16_gp_pseudo_rtx, emit_move_insn (cfun->machine->mips16_gp_pseudo_rtx,
const_gp); const_gp);
...@@ -9223,8 +9313,7 @@ mips16_optimize_gp (first) ...@@ -9223,8 +9313,7 @@ mips16_optimize_gp (first)
if (gpcopy == NULL_RTX if (gpcopy == NULL_RTX
&& GET_CODE (SET_SRC (set)) == CONST && GET_CODE (SET_SRC (set)) == CONST
&& GET_CODE (XEXP (SET_SRC (set), 0)) == REG && XEXP (SET_SRC (set), 0) == pic_offset_table_rtx
&& REGNO (XEXP (SET_SRC (set), 0)) == GP_REG_FIRST + 28
&& GET_CODE (SET_DEST (set)) == REG) && GET_CODE (SET_DEST (set)) == REG)
gpcopy = SET_DEST (set); gpcopy = SET_DEST (set);
else if (slot == NULL_RTX else if (slot == NULL_RTX
...@@ -9249,9 +9338,7 @@ mips16_optimize_gp (first) ...@@ -9249,9 +9338,7 @@ mips16_optimize_gp (first)
&& (GET_CODE (SET_DEST (set)) != REG && (GET_CODE (SET_DEST (set)) != REG
|| REGNO (SET_DEST (set)) != REGNO (gpcopy) || REGNO (SET_DEST (set)) != REGNO (gpcopy)
|| ((GET_CODE (SET_SRC (set)) != CONST || ((GET_CODE (SET_SRC (set)) != CONST
|| GET_CODE (XEXP (SET_SRC (set), 0)) != REG || XEXP (SET_SRC (set), 0) != pic_offset_table_rtx)
|| (REGNO (XEXP (SET_SRC (set), 0))
!= GP_REG_FIRST + 28))
&& ! rtx_equal_p (SET_SRC (set), slot)))) && ! rtx_equal_p (SET_SRC (set), slot))))
break; break;
else if (slot != NULL_RTX else if (slot != NULL_RTX
...@@ -9324,8 +9411,7 @@ mips16_optimize_gp (first) ...@@ -9324,8 +9411,7 @@ mips16_optimize_gp (first)
if (GET_CODE (SET_DEST (set1)) == REG if (GET_CODE (SET_DEST (set1)) == REG
&& GET_CODE (SET_SRC (set1)) == CONST && GET_CODE (SET_SRC (set1)) == CONST
&& GET_CODE (XEXP (SET_SRC (set1), 0)) == REG && XEXP (SET_SRC (set1), 0) == pic_offset_table_rtx
&& REGNO (XEXP (SET_SRC (set1), 0)) == GP_REG_FIRST + 28
&& rtx_equal_p (SET_DEST (set1), SET_DEST (set2)) && rtx_equal_p (SET_DEST (set1), SET_DEST (set2))
&& GET_CODE (SET_SRC (set2)) == PLUS && GET_CODE (SET_SRC (set2)) == PLUS
&& rtx_equal_p (SET_DEST (set1), XEXP (SET_SRC (set2), 0)) && rtx_equal_p (SET_DEST (set1), XEXP (SET_SRC (set2), 0))
...@@ -9387,13 +9473,11 @@ mips16_optimize_gp (first) ...@@ -9387,13 +9473,11 @@ mips16_optimize_gp (first)
&& rtx_equal_p (SET_SRC (set), slot)) && rtx_equal_p (SET_SRC (set), slot))
{ {
enum machine_mode mode; enum machine_mode mode;
rtx src;
mode = GET_MODE (SET_DEST (set)); mode = GET_MODE (SET_DEST (set));
emit_insn_after (gen_rtx (SET, VOIDmode, SET_DEST (set), src = gen_rtx_CONST (mode, pic_offset_table_rtx);
gen_rtx (CONST, mode, emit_insn_after (gen_rtx_SET (VOIDmode, SET_DEST (set), src), insn);
gen_rtx (REG, mode,
GP_REG_FIRST + 28))),
insn);
PUT_CODE (insn, NOTE); PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0; NOTE_SOURCE_FILE (insn) = 0;
......
...@@ -1945,14 +1945,20 @@ extern char mips_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER]; ...@@ -1945,14 +1945,20 @@ extern char mips_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER];
kept in a register. */ kept in a register. */
#define NO_RECURSIVE_FUNCTION_CSE 1 #define NO_RECURSIVE_FUNCTION_CSE 1
/* The register number of the register used to address a table of /* The ABI-defined global pointer. Sometimes we use a different
static data addresses in memory. In some cases this register is register in leaf functions: see PIC_OFFSET_TABLE_REGNUM. */
defined by a processor's "application binary interface" (ABI). #define GLOBAL_POINTER_REGNUM (GP_REG_FIRST + 28)
When this macro is defined, RTL is generated for this register
once, as with the stack pointer and frame pointer registers. If /* We normally use $28 as the global pointer. However, when generating
this macro is not defined, it is up to the machine-dependent n32/64 PIC, it is better for leaf functions to use a call-clobbered
files to allocate such a register (if necessary). */ register instead. They can then avoid saving and restoring $28
#define PIC_OFFSET_TABLE_REGNUM (GP_REG_FIRST + 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) #define PIC_FUNCTION_ADDR_REGNUM (GP_REG_FIRST + 25)
...@@ -2353,23 +2359,14 @@ extern enum reg_class mips_char_to_class[256]; ...@@ -2353,23 +2359,14 @@ extern enum reg_class mips_char_to_class[256];
/* Stack layout; function entry, exit and calling. */ /* 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 STACK_GROWS_DOWNWARD
/* Define this if the nominal address of the stack frame /* The offset of the first local variable from the beginning of the frame.
is at the high-address end of the local variables; See compute_frame_size for details about the frame layout. */
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. */
#define STARTING_FRAME_OFFSET \ #define STARTING_FRAME_OFFSET \
(current_function_outgoing_args_size \ (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 /* Offset from the stack pointer register to an item dynamically
allocated on the stack, e.g., by `alloca'. allocated on the stack, e.g., by `alloca'.
...@@ -2837,13 +2834,6 @@ typedef struct mips_args { ...@@ -2837,13 +2834,6 @@ typedef struct mips_args {
(mips_abi == ABI_EABI && UNITS_PER_FPVALUE >= UNITS_PER_DOUBLE) (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 /* Say that the epilogue uses the return address register. Note that
in the case of sibcalls, the values "used by the epilogue" are in the case of sibcalls, the values "used by the epilogue" are
considered live at the start of the called function. */ considered live at the start of the called function. */
......
...@@ -32,9 +32,7 @@ ...@@ -32,9 +32,7 @@
(UNSPEC_STORE_DF_HIGH 2) (UNSPEC_STORE_DF_HIGH 2)
(UNSPEC_GET_FNADDR 4) (UNSPEC_GET_FNADDR 4)
(UNSPEC_BLOCKAGE 6) (UNSPEC_BLOCKAGE 6)
(UNSPEC_LOADGP 7) (UNSPEC_CPRESTORE 8)
(UNSPEC_SETJMP 8)
(UNSPEC_LONGJMP 9)
(UNSPEC_EH_RECEIVER 10) (UNSPEC_EH_RECEIVER 10)
(UNSPEC_EH_RETURN 11) (UNSPEC_EH_RETURN 11)
(UNSPEC_CONSTTABLE_QI 12) (UNSPEC_CONSTTABLE_QI 12)
...@@ -67,7 +65,9 @@ ...@@ -67,7 +65,9 @@
(RELOC_GOT_DISP 104) (RELOC_GOT_DISP 104)
(RELOC_CALL16 105) (RELOC_CALL16 105)
(RELOC_CALL_HI 106) (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\\ ...@@ -5428,21 +5428,28 @@ move\\t%0,%z4\\n\\
(set_attr "mode" "SF") (set_attr "mode" "SF")
(set_attr "length" "4")]) (set_attr "length" "4")])
;; Instructions to load the global pointer register. ;; The use of gp is hidden when not using explicit relocations.
;; This is volatile to make sure that the scheduler won't move any symbol_ref ;; This blockage instruction prevents the gp load from being
;; uses in front of it. All symbol_refs implicitly use the gp reg. ;; 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)]
""
""
[(set_attr "type" "unknown")
(set_attr "mode" "none")
(set_attr "length" "0")])
(define_insn "loadgp" ;; Emit a .cprestore directive, which expands to a single store instruction.
[(set (reg:DI 28) ;; Note that we continue to use .cprestore for explicit reloc code so that
(unspec_volatile:DI [(match_operand 0 "immediate_operand" "") ;; jals inside inlines asms will work correctly.
(match_operand:DI 1 "register_operand" "")] (define_insn "cprestore"
UNSPEC_LOADGP)) [(unspec_volatile [(match_operand 0 "const_int_operand" "")]
(clobber (reg:DI 1))] UNSPEC_CPRESTORE)]
"" ""
"%[lui\\t$1,%%hi(%%neg(%%gp_rel(%0)))\\n\\taddiu\\t$1,$1,%%lo(%%neg(%%gp_rel(%0)))\\n\\tdaddu\\t$gp,$1,%1%]" ".cprestore\t%0"
[(set_attr "type" "move") [(set_attr "type" "store")
(set_attr "mode" "DI") (set_attr "length" "4")])
(set_attr "length" "12")])
;; Block moves, see mips.c for more details. ;; Block moves, see mips.c for more details.
;; Argument 0 is the destination ;; 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" ...@@ -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 "mode" "none")
(set_attr "length" "24")]) (set_attr "length" "24")])
;; For o32/n32/n64, we save the gp in the jmp_buf as well. While it is ;; For TARGET_ABICALLS, we save the gp in the jmp_buf as well.
;; possible to either pull it off the stack (in the o32 case) or recalculate ;; While it is possible to either pull it off the stack (in the
;; it given t9 and our target label, it takes 3 or 4 insns to do so, and ;; o32 case) or recalculate it given t9 and our target label,
;; this is easy. ;; it takes 3 or 4 insns to do so.
(define_expand "builtin_setjmp_setup" (define_expand "builtin_setjmp_setup"
[(unspec [(match_operand 0 "register_operand" "r")] UNSPEC_SETJMP)] [(use (match_operand 0 "register_operand" ""))]
"TARGET_ABICALLS" "TARGET_ABICALLS"
" {
{ rtx addr;
if (Pmode == DImode)
emit_insn (gen_builtin_setjmp_setup_64 (operands[0]));
else
emit_insn (gen_builtin_setjmp_setup_32 (operands[0]));
DONE;
}")
(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)"
"")
(define_expand "builtin_setjmp_setup_64" addr = plus_constant (operands[0], GET_MODE_SIZE (Pmode) * 3);
[(set (mem:DI (plus:DI (match_operand:DI 0 "register_operand" "r") emit_move_insn (gen_rtx_MEM (Pmode, addr), pic_offset_table_rtx);
(const_int 24))) DONE;
(reg:DI 28))] })
"TARGET_ABICALLS && Pmode == DImode"
"")
;; For o32/n32/n64, we need to arrange for longjmp to put the ;; Restore the gp that we saved above. Despite the comment, it seems that
;; target address in t9 so that we can use it for loading $gp. ;; 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" (define_expand "builtin_longjmp"
[(unspec_volatile [(match_operand 0 "register_operand" "r")] UNSPEC_LONGJMP)] [(use (match_operand 0 "register_operand" "r"))]
"TARGET_ABICALLS" "TARGET_ABICALLS"
" "
{ {
/* The elements of the buffer are, in order: */ /* 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 fp = gen_rtx_MEM (Pmode, operands[0]);
rtx lab = gen_rtx_MEM (Pmode, plus_constant (operands[0], 1*W)); 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 stack = gen_rtx_MEM (Pmode, plus_constant (operands[0], 2*W));
rtx gpv = gen_rtx_MEM (Pmode, plus_constant (operands[0], 3*W)); rtx gpv = gen_rtx_MEM (Pmode, plus_constant (operands[0], 3*W));
rtx pv = gen_rtx_REG (Pmode, 25); rtx pv = gen_rtx_REG (Pmode, PIC_FUNCTION_ADDR_REGNUM);
rtx gp = gen_rtx_REG (Pmode, 28); /* Use gen_raw_REG to avoid being given pic_offset_table_rtx.
The target is bound to be using $28 as the global pointer
/* This bit is the same as expand_builtin_longjmp. */ but the current function might not be. */
rtx gp = gen_raw_REG (Pmode, GLOBAL_POINTER_REGNUM);
/* 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 (hard_frame_pointer_rtx, fp);
emit_move_insn (pv, lab); emit_move_insn (pv, lab);
emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX); emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment