Skip to content

Commit

Permalink
[DebugInfo] Add a specification attribute to LLVM DebugInfo (#115362)
Browse files Browse the repository at this point in the history
Add a specification attribute to LLVM DebugInfo, which is analogous
to DWARF's DW_AT_specification. According to the DWARF spec:
"A debugging information entry that represents a declaration that
completes another (earlier) non-defining declaration may have a
DW_AT_specification attribute whose value is a reference to the
debugging information entry representing the non-defining declaration."

This patch allows types to be specifications of other types. This is
used by Swift to represent generic types. For example, given this Swift
program:

```
struct MyStruct<T> {
    let t: T
}

let variable = MyStruct<Int>(t: 43)
```

The Swift compiler emits (roughly) an unsubtituted type for MyStruct<T>:
```
DW_TAG_structure_type
    DW_AT_name	("MyStruct")
    // "$s1w8MyStructVyxGD" is a Swift mangled name roughly equivalent to 
    // MyStruct<T>
    DW_AT_linkage_name	("$s1w8MyStructVyxGD")
    // other attributes here
```
And a specification for MyStruct<Int>:
```
DW_TAG_structure_type
    DW_AT_specification	(<link to "MyStruct">)
    // "$s1w8MyStructVySiGD" is a Swift mangled name equivalent to
    // MyStruct<Int>
    DW_AT_linkage_name	("$s1w8MyStructVySiGD")
    DW_AT_byte_size	(0x08)
    // other attributes here
```
  • Loading branch information
augusto2112 authored Nov 13, 2024
1 parent 2bd6af8 commit 67fb268
Show file tree
Hide file tree
Showing 13 changed files with 159 additions and 91 deletions.
4 changes: 3 additions & 1 deletion llvm/include/llvm/IR/DIBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,8 @@ namespace llvm {
/// \param Elements Struct elements.
/// \param RunTimeLang Optional parameter, Objective-C runtime version.
/// \param UniqueIdentifier A unique identifier for the struct.
/// \param Specification The type that this type completes. This is used by
/// Swift to represent generic types.
/// \param NumExtraInhabitants The number of extra inhabitants of the type.
/// An extra inhabitant is a bit pattern that does not represent a valid
/// value for instances of a given type. This is used by the Swift language.
Expand All @@ -496,7 +498,7 @@ namespace llvm {
uint64_t SizeInBits, uint32_t AlignInBits, DINode::DIFlags Flags,
DIType *DerivedFrom, DINodeArray Elements, unsigned RunTimeLang = 0,
DIType *VTableHolder = nullptr, StringRef UniqueIdentifier = "",
uint32_t NumExtraInhabitants = 0);
DIType *Specification = nullptr, uint32_t NumExtraInhabitants = 0);

/// Create debugging information entry for an union.
/// \param Scope Scope in which this union is defined.
Expand Down
52 changes: 31 additions & 21 deletions llvm/include/llvm/IR/DebugInfoMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -1201,7 +1201,7 @@ class DICompositeType : public DIType {
static DICompositeType *
getImpl(LLVMContext &Context, unsigned Tag, StringRef Name, Metadata *File,
unsigned Line, DIScope *Scope, DIType *BaseType, uint64_t SizeInBits,
uint32_t AlignInBits, uint64_t OffsetInBits,
uint32_t AlignInBits, uint64_t OffsetInBits, DIType *Specification,
uint32_t NumExtraInhabitants, DIFlags Flags, DINodeArray Elements,
unsigned RuntimeLang, DIType *VTableHolder,
DITemplateParameterArray TemplateParams, StringRef Identifier,
Expand All @@ -1215,7 +1215,7 @@ class DICompositeType : public DIType {
TemplateParams.get(),
getCanonicalMDString(Context, Identifier), Discriminator,
DataLocation, Associated, Allocated, Rank, Annotations.get(),
NumExtraInhabitants, Storage, ShouldCreate);
Specification, NumExtraInhabitants, Storage, ShouldCreate);
}
static DICompositeType *
getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File,
Expand All @@ -1225,8 +1225,9 @@ class DICompositeType : public DIType {
Metadata *VTableHolder, Metadata *TemplateParams,
MDString *Identifier, Metadata *Discriminator, Metadata *DataLocation,
Metadata *Associated, Metadata *Allocated, Metadata *Rank,
Metadata *Annotations, uint32_t NumExtraInhabitants,
StorageType Storage, bool ShouldCreate = true);
Metadata *Annotations, Metadata *Specification,
uint32_t NumExtraInhabitants, StorageType Storage,
bool ShouldCreate = true);

TempDICompositeType cloneImpl() const {
return getTemporary(
Expand All @@ -1235,7 +1236,8 @@ class DICompositeType : public DIType {
getFlags(), getElements(), getRuntimeLang(), getVTableHolder(),
getTemplateParams(), getIdentifier(), getDiscriminator(),
getRawDataLocation(), getRawAssociated(), getRawAllocated(),
getRawRank(), getAnnotations(), getNumExtraInhabitants());
getRawRank(), getAnnotations(), getSpecification(),
getNumExtraInhabitants());
}

public:
Expand All @@ -1249,11 +1251,12 @@ class DICompositeType : public DIType {
StringRef Identifier = "", DIDerivedType *Discriminator = nullptr,
Metadata *DataLocation = nullptr, Metadata *Associated = nullptr,
Metadata *Allocated = nullptr, Metadata *Rank = nullptr,
DINodeArray Annotations = nullptr, uint32_t NumExtraInhabitants = 0),
DINodeArray Annotations = nullptr, DIType *Specification = nullptr,
uint32_t NumExtraInhabitants = 0),
(Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits,
OffsetInBits, NumExtraInhabitants, Flags, Elements, RuntimeLang,
VTableHolder, TemplateParams, Identifier, Discriminator, DataLocation,
Associated, Allocated, Rank, Annotations))
OffsetInBits, Specification, NumExtraInhabitants, Flags, Elements,
RuntimeLang, VTableHolder, TemplateParams, Identifier, Discriminator,
DataLocation, Associated, Allocated, Rank, Annotations))
DEFINE_MDNODE_GET(
DICompositeType,
(unsigned Tag, MDString *Name, Metadata *File, unsigned Line,
Expand All @@ -1264,11 +1267,11 @@ class DICompositeType : public DIType {
Metadata *Discriminator = nullptr, Metadata *DataLocation = nullptr,
Metadata *Associated = nullptr, Metadata *Allocated = nullptr,
Metadata *Rank = nullptr, Metadata *Annotations = nullptr,
uint32_t NumExtraInhabitants = 0),
Metadata *Specification = nullptr, uint32_t NumExtraInhabitants = 0),
(Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits,
OffsetInBits, Flags, Elements, RuntimeLang, VTableHolder, TemplateParams,
Identifier, Discriminator, DataLocation, Associated, Allocated, Rank,
Annotations, NumExtraInhabitants))
Annotations, Specification, NumExtraInhabitants))

TempDICompositeType clone() const { return cloneImpl(); }

Expand All @@ -1283,8 +1286,9 @@ class DICompositeType : public DIType {
getODRType(LLVMContext &Context, MDString &Identifier, unsigned Tag,
MDString *Name, Metadata *File, unsigned Line, Metadata *Scope,
Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits,
uint64_t OffsetInBits, uint32_t NumExtraInhabitants, DIFlags Flags,
Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder,
uint64_t OffsetInBits, Metadata *Specification,
uint32_t NumExtraInhabitants, DIFlags Flags, Metadata *Elements,
unsigned RuntimeLang, Metadata *VTableHolder,
Metadata *TemplateParams, Metadata *Discriminator,
Metadata *DataLocation, Metadata *Associated, Metadata *Allocated,
Metadata *Rank, Metadata *Annotations);
Expand All @@ -1300,14 +1304,16 @@ class DICompositeType : public DIType {
///
/// If not \a LLVMContext::isODRUniquingDebugTypes(), this function returns
/// nullptr.
static DICompositeType *buildODRType(
LLVMContext &Context, MDString &Identifier, unsigned Tag, MDString *Name,
Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType,
uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits,
uint32_t NumExtraInhabitants, DIFlags Flags, Metadata *Elements,
unsigned RuntimeLang, Metadata *VTableHolder, Metadata *TemplateParams,
Metadata *Discriminator, Metadata *DataLocation, Metadata *Associated,
Metadata *Allocated, Metadata *Rank, Metadata *Annotations);
static DICompositeType *
buildODRType(LLVMContext &Context, MDString &Identifier, unsigned Tag,
MDString *Name, Metadata *File, unsigned Line, Metadata *Scope,
Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits,
uint64_t OffsetInBits, Metadata *Specification,
uint32_t NumExtraInhabitants, DIFlags Flags, Metadata *Elements,
unsigned RuntimeLang, Metadata *VTableHolder,
Metadata *TemplateParams, Metadata *Discriminator,
Metadata *DataLocation, Metadata *Associated,
Metadata *Allocated, Metadata *Rank, Metadata *Annotations);

DIType *getBaseType() const { return cast_or_null<DIType>(getRawBaseType()); }
DINodeArray getElements() const {
Expand Down Expand Up @@ -1367,6 +1373,10 @@ class DICompositeType : public DIType {
return cast_or_null<MDTuple>(getRawAnnotations());
}

Metadata *getRawSpecification() const { return getOperand(14); }
DIType *getSpecification() const {
return cast_or_null<DIType>(getRawSpecification());
}
/// Replace operands.
///
/// If this \a isUniqued() and not \a isResolved(), on a uniquing collision
Expand Down
13 changes: 7 additions & 6 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5437,7 +5437,8 @@ bool LLParser::parseDICompositeType(MDNode *&Result, bool IsDistinct) {
OPTIONAL(allocated, MDField, ); \
OPTIONAL(rank, MDSignedOrMDField, ); \
OPTIONAL(annotations, MDField, ); \
OPTIONAL(num_extra_inhabitants, MDUnsignedField, (0, UINT32_MAX));
OPTIONAL(num_extra_inhabitants, MDUnsignedField, (0, UINT32_MAX)); \
OPTIONAL(specification, MDField, );
PARSE_MD_FIELDS();
#undef VISIT_MD_FIELDS

Expand All @@ -5453,10 +5454,10 @@ bool LLParser::parseDICompositeType(MDNode *&Result, bool IsDistinct) {
if (auto *CT = DICompositeType::buildODRType(
Context, *identifier.Val, tag.Val, name.Val, file.Val, line.Val,
scope.Val, baseType.Val, size.Val, align.Val, offset.Val,
num_extra_inhabitants.Val, flags.Val, elements.Val, runtimeLang.Val,
vtableHolder.Val, templateParams.Val, discriminator.Val,
dataLocation.Val, associated.Val, allocated.Val, Rank,
annotations.Val)) {
specification.Val, num_extra_inhabitants.Val, flags.Val,
elements.Val, runtimeLang.Val, vtableHolder.Val, templateParams.Val,
discriminator.Val, dataLocation.Val, associated.Val, allocated.Val,
Rank, annotations.Val)) {
Result = CT;
return false;
}
Expand All @@ -5469,7 +5470,7 @@ bool LLParser::parseDICompositeType(MDNode *&Result, bool IsDistinct) {
size.Val, align.Val, offset.Val, flags.Val, elements.Val,
runtimeLang.Val, vtableHolder.Val, templateParams.Val, identifier.Val,
discriminator.Val, dataLocation.Val, associated.Val, allocated.Val, Rank,
annotations.Val, num_extra_inhabitants.Val));
annotations.Val, specification.Val, num_extra_inhabitants.Val));
return false;
}

Expand Down
16 changes: 11 additions & 5 deletions llvm/lib/Bitcode/Reader/MetadataLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1600,7 +1600,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
break;
}
case bitc::METADATA_COMPOSITE_TYPE: {
if (Record.size() < 16 || Record.size() > 23)
if (Record.size() < 16 || Record.size() > 24)
return error("Invalid record");

// If we have a UUID and this is not a forward declaration, lookup the
Expand Down Expand Up @@ -1630,6 +1630,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
Metadata *Allocated = nullptr;
Metadata *Rank = nullptr;
Metadata *Annotations = nullptr;
Metadata *Specification = nullptr;
auto *Identifier = getMDString(Record[15]);
// If this module is being parsed so that it can be ThinLTO imported
// into another module, composite types only need to be imported as
Expand Down Expand Up @@ -1678,14 +1679,18 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
if (Record.size() > 21) {
Annotations = getMDOrNull(Record[21]);
}
if (Record.size() > 23) {
Specification = getMDOrNull(Record[23]);
}
}
DICompositeType *CT = nullptr;
if (Identifier)
CT = DICompositeType::buildODRType(
Context, *Identifier, Tag, Name, File, Line, Scope, BaseType,
SizeInBits, AlignInBits, OffsetInBits, NumExtraInhabitants, Flags,
Elements, RuntimeLang, VTableHolder, TemplateParams, Discriminator,
DataLocation, Associated, Allocated, Rank, Annotations);
SizeInBits, AlignInBits, OffsetInBits, Specification,
NumExtraInhabitants, Flags, Elements, RuntimeLang, VTableHolder,
TemplateParams, Discriminator, DataLocation, Associated, Allocated,
Rank, Annotations);

