From fedadb60b6fc6425387faf4d514b4e8b0e24180e Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Mon, 23 Aug 2021 10:33:35 -0400 Subject: [PATCH] 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. --- gcc/config/h8300/h8300-protos.h | 2 +- gcc/config/h8300/h8300.c | 29 ++++++++++++++-- gcc/config/h8300/jumpcall.md | 74 +++++++++++++++++++++++++++++++++++++++-- gcc/config/h8300/proepi.md | 10 +++++- 4 files changed, 108 insertions(+), 7 deletions(-) diff --git a/gcc/config/h8300/h8300-protos.h b/gcc/config/h8300/h8300-protos.h index 744337d..3d34401 100644 --- a/gcc/config/h8300/h8300-protos.h +++ b/gcc/config/h8300/h8300-protos.h @@ -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); diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c index 8ccacec..5f7251a 100644 --- a/gcc/config/h8300/h8300.c +++ b/gcc/config/h8300/h8300.c @@ -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; diff --git a/gcc/config/h8300/jumpcall.md b/gcc/config/h8300/jumpcall.md index 3e59fee..b596399 100644 --- a/gcc/config/h8300/jumpcall.md +++ b/gcc/config/h8300/jumpcall.md @@ -290,7 +290,7 @@ (define_insn "call_insn_" [(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_" + [(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_" + [(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)))]) + diff --git a/gcc/config/h8300/proepi.md b/gcc/config/h8300/proepi.md index 44d5968..ab58d02 100644 --- a/gcc/config/h8300/proepi.md +++ b/gcc/config/h8300/proepi.md @@ -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; + }) -- 2.7.4