diff mbox

[6/6] dwarf2: Move CFI output routines to dwarf2cfi.c.

Message ID 1310242442-26123-7-git-send-email-rth@redhat.com
State New
Headers show

Commit Message

Richard Henderson July 9, 2011, 8:14 p.m. UTC
---
 gcc/defaults.h  |   22 ++
 gcc/dwarf2cfi.c |  567 ++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/dwarf2out.c |  638 +------------------------------------------------------
 gcc/dwarf2out.h |    7 +
 4 files changed, 604 insertions(+), 630 deletions(-)
diff mbox

Patch

diff --git a/gcc/defaults.h b/gcc/defaults.h
index 6bacb3c..70c63ce 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -453,6 +453,28 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define DWARF2_FRAME_REG_OUT(REGNO, FOR_EH) (REGNO)
 #endif
 
+/* The size of addresses as they appear in the Dwarf 2 data.
+   Some architectures use word addresses to refer to code locations,
+   but Dwarf 2 info always uses byte addresses.  On such machines,
+   Dwarf 2 addresses need to be larger than the architecture's
+   pointers.  */
+#ifndef DWARF2_ADDR_SIZE
+#define DWARF2_ADDR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
+#endif
+
+/* The size in bytes of a DWARF field indicating an offset or length
+   relative to a debug info section, specified to be 4 bytes in the
+   DWARF-2 specification.  The SGI/MIPS ABI defines it to be the same
+   as PTR_SIZE.  */
+#ifndef DWARF_OFFSET_SIZE
+#define DWARF_OFFSET_SIZE 4
+#endif
+
+/* The size in bytes of a DWARF 4 type signature.  */
+#ifndef DWARF_TYPE_SIGNATURE_SIZE
+#define DWARF_TYPE_SIGNATURE_SIZE 8
+#endif
+
 /* Default sizes for base C types.  If the sizes are different for
    your target, you should override these values by defining the
    appropriate symbols in your tm.h file.  */
diff --git a/gcc/dwarf2cfi.c b/gcc/dwarf2cfi.c
index 28f9b93..5b8420e 100644
--- a/gcc/dwarf2cfi.c
+++ b/gcc/dwarf2cfi.c
@@ -2553,6 +2553,573 @@  execute_dwarf2_frame (void)
   return 0;
 }
 
