stage2 大量优化代码使其自举编译时间大幅缩短
This commit is contained in:
1 parent
e02b0c633a
commit
846f441e3a
38 files changed
+2418
-835
No files matched your search
+612
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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); }
|
||||
@@ -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__ */
|
||||
Reference in new issue
Block a user