Objective-C top-level constructs code generation

Hi,

I've started splitting the Objective-C code generation stuff up into smaller diffs. This one is a bit bigger than the others will be, but the places where it touches existing code are fairly isolated so it should be relatively easy to review.

This provides implementations for the Objective-C classes, protocols and categories on the GNU runtime. I will include the implementation for the Étoilé runtime in a separate patch.

David

objc_top_level.diff (55.9 KB)

Hi David,

Index: CGObjCRuntime.h

--- CGObjCRuntime.h (revision 51550)
+++ CGObjCRuntime.h (working copy)
@@ -15,6 +15,7 @@

#ifndef CLANG_CODEGEN_OBCJRUNTIME_H
#define CLANG_CODEGEN_OBCJRUNTIME_H
+#include "llvm/ADT/SmallVector.h"

namespace llvm {
   class IRBuilder;
@@ -25,11 +26,15 @@
   class Function;
}

+//FIXME: The capitalisation of methods in this class is horribly inconsistent.

This is not useful. In some sense, it encourages someone to be sloppy and hope that everything will be fixed!

namespace clang {
namespace CodeGen {

-// Implements runtime-specific code generation functions
+//FIXME Several methods should be pure virtual but aren't to avoid the
+//partially-implemented subclass breaking.

This is not specific. Remove this from here and add individual FIXMEs.

+
+/// Implements runtime-specific code generation functions.
class CGObjCRuntime {
public:
   virtual ~CGObjCRuntime();
@@ -41,16 +46,71 @@
                                            llvm::Value *Receiver,
                                            llvm::Value *Selector,
                                            llvm::Value** ArgV,
- unsigned ArgC) = 0;
+ 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; }
+ virtual llvm::Function *ModuleInitFunction() =0;
+ /// Get a selector for the specified name and type values
+ virtual llvm::Value *getSelector(llvm::IRBuilder &Builder,
+ llvm::Value *SelName,
+ llvm::Value *SelTypes) =0;
+ /// Generate a constant string object
+ virtual llvm::Constant *GenerateConstantString(const char *String, const size_t
+ length) =0;
+ /// Generate a category. A category contains a list of methods (and
+ /// accompanying metadata) and a list of protocols.
+ virtual void GenerateCategory(const char *ClassName, const char *CategoryName,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodNames,

If use
   llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodNames
then you do not hard code vector size here and let each runtime implementation use it appropriate size.

+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodTypes,
+ const llvm::SmallVector<std::string, 16> &Protocols) =0;
+ /// Generate a class stucture for this class.
+ virtual void GenerateClass(
+ const char *ClassName,
+ const char *SuperClassName,
+ const int instanceSize,
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarOffsets,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodTypes,
+ const llvm::SmallVector<std::string, 16> &Protocols) =0;
+ /// Generate a reference to the named protocol.
+ virtual llvm::Value *GenerateProtocolRef(llvm::IRBuilder &Builder, const char
+ *ProtocolName) =0;
+ virtual llvm::Value *generateMessageSendSuper(llvm::IRBuilder &Builder,

GenereateMessage...

+ const llvm::Type *ReturnTy,
+ llvm::Value *Sender,
+ const char *SuperClassName,
+ llvm::Value *Receiver,
+ llvm::Value *Selector,
+ llvm::Value** ArgV,
+ unsigned ArgC) {return NULL;};
+ /// Generate the named protocol. Protocols contain method metadata but no
+ /// implementations.
+ virtual void GenerateProtocol(const char *ProtocolName,
+ const llvm::SmallVector<std::string, 16> &Protocols,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodTypes) =0;
   /// Generate a function preamble for a method with the specified types
- virtual llvm::Function *MethodPreamble(const llvm::Type *ReturnTy,
+ virtual llvm::Function *MethodPreamble(
+ const std::string &ClassName,
+ const std::string &CategoryName,
+ const std::string &MethodName,
+ const llvm::Type *ReturnTy,
                                          const llvm::Type *SelfTy,
                                          const llvm::Type **ArgTy,
                                          unsigned ArgC,
+ bool isClassMethod,
                                          bool isVarArg) = 0;
+ /// Look up the class for the specified name
+ virtual llvm::Value *LookupClass(llvm::IRBuilder &Builder, llvm::Value
+ *ClassName) =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
Index: CGObjCGNU.cpp

--- CGObjCGNU.cpp (revision 51550)
+++ CGObjCGNU.cpp (working copy)
@@ -16,11 +16,25 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/IRBuilder.h"
#include "llvm/ADT/SmallVector.h"
+#include <cstdarg>
+#include <map>

+// Some zeros used for GEPs in lots of places.
+static llvm::Constant *Zeros[] = {llvm::ConstantInt::get(llvm::Type::Int32Ty, 0),
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 0) };
+static llvm::Constant *NULLPtr = llvm::ConstantPointerNull::get(
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty));
+
+// The version of the runtime that this class targets. Must match the version
+// in the runtime.
+const static int RuntimeVersion = 8;
+static llvm::Constant *ProtocolVersion =
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 2);
namespace {
class CGObjCGNU : public clang::CodeGen::CGObjCRuntime {
private:
   llvm::Module &TheModule;
+ const llvm::StructType *SelStructTy;
   const llvm::Type *SelectorTy;
   const llvm::Type *PtrToInt8Ty;
   const llvm::Type *IMPTy;
@@ -29,10 +43,51 @@
   const llvm::Type *PtrTy;
   const llvm::Type *LongTy;
   const llvm::Type *PtrToIntTy;
+ std::vector<llvm::Constant*> Classes;
+ std::vector<llvm::Constant*> Categories;
+ std::vector<llvm::Constant*> ConstantStrings;
+ llvm::Function *LoadFunction;
+ std::map<std::string, llvm::Constant*> ExistingProtocols;
+ typedef std::pair<std::string, std::string> TypedSelector;
+ std::map<TypedSelector, llvm::GlobalAlias*> TypedSelectors;
+ std::map<std::string, llvm::GlobalAlias*> UntypedSelectors;
+private:
+ llvm::Constant *GenerateIvarList(
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarOffsets);
+ llvm::Constant *GenerateMethodList(const std::string &ClassName,
+ const std::string &CategoryName,
+ const llvm::SmallVector<llvm::Constant*, 16> &MethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &MethodTypes,
+ bool isClassMethodList);
+ llvm::Constant *GenerateProtocolList(
+ const llvm::SmallVector<std::string, 16> &Protocols);
+ llvm::Constant *GenerateClassStructure(
+ llvm::Constant *MetaClass,
+ llvm::Constant *SuperClass,
+ unsigned info,
+ llvm::Constant *Name,
+ llvm::Constant *Version,
+ llvm::Constant *InstanceSize,
+ llvm::Constant *IVars,
+ llvm::Constant *Methods,
+ llvm::Constant *Protocols);
+ llvm::Constant *GenerateProtocolMethodList(
+ const llvm::SmallVector<llvm::Constant*, 16> &MethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &MethodTypes);
+ llvm::Constant *MakeConstantString(const std::string &Str, const std::string
+ &Name="");
+ llvm::Constant *MakeGlobal(const llvm::StructType *Ty,
+ std::vector<llvm::Constant*> V, std::string Name="");
+ llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty,
+ std::vector<llvm::Constant*> V, std::string Name="");
public:
   CGObjCGNU(llvm::Module &Mp,
     const llvm::Type *LLVMIntType,
     const llvm::Type *LLVMLongType);
+ virtual llvm::Constant *GenerateConstantString(const char *String, const size_t
+ length);
   virtual llvm::Value *generateMessageSend(llvm::IRBuilder &Builder,
                                            const llvm::Type *ReturnTy,
                                            llvm::Value *Sender,
@@ -40,17 +95,74 @@
                                            llvm::Value *Selector,
                                            llvm::Value** ArgV,
                                            unsigned ArgC);
- llvm::Value *getSelector(llvm::IRBuilder &Builder,
+ virtual llvm::Value *generateMessageSendSuper(llvm::IRBuilder &Builder,
+ const llvm::Type *ReturnTy,
+ llvm::Value *Sender,
+ const char *SuperClassName,
+ llvm::Value *Receiver,
+ llvm::Value *Selector,
+ llvm::Value** ArgV,
+ unsigned ArgC);
+ virtual llvm::Value *LookupClass(llvm::IRBuilder &Builder, llvm::Value
+ *ClassName);
+ virtual llvm::Value *getSelector(llvm::IRBuilder &Builder,

GetSelector ...

       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);
+ virtual llvm::Function *MethodPreamble(
+ const std::string &ClassName,
+ const std::string &CategoryName,
+ const std::string &MethodName,
+ const llvm::Type *ReturnTy,
+ const llvm::Type *SelfTy,
+ const llvm::Type **ArgTy,
+ unsigned ArgC,
+ bool isClassMethod,
+ bool isVarArg);
+ virtual void GenerateCategory(const char *ClassName, const char *CategoryName,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodTypes,
+ const llvm::SmallVector<std::string, 16> &Protocols);
+ virtual void GenerateClass(
+ const char *ClassName,
+ const char *SuperClassName,
+ const int instanceSize,
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarOffsets,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodTypes,
+ const llvm::SmallVector<std::string, 16> &Protocols);
+ virtual llvm::Value *GenerateProtocolRef(llvm::IRBuilder &Builder, const char
+ *ProtocolName);
+ virtual void GenerateProtocol(const char *ProtocolName,
+ const llvm::SmallVector<std::string, 16> &Protocols,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodTypes);
+ virtual llvm::Function *ModuleInitFunction();
};
} // end anonymous namespace

