Simplify bitfield codegen.

Fix codegen of struct { short a[3]; int b:15; }.

llvm-svn: 46859
This commit is contained in:
Lauro Ramos Venancio 2008-02-07 19:29:53 +00:00
parent 16d4bc3dc0
commit 9eff02d9f8
3 changed files with 48 additions and 52 deletions

View File

@ -454,7 +454,7 @@ EmitOCUVectorElementExpr(const OCUVectorElementExpr *E) {
}
LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
llvm::Value *V;
bool isUnion = false;
Expr *BaseExpr = E->getBase();
llvm::Value *BaseValue = NULL;
@ -476,14 +476,27 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
}
FieldDecl *Field = E->getMemberDecl();
unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
llvm::Value *Idxs[2] = { llvm::Constant::getNullValue(llvm::Type::Int32Ty),
llvm::ConstantInt::get(llvm::Type::Int32Ty, idx) };
llvm::Value *V = Builder.CreateGEP(BaseValue,Idxs, Idxs + 2, "tmp");
if (Field->isBitField()) {
const llvm::Type * FieldTy = ConvertType(Field->getType());
const llvm::PointerType * BaseTy =
cast<llvm::PointerType>(BaseValue->getType());
unsigned AS = BaseTy->getAddressSpace();
BaseValue = Builder.CreateBitCast(BaseValue,
llvm::PointerType::get(FieldTy, AS),
"tmp");
V = Builder.CreateGEP(BaseValue,
llvm::ConstantInt::get(llvm::Type::Int32Ty, idx),
"tmp");
} else {
llvm::Value *Idxs[2] = { llvm::Constant::getNullValue(llvm::Type::Int32Ty),
llvm::ConstantInt::get(llvm::Type::Int32Ty, idx) };
V = Builder.CreateGEP(BaseValue,Idxs, Idxs + 2, "tmp");
}
// Match union field type.
if (isUnion || Field->isBitField()) {
if (isUnion) {
const llvm::Type * FieldTy = ConvertType(Field->getType());
const llvm::PointerType * BaseTy =
cast<llvm::PointerType>(BaseValue->getType());

View File

@ -73,7 +73,6 @@ namespace {
uint64_t llvmSize;
llvm::SmallVector<const FieldDecl *, 8> FieldDecls;
std::vector<const llvm::Type*> LLVMFields;
llvm::SmallVector<uint64_t, 8> Offsets;
llvm::SmallSet<unsigned, 8> PaddingFields;
};
}
@ -449,7 +448,6 @@ void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) {
llvmFieldNo = 0;
Cursor = 0;
LLVMFields.clear();
Offsets.clear();
for (llvm::SmallVector<const FieldDecl *, 8>::iterator I = FieldDecls.begin(),
E = FieldDecls.end(); I != E; ++I) {
@ -499,7 +497,6 @@ void RecordOrganizer::addLLVMField(const llvm::Type *Ty, bool isPaddingField) {
}
unsigned TySize = CGT.getTargetData().getABITypeSizeInBits(Ty);
Offsets.push_back(llvmSize);
llvmSize += TySize;
if (isPaddingField)
PaddingFields.insert(llvmFieldNo);
@ -555,51 +552,26 @@ void RecordOrganizer::placeBitField(const FieldDecl *FD) {
assert (isBitField && "Invalid BitField size expression");
uint64_t BitFieldSize = FieldSize.getZExtValue();
bool FoundPrevField = false;
unsigned TotalOffsets = Offsets.size();
const llvm::Type *Ty = CGT.ConvertType(FD->getType());
uint64_t TySize = CGT.getTargetData().getABITypeSizeInBits(Ty);
if (!TotalOffsets) {
// Special case: the first field.
CGT.addFieldInfo(FD, llvmFieldNo);
unsigned Idx = Cursor / TySize;
unsigned BitsLeft = TySize - (Cursor % TySize);
if (BitsLeft >= BitFieldSize) {
// The bitfield fits in the last aligned field.
// This is : struct { char a; int CurrentField:10;};
// where 'CurrentField' shares first field with 'a'.
CGT.addFieldInfo(FD, Idx);
CGT.addBitFieldInfo(FD, TySize - BitsLeft, BitFieldSize);
Cursor += BitFieldSize;
} else {
// Place the bitfield in a new LLVM field.
// This is : struct { char a; short CurrentField:10;};
// where 'CurrentField' needs a new llvm field.
CGT.addFieldInfo(FD, Idx + 1);
CGT.addBitFieldInfo(FD, 0, BitFieldSize);
addPaddingFields(BitFieldSize);
Cursor = BitFieldSize;
return;
Cursor = (Idx + 1) * TySize + BitFieldSize;
}
// Search for the last aligned field.
for (unsigned i = TotalOffsets; i != 0; --i) {
uint64_t O = Offsets[i - 1];
if (O % TySize == 0) {
FoundPrevField = true;
if (TySize > (Cursor - O) && TySize - (Cursor - O) >= BitFieldSize) {
// The bitfield fits in the last aligned field.
// This is : struct { char a; int CurrentField:10;};
// where 'CurrentField' shares first field with 'a'.
addPaddingFields(Cursor + BitFieldSize);
CGT.addFieldInfo(FD, i - 1);
CGT.addBitFieldInfo(FD, Cursor - O, BitFieldSize);
Cursor += BitFieldSize;
} else {
// Place the bitfield in a new LLVM field.
// This is : struct { char a; short CurrentField:10;};
// where 'CurrentField' needs a new llvm field.
unsigned Padding = 0;
if (Cursor % TySize) {
Padding = TySize - (Cursor % TySize);
addPaddingFields(Cursor + Padding);
}
CGT.addFieldInfo(FD, llvmFieldNo);
CGT.addBitFieldInfo(FD, 0, BitFieldSize);
Cursor += Padding + BitFieldSize;
addPaddingFields(Cursor);
}
break;
}
}
assert(FoundPrevField &&
"Unable to find a place for bitfield in struct layout");
addPaddingFields(Cursor);
}

View File

@ -5,10 +5,12 @@
// RUN: grep "lshr i16 %tmp5, 9" %t1
// RUN: grep "and i32 %tmp, -8192" %t1
// RUN: grep "and i16 %tmp5, -32513" %t1
// RUN: grep "getelementptr (i32\* bitcast (.struct.STestB2\* @stb2 to i32\*), i32 1)" %t1
// Test bitfield access
struct STestB1 { int a:13; char b; unsigned short c:7;} stb1;
struct STestB2 { short a[3]; int b:15} stb2;
int f() {
return stb1.a + stb1.b + stb1.c;
@ -19,3 +21,12 @@ void g() {
stb1.b = 10;
stb1.c = 15;
}
int h() {
return stb2.a[1] + stb2.b;
}
void i(){
stb2.a[2] = -40;
stb2.b = 10;
}