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