// Create a node if we didn't get a lazy ODR type.
if (!CT)
Expand All @@ -1694,7 +1699,8 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
SizeInBits, AlignInBits, OffsetInBits, Flags,
Elements, RuntimeLang, VTableHolder, TemplateParams,
Identifier, Discriminator, DataLocation, Associated,
Allocated, Rank, Annotations, NumExtraInhabitants));
Allocated, Rank, Annotations, Specification,
NumExtraInhabitants));
if (!IsNotUsedInTypeRef && Identifier)
MetadataList.addTypeRef(*Identifier, *cast<DICompositeType>(CT));

Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1947,6 +1947,7 @@ void ModuleBitcodeWriter::writeDICompositeType(
Record.push_back(VE.getMetadataOrNullID(N->getRawRank()));
Record.push_back(VE.getMetadataOrNullID(N->getAnnotations().get()));
Record.push_back(N->getNumExtraInhabitants());
Record.push_back(VE.getMetadataOrNullID(N->getRawSpecification()));

Stream.EmitRecord(bitc::METADATA_COMPOSITE_TYPE, Record, Abbrev);
Record.clear();
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,11 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
addUInt(Buffer, dwarf::DW_AT_calling_convention, dwarf::DW_FORM_data1,
CC);
}

if (auto *SpecifiedFrom = CTy->getSpecification())
addDIEEntry(Buffer, dwarf::DW_AT_specification,
*getOrCreateContextDIE(SpecifiedFrom));

