diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -201,6 +201,9 @@ // Array of non-COMDAT global variables. SmallVector GlobalVariables; + // Array of global variable constants, for emitting S_CONSTANT records. + SmallVector GlobalVariableConstants; + /// The set of comdat .debug$S sections that we've seen so far. Each section /// must start with a magic version number that must only be emitted once. /// This set tracks which sections we've already opened. @@ -313,6 +316,8 @@ void emitDebugInfoForGlobals(); void emitGlobalVariableList(ArrayRef Globals); + void + emitGlobalConstantList(ArrayRef GVEs); void emitDebugInfoForGlobal(const DIGlobalVariable *DIGV, const GlobalVariable *GV, MCSymbol *GVSym); diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -41,6 +41,7 @@ #include "llvm/Config/llvm-config.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h" #include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h" #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" @@ -66,6 +67,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" @@ -2926,9 +2928,40 @@ } } +void CodeViewDebug::emitGlobalConstantList( + ArrayRef GVEs) { + // FIXME: Currently this only emits the global variables in the IR metadata. + // This should also emit enums and static data members. + for (const DIGlobalVariableExpression *GVE : GVEs) { + const DIGlobalVariable *DIGV = GVE->getVariable(); + const DIExpression *Expr = GVE->getExpression(); + + if (!Expr->isConstant()) + continue; + uint64_t Val = Expr->getElement(1); + + MCSymbol *SConstantEnd = beginSymbolRecord(SymbolKind::S_CONSTANT); + OS.AddComment("Type"); + OS.EmitIntValue(getTypeIndex(DIGV->getType()).getIndex(), 4); + OS.AddComment("Value"); + + uint8_t data[64]; + BinaryStreamWriter Writer(data, llvm::support::endianness::little); + CodeViewRecordIO IO(Writer); + cantFail(IO.mapEncodedInteger(Val)); + StringRef SRef((char *)data, Writer.getOffset()); + OS.EmitBinaryData(SRef); + + OS.AddComment("Name"); + emitNullTerminatedSymbolName(OS, DIGV->getDisplayName()); + endSymbolRecord(SConstantEnd); + } +} + void CodeViewDebug::collectGlobalVariableInfo() { DenseMap GlobalMap; + for (const GlobalVariable &GV : MMI->getModule()->globals()) { SmallVector GVEs; GV.getDebugInfo(GVEs); @@ -2940,9 +2973,16 @@ for (const MDNode *Node : CUs->operands()) { const auto *CU = cast(Node); for (const auto *GVE : CU->getGlobalVariables()) { + // Emit constant global variables in a global symbol section. + // Assume that all globals not in GlobalMap are constants. + if (GlobalMap.count(GVE) == 0) + GlobalVariableConstants.push_back(GVE); + const auto *GV = GlobalMap.lookup(GVE); + if (!GV || GV->isDeclarationForLinker()) continue; + const DIGlobalVariable *DIGV = GVE->getVariable(); DIScope *Scope = DIGV->getScope(); SmallVector *VariableList; @@ -2958,7 +2998,7 @@ // Emit this global variable into a COMDAT section. VariableList = &ComdatVariables; else - // Emit this globla variable in a single global symbol section. + // Emit this global variable in a single global symbol section. VariableList = &GlobalVariables; CVGlobalVariable CVGV = {DIGV, GV}; VariableList->emplace_back(std::move(CVGV)); @@ -2971,10 +3011,12 @@ // substream. MSVC doesn't like it if the substream is empty, so only open // it if we have at least one global to emit. switchToDebugSectionForSymbol(nullptr); - if (!GlobalVariables.empty()) { + + if (!GlobalVariables.empty() || !GlobalVariableConstants.empty()) { OS.AddComment("Symbol subsection for globals"); MCSymbol *EndLabel = beginCVSubsection(DebugSubsectionKind::Symbols); emitGlobalVariableList(GlobalVariables); + emitGlobalConstantList(GlobalVariableConstants); endCVSubsection(EndLabel); } diff --git a/llvm/test/DebugInfo/COFF/global-constants.ll b/llvm/test/DebugInfo/COFF/global-constants.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/COFF/global-constants.ll @@ -0,0 +1,64 @@ +; RUN: llc < %s | FileCheck %s --check-prefix=ASM +; RUN: llc < %s -filetype=obj | llvm-readobj - --codeview | FileCheck %s --check-prefix=OBJ + +; C++ source to regenerate: +; const int Test1 = 1; +; int main() { +; return Test1; +; } +; $ clang t.cpp -S -emit-llvm -g -gcodeview -o t.ll + +; ASM-LABEL: .long 241 # Symbol subsection for globals + +; ASM: .short {{.*-.*}} # Record length +; ASM: .short 4359 # Record kind: S_CONSTANT +; ASM-NEXT: .long 4099 # Type +; ASM-NEXT: .byte 0x01, 0x00 # Value +; ASM-NEXT: .asciz "Test1" # Name + +; OBJ: CodeViewDebugInfo [ +; OBJ: Section: .debug$S +; OBJ: Magic: 0x4 +; OBJ: Subsection [ +; OBJ: SubSectionType: Symbols (0xF1) +; OBJ: ConstantSym { +; OBJ-NEXT: Kind: S_CONSTANT (0x1107) +; OBJ-NEXT: Type: const int (0x1003) +; OBJ-NEXT: Value: 1 +; OBJ-NEXT: Name: Test1 +; OBJ-NEXT: } + +; ModuleID = 't.cpp' +source_filename = "t.cpp" +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +; Function Attrs: noinline norecurse nounwind optnone +define dso_local i32 @main() #0 !dbg !13 { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + ret i32 1, !dbg !16 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 9.0.0 (https://github.com/llvm/llvm-project.git 4a1902b6739e3087a03c0ac7ab85b640764e9335)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3, nameTableKind: None) +!1 = !DIFile(filename: "", directory: "C:\5Csrc\5Ctest", checksumkind: CSK_MD5, checksum: "0d5ef00bdd80bdb409a3deac9938f20d") +!2 = !{} +!3 = !{!4} +!4 = !DIGlobalVariableExpression(var: !5, expr: !DIExpression(DW_OP_constu, 1, DW_OP_stack_value)) +!5 = distinct !DIGlobalVariable(name: "Test1", scope: !0, file: !6, line: 1, type: !7, isLocal: true, isDefinition: true) +!6 = !DIFile(filename: "t.cpp", directory: "C:\5Csrc\5Ctest", checksumkind: CSK_MD5, checksum: "0d5ef00bdd80bdb409a3deac9938f20d") +!7 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !8) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = !{i32 2, !"CodeView", i32 1} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"wchar_size", i32 2} +!12 = !{!"clang version 9.0.0 (https://github.com/llvm/llvm-project.git 4a1902b6739e3087a03c0ac7ab85b640764e9335)"} +!13 = distinct !DISubprogram(name: "main", scope: !6, file: !6, line: 3, type: !14, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!14 = !DISubroutineType(types: !15) +!15 = !{!8} +!16 = !DILocation(line: 4, scope: !13)