From 9777687562c338601c2f17906e65e1c1a0aad96f Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 22 Apr 2009 07:32:20 +0000 Subject: [PATCH] Merge ivar access amongst the three runtimes. - For now, this means we are always doing the address computations by hand instead of constructing a proper GEP. Right now, however, this is less important than having fewer entry points to dealing with Objective-C interface layout. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69787 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGObjCGNU.cpp | 24 +--- lib/CodeGen/CGObjCMac.cpp | 223 ++++++++++++++++-------------------- lib/CodeGen/CGObjCRuntime.h | 24 +++- 3 files changed, 124 insertions(+), 147 deletions(-) diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index a1bc9b7ad4..b3054cce35 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -1082,32 +1082,14 @@ LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers) { const ObjCInterfaceDecl *ID = ObjectTy->getAsObjCInterfaceType()->getDecl(); - const FieldDecl *Field = ID->lookupFieldDeclForIvar(CGM.getContext(), Ivar); - if (Ivar->isBitField()) - return CGF.EmitLValueForBitfield(BaseValue, const_cast(Field), - CVRQualifiers); - // TODO: Add a special case for isa (index 0) - unsigned Index = CGM.getTypes().getLLVMFieldNo(Field); - llvm::Value *V = CGF.Builder.CreateStructGEP(BaseValue, Index, "tmp"); - LValue LV = LValue::MakeAddr(V, - Ivar->getType().getCVRQualifiers()|CVRQualifiers); - LValue::SetObjCIvar(LV, true); - return LV; + return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, + EmitIvarOffset(CGF, ID, Ivar)); } llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGen::CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar) { - const llvm::Type *InterfaceLTy = - CGM.getTypes().ConvertType( - CGM.getContext().getObjCInterfaceType(Interface)); - const llvm::StructLayout *Layout = - CGM.getTargetData().getStructLayout(cast(InterfaceLTy)); - const FieldDecl *Field = - Interface->lookupFieldDeclForIvar(CGM.getContext(), Ivar); - uint64_t Offset = - Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(Field)); - + uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar); return llvm::ConstantInt::get( CGM.getTypes().ConvertType(CGM.getContext().LongTy), Offset); diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index d3ac8c92e2..7d1cea7e0e 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -29,6 +29,78 @@ using namespace clang; using namespace CodeGen; +// Common CGObjCRuntime functions, these don't belong here, but they +// don't belong in CGObjCRuntime either so we will live with it for +// now. + +uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, + const ObjCInterfaceDecl *OID, + const ObjCIvarDecl *Ivar) { + assert(!OID->isForwardDecl() && "Invalid interface decl!"); + QualType T = CGM.getContext().getObjCInterfaceType(OID); + const llvm::StructType *InterfaceTy = + cast(CGM.getTypes().ConvertType(T)); + const llvm::StructLayout *Layout = + CGM.getTargetData().getStructLayout(InterfaceTy); + const FieldDecl *Field = + OID->lookupFieldDeclForIvar(CGM.getContext(), Ivar); + if (!Field->isBitField()) + return Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(Field)); + + // FIXME. Must be a better way of getting a bitfield base offset. + CodeGenTypes::BitFieldInfo BFI = CGM.getTypes().getBitFieldInfo(Field); + // FIXME: The "field no" for bitfields is something completely + // different; it is the offset in multiples of the base type size! + uint64_t Offset = CGM.getTypes().getLLVMFieldNo(Field); + const llvm::Type *Ty = + CGM.getTypes().ConvertTypeForMemRecursive(Field->getType()); + Offset *= CGM.getTypes().getTargetData().getTypePaddedSizeInBits(Ty); + return (Offset + BFI.Begin) / 8; +} + +LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, + const ObjCInterfaceDecl *OID, + llvm::Value *BaseValue, + const ObjCIvarDecl *Ivar, + unsigned CVRQualifiers, + llvm::Value *Offset) { + // FIXME: For now, we use an implementation based on just computing + // the offset and calculating things directly. For optimization + // purposes, it would be cleaner to use a GEP on the proper type + // since the structure layout is fixed; however for that we need to + // be able to walk the class chain for an Ivar. + const FieldDecl *Field = + OID->lookupFieldDeclForIvar(CGF.CGM.getContext(), Ivar); + + // (char *) BaseValue + llvm::Type *I8Ptr = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, I8Ptr); + // (char*)BaseValue + Offset_symbol + V = CGF.Builder.CreateGEP(V, Offset, "add.ptr"); + // (type *)((char*)BaseValue + Offset_symbol) + const llvm::Type *IvarTy = + CGF.CGM.getTypes().ConvertTypeForMem(Ivar->getType()); + llvm::Type *ptrIvarTy = llvm::PointerType::getUnqual(IvarTy); + V = CGF.Builder.CreateBitCast(V, ptrIvarTy); + + if (Ivar->isBitField()) { + QualType FieldTy = Field->getType(); + CodeGenTypes::BitFieldInfo bitFieldInfo = + CGF.CGM.getTypes().getBitFieldInfo(Field); + return LValue::MakeBitfield(V, bitFieldInfo.Begin % 8, bitFieldInfo.Size, + FieldTy->isSignedIntegerType(), + FieldTy.getCVRQualifiers()|CVRQualifiers); + } + + LValue LV = LValue::MakeAddr(V, + Ivar->getType().getCVRQualifiers()|CVRQualifiers, + CGF.CGM.getContext().getObjCGCAttrKind(Ivar->getType())); + LValue::SetObjCIvar(LV, true); + return LV; +} + +/// + namespace { typedef std::vector ConstantVector; @@ -731,10 +803,6 @@ protected: /// defined. The return value has type ProtocolPtrTy. llvm::Constant *GetProtocolRef(const ObjCProtocolDecl *PD); - /// GetIvarBaseOffset - returns ivars byte offset. - uint64_t GetIvarBaseOffset(const llvm::StructLayout *Layout, - const FieldDecl *Field); - /// GetFieldBaseOffset - return's field byte offset. uint64_t GetFieldBaseOffset(const ObjCInterfaceDecl *OI, const llvm::StructLayout *Layout, @@ -2015,7 +2083,6 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, ObjCInterfaceDecl *OID = const_cast(ID->getClassInterface()); - const llvm::StructLayout *Layout = GetInterfaceDeclStructLayout(OID); llvm::SmallVector OIvars; GetNamedIvarList(OID, OIvars); @@ -2026,7 +2093,7 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, Ivar[0] = GetMethodVarName(Field->getIdentifier()); Ivar[1] = GetMethodVarType(Field); Ivar[2] = llvm::ConstantInt::get(ObjCTypes.IntTy, - GetIvarBaseOffset(Layout, Field)); + ComputeIvarBaseOffset(CGM, OID, IVD)); Ivars.push_back(llvm::ConstantStruct::get(ObjCTypes.IvarTy, Ivar)); } @@ -2124,32 +2191,14 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD, return Method; } -uint64_t CGObjCCommonMac::GetIvarBaseOffset(const llvm::StructLayout *Layout, - const FieldDecl *Field) { - if (!Field->isBitField()) - return Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(Field)); - - // FIXME. Must be a better way of getting a bitfield base offset. - CodeGenTypes::BitFieldInfo BFI = CGM.getTypes().getBitFieldInfo(Field); - // FIXME: The "field no" for bitfields is something completely - // different; it is the offset in multiples of the base type size! - uint64_t Offset = CGM.getTypes().getLLVMFieldNo(Field); - const llvm::Type *Ty = - CGM.getTypes().ConvertTypeForMemRecursive(Field->getType()); - Offset *= CGM.getTypes().getTargetData().getTypePaddedSizeInBits(Ty); - return (Offset + BFI.Begin) / 8; -} - /// GetFieldBaseOffset - return the field's byte offset. uint64_t CGObjCCommonMac::GetFieldBaseOffset(const ObjCInterfaceDecl *OI, const llvm::StructLayout *Layout, const FieldDecl *Field) { - // Is this a c struct? + // Is this a C struct? if (!OI) return Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(Field)); - const ObjCIvarDecl *Ivar = cast(Field); - const FieldDecl *FD = OI->lookupFieldDeclForIvar(CGM.getContext(), Ivar); - return GetIvarBaseOffset(Layout, FD); + return ComputeIvarBaseOffset(CGM, OI, cast(Field)); } llvm::GlobalVariable * @@ -2628,27 +2677,14 @@ LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers) { const ObjCInterfaceDecl *ID = ObjectTy->getAsObjCInterfaceType()->getDecl(); - const FieldDecl *Field = ID->lookupFieldDeclForIvar(CGM.getContext(), Ivar); - if (Ivar->isBitField()) - return CGF.EmitLValueForBitfield(BaseValue, const_cast(Field), - CVRQualifiers); - // TODO: Add a special case for isa (index 0) - unsigned Index = CGM.getTypes().getLLVMFieldNo(Field); - llvm::Value *V = CGF.Builder.CreateStructGEP(BaseValue, Index, "tmp"); - LValue LV = LValue::MakeAddr(V, - Ivar->getType().getCVRQualifiers()|CVRQualifiers, - CGM.getContext().getObjCGCAttrKind(Ivar->getType())); - LValue::SetObjCIvar(LV, true); - return LV; + return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, + EmitIvarOffset(CGF, ID, Ivar)); } llvm::Value *CGObjCMac::EmitIvarOffset(CodeGen::CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar) { - const llvm::StructLayout *Layout = GetInterfaceDeclStructLayout(Interface); - const FieldDecl *Field = - Interface->lookupFieldDeclForIvar(CGM.getContext(), Ivar); - uint64_t Offset = GetIvarBaseOffset(Layout, Field); + uint64_t Offset = ComputeIvarBaseOffset(CGM, Interface, Ivar); return llvm::ConstantInt::get( CGM.getTypes().ConvertType(CGM.getContext().LongTy), Offset); @@ -4219,62 +4255,28 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData( return GV; } -/// countInheritedIvars - count number of ivars in class and its super class(s) -/// -static int countInheritedIvars(const ObjCInterfaceDecl *OI, - ASTContext &Context) { - int count = 0; - if (!OI) - return 0; - const ObjCInterfaceDecl *SuperClass = OI->getSuperClass(); - if (SuperClass) - count += countInheritedIvars(SuperClass, Context); - for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(), - E = OI->ivar_end(); I != E; ++I) - ++count; - // look into properties. - for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(Context), - E = OI->prop_end(Context); I != E; ++I) { - if ((*I)->getPropertyIvarDecl()) - ++count; - } - return count; -} - void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCInterfaceDecl *OID, uint32_t &InstanceStart, uint32_t &InstanceSize) { - assert(!OID->isForwardDecl() && "Invalid interface decl!"); - const llvm::StructLayout *Layout = GetInterfaceDeclStructLayout(OID); - - int countSuperClassIvars = countInheritedIvars(OID->getSuperClass(), - CGM.getContext()); - const RecordDecl *RD = CGM.getContext().addRecordToClass(OID); - RecordDecl::field_iterator firstField = RD->field_begin(CGM.getContext()); - RecordDecl::field_iterator lastField = RD->field_end(CGM.getContext()); - while (countSuperClassIvars-- > 0) { - lastField = firstField; - ++firstField; - } - - for (RecordDecl::field_iterator e = RD->field_end(CGM.getContext()), - ifield = firstField; ifield != e; ++ifield) - lastField = ifield; - - InstanceStart = InstanceSize = 0; - if (lastField != RD->field_end(CGM.getContext())) { - FieldDecl *Field = *lastField; - const llvm::Type *FieldTy = - CGM.getTypes().ConvertTypeForMem(Field->getType()); - unsigned Size = CGM.getTargetData().getTypePaddedSize(FieldTy); - InstanceSize = GetIvarBaseOffset(Layout, Field) + Size; - if (firstField == RD->field_end(CGM.getContext())) - InstanceStart = InstanceSize; - else { - Field = *firstField; - InstanceStart = GetIvarBaseOffset(Layout, Field); - } + // Find first and last (non-padding) ivars in this interface. + + // FIXME: Use iterator. + llvm::SmallVector OIvars; + GetNamedIvarList(OID, OIvars); + + if (OIvars.empty()) { + InstanceStart = InstanceSize = 0; + return; } + + const ObjCIvarDecl *First = OIvars.front(); + const ObjCIvarDecl *Last = OIvars.back(); + + InstanceStart = ComputeIvarBaseOffset(CGM, OID, First); + const llvm::Type *FieldTy = + CGM.getTypes().ConvertTypeForMem(Last->getType()); + unsigned Size = CGM.getTargetData().getTypePaddedSize(FieldTy); + InstanceSize = ComputeIvarBaseOffset(CGM, OID, Last) + Size; } void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { @@ -4639,7 +4641,6 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( assert(OID && "CGObjCNonFragileABIMac::EmitIvarList - null interface"); // FIXME. Consolidate this with similar code in GenerateClass. - const llvm::StructLayout *Layout = GetInterfaceDeclStructLayout(OID); // Collect declared and synthesized ivars in a small vector. llvm::SmallVector OIvars; @@ -4649,7 +4650,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( ObjCIvarDecl *IVD = OIvars[i]; const FieldDecl *Field = OID->lookupFieldDeclForIvar(CGM.getContext(), IVD); Ivar[0] = EmitIvarOffsetVar(ID->getClassInterface(), IVD, - GetIvarBaseOffset(Layout, Field)); + ComputeIvarBaseOffset(CGM, OID, IVD)); Ivar[1] = GetMethodVarName(Field->getIdentifier()); Ivar[2] = GetMethodVarType(Field); const llvm::Type *FieldTy = @@ -4922,34 +4923,8 @@ LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar( const ObjCIvarDecl *Ivar, unsigned CVRQualifiers) { const ObjCInterfaceDecl *ID = ObjectTy->getAsObjCInterfaceType()->getDecl(); - const FieldDecl *Field = ID->lookupFieldDeclForIvar(CGM.getContext(), Ivar); - llvm::GlobalVariable *IvarOffsetGV = ObjCIvarOffsetVariable(ID, Ivar); - - // (char *) BaseValue - llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, ObjCTypes.Int8PtrTy); - llvm::Value *Offset = CGF.Builder.CreateLoad(IvarOffsetGV); - // (char*)BaseValue + Offset_symbol - V = CGF.Builder.CreateGEP(V, Offset, "add.ptr"); - // (type *)((char*)BaseValue + Offset_symbol) - const llvm::Type *IvarTy = - CGM.getTypes().ConvertTypeForMem(Ivar->getType()); - llvm::Type *ptrIvarTy = llvm::PointerType::getUnqual(IvarTy); - V = CGF.Builder.CreateBitCast(V, ptrIvarTy); - - if (Ivar->isBitField()) { - QualType FieldTy = Field->getType(); - CodeGenTypes::BitFieldInfo bitFieldInfo = - CGM.getTypes().getBitFieldInfo(Field); - return LValue::MakeBitfield(V, bitFieldInfo.Begin, bitFieldInfo.Size, - FieldTy->isSignedIntegerType(), - FieldTy.getCVRQualifiers()|CVRQualifiers); - } - - LValue LV = LValue::MakeAddr(V, - Ivar->getType().getCVRQualifiers()|CVRQualifiers, - CGM.getContext().getObjCGCAttrKind(Ivar->getType())); - LValue::SetObjCIvar(LV, true); - return LV; + return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, + EmitIvarOffset(CGF, ID, Ivar)); } llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset( diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index cae32edf04..28ee0f4e9f 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -25,10 +25,11 @@ namespace llvm { class Constant; + class Function; + class Module; + class StructLayout; class Type; class Value; - class Module; - class Function; } namespace clang { @@ -36,6 +37,7 @@ namespace CodeGen { class CodeGenFunction; } + class FieldDecl; class ObjCAtTryStmt; class ObjCAtThrowStmt; class ObjCAtSynchronizedStmt; @@ -58,6 +60,24 @@ namespace CodeGen { /// Implements runtime-specific code generation functions. class CGObjCRuntime { +protected: + // Utility functions for unified ivar access. These need to + // eventually be folded into other places (the structure layout + // code). + + // Compute an offset to the given ivar, suitable for passing to + // EmitValueForIvarAtOffset. Note that the correct handling of + // bit-fields is carefully coordinated by these two, use caution! + uint64_t ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, + const ObjCInterfaceDecl *OID, + const ObjCIvarDecl *Ivar); + + LValue EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, + const ObjCInterfaceDecl *OID, + llvm::Value *BaseValue, + const ObjCIvarDecl *Ivar, + unsigned CVRQualifiers, + llvm::Value *Offset); public: virtual ~CGObjCRuntime(); -- 2.50.1