Commit 823e9473 by Jakub Jelinek Committed by Jakub Jelinek

re PR debug/43983 (var-tracking needlessly throws away location info for SRAed vars)

	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.

From-SVN: r159357
parent d20cfbc2
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> 2010-05-12 Jan Hubicka <jh@suse.cz>
* cgraph.c (cgraph_mark_address_taken_node): No longer imply needed flag. * cgraph.c (cgraph_mark_address_taken_node): No longer imply needed flag.
......
...@@ -2846,7 +2846,7 @@ dwarf2out.o : dwarf2out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ ...@@ -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) \ 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 \ 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) \ $(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) \ 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) \ $(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) gt-dwarf2asm.h $(DWARF2_H) $(SPLAY_TREE_H) $(TARGET_H)
......
...@@ -91,6 +91,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -91,6 +91,7 @@ along with GCC; see the file COPYING3. If not see
#include "input.h" #include "input.h"
#include "gimple.h" #include "gimple.h"
#include "tree-pass.h" #include "tree-pass.h"
#include "tree-flow.h"
#ifdef DWARF2_DEBUGGING_INFO #ifdef DWARF2_DEBUGGING_INFO
static void dwarf2out_source_line (unsigned int, const char *, int, bool); static void dwarf2out_source_line (unsigned int, const char *, int, bool);
...@@ -4784,6 +4785,10 @@ size_of_loc_descr (dw_loc_descr_ref loc) ...@@ -4784,6 +4785,10 @@ size_of_loc_descr (dw_loc_descr_ref loc)
case DW_OP_piece: case DW_OP_piece:
size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned); size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
break; 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_deref_size:
case DW_OP_xderef_size: case DW_OP_xderef_size:
size += 1; size += 1;
...@@ -5008,6 +5013,10 @@ output_loc_operands (dw_loc_descr_ref loc) ...@@ -5008,6 +5013,10 @@ output_loc_operands (dw_loc_descr_ref loc)
case DW_OP_piece: case DW_OP_piece:
dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL); dw2_asm_output_data_uleb128 (val1->v.val_unsigned, NULL);
break; 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_deref_size:
case DW_OP_xderef_size: case DW_OP_xderef_size:
dw2_asm_output_data (1, val1->v.val_int, NULL); dw2_asm_output_data (1, val1->v.val_int, NULL);
...@@ -5123,6 +5132,12 @@ output_loc_operands_raw (dw_loc_descr_ref loc) ...@@ -5123,6 +5132,12 @@ output_loc_operands_raw (dw_loc_descr_ref loc)
dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned); dw2_asm_output_data_uleb128_raw (val1->v.val_unsigned);
break; 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_consts:
case DW_OP_breg0: case DW_OP_breg0:
case DW_OP_breg1: case DW_OP_breg1:
...@@ -5739,7 +5754,15 @@ DEF_VEC_ALLOC_O(die_arg_entry,gc); ...@@ -5739,7 +5754,15 @@ DEF_VEC_ALLOC_O(die_arg_entry,gc);
/* Node of the variable location list. */ /* Node of the variable location list. */
struct GTY ((chain_next ("%h.next"))) var_loc_node { 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; const char * GTY (()) label;
struct var_loc_node * GTY (()) next; struct var_loc_node * GTY (()) next;
}; };
...@@ -7757,16 +7780,175 @@ equate_decl_number_to_die (tree decl, dw_die_ref decl_die) ...@@ -7757,16 +7780,175 @@ equate_decl_number_to_die (tree decl, dw_die_ref decl_die)
decl_die->decl_id = decl_id; 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. */ /* Add a variable location node to the linked list for DECL. */
static struct var_loc_node * static struct var_loc_node *
add_var_loc_to_decl (tree decl, rtx loc_note, const char *label) 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; var_loc_list *temp;
void **slot; void **slot;
struct var_loc_node *loc = NULL; 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); slot = htab_find_slot_with_hash (decl_loc_table, decl, decl_id, INSERT);
if (*slot == NULL) if (*slot == NULL)
{ {
...@@ -7780,17 +7962,40 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label) ...@@ -7780,17 +7962,40 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
if (temp->last) if (temp->last)
{ {
struct var_loc_node *last = temp->last, *unused = NULL; struct var_loc_node *last = temp->last, *unused = NULL;
rtx *piece_loc = NULL, last_loc_note;
int piece_bitpos = 0;
if (last->next) if (last->next)
{ {
last = last->next; last = last->next;
gcc_assert (last->next == NULL); 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 /* 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 in the chained list, LAST is pointer to the
last element. */ last element. */
/* If the last note doesn't cover any instructions, remove it. */
if (label && strcmp (last->label, label) == 0) 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) if (temp->last != last)
{ {
temp->last->next = NULL; temp->last->next = NULL;
...@@ -7802,17 +8007,28 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label) ...@@ -7802,17 +8007,28 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
{ {
gcc_assert (temp->first == temp->last); gcc_assert (temp->first == temp->last);
memset (temp->last, '\0', sizeof (*temp->last)); memset (temp->last, '\0', sizeof (*temp->last));
temp->last->loc = construct_piece_list (loc_note, bitpos, bitsize);
return temp->last; 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, /* If the current location is the same as the end of the list,
and either both or neither of the locations is uninitialized, and either both or neither of the locations is uninitialized,
we have nothing to do. */ we have nothing to do. */
if ((!rtx_equal_p (NOTE_VAR_LOCATION_LOC (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_LOC (loc_note)))
|| ((NOTE_VAR_LOCATION_STATUS (last->var_loc_note) || ((NOTE_VAR_LOCATION_STATUS (last_loc_note)
!= NOTE_VAR_LOCATION_STATUS (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) == VAR_INIT_STATUS_UNINITIALIZED)
|| (NOTE_VAR_LOCATION_STATUS (loc_note) || (NOTE_VAR_LOCATION_STATUS (loc_note)
== VAR_INIT_STATUS_UNINITIALIZED)))) == VAR_INIT_STATUS_UNINITIALIZED))))
...@@ -7827,6 +8043,11 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label) ...@@ -7827,6 +8043,11 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
} }
else else
loc = GGC_CNEW (struct var_loc_node); 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; last->next = loc;
/* Ensure TEMP->LAST will point either to the new last but one /* Ensure TEMP->LAST will point either to the new last but one
element of the chain, or to the last element in it. */ 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) ...@@ -7841,6 +8062,7 @@ add_var_loc_to_decl (tree decl, rtx loc_note, const char *label)
loc = GGC_CNEW (struct var_loc_node); loc = GGC_CNEW (struct var_loc_node);
temp->first = loc; temp->first = loc;
temp->last = loc; temp->last = loc;
loc->loc = construct_piece_list (loc_note, bitpos, bitsize);
} }
return loc; return loc;
} }
...@@ -14084,7 +14306,11 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address, ...@@ -14084,7 +14306,11 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address,
} }
else 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; have_address = 1;
} }
...@@ -14134,6 +14360,125 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address, ...@@ -14134,6 +14360,125 @@ dw_loc_list_1 (tree loc, rtx varloc, int want_address,
return descr; 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 /* Return the dwarf representation of the location list LOC_LIST of
DECL. WANT_ADDRESS has the same meaning as in loc_list_from_tree DECL. WANT_ADDRESS has the same meaning as in loc_list_from_tree
function. */ function. */
...@@ -14163,32 +14508,35 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address) ...@@ -14163,32 +14508,35 @@ dw_loc_list (var_loc_list *loc_list, tree decl, int want_address)
secname = secname_for_decl (decl); secname = secname_for_decl (decl);
for (node = loc_list->first; node->next; node = node->next) for (node = loc_list->first; node; node = node->next)
if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX) if (GET_CODE (node->loc) == EXPR_LIST
|| NOTE_VAR_LOCATION_LOC (node->loc) != NULL_RTX)
{ {
/* The variable has a location between NODE->LABEL and if (GET_CODE (node->loc) == EXPR_LIST)
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 (descr)
{ {
*listp = new_loc_list (descr, node->label, node->next->label, /* This requires DW_OP_{,bit_}piece, which is not usable
secname); inside DWARF expressions. */
listp = &(*listp)->dw_loc_next; if (want_address != 2)
} continue;
descr = dw_sra_loc_expr (decl, node->loc);
if (descr == NULL)
continue;
} }
else
/* 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); initialized = NOTE_VAR_LOCATION_STATUS (node->loc);
varloc = NOTE_VAR_LOCATION (node->var_loc_note); varloc = NOTE_VAR_LOCATION (node->loc);
descr = dw_loc_list_1 (decl, varloc, want_address, initialized); descr = dw_loc_list_1 (decl, varloc, want_address, initialized);
}
if (descr) if (descr)
{ {
if (!current_function_decl) /* 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; endname = text_end_label;
else else
{ {
...@@ -15950,13 +16298,14 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, ...@@ -15950,13 +16298,14 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl,
if (loc_list if (loc_list
&& loc_list->first && loc_list->first
&& loc_list->first->next == NULL && loc_list->first->next == NULL
&& NOTE_VAR_LOCATION (loc_list->first->var_loc_note) && NOTE_P (loc_list->first->loc)
&& NOTE_VAR_LOCATION_LOC (loc_list->first->var_loc_note)) && NOTE_VAR_LOCATION (loc_list->first->loc)
&& NOTE_VAR_LOCATION_LOC (loc_list->first->loc))
{ {
struct var_loc_node *node; struct var_loc_node *node;
node = loc_list->first; 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) if (GET_CODE (rtl) == EXPR_LIST)
rtl = XEXP (rtl, 0); rtl = XEXP (rtl, 0);
if ((CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING) if ((CONSTANT_P (rtl) || GET_CODE (rtl) == CONST_STRING)
...@@ -20458,8 +20807,6 @@ dwarf2out_var_location (rtx loc_note) ...@@ -20458,8 +20807,6 @@ dwarf2out_var_location (rtx loc_note)
loclabel_num++; loclabel_num++;
last_label = ggc_strdup (loclabel); last_label = ggc_strdup (loclabel);
} }
newloc->var_loc_note = loc_note;
newloc->next = NULL;
if (!NOTE_DURING_CALL_P (loc_note)) if (!NOTE_DURING_CALL_P (loc_note))
newloc->label = last_label; newloc->label = last_label;
......
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> 2010-05-12 Jan Hubicka <jh@suse.cz>
* tree-ssa/unreachable.c: New test. * tree-ssa/unreachable.c: New test.
......
/* 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;
}
...@@ -1609,11 +1609,38 @@ create_access_replacement (struct access *access) ...@@ -1609,11 +1609,38 @@ create_access_replacement (struct access *access)
&& !DECL_ARTIFICIAL (access->base)) && !DECL_ARTIFICIAL (access->base))
{ {
char *pretty_name = make_fancy_name (access->expr); char *pretty_name = make_fancy_name (access->expr);
tree debug_expr = unshare_expr (access->expr), d;
DECL_NAME (repl) = get_identifier (pretty_name); DECL_NAME (repl) = get_identifier (pretty_name);
obstack_free (&name_obstack, 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; DECL_DEBUG_EXPR_IS_FROM (repl) = 1;
TREE_NO_WARNING (repl) = TREE_NO_WARNING (access->base); TREE_NO_WARNING (repl) = TREE_NO_WARNING (access->base);
} }
......
...@@ -4505,10 +4505,27 @@ track_expr_p (tree expr, bool need_rtl) ...@@ -4505,10 +4505,27 @@ track_expr_p (tree expr, bool need_rtl)
realdecl = DECL_DEBUG_EXPR (realdecl); realdecl = DECL_DEBUG_EXPR (realdecl);
if (realdecl == NULL_TREE) if (realdecl == NULL_TREE)
realdecl = expr; 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)) else if (!DECL_P (realdecl))
{
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; return 0;
else
realdecl = expr;
}
else
return 0;
}
} }
/* Do not track EXPR if REALDECL it should be ignored for debugging /* Do not track EXPR if REALDECL it should be ignored for debugging
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment