summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGCXX.cpp
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-02-23 00:48:20 +0000
committerJohn McCall <rjmccall@apple.com>2010-02-23 00:48:20 +0000
commitf8ff7b9fd1d087c421d0eb1c9cb3104739f7c33a (patch)
treef229d2b5be17ec853b0f84115c68efa65064aa98 /clang/lib/CodeGen/CGCXX.cpp
parent886915e3bb7fef8666be60f278dbe982db272870 (diff)
downloadbcm5719-llvm-f8ff7b9fd1d087c421d0eb1c9cb3104739f7c33a.tar.gz
bcm5719-llvm-f8ff7b9fd1d087c421d0eb1c9cb3104739f7c33a.zip
Perform two more constructor/destructor code-size optimizations:
1) emit base destructors as aliases to their unique base class destructors under some careful conditions. This is enabled for the same targets that can support complete-to-base aliases, i.e. not darwin. 2) Emit non-variadic complete constructors for classes with no virtual bases as calls to the base constructor. This is enabled on all targets and in theory can trigger in situations that the alias optimization can't (mostly involving virtual bases, mostly not yet supported). These are bundled together because I didn't think it worthwhile to split them, not because they really need to be. llvm-svn: 96842
Diffstat (limited to 'clang/lib/CodeGen/CGCXX.cpp')
-rw-r--r--clang/lib/CodeGen/CGCXX.cpp121
1 files changed, 106 insertions, 15 deletions
diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp
index e84b68104bd..01648ae0747 100644
--- a/clang/lib/CodeGen/CGCXX.cpp
+++ b/clang/lib/CodeGen/CGCXX.cpp
@@ -27,24 +27,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) {
+/// Determines whether the given function has a trivial body that does
+/// not require any specific codegen.
+static bool HasTrivialBody(const FunctionDecl *FD) {
+ Stmt *S = FD->getBody();
+ if (!S)
+ return true;
+ if (isa<CompoundStmt>(S) && cast<CompoundStmt>(S)->body_empty())
+ return true;
+ return false;
+}
+
+/// Try to emit a base destructor as an alias to its primary
+/// base-class destructor.
+bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
if (!getCodeGenOpts().CXXCtorDtorAliases)
return true;
- // Find the referrent.
- llvm::GlobalValue *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));
+ // If the destructor doesn't have a trivial body, we have to emit it
+ // separately.
+ if (!HasTrivialBody(D))
+ return true;
- // 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");
+ const CXXRecordDecl *Class = D->getParent();
+
+ // If we need to manipulate a VTT parameter, give up.
+ if (Class->getNumVBases()) {
+ // Extra Credit: passing extra parameters is perfectly safe
+ // in many calling conventions, so only bail out if the ctor's
+ // calling convention is nonstandard.
+ return true;
}
+ // If any fields have a non-trivial destructor, we have to emit it
+ // separately.
+ for (CXXRecordDecl::field_iterator I = Class->field_begin(),
+ E = Class->field_end(); I != E; ++I)
+ if (const RecordType *RT = (*I)->getType()->getAs<RecordType>())
+ if (!cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor())
+ return true;
+
+ // Try to find a unique base class with a non-trivial destructor.
+ const CXXRecordDecl *UniqueBase = 0;
+ for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
+ E = Class->bases_end(); I != E; ++I) {
+
+ // We're in the base destructor, so skip virtual bases.
+ if (I->isVirtual()) continue;
+
+ // Skip base classes with trivial destructors.
+ const CXXRecordDecl *Base
+ = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ if (Base->hasTrivialDestructor()) continue;
+
+ // If we've already found a base class with a non-trivial
+ // destructor, give up.
+ if (UniqueBase) return true;
+ UniqueBase = Base;
+ }
+
+ // If we didn't find any bases with a non-trivial destructor, then
+ // the base destructor is actually effectively trivial, which can
+ // happen if it was needlessly user-defined or if there are virtual
+ // bases with non-trivial destructors.
+ if (!UniqueBase)
+ return true;
+
+ // If the base is at a non-zero offset, give up.
+ const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(Class);
+ if (ClassLayout.getBaseClassOffset(UniqueBase) != 0)
+ return true;
+
+ const CXXDestructorDecl *BaseD = UniqueBase->getDestructor(getContext());
+ return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base),
+ GlobalDecl(BaseD, Dtor_Base));
+}
+
+/// Try to emit a definition as a global alias for another definition.
+bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
+ GlobalDecl TargetDecl) {
+ if (!getCodeGenOpts().CXXCtorDtorAliases)
+ return true;
+
// The alias will use the linkage of the referrent. If we can't
// support aliases with that linkage, fail.
llvm::GlobalValue::LinkageTypes Linkage
@@ -72,11 +136,32 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
return true;
}
+ // Derive the type for the alias.
+ const llvm::PointerType *AliasType
+ = getTypes().GetFunctionType(AliasDecl)->getPointerTo();
+
+ // 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() == AliasType &&
+ "declaration exists with different type");
+ }
+
+ // Find the referrent. Some aliases might require a bitcast, in
+ // which case the caller is responsible for ensuring the soundness
+ // of these semantics.
+ llvm::GlobalValue *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));
+ llvm::Constant *Aliasee = Ref;
+ if (Ref->getType() != AliasType)
+ Aliasee = llvm::ConstantExpr::getBitCast(Ref, AliasType);
+
// Create the alias with no name.
llvm::GlobalAlias *Alias =
- new llvm::GlobalAlias(Ref->getType(), Linkage, "", Ref, &getModule());
+ new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule());
- // Switch any previous uses to the alias and continue.
+ // Switch any previous uses to the alias and kill the previous decl.
if (Entry) {
Entry->replaceAllUsesWith(Alias);
Entry->eraseFromParent();
@@ -90,7 +175,6 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl,
return false;
}
-
void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
// The constructor used for constructing this as a complete class;
// constucts the virtual bases, then calls the base constructor.
@@ -169,6 +253,13 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D,
GlobalDecl(D, Dtor_Base)))
return;
+ // The base destructor is equivalent to the base destructor of its
+ // base class if there is exactly one non-virtual base class with a
+ // non-trivial destructor, there are no fields with a non-trivial
+ // destructor, and the body of the destructor is trivial.
+ if (Type == Dtor_Base && !TryEmitBaseDestructorAsAlias(D))
+ return;
+
llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXDestructor(D, Type));
CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn);
OpenPOWER on IntegriCloud