Add a target hook for sibcall epilogues
Checks
Commit Message
Epilogues for sibling calls are generated using the
sibcall_epilogue pattern. One disadvantage of this approach
is that the target doesn't know which call the epilogue is for,
even though the code that generates the pattern has the call
to hand.
Although call instructions are currently rtxes, and so could be
passed as an operand to the pattern, the main point of introducing
rtx_insn was to move towards separating the rtx and insn types
(a good thing IMO). There also isn't an existing practice of
passing genuine instructions (as opposed to labels) to
instruction patterns.
This patch therefore adds a hook that can be defined as an
alternative to sibcall_epilogue. The advantage is that it
can be passed the call; the disadvantage is that it can't
use .md conveniences like generating instructions from
textual patterns (although most epilogues are too complex
to benefit much from that anyway).
Tested on aarch64-linux-gnu and x86_64-linux-gnu. OK to install?
Richard
gcc/
* doc/gccint/target-macros/miscellaneous-parameters.rst:
Add TARGET_EMIT_EPILOGUE_FOR_SIBCALL.
* doc/gccint/target-macros/tm.rst.in: Regenerate.
* target.def (emit_epilogue_for_sibcall): New hook.
* calls.cc (can_implement_as_sibling_call_p): Use it.
* function.cc (thread_prologue_and_epilogue_insns): Likewise.
(reposition_prologue_and_epilogue_notes): Likewise.
* config/aarch64/aarch64-protos.h (aarch64_expand_epilogue): Take
an rtx_call_insn * rather than a bool.
* config/aarch64/aarch64.cc (aarch64_expand_epilogue): Likewise.
(TARGET_EMIT_EPILOGUE_FOR_SIBCALL): Define.
* config/aarch64/aarch64.md (epilogue): Update call.
(sibcall_epilogue): Delete.
---
gcc/calls.cc | 3 ++-
gcc/config/aarch64/aarch64-protos.h | 2 +-
gcc/config/aarch64/aarch64.cc | 11 +++++++----
gcc/config/aarch64/aarch64.md | 11 +----------
.../target-macros/miscellaneous-parameters.rst | 5 +++++
gcc/doc/gccint/target-macros/tm.rst.in | 11 +++++++++++
gcc/function.cc | 15 +++++++++++++--
gcc/target.def | 9 +++++++++
8 files changed, 49 insertions(+), 18 deletions(-)
Comments
On 11/11/22 09:22, Richard Sandiford via Gcc-patches wrote:
> Epilogues for sibling calls are generated using the
> sibcall_epilogue pattern. One disadvantage of this approach
> is that the target doesn't know which call the epilogue is for,
> even though the code that generates the pattern has the call
> to hand.
>
> Although call instructions are currently rtxes, and so could be
> passed as an operand to the pattern, the main point of introducing
> rtx_insn was to move towards separating the rtx and insn types
> (a good thing IMO). There also isn't an existing practice of
> passing genuine instructions (as opposed to labels) to
> instruction patterns.
>
> This patch therefore adds a hook that can be defined as an
> alternative to sibcall_epilogue. The advantage is that it
> can be passed the call; the disadvantage is that it can't
> use .md conveniences like generating instructions from
> textual patterns (although most epilogues are too complex
> to benefit much from that anyway).
>
> Tested on aarch64-linux-gnu and x86_64-linux-gnu. OK to install?
>
> Richard
>
>
> gcc/
> * doc/gccint/target-macros/miscellaneous-parameters.rst:
> Add TARGET_EMIT_EPILOGUE_FOR_SIBCALL.
> * doc/gccint/target-macros/tm.rst.in: Regenerate.
> * target.def (emit_epilogue_for_sibcall): New hook.
> * calls.cc (can_implement_as_sibling_call_p): Use it.
> * function.cc (thread_prologue_and_epilogue_insns): Likewise.
> (reposition_prologue_and_epilogue_notes): Likewise.
> * config/aarch64/aarch64-protos.h (aarch64_expand_epilogue): Take
> an rtx_call_insn * rather than a bool.
> * config/aarch64/aarch64.cc (aarch64_expand_epilogue): Likewise.
> (TARGET_EMIT_EPILOGUE_FOR_SIBCALL): Define.
> * config/aarch64/aarch64.md (epilogue): Update call.
> (sibcall_epilogue): Delete.
Presumably you're going to do something useful with the new hook :-)
OK.
jeff
@@ -2493,7 +2493,8 @@ can_implement_as_sibling_call_p (tree exp,
tree addr,
const args_size &args_size)
{
- if (!targetm.have_sibcall_epilogue ())
+ if (!targetm.have_sibcall_epilogue ()
+ && !targetm.emit_epilogue_for_sibcall)
{
maybe_complain_about_tail_call
(exp,
@@ -886,7 +886,7 @@ const char * aarch64_gen_far_branch (rtx *, int, const char *, const char *);
const char * aarch64_output_probe_stack_range (rtx, rtx);
const char * aarch64_output_probe_sve_stack_clash (rtx, rtx, rtx, rtx);
void aarch64_err_no_fpadvsimd (machine_mode);
-void aarch64_expand_epilogue (bool);
+void aarch64_expand_epilogue (rtx_call_insn *);
rtx aarch64_ptrue_all (unsigned int);
opt_machine_mode aarch64_ptrue_all_mode (rtx);
rtx aarch64_convert_sve_data_to_pred (rtx, machine_mode, rtx);
@@ -10003,7 +10003,7 @@ aarch64_use_return_insn_p (void)
from a deallocated stack, and we optimize the unwind records by
emitting them all together if possible. */
void
-aarch64_expand_epilogue (bool for_sibcall)
+aarch64_expand_epilogue (rtx_call_insn *sibcall)
{
poly_int64 initial_adjust = cfun->machine->frame.initial_adjust;
HOST_WIDE_INT callee_adjust = cfun->machine->frame.callee_adjust;
@@ -10151,7 +10151,7 @@ aarch64_expand_epilogue (bool for_sibcall)
explicitly authenticate.
*/
if (aarch64_return_address_signing_enabled ()
- && (for_sibcall || !TARGET_ARMV8_3))
+ && (sibcall || !TARGET_ARMV8_3))
{
switch (aarch64_ra_sign_key)
{
@@ -10169,7 +10169,7 @@ aarch64_expand_epilogue (bool for_sibcall)
}
/* Stack adjustment for exception handler. */
- if (crtl->calls_eh_return && !for_sibcall)
+ if (crtl->calls_eh_return && !sibcall)
{
/* We need to unwind the stack by the offset computed by
EH_RETURN_STACKADJ_RTX. We have already reset the CFA
@@ -10180,7 +10180,7 @@ aarch64_expand_epilogue (bool for_sibcall)
}
emit_use (gen_rtx_REG (DImode, LR_REGNUM));
- if (!for_sibcall)
+ if (!sibcall)
emit_jump_insn (ret_rtx);
}
@@ -27906,6 +27906,9 @@ aarch64_libgcc_floating_mode_supported_p
#undef TARGET_HAVE_SHADOW_CALL_STACK
#define TARGET_HAVE_SHADOW_CALL_STACK true
+#undef TARGET_EMIT_EPILOGUE_FOR_SIBCALL
+#define TARGET_EMIT_EPILOGUE_FOR_SIBCALL aarch64_expand_epilogue
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-aarch64.h"
@@ -868,16 +868,7 @@ (define_expand "epilogue"
[(clobber (const_int 0))]
""
"
- aarch64_expand_epilogue (false);
- DONE;
- "
-)
-
-(define_expand "sibcall_epilogue"
- [(clobber (const_int 0))]
- ""
- "
- aarch64_expand_epilogue (true);
+ aarch64_expand_epilogue (nullptr);
DONE;
"
)
@@ -556,6 +556,11 @@ Here are several miscellaneous parameters.
:end-before: [TARGET_USE_LATE_PROLOGUE_EPILOGUE]
+.. include:: tm.rst.in
+ :start-after: [TARGET_EMIT_EPILOGUE_FOR_SIBCALL]
+ :end-before: [TARGET_EMIT_EPILOGUE_FOR_SIBCALL]
+
+
.. include:: tm.rst.in
:start-after: [TARGET_MACHINE_DEPENDENT_REORG]
:end-before: [TARGET_MACHINE_DEPENDENT_REORG]
@@ -3724,6 +3724,17 @@
[TARGET_USE_LATE_PROLOGUE_EPILOGUE]
+[TARGET_EMIT_EPILOGUE_FOR_SIBCALL]
+.. function:: void TARGET_EMIT_EPILOGUE_FOR_SIBCALL (rtx_call_insn *call)
+
+ If defined, this hook emits an epilogue sequence for sibling (tail)
+ call instruction :samp:`call`. Another way of providing epilogues
+ for sibling calls is to define the ``sibcall_epilogue`` instruction
+ pattern; the main advantage of this hook over the pattern is that it
+ has access to the call instruction.
+
+[TARGET_EMIT_EPILOGUE_FOR_SIBCALL]
+
[TARGET_MACHINE_DEPENDENT_REORG]
.. function:: void TARGET_MACHINE_DEPENDENT_REORG (void)
@@ -6224,7 +6224,17 @@ thread_prologue_and_epilogue_insns (void)
if (!(CALL_P (insn) && SIBLING_CALL_P (insn)))
continue;
- if (rtx_insn *ep_seq = targetm.gen_sibcall_epilogue ())
+ rtx_insn *ep_seq;
+ if (targetm.emit_epilogue_for_sibcall)
+ {
+ start_sequence ();
+ targetm.emit_epilogue_for_sibcall (as_a<rtx_call_insn *> (insn));
+ ep_seq = get_insns ();
+ end_sequence ();
+ }
+ else
+ ep_seq = targetm.gen_sibcall_epilogue ();
+ if (ep_seq)
{
start_sequence ();
emit_note (NOTE_INSN_EPILOGUE_BEG);
@@ -6284,7 +6294,8 @@ reposition_prologue_and_epilogue_notes (void)
{
if (!targetm.have_prologue ()
&& !targetm.have_epilogue ()
- && !targetm.have_sibcall_epilogue ())
+ && !targetm.have_sibcall_epilogue ()
+ && !targetm.emit_epilogue_for_sibcall)
return;
/* Since the hash table is created on demand, the fact that it is
@@ -4083,6 +4083,15 @@ between instruction sets.",
bool, (),
hook_bool_void_false)
+DEFHOOK
+(emit_epilogue_for_sibcall,
+ "If defined, this hook emits an epilogue sequence for sibling (tail)\n\
+call instruction :samp:`call`. Another way of providing epilogues\n\
+for sibling calls is to define the ``sibcall_epilogue`` instruction\n\
+pattern; the main advantage of this hook over the pattern is that it\n\
+has access to the call instruction.",
+ void, (rtx_call_insn *call), NULL)
+
/* Do machine-dependent code transformations. Called just before
delayed-branch scheduling. */
DEFHOOK