break;
}
default:
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2235,6 +2235,8 @@ static void writeDICompositeType(raw_ostream &Out, const DICompositeType *N,
else
Printer.printMetadata("rank", N->getRawRank(), /*ShouldSkipNull */ true);
Printer.printMetadata("annotations", N->getRawAnnotations());
if (auto *Specification = N->getRawSpecification())
Printer.printMetadata("specification", Specification);
Out << ")";
}

Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/IR/DIBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,13 +521,13 @@ DICompositeType *DIBuilder::createStructType(
DIScope *Context, StringRef Name, DIFile *File, unsigned LineNumber,
uint64_t SizeInBits, uint32_t AlignInBits, DINode::DIFlags Flags,
DIType *DerivedFrom, DINodeArray Elements, unsigned RunTimeLang,
DIType *VTableHolder, StringRef UniqueIdentifier,
DIType *VTableHolder, StringRef UniqueIdentifier, DIType *Specification,
uint32_t NumExtraInhabitants) {
auto *R = DICompositeType::get(
VMContext, dwarf::DW_TAG_structure_type, Name, File, LineNumber,
getNonCompileUnitScope(Context), DerivedFrom, SizeInBits, AlignInBits, 0,
Flags, Elements, RunTimeLang, VTableHolder, nullptr, UniqueIdentifier,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, Specification,
NumExtraInhabitants);
trackIfUnresolved(R);
return R;
Expand Down
43 changes: 22 additions & 21 deletions llvm/lib/IR/DebugInfoMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,21 +770,21 @@ DICompositeType *DICompositeType::getImpl(
Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder,
Metadata *TemplateParams, MDString *Identifier, Metadata *Discriminator,
Metadata *DataLocation, Metadata *Associated, Metadata *Allocated,
Metadata *Rank, Metadata *Annotations, uint32_t NumExtraInhabitants,
StorageType Storage, bool ShouldCreate) {
Metadata *Rank, Metadata *Annotations, Metadata *Specification,
uint32_t NumExtraInhabitants, StorageType Storage, bool ShouldCreate) {
assert(isCanonical(Name) && "Expected canonical MDString");

// Keep this in sync with buildODRType.
DEFINE_GETIMPL_LOOKUP(DICompositeType,
(Tag, Name, File, Line, Scope, BaseType, SizeInBits,
AlignInBits, OffsetInBits, Flags, Elements,
RuntimeLang, VTableHolder, TemplateParams, Identifier,
Discriminator, DataLocation, Associated, Allocated,
Rank, Annotations, NumExtraInhabitants));
DEFINE_GETIMPL_LOOKUP(
DICompositeType,
(Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits,
OffsetInBits, Flags, Elements, RuntimeLang, VTableHolder, TemplateParams,
Identifier, Discriminator, DataLocation, Associated, Allocated, Rank,
Annotations, Specification, NumExtraInhabitants));
Metadata *Ops[] = {File, Scope, Name, BaseType,
Elements, VTableHolder, TemplateParams, Identifier,
Discriminator, DataLocation, Associated, Allocated,
Rank, Annotations};
Rank, Annotations, Specification};
DEFINE_GETIMPL_STORE(DICompositeType,
(Tag, Line, RuntimeLang, SizeInBits, AlignInBits,
OffsetInBits, NumExtraInhabitants, Flags),
Expand All @@ -795,10 +795,11 @@ DICompositeType *DICompositeType::buildODRType(
LLVMContext &Context, MDString &Identifier, unsigned Tag, MDString *Name,
Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType,
uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits,
uint32_t NumExtraInhabitants, DIFlags Flags, Metadata *Elements,
unsigned RuntimeLang, Metadata *VTableHolder, Metadata *TemplateParams,
Metadata *Discriminator, Metadata *DataLocation, Metadata *Associated,
Metadata *Allocated, Metadata *Rank, Metadata *Annotations) {
Metadata *Specification, uint32_t NumExtraInhabitants, DIFlags Flags,
Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder,
Metadata *TemplateParams, Metadata *Discriminator, Metadata *DataLocation,
Metadata *Associated, Metadata *Allocated, Metadata *Rank,
Metadata *Annotations) {
assert(!Identifier.getString().empty() && "Expected valid identifier");
if (!Context.isODRUniquingDebugTypes())
return nullptr;
Expand All @@ -809,8 +810,7 @@ DICompositeType *DICompositeType::buildODRType(
AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang,
VTableHolder, TemplateParams, &Identifier, Discriminator,
DataLocation, Associated, Allocated, Rank, Annotations,
NumExtraInhabitants);

Specification, NumExtraInhabitants);
if (CT->getTag() != Tag)
return nullptr;

Expand All @@ -825,7 +825,7 @@ DICompositeType *DICompositeType::buildODRType(
Metadata *Ops[] = {File, Scope, Name, BaseType,
Elements, VTableHolder, TemplateParams, &Identifier,
Discriminator, DataLocation, Associated, Allocated,
Rank, Annotations};
Rank, Annotations, Specification};
assert((std::end(Ops) - std::begin(Ops)) == (int)CT->getNumOperands() &&
"Mismatched number of operands");
for (unsigned I = 0, E = CT->getNumOperands(); I != E; ++I)
Expand All @@ -838,10 +838,11 @@ DICompositeType *DICompositeType::getODRType(
LLVMContext &Context, MDString &Identifier, unsigned Tag, MDString *Name,
Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType,
uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits,
uint32_t NumExtraInhabitants, DIFlags Flags, Metadata *Elements,
unsigned RuntimeLang, Metadata *VTableHolder, Metadata *TemplateParams,
Metadata *Discriminator, Metadata *DataLocation, Metadata *Associated,
Metadata *Allocated, Metadata *Rank, Metadata *Annotations) {
Metadata *Specification, uint32_t NumExtraInhabitants, DIFlags Flags,
Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder,
Metadata *TemplateParams, Metadata *Discriminator, Metadata *DataLocation,
Metadata *Associated, Metadata *Allocated, Metadata *Rank,
Metadata *Annotations) {
assert(!Identifier.getString().empty() && "Expected valid identifier");
if (!Context.isODRUniquingDebugTypes())
return nullptr;
Expand All @@ -851,7 +852,7 @@ DICompositeType *DICompositeType::getODRType(
Context, Tag, Name, File, Line, Scope, BaseType, SizeInBits,
AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang, VTableHolder,
TemplateParams, &Identifier, Discriminator, DataLocation, Associated,
Allocated, Rank, Annotations, NumExtraInhabitants);
Allocated, Rank, Annotations, Specification, NumExtraInhabitants);
} else {
if (CT->getTag() != Tag)
return nullptr;
Expand Down
Loading

0 comments on commit 67fb268

Please sign in to comment.