[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