Patchwork [3/6] Allow jumps in epilogues

login
register
mail settings
Submitter Bernd Schmidt
Date April 13, 2011, 3:13 p.m.
Message ID <4DA5BDB5.3030906@codesourcery.com>
Download mbox | patch
Permalink /patch/91026/
State New
Headers show

Comments

Bernd Schmidt - April 13, 2011, 3:13 p.m.
The second part is a new patch, which reduces the amount of different
code paths we can take in add_fde_cfi, as this was becoming
unmanageable. The concept is to first emit just the CFI notes, in all
cases. Later, after we're done producing the CFI insns we need, another
pass over the rtl adds the necessary labels and set_loc/advance_loc
CFIs. One consequence of this is that def_cfa_1 can no longer use
lookup_cfa, so it just compares to an old_cfa variable instead. This
also requires target-specific changes as some ports use
dwarf2out_cfi_label. An (untested) example of the necessary changes is
in config/arm.


Bernd
---
 config/arm/arm.c     |    5 
 config/ia64/ia64.c   |    6 
 config/sparc/sparc.c |    7 
 config/vax/vax.c     |    2 
 dwarf2out.c          |  467 ++++++++++++++++++++++++---------------------------
 dwarf2out.h          |   32 +++
 final.c              |    5 
 target.def           |    2 
 tree.h               |   31 ---
 9 files changed, 270 insertions(+), 287 deletions(-)

Patch

Index: gcc/config/arm/arm.c
===================================================================
--- gcc.orig/config/arm/arm.c
+++ gcc/config/arm/arm.c
@@ -19977,18 +19977,19 @@  thumb_pushpop (FILE *f, unsigned long ma
 
   if (push && pushed_words && dwarf2out_do_frame ())
     {
-      char *l = dwarf2out_cfi_label (false);
       int pushed_mask = real_regs;
 
+      dwarf2out_maybe_emit_cfi_label ();
+
       *cfa_offset += pushed_words * 4;
-      dwarf2out_def_cfa (l, SP_REGNUM, *cfa_offset);
+      dwarf2out_def_cfa (SP_REGNUM, *cfa_offset);
 
       pushed_words = 0;
       pushed_mask = real_regs;
       for (regno = 0; regno <= 14; regno++, pushed_mask >>= 1)
 	{
 	  if (pushed_mask & 1)
-	    dwarf2out_reg_save (l, regno, 4 * pushed_words++ - *cfa_offset);
+	    dwarf2out_reg_save (regno, 4 * pushed_words++ - *cfa_offset);
 	}
     }
 }
@@ -20997,10 +20998,9 @@  thumb1_output_function_prologue (FILE *f
 	 the stack pointer.  */
       if (dwarf2out_do_frame ())
 	{
-	  char *l = dwarf2out_cfi_label (false);
-
+	  dwarf2out_maybe_emit_cfi_label ();
 	  cfa_offset = cfa_offset + crtl->args.pretend_args_size;
-	  dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
+	  dwarf2out_def_cfa (SP_REGNUM, cfa_offset);
 	}
     }
 
@@ -21046,10 +21046,10 @@  thumb1_output_function_prologue (FILE *f
 
       if (dwarf2out_do_frame ())
 	{
-	  char *l = dwarf2out_cfi_label (false);
+	  dwarf2out_maybe_emit_cfi_label ();
 
 	  cfa_offset = cfa_offset + 16;
-	  dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
+	  dwarf2out_def_cfa (SP_REGNUM, cfa_offset);
 	}
 
       if (l_mask)
@@ -22749,7 +22749,7 @@  arm_except_unwind_info (struct gcc_optio
    stack alignment.  */
 
 static void
-arm_dwarf_handle_frame_unspec (const char *label, rtx pattern, int index)
+arm_dwarf_handle_frame_unspec (rtx pattern, int index)
 {
   rtx unspec = SET_SRC (pattern);
   gcc_assert (GET_CODE (unspec) == UNSPEC);
@@ -22760,8 +22760,7 @@  arm_dwarf_handle_frame_unspec (const cha
       /* ??? We should set the CFA = (SP & ~7).  At this point we haven't
          put anything on the stack, so hopefully it won't matter.
          CFA = SP will be correct after alignment.  */
-      dwarf2out_reg_save_reg (label, stack_pointer_rtx,
-                              SET_DEST (pattern));
+      dwarf2out_reg_save_reg (stack_pointer_rtx, SET_DEST (pattern));
       break;
     default:
       gcc_unreachable ();
Index: gcc/config/ia64/ia64.c
===================================================================
--- gcc.orig/config/ia64/ia64.c
+++ gcc/config/ia64/ia64.c
@@ -330,7 +330,7 @@  static enum machine_mode ia64_promote_fu
 static void ia64_trampoline_init (rtx, tree, rtx);
 static void ia64_override_options_after_change (void);
 
-static void ia64_dwarf_handle_frame_unspec (const char *, rtx, int);
+static void ia64_dwarf_handle_frame_unspec (rtx, int);
 static tree ia64_builtin_decl (unsigned, bool);
 
 static reg_class_t ia64_preferred_reload_class (rtx, reg_class_t);
@@ -9710,9 +9710,7 @@  ia64_dwarf2out_def_steady_cfa (rtx insn,
    processing.  The real CFA definition is set up above.  */
 
 static void
-ia64_dwarf_handle_frame_unspec (const char * ARG_UNUSED (label),
-				rtx ARG_UNUSED (pattern),
-				int index)
+ia64_dwarf_handle_frame_unspec (rtx ARG_UNUSED (pattern), int index)
 {
   gcc_assert (index == UNSPECV_ALLOC);
 }
Index: gcc/config/sparc/sparc.c
===================================================================
--- gcc.orig/config/sparc/sparc.c
+++ gcc/config/sparc/sparc.c
@@ -454,7 +454,7 @@  static unsigned int sparc_function_arg_b
 						 const_tree);
 static int sparc_arg_partial_bytes (CUMULATIVE_ARGS *,
 				    enum machine_mode, tree, bool);
-static void sparc_dwarf_handle_frame_unspec (const char *, rtx, int);
+static void sparc_dwarf_handle_frame_unspec (rtx, int);
 static void sparc_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
 static void sparc_file_end (void);
 static bool sparc_frame_pointer_required (void);
@@ -9423,12 +9423,11 @@  get_some_local_dynamic_name_1 (rtx *px, 
    This is called from dwarf2out.c to emit call frame instructions
    for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs. */
 static void
-sparc_dwarf_handle_frame_unspec (const char *label,
-				 rtx pattern ATTRIBUTE_UNUSED,
+sparc_dwarf_handle_frame_unspec (rtx pattern ATTRIBUTE_UNUSED,
 				 int index ATTRIBUTE_UNUSED)
 {
   gcc_assert (index == UNSPECV_SAVEW);
-  dwarf2out_window_save (label);
+  dwarf2out_window_save ();
 }
 
 /* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
Index: gcc/config/vax/vax.c
===================================================================
--- gcc.orig/config/vax/vax.c
+++ gcc/config/vax/vax.c
@@ -163,17 +163,18 @@  vax_output_function_prologue (FILE * fil
 
   if (dwarf2out_do_frame ())
     {
-      const char *label = dwarf2out_cfi_label (false);
       int offset = 0;
 
+      dwarf2out_maybe_emit_cfi_label ();
+
       for (regno = FIRST_PSEUDO_REGISTER-1; regno >= 0; --regno)
 	if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
-	  dwarf2out_reg_save (label, regno, offset -= 4);
+	  dwarf2out_reg_save (regno, offset -= 4);
 
-      dwarf2out_reg_save (label, PC_REGNUM, offset -= 4);
-      dwarf2out_reg_save (label, FRAME_POINTER_REGNUM, offset -= 4);
-      dwarf2out_reg_save (label, ARG_POINTER_REGNUM, offset -= 4);
-      dwarf2out_def_cfa (label, FRAME_POINTER_REGNUM, -(offset - 4));
+      dwarf2out_reg_save (PC_REGNUM, offset -= 4);
+      dwarf2out_reg_save (FRAME_POINTER_REGNUM, offset -= 4);
+      dwarf2out_reg_save (ARG_POINTER_REGNUM, offset -= 4);
+      dwarf2out_def_cfa (false, FRAME_POINTER_REGNUM, -(offset - 4));
     }
 
   size -= STARTING_FRAME_OFFSET;
Index: gcc/dwarf2out.c
===================================================================
--- gcc.orig/dwarf2out.c
+++ gcc/dwarf2out.c
@@ -456,11 +456,11 @@  static GTY(()) section *cold_text_sectio
 static char *stripattributes (const char *);
 static const char *dwarf_cfi_name (unsigned);
 static dw_cfi_ref new_cfi (void);
-static void add_cfi (cfi_vec *, dw_cfi_ref);
-static void add_fde_cfi (const char *, dw_cfi_ref);
+static void add_fde_cfi (dw_cfi_ref);
+static void add_cie_cfi (dw_cfi_ref);
 static void lookup_cfa_1 (dw_cfi_ref, dw_cfa_location *, dw_cfa_location *);
 static void lookup_cfa (dw_cfa_location *);
-static void reg_save (const char *, unsigned, unsigned, HOST_WIDE_INT);
+static void reg_save (bool, unsigned, unsigned, HOST_WIDE_INT);
 static void initial_return_save (rtx);
 static HOST_WIDE_INT stack_adjust_offset (const_rtx, HOST_WIDE_INT,
 					  HOST_WIDE_INT);
@@ -469,7 +469,7 @@  static void output_cfi_directive (dw_cfi
 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_frame_debug_expr (rtx);
 static void dwarf2out_cfi_begin_epilogue (rtx);
 static void dwarf2out_frame_debug_restore_state (void);
 
@@ -482,7 +482,7 @@  static struct dw_loc_descr_struct *build
   (dw_cfa_location *, HOST_WIDE_INT);
 static struct dw_loc_descr_struct *build_cfa_aligned_loc
   (HOST_WIDE_INT, HOST_WIDE_INT);
-static void def_cfa_1 (const char *, dw_cfa_location *);
+static void def_cfa_1 (bool, dw_cfa_location *);
 static struct dw_loc_descr_struct *mem_loc_descriptor
   (rtx, enum machine_mode mode, enum var_init_status);
 
@@ -820,35 +820,6 @@  new_cfi (void)
   return cfi;
 }
 
-/* Add a Call Frame Instruction to list of instructions.  */
-
-static inline void
-add_cfi (cfi_vec *vec, dw_cfi_ref cfi)
-{
-  dw_fde_ref fde = current_fde ();
-
-  /* When DRAP is used, CFA is defined with an expression.  Redefine
-     CFA may lead to a different CFA value.   */
-  /* ??? Of course, this heuristic fails when we're annotating epilogues,
-     because of course we'll always want to redefine the CFA back to the
-     stack pointer on the way out.  Where should we move this check?  */
-  if (0 && fde && fde->drap_reg != INVALID_REGNUM)
-    switch (cfi->dw_cfi_opc)
-      {
-        case DW_CFA_def_cfa_register:
-        case DW_CFA_def_cfa_offset:
-        case DW_CFA_def_cfa_offset_sf:
-        case DW_CFA_def_cfa:
-        case DW_CFA_def_cfa_sf:
-	  gcc_unreachable ();
-
-        default:
-          break;
-      }
-
-  VEC_safe_push (dw_cfi_ref, gc, *vec, cfi);
-}
-
 /* The insn after which a new CFI note should be emitted.  */
 static rtx cfi_insn;
 
@@ -858,45 +829,51 @@  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.  */
+/* Generate a new label for the CFI info to refer to.  */
 
-char *
-dwarf2out_cfi_label (bool force)
+static char *
+dwarf2out_cfi_label (void)
 {
   static char label[20];
 
-  if (!force && dwarf2out_do_cfi_asm ())
-    {
-      /* In this case, we will be emitting the asm directive instead of
-	 the label, so just return a placeholder to keep the rest of the
-	 interfaces happy.  */
-      strcpy (label, "<do not output>");
-    }
-  else
-    {
-      int num = dwarf2out_cfi_label_num++;
-      ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", num);
-      cfi_insn = emit_note_after (NOTE_INSN_CFI_LABEL, cfi_insn);
-      NOTE_LABEL_NUMBER (cfi_insn) = num;
-    }
+  int num = dwarf2out_cfi_label_num++;
+  ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", num);
 
   return label;
 }
 
+/* Called by target specific code if it wants to emit CFI insns in the text
+   prologue.  If necessary, emit a CFI label and an advance_loc CFI.  See
+   also cfi_label_required_p.  */
+void
+dwarf2out_maybe_emit_cfi_label (void)
+{
+  if ((dwarf_version == 2
+       && debug_info_level > DINFO_LEVEL_TERSE
+       && (write_symbols == DWARF2_DEBUG
+	   || write_symbols == VMS_AND_DWARF2_DEBUG))
+      || !dwarf2out_do_cfi_asm ())
+    {
+      const char *l;
+      dw_cfi_ref xcfi;
+
+      ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LCFI", dwarf2out_cfi_label_num);
+      l = dwarf2out_cfi_label ();
+      l = xstrdup (l);
+
+      xcfi = new_cfi ();
+      xcfi->dw_cfi_opc = DW_CFA_advance_loc4;
+      xcfi->dw_cfi_oprnd1.dw_cfi_addr = l;
+      add_fde_cfi (xcfi);
+    }
+}
+
 /* Add CFI to the current fde at the PC value indicated by LABEL if specified,
    or to the CIE if LABEL is NULL.  */
 
 static void
-add_fde_cfi (const char *label, dw_cfi_ref cfi)
+add_fde_cfi (dw_cfi_ref cfi)
 {
-  cfi_vec *vec;
-
-  if (cie_cfi_vec == NULL)
-    cie_cfi_vec = VEC_alloc (dw_cfi_ref, gc, 20);
-
-  vec = &cie_cfi_vec;
-
   if (emit_cfa_remember)
     {
       dw_cfi_ref cfi_remember;
@@ -905,110 +882,30 @@  add_fde_cfi (const char *label, dw_cfi_r
       emit_cfa_remember = false;
       cfi_remember = new_cfi ();
       cfi_remember->dw_cfi_opc = DW_CFA_remember_state;
-      add_fde_cfi (label, cfi_remember);
+      add_fde_cfi (cfi_remember);
     }
 
-  if (dwarf2out_do_cfi_asm ())
+  any_cfis_emitted = true;
+  if (cfi_insn != NULL)
     {
-      if (label)
-	{
-	  dw_fde_ref fde = current_fde ();
-
-	  gcc_assert (fde != NULL);
-
-	  /* We still have to add the cfi to the list so that lookup_cfa
-	     works later on.  When -g2 and above we even need to force
-	     emitting of CFI labels and add to list a DW_CFA_set_loc for
-	     convert_cfa_to_fb_loc_list purposes.  If we're generating
-	     DWARF3 output we use DW_OP_call_frame_cfa and so don't use
-	     convert_cfa_to_fb_loc_list.  */
-	  if (dwarf_version == 2
-	      && debug_info_level > DINFO_LEVEL_TERSE
-	      && (write_symbols == DWARF2_DEBUG
-		  || write_symbols == VMS_AND_DWARF2_DEBUG))
-	    {
-	      switch (cfi->dw_cfi_opc)
-		{
-		case DW_CFA_def_cfa_offset:
-		case DW_CFA_def_cfa_offset_sf:
-		case DW_CFA_def_cfa_register:
-		case DW_CFA_def_cfa:
-		case DW_CFA_def_cfa_sf:
-		case DW_CFA_def_cfa_expression:
-		case DW_CFA_restore_state:
-		  if (*label == 0 || strcmp (label, "<do not output>") == 0)
-		    label = dwarf2out_cfi_label (true);
-
-		  if (fde->dw_fde_current_label == NULL
-		      || strcmp (label, fde->dw_fde_current_label) != 0)
-		    {
-		      dw_cfi_ref xcfi;
-
-		      label = xstrdup (label);
-
-		      /* Set the location counter to the new label.  */
-		      xcfi = new_cfi ();
-		      /* It doesn't metter whether DW_CFA_set_loc
-		         or DW_CFA_advance_loc4 is added here, those aren't
-		         emitted into assembly, only looked up by
-		         convert_cfa_to_fb_loc_list.  */
-		      xcfi->dw_cfi_opc = DW_CFA_set_loc;
-		      xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
-		      add_cfi (&fde->dw_fde_cfi, xcfi);
-		      fde->dw_fde_current_label = label;
-		    }
-		  break;
-		default:
-		  break;
-	        }
-	    }
-
-	  cfi_insn = emit_note_after (NOTE_INSN_CFI, cfi_insn);
-	  NOTE_CFI (cfi_insn) = cfi;
-
-	  vec = &fde->dw_fde_cfi;
-	  any_cfis_emitted = true;
-	}
-      /* ??? If this is a CFI for the CIE, we don't emit.  This
-	 assumes that the standard CIE contents that the assembler
-	 uses matches the standard CIE contents that the compiler
-	 uses.  This is probably a bad assumption.  I'm not quite
-	 sure how to address this for now.  */
+      cfi_insn = emit_note_after (NOTE_INSN_CFI, cfi_insn);
+      NOTE_CFI (cfi_insn) = cfi;
     }
-  else if (label)
+  else
     {
       dw_fde_ref fde = current_fde ();
-
-      gcc_assert (fde != NULL);
-
-      if (*label == 0)
-	label = dwarf2out_cfi_label (false);
-
-      if (fde->dw_fde_current_label == NULL
-	  || strcmp (label, fde->dw_fde_current_label) != 0)
-	{
-	  dw_cfi_ref xcfi;
-
-	  label = xstrdup (label);
-
-	  /* Set the location counter to the new label.  */
-	  xcfi = new_cfi ();
-	  /* If we have a current label, advance from there, otherwise
-	     set the location directly using set_loc.  */
-	  xcfi->dw_cfi_opc = fde->dw_fde_current_label
-			     ? DW_CFA_advance_loc4
-			     : DW_CFA_set_loc;
-	  xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
-	  add_cfi (&fde->dw_fde_cfi, xcfi);
-
-	  fde->dw_fde_current_label = label;
-	}
-
-      vec = &fde->dw_fde_cfi;
-      any_cfis_emitted = true;
+      VEC_safe_push (dw_cfi_ref, gc, fde->dw_fde_cfi, cfi);
+      dwarf2out_emit_cfi (cfi);
     }
+}
+
+static void
+add_cie_cfi (dw_cfi_ref cfi)
+{
+  if (cie_cfi_vec == NULL)
+    cie_cfi_vec = VEC_alloc (dw_cfi_ref, gc, 20);
 
-  add_cfi (vec, cfi);
+  VEC_safe_push (dw_cfi_ref, gc, cie_cfi_vec, cfi);
 }
 
 /* Subroutine of lookup_cfa.  */
@@ -1076,6 +973,9 @@  lookup_cfa (dw_cfa_location *loc)
 /* The current rule for calculating the DWARF2 canonical frame address.  */
 static dw_cfa_location cfa;
 
+/* A copy of CFA, for comparison purposes  */
+static dw_cfa_location old_cfa;
+
 /* The register used for saving registers to the stack, and its offset
    from the CFA.  */
 static dw_cfa_location cfa_store;
@@ -1083,25 +983,27 @@  static dw_cfa_location cfa_store;
 /* The current save location around an epilogue.  */
 static dw_cfa_location cfa_remember;
 
+/* Like cfa_remember, but a copy of old_cfa.  */
+static dw_cfa_location old_cfa_remember;
+
 /* The running total of the size of arguments pushed onto the stack.  */
 static HOST_WIDE_INT args_size;
 
 /* The last args_size we actually output.  */
 static HOST_WIDE_INT old_args_size;
 
-/* Entry point to update the canonical frame address (CFA).
-   LABEL is passed to add_fde_cfi.  The value of CFA is now to be
-   calculated from REG+OFFSET.  */
+/* Entry point to update the canonical frame address (CFA).  The value
+   of CFA is now to be calculated from REG+OFFSET.  */
 
 void
-dwarf2out_def_cfa (const char *label, unsigned int reg, HOST_WIDE_INT offset)
+dwarf2out_def_cfa (bool for_cie, unsigned int reg, HOST_WIDE_INT offset)
 {
   dw_cfa_location loc;
   loc.indirect = 0;
   loc.base_offset = 0;
   loc.reg = reg;
   loc.offset = offset;
-  def_cfa_1 (label, &loc);
+  def_cfa_1 (for_cie, &loc);
 }
 
 /* Determine if two dw_cfa_location structures define the same data.  */
@@ -1120,10 +1022,10 @@  cfa_equal_p (const dw_cfa_location *loc1
    the dw_cfa_location structure.  */
 
 static void
-def_cfa_1 (const char *label, dw_cfa_location *loc_p)
+def_cfa_1 (bool for_cie, dw_cfa_location *loc_p)
 {
   dw_cfi_ref cfi;
-  dw_cfa_location old_cfa, loc;
+  dw_cfa_location loc;
 
   cfa = *loc_p;
   loc = *loc_p;
@@ -1132,7 +1034,6 @@  def_cfa_1 (const char *label, dw_cfa_loc
     cfa_store.offset = loc.offset;
 
   loc.reg = DWARF_FRAME_REGNUM (loc.reg);
-  lookup_cfa (&old_cfa);
 
   /* If nothing changed, no need to issue any call frame instructions.  */
   if (cfa_equal_p (&loc, &old_cfa))
@@ -1193,16 +1094,19 @@  def_cfa_1 (const char *label, dw_cfa_loc
       cfi->dw_cfi_oprnd1.dw_cfi_loc = loc_list;
     }
 
-  add_fde_cfi (label, cfi);
+  if (for_cie)
+    add_cie_cfi (cfi);
+  else
+    add_fde_cfi (cfi);
+  old_cfa = loc;
 }
 
 /* Add the CFI for saving a register.  REG is the CFA column number.
-   LABEL is passed to add_fde_cfi.
    If SREG is -1, the register is saved at OFFSET from the CFA;
    otherwise it is saved in SREG.  */
 
 static void
-reg_save (const char *label, unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset)
+reg_save (bool for_cie, unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset)
 {
   dw_cfi_ref cfi = new_cfi ();
   dw_fde_ref fde = current_fde ();
@@ -1238,10 +1142,13 @@  reg_save (const char *label, unsigned in
       cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg;
     }
 
-  add_fde_cfi (label, cfi);
+  if (for_cie)
+    add_cie_cfi (cfi);
+  else
+    add_fde_cfi (cfi);
 }
 
-/* Add the CFI for saving a register window.  LABEL is passed to reg_save.
+/* Add the CFI for saving a register window.
    This CFI tells the unwinder that it needs to restore the window registers
    from the previous frame's window save area.
 
@@ -1249,39 +1156,39 @@  reg_save (const char *label, unsigned in
    assuming 0(cfa)) and what registers are in the window.  */
 
 void
-dwarf2out_window_save (const char *label)
+dwarf2out_window_save (void)
 {
   dw_cfi_ref cfi = new_cfi ();
 
   cfi->dw_cfi_opc = DW_CFA_GNU_window_save;
-  add_fde_cfi (label, cfi);
+  add_fde_cfi (cfi);
 }
 
 /* Entry point for saving a register to the stack.  REG is the GCC register
    number.  LABEL and OFFSET are passed to reg_save.  */
 
 void
-dwarf2out_reg_save (const char *label, unsigned int reg, HOST_WIDE_INT offset)
+dwarf2out_reg_save (unsigned int reg, HOST_WIDE_INT offset)
 {
-  reg_save (label, DWARF_FRAME_REGNUM (reg), INVALID_REGNUM, offset);
+  reg_save (false, DWARF_FRAME_REGNUM (reg), INVALID_REGNUM, offset);
 }
 
 /* Entry point for saving the return address in the stack.
    LABEL and OFFSET are passed to reg_save.  */
 
 void
-dwarf2out_return_save (const char *label, HOST_WIDE_INT offset)
+dwarf2out_return_save (HOST_WIDE_INT offset)
 {
-  reg_save (label, DWARF_FRAME_RETURN_COLUMN, INVALID_REGNUM, offset);
+  reg_save (false, DWARF_FRAME_RETURN_COLUMN, INVALID_REGNUM, offset);
 }
 
 /* Entry point for saving the return address in a register.
    LABEL and SREG are passed to reg_save.  */
 
 void
-dwarf2out_return_reg (const char *label, unsigned int sreg)
+dwarf2out_return_reg (unsigned int sreg)
 {
-  reg_save (label, DWARF_FRAME_RETURN_COLUMN, DWARF_FRAME_REGNUM (sreg), 0);
+  reg_save (false, DWARF_FRAME_RETURN_COLUMN, DWARF_FRAME_REGNUM (sreg), 0);
 }
 
 /* Record the initial position of the return address.  RTL is
@@ -1339,7 +1246,7 @@  initial_return_save (rtx rtl)
     }
 
   if (reg != DWARF_FRAME_RETURN_COLUMN)
-    reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset);
+    reg_save (true, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa.offset);
 }
 
 /* Given a SET, calculate the amount of stack adjustment it
@@ -1609,7 +1516,7 @@  compute_barrier_args_size (void)
    pushed onto the stack.  */
 
 static void
-dwarf2out_args_size (const char *label, HOST_WIDE_INT size)
+dwarf2out_args_size (HOST_WIDE_INT size)
 {
   dw_cfi_ref cfi;
 
@@ -1621,13 +1528,13 @@  dwarf2out_args_size (const char *label, 
   cfi = new_cfi ();
   cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
   cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
-  add_fde_cfi (label, cfi);
+  add_fde_cfi (cfi);
 }
 
 /* Record a stack adjustment of OFFSET bytes.  */
 
 static void
-dwarf2out_stack_adjust (HOST_WIDE_INT offset, const char *label)
+dwarf2out_stack_adjust (HOST_WIDE_INT offset)
 {
   if (cfa.reg == STACK_POINTER_REGNUM)
     cfa.offset += offset;
@@ -1646,9 +1553,9 @@  dwarf2out_stack_adjust (HOST_WIDE_INT of
   if (args_size < 0)
     args_size = 0;
 
-  def_cfa_1 (label, &cfa);
+  def_cfa_1 (false, &cfa);
   if (flag_asynchronous_unwind_tables)
-    dwarf2out_args_size (label, args_size);
+    dwarf2out_args_size (args_size);
 }
 
 /* Check INSN to see if it looks like a push or a stack adjustment, and
@@ -1659,7 +1566,6 @@  static void
 dwarf2out_notice_stack_adjust (rtx insn, bool after_p)
 {
   HOST_WIDE_INT offset;
-  const char *label;
   int i;
 
   /* Don't handle epilogues at all.  Certainly it would be wrong to do so
@@ -1690,7 +1596,7 @@  dwarf2out_notice_stack_adjust (rtx insn,
 	  if (GET_CODE (insn) == SET)
 	    insn = SET_SRC (insn);
 	  gcc_assert (GET_CODE (insn) == CALL);
-	  dwarf2out_args_size ("", INTVAL (XEXP (insn, 1)));
+	  dwarf2out_args_size (INTVAL (XEXP (insn, 1)));
 	}
       return;
     }
@@ -1698,7 +1604,7 @@  dwarf2out_notice_stack_adjust (rtx insn,
   if (CALL_P (insn) && !after_p)
     {
       if (!flag_asynchronous_unwind_tables)
-	dwarf2out_args_size ("", args_size);
+	dwarf2out_args_size (args_size);
       return;
     }
   else if (BARRIER_P (insn))
@@ -1739,8 +1645,7 @@  dwarf2out_notice_stack_adjust (rtx insn,
   if (offset == 0)
     return;
 
-  label = dwarf2out_cfi_label (false);
-  dwarf2out_stack_adjust (offset, label);
+  dwarf2out_stack_adjust (offset);
 }
 
 /* We delay emitting a register save until either (a) we reach the end
@@ -1769,13 +1674,11 @@  struct GTY(()) reg_saved_in_data {
 static GTY(()) struct reg_saved_in_data regs_saved_in_regs[4];
 static GTY(()) size_t num_regs_saved_in_regs;
 
-static const char *last_reg_save_label;
-
 /* Add an entry to QUEUED_REG_SAVES saying that REG is now saved at
    SREG, or if SREG is NULL then it is saved at OFFSET to the CFA.  */
 
 static void
-queue_reg_save (const char *label, rtx reg, rtx sreg, HOST_WIDE_INT offset)
+queue_reg_save (rtx reg, rtx sreg, HOST_WIDE_INT offset)
 {
   struct queued_reg_save *q;
 
@@ -1796,8 +1699,6 @@  queue_reg_save (const char *label, rtx r
   q->reg = reg;
   q->cfa_offset = offset;
   q->saved_reg = sreg;
-
-  last_reg_save_label = label;
 }
 
 /* Output all the entries in QUEUED_REG_SAVES.  */
@@ -1831,11 +1732,10 @@  dwarf2out_flush_queued_reg_saves (void)
 	sreg = DWARF_FRAME_REGNUM (REGNO (q->saved_reg));
       else
 	sreg = INVALID_REGNUM;
-      reg_save (last_reg_save_label, reg, sreg, q->cfa_offset);
+      reg_save (false, reg, sreg, q->cfa_offset);
     }
 
   queued_reg_saves = NULL;
-  last_reg_save_label = NULL;
 }
 
 /* Does INSN clobber any register which QUEUED_REG_SAVES lists a saved
@@ -1865,7 +1765,7 @@  clobbers_queued_reg_save (const_rtx insn
 /* Entry point for saving the first register into the second.  */
 
 void
-dwarf2out_reg_save_reg (const char *label, rtx reg, rtx sreg)
+dwarf2out_reg_save_reg (rtx reg, rtx sreg)
 {
   size_t i;
   unsigned int regno, sregno;
@@ -1883,7 +1783,7 @@  dwarf2out_reg_save_reg (const char *labe
 
   regno = DWARF_FRAME_REGNUM (REGNO (reg));
   sregno = DWARF_FRAME_REGNUM (REGNO (sreg));
-  reg_save (label, regno, sregno, 0);
+  reg_save (false, regno, sregno, 0);
 }
 
 /* What register, if any, is currently saved in REG?  */
@@ -1916,7 +1816,7 @@  static dw_cfa_location cfa_temp;
 /* A subroutine of dwarf2out_frame_debug, process a REG_DEF_CFA note.  */
 
 static void
-dwarf2out_frame_debug_def_cfa (rtx pat, const char *label)
+dwarf2out_frame_debug_def_cfa (rtx pat)
 {
   memset (&cfa, 0, sizeof (cfa));
 
@@ -1947,13 +1847,13 @@  dwarf2out_frame_debug_def_cfa (rtx pat, 
       gcc_unreachable ();
     }
 
-  def_cfa_1 (label, &cfa);
+  def_cfa_1 (false, &cfa);
 }
 
 /* A subroutine of dwarf2out_frame_debug, process a REG_ADJUST_CFA note.  */
 
 static void
-dwarf2out_frame_debug_adjust_cfa (rtx pat, const char *label)
+dwarf2out_frame_debug_adjust_cfa (rtx pat)
 {
   rtx src, dest;
 
@@ -1978,13 +1878,13 @@  dwarf2out_frame_debug_adjust_cfa (rtx pa
   cfa.reg = REGNO (dest);
   gcc_assert (cfa.indirect == 0);
 
-  def_cfa_1 (label, &cfa);
+  def_cfa_1 (false, &cfa);
 }
 
 /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_OFFSET note.  */
 
 static void
-dwarf2out_frame_debug_cfa_offset (rtx set, const char *label)
+dwarf2out_frame_debug_cfa_offset (rtx set)
 {
   HOST_WIDE_INT offset;
   rtx src, addr, span;
@@ -2014,7 +1914,7 @@  dwarf2out_frame_debug_cfa_offset (rtx se
   /* ??? We'd like to use queue_reg_save, but we need to come up with
      a different flushing heuristic for epilogues.  */
   if (!span)
-    reg_save (label, DWARF_FRAME_REGNUM (REGNO (src)), INVALID_REGNUM, offset);
+    reg_save (false, DWARF_FRAME_REGNUM (REGNO (src)), INVALID_REGNUM, offset);
   else
     {
       /* We have a PARALLEL describing where the contents of SRC live.
@@ -2030,7 +1930,7 @@  dwarf2out_frame_debug_cfa_offset (rtx se
 	{
 	  rtx elem = XVECEXP (span, 0, par_index);
 
-	  reg_save (label, DWARF_FRAME_REGNUM (REGNO (elem)),
+	  reg_save (false, DWARF_FRAME_REGNUM (REGNO (elem)),
 		    INVALID_REGNUM, span_offset);
 	  span_offset += GET_MODE_SIZE (GET_MODE (elem));
 	}
@@ -2040,7 +1940,7 @@  dwarf2out_frame_debug_cfa_offset (rtx se
 /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_REGISTER note.  */
 
 static void
-dwarf2out_frame_debug_cfa_register (rtx set, const char *label)
+dwarf2out_frame_debug_cfa_register (rtx set)
 {
   rtx src, dest;
   unsigned sregno, dregno;
@@ -2057,13 +1957,13 @@  dwarf2out_frame_debug_cfa_register (rtx 
 
   /* ??? We'd like to use queue_reg_save, but we need to come up with
      a different flushing heuristic for epilogues.  */
-  reg_save (label, sregno, dregno, 0);
+  reg_save (false, sregno, dregno, 0);
 }
 
 /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_EXPRESSION note. */
 
 static void
-dwarf2out_frame_debug_cfa_expression (rtx set, const char *label)
+dwarf2out_frame_debug_cfa_expression (rtx set)
 {
   rtx src, dest, span;
   dw_cfi_ref cfi = new_cfi ();
@@ -2085,13 +1985,13 @@  dwarf2out_frame_debug_cfa_expression (rt
 
   /* ??? We'd like to use queue_reg_save, were the interface different,
      and, as above, we could manage flushing for epilogues.  */
-  add_fde_cfi (label, cfi);
+  add_fde_cfi (cfi);
 }
 
 /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_RESTORE note.  */
 
 static void
-dwarf2out_frame_debug_cfa_restore (rtx reg, const char *label)
+dwarf2out_frame_debug_cfa_restore (rtx reg)
 {
   dw_cfi_ref cfi = new_cfi ();
   unsigned int regno = DWARF_FRAME_REGNUM (REGNO (reg));
@@ -2099,7 +1999,102 @@  dwarf2out_frame_debug_cfa_restore (rtx r
   cfi->dw_cfi_opc = (regno & ~0x3f ? DW_CFA_restore_extended : DW_CFA_restore);
   cfi->dw_cfi_oprnd1.dw_cfi_reg_num = regno;
 
-  add_fde_cfi (label, cfi);
+  add_fde_cfi (cfi);
+}
+
+/* Examine CFI and return true if a cfi label and set_loc is needed before
+   it.  Even when generating CFI assembler instructions, we still have to
+   add the cfi to the list so that lookup_cfa works later on.  When
+   -g2 and above we even need to force emitting of CFI labels and add
+   to list a DW_CFA_set_loc for convert_cfa_to_fb_loc_list purposes.
+   If we're generating DWARF3 output we use DW_OP_call_frame_cfa and
+   so don't use convert_cfa_to_fb_loc_list.  */
+
+static bool
+cfi_label_required_p (dw_cfi_ref cfi)
+{
+  if (!dwarf2out_do_cfi_asm ())
+    return true;
+
+  if (dwarf_version == 2
+      && debug_info_level > DINFO_LEVEL_TERSE
+      && (write_symbols == DWARF2_DEBUG
+	  || write_symbols == VMS_AND_DWARF2_DEBUG))
+    {
+      switch (cfi->dw_cfi_opc)
+	{
+	case DW_CFA_def_cfa_offset:
+	case DW_CFA_def_cfa_offset_sf:
+	case DW_CFA_def_cfa_register:
+	case DW_CFA_def_cfa:
+	case DW_CFA_def_cfa_sf:
+	case DW_CFA_def_cfa_expression:
+	case DW_CFA_restore_state:
+	  return true;
+	default:
+	  return false;
+	}
+    }
+  return false;
+}
+
+/* Walk the functino, looking for NOTE_INSN_CFI notes.  Add the CFIs to the
+   function's FDE, adding CFI labels and set_loc/advance_loc opcodes as
+   necessary.  */
+static void
+add_cfis_to_fde (void)
+{
+  dw_fde_ref fde = current_fde ();
+  rtx insn, next;
+  /* We always start with a function_begin label.  */
+  bool first = false;
+
+  for (insn = get_insns (); insn; insn = next)
+    {
+      next = NEXT_INSN (insn);
+
+      if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
+	/* Don't attempt to advance_loc4 between labels in different
+	   sections.  */
+	first = true;
+
+      if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_CFI)
+	{
+	  bool required = cfi_label_required_p (NOTE_CFI (insn));
+	  while (next && NOTE_P (next) && NOTE_KIND (next) == NOTE_INSN_CFI)
+	    {
+	      required |= cfi_label_required_p (NOTE_CFI (next));
+	      next = NEXT_INSN (next);
+	    }
+	  if (required)
+	    {
+	      int num = dwarf2out_cfi_label_num;
+	      const char *label = dwarf2out_cfi_label ();
+	      dw_cfi_ref xcfi;
+	      rtx tmp;
+
+	      label = xstrdup (label);
+
+	      /* Set the location counter to the new label.  */
+	      xcfi = new_cfi ();
+	      xcfi->dw_cfi_opc = (first ? DW_CFA_set_loc
+				  : DW_CFA_advance_loc4);
+	      xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
+	      VEC_safe_push (dw_cfi_ref, gc, fde->dw_fde_cfi, xcfi);
+
+	      tmp = emit_note_before (NOTE_INSN_CFI_LABEL, insn);
+	      NOTE_LABEL_NUMBER (tmp) = num;
+	    }
+
+	  do
+	    {
+	      VEC_safe_push (dw_cfi_ref, gc, fde->dw_fde_cfi, NOTE_CFI (insn));
+	      insn = NEXT_INSN (insn);
+	    }
+	  while (insn != next);
+	  first = false;
+	}
+    }
 }
 
 /* Record call frame debugging information for an expression EXPR,
@@ -2298,7 +2293,7 @@  dwarf2out_frame_debug_cfa_restore (rtx r
   	   cfa.reg == fde->drap_reg  */
 
 static void
-dwarf2out_frame_debug_expr (rtx expr, const char *label)
+dwarf2out_frame_debug_expr (rtx expr)
 {
   rtx src, dest, span;
   HOST_WIDE_INT offset;
@@ -2327,7 +2322,7 @@  dwarf2out_frame_debug_expr (rtx expr, co
 	    if (GET_CODE (elem) == SET
 		&& MEM_P (SET_DEST (elem))
 		&& (RTX_FRAME_RELATED_P (elem) || par_index == 0))
-	      dwarf2out_frame_debug_expr (elem, label);
+	      dwarf2out_frame_debug_expr (elem);
 	  }
 
       for (par_index = 0; par_index < limit; par_index++)
@@ -2336,7 +2331,7 @@  dwarf2out_frame_debug_expr (rtx expr, co
 	  if (GET_CODE (elem) == SET
 	      && (!MEM_P (SET_DEST (elem)) || GET_CODE (expr) == SEQUENCE)
 	      && (RTX_FRAME_RELATED_P (elem) || par_index == 0))
-	    dwarf2out_frame_debug_expr (elem, label);
+	    dwarf2out_frame_debug_expr (elem);
 	  else if (GET_CODE (elem) == SET
 		   && par_index != 0
 		   && !RTX_FRAME_RELATED_P (elem))
@@ -2346,7 +2341,7 @@  dwarf2out_frame_debug_expr (rtx expr, co
 	      HOST_WIDE_INT offset = stack_adjust_offset (elem, args_size, 0);
 
 	      if (offset != 0)
-		dwarf2out_stack_adjust (offset, label);
+		dwarf2out_stack_adjust (offset);
 	    }
 	}
       return;
@@ -2406,7 +2401,7 @@  dwarf2out_frame_debug_expr (rtx expr, co
 			    && fde->drap_reg != INVALID_REGNUM
 			    && cfa.reg != REGNO (src));
 	      else
-		queue_reg_save (label, src, dest, 0);
+		queue_reg_save (src, dest, 0);
 	    }
 	  break;
 
@@ -2536,7 +2531,7 @@  dwarf2out_frame_debug_expr (rtx expr, co
 	case UNSPEC:
 	case UNSPEC_VOLATILE:
 	  gcc_assert (targetm.dwarf_handle_frame_unspec);
-	  targetm.dwarf_handle_frame_unspec (label, expr, XINT (src, 1));
+	  targetm.dwarf_handle_frame_unspec (expr, XINT (src, 1));
 	  return;
 
 	  /* Rule 16 */
@@ -2565,7 +2560,7 @@  dwarf2out_frame_debug_expr (rtx expr, co
 	  gcc_unreachable ();
 	}
 
-      def_cfa_1 (label, &cfa);
+      def_cfa_1 (false, &cfa);
       break;
 
     case MEM:
@@ -2721,15 +2716,15 @@  dwarf2out_frame_debug_expr (rtx expr, co
 
 		  fde->drap_reg_saved = 1;
 
-		  def_cfa_1 (label, &cfa_exp);
+		  def_cfa_1 (false, &cfa_exp);
 		  break;
                 }
 
 	      /* If the source register is exactly the CFA, assume
 		 we're saving SP like any other register; this happens
 		 on the ARM.  */
-	      def_cfa_1 (label, &cfa);
-	      queue_reg_save (label, stack_pointer_rtx, NULL_RTX, offset);
+	      def_cfa_1 (false, &cfa);
+	      queue_reg_save (stack_pointer_rtx, NULL_RTX, offset);
 	      break;
 	    }
 	  else
@@ -2745,17 +2740,17 @@  dwarf2out_frame_debug_expr (rtx expr, co
 	      cfa.reg = REGNO (x);
 	      cfa.base_offset = offset;
 	      cfa.indirect = 1;
-	      def_cfa_1 (label, &cfa);
+	      def_cfa_1 (false, &cfa);
 	      break;
 	    }
 	}
 
-      def_cfa_1 (label, &cfa);
+      def_cfa_1 (false, &cfa);
       {
 	span = targetm.dwarf_register_span (src);
 
 	if (!span)
-	  queue_reg_save (label, src, NULL_RTX, offset);
+	  queue_reg_save (src, NULL_RTX, offset);
 	else
 	  {
 	    /* We have a PARALLEL describing where the contents of SRC
@@ -2772,7 +2767,7 @@  dwarf2out_frame_debug_expr (rtx expr, co
 	      {
 		rtx elem = XVECEXP (span, 0, par_index);
 
-		queue_reg_save (label, elem, NULL_RTX, span_offset);
+		queue_reg_save (elem, NULL_RTX, span_offset);
 		span_offset += GET_MODE_SIZE (GET_MODE (elem));
 	      }
 	  }
@@ -2794,7 +2789,6 @@  dwarf2out_frame_debug_expr (rtx expr, co
 void
 dwarf2out_frame_debug (rtx insn, bool after_p)
 {
-  const char *label;
   rtx note, n;
   bool handled_one = false;
 
@@ -2813,10 +2807,10 @@  dwarf2out_frame_debug (rtx insn, bool af
 	 is still used to save registers.  */
       if (!ACCUMULATE_OUTGOING_ARGS)
 	dwarf2out_notice_stack_adjust (insn, after_p);
+      cfi_insn = NULL;
       return;
     }
 
-  label = dwarf2out_cfi_label (false);
   any_cfis_emitted = false;
 
   for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
@@ -2827,7 +2821,7 @@  dwarf2out_frame_debug (rtx insn, bool af
 	goto found;
 
       case REG_CFA_DEF_CFA:
-	dwarf2out_frame_debug_def_cfa (XEXP (note, 0), label);
+	dwarf2out_frame_debug_def_cfa (XEXP (note, 0));
 	handled_one = true;
 	break;
 
@@ -2839,7 +2833,7 @@  dwarf2out_frame_debug (rtx insn, bool af
 	    if (GET_CODE (n) == PARALLEL)
 	      n = XVECEXP (n, 0, 0);
 	  }
-	dwarf2out_frame_debug_adjust_cfa (n, label);
+	dwarf2out_frame_debug_adjust_cfa (n);
 	handled_one = true;
 	break;
 
@@ -2847,7 +2841,7 @@  dwarf2out_frame_debug (rtx insn, bool af
 	n = XEXP (note, 0);
 	if (n == NULL)
 	  n = single_set (insn);
-	dwarf2out_frame_debug_cfa_offset (n, label);
+	dwarf2out_frame_debug_cfa_offset (n);
 	handled_one = true;
 	break;
 
@@ -2859,7 +2853,7 @@  dwarf2out_frame_debug (rtx insn, bool af
 	    if (GET_CODE (n) == PARALLEL)
 	      n = XVECEXP (n, 0, 0);
 	  }
-	dwarf2out_frame_debug_cfa_register (n, label);
+	dwarf2out_frame_debug_cfa_register (n);
 	handled_one = true;
 	break;
 
@@ -2867,7 +2861,7 @@  dwarf2out_frame_debug (rtx insn, bool af
 	n = XEXP (note, 0);
 	if (n == NULL)
 	  n = single_set (insn);
-	dwarf2out_frame_debug_cfa_expression (n, label);
+	dwarf2out_frame_debug_cfa_expression (n);
 	handled_one = true;
 	break;
 
@@ -2880,7 +2874,7 @@  dwarf2out_frame_debug (rtx insn, bool af
 	      n = XVECEXP (n, 0, 0);
 	    n = XEXP (n, 0);
 	  }
-	dwarf2out_frame_debug_cfa_restore (n, label);
+	dwarf2out_frame_debug_cfa_restore (n);
 	handled_one = true;
 	break;
 
@@ -2906,18 +2900,20 @@  dwarf2out_frame_debug (rtx insn, bool af
     {
       if (any_cfis_emitted)
 	dwarf2out_flush_queued_reg_saves ();
+      cfi_insn = NULL;
       return;
     }
 
   insn = PATTERN (insn);
  found:
-  dwarf2out_frame_debug_expr (insn, label);
+  dwarf2out_frame_debug_expr (insn);
 
   /* Check again.  A parallel can save and update the same register.
      We could probably check just once, here, but this is safer than
      removing the check above.  */
   if (any_cfis_emitted || clobbers_queued_reg_save (insn))
     dwarf2out_flush_queued_reg_saves ();
+  cfi_insn = NULL;
 }
 
 /* Called once at the start of final to initialize some data for the
@@ -2926,7 +2922,6 @@  void
 dwarf2out_frame_debug_init (void)
 {
   size_t i;
-  rtx insn;
 
   /* Flush any queued register saves.  */
   dwarf2out_flush_queued_reg_saves ();
@@ -2936,6 +2931,7 @@  dwarf2out_frame_debug_init (void)
   gcc_assert (cfa.reg
 	      == (unsigned long)DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM));
 
+  old_cfa = cfa;
   cfa.reg = STACK_POINTER_REGNUM;
   cfa_store = cfa;
   cfa_temp.reg = -1;
@@ -2947,7 +2943,15 @@  dwarf2out_frame_debug_init (void)
       regs_saved_in_regs[i].saved_in_reg = NULL_RTX;
     }
   num_regs_saved_in_regs = 0;
+}
+
+/* After the (optional) text prologue has been written, emit CFI insns
+   and update the FDE for frame-related instructions.  */
 
+void
+dwarf2out_frame_debug_after_prologue (void)
+{
+  rtx insn;
   if (barrier_args_size)
     {
       XDELETEVEC (barrier_args_size);
@@ -2973,6 +2977,7 @@  dwarf2out_frame_debug_init (void)
 	    case NOTE_INSN_CFA_RESTORE_STATE:
 	      cfi_insn = insn;
 	      dwarf2out_frame_debug_restore_state ();
+	      cfi_insn = NULL;
 	      break;
 	    }
 	  continue;
@@ -2999,12 +3004,15 @@  dwarf2out_frame_debug_init (void)
 	  )
 	dwarf2out_frame_debug (insn, true);
     }
+
+  add_cfis_to_fde ();
 }
 
 void
 dwarf2out_emit_cfi (dw_cfi_ref cfi)
 {
-  output_cfi_directive (cfi);
+  if (dwarf2out_do_cfi_asm ())
+    output_cfi_directive (cfi);
 }
 
 /* Determine if we need to save and restore CFI information around
@@ -3085,23 +3093,24 @@  dwarf2out_cfi_begin_epilogue (rtx insn)
   /* And emulate the state save.  */
   gcc_assert (!cfa_remember.in_use);
   cfa_remember = cfa;
+  old_cfa_remember = old_cfa;
   cfa_remember.in_use = 1;
 }
 
 /* A "subroutine" of dwarf2out_cfi_begin_epilogue.  Emit the restore
    required.  */
 
-void
+static void
 dwarf2out_frame_debug_restore_state (void)
 {
   dw_cfi_ref cfi = new_cfi ();
-  const char *label = dwarf2out_cfi_label (false);
 
   cfi->dw_cfi_opc = DW_CFA_restore_state;
-  add_fde_cfi (label, cfi);
+  add_fde_cfi (cfi);
 
   gcc_assert (cfa_remember.in_use);
   cfa = cfa_remember;
+  old_cfa = old_cfa_remember;
   cfa_remember.in_use = 0;
 }
 
@@ -4296,7 +4305,8 @@  dwarf2out_frame_init (void)
      sake of lookup_cfa.  */
 
   /* On entry, the Canonical Frame Address is at SP.  */
-  dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
+  old_cfa.reg = INVALID_REGNUM;
+  dwarf2out_def_cfa (true, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
 
   if (targetm.debug_unwind_info () == UI_DWARF2
       || targetm.except_unwind_info (&global_options) == UI_DWARF2)
@@ -4353,10 +4363,6 @@  dwarf2out_switch_text_section (void)
     }
   have_multiple_function_sections = true;
 
-  /* Reset the current label on switching text sections, so that we
-     don't attempt to advance_loc4 between labels in different sections.  */
-  fde->dw_fde_current_label = NULL;
-
   /* There is no need to mark used sections when not debugging.  */
   if (cold_text_section != NULL)
     dwarf2out_note_section_used ();
Index: gcc/dwarf2out.h
===================================================================
--- gcc.orig/dwarf2out.h
+++ gcc/dwarf2out.h
@@ -19,9 +19,41 @@  along with GCC; see the file COPYING3.  
 <http://www.gnu.org/licenses/>.  */
 
 struct dw_cfi_struct;
+/* In dwarf2out.c */
+/* Interface of the DWARF2 unwind info support.  */
+
+/* Generate a new label for the CFI info to refer to.  */
+
+extern void dwarf2out_maybe_emit_cfi_label (void);
+
+/* Entry point to update the canonical frame address (CFA).  */
+
+extern void dwarf2out_def_cfa (bool, unsigned, HOST_WIDE_INT);
+
+/* Add the CFI for saving a register window.  */
+
+extern void dwarf2out_window_save (void);
+
+/* Entry point for saving a register to the stack.  */
+
+extern void dwarf2out_reg_save (unsigned, HOST_WIDE_INT);
+
+/* Entry point for saving the return address in the stack.  */
+
+extern void dwarf2out_return_save (HOST_WIDE_INT);
+
+/* Entry point for saving the return address in a register.  */
+
+extern void dwarf2out_return_reg (unsigned);
+
+/* Entry point for saving the first register into the second.  */
+
+extern void dwarf2out_reg_save_reg (rtx, rtx);
+
 extern void dwarf2out_decl (tree);
 extern void dwarf2out_frame_debug (rtx, bool);
 extern void dwarf2out_frame_debug_init (void);
+extern void dwarf2out_frame_debug_after_prologue (void);
 extern void dwarf2out_emit_cfi (struct dw_cfi_struct *);
 extern void dwarf2out_flush_queued_reg_saves (void);
 
Index: gcc/final.c
===================================================================
--- gcc.orig/final.c
+++ gcc/final.c
@@ -1588,6 +1588,11 @@  final_start_function (rtx first ATTRIBUT
   /* First output the function prologue: code to set up the stack frame.  */
   targetm.asm_out.function_prologue (file, get_frame_size ());
 
+#if defined (HAVE_prologue)
+  if (dwarf2out_do_frame ())
+    dwarf2out_frame_debug_after_prologue ();
+#endif
+
   /* If the machine represents the prologue as RTL, the profiling code must
      be emitted when NOTE_INSN_PROLOGUE_END is scanned.  */
 #ifdef HAVE_prologue
Index: gcc/target.def
===================================================================
--- gcc.orig/target.def
+++ gcc/target.def
@@ -1792,7 +1792,7 @@  DEFHOOK
 DEFHOOK
 (dwarf_handle_frame_unspec,
  "",
- void, (const char *label, rtx pattern, int index), NULL)
+ void, (rtx pattern, int index), NULL)
 
 /* ??? Documenting this hook requires a GFDL license grant.  */
 DEFHOOK_UNDOC
Index: gcc/tree.h
===================================================================
--- gcc.orig/tree.h
+++ gcc/tree.h
@@ -5424,37 +5424,6 @@  extern tree tree_overlaps_hard_reg_set (
 #endif
 
 
-/* In dwarf2out.c */
-/* Interface of the DWARF2 unwind info support.  */
-
-/* Generate a new label for the CFI info to refer to.  */
-
-extern char *dwarf2out_cfi_label (bool);
-
-/* Entry point to update the canonical frame address (CFA).  */
-
-extern void dwarf2out_def_cfa (const char *, unsigned, HOST_WIDE_INT);
-
-/* Add the CFI for saving a register window.  */
-
-extern void dwarf2out_window_save (const char *);
-
-/* Entry point for saving a register to the stack.  */
-
-extern void dwarf2out_reg_save (const char *, unsigned, HOST_WIDE_INT);
-
-/* Entry point for saving the return address in the stack.  */
-
-extern void dwarf2out_return_save (const char *, HOST_WIDE_INT);
-
-/* Entry point for saving the return address in a register.  */
-
-extern void dwarf2out_return_reg (const char *, unsigned);
-
-/* Entry point for saving the first register into the second.  */
-
-extern void dwarf2out_reg_save_reg (const char *, rtx, rtx);
-
 /* In tree-inline.c  */
 
 /* The type of a set of already-visited pointers.  Functions for creating
Index: gcc/doc/tm.texi
===================================================================
--- gcc.orig/doc/tm.texi
+++ gcc/doc/tm.texi
@@ -3203,7 +3203,7 @@  someone decided it was a good idea to us
 terminate the stack backtrace.  New ports should avoid this.
 @end defmac
 
-@deftypefn {Target Hook} void TARGET_DWARF_HANDLE_FRAME_UNSPEC (const char *@var{label}, rtx @var{pattern}, int @var{index})
+@deftypefn {Target Hook} void TARGET_DWARF_HANDLE_FRAME_UNSPEC (rtx @var{pattern}, int @var{index})
 This target hook allows the backend to emit frame-related insns that
 contain UNSPECs or UNSPEC_VOLATILEs.  The DWARF 2 call frame debugging
 info engine will invoke it on insns of the form