static unsigned get_object_alignment(expression_t const *const expr) { entity_t *ent; switch (expr->kind) { case EXPR_ARRAY_ACCESS: return get_address_alignment(expr->array_access.array_ref); case EXPR_UNARY_DEREFERENCE: return get_address_alignment(expr->unary.value); case EXPR_REFERENCE: ent = expr->reference.entity; break; case EXPR_SELECT: ent = expr->select.compound_entry; break; default: return get_type_alignment(expr->base.type); } assert(is_declaration(ent)); return get_declaration_alignment(&ent->declaration); }
void layout_compound(compound_t *const compound) { bool const is_union = compound->base.kind == ENTITY_UNION; unsigned alignment = compound->alignment; size_t bit_offset = 0; unsigned size = 0; bool need_pad = false; for (entity_t *entry = compound->members.first_entity; entry; entry = entry->base.next) { if (entry->kind != ENTITY_COMPOUND_MEMBER) continue; compound_member_t *const member = &entry->compound_member; type_t *const m_type = skip_typeref(member->base.type); if (!is_type_valid(m_type)) continue; unsigned m_alignment = get_declaration_alignment(&member->base); alignment = MAX(alignment, m_alignment); unsigned const m_size = get_ctype_size(m_type); if (is_union) { size = MAX(size, m_size); } else if (member->bitfield) { unsigned const alignment_mask = m_alignment - 1; size_t const base_size = m_size * BITS_PER_BYTE; size_t const bit_size = member->bit_size; bit_offset += (size & alignment_mask) * BITS_PER_BYTE; size &= ~alignment_mask; if (bit_offset + bit_size > base_size || (bit_size == 0 && !(member->base.modifiers & DM_PACKED))) { size += (bit_offset + BITS_PER_BYTE - 1) / BITS_PER_BYTE; size = round_up2(size, m_alignment); bit_offset = 0; } if (target.byte_order_big_endian) { member->offset = size & ~alignment_mask; member->bit_offset = base_size - bit_offset - bit_size; } else { member->offset = size; member->bit_offset = bit_offset; } bit_offset += bit_size; size += bit_offset / BITS_PER_BYTE; bit_offset %= BITS_PER_BYTE; } else { if (bit_offset != 0) { bit_offset = 0; size += 1; } unsigned const new_size = round_up2(size, m_alignment); if (new_size > size) { need_pad = true; size = new_size; } member->offset = size; size += m_size; } } if (bit_offset != 0) size += 1; unsigned const new_size = round_up2(size, alignment); if (new_size > size) { need_pad = true; size = new_size; } position_t const *const pos = &compound->base.pos; if (need_pad) { warningf(WARN_PADDED, pos, "%N needs padding", compound); } else if (compound->packed) { warningf(WARN_PACKED, pos, "superfluous packed attribute on %N", compound); } compound->size = size; compound->alignment = alignment; }