+/* Convert a DWARF call frame info. operation to its string name */
+
+static const char *
+dwarf_cfi_name (unsigned int cfi_opc)
+{
+  switch (cfi_opc)
+    {
+    case DW_CFA_advance_loc:
+      return "DW_CFA_advance_loc";
+    case DW_CFA_offset:
+      return "DW_CFA_offset";
+    case DW_CFA_restore:
+      return "DW_CFA_restore";
+    case DW_CFA_nop:
+      return "DW_CFA_nop";
+    case DW_CFA_set_loc:
+      return "DW_CFA_set_loc";
+    case DW_CFA_advance_loc1:
+      return "DW_CFA_advance_loc1";
+    case DW_CFA_advance_loc2:
+      return "DW_CFA_advance_loc2";
+    case DW_CFA_advance_loc4:
+      return "DW_CFA_advance_loc4";
+    case DW_CFA_offset_extended:
+      return "DW_CFA_offset_extended";
+    case DW_CFA_restore_extended:
+      return "DW_CFA_restore_extended";
+    case DW_CFA_undefined:
+      return "DW_CFA_undefined";
+    case DW_CFA_same_value:
+      return "DW_CFA_same_value";
+    case DW_CFA_register:
+      return "DW_CFA_register";
+    case DW_CFA_remember_state:
+      return "DW_CFA_remember_state";
+    case DW_CFA_restore_state:
+      return "DW_CFA_restore_state";
+    case DW_CFA_def_cfa:
+      return "DW_CFA_def_cfa";
+    case DW_CFA_def_cfa_register:
+      return "DW_CFA_def_cfa_register";
+    case DW_CFA_def_cfa_offset:
+      return "DW_CFA_def_cfa_offset";
+
+    /* DWARF 3 */
+    case DW_CFA_def_cfa_expression:
+      return "DW_CFA_def_cfa_expression";
+    case DW_CFA_expression:
+      return "DW_CFA_expression";
+    case DW_CFA_offset_extended_sf:
+      return "DW_CFA_offset_extended_sf";
+    case DW_CFA_def_cfa_sf:
+      return "DW_CFA_def_cfa_sf";
+    case DW_CFA_def_cfa_offset_sf:
+      return "DW_CFA_def_cfa_offset_sf";
+
+    /* SGI/MIPS specific */
+    case DW_CFA_MIPS_advance_loc8:
+      return "DW_CFA_MIPS_advance_loc8";
+
+    /* GNU extensions */
+    case DW_CFA_GNU_window_save:
+      return "DW_CFA_GNU_window_save";
+    case DW_CFA_GNU_args_size:
+      return "DW_CFA_GNU_args_size";
+    case DW_CFA_GNU_negative_offset_extended:
+      return "DW_CFA_GNU_negative_offset_extended";
+
+    default:
+      return "DW_CFA_<unknown>";
+    }
+}
+
+/* This routine will generate the correct assembly data for a location
+   description based on a cfi entry with a complex address.  */
+
+static void
+output_cfa_loc (dw_cfi_ref cfi, int for_eh)
+{
+  dw_loc_descr_ref loc;
+  unsigned long size;
+
+  if (cfi->dw_cfi_opc == DW_CFA_expression)
+    {
+      unsigned r = 
+	DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+      dw2_asm_output_data (1, r, NULL);
+      loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
+    }
+  else
+    loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
+
+  /* Output the size of the block.  */
+  size = size_of_locs (loc);
+  dw2_asm_output_data_uleb128 (size, NULL);
+
+  /* Now output the operations themselves.  */
+  output_loc_sequence (loc, for_eh);
+}
+
+/* Similar, but used for .cfi_escape.  */
+
+static void
+output_cfa_loc_raw (dw_cfi_ref cfi)
+{
+  dw_loc_descr_ref loc;
+  unsigned long size;
+
+  if (cfi->dw_cfi_opc == DW_CFA_expression)
+    {
+      unsigned r = 
+	DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
+      fprintf (asm_out_file, "%#x,", r);
+      loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
+    }
+  else
+    loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
+
+  /* Output the size of the block.  */
+  size = size_of_locs (loc);
+  dw2_asm_output_data_uleb128_raw (size);
+  fputc (',', asm_out_file);
+
+  /* Now output the operations themselves.  */
+  output_loc_sequence_raw (loc);
+}
+
+/* Output a Call Frame Information opcode and its operand(s).  */
+
+void
+output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
+{
+  unsigned long r;
+  HOST_WIDE_INT off;
+
+  if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
+    dw2_asm_output_data (1, (cfi->dw_cfi_opc
+			     | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f)),
+			 "DW_CFA_advance_loc " HOST_WIDE_INT_PRINT_HEX,
+			 ((unsigned HOST_WIDE_INT)
+			  cfi->dw_cfi_oprnd1.dw_cfi_offset));
+  else if (cfi->dw_cfi_opc == DW_CFA_offset)
+    {
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+      dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
+			   "DW_CFA_offset, column %#lx", r);
+      off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
+      dw2_asm_output_data_uleb128 (off, NULL);
+    }
+  else if (cfi->dw_cfi_opc == DW_CFA_restore)
+    {
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+      dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
+			   "DW_CFA_restore, column %#lx", r);
+    }
+  else
+    {
+      dw2_asm_output_data (1, cfi->dw_cfi_opc,
+			   "%s", dwarf_cfi_name (cfi->dw_cfi_opc));
+
+      switch (cfi->dw_cfi_opc)
+	{
+	case DW_CFA_set_loc:
+	  if (for_eh)
+	    dw2_asm_output_encoded_addr_rtx (
+		ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0),
+		gen_rtx_SYMBOL_REF (Pmode, cfi->dw_cfi_oprnd1.dw_cfi_addr),
+		false, NULL);
+	  else
+	    dw2_asm_output_addr (DWARF2_ADDR_SIZE,
+				 cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL);
+	  fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+	  break;
+
+	case DW_CFA_advance_loc1:
+	  dw2_asm_output_delta (1, cfi->dw_cfi_oprnd1.dw_cfi_addr,
+				fde->dw_fde_current_label, NULL);
+	  fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+	  break;
+
+	case DW_CFA_advance_loc2:
+	  dw2_asm_output_delta (2, cfi->dw_cfi_oprnd1.dw_cfi_addr,
+				fde->dw_fde_current_label, NULL);
+	  fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+	  break;
+
+	case DW_CFA_advance_loc4:
+	  dw2_asm_output_delta (4, cfi->dw_cfi_oprnd1.dw_cfi_addr,
+				fde->dw_fde_current_label, NULL);
+	  fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+	  break;
+
+	case DW_CFA_MIPS_advance_loc8:
+	  dw2_asm_output_delta (8, cfi->dw_cfi_oprnd1.dw_cfi_addr,
+				fde->dw_fde_current_label, NULL);
+	  fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+	  break;
+
+	case DW_CFA_offset_extended:
+	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+	  dw2_asm_output_data_uleb128 (r, NULL);
+	  off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
+	  dw2_asm_output_data_uleb128 (off, NULL);
+	  break;
+
+	case DW_CFA_def_cfa:
+	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+	  dw2_asm_output_data_uleb128 (r, NULL);
+	  dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL);
+	  break;
+
+	case DW_CFA_offset_extended_sf:
+	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+	  dw2_asm_output_data_uleb128 (r, NULL);
+	  off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
+	  dw2_asm_output_data_sleb128 (off, NULL);
+	  break;
+
+	case DW_CFA_def_cfa_sf:
+	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+	  dw2_asm_output_data_uleb128 (r, NULL);
+	  off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
+	  dw2_asm_output_data_sleb128 (off, NULL);
+	  break;
+
+	case DW_CFA_restore_extended:
+	case DW_CFA_undefined:
+	case DW_CFA_same_value:
+	case DW_CFA_def_cfa_register:
+	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+	  dw2_asm_output_data_uleb128 (r, NULL);
+	  break;
+
+	case DW_CFA_register:
+	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
+	  dw2_asm_output_data_uleb128 (r, NULL);
+	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, for_eh);
+	  dw2_asm_output_data_uleb128 (r, NULL);
+	  break;
+
+	case DW_CFA_def_cfa_offset:
+	case DW_CFA_GNU_args_size:
+	  dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset, NULL);
+	  break;
+
+	case DW_CFA_def_cfa_offset_sf:
+	  off = div_data_align (cfi->dw_cfi_oprnd1.dw_cfi_offset);
+	  dw2_asm_output_data_sleb128 (off, NULL);
+	  break;
+
+	case DW_CFA_GNU_window_save:
+	  break;
+
+	case DW_CFA_def_cfa_expression:
+	case DW_CFA_expression:
+	  output_cfa_loc (cfi, for_eh);
+	  break;
+
+	case DW_CFA_GNU_negative_offset_extended:
+	  /* Obsoleted by DW_CFA_offset_extended_sf.  */
+	  gcc_unreachable ();
+
+	default:
+	  break;
+	}
+    }
+}
+
+/* Similar, but do it via assembler directives instead.  */
+
+void
+output_cfi_directive (FILE *f, dw_cfi_ref cfi)
+{
+  unsigned long r, r2;
+
+  switch (cfi->dw_cfi_opc)
+    {
+    case DW_CFA_advance_loc:
+    case DW_CFA_advance_loc1:
+    case DW_CFA_advance_loc2:
+    case DW_CFA_advance_loc4:
+    case DW_CFA_MIPS_advance_loc8:
+    case DW_CFA_set_loc:
+      /* Should only be created in a code path not followed when emitting
+	 via directives.  The assembler is going to take care of this for
+	 us.  But this routines is also used for debugging dumps, so
+	 print something.  */
+      gcc_assert (f != asm_out_file);
+      fprintf (f, "\t.cfi_advance_loc\n");
+      break;
+
+    case DW_CFA_offset:
+    case DW_CFA_offset_extended:
+    case DW_CFA_offset_extended_sf:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
+      fprintf (f, "\t.cfi_offset %lu, "HOST_WIDE_INT_PRINT_DEC"\n",
+	       r, cfi->dw_cfi_oprnd2.dw_cfi_offset);
+      break;
+
+    case DW_CFA_restore:
+    case DW_CFA_restore_extended:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
+      fprintf (f, "\t.cfi_restore %lu\n", r);
+      break;
+
+    case DW_CFA_undefined:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
+      fprintf (f, "\t.cfi_undefined %lu\n", r);
+      break;
+
+    case DW_CFA_same_value:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
+      fprintf (f, "\t.cfi_same_value %lu\n", r);
+      break;
+
+    case DW_CFA_def_cfa:
+    case DW_CFA_def_cfa_sf:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
+      fprintf (f, "\t.cfi_def_cfa %lu, "HOST_WIDE_INT_PRINT_DEC"\n",
+	       r, cfi->dw_cfi_oprnd2.dw_cfi_offset);
+      break;
+
+    case DW_CFA_def_cfa_register:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
+      fprintf (f, "\t.cfi_def_cfa_register %lu\n", r);
+      break;
+
+    case DW_CFA_register:
+      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
+      r2 = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, 1);
+      fprintf (f, "\t.cfi_register %lu, %lu\n", r, r2);
+      break;
+
+    case DW_CFA_def_cfa_offset:
+    case DW_CFA_def_cfa_offset_sf:
+      fprintf (f, "\t.cfi_def_cfa_offset "
+	       HOST_WIDE_INT_PRINT_DEC"\n",
+	       cfi->dw_cfi_oprnd1.dw_cfi_offset);
+      break;
+
+    case DW_CFA_remember_state:
+      fprintf (f, "\t.cfi_remember_state\n");
+      break;
+    case DW_CFA_restore_state:
+      fprintf (f, "\t.cfi_restore_state\n");
+      break;
+
+    case DW_CFA_GNU_args_size:
+      if (f == asm_out_file)
+	{
+	  fprintf (f, "\t.cfi_escape %#x,", DW_CFA_GNU_args_size);
+	  dw2_asm_output_data_uleb128_raw (cfi->dw_cfi_oprnd1.dw_cfi_offset);
+	  if (flag_debug_asm)
+	    fprintf (f, "\t%s args_size "HOST_WIDE_INT_PRINT_DEC,
+		     ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset);
+	  fputc ('\n', f);
+	}
+      else
+	{
+	  fprintf (f, "\t.cfi_GNU_args_size "HOST_WIDE_INT_PRINT_DEC "\n",
+		   cfi->dw_cfi_oprnd1.dw_cfi_offset);
+	}
+      break;
+
+    case DW_CFA_GNU_window_save:
+      fprintf (f, "\t.cfi_window_save\n");
+      break;
+
+    case DW_CFA_def_cfa_expression:
+      if (f != asm_out_file)
+	{
+	  fprintf (f, "\t.cfi_def_cfa_expression ...\n");
+	  break;
+	}
+      /* FALLTHRU */
+    case DW_CFA_expression:
+      if (f != asm_out_file)
+	{
+	  fprintf (f, "\t.cfi_cfa_expression ...\n");
+	  break;
+	}
+      fprintf (f, "\t.cfi_escape %#x,", cfi->dw_cfi_opc);
+      output_cfa_loc_raw (cfi);
+      fputc ('\n', f);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+void
+dwarf2out_emit_cfi (dw_cfi_ref cfi)
+{
+  if (dwarf2out_do_cfi_asm ())
+    output_cfi_directive (asm_out_file, cfi);
+}
+
+/* Output CFIs from VEC, up to index UPTO, to bring current FDE to the
+   same state as after executing CFIs in CFI chain.  DO_CFI_ASM is
+   true if .cfi_* directives shall be emitted, false otherwise.  If it
+   is false, FDE and FOR_EH are the other arguments to pass to
+   output_cfi.  */
+
+void
+output_cfis (cfi_vec vec, int upto, bool do_cfi_asm,
+	     dw_fde_ref fde, bool for_eh)
+{
+  int ix;
+  struct dw_cfi_struct cfi_buf;
+  dw_cfi_ref cfi2;
+  dw_cfi_ref cfi_args_size = NULL, cfi_cfa = NULL, cfi_cfa_offset = NULL;
+  VEC(dw_cfi_ref, heap) *regs = VEC_alloc (dw_cfi_ref, heap, 32);
+  unsigned int len, idx;
+
+  for (ix = 0; ix < upto + 1; ix++)
+    {
+      dw_cfi_ref cfi = ix < upto ? VEC_index (dw_cfi_ref, vec, ix) : NULL;
+      switch (cfi ? cfi->dw_cfi_opc : DW_CFA_nop)
+	{
+	case DW_CFA_advance_loc:
+	case DW_CFA_advance_loc1:
+	case DW_CFA_advance_loc2:
+	case DW_CFA_advance_loc4:
+	case DW_CFA_MIPS_advance_loc8:
+	case DW_CFA_set_loc:
+	  /* All advances should be ignored.  */
+	  break;
+	case DW_CFA_remember_state:
+	  {
+	    dw_cfi_ref args_size = cfi_args_size;
+
+	    /* Skip everything between .cfi_remember_state and
+	       .cfi_restore_state.  */
+	    ix++;
+	    if (ix == upto)
+	      goto flush_all;
+
+	    for (; ix < upto; ix++)
+	      {
+		cfi2 = VEC_index (dw_cfi_ref, vec, ix);
+		if (cfi2->dw_cfi_opc == DW_CFA_restore_state)
+		  break;
+		else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size)
+		  args_size = cfi2;
+		else
+		  gcc_assert (cfi2->dw_cfi_opc != DW_CFA_remember_state);
+	      }
+
+	    cfi_args_size = args_size;
+	    break;
+	  }
+	case DW_CFA_GNU_args_size:
+	  cfi_args_size = cfi;
+	  break;
+	case DW_CFA_GNU_window_save:
+	  goto flush_all;
+	case DW_CFA_offset:
+	case DW_CFA_offset_extended:
+	case DW_CFA_offset_extended_sf:
+	case DW_CFA_restore:
+	case DW_CFA_restore_extended:
+	case DW_CFA_undefined:
+	case DW_CFA_same_value:
+	case DW_CFA_register:
+	case DW_CFA_val_offset:
+	case DW_CFA_val_offset_sf:
+	case DW_CFA_expression:
+	case DW_CFA_val_expression:
+	case DW_CFA_GNU_negative_offset_extended:
+	  if (VEC_length (dw_cfi_ref, regs)
+	      <= cfi->dw_cfi_oprnd1.dw_cfi_reg_num)
+	    VEC_safe_grow_cleared (dw_cfi_ref, heap, regs,
+				   cfi->dw_cfi_oprnd1.dw_cfi_reg_num + 1);
+	  VEC_replace (dw_cfi_ref, regs, cfi->dw_cfi_oprnd1.dw_cfi_reg_num,
+		       cfi);
+	  break;
+	case DW_CFA_def_cfa:
+	case DW_CFA_def_cfa_sf:
+	case DW_CFA_def_cfa_expression:
+	  cfi_cfa = cfi;
+	  cfi_cfa_offset = cfi;
+	  break;
+	case DW_CFA_def_cfa_register:
+	  cfi_cfa = cfi;
+	  break;
+	case DW_CFA_def_cfa_offset:
+	case DW_CFA_def_cfa_offset_sf:
+	  cfi_cfa_offset = cfi;
+	  break;
+	case DW_CFA_nop:
+	  gcc_assert (cfi == NULL);
+	flush_all:
+	  len = VEC_length (dw_cfi_ref, regs);
+	  for (idx = 0; idx < len; idx++)
+	    {
+	      cfi2 = VEC_replace (dw_cfi_ref, regs, idx, NULL);
+	      if (cfi2 != NULL
+		  && cfi2->dw_cfi_opc != DW_CFA_restore
+		  && cfi2->dw_cfi_opc != DW_CFA_restore_extended)
+		{
+		  if (do_cfi_asm)
+		    output_cfi_directive (asm_out_file, cfi2);
+		  else
+		    output_cfi (cfi2, fde, for_eh);
+		}
+	    }
+	  if (cfi_cfa && cfi_cfa_offset && cfi_cfa_offset != cfi_cfa)
+	    {
+	      gcc_assert (cfi_cfa->dw_cfi_opc != DW_CFA_def_cfa_expression);
+	      cfi_buf = *cfi_cfa;
+	      switch (cfi_cfa_offset->dw_cfi_opc)
+		{
+		case DW_CFA_def_cfa_offset:
+		  cfi_buf.dw_cfi_opc = DW_CFA_def_cfa;
+		  cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1;
+		  break;
+		case DW_CFA_def_cfa_offset_sf:
+		  cfi_buf.dw_cfi_opc = DW_CFA_def_cfa_sf;
+		  cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1;
+		  break;
+		case DW_CFA_def_cfa:
+		case DW_CFA_def_cfa_sf:
+		  cfi_buf.dw_cfi_opc = cfi_cfa_offset->dw_cfi_opc;
+		  cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd2;
+		  break;
+		default:
+		  gcc_unreachable ();
+		}
+	      cfi_cfa = &cfi_buf;
+	    }
+	  else if (cfi_cfa_offset)
+	    cfi_cfa = cfi_cfa_offset;
+	  if (cfi_cfa)
+	    {
+	      if (do_cfi_asm)
+		output_cfi_directive (asm_out_file, cfi_cfa);
+	      else
+		output_cfi (cfi_cfa, fde, for_eh);
+	    }
+	  cfi_cfa = NULL;
+	  cfi_cfa_offset = NULL;
+	  if (cfi_args_size
+	      && cfi_args_size->dw_cfi_oprnd1.dw_cfi_offset)
+	    {
+	      if (do_cfi_asm)
+		output_cfi_directive (asm_out_file, cfi_args_size);
+	      else
+		output_cfi (cfi_args_size, fde, for_eh);
+	    }
+	  cfi_args_size = NULL;
+	  if (cfi == NULL)
+	    {
+	      VEC_free (dw_cfi_ref, heap, regs);
+	      return;
+	    }
+	  else if (do_cfi_asm)
+	    output_cfi_directive (asm_out_file, cfi);
+	  else
+	    output_cfi (cfi, fde, for_eh);
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+    }
+}
+
 
 /* Save the result of dwarf2out_do_frame across PCH.
    This variable is tri-state, with 0 unset, >0 true, <0 false.  */
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 4431655..6469506 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -160,30 +160,6 @@  static GTY(()) section *debug_frame_section;
 /* Maximum size (in bytes) of an artificially generated label.  */
 #define MAX_ARTIFICIAL_LABEL_BYTES	30
 
-/* The size of addresses as they appear in the Dwarf 2 data.
-   Some architectures use word addresses to refer to code locations,
-   but Dwarf 2 info always uses byte addresses.  On such machines,
-   Dwarf 2 addresses need to be larger than the architecture's
-   pointers.  */
-#ifndef DWARF2_ADDR_SIZE
-#define DWARF2_ADDR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
-#endif
-
-/* The size in bytes of a DWARF field indicating an offset or length
-   relative to a debug info section, specified to be 4 bytes in the
-   DWARF-2 specification.  The SGI/MIPS ABI defines it to be the same
-   as PTR_SIZE.  */
-
-#ifndef DWARF_OFFSET_SIZE
-#define DWARF_OFFSET_SIZE 4
-#endif
-
-/* The size in bytes of a DWARF 4 type signature.  */
-
-#ifndef DWARF_TYPE_SIGNATURE_SIZE
-#define DWARF_TYPE_SIGNATURE_SIZE 8
-#endif
-
 /* According to the (draft) DWARF 3 specification, the initial length
    should either be 4 or 12 bytes.  When it's 12 bytes, the first 4
    bytes are 0xffffffff, followed by the length stored in the next 8
@@ -240,14 +216,9 @@  static GTY(()) section *cold_text_section;
 /* Forward declarations for functions defined in this file.  */
 
 static char *stripattributes (const char *);
-static void output_cfi (dw_cfi_ref, dw_fde_ref, int);
 static void output_call_frame_info (int);
 static void dwarf2out_note_section_used (void);
 
-/* Support for complex CFA locations.  */
-static void output_cfa_loc (dw_cfi_ref, int);
-static void output_cfa_loc_raw (dw_cfi_ref);
-
 /* Personality decl of current unit.  Used only when assembler does not support
    personality CFI.  */
 static GTY(()) rtx current_unit_personality;
@@ -391,98 +362,6 @@  stripattributes (const char *s)
   return stripped;
 }
 
