Skip to content

[CodeView] Read and dump LF_ALIAS - #218243

Open
Nerixyz wants to merge 3 commits into
llvm:mainfrom
Nerixyz:feat/llvm-cv-lf-alias
Open

[CodeView] Read and dump LF_ALIAS#218243
Nerixyz wants to merge 3 commits into
llvm:mainfrom
Nerixyz:feat/llvm-cv-lf-alias

Conversation

@Nerixyz

@Nerixyz Nerixyz commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Most of this is taken from #153936. It only implements the read/dump/reconstruct part of #153936 - doesn't change the generated debug info.

LF_ALIAS represents a typedef typedef UnderlyingType Name. MSVC 19.52.36615 (currently the preview version) can generate it by passing /d1typeAliasDebugRecords. I used that version to test my change. From what I can tell, MSVC only generates LF_ALIAS for integer types (not even pointers to integers even if they're <0x1000). No clue why.

In

typedef char16_t MyByte;
using U16 = char16_t;
struct Foo {
  int bar = 1;
};
using Baz = Foo;
int main() {
  using Inner = char;
  using InnerPtr = char *;
  const MyByte *something = u"a string";
  const U16 *another = u"abc";
  Inner a = '+';
  const Inner *inner = "abc";
  InnerPtr ip = &a;
  Baz baz;
  Baz *bp = &baz;
}

Foo and InnerPtr won't get an LF_ALIAS. The type of baz will be Foo and ip will be char*.
Furthermore, Visual Studio's debugger will fail to inspect a. The others show fine. I think it can only handle aliases when they go through a pointer/reference.

The following additions were made compared to #153936:


Co-authored-by: Walnut ant_b356@me.com

@llvmorg-github-actions

llvmorg-github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown

@llvm/pr-subscribers-objectyaml

@llvm/pr-subscribers-platform-windows

Author: Nerixyz (Nerixyz)

Changes

Most of this is taken from #153936. It only implements the read/dump/reconstruct part of #153936 - it doesn't change the generated debug info.

LF_ALIAS represents a typedef typedef UnderlyingType Name. MSVC 19.52.36615 (currently the preview version) can generate it by passing /d1typeAliasDebugRecords. I used that version to test my change. From what I can tell, MSVC only generates that record for integer types (not even pointers to integers). No clue why.

In

typedef char16_t MyByte;
using U16 = char16_t;
struct Foo {
  int bar = 1;
};
using Baz = Foo;
int main() {
  using Inner = char;
  using InnerPtr = char *;
  const MyByte *something = u"a string";
  const U16 *another = u"abc";
  Inner a = '+';
  const Inner *inner = "abc";
  InnerPtr ip = &amp;a;
  Baz baz;
  Baz *bp = &amp;baz;
}

Foo and InnerPtr won't get an LF_ALIAS. The type of baz will be Foo and ip will be char*.
Furthermore, Visual Studio's debugger will fail to inspect a. The others show fine. I think it can only handle aliases when they go through a pointer/reference.

The following additions were made compared to #153936:


Co-authored-by: Walnut <ant_b356@me.com>


Full diff: https://github.com/llvm/llvm-project/pull/218243.diff

13 Files Affected:

  • (modified) llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def (+1-1)
  • (modified) llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h (+13)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h (+2)
  • (modified) llvm/lib/DebugInfo/CodeView/RecordName.cpp (+5)
  • (modified) llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp (+6)
  • (modified) llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp (+3)
  • (modified) llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp (+6)
  • (modified) llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp (+12)
  • (modified) llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp (+11-1)
  • (modified) llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp (+5)
  • (added) llvm/test/tools/llvm-pdbutil/alias-record.test (+45)
  • (modified) llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp (+5)
  • (modified) llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp (+6)
diff --git a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
index 86a74292dbb11..be0e81edbbb34 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
+++ b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
@@ -50,6 +50,7 @@ TYPE_RECORD_ALIAS(LF_STRUCTURE, 0x1505, Struct, Class)
 TYPE_RECORD_ALIAS(LF_INTERFACE, 0x1519, Interface, Class)
 TYPE_RECORD(LF_UNION, 0x1506, Union)
 TYPE_RECORD(LF_ENUM, 0x1507, Enum)
+TYPE_RECORD(LF_ALIAS, 0x150a, Alias)
 TYPE_RECORD(LF_TYPESERVER2, 0x1515, TypeServer2)
 TYPE_RECORD(LF_VFTABLE, 0x151d, VFTable)
 TYPE_RECORD(LF_VTSHAPE, 0x000a, VFTableShape)
@@ -187,7 +188,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..1b937a8621f7a 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h
@@ -952,6 +952,19 @@ class EndPrecompRecord : public TypeRecord {
   uint32_t Signature = 0;
 };
 
+/// `LF_ALIAS` - A typedef where `Name` is typedef'd to `UnderlyingType`.
+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 2d1bfa6f8dcb9..bd02829c28cbe 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h
@@ -428,6 +428,8 @@ class LVLogicalVisitor final {
                                   TypeIndex TI, LVElement *Element);
   LLVM_ABI Error visitKnownRecord(CVType &Record, EndPrecompRecord &EndPrecomp,
                                   TypeIndex TI, LVElement *Element);
+  LLVM_ABI Error visitKnownRecord(CVType &Record, AliasRecord &Alias,
+                                  TypeIndex TI, LVElement *Element);
 
   LLVM_ABI Error visitUnknownMember(CVMemberRecord &Record, TypeIndex TI);
   LLVM_ABI Error visitKnownMember(CVMemberRecord &Record, BaseClassRecord &Base,
diff --git a/llvm/lib/DebugInfo/CodeView/RecordName.cpp b/llvm/lib/DebugInfo/CodeView/RecordName.cpp
index 476f9bb935379..32b2267c06b3b 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 7dd2bad7da2e1..00f309ce45446 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
@@ -439,3 +439,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/TypeIndexDiscovery.cpp b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
index c19e72187fc9c..38264aa12b3d6 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
@@ -352,6 +352,9 @@ static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind,
   case TypeLeafKind::LF_POINTER:
     handlePointer(Content, Refs);
     break;
+  case TypeLeafKind::LF_ALIAS:
+    Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UnderlyingType
+    break;
   default:
     break;
   }
diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
index e8c9744935bf7..ea436e846e0ee 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
@@ -721,3 +721,9 @@ 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 7320a188051bb..5f6b0f513d37d 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
@@ -2671,6 +2671,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/DebugInfo/PDB/Native/TpiHashing.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
index 941ce78027a21..28967d55324c0 100644
--- a/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
@@ -85,6 +85,15 @@ static Expected<uint32_t> getSourceLineHash(const CVType &Rec) {
   return hashStringV1(StringRef(Buf, 4));
 }
 
+// LF_ALIAS is considered a UDT, so only the name is hashed.
+static Expected<uint32_t> getHashForAlias(const CVType &Rec) {
+  AliasRecord Deserialized;
+  if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec),
+                                               Deserialized))
+    return std::move(E);
+  return hashStringV1(Deserialized.Name);
+}
+
 Expected<TagRecordHash> llvm::pdb::hashTagRecord(const codeview::CVType &Type) {
   switch (Type.kind()) {
   case LF_CLASS:
@@ -112,7 +121,8 @@ Expected<uint32_t> llvm::pdb::hashTypeRecord(const CVType &Rec) {
     return getHashForUdt<UnionRecord>(Rec);
   case LF_ENUM:
     return getHashForUdt<EnumRecord>(Rec);
-
+  case LF_ALIAS:
+    return getHashForAlias(Rec);
   case LF_UDT_SRC_LINE:
     return getSourceLineHash<UdtSourceLineRecord>(Rec);
   case LF_UDT_MOD_SRC_LINE:
diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
index 1542017d9d7e6..0470ec6f8056c 100644
--- a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
+++ b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
@@ -654,6 +654,11 @@ template <> void LeafRecordImpl<EndPrecompRecord>::map(IO &IO) {
   IO.mapRequired("Signature", Record.Signature);
 }
 
+template <> void LeafRecordImpl<AliasRecord>::map(IO &IO) {
+  IO.mapRequired("UnderlyingType", Record.UnderlyingType);
+  IO.mapRequired("Name", Record.Name);
+}
+
 template <> void MemberRecordImpl<OneMethodRecord>::map(IO &IO) {
   MappingTraits<OneMethodRecord>::mapping(IO, Record);
 }
diff --git a/llvm/test/tools/llvm-pdbutil/alias-record.test b/llvm/test/tools/llvm-pdbutil/alias-record.test
new file mode 100644
index 0000000000000..88a979ed5e659
--- /dev/null
+++ b/llvm/test/tools/llvm-pdbutil/alias-record.test
@@ -0,0 +1,45 @@
+# RUN: llvm-pdbutil yaml2pdb %s --pdb=%t.pdb
+# RUN: llvm-pdbutil dump --types --type-extras %t.pdb | FileCheck --check-prefix=CHECK-YAML2PDB %s
+
+# RUN: llvm-pdbutil pdb2yaml --tpi-stream %t.pdb > %t.yaml
+# RUN: FileCheck --input-file=%t.yaml --check-prefix=CHECK-PDB2YAML %s
+
+# CHECK-YAML2PDB:       0x1000 | LF_ALIAS [size = 16, hash = 0x1876E]
+# CHECK-YAML2PDB-NEXT:           underlying type = 0x0070 (char), name = MyByte
+# CHECK-YAML2PDB-NEXT:  0x1001 | LF_ALIAS [size = 12, hash = 0x1D4A]
+# CHECK-YAML2PDB-NEXT:           underlying type = 0x007A (char16_t), name = U16
+# CHECK-YAML2PDB-NEXT:  0x1002 | LF_ALIAS [size = 16, hash = 0x1876E]
+# CHECK-YAML2PDB-NEXT:           underlying type = 0x007A (char16_t), name = MyByte
+
+# CHECK-PDB2YAML:        Records:
+# CHECK-PDB2YAML-NEXT:     - Kind:            LF_ALIAS
+# CHECK-PDB2YAML-NEXT:       Alias:
+# CHECK-PDB2YAML-NEXT:         UnderlyingType:  112
+# CHECK-PDB2YAML-NEXT:         Name:            MyByte
+# CHECK-PDB2YAML-NEXT:     - Kind:            LF_ALIAS
+# CHECK-PDB2YAML-NEXT:       Alias:
+# CHECK-PDB2YAML-NEXT:         UnderlyingType:  122
+# CHECK-PDB2YAML-NEXT:         Name:            U16
+# CHECK-PDB2YAML-NEXT:     - Kind:            LF_ALIAS
+# CHECK-PDB2YAML-NEXT:       Alias:
+# CHECK-PDB2YAML-NEXT:         UnderlyingType:  122
+# CHECK-PDB2YAML-NEXT:         Name:            MyByte
+# CHECK-PDB2YAML-NEXT: ...
+
+---
+TpiStream:
+  Version:         VC80
+  Records:
+    - Kind:            LF_ALIAS
+      Alias:
+        UnderlyingType:  112
+        Name:            MyByte
+    - Kind:            LF_ALIAS
+      Alias:
+        UnderlyingType:  122
+        Name:            U16
+    - Kind:            LF_ALIAS
+      Alias:
+        UnderlyingType:  122
+        Name:            MyByte
+...
diff --git a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
index fc29ec46180c4..13677bce09b75 100644
--- a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
+++ b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
@@ -535,6 +535,11 @@ Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
   return Error::success();
 }
 
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, AliasRecord &AR) {
+  P.formatLine("underlying type = {0}, name = {1}", AR.UnderlyingType, AR.Name);
+  return Error::success();
+}
+
 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
                                                NestedTypeRecord &Nested) {
   P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type);
