Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2023-12

Wrong debug info when using clang backend

17 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Martin Frb

Not suer if the issue is within Fpc or clang...

Should this be reported against Fpc?

- Fedora 33
- Fpc 3.3.1  from Sept 26th
- make all  OPT=" " OPTNEW=" -Clv11.0 " FPCMAKEOPT=" -Clv11.0 " LLVM=1
- clang --version
  clang version 11.0.0 (Fedora 11.0.0-3.fc33)
  Target: x86_64-unknown-linux-gnu
  Thread model: posix
  InstalledDir: /usr/bin

Program at the end of this mail was compiled with -O-

Assembler for nested procedure Bar
/home/m/laz/projects/clang1/clang_nested_proc_1.lpr:8 begin 00000000004012D0 897424F8                 mov [rsp-$08],esi 00000000004012D4 895424F0                 mov [rsp-$10],edx /home/m/laz/projects/clang1/clang_nested_proc_1.lpr:9  a := 1; 00000000004012D8 C74424F801000000         mov [rsp-$08],$00000001 /home/m/laz/projects/clang1/clang_nested_proc_1.lpr:10  b := 1; 00000000004012E0 C74424F001000000         mov [rsp-$10],$00000001 /home/m/laz/projects/clang1/clang_nested_proc_1.lpr:11  c:=2; 00000000004012E8 C74424E402000000         mov [rsp-$1C],$00000002 /home/m/laz/projects/clang1/clang_nested_proc_1.lpr:12  d:=2; 00000000004012F0 C74424E002000000         mov [rsp-$20],$00000002 /home/m/laz/projects/clang1/clang_nested_proc_1.lpr:13  d:=2; 00000000004012F8 C74424E002000000         mov [rsp-$20],$00000002 /home/m/laz/projects/clang1/clang_nested_proc_1.lpr:14  end; 0000000000401300 C3                       ret

Variables d and c are encoded using a location list  <2><9c>: Abbrev Number: 3 (DW_TAG_variable)
    <9d>   DW_AT_location    : 0x24 (location list)     <a1>   DW_AT_name        : (indirect string, offset: 0xab): D     <a5>   DW_AT_decl_file   : 1
    <a6>   DW_AT_decl_line   : 7
    <a7>   DW_AT_type        : <0xdb>
 <2><ab>: Abbrev Number: 3 (DW_TAG_variable)
    <ac>   DW_AT_location    : 0x48 (location list)     <b0>   DW_AT_name        : (indirect string, offset: 0xad): C     <b4>   DW_AT_decl_file   : 1
    <b5>   DW_AT_decl_line   : 7
    <b6>   DW_AT_type        : <0xdb>

Contents of the .debug_loc section:
    Offset   Begin            End              Expression     00000000 00000000004012c3 00000000004012c5 (DW_OP_breg7 (rsp): 0)     00000014 <End of list>
    00000024 0000000000401300 0000000000401301 (DW_OP_breg7 (rsp): -32)     00000038 <End of list>
    00000048 0000000000401300 0000000000401301 (DW_OP_breg7 (rsp): -28)     0000005c <End of list>

Both location lists specify the variable is only available from 0000000000401300 0000000000401301
- That covers exactly the asm "ret" statement.
- Yet the variables are stored on the frame ([rsp-$1C] / [rsp-$20]) => so they are available before.

program clang_nested_proc_1;
{$mode objfpc}
procedure Foo;
   procedure Bar(a, b: integer);
   var
     c,d: integer;
   begin
     a := 1;
     b := 1;
     c:=2;
     d:=2;
     d:=2;
   end;
begin
   Bar(1,2);
end;
begin
   Foo;
end.

line info confirms the addresses from the asm.

Contents of the .debug_line section:
CU: clang_nested_proc_1.lpr:
File name                            Line number    Starting address    View    Stmt
clang_nested_proc_1.lpr                       15 0x4012b0               x clang_nested_proc_1.lpr                       16 0x4012b4               x clang_nested_proc_1.lpr                       17 0x4012c3               x clang_nested_proc_1.lpr                        8 0x4012d0               x clang_nested_proc_1.lpr                        8 0x4012d0       1       x clang_nested_proc_1.lpr                        9 0x4012d8               x clang_nested_proc_1.lpr                       10 0x4012e0               x clang_nested_proc_1.lpr                       11 0x4012e8               x clang_nested_proc_1.lpr                       12 0x4012f0               x clang_nested_proc_1.lpr                       13 0x4012f8               x clang_nested_proc_1.lpr                       14 0x401300               x clang_nested_proc_1.lpr                       19 0x401310               x clang_nested_proc_1.lpr                       19 0x401311               x clang_nested_proc_1.lpr                       20 0x401316               x clang_nested_proc_1.lpr                       21 0x40131b               x clang_nested_proc_1.lpr                       21 0x401322               x

