diff options
Diffstat (limited to 'lib/CodeGen/ItaniumCXXABI.cpp')
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 123 |
1 files changed, 88 insertions, 35 deletions
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 12ef9bd..0c86080f 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -24,6 +24,7 @@ #include "CodeGenModule.h" #include <clang/AST/Mangle.h> #include <clang/AST/Type.h> +#include <llvm/Intrinsics.h> #include <llvm/Target/TargetData.h> #include <llvm/Value.h> @@ -33,15 +34,15 @@ using namespace CodeGen; namespace { class ItaniumCXXABI : public CodeGen::CGCXXABI { private: - const llvm::IntegerType *PtrDiffTy; + llvm::IntegerType *PtrDiffTy; protected: bool IsARM; // It's a little silly for us to cache this. - const llvm::IntegerType *getPtrDiffTy() { + llvm::IntegerType *getPtrDiffTy() { if (!PtrDiffTy) { QualType T = getContext().getPointerDiffType(); - const llvm::Type *Ty = CGM.getTypes().ConvertTypeRecursive(T); + llvm::Type *Ty = CGM.getTypes().ConvertType(T); PtrDiffTy = cast<llvm::IntegerType>(Ty); } return PtrDiffTy; @@ -57,7 +58,7 @@ public: bool isZeroInitializable(const MemberPointerType *MPT); - const llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT); + llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT); llvm::Value *EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, llvm::Value *&This, @@ -175,13 +176,11 @@ CodeGen::CGCXXABI *CodeGen::CreateARMCXXABI(CodeGenModule &CGM) { return new ARMCXXABI(CGM); } -const llvm::Type * +llvm::Type * ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) { if (MPT->isMemberDataPointer()) return getPtrDiffTy(); - else - return llvm::StructType::get(CGM.getLLVMContext(), - getPtrDiffTy(), getPtrDiffTy(), NULL); + return llvm::StructType::get(getPtrDiffTy(), getPtrDiffTy(), NULL); } /// In the Itanium and ARM ABIs, method pointers have the form: @@ -473,8 +472,7 @@ ItaniumCXXABI::EmitMemberPointerConversion(llvm::Constant *C, else Values[1] = llvm::ConstantExpr::getAdd(CS->getOperand(1), Offset); - return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2, - /*Packed=*/false); + return llvm::ConstantStruct::get(CS->getType(), Values); } @@ -489,8 +487,7 @@ ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { llvm::Constant *Zero = llvm::ConstantInt::get(ptrdiff_t, 0); llvm::Constant *Values[2] = { Zero, Zero }; - return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2, - /*Packed=*/false); + return llvm::ConstantStruct::getAnon(Values); } llvm::Constant * @@ -540,7 +537,7 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); const llvm::Type *Ty; // Check whether the function has a computable LLVM signature. - if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) { + if (Types.isFuncTypeConvertible(FPT)) { // The function has a computable LLVM signature; use the correct type. Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic()); @@ -555,8 +552,7 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); } - return llvm::ConstantStruct::get(CGM.getLLVMContext(), - MemPtr, 2, /*Packed=*/false); + return llvm::ConstantStruct::getAnon(MemPtr); } /// The comparison algorithm is pretty easy: the member pointers are @@ -802,10 +798,27 @@ bool ItaniumCXXABI::NeedsArrayCookie(const CXXNewExpr *expr) { if (expr->doesUsualArrayDeleteWantSize()) return true; + // Automatic Reference Counting: + // We need an array cookie for pointers with strong or weak lifetime. + QualType AllocatedType = expr->getAllocatedType(); + if (getContext().getLangOptions().ObjCAutoRefCount && + AllocatedType->isObjCLifetimeType()) { + switch (AllocatedType.getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + return false; + + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Weak: + return true; + } + } + // Otherwise, if the class has a non-trivial destructor, it always // needs a cookie. const CXXRecordDecl *record = - expr->getAllocatedType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + AllocatedType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); return (record && !record->hasTrivialDestructor()); } @@ -816,6 +829,22 @@ bool ItaniumCXXABI::NeedsArrayCookie(const CXXDeleteExpr *expr, if (expr->doesUsualArrayDeleteWantSize()) return true; + // Automatic Reference Counting: + // We need an array cookie for pointers with strong or weak lifetime. + if (getContext().getLangOptions().ObjCAutoRefCount && + elementType->isObjCLifetimeType()) { + switch (elementType.getObjCLifetime()) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + return false; + + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Weak: + return true; + } + } + // Otherwise, if the class has a non-trivial destructor, it always // needs a cookie. const CXXRecordDecl *record = @@ -1005,31 +1034,34 @@ void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF, /*********************** Static local initialization **************************/ static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM, - const llvm::PointerType *GuardPtrTy) { + llvm::PointerType *GuardPtrTy) { // int __cxa_guard_acquire(__guard *guard_object); + llvm::Type *ArgTys[] = { GuardPtrTy }; const llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy), - GuardPtrTy, /*isVarArg=*/false); + ArgTys, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire"); } static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM, - const llvm::PointerType *GuardPtrTy) { + llvm::PointerType *GuardPtrTy) { // void __cxa_guard_release(__guard *guard_object); + llvm::Type *ArgTys[] = { GuardPtrTy }; const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()), - GuardPtrTy, /*isVarArg=*/false); + ArgTys, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release"); } static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM, - const llvm::PointerType *GuardPtrTy) { + llvm::PointerType *GuardPtrTy) { // void __cxa_guard_abort(__guard *guard_object); + llvm::Type *ArgTys[] = { GuardPtrTy }; const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()), - GuardPtrTy, /*isVarArg=*/false); + ArgTys, /*isVarArg=*/false); return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort"); } @@ -1039,7 +1071,7 @@ namespace { llvm::GlobalVariable *Guard; CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {} - void Emit(CodeGenFunction &CGF, bool IsForEH) { + void Emit(CodeGenFunction &CGF, Flags flags) { CGF.Builder.CreateCall(getGuardAbortFn(CGF.CGM, Guard->getType()), Guard) ->setDoesNotThrow(); } @@ -1055,21 +1087,21 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // We only need to use thread-safe statics for local variables; // global initialization is always single-threaded. - bool ThreadsafeStatics = (getContext().getLangOptions().ThreadsafeStatics && - D.isLocalVarDecl()); + bool threadsafe = + (getContext().getLangOptions().ThreadsafeStatics && D.isLocalVarDecl()); const llvm::IntegerType *GuardTy; // If we have a global variable with internal linkage and thread-safe statics // are disabled, we can just let the guard variable be of type i8. - bool UseInt8GuardVariable = !ThreadsafeStatics && GV->hasInternalLinkage(); - if (UseInt8GuardVariable) - GuardTy = Builder.getInt8Ty(); - else { + bool useInt8GuardVariable = !threadsafe && GV->hasInternalLinkage(); + if (useInt8GuardVariable) { + GuardTy = CGF.Int8Ty; + } else { // Guard variables are 64 bits in the generic ABI and 32 bits on ARM. - GuardTy = (IsARM ? Builder.getInt32Ty() : Builder.getInt64Ty()); + GuardTy = (IsARM ? CGF.Int32Ty : CGF.Int64Ty); } - const llvm::PointerType *GuardPtrTy = GuardTy->getPointerTo(); + llvm::PointerType *GuardPtrTy = GuardTy->getPointerTo(); // Create the guard variable. llvm::SmallString<256> GuardVName; @@ -1099,7 +1131,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // if (__cxa_guard_acquire(&obj_guard)) // ... // } - if (IsARM && !UseInt8GuardVariable) { + if (IsARM && !useInt8GuardVariable) { llvm::Value *V = Builder.CreateLoad(GuardVariable); V = Builder.CreateAnd(V, Builder.getInt32(1)); IsInitialized = Builder.CreateIsNull(V, "guard.uninitialized"); @@ -1130,13 +1162,16 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check"); llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end"); + llvm::BasicBlock *NoCheckBlock = EndBlock; + if (threadsafe) NoCheckBlock = CGF.createBasicBlock("init.barrier"); + // Check if the first byte of the guard variable is zero. - Builder.CreateCondBr(IsInitialized, InitCheckBlock, EndBlock); + Builder.CreateCondBr(IsInitialized, InitCheckBlock, NoCheckBlock); CGF.EmitBlock(InitCheckBlock); // Variables used when coping with thread-safe statics and exceptions. - if (ThreadsafeStatics) { + if (threadsafe) { // Call __cxa_guard_acquire. llvm::Value *V = Builder.CreateCall(getGuardAcquireFn(CGM, GuardPtrTy), GuardVariable); @@ -1155,7 +1190,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // Emit the initializer and add a global destructor if appropriate. CGF.EmitCXXGlobalVarDeclInit(D, GV); - if (ThreadsafeStatics) { + if (threadsafe) { // Pop the guard-abort cleanup if we pushed one. CGF.PopCleanupBlock(); @@ -1165,5 +1200,23 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, Builder.CreateStore(llvm::ConstantInt::get(GuardTy, 1), GuardVariable); } + // Emit an acquire memory barrier if using thread-safe statics: + // Itanium ABI: + // An implementation supporting thread-safety on multiprocessor + // systems must also guarantee that references to the initialized + // object do not occur before the load of the initialization flag. + if (threadsafe) { + Builder.CreateBr(EndBlock); + CGF.EmitBlock(NoCheckBlock); + + llvm::Value *_false = Builder.getFalse(); + llvm::Value *_true = Builder.getTrue(); + + Builder.CreateCall5(CGM.getIntrinsic(llvm::Intrinsic::memory_barrier), + /* load-load, load-store */ _true, _true, + /* store-load, store-store */ _false, _false, + /* device or I/O */ _false); + } + CGF.EmitBlock(EndBlock); } |