Continuing Adventures with Objective-C

Hi Chris,

Here's the latest diff - it's getting quite big, but you can ignore most of the stuff in CGObjCEtoile.cpp (it's bitrotted a bit, since I've changed some interfaces).

Hi David,

This is huge. I can't review this. I see a whole bunch of unrelated changes, please split this out into one patch per change. This is important for review, but it is also important for revision control purposes (you can revert one patch without all the others). Also, this allows patch review to be done by different people which might be specialized in certain areas.

Example pieces:
1) the changes for your runtime should be split out
2) the self/_cmd/super changes should be split out.
3) the @defs support should be split out
4) the ccc changes should be split out
5) the codegen refactoring (ConvertReturnType etc) should be split out.
6) the various random codegen improvements should be split out.

Questions:
What is the idea with ImplicitParamInfo in ObjCMethodDecl? Should isObjCPointerType be a method in codegen, or something in the AST?

+++ lib/AST/StmtPrinter.cpp (working copy)
@@ -496,6 +496,9 @@
      case PreDefinedExpr::PrettyFunction:
        OS << "__PRETTY_FUNCTION__";
        break;
+ case PreDefinedExpr::ObjCSuper:
+ OS << "super";
+ break;

this should handle self/_cmd also.

    // typedef struct objc_class *Class;
    const PointerType *ptr = TD->getUnderlyingType()- >getAsPointerType();
- assert(ptr && "'Class' incorrectly typed");
+ //assert(ptr && "'Class' incorrectly typed");
    const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
- assert(rec && "'Class' incorrectly typed");
+ //assert(rec && "'Class' incorrectly typed");
    ClassStructType = rec;

Why are you commenting out code?

@@ -721,16 +721,32 @@
      // Parse all the comma separated declarators.
      DeclSpec DS;
      FieldDeclarators.clear();
+ if(Tok.is(tok::at)) {
+ ConsumeToken();
+ //FIXME: Turn these into helpful errors
+ assert(Tok.isObjCAtKeyword(tok::objc_defs) && "defs expected");
+ ConsumeToken();
+ assert(Tok.is(tok::l_paren) && "( expected");

Please do the fixme: checking in code that is known broken is badness. Also please move the @ handling part to the "else" clause of the if, so that the normal struct case comes before @defs handling.

This is great work and I'm thrilled that you're making such huge enhancements to clang, but I would also really like to get it checked into clang... and we can't do that until it is split up a bit more.

-Chris

Hi Chris,

This is huge. I can't review this. I see a whole bunch of unrelated changes, please split this out into one patch per change. This is important for review, but it is also important for revision control purposes (you can revert one patch without all the others). Also, this allows patch review to be done by different people which might be specialized in certain areas.

Sorry about the size. It's a bit hard to split it up, since many of the changes depend on others. I'm now using svk for clang so I can split future diffs up more easily once my tree is a bit better sync'd with trunk.

Example pieces:
1) the changes for your runtime should be split out

The runtime-specific code is all in GCObjCGNU.cpp and CGObjCEtoile.cpp. It's hard to split these out as separate diffs because these changes depend on changes to the interface declared in CGObjCRuntime.h, which in turn depend on changes in other bits of the code that call it.

The Étoilé runtime stuff is still in a state of flux, so I have enclosed a simplified version of the diff that only changes the interfaces to match the new versions. (etoile.diff)

The GNU runtime specific stuff is all in gnu.diff.

The new runtime interface is in runtimeif.diff. This can not be committed separately from the changes to the runtime implementations and the things in CGObjC.cpp that call it.

2) the self/_cmd/super changes should be split out.

Super is in super.diff. Implicit parameters, which include self and _cmd are in implicit.diff.

3) the @defs support should be split out

This is in defs.diff.

4) the ccc changes should be split out

ccc.diff (These are unchanged from the ccc.diff in the earlier email).

5) the codegen refactoring (ConvertReturnType etc) should be split out.

types.diff contains the changes to CodeGenTypes which allow converting a return type. This is required for the changes to CodeGenFunction::GenerateObjCMethod().

function.diff pulls shared code from CodeGenFunction::GenrateCode and GenerateObjCMethod out. It also removes the method for generating ObjC methods from CodeGenFunction.

objc.diff puts this method and other ObjC specific parts of CodeGenFunction into GCObjC.cpp (where I should have put them to start with).

