From 14e82fd91c6d5041aa840574143521d244f185cd Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Sun, 6 Feb 2011 18:31:40 +0000 Subject: [PATCH] When building with optimizations, emit thunks with available_externally linkage so devirtualized function calls can also be de-thunked. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124984 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGVTables.cpp | 38 ++++++++-- lib/CodeGen/CGVTables.h | 11 ++- .../thunks-available-externally.cpp | 70 +++++++++++++++++++ 3 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 test/CodeGenCXX/thunks-available-externally.cpp diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index e626be2871..3dd7a15fe3 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -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(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(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); diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h index 3aee49372d..7c119fa422 100644 --- a/lib/CodeGen/CGVTables.h +++ b/lib/CodeGen/CGVTables.h @@ -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. diff --git a/test/CodeGenCXX/thunks-available-externally.cpp b/test/CodeGenCXX/thunks-available-externally.cpp new file mode 100644 index 0000000000..697a000187 --- /dev/null +++ b/test/CodeGenCXX/thunks-available-externally.cpp @@ -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); +} + +} -- 2.40.0