diff --git a/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp b/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
index 810aeada33da7..5f11de113c747 100644
--- a/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
+++ b/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
@@ -613,3 +613,9 @@ TEST_F(TypeIndexIteratorTest, RegRelativeIndir) {
   writeSymbolRecords(RR);
   checkTypeReferences(0, RR.Type);
 }
+
+TEST_F(TypeIndexIteratorTest, AliasRecord) {
+  AliasRecord AR(TypeIndex::Int32(), "SomeName");
+  writeTypeRecords(AR);
+  checkTypeReferences(0, AR.UnderlyingType);
+}

@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-debuginfo

Author: Nerixyz (Nerixyz)

Changes

Most of this is taken from #153936. It only implements the read/dump/reconstruct part of #153936 - it doesn't change the generated debug info.

LF_ALIAS represents a typedef typedef UnderlyingType Name. MSVC 19.52.36615 (currently the preview version) can generate it by passing /d1typeAliasDebugRecords. I used that version to test my change. From what I can tell, MSVC only generates that record for integer types (not even pointers to integers). No clue why.

In

typedef char16_t MyByte;
using U16 = char16_t;
struct Foo {
  int bar = 1;
};
using Baz = Foo;
int main() {
  using Inner = char;
  using InnerPtr = char *;
  const MyByte *something = u"a string";
  const U16 *another = u"abc";
  Inner a = '+';
  const Inner *inner = "abc";
  InnerPtr ip = &amp;a;
  Baz baz;
  Baz *bp = &amp;baz;
}

