[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