[cfe-commits] r155894 - in /cfe/trunk: lib/CodeGen/CGCXXABI.cpp lib/CodeGen/CGCXXABI.h lib/CodeGen/CGDeclCXX.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CodeGenFunction.h lib/CodeGen/ItaniumCXXABI.cpp lib/CodeGen/MicrosoftCXXABI.cpp test/CodeGenCXX/microsoft-abi-static-initializers.cpp

John McCall rjmccall at apple.com
Mon Apr 30 23:13:13 PDT 2012


Author: rjmccall
Date: Tue May  1 01:13:13 2012
New Revision: 155894

URL: http://llvm.org/viewvc/llvm-project?rev=155894&view=rev
Log:
Abstract the emission of global destructors into ABI-specific code
and only consider using __cxa_atexit in the Itanium logic.  The
default logic is to use atexit().

Emit "guarded" initializers in Microsoft mode unconditionally.
This is definitely not correct, but it's closer to correct than
just not emitting the initializer.

Based on a patch by Timur Iskhodzhanov!

Added:
    cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
Modified:
    cfe/trunk/lib/CodeGen/CGCXXABI.cpp
    cfe/trunk/lib/CodeGen/CGCXXABI.h
    cfe/trunk/lib/CodeGen/CGDeclCXX.cpp
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.cpp?rev=155894&r1=155893&r2=155894&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.cpp Tue May  1 01:13:13 2012
@@ -221,6 +221,13 @@
   ErrorUnsupportedABI(CGF, "static local variable initialization");
 }
 
+void CGCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
+                                  llvm::Constant *dtor,
+                                  llvm::Constant *addr) {
+  // The default behavior is to use atexit.
+  CGF.registerGlobalDtorWithAtExit(dtor, addr);
+}
+
 /// Returns the adjustment, in bytes, required for the given
 /// member-pointer operation.  Returns null if no adjustment is
 /// required.

Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=155894&r1=155893&r2=155894&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
+++ cfe/trunk/lib/CodeGen/CGCXXABI.h Tue May  1 01:13:13 2012
@@ -272,6 +272,13 @@
   virtual void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
                                llvm::GlobalVariable *DeclPtr, bool PerformInit);
 
+  /// Emit code to force the execution of a destructor during global
+  /// teardown.  The default implementation of this uses atexit.
+  ///
+  /// \param dtor - a function taking a single pointer argument
+  /// \param addr - a pointer to pass to the destructor function.
+  virtual void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor,
+                                  llvm::Constant *addr);
 };
 
 /// Creates an instance of a C++ ABI class.

Modified: cfe/trunk/lib/CodeGen/CGDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDeclCXX.cpp?rev=155894&r1=155893&r2=155894&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDeclCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDeclCXX.cpp Tue May  1 01:13:13 2012
@@ -98,7 +98,7 @@
     argument = llvm::Constant::getNullValue(CGF.Int8PtrTy);
   }
 
-  CGF.EmitCXXGlobalDtorRegistration(function, argument);
+  CGM.getCXXABI().registerGlobalDtor(CGF, function, argument);
 }
 
 /// Emit code to cause the variable at the given address to be considered as
@@ -145,39 +145,6 @@
   EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, Alignment, T);
 }
 
-/// Register a global destructor using __cxa_atexit.
-static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
-                                        llvm::Constant *dtor,
-                                        llvm::Constant *addr) {
-  // We're assuming that the destructor function is something we can
-  // reasonably call with the default CC.  Go ahead and cast it to the
-  // right prototype.
-  llvm::Type *dtorTy =
-    llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, false)->getPointerTo();
-
-  // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d);
-  llvm::Type *paramTys[] = { dtorTy, CGF.Int8PtrTy, CGF.Int8PtrTy };
-  llvm::FunctionType *atexitTy =
-    llvm::FunctionType::get(CGF.IntTy, paramTys, false);
-
-  // Fetch the actual function.
-  llvm::Constant *atexit =
-    CGF.CGM.CreateRuntimeFunction(atexitTy, "__cxa_atexit");
-  if (llvm::Function *fn = dyn_cast<llvm::Function>(atexit))
-    fn->setDoesNotThrow();
-
-  // Create a variable that binds the atexit to this shared object.
-  llvm::Constant *handle =
-    CGF.CGM.CreateRuntimeVariable(CGF.Int8Ty, "__dso_handle");
-
-  llvm::Value *args[] = {
-    llvm::ConstantExpr::getBitCast(dtor, dtorTy),
-    llvm::ConstantExpr::getBitCast(addr, CGF.Int8PtrTy),
-    handle
-  };
-  CGF.Builder.CreateCall(atexit, args);
-}
-
 static llvm::Function *
 CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
                                    llvm::FunctionType *ty,
