Index: gcc/dwarf2out.c
===================================================================
--- gcc.orig/dwarf2out.c
+++ gcc/dwarf2out.c
@@ -470,6 +470,8 @@ static void output_call_frame_info (int)
 static void dwarf2out_note_section_used (void);
 static bool clobbers_queued_reg_save (const_rtx);
 static void dwarf2out_frame_debug_expr (rtx, const char *);
+static void dwarf2out_cfi_begin_epilogue (rtx);
+static void dwarf2out_frame_debug_restore_state (void);
 
 /* Support for complex CFA locations.  */
 static void output_cfa_loc (dw_cfi_ref, int);
@@ -847,6 +849,15 @@ add_cfi (cfi_vec *vec, dw_cfi_ref cfi)
   VEC_safe_push (dw_cfi_ref, gc, *vec, cfi);
 }
 
+/* The insn after which a new CFI note should be emitted.  */
+static rtx cfi_insn;
+
+/* True if remember_state should be emitted before following CFI directive.  */
+static bool emit_cfa_remember;
+
+/* True if any CFI directives were emitted at the current insn.  */
+static bool any_cfis_emitted;
+
 /* Generate a new label for the CFI info to refer to.  FORCE is true
    if a label needs to be output even when using .cfi_* directives.  */
 
@@ -866,18 +877,13 @@ dwarf2out_cfi_label (bool force)
     {
       int num = dwarf2out_cfi_label_num++;
       ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", num);
-      ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LCFI", num);
+      cfi_insn = emit_note_after (NOTE_INSN_CFI_LABEL, cfi_insn);
+      NOTE_LABEL_NUMBER (cfi_insn) = num;
     }
 
   return label;
 }
 
-/* True if remember_state should be emitted before following CFI directive.  */
-static bool emit_cfa_remember;
-
-/* True if any CFI directives were emitted at the current insn.  */
-static bool any_cfis_emitted;
-
 /* Add CFI to the current fde at the PC value indicated by LABEL if specified,
    or to the CIE if LABEL is NULL.  */
 
@@ -957,7 +963,8 @@ add_fde_cfi (const char *label, dw_cfi_r
 	        }
 	    }
 
-	  output_cfi_directive (cfi);
+	  cfi_insn = emit_note_after (NOTE_INSN_CFI, cfi_insn);
+	  NOTE_CFI (cfi_insn) = cfi;
 
 	  vec = &fde->dw_fde_cfi;
 	  any_cfis_emitted = true;
@@ -2791,6 +2798,11 @@ dwarf2out_frame_debug (rtx insn, bool af
   rtx note, n;
   bool handled_one = false;
 
+  if (after_p)
+    cfi_insn = insn;
+  else
+    cfi_insn = PREV_INSN (insn);
+
   if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn))
     dwarf2out_flush_queued_reg_saves ();
 
@@ -2914,6 +2926,7 @@ void
 dwarf2out_frame_debug_init (void)
 {
   size_t i;
+  rtx insn;
 
   /* Flush any queued register saves.  */
   dwarf2out_flush_queued_reg_saves ();
@@ -2940,12 +2953,64 @@ dwarf2out_frame_debug_init (void)
       XDELETEVEC (barrier_args_size);
       barrier_args_size = NULL;
     }
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      rtx pat;
+      if (BARRIER_P (insn))
+	{
+	  dwarf2out_frame_debug (insn, false);
+	  continue;
+	}
+      else if (NOTE_P (insn))
+	{
+	  switch (NOTE_KIND (insn))
+	    {
+	    case NOTE_INSN_EPILOGUE_BEG:
+#if defined (HAVE_epilogue)
+	      dwarf2out_cfi_begin_epilogue (insn);
+#endif
+	      break;
+	    case NOTE_INSN_CFA_RESTORE_STATE:
+	      cfi_insn = insn;
+	      dwarf2out_frame_debug_restore_state ();
+	      break;
+	    }
+	  continue;
+	}
+      if (!NONDEBUG_INSN_P (insn))
+	continue;
+      pat = PATTERN (insn);
+      if (asm_noperands (pat) >= 0)
+	continue;
+      if (GET_CODE (pat) == SEQUENCE)
+	{
+	  int j;
+	  for (j = 1; j < XVECLEN (pat, 0); j++)
+	    dwarf2out_frame_debug (XVECEXP (pat, 0, j), false);
+	  insn = XVECEXP (pat, 0, 0);
+	}
+
+      if (CALL_P (insn) && dwarf2out_do_frame ())
+	dwarf2out_frame_debug (insn, false);
+      if (dwarf2out_do_frame ()
+#if !defined (HAVE_prologue)
+	  && !ACCUMULATE_OUTGOING_ARGS
+#endif
+	  )
+	dwarf2out_frame_debug (insn, true);
+    }
+}
+
+void
+dwarf2out_emit_cfi (dw_cfi_ref cfi)
+{
+  output_cfi_directive (cfi);
 }
 
