diff --git a/gcc/doc/gccint/target-macros/miscellaneous-parameters.rst b/gcc/doc/gccint/target-macros/miscellaneous-parameters.rst
index e4e348c2adc..b48f91d3fd2 100644
--- a/gcc/doc/gccint/target-macros/miscellaneous-parameters.rst
+++ b/gcc/doc/gccint/target-macros/miscellaneous-parameters.rst
@@ -551,6 +551,11 @@ Here are several miscellaneous parameters.
   of the if-block in the ``struct ce_if_block`` structure that is pointed
   to by :samp:`{ce_info}`.
 
+.. include:: tm.rst.in
+  :start-after: [TARGET_USE_LATE_PROLOGUE_EPILOGUE]
+  :end-before: [TARGET_USE_LATE_PROLOGUE_EPILOGUE]
+
+
 .. include:: tm.rst.in
   :start-after: [TARGET_MACHINE_DEPENDENT_REORG]
   :end-before: [TARGET_MACHINE_DEPENDENT_REORG]
diff --git a/gcc/doc/gccint/target-macros/tm.rst.in b/gcc/doc/gccint/target-macros/tm.rst.in
index 44f3a3b2222..2e789f8723d 100644
--- a/gcc/doc/gccint/target-macros/tm.rst.in
+++ b/gcc/doc/gccint/target-macros/tm.rst.in
@@ -3702,6 +3702,28 @@
 
 [TARGET_CC_MODES_COMPATIBLE]
 
+[TARGET_USE_LATE_PROLOGUE_EPILOGUE]
+.. function:: 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.
+
+[TARGET_USE_LATE_PROLOGUE_EPILOGUE]
+
 [TARGET_MACHINE_DEPENDENT_REORG]
 .. function:: void TARGET_MACHINE_DEPENDENT_REORG (void)
 
diff --git a/gcc/function.cc b/gcc/function.cc
index b54a1d81a3b..3b1ab5d09e5 100644
--- a/gcc/function.cc
+++ b/gcc/function.cc
@@ -6641,6 +6641,11 @@ public:
   {}
 
   /* opt_pass methods: */
+  bool gate (function *) final override
+    {
+      return !targetm.use_late_prologue_epilogue ();
+    }
+
   unsigned int execute (function *) final override
     {
       return rest_of_handle_thread_prologue_and_epilogue ();
@@ -6648,6 +6653,38 @@ 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 *) final override
+    {
+      return rest_of_handle_thread_prologue_and_epilogue ();
+    }
+}; // class pass_late_thread_prologue_and_epilogue
+
 } // anon namespace
 
 rtl_opt_pass *
@@ -6656,6 +6693,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 =
diff --git a/gcc/passes.def b/gcc/passes.def
index 193b5794749..822d5713f53 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -518,6 +518,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);
diff --git a/gcc/target.def b/gcc/target.def
index aed1c1d3e22..8b8aef982e8 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -4062,6 +4062,27 @@ returns ``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
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 8480d41384b..63177764ffa 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -612,6 +612,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);
