diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 468fc6e0e5c56..8b67a7f68cf6a 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -414,6 +414,11 @@ CodeGenModule::CodeGenModule(ASTContext &C, CodeGenOpts.CoverageNotesFile.size() || CodeGenOpts.CoverageDataFile.size()) DebugInfo.reset(new CGDebugInfo(*this)); + else if (getTriple().isOSWindows()) + // On Windows targets, we want to emit compiler info even if debug info is + // otherwise disabled. Use a temporary CGDebugInfo instance to emit only + // basic compiler metadata. + CGDebugInfo(*this); Block.GlobalUniqueCount = 0; diff --git a/clang/test/CodeGenCXX/debug-info-coff.cpp b/clang/test/CodeGenCXX/debug-info-coff.cpp new file mode 100644 index 0000000000000..4507f5f40d411 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-coff.cpp @@ -0,0 +1,37 @@ +// REQUIRES: x86-registered-target + +// Check that CodeView compiler version is emitted even when debug info is otherwise disabled. + +// RUN: %clang --target=i686-pc-windows-msvc -S -emit-llvm %s -o - | FileCheck --check-prefix=IR %s +// IR: !llvm.dbg.cu = !{!0} +// IR: !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version {{.*}}", isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug, splitDebugInlining: false, nameTableKind: None) + +// RUN: %clang --target=i686-pc-windows-msvc -c %s -o %t.o +// RUN: llvm-readobj --codeview %t.o | FileCheck %s +// CHECK: CodeViewDebugInfo [ +// CHECK-NEXT: Section: .debug$S (4) +// CHECK-NEXT: Magic: 0x4 +// CHECK-NEXT: Subsection [ +// CHECK-NEXT: SubSectionType: Symbols (0xF1) +// CHECK-NEXT: SubSectionSize: +// 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: Cpp (0x1) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Machine: Pentium3 (0x7) +// CHECK-NEXT: FrontendVersion: +// CHECK-NEXT: BackendVersion: +// CHECK-NEXT: VersionName: clang version +// CHECK-NEXT: } +// CHECK-NEXT: ] +// CHECK-NEXT: ] + +int main() { + return 0; +} diff --git a/clang/test/CodeGenCXX/debug-info-hotpatch-aarch64.cpp b/clang/test/CodeGenCXX/debug-info-hotpatch-aarch64.cpp index 10fb1750f2c55..ff2dfc19961c0 100644 --- a/clang/test/CodeGenCXX/debug-info-hotpatch-aarch64.cpp +++ b/clang/test/CodeGenCXX/debug-info-hotpatch-aarch64.cpp @@ -11,12 +11,9 @@ // RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=HOTPATCH // HOTPATCH: S_COMPILE3 [size = [[#]]] // HOTPATCH: flags = hot patchable -/// -/// Unfortunately we need /Z7, Clang does not systematically generate S_COMPILE3. -/// +// // RUN: %clang_cl --target=aarch64-pc-windows-msvc /c -o %t.obj -- %s -// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=NO-HOTPATCH -// NO-HOTPATCH-NOT: flags = hot patchable +// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=HOTPATCH int main() { return 0; diff --git a/clang/test/CodeGenCXX/debug-info-hotpatch-arm.cpp b/clang/test/CodeGenCXX/debug-info-hotpatch-arm.cpp index 48a61f7fb1977..e31c762b08872 100644 --- a/clang/test/CodeGenCXX/debug-info-hotpatch-arm.cpp +++ b/clang/test/CodeGenCXX/debug-info-hotpatch-arm.cpp @@ -11,12 +11,9 @@ // RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=HOTPATCH // HOTPATCH: S_COMPILE3 [size = [[#]]] // HOTPATCH: flags = hot patchable -/// -/// Unfortunately we need /Z7, Clang does not systematically generate S_COMPILE3. -/// +// // RUN: %clang_cl --target=arm-pc-windows-msvc /c -o %t.obj -- %s -// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=NO-HOTPATCH -// NO-HOTPATCH-NOT: flags = hot patchable +// RUN: llvm-pdbutil dump -symbols %t.obj | FileCheck %s --check-prefix=HOTPATCH int main() { return 0; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index bcfc64c6f36bb..c442741d2a407 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -560,9 +560,12 @@ bool AsmPrinter::doInitialization(Module &M) { } if (MAI->doesSupportDebugInformation()) { + // On Windows targets, emit minimal CodeView compiler info even when debug + // info is disabled. bool EmitCodeView = M.getCodeViewFlag(); - if (EmitCodeView && - (TM.getTargetTriple().isOSWindows() || TM.getTargetTriple().isUEFI())) + if ((TM.getTargetTriple().isOSWindows() && + M.getNamedMetadata("llvm.dbg.cu")) || + (TM.getTargetTriple().isUEFI() && EmitCodeView)) Handlers.push_back(std::make_unique(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..08da2d3835472 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -611,21 +611,32 @@ 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() || - !Asm->getObjFileLowering().getCOFFDebugSymbolsSection()) { + // If COFF debug section is not available, skip any debug info related stuff. + if (!Asm->getObjFileLowering().getCOFFDebugSymbolsSection()) { Asm = nullptr; return; } + CompilerInfoAsm = Asm; 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(Node); CurrentSourceLanguage = MapDWLangToCVLang(CU->getSourceLanguage()); + if (!M->getCodeViewFlag() || CU->getEmissionKind() == DICompileUnit::NoDebug) { + Asm = nullptr; + return; + } collectGlobalVariableInfo(); @@ -636,7 +647,7 @@ void CodeViewDebug::beginModule(Module *M) { } void CodeViewDebug::endModule() { - if (!Asm || !Asm->hasDebugInfo()) + if (!CompilerInfoAsm) return; // The COFF .debug$S section consists of several subsections, each starting @@ -652,6 +663,8 @@ void CodeViewDebug::endModule() { emitObjName(); emitCompilerInformation(); endCVSubsection(CompilerInfo); + if (!Asm) + return; emitInlineeLinesSubsection(); @@ -788,7 +801,7 @@ void CodeViewDebug::emitTypeGlobalHashes() { void CodeViewDebug::emitObjName() { MCSymbol *CompilerEnd = beginSymbolRecord(SymbolKind::S_OBJNAME); - StringRef PathRef(Asm->TM.Options.ObjectFilenameForDebug); + StringRef PathRef(CompilerInfoAsm->TM.Options.ObjectFilenameForDebug); llvm::SmallString<256> PathStore(PathRef); if (PathRef.empty() || PathRef == "-") { @@ -846,7 +859,7 @@ void CodeViewDebug::emitCompilerInformation() { } using ArchType = llvm::Triple::ArchType; ArchType Arch = MMI->getModule()->getTargetTriple().getArch(); - if (Asm->TM.Options.Hotpatch || Arch == ArchType::thumb || + if (CompilerInfoAsm->TM.Options.Hotpatch || Arch == ArchType::thumb || Arch == ArchType::aarch64) { Flags |= static_cast(CompileSym3Flags::HotPatch); } @@ -1015,7 +1028,7 @@ void CodeViewDebug::switchToDebugSectionForSymbol(const MCSymbol *GVSym) { const MCSymbol *KeySym = GVSec ? GVSec->getCOMDATSymbol() : nullptr; MCSectionCOFF *DebugSec = cast( - Asm->getObjFileLowering().getCOFFDebugSymbolsSection()); + CompilerInfoAsm->getObjFileLowering().getCOFFDebugSymbolsSection()); DebugSec = OS.getContext().getAssociativeCOFFSection(DebugSec, KeySym); OS.switchSection(DebugSec); diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h index d13b315135ad9..d7613c761682c 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. + AsmPrinter *CompilerInfoAsm = nullptr; + static LocalVarDef createDefRangeMem(uint16_t CVRegister, int Offset); /// Similar to DbgVariable in DwarfDebug, but not dwarf-specific. diff --git a/llvm/test/DebugInfo/COFF/dwarf-headers.ll b/llvm/test/DebugInfo/COFF/dwarf-headers.ll index 9d515f6cec640..919068e966041 100644 --- a/llvm/test/DebugInfo/COFF/dwarf-headers.ll +++ b/llvm/test/DebugInfo/COFF/dwarf-headers.ll @@ -43,6 +43,33 @@ ; DWO-4: 0x00000000: Compile Unit: {{.*}} version = 0x0004, abbr_offset ; DWO-4: 0x0000000b: DW_TAG_compile_unit +; Check that basic CodeView compiler info is emitted even when the DWARF debug format is used. +; RUN: llc -dwarf-version=4 \ +; RUN: -filetype=obj -O0 -mtriple=x86_64-unknown-windows-msvc < %s \ +; RUN: | llvm-readobj --codeview - | FileCheck %s --check-prefix=CODEVIEW +; CODEVIEW: CodeViewDebugInfo [ +; CODEVIEW-NEXT: Section: .debug$S (4) +; CODEVIEW-NEXT: Magic: 0x4 +; CODEVIEW-NEXT: Subsection [ +; CODEVIEW-NEXT: SubSectionType: Symbols (0xF1) +; CODEVIEW-NEXT: SubSectionSize: 0x90 +; CODEVIEW-NEXT: ObjNameSym { +; CODEVIEW-NEXT: Kind: S_OBJNAME (0x1101) +; CODEVIEW-NEXT: Signature: 0x0 +; CODEVIEW-NEXT: ObjectName: +; CODEVIEW-NEXT: } +; CODEVIEW-NEXT: Compile3Sym { +; CODEVIEW-NEXT: Kind: S_COMPILE3 (0x113C) +; CODEVIEW-NEXT: Language: Cpp (0x1) +; CODEVIEW-NEXT: Flags [ (0x0) +; CODEVIEW-NEXT: ] +; CODEVIEW-NEXT: Machine: X64 (0xD0) +; CODEVIEW-NEXT: FrontendVersion: 17.0.0.0 +; CODEVIEW-NEXT: BackendVersion: +; CODEVIEW-NEXT: VersionName: clang version 17.0.0 +; CODEVIEW-NEXT: } +; CODEVIEW-NEXT: ] +; CODEVIEW-NEXT: ] ; ModuleID = 't.cpp' source_filename = "t.cpp" diff --git a/llvm/test/DebugInfo/COFF/emission-kind-no-codeview.ll b/llvm/test/DebugInfo/COFF/emission-kind-no-codeview.ll new file mode 100644 index 0000000000000..792aaeef483f1 --- /dev/null +++ b/llvm/test/DebugInfo/COFF/emission-kind-no-codeview.ll @@ -0,0 +1,38 @@ +; RUN: llc -filetype=obj -o - < %s | llvm-readobj --codeview - | FileCheck %s +; Check that basic CodeView compiler info is emitted even when the CodeView flag is not set. + +; CHECK-NOT: CodeViewTypes +; CHECK: CodeViewDebugInfo [ +; CHECK-NEXT: Section: .debug$S (4) +; CHECK-NEXT: Magic: 0x4 +; CHECK-NEXT: Subsection [ +; CHECK-NEXT: SubSectionType: Symbols (0xF1) +; CHECK-NEXT: SubSectionSize: 0x2C +; 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 [ (0x0) +; CHECK-NEXT: ] +; CHECK-NEXT: Machine: X64 (0xD0) +; CHECK-NEXT: FrontendVersion: +; CHECK-NEXT: BackendVersion: +; CHECK-NEXT: VersionName: clang +; CHECK-NEXT: } +; CHECK-NEXT: ] +; CHECK-NEXT: ] + +source_filename = "empty" +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.0.24215" + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2} + +!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "clang", emissionKind: NoDebug) +!1 = !DIFile(filename: "empty", directory: "path/to") +!2 = !{i32 2, !"Debug Info Version", i32 3} diff --git a/llvm/test/DebugInfo/COFF/emission-kind-no-debug.ll b/llvm/test/DebugInfo/COFF/emission-kind-no-debug.ll index 4204df512ac31..94fee0e1812fd 100644 --- a/llvm/test/DebugInfo/COFF/emission-kind-no-debug.ll +++ b/llvm/test/DebugInfo/COFF/emission-kind-no-debug.ll @@ -1,8 +1,30 @@ ; RUN: llc -filetype=obj -o - < %s | llvm-readobj --codeview - | FileCheck %s -; Check that debug info isn't emitted for CodeView with emissionKind NoDebug +; Check that only basic compiler info is emitted for CodeView with emissionKind NoDebug -; CHECK-NOT: CodeViewTypes -; CHECK-NOT: CodeViewDebugInfo +; CHECK-NOT: CodeViewTypes +; CHECK: CodeViewDebugInfo [ +; CHECK-NEXT: Section: .debug$S (4) +; CHECK-NEXT: Magic: 0x4 +; CHECK-NEXT: Subsection [ +; CHECK-NEXT: SubSectionType: Symbols (0xF1) +; CHECK-NEXT: SubSectionSize: 0x2C +; 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 [ (0x0) +; CHECK-NEXT: ] +; CHECK-NEXT: Machine: X64 (0xD0) +; CHECK-NEXT: FrontendVersion: +; CHECK-NEXT: BackendVersion: +; CHECK-NEXT: VersionName: clang +; CHECK-NEXT: } +; CHECK-NEXT: ] +; CHECK-NEXT: ] source_filename = "empty" target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" diff --git a/llvm/test/DebugInfo/COFF/fission-cu.ll b/llvm/test/DebugInfo/COFF/fission-cu.ll index 3afcb8717e31f..dcc3fdd2efa75 100644 --- a/llvm/test/DebugInfo/COFF/fission-cu.ll +++ b/llvm/test/DebugInfo/COFF/fission-cu.ll @@ -107,11 +107,11 @@ source_filename = "test/DebugInfo/X86/fission-cu.ll" ; For COFF we should have this set of relocations for the debug info section ; ; OBJ: .debug_info -; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_abbrev (6) -; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_line (26) -; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_str (10) -; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_str (10) -; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_addr (20) +; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_abbrev (8) +; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_line (28) +; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_str (12) +; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_str (12) +; OBJ-NEXT: IMAGE_REL_AMD64_SECREL .debug_addr (22) ; OBJ-NEXT: } ; HDR-NOT: .debug_aranges diff --git a/llvm/test/DebugInfo/COFF/fission-sections.ll b/llvm/test/DebugInfo/COFF/fission-sections.ll index 754e2b888c202..c16a4d072909e 100644 --- a/llvm/test/DebugInfo/COFF/fission-sections.ll +++ b/llvm/test/DebugInfo/COFF/fission-sections.ll @@ -27,13 +27,14 @@ source_filename = "test/DebugInfo/X86/fission-cu.ll" ; OBJ-NEXT: 0 .text ; OBJ-NEXT: 1 .data ; OBJ-NEXT: 2 .bss -; OBJ-NEXT: 3 .debug_abbrev -; OBJ-NEXT: 4 .debug_info -; OBJ-NEXT: 5 .debug_str -; OBJ-NEXT: 6 .debug_addr -; OBJ-NEXT: 7 .debug_pubnames -; OBJ-NEXT: 8 .debug_pubtypes -; OBJ-NEXT: 9 .debug_line +; OBJ-NEXT: 3 .debug$S +; OBJ-NEXT: 4 .debug_abbrev +; OBJ-NEXT: 5 .debug_info +; OBJ-NEXT: 6 .debug_str +; OBJ-NEXT: 7 .debug_addr +; OBJ-NEXT: 8 .debug_pubnames +; OBJ-NEXT: 9 .debug_pubtypes +; OBJ-NEXT: 10 .debug_line ; OBJ: .debug_abbrev ; OBJ: .debug_info diff --git a/llvm/test/DebugInfo/COFF/uefi-nodebug.ll b/llvm/test/DebugInfo/COFF/uefi-nodebug.ll new file mode 100644 index 0000000000000..92e5fd6b5796b --- /dev/null +++ b/llvm/test/DebugInfo/COFF/uefi-nodebug.ll @@ -0,0 +1,16 @@ +; RUN: llc -filetype=obj -o - < %s | llvm-readobj --codeview - | FileCheck %s +; Check that compiler info is not emitted when CodeView flag is not specified + +; CHECK-NOT: CodeViewTypes +; CHECK-NOT: CodeViewDebugInfo + +source_filename = "empty" +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-uefi" + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2} + +!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "clang", emissionKind: NoDebug) +!1 = !DIFile(filename: "empty", directory: "path/to") +!2 = !{i32 2, !"Debug Info Version", i32 3}