-/* Determine if we need to save and restore CFI information around this
-   epilogue.  If SIBCALL is true, then this is a sibcall epilogue.  If
-   we do need to save/restore, then emit the save now, and insert a
-   NOTE_INSN_CFA_RESTORE_STATE at the appropriate place in the stream.  */
+/* Determine if we need to save and restore CFI information around
+   this epilogue.  If we do need to save/restore, then emit the save
+   now, and insert a NOTE_INSN_CFA_RESTORE_STATE at the appropriate
+   place in the stream.  */
 
 void
 dwarf2out_cfi_begin_epilogue (rtx insn)
@@ -2960,8 +3025,10 @@ dwarf2out_cfi_begin_epilogue (rtx insn)
       if (!INSN_P (i))
 	continue;
 
-      /* Look for both regular and sibcalls to end the block.  */
-      if (returnjump_p (i))
+      /* Look for both regular and sibcalls to end the block.  Various
+	 optimization passes may cause us to jump to a common epilogue
+	 tail, so we also accept simplejumps.  */
+      if (returnjump_p (i) || simplejump_p (i))
 	break;
       if (CALL_P (i) && SIBLING_CALL_P (i))
 	break;
Index: gcc/dwarf2out.h
===================================================================
--- gcc.orig/dwarf2out.h
+++ gcc/dwarf2out.h
@@ -18,11 +18,11 @@ You should have received a copy of the G
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+struct dw_cfi_struct;
 extern void dwarf2out_decl (tree);
 extern void dwarf2out_frame_debug (rtx, bool);
 extern void dwarf2out_frame_debug_init (void);
-extern void dwarf2out_cfi_begin_epilogue (rtx);
-extern void dwarf2out_frame_debug_restore_state (void);
+extern void dwarf2out_emit_cfi (struct dw_cfi_struct *);
 extern void dwarf2out_flush_queued_reg_saves (void);
 
 extern void debug_dwarf (void);
Index: gcc/insn-notes.def
===================================================================
--- gcc.orig/insn-notes.def
+++ gcc/insn-notes.def
@@ -77,4 +77,12 @@ INSN_NOTE (SWITCH_TEXT_SECTIONS)
    when an epilogue appears in the middle of a function.  */
 INSN_NOTE (CFA_RESTORE_STATE)
 
+/* When emitting dwarf2 frame information, contains a directive that
+   should be emitted.  */
+INSN_NOTE (CFI)
+
+/* When emitting dwarf2 frame information, contains the number of a debug
+   label that should be emitted.  */
+INSN_NOTE (CFI_LABEL)
+
 #undef INSN_NOTE
Index: gcc/rtl.h
===================================================================
--- gcc.orig/rtl.h
+++ gcc/rtl.h
@@ -180,6 +180,7 @@ union rtunion_def
   mem_attrs *rt_mem;
   reg_attrs *rt_reg;
   struct constant_descriptor_rtx *rt_constant;
+  struct dw_cfi_struct *rt_cfi;
 };
 typedef union rtunion_def rtunion;
 
