[cfe-dev] Objective-C: methods, ivars, and cleanup
David Chisnall
csdavec at swansea.ac.uk
Tue Mar 25 10:00:16 PDT 2008
On 25 Mar 2008, at 15:18, Devang Patel wrote:
> On Mar 24, 2008, at 11:48 AM, David Chisnall wrote:
>
>> Hi,
>>
>> This is a fairly big diff, so I've tried to split it into a few
>> separate parts.
>>
>> globals.diff is a simple addition to the global_ctors code which
>> avoids emitting empty global_ctors.
>
> - // Populate the array
> - std::vector<llvm::Constant*> CtorValues;
> - llvm::Constant *MagicNumber =
> - llvm::ConstantInt::get(llvm::Type::Int32Ty, 65535, false);
> - std::vector<llvm::Constant*> StructValues;
> - for (std::vector<llvm::Constant*>::iterator I =
> GlobalCtors.begin(),
> - E = GlobalCtors.end(); I != E; ++I) {
> - StructValues.clear();
> - StructValues.push_back(MagicNumber);
> - StructValues.push_back(*I);
> + // Populate the array
> + std::vector<llvm::Constant*> CtorValues;
> + llvm::Constant *MagicNumber =
> llvm::ConstantInt::get(llvm::IntegerType::Int32Ty,
> + 65535,
> + false);
> + for (std::vector<llvm::Constant*>::iterator I =
> GlobalCtors.begin(),
> + E = GlobalCtors.end(); I != E; ++I) {
> + std::vector<llvm::Constant*> StructValues;
> + StructValues.push_back(MagicNumber);
>
> Hoist StructValues outside the for loop and use clear(), as it was
> done originally. Looks OK otherwise.
Fixed.
>>
>>
>> etoile_runtime.diff contains a subclass of CGObjCRuntime which
>> implements the runtime-specific parts for the Étoilé runtime.
>> Other parts do not depend on this unless output for this runtime is
>> selected (the runtime to use is currently hard-coded). I am now
>> writing the GNU and Étoilé versions at the same time to make sure
>> the interfaces are sufficiently abstract. Hopefully this will make
>> adding support for the Apple runtimes easy for whoever gets that job.
>
> OK. Few nit-picks
>
> 1) Add doxygen style comments for class methods and variables. Right
> now, I don't see any comment.
Done.
> 2)
> +#define SET(structure, index, value) do {\
> + llvm::Value *element_ptr = Builder.CreateStructGEP(structure,
> index);\
> + Builder.CreateStore(value, element_ptr);} while(0)
>
> Avoid macros like this.
Can you suggest an alternative? I use this pattern in a really large
number of places (and will use it in a lot more by the time I'm
finished. Expanding it everywhere makes the code a lot less readable
and is likely to cause copy-and-paste bugs.
> 3)
> +// BIG FAT WARNING: Much of this code will need factoring out later.
>
> Just use, FIXME: Much of this code ...
Done.
> 4) Now, I regularly see one-parameter-per-line in your patches. For
> example,
>
> + // Slot type
> + SlotTy = llvm::StructType::get(IntTy,
> + IMPTy,
> + PtrToInt8Ty,
> + PtrToInt8Ty,
> + llvm::Type::Int32Ty,
> + 0);
>
> I'd avoid this myself. Clang coding style does not require this (nor
> explicitly prohibits this).
I've only done this where putting them all on the same line would make
the line over 80 characters long. I find it more readable than just
wrapping at 80 characters.
>> obj_struct.diff handles conversion from Objective-C pointers to
>> LLVM types. This is needed for accessing instance variables
>> statically and is used in the ivar access parts. This patch is
>> also self-contained, and does not depend on any other changes.
>
>
> + void CollectIvarTypes(ObjCInterfaceDecl *ObjCClass,
> + std::vector<const llvm::Type*> *IvarTypes);
>
> This is Objective-C specific class method, so rename it as
> CollectObjCIvarTypes.
> Prefer SmallVector instead of std::vector. Pass it as a reference
> instead of a pointer.
Fixed passing by pointer. Kept as std::vector because
StructType::get() takes a std::vector.
> /// getLLVMFieldNo - Return llvm::StructType element number
> /// that corresponds to the field FD.
> unsigned getLLVMFieldNo(const FieldDecl *FD);
> + unsigned getLLVMFieldNo(QualType ObjectTy, const ObjCIvarDecl
> *Decl);
>
> Why do you need new method here ?
This gets the field number from an LLVM structure created from an
Objective-C class, rather than one created from a C structure.
Possibly it should have a different name? Suggestions welcome.
> + // Warning: Use of this is strongly discouraged. Late binding
> of instance
> + // variables is supported on some runtimes and so using static
> binding can
> + // break code when libraries are updated. Only use this if you
> have
> + // previously checked that the ObjCRuntime subclass in use does
> not support
> + // late-bound ivars.
>
> Please add assert() to check late-bound of ivars support.
I'd like to do this, but GodeGenTypes does not have a reference to
anything that has a reference to anything that has a reference to the
ObjCRuntime subclass, so it's non-trivial. Suggestions welcome.
>> runtime_if.diff contains changes to the runtime interface. This
>> probably needs to be committed at the same time as the changes to
>> the GNU runtime, or there might be some conflicts. The Étoilé
>> patch may also conflict with the old definitions if it is committed
>> before this.
>
> OK
>
> -CGObjCRuntime *CreateObjCRuntime(llvm::Module &M);
> +CGObjCRuntime *CreateObjCRuntime(llvm::Module &M,
> + const llvm::Type *LLVMIntType,
> + const llvm::Type *LLVMLongType);
>
> Is not it possible to derive LLVMIntType and LLVMLongType info based
> on Module ?
Maybe? Can I have a hint please?
>> gnu_runtime.diff contains the changes made to the GNU runtime to
>> adopt the new interface. It also adds methods for generating
>> method functions and some things related to creating class
>> structures which are not used yet.
>
> OK. Please add doxygen style comments for each method.
Is three slashes right for Doxygen?
>>
>>
>> method_gen.diff contains the code required to generate Objective-C
>> methods (although it does not yet attach them to class structures.
>
> Index: lib/CodeGen/CGStmt.cpp
> ===================================================================
> --- lib/CodeGen/CGStmt.cpp (revision 48734)
> +++ lib/CodeGen/CGStmt.cpp (working copy)
> @@ -332,9 +332,6 @@
> // Emit the result value, even if unused, to evalute the side
> effects.
> const Expr *RV = S.getRetValue();
>
> - QualType FnRetTy = CurFuncDecl->getType().getCanonicalType();
> - FnRetTy = cast<FunctionType>(FnRetTy)->getResultType();
> -
> if (FnRetTy->isVoidType()) {
> // If the function returns void, emit ret void.
> Builder.CreateRetVoid();
>
> Is this intentional ?
Yes. These have been moved to instance methods variables and created
earlier because they can not be inferred in the same way for Objective-
C methods as for C functions.
> + // Skip the hidden arguments.
> + ++AI; ++AI;
>
> Name two hidden arguments in the comment.
Done.
> void CodeGenFunction::GenerateCode(const FunctionDecl *FD) {
> LLVMIntTy = ConvertType(getContext().IntTy);
> LLVMPointerWidth = static_cast<unsigned>(
>
> getContext
> ().getTypeSize(getContext().getPointerType(getContext().VoidTy)));
>
> CurFuncDecl = FD;
> + FnRetTy = CurFuncDecl->getType().getCanonicalType();
> + FnRetTy = cast<FunctionType>(FnRetTy)->getResultType();
> +
>
> Is this intentional ?
Yes. See above. These are set in GenerateCode and GenerateObjCMethod
now, so that they are the only two methods that need to know whether a
C function or an Objective-C method is being generated.
>> Finally, ivar.diff contains the code required for accessing and
>> modifying Objective-C instance variables. This depends on the
>> stuff in objc_struct.diff for all runtimes that do not use late-
>> bound instance variable addresses (i.e. all of the currently
>> supported ones).
>
> @@ -341,6 +345,17 @@
> return LValue::MakeAddr(CGM.GetAddrOfGlobalVar(VD, false));
> else {
> llvm::Value *V = LocalDeclMap[D];
> + // Check if it's an implicit argument
> + if (!V) {
> + std::string VarName(D->getName());
> + llvm::Function::arg_iterator AI = CurFn->arg_begin();
> + while(AI) {
> + if(VarName == AI->getName()) {
> + return LValue::MakeAddr(AI);
> + }
> + }
> + }
> assert(V && "BlockVarDecl not entered in LocalDeclMap?");
> return LValue::MakeAddr(V);
> }
>
> I'm getting dense here. Please explain what is "implicit argument"
> in this code? Thanks!
In Objective-C, a method is declared like this:
- (id) aMethodTakingAnInteger:(int)anInt andAnObject:(id)anObject
This is then converted to a C function like this:
id method(id self, SEL _cmd, int anInt, id anObject)
The two first arguments are implicit - they are not specified
explicitly in the code, but are inserted in both the caller and callee
by the compiler. They are not always self and _cmd (they are in the
GNU and Apple runtimes, but not in the Étoilé one).
On 25 Mar 2008, at 16:01, Chris Lattner wrote:
>
>> globals.diff is a simple addition to the global_ctors code which
>> avoids emitting empty global_ctors.
>
> A couple things here:
>
> Instead of nesting the entire body of the function, please just use:
>
> if (GlobalCtors.empty()) return;
Done.
> Second, you're implicitly reverting a cleanup fix:
>
> - llvm::StructType* CtorStructTy =
> - llvm::StructType::get(llvm::Type::Int32Ty, FPType, NULL);
>
> is better than:
>
> + std::vector<const llvm::Type*> CtorFields;
> + CtorFields.push_back(llvm::IntegerType::get(32));
> + // i32, function type pair
> + CtorFields.push_back(llvm::PointerType::getUnqual(CtorFuncTy));
> + llvm::StructType* CtorStructTy =
> llvm::StructType::get(CtorFields, false);
>
> Likewise the fix to inline GlobalCtorsVar and several other things.
>
> Finally, please make sure the code fits in 80 columns.
Ooops. svn said it was a conflict when I updated and I thought it was
just being wrong. I've reverted this to the version in svn and
reapplied the fixes and now it is more sensible.
>> etoile_runtime.diff contains a subclass of CGObjCRuntime which
>> implements the runtime-specific parts for the Étoilé runtime.
>> Other parts do not depend on this unless output for this runtime is
>> selected (the runtime to use is currently hard-coded). I am now
>> writing the GNU and Étoilé versions at the same time to make sure
>> the interfaces are sufficiently abstract. Hopefully this will make
>> adding support for the Apple runtimes easy for whoever gets that job.
>
> Ok. I'll let you worry about the correctness of this code :).
> Please make sure you follow coding conventions though. For example,
> don't include commented out code:
>
> +/*
> +clang::CodeGen::CGObjCRuntime *clang::CodeGen::CreateObjCRuntime(
> + llvm::Module &M,
> + const llvm::Type *LLVMIntType,
> + const llvm::Type *LLVMLongType) {
> + return new CGObjCEtoile(M, LLVMIntType, LLVMLongType);
> +}
> +*/
Ooops. I just have that for testing. At some point I need to add a
command-line option for selecting the runtime so I don't need a
recompile every time I want to switch. Want to give me any hints
about which bits of code I need to look at to do this?
> Please fit in 80 cols, please don't use macros:
>
> +#define SET(structure, index, value) do {\
> + llvm::Value *element_ptr = Builder.CreateStructGEP(structure,
> index);\
> + Builder.CreateStore(value, element_ptr);} while(0)
>
> (use a static function instead)
Fixed.
> Stuff like this won't work on 64-bit platforms:
>
> llvm::Constant *SelFunction =
> + TheModule.getOrInsertFunction("lookup_typed_selector",
> + SelectorTy,
> + PtrToInt8Ty,
> + PtrToInt8Ty,
> + 0);
> +
>
> Use NULL instead of 0. Likewise for StructType::get and other
> variadic functions.
Fixed everywhere I spotted it. Let me know if I've missed any...
> +#include <stdarg.h>
Ooops. That's left over from a helper function that's now in LLVM.
> I don't think you need this, but if you do, please use <cstdarg>
> instead.
>
> +//===------- CGObjCEtoile.cpp - Emit LLVM Code from ASTs for a
> Module --------===//
>
> This should follow the formating of the other files more closely.
Slightly confused - I copied the formatting directly from one of the
other files...
The attached diff contains all of the changes mentioned in this email,
and a few minor cleanups, but no completely new code.
David
-------------- next part --------------
A non-text attachment was scrubbed...
Name: clang.diff
Type: application/octet-stream
Size: 46666 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20080325/279df6ed/attachment.obj>
-------------- next part --------------
More information about the cfe-dev
mailing list