re PR target/65697 (__atomic memory barriers not strong enough for __sync builtins)
[gcc.git] / gcc / dwarf2cfi.c
index 245282408221557cdb40d7dddd1065d6917b5c52..e7117fffcc130b44ed4d5b7e953b2248eb9abe1a 100644 (file)
@@ -1,5 +1,5 @@
 /* Dwarf2 Call Frame Information helper routines.
-   Copyright (C) 1992-2014 Free Software Foundation, Inc.
+   Copyright (C) 1992-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -24,21 +24,30 @@ along with GCC; see the file COPYING3.  If not see
 #include "version.h"
 #include "flags.h"
 #include "rtl.h"
+#include "alias.h"
+#include "symtab.h"
 #include "tree.h"
 #include "stor-layout.h"
+#include "hard-reg-set.h"
 #include "function.h"
-#include "basic-block.h"
+#include "cfgbuild.h"
 #include "dwarf2.h"
 #include "dwarf2out.h"
 #include "dwarf2asm.h"
-#include "ggc.h"
-#include "hash-table.h"
 #include "tm_p.h"
 #include "target.h"
 #include "common/common-target.h"
 #include "tree-pass.h"
 
 #include "except.h"            /* expand_builtin_dwarf_sp_column */
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
 #include "expr.h"              /* init_return_column_size */
 #include "regs.h"              /* expand_builtin_init_dwarf_reg_sizes */
 #include "output.h"            /* asm_out_file */
