stage2 提供近乎完整的功能但出现严重性能问题 添加stage0的原生性能记录 stage1添加更多内置函数 nob重构代码使其更加健壮

This commit is contained in:
zzy committed 2026-09-19 18:08:43 +08:00
1 parent b5a7a811b3
commit e02b0c633a
35 files changed
+14018 -216

No files matched your search

+358
View File
@@ -0,0 +1,358 @@
// Expect retcode = 0
// 目标布局(移植自 stage1/spl_layout.c)。输入是 IR 类型表 TypeTable;
// 为每个类型计算 size_bits / align_bits / 字段位偏移,供 ir2vm 使用。
// 默认 64 位平台:标量按 1/2/4/8 字节对齐,指针 = usize,聚合按最大字段对齐
// 且不允许重排(与 stage1 的默认策略一致)。
type .{ .Error } = @import("utils/error.spl");
type .{ .Vec } = @import("utils/vec.spl");
type TypeTable = @import("./type_table.spl");
type .{ .TypeNode, .Agg, .AggKind, .Member } = @import("./type_table.spl");
type .{ .node, .member_at, .make_int, .make_array, .make_agg, .push_member } = @import("./type_table.spl");
type LayoutInfo = struct {
size_bits: usize,
align_bits: usize,
field_bit_offsets: Vec, // usize
field_bit_sizes: Vec, // usize
resolved: bool,
}
type Layout = @self;
infos: Vec, // LayoutInfo
ptr_size: usize,
ptr_align: usize,
type LayoutResult = enum {
Ok: Layout,
Err: Error,
}
fn blank_usizes(): Vec {
ret Vec.blank(@sizeof(usize), @alignof(usize));
}
fn new(): LayoutResult {
ret .Ok(Layout {
.infos = Vec.blank(@sizeof(LayoutInfo), @alignof(LayoutInfo)),
.ptr_size = @sizeof(usize),
.ptr_align = @alignof(usize),
});
}
fn info_at(self: *Layout, id: usize): *LayoutInfo {
if id == 0 || id >= self.infos.len { ret null; }
match Vec.get(&self.infos, id) {
.Ok(ptr) => { ret ptr as *LayoutInfo; },
.Err(error) => { ret null; },
}
ret null;
}
// 未解析或越界返回 null(对应 stage1 spl_layout_info_of)。
fn info_of(self: *Layout, id: usize): *LayoutInfo {
var info = info_at(self, id);
if info == null || !info.resolved { ret null; }
ret info;
}
fn drop(self: *Layout) {
var i: usize = 0;
while i < self.infos.len {
var info = info_at(self, i);
if info != null {
Vec.drop(&info.field_bit_offsets);
Vec.drop(&info.field_bit_sizes);
}
i = i + 1;
}
Vec.drop(&self.infos);
}
fn ensure(self: *Layout, n: usize) {
while self.infos.len < n {
var info = LayoutInfo {
.size_bits = 0,
.align_bits = 0,
.field_bit_offsets = blank_usizes(),
.field_bit_sizes = blank_usizes(),
.resolved = false,
};
match Vec.push(&self.infos, &info as *u8) {
.Ok => {},
.Err(error) => { ret; },
}
}
}
fn push_usize(v: *Vec, x: usize) {
match Vec.push(v, &x as *u8) {
.Ok => {},
.Err(error) => {},
}
}
fn usize_at(v: *Vec, i: usize): usize {
match Vec.get(v, i) {
.Ok(ptr) => { ret (ptr as *usize).*; },
.Err(error) => { ret 0; },
}
ret 0;
}
// 标量对齐(字节);0 表示没有匹配的标量(即未落地)。
fn scalar_align(size_bytes: usize): usize {
if size_bytes == 1 { ret 1; }
if size_bytes == 2 { ret 2; }
if size_bytes == 4 { ret 4; }
if size_bytes == 8 { ret 8; }
ret 0;
}
fn round_up_bits(x: usize, align_bits: usize): usize {
if align_bits <= 1 { ret x; }
ret (x + align_bits - 1) / align_bits * align_bits;
}
fn layout_scalar(info: *LayoutInfo, size_bits: usize) {
var size_bytes = (size_bits + 7) / 8;
var a = scalar_align(size_bytes);
if a == 0 { ret; }
info.size_bits = size_bytes * 8;
info.align_bits = a * 8;
}
fn layout_ptr(self: *Layout, info: *LayoutInfo) {
if self.ptr_size == 0 { ret; }
info.size_bits = self.ptr_size * 8;
info.align_bits = self.ptr_align * 8;
}
// enum 与 struct/union/shape 的布局。字段索引约定(与 ir2vm 一致):
// enum: 0 = tag,1..n = 各变体载荷(同一偏移);其余按声明顺序。
fn layout_agg(self: *Layout, is_enum: bool, is_union: bool, agg: Agg, info: *LayoutInfo) {
var n = agg.variants.len;
if is_enum {
if agg.tag_type == 0 { ret; }
var tag_info = info_at(self, agg.tag_type);
if tag_info == null || !tag_info.resolved { ret; }
var tag_align_bits = tag_info.align_bits;
if tag_align_bits == 0 { tag_align_bits = 8; }
var payload_align_bits: usize = 8;
var payload_size_bits: usize = 0;
var i: usize = 0;
while i < n {
var m = member_at(&agg.variants, i);
if m != null && m.type_id != 0 {
var fi = info_at(self, m.type_id);
if fi == null || !fi.resolved { ret; }
var fa = fi.align_bits;
if fa == 0 { fa = 8; }
if fa > payload_align_bits { payload_align_bits = fa; }
if fi.size_bits > payload_size_bits { payload_size_bits = fi.size_bits; }
}
i = i + 1;
}
var payload_off = round_up_bits(tag_info.size_bits, payload_align_bits);
var final_align = tag_align_bits;
if payload_align_bits > final_align { final_align = payload_align_bits; }
info.size_bits = round_up_bits(payload_off + payload_size_bits, final_align);
info.align_bits = final_align;
push_usize(&info.field_bit_offsets, 0);
push_usize(&info.field_bit_sizes, tag_info.size_bits);
i = 0;
while i < n {
var m = member_at(&agg.variants, i);
var fsize: usize = 0;
if m != null && m.type_id != 0 {
var fi = info_at(self, m.type_id);
if fi != null { fsize = fi.size_bits; }
}
push_usize(&info.field_bit_offsets, payload_off);
push_usize(&info.field_bit_sizes, fsize);
i = i + 1;
}
ret;
}
if n == 0 {
info.size_bits = 0;
info.align_bits = 8;
ret;
}
var max_align_bits: usize = 8;
var offset_bits: usize = 0;
var i: usize = 0;
while i < n {
var m = member_at(&agg.variants, i);
var fsize_bits: usize = 0;
var fsize_align: usize = 8;
if m != null && m.type_id != 0 {
var fi = info_at(self, m.type_id);
if fi == null || !fi.resolved { ret; }
fsize_bits = fi.size_bits;
fsize_align = fi.align_bits;
if fsize_align == 0 { fsize_align = 8; }
}
if is_union {
push_usize(&info.field_bit_offsets, 0);
push_usize(&info.field_bit_sizes, fsize_bits);
if fsize_bits > info.size_bits { info.size_bits = fsize_bits; }
} else {
offset_bits = round_up_bits(offset_bits, fsize_align);
push_usize(&info.field_bit_offsets, offset_bits);
push_usize(&info.field_bit_sizes, fsize_bits);
offset_bits = offset_bits + fsize_bits;
}
if fsize_align > max_align_bits { max_align_bits = fsize_align; }
i = i + 1;
}
if is_union {
info.size_bits = round_up_bits(info.size_bits, max_align_bits);
} else {
info.size_bits = round_up_bits(offset_bits, max_align_bits);
}
info.align_bits = max_align_bits;
}
fn resolve_members(self: *Layout, tt: *TypeTable, agg: Agg) {
var i: usize = 0;
while i < agg.variants.len {
var m = member_at(&agg.variants, i);
if m != null && m.type_id != 0 { resolve_one(self, tt, m.type_id); }
i = i + 1;
}
}
fn resolve_one(self: *Layout, tt: *TypeTable, id: usize) {
var info = info_at(self, id);
if info == null || info.resolved { ret; }
var e = node(tt, id);
if e == null { ret; }
info.resolved = true;
match e.node {
.Error => { info.size_bits = 0; info.align_bits = 8; },
.Infer => { info.size_bits = 0; info.align_bits = 8; },
.Forall => { info.size_bits = 0; info.align_bits = 8; },
.Exists => { info.size_bits = 0; info.align_bits = 8; },
.Never => { info.size_bits = 0; info.align_bits = 8; },
.Unit => { info.size_bits = 0; info.align_bits = 8; },
.Any => { layout_ptr(self, info); },
.Bool => { layout_scalar(info, 8); },
.Int(x) => { layout_scalar(info, x.bits); },
.Float(x) => { layout_scalar(info, x.bits); },
.Ptr(x) => { layout_ptr(self, info); },
.Array(a) => {
resolve_one(self, tt, a.element);
var elem = info_at(self, a.element);
if elem == null || !elem.resolved { ret; }
info.size_bits = elem.size_bits * a.len;
info.align_bits = elem.align_bits;
},
.Struct(agg) => {
resolve_members(self, tt, agg);
layout_agg(self, false, false, agg, info);
},
.Union(agg) => {
resolve_members(self, tt, agg);
layout_agg(self, false, true, agg, info);
},
.Enum(agg) => {
if agg.tag_type != 0 { resolve_one(self, tt, agg.tag_type); }
resolve_members(self, tt, agg);
layout_agg(self, true, false, agg, info);
},
.Shape(agg) => {
resolve_members(self, tt, agg);
layout_agg(self, false, false, agg, info);
},
.Fn(f) => {
var i: usize = 0;
while i < f.params.len {
resolve_one(self, tt, usize_at(&f.params, i));
i = i + 1;
}
resolve_one(self, tt, f.ret_type);
layout_ptr(self, info);
},
}
}
fn resolve(self: *Layout, tt: *TypeTable) {
ensure(self, tt.table.len);
var i: usize = 1;
while i < tt.table.len {
resolve_one(self, tt, i);
i = i + 1;
}
}
fn main() {
var tt: TypeTable = undefined;
match TypeTable.new() {
.Ok(v) => { tt = v; },
.Err(error) => { @assert(false, "layout test: tt init"); ret; },
}
defer { TypeTable.drop(&tt); }
var i32t = make_int(&tt, 32, true);
var u8t = make_int(&tt, 8, false);
var members = Vec.blank(@sizeof(Member), @alignof(Member));
push_member(&members, "a", i32t);
push_member(&members, "b", u8t);
var agg = Agg { .mode = .Auto, .fixed_align_bits = 0, .tag_type = 0, .variants = members };
var sid = make_agg(&tt, .Struct, agg);
var layout: Layout = undefined;
match new() {
.Ok(v) => { layout = v; },
.Err(error) => { @assert(false, "layout test: layout init"); ret; },
}
defer { drop(&layout); }
resolve(&layout, &tt);
var info = info_of(&layout, sid);
if info == null {
@assert(false, "struct layout missing");
ret;
}
@assert(info.size_bits == 64, "struct size_bits");
@assert(info.align_bits == 32, "struct align_bits");
@assert(usize_at(&info.field_bit_offsets, 0) == 0, "field0 off");
@assert(usize_at(&info.field_bit_offsets, 1) == 32, "field1 off");
var arr = make_array(&tt, i32t, 3);
resolve(&layout, &tt);
var ainfo = info_of(&layout, arr);
if ainfo == null {
@assert(false, "array layout missing");
ret;
}
@assert(ainfo.size_bits == 96, "array size_bits");
@assert(ainfo.align_bits == 32, "array align_bits");
var pt = TypeTable.make_ptr(&tt, u8t);
resolve(&layout, &tt);
var pinfo = info_of(&layout, pt);
if pinfo == null {
@assert(false, "ptr layout missing");
ret;
}
@assert(pinfo.size_bits == @sizeof(usize) * 8, "ptr size_bits");
ret;
}