[llvm-commits] [125745] Improve Packed structure support by used

dpatel at apple.com dpatel at apple.com
Thu Apr 5 09:48:14 PDT 2007


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) {





More information about the llvm-commits mailing list