Add tailcall/sibcall support to the H8
gcc/ * config/h8300/h8300-protos.h (h8300_expand_epilogue): Add new argument. * config/h8300/jumpcall.md (call, call_value): Restrict to !SIBLING_CALL_P cases. (subcall, sibcall_value): New patterns & expanders. * config/h8300/proepi.md (epilogue): Pass new argument to h8300_expand_epilogue. (sibcall_epilogue): New expander. * config/h8300/h8300.c (h8300_expand_epilogue): Handle sibcall epilogues too. (h8300_ok_for_sibcall_p): New function. (TARGET_FUNCTION_OK_FOR_SIBCALL): define.
This commit is contained in:
parent
89ff4f027b
commit
fedadb60b6
4 changed files with 108 additions and 7 deletions
|
@ -94,7 +94,7 @@ extern int h8300_tiny_data_p (tree);
|
|||
|
||||
extern int h8300_can_use_return_insn_p (void);
|
||||
extern void h8300_expand_prologue (void);
|
||||
extern void h8300_expand_epilogue (void);
|
||||
extern void h8300_expand_epilogue (bool);
|
||||
extern int h8300_current_function_interrupt_function_p (void);
|
||||
extern int h8300_current_function_monitor_function_p (void);
|
||||
extern int h8300_initial_elimination_offset (int, int);
|
||||
|
|
|
@ -874,7 +874,7 @@ h8300_can_use_return_insn_p (void)
|
|||
/* Generate RTL code for the function epilogue. */
|
||||
|
||||
void
|
||||
h8300_expand_epilogue (void)
|
||||
h8300_expand_epilogue (bool sibcall_p)
|
||||
{
|
||||
int regno;
|
||||
int saved_regs;
|
||||
|
@ -919,6 +919,7 @@ h8300_expand_epilogue (void)
|
|||
/* See if this pop would be the last insn before the return.
|
||||
If so, use rte/l or rts/l instead of pop or ldm.l. */
|
||||
if (TARGET_H8300SX
|
||||
&& !sibcall_p
|
||||
&& !frame_pointer_needed
|
||||
&& frame_size == 0
|
||||
&& (saved_regs & ((1 << (regno - n_regs + 1)) - 1)) == 0)
|
||||
|
@ -931,12 +932,12 @@ h8300_expand_epilogue (void)
|
|||
/* Pop frame pointer if we had one. */
|
||||
if (frame_pointer_needed)
|
||||
{
|
||||
if (TARGET_H8300SX)
|
||||
if (TARGET_H8300SX && !sibcall_p)
|
||||
returned_p = true;
|
||||
h8300_push_pop (HARD_FRAME_POINTER_REGNUM, 1, true, returned_p);
|
||||
}
|
||||
|
||||
if (!returned_p)
|
||||
if (!returned_p && !sibcall_p)
|
||||
emit_jump_insn (ret_rtx);
|
||||
}
|
||||
|
||||
|
@ -5533,6 +5534,25 @@ h8300_push_rounding (poly_int64 bytes)
|
|||
{
|
||||
return ((bytes + PARM_BOUNDARY / 8 - 1) & (-PARM_BOUNDARY / 8));
|
||||
}
|
||||
|
||||
static bool
|
||||
h8300_ok_for_sibcall_p (tree fndecl, tree)
|
||||
{
|
||||
/* If either the caller or target are special, then assume sibling
|
||||
calls are not OK. */
|
||||
if (!fndecl
|
||||
|| h8300_os_task_function_p (fndecl)
|
||||
|| h8300_monitor_function_p (fndecl)
|
||||
|| h8300_interrupt_function_p (fndecl)
|
||||
|| h8300_saveall_function_p (fndecl)
|
||||
|| h8300_os_task_function_p (current_function_decl)
|
||||
|| h8300_monitor_function_p (current_function_decl)
|
||||
|| h8300_interrupt_function_p (current_function_decl)
|
||||
|| h8300_saveall_function_p (current_function_decl))
|
||||
return false;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initialize the GCC target structure. */
|
||||
#undef TARGET_ATTRIBUTE_TABLE
|
||||
|
@ -5628,4 +5648,7 @@ h8300_push_rounding (poly_int64 bytes)
|
|||
#undef TARGET_FLAGS_REGNUM
|
||||
#define TARGET_FLAGS_REGNUM 12
|
||||
|
||||
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
|
||||
#define TARGET_FUNCTION_OK_FOR_SIBCALL h8300_ok_for_sibcall_p
|
||||
|
||||
struct gcc_target targetm = TARGET_INITIALIZER;
|
||||
|
|
|
@ -290,7 +290,7 @@
|
|||
(define_insn "call_insn_<mode>"
|
||||
[(call (mem:QI (match_operand 0 "call_insn_operand" "Cr"))
|
||||
(match_operand:P 1 "general_operand" "g"))]
|
||||
""
|
||||
"!SIBLING_CALL_P (insn)"
|
||||
{
|
||||
rtx xoperands[1];
|
||||
xoperands[0] = gen_rtx_MEM (QImode, operands[0]);
|
||||
|
@ -328,7 +328,7 @@
|
|||
[(set (match_operand 0 "" "=r")
|
||||
(call (mem:QI (match_operand 1 "call_insn_operand" "Cr"))
|
||||
(match_operand:P 2 "general_operand" "g")))]
|
||||
""
|
||||
"!SIBLING_CALL_P (insn)"
|
||||
{
|
||||
rtx xoperands[2];
|
||||
gcc_assert (GET_MODE (operands[1]) == Pmode);
|
||||
|
@ -347,3 +347,73 @@
|
|||
(const_int 2)
|
||||
(const_int 4)))])
|
||||
|
||||
(define_expand "sibcall"
|
||||
[(call (match_operand:QI 0 "call_expander_operand" "")
|
||||
(match_operand 1 "general_operand" ""))]
|
||||
""
|
||||
{
|
||||
if (!register_operand (XEXP (operands[0], 0), Pmode)
|
||||
&& GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF)
|
||||
XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0));
|
||||
})
|
||||
|
||||
(define_insn "sibcall_insn_<mode>"
|
||||
[(call (mem:QI (match_operand 0 "call_insn_operand" "Cr"))
|
||||
(match_operand:P 1 "general_operand" "g"))]
|
||||
"SIBLING_CALL_P (insn)"
|
||||
{
|
||||
rtx xoperands[1];
|
||||
xoperands[0] = gen_rtx_MEM (QImode, operands[0]);
|
||||
gcc_assert (GET_MODE (operands[0]) == Pmode);
|
||||
if (GET_CODE (XEXP (xoperands[0], 0)) == SYMBOL_REF
|
||||
&& (SYMBOL_REF_FLAGS (XEXP (xoperands[0], 0)) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
|
||||
output_asm_insn ("jmp\\t@%0:8", xoperands);
|
||||
else
|
||||
output_asm_insn ("jmp\\t%0", xoperands);
|
||||
return "";
|
||||
}
|
||||
[(set_attr "type" "call")
|
||||
(set (attr "length")
|
||||
(if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
|
||||
(const_int 2)
|
||||
(const_int 4)))])
|
||||
|
||||
;; Call subroutine, returning value in operand 0
|
||||
;; (which must be a hard register).
|
||||
|
||||
;; ??? Even though we use HImode here, this works on the H8/300H and H8S.
|
||||
|
||||
(define_expand "sibcall_value"
|
||||
[(set (match_operand 0 "" "")
|
||||
(call (match_operand:QI 1 "call_expander_operand" "")
|
||||
(match_operand 2 "general_operand" "")))]
|
||||
""
|
||||
{
|
||||
if (!register_operand (XEXP (operands[1], 0), Pmode)
|
||||
&& GET_CODE (XEXP (operands[1], 0)) != SYMBOL_REF)
|
||||
XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0));
|
||||
})
|
||||
|
||||
(define_insn "sibcall_value_insn_<mode>"
|
||||
[(set (match_operand 0 "" "=r")
|
||||
(call (mem:QI (match_operand 1 "call_insn_operand" "Cr"))
|
||||
(match_operand:P 2 "general_operand" "g")))]
|
||||
"SIBLING_CALL_P (insn)"
|
||||
{
|
||||
rtx xoperands[2];
|
||||
gcc_assert (GET_MODE (operands[1]) == Pmode);
|
||||
xoperands[0] = operands[0];
|
||||
xoperands[1] = gen_rtx_MEM (QImode, operands[1]);
|
||||
if (GET_CODE (XEXP (xoperands[1], 0)) == SYMBOL_REF
|
||||
&& (SYMBOL_REF_FLAGS (XEXP (xoperands[1], 0)) & SYMBOL_FLAG_FUNCVEC_FUNCTION))
|
||||
output_asm_insn ("jmp\\t@%1:8", xoperands);
|
||||
else
|
||||
output_asm_insn ("jmp\\t%1", xoperands);
|
||||
return "";
|
||||
}
|
||||
[(set_attr "type" "call")
|
||||
(set (attr "length")
|
||||
(if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
|
||||
(const_int 2)
|
||||
(const_int 4)))])
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
[(return)]
|
||||
""
|
||||
{
|
||||
h8300_expand_epilogue ();
|
||||
h8300_expand_epilogue (false);
|
||||
DONE;
|
||||
})
|
||||
|
||||
|
@ -121,3 +121,11 @@
|
|||
gcc_unreachable ();
|
||||
}
|
||||
[(set_attr "length" "20")])
|
||||
|
||||
(define_expand "sibcall_epilogue"
|
||||
[(const_int 0)]
|
||||
""
|
||||
{
|
||||
h8300_expand_epilogue (true);
|
||||
DONE;
|
||||
})
|
||||
|
|
Loading…
Add table
Reference in a new issue