@@ -212,43 +179,22 @@
   return fn;
 }
 
-/// Register a global destructor using atexit.
-static void emitGlobalDtorWithAtExit(CodeGenFunction &CGF,
-                                     llvm::Constant *dtor,
-                                     llvm::Constant *addr) {
+/// Register a global destructor using the C atexit runtime function.
+void CodeGenFunction::registerGlobalDtorWithAtExit(llvm::Constant *dtor,
+                                                   llvm::Constant *addr) {
   // Create a function which calls the destructor.
-  llvm::Constant *dtorStub = createAtExitStub(CGF.CGM, dtor, addr);
+  llvm::Constant *dtorStub = createAtExitStub(CGM, dtor, addr);
 
   // extern "C" int atexit(void (*f)(void));
   llvm::FunctionType *atexitTy =
-    llvm::FunctionType::get(CGF.IntTy, dtorStub->getType(), false);
+    llvm::FunctionType::get(IntTy, dtorStub->getType(), false);
 
   llvm::Constant *atexit =
-    CGF.CGM.CreateRuntimeFunction(atexitTy, "atexit");
+    CGM.CreateRuntimeFunction(atexitTy, "atexit");
   if (llvm::Function *atexitFn = dyn_cast<llvm::Function>(atexit))
     atexitFn->setDoesNotThrow();
 
-  CGF.Builder.CreateCall(atexit, dtorStub);
-}
-
-void CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *dtor,
-                                                    llvm::Constant *addr) {
-  // Use __cxa_atexit if available.
-  if (CGM.getCodeGenOpts().CXAAtExit) {
-    emitGlobalDtorWithCXAAtExit(*this, dtor, addr);
-    return;
-  }
-
-  // In Apple kexts, we want to add a global destructor entry.
-  // FIXME: shouldn't this be guarded by some variable?
-  if (CGM.getContext().getLangOpts().AppleKext) {
-    // Generate a global destructor entry.
-    CGM.AddCXXDtorEntry(dtor, addr);
-    return;
-  }
-
-  // Otherwise, we just use atexit.
-  emitGlobalDtorWithAtExit(*this, dtor, addr);
+  Builder.CreateCall(atexit, dtorStub)->setDoesNotThrow();
 }
 
 void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=155894&r1=155893&r2=155894&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Tue May  1 01:13:13 2012
@@ -462,7 +462,7 @@
     if (ReferenceTemporaryDtor) {
       llvm::Constant *DtorFn = 
         CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
-      EmitCXXGlobalDtorRegistration(DtorFn, 
+      CGM.getCXXABI().registerGlobalDtor(*this, DtorFn, 
                                     cast<llvm::Constant>(ReferenceTemporary));
     } else {
       assert(!ObjCARCReferenceLifetimeType.isNull());

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=155894&r1=155893&r2=155894&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue May  1 01:13:13 2012
@@ -2411,10 +2411,9 @@
   void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr,
                                 bool PerformInit);
 
-  /// EmitCXXGlobalDtorRegistration - Emits a call to register the global ptr
-  /// with the C++ runtime so that its destructor will be called at exit.
-  void EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
-                                     llvm::Constant *DeclPtr);
+  /// Call atexit() with a function that passes the given argument to
+  /// the given function.
+  void registerGlobalDtorWithAtExit(llvm::Constant *fn, llvm::Constant *addr);
 
   /// Emit code in this function to perform a guarded variable
   /// initialization.  Guarded initializations are used when it's not

Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=155894&r1=155893&r2=155894&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue May  1 01:13:13 2012
@@ -119,6 +119,8 @@
 
   void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
                        llvm::GlobalVariable *DeclPtr, bool PerformInit);
+  void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor,
+                          llvm::Constant *addr);
 };
 
 class ARMCXXABI : public ItaniumCXXABI {
@@ -1097,3 +1099,55 @@
 
   CGF.EmitBlock(EndBlock);
 }
