[llvm-branch-commits] [llvm-gcc-branch] r69489 - /llvm-gcc-4.2/branches/Apple/Dib/gcc/llvm-convert.cpp

Bill Wendling isanbard at gmail.com
Sat Apr 18 15:52:15 PDT 2009


Author: void
Date: Sat Apr 18 17:52:15 2009
New Revision: 69489

URL: http://llvm.org/viewvc/llvm-project?rev=69489&view=rev
Log:
Merge in Chris's changes to the constructor stuff:

--- Merging (from foreign repository) r69396 into '.':
U    gcc/llvm-convert.cpp
--- Merging (from foreign repository) r69398 into '.':
G    gcc/llvm-convert.cpp
--- Merging (from foreign repository) r69400 into '.':
G    gcc/llvm-convert.cpp

Modified:
    llvm-gcc-4.2/branches/Apple/Dib/gcc/llvm-convert.cpp

Modified: llvm-gcc-4.2/branches/Apple/Dib/gcc/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/branches/Apple/Dib/gcc/llvm-convert.cpp?rev=69489&r1=69488&r2=69489&view=diff

==============================================================================
--- llvm-gcc-4.2/branches/Apple/Dib/gcc/llvm-convert.cpp (original)
+++ llvm-gcc-4.2/branches/Apple/Dib/gcc/llvm-convert.cpp Sat Apr 18 17:52:15 2009
@@ -88,18 +88,6 @@
         !isAggregateTreeType(TREE_TYPE(decl));
 }
 
