[lld] 14f7e5f - [LLD][COFF] Make `/summary` work when `/debug` isn't provided (#157476)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 9 04:28:27 PDT 2025


Author: Alexandre Ganea
Date: 2025-09-09T07:28:24-04:00
New Revision: 14f7e5fa06235dac1a2d82290aa4d69de9d56862

URL: https://github.com/llvm/llvm-project/commit/14f7e5fa06235dac1a2d82290aa4d69de9d56862
DIFF: https://github.com/llvm/llvm-project/commit/14f7e5fa06235dac1a2d82290aa4d69de9d56862.diff

LOG: [LLD][COFF] Make `/summary` work when `/debug` isn't provided (#157476)

Previously, `/summary` was meant to print some PDB information. Now move
handling of `/summary` to `Writer.cpp` so that it can have an effect
when `/debug` isn't provided. This will also provide grounds for
extending with more general information.

Added: 
    

Modified: 
    lld/COFF/COFFLinkerContext.h
    lld/COFF/PDB.cpp
    lld/COFF/PDB.h
    lld/COFF/Writer.cpp
    lld/test/COFF/pdb-type-server-simple.test
    lld/test/COFF/precomp-link.test
    lld/test/COFF/precomp-summary-fail.test

Removed: 
    


################################################################################
diff  --git a/lld/COFF/COFFLinkerContext.h b/lld/COFF/COFFLinkerContext.h
index b44263b5a3390..0f8f2062b9f2e 100644
--- a/lld/COFF/COFFLinkerContext.h
+++ b/lld/COFF/COFFLinkerContext.h
@@ -14,6 +14,7 @@
 #include "DebugTypes.h"
 #include "Driver.h"
 #include "InputFiles.h"
+#include "PDB.h"
 #include "SymbolTable.h"
 #include "Writer.h"
 #include "lld/Common/CommonLinkerContext.h"
@@ -113,6 +114,8 @@ class COFFLinkerContext : public CommonLinkerContext {
   Timer tpiStreamLayoutTimer;
   Timer diskCommitTimer;
 
+  std::optional<PDBStats> pdbStats;
+
   Configuration config;
 
   DynamicRelocsChunk *dynamicRelocs = nullptr;

diff  --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp
index e5c62af28fdd2..fd54d20da3ccd 100644
--- a/lld/COFF/PDB.cpp
+++ b/lld/COFF/PDB.cpp
@@ -44,7 +44,6 @@
 #include "llvm/Object/CVDebugRecord.h"
 #include "llvm/Support/CRC.h"
 #include "llvm/Support/Endian.h"
-#include "llvm/Support/FormatAdapters.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/ScopedPrinter.h"
@@ -133,8 +132,8 @@ class PDBLinker {
   /// Write the PDB to disk and store the Guid generated for it in *Guid.
   void commit(codeview::GUID *guid);
 
-  // Print statistics regarding the final PDB
-  void printStats();
+  // Collect some statistics regarding the final PDB
+  void collectStats();
 
 private:
   void pdbMakeAbsolute(SmallVectorImpl<char> &fileName);
@@ -154,13 +153,6 @@ class PDBLinker {
   DebugStringTableSubsection pdbStrTab;
 
   llvm::SmallString<128> nativePath;
-
-  // For statistics
-  uint64_t globalSymbols = 0;
-  uint64_t moduleSymbols = 0;
-  uint64_t publicSymbols = 0;
-  uint64_t nbTypeRecords = 0;
-  uint64_t nbTypeRecordsBytes = 0;
 };
 
 /// Represents an unrelocated DEBUG_S_FRAMEDATA subsection.
@@ -610,7 +602,9 @@ void PDBLinker::analyzeSymbolSubsection(
           addGlobalSymbol(builder.getGsiBuilder(),
                           file->moduleDBI->getModuleIndex(), moduleSymOffset,
                           storage);
-          ++globalSymbols;
+
+          if (ctx.pdbStats.has_value())
+            ++ctx.pdbStats->globalSymbols;
         }
 
         // Update the module stream offset and record any string table index
@@ -619,7 +613,9 @@ void PDBLinker::analyzeSymbolSubsection(
         if (symbolGoesInModuleStream(sym, scopeLevel)) {
           recordStringTableReferences(sym, moduleSymOffset, stringTableFixups);
           moduleSymOffset += alignedSize;
-          ++moduleSymbols;
+
+          if (ctx.pdbStats.has_value())
+            ++ctx.pdbStats->moduleSymbols;
         }
 
         return Error::success();
@@ -1192,10 +1188,10 @@ void PDBLinker::addObjectsToPDB() {
     }
   }
 
-  if (ctx.config.showSummary) {
+  if (ctx.pdbStats.has_value()) {
     for (TpiSource *source : ctx.tpiSourceList) {
-      nbTypeRecords += source->nbTypeRecords;
-      nbTypeRecordsBytes += source->nbTypeRecordsBytes;
+      ctx.pdbStats->nbTypeRecords += source->nbTypeRecords;
+      ctx.pdbStats->nbTypeRecordsBytes += source->nbTypeRecordsBytes;
     }
   }
 }
@@ -1231,43 +1227,24 @@ void PDBLinker::addPublicsToPDB() {
     }
   });
 
