From: Fariborz Jahanian Date: Tue, 30 Oct 2012 20:05:29 +0000 (+0000) Subject: objective-C arc/mrr: Another patch for the new captured block variable X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c6abe9e0d94d82d566c716a1ab3c0fe6daadfb9c;p=clang objective-C arc/mrr: Another patch for the new captured block variable layout meta-data. It is currently off (so no tests). This is wip. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167047 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 5b49bcca09..12f5e0db0c 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -941,6 +941,20 @@ protected: ArrayRef RecFields, unsigned int BytePos, bool ForStrongLayout, bool &HasUnion); + + void UpdateRunSkipBlockVars(bool IsByref, + Qualifiers::ObjCLifetime LifeTime, + unsigned FieldOffset, + unsigned FieldSize); + + void BuildRCBlockVarRecordLayout(const RecordType *RT, + unsigned int BytePos, bool &HasUnion); + + void BuildRCRecordLayout(const llvm::StructLayout *RecLayout, + const RecordDecl *RD, + ArrayRef RecFields, + unsigned int BytePos, bool &HasUnion); + /// GetIvarLayoutName - Returns a unique constant for the given /// ivar layout bitmap. @@ -1946,6 +1960,170 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM, return C; } +void CGObjCCommonMac::UpdateRunSkipBlockVars(bool IsByref, + Qualifiers::ObjCLifetime LifeTime, + unsigned FieldOffset, + unsigned FieldSize) { + unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned FieldSizeInBytes = FieldSize/ByteSizeInBits; + + // __block variables are passed by their descriptor address. + if (IsByref) + RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_BYREF, FieldOffset, + FieldSizeInBytes)); + else if (LifeTime == Qualifiers::OCL_Strong) + RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_STRONG, FieldOffset, + FieldSizeInBytes)); + else if (LifeTime == Qualifiers::OCL_Weak) + RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_WEAK, FieldOffset, + FieldSizeInBytes)); + else if (LifeTime == Qualifiers::OCL_ExplicitNone) + RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_UNRETAINED, FieldOffset, + FieldSizeInBytes)); + else + RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_NON_OBJECT_BYTES, + FieldOffset, + FieldSizeInBytes)); +} + +void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout, + const RecordDecl *RD, + ArrayRef RecFields, + unsigned int BytePos, bool &HasUnion) { + bool IsUnion = (RD && RD->isUnion()); + uint64_t MaxUnionSize = 0; + const FieldDecl *MaxField = 0; + const FieldDecl *LastFieldBitfieldOrUnnamed = 0; + uint64_t MaxFieldOffset = 0; + uint64_t LastBitfieldOrUnnamedOffset = 0; + + if (RecFields.empty()) + return; + unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + + for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { + const FieldDecl *Field = RecFields[i]; + uint64_t FieldOffset; + // Note that 'i' here is actually the field index inside RD of Field, + // although this dependency is hidden. + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); + FieldOffset = (RL.getFieldOffset(i) / ByteSizeInBits); + + // Skip over unnamed or bitfields + if (!Field->getIdentifier() || Field->isBitField()) { + LastFieldBitfieldOrUnnamed = Field; + LastBitfieldOrUnnamedOffset = FieldOffset; + continue; + } + + LastFieldBitfieldOrUnnamed = 0; + QualType FQT = Field->getType(); + if (FQT->isRecordType() || FQT->isUnionType()) { + if (FQT->isUnionType()) + HasUnion = true; + + BuildRCBlockVarRecordLayout(FQT->getAs(), + BytePos + FieldOffset, HasUnion); + continue; + } + + if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) { + const ConstantArrayType *CArray = + dyn_cast_or_null(Array); + uint64_t ElCount = CArray->getSize().getZExtValue(); + assert(CArray && "only array with known element size is supported"); + FQT = CArray->getElementType(); + while (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) { + const ConstantArrayType *CArray = + dyn_cast_or_null(Array); + ElCount *= CArray->getSize().getZExtValue(); + FQT = CArray->getElementType(); + } + + assert(!FQT->isUnionType() && + "layout for array of unions not supported"); + if (FQT->isRecordType() && ElCount) { + int OldIndex = RunSkipBlockVars.size() - 1; + const RecordType *RT = FQT->getAs(); + BuildRCBlockVarRecordLayout(RT, BytePos + FieldOffset, + HasUnion); + + // Replicate layout information for each array element. Note that + // one element is already done. + uint64_t ElIx = 1; + for (int FirstIndex = RunSkipBlockVars.size() - 1 ;ElIx < ElCount; ElIx++) { + uint64_t Size = CGM.getContext().getTypeSize(RT)/ByteSizeInBits; + for (int i = OldIndex+1; i <= FirstIndex; ++i) + RunSkipBlockVars.push_back( + RUN_SKIP(RunSkipBlockVars[i].opcode, + RunSkipBlockVars[i].block_var_bytepos + Size*ElIx, + RunSkipBlockVars[i].block_var_size)); + } + continue; + } + } + unsigned FieldSize = CGM.getContext().getTypeSize(Field->getType()); + if (IsUnion) { + uint64_t UnionIvarSize = FieldSize; + if (UnionIvarSize > MaxUnionSize) { + MaxUnionSize = UnionIvarSize; + MaxField = Field; + MaxFieldOffset = FieldOffset; + } + } else { + UpdateRunSkipBlockVars(false, + Field->getType().getObjCLifetime(), + BytePos + FieldOffset, + FieldSize); + } + } + + if (LastFieldBitfieldOrUnnamed) { + if (LastFieldBitfieldOrUnnamed->isBitField()) { + // Last field was a bitfield. Must update the info. + uint64_t BitFieldSize + = LastFieldBitfieldOrUnnamed->getBitWidthValue(CGM.getContext()); + unsigned Size = (BitFieldSize / ByteSizeInBits) + + ((BitFieldSize % ByteSizeInBits) != 0); + Size += LastBitfieldOrUnnamedOffset; + UpdateRunSkipBlockVars(false, + LastFieldBitfieldOrUnnamed->getType().getObjCLifetime(), + BytePos + LastBitfieldOrUnnamedOffset, + Size*ByteSizeInBits); + } else { + assert(!LastFieldBitfieldOrUnnamed->getIdentifier() &&"Expected unnamed"); + // Last field was unnamed. Must update skip info. + unsigned FieldSize + = CGM.getContext().getTypeSize(LastFieldBitfieldOrUnnamed->getType()); + UpdateRunSkipBlockVars(false, + LastFieldBitfieldOrUnnamed->getType().getObjCLifetime(), + BytePos + LastBitfieldOrUnnamedOffset, + FieldSize); + } + } + + if (MaxField) + UpdateRunSkipBlockVars(false, + MaxField->getType().getObjCLifetime(), + BytePos + MaxFieldOffset, + MaxUnionSize); +} + +void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT, + unsigned int BytePos, + bool &HasUnion) { + const RecordDecl *RD = RT->getDecl(); + SmallVector Fields; + for (RecordDecl::field_iterator i = RD->field_begin(), + e = RD->field_end(); i != e; ++i) + Fields.push_back(*i); + llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0)); + const llvm::StructLayout *RecLayout = + CGM.getDataLayout().getStructLayout(cast(Ty)); + + BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion); +} + llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, const CGBlockInfo &blockInfo) { // FIXME. Temporary call the GC layout routine. @@ -1956,7 +2134,8 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy); RunSkipBlockVars.clear(); - // bool hasUnion = false; + bool hasUnion = false; + unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits; @@ -1983,31 +2162,14 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, uint64_t fieldOffset = layout->getElementOffset(capture.getIndex()); - // __block variables are passed by their descriptor address. - if (ci->isByRef()) { - RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_BYREF, fieldOffset, - WordSizeInBytes)); + assert(!type->isArrayType() && "array variable should not be caught"); + if (const RecordType *record = type->getAs()) { + BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion); continue; } - - assert(!type->isArrayType() && "array variable should not be caught"); - assert(!type->getAs() && - "BuildRCBlockLayout - captured records NYI"); - unsigned fieldSize = CGM.getContext().getTypeSize(type); - - if (type.getObjCLifetime() == Qualifiers::OCL_Strong) - RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_STRONG, fieldOffset, - WordSizeInBytes)); - else if (type.getObjCLifetime() == Qualifiers::OCL_Weak) - RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_WEAK, fieldOffset, - WordSizeInBytes)); - else if (type.getObjCLifetime() == Qualifiers::OCL_ExplicitNone) - RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_UNRETAINED, fieldOffset, - WordSizeInBytes)); - else - RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_NON_OBJECT_BYTES, fieldOffset, - fieldSize/ByteSizeInBits)); + UpdateRunSkipBlockVars(ci->isByRef(), type.getObjCLifetime(), + fieldOffset, fieldSize); } if (RunSkipBlockVars.empty()) @@ -2036,6 +2198,12 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, } unsigned size_in_bytes = end_byte_pos - start_byte_pos + RunSkipBlockVars[j-1].block_var_size; + if (j < size) { + unsigned gap = + RunSkipBlockVars[j].block_var_bytepos - + RunSkipBlockVars[j-1].block_var_bytepos - RunSkipBlockVars[j-1].block_var_size; + size_in_bytes += gap; + } unsigned residue_in_bytes = 0; if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES) { residue_in_bytes = size_in_bytes & mask;