objective-C block meta-data. This patch completes meta-data
generation for captured block variables in arc mode. This includes
inlined version of the meta-data when it can be done. It also includes
severat tests. This is wip. // rdar://12184410.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167241 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 00203be..6742f36 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -27,7 +27,8 @@
CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name)
: Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false),
- HasCXXObject(false), UsesStret(false), StructureType(0), Block(block),
+ HasCXXObject(false), UsesStret(false), HasCapturedVariableLayout(false),
+ StructureType(0), Block(block),
DominatingIP(0) {
// Skip asm prefix, if any. 'name' is usually taken directly from
@@ -308,7 +309,10 @@
info.CanBeGlobal = true;
return;
}
-
+ else if (C.getLangOpts().ObjC1 &&
+ CGM.getLangOpts().getGC() == LangOptions::NonGC)
+ info.HasCapturedVariableLayout = true;
+
// Collect the layout chunks.
SmallVector<BlockLayoutChunk, 16> layout;
layout.reserve(block->capturesCXXThis() +
@@ -667,6 +671,7 @@
// Compute the initial on-stack block flags.
BlockFlags flags = BLOCK_HAS_SIGNATURE;
+ if (blockInfo.HasCapturedVariableLayout) flags |= BLOCK_HAS_EXTENDED_LAYOUT;
if (blockInfo.NeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE;
if (blockInfo.HasCXXObject) flags |= BLOCK_HAS_CXX_OBJ;
if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET;
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 690fa8b..6263562 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -59,6 +59,7 @@
};
enum BlockLiteralFlags {
+ BLOCK_HAS_EXTENDED_LAYOUT = (1 << 23),
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CXX_OBJ = (1 << 26),
BLOCK_IS_GLOBAL = (1 << 28),
@@ -193,6 +194,10 @@
/// UsesStret : True if the block uses an stret return. Mutable
/// because it gets set later in the block-creation process.
mutable bool UsesStret : 1;
+
+ /// HasCapturedVariableLayout : True if block has captured variables
+ /// and their layout meta-data has been generated.
+ bool HasCapturedVariableLayout : 1;
/// The mapping of allocated indexes within the block.
llvm::DenseMap<const VarDecl*, Capture> Captures;
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 12f5e0d..c67e3fd 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -955,6 +955,8 @@
ArrayRef<const FieldDecl*> RecFields,
unsigned int BytePos, bool &HasUnion);
+ uint64_t InlineLayoutInstruction(SmallVectorImpl<unsigned char> &Layout);
+
/// GetIvarLayoutName - Returns a unique constant for the given
/// ivar layout bitmap.
@@ -2124,11 +2126,114 @@
BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion);
}
+/// InlineLayoutInstruction - This routine produce an inline instruction for the
+/// block variable layout if it can. If not, it returns 0. Rules are as follow:
+/// If ((uintptr_t) layout) < (1 << 12), the layout is inline. In the 64bit world,
+/// an inline layout of value 0x0000000000000xyz is interpreted as follows:
+/// x captured object pointers of BLOCK_LAYOUT_STRONG. Followed by
+/// y captured object of BLOCK_LAYOUT_BYREF. Followed by
+/// z captured object of BLOCK_LAYOUT_WEAK. If any of the above is missing, zero
+/// replaces it. For example, 0x00000x00 means x BLOCK_LAYOUT_STRONG and no
+/// BLOCK_LAYOUT_BYREF and no BLOCK_LAYOUT_WEAK objects are captured.
+uint64_t CGObjCCommonMac::InlineLayoutInstruction(
+ SmallVectorImpl<unsigned char> &Layout) {
+ uint64_t Result = 0;
+ if (Layout.size() <= 3) {
+ unsigned size = Layout.size();
+ unsigned strong_word_count = 0, byref_word_count=0, weak_word_count=0;
+ unsigned char inst;
+ enum BLOCK_LAYOUT_OPCODE opcode ;
+ switch (size) {
+ case 3:
+ inst = Layout[0];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_STRONG)
+ strong_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ inst = Layout[1];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_BYREF)
+ byref_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ inst = Layout[2];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ break;
+
+ case 2:
+ inst = Layout[0];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_STRONG) {
+ strong_word_count = (inst & 0xF)+1;
+ inst = Layout[1];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_BYREF)
+ byref_word_count = (inst & 0xF)+1;
+ else if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ }
+ else if (opcode == BLOCK_LAYOUT_BYREF) {
+ byref_word_count = (inst & 0xF)+1;
+ inst = Layout[1];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ }
+ else
+ return 0;
+ break;
+
+ case 1:
+ inst = Layout[0];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_STRONG)
+ strong_word_count = (inst & 0xF)+1;
+ else if (opcode == BLOCK_LAYOUT_BYREF)
+ byref_word_count = (inst & 0xF)+1;
+ else if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ break;
+
+ default:
+ return 0;
+ }
+
+ // Cannot inline when any of the word counts is 15. Because this is one less
+ // than the actual work count (so 15 means 16 actual word counts),
+ // and we can only display 0 thru 15 word counts.
+ if (strong_word_count == 16 || byref_word_count == 16 || weak_word_count == 16)
+ return 0;
+
+ unsigned count =
+ (strong_word_count != 0) + (byref_word_count != 0) + (weak_word_count != 0);
+
+ if (size == count) {
+ if (strong_word_count)
+ Result = strong_word_count;
+ Result <<= 4;
+ if (byref_word_count)
+ Result += byref_word_count;
+ Result <<= 4;
+ if (weak_word_count)
+ Result += weak_word_count;
+ }
+ }
+ return Result;
+}
+
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);
@@ -2167,7 +2272,8 @@
BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion);
continue;
}
- unsigned fieldSize = CGM.getContext().getTypeSize(type);
+ unsigned fieldSize = ci->isByRef() ? WordSizeInBits
+ : CGM.getContext().getTypeSize(type);
UpdateRunSkipBlockVars(ci->isByRef(), type.getObjCLifetime(),
fieldOffset, fieldSize);
}
@@ -2178,7 +2284,7 @@
// 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;
+ SmallVector<unsigned char, 16> Layout;
unsigned size = RunSkipBlockVars.size();
unsigned int shift = (WordSizeInBytes == 8) ? 3 : 2;
@@ -2214,35 +2320,70 @@
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;
+ // value. So, 0xf means 16 words follow!
+ unsigned char inst = (opcode << 4) | 0xf;
+ Layout.push_back(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;
+ Layout.push_back(inst);
}
if (residue_in_bytes > 0) {
- unsigned char inst = (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | residue_in_bytes;
- Layout += inst;
+ unsigned char inst =
+ (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes-1);
+ Layout.push_back(inst);
}
}
+
+ int e = Layout.size()-1;
+ while (e >= 0) {
+ unsigned char inst = Layout[e--];
+ enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES || opcode == BLOCK_LAYOUT_NON_OBJECT_WORDS)
+ Layout.pop_back();
+ else
+ break;
+ }
+
+ uint64_t Result = InlineLayoutInstruction(Layout);
+ if (Result != 0) {
+ // Block variable layout instruction has been inlined.
+ if (CGM.getLangOpts().ObjCGCBitmapPrint) {
+ printf("\n Inline instruction for block variable layout: ");
+ printf("0x0%llx\n", Result);
+ }
+ if (WordSizeInBytes == 8) {
+ const llvm::APInt Instruction(64, Result);
+ return llvm::Constant::getIntegerValue(CGM.Int64Ty, Instruction);
+ }
+ else {
+ const llvm::APInt Instruction(32, Result);
+ return llvm::Constant::getIntegerValue(CGM.Int32Ty, Instruction);
+ }
+ }
+
+ unsigned char inst = (BLOCK_LAYOUT_OPERATOR << 4) | 0;
+ Layout.push_back(inst);
+ std::string BitMap;
+ for (unsigned i = 0, e = Layout.size(); i != e; i++)
+ BitMap += Layout[i];
+
if (CGM.getLangOpts().ObjCGCBitmapPrint) {
printf("\n block variable layout: ");
- for (unsigned i = 0, e = Layout.size(); i != e; i++) {
- unsigned char inst = Layout[i];
+ for (unsigned i = 0, e = BitMap.size(); i != e; i++) {
+ unsigned char inst = BitMap[i];
enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
unsigned delta = 1;
switch (opcode) {
case BLOCK_LAYOUT_OPERATOR:
printf("BL_OPERATOR:");
+ delta = 0;
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:");
@@ -2257,7 +2398,7 @@
printf("BL_WEAK:");
break;
case BLOCK_LAYOUT_UNRETAINED:
- printf("BL_UNRETAINE:");
+ printf("BL_UNRETAINED:");
break;
}
// Actual value of word count is one more that what is in the imm.
@@ -2269,7 +2410,12 @@
printf("\n");
}
}
- return nullPtr;
+
+ llvm::GlobalVariable * Entry =
+ CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
+ llvm::ConstantDataArray::getString(VMContext, BitMap,false),
+ "__TEXT,__objc_classname,cstring_literals", 1, true);
+ return getConstantGEP(VMContext, Entry, 0, 0);
}
llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder,