[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