blob: f0d6f554d55839ea833a258e323438a8383a684b [file] [log] [blame]
Chris Lattnera0fd5ee2008-03-01 08:50:34 +00001//===------- 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
20using namespace clang::CodeGen;
21using namespace clang;
22
23CGObjCRuntime::~CGObjCRuntime() {}
24
25namespace {
26class CGObjCGNU : public CGObjCRuntime {
27private:
28 llvm::Module &TheModule;
29public:
30 CGObjCGNU(llvm::Module &M) : TheModule(M) {};
31 virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
32 const llvm::Type *ReturnTy,
33 llvm::Value *Receiver,
34 llvm::Constant *Selector,
35 llvm::Value** ArgV,
36 unsigned ArgC);
37};
38} // end anonymous namespace
39
40// Generate code for a message send expression on the GNU runtime.
41// BIG FAT WARNING: Much of this code will need factoring out later.
42// FIXME: This currently only handles id returns. Other return types
43// need some explicit casting.
44llvm::Value *CGObjCGNU::generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
45 const llvm::Type *ReturnTy,
46 llvm::Value *Receiver,
47 llvm::Constant *Selector,
48 llvm::Value** ArgV,
49 unsigned ArgC) {
50 // Get the selector Type.
51 const llvm::Type *PtrToInt8Ty =
52 llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
53 std::vector<const llvm::Type*> Str2(2, PtrToInt8Ty);
54 const llvm::Type *SelStructTy = llvm::StructType::get(Str2);
55 const llvm::Type *SelTy = llvm::PointerType::getUnqual(SelStructTy);
56
57 // Look up the selector.
58 // If we haven't got the selector lookup function, look it up now.
59 // TODO: Factor this out and use it to implement @selector() too.
60 llvm::Constant *SelFunction =
61 TheModule.getOrInsertFunction("sel_get_uid", SelTy, PtrToInt8Ty, NULL);
62 // FIXME: Selectors should be statically cached, not looked up on every call.
63
64 // TODO: Pull this out into the caller.
65 llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
66 llvm::Constant *Ops[] = {Idx0, Idx0};
67 llvm::Value *SelStr = llvm::ConstantExpr::getGetElementPtr(Selector, Ops, 2);
68 llvm::Value *cmd = Builder.CreateCall(SelFunction, &SelStr, &SelStr+1);
69
70 // Look up the method implementation.
71 std::vector<const llvm::Type*> impArgTypes;
72 impArgTypes.push_back(Receiver->getType());
73 impArgTypes.push_back(SelTy);
74
75 // Avoid an explicit cast on the IMP by getting a version that has the right
76 // return type.
77 llvm::FunctionType *impType = llvm::FunctionType::get(ReturnTy, impArgTypes,
78 true);
79
80 llvm::Constant *lookupFunction =
81 TheModule.getOrInsertFunction("objc_msg_lookup",
82 llvm::PointerType::get(impType, 0),
83 Receiver->getType(), SelTy, NULL);
84 llvm::SmallVector<llvm::Value*, 16> lookupArgs;
85 lookupArgs.push_back(Receiver);
86 lookupArgs.push_back(cmd);
87 llvm::Value *imp = Builder.CreateCall(lookupFunction,
88 lookupArgs.begin(), lookupArgs.end());
89
90 // Call the method.
91 lookupArgs.insert(lookupArgs.end(), ArgV, ArgV+ArgC);
92 return Builder.CreateCall(imp, lookupArgs.begin(), lookupArgs.end());
93}
94
95CGObjCRuntime * clang::CodeGen::CreateObjCRuntime(llvm::Module &M) {
96 return new CGObjCGNU(M);
97}