Hi All,
DIFactory interface, part of DebugInfo.h, is used to emit LLVM IR constructs to encode debugging information. We are replacing this interface with new simple interface, DIBuilder.
Here is one example that demonstrates differences between two interfaces. To create debug information entries to encode volatile type one would use following call in a language front end,
CreateDerivedType(DW_TAG_volatile_type, Context, StringRef(), File,
0 /line no/, type_size_in_bits, type_align_in_bits,
0 /* offset /, 0 / flags */, OriginalType);
using DIFactory interface. Now, DIBuilder allows you to do the same using following call.
createQualifiedType(DW_TAG_volatile_type, OriginalType);
DIBuilder interface was introduced in Nov/Dec last year. Now, clang has fully adopted this new interface. So we are going to remove DIFactory from llvm sources soon. Our plan is to move DIFactory interface in dragonegg (and llvm-gcc) for now until the front-ends adopt DIBuilder.
If you have any concerns about this plan, please speak up now.
Hi All,
DIFactory interface, part of DebugInfo.h, is used to emit LLVM IR constructs
to encode debugging information. We are replacing this interface with new
simple interface, DIBuilder.
Here is one example that demonstrates differences between two interfaces. To
create debug information entries to encode volatile type one would use
following call in a language front end,
CreateDerivedType(DW_TAG_volatile_type, Context, StringRef(), File,
0 /*line no*/, type_size_in_bits,
type_align_in_bits,
0 /* offset */, 0 /* flags */, OriginalType);
using DIFactory interface. Now, DIBuilder allows you to do the same using
following call.
createQualifiedType(DW_TAG_volatile_type, OriginalType);
DIBuilder interface was introduced in Nov/Dec last year. Now, clang has
fully adopted this new interface. So we are going to remove DIFactory from
llvm sources soon. Our plan is to move DIFactory interface in dragonegg (and
llvm-gcc) for now until the front-ends adopt DIBuilder.
If you have any concerns about this plan, please speak up now.
Assuming it has no impact on the actual dwarf tags, smaller code is better!
-jason
It does make me wonder how you are supposed to represent types which cannot
be properly represented by LLVM types, for example structs with fields at
variable offsets from the start and/or of variable size; or structs with
fields that may or may not be present depending on the value of other fields.
Such types occur in Ada for example.
Ciao, Duncan.
It simplified a bit type construction but the overall code did not
reduce that much. It's still very similar to the previous style but
had a few differences in the IR output.
We had LIT tests that checked the IR and Dwarf and GDB execution and
they failed in all levels more or less around December. This week I
had time to finally refactor it and everything went back to normal
(with lots of changes in the IR/Dwarf checks).
To be honest, debugging metadata in IR is not trivial. You need to
understand what's being built and how it gets used later, and for that
you have to dig deep in the code, a problem that normal IR doesn't
have. Not to mention the lack of validation on the parameters,
metadata accepts anything you put in and the MDNode* behave almost
like void*.
But I have to say that the new DIBuilder is much closer to the
metadata generated than the previous DIFactory, so maybe that'll get
there in time...
Great work Devang! It's really getting a lot nicer to build debug information.
cheers,
--renato
The metadata constructs used to encode debugging information do not use (or refer) LLVM types directly. Here is the interface to emit debug info for a member.
/// createMemberType - Create debugging information entry for a member.
/// @param Name Member name.
/// @param File File where this member is defined.
/// @param LineNo Line number.
/// @param SizeInBits Member size.
/// @param AlignInBits Member alignment.
/// @param OffsetInBits Member offset.
/// @param Flags Flags to encode member attribute, e.g. private
/// @param Ty Parent type.
DIType createMemberType(StringRef Name, DIFile File,
unsigned LineNo, uint64_t SizeInBits,
uint64_t AlignInBits, uint64_t OffsetInBits,
unsigned Flags, DIType Ty);
Of course, the FE needs to know the offset, size, alignment etc... for each field as per source language. The Parent type here is also debug info entry for the enclosing structure/class. Regarding variable size fields, I am not sure how they are encoded in DWARF.
The old interface expected FEs to keep track of everything, where as new interface tries to encapsulate as much info as possible. This should help cleanup FE code responsible to generate debugging information. I made a first pass in clang and simplified code little bit. There is more room for improvement now. If you look at CGDebugInfo.cpp in clang, you'll see "Unit" variable/argument used all over the place. IMO, majority of these could be eliminated thanks to DIBuilder.
Another significant improvement is that it does not expose internal data structures (e.g. DerivedType, CompositeType... ) to FEs. The front-end should not be forced to learn about them and they do not directly represent any DWARF concept anyway. It is just an approach used my predecessor to communicate debug info from FE to llvm code generator.
Now, with the encapsulation provided by DIBuilder, we have more freedom.
Hi Devang,
It does make me wonder how you are supposed to represent types which cannot
be properly represented by LLVM types, for example structs with fields at
variable offsets from the start and/or of variable size; or structs with
fields that may or may not be present depending on the value of other fields.
Such types occur in Ada for example.
The metadata constructs used to encode debugging information do not use (or refer) LLVM types directly. Here is the interface to emit debug info for a member.
thanks for the explanation.
/// createMemberType - Create debugging information entry for a member.
/// @param Name Member name.
/// @param File File where this member is defined.
/// @param LineNo Line number.
/// @param SizeInBits Member size.
For Ada this needs to be a Value* since it is dynamic. But presumably this
interface is a direct mapping to the Dwarf specification, i.e. Dwarf itself
has no way of encoding a variable size here?
/// @param AlignInBits Member alignment.
/// @param OffsetInBits Member offset.
This is likewise dynamic in general.
/// @param Flags Flags to encode member attribute, e.g. private
/// @param Ty Parent type.
DIType createMemberType(StringRef Name, DIFile File,
unsigned LineNo, uint64_t SizeInBits,
uint64_t AlignInBits, uint64_t OffsetInBits,
unsigned Flags, DIType Ty);
Of course, the FE needs to know the offset, size, alignment etc... for each field as per source language. The Parent type here is also debug info entry for the enclosing structure/class. Regarding variable size fields, I am not sure how they are encoded in DWARF.
GCC outputs some language specific Dwarf tags for Ada, perhaps to handle these
kinds of mad types.
Ciao, Duncan.
The old interface expected FEs to keep track of everything, where as new interface tries to encapsulate as much info as possible. This should help cleanup FE code responsible to generate debugging information. I made a first pass in clang and simplified code little bit. There is more room for improvement now. If you look at CGDebugInfo.cpp in clang, you'll see "Unit" variable/argument used all over the place. IMO, majority of these could be eliminated thanks to DIBuilder.
Yes, I got rid of that, too.
Another significant improvement is that it does not expose internal data structures (e.g. DerivedType, CompositeType... ) to FEs. The front-end should not be forced to learn about them and they do not directly represent any DWARF concept anyway. It is just an approach used my predecessor to communicate debug info from FE to llvm code generator.
Indeed, I liked the way it's hidden in DIBuilder. Also the way
typerefs are dealt with, too, is very good.
Would be good to split CreateLocalVariable into CreateArgValue and
CreateAutoVariable. Also would be good to have a simpler array types
creation (CreateArrayType(size, align, ty, num_elms)).
cheers,
--renato
I was going to say that Dwarf is quite flexible, but if the debugger
understand it or not is another matter.
But if you say that GCC has it working for Ada, then probably GDB
already understands it.
Maybe by repeating what GCC does for Ada, we might get a more flexible
API to create variable types (I would create a whole new class of
functions for that)...
--renato
That'd be straight forward to do. Patches welcome!
It would be very easy to add createAdaMemberType(...). After all it does is create a MDNode using the arguments. Once you have the MDNode, it will survive all the way through all LLVM phases until the end where DWARF entries are emitted. So only thing you need is understanding of how to emit it in DWARF in such cases.