[PATCH] Provide debug info for SRA optimized variables (PR debug/43983)

Richard Guenther rguenther@suse.de
Thu May 6 15:40:00 GMT 2010


On Thu, 6 May 2010, Jakub Jelinek wrote:

> Hi!
> 
> SRA sets for the variables it creates DECL_DEBUG_EXPR to a COMPONENT_REF
> or ARRAY_REF to say what part of the original variable has been replaced.
> 
> Unfortunately, var-tracking.c decides not to track such variables. 
> var-tracking.c isn't good at tracking aggregates, but we can easily track
> the replacement variables in var-tracking and only in
> debug_hooks.var_location reconstruct the whole object locations from that.
> 
> The patch below does that.  I had to tweak tree-sra.c slightly as well,
> as otherwise the ARRAY_REFs in DECL_DEBUG_EXPR could contain SSA_NAMEs
> and no passes after SRA touch DECL_DEBUG_EXPR until var-tracking, so
> if the SSA_NAMEs are freed and worse their memory reused for something
> completely else, get_ref_base_and_extent in var-tracking.c/dwarf2out.c
> crashes on it.
> 
> The patch slightly (2% for x86_64 rtl checking cc1plus, 3% for i686 rtl
> checking cc1plus) increases .debug_loc size, which is understandable, given
> that more variables now have locations tracked.  DW_OP_*piece operation
> count in .debug_loc increased from 347 to 23160 in i686 cc1plus.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux.  Ok for trunk?

Comments below.

> 2010-05-06  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.
> 	(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): New
> 	functions.
> 	(add_var_loc_to_decl): Handle SRA optimized variables.
> 	(dw_loc_list_1): For WANT_ADDRESS == 2 prefer DECL_MODE of decl
> 	in VAR_LOCATION note.
> 	(dw_loc_list_2): New function.
> 	(dw_loc_list): Use it.  Don't handle the last range after the
> 	loop, handle it inside of the loop.
> 	(add_location_or_const_value_attribute): Only special case
> 	single entry loc lists if var_loc_note is NOTE_P.
> 	(dwarf2out_var_location): Don't set newloc->var_loc_note
> 	and newloc->next here.
> 
> 	* gcc.dg/guality/sra-1.c: New test.
> 
> --- gcc/var-tracking.c.jj	2010-05-05 19:11:01.000000000 +0200
> +++ gcc/var-tracking.c	2010-05-06 14:24:57.000000000 +0200
> @@ -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
> --- gcc/Makefile.in.jj	2010-05-05 19:11:01.000000000 +0200
> +++ gcc/Makefile.in	2010-05-05 19:11:01.000000000 +0200
> @@ -2844,7 +2844,7 @@ dwarf2out.o : dwarf2out.c $(CONFIG_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)
> --- gcc/tree-sra.c.jj	2010-05-05 19:11:01.000000000 +0200
> +++ gcc/tree-sra.c	2010-05-06 14:16:52.000000000 +0200
> @@ -1609,11 +1609,40 @@ create_access_replacement (struct 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));
> +	    break;

Superfluous break?

> +	    if (TREE_OPERAND (d, 3)
> +		&& TREE_CODE (TREE_OPERAND (d, 3)) == SSA_NAME)
> +	      TREE_OPERAND (d, 3) = SSA_NAME_VAR (TREE_OPERAND (d, 3));
> +	    break;

Likewise?

