@@ -11879,6 +11879,25 @@ of the if-block in the @code{struct ce_if_block} structure that is pointed
to by @var{ce_info}.
@end defmac
+@deftypefn {Target Hook} bool TARGET_USE_LATE_PROLOGUE_EPILOGUE ()
+Return true if the current function's prologue and epilogue should
+be emitted late in the pass pipeline, instead of at the usual point.
+
+Normally, the prologue and epilogue sequences are introduced soon after
+register allocation is complete. The advantage of this approach is that
+it allows the prologue and epilogue instructions to be optimized and
+scheduled with other code in the function. However, some targets
+require the prologue and epilogue to be the first and last sequences
+executed by the function, with no variation allowed. This hook should
+return true on such targets.
+
+The default implementation returns false, which is correct for most
+targets. The hook should only return true if there is a specific
+target limitation that cannot be described in RTL. For example,
+the hook might return true if the prologue and epilogue need to switch
+between instruction sets.
+@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,
@@ -7784,6 +7784,8 @@ of the if-block in the @code{struct ce_if_block} structure that is pointed
to by @var{ce_info}.
@end defmac
+@hook TARGET_USE_LATE_PROLOGUE_EPILOGUE
+
@hook TARGET_MACHINE_DEPENDENT_REORG
@hook TARGET_INIT_BUILTINS
@@ -84,6 +84,7 @@ along with GCC; see the file COPYING3. If not see
#include "function-abi.h"
#include "value-range.h"
#include "gimple-range.h"
+#include "insn-attr.h"
/* So we can assign to cfun in this file. */
#undef cfun
@@ -6629,6 +6630,11 @@ public:
{}
/* opt_pass methods: */
+ bool gate (function *) final override
+ {
+ return !targetm.use_late_prologue_epilogue ();
+ }
+
unsigned int execute (function * fun) final override
{
rest_of_handle_thread_prologue_and_epilogue (fun);
@@ -6637,6 +6643,44 @@ public:
}; // class pass_thread_prologue_and_epilogue
+const pass_data pass_data_late_thread_prologue_and_epilogue =
+{
+ RTL_PASS, /* type */
+ "late_pro_and_epilogue", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_THREAD_PROLOGUE_AND_EPILOGUE, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ ( TODO_df_verify | TODO_df_finish ), /* todo_flags_finish */
+};
+
+class pass_late_thread_prologue_and_epilogue : public rtl_opt_pass
+{
+public:
+ pass_late_thread_prologue_and_epilogue (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_late_thread_prologue_and_epilogue, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ bool gate (function *) final override
+ {
+ return targetm.use_late_prologue_epilogue ();
+ }
+
+ unsigned int execute (function *fn) final override
+ {
+ /* It's not currently possible to have both delay slots and
+ late prologue/epilogue, since the latter has to run before
+ the former, and the former won't honor whatever restrictions
+ the latter is trying to enforce. */
+ gcc_assert (!DELAY_SLOTS);
+ rest_of_handle_thread_prologue_and_epilogue (fn);
+ return 0;
+ }
+}; // class pass_late_thread_prologue_and_epilogue
+
} // anon namespace
rtl_opt_pass *
@@ -6645,6 +6689,12 @@ make_pass_thread_prologue_and_epilogue (gcc::context *ctxt)
return new pass_thread_prologue_and_epilogue (ctxt);
}
+rtl_opt_pass *
+make_pass_late_thread_prologue_and_epilogue (gcc::context *ctxt)
+{
+ return new pass_late_thread_prologue_and_epilogue (ctxt);
+}
+
namespace {
const pass_data pass_data_zero_call_used_regs =
@@ -533,6 +533,9 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_stack_regs_run);
POP_INSERT_PASSES ()
POP_INSERT_PASSES ()
+ NEXT_PASS (pass_late_thread_prologue_and_epilogue);
+ /* No target-independent code motion is allowed beyond this point,
+ excepting the legacy delayed-branch pass. */
NEXT_PASS (pass_late_compilation);
PUSH_INSERT_PASSES_WITHIN (pass_late_compilation)
NEXT_PASS (pass_zero_call_used_regs);
@@ -4153,6 +4153,27 @@ returns @code{VOIDmode}.",
machine_mode, (machine_mode m1, machine_mode m2),
default_cc_modes_compatible)
+DEFHOOK
+(use_late_prologue_epilogue,
+ "Return true if the current function's prologue and epilogue should\n\
+be emitted late in the pass pipeline, instead of at the usual point.\n\
+\n\
+Normally, the prologue and epilogue sequences are introduced soon after\n\
+register allocation is complete. The advantage of this approach is that\n\
+it allows the prologue and epilogue instructions to be optimized and\n\
+scheduled with other code in the function. However, some targets\n\
+require the prologue and epilogue to be the first and last sequences\n\
+executed by the function, with no variation allowed. This hook should\n\
+return true on such targets.\n\
+\n\
+The default implementation returns false, which is correct for most\n\
+targets. The hook should only return true if there is a specific\n\
+target limitation that cannot be described in RTL. For example,\n\
+the hook might return true if the prologue and epilogue need to switch\n\
+between instruction sets.",
+ bool, (),
+ hook_bool_void_false)
+
/* Do machine-dependent code transformations. Called just before
delayed-branch scheduling. */
DEFHOOK
@@ -616,6 +616,8 @@ extern rtl_opt_pass *make_pass_gcse2 (gcc::context *ctxt);
extern rtl_opt_pass *make_pass_split_after_reload (gcc::context *ctxt);
extern rtl_opt_pass *make_pass_thread_prologue_and_epilogue (gcc::context
*ctxt);
+extern rtl_opt_pass *make_pass_late_thread_prologue_and_epilogue (gcc::context
+ *ctxt);
extern rtl_opt_pass *make_pass_zero_call_used_regs (gcc::context *ctxt);
extern rtl_opt_pass *make_pass_stack_adjustments (gcc::context *ctxt);
extern rtl_opt_pass *make_pass_sched_fusion (gcc::context *ctxt);