Reply by email

Jonas Maebe
to Martin Frb
Martin Frb wrote
Not suer if the issue is within Fpc or clang... Should this be reported against Fpc?

FPC defines the variables' debug info at the start of the function and defines their lifetime as starting at the beginning of the function and continuing until the end. But LLVM is free to modify these if it notices these are too pessimistic

My guess is that even without optimisations, LLVM notices these variables' values are not really used later on and reduces the variables' live range.

Jonas

Reply by email

Martin Frb
to Jonas Maebe
Jonas Maebe wrote 13 lines
On 06/12/2023 17:37, Martin Frb via fpc-devel wrote: > Not suer if the issue is within Fpc or clang... > > Should this be reported against Fpc? FPC defines the variables' debug info at the start of the function and defines their lifetime as starting at the beginning of the function and continuing until the end. But LLVM is free to modify these if it notices these are too pessimistic My guess is that even without optimisations, LLVM notices these variables' values are not really used later on and reduces the variables' live range.

Strange, then clang has a serious issue.

I changed the code, so they are used. Still clang only defines the location list for the "end" keyword.
(I also removed the nested aspect)

Which in this case is
/home/m/laz/projects/clang1/clang_nested_proc_1.lpr:17  end; 000000000040143A 4883C448                 add rsp,$48 000000000040143E C3                       ret

And the location list covers those 2 statements.

Maybe it's the version of clang (if anyone has a newer one setup...)

Is there a way to see what fpc tells clang? (in human readable form)

program clang_nested_proc_1;
{$mode objfpc}
   procedure Bar(a, b: integer);
   var
     c,d: integer;
   begin
     c:=Random(99);
     d:=Random(99);
     writeln(a,b,c,d);
     d:=d+a;
     c:=c+b;
     writeln(a,b,c,d);
   end;
procedure Foo;
begin
   Bar(1,2);
end;
begin
   Foo;
end.

Reply by email

Martin Frb
to Martin Frb
Martin Frb wrote 16 lines
On 06/12/2023 21:05, Jonas Maebe via fpc-devel wrote: > On 06/12/2023 17:37, Martin Frb via fpc-devel wrote: >> Not suer if the issue is within Fpc or clang... >> >> Should this be reported against Fpc? > > FPC defines the variables' debug info at the start of the function > and defines their lifetime as starting at the beginning of the > function and continuing until the end. But LLVM is free to modify > these if it notices these are too pessimistic > > My guess is that even without optimisations, LLVM notices these > variables' values are not really used later on and reduces the > variables' live range. Strange, then clang has a serious issue.

But, yes it probably is clang.

If I have enough code, so clang does not optimize the entire function away in -O1, then clang writes info for some of the lines. Actually the variable is in a (or several?) registers. And clang misses some lines too.
But it covers some lines in the procedure.

With -O- it never is in a register...
Well it gets loaded sometimes, but it' always also on the stack. Seems like clang doesn't see it while it is on the stack.

Reply by email

Jonas Maebe
to Martin Frb
Martin Frb wrote 5 lines
If I have enough code, so clang does not optimize the entire function away in -O1, then clang writes info for some of the lines. Actually the variable is in a (or several?) registers. And clang misses some lines too. But it covers some lines in the procedure.

https://releases.llvm.org/11.0.0/docs/SourceLevelDebugging.html#format-common-intrinsics states that llvm.dbg.declare is identical to llvm.dbg.addr, except that it works badly in the context of optimisations, and that as a result it is deprecated and will be removed.

Because of this reason, FPC only uses llvm.dbg.addr. But clang still uses llvm.dbg.declare, and when I change FPC to use that one, the debug info for the variables in your test program is correct. So I'll change FPC to also use llvm.dbg.declare.

Jonas

Reply by email

Jonas Maebe
to Jonas Maebe
Jonas Maebe wrote 6 lines
https://releases.llvm.org/11.0.0/docs/SourceLevelDebugging.html#format-common-intrinsics states that llvm.dbg.declare is identical to llvm.dbg.addr, except that it works badly in the context of optimisations, and that as a result it is deprecated and will be removed. Because of this reason, FPC only uses llvm.dbg.addr. But clang still uses llvm.dbg.declare, and when I change FPC to use that one, the debug info for the variables in your test program is correct. So I'll change FPC to also use llvm.dbg.declare.

Done.

Jonas

Reply by email

Adriaan van Os
to Jonas Maebe
Jonas Maebe wrote 6 lines
> Because of this reason, FPC only uses llvm.dbg.addr. But clang still > uses llvm.dbg.declare, and when I change FPC to use that one, the > debug info for the variables in your test program is correct. So I'll > change FPC to also use llvm.dbg.declare. Done.

