From 55bcace250e1ff366e4482714b344b8cbc8be5f3 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Tue, 15 Jun 2010 22:44:06 +0000 Subject: [PATCH] Patch adds support for copying of those objective-c++ class objects which have GC'able objc object pointers and need to use ObjC's objc_memmove_collectable API (radar 8070772). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106061 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Builtins.def | 1 + lib/CodeGen/CGBuiltin.cpp | 11 +++ lib/CodeGen/CGExprAgg.cpp | 44 +++++++++-- lib/CodeGen/CGExprCXX.cpp | 5 +- lib/CodeGen/CGObjCGNU.cpp | 11 +-- lib/CodeGen/CGObjCMac.cpp | 20 ++--- lib/CodeGen/CGObjCRuntime.h | 2 +- lib/Sema/SemaDecl.cpp | 6 ++ lib/Sema/SemaDeclCXX.cpp | 41 +++++++++-- .../implicit-copy-assign-operator.mm | 57 +++++++++++++++ test/CodeGenCXX/implicit-copy-constructor.mm | 73 +++++++++++++++++++ 11 files changed, 233 insertions(+), 38 deletions(-) create mode 100644 test/CodeGenCXX/implicit-copy-assign-operator.mm create mode 100644 test/CodeGenCXX/implicit-copy-constructor.mm diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index b306954975..a405a41db8 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -540,6 +540,7 @@ LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h") // id objc_msgSend(id, SEL) // but we need new type letters for that. LIBBUILTIN(objc_msgSend, "v*.", "f", "objc/message.h") +LIBBUILTIN(objc_memmove_collectable, "v*v*vC*z", "nF", "objc/objc-auto.h") // Builtin math library functions LIBBUILTIN(pow, "ddd", "fe", "math.h") diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 1811e083a1..2f6b131202 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -14,6 +14,7 @@ #include "TargetInfo.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "CGObjCRuntime.h" #include "clang/Basic/TargetInfo.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" @@ -483,6 +484,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), 0)); return RValue::get(Address); } + + case Builtin::BIobjc_memmove_collectable: { + Value *Address = EmitScalarExpr(E->getArg(0)); + Value *SrcAddr = EmitScalarExpr(E->getArg(1)); + Value *SizeVal = EmitScalarExpr(E->getArg(2)); + CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, + Address, SrcAddr, SizeVal); + return RValue::get(Address); + } + case Builtin::BImemmove: case Builtin::BI__builtin_memmove: { Value *Address = EmitScalarExpr(E->getArg(0)); diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 6c8a60e981..1a644f37a3 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -177,11 +177,16 @@ bool AggExprEmitter::TypeRequiresGCollection(QualType T) { /// directly into the return value slot. If GC does interfere, a final /// move will be performed. void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) { - if (!RequiresGCollection) return; - - CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, DestPtr, + if (RequiresGCollection) { + std::pair TypeInfo = + CGF.getContext().getTypeInfo(E->getType()); + unsigned long size = TypeInfo.first/8; + const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); + llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size); + CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, DestPtr, Src.getAggregateAddr(), - E->getType()); + SizeVal); + } } /// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired. @@ -198,9 +203,14 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) { } if (RequiresGCollection) { + std::pair TypeInfo = + CGF.getContext().getTypeInfo(E->getType()); + unsigned long size = TypeInfo.first/8; + const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); + llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size); CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, DestPtr, Src.getAggregateAddr(), - E->getType()); + SizeVal); return; } // If the result of the assignment is used, copy the LHS there also. @@ -837,6 +847,30 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, if (SrcPtr->getType() != SBP) SrcPtr = Builder.CreateBitCast(SrcPtr, SBP, "tmp"); + if (const RecordType *RecordTy = Ty->getAs()) { + RecordDecl *Record = RecordTy->getDecl(); + if (Record->hasObjectMember()) { + unsigned long size = TypeInfo.first/8; + const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size); + CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr, + SizeVal); + return; + } + } else if (getContext().getAsArrayType(Ty)) { + QualType BaseType = getContext().getBaseElementType(Ty); + if (const RecordType *RecordTy = BaseType->getAs()) { + if (RecordTy->getDecl()->hasObjectMember()) { + unsigned long size = TypeInfo.first/8; + const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size); + CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr, + SizeVal); + return; + } + } + } + Builder.CreateCall5(CGM.getMemCpyFn(DestPtr->getType(), SrcPtr->getType(), IntPtr), DestPtr, SrcPtr, diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index f93c79c742..cf5d9abe8d 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -275,10 +275,7 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress(); QualType Ty = E->getType(); - if (ClassDecl->hasObjectMember()) - CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, This, Src, Ty); - else - EmitAggregateCopy(This, Src, Ty); + EmitAggregateCopy(This, Src, Ty); return RValue::get(This); } } diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 6c25afeb9a..8af4b506c7 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -197,7 +197,7 @@ public: virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, llvm::Value *DestPtr, llvm::Value *SrcPtr, - QualType Ty); + llvm::Value *Size); virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy, llvm::Value *BaseValue, @@ -2174,17 +2174,12 @@ void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, void CGObjCGNU::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, llvm::Value *DestPtr, llvm::Value *SrcPtr, - QualType Ty) { + llvm::Value *Size) { CGBuilderTy B = CGF.Builder; DestPtr = EnforceType(B, DestPtr, IdTy); SrcPtr = EnforceType(B, SrcPtr, PtrToIdTy); - std::pair TypeInfo = CGM.getContext().getTypeInfo(Ty); - unsigned long size = TypeInfo.first/8; - // FIXME: size_t - llvm::Value *N = llvm::ConstantInt::get(LongTy, size); - - B.CreateCall3(MemMoveFn, DestPtr, SrcPtr, N); + B.CreateCall3(MemMoveFn, DestPtr, SrcPtr, Size); } llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable( diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 94735b0871..d59f367347 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -1196,7 +1196,7 @@ public: llvm::Value *src, llvm::Value *dest); virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, llvm::Value *dest, llvm::Value *src, - QualType Ty); + llvm::Value *size); virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy, @@ -1438,7 +1438,7 @@ public: llvm::Value *src, llvm::Value *dest); virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, llvm::Value *dest, llvm::Value *src, - QualType Ty); + llvm::Value *size); virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy, llvm::Value *BaseValue, @@ -2938,15 +2938,11 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, llvm::Value *DestPtr, llvm::Value *SrcPtr, - QualType Ty) { - // Get size info for this aggregate. - std::pair TypeInfo = CGM.getContext().getTypeInfo(Ty); - unsigned long size = TypeInfo.first/8; + llvm::Value *size) { SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy); DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy); - llvm::Value *N = llvm::ConstantInt::get(ObjCTypes.LongTy, size); CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(), - DestPtr, SrcPtr, N); + DestPtr, SrcPtr, size); return; } @@ -5476,15 +5472,11 @@ void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable( CodeGen::CodeGenFunction &CGF, llvm::Value *DestPtr, llvm::Value *SrcPtr, - QualType Ty) { - // Get size info for this aggregate. - std::pair TypeInfo = CGM.getContext().getTypeInfo(Ty); - unsigned long size = TypeInfo.first/8; + llvm::Value *Size) { SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy); DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy); - llvm::Value *N = llvm::ConstantInt::get(ObjCTypes.LongTy, size); CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(), - DestPtr, SrcPtr, N); + DestPtr, SrcPtr, Size); return; } diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index 8de7f10b86..1f6d63b8ab 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -208,7 +208,7 @@ public: virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, llvm::Value *DestPtr, llvm::Value *SrcPtr, - QualType Ty) = 0; + llvm::Value *Size) = 0; }; /// Creates an instance of an Objective-C runtime class. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d1818b813c..e3d20bd5e4 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -6232,6 +6232,12 @@ void Sema::ActOnFields(Scope* S, (FD->getType()->isObjCObjectPointerType() || FD->getType().isObjCGCStrong())) Record->setHasObjectMember(true); + else if (Context.getAsArrayType(FD->getType())) { + QualType BaseType = Context.getBaseElementType(FD->getType()); + if (Record && BaseType->isRecordType() && + BaseType->getAs()->getDecl()->hasObjectMember()) + Record->setHasObjectMember(true); + } // Keep track of the number of named members. if (FD->getIdentifier()) ++NumNamedMembers; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index aa2be17824..0fb30d82a1 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4557,6 +4557,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // \brief Reference to the __builtin_memcpy function. Expr *BuiltinMemCpyRef = 0; + // \brief Reference to the objc_memmove_collectable function. + Expr *CollectableMemCpyRef = 0; // Assign non-static members. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), @@ -4633,9 +4635,34 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Take the address of the field references for "from" and "to". From = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(From)); To = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(To)); - + + bool NeedsCollectableMemCpy = + (BaseType->isRecordType() && + BaseType->getAs()->getDecl()->hasObjectMember()); + + if (NeedsCollectableMemCpy) { + if (!CollectableMemCpyRef) { + // Create a reference to the objc_memmove_collectable function. + LookupResult R(*this, &Context.Idents.get("objc_memmove_collectable"), + Loc, LookupOrdinaryName); + LookupName(R, TUScope, true); + + FunctionDecl *CollectableMemCpy = R.getAsSingle(); + if (!CollectableMemCpy) { + // Something went horribly wrong earlier, and we will have + // complained about it. + Invalid = true; + continue; + } + + CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy, + CollectableMemCpy->getType(), + Loc, 0).takeAs(); + assert(CollectableMemCpyRef && "Builtin reference cannot fail"); + } + } // Create a reference to the __builtin_memcpy builtin function. - if (!BuiltinMemCpyRef) { + else if (!BuiltinMemCpyRef) { LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc, LookupOrdinaryName); LookupName(R, TUScope, true); @@ -4661,10 +4688,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, llvm::SmallVector Commas; // FIXME: Silly Commas.push_back(Loc); Commas.push_back(Loc); - OwningExprResult Call = ActOnCallExpr(/*Scope=*/0, - Owned(BuiltinMemCpyRef->Retain()), - Loc, move_arg(CallArgs), - Commas.data(), Loc); + OwningExprResult Call = ActOnCallExpr(/*Scope=*/0, + NeedsCollectableMemCpy ? + Owned(CollectableMemCpyRef->Retain()) : + Owned(BuiltinMemCpyRef->Retain()), + Loc, move_arg(CallArgs), + Commas.data(), Loc); assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!"); Statements.push_back(Call.takeAs()); continue; diff --git a/test/CodeGenCXX/implicit-copy-assign-operator.mm b/test/CodeGenCXX/implicit-copy-assign-operator.mm new file mode 100644 index 0000000000..16ae1472dd --- /dev/null +++ b/test/CodeGenCXX/implicit-copy-assign-operator.mm @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -fobjc-gc -emit-llvm -triple x86_64-apple-darwin10.0.0 -o - %s | FileCheck %s +struct A { + A &operator=(const A&); + A &operator=(A&); +}; + +struct B { + B &operator=(B&); +}; + +struct C { + virtual C& operator=(const C&); +}; + +struct POD { + id myobjc; + int array[3][4]; +}; + +struct CopyByValue { + CopyByValue(const CopyByValue&); + CopyByValue &operator=(CopyByValue); +}; + +struct D : A, B, virtual C { + int scalar; + int scalar_array[2][3]; + B class_member; + C class_member_array[2][3]; + POD pod_array[2][3]; + + union { + int x; + float f[3]; + }; + + CopyByValue by_value; +}; + +void test_D(D d1, D d2) { + d1 = d2; +} + +// CHECK: define linkonce_odr %struct.D* @_ZN1DaSERS_ +// CHECK: {{call.*_ZN1AaSERS_}} +// CHECK: {{call.*_ZN1BaSERS_}} +// CHECK: {{call.*_ZN1CaSERKS_}} +// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}} +// CHECK: {{call.*_ZN1BaSERS_}} +// CHECK: br +// CHECK: {{call.*_ZN1CaSERKS_}} +// CHECK: {{call.*@objc_memmove_collectable}} +// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}} +// CHECK: call void @_ZN11CopyByValueC1ERKS_ +// CHECK: {{call.*_ZN11CopyByValueaSES_}} +// CHECK: ret + diff --git a/test/CodeGenCXX/implicit-copy-constructor.mm b/test/CodeGenCXX/implicit-copy-constructor.mm new file mode 100644 index 0000000000..489fd9758e --- /dev/null +++ b/test/CodeGenCXX/implicit-copy-constructor.mm @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 -fobjc-gc -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +struct A { + A(); + A(const A&); + A(A&); + ~A(); +}; + +struct B { + B(); + B(B&); +}; + +struct C { + C() {} + C(C& other, A a = A()); + int i, j; +}; + +struct POD { + id myobjc; + int array[3][4]; +}; + +struct D : A, B, virtual C { + D(); + int scalar; + int scalar_array[2][3]; + B class_member; + C class_member_array[2][3]; + POD pod_array[2][3]; + + union { + int x; + float f[3]; + }; +}; + +void f(D d) { + D d2(d); +} + +// CHECK: define linkonce_odr void @_ZN1DC1ERS_ +// CHECK: call void @_ZN1AC1Ev +// CHECK: call void @_ZN1CC2ERS_1A +// CHECK: call void @_ZN1AD1Ev +// CHECK: call void @_ZN1AC2ERS_ +// CHECK: call void @_ZN1BC2ERS_ +// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}} +// CHECK: call void @_ZN1BC1ERS_ +// CHECK: br +// CHECK: {{icmp ult.*, 2}} +// CHECK: {{icmp ult.*, 3}} +// CHECK: call void @_ZN1AC1Ev +// CHECK: call void @_ZN1CC1ERS_1A +// CHECK: call void @_ZN1AD1Ev +// CHECK: {{call.*@objc_memmove_collectable}} +// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}} +// CHECK: ret void + + +template struct X0 { void f0(T * ) { } }; +template struct X1 { X1( X1& , int = 0 ) { } }; +struct X2 { X1 result; }; +void test_X2() +{ + typedef X2 impl; + typedef X0 pimpl; + impl* i; + pimpl pdata; + pdata.f0( new impl(*i)); +} -- 2.40.0