diff options
author | Anders Carlsson <andersca@mac.com> | 2010-02-06 23:23:06 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2010-02-06 23:23:06 +0000 |
commit | a508b7de6c5246ab04ed69d0ab4e9977ec1fb4d4 (patch) | |
tree | 9b5b83fb4a534e2d2decf51f1af85d1a68dae007 /lib/CodeGen/CGDeclCXX.cpp | |
parent | 594d5e8bd9870080aad6a761538e272bc2dfcc13 (diff) |
Add support for threadsafe statics, and make them the default (matching gcc).
Daniel, I'd appreciate a review of the driver/cc1 parts.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95508 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGDeclCXX.cpp')
-rw-r--r-- | lib/CodeGen/CGDeclCXX.cpp | 107 |
1 files changed, 85 insertions, 22 deletions
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 3d5a4e8051..0de3b0be4b 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -184,42 +184,100 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, FinishFunction(); } +static llvm::Constant *getGuardAcquireFn(CodeGenFunction &CGF) { + // int __cxa_guard_acquire(__int64_t *guard_object); + + const llvm::Type *Int64PtrTy = + llvm::Type::getInt64PtrTy(CGF.getLLVMContext()); + + std::vector<const llvm::Type*> Args(1, Int64PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(CGF.ConvertType(CGF.getContext().IntTy), + Args, /*isVarArg=*/false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire"); +} + +static llvm::Constant *getGuardReleaseFn(CodeGenFunction &CGF) { + // void __cxa_guard_release(__int64_t *guard_object); + + const llvm::Type *Int64PtrTy = + llvm::Type::getInt64PtrTy(CGF.getLLVMContext()); + + std::vector<const llvm::Type*> Args(1, Int64PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, /*isVarArg=*/false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release"); +} + +static llvm::Constant *getGuardAbortFn(CodeGenFunction &CGF) { + // void __cxa_guard_abort(__int64_t *guard_object); + + const llvm::Type *Int64PtrTy = + llvm::Type::getInt64PtrTy(CGF.getLLVMContext()); + + std::vector<const llvm::Type*> Args(1, Int64PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, /*isVarArg=*/false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort"); +} + void CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, llvm::GlobalVariable *GV) { - // FIXME: This should use __cxa_guard_{acquire,release}? - - assert(!getContext().getLangOptions().ThreadsafeStatics && - "thread safe statics are currently not supported!"); - + bool ThreadsafeStatics = getContext().getLangOptions().ThreadsafeStatics; + llvm::SmallString<256> GuardVName; CGM.getMangleContext().mangleGuardVariable(&D, GuardVName); // Create the guard variable. - llvm::GlobalValue *GuardV = - new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext), + const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(VMContext); + llvm::GlobalValue *GuardVariable = + new llvm::GlobalVariable(CGM.getModule(), Int64Ty, false, GV->getLinkage(), - llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)), + llvm::Constant::getNullValue(Int64Ty), GuardVName.str()); // Load the first byte of the guard variable. const llvm::Type *PtrTy = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); - llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy), - "tmp"); + llvm::Value *V = + Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy), "tmp"); - // Compare it against 0. - llvm::Value *nullValue - = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)); - llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool"); - - llvm::BasicBlock *InitBlock = createBasicBlock("init"); + llvm::BasicBlock *InitCheckBlock = createBasicBlock("init.check"); llvm::BasicBlock *EndBlock = createBasicBlock("init.end"); - // If the guard variable is 0, jump to the initializer code. - Builder.CreateCondBr(ICmp, InitBlock, EndBlock); + // Check if the first byte of the guard variable is zero. + Builder.CreateCondBr(Builder.CreateIsNull(V, "tobool"), + InitCheckBlock, EndBlock); - EmitBlock(InitBlock); + EmitBlock(InitCheckBlock); + + if (ThreadsafeStatics) { + // Call __cxa_guard_acquire. + V = Builder.CreateCall(getGuardAcquireFn(*this), GuardVariable); + + llvm::BasicBlock *InitBlock = createBasicBlock("init"); + + Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"), + InitBlock, EndBlock); + + EmitBlock(InitBlock); + + if (Exceptions) { + EHCleanupBlock Cleanup(*this); + + // Call __cxa_guard_abort. + Builder.CreateCall(getGuardAbortFn(*this), GuardVariable); + } + } if (D.getType()->isReferenceType()) { QualType T = D.getType(); @@ -232,9 +290,14 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, } else EmitDeclInit(*this, D, GV); - Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), - 1), - Builder.CreateBitCast(GuardV, PtrTy)); + if (ThreadsafeStatics) { + // Call __cxa_guard_release. + Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable); + } else { + llvm::Value *One = + llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1); + Builder.CreateStore(One, Builder.CreateBitCast(GuardVariable, PtrTy)); + } EmitBlock(EndBlock); } |