]> granicus.if.org Git - clang/commitdiff
Refactor some code and implement support for global destructors for static variables.
authorAnders Carlsson <andersca@mac.com>
Sat, 8 Aug 2009 21:45:14 +0000 (21:45 +0000)
committerAnders Carlsson <andersca@mac.com>
Sat, 8 Aug 2009 21:45:14 +0000 (21:45 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78507 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCXX.cpp
lib/CodeGen/CGDecl.cpp
lib/CodeGen/CodeGenFunction.h
lib/Sema/SemaDecl.cpp
test/CodeGenCXX/static-init.cpp [new file with mode: 0644]

index a1ea6bf76a475498e00d1676b237db2071efc266..bed6785ef18e760b77f05bd4bafa25d781ae127c 100644 (file)
@@ -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<const llvm::Type *> 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<RecordType>()) {
+      CXXRecordDecl *RD = cast<CXXRecordDecl>(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));
                       
index 477cf52aad94af3ab8b5889b7a63cb0d5a651121..d3b7db089bc67f8aa9aa1208d6d6fef98410c490 100644 (file)
@@ -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
index 6e4d9ec891981d6137fc6abc207970c81166c0c7..da88b53352eeae592554be24c4b4c83c4dc5fcc1 100644 (file)
@@ -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,
index 44e8b44d7a9e5b5b14bbd27ff25874b3d7e020d1..aac79e9fc702e0620c8c1ba805a8b40f4c74f611 100644 (file)
@@ -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 (file)
index 0000000..2d0b4b0
--- /dev/null
@@ -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;
+}
+