This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[MIPS] Fix handling of big .cprestore offsets (1/2)
- From: Richard Sandiford <rsandifo at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 01 Aug 2004 12:26:25 +0100
- Subject: [MIPS] Fix handling of big .cprestore offsets (1/2)
One of the new struct-by-value-1.exp tests (t023) passes >32k of
arguments by value. If we're generating o32 abicalls, this triggers
the pathological case in which a single load or store can't reach
the gp save slot.
This patch fixes the first of the problems exposed by the test,
namely that the call splitters assumed a single move would be enough.
Since there are several other places where we already do something
similar, I decided to fold all the logic into mips_add_offset.
Bootstrapped & regression tested on mips64-linux-gnu, mips64el-linux-gnu
and mips-sgi-irix6.5. Applied to mainline.
Richard
* 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.
Index: config/mips/mips-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips-protos.h,v
retrieving revision 1.74
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.74 mips-protos.h
*** config/mips/mips-protos.h 16 Jul 2004 07:51:29 -0000 1.74
--- config/mips/mips-protos.h 31 Jul 2004 18:35:07 -0000
*************** extern rtx mips_subword (rtx, int);
*** 121,127 ****
extern bool mips_split_64bit_move_p (rtx, rtx);
extern void mips_split_64bit_move (rtx, rtx);
extern const char *mips_output_move (rtx, rtx);
! extern rtx mips_gp_save_slot (void);
#ifdef RTX_CODE
extern bool mips_emit_scc (enum rtx_code, rtx);
extern void gen_conditional_branch (rtx *, enum rtx_code);
--- 121,127 ----
extern bool mips_split_64bit_move_p (rtx, rtx);
extern void mips_split_64bit_move (rtx, rtx);
extern const char *mips_output_move (rtx, rtx);
! extern void mips_restore_gp (void);
#ifdef RTX_CODE
extern bool mips_emit_scc (enum rtx_code, rtx);
extern void gen_conditional_branch (rtx *, enum rtx_code);
Index: config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.440
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.440 mips.c
*** config/mips/mips.c 20 Jul 2004 07:27:11 -0000 1.440
--- config/mips/mips.c 31 Jul 2004 18:35:17 -0000
*************** static bool mips16_unextended_reference_
*** 164,170 ****
static rtx mips_force_temporary (rtx, rtx);
static rtx mips_split_symbol (rtx, rtx);
static rtx mips_unspec_offset_high (rtx, rtx, rtx, enum mips_symbol_type);
! static rtx mips_add_offset (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);
--- 164,170 ----
static rtx mips_force_temporary (rtx, rtx);
static rtx mips_split_symbol (rtx, rtx);
static rtx mips_unspec_offset_high (rtx, rtx, rtx, enum mips_symbol_type);
! 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);
*************** mips_unspec_offset_high (rtx temp, rtx b
*** 1742,1759 ****
}
! /* Return a legitimate address for REG + OFFSET. This function will
! create a temporary register if OFFSET is not a SMALL_OPERAND. */
static rtx
! mips_add_offset (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));
}
--- 1742,1774 ----
}
! /* 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 temp, rtx reg, HOST_WIDE_INT offset)
{
if (!SMALL_OPERAND (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);
}
*************** mips_legitimize_address (rtx *xloc, enum
*** 1784,1790 ****
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)));
return true;
}
--- 1799,1805 ----
reg = XEXP (*xloc, 0);
if (!mips_valid_base_register_p (reg, mode, 0))
reg = copy_to_mode_reg (Pmode, reg);
! *xloc = mips_add_offset (0, reg, INTVAL (XEXP (*xloc, 1)));
return true;
}
*************** mips_legitimize_const_move (enum machine
*** 1962,1968 ****
&& (!no_new_pseudos || SMALL_OPERAND (offset)))
{
base = mips_force_temporary (dest, base);
! emit_move_insn (dest, mips_add_offset (base, offset));
return;
}
--- 1977,1983 ----
&& (!no_new_pseudos || SMALL_OPERAND (offset)))
{
base = mips_force_temporary (dest, base);
! emit_move_insn (dest, mips_add_offset (0, base, offset));
return;
}
*************** mips_output_move (rtx dest, rtx src)
*** 2666,2690 ****
abort ();
}
! /* Return an rtx for the gp save slot. Valid only when using o32 or
o64 abicalls. */
! rtx
! mips_gp_save_slot (void)
{
! rtx loc;
! 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;
}
/* Emit an instruction of the form (set TARGET (CODE OP0 OP1)). */
--- 2681,2708 ----
abort ();
}
! /* Restore $gp from its save slot. Valid only when using o32 or
o64 abicalls. */
! void
! mips_restore_gp (void)
{
! rtx address, slot;
! if (!TARGET_ABICALLS || !TARGET_OLDABI)
abort ();
! 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 ());
}
/* Emit an instruction of the form (set TARGET (CODE OP0 OP1)). */
*************** mips_emit_fcc_reload (rtx dest, rtx src,
*** 3101,3126 ****
void
mips_set_return_address (rtx address, rtx scratch)
{
! HOST_WIDE_INT gp_offset;
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));
! }
!
! emit_move_insn (gen_rtx_MEM (GET_MODE (address), scratch), address);
}
/* Emit straight-line code to move LENGTH bytes from SRC to DEST.
--- 3119,3133 ----
void
mips_set_return_address (rtx address, rtx scratch)
{
! rtx slot_address;
compute_frame_size (get_frame_size ());
if (((cfun->machine->frame.mask >> 31) & 1) == 0)
abort ();
! slot_address = mips_add_offset (scratch, stack_pointer_rtx,
! cfun->machine->frame.gp_sp_offset);
! emit_move_insn (gen_rtx_MEM (GET_MODE (address), slot_address), address);
}
/* Emit straight-line code to move LENGTH bytes from SRC to DEST.
*************** mips_output_mi_thunk (FILE *file, tree t
*** 6773,6797 ****
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)));
! }
/* Load the offset and add it to THIS. */
emit_move_insn (temp1, gen_rtx_MEM (Pmode, addr));
--- 6758,6764 ----
emit_move_insn (temp1, gen_rtx_MEM (Pmode, this));
/* Set ADDR to a legitimate address for *THIS + 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));
Index: config/mips/mips.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.md,v
retrieving revision 1.262
diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.262 mips.md
*** config/mips/mips.md 19 Jul 2004 17:28:48 -0000 1.262
--- config/mips/mips.md 31 Jul 2004 18:35:24 -0000
*************** (define_split
*** 6860,6876 ****
DONE;
})
! (define_insn "exception_receiver"
[(set (reg:SI 28)
(unspec_volatile:SI [(const_int 0)] UNSPEC_EH_RECEIVER))]
"TARGET_ABICALLS && TARGET_OLDABI"
{
! operands[0] = pic_offset_table_rtx;
! operands[1] = mips_gp_save_slot ();
! return mips_output_move (operands[0], operands[1]);
}
[(set_attr "type" "load")
! (set_attr "length" "8")])
;;
;; ....................
--- 6860,6878 ----
DONE;
})
! (define_insn_and_split "exception_receiver"
[(set (reg:SI 28)
(unspec_volatile:SI [(const_int 0)] UNSPEC_EH_RECEIVER))]
"TARGET_ABICALLS && TARGET_OLDABI"
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
{
! mips_restore_gp ();
! DONE;
}
[(set_attr "type" "load")
! (set_attr "length" "12")])
;;
;; ....................
*************** (define_insn_and_split "call_internal"
*** 7041,7047 ****
{
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 ());
DONE;
}
[(set_attr "jal" "indirect,direct")
--- 7043,7049 ----
{
emit_call_insn (gen_call_split (operands[0], operands[1]));
if (!find_reg_note (operands[2], REG_NORETURN, 0))
! mips_restore_gp ();
DONE;
}
[(set_attr "jal" "indirect,direct")
*************** (define_insn_and_split "call_value_inter
*** 7082,7088 ****
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 ());
DONE;
}
[(set_attr "jal" "indirect,direct")
--- 7084,7090 ----
emit_call_insn (gen_call_value_split (operands[0], operands[1],
operands[2]));
if (!find_reg_note (operands[3], REG_NORETURN, 0))
! mips_restore_gp ();
DONE;
}
[(set_attr "jal" "indirect,direct")
*************** (define_insn_and_split "call_value_multi
*** 7115,7121 ****
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 ());
DONE;
}
[(set_attr "jal" "indirect,direct")
--- 7117,7123 ----
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))
! mips_restore_gp ();
DONE;
}
[(set_attr "jal" "indirect,direct")