[PATCH] Provide debug info for SRA optimized variables (PR debug/43983)
Jakub Jelinek
jakub@redhat.com
Wed May 12 21:00:00 GMT 2010
On Wed, May 12, 2010 at 02:46:42PM -0400, Jason Merrill wrote:
> So, in this patch you're changing the var_loc_note field to be
> either a varloc note or a piece EXPR_LIST that does not appear
> anywhere else in the compiler, correct? Please document this new
> data structure.
Attached is an untested patch that incorporates your feedback
here and on IRC. Hope I haven't missed anything.
I'll actually test it tomorrow.
2010-05-12 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.
* gcc.dg/guality/sra-1.c: New test.
--- gcc/var-tracking.c.jj 2010-05-11 20:16:09.000000000 +0200
+++ gcc/var-tracking.c 2010-05-12 22:33:49.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-11 20:16:09.000000000 +0200
+++ gcc/Makefile.in 2010-05-12 22:33:49.000000000 +0200
@@ -2845,7 +2845,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-11 20:16:09.000000000 +0200
+++ gcc/tree-sra.c 2010-05-12 22:33:49.000000000 +0200
@@ -1609,11 +1609,38 @@ 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));
+ 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);
}
--- gcc/dwarf2out.c.jj 2010-05-12 14:16:52.000000000 +0200
+++ gcc/dwarf2out.c 2010-05-12 23:01:03.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:
@@ -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,171 @@ 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 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);
+ *src = XEXP (piece, 1);
+ if (!copy)
+ 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 +7958,40 @@ 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->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 +8003,28 @@ add_var_loc_to_decl (tree decl, rtx loc_
{
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 +8039,11 @@ add_var_loc_to_decl (tree decl, rtx loc_
}
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 +8058,7 @@ add_var_loc_to_decl (tree decl, rtx loc_
loc = GGC_CNEW (struct var_loc_node);
temp->first = loc;
temp->last = loc;
+ loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
}
return loc;
}
@@ -14085,7 +14303,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;
}
@@ -14135,6 +14357,129 @@ dw_loc_list_1 (tree loc, rtx varloc, int
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)
+ {
+ 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. */
@@ -14164,45 +14509,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->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
@@ -15951,13 +16299,14 @@ add_location_or_const_value_attribute (d
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)
@@ -20459,8 +20808,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-12 22:33:49.000000000 +0200
+++ gcc/testsuite/gcc.dg/guality/sra-1.c 2010-05-12 22:33:49.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
More information about the Gcc-patches
mailing list