unsigned get_ctype_size(type_t const *const type) { switch (type->kind) { case TYPE_ERROR: return 0; case TYPE_ATOMIC: case TYPE_IMAGINARY: case TYPE_ENUM: return get_atomic_type_size(type->atomic.akind); case TYPE_COMPLEX: return get_atomic_type_size(type->atomic.akind) * 2; case TYPE_COMPOUND_STRUCT: case TYPE_COMPOUND_UNION: return type->compound.compound->size; case TYPE_FUNCTION: case TYPE_VOID: return 1; /* GCC extension. */ case TYPE_REFERENCE: case TYPE_POINTER: return pointer_properties.size; case TYPE_ARRAY: { /* TODO: correct if element_type is aligned? */ unsigned element_size = get_ctype_size(type->array.element_type); return type->array.size * element_size; } case TYPE_TYPEDEF: return get_ctype_size(type->typedeft.typedefe->type); case TYPE_TYPEOF: return get_ctype_size(type->typeoft.typeof_type); case TYPE_BUILTIN_TEMPLATE: break; } panic("invalid type"); }
static SExp make_cfunc(void* cfunc, SExp rettype, SExp argtypes) { int argnum = length(argtypes); CFunction* p = (CFunction*)smalloc(sizeof(*p) + sizeof(*p->args) * (argnum-1), TRUE); SExp q; int argsize = 0; int i; p->typeinfo = &TCFunc; p->cfunc = cfunc; p->rettype = sym2ctype(rettype); p->argnum = argnum; for (q = argtypes, i = 0; consp(q); q = CDR(q), ++i) { eCType t = sym2ctype(CAR(q)); int size = get_ctype_size(t); p->args[i].type = t; p->args[i].size = size; argsize += size; } p->argsize = argsize; return ptr2s(p); }
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; }