Revision: 125745 Author: dpatel Date: 2007-04-05 09:48:13 -0700 (Thu, 05 Apr 2007)
Log Message: ----------- Improve Packed structure support by used Packed StructType. Original version of this patch was written by Andrew Lenharth. Later this patch was updated by Duncan Sands. I updated packed bit field support in this patch. Modified Paths: -------------- apple-local/branches/llvm/gcc/llvm-convert.cpp apple-local/branches/llvm/gcc/llvm-types.cpp Modified: apple-local/branches/llvm/gcc/llvm-convert.cpp =================================================================== --- apple-local/branches/llvm/gcc/llvm-convert.cpp 2007-04-05 14:21:17 UTC (rev 125744) +++ apple-local/branches/llvm/gcc/llvm-convert.cpp 2007-04-05 16:48:13 UTC (rev 125745) @@ -4780,6 +4780,10 @@ // the size of the field. To get the pointer close enough, add some // number of alignment units to the pointer. unsigned ByteAlignment = TD.getABITypeAlignment(FieldTy); + // It is possible that an individual field is Packed. This information is + // not reflected in FieldTy. Check DECL_PACKED here. + if (DECL_PACKED(FieldDecl)) + ByteAlignment = 1; assert(ByteAlignment*8 <= LLVMValueBitSize && "Unknown overlap case!"); unsigned NumAlignmentUnits = BitStart/(ByteAlignment*8); assert(NumAlignmentUnits && "Not adjusting pointer?"); @@ -5560,7 +5564,7 @@ if (ResultElts[i] == 0) ResultElts[i] = Constant::getNullValue(STy->getElementType(i)); - return ConstantStruct::get(ResultElts, false); + return ConstantStruct::get(ResultElts, STy->isPacked()); } Constant *TreeConstantToLLVM::ConvertUnionCONSTRUCTOR(tree exp) { Modified: apple-local/branches/llvm/gcc/llvm-types.cpp =================================================================== --- apple-local/branches/llvm/gcc/llvm-types.cpp 2007-04-05 14:21:17 UTC (rev 125744) +++ apple-local/branches/llvm/gcc/llvm-types.cpp 2007-04-05 16:48:13 UTC (rev 125745) @@ -845,10 +845,27 @@ std::vector<uint64_t> ElementSizeInBytes; const TargetData &TD; unsigned GCCStructAlignmentInBytes; + bool Packed; // True if struct is packed + bool LastFieldStartsAtNonByteBoundry; + unsigned ExtraBitsAvailable; // Non-zero if last field is bit field and it + // does not use all allocated bits - StructTypeConversionInfo(TargetMachine &TM, unsigned GCCAlign) - : TD(*TM.getTargetData()), GCCStructAlignmentInBytes(GCCAlign) {} + StructTypeConversionInfo(TargetMachine &TM, unsigned GCCAlign, bool P) + : TD(*TM.getTargetData()), GCCStructAlignmentInBytes(GCCAlign), + Packed(P), LastFieldStartsAtNonByteBoundry(false), ExtraBitsAvailable(0) {} + void lastFieldStartsAtNonByteBoundry(bool value) { + LastFieldStartsAtNonByteBoundry = value; + } + + void extraBitsAvailable (unsigned E) { + ExtraBitsAvailable = E; + } + + void markAsPacked() { + Packed = true; + } + unsigned getGCCStructAlignmentInBytes() const { return GCCStructAlignmentInBytes; } @@ -856,7 +873,7 @@ /// getTypeAlignment - Return the alignment of the specified type in bytes. /// unsigned getTypeAlignment(const Type *Ty) const { - return TD.getABITypeAlignment(Ty); + return Packed ? 1 : TD.getABITypeAlignment(Ty); } /// getTypeSize - Return the size of the specified type in bytes. @@ -868,7 +885,7 @@ /// getLLVMType - Return the LLVM type for the specified object. /// const Type *getLLVMType() const { - return StructType::get(Elements, false); + return StructType::get(Elements, Packed); } /// getSizeAsLLVMStruct - Return the size of this struct if it were converted @@ -877,25 +894,103 @@ uint64_t getSizeAsLLVMStruct() const { if (Elements.empty()) return 0; unsigned MaxAlign = 1; - for (unsigned i = 0, e = Elements.size(); i != e; ++i) - MaxAlign = std::max(MaxAlign, getTypeAlignment(Elements[i])); + if (!Packed) + for (unsigned i = 0, e = Elements.size(); i != e; ++i) + MaxAlign = std::max(MaxAlign, getTypeAlignment(Elements[i])); uint64_t Size = ElementOffsetInBytes.back()+ElementSizeInBytes.back(); return (Size+MaxAlign-1) & ~(MaxAlign-1); } - - /// RemoveLastElementIfOverlapsWith - If the last element in the struct - /// includes the specified byte, remove it. - void RemoveLastElementIfOverlapsWith(uint64_t ByteOffset) { - if (Elements.empty()) return; - assert(ElementOffsetInBytes.back() <= ByteOffset && - "Cannot go backwards in struct"); - if (ElementOffsetInBytes.back()+ElementSizeInBytes.back() > ByteOffset) { - // The last element overlapped with this one, remove it. - Elements.pop_back(); - ElementOffsetInBytes.pop_back(); - ElementSizeInBytes.pop_back(); + + // If this is a Packed struct and ExtraBitsAvailable is not zero then + // remove Extra bytes if ExtraBitsAvailable > 8. + void RemoveExtraBytes () { + + unsigned NoOfBytesToRemove = ExtraBitsAvailable/8; + + if (!Packed) + return; + + if (NoOfBytesToRemove == 0) + return; + + const Type *LastType = Elements.back(); + unsigned PadBytes = 0; + + if (LastType == Type::Int8Ty) + PadBytes = 1 - NoOfBytesToRemove; + else if (LastType == Type::Int16Ty) + PadBytes = 2 - NoOfBytesToRemove; + else if (LastType == Type::Int32Ty) + PadBytes = 4 - NoOfBytesToRemove; + else if (LastType == Type::Int64Ty) + PadBytes = 8 - NoOfBytesToRemove; + else + return; + + assert (PadBytes > 0 && "Unable to remove extra bytes"); + + // Update last element type and size, element offset is unchanged. + const Type *Pad = ArrayType::get(Type::Int8Ty, PadBytes); + Elements.pop_back(); + Elements.push_back(Pad); + + unsigned OriginalSize = ElementSizeInBytes.back(); + ElementSizeInBytes.pop_back(); + ElementSizeInBytes.push_back(OriginalSize - NoOfBytesToRemove); + } + + /// ResizeLastElementIfOverlapsWith - If the last element in the struct + /// includes the specified byte, remove it. Return true struct + /// layout is sized properly. Return false if unable to handle ByteOffset. + /// In this case caller should redo this struct as a packed structure. + bool ResizeLastElementIfOverlapsWith(uint64_t ByteOffset, tree Field, + const Type *Ty) { + const Type *SavedTy = NULL; + + if (!Elements.empty()) { + assert(ElementOffsetInBytes.back() <= ByteOffset && + "Cannot go backwards in struct"); + + SavedTy = Elements.back(); + if (ElementOffsetInBytes.back()+ElementSizeInBytes.back() > ByteOffset) { + // The last element overlapped with this one, remove it. + Elements.pop_back(); + ElementOffsetInBytes.pop_back(); + ElementSizeInBytes.pop_back(); + } } + + // Get the LLVM type for the field. If this field is a bitfield, use the + // declared type, not the shrunk-to-fit type that GCC gives us in TREE_TYPE. + unsigned ByteAlignment = getTypeAlignment(Ty); + unsigned NextByteOffset = getNewElementByteOffset(ByteAlignment); + if (NextByteOffset > ByteOffset || + ByteAlignment > getGCCStructAlignmentInBytes()) { + // LLVM disagrees as to where this field should go in the natural field + // ordering. Therefore convert to a packed struct and try again. + return false; + } + + // If alignment won't round us up to the right boundary, insert explicit + // padding. + if (NextByteOffset < ByteOffset) { + unsigned CurOffset = getNewElementByteOffset(1); + const Type *Pad = Type::Int8Ty; + if (SavedTy && LastFieldStartsAtNonByteBoundry) + // We want to reuse SavedType to access this bit field. + // e.g. struct __attribute__((packed)) { + // unsigned int A, + // unsigned short B : 6, + // C : 15; + // char D; }; + // In this example, previous field is C and D is current field. + addElement(SavedTy, CurOffset, ByteOffset - CurOffset); + else if (ByteOffset - CurOffset != 1) + Pad = ArrayType::get(Pad, ByteOffset - CurOffset); + addElement(Pad, CurOffset, ByteOffset - CurOffset); + } + return true; } /// FieldNo - Remove the specified field and all of the fields that come after @@ -924,6 +1019,8 @@ Elements.push_back(Ty); ElementOffsetInBytes.push_back(Offset); ElementSizeInBytes.push_back(Size); + lastFieldStartsAtNonByteBoundry(false); + ExtraBitsAvailable = 0; } /// getFieldEndOffsetInBytes - Return the byte offset of the byte immediately @@ -984,10 +1081,71 @@ assert(0 && "Could not find field!"); return ~0U; } + + void addNewBitField(unsigned Size, unsigned FirstUnallocatedByte); + + void convertToPacked(); void dump() const; }; +// LLVM disagrees as to where to put field natural field ordering. +// ordering. Therefore convert to a packed struct. +void StructTypeConversionInfo::convertToPacked() { + assert (!Packed && "Packing a packed struct!"); + Packed = true; + + // Fill the padding that existed from alignment restrictions + // with byte arrays to ensure the same layout when converting + // to a packed struct. + for (unsigned x = 1; x < ElementOffsetInBytes.size(); ++x) { + if (ElementOffsetInBytes[x-1] + ElementSizeInBytes[x-1] + < ElementOffsetInBytes[x]) { + uint64_t padding = ElementOffsetInBytes[x] + - ElementOffsetInBytes[x-1] - ElementSizeInBytes[x-1]; + const Type *Pad = Type::Int8Ty; + Pad = ArrayType::get(Pad, padding); + ElementOffsetInBytes.insert(ElementOffsetInBytes.begin() + x, + ElementOffsetInBytes[x-1] + ElementSizeInBytes[x-1]); + ElementSizeInBytes.insert(ElementSizeInBytes.begin() + x, padding); + Elements.insert(Elements.begin() + x, Pad); + } + } +} + +// Add new element which is a bit field. Size is not the size of bit filed, +// but size of bits required to determine type of new Field which will be +// used to access this bit field. +void StructTypeConversionInfo::addNewBitField(unsigned Size, + unsigned FirstUnallocatedByte) { + + // Figure out the LLVM type that we will use for the new field. + // Note, Size is not necessarily size of the new field. It indicates + // additional bits required after FirstunallocatedByte to cover new field. + const Type *NewFieldTy; + if (Size <= 8) + NewFieldTy = Type::Int8Ty; + else if (Size <= 16) + NewFieldTy = Type::Int16Ty; + else if (Size <= 32) + NewFieldTy = Type::Int32Ty; + else { + assert(Size <= 64 && "Bitfield too large!"); + NewFieldTy = Type::Int64Ty; + } + + // Check that the alignment of NewFieldTy won't cause a gap in the structure! + unsigned ByteAlignment = getTypeAlignment(NewFieldTy); + if (FirstUnallocatedByte & (ByteAlignment-1)) { + // Instead of inserting a nice whole field, insert a small array of ubytes. + NewFieldTy = ArrayType::get(Type::Int8Ty, (Size+7)/8); + } + + // Finally, add the new field. + addElement(NewFieldTy, FirstUnallocatedByte, getTypeSize(NewFieldTy)); + ExtraBitsAvailable = NewFieldTy->getPrimitiveSizeInBits() - Size; +} + void StructTypeConversionInfo::dump() const { std::cerr << "Info has " << Elements.size() << " fields:\n"; for (unsigned i = 0, e = Elements.size(); i != e; ++i) { @@ -1029,36 +1187,18 @@ assert((StartOffsetInBits & 7) == 0 && "Non-bit-field has non-byte offset!"); unsigned StartOffsetInBytes = StartOffsetInBits/8; + const Type *Ty = ConvertType(TREE_TYPE(Field)); + // Pop any previous elements out of the struct if they overlap with this one. // This can happen when the C++ front-end overlaps fields with tail padding in // C++ classes. - Info.RemoveLastElementIfOverlapsWith(StartOffsetInBytes); - - // Get the LLVM type for the field. If this field is a bitfield, use the - // declared type, not the shrunk-to-fit type that GCC gives us in TREE_TYPE. - const Type *Ty = ConvertType(TREE_TYPE(Field)); - unsigned ByteAlignment = Info.getTypeAlignment(Ty); - unsigned NextByteOffset = Info.getNewElementByteOffset(ByteAlignment); - if (NextByteOffset > StartOffsetInBytes || - ByteAlignment > Info.getGCCStructAlignmentInBytes()) { - // If the LLVM type is aligned more than the GCC type, we cannot use this - // LLVM type for the field. Instead, insert the field as an array of bytes, - // which we know will have the least alignment possible. - Ty = ArrayType::get(Type::Int8Ty, Info.getTypeSize(Ty)); - ByteAlignment = 1; - NextByteOffset = Info.getNewElementByteOffset(ByteAlignment); + if (!Info.ResizeLastElementIfOverlapsWith(StartOffsetInBytes, Field, Ty)) { + // LLVM disagrees as to where this field should go in the natural field + // ordering. Therefore convert to a packed struct and try again. + Info.convertToPacked(); + DecodeStructFields(Field, Info); } - - // If alignment won't round us up to the right boundary, insert explicit - // padding. - if (NextByteOffset < StartOffsetInBytes) { - unsigned CurOffset = Info.getNewElementByteOffset(1); - const Type *Pad = Type::Int8Ty; - if (StartOffsetInBytes-CurOffset != 1) - Pad = ArrayType::get(Pad, StartOffsetInBytes-CurOffset); - Info.addElement(Pad, CurOffset, StartOffsetInBytes-CurOffset); - } - + // At this point, we know that adding the element will happen at the right // offset. Add it. Info.addElement(Ty, StartOffsetInBytes, Info.getTypeSize(Ty)); @@ -1076,6 +1216,11 @@ void TypeConverter::DecodeStructBitField(tree_node *Field, StructTypeConversionInfo &Info) { unsigned FieldSizeInBits = TREE_INT_CST_LOW(DECL_SIZE(Field)); + + if (DECL_PACKED(Field)) + // Individual fields can be packed. + Info.markAsPacked(); + if (FieldSizeInBits == 0) // Ignore 'int:0', which just affects layout. return; @@ -1093,8 +1238,12 @@ assert(LastFieldBitOffset < StartOffsetInBits && "This bitfield isn't part of the last field!"); if (EndBitOffset <= LastFieldBitOffset+LastFieldBitSize && - LastFieldBitOffset+LastFieldBitSize >= StartOffsetInBits) - return; // Already contained in previous field! + LastFieldBitOffset+LastFieldBitSize >= StartOffsetInBits) { + // Already contained in previous field. Update remaining extra bits that + // are available. + Info.extraBitsAvailable(Info.getEndUnallocatedByte()*8 - EndBitOffset); + return; + } } // Otherwise, this bitfield lives (potentially) partially in the preceeding @@ -1105,47 +1254,65 @@ // Compute the number of bits that we need to add to this struct to cover // this field. - unsigned NumBitsToAdd = FieldSizeInBits; unsigned FirstUnallocatedByte = Info.getEndUnallocatedByte(); - // If there are any, subtract off bits that go in the previous field. + unsigned StartOffsetFromByteBoundry = StartOffsetInBits & 7; + if (StartOffsetInBits < FirstUnallocatedByte*8) { - NumBitsToAdd -= FirstUnallocatedByte*8-StartOffsetInBits; - } else if (StartOffsetInBits > FirstUnallocatedByte*8) { + + // This field's starting point is already allocated. + if (StartOffsetFromByteBoundry == 0) { + // This field starts at byte boundry. Need to allocate space + // for additional bytes not yet allocated. + unsigned AvailableBits = FirstUnallocatedByte * 8 - StartOffsetInBits; + unsigned NumBitsToAdd = FieldSizeInBits - AvailableBits; + Info.addNewBitField(NumBitsToAdd, FirstUnallocatedByte); + return; + } + + // Otherwise, this field's starting point is inside previously used byte. + // This happens with Packed bit fields. In this case one LLVM Field is + // used to access previous field and current field. + + unsigned prevFieldTypeSizeInBits = + Info.Elements.back()->getPrimitiveSizeInBits(); + unsigned NumBitsRequired = FieldSizeInBits + + (prevFieldTypeSizeInBits/8 - 1)*8 + StartOffsetFromByteBoundry; + + // If type used to access previous field is not large enough then + // remove previous field and insert new field that is large enough to + // hold both fields. + Info.RemoveFieldsAfter(Info.Elements.size() - 1); + for (unsigned idx = 0; idx < (prevFieldTypeSizeInBits/8); ++idx) + FirstUnallocatedByte--; + Info.addNewBitField(NumBitsRequired, FirstUnallocatedByte); + // Do this after adding Field. + Info.lastFieldStartsAtNonByteBoundry(true); + return; + } + + if (StartOffsetInBits > FirstUnallocatedByte*8) { // If there is padding between the last field and the struct, insert // explicit bytes into the field to represent it. - assert((StartOffsetInBits & 7) == 0 && - "Next field starts on a non-byte boundary!"); - unsigned PadBytes = StartOffsetInBits/8-FirstUnallocatedByte; + unsigned PadBytes = 0; + unsigned PadBits = 0; + if (StartOffsetFromByteBoundry != 0) { + // New field does not start at byte boundry. + PadBits = StartOffsetInBits - (FirstUnallocatedByte*8); + PadBytes = PadBits/8 + 1; + } + + PadBytes += StartOffsetInBits/8-FirstUnallocatedByte; const Type *Pad = Type::Int8Ty; if (PadBytes != 1) Pad = ArrayType::get(Pad, PadBytes); Info.addElement(Pad, FirstUnallocatedByte, PadBytes); FirstUnallocatedByte = StartOffsetInBits/8; + // This field will use some of the bits from this PadBytes. + FieldSizeInBits = FieldSizeInBits - (PadBytes*8 - PadBits); } - // Figure out the LLVM type that we will use for the new field. - const Type *NewFieldTy; - if (NumBitsToAdd <= 8) - NewFieldTy = Type::Int8Ty; - else if (NumBitsToAdd <= 16) - NewFieldTy = Type::Int16Ty; - else if (NumBitsToAdd <= 32) - NewFieldTy = Type::Int32Ty; - else { - assert(NumBitsToAdd <= 64 && "Bitfield too large!"); - NewFieldTy = Type::Int64Ty; - } - - // Check that the alignment of NewFieldTy won't cause a gap in the structure! - unsigned ByteAlignment = Info.getTypeAlignment(NewFieldTy); - if (FirstUnallocatedByte & (ByteAlignment-1)) { - // Instead of inserting a nice whole field, insert a small array of ubytes. - NewFieldTy = ArrayType::get(Type::Int8Ty, (NumBitsToAdd+7)/8); - } - - // Finally, add the new field. - Info.addElement(NewFieldTy, FirstUnallocatedByte, - Info.getTypeSize(NewFieldTy)); + // Now, Field starts at FirstUnallocatedByte and everything is aligned. + Info.addNewBitField(FieldSizeInBits, FirstUnallocatedByte); } @@ -1176,12 +1343,14 @@ ConvertType(BINFO_TYPE(BINFO_BASE_BINFO(binfo, i))); } - StructTypeConversionInfo Info(*TheTarget, TYPE_ALIGN_UNIT(type)); + StructTypeConversionInfo Info(*TheTarget, TYPE_ALIGN_UNIT(type), + TYPE_PACKED(type)); // Convert over all of the elements of the struct. for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field)) DecodeStructFields(Field, Info); - + + Info.RemoveExtraBytes(); // If the LLVM struct requires explicit tail padding to be the same size as // the GCC struct, insert tail padding now. This handles, e.g., "{}" in C++. if (TYPE_SIZE(type) && TREE_CODE(TYPE_SIZE(type)) == INTEGER_CST) { _______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits