Skip to content

Commit 8c59921

Browse files
committed
Add DWARF for discriminated unions
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
1 parent 4c687f3 commit 8c59921

19 files changed

+380
-56
lines changed

llvm/include/llvm/IR/DIBuilder.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,27 @@ namespace llvm {
258258
uint64_t OffsetInBits,
259259
DINode::DIFlags Flags, DIType *Ty);
260260

261+
/// Create debugging information entry for a variant. A variant
262+
/// normally should be a member of a variant part.
263+
/// \param Scope Member scope.
264+
/// \param Name Member name.
265+
/// \param File File where this member is defined.
266+
/// \param LineNo Line number.
267+
/// \param SizeInBits Member size.
268+
/// \param AlignInBits Member alignment.
269+
/// \param OffsetInBits Member offset.
270+
/// \param Flags Flags to encode member attribute, e.g. private
271+
/// \param Discriminant The discriminant for this branch; null for
272+
/// the default branch
273+
/// \param Ty Parent type.
274+
DIDerivedType *createVariantMemberType(DIScope *Scope, StringRef Name,
275+
DIFile *File, unsigned LineNo,
276+
uint64_t SizeInBits,
277+
uint32_t AlignInBits,
278+
uint64_t OffsetInBits,
279+
Constant *Discriminant,
280+
DINode::DIFlags Flags, DIType *Ty);
281+
261282
/// Create debugging information entry for a bit field member.
262283
/// \param Scope Member scope.
263284
/// \param Name Member name.
@@ -379,6 +400,27 @@ namespace llvm {
379400
unsigned RunTimeLang = 0,
380401
StringRef UniqueIdentifier = "");
381402

403+
/// Create debugging information entry for a variant part. A
404+
/// variant part normally has a discriminator (though this is not
405+
/// required) and a number of variant children.
406+
/// \param Scope Scope in which this union is defined.
407+
/// \param Name Union name.
408+
/// \param File File where this member is defined.
409+
/// \param LineNumber Line number.
410+
/// \param SizeInBits Member size.
411+
/// \param AlignInBits Member alignment.
412+
/// \param Flags Flags to encode member attribute, e.g. private
413+
/// \param Discriminator Discriminant member
414+
/// \param Elements Variant elements.
415+
/// \param UniqueIdentifier A unique identifier for the union.
416+
DICompositeType *createVariantPart(DIScope *Scope, StringRef Name,
417+
DIFile *File, unsigned LineNumber,
418+
uint64_t SizeInBits, uint32_t AlignInBits,
419+
DINode::DIFlags Flags,
420+
DIDerivedType *Discriminator,
421+
DINodeArray Elements,
422+
StringRef UniqueIdentifier = "");
423+
382424
/// Create debugging information for template
383425
/// type parameter.
384426
/// \param Scope Scope in which this type is defined.

llvm/include/llvm/IR/DebugInfoMetadata.h

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,12 @@ class DIDerivedType : public DIType {
847847
return C->getValue();
848848
return nullptr;
849849
}
850+
Constant *getDiscriminantValue() const {
851+
assert(getTag() == dwarf::DW_TAG_member && !isStaticMember());
852+
if (auto *C = cast_or_null<ConstantAsMetadata>(getExtraData()))
853+
return C->getValue();
854+
return nullptr;
855+
}
850856
/// @}
851857

