This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Line info in the presence of __main, and NOTE_INSN_FUNCTION_BEG after scheduling.
- From: Pedro Alves <pedro_alves at portugalmail dot pt>
- To: gcc-patches <gcc-patches at gcc dot gnu dot org>
- Date: Sat, 09 Dec 2006 19:13:38 +0000
- Subject: [PATCH] Line info in the presence of __main, and NOTE_INSN_FUNCTION_BEG after scheduling.
Hi all,
(
This is a follow up of the discussion starting here:
http://sources.redhat.com/ml/gdb/2006-11/msg00134.html
Ending up with Daniel's response here:
http://sources.redhat.com/ml/gdb/2006-11/msg00140.html
)
Currently, in Cygwin, or in any other target that emits calls to __main
in main, when
the user requests a break on main in gdb, gdb will put the break on the
opening {, instead of
on the first statement, eg: on printf below.
#include <stdio.h>
int
main ()
{
printf ("hello world\n");
return 0;
}
The problem is that gdb, in the presence of debug info, uses the second
line number
marker to mark the end of the prologue, and as you can see below,
there is a .loc before __main, confusing gdb.
Snipped from running 'gcc main.c -g -gdwarf-2 -O3 -o main.s -S' :
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB3:
.file 1 "main.c"
.loc 1 5 0
leal 4(%esp), %ecx
LCFI0:
andl $-16, %esp
pushl -4(%ecx)
LCFI1:
pushl %ebp
LCFI2:
movl %esp, %ebp
LCFI3:
pushl %ecx
LCFI4:
subl $4, %esp
LCFI5:
.loc 1 5 0
call ___main
.loc 1 6 0
movl $LC0, (%esp)
call _puts
.loc 1 7 0
movl $0, %eax
.loc 1 8 0
addl $4, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
---
The attached patch fixes the gcc part by doing two things:
- Move the expand_main_function call to before NOTE_INSN_FUNCTION_BEG
note is emitted,
so the __main call is not considered part of the user function body;
- Preserve NOTE_INSN_FUNCTION_BEG/NOTE_INSN_FUNCTION_END across
scheduler runs. It does that
using the REG_SAVE_NOTE mechanism. There where also some old comments
around this mechanism that
were no longer true. The patch also fixes them.
(It also makes final.c:final_scan_insn output some more -dA comments, to
easily track the changes.)
This is the result of gcc main.c -o main.s -dA -O3 -S with the patched
compiler:
$cat main.s
.file "main.c"
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "hello world\0"
.text
.p2align 4,,15
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
# basic block 2
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $4, %esp
# prologue end
call ___main
# function beg
movl $LC0, (%esp)
call _puts
# epilogue beg
addl $4, %esp
# function end
xorl %eax, %eax
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.def _puts; .scl 2; .type 32; .endef
Notice the '# function beg' after 'call ___main'.
Bootstrapped and tested with no regressions on native Cygwin for
--enable-languages=c,c++.
With a gdb patch to make i386 targets skip the prologue using the symbol
table
like most other targets do (currently i386 targets always scan the
prologue the hard way), this fixes all
the GDB testsuite failures (a few dozens) related to setting a
breakpoint on main and running to it (runto_main) on Cygwin.
:ADDPATCH:
Cheers,
Pedro Alves
---
gcc/ChangeLog
2006-12-09 Pedro Alves <pedro_alves@portugalmail.pt>
* cfgexpand.c (tree_expand_cfg): Move expand_main_function and
stack_protect_prologue calls to ...
* function.c (expand_function_start): ... here.
(expand_main_function): Make it static.
* tree.h (expand_main_function): Remove declaration.
* sched-deps.c (sched_analyze): Save NOTE_INSN_FUNCTION_BEG and
NOTE_INSN_FUNCTION_END using REG_SAVE_NOTE.
* haifa-sched.c: Update NOTES handling comment.
(unlink_other_notes): Don't handle NOTE_INSN_FUNCTION_BEG and
NOTE_INSN_FUNCTION_END here.
Update comment.
* final.c (final_scan_insn): Output asm debug comments on
NOTE_INSN_PROLOGUE_BEG, NOTE_INSN_PROLOGUE_END, NOTE_INSN_EPILOGUE_BEG,
NOTE_INSN_FUNCTION_BEG, NOTE_INSN_FUNCTION_END, NOTE_INSN_BLOCK_BEG
and NOTE_INSN_BLOCK_END.
Index: cfgexpand.c
===================================================================
--- cfgexpand.c (revision 119115)
+++ cfgexpand.c (working copy)
@@ -1623,18 +1623,6 @@ tree_expand_cfg (void)
/* Set up parameters and prepare for return, for the function. */
expand_function_start (current_function_decl);
- /* If this function is `main', emit a call to `__main'
- to run global initializers, etc. */
- if (DECL_NAME (current_function_decl)
- && MAIN_NAME_P (DECL_NAME (current_function_decl))
- && DECL_FILE_SCOPE_P (current_function_decl))
- expand_main_function ();
-
- /* Initialize the stack_protect_guard field. This must happen after the
- call to __main (if any) so that the external decl is initialized. */
- if (cfun->stack_protect_guard)
- stack_protect_prologue ();
-
/* Register rtl specific functions for cfg. */
rtl_register_cfg_hooks ();
Index: function.c
===================================================================
--- function.c (revision 119115)
+++ function.c (working copy)
@@ -3927,7 +3927,7 @@ struct tree_opt_pass pass_init_function
};
-void
+static void
expand_main_function (void)
{
#if (defined(INVOKE__main) \
@@ -4170,6 +4170,18 @@ expand_function_start (tree subr)
update_nonlocal_goto_save_area ();
}
+ /* If this function is `main', emit a call to `__main'
+ to run global initializers, etc. */
+ if (DECL_NAME (current_function_decl)
+ && MAIN_NAME_P (DECL_NAME (current_function_decl))
+ && DECL_FILE_SCOPE_P (current_function_decl))
+ expand_main_function ();
+
+ /* Initialize the stack_protect_guard field. This must happen after the
+ call to __main (if any) so that the external decl is initialized. */
+ if (cfun->stack_protect_guard)
+ stack_protect_prologue ();
+
/* The following was moved from init_function_start.
The move is supposed to make sdb output more accurate. */
/* Indicate the beginning of the function body,
Index: tree.h
===================================================================
--- tree.h (revision 119115)
+++ tree.h (working copy)
@@ -4354,7 +4354,6 @@ extern bool fields_compatible_p (tree, t
extern tree find_compatible_field (tree, tree);
/* In function.c */
-extern void expand_main_function (void);
extern void init_dummy_function_start (void);
extern void expand_dummy_function_end (void);
extern unsigned int init_function_for_compilation (void);
Index: sched-deps.c
===================================================================
--- sched-deps.c (revision 119115)
+++ sched-deps.c (working copy)
@@ -1457,6 +1457,7 @@ void
sched_analyze (struct deps *deps, rtx head, rtx tail)
{
rtx insn;
+ rtx reg_note = NULL_RTX;
if (current_sched_info->use_cselib)
cselib_init (true);
@@ -1491,6 +1492,12 @@ sched_analyze (struct deps *deps, rtx he
= alloc_INSN_LIST (insn, deps->last_pending_memory_flush);
}
sched_analyze_insn (deps, PATTERN (insn), insn);
+ if (reg_note)
+ {
+ XEXP (reg_note, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = reg_note;
+ reg_note = NULL_RTX;
+ }
}
else if (CALL_P (insn))
{
@@ -1545,6 +1552,12 @@ sched_analyze (struct deps *deps, rtx he
REG_DEP_ANTI);
sched_analyze_insn (deps, PATTERN (insn), insn);
+ if (reg_note)
+ {
+ XEXP (reg_note, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = reg_note;
+ reg_note = NULL_RTX;
+ }
/* In the absence of interprocedural alias analysis, we must flush
all pending reads and writes, and start new dependencies starting
@@ -1568,6 +1581,15 @@ sched_analyze (struct deps *deps, rtx he
gcc_assert (NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END);
+ if (NOTE_P (insn)
+ && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_END))
+ {
+ reg_note = alloc_EXPR_LIST (REG_SAVE_NOTE,
+ GEN_INT (NOTE_LINE_NUMBER (insn)),
+ reg_note);
+ }
+
if (current_sched_info->use_cselib)
cselib_process_insn (insn);
Index: haifa-sched.c
===================================================================
--- haifa-sched.c (revision 119115)
+++ haifa-sched.c (working copy)
@@ -511,7 +511,7 @@ static void advance_one_cycle (void);
Generally, NOTES are saved before scheduling and restored after scheduling.
The scheduler distinguishes between three types of notes:
- (1) LOOP_BEGIN, LOOP_END, SETJMP, EHREGION_BEG, EHREGION_END notes:
+ (1) NOTE_INSN_FUNCTION_BEG, NOTE_INSN_FUNCTION_BEG notes:
Before scheduling a region, a pointer to the note is added to the insn
that follows or precedes it. (This happens as part of the data dependence
computation). After scheduling an insn, the pointer contained in it is
@@ -1254,7 +1254,9 @@ unlink_other_notes (rtx insn, rtx tail)
/* See sched_analyze to see how these are handled. */
if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
- && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END)
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END)
{
/* Insert the note at the end of the notes list. */
PREV_INSN (insn) = note_list;
@@ -1775,11 +1777,9 @@ debug_ready_list (struct ready_list *rea
fprintf (sched_dump, "\n");
}
-/* Search INSN for REG_SAVE_NOTE note pairs for
- NOTE_INSN_EHREGION_{BEG,END}; and convert them back into
- NOTEs. The REG_SAVE_NOTE note following first one is contains the
- saved value for NOTE_BLOCK_NUMBER which is useful for
- NOTE_INSN_EH_REGION_{BEG,END} NOTEs. */
+/* Search INSN for REG_SAVE_NOTE notes for
+ NOTE_INSN_FUNCTION_{BEG,END}; and convert them back into
+ NOTEs. */
static void
reemit_notes (rtx insn)
Index: final.c
===================================================================
--- final.c (revision 119115)
+++ final.c (working copy)
@@ -1697,9 +1697,7 @@ final_scan_insn (rtx insn, FILE *file, i
switch (NOTE_LINE_NUMBER (insn))
{
case NOTE_INSN_DELETED:
- case NOTE_INSN_FUNCTION_END:
break;
-
case NOTE_INSN_SWITCH_TEXT_SECTIONS:
in_cold_section_p = !in_cold_section_p;
(*debug_hooks->switch_text_section) ();
@@ -1739,6 +1737,9 @@ final_scan_insn (rtx insn, FILE *file, i
targetm.asm_out.function_end_prologue (file);
profile_after_prologue (file);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s prologue end\n", ASM_COMMENT_START);
+
if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
{
*seen |= SEEN_EMITTED;
@@ -1751,12 +1752,17 @@ final_scan_insn (rtx insn, FILE *file, i
case NOTE_INSN_EPILOGUE_BEG:
targetm.asm_out.function_begin_epilogue (file);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s epilogue beg\n", ASM_COMMENT_START);
break;
case NOTE_INSN_FUNCTION_BEG:
app_disable ();
(*debug_hooks->end_prologue) (last_linenum, last_filename);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s function beg\n", ASM_COMMENT_START);
+
if ((*seen & (SEEN_EMITTED | SEEN_NOTE)) == SEEN_NOTE)
{
*seen |= SEEN_EMITTED;
@@ -1767,7 +1773,15 @@ final_scan_insn (rtx insn, FILE *file, i
break;
+ case NOTE_INSN_FUNCTION_END:
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s function end\n", ASM_COMMENT_START);
+ break;
+
case NOTE_INSN_BLOCK_BEG:
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s insn block beg\n", ASM_COMMENT_START);
+
if (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
|| write_symbols == DWARF2_DEBUG
@@ -1789,6 +1803,8 @@ final_scan_insn (rtx insn, FILE *file, i
break;
case NOTE_INSN_BLOCK_END:
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s insn block end\n", ASM_COMMENT_START);
if (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
|| write_symbols == DWARF2_DEBUG