forked from OSchip/llvm-project
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). llvm-svn: 106061
This commit is contained in:
parent
438c35b5d1
commit
021510e96f
|
@ -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")
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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<uint64_t, unsigned> 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<uint64_t, unsigned> 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<RecordType>()) {
|
||||
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<RecordType>()) {
|
||||
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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<uint64_t, unsigned> 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(
|
||||
|
|
|
@ -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<uint64_t, unsigned> 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<uint64_t, unsigned> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<RecordType>()->getDecl()->hasObjectMember())
|
||||
Record->setHasObjectMember(true);
|
||||
}
|
||||
// Keep track of the number of named members.
|
||||
if (FD->getIdentifier())
|
||||
++NumNamedMembers;
|
||||
|
|
|
@ -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<RecordType>()->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<FunctionDecl>();
|
||||
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<Expr>();
|
||||
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<SourceLocation, 4> 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<Expr>());
|
||||
continue;
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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<class T> struct X0 { void f0(T * ) { } };
|
||||
template <class > struct X1 { X1( X1& , int = 0 ) { } };
|
||||
struct X2 { X1<int> result; };
|
||||
void test_X2()
|
||||
{
|
||||
typedef X2 impl;
|
||||
typedef X0<impl> pimpl;
|
||||
impl* i;
|
||||
pimpl pdata;
|
||||
pdata.f0( new impl(*i));
|
||||
}
|
Loading…
Reference in New Issue