blob: e2e7a67558de4e95c0fee8f56a7678d8d0987d5c [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
20
21clang::CodeGen::CGObjCRuntime::~CGObjCRuntime() {}
22
23namespace {
24class CGObjCEtoile : public clang::CodeGen::CGObjCRuntime {
25private:
26 llvm::Module &TheModule;
27 const llvm::Type *SelectorTy;
28 const llvm::PointerType *PtrToInt8Ty;
29 const llvm::Type *IMPTy;
30 const llvm::Type *IntTy;
31 const llvm::Type *PtrTy;
32 const llvm::Type *LongTy;
33 const llvm::Type *PtrToIntTy;
34 const llvm::Type *IdTy;
35 const llvm::Type *CallTy;
36 const llvm::Type *SlotTy;
37 const llvm::Type *LookupFunctionTy;
38public:
39 CGObjCEtoile(llvm::Module &Mp,
40 const llvm::Type *LLVMIntType,
41 const llvm::Type *LLVMLongType);
42 virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
43 const llvm::Type *ReturnTy,
44 llvm::Value *Sender,
45 llvm::Value *Receiver,
46 llvm::Value *Selector,
47 llvm::Value** ArgV,
48 unsigned ArgC);
49 llvm::Value *getSelector(llvm::LLVMFoldingBuilder &Builder,
50 llvm::Value *SelName,
51 llvm::Value *SelTypes);
52 virtual llvm::Function *MethodPreamble(const llvm::Type *ReturnTy,
53 const llvm::Type *SelfTy,
54 const llvm::Type **ArgTy,
55 unsigned ArgC,
56 bool isVarArg);
57};
58} // end anonymous namespace
59
60CGObjCEtoile::CGObjCEtoile(llvm::Module &M,
61 const llvm::Type *LLVMIntType,
62 const llvm::Type *LLVMLongType) :
63 TheModule(M),
64 IntTy(LLVMIntType),
65 LongTy(LLVMLongType)
66{
67 // C string type. Used in lots of places.
68 PtrToInt8Ty =
69 llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
70 // Get the selector Type.
71 SelectorTy = llvm::Type::Int32Ty;
72 PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
73 PtrTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
74
75 // Object type
Chris Lattner72858c92008-04-04 15:59:59 +000076 llvm::PATypeHolder OpaqueObjTy = llvm::OpaqueType::get();
Chris Lattner7ba9c602008-04-04 15:45:52 +000077 llvm::Type *OpaqueIdTy = llvm::PointerType::getUnqual(OpaqueObjTy);
Chris Lattner72858c92008-04-04 15:59:59 +000078 IdTy = llvm::StructType::get(OpaqueIdTy, NULL);
79 llvm::cast<llvm::OpaqueType>(OpaqueObjTy.get())->refineAbstractTypeTo(IdTy);
80 IdTy = llvm::cast<llvm::StructType>(OpaqueObjTy.get());
81 IdTy = llvm::PointerType::getUnqual(IdTy);
Chris Lattner7ba9c602008-04-04 15:45:52 +000082
83 // Call structure type.
Chris Lattner72858c92008-04-04 15:59:59 +000084 llvm::PATypeHolder OpaqueSlotTy = llvm::OpaqueType::get();
85 CallTy = llvm::StructType::get(
86 llvm::PointerType::getUnqual(OpaqueSlotTy),
87 SelectorTy,
88 IdTy,
89 NULL);
90 //CallTy = llvm::PointerType::getUnqual(CallTy);
Chris Lattner7ba9c602008-04-04 15:45:52 +000091
92 // IMP type
93 std::vector<const llvm::Type*> IMPArgs;
94 IMPArgs.push_back(IdTy);
95 IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy));
96 IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
97
98 // Slot type
Chris Lattner72858c92008-04-04 15:59:59 +000099 SlotTy = llvm::StructType::get(IntTy,
100 IMPTy,
101 PtrToInt8Ty,
102 PtrToInt8Ty,
103 llvm::Type::Int32Ty,
104 NULL);
105 llvm::cast<llvm::OpaqueType>(
106 OpaqueSlotTy.get())->refineAbstractTypeTo(SlotTy);
107 SlotTy = llvm::PointerType::getUnqual(
108 llvm::cast<llvm::StructType>(OpaqueSlotTy.get()));
Chris Lattner7ba9c602008-04-04 15:45:52 +0000109
110 // Lookup function type
111 std::vector<const llvm::Type*> LookupFunctionArgs;
112 LookupFunctionArgs.push_back(llvm::PointerType::getUnqual(IdTy));
113 LookupFunctionArgs.push_back(IdTy);
114 LookupFunctionArgs.push_back(SelectorTy);
115 LookupFunctionArgs.push_back(IdTy);
Chris Lattner72858c92008-04-04 15:59:59 +0000116 LookupFunctionTy =
117 llvm::FunctionType::get(SlotTy, LookupFunctionArgs, false);
Chris Lattner7ba9c602008-04-04 15:45:52 +0000118 LookupFunctionTy = llvm::PointerType::getUnqual(LookupFunctionTy);
119
120}
121
Chris Lattner72858c92008-04-04 15:59:59 +0000122/// Looks up the selector for the specified name / type pair.
Chris Lattner7ba9c602008-04-04 15:45:52 +0000123llvm::Value *CGObjCEtoile::getSelector(llvm::LLVMFoldingBuilder &Builder,
124 llvm::Value *SelName,
125 llvm::Value *SelTypes)
126{
127 // Look up the selector.
128 if(SelTypes == 0) {
129 SelTypes = llvm::ConstantPointerNull::get(PtrToInt8Ty);
130 }
131 llvm::Constant *SelFunction =
Chris Lattner72858c92008-04-04 15:59:59 +0000132 TheModule.getOrInsertFunction("lookup_typed_selector",
133 SelectorTy,
134 PtrToInt8Ty,
135 PtrToInt8Ty,
136 NULL);
Chris Lattner7ba9c602008-04-04 15:45:52 +0000137 llvm::SmallVector<llvm::Value*, 2> Args;
138 Args.push_back(SelName);
139 Args.push_back(SelTypes);
140 return Builder.CreateCall(SelFunction, Args.begin(), Args.end());
141}
142
Chris Lattner72858c92008-04-04 15:59:59 +0000143static void SetField(llvm::LLVMFoldingBuilder &Builder,
144 llvm::Value *Structure,
145 unsigned Index,
146 llvm::Value *Value) {
147 llvm::Value *element_ptr = Builder.CreateStructGEP(Structure, Index);
148 Builder.CreateStore(Value, element_ptr);
149}
Chris Lattner7ba9c602008-04-04 15:45:52 +0000150// Generate code for a message send expression on the Etoile runtime.
151// BIG FAT WARNING: Much of this code will need factoring out later.
Chris Lattner72858c92008-04-04 15:59:59 +0000152llvm::Value *CGObjCEtoile::generateMessageSend(
153 llvm::LLVMFoldingBuilder &Builder,
Chris Lattner7ba9c602008-04-04 15:45:52 +0000154 const llvm::Type *ReturnTy,
155 llvm::Value *Sender,
156 llvm::Value *Receiver,
157 llvm::Value *Selector,
158 llvm::Value** ArgV,
159 unsigned ArgC) {
160 // FIXME: Selectors should be statically cached, not looked up on every call.
161 llvm::Value *cmd = getSelector(Builder, Selector, 0);
162 // TODO: [Polymorphic] inline caching
163
164 // Get the lookup function for this object:
165 llvm::Value *ObjAddr = Builder.CreateBitCast(Receiver, PtrToInt8Ty);
166 llvm::Value *FunctionOffset = new llvm::GlobalVariable(llvm::Type::Int32Ty,
167 false,
168 llvm::GlobalValue::ExternalLinkage,
169 0,
170 "lookup_offset",
171 &TheModule);
172 FunctionOffset = Builder.CreateLoad(FunctionOffset);
173 llvm::Value *Tag = Builder.CreateGEP(ObjAddr, FunctionOffset);
174 llvm::Value *Lookup = Builder.CreateBitCast(Tag, LookupFunctionTy);
175
176 // TODO: Remove this when the caller is providing sensible sender info
177 if(Sender == 0) {
178 Sender = llvm::ConstantPointerNull::get((llvm::PointerType*)IdTy);
179 }
180 Receiver = Builder.CreateBitCast(Receiver, IdTy);
181 llvm::Value *ReceiverAddr = Builder.CreateAlloca(IdTy);
182 Builder.CreateStore(Receiver, ReceiverAddr);
183 // Look up the method implementation.
184 llvm::SmallVector<llvm::Value*, 4> LookupArgs;
185 LookupArgs.push_back(ReceiverAddr);
186 LookupArgs.push_back(Receiver);
187 LookupArgs.push_back(cmd);
188 LookupArgs.push_back(Sender);
189 llvm::Value *Slot = Builder.CreateCall(Lookup,
190 LookupArgs.begin(),
191 LookupArgs.end());
192
193 // Create the call structure
194 llvm::Value *Call = Builder.CreateAlloca(CallTy);
Chris Lattner72858c92008-04-04 15:59:59 +0000195 SetField(Builder, Call, 0, Slot);
196 SetField(Builder, Call, 1, cmd);
197 SetField(Builder, Call, 2, Sender);
Chris Lattner7ba9c602008-04-04 15:45:52 +0000198
199 // Get the IMP from the slot and call it
200 // TODO: Property load / store optimisations
201 llvm::Value *IMP = Builder.CreateStructGEP(Slot, 1);
202 // If the return type of the IMP is wrong, cast it so it isn't.
203 if(ReturnTy != IdTy) {
204 std::vector<const llvm::Type*> IMPArgs;
205 IMPArgs.push_back(IdTy);
206 IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy));
207 llvm::Type *NewIMPTy = llvm::FunctionType::get(ReturnTy, IMPArgs, true);
208 IMP = Builder.CreateBitCast(IMP, llvm::PointerType::getUnqual(NewIMPTy));
209 }
210 llvm::SmallVector<llvm::Value*, 16> Args;
211 Args.push_back(Receiver);
212 Args.push_back(Call);
213 Args.insert(Args.end(), ArgV, ArgV+ArgC);
214 return Builder.CreateCall(IMP, Args.begin(), Args.end());
215}
216
Chris Lattner72858c92008-04-04 15:59:59 +0000217/// Generates an LLVM Function object corresponding to the Objective-C method,
218/// including the implicit arguments.
Chris Lattner7ba9c602008-04-04 15:45:52 +0000219llvm::Function *CGObjCEtoile::MethodPreamble(
220 const llvm::Type *ReturnTy,
221 const llvm::Type *SelfTy,
222 const llvm::Type **ArgTy,
223 unsigned ArgC,
224 bool isVarArg) {
225 std::vector<const llvm::Type*> Args;
226 //Args.push_back(SelfTy);
227 Args.push_back(IdTy);
228 Args.push_back(llvm::PointerType::getUnqual(CallTy));
229 for (unsigned i=0; i<ArgC ; i++) {
230 Args.push_back(ArgTy[i]);
231 }
Chris Lattner72858c92008-04-04 15:59:59 +0000232 llvm::FunctionType *MethodTy =
233 llvm::FunctionType::get(ReturnTy, Args, isVarArg);
Chris Lattner7ba9c602008-04-04 15:45:52 +0000234 llvm::Function *Method = new llvm::Function(MethodTy,
235 llvm::GlobalValue::InternalLinkage,
236 ".objc.method",
237 &TheModule);
238 //llvm::BasicBlock *EntryBB = new llvm::BasicBlock("entry", Method);
239 // Set the names of the hidden arguments
240 llvm::Function::arg_iterator AI = Method->arg_begin();
241 AI[0].setName("self");
242 AI[1].setName("_call");
243 // FIXME: Should create the _cmd variable as _call->selector
244 return Method;
245}
246
247/*
248clang::CodeGen::CGObjCRuntime *clang::CodeGen::CreateObjCRuntime(
249 llvm::Module &M,
250 const llvm::Type *LLVMIntType,
251 const llvm::Type *LLVMLongType) {
252 return new CGObjCEtoile(M, LLVMIntType, LLVMLongType);
253}
254*/