[cfe-commits] r78490 - in /cfe/trunk/lib: AST/RecordLayoutBuilder.cpp AST/RecordLayoutBuilder.h CodeGen/CGRecordLayoutBuilder.cpp CodeGen/CGRecordLayoutBuilder.h

Anders Carlsson andersca at mac.com
Sat Aug 8 12:38:24 PDT 2009


Author: andersca
Date: Sat Aug  8 14:38:24 2009
New Revision: 78490

URL: http://llvm.org/viewvc/llvm-project?rev=78490&view=rev
Log:
Take #pragma pack into account when laying out structs. Fixes rdar://problem/7095436.

Modified:
    cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
    cfe/trunk/lib/AST/RecordLayoutBuilder.h
    cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp
    cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.h

Modified: cfe/trunk/lib/AST/RecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RecordLayoutBuilder.cpp?rev=78490&r1=78489&r2=78490&view=diff

==============================================================================
--- cfe/trunk/lib/AST/RecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/AST/RecordLayoutBuilder.cpp Sat Aug  8 14:38:24 2009
@@ -22,8 +22,8 @@
 using namespace clang;
 
 ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) 
-  : Ctx(Ctx), Size(0), Alignment(8), StructPacking(0), NextOffset(0),
-  IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8) {}
+  : Ctx(Ctx), Size(0), Alignment(8), Packed(false), MaxFieldAlignment(0), 
+  NextOffset(0), IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8) {}
 
 /// LayoutVtable - Lay out the vtable and set PrimaryBase.
 void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
@@ -198,10 +198,11 @@
 void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
   IsUnion = D->isUnion();
 
-  if (D->hasAttr<PackedAttr>())
-    StructPacking = 1;
+  Packed = D->hasAttr<PackedAttr>();
+
+  // The #pragma pack attribute specifies the maximum field alignment.
   if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>())
-    StructPacking = PPA->getAlignment();
+    MaxFieldAlignment = PPA->getAlignment();
   
   if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
     UpdateAlignment(AA->getAlignment());
@@ -242,8 +243,11 @@
     NextOffset = Size;
   }
   
-  if (D->hasAttr<PackedAttr>())
-    StructPacking = 1;
+  Packed = D->hasAttr<PackedAttr>();
+  
+  // The #pragma pack attribute specifies the maximum field alignment.
+  if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>())
+    MaxFieldAlignment = PPA->getAlignment();
   
   if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
     UpdateAlignment(AA->getAlignment());
@@ -268,15 +272,12 @@
 }
 
 void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
-  unsigned FieldPacking = StructPacking;
+  bool FieldPacked = Packed;
   uint64_t FieldOffset = IsUnion ? 0 : Size;
   uint64_t FieldSize;
   unsigned FieldAlign;
   
-  // FIXME: Should this override struct packing? Probably we want to
-  // take the minimum?
-  if (D->hasAttr<PackedAttr>())
-    FieldPacking = 1;
+  FieldPacked |= D->hasAttr<PackedAttr>();  
   
   if (const Expr *BitWidthExpr = D->getBitWidth()) {
     // TODO: Need to check this algorithm on other targets!
@@ -285,18 +286,17 @@
     
     std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
     uint64_t TypeSize = FieldInfo.first;
-    
-    // Determine the alignment of this bitfield. The packing
-    // attributes define a maximum and the alignment attribute defines
-    // a minimum.
-    // FIXME: What is the right behavior when the specified alignment
-    // is smaller than the specified packing?
+
     FieldAlign = FieldInfo.second;
-    if (FieldPacking)
-      FieldAlign = std::min(FieldAlign, FieldPacking);
+    
+    if (FieldPacked)
+      FieldAlign = 1;
     if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
       FieldAlign = std::max(FieldAlign, AA->getAlignment());
-    
+    // The maximum field alignment overrides the aligned attribute.
+    if (MaxFieldAlignment)
+      FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+
     // Check if we need to add padding to give the field the correct
     // alignment.
     if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
@@ -324,17 +324,13 @@
       FieldAlign = FieldInfo.second;
     }
     