Foo and InnerPtr won't get an LF_ALIAS. The type of baz will be Foo and ip will be char*.
Furthermore, Visual Studio's debugger will fail to inspect a. The others show fine. I think it can only handle aliases when they go through a pointer/reference.

The following additions were made compared to #153936:


Co-authored-by: Walnut <ant_b356@me.com>


Full diff: https://github.com/llvm/llvm-project/pull/218243.diff

13 Files Affected:

  • (modified) llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def (+1-1)
  • (modified) llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h (+13)
  • (modified) llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h (+2)
  • (modified) llvm/lib/DebugInfo/CodeView/RecordName.cpp (+5)
  • (modified) llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp (+6)
  • (modified) llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp (+3)
  • (modified) llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp (+6)
  • (modified) llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp (+12)
  • (modified) llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp (+11-1)
  • (modified) llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp (+5)
  • (added) llvm/test/tools/llvm-pdbutil/alias-record.test (+45)
  • (modified) llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp (+5)
  • (modified) llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp (+6)
diff --git a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
index 86a74292dbb11..be0e81edbbb34 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
+++ b/llvm/include/llvm/DebugInfo/CodeView/CodeViewTypes.def
@@ -50,6 +50,7 @@ TYPE_RECORD_ALIAS(LF_STRUCTURE, 0x1505, Struct, Class)
 TYPE_RECORD_ALIAS(LF_INTERFACE, 0x1519, Interface, Class)
 TYPE_RECORD(LF_UNION, 0x1506, Union)
 TYPE_RECORD(LF_ENUM, 0x1507, Enum)
+TYPE_RECORD(LF_ALIAS, 0x150a, Alias)
 TYPE_RECORD(LF_TYPESERVER2, 0x1515, TypeServer2)
 TYPE_RECORD(LF_VFTABLE, 0x151d, VFTable)
 TYPE_RECORD(LF_VTSHAPE, 0x000a, VFTableShape)
@@ -187,7 +188,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..1b937a8621f7a 100644
--- a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h
+++ b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h
@@ -952,6 +952,19 @@ class EndPrecompRecord : public TypeRecord {
   uint32_t Signature = 0;
 };
 
+/// `LF_ALIAS` - A typedef where `Name` is typedef'd to `UnderlyingType`.
+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 2d1bfa6f8dcb9..bd02829c28cbe 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h
@@ -428,6 +428,8 @@ class LVLogicalVisitor final {
                                   TypeIndex TI, LVElement *Element);
   LLVM_ABI Error visitKnownRecord(CVType &Record, EndPrecompRecord &EndPrecomp,
                                   TypeIndex TI, LVElement *Element);
+  LLVM_ABI Error visitKnownRecord(CVType &Record, AliasRecord &Alias,
+                                  TypeIndex TI, LVElement *Element);
 
   LLVM_ABI Error visitUnknownMember(CVMemberRecord &Record, TypeIndex TI);
   LLVM_ABI Error visitKnownMember(CVMemberRecord &Record, BaseClassRecord &Base,
diff --git a/llvm/lib/DebugInfo/CodeView/RecordName.cpp b/llvm/lib/DebugInfo/CodeView/RecordName.cpp
index 476f9bb935379..32b2267c06b3b 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 7dd2bad7da2e1..00f309ce45446 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
@@ -439,3 +439,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/TypeIndexDiscovery.cpp b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
index c19e72187fc9c..38264aa12b3d6 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
@@ -352,6 +352,9 @@ static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind,
   case TypeLeafKind::LF_POINTER:
     handlePointer(Content, Refs);
     break;
+  case TypeLeafKind::LF_ALIAS:
+    Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UnderlyingType
+    break;
   default:
     break;
   }
diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
index e8c9744935bf7..ea436e846e0ee 100644
--- a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
+++ b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
@@ -721,3 +721,9 @@ 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 7320a188051bb..5f6b0f513d37d 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
@@ -2671,6 +2671,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/DebugInfo/PDB/Native/TpiHashing.cpp b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
index 941ce78027a21..28967d55324c0 100644
--- a/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
+++ b/llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
@@ -85,6 +85,15 @@ static Expected<uint32_t> getSourceLineHash(const CVType &Rec) {
   return hashStringV1(StringRef(Buf, 4));
 }
 
