- 
                Notifications
    You must be signed in to change notification settings 
- Fork 15k
[CodeGen][COFF] Always emit CodeView compiler info on Windows targets #142970
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| Depends on #142969. | 
| @llvm/pr-subscribers-debuginfo @llvm/pr-subscribers-clang-codegen Author: Jacek Caban (cjacek) ChangesMSVC always emits minimal CodeView metadata containing compiler information, even when debug info is otherwise disabled. While this data is typically not meaningful on its own, the linker may use it to detect whether the object file was built with hotpatch support. To match this behavior, emit compiler info whenever the hotpatch option is enabled. Full diff: https://github.com/llvm/llvm-project/pull/142970.diff 10 Files Affected: 
 diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index cd5fc48c4a22b..2365f675b2dc3 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -473,7 +473,6 @@ static bool initTargetOptions(const CompilerInstance &CI,
   Options.LoopAlignment = CodeGenOpts.LoopAlignment;
   Options.DebugStrictDwarf = CodeGenOpts.DebugStrictDwarf;
   Options.ObjectFilenameForDebug = CodeGenOpts.ObjectFilenameForDebug;
-  Options.Hotpatch = CodeGenOpts.HotPatch;
   Options.JMCInstrument = CodeGenOpts.JMCInstrument;
   Options.XCOFFReadOnlyPointers = CodeGenOpts.XCOFFReadOnlyPointers;
 
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 468fc6e0e5c56..ddad9a66766fd 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -408,11 +408,11 @@ CodeGenModule::CodeGenModule(ASTContext &C,
     TBAA.reset(new CodeGenTBAA(Context, getTypes(), TheModule, CodeGenOpts,
                                getLangOpts()));
 
-  // If debug info or coverage generation is enabled, create the CGDebugInfo
-  // object.
+  // If debug info, coverage generation or hotpatch is enabled, create the
+  // CGDebugInfo object.
   if (CodeGenOpts.getDebugInfo() != llvm::codegenoptions::NoDebugInfo ||
       CodeGenOpts.CoverageNotesFile.size() ||
-      CodeGenOpts.CoverageDataFile.size())
+      CodeGenOpts.CoverageDataFile.size() || CodeGenOpts.HotPatch)
     DebugInfo.reset(new CGDebugInfo(*this));
 
   Block.GlobalUniqueCount = 0;
@@ -1031,6 +1031,10 @@ void CodeGenModule::Release() {
     // Function ID tables for EH Continuation Guard.
     getModule().addModuleFlag(llvm::Module::Warning, "ehcontguard", 1);
   }
+  if (CodeGenOpts.HotPatch) {
+    // Note if we are compiling with /hotpatch.
+    getModule().addModuleFlag(llvm::Module::Warning, "ms-hotpatch", 1);
+  }
   if (Context.getLangOpts().Kernel) {
     // Note if we are compiling with /kernel.
     getModule().addModuleFlag(llvm::Module::Warning, "ms-kernel", 1);
diff --git a/clang/test/CodeGen/patchable-function-entry.c b/clang/test/CodeGen/patchable-function-entry.c
index 2acd748758490..748d5c8bc5ae3 100644
--- a/clang/test/CodeGen/patchable-function-entry.c
+++ b/clang/test/CodeGen/patchable-function-entry.c
@@ -39,3 +39,5 @@ void f(void) {}
 // HOTPATCH: attributes #1 = { {{.*}} "patchable-function"="prologue-short-redirect"
 // HOTPATCH: attributes #2 = { {{.*}} "patchable-function"="prologue-short-redirect"
 // HOTPATCH: attributes #3 = { {{.*}} "patchable-function"="prologue-short-redirect"
+// HOTPATCH: !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug, splitDebugInlining: false, nameTableKind: None)
+// HOTPATCH: !{{.}} = !{i32 2, !"ms-hotpatch", i32 1}
diff --git a/llvm/include/llvm/Target/TargetOptions.h b/llvm/include/llvm/Target/TargetOptions.h
index fd8dad4f6f791..25bbb73e9dedc 100644
--- a/llvm/include/llvm/Target/TargetOptions.h
+++ b/llvm/include/llvm/Target/TargetOptions.h
@@ -150,7 +150,7 @@ namespace llvm {
           EmitAddrsig(false), BBAddrMap(false), EmitCallSiteInfo(false),
           SupportsDebugEntryValues(false), EnableDebugEntryValues(false),
           ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false),
-          XRayFunctionIndex(true), DebugStrictDwarf(false), Hotpatch(false),
+          XRayFunctionIndex(true), DebugStrictDwarf(false),
           PPCGenScalarMASSEntries(false), JMCInstrument(false),
           EnableCFIFixup(false), MisExpect(false), XCOFFReadOnlyPointers(false),
           VerifyArgABICompliance(true),
@@ -363,9 +363,6 @@ namespace llvm {
     /// By default, it is set to false.
     unsigned DebugStrictDwarf : 1;
 
-    /// Emit the hotpatch flag in CodeView debug.
-    unsigned Hotpatch : 1;
-
     /// Enables scalar MASS conversions
     unsigned PPCGenScalarMASSEntries : 1;
 
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index bcfc64c6f36bb..d58e89dffc5c3 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -561,8 +561,12 @@ bool AsmPrinter::doInitialization(Module &M) {
 
   if (MAI->doesSupportDebugInformation()) {
     bool EmitCodeView = M.getCodeViewFlag();
-    if (EmitCodeView &&
-        (TM.getTargetTriple().isOSWindows() || TM.getTargetTriple().isUEFI()))
+    // MSVC always emits minimal CodeView information with compiler metadata,
+    // even when debug info is otherwise disabled. While it's usually not
+    // meaningful, the linker may use it to detect whether the object file has
+    // hotpatching enabled. Emit compiler info in such cases.
+    if ((TM.getTargetTriple().isOSWindows() || TM.getTargetTriple().isUEFI()) &&
+        (EmitCodeView || M.getModuleFlag("ms-hotpatch")))
       Handlers.push_back(std::make_unique<CodeViewDebug>(this));
     if (!EmitCodeView || M.getDwarfVersion()) {
       if (hasDebugInfo()) {
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index fc43bc6f7776d..a0013fb30aa80 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -613,7 +613,8 @@ static SourceLanguage MapDWLangToCVLang(unsigned DWLang) {
 void CodeViewDebug::beginModule(Module *M) {
   // If module doesn't have named metadata anchors or COFF debug section
   // is not available, skip any debug info related stuff.
-  if (!Asm->hasDebugInfo() ||
+  if (!(Asm->hasDebugInfo() ||
+        MMI->getModule()->getModuleFlag("ms-hotpatch")) ||
       !Asm->getObjFileLowering().getCOFFDebugSymbolsSection()) {
     Asm = nullptr;
     return;
@@ -622,10 +623,21 @@ void CodeViewDebug::beginModule(Module *M) {
   TheCPU = mapArchToCVCPUType(M->getTargetTriple().getArch());
 
   // Get the current source language.
-  const MDNode *Node = *M->debug_compile_units_begin();
+  const MDNode *Node;
+  if (Asm->hasDebugInfo()) {
+    Node = *M->debug_compile_units_begin();
+  } else {
+    // When emitting only compiler information, we may have only NoDebug CUs,
+    // which would be skipped by debug_compile_units_begin.
+    NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu");
+    Node = *CUs->operands().begin();
+  }
   const auto *CU = cast<DICompileUnit>(Node);
 
   CurrentSourceLanguage = MapDWLangToCVLang(CU->getSourceLanguage());
+  NoDebug = !M->getCodeViewFlag();
+  if (NoDebug)
+    return;
 
   collectGlobalVariableInfo();
 
@@ -636,7 +648,7 @@ void CodeViewDebug::beginModule(Module *M) {
 }
 
 void CodeViewDebug::endModule() {
-  if (!Asm || !Asm->hasDebugInfo())
+  if (!Asm)
     return;
 
   // The COFF .debug$S section consists of several subsections, each starting
@@ -653,6 +665,9 @@ void CodeViewDebug::endModule() {
   emitCompilerInformation();
   endCVSubsection(CompilerInfo);
 
+  if (NoDebug)
+    return;
+
   emitInlineeLinesSubsection();
 
   // Emit per-function debug information.
@@ -846,8 +861,8 @@ void CodeViewDebug::emitCompilerInformation() {
   }
   using ArchType = llvm::Triple::ArchType;
   ArchType Arch = MMI->getModule()->getTargetTriple().getArch();
-  if (Asm->TM.Options.Hotpatch || Arch == ArchType::thumb ||
-      Arch == ArchType::aarch64) {
+  if (Arch == ArchType::thumb || Arch == ArchType::aarch64 ||
+      MMI->getModule()->getModuleFlag("ms-hotpatch")) {
     Flags |= static_cast<uint32_t>(CompileSym3Flags::HotPatch);
   }
 
@@ -1440,6 +1455,9 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
 }
 
 void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) {
+  if (NoDebug)
+    return;
+
   const TargetSubtargetInfo &TSI = MF->getSubtarget();
   const TargetRegisterInfo *TRI = TSI.getRegisterInfo();
   const MachineFrameInfo &MFI = MF->getFrameInfo();
@@ -3031,6 +3049,9 @@ void CodeViewDebug::collectLexicalBlockInfo(
 }
 
 void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) {
+  if (NoDebug)
+    return;
+
   const Function &GV = MF->getFunction();
   assert(FnDebugInfo.count(&GV));
   assert(CurFn == FnDebugInfo[&GV].get());
@@ -3089,6 +3110,8 @@ static bool isUsableDebugLoc(DebugLoc DL) {
 
 void CodeViewDebug::beginInstruction(const MachineInstr *MI) {
   DebugHandlerBase::beginInstruction(MI);
+  if (NoDebug)
+    return;
 
   // Ignore DBG_VALUE and DBG_LABEL locations and function prologue.
   if (!Asm || !CurFn || MI->isDebugInstr() ||
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
index d13b315135ad9..3bf3e6db768d7 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
@@ -98,6 +98,9 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
   /// The codeview CPU type used by the translation unit.
   codeview::CPUType TheCPU;
 
+  /// Whether to emit compiler information only.
+  bool NoDebug = false;
+
   static LocalVarDef createDefRangeMem(uint16_t CVRegister, int Offset);
 
   /// Similar to DbgVariable in DwarfDebug, but not dwarf-specific.
diff --git a/llvm/test/DebugInfo/PDB/hotpatch-dwarf.c b/llvm/test/DebugInfo/PDB/hotpatch-dwarf.c
new file mode 100644
index 0000000000000..5b1682ee20efd
--- /dev/null
+++ b/llvm/test/DebugInfo/PDB/hotpatch-dwarf.c
@@ -0,0 +1,59 @@
+; RUN: llc -filetype=obj -o - %s | llvm-readobj --codeview - | FileCheck %s
+
+; ModuleID = 'a.c'
+source_filename = "a.c"
+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-unknown-windows-msvc19.33.0"
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local void @test() #0 !dbg !10 {
+entry:
+  ret void, !dbg !13
+}
+
+attributes #0 = { noinline nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "patchable-function"="prologue-short-redirect" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "a.c", directory: "/tmp")
+!2 = !{i32 7, !"Dwarf Version", i32 4}
+!3 = !{i32 2, !"ms-hotpatch", i32 1}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 2}
+!6 = !{i32 8, !"PIC Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 1, !"MaxTLSAlign", i32 65536}
+!9 = !{!"clang version 21.0.0git"}
+!10 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null}
+!13 = !DILocation(line: 1, column: 14, scope: !10)
+
+
+; CHECK:      CodeViewDebugInfo [
+; CHECK-NEXT:   Section: .debug$S (4)
+; CHECK-NEXT:   Magic: 0x4
+; CHECK-NEXT:   Subsection [
+; CHECK-NEXT:     SubSectionType: Symbols (0xF1)
+; CHECK-NEXT:     SubSectionSize: 0x40
+; CHECK-NEXT:     ObjNameSym {
+; CHECK-NEXT:       Kind: S_OBJNAME (0x1101)
+; CHECK-NEXT:       Signature: 0x0
+; CHECK-NEXT:       ObjectName:
+; CHECK-NEXT:     }
+; CHECK-NEXT:     Compile3Sym {
+; CHECK-NEXT:       Kind: S_COMPILE3 (0x113C)
+; CHECK-NEXT:       Language: C (0x0)
+; CHECK-NEXT:       Flags [ (0x4000)
+; CHECK-NEXT:         HotPatch (0x4000)
+; CHECK-NEXT:       ]
+; CHECK-NEXT:       Machine: X64 (0xD0)
+; CHECK-NEXT:       FrontendVersion: 21.0.0.0
+; CHECK-NEXT:       BackendVersion: 21000.0.0.0
+; CHECK-NEXT:       VersionName: clang version 21.0.0git
+; CHECK-NEXT:     }
+; CHECK-NEXT:   ]
+; CHECK-NEXT: ]
diff --git a/llvm/test/DebugInfo/PDB/hotpatch-nodebug.c b/llvm/test/DebugInfo/PDB/hotpatch-nodebug.c
new file mode 100644
index 0000000000000..abce081746188
--- /dev/null
+++ b/llvm/test/DebugInfo/PDB/hotpatch-nodebug.c
@@ -0,0 +1,57 @@
+; RUN: llc -filetype=obj -o - %s | llvm-readobj --codeview - | FileCheck %s
+
+; ModuleID = 'a.c'
+source_filename = "a.c"
+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-unknown-windows-msvc19.33.0"
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local void @test() #0 !dbg !9 {
+entry:
+  ret void, !dbg !12
+}
+
+attributes #0 = { noinline nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "patchable-function"="prologue-short-redirect" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "a.c", directory: "/tmp")
+!2 = !{i32 2, !"ms-hotpatch", i32 1}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 2}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"uwtable", i32 2}
+!7 = !{i32 1, !"MaxTLSAlign", i32 65536}
+!8 = !{!"clang version 21.0.0git"}
+!9 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 1, type: !10, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
+!10 = !DISubroutineType(types: !11)
+!11 = !{}
+!12 = !DILocation(line: 1, column: 14, scope: !9)
+
+; CHECK:      CodeViewDebugInfo [
+; CHECK-NEXT:   Section: .debug$S (4)
+; CHECK-NEXT:   Magic: 0x4
+; CHECK-NEXT:   Subsection [
+; CHECK-NEXT:     SubSectionType: Symbols (0xF1)
+; CHECK-NEXT:     SubSectionSize: 0x40
+; CHECK-NEXT:     ObjNameSym {
+; CHECK-NEXT:       Kind: S_OBJNAME (0x1101)
+; CHECK-NEXT:       Signature: 0x0
+; CHECK-NEXT:       ObjectName:
+; CHECK-NEXT:     }
+; CHECK-NEXT:     Compile3Sym {
+; CHECK-NEXT:       Kind: S_COMPILE3 (0x113C)
+; CHECK-NEXT:       Language: C (0x0)
+; CHECK-NEXT:       Flags [ (0x4000)
+; CHECK-NEXT:         HotPatch (0x4000)
+; CHECK-NEXT:       ]
+; CHECK-NEXT:       Machine: X64 (0xD0)
+; CHECK-NEXT:       FrontendVersion: 21.0.0.0
+; CHECK-NEXT:       BackendVersion: 21000.0.0.0
+; CHECK-NEXT:       VersionName: clang version 21.0.0git
+; CHECK-NEXT:     }
+; CHECK-NEXT:   ]
+; CHECK-NEXT: ]
diff --git a/llvm/test/DebugInfo/PDB/hotpatch.test b/llvm/test/DebugInfo/PDB/hotpatch.test
new file mode 100644
index 0000000000000..7ff15fa3c69a4
--- /dev/null
+++ b/llvm/test/DebugInfo/PDB/hotpatch.test
@@ -0,0 +1,57 @@
+; RUN: llc -filetype=obj -o - %s | llvm-readobj --codeview - | FileCheck %s
+
+; ModuleID = 'a.c'
+source_filename = "a.c"
+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-unknown-windows-msvc19.33.0"
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local void @test() #0 !dbg !10 {
+entry:
+  ret void, !dbg !13
+}
+
+attributes #0 = { noinline nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "patchable-function"="prologue-short-redirect" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "a.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "c59e1f6192de3124537b024248301dd1")
+!2 = !{i32 2, !"CodeView", i32 1}
+!3 = !{i32 2, !"ms-hotpatch", i32 1}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 2}
+!6 = !{i32 8, !"PIC Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 1, !"MaxTLSAlign", i32 65536}
+!9 = !{!"clang version 21.0.0git"}
+!10 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null}
+!13 = !DILocation(line: 1, scope: !10)
+
+; CHECK:      CodeViewDebugInfo [
+; CHECK-NEXT:   Section: .debug$S (4)
+; CHECK-NEXT:   Magic: 0x4
+; CHECK-NEXT:   Subsection [
+; CHECK-NEXT:     SubSectionType: Symbols (0xF1)
+; CHECK-NEXT:     SubSectionSize: 0x40
+; CHECK-NEXT:     ObjNameSym {
+; CHECK-NEXT:       Kind: S_OBJNAME (0x1101)
+; CHECK-NEXT:       Signature: 0x0
+; CHECK-NEXT:       ObjectName:
+; CHECK-NEXT:     }
+; CHECK-NEXT:     Compile3Sym {
+; CHECK-NEXT:       Kind: S_COMPILE3 (0x113C)
+; CHECK-NEXT:       Language: C (0x0)
+; CHECK-NEXT:       Flags [ (0x4000)
+; CHECK-NEXT:         HotPatch (0x4000)
+; CHECK-NEXT:       ]
+; CHECK-NEXT:       Machine: X64 (0xD0)
+; CHECK-NEXT:       FrontendVersion: 21.0.0.0
+; CHECK-NEXT:       BackendVersion: 21000.0.0.0
+; CHECK-NEXT:       VersionName: clang version 21.0.0git
+; CHECK-NEXT:     }
+; CHECK-NEXT:   ]
 | 
| @llvm/pr-subscribers-clang Author: Jacek Caban (cjacek) ChangesMSVC always emits minimal CodeView metadata containing compiler information, even when debug info is otherwise disabled. While this data is typically not meaningful on its own, the linker may use it to detect whether the object file was built with hotpatch support. To match this behavior, emit compiler info whenever the hotpatch option is enabled. Full diff: https://github.com/llvm/llvm-project/pull/142970.diff 10 Files Affected: 
 diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index cd5fc48c4a22b..2365f675b2dc3 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -473,7 +473,6 @@ static bool initTargetOptions(const CompilerInstance &CI,
   Options.LoopAlignment = CodeGenOpts.LoopAlignment;
   Options.DebugStrictDwarf = CodeGenOpts.DebugStrictDwarf;
   Options.ObjectFilenameForDebug = CodeGenOpts.ObjectFilenameForDebug;
-  Options.Hotpatch = CodeGenOpts.HotPatch;
   Options.JMCInstrument = CodeGenOpts.JMCInstrument;
   Options.XCOFFReadOnlyPointers = CodeGenOpts.XCOFFReadOnlyPointers;
 
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 468fc6e0e5c56..ddad9a66766fd 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -408,11 +408,11 @@ CodeGenModule::CodeGenModule(ASTContext &C,
     TBAA.reset(new CodeGenTBAA(Context, getTypes(), TheModule, CodeGenOpts,
                                getLangOpts()));
 
-  // If debug info or coverage generation is enabled, create the CGDebugInfo
-  // object.
+  // If debug info, coverage generation or hotpatch is enabled, create the
+  // CGDebugInfo object.
   if (CodeGenOpts.getDebugInfo() != llvm::codegenoptions::NoDebugInfo ||
       CodeGenOpts.CoverageNotesFile.size() ||
-      CodeGenOpts.CoverageDataFile.size())
+      CodeGenOpts.CoverageDataFile.size() || CodeGenOpts.HotPatch)
     DebugInfo.reset(new CGDebugInfo(*this));
 
   Block.GlobalUniqueCount = 0;
@@ -1031,6 +1031,10 @@ void CodeGenModule::Release() {
     // Function ID tables for EH Continuation Guard.
     getModule().addModuleFlag(llvm::Module::Warning, "ehcontguard", 1);
   }
+  if (CodeGenOpts.HotPatch) {
+    // Note if we are compiling with /hotpatch.
+    getModule().addModuleFlag(llvm::Module::Warning, "ms-hotpatch", 1);
+  }
   if (Context.getLangOpts().Kernel) {
     // Note if we are compiling with /kernel.
     getModule().addModuleFlag(llvm::Module::Warning, "ms-kernel", 1);
diff --git a/clang/test/CodeGen/patchable-function-entry.c b/clang/test/CodeGen/patchable-function-entry.c
index 2acd748758490..748d5c8bc5ae3 100644
--- a/clang/test/CodeGen/patchable-function-entry.c
+++ b/clang/test/CodeGen/patchable-function-entry.c
@@ -39,3 +39,5 @@ void f(void) {}
 // HOTPATCH: attributes #1 = { {{.*}} "patchable-function"="prologue-short-redirect"
 // HOTPATCH: attributes #2 = { {{.*}} "patchable-function"="prologue-short-redirect"
 // HOTPATCH: attributes #3 = { {{.*}} "patchable-function"="prologue-short-redirect"
+// HOTPATCH: !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug, splitDebugInlining: false, nameTableKind: None)
+// HOTPATCH: !{{.}} = !{i32 2, !"ms-hotpatch", i32 1}
diff --git a/llvm/include/llvm/Target/TargetOptions.h b/llvm/include/llvm/Target/TargetOptions.h
index fd8dad4f6f791..25bbb73e9dedc 100644
--- a/llvm/include/llvm/Target/TargetOptions.h
+++ b/llvm/include/llvm/Target/TargetOptions.h
@@ -150,7 +150,7 @@ namespace llvm {
           EmitAddrsig(false), BBAddrMap(false), EmitCallSiteInfo(false),
           SupportsDebugEntryValues(false), EnableDebugEntryValues(false),
           ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false),
-          XRayFunctionIndex(true), DebugStrictDwarf(false), Hotpatch(false),
+          XRayFunctionIndex(true), DebugStrictDwarf(false),
           PPCGenScalarMASSEntries(false), JMCInstrument(false),
           EnableCFIFixup(false), MisExpect(false), XCOFFReadOnlyPointers(false),
           VerifyArgABICompliance(true),
@@ -363,9 +363,6 @@ namespace llvm {
     /// By default, it is set to false.
     unsigned DebugStrictDwarf : 1;
 
-    /// Emit the hotpatch flag in CodeView debug.
-    unsigned Hotpatch : 1;
-
     /// Enables scalar MASS conversions
     unsigned PPCGenScalarMASSEntries : 1;
 
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index bcfc64c6f36bb..d58e89dffc5c3 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -561,8 +561,12 @@ bool AsmPrinter::doInitialization(Module &M) {
 
   if (MAI->doesSupportDebugInformation()) {
     bool EmitCodeView = M.getCodeViewFlag();
-    if (EmitCodeView &&
-        (TM.getTargetTriple().isOSWindows() || TM.getTargetTriple().isUEFI()))
+    // MSVC always emits minimal CodeView information with compiler metadata,
+    // even when debug info is otherwise disabled. While it's usually not
+    // meaningful, the linker may use it to detect whether the object file has
+    // hotpatching enabled. Emit compiler info in such cases.
+    if ((TM.getTargetTriple().isOSWindows() || TM.getTargetTriple().isUEFI()) &&
+        (EmitCodeView || M.getModuleFlag("ms-hotpatch")))
       Handlers.push_back(std::make_unique<CodeViewDebug>(this));
     if (!EmitCodeView || M.getDwarfVersion()) {
       if (hasDebugInfo()) {
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index fc43bc6f7776d..a0013fb30aa80 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -613,7 +613,8 @@ static SourceLanguage MapDWLangToCVLang(unsigned DWLang) {
 void CodeViewDebug::beginModule(Module *M) {
   // If module doesn't have named metadata anchors or COFF debug section
   // is not available, skip any debug info related stuff.
-  if (!Asm->hasDebugInfo() ||
+  if (!(Asm->hasDebugInfo() ||
+        MMI->getModule()->getModuleFlag("ms-hotpatch")) ||
       !Asm->getObjFileLowering().getCOFFDebugSymbolsSection()) {
     Asm = nullptr;
     return;
@@ -622,10 +623,21 @@ void CodeViewDebug::beginModule(Module *M) {
   TheCPU = mapArchToCVCPUType(M->getTargetTriple().getArch());
 
   // Get the current source language.
-  const MDNode *Node = *M->debug_compile_units_begin();
+  const MDNode *Node;
+  if (Asm->hasDebugInfo()) {
+    Node = *M->debug_compile_units_begin();
+  } else {
+    // When emitting only compiler information, we may have only NoDebug CUs,
+    // which would be skipped by debug_compile_units_begin.
+    NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu");
+    Node = *CUs->operands().begin();
+  }
   const auto *CU = cast<DICompileUnit>(Node);
 
   CurrentSourceLanguage = MapDWLangToCVLang(CU->getSourceLanguage());
+  NoDebug = !M->getCodeViewFlag();
+  if (NoDebug)
+    return;
 
   collectGlobalVariableInfo();
 
@@ -636,7 +648,7 @@ void CodeViewDebug::beginModule(Module *M) {
 }
 
 void CodeViewDebug::endModule() {
-  if (!Asm || !Asm->hasDebugInfo())
+  if (!Asm)
     return;
 
   // The COFF .debug$S section consists of several subsections, each starting
@@ -653,6 +665,9 @@ void CodeViewDebug::endModule() {
   emitCompilerInformation();
   endCVSubsection(CompilerInfo);
 
+  if (NoDebug)
+    return;
+
   emitInlineeLinesSubsection();
 
   // Emit per-function debug information.
@@ -846,8 +861,8 @@ void CodeViewDebug::emitCompilerInformation() {
   }
   using ArchType = llvm::Triple::ArchType;
   ArchType Arch = MMI->getModule()->getTargetTriple().getArch();
-  if (Asm->TM.Options.Hotpatch || Arch == ArchType::thumb ||
-      Arch == ArchType::aarch64) {
+  if (Arch == ArchType::thumb || Arch == ArchType::aarch64 ||
+      MMI->getModule()->getModuleFlag("ms-hotpatch")) {
     Flags |= static_cast<uint32_t>(CompileSym3Flags::HotPatch);
   }
 
@@ -1440,6 +1455,9 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
 }
 
 void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) {
+  if (NoDebug)
+    return;
+
   const TargetSubtargetInfo &TSI = MF->getSubtarget();
   const TargetRegisterInfo *TRI = TSI.getRegisterInfo();
   const MachineFrameInfo &MFI = MF->getFrameInfo();
@@ -3031,6 +3049,9 @@ void CodeViewDebug::collectLexicalBlockInfo(
 }
 
 void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) {
+  if (NoDebug)
+    return;
+
   const Function &GV = MF->getFunction();
   assert(FnDebugInfo.count(&GV));
   assert(CurFn == FnDebugInfo[&GV].get());
@@ -3089,6 +3110,8 @@ static bool isUsableDebugLoc(DebugLoc DL) {
 
 void CodeViewDebug::beginInstruction(const MachineInstr *MI) {
   DebugHandlerBase::beginInstruction(MI);
+  if (NoDebug)
+    return;
 
   // Ignore DBG_VALUE and DBG_LABEL locations and function prologue.
   if (!Asm || !CurFn || MI->isDebugInstr() ||
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
index d13b315135ad9..3bf3e6db768d7 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
@@ -98,6 +98,9 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
   /// The codeview CPU type used by the translation unit.
   codeview::CPUType TheCPU;
 
+  /// Whether to emit compiler information only.
+  bool NoDebug = false;
+
   static LocalVarDef createDefRangeMem(uint16_t CVRegister, int Offset);
 
   /// Similar to DbgVariable in DwarfDebug, but not dwarf-specific.
diff --git a/llvm/test/DebugInfo/PDB/hotpatch-dwarf.c b/llvm/test/DebugInfo/PDB/hotpatch-dwarf.c
new file mode 100644
index 0000000000000..5b1682ee20efd
--- /dev/null
+++ b/llvm/test/DebugInfo/PDB/hotpatch-dwarf.c
@@ -0,0 +1,59 @@
+; RUN: llc -filetype=obj -o - %s | llvm-readobj --codeview - | FileCheck %s
+
+; ModuleID = 'a.c'
+source_filename = "a.c"
+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-unknown-windows-msvc19.33.0"
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local void @test() #0 !dbg !10 {
+entry:
+  ret void, !dbg !13
+}
+
+attributes #0 = { noinline nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "patchable-function"="prologue-short-redirect" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "a.c", directory: "/tmp")
+!2 = !{i32 7, !"Dwarf Version", i32 4}
+!3 = !{i32 2, !"ms-hotpatch", i32 1}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 2}
+!6 = !{i32 8, !"PIC Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 1, !"MaxTLSAlign", i32 65536}
+!9 = !{!"clang version 21.0.0git"}
+!10 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null}
+!13 = !DILocation(line: 1, column: 14, scope: !10)
+
+
+; CHECK:      CodeViewDebugInfo [
+; CHECK-NEXT:   Section: .debug$S (4)
+; CHECK-NEXT:   Magic: 0x4
+; CHECK-NEXT:   Subsection [
+; CHECK-NEXT:     SubSectionType: Symbols (0xF1)
+; CHECK-NEXT:     SubSectionSize: 0x40
+; CHECK-NEXT:     ObjNameSym {
+; CHECK-NEXT:       Kind: S_OBJNAME (0x1101)
+; CHECK-NEXT:       Signature: 0x0
+; CHECK-NEXT:       ObjectName:
+; CHECK-NEXT:     }
+; CHECK-NEXT:     Compile3Sym {
+; CHECK-NEXT:       Kind: S_COMPILE3 (0x113C)
+; CHECK-NEXT:       Language: C (0x0)
+; CHECK-NEXT:       Flags [ (0x4000)
+; CHECK-NEXT:         HotPatch (0x4000)
+; CHECK-NEXT:       ]
+; CHECK-NEXT:       Machine: X64 (0xD0)
+; CHECK-NEXT:       FrontendVersion: 21.0.0.0
+; CHECK-NEXT:       BackendVersion: 21000.0.0.0
+; CHECK-NEXT:       VersionName: clang version 21.0.0git
+; CHECK-NEXT:     }
+; CHECK-NEXT:   ]
+; CHECK-NEXT: ]
diff --git a/llvm/test/DebugInfo/PDB/hotpatch-nodebug.c b/llvm/test/DebugInfo/PDB/hotpatch-nodebug.c
new file mode 100644
index 0000000000000..abce081746188
--- /dev/null
+++ b/llvm/test/DebugInfo/PDB/hotpatch-nodebug.c
@@ -0,0 +1,57 @@
+; RUN: llc -filetype=obj -o - %s | llvm-readobj --codeview - | FileCheck %s
+
+; ModuleID = 'a.c'
+source_filename = "a.c"
+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-unknown-windows-msvc19.33.0"
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local void @test() #0 !dbg !9 {
+entry:
+  ret void, !dbg !12
+}
+
+attributes #0 = { noinline nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "patchable-function"="prologue-short-redirect" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "a.c", directory: "/tmp")
+!2 = !{i32 2, !"ms-hotpatch", i32 1}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!4 = !{i32 1, !"wchar_size", i32 2}
+!5 = !{i32 8, !"PIC Level", i32 2}
+!6 = !{i32 7, !"uwtable", i32 2}
+!7 = !{i32 1, !"MaxTLSAlign", i32 65536}
+!8 = !{!"clang version 21.0.0git"}
+!9 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 1, type: !10, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
+!10 = !DISubroutineType(types: !11)
+!11 = !{}
+!12 = !DILocation(line: 1, column: 14, scope: !9)
+
+; CHECK:      CodeViewDebugInfo [
+; CHECK-NEXT:   Section: .debug$S (4)
+; CHECK-NEXT:   Magic: 0x4
+; CHECK-NEXT:   Subsection [
+; CHECK-NEXT:     SubSectionType: Symbols (0xF1)
+; CHECK-NEXT:     SubSectionSize: 0x40
+; CHECK-NEXT:     ObjNameSym {
+; CHECK-NEXT:       Kind: S_OBJNAME (0x1101)
+; CHECK-NEXT:       Signature: 0x0
+; CHECK-NEXT:       ObjectName:
+; CHECK-NEXT:     }
+; CHECK-NEXT:     Compile3Sym {
+; CHECK-NEXT:       Kind: S_COMPILE3 (0x113C)
+; CHECK-NEXT:       Language: C (0x0)
+; CHECK-NEXT:       Flags [ (0x4000)
+; CHECK-NEXT:         HotPatch (0x4000)
+; CHECK-NEXT:       ]
+; CHECK-NEXT:       Machine: X64 (0xD0)
+; CHECK-NEXT:       FrontendVersion: 21.0.0.0
+; CHECK-NEXT:       BackendVersion: 21000.0.0.0
+; CHECK-NEXT:       VersionName: clang version 21.0.0git
+; CHECK-NEXT:     }
+; CHECK-NEXT:   ]
+; CHECK-NEXT: ]
diff --git a/llvm/test/DebugInfo/PDB/hotpatch.test b/llvm/test/DebugInfo/PDB/hotpatch.test
new file mode 100644
index 0000000000000..7ff15fa3c69a4
--- /dev/null
+++ b/llvm/test/DebugInfo/PDB/hotpatch.test
@@ -0,0 +1,57 @@
+; RUN: llc -filetype=obj -o - %s | llvm-readobj --codeview - | FileCheck %s
+
+; ModuleID = 'a.c'
+source_filename = "a.c"
+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-unknown-windows-msvc19.33.0"
+
+; Function Attrs: noinline nounwind optnone uwtable
+define dso_local void @test() #0 !dbg !10 {
+entry:
+  ret void, !dbg !13
+}
+
+attributes #0 = { noinline nounwind optnone uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "patchable-function"="prologue-short-redirect" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "a.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "c59e1f6192de3124537b024248301dd1")
+!2 = !{i32 2, !"CodeView", i32 1}
+!3 = !{i32 2, !"ms-hotpatch", i32 1}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 2}
+!6 = !{i32 8, !"PIC Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 1, !"MaxTLSAlign", i32 65536}
+!9 = !{!"clang version 21.0.0git"}
+!10 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, spFlags: DISPFlagDefinition, unit: !0)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null}
+!13 = !DILocation(line: 1, scope: !10)
+
+; CHECK:      CodeViewDebugInfo [
+; CHECK-NEXT:   Section: .debug$S (4)
+; CHECK-NEXT:   Magic: 0x4
+; CHECK-NEXT:   Subsection [
+; CHECK-NEXT:     SubSectionType: Symbols (0xF1)
+; CHECK-NEXT:     SubSectionSize: 0x40
+; CHECK-NEXT:     ObjNameSym {
+; CHECK-NEXT:       Kind: S_OBJNAME (0x1101)
+; CHECK-NEXT:       Signature: 0x0
+; CHECK-NEXT:       ObjectName:
+; CHECK-NEXT:     }
+; CHECK-NEXT:     Compile3Sym {
+; CHECK-NEXT:       Kind: S_COMPILE3 (0x113C)
+; CHECK-NEXT:       Language: C (0x0)
+; CHECK-NEXT:       Flags [ (0x4000)
+; CHECK-NEXT:         HotPatch (0x4000)
+; CHECK-NEXT:       ]
+; CHECK-NEXT:       Machine: X64 (0xD0)
+; CHECK-NEXT:       FrontendVersion: 21.0.0.0
+; CHECK-NEXT:       BackendVersion: 21000.0.0.0
+; CHECK-NEXT:       VersionName: clang version 21.0.0git
+; CHECK-NEXT:     }
+; CHECK-NEXT:   ]
 | 
| MSVC emits this debug section at all times (S_OBJNAME and S_COMPILE3). Can't we do the same without checking for the  | 
| The other a bit related point to this, is perhaps we should re-evaluate enabling  | 
| I think we could emit this unconditionally, but I wasn’t entirely sure, so I went with a less invasive change for now. I'll prepare a new version. In this version, Clang emits a full debug IR, but if we're going to do this by default, it probably makes more sense to emit just a minimal  Also, enabling  | 
| 
 Yes, I think one of my worry regarding that is increase in build times, since now we would be spawing a  
 When I added that flag, I noted different preludes being generated with  | 
| 
 I would much rather do this: we have other internal tooling withing Microsoft that relies on being able to check what compiler built a module (although we always enable debug info - but it would good to have this in case a team forgot to enable it). | 
| The new version always emits  I wasn't sure whether to enable this for UEFI targets as well, so I didn't. I enabled it for MinGW targets too, since I saw no reason to treat them differently. | 
| 
 AFAIK only recent GCC toolchain supports codeview. I am not sure GDB even does, so this could be a problem. | 
| codeview::CPUType TheCPU; | ||
|  | ||
| /// Whether to emit compiler information only. | ||
| bool NoDebug = false; | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be clearer reading the code above if we named this OnlyCompilerInfo.
| } | ||
|  | ||
| void CodeViewDebug::beginModule(Module *M) { | ||
| // If module doesn't have named metadata anchors or COFF debug section | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adjust comment.
| M.getNamedMetadata("llvm.dbg.cu")) | ||
| Handlers.push_back(std::make_unique<CodeViewDebug>(this)); | ||
| if (!EmitCodeView || M.getDwarfVersion()) { | ||
| if (M.getDwarfVersion() || !M.getCodeViewFlag()) { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just being picky here, but can you please leave the condition in the same order to ease downstream integrations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. I initially reordered the other check as well but reverted it to keep the more expensive check later. Thanks!
| 
 Hmm, so a "regular" mingw object file would end up having both DWARF (if building with  | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you understand what is happening here? I don't understand why this would change....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test emits DWARF debug info, which results in two debug handlers, both emitting labels and causing duplication. I think we can avoid this; I'll take a closer look.
| 
 Yes. 
 I don’t think it should cause any confusion, and my testing confirms that. LLD stores debug chunks separately when reading COFF files in  
 The discard I mentioned above appears to predate CodeView support, git blame shows it was part of the initial import to CVS in 1999. Note that with this change, we’d still use DWARF by default for actual debug info on MinGW; the CodeView compiler info is just an addition. | 
MSVC always emits minimal CodeView metadata with compiler information, even when debug info is otherwise disabled. Other tools may rely on this metadata being present. For example, linkers use it to determine whether hotpatching is enabled for the object file.
| The new version avoids creating unnecessary labels (and most of  | 
| Merged, thanks! | 
…t (NFC) Fixes test from #142970 on Fuchsia CI, which uses "Fuchsia clang version" prefix.
…llvm#142970) MSVC always emits minimal CodeView metadata with compiler information, even when debug info is otherwise disabled. Other tools may rely on this metadata being present. For example, linkers use it to determine whether hotpatching is enabled for the object file.
…t (NFC) Fixes test from llvm#142970 on Fuchsia CI, which uses "Fuchsia clang version" prefix.
…llvm#142970) MSVC always emits minimal CodeView metadata with compiler information, even when debug info is otherwise disabled. Other tools may rely on this metadata being present. For example, linkers use it to determine whether hotpatching is enabled for the object file.
…t (NFC) Fixes test from llvm#142970 on Fuchsia CI, which uses "Fuchsia clang version" prefix.
MSVC always emits minimal CodeView metadata with compiler information, even when debug info is otherwise disabled. Other tools may rely on this metadata being present. For example, linkers use it to determine whether hotpatching is enabled for the object file.