From 6e8df736939325bc2355eeb1e138ecf8b2605616 Mon Sep 17 00:00:00 2001 From: Devang Patel Date: Tue, 11 Dec 2007 00:49:18 +0000 Subject: [PATCH] Add support to share llvm fields for bit-fields. For example, struct { char a; short b:2; }; git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44830 91177308-0d34-0410-b5e6-96231b3b80d8 --- CodeGen/CodeGenTypes.cpp | 62 ++++++++++++++++++++++++++++++-- test/CodeGen/struct-x86-darwin.c | 8 +++-- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/CodeGen/CodeGenTypes.cpp b/CodeGen/CodeGenTypes.cpp index 0cc9516d68..02abf8ee51 100644 --- a/CodeGen/CodeGenTypes.cpp +++ b/CodeGen/CodeGenTypes.cpp @@ -65,6 +65,15 @@ namespace { return STy; } + /// fixCursorPosition - When bit-field is followed by a normal field + /// then cursor position may require some adjustments. For example, + /// struct { char a; short b:2; char c; }; + /// At the beginning of 'c' during layout, cursor position is 10. + /// However, only one llvm struct field is allocated and it is i8. + /// This happens because 'b' shares llvm field with 'a'. + /// Similar adjustment may be required if bit-field is last field. + void fixCursorPosition(const ASTRecordLayout &RL); + private: CodeGenTypes &CGT; llvm::Type *STy; @@ -80,6 +89,7 @@ namespace { uint64_t CurrentFieldStart; llvm::SmallVector FieldDecls; std::vector LLVMFields; + llvm::SmallVector Offsets; }; } @@ -431,8 +441,23 @@ void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) { 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;}; "); + bool FoundPrevField = false; + unsigned TotalOffsets = Offsets.size(); + uint64_t TySize = CGT.getTargetData().getABITypeSizeInBits(Ty); + for (unsigned i = TotalOffsets; i != 0; --i) { + uint64_t O = Offsets[i - 1]; + if (O % TySize == 0) { + // This is appropriate llvm field to share access. + FoundPrevField = true; + CurrentFieldStart = O % TySize; + unsigned FieldBegin = Cursor - (O % TySize); + unsigned FieldEnd = TySize - (FieldBegin + BitFieldSize); + Cursor += BitFieldSize; + CGT.addFieldInfo(FD, FieldNo, FieldBegin, FieldEnd, i); + } + } + assert(FoundPrevField && + "Unable to find a place for bitfield in struct layout"); } } } else if (ExtraBits >= BitFieldSize) { @@ -458,10 +483,20 @@ void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) { } } else { ExtraBits = 0; + // FD is not a bitfield. If prev field was a bit field then it may have + // positioned cursor such that it needs adjustment now. + if (Cursor % 8 != 0) + fixCursorPosition(RL); + const llvm::Type *Ty = CGT.ConvertType(FD->getType()); addLLVMField(Ty, CGT.getTargetData().getABITypeSizeInBits(Ty), FD, 0, 0); } } + + // At the end of structure, cursor should point to end of the strucutre. + // This may not happen automatically if last field is a bit-field. + fixCursorPosition(RL); + STy = llvm::StructType::get(LLVMFields); } @@ -490,6 +525,7 @@ void RecordOrganizer::addLLVMField(const llvm::Type *Ty, uint64_t Size, // combining consequetive padding fields. addPaddingFields(Cursor % AlignmentInBits); + Offsets.push_back(Cursor); CurrentFieldStart = Cursor; Cursor += Size; LLVMFields.push_back(Ty); @@ -533,3 +569,25 @@ void RecordOrganizer::layoutUnionFields() { STy = llvm::StructType::get(Fields); } +/// fixCursorPosition - When bit-field is followed by a normal field +/// then cursor position may require some adjustments. For example, +/// struct { char a; short b:2; char c; }; +/// At the beginning of 'c' during layout, cursor position is 10. +/// However, only one llvm struct field is allocated so far is i8. +/// This happens because 'b' shares llvm field with 'a'. +/// Similar adjustment may be required if last record field is a bit-field. +void RecordOrganizer::fixCursorPosition(const ASTRecordLayout &RL) { + uint64_t llvmSize = 0; + for(std::vector::iterator LI = LLVMFields.begin(), + LE = LLVMFields.end(); LI != LE; ++LI) { + const llvm::Type *Ty = *LI; + llvmSize += CGT.getTargetData().getABITypeSizeInBits(Ty); + } + Cursor = llvmSize; + unsigned llvmSizeBytes = llvmSize/8; + unsigned StructAlign = RL.getAlignment() / 8; + if (llvmSizeBytes % StructAlign) { + unsigned StructPadding = StructAlign - (llvmSizeBytes % StructAlign); + addPaddingFields(StructPadding*8); + } +} diff --git a/test/CodeGen/struct-x86-darwin.c b/test/CodeGen/struct-x86-darwin.c index 1e34a955fd..2fc959a6e0 100644 --- a/test/CodeGen/struct-x86-darwin.c +++ b/test/CodeGen/struct-x86-darwin.c @@ -3,7 +3,9 @@ // 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 +// RUN: grep "STestB2 = type { i8, i8, i8 }" %t1 && +// RUN: grep "STestB3 = type { i8, i8 }" %t1 && +// RUN: grep "STestB4 = type { i8, 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 @@ -14,7 +16,9 @@ struct STest3 {char a; short b; int c; } st3; // Bitfields struct STestB1 {char a; char b:2; } stb1; -struct STestB2 {char a; char b:5; char c:4} stb2; +struct STestB2 {char a; char b:5; char c:4; } stb2; +struct STestB3 {char a; char b:2; } stb3; +struct STestB4 {char a; short b:2; char c; } stb4; //struct STestB {int a:1; char b; int c:13 } stb; // Packed struct STestP1 {char a; short b; int c; } __attribute__((__packed__)) stp1; -- 2.40.0