Author: bwyma Date: Mon Apr 16 09:53:57 2018 New Revision: 330132 URL: http://llvm.org/viewvc/llvm-project?rev=330132&view=rev Log: [CodeView] Initial support for emitting S_THUNK32 symbols for compiler...
When emitting CodeView debug information, compiler-generated thunk routines should be emitted using S_THUNK32 symbols instead of S_GPROC32_ID symbols so Visual Studio can properly step into the user code. This initial support only handles standard thunk ordinals. Differential Revision: https://reviews.llvm.org/D43838 Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp cfe/trunk/lib/CodeGen/CGDebugInfo.h cfe/trunk/lib/CodeGen/CodeGenFunction.cpp cfe/trunk/test/CodeGenCXX/debug-info-thunk.cpp Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=330132&r1=330131&r2=330132&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Mon Apr 16 09:53:57 2018 @@ -3217,7 +3217,8 @@ llvm::DISubroutineType *CGDebugInfo::get 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; @@ -3263,6 +3264,10 @@ void CGDebugInfo::EmitFunctionStart(Glob // Artificial functions should not silently reuse CurLoc. CurLoc = SourceLocation(); } + + if (CurFuncIsThunk) + Flags |= llvm::DINode::FlagThunk; + unsigned LineNo = getLineNumber(Loc); unsigned ScopeLine = getLineNumber(ScopeLoc); Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.h?rev=330132&r1=330131&r2=330132&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDebugInfo.h (original) +++ cfe/trunk/lib/CodeGen/CGDebugInfo.h Mon Apr 16 09:53:57 2018 @@ -366,7 +366,8 @@ public: /// \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); Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=330132&r1=330131&r2=330132&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Mon Apr 16 09:53:57 2018 @@ -1018,7 +1018,8 @@ void CodeGenFunction::StartFunction(Glob 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()) { Modified: cfe/trunk/test/CodeGenCXX/debug-info-thunk.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/debug-info-thunk.cpp?rev=330132&r1=330131&r2=330132&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/debug-info-thunk.cpp (original) +++ cfe/trunk/test/CodeGenCXX/debug-info-thunk.cpp Mon Apr 16 09:53:57 2018 @@ -1,29 +1,277 @@ -// RUN: %clang_cc1 %s -triple %itanium_abi_triple -debug-info-kind=limited -S -emit-llvm -o - | FileCheck %s - -struct A { - virtual void f(); -}; - -struct B { - virtual void f(); -}; - -struct C : A, B { - virtual void f(); -}; - -void C::f() { } -// CHECK: define {{.*}}void @_ZThn{{[48]}}_N1C1fEv -// CHECK-SAME: !dbg ![[SP:[0-9]+]] -// CHECK-NOT: {{ret }} -// CHECK: = load{{.*}} !dbg ![[DBG:[0-9]+]] -// CHECK-NOT: {{ret }} -// CHECK: ret void, !dbg ![[DBG]] +// RUN: %clang_cc1 %s -triple=x86_64-pc-windows-msvc -debug-info-kind=limited -S -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple %itanium_abi_triple -debug-info-kind=limited -S -emit-llvm -o - | FileCheck %s -check-prefix=ITANIUM +// +// Validate we emit a "DIFlagThunk" flag on DISubprogram entries for thunks. +// This flag is used for emitting S_THUNK32 symbols for CodeView debugging. +// +// NOTE: +// Because thunks are compiler generated and don't exist in the source, this +// test is dependent upon the linkage name to identify the thunk. Any changes +// in the name mangling may require this test to be updated. // -// CHECK: ![[SP]] = distinct !DISubprogram(linkageName: "_ZThn{{[48]}}_N1C1fEv" -// CHECK-SAME: line: 15 -// CHECK-SAME: isDefinition: true -// CHECK-SAME: DIFlagArtificial -// CHECK-SAME: ){{$}} +// NOTE: +// The FileCheck directives below use CHECK-DAG because the thunks may not be +// emitted in source order. // -// CHECK: ![[DBG]] = !DILocation(line: 0 + +namespace Test1 { + struct A { + virtual void f(); + }; + + struct B { + virtual void f(); + }; + + struct C : A, B { + virtual void c(); + + virtual void f(); + }; + +// CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@C@Test1@@W7EAAXXZ"{{.*}} flags: {{.*}}DIFlagThunk + void C::f() { } +} + +namespace Test2 { + struct V1 { }; + struct V2 : virtual V1 { }; + + struct A { + virtual V1 *f(); + }; + + struct B : A { + virtual void b(); + + virtual V2 *f(); + }; + +// CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@B@Test2@@QEAAPEAUV1@2@XZ"{{.*}} flags: {{.*}}DIFlagThunk + V2 *B::f() { return 0; } +} + +namespace Test3 { + struct A { + virtual void f(); + }; + + struct B { + virtual void f(); + }; + + struct __attribute__((visibility("protected"))) C : A, B { + virtual void c(); + + virtual void f(); + }; + +// CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@C@Test3@@W7EAAXXZ"{{.*}} flags: {{.*}}DIFlagThunk + void C::f() { } +} + +namespace Test4 { + struct A { + virtual void f(); + }; + + struct B { + virtual void f(); + }; + + namespace { + struct C : A, B { + virtual void c(); + virtual void f(); + }; + } + void C::c() {} +// CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@C@?A@Test4@@W7EAAXXZ"{{.*}} flags: {{.*}}DIFlagThunk + void C::f() {} + + // Force C::f to be used. + void f() { + C c; + c.f(); + } +} + +namespace Test5 { + struct X { + X(); + X(const X&); + X &operator=(const X&); + ~X(); + }; + + struct P { + P(); + P(const P&); + ~P(); + X first; + X second; + }; + + P getP(); + + struct Base1 { + int i; + + virtual X f() { return X(); } + }; + + struct Base2 { + float real; + + virtual X f() { return X(); } + }; + + struct Thunks : Base1, Base2 { + long l; + + virtual X f(); + }; + +// CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@Thunks@Test5@@WBA@EAA?AUX@2@XZ"{{.*}} flags: {{.*}}DIFlagThunk + X Thunks::f() { return X(); } +} + +namespace Test6 { + struct X { + X(); + X(const X&); + X &operator=(const X&); + ~X(); + }; + + struct Small { short s; }; + struct Large { + char array[1024]; + }; + + class A { + protected: + virtual void foo() = 0; + }; + + class B : public A { + protected: + virtual void bar() = 0; + }; + + class C : public A { + protected: + virtual void baz(X, X&, _Complex float, Small, Small&, Large) = 0; + }; + + class D : public B, + public C { +// CHECK-DAG: DISubprogram{{.*}}linkageName: "?foo@D@Test6@@G7EAAXXZ"{{.*}} flags: {{.*}}DIFlagThunk + void foo() {} + void bar() {} + void baz(X, X&, _Complex float, Small, Small&, Large); + }; + + void D::baz(X, X&, _Complex float, Small, Small&, Large) { } + + void testD() { D d; } +} + +namespace Test7 { + struct A { virtual void foo(); }; + struct B { virtual void foo(); }; +// CHECK-DAG: DISubprogram{{.*}}linkageName: "?foo@C@Test7@@W7EAAXXZ"{{.*}} flags: {{.*}}DIFlagThunk + struct C : A, B { void foo() {} }; + + // Test later. + void test() { + C c; + } +} + +namespace Test8 { + struct A { virtual A* f(); }; + struct B : virtual A { virtual A* f(); }; + struct C : B { virtual C* f(); }; +// CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@C@Test8@@QEAAPEAUA@2@XZ"{{.*}} flags: {{.*}}DIFlagThunk + C* C::f() { return 0; } +} + +namespace Test9 { + struct B1 { + virtual B1 &foo1(); + }; + struct Pad1 { + virtual ~Pad1(); + }; + struct Proxy1 : Pad1, B1 { + virtual ~Proxy1(); + }; + struct D : virtual Proxy1 { + virtual ~D(); + virtual D &foo1(); + }; +// CHECK-DAG: DISubprogram{{.*}}linkageName: "?foo1@D@Test9@@$4PPPPPPPE@A@EAAAEAUB1@2@XZ"{{.*}} flags: {{.*}}DIFlagThunk +// CHECK-DAG: DISubprogram{{.*}}linkageName: "?foo1@D@Test9@@$4PPPPPPPE@A@EAAAEAU12@XZ"{{.*}} flags: {{.*}}DIFlagThunk + D& D::foo1() { + return *this; + } +} + +namespace Test10 { + class A { + virtual void f(); + }; + class B { + virtual void f(); + }; + class C : public A, public B { + virtual void f(); + }; +// CHECK-DAG: DISubprogram{{.*}}linkageName: "?f@C@Test10@@G7EAAXXZ"{{.*}} flags: {{.*}}DIFlagThunk + void C::f() { + } +} + +namespace Test11 { + class A { + public: + virtual void f(); + }; + + void test() { +// CHECK-DAG: DISubprogram{{.*}}linkageName: "??_9A@Test11@@$BA@AA"{{.*}} flags: {{.*}}DIFlagThunk + void (A::*p)() = &A::f; + } +} + +namespace Test12 { + struct A { + virtual void f(); + }; + + struct B { + virtual void f(); + }; + + struct C : A, B { + virtual void f(); + }; + + void C::f() { } + // ITANIUM: define {{.*}}void @_ZThn{{[48]}}_N6Test121C1fEv + // ITANIUM-SAME: !dbg ![[SP:[0-9]+]] + // ITANIUM-NOT: {{ret }} + // ITANIUM: = load{{.*}} !dbg ![[DBG:[0-9]+]] + // ITANIUM-NOT: {{ret }} + // ITANIUM: ret void, !dbg ![[DBG]] + // + // ITANIUM: ![[SP]] = distinct !DISubprogram(linkageName: "_ZThn{{[48]}}_N6Test121C1fEv" + // ITANIUM-SAME: line: 261 + // ITANIUM-SAME: isDefinition: true + // ITANIUM-SAME: DIFlagArtificial + // ITANIUM-SAME: DIFlagThunk + // ITANIUM-SAME: ){{$}} + // + // ITANIUM: ![[DBG]] = !DILocation(line: 0 +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits