[cfe-commits] [PATCH] clang/CodeGen: [PR9593] Rework -fno-use-cxa-atexit not to invoke local dtors unconditionally, but use atexit().

NAKAMURA Takumi geek4civic at gmail.com
Fri Apr 6 07:48:33 PDT 2012


Ping. It is essential to build selfhost clang on cygming.

I wonder, for now, if it were enabled not with --fno-use-cxa-atexit,
but triple=cygming.

...Takumi
-------------- next part --------------
commit 566ce3718dc3932d009a8aa977fc3d794da3925d (HEAD)
Author: NAKAMURA Takumi <geek4civic at gmail.com>
Date:   Wed Mar 28 16:22:33 2012

    [PR9593] Rework -fno-use-cxa-atexit not to invoke local dtors unconditionally, but use atexit().
    
    -fno-use-cxa-atexit is by default on cygming, due to unavailability of __cxa_atexit().

diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp
index dc52b11..6387407 100644
--- a/clang/lib/CodeGen/CGDeclCXX.cpp
+++ b/clang/lib/CodeGen/CGDeclCXX.cpp
@@ -148,9 +148,13 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
 void
 CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
                                                llvm::Constant *DeclPtr) {
-  // Generate a global destructor entry if not using __cxa_atexit.
   if (!CGM.getCodeGenOpts().CXAAtExit) {
-    CGM.AddCXXDtorEntry(DtorFn, DeclPtr);
+    if (CGM.getContext().getLangOpts().AppleKext)
+      // Generate a global destructor entry.
+      CGM.AddCXXDtorEntry(DtorFn, DeclPtr);
+    else
+      // Generate atexit().
+      EmitCXXAtExitGlobalDtor(DtorFn, DeclPtr);
     return;
   }
 
@@ -178,6 +182,26 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
   Builder.CreateCall(AtExitFn, Args);
 }
 
+void
+CodeGenFunction::EmitCXXAtExitGlobalDtor(llvm::Constant *DtorFn,
+                                         llvm::Constant *DeclPtr) {
+  // Generate "call void __dtor_() {DeclPtr->~DtorFn();}".
+  DtorFn = CodeGenFunction(CGM).GenerateCXXGlobalDtorFunc(DtorFn, DeclPtr);
+
+  // extern "C" int atexit(void (*)(void));
+  llvm::FunctionType *AtExitFnTy =
+    llvm::FunctionType::get(ConvertType(getContext().IntTy),
+                            DtorFn->getType(),
+                            false);
+
+  llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy,
+                                                       "atexit");
+  if (llvm::Function *Fn = dyn_cast<llvm::Function>(AtExitFn))
+    Fn->setDoesNotThrow();
+
+  Builder.CreateCall(AtExitFn, DtorFn);
+}
+
 void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
                                          llvm::GlobalVariable *DeclPtr,
                                          bool PerformInit) {
@@ -290,7 +314,7 @@ void CodeGenModule::EmitCXXGlobalDtorFunc() {
   llvm::Function *Fn =
     CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__D_a");
 
-  CodeGenFunction(*this).GenerateCXXGlobalDtorFunc(Fn, CXXGlobalDtors);
+  CodeGenFunction(*this).GenerateCXXGlobalDtorsFunc(Fn, CXXGlobalDtors);
   AddGlobalDtor(Fn);
 }
 
@@ -341,7 +365,7 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
   FinishFunction();
 }
 
-void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
+void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
                   const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> >
                                                 &DtorsAndObjects) {
   StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
@@ -361,6 +385,32 @@ void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
   FinishFunction();
 }
 
+llvm::Function *
+CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Constant *DtorFn,
+                                           llvm::Constant *DeclPtr) {
+  // Get the destructor function type
+  // Internal void __dtor_DeclPtr(void)
+  llvm::FunctionType *FTy =
+    llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()),
+                            false);
+  llvm::Function *Fn =
+    CreateGlobalInitOrDestructFunction(CGM, FTy,
+                                       Twine("__dtor_", DeclPtr->getName()));
+
+  StartFunction(GlobalDecl(), getContext().VoidTy, Fn,
+                getTypes().arrangeNullaryFunction(),
+                FunctionArgList(), SourceLocation());
+
+  llvm::CallInst *CI = Builder.CreateCall(DtorFn, DeclPtr);
+  // Make sure the call and the callee agree on calling convention.
+  if (llvm::Function *F = dyn_cast<llvm::Function>(DtorFn))
+    CI->setCallingConv(F->getCallingConv());
+
+  FinishFunction();
+
+  return Fn;
+}
+
 /// generateDestroyHelper - Generates a helper function which, when
 /// invoked, destroys the given object.
 llvm::Function * 
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 85cbd14..e70f329 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -2414,6 +2414,10 @@ public:
   /// with the C++ runtime so that its destructor will be called at exit.
   void EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
                                      llvm::Constant *DeclPtr);
+  /// EmitCXXAtExitGlobalDtor - Creates a call to atexit()
+  /// that a function "void __dtor_DeclPtr() {DeclPtr->~DtorFn();}".
+  void EmitCXXAtExitGlobalDtor(llvm::Constant *DtorFn,
+                               llvm::Constant *DeclPtr);
 
   /// Emit code in this function to perform a guarded variable
   /// initialization.  Guarded initializations are used when it's not
@@ -2429,11 +2433,13 @@ public:
                                  llvm::Constant **Decls,
                                  unsigned NumDecls);
 
-  /// GenerateCXXGlobalDtorFunc - Generates code for destroying global
+  /// GenerateCXXGlobalDtorsFunc - Generates code for destroying global
   /// variables.
-  void GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
-                                 const std::vector<std::pair<llvm::WeakVH,
-                                   llvm::Constant*> > &DtorsAndObjects);
+  void GenerateCXXGlobalDtorsFunc(llvm::Function *Fn,
+                                  const std::vector<std::pair<llvm::WeakVH,
+                                  llvm::Constant*> > &DtorsAndObjects);
+  llvm::Function *GenerateCXXGlobalDtorFunc(llvm::Constant *DtorFn,
+                                            llvm::Constant *DeclPtr);
 
   void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
                                         const VarDecl *D,
diff --git a/clang/test/CodeGenCXX/arm.cpp b/clang/test/CodeGenCXX/arm.cpp
index 36c6c1c..d3c77f8 100644
--- a/clang/test/CodeGenCXX/arm.cpp
+++ b/clang/test/CodeGenCXX/arm.cpp
@@ -20,9 +20,17 @@ public:
 
 // The global dtor needs the right calling conv with -fno-use-cxa-atexit
 // rdar://7817590
-// Checked at end of file.
 bar baz;
 
+// PR9593
+// Make sure atexit(3) is used for global dtors.
+
+// CHECK:      call %class.bar* @_ZN3barC1Ev(%class.bar* @baz)
+// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_baz)
+
+// CHECK: define internal void @__dtor_baz()
+// CHECK: call %class.bar* @_ZN3barD1Ev(%class.bar* @baz)
+
 // Destructors and constructors must return this.
 namespace test1 {
   void foo();
@@ -357,5 +365,5 @@ namespace test8 {
   // CHECK:   call void @_ZN5test21CD0Ev(
   // CHECK:   ret void
 
-// CHECK: @_GLOBAL__D_a()
-// CHECK: call %class.bar* @_ZN3barD1Ev(%class.bar* @baz)
+// CH_ECK: @_GLOBAL__D_a()
+// CH_ECK: call %class.bar* @_ZN3barD1Ev(%class.bar* @baz)
diff --git a/clang/test/CodeGenCXX/global-dtor-no-atexit.cpp b/clang/test/CodeGenCXX/global-dtor-no-atexit.cpp
index 1e125e3..0ba5115 100644
--- a/clang/test/CodeGenCXX/global-dtor-no-atexit.cpp
+++ b/clang/test/CodeGenCXX/global-dtor-no-atexit.cpp
@@ -3,10 +3,15 @@
 // PR7097
 // RUN: %clang_cc1 -triple x86_64 %s -fno-use-cxa-atexit -mconstructor-aliases -emit-llvm -o - | FileCheck %s
 
-// CHECK: define internal void @_GLOBAL__D_a()
-// CHECK:   call void @_ZN1AD1Ev(%class.A* @b)
-// CHECK:   call void @_ZN1AD1Ev(%class.A* @a)
-// CHECK: }
+// CHECK:      call void @_ZN1AC1Ev(%class.A* @a)
+// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_a)
+// CHECK:      define internal void @__dtor_a() nounwind
+// CHECK:      call void @_ZN1AD1Ev(%class.A* @a)
+
+// CHECK:      call void @_ZN1AC1Ev(%class.A* @b)
+// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_b)
+// CHECK:      define internal void @__dtor_b() nounwind
+// CHECK:      call void @_ZN1AD1Ev(%class.A* @b)
 
 class A {
 public:
@@ -15,3 +20,25 @@ public:
 };
 
 A a, b;
+
+// PR9593
+// CHECK:      define void @_Z4funcv()
+// CHECK:      call i32 @__cxa_guard_acquire(i64* @_ZGVZ4funcvE2a1)
+// CHECK:      call void @_ZN1AC1Ev(%class.A* @_ZZ4funcvE2a1)
+// CHECK-NEXT: call i32 @atexit(void ()* @__dtor__ZZ4funcvE2a1)
+// CHECK-NEXT: call void @__cxa_guard_release(i64* @_ZGVZ4funcvE2a1)
+
+// CHECK:      call i32 @__cxa_guard_acquire(i64* @_ZGVZ4funcvE2a2)
+// CHECK:      call void @_ZN1AC1Ev(%class.A* @_ZZ4funcvE2a2)
+// CHECK-NEXT: call i32 @atexit(void ()* @__dtor__ZZ4funcvE2a2)
+// CHECK-NEXT: call void @__cxa_guard_release(i64* @_ZGVZ4funcvE2a2)
+
+// CHECK:      define internal void @__dtor__ZZ4funcvE2a1() nounwind
+// CHECK:      call void @_ZN1AD1Ev(%class.A* @_ZZ4funcvE2a1)
+
+// CHECK:      define internal void @__dtor__ZZ4funcvE2a2() nounwind
+// CHECK:      call void @_ZN1AD1Ev(%class.A* @_ZZ4funcvE2a2)
+
+void func() {
+  static A a1, a2;
+}


More information about the cfe-commits mailing list