Hi! The code in output_loc_list for DWARF5 relies on dw_loc_list_node's section field accuracy, in particular that nodes with labels in the hot subsection have one section (label) and nodes with labels in the cold subsection have another one. But that is actually not the case, so we end up with cross-section symbol difference which assembler doesn't assemble.
The following patch fixes that by making sure that section in the nodes is accurate. We already have loc_list->last_before_switch which points to the last node in the first partition or NULL if either no section switch was seen (if !crtl->has_bb_partition) or if the first node is after the section switch (if crtl->has_bb_partition) and use it for the regions that need to be split among the two. The patch has lots of reindentation, so I'm including here also diff -upbd output of the dwarf2out.c changes. The first if ensures that secname is correct for the first node and the other changes update it in the loop after processing node equal to last_before_switch (or, if doing range_across_switch, after emitting first partition's entry and before emitting second partition's entry). Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? diff -upbd here, patch afterwards: --- gcc/dwarf2out.c.jj 2017-10-23 22:39:27.000000000 +0200 +++ gcc/dwarf2out.c 2017-10-25 21:01:13.237929750 +0200 @@ -16333,21 +16333,31 @@ dw_loc_list (var_loc_list *loc_list, tre This means we have to special case the last node, and generate a range of [last location start, end of function label]. */ + if (cfun && crtl->has_bb_partition) + { + bool save_in_cold_section_p = in_cold_section_p; + in_cold_section_p = first_function_block_is_cold; + if (loc_list->last_before_switch == NULL) + in_cold_section_p = !in_cold_section_p; + secname = secname_for_decl (decl); + in_cold_section_p = save_in_cold_section_p; + } + else secname = secname_for_decl (decl); for (node = loc_list->first; node; node = node->next) + { + bool range_across_switch = false; if (GET_CODE (node->loc) == EXPR_LIST || NOTE_VAR_LOCATION_LOC (node->loc) != NULL_RTX) { if (GET_CODE (node->loc) == EXPR_LIST) { + descr = NULL; /* This requires DW_OP_{,bit_}piece, which is not usable inside DWARF expressions. */ - if (want_address != 2) - continue; + if (want_address == 2) descr = dw_sra_loc_expr (decl, node->loc); - if (descr == NULL) - continue; } else { @@ -16357,7 +16367,6 @@ dw_loc_list (var_loc_list *loc_list, tre } if (descr) { - bool range_across_switch = false; /* If section switch happens in between node->label and node->next->label (or end of function) and we can't emit it as a single entry list, @@ -16393,6 +16402,18 @@ dw_loc_list (var_loc_list *loc_list, tre && strcmp (node->label, endname) == 0) (*listp)->force = true; listp = &(*listp)->dw_loc_next; + } + } + + if (cfun + && crtl->has_bb_partition + && node == loc_list->last_before_switch) + { + bool save_in_cold_section_p = in_cold_section_p; + in_cold_section_p = !first_function_block_is_cold; + secname = secname_for_decl (decl); + in_cold_section_p = save_in_cold_section_p; + } if (range_across_switch) { @@ -16412,13 +16433,11 @@ dw_loc_list (var_loc_list *loc_list, tre endname = node->next->label; else endname = cfun->fde->dw_fde_second_end; - *listp = new_loc_list (descr, - cfun->fde->dw_fde_second_begin, + *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin, 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 2017-10-26 Jakub Jelinek <ja...@redhat.com> PR debug/82718 * dwarf2out.c (dw_loc_list): If crtl->has_bb_partition, temporarily set in_cold_section_p to the partition containing loc_list->first. When seeing loc_list->last_before_switch node, update secname and perform range_across_switch second partition handling only after that. * gcc.dg/debug/dwarf2/pr82718.c: New test. --- gcc/dwarf2out.c.jj 2017-10-23 22:39:27.000000000 +0200 +++ gcc/dwarf2out.c 2017-10-25 21:01:13.237929750 +0200 @@ -16333,92 +16333,111 @@ dw_loc_list (var_loc_list *loc_list, tre This means we have to special case the last node, and generate a range of [last location start, end of function label]. */ - secname = secname_for_decl (decl); + if (cfun && crtl->has_bb_partition) + { + bool save_in_cold_section_p = in_cold_section_p; + in_cold_section_p = first_function_block_is_cold; + if (loc_list->last_before_switch == NULL) + in_cold_section_p = !in_cold_section_p; + secname = secname_for_decl (decl); + in_cold_section_p = save_in_cold_section_p; + } + else + secname = secname_for_decl (decl); for (node = loc_list->first; node; node = node->next) - if (GET_CODE (node->loc) == EXPR_LIST - || NOTE_VAR_LOCATION_LOC (node->loc) != NULL_RTX) - { - 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; + { + bool range_across_switch = false; + if (GET_CODE (node->loc) == EXPR_LIST + || NOTE_VAR_LOCATION_LOC (node->loc) != NULL_RTX) + { + if (GET_CODE (node->loc) == EXPR_LIST) + { + descr = NULL; + /* This requires DW_OP_{,bit_}piece, which is not usable + inside DWARF expressions. */ + if (want_address == 2) + descr = dw_sra_loc_expr (decl, node->loc); + } + 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) + { + /* If section switch happens in between node->label + and node->next->label (or end of function) and + we can't emit it as a single entry list, + emit two ranges, first one ending at the end + of first partition and second one starting at the + beginning of second partition. */ + if (node == loc_list->last_before_switch + && (node != loc_list->first || loc_list->first->next) + && current_function_decl) + { + endname = cfun->fde->dw_fde_end; + range_across_switch = true; + } + /* The variable has a location between NODE->LABEL and + NODE->NEXT->LABEL. */ + else 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); + if (TREE_CODE (decl) == PARM_DECL + && node == loc_list->first + && NOTE_P (node->loc) + && strcmp (node->label, endname) == 0) + (*listp)->force = true; + listp = &(*listp)->dw_loc_next; + } + } + + if (cfun + && crtl->has_bb_partition + && node == loc_list->last_before_switch) + { + bool save_in_cold_section_p = in_cold_section_p; + in_cold_section_p = !first_function_block_is_cold; + secname = secname_for_decl (decl); + in_cold_section_p = save_in_cold_section_p; + } + + if (range_across_switch) + { + if (GET_CODE (node->loc) == EXPR_LIST) 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) - { - bool range_across_switch = false; - /* If section switch happens in between node->label - and node->next->label (or end of function) and - we can't emit it as a single entry list, - emit two ranges, first one ending at the end - of first partition and second one starting at the - beginning of second partition. */ - if (node == loc_list->last_before_switch - && (node != loc_list->first || loc_list->first->next) - && current_function_decl) - { - endname = cfun->fde->dw_fde_end; - range_across_switch = true; - } - /* The variable has a location between NODE->LABEL and - NODE->NEXT->LABEL. */ - else 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); - if (TREE_CODE (decl) == PARM_DECL - && node == loc_list->first - && NOTE_P (node->loc) - && strcmp (node->label, endname) == 0) - (*listp)->force = true; - listp = &(*listp)->dw_loc_next; - - if (range_across_switch) - { - if (GET_CODE (node->loc) == EXPR_LIST) - descr = dw_sra_loc_expr (decl, node->loc); - else - { - initialized = NOTE_VAR_LOCATION_STATUS (node->loc); - varloc = NOTE_VAR_LOCATION (node->loc); - descr = dw_loc_list_1 (decl, varloc, want_address, - initialized); - } - gcc_assert (descr); - /* The variable has a location between NODE->LABEL and - NODE->NEXT->LABEL. */ - if (node->next) - endname = node->next->label; - else - endname = cfun->fde->dw_fde_second_end; - *listp = new_loc_list (descr, - cfun->fde->dw_fde_second_begin, - endname, secname); - listp = &(*listp)->dw_loc_next; - } - } - } + else + { + initialized = NOTE_VAR_LOCATION_STATUS (node->loc); + varloc = NOTE_VAR_LOCATION (node->loc); + descr = dw_loc_list_1 (decl, varloc, want_address, + initialized); + } + gcc_assert (descr); + /* The variable has a location between NODE->LABEL and + NODE->NEXT->LABEL. */ + if (node->next) + endname = node->next->label; + else + endname = cfun->fde->dw_fde_second_end; + *listp = new_loc_list (descr, cfun->fde->dw_fde_second_begin, + 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 --- gcc/testsuite/gcc.dg/debug/dwarf2/pr82718.c.jj 2017-10-25 21:10:53.324920386 +0200 +++ gcc/testsuite/gcc.dg/debug/dwarf2/pr82718.c 2017-10-25 21:10:25.000000000 +0200 @@ -0,0 +1,41 @@ +/* PR debug/82718 */ +/* { dg-do assemble } */ +/* { dg-options "-O2 -gdwarf-5" } */ + +extern int e; +extern long foo (int, void *, unsigned long, unsigned long); +struct S +{ + int f; + unsigned long t, s; +}; + +static inline long +bv (int x, void *y, unsigned long z, unsigned long w) +{ + long a = 0; + do + { + long g; + do + g = (long int) (foo (x, y + a, z - a, w + a)); + while (g == -1L && e == 9959); + if (g <= 0) + return g < 0 ? g : a; + a += g; + } + while ((unsigned long) a < z); + return a; +} + +const char * +baz (struct S *x) +{ + unsigned long h = 8; + char *j = 0; + unsigned long z = x->f; + if (__builtin_expect (!!((unsigned long) bv (x->f, j, z, x->t + h + 10) != z), 0)) + return 0; + x->s = z; + return j; +} Jakub