-/* Divide OFF by DWARF_CIE_DATA_ALIGNMENT, asserting no remainder.  */
-
-static inline HOST_WIDE_INT
-div_data_align (HOST_WIDE_INT off)
-{
-  HOST_WIDE_INT r = off / DWARF_CIE_DATA_ALIGNMENT;
-  gcc_assert (r * DWARF_CIE_DATA_ALIGNMENT == off);
-  return r;
-}
-
-/* Return true if we need a signed version of a given opcode
-   (e.g. DW_CFA_offset_extended_sf vs DW_CFA_offset_extended).  */
-
-static inline bool
-need_data_align_sf_opcode (HOST_WIDE_INT off)
-{
-  return DWARF_CIE_DATA_ALIGNMENT < 0 ? off > 0 : off < 0;
-}
-
-/* Convert a DWARF call frame info. operation to its string name */
-
-static const char *
-dwarf_cfi_name (unsigned int cfi_opc)
-{
-  switch (cfi_opc)
-    {
-    case DW_CFA_advance_loc:
-      return "DW_CFA_advance_loc";
-    case DW_CFA_offset:
-      return "DW_CFA_offset";
-    case DW_CFA_restore:
-      return "DW_CFA_restore";
-    case DW_CFA_nop:
-      return "DW_CFA_nop";
-    case DW_CFA_set_loc:
-      return "DW_CFA_set_loc";
-    case DW_CFA_advance_loc1:
-      return "DW_CFA_advance_loc1";
-    case DW_CFA_advance_loc2:
-      return "DW_CFA_advance_loc2";
-    case DW_CFA_advance_loc4:
-      return "DW_CFA_advance_loc4";
-    case DW_CFA_offset_extended:
-      return "DW_CFA_offset_extended";
-    case DW_CFA_restore_extended:
-      return "DW_CFA_restore_extended";
-    case DW_CFA_undefined:
-      return "DW_CFA_undefined";
-    case DW_CFA_same_value:
-      return "DW_CFA_same_value";
-    case DW_CFA_register:
-      return "DW_CFA_register";
-    case DW_CFA_remember_state:
-      return "DW_CFA_remember_state";
-    case DW_CFA_restore_state:
-      return "DW_CFA_restore_state";
-    case DW_CFA_def_cfa:
-      return "DW_CFA_def_cfa";
-    case DW_CFA_def_cfa_register:
-      return "DW_CFA_def_cfa_register";
-    case DW_CFA_def_cfa_offset:
-      return "DW_CFA_def_cfa_offset";
-
-    /* DWARF 3 */
-    case DW_CFA_def_cfa_expression:
-      return "DW_CFA_def_cfa_expression";
-    case DW_CFA_expression:
-      return "DW_CFA_expression";
-    case DW_CFA_offset_extended_sf:
-      return "DW_CFA_offset_extended_sf";
-    case DW_CFA_def_cfa_sf:
-      return "DW_CFA_def_cfa_sf";
-    case DW_CFA_def_cfa_offset_sf:
-      return "DW_CFA_def_cfa_offset_sf";
-
-    /* SGI/MIPS specific */
-    case DW_CFA_MIPS_advance_loc8:
-      return "DW_CFA_MIPS_advance_loc8";
-
-    /* GNU extensions */
-    case DW_CFA_GNU_window_save:
-      return "DW_CFA_GNU_window_save";
-    case DW_CFA_GNU_args_size:
-      return "DW_CFA_GNU_args_size";
-    case DW_CFA_GNU_negative_offset_extended:
-      return "DW_CFA_GNU_negative_offset_extended";
-
-    default:
-      return "DW_CFA_<unknown>";
-    }
-}
-
 /* Switch [BACK] to eh_frame_section.  If we don't have an eh_frame_section,
    switch to the data section instead, and write out a synthetic start label
    for collect2 the first time around.  */
