Compare commits
2
Commits
49ccdec3dd
...
a64a96f9a4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a64a96f9a4 | ||
|
|
87d9b7ea34 |
No files matched your search
@@ -31,8 +31,9 @@ static const char *splc0_srcs[] = {
|
|||||||
"stage1/spl_intrin.c",
|
"stage1/spl_intrin.c",
|
||||||
"stage1/spl_ir.c",
|
"stage1/spl_ir.c",
|
||||||
"stage1/spl_ast2ir.c",
|
"stage1/spl_ast2ir.c",
|
||||||
// "stage1/spl_ir2vm.c",
|
"stage1/spl_layout.c",
|
||||||
// "stage0/spl_mcode.c",
|
"stage1/spl_ir2vm.c",
|
||||||
|
"stage0/spl_mcode.c",
|
||||||
};
|
};
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
@@ -182,7 +183,7 @@ static void parse_expect(const char *name, Nob_Cmd_Result *expect) {
|
|||||||
if (rest.count == 0)
|
if (rest.count == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (nob_sv_starts_with(rest, nob_sv_from_cstr("Expect"))) {
|
if (!nob_sv_starts_with(rest, nob_sv_from_cstr("Expect"))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rest = nob_sv_from_parts(rest.data + 6, rest.count - 6);
|
rest = nob_sv_from_parts(rest.data + 6, rest.count - 6);
|
||||||
@@ -198,6 +199,7 @@ static void parse_expect(const char *name, Nob_Cmd_Result *expect) {
|
|||||||
for (size_t i = 0; i < value.count && isdigit(value.data[i]); ++i) {
|
for (size_t i = 0; i < value.count && isdigit(value.data[i]); ++i) {
|
||||||
val = val * 10 + (value.data[i] - '0');
|
val = val * 10 + (value.data[i] - '0');
|
||||||
}
|
}
|
||||||
|
// printf("expected code %d\n", val);
|
||||||
expect->exit_code = val;
|
expect->exit_code = val;
|
||||||
} else if (nob_sv_eq(key, nob_sv_from_cstr("stdout"))) {
|
} else if (nob_sv_eq(key, nob_sv_from_cstr("stdout"))) {
|
||||||
}
|
}
|
||||||
@@ -229,14 +231,14 @@ static bool test_once(const char *fname, void *user_data) {
|
|||||||
cmd.count = 0;
|
cmd.count = 0;
|
||||||
nob_cmd_append(&cmd, nob_temp_sprintf(BUILD_FOLDER "%s", cli_path));
|
nob_cmd_append(&cmd, nob_temp_sprintf(BUILD_FOLDER "%s", cli_path));
|
||||||
nob_cmd_append(&cmd, target_sir);
|
nob_cmd_append(&cmd, target_sir);
|
||||||
nob_cmd_run(&cmd);
|
// nob_cmd_run(&cmd);
|
||||||
|
|
||||||
Nob_Cmd_Result result = {0};
|
Nob_Cmd_Result result = {0};
|
||||||
|
|
||||||
Nob_String_Builder cmd_str = {0};
|
Nob_String_Builder cmd_str = {0};
|
||||||
nob_cmd_render(cmd, &cmd_str);
|
nob_cmd_render(cmd, &cmd_str);
|
||||||
nob_sb_append_null(&cmd_str);
|
|
||||||
nob_cmd_capture_popen(cmd_str.items, &result);
|
Nob_String_View sv = nob_sb_to_sv(cmd_str);
|
||||||
|
nob_cmd_capture_popen(nob_temp_sv_to_cstr(sv), &result);
|
||||||
// Expect retcode = number
|
// Expect retcode = number
|
||||||
|
|
||||||
Nob_Cmd_Result expect = {0};
|
Nob_Cmd_Result expect = {0};
|
||||||
@@ -268,6 +270,10 @@ typedef bool (*test_fn_t)(const char *fname, void *user_data);
|
|||||||
static bool run_test(Nob_Files *files, test_fn_t test_once, void *user_data) {
|
static bool run_test(Nob_Files *files, test_fn_t test_once, void *user_data) {
|
||||||
const char *test_folder = "./tests/stage1/";
|
const char *test_folder = "./tests/stage1/";
|
||||||
|
|
||||||
|
if (!prepare_build()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
Nob_File_Paths paths = {0};
|
Nob_File_Paths paths = {0};
|
||||||
nob_read_entire_dir(test_folder, &paths);
|
nob_read_entire_dir(test_folder, &paths);
|
||||||
for (int i = 0; i < files->count; i += 1) {
|
for (int i = 0; i < files->count; i += 1) {
|
||||||
@@ -284,10 +290,6 @@ static bool run_test(Nob_Files *files, test_fn_t test_once, void *user_data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!prepare_build()) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +322,7 @@ int main(int argc, char **argv) {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
SetConsoleOutputCP(CP_UTF8);
|
SetConsoleOutputCP(CP_UTF8);
|
||||||
#endif
|
#endif
|
||||||
NOB_GO_REBUILD_URSELF_PLUS(argc, argv, "nob.h");
|
NOB_GO_REBUILD_URSELF_PLUS(argc, argv, "nob.h", "nob_popen.h");
|
||||||
set_log_handler(nob_cancer_log_handler);
|
set_log_handler(nob_cancer_log_handler);
|
||||||
|
|
||||||
const char *program_name = nob_shift(argv, argc);
|
const char *program_name = nob_shift(argv, argc);
|
||||||
|
|||||||
+105
-14
@@ -15,34 +15,125 @@ typedef struct {
|
|||||||
int count;
|
int count;
|
||||||
} Nob_Files;
|
} Nob_Files;
|
||||||
|
|
||||||
// 运行命令,捕获 stdout 和退出码(不支持 stdin 和 stderr)
|
// 运行命令,捕获 stdout(Windows 下会合并 stderr)和真实退出码。
|
||||||
|
// 返回 true 仅表示命令成功启动并完成,不代表 exit_code == 0。
|
||||||
bool nob_cmd_capture_popen(const char *tname, Nob_Cmd_Result *res) {
|
bool nob_cmd_capture_popen(const char *tname, Nob_Cmd_Result *res) {
|
||||||
memset(res, 0, sizeof(*res));
|
memset(res, 0, sizeof(*res));
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
FILE *fp = _popen(tname, "r");
|
// ---------- Windows: CreateProcessA + 匿名管道 ----------
|
||||||
#else
|
SECURITY_ATTRIBUTES sa = {0};
|
||||||
FILE *fp = popen(tname, "r");
|
sa.nLength = sizeof(sa);
|
||||||
#endif
|
sa.bInheritHandle = TRUE;
|
||||||
|
sa.lpSecurityDescriptor = NULL;
|
||||||
|
|
||||||
|
HANDLE hRead = NULL;
|
||||||
|
HANDLE hWrite = NULL;
|
||||||
|
if (!CreatePipe(&hRead, &hWrite, &sa, 0)) {
|
||||||
|
nob_log(NOB_ERROR, "CreatePipe failed: %s", nob_win32_error_message(GetLastError()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读端不能被继承,否则父进程 ReadFile 永远等不到 EOF
|
||||||
|
if (!SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0)) {
|
||||||
|
nob_log(NOB_ERROR, "SetHandleInformation failed: %s",
|
||||||
|
nob_win32_error_message(GetLastError()));
|
||||||
|
CloseHandle(hRead);
|
||||||
|
CloseHandle(hWrite);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTUPINFOA si = {0};
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
si.dwFlags = STARTF_USESTDHANDLES;
|
||||||
|
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
si.hStdOutput = hWrite;
|
||||||
|
si.hStdError = hWrite; // 把 stderr 也并入 out,需要分离的话另开一条管道
|
||||||
|
|
||||||
|
PROCESS_INFORMATION pi = {0};
|
||||||
|
|
||||||
|
// CreateProcessA 会就地修改 lpCommandLine,必须传可写缓冲
|
||||||
|
char *cmdline = NULL;
|
||||||
|
{
|
||||||
|
size_t n = strlen(tname) + 1;
|
||||||
|
cmdline = (char *)malloc(n);
|
||||||
|
if (!cmdline) {
|
||||||
|
CloseHandle(hRead);
|
||||||
|
CloseHandle(hWrite);
|
||||||
|
nob_log(NOB_ERROR, "malloc failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(cmdline, tname, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL ok = CreateProcessA(NULL, // lpApplicationName: 让系统从 lpCommandLine 里解析
|
||||||
|
cmdline, // lpCommandLine
|
||||||
|
NULL, // lpProcessAttributes
|
||||||
|
NULL, // lpThreadAttributes
|
||||||
|
TRUE, // bInheritHandles: 必须为 TRUE,才能继承管道写端
|
||||||
|
CREATE_NO_WINDOW, // 不弹黑窗;想弹就传 0
|
||||||
|
NULL, // lpEnvironment
|
||||||
|
NULL, // lpCurrentDirectory
|
||||||
|
&si, &pi);
|
||||||
|
|
||||||
|
free(cmdline);
|
||||||
|
|
||||||
|
// 无论成功与否,父进程都不再需要写端(子进程已持有自己的副本)
|
||||||
|
CloseHandle(hWrite);
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
nob_log(NOB_ERROR, "CreateProcessA failed for \"%s\": %s", tname,
|
||||||
|
nob_win32_error_message(GetLastError()));
|
||||||
|
CloseHandle(hRead);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- 读取 stdout ----------
|
||||||
|
{
|
||||||
|
char buffer[4096];
|
||||||
|
DWORD n = 0;
|
||||||
|
while (ReadFile(hRead, buffer, sizeof(buffer), &n, NULL) && n > 0) {
|
||||||
|
nob_sb_append_buf(&res->out, buffer, (size_t)n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CloseHandle(hRead);
|
||||||
|
|
||||||
|
// ---------- 等待并取真实退出码 ----------
|
||||||
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||||
|
DWORD code = 0;
|
||||||
|
if (!GetExitCodeProcess(pi.hProcess, &code)) {
|
||||||
|
nob_log(NOB_ERROR, "GetExitCodeProcess failed: %s",
|
||||||
|
nob_win32_error_message(GetLastError()));
|
||||||
|
code = (DWORD)-1;
|
||||||
|
}
|
||||||
|
res->exit_code = (int)code;
|
||||||
|
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
|
||||||
|
#else
|
||||||
|
// ---------- POSIX: popen ----------
|
||||||
|
FILE *fp = popen(tname, "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
nob_log(NOB_ERROR, "popen failed");
|
nob_log(NOB_ERROR, "popen failed: %s", strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 读取输出到 String_Builder
|
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||||
nob_sb_append_cstr(&res->out, buffer);
|
nob_sb_append_cstr(&res->out, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取退出码
|
int status = pclose(fp);
|
||||||
#ifdef _WIN32
|
if (status == -1) {
|
||||||
res->exit_code = _pclose(fp);
|
nob_log(NOB_ERROR, "pclose failed: %s", strerror(errno));
|
||||||
#else
|
return false;
|
||||||
res->exit_code = pclose(fp);
|
}
|
||||||
if (WIFEXITED(res->exit_code))
|
if (WIFEXITED(status))
|
||||||
res->exit_code = WEXITSTATUS(res->exit_code);
|
status = WEXITSTATUS(status);
|
||||||
|
else if (WIFSIGNALED(status))
|
||||||
|
status = 128 + WTERMSIG(status);
|
||||||
|
res->exit_code = status;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
res->ok = true;
|
res->ok = true;
|
||||||
|
|||||||
+1
-1
@@ -91,7 +91,7 @@ static spl_ast_node_ref_t new_node(parser_t *p, spl_ast_node_kind_t kind, const
|
|||||||
spl_ast_node_t n = {0};
|
spl_ast_node_t n = {0};
|
||||||
n.kind = kind;
|
n.kind = kind;
|
||||||
n.resolved_def_id = 0;
|
n.resolved_def_id = 0;
|
||||||
n.resolved_type_id = 0;
|
n.resolved_lang_tid = 0;
|
||||||
if (tok) {
|
if (tok) {
|
||||||
n.dbg.dbg_name = spl_ast_kind_name(kind);
|
n.dbg.dbg_name = spl_ast_kind_name(kind);
|
||||||
n.dbg.fname = tok->fname;
|
n.dbg.fname = tok->fname;
|
||||||
|
|||||||
+3
-1
@@ -150,8 +150,10 @@ typedef VEC(spl_ast_node_ref_t) spl_ast_node_ref_vec_t;
|
|||||||
struct spl_ast_node {
|
struct spl_ast_node {
|
||||||
spl_ast_node_kind_t kind;
|
spl_ast_node_kind_t kind;
|
||||||
spl_dbg_node_t dbg;
|
spl_dbg_node_t dbg;
|
||||||
|
|
||||||
usize resolved_def_id;
|
usize resolved_def_id;
|
||||||
usize resolved_type_id;
|
usize resolved_lang_tid;
|
||||||
|
usize expected_lang_tid;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
/* SPL_AST_ROOT */
|
/* SPL_AST_ROOT */
|
||||||
|
|||||||
+175
-60
@@ -8,11 +8,8 @@ static spl_type_id_t to_ir_type(spl_ast2ir_t *a, spl_lang_type_id_t lang) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static spl_lang_type_id_t node_lang(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
static spl_lang_type_id_t node_lang(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
||||||
if (!n)
|
(void)a;
|
||||||
return 0;
|
return n ? n->resolved_lang_tid : 0;
|
||||||
if (n->kind == SPL_AST_EXPR_IDENT)
|
|
||||||
return spl_def_get_lang_id(a->sema->type, n->resolved_def_id);
|
|
||||||
return n->resolved_type_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static spl_type_id_t node_ir(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
static spl_type_id_t node_ir(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
||||||
@@ -30,27 +27,48 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
|||||||
static void emit_decl(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
static void emit_decl(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
static void emit_fn(spl_ast2ir_t *a, spl_ast_node_t *n);
|
static void emit_fn(spl_ast2ir_t *a, spl_ast_node_t *n);
|
||||||
static void emit_container(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
static void emit_container(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
|
||||||
static spl_ir_node_ref_t emit_cast(spl_ast2ir_t *a, spl_ast_node_t *n);
|
|
||||||
|
|
||||||
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 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_implicit_cast(spl_ast2ir_t *a, spl_type_id_t ft, spl_type_id_t tt,
|
||||||
|
spl_ir_node_ref_t v);
|
||||||
|
|
||||||
|
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);
|
||||||
static spl_ir_node_ref_t ast2ir_intrin_field(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in);
|
static spl_ir_node_ref_t ast2ir_intrin_field(spl_ast2ir_t *a, spl_ast_node_t *n, spl_intrin_t in);
|
||||||
static spl_ir_node_ref_t ast2ir_intrin_len(spl_ast2ir_t *a, spl_ast_node_t *n);
|
static spl_ir_node_ref_t ast2ir_intrin_len(spl_ast2ir_t *a, spl_ast_node_t *n);
|
||||||
|
|
||||||
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) {
|
||||||
switch (in) {
|
switch (in) {
|
||||||
case SPL_INTRIN_SIZEOF: {
|
case SPL_INTRIN_SIZEOF: {
|
||||||
spl_ast_node_t *arg = spl_ast_node(a->sema->ast, vec_at(n->call.args, 0));
|
spl_ast_node_t *arg = spl_ast_node(a->sema->ast, vec_at(*args, 0));
|
||||||
return spl_ir_builder_type_sizeof(a->ir, node_ir(a, arg));
|
return spl_ir_builder_type_sizeof(a->ir, node_ir(a, arg));
|
||||||
}
|
}
|
||||||
case SPL_INTRIN_ALIGNOF: {
|
case SPL_INTRIN_ALIGNOF: {
|
||||||
spl_ast_node_t *arg = spl_ast_node(a->sema->ast, vec_at(n->call.args, 0));
|
spl_ast_node_t *arg = spl_ast_node(a->sema->ast, vec_at(*args, 0));
|
||||||
return spl_ir_builder_type_alignof(a->ir, node_ir(a, arg));
|
return spl_ir_builder_type_alignof(a->ir, node_ir(a, arg));
|
||||||
}
|
}
|
||||||
case SPL_INTRIN_ASSERT: {
|
case SPL_INTRIN_ASSERT: {
|
||||||
/* 目前 SEMA 只做类型检查,emit 阶段留空,
|
spl_ir_node_ref_t cond = emit_expr(a, vec_at(*args, 0));
|
||||||
@assert 展开需待 control.trap 语义明确后再实现 */
|
if (!cond)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
spl_lang_type_id_t b = spl_lang_make_bool(a->sema->type);
|
||||||
|
spl_ir_node_ref_t notc = spl_ir_builder_arith_not(a->ir, to_ir_type(a, b), cond);
|
||||||
|
spl_ir_node_ref_t br = spl_ir_builder_control_br(a->ir, notc);
|
||||||
|
spl_ir_builder_block_end(a->ir);
|
||||||
|
|
||||||
|
usize trap_blk = spl_ir_builder_block_begin(a->ir);
|
||||||
|
spl_ir_builder_control_trap(a->ir);
|
||||||
|
spl_ir_builder_block_end(a->ir);
|
||||||
|
|
||||||
|
usize cont_blk = spl_ir_builder_block_begin(a->ir);
|
||||||
|
spl_ir_builder_control_br_fixup(a->ir, br, trap_blk, cont_blk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
case SPL_INTRIN_BREAKPOINT:
|
||||||
|
return spl_ir_builder_dbg_breakpoint(a->ir);
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
@@ -88,8 +106,8 @@ static spl_ir_node_ref_t ast2ir_intrin_len(spl_ast2ir_t *a, spl_ast_node_t *n) {
|
|||||||
spl_ir_node_ref_t slice_val = emit_expr(a, n->field.obj);
|
spl_ir_node_ref_t slice_val = emit_expr(a, n->field.obj);
|
||||||
if (!slice_val)
|
if (!slice_val)
|
||||||
return 0;
|
return 0;
|
||||||
return spl_ir_builder_agg_extract(a->ir, usize_ir, usize_ir, SPL_SLICE_LEN_FIELD_IDX,
|
return spl_ir_builder_agg_extract(a->ir, recv->ir_type_id, usize_ir,
|
||||||
slice_val);
|
SPL_SLICE_LEN_FIELD_IDX, slice_val);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -142,12 +160,7 @@ static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
|||||||
if (!spl_type_agg_member_idx(a->sema->type, agg_ir, n->field.field, &idx))
|
if (!spl_type_agg_member_idx(a->sema->type, agg_ir, n->field.field, &idx))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
spl_type_node_t *agg_n = spl_type_node(a->sema->type, agg_ir);
|
return spl_ir_builder_mem_field(a->ir, agg_ir, base, idx);
|
||||||
if (!agg_n)
|
|
||||||
return 0;
|
|
||||||
spl_type_id_t field_ir = vec_at(agg_n->agg_type.variants, idx).type_id;
|
|
||||||
|
|
||||||
return spl_ir_builder_mem_field(a->ir, field_ir, base, idx);
|
|
||||||
}
|
}
|
||||||
case SPL_AST_EXPR_INDEX: {
|
case SPL_AST_EXPR_INDEX: {
|
||||||
spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->index.obj);
|
spl_ast_node_t *obj = spl_ast_node(a->sema->ast, n->index.obj);
|
||||||
@@ -198,7 +211,7 @@ 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_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(a, n->cast.expr);
|
spl_ir_node_ref_t v = emit_expr_raw(a, n->cast.expr);
|
||||||
if (!v)
|
if (!v)
|
||||||
return 0;
|
return 0;
|
||||||
spl_ast_node_t *src = spl_ast_node(a->sema->ast, n->cast.expr);
|
spl_ast_node_t *src = spl_ast_node(a->sema->ast, n->cast.expr);
|
||||||
@@ -238,6 +251,28 @@ 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(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) {
|
||||||
|
spl_ir_node_ref_t val = emit_expr_raw(a, ref);
|
||||||
|
if (!val)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
spl_ast_node_t *n = spl_ast_node(a->sema->ast, ref);
|
||||||
|
if (!n || n->expected_lang_tid == 0)
|
||||||
|
return val;
|
||||||
|
|
||||||
|
spl_lang_type_id_t from = n->resolved_lang_tid;
|
||||||
|
spl_lang_type_id_t to = n->expected_lang_tid;
|
||||||
|
if (!from || from == to)
|
||||||
|
return val;
|
||||||
|
|
||||||
|
spl_type_id_t from_ir = to_ir_type(a, from);
|
||||||
|
spl_type_id_t to_ir = to_ir_type(a, to);
|
||||||
|
if (!from_ir || !to_ir || from_ir == to_ir)
|
||||||
|
return val;
|
||||||
|
|
||||||
|
return emit_implicit_cast(a, from_ir, to_ir, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static spl_ir_node_ref_t emit_expr_raw(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)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -396,22 +431,32 @@ static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
|||||||
if (callee && callee->kind == SPL_AST_EXPR_IDENT) {
|
if (callee && callee->kind == SPL_AST_EXPR_IDENT) {
|
||||||
spl_intrin_t in = spl_intrin_lookup_call(callee->ident.name);
|
spl_intrin_t in = spl_intrin_lookup_call(callee->ident.name);
|
||||||
if (in != SPL_INTRIN_NONE)
|
if (in != SPL_INTRIN_NONE)
|
||||||
return ast2ir_intrin_call(a, n, in);
|
return ast2ir_intrin_call(a, n, in, &n->call.args);
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_ir_node_ref_t fn = emit_expr(a, n->call.callee);
|
spl_ir_node_ref_t fn = emit_expr(a, n->call.callee);
|
||||||
if (!fn)
|
if (!fn)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* 先求所有参数 */
|
||||||
|
usize nargs = vec_size(n->call.args);
|
||||||
|
spl_ir_node_ref_vec_t arg_refs;
|
||||||
|
vec_init(arg_refs);
|
||||||
|
for (usize i = 0; i < nargs; ++i)
|
||||||
|
vec_push(arg_refs, emit_expr(a, vec_at(n->call.args, i)));
|
||||||
|
|
||||||
|
/* 再创建 call 节点 */
|
||||||
spl_type_id_t ret_t = node_ir(a, n);
|
spl_type_id_t ret_t = node_ir(a, n);
|
||||||
spl_ir_node_ref_t call = spl_ir_builder_control_call(a->ir, ret_t, fn);
|
spl_ir_node_ref_t call = spl_ir_builder_control_call(a->ir, ret_t, fn);
|
||||||
if (!call)
|
if (!call) {
|
||||||
|
vec_free(arg_refs);
|
||||||
return 0;
|
return 0;
|
||||||
for (usize i = 0; i < vec_size(n->call.args); ++i) {
|
|
||||||
spl_ir_node_ref_t arg = emit_expr(a, vec_at(n->call.args, i));
|
|
||||||
if (!arg)
|
|
||||||
return 0;
|
|
||||||
spl_ir_builder_control_call_param(a->ir, call, arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (usize i = 0; i < vec_size(arg_refs); ++i)
|
||||||
|
spl_ir_builder_control_call_param(a->ir, call, vec_at(arg_refs, i));
|
||||||
|
vec_free(arg_refs);
|
||||||
|
|
||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
case SPL_AST_EXPR_FIELD: {
|
case SPL_AST_EXPR_FIELD: {
|
||||||
@@ -438,15 +483,25 @@ static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
|||||||
return emit_cast(a, n);
|
return emit_cast(a, n);
|
||||||
case SPL_AST_EXPR_TUPLE: {
|
case SPL_AST_EXPR_TUPLE: {
|
||||||
spl_type_id_t t = node_ir(a, n);
|
spl_type_id_t t = node_ir(a, n);
|
||||||
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, t);
|
usize nelems = vec_size(n->tuple.elems);
|
||||||
if (!node)
|
|
||||||
return 0;
|
spl_ir_node_ref_vec_t field_refs;
|
||||||
for (usize i = 0; i < vec_size(n->tuple.elems); ++i) {
|
vec_init(field_refs);
|
||||||
|
for (usize i = 0; i < nelems; ++i) {
|
||||||
spl_ir_node_ref_t f = emit_expr(a, vec_at(n->tuple.elems, i));
|
spl_ir_node_ref_t f = emit_expr(a, vec_at(n->tuple.elems, i));
|
||||||
if (!f)
|
if (!f)
|
||||||
return 0;
|
Panic("tuple element emit failed");
|
||||||
spl_ir_builder_agg_construct_field(a->ir, node, f);
|
vec_push(field_refs, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, t);
|
||||||
|
if (!node)
|
||||||
|
Panic("agg_construct failed for tuple");
|
||||||
|
|
||||||
|
for (usize i = 0; i < nelems; ++i)
|
||||||
|
spl_ir_builder_agg_construct_field(a->ir, node, vec_at(field_refs, i));
|
||||||
|
|
||||||
|
vec_free(field_refs);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
case SPL_AST_EXPR_ARRAY_LIT: {
|
case SPL_AST_EXPR_ARRAY_LIT: {
|
||||||
@@ -454,16 +509,25 @@ static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
|||||||
if (!t)
|
if (!t)
|
||||||
Panic("array literal has no type after sema");
|
Panic("array literal has no type after sema");
|
||||||
|
|
||||||
|
usize nelems = vec_size(n->array_literal.elems);
|
||||||
|
|
||||||
|
spl_ir_node_ref_vec_t field_refs;
|
||||||
|
vec_init(field_refs);
|
||||||
|
for (usize i = 0; i < nelems; ++i) {
|
||||||
|
spl_ir_node_ref_t f = emit_expr(a, vec_at(n->array_literal.elems, i));
|
||||||
|
if (!f)
|
||||||
|
Panic("array element emit failed");
|
||||||
|
vec_push(field_refs, f);
|
||||||
|
}
|
||||||
|
|
||||||
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, t);
|
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, t);
|
||||||
if (!node)
|
if (!node)
|
||||||
Panic("agg_construct failed for array literal");
|
Panic("agg_construct failed for array literal");
|
||||||
|
|
||||||
for (usize i = 0; i < vec_size(n->array_literal.elems); ++i) {
|
for (usize i = 0; i < nelems; ++i)
|
||||||
spl_ir_node_ref_t f = emit_expr(a, vec_at(n->array_literal.elems, i));
|
spl_ir_builder_agg_construct_field(a->ir, node, vec_at(field_refs, i));
|
||||||
if (!f)
|
|
||||||
Panic("array element emit failed");
|
vec_free(field_refs);
|
||||||
spl_ir_builder_agg_construct_field(a->ir, node, f);
|
|
||||||
}
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
case SPL_AST_EXPR_AGGREGATE_LIT: {
|
case SPL_AST_EXPR_AGGREGATE_LIT: {
|
||||||
@@ -535,47 +599,62 @@ static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
|
|||||||
if (!obj_ln)
|
if (!obj_ln)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* 目前只处理数组->切片的完整形式 arr[..](无 begin / end)
|
spl_type_id_t slice_ir = node_ir(a, n);
|
||||||
或 arr[begin..end] 的通用形式。简化实现只做完整切片。 */
|
|
||||||
spl_type_id_t slice_ir = node_ir(a, n); /* struct{ptr, len} */
|
|
||||||
if (!slice_ir)
|
if (!slice_ir)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, slice_ir);
|
spl_lang_type_id_t elem_lang = obj_ln->extra.elem;
|
||||||
if (!node)
|
spl_type_id_t elem_ir = to_ir_type(a, elem_lang);
|
||||||
return 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_ir_node_ref_t base = emit_lvalue(a, n->slice.obj);
|
spl_ir_node_ref_t base = emit_lvalue(a, n->slice.obj);
|
||||||
if (!base)
|
if (!base)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
spl_type_id_t ptr_ir =
|
spl_ir_node_ref_t begin_v = 0;
|
||||||
spl_type_builder_ptr(a->sema->type, to_ir_type(a, obj_ln->extra.elem));
|
if (n->slice.begin)
|
||||||
|
begin_v = emit_expr(a, n->slice.begin);
|
||||||
|
else
|
||||||
|
begin_v = spl_ir_builder_type_const_int(a->ir, usize_ir, 0);
|
||||||
|
if (!begin_v)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* 字段 0:ptr */
|
spl_ir_node_ref_t ptr = spl_ir_builder_mem_offset(a->ir, elem_ir, base, begin_v);
|
||||||
spl_ir_builder_agg_construct_field(a->ir, node, base);
|
if (!ptr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* 字段 1:len —— 数组取 len,切片取原切片 len */
|
spl_ir_node_ref_t end_v = 0;
|
||||||
spl_ir_node_ref_t len = 0;
|
if (n->slice.end) {
|
||||||
if (obj_ln->kind == SPL_LANG_TYPE_ARRAY) {
|
end_v = emit_expr(a, n->slice.end);
|
||||||
|
} else if (obj_ln->kind == SPL_LANG_TYPE_ARRAY) {
|
||||||
spl_type_node_t *arr = spl_type_node(a->sema->type, obj_ln->ir_type_id);
|
spl_type_node_t *arr = spl_type_node(a->sema->type, obj_ln->ir_type_id);
|
||||||
spl_lang_type_id_t usize = spl_lang_make_int(a->sema->type, sizeof(void *) * 8, 0);
|
end_v = spl_ir_builder_type_const_int(a->ir, usize_ir, arr->array_type.len);
|
||||||
len = spl_ir_builder_type_const_int(a->ir, to_ir_type(a, usize), arr->array_type.len);
|
|
||||||
} else if (obj_ln->kind == SPL_LANG_TYPE_SLICE) {
|
} else if (obj_ln->kind == SPL_LANG_TYPE_SLICE) {
|
||||||
spl_ir_node_ref_t slice_val = emit_expr(a, n->slice.obj);
|
spl_ir_node_ref_t slice_val = emit_expr(a, n->slice.obj);
|
||||||
spl_lang_type_id_t usize = spl_lang_make_int(a->sema->type, sizeof(void *) * 8, 0);
|
end_v = spl_ir_builder_agg_extract(a->ir, obj_ln->ir_type_id, usize_ir,
|
||||||
len = spl_ir_builder_agg_extract(a->ir, to_ir_type(a, usize), to_ir_type(a, usize),
|
|
||||||
SPL_SLICE_LEN_FIELD_IDX, slice_val);
|
SPL_SLICE_LEN_FIELD_IDX, slice_val);
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (!end_v)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
spl_ir_node_ref_t len = spl_ir_builder_arith_sub(a->ir, usize_ir, end_v, begin_v);
|
||||||
|
|
||||||
|
spl_ir_node_ref_t node = spl_ir_builder_agg_construct(a->ir, slice_ir);
|
||||||
|
if (!node)
|
||||||
|
return 0;
|
||||||
|
spl_ir_builder_agg_construct_field(a->ir, node, ptr);
|
||||||
spl_ir_builder_agg_construct_field(a->ir, node, len);
|
spl_ir_builder_agg_construct_field(a->ir, node, len);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
case SPL_AST_EXPR_COMPTIME_CALL:
|
case SPL_AST_EXPR_COMPTIME_CALL: {
|
||||||
// TODO
|
spl_intrin_t in = spl_intrin_lookup_call(n->comptime_call.name);
|
||||||
|
if (in == SPL_INTRIN_NONE)
|
||||||
return 0;
|
return 0;
|
||||||
|
return ast2ir_intrin_call(a, n, in, &n->comptime_call.args);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
TODO();
|
TODO();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -959,6 +1038,42 @@ static void emit_container(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,
|
||||||
|
spl_ir_node_ref_t v) {
|
||||||
|
if (!ft || !tt || ft == tt)
|
||||||
|
return v;
|
||||||
|
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)
|
||||||
|
return v;
|
||||||
|
|
||||||
|
if (fs->kind == SPL_TYPE_INT && ts->kind == SPL_TYPE_INT) {
|
||||||
|
if (fs->int_type.bits == ts->int_type.bits)
|
||||||
|
return spl_ir_builder_cast_bitcast(a->ir, ft, tt, v);
|
||||||
|
if (fs->int_type.bits > ts->int_type.bits)
|
||||||
|
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 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 usize spl_int_map_hash(usize k) { return MAP_HASH_INT(k); }
|
static usize spl_int_map_hash(usize k) { return MAP_HASH_INT(k); }
|
||||||
static int spl_int_map_cmp(usize a, usize b) { return MAP_CMP_INT(a, b); }
|
static int spl_int_map_cmp(usize a, usize b) { return MAP_CMP_INT(a, b); }
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ static const spl_intrin_info_t g_intrin_table[] = {
|
|||||||
SPL_INTRIN_RESULT_USIZE},
|
SPL_INTRIN_RESULT_USIZE},
|
||||||
[SPL_INTRIN_ASSERT] = {"@assert", SPL_INTRIN_ASSERT, SPL_INTRIN_FORM_CALL, 1, 2,
|
[SPL_INTRIN_ASSERT] = {"@assert", SPL_INTRIN_ASSERT, SPL_INTRIN_FORM_CALL, 1, 2,
|
||||||
SPL_INTRIN_RESULT_UNIT},
|
SPL_INTRIN_RESULT_UNIT},
|
||||||
|
[SPL_INTRIN_BREAKPOINT] = {"@breakpoint", SPL_INTRIN_BREAKPOINT, SPL_INTRIN_FORM_CALL, 0, 0,
|
||||||
|
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},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ typedef enum {
|
|||||||
SPL_INTRIN_SIZEOF,
|
SPL_INTRIN_SIZEOF,
|
||||||
SPL_INTRIN_ALIGNOF,
|
SPL_INTRIN_ALIGNOF,
|
||||||
SPL_INTRIN_ASSERT,
|
SPL_INTRIN_ASSERT,
|
||||||
|
SPL_INTRIN_BREAKPOINT,
|
||||||
SPL_INTRIN_LEN,
|
SPL_INTRIN_LEN,
|
||||||
} spl_intrin_t;
|
} spl_intrin_t;
|
||||||
|
|
||||||
|
|||||||
+19
-8
@@ -196,8 +196,8 @@ static void ir_dump_node(const spl_type_t *ty, spl_ir_node_t *n) {
|
|||||||
printf(" float=%f", n->type_const.float_lit);
|
printf(" float=%f", n->type_const.float_lit);
|
||||||
} else if (t && t->kind == SPL_TYPE_FN) {
|
} else if (t && t->kind == SPL_TYPE_FN) {
|
||||||
printf(" fn#%zu", n->type_const.fn);
|
printf(" fn#%zu", n->type_const.fn);
|
||||||
} else if (t && t->kind == SPL_TYPE_PTR) {
|
// } else if (t && t->kind == SPL_TYPE_PTR) {
|
||||||
printf(" str=\"%s\"", n->type_const.cstr_lit ? n->type_const.cstr_lit : "?");
|
// printf(" str=\"%s\"", n->type_const.cstr_lit ? n->type_const.cstr_lit : "?");
|
||||||
} else if (t && t->kind == SPL_TYPE_INT && t->int_type.bits == 8) {
|
} else if (t && t->kind == SPL_TYPE_INT && t->int_type.bits == 8) {
|
||||||
printf(" char='%c'", n->type_const.ch_lit);
|
printf(" char='%c'", n->type_const.ch_lit);
|
||||||
} else {
|
} else {
|
||||||
@@ -315,12 +315,16 @@ static spl_ir_node_ref_t builder_alloc_node(spl_ir_builder_t *b, spl_ir_kind_t k
|
|||||||
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
||||||
n->kind = kind;
|
n->kind = kind;
|
||||||
n->dbg = b->dbg;
|
n->dbg = b->dbg;
|
||||||
if (b->current_block < vec_size(b->blocks)) {
|
|
||||||
vec_at(b->blocks, b->current_block) = ref;
|
if (b->current_block >= vec_size(b->blocks)) {
|
||||||
} else {
|
|
||||||
Panic("unknown bblock");
|
Panic("unknown bblock");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spl_ir_node_ref_t *slot = &vec_at(b->blocks, b->current_block);
|
||||||
|
if (*slot == 0)
|
||||||
|
*slot = ref;
|
||||||
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,7 +382,7 @@ void spl_ir_builder_fn_end(spl_ir_builder_t *b) {
|
|||||||
target = vec_at(b->blocks, fx->block);
|
target = vec_at(b->blocks, fx->block);
|
||||||
}
|
}
|
||||||
if (target == 0) {
|
if (target == 0) {
|
||||||
Panic("unknown reloc target bblock");
|
Panic("reloc to empty/unknown bblock #%zu", fx->block);
|
||||||
}
|
}
|
||||||
switch (fx->slot) {
|
switch (fx->slot) {
|
||||||
case SPL_IR_FIX_BR_TRUE:
|
case SPL_IR_FIX_BR_TRUE:
|
||||||
@@ -411,6 +415,10 @@ void spl_ir_builder_block_end(spl_ir_builder_t *b) {
|
|||||||
if (!b->terminated) {
|
if (!b->terminated) {
|
||||||
Panic("bblock must be end of terminated");
|
Panic("bblock must be end of terminated");
|
||||||
}
|
}
|
||||||
|
if (b->current_block != 0 && b->current_block < vec_size(b->blocks) &&
|
||||||
|
vec_at(b->blocks, b->current_block) == 0) {
|
||||||
|
Panic("bblock #%zu is empty (no entry node emitted)", b->current_block);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define X(name, kind) \
|
#define X(name, kind) \
|
||||||
@@ -584,7 +592,8 @@ spl_ir_node_ref_t spl_ir_builder_type_const_cstr(spl_ir_builder_t *b, spl_type_i
|
|||||||
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_CONST);
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_TYPE_CONST);
|
||||||
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
spl_ir_node_t *n = spl_ir_node(&b->ir, b->current_fn, ref);
|
||||||
n->type_const.tid = tid;
|
n->type_const.tid = tid;
|
||||||
n->type_const.cstr_lit = val;
|
TODO();
|
||||||
|
// n->type_const.cstr_lit = val;
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -769,7 +778,9 @@ spl_ir_node_ref_t spl_ir_builder_control_ret(spl_ir_builder_t *b, spl_type_id_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
spl_ir_node_ref_t spl_ir_builder_control_unreachable(spl_ir_builder_t *b) {
|
spl_ir_node_ref_t spl_ir_builder_control_unreachable(spl_ir_builder_t *b) {
|
||||||
return builder_alloc_node(b, SPL_IR_CONTROL_UNREACHABLE);
|
spl_ir_node_ref_t ref = builder_alloc_node(b, SPL_IR_CONTROL_UNREACHABLE);
|
||||||
|
b->terminated = true;
|
||||||
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
spl_ir_node_ref_t spl_ir_builder_control_trap(spl_ir_builder_t *b) {
|
spl_ir_node_ref_t spl_ir_builder_control_trap(spl_ir_builder_t *b) {
|
||||||
|
|||||||
+1
-1
@@ -145,7 +145,7 @@ typedef struct {
|
|||||||
void *ptr_lit;
|
void *ptr_lit;
|
||||||
usize int_lit;
|
usize int_lit;
|
||||||
double float_lit;
|
double float_lit;
|
||||||
const char *cstr_lit;
|
// const char *cstr_lit;
|
||||||
char ch_lit;
|
char ch_lit;
|
||||||
spl_ir_func_ref_t fn;
|
spl_ir_func_ref_t fn;
|
||||||
};
|
};
|
||||||
|
|||||||
+992
-52
File diff suppressed because it is too large.
Load diff
@@ -24,6 +24,7 @@ typedef struct {
|
|||||||
void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type);
|
void spl_ir2vm_init(spl_ir2vm_t *ctx, const spl_ir_t *ir, const spl_type_t *type);
|
||||||
void spl_ir2vm_drop(spl_ir2vm_t *ctx);
|
void spl_ir2vm_drop(spl_ir2vm_t *ctx);
|
||||||
|
|
||||||
|
int spl_ir2vm_run_func(spl_ir2vm_t *ctx, spl_ir_func_ref_t ref);
|
||||||
int spl_ir2vm_run(spl_ir2vm_t *ctx);
|
int spl_ir2vm_run(spl_ir2vm_t *ctx);
|
||||||
void spl_ir2vm_dump(spl_ir2vm_t *ctx);
|
void spl_ir2vm_dump(spl_ir2vm_t *ctx);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,266 @@
|
|||||||
|
#include "spl_layout.h"
|
||||||
|
|
||||||
|
static void infos_grow(spl_layout_t *layout, usize n) {
|
||||||
|
while (vec_size(layout->infos) < n) {
|
||||||
|
spl_layout_info_t info = {0};
|
||||||
|
vec_init(info.field_bit_offsets);
|
||||||
|
vec_init(info.field_bit_sizes);
|
||||||
|
vec_push(layout->infos, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static spl_layout_info_t *infos_at(spl_layout_t *layout, spl_type_id_t id) {
|
||||||
|
if (id == 0 || id >= vec_size(layout->infos))
|
||||||
|
return NULL;
|
||||||
|
return &vec_at(layout->infos, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spl_layout_add_scalar(spl_layout_t *layout, usize size, usize abi_align) {
|
||||||
|
spl_layout_scalar_t s = {0};
|
||||||
|
s.size = size;
|
||||||
|
s.abi_align = abi_align;
|
||||||
|
s.pref_align = abi_align;
|
||||||
|
vec_init(s.invalid_values);
|
||||||
|
vec_push(layout->scalars, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spl_layout_add_ptr(spl_layout_t *layout, usize addr_space, usize size, usize align) {
|
||||||
|
spl_layout_ptr_t p = {0};
|
||||||
|
p.add_space = addr_space;
|
||||||
|
p.ptr_size = size;
|
||||||
|
p.ptr_align = align;
|
||||||
|
vec_push(layout->pointers, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spl_layout_init(spl_layout_t *layout, spl_layout_target_t *target) {
|
||||||
|
vec_init(layout->scalars);
|
||||||
|
vec_init(layout->pointers);
|
||||||
|
vec_init(layout->infos);
|
||||||
|
layout->target = target;
|
||||||
|
|
||||||
|
/* 默认聚合策略:按最大字段对齐,不允许重排 */
|
||||||
|
layout->aggregate.allow_field_reordering = false;
|
||||||
|
layout->aggregate.align_rule = ALIGN_MAX;
|
||||||
|
layout->aggregate.fixed_align = 0;
|
||||||
|
|
||||||
|
/* 常见 64 位平台的默认布局。
|
||||||
|
若目标平台不适用,调用者 clear 后自行 add_*。 */
|
||||||
|
spl_layout_add_scalar(layout, 1, 1); /* i8 / u8 / bool */
|
||||||
|
spl_layout_add_scalar(layout, 2, 2); /* i16 / u16 */
|
||||||
|
spl_layout_add_scalar(layout, 4, 4); /* i32 / u32 / f32 */
|
||||||
|
spl_layout_add_scalar(layout, 8, 8); /* i64 / u64 / f64 */
|
||||||
|
|
||||||
|
usize ps = sizeof(void *);
|
||||||
|
spl_layout_add_ptr(layout, 0, ps, ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
void spl_layout_drop(spl_layout_t *layout) {
|
||||||
|
for (usize i = 0; i < vec_size(layout->scalars); ++i)
|
||||||
|
vec_free(vec_at(layout->scalars, i).invalid_values);
|
||||||
|
vec_free(layout->scalars);
|
||||||
|
|
||||||
|
vec_free(layout->pointers);
|
||||||
|
|
||||||
|
for (usize i = 0; i < vec_size(layout->infos); ++i) {
|
||||||
|
vec_free(vec_at(layout->infos, i).field_bit_offsets);
|
||||||
|
vec_free(vec_at(layout->infos, i).field_bit_sizes);
|
||||||
|
}
|
||||||
|
vec_free(layout->infos);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const spl_layout_scalar_t *scalar_for_size(spl_layout_t *layout, usize size_bytes) {
|
||||||
|
for (usize i = 0; i < vec_size(layout->scalars); ++i) {
|
||||||
|
spl_layout_scalar_t *s = &vec_at(layout->scalars, i);
|
||||||
|
if (s->size == size_bytes)
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const spl_layout_ptr_t *default_ptr(spl_layout_t *layout) {
|
||||||
|
if (vec_size(layout->pointers) == 0)
|
||||||
|
return NULL;
|
||||||
|
return &vec_at(layout->pointers, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool layout_scalar(spl_layout_t *layout, spl_type_node_t *tn, spl_layout_info_t *out) {
|
||||||
|
usize size_bits = 0;
|
||||||
|
switch (tn->kind) {
|
||||||
|
case SPL_TYPE_INT:
|
||||||
|
if (tn->int_type.bits == 0)
|
||||||
|
return false; /* comptime_int 未落地 */
|
||||||
|
size_bits = tn->int_type.bits;
|
||||||
|
break;
|
||||||
|
case SPL_TYPE_FLOAT:
|
||||||
|
if (tn->float_type.bits == 0)
|
||||||
|
return false; /* comptime_float 未落地 */
|
||||||
|
size_bits = tn->float_type.bits;
|
||||||
|
break;
|
||||||
|
case SPL_TYPE_BOOL:
|
||||||
|
size_bits = 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
usize size_bytes = (size_bits + 7) / 8;
|
||||||
|
const spl_layout_scalar_t *sl = scalar_for_size(layout, size_bytes);
|
||||||
|
if (!sl)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
out->size_bits = sl->size * 8;
|
||||||
|
out->align_bits = sl->abi_align * 8;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool layout_ptr(spl_layout_t *layout, spl_layout_info_t *out) {
|
||||||
|
const spl_layout_ptr_t *pl = default_ptr(layout);
|
||||||
|
if (!pl)
|
||||||
|
return false;
|
||||||
|
out->size_bits = pl->ptr_size * 8;
|
||||||
|
out->align_bits = pl->ptr_align * 8;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static usize round_up_bits(usize x, usize align_bits) {
|
||||||
|
if (align_bits <= 1)
|
||||||
|
return x;
|
||||||
|
usize a = align_bits;
|
||||||
|
return (x + a - 1) / a * a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool layout_agg(spl_layout_t *layout, spl_type_node_t *tn, spl_layout_info_t *out) {
|
||||||
|
usize n = vec_size(tn->agg_type.variants);
|
||||||
|
if (n == 0) {
|
||||||
|
out->size_bits = 0;
|
||||||
|
out->align_bits = 8;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
usize max_align_bits = 8;
|
||||||
|
usize offset_bits = 0;
|
||||||
|
bool is_union = (tn->kind == SPL_TYPE_UNION);
|
||||||
|
|
||||||
|
for (usize i = 0; i < n; ++i) {
|
||||||
|
spl_type_member_t *m = &vec_at(tn->agg_type.variants, i);
|
||||||
|
spl_layout_info_t *fi = infos_at(layout, m->type_id);
|
||||||
|
if (!fi || !fi->resolved)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
usize field_align_bits = fi->align_bits ? fi->align_bits : 8;
|
||||||
|
|
||||||
|
if (is_union) {
|
||||||
|
vec_push(out->field_bit_offsets, 0);
|
||||||
|
vec_push(out->field_bit_sizes, fi->size_bits);
|
||||||
|
if (fi->size_bits > out->size_bits)
|
||||||
|
out->size_bits = fi->size_bits;
|
||||||
|
} else {
|
||||||
|
offset_bits = round_up_bits(offset_bits, field_align_bits);
|
||||||
|
vec_push(out->field_bit_offsets, offset_bits);
|
||||||
|
vec_push(out->field_bit_sizes, fi->size_bits);
|
||||||
|
offset_bits += fi->size_bits;
|
||||||
|
}
|
||||||
|
if (field_align_bits > max_align_bits)
|
||||||
|
max_align_bits = field_align_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 聚合对齐策略 */
|
||||||
|
usize final_align_bits = max_align_bits;
|
||||||
|
if (layout->aggregate.align_rule == ALIGN_FIXED) {
|
||||||
|
final_align_bits = layout->aggregate.fixed_align * 8;
|
||||||
|
} else if (layout->aggregate.align_rule == ALIGN_MAX_WITH_MIN) {
|
||||||
|
usize min_bits = layout->aggregate.fixed_align * 8;
|
||||||
|
if (final_align_bits < min_bits)
|
||||||
|
final_align_bits = min_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_union)
|
||||||
|
out->size_bits = round_up_bits(out->size_bits, final_align_bits);
|
||||||
|
else
|
||||||
|
out->size_bits = round_up_bits(offset_bits, final_align_bits);
|
||||||
|
out->align_bits = final_align_bits;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resolve_type(spl_layout_t *layout, spl_type_t *type, spl_type_id_t id) {
|
||||||
|
spl_layout_info_t *info = infos_at(layout, id);
|
||||||
|
if (!info || info->resolved)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spl_type_node_t *tn = spl_type_node(type, id);
|
||||||
|
if (!tn)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* 先标记已解析:自引用类型(通过 ptr)不会无限递归,
|
||||||
|
但保持防御性写法。 */
|
||||||
|
info->resolved = true;
|
||||||
|
|
||||||
|
switch (tn->kind) {
|
||||||
|
case SPL_TYPE_ERROR:
|
||||||
|
case SPL_TYPE_INFER:
|
||||||
|
case SPL_TYPE_FORALL:
|
||||||
|
case SPL_TYPE_EXISTS:
|
||||||
|
case SPL_TYPE_NEVER:
|
||||||
|
case SPL_TYPE_UNIT:
|
||||||
|
info->size_bits = 0;
|
||||||
|
info->align_bits = 8;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case SPL_TYPE_ANY:
|
||||||
|
/* 顶层类型:stage1 按不透明指针处理 */
|
||||||
|
layout_ptr(layout, info);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case SPL_TYPE_BOOL:
|
||||||
|
case SPL_TYPE_INT:
|
||||||
|
case SPL_TYPE_FLOAT:
|
||||||
|
layout_scalar(layout, tn, info);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case SPL_TYPE_PTR:
|
||||||
|
layout_ptr(layout, info);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case SPL_TYPE_ARRAY: {
|
||||||
|
resolve_type(layout, type, tn->array_type.element);
|
||||||
|
spl_layout_info_t *elem = infos_at(layout, tn->array_type.element);
|
||||||
|
if (!elem || !elem->resolved)
|
||||||
|
return;
|
||||||
|
info->size_bits = elem->size_bits * tn->array_type.len;
|
||||||
|
info->align_bits = elem->align_bits;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SPL_TYPE_STRUCT:
|
||||||
|
case SPL_TYPE_UNION:
|
||||||
|
case SPL_TYPE_ENUM:
|
||||||
|
case SPL_TYPE_SHAPE: {
|
||||||
|
for (usize i = 0; i < vec_size(tn->agg_type.variants); ++i) {
|
||||||
|
spl_type_member_t *m = &vec_at(tn->agg_type.variants, i);
|
||||||
|
resolve_type(layout, type, m->type_id);
|
||||||
|
}
|
||||||
|
layout_agg(layout, tn, info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SPL_TYPE_FN:
|
||||||
|
/* 函数类型按函数指针布局 */
|
||||||
|
for (usize i = 0; i < vec_size(tn->fn_type.params); ++i)
|
||||||
|
resolve_type(layout, type, vec_at(tn->fn_type.params, i));
|
||||||
|
resolve_type(layout, type, tn->fn_type.ret);
|
||||||
|
layout_ptr(layout, info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void spl_layout_resolve(spl_layout_t *layout, spl_type_t *type) {
|
||||||
|
infos_grow(layout, vec_size(type->type_table));
|
||||||
|
for (usize i = 1; i < vec_size(type->type_table); ++i)
|
||||||
|
resolve_type(layout, type, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
const spl_layout_info_t *spl_layout_info_of(spl_layout_t *layout, spl_type_id_t id) {
|
||||||
|
spl_layout_info_t *info = infos_at(layout, id);
|
||||||
|
if (!info || !info->resolved)
|
||||||
|
return NULL;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#ifndef __SPL_LAYOUT_H__
|
||||||
|
#define __SPL_LAYOUT_H__
|
||||||
|
|
||||||
|
#include "spl_type.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
usize size;
|
||||||
|
usize abi_align;
|
||||||
|
usize pref_align;
|
||||||
|
VEC(usize) invalid_values;
|
||||||
|
} spl_layout_scalar_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
usize add_space;
|
||||||
|
usize ptr_size;
|
||||||
|
usize ptr_align;
|
||||||
|
} spl_layout_ptr_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool allow_field_reordering;
|
||||||
|
enum { ALIGN_MAX, ALIGN_FIXED, ALIGN_MAX_WITH_MIN } align_rule;
|
||||||
|
usize fixed_align;
|
||||||
|
} spl_layout_agg_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
usize size_bits;
|
||||||
|
usize align_bits;
|
||||||
|
VEC(usize) field_bit_offsets;
|
||||||
|
VEC(usize) field_bit_sizes;
|
||||||
|
bool resolved;
|
||||||
|
} spl_layout_info_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum { SPL_BIG_ENDIAN, SPL_LITTLE_ENDIAN } endian; // TODO 更多位存储方式
|
||||||
|
|
||||||
|
} spl_layout_target_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VEC(spl_layout_scalar_t) scalars;
|
||||||
|
VEC(spl_layout_ptr_t) pointers;
|
||||||
|
spl_layout_agg_t aggregate;
|
||||||
|
VEC(spl_layout_info_t) infos;
|
||||||
|
spl_layout_target_t *target;
|
||||||
|
} spl_layout_t;
|
||||||
|
|
||||||
|
void spl_layout_init(spl_layout_t *layout, spl_layout_target_t *target);
|
||||||
|
void spl_layout_drop(spl_layout_t *layout);
|
||||||
|
|
||||||
|
void spl_layout_resolve(spl_layout_t *layout, spl_type_t *type);
|
||||||
|
|
||||||
|
void spl_layout_add_scalar(spl_layout_t *layout, usize size, usize abi_align);
|
||||||
|
void spl_layout_add_ptr(spl_layout_t *layout, usize addr_space, usize size, usize align);
|
||||||
|
|
||||||
|
const spl_layout_info_t *spl_layout_info_of(spl_layout_t *layout, spl_type_id_t id);
|
||||||
|
|
||||||
|
#endif /* __SPL_LAYOUT_H__ */
|
||||||
+1266
-85
File diff suppressed because it is too large.
Load diff
+17
-17
@@ -129,25 +129,25 @@ static int compile_spl(const char *src, const char *fname, const char *outpath,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// spl_ir2vm_t ir2vm;
|
spl_ir2vm_t ir2vm;
|
||||||
// spl_ir2vm_init(&ir2vm, &a2ir.ir->ir, sema.type);
|
spl_ir2vm_init(&ir2vm, &a2ir.ir->ir, sema.type);
|
||||||
// int rc = spl_ir2vm_run(&ir2vm);
|
int rc = spl_ir2vm_run(&ir2vm);
|
||||||
// if (rc != 0) {
|
if (rc != 0) {
|
||||||
// printf("ir2vm error %d", rc);
|
printf("ir2vm error %d", rc);
|
||||||
// return rc;
|
return rc;
|
||||||
// }
|
}
|
||||||
// if (dump == DUMP_VM) {
|
if (dump == DUMP_VM) {
|
||||||
// spl_prog_dump(&ir2vm.prog);
|
spl_prog_dump(&ir2vm.prog);
|
||||||
// // memory leak
|
// memory leak
|
||||||
// return 0;
|
return 0;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// spl_prog_store_to_file(outpath, &ir2vm.prog);
|
spl_prog_store_to_file(outpath, &ir2vm.prog);
|
||||||
|
|
||||||
// spl_ir2vm_drop(&ir2vm);
|
spl_ir2vm_drop(&ir2vm);
|
||||||
// spl_ast2ir_drop(&a2ir);
|
spl_ast2ir_drop(&a2ir);
|
||||||
// spl_sema_drop(&sema);
|
spl_sema_drop(&sema);
|
||||||
// spl_ast_drop(&ast);
|
spl_ast_drop(&ast);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user