Files
spl/stage1/spl_emit.c
2026-07-20 12:10:55 +08:00

204 lines
7.4 KiB
C

/* spl_emit.c — IR emission: frame allocator + Layer 1/2 ops */
#include "spl_emit.h"
#include "spl_type.h"
#include <string.h>
/* ============================================================
* Lifecycle
* ============================================================ */
void spl_emit_init(spl_emit_t *e, spl_prog_t *prog) {
memset(e, 0, sizeof(*e));
e->prog = prog;
vec_init(e->call_fixups);
vec_init(e->call_fixup_funcs);
}
void spl_emit_drop(spl_emit_t *e) {
if (!e)
return;
vec_free(e->call_fixups);
vec_free(e->call_fixup_funcs);
}
/* ============================================================
* Frame allocator — non-inline
* ============================================================ */
int fa_alloc_type(spl_frame_alloc_t *fa, spl_type_ctx_t *tctx, int type_idx) {
return fa_alloc(fa, spl_type_size(tctx, type_idx));
}
static spl_val_t emit_raw(spl_emit_t *e, uint16_t opcode, uint16_t type,
spl_val_t imm) {
return spl_prog_emit(e->prog, opcode, type, imm);
}
/* ============================================================
* Layer 1 — single-instruction semantic wrappers
* ============================================================ */
void emit_drop(spl_emit_t *e) { emit_raw(e, SPL_DROP, SPL_VOID, 0); }
void emit_dup(spl_emit_t *e) { emit_raw(e, SPL_DUP, SPL_VOID, 0); }
void emit_swap(spl_emit_t *e) { emit_raw(e, SPL_SWAP, SPL_VOID, 0); }
void emit_rot(spl_emit_t *e) { emit_raw(e, SPL_ROT, SPL_VOID, 0); }
void emit_pick(spl_emit_t *e, int n) { emit_raw(e, SPL_PICK, SPL_VOID, n); }
void emit_push_i32(spl_emit_t *e, int v) { emit_raw(e, SPL_PUSH, SPL_I32, (spl_val_t)v); }
void emit_push_usize(spl_emit_t *e, usize v) {
emit_raw(e, SPL_PUSH, SPL_USIZE, (spl_val_t)v);
}
void emit_push_u64(spl_emit_t *e, uint64_t v) {
emit_raw(e, SPL_PUSH, SPL_U64, (spl_val_t)v);
}
void emit_push_f64(spl_emit_t *e, uint64_t v) {
emit_raw(e, SPL_PUSH, SPL_F64, (spl_val_t)v);
}
void emit_push_ptr(spl_emit_t *e, spl_val_t v) { emit_raw(e, SPL_PUSH, SPL_PTR, v); }
void emit_push_type(spl_emit_t *e, uint16_t bt, spl_val_t v) {
emit_raw(e, SPL_PUSH, bt, v);
}
void emit_load_ptr(spl_emit_t *e) { emit_raw(e, SPL_LOAD, SPL_PTR, 0); }
void emit_load_usize(spl_emit_t *e) { emit_raw(e, SPL_LOAD, SPL_USIZE, 0); }
void emit_load_type(spl_emit_t *e, uint16_t bt) { emit_raw(e, SPL_LOAD, bt, 0); }
void emit_store_i32(spl_emit_t *e) { emit_raw(e, SPL_STORE, SPL_I32, 0); }
void emit_store_ptr(spl_emit_t *e) { emit_raw(e, SPL_STORE, SPL_PTR, 0); }
void emit_store_usize(spl_emit_t *e) { emit_raw(e, SPL_STORE, SPL_USIZE, 0); }
void emit_store_type(spl_emit_t *e, uint16_t bt) { emit_raw(e, SPL_STORE, bt, 0); }
void emit_add_usize(spl_emit_t *e) { emit_raw(e, SPL_ADD, SPL_USIZE, 0); }
void emit_add_u64(spl_emit_t *e) { emit_raw(e, SPL_ADD, SPL_U64, 0); }
void emit_mul_u64(spl_emit_t *e) { emit_raw(e, SPL_MUL, SPL_U64, 0); }
void emit_sub_usize(spl_emit_t *e) { emit_raw(e, SPL_SUB, SPL_USIZE, 0); }
void emit_ult_usize(spl_emit_t *e) { emit_raw(e, SPL_ULT, SPL_USIZE, 0); }
void emit_jmp(spl_emit_t *e, spl_val_t offset) { emit_raw(e, SPL_JMP, SPL_VOID, offset); }
spl_val_t emit_jmp_here(spl_emit_t *e) { return emit_raw(e, SPL_JMP, SPL_VOID, 0); }
spl_val_t emit_bz_here(spl_emit_t *e) { return emit_raw(e, SPL_BZ, SPL_VOID, 0); }
spl_val_t emit_bnz_here(spl_emit_t *e) { return emit_raw(e, SPL_BNZ, SPL_VOID, 0); }
void emit_patch(spl_emit_t *e, spl_val_t addr, spl_val_t target) {
if (addr < vec_size(e->prog->insns))
vec_at(e->prog->insns, addr).imm = target;
}
void emit_patch_here(spl_emit_t *e, spl_val_t addr) {
spl_val_t here = vec_size(e->prog->insns);
emit_patch(e, addr, here - addr - 1);
}
void emit_laddr(spl_emit_t *e, int offset) { emit_raw(e, SPL_LADDR, SPL_PTR, offset); }
void emit_gaddr(spl_emit_t *e, int idx) { emit_raw(e, SPL_GADDR, SPL_PTR, idx); }
void emit_call(spl_emit_t *e, int nargs) { emit_raw(e, SPL_CALL, SPL_VOID, nargs); }
void emit_ncall(spl_emit_t *e, int nargs) {
emit_raw(e, SPL_NCALL, SPL_VOID, nargs);
}
void emit_alloc(spl_emit_t *e, int slots) { emit_raw(e, SPL_ALLOC, SPL_VOID, slots); }
void emit_binop(spl_emit_t *e, uint16_t op, uint16_t bt) { emit_raw(e, op, bt, 0); }
void emit_dbg_void(spl_emit_t *e) { emit_raw(e, SPL_DBG, SPL_VOID, 0); }
void emit_dbg_usize(spl_emit_t *e) { emit_raw(e, SPL_DBG, SPL_USIZE, 0); }
/* ============================================================
* Layer 2 — semantic-level helpers
* ============================================================ */
void emit_frame_copy(spl_emit_t *e, int dest_offset, usize nslots) {
for (usize i = 0; i < nslots; i++) {
if (i < nslots - 1)
emit_dup(e);
if (i > 0) {
emit_push_usize(e, i * sizeof(spl_val_t));
emit_add_usize(e);
}
emit_load_ptr(e);
emit_laddr(e, dest_offset + (int)(i * sizeof(spl_val_t)));
emit_swap(e);
emit_store_ptr(e);
}
}
void emit_copy_addr_to_addr(spl_emit_t *e, usize nslots, int depth) {
for (usize i = 0; i < nslots; i++) {
emit_dup(e);
if (i > 0) {
emit_push_usize(e, i * sizeof(spl_val_t));
emit_add_usize(e);
}
emit_load_ptr(e);
emit_pick(e, 2 + depth);
if (i > 0) {
emit_push_usize(e, i * sizeof(spl_val_t));
emit_add_usize(e);
}
emit_swap(e);
emit_store_ptr(e);
}
emit_drop(e);
emit_drop(e);
}
void emit_load_to_var(spl_emit_t *e, spl_type_ctx_t *tctx, int ptr_slot_offset,
usize byte_offset, int data_type_idx, int var_offset) {
emit_laddr(e, ptr_slot_offset);
emit_load_ptr(e);
emit_ptr_add(e, byte_offset);
if (data_type_idx >= 0 && !spl_type_is_scalar(tctx, data_type_idx) &&
spl_type_size(tctx, data_type_idx) > sizeof(spl_val_t)) {
emit_frame_copy(e, var_offset, spl_type_slot_count(tctx, data_type_idx));
} else {
uint16_t bt = spl_type_emit_type(tctx, data_type_idx);
emit_load_type(e, bt);
emit_laddr(e, var_offset);
emit_swap(e);
emit_store_type(e, bt);
}
}
void emit_store_to_laddr(spl_emit_t *e, int offset, uint16_t type) {
emit_laddr(e, offset);
emit_swap(e);
emit_store_type(e, type);
}
void emit_ptr_add(spl_emit_t *e, usize byte_off) {
if (byte_off > 0) {
emit_push_usize(e, byte_off);
emit_add_usize(e);
}
}
spl_val_t emit_call_with_fixup(spl_emit_t *e, int nargs, int func_idx) {
spl_val_t fixup_addr = emit_raw(e, SPL_PUSH, SPL_PTR, 0);
emit_call(e, nargs);
vec_push(e->call_fixups, fixup_addr);
vec_push(e->call_fixup_funcs, func_idx);
return fixup_addr;
}
void emit_return(spl_emit_t *e, spl_type_ctx_t *tctx, int ret_type_idx) {
if (spl_type_needs_multi_slot(tctx, ret_type_idx)) {
emit_laddr(e, (int)sizeof(spl_val_t));
emit_raw(e, SPL_RET, SPL_PTR, 0);
} else {
uint16_t rt = spl_type_emit_type(tctx, ret_type_idx);
emit_raw(e, SPL_RET, rt, 0);
}
}
void emit_patch_call_fixups(spl_emit_t *e, spl_prog_t *prog) {
for (usize i = 0; i < vec_size(e->call_fixups); i++) {
spl_val_t insn_idx = vec_at(e->call_fixups, i);
int pfi = vec_at(e->call_fixup_funcs, i);
if (pfi >= 0 && pfi < (int)vec_size(prog->funcs)) {
spl_val_t addr = vec_at(prog->funcs, pfi).address;
vec_at(prog->insns, insn_idx).imm = addr;
}
}
}