+2005-07-31 Richard Sandiford <richard@codesourcery.com>
+
+ PR target/20621
+ Backport from mainline:
+
+ 2004-08-01 Richard Sandiford <rsandifo@redhat.com>
+ * config/mips/mips.md (cprestore): Provide two alternatives, one for
+ an in-range offset and one for an out-of-range offset. Wrap the latter
+ in .set macro/.set nomacro if it's inside a .set nomacro block.
+
+ 2004-08-01 Richard Sandiford <rsandifo@redhat.com>
+ * config/mips/mips-protos.h (mips_gp_save_slot): Remove.
+ (mips_restore_gp): Declare.
+ * config/mips/mips.c (mips_add_offset): Add a scratch register
+ argument. Reimplement in rtl only, reusing MIPS16 logic from
+ mips_output_mi_thunk.
+ (mips_legitimize_address, mips_legitimize_const_move): Adjust calls
+ to mips_add_offset.
+ (mips_gp_save_slot): Delete.
+ (mips_restore_gp): New function.
+ (mips_set_return_address, mips_output_mi_thunk): Use mips_add_offset.
+ * config/mips/mips.md (exception_receiver): Turn into a
+ define_insn_and_split. Use mips_restore_gp to do the split.
+ (call_internal, call_value_internal, call_value_multiple_internal): Use
+ mips_restore_gp to restore $gp.
+
2005-07-29 Alan Modra <amodra@bigpond.net.au>
* config/rs6000/sysv4.h (TARGET_ASM_EXCEPTION_SECTION): Delete.
static rtx mips_unspec_address (rtx, enum mips_symbol_type);
static rtx mips_unspec_offset_high (rtx, rtx, rtx, enum mips_symbol_type);
static rtx mips_load_got (rtx, rtx, enum mips_symbol_type);
-static rtx mips_add_offset (rtx, HOST_WIDE_INT);
+static rtx mips_add_offset (rtx, rtx, HOST_WIDE_INT);
static unsigned int mips_build_shift (struct mips_integer_op *, HOST_WIDE_INT);
static unsigned int mips_build_lower (struct mips_integer_op *,
unsigned HOST_WIDE_INT);
}
-/* Return a legitimate address for REG + OFFSET. This function will
- create a temporary register if OFFSET is not a SMALL_OPERAND. */
+/* Return a legitimate address for REG + OFFSET. TEMP is as for
+ mips_force_temporary; it is only needed when OFFSET is not a
+ SMALL_OPERAND. */
static rtx
-mips_add_offset (rtx reg, HOST_WIDE_INT offset)
+mips_add_offset (rtx temp, rtx reg, HOST_WIDE_INT offset)
{
if (!SMALL_OPERAND (offset))
- reg = expand_simple_binop (GET_MODE (reg), PLUS,
- GEN_INT (CONST_HIGH_PART (offset)),
- reg, NULL, 0, OPTAB_WIDEN);
-
- return plus_constant (reg, CONST_LOW_PART (offset));
+ {
+ rtx high;
+ if (TARGET_MIPS16)
+ {
+ /* Load the full offset into a register so that we can use
+ an unextended instruction for the address itself. */
+ high = GEN_INT (offset);
+ offset = 0;
+ }
+ else
+ {
+ /* Leave OFFSET as a 16-bit offset and put the excess in HIGH. */
+ high = GEN_INT (CONST_HIGH_PART (offset));
+ offset = CONST_LOW_PART (offset);
+ }
+ high = mips_force_temporary (temp, high);
+ reg = mips_force_temporary (temp, gen_rtx_PLUS (Pmode, high, reg));
+ }
+ return plus_constant (reg, offset);
}
reg = XEXP (*xloc, 0);
if (!mips_valid_base_register_p (reg, mode, 0))
reg = copy_to_mode_reg (Pmode, reg);
- *xloc = mips_add_offset (reg, INTVAL (XEXP (*xloc, 1)));
+ *xloc = mips_add_offset (0, reg, INTVAL (XEXP (*xloc, 1)));
return true;
}
&& (!no_new_pseudos || SMALL_OPERAND (offset)))
{
base = mips_force_temporary (dest, base);
- emit_move_insn (dest, mips_add_offset (base, offset));
+ emit_move_insn (dest, mips_add_offset (0, base, offset));
return;
}
abort ();
}
\f
-/* Return an rtx for the gp save slot. Valid only when using o32 or
+/* Restore $gp from its save slot. Valid only when using o32 or
o64 abicalls. */
-rtx
-mips_gp_save_slot (void)
+void
+mips_restore_gp (void)
{
- rtx loc;
+ rtx address, slot;
if (!TARGET_ABICALLS || TARGET_NEWABI)
abort ();
- if (frame_pointer_needed)
- loc = hard_frame_pointer_rtx;
- else
- loc = stack_pointer_rtx;
- loc = plus_constant (loc, current_function_outgoing_args_size);
- loc = gen_rtx_MEM (Pmode, loc);
- RTX_UNCHANGING_P (loc) = 1;
- return loc;
+ address = mips_add_offset (pic_offset_table_rtx,
+ frame_pointer_needed
+ ? hard_frame_pointer_rtx
+ : stack_pointer_rtx,
+ current_function_outgoing_args_size);
+ slot = gen_rtx_MEM (Pmode, address);
+ RTX_UNCHANGING_P (slot) = 1;
+
+ emit_move_insn (pic_offset_table_rtx, slot);
+ if (!TARGET_EXPLICIT_RELOCS)
+ emit_insn (gen_blockage ());
}
\f
/* Make normal rtx_code into something we can index from an array */
void
mips_set_return_address (rtx address, rtx scratch)
{
- HOST_WIDE_INT gp_offset;
+ rtx slot_address;
compute_frame_size (get_frame_size ());
if (((cfun->machine->frame.mask >> 31) & 1) == 0)
abort ();
- gp_offset = cfun->machine->frame.gp_sp_offset;
-
- /* Reduce SP + GP_OFSET to a legitimate address and put it in SCRATCH. */
- if (gp_offset < 32768)
- scratch = plus_constant (stack_pointer_rtx, gp_offset);
- else
- {
- emit_move_insn (scratch, GEN_INT (gp_offset));
- if (Pmode == DImode)
- emit_insn (gen_adddi3 (scratch, scratch, stack_pointer_rtx));
- else
- emit_insn (gen_addsi3 (scratch, scratch, stack_pointer_rtx));
- }
+ slot_address = mips_add_offset (scratch, stack_pointer_rtx,
+ cfun->machine->frame.gp_sp_offset);
- emit_move_insn (gen_rtx_MEM (GET_MODE (address), scratch), address);
+ emit_move_insn (gen_rtx_MEM (GET_MODE (address), slot_address), address);
}
\f
/* Emit straight-line code to move LENGTH bytes from SRC to DEST.
emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
/* Set ADDR to a legitimate address for *THIS + VCALL_OFFSET. */
- if (SMALL_OPERAND (vcall_offset))
- addr = gen_rtx_PLUS (Pmode, temp1, GEN_INT (vcall_offset));
- else if (TARGET_MIPS16)
- {
- /* Load the full offset into a register so that we can use
- an unextended instruction for the load itself. */
- emit_move_insn (temp2, GEN_INT (vcall_offset));
- emit_insn (gen_add3_insn (temp1, temp1, temp2));
- addr = temp1;
- }
- else
- {
- /* Load the high part of the offset into a register and
- leave the low part for the address. */
- emit_move_insn (temp2, GEN_INT (CONST_HIGH_PART (vcall_offset)));
- emit_insn (gen_add3_insn (temp1, temp1, temp2));
- addr = gen_rtx_PLUS (Pmode, temp1,
- GEN_INT (CONST_LOW_PART (vcall_offset)));
- }
+ addr = mips_add_offset (temp2, temp1, vcall_offset);
/* Load the offset and add it to THIS. */
emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
(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.
+;; Emit a .cprestore directive, which normally expands to a single store
+;; instruction. Note that we continue to use .cprestore for explicit reloc
+;; code so that jals inside inline asms will work correctly.
(define_insn "cprestore"
- [(unspec_volatile [(match_operand 0 "const_int_operand" "")]
+ [(unspec_volatile [(match_operand 0 "const_int_operand" "I,i")]
UNSPEC_CPRESTORE)]
""
- ".cprestore\t%0"
+{
+ if (set_nomacro && which_alternative == 1)
+ return ".set\tmacro\;.cprestore\t%0\;.set\tnomacro";
+ else
+ return ".cprestore\t%0";
+}
[(set_attr "type" "store")
- (set_attr "length" "4")])
+ (set_attr "length" "4,12")])
\f
;; Block moves, see mips.c for more details.
;; Argument 0 is the destination
DONE;
})
-(define_insn "exception_receiver"
+(define_insn_and_split "exception_receiver"
[(set (reg:SI 28)
(unspec_volatile:SI [(const_int 0)] UNSPEC_EH_RECEIVER))]
"TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64)"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
{
- operands[0] = pic_offset_table_rtx;
- operands[1] = mips_gp_save_slot ();
- return mips_output_move (operands[0], operands[1]);
+ mips_restore_gp ();
+ DONE;
}
[(set_attr "type" "load")
- (set_attr "length" "8")])
+ (set_attr "length" "12")])
\f
;;
;; ....................
{
emit_call_insn (gen_call_split (operands[0], operands[1]));
if (!find_reg_note (operands[2], REG_NORETURN, 0))
- emit_move_insn (pic_offset_table_rtx, mips_gp_save_slot ());
+ mips_restore_gp ();
DONE;
}
[(set_attr "jal" "indirect,direct")
emit_call_insn (gen_call_value_split (operands[0], operands[1],
operands[2]));
if (!find_reg_note (operands[3], REG_NORETURN, 0))
- emit_move_insn (pic_offset_table_rtx, mips_gp_save_slot ());
+ mips_restore_gp ();
DONE;
}
[(set_attr "jal" "indirect,direct")
emit_call_insn (gen_call_value_multiple_split (operands[0], operands[1],
operands[2], operands[3]));
if (!find_reg_note (operands[4], REG_NORETURN, 0))
- emit_move_insn (pic_offset_table_rtx, mips_gp_save_slot ());
+ mips_restore_gp ();
DONE;
}
[(set_attr "jal" "indirect,direct")