From: Fariborz Jahanian Date: Wed, 11 May 2011 16:58:31 +0000 (+0000) Subject: Implenment #pack pragma and ms_struct attribute layout. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6ec50ad4b12cbb6ca12036080808f912d5ee2515;p=clang Implenment #pack pragma and ms_struct attribute layout. Concludes // radar://8823265. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131188 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 5a11984786..3c397a2059 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -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 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, diff --git a/test/CodeGen/ms_struct-pack.c b/test/CodeGen/ms_struct-pack.c index 4aac832ed8..fe9e63aacf 100644 --- a/test/CodeGen/ms_struct-pack.c +++ b/test/CodeGen/ms_struct-pack.c @@ -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]; +