> +	    /* 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);
>      }

The tree-sra.c changes are ok with the above fixed.  I'd appreciate
someone else look at the dwarf2out.c change.

Thanks,
Richard.

> --- gcc/dwarf2out.c.jj	2010-05-05 19:10:53.000000000 +0200
> +++ gcc/dwarf2out.c	2010-05-06 14:34:39.000000000 +0200
> @@ -91,6 +91,7 @@ along with GCC; see the file COPYING3.  
>  #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 lo
>      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_re
>        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:
> @@ -7757,16 +7772,92 @@ equate_decl_number_to_die (tree decl, dw
>    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 var_loc_note field for
> +   LOC_NOTE and BITPOS/BITSIZE.  */
> +
> +static rtx
> +construct_var_loc_note (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;
> +}
> +
>  /* 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 +7871,70 @@ add_var_loc_to_decl (tree decl, rtx loc_
>    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->var_loc_note) == EXPR_LIST)
> +	{
> +	  piece_loc = &last->var_loc_note;
> +	  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)
> +	    {
> +	      int diff;
> +	      /* Add padding if needed.  */
> +	      if (bitpos != piece_bitpos)
> +		{
> +		  *piece_loc
> +		    = decl_piece_node (NULL_RTX, bitpos - piece_bitpos,
> +				       *piece_loc);
> +		  piece_loc = &XEXP (*piece_loc, 1);
> +		}
> +	      else if (*piece_loc
> +		       && decl_piece_bitsize (*piece_loc) == bitsize)
> +		{
> +		  /* A piece with correct bitpos and bitsize already exist,
> +		     just update the location for it and return.  */
> +		  *decl_piece_varloc_ptr (*piece_loc) = loc_note;
> +		  return NULL;
> +		}
> +	      /* Add the piece that changed.  */
> +	      *piece_loc = decl_piece_node (loc_note, bitsize, *piece_loc);
> +	      piece_loc = &XEXP (*piece_loc, 1);
> +	      /* Skip over pieces that overlap it.  */
> +	      diff = bitpos - piece_bitpos + bitsize;
> +	      while (diff > 0 && *piece_loc)
> +		{
> +		  rtx piece = *piece_loc;
> +		  diff -= decl_piece_bitsize (piece);
> +		  *piece_loc = XEXP (piece, 1);
> +		  free_EXPR_LIST_node (piece);
> +		}
> +	      /* Add padding if needed.  */
> +	      if (diff < 0 && *piece_loc)
> +		*piece_loc = decl_piece_node (NULL_RTX, -diff, *piece_loc);
> +	      return NULL;
> +	    }
> +	  /* If the last note doesn't cover any instructions, remove it.  */
>  	  if (temp->last != last)
>  	    {
>  	      temp->last->next = NULL;
> @@ -7802,17 +7946,29 @@ add_var_loc_to_decl (tree decl, rtx loc_
>  	    {
>  	      gcc_assert (temp->first == temp->last);
>  	      memset (temp->last, '\0', sizeof (*temp->last));
> +	      temp->last->var_loc_note
> +		= construct_var_loc_note (loc_note, bitpos, bitsize);
>  	      return temp->last;
>  	    }
>  	}
> +      if (bitsize == -1 && NOTE_P (last->var_loc_note))
> +	last_loc_note = last->var_loc_note;
> +      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 +7983,57 @@ add_var_loc_to_decl (tree decl, rtx loc_
>  	    }
>  	  else
>  	    loc = GGC_CNEW (struct var_loc_node);
> +	  if (bitsize == -1 || piece_loc == NULL)
> +	    loc->var_loc_note
> +	      = construct_var_loc_note (loc_note, bitpos, bitsize);
> +	  else
> +	    {
> +	      int diff;
> +	      rtx *new_piece_loc = &loc->var_loc_note;
> +	      rtx *p = &last->var_loc_note;
> +	      /* First copy all nodes preceeding the current bitpos.  */
> +	      while (p != piece_loc)
> +		{
> +		  *new_piece_loc
> +		    = decl_piece_node (*decl_piece_varloc_ptr (*p),
> +				       decl_piece_bitsize (*p), NULL_RTX);
> +		  new_piece_loc = &XEXP (*new_piece_loc, 1);
> +		  p = &XEXP (*p, 1);
> +		}
> +	      /* Add padding if needed.  */
> +	      if (bitpos != piece_bitpos)
> +		{
> +		  *new_piece_loc
> +		    = decl_piece_node (NULL_RTX, bitpos - piece_bitpos,
> +				       NULL_RTX);
> +		  new_piece_loc = &XEXP (*new_piece_loc, 1);
> +		}
> +	      /* Add the actual piece that caused the change.  */
> +	      *new_piece_loc = decl_piece_node (loc_note, bitsize, NULL_RTX);
> +	      new_piece_loc = &XEXP (*new_piece_loc, 1);
> +	      /* Skip nodes overlapping it.  */
> +	      diff = bitpos - piece_bitpos + bitsize;
> +	      while (diff > 0 && *p)
> +		{
> +		  diff -= decl_piece_bitsize (*p);
> +		  p = &XEXP (*p, 1);
> +		}
> +	      /* Add padding if needed.  */
> +	      if (diff < 0 && *p)
> +		{
> +		  *new_piece_loc = decl_piece_node (NULL_RTX, -diff, NULL_RTX);
> +		  new_piece_loc = &XEXP (*new_piece_loc, 1);
> +		}
> +	      /* Finally copy all nodes following it.  */
> +	      while (*p)
> +		{
> +		  *new_piece_loc
> +		    = decl_piece_node (*decl_piece_varloc_ptr (*p),
> +				       decl_piece_bitsize (*p), NULL_RTX);
> +		  new_piece_loc = &XEXP (*new_piece_loc, 1);
> +		  p = &XEXP (*p, 1);
> +		}
> +	    }
>  	  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 +8048,7 @@ add_var_loc_to_decl (tree decl, rtx loc_
>        loc = GGC_CNEW (struct var_loc_node);
>        temp->first = loc;
>        temp->last = loc;
> +      loc->var_loc_note = construct_var_loc_note (loc_note, bitpos, bitsize);
>      }
>    return loc;
>  }
> @@ -14070,7 +14278,11 @@ dw_loc_list_1 (tree loc, rtx varloc, int
>      }
>    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;
>      }
>  
> @@ -14120,6 +14332,121 @@ dw_loc_list_1 (tree loc, rtx varloc, int
>    return descr;
>  }
>  
> +/* 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_loc_list_2 (tree decl, rtx var_loc_note)
> +{
> +  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 = var_loc_note; 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 (padsize)
> +	{
> +	  if (padsize > decl_size)
> +	    return NULL;
> +	  decl_size -= padsize;
> +	  if ((padsize % BITS_PER_UNIT) == 0)
> +	    *descr_tail = new_loc_descr (DW_OP_piece,
> +					 padsize / BITS_PER_UNIT, 0);
> +	  else if (dwarf_version >= 3 || !dwarf_strict)
> +	    *descr_tail = new_loc_descr (DW_OP_bit_piece, padsize, 0);
> +	  else
> +	    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)
> +	{
> +	  if ((bitsize % BITS_PER_UNIT) == 0)
> +	    *descr_tail = new_loc_descr (DW_OP_piece,
> +					 bitsize / BITS_PER_UNIT, 0);
> +	  else if (dwarf_version >= 3 || !dwarf_strict)
> +	    *descr_tail = new_loc_descr (DW_OP_bit_piece, bitsize, 0);
> +	  else
> +	    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)
> +    {
> +      if ((decl_size % BITS_PER_UNIT) == 0)
> +	*descr_tail = new_loc_descr (DW_OP_piece,
> +				     decl_size / BITS_PER_UNIT, 0);
> +      else if (dwarf_version >= 3 || !dwarf_strict)
> +	*descr_tail = new_loc_descr (DW_OP_bit_piece, decl_size, 0);
> +      else
> +	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.  */
> @@ -14149,45 +14476,48 @@ dw_loc_list (var_loc_list *loc_list, tre
>  
>    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->var_loc_note) == EXPR_LIST
> +	|| NOTE_VAR_LOCATION_LOC (node->var_loc_note) != 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->var_loc_note) == EXPR_LIST)
> +	  {
> +	    /* This requires DW_OP_{,bit_}piece, which is not usable
> +	       inside DWARF expressions.  */
> +	    if (want_address != 2)
> +	      continue;
> +	    descr = dw_loc_list_2 (decl, node->var_loc_note);
> +	    if (descr == NULL)
> +	      continue;
> +	  }
> +	else
> +	  {
> +	    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)
>  	  {
> -	    *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
> @@ -15936,6 +16266,7 @@ add_location_or_const_value_attribute (d
>    if (loc_list
>        && loc_list->first
>        && loc_list->first->next == NULL
> +      && NOTE_P (loc_list->first->var_loc_note)
>        && NOTE_VAR_LOCATION (loc_list->first->var_loc_note)
>        && NOTE_VAR_LOCATION_LOC (loc_list->first->var_loc_note))
>      {
> @@ -20421,8 +20752,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;
> --- gcc/testsuite/gcc.dg/guality/sra-1.c.jj	2010-05-05 20:13:32.000000000 +0200
> +++ gcc/testsuite/gcc.dg/guality/sra-1.c	2010-05-05 20:13:32.000000000 +0200
> @@ -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;
> +}
> 
> 	Jakub
> 
> 

-- 
Richard Guenther <rguenther@suse.de>
Novell / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 - GF: Markus Rex



More information about the Gcc-patches mailing list