From 0c58ce9346e9a6366bd57f4531b267bda68ac6b0 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Sat, 27 Oct 2012 21:10:38 +0000 Subject: [PATCH] objective-C arc/mrr: Patch for the new block variable layout meta-data. It is currently off (so no tests). This is wip. llvm-svn: 166892 --- clang/lib/CodeGen/CGBlocks.cpp | 8 +- clang/lib/CodeGen/CGObjCGNU.cpp | 5 +- clang/lib/CodeGen/CGObjCMac.cpp | 167 +++++++++++++++++++++++++++++++++++++- clang/lib/CodeGen/CGObjCRuntime.h | 2 + 4 files changed, 176 insertions(+), 6 deletions(-) diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index 3e126f8..00203be 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -103,8 +103,12 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, CGM.GetAddrOfConstantCString(typeAtEncoding), i8p)); // GC layout. - if (C.getLangOpts().ObjC1) - elements.push_back(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo)); + if (C.getLangOpts().ObjC1) { + if (CGM.getLangOpts().getGC() != LangOptions::NonGC) + elements.push_back(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo)); + else + elements.push_back(CGM.getObjCRuntime().BuildRCBlockLayout(CGM, blockInfo)); + } else elements.push_back(llvm::Constant::getNullValue(i8p)); diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index 80fa2af..3cf7baa 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -533,7 +533,10 @@ public: const CGBlockInfo &blockInfo) { return NULLPtr; } - + virtual llvm::Constant *BuildRCBlockLayout(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) { + return NULLPtr; + } virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) { return 0; } diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 99a59cb..5b49bcc 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -811,9 +811,10 @@ public: public: enum BLOCK_LAYOUT_OPCODE opcode; unsigned block_var_bytepos; + unsigned block_var_size; RUN_SKIP(enum BLOCK_LAYOUT_OPCODE Opcode = BLOCK_LAYOUT_OPERATOR, - unsigned BytePos = 0) - : opcode(Opcode), block_var_bytepos(BytePos) {} + unsigned BytePos = 0, unsigned Size = 0) + : opcode(Opcode), block_var_bytepos(BytePos), block_var_size(Size) {} // Allow sorting based on byte pos. bool operator<(const RUN_SKIP &b) const { @@ -1030,6 +1031,8 @@ public: virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0; virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM, const CGBlockInfo &blockInfo); + virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM, + const CGBlockInfo &blockInfo); }; @@ -1858,8 +1861,8 @@ static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) { llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM, const CGBlockInfo &blockInfo) { + llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy); - if (CGM.getLangOpts().getGC() == LangOptions::NonGC && !CGM.getLangOpts().ObjCAutoRefCount) return nullPtr; @@ -1943,6 +1946,164 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM, return C; } +llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) { + // FIXME. Temporary call the GC layout routine. + return BuildGCBlockLayout(CGM, blockInfo); + + assert(CGM.getLangOpts().getGC() == LangOptions::NonGC); + + llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy); + + RunSkipBlockVars.clear(); + // bool hasUnion = false; + unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits; + + const BlockDecl *blockDecl = blockInfo.getBlockDecl(); + + // Calculate the basic layout of the block structure. + const llvm::StructLayout *layout = + CGM.getDataLayout().getStructLayout(blockInfo.StructureType); + + // Ignore the optional 'this' capture: C++ objects are not assumed + // to be GC'ed. + + // Walk the captured variables. + for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(), + ce = blockDecl->capture_end(); ci != ce; ++ci) { + const VarDecl *variable = ci->getVariable(); + QualType type = variable->getType(); + + const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); + + // Ignore constant captures. + if (capture.isConstant()) continue; + + 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)); + 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)); + } + + if (RunSkipBlockVars.empty()) + return nullPtr; + + // Sort on byte position; captures might not be allocated in order, + // and unions can do funny things. + llvm::array_pod_sort(RunSkipBlockVars.begin(), RunSkipBlockVars.end()); + std::string Layout; + + unsigned size = RunSkipBlockVars.size(); + unsigned int shift = (WordSizeInBytes == 8) ? 3 : 2; + unsigned int mask = (WordSizeInBytes == 8) ? 0x7 : 0x3; + for (unsigned i = 0; i < size; i++) { + enum BLOCK_LAYOUT_OPCODE opcode = RunSkipBlockVars[i].opcode; + unsigned start_byte_pos = RunSkipBlockVars[i].block_var_bytepos; + unsigned end_byte_pos = start_byte_pos; + unsigned j = i+1; + while (j < size) { + if (opcode == RunSkipBlockVars[j].opcode) { + end_byte_pos = RunSkipBlockVars[j++].block_var_bytepos; + i++; + } + else + break; + } + unsigned size_in_bytes = + end_byte_pos - start_byte_pos + RunSkipBlockVars[j-1].block_var_size; + unsigned residue_in_bytes = 0; + if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES) { + residue_in_bytes = size_in_bytes & mask; + size_in_bytes -= residue_in_bytes; + opcode = BLOCK_LAYOUT_NON_OBJECT_WORDS; + } + + unsigned size_in_words = size_in_bytes >> shift; + while (size_in_words >= 16) { + // Note that value in imm. is one less that the actual + // value. So, 0xff means 16 words follow! + unsigned char inst = (opcode << 4) | 0xff; + Layout += inst; + size_in_words -= 16; + } + if (size_in_words > 0) { + // Note that value in imm. is one less that the actual + // value. So, we subtract 1 away! + unsigned char inst = (opcode << 4) | (size_in_words-1); + Layout += inst; + } + if (residue_in_bytes > 0) { + unsigned char inst = (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | residue_in_bytes; + Layout += inst; + } + } + if (CGM.getLangOpts().ObjCGCBitmapPrint) { + printf("\n block variable layout: "); + for (unsigned i = 0, e = Layout.size(); i != e; i++) { + unsigned char inst = Layout[i]; + enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4); + unsigned delta = 1; + switch (opcode) { + case BLOCK_LAYOUT_OPERATOR: + printf("BL_OPERATOR:"); + break; + case BLOCK_LAYOUT_NON_OBJECT_BYTES: + printf("BL_NON_OBJECT_BYTES:"); + delta = 0; + break; + case BLOCK_LAYOUT_NON_OBJECT_WORDS: + printf("BL_NON_OBJECT_WORD:"); + break; + case BLOCK_LAYOUT_STRONG: + printf("BL_STRONG:"); + break; + case BLOCK_LAYOUT_BYREF: + printf("BL_BYREF:"); + break; + case BLOCK_LAYOUT_WEAK: + printf("BL_WEAK:"); + break; + case BLOCK_LAYOUT_UNRETAINED: + printf("BL_UNRETAINE:"); + break; + } + // Actual value of word count is one more that what is in the imm. + // field of the instruction + printf("%d", (inst & 0xf) + delta); + if (i < e-1) + printf(", "); + else + printf("\n"); + } + } + return nullPtr; +} + llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder, const ObjCProtocolDecl *PD) { // FIXME: I don't understand why gcc generates this, or where it is diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h index 219a3e4..bc6589d 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.h +++ b/clang/lib/CodeGen/CGObjCRuntime.h @@ -261,6 +261,8 @@ public: llvm::Value *Size) = 0; virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM, const CodeGen::CGBlockInfo &blockInfo) = 0; + virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM, + const CodeGen::CGBlockInfo &blockInfo) = 0; virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) = 0; struct MessageSendInfo { -- 2.7.4