2013-01-30 Jakub Jelinek PR debug/56154 * dwarf2out.c (dwarf2_debug_hooks): Set end_function hook to dwarf2out_end_function. (in_first_function_p, maybe_at_text_label_p, first_loclabel_num_not_at_text_label): New variables. (dwarf2out_var_location): In the first function find out lowest loclabel_num N where .LVLN is known not to be equal to .Ltext0. (find_empty_loc_ranges_at_text_label, dwarf2out_end_function): New functions. * gcc.dg/guality/pr56154-1.c: New test. * gcc.dg/guality/pr56154-2.c: New test. * gcc.dg/guality/pr56154-3.c: New test. * gcc.dg/guality/pr56154-4.c: New test. * gcc.dg/guality/pr56154-aux.c: New file. --- gcc/dwarf2out.c.jj 2013-01-11 09:02:48.000000000 +0100 +++ gcc/dwarf2out.c 2013-01-30 16:18:58.362552894 +0100 @@ -2351,6 +2351,7 @@ static void dwarf2out_imported_module_or static void dwarf2out_abstract_function (tree); static void dwarf2out_var_location (rtx); static void dwarf2out_begin_function (tree); +static void dwarf2out_end_function (unsigned int); static void dwarf2out_set_name (tree, tree); /* The debug hooks structure. */ @@ -2378,7 +2379,7 @@ const struct gcc_debug_hooks dwarf2_debu #endif dwarf2out_end_epilogue, dwarf2out_begin_function, - debug_nothing_int, /* end_function */ + dwarf2out_end_function, /* end_function */ dwarf2out_function_decl, /* function_decl */ dwarf2out_global_decl, dwarf2out_type_decl, /* type_decl */ @@ -20627,6 +20628,14 @@ dwarf2out_set_name (tree decl, tree name add_name_attribute (die, dname); } +/* True if before or during processing of the first function being emitted. */ +static bool in_first_function_p = true; +/* True if loc_note during dwarf2out_var_location call might still be + before first real instruction at address equal to .Ltext0. */ +static bool maybe_at_text_label_p = true; +/* One above highest N where .LVLN label might be equal to .Ltext0 label. */ +static unsigned int first_loclabel_num_not_at_text_label; + /* Called by the final INSN scan whenever we see a var location. We use it to drop labels in the right places, and throw the location in our lookup table. */ @@ -20734,6 +20743,45 @@ dwarf2out_var_location (rtx loc_note) ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num); loclabel_num++; last_label = ggc_strdup (loclabel); + /* See if loclabel might be equal to .Ltext0. If yes, + bump first_loclabel_num_not_at_text_label. */ + if (!have_multiple_function_sections + && in_first_function_p + && maybe_at_text_label_p) + { + static rtx last_start; + rtx insn; + for (insn = loc_note; insn; insn = previous_insn (insn)) + if (insn == last_start) + break; + else if (!NONDEBUG_INSN_P (insn)) + continue; + else + { + rtx body = PATTERN (insn); + if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER) + continue; + /* Inline asm could occupy zero bytes. */ + else if (GET_CODE (body) == ASM_INPUT + || asm_noperands (body) >= 0) + continue; +#ifdef HAVE_attr_length + else if (get_attr_min_length (insn) == 0) + continue; +#endif + else + { + /* Assume insn has non-zero length. */ + maybe_at_text_label_p = false; + break; + } + } + if (maybe_at_text_label_p) + { + last_start = loc_note; + first_loclabel_num_not_at_text_label = loclabel_num; + } + } } if (!var_loc_p) @@ -20903,6 +20951,59 @@ dwarf2out_begin_function (tree fun) set_cur_line_info_table (sec); } +/* Helper function of dwarf2out_end_function, called only after emitting + the very first function into assembly. Check if some .debug_loc range + might end with a .LVL* label that could be equal to .Ltext0. + In that case we must force using absolute addresses in .debug_loc ranges, + because this range could be .LVLN-.Ltext0 .. .LVLM-.Ltext0 for + .LVLN == .LVLM == .Ltext0, thus 0 .. 0, which is a .debug_loc + list terminator. + Set have_multiple_function_sections to true in that case and + terminate htab traversal. */ + +static int +find_empty_loc_ranges_at_text_label (void **slot, void *) +{ + var_loc_list *entry; + struct var_loc_node *node; + + entry = (var_loc_list *) *slot; + node = entry->first; + if (node && node->next && node->next->label) + { + unsigned int i; + const char *label = node->next->label; + char loclabel[MAX_ARTIFICIAL_LABEL_BYTES]; + + for (i = 0; i < first_loclabel_num_not_at_text_label; i++) + { + ASM_GENERATE_INTERNAL_LABEL (loclabel, "LVL", i); + if (strcmp (label, loclabel) == 0) + { + have_multiple_function_sections = true; + return 0; + } + } + } + return 1; +} + +/* Hook called after emitting a function into assembly. + This does something only for the very first function emitted. */ + +static void +dwarf2out_end_function (unsigned int) +{ + if (in_first_function_p + && !have_multiple_function_sections + && first_loclabel_num_not_at_text_label + && decl_loc_table) + htab_traverse (decl_loc_table, find_empty_loc_ranges_at_text_label, + NULL); + in_first_function_p = false; + maybe_at_text_label_p = false; +} + /* Add OPCODE+VAL as an entry at the end of the opcode array in TABLE. */ static void --- gcc/testsuite/gcc.dg/guality/pr56154-1.c.jj 2013-01-30 17:14:20.850820429 +0100 +++ gcc/testsuite/gcc.dg/guality/pr56154-1.c 2013-01-30 17:47:25.242537776 +0100 @@ -0,0 +1,29 @@ +/* PR debug/56154 */ +/* { dg-do run } */ +/* { dg-options "-g" } */ +/* { dg-additional-sources "pr56154-aux.c" } */ + +#include "../nop.h" + +union U { int a, b; }; +volatile int z; + +__attribute__((noinline, noclone)) int +foo (int fd, union U x) +{ + int result = x.a != 0; + if (fd != 0) + result = x.a == 0; + asm (NOP : : : "memory"); /* { dg-final { gdb-test pr56154-1.c:17 "x.a" "4" } } */ + z = x.a; + x.a = 6; + asm (NOP : : : "memory"); /* { dg-final { gdb-test pr56154-1.c:20 "x.a" "6" } } */ + return result; +} + +void +test_main (void) +{ + union U u = { .a = 4 }; + foo (0, u); +} --- gcc/testsuite/gcc.dg/guality/pr56154-2.c.jj 2013-01-30 17:58:28.229799607 +0100 +++ gcc/testsuite/gcc.dg/guality/pr56154-2.c 2013-01-30 18:06:38.306982101 +0100 @@ -0,0 +1,39 @@ +/* PR debug/56154 */ +/* { dg-do run } */ +/* { dg-options "-g" } */ +/* { dg-additional-sources "pr56154-aux.c" } */ + +#include "../nop.h" + +extern void abort (void); + +__attribute__((noinline, noclone)) int +foo (int x) +{ + asm (""); + x++; + asm (""); + x++; + asm (""); + x++; + asm (""); + x++; + asm (""); + x++; + asm (""); + x++; + asm (""); + x++; + asm (""); + x++; + asm (NOP : : : "memory"); + asm (NOP : : : "memory"); /* { dg-final { gdb-test pr56154-2.c:30 "x" "28" } } */ + return x; +} + +void +test_main (void) +{ + if (foo (20) != 28) + abort (); +} --- gcc/testsuite/gcc.dg/guality/pr56154-3.c.jj 2013-01-30 18:04:47.531604188 +0100 +++ gcc/testsuite/gcc.dg/guality/pr56154-3.c 2013-01-30 18:06:25.031055514 +0100 @@ -0,0 +1,31 @@ +/* PR debug/56154 */ +/* { dg-do run } */ +/* { dg-options "-g" } */ +/* { dg-additional-sources "pr56154-aux.c" } */ + +#include "../nop.h" + +extern void abort (void); + +__attribute__((noinline, noclone)) int +foo (int x) +{ + x++; + x++; + x++; + x++; + x++; + x++; + x++; + x++; + asm (NOP : : : "memory"); + asm (NOP : : : "memory"); /* { dg-final { gdb-test pr56154-3.c:22 "x" "28" } } */ + return x; +} + +void +test_main (void) +{ + if (foo (20) != 28) + abort (); +} --- gcc/testsuite/gcc.dg/guality/pr56154-4.c.jj 2013-01-30 18:05:45.959280837 +0100 +++ gcc/testsuite/gcc.dg/guality/pr56154-4.c 2013-01-30 18:07:50.457602221 +0100 @@ -0,0 +1,34 @@ +/* PR debug/56154 */ +/* { dg-do run } */ +/* { dg-options "-g" } */ +/* { dg-additional-sources "pr56154-aux.c" } */ + +#include "../nop.h" + +extern void abort (void); + +volatile int z; + +__attribute__((noinline, noclone)) int +foo (int x) +{ + z = 6; + x++; + x++; + x++; + x++; + x++; + x++; + x++; + x++; + asm (NOP : : : "memory"); + asm (NOP : : : "memory"); /* { dg-final { gdb-test pr56154-4.c:25 "x" "28" } } */ + return x; +} + +void +test_main (void) +{ + if (foo (20) != 28) + abort (); +} --- gcc/testsuite/gcc.dg/guality/pr56154-aux.c.jj 2013-01-30 17:47:08.467632262 +0100 +++ gcc/testsuite/gcc.dg/guality/pr56154-aux.c 2013-01-30 17:14:28.000000000 +0100 @@ -0,0 +1,11 @@ +/* PR debug/56154 */ +/* { dg-do compile } */ + +extern void test_main (void); + +int +main () +{ + test_main (); + return 0; +}