blob: efd5fac3293c2cdf5d2faaf140a62d805e9ee564 [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"
17#include "llvm/Support/LLVMBuilder.h"
18#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);
39 virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
40 const llvm::Type *ReturnTy,
41 llvm::Value *Sender,
42 llvm::Value *Receiver,
43 llvm::Value *Selector,
44 llvm::Value** ArgV,
45 unsigned ArgC);
46 llvm::Value *getSelector(llvm::LLVMFoldingBuilder &Builder,
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
57CGObjCEtoile::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 Lattner72858c92008-04-04 15:59:59 +000073 llvm::PATypeHolder OpaqueObjTy = llvm::OpaqueType::get();
Chris Lattner7ba9c602008-04-04 15:45:52 +000074 llvm::Type *OpaqueIdTy = llvm::PointerType::getUnqual(OpaqueObjTy);
Chris Lattner72858c92008-04-04 15:59:59 +000075 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 Lattner7ba9c602008-04-04 15:45:52 +000079
80 // Call structure type.
Chris Lattner72858c92008-04-04 15:59:59 +000081 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 Lattner7ba9c602008-04-04 15:45:52 +000088
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 Lattner72858c92008-04-04 15:59:59 +000096 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 Lattner7ba9c602008-04-04 15:45:52 +0000106
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 Lattner72858c92008-04-04 15:59:59 +0000113 LookupFunctionTy =
114 llvm::FunctionType::get(SlotTy, LookupFunctionArgs, false);
Chris Lattner7ba9c602008-04-04 15:45:52 +0000115 LookupFunctionTy = llvm::PointerType::getUnqual(LookupFunctionTy);
116
117}
118
Chris Lattner72858c92008-04-04 15:59:59 +0000119/// Looks up the selector for the specified name / type pair.
Chris Lattner7ba9c602008-04-04 15:45:52 +0000120llvm::Value *CGObjCEtoile::getSelector(llvm::LLVMFoldingBuilder &Builder,
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 Lattner72858c92008-04-04 15:59:59 +0000129 TheModule.getOrInsertFunction("lookup_typed_selector",
130 SelectorTy,
131 PtrToInt8Ty,
132 PtrToInt8Ty,
133 NULL);
Chris Lattner7ba9c602008-04-04 15:45:52 +0000134 llvm::SmallVector<llvm::Value*, 2> Args;
135 Args.push_back(SelName);
136 Args.push_back(SelTypes);
137 return Builder.CreateCall(SelFunction, Args.begin(), Args.end());
138}
139
Chris Lattner72858c92008-04-04 15:59:59 +0000140static void SetField(llvm::LLVMFoldingBuilder &Builder,
141 llvm::Value *Structure,
142 unsigned Index,
143 llvm::Value *Value) {
144 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 Lattner72858c92008-04-04 15:59:59 +0000149llvm::Value *CGObjCEtoile::generateMessageSend(
150 llvm::LLVMFoldingBuilder &Builder,
Chris Lattner7ba9c602008-04-04 15:45:52 +0000151 const llvm::Type *ReturnTy,
152 llvm::Value *Sender,
153 llvm::Value *Receiver,
154 llvm::Value *Selector,
155 llvm::Value** ArgV,
156 unsigned ArgC) {
157 // FIXME: Selectors should be statically cached, not looked up on every call.
158 llvm::Value *cmd = getSelector(Builder, Selector, 0);
159 // TODO: [Polymorphic] inline caching
160
161 // Get the lookup function for this object:
162 llvm::Value *ObjAddr = Builder.CreateBitCast(Receiver, PtrToInt8Ty);
163 llvm::Value *FunctionOffset = new llvm::GlobalVariable(llvm::Type::Int32Ty,
164 false,
165 llvm::GlobalValue::ExternalLinkage,
166 0,
167 "lookup_offset",
168 &TheModule);
169 FunctionOffset = Builder.CreateLoad(FunctionOffset);
170 llvm::Value *Tag = Builder.CreateGEP(ObjAddr, FunctionOffset);
171 llvm::Value *Lookup = Builder.CreateBitCast(Tag, LookupFunctionTy);
172
173 // TODO: Remove this when the caller is providing sensible sender info
174 if(Sender == 0) {
175 Sender = llvm::ConstantPointerNull::get((llvm::PointerType*)IdTy);
176 }
177 Receiver = Builder.CreateBitCast(Receiver, IdTy);
178 llvm::Value *ReceiverAddr = Builder.CreateAlloca(IdTy);
179 Builder.CreateStore(Receiver, ReceiverAddr);
180 // Look up the method implementation.
181 llvm::SmallVector<llvm::Value*, 4> LookupArgs;
182 LookupArgs.push_back(ReceiverAddr);
183 LookupArgs.push_back(Receiver);
184 LookupArgs.push_back(cmd);
185 LookupArgs.push_back(Sender);
186 llvm::Value *Slot = Builder.CreateCall(Lookup,
187 LookupArgs.begin(),
188 LookupArgs.end());
189
190 // Create the call structure
191 llvm::Value *Call = Builder.CreateAlloca(CallTy);
Chris Lattner72858c92008-04-04 15:59:59 +0000192 SetField(Builder, Call, 0, Slot);
193 SetField(Builder, Call, 1, cmd);
194 SetField(Builder, Call, 2, Sender);
Chris Lattner7ba9c602008-04-04 15:45:52 +0000195
196 // Get the IMP from the slot and call it
197 // TODO: Property load / store optimisations
198 llvm::Value *IMP = Builder.CreateStructGEP(Slot, 1);
199 // If the return type of the IMP is wrong, cast it so it isn't.
200 if(ReturnTy != IdTy) {
201 std::vector<const llvm::Type*> IMPArgs;
202 IMPArgs.push_back(IdTy);
203 IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy));
204 llvm::Type *NewIMPTy = llvm::FunctionType::get(ReturnTy, IMPArgs, true);
205 IMP = Builder.CreateBitCast(IMP, llvm::PointerType::getUnqual(NewIMPTy));
206 }
207 llvm::SmallVector<llvm::Value*, 16> Args;
208 Args.push_back(Receiver);
209 Args.push_back(Call);
210 Args.insert(Args.end(), ArgV, ArgV+ArgC);
211 return Builder.CreateCall(IMP, Args.begin(), Args.end());
212}
213
Chris Lattner72858c92008-04-04 15:59:59 +0000214/// Generates an LLVM Function object corresponding to the Objective-C method,
215/// including the implicit arguments.
Chris Lattner7ba9c602008-04-04 15:45:52 +0000216llvm::Function *CGObjCEtoile::MethodPreamble(
217 const llvm::Type *ReturnTy,
218 const llvm::Type *SelfTy,
219 const llvm::Type **ArgTy,
220 unsigned ArgC,
221 bool isVarArg) {
222 std::vector<const llvm::Type*> Args;
223 //Args.push_back(SelfTy);
224 Args.push_back(IdTy);
225 Args.push_back(llvm::PointerType::getUnqual(CallTy));
226 for (unsigned i=0; i<ArgC ; i++) {
227 Args.push_back(ArgTy[i]);
228 }
Chris Lattner72858c92008-04-04 15:59:59 +0000229 llvm::FunctionType *MethodTy =
230 llvm::FunctionType::get(ReturnTy, Args, isVarArg);
Gabor Greif984d0b42008-04-06 20:42:52 +0000231 llvm::Function *Method = llvm::Function::Create(MethodTy,
Chris Lattner7ba9c602008-04-04 15:45:52 +0000232 llvm::GlobalValue::InternalLinkage,
233 ".objc.method",
234 &TheModule);
235 //llvm::BasicBlock *EntryBB = new llvm::BasicBlock("entry", Method);
236 // Set the names of the hidden arguments
237 llvm::Function::arg_iterator AI = Method->arg_begin();
238 AI[0].setName("self");
239 AI[1].setName("_call");
240 // FIXME: Should create the _cmd variable as _call->selector
241 return Method;
242}
243
244/*
245clang::CodeGen::CGObjCRuntime *clang::CodeGen::CreateObjCRuntime(
246 llvm::Module &M,
247 const llvm::Type *LLVMIntType,
248 const llvm::Type *LLVMLongType) {
249 return new CGObjCEtoile(M, LLVMIntType, LLVMLongType);
250}
251*/