Just out of curiosity: Clang is by fpc used as a driver program, as it is asier to call it than tools like llc, opt and llvm-linker ?

Regards,

Adriaan van Os

Reply by email

Jonas Maebe
to Adriaan van Os
Adriaan van Os wrote 10 lines
Jonas Maebe via fpc-devel wrote: >> Because of this reason, FPC only uses llvm.dbg.addr. But clang still >> uses llvm.dbg.declare, and when I change FPC to use that one, the >> debug info for the variables in your test program is correct. So I'll >> change FPC to also use llvm.dbg.declare. > > Done. Just out of curiosity: Clang is by fpc used as a driver program, as it is asier to call it than tools like llc, opt and llvm-linker ?

It's indeed easier, and it also supports some preprocessing that llc doesn't (I don't remember what exactly llc didn't support, perhaps comments). It's also faster since you call one tool rather than 2 or 3.

Jonas

Reply by email

Adriaan van Os
to Jonas Maebe

Jonas,

It's indeed easier, and it also supports some preprocessing that llc doesn't (I don't remember what exactly llc didn't support, perhaps comments). It's also faster since you call one tool rather than 2 or 3.

Another question. Is there a way to put pragmas in fpc source code to be passed to CLang, eg. those mentioned here <https://llvm.org/docs/Vectorizers.html> ? That would gain a lot, at little cost.

Regards,

Adriaan van Os

Reply by email

Jonas Maebe
to Adriaan van Os
Adriaan van Os wrote
Another question. Is there a way to put pragmas in fpc source code to be passed to CLang, eg. those mentioned here <https://llvm.org/docs/Vectorizers.html> ? That would gain a lot, at little cost.

No. However, FPC command line parameters (e.g. -O, -Cp) and directives/modifiers (e.g. inline, const, constref, ...) get translated into LLVM directives wherever possible.

So if/when we would get FPC equivalents of such directives, I could translate those to LLVM IR as well.

Jonas

Reply by email

Adriaan van Os
to Jonas Maebe
Jonas Maebe wrote 13 lines
On 09/12/2023 10:07, Adriaan van Os via fpc-devel wrote: > Another question. Is there a way to put pragmas in fpc source code to > be passed to CLang, eg. those mentioned here > <https://llvm.org/docs/Vectorizers.html> ? That would gain a lot, at > little cost. No. However, FPC command line parameters (e.g. -O, -Cp) and directives/modifiers (e.g. inline, const, constref, ...) get translated into LLVM directives wherever possible. So if/when we would get FPC equivalents of such directives, I could translate those to LLVM IR as well.

Then I suggest the following (and I can prepare a patch to the code and docs if it were to be accepted)

$vectorize ON}
{$vectorize OFF}
{$vectorize WIDTH=VALUE}
{$vectorize TYPE=FIXED}
{$vectorize TYPE=SCALABLE}
{$vectorize PREDICATE=ON}
{$vectorize PREDICATE=OFF}

For a description, see <https://llvm.org/docs/Vectorizers.html#command-line-flags>. And

{$unroll ON}
{$unroll OFF}
{$unroll FULL}
{$unroll COUNT=VALUE}

For a description, see
<https://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>.

LLVM equivalents of these compiler switches will be passed (by Jonas) to Clang as IR methadata.

Also, I suggest

-Cl<xxx> Pass xxx to Clang as pragma on the command-line.

Regards,

Adriaan van Os

Reply by email

Jonas Maebe
to Adriaan van Os
Adriaan van Os wrote 25 lines
Jonas Maebe via fpc-devel wrote: > So if/when we would get FPC equivalents of such directives, I could > translate those to LLVM IR as well. Then I suggest the following (and I can prepare a patch to the code and docs if it were to be accepted) $vectorize ON} {$vectorize OFF} {$vectorize WIDTH=VALUE} {$vectorize TYPE=FIXED} {$vectorize TYPE=SCALABLE} {$vectorize PREDICATE=ON} {$vectorize PREDICATE=OFF} For a description, see <https://llvm.org/docs/Vectorizers.html#command-line-flags>. And {$unroll ON} {$unroll OFF} {$unroll FULL} {$unroll COUNT=VALUE} For a description, see <https://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>.

I'd rather not introduce directives that are specific to clang, and especially none only apply to the next loop. We don't have a single directive yet that works like this.

Maybe attributes would be more appropriate, although I don't think Delphi (or FPC) currently supports attributes for statements.

Also, I suggest -Cl<xxx>   Pass xxx to Clang as pragma on the command-line.

You can already pass command line options to clang using the generic -ao command line parameter.

Jonas

Reply by email

