diff options
-rw-r--r-- | lib/CodeGen/CGCXX.cpp | 113 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 29 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.h | 26 | ||||
-rw-r--r-- | test/CodeGenCXX/default-arguments.cpp | 9 | ||||
-rw-r--r-- | test/CodeGenCXX/mangle-subst-std.cpp | 3 | ||||
-rw-r--r-- | test/CodeGenCXX/mangle.cpp | 3 | ||||
-rw-r--r-- | test/CodeGenCXX/member-templates.cpp | 2 | ||||
-rw-r--r-- | test/CodeGenCXX/virtual-bases.cpp | 6 | ||||
-rw-r--r-- | test/CodeGenCXX/virtual-destructor-calls.cpp | 3 | ||||
-rw-r--r-- | test/CodeGenCXX/vtable-pointer-initialization.cpp | 4 |
10 files changed, 155 insertions, 43 deletions
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index c4c52aac03..f0d01969a9 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/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))); } diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 5a552c490a..41575e41e5 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/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<DLLExportAttr>()) { - GV->setLinkage(llvm::Function::DLLExportLinkage); + return llvm::Function::DLLExportLinkage; } else if (D->hasAttr<WeakAttr>()) { - 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/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 8280766c70..a5e1d9f12b 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/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<CXXConstructorDecl>(GD.getDecl())) + return GetAddrOfCXXConstructor(cast<CXXConstructorDecl>(GD.getDecl()), + GD.getCtorType()); + else if (isa<CXXDestructorDecl>(GD.getDecl())) + return GetAddrOfCXXDestructor(cast<CXXDestructorDecl>(GD.getDecl()), + GD.getDtorType()); + else if (isa<FunctionDecl>(GD.getDecl())) + return GetAddrOfFunction(GD); + else + return GetAddrOfGlobalVar(cast<VarDecl>(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/test/CodeGenCXX/default-arguments.cpp b/test/CodeGenCXX/default-arguments.cpp index 282e5d0d50..de53a6958f 100644 --- a/test/CodeGenCXX/default-arguments.cpp +++ b/test/CodeGenCXX/default-arguments.cpp @@ -26,6 +26,8 @@ struct B { B(const A1& = A1(), const A2& = A2()); }; +// CHECK: @_ZN1CC1Ev = alias {{.*}} @_ZN1CC2Ev + // CHECK: define void @_Z2f1v() void f1() { @@ -42,13 +44,6 @@ struct C { C(); }; -// CHECK: define void @_ZN1CC1Ev( -// CHECK: call void @_ZN2A1C1Ev( -// CHECK: call void @_ZN2A2C1Ev( -// CHECK: call void @_ZN1BC1ERK2A1RK2A2( -// CHECK: call void @_ZN2A2D1Ev -// CHECK: call void @_ZN2A1D1Ev - // CHECK: define void @_ZN1CC2Ev( // CHECK: call void @_ZN2A1C1Ev( // CHECK: call void @_ZN2A2C1Ev( diff --git a/test/CodeGenCXX/mangle-subst-std.cpp b/test/CodeGenCXX/mangle-subst-std.cpp index 913c8f101b..aea841557c 100644 --- a/test/CodeGenCXX/mangle-subst-std.cpp +++ b/test/CodeGenCXX/mangle-subst-std.cpp @@ -1,9 +1,10 @@ // RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s +// CHECK: @_ZNSt1AC1Ev = alias {{.*}} @_ZNSt1AC2Ev + namespace std { struct A { A(); }; - // CHECK: define void @_ZNSt1AC1Ev // CHECK: define void @_ZNSt1AC2Ev A::A() { } }; diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp index 07183782e7..320b681ac8 100644 --- a/test/CodeGenCXX/mangle.cpp +++ b/test/CodeGenCXX/mangle.cpp @@ -11,6 +11,8 @@ struct Y { }; //CHECK: @pr5966_i = external global //CHECK: @_ZL8pr5966_i = internal global +// CHECK: @_ZN2S7C1Ev = alias {{.*}} @_ZN2S7C2Ev + // CHECK: define zeroext i1 @_ZplRK1YRA100_P1X bool operator+(const Y&, X* (&xs)[100]) { return false; } @@ -219,7 +221,6 @@ struct S7 { }; // PR5139 -// CHECK: @_ZN2S7C1Ev // CHECK: @_ZN2S7C2Ev // CHECK: @"_ZN2S73$_0C1Ev" S7::S7() {} diff --git a/test/CodeGenCXX/member-templates.cpp b/test/CodeGenCXX/member-templates.cpp index 355ba20e17..5ec3226296 100644 --- a/test/CodeGenCXX/member-templates.cpp +++ b/test/CodeGenCXX/member-templates.cpp @@ -15,7 +15,7 @@ struct B { template<typename T> B::B(T) {} -// CHECK: define void @_ZN1BC1IiEET_(%struct.B* %this, i32) +// CHECK: @_ZN1BC1IiEET_ = alias {{.*}} @_ZN1BC2IiEET_ // CHECK: define void @_ZN1BC2IiEET_(%struct.B* %this, i32) template B::B(int); diff --git a/test/CodeGenCXX/virtual-bases.cpp b/test/CodeGenCXX/virtual-bases.cpp index 200f21a5da..bd29b8d9d3 100644 --- a/test/CodeGenCXX/virtual-bases.cpp +++ b/test/CodeGenCXX/virtual-bases.cpp @@ -4,7 +4,7 @@ struct A { A(); }; -// CHECK: define void @_ZN1AC1Ev(%struct.A* %this) +// CHECK: @_ZN1AC1Ev = alias {{.*}} @_ZN1AC2Ev // CHECK: define void @_ZN1AC2Ev(%struct.A* %this) A::A() { } @@ -12,14 +12,14 @@ struct B : virtual A { B(); }; -// CHECK: define void @_ZN1BC1Ev(%struct.B* %this) // CHECK: define void @_ZN1BC2Ev(%struct.B* %this, i8** %vtt) +// CHECK: define void @_ZN1BC1Ev(%struct.B* %this) B::B() { } struct C : virtual A { C(bool); }; -// CHECK: define void @_ZN1CC1Eb(%struct.B* %this, i1 zeroext) // CHECK: define void @_ZN1CC2Eb(%struct.B* %this, i8** %vtt, i1 zeroext) +// CHECK: define void @_ZN1CC1Eb(%struct.B* %this, i1 zeroext) C::C(bool) { } diff --git a/test/CodeGenCXX/virtual-destructor-calls.cpp b/test/CodeGenCXX/virtual-destructor-calls.cpp index 01ca1442f2..650fd69bbe 100644 --- a/test/CodeGenCXX/virtual-destructor-calls.cpp +++ b/test/CodeGenCXX/virtual-destructor-calls.cpp @@ -9,8 +9,7 @@ struct B : A { }; // Complete dtor. -// CHECK: define void @_ZN1BD1Ev -// CHECK: call void @_ZN1AD2Ev +// CHECK: @_ZN1BD1Ev = alias {{.*}} @_ZN1BD2Ev // Deleting dtor. // CHECK: define void @_ZN1BD0Ev diff --git a/test/CodeGenCXX/vtable-pointer-initialization.cpp b/test/CodeGenCXX/vtable-pointer-initialization.cpp index 92e011752f..ebe531529b 100644 --- a/test/CodeGenCXX/vtable-pointer-initialization.cpp +++ b/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( |