stage2 提供c后端 提交stage1的测试

This commit is contained in:
zzy committed 2026-09-20 17:56:11 +08:00
1 parent 846f441e3a
commit 51d408d524
82 files changed
+6872 -65

No files matched your search

+629
View File
@@ -0,0 +1,629 @@
/* spl_rt.h - SPL native runtime (header-only, C89-friendly)
*
* 提供 ir2c 生成代码所需的所有 `#extern(vm)` 符号,以及 SPL 基础类型别名。
* 目标:生成代码可用 C89 语法通过(不依赖 stdint/stdbool)。
*/
#ifndef __SPL_RT_H__
#define __SPL_RT_H__
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* 语义清晰的 inline:C99 用 static inline,GNU 用 __inline__,C89 退化为 static */
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define SPL_INLINE static inline
#elif defined(__GNUC__) || defined(__clang__)
#define SPL_INLINE static __inline__
#else
#define SPL_INLINE static
#endif
/* ---- SPL 基础类型别名 ---- */
typedef unsigned char u8;
typedef signed char i8;
typedef unsigned short u16;
typedef signed short i16;
typedef unsigned int u32;
typedef signed int i32;
typedef unsigned long long u64;
typedef signed long long i64;
typedef u64 usize;
typedef i64 isize;
/* 注:不定义 bool/true/false,避免与 C23 关键字冲突;生成代码用 u8 表示布尔。 */
/* ---- panic / trap ---- */
SPL_INLINE void spl_panic(const char *msg) {
fprintf(stderr, "%s\n", msg ? msg : "panic");
exit(1);
}
SPL_INLINE void spl_trap(void) { abort(); }
/* ---- mem ---- */
SPL_INLINE void *vm_alloc(u64 sz) {
if (sz == 0)
return NULL;
return malloc((size_t)sz);
}
SPL_INLINE void vm_free(void *p) {
if (p)
free(p);
}
SPL_INLINE void *vm_realloc(void *p, u64 sz) {
if (!p)
return vm_alloc(sz);
if (sz == 0) {
free(p);
return NULL;
}
return realloc(p, (size_t)sz);
}
SPL_INLINE void *vm_memcpy(void *dst, const void *src, u64 n) {
if (n)
memcpy(dst, src, (size_t)n);
return dst;
}
SPL_INLINE void *vm_memmove(void *dst, const void *src, u64 n) {
if (n)
memmove(dst, src, (size_t)n);
return dst;
}
SPL_INLINE i64 vm_memcmp(const void *a, const void *b, u64 n) {
if (n == 0)
return 0;
return (i64)memcmp(a, b, (size_t)n);
}
SPL_INLINE i32 vm_bytes_eq(const void *a, u64 alen, const void *b, u64 blen) {
if (alen != blen)
return 0;
if (alen == 0)
return 1;
if (!a || !b)
return 0;
return memcmp(a, b, (size_t)alen) == 0;
}
/* ---- Vec ---- */
typedef struct {
usize raw;
usize data;
usize len;
usize cap;
usize elem_size;
usize elem_align;
} spl_vec_t;
SPL_INLINE int spl_vec_is_valid(const spl_vec_t *v) {
usize a;
if (v->elem_size == 0)
return 0;
a = v->elem_align;
if (a == 0 || (a & (a - 1)) != 0)
return 0;
if (v->len > v->cap)
return 0;
if (v->cap == 0)
return v->raw == 0 && v->data == 0 && v->len == 0;
if (v->raw == 0 || v->data == 0)
return 0;
return (v->data & (a - 1)) == 0;
}
SPL_INLINE int spl_align_ok(usize a) { return a != 0 && (a & (a - 1)) == 0; }
SPL_INLINE void spl_grow(usize current, usize need, usize *out) {
usize cap = current < 8 ? 8 : current;
usize limit = ~(usize)0;
while (cap < need) {
if (cap > limit / 2) {
cap = need;
break;
}
cap = cap * 2;
}
*out = cap;
}
SPL_INLINE int spl_vec_allocate(spl_vec_t *out, usize capacity, usize elem_size, usize elem_align) {
usize bytes, mask, addr;
void *raw;
if (elem_size == 0)
return 1;
if (!spl_align_ok(elem_align))
return 4;
out->raw = 0;
out->data = 0;
out->len = 0;
out->cap = 0;
out->elem_size = elem_size;
out->elem_align = elem_align;
if (capacity == 0)
return 0;
if (capacity > ~(usize)0 / elem_size)
return 3;
bytes = capacity * elem_size;
mask = elem_align - 1;
if (bytes > ~(usize)0 - mask)
return 3;
raw = malloc(bytes + mask);
if (!raw)
return 3;
addr = (usize)raw;
if (addr > ~(usize)0 - mask) {
free(raw);
return 3;
}
out->raw = addr;
out->data = (addr + mask) & ~mask;
out->cap = capacity;
return 0;
}
SPL_INLINE int spl_vec_reserve_raw(spl_vec_t *v, usize need) {
usize new_cap = 0, used = 0, old;
spl_vec_t fresh;
int rc;
if (need <= v->cap)
return 0;
spl_grow(v->cap, need, &new_cap);
rc = spl_vec_allocate(&fresh, new_cap, v->elem_size, v->elem_align);
if (rc)
return rc;
if (v->len != 0) {
if (v->len > ~(usize)0 / v->elem_size) {
free((void *)fresh.raw);
return 3;
}
used = v->len * v->elem_size;
}
if (used)
memcpy((void *)fresh.data, (void *)v->data, used);
fresh.len = v->len;
old = v->raw;
*v = fresh;
if (old)
free((void *)old);
return 0;
}
SPL_INLINE void spl_vec_release(spl_vec_t *v) {
usize es = v->elem_size, ea = v->elem_align;
if (v->raw)
free((void *)v->raw);
v->raw = 0;
v->data = 0;
v->len = 0;
v->cap = 0;
v->elem_size = es;
v->elem_align = ea;
}
SPL_INLINE i32 vm_vec_valid(void *vv) {
const spl_vec_t *v = (const spl_vec_t *)vv;
return v ? spl_vec_is_valid(v) : 0;
}
SPL_INLINE i32 vm_vec_push_raw(void *vv, const void *elem) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v || !elem)
return 0;
if (v->len < v->cap) {
memcpy((void *)(v->data + v->len * v->elem_size), elem, v->elem_size);
v->len++;
return 1;
}
return 0;
}
SPL_INLINE i32 vm_vec_get(void *vv, u64 index, void **out) {
const spl_vec_t *v = (const spl_vec_t *)vv;
if (!v || !out)
return 1;
if (!spl_vec_is_valid(v))
return 1;
if (index >= v->len)
return 2;
*out = (void *)(v->data + index * v->elem_size);
return 0;
}
SPL_INLINE i32 vm_vec_push(void *vv, const void *elem) {
spl_vec_t *v = (spl_vec_t *)vv;
int rc;
if (!v || !elem || !spl_vec_is_valid(v))
return 1;
if (v->len < v->cap) {
memcpy((void *)(v->data + v->len * v->elem_size), elem, v->elem_size);
v->len++;
return 0;
}
rc = spl_vec_reserve_raw(v, v->len + 1);
if (rc)
return rc;
memmove((void *)(v->data + v->len * v->elem_size), elem, v->elem_size);
v->len++;
return 0;
}
SPL_INLINE i32 vm_vec_allocate(void *out, u64 capacity, u64 elem_size, u64 elem_align) {
return spl_vec_allocate((spl_vec_t *)out, capacity, elem_size, elem_align);
}
SPL_INLINE i32 vm_vec_reserve_raw(void *vv, u64 need) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v)
return 1;
return spl_vec_reserve_raw(v, need);
}
SPL_INLINE i32 vm_vec_append(void *vv, const void *elems, u64 count) {
spl_vec_t *v = (spl_vec_t *)vv;
usize copy_bytes, new_len, used, source_offset = 0;
int source_inside = 0, rc;
if (!v || !spl_vec_is_valid(v))
return 1;
if (count == 0)
return 0;
if (!elems)
return 1;
if (count > ~(usize)0 / v->elem_size)
return 3;
copy_bytes = count * v->elem_size;
if (v->len > ~(usize)0 - count)
return 3;
new_len = v->len + count;
used = v->len * v->elem_size;
if (used) {
usize base = v->data;
usize source = (usize)elems;
if (source >= base && source - base < used) {
source_offset = source - base;
if (copy_bytes > used - source_offset)
return 2;
source_inside = 1;
}
}
rc = spl_vec_reserve_raw(v, new_len);
if (rc)
return rc;
if (source_inside)
elems = (const void *)(v->data + source_offset);
memmove((void *)(v->data + used), elems, copy_bytes);
v->len = new_len;
return 0;
}
SPL_INLINE i32 vm_vec_set(void *vv, u64 index, const void *elem) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v || !elem || !spl_vec_is_valid(v))
return 1;
if (index >= v->len)
return 2;
memmove((void *)(v->data + index * v->elem_size), elem, v->elem_size);
return 0;
}
SPL_INLINE i32 vm_vec_pop(void *vv, void *out) {
spl_vec_t *v = (spl_vec_t *)vv;
if (!v || !out || !spl_vec_is_valid(v))
return 1;
if (v->len == 0)
return 2;
memmove(out, (void *)(v->data + (v->len - 1) * v->elem_size), v->elem_size);
v->len--;
return 0;
}
SPL_INLINE i32 vm_vec_clone(void *outp, const void *srcp) {
spl_vec_t *out = (spl_vec_t *)outp;
const spl_vec_t *src = (const spl_vec_t *)srcp;
spl_vec_t fresh;
usize bytes;
int rc;
if (!out || !src || !spl_vec_is_valid(out) || !spl_vec_is_valid(src))
return 1;
if (out->elem_size != src->elem_size || out->elem_align != src->elem_align)
return 1;
fresh.raw = 0;
fresh.data = 0;
fresh.len = 0;
fresh.cap = 0;
fresh.elem_size = src->elem_size;
fresh.elem_align = src->elem_align;
rc = spl_vec_reserve_raw(&fresh, src->len);
if (rc)
return rc;
bytes = src->len * src->elem_size;
if (bytes)
memcpy((void *)fresh.data, (void *)src->data, bytes);
fresh.len = src->len;
if (out->raw)
free((void *)out->raw);
*out = fresh;
return 0;
}
SPL_INLINE void vm_vec_drop(void *vv) {
spl_vec_t *v = (spl_vec_t *)vv;
if (v)
spl_vec_release(v);
}
/* ---- Map ---- */
typedef struct {
spl_vec_t keys;
spl_vec_t vals;
spl_vec_t states;
usize size;
usize key_size;
usize val_size;
usize hash_kind;
} spl_map_t;
SPL_INLINE usize spl_hash_usize_value(usize value) {
usize prime = 1099511628211ull;
usize h = value;
h = (h ^ (h >> 30)) * prime;
h = h ^ (h >> 27);
h = h * prime;
h = h ^ (h >> 31);
if (h == 0)
return prime;
return h;
}
SPL_INLINE usize spl_hash_bytes(const void *data, usize len) {
const unsigned char *p = (const unsigned char *)data;
usize h = 14695981039346656037ull;
usize prime = 1099511628211ull;
usize i;
for (i = 0; i < len; i++)
h = (h ^ (usize)p[i]) * prime;
return h;
}
SPL_INLINE usize spl_map_hash(const spl_map_t *m, const void *key) {
const usize *v;
if (m->hash_kind == 0)
return spl_hash_usize_value(*(const usize *)key);
if (m->hash_kind == 2)
return 3;
v = (const usize *)key;
return spl_hash_bytes((const void *)v[0], v[1]);
}
SPL_INLINE int spl_map_eq(const spl_map_t *m, const void *a, const void *b) {
const usize *x;
const usize *y;
if (m->hash_kind == 0 || m->hash_kind == 2)
return *(const usize *)a == *(const usize *)b;
x = (const usize *)a;
y = (const usize *)b;
if (x[1] != y[1])
return 0;
if (x[1] == 0)
return 1;
return memcmp((const void *)x[0], (const void *)y[0], x[1]) == 0;
}
SPL_INLINE int spl_map_valid(const spl_map_t *m) {
if (m->key_size == 0 || m->val_size == 0)
return 0;
if (m->keys.len != m->states.len || m->vals.len != m->states.len)
return 0;
if (m->size > m->states.len)
return 0;
return 1;
}
SPL_INLINE usize spl_map_find_slot(const spl_map_t *m, const void *key) {
usize mask, i, probes;
unsigned char *st;
if (m->states.cap == 0)
return ~(usize)0;
mask = m->states.cap - 1;
i = spl_map_hash(m, key) & mask;
st = (unsigned char *)m->states.data;
probes = 0;
while (probes < m->states.cap && st[i] != 0) {
if (st[i] == 1 && spl_map_eq(m, (const void *)(m->keys.data + i * m->key_size), key))
return i;
i = (i + 1) & mask;
probes++;
}
return ~(usize)0;
}
SPL_INLINE void spl_map_place(spl_map_t *m, const void *key, const void *val) {
usize mask, i, first_deleted, probes;
unsigned char *st;
mask = m->states.cap - 1;
i = spl_map_hash(m, key) & mask;
st = (unsigned char *)m->states.data;
first_deleted = ~(usize)0;
probes = 0;
while (probes < m->states.cap && st[i] != 0) {
if (st[i] == 2 && first_deleted == ~(usize)0)
first_deleted = i;
i = (i + 1) & mask;
probes++;
}
if (first_deleted != ~(usize)0)
i = first_deleted;
memcpy((void *)(m->keys.data + i * m->key_size), key, m->key_size);
memcpy((void *)(m->vals.data + i * m->val_size), val, m->val_size);
st[i] = 1;
m->size++;
}
SPL_INLINE int spl_map_reserve(spl_map_t *m, usize need) {
usize new_cap = 0, i;
spl_map_t fresh;
int rc;
if (!spl_map_valid(m))
return 1;
if (need <= m->states.cap)
return 0;
spl_grow(m->states.cap, need, &new_cap);
fresh = *m;
fresh.keys.raw = 0;
fresh.keys.data = 0;
fresh.keys.len = 0;
fresh.keys.cap = 0;
fresh.vals.raw = 0;
fresh.vals.data = 0;
fresh.vals.len = 0;
fresh.vals.cap = 0;
fresh.states.raw = 0;
fresh.states.data = 0;
fresh.states.len = 0;
fresh.states.cap = 0;
fresh.size = 0;
rc = spl_vec_reserve_raw(&fresh.keys, new_cap);
if (rc)
goto fail;
rc = spl_vec_reserve_raw(&fresh.vals, new_cap);
if (rc)
goto fail;
rc = spl_vec_reserve_raw(&fresh.states, new_cap);
if (rc)
goto fail;
fresh.keys.len = new_cap;
fresh.vals.len = new_cap;
fresh.states.len = new_cap;
memset((void *)fresh.states.data, 0, new_cap);
for (i = 0; i < m->states.len; i++) {
if (((unsigned char *)m->states.data)[i] == 1)
spl_map_place(&fresh, (const void *)(m->keys.data + i * m->key_size),
(const void *)(m->vals.data + i * m->val_size));
}
spl_vec_release(&m->keys);
spl_vec_release(&m->vals);
spl_vec_release(&m->states);
*m = fresh;
return 0;
fail:
spl_vec_release(&fresh.keys);
spl_vec_release(&fresh.vals);
spl_vec_release(&fresh.states);
return rc;
}
SPL_INLINE i32 vm_map_valid(void *mm) {
const spl_map_t *m = (const spl_map_t *)mm;
return m ? spl_map_valid(m) : 0;
}
SPL_INLINE i32 vm_map_reserve(void *mm, u64 need) {
spl_map_t *m = (spl_map_t *)mm;
if (!m)
return 1;
return spl_map_reserve(m, need);
}
SPL_INLINE i32 vm_map_put(void *mm, const void *key, const void *val) {
spl_map_t *m = (spl_map_t *)mm;
usize existing;
if (!m || !key || !val || !spl_map_valid(m))
return 1;
existing = spl_map_find_slot(m, key);
if (existing != ~(usize)0) {
memcpy((void *)(m->vals.data + existing * m->val_size), val, m->val_size);
return 0;
}
if (m->states.cap == 0) {
int rc = spl_map_reserve(m, 8);
if (rc)
return rc;
} else {
usize next_size, scaled;
if (m->size > ~(usize)0 - 1)
return 3;
next_size = m->size + 1;
if (next_size > ~(usize)0 / 128)
return 3;
scaled = next_size * 128;
if (scaled / m->states.cap >= 70) {
int rc;
if (m->states.cap > ~(usize)0 / 2)
return 3;
rc = spl_map_reserve(m, m->states.cap * 2);
if (rc)
return rc;
}
}
spl_map_place(m, key, val);
return 0;
}
SPL_INLINE i32 vm_map_get(void *mm, const void *key, void *out) {
spl_map_t *m = (spl_map_t *)mm;
usize i;
if (!m || !key || !out || !spl_map_valid(m))
return 1;
i = spl_map_find_slot(m, key);
if (i == ~(usize)0)
return 1;
memcpy(out, (void *)(m->vals.data + i * m->val_size), m->val_size);
return 0;
}
SPL_INLINE i32 vm_map_del(void *mm, const void *key) {
spl_map_t *m = (spl_map_t *)mm;
usize i;
if (!m || !key || !spl_map_valid(m))
return 1;
i = spl_map_find_slot(m, key);
if (i == ~(usize)0)
return 1;
((unsigned char *)m->states.data)[i] = 2;
m->size--;
return 0;
}
SPL_INLINE void vm_map_clear(void *mm) {
spl_map_t *m = (spl_map_t *)mm;
if (!m)
return;
if (m->states.data && m->states.len)
memset((void *)m->states.data, 0, m->states.len);
m->size = 0;
}
SPL_INLINE void vm_map_drop(void *mm) {
spl_map_t *m = (spl_map_t *)mm;
if (!m)
return;
spl_vec_release(&m->keys);
spl_vec_release(&m->vals);
spl_vec_release(&m->states);
m->size = 0;
}
/* ---- file ---- */
SPL_INLINE void *vm_fopen(void *path, void *mode) {
return (void *)fopen((const char *)path, (const char *)mode);
}
SPL_INLINE i32 vm_fclose(void *f) { return f ? fclose((FILE *)f) : 0; }
SPL_INLINE u64 vm_fread(void *buf, u64 sz, u64 n, void *f) {
return f ? (u64)fread(buf, (size_t)sz, (size_t)n, (FILE *)f) : 0;
}
SPL_INLINE u64 vm_fwrite(void *buf, u64 sz, u64 n, void *f) {
return f ? (u64)fwrite(buf, (size_t)sz, (size_t)n, (FILE *)f) : 0;
}
SPL_INLINE u64 vm_fsize(void *f) {
long cur, end;
if (!f)
return 0;
cur = ftell((FILE *)f);
if (cur < 0)
return 0;
if (fseek((FILE *)f, 0, SEEK_END) != 0)
return 0;
end = ftell((FILE *)f);
fseek((FILE *)f, cur, SEEK_SET);
return end < 0 ? 0 : (u64)end;
}
SPL_INLINE void *vm_stdin(void) { return (void *)stdin; }
SPL_INLINE void *vm_stdout(void) { return (void *)stdout; }
SPL_INLINE void *vm_stderr(void) { return (void *)stderr; }
SPL_INLINE i32 vm_putchar(i32 c) { return fputc(c, stdout); }
SPL_INLINE i32 vm_getchar(void) { return fgetc(stdin); }
/* ---- misc ---- */
SPL_INLINE void vm_exit(i32 code) { exit(code); }
SPL_INLINE u64 vm_timestamp(u64 kind) {
time_t sec = time(NULL);
if (kind == 1)
return (u64)sec;
if (kind == 2)
return 0;
if (kind == 4)
return (u64)sec * 1000000000ull;
return 0;
}
/* ---- 内嵌 VM(comptime):实现在 spl_vm_embed.c,链接 stage0 VM ---- */
#define SPL_VM_EMBED_IMPLIMENTATION
#include "spl_vm_embed.h"
#endif /* __SPL_RT_H__ */
+109
View File
@@ -0,0 +1,109 @@
/* spl_vm_embed.h - 原生编译器内嵌 VM(comptime 执行)。
*
* 单 TU 合并式:定义 SPL_VM_EMBED_IMPLIMENTATION 后 include 本头,会把 stage0 的
* spl_mcode.c / spl_syscall.c / spl_vm.c 一并纳入当前翻译单元(不单独编译/链接)。
*/
#ifndef __SPL_VM_EMBED_H__
#define __SPL_VM_EMBED_H__
void *vm_new(void);
void vm_drop(void *vm);
int vm_load_from_buffer(void *vm, const void *buf, unsigned long long len);
void vm_push(void *vm, unsigned long long val);
int vm_call(void *vm, const char *name, unsigned long long nargs);
int vm_run(void *vm);
#ifdef SPL_VM_EMBED_IMPLIMENTATION
#include "../../stage0/spl_mcode.h"
void spl_syscall_register(spl_prog_t *prog) { (void)prog; /* stub */ }
#include "../../stage0/spl_mcode.c"
#include "../../stage0/spl_vm.c"
void *vm_new(void) {
spl_vm_t *vm = (spl_vm_t *)malloc(sizeof(spl_vm_t));
if (!vm)
return 0;
spl_vm_init(vm);
return vm;
}
void vm_drop(void *p) {
spl_vm_t *vm = (spl_vm_t *)p;
if (!vm)
return;
if (vm->prog) {
spl_prog_drop(vm->prog);
free(vm->prog);
vm->prog = 0;
}
spl_vm_drop(vm);
free(vm);
}
int vm_load_from_buffer(void *p, const void *buf, unsigned long long len) {
spl_vm_t *vm = (spl_vm_t *)p;
spl_prog_t *prog;
if (!vm || !buf)
return -1;
prog = (spl_prog_t *)malloc(sizeof(spl_prog_t));
if (!prog)
return -1;
if (spl_prog_load_from_buffer((const char *)buf, (usize)len, prog) != 0) {
free(prog);
return -1;
}
spl_syscall_register(prog);
if (spl_vm_load_prog(vm, prog) != 0) {
spl_prog_drop(prog);
free(prog);
return -1;
}
return 0;
}
void vm_push(void *p, unsigned long long val) {
spl_vm_t *vm = (spl_vm_t *)p;
if (!vm)
return;
if (vm->sp >= vm->config.max_stack_depth)
return;
vm->stacks.data[vm->sp++] = (spl_vm_val_t)val;
}
int vm_call(void *p, const char *name, unsigned long long nargs) {
spl_vm_t *vm = (spl_vm_t *)p;
spl_vm_func_t *func;
if (!vm || !name)
return -1;
func = spl_prog_get_func(vm->prog, name);
if (!func)
return -1;
if (vm->cp >= vm->config.max_call_depth)
return -1;
/* 入口调用:ip=-1 作 sentinel;实参由 vm_push 压栈。 */
vm->ip = (usize)-1;
vm->cp = 0;
vm->fp = 0;
vm->frames.data[0].saved_sp = vm->sp - (usize)nargs;
vm->frames.data[0].saved_fp = vm->fp;
vm->frames.data[0].saved_ip = vm->ip;
vm->frames.data[0].nargs = (spl_vm_val_t)nargs;
vm->cp = 1;
vm->ip = (usize)func->address;
vm->fp = vm->sp - (usize)nargs;
return 0;
}
int vm_run(void *p) {
spl_vm_t *vm = (spl_vm_t *)p;
if (!vm)
return -1;
spl_vm_run_until(vm, 0);
return (int)vm->exit_code;
}
#endif /* SPL_VM_EMBED_IMPLIMENTATION */
#endif /* __SPL_VM_EMBED_H__ */
+1 -1
View File
@@ -5,7 +5,7 @@ type spl_vm_val_t = u64; // usize
#extern(vm) fn vm_drop(vm: *any): void;
#extern(vm) fn vm_load(vm: *any, fpath: *u8): void;
#extern(vm) fn vm_load_from_buffer(vm: *any, buffer: []u8): void;
#extern(vm) fn vm_load_from_buffer(vm: *any, buf: *any, len: usize): i32;
#extern(vm) fn vm_push(vm: *any, val: spl_vm_val_t): void;
// TODO