852858
static bool classof(const Metadata *MD) {
@@ -889,27 +895,29 @@ class DICompositeType : public DIType {
889895
uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits,
890896
DIFlags Flags, DINodeArray Elements, unsigned RuntimeLang,
891897
DITypeRef VTableHolder, DITemplateParameterArray TemplateParams,
892-
StringRef Identifier, StorageType Storage, bool ShouldCreate = true) {
898+
StringRef Identifier, DIDerivedType *Discriminator,
899+
StorageType Storage, bool ShouldCreate = true) {
893900
return getImpl(
894901
Context, Tag, getCanonicalMDString(Context, Name), File, Line, Scope,
895902
BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements.get(),
896903
RuntimeLang, VTableHolder, TemplateParams.get(),
897-
getCanonicalMDString(Context, Identifier), Storage, ShouldCreate);
904+
getCanonicalMDString(Context, Identifier), Discriminator, Storage, ShouldCreate);
898905
}
899906
static DICompositeType *
900907
getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File,
901908
unsigned Line, Metadata *Scope, Metadata *BaseType,
902909
uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits,
903910
DIFlags Flags, Metadata *Elements, unsigned RuntimeLang,
904911
Metadata *VTableHolder, Metadata *TemplateParams,
905-
MDString *Identifier, StorageType Storage, bool ShouldCreate = true);
912+
MDString *Identifier, Metadata *Discriminator,
913+
StorageType Storage, bool ShouldCreate = true);
906914

907915
TempDICompositeType cloneImpl() const {
908916
return getTemporary(getContext(), getTag(), getName(), getFile(), getLine(),
909917
getScope(), getBaseType(), getSizeInBits(),
910918
getAlignInBits(), getOffsetInBits(), getFlags(),
911919
getElements(), getRuntimeLang(), getVTableHolder(),
912-
getTemplateParams(), getIdentifier());
920+
getTemplateParams(), getIdentifier(), getDiscriminator());
913921
}
914922

915923
public:
@@ -920,21 +928,22 @@ class DICompositeType : public DIType {
920928
DIFlags Flags, DINodeArray Elements, unsigned RuntimeLang,
921929
DITypeRef VTableHolder,
922930
DITemplateParameterArray TemplateParams = nullptr,
923-
StringRef Identifier = ""),
931+
StringRef Identifier = "", DIDerivedType *Discriminator = nullptr),
924932
(Tag, Name, File, Line, Scope, BaseType, SizeInBits,
925933
AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang,
926-
VTableHolder, TemplateParams, Identifier))
934+
VTableHolder, TemplateParams, Identifier, Discriminator))
927935
DEFINE_MDNODE_GET(DICompositeType,
928936
(unsigned Tag, MDString *Name, Metadata *File,
929937
unsigned Line, Metadata *Scope, Metadata *BaseType,
930938
uint64_t SizeInBits, uint32_t AlignInBits,
931939
uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements,
932940
unsigned RuntimeLang, Metadata *VTableHolder,
933941
Metadata *TemplateParams = nullptr,
934-
MDString *Identifier = nullptr),
942+
MDString *Identifier = nullptr,
943+
Metadata *Discriminator = nullptr),
935944
(Tag, Name, File, Line, Scope, BaseType, SizeInBits,
936945
AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang,
937-
VTableHolder, TemplateParams, Identifier))
946+
VTableHolder, TemplateParams, Identifier, Discriminator))
938947

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

@@ -951,7 +960,7 @@ class DICompositeType : public DIType {
951960
Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits,
952961
uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements,
953962
unsigned RuntimeLang, Metadata *VTableHolder,
954-
Metadata *TemplateParams);
963+
Metadata *TemplateParams, Metadata *Discriminator);
955964
static DICompositeType *getODRTypeIfExists(LLVMContext &Context,
956965
MDString &Identifier);
957966

@@ -970,7 +979,7 @@ class DICompositeType : public DIType {
970979
Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits,
971980
uint64_t OffsetInBits, DIFlags Flags, Metadata *Elements,
972981
unsigned RuntimeLang, Metadata *VTableHolder,
973-
Metadata *TemplateParams);
982+
Metadata *TemplateParams, Metadata *Discriminator);
974983

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

