stage2 提供近乎完整的功能但出现严重性能问题 添加stage0的原生性能记录 stage1添加更多内置函数 nob重构代码使其更加健壮
This commit is contained in:
1 parent
b5a7a811b3
commit
e02b0c633a
35 files changed
+14018
-216
No files matched your search
@@ -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;
|
||||
}
|
||||
Reference in new issue
Block a user