@@ -708,6 +709,7 @@ extern void rtl_check_failed_flag (const
 #define XTREE(RTX, N)   (RTL_CHECK1 (RTX, N, 't').rt_tree)
 #define XBBDEF(RTX, N)	(RTL_CHECK1 (RTX, N, 'B').rt_bb)
 #define XTMPL(RTX, N)	(RTL_CHECK1 (RTX, N, 'T').rt_str)
+#define XCFI(RTX, N)	(RTL_CHECK1 (RTX, N, 'C').rt_cfi)
 
 #define XVECEXP(RTX, N, M)	RTVEC_ELT (XVEC (RTX, N), M)
 #define XVECLEN(RTX, N)		GET_NUM_ELEM (XVEC (RTX, N))
@@ -740,6 +742,7 @@ extern void rtl_check_failed_flag (const
 #define XCMODE(RTX, N, C)     (RTL_CHECKC1 (RTX, N, C).rt_type)
 #define XCTREE(RTX, N, C)     (RTL_CHECKC1 (RTX, N, C).rt_tree)
 #define XCBBDEF(RTX, N, C)    (RTL_CHECKC1 (RTX, N, C).rt_bb)
+#define XCCFI(RTX, N, C)      (RTL_CHECKC1 (RTX, N, C).rt_cfi)
 #define XCCSELIB(RTX, N, C)   (RTL_CHECKC1 (RTX, N, C).rt_cselib)
 
 #define XCVECEXP(RTX, N, M, C)	RTVEC_ELT (XCVEC (RTX, N, C), M)
@@ -882,6 +885,8 @@ extern const char * const reg_note_name[
 #define NOTE_BLOCK(INSN)	XCTREE (INSN, 4, NOTE)
 #define NOTE_EH_HANDLER(INSN)	XCINT (INSN, 4, NOTE)
 #define NOTE_BASIC_BLOCK(INSN)	XCBBDEF (INSN, 4, NOTE)
+#define NOTE_CFI(INSN)		XCCFI (INSN, 4, NOTE)
+#define NOTE_LABEL_NUMBER(INSN)	XCINT (INSN, 4, NOTE)
 #define NOTE_VAR_LOCATION(INSN)	XCEXP (INSN, 4, NOTE)
 
 /* In a NOTE that is a line number, this is the line number.
Index: gcc/final.c
===================================================================
--- gcc.orig/final.c
+++ gcc/final.c
@@ -1678,7 +1678,7 @@ final_end_function (void)
 void
 final (rtx first, FILE *file, int optimize_p)
 {
-  rtx insn;
+  rtx insn, next;
   int max_uid = 0;
   int seen = 0;
 
@@ -1723,6 +1723,15 @@ final (rtx first, FILE *file, int optimi
 
       insn = final_scan_insn (insn, file, optimize_p, 0, &seen);
     }
+
+  for (insn = first; insn; insn = next)
+    {
+      next = NEXT_INSN (insn);
+      if (NOTE_P (insn)
+	  && (NOTE_KIND (insn) == NOTE_INSN_CFI
+	      || NOTE_KIND (insn) == NOTE_INSN_CFI_LABEL))
+	delete_insn (insn);
+    }
 }
 
 const char *
@@ -1899,16 +1908,19 @@ final_scan_insn (rtx insn, FILE *file, i
 	  break;
 
 	case NOTE_INSN_EPILOGUE_BEG:
-#if defined (HAVE_epilogue)
-	  if (dwarf2out_do_frame ())
-	    dwarf2out_cfi_begin_epilogue (insn);
-#endif
 	  (*debug_hooks->begin_epilogue) (last_linenum, last_filename);
 	  targetm.asm_out.function_begin_epilogue (file);
 	  break;
 
 	case NOTE_INSN_CFA_RESTORE_STATE:
-	  dwarf2out_frame_debug_restore_state ();
+	  break;
+
+	case NOTE_INSN_CFI:
+	  dwarf2out_emit_cfi (NOTE_CFI (insn));
+	  break;
+
+	case NOTE_INSN_CFI_LABEL:
+	  ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LCFI", NOTE_LABEL_NUMBER (insn));
 	  break;
 
 	case NOTE_INSN_FUNCTION_BEG:
@@ -2018,8 +2030,6 @@ final_scan_insn (rtx insn, FILE *file, i
       break;
 
     case BARRIER:
-      if (dwarf2out_do_frame ())
-	dwarf2out_frame_debug (insn, false);
       break;
 
     case CODE_LABEL:
@@ -2285,12 +2295,6 @@ final_scan_insn (rtx insn, FILE *file, i
 
 	    final_sequence = body;
 
-	    /* Record the delay slots' frame information before the branch.
-	       This is needed for delayed calls: see execute_cfa_program().  */
-	    if (dwarf2out_do_frame ())
-	      for (i = 1; i < XVECLEN (body, 0); i++)
-		dwarf2out_frame_debug (XVECEXP (body, 0, i), false);
-
 	    /* The first insn in this SEQUENCE might be a JUMP_INSN that will
 	       force the restoration of a comparison that was previously
 	       thought unnecessary.  If that happens, cancel this sequence
@@ -2604,9 +2608,6 @@ final_scan_insn (rtx insn, FILE *file, i
 
 	current_output_insn = debug_insn = insn;
 
-	if (CALL_P (insn) && dwarf2out_do_frame ())
-	  dwarf2out_frame_debug (insn, false);
-
 	/* Find the proper template for this insn.  */
 	templ = get_insn_template (insn_code_number, insn);
 
@@ -2686,16 +2687,6 @@ final_scan_insn (rtx insn, FILE *file, i
 	  targetm.asm_out.final_postscan_insn (file, insn, recog_data.operand,
 					       recog_data.n_operands);
 
-	/* If necessary, report the effect that the instruction has on
-	   the unwind info.   We've already done this for delay slots
-	   and call instructions.  */
-	if (final_sequence == 0
-#if !defined (HAVE_prologue)
-	    && !ACCUMULATE_OUTGOING_ARGS
-#endif
-	    && dwarf2out_do_frame ())
-	  dwarf2out_frame_debug (insn, true);
-
 	if (!targetm.asm_out.unwind_emit_before_insn
 	    && targetm.asm_out.unwind_emit)
 	  targetm.asm_out.unwind_emit (asm_out_file, insn);
