dwarf2cfi: Implement change_cfi_row.
authorRichard Henderson <rth@redhat.com>
Sat, 23 Jul 2011 20:17:54 +0000 (13:17 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Sat, 23 Jul 2011 20:17:54 +0000 (13:17 -0700)
Add a generic function to adjust cfi state from one row to another.
Use this to implement text section switching.  This will also be
usable for arbitrary changes around a cfg for shrink-wrapping.

        * dwarf2cfi.c (add_cfi_args_size): Split out from...
        (dwarf2out_args_size): ... here.
        (add_cfi_restore): Split out from ...
        (dwarf2out_frame_debug_cfa_restore): ... here.
        (def_cfa_0): Split out from ...
        (def_cfa_1): ... here.
        (cfi_oprnd_equal_p, cfi_equal_p): New.
        (change_cfi_row): New.
        (add_cfis_to_fde): Set fde->dw_fde_switch_cfi_index.
        (create_cfi_notes): Use change_cfi_row at SWITCH_TEXT note.
        (output_cfis): Remove.
        * dwarf2out.c (output_fde): Simplify output_cfi loop.
        (dwarf2out_switch_text_section): Don't call output_cfis.
        (dw_val_equal_p, loc_descr_equal_p_1, loc_descr_equal_p): New.
        * dwarf2out.h: Update decls.
        (enum dw_val_class): Add dw_val_class_none.

From-SVN: r176700

gcc/ChangeLog
gcc/dwarf2cfi.c
gcc/dwarf2out.c
gcc/dwarf2out.h

index 6277b1eee818f668e79c802b25ab7a2849f593b2..89fc46a7f12a19e8e30124c085d198b39edf6a58 100644 (file)
@@ -1,3 +1,22 @@
+2011-07-23  Richard Henderson  <rth@redhat.com>
+
+       * dwarf2cfi.c (add_cfi_args_size): Split out from...
+       (dwarf2out_args_size): ... here.
+       (add_cfi_restore): Split out from ...
+       (dwarf2out_frame_debug_cfa_restore): ... here.
+       (def_cfa_0): Split out from ...
+       (def_cfa_1): ... here.
+       (cfi_oprnd_equal_p, cfi_equal_p): New.
+       (change_cfi_row): New.
+       (add_cfis_to_fde): Set fde->dw_fde_switch_cfi_index.
+       (create_cfi_notes): Use change_cfi_row at SWITCH_TEXT note.
+       (output_cfis): Remove.
+       * dwarf2out.c (output_fde): Simplify output_cfi loop.
+       (dwarf2out_switch_text_section): Don't call output_cfis.
+       (dw_val_equal_p, loc_descr_equal_p_1, loc_descr_equal_p): New.
+       * dwarf2out.h: Update decls.
+       (enum dw_val_class): Add dw_val_class_none.
+
 2011-07-23  Richard Henderson  <rth@redhat.com>
 
        * dwarf2cfi.c (update_row_reg_save): New.
index 36fa7f86cf5f57f1f920164fe4775847379626b6..745e137d26913b46c8853dd8018941c108533a33 100644 (file)
@@ -285,6 +285,28 @@ add_cfi (dw_cfi_ref cfi)
     VEC_safe_push (dw_cfi_ref, gc, *add_cfi_vec, cfi);
 }
 
+static void
+add_cfi_args_size (HOST_WIDE_INT size)
+{
+  dw_cfi_ref cfi = new_cfi ();
+
+  cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
+  cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
+
+  add_cfi (cfi);
+}
+
+static void
+add_cfi_restore (unsigned reg)
+{
+  dw_cfi_ref cfi = new_cfi ();
+
+  cfi->dw_cfi_opc = (reg & ~0x3f ? DW_CFA_restore_extended : DW_CFA_restore);
+  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+
+  add_cfi (cfi);
+}
+
 /* Perform ROW->REG_SAVE[COLUMN] = CFI.  CFI may be null, indicating
    that the register column is no longer saved.  */
 
@@ -474,64 +496,109 @@ cfa_equal_p (const dw_cfa_location *loc1, const dw_cfa_location *loc2)
              || loc1->base_offset == loc2->base_offset));
 }
 
-/* This routine does the actual work.  The CFA is now calculated from
-   the dw_cfa_location structure.  */
+/* Determine if two CFI operands are identical.  */
 
