More Next objc2's gc ivar layout bitmap work.
Work in progress.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66615 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 9f3e303..45e4b12 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -308,6 +308,7 @@
   
 class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
   class GC_IVAR {
+  public:
     unsigned int ivar_bytepos;
     unsigned int ivar_size;
     GC_IVAR() : ivar_bytepos(0), ivar_size(0) {}
@@ -2461,11 +2462,15 @@
                               const std::vector<FieldDecl*>& RecFields,
                               unsigned int BytePos, bool ForStrongLayout,
                               int &Index, int &SkIndex, bool &HasUnion) {
-  bool is_union = (RD && RD->isUnion());
+  bool IsUnion = (RD && RD->isUnion());
+  uint64_t MaxUnionIvarSize = 0;
+  uint64_t MaxSkippedUnionIvarSize = 0;
+  FieldDecl *MaxField = 0;
+  FieldDecl *MaxSkippedField = 0;
   unsigned int base = 0;
   if (RecFields.empty())
     return;
-  if (is_union)
+  if (IsUnion)
     base = BytePos + GetIvarBaseOffset(Layout, RecFields[0]);
 
   for (unsigned i = 0; i < RecFields.size(); i++) {
@@ -2478,6 +2483,10 @@
       std::vector<FieldDecl*> NestedRecFields;
       if (FQT->isUnionType())
         HasUnion = true;
+      else
+        assert(FQT->isRecordType() && 
+               "only union/record is supported for ivar layout bitmap");
+
       const RecordType *RT = FQT->getAsRecordType();
       const RecordDecl *RD = RT->getDecl();
       // FIXME - Find a more efficiant way of passing records down.
@@ -2493,8 +2502,124 @@
       continue;
     }
     else if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
-        FQT = Array->getElementType();
+      const ConstantArrayType *CArray = 
+                                 dyn_cast_or_null<ConstantArrayType>(Array);
+      assert(CArray && "only array with know element size is supported");
+      FQT = CArray->getElementType();
+      assert(!FQT->isUnionType() && 
+             "layout for array of unions not supported");
+      if (FQT->isRecordType()) {
+        uint64_t ElCount = CArray->getSize().getZExtValue();
+        int OldIndex = Index;
+        int OldSkIndex = SkIndex;
+        
+        std::vector<FieldDecl*> ElementRecFields;
+        // FIXME - Use a common routine with the above!
+        const RecordType *RT = FQT->getAsRecordType();
+        const RecordDecl *RD = RT->getDecl();
+        // FIXME - Find a more efficiant way of passing records down.
+        unsigned j = 0;
+        for (RecordDecl::field_iterator i = RD->field_begin(),
+             e = RD->field_end(); i != e; ++i)
+          ElementRecFields[j++] = (*i);
+        BuildAggrIvarLayout(Layout, RD,
+                            ElementRecFields,
+                            BytePos + GetIvarBaseOffset(Layout, Field),
+                            ForStrongLayout, Index, SkIndex,
+                            HasUnion);
+        // Replicate layout information for each array element. Note that
+        // one element is already done.
+        uint64_t ElIx = 1;
+        for (int FirstIndex = Index, FirstSkIndex = SkIndex;
+             ElIx < ElCount; ElIx++) {
+          uint64_t Size = CGM.getContext().getTypeSize(RT);
+          for (int i = OldIndex+1; i <= FirstIndex; ++i)
+          {
+            IvarsInfo[++Index].ivar_bytepos = 
+              IvarsInfo[i].ivar_bytepos + Size*ElIx;
+            IvarsInfo[Index].ivar_size = IvarsInfo[i].ivar_size;
+          }
+          
+          for (int i = OldSkIndex+1; i <= FirstSkIndex; ++i)
+          {
+            SkipIvars[++SkIndex].ivar_bytepos = 
+              SkipIvars[i].ivar_bytepos + Size*ElIx;
+            SkipIvars[SkIndex].ivar_size = SkipIvars[i].ivar_size;
+          }
+        }
+        continue;
+      }
     }
+    // At this point, we are done with Record/Union and array there of.
+    // For other arrays we are down to its element type.
+    QualType::GCAttrTypes GCAttr = QualType::GCNone;
+    do {
+      if (FQT.isObjCGCStrong() || FQT.isObjCGCWeak()) {
+        GCAttr = FQT.isObjCGCStrong() ? QualType::Strong : QualType::Weak;
+        break;
+      }
+      else if (FQT->hasObjCPointerRepresentation()) {
+        GCAttr = QualType::Strong;
+        break;
+      }
+      else if (const PointerType *PT = FQT->getAsPointerType()) {
+        FQT = PT->getPointeeType();
+      }
+      else {
+        break;
+      }
+    } while (true);
+    if ((ForStrongLayout && GCAttr == QualType::Strong)
+        || (!ForStrongLayout && GCAttr == QualType::Weak)) {
+      if (IsUnion)
+      {
+        uint64_t UnionIvarSize = CGM.getContext().getTypeSize(Field->getType());
+        if (UnionIvarSize > MaxUnionIvarSize)
+        {
+          MaxUnionIvarSize = UnionIvarSize;
+          MaxField = Field;
+        }
+      }
+      else
+      {
+        IvarsInfo[++Index].ivar_bytepos = 
+          BytePos + GetIvarBaseOffset(Layout, Field);
+        IvarsInfo[Index].ivar_size = 
+          CGM.getContext().getTypeSize(Field->getType());
+      }
+    }
+    else if ((ForStrongLayout && 
+              (GCAttr == QualType::GCNone || GCAttr == QualType::Weak))
+             || (!ForStrongLayout && GCAttr != QualType::Weak)) {
+      if (IsUnion)
+      {
+        uint64_t UnionIvarSize = CGM.getContext().getTypeSize(Field->getType());
+        if (UnionIvarSize > MaxSkippedUnionIvarSize)
+        {
+          MaxSkippedUnionIvarSize = UnionIvarSize;
+          MaxSkippedField = Field;
+        }
+      }
+      else
+      {
+        SkipIvars[++SkIndex].ivar_bytepos = 
+          BytePos + GetIvarBaseOffset(Layout, Field);
+        SkipIvars[SkIndex].ivar_size = 
+          CGM.getContext().getTypeSize(Field->getType());
+      }
+    }
+  }
+  if (MaxField)
+  {
+    IvarsInfo[++Index].ivar_bytepos = 
+      BytePos + GetIvarBaseOffset(Layout, MaxField);
+    IvarsInfo[Index].ivar_size = MaxUnionIvarSize;
+  }
+  if (MaxSkippedField)
+  {
+    SkipIvars[++SkIndex].ivar_bytepos = 
+      BytePos + GetIvarBaseOffset(Layout, MaxSkippedField);
+    SkipIvars[SkIndex].ivar_size = MaxSkippedUnionIvarSize;
   }
   return;
 }