+// LF_ALIAS is considered a UDT, so only the name is hashed.
+static Expected<uint32_t> getHashForAlias(const CVType &Rec) {
+  AliasRecord Deserialized;
+  if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec),
+                                               Deserialized))
+    return std::move(E);
+  return hashStringV1(Deserialized.Name);
+}
+
 Expected<TagRecordHash> llvm::pdb::hashTagRecord(const codeview::CVType &Type) {
   switch (Type.kind()) {
   case LF_CLASS:
@@ -112,7 +121,8 @@ Expected<uint32_t> llvm::pdb::hashTypeRecord(const CVType &Rec) {
     return getHashForUdt<UnionRecord>(Rec);
   case LF_ENUM:
     return getHashForUdt<EnumRecord>(Rec);
-
+  case LF_ALIAS:
+    return getHashForAlias(Rec);
   case LF_UDT_SRC_LINE:
     return getSourceLineHash<UdtSourceLineRecord>(Rec);
   case LF_UDT_MOD_SRC_LINE:
diff --git a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
index 1542017d9d7e6..0470ec6f8056c 100644
--- a/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
+++ b/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp
@@ -654,6 +654,11 @@ template <> void LeafRecordImpl<EndPrecompRecord>::map(IO &IO) {
   IO.mapRequired("Signature", Record.Signature);
 }
 
+template <> void LeafRecordImpl<AliasRecord>::map(IO &IO) {
+  IO.mapRequired("UnderlyingType", Record.UnderlyingType);
+  IO.mapRequired("Name", Record.Name);
+}
+
 template <> void MemberRecordImpl<OneMethodRecord>::map(IO &IO) {
   MappingTraits<OneMethodRecord>::mapping(IO, Record);
 }
diff --git a/llvm/test/tools/llvm-pdbutil/alias-record.test b/llvm/test/tools/llvm-pdbutil/alias-record.test
new file mode 100644
index 0000000000000..88a979ed5e659
--- /dev/null
+++ b/llvm/test/tools/llvm-pdbutil/alias-record.test
@@ -0,0 +1,45 @@
+# RUN: llvm-pdbutil yaml2pdb %s --pdb=%t.pdb
+# RUN: llvm-pdbutil dump --types --type-extras %t.pdb | FileCheck --check-prefix=CHECK-YAML2PDB %s
+
+# RUN: llvm-pdbutil pdb2yaml --tpi-stream %t.pdb > %t.yaml
+# RUN: FileCheck --input-file=%t.yaml --check-prefix=CHECK-PDB2YAML %s
+
+# CHECK-YAML2PDB:       0x1000 | LF_ALIAS [size = 16, hash = 0x1876E]
+# CHECK-YAML2PDB-NEXT:           underlying type = 0x0070 (char), name = MyByte
+# CHECK-YAML2PDB-NEXT:  0x1001 | LF_ALIAS [size = 12, hash = 0x1D4A]
+# CHECK-YAML2PDB-NEXT:           underlying type = 0x007A (char16_t), name = U16
+# CHECK-YAML2PDB-NEXT:  0x1002 | LF_ALIAS [size = 16, hash = 0x1876E]
+# CHECK-YAML2PDB-NEXT:           underlying type = 0x007A (char16_t), name = MyByte
+
+# CHECK-PDB2YAML:        Records:
+# CHECK-PDB2YAML-NEXT:     - Kind:            LF_ALIAS
+# CHECK-PDB2YAML-NEXT:       Alias:
+# CHECK-PDB2YAML-NEXT:         UnderlyingType:  112
+# CHECK-PDB2YAML-NEXT:         Name:            MyByte
+# CHECK-PDB2YAML-NEXT:     - Kind:            LF_ALIAS
+# CHECK-PDB2YAML-NEXT:       Alias:
+# CHECK-PDB2YAML-NEXT:         UnderlyingType:  122
+# CHECK-PDB2YAML-NEXT:         Name:            U16
+# CHECK-PDB2YAML-NEXT:     - Kind:            LF_ALIAS
+# CHECK-PDB2YAML-NEXT:       Alias:
+# CHECK-PDB2YAML-NEXT:         UnderlyingType:  122
+# CHECK-PDB2YAML-NEXT:         Name:            MyByte
+# CHECK-PDB2YAML-NEXT: ...
+
+---
+TpiStream:
+  Version:         VC80
+  Records:
+    - Kind:            LF_ALIAS
+      Alias:
+        UnderlyingType:  112
+        Name:            MyByte
+    - Kind:            LF_ALIAS
+      Alias:
+        UnderlyingType:  122
+        Name:            U16
+    - Kind:            LF_ALIAS
+      Alias:
+        UnderlyingType:  122
+        Name:            MyByte
+...
diff --git a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
index fc29ec46180c4..13677bce09b75 100644
--- a/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
+++ b/llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp
@@ -535,6 +535,11 @@ Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
   return Error::success();
 }
 
+Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, AliasRecord &AR) {
+  P.formatLine("underlying type = {0}, name = {1}", AR.UnderlyingType, AR.Name);
+  return Error::success();
+}
+
 Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
                                                NestedTypeRecord &Nested) {
   P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type);
