1394 lines
47 KiB
C
1394 lines
47 KiB
C
/* spl_ir2vm.c IR SIR (spl_prog_t) 降级
|
||
*
|
||
* ABI 约定spl_ir2vm.h。要点:
|
||
* - 布局(C ABI)唯一来源在此文件 * - 每个产生IR 节点 = 一vreg(locals 区按类型对齐的字节块*
|
||
* - 纯值节点(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_t(struct)重名:局部重命名 */
|
||
#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 0;enum 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 usize;idx1=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; /* 聚合 */
|
||
}
|
||
}
|
||
|
||
/* 算术/比较 tag:bool I32(VM 的算术宏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)) {
|
||
/* 聚合值参数:分配 vreg(prologue 从参数区 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;
|
||
|
||
/* prologue:ALLOC + 聚合值参数 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);
|
||
}
|
||
|
||
/* 收集 native(nodes 为空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 gdata:value 节点(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 name(spl_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; }
|