Index: llvm/trunk/include/llvm/MC/MCObjectFileInfo.h =================================================================== --- llvm/trunk/include/llvm/MC/MCObjectFileInfo.h +++ llvm/trunk/include/llvm/MC/MCObjectFileInfo.h @@ -127,6 +127,7 @@ MCSection *DwarfGnuPubTypesSection; MCSection *COFFDebugSymbolsSection; + MCSection *COFFDebugTypesSection; /// Extra TLS Variable Data section. /// @@ -274,6 +275,10 @@ MCSection *getCOFFDebugSymbolsSection() const { return COFFDebugSymbolsSection; } + MCSection *getCOFFDebugTypesSection() const { + return COFFDebugTypesSection; + } + MCSection *getTLSExtraDataSection() const { return TLSExtraDataSection; } const MCSection *getTLSDataSection() const { return TLSDataSection; } Index: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -22,6 +22,7 @@ #include "llvm/CodeGen/LexicalScopes.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DebugLoc.h" #include "llvm/MC/MCStreamer.h" @@ -33,19 +34,31 @@ AsmPrinter *Asm; DebugLoc PrevInstLoc; + struct InlineSite { + TinyPtrVector ChildSites; + const DISubprogram *Inlinee = nullptr; + unsigned SiteFuncId = 0; + }; + // For each function, store a vector of labels to its instructions, as well as // to the end of the function. struct FunctionInfo { + /// Map from inlined call site to inlined instructions and child inlined + /// call sites. Listed in program order. + MapVector InlineSites; + DebugLoc LastLoc; MCSymbol *End = nullptr; unsigned FuncId = 0; - unsigned LastFileId; + unsigned LastFileId = 0; bool HaveLineInfo = false; }; FunctionInfo *CurFn; unsigned NextFuncId = 0; + InlineSite &getInlineSite(const DILocation *Loc); + /// Remember some debug info about each function. Keep it in a stable order to /// emit at the end of the TU. MapVector FnDebugInfo; @@ -53,6 +66,16 @@ /// Map from DIFile to .cv_file id. DenseMap FileIdMap; + DenseMap SubprogramToFuncId; + + unsigned TypeCount = 0; + + /// Gets the next type index and increments the count of types streamed so + /// far. + codeview::TypeIndex getNextTypeIndex() { + return codeview::TypeIndex(codeview::TypeIndex::FirstNonSimpleIndex + TypeCount++); + } + typedef std::map FileToFilepathMapTy; FileToFilepathMapTy FileToFilepathMap; StringRef getFullFilepath(const DIFile *S); @@ -68,8 +91,13 @@ FileToFilepathMap.clear(); } + void emitTypeInformation(); + void emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI); + void emitInlinedCallSite(const FunctionInfo &FI, const DILocation *InlinedAt, + const InlineSite &Site); + public: CodeViewDebug(AsmPrinter *Asm); Index: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -15,6 +15,8 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/COFF.h" @@ -87,6 +89,17 @@ return Insertion.first->second; } +CodeViewDebug::InlineSite &CodeViewDebug::getInlineSite(const DILocation *Loc) { + const DILocation *InlinedAt = Loc->getInlinedAt(); + auto Insertion = CurFn->InlineSites.insert({InlinedAt, InlineSite()}); + if (Insertion.second) { + InlineSite &Site = Insertion.first->second; + Site.SiteFuncId = NextFuncId++; + Site.Inlinee = Loc->getScope()->getSubprogram(); + } + return Insertion.first->second; +} + void CodeViewDebug::maybeRecordLocation(DebugLoc DL, const MachineFunction *MF) { // Skip this instruction if it has the same location as the previous one. @@ -115,7 +128,28 @@ else FileId = CurFn->LastFileId = maybeRecordFile(DL->getFile()); CurFn->LastLoc = DL; - Asm->OutStreamer->EmitCVLocDirective(CurFn->FuncId, FileId, DL.getLine(), + + unsigned FuncId = CurFn->FuncId; + if (const DILocation *Loc = DL->getInlinedAt()) { + // If this location was actually inlined from somewhere else, give it the ID + // of the inline call site. + FuncId = getInlineSite(DL.get()).SiteFuncId; + // Ensure we have links in the tree of inline call sites. + const DILocation *ChildLoc = nullptr; + while (Loc->getInlinedAt()) { + InlineSite &Site = getInlineSite(Loc); + if (ChildLoc) { + // Record the child inline site if not already present. + auto B = Site.ChildSites.begin(), E = Site.ChildSites.end(); + if (std::find(B, E, Loc) != E) + break; + Site.ChildSites.push_back(Loc); + } + ChildLoc = Loc; + } + } + + Asm->OutStreamer->EmitCVLocDirective(FuncId, FileId, DL.getLine(), DL.getCol(), /*PrologueEnd=*/false, /*IsStmt=*/false, DL->getFilename()); } @@ -139,6 +173,8 @@ if (FnDebugInfo.empty()) return; + emitTypeInformation(); + // FIXME: For functions that are comdat, we should emit separate .debug$S // sections that are comdat associative with the main function instead of // having one big .debug$S section. @@ -167,6 +203,60 @@ clear(); } +template static void emitRecord(MCStreamer &OS, const T &Rec) { + OS.EmitBytes(StringRef(reinterpret_cast(&Rec), sizeof(Rec))); +} + +void CodeViewDebug::emitTypeInformation() { + // Start the .debug$T section with 0x4. + Asm->OutStreamer->SwitchSection( + Asm->getObjFileLowering().getCOFFDebugTypesSection()); + Asm->EmitInt32(COFF::DEBUG_SECTION_MAGIC); + + NamedMDNode *CU_Nodes = + Asm->MMI->getModule()->getNamedMetadata("llvm.dbg.cu"); + if (!CU_Nodes) + return; + + // This type info currently only holds function ids for use with inline call + // frame info. All functions are assigned a simple 'void ()' type. Emit that + // type here. + TypeIndex ArgListIdx = getNextTypeIndex(); + Asm->EmitInt16(2 + sizeof(ArgList)); + Asm->EmitInt16(LF_ARGLIST); + Asm->EmitInt32(0); + + TypeIndex VoidProcIdx = getNextTypeIndex(); + Asm->EmitInt16(2 + sizeof(ProcedureType)); + Asm->EmitInt16(LF_PROCEDURE); + ProcedureType Proc{}; // Zero initialize. + Proc.ReturnType = TypeIndex::Void(); + Proc.CallConv = CallingConvention::NearC; + Proc.Options = FunctionOptions::None; + Proc.NumParameters = 0; + Proc.ArgListType = ArgListIdx; + emitRecord(*Asm->OutStreamer, Proc); + + for (MDNode *N : CU_Nodes->operands()) { + auto *CUNode = cast(N); + for (auto *SP : CUNode->getSubprograms()) { + StringRef DisplayName = SP->getDisplayName(); + Asm->EmitInt16(2 + sizeof(FuncId) + DisplayName.size() + 1); + Asm->EmitInt16(LF_FUNC_ID); + + FuncId Func{}; // Zero initialize. + Func.ParentScope = TypeIndex(); + Func.FunctionType = VoidProcIdx; + emitRecord(*Asm->OutStreamer, Func); + Asm->OutStreamer->EmitBytes(DisplayName); + Asm->EmitInt8(0); + + TypeIndex FuncIdIdx = getNextTypeIndex(); + SubprogramToFuncId.insert(std::make_pair(SP, FuncIdIdx)); + } + } +} + static void EmitLabelDiff(MCStreamer &Streamer, const MCSymbol *From, const MCSymbol *To, unsigned int Size = 4) { @@ -179,6 +269,44 @@ Streamer.EmitValue(AddrDelta, Size); } +void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI, + const DILocation *InlinedAt, + const InlineSite &Site) { + MCStreamer &OS = *Asm->OutStreamer; + + MCSymbol *InlineBegin = Asm->MMI->getContext().createTempSymbol(), + *InlineEnd = Asm->MMI->getContext().createTempSymbol(); + + assert(SubprogramToFuncId.count(Site.Inlinee)); + TypeIndex InlineeIdx = SubprogramToFuncId[Site.Inlinee]; + + // SymbolRecord + EmitLabelDiff(OS, InlineBegin, InlineEnd, 2); // RecordLength + OS.EmitLabel(InlineBegin); + Asm->EmitInt16(SymbolRecordKind::S_INLINESITE); // RecordKind + + InlineSiteSym SiteBytes{}; + SiteBytes.Inlinee = InlineeIdx; + Asm->OutStreamer->EmitBytes( + StringRef(reinterpret_cast(&SiteBytes), sizeof(SiteBytes))); + + // FIXME: annotations + + OS.EmitLabel(InlineEnd); + + // Recurse on child inlined call sites before closing the scope. + for (const DILocation *ChildSite : Site.ChildSites) { + auto I = FI.InlineSites.find(ChildSite); + assert(I != FI.InlineSites.end() && + "child site not in function inline site map"); + emitInlinedCallSite(FI, ChildSite, I->second); + } + + // Close the scope. + Asm->EmitInt16(2); // RecordLength + Asm->EmitInt16(SymbolRecordKind::S_INLINESITE_END); // RecordKind +} + void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI) { // For each function there is a separate subsection @@ -224,6 +352,15 @@ Asm->EmitInt8(0); Asm->OutStreamer->EmitLabel(ProcSegmentEnd); + // Emit inlined call site information. Only emit functions inlined directly + // into the parent function. We'll emit the other sites recursively as part + // of their parent inline site. + for (auto &KV : FI.InlineSites) { + const DILocation *InlinedAt = KV.first; + if (!InlinedAt->getInlinedAt()) + emitInlinedCallSite(FI, InlinedAt, KV.second); + } + // We're done with this function. Asm->EmitInt16(0x0002); Asm->EmitInt16(unsigned(SymbolRecordKind::S_PROC_ID_END)); Index: llvm/trunk/lib/MC/MCObjectFileInfo.cpp =================================================================== --- llvm/trunk/lib/MC/MCObjectFileInfo.cpp +++ llvm/trunk/lib/MC/MCObjectFileInfo.cpp @@ -191,6 +191,7 @@ SectionKind::getReadOnlyWithRel()); COFFDebugSymbolsSection = nullptr; + COFFDebugTypesSection = nullptr; if (useCompactUnwind(T)) { CompactUnwindSection = @@ -484,6 +485,7 @@ ELF::SHF_ALLOC); COFFDebugSymbolsSection = nullptr; + COFFDebugTypesSection = nullptr; // Debug Info Sections. DwarfAbbrevSection = Ctx->getELFSection(".debug_abbrev", ELF::SHT_PROGBITS, 0, @@ -623,9 +625,14 @@ // Debug info. COFFDebugSymbolsSection = - Ctx->getCOFFSection(".debug$S", COFF::IMAGE_SCN_MEM_DISCARDABLE | - COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | - COFF::IMAGE_SCN_MEM_READ, + Ctx->getCOFFSection(".debug$S", (COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ), + SectionKind::getMetadata()); + COFFDebugTypesSection = + Ctx->getCOFFSection(".debug$T", (COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ), SectionKind::getMetadata()); DwarfAbbrevSection = Ctx->getCOFFSection( Index: llvm/trunk/test/DebugInfo/COFF/inlining.ll =================================================================== --- llvm/trunk/test/DebugInfo/COFF/inlining.ll +++ llvm/trunk/test/DebugInfo/COFF/inlining.ll @@ -0,0 +1,160 @@ +; RUN: llc -mcpu=core2 -mtriple=i686-pc-win32 < %s | FileCheck %s --check-prefix=ASM +; RUN: llc -mcpu=core2 -mtriple=i686-pc-win32 < %s -filetype=obj | llvm-readobj -codeview | FileCheck %s --check-prefix=OBJ + +; This LL file was generated by running 'clang -O1 -g -gcodeview' on the +; following code: +; 1: extern volatile int x; +; 2: static inline void foo() { +; 3: int y = 1; +; 4: x += (int)&y; +; 5: x += 2; +; 6: x += 3; +; 7: } +; 8: static inline void bar() { +; 9: x += 4; +; 10: foo(); +; 11: x += 5; +; 12: } +; 13: void baz() { +; 14: x += 6; +; 15: bar(); +; 16: x += 7; +; 17: } + +; ASM: .cv_loc 0 1 13 0 is_stmt 0 # t.cpp:13:0 +; ASM: .cv_loc 0 1 14 5 # t.cpp:14:5 +; ASM: addl $6, "?x@@3HC" +; ASM: .cv_loc 1 1 9 5 # t.cpp:9:5 +; ASM: addl $4, "?x@@3HC" +; ASM: .cv_loc 2 1 3 7 # t.cpp:3:7 +; ASM: .cv_loc 2 1 4 5 # t.cpp:4:5 +; ASM: addl {{.*}}, "?x@@3HC" +; ASM: .cv_loc 2 1 5 5 # t.cpp:5:5 +; ASM: addl $2, "?x@@3HC" +; ASM: .cv_loc 2 1 6 5 # t.cpp:6:5 +; ASM: addl $3, "?x@@3HC" +; ASM: .cv_loc 1 1 11 5 # t.cpp:11:5 +; ASM: addl $5, "?x@@3HC" +; ASM: .cv_loc 0 1 16 5 # t.cpp:16:5 +; ASM: addl $7, "?x@@3HC" +; ASM: .cv_loc 0 1 17 1 # t.cpp:17:1 + +; OBJ: ProcStart { +; OBJ: PtrParent: 0x0 +; OBJ: PtrEnd: 0x0 +; OBJ: PtrNext: 0x0 +; OBJ: CodeSize: 0x3D +; OBJ: DbgStart: 0x0 +; OBJ: DbgEnd: 0x0 +; OBJ: FunctionType: 0x0 +; OBJ: CodeOffset: ?baz@@YAXXZ+0x0 +; OBJ: Segment: 0x0 +; OBJ: Flags [ (0x0) +; OBJ: ] +; OBJ: DisplayName: baz +; OBJ: LinkageName: ?baz@@YAXXZ +; OBJ: } +; OBJ: InlineSite { +; OBJ: PtrParent: 0x0 +; OBJ: PtrEnd: 0x0 +; OBJ: Inlinee: bar (0x1003) +; OBJ: BinaryAnnotations [ +; OBJ: ] +; OBJ: } +; OBJ: InlineSite { +; OBJ: PtrParent: 0x0 +; OBJ: PtrEnd: 0x0 +; OBJ: Inlinee: foo (0x1004) +; OBJ: BinaryAnnotations [ +; OBJ: ] +; OBJ: } +; OBJ: InlineSiteEnd { +; OBJ: } +; OBJ: InlineSiteEnd { +; OBJ: } +; OBJ: ProcEnd + +; ModuleID = 't.cpp' +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc18.0.0" + +@"\01?x@@3HC" = external global i32, align 4 + +; Function Attrs: norecurse nounwind uwtable +define void @"\01?baz@@YAXXZ"() #0 !dbg !4 { +entry: + %y.i.i = alloca i32, align 4 + %0 = load volatile i32, i32* @"\01?x@@3HC", align 4, !dbg !12, !tbaa !13 + %add = add nsw i32 %0, 6, !dbg !12 + store volatile i32 %add, i32* @"\01?x@@3HC", align 4, !dbg !12, !tbaa !13 + %1 = load volatile i32, i32* @"\01?x@@3HC", align 4, !dbg !17, !tbaa !13 + %add.i = add nsw i32 %1, 4, !dbg !17 + store volatile i32 %add.i, i32* @"\01?x@@3HC", align 4, !dbg !17, !tbaa !13 + %2 = bitcast i32* %y.i.i to i8*, !dbg !19 + call void @llvm.lifetime.start(i64 4, i8* %2) #2, !dbg !19 + store i32 1, i32* %y.i.i, align 4, !dbg !21, !tbaa !13 + %3 = ptrtoint i32* %y.i.i to i64, !dbg !22 + %4 = trunc i64 %3 to i32, !dbg !22 + %5 = load volatile i32, i32* @"\01?x@@3HC", align 4, !dbg !23, !tbaa !13 + %add.i.i = add nsw i32 %5, %4, !dbg !23 + store volatile i32 %add.i.i, i32* @"\01?x@@3HC", align 4, !dbg !23, !tbaa !13 + %6 = load volatile i32, i32* @"\01?x@@3HC", align 4, !dbg !24, !tbaa !13 + %add1.i.i = add nsw i32 %6, 2, !dbg !24 + store volatile i32 %add1.i.i, i32* @"\01?x@@3HC", align 4, !dbg !24, !tbaa !13 + %7 = load volatile i32, i32* @"\01?x@@3HC", align 4, !dbg !25, !tbaa !13 + %add2.i.i = add nsw i32 %7, 3, !dbg !25 + store volatile i32 %add2.i.i, i32* @"\01?x@@3HC", align 4, !dbg !25, !tbaa !13 + call void @llvm.lifetime.end(i64 4, i8* %2) #2, !dbg !26 + %8 = load volatile i32, i32* @"\01?x@@3HC", align 4, !dbg !27, !tbaa !13 + %add1.i = add nsw i32 %8, 5, !dbg !27 + store volatile i32 %add1.i, i32* @"\01?x@@3HC", align 4, !dbg !27, !tbaa !13 + %9 = load volatile i32, i32* @"\01?x@@3HC", align 4, !dbg !28, !tbaa !13 + %add1 = add nsw i32 %9, 7, !dbg !28 + store volatile i32 %add1, i32* @"\01?x@@3HC", align 4, !dbg !28, !tbaa !13 + ret void, !dbg !29 +} + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.start(i64, i8* nocapture) #1 + +; Function Attrs: argmemonly nounwind +declare void @llvm.lifetime.end(i64, i8* nocapture) #1 + +attributes #0 = { norecurse nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { argmemonly nounwind } +attributes #2 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: 2, enums: !2, subprograms: !3) +!1 = !DIFile(filename: "t.cpp", directory: "D:\5Csrc\5Cllvm\5Cbuild") +!2 = !{} +!3 = !{!4, !6, !7} +!4 = distinct !DISubprogram(name: "baz", scope: !1, file: !1, line: 13, type: !5, isLocal: false, isDefinition: true, scopeLine: 13, flags: DIFlagPrototyped, isOptimized: true, variables: !2) +!5 = !DISubroutineType(types: !2) +!6 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 8, type: !5, isLocal: true, isDefinition: true, scopeLine: 8, flags: DIFlagPrototyped, isOptimized: true, variables: !2) +!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 2, type: !5, isLocal: true, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: true, variables: !2) +!8 = !{i32 2, !"CodeView", i32 1} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"PIC Level", i32 2} +!11 = !{!"clang version 3.9.0 "} +!12 = !DILocation(line: 14, column: 5, scope: !4) +!13 = !{!14, !14, i64 0} +!14 = !{!"int", !15, i64 0} +!15 = !{!"omnipotent char", !16, i64 0} +!16 = !{!"Simple C/C++ TBAA"} +!17 = !DILocation(line: 9, column: 5, scope: !6, inlinedAt: !18) +!18 = distinct !DILocation(line: 15, column: 3, scope: !4) +!19 = !DILocation(line: 3, column: 3, scope: !7, inlinedAt: !20) +!20 = distinct !DILocation(line: 10, column: 3, scope: !6, inlinedAt: !18) +!21 = !DILocation(line: 3, column: 7, scope: !7, inlinedAt: !20) +!22 = !DILocation(line: 4, column: 8, scope: !7, inlinedAt: !20) +!23 = !DILocation(line: 4, column: 5, scope: !7, inlinedAt: !20) +!24 = !DILocation(line: 5, column: 5, scope: !7, inlinedAt: !20) +!25 = !DILocation(line: 6, column: 5, scope: !7, inlinedAt: !20) +!26 = !DILocation(line: 7, column: 1, scope: !7, inlinedAt: !20) +!27 = !DILocation(line: 11, column: 5, scope: !6, inlinedAt: !18) +!28 = !DILocation(line: 16, column: 5, scope: !4) +!29 = !DILocation(line: 17, column: 1, scope: !4)