Michael Van Canneyt
to Jonas Maebe
Jonas Maebe wrote 34 lines
On 09/12/2023 13:35, Adriaan van Os via fpc-devel wrote: > Jonas Maebe via fpc-devel wrote: >> So if/when we would get FPC equivalents of such directives, I could >> translate those to LLVM IR as well. > > Then I suggest the following (and I can prepare a patch to the code and > docs if it were to be accepted) > > $vectorize ON} > {$vectorize OFF} > {$vectorize WIDTH=VALUE} > {$vectorize TYPE=FIXED} > {$vectorize TYPE=SCALABLE} > {$vectorize PREDICATE=ON} > {$vectorize PREDICATE=OFF} > > For a description, see > <https://llvm.org/docs/Vectorizers.html#command-line-flags>. And > > {$unroll ON} > {$unroll OFF} > {$unroll FULL} > {$unroll COUNT=VALUE} > > For a description, see > <https://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>. I'd rather not introduce directives that are specific to clang, and especially none only apply to the next loop. We don't have a single directive yet that works like this. Maybe attributes would be more appropriate, although I don't think Delphi (or FPC) currently supports attributes for statements.

Please don't:
Attributes are designed for runtime consumption. I'm heavily opposed to start using them to influence the code generation. The compiler should remain ignorant of their meaning and use.

Maybe a single {$PRAGMA XYZ} directive can be introduced to control this kind of stuff, with a fixed list of XYZ.
Backends can intepret the XYZ pragmas as they see fit.

Michael.

Reply by email

Adriaan van Os
to Michael Van Canneyt
Michael Van Canneyt wrote
Maybe a single {$PRAGMA XYZ} directive can be introduced to control this kind of stuff, with a fixed list of XYZ. Backends can intepret the XYZ pragmas as they see fit.

Yes, a {$pragma} directive is fine for me. It seems absurd to ignore code improvement capabilities that we get for free with the llvm back-end.

Regards,

Adriaan van Os

{$pragma vectorize ON}
{$pragma vectorize OFF}
{$pragma vectorize WIDTH=n}
{$pragma vectorize TYPE=FIXED}
{$pragma vectorize TYPE=SCALABLE}
{$pragma vectorize PREDICATE=ON}
{$pragma vectorize PREDICATE=OFF}

For a description, see <https://llvm.org/docs/Vectorizers.html#command-line-flags>. And

{$pragma unroll ON}
{$pragma unroll OFF}
{$pragma unroll FULL}
{$pragma unroll COUNT=n}

For a description, see <https://llvm.org/docs/Vectorizers.html#command-line-flags>. And

Reply by email

Adriaan van Os
to Jonas Maebe: I'd rather not introduce directives that are specific to clang, and especially none only…
Jonas Maebe wrote
I'd rather not introduce directives that are specific to clang, and especially none only apply to the next loop. We don't have a single directive yet that works like this.

The latter is a good point and that's why I would suggest to make their Pascal equivalents valid, not for the next for-loop, but until-otherwise. Then, a loop can be explicitely targeted with {$push ...} and {$pop}.

Regards,

Adriaan van Os

Reply by email

Jonas Maebe
to Adriaan van Os
Adriaan van Os wrote 10 lines
Jonas Maebe via fpc-devel wrote: > I'd rather not introduce directives that are specific to clang, and > especially none only apply to the next loop. We don't have a single > directive yet that works like this. The latter is a good point and that's why I would suggest to make their Pascal equivalents valid, not for the next for-loop, but until-otherwise. Then, a loop can be explicitely targeted with {$push ...} and {$pop}.

I don't think that makes much sense. Most of the time, the loops in a single source file will be quite different and need different explicit unroll instructions, if any. There is a reason why they only apply to the next loop in clang.

It's just that directives don't work very well in that context, and hence my initial suggestion to use attributes instead. I'm by no means married to that proposal, but I don't think directives are a good approach either.

Jonas

Reply by email

Adriaan van Os
to Jonas Maebe
Jonas Maebe wrote 21 lines
On 14/12/2023 08:41, Adriaan van Os via fpc-devel wrote: > Jonas Maebe via fpc-devel wrote: > >> I'd rather not introduce directives that are specific to clang, and >> especially none only apply to the next loop. We don't have a single >> directive yet that works like this. > > The latter is a good point and that's why I would suggest to make > their Pascal equivalents valid, not for the next for-loop, but > until-otherwise. Then, a loop can be explicitely targeted with {$push > ...} and {$pop}. I don't think that makes much sense. Most of the time, the loops in a single source file will be quite different and need different explicit unroll instructions, if any. There is a reason why they only apply to the next loop in clang. It's just that directives don't work very well in that context, and hence my initial suggestion to use attributes instead. I'm by no means married to that proposal, but I don't think directives are a good approach either.

GNU Pascal has attributes <https://www.gnu-pascal.de/gpc/attribute.html>. They are fine for me.

Regards,

Adriaan van Os

Reply by email