-  if (!publics.empty()) {
-    publicSymbols = publics.size();
+  if (ctx.pdbStats.has_value())
+    ctx.pdbStats->publicSymbols = publics.size();
+
+  if (!publics.empty())
     gsiBuilder.addPublicSymbols(std::move(publics));
-  }
 }
 
-void PDBLinker::printStats() {
+void PDBLinker::collectStats() {
   if (!ctx.config.showSummary)
     return;
 
+  ctx.pdbStats->nbTPIrecords = builder.getTpiBuilder().getRecordCount();
+  ctx.pdbStats->nbIPIrecords = builder.getIpiBuilder().getRecordCount();
+  ctx.pdbStats->strTabSize = pdbStrTab.size();
+
   SmallString<256> buffer;
   raw_svector_ostream stream(buffer);
 
-  stream << center_justify("Summary", 80) << '\n'
-         << std::string(80, '-') << '\n';
-
-  auto print = [&](uint64_t v, StringRef s) {
-    stream << formatv("{0}",
-                      fmt_align(formatv("{0:N}", v), AlignStyle::Right, 20))
-           << " " << s << '\n';
-  };
-
-  print(ctx.objFileInstances.size(),
-        "Input OBJ files (expanded from all cmd-line inputs)");
-  print(ctx.consumedInputsSize,
-        "Size of all consumed OBJ files (non-lazy), in bytes");
-  print(ctx.typeServerSourceMappings.size(), "PDB type server dependencies");
-  print(ctx.precompSourceMappings.size(), "Precomp OBJ dependencies");
-  print(nbTypeRecords, "Input type records");
-  print(nbTypeRecordsBytes, "Size of all input type records, in bytes");
-  print(builder.getTpiBuilder().getRecordCount(), "Merged TPI records");
-  print(builder.getIpiBuilder().getRecordCount(), "Merged IPI records");
-  print(pdbStrTab.size(), "Output PDB strings");
-  print(globalSymbols, "Global symbol records");
-  print(moduleSymbols, "Module symbol records");
-  print(publicSymbols, "Public symbol records");
-
   auto printLargeInputTypeRecs = [&](StringRef name,
                                      ArrayRef<uint32_t> recCounts,
                                      TypeCollection &records) {
@@ -1318,9 +1295,9 @@ void PDBLinker::printStats() {
     // FIXME: Reimplement for ghash.
     printLargeInputTypeRecs("TPI", tMerger.tpiCounts, tMerger.getTypeTable());
     printLargeInputTypeRecs("IPI", tMerger.ipiCounts, tMerger.getIDTable());
-  }
 
-  Msg(ctx) << buffer;
+    ctx.pdbStats->largeInputTypeRecs = buffer.str();
+  }
 }
 
 void PDBLinker::addNatvisFiles() {
@@ -1624,6 +1601,9 @@ void lld::coff::createPDB(COFFLinkerContext &ctx,
   {
     PDBLinker pdb(ctx);
 
+    if (ctx.config.showSummary)
+      ctx.pdbStats.emplace();
+
     pdb.initialize(buildId);
     pdb.addObjectsToPDB();
     pdb.addImportFilesToPDB();
@@ -1640,8 +1620,8 @@ void lld::coff::createPDB(COFFLinkerContext &ctx,
       memcpy(&buildId->PDB70.Signature, &guid, 16);
     }
 
+    pdb.collectStats();
     t1.stop();
-    pdb.printStats();
 
     // Manually start this profile point to measure ~PDBLinker().
     if (getTimeTraceProfilerInstance() != nullptr)

diff  --git a/lld/COFF/PDB.h b/lld/COFF/PDB.h
index 991805cc95b38..4a5df37c0fe6f 100644
--- a/lld/COFF/PDB.h
+++ b/lld/COFF/PDB.h
@@ -30,6 +30,19 @@ void createPDB(COFFLinkerContext &ctx, llvm::ArrayRef<uint8_t> sectionTable,
 std::optional<std::pair<llvm::StringRef, uint32_t>>
 getFileLineCodeView(const SectionChunk *c, uint32_t addr);
 
+// For statistics
+struct PDBStats {
+  uint64_t globalSymbols = 0;
+  uint64_t moduleSymbols = 0;
+  uint64_t publicSymbols = 0;
+  uint64_t nbTypeRecords = 0;
+  uint64_t nbTypeRecordsBytes = 0;
+  uint64_t nbTPIrecords = 0;
+  uint64_t nbIPIrecords = 0;
+  uint64_t strTabSize = 0;
+  std::string largeInputTypeRecs;
+};
+
 } // namespace coff
 } // namespace lld
 

diff  --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 37577e8dd93d9..e0d0ac18ea5d5 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -27,6 +27,8 @@
 #include "llvm/MC/StringTableBuilder.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Parallel.h"
 #include "llvm/Support/RandomNumberGenerator.h"
 #include "llvm/Support/TimeProfiler.h"
@@ -282,6 +284,8 @@ class Writer {
   template <typename T>
   void prepareLoadConfig(SymbolTable &symtab, T *loadConfig);
 
+  void printSummary();
+
   std::unique_ptr<FileOutputBuffer> &buffer;
   std::map<PartialSectionKey, PartialSection *> partialSections;
   StringTableBuilder strtab;
@@ -823,6 +827,8 @@ void Writer::run() {
 
   writePEChecksum();
 
+  printSummary();
+
   if (errorCount())
     return;
 
@@ -3046,3 +3052,43 @@ void Writer::prepareLoadConfig(SymbolTable &symtab, T *loadConfig) {
 #undef CHECK_VA
 #undef CHECK_ABSOLUTE
 }
+
+void Writer::printSummary() {
+  if (!ctx.config.showSummary)
+    return;
+
+  SmallString<256> buffer;
+  raw_svector_ostream stream(buffer);
+
+  stream << center_justify("Summary", 80) << '\n'
+         << std::string(80, '-') << '\n';
+
+  auto print = [&](uint64_t v, StringRef s) {
+    stream << formatv("{0}",
+                      fmt_align(formatv("{0:N}", v), AlignStyle::Right, 20))
+           << " " << s << '\n';
+  };
+
+  bool hasStats = ctx.pdbStats.has_value();
+
+  print(ctx.objFileInstances.size(),
+        "Input OBJ files (expanded from all cmd-line inputs)");
+  print(ctx.consumedInputsSize,
+        "Size of all consumed OBJ files (non-lazy), in bytes");
+  print(ctx.typeServerSourceMappings.size(), "PDB type server dependencies");
+  print(ctx.precompSourceMappings.size(), "Precomp OBJ dependencies");
+  print(hasStats ? ctx.pdbStats->nbTypeRecords : 0, "Input debug type records");
+  print(hasStats ? ctx.pdbStats->nbTypeRecordsBytes : 0,
+        "Size of all input debug type records, in bytes");
+  print(hasStats ? ctx.pdbStats->nbTPIrecords : 0, "Merged TPI records");
+  print(hasStats ? ctx.pdbStats->nbIPIrecords : 0, "Merged IPI records");
+  print(hasStats ? ctx.pdbStats->strTabSize : 0, "Output PDB strings");
+  print(hasStats ? ctx.pdbStats->globalSymbols : 0, "Global symbol records");
+  print(hasStats ? ctx.pdbStats->moduleSymbols : 0, "Module symbol records");
+  print(hasStats ? ctx.pdbStats->publicSymbols : 0, "Public symbol records");
+
+  if (hasStats)
+    stream << ctx.pdbStats->largeInputTypeRecs;
+
+  Msg(ctx) << buffer;
+}

diff  --git a/lld/test/COFF/pdb-type-server-simple.test b/lld/test/COFF/pdb-type-server-simple.test
index 5323a078ac432..693bd9b482dae 100644
--- a/lld/test/COFF/pdb-type-server-simple.test
+++ b/lld/test/COFF/pdb-type-server-simple.test
@@ -110,8 +110,8 @@ SUMMARY-NEXT:                    2 Input OBJ files (expanded from all cmd-line i
 SUMMARY-NEXT: Size of all consumed OBJ files (non-lazy), in bytes
 SUMMARY-NEXT:                    1 PDB type server dependencies
 SUMMARY-NEXT:                    0 Precomp OBJ dependencies
-SUMMARY-NEXT:                   25 Input type records
-SUMMARY-NEXT:                  868 Size of all input type records, in bytes
+SUMMARY-NEXT:                   25 Input debug type records
+SUMMARY-NEXT:                  868 Size of all input debug type records, in bytes
 SUMMARY-NEXT:                    9 Merged TPI records
 SUMMARY-NEXT:                   16 Merged IPI records
 SUMMARY-NEXT:                    3 Output PDB strings

diff  --git a/lld/test/COFF/precomp-link.test b/lld/test/COFF/precomp-link.test
index 1c26042a44c33..389747920ffcf 100644
--- a/lld/test/COFF/precomp-link.test
+++ b/lld/test/COFF/precomp-link.test
@@ -3,6 +3,9 @@ RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s
 RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug:ghash /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf /summary | FileCheck %s -check-prefix SUMMARY
 RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s
 
+RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /out:%t.exe /opt:ref /opt:icf /summary | FileCheck %s -check-prefix SUMMARY-NODEBUG
+RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /out:%t.exe /opt:ref /opt:icf /summary | FileCheck %s -check-prefix SUMMARY-NODEBUG
+
 RUN: lld-link %S/Inputs/precomp.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf
 RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s
 
@@ -63,8 +66,8 @@ SUMMARY-NEXT:                    3 Input OBJ files (expanded from all cmd-line i
 SUMMARY-NEXT: Size of all consumed OBJ files (non-lazy), in bytes
 SUMMARY-NEXT:                    0 PDB type server dependencies
 SUMMARY-NEXT:                    1 Precomp OBJ dependencies
-SUMMARY-NEXT:                1,066 Input type records
-SUMMARY-NEXT:               55,968 Size of all input type records, in bytes
+SUMMARY-NEXT:                1,066 Input debug type records
+SUMMARY-NEXT:               55,968 Size of all input debug type records, in bytes
 SUMMARY-NEXT:                  874 Merged TPI records
 SUMMARY-NEXT:                  170 Merged IPI records
 SUMMARY-NEXT:                    5 Output PDB strings
@@ -72,6 +75,21 @@ SUMMARY-NEXT:                  167 Global symbol records
 SUMMARY-NEXT:                   20 Module symbol records
 SUMMARY-NEXT:                    3 Public symbol records
 
+SUMMARY-NODEBUG:                                     Summary
+SUMMARY-NODEBUG-NEXT: --------------------------------------------------------------------------------
+SUMMARY-NODEBUG-NEXT:                    3 Input OBJ files (expanded from all cmd-line inputs)
+SUMMARY-NODEBUG-NEXT: Size of all consumed OBJ files (non-lazy), in bytes
+SUMMARY-NODEBUG-NEXT:                    0 PDB type server dependencies
+SUMMARY-NODEBUG-NEXT:                    0 Precomp OBJ dependencies
+SUMMARY-NODEBUG-NEXT:                    0 Input debug type records
+SUMMARY-NODEBUG-NEXT:                    0 Size of all input debug type records, in bytes
+SUMMARY-NODEBUG-NEXT:                    0 Merged TPI records
+SUMMARY-NODEBUG-NEXT:                    0 Merged IPI records
+SUMMARY-NODEBUG-NEXT:                    0 Output PDB strings
+SUMMARY-NODEBUG-NEXT:                    0 Global symbol records
+SUMMARY-NODEBUG-NEXT:                    0 Module symbol records
+SUMMARY-NODEBUG-NEXT:                    0 Public symbol records
+
 // precomp.h
 #pragma once
 int Function(char A);

diff  --git a/lld/test/COFF/precomp-summary-fail.test b/lld/test/COFF/precomp-summary-fail.test
index 0d528c76c2180..5568316ff63c6 100644
--- a/lld/test/COFF/precomp-summary-fail.test
+++ b/lld/test/COFF/precomp-summary-fail.test
@@ -15,8 +15,8 @@ SUMMARY-NEXT:                    2 Input OBJ files (expanded from all cmd-line i
 SUMMARY-NEXT: Size of all consumed OBJ files (non-lazy), in bytes
 SUMMARY-NEXT:                    0 PDB type server dependencies
 SUMMARY-NEXT:                    1 Precomp OBJ dependencies
-SUMMARY-NEXT:                    8 Input type records
-SUMMARY-NEXT:                  232 Size of all input type records, in bytes
+SUMMARY-NEXT:                    8 Input debug type records
+SUMMARY-NEXT:                  232 Size of all input debug type records, in bytes
 SUMMARY-NEXT:                    3 Merged TPI records
 SUMMARY-NEXT:                    2 Merged IPI records
 SUMMARY-NEXT:                    1 Output PDB strings


        


More information about the llvm-commits mailing list