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;
typedef std::pair<std::string, std::string> TypedSelector;
std::map<TypedSelector, llvm::GlobalAlias*> TypedSelectors;
llvm::StringMap<llvm::GlobalAlias*> 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;
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 *);
} else {
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
}
+ PtrToIdTy = llvm::PointerType::getUnqual(IdTy);
// IMP type
std::vector<const llvm::Type*> 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<const llvm::Type*> 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
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;
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<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
llvm::Value *cmd;
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<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);
}
llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(