-/// isStructWithVarSizeArrayAtEnd - Return true if this StructType contains a
-/// zero sized array as its last element.  This typically happens due to C
-/// constructs like:  struct X { int A; char B[]; };
-static bool isStructWithVarSizeArrayAtEnd(const Type *Ty) {
-  const StructType *STy = dyn_cast<StructType>(Ty);
-  if (STy == 0) return false;
-  assert(STy->getNumElements() && "empty struct?");
-  const Type *LastElTy = STy->getElementType(STy->getNumElements()-1);
-  return isa<ArrayType>(LastElTy) && 
-         cast<ArrayType>(LastElTy)->getNumElements() == 0;
-}
-
 /// getINTEGER_CSTVal - Return the specified INTEGER_CST value as a uint64_t.
 ///
 uint64_t getINTEGER_CSTVal(tree exp) {
@@ -6517,23 +6505,22 @@
 }
 
 Constant *TreeConstantToLLVM::ConvertVECTOR_CST(tree exp) {
-  if (TREE_VECTOR_CST_ELTS(exp)) {
-    std::vector<Constant*> Elts;
-    for (tree elt = TREE_VECTOR_CST_ELTS(exp); elt; elt = TREE_CHAIN(elt))
-      Elts.push_back(Convert(TREE_VALUE(elt)));
-    
-    // The vector should be zero filled if insufficient elements are provided.
-    if (Elts.size() < TYPE_VECTOR_SUBPARTS(TREE_TYPE(exp))) {
-      tree EltType = TREE_TYPE(TREE_TYPE(exp));
-      Constant *Zero = Constant::getNullValue(ConvertType(EltType));
-      while (Elts.size() < TYPE_VECTOR_SUBPARTS(TREE_TYPE(exp)))
-        Elts.push_back(Zero);
-    }
-    
-    return ConstantVector::get(Elts);
-  } else {
+  if (!TREE_VECTOR_CST_ELTS(exp))
     return Constant::getNullValue(ConvertType(TREE_TYPE(exp)));
+
+  std::vector<Constant*> Elts;
+  for (tree elt = TREE_VECTOR_CST_ELTS(exp); elt; elt = TREE_CHAIN(elt))
+    Elts.push_back(Convert(TREE_VALUE(elt)));
+  
+  // The vector should be zero filled if insufficient elements are provided.
+  if (Elts.size() < TYPE_VECTOR_SUBPARTS(TREE_TYPE(exp))) {
+    tree EltType = TREE_TYPE(TREE_TYPE(exp));
+    Constant *Zero = Constant::getNullValue(ConvertType(EltType));
+    while (Elts.size() < TYPE_VECTOR_SUBPARTS(TREE_TYPE(exp)))
+      Elts.push_back(Zero);
   }
+  
+  return ConstantVector::get(Elts);
 }
 
 Constant *TreeConstantToLLVM::ConvertSTRING_CST(tree exp) {
@@ -6778,334 +6765,388 @@
   return ConstantStruct::get(ResultElts, false);
 }
 
-/// InsertBitFieldValue - Process the assignment of a bitfield value into an
-/// LLVM struct value.  Val may be null if nothing has been assigned into this
-/// field, so FieldTy indicates the type of the LLVM struct type to use.
-static Constant *InsertBitFieldValue(uint64_t ValToInsert,
-                                     unsigned NumBitsToInsert,
-                                     unsigned OffsetToBitFieldStart,
-                                     unsigned FieldBitSize,
-                                     Constant *Val, const Type *FieldTy) {
-  if (FieldTy->isInteger()) {
-    uint64_t ExistingVal;
-    if (Val == 0)
-      ExistingVal = 0;
-    else {
-      assert(isa<ConstantInt>(Val) && "Bitfield shared with non-bit-field?");
-      ExistingVal = cast<ConstantInt>(Val)->getZExtValue();
+
+namespace {
+/// ConstantLayoutInfo - A helper class used by ConvertRecordCONSTRUCTOR to
+/// lay out struct inits.
+struct ConstantLayoutInfo {
+  const TargetData &TD;
+  
+  /// ResultElts - The initializer elements so far.
+  std::vector<Constant*> ResultElts;
+  
+  /// StructIsPacked - This is set to true if we find out that we have to emit
+  /// the ConstantStruct as a Packed LLVM struct type (because the LLVM
+  /// alignment rules would prevent laying out the struct correctly).
+  bool StructIsPacked;
+  
+  /// NextFieldByteStart - This field indicates the *byte* that the next field
+  /// will start at.  Put another way, this is the size of the struct as
+  /// currently laid out, but without any tail padding considered.
+  uint64_t NextFieldByteStart;
+
+  /// MaxLLVMFieldAlignment - This is the largest alignment of any IR field,
+  /// which is the alignment that the ConstantStruct will get.
+  unsigned MaxLLVMFieldAlignment;
+  
+  
+  ConstantLayoutInfo(const TargetData &TD) : TD(TD) {
+    StructIsPacked = false;
+    NextFieldByteStart = 0;
+    MaxLLVMFieldAlignment = 1;
+  }
+  
+  void ConvertToPacked();
+  void AddFieldToRecordConstant(Constant *Val, uint64_t GCCFieldOffsetInBits);
+  void AddBitFieldToRecordConstant(ConstantInt *Val,
+                                   uint64_t GCCFieldOffsetInBits);
+  void HandleTailPadding(uint64_t GCCStructBitSize);
+};
+  
+}
+
+/// ConvertToPacked - Given a partially constructed initializer for a LLVM
+/// struct constant, change it to make all the implicit padding between elements
+/// be fully explicit.
+void ConstantLayoutInfo::ConvertToPacked() {
+  uint64_t EltOffs = 0;
+  for (unsigned i = 0, e = ResultElts.size(); i != e; ++i) {
+    Constant *Val = ResultElts[i];
+    
+    // Check to see if this element has an alignment that would cause it to get
+    // offset.  If so, insert explicit padding for the offset.
+    unsigned ValAlign = TD.getABITypeAlignment(Val->getType());
+    uint64_t AlignedEltOffs = TargetData::RoundUpAlignment(EltOffs, ValAlign);
+    
+    // If the alignment doesn't affect the element offset, then the value is ok.
+    // Accept the field and keep moving.
+    if (AlignedEltOffs == EltOffs) {
+      EltOffs += TD.getTypePaddedSize(Val->getType());
+      continue;
     }
     
-    // Compute the value to insert, and the mask to use.
-    uint64_t FieldMask;
-    if (BYTES_BIG_ENDIAN) {
-      FieldMask = ~0ULL >> (64-NumBitsToInsert);
-      FieldMask   <<= FieldBitSize-(OffsetToBitFieldStart+NumBitsToInsert);
-      ValToInsert <<= FieldBitSize-(OffsetToBitFieldStart+NumBitsToInsert);
+    // Otherwise, there is padding here.  Insert explicit zeros.
+    const Type *PadTy = Type::Int8Ty;
+    if (AlignedEltOffs-EltOffs != 1)
+      PadTy = ArrayType::get(PadTy, AlignedEltOffs-EltOffs);
+    ResultElts.insert(ResultElts.begin()+i, Constant::getNullValue(PadTy));
+    ++e;  // One extra element to scan.
+  }
+  
+  // Packed now!
+  MaxLLVMFieldAlignment = 1;
+  StructIsPacked = true;
+}
+
+
+/// AddFieldToRecordConstant - As ConvertRecordCONSTRUCTOR builds up an LLVM
+/// constant to represent a GCC CONSTRUCTOR node, it calls this method to add
+/// fields.  The design of this is that it adds leading/trailing padding as
+/// needed to make the piece fit together and honor the GCC layout.  This does
+/// not handle bitfields.
+///
+/// The arguments are:
+///   Val: The value to add to the struct, with a size that matches the size of
+///        the corresponding GCC field.
+///   GCCFieldOffsetInBits: The offset that we have to put Val in the result. 
+///
+void ConstantLayoutInfo::
+AddFieldToRecordConstant(Constant *Val, uint64_t GCCFieldOffsetInBits) {
+  assert((TD.getTypeSizeInBits(Val->getType()) & 7) == 0 &&
+         "Cannot handle non-byte sized values");
+  
+  // Figure out how to add this non-bitfield value to our constant struct so
+  // that it ends up at the right offset.  There are four cases we have to
+  // think about:
+  //   1. We may be able to just slap it onto the end of our struct and have
+  //      everything be ok.
+  //   2. We may have to insert explicit padding into the LLVM struct to get
+  //      the initializer over into the right space.  This is needed when the
+  //      GCC field has a larger alignment than the LLVM field.
+  //   3. The LLVM field may be too far over and we may be forced to convert
+  //      this to an LLVM packed struct.  This is required when the LLVM
+  //      alignment is larger than the GCC alignment.
+  //   4. We may have a bitfield that needs to be merged into a previous
+  //      field.
+  // Start by determining which case we have by looking at where LLVM and GCC
+  // would place the field.
+  
+  // Verified that we haven't already laid out bytes that will overlap with
+  // this new field.
+  assert(NextFieldByteStart*8 <= GCCFieldOffsetInBits &&
+         "Overlapping LLVM fields!");
+  
+  // Compute the offset the field would get if we just stuck 'Val' onto the
+  // end of our structure right now.  It is NextFieldByteStart rounded up to
+  // the LLVM alignment of Val's type.
+  unsigned ValLLVMAlign = 1;
+  
+  if (!StructIsPacked) { // Packed structs ignore the alignment of members.
+    ValLLVMAlign = TD.getABITypeAlignment(Val->getType());
+    MaxLLVMFieldAlignment = std::max(MaxLLVMFieldAlignment, ValLLVMAlign);
+  }
+  
+  // LLVMNaturalByteOffset - This is where LLVM would drop the field if we
+  // slap it onto the end of the struct.
+  uint64_t LLVMNaturalByteOffset
+    = TargetData::RoundUpAlignment(NextFieldByteStart, ValLLVMAlign);
+  
+  // If adding the LLVM field would push it over too far, then we must have a
+  // case that requires the LLVM struct to be packed.  Do it now if so.
+  if (LLVMNaturalByteOffset*8 > GCCFieldOffsetInBits) {
+    // Switch to packed.
+    ConvertToPacked();
+    LLVMNaturalByteOffset = NextFieldByteStart;
+    assert(LLVMNaturalByteOffset*8 <= GCCFieldOffsetInBits &&
+           "Packing didn't fix the problem!");
+  }
+  
+  // If the LLVM offset is not large enough, we need to insert explicit
+  // padding in the LLVM struct between the fields.
+  if (LLVMNaturalByteOffset*8 < GCCFieldOffsetInBits) {
+    // Insert enough padding to fully fill in the hole.  Insert padding from
+    // NextFieldByteStart (not LLVMNaturalByteOffset) because the padding will
+    // not get the same alignment as "Val".
+    const Type *FillTy = Type::Int8Ty;
+    if (GCCFieldOffsetInBits/8-NextFieldByteStart != 1)
+      FillTy = ArrayType::get(FillTy,
+                              GCCFieldOffsetInBits/8-NextFieldByteStart);
+    ResultElts.push_back(Constant::getNullValue(FillTy));
+    
+    NextFieldByteStart = GCCFieldOffsetInBits/8;
+    LLVMNaturalByteOffset
+      = TargetData::RoundUpAlignment(NextFieldByteStart, ValLLVMAlign);
+  }
+  
+  // Slap 'Val' onto the end of our ConstantStruct, it must be known to land
+  // at the right offset now.
+  assert(LLVMNaturalByteOffset*8 == GCCFieldOffsetInBits);
+  ResultElts.push_back(Val);
+  NextFieldByteStart = LLVMNaturalByteOffset;
+  NextFieldByteStart += TD.getTypePaddedSize(Val->getType());
+}
+
+/// AddBitFieldToRecordConstant - Bitfields can span multiple LLVM fields and
+/// have other annoying properties, thus requiring extra layout rules.  This
+/// routine handles the extra complexity and then forwards to
+/// AddFieldToRecordConstant.
+void ConstantLayoutInfo::
+AddBitFieldToRecordConstant(ConstantInt *ValC, uint64_t GCCFieldOffsetInBits) {
+  // If the field is a bitfield, it could partially go in a previously
+  // laid out structure member, and may add elements to the end of the currently
+  // laid out structure.
+  //
+  // Since bitfields can only partially overlap other bitfields, because we
+  // always emit components of bitfields as i8, and because we never emit tail
+  // padding until we know it exists, this boils down to merging pieces of the
+  // bitfield values into i8's.  This is also simplified by the fact that
+  // bitfields can only be initialized by ConstantInts.  An interesting case is
+  // sharing of tail padding in C++ structures.  Because this can only happen
+  // in inheritance cases, and those are non-POD, we should never see them here.
+  
+  // First handle any part of Val that overlaps an already laid out field by
+  // merging it into it.  By the above invariants, we know that it is an i8 that
+  // we are merging into.  Note that we may be inserting *all* of Val into the
+  // previous field.
+  if (GCCFieldOffsetInBits < NextFieldByteStart*8) {
+    unsigned ValBitSize = ValC->getBitWidth();
+    assert(!ResultElts.empty() && "Bitfield starts before first element?");
+    assert(ResultElts.back()->getType() == Type::Int8Ty &&
+           isa<ConstantInt>(ResultElts.back()) &&
+           "Merging bitfield with non-bitfield value?");
+    assert(NextFieldByteStart*8 - GCCFieldOffsetInBits < 8 &&
+           "Bitfield overlaps backwards more than one field?");
+
+    // Figure out how many bits can fit into the previous field given the
+    // starting point in that field.
+    unsigned BitsInPreviousField =
+      unsigned(NextFieldByteStart*8 - GCCFieldOffsetInBits);
+    assert(BitsInPreviousField != 0 && "Previous field should not be null!");
+    
+    // Split the bits that will be inserted into the previous element out of
+    // Val into a new constant.  If Val is completely contained in the previous
+    // element, this sets Val to null, otherwise we shrink Val to contain the
+    // bits to insert in the next element.
+    APInt ValForPrevField(ValC->getValue());
+    if (BitsInPreviousField >= ValBitSize) {
+      // The whole field fits into the previous field.
+      ValC = 0;
+    } else if (!BYTES_BIG_ENDIAN) {
+      // Little endian, take bits from the bottom of the field value.
+      ValForPrevField.trunc(BitsInPreviousField);
+      APInt Tmp = ValC->getValue();
+      Tmp = Tmp.lshr(BitsInPreviousField);
+      Tmp = Tmp.trunc(ValBitSize-BitsInPreviousField);
+      ValC = ConstantInt::get(Tmp);
     } else {
-      FieldMask = ~0ULL >> (64-NumBitsToInsert);
-      FieldMask   <<= OffsetToBitFieldStart;
-      ValToInsert <<= OffsetToBitFieldStart;
+      // Big endian, take bits from the top of the field value.
+      ValForPrevField = ValForPrevField.lshr(ValBitSize-BitsInPreviousField);
+      ValForPrevField.trunc(BitsInPreviousField);
+      
+      APInt Tmp = ValC->getValue();
+      Tmp = Tmp.trunc(ValBitSize-BitsInPreviousField);
+      ValC = ConstantInt::get(Tmp);
     }
-
-    // Insert the new value into the field and return it.
-    uint64_t NewVal = (ExistingVal & ~FieldMask) | ValToInsert;
-    return TheFolder->CreateTruncOrBitCast(ConstantInt::get(Type::Int64Ty,
-                                                            NewVal), FieldTy);
-  } else {
-    // Otherwise, this is initializing part of an array of bytes.  Recursively
-    // insert each byte.
-    assert(isa<ArrayType>(FieldTy) && 
-           cast<ArrayType>(FieldTy)->getElementType() == Type::Int8Ty &&
-           "Not an array of bytes?");
-    // Expand the already parsed initializer into its elements if it is a 
-    // ConstantArray or ConstantAggregateZero.
-    std::vector<Constant*> Elts;
-    Elts.resize(cast<ArrayType>(FieldTy)->getNumElements());
-    
-    if (Val) {
-      if (ConstantArray *CA = dyn_cast<ConstantArray>(Val)) {
-        for (unsigned i = 0, e = Elts.size(); i != e; ++i)
-          Elts[i] = CA->getOperand(i);
-      } else {
-        assert(isa<ConstantAggregateZero>(Val) && "Unexpected initializer!");
-        Constant *Elt = Constant::getNullValue(Type::Int8Ty);
-        for (unsigned i = 0, e = Elts.size(); i != e; ++i)
-          Elts[i] = Elt;
-      }
+    
+    // Okay, we're going to insert ValForPrevField into the previous i8, extend
+    // it and shift into place.
+    ValForPrevField.zext(8);
+    if (!BYTES_BIG_ENDIAN) {
+      ValForPrevField = ValForPrevField.shl(8-BitsInPreviousField);
+    } else {
+      // On big endian, if the entire field fits into the remaining space, shift
+      // over to not take part of the next field's bits.
+      if (BitsInPreviousField > ValBitSize)
+        ValForPrevField = ValForPrevField.shl(BitsInPreviousField-ValBitSize);
     }
     
-    // Loop over all of our elements, inserting pieces into each one as
-    // appropriate.
-    unsigned i = OffsetToBitFieldStart/8;  // Skip to first byte
-    OffsetToBitFieldStart &= 7;
+    // "or" in the previous value and install it.
+    const APInt &LastElt = cast<ConstantInt>(ResultElts.back())->getValue();
+    ResultElts.back() = ConstantInt::get(ValForPrevField | LastElt);
     
-    for (; NumBitsToInsert; ++i) {
-      assert(i < Elts.size() && "Inserting out of range!");
-      
-      unsigned NumEltBitsToInsert = std::min(8-OffsetToBitFieldStart,
-                                             NumBitsToInsert);
-      
-      uint64_t EltValToInsert;
-      if (BYTES_BIG_ENDIAN) {
-        // If this is a big-endian bit-field, take the top NumBitsToInsert
-        // bits from the bitfield value.
-        EltValToInsert = ValToInsert >> (NumBitsToInsert-NumEltBitsToInsert);
+    // If the whole bit-field fit into the previous field, we're done.
+    if (ValC == 0) return;
+    GCCFieldOffsetInBits = NextFieldByteStart*8;
+  }
+  
+  assert(GCCFieldOffsetInBits == NextFieldByteStart*8 && 
+         "expected no missing bitfields");
+
+  APInt Val = ValC->getValue();
+
+  // Okay, we know that we're plopping bytes onto the end of the struct.
+  // Iterate while there is stuff to do.
+  while (1) {
+    ConstantInt *ValToAppend;
+    if (Val.getBitWidth() > 8) {
+      if (!BYTES_BIG_ENDIAN) {
+        // Little endian lays out low bits first.
+        APInt Tmp = Val;
+        Tmp.trunc(8);
+        ValToAppend = ConstantInt::get(Tmp);
         
-        // Clear the handled bits from BitfieldVal.
-        ValToInsert &= (1ULL << (NumBitsToInsert-NumEltBitsToInsert))-1;
+        Val = Val.lshr(8);
       } else {
-        // If this is little-endian bit-field, take the bottom NumBitsToInsert
-        // bits from the bitfield value.
-        EltValToInsert = ValToInsert & ((1ULL << NumEltBitsToInsert)-1);
-        ValToInsert >>= NumEltBitsToInsert;
+        // Big endian lays out high bits first.
+        APInt Tmp = Val;
+        Tmp = Tmp.lshr(Tmp.getBitWidth()-8);
+        Tmp.trunc(8);
+        ValToAppend = ConstantInt::get(Tmp);
       }
-
-      Elts[i] = InsertBitFieldValue(EltValToInsert, NumEltBitsToInsert,
-                                    OffsetToBitFieldStart, 8, Elts[i], 
-                                    Type::Int8Ty);
-      
-      // Advance for next element.
-      OffsetToBitFieldStart = 0;
-      NumBitsToInsert -= NumEltBitsToInsert;
-    }
-
-    // Pad extra array elements. This may happens when one llvm field
-    // is used to access two struct fields and llvm field is represented
-    // as an array of bytes.
-    for (; i < Elts.size(); ++i)
-      Elts[i] = ConstantInt::get((cast<ArrayType>(FieldTy))->getElementType(),
-                                 0);
-
-    return ConstantArray::get(cast<ArrayType>(FieldTy), Elts);
-  }
-}
-
-
-/// ProcessBitFieldInitialization - Handle a static initialization of a 
-/// RECORD_TYPE field that is a bitfield.
-static void ProcessBitFieldInitialization(tree Field, Value *Val,
-                                          const StructType *STy,
-                                          std::vector<Constant*> &ResultElts) {
-  // Get the offset and size of the bitfield, in bits.
-  unsigned BitfieldBitOffset = getFieldOffsetInBits(Field);
-  unsigned BitfieldSize      = TREE_INT_CST_LOW(DECL_SIZE(Field));
-  
-  // Get the value to insert into the bitfield.
-  assert(Val->getType()->isInteger() && "Bitfield initializer isn't int!");
-  assert(isa<ConstantInt>(Val) && "Non-constant bitfield initializer!");
-  uint64_t BitfieldVal = cast<ConstantInt>(Val)->getZExtValue();
-  
-  // Ensure that the top bits (which don't go into the bitfield) are zero.
-  BitfieldVal &= ~0ULL >> (64-BitfieldSize);
-  
-  // Get the struct field layout info for this struct.
-  const StructLayout *STyLayout = getTargetData().getStructLayout(STy);
-  
-  // If this is a bitfield, we know that FieldNo is the *first* LLVM field
-  // that contains bits from the bitfield overlayed with the declared type of
-  // the bitfield.  This bitfield value may be spread across multiple fields, or
-  // it may be just this field, or it may just be a small part of this field.
-  unsigned int FieldNo = GetFieldIndex(Field);
-  assert(FieldNo < ResultElts.size() && "Invalid struct field number!");
-
-  // Get the offset and size of the LLVM field.
-  uint64_t STyFieldBitOffs = STyLayout->getElementOffset(FieldNo)*8;
-  
-  assert(BitfieldBitOffset >= STyFieldBitOffs &&
-         "This bitfield doesn't start in this LLVM field!");
-  unsigned OffsetToBitFieldStart = BitfieldBitOffset-STyFieldBitOffs;
-  
-  // Loop over all of the fields this bitfield is part of.  This is usually just
-  // one, but can be several in some cases.
-  for (; BitfieldSize; ++FieldNo) {
-    assert(STyFieldBitOffs == STyLayout->getElementOffset(FieldNo)*8 &&
-           "Bitfield LLVM fields are not exactly consecutive in memory!");
-    
-    // Compute overlap of this bitfield with this LLVM field, then call a
-    // function to insert (the STy element may be an array of bytes or
-    // something).
-    const Type *STyFieldTy = STy->getElementType(FieldNo);
-    unsigned STyFieldBitSize = getTargetData().getTypeSizeInBits(STyFieldTy);
-    
-    // If the bitfield starts after this field, advance to the next field.  This
-    // can happen because we start looking at the first element overlapped by
-    // an aligned instance of the declared type. 
-    if (OffsetToBitFieldStart >= STyFieldBitSize) {
-      OffsetToBitFieldStart -= STyFieldBitSize;
-      STyFieldBitOffs       += STyFieldBitSize;
-      continue;
-    }
-    
-    // We are inserting part of 'Val' into this LLVM field.  The start bit
-    // is OffsetToBitFieldStart.  Compute the number of bits from this bitfield
-    // we are inserting into this LLVM field.
-    unsigned NumBitsToInsert =
-      std::min(BitfieldSize, STyFieldBitSize-OffsetToBitFieldStart);
-    
-    // Compute the NumBitsToInsert-wide value that we are going to insert
-    // into this field as an ulong integer constant value.
-    uint64_t ValToInsert;
-    if (BYTES_BIG_ENDIAN) {
-      // If this is a big-endian bit-field, take the top NumBitsToInsert
-      // bits from the bitfield value.
-      ValToInsert = BitfieldVal >> (BitfieldSize-NumBitsToInsert);
-      
-      // Clear the handled bits from BitfieldVal.
-      BitfieldVal &= (1ULL << (BitfieldSize-NumBitsToInsert))-1;
+    } else if (Val.getBitWidth() == 8) {
+      ValToAppend = ConstantInt::get(Val);
     } else {
-      // If this is little-endian bit-field, take the bottom NumBitsToInsert
-      // bits from the bitfield value.
-      ValToInsert = BitfieldVal & ((1ULL << NumBitsToInsert)-1);
-      BitfieldVal >>= NumBitsToInsert;
+      APInt Tmp = Val;
+      Tmp.zext(8);
+      
+      if (BYTES_BIG_ENDIAN)
+        Tmp = Tmp << 8-Val.getBitWidth();
+      ValToAppend = ConstantInt::get(Tmp);
     }
     
-    ResultElts[FieldNo] = InsertBitFieldValue(ValToInsert, NumBitsToInsert,
-                                              OffsetToBitFieldStart,
-                                              STyFieldBitSize,
-                                              ResultElts[FieldNo], STyFieldTy);
+    ResultElts.push_back(ValToAppend);
+    ++NextFieldByteStart;
     
-    // If this bitfield splits across multiple LLVM fields, update these
-    // values for the next field.
-    BitfieldSize          -= NumBitsToInsert;
-    STyFieldBitOffs       += STyFieldBitSize;
-    OffsetToBitFieldStart = 0;
+    if (Val.getBitWidth() <= 8)
+      break;
+    Val.trunc(Val.getBitWidth()-8);
   }
 }
 
-/// ConvertStructFieldInitializerToType - Convert the input value to a new type,
-/// when constructing the field initializers for a constant CONSTRUCTOR object.
-static Constant *ConvertStructFieldInitializerToType(Constant *Val, 
-                                                     const Type *FieldTy) {
-  const TargetData &TD = getTargetData();
-  assert(TD.getTypePaddedSize(FieldTy) == TD.getTypePaddedSize(Val->getType()) &&
-         "Mismatched initializer type isn't same size as initializer!");
-
-  // If this is an integer initializer for an array of ubytes, we are
-  // initializing an unaligned integer field.  Break the integer initializer up
-  // into pieces.
-  if (ConstantInt *CI = dyn_cast<ConstantInt>(Val)) {
-    if (const ArrayType *ATy = dyn_cast<ArrayType>(FieldTy))
-      if (ATy->getElementType() == Type::Int8Ty) {
-        std::vector<Constant*> ArrayElts;
-        uint64_t Val = CI->getZExtValue();
-        for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
-          unsigned char EltVal;
 
-          if (BYTES_BIG_ENDIAN) {
-            EltVal = (Val >> 8*(e-i-1)) & 0xFF;
-          } else {
-            EltVal = (Val >> 8*i) & 0xFF;
-          }
-
-          ArrayElts.push_back(ConstantInt::get(Type::Int8Ty, EltVal));
-        }
-
-        return ConstantArray::get(ATy, ArrayElts);
-      }
+/// HandleTailPadding - Check to see if the struct fields, as laid out so far,
+/// will be large enough to make the generated constant struct have the right
+/// size.  If not, add explicit tail padding.  If rounding up based on the LLVM
+/// IR alignment would make the struct too large, convert it to a packed LLVM
+/// struct.
+void ConstantLayoutInfo::HandleTailPadding(uint64_t GCCStructBitSize) {
+  uint64_t GCCStructSize = (GCCStructBitSize+7)/8;
+  uint64_t LLVMNaturalSize =
+    TargetData::RoundUpAlignment(NextFieldByteStart, MaxLLVMFieldAlignment);
+  
+  // If the total size of the laid out data is within the size of the GCC type
+  // but the rounded-up size (including the tail padding induced by LLVM
+  // alignment) is too big, convert to a packed struct type.  We don't do this
+  // if the size of the laid out fields is too large because initializers like
+  //
+  //    struct X { int A; char C[]; } x = { 4, "foo" };
+  //
+  // can occur and no amount of packing will help.
+  if (NextFieldByteStart <= GCCStructSize &&   // Not flexible init case.
+      LLVMNaturalSize > GCCStructSize) {       // Tail pad will overflow type.
+    assert(!StructIsPacked && "LLVM Struct type overflow!");
+    
+    // Switch to packed.
+    ConvertToPacked();
+    LLVMNaturalSize = NextFieldByteStart;
+    
+    // Verify that packing solved the problem.
+    assert(LLVMNaturalSize <= GCCStructSize &&
+           "Oversized should be handled by packing");
+  }
+  
+  // If the LLVM Size is too small, add some tail padding to fill it in.
+  if (LLVMNaturalSize < GCCStructSize) {
+    const Type *FillTy = Type::Int8Ty;
+    if (GCCStructSize - NextFieldByteStart != 1)
+      FillTy = ArrayType::get(FillTy, GCCStructSize - NextFieldByteStart);
+    ResultElts.push_back(Constant::getNullValue(FillTy));
   }
-
-  // Otherwise, we can get away with this initialization.
-  assert(TD.getABITypeAlignment(FieldTy) >= 
-         TD.getABITypeAlignment(Val->getType()) &&
-         "Field initialize is over aligned for LLVM type!");
-  return Val;
 }
 
-
 Constant *TreeConstantToLLVM::ConvertRecordCONSTRUCTOR(tree exp) {
-  const StructType *STy = cast<StructType>(ConvertType(TREE_TYPE(exp)));
-  std::vector<Constant*> ResultElts;
-  ResultElts.resize(STy->getNumElements());
-
+  ConstantLayoutInfo LayoutInfo(getTargetData());
+  
   tree NextField = TYPE_FIELDS(TREE_TYPE(exp));
-  unsigned HOST_WIDE_INT ix;
-  tree elt_value;
-  tree Field; // The fielddecl for the field.
-  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), ix, Field, elt_value) {
-    unsigned FieldNo;
-    if (Field == 0) {           // If an explicit field is specified, use it.
+  unsigned HOST_WIDE_INT CtorIndex;
+  tree FieldValue;
+  tree Field; // The FIELD_DECL for the field.
+  FOR_EACH_CONSTRUCTOR_ELT(CONSTRUCTOR_ELTS(exp), CtorIndex, Field, FieldValue){
+    // If an explicit field is specified, use it.
+    if (Field == 0) {
       Field = NextField;
       // Advance to the next FIELD_DECL, skipping over other structure members
       // (e.g. enums).
-      for (; 1; Field = TREE_CHAIN(Field)) {
+      while (1) {
         assert(Field && "Fell off end of record!");
         if (TREE_CODE(Field) == FIELD_DECL) break;
+        Field = TREE_CHAIN(Field);
       }
     }
-
+    
     // Decode the field's value.
-    Constant *Val = Convert(elt_value);
-
-    // If the field is a bitfield, it could be spread across multiple fields and
-    // may start at some bit offset.
-    if (isBitfield(Field)) {
-      ProcessBitFieldInitialization(Field, Val, STy, ResultElts);
-    } else {
-      // If not, things are much simpler.
-      unsigned int FieldNo = GetFieldIndex(Field);
-      assert(FieldNo < ResultElts.size() && "Invalid struct field number!");
-
-      // Example: struct X { int A; char C[]; } x = { 4, "foo" };
-      assert((TYPE_SIZE(getDeclaredType(Field)) ||
-             (FieldNo == ResultElts.size()-1 &&
-              isStructWithVarSizeArrayAtEnd(STy)))
-             && "field with no size is not array at end of struct!");
-
-      // If this is an initialization of a global that ends with a variable
-      // sized array at its end, and the initializer has a non-zero number of
-      // elements, then Val contains the actual type for the array.  Otherwise,
-      // we know that the initializer has to match the element type of the LLVM
-      // structure field.  If not, then there is something that is not
-      // straight-forward going on.  For example, we could be initializing an
-      // unaligned integer field (e.g. due to attribute packed) with an
-      // integer.  The struct field will have type [4 x ubyte] instead of
-      // "int" for example.  If we ignored this, we would lay out the
-      // initializer wrong.
-      if (TYPE_SIZE(getDeclaredType(Field)) &&
-          Val->getType() != STy->getElementType(FieldNo))
-        Val = ConvertStructFieldInitializerToType(Val,
-                                                  STy->getElementType(FieldNo));
+    Constant *Val = Convert(FieldValue);
+    
+    // GCCFieldOffsetInBits is where GCC is telling us to put the current field.
+    uint64_t GCCFieldOffsetInBits = getFieldOffsetInBits(Field);
+    NextField = TREE_CHAIN(Field);
+    
 
-      ResultElts[FieldNo] = Val;
+    // If this is a non-bitfield value, just slap it onto the end of the struct
+    // with the appropriate padding etc.  If it is a bitfield, we have more
+    // processing to do.
+    if (!isBitfield(Field))
+      LayoutInfo.AddFieldToRecordConstant(Val, GCCFieldOffsetInBits);
+    else {
+      assert(isa<ConstantInt>(Val) && "Can only init bitfield with constant");
+      assert(Val->getType()->getPrimitiveSizeInBits() ==
+                TREE_INT_CST_LOW(DECL_SIZE(Field)) &&
+             "disagreement between LLVM and GCC on bitfield size");
+      LayoutInfo.AddBitFieldToRecordConstant(cast<ConstantInt>(Val),
+                                             GCCFieldOffsetInBits);
     }
-
-    NextField = TREE_CHAIN(Field);
   }
   
-  // Fill in null elements with zeros.
-  for (unsigned i = 0, e = ResultElts.size(); i != e; ++i) {
-    if (ResultElts[i] == 0)
-      ResultElts[i] = Constant::getNullValue(STy->getElementType(i));
-  }
-
-  // The type we're going to build for the initializer is not necessarily the
-  // same as the type of the struct.  In cases where there is a union field.
-  // it is possible for the size and/or alignment of the two structs to differ,
-  // in which case we need some explicit padding.
-  Constant *retval = ConstantStruct::get(ResultElts, STy->isPacked());
-  const Type *NewSTy = retval->getType();
-
-  unsigned oldLLVMSize = getTargetData().getTypePaddedSize(STy);
-  unsigned oldLLVMAlign = getTargetData().getABITypeAlignment(STy);
-  oldLLVMSize = ((oldLLVMSize+oldLLVMAlign-1)/oldLLVMAlign)*oldLLVMAlign;
-
-  unsigned newLLVMSize = getTargetData().getTypePaddedSize(NewSTy);
-  unsigned newLLVMAlign = getTargetData().getABITypeAlignment(NewSTy);
-  newLLVMSize = ((newLLVMSize+newLLVMAlign-1)/newLLVMAlign)*newLLVMAlign;
-
-  // oldSize < newSize occurs legitimately when we don't know the size of
-  // the struct.
-  if (newLLVMSize < oldLLVMSize) {
-    const Type *FillTy;
-    if (oldLLVMSize - newLLVMSize == 1)
-      FillTy = Type::Int8Ty;
-    else
-      FillTy = ArrayType::get(Type::Int8Ty, oldLLVMSize - newLLVMSize);
-    ResultElts.push_back(Constant::getNullValue(FillTy));
-    retval = ConstantStruct::get(ResultElts, STy->isPacked());
-  }
-
-  return retval;
+  // Check to see if the struct fields, as laid out so far, will be large enough
+  // to make the generated constant struct have the right size.  If not, add
+  // explicit tail padding.  If rounding up based on the LLVM IR alignment would
+  // make the struct too large, convert it to a packed LLVM struct.
+  tree StructTypeSizeTree = TYPE_SIZE(TREE_TYPE(exp));
+  if (StructTypeSizeTree && TREE_CODE(StructTypeSizeTree) == INTEGER_CST)
+    LayoutInfo.HandleTailPadding(getInt64(StructTypeSizeTree, true));
+  
+  // Okay, we're done, return the computed elements.
+  return ConstantStruct::get(LayoutInfo.ResultElts, LayoutInfo.StructIsPacked);
 }
 
 Constant *TreeConstantToLLVM::ConvertUnionCONSTRUCTOR(tree exp) {
@@ -7125,8 +7166,8 @@
   // it out.
   tree UnionType = TREE_TYPE(exp);
   if (TYPE_SIZE(UnionType) && TREE_CODE(TYPE_SIZE(UnionType)) == INTEGER_CST) {
-    unsigned UnionSize = ((unsigned)TREE_INT_CST_LOW(TYPE_SIZE(UnionType))+7)/8;
-    unsigned InitSize = getTargetData().getTypePaddedSize(Elts[0]->getType());
+    uint64_t UnionSize = ((uint64_t)TREE_INT_CST_LOW(TYPE_SIZE(UnionType))+7)/8;
+    uint64_t InitSize = getTargetData().getTypePaddedSize(Elts[0]->getType());
     if (UnionSize != InitSize) {
       const Type *FillTy;
       assert(UnionSize > InitSize && "Init shouldn't be larger than union!");





More information about the llvm-branch-commits mailing list