Path: utzoo!utgpu!jarvis.csri.toronto.edu!cs.utexas.edu!tut.cis.ohio-state.edu!ICS.UCI.EDU!rfg From: rfg@ICS.UCI.EDU Newsgroups: gnu.gcc.bug Subject: BUG(s) with -g & -O & COFF using GCC (G++) 1.36 (1.36.1) Message-ID: <8912061430.aa24708@ICS.UCI.EDU> Date: 6 Dec 89 22:29:02 GMT Sender: daemon@tut.cis.ohio-state.edu Distribution: gnu Organization: GNUs Not Usenet Lines: 360 WARNING: The following message is LONG and is only of concern to those people who give a darn if -g and -O work correctly with COFF object files. Others should skip this message now. The following code (derived from one of the libg++ test programs) causes assembler errors on System V when compiled with -g and -O under either GCC 1.36 or G++ 1.36.1 (with lots of patches for the m88k & DG-UX installed). ----------------------------------------------------------------- int unused; inline int unused_indices() { return unused; } int add(const int elem) { for(;;) { if (unused_indices() != 0) { int i = 7; return i; } unused = 0; } } ----------------------------------------------------------------- The problem here seems to be that (a) System V assemblers may check to see that symbol definitions for the *special* debugging symbols ".bb" (begin-block) and ".eb" (end-block) are properly paired and ordered (as it seems they should be anyway). When using -g (with GCC or G++) symbol definitions for the special symbols ".bb" and ".eb" are generated from special kinds of line NOTES (specifically, from NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END respectively). Unfortunately, if you are using -g *and* -O, then jump optimization can cause a NOTE_INSN_BLOCK_BEG to become separated from its corresponding NOTE_INSN_BLOCK_END, and the code motion that jump optimization may cause to occur can then cause the NOTE_INSN_BLOCK_END to appear *before* its associated NOTE_INSN_BLOCK_BEG! Thus, the assembler will see a symbol definition for ".eb" *before* a symbol definition for ".bb". The proper solution seems to be simply to prevent jump optimization from separating a matched pair of NOTE_INSN_BLOCK_BEG & NOTE_INSN_BLOCK_END. The following patches for jump.c implement this solution. (Your line numbers may vary.) --------------------------------------- While investigating this problem, I also noticed that the regular line number NOTES for the inlined function call in the example above were also looking quite screwy. I made some fixes (included below) for these cases as well. Specifically, it seems to me that the code which causes parameter values to be "passed into" an inline function invocation should be thought of (by a debugger) as occuring on the line containing the start of the inline function (or as near thereto as possible). In the example above, this would be either line #3 or line #4 (for the inlined call to "unused_indicies()"). Also, at the point in the generated code where the inlining ends (line #11 in the example above), it seems to me that the compiler should make another new line-number note which *could* inform a debugger that we are now back executing the rest of the normal line that follows the inlined function call. I have implemented these changes also, and the necessary patches (to integrate.c, stmt.c and c-parse.y) are included below following the patches for jump.c. (Your line numbers may vary.) --------------------------------------- Note that on System V, the latter set of patches will (in all probability) actually be useless (other than making it easier to read rtl dumps). This is because COFF line number information looses totally when it comes to inlined functions. COFF line numbers are supposed to always be expressed as positive line OFFSETS from the first line of the containing function. Unfortunately, inlining can cause the COFF line numbers for chunks of inlined code to be NEGATIVE!!! System V assemblers/linkers/debuggers can (and often do) choke on such negative line numbers. Because of this final problem (which probably only arises when you have SDB_DEBUGGING_INFO defined in your tm-*.h file), I suggest that those people who are using any of the following tm-*.h files should check their definitions of ASM_OUTPUT_SOURCE_LINE to be sure that negative line numbers get filtered out. I do not have time to check all of these myself. The (potentially) problematic tm-*.h files are: tm-3b1.h tm-encore.h tm-harris.h tm-i386v.h tm-m88k.h (I fixed my copy!) tm-vaxv.h Note that a similar (negative line-number) problem can occur (with COFF) if your definitions of PUT_SDB_BLOCK_START and PUT_SDB_BLOCK_END fail to filter out negative line numbers. There are default definitions of these macros in sdbout.c (and these default definitions should probably be fixed to do the filtering) but you may also want to created fixed definitions of these two macros (which do the filtering) in your own tm-*.h file (if you are using one of the tm-*.h files listed above). Enjoy, // rfg diff -rc2 1.36.1/jump.c 1.36.2/jump.c *** 1.36.1/jump.c Wed Sep 6 21:39:18 1989 --- 1.36.2/jump.c Wed Dec 6 12:49:55 1989 *************** *** 84,87 **** --- 84,88 ---- rtx next_real_insn (); rtx prev_real_insn (); + static rtx last_insn_for_range (); rtx next_label (); *************** *** 449,454 **** rtx range1beg = NEXT_INSN (insn); rtx range2beg = NEXT_INSN (label1); ! rtx range1after = NEXT_INSN (range1end); ! rtx range2after = NEXT_INSN (range2end); /* Splice range2 between INSN and LABEL1. */ NEXT_INSN (insn) = range2beg; --- 450,476 ---- rtx range1beg = NEXT_INSN (insn); rtx range2beg = NEXT_INSN (label1); ! rtx range1after; ! rtx range2after; ! ! /* If necessary, adjust each range so that it ! includes a following NOTE_INSN_BLOCK_END if ! one follows the range but preceeds any following ! CODE_LABEL's or real insns. This is needed ! because of the possibility that one of the ! ranges contains a NOTE_INSN_BLOCK_BEG that ! corresponds to the NOTE_INSN_BLOCK_END that we ! may find following the nominal range. In such ! cases, we want to be sure to include the ! corresponding NOTE_INSN_BLOCK_END in the same ! range. The range adjustment also causes ! BARRIERs to be kept with their associated ! JUMP_INSNs, but that's just a side effect. */ ! ! range1end = last_insn_for_range (range1end); ! range2end = last_insn_for_range (range2end); ! ! range1after = NEXT_INSN (range1end); ! range2after = NEXT_INSN (range2end); ! /* Splice range2 between INSN and LABEL1. */ NEXT_INSN (insn) = range2beg; *************** *** 958,961 **** --- 980,1018 ---- return insn; + } + + /* Return the NOTE_INSN_BLOCK_END that follows INSN (but preceeds any + following real insns). Failing that, return the last following BARRIER + that follows INSN (but preceeds any following real insns). Failing that, + return INSN (which may be 0). */ + + static rtx + last_insn_for_range (insn) + rtx insn; + { + register rtx return_val; + register rtx ahead; + register RTX_CODE code; + + if (insn == 0) + return insn; + return_val = insn; + for (ahead = NEXT_INSN (insn); ahead; ahead = NEXT_INSN (ahead)) + { + switch (GET_CODE (ahead)) + { + case BARRIER: + return_val = ahead; + break; + case NOTE: + if (NOTE_LINE_NUMBER (ahead) == NOTE_INSN_BLOCK_END) + return ahead; + else + continue; /* Just pass over regular NOTEs */ + default: + return return_val; + } + } + return return_val; } %%% here are the patches to get line numbers right for inlined calls diff -rc2 1.36.1/c-parse.y 1.36.2/c-parse.y *** 1.36.1/c-parse.y Tue Sep 19 22:11:01 1989 --- 1.36.2/c-parse.y Wed Dec 6 01:31:13 1989 *************** *** 952,956 **** clear_last_expr (); push_momentary (); ! expand_start_bindings (0); } ; --- 952,956 ---- clear_last_expr (); push_momentary (); ! expand_start_bindings (0, 1); } ; diff -rc2 1.36.1/integrate.c 1.36.2/integrate.c *** 1.36.1/integrate.c Wed Nov 22 12:11:00 1989 --- 1.36.2/integrate.c Wed Dec 6 01:32:14 1989 *************** *** 28,31 **** --- 28,32 ---- #include "insn-flags.h" #include "expr.h" + #include "input.h" #include "obstack.h" *************** *** 592,595 **** --- 593,597 ---- rtx header = DECL_SAVED_INSNS (fndecl); rtx insns = FIRST_FUNCTION_INSN (header); + rtx parm_insns = FIRST_PARM_INSN (header); rtx insn; int max_regno = MAX_REGNUM (header) + 1; *************** *** 629,632 **** --- 631,644 ---- } + /* For the benefit of debuggers that might understand such things, make + a note here of the file and line which contain the function header + for the function being inlined. Also, make sure that the subsequent + call to expand_start_bindings() does not make another note based on + the actual current line & file (i.e. the place where the inlining is + actually occuring). Making such a note would just nullify the effect + of the note we are making here. */ + + emit_note (NOTE_SOURCE_FILE (parm_insns), NOTE_LINE_NUMBER (parm_insns)); + /* Make a binding contour to keep inline cleanups called at outer function-scope level from looking like they are shadowing *************** *** 636,640 **** /* Make a fresh binding contour that we can easily remove. */ pushlevel (0); ! expand_start_bindings (0); /* Get all the actual args as RTL, and store them in ARG_VEC. */ --- 648,652 ---- /* Make a fresh binding contour that we can easily remove. */ pushlevel (0); ! expand_start_bindings (0, 0); /* Get all the actual args as RTL, and store them in ARG_VEC. */ *************** *** 1073,1077 **** /* End the scope containing the copied formal parameter variables. */ ! expand_end_bindings (getdecls (), 1, 1); poplevel (1, 1, 0); poplevel (0, 0, 0); --- 1085,1091 ---- /* End the scope containing the copied formal parameter variables. */ ! expand_end_bindings (getdecls (), 0, 1); ! /* Make sure that debuggers know that we are back where we started. */ ! emit_note (input_filename, lineno); poplevel (1, 1, 0); poplevel (0, 0, 0); diff -rc2 1.36.1/stmt.c 1.36.2/stmt.c *** 1.36.1/stmt.c Wed Nov 22 12:11:20 1989 --- 1.36.2/stmt.c Wed Dec 6 01:36:10 1989 *************** *** 52,55 **** --- 52,56 ---- #include "rtl.h" + #include "input.h" #include "tree.h" #include "flags.h" *************** *** 1678,1683 **** void ! expand_start_bindings (exit_flag) int exit_flag; { struct nesting *thisblock --- 1679,1685 ---- void ! expand_start_bindings (exit_flag, line_note_flag) int exit_flag; + int line_note_flag; { struct nesting *thisblock *************** *** 1684,1689 **** = (struct nesting *) xmalloc (sizeof (struct nesting)); ! rtx note = emit_note (0, NOTE_INSN_BLOCK_BEG); /* Make an entry on block_stack for the block we are entering. */ --- 1686,1701 ---- = (struct nesting *) xmalloc (sizeof (struct nesting)); ! /* Force a line note here just in case this block gets moved around due to ! jump optimizations. */ + rtx note = (line_note_flag) + ? emit_line_note_force (input_filename, lineno) + : 0; + + if (note) + emit_note (0, NOTE_INSN_BLOCK_BEG); + else + note = emit_note (0, NOTE_INSN_BLOCK_BEG); + /* Make an entry on block_stack for the block we are entering. */ *************** *** 1772,1779 **** if (mark_ends) ! emit_note (0, NOTE_INSN_BLOCK_END); else ! /* Get rid of the beginning-mark if we don't make an end-mark. */ ! NOTE_LINE_NUMBER (thisblock->data.block.first_insn) = NOTE_INSN_DELETED; if (thisblock->exit_label) --- 1784,1800 ---- if (mark_ends) ! { ! emit_note (input_filename, lineno); ! emit_note (0, NOTE_INSN_BLOCK_END); ! } else ! { ! /* Get rid of the beginning-mark if we don't make an end-mark. */ ! rtx block_beg_note = thisblock->data.block.first_insn; ! ! if (NOTE_LINE_NUMBER (block_beg_note) != NOTE_INSN_BLOCK_BEG) ! block_beg_note = NEXT_INSN (block_beg_note); ! NOTE_LINE_NUMBER (block_beg_note) = NOTE_INSN_DELETED; ! } if (thisblock->exit_label)