stage1 使用切片表达字符串而非C字符串 提供属性系统

This commit is contained in:
zzy committed 2026-09-13 22:26:41 +08:00
1 parent a64a96f9a4
commit 72ae6d6994
14 files changed
+685 -1256

No files matched your search

+174 -67
View File
@@ -68,6 +68,41 @@ static usize ir_agg_field_off(spl_ir2vm_t *ctx, spl_type_id_t tid, usize idx) {
return 0;
}
static int get_or_add_native(spl_ir2vm_t *ctx, const char *name) {
if (!name)
return -1;
for (usize i = 0; i < vec_size(ctx->prog.natives); ++i) {
spl_vm_native_t *n = &vec_at(ctx->prog.natives, i);
if (n->name && strcmp(n->name, name) == 0)
return (int)i;
}
spl_vm_native_t nat = {0};
nat.name = strdup(name);
nat.idx_of_strtab = 0;
nat.impl_fn = NULL;
vec_push(ctx->prog.natives, nat);
return (int)(vec_size(ctx->prog.natives) - 1);
}
static bool fn_check_extern(spl_ir2vm_t *ctx, spl_ir_func_t *f, const char **out_target) {
if (out_target)
*out_target = NULL;
if (!ctx->attr || !f)
return false;
for (usize i = 0; i < vec_size(f->attrs); ++i) {
spl_attr_node_t *a = spl_attr_node(ctx->attr, vec_at(f->attrs, i));
if (!a || !a->info)
continue;
if (strcmp(a->info->name, "extern") != 0)
continue;
a->consumed_mask |= (1u << SPL_ATTR_STAGE_IR);
if (out_target && vec_size(a->args) >= 1 && vec_at(a->args, 0).kind == SPL_ATTR_ARG_STR)
*out_target = vec_at(a->args, 0).value.s;
return true;
}
return false;
}
static uint8_t vm_kind_of(spl_ir2vm_t *ctx, spl_type_id_t tid) {
spl_type_node_t *tn = spl_type_node(ctx->type, tid);
if (!tn)
@@ -217,17 +252,12 @@ static usize node_data_size(spl_ir2vm_t *ctx, const spl_ir_func_t *f, const spl_
if (ir_is_aggregate(ctx, node->mem_load.tid))
return ir_type_size(ctx, node->mem_load.tid);
return 0;
case SPL_IR_DBG_PANIC:
return sizeof(spl_vm_val_t) * 4; /* TODO: fmt slice + msg slice */
case SPL_IR_CONTROL_CALL:
if (ir_is_aggregate(ctx, node->control_call.tid))
return ir_type_size(ctx, node->control_call.tid);
return 0;
case SPL_IR_TYPE_CONST: {
spl_type_node_t *tn = spl_type_node(ctx->type, node->type_const.tid);
if (tn && (tn->kind == SPL_TYPE_STRUCT || tn->kind == SPL_TYPE_ARRAY ||
tn->kind == SPL_TYPE_UNION))
return ir_type_size(ctx, node->type_const.tid);
return 0;
}
default:
return 0;
}
@@ -415,30 +445,17 @@ static void cg_const(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
return;
if (tn->kind == SPL_TYPE_FN) {
usize idx = ip_of(cg);
CG_PUSH(cg, SPL_PTR, 0);
cg_add_fix(cg, idx, FIX_FNADDR, 0, n->type_const.fn);
cg_store_slot(cg, ref, SPL_PTR);
return;
}
isize nat_idx = -1;
if (n->type_const.fn > 0)
map_get(ctx->extern_native, n->type_const.fn, &nat_idx);
if (tn->kind == SPL_TYPE_STRUCT || tn->kind == SPL_TYPE_ARRAY || tn->kind == SPL_TYPE_UNION) {
const char *bytes = (const char *)n->type_const.ptr_lit;
if (!bytes)
bytes = "";
usize len = strlen(bytes);
usize data_idx = (usize)spl_prog_add_data(&ctx->prog, (void *)bytes, len + 1);
usize base = vec_at(cg->frame.slots, ref).data_off;
usize ptr_off = ir_agg_field_off(ctx, tid, 0);
usize len_off = ir_agg_field_off(ctx, tid, 1);
CG_GADDR(cg, data_idx);
cg_store_at(cg, base + ptr_off, SPL_PTR);
CG_PUSH(cg, SPL_U64, len);
cg_store_at(cg, base + len_off, SPL_U64);
CG_LADDR(cg, base);
if (nat_idx >= 0) {
CG_PUSH(cg, SPL_U64, (spl_vm_val_t)nat_idx);
} else {
usize idx = ip_of(cg);
CG_PUSH(cg, SPL_PTR, 0);
cg_add_fix(cg, idx, FIX_FNADDR, 0, n->type_const.fn);
}
cg_store_slot(cg, ref, SPL_PTR);
return;
}
@@ -506,6 +523,21 @@ static void cg_mem(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
break;
}
case SPL_IR_MEM_GLOBAL_ALLOC: {
const spl_ir_node_t *cn = &vec_at(cg->irf->nodes, n->mem_global_alloc.const_node);
int idx = 0;
if (cn->kind == SPL_IR_TYPE_CONST && cn->type_const.ptr_lit) {
usize size = ir_type_size(ctx, cn->type_const.tid);
idx = spl_prog_add_data(&ctx->prog, cn->type_const.ptr_lit, size);
}
if (idx > 0)
emit(cg, SPL_GADDR, SPL_VOID, (spl_vm_val_t)idx);
else
CG_PUSH(cg, SPL_PTR, 0);
cg_store_slot(cg, ref, SPL_PTR);
break;
}
case SPL_IR_MEM_LOAD: {
spl_type_id_t tid = n->mem_load.tid;
if (ir_is_aggregate(ctx, tid)) {
@@ -716,43 +748,48 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
}
case SPL_IR_CONTROL_CALL: {
usize nargs = vec_size(n->control_call.params);
for (usize i = 0; i < nargs; ++i) {
spl_ir_node_ref_t pref = vec_at(n->control_call.params, i);
const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref);
spl_type_id_t ptid = ir_result_tid(pn);
uint8_t pk = vm_kind_of(ctx, ptid);
cg_load_slot(cg, pref, pk);
}
bool direct = false;
spl_ir_func_ref_t callee_ref = 0;
spl_ir_node_ref_t fref = n->control_call.func;
if (fref < vec_size(cg->irf->nodes)) {
const spl_ir_node_t *fn_node = &vec_at(cg->irf->nodes, fref);
if (fn_node->kind == SPL_IR_TYPE_CONST) {
spl_type_node_t *ftn = spl_type_node(ctx->type, fn_node->type_const.tid);
if (ftn && ftn->kind == SPL_TYPE_FN) {
usize idx = ip_of(cg);
CG_PUSH(cg, SPL_PTR, 0);
cg_add_fix(cg, idx, FIX_FNADDR, 0, fn_node->type_const.fn);
emit(cg, SPL_CALL, SPL_VOID, nargs);
direct = true;
}
}
if (fn_node->kind == SPL_IR_TYPE_CONST)
callee_ref = fn_node->type_const.fn;
}
if (!direct)
emit(cg, SPL_HALT, SPL_VOID, 0);
spl_type_id_t rtid = n->control_call.tid;
if (ir_is_aggregate(ctx, rtid)) {
cg_store_slot(cg, ref, SPL_PTR);
usize data = vec_at(cg->frame.slots, ref).data_off;
cg_copy_agg(cg, ptr_slot(vec_at(cg->frame.slots, ref).result_off), direct_data(data),
rtid);
CG_LADDR(cg, data);
cg_store_slot(cg, ref, SPL_PTR);
isize nat_idx = -1;
if (callee_ref > 0)
map_get(ctx->extern_native, callee_ref, &nat_idx);
usize nargs = vec_size(n->control_call.params);
if (nat_idx >= 0) {
for (usize i = 0; i < nargs; ++i) {
spl_ir_node_ref_t pref = vec_at(n->control_call.params, i);
const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref);
spl_type_id_t ptid = ir_result_tid(pn);
uint8_t pk = vm_kind_of(ctx, ptid);
cg_load_slot(cg, pref, pk);
}
CG_PUSH(cg, SPL_U64, (spl_vm_val_t)nat_idx);
emit(cg, SPL_NCALL, SPL_VOID, (spl_vm_val_t)nargs);
uint8_t rk = vm_kind_of(ctx, n->control_call.tid);
if (rk == SPL_VOID)
emit(cg, SPL_DROP, SPL_VOID, 0); /* NCALL 总是 push 一个结果 */
else
cg_store_slot(cg, ref, rk);
} else {
uint8_t rk = vm_kind_of(ctx, rtid);
for (usize i = 0; i < nargs; ++i) {
spl_ir_node_ref_t pref = vec_at(n->control_call.params, i);
const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref);
spl_type_id_t ptid = ir_result_tid(pn);
uint8_t pk = vm_kind_of(ctx, ptid);
cg_load_slot(cg, pref, pk);
}
cg_load_slot(cg, fref, SPL_PTR);
emit(cg, SPL_CALL, SPL_VOID, (spl_vm_val_t)nargs);
uint8_t rk = vm_kind_of(ctx, n->control_call.tid);
if (rk != SPL_VOID)
cg_store_slot(cg, ref, rk);
}
@@ -761,7 +798,7 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
case SPL_IR_CONTROL_UNREACHABLE:
case SPL_IR_CONTROL_TRAP:
emit(cg, SPL_HALT, SPL_VOID, 0);
emit(cg, SPL_HALT, SPL_VOID, 1);
break;
default:
@@ -817,9 +854,18 @@ static void cg_node(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
case SPL_IR_ARITH_NEG:
cg_unop(cg, ref, n, SPL_NEG);
break;
case SPL_IR_ARITH_NOT:
cg_unop(cg, ref, n, SPL_NOT);
case SPL_IR_ARITH_NOT: {
spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->arith.tid);
if (tn && tn->kind == SPL_TYPE_BOOL) {
cg_load_slot(cg, n->arith.left, SPL_BOOL);
CG_PUSH(cg, SPL_U8, 0);
CG_OP(cg, SPL_EQ, SPL_U8);
cg_store_slot(cg, ref, SPL_BOOL);
} else {
cg_unop(cg, ref, n, SPL_NOT);
}
break;
}
case SPL_IR_ARITH_ABS:
break;
@@ -869,6 +915,7 @@ static void cg_node(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
break;
case SPL_IR_MEM_ALLOCA:
case SPL_IR_MEM_GLOBAL_ALLOC:
case SPL_IR_MEM_LOAD:
case SPL_IR_MEM_STORE:
case SPL_IR_MEM_OFFSET:
@@ -898,6 +945,39 @@ static void cg_node(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
cg_control(cg, ref, n);
break;
case SPL_IR_DBG_PANIC: {
spl_ir2vm_t *ctx = cg->ctx;
usize data = vec_at(cg->frame.slots, ref).data_off;
int msg_idx = spl_prog_add_data(&ctx->prog, (void *)n->dbg_panic.msg, n->dbg_panic.len);
int fmt_idx = spl_prog_add_data(&ctx->prog, "%s", 2);
if (msg_idx <= 0 || fmt_idx <= 0)
break;
/* fmt slice = {ptr, len=2} 写到 data+0 */
CG_GADDR(cg, (spl_vm_val_t)fmt_idx);
cg_store_at(cg, data + 0, SPL_PTR);
CG_PUSH(cg, SPL_U64, 2);
cg_store_at(cg, data + 8, SPL_U64);
/* msg slice = {ptr, len} 写到 data+16 */
CG_GADDR(cg, (spl_vm_val_t)msg_idx);
cg_store_at(cg, data + 16, SPL_PTR);
CG_PUSH(cg, SPL_U64, n->dbg_panic.len);
cg_store_at(cg, data + 24, SPL_U64);
/* push fmt slice 指针,push msg slice 指针 */
CG_LADDR(cg, data + 0);
CG_LADDR(cg, data + 16);
/* NCALL vm_printf(2) */
int nat = get_or_add_native(ctx, "vm_printf");
CG_PUSH(cg, SPL_U64, (spl_vm_val_t)nat);
emit(cg, SPL_NCALL, SPL_VOID, 2);
emit(cg, SPL_DROP, SPL_VOID, 0); /* 丢弃返回值 */
break;
}
case SPL_IR_DBG_BREAKPOINT:
emit(cg, SPL_BK, SPL_VOID, 0);
break;
@@ -963,13 +1043,23 @@ static usize translate_function(spl_ir2vm_t *ctx, spl_ir_func_ref_t fid, fix_vec
return func_ip;
}
void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type) {
static usize spl_map_hash(usize k) { return MAP_HASH_INT(k); }
static int spl_map_cmp(usize a, usize b) { return MAP_CMP_INT(a, b); }
void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type,
const spl_attr_t *attr) {
Assert(ir != NULL && type != NULL && attr != NULL);
ctx->ir = ir;
ctx->type = type;
ctx->attr = attr;
map_init(ctx->extern_native, spl_map_hash, spl_map_cmp);
spl_prog_init(&ctx->prog);
}
void spl_ir2vm_drop(spl_ir2vm_t *ctx) { spl_prog_drop(&ctx->prog); }
void spl_ir2vm_drop(spl_ir2vm_t *ctx) {
spl_prog_drop(&ctx->prog);
map_free(ctx->extern_native);
}
int spl_ir2vm_run_func(spl_ir2vm_t *ctx, spl_ir_func_ref_t ref) {
fix_vec_t all_fixups;
@@ -984,13 +1074,30 @@ int spl_ir2vm_run(spl_ir2vm_t *ctx) {
if (n <= 1)
return 0;
/* Pass 1:扫描所有 fn,把 extern 的登记到 map 里 */
for (spl_ir_func_ref_t i = 1; i < n; ++i) {
spl_ir_func_t *irf = spl_ir_func((spl_ir_t *)ctx->ir, i);
if (!irf)
continue;
if (fn_check_extern(ctx, irf, NULL)) {
int nat_idx = get_or_add_native(ctx, irf->name);
map_put(ctx->extern_native, i, (isize)nat_idx);
}
}
/* Pass 2:翻译非 extern 的函数 */
usize *fid_ip = calloc(n, sizeof(usize));
fix_vec_t all_fixups;
vec_init(all_fixups);
for (spl_ir_func_ref_t i = 1; i < n; ++i)
for (spl_ir_func_ref_t i = 1; i < n; ++i) {
isize dummy = -1;
if (map_get(ctx->extern_native, i, &dummy))
continue;
fid_ip[i] = translate_function(ctx, i, &all_fixups);
}
/* FNADDR 回填 */
for (usize i = 0; i < vec_size(all_fixups); ++i) {
fix_t *fx = &vec_at(all_fixups, i);
if (fx->kind != FIX_FNADDR)