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

+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;
VEC(usize) node_ip;
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;
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);
}
/* ---------- 块内栈化(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 {
bool indirect;
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) {
uint8_t k = vm_kind_of(cg->ctx, n->arith.tid);
cg_load_slot(cg, n->arith.left, k);
cg_load_slot(cg, n->arith.right, k);
cg_operand(cg, n->arith.left, k, 0);
cg_operand(cg, n->arith.right, k, 1);
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) {
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_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) {
uint8_t k = vm_kind_of(cg->ctx, n->cmp.tid);
cg_load_slot(cg, n->cmp.a, k);
cg_load_slot(cg, n->cmp.b, k);
cg_operand(cg, n->cmp.a, k, 0);
cg_operand(cg, n->cmp.b, k, 1);
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) {
@@ -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_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;
}
@@ -507,7 +748,7 @@ static void cg_const(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
break;
}
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) {
@@ -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 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) {
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);
}
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) {
@@ -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);
} else {
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_store_slot(cg, ref, k);
cg_result(cg, ref, k);
}
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);
} else {
uint8_t k = vm_kind_of(ctx, tid);
cg_load_slot(cg, n->mem_store.ptr, SPL_PTR);
cg_load_slot(cg, n->mem_store.val, k);
cg_operand(cg, n->mem_store.ptr, SPL_PTR, 0);
cg_operand(cg, n->mem_store.val, k, 1);
CG_STORE(cg, k);
}
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);
if (elem_size == 0)
elem_size = 1;
cg_load_slot(cg, n->mem_offset.ptr, SPL_PTR);
cg_load_slot(cg, n->mem_offset.offset, SPL_U64);
cg_operand(cg, n->mem_offset.ptr, SPL_PTR, 0);
cg_operand(cg, n->mem_offset.offset, SPL_U64, 1);
CG_PUSH(cg, SPL_U64, elem_size);
CG_OP(cg, SPL_MUL, SPL_U64);
CG_OP(cg, SPL_ADD, SPL_PTR);
cg_store_slot(cg, ref, SPL_PTR);
cg_result(cg, ref, SPL_PTR);
break;
}
case SPL_IR_MEM_FIELD_PTR: {
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);
cg_load_slot(cg, n->mem_field_ptr.agg, SPL_PTR);
cg_operand(cg, n->mem_field_ptr.agg, SPL_PTR, 0);
if (off) {
CG_PUSH(cg, SPL_U64, off);
CG_OP(cg, SPL_ADD, SPL_PTR);
}
cg_store_slot(cg, ref, SPL_PTR);
cg_result(cg, ref, SPL_PTR);
break;
}
@@ -742,7 +983,7 @@ static void cg_typeop(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
return;
}
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) {
@@ -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);
spl_type_id_t ptid = ir_result_tid(ctx, pn);
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);
emit(cg, SPL_NCALL, SPL_VOID, (spl_vm_val_t)nargs);
uint8_t rk = vm_kind_of(ctx, n->control_call.tid);
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
cg_store_slot(cg, ref, rk);
cg_result(cg, ref, rk);
} else {
spl_type_id_t ret_t = n->control_call.tid;
bool ret_is_sret = ir_is_aggregate(ctx, ret_t);
usize sret_off = 0;
usize j = 0;
if (ret_is_sret) {
sret_off = vec_at(cg->frame.slots, ref).data_off;
CG_LADDR(cg, sret_off);
j = 1;
}
for (usize i = 0; i < nargs; ++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);
spl_type_id_t ptid = ir_result_tid(ctx, pn);
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);
emit(cg, SPL_CALL, SPL_VOID, actual_nargs);
if (ret_is_sret) {
/* 结果槽保存 sret 指针,后续 agg_extract 把它当聚合首地址 */
/* result slot saves sret pointer */
CG_LADDR(cg, sret_off);
cg_store_slot(cg, ref, SPL_PTR);
cg_result(cg, ref, SPL_PTR);
} else {
uint8_t rk = vm_kind_of(ctx, ret_t);
if (rk != SPL_VOID)
cg_store_slot(cg, ref, rk);
cg_result(cg, ref, rk);
}
}
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: {
spl_type_node_t *tn = spl_type_node(cg->ctx->type, n->arith.tid);
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_OP(cg, SPL_EQ, SPL_BOOL);
cg_store_slot(cg, ref, SPL_BOOL);
cg_result(cg, ref, SPL_BOOL);
} else {
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)
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) {
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);
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) {
@@ -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); }
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);
ctx->ir = ir;
ctx->type = type;
ctx->attr = attr;
ctx->layout = layout;
ctx->opt = opt;
map_init(ctx->extern_native, spl_map_hash, spl_map_cmp);
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_diag_t *diag;
int opt; /* 非 0:块内操作数栈化(表达式临时值留栈,块边界溢出回槽) */
} spl_ir2vm_t;
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);
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);
/* Nested imports share def_table, but each module has its own scope.
* Resolve other modules' signatures only when processing their AST. */
if (d->owner_ast == sema->ast && d->kind == SPL_DEF_FN &&
d->state == SPL_DECL_UNRESOLVED)
if (d->owner_ast == sema->ast && d->kind == SPL_DEF_FN && d->state == SPL_DECL_UNRESOLVED)
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;
if (!spl_scope_find(sema->scope, n->ident.name, &symbol) ||
symbol.kind != SPL_SYMBOL_KIND_TYPE) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg,
"`%s` is not a type", n->ident.name);
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, "`%s` is not a type",
n->ident.name);
return 0;
}
spl_def_node_t *def = spl_def_node(sema->type, symbol.node);
if (!sema_def_is_type(def)) {
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg,
"`%s` is not a type", n->ident.name);
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg, "`%s` is not a type",
n->ident.name);
return 0;
}
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;
vec_init(elements);
for (usize i = 0; i < vec_size(n->tuple.elems); ++i) {
spl_lang_type_id_t element =
sema_infer_type_context(sema, vec_at(n->tuple.elems, i));
spl_lang_type_id_t element = sema_infer_type_context(sema, vec_at(n->tuple.elems, i));
if (!element) {
vec_free(elements);
return 0;
}
vec_push(elements, element);
}
spl_lang_type_id_t result = spl_lang_make_tuple(
sema->type, vec_unsafe_get_data(elements), vec_size(elements));
spl_lang_type_id_t result =
spl_lang_make_tuple(sema->type, vec_unsafe_get_data(elements), vec_size(elements));
vec_free(elements);
n->resolved_lang_tid = result;
return result;
@@ -2866,6 +2864,7 @@ void spl_sema_dump(spl_sema_t *sema) {
printf("Scopes:\n");
for (usize i = 1; i < vec_size(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);
/* 按符号名排序输出:与哈希表内部布局解耦,保证确定顺序。 */
@@ -2873,6 +2872,7 @@ void spl_sema_dump(spl_sema_t *sema) {
spl_sema_sym_t *arr = nsyms ? malloc(nsyms * sizeof(*arr)) : NULL;
usize k = 0;
map_for(scope->symbols, j) {
Assert(arr != NULL);
arr[k].key = unsafe_map_at(scope->symbols, j).key;
arr[k].sym = unsafe_map_at(scope->symbols, j).val;
k++;
@@ -2880,6 +2880,7 @@ void spl_sema_dump(spl_sema_t *sema) {
if (arr && nsyms > 1)
qsort(arr, nsyms, sizeof(*arr), spl_sema_sym_cmp);
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);
}
free(arr);
+30 -7
View File
@@ -10,6 +10,9 @@
#include <stdlib.h>
#include <string.h>
#include "ir_opt.h"
#include "vm_opt.h"
#include "spl_ast.h"
#include "spl_ast2ir.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,
dump_t dump) {
dump_t dump, int opt) {
(void)gen_debug;
spl_diag_t diag;
@@ -326,6 +329,10 @@ static int compile_spl(const char *src, const char *fname, const char *outpath,
rc = 1;
goto cleanup;
}
/* IR 层优化 pass(默认关闭,--opt 开启)。 */
if (opt)
spl_ir_opt(&ir_builder.ir, &attr);
if (dump == DUMP_IR) {
spl_ir_dump(&ir_builder.ir, &lang_type.ir, &attr);
goto cleanup;
@@ -334,7 +341,7 @@ static int compile_spl(const char *src, const char *fname, const char *outpath,
/* 类型已全部就绪:解析 layout,供 ir2vm 的 size/align/offset 使用。 */
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;
spl_diag_set_stage(&diag, SPL_STAGE_IR2VM);
ir2vm.diag = &diag;
@@ -348,6 +355,10 @@ static int compile_spl(const char *src, const char *fname, const char *outpath,
goto cleanup;
}
/* ir2vm 之后的字节码优化 pass(默认关闭,--opt 开启)。 */
if (opt)
spl_prog_opt(&ir2vm.prog);
spl_prog_store_to_file(outpath, &ir2vm.prog);
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");
return 0;
}
int opt = 0;
for (int ai = 1; ai < argc; ai++)
if (strcmp(argv[ai], "--opt") == 0)
opt = 1;
int argi = 1;
if (argi >= argc) {
LOG_FATAL("Usage: splc0 [--dump <flags>] <in> [out]");
@@ -435,19 +451,26 @@ int main(int argc, char **argv) {
return 1;
}
int gen_debug = 0;
if (strcmp(argv[argi], "-g") == 0) {
gen_debug = 1;
argi++;
while (argi < argc - 1) {
if (strcmp(argv[argi], "-g") == 0) {
gen_debug = 1;
argi++;
} else if (strcmp(argv[argi], "--opt") == 0) {
opt = 1;
argi++;
} else {
break;
}
}
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;
}
long len;
char *src = read_file(argv[argi], &len);
if (!src)
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);
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__ */