9921003
/// Replace operands.
9931004
///

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4156,7 +4156,8 @@ bool LLParser::ParseDICompositeType(MDNode *&Result, bool IsDistinct) {
41564156
OPTIONAL(runtimeLang, DwarfLangField, ); \
41574157
OPTIONAL(vtableHolder, MDField, ); \
41584158
OPTIONAL(templateParams, MDField, ); \
4159-
OPTIONAL(identifier, MDStringField, );
4159+
OPTIONAL(identifier, MDStringField, ); \
4160+
OPTIONAL(discriminator, MDField, );
41604161
PARSE_MD_FIELDS();
41614162
#undef VISIT_MD_FIELDS
41624163

@@ -4166,7 +4167,7 @@ bool LLParser::ParseDICompositeType(MDNode *&Result, bool IsDistinct) {
41664167
Context, *identifier.Val, tag.Val, name.Val, file.Val, line.Val,
41674168
scope.Val, baseType.Val, size.Val, align.Val, offset.Val, flags.Val,
41684169
elements.Val, runtimeLang.Val, vtableHolder.Val,
4169-
templateParams.Val)) {
4170+
templateParams.Val, discriminator.Val)) {
41704171
Result = CT;
41714172
return false;
41724173
}
@@ -4177,7 +4178,8 @@ bool LLParser::ParseDICompositeType(MDNode *&Result, bool IsDistinct) {
41774178
DICompositeType,
41784179
(Context, tag.Val, name.Val, file.Val, line.Val, scope.Val, baseType.Val,
41794180
size.Val, align.Val, offset.Val, flags.Val, elements.Val,
4180-
runtimeLang.Val, vtableHolder.Val, templateParams.Val, identifier.Val));
4181+
runtimeLang.Val, vtableHolder.Val, templateParams.Val, identifier.Val,
4182+
discriminator.Val));
41814183
return false;
41824184
}
41834185

llvm/lib/BinaryFormat/Dwarf.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -393,16 +393,6 @@ StringRef llvm::dwarf::ArrayOrderString(unsigned Order) {
393393
return StringRef();
394394
}
395395

396-
StringRef llvm::dwarf::DiscriminantString(unsigned Discriminant) {
397-
switch (Discriminant) {
398-
case DW_DSC_label:
399-
return "DW_DSC_label";
400-
case DW_DSC_range:
401-
return "DW_DSC_range";
402-
}
403-
return StringRef();
404-
}
405-
406396
StringRef llvm::dwarf::LNStandardString(unsigned Standard) {
407397
switch (Standard) {
408398
default:
@@ -563,8 +553,6 @@ StringRef llvm::dwarf::AttributeValueString(uint16_t Attr, unsigned Val) {
563553
return InlineCodeString(Val);
564554
case DW_AT_ordering:
565555
return ArrayOrderString(Val);
566-
case DW_AT_discr_value:
567-
return DiscriminantString(Val);
568556
}
569557

570558
return StringRef();

llvm/lib/Bitcode/Reader/MetadataLoader.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,7 +1246,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
12461246
break;
12471247
}
12481248
case bitc::METADATA_COMPOSITE_TYPE: {
1249-
if (Record.size() != 16)
1249+
if (Record.size() < 16 || Record.size() > 17)
12501250
return error("Invalid record");
12511251

12521252
// If we have a UUID and this is not a forward declaration, lookup the
@@ -1269,6 +1269,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
12691269
unsigned RuntimeLang = Record[12];
12701270
Metadata *VTableHolder = nullptr;
12711271
Metadata *TemplateParams = nullptr;
1272+
Metadata *Discriminator = nullptr;
12721273
auto *Identifier = getMDString(Record[15]);
12731274
// If this module is being parsed so that it can be ThinLTO imported
12741275
// into another module, composite types only need to be imported
@@ -1289,13 +1290,15 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
12891290
Elements = getMDOrNull(Record[11]);
12901291
VTableHolder = getDITypeRefOrNull(Record[13]);
12911292
TemplateParams = getMDOrNull(Record[14]);
1293+
if (Record.size() > 16)
1294+
Discriminator = getMDOrNull(Record[16]);
12921295
}
12931296
DICompositeType *CT = nullptr;
12941297
if (Identifier)
12951298
CT = DICompositeType::buildODRType(
12961299
Context, *Identifier, Tag, Name, File, Line, Scope, BaseType,
12971300
SizeInBits, AlignInBits, OffsetInBits, Flags, Elements, RuntimeLang,
1298-
VTableHolder, TemplateParams);
1301+
VTableHolder, TemplateParams, Discriminator);
12991302

