239 lines
8.5 KiB
Diff
239 lines
8.5 KiB
Diff
From 10351a5dade506b85992c0d9f029cf37c8e90ef4 Mon Sep 17 00:00:00 2001
|
|
From: Richard Sandiford <richard.sandiford@arm.com>
|
|
Date: Tue, 5 Dec 2023 09:35:57 +0000
|
|
Subject: [PATCH 046/144] Add a target hook for sibcall epilogues
|
|
|
|
Reference: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=2e0aefa77157396acb48833407637303edba450a
|
|
|
|
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).
|
|
|
|
gcc/
|
|
* doc/tm.texi.in: Add TARGET_EMIT_EPILOGUE_FOR_SIBCALL.
|
|
* doc/tm.texi: 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 +----------
|
|
gcc/doc/tm.texi | 8 ++++++++
|
|
gcc/doc/tm.texi.in | 2 ++
|
|
gcc/function.cc | 15 +++++++++++++--
|
|
gcc/target.def | 9 +++++++++
|
|
8 files changed, 43 insertions(+), 18 deletions(-)
|
|
|
|
diff --git a/gcc/calls.cc b/gcc/calls.cc
|
|
index 4d0bc45be..c1db66883 100644
|
|
--- a/gcc/calls.cc
|
|
+++ b/gcc/calls.cc
|
|
@@ -2461,7 +2461,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,
|
|
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
|
|
index 86e444a60..97984f3ab 100644
|
|
--- a/gcc/config/aarch64/aarch64-protos.h
|
|
+++ b/gcc/config/aarch64/aarch64-protos.h
|
|
@@ -887,7 +887,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);
|
|
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
|
|
index fc7540023..76bb0a5dd 100644
|
|
--- a/gcc/config/aarch64/aarch64.cc
|
|
+++ b/gcc/config/aarch64/aarch64.cc
|
|
@@ -9829,7 +9829,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;
|
|
@@ -9977,7 +9977,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)
|
|
{
|
|
@@ -9995,7 +9995,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
|
|
@@ -10006,7 +10006,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);
|
|
}
|
|
|
|
@@ -27923,6 +27923,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"
|
|
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
|
|
index 5473e2720..22c22b1c6 100644
|
|
--- a/gcc/config/aarch64/aarch64.md
|
|
+++ b/gcc/config/aarch64/aarch64.md
|
|
@@ -869,16 +869,7 @@
|
|
[(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;
|
|
"
|
|
)
|
|
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
|
|
index f8109834d..3601994c3 100644
|
|
--- a/gcc/doc/tm.texi
|
|
+++ b/gcc/doc/tm.texi
|
|
@@ -11913,6 +11913,14 @@ the hook might return true if the prologue and epilogue need to switch
|
|
between instruction sets.
|
|
@end deftypefn
|
|
|
|
+@deftypefn {Target Hook} void TARGET_EMIT_EPILOGUE_FOR_SIBCALL (rtx_call_insn *@var{call})
|
|
+If defined, this hook emits an epilogue sequence for sibling (tail)
|
|
+call instruction @var{call}. Another way of providing epilogues
|
|
+for sibling calls is to define the @code{sibcall_epilogue} instruction
|
|
+pattern; the main advantage of this hook over the pattern is that it
|
|
+has access to the call instruction.
|
|
+@end deftypefn
|
|
+
|
|
@deftypefn {Target Hook} void TARGET_MACHINE_DEPENDENT_REORG (void)
|
|
If non-null, this hook performs a target-specific pass over the
|
|
instruction stream. The compiler will run it at all optimization levels,
|
|
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
|
|
index 9d72fe18d..8062ee79c 100644
|
|
--- a/gcc/doc/tm.texi.in
|
|
+++ b/gcc/doc/tm.texi.in
|
|
@@ -7920,6 +7920,8 @@ to by @var{ce_info}.
|
|
|
|
@hook TARGET_USE_LATE_PROLOGUE_EPILOGUE
|
|
|
|
+@hook TARGET_EMIT_EPILOGUE_FOR_SIBCALL
|
|
+
|
|
@hook TARGET_MACHINE_DEPENDENT_REORG
|
|
|
|
@hook TARGET_INIT_BUILTINS
|
|
diff --git a/gcc/function.cc b/gcc/function.cc
|
|
index eac179dd3..94afb266e 100644
|
|
--- a/gcc/function.cc
|
|
+++ b/gcc/function.cc
|
|
@@ -6217,7 +6217,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);
|
|
@@ -6267,7 +6277,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
|
|
diff --git a/gcc/target.def b/gcc/target.def
|
|
index d70363da5..609b2dff6 100644
|
|
--- a/gcc/target.def
|
|
+++ b/gcc/target.def
|
|
@@ -4084,6 +4084,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 @var{call}. Another way of providing epilogues\n\
|
|
+for sibling calls is to define the @code{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
|
|
--
|
|
2.19.1
|
|
|