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:
Anders Carlsson 2011-02-06 18:31:40 +00:00
parent fe8a9939f9
commit 8b02183ff3
3 changed files with 113 additions and 6 deletions

View File

@ -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);

View File

@ -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.

View File

@ -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);
}
}