This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug middle-end/10003] gcc -g mis-places low_pc of inlined functions


PLEASE REPLY TO gcc-bugzilla@gcc.gnu.org ONLY, *NOT* gcc-bugs@gcc.gnu.org.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=10003



------- Additional Comments From carlo at alinoe dot com  2003-09-18 01:08 -------
I looked into this, using a little program:

extern int a;

inline void g() { a = a + 1; }

void f() {
  g();
}


Which sports the problem that
the low_pc of the inlined g() is
including the start of f():

# /usr/src/gcc/gcc-cvs-3.4-objdir/gcc/cc1plus -fpreprocessed troep.i -quiet
-dumpbase troep.c -mtune=pentiumpro -auxbase troep -g -O -version -o troep.s
# as -V -Qy -o troep.o troep.s
# objdump -d troep.o
00000000 <_Z1fv>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   ff 05 00 00 00 00       incl   0x0
   9:   5d                      pop    %ebp
   a:   c3                      ret

The "push %ebp" and "mov %esp,%ebp" are included
in the low_pc/high_pc for g():

# readelf --debug-dump troep.o
 <2><3d>: Abbrev Number: 3 (DW_TAG_inlined_subroutine)
     DW_AT_abstract_origin: <4b>
     DW_AT_low_pc      : 0 0
     DW_AT_high_pc     : 0x9 9
 <1><4b>: Abbrev Number: 4 (DW_TAG_subprogram)
     DW_AT_external    : 1
     DW_AT_name        : g


The reason that this happens is because in
gcc/dwarf2out.c function gen_inlined_subroutine_die
the low_pc is generated using

      ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
                                   BLOCK_NUMBER (stmt));
      add_AT_lbl_id (subr_die, DW_AT_low_pc, label);

which translates in that it uses the string ".LBB2"
which is supposedly corresponding with the revelant 'stmt'
block.

The actual place where .LBB2 is emitted then determines
the real value of low_pc.

Looking at the assembly from the troep.s file we see:

_Z1fv:
.LFB4:
        .file 1 "troep.c"
        .loc 1 5 0
.LBB2:
.LBB3:
.LBB4:
        pushl   %ebp
.LCFI0:
        movl    %esp, %ebp
.LCFI1:
        .loc 1 3 0
        incl    a
.LBE4:
.LBE3:
.LBE2:
        .loc 1 7 0
        popl    %ebp
        ret


In other words, the .LBB2 label indeed includes
the 'pushl %ebp' and 'movl %esp, %ebp'.

I started to dump various intermitant RTL code
and found the first occurence of the 'push %ebp'
in the output of -dB :

(note 3 1 30 NOTE_INSN_FUNCTION_BEG)

;; Start of basic block 0, registers live: 6 [bp] 7 [sp] 16 [] 20 [frame]
(note 30 3 34 0 [bb 0] NOTE_INSN_BASIC_BLOCK)

(insn/f 34 30 35 0 troep.c:5 (set (mem:SI (pre_dec:SI (reg/f:SI 7 esp)) [0 S4 A8])
        (reg/f:SI 6 ebp)) 32 {*pushsi2} (nil)
    (nil))

(insn/f 35 34 36 0 troep.c:5 (set (reg/f:SI 6 ebp)
        (reg/f:SI 7 esp)) 38 {*movsi_1} (nil)
    (nil))


Note that already here the start of 'basic block 0'
is BEFORE these instructions.  This seems the only
basic block left - in many debug dumps I see no a clear
appearance of the three blocks that should be involved
according to the final assembly output.

The first dump (.01.rtl) these three blocks are still there:

;; Function void f()

(note 1 0 2 ("troep.c") 5)

(note 2 1 3 NOTE_INSN_DELETED)

(note 3 2 4 NOTE_INSN_FUNCTION_BEG)

(note 4 3 5 NOTE_INSN_DELETED)

(note 5 4 6 0x402a4c30 NOTE_INSN_BLOCK_BEG)

(note 6 5 7 NOTE_INSN_DELETED)

(note 7 6 8 NOTE_INSN_DELETED)

(note 8 7 9 NOTE_INSN_DELETED)

(note 9 8 10 ("troep.c") 6)

(note 10 9 11 NOTE_INSN_DELETED)

(note 11 10 12 NOTE_INSN_DELETED)

(note 12 11 13 ("troep.c") 3)

(note 13 12 14 0x402a4c80 NOTE_INSN_BLOCK_BEG)

(note 14 13 15 0x402a4ca8 NOTE_INSN_BLOCK_BEG)

(note 15 14 16 NOTE_INSN_DELETED)

(note 16 15 17 NOTE_INSN_DELETED)

(note 17 16 18 NOTE_INSN_DELETED)

(note 18 17 19 NOTE_INSN_DELETED)

(note 19 18 20 NOTE_INSN_DELETED)

(insn 20 19 21 (set (reg:SI 59)
        (mem/f:SI (symbol_ref:SI ("a") [flags 0x40] <var_decl 0x402c62f4 a>) [0
a+0 S4 A32])) -1 (nil)
    (nil))
[etc, this is the start of a = a + 1]

But here it is unclear to me where the "push %ebp"
should be.

However, because already the next dump in line
(troep.c.02.sibling) seems to have gotten rid of
two blocks:

;; Function void f()

(note 1 0 3 ("troep.c") 5)

(note 3 1 9 NOTE_INSN_FUNCTION_BEG)

(note 9 3 12 ("troep.c") 6)

(note 12 9 30 ("troep.c") 3)

(note 30 12 20 0 [bb 0] NOTE_INSN_BASIC_BLOCK)

(insn 20 30 21 0 troep.c:3 (set (reg:SI 59)
        (mem/f:SI (symbol_ref:SI ("a") [flags 0x40] <var_decl 0x402c62f4 a>) [0
a+0 S4 A32])) -1 (nil)
    (nil))
[etc]

and where this '(note 30 ...' no doubt is the
inner block and therefore the start of g(),
I would conclude that also the block in the
last dump is this block. (? or the dumps suck).


An important observation is that when we
add persistent code to f(), before g(), like this:

extern int a, b;

inline void g() { a = a + 1; }

void f() {
  b = b + 1;
  g();
}

Then the problem goes away! :

_Z1fv:
.LFB4:
        .file 1 "troep.c"
        .loc 1 5 0
.LBB2:
        pushl   %ebp
.LCFI0:
        movl    %esp, %ebp
.LCFI1:
        .loc 1 6 0
        incl    b
.LBB3:
.LBB4:
        .loc 1 3 0
        incl    a
.LBE4:
.LBE3:
.LBE2:
        .loc 1 8 0
        popl    %ebp
        ret
[...]
        .uleb128 0x3
        .long   0x4b
        .long   .LBB3
        .long   .LBE3

Now the block is .LBB3 till .LBE3
and as you see it does not include
too much anymore!

Therefore I am inclined to think that
the problem lays in the point where
the "push %ebp" and "movl %esp, %ebp"
are emitted; it seems that this is
'delayed' till there is other code
emitted (?) - but as a result is emitted
after the start of a block that was
marking the start of an inlined function!
This of course does not happen in the
case when there is code in f() between
its start and the call to g().

I am sorry I can't be of further help;
I am not famliar with the internals of
gcc at all.  But I hope that this will
help a little in finding the real problem.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]