CGObjCGNU.cpp revision 391d77a26382dddf25da73e29fc1fa5aaaea4c6f
1//===------- CGObjCGNU.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 GNU runtime.
11//
12//===----------------------------------------------------------------------===//
13
14#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 CGObjCGNU : public clang::CodeGen::CGObjCRuntime {
25private:
26  llvm::Module &TheModule;
27  const llvm::Type *SelectorTy;
28  const llvm::Type *PtrToInt8Ty;
29  const llvm::Type *IMPTy;
30  const llvm::Type *IdTy;
31  const llvm::Type *IntTy;
32  const llvm::Type *PtrTy;
33  const llvm::Type *LongTy;
34  const llvm::Type *PtrToIntTy;
35public:
36  CGObjCGNU(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
57CGObjCGNU::CGObjCGNU(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  const llvm::Type *SelStructTy = llvm::StructType::get(
69      PtrToInt8Ty,
70      PtrToInt8Ty,
71      NULL);
72  SelectorTy = llvm::PointerType::getUnqual(SelStructTy);
73  PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
74  PtrTy = PtrToInt8Ty;
75
76  // Object type
77  llvm::PATypeHolder OpaqueObjTy = llvm::OpaqueType::get();
78  llvm::Type *OpaqueIdTy = llvm::PointerType::getUnqual(OpaqueObjTy);
79  IdTy = llvm::StructType::get(OpaqueIdTy, NULL);
80  llvm::cast<llvm::OpaqueType>(OpaqueObjTy.get())->refineAbstractTypeTo(IdTy);
81  IdTy = llvm::cast<llvm::StructType>(OpaqueObjTy.get());
82  IdTy = llvm::PointerType::getUnqual(IdTy);
83
84  // IMP type
85  std::vector<const llvm::Type*> IMPArgs;
86  IMPArgs.push_back(IdTy);
87  IMPArgs.push_back(SelectorTy);
88  IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
89
90}
91
92/// Looks up the selector for the specified name / type pair.
93// FIXME: Selectors should be statically cached, not looked up on every call.
94llvm::Value *CGObjCGNU::getSelector(llvm::LLVMFoldingBuilder &Builder,
95    llvm::Value *SelName,
96    llvm::Value *SelTypes)
97{
98  // Look up the selector.
99  llvm::Value *cmd;
100  if(SelTypes == 0) {
101    llvm::Constant *SelFunction = TheModule.getOrInsertFunction("sel_get_uid",
102        SelectorTy,
103        PtrToInt8Ty,
104        NULL);
105    cmd = Builder.CreateCall(SelFunction, SelName);
106  }
107  else {
108    llvm::Constant *SelFunction =
109      TheModule.getOrInsertFunction("sel_get_typed_uid",
110          SelectorTy,
111          PtrToInt8Ty,
112          PtrToInt8Ty,
113          NULL);
114    llvm::Value *Args[] = { SelName, SelTypes };
115    cmd = Builder.CreateCall(SelFunction, Args, Args+2);
116  }
117  return cmd;
118}
119
120
121/// Generate code for a message send expression on the GNU runtime.
122// FIXME: Much of this code will need factoring out later.
123// TODO: This should take a sender argument (pointer to self in the calling
124// context)
125llvm::Value *CGObjCGNU::generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
126                                            const llvm::Type *ReturnTy,
127                                            llvm::Value *Sender,
128                                            llvm::Value *Receiver,
129                                            llvm::Value *Selector,
130                                            llvm::Value** ArgV,
131                                            unsigned ArgC) {
132  llvm::Value *cmd = getSelector(Builder, Selector, 0);
133
134  // Look up the method implementation.
135  std::vector<const llvm::Type*> impArgTypes;
136  impArgTypes.push_back(Receiver->getType());
137  impArgTypes.push_back(SelectorTy);
138
139  // Avoid an explicit cast on the IMP by getting a version that has the right
140  // return type.
141  llvm::FunctionType *impType = llvm::FunctionType::get(ReturnTy, impArgTypes,
142                                                        true);
143
144  llvm::Constant *lookupFunction =
145     TheModule.getOrInsertFunction("objc_msg_lookup",
146                                   llvm::PointerType::getUnqual(impType),
147                                   Receiver->getType(), SelectorTy, NULL);
148  llvm::SmallVector<llvm::Value*, 16> lookupArgs;
149  lookupArgs.push_back(Receiver);
150  lookupArgs.push_back(cmd);
151  llvm::Value *imp = Builder.CreateCall(lookupFunction,
152                                        lookupArgs.begin(), lookupArgs.end());
153
154  // Call the method.
155  lookupArgs.insert(lookupArgs.end(), ArgV, ArgV+ArgC);
156  return Builder.CreateCall(imp, lookupArgs.begin(), lookupArgs.end());
157}
158
159llvm::Function *CGObjCGNU::MethodPreamble(
160                                         const llvm::Type *ReturnTy,
161                                         const llvm::Type *SelfTy,
162                                         const llvm::Type **ArgTy,
163                                         unsigned ArgC,
164                                         bool isVarArg) {
165  std::vector<const llvm::Type*> Args;
166  Args.push_back(SelfTy);
167  Args.push_back(SelectorTy);
168  Args.insert(Args.end(), ArgTy, ArgTy+ArgC);
169
170  llvm::FunctionType *MethodTy = llvm::FunctionType::get(ReturnTy,
171      Args,
172      isVarArg);
173  llvm::Function *Method = new llvm::Function(MethodTy,
174      llvm::GlobalValue::InternalLinkage,
175      ".objc.method",
176      &TheModule);
177  // Set the names of the hidden arguments
178  llvm::Function::arg_iterator AI = Method->arg_begin();
179  AI->setName("self");
180  ++AI;
181  AI->setName("_cmd");
182  return Method;
183}
184
185clang::CodeGen::CGObjCRuntime *clang::CodeGen::CreateObjCRuntime(
186    llvm::Module &M,
187    const llvm::Type *LLVMIntType,
188    const llvm::Type *LLVMLongType) {
189  return new CGObjCGNU(M, LLVMIntType, LLVMLongType);
190}
191