module.diff contains the runtime-agnostic code for generating module-level ObjC constructs (classes, categories and protocols). This depends on the new runtime interface since the old one did not have methods for doing any of this.

static.diff fixes static variables in ObjC methods.

override.diff allows the types of id and Class to be redefined. This happens whenever a runtime-specific header file is included. I think GCC avoids this problem by including these headers itself and picking up the declarations from there.

union.diff adds support for GCC's cast-to-union extension, which is used in a depressing number of places in the GNUstep code.

cast.diff fixes a number of cases where implicit casts are not correctly codegen'd, and allows Objective-C const id to have messages sent to it.

expr.diff contains a load of small tidies (i.e. everything I couldn't thing of which diff to put it in)

6) the various random codegen improvements should be split out.

const_str.diff adds a call to the runtime-specific method for generating constant ObjC strings. It also relaxes the string class type checking. If NSConstantString has not been declared when a constant string is encountered (which happens quite often) then the constant string is an id. If it has, then it is an NSConstantString.

aggmsg.diff generates message sends that return aggregate types by calling runtime-specific methods. There are corresponding changes in the runtime-specific code to make this actually work.

Questions:
What is the idea with ImplicitParamInfo in ObjCMethodDecl?

It allows enumeration of things like self and _cmd. For the Étoilé runtime it will also provide support for _call (which is mainly used by prototype-base languages such as Io and JavaScript, but might be useful to export to Objective-C programmers). In a future patch I will factor the code that sets these out into a runtime-specific class. These are just function parameters, so they do not need any special handling (the existing code for accessing local variables works on them in the codegen).

This is basically a generalisation of the existing selfDecl stuff. At the moment, self and _cmd are hard-coded. When this is committed I will allow other implicit parameters to be defined per-runtime.

Should isObjCPointerType be a method in codegen, or something in the AST?

It is in CodeGen because it is only used in CodeGen. It is used to decide when two pointers which point to different LLVM types can be implicitly bitcast - AST is unaware of LLVM types so it doesn't make this distinction. This is probably not the ideal solution, so suggestion are welcome.

+++ lib/AST/StmtPrinter.cpp (working copy)
@@ -496,6 +496,9 @@
    case PreDefinedExpr::PrettyFunction:
      OS << "__PRETTY_FUNCTION__";
      break;
+ case PreDefinedExpr::ObjCSuper:
+ OS << "super";
+ break;

this should handle self/_cmd also.

self and _cmd are handled by the implicit parameter code now. They work as any other variable references, both when accessing them in codegen and when doing an AST print. super is different because it is an alias for self with special semantics. These should not have been left in Expr.h diff, since they are never used.

  // typedef struct objc_class *Class;
  const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType();
- assert(ptr && "'Class' incorrectly typed");
+ //assert(ptr && "'Class' incorrectly typed");
  const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
- assert(rec && "'Class' incorrectly typed");
+ //assert(rec && "'Class' incorrectly typed");
  ClassStructType = rec;

Why are you commenting out code?

Because it was breaking something else which I have now fixed and I forgot to uncomment them. The asserts requiring SEL to be a pointer type will have to be changed at some point since SEL is an i32 in the Étoilé runtime. (SEL is an opaque type with respect to the language. The fact that it is a pointer in the GNU and NeXT runtimes is an implementation detail and doesn't belong in the AST).

@@ -721,16 +721,32 @@
    // Parse all the comma separated declarators.
    DeclSpec DS;
    FieldDeclarators.clear();
+ if(Tok.is(tok::at)) {
+ ConsumeToken();
+ //FIXME: Turn these into helpful errors
+ assert(Tok.isObjCAtKeyword(tok::objc_defs) && "defs expected");
+ ConsumeToken();
+ assert(Tok.is(tok::l_paren) && "( expected");

Please do the fixme: checking in code that is known broken is badness.

Sorry, I hadn't read the diagnostics code when I wrote this. Fixed now. I've also replaced the corresponding assert in SemaDecl with an error.

Also please move the @ handling part to the "else" clause of the if, so that the normal struct case comes before @defs handling.

Done.

This is great work and I'm thrilled that you're making such huge enhancements to clang, but I would also really like to get it checked into clang... and we can't do that until it is split up a bit more.

I've stopped working on new things to focus on getting the current changes merged so I don't diverge any further. Let me know what needs changing to get it committed.

David

cast.diff (4.34 KB)

ccc.diff (676 Bytes)

const_str.diff (1.76 KB)

defs.diff (5.51 KB)

etoile.diff (5.96 KB)

expr.diff (9.5 KB)

function.diff (6.28 KB)

gnu.diff (38.9 KB)

implicit.diff (4.13 KB)

module.diff (10.2 KB)

objc.diff (8.5 KB)

override.diff (4.99 KB)

runtimeif.diff (5.44 KB)

static.diff (616 Bytes)

super.diff (1.9 KB)

types.diff (3.13 KB)

union.diff (1.61 KB)

vla.diff (587 Bytes)

aggmesg.diff (1.81 KB)

Please include testcases with all of the patches; it makes things
easier to review, and they're necessary to commit fixes. Please put
fixes that don't have any dependencies into separate emails; it makes
them easier to track.

A quick review of some of diffs:

vla.diff:
Nowhere near a complete implementation of vlas; better to error out
than generate bad code. I think I sent a partial patch to this list
at one point, but I never finished it.

aggmesg.diff:
Please split this patch into its independent parts.

The VisitObjCMessageExpr implementation looks correct, although the
FIXME doesn't seem relevant, and there's no point to constructing the
RValue.

The VisitCastExpr implementation is clearly wrong; you're throwing out
the emitted value. Also, you should add some assertions to make sure
it's a scalar to union cast. (Also, don't resubmit this until the
Sema changes this depends on are committed.)

union.diff:
You definitely need to implement that FIXME before the patch goes in.
Also, you want to be checking for type compatibility, not pointer
equality.

types.diff:
Please split this patch into its independent parts.

The change for "case Type::ObjCQualifiedId" looks fine.

I'm a bit concerned that the implementation of ConvertReturnType might
not be appropriate to call from within ConvertNewType; that code tends
to be fragile.

super.diff:
Please make a new expession type instead of overloading PreDefinedExpr.

static.diff:
Please put the logic ObjCMethodDecl, alongside
getSynthesizedMethodSize(). (Or is that logic already elsewhere?)

ccc.diff:
Send this patch in a separate email, so that the ccc maintainer sees it.

cast.diff:
This is mixing fixes. Please separate.

If two types are compatible, they should have the same LLVM type, I
think; is the ObjC code abusing type compatibility? Maybe we need to
be emitting more ImplicitCasts into the AST?

-Eli

Hmm, I guess I really ought the go into more detail on this bit.
First off, I'm sure this work will be very useful for people using
ObjC, so keep up the good work. If the review comments seem a bit
harsh, it's just the natural writing style for reviews, and if you
disagree with a comment, feel free to say so.

The key to making things move as quickly as possible is to make small,
independent patches which can be committed separately without breaking
the build. For example, take const_str.diff. The Sema changes are
independent of the other changes. So send one email, with one patch,
including a testcase, which can be committed separately from the
others. That should be reviewed and committed quickly. Then, send
one email, with one patch, which allows the codegen of ObjC string
literals. This is more work than submitting multiple fixes together,
but once things start moving, you'll find that everything runs a lot
smoother.

If you haven't read http://llvm.org/docs/DeveloperPolicy.html, you
might also find that useful.

-Eli

David,

Is this patch sufficient to support VLAs ? Your patch removes an assert but somehow it is not visible in diffs.

David,

David,

types.diff contains the changes to CodeGenTypes which allow converting a return type. This is required for the changes to CodeGenFunction::GenerateObjCMethod().

@@ -139,7 +144,7 @@
   /// memory representation is usually i8 or i32, depending on the target.
   const llvm::Type *ConvertTypeForMem(QualType T);

- void CollectObjCIvarTypes(ObjCInterfaceDecl *ObjCClass,
+ void CollectObjCIvarTypes(const ObjCInterfaceDecl *ObjCClass,
       std::vector<const llvm::Type*> &IvarTypes);

   const CGRecordLayout *getCGRecordLayout(const TagDecl*) const;
Index: lib/CodeGen/CodeGenTypes.cpp

--- lib/CodeGen/CodeGenTypes.cpp (revision 51026)
+++ lib/CodeGen/CodeGenTypes.cpp (working copy)
@@ -168,7 +168,7 @@
/// 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,
+void CodeGenTypes::CollectObjCIvarTypes(const ObjCInterfaceDecl *ObjCClass,
                                     std::vector<const llvm::Type*> &IvarTypes) {
   ObjCInterfaceDecl *SuperClass = ObjCClass->getSuperClass();
   if (SuperClass)

This is a separate and obvious patch.

+const llvm::Type *CodeGenTypes::ConvertReturnType(QualType T) {
+ if (T->isVoidType())
+ {
+ return llvm::Type::VoidTy; // Result of function uses llvm void.
+ }
+ else
+ return ConvertType(T);
+}
+

Please add doxygen style comment and drop extra { and }

@@ -320,8 +325,8 @@
     break;

   case Type::ObjCQualifiedId:
- assert(0 && "FIXME: add missing functionality here");
- break;
+ // For CodeGen purposes, any id type is an opque pointer
+ return ConvertTypeRecursive(Context.getObjCIdType());

   case Type::Tagged: {
     const TagDecl *TD = cast<TagType>(Ty).getDecl();

This is independent and looks ok.

David,

cast.diff fixes a number of cases where implicit casts are not correctly codegen'd, and allows Objective-C const id to have messages sent to it.

Index: lib/CodeGen/CodeGenFunction.h

--- lib/CodeGen/CodeGenFunction.h (revision 51026)
+++ lib/CodeGen/CodeGenFunction.h (working copy)
@@ -67,7 +67,9 @@
   class ChooseExpr;
   class PreDefinedExpr;
   class ObjCStringLiteral;
+ class ObjCSelectorExpr;
   class ObjCIvarRefExpr;
+ class ObjCMessageExpr;
   class MemberExpr;

   class VarDecl;
@@ -296,11 +298,15 @@

Do you need this ? I don't see any use in this patch.

   void GenerateObjCMethod(const ObjCMethodDecl *OMD);
   void GenerateCode(const FunctionDecl *FD);

   const llvm::Type *ConvertType(QualType T);

   llvm::Value *LoadObjCSelf();

+ /// isObjCPointerType - Return true if the specificed AST type will map onto
+ /// some Objective-C pointer type.
+ static bool isObjCPointerType(QualType T);
   /// hasAggregateLLVMType - Return true if the specified AST type will map into
   /// an aggregate LLVM type or is void.
   static bool hasAggregateLLVMType(QualType T);

Index: lib/CodeGen/CodeGenFunction.cpp

--- lib/CodeGen/CodeGenFunction.cpp (revision 51026)
+++ lib/CodeGen/CodeGenFunction.cpp (working copy)
@@ -50,70 +54,20 @@
   return CGM.getTypes().ConvertType(T);
}

+bool CodeGenFunction::isObjCPointerType(QualType T) {
+ // All Objective-C types are pointers.
+ return T->isObjCInterfaceType() ||
+ T->isObjCQualifiedInterfaceType() || T->isObjCQualifiedIdType();
+}
+
bool CodeGenFunction::hasAggregateLLVMType(QualType T) {
- return !T->isRealType() && !T->isPointerLikeType() &&
- !T->isVoidType() && !T->isVectorType() && !T->isFunctionType();
+ return !isObjCPointerType(T) &&!T->isRealType() && !T->isPointerLikeType() &&
+ !T->isVoidType() && !T->isVectorType() && !T->isFunctionType();
}

This is part of patch OK. I think, Eli addressed other part.

This looks OK.
Thanks!

Ooops, those should have been in a different diff (it's hard to keep track of which bits depend on which other bits). These are needed here for the declaration of EmitObjCSelectorExpr() and EmitObjCMessageExpr(). It seems I messed up quite badly splitting the diff into small parts, since these are used in the code in expr.diff and defined in objc.diff. Sorry.

David

aggmsg.diff generates message sends that return aggregate types by calling runtime-specific methods. There are corresponding changes in the runtime-specific code to make this actually work.

Index: lib/CodeGen/CGExprAgg.cpp

--- lib/CodeGen/CGExprAgg.cpp (revision 51026)
+++ lib/CodeGen/CGExprAgg.cpp (working copy)
@@ -77,12 +77,15 @@
   // case Expr::UnaryOperatorClass:
   // case Expr::CastExprClass:
   void VisitImplicitCastExpr(ImplicitCastExpr *E);
+ void VisitCastExpr(const CastExpr *E);
   void VisitCallExpr(const CallExpr *E);
   void VisitStmtExpr(const StmtExpr *E);
   void VisitBinaryOperator(const BinaryOperator *BO);
   void VisitBinAssign(const BinaryOperator *E);
   void VisitOverloadExpr(const OverloadExpr *E);

+ void VisitObjCMessageExpr(ObjCMessageExpr *E);
+

Avoid xtra white spaces

   void VisitConditionalOperator(const ConditionalOperator *CO);
   void VisitInitListExpr(InitListExpr *E);
@@ -182,9 +185,13 @@
   assert(CGF.getContext().typesAreCompatible(
              STy.getUnqualifiedType(), Ty.getUnqualifiedType())
          && "Implicit cast types must be compatible");
-
   Visit(E->getSubExpr());
}
+// This should only be used when constructing a cast to a union type
+void AggExprEmitter::VisitCastExpr(const CastExpr *E) {
+ // Does this work on big-endian archs?

why not ?

Patch is ok.

expr.diff contains a load of small tidies (i.e. everything I couldn't thing of which diff to put it in)

It is easier for everyone if you get such patches in as soon as you run into them.

Index: lib/CodeGen/CGExprScalar.cpp

--- lib/CodeGen/CGExprScalar.cpp (revision 51026)
+++ lib/CodeGen/CGExprScalar.cpp (working copy)
@@ -125,6 +125,7 @@
     return EmitLoadOfLValue(E);
   }
   Value *VisitObjCMessageExpr(ObjCMessageExpr *E);
+ Value *VisitObjCProtocolExpr(ObjCProtocolExpr *E);
   Value *VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { return EmitLoadOfLValue(E);}
   Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
   Value *VisitMemberExpr(Expr *E) { return EmitLoadOfLValue(E); }
@@ -298,6 +299,9 @@
   Value *VisitChooseExpr(ChooseExpr *CE);
   Value *VisitOverloadExpr(OverloadExpr *OE);
   Value *VisitVAArgExpr(VAArgExpr *VE);
+ Value *VisitObjCSelectorExpr(const ObjCSelectorExpr *E) {
+ return CGF.EmitObjCSelectorExpr(E);
+ }
   Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
     return CGF.EmitObjCStringLiteral(E);
   }

ok

@@ -374,6 +378,9 @@
   }

   if (isa<PointerType>(SrcType)) {
+ if(CGF.isObjCPointerType(DstType)) {
+ return Builder.CreateBitCast(Src, DstTy, "conv");
+ }

ok

     // Must be an ptr to int cast.
     assert(isa<llvm::IntegerType>(DstTy) && "not ptr->int?");
     return Builder.CreatePtrToInt(Src, DstTy, "conv");
@@ -452,46 +459,7 @@
   return llvm::UndefValue::get(CGF.ConvertType(E->getType()));
}

-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
- // arguments in generic code.
-
- // Find the receiver
- llvm::Value *Receiver = CGF.EmitScalarExpr(E->getReceiver());

- // Process the arguments
- unsigned ArgC = E->getNumArgs();
- llvm::SmallVector<llvm::Value*, 16> Args;
- for (unsigned i = 0; i != ArgC; ++i) {
- Expr *ArgExpr = E->getArg(i);
- QualType ArgTy = ArgExpr->getType();
- if (!CGF.hasAggregateLLVMType(ArgTy)) {
- // Scalar argument is passed by-value.
- Args.push_back(CGF.EmitScalarExpr(ArgExpr));
- } else if (ArgTy->isAnyComplexType()) {
- // Make a temporary alloca to pass the argument.
- llvm::Value *DestMem = CGF.CreateTempAlloca(ConvertType(ArgTy));
- CGF.EmitComplexExprIntoAddr(ArgExpr, DestMem, false);
- Args.push_back(DestMem);
- } else {
- llvm::Value *DestMem = CGF.CreateTempAlloca(ConvertType(ArgTy));
- CGF.EmitAggExpr(ArgExpr, DestMem, false);
- Args.push_back(DestMem);
- }
- }
-
- // Get the selector string
- std::string SelStr = E->getSelector().getName();
- llvm::Constant *Selector = CGF.CGM.GetAddrOfConstantString(SelStr);
-
- llvm::Value *SelPtr = Builder.CreateStructGEP(Selector, 0);
- return Runtime->generateMessageSend(Builder, ConvertType(E->getType()),
- CGF.LoadObjCSelf(),
- Receiver, SelPtr,
- &Args[0], Args.size());
-}
-

I guess this is moved somewhere else ?

Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
   // Emit subscript expressions in rvalue context's. For most cases, this just
   // loads the lvalue formed by the subscript expr. However, we have to be
@@ -522,11 +490,11 @@
     // will not true when we add support for VLAs.
     Value *V = EmitLValue(Op).getAddress(); // Bitfields can't be arrays.

- assert(isa<llvm::PointerType>(V->getType()) &&
- isa<llvm::ArrayType>(cast<llvm::PointerType>(V->getType())
- ->getElementType()) &&
- "Doesn't support VLAs yet!");
- V = Builder.CreateStructGEP(V, 0, "arraydecay");
+ if (isa<llvm::PointerType>(V->getType()) &&
+ isa<llvm::ArrayType>(cast<llvm::PointerType>(V->getType())
+ ->getElementType())) {
+ V = Builder.CreateStructGEP(V, 0, "arraydecay");
+ }

     // The resultant pointer type can be implicitly casted to other pointer
     // types as well, for example void*.
@@ -660,6 +628,13 @@
   if (TypeToSize->isVoidType())
     return llvm::ConstantInt::get(llvm::APInt(ResultWidth, 1));

+ // Get the size of VLAs
+ if (TypeToSize->isVariablyModifiedType() && isSizeOf) {
+ const VariableArrayType *VLA = TypeToSize->getAsVariableArrayType();
+ Value *ElementSize = EmitSizeAlignOf(VLA->getElementType(), RetType, true);
+ Value *Elements = CGF.EmitScalarExpr(VLA->getSizeExpr());
+ return Builder.CreateMul(Elements, ElementSize);
+ }
   /// FIXME: This doesn't handle VLAs yet!
   std::pair<uint64_t, unsigned> Info = CGF.getContext().getTypeInfo(TypeToSize);

Please include these with VLA patch so that it is possible to review VLA support.

@@ -908,6 +883,11 @@
                                   LHS, RHS, "cmp");
     } else {
       // Signed integers and pointers.
+ const llvm::Type *LHSTy = LHS->getType();
+ // Are we comparing pointers to different types?
+ if (RHS->getType() != LHSTy) {
+ RHS = Builder.CreateBitCast(RHS, LHSTy);

createPointerCast ?

@@ -629,9 +637,11 @@

   // Handle struct-return functions by passing a pointer to the location that
   // we would like to return into.
+ int RealArgStart = 0;
   if (hasAggregateLLVMType(ResultType)) {
     // Create a temporary alloca to hold the result of the call. :frowning:
     Args.push_back(CreateTempAlloca(ConvertType(ResultType)));
+ RealArgStart++;
     // FIXME: set the stret attribute on the argument.
   }

@@ -640,7 +650,16 @@

     if (!hasAggregateLLVMType(ArgTy)) {
       // Scalar argument is passed by-value.
- Args.push_back(EmitScalarExpr(ArgExprs[i]));
+ llvm::Value *ArgVal = EmitScalarExpr(ArgExprs[i]);
+ const llvm::FunctionType *CalleeTy = cast<llvm::FunctionType>(
+ cast<llvm::PointerType>(Callee->getType())->getElementType());
+ if (i < CalleeTy->getNumParams()) {

use assert instead of this check. Otherwise this part is OK.

+ const llvm::Type *ArgTy = CalleeTy->getParamType(i + RealArgStart);
+ if (ArgTy && (ArgVal->getType() != ArgTy)) {
+ ArgVal = Builder.CreateBitCast(ArgVal, ArgTy);
+ }
+ }
+ Args.push_back(ArgVal);
     } else if (ArgTy->isAnyComplexType()) {
       // Make a temporary alloca to pass the argument.
       llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy));

LLVM and clangs development style prefers small and incremental changes. We are able to introduce big features and huge improvements using this style. If you adhere to this style then it'll be easier for you to make progress faster.

function.diff pulls shared code from CodeGenFunction::GenrateCode and GenerateObjCMethod out.

Yay! Pl. co-ordinate with Sanjiv who is adding debug info support and updating this part in recent patch.

It also removes the method for generating ObjC methods from CodeGenFunction.

-llvm::Value *CodeGenFunction::LoadObjCSelf(void)
-{
- if(const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(CurFuncDecl)) {
- llvm::Value *SelfPtr = LocalDeclMap[&(*OMD->getSelfDecl())];
- return Builder.CreateLoad(SelfPtr, "self");
- }
- return NULL;
-}

What about LoadObjCSelf uses ?
Otherwise, patch is OK.
Thanks!

I guess this is moved somewhere else ?

I've moved the Objective-C-specific stuff into CGObjC.cpp. This should make future ObjC-related diffs a bit easier to read.

Please include these with VLA patch so that it is possible to review VLA support.

Sorry - copy-and-paste error.

@@ -908,6 +883,11 @@
                                  LHS, RHS, "cmp");
    } else {
      // Signed integers and pointers.
+ const llvm::Type *LHSTy = LHS->getType();
+ // Are we comparing pointers to different types?
+ if (RHS->getType() != LHSTy) {
+ RHS = Builder.CreateBitCast(RHS, LHSTy);

createPointerCast ?

Makes sense.

@@ -629,9 +637,11 @@

  // Handle struct-return functions by passing a pointer to the location that
  // we would like to return into.
+ int RealArgStart = 0;
  if (hasAggregateLLVMType(ResultType)) {
    // Create a temporary alloca to hold the result of the call. :frowning:
    Args.push_back(CreateTempAlloca(ConvertType(ResultType)));
+ RealArgStart++;
    // FIXME: set the stret attribute on the argument.
  }

@@ -640,7 +650,16 @@

    if (!hasAggregateLLVMType(ArgTy)) {
      // Scalar argument is passed by-value.
- Args.push_back(EmitScalarExpr(ArgExprs[i]));
+ llvm::Value *ArgVal = EmitScalarExpr(ArgExprs[i]);
+ const llvm::FunctionType *CalleeTy = cast<llvm::FunctionType>(
+ cast<llvm::PointerType>(Callee->getType())->getElementType());
+ if (i < CalleeTy->getNumParams()) {

use assert instead of this check. Otherwise this part is OK.

I don't believe this should be an assert - i can be greater than the number of parameters in a variadic function and this is not an error. Variadic parameters do not been implicit casting because they are not type-checked.

+ const llvm::Type *ArgTy = CalleeTy->getParamType(i + RealArgStart);
+ if (ArgTy && (ArgVal->getType() != ArgTy)) {
+ ArgVal = Builder.CreateBitCast(ArgVal, ArgTy);
+ }
+ }
+ Args.push_back(ArgVal);
    } else if (ArgTy->isAnyComplexType()) {
      // Make a temporary alloca to pass the argument.
      llvm::Value *DestMem = CreateTempAlloca(ConvertType(ArgTy));

LLVM and clangs development style prefers small and incremental changes. We are able to introduce big features and huge improvements using this style. If you adhere to this style then it'll be easier for you to make progress faster.

Sorry - I lost track of how big my out-of-tree changes were getting.

David

This method is moved into CGObjC.cpp. (objc.diff)

David

David,

union.diff adds support for GCC's cast-to-union extension, which is used in a depressing number of places in the GNUstep code.

It is a good idea to include a patch here to add the switch to enable this extension. I did not know about this extension until now!.

I've not looked at the dialect options code at all yet. Is there an existing flag I should test to see if we are in GNU-compatible mode?

Do you need a codegen patch to complete this support ?

I think I accidentally put the codegen part of this in expr.diff. (VisitCastExpr)

David

No. I accidentally put the implementation of sizeof() for VLAs into a different patch. I think the included patch now includes both parts.

vla.diff (2.12 KB)

Just make the diagnostic of type EXTENSION; those are automatically
hidden outside of strict compliance mode. clang is basically always
in GNU-compatible mode, at least at the moment.

-Eli

I haven't looked at your patch closely, but you might want to take a
look at http://lists.cs.uiuc.edu/pipermail/cfe-dev/2008-February/001069.html,
and also the C99 standard for some of the edge cases, like typedefs.

-Eli