forked from OSchip/llvm-project
Add initial support for objc codegen for methods, ivars, and the
etoile runtime, patch by David Chisnall! llvm-svn: 48969
This commit is contained in:
parent
dd0ace574b
commit
4bd5596d08
|
@ -82,6 +82,7 @@ RValue CodeGenFunction::EmitAnyExpr(const Expr *E, llvm::Value *AggLoc,
|
|||
LValue CodeGenFunction::EmitLValue(const Expr *E) {
|
||||
switch (E->getStmtClass()) {
|
||||
default: {
|
||||
printf("Statement class: %d\n", E->getStmtClass());
|
||||
WarnUnsupported(E, "l-value expression");
|
||||
llvm::Type *Ty = llvm::PointerType::getUnqual(ConvertType(E->getType()));
|
||||
return LValue::MakeAddr(llvm::UndefValue::get(Ty));
|
||||
|
@ -94,6 +95,9 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
|
|||
return EmitPreDefinedLValue(cast<PreDefinedExpr>(E));
|
||||
case Expr::StringLiteralClass:
|
||||
return EmitStringLiteralLValue(cast<StringLiteral>(E));
|
||||
|
||||
case Expr::ObjCIvarRefExprClass:
|
||||
return EmitObjCIvarRefLValue(cast<ObjCIvarRefExpr>(E));
|
||||
|
||||
case Expr::UnaryOperatorClass:
|
||||
return EmitUnaryOpLValue(cast<UnaryOperator>(E));
|
||||
|
@ -555,6 +559,41 @@ LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
|
|||
return LValue::MakeAddr(RV.getAggregateAddr());
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E) {
|
||||
// Objective-C objects are traditionally C structures with their layout
|
||||
// defined at compile-time. In some implementations, their layout is not
|
||||
// defined until run time in order to allow instance variables to be added to
|
||||
// a class without recompiling all of the subclasses. If this is the case
|
||||
// then the CGObjCRuntime subclass must return true to LateBoundIvars and
|
||||
// implement the lookup itself.
|
||||
if(CGM.getObjCRuntime()->LateBoundIVars()) {
|
||||
assert(0 && "FIXME: Implement support for late-bound instance variables");
|
||||
return LValue(); // Not reached.
|
||||
}
|
||||
else {
|
||||
// Get a structure type for the object
|
||||
QualType ExprTy = E->getBase()->getType();
|
||||
const llvm::Type *ObjectType = ConvertType(ExprTy);
|
||||
//TODO: Add a special case for isa (index 0)
|
||||
// Work out which index the ivar is
|
||||
const ObjCIvarDecl *Decl = E->getDecl();
|
||||
unsigned Index = CGM.getTypes().getLLVMFieldNo(Decl);
|
||||
|
||||
// Get object pointer
|
||||
llvm::Value * Object = EmitLValue(E->getBase()).getAddress();
|
||||
// Coerce object pointer to correct type.
|
||||
if (Object->getType() != ObjectType) {
|
||||
Object = Builder.CreateBitCast(Object, ObjectType);
|
||||
}
|
||||
// Get the correct element
|
||||
llvm::Value * Element = Builder.CreateStructGEP(Object,
|
||||
Index,
|
||||
Decl->getName());
|
||||
// Element = Builder.CreateLoad(Element);
|
||||
return LValue::MakeAddr(Element);
|
||||
}
|
||||
}
|
||||
|
||||
RValue CodeGenFunction::EmitCallExpr(llvm::Value *Callee, QualType FnType,
|
||||
Expr *const *ArgExprs, unsigned NumArgs) {
|
||||
// The callee type will always be a pointer to function type, get the function
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "llvm/GlobalVariable.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/ValueSymbolTable.h"
|
||||
#include <cstdarg>
|
||||
|
||||
using namespace clang;
|
||||
|
@ -126,6 +127,7 @@ public:
|
|||
return EmitLoadOfLValue(E);
|
||||
}
|
||||
Value *VisitObjCMessageExpr(ObjCMessageExpr *E);
|
||||
Value *VisitObjCIvarRefExpr(ObjCIvarRefExpr *E);
|
||||
Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
|
||||
Value *VisitMemberExpr(Expr *E) { return EmitLoadOfLValue(E); }
|
||||
Value *VisitOCUVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); }
|
||||
|
@ -449,6 +451,10 @@ Value *ScalarExprEmitter::VisitExpr(Expr *E) {
|
|||
return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
|
||||
}
|
||||
|
||||
Value *ScalarExprEmitter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
|
||||
return Builder.CreateLoad(CGF.EmitObjCIvarRefLValue(E).getAddress());
|
||||
}
|
||||
|
||||
Value *ScalarExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
|
||||
// Only the lookup mechanism and first two arguments of the method
|
||||
// implementation vary between runtimes. We can get the receiver and
|
||||
|
@ -481,11 +487,13 @@ Value *ScalarExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) {
|
|||
// Get the selector string
|
||||
std::string SelStr = E->getSelector().getName();
|
||||
llvm::Constant *Selector = CGF.CGM.GetAddrOfConstantString(SelStr);
|
||||
ConvertType(E->getType());
|
||||
|
||||
llvm::Value *SelPtr = Builder.CreateStructGEP(Selector, 0);
|
||||
return Runtime->generateMessageSend(Builder,
|
||||
ConvertType(E->getType()),
|
||||
CGF.CurFn->getValueSymbolTable().lookup("self"),
|
||||
Receiver,
|
||||
Selector,
|
||||
SelPtr,
|
||||
&Args[0],
|
||||
Args.size());
|
||||
}
|
||||
|
|
|
@ -23,3 +23,4 @@ llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E){
|
|||
return CGM.GetAddrOfConstantCFString(S);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===//
|
||||
//===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -17,60 +17,124 @@
|
|||
#include "llvm/Support/LLVMBuilder.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
using namespace clang::CodeGen;
|
||||
using namespace clang;
|
||||
|
||||
CGObjCRuntime::~CGObjCRuntime() {}
|
||||
clang::CodeGen::CGObjCRuntime::~CGObjCRuntime() {}
|
||||
|
||||
namespace {
|
||||
class CGObjCGNU : public CGObjCRuntime {
|
||||
class CGObjCGNU : public clang::CodeGen::CGObjCRuntime {
|
||||
private:
|
||||
llvm::Module &TheModule;
|
||||
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;
|
||||
public:
|
||||
CGObjCGNU(llvm::Module &M) : TheModule(M) {};
|
||||
CGObjCGNU(llvm::Module &Mp,
|
||||
const llvm::Type *LLVMIntType,
|
||||
const llvm::Type *LLVMLongType);
|
||||
virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
|
||||
const llvm::Type *ReturnTy,
|
||||
llvm::Value *Sender,
|
||||
llvm::Value *Receiver,
|
||||
llvm::Constant *Selector,
|
||||
llvm::Value *Selector,
|
||||
llvm::Value** ArgV,
|
||||
unsigned ArgC);
|
||||
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);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
// Generate code for a message send expression on the GNU runtime.
|
||||
// BIG FAT WARNING: Much of this code will need factoring out later.
|
||||
// FIXME: This currently only handles id returns. Other return types
|
||||
// need some explicit casting.
|
||||
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)
|
||||
llvm::Value *CGObjCGNU::generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
|
||||
const llvm::Type *ReturnTy,
|
||||
llvm::Value *Sender,
|
||||
llvm::Value *Receiver,
|
||||
llvm::Constant *Selector,
|
||||
llvm::Value *Selector,
|
||||
llvm::Value** ArgV,
|
||||
unsigned ArgC) {
|
||||
// Get the selector Type.
|
||||
const llvm::Type *PtrToInt8Ty =
|
||||
llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
|
||||
const llvm::Type *SelStructTy =
|
||||
llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, NULL);
|
||||
const llvm::Type *SelTy = llvm::PointerType::getUnqual(SelStructTy);
|
||||
|
||||
// Look up the selector.
|
||||
// If we haven't got the selector lookup function, look it up now.
|
||||
// TODO: Factor this out and use it to implement @selector() too.
|
||||
llvm::Constant *SelFunction =
|
||||
TheModule.getOrInsertFunction("sel_get_uid", SelTy, PtrToInt8Ty, NULL);
|
||||
// FIXME: Selectors should be statically cached, not looked up on every call.
|
||||
|
||||
// TODO: Pull this out into the caller.
|
||||
llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
|
||||
llvm::Constant *Ops[] = {Idx0, Idx0};
|
||||
llvm::Value *SelStr = llvm::ConstantExpr::getGetElementPtr(Selector, Ops, 2);
|
||||
llvm::Value *cmd = Builder.CreateCall(SelFunction, &SelStr, &SelStr+1);
|
||||
llvm::Value *cmd = getSelector(Builder, Selector, 0);
|
||||
|
||||
// Look up the method implementation.
|
||||
std::vector<const llvm::Type*> impArgTypes;
|
||||
impArgTypes.push_back(Receiver->getType());
|
||||
impArgTypes.push_back(SelTy);
|
||||
impArgTypes.push_back(SelectorTy);
|
||||
|
||||
// Avoid an explicit cast on the IMP by getting a version that has the right
|
||||
// return type.
|
||||
|
@ -79,8 +143,8 @@ llvm::Value *CGObjCGNU::generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
|
|||
|
||||
llvm::Constant *lookupFunction =
|
||||
TheModule.getOrInsertFunction("objc_msg_lookup",
|
||||
llvm::PointerType::get(impType, 0),
|
||||
Receiver->getType(), SelTy, NULL);
|
||||
llvm::PointerType::getUnqual(impType),
|
||||
Receiver->getType(), SelectorTy, NULL);
|
||||
llvm::SmallVector<llvm::Value*, 16> lookupArgs;
|
||||
lookupArgs.push_back(Receiver);
|
||||
lookupArgs.push_back(cmd);
|
||||
|
@ -92,6 +156,35 @@ llvm::Value *CGObjCGNU::generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
|
|||
return Builder.CreateCall(imp, lookupArgs.begin(), lookupArgs.end());
|
||||
}
|
||||
|
||||
CGObjCRuntime * clang::CodeGen::CreateObjCRuntime(llvm::Module &M) {
|
||||
return new CGObjCGNU(M);
|
||||
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);
|
||||
llvm::Function *Method = new llvm::Function(MethodTy,
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -22,8 +22,10 @@ namespace llvm {
|
|||
class Type;
|
||||
class Value;
|
||||
class Module;
|
||||
class Function;
|
||||
}
|
||||
|
||||
|
||||
namespace clang {
|
||||
namespace CodeGen {
|
||||
|
||||
|
@ -32,16 +34,35 @@ class CGObjCRuntime {
|
|||
public:
|
||||
virtual ~CGObjCRuntime();
|
||||
|
||||
// Generate an Objective-C message send operation
|
||||
/// Generate an Objective-C message send operation
|
||||
virtual llvm::Value *generateMessageSend(llvm::LLVMFoldingBuilder &Builder,
|
||||
const llvm::Type *ReturnTy,
|
||||
llvm::Value *Sender,
|
||||
llvm::Value *Receiver,
|
||||
llvm::Constant *Selector,
|
||||
llvm::Value *Selector,
|
||||
llvm::Value** ArgV,
|
||||
unsigned ArgC) = 0;
|
||||
/// Generate the function required to register all Objective-C components in
|
||||
/// this compilation unit with the runtime library.
|
||||
virtual llvm::Function *ModuleInitFunction() { return 0; }
|
||||
/// Generate a function preamble for a method with the specified types
|
||||
virtual llvm::Function *MethodPreamble(const llvm::Type *ReturnTy,
|
||||
const llvm::Type *SelfTy,
|
||||
const llvm::Type **ArgTy,
|
||||
unsigned ArgC,
|
||||
bool isVarArg) = 0;
|
||||
/// If instance variable addresses are determined at runtime then this should
|
||||
/// return true, otherwise instance variables will be accessed directly from
|
||||
/// the structure. If this returns true then @defs is invalid for this
|
||||
/// runtime and a warning should be generated.
|
||||
virtual bool LateBoundIVars() { return false; }
|
||||
};
|
||||
|
||||
CGObjCRuntime *CreateObjCRuntime(llvm::Module &M);
|
||||
/// Creates an instance of an Objective-C runtime class.
|
||||
//TODO: This should include some way of selecting which runtime to target.
|
||||
CGObjCRuntime *CreateObjCRuntime(llvm::Module &M,
|
||||
const llvm::Type *LLVMIntType,
|
||||
const llvm::Type *LLVMLongType);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -332,9 +332,6 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
|
|||
// Emit the result value, even if unused, to evalute the side effects.
|
||||
const Expr *RV = S.getRetValue();
|
||||
|
||||
QualType FnRetTy = CurFuncDecl->getType().getCanonicalType();
|
||||
FnRetTy = cast<FunctionType>(FnRetTy)->getResultType();
|
||||
|
||||
if (FnRetTy->isVoidType()) {
|
||||
// If the function returns void, emit ret void.
|
||||
Builder.CreateRetVoid();
|
||||
|
|
|
@ -26,7 +26,7 @@ using namespace CodeGen;
|
|||
|
||||
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
|
||||
: CGM(cgm), Target(CGM.getContext().Target), SwitchInsn(NULL),
|
||||
CaseRangeBlock(NULL) {}
|
||||
CaseRangeBlock(NULL) {}
|
||||
|
||||
ASTContext &CodeGenFunction::getContext() const {
|
||||
return CGM.getContext();
|
||||
|
@ -55,6 +55,80 @@ bool CodeGenFunction::hasAggregateLLVMType(QualType T) {
|
|||
!T->isVoidType() && !T->isVectorType() && !T->isFunctionType();
|
||||
}
|
||||
|
||||
/// Generate an Objective-C method. An Objective-C method is a C function with
|
||||
/// its pointer, name, and types registered in the class struture.
|
||||
// FIXME: This method contains a lot of code copied and pasted from
|
||||
// GenerateCode. This should be factored out.
|
||||
void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
|
||||
llvm::SmallVector<const llvm::Type *, 16> ParamTypes;
|
||||
for (unsigned i=0 ; i<OMD->param_size() ; i++) {
|
||||
ParamTypes.push_back(ConvertType(OMD->getParamDecl(i)->getType()));
|
||||
}
|
||||
CurFn = CGM.getObjCRuntime()->MethodPreamble(ConvertType(OMD->getResultType()),
|
||||
llvm::PointerType::getUnqual(llvm::Type::Int32Ty),
|
||||
ParamTypes.begin(),
|
||||
OMD->param_size(),
|
||||
OMD->isVariadic());
|
||||
llvm::BasicBlock *EntryBB = new llvm::BasicBlock("entry", CurFn);
|
||||
|
||||
// Create a marker to make it easy to insert allocas into the entryblock
|
||||
// later. Don't create this with the builder, because we don't want it
|
||||
// folded.
|
||||
llvm::Value *Undef = llvm::UndefValue::get(llvm::Type::Int32Ty);
|
||||
AllocaInsertPt = new llvm::BitCastInst(Undef, llvm::Type::Int32Ty, "allocapt",
|
||||
EntryBB);
|
||||
|
||||
FnRetTy = OMD->getResultType();
|
||||
|
||||
Builder.SetInsertPoint(EntryBB);
|
||||
|
||||
// Emit allocs for param decls. Give the LLVM Argument nodes names.
|
||||
llvm::Function::arg_iterator AI = CurFn->arg_begin();
|
||||
|
||||
// Name the struct return argument.
|
||||
// FIXME: Probably should be in the runtime, or it will trample the other
|
||||
// hidden arguments.
|
||||
if (hasAggregateLLVMType(OMD->getResultType())) {
|
||||
AI->setName("agg.result");
|
||||
++AI;
|
||||
}
|
||||
|
||||
// Add implicit parameters to the decl map.
|
||||
// TODO: Add something to AST to let the runtime specify the names and types
|
||||
// of these.
|
||||
llvm::Value *&DMEntry = LocalDeclMap[&(*OMD->getSelfDecl())];
|
||||
DMEntry = AI;
|
||||
++AI; ++AI;
|
||||
|
||||
|
||||
for (unsigned i = 0, e = OMD->getNumParams(); i != e; ++i, ++AI) {
|
||||
assert(AI != CurFn->arg_end() && "Argument mismatch!");
|
||||
EmitParmDecl(*OMD->getParamDecl(i), AI);
|
||||
}
|
||||
|
||||
// Emit the function body.
|
||||
EmitStmt(OMD->getBody());
|
||||
|
||||
// Emit a return for code that falls off the end. If insert point
|
||||
// is a dummy block with no predecessors then remove the block itself.
|
||||
llvm::BasicBlock *BB = Builder.GetInsertBlock();
|
||||
if (isDummyBlock(BB))
|
||||
BB->eraseFromParent();
|
||||
else {
|
||||
if (CurFn->getReturnType() == llvm::Type::VoidTy)
|
||||
Builder.CreateRetVoid();
|
||||
else
|
||||
Builder.CreateRet(llvm::UndefValue::get(CurFn->getReturnType()));
|
||||
}
|
||||
assert(BreakContinueStack.empty() &&
|
||||
"mismatched push/pop in break/continue stack!");
|
||||
|
||||
// Remove the AllocaInsertPt instruction, which is just a convenience for us.
|
||||
AllocaInsertPt->eraseFromParent();
|
||||
AllocaInsertPt = 0;
|
||||
// Verify that the function is well formed.
|
||||
assert(!verifyFunction(*CurFn) && "Generated method is not well formed.");
|
||||
}
|
||||
|
||||
void CodeGenFunction::GenerateCode(const FunctionDecl *FD) {
|
||||
LLVMIntTy = ConvertType(getContext().IntTy);
|
||||
|
@ -62,6 +136,9 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD) {
|
|||
getContext().getTypeSize(getContext().getPointerType(getContext().VoidTy)));
|
||||
|
||||
CurFuncDecl = FD;
|
||||
FnRetTy = CurFuncDecl->getType()->getAsFunctionType()->getResultType();
|
||||
|
||||
|
||||
CurFn = cast<llvm::Function>(CGM.GetAddrOfFunctionDecl(FD, true));
|
||||
assert(CurFn->isDeclaration() && "Function already has body?");
|
||||
|
||||
|
@ -144,7 +221,7 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD) {
|
|||
AllocaInsertPt = 0;
|
||||
|
||||
// Verify that the function is well formed.
|
||||
assert(!verifyFunction(*CurFn));
|
||||
assert(!verifyFunction(*CurFn) && "Generated function is not well formed.");
|
||||
}
|
||||
|
||||
/// isDummyBlock - Return true if BB is an empty basic block
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#ifndef CLANG_CODEGEN_CODEGENFUNCTION_H
|
||||
#define CLANG_CODEGEN_CODEGENFUNCTION_H
|
||||
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/LLVMBuilder.h"
|
||||
|
@ -27,8 +28,8 @@ namespace clang {
|
|||
class ASTContext;
|
||||
class Decl;
|
||||
class FunctionDecl;
|
||||
class ObjCMethodDecl;
|
||||
class TargetInfo;
|
||||
class QualType;
|
||||
class FunctionTypeProto;
|
||||
|
||||
class Stmt;
|
||||
|
@ -66,6 +67,7 @@ namespace clang {
|
|||
class ChooseExpr;
|
||||
class PreDefinedExpr;
|
||||
class ObjCStringLiteral;
|
||||
class ObjCIvarRefExpr;
|
||||
class MemberExpr;
|
||||
|
||||
class BlockVarDecl;
|
||||
|
@ -245,6 +247,7 @@ public:
|
|||
llvm::LLVMFoldingBuilder Builder;
|
||||
|
||||
const FunctionDecl *CurFuncDecl;
|
||||
QualType FnRetTy;
|
||||
llvm::Function *CurFn;
|
||||
|
||||
/// AllocaInsertPoint - This is an instruction in the entry block before which
|
||||
|
@ -286,6 +289,7 @@ public:
|
|||
|
||||
ASTContext &getContext() const;
|
||||
|
||||
void GenerateObjCMethod(const ObjCMethodDecl *OMD);
|
||||
void GenerateCode(const FunctionDecl *FD);
|
||||
|
||||
const llvm::Type *ConvertType(QualType T);
|
||||
|
@ -422,7 +426,8 @@ public:
|
|||
|
||||
LValue EmitLValueForField(llvm::Value* Base, FieldDecl* Field,
|
||||
bool isUnion);
|
||||
|
||||
|
||||
LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E);
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Scalar Expression Emission
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
|
@ -34,10 +34,16 @@ CodeGenModule::CodeGenModule(ASTContext &C, const LangOptions &LO,
|
|||
: Context(C), Features(LO), TheModule(M), TheTargetData(TD), Diags(diags),
|
||||
Types(C, M, TD), MemCpyFn(0), MemSetFn(0), CFConstantStringClassRef(0) {
|
||||
//TODO: Make this selectable at runtime
|
||||
Runtime = CreateObjCRuntime(M);
|
||||
Runtime = CreateObjCRuntime(M,
|
||||
getTypes().ConvertType(getContext().IntTy),
|
||||
getTypes().ConvertType(getContext().LongTy));
|
||||
}
|
||||
|
||||
CodeGenModule::~CodeGenModule() {
|
||||
llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction();
|
||||
if (ObjCInitFunction) {
|
||||
AddGlobalCtor(ObjCInitFunction);
|
||||
}
|
||||
EmitGlobalCtors();
|
||||
delete Runtime;
|
||||
}
|
||||
|
@ -70,7 +76,10 @@ void CodeGenModule::AddGlobalCtor(llvm::Function * Ctor) {
|
|||
GlobalCtors.push_back(Ctor);
|
||||
}
|
||||
|
||||
/// EmitGlobalCtors - Generates the array of contsturctor functions to be
|
||||
/// called on module load, if any have been registered with AddGlobalCtor.
|
||||
void CodeGenModule::EmitGlobalCtors() {
|
||||
if (GlobalCtors.empty()) return;
|
||||
// Get the type of @llvm.global_ctors
|
||||
std::vector<const llvm::Type*> CtorFields;
|
||||
CtorFields.push_back(llvm::IntegerType::get(32));
|
||||
|
@ -114,6 +123,8 @@ void CodeGenModule::EmitGlobalCtors() {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// ReplaceMapValuesWith - This is a really slow and bad function that
|
||||
/// searches for any entries in GlobalDeclMap that point to OldVal, changing
|
||||
/// them to point to NewVal. This is badbadbad, FIXME!
|
||||
|
@ -263,6 +274,12 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
|
|||
}
|
||||
|
||||
|
||||
void CodeGenModule::EmitObjCMethod(const ObjCMethodDecl *OMD) {
|
||||
// If this is not a prototype, emit the body.
|
||||
if (OMD->getBody())
|
||||
CodeGenFunction(*this).GenerateObjCMethod(OMD);
|
||||
}
|
||||
|
||||
void CodeGenModule::EmitFunction(const FunctionDecl *FD) {
|
||||
// If this is not a prototype, emit the body.
|
||||
if (FD->getBody())
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace llvm {
|
|||
namespace clang {
|
||||
class ASTContext;
|
||||
class FunctionDecl;
|
||||
class ObjCMethodDecl;
|
||||
class Decl;
|
||||
class Expr;
|
||||
class Stmt;
|
||||
|
@ -100,6 +101,7 @@ public:
|
|||
void AddGlobalCtor(llvm::Function * Ctor);
|
||||
void EmitGlobalCtors(void);
|
||||
|
||||
void EmitObjCMethod(const ObjCMethodDecl *OMD);
|
||||
void EmitFunction(const FunctionDecl *FD);
|
||||
void EmitGlobalVar(const FileVarDecl *D);
|
||||
void EmitGlobalVarDeclarator(const FileVarDecl *D);
|
||||
|
|
|
@ -144,7 +144,22 @@ void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) {
|
|||
cast<llvm::OpaqueType>(OpaqueHolder.get())->refineAbstractTypeTo(NT);
|
||||
}
|
||||
|
||||
|
||||
/// Produces a vector containing the all of the instance variables in an
|
||||
/// Objective-C object, in the order that they appear. Used to create LLVM
|
||||
/// structures corresponding to Objective-C objects.
|
||||
void CodeGenTypes::CollectObjCIvarTypes(ObjCInterfaceDecl *ObjCClass,
|
||||
std::vector<const llvm::Type*> &IvarTypes) {
|
||||
ObjCInterfaceDecl *SuperClass = ObjCClass->getSuperClass();
|
||||
if(SuperClass) {
|
||||
CollectObjCIvarTypes(SuperClass, IvarTypes);
|
||||
}
|
||||
for(ObjCInterfaceDecl::ivar_iterator ivar=ObjCClass->ivar_begin() ;
|
||||
ivar != ObjCClass->ivar_end() ;
|
||||
ivar++) {
|
||||
IvarTypes.push_back(ConvertType((*ivar)->getType()));
|
||||
ObjCIvarInfo[*ivar] = IvarTypes.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
|
||||
const clang::Type &Ty = *T.getCanonicalType();
|
||||
|
@ -263,9 +278,21 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
|
|||
case Type::ASQual:
|
||||
return ConvertType(QualType(cast<ASQualType>(Ty).getBaseType(), 0));
|
||||
|
||||
case Type::ObjCInterface:
|
||||
assert(0 && "FIXME: add missing functionality here");
|
||||
break;
|
||||
case Type::ObjCInterface: {
|
||||
// Warning: Use of this is strongly discouraged. Late binding of instance
|
||||
// variables is supported on some runtimes and so using static binding can
|
||||
// break code when libraries are updated. Only use this if you have
|
||||
// previously checked that the ObjCRuntime subclass in use does not support
|
||||
// late-bound ivars.
|
||||
ObjCInterfaceType OIT = cast<ObjCInterfaceType>(Ty);
|
||||
std::vector<const llvm::Type*> IvarTypes;
|
||||
// Pointer to the class. This is just a placeholder. Operations that
|
||||
// actually use the isa pointer should cast it to the Class type provided
|
||||
// by the runtime.
|
||||
IvarTypes.push_back(llvm::PointerType::getUnqual(llvm::Type::Int8Ty));
|
||||
CollectObjCIvarTypes(OIT.getDecl(), IvarTypes);
|
||||
return llvm::StructType::get(IvarTypes);
|
||||
}
|
||||
|
||||
case Type::ObjCQualifiedInterface:
|
||||
assert(0 && "FIXME: add missing functionality here");
|
||||
|
@ -399,6 +426,13 @@ unsigned CodeGenTypes::getLLVMFieldNo(const FieldDecl *FD) {
|
|||
return I->second;
|
||||
}
|
||||
|
||||
unsigned CodeGenTypes::getLLVMFieldNo(const ObjCIvarDecl *OID) {
|
||||
llvm::DenseMap<const ObjCIvarDecl*, unsigned>::iterator
|
||||
I = ObjCIvarInfo.find(OID);
|
||||
assert (I != ObjCIvarInfo.end() && "Unable to find field info");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
/// addFieldInfo - Assign field number to field FD.
|
||||
void CodeGenTypes::addFieldInfo(const FieldDecl *FD, unsigned No) {
|
||||
FieldInfo[FD] = No;
|
||||
|
|
|
@ -34,6 +34,8 @@ namespace clang {
|
|||
class FunctionTypeProto;
|
||||
class FieldDecl;
|
||||
class RecordDecl;
|
||||
class ObjCInterfaceDecl;
|
||||
class ObjCIvarDecl;
|
||||
|
||||
namespace CodeGen {
|
||||
class CodeGenTypes;
|
||||
|
@ -86,6 +88,7 @@ class CodeGenTypes {
|
|||
/// FieldInfo - This maps struct field with corresponding llvm struct type
|
||||
/// field no. This info is populated by record organizer.
|
||||
llvm::DenseMap<const FieldDecl *, unsigned> FieldInfo;
|
||||
llvm::DenseMap<const ObjCIvarDecl *, unsigned> ObjCIvarInfo;
|
||||
|
||||
public:
|
||||
class BitFieldInfo {
|
||||
|
@ -128,12 +131,15 @@ public:
|
|||
/// memory representation is usually i8 or i32, depending on the target.
|
||||
const llvm::Type *ConvertTypeForMem(QualType T);
|
||||
|
||||
void CollectObjCIvarTypes(ObjCInterfaceDecl *ObjCClass,
|
||||
std::vector<const llvm::Type*> &IvarTypes);
|
||||
|
||||
const CGRecordLayout *getCGRecordLayout(const TagDecl*) const;
|
||||
|
||||
/// getLLVMFieldNo - Return llvm::StructType element number
|
||||
/// that corresponds to the field FD.
|
||||
unsigned getLLVMFieldNo(const FieldDecl *FD);
|
||||
unsigned getLLVMFieldNo(const ObjCIvarDecl *OID);
|
||||
|
||||
|
||||
/// UpdateCompletedType - When we find the full definition for a TagDecl,
|
||||
|
|
|
@ -65,6 +65,10 @@ namespace {
|
|||
Builder->EmitFunction(FD);
|
||||
} else if (FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
|
||||
Builder->EmitGlobalVarDeclarator(FVD);
|
||||
} else if (isa<ObjCClassDecl>(D) || isa<ObjCCategoryDecl>(D)) {
|
||||
// Forward declaration. Only used for type checking.
|
||||
} else if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)){
|
||||
Builder->EmitObjCMethod(OMD);
|
||||
} else if (LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(D)) {
|
||||
if (LSD->getLanguage() == LinkageSpecDecl::lang_cxx)
|
||||
Builder->WarnUnsupported(LSD, "linkage spec");
|
||||
|
|
Loading…
Reference in New Issue