mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 03:46:06 +00:00
MS ABI: Update the thunk linkage computation
As suggested by Reid: - class has GVA_Internal linkage -> internal - thunk has return adjustment -> weak_odr, to handle evil corner case [1] - all other normal methods -> linkonce_odr 1. Evil corner case: struct Incomplete; struct A { int a; virtual A *bar(); }; struct B { int b; virtual B *foo(Incomplete); }; struct C : A, B { int c; virtual C *foo(Incomplete); }; C c; Here, the thunk for C::foo() will be emitted when C::foo() is defined, which might be in a different translation unit, so it needs to be weak_odr. Differential Revision: http://reviews.llvm.org/D3992 llvm-svn: 210368
This commit is contained in:
parent
0766ae08e5
commit
c94391d3bf
@ -359,7 +359,8 @@ public:
|
||||
/// base tables.
|
||||
virtual void emitVirtualInheritanceTables(const CXXRecordDecl *RD) = 0;
|
||||
|
||||
virtual void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) = 0;
|
||||
virtual void setThunkLinkage(llvm::Function *Thunk, bool ForVTable,
|
||||
GlobalDecl GD, bool ReturnAdjustment) = 0;
|
||||
|
||||
virtual llvm::Value *performThisAdjustment(CodeGenFunction &CGF,
|
||||
llvm::Value *This,
|
||||
|
@ -382,12 +382,14 @@ void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
|
||||
// FIXME: Do something better here; GenerateVarArgsThunk is extremely ugly.
|
||||
if (!UseAvailableExternallyLinkage) {
|
||||
CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, Thunk);
|
||||
CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable);
|
||||
CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable, GD,
|
||||
!Thunk.Return.isEmpty());
|
||||
}
|
||||
} else {
|
||||
// Normal thunk body generation.
|
||||
CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk);
|
||||
CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable);
|
||||
CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable, GD,
|
||||
!Thunk.Return.isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,8 @@ public:
|
||||
|
||||
void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override;
|
||||
|
||||
void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) override {
|
||||
void setThunkLinkage(llvm::Function *Thunk, bool ForVTable, GlobalDecl GD,
|
||||
bool ReturnAdjustment) override {
|
||||
// Allow inlining of thunks by emitting them with available_externally
|
||||
// linkage together with vtables when needed.
|
||||
if (ForVTable)
|
||||
|
@ -201,11 +201,20 @@ public:
|
||||
void emitVBTableDefinition(const VPtrInfo &VBT, const CXXRecordDecl *RD,
|
||||
llvm::GlobalVariable *GV) const;
|
||||
|
||||
void setThunkLinkage(llvm::Function *Thunk, bool ForVTable) override {
|
||||
Thunk->setLinkage(llvm::GlobalValue::WeakAnyLinkage);
|
||||
|
||||
void setThunkLinkage(llvm::Function *Thunk, bool ForVTable,
|
||||
GlobalDecl GD, bool ReturnAdjustment) override {
|
||||
// Never dllimport/dllexport thunks.
|
||||
Thunk->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
|
||||
|
||||
GVALinkage Linkage =
|
||||
getContext().GetGVALinkageForFunction(cast<FunctionDecl>(GD.getDecl()));
|
||||
|
||||
if (Linkage == GVA_Internal)
|
||||
Thunk->setLinkage(llvm::GlobalValue::InternalLinkage);
|
||||
else if (ReturnAdjustment)
|
||||
Thunk->setLinkage(llvm::GlobalValue::WeakODRLinkage);
|
||||
else
|
||||
Thunk->setLinkage(llvm::GlobalValue::LinkOnceODRLinkage);
|
||||
}
|
||||
|
||||
llvm::Value *performThisAdjustment(CodeGenFunction &CGF, llvm::Value *This,
|
||||
|
@ -566,7 +566,7 @@ namespace DontUseDtorAlias {
|
||||
|
||||
namespace Vtordisp {
|
||||
// Don't dllimport the vtordisp.
|
||||
// MO1-DAG: define weak x86_thiscallcc void @"\01?f@?$C@D@Vtordisp@@$4PPPPPPPM@A@AEXXZ"
|
||||
// MO1-DAG: define linkonce_odr x86_thiscallcc void @"\01?f@?$C@D@Vtordisp@@$4PPPPPPPM@A@AEXXZ"
|
||||
|
||||
class Base {
|
||||
virtual void f() {}
|
||||
|
@ -153,7 +153,7 @@ C::~C() {
|
||||
void foo() {
|
||||
C c;
|
||||
}
|
||||
// DTORS2-LABEL: define weak x86_thiscallcc void @"\01??_EC@dtor_in_second_nvbase@@W3AEPAXI@Z"
|
||||
// DTORS2-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_EC@dtor_in_second_nvbase@@W3AEPAXI@Z"
|
||||
// DTORS2: (%"struct.dtor_in_second_nvbase::C"* %this, i32 %should_call_delete)
|
||||
// Do an adjustment from B* to C*.
|
||||
// DTORS2: getelementptr i8* %{{.*}}, i32 -4
|
||||
|
@ -61,13 +61,13 @@ struct C : A, B {
|
||||
|
||||
C::C() {} // Emits vftable and forces thunk generation.
|
||||
|
||||
// CODEGEN-LABEL: define weak x86_thiscallcc void @"\01??_EC@@W3AEPAXI@Z"(%struct.C* %this, i32 %should_call_delete)
|
||||
// CODEGEN-LABEL: define linkonce_odr x86_thiscallcc void @"\01??_EC@@W3AEPAXI@Z"(%struct.C* %this, i32 %should_call_delete)
|
||||
// CODEGEN: getelementptr i8* {{.*}}, i32 -4
|
||||
// FIXME: should actually call _EC, not _GC.
|
||||
// CODEGEN: call x86_thiscallcc void @"\01??_GC@@UAEPAXI@Z"
|
||||
// CODEGEN: ret
|
||||
|
||||
// CODEGEN-LABEL: define weak x86_thiscallcc void @"\01?public_f@C@@W3AEXXZ"(%struct.C*
|
||||
// CODEGEN-LABEL: define linkonce_odr x86_thiscallcc void @"\01?public_f@C@@W3AEXXZ"(%struct.C*
|
||||
// CODEGEN: getelementptr i8* {{.*}}, i32 -4
|
||||
// CODEGEN: call x86_thiscallcc void @"\01?public_f@C@@UAEXXZ"(%struct.C*
|
||||
// CODEGEN: ret
|
||||
@ -91,7 +91,7 @@ struct E : D {
|
||||
|
||||
E::E() {} // Emits vftable and forces thunk generation.
|
||||
|
||||
// CODEGEN-LABEL: define weak x86_thiscallcc %struct.C* @"\01?goo@E@@QAEPAUB@@XZ"
|
||||
// CODEGEN-LABEL: define weak_odr x86_thiscallcc %struct.C* @"\01?goo@E@@QAEPAUB@@XZ"
|
||||
// CODEGEN: call x86_thiscallcc %struct.C* @"\01?goo@E@@UAEPAUC@@XZ"
|
||||
// CODEGEN: getelementptr inbounds i8* {{.*}}, i32 4
|
||||
// CODEGEN: ret
|
||||
@ -124,7 +124,7 @@ struct I : D {
|
||||
|
||||
I::I() {} // Emits vftable and forces thunk generation.
|
||||
|
||||
// CODEGEN-LABEL: define weak x86_thiscallcc %struct.{{[BF]}}* @"\01?goo@I@@QAEPAUB@@XZ"
|
||||
// CODEGEN-LABEL: define weak_odr x86_thiscallcc %struct.{{[BF]}}* @"\01?goo@I@@QAEPAUB@@XZ"
|
||||
// CODEGEN: %[[ORIG_RET:.*]] = call x86_thiscallcc %struct.F* @"\01?goo@I@@UAEPAUF@@XZ"
|
||||
// CODEGEN: %[[ORIG_RET_i8:.*]] = bitcast %struct.F* %[[ORIG_RET]] to i8*
|
||||
// CODEGEN: %[[VBPTR_i8:.*]] = getelementptr inbounds i8* %[[ORIG_RET_i8]], i32 4
|
||||
@ -152,3 +152,14 @@ struct C : A, B {
|
||||
};
|
||||
C c;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct E : D {
|
||||
E();
|
||||
virtual C* goo();
|
||||
};
|
||||
E::E() {}
|
||||
E e;
|
||||
// Class with internal linkage has internal linkage thunks.
|
||||
// CODEGEN: define internal x86_thiscallcc %struct.C* @"\01?goo@E@?A@@QAEPAUB@@XZ"
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ struct D : virtual C {
|
||||
|
||||
D::D() {} // Forces vftable emission.
|
||||
|
||||
// CHECK-LABEL: define weak x86_thiscallcc void @"\01?f@D@@$4PPPPPPPM@A@AEXXZ"
|
||||
// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01?f@D@@$4PPPPPPPM@A@AEXXZ"
|
||||
// CHECK: %[[ECX:.*]] = load %struct.D** %{{.*}}
|
||||
// CHECK: %[[ECX_i8:.*]] = bitcast %struct.D* %[[ECX]] to i8*
|
||||
// CHECK: %[[VTORDISP_PTR_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 -4
|
||||
@ -34,7 +34,7 @@ D::D() {} // Forces vftable emission.
|
||||
// CHECK: call x86_thiscallcc void @"\01?f@D@@UAEXXZ"(i8* %[[ADJUSTED_i8]])
|
||||
// CHECK: ret void
|
||||
|
||||
// CHECK-LABEL: define weak x86_thiscallcc void @"\01?f@D@@$4PPPPPPPI@3AEXXZ"
|
||||
// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01?f@D@@$4PPPPPPPI@3AEXXZ"
|
||||
// CHECK: %[[ECX:.*]] = load %struct.D** %{{.*}}
|
||||
// CHECK: %[[ECX_i8:.*]] = bitcast %struct.D* %[[ECX]] to i8*
|
||||
// CHECK: %[[VTORDISP_PTR_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 -8
|
||||
@ -63,7 +63,7 @@ struct G : virtual F, virtual E {
|
||||
|
||||
G::G() {} // Forces vftable emission.
|
||||
|
||||
// CHECK-LABEL: define weak x86_thiscallcc void @"\01?f@E@@$R4BA@M@PPPPPPPM@7AEXXZ"(i8*)
|
||||
// CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"\01?f@E@@$R4BA@M@PPPPPPPM@7AEXXZ"(i8*)
|
||||
// CHECK: %[[ECX:.*]] = load %struct.E** %{{.*}}
|
||||
// CHECK: %[[ECX_i8:.*]] = bitcast %struct.E* %[[ECX]] to i8*
|
||||
// CHECK: %[[VTORDISP_PTR_i8:.*]] = getelementptr i8* %[[ECX_i8]], i32 -4
|
||||
|
@ -145,7 +145,7 @@ struct X: virtual C {
|
||||
// MANGLING-DAG: @"\01??_7X@Test4@@6B@"
|
||||
|
||||
// Also check the mangling of the thunk.
|
||||
// MANGLING-DAG: define weak x86_thiscallcc void @"\01?f@C@@WPPPPPPPI@AEXXZ"
|
||||
// MANGLING-DAG: define linkonce_odr x86_thiscallcc void @"\01?f@C@@WPPPPPPPI@AEXXZ"
|
||||
};
|
||||
|
||||
X::X() {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user