Files

222 lines
8.9 KiB
C

/* spl_mcode.h - SPL VM Machine Code: instruction set and binary format
*/
#ifndef __SPL_MCODE_H__
#define __SPL_MCODE_H__
#include "include/core_map.h"
#include "include/core_vec.h"
#include <stddef.h>
#include <stdint.h>
#ifndef SPL_USIZE_TYPEDEF
#define SPL_USIZE_TYPEDEF
typedef uintptr_t usize;
#endif
#ifndef SPL_ISIZE_TYPEDEF
#define SPL_ISIZE_TYPEDEF
typedef intptr_t isize;
#endif
typedef enum {
SPL_VOID,
SPL_BOOL,
SPL_I8,
SPL_U8,
SPL_I16,
SPL_U16,
SPL_I32,
SPL_U32,
SPL_I64,
SPL_U64,
SPL_ISIZE,
SPL_USIZE,
SPL_F32,
SPL_F64,
SPL_PTR,
SPL_TYPE_COUNT,
} spl_vm_kind_t;
/* clang-format off */
#define SPL_OPCODES(X) \
/* opcode, name, argc, pop, push, desc */ \
X(SPL_ERROR, "error", 0, 0, 0, "invalid opcode / internal error") \
/* 栈操作 */ \
X(SPL_PUSH, "push", 1, 0, 1, "push immediate") \
X(SPL_DUP, "dup", 0, 0, 1, "duplicate top of stack") \
X(SPL_DROP, "drop", 0, 1, 0, "discard top of stack") \
X(SPL_SWAP, "swap", 0, 2, 2, "swap top two elements") \
X(SPL_PICK, "pick", 1, 0, 1, "push copy of stack[imm] (0=TOS)") \
X(SPL_ROT, "rot", 0, 3, 3, "rotate top three (a b c -- b c a)") \
/* 算术 */ \
X(SPL_ADD, "add", 0, 2, 1, "integer addition") \
X(SPL_SUB, "sub", 0, 2, 1, "integer subtraction") \
X(SPL_MUL, "mul", 0, 2, 1, "integer multiplication") \
X(SPL_DIV_S, "div_s", 0, 2, 1, "signed division") \
X(SPL_DIV_U, "div_u", 0, 2, 1, "unsigned division") \
X(SPL_REM_S, "rem_s", 0, 2, 1, "signed remainder") \
X(SPL_REM_U, "rem_u", 0, 2, 1, "unsigned remainder") \
X(SPL_NEG, "neg", 0, 1, 1, "two's complement negation") \
/* 位运算 */ \
X(SPL_AND, "and", 0, 2, 1, "bitwise AND") \
X(SPL_OR, "or", 0, 2, 1, "bitwise OR") \
X(SPL_XOR, "xor", 0, 2, 1, "bitwise XOR") \
X(SPL_NOT, "not", 0, 1, 1, "bitwise NOT") \
X(SPL_SHL, "shl", 0, 2, 1, "left shift") \
X(SPL_SHR_U, "shr_u", 0, 2, 1, "logical right shift (zero-fill)") \
X(SPL_SHR_S, "shr_s", 0, 2, 1, "arithmetic right shift (sign-fill)") \
/* 比较 */ \
X(SPL_EQ, "eq", 0, 2, 1, "equal") \
X(SPL_NE, "ne", 0, 2, 1, "not equal") \
X(SPL_SLT, "slt", 0, 2, 1, "signed less than") \
X(SPL_SLE, "sle", 0, 2, 1, "signed less or equal") \
X(SPL_ULT, "ult", 0, 2, 1, "unsigned less than") \
X(SPL_ULE, "ule", 0, 2, 1, "unsigned less or equal") \
X(SPL_SGT, "sgt", 0, 2, 1, "signed greater than") \
X(SPL_SGE, "sge", 0, 2, 1, "signed greater or equal") \
X(SPL_UGT, "ugt", 0, 2, 1, "unsigned greater than") \
X(SPL_UGE, "uge", 0, 2, 1, "unsigned greater or equal") \
/* 类型转换 */ \
X(SPL_TRUNC, "trunc", 1, 1, 1, "truncate to low imm bits") \
X(SPL_SEXT, "sext", 1, 1, 1, "sign-extend from bit imm") \
X(SPL_ZEXT, "zext", 1, 1, 1, "zero-extend from bit imm") \
/* 控制流 */ \
X(SPL_JMP, "jmp", 1, 0, 0, "unconditional jump (offset isize)") \
X(SPL_BZ, "bz", 1, 1, 0, "pop; jump if zero (offset isize)") \
X(SPL_BNZ, "bnz", 1, 1, 0, "pop; jump if non-zero (offset isize)") \
X(SPL_HALT, "halt", 0, 0, 0, "stop execution") \
/* 函数调用 */ \
X(SPL_CALL, "call", 1, 0, 0, "call function pop function offset, call it") \
X(SPL_CALLI, "calli", 0, 1, 0, "indirect call: pop function address, call it") \
X(SPL_RET, "ret", 0, 0, 0, "return from function") \
/* 栈帧局部变量 */ \
X(SPL_ALLOC, "alloc", 1, 0, 0, "allocate imm zero-slots on stack") \
X(SPL_LADDR, "laddr", 1, 0, 1, "push address of local at fp + imm bytes") \
X(SPL_GADDR, "gaddr", 1, 0, 1, "push address of global at gp + imm") \
/* 间接内存访问 */ \
X(SPL_LOAD, "load", 0, 1, 1, "load sizeof(type)-bits zero-extended") \
X(SPL_STORE, "store", 0, 2, 0, "store low sizeof(type)-bits") \
X(SPL_MEMCPY, "memcpy", 0, 3, 0, "copy n bytes: pop dst, src, n (VM address space)") \
/* 原生接口 */ \
X(SPL_NCALL, "ncall", 1, 0, 1, "call native function by index") \
X(SPL_NLIB, "nlib", 1, 0, 0, "dlopen library (name idx)") \
/* 调试 */ \
X(SPL_BK, "breakpoint", 0, 0, 0, "break point when exec will stop run") \
X(SPL_DBG, "dbg", 0, 0, 0, "print VM debug info (stack, backtrace, locals)")
/* clang-format on */
typedef enum {
#define X(opcode, name, argc, pop, push, desc) opcode,
SPL_OPCODES(X)
#undef X
SPL_OPCODE_COUNT,
} spl_vm_opcode_t;
/*
* Binary format (all metadata fields spl_val_t LE):
* magic[8] = "SPLBIN\0\0"
* nfuncs, ninsns, nnatives, nstrs, ndata
* [func table] each: name_len, name(pad8), idx_of_strtab, nargs, ninsns, address
* [insns] each: opcode(2) type(2) imm(8) = 12 bytes
* [natives] each: name_len, name(pad8), idx_of_strtab
* [strtab] each: slen, str(pad8)
* [gdata] each: dsize(8), data(dsize bytes, padded to 8)
*
* === Aggregate Return ABI (sret) ===
*
* 凡返回值类型为聚合(struct / union / enum / array / shape),
* 采用调用者分配 / 被调用者填充的间接返回约定:
*
* Before CALL:
* - caller 在自己的帧里 alloca 一块 RetTy 大小的空间
* - 该空间的地址作为第 0 个实参先压栈
* - 其余实参照常从左到右压栈
* - target 地址最后压栈
* - CALL imm = 普通实参个数 + 1
*
* Callee 进入后:
* - fp+0 存放 sret 指针
* - 形参 i 位于 fp + 8*(i+1)
* - 返回值直接写入 *(fp+0),然后执行 RET void
*
* Caller 侧:
* - 调用完成后,CALL 结果槽保存 sret 指针;
* 后续对聚合值的所有读取都通过该指针进行
*/
#define SPL_BINFMT_MAGIC "SPLBIN\0\0"
// All SIR stack values are ptr-bit unsigned integers
typedef usize spl_vm_val_t;
typedef struct spl_vm_ins {
uint8_t opcode;
uint8_t type;
spl_vm_val_t imm;
} spl_vm_ins_t;
typedef VEC(spl_vm_ins_t) spl_vm_ins_vec_t;
typedef struct spl_vm_func {
char *name;
spl_vm_val_t idx_of_strtab;
spl_vm_val_t nargs;
spl_vm_val_t ninsns;
spl_vm_val_t address;
} spl_vm_func_t;
typedef VEC(spl_vm_func_t) spl_vm_func_vec_t;
/* Native function pointer type */
struct spl_vm;
typedef struct spl_vm spl_vm_t;
typedef spl_vm_val_t (*spl_vm_fn_t)(spl_vm_t *vm, int nargs, spl_vm_val_t *args);
typedef struct spl_vm_native {
char *name;
spl_vm_val_t idx_of_strtab;
spl_vm_fn_t impl_fn;
} spl_vm_native_t;
typedef VEC(spl_vm_native_t) spl_vm_native_vec_t;
typedef struct {
unsigned char *data;
usize size;
} spl_vm_gdata_t;
typedef VEC(spl_vm_gdata_t) spl_vm_data_t;
typedef VEC(const char *) spl_vm_strtab_t;
typedef MAP(const char *, const char *) spl_vm_symtab_t;
/* Opaque handle for loaded program */
typedef struct spl_prog {
spl_vm_ins_vec_t insns;
spl_vm_func_vec_t funcs;
spl_vm_native_vec_t natives;
spl_vm_data_t gdata;
spl_vm_strtab_t strtab;
spl_vm_symtab_t symtab;
char *debug; /* 文件尾部 debug 段(splc0 -g 追加的文本),无则 NULL */
usize debug_size;
} spl_prog_t;
void spl_prog_init(spl_prog_t *prog);
void spl_prog_drop(spl_prog_t *prog);
void spl_prog_dump(spl_prog_t *prog);
int spl_prog_load_from_file(const char *fname, spl_prog_t *prog);
int spl_prog_load_from_buffer(const char *buffer, usize len, spl_prog_t *prog);
int spl_prog_store_to_file(const char *fname, spl_prog_t *prog);
int spl_prog_add_instr(spl_prog_t *prog, uint8_t opcode, uint8_t type, spl_vm_val_t imm);
int spl_prog_add_data(spl_prog_t *prog, void *ptr, usize size);
int spl_prog_add_func(spl_prog_t *prog, spl_vm_func_t *func);
int spl_prog_add_native(spl_prog_t *prog, spl_vm_native_t *native);
spl_vm_func_t *spl_prog_get_func(spl_prog_t *prog, const char *name);
spl_vm_native_t *spl_prog_get_native(spl_prog_t *prog, const char *name);
/* Opcode name lookup for debugging/dumping */
const char *spl_vm_opcode_name(spl_vm_opcode_t opcode);
const char *spl_vm_type_kind_name(spl_vm_kind_t type);
void spl_vm_ins_dump(spl_vm_ins_t *ins, spl_vm_val_t addr);
#endif /* __SPL_MCODE_H__ */