+2007-03-06 Richard Sandiford <richard@codesourcery.com>
+
+ * config/m68k/m68k-protos.h (output_sibcall): Declare.
+ (mips_expand_epilogue): Add a bool parameter.
+ (m68k_legitimize_sibcall_address): Declare.
+ * config/m68k/m68k.c (TARGET_FUNCTION_OK_FOR_SIBCALL): Define.
+ (m68k_expand_epilogue): Add a parameter to select between sibling
+ and normal epilogues. Only generate a return for the latter.
+ (m68k_ok_for_sibcall_p): New function.
+ (m68k_legitimize_sibcall_address, output_sibcall): New functions.
+ * config/m68k/m68k.md (sibcall, *sibcall): New patterns.
+ (sibcall_value, *sibcall_value): Likewise.
+ (*call, *call_value): Require !SIBLING_CALL_P.
+ (epilogue): Update call to m68k_expand_epilogue.
+ (sibcall_epilogue): New pattern.
+ * config/m68k/predicates.md (const_call_operand): Say that this
+ predicate applies to sibling calls too.
+ (sibcall_operand): New predicate.
+
2007-03-06 Richard Sandiford <richard@codesourcery.com>
* config/m68k/m68k.md (movsf_cf_soft): Provide the same non-mov3q
extern const char *output_iorsi3 (rtx *);
extern const char *output_xorsi3 (rtx *);
extern const char *output_call (rtx);
+extern const char *output_sibcall (rtx);
extern void output_dbcc_and_branch (rtx *);
extern int floating_exact_log2 (rtx);
extern bool strict_low_part_peephole_ok (enum machine_mode mode, rtx first_insn, rtx target);
extern int flags_in_68881 (void);
extern void m68k_expand_prologue (void);
extern bool m68k_use_return_insn (void);
-extern void m68k_expand_epilogue (void);
+extern void m68k_expand_epilogue (bool);
extern void override_options (void);
extern const char *m68k_cpp_cpu_ident (const char *);
extern const char *m68k_cpp_cpu_family (const char *);
extern void init_68881_table (void);
extern rtx m68k_legitimize_call_address (rtx);
+extern rtx m68k_legitimize_sibcall_address (rtx);
extern int m68k_hard_regno_rename_ok(unsigned int, unsigned int);
bool *no_add_attrs);
static void m68k_compute_frame_layout (void);
static bool m68k_save_reg (unsigned int regno, bool interrupt_handler);
+static bool m68k_ok_for_sibcall_p (tree, tree);
static bool m68k_rtx_costs (rtx, int, int, int *);
\f
#undef TARGET_CANNOT_FORCE_CONST_MEM
#define TARGET_CANNOT_FORCE_CONST_MEM m68k_illegitimate_symbolic_constant_p
+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL m68k_ok_for_sibcall_p
+
static const struct attribute_spec m68k_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
return current_frame.offset == 0;
}
-/* Emit RTL for the "epilogue" define_expand.
+/* Emit RTL for the "epilogue" or "sibcall_epilogue" define_expand;
+ SIBCALL_P says which.
The function epilogue should not depend on the current stack pointer!
It should use the frame pointer only, if there is a frame pointer.
omit stack adjustments before returning. */
void
-m68k_expand_epilogue (void)
+m68k_expand_epilogue (bool sibcall_p)
{
HOST_WIDE_INT fsize, fsize_with_regs;
bool big, restore_from_sp;
stack_pointer_rtx,
EH_RETURN_STACKADJ_RTX));
- emit_insn (gen_rtx_RETURN (VOIDmode));
+ if (!sibcall_p)
+ emit_insn (gen_rtx_RETURN (VOIDmode));
}
\f
/* Return true if X is a valid comparison operator for the dbcc
return cc_status.flags & CC_IN_68881;
}
+/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL_P. We cannot use sibcalls
+ for nested functions because we use the static chain register for
+ indirect calls. */
+
+static bool
+m68k_ok_for_sibcall_p (tree decl ATTRIBUTE_UNUSED, tree exp)
+{
+ return TREE_OPERAND (exp, 2) == NULL;
+}
+
/* Convert X to a legitimate function call memory reference and return the
result. */
return replace_equiv_address (x, force_reg (Pmode, XEXP (x, 0)));
}
+/* Likewise for sibling calls. */
+
+rtx
+m68k_legitimize_sibcall_address (rtx x)
+{
+ gcc_assert (MEM_P (x));
+ if (sibcall_operand (XEXP (x, 0), VOIDmode))
+ return x;
+
+ emit_move_insn (gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM), XEXP (x, 0));
+ return replace_equiv_address (x, gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM));
+}
+
/* Output a dbCC; jCC sequence. Note we do not handle the
floating point version of this sequence (Fdbcc). We also
do not handle alternative conditions when CC_NO_OVERFLOW is
return "jsr %a0";
}
+/* Likewise sibling calls. */
+
+const char *
+output_sibcall (rtx x)
+{
+ if (symbolic_operand (x, VOIDmode))
+ return m68k_symbolic_jump;
+ else
+ return "jmp %a0";
+}
+
#ifdef M68K_TARGET_COFF
/* Output assembly to switch to section NAME with attribute FLAGS. */
"subql #1,%0\;cmpl #-1,%0\;jne %l1";
})
+(define_expand "sibcall"
+ [(call (match_operand:QI 0 "memory_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+{
+ operands[0] = m68k_legitimize_sibcall_address (operands[0]);
+})
+
+(define_insn "*sibcall"
+ [(call (mem:QI (match_operand:SI 0 "sibcall_operand" ""))
+ (match_operand:SI 1 "general_operand" ""))]
+ "SIBLING_CALL_P (insn)"
+{
+ return output_sibcall (operands[0]);
+})
+
+(define_expand "sibcall_value"
+ [(set (match_operand 0 "" "")
+ (call (match_operand:QI 1 "memory_operand" "")
+ (match_operand:SI 2 "general_operand" "")))]
+ ""
+{
+ operands[1] = m68k_legitimize_sibcall_address (operands[1]);
+})
+
+(define_insn "*sibcall_value"
+ [(set (match_operand 0 "" "=rf,rf")
+ (call (mem:QI (match_operand:SI 1 "sibcall_operand" ""))
+ (match_operand:SI 2 "general_operand" "")))]
+ "SIBLING_CALL_P (insn)"
+{
+ operands[0] = operands[1];
+ return output_sibcall (operands[0]);
+})
+
;; Call subroutine with no return value.
(define_expand "call"
[(call (match_operand:QI 0 "memory_operand" "")
[(call (mem:QI (match_operand:SI 0 "call_operand" "a,W"))
(match_operand:SI 1 "general_operand" "g,g"))]
;; Operand 1 not really used on the m68000.
- ""
+ "!SIBLING_CALL_P (insn)"
{
return output_call (operands[0]);
})
(call (mem:QI (match_operand:SI 1 "call_operand" "a,W"))
(match_operand:SI 2 "general_operand" "g,g")))]
;; Operand 2 not really used on the m68000.
- ""
+ "!SIBLING_CALL_P (insn)"
{
operands[0] = operands[1];
return output_call (operands[0]);
[(return)]
""
{
- m68k_expand_epilogue ();
+ m68k_expand_epilogue (false);
+ DONE;
+})
+
+(define_expand "sibcall_epilogue"
+ [(return)]
+ ""
+{
+ m68k_expand_epilogue (true);
DONE;
})
}
})
-;; A constant that can be used the address in a call insn.
+;; A constant that can be used the address in a call or sibcall insn.
(define_predicate "const_call_operand"
(ior (match_operand 0 "const_int_operand")
(and (match_test "m68k_symbolic_call != NULL")
(ior (match_operand 0 "const_call_operand")
(match_operand 0 "register_operand")))
+;; An operand that can be used as the address in a sibcall insn.
+(define_predicate "sibcall_operand"
+ (ior (match_operand 0 "const_call_operand")
+ (and (match_code "reg")
+ (match_test "REGNO (op) == STATIC_CHAIN_REGNUM"))))
+
;; TODO: Add a comment here.
(define_predicate "post_inc_operand"