diff --git a/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp b/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
index 810aeada33da7..5f11de113c747 100644
--- a/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
+++ b/llvm/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
@@ -613,3 +613,9 @@ TEST_F(TypeIndexIteratorTest, RegRelativeIndir) {
   writeSymbolRecords(RR);
   checkTypeReferences(0, RR.Type);
 }
+
+TEST_F(TypeIndexIteratorTest, AliasRecord) {
+  AliasRecord AR(TypeIndex::Int32(), "SomeName");
+  writeTypeRecords(AR);
+  checkTypeReferences(0, AR.UnderlyingType);
+}

@dpaoliello dpaoliello left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add handling in SymbolCache::findSymbolByTypeIndex - there may be downstream implications of that...

Comment thread llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h
Comment thread llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp
};

/// `LF_ALIAS` - A typedef where `Name` is typedef'd to `UnderlyingType`.
class AliasRecord : public TypeRecord {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any change to getSizeInBytesForTypeRecord - I don't think the default case is correct though, should we be forwarding the size of the underlying type?

@Nerixyz Nerixyz Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the default case is correct though, should we be forwarding the size of the underlying type?

Yeah - it returns (essentially) garbage for non-aggregates, the comment above says that

/// Given an arbitrary codeview type, return the type's size in the case
/// of aggregate (LF_STRUCTURE, LF_CLASS, LF_INTERFACE, LF_UNION).

I don't see LF_ALIAS as an aggregate. And given the function signature, it shouldn't read in the TPI stream. In my opinion, it should return an optional and only return the size in the documented cases.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm that also seems wrong - it should handle modifiers too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #218715 for this.

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown

✅ With the latest revision this PR passed the C/C++ code formatter.

@Nerixyz
Nerixyz force-pushed the feat/llvm-cv-lf-alias branch from 28b3446 to eb1f30c Compare August 24, 2026 19:42
@github-actions

Copy link
Copy Markdown

🐧 Linux x64 Test Results

  • 181192 tests passed
  • 3721 tests skipped
  • 1 test failed

Failed Tests

(click on a test name to see its output)

MLIR

MLIR.Dialect/Vector/vector-unroll-options.mlir
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 1
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/mlir-opt /home/gha/actions-runner/_work/llvm-project/llvm-project/mlir/test/Dialect/Vector/vector-unroll-options.mlir -test-vector-unrolling-patterns=unroll-based-on-type -split-input-file | /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck /home/gha/actions-runner/_work/llvm-project/llvm-project/mlir/test/Dialect/Vector/vector-unroll-options.mlir
# executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/mlir-opt /home/gha/actions-runner/_work/llvm-project/llvm-project/mlir/test/Dialect/Vector/vector-unroll-options.mlir -test-vector-unrolling-patterns=unroll-based-on-type -split-input-file
# note: command had no output on stdout or stderr
# executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck /home/gha/actions-runner/_work/llvm-project/llvm-project/mlir/test/Dialect/Vector/vector-unroll-options.mlir
# .---command stderr------------
# | /home/gha/actions-runner/_work/llvm-project/llvm-project/mlir/test/Dialect/Vector/vector-unroll-options.mlir:878:11: error: CHECK: expected string not found in input
# | // CHECK: %[[E0:.*]] = vector.extract_strided_slice %{{.*}} {offsets = [0, 0, 0], sizes = [1, 2, 2], strides = [1, 1, 1]} : vector<2x2x4xf32> to vector<1x2x2xf32>
# |           ^
# | <stdin>:726:61: note: scanning from here
# |  %cst = arith.constant dense<0.000000e+00> : vector<2x2xf32>
# |                                                             ^
# | <stdin>:726:61: note: pattern attempts to capture variables: "E0"
# |  %cst = arith.constant dense<0.000000e+00> : vector<2x2xf32>
# |                                                             ^
# | <stdin>:727:2: note: possible intended match here
# |  %0 = vector.extract_strided_slice %arg0 offsets = [0, 0, 0], sizes = [1, 2, 2], strides = [1, 1, 1] : vector<2x2x4xf32> to vector<1x2x2xf32>
# |  ^
# | 
# | Input file: <stdin>
# | Check file: /home/gha/actions-runner/_work/llvm-project/llvm-project/mlir/test/Dialect/Vector/vector-unroll-options.mlir
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |              .
# |              .
# |              .
# |            721: } 
# |            722:  
# |            723: // ----- 
# |            724: module { 
# |            725:  func.func @vector_multi_reduction_rank_mismatch(%arg0: vector<2x2x4xf32>, %arg1: vector<2x2xf32>) -> vector<2x2xf32> { 
# |            726:  %cst = arith.constant dense<0.000000e+00> : vector<2x2xf32> 
# | check:878'0                                                                {   search range start (exclusive)
# | check:878'1                                                                    error: no match found in search range
# | check:878'2                                                                    pattern attempts to capture variables: "E0"
# |            727:  %0 = vector.extract_strided_slice %arg0 offsets = [0, 0, 0], sizes = [1, 2, 2], strides = [1, 1, 1] : vector<2x2x4xf32> to vector<1x2x2xf32> 
# | check:878'3      ?                                                                                                                                              possible intended match
# |            728:  %1 = vector.extract_strided_slice %arg1 offsets = [0, 0], sizes = [1, 2], strides = [1, 1] : vector<2x2xf32> to vector<1x2xf32> 
# |            729:  %2 = vector.multi_reduction <add>, %0, %1 [2] : vector<1x2x2xf32> to vector<1x2xf32> 
# |            730:  %3 = vector.extract_strided_slice %arg0 offsets = [0, 0, 2], sizes = [1, 2, 2], strides = [1, 1, 1] : vector<2x2x4xf32> to vector<1x2x2xf32> 
# |            731:  %4 = vector.multi_reduction <add>, %3, %2 [2] : vector<1x2x2xf32> to vector<1x2xf32> 
# |            732:  %5 = vector.extract_strided_slice %arg0 offsets = [1, 0, 0], sizes = [1, 2, 2], strides = [1, 1, 1] : vector<2x2x4xf32> to vector<1x2x2xf32> 
# |              .
# |              .
# |              .
# |            737:  %10 = vector.insert_strided_slice %4, %cst offsets = [0, 0], strides = [1, 1] : vector<1x2xf32> into vector<2x2xf32> 
# |            738:  %11 = vector.insert_strided_slice %9, %10 offsets = [1, 0], strides = [1, 1] : vector<1x2xf32> into vector<2x2xf32> 
# |            739:  return %11 : vector<2x2xf32> 
# |            740:  } 
# |            741: } 
# |            742:  
# | check:878'4      } search range end (exclusive)
# | >>>>>>
# `-----------------------------
# error: command failed with exit status: 1

--

If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the infrastructure label.

@github-actions

Copy link
Copy Markdown

🪟 Windows x64 Test Results

