abort ();
}
\f
-/* Return instructions to restore the global pointer from the stack,
- assuming TARGET_ABICALLS. Used by exception_receiver to set up
- the GP for exception handlers.
+/* Return an rtx for the gp save slot. Valid only when using o32 or
+ o64 abicalls. */
- OPERANDS is an array of operands whose contents are undefined
- on entry. */
-
-const char *
-mips_restore_gp (rtx *operands)
+rtx
+mips_gp_save_slot (void)
{
rtx loc;
- operands[0] = pic_offset_table_rtx;
+ 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);
- operands[1] = gen_rtx_MEM (ptr_mode, loc);
-
- return mips_output_move (operands[0], operands[1]);
+ loc = gen_rtx_MEM (Pmode, loc);
+ RTX_UNCHANGING_P (loc) = 1;
+ return loc;
}
\f
-\f
/* Make normal rtx_code into something we can index from an array */
static enum internal_test
[(set (reg:SI 28)
(unspec_volatile:SI [(const_int 0)] UNSPEC_EH_RECEIVER))]
"TARGET_ABICALLS && (mips_abi == ABI_32 || mips_abi == ABI_O64)"
- { return mips_restore_gp (operands); }
+{
+ 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")])
\f
DONE;
})
+;; This instruction directly corresponds to an assembly-language "jal".
+;; There are four cases:
+;;
+;; - -mno-abicalls:
+;; Both symbolic and register destinations are OK. The pattern
+;; always expands to a single mips instruction.
+;;
+;; - -mabicalls/-mno-explicit-relocs:
+;; Again, both symbolic and register destinations are OK.
+;; The call is treated as a multi-instruction black box.
+;;
+;; - -mabicalls/-mexplicit-relocs with n32 or n64:
+;; Only "jal $25" is allowed. This expands to a single "jalr $25"
+;; instruction.
+;;
+;; - -mabicalls/-mexplicit-relocs with o32 or o64:
+;; Only "jal $25" is allowed. The call is actually two instructions:
+;; "jalr $25" followed by an insn to reload $gp.
+;;
+;; In the last case, we can generate the individual instructions with
+;; a define_split. There are several things to be wary of:
+;;
+;; - We can't expose the load of $gp before reload. If we did,
+;; it might get removed as dead, but reload can introduce new
+;; uses of $gp by rematerializing constants.
+;;
+;; - We shouldn't restore $gp after calls that never return.
+;; It isn't valid to insert instructions between a noreturn
+;; call and the following barrier.
+;;
+;; - The splitter deliberately changes the liveness of $gp. The unsplit
+;; instruction preserves $gp and so have no effect on its liveness.
+;; But once we generate the separate insns, it becomes obvious that
+;; $gp is not live on entry to the call.
+;;
+;; ??? The operands[2] = insn check is a hack to make the original insn
+;; available to the splitter.
(define_insn_and_split "call_internal"
[(call (mem:SI (match_operand 0 "call_insn_operand" "c,S"))
(match_operand 1 "" ""))
(clobber (reg:SI 31))]
""
- "%*jal\t%0%/"
- "reload_completed && TARGET_SPLIT_CALLS"
+ { return TARGET_SPLIT_CALLS ? "#" : "%*jal\t%0%/"; }
+ "reload_completed && TARGET_SPLIT_CALLS && (operands[2] = insn)"
[(const_int 0)]
{
emit_call_insn (gen_call_split (operands[0], operands[1]));
- emit_insn (gen_exception_receiver ());
+ 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")
[(call (mem:SI (match_operand 0 "call_insn_operand" "c"))
(match_operand 1 "" ""))
(clobber (reg:SI 31))
- (const_int 1)]
+ (clobber (reg:SI 28))]
"TARGET_SPLIT_CALLS"
"%*jalr\t%0%/"
[(set_attr "type" "call")])
DONE;
})
+;; See comment for call_internal.
(define_insn_and_split "call_value_internal"
[(set (match_operand 0 "register_operand" "=df,df")
(call (mem:SI (match_operand 1 "call_insn_operand" "c,S"))
(match_operand 2 "" "")))
(clobber (reg:SI 31))]
""
- "%*jal\t%1%/"
- "reload_completed && TARGET_SPLIT_CALLS"
+ { return TARGET_SPLIT_CALLS ? "#" : "%*jal\t%1%/"; }
+ "reload_completed && TARGET_SPLIT_CALLS && (operands[3] = insn)"
[(const_int 0)]
{
emit_call_insn (gen_call_value_split (operands[0], operands[1],
operands[2]));
- emit_insn (gen_exception_receiver ());
+ 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")
(call (mem:SI (match_operand 1 "call_insn_operand" "c"))
(match_operand 2 "" "")))
(clobber (reg:SI 31))
- (const_int 1)]
+ (clobber (reg:SI 28))]
"TARGET_SPLIT_CALLS"
"%*jalr\t%1%/"
[(set_attr "type" "call")])
+;; See comment for call_internal.
(define_insn_and_split "call_value_multiple_internal"
[(set (match_operand 0 "register_operand" "=df,df")
(call (mem:SI (match_operand 1 "call_insn_operand" "c,S"))
(match_dup 2)))
(clobber (reg:SI 31))]
""
- "%*jal\t%1%/"
- "reload_completed && TARGET_SPLIT_CALLS"
+ { return TARGET_SPLIT_CALLS ? "#" : "%*jal\t%1%/"; }
+ "reload_completed && TARGET_SPLIT_CALLS && (operands[4] = insn)"
[(const_int 0)]
{
emit_call_insn (gen_call_value_multiple_split (operands[0], operands[1],
operands[2], operands[3]));
- emit_insn (gen_exception_receiver ());
+ 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")
(call (mem:SI (match_dup 1))
(match_dup 2)))
(clobber (reg:SI 31))
- (const_int 1)]
+ (clobber (reg:SI 28))]
"TARGET_SPLIT_CALLS"
"%*jalr\t%1%/"
[(set_attr "type" "call")])