@@ -632,454 +511,6 @@  dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi)
     }
 }
 
-/* Output a Call Frame Information opcode and its operand(s).  */
-
-static void
-output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int for_eh)
-{
-  unsigned long r;
-  HOST_WIDE_INT off;
-
-  if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
-    dw2_asm_output_data (1, (cfi->dw_cfi_opc
-			     | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f)),
-			 "DW_CFA_advance_loc " HOST_WIDE_INT_PRINT_HEX,
-			 ((unsigned HOST_WIDE_INT)
-			  cfi->dw_cfi_oprnd1.dw_cfi_offset));
-  else if (cfi->dw_cfi_opc == DW_CFA_offset)
-    {
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-      dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
-			   "DW_CFA_offset, column %#lx", r);
-      off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
-      dw2_asm_output_data_uleb128 (off, NULL);
-    }
-  else if (cfi->dw_cfi_opc == DW_CFA_restore)
-    {
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-      dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
-			   "DW_CFA_restore, column %#lx", r);
-    }
-  else
-    {
-      dw2_asm_output_data (1, cfi->dw_cfi_opc,
-			   "%s", dwarf_cfi_name (cfi->dw_cfi_opc));
-
-      switch (cfi->dw_cfi_opc)
-	{
-	case DW_CFA_set_loc:
-	  if (for_eh)
-	    dw2_asm_output_encoded_addr_rtx (
-		ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/1, /*global=*/0),
-		gen_rtx_SYMBOL_REF (Pmode, cfi->dw_cfi_oprnd1.dw_cfi_addr),
-		false, NULL);
-	  else
-	    dw2_asm_output_addr (DWARF2_ADDR_SIZE,
-				 cfi->dw_cfi_oprnd1.dw_cfi_addr, NULL);
-	  fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
-	  break;
-
-	case DW_CFA_advance_loc1:
-	  dw2_asm_output_delta (1, cfi->dw_cfi_oprnd1.dw_cfi_addr,
-				fde->dw_fde_current_label, NULL);
-	  fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
-	  break;
-
-	case DW_CFA_advance_loc2:
-	  dw2_asm_output_delta (2, cfi->dw_cfi_oprnd1.dw_cfi_addr,
-				fde->dw_fde_current_label, NULL);
-	  fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
-	  break;
-
-	case DW_CFA_advance_loc4:
-	  dw2_asm_output_delta (4, cfi->dw_cfi_oprnd1.dw_cfi_addr,
-				fde->dw_fde_current_label, NULL);
-	  fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
-	  break;
-
-	case DW_CFA_MIPS_advance_loc8:
-	  dw2_asm_output_delta (8, cfi->dw_cfi_oprnd1.dw_cfi_addr,
-				fde->dw_fde_current_label, NULL);
-	  fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
-	  break;
-
-	case DW_CFA_offset_extended:
-	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-	  dw2_asm_output_data_uleb128 (r, NULL);
-	  off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
-	  dw2_asm_output_data_uleb128 (off, NULL);
-	  break;
-
-	case DW_CFA_def_cfa:
-	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-	  dw2_asm_output_data_uleb128 (r, NULL);
-	  dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset, NULL);
-	  break;
-
-	case DW_CFA_offset_extended_sf:
-	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-	  dw2_asm_output_data_uleb128 (r, NULL);
-	  off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
-	  dw2_asm_output_data_sleb128 (off, NULL);
-	  break;
-
-	case DW_CFA_def_cfa_sf:
-	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-	  dw2_asm_output_data_uleb128 (r, NULL);
-	  off = div_data_align (cfi->dw_cfi_oprnd2.dw_cfi_offset);
-	  dw2_asm_output_data_sleb128 (off, NULL);
-	  break;
-
-	case DW_CFA_restore_extended:
-	case DW_CFA_undefined:
-	case DW_CFA_same_value:
-	case DW_CFA_def_cfa_register:
-	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-	  dw2_asm_output_data_uleb128 (r, NULL);
-	  break;
-
-	case DW_CFA_register:
-	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-	  dw2_asm_output_data_uleb128 (r, NULL);
-	  r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, for_eh);
-	  dw2_asm_output_data_uleb128 (r, NULL);
-	  break;
-
-	case DW_CFA_def_cfa_offset:
-	case DW_CFA_GNU_args_size:
-	  dw2_asm_output_data_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset, NULL);
-	  break;
-
-	case DW_CFA_def_cfa_offset_sf:
-	  off = div_data_align (cfi->dw_cfi_oprnd1.dw_cfi_offset);
-	  dw2_asm_output_data_sleb128 (off, NULL);
-	  break;
-
-	case DW_CFA_GNU_window_save:
-	  break;
-
-	case DW_CFA_def_cfa_expression:
-	case DW_CFA_expression:
-	  output_cfa_loc (cfi, for_eh);
-	  break;
-
-	case DW_CFA_GNU_negative_offset_extended:
-	  /* Obsoleted by DW_CFA_offset_extended_sf.  */
-	  gcc_unreachable ();
-
-	default:
-	  break;
-	}
-    }
-}
-
-/* Similar, but do it via assembler directives instead.  */
-
-void
-output_cfi_directive (FILE *f, dw_cfi_ref cfi)
-{
-  unsigned long r, r2;
-
-  switch (cfi->dw_cfi_opc)
-    {
-    case DW_CFA_advance_loc:
-    case DW_CFA_advance_loc1:
-    case DW_CFA_advance_loc2:
-    case DW_CFA_advance_loc4:
-    case DW_CFA_MIPS_advance_loc8:
-    case DW_CFA_set_loc:
-      /* Should only be created in a code path not followed when emitting
-	 via directives.  The assembler is going to take care of this for
-	 us.  But this routines is also used for debugging dumps, so
-	 print something.  */
-      gcc_assert (f != asm_out_file);
-      fprintf (f, "\t.cfi_advance_loc\n");
-      break;
-
-    case DW_CFA_offset:
-    case DW_CFA_offset_extended:
-    case DW_CFA_offset_extended_sf:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      fprintf (f, "\t.cfi_offset %lu, "HOST_WIDE_INT_PRINT_DEC"\n",
-	       r, cfi->dw_cfi_oprnd2.dw_cfi_offset);
-      break;
-
-    case DW_CFA_restore:
-    case DW_CFA_restore_extended:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      fprintf (f, "\t.cfi_restore %lu\n", r);
-      break;
-
-    case DW_CFA_undefined:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      fprintf (f, "\t.cfi_undefined %lu\n", r);
-      break;
-
-    case DW_CFA_same_value:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      fprintf (f, "\t.cfi_same_value %lu\n", r);
-      break;
-
-    case DW_CFA_def_cfa:
-    case DW_CFA_def_cfa_sf:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      fprintf (f, "\t.cfi_def_cfa %lu, "HOST_WIDE_INT_PRINT_DEC"\n",
-	       r, cfi->dw_cfi_oprnd2.dw_cfi_offset);
-      break;
-
-    case DW_CFA_def_cfa_register:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      fprintf (f, "\t.cfi_def_cfa_register %lu\n", r);
-      break;
-
-    case DW_CFA_register:
-      r = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      r2 = DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd2.dw_cfi_reg_num, 1);
-      fprintf (f, "\t.cfi_register %lu, %lu\n", r, r2);
-      break;
-
-    case DW_CFA_def_cfa_offset:
-    case DW_CFA_def_cfa_offset_sf:
-      fprintf (f, "\t.cfi_def_cfa_offset "
-	       HOST_WIDE_INT_PRINT_DEC"\n",
-	       cfi->dw_cfi_oprnd1.dw_cfi_offset);
-      break;
-
-    case DW_CFA_remember_state:
-      fprintf (f, "\t.cfi_remember_state\n");
-      break;
-    case DW_CFA_restore_state:
-      fprintf (f, "\t.cfi_restore_state\n");
-      break;
-
-    case DW_CFA_GNU_args_size:
-      if (f == asm_out_file)
-	{
-	  fprintf (f, "\t.cfi_escape %#x,", DW_CFA_GNU_args_size);
-	  dw2_asm_output_data_uleb128_raw (cfi->dw_cfi_oprnd1.dw_cfi_offset);
-	  if (flag_debug_asm)
-	    fprintf (f, "\t%s args_size "HOST_WIDE_INT_PRINT_DEC,
-		     ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset);
-	  fputc ('\n', f);
-	}
-      else
-	{
-	  fprintf (f, "\t.cfi_GNU_args_size "HOST_WIDE_INT_PRINT_DEC "\n",
-		   cfi->dw_cfi_oprnd1.dw_cfi_offset);
-	}
-      break;
-
-    case DW_CFA_GNU_window_save:
-      fprintf (f, "\t.cfi_window_save\n");
-      break;
-
-    case DW_CFA_def_cfa_expression:
-      if (f != asm_out_file)
-	{
-	  fprintf (f, "\t.cfi_def_cfa_expression ...\n");
-	  break;
-	}
-      /* FALLTHRU */
-    case DW_CFA_expression:
-      if (f != asm_out_file)
-	{
-	  fprintf (f, "\t.cfi_cfa_expression ...\n");
-	  break;
-	}
-      fprintf (f, "\t.cfi_escape %#x,", cfi->dw_cfi_opc);
-      output_cfa_loc_raw (cfi);
-      fputc ('\n', f);
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-}
-
-void
-dwarf2out_emit_cfi (dw_cfi_ref cfi)
-{
-  if (dwarf2out_do_cfi_asm ())
-    output_cfi_directive (asm_out_file, cfi);
-}
-
-/* Output CFIs from VEC, up to index UPTO, to bring current FDE to the
-   same state as after executing CFIs in CFI chain.  DO_CFI_ASM is
-   true if .cfi_* directives shall be emitted, false otherwise.  If it
-   is false, FDE and FOR_EH are the other arguments to pass to
-   output_cfi.  */
-
-static void
-output_cfis (cfi_vec vec, int upto, bool do_cfi_asm,
-	     dw_fde_ref fde, bool for_eh)
-{
-  int ix;
-  struct dw_cfi_struct cfi_buf;
-  dw_cfi_ref cfi2;
-  dw_cfi_ref cfi_args_size = NULL, cfi_cfa = NULL, cfi_cfa_offset = NULL;
-  VEC(dw_cfi_ref, heap) *regs = VEC_alloc (dw_cfi_ref, heap, 32);
-  unsigned int len, idx;
-
-  for (ix = 0; ix < upto + 1; ix++)
-    {
-      dw_cfi_ref cfi = ix < upto ? VEC_index (dw_cfi_ref, vec, ix) : NULL;
-      switch (cfi ? cfi->dw_cfi_opc : DW_CFA_nop)
-	{
-	case DW_CFA_advance_loc:
-	case DW_CFA_advance_loc1:
-	case DW_CFA_advance_loc2:
-	case DW_CFA_advance_loc4:
-	case DW_CFA_MIPS_advance_loc8:
-	case DW_CFA_set_loc:
-	  /* All advances should be ignored.  */
-	  break;
-	case DW_CFA_remember_state:
-	  {
-	    dw_cfi_ref args_size = cfi_args_size;
-
-	    /* Skip everything between .cfi_remember_state and
-	       .cfi_restore_state.  */
-	    ix++;
-	    if (ix == upto)
-	      goto flush_all;
-
-	    for (; ix < upto; ix++)
-	      {
-		cfi2 = VEC_index (dw_cfi_ref, vec, ix);
-		if (cfi2->dw_cfi_opc == DW_CFA_restore_state)
-		  break;
-		else if (cfi2->dw_cfi_opc == DW_CFA_GNU_args_size)
-		  args_size = cfi2;
-		else
-		  gcc_assert (cfi2->dw_cfi_opc != DW_CFA_remember_state);
-	      }
-
-	    cfi_args_size = args_size;
-	    break;
-	  }
-	case DW_CFA_GNU_args_size:
-	  cfi_args_size = cfi;
-	  break;
-	case DW_CFA_GNU_window_save:
-	  goto flush_all;
-	case DW_CFA_offset:
-	case DW_CFA_offset_extended:
-	case DW_CFA_offset_extended_sf:
-	case DW_CFA_restore:
-	case DW_CFA_restore_extended:
-	case DW_CFA_undefined:
-	case DW_CFA_same_value:
-	case DW_CFA_register:
-	case DW_CFA_val_offset:
-	case DW_CFA_val_offset_sf:
-	case DW_CFA_expression:
-	case DW_CFA_val_expression:
-	case DW_CFA_GNU_negative_offset_extended:
-	  if (VEC_length (dw_cfi_ref, regs)
-	      <= cfi->dw_cfi_oprnd1.dw_cfi_reg_num)
-	    VEC_safe_grow_cleared (dw_cfi_ref, heap, regs,
-				   cfi->dw_cfi_oprnd1.dw_cfi_reg_num + 1);
-	  VEC_replace (dw_cfi_ref, regs, cfi->dw_cfi_oprnd1.dw_cfi_reg_num,
-		       cfi);
-	  break;
-	case DW_CFA_def_cfa:
-	case DW_CFA_def_cfa_sf:
-	case DW_CFA_def_cfa_expression:
-	  cfi_cfa = cfi;
-	  cfi_cfa_offset = cfi;
-	  break;
-	case DW_CFA_def_cfa_register:
-	  cfi_cfa = cfi;
-	  break;
-	case DW_CFA_def_cfa_offset:
-	case DW_CFA_def_cfa_offset_sf:
-	  cfi_cfa_offset = cfi;
-	  break;
-	case DW_CFA_nop:
-	  gcc_assert (cfi == NULL);
-	flush_all:
-	  len = VEC_length (dw_cfi_ref, regs);
-	  for (idx = 0; idx < len; idx++)
-	    {
-	      cfi2 = VEC_replace (dw_cfi_ref, regs, idx, NULL);
-	      if (cfi2 != NULL
-		  && cfi2->dw_cfi_opc != DW_CFA_restore
-		  && cfi2->dw_cfi_opc != DW_CFA_restore_extended)
-		{
-		  if (do_cfi_asm)
-		    output_cfi_directive (asm_out_file, cfi2);
-		  else
-		    output_cfi (cfi2, fde, for_eh);
-		}
-	    }
-	  if (cfi_cfa && cfi_cfa_offset && cfi_cfa_offset != cfi_cfa)
-	    {
-	      gcc_assert (cfi_cfa->dw_cfi_opc != DW_CFA_def_cfa_expression);
-	      cfi_buf = *cfi_cfa;
-	      switch (cfi_cfa_offset->dw_cfi_opc)
-		{
-		case DW_CFA_def_cfa_offset:
-		  cfi_buf.dw_cfi_opc = DW_CFA_def_cfa;
-		  cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1;
-		  break;
-		case DW_CFA_def_cfa_offset_sf:
-		  cfi_buf.dw_cfi_opc = DW_CFA_def_cfa_sf;
-		  cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd1;
-		  break;
-		case DW_CFA_def_cfa:
-		case DW_CFA_def_cfa_sf:
-		  cfi_buf.dw_cfi_opc = cfi_cfa_offset->dw_cfi_opc;
-		  cfi_buf.dw_cfi_oprnd2 = cfi_cfa_offset->dw_cfi_oprnd2;
-		  break;
-		default:
-		  gcc_unreachable ();
-		}
-	      cfi_cfa = &cfi_buf;
-	    }
-	  else if (cfi_cfa_offset)
-	    cfi_cfa = cfi_cfa_offset;
-	  if (cfi_cfa)
-	    {
-	      if (do_cfi_asm)
-		output_cfi_directive (asm_out_file, cfi_cfa);
-	      else
-		output_cfi (cfi_cfa, fde, for_eh);
-	    }
-	  cfi_cfa = NULL;
-	  cfi_cfa_offset = NULL;
-	  if (cfi_args_size
-	      && cfi_args_size->dw_cfi_oprnd1.dw_cfi_offset)
-	    {
-	      if (do_cfi_asm)
-		output_cfi_directive (asm_out_file, cfi_args_size);
-	      else
-		output_cfi (cfi_args_size, fde, for_eh);
-	    }
-	  cfi_args_size = NULL;
-	  if (cfi == NULL)
-	    {
-	      VEC_free (dw_cfi_ref, heap, regs);
-	      return;
-	    }
-	  else if (do_cfi_asm)
-	    output_cfi_directive (asm_out_file, cfi);
-	  else
-	    output_cfi (cfi, fde, for_eh);
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
-    }
-}
-
-/* Like output_cfis, but emit all CFIs in the vector.  */
-static void
-output_all_cfis (cfi_vec vec, bool do_cfi_asm,
-		 dw_fde_ref fde, bool for_eh)
-{
-  output_cfis (vec, VEC_length (dw_cfi_ref, vec), do_cfi_asm, fde, for_eh);
-}
-
 /* Output one FDE.  */
 
 static void
@@ -1752,14 +1183,17 @@  dwarf2out_switch_text_section (void)
     = (sect == text_section
        || (cold_text_section && sect == cold_text_section));
 
+  fde->dw_fde_switch_cfi_index = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
+
   if (dwarf2out_do_cfi_asm ())
     {
       dwarf2out_do_cfi_startproc (true);
       /* As this is a different FDE, insert all current CFI instructions
 	 again.  */
-      output_all_cfis (fde->dw_fde_cfi, true, fde, true);
+      output_cfis (fde->dw_fde_cfi, fde->dw_fde_switch_cfi_index,
+		   true, fde, true);
     }
-  fde->dw_fde_switch_cfi_index = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
+
   var_location_switch_text_section ();
 
   set_cur_line_info_table (sect);
@@ -2258,7 +1692,6 @@  loc_list_plus_const (dw_loc_list_ref list_head, HOST_WIDE_INT offset)
 #define DWARF_REF_SIZE	\
   (dwarf_version == 2 ? DWARF2_ADDR_SIZE : DWARF_OFFSET_SIZE)
 
-static unsigned long size_of_locs (dw_loc_descr_ref);
 static unsigned long int get_base_type_offset (dw_die_ref);
 
 /* Return the size of a location descriptor.  */
@@ -2442,7 +1875,7 @@  size_of_loc_descr (dw_loc_descr_ref loc)
 
 /* Return the size of a series of location descriptors.  */
 
-static unsigned long
+unsigned long
 size_of_locs (dw_loc_descr_ref loc)
 {
   dw_loc_descr_ref l;
@@ -2471,7 +1904,6 @@  size_of_locs (dw_loc_descr_ref loc)
 static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
 static void get_ref_die_offset_label (char *, dw_die_ref);
 static unsigned long int get_ref_die_offset (dw_die_ref);
-static void output_loc_sequence (dw_loc_descr_ref, int);
 
 /* Output location description stack opcode's operands (if any).
    The for_eh_or_skip parameter controls whether register numbers are
@@ -2841,7 +2273,7 @@  output_loc_operands (dw_loc_descr_ref loc, int for_eh_or_skip)
    info).  This should be suppressed for the cases that have not been converted
    (i.e. symbolic debug info), by setting the parameter < 0.  See PR47324.  */
 
-static void
+void
 output_loc_sequence (dw_loc_descr_ref loc, int for_eh_or_skip)
 {
   for (; loc != NULL; loc = loc->dw_loc_next)
@@ -3020,7 +2452,7 @@  output_loc_operands_raw (dw_loc_descr_ref loc)
     }
 }
 
-static void
+void
 output_loc_sequence_raw (dw_loc_descr_ref loc)
 {
   while (1)
@@ -3053,60 +2485,6 @@  output_loc_sequence_raw (dw_loc_descr_ref loc)
     }
 }
 
