OSDN Git Service

PR debug/43983
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 13 May 2010 10:40:51 +0000 (10:40 +0000)
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 13 May 2010 10:40:51 +0000 (10:40 +0000)
* var-tracking.c (track_expr_p): Allow tracking of variables optimized
by SRA.
* Makefile.in (dwarf2out.o): Depend on $(TREE_FLOW_H).
* tree-sra.c (create_access_replacement): Call unshare_expr before
passing expr to SET_DECL_DEBUG_EXPR, and remove any SSA_NAMEs from
it.
* dwarf2out.c: Include tree-flow.h.
(struct var_loc_node): Rename var_loc_note field to loc, add comment.
(size_of_loc_descr, output_loc_operands, output_loc_operands_raw):
Handle DW_OP_bit_piece.
(decl_piece_bitsize, decl_piece_varloc_ptr, decl_piece_node,
construct_piece_list, adjust_piece_list): New functions.
(add_var_loc_to_decl): Handle SRA optimized variables.
Adjust for var_loc_note to loc field renaming.
(dw_loc_list_1): For WANT_ADDRESS == 2 prefer DECL_MODE of decl
in VAR_LOCATION note.
(new_loc_descr_op_bit_piece): New function.
(dw_sra_loc_expr): New function.
(dw_loc_list): Use it.  Don't handle the last range after the
loop, handle it inside of the loop.  Adjust for var_loc_note
to loc field renaming.
(add_location_or_const_value_attribute): Only special case
single entry loc lists if loc is NOTE_P.  Adjust for
var_loc_note to loc field renaming.
(dwarf2out_var_location): Don't set newloc->var_loc_note
and newloc->next here.

* gcc.dg/guality/sra-1.c: New test.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@159357 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/Makefile.in
gcc/dwarf2out.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/guality/sra-1.c [new file with mode: 0644]
gcc/tree-sra.c
gcc/var-tracking.c

index f6b1554..d031767 100644 (file)
@@ -1,3 +1,33 @@
+2010-05-13  Jakub Jelinek  <jakub@redhat.com>
+
+       PR debug/43983
+       * var-tracking.c (track_expr_p): Allow tracking of variables optimized
+       by SRA.
+       * Makefile.in (dwarf2out.o): Depend on $(TREE_FLOW_H).
+       * tree-sra.c (create_access_replacement): Call unshare_expr before
+       passing expr to SET_DECL_DEBUG_EXPR, and remove any SSA_NAMEs from
+       it.
+       * dwarf2out.c: Include tree-flow.h.
+       (struct var_loc_node): Rename var_loc_note field to loc, add comment.
+       (size_of_loc_descr, output_loc_operands, output_loc_operands_raw):
+       Handle DW_OP_bit_piece.
+       (decl_piece_bitsize, decl_piece_varloc_ptr, decl_piece_node,
+       construct_piece_list, adjust_piece_list): New functions.
+       (add_var_loc_to_decl): Handle SRA optimized variables.
+       Adjust for var_loc_note to loc field renaming.
+       (dw_loc_list_1): For WANT_ADDRESS == 2 prefer DECL_MODE of decl
+       in VAR_LOCATION note.
+       (new_loc_descr_op_bit_piece): New function.
+       (dw_sra_loc_expr): New function.
+       (dw_loc_list): Use it.  Don't handle the last range after the
+       loop, handle it inside of the loop.  Adjust for var_loc_note
+       to loc field renaming.
+       (add_location_or_const_value_attribute): Only special case
+       single entry loc lists if loc is NOTE_P.  Adjust for
+       var_loc_note to loc field renaming.
+       (dwarf2out_var_location): Don't set newloc->var_loc_note
+       and newloc->next here.
+
 2010-05-12  Jan Hubicka  <jh@suse.cz>
 
        * cgraph.c (cgraph_mark_address_taken_node): No longer imply needed flag.