13001303
// Create a node if we didn't get a lazy ODR type.
13011304
if (!CT)

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,7 @@ void ModuleBitcodeWriter::writeDICompositeType(
15261526
Record.push_back(VE.getMetadataOrNullID(N->getVTableHolder()));
15271527
Record.push_back(VE.getMetadataOrNullID(N->getTemplateParams().get()));
15281528
Record.push_back(VE.getMetadataOrNullID(N->getRawIdentifier()));
1529+
Record.push_back(VE.getMetadataOrNullID(N->getDiscriminator()));
15291530

15301531
Stream.EmitRecord(bitc::METADATA_COMPOSITE_TYPE, Record, Abbrev);
15311532
Record.clear();

llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -946,9 +946,24 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
946946
case dwarf::DW_TAG_enumeration_type:
947947
constructEnumTypeDIE(Buffer, CTy);
948948
break;
949+
case dwarf::DW_TAG_variant_part:
949950
case dwarf::DW_TAG_structure_type:
950951
case dwarf::DW_TAG_union_type:
951952
case dwarf::DW_TAG_class_type: {
953+
// Emit the discriminator for a variant part.
954+
DIDerivedType *Discriminator = nullptr;
955+
if (Tag == dwarf::DW_TAG_variant_part) {
956+
Discriminator = CTy->getDiscriminator();
957+
if (Discriminator) {
958+
// DWARF says:
959+
// If the variant part has a discriminant, the discriminant is
960+
// represented by a separate debugging information entry which is
961+
// a child of the variant part entry.
962+
DIE &DiscMember = constructMemberDIE(Buffer, Discriminator);
963+
addDIEEntry(Buffer, dwarf::DW_AT_discr, DiscMember);
964+
}
965+
}
966+
952967
// Add elements to structure type.
953968
DINodeArray Elements = CTy->getElements();
954969
for (const auto *Element : Elements) {
@@ -962,6 +977,18 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
962977
addType(ElemDie, resolve(DDTy->getBaseType()), dwarf::DW_AT_friend);
963978
} else if (DDTy->isStaticMember()) {
964979
getOrCreateStaticMemberDIE(DDTy);
980+
} else if (Tag == dwarf::DW_TAG_variant_part) {
981+
// When emitting a variant part, wrap each member in
982+
// DW_TAG_variant.
983+
DIE &Variant = createAndAddDIE(dwarf::DW_TAG_variant, Buffer);
984+
if (const ConstantInt *CI =
985+
dyn_cast_or_null<ConstantInt>(DDTy->getDiscriminantValue())) {
986+
if (isUnsignedDIType(DD, resolve(Discriminator->getBaseType())))
987+
addUInt(Variant, dwarf::DW_AT_discr_value, None, CI->getZExtValue());
988+
else
989+
addSInt(Variant, dwarf::DW_AT_discr_value, None, CI->getSExtValue());
990+
}
991+
constructMemberDIE(Variant, DDTy);
965992
} else {
966993
constructMemberDIE(Buffer, DDTy);
967994
}
@@ -981,6 +1008,11 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
9811008
if (unsigned PropertyAttributes = Property->getAttributes())
9821009
addUInt(ElemDie, dwarf::DW_AT_APPLE_property_attribute, None,
9831010
PropertyAttributes);
1011+
} else if (auto *Composite = dyn_cast<DICompositeType>(Element)) {
1012+
if (Composite->getTag() == dwarf::DW_TAG_variant_part) {
1013+
DIE &VariantPart = createAndAddDIE(Composite->getTag(), Buffer);
1014+
constructTypeDIE(VariantPart, Composite);
1015+
}
9841016
}
9851017
}
9861018

@@ -1430,7 +1462,7 @@ void DwarfUnit::constructContainingTypeDIEs() {
14301462
}
14311463
}
14321464