@@ -100,7 +109,7 @@ typedef struct GTY(()) reg_saved_in_data_struct {
 typedef struct
 {
   /* The insn that begins the trace.  */
-  rtx head;
+  rtx_insn *head;
 
   /* The row state at the beginning and end of the trace.  */
   dw_cfi_row *beg_row, *end_row;
@@ -113,7 +122,7 @@ typedef struct
   HOST_WIDE_INT beg_delay_args_size, end_delay_args_size;
 
   /* The first EH insn in the trace, where beg_delay_args_size must be set.  */
-  rtx eh_head;
+  rtx_insn *eh_head;
 
   /* The following variables contain data used in interpreting frame related
      expressions.  These are not part of the "real" row state as defined by
@@ -158,22 +167,20 @@ typedef dw_trace_info *dw_trace_info_ref;
 
 /* Hashtable helpers.  */
 
-struct trace_info_hasher : typed_noop_remove <dw_trace_info>
+struct trace_info_hasher : nofree_ptr_hash <dw_trace_info>
 {
-  typedef dw_trace_info value_type;
-  typedef dw_trace_info compare_type;
-  static inline hashval_t hash (const value_type *);
-  static inline bool equal (const value_type *, const compare_type *);
+  static inline hashval_t hash (const dw_trace_info *);
+  static inline bool equal (const dw_trace_info *, const dw_trace_info *);
 };
 
 inline hashval_t
-trace_info_hasher::hash (const value_type *ti)
+trace_info_hasher::hash (const dw_trace_info *ti)
 {
   return INSN_UID (ti->head);
 }
 
 inline bool
-trace_info_hasher::equal (const value_type *a, const compare_type *b)
+trace_info_hasher::equal (const dw_trace_info *a, const dw_trace_info *b)
 {
   return a->head == b->head;
 }
@@ -196,7 +203,7 @@ static GTY(()) reg_saved_in_data *cie_return_save;
 static GTY(()) unsigned long dwarf2out_cfi_label_num;
 
 /* The insn after which a new CFI note should be emitted.  */
-static rtx add_cfi_insn;
+static rtx_insn *add_cfi_insn;
 
 /* When non-null, add_cfi will add the CFI to this vector.  */
 static cfi_vec *add_cfi_vec;
@@ -244,7 +251,7 @@ expand_builtin_dwarf_sp_column (void)
    which has mode MODE.  Initialize column C as a return address column.  */
 
 static void
-init_return_column_size (enum machine_mode mode, rtx mem, unsigned int c)
+init_return_column_size (machine_mode mode, rtx mem, unsigned int c)
 {
   HOST_WIDE_INT offset = c * GET_MODE_SIZE (mode);
   HOST_WIDE_INT size = GET_MODE_SIZE (Pmode);
@@ -252,46 +259,103 @@ init_return_column_size (enum machine_mode mode, rtx mem, unsigned int c)
                  gen_int_mode (size, mode));
 }
 
-/* Generate code to initialize the register size table.  */
+/* Datastructure used by expand_builtin_init_dwarf_reg_sizes and
+   init_one_dwarf_reg_size to communicate on what has been done by the
+   latter.  */
+
+typedef struct
+{
+  /* Whether the dwarf return column was initialized.  */
+  bool wrote_return_column;
+
+  /* For each hard register REGNO, whether init_one_dwarf_reg_size
+     was given REGNO to process already.  */
+  bool processed_regno [FIRST_PSEUDO_REGISTER];
+
+} init_one_dwarf_reg_state;
+
+/* Helper for expand_builtin_init_dwarf_reg_sizes.  Generate code to
+   initialize the dwarf register size table entry corresponding to register
+   REGNO in REGMODE.  TABLE is the table base address, SLOTMODE is the mode to
+   use for the size entry to initialize, and INIT_STATE is the communication
+   datastructure conveying what we're doing to our caller.  */
+
+static
+void init_one_dwarf_reg_size (int regno, machine_mode regmode,
+                             rtx table, machine_mode slotmode,
+                             init_one_dwarf_reg_state *init_state)
+{
+  const unsigned int dnum = DWARF_FRAME_REGNUM (regno);
+  const unsigned int rnum = DWARF2_FRAME_REG_OUT (dnum, 1);
+  const unsigned int dcol = DWARF_REG_TO_UNWIND_COLUMN (rnum);
+  
+  const HOST_WIDE_INT slotoffset = dcol * GET_MODE_SIZE (slotmode);
+  const HOST_WIDE_INT regsize = GET_MODE_SIZE (regmode);
+
+  init_state->processed_regno[regno] = true;
+
+  if (rnum >= DWARF_FRAME_REGISTERS)
+    return;
+
+  if (dnum == DWARF_FRAME_RETURN_COLUMN)
+    {
+      if (regmode == VOIDmode)
+       return;
+      init_state->wrote_return_column = true;
+    }
+
+  if (slotoffset < 0)
+    return;
+
+  emit_move_insn (adjust_address (table, slotmode, slotoffset),
+                 gen_int_mode (regsize, slotmode));
+}
+
+/* Generate code to initialize the dwarf register size table located
+   at the provided ADDRESS.  */
 
 void
 expand_builtin_init_dwarf_reg_sizes (tree address)
 {
   unsigned int i;
-  enum machine_mode mode = TYPE_MODE (char_type_node);
+  machine_mode mode = TYPE_MODE (char_type_node);
   rtx addr = expand_normal (address);
   rtx mem = gen_rtx_MEM (BLKmode, addr);
-  bool wrote_return_column = false;
+
+  init_one_dwarf_reg_state init_state;
+
+  memset ((char *)&init_state, 0, sizeof (init_state));
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
-      unsigned int dnum = DWARF_FRAME_REGNUM (i);
-      unsigned int rnum = DWARF2_FRAME_REG_OUT (dnum, 1);
+      machine_mode save_mode;
+      rtx span;
 
-      if (rnum < DWARF_FRAME_REGISTERS)
-       {
-         HOST_WIDE_INT offset = rnum * GET_MODE_SIZE (mode);
-         enum machine_mode save_mode = reg_raw_mode[i];
-         HOST_WIDE_INT size;
+      /* No point in processing a register multiple times.  This could happen
+        with register spans, e.g. when a reg is first processed as a piece of
+        a span, then as a register on its own later on.  */
+
+      if (init_state.processed_regno[i])
+       continue;
 
-         if (HARD_REGNO_CALL_PART_CLOBBERED (i, save_mode))
-           save_mode = choose_hard_reg_mode (i, 1, true);
-         if (dnum == DWARF_FRAME_RETURN_COLUMN)
+      save_mode = targetm.dwarf_frame_reg_mode (i);
+      span = targetm.dwarf_register_span (gen_rtx_REG (save_mode, i));
+
+      if (!span)
+       init_one_dwarf_reg_size (i, save_mode, mem, mode, &init_state);
+      else
+       {
+         for (int si = 0; si < XVECLEN (span, 0); si++)
            {
-             if (save_mode == VOIDmode)
-               continue;
-             wrote_return_column = true;
-           }
-         size = GET_MODE_SIZE (save_mode);
-         if (offset < 0)
-           continue;
+             rtx reg = XVECEXP (span, 0, si);
 
-         emit_move_insn (adjust_address (mem, mode, offset),
-                         gen_int_mode (size, mode));
+             init_one_dwarf_reg_size
+               (REGNO (reg), GET_MODE (reg), mem, mode, &init_state);
+           }
        }
     }
 
-  if (!wrote_return_column)
+  if (!init_state.wrote_return_column)
     init_return_column_size (mode, mem, DWARF_FRAME_RETURN_COLUMN);
 
 #ifdef DWARF_ALT_FRAME_RETURN_COLUMN
@@ -303,7 +367,7 @@ expand_builtin_init_dwarf_reg_sizes (tree address)
 
 \f
 static dw_trace_info *
-get_trace_info (rtx insn)
+get_trace_info (rtx_insn *insn)
 {
   dw_trace_info dummy;
   dummy.head = insn;
@@ -311,7 +375,7 @@ get_trace_info (rtx insn)
 }
 
 static bool
-save_point_p (rtx insn)
+save_point_p (rtx_insn *insn)
 {
   /* Labels, except those that are really jump tables.  */
   if (LABEL_P (insn))
@@ -841,7 +905,7 @@ reg_save (unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset)
    and adjust data structures to match.  */
 
 static void
-notice_args_size (rtx insn)
+notice_args_size (rtx_insn *insn)
 {
   HOST_WIDE_INT args_size, delta;
   rtx note;
@@ -865,9 +929,9 @@ notice_args_size (rtx insn)
 
       /* Convert a change in args_size (always a positive in the
         direction of stack growth) to a change in stack pointer.  */
-#ifndef STACK_GROWS_DOWNWARD
-      delta = -delta;
-#endif
+      if (!STACK_GROWS_DOWNWARD)
+       delta = -delta;
+
       cur_cfa->offset += delta;
     }
 }
@@ -876,7 +940,7 @@ notice_args_size (rtx insn)
    data within the trace related to EH insns and args_size.  */
 
 static void
-notice_eh_throw (rtx insn)
+notice_eh_throw (rtx_insn *insn)
 {
   HOST_WIDE_INT args_size;
 
@@ -1937,16 +2001,16 @@ dwarf2out_frame_debug_expr (rtx expr)
    register to the stack.  */
 
 static void
-dwarf2out_frame_debug (rtx insn)
+dwarf2out_frame_debug (rtx_insn *insn)
 {
-  rtx note, n;
+  rtx note, n, pat;
   bool handled_one = false;
 
   for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
     switch (REG_NOTE_KIND (note))
       {
       case REG_FRAME_RELATED_EXPR:
-       insn = XEXP (note, 0);
+       pat = XEXP (note, 0);
        goto do_frame_expr;
 
       case REG_CFA_DEF_CFA:
@@ -2038,14 +2102,14 @@ dwarf2out_frame_debug (rtx insn)
 
   if (!handled_one)
     {
-      insn = PATTERN (insn);
+      pat = PATTERN (insn);
     do_frame_expr:
-      dwarf2out_frame_debug_expr (insn);
+      dwarf2out_frame_debug_expr (pat);
 
       /* 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 at the start of the function.  */
-      if (clobbers_queued_reg_save (insn))
+      if (clobbers_queued_reg_save (pat))
        dwarf2out_flush_queued_reg_saves ();
     }
 }
@@ -2168,7 +2232,6 @@ add_cfis_to_fde (void)
              int num = dwarf2out_cfi_label_num;
              const char *label = dwarf2out_cfi_label ();
              dw_cfi_ref xcfi;
-             rtx tmp;
 
              /* Set the location counter to the new label.  */
              xcfi = new_cfi ();
@@ -2177,7 +2240,7 @@ add_cfis_to_fde (void)
              xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
              vec_safe_push (fde->dw_fde_cfi, xcfi);
 
-             tmp = emit_note_before (NOTE_INSN_CFI_LABEL, insn);
+             rtx_note *tmp = emit_note_before (NOTE_INSN_CFI_LABEL, insn);
              NOTE_LABEL_NUMBER (tmp) = num;
            }
 
@@ -2197,7 +2260,7 @@ add_cfis_to_fde (void)
    trace from CUR_TRACE and CUR_ROW.  */
 
 static void
-maybe_record_trace_start (rtx start, rtx origin)
+maybe_record_trace_start (rtx_insn *start, rtx_insn *origin)
 {
   dw_trace_info *ti;
   HOST_WIDE_INT args_size;
@@ -2248,7 +2311,7 @@ maybe_record_trace_start (rtx start, rtx origin)
    and non-local goto edges.  */
 
 static void
-maybe_record_trace_start_abnormal (rtx start, rtx origin)
+maybe_record_trace_start_abnormal (rtx_insn *start, rtx_insn *origin)
 {
   HOST_WIDE_INT save_args_size, delta;
   dw_cfa_location save_cfa;
@@ -2268,9 +2331,9 @@ maybe_record_trace_start_abnormal (rtx start, rtx origin)
     {
       /* Convert a change in args_size (always a positive in the
         direction of stack growth) to a change in stack pointer.  */
-#ifndef STACK_GROWS_DOWNWARD
-      delta = -delta;
-#endif
+      if (!STACK_GROWS_DOWNWARD)
+       delta = -delta;
+
       cur_row->cfa.offset += delta;
     }
   
@@ -2284,7 +2347,7 @@ maybe_record_trace_start_abnormal (rtx start, rtx origin)
 /* ??? Sadly, this is in large part a duplicate of make_edges.  */
 
 static void
-create_trace_edges (rtx insn)
+create_trace_edges (rtx_insn *insn)
 {
   rtx tmp;
   int i, n;
@@ -2303,14 +2366,14 @@ create_trace_edges (rtx insn)
          n = GET_NUM_ELEM (vec);
          for (i = 0; i < n; ++i)
            {
-             rtx lab = XEXP (RTVEC_ELT (vec, i), 0);
+             rtx_insn *lab = as_a <rtx_insn *> (XEXP (RTVEC_ELT (vec, i), 0));
              maybe_record_trace_start (lab, insn);
            }
        }
       else if (computed_jump_p (insn))
        {
-         for (rtx_expr_list *lab = forced_labels; lab; lab = lab->next ())
-           maybe_record_trace_start (lab->element (), insn);
+         for (rtx_insn_list *lab = forced_labels; lab; lab = lab->next ())
+           maybe_record_trace_start (lab->insn (), insn);
        }
       else if (returnjump_p (insn))
        ;
@@ -2319,13 +2382,14 @@ create_trace_edges (rtx insn)
          n = ASM_OPERANDS_LABEL_LENGTH (tmp);
          for (i = 0; i < n; ++i)
            {
-             rtx lab = XEXP (ASM_OPERANDS_LABEL (tmp, i), 0);
+             rtx_insn *lab =
+               as_a <rtx_insn *> (XEXP (ASM_OPERANDS_LABEL (tmp, i), 0));
              maybe_record_trace_start (lab, insn);
            }
        }
       else
        {
-         rtx lab = JUMP_LABEL (insn);
+         rtx_insn *lab = JUMP_LABEL_AS_INSN (insn);
          gcc_assert (lab != NULL);
          maybe_record_trace_start (lab, insn);
        }
@@ -2338,10 +2402,10 @@ create_trace_edges (rtx insn)
 
       /* Process non-local goto edges.  */
       if (can_nonlocal_goto (insn))
-       for (rtx_expr_list *lab = nonlocal_goto_handler_labels;
+       for (rtx_insn_list *lab = nonlocal_goto_handler_labels;
             lab;
             lab = lab->next ())
-         maybe_record_trace_start_abnormal (lab->element (), insn);
+         maybe_record_trace_start_abnormal (lab->insn (), insn);
     }
   else if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (PATTERN (insn)))
     {
@@ -2363,7 +2427,7 @@ create_trace_edges (rtx insn)
 /* A subroutine of scan_trace.  Do what needs to be done "after" INSN.  */
 
 static void
-scan_insn_after (rtx insn)
+scan_insn_after (rtx_insn *insn)
 {
   if (RTX_FRAME_RELATED_P (insn))
     dwarf2out_frame_debug (insn);
@@ -2376,7 +2440,7 @@ scan_insn_after (rtx insn)
 static void
 scan_trace (dw_trace_info *trace)
 {
-  rtx prev, insn = trace->head;
+  rtx_insn *prev, *insn = trace->head;
   dw_cfa_location this_cfa;
 
   if (dump_file)
@@ -2397,7 +2461,7 @@ scan_trace (dw_trace_info *trace)
        insn;
        prev = insn, insn = NEXT_INSN (insn))
     {
-      rtx control;
+      rtx_insn *control;
 
       /* Do everything that happens "before" the insn.  */
       add_cfi_insn = prev;
@@ -2424,10 +2488,10 @@ scan_trace (dw_trace_info *trace)
         handling for the positioning of the notes.  */
       if (rtx_sequence *pat = dyn_cast <rtx_sequence *> (PATTERN (insn)))
        {
-         rtx elt;
+         rtx_insn *elt;
          int i, n = pat->len ();
 
-         control = pat->element (0);
+         control = pat->insn (0);
          if (can_throw_internal (control))
            notice_eh_throw (control);
          dwarf2out_flush_queued_reg_saves ();
@@ -2439,7 +2503,7 @@ scan_trace (dw_trace_info *trace)
              gcc_assert (!RTX_FRAME_RELATED_P (control));
              gcc_assert (!find_reg_note (control, REG_ARGS_SIZE, NULL));
 
-             elt = pat->element (1);
+             elt = pat->insn (1);
 
              if (INSN_FROM_TARGET_P (elt))
                {
@@ -2494,7 +2558,7 @@ scan_trace (dw_trace_info *trace)
 
          for (i = 1; i < n; ++i)
            {
-             elt = pat->element (i);
+             elt = pat->insn (i);
              scan_insn_after (elt);
            }
 
@@ -2576,10 +2640,10 @@ create_cfi_notes (void)
 
 /* Return the insn before the first NOTE_INSN_CFI after START.  */
 
-static rtx
-before_next_cfi_note (rtx start)
+static rtx_insn *
+before_next_cfi_note (rtx_insn *start)
 {
-  rtx prev = start;
+  rtx_insn *prev = start;
   while (start)
     {
       if (NOTE_P (start) && NOTE_KIND (start) == NOTE_INSN_CFI)
@@ -2674,7 +2738,7 @@ connect_traces (void)
 
       if (dump_file && add_cfi_insn != ti->head)
        {
-         rtx note;
+         rtx_insn *note;
 
          fprintf (dump_file, "Fixup between trace %u and %u:\n",
                   prev_ti->id, ti->id);
@@ -2764,7 +2828,7 @@ create_pseudo_cfg (void)
          memset (&ti, 0, sizeof (ti));
          ti.head = insn;
          ti.switch_sections = switch_sections;
-         ti.id = trace_info.length () - 1;
+         ti.id = trace_info.length ();
          trace_info.safe_push (ti);
 
          saw_barrier = false;
@@ -2782,7 +2846,7 @@ create_pseudo_cfg (void)
       dw_trace_info **slot;
 
       if (dump_file)
-       fprintf (dump_file, "Creating trace %u : start at %s %d%s\n", i,
+       fprintf (dump_file, "Creating trace %u : start at %s %d%s\n", tp->id,
                 rtx_name[(int) GET_CODE (tp->head)], INSN_UID (tp->head),
                 tp->switch_sections ? " (section switch)" : "");
 
@@ -2861,7 +2925,6 @@ create_cie_data (void)
   dw_trace_info cie_trace;
 
   dw_stack_pointer_regnum = DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM);
-  dw_frame_pointer_regnum = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM);
 
   memset (&cie_trace, 0, sizeof (cie_trace));
   cur_trace = &cie_trace;
@@ -2914,6 +2977,9 @@ create_cie_data (void)
 static unsigned int
 execute_dwarf2_frame (void)
 {
+  /* Different HARD_FRAME_POINTER_REGNUM might coexist in the same file.  */
+  dw_frame_pointer_regnum = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM);
+
   /* The first time we're called, compute the incoming frame state.  */
   if (cie_cfi_vec == NULL)
     create_cie_data ();
@@ -3178,7 +3244,7 @@ output_cfi_directive (FILE *f, dw_cfi_ref cfi)
     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",
+      fprintf (f, "\t.cfi_offset %lu, " HOST_WIDE_INT_PRINT_DEC"\n",
               r, cfi->dw_cfi_oprnd2.dw_cfi_offset);
       break;
 
@@ -3201,7 +3267,7 @@ output_cfi_directive (FILE *f, dw_cfi_ref cfi)
     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",
+      fprintf (f, "\t.cfi_def_cfa %lu, " HOST_WIDE_INT_PRINT_DEC"\n",
               r, cfi->dw_cfi_oprnd2.dw_cfi_offset);
       break;
 
@@ -3236,13 +3302,13 @@ output_cfi_directive (FILE *f, dw_cfi_ref cfi)
          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,
+           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",
+         fprintf (f, "\t.cfi_GNU_args_size " HOST_WIDE_INT_PRINT_DEC "\n",
                   cfi->dw_cfi_oprnd1.dw_cfi_offset);
        }
       break;