index 9fef0ce..3ce9d60 100644 (file)
@@ -2846,7 +2846,7 @@ dwarf2out.o : dwarf2out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    output.h $(DIAGNOSTIC_H) $(REAL_H) hard-reg-set.h $(REGS_H) $(EXPR_H) \
    libfuncs.h $(TOPLEV_H) dwarf2out.h reload.h $(GGC_H) $(EXCEPT_H) dwarf2asm.h \
    $(TM_P_H) langhooks.h $(HASHTAB_H) gt-dwarf2out.h $(TARGET_H) $(CGRAPH_H) \
-   $(MD5_H) $(INPUT_H) $(FUNCTION_H) $(GIMPLE_H) $(TREE_PASS_H)
+   $(MD5_H) $(INPUT_H) $(FUNCTION_H) $(GIMPLE_H) $(TREE_PASS_H) $(TREE_FLOW_H)
 dwarf2asm.o : dwarf2asm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(FLAGS_H) $(RTL_H) $(TREE_H) output.h dwarf2asm.h $(TM_P_H) $(GGC_H) \
    gt-dwarf2asm.h $(DWARF2_H) $(SPLAY_TREE_H) $(TARGET_H)
index 2e8ed39..fc941e2 100644 (file)
@@ -91,6 +91,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "input.h"
 #include "gimple.h"
 #include "tree-pass.h"
+#include "tree-flow.h"
 
 #ifdef DWARF2_DEBUGGING_INFO
 static void dwarf2out_source_line (unsigned int, const char *, int, bool);
@@ -4784,6 +4785,10 @@ size_of_loc_descr (dw_loc_descr_ref loc)
     case DW_OP_piece:
       size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
       break;
+    case DW_OP_bit_piece:
+      size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+      size += size_of_uleb128 (loc->dw_loc_oprnd2.v.val_unsigned);
+      break;
     case DW_OP_deref_size:
     case DW_OP_xderef_size:
       size += 1;
@@ -5008,6 +5013,10 @@ output_loc_operands (dw_loc_descr_ref loc)
     case DW_OP_piece:
       dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
       break;
+    case DW_OP_bit_piece:
+      dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
+      dw2_asm_output_data_uleb128 (val2->v.val_unsigned, NULL);
+      break;
     case DW_OP_deref_size:
     case DW_OP_xderef_size:
       dw2_asm_output_data (1, val1->v.val_int, NULL);
@@ -5123,6 +5132,12 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
       dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned);
       break;
 
+    case DW_OP_bit_piece:
+      fputc (',', asm_out_file);
+      dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned);
+      dw2_asm_output_data_uleb128_raw (val2->v.val_unsigned);
+      break;
+
     case DW_OP_consts:
     case DW_OP_breg0:
     case DW_OP_breg1:
@@ -5739,7 +5754,15 @@ DEF_VEC_ALLOC_O(die_arg_entry,gc);
 
 /* Node of the variable location list.  */
 struct GTY ((chain_next ("%h.next"))) var_loc_node {
-  rtx GTY (()) var_loc_note;
+  /* Either NOTE_INSN_VAR_LOCATION, or, for SRA optimized variables,
+     EXPR_LIST chain.  For small bitsizes, bitsize is encoded
+     in mode of the EXPR_LIST node and first EXPR_LIST operand
+     is either NOTE_INSN_VAR_LOCATION for a piece with a known
+     location or NULL for padding.  For larger bitsizes,
+     mode is 0 and first operand is a CONCAT with bitsize
+     as first CONCAT operand and NOTE_INSN_VAR_LOCATION resp.
+     NULL as second operand.  */
+  rtx GTY (()) loc;
   const char * GTY (()) label;
   struct var_loc_node * GTY (()) next;
 };
@@ -7757,16 +7780,175 @@ equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
   decl_die->decl_id = decl_id;
 }
 
