Adopt objc_assign_threadlocal() for __thread variables of GC types.

Implements radar 8203301.

llvm-svn: 108917
This commit is contained in:
Fariborz Jahanian 2010-07-20 20:30:03 +00:00
parent 6c01820900
commit 217af240b5
5 changed files with 57 additions and 17 deletions

View File

@ -836,8 +836,10 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst,
llvm::Value *BytesBetween = Builder.CreateSub(LHS, RHS, "ivar.offset"); llvm::Value *BytesBetween = Builder.CreateSub(LHS, RHS, "ivar.offset");
CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, dst, CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, dst,
BytesBetween); BytesBetween);
} else if (Dst.isGlobalObjCRef()) } else if (Dst.isGlobalObjCRef()) {
CGM.getObjCRuntime().EmitObjCGlobalAssign(*this, src, LvalueDst); CGM.getObjCRuntime().EmitObjCGlobalAssign(*this, src, LvalueDst,
Dst.isThreadLocalRef());
}
else else
CGM.getObjCRuntime().EmitObjCStrongCastAssign(*this, src, LvalueDst); CGM.getObjCRuntime().EmitObjCStrongCastAssign(*this, src, LvalueDst);
return; return;
@ -1055,8 +1057,10 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
if (const DeclRefExpr *Exp = dyn_cast<DeclRefExpr>(E)) { if (const DeclRefExpr *Exp = dyn_cast<DeclRefExpr>(E)) {
if (const VarDecl *VD = dyn_cast<VarDecl>(Exp->getDecl())) { if (const VarDecl *VD = dyn_cast<VarDecl>(Exp->getDecl())) {
if ((VD->isBlockVarDecl() && !VD->hasLocalStorage()) || if ((VD->isBlockVarDecl() && !VD->hasLocalStorage()) ||
VD->isFileVarDecl()) VD->isFileVarDecl()) {
LV.SetGlobalObjCRef(LV, true); LV.SetGlobalObjCRef(LV, true);
LV.SetThreadLocalRef(LV, VD->isThreadSpecified());
}
} }
LV.SetObjCArray(LV, E->getType()->isArrayType()); LV.SetObjCArray(LV, E->getType()->isArrayType());
return; return;

View File

@ -192,7 +192,8 @@ public:
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst); llvm::Value *src, llvm::Value *dst);
virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest); llvm::Value *src, llvm::Value *dest,
bool threadlocal=false);
virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest, llvm::Value *src, llvm::Value *dest,
llvm::Value *ivarOffset); llvm::Value *ivarOffset);
@ -2075,11 +2076,16 @@ void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
} }
void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) { llvm::Value *src, llvm::Value *dst,
bool threadlocal) {
CGBuilderTy B = CGF.Builder; CGBuilderTy B = CGF.Builder;
src = EnforceType(B, src, IdTy); src = EnforceType(B, src, IdTy);
dst = EnforceType(B, dst, PtrToIdTy); dst = EnforceType(B, dst, PtrToIdTy);
B.CreateCall2(GlobalAssignFn, src, dst); if (!threadlocal)
B.CreateCall2(GlobalAssignFn, src, dst);
else
// FIXME. Add threadloca assign API
assert(false && "EmitObjCGlobalAssign - Threal Local API NYI");
} }
void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,

View File

@ -402,6 +402,16 @@ public:
return CGM.CreateRuntimeFunction(FTy, "objc_assign_global"); return CGM.CreateRuntimeFunction(FTy, "objc_assign_global");
} }
/// GcAssignThreadLocalFn -- LLVM objc_assign_threadlocal function.
llvm::Constant *getGcAssignThreadLocalFn() {
// id objc_assign_threadlocal(id src, id * dest)
std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
Args.push_back(ObjectPtrTy->getPointerTo());
llvm::FunctionType *FTy =
llvm::FunctionType::get(ObjectPtrTy, Args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_assign_threadlocal");
}
/// GcAssignIvarFn -- LLVM objc_assign_ivar function. /// GcAssignIvarFn -- LLVM objc_assign_ivar function.
llvm::Constant *getGcAssignIvarFn() { llvm::Constant *getGcAssignIvarFn() {
// id objc_assign_ivar(id, id *, ptrdiff_t) // id objc_assign_ivar(id, id *, ptrdiff_t)
@ -425,7 +435,7 @@ public:
/// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function. /// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function.
llvm::Constant *getGcAssignStrongCastFn() { llvm::Constant *getGcAssignStrongCastFn() {
// id objc_assign_global(id, id *) // id objc_assign_strongCast(id, id *)
std::vector<const llvm::Type*> Args(1, ObjectPtrTy); std::vector<const llvm::Type*> Args(1, ObjectPtrTy);
Args.push_back(ObjectPtrTy->getPointerTo()); Args.push_back(ObjectPtrTy->getPointerTo());
llvm::FunctionType *FTy = llvm::FunctionType *FTy =
@ -1198,7 +1208,8 @@ public:
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst); llvm::Value *src, llvm::Value *dst);
virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest); llvm::Value *src, llvm::Value *dest,
bool threadlocal = false);
virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest, llvm::Value *src, llvm::Value *dest,
llvm::Value *ivarOffset); llvm::Value *ivarOffset);
@ -1444,7 +1455,8 @@ public:
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst); llvm::Value *src, llvm::Value *dst);
virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest); llvm::Value *src, llvm::Value *dest,
bool threadlocal = false);
virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest, llvm::Value *src, llvm::Value *dest,
llvm::Value *ivarOffset); llvm::Value *ivarOffset);
@ -2996,7 +3008,8 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
/// objc_assign_global (id src, id *dst) /// objc_assign_global (id src, id *dst)
/// ///
void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) { llvm::Value *src, llvm::Value *dst,
bool threadlocal) {
const llvm::Type * SrcTy = src->getType(); const llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) { if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
@ -3007,8 +3020,12 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
} }
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy); dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(), if (!threadlocal)
src, dst, "globalassign"); CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(),
src, dst, "globalassign");
else
CGF.Builder.CreateCall2(ObjCTypes.getGcAssignThreadLocalFn(),
src, dst, "threadlocalassign");
return; return;
} }
@ -5657,7 +5674,8 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
/// objc_assign_global (id src, id *dst) /// objc_assign_global (id src, id *dst)
/// ///
void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) { llvm::Value *src, llvm::Value *dst,
bool threadlocal) {
const llvm::Type * SrcTy = src->getType(); const llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) { if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
@ -5668,8 +5686,12 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
} }
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy); dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(), if (!threadlocal)
src, dst, "globalassign"); CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(),
src, dst, "globalassign");
else
CGF.Builder.CreateCall2(ObjCTypes.getGcAssignThreadLocalFn(),
src, dst, "threadlocalassign");
return; return;
} }

View File

@ -192,7 +192,8 @@ public:
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest) = 0; llvm::Value *src, llvm::Value *dest) = 0;
virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest) = 0; llvm::Value *src, llvm::Value *dest,
bool threadlocal=false) = 0;
virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dest, llvm::Value *src, llvm::Value *dest,
llvm::Value *ivarOffset) = 0; llvm::Value *ivarOffset) = 0;

View File

@ -149,6 +149,9 @@ class LValue {
// Lvalue is a global reference of an objective-c object // Lvalue is a global reference of an objective-c object
bool GlobalObjCRef : 1; bool GlobalObjCRef : 1;
// Lvalue is a thread local reference
bool ThreadLocalRef : 1;
Expr *BaseIvarExp; Expr *BaseIvarExp;
private: private:
void SetQualifiers(Qualifiers Quals) { void SetQualifiers(Qualifiers Quals) {
@ -157,6 +160,7 @@ private:
// FIXME: Convenient place to set objc flags to 0. This should really be // FIXME: Convenient place to set objc flags to 0. This should really be
// done in a user-defined constructor instead. // done in a user-defined constructor instead.
this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false; this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false;
this->ThreadLocalRef = false;
this->BaseIvarExp = 0; this->BaseIvarExp = 0;
} }
@ -178,6 +182,7 @@ public:
bool isObjCArray() const { return ObjIsArray; } bool isObjCArray() const { return ObjIsArray; }
bool isNonGC () const { return NonGC; } bool isNonGC () const { return NonGC; }
bool isGlobalObjCRef() const { return GlobalObjCRef; } bool isGlobalObjCRef() const { return GlobalObjCRef; }
bool isThreadLocalRef() const { return ThreadLocalRef; }
bool isObjCWeak() const { return Quals.getObjCGCAttr() == Qualifiers::Weak; } bool isObjCWeak() const { return Quals.getObjCGCAttr() == Qualifiers::Weak; }
bool isObjCStrong() const { return Quals.getObjCGCAttr() == Qualifiers::Strong; } bool isObjCStrong() const { return Quals.getObjCGCAttr() == Qualifiers::Strong; }
@ -195,7 +200,9 @@ public:
static void SetGlobalObjCRef(LValue& R, bool iValue) { static void SetGlobalObjCRef(LValue& R, bool iValue) {
R.GlobalObjCRef = iValue; R.GlobalObjCRef = iValue;
} }
static void SetThreadLocalRef(LValue& R, bool iValue) {
R.ThreadLocalRef = iValue;
}
static void SetObjCNonGC(LValue& R, bool iValue) { static void SetObjCNonGC(LValue& R, bool iValue) {
R.NonGC = iValue; R.NonGC = iValue;
} }