+
+static std::string SymbolNameForClass(std::string ClassName) {
+ return ".objc_class_" + ClassName;
+}
+
+static std::string SymbolNameForMethod(const std::string &ClassName, const
+ std::string CategoryName, const std::string MethodName, bool isClassMethod)
+{
+ if (isClassMethod) {
+ return "._objc_method_" + ClassName +"("+CategoryName+")"+ "+" + MethodName;
+ }

nit pick. Use { } only if the block is more then 1 line.

+ return "._objc_method_" + ClassName +"("+CategoryName+")"+ "-" + MethodName;
+}
+
CGObjCGNU::CGObjCGNU(llvm::Module &M,
     const llvm::Type *LLVMIntType,
     const llvm::Type *LLVMLongType) :
@@ -62,11 +174,12 @@
   PtrToInt8Ty =
     llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
   // Get the selector Type.
- const llvm::Type *SelStructTy = llvm::StructType::get(
+ SelStructTy = llvm::StructType::get(
       PtrToInt8Ty,
       NULL);
   SelectorTy = llvm::PointerType::getUnqual(SelStructTy);
+ M.addTypeName(".objc_selector", SelectorTy);
   PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
   PtrTy = PtrToInt8Ty;

@@ -77,24 +190,65 @@
   llvm::cast<llvm::OpaqueType>(OpaqueObjTy.get())->refineAbstractTypeTo(IdTy);
   IdTy = llvm::cast<llvm::StructType>(OpaqueObjTy.get());
   IdTy = llvm::PointerType::getUnqual(IdTy);
+ M.addTypeName(".objc_id", IdTy);

   // IMP type
   std::vector<const llvm::Type*> IMPArgs;
   IMPArgs.push_back(IdTy);
   IMPArgs.push_back(SelectorTy);
   IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true);
-
+ M.addTypeName(".objc_imp", IMPTy);
}
+// This has to perform the lookup every time, since posing and related
+// techniques can modify the name -> class mapping.
+llvm::Value *CGObjCGNU::LookupClass(llvm::IRBuilder &Builder,
+ llvm::Value *ClassName) {
+ llvm::Constant *ClassLookupFn =
+ TheModule.getOrInsertFunction("objc_lookup_class", IdTy, PtrToInt8Ty,
+ NULL);
+ return Builder.CreateCall(ClassLookupFn, ClassName);
+}

/// 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::IRBuilder &Builder,
     llvm::Value *SelName,
- llvm::Value *SelTypes)
-{
- // Look up the selector.
+ llvm::Value *SelTypes) {
+ // For static selectors, we return an alias for now then store them all in a
+ // list that the runtime will initialise later.
+ if (llvm::Constant *CName = llvm::dyn_cast<llvm::Constant>(SelName)) {
+ // Untyped selector
+ if (SelTypes == 0) {
+ // If it's already cached, return it.
+ if (UntypedSelectors[CName->getStringValue()]) {
+ return Builder.CreateLoad(UntypedSelectors[CName->getStringValue()]);
+ }
+ // If it isn't, cache it.
+ llvm::GlobalAlias *Sel = new llvm::GlobalAlias(llvm::PointerType::getUnqual(SelectorTy),
+ llvm::GlobalValue::InternalLinkage, ".objc_untyped_selector_alias", NULL,
+ &TheModule);
+ UntypedSelectors[CName->getStringValue()] = Sel;
+ return Builder.CreateLoad(Sel);
+ }
+ // Typed selectors
+ if (llvm::Constant *CTypes = llvm::dyn_cast<llvm::Constant>(SelTypes)) {
+ TypedSelector Selector = TypedSelector(CName->getStringValue(),
+ CTypes->getStringValue());
+ // If it's already cached, return it.
+ if (TypedSelectors[Selector]) {
+ return Builder.CreateLoad(TypedSelectors[Selector]);
+ }
+ // If it isn't, cache it.
+ llvm::GlobalAlias *Sel = new llvm::GlobalAlias(llvm::PointerType::getUnqual(SelectorTy),
+ llvm::GlobalValue::InternalLinkage, ".objc_typed_selector_alias", NULL,
+ &TheModule);
+ TypedSelectors[Selector] = Sel;
+ return Builder.CreateLoad(Sel);
+ }
+ }
+ // Dynamically look up selectors from non-constant sources
   llvm::Value *cmd;
- if(SelTypes == 0) {
+ if (SelTypes == 0) {
     llvm::Constant *SelFunction = TheModule.getOrInsertFunction("sel_get_uid",
         SelectorTy,
         PtrToInt8Ty,
@@ -114,10 +268,88 @@
}

+llvm::Constant *CGObjCGNU::MakeConstantString(const std::string &Str, const
+ std::string &Name) {
+ llvm::Constant * ConstStr = llvm::ConstantArray::get(Str);
+ ConstStr = new llvm::GlobalVariable(ConstStr->getType(), true,
+ llvm::GlobalValue::InternalLinkage,
+ ConstStr, Name, &TheModule);
+ return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2);
+}
+llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty,
+ std::vector<llvm::Constant*> V, std::string Name) {

Please use vector reference here

+ llvm::Constant *C = llvm::ConstantStruct::get(Ty, V);
+ return new llvm::GlobalVariable(Ty, false,
+ llvm::GlobalValue::InternalLinkage, C, Name, &TheModule);
+}
+llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
+ std::vector<llvm::Constant*> V, std::string Name) {

and here.

+ llvm::Constant *C = llvm::ConstantArray::get(Ty, V);
+ return new llvm::GlobalVariable(Ty, false,
+ llvm::GlobalValue::InternalLinkage, C, Name, &TheModule);
+}
+
+/// Generate an NSConstantString object.
+//TODO: In case there are any crazy people still using Objective-C without an
+//OpenStep implementation, this should let them select their own class for
+//constant strings.

:slight_smile: Here, you want to say "GNU Objective-C runtime" here.

+llvm::Constant *CGObjCGNU::GenerateConstantString(const char *String, const
+ size_t length) {
+ std::vector<llvm::Constant*> Ivars;
+ Ivars.push_back(NULLPtr);
+ Ivars.push_back(MakeConstantString(String));
+ Ivars.push_back(llvm::ConstantInt::get(IntTy, length));
+ llvm::Constant *ObjCStr = MakeGlobal(
+ llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, IntTy, NULL),
+ Ivars, ".objc_str");
+ ConstantStrings.push_back(
+ llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty));
+ return ObjCStr;
+}
+llvm::Value *CGObjCGNU::generateMessageSendSuper(llvm::IRBuilder &Builder,
+ const llvm::Type *ReturnTy,
+ llvm::Value *Sender,
+ const char *SuperClassName,
+ llvm::Value *Receiver,
+ llvm::Value *Selector,
+ llvm::Value** ArgV,
+ unsigned ArgC) {
+ // TODO: This should be cached, not looked up every time.
+ llvm::Value *ReceiverClass = LookupClass(Builder,
+ MakeConstantString(SuperClassName));
+ llvm::Value *cmd = getSelector(Builder, Selector, 0);
+ std::vector<const llvm::Type*> impArgTypes;
+ impArgTypes.push_back(Receiver->getType());
+ impArgTypes.push_back(SelectorTy);
+
+ // 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);
+ // Construct the structure used to look up the IMP
+ llvm::StructType *ObjCSuperTy = llvm::StructType::get(Receiver->getType(),
+ IdTy, NULL);
+ llvm::Value *ObjCSuper = Builder.CreateAlloca(ObjCSuperTy);
+ Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0));
+ Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1));
+
+ // Get the IMP
+ llvm::Constant *lookupFunction =
+ TheModule.getOrInsertFunction("objc_msg_lookup_super",
+ llvm::PointerType::getUnqual(impType),
+ llvm::PointerType::getUnqual(ObjCSuperTy),
+ SelectorTy, NULL);
+ llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
+ llvm::Value *imp = Builder.CreateCall(lookupFunction, lookupArgs, lookupArgs+2);
+
+ // Call the method
+ llvm::SmallVector<llvm::Value*, 8> callArgs;
+ callArgs.push_back(Receiver);
+ callArgs.push_back(cmd);
+ callArgs.insert(callArgs.end(), ArgV, ArgV+ArgC);
+ return Builder.CreateCall(imp, callArgs.begin(), callArgs.end());
+}
/// 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::IRBuilder &Builder,
                                             const llvm::Type *ReturnTy,
                                             llvm::Value *Sender,
