stage2 大量优化代码使其自举编译时间大幅缩短

This commit is contained in:
zzy committed 2026-09-20 09:33:20 +08:00
1 parent e02b0c633a
commit 846f441e3a
38 files changed
+2418 -835

No files matched your search

+2
View File
@@ -42,6 +42,8 @@ static const char *splc0_srcs[] = {
"stage1/spl_ast2ir.c", "stage1/spl_ast2ir.c",
"stage1/spl_layout.c", "stage1/spl_layout.c",
"stage1/spl_ir2vm.c", "stage1/spl_ir2vm.c",
"stage1/ir_opt.c",
"stage1/vm_opt.c",
"stage0/spl_mcode.c", "stage0/spl_mcode.c",
}; };
/* clang-format on */ /* clang-format on */
+11
View File
@@ -33,6 +33,7 @@ typedef struct {
int profile; int profile;
int profile_interval; int profile_interval;
const char *profile_out; const char *profile_out;
int stats;
const char *entry; const char *entry;
const char *path; /* file.sir */ const char *path; /* file.sir */
const char **args; /* spl 程序参数(file.sir 之后) */ const char **args; /* spl 程序参数(file.sir 之后) */
@@ -48,6 +49,7 @@ static void usage(void) {
" --trace print every instruction\n" " --trace print every instruction\n"
" --profile[=N] native sampling profiler (every N insns, default 10000)\n" " --profile[=N] native sampling profiler (every N insns, default 10000)\n"
" --profile-out <p> profile output prefix (default build/profile)\n" " --profile-out <p> profile output prefix (default build/profile)\n"
" --stats print executed instructions / call count at exit\n"
" -h, --help show help\n"); " -h, --help show help\n");
} }
@@ -72,6 +74,8 @@ static int parse_args(int argc, const char **argv, cli_opts_t *o) {
o->trace = 1; o->trace = 1;
} else if (strcmp(a, "--disasm") == 0) { } else if (strcmp(a, "--disasm") == 0) {
o->disasm = 1; o->disasm = 1;
} else if (strcmp(a, "--stats") == 0) {
o->stats = 1;
} else if (strcmp(a, "--profile") == 0) { } else if (strcmp(a, "--profile") == 0) {
o->profile = 1; o->profile = 1;
} else if (strncmp(a, "--profile=", 10) == 0) { } else if (strncmp(a, "--profile=", 10) == 0) {
@@ -656,6 +660,8 @@ int main(int argc, const char **argv) {
if (o.debug) { if (o.debug) {
fprintf(stderr, "spl_cli: debug mode on\n"); fprintf(stderr, "spl_cli: debug mode on\n");
spl_vm_set_debug(&vm, 1); spl_vm_set_debug(&vm, 1);
} else {
spl_vm_set_debug(&vm, 0);
} }
if (o.trace) { if (o.trace) {
fprintf(stderr, "spl_cli: trace mode on\n"); fprintf(stderr, "spl_cli: trace mode on\n");
@@ -710,6 +716,11 @@ int main(int argc, const char **argv) {
fprintf(stderr, "spl_cli: hit breakpoint (run with -g to debug)\n"); fprintf(stderr, "spl_cli: hit breakpoint (run with -g to debug)\n");
} }
if (o.stats) {
fprintf(stderr, "spl_cli: stats steps=%llu calls=%llu\n", (unsigned long long)vm.steps,
(unsigned long long)vm.ncalls);
}
if (o.profile) { if (o.profile) {
const char *prefix = o.profile_out ? o.profile_out : "build/profile"; const char *prefix = o.profile_out ? o.profile_out : "build/profile";
char folded[1024]; char folded[1024];
+3
View File
@@ -103,6 +103,7 @@ typedef enum {
#define X(opcode, name, argc, pop, push, desc) opcode, #define X(opcode, name, argc, pop, push, desc) opcode,
SPL_OPCODES(X) SPL_OPCODES(X)
#undef X #undef X
SPL_OPCODE_COUNT,
} spl_vm_opcode_t; } spl_vm_opcode_t;
/* /*
@@ -191,6 +192,8 @@ void spl_prog_init(spl_prog_t *prog);
void spl_prog_drop(spl_prog_t *prog); void spl_prog_drop(spl_prog_t *prog);
void spl_prog_dump(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_file(const char *fname, spl_prog_t *prog);
int spl_prog_store_to_file(const char *fname, spl_prog_t *prog); int spl_prog_store_to_file(const char *fname, spl_prog_t *prog);
+641
View File
@@ -348,6 +348,10 @@ static spl_vm_val_t vm_timestamp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
if (!_vm) if (!_vm)
return 0; return 0;
return (spl_vm_val_t)_vm->steps; return (spl_vm_val_t)_vm->steps;
case 5:
if (!_vm)
return 0;
return (spl_vm_val_t)_vm->ncalls;
case 4: case 4:
return has_time ? (spl_vm_val_t)((unsigned long long)ts.tv_sec * 1000000000ull + return has_time ? (spl_vm_val_t)((unsigned long long)ts.tv_sec * 1000000000ull +
(unsigned long long)ts.tv_nsec) (unsigned long long)ts.tv_nsec)
@@ -493,6 +497,623 @@ SYSCALL_1(vm_run, spl_vm_t *, spl_vm_run_until(a1, 0))
* prog->natives against known syscall names and hooks up impl_fn. * prog->natives against known syscall names and hooks up impl_fn.
* ================================================================= */ * ================================================================= */
/* =================================================================
* Native std containers (spike: Vec valid/push_raw/get)
*
* 布局镜像 stage2/utils/vec.spl 的 Vec:
* raw, data, len, cap, elem_size, elem_align (均为机器字)
* 结构体按值传递/复制由 SPL 负责,native 只按指针操作。
* ================================================================= */
typedef struct {
uintptr_t raw;
uintptr_t data;
uintptr_t len;
uintptr_t cap;
uintptr_t elem_size;
uintptr_t elem_align;
} spl_vec_t;
static int spl_vec_is_valid(const spl_vec_t *v) {
if (v->elem_size == 0)
return 0;
uintptr_t 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;
}
static spl_vm_val_t vm_vec_valid(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_vec_valid", 1);
const spl_vec_t *v = (const spl_vec_t *)(uintptr_t)args[0];
return (spl_vm_val_t)(v ? spl_vec_is_valid(v) : 0);
}
static spl_vm_val_t vm_vec_push_raw(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_vec_push_raw", 2);
spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0];
const void *elem = (const void *)(uintptr_t)args[1];
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;
}
/* out 接收元素指针;返回 0 成功,1 无效参数,2 越界。 */
static int spl_vec_reserve_raw(spl_vec_t *v, uintptr_t need);
static spl_vm_val_t vm_vec_push(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_vec_push", 2);
spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0];
const void *elem = (const void *)(uintptr_t)args[1];
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;
}
int 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;
}
static spl_vm_val_t vm_vec_get(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_vec_get", 3);
const spl_vec_t *v = (const spl_vec_t *)(uintptr_t)args[0];
uintptr_t index = (uintptr_t)args[1];
uintptr_t *out = (uintptr_t *)(uintptr_t)args[2];
if (!v || !out)
return 1;
if (!spl_vec_is_valid(v))
return 1;
if (index >= v->len)
return 2;
*out = v->data + index * v->elem_size;
return 0;
}
/* 错误码统一:0 ok / 1 InvalidArgument / 2 OutOfRange / 3 Overflow / 4 InvalidAlignment */
static int spl_align_ok(uintptr_t a) { return a != 0 && (a & (a - 1)) == 0; }
static int spl_grow_capacity(uintptr_t current, uintptr_t min_cap, uintptr_t need,
uintptr_t *out) {
uintptr_t cap = current < min_cap ? min_cap : current;
uintptr_t limit = ~(uintptr_t)0;
while (cap < need) {
if (cap > limit / 2) {
cap = need;
break;
}
cap = cap * 2;
}
*out = cap;
return 0;
}
static int spl_vec_allocate(spl_vec_t *out, uintptr_t capacity, uintptr_t elem_size,
uintptr_t elem_align) {
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 > ~(uintptr_t)0 / elem_size)
return 3;
uintptr_t bytes = capacity * elem_size;
uintptr_t mask = elem_align - 1;
if (bytes > ~(uintptr_t)0 - mask)
return 3;
uintptr_t total = bytes + mask;
void *raw = malloc(total);
if (!raw)
return 3;
uintptr_t addr = (uintptr_t)raw;
if (addr > ~(uintptr_t)0 - mask) {
free(raw);
return 3;
}
out->raw = addr;
out->data = (addr + mask) & ~mask;
out->cap = capacity;
return 0;
}
static spl_vm_val_t vm_vec_allocate(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_vec_allocate", 4);
spl_vec_t *out = (spl_vec_t *)(uintptr_t)args[0];
if (!out)
return 1;
return (spl_vm_val_t)spl_vec_allocate(out, (uintptr_t)args[1], (uintptr_t)args[2],
(uintptr_t)args[3]);
}
static int spl_vec_reserve_raw(spl_vec_t *v, uintptr_t need) {
if (need <= v->cap)
return 0;
uintptr_t new_cap = 0;
spl_grow_capacity(v->cap, 8, need, &new_cap);
spl_vec_t fresh;
int rc = spl_vec_allocate(&fresh, new_cap, v->elem_size, v->elem_align);
if (rc)
return rc;
uintptr_t used = 0;
if (v->len != 0) {
if (v->len > ~(uintptr_t)0 / v->elem_size) {
free((void *)fresh.raw);
return 3;
}
used = v->len * v->elem_size;
}
if (used != 0)
memcpy((void *)fresh.data, (void *)v->data, used);
fresh.len = v->len;
uintptr_t old = v->raw;
*v = fresh;
if (old)
free((void *)old);
return 0;
}
static spl_vm_val_t vm_vec_reserve_raw(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_vec_reserve_raw", 2);
spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0];
if (!v)
return 1;
return (spl_vm_val_t)spl_vec_reserve_raw(v, (uintptr_t)args[1]);
}
static spl_vm_val_t vm_vec_append(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_vec_append", 3);
spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0];
const void *elems = (const void *)(uintptr_t)args[1];
uintptr_t count = (uintptr_t)args[2];
if (!v || !spl_vec_is_valid(v))
return 1;
if (count == 0)
return 0;
if (!elems)
return 1;
if (count > ~(uintptr_t)0 / v->elem_size)
return 3;
uintptr_t copy_bytes = count * v->elem_size;
if (v->len > ~(uintptr_t)0 - count)
return 3;
uintptr_t new_len = v->len + count;
uintptr_t used = v->len * v->elem_size;
int source_inside = 0;
uintptr_t source_offset = 0;
if (used != 0) {
uintptr_t base = v->data;
uintptr_t source = (uintptr_t)elems;
if (source >= base && source - base < used) {
source_offset = source - base;
if (copy_bytes > used - source_offset)
return 2;
source_inside = 1;
}
}
int 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;
}
static spl_vm_val_t vm_vec_set(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_vec_set", 3);
spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0];
uintptr_t index = (uintptr_t)args[1];
const void *elem = (const void *)(uintptr_t)args[2];
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;
}
static spl_vm_val_t vm_vec_pop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_vec_pop", 2);
spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0];
void *out = (void *)(uintptr_t)args[1];
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;
}
static spl_vm_val_t vm_vec_clone(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_vec_clone", 2);
spl_vec_t *out = (spl_vec_t *)(uintptr_t)args[0];
const spl_vec_t *src = (const spl_vec_t *)(uintptr_t)args[1];
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;
spl_vec_t fresh;
fresh.raw = 0;
fresh.data = 0;
fresh.len = 0;
fresh.cap = 0;
fresh.elem_size = src->elem_size;
fresh.elem_align = src->elem_align;
int rc = spl_vec_reserve_raw(&fresh, src->len);
if (rc)
return rc;
uintptr_t bytes = src->len * src->elem_size;
if (bytes != 0)
memcpy((void *)fresh.data, (void *)src->data, bytes);
fresh.len = src->len;
if (out->raw)
free((void *)out->raw);
*out = fresh;
return 0;
}
static spl_vm_val_t vm_vec_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_vec_drop", 1);
spl_vec_t *v = (spl_vec_t *)(uintptr_t)args[0];
if (!v)
return 0;
uintptr_t es = v->elem_size;
uintptr_t 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;
return 0;
}
static spl_vm_val_t vm_memmove(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
CHECK_NARGS("vm_memmove", 3);
void *dst = (void *)(uintptr_t)args[0];
const void *src = (const void *)(uintptr_t)args[1];
size_t size = (size_t)args[2];
if (size == 0)
return (spl_vm_val_t)(uintptr_t)dst;
ADDRCHECK(_vm, dst, size, "vm_memmove(dst)");
ADDRCHECK(_vm, src, size, "vm_memmove(src)");
memmove(dst, src, size);
return (spl_vm_val_t)(uintptr_t)dst;
}
/* =================================================================
* Native Map(开放寻址 + 墓碑),布局镜像 stage2/utils/map.spl 的 Map。
* hash_kind: 0 = usize;1 = ByteView(按内容);2 = 常量(仅测试用)。
* ================================================================= */
typedef struct {
spl_vec_t keys;
spl_vec_t vals;
spl_vec_t states;
uintptr_t size;
uintptr_t key_size;
uintptr_t val_size;
uintptr_t hash_kind;
} spl_map_t;
static void spl_vec_release(spl_vec_t *v) {
uintptr_t es = v->elem_size;
uintptr_t 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;
}
static uintptr_t spl_hash_usize_value(uintptr_t value) {
uintptr_t prime = 1099511628211ull;
uintptr_t 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;
}
static uintptr_t spl_hash_bytes(const void *data, uintptr_t len) {
const unsigned char *p = (const unsigned char *)data;
uintptr_t h = 14695981039346656037ull;
uintptr_t prime = 1099511628211ull;
for (uintptr_t i = 0; i < len; i++)
h = (h ^ (uintptr_t)p[i]) * prime;
return h;
}
static uintptr_t spl_map_hash(const spl_map_t *m, const void *key) {
if (m->hash_kind == 0)
return spl_hash_usize_value(*(const uintptr_t *)key);
if (m->hash_kind == 2)
return 3;
const uintptr_t *v = (const uintptr_t *)key; /* ByteView { ptr, len } */
return spl_hash_bytes((const void *)v[0], v[1]);
}
static int spl_map_eq(const spl_map_t *m, const void *a, const void *b) {
if (m->hash_kind == 0 || m->hash_kind == 2)
return *(const uintptr_t *)a == *(const uintptr_t *)b;
const uintptr_t *x = (const uintptr_t *)a;
const uintptr_t *y = (const uintptr_t *)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;
}
static 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;
}
static uintptr_t spl_map_find_slot(const spl_map_t *m, const void *key) {
if (m->states.cap == 0)
return ~(uintptr_t)0;
uintptr_t mask = m->states.cap - 1;
uintptr_t i = spl_map_hash(m, key) & mask;
unsigned char *st = (unsigned char *)m->states.data;
uintptr_t 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 ~(uintptr_t)0;
}
static void spl_map_place(spl_map_t *m, const void *key, const void *val) {
uintptr_t mask = m->states.cap - 1;
uintptr_t i = spl_map_hash(m, key) & mask;
unsigned char *st = (unsigned char *)m->states.data;
uintptr_t first_deleted = ~(uintptr_t)0;
uintptr_t probes = 0;
while (probes < m->states.cap && st[i] != 0) {
if (st[i] == 2 && first_deleted == ~(uintptr_t)0)
first_deleted = i;
i = (i + 1) & mask;
probes++;
}
if (first_deleted != ~(uintptr_t)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++;
}
static int spl_map_reserve(spl_map_t *m, uintptr_t need) {
if (!spl_map_valid(m))
return 1;
if (need <= m->states.cap)
return 0;
uintptr_t new_cap = 0;
spl_grow_capacity(m->states.cap, 8, need, &new_cap);
spl_map_t 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;
int 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 (uintptr_t 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;
}
static spl_vm_val_t vm_bytes_eq(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_bytes_eq", 4);
const void *a = (const void *)(uintptr_t)args[0];
uintptr_t alen = (uintptr_t)args[1];
const void *b = (const void *)(uintptr_t)args[2];
uintptr_t blen = (uintptr_t)args[3];
if (alen != blen)
return 0;
if (alen == 0)
return 1;
if (!a || !b)
return 0;
return memcmp(a, b, alen) == 0;
}
static spl_vm_val_t vm_map_valid(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_map_valid", 1);
const spl_map_t *m = (const spl_map_t *)(uintptr_t)args[0];
return (spl_vm_val_t)(m ? spl_map_valid(m) : 0);
}
static spl_vm_val_t vm_map_reserve(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_map_reserve", 2);
spl_map_t *m = (spl_map_t *)(uintptr_t)args[0];
if (!m)
return 1;
return (spl_vm_val_t)spl_map_reserve(m, (uintptr_t)args[1]);
}
static spl_vm_val_t vm_map_put(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_map_put", 3);
spl_map_t *m = (spl_map_t *)(uintptr_t)args[0];
const void *key = (const void *)(uintptr_t)args[1];
const void *val = (const void *)(uintptr_t)args[2];
if (!m || !key || !val || !spl_map_valid(m))
return 1;
uintptr_t existing = spl_map_find_slot(m, key);
if (existing != ~(uintptr_t)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 {
if (m->size > ~(uintptr_t)0 - 1)
return 3;
uintptr_t next_size = m->size + 1;
if (next_size > ~(uintptr_t)0 / 128)
return 3;
uintptr_t scaled = next_size * 128;
if (scaled / m->states.cap >= 70) {
if (m->states.cap > ~(uintptr_t)0 / 2)
return 3;
int rc = spl_map_reserve(m, m->states.cap * 2);
if (rc)
return rc;
}
}
spl_map_place(m, key, val);
return 0;
}
static spl_vm_val_t vm_map_get(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_map_get", 3);
spl_map_t *m = (spl_map_t *)(uintptr_t)args[0];
const void *key = (const void *)(uintptr_t)args[1];
void *out = (void *)(uintptr_t)args[2];
if (!m || !key || !out || !spl_map_valid(m))
return 1;
uintptr_t i = spl_map_find_slot(m, key);
if (i == ~(uintptr_t)0)
return 1;
memcpy(out, (void *)(m->vals.data + i * m->val_size), m->val_size);
return 0;
}
static spl_vm_val_t vm_map_del(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_map_del", 2);
spl_map_t *m = (spl_map_t *)(uintptr_t)args[0];
const void *key = (const void *)(uintptr_t)args[1];
if (!m || !key || !spl_map_valid(m))
return 1;
uintptr_t i = spl_map_find_slot(m, key);
if (i == ~(uintptr_t)0)
return 1;
((unsigned char *)m->states.data)[i] = 2;
m->size--;
return 0;
}
static spl_vm_val_t vm_map_clear(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_map_clear", 1);
spl_map_t *m = (spl_map_t *)(uintptr_t)args[0];
if (!m)
return 0;
if (m->states.data && m->states.len)
memset((void *)m->states.data, 0, m->states.len);
m->size = 0;
return 0;
}
static spl_vm_val_t vm_map_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) {
(void)_vm;
CHECK_NARGS("vm_map_drop", 1);
spl_map_t *m = (spl_map_t *)(uintptr_t)args[0];
if (!m)
return 0;
spl_vec_release(&m->keys);
spl_vec_release(&m->vals);
spl_vec_release(&m->states);
m->size = 0;
return 0;
}
void spl_syscall_register(spl_prog_t *prog) { void spl_syscall_register(spl_prog_t *prog) {
static spl_vm_native_t table[] = { static spl_vm_native_t table[] = {
/* OS operations */ /* OS operations */
@@ -516,6 +1137,26 @@ void spl_syscall_register(spl_prog_t *prog) {
{"vm_memcpy", 0, vm_memcpy}, {"vm_memcpy", 0, vm_memcpy},
{"vm_memcmp", 0, vm_memcmp}, {"vm_memcmp", 0, vm_memcmp},
{"vm_printf", 0, vm_printf}, {"vm_printf", 0, vm_printf},
{"vm_vec_valid", 0, vm_vec_valid},
{"vm_vec_push_raw", 0, vm_vec_push_raw},
{"vm_vec_push", 0, vm_vec_push},
{"vm_vec_get", 0, vm_vec_get},
{"vm_vec_allocate", 0, vm_vec_allocate},
{"vm_vec_reserve_raw", 0, vm_vec_reserve_raw},
{"vm_vec_append", 0, vm_vec_append},
{"vm_vec_set", 0, vm_vec_set},
{"vm_vec_pop", 0, vm_vec_pop},
{"vm_vec_clone", 0, vm_vec_clone},
{"vm_vec_drop", 0, vm_vec_drop},
{"vm_memmove", 0, vm_memmove},
{"vm_bytes_eq", 0, vm_bytes_eq},
{"vm_map_valid", 0, vm_map_valid},
{"vm_map_reserve", 0, vm_map_reserve},
{"vm_map_put", 0, vm_map_put},
{"vm_map_get", 0, vm_map_get},
{"vm_map_del", 0, vm_map_del},
{"vm_map_clear", 0, vm_map_clear},
{"vm_map_drop", 0, vm_map_drop},
{"vm_timestamp", 0, vm_timestamp}, {"vm_timestamp", 0, vm_timestamp},
/* VM operations (comptime) */ /* VM operations (comptime) */
+292 -202
View File
@@ -11,6 +11,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
static void spl_vm_profile_free(spl_vm_t *vm); static void spl_vm_profile_free(spl_vm_t *vm);
@@ -67,7 +68,7 @@ static int spl_type_size(spl_vm_kind_t t) {
case SPL_USIZE: case SPL_USIZE:
case SPL_PTR: case SPL_PTR:
return sizeof(void *); return sizeof(void *);
case SPL_TYPE_COUNT: default:
return 0; return 0;
} }
return 0; return 0;
@@ -570,6 +571,7 @@ void spl_vm_init_ex(spl_vm_t *vm, int stack_size, int call_depth) {
vm->sp = vm->fp = vm->ip = vm->cp = vm->gp = 0; vm->sp = vm->fp = vm->ip = vm->cp = vm->gp = 0;
vm->steps = 0; vm->steps = 0;
vm->ncalls = 0;
vm->profile = NULL; vm->profile = NULL;
vm->profile_interval = 0; vm->profile_interval = 0;
vm->prog = NULL; vm->prog = NULL;
@@ -708,22 +710,29 @@ void spl_vm_set_debug(spl_vm_t *vm, int enabled) {
static inline int spl_vm_call(spl_vm_t *vm, spl_vm_val_t addr, spl_vm_val_t nargs) { static inline int spl_vm_call(spl_vm_t *vm, spl_vm_val_t addr, spl_vm_val_t nargs) {
if (vm->cp >= vm->config.max_call_depth) if (vm->cp >= vm->config.max_call_depth)
VM_ERROR("call depth exceeded"); VM_ERROR("call depth exceeded");
// spl_vm_stackdump(vm, vm->sp);
PUSH(SPL_STACK_CANARY); uintptr_t saved_sp;
/* Shift args right by 1 to create gap for canary at fp-1 */ if (vm->debug) {
for (usize i = vm->sp; i >= vm->sp - nargs; --i) { /* debug:在 fp-1 留金丝雀位,需要把实参右移一格。 */
vm->stacks.data[i] = vm->stacks.data[i - 1]; PUSH(SPL_STACK_CANARY);
for (usize i = vm->sp; i >= vm->sp - nargs; --i)
vm->stacks.data[i] = vm->stacks.data[i - 1];
saved_sp = vm->sp - nargs - 1;
} else {
/* 非 debug:不做金丝雀搬移;实参在 sp-nargs..sp-1,fp 指向 arg0。 */
saved_sp = vm->sp - nargs;
} }
vm->frames.data[vm->cp].saved_sp = vm->sp - nargs - 1;
vm->frames.data[vm->cp].saved_fp = vm->fp; spl_callframe_t *fr = &vm->frames.data[vm->cp];
vm->frames.data[vm->cp].saved_ip = vm->ip; fr->saved_sp = saved_sp;
vm->frames.data[vm->cp].nargs = nargs; fr->saved_fp = vm->fp;
fr->saved_ip = vm->ip;
fr->nargs = nargs;
vm->cp++; vm->cp++;
vm->ip = addr; vm->ip = addr;
vm->fp = vm->sp - nargs; vm->fp = vm->sp - nargs;
if (vm->fp > 0) if (vm->debug && vm->fp > 0)
STACK_CANARY(vm) = SPL_STACK_CANARY; STACK_CANARY(vm) = SPL_STACK_CANARY;
// spl_vm_stackdump(vm, vm->sp);
return 0; return 0;
} }
@@ -800,6 +809,13 @@ static int func_index_by_ip(spl_prog_t *prog, spl_vm_val_t ip) {
return -1; return -1;
} }
static uint64_t prof_now_ns(void) {
struct timespec ts;
if (timespec_get(&ts, TIME_UTC) != TIME_UTC)
return 0;
return (uint64_t)ts.tv_sec * 1000000000ull + (uint64_t)ts.tv_nsec;
}
static void spl_vm_sample(spl_vm_t *vm) { static void spl_vm_sample(spl_vm_t *vm) {
spl_prof_t *p = (spl_prof_t *)vm->profile; spl_prof_t *p = (spl_prof_t *)vm->profile;
spl_prog_t *prog = vm->prog; spl_prog_t *prog = vm->prog;
@@ -823,6 +839,17 @@ static void spl_vm_sample(spl_vm_t *vm) {
} }
} }
int leaf = func_index_by_ip(prog, vm->ip > 0 ? vm->ip - 1 : 0); int leaf = func_index_by_ip(prog, vm->ip > 0 ? vm->ip - 1 : 0);
/* time-slice:把两次采样之间的时间记到当前活跃函数(leaf)。 */
uint64_t now = prof_now_ns();
if (p->last_ns != 0 && now > p->last_ns) {
uint64_t d = now - p->last_ns;
p->total_ns += d;
if (leaf >= 0 && (usize)leaf < vec_size(p->self_ns))
p->self_ns.data[leaf] += d;
}
p->last_ns = now;
const char *ln = leaf >= 0 ? vec_at(prog->funcs, (usize)leaf).name : "?"; const char *ln = leaf >= 0 ? vec_at(prog->funcs, (usize)leaf).name : "?";
size_t ll = strlen(ln); size_t ll = strlen(ln);
if (len + ll + 1 < sizeof(buf)) { if (len + ll + 1 < sizeof(buf)) {
@@ -853,10 +880,13 @@ void spl_vm_profile_enable(spl_vm_t *vm, usize interval) {
memset(p, 0, sizeof(*p)); memset(p, 0, sizeof(*p));
map_init(p->stacks, MAP_HASH_STR, MAP_CMP_STR); map_init(p->stacks, MAP_HASH_STR, MAP_CMP_STR);
vec_init(p->self_samples); vec_init(p->self_samples);
vec_init(p->self_ns);
if (vm->prog) { if (vm->prog) {
usize n = vec_size(vm->prog->funcs); usize n = vec_size(vm->prog->funcs);
for (usize i = 0; i < n; i++) for (usize i = 0; i < n; i++) {
vec_push(p->self_samples, (usize)0); vec_push(p->self_samples, (usize)0);
vec_push(p->self_ns, (uint64_t)0);
}
} }
vm->profile = p; vm->profile = p;
vm->profile_interval = interval ? interval : 100000; vm->profile_interval = interval ? interval : 100000;
@@ -869,6 +899,7 @@ static void spl_vm_profile_free(spl_vm_t *vm) {
map_for(p->stacks, i) { free((void *)p->stacks.data[i].key); } map_for(p->stacks, i) { free((void *)p->stacks.data[i].key); }
map_free(p->stacks); map_free(p->stacks);
vec_free(p->self_samples); vec_free(p->self_samples);
vec_free(p->self_ns);
free(p); free(p);
vm->profile = NULL; vm->profile = NULL;
} }
@@ -891,20 +922,67 @@ void spl_vm_profile_dump_table(spl_vm_t *vm, const char *path) {
FILE *f = fopen(path, "wb"); FILE *f = fopen(path, "wb");
if (!f) if (!f)
return; return;
fprintf(f, "samples=%zu interval=%zu\n", p->samples, vm->profile_interval); fprintf(f, "samples=%zu interval=%zu total_ns=%llu\n", p->samples, vm->profile_interval,
fprintf(f, "func\tself_samples\tpercent\n"); (unsigned long long)p->total_ns);
fprintf(f, "func\tself_samples\tpct_samples\tself_ns\tpct_ns\tns_per_step\n");
for (usize i = 0; i < vec_size(vm->prog->funcs); i++) { for (usize i = 0; i < vec_size(vm->prog->funcs); i++) {
usize c = i < vec_size(p->self_samples) ? p->self_samples.data[i] : 0; usize c = i < vec_size(p->self_samples) ? p->self_samples.data[i] : 0;
if (c == 0) if (c == 0)
continue; continue;
uint64_t t = i < vec_size(p->self_ns) ? p->self_ns.data[i] : 0;
spl_vm_func_t *fn = &vec_at(vm->prog->funcs, i); spl_vm_func_t *fn = &vec_at(vm->prog->funcs, i);
fprintf(f, "%s\t%zu\t%.2f\n", fn->name, c, double ps = p->samples ? (100.0 * (double)c / (double)p->samples) : 0.0;
p->samples ? (100.0 * (double)c / (double)p->samples) : 0.0); double pt = p->total_ns ? (100.0 * (double)t / (double)p->total_ns) : 0.0;
double nps = c ? ((double)t / (double)c) : 0.0;
fprintf(f, "%s\t%zu\t%.2f\t%llu\t%.2f\t%.1f\n", fn->name, c, ps, (unsigned long long)t, pt,
nps);
} }
fclose(f); fclose(f);
} }
int spl_vm_run_once(spl_vm_t *vm) { /* 单步执行核心(static,便于内联进热循环)。 */
/* computed-goto 调度:每个 opcode 直接跳到对应标签;limit=SIZE_MAX 表示不限步。 */
#define DT(op) [op] = &&L_##op
#define FETCH() \
do { \
if (vm->ip >= (spl_vm_val_t)vec_size(prog->insns)) { \
fprintf(stderr, "vm: ip=%zd out of bounds\n", vm->ip); \
vm->exit_code = 1; \
return -1; \
} \
ins = &vec_at(prog->insns, vm->ip); \
vm->ip++; \
vm->steps++; \
if (vm->profile && vm->profile_interval && (vm->steps % vm->profile_interval) == 0) \
spl_vm_sample(vm); \
if (vm->trace) { \
fprintf(stderr, "vm: ip=%zd op=%s type=%s imm=%zu sp=%zd fp=%zd\n", vm->ip - 1, \
spl_vm_opcode_name(ins->opcode), spl_vm_type_kind_name(ins->type), ins->imm, \
vm->sp, vm->fp); \
} \
} while (0)
#define DISPATCH() \
do { \
if (vm->debug && vm->fp > 0 && STACK_CANARY(vm) != SPL_STACK_CANARY) { \
snprintf(vm->error_msg, sizeof(vm->error_msg), \
"STACK CANARY CORRUPTED at ip=%zd, fp=%zd\n", vm->ip - 1, vm->fp); \
VM_ERROR(vm->error_msg); \
} \
if (limit && --limit == 0) \
return 0; \
if (ip_breakpoint_hit(vm)) { \
if (vm->skip_bp) \
vm->skip_bp = 0; \
else \
return 2; \
} \
FETCH(); \
goto *vm_dispatch[ins->opcode]; \
} while (0)
static int vm_loop(spl_vm_t *vm, size_t limit) {
const spl_vm_ins_t *ins; const spl_vm_ins_t *ins;
spl_prog_t *prog; spl_prog_t *prog;
@@ -912,73 +990,78 @@ int spl_vm_run_once(spl_vm_t *vm) {
return -1; return -1;
prog = vm->prog; prog = vm->prog;
if (vm->ip >= vec_size(prog->insns)) { static void *vm_dispatch[SPL_OPCODE_COUNT] = {
fprintf(stderr, "vm: ip=%zd out of bounds\n", vm->ip); DT(SPL_PUSH), DT(SPL_DUP), DT(SPL_DROP),
vm->exit_code = 1; DT(SPL_SWAP), DT(SPL_PICK), DT(SPL_ROT),
return -1; DT(SPL_ADD), DT(SPL_SUB), DT(SPL_MUL),
} DT(SPL_DIV_S), DT(SPL_DIV_U), DT(SPL_REM_S),
DT(SPL_REM_U), DT(SPL_NEG), DT(SPL_AND),
DT(SPL_OR), DT(SPL_XOR), DT(SPL_NOT),
DT(SPL_SHL), DT(SPL_SHR_U), DT(SPL_SHR_S),
DT(SPL_EQ), DT(SPL_NE), DT(SPL_SLT),
DT(SPL_SLE), DT(SPL_ULT), DT(SPL_ULE),
DT(SPL_SGT), DT(SPL_SGE), DT(SPL_UGT),
DT(SPL_UGE), DT(SPL_TRUNC), DT(SPL_SEXT),
DT(SPL_ZEXT), DT(SPL_JMP), DT(SPL_BZ),
DT(SPL_BNZ), DT(SPL_HALT), DT(SPL_CALL),
DT(SPL_CALLI), DT(SPL_RET), DT(SPL_ALLOC),
DT(SPL_LADDR), DT(SPL_GADDR), DT(SPL_LOAD),
DT(SPL_STORE), DT(SPL_NCALL), DT(SPL_NLIB),
DT(SPL_BK), DT(SPL_DBG), [SPL_ERROR] = &&L_default,
};
/* 断点:即将执行的指令命中 ip 断点 -> 暂停(返回 2)。 if (limit == 0)
* skip_bp 置位时执行当前指令(continue 越过当前断点)。 */ return 0;
if (ip_breakpoint_hit(vm)) { if (ip_breakpoint_hit(vm)) {
if (vm->skip_bp) { if (vm->skip_bp)
vm->skip_bp = 0; vm->skip_bp = 0;
} else { else
return 2; return 2;
}
} }
FETCH();
goto *vm_dispatch[ins->opcode];
ins = &vec_at(prog->insns, vm->ip); /* ========== Stack ========== */
vm->ip++; L_SPL_PUSH:
vm->steps++; PUSH(ins->imm);
if (vm->profile && vm->profile_interval && (vm->steps % vm->profile_interval) == 0) DISPATCH();
spl_vm_sample(vm);
if (vm->trace) { L_SPL_DUP:
fprintf(stderr, "vm: ip=%zd op=%s type=%s imm=%zu sp=%zd fp=%zd\n", vm->ip - 1, {
spl_vm_opcode_name(ins->opcode), spl_vm_type_kind_name(ins->type), ins->imm, vm->sp,
vm->fp);
}
switch (ins->opcode) {
/* ========== Stack ========== */
case SPL_PUSH:
PUSH(ins->imm);
break;
case SPL_DUP: {
if (vm->sp < 1) if (vm->sp < 1)
VM_ERROR("DUP: stack underflow"); VM_ERROR("DUP: stack underflow");
spl_vm_val_t _v = vm->stacks.data[vm->sp - 1]; spl_vm_val_t _v = vm->stacks.data[vm->sp - 1];
PUSH(_v); PUSH(_v);
break; DISPATCH();
} }
case SPL_DROP: L_SPL_DROP:
if (vm->sp < 1) if (vm->sp < 1)
VM_ERROR("DROP: stack underflow"); VM_ERROR("DROP: stack underflow");
vm->sp--; vm->sp--;
break; DISPATCH();
case SPL_SWAP: { L_SPL_SWAP:
{
if (vm->sp < 2) if (vm->sp < 2)
VM_ERROR("SWAP: stack underflow"); VM_ERROR("SWAP: stack underflow");
spl_vm_val_t _t = vm->stacks.data[vm->sp - 1]; spl_vm_val_t _t = vm->stacks.data[vm->sp - 1];
vm->stacks.data[vm->sp - 1] = vm->stacks.data[vm->sp - 2]; vm->stacks.data[vm->sp - 1] = vm->stacks.data[vm->sp - 2];
vm->stacks.data[vm->sp - 2] = _t; vm->stacks.data[vm->sp - 2] = _t;
break; DISPATCH();
} }
case SPL_PICK: { L_SPL_PICK:
{
isize _idx = ins->imm; isize _idx = ins->imm;
if ((usize)_idx >= vm->sp) if ((usize)_idx >= vm->sp)
VM_ERROR("PICK: index out of range"); VM_ERROR("PICK: index out of range");
PUSH(vm->stacks.data[vm->sp - 1 - _idx]); PUSH(vm->stacks.data[vm->sp - 1 - _idx]);
break; DISPATCH();
} }
case SPL_ROT: { L_SPL_ROT:
{
if (vm->sp < 3) if (vm->sp < 3)
VM_ERROR("ROT: stack underflow"); VM_ERROR("ROT: stack underflow");
spl_vm_val_t _a = vm->stacks.data[vm->sp - 3]; spl_vm_val_t _a = vm->stacks.data[vm->sp - 3];
@@ -987,34 +1070,35 @@ int spl_vm_run_once(spl_vm_t *vm) {
vm->stacks.data[vm->sp - 3] = _b; vm->stacks.data[vm->sp - 3] = _b;
vm->stacks.data[vm->sp - 2] = _c; vm->stacks.data[vm->sp - 2] = _c;
vm->stacks.data[vm->sp - 1] = _a; vm->stacks.data[vm->sp - 1] = _a;
break; DISPATCH();
} }
/* ========== Arithmetic ========== */ /* ========== Arithmetic ========== */
case SPL_ADD: L_SPL_ADD:
ARITH_BINOP(+); ARITH_BINOP(+);
break; DISPATCH();
case SPL_SUB: L_SPL_SUB:
ARITH_BINOP(-); ARITH_BINOP(-);
break; DISPATCH();
case SPL_MUL: L_SPL_MUL:
ARITH_BINOP(*); ARITH_BINOP(*);
break; DISPATCH();
case SPL_DIV_S: L_SPL_DIV_S:
DIV_REM_S(/); DIV_REM_S(/);
break; DISPATCH();
case SPL_DIV_U: L_SPL_DIV_U:
DIV_REM_U(/); DIV_REM_U(/);
break; DISPATCH();
case SPL_REM_S: L_SPL_REM_S:
DIV_REM_S(%); DIV_REM_S(%);
break; DISPATCH();
case SPL_REM_U: L_SPL_REM_U:
DIV_REM_U(%); DIV_REM_U(%);
break; DISPATCH();
case SPL_NEG: { L_SPL_NEG:
{
spl_vm_val_t _a = POP(); spl_vm_val_t _a = POP();
if (spl_is_float((spl_vm_kind_t)ins->type)) { if (spl_is_float((spl_vm_kind_t)ins->type)) {
double _d; double _d;
@@ -1032,115 +1116,129 @@ int spl_vm_run_once(spl_vm_t *vm) {
} else { } else {
PUSH(-(int64_t)_a); PUSH(-(int64_t)_a);
} }
break; DISPATCH();
} }
/* ========== Bitwise ========== */ /* ========== Bitwise ========== */
case SPL_AND: { L_SPL_AND:
{
spl_vm_val_t _b = POP(), _a = POP(); spl_vm_val_t _b = POP(), _a = POP();
PUSH(_a & _b); PUSH(_a & _b);
break; DISPATCH();
} }
case SPL_OR: { L_SPL_OR:
{
spl_vm_val_t _b = POP(), _a = POP(); spl_vm_val_t _b = POP(), _a = POP();
PUSH(_a | _b); PUSH(_a | _b);
break; DISPATCH();
} }
case SPL_XOR: { L_SPL_XOR:
{
spl_vm_val_t _b = POP(), _a = POP(); spl_vm_val_t _b = POP(), _a = POP();
PUSH(_a ^ _b); PUSH(_a ^ _b);
break; DISPATCH();
} }
case SPL_NOT: { L_SPL_NOT:
{
PUSH(~POP()); PUSH(~POP());
break; DISPATCH();
} }
case SPL_SHL: { L_SPL_SHL:
{
int _s = (int)(POP() & 63); int _s = (int)(POP() & 63);
PUSH(POP() << _s); PUSH(POP() << _s);
break; DISPATCH();
} }
case SPL_SHR_U: { L_SPL_SHR_U:
{
int _s = (int)(POP() & 63); int _s = (int)(POP() & 63);
PUSH(POP() >> _s); PUSH(POP() >> _s);
break; DISPATCH();
} }
case SPL_SHR_S: { L_SPL_SHR_S:
{
int _s = (int)(POP() & 63); int _s = (int)(POP() & 63);
PUSH(POP() >> _s); PUSH(POP() >> _s);
break; DISPATCH();
} }
/* ========== Comparison ========== */ /* ========== Comparison ========== */
case SPL_EQ: L_SPL_EQ:
CMP_ALL(==); CMP_ALL(==);
break; DISPATCH();
case SPL_NE: L_SPL_NE:
CMP_ALL(!=); CMP_ALL(!=);
break; DISPATCH();
case SPL_SLT: L_SPL_SLT:
CMP_S(<); CMP_S(<);
break; DISPATCH();
case SPL_SLE: L_SPL_SLE:
CMP_S(<=); CMP_S(<=);
break; DISPATCH();
case SPL_SGT: L_SPL_SGT:
CMP_S(>); CMP_S(>);
break; DISPATCH();
case SPL_SGE: L_SPL_SGE:
CMP_S(>=); CMP_S(>=);
break; DISPATCH();
case SPL_ULT: L_SPL_ULT:
CMP_U(<); CMP_U(<);
break; DISPATCH();
case SPL_ULE: L_SPL_ULE:
CMP_U(<=); CMP_U(<=);
break; DISPATCH();
case SPL_UGT: L_SPL_UGT:
CMP_U(>); CMP_U(>);
break; DISPATCH();
case SPL_UGE: L_SPL_UGE:
CMP_U(>=); CMP_U(>=);
break; DISPATCH();
/* ========== Control Flow (relative offset) ========== */ /* ========== Control Flow (relative offset) ========== */
case SPL_JMP: L_SPL_JMP:
vm->ip = vm->ip + ins->imm; vm->ip = vm->ip + ins->imm;
break; DISPATCH();
case SPL_BZ: { L_SPL_BZ:
{
if (POP() == 0) if (POP() == 0)
vm->ip = vm->ip + ins->imm; vm->ip = vm->ip + ins->imm;
break; DISPATCH();
} }
case SPL_BNZ: { L_SPL_BNZ:
{
if (POP() != 0) if (POP() != 0)
vm->ip = vm->ip + ins->imm; vm->ip = vm->ip + ins->imm;
break; DISPATCH();
} }
case SPL_CALL: { L_SPL_CALL:
{
spl_vm_val_t _nargs = ins->imm; spl_vm_val_t _nargs = ins->imm;
spl_vm_val_t _addr = POP(); spl_vm_val_t _addr = POP();
vm->ncalls++;
int _hit = fn_breakpoint_hit(vm, _addr); int _hit = fn_breakpoint_hit(vm, _addr);
spl_vm_call(vm, _addr, _nargs); spl_vm_call(vm, _addr, _nargs);
if (_hit) if (_hit)
return 2; /* 已进入函数,暂停在函数入口 */ return 2; /* 已进入函数,暂停在函数入口 */
break; DISPATCH();
} }
case SPL_CALLI: { L_SPL_CALLI:
{
spl_vm_val_t _addr = POP(); spl_vm_val_t _addr = POP();
spl_vm_val_t _nargs = POP(); spl_vm_val_t _nargs = POP();
vm->ncalls++;
int _hit = fn_breakpoint_hit(vm, _addr); int _hit = fn_breakpoint_hit(vm, _addr);
spl_vm_call(vm, _addr, _nargs); spl_vm_call(vm, _addr, _nargs);
if (_hit) if (_hit)
return 2; return 2;
break; DISPATCH();
} }
case SPL_RET: { L_SPL_RET:
{
spl_vm_val_t _retval = 0; spl_vm_val_t _retval = 0;
if (ins->type != SPL_VOID) if (ins->type != SPL_VOID)
_retval = POP(); _retval = POP();
@@ -1161,16 +1259,17 @@ int spl_vm_run_once(spl_vm_t *vm) {
if (ins->type != SPL_VOID) if (ins->type != SPL_VOID)
PUSH(_retval); PUSH(_retval);
// spl_vm_stackdump(vm, vm->sp); // spl_vm_stackdump(vm, vm->sp);
break; DISPATCH();
} }
case SPL_HALT: L_SPL_HALT:
if (ins->imm) if (ins->imm)
vm->exit_code = (int)ins->imm; vm->exit_code = (int)ins->imm;
return 1; return 1;
/* ========== Stack / Frame Local Memory ========== */ /* ========== Stack / Frame Local Memory ========== */
case SPL_ALLOC: { L_SPL_ALLOC:
{
spl_vm_val_t _k = ins->imm; spl_vm_val_t _k = ins->imm;
uintptr_t _new_sp = vm->sp + _k; uintptr_t _new_sp = vm->sp + _k;
if (_new_sp > vm->config.max_stack_depth) if (_new_sp > vm->config.max_stack_depth)
@@ -1178,14 +1277,15 @@ int spl_vm_run_once(spl_vm_t *vm) {
for (uintptr_t _i = vm->sp; _i < _new_sp; _i++) for (uintptr_t _i = vm->sp; _i < _new_sp; _i++)
vm->stacks.data[_i] = 0; vm->stacks.data[_i] = 0;
vm->sp = _new_sp; vm->sp = _new_sp;
break; DISPATCH();
} }
case SPL_LADDR: L_SPL_LADDR:
PUSH((spl_vm_val_t)((char *)(vm->stacks.data + vm->fp) + ins->imm)); PUSH((spl_vm_val_t)((char *)(vm->stacks.data + vm->fp) + ins->imm));
break; DISPATCH();
case SPL_GADDR: { L_SPL_GADDR:
{
spl_vm_val_t _idx = ins->imm; spl_vm_val_t _idx = ins->imm;
if (_idx == 0 || _idx >= vec_size(prog->gdata)) if (_idx == 0 || _idx >= vec_size(prog->gdata))
VM_ERROR("GADDR: global data index out of range"); VM_ERROR("GADDR: global data index out of range");
@@ -1193,11 +1293,12 @@ int spl_vm_run_once(spl_vm_t *vm) {
if (!gd->data) if (!gd->data)
VM_ERROR("GADDR: null gdata entry"); VM_ERROR("GADDR: null gdata entry");
PUSH((spl_vm_val_t)(uintptr_t)gd->data); PUSH((spl_vm_val_t)(uintptr_t)gd->data);
break; DISPATCH();
} }
/* ========== Indirect Memory (load/store with types) ========== */ /* ========== Indirect Memory (load/store with types) ========== */
case SPL_LOAD: { L_SPL_LOAD:
{
void *_addr = (void *)POP(); void *_addr = (void *)POP();
CHECK_ADDR(_addr, "LOAD"); CHECK_ADDR(_addr, "LOAD");
spl_vm_val_t _v = 0; spl_vm_val_t _v = 0;
@@ -1209,18 +1310,20 @@ int spl_vm_run_once(spl_vm_t *vm) {
_v = (spl_vm_val_t)(((isize)(_v << _shift)) >> _shift); _v = (spl_vm_val_t)(((isize)(_v << _shift)) >> _shift);
} }
PUSH(_v); PUSH(_v);
break; DISPATCH();
} }
case SPL_STORE: { L_SPL_STORE:
{
spl_vm_val_t _v = POP(); spl_vm_val_t _v = POP();
void *_addr = (void *)POP(); void *_addr = (void *)POP();
CHECK_ADDR(_addr, "STORE"); CHECK_ADDR(_addr, "STORE");
memcpy(_addr, &_v, spl_type_size(ins->type)); memcpy(_addr, &_v, spl_type_size(ins->type));
break; DISPATCH();
} }
/* ========== Type Conversion ========== */ /* ========== Type Conversion ========== */
case SPL_TRUNC: { L_SPL_TRUNC:
{
spl_vm_val_t _v = POP(); spl_vm_val_t _v = POP();
intptr_t _bits = ins->imm; intptr_t _bits = ins->imm;
if (_bits < 1 || _bits > 64) if (_bits < 1 || _bits > 64)
@@ -1230,10 +1333,11 @@ int spl_vm_run_once(spl_vm_t *vm) {
_v &= _mask; _v &= _mask;
} }
PUSH(_v); PUSH(_v);
break; DISPATCH();
} }
case SPL_SEXT: { L_SPL_SEXT:
{
spl_vm_val_t _v = POP(); spl_vm_val_t _v = POP();
intptr_t _bits = ins->imm; intptr_t _bits = ins->imm;
if (_bits < 1 || _bits > 64) if (_bits < 1 || _bits > 64)
@@ -1246,10 +1350,11 @@ int spl_vm_run_once(spl_vm_t *vm) {
_v |= ~_mask; _v |= ~_mask;
} }
PUSH(_v); PUSH(_v);
break; DISPATCH();
} }
case SPL_ZEXT: { L_SPL_ZEXT:
{
spl_vm_val_t _v = POP(); spl_vm_val_t _v = POP();
intptr_t _bits = ins->imm; intptr_t _bits = ins->imm;
if (_bits < 1 || _bits > 64) if (_bits < 1 || _bits > 64)
@@ -1257,11 +1362,12 @@ int spl_vm_run_once(spl_vm_t *vm) {
if (_bits < 64) if (_bits < 64)
_v &= ((spl_vm_val_t)1 << _bits) - 1; _v &= ((spl_vm_val_t)1 << _bits) - 1;
PUSH(_v); PUSH(_v);
break; DISPATCH();
} }
/* ========== Native Interface ========== */ /* ========== Native Interface ========== */
case SPL_NCALL: { L_SPL_NCALL:
{
intptr_t _nargs = ins->imm; intptr_t _nargs = ins->imm;
spl_vm_val_t _nat_idx = POP(); spl_vm_val_t _nat_idx = POP();
spl_vm_native_t *_nat; spl_vm_native_t *_nat;
@@ -1287,10 +1393,11 @@ int spl_vm_run_once(spl_vm_t *vm) {
} }
vm->sp -= _nargs; vm->sp -= _nargs;
PUSH(_result); PUSH(_result);
break; DISPATCH();
} }
case SPL_NLIB: { L_SPL_NLIB:
{
spl_vm_val_t _si = ins->imm; spl_vm_val_t _si = ins->imm;
const char *_lib; const char *_lib;
if (_si >= vec_size(prog->strtab) || !vec_at(prog->strtab, _si)) if (_si >= vec_size(prog->strtab) || !vec_at(prog->strtab, _si))
@@ -1303,11 +1410,12 @@ int spl_vm_run_once(spl_vm_t *vm) {
} else { } else {
PUSH(_handle); PUSH(_handle);
} }
break; DISPATCH();
} }
/* ========== Debug ========== */ /* ========== Debug ========== */
case SPL_DBG: { L_SPL_DBG:
{
fprintf(stderr, "---DGB: current ip %zu---\n", vm->ip); fprintf(stderr, "---DGB: current ip %zu---\n", vm->ip);
spl_vm_dump_instr(vm, vm->ip - 6); spl_vm_dump_instr(vm, vm->ip - 6);
spl_vm_dump_instr(vm, vm->ip - 5); spl_vm_dump_instr(vm, vm->ip - 5);
@@ -1320,44 +1428,26 @@ int spl_vm_run_once(spl_vm_t *vm) {
spl_vm_backtrace(vm, vm->fp); spl_vm_backtrace(vm, vm->fp);
spl_vm_stackdump(vm, vm->sp); spl_vm_stackdump(vm, vm->sp);
fprintf(stderr, "---DGB END ---\n"); fprintf(stderr, "---DGB END ---\n");
break; DISPATCH();
} }
case SPL_BK: { L_SPL_BK:
{
return 2; /* breakpoint: pause execution */ return 2; /* breakpoint: pause execution */
} }
default: L_default:
fprintf(stderr, "vm: unknown opcode %d at ip=%zd\n", ins->opcode, vm->ip - 1); fprintf(stderr, "vm: unknown opcode %d at ip=%zd\n", ins->opcode, vm->ip - 1);
vm->exit_code = 1; vm->exit_code = 1;
return -1; return -1;
}
/* canary check in debug mode (canary is at fp-1, invisible to compiled code) */
if (vm->debug && vm->fp > 0) {
if (STACK_CANARY(vm) != SPL_STACK_CANARY) {
snprintf(vm->error_msg, sizeof(vm->error_msg),
"STACK CANARY CORRUPTED at ip=%zd, fp=%zd\n", vm->ip - 1, vm->fp);
VM_ERROR(vm->error_msg);
}
}
return 0;
} }
int spl_vm_run_once(spl_vm_t *vm) { return vm_loop(vm, 1); }
int spl_vm_run_until(spl_vm_t *vm, size_t step) { int spl_vm_run_until(spl_vm_t *vm, size_t step) {
size_t _count = 0;
int _ret;
if (!vm) if (!vm)
return -1; return -1;
while (1) { return vm_loop(vm, step ? step : (size_t)-1);
if (step > 0 && _count >= step)
return 0;
_ret = spl_vm_run_once(vm);
if (_ret != 0)
return _ret;
_count++;
}
} }
static const char *func_name_by_ip(spl_prog_t *prog, spl_vm_val_t ip) { static const char *func_name_by_ip(spl_prog_t *prog, spl_vm_val_t ip) {
+5 -1
View File
@@ -23,6 +23,9 @@ typedef VEC(spl_callframe_t) spl_frame_vec_t;
typedef struct { typedef struct {
MAP(const char *, usize) stacks; MAP(const char *, usize) stacks;
VEC(usize) self_samples; VEC(usize) self_samples;
VEC(uint64_t) self_ns; /* 每函数 time-slice 累加(纳秒) */
uint64_t last_ns;
uint64_t total_ns;
usize samples; usize samples;
} spl_prof_t; } spl_prof_t;
@@ -34,7 +37,8 @@ typedef struct spl_vm {
uintptr_t fp; // frame pointer uintptr_t fp; // frame pointer
uintptr_t cp; // call pointer uintptr_t cp; // call pointer
uintptr_t ip; // instr pointer uintptr_t ip; // instr pointer
uint64_t steps; // 已执行指令数(供性能分析参考) uint64_t steps; // 已执行指令数(供性能分析参考)
uint64_t ncalls; // 已执行 CALL/CALLI 次数(供性能分析参考)
int exit_code; int exit_code;
int trace; /* non-zero to print each instruction */ int trace; /* non-zero to print each instruction */
int debug; /* non-zero to enable canary checks */ int debug; /* non-zero to enable canary checks */
+612
View File
@@ -0,0 +1,612 @@
/* ir_opt.c - IR 层优化 pass
*
* 通用函数内联(任意大小/形状的 callee,不再限叶子):
* - callee 体内允许 control.call(嵌套调用)、分支/循环、多个返回、unit 返回;
* - 参数:克隆体内 Param 的“使用处”替换为调用实参 ref;
* - 控制流:克隆体追加到调用者末尾,内部 br/jmp/label 整体 +shift;
* - 返回:
* * 有返回值:在调用者追加 ret 槽(MemAlloca)与常量 1;每个 Ret 改为
* jmp 到“MemStore(槽, val) + jmp(join)”,join 处 MemLoad(槽) 供使用者;
* * 无返回值(unit):每个 Ret 直接 jmp 到调用点之后。
* - 调用点改为 jmp 到克隆体入口;其使用者改指到 join 的 MemLoad(或 0)。
* - 防环:若 callee(传递)可达 caller,则拒绝内联,保证调用图保持无环、
* 内联过程终止(直接/间接递归都不会被内联)。
* - 迭代到不动点(无环调用图上轮数有上界)。
* 默认关闭(splc0 --opt 驱动),且只内联显式 `#inline` 标记的 callee。 */
#include "ir_opt.h"
#include <stdlib.h>
#include <string.h>
typedef struct {
spl_ir_t *ir;
spl_ir_func_ref_t caller;
spl_ir_func_ref_t callee;
spl_ir_node_ref_t shift; /* new = old + shift */
usize nparams;
spl_ir_node_ref_t *param_ref;
spl_ir_node_ref_t *param_arg;
} inline_ctx_t;
static spl_ir_node_t *nd(spl_ir_t *ir, spl_ir_func_ref_t fid, spl_ir_node_ref_t ref) {
return spl_ir_node(ir, fid, ref);
}
/* ---- 引用重写(克隆体旧 ref -> 新 ref) ---- */
static spl_ir_node_ref_t rw(inline_ctx_t *c, spl_ir_node_ref_t r) {
if (r == 0)
return 0;
for (usize i = 0; i < c->nparams; i++)
if (c->param_ref[i] == r)
return c->param_arg[i];
return r + c->shift;
}
static void rw_vec(inline_ctx_t *c, spl_ir_node_ref_vec_t *v) {
for (usize i = 0; i < vec_size(*v); i++)
vec_at(*v, i) = rw(c, vec_at(*v, i));
}
static void rw_node(inline_ctx_t *c, spl_ir_node_t *n) {
switch (n->kind) {
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:
n->arith.left = rw(c, n->arith.left);
n->arith.right = rw(c, n->arith.right);
break;
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:
n->cmp.a = rw(c, n->cmp.a);
n->cmp.b = rw(c, n->cmp.b);
break;
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:
n->cast.val = rw(c, n->cast.val);
break;
case SPL_IR_MEM_ALLOCA:
n->mem_alloc.count = rw(c, n->mem_alloc.count);
break;
case SPL_IR_MEM_GLOBAL_ALLOC:
n->mem_global_alloc.const_node = rw(c, n->mem_global_alloc.const_node);
break;
case SPL_IR_MEM_LOAD:
n->mem_load.ptr = rw(c, n->mem_load.ptr);
break;
case SPL_IR_MEM_STORE:
n->mem_store.ptr = rw(c, n->mem_store.ptr);
n->mem_store.val = rw(c, n->mem_store.val);
break;
case SPL_IR_MEM_OFFSET:
n->mem_offset.ptr = rw(c, n->mem_offset.ptr);
n->mem_offset.offset = rw(c, n->mem_offset.offset);
break;
case SPL_IR_MEM_FIELD_PTR:
n->mem_field_ptr.agg = rw(c, n->mem_field_ptr.agg);
break;
case SPL_IR_MEM_COPY:
n->mem_copy.dst = rw(c, n->mem_copy.dst);
n->mem_copy.src = rw(c, n->mem_copy.src);
n->mem_copy.size = rw(c, n->mem_copy.size);
break;
case SPL_IR_MEM_SET:
n->mem_set.dst = rw(c, n->mem_set.dst);
n->mem_set.val = rw(c, n->mem_set.val);
n->mem_set.size = rw(c, n->mem_set.size);
break;
case SPL_IR_TYPE_OFFSETOF:
n->ir_offsetof.field_idx = rw(c, n->ir_offsetof.field_idx);
break;
case SPL_IR_AGG_CONSTRUCT:
rw_vec(c, &n->agg_construct.fields);
break;
case SPL_IR_AGG_EXTRACT:
n->agg_extract.val = rw(c, n->agg_extract.val);
break;
case SPL_IR_AGG_INSERT:
n->agg_insert.agg = rw(c, n->agg_insert.agg);
n->agg_insert.field = rw(c, n->agg_insert.field);
break;
case SPL_IR_CONTROL_SELECT:
n->control_select.cond = rw(c, n->control_select.cond);
n->control_select.true_val = rw(c, n->control_select.true_val);
n->control_select.false_val = rw(c, n->control_select.false_val);
break;
case SPL_IR_CONTROL_BR:
n->control_br.cond = rw(c, n->control_br.cond);
n->control_br.true_label = rw(c, n->control_br.true_label);
n->control_br.false_label = rw(c, n->control_br.false_label);
break;
case SPL_IR_CONTROL_JMP:
n->control_jmp.label = rw(c, n->control_jmp.label);
break;
case SPL_IR_CONTROL_PARAM:
n->control_param.idx = rw(c, n->control_param.idx);
break;
case SPL_IR_CONTROL_RET:
n->control_ret.val = rw(c, n->control_ret.val);
break;
case SPL_IR_CONTROL_CALL:
n->control_call.func = rw(c, n->control_call.func);
rw_vec(c, &n->control_call.params);
break;
default:
break;
}
}
/* ---- 克隆 ---- */
static void clone_ref_vec(spl_ir_node_ref_vec_t *dst, const spl_ir_node_ref_vec_t *src) {
dst->size = 0;
dst->cap = 0;
dst->data = NULL;
usize n = vec_size(*src);
if (n == 0)
return;
spl_ir_node_ref_t *p = (spl_ir_node_ref_t *)malloc(sizeof(spl_ir_node_ref_t) * n);
if (!p)
return;
memcpy(p, src->data, sizeof(spl_ir_node_ref_t) * n);
dst->data = p;
dst->size = n;
dst->cap = n;
}
static void clone_node(spl_ir_t *ir, spl_ir_func_ref_t caller, spl_ir_node_ref_t dst_ref,
const spl_ir_node_t *src) {
spl_ir_node_t *dst = nd(ir, caller, dst_ref);
memcpy(dst, src, sizeof(*dst));
dst->attrs.data = NULL;
dst->attrs.size = 0;
dst->attrs.cap = 0;
if (vec_size(src->attrs) != 0)
clone_ref_vec((spl_ir_node_ref_vec_t *)&dst->attrs,
(const spl_ir_node_ref_vec_t *)&src->attrs);
if (src->kind == SPL_IR_AGG_CONSTRUCT)
clone_ref_vec(&dst->agg_construct.fields, &src->agg_construct.fields);
else if (src->kind == SPL_IR_CONTROL_CALL)
clone_ref_vec(&dst->control_call.params, &src->control_call.params);
}
/* ---- 调用图可达性(防环) ---- */
static spl_ir_func_ref_t call_callee(spl_ir_t *ir, spl_ir_func_ref_t fid, spl_ir_node_t *call) {
spl_ir_node_t *fn = nd(ir, fid, call->control_call.func);
if (!fn || fn->kind != SPL_IR_TYPE_CONST)
return 0;
return fn->type_const.fn;
}
static bool reaches(spl_ir_t *ir, spl_ir_func_ref_t from, spl_ir_func_ref_t target,
unsigned char *mark) {
if (from == 0)
return false;
if (from == target)
return true;
if (mark[from])
return false;
mark[from] = 1;
spl_ir_func_t *f = spl_ir_func(ir, from);
if (!f)
return false;
usize n = vec_size(f->nodes);
for (usize i = 1; i < n; i++) {
spl_ir_node_t *x = nd(ir, from, i);
if (x && x->kind == SPL_IR_CONTROL_CALL) {
spl_ir_func_ref_t c = call_callee(ir, from, x);
if (c != 0 && reaches(ir, c, target, mark))
return true;
}
}
return false;
}
/* 从 from 的直接被调者出发是否能到达 target(用于判断 from 自身是否递归/自可达)。 */
static bool reaches_succ(spl_ir_t *ir, spl_ir_func_ref_t from, spl_ir_func_ref_t target,
unsigned char *mark) {
spl_ir_func_t *f = spl_ir_func(ir, from);
if (!f)
return false;
usize n = vec_size(f->nodes);
for (usize i = 1; i < n; i++) {
spl_ir_node_t *x = nd(ir, from, i);
if (x && x->kind == SPL_IR_CONTROL_CALL) {
spl_ir_func_ref_t c = call_callee(ir, from, x);
if (c != 0 && reaches(ir, c, target, mark))
return true;
}
}
return false;
}
/* ---- 内联一个调用点 ---- */
typedef struct {
spl_ir_node_ref_t clone_ref;
spl_ir_node_ref_t val;
} ret_rec_t;
static bool param_index(spl_ir_t *ir, spl_ir_func_ref_t fid, spl_ir_node_t *p, usize *out) {
spl_ir_node_t *idx = nd(ir, fid, p->control_param.idx);
if (!idx || idx->kind != SPL_IR_TYPE_CONST)
return false;
*out = idx->type_const.int_lit;
return true;
}
static spl_ir_node_ref_t find_const_src(spl_ir_t *ir, spl_ir_func_ref_t fid) {
spl_ir_func_t *f = spl_ir_func(ir, fid);
if (!f)
return 0;
for (usize i = 1; i < vec_size(f->nodes); i++) {
spl_ir_node_t *x = nd(ir, fid, i);
if (x && x->kind == SPL_IR_TYPE_CONST)
return i;
}
return 0;
}
static bool try_inline(spl_ir_t *ir, spl_ir_func_ref_t caller, spl_ir_node_ref_t ci,
spl_ir_func_ref_t callee) {
spl_ir_func_t *cf = spl_ir_func(ir, caller);
spl_ir_func_t *calf = spl_ir_func(ir, callee);
if (!cf || !calf || callee == caller)
return false;
spl_ir_node_t *call = nd(ir, caller, ci);
if (!call || call->kind != SPL_IR_CONTROL_CALL)
return false;
usize orig_len = vec_size(cf->nodes);
if (ci + 1 >= orig_len)
return false;
usize nargs = vec_size(call->control_call.params);
/* 统计参数与返回,分配动态映射。 */
usize cnodes = vec_size(calf->nodes);
usize in_params = 0;
usize in_rets = 0;
for (usize i = 1; i < cnodes; i++) {
spl_ir_node_t *x = nd(ir, callee, i);
if (!x)
return false;
if (x->kind == SPL_IR_CONTROL_PARAM)
in_params++;
else if (x->kind == SPL_IR_CONTROL_RET)
in_rets++;
}
if (in_rets == 0 || in_params != nargs)
return false;
inline_ctx_t c;
memset(&c, 0, sizeof(c));
c.ir = ir;
c.caller = caller;
c.callee = callee;
c.nparams = in_params;
c.param_ref = (spl_ir_node_ref_t *)malloc(sizeof(spl_ir_node_ref_t) * (in_params ? in_params : 1));
c.param_arg = (spl_ir_node_ref_t *)malloc(sizeof(spl_ir_node_ref_t) * (in_params ? in_params : 1));
ret_rec_t *recs = (ret_rec_t *)malloc(sizeof(ret_rec_t) * (in_rets ? in_rets : 1));
if (!c.param_ref || !c.param_arg || !recs) {
free(c.param_ref);
free(c.param_arg);
free(recs);
return false;
}
spl_type_id_t ret_tid = call->control_call.tid;
/* 参数映射(旧 ref -> 实参 ref)。 */
usize pi = 0;
for (usize i = 1; i < cnodes; i++) {
spl_ir_node_t *x = nd(ir, callee, i);
if (x && x->kind == SPL_IR_CONTROL_PARAM) {
usize idx = 0;
if (!param_index(ir, callee, x, &idx) || idx >= nargs) {
free(c.param_ref);
free(c.param_arg);
free(recs);
return false;
}
c.param_ref[pi] = i;
c.param_arg[pi] = vec_at(call->control_call.params, idx);
pi++;
}
}
bool has_val = false;
for (usize i = 1; i < cnodes; i++) {
spl_ir_node_t *x = nd(ir, callee, i);
if (x && x->kind == SPL_IR_CONTROL_RET && x->control_ret.val != 0)
has_val = true;
}
spl_ir_node_ref_t const_src = find_const_src(ir, callee);
if (has_val && const_src == 0) {
free(c.param_ref);
free(c.param_arg);
free(recs);
return false;
}
/* 释放调用点原 params(随后 ci 改为 jmp) */
vec_free(call->control_call.params);
/* 克隆体入口前置:常量 1 + ret 槽 */
spl_ir_node_ref_t body_entry = 0;
spl_ir_node_ref_t slot_ref = 0;
if (has_val) {
spl_ir_node_ref_t c_ref = spl_ir_alloc_node(ir, caller);
clone_node(ir, caller, c_ref, nd(ir, callee, const_src));
spl_ir_node_t *cn = nd(ir, caller, c_ref);
cn->kind = SPL_IR_TYPE_CONST;
cn->type_const.int_lit = 1;
slot_ref = spl_ir_alloc_node(ir, caller);
spl_ir_node_t *sn = nd(ir, caller, slot_ref);
memset(sn, 0, sizeof(*sn));
sn->kind = SPL_IR_MEM_ALLOCA;
sn->mem_alloc.tid = ret_tid;
sn->mem_alloc.count = c_ref;
body_entry = c_ref;
}
c.shift = vec_size(cf->nodes) - 1;
if (!has_val)
body_entry = vec_size(cf->nodes);
/* 克隆体 */
usize nrec = 0;
for (usize i = 1; i < cnodes; i++) {
spl_ir_node_ref_t dst_ref = spl_ir_alloc_node(ir, caller);
if (dst_ref == 0) {
free(c.param_ref);
free(c.param_arg);
free(recs);
return false;
}
spl_ir_node_t *src = nd(ir, callee, i);
clone_node(ir, caller, dst_ref, src);
rw_node(&c, nd(ir, caller, dst_ref));
spl_ir_node_t *x = nd(ir, caller, dst_ref);
/* 克隆进来的 Param 使用处已替换为实参,节点本身不能留在调用者里
* 改变其参数个数;退化为无害常量。 */
if (src->kind == SPL_IR_CONTROL_PARAM) {
x->kind = SPL_IR_TYPE_CONST;
x->type_const.tid = 0;
x->type_const.int_lit = 0;
continue;
}
if (x->kind == SPL_IR_CONTROL_RET) {
recs[nrec].clone_ref = dst_ref;
recs[nrec].val = x->control_ret.val;
nrec++;
x->kind = SPL_IR_CONTROL_JMP;
x->control_jmp.label = 0; /* 稍后回填 */
}
}
spl_ir_node_ref_t ret_new = 0;
if (has_val) {
spl_ir_node_ref_t join = spl_ir_alloc_node(ir, caller);
spl_ir_node_t *jn = nd(ir, caller, join);
memset(jn, 0, sizeof(*jn));
jn->kind = SPL_IR_MEM_LOAD;
jn->mem_load.tid = ret_tid;
jn->mem_load.ptr = slot_ref;
/* join 之后跳回调用点的后继(原代码此处靠 fallthrough)。 */
spl_ir_node_ref_t jc = spl_ir_alloc_node(ir, caller);
spl_ir_node_t *jcn = nd(ir, caller, jc);
memset(jcn, 0, sizeof(*jcn));
jcn->kind = SPL_IR_CONTROL_JMP;
jcn->control_jmp.label = ci + 1;
for (usize k = 0; k < nrec; k++) {
spl_ir_node_ref_t st = spl_ir_alloc_node(ir, caller);
spl_ir_node_t *stn = nd(ir, caller, st);
memset(stn, 0, sizeof(*stn));
stn->kind = SPL_IR_MEM_STORE;
stn->mem_store.tid = ret_tid;
stn->mem_store.ptr = slot_ref;
stn->mem_store.val = recs[k].val;
spl_ir_node_ref_t jr = spl_ir_alloc_node(ir, caller);
spl_ir_node_t *jrn = nd(ir, caller, jr);
memset(jrn, 0, sizeof(*jrn));
jrn->kind = SPL_IR_CONTROL_JMP;
jrn->control_jmp.label = join;
spl_ir_node_t *rn = nd(ir, caller, recs[k].clone_ref);
rn->control_jmp.label = st;
}
ret_new = join;
} else {
for (usize k = 0; k < nrec; k++) {
spl_ir_node_t *rn = nd(ir, caller, recs[k].clone_ref);
rn->control_jmp.label = ci + 1;
}
}
/* 调用点 -> jmp 到克隆体入口 */
call = nd(ir, caller, ci);
call->kind = SPL_IR_CONTROL_JMP;
call->control_jmp.label = body_entry;
/* 使用者替换:只把等于 ci 的引用改为 ret_new(不动其它 ref) */
for (usize j = 1; j < orig_len; j++) {
spl_ir_node_t *x = nd(ir, caller, j);
if (!x)
continue;
switch (x->kind) {
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:
if (x->arith.left == ci) x->arith.left = ret_new;
if (x->arith.right == ci) x->arith.right = ret_new;
break;
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:
if (x->cmp.a == ci) x->cmp.a = ret_new;
if (x->cmp.b == ci) x->cmp.b = ret_new;
break;
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:
if (x->cast.val == ci) x->cast.val = ret_new;
break;
case SPL_IR_MEM_ALLOCA:
if (x->mem_alloc.count == ci) x->mem_alloc.count = ret_new;
break;
case SPL_IR_MEM_GLOBAL_ALLOC:
if (x->mem_global_alloc.const_node == ci) x->mem_global_alloc.const_node = ret_new;
break;
case SPL_IR_MEM_LOAD:
if (x->mem_load.ptr == ci) x->mem_load.ptr = ret_new;
break;
case SPL_IR_MEM_STORE:
if (x->mem_store.ptr == ci) x->mem_store.ptr = ret_new;
if (x->mem_store.val == ci) x->mem_store.val = ret_new;
break;
case SPL_IR_MEM_OFFSET:
if (x->mem_offset.ptr == ci) x->mem_offset.ptr = ret_new;
if (x->mem_offset.offset == ci) x->mem_offset.offset = ret_new;
break;
case SPL_IR_MEM_FIELD_PTR:
if (x->mem_field_ptr.agg == ci) x->mem_field_ptr.agg = ret_new;
break;
case SPL_IR_MEM_COPY:
if (x->mem_copy.dst == ci) x->mem_copy.dst = ret_new;
if (x->mem_copy.src == ci) x->mem_copy.src = ret_new;
if (x->mem_copy.size == ci) x->mem_copy.size = ret_new;
break;
case SPL_IR_MEM_SET:
if (x->mem_set.dst == ci) x->mem_set.dst = ret_new;
if (x->mem_set.val == ci) x->mem_set.val = ret_new;
if (x->mem_set.size == ci) x->mem_set.size = ret_new;
break;
case SPL_IR_TYPE_OFFSETOF:
if (x->ir_offsetof.field_idx == ci) x->ir_offsetof.field_idx = ret_new;
break;
case SPL_IR_AGG_CONSTRUCT:
for (usize k = 0; k < vec_size(x->agg_construct.fields); k++)
if (vec_at(x->agg_construct.fields, k) == ci)
vec_at(x->agg_construct.fields, k) = ret_new;
break;
case SPL_IR_AGG_EXTRACT:
if (x->agg_extract.val == ci) x->agg_extract.val = ret_new;
break;
case SPL_IR_AGG_INSERT:
if (x->agg_insert.agg == ci) x->agg_insert.agg = ret_new;
if (x->agg_insert.field == ci) x->agg_insert.field = ret_new;
break;
case SPL_IR_CONTROL_SELECT:
if (x->control_select.cond == ci) x->control_select.cond = ret_new;
if (x->control_select.true_val == ci) x->control_select.true_val = ret_new;
if (x->control_select.false_val == ci) x->control_select.false_val = ret_new;
break;
case SPL_IR_CONTROL_BR:
if (x->control_br.cond == ci) x->control_br.cond = ret_new;
break;
case SPL_IR_CONTROL_CALL:
if (x->control_call.func == ci) x->control_call.func = ret_new;
for (usize k = 0; k < vec_size(x->control_call.params); k++)
if (vec_at(x->control_call.params, k) == ci)
vec_at(x->control_call.params, k) = ret_new;
break;
case SPL_IR_CONTROL_PARAM:
if (x->control_param.idx == ci) x->control_param.idx = ret_new;
break;
case SPL_IR_CONTROL_RET:
if (x->control_ret.val == ci) x->control_ret.val = ret_new;
break;
default:
break;
}
}
free(c.param_ref);
free(c.param_arg);
free(recs);
return true;
}
static bool func_has_attr(const spl_attr_t *attr, const spl_ir_func_t *f, const char *name);
static int opt_function(spl_ir_t *ir, spl_ir_func_ref_t fid, const spl_attr_t *attr,
unsigned char *mark, usize nfuncs) {
spl_ir_func_t *f = spl_ir_func(ir, fid);
if (!f)
return 0;
int done = 0;
usize orig = vec_size(f->nodes);
for (usize ci = 1; ci < orig; ci++) {
spl_ir_node_t *x = nd(ir, fid, ci);
if (!x || x->kind != SPL_IR_CONTROL_CALL)
continue;
spl_ir_func_ref_t callee = call_callee(ir, fid, x);
if (callee == 0 || callee == fid || callee >= nfuncs)
continue;
spl_ir_func_t *calf = spl_ir_func(ir, callee);
if (!func_has_attr(attr, calf, "inline") || func_has_attr(attr, calf, "noinline"))
continue;
/* extern 是占位体,绝不能内联。 */
if (func_has_attr(attr, calf, "extern"))
continue;
/* 防环:callee 传递可达 caller 时拒绝(覆盖直接/间接互递归)。 */
memset(mark, 0, nfuncs);
if (reaches(ir, callee, fid, mark))
continue;
/* 防爆炸:callee 自身递归时拒绝(否则不动点会反复内联其内部调用)。 */
memset(mark, 0, nfuncs);
if (reaches_succ(ir, callee, callee, mark))
continue;
if (try_inline(ir, fid, ci, callee))
done++;
}
return done;
}
/* 是否带有指定名字的属性/tag。 */
static bool func_has_attr(const spl_attr_t *attr, const spl_ir_func_t *f, const char *name) {
if (!attr || !f)
return false;
for (usize i = 0; i < vec_size(f->attrs); ++i) {
spl_attr_node_t *a = spl_attr_node((spl_attr_t *)attr, vec_at(f->attrs, i));
if (!a || !a->info)
continue;
if (strcmp(a->info->name, name) == 0)
return true;
}
return false;
}
void spl_ir_opt(spl_ir_t *ir, const spl_attr_t *attr) {
if (!ir)
return;
usize nfuncs = vec_size(ir->funcs);
unsigned char *mark = (unsigned char *)malloc(nfuncs ? nfuncs : 1);
if (!mark)
return;
/* 无环调用图上,最多 nfuncs 轮即可到不动点。 */
for (usize pass = 0; pass <= nfuncs; pass++) {
int total = 0;
usize n = vec_size(ir->funcs);
for (spl_ir_func_ref_t fid = 1; fid < n && fid < nfuncs; fid++)
total += opt_function(ir, fid, attr, mark, nfuncs);
if (total == 0)
break;
}
free(mark);
}
+11
View File
@@ -0,0 +1,11 @@
#ifndef __IR_OPT_H__
#define __IR_OPT_H__
/* IR 层优化 pass:输入输出都是 spl_ir_t(节点 arena),纯函数式、可开关。
* 由 splc0 --opt 在 ast2ir 之后、ir2vm 之前调用。 */
#include "spl_ir.h"
void spl_ir_opt(spl_ir_t *ir, const spl_attr_t *attr);
#endif /* __IR_OPT_H__ */
+319 -34
View File
@@ -344,6 +344,13 @@ typedef struct {
frame_layout_t frame; frame_layout_t frame;
VEC(usize) node_ip; VEC(usize) node_ip;
fix_vec_t *fixups; fix_vec_t *fixups;
/* 块内栈化(opt) */
int opt;
uint8_t *stk_loc; /* per node: 1 = 值当前在操作数栈上 */
usize *stk_pos; /* 在虚拟栈中的位置 */
usize *use_left; /* 剩余使用次数 */
usize *at_pos; /* 每个栈位置对应的 node ref */
usize tracked; /* 当前栈上被跟踪的值个数 */
} cgen_t; } cgen_t;
static void emit(cgen_t *cg, uint8_t op, uint8_t ty, spl_vm_val_t imm) { static void emit(cgen_t *cg, uint8_t op, uint8_t ty, spl_vm_val_t imm) {
@@ -378,6 +385,240 @@ static void cg_store_at(cgen_t *cg, usize addr, uint8_t k) {
CG_STORE(cg, k); CG_STORE(cg, k);
} }
/* ---------- 块内栈化(opt)辅助 ---------- */
static uint8_t node_result_kind(cgen_t *cg, usize ref) {
const spl_ir_node_t *n = &vec_at(cg->irf->nodes, ref);
return vm_kind_of(cg->ctx, ir_result_tid(cg->ctx, n));
}
static bool node_stackable(cgen_t *cg, const spl_ir_node_t *n) {
switch (n->kind) {
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_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:
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:
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:
case SPL_IR_TYPE_CONST: {
spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->type_const.tid);
return tn && tn->kind != SPL_TYPE_UNIT;
}
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:
case SPL_IR_MEM_OFFSET:
case SPL_IR_MEM_FIELD_PTR:
return true;
case SPL_IR_MEM_LOAD:
return !ir_is_aggregate(cg->ctx, n->mem_load.tid);
default:
return false;
}
}
/* 该节点必须使用槽(直接按槽偏移读写 / 控制转移 / 聚合数据),生成前需 flush。 */
static bool node_needs_slots(cgen_t *cg, const spl_ir_node_t *n) {
switch (n->kind) {
case SPL_IR_MEM_ALLOCA:
case SPL_IR_MEM_GLOBAL_ALLOC:
case SPL_IR_MEM_COPY:
case SPL_IR_MEM_SET:
case SPL_IR_AGG_CONSTRUCT:
case SPL_IR_AGG_EXTRACT:
case SPL_IR_AGG_INSERT:
case SPL_IR_CONTROL_SELECT:
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_PANIC:
case SPL_IR_DBG_BREAKPOINT:
return true;
case SPL_IR_MEM_LOAD:
return ir_is_aggregate(cg->ctx, n->mem_load.tid);
case SPL_IR_MEM_STORE:
return ir_is_aggregate(cg->ctx, n->mem_store.tid);
default:
return false;
}
}
/* 取操作数到 TOS:若在栈上就 PICK,否则从槽 load。j = 本节点已压入的操作数个数。 */
static void cg_operand(cgen_t *cg, usize ref, uint8_t k, usize j) {
if (cg->opt) {
if (cg->use_left[ref] > 0)
cg->use_left[ref]--;
if (cg->stk_loc[ref]) {
/* 始终复制一份到 TOS,绝不消费栈上的“被跟踪原值”,否则位置模型失效。 */
usize dist = cg->tracked + j - 1 - cg->stk_pos[ref];
emit(cg, SPL_PICK, SPL_VOID, dist);
return;
}
}
cg_load_slot(cg, ref, k);
}
/* 节点结果:若仍会被使用则留在栈上,否则 DROP。 */
static void cg_result(cgen_t *cg, usize ref, uint8_t k) {
if (cg->opt) {
if (cg->use_left[ref] > 0) {
cg->stk_loc[ref] = 1;
cg->stk_pos[ref] = cg->tracked;
cg->at_pos[cg->tracked] = ref;
cg->tracked++;
} else {
emit(cg, SPL_DROP, SPL_VOID, 0);
}
return;
}
cg_store_slot(cg, ref, k);
}
/* 把栈上仍存活的值溢出回各自槽(TOS 起),死值 DROP;清空跟踪。 */
static void cg_flush(cgen_t *cg) {
if (!cg->opt)
return;
while (cg->tracked > 0) {
cg->tracked--;
usize r = cg->at_pos[cg->tracked];
cg->stk_loc[r] = 0;
if (cg->use_left[r] > 0) {
uint8_t k = node_result_kind(cg, r);
cg_store_slot(cg, r, k);
} else {
emit(cg, SPL_DROP, SPL_VOID, 0);
}
}
}
/* 统计被引用次数(所有节点载荷中的 node ref)。 */
static void count_ref(cgen_t *cg, usize r) {
if (r != 0 && r < vec_size(cg->irf->nodes))
cg->use_left[r]++;
}
static void count_refs_vec(cgen_t *cg, const spl_ir_node_ref_vec_t *v) {
for (usize i = 0; i < vec_size(*v); i++)
count_ref(cg, vec_at(*v, i));
}
static void count_refs(cgen_t *cg, const spl_ir_node_t *n) {
switch (n->kind) {
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:
count_ref(cg, n->arith.left);
count_ref(cg, n->arith.right);
break;
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:
count_ref(cg, n->cmp.a);
count_ref(cg, n->cmp.b);
break;
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:
count_ref(cg, n->cast.val);
break;
case SPL_IR_MEM_ALLOCA:
count_ref(cg, n->mem_alloc.count);
break;
case SPL_IR_MEM_GLOBAL_ALLOC:
count_ref(cg, n->mem_global_alloc.const_node);
break;
case SPL_IR_MEM_LOAD:
count_ref(cg, n->mem_load.ptr);
break;
case SPL_IR_MEM_STORE:
count_ref(cg, n->mem_store.ptr);
count_ref(cg, n->mem_store.val);
break;
case SPL_IR_MEM_OFFSET:
count_ref(cg, n->mem_offset.ptr);
count_ref(cg, n->mem_offset.offset);
break;
case SPL_IR_MEM_FIELD_PTR:
count_ref(cg, n->mem_field_ptr.agg);
break;
case SPL_IR_MEM_COPY:
count_ref(cg, n->mem_copy.dst);
count_ref(cg, n->mem_copy.src);
count_ref(cg, n->mem_copy.size);
break;
case SPL_IR_MEM_SET:
count_ref(cg, n->mem_set.dst);
count_ref(cg, n->mem_set.val);
count_ref(cg, n->mem_set.size);
break;
case SPL_IR_TYPE_OFFSETOF:
count_ref(cg, n->ir_offsetof.field_idx);
break;
case SPL_IR_AGG_CONSTRUCT:
count_refs_vec(cg, &n->agg_construct.fields);
break;
case SPL_IR_AGG_EXTRACT:
count_ref(cg, n->agg_extract.val);
break;
case SPL_IR_AGG_INSERT:
count_ref(cg, n->agg_insert.agg);
count_ref(cg, n->agg_insert.field);
break;
case SPL_IR_CONTROL_SELECT:
count_ref(cg, n->control_select.cond);
count_ref(cg, n->control_select.true_val);
count_ref(cg, n->control_select.false_val);
break;
case SPL_IR_CONTROL_BR:
count_ref(cg, n->control_br.cond);
count_ref(cg, n->control_br.true_label);
count_ref(cg, n->control_br.false_label);
break;
case SPL_IR_CONTROL_JMP:
count_ref(cg, n->control_jmp.label);
break;
case SPL_IR_CONTROL_CALL:
count_ref(cg, n->control_call.func);
count_refs_vec(cg, &n->control_call.params);
break;
case SPL_IR_CONTROL_PARAM:
count_ref(cg, n->control_param.idx);
break;
case SPL_IR_CONTROL_RET:
count_ref(cg, n->control_ret.val);
break;
default:
break;
}
}
typedef struct { typedef struct {
bool indirect; bool indirect;
usize off; usize off;
@@ -439,25 +680,25 @@ static void cg_add_fix(cgen_t *cg, usize ins_idx, fix_kind_t kind, spl_ir_node_r
static void cg_binop(cgen_t *cg, usize ref, const spl_ir_node_t *n, uint8_t op) { static void cg_binop(cgen_t *cg, usize ref, const spl_ir_node_t *n, uint8_t op) {
uint8_t k = vm_kind_of(cg->ctx, n->arith.tid); uint8_t k = vm_kind_of(cg->ctx, n->arith.tid);
cg_load_slot(cg, n->arith.left, k); cg_operand(cg, n->arith.left, k, 0);
cg_load_slot(cg, n->arith.right, k); cg_operand(cg, n->arith.right, k, 1);
CG_OP(cg, op, k); CG_OP(cg, op, k);
cg_store_slot(cg, ref, k); cg_result(cg, ref, k);
} }
static void cg_unop(cgen_t *cg, usize ref, const spl_ir_node_t *n, uint8_t op) { static void cg_unop(cgen_t *cg, usize ref, const spl_ir_node_t *n, uint8_t op) {
uint8_t k = vm_kind_of(cg->ctx, n->arith.tid); uint8_t k = vm_kind_of(cg->ctx, n->arith.tid);
cg_load_slot(cg, n->arith.left, k); cg_operand(cg, n->arith.left, k, 0);
CG_OP(cg, op, k); CG_OP(cg, op, k);
cg_store_slot(cg, ref, k); cg_result(cg, ref, k);
} }
static void cg_cmp(cgen_t *cg, usize ref, const spl_ir_node_t *n, uint8_t op) { static void cg_cmp(cgen_t *cg, usize ref, const spl_ir_node_t *n, uint8_t op) {
uint8_t k = vm_kind_of(cg->ctx, n->cmp.tid); uint8_t k = vm_kind_of(cg->ctx, n->cmp.tid);
cg_load_slot(cg, n->cmp.a, k); cg_operand(cg, n->cmp.a, k, 0);
cg_load_slot(cg, n->cmp.b, k); cg_operand(cg, n->cmp.b, k, 1);
CG_OP(cg, op, k); CG_OP(cg, op, k);
cg_store_slot(cg, ref, SPL_BOOL); cg_result(cg, ref, SPL_BOOL);
} }
static void cg_const(cgen_t *cg, usize ref, const spl_ir_node_t *n) { static void cg_const(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
@@ -479,7 +720,7 @@ static void cg_const(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
CG_PUSH(cg, SPL_PTR, 0); CG_PUSH(cg, SPL_PTR, 0);
cg_add_fix(cg, idx, FIX_FNADDR, 0, n->type_const.fn); cg_add_fix(cg, idx, FIX_FNADDR, 0, n->type_const.fn);
} }
cg_store_slot(cg, ref, SPL_PTR); cg_result(cg, ref, SPL_PTR);
return; return;
} }
@@ -507,7 +748,7 @@ static void cg_const(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
break; break;
} }
CG_PUSH(cg, k, imm); CG_PUSH(cg, k, imm);
cg_store_slot(cg, ref, k); cg_result(cg, ref, k);
} }
static void cg_cast(cgen_t *cg, usize ref, const spl_ir_node_t *n) { static void cg_cast(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
@@ -520,7 +761,7 @@ static void cg_cast(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
uint8_t fk = vm_kind_of(ctx, n->cast.from_tid); uint8_t fk = vm_kind_of(ctx, n->cast.from_tid);
uint8_t tk = vm_kind_of(ctx, n->cast.to_tid); uint8_t tk = vm_kind_of(ctx, n->cast.to_tid);
cg_load_slot(cg, n->cast.val, fk); cg_operand(cg, n->cast.val, fk, 0);
if (ft->kind == SPL_TYPE_INT && tt->kind == SPL_TYPE_INT) { if (ft->kind == SPL_TYPE_INT && tt->kind == SPL_TYPE_INT) {
usize fb = ft->int_type.bits; usize fb = ft->int_type.bits;
@@ -533,7 +774,7 @@ static void cg_cast(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
emit(cg, SPL_ZEXT, SPL_VOID, 1); emit(cg, SPL_ZEXT, SPL_VOID, 1);
} }
cg_store_slot(cg, ref, tk); cg_result(cg, ref, tk);
} }
static void cg_mem(cgen_t *cg, usize ref, const spl_ir_node_t *n) { static void cg_mem(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
@@ -571,9 +812,9 @@ static void cg_mem(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
cg_store_slot(cg, ref, SPL_PTR); cg_store_slot(cg, ref, SPL_PTR);
} else { } else {
uint8_t k = vm_kind_of(ctx, tid); uint8_t k = vm_kind_of(ctx, tid);
cg_load_slot(cg, n->mem_load.ptr, SPL_PTR); cg_operand(cg, n->mem_load.ptr, SPL_PTR, 0);
CG_LOAD(cg, k); CG_LOAD(cg, k);
cg_store_slot(cg, ref, k); cg_result(cg, ref, k);
} }
break; break;
} }
@@ -585,8 +826,8 @@ static void cg_mem(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
ptr_slot(vec_at(cg->frame.slots, n->mem_store.ptr).result_off), tid); ptr_slot(vec_at(cg->frame.slots, n->mem_store.ptr).result_off), tid);
} else { } else {
uint8_t k = vm_kind_of(ctx, tid); uint8_t k = vm_kind_of(ctx, tid);
cg_load_slot(cg, n->mem_store.ptr, SPL_PTR); cg_operand(cg, n->mem_store.ptr, SPL_PTR, 0);
cg_load_slot(cg, n->mem_store.val, k); cg_operand(cg, n->mem_store.val, k, 1);
CG_STORE(cg, k); CG_STORE(cg, k);
} }
break; break;
@@ -596,24 +837,24 @@ static void cg_mem(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
usize elem_size = ir_type_size(ctx, n->mem_offset.tid); usize elem_size = ir_type_size(ctx, n->mem_offset.tid);
if (elem_size == 0) if (elem_size == 0)
elem_size = 1; elem_size = 1;
cg_load_slot(cg, n->mem_offset.ptr, SPL_PTR); cg_operand(cg, n->mem_offset.ptr, SPL_PTR, 0);
cg_load_slot(cg, n->mem_offset.offset, SPL_U64); cg_operand(cg, n->mem_offset.offset, SPL_U64, 1);
CG_PUSH(cg, SPL_U64, elem_size); CG_PUSH(cg, SPL_U64, elem_size);
CG_OP(cg, SPL_MUL, SPL_U64); CG_OP(cg, SPL_MUL, SPL_U64);
CG_OP(cg, SPL_ADD, SPL_PTR); CG_OP(cg, SPL_ADD, SPL_PTR);
cg_store_slot(cg, ref, SPL_PTR); cg_result(cg, ref, SPL_PTR);
break; break;
} }
case SPL_IR_MEM_FIELD_PTR: { case SPL_IR_MEM_FIELD_PTR: {
spl_type_id_t agg_tid = n->mem_field_ptr.tid; spl_type_id_t agg_tid = n->mem_field_ptr.tid;
usize off = ir_agg_field_off(ctx, agg_tid, n->mem_field_ptr.field_idx); usize off = ir_agg_field_off(ctx, agg_tid, n->mem_field_ptr.field_idx);
cg_load_slot(cg, n->mem_field_ptr.agg, SPL_PTR); cg_operand(cg, n->mem_field_ptr.agg, SPL_PTR, 0);
if (off) { if (off) {
CG_PUSH(cg, SPL_U64, off); CG_PUSH(cg, SPL_U64, off);
CG_OP(cg, SPL_ADD, SPL_PTR); CG_OP(cg, SPL_ADD, SPL_PTR);
} }
cg_store_slot(cg, ref, SPL_PTR); cg_result(cg, ref, SPL_PTR);
break; break;
} }
@@ -742,7 +983,7 @@ static void cg_typeop(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
return; return;
} }
CG_PUSH(cg, SPL_U64, v); CG_PUSH(cg, SPL_U64, v);
cg_store_slot(cg, ref, SPL_U64); cg_result(cg, ref, SPL_U64);
} }
static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) { static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
@@ -829,44 +1070,47 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref); const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref);
spl_type_id_t ptid = ir_result_tid(ctx, pn); spl_type_id_t ptid = ir_result_tid(ctx, pn);
uint8_t pk = vm_kind_of(ctx, ptid); uint8_t pk = vm_kind_of(ctx, ptid);
cg_load_slot(cg, pref, pk); cg_operand(cg, pref, pk, i);
} }
CG_PUSH(cg, SPL_U64, (spl_vm_val_t)nat_idx); CG_PUSH(cg, SPL_U64, (spl_vm_val_t)nat_idx);
emit(cg, SPL_NCALL, SPL_VOID, (spl_vm_val_t)nargs); emit(cg, SPL_NCALL, SPL_VOID, (spl_vm_val_t)nargs);
uint8_t rk = vm_kind_of(ctx, n->control_call.tid); uint8_t rk = vm_kind_of(ctx, n->control_call.tid);
if (rk == SPL_VOID) if (rk == SPL_VOID)
emit(cg, SPL_DROP, SPL_VOID, 0); /* NCALL 总是 push 一个结果 */ emit(cg, SPL_DROP, SPL_VOID, 0); /* NCALL always push result */
else else
cg_store_slot(cg, ref, rk); cg_result(cg, ref, rk);
} else { } else {
spl_type_id_t ret_t = n->control_call.tid; spl_type_id_t ret_t = n->control_call.tid;
bool ret_is_sret = ir_is_aggregate(ctx, ret_t); bool ret_is_sret = ir_is_aggregate(ctx, ret_t);
usize sret_off = 0; usize sret_off = 0;
usize j = 0;
if (ret_is_sret) { if (ret_is_sret) {
sret_off = vec_at(cg->frame.slots, ref).data_off; sret_off = vec_at(cg->frame.slots, ref).data_off;
CG_LADDR(cg, sret_off); CG_LADDR(cg, sret_off);
j = 1;
} }
for (usize i = 0; i < nargs; ++i) { for (usize i = 0; i < nargs; ++i) {
spl_ir_node_ref_t pref = vec_at(n->control_call.params, i); spl_ir_node_ref_t pref = vec_at(n->control_call.params, i);
const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref); const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref);
spl_type_id_t ptid = ir_result_tid(ctx, pn); spl_type_id_t ptid = ir_result_tid(ctx, pn);
uint8_t pk = vm_kind_of(ctx, ptid); uint8_t pk = vm_kind_of(ctx, ptid);
cg_load_slot(cg, pref, pk); cg_operand(cg, pref, pk, j);
j++;
} }
cg_load_slot(cg, fref, SPL_PTR); cg_operand(cg, fref, SPL_PTR, j);
spl_vm_val_t actual_nargs = nargs + (ret_is_sret ? 1 : 0); spl_vm_val_t actual_nargs = nargs + (ret_is_sret ? 1 : 0);
emit(cg, SPL_CALL, SPL_VOID, actual_nargs); emit(cg, SPL_CALL, SPL_VOID, actual_nargs);
if (ret_is_sret) { if (ret_is_sret) {
/* 结果槽保存 sret 指针,后续 agg_extract 把它当聚合首地址 */ /* result slot saves sret pointer */
CG_LADDR(cg, sret_off); CG_LADDR(cg, sret_off);
cg_store_slot(cg, ref, SPL_PTR); cg_result(cg, ref, SPL_PTR);
} else { } else {
uint8_t rk = vm_kind_of(ctx, ret_t); uint8_t rk = vm_kind_of(ctx, ret_t);
if (rk != SPL_VOID) if (rk != SPL_VOID)
cg_store_slot(cg, ref, rk); cg_result(cg, ref, rk);
} }
} }
break; break;
@@ -933,10 +1177,10 @@ static void cg_node(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
case SPL_IR_ARITH_NOT: { case SPL_IR_ARITH_NOT: {
spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->arith.tid); spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->arith.tid);
if (tn && tn->kind == SPL_TYPE_BOOL) { if (tn && tn->kind == SPL_TYPE_BOOL) {
cg_load_slot(cg, n->arith.left, SPL_BOOL); cg_operand(cg, n->arith.left, SPL_BOOL, 0);
CG_PUSH(cg, SPL_BOOL, 0); CG_PUSH(cg, SPL_BOOL, 0);
CG_OP(cg, SPL_EQ, SPL_BOOL); CG_OP(cg, SPL_EQ, SPL_BOOL);
cg_store_slot(cg, ref, SPL_BOOL); cg_result(cg, ref, SPL_BOOL);
} else { } else {
cg_unop(cg, ref, n, SPL_NOT); cg_unop(cg, ref, n, SPL_NOT);
} }
@@ -1098,9 +1342,49 @@ static usize translate_function(spl_ir2vm_t *ctx, spl_ir_func_ref_t fid, fix_vec
for (usize i = 0; i < nnodes; ++i) for (usize i = 0; i < nnodes; ++i)
vec_push(cg.node_ip, 0); vec_push(cg.node_ip, 0);
unsigned char *leader = NULL;
cg.opt = ctx->opt;
if (ctx->opt) {
cg.stk_loc = (uint8_t *)calloc(nnodes, 1);
cg.stk_pos = (usize *)calloc(nnodes, sizeof(usize));
cg.use_left = (usize *)calloc(nnodes, sizeof(usize));
cg.at_pos = (usize *)calloc(nnodes, sizeof(usize));
leader = (unsigned char *)calloc(nnodes, 1);
cg.tracked = 0;
for (usize i = 1; i < nnodes; ++i)
count_refs(&cg, &vec_at(irf->nodes, i));
if (nnodes > 1)
leader[1] = 1;
for (usize i = 1; i < nnodes; ++i) {
const spl_ir_node_t *n = &vec_at(irf->nodes, i);
if (n->kind == SPL_IR_CONTROL_BR) {
if (n->control_br.true_label < nnodes)
leader[n->control_br.true_label] = 1;
if (n->control_br.false_label < nnodes)
leader[n->control_br.false_label] = 1;
} else if (n->kind == SPL_IR_CONTROL_JMP) {
if (n->control_jmp.label < nnodes)
leader[n->control_jmp.label] = 1;
}
}
}
for (usize i = 1; i < nnodes; ++i) { for (usize i = 1; i < nnodes; ++i) {
const spl_ir_node_t *n = &vec_at(irf->nodes, i);
if (cg.opt) {
if (leader[i] || node_needs_slots(&cg, n))
cg_flush(&cg);
}
vec_at(cg.node_ip, i) = ip_of(&cg); vec_at(cg.node_ip, i) = ip_of(&cg);
cg_node(&cg, i, &vec_at(irf->nodes, i)); cg_node(&cg, i, n);
}
if (cg.opt) {
cg_flush(&cg);
free(cg.stk_loc);
free(cg.stk_pos);
free(cg.use_left);
free(cg.at_pos);
free(leader);
} }
for (usize i = 0; i < vec_size(local_fixups); ++i) { for (usize i = 0; i < vec_size(local_fixups); ++i) {
@@ -1124,12 +1408,13 @@ static usize spl_map_hash(usize k) { return MAP_HASH_INT(k); }
static int spl_map_cmp(usize a, usize b) { return MAP_CMP_INT(a, b); } static int spl_map_cmp(usize a, usize b) { return MAP_CMP_INT(a, b); }
void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type, void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type,
spl_layout_t *layout, const spl_attr_t *attr) { spl_layout_t *layout, const spl_attr_t *attr, int opt) {
Assert(ir != NULL && type != NULL && attr != NULL); Assert(ir != NULL && type != NULL && attr != NULL);
ctx->ir = ir; ctx->ir = ir;
ctx->type = type; ctx->type = type;
ctx->attr = attr; ctx->attr = attr;
ctx->layout = layout; ctx->layout = layout;
ctx->opt = opt;
map_init(ctx->extern_native, spl_map_hash, spl_map_cmp); map_init(ctx->extern_native, spl_map_hash, spl_map_cmp);
spl_prog_init(&ctx->prog); spl_prog_init(&ctx->prog);
+2 -1
View File
@@ -25,10 +25,11 @@ typedef struct {
spl_layout_t *layout; /* 借用 splc0 的 layout(size/align/offset 唯一来源) */ spl_layout_t *layout; /* 借用 splc0 的 layout(size/align/offset 唯一来源) */
spl_diag_t *diag; spl_diag_t *diag;
int opt; /* 非 0:块内操作数栈化(表达式临时值留栈,块边界溢出回槽) */
} spl_ir2vm_t; } spl_ir2vm_t;
void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type, void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type,
spl_layout_t *layout, const spl_attr_t *attr); spl_layout_t *layout, const spl_attr_t *attr, int opt);
void spl_ir2vm_drop(spl_ir2vm_t *ctx); void spl_ir2vm_drop(spl_ir2vm_t *ctx);
int spl_ir2vm_run_func(spl_ir2vm_t *ctx, spl_ir_func_ref_t ref); int spl_ir2vm_run_func(spl_ir2vm_t *ctx, spl_ir_func_ref_t ref);
+11 -10
View File
@@ -764,8 +764,7 @@ static void sema_collect_signatures(spl_sema_t *sema) {
spl_def_node_t *d = &vec_at(sema->type->def_table, i); spl_def_node_t *d = &vec_at(sema->type->def_table, i);
/* Nested imports share def_table, but each module has its own scope. /* Nested imports share def_table, but each module has its own scope.
* Resolve other modules' signatures only when processing their AST. */ * Resolve other modules' signatures only when processing their AST. */
if (d->owner_ast == sema->ast && d->kind == SPL_DEF_FN && if (d->owner_ast == sema->ast && d->kind == SPL_DEF_FN && d->state == SPL_DECL_UNRESOLVED)
d->state == SPL_DECL_UNRESOLVED)
sema_eval_decl(sema, i); sema_eval_decl(sema, i);
} }
} }
@@ -830,14 +829,14 @@ static spl_lang_type_id_t sema_infer_type_context(spl_sema_t *sema, spl_ast_node
spl_symbol_t symbol; spl_symbol_t symbol;
if (!spl_scope_find(sema->scope, n->ident.name, &symbol) || if (!spl_scope_find(sema->scope, n->ident.name, &symbol) ||
symbol.kind != SPL_SYMBOL_KIND_TYPE) { symbol.kind != SPL_SYMBOL_KIND_TYPE) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, "`%s` is not a type",
"`%s` is not a type", n->ident.name); n->ident.name);
return 0; return 0;
} }
spl_def_node_t *def = spl_def_node(sema->type, symbol.node); spl_def_node_t *def = spl_def_node(sema->type, symbol.node);
if (!sema_def_is_type(def)) { if (!sema_def_is_type(def)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, "`%s` is not a type",
"`%s` is not a type", n->ident.name); n->ident.name);
return 0; return 0;
} }
n->resolved_def_id = symbol.node; n->resolved_def_id = symbol.node;
@@ -880,16 +879,15 @@ static spl_lang_type_id_t sema_infer_type_context(spl_sema_t *sema, spl_ast_node
spl_lang_type_id_vec_t elements; spl_lang_type_id_vec_t elements;
vec_init(elements); vec_init(elements);
for (usize i = 0; i < vec_size(n->tuple.elems); ++i) { for (usize i = 0; i < vec_size(n->tuple.elems); ++i) {
spl_lang_type_id_t element = spl_lang_type_id_t element = sema_infer_type_context(sema, vec_at(n->tuple.elems, i));
sema_infer_type_context(sema, vec_at(n->tuple.elems, i));
if (!element) { if (!element) {
vec_free(elements); vec_free(elements);
return 0; return 0;
} }
vec_push(elements, element); vec_push(elements, element);
} }
spl_lang_type_id_t result = spl_lang_make_tuple( spl_lang_type_id_t result =
sema->type, vec_unsafe_get_data(elements), vec_size(elements)); spl_lang_make_tuple(sema->type, vec_unsafe_get_data(elements), vec_size(elements));
vec_free(elements); vec_free(elements);
n->resolved_lang_tid = result; n->resolved_lang_tid = result;
return result; return result;
@@ -2866,6 +2864,7 @@ void spl_sema_dump(spl_sema_t *sema) {
printf("Scopes:\n"); printf("Scopes:\n");
for (usize i = 1; i < vec_size(sema->scope->scopes); ++i) { for (usize i = 1; i < vec_size(sema->scope->scopes); ++i) {
spl_scope_node_t *scope = &vec_at(sema->scope->scopes, i); spl_scope_node_t *scope = &vec_at(sema->scope->scopes, i);
Assert(scope != NULL);
printf("scope[%zu] parent=%zu\n", i, scope->parent); printf("scope[%zu] parent=%zu\n", i, scope->parent);
/* 按符号名排序输出:与哈希表内部布局解耦,保证确定顺序。 */ /* 按符号名排序输出:与哈希表内部布局解耦,保证确定顺序。 */
@@ -2873,6 +2872,7 @@ void spl_sema_dump(spl_sema_t *sema) {
spl_sema_sym_t *arr = nsyms ? malloc(nsyms * sizeof(*arr)) : NULL; spl_sema_sym_t *arr = nsyms ? malloc(nsyms * sizeof(*arr)) : NULL;
usize k = 0; usize k = 0;
map_for(scope->symbols, j) { map_for(scope->symbols, j) {
Assert(arr != NULL);
arr[k].key = unsafe_map_at(scope->symbols, j).key; arr[k].key = unsafe_map_at(scope->symbols, j).key;
arr[k].sym = unsafe_map_at(scope->symbols, j).val; arr[k].sym = unsafe_map_at(scope->symbols, j).val;
k++; k++;
@@ -2880,6 +2880,7 @@ void spl_sema_dump(spl_sema_t *sema) {
if (arr && nsyms > 1) if (arr && nsyms > 1)
qsort(arr, nsyms, sizeof(*arr), spl_sema_sym_cmp); qsort(arr, nsyms, sizeof(*arr), spl_sema_sym_cmp);
for (k = 0; k < nsyms; ++k) { for (k = 0; k < nsyms; ++k) {
Assert(arr != NULL);
printf(" %s -> def`%s`#%zu\n", arr[k].key, arr[k].sym.name, arr[k].sym.node); printf(" %s -> def`%s`#%zu\n", arr[k].key, arr[k].sym.name, arr[k].sym.node);
} }
free(arr); free(arr);
+30 -7
View File
@@ -10,6 +10,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "ir_opt.h"
#include "vm_opt.h"
#include "spl_ast.h" #include "spl_ast.h"
#include "spl_ast2ir.h" #include "spl_ast2ir.h"
#include "spl_diag.h" #include "spl_diag.h"
@@ -217,7 +220,7 @@ static spl_ast_t *driver_load(void *user, const char *from_fname, const char *pa
} }
static int compile_spl(const char *src, const char *fname, const char *outpath, int gen_debug, static int compile_spl(const char *src, const char *fname, const char *outpath, int gen_debug,
dump_t dump) { dump_t dump, int opt) {
(void)gen_debug; (void)gen_debug;
spl_diag_t diag; spl_diag_t diag;
@@ -326,6 +329,10 @@ static int compile_spl(const char *src, const char *fname, const char *outpath,
rc = 1; rc = 1;
goto cleanup; goto cleanup;
} }
/* IR 层优化 pass(默认关闭,--opt 开启)。 */
if (opt)
spl_ir_opt(&ir_builder.ir, &attr);
if (dump == DUMP_IR) { if (dump == DUMP_IR) {
spl_ir_dump(&ir_builder.ir, &lang_type.ir, &attr); spl_ir_dump(&ir_builder.ir, &lang_type.ir, &attr);
goto cleanup; goto cleanup;
@@ -334,7 +341,7 @@ static int compile_spl(const char *src, const char *fname, const char *outpath,
/* 类型已全部就绪:解析 layout,供 ir2vm 的 size/align/offset 使用。 */ /* 类型已全部就绪:解析 layout,供 ir2vm 的 size/align/offset 使用。 */
spl_layout_resolve(&layout, &lang_type.ir); spl_layout_resolve(&layout, &lang_type.ir);
spl_ir2vm_init(&ir2vm, &a2ir.ir->ir, &lang_type.ir, &layout, &attr); spl_ir2vm_init(&ir2vm, &a2ir.ir->ir, &lang_type.ir, &layout, &attr, opt);
ir2vm_ok = 1; ir2vm_ok = 1;
spl_diag_set_stage(&diag, SPL_STAGE_IR2VM); spl_diag_set_stage(&diag, SPL_STAGE_IR2VM);
ir2vm.diag = &diag; ir2vm.diag = &diag;
@@ -348,6 +355,10 @@ static int compile_spl(const char *src, const char *fname, const char *outpath,
goto cleanup; goto cleanup;
} }
/* ir2vm 之后的字节码优化 pass(默认关闭,--opt 开启)。 */
if (opt)
spl_prog_opt(&ir2vm.prog);
spl_prog_store_to_file(outpath, &ir2vm.prog); spl_prog_store_to_file(outpath, &ir2vm.prog);
rc = 0; rc = 0;
@@ -397,6 +408,11 @@ int main(int argc, char **argv) {
LOG_INFO("splc0 --dump <flags> <file> dump: lex,ast,sema,ir,vm,none"); LOG_INFO("splc0 --dump <flags> <file> dump: lex,ast,sema,ir,vm,none");
return 0; return 0;
} }
int opt = 0;
for (int ai = 1; ai < argc; ai++)
if (strcmp(argv[ai], "--opt") == 0)
opt = 1;
int argi = 1; int argi = 1;
if (argi >= argc) { if (argi >= argc) {
LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]"); LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]");
@@ -435,19 +451,26 @@ int main(int argc, char **argv) {
return 1; return 1;
} }
int gen_debug = 0; int gen_debug = 0;
if (strcmp(argv[argi], "-g") == 0) { while (argi < argc - 1) {
gen_debug = 1; if (strcmp(argv[argi], "-g") == 0) {
argi++; gen_debug = 1;
argi++;
} else if (strcmp(argv[argi], "--opt") == 0) {
opt = 1;
argi++;
} else {
break;
}
} }
if (argc < argi + 2) { if (argc < argi + 2) {
LOG_FATAL("Usage: splc0 <in> <out> [-g] or splc0 --dump <flags> <file>\n"); LOG_FATAL("Usage: splc0 <in> <out> [-g] [--opt] or splc0 --dump <flags> <file>\n");
return 1; return 1;
} }
long len; long len;
char *src = read_file(argv[argi], &len); char *src = read_file(argv[argi], &len);
if (!src) if (!src)
return 1; return 1;
int rc = compile_spl(src, argv[argi], argv[argi + 1], gen_debug, dump); int rc = compile_spl(src, argv[argi], argv[argi + 1], gen_debug, dump, opt);
free(src); free(src);
return rc; return rc;
} }
+165
View File
@@ -0,0 +1,165 @@
/* vm_opt.c - 字节码(VM 层)优化 pass
*
* 从 stage0/spl_mcode.c 迁出:对已生成的 spl_prog_t 做 prog->prog 优化。
* 默认不启用(由 splc0 --opt 驱动)。 */
#include "vm_opt.h"
#include "../stage0/include/core_map.h"
#include <stdlib.h>
/* 消除“store 后立刻 load 同一槽位”的往返。
*
* 模式(5 条):laddr X; swap; store k; laddr X; load k
* 变换(3 条):laddr X; pick 1; store k
* [.., v] -> laddr X => [.., v, X]
* -> pick 1 => [.., v, X, v]
* -> store k => [.., v] (存 v 到 X,同时栈上保留 v)
* 与原来 store 后再 load 的效果等价,但去掉 2 条指令与一次内存读。
*
* 会真的删除指令,因此必须重定位:相对跳转、函数表 address、
* 以及作为函数指针的 `push ptr <addr>`。仅当被删/被改写的指令不是
* 跳转目标或函数入口时才变换(已收集 mark)。 */
static usize peep_hash_int(usize k) { return MAP_HASH_INT(k); }
static int peep_cmp_int(usize a, usize b) { return MAP_CMP_INT(a, b); }
void spl_prog_peephole(spl_prog_t *prog) {
if (!prog)
return;
usize n = vec_size(prog->insns);
if (n < 5)
return;
spl_vm_ins_t *ins = prog->insns.data;
unsigned char *mark = (unsigned char *)calloc(n, 1); /* 跳转目标/函数入口,受保护 */
unsigned char *rem = (unsigned char *)calloc(n, 1);
if (!mark || !rem) {
free(mark);
free(rem);
return;
}
for (usize i = 0; i < n; i++) {
spl_vm_ins_t *x = &ins[i];
if (x->opcode == SPL_JMP || x->opcode == SPL_BZ || x->opcode == SPL_BNZ) {
isize t = (isize)i + 1 + (isize)x->imm;
if (t >= 0 && (usize)t < n)
mark[(usize)t] = 1;
}
}
vec_for(prog->funcs, fi) {
spl_vm_func_t *f = &vec_at(prog->funcs, fi);
if (f->address < n)
mark[f->address] = 1;
}
for (usize i = 0; i + 4 < n; i++) {
spl_vm_ins_t *a = &ins[i];
spl_vm_ins_t *b = &ins[i + 1];
spl_vm_ins_t *c = &ins[i + 2];
spl_vm_ins_t *d = &ins[i + 3];
spl_vm_ins_t *e = &ins[i + 4];
if (a->opcode == SPL_LADDR && b->opcode == SPL_SWAP && c->opcode == SPL_STORE &&
d->opcode == SPL_LADDR && e->opcode == SPL_LOAD && a->imm == d->imm &&
c->type == e->type) {
if (mark[i + 1] || mark[i + 3] || mark[i + 4])
continue;
b->opcode = SPL_PICK;
b->type = SPL_VOID;
b->imm = 1;
rem[i + 3] = 1;
rem[i + 4] = 1;
i += 4;
}
}
usize kept = 0;
for (usize i = 0; i < n; i++)
if (!rem[i])
kept++;
if (kept == n) {
free(mark);
free(rem);
return;
}
spl_vm_ins_t *fresh = (spl_vm_ins_t *)malloc(sizeof(spl_vm_ins_t) * (kept ? kept : 1));
usize *map = (usize *)malloc(sizeof(usize) * (n + 1)); /* old index -> new index */
usize *old_of_new = (usize *)malloc(sizeof(usize) * (kept ? kept : 1));
if (!fresh || !map || !old_of_new) {
free(mark);
free(rem);
free(fresh);
free(map);
free(old_of_new);
return;
}
usize out = 0;
for (usize i = 0; i < n; i++) {
if (!rem[i]) {
map[i] = out;
old_of_new[out] = i;
fresh[out] = ins[i];
out++;
}
}
map[n] = kept;
for (usize i = n; i-- > 0;)
if (rem[i])
map[i] = map[i + 1];
/* 函数地址 old->new */
MAP(usize, usize) addr_map;
map_init(addr_map, peep_hash_int, peep_cmp_int);
vec_for(prog->funcs, fi) {
spl_vm_func_t *f = &vec_at(prog->funcs, fi);
usize old_a = f->address;
if (old_a < n) {
usize new_a = map[old_a];
map_put(addr_map, old_a, new_a);
f->address = new_a;
}
}
/* 修正相对跳转与函数指针常量 */
for (usize j = 0; j < kept; j++) {
spl_vm_ins_t *x = &fresh[j];
if (x->opcode == SPL_JMP || x->opcode == SPL_BZ || x->opcode == SPL_BNZ) {
isize t = (isize)old_of_new[j] + 1 + (isize)x->imm;
if (t >= 0 && (usize)t <= n) {
usize nt = map[(usize)t];
x->imm = (spl_vm_val_t)(isize)((isize)nt - (isize)(j + 1));
}
} else if (x->opcode == SPL_PUSH && x->type == SPL_PTR && x->imm != 0) {
usize nv = 0;
if (map_get(addr_map, (usize)x->imm, &nv))
x->imm = nv;
}
}
map_free(addr_map);
/* 指令删除后函数长度变化,重算 ninsns(函数按地址升序排列)。 */
{
usize nf = vec_size(prog->funcs);
for (usize i = 0; i < nf; i++) {
spl_vm_func_t *f = &vec_at(prog->funcs, i);
usize next = (i + 1 < nf) ? vec_at(prog->funcs, i + 1).address : kept;
f->ninsns = next > f->address ? (spl_vm_val_t)(next - f->address) : 0;
}
}
free(prog->insns.data);
prog->insns.data = fresh;
prog->insns.size = kept;
prog->insns.cap = kept;
free(mark);
free(rem);
free(map);
free(old_of_new);
}
/* 优化 pass 流水线(纯 prog->prog):当前 P1,后续可追加。 */
void spl_prog_opt(spl_prog_t *prog) { spl_prog_peephole(prog); }
+11
View File
@@ -0,0 +1,11 @@
#ifndef __VM_OPT_H__
#define __VM_OPT_H__
/* 字节码(VM 层)优化 pass:输入输出都是 spl_prog_t,纯函数式、可开关。 */
#include "../stage0/spl_mcode.h"
void spl_prog_peephole(spl_prog_t *prog);
void spl_prog_opt(spl_prog_t *prog);
#endif /* __VM_OPT_H__ */
+2 -5
View File
@@ -272,11 +272,8 @@ fn drop(self: *Ast) {
} }
fn node(self: *Ast, ref: usize): *Node { fn node(self: *Ast, ref: usize): *Node {
match Vec.get(&self.nodes, ref) { if ref >= self.nodes.len { ret null; }
.Ok(ptr) => { ret ptr as *Node; }, ret (self.nodes.data as *Node) + ref;
.Err(error) => { ret null; },
}
ret null;
} }
// 追加节点,返回其引用(失败返回 0)。 // 追加节点,返回其引用(失败返回 0)。
+4 -4
View File
@@ -6,7 +6,7 @@
type .{ .Error } = @import("utils/error.spl"); type .{ .Error } = @import("utils/error.spl");
type .{ .Vec } = @import("utils/vec.spl"); type .{ .Vec } = @import("utils/vec.spl");
type .{ .Map } = @import("utils/map.spl"); type .{ .Map, .hash_kind_usize } = @import("utils/map.spl");
type .{ .ByteView } = @import("utils/byte_view.spl"); type .{ .ByteView } = @import("utils/byte_view.spl");
type .{ .ByteBuffer } = @import("utils/byte_buffer.spl"); type .{ .ByteBuffer } = @import("utils/byte_buffer.spl");
type .{ .hash_usize, .eq_usize } = @import("utils/hash.spl"); type .{ .hash_usize, .eq_usize } = @import("utils/hash.spl");
@@ -54,8 +54,8 @@ owned: Vec, // ByteBuffer:为 dbg.panic 消息提供稳定存储
// ---- 小工具 ---- // ---- 小工具 ----
fn list_at(v: Vec, i: usize): usize { fn list_at(v: Vec, i: usize): usize {
match Vec.get(&v, i) { .Ok(p) => { ret (p as *usize).*; }, .Err(e) => { ret 0; } } if i >= v.len { ret 0; }
ret 0; ret ((v.data as *usize) + i).*;
} }
fn push_u(v: *Vec, x: usize) { fn push_u(v: *Vec, x: usize) {
@@ -2069,7 +2069,7 @@ fn new(builder: *IrBuilder, sema: *Sema, diag: *Diag): Ast2Ir {
.ir = builder, .ir = builder,
.ast = sema.ast, .ast = sema.ast,
.def2ir_map = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize), .def2ir_map = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize),
hash_usize, eq_usize), hash_kind_usize()),
.loop_stack = Vec.blank(@sizeof(LoopCtx), @alignof(LoopCtx)), .loop_stack = Vec.blank(@sizeof(LoopCtx), @alignof(LoopCtx)),
.defer_stack = Vec.blank(@sizeof(usize), @alignof(usize)), .defer_stack = Vec.blank(@sizeof(usize), @alignof(usize)),
.cur_ret_lang = 0, .cur_ret_lang = 0,
+1 -5
View File
@@ -132,11 +132,7 @@ fn drop(self: *Attr) {
fn node(self: *Attr, id: usize): *AttrNode { fn node(self: *Attr, id: usize): *AttrNode {
if id == 0 || id >= self.table.len { ret null; } if id == 0 || id >= self.table.len { ret null; }
match Vec.get(&self.table, id) { ret (self.table.data as *AttrNode) + id;
.Ok(ptr) => { ret ptr as *AttrNode; },
.Err(error) => { ret null; },
}
ret null;
} }
fn info_at(self: *Attr, index: usize): *AttrInfo { fn info_at(self: *Attr, index: usize): *AttrInfo {
+1 -5
View File
@@ -87,11 +87,7 @@ fn drop(self: *DefTable) {
// id 0 与越界均返回 null(对应 stage1 spl_def_node)。 // id 0 与越界均返回 null(对应 stage1 spl_def_node)。
fn node(self: *DefTable, id: usize): *DefNode { fn node(self: *DefTable, id: usize): *DefNode {
if id == 0 || id >= self.table.len { ret null; } if id == 0 || id >= self.table.len { ret null; }
match Vec.get(&self.table, id) { ret (self.table.data as *DefNode) + id;
.Ok(ptr) => { ret ptr as *DefNode; },
.Err(error) => { ret null; },
}
ret null;
} }
fn count(self: *DefTable): usize { fn count(self: *DefTable): usize {
+1 -4
View File
@@ -161,10 +161,7 @@ fn table_count(): usize {
fn strip_at(name: ByteView): ByteView { fn strip_at(name: ByteView): ByteView {
if name.len > 0 && name.ptr[0] == '@' { if name.len > 0 && name.ptr[0] == '@' {
match ByteView.slice(name, 1, name.len) { ret ByteView { .ptr = name.ptr + 1, .len = name.len - 1 };
.Ok(rest) => { ret rest; },
.Err(error) => { ret name; },
}
} }
ret name; ret name;
} }
+17 -41
View File
@@ -167,26 +167,16 @@ fn drop_body(body: IrBody) {
fn drop(self: *Ir) { fn drop(self: *Ir) {
var i: usize = 0; var i: usize = 0;
while i < self.funcs.len { while i < self.funcs.len {
match Vec.get(&self.funcs, i) { var f = (self.funcs.data as *IrFunc) + i;
.Ok(ptr) => { var j: usize = 0;
var f = ptr as *IrFunc; while j < f.nodes.len {
var j: usize = 0; var e = (f.nodes.data as *IrEntry) + j;
while j < f.nodes.len { Vec.drop(&e.attrs);
match Vec.get(&f.nodes, j) { drop_body(e.body);
.Ok(np) => { j = j + 1;
var e = np as *IrEntry;
Vec.drop(&e.attrs);
drop_body(e.body);
},
.Err(error) => {},
}
j = j + 1;
}
Vec.drop(&f.attrs);
Vec.drop(&f.nodes);
},
.Err(error) => {},
} }
Vec.drop(&f.attrs);
Vec.drop(&f.nodes);
i = i + 1; i = i + 1;
} }
Vec.drop(&self.funcs); Vec.drop(&self.funcs);
@@ -207,36 +197,22 @@ fn alloc_fn(self: *Ir): usize {
fn alloc_node(self: *Ir, fn_id: usize): usize { fn alloc_node(self: *Ir, fn_id: usize): usize {
if fn_id == 0 || fn_id >= self.funcs.len { ret 0; } if fn_id == 0 || fn_id >= self.funcs.len { ret 0; }
match Vec.get(&self.funcs, fn_id) { var f = (self.funcs.data as *IrFunc) + fn_id;
.Ok(ptr) => { var n = new_entry();
var f = ptr as *IrFunc; match Vec.push(&f.nodes, &n as *u8) { .Ok => {}, .Err(error) => { ret 0; } }
var n = new_entry(); ret f.nodes.len - 1;
match Vec.push(&f.nodes, &n as *u8) { .Ok => {}, .Err(error) => { ret 0; } }
ret f.nodes.len - 1;
},
.Err(error) => {},
}
ret 0;
} }
fn func(self: *Ir, fn_id: usize): *IrFunc { fn func(self: *Ir, fn_id: usize): *IrFunc {
if fn_id == 0 || fn_id >= self.funcs.len { ret null; } if fn_id == 0 || fn_id >= self.funcs.len { ret null; }
match Vec.get(&self.funcs, fn_id) { ret (self.funcs.data as *IrFunc) + fn_id;
.Ok(ptr) => { ret ptr as *IrFunc; },
.Err(error) => { ret null; },
}
ret null;
} }
fn node(self: *Ir, fn_id: usize, node_id: usize): *IrEntry { fn node(self: *Ir, fn_id: usize, node_id: usize): *IrEntry {
var f = func(self, fn_id); var f = func(self, fn_id);
if f == null { ret null; } if f == null { ret null; }
if node_id == 0 || node_id >= f.nodes.len { ret null; } if node_id == 0 || node_id >= f.nodes.len { ret null; }
match Vec.get(&f.nodes, node_id) { ret (f.nodes.data as *IrEntry) + node_id;
.Ok(ptr) => { ret ptr as *IrEntry; },
.Err(error) => { ret null; },
}
ret null;
} }
fn kind_name(kind: IrKind): []u8 { fn kind_name(kind: IrKind): []u8 {
@@ -345,8 +321,8 @@ fn dump_attrs(out: *ByteBuffer, attr: *Attr, ids: Vec): bool {
} }
fn list_at(v: Vec, i: usize): usize { fn list_at(v: Vec, i: usize): usize {
match Vec.get(&v, i) { .Ok(p) => { ret (p as *usize).*; }, .Err(e) => { ret 0; } } if i >= v.len { ret 0; }
ret 0; ret ((v.data as *usize) + i).*;
} }
fn dump_body(out: *ByteBuffer, ty: *TypeTable, e: *IrEntry): bool { fn dump_body(out: *ByteBuffer, ty: *TypeTable, e: *IrEntry): bool {
+12 -2
View File
@@ -362,7 +362,7 @@ fn frame_build(fl: *FrameLayout, ctx: *Ir2Vm, fid: usize) {
var i: usize = 0; var i: usize = 0;
while i < n { while i < n {
var blank: Slot = .{ .result_off = 0, .data_off = 0 }; var blank: Slot = .{ .result_off = 0, .data_off = 0 };
match Vec.push(&fl.slots, &blank as *u8) { .Ok => {}, .Err(error) => {} } ignore_bool(Vec.push_raw(&fl.slots, &blank as *u8));
i = i + 1; i = i + 1;
} }
@@ -421,7 +421,17 @@ fixups: *Vec,
terminated: bool, terminated: bool,
fn emit(cg: *Cgen, op: Op, ty: VmKind, imm: usize) { fn emit(cg: *Cgen, op: Op, ty: VmKind, imm: usize) {
ignore_usize(Mcode.add_instr(&cg.ctx.prog, op, ty, imm)); var prog = &cg.ctx.prog;
var i = prog.insns.len;
if i < prog.insns.cap {
var p = (prog.insns.data as *VmIns) + i;
p.opcode = op;
p.ty = ty;
p.imm = imm;
prog.insns.len = i + 1;
ret;
}
ignore_usize(Mcode.add_instr(prog, op, ty, imm));
} }
fn ip_of(cg: *Cgen): usize { fn ip_of(cg: *Cgen): usize {
+2 -2
View File
@@ -14,8 +14,8 @@ type Ir = @import("./ir.spl");
type .{ .IrKind, .ConstLit, .IrEntry, .IrFunc, .IrBody } = @import("./ir.spl"); type .{ .IrKind, .ConstLit, .IrEntry, .IrFunc, .IrBody } = @import("./ir.spl");
fn list_at(v: Vec, i: usize): usize { fn list_at(v: Vec, i: usize): usize {
match Vec.get(&v, i) { .Ok(p) => { ret (p as *usize).*; }, .Err(e) => { ret 0; } } if i >= v.len { ret 0; }
ret 0; ret ((v.data as *usize) + i).*;
} }
// ---- builder ---- // ---- builder ----
+3 -7
View File
@@ -9,7 +9,7 @@
type .{ .Error } = @import("utils/error.spl"); type .{ .Error } = @import("utils/error.spl");
type .{ .Vec } = @import("utils/vec.spl"); type .{ .Vec } = @import("utils/vec.spl");
type .{ .Map } = @import("utils/map.spl"); type .{ .Map, .hash_kind_usize } = @import("utils/map.spl");
type .{ .ByteView } = @import("utils/byte_view.spl"); type .{ .ByteView } = @import("utils/byte_view.spl");
type .{ .ByteBuffer } = @import("utils/byte_buffer.spl"); type .{ .ByteBuffer } = @import("utils/byte_buffer.spl");
type .{ .append_usize } = @import("utils/fmt.spl"); type .{ .append_usize } = @import("utils/fmt.spl");
@@ -183,7 +183,7 @@ fn new(): LangTypeResult {
.ir = ir, .ir = ir,
.lang_table = lang_table, .lang_table = lang_table,
.fold = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize), .fold = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize),
hash_usize, eq_usize), hash_kind_usize()),
.defs = defs, .defs = defs,
.owned_names = Vec.blank(@sizeof(ByteBuffer), @alignof(ByteBuffer)), .owned_names = Vec.blank(@sizeof(ByteBuffer), @alignof(ByteBuffer)),
}; };
@@ -218,11 +218,7 @@ fn drop(self: *LangType) {
// id 0 与越界返回 null(对应 stage1 spl_lang_type_node)。 // id 0 与越界返回 null(对应 stage1 spl_lang_type_node)。
fn lang_node(self: *LangType, id: usize): *LangEntry { fn lang_node(self: *LangType, id: usize): *LangEntry {
if id == 0 || id >= self.lang_table.len { ret null; } if id == 0 || id >= self.lang_table.len { ret null; }
match Vec.get(&self.lang_table, id) { ret (self.lang_table.data as *LangEntry) + id;
.Ok(ptr) => { ret ptr as *LangEntry; },
.Err(error) => { ret null; },
}
ret null;
} }
fn ir_type(self: *LangType, lang_id: usize): usize { fn ir_type(self: *LangType, lang_id: usize): usize {
+1 -5
View File
@@ -44,11 +44,7 @@ fn new(): LayoutResult {
fn info_at(self: *Layout, id: usize): *LayoutInfo { fn info_at(self: *Layout, id: usize): *LayoutInfo {
if id == 0 || id >= self.infos.len { ret null; } if id == 0 || id >= self.infos.len { ret null; }
match Vec.get(&self.infos, id) { ret (self.infos.data as *LayoutInfo) + id;
.Ok(ptr) => { ret ptr as *LayoutInfo; },
.Err(error) => { ret null; },
}
ret null;
} }
// 未解析或越界返回 null(对应 stage1 spl_layout_info_of)。 // 未解析或越界返回 null(对应 stage1 spl_layout_info_of)。
+2 -5
View File
@@ -92,11 +92,8 @@ fn has3(self: *Lexer, ch1: u8, ch2: u8): bool {
} }
fn sub(self: *Lexer, start: usize, end: usize): ByteView { fn sub(self: *Lexer, start: usize, end: usize): ByteView {
match ByteView.slice(self.src, start, end) { if start >= end { ret ByteView.empty(); }
.Ok(v) => { ret v; }, ret ByteView { .ptr = self.src.ptr + start, .len = end - start };
.Err(error) => { ret ByteView.empty(); },
}
ret ByteView.empty();
} }
// 产出 token 并把 pos/col 推进到 end。Vec.push 失败视为致命(同 vec.make_vec 风格)。 // 产出 token 并把 pos/col 推进到 end。Vec.push 失败视为致命(同 vec.make_vec 风格)。
+71 -26
View File
@@ -265,6 +265,15 @@ fn drop(self: *Prog) {
// ---- 构建 ---- // ---- 构建 ----
fn add_instr(self: *Prog, op: Op, ty: VmKind, imm: usize): usize { fn add_instr(self: *Prog, op: Op, ty: VmKind, imm: usize): usize {
var i = self.insns.len;
if i < self.insns.cap {
var p = (self.insns.data as *VmIns) + i;
p.opcode = op;
p.ty = ty;
p.imm = imm;
self.insns.len = i + 1;
ret i + 1;
}
var ins = VmIns { .opcode = op, .ty = ty, .imm = imm }; var ins = VmIns { .opcode = op, .ty = ty, .imm = imm };
if !Vec.push_raw(&self.insns, &ins as *u8) { ret 0; } if !Vec.push_raw(&self.insns, &ins as *u8) { ret 0; }
ret self.insns.len; ret self.insns.len;
@@ -462,11 +471,8 @@ fn dump(self: *Prog, out: *ByteBuffer): bool {
} }
fn ins_at(self: *Prog, i: usize): VmIns { fn ins_at(self: *Prog, i: usize): VmIns {
match Vec.get(&self.insns, i) { if i >= self.insns.len { ret VmIns { .opcode = .Error, .ty = .Void, .imm = 0 }; }
.Ok(ptr) => { ret (ptr as *VmIns).*; }, ret ((self.insns.data as *VmIns) + i).*;
.Err(error) => { ret VmIns { .opcode = .Error, .ty = .Void, .imm = 0 }; },
}
ret VmIns { .opcode = .Error, .ty = .Void, .imm = 0 };
} }
fn func_at(self: *Prog, i: usize): *VmFunc { fn func_at(self: *Prog, i: usize): *VmFunc {
@@ -491,41 +497,43 @@ fn align8(n: usize): usize {
ret (n + 7) & (~(7 as usize)); ret (n + 7) & (~(7 as usize));
} }
// 说明:以下 put_* 直接写入已预留容量的 ByteBuffer 存储(store 已按精确总大小 reserve),
// 跳过 ByteBuffer.append → Vec.append 的校验/拷贝路径。若容量不足会越界,故 store 先校验容量。
fn put_u8(out: *ByteBuffer, b: u8): bool { fn put_u8(out: *ByteBuffer, b: u8): bool {
match ByteBuffer.append_byte(out, b) { .Ok => { ret true; }, .Err(error) => { ret false; } } out.storage.data[out.storage.len] = b;
ret false; out.storage.len = out.storage.len + 1;
ret true;
} }
// 直接按小端整型写(x86 小端;VM 的 STORE 用 memcpy,未对齐也安全)。
fn put_u16(out: *ByteBuffer, v: usize): bool { fn put_u16(out: *ByteBuffer, v: usize): bool {
if !put_u8(out, (v & 255) as u8) { ret false; } var d = out.storage.data + out.storage.len;
ret put_u8(out, ((v >> 8) & 255) as u8); (d as *u16).* = v as u16;
out.storage.len = out.storage.len + 2;
ret true;
} }
fn put_u64(out: *ByteBuffer, v: usize): bool { fn put_u64(out: *ByteBuffer, v: usize): bool {
var i: usize = 0; var d = out.storage.data + out.storage.len;
while i < 8 { (d as *u64).* = v as u64;
if !put_u8(out, ((v >> (i * 8)) & 255) as u8) { ret false; } out.storage.len = out.storage.len + 8;
i = i + 1;
}
ret true; ret true;
} }
fn put_zeros(out: *ByteBuffer, n: usize): bool { fn put_zeros(out: *ByteBuffer, n: usize): bool {
var i: usize = 0; if n != 0 {
while i < n { ignore_ptr(Mem.set((out.storage.data + out.storage.len) as *any, 0, n));
if !put_u8(out, 0) { ret false; } out.storage.len = out.storage.len + n;
i = i + 1;
} }
ret true; ret true;
} }
fn put_view(out: *ByteBuffer, v: ByteView): bool { fn put_view(out: *ByteBuffer, v: ByteView): bool {
if v.len == 0 { ret true; } if v.len == 0 { ret true; }
match ByteBuffer.append(out, ByteView.as_slice(v)) { Mem.copy((out.storage.data + out.storage.len) as *any, v.ptr as *any, v.len);
.Ok => { ret true; }, out.storage.len = out.storage.len + v.len;
.Err(error) => { ret false; }, ret true;
}
ret false;
} }
// 写入「带结尾 NUL、再按 8 对齐」的名称字段(对应 C 侧 nlen = strlen+1)。 // 写入「带结尾 NUL、再按 8 对齐」的名称字段(对应 C 侧 nlen = strlen+1)。
@@ -541,6 +549,41 @@ fn store(self: *Prog, path: ByteView): Status {
var out = ByteBuffer.new(); var out = ByteBuffer.new();
defer { ByteBuffer.drop(&out); } defer { ByteBuffer.drop(&out); }
// 精确预估输出大小并一次性预留,避免大文件逐字节增长导致的重复拷贝。
var total: usize = 48;
var fi: usize = 0;
while fi < self.funcs.len {
var f = func_at(self, fi);
if f != null {
var nlen = f.name.len + 1;
total = total + 8 + align8(nlen) + 32;
}
fi = fi + 1;
}
total = total + self.insns.len * 12;
fi = 0;
while fi < self.natives.len {
var n = native_at(self, fi);
if n != null {
var nlen = n.name.len + 1;
total = total + 8 + align8(nlen) + 8;
}
fi = fi + 1;
}
fi = 0;
while fi < self.strtab.len {
total = total + 8 + align8(str_at(self, fi).len);
fi = fi + 1;
}
fi = 1;
while fi < self.gdata.len {
var e = gdata_at(self, fi);
if e != null { total = total + 8 + align8(e.storage.len); }
fi = fi + 1;
}
match ByteBuffer.reserve(&out, total) { .Ok => {}, .Err(error) => {} }
if out.storage.cap < total || out.storage.data == null { ret .Err(make(.Io)); }
if !put_view(&out, ByteView.from_slice("SPLBIN")) { ret .Err(make(.Io)); } if !put_view(&out, ByteView.from_slice("SPLBIN")) { ret .Err(make(.Io)); }
if !put_zeros(&out, 2) { ret .Err(make(.Io)); } if !put_zeros(&out, 2) { ret .Err(make(.Io)); }
@@ -572,9 +615,11 @@ fn store(self: *Prog, path: ByteView): Status {
i = 0; i = 0;
while i < ninsns { while i < ninsns {
var ins = ins_at(self, i); var ins = ins_at(self, i);
if !put_u16(&out, @enum2int(ins.opcode) as usize) { ret .Err(make(.Io)); } var d = out.storage.data + out.storage.len;
if !put_u16(&out, @enum2int(ins.ty) as usize) { ret .Err(make(.Io)); } (d as *u16).* = @enum2int(ins.opcode) as u16;
if !put_u64(&out, ins.imm) { ret .Err(make(.Io)); } ((d + 2) as *u16).* = @enum2int(ins.ty) as u16;
((d + 4) as *u64).* = ins.imm as u64;
out.storage.len = out.storage.len + 12;
i = i + 1; i = i + 1;
} }
+7 -9
View File
@@ -42,11 +42,8 @@ fn new(ast: *Ast, toks: Vec, diag: *Diag): Parser {
// ---- token 访问 ---- // ---- token 访问 ----
fn token_ptr(self: *Parser, index: usize): *Token { fn token_ptr(self: *Parser, index: usize): *Token {
match Vec.get(&self.toks, index) { if index >= self.toks.len { ret null; }
.Ok(ptr) => { ret ptr as *Token; }, ret (self.toks.data as *Token) + index;
.Err(error) => { ret null; },
}
ret null;
} }
fn is_trivia(kind: TokenKind): bool { fn is_trivia(kind: TokenKind): bool {
@@ -61,16 +58,17 @@ fn is_trivia(kind: TokenKind): bool {
// 跳过 trivia;返回当前 token(含 EOF)。越界返回 null。 // 跳过 trivia;返回当前 token(含 EOF)。越界返回 null。
fn peek(self: *Parser): *Token { fn peek(self: *Parser): *Token {
var n = self.toks.len; var n = self.toks.len;
var base = self.toks.data as *Token;
var i = self.pos; var i = self.pos;
while i < n { while i < n {
var t = token_ptr(self, i); if base == null { break; }
if t == null { break; } var t = base + i;
if !is_trivia(t.kind) { break; } if !is_trivia(t.kind) { break; }
i = i + 1; i = i + 1;
} }
self.pos = i; self.pos = i;
if i >= n { ret null; } if i >= n || base == null { ret null; }
ret token_ptr(self, i); ret base + i;
} }
fn advance(self: *Parser): *Token { fn advance(self: *Parser): *Token {
+3 -7
View File
@@ -7,7 +7,7 @@
type .{ .Error } = @import("utils/error.spl"); type .{ .Error } = @import("utils/error.spl");
type .{ .Vec } = @import("utils/vec.spl"); type .{ .Vec } = @import("utils/vec.spl");
type .{ .Map } = @import("utils/map.spl"); type .{ .Map, .hash_kind_view } = @import("utils/map.spl");
type .{ .ByteView } = @import("utils/byte_view.spl"); type .{ .ByteView } = @import("utils/byte_view.spl");
type .{ .hash_view, .eq_view } = @import("utils/hash.spl"); type .{ .hash_view, .eq_view } = @import("utils/hash.spl");
@@ -43,7 +43,7 @@ type ScopeResult = enum {
fn new_map(): Map { fn new_map(): Map {
ret Map.new(@sizeof(ByteView), @alignof(ByteView), @sizeof(Symbol), @alignof(Symbol), ret Map.new(@sizeof(ByteView), @alignof(ByteView), @sizeof(Symbol), @alignof(Symbol),
hash_view, eq_view); hash_kind_view());
} }
fn new(): ScopeResult { fn new(): ScopeResult {
@@ -81,11 +81,7 @@ fn drop(self: *Scope) {
// id 0 与越界返回 null。 // id 0 与越界返回 null。
fn node(self: *Scope, id: usize): *ScopeNode { fn node(self: *Scope, id: usize): *ScopeNode {
if id == 0 || id >= self.scopes.len { ret null; } if id == 0 || id >= self.scopes.len { ret null; }
match Vec.get(&self.scopes, id) { ret (self.scopes.data as *ScopeNode) + id;
.Ok(ptr) => { ret ptr as *ScopeNode; },
.Err(error) => { ret null; },
}
ret null;
} }
// 新作用域 parent = 当前作用域;不自动切换 current(调用方负责,见 sema)。 // 新作用域 parent = 当前作用域;不自动切换 current(调用方负责,见 sema)。
+4 -7
View File
@@ -9,7 +9,7 @@
type .{ .Error, .Status } = @import("utils/error.spl"); type .{ .Error, .Status } = @import("utils/error.spl");
type .{ .Vec } = @import("utils/vec.spl"); type .{ .Vec } = @import("utils/vec.spl");
type .{ .Map } = @import("utils/map.spl"); type .{ .Map, .hash_kind_usize } = @import("utils/map.spl");
type .{ .ByteView } = @import("utils/byte_view.spl"); type .{ .ByteView } = @import("utils/byte_view.spl");
type .{ .ByteBuffer } = @import("utils/byte_buffer.spl"); type .{ .ByteBuffer } = @import("utils/byte_buffer.spl");
type .{ .append_usize } = @import("utils/fmt.spl"); type .{ .append_usize } = @import("utils/fmt.spl");
@@ -69,11 +69,8 @@ type SemaResult = enum {
// ---- 小工具 ---- // ---- 小工具 ----
fn list_at(v: Vec, i: usize): usize { fn list_at(v: Vec, i: usize): usize {
match Vec.get(&v, i) { if i >= v.len { ret 0; }
.Ok(ptr) => { ret (ptr as *usize).*; }, ret ((v.data as *usize) + i).*;
.Err(error) => { ret 0; },
}
ret 0;
} }
fn push_u(v: *Vec, x: usize) { fn push_u(v: *Vec, x: usize) {
@@ -234,7 +231,7 @@ fn new(ast: *Ast, diag: *Diag): SemaResult {
.current_loop_break_tid = 0, .current_loop_break_tid = 0,
.label_stack = Vec.blank(@sizeof(ByteView), @alignof(ByteView)), .label_stack = Vec.blank(@sizeof(ByteView), @alignof(ByteView)),
.ir_to_lang = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize), .ir_to_lang = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize),
hash_usize, eq_usize), hash_kind_usize()),
}; };
ret .Ok(s); ret .Ok(s);
} }
+4
View File
@@ -25,6 +25,10 @@ fn steps(): usize {
ret vm_timestamp(3); ret vm_timestamp(3);
} }
fn calls(): usize {
ret vm_timestamp(5);
}
fn now_ns(): usize { fn now_ns(): usize {
ret vm_timestamp(4); ret vm_timestamp(4);
} }
+58 -30
View File
@@ -66,37 +66,65 @@ fn is_trivia(kind: TokenKind): bool {
} }
} }
// 先按长度与首字节分派,再做完整比较,避免对每个标识符做全表串比较。
fn keyword_of(text: ByteView): KeywordResult { fn keyword_of(text: ByteView): KeywordResult {
if is(text, "any") { ret .Yes(.Any); } var n = text.len;
if is(text, "as") { ret .Yes(.As); } if n == 0 { ret .No; }
if is(text, "bool") { ret .Yes(.Bool); } var c0 = text.ptr[0];
if is(text, "break") { ret .Yes(.Break); } if n == 2 {
if is(text, "catch") { ret .Yes(.Catch); } if c0 == 'a' && is(text, "as") { ret .Yes(.As); }
if is(text, "comptime") { ret .Yes(.Comptime); } if c0 == 'f' && is(text, "fn") { ret .Yes(.Fn); }
if is(text, "const") { ret .Yes(.Const); } if c0 == 'i' && is(text, "if") { ret .Yes(.If); }
if is(text, "continue") { ret .Yes(.Continue); } ret .No;
if is(text, "defer") { ret .Yes(.Defer); } }
if is(text, "else") { ret .Yes(.Else); } if n == 3 {
if is(text, "enum") { ret .Yes(.Enum); } if c0 == 'a' && is(text, "any") { ret .Yes(.Any); }
if is(text, "errdefer") { ret .Yes(.Errdefer); } if c0 == 'f' && is(text, "for") { ret .Yes(.For); }
if is(text, "false") { ret .Yes(.False); } if c0 == 'r' && is(text, "ret") { ret .Yes(.Ret); }
if is(text, "fn") { ret .Yes(.Fn); } if c0 == 't' && is(text, "try") { ret .Yes(.Try); }
if is(text, "for") { ret .Yes(.For); } if c0 == 'v' && is(text, "var") { ret .Yes(.Var); }
if is(text, "if") { ret .Yes(.If); } ret .No;
if is(text, "loop") { ret .Yes(.Loop); } }
if is(text, "match") { ret .Yes(.Match); } if n == 4 {
if is(text, "null") { ret .Yes(.Null); } if c0 == 'b' && is(text, "bool") { ret .Yes(.Bool); }
if is(text, "ret") { ret .Yes(.Ret); } if c0 == 'e' && is(text, "else") { ret .Yes(.Else); }
if is(text, "shape") { ret .Yes(.Shape); } if c0 == 'e' && is(text, "enum") { ret .Yes(.Enum); }
if is(text, "struct") { ret .Yes(.Struct); } if c0 == 'l' && is(text, "loop") { ret .Yes(.Loop); }
if is(text, "true") { ret .Yes(.True); } if c0 == 'n' && is(text, "null") { ret .Yes(.Null); }
if is(text, "try") { ret .Yes(.Try); } if c0 == 't' && is(text, "true") { ret .Yes(.True); }
if is(text, "type") { ret .Yes(.Type); } if c0 == 't' && is(text, "type") { ret .Yes(.Type); }
if is(text, "undefined") { ret .Yes(.Undefined); } ret .No;
if is(text, "union") { ret .Yes(.Union); } }
if is(text, "var") { ret .Yes(.Var); } if n == 5 {
if is(text, "while") { ret .Yes(.While); } if c0 == 'b' && is(text, "break") { ret .Yes(.Break); }
if is(text, "_") { ret .Yes(.Underscore); } if c0 == 'c' && is(text, "catch") { ret .Yes(.Catch); }
if c0 == 'c' && is(text, "const") { ret .Yes(.Const); }
if c0 == 'd' && is(text, "defer") { ret .Yes(.Defer); }
if c0 == 'f' && is(text, "false") { ret .Yes(.False); }
if c0 == 'm' && is(text, "match") { ret .Yes(.Match); }
if c0 == 's' && is(text, "shape") { ret .Yes(.Shape); }
if c0 == 'u' && is(text, "union") { ret .Yes(.Union); }
if c0 == 'w' && is(text, "while") { ret .Yes(.While); }
ret .No;
}
if n == 6 {
if c0 == 's' && is(text, "struct") { ret .Yes(.Struct); }
ret .No;
}
if n == 8 {
if c0 == 'c' && is(text, "comptime") { ret .Yes(.Comptime); }
if c0 == 'c' && is(text, "continue") { ret .Yes(.Continue); }
if c0 == 'e' && is(text, "errdefer") { ret .Yes(.Errdefer); }
ret .No;
}
if n == 9 {
if c0 == 'u' && is(text, "undefined") { ret .Yes(.Undefined); }
ret .No;
}
if n == 1 {
if c0 == '_' && is(text, "_") { ret .Yes(.Underscore); }
ret .No;
}
ret .No; ret .No;
} }
+5 -12
View File
@@ -9,7 +9,7 @@
type .{ .Error } = @import("utils/error.spl"); type .{ .Error } = @import("utils/error.spl");
type .{ .Vec } = @import("utils/vec.spl"); type .{ .Vec } = @import("utils/vec.spl");
type .{ .Map } = @import("utils/map.spl"); type .{ .Map, .hash_kind_usize } = @import("utils/map.spl");
type .{ .ByteView } = @import("utils/byte_view.spl"); type .{ .ByteView } = @import("utils/byte_view.spl");
type .{ .ByteBuffer } = @import("utils/byte_buffer.spl"); type .{ .ByteBuffer } = @import("utils/byte_buffer.spl");
type .{ .append_usize } = @import("utils/fmt.spl"); type .{ .append_usize } = @import("utils/fmt.spl");
@@ -301,11 +301,8 @@ fn usize_at(v: Vec, i: usize): usize {
} }
fn member_at(v: *Vec, i: usize): *Member { fn member_at(v: *Vec, i: usize): *Member {
match Vec.get(v, i) { if i >= v.len { ret null; }
.Ok(ptr) => { ret ptr as *Member; }, ret (v.data as *Member) + i;
.Err(error) => { ret null; },
}
ret null;
} }
fn push_member(v: *Vec, name: []u8, type_id: usize) { fn push_member(v: *Vec, name: []u8, type_id: usize) {
@@ -323,11 +320,7 @@ fn push_member(v: *Vec, name: []u8, type_id: usize) {
// id 0 与越界均返回 null(对应 stage1 spl_type_node)。 // id 0 与越界均返回 null(对应 stage1 spl_type_node)。
fn node(self: *TypeTable, id: usize): *TypeEntry { fn node(self: *TypeTable, id: usize): *TypeEntry {
if id == 0 || id >= self.table.len { ret null; } if id == 0 || id >= self.table.len { ret null; }
match Vec.get(&self.table, id) { ret (self.table.data as *TypeEntry) + id;
.Ok(ptr) => { ret ptr as *TypeEntry; },
.Err(error) => { ret null; },
}
ret null;
} }
// ---- 生命周期 ---- // ---- 生命周期 ----
@@ -336,7 +329,7 @@ fn new(): TypeTableResult {
var tt = TypeTable { var tt = TypeTable {
.table = Vec.blank(@sizeof(TypeEntry), @alignof(TypeEntry)), .table = Vec.blank(@sizeof(TypeEntry), @alignof(TypeEntry)),
.fold = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize), .fold = Map.new(@sizeof(usize), @alignof(usize), @sizeof(usize), @alignof(usize),
hash_usize, eq_usize), hash_kind_usize()),
}; };
var sentinel = TypeEntry { .hash_next = 0, .node = .Error }; var sentinel = TypeEntry { .hash_next = 0, .node = .Error };
match Vec.push(&tt.table, &sentinel as *u8) { match Vec.push(&tt.table, &sentinel as *u8) {
+3 -7
View File
@@ -5,6 +5,8 @@
type .{ .Error, .make } = @import("error.spl"); type .{ .Error, .make } = @import("error.spl");
#extern(vm) fn vm_bytes_eq(a: *any, alen: usize, b: *any, blen: usize): i32;
type ByteView = @self; type ByteView = @self;
ptr: *u8, ptr: *u8,
@@ -62,13 +64,7 @@ fn byte_at(self: ByteView, index: usize): ByteResult {
} }
fn eq(a: ByteView, b: ByteView): bool { fn eq(a: ByteView, b: ByteView): bool {
if a.len != b.len { ret false; } ret vm_bytes_eq(a.ptr as *any, a.len, b.ptr as *any, b.len) != 0;
var i: usize = 0;
while i < a.len {
if a.ptr[i] != b.ptr[i] { ret false; }
i = i + 1;
}
ret true;
} }
// 按无符号字节进行字典序比较,结果只承诺小于、等于或大于零。 // 按无符号字节进行字典序比较,结果只承诺小于、等于或大于零。
+45 -190
View File
@@ -7,9 +7,14 @@
type .{ .Error, .Status, .make } = @import("error.spl"); type .{ .Error, .Status, .make } = @import("error.spl");
type .{ .Vec } = @import("vec.spl"); type .{ .Vec } = @import("vec.spl");
type .{ .ByteView } = @import("byte_view.spl"); type .{ .ByteView } = @import("byte_view.spl");
type .{ .hash_usize, .eq_usize, .hash_view, .eq_view } = @import("hash.spl");
type .{ .checked_add, .checked_mul, .grow_capacity } = @import("memory.spl"); #extern(vm) fn vm_map_valid(m: *any): i32;
type .{ .copy } = @import("../sys/mem.spl"); #extern(vm) fn vm_map_reserve(m: *any, need: usize): i32;
#extern(vm) fn vm_map_put(m: *any, key: *any, val: *any): i32;
#extern(vm) fn vm_map_get(m: *any, key: *any, out: *any): i32;
#extern(vm) fn vm_map_del(m: *any, key: *any): i32;
#extern(vm) fn vm_map_clear(m: *any): void;
#extern(vm) fn vm_map_drop(m: *any): void;
// 槽位状态:Empty/Occupied/Deleted(墓碑,仅在扩容重哈希时清除)。 // 槽位状态:Empty/Occupied/Deleted(墓碑,仅在扩容重哈希时清除)。
// 负载因子 70/128。 // 负载因子 70/128。
@@ -20,11 +25,6 @@ type SlotState = enum {
Deleted, Deleted,
} }
fn state_code(state: SlotState): u8 {
var s: SlotState = state;
ret @enum2int(s) as u8;
}
// 查找/删除结果:显式区分命中与缺失,替代 bool 哨兵。 // 查找/删除结果:显式区分命中与缺失,替代 bool 哨兵。
type LookupResult = enum { type LookupResult = enum {
Found, Found,
@@ -39,11 +39,15 @@ states: Vec,
size: usize, size: usize,
key_size: usize, key_size: usize,
val_size: usize, val_size: usize,
hash_fn: fn(*u8): usize, hash_kind: usize,
eq_fn: fn(*u8, *u8): bool,
// 键解释:0 = usize;1 = ByteView(按内容哈希/比较)。
fn hash_kind_usize(): usize { ret 0; }
fn hash_kind_view(): usize { ret 1; }
fn hash_kind_constant(): usize { ret 2; }
fn blank(key_size: usize, key_align: usize, val_size: usize, val_align: usize, fn blank(key_size: usize, key_align: usize, val_size: usize, val_align: usize,
hash_fn: fn(*u8): usize, eq_fn: fn(*u8, *u8): bool): Map { hash_kind: usize): Map {
ret Map { ret Map {
.keys = Vec.blank(key_size, key_align), .keys = Vec.blank(key_size, key_align),
.vals = Vec.blank(val_size, val_align), .vals = Vec.blank(val_size, val_align),
@@ -51,23 +55,30 @@ fn blank(key_size: usize, key_align: usize, val_size: usize, val_align: usize,
.size = 0, .size = 0,
.key_size = key_size, .key_size = key_size,
.val_size = val_size, .val_size = val_size,
.hash_fn = hash_fn, .hash_kind = hash_kind,
.eq_fn = eq_fn,
}; };
} }
fn new(key_size: usize, key_align: usize, val_size: usize, val_align: usize, fn new(key_size: usize, key_align: usize, val_size: usize, val_align: usize,
hash_fn: fn(*u8): usize, eq_fn: fn(*u8, *u8): bool): Map { hash_kind: usize): Map {
ret blank(key_size, key_align, val_size, val_align, hash_fn, eq_fn); ret blank(key_size, key_align, val_size, val_align, hash_kind);
} }
fn valid(self: Map): bool { fn status_from_code(code: i32): Status {
if self.key_size == 0 || self.val_size == 0 { ret false; } if code == 0 { ret .Ok; }
if self.states.len != self.keys.len || self.states.len != self.vals.len { if code == 2 { ret .Err(make(.OutOfRange)); }
ret false; if code == 3 { ret .Err(make(.Overflow)); }
} if code == 4 { ret .Err(make(.InvalidAlignment)); }
if self.size > self.states.len { ret false; } ret .Err(make(.InvalidArgument));
ret true; }
fn lookup_from_code(code: i32): LookupResult {
if code == 0 { ret .Found; }
ret .NotFound;
}
fn valid(self: *Map): bool {
ret vm_map_valid(self as *any) != 0;
} }
fn size(self: Map): usize { fn size(self: Map): usize {
@@ -85,10 +96,8 @@ fn slot_count(self: Map): usize {
fn slot_state(self: Map, index: usize): SlotState { fn slot_state(self: Map, index: usize): SlotState {
var code = self.states.data[index]; var code = self.states.data[index];
var occupied: SlotState = .Occupied; if code == 1 { ret .Occupied; }
var deleted_state: SlotState = .Deleted; if code == 2 { ret .Deleted; }
if code == state_code(occupied) { ret .Occupied; }
if code == state_code(deleted_state) { ret .Deleted; }
ret .Empty; ret .Empty;
} }
@@ -109,186 +118,32 @@ fn val_at(self: *Map, index: usize): *u8 {
ret self.vals.data + index * self.val_size; ret self.vals.data + index * self.val_size;
} }
// 返回占用键的槽位;未找到返回 ~0。容量为 0 时直接未找到。
fn find_slot(self: *Map, key: *u8): usize {
if self.states.cap == 0 { ret ~(0 as usize); }
var mask = self.states.cap - 1;
var i = self.hash_fn(key) & mask;
var empty: SlotState = .Empty;
var occupied: SlotState = .Occupied;
var probes: usize = 0;
while probes < self.states.cap && self.states.data[i] != state_code(empty) {
if self.states.data[i] == state_code(occupied) &&
self.eq_fn(self.keys.data + i * self.key_size, key) {
ret i;
}
i = (i + 1) & mask;
probes = probes + 1;
}
ret ~(0 as usize);
}
// 要求容量非零且键不存在。优先复用探测链中的第一个墓碑。
fn place(self: *Map, key: *u8, val: *u8) {
var mask = self.states.cap - 1;
var i = self.hash_fn(key) & mask;
var empty: SlotState = .Empty;
var deleted: SlotState = .Deleted;
var occupied: SlotState = .Occupied;
var first_deleted = ~(0 as usize);
var probes: usize = 0;
while probes < self.states.cap && self.states.data[i] != state_code(empty) {
if self.states.data[i] == state_code(deleted) && first_deleted == ~(0 as usize) {
first_deleted = i;
}
i = (i + 1) & mask;
probes = probes + 1;
}
if first_deleted != ~(0 as usize) {
i = first_deleted;
}
copy((self.keys.data + i * self.key_size) as *any, key as *any, self.key_size);
copy((self.vals.data + i * self.val_size) as *any, val as *any, self.val_size);
self.states.data[i] = state_code(occupied);
self.size = self.size + 1;
}
// 保证至少 need 个槽位。所有检查在旧表改动前完成,失败保持原表不变。 // 保证至少 need 个槽位。所有检查在旧表改动前完成,失败保持原表不变。
fn reserve(self: *Map, need: usize): Status { fn reserve(self: *Map, need: usize): Status {
if !valid(self.*) { ret .Err(make(.InvalidArgument)); } ret status_from_code(vm_map_reserve(self as *any, need));
if need <= self.states.cap { ret .Ok; }
var new_cap = grow_capacity(self.states.cap, 8, need);
var fresh = self.*;
fresh.keys = Vec.blank(self.key_size, self.keys.elem_align);
fresh.vals = Vec.blank(self.val_size, self.vals.elem_align);
fresh.states = Vec.blank(1, 1);
fresh.size = 0;
match Vec.reserve(&fresh.keys, new_cap) {
.Ok => {},
.Err(error) => { drop(&fresh); ret .Err(error); },
}
match Vec.reserve(&fresh.vals, new_cap) {
.Ok => {},
.Err(error) => { drop(&fresh); ret .Err(error); },
}
match Vec.reserve(&fresh.states, new_cap) {
.Ok => {},
.Err(error) => { drop(&fresh); ret .Err(error); },
}
fresh.keys.len = new_cap;
fresh.vals.len = new_cap;
fresh.states.len = new_cap;
var i: usize = 0;
var empty: SlotState = .Empty;
var occupied: SlotState = .Occupied;
while i < new_cap {
fresh.states.data[i] = state_code(empty);
i = i + 1;
}
i = 0;
while i < self.states.len {
if self.states.data[i] == state_code(occupied) {
place(&fresh, self.keys.data + i * self.key_size,
self.vals.data + i * self.val_size);
}
i = i + 1;
}
var old_keys = self.keys;
var old_vals = self.vals;
var old_states = self.states;
self.* = fresh;
Vec.drop(&old_keys);
Vec.drop(&old_vals);
Vec.drop(&old_states);
ret .Ok;
} }
// 覆盖已存在的键;否则插入并可能扩容。 // 覆盖已存在的键;否则插入并可能扩容。
fn put(self: *Map, key: *u8, val: *u8): Status { fn put(self: *Map, key: *u8, val: *u8): Status {
if !valid(self.*) || key == null || val == null { ret status_from_code(vm_map_put(self as *any, key as *any, val as *any));
ret .Err(make(.InvalidArgument));
}
var existing = find_slot(self, key);
if existing != ~(0 as usize) {
copy((self.vals.data + existing * self.val_size) as *any, val as *any, self.val_size);
ret .Ok;
}
if self.states.cap == 0 {
match reserve(self, 8) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
} else {
var next_size: usize = 0;
match checked_add(self.size, 1) {
.Ok(value) => { next_size = value; },
.Err(error) => { ret .Err(error); },
}
var scaled: usize = 0;
match checked_mul(next_size, 128) {
.Ok(value) => { scaled = value; },
.Err(error) => { ret .Err(error); },
}
if scaled / self.states.cap >= 70 {
var need: usize = 0;
match checked_mul(self.states.cap, 2) {
.Ok(value) => { need = value; },
.Err(error) => { ret .Err(error); },
}
match reserve(self, need) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
}
}
place(self, key, val);
ret .Ok;
} }
// 找到键则把值复制到 out 并返回 Found;否则 out 不变并返回 NotFound。 // 找到键则把值复制到 out 并返回 Found;否则 out 不变并返回 NotFound。
fn get(self: *Map, key: *u8, out: *u8): LookupResult { fn get(self: *Map, key: *u8, out: *u8): LookupResult {
if !valid(self.*) || key == null || out == null { ret .NotFound; } ret lookup_from_code(vm_map_get(self as *any, key as *any, out as *any));
var i = find_slot(self, key);
if i == ~(0 as usize) { ret .NotFound; }
copy(out as *any, (self.vals.data + i * self.val_size) as *any, self.val_size);
ret .Found;
} }
fn del(self: *Map, key: *u8): LookupResult { fn del(self: *Map, key: *u8): LookupResult {
if !valid(self.*) || key == null { ret .NotFound; } ret lookup_from_code(vm_map_del(self as *any, key as *any));
var i = find_slot(self, key);
if i == ~(0 as usize) { ret .NotFound; }
var deleted_state: SlotState = .Deleted;
self.states.data[i] = state_code(deleted_state);
self.size = self.size - 1;
ret .Found;
} }
// 清空内容但保留容量。墓碑与负载计数一并复位。 // 清空内容但保留容量。墓碑与负载计数一并复位。
fn clear(self: *Map) { fn clear(self: *Map) {
var i: usize = 0; vm_map_clear(self as *any);
var empty: SlotState = .Empty;
while i < self.states.len {
self.states.data[i] = state_code(empty);
i = i + 1;
}
self.size = 0;
} }
fn drop(self: *Map) { fn drop(self: *Map) {
Vec.drop(&self.keys); vm_map_drop(self as *any);
Vec.drop(&self.vals);
Vec.drop(&self.states);
self.size = 0;
} }
fn take(source: *Map): Map { fn take(source: *Map): Map {
@@ -348,13 +203,13 @@ fn deleted(m: *Map, key: *u8): bool {
} }
fn make_int_map(): Map { fn make_int_map(): Map {
ret new(@sizeof(usize), @alignof(usize), @sizeof(i32), @alignof(i32), hash_usize, eq_usize); ret new(@sizeof(usize), @alignof(usize), @sizeof(i32), @alignof(i32), hash_kind_usize());
} }
fn test_put_get_update() { fn test_put_get_update() {
var m = make_int_map(); var m = make_int_map();
@assert(size(m) == 0 && capacity(m) == 0, "empty map"); @assert(size(m) == 0 && capacity(m) == 0, "empty map");
@assert(valid(m)); @assert(valid(&m));
var key: usize = 0; var key: usize = 0;
var value: i32 = 0; var value: i32 = 0;
@@ -367,7 +222,7 @@ fn test_put_get_update() {
key = 7; key = 7;
value = 70; value = 70;
expect_ok(put(&m, &key as *u8, &value as *u8)); expect_ok(put(&m, &key as *u8, &value as *u8));
@assert(size(m) == 1 && valid(m)); @assert(size(m) == 1 && valid(&m));
out = -1; out = -1;
@assert(found(&m, &key as *u8, &out as *u8) && out == 70, "insert then get"); @assert(found(&m, &key as *u8, &out as *u8) && out == 70, "insert then get");
@@ -463,7 +318,7 @@ fn test_take_and_self_put() {
fn test_byte_view_keys() { fn test_byte_view_keys() {
var m = new(@sizeof(ByteView), @alignof(ByteView), @sizeof(i32), @alignof(i32), var m = new(@sizeof(ByteView), @alignof(ByteView), @sizeof(i32), @alignof(i32),
hash_view, eq_view); hash_kind_view());
defer { drop(&m); } defer { drop(&m); }
var alpha = ByteView.from_slice("alpha"); var alpha = ByteView.from_slice("alpha");
+3 -25
View File
@@ -5,6 +5,7 @@
type .{ .Error, .Status, .make } = @import("error.spl"); type .{ .Error, .Status, .make } = @import("error.spl");
#extern(vm) fn vm_memcpy(dst: *any, src: *any, n: usize): *any; #extern(vm) fn vm_memcpy(dst: *any, src: *any, n: usize): *any;
#extern(vm) fn vm_memmove(dst: *any, src: *any, n: usize): *any;
fn ignore_ptr(p: *any) {} fn ignore_ptr(p: *any) {}
@@ -73,31 +74,8 @@ fn move(dst: []u8, src: []u8): Status {
} }
if dst_addr == src_addr { ret .Ok; } if dst_addr == src_addr { ret .Ok; }
// 非重叠且较大时走原生 memcpy(Vec 扩容复制是常见场景)。 // 重叠安全,统一走原生 memmove。
var non_overlap = false; ignore_ptr(vm_memmove(dst.ptr as *any, src.ptr as *any, count));
if dst_addr < src_addr {
if src_addr - dst_addr >= count { non_overlap = true; }
} else {
if dst_addr - src_addr >= count { non_overlap = true; }
}
if non_overlap && count >= 16 {
ignore_ptr(vm_memcpy(dst.ptr as *any, src.ptr as *any, count));
ret .Ok;
}
if dst_addr < src_addr {
var i: usize = 0;
while i < count {
dst.ptr[i] = src.ptr[i];
i = i + 1;
}
} else {
var i = count;
while i > 0 {
i = i - 1;
dst.ptr[i] = src.ptr[i];
}
}
ret .Ok; ret .Ok;
} }
+8 -8
View File
@@ -3,7 +3,8 @@
// 开放寻址集合。键按字节复制到集合自己的存储中;集合只释放自身存储, // 开放寻址集合。键按字节复制到集合自己的存储中;集合只释放自身存储,
// 不释放键值内部引用的资源。哈希与相等回调的约定和 Map 一致。 // 不释放键值内部引用的资源。哈希与相等回调的约定和 Map 一致。
type .{ .Status } = @import("error.spl"); type .{ .Status } = @import("error.spl");
type .{ .Map, .LookupResult } = @import("map.spl"); type .{ .Map, .LookupResult, .hash_kind_usize, .hash_kind_view, .hash_kind_constant } =
@import("map.spl");
type .{ .ByteView } = @import("byte_view.spl"); type .{ .ByteView } = @import("byte_view.spl");
type .{ .hash_usize, .eq_usize, .hash_view, .eq_view } = @import("hash.spl"); type .{ .hash_usize, .eq_usize, .hash_view, .eq_view } = @import("hash.spl");
@@ -11,15 +12,14 @@ type Set = @self;
map: Map, map: Map,
fn new(key_size: usize, key_align: usize, fn new(key_size: usize, key_align: usize, hash_kind: usize): Set {
hash_fn: fn(*u8): usize, eq_fn: fn(*u8, *u8): bool): Set {
ret Set { ret Set {
.map = Map.new(key_size, key_align, 1, 1, hash_fn, eq_fn), .map = Map.new(key_size, key_align, 1, 1, hash_kind),
}; };
} }
fn valid(self: Set): bool { fn valid(self: Set): bool {
ret Map.valid(self.map) && self.map.val_size == 1; ret Map.valid(&self.map) && self.map.val_size == 1;
} }
fn size(self: Set): usize { fn size(self: Set): usize {
@@ -104,7 +104,7 @@ fn constant_hash(key: *u8): usize {
} }
fn test_insert_find_remove() { fn test_insert_find_remove() {
var set = new(@sizeof(usize), @alignof(usize), hash_usize, eq_usize); var set = new(@sizeof(usize), @alignof(usize), hash_kind_usize());
defer { drop(&set); } defer { drop(&set); }
@assert(valid(set)); @assert(valid(set));
@assert(size(set) == 0 && capacity(set) == 0); @assert(size(set) == 0 && capacity(set) == 0);
@@ -169,7 +169,7 @@ fn test_insert_find_remove() {
} }
fn test_collisions_and_take() { fn test_collisions_and_take() {
var set = new(@sizeof(usize), @alignof(usize), constant_hash, eq_usize); var set = new(@sizeof(usize), @alignof(usize), hash_kind_constant());
defer { drop(&set); } defer { drop(&set); }
var i: usize = 0; var i: usize = 0;
@@ -213,7 +213,7 @@ fn test_collisions_and_take() {
} }
fn test_byte_view_keys() { fn test_byte_view_keys() {
var set = new(@sizeof(ByteView), @alignof(ByteView), hash_view, eq_view); var set = new(@sizeof(ByteView), @alignof(ByteView), hash_kind_view());
defer { drop(&set); } defer { drop(&set); }
var alpha = ByteView.from_slice("alpha"); var alpha = ByteView.from_slice("alpha");
+2 -2
View File
@@ -6,7 +6,7 @@
type .{ .Error, .Status, .make } = @import("error.spl"); type .{ .Error, .Status, .make } = @import("error.spl");
type .{ .ByteView, .FindResult } = @import("byte_view.spl"); type .{ .ByteView, .FindResult } = @import("byte_view.spl");
type .{ .Vec } = @import("vec.spl"); type .{ .Vec } = @import("vec.spl");
type .{ .Map } = @import("map.spl"); type .{ .Map, .hash_kind_view } = @import("map.spl");
type .{ .hash_view, .eq_view } = @import("hash.spl"); type .{ .hash_view, .eq_view } = @import("hash.spl");
type Position = struct { type Position = struct {
@@ -134,7 +134,7 @@ fn set_new(): Sources {
ret Sources { ret Sources {
.items = Vec.blank(@sizeof(Source), 8), .items = Vec.blank(@sizeof(Source), 8),
.by_name = Map.blank(@sizeof(ByteView), @alignof(ByteView), @sizeof(usize), .by_name = Map.blank(@sizeof(ByteView), @alignof(ByteView), @sizeof(usize),
@alignof(usize), hash_view, eq_view), @alignof(usize), hash_kind_view()),
}; };
} }
+44 -172
View File
@@ -7,6 +7,18 @@ type .{ .Error, .Kind, .Status } = @import("error.spl");
type .{ .SizeResult, .checked_add, .checked_mul, .grow_capacity, .move } = @import("memory.spl"); type .{ .SizeResult, .checked_add, .checked_mul, .grow_capacity, .move } = @import("memory.spl");
type .{ .alloc, .copy, .free } = @import("../sys/mem.spl"); type .{ .alloc, .copy, .free } = @import("../sys/mem.spl");
#extern(vm) fn vm_vec_valid(v: *any): i32;
#extern(vm) fn vm_vec_push_raw(v: *any, elem: *any): i32;
#extern(vm) fn vm_vec_push(v: *any, elem: *any): i32;
#extern(vm) fn vm_vec_get(v: *any, index: usize, out: *any): i32;
#extern(vm) fn vm_vec_allocate(out: *any, capacity: usize, elem_size: usize, elem_align: usize): i32;
#extern(vm) fn vm_vec_reserve_raw(v: *any, need: usize): i32;
#extern(vm) fn vm_vec_append(v: *any, elems: *any, count: usize): i32;
#extern(vm) fn vm_vec_set(v: *any, index: usize, elem: *any): i32;
#extern(vm) fn vm_vec_pop(v: *any, out: *any): i32;
#extern(vm) fn vm_vec_clone(out: *any, src: *any): i32;
#extern(vm) fn vm_vec_drop(v: *any): void;
type Vec = @self; type Vec = @self;
raw: *u8, raw: *u8,
@@ -51,95 +63,41 @@ fn new(elem_size: usize, elem_align: usize): VecResult {
// 按指针接收,避免每次调用复制整个 Vec;内联对齐检查,省一次函数调用。 // 按指针接收,避免每次调用复制整个 Vec;内联对齐检查,省一次函数调用。
fn valid(self: *Vec): bool { fn valid(self: *Vec): bool {
if self.elem_size == 0 { ret false; } ret vm_vec_valid(self as *any) != 0;
var a = self.elem_align;
if a == 0 || (a & (a - 1)) != 0 { ret false; }
if self.len > self.cap { ret false; }
if self.cap == 0 {
ret self.raw == null && self.data == null && self.len == 0;
}
if self.raw == null || self.data == null { ret false; }
ret (self.data as usize & (a - 1)) == 0;
} }
fn status_error(kind: Kind): Status { fn status_error(kind: Kind): Status {
ret .Err(Error.make(kind)); ret .Err(Error.make(kind));
} }
// native 错误码 -> Error.Kind(0 ok / 1 InvalidArgument / 2 OutOfRange / 3 Overflow / 4 InvalidAlignment)
fn kind_from_code(code: i32): Kind {
if code == 2 { ret .OutOfRange; }
if code == 3 { ret .Overflow; }
if code == 4 { ret .InvalidAlignment; }
ret .InvalidArgument;
}
fn status_from_code(code: i32): Status {
if code == 0 { ret .Ok; }
ret status_error(kind_from_code(code));
}
// 计算元素区字节数。错误时不修改任何 Vec。 // 计算元素区字节数。错误时不修改任何 Vec。
fn byte_count(count: usize, elem_size: usize): SizeResult { fn byte_count(count: usize, elem_size: usize): SizeResult {
ret checked_mul(count, elem_size); ret checked_mul(count, elem_size);
} }
fn allocate(capacity: usize, elem_size: usize, elem_align: usize): VecResult { fn allocate(capacity: usize, elem_size: usize, elem_align: usize): VecResult {
if elem_size == 0 { ret .Err(Error.make(.InvalidArgument)); } var v: Vec = undefined;
if !valid_alignment(elem_align) { var rc = vm_vec_allocate(&v as *any, capacity, elem_size, elem_align);
ret .Err(Error.make(.InvalidAlignment)); if rc == 0 { ret .Ok(v); }
} ret .Err(Error.make(kind_from_code(rc)));
if capacity == 0 { ret .Ok(blank(elem_size, elem_align)); }
var bytes: usize = 0;
match byte_count(capacity, elem_size) {
.Ok(value) => { bytes = value; },
.Err(error) => { ret .Err(error); },
}
var total: usize = 0;
match checked_add(bytes, elem_align - 1) {
.Ok(value) => { total = value; },
.Err(error) => { ret .Err(error); },
}
var raw = alloc(total) as *u8;
if raw == null {
ret .Err(Error.make(.Overflow));
}
var address = raw as usize;
var mask = elem_align - 1;
if address > (~(0 as usize)) - mask {
free(raw as *any);
ret .Err(Error.make(.Overflow));
}
var aligned = (address + mask) & ~mask;
ret .Ok(Vec {
.raw = raw,
.data = aligned as *u8,
.len = 0,
.cap = capacity,
.elem_size = elem_size,
.elem_align = elem_align,
});
} }
// 与 reserve 相同,但假定调用方已校验 self(内部热路径用,省去重复 valid)。 // 与 reserve 相同,但假定调用方已校验 self(内部热路径用,省去重复 valid)。
fn reserve_raw(self: *Vec, need: usize): Status { fn reserve_raw(self: *Vec, need: usize): Status {
if need <= self.cap { ret .Ok; } ret status_from_code(vm_vec_reserve_raw(self as *any, need));
var new_cap = grow_capacity(self.cap, 8, need);
var fresh: Vec = undefined;
match allocate(new_cap, self.elem_size, self.elem_align) {
.Ok(value) => { fresh = value; },
.Err(error) => { ret .Err(error); },
}
var used_bytes: usize = 0;
match byte_count(self.len, self.elem_size) {
.Ok(value) => { used_bytes = value; },
.Err(error) => {
drop(&fresh);
ret .Err(error);
},
}
if used_bytes != 0 {
copy(fresh.data as *any, self.data as *any, used_bytes);
}
fresh.len = self.len;
var old_raw = self.raw;
self.* = fresh;
free(old_raw as *any);
ret .Ok;
} }
// 保证至少可容纳 need 个元素(外部入口,含校验)。 // 保证至少可容纳 need 个元素(外部入口,含校验)。
@@ -154,81 +112,30 @@ fn with_capacity(elem_size: usize, elem_align: usize, capacity: usize): VecResul
} }
fn get(self: *Vec, index: usize): PtrResult { fn get(self: *Vec, index: usize): PtrResult {
if !valid(self) { ret .Err(Error.make(.InvalidArgument)); } var out: *u8 = null;
if index >= self.len { ret .Err(Error.make(.OutOfRange)); } var rc = vm_vec_get(self as *any, index, &out as *any);
ret .Ok(self.data + index * self.elem_size); if rc == 0 { ret .Ok(out); }
if rc == 2 { ret .Err(Error.make(.OutOfRange)); }
ret .Err(Error.make(.InvalidArgument));
} }
fn set(self: *Vec, index: usize, elem: *u8): Status { fn set(self: *Vec, index: usize, elem: *u8): Status {
if !valid(self) || elem == null { ret status_error(.InvalidArgument); } ret status_from_code(vm_vec_set(self as *any, index, elem as *any));
if index >= self.len { ret status_error(.OutOfRange); }
var dst = self.data + index * self.elem_size;
ret move(dst[0..self.elem_size], elem[0..self.elem_size]);
} }
// 追加 count 个连续元素。elems 可以指向 self 当前已初始化的元素区。 // 追加 count 个连续元素。elems 可以指向 self 当前已初始化的元素区。
fn append(self: *Vec, elems: *u8, count: usize): Status { fn append(self: *Vec, elems: *u8, count: usize): Status {
if !valid(self) { ret status_error(.InvalidArgument); } ret status_from_code(vm_vec_append(self as *any, elems as *any, count));
if count == 0 { ret .Ok; }
if elems == null { ret status_error(.InvalidArgument); }
var copy_bytes: usize = 0;
match byte_count(count, self.elem_size) {
.Ok(value) => { copy_bytes = value; },
.Err(error) => { ret .Err(error); },
}
var new_len: usize = 0;
match checked_add(self.len, count) {
.Ok(value) => { new_len = value; },
.Err(error) => { ret .Err(error); },
}
var used_bytes: usize = 0;
match byte_count(self.len, self.elem_size) {
.Ok(value) => { used_bytes = value; },
.Err(error) => { ret .Err(error); },
}
var source_inside = false;
var source_offset: usize = 0;
if used_bytes != 0 {
var base = self.data as usize;
var source = elems as usize;
if source >= base && source - base < used_bytes {
source_offset = source - base;
if copy_bytes > used_bytes - source_offset {
ret status_error(.OutOfRange);
}
source_inside = true;
}
}
match reserve_raw(self, new_len) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
if source_inside { elems = self.data + source_offset; }
var dst = self.data + used_bytes;
match move(dst[0..copy_bytes], elems[0..copy_bytes]) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
self.len = new_len;
ret .Ok;
} }
fn push(self: *Vec, elem: *u8): Status { fn push(self: *Vec, elem: *u8): Status {
ret append(self, elem, 1); ret status_from_code(vm_vec_push(self as *any, elem as *any));
} }
// 热路径:假定 self 有效且已有容量时直接写入;容量不足才回退到 append。 // 热路径:假定 self 有效且已有容量时直接写入;容量不足才回退到 append。
fn push_raw(self: *Vec, elem: *u8): bool { fn push_raw(self: *Vec, elem: *u8): bool {
if self.len < self.cap { if elem == null { ret false; }
copy(self.data + self.len * self.elem_size, elem, self.elem_size); if vm_vec_push_raw(self as *any, elem as *any) != 0 { ret true; }
self.len = self.len + 1;
ret true;
}
match append(self, elem, 1) { match append(self, elem, 1) {
.Ok => { ret true; }, .Ok => { ret true; },
.Err(error) => { ret false; }, .Err(error) => { ret false; },
@@ -238,15 +145,7 @@ fn push_raw(self: *Vec, elem: *u8): bool {
// 将末元素复制到 out,然后缩短数组。out 可以与元素区重叠。 // 将末元素复制到 out,然后缩短数组。out 可以与元素区重叠。
fn pop(self: *Vec, out: *u8): Status { fn pop(self: *Vec, out: *u8): Status {
if !valid(self) || out == null { ret status_error(.InvalidArgument); } ret status_from_code(vm_vec_pop(self as *any, out as *any));
if self.len == 0 { ret status_error(.OutOfRange); }
var source = self.data + (self.len - 1) * self.elem_size;
match move(out[0..self.elem_size], source[0..self.elem_size]) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
self.len = self.len - 1;
ret .Ok;
} }
fn clear(self: *Vec) { fn clear(self: *Vec) {
@@ -256,31 +155,7 @@ fn clear(self: *Vec) {
// 成功时先释放 out 原有存储再提交副本;失败保持 out 不变。 // 成功时先释放 out 原有存储再提交副本;失败保持 out 不变。
// out 与 src 指向同一个 Vec 也允许。 // out 与 src 指向同一个 Vec 也允许。
fn clone(out: *Vec, src: Vec): Status { fn clone(out: *Vec, src: Vec): Status {
if !valid(out) || !valid(&src) { ret status_error(.InvalidArgument); } ret status_from_code(vm_vec_clone(out as *any, &src as *any));
if out.elem_size != src.elem_size || out.elem_align != src.elem_align {
ret status_error(.InvalidArgument);
}
var fresh = blank(src.elem_size, src.elem_align);
match reserve(&fresh, src.len) {
.Ok => {},
.Err(error) => { ret .Err(error); },
}
var bytes: usize = 0;
match byte_count(src.len, src.elem_size) {
.Ok(value) => { bytes = value; },
.Err(error) => {
drop(&fresh);
ret .Err(error);
},
}
if bytes != 0 {
copy(fresh.data as *any, src.data as *any, bytes);
}
fresh.len = src.len;
drop(out);
out.* = fresh;
ret .Ok;
} }
// 显式转移所有权,返回值必须由接收方最终 drop。 // 显式转移所有权,返回值必须由接收方最终 drop。
@@ -291,10 +166,7 @@ fn take(source: *Vec): Vec {
} }
fn drop(self: *Vec) { fn drop(self: *Vec) {
var elem_size = self.elem_size; vm_vec_drop(self as *any);
var elem_align = self.elem_align;
free(self.raw as *any);
self.* = blank(elem_size, elem_align);
} }
fn expect_ok(result: Status) { fn expect_ok(result: Status) {