Index: llvm-gcc.test/gcc/testsuite/gcc.apple/6564697.c =================================================================== --- llvm-gcc.test/gcc/testsuite/gcc.apple/6564697.c (revision 0) +++ llvm-gcc.test/gcc/testsuite/gcc.apple/6564697.c (revision 0) @@ -0,0 +1,41 @@ +/* APPLE LOCAL file 6564697 */ +/* { dg-do run } */ +/* { dg-options -std=c99 } */ +#include +#include +struct sl_value_small_struct +{ + int info; + union + { + int id; /* Initializer for u.id must be 8-byte aligned on 64-bit targets. */ + char *str; + } u; +}; +const struct sl_value_small_struct static_regs[] = { +{ 101, {.str = "fubar"} }, +{ 102, {.id = 2} }, +{ 103, {.str = "fubar"} }, +{ 104, {.id = 4} }, +}; + +void +printit(const struct sl_value_small_struct *st) { + printf ("info=%d, id=%d (str=%p)\n", st->info, st->u.id, st->u.str); +} + +int one = 1, three = 3; + +int +main() +{ + /* printit(static_regs+1); printit(static_regs+3); */ + if (static_regs[one].info != 102) + abort(); + if (static_regs[one].u.id != 2) + abort(); + if (static_regs[three].info != 104) + abort(); + if (static_regs[three].u.id != 4) + abort(); +} Index: llvm-gcc.test/gcc/llvm-convert.cpp =================================================================== --- llvm-gcc.test/gcc/llvm-convert.cpp (revision 64914) +++ llvm-gcc.test/gcc/llvm-convert.cpp (working copy) @@ -6985,8 +6985,8 @@ static Constant *InsertBitFieldValue(uin /// ProcessBitFieldInitialization - Handle a static initialization of a /// RECORD_TYPE field that is a bitfield. -static void ProcessBitFieldInitialization(tree Field, Value *Val, - const StructType *STy, +static void ProcessBitFieldInitialization(tree Field, unsigned &FieldNo, + Value *Val, const StructType *STy, std::vector &ResultElts) { // Get the offset and size of the bitfield, in bits. unsigned BitfieldBitOffset = getFieldOffsetInBits(Field); @@ -7003,15 +7003,15 @@ static void ProcessBitFieldInitializatio // 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 + // If this is a bitfield, we know that LLVMFieldNo is the *first* LLVM field + // that contains bits from the bitfield overlaid 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!"); + unsigned int LLVMFieldNo = GetFieldIndex(Field); + assert(LLVMFieldNo < ResultElts.size() && "Invalid struct field number!"); // Get the offset and size of the LLVM field. - uint64_t STyFieldBitOffs = STyLayout->getElementOffset(FieldNo)*8; + uint64_t STyFieldBitOffs = STyLayout->getElementOffset(LLVMFieldNo)*8; assert(BitfieldBitOffset >= STyFieldBitOffs && "This bitfield doesn't start in this LLVM field!"); @@ -7019,14 +7019,14 @@ static void ProcessBitFieldInitializatio // 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 && + for (; BitfieldSize; ++LLVMFieldNo, ++FieldNo) { + assert(STyFieldBitOffs == STyLayout->getElementOffset(LLVMFieldNo)*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); + const Type *STyFieldTy = STy->getElementType(LLVMFieldNo); unsigned STyFieldBitSize = getTargetData().getTypeSizeInBits(STyFieldTy); // If the bitfield starts after this field, advance to the next field. This @@ -7069,6 +7069,9 @@ static void ProcessBitFieldInitializatio // If this bitfield splits across multiple LLVM fields, update these // values for the next field. BitfieldSize -= NumBitsToInsert; + // If we're done, return immediately, avoiding increment of FieldNo. + if (BitfieldSize == 0) + return; STyFieldBitOffs += STyFieldBitSize; OffsetToBitFieldStart = 0; } @@ -7113,18 +7116,20 @@ static Constant *ConvertStructFieldIniti return Val; } - Constant *TreeConstantToLLVM::ConvertRecordCONSTRUCTOR(tree exp) { const StructType *STy = cast(ConvertType(TREE_TYPE(exp))); std::vector ResultElts; - ResultElts.resize(STy->getNumElements()); - + // In theory, /every/ field might need padding. + ResultElts.resize(2 * STy->getNumElements()); + bool PredecessorWasBitfield = false; tree NextField = TYPE_FIELDS(TREE_TYPE(exp)); unsigned HOST_WIDE_INT ix; tree elt_value; tree Field; // The fielddecl for the field. + unsigned int FieldNo=0, LastBittenFieldNo; + uint64_t HighWaterMarkInBits=0; + uint64_t FieldOffsetInBits; FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), ix, Field, elt_value) { - unsigned FieldNo; if (Field == 0) { // If an explicit field is specified, use it. Field = NextField; // Advance to the next FIELD_DECL, skipping over other structure members @@ -7134,18 +7139,57 @@ Constant *TreeConstantToLLVM::ConvertRec if (TREE_CODE(Field) == FIELD_DECL) break; } } + // Get the offset (beginning_of_field - beginning_of_struct) from GCC. + FieldOffsetInBits = getFieldOffsetInBits(Field); // Decode the field's value. Constant *Val = Convert(elt_value); + // If there's a hole in the initializer, create padding for it. + assert(HighWaterMarkInBits <= FieldOffsetInBits + && "misinterpreted struct initializer"); + uint64_t PaddingSizeInBits = FieldOffsetInBits - HighWaterMarkInBits; + // If there's a gap of at least one byte, pad it. + if (PaddingSizeInBits >= 8) { + const Type *FillTy; + if (PaddingSizeInBits == 8) + FillTy = Type::Int8Ty; + else + FillTy = ArrayType::get(Type::Int8Ty, PaddingSizeInBits/8); + ResultElts[FieldNo++] = Constant::getNullValue(FillTy); + } + // 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); + // LastBittenFieldNo will be updated to the last field + // contaminated^Wcontaining an initalized bit. + LastBittenFieldNo = FieldNo; + ProcessBitFieldInitialization(Field, LastBittenFieldNo, + Val, STy, ResultElts); + PredecessorWasBitfield = true; } else { // If not, things are much simpler. - unsigned int FieldNo = GetFieldIndex(Field); - assert(FieldNo < ResultElts.size() && "Invalid struct field number!"); + const StructLayout *SL = getTargetData().getStructLayout(STy); + unsigned LLVMFieldNo = SL->getElementContainingOffset(FieldOffsetInBits/8); + + if (PredecessorWasBitfield) { + unsigned FieldAlignMask = TYPE_ALIGN(TREE_TYPE(Field)) - 1; + // HighWaterMarkInBits is probably unaligned; it points at the + // next bit to allocate. Advance it to the next GCC field + // alignment boundary. + HighWaterMarkInBits = + (HighWaterMarkInBits + FieldAlignMask) & ~FieldAlignMask; + // LastBittenFieldNo is last FieldNo with an initialized bit + // inside (it's also a miserable pun). Successor non-bit + // fields must go into the next ResultElt[]. + FieldNo = LastBittenFieldNo + 1; + PredecessorWasBitfield = false; + assert((HighWaterMarkInBits & FieldAlignMask) == 0 + && "leftover bits confusing field initialization"); + } + assert((HighWaterMarkInBits & 7) == 0 + && "expected byte alignment at minimum"); // Example: struct X { int A; char C[]; } x = { 4, "foo" }; assert((TYPE_SIZE(getDeclaredType(Field)) || @@ -7164,21 +7208,26 @@ Constant *TreeConstantToLLVM::ConvertRec // "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->getType() != STy->getElementType(LLVMFieldNo)) Val = ConvertStructFieldInitializerToType(Val, - STy->getElementType(FieldNo)); + STy->getElementType(LLVMFieldNo)); - ResultElts[FieldNo] = Val; + ResultElts[FieldNo++] = Val; } + HighWaterMarkInBits += TREE_INT_CST_LOW(DECL_SIZE(Field)); + NextField = TREE_CHAIN(Field); } + + if (PredecessorWasBitfield) + FieldNo = LastBittenFieldNo + 1; + + assert(FieldNo <= ResultElts.size() + && "Either LLVM & GCC structs are dissimilar," + " or too much padding was generated!"); - // 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)); - } + ResultElts.resize(FieldNo); // 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.