diff --git a/clang/include/clang/CodeGen/CodeGenOptions.h b/clang/include/clang/CodeGen/CodeGenOptions.h index e1d4ad1b1cce..e0e0f779bf5a 100644 --- a/clang/include/clang/CodeGen/CodeGenOptions.h +++ b/clang/include/clang/CodeGen/CodeGenOptions.h @@ -53,6 +53,8 @@ public: unsigned UnwindTables : 1; /// Emit unwind tables. unsigned VerifyModule : 1; /// Control whether the module should be run /// through the LLVM Verifier. + unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker + /// aliases to base ctors when possible. /// The code model to use (-mcmodel). std::string CodeModel; @@ -101,6 +103,7 @@ public: UnrollLoops = 0; UnwindTables = 0; VerifyModule = 1; + CXXCtorDtorAliases = 0; Inlining = NoInlining; RelocationModel = "pic"; diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td index 047363ea597b..7cd26ef04cc2 100644 --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -143,6 +143,8 @@ def mrelocation_model : Separate<"-mrelocation-model">, HelpText<"The relocation model to use">; def munwind_tables : Flag<"-munwind-tables">, HelpText<"Generate unwinding tables for all functions">; +def mconstructor_aliases : Flag<"-mconstructor-aliases">, + HelpText<"Emit complete constructors and destructors as aliases when possible">; def O : Joined<"-O">, HelpText<"Optimization level">; def Os : Flag<"-Os">, HelpText<"Optimize for size">; diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index c4c52aac034a..e84b68104bd0 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -22,21 +22,96 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/StmtCXX.h" +#include "clang/CodeGen/CodeGenOptions.h" #include "llvm/ADT/StringExtras.h" 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) { + if (!getCodeGenOpts().CXXCtorDtorAliases) + return true; + + // Find the referrent. + llvm::GlobalValue *Ref = cast(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(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) { + // The constructor used for constructing this as a complete class; + // constucts the virtual bases, then calls the base constructor. EmitGlobal(GlobalDecl(D, Ctor_Complete)); + + // The constructor used for constructing this as a base class; + // ignores virtual bases. EmitGlobal(GlobalDecl(D, Ctor_Base)); } 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(GetAddrOfCXXConstructor(D, Type)); CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn); @@ -44,15 +119,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(); const llvm::FunctionType *FTy = getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type), FPT->isVariadic()); - - const char *Name = getMangledCXXCtorName(D, Type); return cast( GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type))); } @@ -67,15 +144,32 @@ const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D, } void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { + // 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)); + + // 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 used for destructing this as a base class; ignores + // virtual bases. 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(GetAddrOfCXXDestructor(D, Type)); CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn); @@ -83,13 +177,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( GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(D, Type))); } diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 5a552c490ac6..41575e41e53c 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -316,24 +316,20 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, return CodeGenModule::GVA_CXXInline; } -/// SetFunctionDefinitionAttributes - Set attributes for a global. -/// -/// FIXME: This is currently only done for aliases and functions, but not for -/// variables (these details are set in EmitGlobalVarDefinition for variables). -void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D, - llvm::GlobalValue *GV) { +llvm::GlobalValue::LinkageTypes +CodeGenModule::getFunctionLinkage(const FunctionDecl *D) { GVALinkage Linkage = GetLinkageForFunction(getContext(), D, Features); if (Linkage == GVA_Internal) { - GV->setLinkage(llvm::Function::InternalLinkage); + return llvm::Function::InternalLinkage; } else if (D->hasAttr()) { - GV->setLinkage(llvm::Function::DLLExportLinkage); + return llvm::Function::DLLExportLinkage; } else if (D->hasAttr()) { - GV->setLinkage(llvm::Function::WeakAnyLinkage); + return llvm::Function::WeakAnyLinkage; } else if (Linkage == GVA_C99Inline) { // In C99 mode, 'inline' functions are guaranteed to have a strong // definition somewhere else, so we can use available_externally linkage. - GV->setLinkage(llvm::Function::AvailableExternallyLinkage); + return llvm::Function::AvailableExternallyLinkage; } else if (Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) { // In C++, the compiler has to emit a definition in every translation unit // that references the function. We should use linkonce_odr because @@ -341,13 +337,22 @@ void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D, // don't need to codegen it. b) if the function persists, it needs to be // merged with other definitions. c) C++ has the ODR, so we know the // definition is dependable. - GV->setLinkage(llvm::Function::LinkOnceODRLinkage); + return llvm::Function::LinkOnceODRLinkage; } else { assert(Linkage == GVA_StrongExternal); // Otherwise, we have strong external linkage. - GV->setLinkage(llvm::Function::ExternalLinkage); + return llvm::Function::ExternalLinkage; } +} + +/// SetFunctionDefinitionAttributes - Set attributes for a global. +/// +/// FIXME: This is currently only done for aliases and functions, but not for +/// variables (these details are set in EmitGlobalVarDefinition for variables). +void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D, + llvm::GlobalValue *GV) { + GV->setLinkage(getFunctionLinkage(D)); SetCommonAttributes(D, GV); } diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 8280766c7035..a5e1d9f12b33 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -206,6 +206,19 @@ public: /// GlobalValue. void setGlobalVisibility(llvm::GlobalValue *GV, const Decl *D) const; + llvm::Constant *GetAddrOfGlobal(GlobalDecl GD) { + if (isa(GD.getDecl())) + return GetAddrOfCXXConstructor(cast(GD.getDecl()), + GD.getCtorType()); + else if (isa(GD.getDecl())) + return GetAddrOfCXXDestructor(cast(GD.getDecl()), + GD.getDtorType()); + else if (isa(GD.getDecl())) + return GetAddrOfFunction(GD); + else + return GetAddrOfGlobalVar(cast(GD.getDecl())); + } + /// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the /// given global variable. If Ty is non-null and if the global doesn't exist, /// then it will be greated with the specified type instead of whatever the @@ -291,13 +304,13 @@ public: /// GetAddrOfCXXConstructor - Return the address of the constructor of the /// given type. - llvm::Function *GetAddrOfCXXConstructor(const CXXConstructorDecl *D, - CXXCtorType Type); + llvm::GlobalValue *GetAddrOfCXXConstructor(const CXXConstructorDecl *D, + CXXCtorType Type); /// GetAddrOfCXXDestructor - Return the address of the constructor of the /// given type. - llvm::Function *GetAddrOfCXXDestructor(const CXXDestructorDecl *D, - CXXDtorType Type); + llvm::GlobalValue *GetAddrOfCXXDestructor(const CXXDestructorDecl *D, + CXXDtorType Type); /// getBuiltinLibFunction - Given a builtin id for a function like /// "__builtin_fabsf", return a Function* for "fabsf". @@ -417,6 +430,9 @@ public: GVA_TemplateInstantiation }; + llvm::GlobalVariable::LinkageTypes + getFunctionLinkage(const FunctionDecl *FD); + /// getVtableLinkage - Return the appropriate linkage for the vtable, VTT, /// and type information of the given class. static llvm::GlobalVariable::LinkageTypes @@ -468,6 +484,8 @@ private: // C++ related functions. + bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target); + void EmitNamespace(const NamespaceDecl *D); void EmitLinkageSpec(const LinkageSpecDecl *D); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index a193ac870307..64a42bc0ec40 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -180,6 +180,8 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-mrelocation-model"); Res.push_back(Opts.RelocationModel); } + if (Opts.CXXCtorDtorAliases) + Res.push_back("-mconstructor-aliases"); if (!Opts.VerifyModule) Res.push_back("-disable-llvm-verifier"); } @@ -789,6 +791,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.SoftFloat = Args.hasArg(OPT_msoft_float); Opts.UnwindTables = Args.hasArg(OPT_munwind_tables); Opts.RelocationModel = getLastArgValue(Args, OPT_mrelocation_model, "pic"); + Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); Opts.MainFileName = getLastArgValue(Args, OPT_main_file_name); Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); diff --git a/clang/test/CodeGenCXX/virtual-bases.cpp b/clang/test/CodeGenCXX/virtual-bases.cpp index 200f21a5da72..627717576302 100644 --- a/clang/test/CodeGenCXX/virtual-bases.cpp +++ b/clang/test/CodeGenCXX/virtual-bases.cpp @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases | FileCheck %s struct A { A(); }; -// CHECK: define void @_ZN1AC1Ev(%struct.A* %this) +// CHECK: @_ZN1AC1Ev = alias {{.*}} @_ZN1AC2Ev // CHECK: define void @_ZN1AC2Ev(%struct.A* %this) A::A() { } diff --git a/clang/test/CodeGenCXX/virtual-destructor-calls.cpp b/clang/test/CodeGenCXX/virtual-destructor-calls.cpp index 0a10fd138f8d..91fd598d4c92 100644 --- a/clang/test/CodeGenCXX/virtual-destructor-calls.cpp +++ b/clang/test/CodeGenCXX/virtual-destructor-calls.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases | FileCheck %s struct A { virtual ~A(); @@ -8,9 +8,8 @@ struct B : A { virtual ~B(); }; -// Complete dtor: just defers to base dtor because there are no vbases. -// CHECK: define void @_ZN1BD1Ev -// CHECK: call void @_ZN1BD2Ev +// Complete dtor: just an alias because there are no virtual bases. +// CHECK: @_ZN1BD1Ev = alias {{.*}} @_ZN1BD2Ev // Deleting dtor: defers to the complete dtor. // CHECK: define void @_ZN1BD0Ev diff --git a/clang/test/CodeGenCXX/vtable-pointer-initialization.cpp b/clang/test/CodeGenCXX/vtable-pointer-initialization.cpp index 92e011752f3f..ebe531529b81 100644 --- a/clang/test/CodeGenCXX/vtable-pointer-initialization.cpp +++ b/clang/test/CodeGenCXX/vtable-pointer-initialization.cpp @@ -19,14 +19,14 @@ struct A : Base { Field field; }; -// CHECK: define void @_ZN1AC1Ev( +// CHECK: define void @_ZN1AC2Ev( // CHECK: call void @_ZN4BaseC2Ev( // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) // CHECK: call void @_ZN5FieldC1Ev( // CHECK: ret void A::A() { } -// CHECK: define void @_ZN1AD1Ev( +// CHECK: define void @_ZN1AD2Ev( // CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) // CHECK: call void @_ZN5FieldD1Ev( // CHECK: call void @_ZN4BaseD2Ev(