  • 140295 tests passed
  • 3734 tests skipped
  • 1 test failed

Failed Tests

(click on a test name to see its output)

MLIR

MLIR.Dialect/Vector/vector-unroll-options.mlir
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 1
c:\_work\llvm-project\llvm-project\build\bin\mlir-opt.exe C:\_work\llvm-project\llvm-project\mlir\test\Dialect\Vector\vector-unroll-options.mlir -test-vector-unrolling-patterns=unroll-based-on-type -split-input-file | c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe C:\_work\llvm-project\llvm-project\mlir\test\Dialect\Vector\vector-unroll-options.mlir
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\mlir-opt.exe' 'C:\_work\llvm-project\llvm-project\mlir\test\Dialect\Vector\vector-unroll-options.mlir' -test-vector-unrolling-patterns=unroll-based-on-type -split-input-file
# note: command had no output on stdout or stderr
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe' 'C:\_work\llvm-project\llvm-project\mlir\test\Dialect\Vector\vector-unroll-options.mlir'
# .---command stderr------------
# | C:\_work\llvm-project\llvm-project\mlir\test\Dialect\Vector\vector-unroll-options.mlir:878:11: error: CHECK: expected string not found in input
# | // CHECK: %[[E0:.*]] = vector.extract_strided_slice %{{.*}} {offsets = [0, 0, 0], sizes = [1, 2, 2], strides = [1, 1, 1]} : vector<2x2x4xf32> to vector<1x2x2xf32>
# |           ^
# | <stdin>:726:61: note: scanning from here
# |  %cst = arith.constant dense<0.000000e+00> : vector<2x2xf32>
# |                                                             ^
# | <stdin>:726:61: note: pattern attempts to capture variables: "E0"
# |  %cst = arith.constant dense<0.000000e+00> : vector<2x2xf32>
# |                                                             ^
# | <stdin>:727:2: note: possible intended match here
# |  %0 = vector.extract_strided_slice %arg0 offsets = [0, 0, 0], sizes = [1, 2, 2], strides = [1, 1, 1] : vector<2x2x4xf32> to vector<1x2x2xf32>
# |  ^
# | 
# | Input file: <stdin>
# | Check file: C:\_work\llvm-project\llvm-project\mlir\test\Dialect\Vector\vector-unroll-options.mlir
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |              .
# |              .
# |              .
# |            721: } 
# |            722:  
# |            723: // ----- 
# |            724: module { 
# |            725:  func.func @vector_multi_reduction_rank_mismatch(%arg0: vector<2x2x4xf32>, %arg1: vector<2x2xf32>) -> vector<2x2xf32> { 
# |            726:  %cst = arith.constant dense<0.000000e+00> : vector<2x2xf32> 
# | check:878'0                                                                {   search range start (exclusive)
# | check:878'1                                                                    error: no match found in search range
# | check:878'2                                                                    pattern attempts to capture variables: "E0"
# |            727:  %0 = vector.extract_strided_slice %arg0 offsets = [0, 0, 0], sizes = [1, 2, 2], strides = [1, 1, 1] : vector<2x2x4xf32> to vector<1x2x2xf32> 
# | check:878'3      ?                                                                                                                                              possible intended match
# |            728:  %1 = vector.extract_strided_slice %arg1 offsets = [0, 0], sizes = [1, 2], strides = [1, 1] : vector<2x2xf32> to vector<1x2xf32> 
# |            729:  %2 = vector.multi_reduction <add>, %0, %1 [2] : vector<1x2x2xf32> to vector<1x2xf32> 
# |            730:  %3 = vector.extract_strided_slice %arg0 offsets = [0, 0, 2], sizes = [1, 2, 2], strides = [1, 1, 1] : vector<2x2x4xf32> to vector<1x2x2xf32> 
# |            731:  %4 = vector.multi_reduction <add>, %3, %2 [2] : vector<1x2x2xf32> to vector<1x2xf32> 
# |            732:  %5 = vector.extract_strided_slice %arg0 offsets = [1, 0, 0], sizes = [1, 2, 2], strides = [1, 1, 1] : vector<2x2x4xf32> to vector<1x2x2xf32> 
# |              .
# |              .
# |              .
# |            737:  %10 = vector.insert_strided_slice %4, %cst offsets = [0, 0], strides = [1, 1] : vector<1x2xf32> into vector<2x2xf32> 
# |            738:  %11 = vector.insert_strided_slice %9, %10 offsets = [1, 0], strides = [1, 1] : vector<1x2xf32> into vector<2x2xf32> 
# |            739:  return %11 : vector<2x2xf32> 
# |            740:  } 
# |            741: } 
# |            742:  
# | check:878'4      } search range end (exclusive)
# | >>>>>>
# `-----------------------------
# error: command failed with exit status: 1

--

If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the infrastructure label.


NativeTypeTypedefAlias::NativeTypeTypedefAlias(
NativeSession &Session, SymIndexId Id,
NativeTypeTypedefAlias &UnmodifiedType, codeview::ModifierRecord Modifier)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused - where does this Modifier come from? Why aren't we dumping it elsewhere?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like dead functionality, perhaps exercised by the original PR. I would leave it out of scope if you don't need it for the core parsing / dumping code.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't dead - it's used in SymbolCache::createSymbolForModifiedType. It's similar to how modifiers for tag records are handled.

@rnk rnk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. It sounds like there's a "PDB schema change" coming, if that's the right word for it.

I seem to recall that Symbol UDTs were a major bottleneck for PDB writing, so it makes sense that Microsoft would seek to shift that information from the symbol record stream over to the type record stream, where it gets merged more efficiently.

It then just becomes a question of figuring out which typedefs are active in which translation unit, and I don't know how they'll do it. I guess that's a relevant question for LLDB.

Comment thread llvm/lib/DebugInfo/PDB/Native/TpiHashing.cpp

NativeTypeTypedefAlias::NativeTypeTypedefAlias(
NativeSession &Session, SymIndexId Id,
NativeTypeTypedefAlias &UnmodifiedType, codeview::ModifierRecord Modifier)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like dead functionality, perhaps exercised by the original PR. I would leave it out of scope if you don't need it for the core parsing / dumping code.

@Nerixyz

Nerixyz commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

Interesting. It sounds like there's a "PDB schema change" coming, if that's the right word for it.

Technically, LF_ALIAS existed for some time now as it's also in the original microsoft-pdb repo, but no one used it. Not sure what got it started in this case.

I seem to recall that Symbol UDTs were a major bottleneck for PDB writing, so it makes sense that Microsoft would seek to shift that information from the symbol record stream over to the type record stream, where it gets merged more efficiently.

It then just becomes a question of figuring out which typedefs are active in which translation unit, and I don't know how they'll do it. I guess that's a relevant question for LLDB.

LLDB has only looked at the symbol UDTs when searching types. That seems to be what the DIA SDK does today too. I'm hoping to change that. Having this in the type stream also means that we know which values use a typedef - before we only knew that a typedef existed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants