diff options
| author | Richard Sandiford <rsandifo@redhat.com> | 2003-06-09 07:19:14 +0000 |
|---|---|---|
| committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2003-06-09 07:19:14 +0000 |
| commit | f833ffd42150a2e69fb37a5b7f9c8216d2613ff8 (patch) | |
| tree | fc9941d89e0d050b2e6febd4713f24b9619afa35 /gcc/config/mips/mips.c | |
| parent | 32ad6a47f78997e7cb032cea8c45ad09d57a5b7a (diff) | |
| download | gcc-f833ffd42150a2e69fb37a5b7f9c8216d2613ff8.zip gcc-f833ffd42150a2e69fb37a5b7f9c8216d2613ff8.tar.gz gcc-f833ffd42150a2e69fb37a5b7f9c8216d2613ff8.tar.bz2 | |
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
Diffstat (limited to 'gcc/config/mips/mips.c')
| -rw-r--r-- | gcc/config/mips/mips.c | 348 |
1 files changed, 216 insertions, 132 deletions
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 2604d49..47f3edd 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -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]; + /* 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. */ - 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); - } +static void +mips_gp_insn (dest, src) + rtx dest, src; +{ + rtx insn; - if (dwarf2out_do_frame ()) - dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, tsize); + 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 && TARGET_NEWABI && cfun->machine->global_pointer > 0) + { + rtx temp, fnsymbol, fnaddr; - 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))); + 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; |
