From 0b2bd47151ee9205ad6c66d1ffb921918106088a Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Tue, 13 Apr 2010 00:38:05 +0000 Subject: [PATCH] Add support for objc_copyStruct to enforce atomicity of aggregate properties in setter/getter methods. wip. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101107 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGObjC.cpp | 80 +++++++++++++++++++- lib/CodeGen/CodeGenFunction.h | 1 + test/CodeGenObjC/atomic-aggregate-property.m | 19 +++++ 3 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 test/CodeGenObjC/atomic-aggregate-property.m diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 206d438ced..ffdcbdcdea 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -208,7 +208,42 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified()); } else if (hasAggregateLLVMType(Ivar->getType())) { - EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType()); + if (!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) + && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect + && CGM.getObjCRuntime().GetCopyStructFunction()) { + llvm::Value *GetCopyStructFn = + CGM.getObjCRuntime().GetCopyStructFunction(); + CodeGenTypes &Types = CGM.getTypes(); + // objc_copyStruct (ReturnValue, &structIvar, + // sizeof (Type of Ivar), isAtomic, false); + CallArgList Args; + RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue, + Types.ConvertType(getContext().VoidPtrTy))); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), + Types.ConvertType(getContext().VoidPtrTy))); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + // sizeof (Type of Ivar) + uint64_t Size = getContext().getTypeSize(Ivar->getType()) / 8; + llvm::Value *SizeVal = + llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size); + Args.push_back(std::make_pair(RValue::get(SizeVal), + getContext().LongTy)); + // FIXME. Implement when Atomic is false; But when struct has + // gc'able data member! + llvm::Value *isAtomic = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1); + Args.push_back(std::make_pair(RValue::get(isAtomic), + getContext().BoolTy)); + llvm::Value *False = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0); + Args.push_back(std::make_pair(RValue::get(False), getContext().BoolTy)); + EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, + FunctionType::ExtInfo()), + GetCopyStructFn, ReturnValueSlot(), Args); + } + else + EmitAggregateCopy(ReturnValue, LV.getAddress(), Ivar->getType()); } else { CodeGenTypes &Types = CGM.getTypes(); RValue RV = EmitLoadOfLValue(LV, Ivar->getType()); @@ -289,6 +324,41 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, FunctionType::ExtInfo()), SetPropertyFn, ReturnValueSlot(), Args); + } else if (IsAtomic && hasAggregateLLVMType(Ivar->getType()) && + !Ivar->getType()->isAnyComplexType() && + IndirectObjCSetterArg(*CurFnInfo) + && CGM.getObjCRuntime().GetCopyStructFunction()) { + // objc_copyStruct (&structIvar, &Arg, + // sizeof (struct something), true, false); + llvm::Value *GetCopyStructFn = + CGM.getObjCRuntime().GetCopyStructFunction(); + CodeGenTypes &Types = CGM.getTypes(); + CallArgList Args; + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); + RValue RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), + Types.ConvertType(getContext().VoidPtrTy))); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()]; + llvm::Value *ArgAsPtrTy = + Builder.CreateBitCast(Arg, + Types.ConvertType(getContext().VoidPtrTy)); + RV = RValue::get(ArgAsPtrTy); + Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + // sizeof (Type of Ivar) + uint64_t Size = getContext().getTypeSize(Ivar->getType()) / 8; + llvm::Value *SizeVal = + llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size); + Args.push_back(std::make_pair(RValue::get(SizeVal), + getContext().LongTy)); + llvm::Value *True = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1); + Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy)); + llvm::Value *False = + llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0); + Args.push_back(std::make_pair(RValue::get(False), getContext().BoolTy)); + EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, + FunctionType::ExtInfo()), + GetCopyStructFn, ReturnValueSlot(), Args); } else { // FIXME: Find a clean way to avoid AST node creation. SourceLocation Loc = PD->getLocation(); @@ -318,6 +388,14 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, FinishFunction(); } +bool CodeGenFunction::IndirectObjCSetterArg(const CGFunctionInfo &FI) { + CGFunctionInfo::const_arg_iterator it = FI.arg_begin(); + it++; it++; + const ABIArgInfo &AI = it->info; + // FIXME. Is this sufficient check? + return (AI.getKind() == ABIArgInfo::Indirect); +} + llvm::Value *CodeGenFunction::LoadObjCSelf() { const ObjCMethodDecl *OMD = cast(CurFuncDecl); // See if we need to lazily forward self inside a block literal. diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index f21350d0f2..10f100d3f4 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -479,6 +479,7 @@ public: /// for the given property. void GenerateObjCSetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID); + bool IndirectObjCSetterArg(const CGFunctionInfo &FI); //===--------------------------------------------------------------------===// // Block Bits diff --git a/test/CodeGenObjC/atomic-aggregate-property.m b/test/CodeGenObjC/atomic-aggregate-property.m new file mode 100644 index 0000000000..66762c436f --- /dev/null +++ b/test/CodeGenObjC/atomic-aggregate-property.m @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck -check-prefix LP64 %s +// rdar: // 7849824 + +struct s { + double a, b, c, d; +}; + +@interface A +@property (readwrite) double x; +@property (readwrite) struct s y; +@end + +@implementation A +@synthesize x; +@synthesize y; +@end + +// CHECK-LP64: call void @objc_copyStruct +// CHECK-LP64: call void @objc_copyStruct