+
+/// Register a global destructor using __cxa_atexit.
+static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
+                                        llvm::Constant *dtor,
+                                        llvm::Constant *addr) {
+  // We're assuming that the destructor function is something we can
+  // reasonably call with the default CC.  Go ahead and cast it to the
+  // right prototype.
+  llvm::Type *dtorTy =
+    llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, false)->getPointerTo();
+
+  // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d);
+  llvm::Type *paramTys[] = { dtorTy, CGF.Int8PtrTy, CGF.Int8PtrTy };
+  llvm::FunctionType *atexitTy =
+    llvm::FunctionType::get(CGF.IntTy, paramTys, false);
+
+  // Fetch the actual function.
+  llvm::Constant *atexit =
+    CGF.CGM.CreateRuntimeFunction(atexitTy, "__cxa_atexit");
+  if (llvm::Function *fn = dyn_cast<llvm::Function>(atexit))
+    fn->setDoesNotThrow();
+
+  // Create a variable that binds the atexit to this shared object.
+  llvm::Constant *handle =
+    CGF.CGM.CreateRuntimeVariable(CGF.Int8Ty, "__dso_handle");
+
+  llvm::Value *args[] = {
+    llvm::ConstantExpr::getBitCast(dtor, dtorTy),
+    llvm::ConstantExpr::getBitCast(addr, CGF.Int8PtrTy),
+    handle
+  };
+  CGF.Builder.CreateCall(atexit, args)->setDoesNotThrow();
+}
+
+/// Register a global destructor as best as we know how.
+void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
+                                       llvm::Constant *dtor,
+                                       llvm::Constant *addr) {
+  // Use __cxa_atexit if available.
+  if (CGM.getCodeGenOpts().CXAAtExit) {
+    return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr);
+  }
+
+  // In Apple kexts, we want to add a global destructor entry.
+  // FIXME: shouldn't this be guarded by some variable?
+  if (CGM.getContext().getLangOpts().AppleKext) {
+    // Generate a global destructor entry.
+    return CGM.AddCXXDtorEntry(dtor, addr);
+  }
+
+  CGF.registerGlobalDtorWithAtExit(dtor, addr);
+}

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=155894&r1=155893&r2=155894&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Tue May  1 01:13:13 2012
@@ -56,6 +56,11 @@
     // TODO: 'for base' flag
   }
 
+  void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
+                       llvm::GlobalVariable *DeclPtr,
+                       bool PerformInit);
+
+
   // ==== Notes on array cookies =========
   //
   // MSVC seems to only use cookies when the class has a destructor; a
@@ -149,6 +154,17 @@
                                                 cookieSize.getQuantity());
 }
 
+void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
+                                      llvm::GlobalVariable *DeclPtr,
+                                      bool PerformInit) {
+  // FIXME: this code was only tested for global initialization.
+  // Not sure whether we want thread-safe static local variables as VS
+  // doesn't make them thread-safe.
+
+  // Emit the initializer and add a global destructor if appropriate.
+  CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit);
+}
+
 CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
   return new MicrosoftCXXABI(CGM);
 }

Added: cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp?rev=155894&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-static-initializers.cpp Tue May  1 01:13:13 2012
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+struct S {
+  S() {}
+  ~S() {}
+} s;
+
+// CHECK: define internal void [[INIT_s:@.*global_var.*]] nounwind
+// CHECK: call void @"\01??0S@@QAE at XZ"
+// CHECK: call i32 @atexit(void ()* @"__dtor_\01?s@@3US@@A")
+// CHECK: ret void
+
+// CHECK: define internal void @"__dtor_\01?s@@3US@@A"() nounwind {
+// CHECK: call void @"\01??1S@@QAE at XZ"
+// CHECK: ret void
+
+// Force WeakODRLinkage by using templates
+class A {
+ public:
+  A() {}
+  ~A() {}
+};
+
+template<typename T>
+class B {
+ public:
+  static A foo;
+};
+
+template<typename T> A B<T>::foo;
+
+void force_usage() {
+  (void)B<int>::foo;  // (void) - force usage
+}
+
+// CHECK: define internal void [[INIT_foo:@.*global_var.*]] nounwind
+// CHECK: call void @"\01??0A@@QAE at XZ"
+// CHECK: call i32 @atexit(void ()* [[FOO_DTOR:@"__dtor_.*foo at .*]])
+// CHECK: ret void
+
+// CHECK: define linkonce_odr void @"\01??0A@@QAE at XZ"
+
+// CHECK: define linkonce_odr void @"\01??1A@@QAE at XZ"
+
+// CHECK: define internal void [[FOO_DTOR]]
+// CHECK: call void @"\01??1A@@QAE at XZ"{{.*}}foo
+// CHECK: ret void
+
+// CHECK: define internal void @_GLOBAL__I_a() nounwind {
+// CHECK: call void [[INIT_s]]
+// CHECK: call void [[INIT_foo]]
+// CHECK: ret void





More information about the cfe-commits mailing list