]> granicus.if.org Git - clang/commitdiff
Implenment #pack pragma and ms_struct attribute layout.
authorFariborz Jahanian <fjahanian@apple.com>
Wed, 11 May 2011 16:58:31 +0000 (16:58 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Wed, 11 May 2011 16:58:31 +0000 (16:58 +0000)
Concludes // radar://8823265.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131188 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/RecordLayoutBuilder.cpp
test/CodeGen/ms_struct-pack.c

index 5a1198478678626da15b8f972088f90b2e9cebec..3c397a2059ba28427230232b1c0481b9843d7e1a 100644 (file)
@@ -1259,6 +1259,7 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
   // the future, this will need to be tweakable by targets.
   const FieldDecl *LastFD = 0;
   ZeroLengthBitfield = 0;
+  unsigned RemainingInAlignment = 0;
   for (RecordDecl::field_iterator Field = D->field_begin(),
        FieldEnd = D->field_end(); Field != FieldEnd; ++Field) {
     if (IsMsStruct) {
@@ -1295,17 +1296,33 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
         // This check is needed for 'long long' in -m32 mode.
         if (TypeSizeLastFD > FieldAlignLastFD)
           FieldAlignLastFD = TypeSizeLastFD;
+        
         if (TypeSizeLastFD != TypeSize) {
+          if (RemainingInAlignment &&
+              LastFD && LastFD->isBitField() &&
+              LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
+            // If previous field was a bitfield with some remaining unfilled
+            // bits, pad the field so current field starts on its type boundary.
+            uint64_t FieldOffset = 
+            getDataSizeInBits() - UnfilledBitsInLastByte;
+            uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
+            setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+                                                 Context.Target.getCharAlign()));
+            setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+            RemainingInAlignment = 0;
+          }
+          
           uint64_t UnpaddedFieldOffset = 
             getDataSizeInBits() - UnfilledBitsInLastByte;
           FieldAlign = std::max(FieldAlign, FieldAlignLastFD);
+          
           // The maximum field alignment overrides the aligned attribute.
           if (!MaxFieldAlignment.isZero()) {
             unsigned MaxFieldAlignmentInBits = 
               Context.toBits(MaxFieldAlignment);
             FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
           }
-
+          
           uint64_t NewSizeInBits = 
             llvm::RoundUpToAlignment(UnpaddedFieldOffset, FieldAlign);
           setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
@@ -1313,11 +1330,40 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
           UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
           setSize(std::max(getSizeInBits(), getDataSizeInBits()));
         }
+        if (FD->isBitField()) {
+          uint64_t FieldSize = 
+            FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+          assert (FieldSize > 0 && "LayoutFields - ms_struct layout");
+          if (RemainingInAlignment < FieldSize)
+            RemainingInAlignment = TypeSize - FieldSize;
+          else
+            RemainingInAlignment -= FieldSize;
+        }
+      }
+      else if (FD->isBitField()) {
+        uint64_t FieldSize = 
+          FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
+        std::pair<uint64_t, unsigned> FieldInfo = 
+          Context.getTypeInfo(FD->getType());
+        uint64_t TypeSize = FieldInfo.first;
+        RemainingInAlignment = TypeSize - FieldSize;
       }
       LastFD = FD;
     }
     LayoutField(*Field);
   }
+  if (IsMsStruct && RemainingInAlignment &&
+      LastFD && LastFD->isBitField() &&
+      LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
+    // If we ended a bitfield before the full length of the type then
+    // pad the struct out to the full length of the last type.
+    uint64_t FieldOffset = 
+      getDataSizeInBits() - UnfilledBitsInLastByte;
+    uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
+    setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
+                                         Context.Target.getCharAlign()));
+    setSize(std::max(getSizeInBits(), getDataSizeInBits()));
+  }
 }
 
 void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
index 4aac832ed870cc812a5b0ed765401fe1f22d9f71..fe9e63aacf3dd582bd145f1714bd5ae497e73501 100644 (file)
@@ -2,6 +2,36 @@
 // rdar://8823265
 
 #pragma pack(1)
+struct _one_ms {
+        short m:9;      // size is 2
+        int q:27;       // size is 6
+        short w:13;     // size is 8
+        short e:3;      // size is 8
+        char r:4;       // size is 9
+        char t:7;       // size is 10
+        short y:16;     // size is 12
+        short u:1;      // size is 14
+        char i:2;       // size is 15
+        int a;          // size is 19
+        char o:6;       // size is 20
+        char s:2;       // size is 20
+        short d:10;     // size is 22
+        short f:4;      // size is 22
+        char b;         // size is 23
+        char g:1;       // size is 24
+        short h:13;     // size is 26
+        char j:8;       // size is 27
+        char k:5;       // size is 28
+        char c;         // size is 29
+        int l:28;       // size is 33
+        char z:7;       // size is 34
+        int x:20;       // size is 38
+} __attribute__((__ms_struct__));
+typedef struct _one_ms one_ms;
+
+static int a1[(sizeof(one_ms) == 38) - 1];
+
+#pragma pack(2)
 struct _two_ms {
         short m:9;      // size is 2
         int q:27;       // size is 6
@@ -10,25 +40,86 @@ struct _two_ms {
         char r:4;       // size is 9
         char t:7;       // size is 10
         short y:16;     // size is 12
-// clang and gcc start differing here. clang seems to follow the rules.
-        short u:1;      // size is clang: 13 gcc:14 
-        char i:2;       // size is 14
-        int a;          // size is 18
-        char o:6;       // size is 19
-        char s:2;       // size is 19
-        short d:10;     // size is 21
-        short f:4;      // size is 21
-        char b;         // size is 22
-        char g:1;       // size is 23
-        short h:13;     // size is 25
-        char j:8;       // size is 26
-        char k:5;       // size is 27
-        char c;         // size is 28
-        int l:28;       // size is 32
-        char z:7;       // size is 33
-        int x:20;       // size is clang: 36 gcc:38
-        } __attribute__((__ms_struct__));
+        short u:1;      // size is 14
+        char i:2;       // size is 15
+        int a;          // size is 19
+        char o:6;       // size is 20
+        char s:2;       // size is 20
+        short d:10;     // size is 22
+        short f:4;      // size is 22
+        char b;         // size is 23
+        char g:1;       // size is 24
+        short h:13;     // size is 26
+        char j:8;       // size is 27
+        char k:5;       // size is 28
+        char c;         // size is 29
+        int l:28;       // size is 33
+        char z:7;       // size is 34
+        int x:20;       // size is 38
+} __attribute__((__ms_struct__));
+
 typedef struct _two_ms two_ms;
 
-// gcc says size is 38, but its does not seem right!
-static int a1[(sizeof(two_ms) == 36) - 1];
+static int a2[(sizeof(two_ms) == 42) - 1];
+
+#pragma pack(4)
+struct _four_ms {
+        short m:9;      // size is 2
+        int q:27;       // size is 6
+        short w:13;     // size is 8
+        short e:3;      // size is 8
+        char r:4;       // size is 9
+        char t:7;       // size is 10
+        short y:16;     // size is 12
+        short u:1;      // size is 14
+        char i:2;       // size is 15
+        int a;          // size is 19
+        char o:6;       // size is 20
+        char s:2;       // size is 20
+        short d:10;     // size is 22
+        short f:4;      // size is 22
+        char b;         // size is 23
+        char g:1;       // size is 24
+        short h:13;     // size is 26
+        char j:8;       // size is 27
+        char k:5;       // size is 28
+        char c;         // size is 29
+        int l:28;       // size is 33
+        char z:7;       // size is 34
+        int x:20;       // size is 38
+} __attribute__((__ms_struct__));
+typedef struct _four_ms four_ms;
+
+static int a4[(sizeof(four_ms) == 48) - 1];
+
+#pragma pack(8)
+struct _eight_ms {
+        short m:9;      // size is 2
+        int q:27;       // size is 6
+        short w:13;     // size is 8
+        short e:3;      // size is 8
+        char r:4;       // size is 9
+        char t:7;       // size is 10
+        short y:16;     // size is 12
+        short u:1;      // size is 14
+        char i:2;       // size is 15
+        int a;          // size is 19
+        char o:6;       // size is 20
+        char s:2;       // size is 20
+        short d:10;     // size is 22
+        short f:4;      // size is 22
+        char b;         // size is 23
+        char g:1;       // size is 24
+        short h:13;     // size is 26
+        char j:8;       // size is 27
+        char k:5;       // size is 28
+        char c;         // size is 29
+        int l:28;       // size is 33
+        char z:7;       // size is 34
+        int x:20;       // size is 38
+} __attribute__((__ms_struct__));
+
+typedef struct _eight_ms eight_ms;
+
+static int a8[(sizeof(eight_ms) == 48) - 1];
+