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);
|
||||
}
|
||||
Reference in new issue
Block a user