Index: llvm/include/llvm/IR/DebugInfoFlags.def =================================================================== --- llvm/include/llvm/IR/DebugInfoFlags.def +++ llvm/include/llvm/IR/DebugInfoFlags.def @@ -46,6 +46,7 @@ HANDLE_DI_FLAG((1 << 22), TypePassByValue) HANDLE_DI_FLAG((1 << 23), TypePassByReference) HANDLE_DI_FLAG((1 << 24), FixedEnum) +HANDLE_DI_FLAG((1 << 25), Thunk) // To avoid needing a dedicated value for IndirectVirtualBase, we use // the bitwise or of Virtual and FwdDecl, which does not otherwise @@ -55,7 +56,7 @@ #ifdef DI_FLAG_LARGEST_NEEDED // intended to be used with ADT/BitmaskEnum.h // NOTE: always must be equal to largest flag, check this when adding new flag -HANDLE_DI_FLAG((1 << 24), Largest) +HANDLE_DI_FLAG((1 << 25), Largest) #undef DI_FLAG_LARGEST_NEEDED #endif Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -1694,6 +1694,11 @@ /// Return true if this subprogram is C++11 noreturn or C11 _Noreturn bool isNoReturn() const { return getFlags() & FlagNoReturn; } + // Check if this routine is a compiler-generated thunk. + // + // Returns true if this subprogram is a thunk generated by the compiler. + bool isThunk() const { return getFlags() & FlagThunk; } + DIScopeRef getScope() const { return DIScopeRef(getRawScope()); } StringRef getName() const { return getStringOperand(2); } Index: llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h =================================================================== --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -225,6 +225,10 @@ void emitInlineeLinesSubsection(); + void emitDebugInfoForThunk(const Function *GV, + FunctionInfo &FI, + const MCSymbol *Fn); + void emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI); void emitDebugInfoForGlobals(); Index: llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -828,6 +828,54 @@ emitCodeViewMagicVersion(); } +// Emit an S_THUNK32/S_END symbol pair for a thunk routine. +// The only supported thunk ordinal is currently the standard type. +void CodeViewDebug::emitDebugInfoForThunk(const Function *GV, + FunctionInfo &FI, + const MCSymbol *Fn) { + std::string FuncName = GlobalValue::dropLLVMManglingEscape(GV->getName()); + const ThunkOrdinal ordinal = ThunkOrdinal::Standard; // Only supported kind. + + OS.AddComment("Symbol subsection for " + Twine(FuncName)); + MCSymbol *SymbolsEnd = beginCVSubsection(DebugSubsectionKind::Symbols); + + // Emit S_THUNK32 + MCSymbol *ThunkRecordBegin = MMI->getContext().createTempSymbol(), + *ThunkRecordEnd = MMI->getContext().createTempSymbol(); + OS.AddComment("Record length"); + OS.emitAbsoluteSymbolDiff(ThunkRecordEnd, ThunkRecordBegin, 2); + OS.EmitLabel(ThunkRecordBegin); + OS.AddComment("Record kind: S_THUNK32"); + OS.EmitIntValue(unsigned(SymbolKind::S_THUNK32), 2); + OS.AddComment("PtrParent"); + OS.EmitIntValue(0, 4); + OS.AddComment("PtrEnd"); + OS.EmitIntValue(0, 4); + OS.AddComment("PtrNext"); + OS.EmitIntValue(0, 4); + OS.AddComment("Thunk section relative address"); + OS.EmitCOFFSecRel32(Fn, /*Offset=*/0); + OS.AddComment("Thunk section index"); + OS.EmitCOFFSectionIndex(Fn); + OS.AddComment("Code size"); + OS.emitAbsoluteSymbolDiff(FI.End, Fn, 2); + OS.AddComment("Ordinal"); + OS.EmitIntValue(unsigned(ordinal), 1); + OS.AddComment("Function name"); + emitNullTerminatedSymbolName(OS, FuncName); + // Additional fields specific to the thunk ordinal would go here. + OS.EmitLabel(ThunkRecordEnd); + + // Emit S_END + const unsigned RecordLengthForSymbolEnd = 2; + OS.AddComment("Record length"); + OS.EmitIntValue(RecordLengthForSymbolEnd, 2); + OS.AddComment("Record kind: S_END"); + OS.EmitIntValue(unsigned(SymbolKind::S_END), 2); + + endCVSubsection(SymbolsEnd); +} + void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI) { // For each function there is a separate subsection which holds the PC to @@ -843,6 +891,11 @@ assert(SP); setCurrentSubprogram(SP); + if (SP->isThunk()) { + emitDebugInfoForThunk(GV, FI, Fn); + return; + } + // If we have a display name, build the fully qualified name by walking the // chain of scopes. if (!SP->getName().empty()) Index: llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp +++ llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp @@ -129,6 +129,7 @@ } Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) { + W.printString("Name", Thunk.Name); W.printNumber("Parent", Thunk.Parent); W.printNumber("End", Thunk.End); W.printNumber("Next", Thunk.Next); Index: llvm/test/DebugInfo/COFF/thunk.ll =================================================================== --- llvm/test/DebugInfo/COFF/thunk.ll +++ llvm/test/DebugInfo/COFF/thunk.ll @@ -0,0 +1,544 @@ +; RUN: llc < %s -filetype=obj | llvm-readobj - -codeview | FileCheck %s +; RUN: llc < %s | FileCheck %s --check-prefix=ASM +; RUN: opt -S -debugger-tune=lldb %s | FileCheck -check-prefix=OPT %s +; +; -- "thunk.cpp" begin -------------------------------------------------------- +; class A { public: virtual bool MyMethod() { return true; } }; +; class B { public: virtual bool MyMethod() { return true; } }; +; class C : public virtual A, public virtual B { +; public: +; virtual bool MyMethod() { return true; } +; }; +; +; int main() +; { +; A* a = new C(); +; B* b = new C(); +; C* c = new C(); +; a->MyMethod(); +; b->MyMethod(); +; c->MyMethod(); +; return 0; +; } +; -- "thunk.cpp" end ---------------------------------------------------------- +; +; Build command: +; $ clang -S -emit-llvm -g -gcodeview thunk.cpp +; +; CHECK: Thunk32Sym { +; CHECK-NEXT: Kind: S_THUNK32 ({{.*}}) +; CHECK-NEXT: Name: {{.*MyMethod.*C.*}} +; CHECK-NEXT: Parent: 0 +; CHECK-NEXT: End: 0 +; CHECK-NEXT: Next: 0 +; CHECK-NEXT: Off: 0 +; CHECK-NEXT: Seg: 0 +; CHECK-NEXT: Len: {{[0-9]+}} +; CHECK-NEXT: Ordinal: Standard (0x0) +; CHECK-NEXT: } +; CHECK-NEXT: ScopeEndSym { +; CHECK-NEXT: Kind: S_END ({{.*}}) +; CHECK-NEXT: } + +; +; ASM: .long 241 # Symbol subsection for ?MyMethod@C@@W7EAA_NXZ +; ASM-NEXT: .long {{.*}} # Subsection size +; ASM-NEXT: {{\.L.*}}: +; ASM-NEXT: .short [[END:.?L.*]]-[[BEGIN:.?L.*]] # Record length +; ASM-NEXT: [[BEGIN]]: +; ASM-NEXT: .short 4354 # Record kind: S_THUNK32 +; ASM-NEXT: .long 0 # PtrParent +; ASM-NEXT: .long 0 # PtrEnd +; ASM-NEXT: .long 0 # PtrNext +; ASM-NEXT: .secrel32 "{{.*MyMethod.*C.*}}" # Thunk section relative address +; ASM-NEXT: .secidx "{{.*MyMethod.*C.*}}" # Thunk section index +; ASM-NEXT: .short .Lfunc_end{{.*}}-"{{.*MyMethod.*C.*}}" # Code size +; ASM-NEXT: .byte 0 # Ordinal +; ASM-NEXT: .asciz "{{.*MyMethod.*C.*}}" # Function name +; ASM-NEXT: [[END]]: +; ASM-NEXT: .short 2 # Record length +; ASM-NEXT: .short 6 # Record kind: S_END +; +; OPT: DISubprogram(linkageName: "{{.*MyMethod.*C.*}}",{{.*}} line: 5,{{.*}} flags: DIFlagArtificial | DIFlagThunk{{.*}}) +; + +; ModuleID = 'thunk.cpp' +source_filename = "thunk.cpp" +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.0.24210" + +%rtti.CompleteObjectLocator = type { i32, i32, i32, i32, i32, i32 } +%rtti.TypeDescriptor7 = type { i8**, i8*, [8 x i8] } +%rtti.ClassHierarchyDescriptor = type { i32, i32, i32, i32 } +%rtti.BaseClassDescriptor = type { i32, i32, i32, i32, i32, i32, i32 } +%class.A = type { i32 (...)** } +%class.B = type { i32 (...)** } +%class.C = type { i32*, %class.A, %class.B } + +$"\01??0C@@QEAA@XZ" = comdat any + +$"\01??0A@@QEAA@XZ" = comdat any + +$"\01??0B@@QEAA@XZ" = comdat any + +$"\01?MyMethod@C@@UEAA_NXZ" = comdat any + +$"\01?MyMethod@C@@W7EAA_NXZ" = comdat any + +$"\01?MyMethod@A@@UEAA_NXZ" = comdat any + +$"\01?MyMethod@B@@UEAA_NXZ" = comdat any + +$"\01??_8C@@7B@" = comdat any + +$"\01??_7C@@6BA@@@" = comdat largest + +$"\01??_7C@@6BB@@@" = comdat largest + +$"\01??_R4C@@6BA@@@" = comdat any + +$"\01??_R0?AVC@@@8" = comdat any + +$"\01??_R3C@@8" = comdat any + +$"\01??_R2C@@8" = comdat any + +$"\01??_R1A@?0A@EA@C@@8" = comdat any + +$"\01??_R1A@A@3FA@A@@8" = comdat any + +$"\01??_R0?AVA@@@8" = comdat any + +$"\01??_R3A@@8" = comdat any + +$"\01??_R2A@@8" = comdat any + +$"\01??_R1A@?0A@EA@A@@8" = comdat any + +$"\01??_R1A@A@7FA@B@@8" = comdat any + +$"\01??_R0?AVB@@@8" = comdat any + +$"\01??_R3B@@8" = comdat any + +$"\01??_R2B@@8" = comdat any + +$"\01??_R1A@?0A@EA@B@@8" = comdat any + +$"\01??_R4C@@6BB@@@" = comdat any + +$"\01??_7A@@6B@" = comdat largest + +$"\01??_R4A@@6B@" = comdat any + +$"\01??_7B@@6B@" = comdat largest + +$"\01??_R4B@@6B@" = comdat any + +@"\01??_8C@@7B@" = linkonce_odr unnamed_addr constant [3 x i32] [i32 0, i32 8, i32 16], comdat +@0 = private unnamed_addr constant { [2 x i8*] } { [2 x i8*] [i8* bitcast (%rtti.CompleteObjectLocator* @"\01??_R4C@@6BA@@@" to i8*), i8* bitcast (i1 (i8*)* @"\01?MyMethod@C@@UEAA_NXZ" to i8*)] }, comdat($"\01??_7C@@6BA@@@") +@1 = private unnamed_addr constant { [2 x i8*] } { [2 x i8*] [i8* bitcast (%rtti.CompleteObjectLocator* @"\01??_R4C@@6BB@@@" to i8*), i8* bitcast (i1 (i8*)* @"\01?MyMethod@C@@W7EAA_NXZ" to i8*)] }, comdat($"\01??_7C@@6BB@@@") +@"\01??_R4C@@6BA@@@" = linkonce_odr constant %rtti.CompleteObjectLocator { i32 1, i32 8, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"\01??_R0?AVC@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"\01??_R3C@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.CompleteObjectLocator* @"\01??_R4C@@6BA@@@" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat +@"\01??_7type_info@@6B@" = external constant i8* +@"\01??_R0?AVC@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AVC@@\00" }, comdat +@__ImageBase = external constant i8 +@"\01??_R3C@@8" = linkonce_odr constant %rtti.ClassHierarchyDescriptor { i32 0, i32 3, i32 3, i32 trunc (i64 sub nuw nsw (i64 ptrtoint ([4 x i32]* @"\01??_R2C@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat +@"\01??_R2C@@8" = linkonce_odr constant [4 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.BaseClassDescriptor* @"\01??_R1A@?0A@EA@C@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.BaseClassDescriptor* @"\01??_R1A@A@3FA@A@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.BaseClassDescriptor* @"\01??_R1A@A@7FA@B@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0], comdat +@"\01??_R1A@?0A@EA@C@@8" = linkonce_odr constant %rtti.BaseClassDescriptor { i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"\01??_R0?AVC@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 2, i32 0, i32 -1, i32 0, i32 64, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"\01??_R3C@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat +@"\01??_R1A@A@3FA@A@@8" = linkonce_odr constant %rtti.BaseClassDescriptor { i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"\01??_R0?AVA@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 0, i32 0, i32 4, i32 80, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"\01??_R3A@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat +@"\01??_R0?AVA@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AVA@@\00" }, comdat +@"\01??_R3A@@8" = linkonce_odr constant %rtti.ClassHierarchyDescriptor { i32 0, i32 0, i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint ([2 x i32]* @"\01??_R2A@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat +@"\01??_R2A@@8" = linkonce_odr constant [2 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.BaseClassDescriptor* @"\01??_R1A@?0A@EA@A@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0], comdat +@"\01??_R1A@?0A@EA@A@@8" = linkonce_odr constant %rtti.BaseClassDescriptor { i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"\01??_R0?AVA@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 0, i32 -1, i32 0, i32 64, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"\01??_R3A@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat +@"\01??_R1A@A@7FA@B@@8" = linkonce_odr constant %rtti.BaseClassDescriptor { i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"\01??_R0?AVB@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 0, i32 0, i32 8, i32 80, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"\01??_R3B@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat +@"\01??_R0?AVB@@@8" = linkonce_odr global %rtti.TypeDescriptor7 { i8** @"\01??_7type_info@@6B@", i8* null, [8 x i8] c".?AVB@@\00" }, comdat +@"\01??_R3B@@8" = linkonce_odr constant %rtti.ClassHierarchyDescriptor { i32 0, i32 0, i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint ([2 x i32]* @"\01??_R2B@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat +@"\01??_R2B@@8" = linkonce_odr constant [2 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.BaseClassDescriptor* @"\01??_R1A@?0A@EA@B@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0], comdat +@"\01??_R1A@?0A@EA@B@@8" = linkonce_odr constant %rtti.BaseClassDescriptor { i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"\01??_R0?AVB@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 0, i32 -1, i32 0, i32 64, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"\01??_R3B@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat +@"\01??_R4C@@6BB@@@" = linkonce_odr constant %rtti.CompleteObjectLocator { i32 1, i32 16, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"\01??_R0?AVC@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"\01??_R3C@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.CompleteObjectLocator* @"\01??_R4C@@6BB@@@" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat +@2 = private unnamed_addr constant { [2 x i8*] } { [2 x i8*] [i8* bitcast (%rtti.CompleteObjectLocator* @"\01??_R4A@@6B@" to i8*), i8* bitcast (i1 (%class.A*)* @"\01?MyMethod@A@@UEAA_NXZ" to i8*)] }, comdat($"\01??_7A@@6B@") +@"\01??_R4A@@6B@" = linkonce_odr constant %rtti.CompleteObjectLocator { i32 1, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"\01??_R0?AVA@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"\01??_R3A@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.CompleteObjectLocator* @"\01??_R4A@@6B@" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat +@3 = private unnamed_addr constant { [2 x i8*] } { [2 x i8*] [i8* bitcast (%rtti.CompleteObjectLocator* @"\01??_R4B@@6B@" to i8*), i8* bitcast (i1 (%class.B*)* @"\01?MyMethod@B@@UEAA_NXZ" to i8*)] }, comdat($"\01??_7B@@6B@") +@"\01??_R4B@@6B@" = linkonce_odr constant %rtti.CompleteObjectLocator { i32 1, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor7* @"\01??_R0?AVB@@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.ClassHierarchyDescriptor* @"\01??_R3B@@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.CompleteObjectLocator* @"\01??_R4B@@6B@" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, comdat + +@"\01??_7C@@6BA@@@" = unnamed_addr alias i8*, getelementptr inbounds ({ [2 x i8*] }, { [2 x i8*] }* @0, i32 0, i32 0, i32 1) +@"\01??_7C@@6BB@@@" = unnamed_addr alias i8*, getelementptr inbounds ({ [2 x i8*] }, { [2 x i8*] }* @1, i32 0, i32 0, i32 1) +@"\01??_7A@@6B@" = unnamed_addr alias i8*, getelementptr inbounds ({ [2 x i8*] }, { [2 x i8*] }* @2, i32 0, i32 0, i32 1) +@"\01??_7B@@6B@" = unnamed_addr alias i8*, getelementptr inbounds ({ [2 x i8*] }, { [2 x i8*] }* @3, i32 0, i32 0, i32 1) + +; Function Attrs: noinline norecurse uwtable +define i32 @main() #0 !dbg !7 { +entry: + %retval = alloca i32, align 4 + %a = alloca %class.A*, align 8 + %b = alloca %class.B*, align 8 + %c = alloca %class.C*, align 8 + store i32 0, i32* %retval, align 4 + call void @llvm.dbg.declare(metadata %class.A** %a, metadata !11, metadata !23), !dbg !24 + %call = call i8* @"\01??2@YAPEAX_K@Z"(i64 24) #6, !dbg !25 + %0 = bitcast i8* %call to %class.C*, !dbg !25 + %1 = bitcast %class.C* %0 to i8*, !dbg !26 + call void @llvm.memset.p0i8.i64(i8* %1, i8 0, i64 24, i32 8, i1 false), !dbg !26 + %call1 = call %class.C* @"\01??0C@@QEAA@XZ"(%class.C* %0, i32 1) #7, !dbg !27 + %2 = icmp eq %class.C* %0, null, !dbg !25 + br i1 %2, label %cast.end, label %cast.notnull, !dbg !25 + +cast.notnull: ; preds = %entry + %3 = bitcast %class.C* %0 to i8*, !dbg !29 + %vbptr = getelementptr inbounds i8, i8* %3, i64 0, !dbg !29 + %4 = bitcast i8* %vbptr to i32**, !dbg !29 + %vbtable = load i32*, i32** %4, align 8, !dbg !29 + %5 = getelementptr inbounds i32, i32* %vbtable, i32 1, !dbg !29 + %vbase_offs = load i32, i32* %5, align 4, !dbg !29 + %6 = sext i32 %vbase_offs to i64, !dbg !29 + %7 = add nsw i64 0, %6, !dbg !29 + %8 = bitcast %class.C* %0 to i8*, !dbg !29 + %add.ptr = getelementptr inbounds i8, i8* %8, i64 %7, !dbg !29 + %9 = bitcast i8* %add.ptr to %class.A*, !dbg !29 + br label %cast.end, !dbg !29 + +cast.end: ; preds = %cast.notnull, %entry + %cast.result = phi %class.A* [ %9, %cast.notnull ], [ null, %entry ], !dbg !31 + store %class.A* %cast.result, %class.A** %a, align 8, !dbg !33 + call void @llvm.dbg.declare(metadata %class.B** %b, metadata !34, metadata !23), !dbg !43 + %call2 = call i8* @"\01??2@YAPEAX_K@Z"(i64 24) #6, !dbg !44 + %10 = bitcast i8* %call2 to %class.C*, !dbg !44 + %11 = bitcast %class.C* %10 to i8*, !dbg !45 + call void @llvm.memset.p0i8.i64(i8* %11, i8 0, i64 24, i32 8, i1 false), !dbg !45 + %call3 = call %class.C* @"\01??0C@@QEAA@XZ"(%class.C* %10, i32 1) #7, !dbg !46 + %12 = icmp eq %class.C* %10, null, !dbg !44 + br i1 %12, label %cast.end9, label %cast.notnull4, !dbg !44 + +cast.notnull4: ; preds = %cast.end + %13 = bitcast %class.C* %10 to i8*, !dbg !47 + %vbptr5 = getelementptr inbounds i8, i8* %13, i64 0, !dbg !47 + %14 = bitcast i8* %vbptr5 to i32**, !dbg !47 + %vbtable6 = load i32*, i32** %14, align 8, !dbg !47 + %15 = getelementptr inbounds i32, i32* %vbtable6, i32 2, !dbg !47 + %vbase_offs7 = load i32, i32* %15, align 4, !dbg !47 + %16 = sext i32 %vbase_offs7 to i64, !dbg !47 + %17 = add nsw i64 0, %16, !dbg !47 + %18 = bitcast %class.C* %10 to i8*, !dbg !47 + %add.ptr8 = getelementptr inbounds i8, i8* %18, i64 %17, !dbg !47 + %19 = bitcast i8* %add.ptr8 to %class.B*, !dbg !47 + br label %cast.end9, !dbg !47 + +cast.end9: ; preds = %cast.notnull4, %cast.end + %cast.result10 = phi %class.B* [ %19, %cast.notnull4 ], [ null, %cast.end ], !dbg !48 + store %class.B* %cast.result10, %class.B** %b, align 8, !dbg !49 + call void @llvm.dbg.declare(metadata %class.C** %c, metadata !50, metadata !23), !dbg !60 + %call11 = call i8* @"\01??2@YAPEAX_K@Z"(i64 24) #6, !dbg !61 + %20 = bitcast i8* %call11 to %class.C*, !dbg !61 + %21 = bitcast %class.C* %20 to i8*, !dbg !62 + call void @llvm.memset.p0i8.i64(i8* %21, i8 0, i64 24, i32 8, i1 false), !dbg !62 + %call12 = call %class.C* @"\01??0C@@QEAA@XZ"(%class.C* %20, i32 1) #7, !dbg !63 + store %class.C* %20, %class.C** %c, align 8, !dbg !60 + %22 = load %class.A*, %class.A** %a, align 8, !dbg !64 + %23 = bitcast %class.A* %22 to i1 (%class.A*)***, !dbg !65 + %vtable = load i1 (%class.A*)**, i1 (%class.A*)*** %23, align 8, !dbg !65 + %vfn = getelementptr inbounds i1 (%class.A*)*, i1 (%class.A*)** %vtable, i64 0, !dbg !65 + %24 = load i1 (%class.A*)*, i1 (%class.A*)** %vfn, align 8, !dbg !65 + %call13 = call zeroext i1 %24(%class.A* %22), !dbg !65 + %25 = load %class.B*, %class.B** %b, align 8, !dbg !66 + %26 = bitcast %class.B* %25 to i1 (%class.B*)***, !dbg !67 + %vtable14 = load i1 (%class.B*)**, i1 (%class.B*)*** %26, align 8, !dbg !67 + %vfn15 = getelementptr inbounds i1 (%class.B*)*, i1 (%class.B*)** %vtable14, i64 0, !dbg !67 + %27 = load i1 (%class.B*)*, i1 (%class.B*)** %vfn15, align 8, !dbg !67 + %call16 = call zeroext i1 %27(%class.B* %25), !dbg !67 + %28 = load %class.C*, %class.C** %c, align 8, !dbg !68 + %29 = bitcast %class.C* %28 to i8*, !dbg !69 + %vbptr17 = getelementptr inbounds i8, i8* %29, i64 0, !dbg !69 + %30 = bitcast i8* %vbptr17 to i32**, !dbg !69 + %vbtable18 = load i32*, i32** %30, align 8, !dbg !69 + %31 = getelementptr inbounds i32, i32* %vbtable18, i32 1, !dbg !69 + %vbase_offs19 = load i32, i32* %31, align 4, !dbg !69 + %32 = sext i32 %vbase_offs19 to i64, !dbg !69 + %33 = add nsw i64 0, %32, !dbg !69 + %34 = getelementptr inbounds i8, i8* %29, i64 %33, !dbg !69 + %35 = bitcast i8* %34 to i1 (i8*)***, !dbg !69 + %vtable20 = load i1 (i8*)**, i1 (i8*)*** %35, align 8, !dbg !69 + %vfn21 = getelementptr inbounds i1 (i8*)*, i1 (i8*)** %vtable20, i64 0, !dbg !69 + %36 = load i1 (i8*)*, i1 (i8*)** %vfn21, align 8, !dbg !69 + %37 = bitcast %class.C* %28 to i8*, !dbg !69 + %vbptr22 = getelementptr inbounds i8, i8* %37, i64 0, !dbg !69 + %38 = bitcast i8* %vbptr22 to i32**, !dbg !69 + %vbtable23 = load i32*, i32** %38, align 8, !dbg !69 + %39 = getelementptr inbounds i32, i32* %vbtable23, i32 1, !dbg !69 + %vbase_offs24 = load i32, i32* %39, align 4, !dbg !69 + %40 = sext i32 %vbase_offs24 to i64, !dbg !69 + %41 = add nsw i64 0, %40, !dbg !69 + %42 = getelementptr inbounds i8, i8* %37, i64 %41, !dbg !69 + %call25 = call zeroext i1 %36(i8* %42), !dbg !69 + ret i32 0, !dbg !70 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nobuiltin +declare noalias i8* @"\01??2@YAPEAX_K@Z"(i64) #2 + +; Function Attrs: argmemonly nounwind +declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1) #3 + +; Function Attrs: noinline nounwind uwtable +define linkonce_odr %class.C* @"\01??0C@@QEAA@XZ"(%class.C* returned %this, i32 %is_most_derived) unnamed_addr #4 comdat align 2 !dbg !71 { +entry: + %retval = alloca %class.C*, align 8 + %is_most_derived.addr = alloca i32, align 4 + %this.addr = alloca %class.C*, align 8 + store i32 %is_most_derived, i32* %is_most_derived.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %is_most_derived.addr, metadata !75, metadata !23), !dbg !76 + store %class.C* %this, %class.C** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %class.C** %this.addr, metadata !77, metadata !23), !dbg !76 + %this1 = load %class.C*, %class.C** %this.addr, align 8 + store %class.C* %this1, %class.C** %retval, align 8 + %is_most_derived2 = load i32, i32* %is_most_derived.addr, align 4 + %is_complete_object = icmp ne i32 %is_most_derived2, 0, !dbg !78 + br i1 %is_complete_object, label %ctor.init_vbases, label %ctor.skip_vbases, !dbg !78 + +ctor.init_vbases: ; preds = %entry + %this.int8 = bitcast %class.C* %this1 to i8*, !dbg !79 + %0 = getelementptr inbounds i8, i8* %this.int8, i64 0, !dbg !79 + %vbptr.C = bitcast i8* %0 to i32**, !dbg !79 + store i32* getelementptr inbounds ([3 x i32], [3 x i32]* @"\01??_8C@@7B@", i32 0, i32 0), i32** %vbptr.C, align 8, !dbg !79 + %1 = bitcast %class.C* %this1 to i8*, !dbg !79 + %2 = getelementptr inbounds i8, i8* %1, i64 8, !dbg !79 + %3 = bitcast i8* %2 to %class.A*, !dbg !79 + %call = call %class.A* @"\01??0A@@QEAA@XZ"(%class.A* %3) #7, !dbg !79 + %4 = bitcast %class.C* %this1 to i8*, !dbg !79 + %5 = getelementptr inbounds i8, i8* %4, i64 16, !dbg !79 + %6 = bitcast i8* %5 to %class.B*, !dbg !79 + %call3 = call %class.B* @"\01??0B@@QEAA@XZ"(%class.B* %6) #7, !dbg !81 + br label %ctor.skip_vbases, !dbg !79 + +ctor.skip_vbases: ; preds = %ctor.init_vbases, %entry + %7 = bitcast %class.C* %this1 to i8*, !dbg !83 + %vbptr = getelementptr inbounds i8, i8* %7, i64 0, !dbg !83 + %8 = bitcast i8* %vbptr to i32**, !dbg !83 + %vbtable = load i32*, i32** %8, align 8, !dbg !83 + %9 = getelementptr inbounds i32, i32* %vbtable, i32 1, !dbg !83 + %vbase_offs = load i32, i32* %9, align 4, !dbg !83 + %10 = sext i32 %vbase_offs to i64, !dbg !83 + %11 = add nsw i64 0, %10, !dbg !83 + %12 = bitcast %class.C* %this1 to i8*, !dbg !83 + %add.ptr = getelementptr inbounds i8, i8* %12, i64 %11, !dbg !83 + %13 = bitcast i8* %add.ptr to i32 (...)***, !dbg !83 + store i32 (...)** bitcast (i8** @"\01??_7C@@6BA@@@" to i32 (...)**), i32 (...)*** %13, align 8, !dbg !83 + %14 = bitcast %class.C* %this1 to i8*, !dbg !83 + %vbptr4 = getelementptr inbounds i8, i8* %14, i64 0, !dbg !83 + %15 = bitcast i8* %vbptr4 to i32**, !dbg !83 + %vbtable5 = load i32*, i32** %15, align 8, !dbg !83 + %16 = getelementptr inbounds i32, i32* %vbtable5, i32 2, !dbg !83 + %vbase_offs6 = load i32, i32* %16, align 4, !dbg !83 + %17 = sext i32 %vbase_offs6 to i64, !dbg !83 + %18 = add nsw i64 0, %17, !dbg !83 + %19 = bitcast %class.C* %this1 to i8*, !dbg !83 + %add.ptr7 = getelementptr inbounds i8, i8* %19, i64 %18, !dbg !83 + %20 = bitcast i8* %add.ptr7 to i32 (...)***, !dbg !83 + store i32 (...)** bitcast (i8** @"\01??_7C@@6BB@@@" to i32 (...)**), i32 (...)*** %20, align 8, !dbg !83 + %21 = load %class.C*, %class.C** %retval, align 8, !dbg !83 + ret %class.C* %21, !dbg !83 +} + +; Function Attrs: noinline nounwind uwtable +define linkonce_odr %class.A* @"\01??0A@@QEAA@XZ"(%class.A* returned %this) unnamed_addr #4 comdat align 2 !dbg !85 { +entry: + %this.addr = alloca %class.A*, align 8 + store %class.A* %this, %class.A** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %class.A** %this.addr, metadata !89, metadata !23), !dbg !90 + %this1 = load %class.A*, %class.A** %this.addr, align 8 + %0 = bitcast %class.A* %this1 to i32 (...)***, !dbg !91 + store i32 (...)** bitcast (i8** @"\01??_7A@@6B@" to i32 (...)**), i32 (...)*** %0, align 8, !dbg !91 + ret %class.A* %this1, !dbg !91 +} + +; Function Attrs: noinline nounwind uwtable +define linkonce_odr %class.B* @"\01??0B@@QEAA@XZ"(%class.B* returned %this) unnamed_addr #4 comdat align 2 !dbg !92 { +entry: + %this.addr = alloca %class.B*, align 8 + store %class.B* %this, %class.B** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %class.B** %this.addr, metadata !96, metadata !23), !dbg !97 + %this1 = load %class.B*, %class.B** %this.addr, align 8 + %0 = bitcast %class.B* %this1 to i32 (...)***, !dbg !98 + store i32 (...)** bitcast (i8** @"\01??_7B@@6B@" to i32 (...)**), i32 (...)*** %0, align 8, !dbg !98 + ret %class.B* %this1, !dbg !98 +} + +; Function Attrs: noinline nounwind uwtable +define linkonce_odr zeroext i1 @"\01?MyMethod@C@@UEAA_NXZ"(i8*) unnamed_addr #4 comdat align 2 !dbg !99 { +entry: + %this.addr = alloca %class.C*, align 8 + %this = bitcast i8* %0 to %class.C* + %1 = bitcast %class.C* %this to i8* + %2 = getelementptr inbounds i8, i8* %1, i32 -8 + %3 = bitcast i8* %2 to %class.C* + store %class.C* %3, %class.C** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %class.C** %this.addr, metadata !100, metadata !23), !dbg !101 + %this1 = load %class.C*, %class.C** %this.addr, align 8 + ret i1 true, !dbg !102 +} + +; Function Attrs: noinline uwtable +define linkonce_odr zeroext i1 @"\01?MyMethod@C@@W7EAA_NXZ"(i8*) unnamed_addr #5 comdat align 2 !dbg !103 { +entry: + %this.addr = alloca %class.C*, align 8 + %this = bitcast i8* %0 to %class.C* + store %class.C* %this, %class.C** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %class.C** %this.addr, metadata !105, metadata !23), !dbg !106 + %this1 = load %class.C*, %class.C** %this.addr, align 8, !dbg !106 + %1 = bitcast %class.C* %this1 to i8*, !dbg !106 + %2 = getelementptr i8, i8* %1, i32 -8, !dbg !106 + %call = tail call zeroext i1 @"\01?MyMethod@C@@UEAA_NXZ"(i8* %2), !dbg !106 + ret i1 %call, !dbg !106 +} + +; Function Attrs: noinline nounwind uwtable +define linkonce_odr zeroext i1 @"\01?MyMethod@A@@UEAA_NXZ"(%class.A* %this) unnamed_addr #4 comdat align 2 !dbg !107 { +entry: + %this.addr = alloca %class.A*, align 8 + store %class.A* %this, %class.A** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %class.A** %this.addr, metadata !108, metadata !23), !dbg !109 + %this1 = load %class.A*, %class.A** %this.addr, align 8 + ret i1 true, !dbg !110 +} + +; Function Attrs: noinline nounwind uwtable +define linkonce_odr zeroext i1 @"\01?MyMethod@B@@UEAA_NXZ"(%class.B* %this) unnamed_addr #4 comdat align 2 !dbg !111 { +entry: + %this.addr = alloca %class.B*, align 8 + store %class.B* %this, %class.B** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %class.B** %this.addr, metadata !112, metadata !23), !dbg !113 + %this1 = load %class.B*, %class.B** %this.addr, align 8 + ret i1 true, !dbg !114 +} + +attributes #0 = { noinline norecurse uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "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"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nobuiltin "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #3 = { argmemonly nounwind } +attributes #4 = { noinline nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "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"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #5 = { noinline uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "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"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #6 = { builtin } +attributes #7 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 5.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "thunk.cpp", directory: "C:/path/to/directory", checksumkind: CSK_MD5, checksum: "f5c2ef3ded84645a49347c61948c7970") +!2 = !{} +!3 = !{i32 2, !"CodeView", i32 1} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"PIC Level", i32 2} +!6 = !{!"clang version 5.0.0"} +!7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 8, type: !8, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocalVariable(name: "a", scope: !7, file: !1, line: 10, type: !12) +!12 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) +!13 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "A", file: !1, line: 1, size: 64, elements: !14, vtableHolder: !13, identifier: ".?AVA@@") +!14 = !{!15, !16, !18} +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "__vtbl_ptr_type", baseType: null, size: 64) +!16 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$A", scope: !1, file: !1, baseType: !17, size: 64, flags: DIFlagArtificial) +!17 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) +!18 = !DISubprogram(name: "MyMethod", linkageName: "\01?MyMethod@A@@UEAA_NXZ", scope: !13, file: !1, line: 1, type: !19, isLocal: false, isDefinition: false, scopeLine: 1, containingType: !13, virtuality: DW_VIRTUALITY_virtual, virtualIndex: 0, flags: DIFlagPublic | DIFlagPrototyped | DIFlagIntroducedVirtual, isOptimized: false) +!19 = !DISubroutineType(types: !20) +!20 = !{!21, !22} +!21 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) +!22 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!23 = !DIExpression() +!24 = !DILocation(line: 10, column: 8, scope: !7) +!25 = !DILocation(line: 10, column: 12, scope: !7) +!26 = !DILocation(line: 10, column: 16, scope: !7) +!27 = !DILocation(line: 10, column: 16, scope: !28) +!28 = !DILexicalBlockFile(scope: !7, file: !1, discriminator: 6) +!29 = !DILocation(line: 10, column: 12, scope: !30) +!30 = !DILexicalBlockFile(scope: !7, file: !1, discriminator: 2) +!31 = !DILocation(line: 10, column: 12, scope: !32) +!32 = !DILexicalBlockFile(scope: !7, file: !1, discriminator: 4) +!33 = !DILocation(line: 10, column: 8, scope: !32) +!34 = !DILocalVariable(name: "b", scope: !7, file: !1, line: 11, type: !35) +!35 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !36, size: 64) +!36 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "B", file: !1, line: 2, size: 64, elements: !37, vtableHolder: !36, identifier: ".?AVB@@") +!37 = !{!15, !38, !39} +!38 = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$B", scope: !1, file: !1, baseType: !17, size: 64, flags: DIFlagArtificial) +!39 = !DISubprogram(name: "MyMethod", linkageName: "\01?MyMethod@B@@UEAA_NXZ", scope: !36, file: !1, line: 2, type: !40, isLocal: false, isDefinition: false, scopeLine: 2, containingType: !36, virtuality: DW_VIRTUALITY_virtual, virtualIndex: 0, flags: DIFlagPublic | DIFlagPrototyped | DIFlagIntroducedVirtual, isOptimized: false) +!40 = !DISubroutineType(types: !41) +!41 = !{!21, !42} +!42 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !36, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!43 = !DILocation(line: 11, column: 8, scope: !7) +!44 = !DILocation(line: 11, column: 12, scope: !7) +!45 = !DILocation(line: 11, column: 16, scope: !7) +!46 = !DILocation(line: 11, column: 16, scope: !28) +!47 = !DILocation(line: 11, column: 12, scope: !30) +!48 = !DILocation(line: 11, column: 12, scope: !32) +!49 = !DILocation(line: 11, column: 8, scope: !32) +!50 = !DILocalVariable(name: "c", scope: !7, file: !1, line: 12, type: !51) +!51 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !52, size: 64) +!52 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "C", file: !1, line: 3, size: 192, elements: !53, vtableHolder: !52, identifier: ".?AVC@@") +!53 = !{!54, !55, !56} +!54 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !52, baseType: !13, offset: 4, flags: DIFlagPublic | DIFlagVirtual) +!55 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !52, baseType: !36, offset: 8, flags: DIFlagPublic | DIFlagVirtual) +!56 = !DISubprogram(name: "MyMethod", linkageName: "\01?MyMethod@C@@UEAA_NXZ", scope: !52, file: !1, line: 5, type: !57, isLocal: false, isDefinition: false, scopeLine: 5, containingType: !52, virtuality: DW_VIRTUALITY_virtual, virtualIndex: 0, thisAdjustment: 8, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: false) +!57 = !DISubroutineType(types: !58) +!58 = !{!21, !59} +!59 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !52, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!60 = !DILocation(line: 12, column: 8, scope: !7) +!61 = !DILocation(line: 12, column: 12, scope: !7) +!62 = !DILocation(line: 12, column: 16, scope: !7) +!63 = !DILocation(line: 12, column: 16, scope: !30) +!64 = !DILocation(line: 13, column: 5, scope: !7) +!65 = !DILocation(line: 13, column: 8, scope: !7) +!66 = !DILocation(line: 14, column: 5, scope: !7) +!67 = !DILocation(line: 14, column: 8, scope: !7) +!68 = !DILocation(line: 15, column: 5, scope: !7) +!69 = !DILocation(line: 15, column: 8, scope: !7) +!70 = !DILocation(line: 16, column: 5, scope: !7) +!71 = distinct !DISubprogram(name: "C", linkageName: "\01??0C@@QEAA@XZ", scope: !52, file: !1, line: 3, type: !72, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !74, variables: !2) +!72 = !DISubroutineType(types: !73) +!73 = !{null, !59} +!74 = !DISubprogram(name: "C", scope: !52, type: !72, isLocal: false, isDefinition: false, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, isOptimized: false) +!75 = !DILocalVariable(name: "is_most_derived", arg: 2, scope: !71, type: !10, flags: DIFlagArtificial) +!76 = !DILocation(line: 0, scope: !71) +!77 = !DILocalVariable(name: "this", arg: 1, scope: !71, type: !51, flags: DIFlagArtificial | DIFlagObjectPointer) +!78 = !DILocation(line: 3, column: 7, scope: !71) +!79 = !DILocation(line: 3, column: 7, scope: !80) +!80 = !DILexicalBlockFile(scope: !71, file: !1, discriminator: 2) +!81 = !DILocation(line: 3, column: 7, scope: !82) +!82 = !DILexicalBlockFile(scope: !71, file: !1, discriminator: 6) +!83 = !DILocation(line: 3, column: 7, scope: !84) +!84 = !DILexicalBlockFile(scope: !71, file: !1, discriminator: 4) +!85 = distinct !DISubprogram(name: "A", linkageName: "\01??0A@@QEAA@XZ", scope: !13, file: !1, line: 1, type: !86, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !88, variables: !2) +!86 = !DISubroutineType(types: !87) +!87 = !{null, !22} +!88 = !DISubprogram(name: "A", scope: !13, type: !86, isLocal: false, isDefinition: false, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, isOptimized: false) +!89 = !DILocalVariable(name: "this", arg: 1, scope: !85, type: !12, flags: DIFlagArtificial | DIFlagObjectPointer) +!90 = !DILocation(line: 0, scope: !85) +!91 = !DILocation(line: 1, column: 7, scope: !85) +!92 = distinct !DISubprogram(name: "B", linkageName: "\01??0B@@QEAA@XZ", scope: !36, file: !1, line: 2, type: !93, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagArtificial | DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !95, variables: !2) +!93 = !DISubroutineType(types: !94) +!94 = !{null, !42} +!95 = !DISubprogram(name: "B", scope: !36, type: !93, isLocal: false, isDefinition: false, flags: DIFlagPublic | DIFlagArtificial | DIFlagPrototyped, isOptimized: false) +!96 = !DILocalVariable(name: "this", arg: 1, scope: !92, type: !35, flags: DIFlagArtificial | DIFlagObjectPointer) +!97 = !DILocation(line: 0, scope: !92) +!98 = !DILocation(line: 2, column: 7, scope: !92) +!99 = distinct !DISubprogram(name: "MyMethod", linkageName: "\01?MyMethod@C@@UEAA_NXZ", scope: !52, file: !1, line: 5, type: !57, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !56, variables: !2) +!100 = !DILocalVariable(name: "this", arg: 1, scope: !99, type: !51, flags: DIFlagArtificial | DIFlagObjectPointer) +!101 = !DILocation(line: 0, scope: !99) +!102 = !DILocation(line: 5, column: 31, scope: !99) +!103 = distinct !DISubprogram(linkageName: "\01?MyMethod@C@@W7EAA_NXZ", scope: !1, file: !1, line: 5, type: !104, isLocal: false, isDefinition: true, flags: DIFlagArtificial | DIFlagThunk, isOptimized: false, unit: !0, variables: !2) +!104 = !DISubroutineType(types: !2) +!105 = !DILocalVariable(name: "this", arg: 1, scope: !103, type: !51, flags: DIFlagArtificial | DIFlagObjectPointer) +!106 = !DILocation(line: 0, scope: !103) +!107 = distinct !DISubprogram(name: "MyMethod", linkageName: "\01?MyMethod@A@@UEAA_NXZ", scope: !13, file: !1, line: 1, type: !19, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !18, variables: !2) +!108 = !DILocalVariable(name: "this", arg: 1, scope: !107, type: !12, flags: DIFlagArtificial | DIFlagObjectPointer) +!109 = !DILocation(line: 0, scope: !107) +!110 = !DILocation(line: 1, column: 45, scope: !107) +!111 = distinct !DISubprogram(name: "MyMethod", linkageName: "\01?MyMethod@B@@UEAA_NXZ", scope: !36, file: !1, line: 2, type: !40, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !0, declaration: !39, variables: !2) +!112 = !DILocalVariable(name: "this", arg: 1, scope: !111, type: !35, flags: DIFlagArtificial | DIFlagObjectPointer) +!113 = !DILocation(line: 0, scope: !111) +!114 = !DILocation(line: 2, column: 45, scope: !111) + Index: llvm/tools/clang/lib/CodeGen/CGDebugInfo.h =================================================================== --- llvm/tools/clang/lib/CodeGen/CGDebugInfo.h +++ llvm/tools/clang/lib/CodeGen/CGDebugInfo.h @@ -366,7 +366,8 @@ /// \param ScopeLoc The location of the function body. void EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, SourceLocation ScopeLoc, QualType FnType, - llvm::Function *Fn, CGBuilderTy &Builder); + llvm::Function *Fn, bool CurFnIsThunk, + CGBuilderTy &Builder); /// Start a new scope for an inlined function. void EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD); Index: llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp +++ llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp @@ -3194,7 +3194,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, SourceLocation ScopeLoc, QualType FnType, - llvm::Function *Fn, CGBuilderTy &Builder) { + llvm::Function *Fn, bool CurFuncIsThunk, + CGBuilderTy &Builder) { StringRef Name; StringRef LinkageName; @@ -3240,6 +3241,10 @@ // Artificial functions should not silently reuse CurLoc. CurLoc = SourceLocation(); } + + if (CurFuncIsThunk) + Flags |= llvm::DINode::FlagThunk; + unsigned LineNo = getLineNumber(Loc); unsigned ScopeLine = getLineNumber(ScopeLoc); Index: llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp +++ llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp @@ -997,7 +997,8 @@ ArgTypes.push_back(VD->getType()); QualType FnType = getContext().getFunctionType( RetTy, ArgTypes, FunctionProtoType::ExtProtoInfo(CC)); - DI->EmitFunctionStart(GD, Loc, StartLoc, FnType, CurFn, Builder); + DI->EmitFunctionStart(GD, Loc, StartLoc, FnType, CurFn, CurFuncIsThunk, + Builder); } if (ShouldInstrumentFunction()) {