[cfe-commits] r167241 - in /cfe/trunk: lib/CodeGen/CGBlocks.cpp lib/CodeGen/CGBlocks.h lib/CodeGen/CGObjCMac.cpp test/CodeGenObjC/arc-block-ivar-layout.m test/CodeGenObjC/arc-blocks.m test/CodeGenObjC/arc-captured-block-var-inlined-layout.m test/CodeGenObjC/arc-captured-block-var-layout.m
Fariborz Jahanian
fjahanian at apple.com
Thu Nov 1 11:32:56 PDT 2012
Author: fjahanian
Date: Thu Nov 1 13:32:55 2012
New Revision: 167241
URL: http://llvm.org/viewvc/llvm-project?rev=167241&view=rev
Log:
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.
Added:
cfe/trunk/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m
cfe/trunk/test/CodeGenObjC/arc-captured-block-var-layout.m
Removed:
cfe/trunk/test/CodeGenObjC/arc-block-ivar-layout.m
Modified:
cfe/trunk/lib/CodeGen/CGBlocks.cpp
cfe/trunk/lib/CodeGen/CGBlocks.h
cfe/trunk/lib/CodeGen/CGObjCMac.cpp
cfe/trunk/test/CodeGenObjC/arc-blocks.m
Modified: cfe/trunk/lib/CodeGen/CGBlocks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.cpp?rev=167241&r1=167240&r2=167241&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBlocks.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGBlocks.cpp Thu Nov 1 13:32:55 2012
@@ -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;
Modified: cfe/trunk/lib/CodeGen/CGBlocks.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBlocks.h?rev=167241&r1=167240&r2=167241&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBlocks.h (original)
+++ cfe/trunk/lib/CodeGen/CGBlocks.h Thu Nov 1 13:32:55 2012
@@ -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;
Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=167241&r1=167240&r2=167241&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Thu Nov 1 13:32:55 2012
@@ -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,
Removed: cfe/trunk/test/CodeGenObjC/arc-block-ivar-layout.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-block-ivar-layout.m?rev=167240&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-block-ivar-layout.m (original)
+++ cfe/trunk/test/CodeGenObjC/arc-block-ivar-layout.m (removed)
@@ -1,60 +0,0 @@
-// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -emit-llvm %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
-// rdar://8991729
-
-__weak id wid;
-void x(id y) {}
-void y(int a) {}
-
-extern id opaque_id();
-
-void f() {
- __block int byref_int = 0;
- char ch = 'a';
- char ch1 = 'b';
- char ch2 = 'c';
- short sh = 2;
- const id bar = (id) opaque_id();
- id baz = 0;
- __strong id strong_void_sta;
- __block id byref_bab = (id)0;
- __block id bl_var1;
- int i; double dob;
-
-// The patterns here are a sequence of bytes, each saying first how
-// many sizeof(void*) chunks to skip (high nibble) and then how many
-// to scan (low nibble). A zero byte says that we've reached the end
-// of the pattern.
-//
-// All of these patterns start with 01 3x because the block header on
-// LP64 consists of an isa pointer (which we're supposed to scan for
-// some reason) followed by three words (2 ints, a function pointer,
-// and a descriptor pointer).
-
-// Test 1
-// byref int, short, char, char, char, id, id, strong id, byref id
-// 01 35 10 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"\015\10\00"
- void (^b)() = ^{
- byref_int = sh + ch+ch1+ch2 ;
- x(bar);
- x(baz);
- x((id)strong_void_sta);
- x(byref_bab);
- };
- b();
-
-// Test 2
-// byref int, short, char, char, char, id, id, strong id, byref void*, byref id
-// 01 36 10 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"\016\10\00"
- void (^c)() = ^{
- byref_int = sh + ch+ch1+ch2 ;
- x(bar);
- x(baz);
- x((id)strong_void_sta);
- x(wid);
- bl_var1 = 0;
- x(byref_bab);
- };
-}
Modified: cfe/trunk/test/CodeGenObjC/arc-blocks.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-blocks.m?rev=167241&r1=167240&r2=167241&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-blocks.m (original)
+++ cfe/trunk/test/CodeGenObjC/arc-blocks.m Thu Nov 1 13:32:55 2012
@@ -118,8 +118,8 @@
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]]
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
- // 0x42000000 - has signature, copy/dispose helpers
- // CHECK: store i32 1107296256,
+ // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT
+ // CHECK: store i32 1115684864,
// CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
// CHECK-NEXT: store i8* [[T0]], i8**
// CHECK: call void @test4_helper(
@@ -170,8 +170,8 @@
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: store i8* [[T1]], i8** [[VAR]],
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
- // 0x40000000 - has signature but no copy/dispose
- // CHECK: store i32 1073741824, i32*
+ // 0x40800000 - has signature but no copy/dispose, as well as BLOCK_HAS_EXTENDED_LAYOUT
+ // CHECK: store i32 1082130432, i32*
// CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-NEXT: [[T0:%.*]] = load i8** [[VAR]]
// CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]]
@@ -198,8 +198,8 @@
// CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T1]])
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
- // 0x42000000 - has signature, copy/dispose helpers
- // CHECK: store i32 1107296256,
+ // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT
+ // CHECK: store i32 1115684864,
// CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
// CHECK-NEXT: store i8* [[T0]], i8**
// CHECK: call void @test6_helper(
@@ -247,8 +247,8 @@
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T1]])
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
- // 0x42000000 - has signature, copy/dispose helpers
- // CHECK: store i32 1107296256,
+ // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT
+ // CHECK: store i32 1115684864,
// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[VAR]])
// CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]])
Added: cfe/trunk/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m?rev=167241&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m Thu Nov 1 13:32:55 2012
@@ -0,0 +1,102 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -emit-llvm %s -o %t-64.s
+// rdar://12184410
+
+void x(id y) {}
+void y(int a) {}
+
+extern id opaque_id();
+
+void f() {
+ __block int byref_int = 0;
+ const id bar = (id) opaque_id();
+ id baz = 0;
+ __strong id strong_void_sta;
+ __block id byref_bab = (id)0;
+ __block id bl_var1;
+
+// Inline instruction for block variable layout: 0x0100
+// CKECK-LP64: i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), i64 256 }
+ void (^b)() = ^{
+ x(bar);
+ };
+
+// Inline instruction for block variable layout: 0x0210
+// CKECK-LP64: i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), i64 528 }
+ void (^c)() = ^{
+ x(bar);
+ x(baz);
+ byref_int = 1;
+ };
+
+// Inline instruction for block variable layout: 0x0230
+// CKECK-LP64: i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), i64 560 }
+ void (^d)() = ^{
+ x(bar);
+ x(baz);
+ byref_int = 1;
+ bl_var1 = 0;
+ byref_bab = 0;
+ };
+
+// Inline instruction for block variable layout: 0x0231
+// CKECK-LP64: i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), i64 561 }
+ __weak id wid;
+ id (^e)() = ^{
+ x(bar);
+ x(baz);
+ byref_int = 1;
+ bl_var1 = 0;
+ byref_bab = 0;
+ return wid;
+ };
+
+// Inline instruction for block variable layout: 0x0235
+// CKECK-LP64: i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), i64 565 }
+ __weak id wid1, wid2, wid3, wid4;
+ id (^f)() = ^{
+ x(bar);
+ x(baz);
+ byref_int = 1;
+ bl_var1 = 0;
+ byref_bab = 0;
+ x(wid1);
+ x(wid2);
+ x(wid3);
+ x(wid4);
+ return wid;
+ };
+
+// Inline instruction for block variable layout: 0x035
+// CKECK-LP64: i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), i64 53 }
+ id (^g)() = ^{
+ byref_int = 1;
+ bl_var1 = 0;
+ byref_bab = 0;
+ x(wid1);
+ x(wid2);
+ x(wid3);
+ x(wid4);
+ return wid;
+ };
+
+// Inline instruction for block variable layout: 0x01
+// CKECK-LP64: i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), i64 1 }
+ id (^h)() = ^{
+ return wid;
+ };
+
+// Inline instruction for block variable layout: 0x020
+// CKECK-LP64: i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), i64 32 }
+ void (^ii)() = ^{
+ byref_int = 1;
+ byref_bab = 0;
+ };
+
+// Inline instruction for block variable layout: 0x0102
+// CKECK-LP64: i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), i64 258 }
+ void (^jj)() = ^{
+ x(bar);
+ x(wid1);
+ x(wid2);
+ };
+}
Added: cfe/trunk/test/CodeGenObjC/arc-captured-block-var-layout.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-captured-block-var-layout.m?rev=167241&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-captured-block-var-layout.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-captured-block-var-layout.m Thu Nov 1 13:32:55 2012
@@ -0,0 +1,425 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -emit-llvm %s -o %t-64.s
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// rdar://12184410
+
+void x(id y) {}
+void y(int a) {}
+
+extern id opaque_id();
+
+void f() {
+ __weak id wid;
+ __block int byref_int = 0;
+ char ch = 'a';
+ char ch1 = 'b';
+ char ch2 = 'c';
+ short sh = 2;
+ const id bar = (id) opaque_id();
+ id baz = 0;
+ __strong id strong_void_sta;
+ __block id byref_bab = (id)0;
+ __block id bl_var1;
+ int i; double dob;
+
+// The patterns here are a sequence of bytes, each saying first how
+// many sizeof(void*) chunks to skip (high nibble) and then how many
+// to scan (low nibble). A zero byte says that we've reached the end
+// of the pattern.
+//
+// All of these patterns start with 01 3x because the block header on
+// LP64 consists of an isa pointer (which we're supposed to scan for
+// some reason) followed by three words (2 ints, a function pointer,
+// and a descriptor pointer).
+
+// Test 1
+// block variable layout: BL_BYREF:1, BL_STRONG:3, BL_BYREF:1, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"@2@\00"
+ void (^b)() = ^{
+ byref_int = sh + ch+ch1+ch2 ;
+ x(bar);
+ x(baz);
+ x((id)strong_void_sta);
+ x(byref_bab);
+ };
+ b();
+
+// Test 2
+// block variable layout: BL_BYREF:1, BL_STRONG:3, BL_WEAK:1, BL_BYREF:2, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"@2PA\00"
+ void (^c)() = ^{
+ byref_int = sh + ch+ch1+ch2 ;
+ x(bar);
+ x(baz);
+ x((id)strong_void_sta);
+ x(wid);
+ bl_var1 = 0;
+ x(byref_bab);
+ };
+}
+
+ at class NSString, NSNumber;
+void g() {
+ NSString *foo;
+ NSNumber *bar;
+ unsigned int bletch;
+ __weak id weak_delegate;
+ unsigned int i;
+ NSString *y;
+ NSString *z;
+// block variable layout: BL_STRONG:2, BL_WEAK:1, BL_STRONG:2, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"1P1\00"
+ void (^c)() = ^{
+ int j = i + bletch;
+ x(foo);
+ x(bar);
+ x(weak_delegate);
+ x(y);
+ x(z);
+ };
+ c();
+}
+
+// Test 5 (unions/structs and their nesting):
+void h() {
+ struct S5 {
+ int i1;
+ __unsafe_unretained id o1;
+ struct V {
+ int i2;
+ __unsafe_unretained id o2;
+ } v1;
+ int i3;
+ union UI {
+ void * i1;
+ __unsafe_unretained id o1;
+ int i3;
+ __unsafe_unretained id o3;
+ }ui;
+ };
+
+ union U {
+ void * i1;
+ __unsafe_unretained id o1;
+ int i3;
+ __unsafe_unretained id o3;
+ }ui;
+
+ struct S5 s2;
+ union U u2;
+ __block id block_id;
+
+/**
+block variable layout: BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1, BL_NON_OBJECT_WORD:1,
+ BL_UNRETAINE:1, BL_NON_OBJECT_WORD:3, BL_BYREF:1, BL_OPERATOR:0
+*/
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [7 x i8] c" ` `\22@\00"
+ void (^c)() = ^{
+ x(s2.ui.o1);
+ x(u2.o1);
+ block_id = 0;
+ };
+ c();
+}
+
+// Test for array of stuff.
+void arr1() {
+ struct S {
+ __unsafe_unretained id unsafe_unretained_var[4];
+ } imported_s;
+
+// block variable layout: BL_UNRETAINE:4, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [2 x i8] c"c\00"
+ void (^c)() = ^{
+ x(imported_s.unsafe_unretained_var[2]);
+ };
+
+ c();
+}
+
+// Test2 for array of stuff.
+void arr2() {
+ struct S {
+ int a;
+ __unsafe_unretained id unsafe_unretained_var[4];
+ } imported_s;
+
+// block variable layout: BL_NON_OBJECT_WORD:1, BL_UNRETAINE:4, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c" c\00"
+ void (^c)() = ^{
+ x(imported_s.unsafe_unretained_var[2]);
+ };
+
+ c();
+}
+
+// Test3 for array of stuff.
+void arr3() {
+ struct S {
+ int a;
+ __unsafe_unretained id unsafe_unretained_var[0];
+ } imported_s;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ void (^c)() = ^{
+ int i = imported_s.a;
+ };
+
+ c();
+}
+
+
+// Test4 for array of stuff.
+ at class B;
+void arr4() {
+ struct S {
+ struct s0 {
+ __unsafe_unretained id s_f0;
+ __unsafe_unretained id s_f1;
+ } f0;
+
+ __unsafe_unretained id f1;
+
+ struct s1 {
+ int *f0;
+ __unsafe_unretained B *f1;
+ } f4[2][2];
+ } captured_s;
+
+/**
+block variable layout: BL_UNRETAINE:3,
+ BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1,
+ BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1,
+ BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1,
+ BL_NON_OBJECT_WORD:1, BL_UNRETAINE:1,
+ BL_OPERATOR:0
+*/
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [10 x i8]
+ void (^c)() = ^{
+ id i = captured_s.f0.s_f1;
+ };
+
+ c();
+}
+
+// Test1 bitfield in cpatured aggregate.
+void bf1() {
+ struct S {
+ int flag : 25;
+ int flag1: 7;
+ int flag2 :1;
+ int flag3: 7;
+ int flag4: 24;
+ } s;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ int (^c)() = ^{
+ return s.flag;
+ };
+ c();
+}
+
+// Test2 bitfield in cpatured aggregate.
+void bf2() {
+ struct S {
+ int flag : 1;
+ } s;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ int (^c)() = ^{
+ return s.flag;
+ };
+ c();
+}
+
+// Test3 bitfield in cpatured aggregate.
+void bf3() {
+
+ struct {
+ unsigned short _reserved : 16;
+
+ unsigned char _draggedNodesAreDeletable: 1;
+ unsigned char _draggedOutsideOutlineView : 1;
+ unsigned char _adapterRespondsTo_addRootPaths : 1;
+ unsigned char _adapterRespondsTo_moveDataNodes : 1;
+ unsigned char _adapterRespondsTo_removeRootDataNode : 1;
+ unsigned char _adapterRespondsTo_doubleClickDataNode : 1;
+ unsigned char _adapterRespondsTo_selectDataNode : 1;
+ unsigned char _adapterRespondsTo_textDidEndEditing : 1;
+ unsigned char _adapterRespondsTo_updateAndSaveRoots : 1;
+ unsigned char _adapterRespondsTo_askToDeleteRootNodes : 1;
+ unsigned char _adapterRespondsTo_contextMenuForSelectedNodes : 1;
+ unsigned char _adapterRespondsTo_pasteboardFilenamesForNodes : 1;
+ unsigned char _adapterRespondsTo_writeItemsToPasteboard : 1;
+ unsigned char _adapterRespondsTo_writeItemsToPasteboardXXXX : 1;
+
+ unsigned int _filler : 32;
+ } _flags;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ unsigned char (^c)() = ^{
+ return _flags._draggedNodesAreDeletable;
+ };
+
+ c();
+}
+
+// Test4 unnamed bitfield
+void bf4() {
+
+ struct {
+ unsigned short _reserved : 16;
+
+ unsigned char _draggedNodesAreDeletable: 1;
+ unsigned char _draggedOutsideOutlineView : 1;
+ unsigned char _adapterRespondsTo_addRootPaths : 1;
+ unsigned char _adapterRespondsTo_moveDataNodes : 1;
+ unsigned char _adapterRespondsTo_removeRootDataNode : 1;
+ unsigned char _adapterRespondsTo_doubleClickDataNode : 1;
+ unsigned char _adapterRespondsTo_selectDataNode : 1;
+ unsigned char _adapterRespondsTo_textDidEndEditing : 1;
+
+ unsigned long long : 64;
+
+ unsigned char _adapterRespondsTo_updateAndSaveRoots : 1;
+ unsigned char _adapterRespondsTo_askToDeleteRootNodes : 1;
+ unsigned char _adapterRespondsTo_contextMenuForSelectedNodes : 1;
+ unsigned char _adapterRespondsTo_pasteboardFilenamesForNodes : 1;
+ unsigned char _adapterRespondsTo_writeItemsToPasteboard : 1;
+ unsigned char _adapterRespondsTo_writeItemsToPasteboardXXXX : 1;
+
+ unsigned int _filler : 32;
+ } _flags;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ unsigned char (^c)() = ^{
+ return _flags._draggedNodesAreDeletable;
+ };
+
+ c();
+}
+
+
+
+// Test5 unnamed bitfield.
+void bf5() {
+ struct {
+ unsigned char flag : 1;
+ unsigned int : 32;
+ unsigned char flag1 : 1;
+ } _flags;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ unsigned char (^c)() = ^{
+ return _flags.flag;
+ };
+
+ c();
+}
+
+
+// Test6 0 length bitfield.
+void bf6() {
+ struct {
+ unsigned char flag : 1;
+ unsigned int : 0;
+ unsigned char flag1 : 1;
+ } _flags;
+
+// block variable layout: BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+ unsigned char (^c)() = ^{
+ return _flags.flag;
+ };
+
+ c();
+}
+
+// Test7 large number of captured variables.
+void Test7() {
+ __weak id wid;
+ __weak id wid1, wid2, wid3, wid4;
+ __weak id wid5, wid6, wid7, wid8;
+ __weak id wid9, wid10, wid11, wid12;
+ __weak id wid13, wid14, wid15, wid16;
+ const id bar = (id) opaque_id();
+//block variable layout: BL_STRONG:1, BL_WEAK:16, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"0_\00"
+ void (^b)() = ^{
+ x(bar);
+ x(wid1);
+ x(wid2);
+ x(wid3);
+ x(wid4);
+ x(wid5);
+ x(wid6);
+ x(wid7);
+ x(wid8);
+ x(wid9);
+ x(wid10);
+ x(wid11);
+ x(wid12);
+ x(wid13);
+ x(wid14);
+ x(wid15);
+ x(wid16);
+ };
+}
+
+
+// Test 8 very large number of captured variables.
+void Test8() {
+__weak id wid;
+ __weak id wid1, wid2, wid3, wid4;
+ __weak id wid5, wid6, wid7, wid8;
+ __weak id wid9, wid10, wid11, wid12;
+ __weak id wid13, wid14, wid15, wid16;
+ __weak id w1, w2, w3, w4;
+ __weak id w5, w6, w7, w8;
+ __weak id w9, w10, w11, w12;
+ __weak id w13, w14, w15, w16;
+ const id bar = (id) opaque_id();
+// block variable layout: BL_STRONG:1, BL_WEAK:16, BL_WEAK:16, BL_WEAK:1, BL_OPERATOR:0
+// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8]
+ void (^b)() = ^{
+ x(bar);
+ x(wid1);
+ x(wid2);
+ x(wid3);
+ x(wid4);
+ x(wid5);
+ x(wid6);
+ x(wid7);
+ x(wid8);
+ x(wid9);
+ x(wid10);
+ x(wid11);
+ x(wid12);
+ x(wid13);
+ x(wid14);
+ x(wid15);
+ x(wid16);
+ x(w1);
+ x(w2);
+ x(w3);
+ x(w4);
+ x(w5);
+ x(w6);
+ x(w7);
+ x(w8);
+ x(w9);
+ x(w10);
+ x(w11);
+ x(w12);
+ x(w13);
+ x(w14);
+ x(w15);
+ x(w16);
+ x(wid);
+ };
+}
More information about the cfe-commits
mailing list