-    // Determine the alignment of this bitfield. The packing
-    // attributes define a maximum and the alignment attribute defines
-    // a minimum. Additionally, the packing alignment must be at least
-    // a byte for non-bitfields.
-    //
-    // FIXME: What is the right behavior when the specified alignment
-    // is smaller than the specified packing?
-    if (FieldPacking)
-      FieldAlign = std::min(FieldAlign, std::max(8U, FieldPacking));
+    if (FieldPacked)
+      FieldAlign = 8;
     if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
       FieldAlign = std::max(FieldAlign, AA->getAlignment());
+    // The maximum field alignment overrides the aligned attribute.
+    if (MaxFieldAlignment)
+      FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
     
     // Round up the current record size to the field's alignment boundary.
     FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);

Modified: cfe/trunk/lib/AST/RecordLayoutBuilder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/RecordLayoutBuilder.h?rev=78490&r1=78489&r2=78490&view=diff

==============================================================================
--- cfe/trunk/lib/AST/RecordLayoutBuilder.h (original)
+++ cfe/trunk/lib/AST/RecordLayoutBuilder.h Sat Aug  8 14:38:24 2009
@@ -30,7 +30,8 @@
   unsigned Alignment;
   llvm::SmallVector<uint64_t, 16> FieldOffsets;
   
-  unsigned StructPacking;
+  bool Packed;
+  unsigned MaxFieldAlignment;
   uint64_t NextOffset;
   bool IsUnion;
   

Modified: cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp?rev=78490&r1=78489&r2=78490&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp Sat Aug  8 14:38:24 2009
@@ -27,13 +27,15 @@
 using namespace CodeGen;
 
 void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
+  Alignment = Types.getContext().getASTRecordLayout(D).getAlignment() / 8;
+
   if (D->isUnion()) {
     LayoutUnion(D);
     return;
   }
 
   Packed = D->hasAttr<PackedAttr>();
-
+  
   if (LayoutFields(D))
     return;
   
@@ -115,6 +117,21 @@
   const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType());
   unsigned TypeAlignment = getTypeAlignment(Ty);
 
+  // If the type alignment is larger then the struct alignment, we must use
+  // a packed struct.
+  if (TypeAlignment > Alignment) {
+    assert(!Packed && "Alignment is wrong even with packed struct!");
+    return false;
+  }
+  
+  if (const RecordType *RT = D->getType()->getAs<RecordType>()) {
+    const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
+    if (const PragmaPackAttr *PPA = RD->getAttr<PragmaPackAttr>()) {
+      if (PPA->getAlignment() != TypeAlignment * 8 && !Packed)
+        return false;
+    }
+  }
+
   // Round up the field offset to the alignment of the field type.
   uint64_t AlignedNextFieldOffsetInBytes = 
     llvm::RoundUpToAlignment(NextFieldOffsetInBytes, TypeAlignment);
@@ -193,6 +210,7 @@
 
 bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
   assert(!D->isUnion() && "Can't call LayoutFields on a union!");
+  assert(Alignment && "Did not set alignment!");
   
   const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D);
   

Modified: cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.h?rev=78490&r1=78489&r2=78490&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.h (original)
+++ cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.h Sat Aug  8 14:38:24 2009
@@ -36,6 +36,9 @@
   /// Packed - Whether the resulting LLVM struct will be packed or not.
   bool Packed;
 
+  /// Alignment - Contains the alignment of the RecordDecl.
+  unsigned Alignment;
+
   /// AlignmentAsLLVMStruct - Will contain the maximum alignment of all the
   /// LLVM types.
   unsigned AlignmentAsLLVMStruct;
@@ -69,7 +72,7 @@
   llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
   
   CGRecordLayoutBuilder(CodeGenTypes &Types) 
-    : Types(Types), Packed(false), AlignmentAsLLVMStruct(1)
+    : Types(Types), Packed(false), Alignment(0), AlignmentAsLLVMStruct(1)
     , BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
 
   /// Layout - Will layout a RecordDecl.





More information about the cfe-commits mailing list