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.
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.
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
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,
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,
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());
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
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 {
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);
+}
// 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
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);
}
--- /dev/null
+// 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@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@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@XZ"
+// CHECK: call i32 @atexit(void ()* [[FOO_DTOR:@"__dtor_.*foo@.*]])
+// CHECK: ret void
+
+// CHECK: define linkonce_odr void @"\01??0A@@QAE@XZ"
+
+// CHECK: define linkonce_odr void @"\01??1A@@QAE@XZ"
+
+// CHECK: define internal void [[FOO_DTOR]]
+// CHECK: call void @"\01??1A@@QAE@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