Skip to content

Commit

Permalink
Add DWARF for discriminated unions
Browse files Browse the repository at this point in the history
n Rust, an enum that carries data in the variants is, essentially, a
discriminated union. Furthermore, the Rust compiler will perform
space optimizations on such enums in some situations. Previously,
DWARF for these constructs was emitted using a hack (a magic field
name); but this approach stopped working when more space optimizations
were added in rust-lang/rust#45225.

This patch changes LLVM to allow discriminated unions to be
represented in DWARF. It adds createDiscriminatedUnionType and
createDiscriminatedMemberType to DIBuilder and then arranges for this
to be emitted using DWARF's DW_TAG_variant_part and DW_TAG_variant.

Note that DWARF requires that a discriminated union be represented as
a structure with a variant part. However, as Rust only needs to emit
pure discriminated unions, this is what I chose to expose on
DIBuilder.

Patch by Tom Tromey!

Differential Revision: https://reviews.llvm.org/D42082

llvm-svn: 324426
  • Loading branch information
adrian-prantl committed Feb 6, 2018
1 parent 4c687f3 commit 8c59921
Show file tree
Hide file tree
Showing 19 changed files with 380 additions and 56 deletions.
42 changes: 42 additions & 0 deletions llvm/include/llvm/IR/DIBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,27 @@ namespace llvm {
uint64_t OffsetInBits,
DINode::DIFlags Flags, DIType *Ty);

/// Create debugging information entry for a variant. A variant
/// normally should be a member of a variant part.
/// \param Scope Member scope.
/// \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 Discriminant The discriminant for this branch; null for
/// the default branch
/// \param Ty Parent type.
DIDerivedType *createVariantMemberType(DIScope *Scope, StringRef Name,
DIFile *File, unsigned LineNo,
uint64_t SizeInBits,
uint32_t AlignInBits,
uint64_t OffsetInBits,
Constant *Discriminant,
DINode::DIFlags Flags, DIType *Ty);

/// Create debugging information entry for a bit field member.
/// \param Scope Member scope.
/// \param Name Member name.
Expand Down Expand Up @@ -379,6 +400,27 @@ namespace llvm {
unsigned RunTimeLang = 0,
StringRef UniqueIdentifier = "");

/// Create debugging information entry for a variant part. A
/// variant part normally has a discriminator (though this is not
/// required) and a number of variant children.
/// \param Scope Scope in which this union is defined.
/// \param Name Union name.
/// \param File File where this member is defined.
/// \param LineNumber Line number.
/// \param SizeInBits Member size.
/// \param AlignInBits Member alignment.
/// \param Flags Flags to encode member attribute, e.g. private
/// \param Discriminator Discriminant member
/// \param Elements Variant elements.
/// \param UniqueIdentifier A unique identifier for the union.
DICompositeType *createVariantPart(DIScope *Scope, StringRef Name,
DIFile *File, unsigned LineNumber,
uint64_t SizeInBits, uint32_t AlignInBits,
DINode::DIFlags Flags,
DIDerivedType *Discriminator,
DINodeArray Elements,
StringRef UniqueIdentifier = "");

/// Create debugging information for template
/// type parameter.
/// \param Scope Scope in which this type is defined.
Expand Down
31 changes: 21 additions & 10 deletions llvm/include/llvm/IR/DebugInfoMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -847,6 +847,12 @@ class DIDerivedType : public DIType {
return C->getValue();
return nullptr;
}
Constant *getDiscriminantValue() const {
assert(getTag() == dwarf::DW_TAG_member && !isStaticMember());
if (auto *C = cast_or_null<ConstantAsMetadata>(getExtraData()))
return C->getValue();
return nullptr;
}
/// @}

static bool classof(const Metadata *MD) {
Expand Down Expand Up @@ -889,27 +895,29 @@ class DICompositeType : public DIType {
uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits,
DIFlags Flags, DINodeArray Elements, unsigned RuntimeLang,
DITypeRef VTableHolder, DITemplateParameterArray TemplateParams,
StringRef Identifier, StorageType Storage, bool ShouldCreate = true) {
StringRef Identifier, DIDerivedType *Discriminator,
StorageType Storage, bool ShouldCreate = true) {
return getImpl(
Context, Tag, getCanonicalMDString(Context, Name), File, Line, Scope,
BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements.get(),
RuntimeLang, VTableHolder, TemplateParams.get(),
getCanonicalMDString(Context, Identifier), Storage, ShouldCreate);
getCanonicalMDString(Context, Identifier), Discriminator, Storage, ShouldCreate);
}
static DICompositeType *
getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File,
unsigned Line, Metadata *Scope, Metadata *BaseType,
uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits,
DIFlags Flags, Metadata *Elements, unsigned RuntimeLang,
Metadata *VTableHolder, Metadata *TemplateParams,
MDString *Identifier, StorageType Storage, bool ShouldCreate = true);
MDString *Identifier, Metadata *Discriminator,
StorageType Storage, bool ShouldCreate = true);

TempDICompositeType cloneImpl() const {
return getTemporary(getContext(), getTag(), getName(), getFile(), getLine(),
getScope(), getBaseType(), getSizeInBits(),
getAlignInBits(), getOffsetInBits(), getFlags(),
getElements(), getRuntimeLang(), getVTableHolder(),
getTemplateParams(), getIdentifier());
getTemplateParams(), getIdentifier(), getDiscriminator());
}

public:
Expand All @@ -920,21 +928,22 @@ class DICompositeType : public DIType {
DIFlags Flags, DINodeArray Elements, unsigned RuntimeLang,
DITypeRef VTableHolder,
DITemplateParameterArray TemplateParams = nullptr,
StringRef Identifier = ""),
StringRef Identifier = "", DIDerivedType *Discriminator = nullptr),
(Tag, Name, File, Line, Scope, BaseType, SizeInBits,
AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang,
VTableHolder, TemplateParams, Identifier))
VTableHolder, TemplateParams, Identifier, Discriminator))
DEFINE_MDNODE_GET(DICompositeType,
(unsigned Tag, MDString *Name, Metadata *File,
unsigned Line, Metadata *Scope, Metadata *BaseType,
uint64_t SizeInBits, uint32_t AlignInBits,
uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements,
unsigned RuntimeLang, Metadata *VTableHolder,
Metadata *TemplateParams = nullptr,
MDString *Identifier = nullptr),
MDString *Identifier = nullptr,
Metadata *Discriminator = nullptr),
(Tag, Name, File, Line, Scope, BaseType, SizeInBits,
AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang,
VTableHolder, TemplateParams, Identifier))
VTableHolder, TemplateParams, Identifier, Discriminator))

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

Expand All @@ -951,7 +960,7 @@ class DICompositeType : public DIType {
Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits,
uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements,
unsigned RuntimeLang, Metadata *VTableHolder,
Metadata *TemplateParams);
Metadata *TemplateParams, Metadata *Discriminator);
static DICompositeType *getODRTypeIfExists(LLVMContext &Context,
MDString &Identifier);

Expand All @@ -970,7 +979,7 @@ class DICompositeType : public DIType {
Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits,
uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements,
unsigned RuntimeLang, Metadata *VTableHolder,
Metadata *TemplateParams);
Metadata *TemplateParams, Metadata *Discriminator);

DITypeRef getBaseType() const { return DITypeRef(getRawBaseType()); }
DINodeArray getElements() const {
Expand All @@ -988,6 +997,8 @@ class DICompositeType : public DIType {
Metadata *getRawVTableHolder() const { return getOperand(5); }
Metadata *getRawTemplateParams() const { return getOperand(6); }
MDString *getRawIdentifier() const { return getOperandAs<MDString>(7); }
Metadata *getRawDiscriminator() const { return getOperand(8); }
DIDerivedType *getDiscriminator() const { return getOperandAs<DIDerivedType>(8); }

/// Replace operands.
///
Expand Down
8 changes: 5 additions & 3 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4156,7 +4156,8 @@ bool LLParser::ParseDICompositeType(MDNode *&Result, bool IsDistinct) {
OPTIONAL(runtimeLang, DwarfLangField, ); \
OPTIONAL(vtableHolder, MDField, ); \
OPTIONAL(templateParams, MDField, ); \
OPTIONAL(identifier, MDStringField, );
OPTIONAL(identifier, MDStringField, ); \
OPTIONAL(discriminator, MDField, );
PARSE_MD_FIELDS();
#undef VISIT_MD_FIELDS

Expand All @@ -4166,7 +4167,7 @@ bool LLParser::ParseDICompositeType(MDNode *&Result, bool IsDistinct) {
Context, *identifier.Val, tag.Val, name.Val, file.Val, line.Val,
scope.Val, baseType.Val, size.Val, align.Val, offset.Val, flags.Val,
elements.Val, runtimeLang.Val, vtableHolder.Val,
templateParams.Val)) {
templateParams.Val, discriminator.Val)) {
Result = CT;
return false;
}
Expand All @@ -4177,7 +4178,8 @@ bool LLParser::ParseDICompositeType(MDNode *&Result, bool IsDistinct) {
DICompositeType,
(Context, tag.Val, name.Val, file.Val, line.Val, scope.Val, baseType.Val,
size.Val, align.Val, offset.Val, flags.Val, elements.Val,
runtimeLang.Val, vtableHolder.Val, templateParams.Val, identifier.Val));
runtimeLang.Val, vtableHolder.Val, templateParams.Val, identifier.Val,
discriminator.Val));
return false;
}