@@ -129,12 +361,21 @@

   // Look up the method implementation.
   std::vector<const llvm::Type*> impArgTypes;
+ const llvm::Type *RetTy;
+ if (ReturnTy->isFirstClassType() && ReturnTy != llvm::Type::VoidTy) {

Now, isSingleType() is now preferred over isFirstClassType() here and other places where you check return type.

+ RetTy = ReturnTy;
+ } else {
+ // For struct returns allocate the space in the caller and pass it up to
+ // the sender.

Note, LLVM is moving in the direction to where return will be able to return aggregates.

+ RetTy = llvm::Type::VoidTy;
+ impArgTypes.push_back(llvm::PointerType::getUnqual(ReturnTy));
+ }
   impArgTypes.push_back(Receiver->getType());
   impArgTypes.push_back(SelectorTy);

   // 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,
+ llvm::FunctionType *impType = llvm::FunctionType::get(RetTy, impArgTypes,
                                                         true);

   llvm::Constant *lookupFunction =
@@ -144,20 +385,480 @@
   llvm::Value *imp = Builder.CreateCall2(lookupFunction, Receiver, cmd);

   // Call the method.
- llvm::SmallVector<llvm::Value*, 16> lookupArgs;
- lookupArgs.push_back(Receiver);
- lookupArgs.push_back(cmd);
- lookupArgs.insert(lookupArgs.end(), ArgV, ArgV+ArgC);
- return Builder.CreateCall(imp, lookupArgs.begin(), lookupArgs.end());
+ if (ReturnTy->isFirstClassType() && ReturnTy != llvm::Type::VoidTy) {
+ llvm::SmallVector<llvm::Value*, 16> Args;
+ Args.push_back(Receiver);
+ Args.push_back(cmd);
+ Args.insert(Args.end(), ArgV, ArgV+ArgC);
+ return Builder.CreateCall(imp, Args.begin(), Args.end());
+ } else {
+ llvm::SmallVector<llvm::Value*, 16> Args;
+ llvm::Value *Return = Builder.CreateAlloca(ReturnTy);
+ Args.push_back(Return);
+ Args.push_back(Receiver);
+ Args.push_back(cmd);
+ Args.insert(Args.end(), ArgV, ArgV+ArgC);
+ Builder.CreateCall(imp, Args.begin(), Args.end());
+ return Return;
+ }
}

+/// Generates a MethodList. Used in construction of a objc_class and
+/// objc_category structures.
+llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName,
+ const std::string &CategoryName, const llvm::SmallVector<llvm::Constant*,
+ 16> &MethodNames, const llvm::SmallVector<llvm::Constant*, 16>
+ &MethodTypes, bool isClassMethodList) {
+ // Get the method structure type.
+ llvm::StructType *ObjCMethodTy = llvm::StructType::get(
+ PtrToInt8Ty, // Really a selector, but the runtime creates it us.
+ PtrToInt8Ty, // Method types
+ llvm::PointerType::getUnqual(IMPTy), //Method pointer
+ NULL);
+ std::vector<llvm::Constant*> Methods;
+ std::vector<llvm::Constant*> Elements;
+ for(unsigned int i=0 ; i<MethodTypes.size() ; i++) {

for (unsigned int i = 0, e < MethodTypes.size(); i != e; ++i) {

+ Elements.clear();
+ Elements.push_back( llvm::ConstantExpr::getGetElementPtr(MethodNames[i],
+ Zeros, 2));
+ Elements.push_back(
+ llvm::ConstantExpr::getGetElementPtr(MethodTypes[i], Zeros, 2));
+ llvm::Constant *Method =
+ TheModule.getFunction(SymbolNameForMethod(ClassName, CategoryName,
+ MethodNames[i]->getStringValue(), isClassMethodList));
+ Method = llvm::ConstantExpr::getBitCast(Method,
+ llvm::PointerType::getUnqual(IMPTy));
+ Elements.push_back(Method);
+ Methods.push_back(llvm::ConstantStruct::get(ObjCMethodTy, Elements));
+ }
+
+ // Array of method structures
+ llvm::ArrayType *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodTy,
+ MethodNames.size());
+ llvm::Constant *MethodArray = llvm::ConstantArray::get(ObjCMethodArrayTy,
+ Methods);
+
+ // Structure containing list pointer, array and array count
+ llvm::SmallVector<const llvm::Type*, 16> ObjCMethodListFields;
+ llvm::PATypeHolder OpaqueNextTy = llvm::OpaqueType::get();
+ llvm::Type *NextPtrTy = llvm::PointerType::getUnqual(OpaqueNextTy);
+ llvm::StructType *ObjCMethodListTy = llvm::StructType::get(NextPtrTy,
+ IntTy,
+ ObjCMethodArrayTy,
+ NULL);
+ // Refine next pointer type to concrete type
+ llvm::cast<llvm::OpaqueType>(
+ OpaqueNextTy.get())->refineAbstractTypeTo(ObjCMethodListTy);
+ ObjCMethodListTy = llvm::cast<llvm::StructType>(OpaqueNextTy.get());
+
+ Methods.clear();
+ Methods.push_back(llvm::ConstantPointerNull::get(
+ llvm::PointerType::getUnqual(ObjCMethodListTy)));
+ Methods.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty,
+ MethodTypes.size()));
+ Methods.push_back(MethodArray);
+
+ // Create an instance of the structure
+ return MakeGlobal(ObjCMethodListTy, Methods, ".objc_method_list");
+}
+
+/// Generates an IvarList. Used in construction of a objc_class
+llvm::Constant *CGObjCGNU::GenerateIvarList(
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarOffsets) {
+ // Get the method structure type.
+ llvm::StructType *ObjCIvarTy = llvm::StructType::get(
+ PtrToInt8Ty,
+ IntTy,
+ NULL);
+ std::vector<llvm::Constant*> Ivars;
+ std::vector<llvm::Constant*> Elements;
+ for(unsigned int i=0 ; i<IvarNames.size() ; i++) {
+ Elements.clear();
+ Elements.push_back( llvm::ConstantExpr::getGetElementPtr(IvarNames[i],
+ Zeros, 2));
+ Elements.push_back( llvm::ConstantExpr::getGetElementPtr(IvarTypes[i],
+ Zeros, 2));
+ Elements.push_back(IvarOffsets[i]);
+ Ivars.push_back(llvm::ConstantStruct::get(ObjCIvarTy, Elements));
+ }
+
+ // Array of method structures
+ llvm::ArrayType *ObjCIvarArrayTy = llvm::ArrayType::get(ObjCIvarTy,
+ IvarNames.size());
+
+ Elements.clear();
+ Elements.push_back(llvm::ConstantInt::get(
+ llvm::cast<llvm::IntegerType>(IntTy), (int)IvarNames.size()));
+ Elements.push_back(llvm::ConstantArray::get(ObjCIvarArrayTy, Ivars));
+ // Structure containing array and array count
+ llvm::StructType *ObjCIvarListTy = llvm::StructType::get(IntTy,
+ ObjCIvarArrayTy,
+ NULL);
+
+ // Create an instance of the structure
+ return MakeGlobal(ObjCIvarListTy, Elements, ".objc_ivar_list");
+}
+
+/// Generate a class structure
+llvm::Constant *CGObjCGNU::GenerateClassStructure(
+ llvm::Constant *MetaClass,
+ llvm::Constant *SuperClass,
+ unsigned info,
+ llvm::Constant *Name,
+ llvm::Constant *Version,
+ llvm::Constant *InstanceSize,
+ llvm::Constant *IVars,
+ llvm::Constant *Methods,
+ llvm::Constant *Protocols) {
+ // Set up the class structure
+ // Note: Several of these are char*s when they should be ids. This is
+ // because the runtime performs this translation on load.
+ llvm::StructType *ClassTy = llvm::StructType::get(
+ PtrToInt8Ty, // class_pointer
+ PtrToInt8Ty, // super_class
+ PtrToInt8Ty, // name
+ LongTy, // version
+ LongTy, // info
+ LongTy, // instance_size
+ IVars->getType(), // ivars
+ Methods->getType(), // methods
+ // These are all filled in by the runtime, so we pretend
+ PtrTy, // dtable
+ PtrTy, // subclass_list
+ PtrTy, // sibling_class
+ PtrTy, // protocols
+ PtrTy, // gc_object_type
+ NULL);
+ llvm::Constant *Zero = llvm::ConstantInt::get(LongTy, 0);
+ llvm::Constant *NullP =
+ llvm::ConstantPointerNull::get(llvm::cast<llvm::PointerType>(PtrTy));
+ // Fill in the structure
+ std::vector<llvm::Constant*> Elements;
+ Elements.push_back(llvm::ConstantExpr::getBitCast(MetaClass, PtrToInt8Ty));
+ Elements.push_back(SuperClass);
+ Elements.push_back(Name);
+ Elements.push_back(Zero);
+ Elements.push_back(llvm::ConstantInt::get(LongTy, info));
+ Elements.push_back(InstanceSize);
+ Elements.push_back(IVars);
+ Elements.push_back(Methods);
+ Elements.push_back(NullP);
+ Elements.push_back(llvm::ConstantExpr::getBitCast(Protocols, PtrTy));
+ Elements.push_back(NullP);
+ // Create an instance of the structure
+ return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name->getStringValue()));
+}

Add extra line before starting new function.

+llvm::Constant *CGObjCGNU::GenerateProtocolMethodList(
+ const llvm::SmallVector<llvm::Constant*, 16> &MethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &MethodTypes) {
+ // Get the method structure type.
+ llvm::StructType *ObjCMethodDescTy = llvm::StructType::get(
+ PtrToInt8Ty, // Really a selector, but the runtime does the casting for us.
+ PtrToInt8Ty,
+ NULL);
+ std::vector<llvm::Constant*> Methods;
+ std::vector<llvm::Constant*> Elements;
+ for(unsigned int i=0 ; i<MethodTypes.size() ; i++) {
+ Elements.clear();
+ Elements.push_back( llvm::ConstantExpr::getGetElementPtr(MethodNames[i],
+ Zeros, 2));
+ Elements.push_back(
+ llvm::ConstantExpr::getGetElementPtr(MethodTypes[i], Zeros, 2));
+ Methods.push_back(llvm::ConstantStruct::get(ObjCMethodDescTy, Elements));
+ }
+ llvm::ArrayType *ObjCMethodArrayTy = llvm::ArrayType::get(ObjCMethodDescTy,
+ MethodNames.size());
+ llvm::Constant *Array = llvm::ConstantArray::get(ObjCMethodArrayTy, Methods);
+ llvm::StructType *ObjCMethodDescListTy = llvm::StructType::get(
+ IntTy, ObjCMethodArrayTy, NULL);
+ Methods.clear();
+ Methods.push_back(llvm::ConstantInt::get(IntTy, MethodNames.size()));
+ Methods.push_back(Array);
+ return MakeGlobal(ObjCMethodDescListTy, Methods, ".objc_method_list");
+}
+// Create the protocol list structure used in classes, categories and so on
+llvm::Constant *CGObjCGNU::GenerateProtocolList(
+ const llvm::SmallVector<std::string, 16> &Protocols) {
+ llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(PtrToInt8Ty,
+ Protocols.size());
+ llvm::StructType *ProtocolListTy = llvm::StructType::get(
+ PtrTy, //Should be a recurisve pointer, but it's always NULL here.
+ LongTy,//FIXME: Should be size_t
+ ProtocolArrayTy,
+ NULL);
+ std::vector<llvm::Constant*> Elements;
+ for(const std::string *iter=Protocols.begin() ; iter != Protocols.end() ;
+ iter++) {
+ llvm::Constant *Ptr =
+ llvm::ConstantExpr::getBitCast(ExistingProtocols[*iter], PtrToInt8Ty);
+ Elements.push_back(Ptr);
+ }
+ llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy,
+ Elements);
+ Elements.clear();
+ Elements.push_back(NULLPtr);
+ Elements.push_back(llvm::ConstantInt::get(llvm::cast<llvm::IntegerType>(LongTy),
+ Protocols.size()));
+ Elements.push_back(ProtocolArray);
+ return MakeGlobal(ProtocolListTy, Elements, ".objc_protocol_list");
+}
+llvm::Value *CGObjCGNU::GenerateProtocolRef(llvm::IRBuilder &Builder, const char
+ *ProtocolName) {
+ return ExistingProtocols[ProtocolName];
+}
+void CGObjCGNU::GenerateProtocol(const char *ProtocolName,
+ const llvm::SmallVector<std::string, 16> &Protocols,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodTypes) {
+
+ llvm::Constant *ProtocolList = GenerateProtocolList(Protocols);
+ llvm::Constant *InstanceMethodList =
+ GenerateProtocolMethodList(InstanceMethodNames, InstanceMethodTypes);
+ llvm::Constant *ClassMethodList =
+ GenerateProtocolMethodList(ClassMethodNames, ClassMethodTypes);
+ // Protocols are objects containing lists of the methods implemented and
+ // protocols adopted.
+ llvm::StructType *ProtocolTy = llvm::StructType::get(IdTy,
+ PtrToInt8Ty,
+ ProtocolList->getType(),
+ InstanceMethodList->getType(),
+ ClassMethodList->getType(),
+ NULL);
+ std::vector<llvm::Constant*> Elements;
+ // The isa pointer must be set to a magic number so the runtime knows it's
+ // the correct layout.
+ Elements.push_back(llvm::ConstantExpr::getIntToPtr(ProtocolVersion, IdTy));
+ Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name"));
+ Elements.push_back(ProtocolList);
+ Elements.push_back(InstanceMethodList);
+ Elements.push_back(ClassMethodList);
+ ExistingProtocols[ProtocolName] =
+ llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolTy, Elements,
+ ".objc_protocol"), IdTy);
+}
+
+void CGObjCGNU::GenerateCategory(
+ const char *ClassName,
+ const char *CategoryName,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodTypes,
+ const llvm::SmallVector<std::string, 16> &Protocols) {
+ std::vector<llvm::Constant*> Elements;
+ Elements.push_back(MakeConstantString(CategoryName));
+ Elements.push_back(MakeConstantString(ClassName));
+ // Instance method list
+ Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList(ClassName,
+ CategoryName, InstanceMethodNames, InstanceMethodTypes, false),
+ PtrTy));
+ // Class method list
+ Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateMethodList(ClassName,
+ CategoryName, ClassMethodNames, ClassMethodTypes, true), PtrTy));
+ // Protocol list
+ Elements.push_back(llvm::ConstantExpr::getBitCast(GenerateProtocolList(Protocols),
+ PtrTy));
+ Categories.push_back(llvm::ConstantExpr::getBitCast(
+ MakeGlobal(llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, PtrTy,
+ PtrTy, PtrTy, NULL), Elements), PtrTy));
+}
+void CGObjCGNU::GenerateClass(
+ const char *ClassName,
+ const char *SuperClassName,
+ const int instanceSize,
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &IvarOffsets,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &InstanceMethodTypes,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodNames,
+ const llvm::SmallVector<llvm::Constant*, 16> &ClassMethodTypes,
+ const llvm::SmallVector<std::string, 16> &Protocols) {
+ // Get the superclass pointer.
+ llvm::Constant *SuperClass;
+ if (SuperClassName) {
+ SuperClass = MakeConstantString(SuperClassName, ".super_class_name");
+ } else {
+ SuperClass = llvm::ConstantPointerNull::get(
+ llvm::cast<llvm::PointerType>(PtrToInt8Ty));
+ }
+ llvm::Constant * Name = MakeConstantString(ClassName, ".class_name");
+ // Empty vector used to construct empty method lists
+ llvm::SmallVector<llvm::Constant*, 16> empty;
+ // Generate the method and instance variable lists
+ llvm::Constant *MethodList = GenerateMethodList(ClassName, "",
+ InstanceMethodNames, InstanceMethodTypes, false);
+ llvm::Constant *ClassMethodList = GenerateMethodList(ClassName, "",
+ ClassMethodNames, ClassMethodTypes, true);
+ llvm::Constant *IvarList = GenerateIvarList(IvarNames, IvarTypes,
+ IvarOffsets);
+ //Generate metaclass for class methods
+ llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr,
+ NULLPtr, 0x2L, NULLPtr, 0, Zeros[0], GenerateIvarList(
+ empty, empty, empty), ClassMethodList, NULLPtr);
+ // Generate the class structure
+ llvm::Constant *ClassStruct = GenerateClassStructure(MetaClassStruct,
+ SuperClass, 0x1L, Name, 0,
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, instanceSize), IvarList,
+ MethodList, GenerateProtocolList(Protocols));
+ // Add class structure to list to be added to the symtab later
+ ClassStruct = llvm::ConstantExpr::getBitCast(ClassStruct, PtrToInt8Ty);
+ Classes.push_back(ClassStruct);
+}
+
+llvm::Function *CGObjCGNU::ModuleInitFunction() {
+ // Only emit an ObjC load function if no Objective-C stuff has been called
+ if (Classes.size() + Categories.size() + ConstantStrings.size() +
+ ExistingProtocols.size() + TypedSelectors.size() +
+ UntypedSelectors.size() == 0) {
+ return NULL;
+ }
+ std::vector<llvm::Constant*> Elements;
+ // Generate statics list:
+ llvm::ArrayType *StaticsArrayTy = llvm::ArrayType::get(PtrToInt8Ty,
+ ConstantStrings.size() + 1);
+ ConstantStrings.push_back(NULLPtr);
+ Elements.push_back(MakeConstantString("NSConstantString",
+ ".objc_static_class_name"));
+ Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy, ConstantStrings));
+ llvm::StructType *StaticsListTy = llvm::StructType::get(PtrToInt8Ty,
+ StaticsArrayTy, NULL);
+ llvm::Constant *Statics = MakeGlobal(StaticsListTy, Elements, ".objc_statics");
+ Statics = new
+ llvm::GlobalVariable(llvm::PointerType::getUnqual(StaticsListTy), false,
+ llvm::GlobalValue::InternalLinkage, Statics, ".objc_statics_ptr",
+ &TheModule);
+ Statics = llvm::ConstantExpr::getBitCast(Statics, PtrTy);
+ // Array of classes, categories, and constant objects
+ llvm::ArrayType *ClassListTy = llvm::ArrayType::get(PtrToInt8Ty,
+ Classes.size() + Categories.size() + 2);
+ llvm::StructType *SymTabTy = llvm::StructType::get(
+ LongTy,
+ SelectorTy,
+ llvm::Type::Int16Ty,
+ ClassListTy,
+ NULL);
+
+ Elements.clear();
+ // Pointer to an array of selectors used in this module.
+ std::vector<llvm::Constant*> Selectors;
+ for(std::map<TypedSelector, llvm::GlobalAlias*>::iterator
+ iter=TypedSelectors.begin() ; iter!=TypedSelectors.end() ; iter++) {
+ Elements.push_back(MakeConstantString((*iter).first.first, ".objc_sel_name"));
+ Elements.push_back(MakeConstantString((*iter).first.first, ".objc_sel_types"));
+ Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
+ Elements.clear();
+ }
+ for(std::map<std::string, llvm::GlobalAlias*>::iterator
+ iter=UntypedSelectors.begin() ; iter!=UntypedSelectors.end() ; iter++) {
+ Elements.push_back(MakeConstantString((*iter).first, ".objc_sel_name"));
+ Elements.push_back(NULLPtr);
+ Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
+ Elements.clear();
+ }
+ Elements.push_back(NULLPtr);
+ Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements));
+ Elements.clear();
+ // Number of static selectors
+ Elements.push_back(llvm::ConstantInt::get(LongTy, Selectors.size() ));
+ llvm::Constant *SelectorList = MakeGlobal(
+ llvm::ArrayType::get(SelStructTy, Selectors.size()), Selectors,
+ ".objc_selector_list");
+ Elements.push_back(llvm::ConstantExpr::getBitCast(SelectorList, SelectorTy));
+
+ // Now that all of the static selectors exist, create pointers to them.
+ int index = 0;
+ for(std::map<TypedSelector, llvm::GlobalAlias*>::iterator
+ iter=TypedSelectors.begin() ; iter!=TypedSelectors.end() ; iter++) {

Please use

for(std::map<TypedSelector, llvm::GlobalAlias*>::iterator
    iter=TypedSelectors.begin(), iterEnd =TypedSelectors.end();
    iter != iterEnd; ++iter)

form here and other places.

+ llvm::Constant *Idxs[] = {Zeros[0],
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, index++), Zeros[0]};
+ llvm::GlobalVariable *SelPtr = new llvm::GlobalVariable(SelectorTy, true,
+ llvm::GlobalValue::InternalLinkage,
+ llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
+ ".objc_sel_ptr", &TheModule);
+ (*iter).second->setAliasee(SelPtr);
+ }
+ for(std::map<std::string, llvm::GlobalAlias*>::iterator
+ iter=UntypedSelectors.begin() ; iter!=UntypedSelectors.end() ; iter++) {
+ llvm::Constant *Idxs[] = {Zeros[0],
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, index++), Zeros[0]};
+ llvm::GlobalVariable *SelPtr = new llvm::GlobalVariable(SelectorTy, true,
+ llvm::GlobalValue::InternalLinkage,
+ llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2),
+ ".objc_sel_ptr", &TheModule);
+ (*iter).second->setAliasee(SelPtr);
+ }
+ // Number of classes defined.
+ Elements.push_back(llvm::ConstantInt::get(llvm::Type::Int16Ty,
+ Classes.size()));
+ // Number of categories defined
+ Elements.push_back(llvm::ConstantInt::get(llvm::Type::Int16Ty,
+ Categories.size()));
+ // Create an array of classes, then categories, then static object instances
+ Classes.insert(Classes.end(), Categories.begin(), Categories.end());
+ // NULL-terminated list of static object instances (mainly constant strings)
+ Classes.push_back(Statics);
+ Classes.push_back(NULLPtr);
+ llvm::Constant *ClassList = llvm::ConstantArray::get(ClassListTy, Classes);
+ Elements.push_back(ClassList);
+ // Construct the symbol table
+ llvm::Constant *SymTab= MakeGlobal(SymTabTy, Elements);
+
+ // The symbol table is contained in a module which has some version-checking
+ // constants
+ llvm::StructType * ModuleTy = llvm::StructType::get(LongTy, LongTy,
+ PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy), NULL);
+ Elements.clear();
+ // Runtime version used for compatibility checking.
+ Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion));
+ //FIXME: Should be sizeof(ModuleTy)
+ Elements.push_back(llvm::ConstantInt::get(LongTy, 16));
+ //FIXME: Should be the path to the file where this module was declared
+ Elements.push_back(NULLPtr);
+ Elements.push_back(SymTab);
+ llvm::Value *Module = MakeGlobal(ModuleTy, Elements);
+
+ // Create the load function calling the runtime entry point with the module
+ // structure
+ std::vector<const llvm::Type*> VoidArgs;
+ llvm::Function * LoadFunction = llvm::Function::Create(
+ llvm::FunctionType::get(llvm::Type::VoidTy, VoidArgs, false),
+ llvm::GlobalValue::InternalLinkage, ".objc_load_function",
+ &TheModule);
+ llvm::BasicBlock *EntryBB = llvm::BasicBlock::Create("entry", LoadFunction);
+ llvm::IRBuilder Builder;
+ Builder.SetInsertPoint(EntryBB);
+ llvm::Value *Register = TheModule.getOrInsertFunction("__objc_exec_class",
+ llvm::Type::VoidTy, llvm::PointerType::getUnqual(ModuleTy), NULL);
+ Builder.CreateCall(Register, Module);
+ Builder.CreateRetVoid();
+ return LoadFunction;
+}
llvm::Function *CGObjCGNU::MethodPreamble(
+ const std::string &ClassName,
+ const std::string &CategoryName,
+ const std::string &MethodName,
                                          const llvm::Type *ReturnTy,
                                          const llvm::Type *SelfTy,
                                          const llvm::Type **ArgTy,
                                          unsigned ArgC,
+ bool isClassMethod,
                                          bool isVarArg) {
   std::vector<const llvm::Type*> Args;
+ if (!ReturnTy->isFirstClassType() && ReturnTy != llvm::Type::VoidTy) {
+ Args.push_back(llvm::PointerType::getUnqual(ReturnTy));
+ ReturnTy = llvm::Type::VoidTy;
+ }
   Args.push_back(SelfTy);
   Args.push_back(SelectorTy);
   Args.insert(Args.end(), ArgTy, ArgTy+ArgC);
@@ -165,12 +866,20 @@
   llvm::FunctionType *MethodTy = llvm::FunctionType::get(ReturnTy,
       Args,
       isVarArg);
+ std::string FunctionName = SymbolNameForMethod(ClassName, CategoryName,
+ MethodName, isClassMethod);
+
   llvm::Function *Method = llvm::Function::Create(MethodTy,
       llvm::GlobalValue::InternalLinkage,
- ".objc.method",
+ FunctionName,
       &TheModule);
- // Set the names of the hidden arguments
   llvm::Function::arg_iterator AI = Method->arg_begin();
+ // Name the struct return argument.
+ // FIXME: This is probably the wrong test.
+ if (!ReturnTy->isFirstClassType() && ReturnTy != llvm::Type::VoidTy) {
+ AI->setName("agg.result");
+ ++AI;
+ }
   AI->setName("self");
   ++AI;
   AI->setName("_cmd");
Index: CodeGenModule.cpp

--- CodeGenModule.cpp (revision 51550)
+++ CodeGenModule.cpp (working copy)
@@ -25,6 +25,7 @@
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Intrinsics.h"
+#include "llvm/Target/TargetData.h"
#include "llvm/Analysis/Verifier.h"
#include <algorithm>
using namespace clang;
@@ -49,10 +50,10 @@
}

