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:
Chris Lattner 2008-03-30 23:03:07 +00:00
parent dd0ace574b
commit 4bd5596d08
13 changed files with 357 additions and 53 deletions

View File

@ -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

View File

@ -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());
}

View File

@ -23,3 +23,4 @@ llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E){
return CGM.GetAddrOfConstantCFString(S);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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
//===--------------------------------------------------------------------===//

View File

@ -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())

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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");