Expand Down
12 changes: 0 additions & 12 deletions llvm/lib/BinaryFormat/Dwarf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,16 +393,6 @@ StringRef llvm::dwarf::ArrayOrderString(unsigned Order) {
return StringRef();
}

StringRef llvm::dwarf::DiscriminantString(unsigned Discriminant) {
switch (Discriminant) {
case DW_DSC_label:
return "DW_DSC_label";
case DW_DSC_range:
return "DW_DSC_range";
}
return StringRef();
}

StringRef llvm::dwarf::LNStandardString(unsigned Standard) {
switch (Standard) {
default:
Expand Down Expand Up @@ -563,8 +553,6 @@ StringRef llvm::dwarf::AttributeValueString(uint16_t Attr, unsigned Val) {
return InlineCodeString(Val);
case DW_AT_ordering:
return ArrayOrderString(Val);
case DW_AT_discr_value:
return DiscriminantString(Val);
}

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

// If we have a UUID and this is not a forward declaration, lookup the
Expand All @@ -1269,6 +1269,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
unsigned RuntimeLang = Record[12];
Metadata *VTableHolder = nullptr;
Metadata *TemplateParams = nullptr;
Metadata *Discriminator = 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
Expand All @@ -1289,13 +1290,15 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
Elements = getMDOrNull(Record[11]);
VTableHolder = getDITypeRefOrNull(Record[13]);
TemplateParams = getMDOrNull(Record[14]);
if (Record.size() > 16)
Discriminator = getMDOrNull(Record[16]);
}
DICompositeType *CT = nullptr;
if (Identifier)
CT = DICompositeType::buildODRType(
Context, *Identifier, Tag, Name, File, Line, Scope, BaseType,
SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang,
VTableHolder, TemplateParams);
VTableHolder, TemplateParams, Discriminator);

// Create a node if we didn't get a lazy ODR type.
if (!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 @@ -1526,6 +1526,7 @@ void ModuleBitcodeWriter::writeDICompositeType(
Record.push_back(VE.getMetadataOrNullID(N->getVTableHolder()));
Record.push_back(VE.getMetadataOrNullID(N->getTemplateParams().get()));
Record.push_back(VE.getMetadataOrNullID(N->getRawIdentifier()));
Record.push_back(VE.getMetadataOrNullID(N->getDiscriminator()));

Stream.EmitRecord(bitc::METADATA_COMPOSITE_TYPE, Record, Abbrev);
Record.clear();
Expand Down
36 changes: 35 additions & 1 deletion llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -946,9 +946,24 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
case dwarf::DW_TAG_enumeration_type:
constructEnumTypeDIE(Buffer, CTy);
break;
case dwarf::DW_TAG_variant_part:
case dwarf::DW_TAG_structure_type:
case dwarf::DW_TAG_union_type:
case dwarf::DW_TAG_class_type: {
// Emit the discriminator for a variant part.
DIDerivedType *Discriminator = nullptr;
if (Tag == dwarf::DW_TAG_variant_part) {
Discriminator = CTy->getDiscriminator();
if (Discriminator) {
// DWARF says:
// If the variant part has a discriminant, the discriminant is
// represented by a separate debugging information entry which is
// a child of the variant part entry.
DIE &DiscMember = constructMemberDIE(Buffer, Discriminator);
addDIEEntry(Buffer, dwarf::DW_AT_discr, DiscMember);
}
}

// Add elements to structure type.
DINodeArray Elements = CTy->getElements();
for (const auto *Element : Elements) {
Expand All @@ -962,6 +977,18 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
addType(ElemDie, resolve(DDTy->getBaseType()), dwarf::DW_AT_friend);
} else if (DDTy->isStaticMember()) {
getOrCreateStaticMemberDIE(DDTy);
} else if (Tag == dwarf::DW_TAG_variant_part) {
// When emitting a variant part, wrap each member in
// DW_TAG_variant.
DIE &Variant = createAndAddDIE(dwarf::DW_TAG_variant, Buffer);
if (const ConstantInt *CI =
dyn_cast_or_null<ConstantInt>(DDTy->getDiscriminantValue())) {
if (isUnsignedDIType(DD, resolve(Discriminator->getBaseType())))
addUInt(Variant, dwarf::DW_AT_discr_value, None, CI->getZExtValue());
else
addSInt(Variant, dwarf::DW_AT_discr_value, None, CI->getSExtValue());
}
constructMemberDIE(Variant, DDTy);
} else {
constructMemberDIE(Buffer, DDTy);
}
Expand All @@ -981,6 +1008,11 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
if (unsigned PropertyAttributes = Property->getAttributes())
addUInt(ElemDie, dwarf::DW_AT_APPLE_property_attribute, None,
PropertyAttributes);
} else if (auto *Composite = dyn_cast<DICompositeType>(Element)) {
if (Composite->getTag() == dwarf::DW_TAG_variant_part) {
DIE &VariantPart = createAndAddDIE(Composite->getTag(), Buffer);
constructTypeDIE(VariantPart, Composite);
}
}
}

Expand Down Expand Up @@ -1430,7 +1462,7 @@ void DwarfUnit::constructContainingTypeDIEs() {
}
}

void DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) {
DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) {
DIE &MemberDie = createAndAddDIE(DT->getTag(), Buffer);
StringRef Name = DT->getName();
if (!Name.empty())
Expand Down Expand Up @@ -1535,6 +1567,8 @@ void DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) {

if (DT->isArtificial())
addFlag(MemberDie, dwarf::DW_AT_artificial);

return MemberDie;
}

DIE *DwarfUnit::getOrCreateStaticMemberDIE(const DIDerivedType *DT) {
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ class DwarfUnit : public DIEUnit {
void constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, DIE *IndexTy);
void constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy);
void constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy);
void constructMemberDIE(DIE &Buffer, const DIDerivedType *DT);
DIE &constructMemberDIE(DIE &Buffer, const DIDerivedType *DT);
void constructTemplateTypeParameterDIE(DIE &Buffer,
const DITemplateTypeParameter *TP);
void constructTemplateValueParameterDIE(DIE &Buffer,
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1691,6 +1691,7 @@ static void writeDICompositeType(raw_ostream &Out, const DICompositeType *N,
Printer.printMetadata("vtableHolder", N->getRawVTableHolder());
Printer.printMetadata("templateParams", N->getRawTemplateParams());
Printer.printString("identifier", N->getIdentifier());
Printer.printMetadata("discriminator", N->getRawDiscriminator());
Out << ")";
}

Expand Down
25 changes: 25 additions & 0 deletions llvm/lib/IR/DIBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,19 @@ static ConstantAsMetadata *getConstantOrNull(Constant *C) {
return nullptr;
}

DIDerivedType *DIBuilder::createVariantMemberType(DIScope *Scope, StringRef Name,
DIFile *File, unsigned LineNumber,
uint64_t SizeInBits,
uint32_t AlignInBits,
uint64_t OffsetInBits,
Constant *Discriminant,
DINode::DIFlags Flags, DIType *Ty) {
return DIDerivedType::get(VMContext, dwarf::DW_TAG_member, Name, File,
LineNumber, getNonCompileUnitScope(Scope), Ty,
SizeInBits, AlignInBits, OffsetInBits, None, Flags,
getConstantOrNull(Discriminant));
}

DIDerivedType *DIBuilder::createBitFieldMemberType(
DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber,
uint64_t SizeInBits, uint64_t OffsetInBits, uint64_t StorageOffsetInBits,
Expand Down Expand Up @@ -458,6 +471,18 @@ DICompositeType *DIBuilder::createUnionType(
return R;
}

DICompositeType *DIBuilder::createVariantPart(
DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber,
uint64_t SizeInBits, uint32_t AlignInBits, DINode::DIFlags Flags,
DIDerivedType *Discriminator, DINodeArray Elements, StringRef UniqueIdentifier) {
auto *R = DICompositeType::get(
VMContext, dwarf::DW_TAG_variant_part, Name, File, LineNumber,
getNonCompileUnitScope(Scope), nullptr, SizeInBits, AlignInBits, 0, Flags,
Elements, 0, nullptr, nullptr, UniqueIdentifier, Discriminator);
trackIfUnresolved(R);
return R;
}

DISubroutineType *DIBuilder::createSubroutineType(DITypeRefArray ParameterTypes,
DINode::DIFlags Flags,
unsigned CC) {
Expand Down
Loading

0 comments on commit 8c59921

Please sign in to comment.