Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 1 | //===------- CGObjCEtoile.cpp - Emit LLVM Code from ASTs for a Module --------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This provides Objective-C code generation targetting the Etoile runtime. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 14 | #include "CGObjCRuntime.h" |
| 15 | #include "llvm/Module.h" |
| 16 | #include "llvm/Support/Compiler.h" |
Chris Lattner | 50b3674 | 2008-04-13 07:32:11 +0000 | [diff] [blame] | 17 | #include "llvm/Support/IRBuilder.h" |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 18 | #include "llvm/ADT/SmallVector.h" |
| 19 | |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 20 | namespace { |
| 21 | class CGObjCEtoile : public clang::CodeGen::CGObjCRuntime { |
| 22 | private: |
| 23 | llvm::Module &TheModule; |
| 24 | const llvm::Type *SelectorTy; |
| 25 | const llvm::PointerType *PtrToInt8Ty; |
| 26 | const llvm::Type *IMPTy; |
| 27 | const llvm::Type *IntTy; |
| 28 | const llvm::Type *PtrTy; |
| 29 | const llvm::Type *LongTy; |
| 30 | const llvm::Type *PtrToIntTy; |
| 31 | const llvm::Type *IdTy; |
| 32 | const llvm::Type *CallTy; |
| 33 | const llvm::Type *SlotTy; |
| 34 | const llvm::Type *LookupFunctionTy; |
| 35 | public: |
| 36 | CGObjCEtoile(llvm::Module &Mp, |
| 37 | const llvm::Type *LLVMIntType, |
| 38 | const llvm::Type *LLVMLongType); |
Chris Lattner | 50b3674 | 2008-04-13 07:32:11 +0000 | [diff] [blame] | 39 | virtual llvm::Value *generateMessageSend(llvm::IRBuilder &Builder, |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 40 | const llvm::Type *ReturnTy, |
| 41 | llvm::Value *Sender, |
| 42 | llvm::Value *Receiver, |
| 43 | llvm::Value *Selector, |
| 44 | llvm::Value** ArgV, |
| 45 | unsigned ArgC); |
Chris Lattner | 50b3674 | 2008-04-13 07:32:11 +0000 | [diff] [blame] | 46 | llvm::Value *getSelector(llvm::IRBuilder &Builder, |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 47 | llvm::Value *SelName, |
| 48 | llvm::Value *SelTypes); |
| 49 | virtual llvm::Function *MethodPreamble(const llvm::Type *ReturnTy, |
| 50 | const llvm::Type *SelfTy, |
| 51 | const llvm::Type **ArgTy, |
| 52 | unsigned ArgC, |
| 53 | bool isVarArg); |
| 54 | }; |
| 55 | } // end anonymous namespace |
| 56 | |
| 57 | CGObjCEtoile::CGObjCEtoile(llvm::Module &M, |
| 58 | const llvm::Type *LLVMIntType, |
| 59 | const llvm::Type *LLVMLongType) : |
| 60 | TheModule(M), |
| 61 | IntTy(LLVMIntType), |
| 62 | LongTy(LLVMLongType) |
| 63 | { |
| 64 | // C string type. Used in lots of places. |
| 65 | PtrToInt8Ty = |
| 66 | llvm::PointerType::getUnqual(llvm::Type::Int8Ty); |
| 67 | // Get the selector Type. |
| 68 | SelectorTy = llvm::Type::Int32Ty; |
| 69 | PtrToIntTy = llvm::PointerType::getUnqual(IntTy); |
| 70 | PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); |
| 71 | |
| 72 | // Object type |
Chris Lattner | 72858c9 | 2008-04-04 15:59:59 +0000 | [diff] [blame] | 73 | llvm::PATypeHolder OpaqueObjTy = llvm::OpaqueType::get(); |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 74 | llvm::Type *OpaqueIdTy = llvm::PointerType::getUnqual(OpaqueObjTy); |
Chris Lattner | 72858c9 | 2008-04-04 15:59:59 +0000 | [diff] [blame] | 75 | IdTy = llvm::StructType::get(OpaqueIdTy, NULL); |
| 76 | llvm::cast<llvm::OpaqueType>(OpaqueObjTy.get())->refineAbstractTypeTo(IdTy); |
| 77 | IdTy = llvm::cast<llvm::StructType>(OpaqueObjTy.get()); |
| 78 | IdTy = llvm::PointerType::getUnqual(IdTy); |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 79 | |
| 80 | // Call structure type. |
Chris Lattner | 72858c9 | 2008-04-04 15:59:59 +0000 | [diff] [blame] | 81 | llvm::PATypeHolder OpaqueSlotTy = llvm::OpaqueType::get(); |
| 82 | CallTy = llvm::StructType::get( |
| 83 | llvm::PointerType::getUnqual(OpaqueSlotTy), |
| 84 | SelectorTy, |
| 85 | IdTy, |
| 86 | NULL); |
| 87 | //CallTy = llvm::PointerType::getUnqual(CallTy); |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 88 | |
| 89 | // IMP type |
| 90 | std::vector<const llvm::Type*> IMPArgs; |
| 91 | IMPArgs.push_back(IdTy); |
| 92 | IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy)); |
| 93 | IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true); |
| 94 | |
| 95 | // Slot type |
Chris Lattner | 72858c9 | 2008-04-04 15:59:59 +0000 | [diff] [blame] | 96 | SlotTy = llvm::StructType::get(IntTy, |
| 97 | IMPTy, |
| 98 | PtrToInt8Ty, |
| 99 | PtrToInt8Ty, |
| 100 | llvm::Type::Int32Ty, |
| 101 | NULL); |
| 102 | llvm::cast<llvm::OpaqueType>( |
| 103 | OpaqueSlotTy.get())->refineAbstractTypeTo(SlotTy); |
| 104 | SlotTy = llvm::PointerType::getUnqual( |
| 105 | llvm::cast<llvm::StructType>(OpaqueSlotTy.get())); |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 106 | |
| 107 | // Lookup function type |
| 108 | std::vector<const llvm::Type*> LookupFunctionArgs; |
| 109 | LookupFunctionArgs.push_back(llvm::PointerType::getUnqual(IdTy)); |
| 110 | LookupFunctionArgs.push_back(IdTy); |
| 111 | LookupFunctionArgs.push_back(SelectorTy); |
| 112 | LookupFunctionArgs.push_back(IdTy); |
Chris Lattner | 72858c9 | 2008-04-04 15:59:59 +0000 | [diff] [blame] | 113 | LookupFunctionTy = |
| 114 | llvm::FunctionType::get(SlotTy, LookupFunctionArgs, false); |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 115 | LookupFunctionTy = llvm::PointerType::getUnqual(LookupFunctionTy); |
| 116 | |
| 117 | } |
| 118 | |
Chris Lattner | 72858c9 | 2008-04-04 15:59:59 +0000 | [diff] [blame] | 119 | /// Looks up the selector for the specified name / type pair. |
Chris Lattner | 50b3674 | 2008-04-13 07:32:11 +0000 | [diff] [blame] | 120 | llvm::Value *CGObjCEtoile::getSelector(llvm::IRBuilder &Builder, |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 121 | llvm::Value *SelName, |
| 122 | llvm::Value *SelTypes) |
| 123 | { |
| 124 | // Look up the selector. |
| 125 | if(SelTypes == 0) { |
| 126 | SelTypes = llvm::ConstantPointerNull::get(PtrToInt8Ty); |
| 127 | } |
| 128 | llvm::Constant *SelFunction = |
Chris Lattner | 72858c9 | 2008-04-04 15:59:59 +0000 | [diff] [blame] | 129 | TheModule.getOrInsertFunction("lookup_typed_selector", |
| 130 | SelectorTy, |
| 131 | PtrToInt8Ty, |
| 132 | PtrToInt8Ty, |
| 133 | NULL); |
Chris Lattner | 3eae03e | 2008-05-06 00:56:42 +0000 | [diff] [blame] | 134 | return Builder.CreateCall2(SelFunction, SelName, SelTypes); |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 135 | } |
| 136 | |
Chris Lattner | 50b3674 | 2008-04-13 07:32:11 +0000 | [diff] [blame] | 137 | static void SetField(llvm::IRBuilder &Builder, llvm::Value *Structure, |
| 138 | unsigned Index, llvm::Value *Value) { |
Chris Lattner | 72858c9 | 2008-04-04 15:59:59 +0000 | [diff] [blame] | 139 | llvm::Value *element_ptr = Builder.CreateStructGEP(Structure, Index); |
| 140 | Builder.CreateStore(Value, element_ptr); |
| 141 | } |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 142 | // Generate code for a message send expression on the Etoile runtime. |
| 143 | // BIG FAT WARNING: Much of this code will need factoring out later. |
Chris Lattner | 50b3674 | 2008-04-13 07:32:11 +0000 | [diff] [blame] | 144 | llvm::Value *CGObjCEtoile::generateMessageSend(llvm::IRBuilder &Builder, |
| 145 | const llvm::Type *ReturnTy, |
| 146 | llvm::Value *Sender, |
| 147 | llvm::Value *Receiver, |
| 148 | llvm::Value *Selector, |
| 149 | llvm::Value** ArgV, |
| 150 | unsigned ArgC) { |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 151 | // FIXME: Selectors should be statically cached, not looked up on every call. |
| 152 | llvm::Value *cmd = getSelector(Builder, Selector, 0); |
| 153 | // TODO: [Polymorphic] inline caching |
| 154 | |
| 155 | // Get the lookup function for this object: |
| 156 | llvm::Value *ObjAddr = Builder.CreateBitCast(Receiver, PtrToInt8Ty); |
| 157 | llvm::Value *FunctionOffset = new llvm::GlobalVariable(llvm::Type::Int32Ty, |
| 158 | false, |
| 159 | llvm::GlobalValue::ExternalLinkage, |
| 160 | 0, |
| 161 | "lookup_offset", |
| 162 | &TheModule); |
| 163 | FunctionOffset = Builder.CreateLoad(FunctionOffset); |
| 164 | llvm::Value *Tag = Builder.CreateGEP(ObjAddr, FunctionOffset); |
| 165 | llvm::Value *Lookup = Builder.CreateBitCast(Tag, LookupFunctionTy); |
| 166 | |
| 167 | // TODO: Remove this when the caller is providing sensible sender info |
| 168 | if(Sender == 0) { |
| 169 | Sender = llvm::ConstantPointerNull::get((llvm::PointerType*)IdTy); |
| 170 | } |
| 171 | Receiver = Builder.CreateBitCast(Receiver, IdTy); |
| 172 | llvm::Value *ReceiverAddr = Builder.CreateAlloca(IdTy); |
| 173 | Builder.CreateStore(Receiver, ReceiverAddr); |
| 174 | // Look up the method implementation. |
| 175 | llvm::SmallVector<llvm::Value*, 4> LookupArgs; |
| 176 | LookupArgs.push_back(ReceiverAddr); |
| 177 | LookupArgs.push_back(Receiver); |
| 178 | LookupArgs.push_back(cmd); |
| 179 | LookupArgs.push_back(Sender); |
Chris Lattner | 3eae03e | 2008-05-06 00:56:42 +0000 | [diff] [blame] | 180 | llvm::Value *Slot = Builder.CreateCall(Lookup, LookupArgs.begin(), |
| 181 | LookupArgs.end()); |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 182 | |
| 183 | // Create the call structure |
| 184 | llvm::Value *Call = Builder.CreateAlloca(CallTy); |
Chris Lattner | 72858c9 | 2008-04-04 15:59:59 +0000 | [diff] [blame] | 185 | SetField(Builder, Call, 0, Slot); |
| 186 | SetField(Builder, Call, 1, cmd); |
| 187 | SetField(Builder, Call, 2, Sender); |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 188 | |
| 189 | // Get the IMP from the slot and call it |
| 190 | // TODO: Property load / store optimisations |
| 191 | llvm::Value *IMP = Builder.CreateStructGEP(Slot, 1); |
| 192 | // If the return type of the IMP is wrong, cast it so it isn't. |
| 193 | if(ReturnTy != IdTy) { |
| 194 | std::vector<const llvm::Type*> IMPArgs; |
| 195 | IMPArgs.push_back(IdTy); |
| 196 | IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy)); |
| 197 | llvm::Type *NewIMPTy = llvm::FunctionType::get(ReturnTy, IMPArgs, true); |
| 198 | IMP = Builder.CreateBitCast(IMP, llvm::PointerType::getUnqual(NewIMPTy)); |
| 199 | } |
| 200 | llvm::SmallVector<llvm::Value*, 16> Args; |
| 201 | Args.push_back(Receiver); |
| 202 | Args.push_back(Call); |
| 203 | Args.insert(Args.end(), ArgV, ArgV+ArgC); |
| 204 | return Builder.CreateCall(IMP, Args.begin(), Args.end()); |
| 205 | } |
| 206 | |
Chris Lattner | 72858c9 | 2008-04-04 15:59:59 +0000 | [diff] [blame] | 207 | /// Generates an LLVM Function object corresponding to the Objective-C method, |
| 208 | /// including the implicit arguments. |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 209 | llvm::Function *CGObjCEtoile::MethodPreamble( |
| 210 | const llvm::Type *ReturnTy, |
| 211 | const llvm::Type *SelfTy, |
| 212 | const llvm::Type **ArgTy, |
| 213 | unsigned ArgC, |
| 214 | bool isVarArg) { |
| 215 | std::vector<const llvm::Type*> Args; |
| 216 | //Args.push_back(SelfTy); |
| 217 | Args.push_back(IdTy); |
| 218 | Args.push_back(llvm::PointerType::getUnqual(CallTy)); |
| 219 | for (unsigned i=0; i<ArgC ; i++) { |
| 220 | Args.push_back(ArgTy[i]); |
| 221 | } |
Chris Lattner | 72858c9 | 2008-04-04 15:59:59 +0000 | [diff] [blame] | 222 | llvm::FunctionType *MethodTy = |
| 223 | llvm::FunctionType::get(ReturnTy, Args, isVarArg); |
Gabor Greif | 984d0b4 | 2008-04-06 20:42:52 +0000 | [diff] [blame] | 224 | llvm::Function *Method = llvm::Function::Create(MethodTy, |
Chris Lattner | 7ba9c60 | 2008-04-04 15:45:52 +0000 | [diff] [blame] | 225 | llvm::GlobalValue::InternalLinkage, |
| 226 | ".objc.method", |
| 227 | &TheModule); |
| 228 | //llvm::BasicBlock *EntryBB = new llvm::BasicBlock("entry", Method); |
| 229 | // Set the names of the hidden arguments |
| 230 | llvm::Function::arg_iterator AI = Method->arg_begin(); |
| 231 | AI[0].setName("self"); |
| 232 | AI[1].setName("_call"); |
| 233 | // FIXME: Should create the _cmd variable as _call->selector |
| 234 | return Method; |
| 235 | } |
| 236 | |
| 237 | /* |
| 238 | clang::CodeGen::CGObjCRuntime *clang::CodeGen::CreateObjCRuntime( |
| 239 | llvm::Module &M, |
| 240 | const llvm::Type *LLVMIntType, |
| 241 | const llvm::Type *LLVMLongType) { |
| 242 | return new CGObjCEtoile(M, LLVMIntType, LLVMLongType); |
| 243 | } |
| 244 | */ |