-static void
-def_cfa_1 (dw_cfa_location *loc_p)
+static bool
+cfi_oprnd_equal_p (enum dw_cfi_oprnd_type t, dw_cfi_oprnd *a, dw_cfi_oprnd *b)
 {
-  dw_cfi_ref cfi;
-  dw_cfa_location loc = *loc_p;
+  switch (t)
+    {
+    case dw_cfi_oprnd_unused:
+      return true;
+    case dw_cfi_oprnd_reg_num:
+      return a->dw_cfi_reg_num == b->dw_cfi_reg_num;
+    case dw_cfi_oprnd_offset:
+      return a->dw_cfi_offset == b->dw_cfi_offset;
+    case dw_cfi_oprnd_addr:
+      return (a->dw_cfi_addr == b->dw_cfi_addr
+             || strcmp (a->dw_cfi_addr, b->dw_cfi_addr) == 0);
+    case dw_cfi_oprnd_loc:
+      return loc_descr_equal_p (a->dw_cfi_loc, b->dw_cfi_loc);
+    }
+  gcc_unreachable ();
+}
 
-  if (cfa_store.reg == loc.reg && loc.indirect == 0)
-    cfa_store.offset = loc.offset;
+/* Determine if two CFI entries are identical.  */
+
+static bool
+cfi_equal_p (dw_cfi_ref a, dw_cfi_ref b)
+{
+  enum dwarf_call_frame_info opc;
+
+  /* Make things easier for our callers, including missing operands.  */
+  if (a == b)
+    return true;
+  if (a == NULL || b == NULL)
+    return false;
+
+  /* Obviously, the opcodes must match.  */
+  opc = a->dw_cfi_opc;
+  if (opc != b->dw_cfi_opc)
+    return false;
+
+  /* Compare the two operands, re-using the type of the operands as
+     already exposed elsewhere.  */
+  return (cfi_oprnd_equal_p (dw_cfi_oprnd1_desc (opc),
+                            &a->dw_cfi_oprnd1, &b->dw_cfi_oprnd1)
+         && cfi_oprnd_equal_p (dw_cfi_oprnd2_desc (opc),
+                               &a->dw_cfi_oprnd2, &b->dw_cfi_oprnd2));
+}
+
+/* The CFA is now calculated from NEW_CFA.  Consider OLD_CFA in determining
+   what opcode to emit.  Returns the CFI opcode to effect the change, or
+   NULL if NEW_CFA == OLD_CFA.  */
+
+static dw_cfi_ref
+def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location *new_cfa)
+{
+  dw_cfi_ref cfi;
 
   /* If nothing changed, no need to issue any call frame instructions.  */
-  if (cfa_equal_p (&loc, &cur_row->cfa))
-    return;
+  if (cfa_equal_p (old_cfa, new_cfa))
+    return NULL;
 
   cfi = new_cfi ();
 
-  if (loc.reg == cur_row->cfa.reg && !loc.indirect && !cur_row->cfa.indirect)
+  if (new_cfa->reg == old_cfa->reg && !new_cfa->indirect && !old_cfa->indirect)
     {
       /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction, indicating
         the CFA register did not change but the offset did.  The data
         factoring for DW_CFA_def_cfa_offset_sf happens in output_cfi, or
         in the assembler via the .cfi_def_cfa_offset directive.  */
-      if (loc.offset < 0)
+      if (new_cfa->offset < 0)
        cfi->dw_cfi_opc = DW_CFA_def_cfa_offset_sf;
       else
        cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
-      cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset;
+      cfi->dw_cfi_oprnd1.dw_cfi_offset = new_cfa->offset;
     }
 
 #ifndef MIPS_DEBUGGING_INFO  /* SGI dbx thinks this means no offset.  */
-  else if (loc.offset == cur_row->cfa.offset
-          && cur_row->cfa.reg != INVALID_REGNUM
-          && !loc.indirect
-          && !cur_row->cfa.indirect)
+  else if (new_cfa->offset == old_cfa->offset
+          && old_cfa->reg != INVALID_REGNUM
+          && !new_cfa->indirect
+          && !old_cfa->indirect)
     {
       /* Construct a "DW_CFA_def_cfa_register <register>" instruction,
         indicating the CFA register has changed to <register> but the
         offset has not changed.  */
       cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
-      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
+      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg;
     }
 #endif
 
-  else if (loc.indirect == 0)
+  else if (new_cfa->indirect == 0)
     {
       /* Construct a "DW_CFA_def_cfa <register> <offset>" instruction,
         indicating the CFA register has changed to <register> with
         the specified offset.  The data factoring for DW_CFA_def_cfa_sf
         happens in output_cfi, or in the assembler via the .cfi_def_cfa
         directive.  */
-      if (loc.offset < 0)
+      if (new_cfa->offset < 0)
        cfi->dw_cfi_opc = DW_CFA_def_cfa_sf;
       else
        cfi->dw_cfi_opc = DW_CFA_def_cfa;
-      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
-      cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset;
+      cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg;
+      cfi->dw_cfi_oprnd2.dw_cfi_offset = new_cfa->offset;
     }
   else
     {
@@ -541,14 +608,32 @@ def_cfa_1 (dw_cfa_location *loc_p)
       struct dw_loc_descr_struct *loc_list;
 
       cfi->dw_cfi_opc = DW_CFA_def_cfa_expression;
-      loc_list = build_cfa_loc (&loc, 0);
+      loc_list = build_cfa_loc (new_cfa, 0);
       cfi->dw_cfi_oprnd1.dw_cfi_loc = loc_list;
-
-      cur_row->cfa_cfi = cfi;
     }
 
-  add_cfi (cfi);
-  cur_row->cfa = loc;
+  return cfi;
+}
+
+/* Similarly, but take OLD_CFA from CUR_ROW, and update it after the fact.  */
+
+static void
+def_cfa_1 (dw_cfa_location *new_cfa)
+{
+  dw_cfi_ref cfi;
+
+  if (cfa_store.reg == new_cfa->reg && new_cfa->indirect == 0)
+    cfa_store.offset = new_cfa->offset;
+
+  cfi = def_cfa_0 (&cur_row->cfa, new_cfa);
+  if (cfi)
+    {
+      cur_row->cfa = *new_cfa;
+      if (cfi->dw_cfi_opc == DW_CFA_def_cfa_expression)
+        cur_row->cfa_cfi = cfi;
+
+      add_cfi (cfi);
+    }
 }
 
 /* Add the CFI for saving a register.  REG is the CFA column number.
@@ -871,17 +956,11 @@ compute_barrier_args_size (void)
 static void
 dwarf2out_args_size (HOST_WIDE_INT size)
 {
-  dw_cfi_ref cfi;
-
   if (size == cur_row->args_size)
     return;
 
   cur_row->args_size = size;
-
-  cfi = new_cfi ();
-  cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
-  cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
-  add_cfi (cfi);
+  add_cfi_args_size (size);
 }
 
 /* Record a stack adjustment of OFFSET bytes.  */