-/* This routine will generate the correct assembly data for a location
-   description based on a cfi entry with a complex address.  */
-
-static void
-output_cfa_loc (dw_cfi_ref cfi, int for_eh)
-{
-  dw_loc_descr_ref loc;
-  unsigned long size;
-
-  if (cfi->dw_cfi_opc == DW_CFA_expression)
-    {
-      unsigned r = 
-	DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, for_eh);
-      dw2_asm_output_data (1, r, NULL);
-      loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
-    }
-  else
-    loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
-
-  /* Output the size of the block.  */
-  size = size_of_locs (loc);
-  dw2_asm_output_data_uleb128 (size, NULL);
-
-  /* Now output the operations themselves.  */
-  output_loc_sequence (loc, for_eh);
-}
-
-/* Similar, but used for .cfi_escape.  */
-
-static void
-output_cfa_loc_raw (dw_cfi_ref cfi)
-{
-  dw_loc_descr_ref loc;
-  unsigned long size;
-
-  if (cfi->dw_cfi_opc == DW_CFA_expression)
-    {
-      unsigned r = 
-	DWARF2_FRAME_REG_OUT (cfi->dw_cfi_oprnd1.dw_cfi_reg_num, 1);
-      fprintf (asm_out_file, "%#x,", r);
-      loc = cfi->dw_cfi_oprnd2.dw_cfi_loc;
-    }
-  else
-    loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
-
-  /* Output the size of the block.  */
-  size = size_of_locs (loc);
-  dw2_asm_output_data_uleb128_raw (size);
-  fputc (',', asm_out_file);
-
-  /* Now output the operations themselves.  */
-  output_loc_sequence_raw (loc);
-}
-
 /* This function builds a dwarf location descriptor sequence from a
    dw_cfa_location, adding the given OFFSET to the result of the
    expression.  */
diff --git a/gcc/dwarf2out.h b/gcc/dwarf2out.h
index 19bae4a..d41453b 100644
--- a/gcc/dwarf2out.h
+++ b/gcc/dwarf2out.h
@@ -228,11 +228,18 @@  extern struct dw_loc_descr_struct *mem_loc_descriptor
 extern enum machine_mode get_address_mode (rtx mem);
 extern dw_fde_ref dwarf2out_alloc_current_fde (void);
 
+extern unsigned long size_of_locs (dw_loc_descr_ref);
+extern void output_loc_sequence (dw_loc_descr_ref, int);
+extern void output_loc_sequence_raw (dw_loc_descr_ref);
+
 /* Interface from dwarf2cfi.c to dwarf2out.c.  */
 extern void lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc,
 			  dw_cfa_location *remember);
 extern bool cfa_equal_p (const dw_cfa_location *, const dw_cfa_location *);
 
+extern void output_cfi (dw_cfi_ref, dw_fde_ref, int);
+extern void output_cfis (cfi_vec, int, bool, dw_fde_ref, bool);
+
 extern GTY(()) cfi_vec cie_cfi_vec;
 
 /* Interface from dwarf2*.c to the rest of the compiler.  */