When building with optimizations, emit thunks with available_externally linkage so devirtualized function calls can also be de-thunked.
llvm-svn: 124984
This commit is contained in:
parent
fe8a9939f9
commit
8b02183ff3
|
@ -2679,7 +2679,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD,
|
|||
setThunkVisibility(CGM, MD, Thunk, Fn);
|
||||
}
|
||||
|
||||
void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk)
|
||||
void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
|
||||
bool UseAvailableExternallyLinkage)
|
||||
{
|
||||
llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk);
|
||||
|
||||
|
@ -2714,9 +2715,37 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk)
|
|||
OldThunkFn->eraseFromParent();
|
||||
}
|
||||
|
||||
// Actually generate the thunk body.
|
||||
llvm::Function *ThunkFn = cast<llvm::Function>(Entry);
|
||||
|
||||
if (!ThunkFn->isDeclaration()) {
|
||||
if (UseAvailableExternallyLinkage) {
|
||||
// There is already a thunk emitted for this function, do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
// We should never be able to get a function with a definition here.
|
||||
assert(false && "Shouldn't have an already existing definition");
|
||||
}
|
||||
|
||||
// Actually generate the thunk body.
|
||||
CodeGenFunction(CGM).GenerateThunk(ThunkFn, GD, Thunk);
|
||||
|
||||
if (UseAvailableExternallyLinkage)
|
||||
ThunkFn->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
|
||||
}
|
||||
|
||||
void CodeGenVTables::MaybeEmitThunkAvailableExternally(GlobalDecl GD,
|
||||
const ThunkInfo &Thunk) {
|
||||
// We only want to do this when building with optimizations.
|
||||
if (!CGM.getCodeGenOpts().OptimizationLevel)
|
||||
return;
|
||||
|
||||
// We can't emit thunks for member functions with incomplete types.
|
||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
|
||||
if (CGM.getTypes().VerifyFuncTypeComplete(MD->getType().getTypePtr()))
|
||||
return;
|
||||
|
||||
EmitThunk(GD, Thunk, /*UseAvailableExternallyLinkage=*/true);
|
||||
}
|
||||
|
||||
void CodeGenVTables::EmitThunks(GlobalDecl GD)
|
||||
|
@ -2741,7 +2770,7 @@ void CodeGenVTables::EmitThunks(GlobalDecl GD)
|
|||
|
||||
const ThunkInfoVectorTy &ThunkInfoVector = I->second;
|
||||
for (unsigned I = 0, E = ThunkInfoVector.size(); I != E; ++I)
|
||||
EmitThunk(GD, ThunkInfoVector[I]);
|
||||
EmitThunk(GD, ThunkInfoVector[I], /*UseAvailableExternallyLinkage=*/false);
|
||||
}
|
||||
|
||||
void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD,
|
||||
|
@ -2913,7 +2942,8 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
|
|||
const ThunkInfo &Thunk = VTableThunks[NextVTableThunkIndex].second;
|
||||
|
||||
Init = CGM.GetAddrOfThunk(GD, Thunk);
|
||||
|
||||
MaybeEmitThunkAvailableExternally(GD, Thunk);
|
||||
|
||||
NextVTableThunkIndex++;
|
||||
} else {
|
||||
const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(GD);
|
||||
|
|
|
@ -183,8 +183,15 @@ class CodeGenVTables {
|
|||
void ComputeMethodVTableIndices(const CXXRecordDecl *RD);
|
||||
|
||||
/// EmitThunk - Emit a single thunk.
|
||||
void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk);
|
||||
|
||||
void EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk,
|
||||
bool UseAvailableExternallyLinkage);
|
||||
|
||||
/// MaybeEmitThunkAvailableExternally - Try to emit the given thunk with
|
||||
/// available_externally linkage to allow for inlining of thunks.
|
||||
/// This will be done iff optimizations are enabled and the member function
|
||||
/// doesn't contain any incomplete types.
|
||||
void MaybeEmitThunkAvailableExternally(GlobalDecl GD, const ThunkInfo &Thunk);
|
||||
|
||||
/// ComputeVTableRelatedInformation - Compute and store all vtable related
|
||||
/// information (vtable layout, vbase offset offsets, thunks etc) for the
|
||||
/// given record decl.
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o - | FileCheck %s
|
||||
|
||||
// Check that we don't assert on this case.
|
||||
namespace Test1 {
|
||||
|
||||
struct Incomplete;
|
||||
|
||||
struct A {
|
||||
virtual void f();
|
||||
virtual void g(Incomplete);
|
||||
virtual void h();
|
||||
virtual void i();
|
||||
int a;
|
||||
};
|
||||
|
||||
struct B {
|
||||
virtual void f();
|
||||
virtual void g(Incomplete);
|
||||
virtual void h();
|
||||
virtual void i();
|
||||
int b;
|
||||
};
|
||||
|
||||
struct C : A, B {
|
||||
C();
|
||||
|
||||
virtual void f();
|
||||
virtual void g(Incomplete);
|
||||
virtual void h();
|
||||
virtual void i();
|
||||
};
|
||||
|
||||
void C::h() { }
|
||||
|
||||
C::C() { }
|
||||
|
||||
void C::i() { }
|
||||
|
||||
}
|
||||
|
||||
namespace Test2 {
|
||||
|
||||
struct A {
|
||||
virtual void f();
|
||||
int a;
|
||||
};
|
||||
|
||||
struct B {
|
||||
virtual void f();
|
||||
int b;
|
||||
};
|
||||
|
||||
struct C : A, B {
|
||||
virtual void f();
|
||||
};
|
||||
|
||||
static void f(B* b) {
|
||||
b->f();
|
||||
}
|
||||
|
||||
// CHECK: define void @_ZN5Test21fEv()
|
||||
// CHECK: call void @_ZN5Test21C1fEv
|
||||
// CHECK: ret void
|
||||
// CHECK: define available_externally void @_ZThn16_N5Test21C1fEv
|
||||
void f() {
|
||||
C c;
|
||||
f(&c);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue