Compare commits
2
Commits
09d05e3a34
...
7cbe2d2b9a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7cbe2d2b9a | ||
|
|
f6a0bce9f0 |
No files matched your search
+16
-28
@@ -115,38 +115,26 @@ typedef enum {
|
|||||||
* [strtab] each: slen, str(pad8)
|
* [strtab] each: slen, str(pad8)
|
||||||
* [gdata] each: dsize(8), data(dsize bytes, padded to 8)
|
* [gdata] each: dsize(8), data(dsize bytes, padded to 8)
|
||||||
*
|
*
|
||||||
* === Calling Convention ===
|
* === Aggregate Return ABI (sret) ===
|
||||||
|
*
|
||||||
|
* 凡返回值类型为聚合(struct / union / enum / array / shape),
|
||||||
|
* 采用调用者分配 / 被调用者填充的间接返回约定:
|
||||||
*
|
*
|
||||||
* Before CALL:
|
* Before CALL:
|
||||||
* - args pushed left-to-right
|
* - caller 在自己的帧里 alloca 一块 RetTy 大小的空间
|
||||||
* - target address pushed last
|
* - 该空间的地址作为第 0 个实参先压栈
|
||||||
|
* - 其余实参照常从左到右压栈
|
||||||
|
* - target 地址最后压栈
|
||||||
|
* - CALL imm = 普通实参个数 + 1
|
||||||
*
|
*
|
||||||
* CALL (imm = nargs):
|
* Callee 进入后:
|
||||||
* 1. pop target address
|
* - fp+0 存放 sret 指针
|
||||||
* 2. callstack[cp++] = {saved_fp, saved_ip, nargs}
|
* - 形参 i 位于 fp + 8*(i+1)
|
||||||
* 3. fp = sp - nargs (fp points to arg0)
|
* - 返回值直接写入 *(fp+0),然后执行 RET void
|
||||||
* 4. ip = target address
|
|
||||||
*
|
*
|
||||||
* ALLOC k:
|
* Caller 侧:
|
||||||
* sp += k (slots zeroed; local[j] = stacks.data[fp + nargs + j])
|
* - 调用完成后,CALL 结果槽保存 sret 指针;
|
||||||
*
|
* 后续对聚合值的所有读取都通过该指针进行
|
||||||
* LADDR imm:
|
|
||||||
* push &stacks.data[fp + imm]
|
|
||||||
* (imm < nargs accesses args; imm >= nargs accesses locals)
|
|
||||||
*
|
|
||||||
* GADDR imm:
|
|
||||||
* push prog->gdata[imm] (pointer to global data blob)
|
|
||||||
*
|
|
||||||
* RET:
|
|
||||||
* 1. pop retval if non-void type
|
|
||||||
* 2. sp = fp
|
|
||||||
* 3. pop frame; fp = saved_fp, ip = saved_ip
|
|
||||||
* 4. push retval if non-void type
|
|
||||||
*
|
|
||||||
* CALLI (indirect call):
|
|
||||||
* - stack before: ..., arg0, ..., argN-1, nargs, func_addr
|
|
||||||
* 1. pop func_addr, then pop nargs
|
|
||||||
* 2. same as CALL steps 2-4
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SPL_BINFMT_MAGIC "SPLBIN\0\0"
|
#define SPL_BINFMT_MAGIC "SPLBIN\0\0"
|
||||||
|
|||||||
+6
-3
@@ -175,11 +175,14 @@ static isize parse_int_literal(const spl_tok_t *t) {
|
|||||||
buf[j++] = t->lexeme[i];
|
buf[j++] = t->lexeme[i];
|
||||||
}
|
}
|
||||||
buf[j] = 0;
|
buf[j] = 0;
|
||||||
|
/* 字面量按无符号位模式解析,以容纳完整的 u64 值域 */
|
||||||
if (j >= 3 && buf[0] == '0' && (buf[1] == 'b' || buf[1] == 'B'))
|
if (j >= 3 && buf[0] == '0' && (buf[1] == 'b' || buf[1] == 'B'))
|
||||||
return (isize)strtoll(buf + 2, NULL, 2);
|
return (isize)strtoull(buf + 2, NULL, 2);
|
||||||
if (j >= 3 && buf[0] == '0' && (buf[1] == 'o' || buf[1] == 'O'))
|
if (j >= 3 && buf[0] == '0' && (buf[1] == 'o' || buf[1] == 'O'))
|
||||||
return (isize)strtoll(buf + 2, NULL, 8);
|
return (isize)strtoull(buf + 2, NULL, 8);
|
||||||
return (isize)strtoll(buf, NULL, 0);
|
if (j >= 3 && buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X'))
|
||||||
|
return (isize)strtoull(buf, NULL, 16);
|
||||||
|
return (isize)strtoull(buf, NULL, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
static double parse_float_literal(const spl_tok_t *t) {
|
static double parse_float_literal(const spl_tok_t *t) {
|
||||||
|
|||||||
+377
-224
@@ -21,6 +21,10 @@ static spl_ir_node_ref_t const_usize(spl_ast2ir_t *a, usize v) {
|
|||||||
return spl_ir_builder_type_const_int(a->ir, to_ir_type(a, t), v);
|
return spl_ir_builder_type_const_int(a->ir, to_ir_type(a, t), v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static spl_ir_node_ref_t emit_if_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
|
static spl_ir_node_ref_t emit_loop_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
|
static void emit_break_stmt(spl_ast2ir_t *a, spl_ast_node_t *n);
|
||||||
|
|
||||||
static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
@@ -30,8 +34,12 @@ static void emit_fn_body(spl_ast2ir_t *a, spl_ast_node_t *n);
|
|||||||
static void emit_container_reserve(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
static void emit_container_reserve(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
static void emit_container_body(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
static void emit_container_body(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
|
|
||||||
|
static spl_ir_node_ref_t ast2ir_emit_cast_builtin(spl_ast2ir_t *a, spl_ast_node_t *n,
|
||||||
|
spl_intrin_t in, spl_type_id_t ft,
|
||||||
|
spl_type_id_t tt, spl_ir_node_ref_t v);
|
||||||
static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, spl_ast_node_t *n);
|
static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, spl_ast_node_t *n);
|
||||||
static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
|
static spl_ir_node_ref_t emit_if_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
static spl_ir_node_ref_t emit_implicit_cast(spl_ast2ir_t *a, spl_type_id_t ft, spl_type_id_t tt,
|
static spl_ir_node_ref_t emit_implicit_cast(spl_ast2ir_t *a, spl_type_id_t ft, spl_type_id_t tt,
|
||||||
spl_ir_node_ref_t v);
|
spl_ir_node_ref_t v);
|
||||||
|
|
||||||
@@ -123,6 +131,32 @@ static void copy_attrs_to_ir_func(spl_ast2ir_t *a, spl_ast_node_t *n, spl_ir_fun
|
|||||||
vec_push(irf->attrs, vec_at(n->attrs, i));
|
vec_push(irf->attrs, vec_at(n->attrs, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static spl_ir_node_ref_t ast2ir_intrin_cast(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in,
|
||||||
|
spl_ast_node_ref_vec_t *args) {
|
||||||
|
usize nargs = vec_size(*args);
|
||||||
|
if (nargs < 1) {
|
||||||
|
SPL_ERROR(&n->dbg, "cast builtin requires at least 1 argument");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
spl_ir_node_ref_t v = emit_expr(a, vec_at(*args, 0));
|
||||||
|
if (!v)
|
||||||
|
return 0;
|
||||||
|
spl_ast_node_t *src = spl_ast_node(a->sema->ast, vec_at(*args, 0));
|
||||||
|
spl_type_id_t ft = node_ir(a, src);
|
||||||
|
|
||||||
|
spl_type_id_t tt = 0;
|
||||||
|
if (nargs >= 2) {
|
||||||
|
spl_ast_node_t *targ = spl_ast_node(a->sema->ast, vec_at(*args, 1));
|
||||||
|
tt = node_ir(a, targ);
|
||||||
|
} else {
|
||||||
|
/* 单参数形式:目标类型由 sema 在节点上标好的 resolved 类型给出 */
|
||||||
|
tt = node_ir(a, n);
|
||||||
|
}
|
||||||
|
if (!ft || !tt)
|
||||||
|
return 0;
|
||||||
|
return ast2ir_emit_cast_builtin(a, n, in, ft, tt, v);
|
||||||
|
}
|
||||||
|
|
||||||
static spl_ir_node_ref_t ast2ir_intrin_call(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in,
|
static spl_ir_node_ref_t ast2ir_intrin_call(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in,
|
||||||
spl_ast_node_ref_vec_t *args) {
|
spl_ast_node_ref_vec_t *args) {
|
||||||
switch (in) {
|
switch (in) {
|
||||||
@@ -177,6 +211,17 @@ static spl_ir_node_ref_t ast2ir_intrin_call(spl_ast2ir_t *a, spl_ast_node_t *n,
|
|||||||
spl_ir_builder_control_br_fixup(a->ir, br, panic_blk, cont_blk);
|
spl_ir_builder_control_br_fixup(a->ir, br, panic_blk, cont_blk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
case SPL_INTRIN_INT_CAST:
|
||||||
|
case SPL_INTRIN_TRUNCATE:
|
||||||
|
case SPL_INTRIN_BIT_CAST:
|
||||||
|
case SPL_INTRIN_FLOAT_CAST:
|
||||||
|
case SPL_INTRIN_INT_FROM_FLOAT:
|
||||||
|
case SPL_INTRIN_FLOAT_FROM_INT:
|
||||||
|
case SPL_INTRIN_INT_FROM_BOOL:
|
||||||
|
case SPL_INTRIN_INT_FROM_PTR:
|
||||||
|
case SPL_INTRIN_PTR_FROM_INT:
|
||||||
|
case SPL_INTRIN_PTR_CAST:
|
||||||
|
return ast2ir_intrin_cast(a, n, in, args);
|
||||||
case SPL_INTRIN_BREAKPOINT:
|
case SPL_INTRIN_BREAKPOINT:
|
||||||
return spl_ir_builder_dbg_breakpoint(a->ir);
|
return spl_ir_builder_dbg_breakpoint(a->ir);
|
||||||
default:
|
default:
|
||||||
@@ -351,6 +396,45 @@ static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static spl_ir_node_ref_t ast2ir_emit_cast_builtin(spl_ast2ir_t *a, spl_ast_node_t *n,
|
||||||
|
spl_intrin_t in, spl_type_id_t ft,
|
||||||
|
spl_type_id_t tt, spl_ir_node_ref_t v) {
|
||||||
|
switch (in) {
|
||||||
|
case SPL_INTRIN_INT_CAST: {
|
||||||
|
spl_type_node_t *fs = spl_type_node(a->sema->type, ft);
|
||||||
|
if (fs && fs->int_type.is_signed)
|
||||||
|
return spl_ir_builder_cast_sext(a->ir, ft, tt, v);
|
||||||
|
return spl_ir_builder_cast_zext(a->ir, ft, tt, v);
|
||||||
|
}
|
||||||
|
case SPL_INTRIN_TRUNCATE:
|
||||||
|
return spl_ir_builder_cast_trunc(a->ir, ft, tt, v);
|
||||||
|
case SPL_INTRIN_BIT_CAST:
|
||||||
|
return spl_ir_builder_cast_bitcast(a->ir, ft, tt, v);
|
||||||
|
case SPL_INTRIN_FLOAT_CAST: {
|
||||||
|
spl_type_node_t *fs = spl_type_node(a->sema->type, ft);
|
||||||
|
spl_type_node_t *ts = spl_type_node(a->sema->type, tt);
|
||||||
|
if (fs && ts && fs->float_type.bits > ts->float_type.bits)
|
||||||
|
return spl_ir_builder_cast_ftrunc(a->ir, ft, tt, v);
|
||||||
|
return spl_ir_builder_cast_fext(a->ir, ft, tt, v);
|
||||||
|
}
|
||||||
|
case SPL_INTRIN_INT_FROM_FLOAT:
|
||||||
|
return spl_ir_builder_case_float2int(a->ir, ft, tt, v);
|
||||||
|
case SPL_INTRIN_FLOAT_FROM_INT:
|
||||||
|
return spl_ir_builder_case_int2float(a->ir, ft, tt, v);
|
||||||
|
case SPL_INTRIN_INT_FROM_BOOL:
|
||||||
|
return spl_ir_builder_cast_bool2int(a->ir, ft, tt, v);
|
||||||
|
case SPL_INTRIN_INT_FROM_PTR:
|
||||||
|
return spl_ir_builder_cast_ptr2int(a->ir, ft, tt, v);
|
||||||
|
case SPL_INTRIN_PTR_FROM_INT:
|
||||||
|
return spl_ir_builder_cast_int2ptr(a->ir, ft, tt, v);
|
||||||
|
case SPL_INTRIN_PTR_CAST:
|
||||||
|
return spl_ir_builder_cast_bitcast(a->ir, ft, tt, v);
|
||||||
|
default:
|
||||||
|
SPL_ERROR(&n->dbg, "as: unknown cast builtin");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
||||||
spl_ir_node_ref_t v = emit_expr_raw(a, n->cast.expr);
|
spl_ir_node_ref_t v = emit_expr_raw(a, n->cast.expr);
|
||||||
if (!v)
|
if (!v)
|
||||||
@@ -359,36 +443,15 @@ static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
|||||||
spl_ast_node_t *dst = spl_ast_node(a->sema->ast, n->cast.type);
|
spl_ast_node_t *dst = spl_ast_node(a->sema->ast, n->cast.type);
|
||||||
spl_type_id_t ft = node_ir(a, src);
|
spl_type_id_t ft = node_ir(a, src);
|
||||||
spl_type_id_t tt = node_ir(a, dst);
|
spl_type_id_t tt = node_ir(a, dst);
|
||||||
spl_type_node_t *fs = spl_type_node(a->sema->type, ft);
|
if (!ft || !tt)
|
||||||
spl_type_node_t *ts = spl_type_node(a->sema->type, tt);
|
|
||||||
if (!fs || !ts)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (fs->kind == SPL_TYPE_INT && ts->kind == SPL_TYPE_INT) {
|
spl_intrin_t in = spl_intrin_lookup_cast(a->sema->type, ft, tt);
|
||||||
if (fs->int_type.bits == ts->int_type.bits)
|
if (in == SPL_INTRIN_NONE) {
|
||||||
return spl_ir_builder_cast_bitcast(a->ir, ft, tt, v);
|
SPL_ERROR(&n->dbg, "as: no conversion between the given types");
|
||||||
if (fs->int_type.bits > ts->int_type.bits)
|
return 0;
|
||||||
return spl_ir_builder_cast_trunc(a->ir, ft, tt, v);
|
|
||||||
if (fs->int_type.is_signed)
|
|
||||||
return spl_ir_builder_cast_sext(a->ir, ft, tt, v);
|
|
||||||
return spl_ir_builder_cast_zext(a->ir, ft, tt, v);
|
|
||||||
}
|
}
|
||||||
if (fs->kind == SPL_TYPE_INT && ts->kind == SPL_TYPE_FLOAT)
|
return ast2ir_emit_cast_builtin(a, n, in, ft, tt, v);
|
||||||
return spl_ir_builder_case_int2float(a->ir, ft, tt, v);
|
|
||||||
if (fs->kind == SPL_TYPE_FLOAT && ts->kind == SPL_TYPE_INT)
|
|
||||||
return spl_ir_builder_case_float2int(a->ir, ft, tt, v);
|
|
||||||
if (fs->kind == SPL_TYPE_FLOAT && ts->kind == SPL_TYPE_FLOAT) {
|
|
||||||
if (fs->float_type.bits > ts->float_type.bits)
|
|
||||||
return spl_ir_builder_cast_ftrunc(a->ir, ft, tt, v);
|
|
||||||
return spl_ir_builder_cast_fext(a->ir, ft, tt, v);
|
|
||||||
}
|
|
||||||
if (fs->kind == SPL_TYPE_BOOL && ts->kind == SPL_TYPE_INT)
|
|
||||||
return spl_ir_builder_cast_bool2int(a->ir, ft, tt, v);
|
|
||||||
if (fs->kind == SPL_TYPE_PTR && ts->kind == SPL_TYPE_INT)
|
|
||||||
return spl_ir_builder_cast_ptr2int(a->ir, ft, tt, v);
|
|
||||||
if (fs->kind == SPL_TYPE_INT && ts->kind == SPL_TYPE_PTR)
|
|
||||||
return spl_ir_builder_cast_int2ptr(a->ir, ft, tt, v);
|
|
||||||
return spl_ir_builder_cast_bitcast(a->ir, ft, tt, v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
||||||
@@ -630,6 +693,16 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case SPL_OP_BOOL_OR: {
|
||||||
|
spl_ast_node_t *bmln = spl_ast_node(a->sema->ast, n->binary.left);
|
||||||
|
spl_type_id_t op_tid = bmln ? node_ir(a, bmln) : 0;
|
||||||
|
return spl_ir_builder_arith_or(a->ir, op_tid, l, r);
|
||||||
|
}
|
||||||
|
case SPL_OP_BOOL_AND: {
|
||||||
|
spl_ast_node_t *bmln = spl_ast_node(a->sema->ast, n->binary.left);
|
||||||
|
spl_type_id_t op_tid = bmln ? node_ir(a, bmln) : 0;
|
||||||
|
return spl_ir_builder_arith_and(a->ir, op_tid, l, r);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -863,11 +936,10 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
|
|||||||
}
|
}
|
||||||
case SPL_AST_EXPR_IF:
|
case SPL_AST_EXPR_IF:
|
||||||
case SPL_AST_EXPR_IFVAR:
|
case SPL_AST_EXPR_IFVAR:
|
||||||
|
return emit_if_like(a, ref);
|
||||||
case SPL_AST_EXPR_WHILE:
|
case SPL_AST_EXPR_WHILE:
|
||||||
case SPL_AST_EXPR_LOOP: {
|
case SPL_AST_EXPR_LOOP:
|
||||||
emit_stmt(a, ref);
|
return emit_loop_like(a, ref);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case SPL_AST_EXPR_SLICE: {
|
case SPL_AST_EXPR_SLICE: {
|
||||||
spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->slice.obj);
|
spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->slice.obj);
|
||||||
spl_lang_type_id_t obj_lang = node_lang(a, obj);
|
spl_lang_type_id_t obj_lang = node_lang(a, obj);
|
||||||
@@ -888,7 +960,23 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
|
|||||||
spl_lang_type_id_t usize_lang = spl_lang_make_int(a->sema->type, sizeof(void *) * 8, 0);
|
spl_lang_type_id_t usize_lang = spl_lang_make_int(a->sema->type, sizeof(void *) * 8, 0);
|
||||||
spl_type_id_t usize_ir = to_ir_type(a, usize_lang);
|
spl_type_id_t usize_ir = to_ir_type(a, usize_lang);
|
||||||
|
|
||||||
spl_ir_node_ref_t base = emit_lvalue(a, n->slice.obj);
|
/* base = 元素数据首地址 */
|
||||||
|
spl_ir_node_ref_t base = 0;
|
||||||
|
if (obj_kind == SPL_LANG_TYPE_PTR) {
|
||||||
|
/* ptr 值本身就是首元素地址 */
|
||||||
|
base = emit_expr(a, n->slice.obj);
|
||||||
|
} else if (obj_kind == SPL_LANG_TYPE_SLICE) {
|
||||||
|
/* 取 slice 的 ptr 字段 */
|
||||||
|
spl_ir_node_ref_t slice_val = emit_expr(a, n->slice.obj);
|
||||||
|
if (!slice_val)
|
||||||
|
return 0;
|
||||||
|
spl_type_id_t ptr_ir = spl_type_builder_ptr((spl_type_t *)a->sema->type, elem_ir);
|
||||||
|
base = spl_ir_builder_agg_extract(a->ir, obj_ir, ptr_ir, SPL_SLICE_PTR_FIELD_IDX,
|
||||||
|
slice_val);
|
||||||
|
} else {
|
||||||
|
/* ARRAY:&arr 即首元素地址 */
|
||||||
|
base = emit_lvalue(a, n->slice.obj);
|
||||||
|
}
|
||||||
if (!base)
|
if (!base)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -944,6 +1032,257 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static spl_ir_node_ref_t emit_if_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
||||||
|
spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref);
|
||||||
|
if (!n || n->kind != SPL_AST_EXPR_IF)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
spl_type_id_t if_t = node_ir(a, n);
|
||||||
|
spl_type_node_t *if_tn = if_t ? spl_type_node(a->sema->type, if_t) : NULL;
|
||||||
|
/* 只有 when 有非 unit 值时(作为表达式使用),才分配 result_slot */
|
||||||
|
bool need_result = if_tn && if_tn->kind != SPL_TYPE_UNIT;
|
||||||
|
|
||||||
|
spl_ir_node_ref_t result_slot = 0;
|
||||||
|
if (need_result)
|
||||||
|
result_slot = spl_ir_builder_mem_alloca(a->ir, if_t, const_usize(a, 1));
|
||||||
|
|
||||||
|
spl_ir_node_ref_t cond = emit_expr(a, n->if_expr.cond);
|
||||||
|
if (!cond)
|
||||||
|
Panic("if cond emit failed");
|
||||||
|
spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, cond);
|
||||||
|
spl_ir_builder_block_end(a->ir);
|
||||||
|
|
||||||
|
usize then_blk = spl_ir_builder_block_begin(a->ir);
|
||||||
|
spl_ir_node_ref_t then_v = 0;
|
||||||
|
if (n->if_expr.then_block)
|
||||||
|
then_v = emit_expr(a, n->if_expr.then_block);
|
||||||
|
if (result_slot && then_v)
|
||||||
|
spl_ir_builder_mem_store(a->ir, if_t, result_slot, then_v);
|
||||||
|
spl_ir_node_ref_t then_end = 0;
|
||||||
|
if (!a->ir->terminated)
|
||||||
|
then_end = spl_ir_builder_control_jmp(a->ir);
|
||||||
|
spl_ir_builder_block_end(a->ir);
|
||||||
|
|
||||||
|
usize else_blk = spl_ir_builder_block_begin(a->ir);
|
||||||
|
spl_ir_node_ref_t else_v = 0;
|
||||||
|
if (n->if_expr.else_branch)
|
||||||
|
else_v = emit_expr(a, n->if_expr.else_branch);
|
||||||
|
if (result_slot && else_v)
|
||||||
|
spl_ir_builder_mem_store(a->ir, if_t, result_slot, else_v);
|
||||||
|
spl_ir_node_ref_t else_end = 0;
|
||||||
|
if (!a->ir->terminated)
|
||||||
|
else_end = spl_ir_builder_control_jmp(a->ir);
|
||||||
|
spl_ir_builder_block_end(a->ir);
|
||||||
|
|
||||||
|
usize merge_blk = spl_ir_builder_block_begin(a->ir);
|
||||||
|
spl_ir_builder_control_br_fixup(a->ir, br, then_blk, else_blk);
|
||||||
|
if (then_end)
|
||||||
|
spl_ir_builder_control_jmp_fixup(a->ir, then_end, merge_blk);
|
||||||
|
if (else_end)
|
||||||
|
spl_ir_builder_control_jmp_fixup(a->ir, else_end, merge_blk);
|
||||||
|
|
||||||
|
if (!result_slot)
|
||||||
|
return 0;
|
||||||
|
return spl_ir_builder_mem_load(a->ir, if_t, result_slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
static spl_ir_node_ref_t emit_if_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
||||||
|
spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref);
|
||||||
|
if (!n)
|
||||||
|
return 0;
|
||||||
|
bool is_ifvar = (n->kind == SPL_AST_EXPR_IFVAR);
|
||||||
|
|
||||||
|
spl_type_id_t result_t = node_ir(a, n);
|
||||||
|
spl_type_node_t *rtn = result_t ? spl_type_node(a->sema->type, result_t) : NULL;
|
||||||
|
bool need_result = rtn && rtn->kind != SPL_TYPE_UNIT;
|
||||||
|
|
||||||
|
spl_ir_node_ref_t result_slot = 0;
|
||||||
|
if (need_result)
|
||||||
|
result_slot = spl_ir_builder_mem_alloca(a->ir, result_t, const_usize(a, 1));
|
||||||
|
|
||||||
|
spl_ir_node_ref_t cond = 0;
|
||||||
|
spl_ast_node_ref_t then_ref = 0;
|
||||||
|
spl_ast_node_ref_t else_ref = 0;
|
||||||
|
|
||||||
|
if (is_ifvar) {
|
||||||
|
emit_decl(a, n->ifvar_expr.var_decl);
|
||||||
|
spl_ast_node_t *vd = spl_ast_node(a->sema->ast, n->ifvar_expr.var_decl);
|
||||||
|
if (!vd || !vd->var_const_decl.init_expr)
|
||||||
|
Panic("ifvar requires initializer");
|
||||||
|
spl_ir_node_ref_t slot = 0;
|
||||||
|
if (!map_get(a->def2ir_map, vd->resolved_def_id, &slot))
|
||||||
|
Panic("ifvar var slot not found");
|
||||||
|
cond = spl_ir_builder_mem_load(a->ir, node_ir(a, vd), slot);
|
||||||
|
then_ref = n->ifvar_expr.then_block;
|
||||||
|
else_ref = n->ifvar_expr.else_branch;
|
||||||
|
} else {
|
||||||
|
cond = emit_expr(a, n->if_expr.cond);
|
||||||
|
then_ref = n->if_expr.then_block;
|
||||||
|
else_ref = n->if_expr.else_branch;
|
||||||
|
}
|
||||||
|
if (!cond)
|
||||||
|
Panic("if cond emit failed");
|
||||||
|
|
||||||
|
spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, cond);
|
||||||
|
spl_ir_builder_block_end(a->ir);
|
||||||
|
|
||||||
|
usize then_blk = spl_ir_builder_block_begin(a->ir);
|
||||||
|
spl_ir_node_ref_t then_v = 0;
|
||||||
|
if (then_ref)
|
||||||
|
then_v = emit_expr(a, then_ref);
|
||||||
|
if (result_slot && then_v)
|
||||||
|
spl_ir_builder_mem_store(a->ir, result_t, result_slot, then_v);
|
||||||
|
spl_ir_node_ref_t then_end = 0;
|
||||||
|
if (!a->ir->terminated)
|
||||||
|
then_end = spl_ir_builder_control_jmp(a->ir);
|
||||||
|
spl_ir_builder_block_end(a->ir);
|
||||||
|
|
||||||
|
usize else_blk = spl_ir_builder_block_begin(a->ir);
|
||||||
|
spl_ir_node_ref_t else_v = 0;
|
||||||
|
if (else_ref)
|
||||||
|
else_v = emit_expr(a, else_ref);
|
||||||
|
if (result_slot && else_v)
|
||||||
|
spl_ir_builder_mem_store(a->ir, result_t, result_slot, else_v);
|
||||||
|
spl_ir_node_ref_t else_end = 0;
|
||||||
|
if (!a->ir->terminated)
|
||||||
|
else_end = spl_ir_builder_control_jmp(a->ir);
|
||||||
|
spl_ir_builder_block_end(a->ir);
|
||||||
|
|
||||||
|
usize merge_blk = spl_ir_builder_block_begin(a->ir);
|
||||||
|
spl_ir_builder_control_br_fixup(a->ir, br, then_blk, else_blk);
|
||||||
|
if (then_end)
|
||||||
|
spl_ir_builder_control_jmp_fixup(a->ir, then_end, merge_blk);
|
||||||
|
if (else_end)
|
||||||
|
spl_ir_builder_control_jmp_fixup(a->ir, else_end, merge_blk);
|
||||||
|
|
||||||
|
if (!result_slot)
|
||||||
|
return 0;
|
||||||
|
return spl_ir_builder_mem_load(a->ir, result_t, result_slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
static spl_ir_node_ref_t emit_loop_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
||||||
|
spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref);
|
||||||
|
if (!n)
|
||||||
|
return 0;
|
||||||
|
bool is_while = (n->kind == SPL_AST_EXPR_WHILE);
|
||||||
|
|
||||||
|
spl_type_id_t result_t = node_ir(a, n);
|
||||||
|
spl_type_node_t *rtn = result_t ? spl_type_node(a->sema->type, result_t) : NULL;
|
||||||
|
bool need_result = rtn && rtn->kind != SPL_TYPE_UNIT;
|
||||||
|
|
||||||
|
spl_ir_node_ref_t result_slot = 0;
|
||||||
|
if (need_result)
|
||||||
|
result_slot = spl_ir_builder_mem_alloca(a->ir, result_t, const_usize(a, 1));
|
||||||
|
|
||||||
|
spl_ir_node_ref_t pre_jmp = 0;
|
||||||
|
if (!a->ir->terminated)
|
||||||
|
pre_jmp = spl_ir_builder_control_jmp(a->ir);
|
||||||
|
spl_ir_builder_block_end(a->ir);
|
||||||
|
|
||||||
|
/* while 需要独立 head 块(含 cond + br);
|
||||||
|
loop 没有头块,body_blk 同时是入口和回跳目标 */
|
||||||
|
usize head_blk = 0;
|
||||||
|
spl_ir_node_ref_t br = 0;
|
||||||
|
|
||||||
|
if (is_while) {
|
||||||
|
head_blk = spl_ir_builder_block_begin(a->ir);
|
||||||
|
spl_ir_node_ref_t cond = emit_expr(a, n->while_expr.cond);
|
||||||
|
if (!cond)
|
||||||
|
Panic("while cond emit failed");
|
||||||
|
br = spl_ir_builder_control_br(a->ir, cond);
|
||||||
|
spl_ir_builder_block_end(a->ir);
|
||||||
|
}
|
||||||
|
|
||||||
|
usize body_blk = spl_ir_builder_block_begin(a->ir);
|
||||||
|
usize cont_blk = is_while ? head_blk : body_blk;
|
||||||
|
|
||||||
|
spl_loop_ctx_t ctx = {0};
|
||||||
|
ctx.cont_blk = cont_blk;
|
||||||
|
ctx.brk_blk = 0;
|
||||||
|
ctx.label = NULL;
|
||||||
|
ctx.result_slot = result_slot;
|
||||||
|
ctx.result_tid = result_t;
|
||||||
|
|
||||||
|
spl_ast_node_ref_t label_ref = is_while ? n->while_expr.label : n->loop_expr.label;
|
||||||
|
if (label_ref) {
|
||||||
|
spl_ast_node_t *ln = spl_ast_node(a->sema->ast, label_ref);
|
||||||
|
if (ln && ln->kind == SPL_AST_LABEL)
|
||||||
|
ctx.label = ln->label.name;
|
||||||
|
}
|
||||||
|
vec_init(ctx.breaks);
|
||||||
|
vec_push(a->loop_stack, ctx);
|
||||||
|
|
||||||
|
spl_ast_node_ref_t body_ref = is_while ? n->while_expr.body : n->loop_expr.body;
|
||||||
|
if (body_ref)
|
||||||
|
emit_expr(a, body_ref);
|
||||||
|
|
||||||
|
spl_ir_node_ref_t body_end = 0;
|
||||||
|
if (!a->ir->terminated)
|
||||||
|
body_end = spl_ir_builder_control_jmp(a->ir);
|
||||||
|
spl_ir_builder_block_end(a->ir);
|
||||||
|
|
||||||
|
usize after_blk = spl_ir_builder_block_begin(a->ir);
|
||||||
|
spl_ir_node_ref_t else_v = 0;
|
||||||
|
if (is_while && n->while_expr.else_branch)
|
||||||
|
else_v = emit_expr(a, n->while_expr.else_branch);
|
||||||
|
if (result_slot && else_v)
|
||||||
|
spl_ir_builder_mem_store(a->ir, result_t, result_slot, else_v);
|
||||||
|
|
||||||
|
if (pre_jmp)
|
||||||
|
spl_ir_builder_control_jmp_fixup(a->ir, pre_jmp, cont_blk);
|
||||||
|
if (br)
|
||||||
|
spl_ir_builder_control_br_fixup(a->ir, br, body_blk, after_blk);
|
||||||
|
if (body_end)
|
||||||
|
spl_ir_builder_control_jmp_fixup(a->ir, body_end, cont_blk);
|
||||||
|
|
||||||
|
spl_loop_ctx_t *top = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1);
|
||||||
|
for (usize i = 0; i < vec_size(top->breaks); ++i)
|
||||||
|
spl_ir_builder_control_jmp_fixup(a->ir, vec_at(top->breaks, i), after_blk);
|
||||||
|
vec_free(top->breaks);
|
||||||
|
vec_pop(a->loop_stack);
|
||||||
|
|
||||||
|
if (!result_slot)
|
||||||
|
return 0;
|
||||||
|
return spl_ir_builder_mem_load(a->ir, result_t, result_slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emit_break_stmt(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
||||||
|
if (vec_size(a->loop_stack) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const char *lbl = NULL;
|
||||||
|
if (n->statement_break.label) {
|
||||||
|
spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->statement_break.label);
|
||||||
|
if (ln && ln->kind == SPL_AST_LABEL)
|
||||||
|
lbl = ln->label.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
spl_loop_ctx_t *target = NULL;
|
||||||
|
if (lbl) {
|
||||||
|
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
|
||||||
|
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
|
||||||
|
if (c->label && strcmp(c->label, lbl) == 0) {
|
||||||
|
target = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1);
|
||||||
|
}
|
||||||
|
if (!target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* 有值 loop:先把 break 值写入 result_slot 再跳转 */
|
||||||
|
if (n->statement_break.expr && target->result_slot) {
|
||||||
|
spl_ir_node_ref_t bv = emit_expr(a, n->statement_break.expr);
|
||||||
|
if (bv)
|
||||||
|
spl_ir_builder_mem_store(a->ir, target->result_tid, target->result_slot, bv);
|
||||||
|
}
|
||||||
|
|
||||||
|
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
|
||||||
|
vec_push(target->breaks, jmp);
|
||||||
|
}
|
||||||
|
|
||||||
static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
||||||
spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref);
|
spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref);
|
||||||
if (!n)
|
if (!n)
|
||||||
@@ -983,205 +1322,19 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
|||||||
if (n->statement_expr.expr)
|
if (n->statement_expr.expr)
|
||||||
emit_expr(a, n->statement_expr.expr);
|
emit_expr(a, n->statement_expr.expr);
|
||||||
return;
|
return;
|
||||||
case SPL_AST_EXPR_IF: {
|
case SPL_AST_EXPR_IF:
|
||||||
spl_type_id_t if_t = node_ir(a, n);
|
|
||||||
spl_ir_node_ref_t result_slot = 0;
|
|
||||||
if (if_t)
|
|
||||||
result_slot = spl_ir_builder_mem_alloca(a->ir, if_t, const_usize(a, 1));
|
|
||||||
|
|
||||||
spl_ir_node_ref_t cond = emit_expr(a, n->if_expr.cond);
|
|
||||||
if (!cond)
|
|
||||||
Panic("if cond emit failed");
|
|
||||||
spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, cond);
|
|
||||||
spl_ir_builder_block_end(a->ir);
|
|
||||||
|
|
||||||
usize then_blk = spl_ir_builder_block_begin(a->ir);
|
|
||||||
spl_ir_node_ref_t then_v = 0;
|
|
||||||
if (n->if_expr.then_block)
|
|
||||||
then_v = emit_expr(a, n->if_expr.then_block);
|
|
||||||
if (result_slot && then_v)
|
|
||||||
spl_ir_builder_mem_store(a->ir, if_t, result_slot, then_v);
|
|
||||||
spl_ir_node_ref_t then_end = 0;
|
|
||||||
if (!a->ir->terminated)
|
|
||||||
then_end = spl_ir_builder_control_jmp(a->ir);
|
|
||||||
spl_ir_builder_block_end(a->ir);
|
|
||||||
|
|
||||||
usize else_blk = spl_ir_builder_block_begin(a->ir);
|
|
||||||
spl_ir_node_ref_t else_v = 0;
|
|
||||||
if (n->if_expr.else_branch)
|
|
||||||
else_v = emit_expr(a, n->if_expr.else_branch);
|
|
||||||
if (result_slot && else_v)
|
|
||||||
spl_ir_builder_mem_store(a->ir, if_t, result_slot, else_v);
|
|
||||||
spl_ir_node_ref_t else_end = 0;
|
|
||||||
if (!a->ir->terminated)
|
|
||||||
else_end = spl_ir_builder_control_jmp(a->ir);
|
|
||||||
spl_ir_builder_block_end(a->ir);
|
|
||||||
|
|
||||||
usize merge_blk = spl_ir_builder_block_begin(a->ir);
|
|
||||||
spl_ir_builder_control_br_fixup(a->ir, br, then_blk, else_blk);
|
|
||||||
if (then_end)
|
|
||||||
spl_ir_builder_control_jmp_fixup(a->ir, then_end, merge_blk);
|
|
||||||
if (else_end)
|
|
||||||
spl_ir_builder_control_jmp_fixup(a->ir, else_end, merge_blk);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case SPL_AST_EXPR_IFVAR: {
|
case SPL_AST_EXPR_IFVAR: {
|
||||||
emit_decl(a, n->ifvar_expr.var_decl);
|
(void)emit_if_like(a, ref);
|
||||||
spl_ast_node_t *vd = spl_ast_node(a->sema->ast, n->ifvar_expr.var_decl);
|
|
||||||
if (!vd || !vd->var_const_decl.init_expr)
|
|
||||||
Panic("ifvar requires initializer");
|
|
||||||
|
|
||||||
spl_ir_node_ref_t slot = 0;
|
|
||||||
if (!map_get(a->def2ir_map, vd->resolved_def_id, &slot))
|
|
||||||
Panic("ifvar var slot not found");
|
|
||||||
spl_ir_node_ref_t cond = spl_ir_builder_mem_load(a->ir, node_ir(a, vd), slot);
|
|
||||||
|
|
||||||
spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, cond);
|
|
||||||
spl_ir_builder_block_end(a->ir);
|
|
||||||
|
|
||||||
usize then_blk = spl_ir_builder_block_begin(a->ir);
|
|
||||||
if (n->ifvar_expr.then_block)
|
|
||||||
emit_expr(a, n->ifvar_expr.then_block);
|
|
||||||
spl_ir_node_ref_t then_end = 0;
|
|
||||||
if (!a->ir->terminated)
|
|
||||||
then_end = spl_ir_builder_control_jmp(a->ir);
|
|
||||||
spl_ir_builder_block_end(a->ir);
|
|
||||||
|
|
||||||
usize else_blk = spl_ir_builder_block_begin(a->ir);
|
|
||||||
if (n->ifvar_expr.else_branch)
|
|
||||||
emit_expr(a, n->ifvar_expr.else_branch);
|
|
||||||
spl_ir_node_ref_t else_end = 0;
|
|
||||||
if (!a->ir->terminated)
|
|
||||||
else_end = spl_ir_builder_control_jmp(a->ir);
|
|
||||||
spl_ir_builder_block_end(a->ir);
|
|
||||||
|
|
||||||
usize merge_blk = spl_ir_builder_block_begin(a->ir);
|
|
||||||
spl_ir_builder_control_br_fixup(a->ir, br, then_blk, else_blk);
|
|
||||||
if (then_end)
|
|
||||||
spl_ir_builder_control_jmp_fixup(a->ir, then_end, merge_blk);
|
|
||||||
if (else_end)
|
|
||||||
spl_ir_builder_control_jmp_fixup(a->ir, else_end, merge_blk);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case SPL_AST_EXPR_WHILE: {
|
|
||||||
spl_ir_node_ref_t pre_jmp = 0;
|
|
||||||
if (!a->ir->terminated)
|
|
||||||
pre_jmp = spl_ir_builder_control_jmp(a->ir);
|
|
||||||
spl_ir_builder_block_end(a->ir);
|
|
||||||
|
|
||||||
usize head_blk = spl_ir_builder_block_begin(a->ir);
|
|
||||||
spl_ir_node_ref_t cond = emit_expr(a, n->while_expr.cond);
|
|
||||||
if (!cond)
|
|
||||||
Panic("while cond emit failed");
|
|
||||||
spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, cond);
|
|
||||||
spl_ir_builder_block_end(a->ir);
|
|
||||||
|
|
||||||
usize body_blk = spl_ir_builder_block_begin(a->ir);
|
|
||||||
|
|
||||||
spl_loop_ctx_t ctx = {0};
|
|
||||||
ctx.cont_blk = head_blk;
|
|
||||||
ctx.brk_blk = 0;
|
|
||||||
ctx.label = NULL;
|
|
||||||
if (n->while_expr.label) {
|
|
||||||
spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->while_expr.label);
|
|
||||||
if (ln && ln->kind == SPL_AST_LABEL)
|
|
||||||
ctx.label = ln->label.name;
|
|
||||||
}
|
|
||||||
vec_init(ctx.breaks);
|
|
||||||
vec_push(a->loop_stack, ctx);
|
|
||||||
|
|
||||||
if (n->while_expr.body)
|
|
||||||
emit_expr(a, n->while_expr.body);
|
|
||||||
spl_ir_node_ref_t body_end = 0;
|
|
||||||
if (!a->ir->terminated)
|
|
||||||
body_end = spl_ir_builder_control_jmp(a->ir);
|
|
||||||
spl_ir_builder_block_end(a->ir);
|
|
||||||
|
|
||||||
usize after_blk = spl_ir_builder_block_begin(a->ir);
|
|
||||||
if (n->while_expr.else_branch)
|
|
||||||
emit_expr(a, n->while_expr.else_branch);
|
|
||||||
|
|
||||||
if (pre_jmp)
|
|
||||||
spl_ir_builder_control_jmp_fixup(a->ir, pre_jmp, head_blk);
|
|
||||||
spl_ir_builder_control_br_fixup(a->ir, br, body_blk, after_blk);
|
|
||||||
if (body_end)
|
|
||||||
spl_ir_builder_control_jmp_fixup(a->ir, body_end, head_blk);
|
|
||||||
|
|
||||||
spl_loop_ctx_t *top = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1);
|
|
||||||
for (usize i = 0; i < vec_size(top->breaks); ++i)
|
|
||||||
spl_ir_builder_control_jmp_fixup(a->ir, vec_at(top->breaks, i), after_blk);
|
|
||||||
vec_free(top->breaks);
|
|
||||||
vec_pop(a->loop_stack);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case SPL_AST_EXPR_WHILE:
|
||||||
case SPL_AST_EXPR_LOOP: {
|
case SPL_AST_EXPR_LOOP: {
|
||||||
spl_ir_node_ref_t pre_jmp = 0;
|
(void)emit_loop_like(a, ref);
|
||||||
if (!a->ir->terminated)
|
|
||||||
pre_jmp = spl_ir_builder_control_jmp(a->ir);
|
|
||||||
spl_ir_builder_block_end(a->ir);
|
|
||||||
|
|
||||||
usize head_blk = spl_ir_builder_block_begin(a->ir);
|
|
||||||
|
|
||||||
spl_loop_ctx_t ctx = {0};
|
|
||||||
ctx.cont_blk = head_blk;
|
|
||||||
ctx.brk_blk = 0;
|
|
||||||
ctx.label = NULL;
|
|
||||||
if (n->loop_expr.label) {
|
|
||||||
spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->loop_expr.label);
|
|
||||||
if (ln && ln->kind == SPL_AST_LABEL)
|
|
||||||
ctx.label = ln->label.name;
|
|
||||||
}
|
|
||||||
vec_init(ctx.breaks);
|
|
||||||
vec_push(a->loop_stack, ctx);
|
|
||||||
|
|
||||||
if (n->loop_expr.body)
|
|
||||||
emit_expr(a, n->loop_expr.body);
|
|
||||||
spl_ir_node_ref_t body_end = 0;
|
|
||||||
if (!a->ir->terminated)
|
|
||||||
body_end = spl_ir_builder_control_jmp(a->ir);
|
|
||||||
spl_ir_builder_block_end(a->ir);
|
|
||||||
|
|
||||||
usize after_blk = spl_ir_builder_block_begin(a->ir);
|
|
||||||
|
|
||||||
if (pre_jmp)
|
|
||||||
spl_ir_builder_control_jmp_fixup(a->ir, pre_jmp, head_blk);
|
|
||||||
if (body_end)
|
|
||||||
spl_ir_builder_control_jmp_fixup(a->ir, body_end, head_blk);
|
|
||||||
|
|
||||||
spl_loop_ctx_t *top = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1);
|
|
||||||
for (usize i = 0; i < vec_size(top->breaks); ++i)
|
|
||||||
spl_ir_builder_control_jmp_fixup(a->ir, vec_at(top->breaks, i), after_blk);
|
|
||||||
vec_free(top->breaks);
|
|
||||||
vec_pop(a->loop_stack);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case SPL_AST_STATEMENT_BREAK: {
|
case SPL_AST_STATEMENT_BREAK:
|
||||||
if (vec_size(a->loop_stack) == 0)
|
emit_break_stmt(a, n);
|
||||||
return;
|
|
||||||
|
|
||||||
const char *lbl = NULL;
|
|
||||||
if (n->statement_break.label) {
|
|
||||||
spl_ast_node_t *ln = spl_ast_node(a->sema->ast, n->statement_break.label);
|
|
||||||
if (ln && ln->kind == SPL_AST_LABEL)
|
|
||||||
lbl = ln->label.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
|
|
||||||
|
|
||||||
if (lbl) {
|
|
||||||
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
|
|
||||||
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
|
|
||||||
if (c->label && strcmp(c->label, lbl) == 0) {
|
|
||||||
vec_push(c->breaks, jmp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec_push(vec_at(a->loop_stack, vec_size(a->loop_stack) - 1).breaks, jmp);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
case SPL_AST_STATEMENT_CONTINUE: {
|
case SPL_AST_STATEMENT_CONTINUE: {
|
||||||
if (vec_size(a->loop_stack) == 0)
|
if (vec_size(a->loop_stack) == 0)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ typedef struct {
|
|||||||
usize brk_blk;
|
usize brk_blk;
|
||||||
const char *label;
|
const char *label;
|
||||||
spl_ir_node_ref_vec_t breaks;
|
spl_ir_node_ref_vec_t breaks;
|
||||||
|
spl_ir_node_ref_t result_slot;
|
||||||
|
spl_type_id_t result_tid;
|
||||||
} spl_loop_ctx_t;
|
} spl_loop_ctx_t;
|
||||||
typedef VEC(spl_loop_ctx_t) spl_loop_ctx_vec_t;
|
typedef VEC(spl_loop_ctx_t) spl_loop_ctx_vec_t;
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,26 @@ static const spl_intrin_info_t g_intrin_table[] = {
|
|||||||
SPL_INTRIN_RESULT_UNIT},
|
SPL_INTRIN_RESULT_UNIT},
|
||||||
[SPL_INTRIN_LEN] = {"len", SPL_INTRIN_LEN, SPL_INTRIN_FORM_FIELD, 0, 0,
|
[SPL_INTRIN_LEN] = {"len", SPL_INTRIN_LEN, SPL_INTRIN_FORM_FIELD, 0, 0,
|
||||||
SPL_INTRIN_RESULT_USIZE},
|
SPL_INTRIN_RESULT_USIZE},
|
||||||
|
[SPL_INTRIN_INT_CAST] = {"@int_cast", SPL_INTRIN_INT_CAST, SPL_INTRIN_FORM_CALL, 2, 2,
|
||||||
|
SPL_INTRIN_RESULT_UNIT},
|
||||||
|
[SPL_INTRIN_TRUNCATE] = {"@truncate", SPL_INTRIN_TRUNCATE, SPL_INTRIN_FORM_CALL, 2, 2,
|
||||||
|
SPL_INTRIN_RESULT_UNIT},
|
||||||
|
[SPL_INTRIN_BIT_CAST] = {"@bit_cast", SPL_INTRIN_BIT_CAST, SPL_INTRIN_FORM_CALL, 2, 2,
|
||||||
|
SPL_INTRIN_RESULT_UNIT},
|
||||||
|
[SPL_INTRIN_FLOAT_CAST] = {"@float_cast", SPL_INTRIN_FLOAT_CAST, SPL_INTRIN_FORM_CALL, 2, 2,
|
||||||
|
SPL_INTRIN_RESULT_UNIT},
|
||||||
|
[SPL_INTRIN_INT_FROM_FLOAT] = {"@int_from_float", SPL_INTRIN_INT_FROM_FLOAT,
|
||||||
|
SPL_INTRIN_FORM_CALL, 2, 2, SPL_INTRIN_RESULT_UNIT},
|
||||||
|
[SPL_INTRIN_FLOAT_FROM_INT] = {"@float_from_int", SPL_INTRIN_FLOAT_FROM_INT,
|
||||||
|
SPL_INTRIN_FORM_CALL, 2, 2, SPL_INTRIN_RESULT_UNIT},
|
||||||
|
[SPL_INTRIN_INT_FROM_BOOL] = {"@int_from_bool", SPL_INTRIN_INT_FROM_BOOL, SPL_INTRIN_FORM_CALL,
|
||||||
|
1, 2, SPL_INTRIN_RESULT_UNIT},
|
||||||
|
[SPL_INTRIN_INT_FROM_PTR] = {"@int_from_ptr", SPL_INTRIN_INT_FROM_PTR, SPL_INTRIN_FORM_CALL, 1,
|
||||||
|
2, SPL_INTRIN_RESULT_UNIT},
|
||||||
|
[SPL_INTRIN_PTR_FROM_INT] = {"@ptr_from_int", SPL_INTRIN_PTR_FROM_INT, SPL_INTRIN_FORM_CALL, 2,
|
||||||
|
2, SPL_INTRIN_RESULT_UNIT},
|
||||||
|
[SPL_INTRIN_PTR_CAST] = {"@ptr_cast", SPL_INTRIN_PTR_CAST, SPL_INTRIN_FORM_CALL, 2, 2,
|
||||||
|
SPL_INTRIN_RESULT_UNIT},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const usize g_intrin_count = sizeof(g_intrin_table) / sizeof(g_intrin_table[0]);
|
static const usize g_intrin_count = sizeof(g_intrin_table) / sizeof(g_intrin_table[0]);
|
||||||
@@ -46,3 +66,34 @@ spl_intrin_t spl_intrin_lookup_field(spl_lang_type_kind_t recv_kind, const char
|
|||||||
}
|
}
|
||||||
return SPL_INTRIN_NONE;
|
return SPL_INTRIN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spl_intrin_t spl_intrin_lookup_cast(spl_type_t *type, spl_type_id_t ft, spl_type_id_t tt) {
|
||||||
|
/* 这是 `as` 的展开规则表。要调整 as 的语义,改这里。 */
|
||||||
|
spl_type_node_t *f = spl_type_node(type, ft);
|
||||||
|
spl_type_node_t *t = spl_type_node(type, tt);
|
||||||
|
if (!f || !t)
|
||||||
|
return SPL_INTRIN_NONE;
|
||||||
|
|
||||||
|
if (f->kind == SPL_TYPE_INT && t->kind == SPL_TYPE_INT) {
|
||||||
|
usize fb = f->int_type.bits;
|
||||||
|
usize tb = t->int_type.bits;
|
||||||
|
if (fb == tb)
|
||||||
|
return SPL_INTRIN_BIT_CAST;
|
||||||
|
if (fb > tb)
|
||||||
|
return SPL_INTRIN_TRUNCATE;
|
||||||
|
return SPL_INTRIN_INT_CAST;
|
||||||
|
}
|
||||||
|
if (f->kind == SPL_TYPE_FLOAT && t->kind == SPL_TYPE_FLOAT)
|
||||||
|
return SPL_INTRIN_FLOAT_CAST;
|
||||||
|
if (f->kind == SPL_TYPE_BOOL && t->kind == SPL_TYPE_INT)
|
||||||
|
return SPL_INTRIN_INT_FROM_BOOL;
|
||||||
|
if (f->kind == SPL_TYPE_PTR && t->kind == SPL_TYPE_INT)
|
||||||
|
return SPL_INTRIN_INT_FROM_PTR;
|
||||||
|
if (f->kind == SPL_TYPE_INT && t->kind == SPL_TYPE_PTR)
|
||||||
|
return SPL_INTRIN_PTR_FROM_INT;
|
||||||
|
if (f->kind == SPL_TYPE_PTR && t->kind == SPL_TYPE_PTR)
|
||||||
|
return SPL_INTRIN_PTR_CAST;
|
||||||
|
|
||||||
|
/* int float 刻意不在这里:只能通过显式 builtin 调用。 */
|
||||||
|
return SPL_INTRIN_NONE;
|
||||||
|
}
|
||||||
+11
-4
@@ -11,6 +11,16 @@ typedef enum {
|
|||||||
SPL_INTRIN_ASSERT,
|
SPL_INTRIN_ASSERT,
|
||||||
SPL_INTRIN_BREAKPOINT,
|
SPL_INTRIN_BREAKPOINT,
|
||||||
SPL_INTRIN_LEN,
|
SPL_INTRIN_LEN,
|
||||||
|
SPL_INTRIN_INT_CAST,
|
||||||
|
SPL_INTRIN_TRUNCATE,
|
||||||
|
SPL_INTRIN_BIT_CAST,
|
||||||
|
SPL_INTRIN_FLOAT_CAST,
|
||||||
|
SPL_INTRIN_INT_FROM_FLOAT,
|
||||||
|
SPL_INTRIN_FLOAT_FROM_INT,
|
||||||
|
SPL_INTRIN_INT_FROM_BOOL,
|
||||||
|
SPL_INTRIN_INT_FROM_PTR,
|
||||||
|
SPL_INTRIN_PTR_FROM_INT,
|
||||||
|
SPL_INTRIN_PTR_CAST,
|
||||||
} spl_intrin_t;
|
} spl_intrin_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -33,13 +43,10 @@ typedef struct {
|
|||||||
spl_intrin_result_t result;
|
spl_intrin_result_t result;
|
||||||
} spl_intrin_info_t;
|
} spl_intrin_info_t;
|
||||||
|
|
||||||
/* 统一入口:名字 → 枚举。name 允许带或不带 '@'。 */
|
|
||||||
spl_intrin_t spl_intrin_lookup_call(const char *name);
|
spl_intrin_t spl_intrin_lookup_call(const char *name);
|
||||||
|
|
||||||
/* 统一入口:字段形态,按接收者类型分派。 */
|
|
||||||
spl_intrin_t spl_intrin_lookup_field(spl_lang_type_kind_t recv_kind, const char *field);
|
spl_intrin_t spl_intrin_lookup_field(spl_lang_type_kind_t recv_kind, const char *field);
|
||||||
|
spl_intrin_t spl_intrin_lookup_cast(spl_type_t *type, spl_type_id_t ft, spl_type_id_t tt);
|
||||||
|
|
||||||
/* 从枚举取得元数据,SEMA/AST2IR 都从这里读。 */
|
|
||||||
const spl_intrin_info_t *spl_intrin_info(spl_intrin_t kind);
|
const spl_intrin_info_t *spl_intrin_info(spl_intrin_t kind);
|
||||||
|
|
||||||
/* ---- 与 IR 侧共享的类型布局约定 ---- */
|
/* ---- 与 IR 侧共享的类型布局约定 ---- */
|
||||||
|
|||||||
+47
-8
@@ -193,7 +193,7 @@ static spl_type_id_t ir_result_tid(spl_ir2vm_t *ctx, const spl_ir_node_t *n) {
|
|||||||
case SPL_IR_CASE_FLOAT2INT:
|
case SPL_IR_CASE_FLOAT2INT:
|
||||||
return n->cast.to_tid;
|
return n->cast.to_tid;
|
||||||
case SPL_IR_MEM_ALLOCA:
|
case SPL_IR_MEM_ALLOCA:
|
||||||
return n->mem_alloc.tid;
|
return spl_type_builder_ptr((spl_type_t *)ctx->type, n->mem_alloc.tid);
|
||||||
case SPL_IR_MEM_GLOBAL_ALLOC:
|
case SPL_IR_MEM_GLOBAL_ALLOC:
|
||||||
return n->mem_global_alloc.tid;
|
return n->mem_global_alloc.tid;
|
||||||
case SPL_IR_MEM_LOAD:
|
case SPL_IR_MEM_LOAD:
|
||||||
@@ -306,7 +306,10 @@ static void frame_build(frame_layout_t *fl, spl_ir2vm_t *ctx, spl_ir_func_ref_t
|
|||||||
|
|
||||||
spl_type_node_t *ftn = spl_type_node(ctx->type, f->fn_tid);
|
spl_type_node_t *ftn = spl_type_node(ctx->type, f->fn_tid);
|
||||||
usize nargs = (ftn && ftn->kind == SPL_TYPE_FN) ? vec_size(ftn->fn_type.params) : 0;
|
usize nargs = (ftn && ftn->kind == SPL_TYPE_FN) ? vec_size(ftn->fn_type.params) : 0;
|
||||||
fl->args_bytes = nargs * sizeof(spl_vm_val_t);
|
spl_type_id_t ret_t = (ftn && ftn->kind == SPL_TYPE_FN) ? ftn->fn_type.ret : 0;
|
||||||
|
/* 聚合返回时 fp+0 是 caller 传入的 sret 指针,占用一个隐藏参数槽 */
|
||||||
|
usize hidden_sret = ir_is_aggregate(ctx, ret_t) ? 1 : 0;
|
||||||
|
fl->args_bytes = (nargs + hidden_sret) * sizeof(spl_vm_val_t);
|
||||||
|
|
||||||
usize off = fl->args_bytes;
|
usize off = fl->args_bytes;
|
||||||
|
|
||||||
@@ -743,14 +746,35 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
|
|||||||
if (idx_node->kind == SPL_IR_TYPE_CONST)
|
if (idx_node->kind == SPL_IR_TYPE_CONST)
|
||||||
idx = (usize)idx_node->type_const.int_lit;
|
idx = (usize)idx_node->type_const.int_lit;
|
||||||
}
|
}
|
||||||
CG_LADDR(cg, idx * sizeof(spl_vm_val_t));
|
/* 聚合返回时 fp+0 是 sret 指针,实参从 fp+8 起 */
|
||||||
|
spl_type_node_t *ftn = spl_type_node(ctx->type, cg->irf->fn_tid);
|
||||||
|
spl_type_id_t cur_ret = (ftn && ftn->kind == SPL_TYPE_FN) ? ftn->fn_type.ret : 0;
|
||||||
|
usize shift = ir_is_aggregate(ctx, cur_ret) ? 1 : 0;
|
||||||
|
CG_LADDR(cg, (idx + shift) * sizeof(spl_vm_val_t));
|
||||||
CG_LOAD(cg, k);
|
CG_LOAD(cg, k);
|
||||||
cg_store_slot(cg, ref, k);
|
cg_store_slot(cg, ref, k);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SPL_IR_CONTROL_RET: {
|
case SPL_IR_CONTROL_RET: {
|
||||||
uint8_t k = vm_kind_of(ctx, n->control_ret.tid);
|
spl_type_id_t ret_tid = n->control_ret.tid;
|
||||||
|
if (ir_is_aggregate(ctx, ret_tid)) {
|
||||||
|
/* sret:把返回值写入 *(fp+0),然后以 void 返回 */
|
||||||
|
if (n->control_ret.val) {
|
||||||
|
usize sz = ir_type_size(ctx, ret_tid);
|
||||||
|
CG_LADDR(cg, 0);
|
||||||
|
CG_LOAD(cg, SPL_PTR);
|
||||||
|
cg_load_slot(cg, n->control_ret.val, SPL_PTR);
|
||||||
|
CG_PUSH(cg, SPL_U64, sz);
|
||||||
|
int nat = get_or_add_native(ctx, "vm_memcpy");
|
||||||
|
CG_PUSH(cg, SPL_U64, (spl_vm_val_t)nat);
|
||||||
|
emit(cg, SPL_NCALL, SPL_VOID, 3);
|
||||||
|
emit(cg, SPL_DROP, SPL_VOID, 0);
|
||||||
|
}
|
||||||
|
emit(cg, SPL_RET, SPL_VOID, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uint8_t k = vm_kind_of(ctx, ret_tid);
|
||||||
if (k != SPL_VOID && n->control_ret.val)
|
if (k != SPL_VOID && n->control_ret.val)
|
||||||
cg_load_slot(cg, n->control_ret.val, k);
|
cg_load_slot(cg, n->control_ret.val, k);
|
||||||
emit(cg, SPL_RET, k, 0);
|
emit(cg, SPL_RET, k, 0);
|
||||||
@@ -807,6 +831,14 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
|
|||||||
else
|
else
|
||||||
cg_store_slot(cg, ref, rk);
|
cg_store_slot(cg, ref, rk);
|
||||||
} else {
|
} 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;
|
||||||
|
|
||||||
|
if (ret_is_sret) {
|
||||||
|
sret_off = vec_at(cg->frame.slots, ref).data_off;
|
||||||
|
CG_LADDR(cg, sret_off);
|
||||||
|
}
|
||||||
for (usize i = 0; i < nargs; ++i) {
|
for (usize i = 0; i < nargs; ++i) {
|
||||||
spl_ir_node_ref_t pref = vec_at(n->control_call.params, i);
|
spl_ir_node_ref_t pref = vec_at(n->control_call.params, i);
|
||||||
const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref);
|
const spl_ir_node_t *pn = &vec_at(cg->irf->nodes, pref);
|
||||||
@@ -815,11 +847,18 @@ static void cg_control(cgen_t *cg, usize ref, const spl_ir_node_t *n) {
|
|||||||
cg_load_slot(cg, pref, pk);
|
cg_load_slot(cg, pref, pk);
|
||||||
}
|
}
|
||||||
cg_load_slot(cg, fref, SPL_PTR);
|
cg_load_slot(cg, fref, SPL_PTR);
|
||||||
emit(cg, SPL_CALL, SPL_VOID, (spl_vm_val_t)nargs);
|
spl_vm_val_t actual_nargs = nargs + (ret_is_sret ? 1 : 0);
|
||||||
|
emit(cg, SPL_CALL, SPL_VOID, actual_nargs);
|
||||||
|
|
||||||
uint8_t rk = vm_kind_of(ctx, n->control_call.tid);
|
if (ret_is_sret) {
|
||||||
if (rk != SPL_VOID)
|
/* 结果槽保存 sret 指针,后续 agg_extract 把它当聚合首地址 */
|
||||||
cg_store_slot(cg, ref, rk);
|
CG_LADDR(cg, sret_off);
|
||||||
|
cg_store_slot(cg, ref, SPL_PTR);
|
||||||
|
} else {
|
||||||
|
uint8_t rk = vm_kind_of(ctx, ret_t);
|
||||||
|
if (rk != SPL_VOID)
|
||||||
|
cg_store_slot(cg, ref, rk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+118
-32
@@ -260,7 +260,12 @@ static inline void sema_push_scope(spl_sema_t *sema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void sema_pop_scope(spl_sema_t *sema) {
|
static inline void sema_pop_scope(spl_sema_t *sema) {
|
||||||
sema->scope->current_scope = sema->store_scope;
|
spl_scope_id_t cur = sema->scope->current_scope;
|
||||||
|
if (cur != 0 && cur < vec_size(sema->scope->scopes)) {
|
||||||
|
sema->scope->current_scope = vec_at(sema->scope->scopes, cur).parent;
|
||||||
|
} else {
|
||||||
|
sema->scope->current_scope = sema->store_scope;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static spl_lang_type_id_t sema_for_elem_type(spl_sema_t *sema, spl_lang_type_id_t lang_tid) {
|
static spl_lang_type_id_t sema_for_elem_type(spl_sema_t *sema, spl_lang_type_id_t lang_tid) {
|
||||||
@@ -576,7 +581,7 @@ static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n,
|
|||||||
switch (in) {
|
switch (in) {
|
||||||
case SPL_INTRIN_SIZEOF:
|
case SPL_INTRIN_SIZEOF:
|
||||||
case SPL_INTRIN_ALIGNOF: {
|
case SPL_INTRIN_ALIGNOF: {
|
||||||
sema_infer(sema, vec_at(*args, 0)); /* 求类型表达式的值 */
|
sema_infer(sema, vec_at(*args, 0));
|
||||||
return spl_lang_make_int(sema->type, sizeof(void *) * 8, 0);
|
return spl_lang_make_int(sema->type, sizeof(void *) * 8, 0);
|
||||||
}
|
}
|
||||||
case SPL_INTRIN_ASSERT: {
|
case SPL_INTRIN_ASSERT: {
|
||||||
@@ -586,6 +591,48 @@ static spl_lang_type_id_t sema_intrin_call(spl_sema_t *sema, spl_ast_node_t *n,
|
|||||||
sema_infer(sema, vec_at(*args, 1));
|
sema_infer(sema, vec_at(*args, 1));
|
||||||
return spl_lang_make_unit(sema->type);
|
return spl_lang_make_unit(sema->type);
|
||||||
}
|
}
|
||||||
|
case SPL_INTRIN_INT_CAST:
|
||||||
|
case SPL_INTRIN_TRUNCATE:
|
||||||
|
case SPL_INTRIN_BIT_CAST:
|
||||||
|
case SPL_INTRIN_FLOAT_CAST:
|
||||||
|
case SPL_INTRIN_INT_FROM_FLOAT:
|
||||||
|
case SPL_INTRIN_FLOAT_FROM_INT:
|
||||||
|
case SPL_INTRIN_PTR_FROM_INT:
|
||||||
|
case SPL_INTRIN_PTR_CAST: {
|
||||||
|
/* 双参数形式:源表达式 + 目标类型 */
|
||||||
|
spl_lang_type_id_t src_lang = sema_infer(sema, vec_at(*args, 0));
|
||||||
|
if (!src_lang)
|
||||||
|
return 0;
|
||||||
|
spl_lang_type_id_t dst_lang = sema_infer(sema, vec_at(*args, 1));
|
||||||
|
if (!dst_lang)
|
||||||
|
return 0;
|
||||||
|
spl_type_id_t ft = spl_lang_type_get_ir_type(sema->type, src_lang);
|
||||||
|
spl_type_id_t tt = spl_lang_type_get_ir_type(sema->type, dst_lang);
|
||||||
|
spl_intrin_t expected = spl_intrin_lookup_cast(sema->type, ft, tt);
|
||||||
|
if (expected == SPL_INTRIN_NONE) {
|
||||||
|
SPL_ERROR(&n->dbg, "`%s`: incompatible types", info->name);
|
||||||
|
sema->error_count++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* 允许显式 builtin 覆盖 as 的默认选择(例如用 @int_cast 代替 @truncate) */
|
||||||
|
n->resolved_lang_tid = dst_lang;
|
||||||
|
return dst_lang;
|
||||||
|
}
|
||||||
|
case SPL_INTRIN_INT_FROM_BOOL:
|
||||||
|
case SPL_INTRIN_INT_FROM_PTR: {
|
||||||
|
/* 单参数:目标类型默认 usize;双参数时以第二参数为准 */
|
||||||
|
sema_infer(sema, vec_at(*args, 0));
|
||||||
|
if (nargs >= 2) {
|
||||||
|
spl_lang_type_id_t dst = sema_infer(sema, vec_at(*args, 1));
|
||||||
|
if (!dst)
|
||||||
|
return 0;
|
||||||
|
n->resolved_lang_tid = dst;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
spl_lang_type_id_t r = spl_lang_make_int(sema->type, sizeof(void *) * 8, 0);
|
||||||
|
n->resolved_lang_tid = r;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
@@ -868,19 +915,33 @@ static spl_lang_type_id_t sema_coerce(spl_sema_t *sema, spl_ast_node_ref_t ref,
|
|||||||
return expected;
|
return expected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SPL_AST_EXPR_LOOP: {
|
||||||
|
spl_lang_type_id_t saved = sema->current_loop_break_tid;
|
||||||
|
sema->current_loop_break_tid = expected;
|
||||||
|
sema_infer(sema, ref);
|
||||||
|
sema->current_loop_break_tid = saved;
|
||||||
|
n->resolved_lang_tid = expected;
|
||||||
|
return expected;
|
||||||
|
}
|
||||||
|
|
||||||
case SPL_AST_EXPR_BLOCK: {
|
case SPL_AST_EXPR_BLOCK: {
|
||||||
|
sema_push_scope(sema);
|
||||||
for (usize i = 0; i < vec_size(n->block.stmts); ++i)
|
for (usize i = 0; i < vec_size(n->block.stmts); ++i)
|
||||||
sema_infer(sema, vec_at(n->block.stmts, i));
|
sema_infer(sema, vec_at(n->block.stmts, i));
|
||||||
|
spl_lang_type_id_t r = 0;
|
||||||
if (n->block.tail_expr) {
|
if (n->block.tail_expr) {
|
||||||
spl_lang_type_id_t t = sema_coerce(sema, n->block.tail_expr, expected);
|
spl_lang_type_id_t t = sema_coerce(sema, n->block.tail_expr, expected);
|
||||||
if (!t)
|
if (!t) {
|
||||||
|
sema_pop_scope(sema);
|
||||||
return 0;
|
return 0;
|
||||||
n->resolved_lang_tid = t;
|
}
|
||||||
return t;
|
r = t;
|
||||||
|
} else {
|
||||||
|
r = spl_lang_make_unit(sema->type);
|
||||||
}
|
}
|
||||||
spl_lang_type_id_t u = spl_lang_make_unit(sema->type);
|
sema_pop_scope(sema);
|
||||||
n->resolved_lang_tid = u;
|
n->resolved_lang_tid = r;
|
||||||
return u;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -1218,11 +1279,12 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
|||||||
if (!sema_coerce(sema, vec_at(n->call.args, i), pt))
|
if (!sema_coerce(sema, vec_at(n->call.args, i), pt))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* varargs:默认提升到 isize */
|
|
||||||
if (has_varargs) {
|
if (has_varargs) {
|
||||||
spl_lang_type_id_t vt = spl_lang_make_int(sema->type, sizeof(void *) * 8, 1);
|
for (usize i = fixed; i < nargs; ++i) {
|
||||||
for (usize i = fixed; i < nargs; ++i)
|
if (!sema_infer(sema, vec_at(n->call.args, i)))
|
||||||
sema_coerce(sema, vec_at(n->call.args, i), vt);
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_lang_type_id_t ret = fn->extra.fn.ret;
|
spl_lang_type_id_t ret = fn->extra.fn.ret;
|
||||||
@@ -1350,33 +1412,48 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
|||||||
|
|
||||||
/* ---------- CAST ---------- */
|
/* ---------- CAST ---------- */
|
||||||
case SPL_AST_EXPR_CAST: {
|
case SPL_AST_EXPR_CAST: {
|
||||||
spl_lang_type_id_t dst = sema_infer(sema, n->cast.type);
|
spl_lang_type_id_t dst_lang = sema_infer(sema, n->cast.type);
|
||||||
if (!dst)
|
if (!dst_lang)
|
||||||
return 0;
|
return 0;
|
||||||
spl_lang_type_id_t src = sema_infer(sema, n->cast.expr);
|
spl_lang_type_id_t src_lang = sema_infer(sema, n->cast.expr);
|
||||||
if (!src)
|
if (!src_lang)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* 仅当 src 是 comptime 时收紧到 dst;具体类型间的 as 直接放行(截断/扩展由 ast2ir 生成) */
|
spl_lang_type_node_t *sn = spl_lang_type_node(sema->type, src_lang);
|
||||||
spl_lang_type_node_t *sn = spl_lang_type_node(sema->type, src);
|
|
||||||
spl_type_node_t *sir = sn ? spl_type_node(sema->type, sn->ir_type_id) : NULL;
|
spl_type_node_t *sir = sn ? spl_type_node(sema->type, sn->ir_type_id) : NULL;
|
||||||
bool src_comptime =
|
bool src_is_literal_int =
|
||||||
(sn && sn->kind == SPL_LANG_TYPE_INT && sir && sir->int_type.bits == 0) ||
|
sn && sn->kind == SPL_LANG_TYPE_INT && sir && sir->int_type.bits == 0;
|
||||||
(sn && sn->kind == SPL_LANG_TYPE_FLOAT && sir && sir->float_type.bits == 0);
|
bool src_is_literal_float =
|
||||||
if (src_comptime) {
|
sn && sn->kind == SPL_LANG_TYPE_FLOAT && sir && sir->float_type.bits == 0;
|
||||||
if (!sema_coerce(sema, n->cast.expr, dst))
|
|
||||||
|
if (src_is_literal_int || src_is_literal_float) {
|
||||||
|
/* 字面量目标物化:允许任意宽度,as 会按其语义处理 */
|
||||||
|
spl_ast_node_t *src_node = spl_ast_node(sema->ast, n->cast.expr);
|
||||||
|
if (src_node && (src_node->kind == SPL_AST_EXPR_INT_LIT ||
|
||||||
|
src_node->kind == SPL_AST_EXPR_FLOAT_LIT)) {
|
||||||
|
src_node->resolved_lang_tid = dst_lang;
|
||||||
|
} else if (!sema_coerce(sema, n->cast.expr, dst_lang)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
n->resolved_lang_tid = dst_lang;
|
||||||
|
return dst_lang;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sn && !(sn->kind == SPL_LANG_TYPE_INT || sn->kind == SPL_LANG_TYPE_FLOAT ||
|
spl_type_id_t ft = spl_lang_type_get_ir_type(sema->type, src_lang);
|
||||||
sn->kind == SPL_LANG_TYPE_BOOL || sn->kind == SPL_LANG_TYPE_PTR)) {
|
spl_type_id_t tt = spl_lang_type_get_ir_type(sema->type, dst_lang);
|
||||||
SPL_ERROR(&n->dbg, "invalid cast from non-primitive type");
|
if (!ft || !tt) {
|
||||||
|
SPL_ERROR(&n->dbg, "as: unresolved source or target type");
|
||||||
sema->error_count++;
|
sema->error_count++;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
spl_intrin_t in = spl_intrin_lookup_cast(sema->type, ft, tt);
|
||||||
n->resolved_lang_tid = dst;
|
if (in == SPL_INTRIN_NONE) {
|
||||||
return dst;
|
SPL_ERROR(&n->dbg, "as: invalid conversion (not supported by as)");
|
||||||
|
sema->error_count++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
n->resolved_lang_tid = dst_lang;
|
||||||
|
return dst_lang;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- TUPLE ---------- */
|
/* ---------- TUPLE ---------- */
|
||||||
@@ -1495,11 +1572,13 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
|||||||
|
|
||||||
/* ---------- BLOCK ---------- */
|
/* ---------- BLOCK ---------- */
|
||||||
case SPL_AST_EXPR_BLOCK: {
|
case SPL_AST_EXPR_BLOCK: {
|
||||||
|
sema_push_scope(sema);
|
||||||
spl_lang_type_id_t last = 0;
|
spl_lang_type_id_t last = 0;
|
||||||
for (usize i = 0; i < vec_size(n->block.stmts); ++i)
|
for (usize i = 0; i < vec_size(n->block.stmts); ++i)
|
||||||
last = sema_infer(sema, vec_at(n->block.stmts, i));
|
sema_infer(sema, vec_at(n->block.stmts, i));
|
||||||
if (n->block.tail_expr)
|
if (n->block.tail_expr)
|
||||||
last = sema_infer(sema, n->block.tail_expr);
|
last = sema_infer(sema, n->block.tail_expr);
|
||||||
|
sema_pop_scope(sema);
|
||||||
n->resolved_lang_tid = last;
|
n->resolved_lang_tid = last;
|
||||||
return last;
|
return last;
|
||||||
}
|
}
|
||||||
@@ -1899,8 +1978,14 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
|||||||
sema->error_count++;
|
sema->error_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (n->statement_break.expr)
|
if (n->statement_break.expr) {
|
||||||
sema_infer(sema, n->statement_break.expr);
|
/* 有值 loop:break 值 coerce 到 loop 的期望类型 */
|
||||||
|
if (sema->current_loop_break_tid != 0) {
|
||||||
|
sema_coerce(sema, n->statement_break.expr, sema->current_loop_break_tid);
|
||||||
|
} else {
|
||||||
|
sema_infer(sema, n->statement_break.expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
case SPL_AST_STATEMENT_CONTINUE: {
|
case SPL_AST_STATEMENT_CONTINUE: {
|
||||||
@@ -1968,6 +2053,7 @@ void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope
|
|||||||
sema->error_count = 0;
|
sema->error_count = 0;
|
||||||
sema->current_fn_ret_tid = 0;
|
sema->current_fn_ret_tid = 0;
|
||||||
sema->current_aggregate_lang = 0;
|
sema->current_aggregate_lang = 0;
|
||||||
|
sema->current_loop_break_tid = 0;
|
||||||
sema->attr = attr;
|
sema->attr = attr;
|
||||||
sema->root = (spl_symbol_t){0};
|
sema->root = (spl_symbol_t){0};
|
||||||
sema->store_scope = 0;
|
sema->store_scope = 0;
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ typedef struct {
|
|||||||
spl_attr_t *attr;
|
spl_attr_t *attr;
|
||||||
spl_lang_type_id_t current_aggregate_lang;
|
spl_lang_type_id_t current_aggregate_lang;
|
||||||
spl_lang_type_id_t current_fn_ret_tid;
|
spl_lang_type_id_t current_fn_ret_tid;
|
||||||
|
spl_lang_type_id_t current_loop_break_tid;
|
||||||
spl_symbol_path_t label_stack;
|
spl_symbol_path_t label_stack;
|
||||||
} spl_sema_t;
|
} spl_sema_t;
|
||||||
|
|
||||||
|
|||||||
+4
-9
@@ -575,20 +575,15 @@ bool spl_lang_mpa_int_fits(const spl_type_t *type, spl_lang_type_id_t target, sp
|
|||||||
if (bits == 0)
|
if (bits == 0)
|
||||||
return true;
|
return true;
|
||||||
bool target_signed = ir->int_type.is_signed != 0;
|
bool target_signed = ir->int_type.is_signed != 0;
|
||||||
|
/* 字面量是无符号位模式:负号由 unary MINUS 承担 */
|
||||||
int64_t val = (int64_t)v.bits;
|
uint64_t uval = v.bits;
|
||||||
|
|
||||||
if (target_signed) {
|
if (target_signed) {
|
||||||
if (bits >= 64)
|
if (bits >= 64)
|
||||||
return true;
|
return true;
|
||||||
int64_t lo = -((int64_t)1 << (bits - 1));
|
uint64_t hi = ((uint64_t)1 << (bits - 1)) - 1;
|
||||||
int64_t hi = ((int64_t)1 << (bits - 1)) - 1;
|
return uval <= hi;
|
||||||
return val >= lo && val <= hi;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val < 0)
|
|
||||||
return false;
|
|
||||||
uint64_t uval = (uint64_t)val;
|
|
||||||
if (bits >= 64)
|
if (bits >= 64)
|
||||||
return true;
|
return true;
|
||||||
uint64_t hi = ((uint64_t)1 << bits) - 1;
|
uint64_t hi = ((uint64_t)1 << bits) - 1;
|
||||||
|
|||||||
Reference in new issue
Block a user