[cfe-commits] r83230 - in /cfe/trunk: lib/CodeGen/CGExprConstant.cpp test/CodeGen/const-init.c

Anders Carlsson andersca at mac.com
Thu Oct 1 19:15:21 PDT 2009


Author: andersca
Date: Thu Oct  1 21:15:20 2009
New Revision: 83230

URL: http://llvm.org/viewvc/llvm-project?rev=83230&view=rev
Log:
When building constant structs, check if the resulting LLVM struct will be bigger than the record layout size and use a packed struct if that's the case. Fixes PR5108.

Modified:
    cfe/trunk/lib/CodeGen/CGExprConstant.cpp
    cfe/trunk/test/CodeGen/const-init.c

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

==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Thu Oct  1 21:15:20 2009
@@ -37,10 +37,13 @@
 
   unsigned NextFieldOffsetInBytes;
 
+  unsigned LLVMStructAlignment;
+  
   std::vector<llvm::Constant *> Elements;
 
   ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF)
-    : CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0) { }
+    : CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0),
+    LLVMStructAlignment(1) { }
 
   bool AppendField(const FieldDecl *Field, uint64_t FieldOffset,
                    const Expr *InitExpr) {
@@ -61,44 +64,11 @@
       llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment);
 
     if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) {
-      std::vector<llvm::Constant *> PackedElements;
-
       assert(!Packed && "Alignment is wrong even with a packed struct!");
 
       // Convert the struct to a packed struct.
-      uint64_t ElementOffsetInBytes = 0;
-
-      for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
-        llvm::Constant *C = Elements[i];
-
-        unsigned ElementAlign =
-          CGM.getTargetData().getABITypeAlignment(C->getType());
-        uint64_t AlignedElementOffsetInBytes =
-          llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign);
-
-        if (AlignedElementOffsetInBytes > ElementOffsetInBytes) {
-          // We need some padding.
-          uint64_t NumBytes =
-            AlignedElementOffsetInBytes - ElementOffsetInBytes;
-
-          const llvm::Type *Ty = llvm::Type::getInt8Ty(CGF->getLLVMContext());
-          if (NumBytes > 1)
-            Ty = llvm::ArrayType::get(Ty, NumBytes);
-
-          llvm::Constant *Padding = llvm::Constant::getNullValue(Ty);
-          PackedElements.push_back(Padding);
-          ElementOffsetInBytes += getSizeInBytes(Padding);
-        }
-
-        PackedElements.push_back(C);
-        ElementOffsetInBytes += getSizeInBytes(C);
-      }
-
-      assert(ElementOffsetInBytes == NextFieldOffsetInBytes &&
-             "Packing the struct changed its size!");
-
-      Elements = PackedElements;
-      Packed = true;
+      ConvertStructToPacked();
+      
       AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes;
     }
 
@@ -115,7 +85,7 @@
     // Add the field.
     Elements.push_back(C);
     NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + getSizeInBytes(C);
-
+    LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment);
     return true;
   }
 
@@ -270,6 +240,44 @@
     AppendPadding(NumPadBytes);
   }
 
+  void ConvertStructToPacked() {
+    std::vector<llvm::Constant *> PackedElements;
+    uint64_t ElementOffsetInBytes = 0;
+
+    for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
+      llvm::Constant *C = Elements[i];
+
+      unsigned ElementAlign =
+        CGM.getTargetData().getABITypeAlignment(C->getType());
+      uint64_t AlignedElementOffsetInBytes =
+        llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign);
+
+      if (AlignedElementOffsetInBytes > ElementOffsetInBytes) {
+        // We need some padding.
+        uint64_t NumBytes =
+          AlignedElementOffsetInBytes - ElementOffsetInBytes;
+
+        const llvm::Type *Ty = llvm::Type::getInt8Ty(CGF->getLLVMContext());
+        if (NumBytes > 1)
+          Ty = llvm::ArrayType::get(Ty, NumBytes);
+
+        llvm::Constant *Padding = llvm::Constant::getNullValue(Ty);
+        PackedElements.push_back(Padding);
+        ElementOffsetInBytes += getSizeInBytes(Padding);
+      }
+
+      PackedElements.push_back(C);
+      ElementOffsetInBytes += getSizeInBytes(C);
+    }
+
+    assert(ElementOffsetInBytes == NextFieldOffsetInBytes &&
+           "Packing the struct changed its size!");
+
+    Elements = PackedElements;
+    LLVMStructAlignment = 1;
+    Packed = true;
+  }
+                              
   bool Build(InitListExpr *ILE) {
     RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
     const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
@@ -306,11 +314,24 @@
       // we must have a flexible array member at the end.
       assert(RD->hasFlexibleArrayMember() &&
              "Must have flexible array member if struct is bigger than type!");
-
+      
       // No tail padding is necessary.
       return true;
     }
 
+    uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes, 
+                                                        LLVMStructAlignment);
+
+    // Check if we need to convert the struct to a packed struct.
+    if (NextFieldOffsetInBytes <= LayoutSizeInBytes && 
+        LLVMSizeInBytes > LayoutSizeInBytes) {
+      assert(!Packed && "Size mismatch!");
+      
+      ConvertStructToPacked();
+      assert(NextFieldOffsetInBytes == LayoutSizeInBytes &&
+             "Converting to packed did not help!");
+    }
+
     // Append tail padding if necessary.
     AppendTailPadding(Layout.getSize());
 

Modified: cfe/trunk/test/CodeGen/const-init.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/const-init.c?rev=83230&r1=83229&r2=83230&view=diff

==============================================================================
--- cfe/trunk/test/CodeGen/const-init.c (original)
+++ cfe/trunk/test/CodeGen/const-init.c Thu Oct  1 21:15:20 2009
@@ -1,4 +1,4 @@
-// RUN: clang-cc -triple i386-pc-linux-gnu -verify -emit-llvm -o %t %s &&
+// RUN: clang-cc -triple i386-pc-linux-gnu -verify -emit-llvm -o %t %s | FileCheck %s --input-file=%t &&
 
 #include <stdint.h>
 
@@ -47,6 +47,12 @@
 // RUN: grep '@g10 = global i32 0' %t &&
 int g10 = (2.0 + 3.0i) * (5.0 + 7.0i) != (-11.0 + 29.0i);
 
+// PR5108
+// CHECK: @ss = global %4 <{ i32 0, i8 7 }>, align 1
+struct s {
+  unsigned long a;
+  unsigned long b:3;
+} __attribute__((__packed__)) ss  = { .a = 0x0, .b = 7,  };
 
 // Global references
 // RUN: grep '@g11.l0 = internal global i32 ptrtoint (i32 ()\* @g11 to i32)' %t &&





More information about the cfe-commits mailing list