[cfe-commits] r51576 - /cfe/trunk/lib/CodeGen/CodeGenTypes.cpp
Eli Friedman
eli.friedman at gmail.com
Mon May 26 20:14:45 PDT 2008
Author: efriedma
Date: Mon May 26 22:14:44 2008
New Revision: 51576
URL: http://llvm.org/viewvc/llvm-project?rev=51576&view=rev
Log:
Rewrite struct/union layout. This is mostly cleanup; this might also fix
a few bugs, but I don't know of any in particular. This has good effects
besides cleanup, though: it also should make it easier to implement the
aligned and packed attributes, and also target-specific struct layouts,
because the code won't have to be duplicated in codegen.
Modified:
cfe/trunk/lib/CodeGen/CodeGenTypes.cpp
Modified: cfe/trunk/lib/CodeGen/CodeGenTypes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTypes.cpp?rev=51576&r1=51575&r2=51576&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenTypes.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenTypes.cpp Mon May 26 22:14:44 2008
@@ -27,20 +27,8 @@
/// FIXME : Handle field aligments. Handle packed structs.
class RecordOrganizer {
public:
- explicit RecordOrganizer(CodeGenTypes &Types) :
- CGT(Types), STy(NULL), llvmFieldNo(0), Cursor(0),
- llvmSize(0) {}
-
- /// addField - Add new field.
- void addField(const FieldDecl *FD);
-
- /// addLLVMField - Add llvm struct field that corresponds to llvm type Ty.
- /// Increment field count.
- void addLLVMField(const llvm::Type *Ty, bool isPaddingField = false);
-
- /// addPaddingFields - Current cursor is not suitable place to add next
- /// field. Add required padding fields.
- void addPaddingFields(unsigned WaterMark);
+ explicit RecordOrganizer(CodeGenTypes &Types, const RecordDecl& Record) :
+ CGT(Types), RD(Record), STy(NULL) {}
/// layoutStructFields - Do the actual work and lay out all fields. Create
/// corresponding llvm struct type. This should be invoked only after
@@ -50,7 +38,7 @@
/// layoutUnionFields - Do the actual work and lay out all fields. Create
/// corresponding llvm struct type. This should be invoked only after
/// all fields are added.
- void layoutUnionFields();
+ void layoutUnionFields(const ASTRecordLayout &RL);
/// getLLVMType - Return associated llvm struct type. This may be NULL
/// if fields are not laid out.
@@ -58,21 +46,14 @@
return STy;
}
- /// placeBitField - Find a place for FD, which is a bit-field.
- void placeBitField(const FieldDecl *FD);
-
llvm::SmallSet<unsigned, 8> &getPaddingFields() {
return PaddingFields;
}
private:
CodeGenTypes &CGT;
+ const RecordDecl& RD;
llvm::Type *STy;
- unsigned llvmFieldNo;
- uint64_t Cursor;
- uint64_t llvmSize;
- llvm::SmallVector<const FieldDecl *, 8> FieldDecls;
- std::vector<const llvm::Type*> LLVMFields;
llvm::SmallSet<unsigned, 8> PaddingFields;
};
}
@@ -398,9 +379,7 @@
const RecordDecl *RD = cast<const RecordDecl>(TD);
if (TD->getKind() == Decl::Struct || TD->getKind() == Decl::Class) {
// Layout fields.
- RecordOrganizer RO(*this);
- for (unsigned i = 0, e = RD->getNumMembers(); i != e; ++i)
- RO.addField(RD->getMember(i));
+ RecordOrganizer RO(*this, *RD);
RO.layoutStructFields(Context.getASTRecordLayout(RD));
@@ -413,11 +392,9 @@
// Just use the largest element of the union, breaking ties with the
// highest aligned member.
if (RD->getNumMembers() != 0) {
- RecordOrganizer RO(*this);
- for (unsigned i = 0, e = RD->getNumMembers(); i != e; ++i)
- RO.addField(RD->getMember(i));
+ RecordOrganizer RO(*this, *RD);
- RO.layoutUnionFields();
+ RO.layoutUnionFields(Context.getASTRecordLayout(RD));
// Get llvm::StructType.
CGRecordLayouts[TD] = new CGRecordLayout(RO.getLLVMType(),
@@ -482,184 +459,95 @@
return I->second;
}
-/// addField - Add new field.
-void RecordOrganizer::addField(const FieldDecl *FD) {
- assert (!STy && "Record fields are already laid out");
- FieldDecls.push_back(FD);
-}
-
/// layoutStructFields - Do the actual work and lay out all fields. Create
-/// corresponding llvm struct type. This should be invoked only after
-/// all fields are added.
-/// FIXME : At the moment assume
-/// - one to one mapping between AST FieldDecls and
-/// llvm::StructType elements.
-/// - Ignore bit fields
-/// - Ignore field aligments
-/// - Ignore packed structs
+/// corresponding llvm struct type.
+/// Note that this doesn't actually try to do struct layout; it depends on
+/// the layout built by the AST. (We have to do struct layout to do Sema,
+/// and there's no point to duplicating the work.)
void RecordOrganizer::layoutStructFields(const ASTRecordLayout &RL) {
// FIXME : Use SmallVector
- llvmSize = 0;
- llvmFieldNo = 0;
- Cursor = 0;
- LLVMFields.clear();
-
- for (llvm::SmallVector<const FieldDecl *, 8>::iterator I = FieldDecls.begin(),
- E = FieldDecls.end(); I != E; ++I) {
- const FieldDecl *FD = *I;
-
- if (FD->isBitField())
- placeBitField(FD);
- else {
- const llvm::Type *Ty = CGT.ConvertTypeRecursive(FD->getType());
- addLLVMField(Ty);
- CGT.addFieldInfo(FD, llvmFieldNo - 1);
- Cursor = llvmSize;
- }
- }
-
- unsigned StructAlign = RL.getAlignment();
- if (llvmSize % StructAlign) {
- unsigned StructPadding = StructAlign - (llvmSize % StructAlign);
- bool needStructPadding = true;
- if (!LLVMFields.empty()) {
- const llvm::Type *LastFieldType = LLVMFields.back();
- const llvm::Type *LastFieldDeclType =
- CGT.ConvertTypeRecursive(FieldDecls.back()->getType());
- if (LastFieldType != LastFieldDeclType) {
- unsigned LastFieldTypeSize =
- CGT.getTargetData().getABITypeSizeInBits(LastFieldType);
- unsigned LastFieldDeclTypeSize =
- CGT.getTargetData().getABITypeSizeInBits(LastFieldDeclType);
- if (LastFieldDeclTypeSize > LastFieldTypeSize
- && StructPadding == (LastFieldDeclTypeSize - LastFieldTypeSize)) {
- // Replace last LLVMField with a LastFieldDeclType field will
- // to avoid extra padding fields.
- LLVMFields.pop_back();
- LLVMFields.push_back(LastFieldDeclType);
- needStructPadding = false;
- }
+ uint64_t llvmSize = 0;
+ std::vector<const llvm::Type*> LLVMFields;
+ bool packedStruct = false;
+ int NumMembers = RD.getNumMembers();
+
+ for (int curField = 0; curField < NumMembers; curField++) {
+ const FieldDecl *FD = RD.getMember(curField);
+ uint64_t offset = RL.getFieldOffset(curField);
+ const llvm::Type *Ty = CGT.ConvertTypeRecursive(FD->getType());
+ uint64_t size = CGT.getTargetData().getABITypeSize(Ty) * 8;
+
+ if (FD->isBitField()) {
+ Expr *BitWidth = FD->getBitWidth();
+ llvm::APSInt FieldSize(32);
+ bool isBitField =
+ BitWidth->isIntegerConstantExpr(FieldSize, CGT.getContext());
+ assert (isBitField && "Invalid BitField size expression");
+ uint64_t BitFieldSize = FieldSize.getZExtValue();
+
+ // Bitfield field info is different from other field info;
+ // it actually ignores the underlying LLVM struct because
+ // there isn't any convenient mapping.
+ CGT.addFieldInfo(FD, offset / size);
+ CGT.addBitFieldInfo(FD, offset % size, BitFieldSize);
+ } else {
+ // Put the element into the struct. This would be simpler
+ // if we didn't bother, but it seems a bit too strange to
+ // allocate all structs as i8 arrays.
+ while (llvmSize < offset) {
+ LLVMFields.push_back(llvm::Type::Int8Ty);
+ llvmSize += 8;
}
+
+ unsigned Align = CGT.getTargetData().getABITypeAlignment(Ty) * 8;
+ if (llvmSize % Align)
+ packedStruct = true;
+
+ llvmSize += size;
+ CGT.addFieldInfo(FD, LLVMFields.size());
+ LLVMFields.push_back(Ty);
}
- if (needStructPadding)
- addPaddingFields(llvmSize + StructPadding);
}
- STy = llvm::StructType::get(LLVMFields);
-}
+ while (llvmSize < RL.getSize()) {
+ LLVMFields.push_back(llvm::Type::Int8Ty);
+ llvmSize += 8;
+ }
-/// addPaddingFields - Current cursor is not suitable place to add next field.
-/// Add required padding fields.
-void RecordOrganizer::addPaddingFields(unsigned WaterMark) {
- assert(WaterMark >= llvmSize && "Invalid padding Field");
- unsigned RequiredBits = WaterMark - llvmSize;
- unsigned RequiredBytes = (RequiredBits + 7) / 8;
- if (RequiredBytes == 1)
- // This is a bitfield that is using few bits from this byte.
- // It is not a padding field.
- addLLVMField(llvm::Type::Int8Ty, false);
- else
- for (unsigned i = 0; i != RequiredBytes; ++i)
- addLLVMField(llvm::Type::Int8Ty, true);
-}
-
-/// addLLVMField - Add llvm struct field that corresponds to llvm type Ty.
-/// Increment field count.
-void RecordOrganizer::addLLVMField(const llvm::Type *Ty, bool isPaddingField) {
-
- unsigned AlignmentInBits = CGT.getTargetData().getABITypeAlignment(Ty) * 8;
- if (llvmSize % AlignmentInBits) {
- // At the moment, insert padding fields even if target specific llvm
- // type alignment enforces implict padding fields for FD. Later on,
- // optimize llvm fields by removing implicit padding fields and
- // combining consequetive padding fields.
- unsigned Padding = AlignmentInBits - (llvmSize % AlignmentInBits);
- addPaddingFields(llvmSize + Padding);
- }
-
- unsigned TySize = CGT.getTargetData().getABITypeSizeInBits(Ty);
- llvmSize += TySize;
- if (isPaddingField)
- PaddingFields.insert(llvmFieldNo);
- LLVMFields.push_back(Ty);
- ++llvmFieldNo;
+ STy = llvm::StructType::get(LLVMFields, packedStruct);
+ assert(CGT.getTargetData().getABITypeSizeInBits(STy) == RL.getSize());
}
/// layoutUnionFields - Do the actual work and lay out all fields. Create
/// corresponding llvm struct type. This should be invoked only after
/// all fields are added.
-void RecordOrganizer::layoutUnionFields() {
-
- unsigned PrimaryEltNo = 0;
- std::pair<uint64_t, unsigned> PrimaryElt =
- CGT.getContext().getTypeInfo(FieldDecls[0]->getType());
- if (FieldDecls[0]->isBitField())
- placeBitField(FieldDecls[0]);
- else
- CGT.addFieldInfo(FieldDecls[0], 0);
+void RecordOrganizer::layoutUnionFields(const ASTRecordLayout &RL) {
+ for (int curField = 0; curField < RD.getNumMembers(); curField++) {
+ const FieldDecl *FD = RD.getMember(curField);
+ // The offset should usually be zero, but bitfields could be strange
+ uint64_t offset = RL.getFieldOffset(curField);
+
+ if (FD->isBitField()) {
+ Expr *BitWidth = FD->getBitWidth();
+ llvm::APSInt FieldSize(32);
+ bool isBitField =
+ BitWidth->isIntegerConstantExpr(FieldSize, CGT.getContext());
+ assert (isBitField && "Invalid BitField size expression");
+ uint64_t BitFieldSize = FieldSize.getZExtValue();
- unsigned Size = FieldDecls.size();
- for(unsigned i = 1; i != Size; ++i) {
- const FieldDecl *FD = FieldDecls[i];
- std::pair<uint64_t, unsigned> EltInfo =
- CGT.getContext().getTypeInfo(FD->getType());
-
- // Use largest element, breaking ties with the hightest aligned member.
- if (EltInfo.first > PrimaryElt.first ||
- (EltInfo.first == PrimaryElt.first &&
- EltInfo.second > PrimaryElt.second)) {
- PrimaryElt = EltInfo;
- PrimaryEltNo = i;
- }
-
- // In union, each field gets first slot.
- if (FD->isBitField())
- placeBitField(FD);
- else
CGT.addFieldInfo(FD, 0);
+ CGT.addBitFieldInfo(FD, offset, BitFieldSize);
+ } else {
+ CGT.addFieldInfo(FD, 0);
+ }
}
- std::vector<const llvm::Type*> Fields;
- const llvm::Type *Ty =
- CGT.ConvertTypeRecursive(FieldDecls[PrimaryEltNo]->getType());
- Fields.push_back(Ty);
- STy = llvm::StructType::get(Fields);
-}
-
-/// placeBitField - Find a place for FD, which is a bit-field.
-/// This function searches for the last aligned field. If the bit-field fits in
-/// it, it is reused. Otherwise, the bit-field is placed in a new field.
-void RecordOrganizer::placeBitField(const FieldDecl *FD) {
-
- assert (FD->isBitField() && "FD is not a bit-field");
- Expr *BitWidth = FD->getBitWidth();
- llvm::APSInt FieldSize(32);
- bool isBitField =
- BitWidth->isIntegerConstantExpr(FieldSize, CGT.getContext());
- assert (isBitField && "Invalid BitField size expression");
- uint64_t BitFieldSize = FieldSize.getZExtValue();
-
- const llvm::Type *Ty = CGT.ConvertTypeRecursive(FD->getType());
- uint64_t TySize = CGT.getTargetData().getABITypeSizeInBits(Ty);
-
- 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);
- Cursor = (Idx + 1) * TySize + BitFieldSize;
- }
- if (Cursor > llvmSize)
- addPaddingFields(Cursor);
+ // This looks stupid, but it is correct in the sense that
+ // it works no matter how complicated the sizes and alignments
+ // of the union elements are. The natural alignment
+ // of the result doesn't matter because anyone allocating
+ // structures should be aligning them appropriately anyway.
+ // FIXME: We can be a bit more intuitive in a lot of cases.
+ STy = llvm::ArrayType::get(llvm::Type::Int8Ty, RL.getSize() / 8);
+ assert(CGT.getTargetData().getABITypeSizeInBits(STy) == RL.getSize());
}
More information about the cfe-commits
mailing list