1433-
void DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) {
1465+
DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) {
14341466
DIE &MemberDie = createAndAddDIE(DT->getTag(), Buffer);
14351467
StringRef Name = DT->getName();
14361468
if (!Name.empty())
@@ -1535,6 +1567,8 @@ void DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) {
15351567

15361568
if (DT->isArtificial())
15371569
addFlag(MemberDie, dwarf::DW_AT_artificial);
1570+
1571+
return MemberDie;
15381572
}
15391573

15401574
DIE *DwarfUnit::getOrCreateStaticMemberDIE(const DIDerivedType *DT) {

llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ class DwarfUnit : public DIEUnit {
341341
void constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, DIE *IndexTy);
342342
void constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy);
343343
void constructEnumTypeDIE(DIE &Buffer, const DICompositeType *CTy);
344-
void constructMemberDIE(DIE &Buffer, const DIDerivedType *DT);
344+
DIE &constructMemberDIE(DIE &Buffer, const DIDerivedType *DT);
345345
void constructTemplateTypeParameterDIE(DIE &Buffer,
346346
const DITemplateTypeParameter *TP);
347347
void constructTemplateValueParameterDIE(DIE &Buffer,

llvm/lib/IR/AsmWriter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,6 +1691,7 @@ static void writeDICompositeType(raw_ostream &Out, const DICompositeType *N,
16911691
Printer.printMetadata("vtableHolder", N->getRawVTableHolder());
16921692
Printer.printMetadata("templateParams", N->getRawTemplateParams());
16931693
Printer.printString("identifier", N->getIdentifier());
1694+
Printer.printMetadata("discriminator", N->getRawDiscriminator());
16941695
Out << ")";
16951696
}
16961697

llvm/lib/IR/DIBuilder.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,19 @@ static ConstantAsMetadata *getConstantOrNull(Constant *C) {
333333
return nullptr;
334334
}
335335

336+
DIDerivedType *DIBuilder::createVariantMemberType(DIScope *Scope, StringRef Name,
337+
DIFile *File, unsigned LineNumber,
338+
uint64_t SizeInBits,
339+
uint32_t AlignInBits,
340+
uint64_t OffsetInBits,
341+
Constant *Discriminant,
342+
DINode::DIFlags Flags, DIType *Ty) {
343+
return DIDerivedType::get(VMContext, dwarf::DW_TAG_member, Name, File,
344+
LineNumber, getNonCompileUnitScope(Scope), Ty,
345+
SizeInBits, AlignInBits, OffsetInBits, None, Flags,
346+
getConstantOrNull(Discriminant));
347+
}
348+
336349
DIDerivedType *DIBuilder::createBitFieldMemberType(
337350
DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber,
338351
uint64_t SizeInBits, uint64_t OffsetInBits, uint64_t StorageOffsetInBits,
@@ -458,6 +471,18 @@ DICompositeType *DIBuilder::createUnionType(
458471
return R;
459472
}
460473

474+
DICompositeType *DIBuilder::createVariantPart(
475+
DIScope *Scope, StringRef Name, DIFile *File, unsigned LineNumber,
476+
uint64_t SizeInBits, uint32_t AlignInBits, DINode::DIFlags Flags,
477+
DIDerivedType *Discriminator, DINodeArray Elements, StringRef UniqueIdentifier) {
478+
auto *R = DICompositeType::get(
479+
VMContext, dwarf::DW_TAG_variant_part, Name, File, LineNumber,
480+
getNonCompileUnitScope(Scope), nullptr, SizeInBits, AlignInBits, 0, Flags,
481+
Elements, 0, nullptr, nullptr, UniqueIdentifier, Discriminator);
482+
trackIfUnresolved(R);
483+
return R;
484+
}
485+
461486
DISubroutineType *DIBuilder::createSubroutineType(DITypeRefArray ParameterTypes,
462487
DINode::DIFlags Flags,
463488
unsigned CC) {

0 commit comments

Comments
 (0)