@@ -1385,13 +1464,9 @@ dwarf2out_frame_debug_cfa_expression (rtx set)
 static void
 dwarf2out_frame_debug_cfa_restore (rtx reg)
 {
-  dw_cfi_ref cfi = new_cfi ();
   unsigned int regno = dwf_regno (reg);
 
-  cfi->dw_cfi_opc = (regno & ~0x3f ? DW_CFA_restore_extended : DW_CFA_restore);
-  cfi->dw_cfi_oprnd1.dw_cfi_reg_num = regno;
-
-  add_cfi (cfi);
+  add_cfi_restore (regno);
   update_row_reg_save (cur_row, regno, NULL);
 }
 
@@ -2238,6 +2313,48 @@ dwarf2out_frame_debug (rtx insn, bool after_p)
     dwarf2out_flush_queued_reg_saves ();
 }
 
+/* Emit CFI info to change the state from OLD_ROW to NEW_ROW.  */
+
+static void
+change_cfi_row (dw_cfi_row_ref old_row, dw_cfi_row_ref new_row)
+{
+  size_t i, n_old, n_new, n_max;
+  dw_cfi_ref cfi;
+
+  if (new_row->cfa_cfi && !cfi_equal_p (old_row->cfa_cfi, new_row->cfa_cfi))
+    add_cfi (new_row->cfa_cfi);
+  else
+    {
+      cfi = def_cfa_0 (&old_row->cfa, &new_row->cfa);
+      if (cfi)
+       add_cfi (cfi);
+    }
+
+  if (old_row->args_size != new_row->args_size)
+    add_cfi_args_size (new_row->args_size);
+
+  n_old = VEC_length (dw_cfi_ref, old_row->reg_save);
+  n_new = VEC_length (dw_cfi_ref, new_row->reg_save);
+  n_max = MAX (n_old, n_new);
+
+  for (i = 0; i < n_max; ++i)
+    {
+      dw_cfi_ref r_old = NULL, r_new = NULL;
+
+      if (i < n_old)
+       r_old = VEC_index (dw_cfi_ref, old_row->reg_save, i);
+      if (i < n_new)
+       r_new = VEC_index (dw_cfi_ref, new_row->reg_save, i);
+
+      if (r_old == r_new)
+       ;
+      else if (r_new == NULL)
+       add_cfi_restore (i);
+      else if (!cfi_equal_p (r_old, r_new))
+        add_cfi (r_new);
+    }
+}
+
 /* Examine CFI and return true if a cfi label and set_loc is needed
    beforehand.  Even when generating CFI assembler instructions, we
    still have to add the cfi to the list so that lookup_cfa_1 works
@@ -2291,6 +2408,8 @@ add_cfis_to_fde (void)
 
       if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
        {
+         fde->dw_fde_switch_cfi_index
+           = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
          /* Don't attempt to advance_loc4 between labels
             in different sections.  */
          first = true;
