Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 1 | //===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===// |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 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" |
Chris Lattner | 50b3674 | 2008-04-13 07:32:11 +0000 | [diff] [blame] | 17 | #include "llvm/Support/IRBuilder.h" |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 18 | #include "llvm/ADT/SmallVector.h" |
| 19 | |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 20 | namespace { |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 21 | class CGObjCGNU : public clang::CodeGen::CGObjCRuntime { |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 22 | private: |
| 23 | llvm::Module &TheModule; |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 24 | const llvm::Type *SelectorTy; |
| 25 | const llvm::Type *PtrToInt8Ty; |
| 26 | const llvm::Type *IMPTy; |
| 27 | const llvm::Type *IdTy; |
| 28 | const llvm::Type *IntTy; |
| 29 | const llvm::Type *PtrTy; |
| 30 | const llvm::Type *LongTy; |
| 31 | const llvm::Type *PtrToIntTy; |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 32 | public: |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 33 | CGObjCGNU(llvm::Module &Mp, |
| 34 | const llvm::Type *LLVMIntType, |
| 35 | const llvm::Type *LLVMLongType); |
Chris Lattner | 50b3674 | 2008-04-13 07:32:11 +0000 | [diff] [blame] | 36 | virtual llvm::Value *generateMessageSend(llvm::IRBuilder &Builder, |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 37 | const llvm::Type *ReturnTy, |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 38 | llvm::Value *Sender, |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 39 | llvm::Value *Receiver, |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 40 | llvm::Value *Selector, |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 41 | llvm::Value** ArgV, |
| 42 | unsigned ArgC); |
Chris Lattner | 50b3674 | 2008-04-13 07:32:11 +0000 | [diff] [blame] | 43 | llvm::Value *getSelector(llvm::IRBuilder &Builder, |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 44 | llvm::Value *SelName, |
| 45 | llvm::Value *SelTypes); |
| 46 | virtual llvm::Function *MethodPreamble(const llvm::Type *ReturnTy, |
| 47 | const llvm::Type *SelfTy, |
| 48 | const llvm::Type **ArgTy, |
| 49 | unsigned ArgC, |
| 50 | bool isVarArg); |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 51 | }; |
| 52 | } // end anonymous namespace |
| 53 | |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 54 | CGObjCGNU::CGObjCGNU(llvm::Module &M, |
| 55 | const llvm::Type *LLVMIntType, |
| 56 | const llvm::Type *LLVMLongType) : |
| 57 | TheModule(M), |
| 58 | IntTy(LLVMIntType), |
| 59 | LongTy(LLVMLongType) |
| 60 | { |
| 61 | // C string type. Used in lots of places. |
| 62 | PtrToInt8Ty = |
| 63 | llvm::PointerType::getUnqual(llvm::Type::Int8Ty); |
| 64 | // Get the selector Type. |
| 65 | const llvm::Type *SelStructTy = llvm::StructType::get( |
| 66 | PtrToInt8Ty, |
| 67 | PtrToInt8Ty, |
| 68 | NULL); |
| 69 | SelectorTy = llvm::PointerType::getUnqual(SelStructTy); |
| 70 | PtrToIntTy = llvm::PointerType::getUnqual(IntTy); |
| 71 | PtrTy = PtrToInt8Ty; |
| 72 | |
| 73 | // Object type |
| 74 | llvm::PATypeHolder OpaqueObjTy = llvm::OpaqueType::get(); |
| 75 | llvm::Type *OpaqueIdTy = llvm::PointerType::getUnqual(OpaqueObjTy); |
| 76 | IdTy = llvm::StructType::get(OpaqueIdTy, NULL); |
| 77 | llvm::cast<llvm::OpaqueType>(OpaqueObjTy.get())->refineAbstractTypeTo(IdTy); |
| 78 | IdTy = llvm::cast<llvm::StructType>(OpaqueObjTy.get()); |
| 79 | IdTy = llvm::PointerType::getUnqual(IdTy); |
| 80 | |
| 81 | // IMP type |
| 82 | std::vector<const llvm::Type*> IMPArgs; |
| 83 | IMPArgs.push_back(IdTy); |
| 84 | IMPArgs.push_back(SelectorTy); |
| 85 | IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true); |
| 86 | |
| 87 | } |
| 88 | |
| 89 | /// Looks up the selector for the specified name / type pair. |
| 90 | // FIXME: Selectors should be statically cached, not looked up on every call. |
Chris Lattner | 50b3674 | 2008-04-13 07:32:11 +0000 | [diff] [blame] | 91 | llvm::Value *CGObjCGNU::getSelector(llvm::IRBuilder &Builder, |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 92 | llvm::Value *SelName, |
| 93 | llvm::Value *SelTypes) |
| 94 | { |
| 95 | // Look up the selector. |
| 96 | llvm::Value *cmd; |
| 97 | if(SelTypes == 0) { |
| 98 | llvm::Constant *SelFunction = TheModule.getOrInsertFunction("sel_get_uid", |
| 99 | SelectorTy, |
| 100 | PtrToInt8Ty, |
| 101 | NULL); |
| 102 | cmd = Builder.CreateCall(SelFunction, SelName); |
| 103 | } |
| 104 | else { |
| 105 | llvm::Constant *SelFunction = |
| 106 | TheModule.getOrInsertFunction("sel_get_typed_uid", |
| 107 | SelectorTy, |
| 108 | PtrToInt8Ty, |
| 109 | PtrToInt8Ty, |
| 110 | NULL); |
Chris Lattner | 3eae03e | 2008-05-06 00:56:42 +0000 | [diff] [blame] | 111 | cmd = Builder.CreateCall2(SelFunction, SelName, SelTypes); |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 112 | } |
| 113 | return cmd; |
| 114 | } |
| 115 | |
| 116 | |
| 117 | /// Generate code for a message send expression on the GNU runtime. |
| 118 | // FIXME: Much of this code will need factoring out later. |
| 119 | // TODO: This should take a sender argument (pointer to self in the calling |
| 120 | // context) |
Chris Lattner | 50b3674 | 2008-04-13 07:32:11 +0000 | [diff] [blame] | 121 | llvm::Value *CGObjCGNU::generateMessageSend(llvm::IRBuilder &Builder, |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 122 | const llvm::Type *ReturnTy, |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 123 | llvm::Value *Sender, |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 124 | llvm::Value *Receiver, |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 125 | llvm::Value *Selector, |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 126 | llvm::Value** ArgV, |
| 127 | unsigned ArgC) { |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 128 | llvm::Value *cmd = getSelector(Builder, Selector, 0); |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 129 | |
| 130 | // Look up the method implementation. |
| 131 | std::vector<const llvm::Type*> impArgTypes; |
| 132 | impArgTypes.push_back(Receiver->getType()); |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 133 | impArgTypes.push_back(SelectorTy); |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 134 | |
| 135 | // Avoid an explicit cast on the IMP by getting a version that has the right |
| 136 | // return type. |
| 137 | llvm::FunctionType *impType = llvm::FunctionType::get(ReturnTy, impArgTypes, |
| 138 | true); |
| 139 | |
| 140 | llvm::Constant *lookupFunction = |
| 141 | TheModule.getOrInsertFunction("objc_msg_lookup", |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 142 | llvm::PointerType::getUnqual(impType), |
| 143 | Receiver->getType(), SelectorTy, NULL); |
Chris Lattner | 3eae03e | 2008-05-06 00:56:42 +0000 | [diff] [blame] | 144 | llvm::Value *imp = Builder.CreateCall2(lookupFunction, Receiver, cmd); |
| 145 | |
| 146 | // Call the method. |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 147 | llvm::SmallVector<llvm::Value*, 16> lookupArgs; |
| 148 | lookupArgs.push_back(Receiver); |
| 149 | lookupArgs.push_back(cmd); |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 150 | lookupArgs.insert(lookupArgs.end(), ArgV, ArgV+ArgC); |
| 151 | return Builder.CreateCall(imp, lookupArgs.begin(), lookupArgs.end()); |
| 152 | } |
| 153 | |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 154 | llvm::Function *CGObjCGNU::MethodPreamble( |
| 155 | const llvm::Type *ReturnTy, |
| 156 | const llvm::Type *SelfTy, |
| 157 | const llvm::Type **ArgTy, |
| 158 | unsigned ArgC, |
| 159 | bool isVarArg) { |
| 160 | std::vector<const llvm::Type*> Args; |
| 161 | Args.push_back(SelfTy); |
| 162 | Args.push_back(SelectorTy); |
| 163 | Args.insert(Args.end(), ArgTy, ArgTy+ArgC); |
| 164 | |
| 165 | llvm::FunctionType *MethodTy = llvm::FunctionType::get(ReturnTy, |
| 166 | Args, |
| 167 | isVarArg); |
Gabor Greif | 984d0b4 | 2008-04-06 20:42:52 +0000 | [diff] [blame] | 168 | llvm::Function *Method = llvm::Function::Create(MethodTy, |
Chris Lattner | 391d77a | 2008-03-30 23:03:07 +0000 | [diff] [blame] | 169 | llvm::GlobalValue::InternalLinkage, |
| 170 | ".objc.method", |
| 171 | &TheModule); |
| 172 | // Set the names of the hidden arguments |
| 173 | llvm::Function::arg_iterator AI = Method->arg_begin(); |
| 174 | AI->setName("self"); |
| 175 | ++AI; |
| 176 | AI->setName("_cmd"); |
| 177 | return Method; |
| 178 | } |
| 179 | |
| 180 | clang::CodeGen::CGObjCRuntime *clang::CodeGen::CreateObjCRuntime( |
| 181 | llvm::Module &M, |
| 182 | const llvm::Type *LLVMIntType, |
| 183 | const llvm::Type *LLVMLongType) { |
| 184 | return new CGObjCGNU(M, LLVMIntType, LLVMLongType); |
Chris Lattner | 0f98426 | 2008-03-01 08:50:34 +0000 | [diff] [blame] | 185 | } |