diff --git a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def index a31111eb80a4e..aa3beea75c75b 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def +++ b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def @@ -53,6 +53,7 @@ TYPE_RECORD(LF_ENUM, 0x1507, Enum) TYPE_RECORD(LF_TYPESERVER2, 0x1515, TypeServer2) TYPE_RECORD(LF_VFTABLE, 0x151d, VFTable) TYPE_RECORD(LF_VTSHAPE, 0x000a, VFTableShape) +TYPE_RECORD(LF_ALIAS, 0x150a, Alias) TYPE_RECORD(LF_BITFIELD, 0x1205, BitField) @@ -181,7 +182,6 @@ CV_TYPE(LF_MANAGED_ST, 0x140f) CV_TYPE(LF_ST_MAX, 0x1500) CV_TYPE(LF_TYPESERVER, 0x1501) CV_TYPE(LF_DIMARRAY, 0x1508) -CV_TYPE(LF_ALIAS, 0x150a) CV_TYPE(LF_DEFARG, 0x150b) CV_TYPE(LF_FRIENDFCN, 0x150c) CV_TYPE(LF_NESTTYPEEX, 0x1512) diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h index 5a84fac5f5903..5eb8097e3a8ef 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h +++ b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -952,6 +952,18 @@ class EndPrecompRecord : public TypeRecord { uint32_t Signature = 0; }; +// LF_ALIAS +class AliasRecord : public TypeRecord { +public: + AliasRecord() = default; + explicit AliasRecord(TypeRecordKind Kind) : TypeRecord(Kind) {} + AliasRecord(TypeIndex UnderlyingType, StringRef Name) + : TypeRecord(TypeRecordKind::Alias), UnderlyingType(UnderlyingType), Name(Name) {} + + TypeIndex UnderlyingType; + StringRef Name; +}; + } // end namespace codeview } // end namespace llvm diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h index eb6371e911be4..164ea990336e0 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h @@ -418,6 +418,8 @@ class LVLogicalVisitor final { LVElement *Element); Error visitKnownRecord(CVType &Record, EndPrecompRecord &EndPrecomp, TypeIndex TI, LVElement *Element); + Error visitKnownRecord(CVType &Record, AliasRecord &Alias, + TypeIndex TI, LVElement *Element); Error visitUnknownMember(CVMemberRecord &Record, TypeIndex TI); Error visitKnownMember(CVMemberRecord &Record, BaseClassRecord &Base, diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index c5d6e40eb7c1e..b6863759dd10a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1728,6 +1728,9 @@ TypeIndex CodeViewDebug::lowerTypeAlias(const DIDerivedType *Ty) { addToUDTs(Ty); + AliasRecord AR(UnderlyingTypeIndex, TypeName); + auto AliasIndex = TypeTable.writeLeafType(AR); + if (UnderlyingTypeIndex == TypeIndex(SimpleTypeKind::Int32Long) && TypeName == "HRESULT") return TypeIndex(SimpleTypeKind::HResult); @@ -1735,7 +1738,7 @@ TypeIndex CodeViewDebug::lowerTypeAlias(const DIDerivedType *Ty) { TypeName == "wchar_t") return TypeIndex(SimpleTypeKind::WideCharacter); - return UnderlyingTypeIndex; + return AliasIndex; } TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) { @@ -2750,14 +2753,6 @@ TypeIndex CodeViewDebug::getCompleteTypeIndex(const DIType *Ty) { if (!Ty) return TypeIndex::Void(); - // Look through typedefs when getting the complete type index. Call - // getTypeIndex on the typdef to ensure that any UDTs are accumulated and are - // emitted only once. - if (Ty->getTag() == dwarf::DW_TAG_typedef) - (void)getTypeIndex(Ty); - while (Ty->getTag() == dwarf::DW_TAG_typedef) - Ty = cast(Ty)->getBaseType(); - // If this is a non-record type, the complete type index is the same as the // normal type index. Just call getTypeIndex. switch (Ty->getTag()) { diff --git a/llvm/lib/DebugInfo/CodeView/RecordName.cpp b/llvm/lib/DebugInfo/CodeView/RecordName.cpp index e06b036ede63a..80c9cfa2253fb 100644 --- a/llvm/lib/DebugInfo/CodeView/RecordName.cpp +++ b/llvm/lib/DebugInfo/CodeView/RecordName.cpp @@ -251,6 +251,11 @@ Error TypeNameComputer::visitKnownRecord(CVType &CVR, return Error::success(); } +Error TypeNameComputer::visitKnownRecord(CVType &CVR, AliasRecord &Alias) { + Name = Alias.Name; + return Error::success(); +} + std::string llvm::codeview::computeTypeName(TypeCollection &Types, TypeIndex Index) { TypeNameComputer Computer(Types); diff --git a/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp index 776676410e782..629b7e5746ff4 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp @@ -568,3 +568,9 @@ Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, W->printHex("Signature", EndPrecomp.getSignature()); return Error::success(); } + +Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, AliasRecord &Alias) { + printTypeIndex("UnderlyingType", Alias.UnderlyingType); + W->printString("Name", Alias.Name); + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp index 0bc65f8d0359a..530a119de85fe 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp @@ -752,3 +752,10 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR, error(IO.mapInteger(EndPrecomp.Signature, "Signature")); return Error::success(); } + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, AliasRecord &Alias) { + error(IO.mapInteger(Alias.UnderlyingType, "UnderlyingType")); + error(IO.mapStringZ(Alias.Name, "Name")); + + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp index 24eaa1234727d..6cd53d42a43cd 100644 --- a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp @@ -2623,6 +2623,18 @@ Error LVLogicalVisitor::visitKnownRecord(CVType &Record, return Error::success(); } +// LF_ALIAS (TPI) +Error LVLogicalVisitor::visitKnownRecord(CVType &Record, AliasRecord &Alias, + TypeIndex TI, LVElement *Element) { + LLVM_DEBUG({ + printTypeBegin(Record, TI, Element, StreamTPI); + printTypeIndex("UnderlyingType", Alias.UnderlyingType, StreamTPI); + W.printString("Name", Alias.Name); + printTypeEnd(Record); + }); + return Error::success(); +} + Error LVLogicalVisitor::visitUnknownMember(CVMemberRecord &Record, TypeIndex TI) { LLVM_DEBUG({ W.printHex("UnknownMember", unsigned(Record.Kind)); }); diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp index f4ca1b22eafa0..84f33a3fea6a8 100644 --- a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp +++ b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp @@ -614,6 +614,11 @@ template <> void LeafRecordImpl::map(IO &IO) { IO.mapRequired("Signature", Record.Signature); } +template <> void LeafRecordImpl::map(IO &IO) { + IO.mapRequired("UnderlyingType", Record.UnderlyingType); + IO.mapRequired("Name", Record.Name); +} + template <> void MemberRecordImpl::map(IO &IO) { MappingTraits::mapping(IO, Record); } diff --git a/llvm/test/DebugInfo/PDB/Inputs/typedef.ll b/llvm/test/DebugInfo/PDB/Inputs/typedef.ll new file mode 100644 index 0000000000000..b6ea8c77e944e --- /dev/null +++ b/llvm/test/DebugInfo/PDB/Inputs/typedef.ll @@ -0,0 +1,43 @@ +; ModuleID = 'typedef.cpp' +source_filename = "typedef.cpp" +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.44.35214" + +; Function Attrs: mustprogress noinline norecurse nounwind optnone uwtable +define dso_local noundef i32 @main() #0 !dbg !14 { +entry: + %retval = alloca i32, align 4 + %val = alloca i8, align 1 + %val2 = alloca i64, align 8 + store i32 0, ptr %retval, align 4 + #dbg_declare(ptr %val, !19, !DIExpression(), !22) + store i8 15, ptr %val, align 1, !dbg !22 + #dbg_declare(ptr %val2, !23, !DIExpression(), !26) + store i64 -1, ptr %val2, align 8, !dbg !26 + ret i32 0, !dbg !27 +} + +attributes #0 = { mustprogress noinline norecurse nounwind optnone uwtable } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8} +!llvm.ident = !{!13} + +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !5, producer: "clang version 22.0.0git (https://github.com/Walnut356/llvm-project.git 0e257f7d7edfcda5655eeaac55d0ffc398e773a2)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!5 = !DIFile(filename: "typedef.cpp", directory: "llvm-project") +!7 = !{i32 2, !"CodeView", i32 1} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!13 = !{!"clang version 22.0.0git (https://github.com/Walnut356/llvm-project.git 0e257f7d7edfcda5655eeaac55d0ffc398e773a2)"} +!14 = distinct !DISubprogram(name: "main", scope: !5, file: !5, line: 6, type: !15, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2) +!15 = !DISubroutineType(types: !16) +!16 = !{!17} +!17 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!19 = !DILocalVariable(name: "val", scope: !14, file: !5, line: 7, type: !20) +!20 = !DIDerivedType(tag: DW_TAG_typedef, name: "u8", file: !5, line: 3, baseType: !21) +!21 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) +!22 = !DILocation(line: 7, scope: !14) +!23 = !DILocalVariable(name: "val2", scope: !14, file: !5, line: 8, type: !24) +!24 = !DIDerivedType(tag: DW_TAG_typedef, name: "i64", file: !5, line: 4, baseType: !25) +!25 = !DIBasicType(name: "long long", size: 64, encoding: DW_ATE_signed) +!26 = !DILocation(line: 8, scope: !14) +!27 = !DILocation(line: 10, scope: !14) diff --git a/llvm/test/DebugInfo/PDB/Inputs/typedef.yaml b/llvm/test/DebugInfo/PDB/Inputs/typedef.yaml new file mode 100644 index 0000000000000..c6994647f5dc8 --- /dev/null +++ b/llvm/test/DebugInfo/PDB/Inputs/typedef.yaml @@ -0,0 +1,12 @@ +--- +TpiStream: + Records: + - Kind: LF_ALIAS + Alias: + UnderlyingType: 32 + Name: u8 + - Kind: LF_ALIAS + Alias: + UnderlyingType: 19 + Name: i64 +... \ No newline at end of file diff --git a/llvm/test/DebugInfo/PDB/typedef.test b/llvm/test/DebugInfo/PDB/typedef.test new file mode 100644 index 0000000000000..0395f327591de --- /dev/null +++ b/llvm/test/DebugInfo/PDB/typedef.test @@ -0,0 +1,62 @@ +Built with clang (22+) because MSVC does not output lf_alias for typedefs + +Build typedef.ll with clang -S -emit-llvm -g: + +``` +void *__purecall = 0; + +typedef unsigned char u8; +using i64 = long long; + +int main() { + u8 val = 15; + i64 val2 = -1; + + return 0; +} +``` + +RUN: llc -O0 %p/Inputs/typedef.ll --filetype=obj -o %t.obj +RUN: llvm-pdbutil dump --types %t.obj | FileCheck --check-prefix=OBJTYPE %s + +OBJTYPE: 0x1003 | LF_ALIAS [size = 12] alias = u8, underlying type = 0x0020 (unsigned char) +OBJTYPE-NEXT: 0x1004 | LF_ALIAS [size = 12] alias = i64, underlying type = 0x0013 (__int64) + +RUN: llvm-pdbutil dump --symbols %t.obj | FileCheck --check-prefix=OBJSYM %s + +OBJSYM: 0 | S_LOCAL [size = 16] `val` +OBJSYM-NEXT: type=0x1003 (u8), flags = none +OBJSYM: 0 | S_LOCAL [size = 16] `val2` +OBJSYM: type=0x1004 (i64), flags = none +OBJSYM: 0 | S_UDT [size = 12] `u8` +OBJSYM-NEXT: original type = 0x1003 +OBJSYM-NEXT: 0 | S_UDT [size = 12] `i64` +OBJSYM-NEXT: original type = 0x1004 + + +typedef.yaml file generated via `clang -fno-rtti -g -O0 typedef.cpp` and `llvm-pdbutil pdb2yaml -tpi-stream`, and then manually +reduced to only the typedef nodes + +RUN: llvm-pdbutil yaml2pdb -pdb=%t.yaml.pdb %p/Inputs/typedef.yaml +RUN: llvm-pdbutil dump --types %t.yaml.pdb \ +RUN: | FileCheck --check-prefix=TYPES %s + +Also check that the YAML output hasn't drifted +RUN: llvm-pdbutil pdb2yaml -tpi-stream %t.yaml.pdb \ +RUN: | FileCheck --check-prefixes=YAML %s + +TYPES: Types (TPI Stream) +TYPES-NEXT:============================================================ +TYPES-NEXT: Showing 2 records +TYPES-NEXT: 0x1000 | LF_ALIAS [size = 12] alias = u8, underlying type = 0x0020 (unsigned char) +TYPES-NEXT: 0x1001 | LF_ALIAS [size = 12] alias = i64, underlying type = 0x0013 (__int64) + + +YAML: - Kind: LF_ALIAS +YAML-NEXT: Alias: +YAML-NEXT: UnderlyingType: 32 +YAML-NEXT: Name: u8 +YAML-NEXT: - Kind: LF_ALIAS +YAML-NEXT: Alias: +YAML-NEXT: UnderlyingType: 19 +YAML-NEXT: Name: i64 \ No newline at end of file diff --git a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp index db3a752d58165..b7caf167c3d61 100644 --- a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp +++ b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp @@ -523,6 +523,13 @@ Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, return Error::success(); } +Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVT, + AliasRecord &Alias) { + P.format(" alias = {0}, underlying type = {1}", Alias.Name, + Alias.UnderlyingType); + return Error::success(); +} + Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR, NestedTypeRecord &Nested) { P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type);