Files
spl/stage1/spl_ir2vm.c

1394 lines
47 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* spl_ir2vm.c IR SIR (spl_prog_t) 降级
*
* ABI 约定spl_ir2vm.h。要点
* - 布局C ABI唯一来源在此文件 * - 每个产生IR 节点 = 一vreglocals 区按类型对齐的字节块*
* - 纯值节点type.const / gdata.addr / mem.alloca / sizeof 折叠 / param * 不落 vreg引用处重算
* * - 聚合= 字节块整体搬运NCALL vm_memcpy * - 聚合返回sret隐*T 参数,最后一个) * -
* 两遍发射先发指令记label→地址回JMP/BZ/BNZ全部函 * 生成后回const_fnref 的函数地址 */
#include "spl_ir2vm.h"
/* VM 枚举 spl_type_t stage1 spl_type_tstruct重名局部重命名 */
#define spl_type_t spl_vm_tag_t
#include "../stage0/spl_mcode.h"
#undef spl_type_t
#include "../stage0/include/core_vec.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static spl_type_node_t *tn(const spl_type_t *ty, spl_type_id_t tid) {
return spl_type_node((spl_type_t *)ty, tid);
}
static spl_type_id_t under(const spl_type_t *ty, spl_type_id_t tid) {
spl_type_node_t *t = tn(ty, tid);
return (t && t->kind == SPL_TYPE_ID) ? t->type_id : tid;
}
static usize align_up(usize v, usize a) { return (v + a - 1) & ~(a - 1); }
static int is_agg(const spl_type_t *ty, spl_type_id_t tid) {
spl_type_node_t *t = tn(ty, under(ty, tid));
return t &&
(t->kind == SPL_TYPE_STRUCT || t->kind == SPL_TYPE_UNION || t->kind == SPL_TYPE_ENUM ||
t->kind == SPL_TYPE_SLICE || t->kind == SPL_TYPE_RANGE || t->kind == SPL_TYPE_ARRAY);
}
static usize type_align(const spl_type_t *ty, spl_type_id_t tid) {
spl_type_node_t *t = tn(ty, under(ty, tid));
if (!t)
return 1;
switch (t->kind) {
case SPL_TYPE_VOID:
case SPL_TYPE_BOOL:
return 1;
case SPL_TYPE_INT:
return t->int_type.bits / 8;
case SPL_TYPE_FLOAT:
return t->float_type.bits / 8;
case SPL_TYPE_PTR:
case SPL_TYPE_FN:
case SPL_TYPE_SLICE:
case SPL_TYPE_RANGE:
case SPL_TYPE_ENUM:
return sizeof(usize);
case SPL_TYPE_ARRAY:
return type_align(ty, t->array_type.element);
case SPL_TYPE_STRUCT:
case SPL_TYPE_UNION: {
usize a = 1;
for (usize i = 0; i < t->agg_field_types.size; i++) {
usize fa = type_align(ty, t->agg_field_types.data[i]);
if (fa > a)
a = fa;
}
return a;
}
default:
return 1;
}
}
static usize type_size(const spl_type_t *ty, spl_type_id_t tid) {
spl_type_node_t *t = tn(ty, under(ty, tid));
if (!t)
return 0;
switch (t->kind) {
case SPL_TYPE_VOID:
return 0;
case SPL_TYPE_BOOL:
case SPL_TYPE_INT:
return t->kind == SPL_TYPE_BOOL ? 1 : t->int_type.bits / 8;
case SPL_TYPE_FLOAT:
return t->float_type.bits / 8;
case SPL_TYPE_PTR:
case SPL_TYPE_FN:
return sizeof(usize);
case SPL_TYPE_SLICE:
case SPL_TYPE_RANGE:
return sizeof(usize) * 2;
case SPL_TYPE_ARRAY:
return t->array_type.len * type_size(ty, t->array_type.element);
case SPL_TYPE_STRUCT: {
usize sz = 0;
for (usize i = 0; i < t->agg_field_types.size; i++) {
usize fa = type_align(ty, t->agg_field_types.data[i]);
sz = align_up(sz, fa);
sz += type_size(ty, t->agg_field_types.data[i]);
}
return align_up(sz, type_align(ty, tid)); /* 尾填*/
}
case SPL_TYPE_UNION: {
usize sz = 0;
for (usize i = 0; i < t->agg_field_types.size; i++) {
usize fs = type_size(ty, t->agg_field_types.data[i]);
if (fs > sz)
sz = fs;
}
return align_up(sz, type_align(ty, tid));
}
case SPL_TYPE_ENUM: {
usize payload = 0;
spl_type_id_t self = under(ty, tid);
for (usize i = 0; i < t->enum_type.variants.size; i++) {
spl_type_id_t v = under(ty, t->enum_type.variants.data[i]);
if (v == self)
continue;
usize vs = type_size(ty, v);
if (vs > payload)
payload = vs;
}
return align_up(sizeof(usize) + payload, sizeof(usize));
}
default:
return 0;
}
}
/* 聚合字段字节偏移struct 顺序对齐union 0enum tag=0/payload=8 * slice/range = idx*8*/
static usize field_offset(const spl_type_t *ty, spl_type_id_t agg_tid, isize idx) {
spl_type_node_t *t = tn(ty, under(ty, agg_tid));
if (!t)
return 0;
switch (t->kind) {
case SPL_TYPE_SLICE:
case SPL_TYPE_RANGE:
return (usize)idx * sizeof(usize);
case SPL_TYPE_ARRAY:
return (usize)idx * type_size(ty, t->array_type.element);
case SPL_TYPE_ENUM:
return idx <= 0 ? 0 : sizeof(usize);
case SPL_TYPE_UNION:
return 0;
case SPL_TYPE_STRUCT: {
if (idx < 0 || (usize)idx >= t->agg_field_types.size)
return 0;
usize off = 0;
for (isize i = 0; i < idx; i++) {
usize fa = type_align(ty, t->agg_field_types.data[i]);
off = align_up(off, fa);
off += type_size(ty, t->agg_field_types.data[i]);
}
return align_up(off, type_align(ty, t->agg_field_types.data[idx]));
}
default:
return 0;
}
}
/* 聚合字段类型enum idx0=tag usizeidx1=payload 首个非自身变体) */
static spl_type_id_t field_type(const spl_type_t *ty, spl_type_id_t agg_tid, isize idx) {
spl_type_node_t *t = tn(ty, under(ty, agg_tid));
if (!t)
return 0;
switch (t->kind) {
case SPL_TYPE_SLICE:
if (idx == 0)
return spl_type_ptr((spl_type_t *)ty, t->slice_element);
if (idx == 1)
return spl_type_int((spl_type_t *)ty, sizeof(usize) * 8, 0);
return 0;
case SPL_TYPE_RANGE:
return t->range_element;
case SPL_TYPE_ARRAY:
return t->array_type.element;
case SPL_TYPE_ENUM:
if (idx <= 0)
return spl_type_int((spl_type_t *)ty, sizeof(usize) * 8, 0);
{
spl_type_id_t self = under(ty, agg_tid);
for (usize i = 0; i < t->enum_type.variants.size; i++) {
spl_type_id_t v = under(ty, t->enum_type.variants.data[i]);
if (v != self)
return v;
}
}
return spl_type_int((spl_type_t *)ty, sizeof(usize) * 8, 0);
default:
if (idx < 0 || (usize)idx >= t->agg_field_types.size)
return 0;
return t->agg_field_types.data[idx];
}
}
/* IR 类型 SIR 标量 tag聚合返SPL_VOID */
static spl_vm_tag_t vm_tag(const spl_type_t *ty, spl_type_id_t tid) {
spl_type_node_t *t = tn(ty, under(ty, tid));
if (!t)
return SPL_VOID;
switch (t->kind) {
case SPL_TYPE_VOID:
return SPL_VOID;
case SPL_TYPE_BOOL:
return SPL_BOOL;
case SPL_TYPE_INT:
switch (t->int_type.bits / 8) {
case 1:
return t->int_type.is_signed ? SPL_I8 : SPL_U8;
case 2:
return t->int_type.is_signed ? SPL_I16 : SPL_U16;
case 4:
return t->int_type.is_signed ? SPL_I32 : SPL_U32;
default:
return t->int_type.is_signed ? SPL_I64 : SPL_U64;
}
case SPL_TYPE_FLOAT:
return t->float_type.bits == 32 ? SPL_F32 : SPL_F64;
case SPL_TYPE_PTR:
case SPL_TYPE_FN:
return SPL_PTR;
default:
return SPL_VOID; /* 聚合 */
}
}
/* 算术/比较 tagbool I32VM 的算术宏BOOL case值已零扩展等价 */
static spl_vm_tag_t arith_tag(const spl_type_t *ty, spl_type_id_t tid) {
spl_type_node_t *t = tn(ty, under(ty, tid));
if (t && t->kind == SPL_TYPE_BOOL)
return SPL_I32;
return vm_tag(ty, tid);
}
static int is_void(const spl_type_t *ty, spl_type_id_t tid) {
spl_type_node_t *t = tn(ty, under(ty, tid));
return t && t->kind == SPL_TYPE_VOID;
}
/* ================================================================
* 发射上下 * ================================================================ */
typedef struct {
usize insn_idx;
isize target_node; /* >=0: IR label node0: 绝对地址 */
isize abs_addr;
int is_call_pad; /* 0 = 跳转 = const_fnref PUSH 占位imm=函数地址*/
spl_ir_func_ref_t fn;
} fix_t;
typedef VEC(fix_t) fix_vec_t;
typedef struct {
spl_ir2vm_t *pub;
spl_prog_t prog;
int err;
VEC(isize) func_addr; /* IR func id SIR 地址native = -1 */
VEC(isize) native_idx; /* IR func id native 表下标native = -1 */
VEC(usize) cstr_gdata; /* cstr 去重:字符串 prog.gdata 下标 */
VEC(const char *) cstr_list;
fix_vec_t fnfixes; /* const_fnref PUSH 占位(函数地址回填*/
} ctx_t;
typedef struct {
ctx_t *c;
spl_ir_func_ref_t fid;
spl_ir_func_t *f;
spl_type_id_t ret_tid;
int sret;
usize sret_off; /* sret 参数在参数区字节偏移 */
usize param_bytes;
usize *param_off; /* 每参数偏*/
usize nparams;
usize *vreg_off; /* node ref locals 偏移 */
usize nvreg;
isize *label_addr; /* node ref 指令地址1 未定 */
usize nlabel;
usize locals_bytes;
usize temp_off; /* mem.set 计数器槽 */
usize insn_base;
fix_vec_t fixes;
} fctx_t;
static void diag(ctx_t *c, spl_ir_func_ref_t fid, spl_ir_node_ref_t ref, const char *msg) {
c->err++;
const spl_ir_t *ir = c->pub->ir;
const char *fname =
(fid && fid < ir->funcs.size && ir->funcs.data[fid].name) ? ir->funcs.data[fid].name : "?";
LOG_ERROR("ir2vm: func @%s node %zu: %s", fname, ref, msg);
}
/* ---- 指令发射 ---- */
static usize add_insn(fctx_t *fc, uint8_t opcode, uint8_t type, spl_val_t imm) {
return (usize)spl_prog_add_instr(&fc->c->prog, opcode, type, imm) - 1;
}
static void emit_push(fctx_t *fc, spl_val_t imm) { add_insn(fc, SPL_PUSH, SPL_VOID, imm); }
static void emit_load_insn(fctx_t *fc, spl_vm_tag_t tag) { add_insn(fc, SPL_LOAD, tag, 0); }
static void emit_store_insn(fctx_t *fc, spl_vm_tag_t tag) { add_insn(fc, SPL_STORE, tag, 0); }
static void emit_laddr(fctx_t *fc, usize byte_off) { add_insn(fc, SPL_LADDR, SPL_VOID, byte_off); }
static void emit_gaddr(fctx_t *fc, usize idx) { add_insn(fc, SPL_GADDR, SPL_VOID, idx); }
static void emit_arith(fctx_t *fc, spl_opcode_t op, spl_vm_tag_t tag) { add_insn(fc, op, tag, 0); }
static void emit_jmp_fix(fctx_t *fc, isize target_node, isize abs_addr) {
usize idx = add_insn(fc, SPL_JMP, SPL_VOID, 0);
fix_t fx = {idx, target_node, abs_addr, 0, 0};
vec_push(fc->fixes, fx);
}
static void emit_bnz_fix(fctx_t *fc, isize target_node, isize abs_addr) {
usize idx = add_insn(fc, SPL_BNZ, SPL_VOID, 0);
fix_t fx = {idx, target_node, abs_addr, 0, 0};
vec_push(fc->fixes, fx);
}
/* ---- native 辅助vm_memcpy ---- */
static isize native_index(ctx_t *c, const char *name) {
for (usize i = 0; i < c->prog.natives.size; i++)
if (c->prog.natives.data[i].name && strcmp(c->prog.natives.data[i].name, name) == 0)
return (isize)i;
return -1;
}
static void emit_memcpy(fctx_t *fc, usize size) {
isize ni = native_index(fc->c, "vm_memcpy");
if (ni < 0)
diag(fc->c, fc->fid, 0, "vm_memcpy native not registered");
emit_push(fc, (spl_val_t)size);
emit_push(fc, (spl_val_t)ni);
add_insn(fc, SPL_NCALL, SPL_VOID, 3);
}
/* ================================================================
* 节点信息
* ================================================================ */
static spl_ir_node_t *n_at(spl_ir_func_t *f, spl_ir_node_ref_t ref) {
if (!ref || ref >= f->nodes.size)
return NULL;
return &f->nodes.data[ref];
}
static spl_type_id_t fn_ret(const spl_type_t *ty, spl_type_id_t fn_tid) {
spl_type_node_t *t = tn(ty, under(ty, fn_tid));
return (t && t->kind == SPL_TYPE_FN) ? t->fn_type.ret : 0;
}
static spl_type_id_t node_type(const spl_ir_t *ir, const spl_type_t *ty, spl_ir_func_t *f,
spl_ir_node_ref_t ref) {
spl_ir_node_t *n = n_at(f, ref);
if (!n)
return 0;
switch (n->kind) {
case SPL_IR_TYPE_CONST:
return n->type_const.tid;
case SPL_IR_ARITH_ADD:
case SPL_IR_ARITH_SUB:
case SPL_IR_ARITH_MUL:
case SPL_IR_ARITH_DIV:
case SPL_IR_ARITH_REM:
case SPL_IR_ARITH_NEG:
case SPL_IR_ARITH_ABS:
case SPL_IR_ARITH_AND:
case SPL_IR_ARITH_OR:
case SPL_IR_ARITH_XOR:
case SPL_IR_ARITH_SHL:
case SPL_IR_ARITH_SHR:
case SPL_IR_ARITH_NOT:
return n->arith.tid;
case SPL_IR_CMP_EQ:
case SPL_IR_CMP_NE:
case SPL_IR_CMP_LT:
case SPL_IR_CMP_LE:
case SPL_IR_CMP_GT:
case SPL_IR_CMP_GE:
return spl_type_bool((spl_type_t *)ty);
case SPL_IR_CAST_TRUNC:
case SPL_IR_CAST_ZEXT:
case SPL_IR_CAST_SEXT:
case SPL_IR_CAST_FEXT:
case SPL_IR_CAST_FTRUNC:
case SPL_IR_CAST_BITCAST:
case SPL_IR_CAST_PTR2INT:
case SPL_IR_CAST_INT2PTR:
case SPL_IR_CAST_BOOL2INT:
case SPL_IR_CASE_INT2FLOAT:
case SPL_IR_CASE_FLOAT2INT:
return n->cast.to_tid;
case SPL_IR_MEM_ALLOCA:
return spl_type_ptr((spl_type_t *)ty, n->mem_alloc.tid);
case SPL_IR_MEM_LOAD:
return n->mem_load.tid;
case SPL_IR_MEM_OFFSET:
return spl_type_ptr((spl_type_t *)ty, n->mem_offset.tid);
case SPL_IR_MEM_FIELD_PTR:
return spl_type_ptr((spl_type_t *)ty, field_type(ty, n->mem_field_ptr.tid,
(isize)n->mem_field_ptr.field_idx));
case SPL_IR_MEM_GLOBAL_ALLOC: {
spl_type_id_t gt = 0;
if (ir && n->mem_global_alloc.const_node < ir->gdata.size)
gt = ir->gdata.data[n->mem_global_alloc.const_node].type_const.tid;
return spl_type_ptr((spl_type_t *)ty, gt);
}
case SPL_IR_AGG_CONSTRUCT:
return n->agg_construct.tid;
case SPL_IR_AGG_EXTRACT:
return n->agg_extract.field_tid;
case SPL_IR_AGG_INSERT:
return n->agg_insert.tid;
case SPL_IR_CONTROL_SELECT:
return n->control_select.tid;
case SPL_IR_CONTROL_CALL:
return fn_ret(ty, n->control_call.tid);
case SPL_IR_CONTROL_PARAM:
return n->control_param.tid;
case SPL_IR_CONTROL_RET:
return n->control_ret.tid;
case SPL_IR_TYPE_BITSIZEOF:
case SPL_IR_TYPE_SIZEOF:
case SPL_IR_TYPE_ALIGNOF:
case SPL_IR_TYPE_OFFSETOF:
case SPL_IR_TYPE_FIELD_COUNT:
return spl_type_int((spl_type_t *)ty, sizeof(usize) * 8, 0);
default:
return 0;
}
}
/* 是否需vreg 槽布局用。const/gaddr/param/sizeof 折叠不落 vreg
* alloca 的槽即缓冲区本体,仍需分配*/
static int needs_vreg_slot(spl_ir_func_t *f, spl_ir_node_ref_t ref) {
spl_ir_node_t *n = n_at(f, ref);
if (!n)
return 0;
switch (n->kind) {
case SPL_IR_TYPE_CONST:
case SPL_IR_MEM_GLOBAL_ALLOC:
case SPL_IR_CONTROL_PARAM:
case SPL_IR_TYPE_BITSIZEOF:
case SPL_IR_TYPE_SIZEOF:
case SPL_IR_TYPE_ALIGNOF:
case SPL_IR_TYPE_OFFSETOF:
case SPL_IR_TYPE_FIELD_COUNT:
return 0;
default:
return 1;
}
}
/* ================================================================
* 发射emit_value / emit_node
* ================================================================ */
static int produces_value(spl_ir_kind_t k) {
switch (k) {
case SPL_IR_MEM_STORE:
case SPL_IR_MEM_COPY:
case SPL_IR_MEM_SET:
case SPL_IR_MEM_FENCE:
case SPL_IR_CONTROL_BR:
case SPL_IR_CONTROL_JMP:
case SPL_IR_CONTROL_RET:
case SPL_IR_CONTROL_UNREACHABLE:
case SPL_IR_CONTROL_TRAP:
case SPL_IR_DBG_BREAKPOINT:
case SPL_IR_DBG_DECLARE:
return 0;
default:
return 1;
}
}
static spl_opcode_t arith_op(spl_ir_kind_t k, int is_signed);
static int is_signed_type(const spl_type_t *ty, spl_type_id_t tid);
static void emit_value(fctx_t *fc, spl_ir_node_ref_t ref);
/* 整数字宽bool = 1其余取 int bits*/
static usize int_bits(const spl_type_t *ty, spl_type_id_t tid) {
spl_type_node_t *t = tn(ty, under(ty, tid));
if (!t)
return 0;
if (t->kind == SPL_TYPE_BOOL)
return 1;
if (t->kind == SPL_TYPE_INT)
return t->int_type.bits;
return 0;
}
static void emit_store_vreg(fctx_t *fc, spl_ir_node_ref_t ref) {
const spl_type_t *ty = fc->c->pub->type;
spl_type_id_t tid = node_type(fc->c->pub->ir, ty, fc->f, ref);
if (!tid)
return;
if (is_agg(ty, tid)) {
/* 栈顶 = 聚合值地址memcpy(栈顶 vreg(ref)) */
emit_laddr(fc, fc->param_bytes + fc->vreg_off[ref]);
add_insn(fc, SPL_SWAP, SPL_VOID, 0);
emit_memcpy(fc, type_size(ty, tid));
} else {
emit_laddr(fc, fc->param_bytes + fc->vreg_off[ref]);
add_insn(fc, SPL_SWAP, SPL_VOID, 0);
emit_store_insn(fc, vm_tag(ty, tid));
}
}
static void emit_const_push(fctx_t *fc, spl_ir_node_t *n) {
const spl_type_t *ty = fc->c->pub->type;
spl_type_id_t tid = n->type_const.tid;
spl_type_node_t *t = tn(ty, under(ty, tid));
if (!t) {
diag(fc->c, fc->fid, 0, "bad const type");
return;
}
switch (t->kind) {
case SPL_TYPE_INT:
emit_push(fc, (spl_val_t)(usize)n->type_const.int_lit);
return;
case SPL_TYPE_BOOL:
emit_push(fc, n->type_const.int_lit ? 1 : 0);
return;
case SPL_TYPE_FLOAT: {
double d = n->type_const.float_lit;
if (t->float_type.bits == 32) {
float f = (float)d;
spl_val_t b = 0;
memcpy(&b, &f, 4);
emit_push(fc, b);
} else {
spl_val_t b = 0;
memcpy(&b, &d, 8);
emit_push(fc, b);
}
return;
}
case SPL_TYPE_PTR:
if (n->type_const.cstr_lit) {
/* 字符串常量gdata 条目地址 */
isize gi = -1;
for (usize i = 0; i < fc->c->cstr_list.size; i++)
if (strcmp(fc->c->cstr_list.data[i], n->type_const.cstr_lit) == 0) {
gi = (isize)fc->c->cstr_gdata.data[i];
break;
}
if (gi < 0)
diag(fc->c, fc->fid, 0, "string const not registered");
emit_gaddr(fc, (usize)gi);
} else {
emit_push(fc, 0);
}
return;
case SPL_TYPE_FN: {
spl_ir_func_ref_t fn = n->type_const.fn;
if (fn && fn < fc->c->func_addr.size && fc->c->native_idx.data[fn] >= 0) {
diag(fc->c, fc->fid, 0, "native function used as value");
emit_push(fc, 0);
return;
}
usize idx = add_insn(fc, SPL_PUSH, SPL_VOID, 0);
fix_t fx = {idx, -1, 0, 1, fn};
vec_push(fc->c->fnfixes, fx);
return;
}
case SPL_TYPE_SLICE:
case SPL_TYPE_RANGE:
case SPL_TYPE_ARRAY:
case SPL_TYPE_STRUCT:
case SPL_TYPE_UNION:
case SPL_TYPE_ENUM:
diag(fc->c, fc->fid, 0, "aggregate const not supported");
emit_push(fc, 0);
return;
default:
diag(fc->c, fc->fid, 0, "bad const kind");
emit_push(fc, 0);
return;
}
}
static void emit_value(fctx_t *fc, spl_ir_node_ref_t ref) {
const spl_ir_t *ir = fc->c->pub->ir;
const spl_type_t *ty = fc->c->pub->type;
spl_ir_node_t *n = n_at(fc->f, ref);
if (!n) {
diag(fc->c, fc->fid, ref, "bad operand");
emit_push(fc, 0);
return;
}
switch (n->kind) {
case SPL_IR_TYPE_CONST:
emit_const_push(fc, n);
return;
case SPL_IR_MEM_GLOBAL_ALLOC: {
const spl_ir_t *ir2 = fc->c->pub->ir;
usize idx = n->mem_global_alloc.const_node;
if (idx >= ir2->gdata.size) {
diag(fc->c, fc->fid, ref, "unknown global symbol");
emit_push(fc, 0);
} else {
emit_gaddr(fc, idx);
}
return;
}
case SPL_IR_MEM_ALLOCA:
emit_laddr(fc, fc->param_bytes + fc->vreg_off[ref]);
return;
case SPL_IR_CONTROL_PARAM: {
if (is_agg(ty, n->control_param.tid)) {
/* 聚合值参数prologue 已 memcpy 到 param vreg取 vreg 地址 */
emit_laddr(fc, fc->param_bytes + fc->vreg_off[ref]);
} else {
usize po = fc->param_off ? fc->param_off[n->control_param.idx] : 0;
emit_laddr(fc, po);
emit_load_insn(fc, vm_tag(ty, n->control_param.tid));
}
return;
}
case SPL_IR_TYPE_BITSIZEOF:
emit_push(fc, type_size(ty, n->bitsizeof.tid) * 8);
return;
case SPL_IR_TYPE_SIZEOF:
emit_push(fc, type_size(ty, n->ir_sizeof.tid));
return;
case SPL_IR_TYPE_ALIGNOF:
emit_push(fc, type_align(ty, n->ir_alignof.tid));
return;
case SPL_IR_TYPE_OFFSETOF: {
spl_ir_node_t *fi = n_at(fc->f, n->ir_offsetof.field_idx);
isize idx = 0;
if (fi && fi->kind == SPL_IR_TYPE_CONST)
idx = fi->type_const.int_lit;
emit_push(fc, field_offset(ty, n->ir_offsetof.tid, idx));
return;
}
case SPL_IR_TYPE_FIELD_COUNT: {
spl_type_node_t *tt = tn(ty, under(ty, n->field_count.tid));
usize cnt = 0;
if (tt && (tt->kind == SPL_TYPE_STRUCT || tt->kind == SPL_TYPE_UNION))
cnt = tt->agg_field_types.size;
else if (tt && tt->kind == SPL_TYPE_ENUM)
cnt = tt->enum_type.variants.size;
emit_push(fc, cnt);
return;
}
default: {
spl_type_id_t tid = node_type(ir, ty, fc->f, ref);
if (!tid) {
diag(fc->c, fc->fid, ref, "value node has no type");
emit_push(fc, 0);
return;
}
if (is_agg(ty, tid)) {
emit_laddr(fc, fc->param_bytes + fc->vreg_off[ref]);
} else {
emit_laddr(fc, fc->param_bytes + fc->vreg_off[ref]);
emit_load_insn(fc, vm_tag(ty, tid));
}
return;
}
}
}
static void emit_node(fctx_t *fc, spl_ir_node_ref_t ref);
/* 记录 IR 块首 label 当前指令地址 */
static void mark_label(fctx_t *fc, spl_ir_node_ref_t ref) {
if (ref >= fc->nlabel)
return;
if (fc->label_addr[ref] < 0)
fc->label_addr[ref] = (isize)fc->c->prog.insns.size;
}
static void emit_node(fctx_t *fc, spl_ir_node_ref_t ref) {
const spl_ir_t *ir = fc->c->pub->ir;
const spl_type_t *ty = fc->c->pub->type;
spl_ir_node_t *n = n_at(fc->f, ref);
if (!n)
return;
mark_label(fc, ref);
switch (n->kind) {
case SPL_IR_TYPE_CONST:
case SPL_IR_MEM_GLOBAL_ALLOC:
case SPL_IR_MEM_ALLOCA:
case SPL_IR_CONTROL_PARAM:
case SPL_IR_TYPE_BITSIZEOF:
case SPL_IR_TYPE_SIZEOF:
case SPL_IR_TYPE_ALIGNOF:
case SPL_IR_TYPE_OFFSETOF:
case SPL_IR_TYPE_FIELD_COUNT:
return; /* 纯节点:引用时重*/
case SPL_IR_ARITH_ADD:
case SPL_IR_ARITH_SUB:
case SPL_IR_ARITH_MUL:
case SPL_IR_ARITH_DIV:
case SPL_IR_ARITH_REM:
case SPL_IR_ARITH_AND:
case SPL_IR_ARITH_OR:
case SPL_IR_ARITH_XOR:
case SPL_IR_ARITH_SHL:
case SPL_IR_ARITH_SHR: {
spl_type_id_t tid = n->arith.tid;
emit_value(fc, n->arith.left);
if (n->arith.right)
emit_value(fc, n->arith.right);
emit_arith(fc, arith_op(n->kind, is_signed_type(ty, tid)), arith_tag(ty, tid));
emit_store_vreg(fc, ref);
return;
}
case SPL_IR_ARITH_NEG: {
emit_value(fc, n->arith.left);
emit_arith(fc, SPL_NEG, arith_tag(ty, n->arith.tid));
emit_store_vreg(fc, ref);
return;
}
case SPL_IR_ARITH_NOT: {
emit_value(fc, n->arith.left);
emit_arith(fc, SPL_NOT, SPL_VOID);
emit_store_vreg(fc, ref);
return;
}
case SPL_IR_ARITH_ABS: {
spl_vm_tag_t tag = arith_tag(ty, n->arith.tid);
emit_value(fc, n->arith.left); /* x */
emit_push(fc, 0);
emit_arith(fc, SPL_SLT, tag); /* x<0 */
usize bz = add_insn(fc, SPL_BZ, SPL_VOID, 0);
emit_value(fc, n->arith.left);
emit_arith(fc, SPL_NEG, arith_tag(ty, n->arith.tid));
usize jmp = add_insn(fc, SPL_JMP, SPL_VOID, 0);
usize pos_addr = fc->c->prog.insns.size;
fc->c->prog.insns.data[bz].imm = pos_addr - (bz + 1);
emit_value(fc, n->arith.left);
usize end_addr = fc->c->prog.insns.size;
fc->c->prog.insns.data[jmp].imm = end_addr - (jmp + 1);
emit_store_vreg(fc, ref);
return;
}
case SPL_IR_CMP_EQ:
case SPL_IR_CMP_NE:
case SPL_IR_CMP_LT:
case SPL_IR_CMP_LE:
case SPL_IR_CMP_GT:
case SPL_IR_CMP_GE: {
spl_type_id_t tid = n->cmp.tid;
emit_value(fc, n->cmp.a);
emit_value(fc, n->cmp.b);
spl_opcode_t op;
switch (n->kind) {
case SPL_IR_CMP_EQ:
op = SPL_EQ;
break;
case SPL_IR_CMP_NE:
op = SPL_NE;
break;
case SPL_IR_CMP_LT:
op = is_signed_type(ty, tid) ? SPL_SLT : SPL_ULT;
break;
case SPL_IR_CMP_LE:
op = is_signed_type(ty, tid) ? SPL_SLE : SPL_ULE;
break;
case SPL_IR_CMP_GT:
op = is_signed_type(ty, tid) ? SPL_SGT : SPL_UGT;
break;
default:
op = is_signed_type(ty, tid) ? SPL_SGE : SPL_UGE;
break;
}
emit_arith(fc, op, arith_tag(ty, tid));
emit_store_vreg(fc, ref);
return;
}
case SPL_IR_CAST_TRUNC: {
usize bits = int_bits(ty, n->cast.to_tid);
emit_value(fc, n->cast.val);
add_insn(fc, SPL_TRUNC, SPL_VOID, bits);
emit_store_vreg(fc, ref);
return;
}
case SPL_IR_CAST_SEXT: {
usize bits = int_bits(ty, n->cast.from_tid);
emit_value(fc, n->cast.val);
add_insn(fc, SPL_SEXT, SPL_VOID, bits);
emit_store_vreg(fc, ref);
return;
}
case SPL_IR_CAST_ZEXT: {
usize bits = int_bits(ty, n->cast.from_tid);
emit_value(fc, n->cast.val);
add_insn(fc, SPL_ZEXT, SPL_VOID, bits);
emit_store_vreg(fc, ref);
return;
}
case SPL_IR_CAST_BITCAST:
case SPL_IR_CAST_PTR2INT:
case SPL_IR_CAST_INT2PTR:
case SPL_IR_CAST_BOOL2INT:
emit_value(fc, n->cast.val);
emit_store_vreg(fc, ref);
return;
case SPL_IR_CAST_FEXT:
case SPL_IR_CAST_FTRUNC:
case SPL_IR_CASE_INT2FLOAT:
case SPL_IR_CASE_FLOAT2INT:
diag(fc->c, fc->fid, ref, "float/int conversion not implemented in ir2vm");
emit_value(fc, n->cast.val);
emit_store_vreg(fc, ref);
return;
case SPL_IR_MEM_LOAD: {
spl_type_id_t tid = n->mem_load.tid;
if (is_agg(ty, tid)) {
emit_value(fc, n->mem_load.ptr); /* [src] */
emit_laddr(fc, fc->param_bytes + fc->vreg_off[ref]);
add_insn(fc, SPL_SWAP, SPL_VOID, 0); /* [dst, src] */
emit_memcpy(fc, type_size(ty, tid));
} else {
emit_value(fc, n->mem_load.ptr);
emit_load_insn(fc, vm_tag(ty, tid));
emit_store_vreg(fc, ref);
}
return;
}
case SPL_IR_MEM_STORE: {
spl_type_id_t tid = n->mem_store.tid;
if (is_agg(ty, tid)) {
emit_value(fc, n->mem_store.ptr); /* [dst] */
emit_value(fc, n->mem_store.val); /* [dst, src] */
emit_memcpy(fc, type_size(ty, tid));
} else {
emit_value(fc, n->mem_store.ptr);
emit_value(fc, n->mem_store.val);
emit_store_insn(fc, vm_tag(ty, tid));
}
return;
}
case SPL_IR_MEM_OFFSET: {
emit_value(fc, n->mem_offset.ptr);
emit_value(fc, n->mem_offset.offset);
emit_push(fc, type_size(ty, n->mem_offset.tid));
emit_arith(fc, SPL_MUL, SPL_USIZE);
emit_arith(fc, SPL_ADD, SPL_USIZE);
emit_store_vreg(fc, ref);
return;
}
case SPL_IR_MEM_FIELD_PTR: {
emit_value(fc, n->mem_field_ptr.agg);
emit_push(fc, field_offset(ty, n->mem_field_ptr.tid, (isize)n->mem_field_ptr.field_idx));
emit_arith(fc, SPL_ADD, SPL_USIZE);
emit_store_vreg(fc, ref);
return;
}
case SPL_IR_MEM_COPY: {
emit_value(fc, n->mem_copy.dst);
emit_value(fc, n->mem_copy.src);
emit_value(fc, n->mem_copy.size);
isize ni = native_index(fc->c, "vm_memcpy");
emit_push(fc, (spl_val_t)ni);
add_insn(fc, SPL_NCALL, SPL_VOID, 3);
return;
}
case SPL_IR_MEM_SET: {
/* 字节填充循环i=0; L: if i>=size goto E; dst[i]=val; i++; jmp L; E: */
usize temp = fc->temp_off;
emit_laddr(fc, fc->param_bytes + temp);
emit_push(fc, 0);
emit_store_insn(fc, SPL_U64);
usize l1 = fc->c->prog.insns.size;
emit_laddr(fc, fc->param_bytes + temp);
emit_load_insn(fc, SPL_U64);
emit_value(fc, n->mem_set.size);
emit_arith(fc, SPL_ULT, SPL_USIZE);
usize bz = add_insn(fc, SPL_BZ, SPL_VOID, 0);
emit_value(fc, n->mem_set.dst);
emit_laddr(fc, fc->param_bytes + temp);
emit_load_insn(fc, SPL_U64);
emit_arith(fc, SPL_ADD, SPL_USIZE);
emit_value(fc, n->mem_set.val);
emit_store_insn(fc, SPL_U8);
emit_laddr(fc, fc->param_bytes + temp);
emit_load_insn(fc, SPL_U64);
emit_push(fc, 1);
emit_arith(fc, SPL_ADD, SPL_U64);
emit_store_insn(fc, SPL_U64);
usize jmp = add_insn(fc, SPL_JMP, SPL_VOID, 0);
usize e_addr = fc->c->prog.insns.size;
fc->c->prog.insns.data[bz].imm = e_addr - (bz + 1);
fc->c->prog.insns.data[jmp].imm = l1 - (jmp + 1);
return;
}
case SPL_IR_MEM_FENCE:
return;
case SPL_IR_AGG_CONSTRUCT: {
spl_type_id_t agg_tid = n->agg_construct.tid;
for (usize i = 0; i < n->agg_construct.fields.size; i++) {
/* 字段实际类型取字段节点enum payload 因变体而异*/
spl_type_id_t ft = node_type(ir, ty, fc->f, n->agg_construct.fields.data[i]);
if (!ft)
ft = field_type(ty, agg_tid, (isize)i);
emit_laddr(fc, fc->param_bytes + fc->vreg_off[ref]);
usize foff = field_offset(ty, agg_tid, (isize)i);
if (foff) {
emit_push(fc, foff);
emit_arith(fc, SPL_ADD, SPL_USIZE);
}
emit_value(fc, n->agg_construct.fields.data[i]);
if (is_agg(ty, ft))
emit_memcpy(fc, type_size(ty, ft));
else
emit_store_insn(fc, vm_tag(ty, ft));
}
return;
}
case SPL_IR_AGG_EXTRACT: {
spl_type_id_t agg_tid = n->agg_extract.tid;
isize idx = n->agg_extract.field_idx;
spl_type_id_t ft = n->agg_extract.field_tid;
if (!ft)
ft = field_type(ty, agg_tid, idx);
emit_value(fc, n->agg_extract.val); /* [val 地址] */
usize foff = field_offset(ty, agg_tid, idx);
if (foff) {
emit_push(fc, foff);
emit_arith(fc, SPL_ADD, SPL_USIZE);
}
if (is_agg(ty, ft)) {
emit_laddr(fc, fc->param_bytes + fc->vreg_off[ref]);
add_insn(fc, SPL_SWAP, SPL_VOID, 0);
emit_memcpy(fc, type_size(ty, ft));
} else {
emit_load_insn(fc, vm_tag(ty, ft));
emit_store_vreg(fc, ref);
}
return;
}
case SPL_IR_AGG_INSERT: {
spl_type_id_t agg_tid = n->agg_insert.tid;
isize idx = n->agg_insert.field_idx;
spl_type_id_t ft = node_type(ir, ty, fc->f, n->agg_insert.field);
if (!ft)
ft = field_type(ty, agg_tid, idx);
emit_value(fc, n->agg_insert.agg);
emit_laddr(fc, fc->param_bytes + fc->vreg_off[ref]);
add_insn(fc, SPL_SWAP, SPL_VOID, 0);
emit_memcpy(fc, type_size(ty, agg_tid));
emit_laddr(fc, fc->param_bytes + fc->vreg_off[ref]);
usize foff = field_offset(ty, agg_tid, idx);
if (foff) {
emit_push(fc, foff);
emit_arith(fc, SPL_ADD, SPL_USIZE);
}
emit_value(fc, n->agg_insert.field);
if (is_agg(ty, ft))
emit_memcpy(fc, type_size(ty, ft));
else
emit_store_insn(fc, vm_tag(ty, ft));
return;
}
case SPL_IR_CONTROL_SELECT: {
emit_value(fc, n->control_select.cond);
usize bz = add_insn(fc, SPL_BZ, SPL_VOID, 0);
emit_value(fc, n->control_select.true_val);
usize jmp = add_insn(fc, SPL_JMP, SPL_VOID, 0);
usize else_addr = fc->c->prog.insns.size;
fc->c->prog.insns.data[bz].imm = else_addr - (bz + 1);
emit_value(fc, n->control_select.false_val);
usize end_addr = fc->c->prog.insns.size;
fc->c->prog.insns.data[jmp].imm = end_addr - (jmp + 1);
emit_store_vreg(fc, ref);
return;
}
case SPL_IR_CONTROL_BR: {
emit_value(fc, n->control_br.cond);
emit_bnz_fix(fc, n->control_br.true_label, -1);
emit_jmp_fix(fc, n->control_br.false_label, -1);
return;
}
case SPL_IR_CONTROL_JMP:
emit_jmp_fix(fc, n->control_jmp.label, -1);
return;
case SPL_IR_CONTROL_CALL: {
spl_type_id_t fn_tid = n->control_call.tid;
spl_type_id_t ret = fn_ret(ty, fn_tid);
int sret = is_agg(ty, ret);
/* 槽数:标量 1 槽;聚合按 C ABI 块数sret 地址 1 槽 */
usize nargs = 0;
for (usize i = 0; i < n->control_call.params.size; i++) {
spl_type_id_t pt = node_type(ir, ty, fc->f, n->control_call.params.data[i]);
if (is_agg(ty, pt))
nargs += align_up(type_size(ty, pt), 8) / 8;
else
nargs += 1;
}
if (sret)
nargs += 1;
for (usize i = 0; i < n->control_call.params.size; i++) {
spl_ir_node_ref_t pref = n->control_call.params.data[i];
spl_type_id_t pt = node_type(ir, ty, fc->f, pref);
if (is_agg(ty, pt)) {
/* 聚合值按值:逐 8 字节块压栈vreg 已 8 对齐) */
usize sz = align_up(type_size(ty, pt), 8);
for (usize j = 0; j < sz / 8; j++) {
emit_laddr(fc, fc->param_bytes + fc->vreg_off[pref] + j * 8);
emit_load_insn(fc, SPL_U64);
}
} else {
emit_value(fc, pref);
}
}
if (sret)
emit_laddr(fc, fc->param_bytes + fc->vreg_off[ref]);
spl_ir_node_t *fn = n_at(fc->f, n->control_call.func);
if (fn && fn->kind == SPL_IR_TYPE_CONST && fn->type_const.fn &&
fn->type_const.fn < fc->c->func_addr.size) {
spl_ir_func_ref_t fid = fn->type_const.fn;
if (fc->c->native_idx.data[fid] >= 0) {
emit_push(fc, (spl_val_t)fc->c->native_idx.data[fid]);
add_insn(fc, SPL_NCALL, SPL_VOID, nargs);
} else {
usize idx = add_insn(fc, SPL_PUSH, SPL_VOID, 0);
fix_t fx = {idx, -1, 0, 1, fid};
vec_push(fc->c->fnfixes, fx);
add_insn(fc, SPL_CALL, SPL_VOID, nargs);
}
} else {
/* 间接调用:栈 [args, func_addr, nargs] CALLI */
emit_value(fc, n->control_call.func);
emit_push(fc, nargs);
add_insn(fc, SPL_CALLI, SPL_VOID, 0);
}
if (ret && !is_agg(ty, ret))
emit_store_vreg(fc, ref);
return;
}
case SPL_IR_CONTROL_RET: {
spl_type_id_t tid = n->control_ret.tid;
if (is_agg(ty, tid)) {
if (n->control_ret.val) {
emit_value(fc, n->control_ret.val);
emit_laddr(fc, fc->sret_off);
emit_load_insn(fc, SPL_PTR);
add_insn(fc, SPL_SWAP, SPL_VOID, 0);
emit_memcpy(fc, type_size(ty, tid));
}
add_insn(fc, SPL_RET, SPL_VOID, 0);
} else if (!is_void(ty, tid)) {
if (n->control_ret.val)
emit_value(fc, n->control_ret.val);
else
emit_push(fc, 0); /* 空体函数返回未定义0 */
add_insn(fc, SPL_RET, vm_tag(ty, tid), 0);
} else {
add_insn(fc, SPL_RET, SPL_VOID, 0);
}
return;
}
case SPL_IR_CONTROL_UNREACHABLE:
case SPL_IR_CONTROL_TRAP:
diag(fc->c, fc->fid, ref, "control.unreachable/trap not implemented");
add_insn(fc, SPL_HALT, SPL_VOID, 0);
return;
case SPL_IR_DBG_BREAKPOINT:
add_insn(fc, SPL_BK, SPL_VOID, 0);
return;
case SPL_IR_DBG_DECLARE:
return;
default:
diag(fc->c, fc->fid, ref, "unsupported IR node");
return;
}
}
/* ---- 算术 opcode 映射 ---- */
static spl_opcode_t arith_op(spl_ir_kind_t k, int is_signed) {
switch (k) {
case SPL_IR_ARITH_ADD:
return SPL_ADD;
case SPL_IR_ARITH_SUB:
return SPL_SUB;
case SPL_IR_ARITH_MUL:
return SPL_MUL;
case SPL_IR_ARITH_DIV:
return is_signed ? SPL_DIV_S : SPL_DIV_U;
case SPL_IR_ARITH_REM:
return is_signed ? SPL_REM_S : SPL_REM_U;
case SPL_IR_ARITH_AND:
return SPL_AND;
case SPL_IR_ARITH_OR:
return SPL_OR;
case SPL_IR_ARITH_XOR:
return SPL_XOR;
case SPL_IR_ARITH_SHL:
return SPL_SHL;
case SPL_IR_ARITH_SHR:
return is_signed ? SPL_SHR_S : SPL_SHR_U;
default:
return SPL_ADD;
}
}
static int is_signed_type(const spl_type_t *ty, spl_type_id_t tid) {
spl_type_node_t *t = tn(ty, under(ty, tid));
return t && t->kind == SPL_TYPE_INT && t->int_type.is_signed;
}
/* ================================================================
* 函数生成 + 主流
* ================================================================ */
static void gdata_bytes(ctx_t *c, const spl_ir_node_t *g, unsigned char *out) {
const spl_type_t *ty = c->pub->type;
spl_type_id_t tid = g->type_const.tid;
usize sz = type_size(ty, tid);
memset(out, 0, sz);
spl_type_node_t *t = tn(ty, under(ty, tid));
if (!t)
return;
if (t->kind == SPL_TYPE_INT || t->kind == SPL_TYPE_BOOL) {
isize v = (isize)g->type_const.int_lit;
usize n = sz < sizeof(isize) ? sz : sizeof(isize);
memcpy(out, &v, n);
} else if (t->kind == SPL_TYPE_FLOAT) {
if (t->float_type.bits == 32) {
float f = (float)g->type_const.float_lit;
memcpy(out, &f, sz < 4 ? sz : 4);
} else {
double d = g->type_const.float_lit;
memcpy(out, &d, sz < 8 ? sz : 8);
}
}
}
static void gen_func(ctx_t *c, spl_ir_func_ref_t fid) {
const spl_ir_t *ir = c->pub->ir;
const spl_type_t *ty = c->pub->type;
fctx_t fc;
memset(&fc, 0, sizeof fc);
fc.c = c;
fc.fid = fid;
fc.f = &ir->funcs.data[fid];
vec_init(fc.fixes);
spl_type_id_t fn_tid = fc.f->fn_tid;
spl_type_node_t *ftn = tn(ty, under(ty, fn_tid));
usize nparams = (ftn && ftn->kind == SPL_TYPE_FN) ? ftn->fn_type.params.size : 0;
/* 参数布局C ABI标量 align8 一槽 8B聚合 align8 + size 跨多槽 */
usize off = 0;
fc.nparams = nparams;
fc.param_off = (usize *)malloc((nparams ? nparams : 1) * sizeof(usize));
for (usize i = 0; i < nparams; i++) {
spl_type_id_t pt = ftn->fn_type.params.data[i];
off = align_up(off, 8);
fc.param_off[i] = off;
if (is_agg(ty, pt))
off += align_up(type_size(ty, pt), 8);
else
off += 8;
}
fc.ret_tid = (ftn && ftn->kind == SPL_TYPE_FN) ? ftn->fn_type.ret : 0;
fc.sret = is_agg(ty, fc.ret_tid);
fc.sret_off = align_up(off, 8);
if (fc.sret)
off = fc.sret_off + 8;
fc.param_bytes = off;
/* vreg / label 布局*/
fc.nvreg = fc.f->nodes.size;
fc.vreg_off = (usize *)calloc(fc.nvreg ? fc.nvreg : 1, sizeof(usize));
fc.nlabel = fc.f->nodes.size;
fc.label_addr = (isize *)malloc((fc.nlabel ? fc.nlabel : 1) * sizeof(isize));
for (usize i = 0; i < fc.nlabel; i++)
fc.label_addr[i] = -1;
usize locals = 0;
for (usize ref = 1; ref < fc.f->nodes.size; ref++) {
spl_ir_node_t *rn = &fc.f->nodes.data[ref];
if (!produces_value(rn->kind))
continue;
spl_type_id_t tid = 0;
if (!needs_vreg_slot(fc.f, ref)) {
/* 聚合值参数:分配 vregprologue 从参数区 memcpy 进来) */
if (rn->kind == SPL_IR_CONTROL_PARAM && is_agg(ty, rn->control_param.tid))
tid = rn->control_param.tid;
else
continue;
} else {
tid = node_type(ir, ty, fc.f, ref);
/* alloca 的槽 = 缓冲区本体,大小为 mem_alloc.tid 而非 *T */
if (rn->kind == SPL_IR_MEM_ALLOCA)
tid = rn->mem_alloc.tid;
}
if (!tid)
continue;
usize sz = type_size(ty, tid);
usize al = type_align(ty, tid);
if (is_agg(ty, tid))
al = align_up(al, 8); /* 聚合 vreg 8 对齐:聚合参数逐块压栈需 8 字节边界 */
locals = align_up(locals, al);
fc.vreg_off[ref] = locals;
locals += sz;
}
fc.temp_off = align_up(locals, 8);
locals = fc.temp_off + 8; /* mem.set 计数器槽 */
fc.locals_bytes = locals;
/* prologueALLOC + 聚合值参数 memcpy参数区 → param vreg */
fc.insn_base = c->prog.insns.size;
usize k = (locals + 7) / 8;
add_insn(&fc, SPL_ALLOC, SPL_VOID, k);
for (usize ref = 1; ref < fc.f->nodes.size; ref++) {
spl_ir_node_t *rn = &fc.f->nodes.data[ref];
if (rn->kind != SPL_IR_CONTROL_PARAM)
continue;
spl_type_id_t pt = rn->control_param.tid;
if (!is_agg(ty, pt))
continue;
usize pidx = rn->control_param.idx;
emit_laddr(&fc, fc.param_off[pidx]); /* 参数区聚合起始 */
emit_laddr(&fc, fc.param_bytes + fc.vreg_off[ref]); /* param vreg */
add_insn(&fc, SPL_SWAP, SPL_VOID, 0);
emit_memcpy(&fc, type_size(ty, pt));
}
/* 节点发射 */
for (usize ref = 1; ref < fc.f->nodes.size; ref++)
emit_node(&fc, ref);
/* 末尾兜底若最后不是终止指令RET(void) */
if (c->prog.insns.size) {
spl_ins_t *last = &c->prog.insns.data[c->prog.insns.size - 1];
spl_opcode_t lop = (spl_opcode_t)last->opcode;
if (lop != SPL_RET && lop != SPL_JMP && lop != SPL_BZ && lop != SPL_BNZ &&
lop != SPL_HALT) {
add_insn(&fc, SPL_RET, SPL_VOID, 0);
}
}
/* 回填 IR label 跳转 */
for (usize i = 0; i < fc.fixes.size; i++) {
fix_t *fx = &fc.fixes.data[i];
isize addr = fx->target_node >= 0 ? fc.label_addr[fx->target_node] : fx->abs_addr;
if (addr < 0) {
diag(c, fid, 0, "unresolved branch target");
continue;
}
c->prog.insns.data[fx->insn_idx].imm = (spl_val_t)(addr - (isize)(fx->insn_idx + 1));
}
/* func */
spl_func_t sf;
memset(&sf, 0, sizeof sf);
sf.name = fc.f->name ? strdup(fc.f->name) : strdup("?");
sf.nargs = (fc.param_bytes + 7) / 8; /* C ABI 参数区槽数(含 sret */
sf.ninsns = c->prog.insns.size - fc.insn_base;
sf.address = fc.insn_base;
sf.idx_of_strtab = 0;
spl_prog_add_func(&c->prog, &sf);
free(fc.param_off);
free(fc.vreg_off);
free(fc.label_addr);
vec_free(fc.fixes);
}
int spl_ir2vm_run(spl_ir2vm_t *ctx, const char *outpath) {
ctx_t c;
memset(&c, 0, sizeof c);
c.pub = ctx;
spl_prog_init(&c.prog);
vec_init(c.func_addr);
vec_init(c.native_idx);
vec_init(c.cstr_gdata);
vec_init(c.cstr_list);
vec_init(c.fnfixes);
const spl_ir_t *ir = ctx->ir;
const spl_type_t *ty = ctx->type;
for (usize i = 0; i < ir->funcs.size; i++) {
vec_push(c.func_addr, (isize)-1);
vec_push(c.native_idx, (isize)-1);
}
/* 收集 nativenodes 为空IR func = @extern 声明*/
for (usize fid = 1; fid < ir->funcs.size; fid++) {
spl_ir_func_t *f = &ir->funcs.data[fid];
if (f->nodes.size == 0) {
spl_native_t nat;
memset(&nat, 0, sizeof nat);
nat.name = f->name ? strdup(f->name) : strdup("?");
nat.idx_of_strtab = 0;
nat.impl_fn = NULL;
c.native_idx.data[fid] = spl_prog_add_native(&c.prog, &nat) - 1;
}
}
/* 辅助 native聚合拷贝需vm_memcpy */
if (native_index(&c, "vm_memcpy") < 0) {
spl_native_t nat;
memset(&nat, 0, sizeof nat);
nat.name = strdup("vm_memcpy");
nat.impl_fn = NULL;
spl_prog_add_native(&c.prog, &nat);
}
/* 全局 var/const gdatavalue 节点type.const求值 → SIR blob */
for (usize gi = 0; gi < ir->gdata.size; gi++) {
const spl_ir_node_t *g = &ir->gdata.data[gi];
usize sz = type_size(ty, g->type_const.tid);
unsigned char *buf = (unsigned char *)malloc(sz ? sz : 1);
gdata_bytes(&c, g, buf);
spl_prog_add_data(&c.prog, buf, sz);
free(buf);
}
/* 字符串常gdata去重仅 PTR 类型const 才可能是 cstr_lit */
for (usize fid = 1; fid < ir->funcs.size; fid++) {
spl_ir_func_t *f = &ir->funcs.data[fid];
for (usize r = 1; r < f->nodes.size; r++) {
spl_ir_node_t *n = &f->nodes.data[r];
if (n->kind != SPL_IR_TYPE_CONST || !n->type_const.cstr_lit)
continue;
spl_type_node_t *ct = tn(ty, under(ty, n->type_const.tid));
if (!ct || ct->kind != SPL_TYPE_PTR)
continue;
int dup = 0;
for (usize i = 0; i < c.cstr_list.size; i++)
if (strcmp(c.cstr_list.data[i], n->type_const.cstr_lit) == 0) {
dup = 1;
break;
}
if (dup)
continue;
vec_push(c.cstr_list, n->type_const.cstr_lit);
vec_push(c.cstr_gdata, c.prog.gdata.size);
spl_prog_add_data(&c.prog, (void *)n->type_const.cstr_lit,
strlen(n->type_const.cstr_lit) + 1);
}
}
/* 生成普通函*/
for (usize fid = 1; fid < ir->funcs.size; fid++) {
if (ir->funcs.data[fid].nodes.size == 0)
continue;
c.func_addr.data[fid] = (isize)c.prog.insns.size;
gen_func(&c, fid);
}
/* 回填函数引用const_fnref 函数地址*/
for (usize i = 0; i < c.fnfixes.size; i++) {
fix_t *fx = &c.fnfixes.data[i];
isize addr = (fx->fn && fx->fn < c.func_addr.size) ? c.func_addr.data[fx->fn] : -1;
if (addr < 0) {
diag(&c, fx->fn, 0, "function reference unresolved");
continue;
}
c.prog.insns.data[fx->insn_idx].imm = (spl_val_t)addr;
}
if (!c.err && outpath)
spl_prog_store_to_file(outpath, &c.prog);
if (c.err)
fprintf(stderr, "ir2vm errors=%d\n", c.err);
/* 释放 native/func namespl_prog_drop 会释放) */
int rc = c.err;
spl_prog_drop(&c.prog);
vec_free(c.func_addr);
vec_free(c.native_idx);
vec_free(c.cstr_gdata);
vec_free(c.cstr_list);
vec_free(c.fnfixes);
return rc;
}
void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type) {
ctx->ir = ir;
ctx->type = type;
}
void spl_ir2vm_drop(spl_ir2vm_t *ctx) { (void)ctx; }
void spl_ir2vm_dump(spl_ir2vm_t *ctx) { (void)ctx; }