From: Devang Patel Date: Thu, 6 Dec 2007 19:16:05 +0000 (+0000) Subject: More struct bitfields layout work. Now handle, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=37884b3b3ab34bf539ba3eee44708886f2fc91cf;p=clang More struct bitfields layout work. Now handle, struct STestB1 {char a; char b:2; } stb1; struct STestB2 {char a; char b:5; char c:4} stb2; git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44664 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/CodeGen/CodeGenTypes.cpp b/CodeGen/CodeGenTypes.cpp index 9785a93845..f73c9dfeef 100644 --- a/CodeGen/CodeGenTypes.cpp +++ b/CodeGen/CodeGenTypes.cpp @@ -359,12 +359,13 @@ unsigned CodeGenTypes::getLLVMFieldNo(const FieldDecl *FD) { /// addFieldInfo - Assign field number to field FD. void CodeGenTypes::addFieldInfo(const FieldDecl *FD, unsigned No, - unsigned Begin, unsigned End) { + unsigned Begin, unsigned End, + unsigned AccessNo) { if (Begin == 0 && End == 0) FieldInfo[FD] = No; else // FD is a bit field - BitFields.insert(std::make_pair(FD, BitFieldInfo(No, Begin, End))); + BitFields.insert(std::make_pair(FD, BitFieldInfo(No, Begin, End, AccessNo))); } /// getCGRecordLayout - Return record layout info for the given llvm::Type. @@ -409,24 +410,52 @@ void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) { assert (isBitField && "Invalid BitField size expression"); uint64_t BitFieldSize = FieldSize.getZExtValue(); if (ExtraBits == 0) { - const llvm::Type *PrevTy = LLVMFields.back(); + // CurrentField is a bit-field and structure is in one of the + // following form. + // struct { char CurrentField:2; char B:4; } + // struct { char A; char CurrentField:2; }; + // struct { char A; short CurrentField:2; }; const llvm::Type *Ty = CGT.ConvertType(FD->getType()); - assert (CGT.getTargetData().getTypeSizeInBits(PrevTy) >= - CGT.getTargetData().getTypeSizeInBits(Ty) - && "FIXME Unable to handle bit field. Reuse last field"); - // Calculate extra bits available in this bitfield. ExtraBits = CGT.getTargetData().getTypeSizeInBits(Ty) - BitFieldSize; - addLLVMField(Ty, BitFieldSize, FD, 0, ExtraBits); + + if (LLVMFields.empty()) + // Ths is - struct { char CurrentField:2; char B:4; } + addLLVMField(Ty, BitFieldSize, FD, 0, ExtraBits); + else { + const llvm::Type *PrevTy = LLVMFields.back(); + if (CGT.getTargetData().getTypeSizeInBits(PrevTy) >= + CGT.getTargetData().getTypeSizeInBits(Ty)) + // This is - struct { char A; char CurrentField:2; }; + addLLVMField(Ty, BitFieldSize, FD, 0, ExtraBits); + else { + // This is - struct { char A; short CurrentField:2; }; + // Use one of the previous filed to access current field. + assert(0 + && "Incomplete support for struct { char a; short b:2;}; "); + } + } } else if (ExtraBits >= BitFieldSize) { // Reuse existing llvm field ExtraBits = ExtraBits - BitFieldSize; CGT.addFieldInfo(FD, FieldNo, Cursor - CurrentFieldStart, - ExtraBits); + ExtraBits, FieldNo); Cursor = Cursor + BitFieldSize; ++FieldNo; - } else - assert (!FD->isBitField() && "Bit fields are not yet supported"); + } else { + //ExtraBits are not enough to hold entire FD. + const llvm::Type *Ty = CGT.ConvertType(FD->getType()); + const llvm::Type *PrevTy = LLVMFields.back(); + uint64_t TySize = CGT.getTargetData().getTypeSizeInBits(Ty); + if (CGT.getTargetData().getTypeSizeInBits(PrevTy) >= TySize) { + // Previous field does not allow sharing of ExtraBits. Use new field. + // struct { char a; char b:5; char c:4; } where c is current FD. + Cursor += ExtraBits; + ExtraBits = 0; + addLLVMField(Ty, TySize, FD, 0, BitFieldSize); + } else + assert (!FD->isBitField() && "Bit fields are not yet supported"); + } } else { ExtraBits = 0; const llvm::Type *Ty = CGT.ConvertType(FD->getType()); @@ -465,7 +494,7 @@ void RecordOrganizer::addLLVMField(const llvm::Type *Ty, uint64_t Size, Cursor += Size; LLVMFields.push_back(Ty); if (FD) - CGT.addFieldInfo(FD, FieldNo, Begin, End); + CGT.addFieldInfo(FD, FieldNo, Begin, End, FieldNo); ++FieldNo; } @@ -477,7 +506,7 @@ void RecordOrganizer::layoutUnionFields() { unsigned PrimaryEltNo = 0; std::pair PrimaryElt = CGT.getContext().getTypeInfo(FieldDecls[0]->getType(), SourceLocation()); - CGT.addFieldInfo(FieldDecls[0], 0, 0, 0); + CGT.addFieldInfo(FieldDecls[0], 0, 0, 0, 0); unsigned Size = FieldDecls.size(); for(unsigned i = 1; i != Size; ++i) { @@ -495,7 +524,7 @@ void RecordOrganizer::layoutUnionFields() { } // In union, each field gets first slot. - CGT.addFieldInfo(FD, 0, 0, 0); + CGT.addFieldInfo(FD, 0, 0, 0, 0); } std::vector Fields; diff --git a/CodeGen/CodeGenTypes.h b/CodeGen/CodeGenTypes.h index 68dcd21b42..a5b540188f 100644 --- a/CodeGen/CodeGenTypes.h +++ b/CodeGen/CodeGenTypes.h @@ -78,12 +78,19 @@ class CodeGenTypes { class BitFieldInfo { public: - explicit BitFieldInfo(unsigned N, unsigned B, unsigned E) - : No(N), Begin(B), End(E) {} + explicit BitFieldInfo(unsigned N, unsigned B, unsigned E, unsigned A) + : No(N), Begin(B), End(E), AccessFieldNo(A) {} private: + // No - Field number in llvm struct. unsigned No; unsigned Begin; unsigned End; + // AccessFieldNo - llvm struct field number that is used to + // access this field. It may be not same as No. For example, + // struct S { char a; short b:2; } + // Here field 'b' is second field however it is accessed as + // 9th and 10th bitfield of first field whose type is short. + unsigned AccessFieldNo; }; llvm::DenseMap BitFields; @@ -125,7 +132,7 @@ public: /// addFieldInfo - Assign field number to field FD. void addFieldInfo(const FieldDecl *FD, unsigned No, unsigned Begin, - unsigned End); + unsigned End, unsigned AccessNo); }; } // end namespace CodeGen diff --git a/test/CodeGen/struct-x86-darwin.c b/test/CodeGen/struct-x86-darwin.c index f7c4bf5021..1e34a955fd 100644 --- a/test/CodeGen/struct-x86-darwin.c +++ b/test/CodeGen/struct-x86-darwin.c @@ -1,7 +1,9 @@ // RUN: clang %s -emit-llvm > %t1 -// RUN grep "STest1 = type { i32, \[4 x i16\], double }" %t1 -// RUN: grep "STest2 = type { i16, i16, i32, i32 }" %t1 -// RUN: grep "STest3 = type { i8, i8, i16, i32 }" %t1 +// Run grep "STest1 = type { i32, \[4 x i16\], double }" %t1 && +// RUN: grep "STest2 = type { i16, i16, i32, i32 }" %t1 && +// RUN: grep "STest3 = type { i8, i8, i16, i32 }" %t1 && +// RUN: grep "STestB1 = type { i8, i8 }" %t1 && +// RUN: grep "STestB2 = type { i8, i8, i8 }" %t1 // Test struct layout for x86-darwin target // FIXME : Enable this test for x86-darwin only. At the moment clang hard codes // x86-darwin as the target @@ -10,5 +12,9 @@ struct STest1 {int x; short y[4]; double z; } st1; struct STest2 {short a,b; int c,d; } st2; struct STest3 {char a; short b; int c; } st3; -// Bitfields struct STestB1 {int a:1; char b; int c:13 } stb1; +// Bitfields +struct STestB1 {char a; char b:2; } stb1; +struct STestB2 {char a; char b:5; char c:4} stb2; + +//struct STestB {int a:1; char b; int c:13 } stb; // Packed struct STestP1 {char a; short b; int c; } __attribute__((__packed__)) stp1;