blob: 1bd01ef518a86f2ffdeba3740f7de0e5359521ba [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);
Chris Lattnerbe09ede2008-04-04 15:47:22 +000079 IdTy = llvm::PointerType::getUnqual(llvm::StructType::get(OpaqueIdTy, NULL));
Chris Lattner7ba9c602008-04-04 15:45:52 +000080 OpaqueObjTy->refineAbstractTypeTo(IdTy);
81
82 // Call structure type.
83 llvm::OpaqueType *OpaqueSlotTy = llvm::OpaqueType::get();
84 CallTy = llvm::StructType::get(llvm::PointerType::getUnqual(OpaqueSlotTy),
Chris Lattnerbe09ede2008-04-04 15:47:22 +000085 SelectorTy, IdTy, NULL);
Chris Lattner7ba9c602008-04-04 15:45:52 +000086
87 // IMP type
88 std::vector<const llvm::Type*> IMPArgs;
89 IMPArgs.push_back(IdTy);
90 IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy));
91 IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
92
93 // Slot type
Chris Lattnerbe09ede2008-04-04 15:47:22 +000094 SlotTy = llvm::StructType::get(IntTy, IMPTy, PtrToInt8Ty, PtrToInt8Ty,
95 llvm::Type::Int32Ty, NULL);
Chris Lattner7ba9c602008-04-04 15:45:52 +000096 OpaqueSlotTy->refineAbstractTypeTo(SlotTy);
97 SlotTy = llvm::PointerType::getUnqual(SlotTy);
98
99 // Lookup function type
100 std::vector<const llvm::Type*> LookupFunctionArgs;
101 LookupFunctionArgs.push_back(llvm::PointerType::getUnqual(IdTy));
102 LookupFunctionArgs.push_back(IdTy);
103 LookupFunctionArgs.push_back(SelectorTy);
104 LookupFunctionArgs.push_back(IdTy);
105 LookupFunctionTy = llvm::FunctionType::get(SlotTy, LookupFunctionArgs, false);
106 LookupFunctionTy = llvm::PointerType::getUnqual(LookupFunctionTy);
107
108}
109
110// Looks up the selector for the specified name / type pair.
111llvm::Value *CGObjCEtoile::getSelector(llvm::LLVMFoldingBuilder &Builder,
112 llvm::Value *SelName,
113 llvm::Value *SelTypes)
114{
115 // Look up the selector.
116 if(SelTypes == 0) {
117 SelTypes = llvm::ConstantPointerNull::get(PtrToInt8Ty);
118 }
119 llvm::Constant *SelFunction =
Chris Lattnerbe09ede2008-04-04 15:47:22 +0000120 TheModule.getOrInsertFunction("lookup_typed_selector", SelectorTy,
121 PtrToInt8Ty, PtrToInt8Ty, NULL);
Chris Lattner7ba9c602008-04-04 15:45:52 +0000122 llvm::SmallVector<llvm::Value*, 2> Args;
123 Args.push_back(SelName);
124 Args.push_back(SelTypes);
125 return Builder.CreateCall(SelFunction, Args.begin(), Args.end());
126}
127
128#define SET(structure, index, value) do {\
129 llvm::Value *element_ptr = Builder.CreateStructGEP(structure, index);\
130 Builder.CreateStore(value, element_ptr);} while(0)
131// Generate code for a message send expression on the Etoile runtime.
132// BIG FAT WARNING: Much of this code will need factoring out later.
133llvm::Value *CGObjCEtoile::generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
134 const llvm::Type *ReturnTy,
135 llvm::Value *Sender,
136 llvm::Value *Receiver,
137 llvm::Value *Selector,
138 llvm::Value** ArgV,
139 unsigned ArgC) {
140 // FIXME: Selectors should be statically cached, not looked up on every call.
141 llvm::Value *cmd = getSelector(Builder, Selector, 0);
142 // TODO: [Polymorphic] inline caching
143
144 // Get the lookup function for this object:
145 llvm::Value *ObjAddr = Builder.CreateBitCast(Receiver, PtrToInt8Ty);
146 llvm::Value *FunctionOffset = new llvm::GlobalVariable(llvm::Type::Int32Ty,
147 false,
148 llvm::GlobalValue::ExternalLinkage,
149 0,
150 "lookup_offset",
151 &TheModule);
152 FunctionOffset = Builder.CreateLoad(FunctionOffset);
153 llvm::Value *Tag = Builder.CreateGEP(ObjAddr, FunctionOffset);
154 llvm::Value *Lookup = Builder.CreateBitCast(Tag, LookupFunctionTy);
155
156 // TODO: Remove this when the caller is providing sensible sender info
157 if(Sender == 0) {
158 Sender = llvm::ConstantPointerNull::get((llvm::PointerType*)IdTy);
159 }
160 Receiver = Builder.CreateBitCast(Receiver, IdTy);
161 llvm::Value *ReceiverAddr = Builder.CreateAlloca(IdTy);
162 Builder.CreateStore(Receiver, ReceiverAddr);
163 // Look up the method implementation.
164 llvm::SmallVector<llvm::Value*, 4> LookupArgs;
165 LookupArgs.push_back(ReceiverAddr);
166 LookupArgs.push_back(Receiver);
167 LookupArgs.push_back(cmd);
168 LookupArgs.push_back(Sender);
169 llvm::Value *Slot = Builder.CreateCall(Lookup,
170 LookupArgs.begin(),
171 LookupArgs.end());
172
173 // Create the call structure
174 llvm::Value *Call = Builder.CreateAlloca(CallTy);
175 SET(Call, 0, Slot);
176 SET(Call, 1, cmd);
177 SET(Call, 2, Sender);
178
179 // Get the IMP from the slot and call it
180 // TODO: Property load / store optimisations
181 llvm::Value *IMP = Builder.CreateStructGEP(Slot, 1);
182 // If the return type of the IMP is wrong, cast it so it isn't.
183 if(ReturnTy != IdTy) {
184 std::vector<const llvm::Type*> IMPArgs;
185 IMPArgs.push_back(IdTy);
186 IMPArgs.push_back(llvm::PointerType::getUnqual(CallTy));
187 llvm::Type *NewIMPTy = llvm::FunctionType::get(ReturnTy, IMPArgs, true);
188 IMP = Builder.CreateBitCast(IMP, llvm::PointerType::getUnqual(NewIMPTy));
189 }
190 llvm::SmallVector<llvm::Value*, 16> Args;
191 Args.push_back(Receiver);
192 Args.push_back(Call);
193 Args.insert(Args.end(), ArgV, ArgV+ArgC);
194 return Builder.CreateCall(IMP, Args.begin(), Args.end());
195}
196
197llvm::Function *CGObjCEtoile::MethodPreamble(
198 const llvm::Type *ReturnTy,
199 const llvm::Type *SelfTy,
200 const llvm::Type **ArgTy,
201 unsigned ArgC,
202 bool isVarArg) {
203 std::vector<const llvm::Type*> Args;
204 //Args.push_back(SelfTy);
205 Args.push_back(IdTy);
206 Args.push_back(llvm::PointerType::getUnqual(CallTy));
207 for (unsigned i=0; i<ArgC ; i++) {
208 Args.push_back(ArgTy[i]);
209 }
210 llvm::FunctionType *MethodTy = llvm::FunctionType::get(ReturnTy, Args, isVarArg);
211 llvm::Function *Method = new llvm::Function(MethodTy,
212 llvm::GlobalValue::InternalLinkage,
213 ".objc.method",
214 &TheModule);
215 //llvm::BasicBlock *EntryBB = new llvm::BasicBlock("entry", Method);
216 // Set the names of the hidden arguments
217 llvm::Function::arg_iterator AI = Method->arg_begin();
218 AI[0].setName("self");
219 AI[1].setName("_call");
220 // FIXME: Should create the _cmd variable as _call->selector
221 return Method;
222}
223
224/*
225clang::CodeGen::CGObjCRuntime *clang::CodeGen::CreateObjCRuntime(
226 llvm::Module &M,
227 const llvm::Type *LLVMIntType,
228 const llvm::Type *LLVMLongType) {
229 return new CGObjCEtoile(M, LLVMIntType, LLVMLongType);
230}
231*/