2008-03-31 07:03:07 +08:00
|
|
|
//===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===//
|
2008-03-01 16:50:34 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This provides Objective-C code generation targetting the GNU runtime.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "CGObjCRuntime.h"
|
|
|
|
#include "llvm/Module.h"
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
#include "llvm/Support/LLVMBuilder.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
|
|
|
|
namespace {
|
2008-03-31 07:03:07 +08:00
|
|
|
class CGObjCGNU : public clang::CodeGen::CGObjCRuntime {
|
2008-03-01 16:50:34 +08:00
|
|
|
private:
|
|
|
|
llvm::Module &TheModule;
|
2008-03-31 07:03:07 +08:00
|
|
|
const llvm::Type *SelectorTy;
|
|
|
|
const llvm::Type *PtrToInt8Ty;
|
|
|
|
const llvm::Type *IMPTy;
|
|
|
|
const llvm::Type *IdTy;
|
|
|
|
const llvm::Type *IntTy;
|
|
|
|
const llvm::Type *PtrTy;
|
|
|
|
const llvm::Type *LongTy;
|
|
|
|
const llvm::Type *PtrToIntTy;
|
2008-03-01 16:50:34 +08:00
|
|
|
public:
|
2008-03-31 07:03:07 +08:00
|
|
|
CGObjCGNU(llvm::Module &Mp,
|
|
|
|
const llvm::Type *LLVMIntType,
|
|
|
|
const llvm::Type *LLVMLongType);
|
2008-03-01 16:50:34 +08:00
|
|
|
virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
|
|
|
|
const llvm::Type *ReturnTy,
|
2008-03-31 07:03:07 +08:00
|
|
|
llvm::Value *Sender,
|
2008-03-01 16:50:34 +08:00
|
|
|
llvm::Value *Receiver,
|
2008-03-31 07:03:07 +08:00
|
|
|
llvm::Value *Selector,
|
2008-03-01 16:50:34 +08:00
|
|
|
llvm::Value** ArgV,
|
|
|
|
unsigned ArgC);
|
2008-03-31 07:03:07 +08:00
|
|
|
llvm::Value *getSelector(llvm::LLVMFoldingBuilder &Builder,
|
|
|
|
llvm::Value *SelName,
|
|
|
|
llvm::Value *SelTypes);
|
|
|
|
virtual llvm::Function *MethodPreamble(const llvm::Type *ReturnTy,
|
|
|
|
const llvm::Type *SelfTy,
|
|
|
|
const llvm::Type **ArgTy,
|
|
|
|
unsigned ArgC,
|
|
|
|
bool isVarArg);
|
2008-03-01 16:50:34 +08:00
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2008-03-31 07:03:07 +08:00
|
|
|
CGObjCGNU::CGObjCGNU(llvm::Module &M,
|
|
|
|
const llvm::Type *LLVMIntType,
|
|
|
|
const llvm::Type *LLVMLongType) :
|
|
|
|
TheModule(M),
|
|
|
|
IntTy(LLVMIntType),
|
|
|
|
LongTy(LLVMLongType)
|
|
|
|
{
|
|
|
|
// C string type. Used in lots of places.
|
|
|
|
PtrToInt8Ty =
|
|
|
|
llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
|
|
|
|
// Get the selector Type.
|
|
|
|
const llvm::Type *SelStructTy = llvm::StructType::get(
|
|
|
|
PtrToInt8Ty,
|
|
|
|
PtrToInt8Ty,
|
|
|
|
NULL);
|
|
|
|
SelectorTy = llvm::PointerType::getUnqual(SelStructTy);
|
|
|
|
PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
|
|
|
|
PtrTy = PtrToInt8Ty;
|
|
|
|
|
|
|
|
// Object type
|
|
|
|
llvm::PATypeHolder OpaqueObjTy = llvm::OpaqueType::get();
|
|
|
|
llvm::Type *OpaqueIdTy = llvm::PointerType::getUnqual(OpaqueObjTy);
|
|
|
|
IdTy = llvm::StructType::get(OpaqueIdTy, NULL);
|
|
|
|
llvm::cast<llvm::OpaqueType>(OpaqueObjTy.get())->refineAbstractTypeTo(IdTy);
|
|
|
|
IdTy = llvm::cast<llvm::StructType>(OpaqueObjTy.get());
|
|
|
|
IdTy = llvm::PointerType::getUnqual(IdTy);
|
|
|
|
|
|
|
|
// IMP type
|
|
|
|
std::vector<const llvm::Type*> IMPArgs;
|
|
|
|
IMPArgs.push_back(IdTy);
|
|
|
|
IMPArgs.push_back(SelectorTy);
|
|
|
|
IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Looks up the selector for the specified name / type pair.
|
|
|
|
// FIXME: Selectors should be statically cached, not looked up on every call.
|
|
|
|
llvm::Value *CGObjCGNU::getSelector(llvm::LLVMFoldingBuilder &Builder,
|
|
|
|
llvm::Value *SelName,
|
|
|
|
llvm::Value *SelTypes)
|
|
|
|
{
|
|
|
|
// Look up the selector.
|
|
|
|
llvm::Value *cmd;
|
|
|
|
if(SelTypes == 0) {
|
|
|
|
llvm::Constant *SelFunction = TheModule.getOrInsertFunction("sel_get_uid",
|
|
|
|
SelectorTy,
|
|
|
|
PtrToInt8Ty,
|
|
|
|
NULL);
|
|
|
|
cmd = Builder.CreateCall(SelFunction, SelName);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
llvm::Constant *SelFunction =
|
|
|
|
TheModule.getOrInsertFunction("sel_get_typed_uid",
|
|
|
|
SelectorTy,
|
|
|
|
PtrToInt8Ty,
|
|
|
|
PtrToInt8Ty,
|
|
|
|
NULL);
|
|
|
|
llvm::Value *Args[] = { SelName, SelTypes };
|
|
|
|
cmd = Builder.CreateCall(SelFunction, Args, Args+2);
|
|
|
|
}
|
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Generate code for a message send expression on the GNU runtime.
|
|
|
|
// FIXME: Much of this code will need factoring out later.
|
|
|
|
// TODO: This should take a sender argument (pointer to self in the calling
|
|
|
|
// context)
|
2008-03-01 16:50:34 +08:00
|
|
|
llvm::Value *CGObjCGNU::generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
|
|
|
|
const llvm::Type *ReturnTy,
|
2008-03-31 07:03:07 +08:00
|
|
|
llvm::Value *Sender,
|
2008-03-01 16:50:34 +08:00
|
|
|
llvm::Value *Receiver,
|
2008-03-31 07:03:07 +08:00
|
|
|
llvm::Value *Selector,
|
2008-03-01 16:50:34 +08:00
|
|
|
llvm::Value** ArgV,
|
|
|
|
unsigned ArgC) {
|
2008-03-31 07:03:07 +08:00
|
|
|
llvm::Value *cmd = getSelector(Builder, Selector, 0);
|
2008-03-01 16:50:34 +08:00
|
|
|
|
|
|
|
// Look up the method implementation.
|
|
|
|
std::vector<const llvm::Type*> impArgTypes;
|
|
|
|
impArgTypes.push_back(Receiver->getType());
|
2008-03-31 07:03:07 +08:00
|
|
|
impArgTypes.push_back(SelectorTy);
|
2008-03-01 16:50:34 +08:00
|
|
|
|
|
|
|
// Avoid an explicit cast on the IMP by getting a version that has the right
|
|
|
|
// return type.
|
|
|
|
llvm::FunctionType *impType = llvm::FunctionType::get(ReturnTy, impArgTypes,
|
|
|
|
true);
|
|
|
|
|
|
|
|
llvm::Constant *lookupFunction =
|
|
|
|
TheModule.getOrInsertFunction("objc_msg_lookup",
|
2008-03-31 07:03:07 +08:00
|
|
|
llvm::PointerType::getUnqual(impType),
|
|
|
|
Receiver->getType(), SelectorTy, NULL);
|
2008-03-01 16:50:34 +08:00
|
|
|
llvm::SmallVector<llvm::Value*, 16> lookupArgs;
|
|
|
|
lookupArgs.push_back(Receiver);
|
|
|
|
lookupArgs.push_back(cmd);
|
|
|
|
llvm::Value *imp = Builder.CreateCall(lookupFunction,
|
|
|
|
lookupArgs.begin(), lookupArgs.end());
|
|
|
|
|
|
|
|
// Call the method.
|
|
|
|
lookupArgs.insert(lookupArgs.end(), ArgV, ArgV+ArgC);
|
|
|
|
return Builder.CreateCall(imp, lookupArgs.begin(), lookupArgs.end());
|
|
|
|
}
|
|
|
|
|
2008-03-31 07:03:07 +08:00
|
|
|
llvm::Function *CGObjCGNU::MethodPreamble(
|
|
|
|
const llvm::Type *ReturnTy,
|
|
|
|
const llvm::Type *SelfTy,
|
|
|
|
const llvm::Type **ArgTy,
|
|
|
|
unsigned ArgC,
|
|
|
|
bool isVarArg) {
|
|
|
|
std::vector<const llvm::Type*> Args;
|
|
|
|
Args.push_back(SelfTy);
|
|
|
|
Args.push_back(SelectorTy);
|
|
|
|
Args.insert(Args.end(), ArgTy, ArgTy+ArgC);
|
|
|
|
|
|
|
|
llvm::FunctionType *MethodTy = llvm::FunctionType::get(ReturnTy,
|
|
|
|
Args,
|
|
|
|
isVarArg);
|
2008-04-07 04:42:52 +08:00
|
|
|
llvm::Function *Method = llvm::Function::Create(MethodTy,
|
2008-03-31 07:03:07 +08:00
|
|
|
llvm::GlobalValue::InternalLinkage,
|
|
|
|
".objc.method",
|
|
|
|
&TheModule);
|
|
|
|
// Set the names of the hidden arguments
|
|
|
|
llvm::Function::arg_iterator AI = Method->arg_begin();
|
|
|
|
AI->setName("self");
|
|
|
|
++AI;
|
|
|
|
AI->setName("_cmd");
|
|
|
|
return Method;
|
|
|
|
}
|
|
|
|
|
|
|
|
clang::CodeGen::CGObjCRuntime *clang::CodeGen::CreateObjCRuntime(
|
|
|
|
llvm::Module &M,
|
|
|
|
const llvm::Type *LLVMIntType,
|
|
|
|
const llvm::Type *LLVMLongType) {
|
|
|
|
return new CGObjCGNU(M, LLVMIntType, LLVMLongType);
|
2008-03-01 16:50:34 +08:00
|
|
|
}
|