From 3b2e16b3d25f6b311dba2871e2a566c96238c3d2 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Sat, 8 Aug 2009 21:45:14 +0000 Subject: [PATCH] Refactor some code and implement support for global destructors for static variables. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78507 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGCXX.cpp | 82 ++++++++++++++++++++++++++++----- lib/CodeGen/CGDecl.cpp | 2 +- lib/CodeGen/CodeGenFunction.h | 15 ++++-- lib/Sema/SemaDecl.cpp | 2 +- test/CodeGenCXX/static-init.cpp | 13 ++++++ 5 files changed, 97 insertions(+), 17 deletions(-) create mode 100644 test/CodeGenCXX/static-init.cpp diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index a1ea6bf76a..bed6785ef1 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -26,8 +26,74 @@ using namespace clang; using namespace CodeGen; void -CodeGenFunction::GenerateStaticCXXBlockVarDeclInit(const VarDecl &D, - llvm::GlobalVariable *GV) { +CodeGenFunction::EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor, + llvm::Constant *DeclPtr) { + // FIXME: This is ABI dependent and we use the Itanium ABI. + + const llvm::Type *Int8PtrTy = + llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + + std::vector Params; + Params.push_back(Int8PtrTy); + + // Get the destructor function type + const llvm::Type *DtorFnTy = + llvm::FunctionType::get(llvm::Type::VoidTy, Params, false); + DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy); + + Params.clear(); + Params.push_back(DtorFnTy); + Params.push_back(Int8PtrTy); + Params.push_back(Int8PtrTy); + + // Get the __cxa_atexit function type + // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d ); + const llvm::FunctionType *AtExitFnTy = + llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false); + + llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy, + "__cxa_atexit"); + + llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy, + "__dso_handle"); + + llvm::Constant *DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); + + llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy), + llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy), + llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) }; + Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args)); +} + +void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, + llvm::Constant *DeclPtr) { + assert(D.hasGlobalStorage() && + "VarDecl must have global storage!"); + + const Expr *Init = D.getInit(); + QualType T = D.getType(); + + if (T->isReferenceType()) { + ErrorUnsupported(Init, "Global variable that binds to a reference"); + } else if (!hasAggregateLLVMType(T)) { + llvm::Value *V = EmitScalarExpr(Init); + EmitStoreOfScalar(V, DeclPtr, T.isVolatileQualified(), T); + } else if (T->isAnyComplexType()) { + EmitComplexExprIntoAddr(Init, DeclPtr, T.isVolatileQualified()); + } else { + EmitAggExpr(Init, DeclPtr, T.isVolatileQualified()); + + if (const RecordType *RT = T->getAs()) { + CXXRecordDecl *RD = cast(RT->getDecl()); + if (!RD->hasTrivialDestructor()) + EmitCXXGlobalDtorRegistration(RD->getDestructor(getContext()), DeclPtr); + } + } +} + +void +CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, + llvm::GlobalVariable *GV) { // FIXME: This should use __cxa_guard_{acquire,release}? assert(!getContext().getLangOptions().ThreadsafeStatics && @@ -61,16 +127,8 @@ CodeGenFunction::GenerateStaticCXXBlockVarDeclInit(const VarDecl &D, EmitBlock(InitBlock); - const Expr *Init = D.getInit(); - if (!hasAggregateLLVMType(Init->getType())) { - llvm::Value *V = EmitScalarExpr(Init); - Builder.CreateStore(V, GV, D.getType().isVolatileQualified()); - } else if (Init->getType()->isAnyComplexType()) { - EmitComplexExprIntoAddr(Init, GV, D.getType().isVolatileQualified()); - } else { - EmitAggExpr(Init, GV, D.getType().isVolatileQualified()); - } - + EmitCXXGlobalVarDeclInit(D, GV); + Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::Int8Ty, 1), Builder.CreateBitCast(GuardV, PtrTy)); diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 477cf52aad..d3b7db089b 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -140,7 +140,7 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) { if (!getContext().getLangOptions().CPlusPlus) CGM.ErrorUnsupported(D.getInit(), "constant l-value expression"); else - GenerateStaticCXXBlockVarDeclInit(D, GV); + EmitStaticCXXBlockVarDeclInit(D, GV); } else { // The initializer may differ in type from the global. Rewrite // the global to match the initializer. (We have to do this diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 6e4d9ec891..da88b53352 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -887,11 +887,20 @@ public: llvm::GlobalValue::LinkageTypes Linkage); - /// GenerateStaticCXXBlockVarDecl - Create the initializer for a C++ + /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++ /// runtime initialized static block var decl. - void GenerateStaticCXXBlockVarDeclInit(const VarDecl &D, - llvm::GlobalVariable *GV); + void EmitStaticCXXBlockVarDeclInit(const VarDecl &D, + llvm::GlobalVariable *GV); + /// EmitCXXGlobalVarDeclInit - Create the initializer for a C++ + /// variable with global storage. + void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr); + + /// EmitCXXGlobalDtorRegistration - Emits a call to register the global ptr + /// with the C++ runtime so that its destructor will be called at exit. + void EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor, + llvm::Constant *DeclPtr); + void EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E); RValue EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 44e8b44d7a..aac79e9fc7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3227,7 +3227,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, if (!Constructor) Var->setInvalidDecl(); else { - if (!RD->hasTrivialConstructor()) + if (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor()) InitializeVarWithConstructor(Var, Constructor, InitType, 0, 0); FinalizeVarWithDestructor(Var, InitType); } diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp new file mode 100644 index 0000000000..2d0b4b0c77 --- /dev/null +++ b/test/CodeGenCXX/static-init.cpp @@ -0,0 +1,13 @@ +// RUN: clang-cc -triple=x86_64-apple-darwin9 -emit-llvm %s -o %t && +// RUN: grep "call void @_ZN1AC1Ev" %t | count 1 && +// RUN: grep "call i32 @__cxa_atexit(void (i8\*)\* bitcast (void (%.truct.A\*)\* @_ZN1AD1Ev to void (i8\*)\*), i8\* getelementptr (%.truct.A\* @_ZZ1fvE1a, i32 0, i32 0), i8\* bitcast (i8\*\* @__dso_handle to i8\*))" %t | count 1 + +struct A { + A(); + ~A(); +}; + +void f() { + static A a; +} + -- 2.40.0