initial layout support for structures and unions.  This isn't actually
hooked up to anything, so it's not very useful yet.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@40006 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp
index f7ae1a0..e2447b9 100644
--- a/AST/ASTContext.cpp
+++ b/AST/ASTContext.cpp
@@ -145,6 +145,9 @@
   LongDoubleComplexTy = getComplexType(LongDoubleTy);
 }
 
+//===----------------------------------------------------------------------===//
+//                         Type Sizing and Analysis
+//===----------------------------------------------------------------------===//
 
 /// getTypeSize - Return the size of the specified type, in bits.  This method
 /// does not work on incomplete types.
@@ -197,9 +200,76 @@
     return getTypeInfo(cast<ReferenceType>(T)->getReferenceeType(), L);
   }
   
+  assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2");
   return std::make_pair(Size, Align);
 }
 
+/// getRecordLayout - Get or compute information about the layout of the
+/// specified record (struct/union/class), which indicates its size and field
+/// position information.
+const RecordLayout &ASTContext::getRecordLayout(const RecordDecl *D,
+                                                SourceLocation L) {
+  assert(D->isDefinition() && "Cannot get layout of forward declarations!");
+  
+  // Look up this layout, if already laid out, return what we have.
+  const RecordLayout *&Entry = RecordLayoutInfo[D];
+  if (Entry) return *Entry;
+  
+  // Allocate and assign into RecordLayoutInfo here.  The "Entry" reference can
+  // be invalidated (dangle) if the RecordLayoutInfo hashtable is inserted into.
+  RecordLayout *NewEntry = new RecordLayout();
+  Entry = NewEntry;
+  
+  uint64_t *FieldOffsets = new uint64_t[D->getNumMembers()];
+  uint64_t RecordSize = 0;
+  unsigned RecordAlign = 8;  // Default alignment = 1 byte = 8 bits.
+
+  if (D->getKind() != Decl::Union) {
+    // Layout each field, for now, just sequentially, respecting alignment.  In
+    // the future, this will need to be tweakable by targets.
+    for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) {
+      const FieldDecl *FD = D->getMember(i);
+      std::pair<uint64_t, unsigned> FieldInfo = getTypeInfo(FD->getType(), L);
+      uint64_t FieldSize = FieldInfo.first;
+      unsigned FieldAlign = FieldInfo.second;
+      
+      // Round up the current record size to the field's alignment boundary.
+      RecordSize = (RecordSize+FieldAlign-1) & ~(FieldAlign-1);
+      
+      // Place this field at the current location.
+      FieldOffsets[i] = RecordSize;
+      
+      // Reserve space for this field.
+      RecordSize += FieldSize;
+      
+      // Remember max struct/class alignment.
+      RecordAlign = std::max(RecordAlign, FieldAlign);
+    }
+    
+    // Finally, round the size of the total struct up to the alignment of the
+    // struct itself.
+    RecordSize = (RecordSize+RecordAlign-1) & ~(RecordAlign-1);
+  } else {
+    // Union layout just puts each member at the start of the record.
+    for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) {
+      const FieldDecl *FD = D->getMember(i);
+      std::pair<uint64_t, unsigned> FieldInfo = getTypeInfo(FD->getType(), L);
+      uint64_t FieldSize = FieldInfo.first;
+      unsigned FieldAlign = FieldInfo.second;
+      
+      // Round up the current record size to the field's alignment boundary.
+      RecordSize = std::max(RecordSize, FieldSize);
+      
+      // Place this field at the start of the record.
+      FieldOffsets[i] = 0;
+      
+      // Remember max struct/class alignment.
+      RecordAlign = std::max(RecordAlign, FieldAlign);
+    }
+  }
+}
+
+
 //===----------------------------------------------------------------------===//
 //                   Type creation/memoization methods
 //===----------------------------------------------------------------------===//