blob: b92418a9189645f39269987ebb9049da43ce18d7 [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
14#include <stdarg.h>
15#include "CGObjCRuntime.h"
16#include "llvm/Module.h"
17#include "llvm/Support/Compiler.h"
18#include "llvm/Support/LLVMBuilder.h"
19#include "llvm/ADT/SmallVector.h"
20
21
22clang::CodeGen::CGObjCRuntime::~CGObjCRuntime() {}
23
24namespace {
25class CGObjCEtoile : public clang::CodeGen::CGObjCRuntime {
26private:
27 llvm::Module &TheModule;
28 const llvm::Type *SelectorTy;
29 const llvm::PointerType *PtrToInt8Ty;
30 const llvm::Type *IMPTy;
31 const llvm::Type *IntTy;
32 const llvm::Type *PtrTy;
33 const llvm::Type *LongTy;
34 const llvm::Type *PtrToIntTy;
35 const llvm::Type *IdTy;
36 const llvm::Type *CallTy;
37 const llvm::Type *SlotTy;
38 const llvm::Type *LookupFunctionTy;
39public:
40 CGObjCEtoile(llvm::Module &Mp,
41 const llvm::Type *LLVMIntType,
42 const llvm::Type *LLVMLongType);
43 virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
44 const llvm::Type *ReturnTy,
45 llvm::Value *Sender,
46 llvm::Value *Receiver,
47 llvm::Value *Selector,
48 llvm::Value** ArgV,
49 unsigned ArgC);
50 llvm::Value *getSelector(llvm::LLVMFoldingBuilder &Builder,
51 llvm::Value *SelName,
52 llvm::Value *SelTypes);
53 virtual llvm::Function *MethodPreamble(const llvm::Type *ReturnTy,
54 const llvm::Type *SelfTy,
55 const llvm::Type **ArgTy,
56 unsigned ArgC,
57 bool isVarArg);
58};
59} // end anonymous namespace
60
61CGObjCEtoile::CGObjCEtoile(llvm::Module &M,
62 const llvm::Type *LLVMIntType,
63 const llvm::Type *LLVMLongType) :
64 TheModule(M),
65 IntTy(LLVMIntType),
66 LongTy(LLVMLongType)
67{
68 // C string type. Used in lots of places.
69 PtrToInt8Ty =
70 llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
71 // Get the selector Type.
72 SelectorTy = llvm::Type::Int32Ty;
73 PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
74 PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
75
76 // Object type
77 llvm::OpaqueType *OpaqueObjTy = llvm::OpaqueType::get();
78 llvm::Type *OpaqueIdTy = llvm::PointerType::getUnqual(OpaqueObjTy);
79 IdTy = llvm::PointerType::getUnqual(llvm::StructType::get(OpaqueIdTy, 0));
80 OpaqueObjTy->refineAbstractTypeTo(IdTy);
81
82 // Call structure type.
83 llvm::OpaqueType *OpaqueSlotTy = llvm::OpaqueType::get();
84 CallTy = llvm::StructType::get(llvm::PointerType::getUnqual(OpaqueSlotTy),
85 SelectorTy,
86 IdTy,
87 0);
88 //CallTy = llvm::PointerType::getUnqual(CallTy);
89
90 // IMP type
91 std::vector<const llvm::Type*> IMPArgs;
92 IMPArgs.push_back(IdTy);
93 IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy));
94 IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
95
96 // Slot type
97 SlotTy = llvm::StructType::get(IntTy,
98 IMPTy,
99 PtrToInt8Ty,
100 PtrToInt8Ty,
101 llvm::Type::Int32Ty,
102 0);
103 OpaqueSlotTy->refineAbstractTypeTo(SlotTy);
104 SlotTy = llvm::PointerType::getUnqual(SlotTy);
105
106 // Lookup function type
107 std::vector<const llvm::Type*> LookupFunctionArgs;
108 LookupFunctionArgs.push_back(llvm::PointerType::getUnqual(IdTy));
109 LookupFunctionArgs.push_back(IdTy);
110 LookupFunctionArgs.push_back(SelectorTy);
111 LookupFunctionArgs.push_back(IdTy);
112 LookupFunctionTy = llvm::FunctionType::get(SlotTy, LookupFunctionArgs, false);
113 LookupFunctionTy = llvm::PointerType::getUnqual(LookupFunctionTy);
114
115}
116
117// Looks up the selector for the specified name / type pair.
118llvm::Value *CGObjCEtoile::getSelector(llvm::LLVMFoldingBuilder &Builder,
119 llvm::Value *SelName,
120 llvm::Value *SelTypes)
121{
122 // Look up the selector.
123 if(SelTypes == 0) {
124 SelTypes = llvm::ConstantPointerNull::get(PtrToInt8Ty);
125 }
126 llvm::Constant *SelFunction =
127 TheModule.getOrInsertFunction("lookup_typed_selector",
128 SelectorTy,
129 PtrToInt8Ty,
130 PtrToInt8Ty,
131 0);
132 llvm::SmallVector<llvm::Value*, 2> Args;
133 Args.push_back(SelName);
134 Args.push_back(SelTypes);
135 return Builder.CreateCall(SelFunction, Args.begin(), Args.end());
136}
137
138#define SET(structure, index, value) do {\
139 llvm::Value *element_ptr = Builder.CreateStructGEP(structure, index);\
140 Builder.CreateStore(value, element_ptr);} while(0)
141// Generate code for a message send expression on the Etoile runtime.
142// BIG FAT WARNING: Much of this code will need factoring out later.
143llvm::Value *CGObjCEtoile::generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
144 const llvm::Type *ReturnTy,
145 llvm::Value *Sender,
146 llvm::Value *Receiver,
147 llvm::Value *Selector,
148 llvm::Value** ArgV,
149 unsigned ArgC) {
150 // FIXME: Selectors should be statically cached, not looked up on every call.
151 llvm::Value *cmd = getSelector(Builder, Selector, 0);
152 // TODO: [Polymorphic] inline caching
153
154 // Get the lookup function for this object:
155 llvm::Value *ObjAddr = Builder.CreateBitCast(Receiver, PtrToInt8Ty);
156 llvm::Value *FunctionOffset = new llvm::GlobalVariable(llvm::Type::Int32Ty,
157 false,
158 llvm::GlobalValue::ExternalLinkage,
159 0,
160 "lookup_offset",
161 &TheModule);
162 FunctionOffset = Builder.CreateLoad(FunctionOffset);
163 llvm::Value *Tag = Builder.CreateGEP(ObjAddr, FunctionOffset);
164 llvm::Value *Lookup = Builder.CreateBitCast(Tag, LookupFunctionTy);
165
166 // TODO: Remove this when the caller is providing sensible sender info
167 if(Sender == 0) {
168 Sender = llvm::ConstantPointerNull::get((llvm::PointerType*)IdTy);
169 }
170 Receiver = Builder.CreateBitCast(Receiver, IdTy);
171 llvm::Value *ReceiverAddr = Builder.CreateAlloca(IdTy);
172 Builder.CreateStore(Receiver, ReceiverAddr);
173 // Look up the method implementation.
174 llvm::SmallVector<llvm::Value*, 4> LookupArgs;
175 LookupArgs.push_back(ReceiverAddr);
176 LookupArgs.push_back(Receiver);
177 LookupArgs.push_back(cmd);
178 LookupArgs.push_back(Sender);
179 llvm::Value *Slot = Builder.CreateCall(Lookup,
180 LookupArgs.begin(),
181 LookupArgs.end());
182
183 // Create the call structure
184 llvm::Value *Call = Builder.CreateAlloca(CallTy);
185 SET(Call, 0, Slot);
186 SET(Call, 1, cmd);
187 SET(Call, 2, Sender);
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
207llvm::Function *CGObjCEtoile::MethodPreamble(
208 const llvm::Type *ReturnTy,
209 const llvm::Type *SelfTy,
210 const llvm::Type **ArgTy,
211 unsigned ArgC,
212 bool isVarArg) {
213 std::vector<const llvm::Type*> Args;
214 //Args.push_back(SelfTy);
215 Args.push_back(IdTy);
216 Args.push_back(llvm::PointerType::getUnqual(CallTy));
217 for (unsigned i=0; i<ArgC ; i++) {
218 Args.push_back(ArgTy[i]);
219 }
220 llvm::FunctionType *MethodTy = llvm::FunctionType::get(ReturnTy, Args, isVarArg);
221 llvm::Function *Method = new llvm::Function(MethodTy,
222 llvm::GlobalValue::InternalLinkage,
223 ".objc.method",
224 &TheModule);
225 //llvm::BasicBlock *EntryBB = new llvm::BasicBlock("entry", Method);
226 // Set the names of the hidden arguments
227 llvm::Function::arg_iterator AI = Method->arg_begin();
228 AI[0].setName("self");
229 AI[1].setName("_call");
230 // FIXME: Should create the _cmd variable as _call->selector
231 return Method;
232}
233
234/*
235clang::CodeGen::CGObjCRuntime *clang::CodeGen::CreateObjCRuntime(
236 llvm::Module &M,
237 const llvm::Type *LLVMIntType,
238 const llvm::Type *LLVMLongType) {
239 return new CGObjCEtoile(M, LLVMIntType, LLVMLongType);
240}
241*/