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;

llvm-svn: 44664
This commit is contained in:
Devang Patel 2007-12-06 19:16:05 +00:00
parent 5eff4de9c8
commit 65a2288eef
3 changed files with 63 additions and 21 deletions

View File

@ -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<uint64_t, unsigned> 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<const llvm::Type*> Fields;

View File

@ -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<const FieldDecl *, BitFieldInfo> 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

View File

@ -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;