Files

325 lines
11 KiB
C

#include "spl_layout.h"
static void infos_grow(spl_layout_t *layout, usize n) {
while (vec_size(layout->infos) < n) {
spl_layout_info_t info = {0};
vec_init(info.field_bit_offsets);
vec_init(info.field_bit_sizes);
vec_push(layout->infos, info);
}
}
static spl_layout_info_t *infos_at(spl_layout_t *layout, spl_type_id_t id) {
if (id == 0 || id >= vec_size(layout->infos))
return NULL;
return &vec_at(layout->infos, id);
}
void spl_layout_add_scalar(spl_layout_t *layout, usize size, usize abi_align) {
spl_layout_scalar_t s = {0};
s.size = size;
s.abi_align = abi_align;
s.pref_align = abi_align;
vec_init(s.invalid_values);
vec_push(layout->scalars, s);
}
void spl_layout_add_ptr(spl_layout_t *layout, usize addr_space, usize size, usize align) {
spl_layout_ptr_t p = {0};
p.add_space = addr_space;
p.ptr_size = size;
p.ptr_align = align;
vec_push(layout->pointers, p);
}
void spl_layout_init(spl_layout_t *layout, spl_layout_target_t *target) {
vec_init(layout->scalars);
vec_init(layout->pointers);
vec_init(layout->infos);
layout->target = target;
/* 默认聚合策略:按最大字段对齐,不允许重排 */
layout->aggregate.allow_field_reordering = false;
layout->aggregate.align_rule = ALIGN_MAX;
layout->aggregate.fixed_align = 0;
/* 常见 64 位平台的默认布局。
若目标平台不适用,调用者 clear 后自行 add_*。 */
spl_layout_add_scalar(layout, 1, 1); /* i8 / u8 / bool */
spl_layout_add_scalar(layout, 2, 2); /* i16 / u16 */
spl_layout_add_scalar(layout, 4, 4); /* i32 / u32 / f32 */
spl_layout_add_scalar(layout, 8, 8); /* i64 / u64 / f64 */
usize ps = target && target->ptr_size ? target->ptr_size : sizeof(void *);
usize pa = target && target->ptr_align ? target->ptr_align : sizeof(void *);
spl_layout_add_ptr(layout, 0, ps, pa);
}
void spl_layout_drop(spl_layout_t *layout) {
for (usize i = 0; i < vec_size(layout->scalars); ++i)
vec_free(vec_at(layout->scalars, i).invalid_values);
vec_free(layout->scalars);
vec_free(layout->pointers);
for (usize i = 0; i < vec_size(layout->infos); ++i) {
vec_free(vec_at(layout->infos, i).field_bit_offsets);
vec_free(vec_at(layout->infos, i).field_bit_sizes);
}
vec_free(layout->infos);
}
static const spl_layout_scalar_t *scalar_for_size(spl_layout_t *layout, usize size_bytes) {
for (usize i = 0; i < vec_size(layout->scalars); ++i) {
spl_layout_scalar_t *s = &vec_at(layout->scalars, i);
if (s->size == size_bytes)
return s;
}
return NULL;
}
static const spl_layout_ptr_t *default_ptr(spl_layout_t *layout) {
if (vec_size(layout->pointers) == 0)
return NULL;
return &vec_at(layout->pointers, 0);
}
static bool layout_scalar(spl_layout_t *layout, spl_type_node_t *tn, spl_layout_info_t *out) {
usize size_bits = 0;
switch (tn->kind) {
case SPL_TYPE_INT:
if (tn->int_type.bits == 0)
return false; /* comptime_int 未落地 */
size_bits = tn->int_type.bits;
break;
case SPL_TYPE_FLOAT:
if (tn->float_type.bits == 0)
return false; /* comptime_float 未落地 */
size_bits = tn->float_type.bits;
break;
case SPL_TYPE_BOOL:
size_bits = 8;
break;
default:
return false;
}
usize size_bytes = (size_bits + 7) / 8;
const spl_layout_scalar_t *sl = scalar_for_size(layout, size_bytes);
if (!sl)
return false;
out->size_bits = sl->size * 8;
out->align_bits = sl->abi_align * 8;
return true;
}
static bool layout_ptr(spl_layout_t *layout, spl_layout_info_t *out) {
const spl_layout_ptr_t *pl = default_ptr(layout);
if (!pl)
return false;
out->size_bits = pl->ptr_size * 8;
out->align_bits = pl->ptr_align * 8;
return true;
}
static usize round_up_bits(usize x, usize align_bits) {
if (align_bits <= 1)
return x;
usize a = align_bits;
return (x + a - 1) / a * a;
}
static bool layout_agg(spl_layout_t *layout, spl_type_node_t *tn, spl_layout_info_t *out) {
usize n = vec_size(tn->agg_type.variants);
if (tn->kind == SPL_TYPE_ENUM) {
spl_type_id_t tag_tid = tn->agg_type.tag_type;
if (!tag_tid)
return false;
spl_layout_info_t *tag_info = infos_at(layout, tag_tid);
if (!tag_info || !tag_info->resolved)
return false;
usize tag_align_bits = tag_info->align_bits ? tag_info->align_bits : 8;
usize payload_align_bits = 8;
usize payload_size_bits = 0;
for (usize i = 0; i < n; ++i) {
spl_type_member_t *m = &vec_at(tn->agg_type.variants, i);
if (m->type_id == 0) /* 无载荷变体 */
continue;
spl_layout_info_t *fi = infos_at(layout, m->type_id);
if (!fi || !fi->resolved)
return false;
usize fa = fi->align_bits ? fi->align_bits : 8;
if (fa > payload_align_bits)
payload_align_bits = fa;
if (fi->size_bits > payload_size_bits)
payload_size_bits = fi->size_bits;
}
usize payload_off = round_up_bits(tag_info->size_bits, payload_align_bits);
usize final_align_bits =
tag_align_bits > payload_align_bits ? tag_align_bits : payload_align_bits;
out->size_bits = round_up_bits(payload_off + payload_size_bits, final_align_bits);
out->align_bits = final_align_bits;
/* 字段索引约定(与 ir2vm 一致):0 = tag,1..n = 各变体载荷(同一偏移)。 */
vec_push(out->field_bit_offsets, 0);
vec_push(out->field_bit_sizes, tag_info->size_bits);
for (usize i = 0; i < n; ++i) {
spl_type_member_t *m = &vec_at(tn->agg_type.variants, i);
usize fsize = 0;
if (m->type_id) {
spl_layout_info_t *fi = infos_at(layout, m->type_id);
if (fi)
fsize = fi->size_bits;
}
vec_push(out->field_bit_offsets, payload_off);
vec_push(out->field_bit_sizes, fsize);
}
return true;
}
if (n == 0) {
out->size_bits = 0;
out->align_bits = 8;
return true;
}
usize max_align_bits = 8;
usize offset_bits = 0;
bool is_union = (tn->kind == SPL_TYPE_UNION);
for (usize i = 0; i < n; ++i) {
spl_type_member_t *m = &vec_at(tn->agg_type.variants, i);
usize fsize_bits = 0;
usize fsize_align = 8;
if (m->type_id) {
spl_layout_info_t *fi = infos_at(layout, m->type_id);
if (!fi || !fi->resolved)
return false;
fsize_bits = fi->size_bits;
fsize_align = fi->align_bits ? fi->align_bits : 8;
}
usize field_align_bits = fsize_align;
if (is_union) {
vec_push(out->field_bit_offsets, 0);
vec_push(out->field_bit_sizes, fsize_bits);
if (fsize_bits > out->size_bits)
out->size_bits = fsize_bits;
} else {
offset_bits = round_up_bits(offset_bits, field_align_bits);
vec_push(out->field_bit_offsets, offset_bits);
vec_push(out->field_bit_sizes, fsize_bits);
offset_bits += fsize_bits;
}
if (field_align_bits > max_align_bits)
max_align_bits = field_align_bits;
}
usize final_align_bits = max_align_bits;
if (layout->aggregate.align_rule == ALIGN_FIXED) {
final_align_bits = layout->aggregate.fixed_align * 8;
} else if (layout->aggregate.align_rule == ALIGN_MAX_WITH_MIN) {
usize min_bits = layout->aggregate.fixed_align * 8;
if (final_align_bits < min_bits)
final_align_bits = min_bits;
}
if (is_union)
out->size_bits = round_up_bits(out->size_bits, final_align_bits);
else
out->size_bits = round_up_bits(offset_bits, final_align_bits);
out->align_bits = final_align_bits;
return true;
}
static void resolve_type(spl_layout_t *layout, spl_type_t *type, spl_type_id_t id) {
spl_layout_info_t *info = infos_at(layout, id);
if (!info || info->resolved)
return;
spl_type_node_t *tn = spl_type_node(type, id);
if (!tn)
return;
/* 先标记已解析:自引用类型(通过 ptr)不会无限递归,
但保持防御性写法。 */
info->resolved = true;
switch (tn->kind) {
case SPL_TYPE_ERROR:
case SPL_TYPE_INFER:
case SPL_TYPE_FORALL:
case SPL_TYPE_EXISTS:
case SPL_TYPE_NEVER:
case SPL_TYPE_UNIT:
info->size_bits = 0;
info->align_bits = 8;
return;
case SPL_TYPE_ANY:
/* 顶层类型:stage1 按不透明指针处理 */
layout_ptr(layout, info);
return;
case SPL_TYPE_BOOL:
case SPL_TYPE_INT:
case SPL_TYPE_FLOAT:
layout_scalar(layout, tn, info);
return;
case SPL_TYPE_PTR:
layout_ptr(layout, info);
return;
case SPL_TYPE_ARRAY: {
resolve_type(layout, type, tn->array_type.element);
spl_layout_info_t *elem = infos_at(layout, tn->array_type.element);
if (!elem || !elem->resolved)
return;
info->size_bits = elem->size_bits * tn->array_type.len;
info->align_bits = elem->align_bits;
return;
}
case SPL_TYPE_STRUCT:
case SPL_TYPE_UNION:
case SPL_TYPE_ENUM:
case SPL_TYPE_SHAPE: {
if (tn->kind == SPL_TYPE_ENUM && tn->agg_type.tag_type)
resolve_type(layout, type, tn->agg_type.tag_type);
for (usize i = 0; i < vec_size(tn->agg_type.variants); ++i) {
spl_type_member_t *m = &vec_at(tn->agg_type.variants, i);
if (m->type_id)
resolve_type(layout, type, m->type_id);
}
layout_agg(layout, tn, info);
return;
}
case SPL_TYPE_FN:
/* 函数类型按函数指针布局 */
for (usize i = 0; i < vec_size(tn->fn_type.params); ++i)
resolve_type(layout, type, vec_at(tn->fn_type.params, i));
resolve_type(layout, type, tn->fn_type.ret);
layout_ptr(layout, info);
return;
}
}
void spl_layout_resolve(spl_layout_t *layout, spl_type_t *type) {
infos_grow(layout, vec_size(type->type_table));
for (usize i = 1; i < vec_size(type->type_table); ++i)
resolve_type(layout, type, i);
}
const spl_layout_info_t *spl_layout_info_of(spl_layout_t *layout, spl_type_id_t id) {
spl_layout_info_t *info = infos_at(layout, id);
if (!info || !info->resolved)
return NULL;
return info;
}