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,331 @@
|
||||
// Expect retcode = 0
|
||||
|
||||
// 内建(intrinsic)注册表(移植自 stage1/spl_intrin.c)。表是数据:按 kind 查
|
||||
// 描述信息,按名字/字段/`as` 转换规则反查 kind。新增内建只改 info_at,
|
||||
// 不改 sema 逻辑(对应 SPL.md 的 @/# 扩展点)。
|
||||
|
||||
type .{ .ByteView } = @import("utils/byte_view.spl");
|
||||
type TypeTable = @import("./type_table.spl");
|
||||
type .{ .TypeNode, .TypeEntry } = @import("./type_table.spl");
|
||||
type .{ .LangKind } = @import("./lang_type.spl");
|
||||
|
||||
// 文件命名空间(供跨模块用 IntrinOps.foo 调用)。
|
||||
type IntrinOps = @self;
|
||||
|
||||
type Intrin = enum {
|
||||
None,
|
||||
BitSizeof,
|
||||
Sizeof,
|
||||
Alignof,
|
||||
Assert,
|
||||
Breakpoint,
|
||||
Len,
|
||||
IntCast,
|
||||
Truncate,
|
||||
BitCast,
|
||||
FloatCast,
|
||||
Float2Int,
|
||||
Int2Float,
|
||||
Bool2Int,
|
||||
Ptr2Int,
|
||||
Int2Ptr,
|
||||
PtrCast,
|
||||
Enum2Int,
|
||||
OffsetOf,
|
||||
FieldCount,
|
||||
}
|
||||
|
||||
type IntrinForm = enum {
|
||||
Call,
|
||||
Field,
|
||||
}
|
||||
|
||||
type IntrinResult = enum {
|
||||
Unit,
|
||||
Bool,
|
||||
Usize,
|
||||
}
|
||||
|
||||
type IntrinInfo = struct {
|
||||
name: ByteView,
|
||||
kind: Intrin,
|
||||
form: IntrinForm,
|
||||
min_args: i32,
|
||||
max_args: i32, // -1 = variadic
|
||||
result: IntrinResult,
|
||||
}
|
||||
|
||||
fn form_is(a: IntrinForm, b: IntrinForm): bool {
|
||||
ret @enum2int(a) == @enum2int(b);
|
||||
}
|
||||
|
||||
fn kind_is(a: LangKind, b: LangKind): bool {
|
||||
ret @enum2int(a) == @enum2int(b);
|
||||
}
|
||||
|
||||
// 与 stage1 表逐项对应(枚举顺序即 kind 数值)。
|
||||
fn info_at(index: usize): IntrinInfo {
|
||||
match index {
|
||||
1 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@bitsizeof"), .kind = .BitSizeof,
|
||||
.form = .Call, .min_args = 1, .max_args = 1, .result = .Usize };
|
||||
},
|
||||
2 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@sizeof"), .kind = .Sizeof,
|
||||
.form = .Call, .min_args = 1, .max_args = 1, .result = .Usize };
|
||||
},
|
||||
3 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@alignof"), .kind = .Alignof,
|
||||
.form = .Call, .min_args = 1, .max_args = 1, .result = .Usize };
|
||||
},
|
||||
4 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@assert"), .kind = .Assert,
|
||||
.form = .Call, .min_args = 1, .max_args = 2, .result = .Unit };
|
||||
},
|
||||
5 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@breakpoint"), .kind = .Breakpoint,
|
||||
.form = .Call, .min_args = 0, .max_args = 0, .result = .Unit };
|
||||
},
|
||||
6 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("len"), .kind = .Len,
|
||||
.form = .Field, .min_args = 0, .max_args = 0, .result = .Usize };
|
||||
},
|
||||
7 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@int_cast"), .kind = .IntCast,
|
||||
.form = .Call, .min_args = 2, .max_args = 2, .result = .Unit };
|
||||
},
|
||||
8 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@truncate"), .kind = .Truncate,
|
||||
.form = .Call, .min_args = 2, .max_args = 2, .result = .Unit };
|
||||
},
|
||||
9 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@bit_cast"), .kind = .BitCast,
|
||||
.form = .Call, .min_args = 2, .max_args = 2, .result = .Unit };
|
||||
},
|
||||
10 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@float_cast"), .kind = .FloatCast,
|
||||
.form = .Call, .min_args = 2, .max_args = 2, .result = .Unit };
|
||||
},
|
||||
11 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@float2int"), .kind = .Float2Int,
|
||||
.form = .Call, .min_args = 2, .max_args = 2, .result = .Unit };
|
||||
},
|
||||
12 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@int2float"), .kind = .Int2Float,
|
||||
.form = .Call, .min_args = 2, .max_args = 2, .result = .Unit };
|
||||
},
|
||||
13 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@bool2int"), .kind = .Bool2Int,
|
||||
.form = .Call, .min_args = 1, .max_args = 2, .result = .Unit };
|
||||
},
|
||||
14 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@ptr2int"), .kind = .Ptr2Int,
|
||||
.form = .Call, .min_args = 1, .max_args = 2, .result = .Unit };
|
||||
},
|
||||
15 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@int2ptr"), .kind = .Int2Ptr,
|
||||
.form = .Call, .min_args = 2, .max_args = 2, .result = .Unit };
|
||||
},
|
||||
16 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@ptr_cast"), .kind = .PtrCast,
|
||||
.form = .Call, .min_args = 2, .max_args = 2, .result = .Unit };
|
||||
},
|
||||
17 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@enum2int"), .kind = .Enum2Int,
|
||||
.form = .Call, .min_args = 1, .max_args = 1, .result = .Usize };
|
||||
},
|
||||
18 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@offsetof"), .kind = .OffsetOf,
|
||||
.form = .Call, .min_args = 2, .max_args = 2, .result = .Usize };
|
||||
},
|
||||
19 => {
|
||||
ret IntrinInfo { .name = ByteView.from_slice("@field_count"), .kind = .FieldCount,
|
||||
.form = .Call, .min_args = 1, .max_args = 1, .result = .Usize };
|
||||
},
|
||||
_ => {
|
||||
ret IntrinInfo { .name = ByteView.empty(), .kind = .None, .form = .Call,
|
||||
.min_args = 0, .max_args = 0, .result = .Unit };
|
||||
},
|
||||
}
|
||||
ret IntrinInfo { .name = ByteView.empty(), .kind = .None, .form = .Call,
|
||||
.min_args = 0, .max_args = 0, .result = .Unit };
|
||||
}
|
||||
|
||||
fn info(kind: Intrin): IntrinInfo {
|
||||
ret info_at(@enum2int(kind) as usize);
|
||||
}
|
||||
|
||||
fn table_count(): usize {
|
||||
ret 20;
|
||||
}
|
||||
|
||||
fn strip_at(name: ByteView): ByteView {
|
||||
if name.len > 0 && name.ptr[0] == '@' {
|
||||
match ByteView.slice(name, 1, name.len) {
|
||||
.Ok(rest) => { ret rest; },
|
||||
.Err(error) => { ret name; },
|
||||
}
|
||||
}
|
||||
ret name;
|
||||
}
|
||||
|
||||
// 按名查找 CALL 形态的内建;忽略前导 '@'。
|
||||
fn lookup_call(name: ByteView): Intrin {
|
||||
var want = strip_at(name);
|
||||
var i: usize = 1;
|
||||
while i < table_count() {
|
||||
var d = info_at(i);
|
||||
if form_is(d.form, .Call) {
|
||||
var dn = strip_at(d.name);
|
||||
if ByteView.eq(dn, want) { ret d.kind; }
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
ret .None;
|
||||
}
|
||||
|
||||
// 按接收者类型 + 字段名查找 FIELD 形态内建。
|
||||
fn lookup_field(recv: LangKind, field: ByteView): Intrin {
|
||||
if ByteView.eq(field, ByteView.from_slice("len")) {
|
||||
if kind_is(recv, .Array) || kind_is(recv, .Slice) { ret .Len; }
|
||||
}
|
||||
ret .None;
|
||||
}
|
||||
|
||||
fn is_int(e: *TypeEntry): bool {
|
||||
match e.node {
|
||||
.Int(x) => { ret true; },
|
||||
_ => { ret false; },
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn is_float(e: *TypeEntry): bool {
|
||||
match e.node {
|
||||
.Float(x) => { ret true; },
|
||||
_ => { ret false; },
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn is_bool(e: *TypeEntry): bool {
|
||||
match e.node {
|
||||
.Bool => { ret true; },
|
||||
_ => { ret false; },
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn is_ptr(e: *TypeEntry): bool {
|
||||
match e.node {
|
||||
.Ptr(x) => { ret true; },
|
||||
_ => { ret false; },
|
||||
}
|
||||
ret false;
|
||||
}
|
||||
|
||||
fn int_bits(e: *TypeEntry): usize {
|
||||
match e.node {
|
||||
.Int(x) => { ret x.bits; },
|
||||
_ => { ret 0; },
|
||||
}
|
||||
ret 0;
|
||||
}
|
||||
|
||||
// `as` 的展开规则表(改 as 语义只改这里)。
|
||||
fn lookup_cast(ir: *TypeTable, ft: usize, tt: usize): Intrin {
|
||||
var f = TypeTable.node(ir, ft);
|
||||
var t = TypeTable.node(ir, tt);
|
||||
if f == null || t == null { ret .None; }
|
||||
|
||||
if is_int(f) && is_int(t) {
|
||||
var fb = int_bits(f);
|
||||
var tb = int_bits(t);
|
||||
if fb == tb { ret .BitCast; }
|
||||
if fb > tb { ret .Truncate; }
|
||||
ret .IntCast;
|
||||
}
|
||||
if is_float(f) && is_float(t) { ret .FloatCast; }
|
||||
if is_bool(f) && is_int(t) { ret .Bool2Int; }
|
||||
if is_ptr(f) && is_int(t) { ret .Ptr2Int; }
|
||||
if is_int(f) && is_ptr(t) { ret .Int2Ptr; }
|
||||
if is_ptr(f) && is_ptr(t) { ret .PtrCast; }
|
||||
ret .None;
|
||||
}
|
||||
|
||||
// ---- 测试 ----
|
||||
|
||||
fn test_info_table() {
|
||||
var d = info(.Sizeof);
|
||||
@assert(ByteView.eq(d.name, ByteView.from_slice("@sizeof")), "sizeof name");
|
||||
@assert(d.min_args == 1 && d.max_args == 1, "sizeof arity");
|
||||
@assert(form_is(d.form, .Call), "sizeof form");
|
||||
|
||||
var l = info(.Len);
|
||||
@assert(ByteView.eq(l.name, ByteView.from_slice("len")), "len name");
|
||||
@assert(form_is(l.form, .Field), "len form");
|
||||
}
|
||||
|
||||
fn test_lookup_call() {
|
||||
@assert(@enum2int(lookup_call(ByteView.from_slice("sizeof"))) == @enum2int(Intrin.Sizeof),
|
||||
"sizeof by bare name");
|
||||
@assert(@enum2int(lookup_call(ByteView.from_slice("@sizeof"))) == @enum2int(Intrin.Sizeof),
|
||||
"sizeof by @name");
|
||||
@assert(@enum2int(lookup_call(ByteView.from_slice("assert"))) == @enum2int(Intrin.Assert),
|
||||
"assert");
|
||||
@assert(@enum2int(lookup_call(ByteView.from_slice("len"))) == @enum2int(Intrin.None),
|
||||
"len is field, not call");
|
||||
@assert(@enum2int(lookup_call(ByteView.from_slice("nope"))) == @enum2int(Intrin.None),
|
||||
"unknown");
|
||||
}
|
||||
|
||||
fn test_lookup_field() {
|
||||
@assert(@enum2int(lookup_field(.Slice, ByteView.from_slice("len"))) ==
|
||||
@enum2int(Intrin.Len),
|
||||
"slice len");
|
||||
@assert(@enum2int(lookup_field(.Array, ByteView.from_slice("len"))) ==
|
||||
@enum2int(Intrin.Len),
|
||||
"array len");
|
||||
@assert(@enum2int(lookup_field(.Struct, ByteView.from_slice("len"))) ==
|
||||
@enum2int(Intrin.None),
|
||||
"struct len");
|
||||
@assert(@enum2int(lookup_field(.Slice, ByteView.from_slice("ptr"))) ==
|
||||
@enum2int(Intrin.None),
|
||||
"slice ptr");
|
||||
}
|
||||
|
||||
fn test_lookup_cast() {
|
||||
var ir: TypeTable = undefined;
|
||||
match TypeTable.new() {
|
||||
.Ok(v) => { ir = v; },
|
||||
.Err(error) => { @assert(false, "type table new failed"); },
|
||||
}
|
||||
defer { TypeTable.drop(&ir); }
|
||||
|
||||
var i32t = TypeTable.make_int(&ir, 32, true);
|
||||
var i64t = TypeTable.make_int(&ir, 64, true);
|
||||
var f64t = TypeTable.make_float(&ir, 64);
|
||||
var boolt = TypeTable.make_bool(&ir);
|
||||
var pt = TypeTable.make_ptr(&ir, i32t);
|
||||
|
||||
@assert(@enum2int(lookup_cast(&ir, i64t, i32t)) == @enum2int(Intrin.Truncate),
|
||||
"truncate");
|
||||
@assert(@enum2int(lookup_cast(&ir, i32t, i64t)) == @enum2int(Intrin.IntCast), "int cast");
|
||||
@assert(@enum2int(lookup_cast(&ir, i32t, i32t)) == @enum2int(Intrin.BitCast), "bit cast");
|
||||
@assert(@enum2int(lookup_cast(&ir, f64t, f64t)) == @enum2int(Intrin.FloatCast),
|
||||
"float cast");
|
||||
@assert(@enum2int(lookup_cast(&ir, boolt, i32t)) == @enum2int(Intrin.Bool2Int),
|
||||
"bool2int");
|
||||
@assert(@enum2int(lookup_cast(&ir, pt, i32t)) == @enum2int(Intrin.Ptr2Int), "ptr2int");
|
||||
@assert(@enum2int(lookup_cast(&ir, i32t, pt)) == @enum2int(Intrin.Int2Ptr), "int2ptr");
|
||||
@assert(@enum2int(lookup_cast(&ir, pt, pt)) == @enum2int(Intrin.PtrCast), "ptr cast");
|
||||
@assert(@enum2int(lookup_cast(&ir, i32t, f64t)) == @enum2int(Intrin.None),
|
||||
"int->float forbidden");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_info_table();
|
||||
test_lookup_call();
|
||||
test_lookup_field();
|
||||
test_lookup_cast();
|
||||
}
|
||||
Reference in new issue
Block a user