CodeGenModule::~CodeGenModule() {
+ EmitStatics();
   llvm::Function *ObjCInitFunction = Runtime->ModuleInitFunction();
   if (ObjCInitFunction)
     AddGlobalCtor(ObjCInitFunction);
- EmitStatics();
   EmitGlobalCtors();
   EmitAnnotations();
   delete Runtime;
@@ -328,7 +329,159 @@
   if (OMD->getBody())
     CodeGenFunction(*this).GenerateObjCMethod(OMD);
}
+void CodeGenModule::EmitObjCProtocolImplementation(const ObjCProtocolDecl *PD){

Why are these methods not runtime specific ?

+ llvm::SmallVector<std::string, 16> Protocols;
+ for(unsigned i=0 ; i<PD->getNumReferencedProtocols() ; i++)
+ {
+ Protocols.push_back(PD->getReferencedProtocols()[i]->getName());
+ }

Avoid unnecessary { and }

Hi Devang,

Thanks for the feedback. Here is a new version.

+//FIXME: The capitalisation of methods in this class is horribly
inconsistent.

This is not useful. In some sense, it encourages someone to be sloppy
and hope that everything will be fixed!

Yup, total cop-out. Fixed now.

+//FIXME Several methods should be pure virtual but aren't to avoid
the
+//partially-implemented subclass breaking.

This is not specific. Remove this from here and add individual FIXMEs.

Ooops. This is left over from earlier and is actually fixed in the code. I've removed the comment.

+ virtual void GenerateCategory(const char *ClassName, const char
*CategoryName,
+ const llvm::SmallVector<llvm::Constant*, 16>
&InstanceMethodNames,

If use
  llvm::SmallVectorImpl<llvm::Constant *> &InstanceMethodNames
then you do not hard code vector size here and let each runtime
implementation use it appropriate size.

Thanks, I was wondering if there was a sensible way of doing this. I've fixed this in the interface. There are a few places now in caller that can have their SmallVector sizes tuned a bit, but I'll wait for a later patch to do that.

+ virtual llvm::Value *generateMessageSendSuper(llvm::IRBuilder
&Builder,

GenereateMessage...

Fixed.

+ virtual llvm::Value *getSelector(llvm::IRBuilder &Builder,

GetSelector ...

Fixed.

isClassMethod)
+{
+ if (isClassMethod) {
+ return "._objc_method_" + ClassName +"("+CategoryName+")"+ "+"
+ MethodName;
+ }

nit pick. Use { } only if the block is more then 1 line.

I prefer to use blocks everywhere, since it makes it easier to see fall-through in nested conditionals and makes inserting debugging lines easier, but if LLVM coding conventions require them to not be blocks then I will try to remember in future. I've removed this one.

+ std::vector<llvm::Constant*> V, std::string Name) {

Please use vector reference here

+llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
+ std::vector<llvm::Constant*> V, std::string Name) {

and here.

Fixed.

+ llvm::Constant *C = llvm::ConstantArray::get(Ty, V);
+ return new llvm::GlobalVariable(Ty, false,
+ llvm::GlobalValue::InternalLinkage, C, Name, &TheModule);
+}
+
+/// Generate an NSConstantString object.
+//TODO: In case there are any crazy people still using Objective-C
without an
+//OpenStep implementation, this should let them select their own
class for
+//constant strings.

:slight_smile: Here, you want to say "GNU Objective-C runtime" here.

Pedantic, but since I am using this code with a Smalltalk compiler too I guess it's valid so I'll change it...
I stand by my statement that only crazy people program without OpenStep though :slight_smile:

+ if (ReturnTy->isFirstClassType() && ReturnTy !=
llvm::Type::VoidTy) {

Now, isSingleType() is now preferred over isFirstClassType() here and
other places where you check return type.

Fixed. (Presumably this was meant to be isSingleValueType()?)

+ RetTy = ReturnTy;
+ } else {
+ // For struct returns allocate the space in the caller and pass
it up to
+ // the sender.

Note, LLVM is moving in the direction to where return will be able to
return aggregates.

Someone mentioned that C ABI issues make it difficult to use this in this particular case. I have added a TODO to revisit it when LLVM gets support for aggregate return types.

+ for(unsigned int i=0 ; i<MethodTypes.size() ; i++) {

for (unsigned int i = 0, e < MethodTypes.size(); i != e; ++i) {

Fixed everywhere I found - I might have missed one or two...

+ return MakeGlobal(ClassTy, Elements, SymbolNameForClass(Name-

getStringValue()));

+}

Add extra line before starting new function.

Fixed.

+ for(std::map<TypedSelector, llvm::GlobalAlias*>::iterator
+ iter=TypedSelectors.begin() ; iter!=TypedSelectors.end() ;
iter++) {

Please use

for(std::map<TypedSelector, llvm::GlobalAlias*>::iterator
   iter=TypedSelectors.begin(), iterEnd =TypedSelectors.end();
   iter != iterEnd; ++iter)

form here and other places.

Fixed. Also added the missing space between for and the bracket.

+void CodeGenModule::EmitObjCProtocolImplementation(const
ObjCProtocolDecl *PD){

Why are these methods not runtime specific ?

These methods correspond to language features, which are runtime agnostic. They then call the runtime-specific methods which perform the target-specific things. All runtimes, for example, need to know the method names and type encodings in a protocol (and how these are found is specific to the source language, in this case Objective-C). This then calls the runtime method Runtime->GenerateProtocol, which either sets up some data structures or calls some runtime functions, depending on the runtime library being used.

+ llvm::SmallVector<std::string, 16> Protocols;
+ for(unsigned i=0 ; i<PD->getNumReferencedProtocols() ; i++)
+ {
+ Protocols.push_back(PD->getReferencedProtocols()[i]->getName());
+ }

Avoid unnecessary { and }

Fixed here and in three other places.

objc.diff (59.9 KB)

Nice! This is looking good. A few more thoughts:

+// Some zeros used for GEPs in lots of places.
+static llvm::Constant *Zeros[] = {llvm::ConstantInt::get(llvm::Type::Int32Ty, 0),
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 0) };
+static llvm::Constant *NULLPtr = llvm::ConstantPointerNull::get(
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty));
+static llvm::Constant *ProtocolVersion =
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 2);

This causes static initializers to be formed and run. Please stay away from them. Maybe these should be instance variables of the class?

+ std::map<std::string, llvm::Constant*> ExistingProtocols;
+ typedef std::pair<std::string, std::string> TypedSelector;
+ std::map<TypedSelector, llvm::GlobalAlias*> TypedSelectors;
+ std::map<std::string, llvm::GlobalAlias*> UntypedSelectors;

std::map's from std::string are really inefficient. Can you use StringMap for these?

These:
+static std::string SymbolNameForClass(std::string ClassName) {
+static std::string SymbolNameForMethod(const std::string &ClassName, const
+ std::string CategoryName, const std::string MethodName, bool isClassMethod)

Copy the std::string objects. Please pass as "const std::string &foo" to avoid this. Likewise in a few other places (e.g. MakeGlobal)

+ if (isClassMethod)
+ return "._objc_method_" + ClassName +"("+CategoryName+")"+ "+" + MethodName;
+ return "._objc_method_" + ClassName +"("+CategoryName+")"+ "-" + MethodName;
+}

How about something like:
   return "._objc_method_" + ClassName +"("+CategoryName+")"+
         (isClassMethod ? "+" : "-") + MethodName;

To make it more obvious what the difference is between the two.

+ if (ReturnTy->isSingleValueType() && ReturnTy != llvm::Type::VoidTy) {
+ llvm::SmallVector<llvm::Value*, 16> Args;
+ Args.push_back(Receiver);
+ Args.push_back(cmd);
+ Args.insert(Args.end(), ArgV, ArgV+ArgC);
+ return Builder.CreateCall(imp, Args.begin(), Args.end());
+ } else {
+ llvm::SmallVector<llvm::Value*, 16> Args;
+ llvm::Value *Return = Builder.CreateAlloca(ReturnTy);
+ Args.push_back(Return);
+ Args.push_back(Receiver);
+ Args.push_back(cmd);
+ Args.insert(Args.end(), ArgV, ArgV+ArgC);
+ Builder.CreateCall(imp, Args.begin(), Args.end());
+ return Return;
+ }

Is there a specific reason not to share the common code here?

+void CGObjCGNU::GenerateProtocol(const char *ProtocolName,

It would be nice to add a block comment above each of these methods with a C struct (in the comment) that describes the thing that you are generating. This would make it easier to follow the code.

+ if (Classes.size() + Categories.size() + ConstantStrings.size() +
+ ExistingProtocols.size() + TypedSelectors.size() +
+ UntypedSelectors.size() == 0) {

It is generally better to query .empty() instead of .size() if you just care about whether it is empty or not. Also, using "if (x.empty() && y.empty() && z.empty() ...)" is more idiomatic than using additions.

+ Elements.push_back(MakeConstantString((*iter).first.first, ".objc_sel_types"));

Watch out for 80 columns.

+ const llvm::StructLayout *Layout =
+ TheTargetData.getStructLayout(llvm::cast<const llvm::StructType>(ObjTy));

You don't need the llvm:: qualifier on cast, and you don't need 'const' in the type argument (the constness of the result follows the constness of the input). This should be enough:

+ const llvm::StructLayout *Layout =
+ TheTargetData.getStructLayout(cast<llvm::StructType>(ObjTy));

+++ lib/CodeGen/ModuleBuilder.cpp (working copy)
@@ -67,6 +67,24 @@

        if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
          Builder->EmitFunction(FD);
+ } else if (dyn_cast<ObjCClassDecl>(D)){
+ //Forward declaration. Only used for type checking.

If you're not using the result of the dyn_cast, please use isa<ObjCClassDecl>(D) instead. Likewise for other cases in this file.

This is looking nice!

-Chris

Hi Devang,

Thanks for the feedback. Here is a new version.

Nice! This is looking good. A few more thoughts:

+// Some zeros used for GEPs in lots of places.
+static llvm::Constant *Zeros =
{llvm::ConstantInt::get(llvm::Type::Int32Ty, 0),
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 0) };
+static llvm::Constant *NULLPtr = llvm::ConstantPointerNull::get(
+ llvm::PointerType::getUnqual(llvm::Type::Int8Ty));
+static llvm::Constant *ProtocolVersion =
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 2);

This causes static initializers to be formed and run. Please stay
away from them. Maybe these should be instance variables of the class?

Okay.

+ std::map<std::string, llvm::Constant*> ExistingProtocols;
+ typedef std::pair<std::string, std::string> TypedSelector;
+ std::map<TypedSelector, llvm::GlobalAlias*> TypedSelectors;
+ std::map<std::string, llvm::GlobalAlias*> UntypedSelectors;

std::map's from std::string are really inefficient. Can you use
StringMap for these?

Done for the two with string keys. I'm happy to accept suggestions for a more efficient way of storing typed selectors (although clang currently never uses that code path, so the inefficiency isn't important).

These:
+static std::string SymbolNameForClass(std::string ClassName) {
+static std::string SymbolNameForMethod(const std::string &ClassName,
const
+ std::string CategoryName, const std::string MethodName, bool
isClassMethod)

Copy the std::string objects. Please pass as "const std::string &foo"
to avoid this. Likewise in a few other places (e.g. MakeGlobal)

Done.

+ if (isClassMethod)
+ return "._objc_method_" + ClassName +"("+CategoryName+")"+ "+" +
MethodName;
+ return "._objc_method_" + ClassName +"("+CategoryName+")"+ "-" +
MethodName;
+}

How about something like:
  return "._objc_method_" + ClassName +"("+CategoryName+")"+
        (isClassMethod ? "+" : "-") + MethodName;

To make it more obvious what the difference is between the two.

Yup, seems clearer.

+ if (ReturnTy->isSingleValueType() && ReturnTy !=
llvm::Type::VoidTy) {
+ llvm::SmallVector<llvm::Value*, 16> Args;
+ Args.push_back(Receiver);
+ Args.push_back(cmd);
+ Args.insert(Args.end(), ArgV, ArgV+ArgC);
+ return Builder.CreateCall(imp, Args.begin(), Args.end());
+ } else {
+ llvm::SmallVector<llvm::Value*, 16> Args;
+ llvm::Value *Return = Builder.CreateAlloca(ReturnTy);
+ Args.push_back(Return);
+ Args.push_back(Receiver);
+ Args.push_back(cmd);
+ Args.insert(Args.end(), ArgV, ArgV+ArgC);
+ Builder.CreateCall(imp, Args.begin(), Args.end());
+ return Return;
+ }

Is there a specific reason not to share the common code here?

Other than incompetence? No. Fixed.

+void CGObjCGNU::GenerateProtocol(const char *ProtocolName,

It would be nice to add a block comment above each of these methods
with a C struct (in the comment) that describes the thing that you are
generating. This would make it easier to follow the code.

I don't want to copy the structs directly from the runtime headers, since the header is GPL'd (with a special exemption for code compiled with GCC, but not for code compiled with LLVM) and, although you can't copyright an interface, you can copyright a representation of an interface (see AT&T Vs UCB). I've added a comment at the top of the file pointing people in the right direction for finding the structures.

+ if (Classes.size() + Categories.size() + ConstantStrings.size() +
+ ExistingProtocols.size() + TypedSelectors.size() +
+ UntypedSelectors.size() == 0) {

It is generally better to query .empty() instead of .size() if you
just care about whether it is empty or not. Also, using "if
(x.empty() && y.empty() && z.empty() ...)" is more idiomatic than
using additions.

Fixed.

+ Elements.push_back(MakeConstantString((*iter).first.first,
".objc_sel_types"));

Watch out for 80 columns.

Fixed.

+ const llvm::StructLayout *Layout =
+ TheTargetData.getStructLayout(llvm::cast<const
llvm::StructType>(ObjTy));

You don't need the llvm:: qualifier on cast, and you don't need
'const' in the type argument (the constness of the result follows the
constness of the input). This should be enough:

+ const llvm::StructLayout *Layout =
+ TheTargetData.getStructLayout(cast<llvm::StructType>(ObjTy));

Done.

+++ lib/CodeGen/ModuleBuilder.cpp (working copy)
@@ -67,6 +67,24 @@

       if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
         Builder->EmitFunction(FD);
+ } else if (dyn_cast<ObjCClassDecl>(D)){
+ //Forward declaration. Only used for type checking.

If you're not using the result of the dyn_cast, please use
isa<ObjCClassDecl>(D) instead. Likewise for other cases in this file.

Fixed.

David

objc.diff (60.5 KB)

+ std::map<std::string, llvm::Constant*> ExistingProtocols;
+ typedef std::pair<std::string, std::string> TypedSelector;
+ std::map<TypedSelector, llvm::GlobalAlias*> TypedSelectors;
+ std::map<std::string, llvm::GlobalAlias*> UntypedSelectors;

std::map's from std::string are really inefficient. Can you use
StringMap for these?

Done for the two with string keys. I'm happy to accept suggestions for a more efficient way of storing typed selectors (although clang currently never uses that code path, so the inefficiency isn't important).

If TypedSelectors are never used? Why have them?

One simple way to do it with stringmap is to insert the string with a \0 or some other sentinel between the two pieces.

+void CGObjCGNU::GenerateProtocol(const char *ProtocolName,

It would be nice to add a block comment above each of these methods
with a C struct (in the comment) that describes the thing that you are
generating. This would make it easier to follow the code.

I don't want to copy the structs directly from the runtime headers, since the header is GPL'd (with a special exemption for code compiled with GCC, but not for code compiled with LLVM) and, although you can't copyright an interface, you can copyright a representation of an interface (see AT&T Vs UCB). I've added a comment at the top of the file pointing people in the right direction for finding the structures.

Fair enough. However, you don't have to copy and paste the structs, just rewrite them based on your knowledge of what they are, for example looking at the code that emits the LLVM IR and naming the fields how you wish.

+++ lib/CodeGen/CGObjCGNU.cpp (working copy)
+#include <cstdarg>

Is this needed?

+const static int RuntimeVersion = 8;
+static llvm::Constant *ProtocolVersion =
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 2);

RuntimeVersion is ok, but ProtocolVersion still requires a static ctor. Please remove. It is also slightly more idiomatic to use "static const int" instead of "const static int", but it doesn't make that much of a difference.

+static std::string SymbolNameForMethod(const std::string &ClassName, const
+ std::string CategoryName, const std::string &MethodName, bool isClassMethod)

CategoryName is still passed by copy

+ if (llvm::Constant *CName = llvm::dyn_cast<llvm::Constant>(SelName)) {

I think you can just use dyn_cast instead of llvm::dyn_cast. If not, I suggest adding a 'using llvm::dyn_cast;' to the top of the cpp file.

+ llvm::GlobalAlias *Sel = new llvm::GlobalAlias(llvm::PointerType::getUnqual(SelectorTy),
+ llvm::GlobalValue::InternalLinkage, ".objc_untyped_selector_alias", NULL,
+ &TheModule);

80 cols, also elsewhere.

Otherwise, looks great. Please commit with these updates. Thanks David!

-Chris

+ std::map<std::string, llvm::Constant*> ExistingProtocols;
+ typedef std::pair<std::string, std::string> TypedSelector;
+ std::map<TypedSelector, llvm::GlobalAlias*> TypedSelectors;
+ std::map<std::string, llvm::GlobalAlias*> UntypedSelectors;

std::map's from std::string are really inefficient. Can you use
StringMap for these?

Done for the two with string keys. I'm happy to accept suggestions for a more efficient way of storing typed selectors (although clang currently never uses that code path, so the inefficiency isn't important).

If TypedSelectors are never used? Why have them?

They aren't used yet, but they will be later (they allow a slightly more efficient implementation of Distributed Objects, which GNUstep supports).

One simple way to do it with stringmap is to insert the string with a \0 or some other sentinel between the two pieces.

I'll leave this for now, and come back to it when typed selectors are actually used.

+void CGObjCGNU::GenerateProtocol(const char *ProtocolName,

It would be nice to add a block comment above each of these methods
with a C struct (in the comment) that describes the thing that you are
generating. This would make it easier to follow the code.

I don't want to copy the structs directly from the runtime headers, since the header is GPL'd (with a special exemption for code compiled with GCC, but not for code compiled with LLVM) and, although you can't copyright an interface, you can copyright a representation of an interface (see AT&T Vs UCB). I've added a comment at the top of the file pointing people in the right direction for finding the structures.

Fair enough. However, you don't have to copy and paste the structs, just rewrite them based on your knowledge of what they are, for example looking at the code that emits the LLVM IR and naming the fields how you wish.

+++ lib/CodeGen/CGObjCGNU.cpp (working copy)
+#include <cstdarg>

Is this needed?

Ooops. No, not now the helper functions have been moved back into LLVM.

+const static int RuntimeVersion = 8;
+static llvm::Constant *ProtocolVersion =
+ llvm::ConstantInt::get(llvm::Type::Int32Ty, 2);

RuntimeVersion is ok, but ProtocolVersion still requires a static ctor. Please remove. It is also slightly more idiomatic to use "static const int" instead of "const static int", but it doesn't make that much of a difference.

I've turned ProtocolVersion into an int and now construct the llvm::ConstantInt where it's used.

+static std::string SymbolNameForMethod(const std::string &ClassName, const
+ std::string CategoryName, const std::string &MethodName, bool isClassMethod)

CategoryName is still passed by copy

Fixed.

+ if (llvm::Constant *CName = llvm::dyn_cast<llvm::Constant>(SelName)) {

I think you can just use dyn_cast instead of llvm::dyn_cast. If not, I suggest adding a 'using llvm::dyn_cast;' to the top of the cpp file.

Fixed.

+ llvm::GlobalAlias *Sel = new llvm::GlobalAlias(llvm::PointerType::getUnqual(SelectorTy),
+ llvm::GlobalValue::InternalLinkage, ".objc_untyped_selector_alias", NULL,
+ &TheModule);

80 cols, also elsewhere.

Fixed.

Otherwise, looks great. Please commit with these updates. Thanks David!

I've attached the new diff. Can someone commit it?

David

objc.diff (60.7 KB)

So, this generates:

CodeGenModule.cpp: In member function ‘void clang::CodeGen::CodeGenModule::EmitObjCClassImplementation(const clang::ObjCImplementationDecl*)’:
CodeGenModule.cpp:334: warning: ‘ObjTy’ may be used uninitialized in this function

the code looks like:

   const llvm::Type *ObjTy;
   if (!Runtime->LateBoundIVars()) {
     ObjTy = getTypes().ConvertType(Context.getObjCInterfaceType(ClassDecl));
     instanceSize = TheTargetData.getABITypeSize(ObjTy);
   }

   // Collect information about instance variables.
   llvm::SmallVector<llvm::Constant*, 16> IvarNames;
   llvm::SmallVector<llvm::Constant*, 16> IvarTypes;
   llvm::SmallVector<llvm::Constant*, 16> IvarOffsets;
   const llvm::StructLayout *Layout =
     TheTargetData.getStructLayout(cast<llvm::StructType>(ObjTy));

So, would initializing this to 0 be appropriate?

Hi Mike,

I've started splitting the Objective-C code generation stuff up into smaller diffs.

Sadly, I haven't had a chance to do much with this lately. I still have a huge pile of clang diffs sitting on my machine waiting to be submitted, and I've made a number of bug fixes in the copy of CGObjCGNU that we're using in the back end of a Smalltalk compiler, but the copy I'm using there pre-dates Chris introducing clang dependencies into this file and I haven't had time to back-port the fixes to clang.

So, this generates:

CodeGenModule.cpp: In member function ‘void clang::CodeGen::CodeGenModule::EmitObjCClassImplementation(const clang::ObjCImplementationDecl*)’:
CodeGenModule.cpp:334: warning: ‘ObjTy’ may be used uninitialized in this function

the code looks like:

  const llvm::Type *ObjTy;
  if (!Runtime->LateBoundIVars()) {
    ObjTy = getTypes().ConvertType(Context.getObjCInterfaceType(ClassDecl));
    instanceSize = TheTargetData.getABITypeSize(ObjTy);
  }

  // Collect information about instance variables.
  llvm::SmallVector<llvm::Constant*, 16> IvarNames;
  llvm::SmallVector<llvm::Constant*, 16> IvarTypes;
  llvm::SmallVector<llvm::Constant*, 16> IvarOffsets;
  const llvm::StructLayout *Layout =
    TheTargetData.getStructLayout(cast<llvm::StructType>(ObjTy));

So, would initializing this to 0 be appropriate?

This would make the warning go away. It would also be worth adding an 'assert(0 && "Late-bound instance variables not yet supported);' in an else block here, since there is not yet any code for this, which is required by newer ObjC runtimes.

David

Ok, thanks. Fixed in r54654. Take a glance at it and let me know if I did it right. :slight_smile: