summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGCXX.cpp
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-02-17 03:52:49 +0000
committerJohn McCall <rjmccall@apple.com>2010-02-17 03:52:49 +0000
commit67cea74745f6b7767fc6681eac58d152c383b6c2 (patch)
treeac79fda2c0cec629f1f990c9b3d4c067666619e5 /clang/lib/CodeGen/CGCXX.cpp
parent5734217c8493dd4f034482a0df2ad48826408032 (diff)
downloadbcm5719-llvm-67cea74745f6b7767fc6681eac58d152c383b6c2.tar.gz
bcm5719-llvm-67cea74745f6b7767fc6681eac58d152c383b6c2.zip
Emit complete constructors and destructors as aliases to base constructors
and destructors when the two entities are semantically identical, i.e. when the class has no virtual base classes. We only do this for linkage types for which aliases are supported, i.e. internal and external, i.e. not linkonce. llvm-svn: 96451
Diffstat (limited to 'clang/lib/CodeGen/CGCXX.cpp')
-rw-r--r--clang/lib/CodeGen/CGCXX.cpp113
1 files changed, 103 insertions, 10 deletions
diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp
index c4c52aac034..f0d01969a9c 100644
--- a/clang/lib/CodeGen/CGCXX.cpp
+++ b/clang/lib/CodeGen/CGCXX.cpp
@@ -26,17 +26,88 @@
using namespace clang;
using namespace CodeGen;
+/// Try to emit a definition as a global alias for another definition.
+bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
+ GlobalDecl TargetDecl) {
+ // Find the referrent.
+ llvm::GlobalValue *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));
+
+ // Look for an existing entry.
+ const char *MangledName = getMangledName(AliasDecl);
+ llvm::GlobalValue *&Entry = GlobalDeclMap[MangledName];
+ if (Entry) {
+ assert(Entry->isDeclaration() && "definition already exists for alias");
+ assert(Entry->getType() == Ref->getType() &&
+ "declaration exists with different type");
+ }
+
+ // The alias will use the linkage of the referrent. If we can't
+ // support aliases with that linkage, fail.
+ llvm::GlobalValue::LinkageTypes Linkage
+ = getFunctionLinkage(cast<FunctionDecl>(AliasDecl.getDecl()));
+
+ switch (Linkage) {
+ // We can definitely emit aliases to definitions with external linkage.
+ case llvm::GlobalValue::ExternalLinkage:
+ case llvm::GlobalValue::ExternalWeakLinkage:
+ break;
+
+ // Same with local linkage.
+ case llvm::GlobalValue::InternalLinkage:
+ case llvm::GlobalValue::PrivateLinkage:
+ case llvm::GlobalValue::LinkerPrivateLinkage:
+ break;
+
+ // We should try to support linkonce linkages.
+ case llvm::GlobalValue::LinkOnceAnyLinkage:
+ case llvm::GlobalValue::LinkOnceODRLinkage:
+ return true;
+
+ // Other linkages will probably never be supported.
+ default:
+ return true;
+ }
+
+ // Create the alias with no name.
+ llvm::GlobalAlias *Alias =
+ new llvm::GlobalAlias(Ref->getType(), Linkage, "", Ref, &getModule());
+
+ // Switch any previous uses to the alias and continue.
+ if (Entry) {
+ Entry->replaceAllUsesWith(Alias);
+ Entry->eraseFromParent();
+ }
+ Entry = Alias;
+
+ // Finally, set up the alias with its proper name and attributes.
+ Alias->setName(MangledName);
+ SetCommonAttributes(AliasDecl.getDecl(), Alias);
+
+ return false;
+}
void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
- EmitGlobal(GlobalDecl(D, Ctor_Complete));
+ // The constructor used for constructing this as a base class;
+ // ignores virtual bases.
EmitGlobal(GlobalDecl(D, Ctor_Base));
+
+ // The constructor used for constructing this as a complete class;
+ // constucts the virtual bases, then calls the base constructor.
+ EmitGlobal(GlobalDecl(D, Ctor_Complete));
}
void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D,
CXXCtorType Type) {
+ // The complete constructor is equivalent to the base constructor
+ // for classes with no virtual bases. Try to emit it as an alias.
+ if (Type == Ctor_Complete &&
+ !D->getParent()->getNumVBases() &&
+ !TryEmitDefinitionAsAlias(GlobalDecl(D, Ctor_Complete),
+ GlobalDecl(D, Ctor_Base)))
+ return;
- llvm::Function *Fn = GetAddrOfCXXConstructor(D, Type);
+ llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXConstructor(D, Type));
CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn);
@@ -44,15 +115,17 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D,
SetLLVMFunctionAttributesForDefinition(D, Fn);
}
-llvm::Function *
+llvm::GlobalValue *
CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
CXXCtorType Type) {
+ const char *Name = getMangledCXXCtorName(D, Type);
+ if (llvm::GlobalValue *V = GlobalDeclMap[Name])
+ return V;
+
const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>();
const llvm::FunctionType *FTy =
getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type),
FPT->isVariadic());
-
- const char *Name = getMangledCXXCtorName(D, Type);
return cast<llvm::Function>(
GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type)));
}
@@ -67,15 +140,32 @@ const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D,
}
void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
+ // The destructor used for destructing this as a base class; ignores
+ // virtual bases.
+ EmitGlobal(GlobalDecl(D, Dtor_Base));
+
+ // The destructor used for destructing this as a most-derived class;
+ // call the base destructor and then destructs any virtual bases.
+ EmitGlobal(GlobalDecl(D, Dtor_Complete));
+
+ // The destructor in a virtual table is always a 'deleting'
+ // destructor, which calls the complete destructor and then uses the
+ // appropriate operator delete.
if (D->isVirtual())
EmitGlobal(GlobalDecl(D, Dtor_Deleting));
- EmitGlobal(GlobalDecl(D, Dtor_Complete));
- EmitGlobal(GlobalDecl(D, Dtor_Base));
}
void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType Type) {
- llvm::Function *Fn = GetAddrOfCXXDestructor(D, Type);
+ // The complete destructor is equivalent to the base destructor for
+ // classes with no virtual bases, so try to emit it as an alias.
+ if (Type == Dtor_Complete &&
+ !D->getParent()->getNumVBases() &&
+ !TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Complete),
+ GlobalDecl(D, Dtor_Base)))
+ return;
+
+ llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXDestructor(D, Type));
CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn);
@@ -83,13 +173,16 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D,
SetLLVMFunctionAttributesForDefinition(D, Fn);
}
-llvm::Function *
+llvm::GlobalValue *
CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType Type) {
+ const char *Name = getMangledCXXDtorName(D, Type);
+ if (llvm::GlobalValue *V = GlobalDeclMap[Name])
+ return V;
+
const llvm::FunctionType *FTy =
getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type), false);
- const char *Name = getMangledCXXDtorName(D, Type);
return cast<llvm::Function>(
GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type)));
}
OpenPOWER on IntegriCloud