@@ -2370,6 +2489,16 @@ create_cfi_notes (void)
              add_cfi_insn = insn;
              dwarf2out_frame_debug_restore_state ();
              break;
+
+           case NOTE_INSN_SWITCH_TEXT_SECTIONS:
+             /* In dwarf2out_switch_text_section, we'll begin a new FDE
+                for the portion of the function in the alternate text
+                section.  The row state at the very beginning of that
+                new FDE will be exactly the row state from the CIE.
+                Emit whatever CFIs are necessary to make CUR_ROW current.  */
+             add_cfi_insn = insn;
+             change_cfi_row (cie_cfi_row, cur_row);
+             break;
            }
          continue;
        }
@@ -3047,175 +3176,6 @@ 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 ();
-       }
-    }
-}
 \f
 
 /* Save the result of dwarf2out_do_frame across PCH.
index 639a383d84898e63a015064f0e947a40de2be86a..d430753bfe5644c2fc65841807ae53c65fa213da 100644 (file)
@@ -519,11 +519,9 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second,
            char *section_start_label, int fde_encoding, char *augmentation,
            bool any_lsda_needed, int lsda_encoding)
 {
-  int ix;
   const char *begin, *end;
   static unsigned int j;
   char l1[20], l2[20];
-  dw_cfi_ref cfi;
 
   targetm.asm_out.emit_unwind_label (asm_out_file, fde->decl, for_eh,
                                     /* empty */ 0);
@@ -603,36 +601,24 @@ output_fde (dw_fde_ref fde, bool for_eh, bool second,
        dw2_asm_output_data_uleb128 (0, "Augmentation size");
     }
 
-  /* Loop through the Call Frame Instructions associated with
-     this FDE.  */
+  /* Loop through the Call Frame Instructions associated with this FDE.  */
   fde->dw_fde_current_label = begin;
-  if (fde->dw_fde_second_begin == NULL)
-    FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi)
-      output_cfi (cfi, fde, for_eh);
-  else if (!second)
-    {
-      if (fde->dw_fde_switch_cfi_index > 0)
-       FOR_EACH_VEC_ELT (dw_cfi_ref, fde->dw_fde_cfi, ix, cfi)
-         {
-           if (ix == fde->dw_fde_switch_cfi_index)
-             break;
-           output_cfi (cfi, fde, for_eh);
-         }
-    }
-  else
-    {
-      int i, from = 0;
-      int until = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
+  {
+    size_t from, until, i;
 
-      if (fde->dw_fde_switch_cfi_index > 0)
-       {
-         from = fde->dw_fde_switch_cfi_index;
-         output_cfis (fde->dw_fde_cfi, from, false, fde, for_eh);
-       }
-      for (i = from; i < until; i++)
-       output_cfi (VEC_index (dw_cfi_ref, fde->dw_fde_cfi, i),
-                   fde, for_eh);
-    }
+    from = 0;
+    until = VEC_length (dw_cfi_ref, fde->dw_fde_cfi);
+
+    if (fde->dw_fde_second_begin == NULL)
+      ;
+    else if (!second)
+      until = fde->dw_fde_switch_cfi_index;
+    else
+      from = fde->dw_fde_switch_cfi_index;
+
+    for (i = from; i < until; i++)
+      output_cfi (VEC_index (dw_cfi_ref, fde->dw_fde_cfi, i), fde, for_eh);
+  }
 
   /* If we are to emit a ref/link from function bodies to their frame tables,
      do it now.  This is typically performed to make sure that tables
@@ -1184,16 +1170,8 @@ 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_cfis (fde->dw_fde_cfi, fde->dw_fde_switch_cfi_index,
-                  true, fde, true);
-    }
+    dwarf2out_do_cfi_startproc (true);
 
   var_location_switch_text_section ();
 
@@ -1639,6 +1617,109 @@ add_loc_descr (dw_loc_descr_ref *list_head, dw_loc_descr_ref descr)
   *d = descr;
 }
 
+/* Compare two location operands for exact equality.  */
+
+static bool
+dw_val_equal_p (dw_val_node *a, dw_val_node *b)
+{
+  if (a->val_class != b->val_class)
+    return false;
+  switch (a->val_class)
+    {
+    case dw_val_class_none:
+      return true;
+    case dw_val_class_addr:
+      return rtx_equal_p (a->v.val_addr, b->v.val_addr);
+
+    case dw_val_class_offset:
+    case dw_val_class_unsigned_const:
+    case dw_val_class_const:
+    case dw_val_class_range_list:
+    case dw_val_class_lineptr:
+    case dw_val_class_macptr:
+      /* These are all HOST_WIDE_INT, signed or unsigned.  */
+      return a->v.val_unsigned == b->v.val_unsigned;
+
+    case dw_val_class_loc:
+      return a->v.val_loc == b->v.val_loc;
+    case dw_val_class_loc_list:
+      return a->v.val_loc_list == b->v.val_loc_list;
+    case dw_val_class_die_ref:
+      return a->v.val_die_ref.die == b->v.val_die_ref.die;
+    case dw_val_class_fde_ref:
+      return a->v.val_fde_index == b->v.val_fde_index;
+    case dw_val_class_lbl_id:
+      return strcmp (a->v.val_lbl_id, b->v.val_lbl_id) == 0;
+    case dw_val_class_str:
+      return a->v.val_str == b->v.val_str;
+    case dw_val_class_flag:
+      return a->v.val_flag == b->v.val_flag;
+    case dw_val_class_file:
+      return a->v.val_file == b->v.val_file;
+    case dw_val_class_decl_ref:
+      return a->v.val_decl_ref == b->v.val_decl_ref;
+    
+    case dw_val_class_const_double:
+      return (a->v.val_double.high == b->v.val_double.high
+             && a->v.val_double.low == b->v.val_double.low);
+
+    case dw_val_class_vec:
+      {
+       size_t a_len = a->v.val_vec.elt_size * a->v.val_vec.length;
+       size_t b_len = b->v.val_vec.elt_size * b->v.val_vec.length;
+
+       return (a_len == b_len
+               && !memcmp (a->v.val_vec.array, b->v.val_vec.array, a_len));
+      }
+
+    case dw_val_class_data8:
+      return memcmp (a->v.val_data8, b->v.val_data8, 8) == 0;
+
+    case dw_val_class_vms_delta:
+      return (!strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1)
+              && !strcmp (a->v.val_vms_delta.lbl1, b->v.val_vms_delta.lbl1));
+    }
+  gcc_unreachable ();
+}
+
+/* Compare two location atoms for exact equality.  */
+
+static bool
+loc_descr_equal_p_1 (dw_loc_descr_ref a, dw_loc_descr_ref b)
+{
+  if (a->dw_loc_opc != b->dw_loc_opc)
+    return false;
+
+  /* ??? This is only ever set for DW_OP_constNu, for N equal to the
+     address size, but since we always allocate cleared storage it
+     should be zero for other types of locations.  */
+  if (a->dtprel != b->dtprel)
+    return false;
+
+  return (dw_val_equal_p (&a->dw_loc_oprnd1, &b->dw_loc_oprnd1)
+         && dw_val_equal_p (&a->dw_loc_oprnd2, &b->dw_loc_oprnd2));
+}
+
+/* Compare two complete location expressions for exact equality.  */
+
+bool
+loc_descr_equal_p (dw_loc_descr_ref a, dw_loc_descr_ref b)
+{
+  while (1)
+    {
+      if (a == b)
+       return true;
+      if (a == NULL || b == NULL)
+       return false;
+      if (!loc_descr_equal_p_1 (a, b))
+       return false;
+
+      a = a->dw_loc_next;
+      b = b->dw_loc_next;
+    }
+}
+
+
 /* Add a constant OFFSET to a location expression.  */
 
 static void
index d0e76a786f8a1c6ef2a97ba34e99a1d3c0b4bbcb..711e8ab0d5ede91cbfef5e691730d43f11afedce 100644 (file)
@@ -134,6 +134,7 @@ typedef struct GTY(()) cfa_loc {
 
 enum dw_val_class
 {
+  dw_val_class_none,
   dw_val_class_addr,
   dw_val_class_offset,
   dw_val_class_loc,
@@ -226,6 +227,7 @@ extern struct dw_loc_descr_struct *build_cfa_aligned_loc
 extern struct dw_loc_descr_struct *mem_loc_descriptor
   (rtx, enum machine_mode mode, enum machine_mode mem_mode,
    enum var_init_status);
+extern bool loc_descr_equal_p (dw_loc_descr_ref, dw_loc_descr_ref);
 extern enum machine_mode get_address_mode (rtx mem);
 extern dw_fde_ref dwarf2out_alloc_current_fde (void);
 
@@ -239,7 +241,6 @@ extern void lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc,
 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;