+/* Return how many bits covers PIECE EXPR_LIST.  */
+
+static int
+decl_piece_bitsize (rtx piece)
+{
+  int ret = (int) GET_MODE (piece);
+  if (ret)
+    return ret;
+  gcc_assert (GET_CODE (XEXP (piece, 0)) == CONCAT
+             && CONST_INT_P (XEXP (XEXP (piece, 0), 0)));
+  return INTVAL (XEXP (XEXP (piece, 0), 0));
+}
+
+/* Return pointer to the location of location note in PIECE EXPR_LIST.  */
+
+static rtx *
+decl_piece_varloc_ptr (rtx piece)
+{
+  if ((int) GET_MODE (piece))
+    return &XEXP (piece, 0);
+  else
+    return &XEXP (XEXP (piece, 0), 1);
+}
+
+/* Create an EXPR_LIST for location note LOC_NOTE covering BITSIZE bits.
+   Next is the chain of following piece nodes.  */
+
+static rtx
+decl_piece_node (rtx loc_note, HOST_WIDE_INT bitsize, rtx next)
+{
+  if (bitsize <= (int) MAX_MACHINE_MODE)
+    return alloc_EXPR_LIST (bitsize, loc_note, next);
+  else
+    return alloc_EXPR_LIST (0, gen_rtx_CONCAT (VOIDmode,
+                                              GEN_INT (bitsize),
+                                              loc_note), next);
+}
+
+/* Return rtx that should be stored into loc field for
+   LOC_NOTE and BITPOS/BITSIZE.  */
+
+static rtx
+construct_piece_list (rtx loc_note, HOST_WIDE_INT bitpos,
+                     HOST_WIDE_INT bitsize)
+{
+  if (bitsize != -1)
+    {
+      loc_note = decl_piece_node (loc_note, bitsize, NULL_RTX);
+      if (bitpos != 0)
+       loc_note = decl_piece_node (NULL_RTX, bitpos, loc_note);
+    }
+  return loc_note;
+}
+
+/* This function either modifies location piece list *DEST in
+   place (if SRC and INNER is NULL), or copies location piece list
+   *SRC to *DEST while modifying it.  Location BITPOS is modified
+   to contain LOC_NOTE, any pieces overlapping it are removed resp.
+   not copied and if needed some padding around it is added.
+   When modifying in place, DEST should point to EXPR_LIST where
+   earlier pieces cover PIECE_BITPOS bits, when copying SRC points
+   to the start of the whole list and INNER points to the EXPR_LIST
+   where earlier pieces cover PIECE_BITPOS bits.  */
+
+static void
+adjust_piece_list (rtx *dest, rtx *src, rtx *inner,
+                  HOST_WIDE_INT bitpos, HOST_WIDE_INT piece_bitpos,
+                  HOST_WIDE_INT bitsize, rtx loc_note)
+{
+  int diff;
+  bool copy = inner != NULL;
+
+  if (copy)
+    {
+      /* First copy all nodes preceeding the current bitpos.  */
+      while (src != inner)
+       {
+         *dest = decl_piece_node (*decl_piece_varloc_ptr (*src),
+                                  decl_piece_bitsize (*src), NULL_RTX);
+         dest = &XEXP (*dest, 1);
+         src = &XEXP (*src, 1);
+       }
+    }
+  /* Add padding if needed.  */
+  if (bitpos != piece_bitpos)
+    {
+      *dest = decl_piece_node (NULL_RTX, bitpos - piece_bitpos,
+                              copy ? NULL_RTX : *dest);
+      dest = &XEXP (*dest, 1);
+    }
+  else if (*dest && decl_piece_bitsize (*dest) == bitsize)
+    {
+      gcc_assert (!copy);
+      /* A piece with correct bitpos and bitsize already exist,
+        just update the location for it and return.  */
+      *decl_piece_varloc_ptr (*dest) = loc_note;
+      return;
+    }
+  /* Add the piece that changed.  */
+  *dest = decl_piece_node (loc_note, bitsize, copy ? NULL_RTX : *dest);
+  dest = &XEXP (*dest, 1);
+  /* Skip over pieces that overlap it.  */
+  diff = bitpos - piece_bitpos + bitsize;
+  if (!copy)
+    src = dest;
+  while (diff > 0 && *src)
+    {
+      rtx piece = *src;
+      diff -= decl_piece_bitsize (piece);
+      if (copy)
+       src = &XEXP (piece, 1);
+      else
+       {
+         *src = XEXP (piece, 1);
+         free_EXPR_LIST_node (piece);
+       }
+    }
+  /* Add padding if needed.  */
+  if (diff < 0 && *src)
+    {
+      if (!copy)
+       dest = src;
+      *dest = decl_piece_node (NULL_RTX, -diff, copy ? NULL_RTX : *dest);
+      dest = &XEXP (*dest, 1);
+    }
+  if (!copy)
+    return;
+  /* Finally copy all nodes following it.  */
+  while (*src)
+    {
+      *dest = decl_piece_node (*decl_piece_varloc_ptr (*src),
+                              decl_piece_bitsize (*src), NULL_RTX);
+      dest = &XEXP (*dest, 1);
+      src = &XEXP (*src, 1);
+    }
+}
+
 /* Add a variable location node to the linked list for DECL.  */
 
 static struct var_loc_node *
 add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
 {
-  unsigned int decl_id = DECL_UID (decl);
+  unsigned int decl_id;
   var_loc_list *temp;
   void **slot;
   struct var_loc_node *loc = NULL;
+  HOST_WIDE_INT bitsize = -1, bitpos = -1;
+
+  if (DECL_DEBUG_EXPR_IS_FROM (decl))
+    {
+      tree realdecl = DECL_DEBUG_EXPR (decl);
+      if (realdecl && handled_component_p (realdecl))
+       {
+         HOST_WIDE_INT maxsize;
+         tree innerdecl;
+         innerdecl
+           = get_ref_base_and_extent (realdecl, &bitpos, &bitsize, &maxsize);
+         if (!DECL_P (innerdecl)
+             || DECL_IGNORED_P (innerdecl)
+             || TREE_STATIC (innerdecl)
+             || bitsize <= 0
+             || bitpos + bitsize > 256
+             || bitsize != maxsize)
+           return NULL;
+         decl = innerdecl;
+       }
+    }
 
+  decl_id = DECL_UID (decl);
   slot = htab_find_slot_with_hash (decl_loc_table, decl, decl_id, INSERT);
   if (*slot == NULL)
     {
@@ -7780,17 +7962,40 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
   if (temp->last)
     {
       struct var_loc_node *last = temp->last, *unused = NULL;
+      rtx *piece_loc = NULL, last_loc_note;
+      int piece_bitpos = 0;
       if (last->next)
        {
          last = last->next;
          gcc_assert (last->next == NULL);
        }
+      if (bitsize != -1 && GET_CODE (last->loc) == EXPR_LIST)
+       {
+         piece_loc = &last->loc;
+         do
+           {
+             int cur_bitsize = decl_piece_bitsize (*piece_loc);
+             if (piece_bitpos + cur_bitsize > bitpos)
+               break;
+             piece_bitpos += cur_bitsize;
+             piece_loc = &XEXP (*piece_loc, 1);
+           }
+         while (*piece_loc);
+       }
       /* TEMP->LAST here is either pointer to the last but one or
         last element in the chained list, LAST is pointer to the
         last element.  */
-      /* If the last note doesn't cover any instructions, remove it.  */
       if (label && strcmp (last->label, label) == 0)
        {
+         /* For SRA optimized variables if there weren't any real
+            insns since last note, just modify the last node.  */
+         if (piece_loc != NULL)
+           {
+             adjust_piece_list (piece_loc, NULL, NULL,
+                                bitpos, piece_bitpos, bitsize, loc_note);
+             return NULL;
+           }
+         /* If the last note doesn't cover any instructions, remove it.  */
          if (temp->last != last)
            {
              temp->last->next = NULL;
@@ -7802,17 +8007,28 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
            {
              gcc_assert (temp->first == temp->last);
              memset (temp->last, '\0', sizeof (*temp->last));
+             temp->last->loc = construct_piece_list (loc_note, bitpos, bitsize);
              return temp->last;
            }
        }
+      if (bitsize == -1 && NOTE_P (last->loc))
+       last_loc_note = last->loc;
+      else if (piece_loc != NULL
+              && *piece_loc != NULL_RTX
+              && piece_bitpos == bitpos
+              && decl_piece_bitsize (*piece_loc) == bitsize)
+       last_loc_note = *decl_piece_varloc_ptr (*piece_loc);
+      else
+       last_loc_note = NULL_RTX;
       /* If the current location is the same as the end of the list,
         and either both or neither of the locations is uninitialized,
         we have nothing to do.  */
-      if ((!rtx_equal_p (NOTE_VAR_LOCATION_LOC (last->var_loc_note),
-                        NOTE_VAR_LOCATION_LOC (loc_note)))
-         || ((NOTE_VAR_LOCATION_STATUS (last->var_loc_note)
+      if (last_loc_note == NULL_RTX
+         || (!rtx_equal_p (NOTE_VAR_LOCATION_LOC (last_loc_note),
+                           NOTE_VAR_LOCATION_LOC (loc_note)))
+         || ((NOTE_VAR_LOCATION_STATUS (last_loc_note)
               != NOTE_VAR_LOCATION_STATUS (loc_note))
-             && ((NOTE_VAR_LOCATION_STATUS (last->var_loc_note)
+             && ((NOTE_VAR_LOCATION_STATUS (last_loc_note)
                   == VAR_INIT_STATUS_UNINITIALIZED)
                  || (NOTE_VAR_LOCATION_STATUS (loc_note)
                      == VAR_INIT_STATUS_UNINITIALIZED))))
@@ -7827,6 +8043,11 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
            }
          else
            loc = GGC_CNEW (struct var_loc_node);
+         if (bitsize == -1 || piece_loc == NULL)
+           loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
+         else
+           adjust_piece_list (&loc->loc, &last->loc, piece_loc,
+                              bitpos, piece_bitpos, bitsize, loc_note);
          last->next = loc;
          /* Ensure TEMP->LAST will point either to the new last but one
             element of the chain, or to the last element in it.  */
@@ -7841,6 +8062,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
       loc = GGC_CNEW (struct var_loc_node);
       temp->first = loc;
       temp->last = loc;
+      loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
     }
   return loc;
 }
@@ -14084,7 +14306,11 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address,
     }
   else
     {
-      descr = loc_descriptor (varloc, DECL_MODE (loc), initialized);
+      if (GET_CODE (varloc) == VAR_LOCATION)
+       mode = DECL_MODE (PAT_VAR_LOCATION_DECL (varloc));
+      else
+       mode = DECL_MODE (loc);
+      descr = loc_descriptor (varloc, mode, initialized);
       have_address = 1;
     }
 
@@ -14134,6 +14360,125 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address,
   return descr;
 }
 
+/* Create a DW_OP_piece or DW_OP_bit_piece for bitsize, or return NULL
+   if it is not possible.  */
+
+static dw_loc_descr_ref
+new_loc_descr_op_bit_piece (HOST_WIDE_INT bitsize)
+{
+  if ((bitsize % BITS_PER_UNIT) == 0)
+    return new_loc_descr (DW_OP_piece, bitsize / BITS_PER_UNIT, 0);
+  else if (dwarf_version >= 3 || !dwarf_strict)
+    return new_loc_descr (DW_OP_bit_piece, bitsize, 0);
+  else
+    return NULL;
+}
+
+/* Helper function for dw_loc_list.  Compute proper Dwarf location descriptor
+   for VAR_LOC_NOTE for variable DECL that has been optimized by SRA.  */
+
+static dw_loc_descr_ref
+dw_sra_loc_expr (tree decl, rtx loc)
+{
+  rtx p;
+  unsigned int padsize = 0;
+  dw_loc_descr_ref descr, *descr_tail;
+  unsigned HOST_WIDE_INT decl_size;
+  rtx varloc;
+  enum var_init_status initialized;
+
+  if (DECL_SIZE (decl) == NULL
+      || !host_integerp (DECL_SIZE (decl), 1))
+    return NULL;
+
+  decl_size = tree_low_cst (DECL_SIZE (decl), 1);
+  descr = NULL;
+  descr_tail = &descr;
+
+  for (p = loc; p; p = XEXP (p, 1))
+    {
+      unsigned int bitsize = decl_piece_bitsize (p);
+      rtx loc_note = *decl_piece_varloc_ptr (p);
+      dw_loc_descr_ref cur_descr;
+      dw_loc_descr_ref *tail, last = NULL;
+      unsigned int opsize = 0;
+
+      if (loc_note == NULL_RTX
+         || NOTE_VAR_LOCATION_LOC (loc_note) == NULL_RTX)
+       {
+         padsize += bitsize;
+         continue;
+       }
+      initialized = NOTE_VAR_LOCATION_STATUS (loc_note);
+      varloc = NOTE_VAR_LOCATION (loc_note);
+      cur_descr = dw_loc_list_1 (decl, varloc, 2, initialized);
+      if (cur_descr == NULL)
+       {
+         padsize += bitsize;
+         continue;
+       }
+
+      /* Check that cur_descr either doesn't use
+        DW_OP_*piece operations, or their sum is equal
+        to bitsize.  Otherwise we can't embed it.  */
+      for (tail = &cur_descr; *tail != NULL;
+          tail = &(*tail)->dw_loc_next)
+       if ((*tail)->dw_loc_opc == DW_OP_piece)
+         {
+           opsize += (*tail)->dw_loc_oprnd1.v.val_unsigned
+                     * BITS_PER_UNIT;
+           last = *tail;
+         }
+       else if ((*tail)->dw_loc_opc == DW_OP_bit_piece)
+         {
+           opsize += (*tail)->dw_loc_oprnd1.v.val_unsigned;
+           last = *tail;
+         }
+
+      if (last != NULL && opsize != bitsize)
+       {
+         padsize += bitsize;
+         continue;
+       }
+
+      /* If there is a hole, add DW_OP_*piece after empty DWARF
+        expression, which means that those bits are optimized out.  */
+      if (padsize)
+       {
+         if (padsize > decl_size)
+           return NULL;
+         decl_size -= padsize;
+         *descr_tail = new_loc_descr_op_bit_piece (padsize);
+         if (*descr_tail == NULL)
+           return NULL;
+         descr_tail = &(*descr_tail)->dw_loc_next;
+         padsize = 0;
+       }
+      *descr_tail = cur_descr;
+      descr_tail = tail;
+      if (bitsize > decl_size)
+       return NULL;
+      decl_size -= bitsize;
+      if (last == NULL)
+       {
+         *descr_tail = new_loc_descr_op_bit_piece (bitsize);
+         if (*descr_tail == NULL)
+           return NULL;
+         descr_tail = &(*descr_tail)->dw_loc_next;
+       }
+    }
+
+  /* If there were any non-empty expressions, add padding till the end of
+     the decl.  */
+  if (descr != NULL && decl_size != 0)
+    {
+      *descr_tail = new_loc_descr_op_bit_piece (decl_size);
+      if (*descr_tail == NULL)
+       return NULL;
+    }
+  return descr;
+}
+
 /* Return the dwarf representation of the location list LOC_LIST of
    DECL.  WANT_ADDRESS has the same meaning as in loc_list_from_tree
    function.  */
@@ -14163,45 +14508,48 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
 
   secname = secname_for_decl (decl);
 
-  for (node = loc_list->first; node->next; node = node->next)
-    if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
+  for (node = loc_list->first; node; node = node->next)
+    if (GET_CODE (node->loc) == EXPR_LIST
+       || NOTE_VAR_LOCATION_LOC (node->loc) != NULL_RTX)
       {
-       /* The variable has a location between NODE->LABEL and
-          NODE->NEXT->LABEL.  */
-       initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-       varloc = NOTE_VAR_LOCATION (node->var_loc_note);
-       descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
+       if (GET_CODE (node->loc) == EXPR_LIST)
+         {
+           /* This requires DW_OP_{,bit_}piece, which is not usable
+              inside DWARF expressions.  */
+           if (want_address != 2)
+             continue;
+           descr = dw_sra_loc_expr (decl, node->loc);
+           if (descr == NULL)
+             continue;
+         }
+       else
+         {
+           initialized = NOTE_VAR_LOCATION_STATUS (node->loc);
+           varloc = NOTE_VAR_LOCATION (node->loc);
+           descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
+         }
        if (descr)
          {
-           *listp = new_loc_list (descr, node->label, node->next->label,
-                                  secname);
+           /* The variable has a location between NODE->LABEL and
+              NODE->NEXT->LABEL.  */
+           if (node->next)
+             endname = node->next->label;
+           /* If the variable has a location at the last label
+              it keeps its location until the end of function.  */
+           else if (!current_function_decl)
+             endname = text_end_label;
+           else
+             {
+               ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+                                            current_function_funcdef_no);
+               endname = ggc_strdup (label_id);
+             }
+
+           *listp = new_loc_list (descr, node->label, endname, secname);
            listp = &(*listp)->dw_loc_next;
          }
       }
 
-  /* If the variable has a location at the last label
-     it keeps its location until the end of function.  */
-  if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX)
-    {
-      initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note);
-      varloc = NOTE_VAR_LOCATION (node->var_loc_note);
-      descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
-      if (descr)
-       {
-         if (!current_function_decl)
-           endname = text_end_label;
-         else
-           {
-             ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
-                                          current_function_funcdef_no);
-             endname = ggc_strdup (label_id);
-           }
-
-         *listp = new_loc_list (descr, node->label, endname, secname);
-         listp = &(*listp)->dw_loc_next;
-       }
-    }
-
   /* Try to avoid the overhead of a location list emitting a location
      expression instead, but only if we didn't have more than one
      location entry in the first place.  If some entries were not
@@ -15950,13 +16298,14 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
   if (loc_list
       && loc_list->first
       && loc_list->first->next == NULL
-      && NOTE_VAR_LOCATION (loc_list->first->var_loc_note)
-      && NOTE_VAR_LOCATION_LOC (loc_list->first->var_loc_note))
+      && NOTE_P (loc_list->first->loc)
+      && NOTE_VAR_LOCATION (loc_list->first->loc)
+      && NOTE_VAR_LOCATION_LOC (loc_list->first->loc))
     {
       struct var_loc_node *node;
 
       node = loc_list->first;
-      rtl = NOTE_VAR_LOCATION_LOC (node->var_loc_note);
+      rtl = NOTE_VAR_LOCATION_LOC (node->loc);
       if (GET_CODE (rtl) == EXPR_LIST)
        rtl = XEXP (rtl, 0);
       if ((CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
@@ -20458,8 +20807,6 @@ dwarf2out_var_location (rtx loc_note)
       loclabel_num++;
       last_label = ggc_strdup (loclabel);
     }
-  newloc->var_loc_note = loc_note;
-  newloc->next = NULL;
 
   if (!NOTE_DURING_CALL_P (loc_note))
     newloc->label = last_label;
index 8f18143..8b0418c 100644 (file)
@@ -1,3 +1,8 @@
+2010-05-13  Jakub Jelinek  <jakub@redhat.com>
+
+       PR debug/43983
+       * gcc.dg/guality/sra-1.c: New test.
+
 2010-05-12  Jan Hubicka  <jh@suse.cz>
 
        * tree-ssa/unreachable.c: New test.
diff --git a/gcc/testsuite/gcc.dg/guality/sra-1.c b/gcc/testsuite/gcc.dg/guality/sra-1.c
new file mode 100644 (file)
index 0000000..feb1158
--- /dev/null
@@ -0,0 +1,56 @@
+/* PR debug/43983 */
+/* { dg-do run } */
+/* { dg-options "-g" } */
+
+struct A { int i; int j; };
+struct B { int : 4; int i : 12; int j : 12; int : 4; };
+
+__attribute__((noinline)) void
+bar (int x)
+{
+  asm volatile ("" : : "r" (x) : "memory");
+}
+
+__attribute__((noinline)) int
+f1 (int k)
+{
+  struct A a = { 4, k + 6 };
+  asm ("" : "+r" (a.i));
+  a.j++;
+  bar (a.i);           /* { dg-final { gdb-test 20 "a.i" "4" } } */
+  bar (a.j);           /* { dg-final { gdb-test 20 "a.j" "14" } } */
+  return a.i + a.j;
+}
+
+__attribute__((noinline)) int
+f2 (int k)
+{
+  int a[2] = { 4, k + 6 };
+  asm ("" : "+r" (a[0]));
+  a[1]++;
+  bar (a[0]);          /* { dg-final { gdb-test 31 "a\[0\]" "4" } } */
+  bar (a[1]);          /* { dg-final { gdb-test 31 "a\[1\]" "14" } } */
+  return a[0] + a[1];
+}
+
+__attribute__((noinline)) int
+f3 (int k)
+{
+  struct B a = { 4, k + 6 };
+  asm ("" : "+r" (a.i));
+  a.j++;
+  bar (a.i);           /* { dg-final { gdb-test 42 "a.i" "4" } } */
+  bar (a.j);           /* { dg-final { gdb-test 42 "a.j" "14" } } */
+  return a.i + a.j;
+}
+
+int
+main (void)
+{
+  int k;
+  asm ("" : "=r" (k) : "0" (7));
+  f1 (k);
+  f2 (k);
+  f3 (k);
+  return 0;
+}
index 166338f..33144d7 100644 (file)
@@ -1609,11 +1609,38 @@ create_access_replacement (struct access *access)
       && !DECL_ARTIFICIAL (access->base))
     {
       char *pretty_name = make_fancy_name (access->expr);
+      tree debug_expr = unshare_expr (access->expr), d;
 
       DECL_NAME (repl) = get_identifier (pretty_name);
       obstack_free (&name_obstack, pretty_name);
 
-      SET_DECL_DEBUG_EXPR (repl, access->expr);
+      /* Get rid of any SSA_NAMEs embedded in debug_expr,
+        as DECL_DEBUG_EXPR isn't considered when looking for still
+        used SSA_NAMEs and thus they could be freed.  All debug info
+        generation cares is whether something is constant or variable
+        and that get_ref_base_and_extent works properly on the
+        expression.  */
+      for (d = debug_expr; handled_component_p (d); d = TREE_OPERAND (d, 0))
+       switch (TREE_CODE (d))
+         {
+         case ARRAY_REF:
+         case ARRAY_RANGE_REF:
+           if (TREE_OPERAND (d, 1)
+               && TREE_CODE (TREE_OPERAND (d, 1)) == SSA_NAME)
+             TREE_OPERAND (d, 1) = SSA_NAME_VAR (TREE_OPERAND (d, 1));
+           if (TREE_OPERAND (d, 3)
+               && TREE_CODE (TREE_OPERAND (d, 3)) == SSA_NAME)
+             TREE_OPERAND (d, 3) = SSA_NAME_VAR (TREE_OPERAND (d, 3));
+           /* FALLTHRU */
+         case COMPONENT_REF:
+           if (TREE_OPERAND (d, 2)
+               && TREE_CODE (TREE_OPERAND (d, 2)) == SSA_NAME)
+             TREE_OPERAND (d, 2) = SSA_NAME_VAR (TREE_OPERAND (d, 2));
+           break;
+         default:
+           break;
+         }
+      SET_DECL_DEBUG_EXPR (repl, debug_expr);
       DECL_DEBUG_EXPR_IS_FROM (repl) = 1;
       TREE_NO_WARNING (repl) = TREE_NO_WARNING (access->base);
     }
index 040a3e7..c980da6 100644 (file)
@@ -4505,10 +4505,27 @@ track_expr_p (tree expr, bool need_rtl)
       realdecl = DECL_DEBUG_EXPR (realdecl);
       if (realdecl == NULL_TREE)
        realdecl = expr;
-      /* ??? We don't yet know how to emit DW_OP_piece for variable
-        that has been SRA'ed.  */
       else if (!DECL_P (realdecl))
-       return 0;
+       {
+         if (handled_component_p (realdecl))
+           {
+             HOST_WIDE_INT bitsize, bitpos, maxsize;
+             tree innerdecl
+               = get_ref_base_and_extent (realdecl, &bitpos, &bitsize,
+                                          &maxsize);
+             if (!DECL_P (innerdecl)
+                 || DECL_IGNORED_P (innerdecl)
+                 || TREE_STATIC (innerdecl)
+                 || bitsize <= 0
+                 || bitpos + bitsize > 256
+                 || bitsize != maxsize)
+               return 0;
+             else
+               realdecl = expr;
+           }
+         else
+           return 0;
+       }
     }
 
   /* Do not track EXPR if REALDECL it should be ignored for debugging