Index: lib/CodeGen/AsmPrinter/CodeViewDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -190,6 +190,8 @@ void emitTypeInformation(); + void emitCompilerInformation(); + void emitInlineeLinesSubsection(); void emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI); Index: lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/TinyPtrVector.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/EnumTables.h" #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" @@ -494,6 +495,120 @@ }); } +static SourceLanguage MapDWLangToCVLang(unsigned DWLang) { + switch (DWLang) { + case dwarf::DW_LANG_C: + case dwarf::DW_LANG_C89: + case dwarf::DW_LANG_C99: + case dwarf::DW_LANG_C11: + case dwarf::DW_LANG_ObjC: + return SourceLanguage::C; + case dwarf::DW_LANG_C_plus_plus: + case dwarf::DW_LANG_C_plus_plus_03: + case dwarf::DW_LANG_C_plus_plus_11: + case dwarf::DW_LANG_C_plus_plus_14: + return SourceLanguage::Cpp; + case dwarf::DW_LANG_Fortran77: + case dwarf::DW_LANG_Fortran90: + case dwarf::DW_LANG_Fortran03: + case dwarf::DW_LANG_Fortran08: + return SourceLanguage::Fortran; + case dwarf::DW_LANG_Pascal83: + return SourceLanguage::Pascal; + case dwarf::DW_LANG_Cobol74: + case dwarf::DW_LANG_Cobol85: + return SourceLanguage::Cobol; + case dwarf::DW_LANG_Java: + return SourceLanguage::Java; + default: + // There's no CodeView representation for this language, and CV doesn't + // have an "unknown" option for the language field, so we'll use MASM, + // as it's very low level. + return SourceLanguage::Masm; + } +} + +static CPUType MapCPUtoCVCPU(StringRef Name) { + // There's no direct mapping between LLVM's architecture and CodeView's. + // The Microsoft compiler /arch option is mainly about which SIMD instruction + // sets the target processor is expected to have. The clang-cl driver maps + // Microsoft /arch options to these LLVM architectures (see getX86TargetCPU in + // clang/lib/Driver/Tools.cpp). This attempts to map those LLVM architectures + // into CodeView architectures. + return llvm::StringSwitch(Name) + .Case("i386", CPUType::Intel80386) + .Case("pentium3", CPUType::Pentium3) + .Case("pentium4", CPUType::Pentium3) + .Case("sandybridge", CPUType::Ia64) + .Case("haswell", CPUType::Ia64_2) + .Case("i686", CPUType::PentiumPro) + .Default(CPUType::Intel80386); // CodeView doesn't have an "unknown" arch. +} + +struct Version { + int Part[4]; +}; + +// Takes a StringRef like "clang 4.0.0.0" and parses out the version number. +static Version ParseVersion(StringRef Name) { + Version V = {0, 0, 0, 0}; + int N = 0; + for (const char C : Name) { + if (isdigit(C)) { + V.Part[N] *= 10; + V.Part[N] += C - '0'; + } else if (C == '.') { + ++N; + if (N >= 4) + return V; + } + } + return V; +} + +void CodeViewDebug::emitCompilerInformation() { + MCContext &Context = MMI->getContext(); + MCSymbol *CompilerBegin = Context.createTempSymbol(), + *CompilerEnd = Context.createTempSymbol(); + OS.AddComment("Record length"); + OS.emitAbsoluteSymbolDiff(CompilerEnd, CompilerBegin, 2); + OS.EmitLabel(CompilerBegin); + OS.AddComment("Record kind: S_COMPILE3"); + OS.EmitIntValue(SymbolKind::S_COMPILE3, 2); + uint32_t Flags = 0; + + NamedMDNode *CUs = MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); + const MDNode *Node = *CUs->operands().begin(); + const auto *CU = cast(Node); + + // The low byte of the flags indicates the source language. + Flags = MapDWLangToCVLang(CU->getSourceLanguage()); + // TODO: Figure out which other flags need to be set. + + OS.AddComment("Flags and language"); + OS.EmitIntValue(Flags, 4); + + OS.AddComment("CPUType"); + StringRef Triple = Asm->getTargetTriple(); + StringRef CPUName = Triple.take_front(Triple.find("-")); + CPUType CPU = MapCPUtoCVCPU(CPUName); + OS.EmitIntValue(static_cast(CPU), 2); + + StringRef CompilerVersion = CU->getProducer(); + Version V = ParseVersion(CompilerVersion); + OS.AddComment("Frontend version"); + for (int N = 0; N < 4; ++N) + OS.EmitIntValue(V.Part[N], 2); + OS.AddComment("Backend version"); + for (int N = 0; N < 4; ++N) + OS.EmitIntValue(V.Part[N], 2); + + OS.AddComment("Null-terminated compiler version string"); + emitNullTerminatedSymbolName(OS, CompilerVersion); + + OS.EmitLabel(CompilerEnd); +} + void CodeViewDebug::emitInlineeLinesSubsection() { if (InlinedSubprograms.empty()) return; @@ -645,13 +760,13 @@ OS.emitAbsoluteSymbolDiff(ProcRecordEnd, ProcRecordBegin, 2); OS.EmitLabel(ProcRecordBegin); - if (GV->hasLocalLinkage()) { - OS.AddComment("Record kind: S_LPROC32_ID"); - OS.EmitIntValue(unsigned(SymbolKind::S_LPROC32_ID), 2); - } else { - OS.AddComment("Record kind: S_GPROC32_ID"); - OS.EmitIntValue(unsigned(SymbolKind::S_GPROC32_ID), 2); - } + if (GV->hasLocalLinkage()) { + OS.AddComment("Record kind: S_LPROC32_ID"); + OS.EmitIntValue(unsigned(SymbolKind::S_LPROC32_ID), 2); + } else { + OS.AddComment("Record kind: S_GPROC32_ID"); + OS.EmitIntValue(unsigned(SymbolKind::S_GPROC32_ID), 2); + } // These fields are filled in by tools like CVPACK which run after the fact. OS.AddComment("PtrParent"); @@ -1961,6 +2076,8 @@ OS.AddComment("Subsection size"); OS.emitAbsoluteSymbolDiff(EndLabel, BeginLabel, 4); OS.EmitLabel(BeginLabel); + if (Kind == ModuleSubstreamKind::Symbols) + emitCompilerInformation(); return EndLabel; } Index: test/MC/COFF/cv-compiler-info.ll =================================================================== --- /dev/null +++ test/MC/COFF/cv-compiler-info.ll @@ -0,0 +1,56 @@ +; RUN: llc -mtriple i686-pc-windows-msvc < %s | FileCheck %s +; ModuleID = 'D:\src\scopes\foo.cpp' +source_filename = "D:\5Csrc\5Cscopes\5Cfoo.cpp" +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686-pc-windows-msvc19.0.23918" + +; Function Attrs: nounwind sspstrong +define i32 @"\01?foo@@YAHXZ"() #0 !dbg !10 { +entry: + ret i32 42, !dbg !14 +} + +attributes #0 = { nounwind sspstrong "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 4.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +; The debug$S section should begin with an S_COMPILE3 record that identifies the +; source language and the version of the compiler based on the DICompileUnit. +; CHECK: .section .debug$S,"dr" +; CHECK: .p2align 2 +; CHECK: .long 4 # Debug section magic +; CHECK: .long 241 # Symbol subsection for foo +; CHECK: .long Ltmp3-Ltmp2 # Subsection size +; CHECK: Ltmp2: +; CHECK: .short Ltmp5-Ltmp4 # Record length +; CHECK: Ltmp4: +; CHECK: .short 4412 # Record kind: S_COMPILE3 +; CHECK: .long 1 # Flags and language +; CHECK: .short 6 # CPUType +; CHECK: .short 4 # Frontend version +; CHECK: .short 0 +; CHECK: .short 0 +; CHECK: .short 0 +; CHECK: .short 4 # Backend version +; CHECK: .short 0 +; CHECK: .short 0 +; CHECK: .short 0 +; CHECK: .asciz "clang version 4.0.0 " # Null-terminated compiler version string +; CHECK: Ltmp5: +!1 = !DIFile(filename: "D:\5Csrc\5Cscopes\5Cfoo.cpp", directory: "D:\5Csrc\5Cscopes\5Cclang") +!2 = !{} +!3 = !{i32 6, !"Linker Options", !4} +!4 = !{!5, !6} +!5 = !{!"/DEFAULTLIB:libcmtd.lib"} +!6 = !{!"/DEFAULTLIB:oldnames.lib"} +!7 = !{i32 2, !"CodeView", i32 1} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{!"clang version 4.0.0 "} +!10 = distinct !DISubprogram(name: "foo", linkageName: "\01?foo@@YAHXZ", scope: !1, file: !1, line: 1, type: !11, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!11 = !DISubroutineType(types: !12) +!12 = !{!13} +!13 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!14 = !DILocation(line: 2, scope: !10)