From 4cf6f5fdc529f0b4412505e2e6af099370a479b3 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Fri, 16 Apr 2010 15:57:11 +0000 Subject: [PATCH] More work on wide bit-fields, WIP. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101467 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/RecordLayoutBuilder.cpp | 65 ++++++++++++++++++++++++++++++++ lib/AST/RecordLayoutBuilder.h | 1 + test/SemaCXX/bitfield-layout.cpp | 20 +++++++++- 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 4d0675cf17..388d47193a 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -609,6 +609,66 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { LayoutField(*Field); } +void ASTRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, + uint64_t TypeSize) { + assert(Context.getLangOptions().CPlusPlus && + "Can only have wide bit-fields in C++!"); + + // Itanium C++ ABI 2.4: + // If sizeof(T)*8 < n, let T' be the largest integral POD type with + // sizeof(T')*8 <= n. + + QualType IntegralPODTypes[] = { + Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy, + Context.UnsignedLongTy, Context.UnsignedLongLongTy + }; + + printf("field sizes %llu type size %llu\n", + FieldSize, TypeSize); + + QualType Type; + for (unsigned I = 0, E = llvm::array_lengthof(IntegralPODTypes); + I != E; ++I) { + uint64_t Size = Context.getTypeSize(IntegralPODTypes[I]); + printf("going to try %s %llu\n", IntegralPODTypes[I].getAsString().c_str(), + Size); + + if (Size > FieldSize) + break; + + Type = IntegralPODTypes[I]; + } + assert(!Type.isNull() && "Did not find a type!"); + printf("type should be %s\n", Type.getAsString().c_str()); + + unsigned TypeAlign = Context.getTypeAlign(Type); + + // We're not going to use any of the unfilled bits in the last byte. + UnfilledBitsInLastByte = 0; + + // The bitfield is allocated starting at the next offset aligned appropriately + // for T', with length n bits. + uint64_t FieldOffset = llvm::RoundUpToAlignment(DataSize, TypeAlign); + + if (IsUnion) { + DataSize = std::max(DataSize, FieldSize); + } else { + uint64_t NewSizeInBits = FieldOffset + FieldSize; + + DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8); + UnfilledBitsInLastByte = DataSize - NewSizeInBits; + } + + // Place this field at the current location. + FieldOffsets.push_back(FieldOffset); + + // Update the size. + Size = std::max(Size, DataSize); + + // Remember max struct/class alignment. + UpdateAlignment(TypeAlign); +} + void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { bool FieldPacked = Packed || D->hasAttr(); uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte); @@ -618,6 +678,11 @@ void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { uint64_t TypeSize = FieldInfo.first; unsigned FieldAlign = FieldInfo.second; + if (FieldSize > TypeSize) { + LayoutWideBitField(FieldSize, TypeSize); + return; + } + if (FieldPacked || !Context.Target.useBitFieldTypeAlignment()) FieldAlign = 1; if (const AlignedAttr *AA = D->getAttr()) diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index e0d5140170..f277c29398 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -91,6 +91,7 @@ class ASTRecordLayoutBuilder { void LayoutFields(const RecordDecl *D); void LayoutField(const FieldDecl *D); + void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize); void LayoutBitField(const FieldDecl *D); /// DeterminePrimaryBase - Determine the primary base of the given class. diff --git a/test/SemaCXX/bitfield-layout.cpp b/test/SemaCXX/bitfield-layout.cpp index 318a57f0d1..adecf55a87 100644 --- a/test/SemaCXX/bitfield-layout.cpp +++ b/test/SemaCXX/bitfield-layout.cpp @@ -3,10 +3,28 @@ #define CHECK_SIZE(name, size) extern int name##1[sizeof(name) == size ? 1 : -1]; #define CHECK_ALIGN(name, size) extern int name##2[__alignof(name) == size ? 1 : -1]; -// Simple test. +// Simple tests. struct Test1 { char c : 9; // expected-warning {{size of bit-field 'c' (9 bits) exceeds the size of its type; value will be truncated to 8 bits}} }; CHECK_SIZE(Test1, 2); CHECK_ALIGN(Test1, 1); +struct Test2 { + char c : 16; // expected-warning {{size of bit-field 'c' (16 bits) exceeds the size of its type; value will be truncated to 8 bits}} +}; +CHECK_SIZE(Test2, 2); +CHECK_ALIGN(Test2, 2); + +struct Test3 { + char c : 32; // expected-warning {{size of bit-field 'c' (32 bits) exceeds the size of its type; value will be truncated to 8 bits}} +}; +CHECK_SIZE(Test3, 4); +CHECK_ALIGN(Test3, 4); + +struct Test4 { + char c : 64; // expected-warning {{size of bit-field 'c' (64 bits) exceeds the size of its type; value will be truncated to 8 bits}} +}; +CHECK_SIZE(Test4, 8); +CHECK_ALIGN(Test4, 8); +