blob: 94471ad4df906a331c35abc23dcf6deb301f9915 [file] [log] [blame]
Chris Lattner7ba9c602008-04-04 15:45:52 +00001//===------- 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 Lattner7ba9c602008-04-04 15:45:52 +000014#include "CGObjCRuntime.h"
15#include "llvm/Module.h"
16#include "llvm/Support/Compiler.h"
Chris Lattner50b36742008-04-13 07:32:11 +000017#include "llvm/Support/IRBuilder.h"
Chris Lattner7ba9c602008-04-04 15:45:52 +000018#include "llvm/ADT/SmallVector.h"
19
Chris Lattner7ba9c602008-04-04 15:45:52 +000020namespace {
21class CGObjCEtoile : public clang::CodeGen::CGObjCRuntime {
22private:
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;
35public:
36 CGObjCEtoile(llvm::Module &Mp,
37 const llvm::Type *LLVMIntType,
38 const llvm::Type *LLVMLongType);
Chris Lattner50b36742008-04-13 07:32:11 +000039 virtual llvm::Value *generateMessageSend(llvm::IRBuilder &Builder,
Chris Lattner7ba9c602008-04-04 15:45:52 +000040 const llvm::Type *ReturnTy,
41 llvm::Value *Sender,
42 llvm::Value *Receiver,
43 llvm::Value *Selector,
44 llvm::Value** ArgV,
45 unsigned ArgC);
Chris Lattner50b36742008-04-13 07:32:11 +000046 llvm::Value *getSelector(llvm::IRBuilder &Builder,
Chris Lattner7ba9c602008-04-04 15:45:52 +000047 llvm::Value *SelName,
48 llvm::Value *SelTypes);
Anton Korobeynikov20ff3102008-06-01 14:13:53 +000049 virtual llvm::Function *MethodPreamble(
50 const std::string &ClassName,
51 const std::string &CategoryName,
52 const std::string &MethodName,
53 const llvm::Type *ReturnTy,
Chris Lattner7ba9c602008-04-04 15:45:52 +000054 const llvm::Type *SelfTy,
55 const llvm::Type **ArgTy,
56 unsigned ArgC,
Anton Korobeynikov20ff3102008-06-01 14:13:53 +000057 bool isClassMethod,
Chris Lattner7ba9c602008-04-04 15:45:52 +000058 bool isVarArg);
59};
60} // end anonymous namespace
61
62CGObjCEtoile::CGObjCEtoile(llvm::Module &M,
63 const llvm::Type *LLVMIntType,
64 const llvm::Type *LLVMLongType) :
65 TheModule(M),
66 IntTy(LLVMIntType),
67 LongTy(LLVMLongType)
68{
69 // C string type. Used in lots of places.
70 PtrToInt8Ty =
71 llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
72 // Get the selector Type.
73 SelectorTy = llvm::Type::Int32Ty;
74 PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
75 PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
76
77 // Object type
Chris Lattner72858c92008-04-04 15:59:59 +000078 llvm::PATypeHolder OpaqueObjTy = llvm::OpaqueType::get();
Chris Lattner7ba9c602008-04-04 15:45:52 +000079 llvm::Type *OpaqueIdTy = llvm::PointerType::getUnqual(OpaqueObjTy);
Chris Lattner72858c92008-04-04 15:59:59 +000080 IdTy = llvm::StructType::get(OpaqueIdTy, NULL);
81 llvm::cast<llvm::OpaqueType>(OpaqueObjTy.get())->refineAbstractTypeTo(IdTy);
82 IdTy = llvm::cast<llvm::StructType>(OpaqueObjTy.get());
83 IdTy = llvm::PointerType::getUnqual(IdTy);
Chris Lattner7ba9c602008-04-04 15:45:52 +000084
85 // Call structure type.
Chris Lattner72858c92008-04-04 15:59:59 +000086 llvm::PATypeHolder OpaqueSlotTy = llvm::OpaqueType::get();
87 CallTy = llvm::StructType::get(
88 llvm::PointerType::getUnqual(OpaqueSlotTy),
89 SelectorTy,
90 IdTy,
91 NULL);
92 //CallTy = llvm::PointerType::getUnqual(CallTy);
Chris Lattner7ba9c602008-04-04 15:45:52 +000093
94 // IMP type
95 std::vector<const llvm::Type*> IMPArgs;
96 IMPArgs.push_back(IdTy);
97 IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy));
98 IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
99
100 // Slot type
Chris Lattner72858c92008-04-04 15:59:59 +0000101 SlotTy = llvm::StructType::get(IntTy,
102 IMPTy,
103 PtrToInt8Ty,
104 PtrToInt8Ty,
105 llvm::Type::Int32Ty,
106 NULL);
107 llvm::cast<llvm::OpaqueType>(
108 OpaqueSlotTy.get())->refineAbstractTypeTo(SlotTy);
109 SlotTy = llvm::PointerType::getUnqual(
110 llvm::cast<llvm::StructType>(OpaqueSlotTy.get()));
Chris Lattner7ba9c602008-04-04 15:45:52 +0000111
112 // Lookup function type
113 std::vector<const llvm::Type*> LookupFunctionArgs;
114 LookupFunctionArgs.push_back(llvm::PointerType::getUnqual(IdTy));
115 LookupFunctionArgs.push_back(IdTy);
116 LookupFunctionArgs.push_back(SelectorTy);
117 LookupFunctionArgs.push_back(IdTy);
Chris Lattner72858c92008-04-04 15:59:59 +0000118 LookupFunctionTy =
119 llvm::FunctionType::get(SlotTy, LookupFunctionArgs, false);
Chris Lattner7ba9c602008-04-04 15:45:52 +0000120 LookupFunctionTy = llvm::PointerType::getUnqual(LookupFunctionTy);
121
122}
123
Chris Lattner72858c92008-04-04 15:59:59 +0000124/// Looks up the selector for the specified name / type pair.
Chris Lattner50b36742008-04-13 07:32:11 +0000125llvm::Value *CGObjCEtoile::getSelector(llvm::IRBuilder &Builder,
Chris Lattner7ba9c602008-04-04 15:45:52 +0000126 llvm::Value *SelName,
127 llvm::Value *SelTypes)
128{
129 // Look up the selector.
130 if(SelTypes == 0) {
131 SelTypes = llvm::ConstantPointerNull::get(PtrToInt8Ty);
132 }
133 llvm::Constant *SelFunction =
Chris Lattner72858c92008-04-04 15:59:59 +0000134 TheModule.getOrInsertFunction("lookup_typed_selector",
135 SelectorTy,
136 PtrToInt8Ty,
137 PtrToInt8Ty,
138 NULL);
Chris Lattner3eae03e2008-05-06 00:56:42 +0000139 return Builder.CreateCall2(SelFunction, SelName, SelTypes);
Chris Lattner7ba9c602008-04-04 15:45:52 +0000140}
141
Chris Lattner50b36742008-04-13 07:32:11 +0000142static void SetField(llvm::IRBuilder &Builder, llvm::Value *Structure,
143 unsigned Index, llvm::Value *Value) {
Chris Lattner72858c92008-04-04 15:59:59 +0000144 llvm::Value *element_ptr = Builder.CreateStructGEP(Structure, Index);
145 Builder.CreateStore(Value, element_ptr);
146}
Chris Lattner7ba9c602008-04-04 15:45:52 +0000147// Generate code for a message send expression on the Etoile runtime.
148// BIG FAT WARNING: Much of this code will need factoring out later.
Chris Lattner50b36742008-04-13 07:32:11 +0000149llvm::Value *CGObjCEtoile::generateMessageSend(llvm::IRBuilder &Builder,
150 const llvm::Type *ReturnTy,
151 llvm::Value *Sender,
152 llvm::Value *Receiver,
153 llvm::Value *Selector,
154 llvm::Value** ArgV,
155 unsigned ArgC) {
Chris Lattner7ba9c602008-04-04 15:45:52 +0000156 // FIXME: Selectors should be statically cached, not looked up on every call.
157 llvm::Value *cmd = getSelector(Builder, Selector, 0);
158 // TODO: [Polymorphic] inline caching
159
160 // Get the lookup function for this object:
161 llvm::Value *ObjAddr = Builder.CreateBitCast(Receiver, PtrToInt8Ty);
162 llvm::Value *FunctionOffset = new llvm::GlobalVariable(llvm::Type::Int32Ty,
163 false,
164 llvm::GlobalValue::ExternalLinkage,
165 0,
166 "lookup_offset",
167 &TheModule);
168 FunctionOffset = Builder.CreateLoad(FunctionOffset);
169 llvm::Value *Tag = Builder.CreateGEP(ObjAddr, FunctionOffset);
170 llvm::Value *Lookup = Builder.CreateBitCast(Tag, LookupFunctionTy);
171
172 // TODO: Remove this when the caller is providing sensible sender info
173 if(Sender == 0) {
174 Sender = llvm::ConstantPointerNull::get((llvm::PointerType*)IdTy);
175 }
176 Receiver = Builder.CreateBitCast(Receiver, IdTy);
177 llvm::Value *ReceiverAddr = Builder.CreateAlloca(IdTy);
178 Builder.CreateStore(Receiver, ReceiverAddr);
179 // Look up the method implementation.
180 llvm::SmallVector<llvm::Value*, 4> LookupArgs;
181 LookupArgs.push_back(ReceiverAddr);
182 LookupArgs.push_back(Receiver);
183 LookupArgs.push_back(cmd);
184 LookupArgs.push_back(Sender);
Chris Lattner3eae03e2008-05-06 00:56:42 +0000185 llvm::Value *Slot = Builder.CreateCall(Lookup, LookupArgs.begin(),
186 LookupArgs.end());
Chris Lattner7ba9c602008-04-04 15:45:52 +0000187
188 // Create the call structure
189 llvm::Value *Call = Builder.CreateAlloca(CallTy);
Chris Lattner72858c92008-04-04 15:59:59 +0000190 SetField(Builder, Call, 0, Slot);
191 SetField(Builder, Call, 1, cmd);
192 SetField(Builder, Call, 2, Sender);
Chris Lattner7ba9c602008-04-04 15:45:52 +0000193
194 // Get the IMP from the slot and call it
195 // TODO: Property load / store optimisations
196 llvm::Value *IMP = Builder.CreateStructGEP(Slot, 1);
197 // If the return type of the IMP is wrong, cast it so it isn't.
198 if(ReturnTy != IdTy) {
199 std::vector<const llvm::Type*> IMPArgs;
200 IMPArgs.push_back(IdTy);
201 IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy));
202 llvm::Type *NewIMPTy = llvm::FunctionType::get(ReturnTy, IMPArgs, true);
203 IMP = Builder.CreateBitCast(IMP, llvm::PointerType::getUnqual(NewIMPTy));
204 }
205 llvm::SmallVector<llvm::Value*, 16> Args;
206 Args.push_back(Receiver);
207 Args.push_back(Call);
208 Args.insert(Args.end(), ArgV, ArgV+ArgC);
209 return Builder.CreateCall(IMP, Args.begin(), Args.end());
210}
211
Chris Lattner72858c92008-04-04 15:59:59 +0000212/// Generates an LLVM Function object corresponding to the Objective-C method,
213/// including the implicit arguments.
Chris Lattner7ba9c602008-04-04 15:45:52 +0000214llvm::Function *CGObjCEtoile::MethodPreamble(
Anton Korobeynikov20ff3102008-06-01 14:13:53 +0000215 const std::string &ClassName,
216 const std::string &CategoryName,
217 const std::string &MethodName,
Chris Lattner7ba9c602008-04-04 15:45:52 +0000218 const llvm::Type *ReturnTy,
219 const llvm::Type *SelfTy,
220 const llvm::Type **ArgTy,
221 unsigned ArgC,
Anton Korobeynikov20ff3102008-06-01 14:13:53 +0000222 bool isClassMethod,
Chris Lattner7ba9c602008-04-04 15:45:52 +0000223 bool isVarArg) {
224 std::vector<const llvm::Type*> Args;
225 //Args.push_back(SelfTy);
226 Args.push_back(IdTy);
227 Args.push_back(llvm::PointerType::getUnqual(CallTy));
228 for (unsigned i=0; i<ArgC ; i++) {
229 Args.push_back(ArgTy[i]);
230 }
Chris Lattner72858c92008-04-04 15:59:59 +0000231 llvm::FunctionType *MethodTy =
232 llvm::FunctionType::get(ReturnTy, Args, isVarArg);
Gabor Greif984d0b42008-04-06 20:42:52 +0000233 llvm::Function *Method = llvm::Function::Create(MethodTy,
Chris Lattner7ba9c602008-04-04 15:45:52 +0000234 llvm::GlobalValue::InternalLinkage,
235 ".objc.method",
236 &TheModule);
237 //llvm::BasicBlock *EntryBB = new llvm::BasicBlock("entry", Method);
238 // Set the names of the hidden arguments
239 llvm::Function::arg_iterator AI = Method->arg_begin();
240 AI[0].setName("self");
241 AI[1].setName("_call");
242 // FIXME: Should create the _cmd variable as _call->selector
243 return Method;
244}
245
246/*
247clang::CodeGen::CGObjCRuntime *clang::CodeGen::CreateObjCRuntime(
248 llvm::Module &M,
249 const llvm::Type *LLVMIntType,
250 const llvm::Type *LLVMLongType) {
251 return new CGObjCEtoile(M, LLVMIntType, LLVMLongType);
252}
253*/