From: David Chisnall Date: Wed, 3 Feb 2010 15:59:02 +0000 (+0000) Subject: First pass at adding GC support for GNU runtime. GC ivar maps not yet constructed... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ef6e0f3218b64d8ea3b8b57ee657fec8da228a43;p=clang First pass at adding GC support for GNU runtime. GC ivar maps not yet constructed, GC flag not set. Please don't try using this yet - the runtime support is still very immature and your code will almost certainly crash if you do. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95222 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index d69477852a..e068b68b3f 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -55,6 +55,7 @@ private: const llvm::PointerType *PtrToInt8Ty; const llvm::FunctionType *IMPTy; const llvm::PointerType *IdTy; + const llvm::PointerType *PtrToIdTy; QualType ASTIdTy; const llvm::IntegerType *IntTy; const llvm::PointerType *PtrTy; @@ -71,6 +72,11 @@ private: typedef std::pair TypedSelector; std::map TypedSelectors; llvm::StringMap UntypedSelectors; + // Selectors that we don't emit in GC mode + Selector RetainSel, ReleaseSel, AutoreleaseSel; + // Functions used for GC. + llvm::Constant *IvarAssignFn, *StrongCastAssignFn, *MemMoveFn, *WeakReadFn, + *WeakAssignFn, *GlobalAssignFn; // Some zeros used for GEPs in lots of places. llvm::Constant *Zeros[2]; llvm::Constant *NULLPtr; @@ -123,6 +129,10 @@ private: llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID, const ObjCIvarDecl *Ivar); void EmitClassRef(const std::string &className); + llvm::Value* EnforceType(CGBuilderTy B, llvm::Value *V, const llvm::Type *Ty){ + if (V->getType() == Ty) return V; + return B.CreateBitCast(V, Ty); + } public: CGObjCGNU(CodeGen::CodeGenModule &cgm); virtual llvm::Constant *GenerateConstantString(const StringLiteral *); @@ -266,12 +276,54 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) } else { IdTy = cast(CGM.getTypes().ConvertType(ASTIdTy)); } + PtrToIdTy = llvm::PointerType::getUnqual(IdTy); // IMP type std::vector IMPArgs; IMPArgs.push_back(IdTy); IMPArgs.push_back(SelectorTy); IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true); + + if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { + // Get selectors needed in GC mode + RetainSel = GetNullarySelector("retain", CGM.getContext()); + ReleaseSel = GetNullarySelector("release", CGM.getContext()); + AutoreleaseSel = GetNullarySelector("autorelease", CGM.getContext()); + + // Get functions needed in GC mode + + // id objc_assign_ivar(id, id, ptrdiff_t); + std::vector Args(1, IdTy); + Args.push_back(PtrToIdTy); + // FIXME: ptrdiff_t + Args.push_back(LongTy); + llvm::FunctionType *FTy = llvm::FunctionType::get(IdTy, Args, false); + IvarAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar"); + // id objc_assign_strongCast (id, id*) + Args.pop_back(); + FTy = llvm::FunctionType::get(IdTy, Args, false); + StrongCastAssignFn = + CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast"); + // id objc_assign_global(id, id*); + FTy = llvm::FunctionType::get(IdTy, Args, false); + GlobalAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_global"); + // id objc_assign_weak(id, id*); + FTy = llvm::FunctionType::get(IdTy, Args, false); + WeakAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_weak"); + // id objc_read_weak(id*); + Args.clear(); + Args.push_back(PtrToIdTy); + FTy = llvm::FunctionType::get(IdTy, Args, false); + WeakReadFn = CGM.CreateRuntimeFunction(FTy, "objc_read_weak"); + // void *objc_memmove_collectable(void*, void *, size_t); + Args.clear(); + Args.push_back(PtrToInt8Ty); + Args.push_back(PtrToInt8Ty); + // FIXME: size_t + Args.push_back(LongTy); + FTy = llvm::FunctionType::get(IdTy, Args, false); + MemMoveFn = CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable"); + } } // This has to perform the lookup every time, since posing and related @@ -400,6 +452,14 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { + if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { + if (Sel == RetainSel || Sel == AutoreleaseSel) { + return RValue::get(Receiver); + } + if (Sel == ReleaseSel) { + return RValue::get(0); + } + } llvm::Value *cmd = GetSelector(CGF.Builder, Sel); CallArgList ActualArgs; @@ -494,6 +554,14 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, bool IsClassMessage, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { + if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { + if (Sel == RetainSel || Sel == AutoreleaseSel) { + return RValue::get(Receiver); + } + if (Sel == ReleaseSel) { + return RValue::get(0); + } + } CGBuilderTy &Builder = CGF.Builder; IdTy = cast(CGM.getTypes().ConvertType(ASTIdTy)); llvm::Value *cmd; @@ -1918,35 +1986,58 @@ void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF, llvm::Value *AddrWeakObj) { - return 0; + CGBuilderTy B = CGF.Builder; + AddrWeakObj = EnforceType(B, AddrWeakObj, IdTy); + return B.CreateCall(WeakReadFn, AddrWeakObj); } void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { - return; + CGBuilderTy B = CGF.Builder; + src = EnforceType(B, src, IdTy); + dst = EnforceType(B, dst, PtrToIdTy); + B.CreateCall2(WeakAssignFn, src, dst); } void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { - return; + CGBuilderTy B = CGF.Builder; + src = EnforceType(B, src, IdTy); + dst = EnforceType(B, dst, PtrToIdTy); + B.CreateCall2(GlobalAssignFn, src, dst); } void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst, llvm::Value *ivarOffset) { - return; + CGBuilderTy B = CGF.Builder; + src = EnforceType(B, src, IdTy); + dst = EnforceType(B, dst, PtrToIdTy); + B.CreateCall3(IvarAssignFn, src, dst, ivarOffset); } void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { - return; + CGBuilderTy B = CGF.Builder; + src = EnforceType(B, src, IdTy); + dst = EnforceType(B, dst, PtrToIdTy); + B.CreateCall2(StrongCastAssignFn, src, dst); } void CGObjCGNU::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, llvm::Value *DestPtr, llvm::Value *SrcPtr, QualType Ty) { - return; + 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); } llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(