Index: include/llvm/DebugInfo/CodeView/TypeRecord.h =================================================================== --- include/llvm/DebugInfo/CodeView/TypeRecord.h +++ include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -19,6 +19,10 @@ namespace llvm { namespace codeview { +using llvm::support::little32_t; +using llvm::support::ulittle16_t; +using llvm::support::ulittle32_t; + class TypeRecord { protected: explicit TypeRecord(TypeRecordKind Kind) : Kind(Kind) {} @@ -264,6 +268,305 @@ private: ArrayRef Slots; }; + +//===----------------------------------------------------------------------===// +// On-disk representation of type information + +// A CodeView type stream is a sequence of TypeRecords. Records larger than +// 65536 must chain on to a second record. Each TypeRecord is followed by one of +// the leaf types described below. +struct TypeRecordPrefix { + ulittle16_t Len; // Type record length, starting from &Leaf. + ulittle16_t Leaf; // Type record kind (TypeLeafKind) +}; + +// LF_TYPESERVER2 +struct TypeServer2 { + char Signature[16]; // GUID + ulittle32_t Age; + // Name: Name of the PDB as a null-terminated string +}; + +// LF_STRING_ID +struct StringId { + TypeIndex id; +}; + +// LF_FUNC_ID +struct FuncId { + TypeIndex ParentScope; + TypeIndex FunctionType; + // Name: The null-terminated name follows. +}; + +// LF_CLASS, LF_STRUCT, LF_INTERFACE +struct ClassType { + ulittle16_t MemberCount; // Number of members in FieldList. + ulittle16_t Properties; // ClassOptions bitset + TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members + TypeIndex DerivedFrom; // LF_DERIVED: List of known derived classes + TypeIndex VShape; // LF_VTSHAPE: Shape of the vftable + // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC integer. + // Name: The null-terminated name follows. +}; + +// LF_UNION +struct UnionType { + ulittle16_t MemberCount; // Number of members in FieldList. + ulittle16_t Properties; // ClassOptions bitset + TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members + // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC integer. + // Name: The null-terminated name follows. +}; + +// LF_POINTER +struct PointerType { + TypeIndex PointeeType; + ulittle32_t Attrs; // pointer attributes + // if pointer to member: + // PointerToMemberTail + + PointerKind getPtrKind() const { return PointerKind(Attrs & 0x1f); } + PointerMode getPtrMode() const { return PointerMode((Attrs >> 5) & 0x07); } + bool isFlat() const { return Attrs & (1 << 8); } + bool isVolatile() const { return Attrs & (1 << 9); } + bool isConst() const { return Attrs & (1 << 10); } + bool isUnaligned() const { return Attrs & (1 << 11); } + + bool isPointerToDataMember() const { + return getPtrMode() == PointerMode::PointerToDataMember; + } + bool isPointerToMemberFunction() const { + return getPtrMode() == PointerMode::PointerToMemberFunction; + } + bool isPointerToMember() const { + return isPointerToMemberFunction() || isPointerToDataMember(); + } +}; + +struct PointerToMemberTail { + TypeIndex ClassType; + ulittle16_t Representation; // PointerToMemberRepresentation +}; + +/// In Clang parlance, these are "qualifiers". LF_MODIFIER +struct TypeModifier { + TypeIndex ModifiedType; + ulittle16_t Modifiers; // ModifierOptions +}; + +// LF_VTSHAPE +struct VTableShape { + // Number of vftable entries. Each method may have more than one entry due to + // things like covariant return types. + ulittle16_t VFEntryCount; + // Descriptors[]: 4-bit virtual method descriptors of type CV_VTS_desc_e. +}; + +// LF_UDT_SRC_LINE +struct UDTSrcLine { + TypeIndex UDT; // The user-defined type + TypeIndex SourceFile; // StringID containing the source filename + ulittle32_t LineNumber; +}; + +// LF_ARGLIST, LF_SUBSTR_LIST +struct ArgList { + ulittle32_t NumArgs; // Number of arguments + // ArgTypes[]: Type indicies of arguments +}; + +// LF_BUILDINFO +struct BuildInfo { + ulittle16_t NumArgs; // Number of arguments + // ArgTypes[]: Type indicies of arguments +}; + +// LF_ENUM +struct EnumType { + ulittle16_t NumEnumerators; // Number of enumerators + ulittle16_t Properties; + TypeIndex UnderlyingType; + TypeIndex FieldListType; + // Name: The null-terminated name follows. +}; + +// LF_ARRAY +struct ArrayType { + TypeIndex ElementType; + TypeIndex IndexType; + // SizeOf: LF_NUMERIC encoded size in bytes. Not element count! + // Name: The null-terminated name follows. +}; + +// LF_VFTABLE +struct VFTableType { + TypeIndex CompleteClass; // Class that owns this vftable. + TypeIndex OverriddenVFTable; // VFTable that this overrides. + ulittle32_t VFPtrOffset; // VFPtr offset in CompleteClass + ulittle32_t NamesLen; // Length of subsequent names array in bytes. + // Names: A sequence of null-terminated strings. First string is vftable + // names. +}; + +// LF_MFUNC_ID +struct MemberFuncId { + TypeIndex ClassType; + TypeIndex FunctionType; + // Name: The null-terminated name follows. +}; + +// LF_PROCEDURE +struct ProcedureType { + TypeIndex ReturnType; + CallingConvention CallConv; + FunctionOptions Options; + ulittle16_t NumParameters; + TypeIndex ArgListType; +}; + +// LF_MFUNCTION +struct MemberFunctionType { + TypeIndex ReturnType; + TypeIndex ClassType; + TypeIndex ThisType; + CallingConvention CallConv; + FunctionOptions Options; + ulittle16_t NumParameters; + TypeIndex ArgListType; + little32_t ThisAdjustment; +}; + +//===----------------------------------------------------------------------===// +// Field list records, which do not include leafs or sizes + +/// Equvalent to CV_fldattr_t in cvinfo.h. +struct MemberAttributes { + ulittle16_t Attrs; + + /// Get the access specifier. Valid for any kind of member. + MemberAccess getAccess() const { + return MemberAccess(unsigned(Attrs) & unsigned(MethodOptions::AccessMask)); + } + + /// Indicates if a method is defined with friend, virtual, static, etc. + MethodKind getMethodKind() const { + return MethodKind( + (unsigned(Attrs) & unsigned(MethodOptions::MethodKindMask)) >> 2); + } + + /// Get the flags that are not included in access control or method + /// properties. + MethodOptions getFlags() const { + return MethodOptions( + unsigned(Attrs) & + ~unsigned(MethodOptions::AccessMask | MethodOptions::MethodKindMask)); + } + + /// Is this method virtual. + bool isVirtual() const { + auto MP = getMethodKind(); + return MP != MethodKind::Vanilla && MP != MethodKind::Friend && + MP != MethodKind::Static; + } + + /// Does this member introduce a new virtual method. + bool isIntroducedVirtual() const { + auto MP = getMethodKind(); + return MP == MethodKind::IntroducingVirtual || + MP == MethodKind::PureIntroducingVirtual; + } +}; + +// LF_NESTTYPE +struct NestedType { + ulittle16_t Pad0; // Should be zero + TypeIndex Type; // Type index of nested type + // Name: Null-terminated string +}; + +// LF_ONEMETHOD +struct OneMethod { + MemberAttributes Attrs; + TypeIndex Type; + // If is introduced virtual method: + // VFTableOffset: int32_t offset in vftable + // Name: Null-terminated string + + MethodKind getMethodKind() const { + return Attrs.getMethodKind(); + } + + bool isVirtual() const { return Attrs.isVirtual(); } + bool isIntroducedVirtual() const { return Attrs.isIntroducedVirtual(); } +}; + +struct MethodListEntry { + MemberAttributes Attrs; + ulittle16_t Padding; + + TypeIndex Type; + // If is introduced virtual method: + // VFTableOffset: int32_t offset in vftable + + MethodKind getMethodKind() const { + return Attrs.getMethodKind(); + } + + bool isVirtual() const { return Attrs.isVirtual(); } + bool isIntroducedVirtual() const { return Attrs.isIntroducedVirtual(); } +}; + +/// For method overload sets. LF_METHOD +struct OverloadedMethod { + ulittle16_t MethodCount; // Size of overload set + TypeIndex MethList; // Type index of methods in overload set + // Name: Null-terminated string +}; + +// LF_VFUNCTAB +struct VirtualFunctionPointer { + ulittle16_t Pad0; + TypeIndex Type; // Type of vfptr +}; + +// LF_MEMBER +struct DataMember { + MemberAttributes Attrs; // Access control attributes, etc + TypeIndex Type; + // FieldOffset: LF_NUMERIC encoded byte offset + // Name: Null-terminated string +}; + +// LF_STMEMBER +struct StaticDataMember { + MemberAttributes Attrs; // Access control attributes, etc + TypeIndex Type; + // Name: Null-terminated string +}; + +// LF_ENUMERATE +struct Enumerator { + MemberAttributes Attrs; // Access control attributes, etc + // EnumValue: LF_NUMERIC encoded enumerator value + // Name: Null-terminated string +}; + +// LF_BCLASS, LF_BINTERFACE +struct BaseClass { + MemberAttributes Attrs; // Access control attributes, etc + TypeIndex BaseType; // Base class type + // BaseOffset: LF_NUMERIC encoded byte offset of base from derived. +}; + +// LF_VBCLASS | LV_IVBCLASS +struct VirtualBaseClass { + MemberAttributes Attrs; // Access control attributes, etc. + TypeIndex BaseType; // Base class type + TypeIndex VBPtrType; // Virtual base pointer type + // VBPtrOffset: Offset of vbptr from vfptr encoded as LF_NUMERIC. + // VBTableIndex: Index of vbase within vbtable encoded as LF_NUMERIC. +}; } } Index: include/llvm/MC/MCObjectFileInfo.h =================================================================== --- include/llvm/MC/MCObjectFileInfo.h +++ 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: lib/CodeGen/AsmPrinter/CodeViewDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ 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,16 +34,36 @@ AsmPrinter *Asm; DebugLoc PrevInstLoc; + struct InlineInfo { + TinyPtrVector ChildSites; + TinyPtrVector Instrs; + }; + // For each function, store a vector of labels to its instructions, as well as // to the end of the function. struct FunctionInfo { DebugLoc LastLoc; SmallVector Instrs; + + /// Map from inlined call site to inlined instructions and child inlined + /// call sites. Listed in program order. + MapVector InlineSites; + MCSymbol *End; FunctionInfo() : End(nullptr) {} }; FunctionInfo *CurFn; + 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 DenseMap FnDebugInfoTy; FnDebugInfoTy FnDebugInfo; // Store the functions we've visited in a vector so we can maintain a stable @@ -102,8 +123,13 @@ LabelsAndLocs.clear(); } + void emitTypeInformation(); + void emitDebugInfoForFunction(const Function *GV); + void emitInlinedCallSite(const FunctionInfo &FI, const DILocation *InlinedAt, + const InlineInfo &Site); + public: CodeViewDebug(AsmPrinter *Asm); Index: lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -14,6 +14,8 @@ #include "CodeViewDebug.h" #include "llvm/DebugInfo/CodeView/CodeView.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" @@ -92,7 +94,21 @@ MCSymbol *MCL = Asm->MMI->getContext().createTempSymbol(); Asm->OutStreamer->EmitLabel(MCL); - CurFn->Instrs.push_back(MCL); + if (const DILocation *Loc = DL->getInlinedAt()) { + CurFn->InlineSites[Loc].Instrs.push_back(MCL); + // Invert the IR child-to-parent links. + while (const DILocation *ParentLoc = Loc->getInlinedAt()) { + InlineInfo &ParentSite = CurFn->InlineSites[ParentLoc]; + auto B = ParentSite.ChildSites.begin(), E = ParentSite.ChildSites.end(); + // Stop inserting links if we've already inserted this one. + if (std::find(B, E, Loc) != E) + break; + ParentSite.ChildSites.push_back(Loc); + Loc = ParentLoc; + } + } else { + CurFn->Instrs.push_back(MCL); + } LabelsAndLocs[MCL] = DL; } @@ -115,6 +131,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. @@ -165,6 +183,59 @@ clear(); } +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 {}; + Proc.ReturnType = TypeIndex::Void(); + Proc.CallConv = CallingConvention::NearC; + Proc.Options = FunctionOptions::None; + Proc.NumParameters = 0; + Proc.ArgListType = ArgListIdx; + Asm->OutStreamer->EmitBytes( + StringRef(reinterpret_cast(&Proc), sizeof(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{}; + // FIXME: Should be full namespace scope as a string id. + Func.ParentScope = TypeIndex(); + Func.FunctionType = VoidProcIdx; + Asm->OutStreamer->EmitBytes( + StringRef(reinterpret_cast(&Func), sizeof(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) { @@ -181,6 +252,52 @@ return DL.get()->getScope()->getFile(); } +void CodeViewDebug::emitInlinedCallSite(const FunctionInfo &FI, + const DILocation *InlinedAt, + const InlineInfo &Site) { + MCStreamer &OS = *Asm->OutStreamer; + + MCSymbol *InlineBegin = Asm->MMI->getContext().createTempSymbol(), + *InlineEnd = Asm->MMI->getContext().createTempSymbol(); + + // Find the inlinee by looking for inlined instructions or an inlined call + // site if there are none. + const DILocation *DL; + if (!Site.ChildSites.empty()) + DL = Site.ChildSites.front(); + else + DL = LabelsAndLocs[Site.Instrs.front()].get(); + const DISubprogram *Inlinee = DL->getScope()->getSubprogram(); + assert(SubprogramToFuncId.count(Inlinee)); + TypeIndex InlineeIdx = SubprogramToFuncId[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) { // For each function there is a separate subsection // which holds the PC to file:line table. @@ -188,7 +305,7 @@ assert(Fn); const FunctionInfo &FI = FnDebugInfo[GV]; - if (FI.Instrs.empty()) + if (FI.Instrs.empty() && FI.InlineSites.empty()) return; assert(FI.End && "Don't know where the function ends?"); @@ -230,6 +347,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: lib/MC/MCObjectFileInfo.cpp =================================================================== --- lib/MC/MCObjectFileInfo.cpp +++ 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: test/DebugInfo/COFF/inlining.ll =================================================================== --- /dev/null +++ test/DebugInfo/COFF/inlining.ll @@ -0,0 +1,114 @@ +; RUN: llc -mcpu=core2 -mtriple=i686-pc-win32 < %s -filetype=obj | llvm-readobj -codeview | FileCheck %s + +; This LL file was generated by running clang on the following code: +; extern volatile int x; +; static inline void foo() { +; int y = 1; +; x += (int)&y; +; x += 2; +; x += 3; +; } +; static inline void bar() { +; x += 4; +; foo(); +; x += 5; +; } +; void baz() { +; x += 6; +; bar(); +; x += 7; +; } + +; CHECK: InlineSite { +; CHECK: Inlinee: bar +; CHECK: } +; CHECK: InlineSite { +; CHECK: Inlinee: foo +; CHECK: } +; CHECK: InlineSiteEnd +; CHECK: InlineSiteEnd + +; 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) Index: tools/llvm-readobj/CodeView.h =================================================================== --- tools/llvm-readobj/CodeView.h +++ tools/llvm-readobj/CodeView.h @@ -26,7 +26,6 @@ namespace llvm { namespace codeview { -using llvm::support::little32_t; using llvm::support::ulittle16_t; using llvm::support::ulittle32_t; @@ -48,304 +47,6 @@ }; }; -//===----------------------------------------------------------------------===// -// On-disk representation of type information - -// A CodeView type stream is a sequence of TypeRecords. Records larger than -// 65536 must chain on to a second record. Each TypeRecord is followed by one of -// the leaf types described below. -struct TypeRecordPrefix { - ulittle16_t Len; // Type record length, starting from &Leaf. - ulittle16_t Leaf; // Type record kind (TypeLeafKind) -}; - -// LF_TYPESERVER2 -struct TypeServer2 { - char Signature[16]; // GUID - ulittle32_t Age; - // Name: Name of the PDB as a null-terminated string -}; - -// LF_STRING_ID -struct StringId { - TypeIndex id; -}; - -// LF_FUNC_ID -struct FuncId { - TypeIndex ParentScope; - TypeIndex FunctionType; - // Name: The null-terminated name follows. -}; - -// LF_CLASS, LF_STRUCT, LF_INTERFACE -struct ClassType { - ulittle16_t MemberCount; // Number of members in FieldList. - ulittle16_t Properties; // ClassOptions bitset - TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members - TypeIndex DerivedFrom; // LF_DERIVED: List of known derived classes - TypeIndex VShape; // LF_VTSHAPE: Shape of the vftable - // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC integer. - // Name: The null-terminated name follows. -}; - -// LF_UNION -struct UnionType { - ulittle16_t MemberCount; // Number of members in FieldList. - ulittle16_t Properties; // ClassOptions bitset - TypeIndex FieldList; // LF_FIELDLIST: List of all kinds of members - // SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC integer. - // Name: The null-terminated name follows. -}; - -// LF_POINTER -struct PointerType { - TypeIndex PointeeType; - ulittle32_t Attrs; // pointer attributes - // if pointer to member: - // PointerToMemberTail - - PointerKind getPtrKind() const { return PointerKind(Attrs & 0x1f); } - PointerMode getPtrMode() const { return PointerMode((Attrs >> 5) & 0x07); } - bool isFlat() const { return Attrs & (1 << 8); } - bool isVolatile() const { return Attrs & (1 << 9); } - bool isConst() const { return Attrs & (1 << 10); } - bool isUnaligned() const { return Attrs & (1 << 11); } - - bool isPointerToDataMember() const { - return getPtrMode() == PointerMode::PointerToDataMember; - } - bool isPointerToMemberFunction() const { - return getPtrMode() == PointerMode::PointerToMemberFunction; - } - bool isPointerToMember() const { - return isPointerToMemberFunction() || isPointerToDataMember(); - } -}; - -struct PointerToMemberTail { - TypeIndex ClassType; - ulittle16_t Representation; // PointerToMemberRepresentation -}; - -/// In Clang parlance, these are "qualifiers". LF_MODIFIER -struct TypeModifier { - TypeIndex ModifiedType; - ulittle16_t Modifiers; // ModifierOptions -}; - -// LF_VTSHAPE -struct VTableShape { - // Number of vftable entries. Each method may have more than one entry due to - // things like covariant return types. - ulittle16_t VFEntryCount; - // Descriptors[]: 4-bit virtual method descriptors of type CV_VTS_desc_e. -}; - -// LF_UDT_SRC_LINE -struct UDTSrcLine { - TypeIndex UDT; // The user-defined type - TypeIndex SourceFile; // StringID containing the source filename - ulittle32_t LineNumber; -}; - -// LF_ARGLIST, LF_SUBSTR_LIST -struct ArgList { - ulittle32_t NumArgs; // Number of arguments - // ArgTypes[]: Type indicies of arguments -}; - -// LF_BUILDINFO -struct BuildInfo { - ulittle16_t NumArgs; // Number of arguments - // ArgTypes[]: Type indicies of arguments -}; - -// LF_ENUM -struct EnumType { - ulittle16_t NumEnumerators; // Number of enumerators - ulittle16_t Properties; - TypeIndex UnderlyingType; - TypeIndex FieldListType; - // Name: The null-terminated name follows. -}; - -// LF_ARRAY -struct ArrayType { - TypeIndex ElementType; - TypeIndex IndexType; - // SizeOf: LF_NUMERIC encoded size in bytes. Not element count! - // Name: The null-terminated name follows. -}; - -// LF_VFTABLE -struct VFTableType { - TypeIndex CompleteClass; // Class that owns this vftable. - TypeIndex OverriddenVFTable; // VFTable that this overrides. - ulittle32_t VFPtrOffset; // VFPtr offset in CompleteClass - ulittle32_t NamesLen; // Length of subsequent names array in bytes. - // Names: A sequence of null-terminated strings. First string is vftable - // names. -}; - -// LF_MFUNC_ID -struct MemberFuncId { - TypeIndex ClassType; - TypeIndex FunctionType; - // Name: The null-terminated name follows. -}; - -// LF_PROCEDURE -struct ProcedureType { - TypeIndex ReturnType; - CallingConvention CallConv; - FunctionOptions Options; - ulittle16_t NumParameters; - TypeIndex ArgListType; -}; - -// LF_MFUNCTION -struct MemberFunctionType { - TypeIndex ReturnType; - TypeIndex ClassType; - TypeIndex ThisType; - CallingConvention CallConv; - FunctionOptions Options; - ulittle16_t NumParameters; - TypeIndex ArgListType; - little32_t ThisAdjustment; -}; - -//===----------------------------------------------------------------------===// -// Field list records, which do not include leafs or sizes - -/// Equvalent to CV_fldattr_t in cvinfo.h. -struct MemberAttributes { - ulittle16_t Attrs; - - /// Get the access specifier. Valid for any kind of member. - MemberAccess getAccess() const { - return MemberAccess(unsigned(Attrs) & unsigned(MethodOptions::AccessMask)); - } - - /// Indicates if a method is defined with friend, virtual, static, etc. - MethodKind getMethodKind() const { - return MethodKind( - (unsigned(Attrs) & unsigned(MethodOptions::MethodKindMask)) >> 2); - } - - /// Get the flags that are not included in access control or method - /// properties. - MethodOptions getFlags() const { - return MethodOptions( - unsigned(Attrs) & - ~unsigned(MethodOptions::AccessMask | MethodOptions::MethodKindMask)); - } - - /// Is this method virtual. - bool isVirtual() const { - auto MP = getMethodKind(); - return MP != MethodKind::Vanilla && MP != MethodKind::Friend && - MP != MethodKind::Static; - } - - /// Does this member introduce a new virtual method. - bool isIntroducedVirtual() const { - auto MP = getMethodKind(); - return MP == MethodKind::IntroducingVirtual || - MP == MethodKind::PureIntroducingVirtual; - } -}; - -// LF_NESTTYPE -struct NestedType { - ulittle16_t Pad0; // Should be zero - TypeIndex Type; // Type index of nested type - // Name: Null-terminated string -}; - -// LF_ONEMETHOD -struct OneMethod { - MemberAttributes Attrs; - TypeIndex Type; - // If is introduced virtual method: - // VFTableOffset: int32_t offset in vftable - // Name: Null-terminated string - - MethodKind getMethodKind() const { - return Attrs.getMethodKind(); - } - - bool isVirtual() const { return Attrs.isVirtual(); } - bool isIntroducedVirtual() const { return Attrs.isIntroducedVirtual(); } -}; - -struct MethodListEntry { - MemberAttributes Attrs; - ulittle16_t Padding; - - TypeIndex Type; - // If is introduced virtual method: - // VFTableOffset: int32_t offset in vftable - - MethodKind getMethodKind() const { - return Attrs.getMethodKind(); - } - - bool isVirtual() const { return Attrs.isVirtual(); } - bool isIntroducedVirtual() const { return Attrs.isIntroducedVirtual(); } -}; - -/// For method overload sets. LF_METHOD -struct OverloadedMethod { - ulittle16_t MethodCount; // Size of overload set - TypeIndex MethList; // Type index of methods in overload set - // Name: Null-terminated string -}; - -// LF_VFUNCTAB -struct VirtualFunctionPointer { - ulittle16_t Pad0; - TypeIndex Type; // Type of vfptr -}; - -// LF_MEMBER -struct DataMember { - MemberAttributes Attrs; // Access control attributes, etc - TypeIndex Type; - // FieldOffset: LF_NUMERIC encoded byte offset - // Name: Null-terminated string -}; - -// LF_STMEMBER -struct StaticDataMember { - MemberAttributes Attrs; // Access control attributes, etc - TypeIndex Type; - // Name: Null-terminated string -}; - -// LF_ENUMERATE -struct Enumerator { - MemberAttributes Attrs; // Access control attributes, etc - // EnumValue: LF_NUMERIC encoded enumerator value - // Name: Null-terminated string -}; - -// LF_BCLASS, LF_BINTERFACE -struct BaseClass { - MemberAttributes Attrs; // Access control attributes, etc - TypeIndex BaseType; // Base class type - // BaseOffset: LF_NUMERIC encoded byte offset of base from derived. -}; - -// LF_VBCLASS | LV_IVBCLASS -struct VirtualBaseClass { - MemberAttributes Attrs; // Access control attributes, etc. - TypeIndex BaseType; // Base class type - TypeIndex VBPtrType; // Virtual base pointer type - // VBPtrOffset: Offset of vbptr from vfptr encoded as LF_NUMERIC. - // VBTableIndex: Index of vbase within vbtable encoded as LF_NUMERIC. -}; } // namespace codeview } // namespace llvm