Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb0ff9b663 | ||
|
|
70ac7380e9 |
No files matched your search
@@ -30,6 +30,7 @@ static const char *splc0_srcs[] = {
|
||||
"stage1/spl_parser.c",
|
||||
"stage1/spl_dumptree.c",
|
||||
"stage1/spl_type.c",
|
||||
"stage1/spl_fold.c",
|
||||
"stage1/spl_lang_type.c",
|
||||
"stage1/spl_attr.c",
|
||||
"stage1/spl_scope.c",
|
||||
@@ -78,6 +79,16 @@ static const char *obj_path(const char *src) {
|
||||
return out;
|
||||
}
|
||||
|
||||
// Windows 上 clang/gcc 会输出 build/foo.exe;这里统一带上后缀,
|
||||
// 否则 nob_needs_rebuild 找不到输出会每次重新链接。
|
||||
static const char *exe_path(const char *name) {
|
||||
#ifdef _WIN32
|
||||
return nob_temp_sprintf(BUILD_FOLDER "%s.exe", name);
|
||||
#else
|
||||
return nob_temp_sprintf(BUILD_FOLDER "%s", name);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool sync_cflags_stamp(void) {
|
||||
Nob_String_View cflags = nob_sv_from_cstr(CFLAGS_STR);
|
||||
Nob_String_Builder old = {0};
|
||||
@@ -95,10 +106,39 @@ static bool sync_cflags_stamp(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 头文件依赖:收集 stage0/stage1 下的所有 .h,作为每个 object 的输入。
|
||||
// nob 不解析 #include,这里用“任一头文件变化则重建全部 object”的保守策略,
|
||||
// 避免头文件改动后各 .o 结构体布局/常量不一致导致的隐蔽错误。
|
||||
static Nob_Files g_headers = {0};
|
||||
|
||||
static bool collect_header_entry(Nob_Walk_Entry entry) {
|
||||
if (entry.type != NOB_FILE_REGULAR)
|
||||
return true;
|
||||
const char *dot = strrchr(entry.path, '.');
|
||||
if (!dot || strcmp(dot, ".h") != 0)
|
||||
return true;
|
||||
if (strstr(entry.path, ".old") != NULL)
|
||||
return true;
|
||||
da_append(&g_headers, nob_temp_strdup(entry.path));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool collect_headers(void) {
|
||||
if (g_headers.count > 0)
|
||||
return true;
|
||||
if (!nob_walk_dir("stage0", collect_header_entry))
|
||||
return false;
|
||||
if (!nob_walk_dir("stage1", collect_header_entry))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool prepare_build(void) {
|
||||
if (!nob_mkdir_if_not_exists(BUILD_FOLDER))
|
||||
return false;
|
||||
return sync_cflags_stamp();
|
||||
if (!sync_cflags_stamp())
|
||||
return false;
|
||||
return collect_headers();
|
||||
}
|
||||
|
||||
static bool build_object(const char *src) {
|
||||
@@ -108,8 +148,16 @@ static bool build_object(const char *src) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *inputs[] = {src, CFLAGS_STAMP};
|
||||
int needs = nob_needs_rebuild(obj, inputs, NOB_ARRAY_LEN(inputs));
|
||||
// 依赖:源文件 + 所有头文件 + cflags 戳。
|
||||
size_t ninputs = g_headers.count + 2;
|
||||
const char **inputs = (const char **)nob_temp_alloc(sizeof(const char *) * ninputs);
|
||||
inputs[0] = src;
|
||||
for (size_t i = 0; i < g_headers.count; ++i) {
|
||||
inputs[i + 1] = g_headers.items[i];
|
||||
}
|
||||
inputs[ninputs - 1] = CFLAGS_STAMP;
|
||||
|
||||
int needs = nob_needs_rebuild(obj, inputs, ninputs);
|
||||
if (needs < 0)
|
||||
return false;
|
||||
if (needs == 0)
|
||||
@@ -125,7 +173,7 @@ static bool build_object(const char *src) {
|
||||
}
|
||||
|
||||
static bool link_exe(const target_t *target) {
|
||||
const char *exe = nob_temp_sprintf(BUILD_FOLDER "%s", target->name);
|
||||
const char *exe = exe_path(target->name);
|
||||
const char **objs = (const char **)nob_temp_alloc(sizeof(const char *) * target->srcs_count);
|
||||
for (size_t i = 0; i < target->srcs_count; ++i) {
|
||||
objs[i] = obj_path(target->srcs[i]);
|
||||
@@ -225,7 +273,7 @@ static bool test_once(const char *fname, void *user_data) {
|
||||
}
|
||||
cmd.count = 0;
|
||||
|
||||
nob_cmd_append(&cmd, nob_temp_sprintf(BUILD_FOLDER "%s", compiler_path));
|
||||
nob_cmd_append(&cmd, exe_path(compiler_path));
|
||||
nob_cmd_append(&cmd, fname, target_sir);
|
||||
if (!nob_cmd_run(&cmd)) {
|
||||
return false;
|
||||
@@ -235,7 +283,7 @@ static bool test_once(const char *fname, void *user_data) {
|
||||
return 1;
|
||||
}
|
||||
cmd.count = 0;
|
||||
nob_cmd_append(&cmd, nob_temp_sprintf(BUILD_FOLDER "%s", cli_path));
|
||||
nob_cmd_append(&cmd, exe_path(cli_path));
|
||||
nob_cmd_append(&cmd, target_sir);
|
||||
// nob_cmd_run(&cmd);
|
||||
|
||||
@@ -267,7 +315,7 @@ static bool test_once_with_dump(const char *fname, void *user_data) {
|
||||
if (!build_target(target_name))
|
||||
return 1;
|
||||
Nob_Cmd cmd = {0};
|
||||
nob_cmd_append(&cmd, nob_temp_sprintf(BUILD_FOLDER "%s", target_name));
|
||||
nob_cmd_append(&cmd, exe_path(target_name));
|
||||
nob_cmd_append(&cmd, "--dump", (char *)user_data, fname, BUILD_FOLDER "t.sir");
|
||||
return nob_cmd_run(&cmd);
|
||||
}
|
||||
@@ -402,7 +450,7 @@ int main(int argc, char **argv) {
|
||||
if (!build_target(target_name))
|
||||
return 1;
|
||||
Nob_Cmd cmd = {0};
|
||||
nob_cmd_append(&cmd, nob_temp_sprintf(BUILD_FOLDER "%s", target_name));
|
||||
nob_cmd_append(&cmd, exe_path(target_name));
|
||||
while (argc > 0) {
|
||||
nob_cmd_append(&cmd, nob_shift(argv, argc));
|
||||
}
|
||||
|
||||
@@ -202,33 +202,6 @@ static inline usize map_hash_str(const char *s) {
|
||||
_found; \
|
||||
}))
|
||||
|
||||
/**
|
||||
* 查询(续探):首次调用前将 *in_out_idx 置为 (usize)-1,
|
||||
* 则从键自身的 hash 桶开始查找;命中后 *out_val 被赋值、返回 1,
|
||||
* 且 *in_out_idx 更新为命中槽位,下次调用从该槽的下一个继续探测(碰撞续探)。
|
||||
* 扫描到空槽返回 0。用于 key 碰撞后需要回表二次比较的场景。
|
||||
*/
|
||||
#define map_get_continue(map, _key, out_val, in_out_idx) \
|
||||
(({ \
|
||||
int _found = 0; \
|
||||
if ((map).cap > 0) { \
|
||||
usize _mask = (map).cap - 1; \
|
||||
usize _idx = (*(in_out_idx) == (usize) - 1) ? (map).hash(_key) & _mask \
|
||||
: (*(in_out_idx) + 1) & _mask; \
|
||||
while ((map).data[_idx].state != __MAP_SLOT_EMPTY) { \
|
||||
if ((map).data[_idx].state == __MAP_SLOT_OCCUPIED && \
|
||||
(map).cmp((map).data[_idx].key, _key) == 0) { \
|
||||
*out_val = (map).data[_idx].val; \
|
||||
*(in_out_idx) = _idx; \
|
||||
_found = 1; \
|
||||
break; \
|
||||
} \
|
||||
_idx = (_idx + 1) & _mask; \
|
||||
} \
|
||||
} \
|
||||
_found; \
|
||||
}))
|
||||
|
||||
/**
|
||||
* 删除指定键
|
||||
*/
|
||||
|
||||
+3
-1
@@ -1917,7 +1917,9 @@ static spl_ir_node_ref_t emit_implicit_cast(spl_ast2ir_t *a, spl_ast_node_t *n,
|
||||
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_PTR)
|
||||
bool fs_ptr_like = fs->kind == SPL_TYPE_PTR || fs->kind == SPL_TYPE_FN;
|
||||
bool ts_ptr_like = ts->kind == SPL_TYPE_PTR || ts->kind == SPL_TYPE_FN;
|
||||
if (fs_ptr_like && ts_ptr_like)
|
||||
return v;
|
||||
|
||||
if (fs->kind == SPL_TYPE_PTR && ts->kind == SPL_TYPE_INT)
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "spl_fold.h"
|
||||
|
||||
static usize spl_fold_bucket_hash(usize k) { return MAP_HASH_INT(k); }
|
||||
static int spl_fold_bucket_cmp(usize a, usize b) { return MAP_CMP_INT(a, b); }
|
||||
|
||||
void spl_fold_init(spl_fold_t *fold, void *ctx, spl_fold_eq_fn eq, spl_fold_next_fn next,
|
||||
spl_fold_set_next_fn set_next) {
|
||||
map_init(fold->buckets, spl_fold_bucket_hash, spl_fold_bucket_cmp);
|
||||
fold->ctx = ctx;
|
||||
fold->eq = eq;
|
||||
fold->next = next;
|
||||
fold->set_next = set_next;
|
||||
}
|
||||
|
||||
void spl_fold_drop(spl_fold_t *fold) { map_free(fold->buckets); }
|
||||
|
||||
spl_fold_id_t spl_fold_find(const spl_fold_t *fold, usize hash, const void *probe) {
|
||||
spl_fold_id_t cur = 0;
|
||||
if (!map_get(fold->buckets, hash, &cur))
|
||||
return 0;
|
||||
while (cur) {
|
||||
if (fold->eq(fold->ctx, cur, probe))
|
||||
return cur;
|
||||
cur = fold->next(fold->ctx, cur);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spl_fold_insert(spl_fold_t *fold, usize hash, spl_fold_id_t id) {
|
||||
spl_fold_id_t head = 0;
|
||||
map_get(fold->buckets, hash, &head);
|
||||
fold->set_next(fold->ctx, id, head);
|
||||
map_put(fold->buckets, hash, id);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef __SPL_FOLD_H__
|
||||
#define __SPL_FOLD_H__
|
||||
|
||||
#include "../stage0/include/utils.h"
|
||||
|
||||
/* 通用 intrusive 哈希集合,对应 LLVM FoldingSet 的桶链部分。
|
||||
- 节点表由调用方持有,节点自带 next 字段;
|
||||
- hash 只用于选择桶(本实现以完整 hash 值作桶 map 的 key),
|
||||
相等始终由 eq 回调做结构比较;
|
||||
- 只增不删,适合类型 intern。 */
|
||||
typedef usize spl_fold_id_t;
|
||||
|
||||
/* 相等返回非零;probe 指向调用方的临时(尚未入表)节点。 */
|
||||
typedef int (*spl_fold_eq_fn)(void *ctx, spl_fold_id_t node, const void *probe);
|
||||
typedef spl_fold_id_t (*spl_fold_next_fn)(void *ctx, spl_fold_id_t node);
|
||||
typedef void (*spl_fold_set_next_fn)(void *ctx, spl_fold_id_t node, spl_fold_id_t next);
|
||||
|
||||
typedef struct {
|
||||
MAP(usize, spl_fold_id_t) buckets;
|
||||
void *ctx;
|
||||
spl_fold_eq_fn eq;
|
||||
spl_fold_next_fn next;
|
||||
spl_fold_set_next_fn set_next;
|
||||
} spl_fold_t;
|
||||
|
||||
void spl_fold_init(spl_fold_t *fold, void *ctx, spl_fold_eq_fn eq, spl_fold_next_fn next,
|
||||
spl_fold_set_next_fn set_next);
|
||||
void spl_fold_drop(spl_fold_t *fold);
|
||||
|
||||
/* 命中返回已存在的 id,否则返回 0。 */
|
||||
spl_fold_id_t spl_fold_find(const spl_fold_t *fold, usize hash, const void *probe);
|
||||
|
||||
/* 把已分配 id 的节点挂到对应桶头。 */
|
||||
void spl_fold_insert(spl_fold_t *fold, usize hash, spl_fold_id_t id);
|
||||
|
||||
#endif /* __SPL_FOLD_H__ */
|
||||
@@ -1182,6 +1182,10 @@ int spl_ir2vm_run(spl_ir2vm_t *ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
/* 保留 insn 0 作为哨兵:确保真实函数入口地址非零,
|
||||
从而 0 可唯一表示 null 函数指针(函数指针与 null 比较)。 */
|
||||
spl_prog_add_instr(&ctx->prog, SPL_HALT, SPL_VOID, 0);
|
||||
|
||||
/* Pass 2:翻译非 extern 的函数 */
|
||||
usize *fid_ip = calloc(n, sizeof(usize));
|
||||
fix_vec_t all_fixups;
|
||||
|
||||
+59
-26
@@ -1,36 +1,37 @@
|
||||
#include "spl_lang_type.h"
|
||||
|
||||
static usize spl_lang_type_hash(spl_lang_type_node_t n) {
|
||||
usize hash = (usize)n.kind * 131 + n.ir_type_id;
|
||||
usize hash = spl_hash_seed();
|
||||
hash = spl_hash_mix(hash, (usize)n.kind);
|
||||
hash = spl_hash_mix(hash, n.ir_type_id);
|
||||
switch (n.kind) {
|
||||
case SPL_LANG_TYPE_PTR:
|
||||
case SPL_LANG_TYPE_SLICE:
|
||||
case SPL_LANG_TYPE_RANGE:
|
||||
hash += n.extra.elem;
|
||||
hash = spl_hash_mix(hash, n.extra.elem);
|
||||
break;
|
||||
case SPL_LANG_TYPE_TUPLE:
|
||||
hash = spl_hash_mix(hash, vec_size(n.extra.elems));
|
||||
for (usize i = 0; i < vec_size(n.extra.elems); i++) {
|
||||
hash += vec_at(n.extra.elems, i);
|
||||
hash = spl_hash_mix(hash, vec_at(n.extra.elems, i));
|
||||
}
|
||||
break;
|
||||
case SPL_LANG_TYPE_FN:
|
||||
hash += n.extra.fn.ret;
|
||||
hash = spl_hash_mix(hash, n.extra.fn.ret);
|
||||
hash = spl_hash_mix(hash, vec_size(n.extra.fn.params));
|
||||
for (usize i = 0; i < vec_size(n.extra.fn.params); i++) {
|
||||
hash += vec_at(n.extra.fn.params, i);
|
||||
hash = spl_hash_mix(hash, vec_at(n.extra.fn.params, i));
|
||||
}
|
||||
break;
|
||||
case SPL_LANG_TYPE_STRUCT:
|
||||
case SPL_LANG_TYPE_UNION:
|
||||
case SPL_LANG_TYPE_ENUM:
|
||||
case SPL_LANG_TYPE_SHAPE:
|
||||
hash = spl_hash_mix(hash, vec_size(n.methods));
|
||||
for (usize i = 0; i < vec_size(n.methods); i++) {
|
||||
spl_lang_method_t *m = &vec_at(n.methods, i);
|
||||
hash += m->def_id * 31;
|
||||
if (m->name) {
|
||||
const char *s = m->name;
|
||||
while (*s)
|
||||
hash = hash * 31 + (usize)(*s++);
|
||||
}
|
||||
hash = spl_hash_mix(hash, m->def_id);
|
||||
hash = spl_hash_mix_str(hash, m->name);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -87,9 +88,6 @@ static int spl_lang_type_eq(spl_lang_type_node_t n1, spl_lang_type_node_t n2) {
|
||||
}
|
||||
}
|
||||
|
||||
static usize spl_lang_map_hash(usize k) { return MAP_HASH_INT(k); }
|
||||
static int spl_lang_map_cmp(usize a, usize b) { return MAP_CMP_INT(a, b); }
|
||||
|
||||
static void spl_lang_node_free_extra(spl_lang_type_node_t *n) {
|
||||
switch (n->kind) {
|
||||
case SPL_LANG_TYPE_TUPLE:
|
||||
@@ -109,20 +107,35 @@ static void spl_lang_node_free_extra(spl_lang_type_node_t *n) {
|
||||
}
|
||||
}
|
||||
|
||||
/* spl_fold 回调:只在链内做结构比较(同桶已保证 hash 相同)。 */
|
||||
static int spl_lang_fold_eq(void *ctx, spl_fold_id_t node, const void *probe) {
|
||||
spl_lang_type_t *type = (spl_lang_type_t *)ctx;
|
||||
return spl_lang_type_eq(vec_at(type->lang_table, node),
|
||||
*(const spl_lang_type_node_t *)probe) == 0;
|
||||
}
|
||||
|
||||
static spl_fold_id_t spl_lang_fold_next(void *ctx, spl_fold_id_t node) {
|
||||
spl_lang_type_t *type = (spl_lang_type_t *)ctx;
|
||||
return vec_at(type->lang_table, node).hash_next;
|
||||
}
|
||||
|
||||
static void spl_lang_fold_set_next(void *ctx, spl_fold_id_t node, spl_fold_id_t next) {
|
||||
spl_lang_type_t *type = (spl_lang_type_t *)ctx;
|
||||
vec_at(type->lang_table, node).hash_next = next;
|
||||
}
|
||||
|
||||
spl_lang_type_id_t spl_lang_node_push(spl_lang_type_t *type, spl_lang_type_node_t *node) {
|
||||
usize hash = spl_lang_type_hash(*node);
|
||||
usize idx = (usize)-1;
|
||||
spl_lang_type_id_t cand = 0;
|
||||
while (map_get_continue(type->lang_map, hash, &cand, &idx)) {
|
||||
spl_lang_type_node_t *existing = &vec_at(type->lang_table, cand);
|
||||
if (spl_lang_type_eq(*existing, *node) == 0) {
|
||||
spl_lang_node_free_extra(node);
|
||||
return cand;
|
||||
}
|
||||
|
||||
spl_lang_type_id_t existing = spl_fold_find(&type->lang_fold, hash, node);
|
||||
if (existing) {
|
||||
spl_lang_node_free_extra(node);
|
||||
return existing;
|
||||
}
|
||||
|
||||
spl_lang_type_id_t id = vec_size(type->lang_table);
|
||||
vec_push(type->lang_table, *node);
|
||||
map_put_new(type->lang_map, hash, id);
|
||||
spl_fold_insert(&type->lang_fold, hash, id);
|
||||
node->kind = SPL_LANG_TYPE_ERROR;
|
||||
return id;
|
||||
}
|
||||
@@ -133,7 +146,8 @@ void spl_lang_type_init(spl_lang_type_t *type) {
|
||||
vec_init(type->lang_table);
|
||||
spl_lang_type_node_t lang_node = {0};
|
||||
vec_push(type->lang_table, lang_node);
|
||||
map_init(type->lang_map, spl_lang_map_hash, spl_lang_map_cmp);
|
||||
spl_fold_init(&type->lang_fold, type, spl_lang_fold_eq, spl_lang_fold_next,
|
||||
spl_lang_fold_set_next);
|
||||
|
||||
vec_init(type->def_table);
|
||||
vec_push(type->def_table, (spl_def_node_t){0});
|
||||
@@ -144,7 +158,7 @@ void spl_lang_type_drop(spl_lang_type_t *type) {
|
||||
spl_lang_type_node_t *n = &vec_at(type->lang_table, i);
|
||||
spl_lang_node_free_extra(n);
|
||||
}
|
||||
map_free(type->lang_map);
|
||||
spl_fold_drop(&type->lang_fold);
|
||||
vec_free(type->lang_table);
|
||||
|
||||
vec_free(type->def_table);
|
||||
@@ -182,7 +196,7 @@ void spl_lang_define_ir(spl_lang_type_t *type, spl_type_id_t id, spl_type_node_t
|
||||
return;
|
||||
spl_type_node_t *slot = &vec_at(type->ir.type_table, id);
|
||||
/* slot 原是空 ERROR 节点,无 vec 字段可释放。node 的 vec 字段 move 进 slot。
|
||||
占位 id 不写 type_map,不参与 hash-consing。 */
|
||||
占位 id 不写 type_fold,不参与 hash-consing。 */
|
||||
*slot = *node;
|
||||
node->kind = SPL_TYPE_ERROR;
|
||||
}
|
||||
@@ -482,6 +496,13 @@ bool spl_lang_type_is_subtype(const spl_lang_type_t *type, spl_lang_type_id_t su
|
||||
return ir_sub->float_type.bits == 0;
|
||||
}
|
||||
|
||||
/* null(*never)可隐式转换为函数指针:函数值按指针布局,可空。 */
|
||||
if (nsuper->kind == SPL_LANG_TYPE_FN && nsub->kind == SPL_LANG_TYPE_PTR) {
|
||||
spl_lang_type_node_t *sub_elem = spl_lang_type_node(type, nsub->extra.elem);
|
||||
if (sub_elem && sub_elem->kind == SPL_LANG_TYPE_NEVER)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (nsub->kind == SPL_LANG_TYPE_PTR && nsuper->kind == SPL_LANG_TYPE_PTR) {
|
||||
if (nsub->extra.elem == nsuper->extra.elem)
|
||||
return true;
|
||||
@@ -568,6 +589,18 @@ spl_lang_type_id_t spl_lang_type_join(const spl_lang_type_t *type, spl_lang_type
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 函数指针可空:fn 与 null(*never)求交得到 fn。 */
|
||||
if (na->kind == SPL_LANG_TYPE_FN && nb->kind == SPL_LANG_TYPE_PTR) {
|
||||
spl_lang_type_node_t *eb = spl_lang_type_node(type, nb->extra.elem);
|
||||
if (eb && eb->kind == SPL_LANG_TYPE_NEVER)
|
||||
return a;
|
||||
}
|
||||
if (na->kind == SPL_LANG_TYPE_PTR && nb->kind == SPL_LANG_TYPE_FN) {
|
||||
spl_lang_type_node_t *ea = spl_lang_type_node(type, na->extra.elem);
|
||||
if (ea && ea->kind == SPL_LANG_TYPE_NEVER)
|
||||
return b;
|
||||
}
|
||||
|
||||
if (na->kind == SPL_LANG_TYPE_PTR && nb->kind == SPL_LANG_TYPE_PTR) {
|
||||
if (na->extra.elem == nb->extra.elem)
|
||||
return a;
|
||||
|
||||
@@ -51,9 +51,9 @@ typedef struct {
|
||||
spl_lang_type_id_t ret;
|
||||
} fn;
|
||||
} extra;
|
||||
usize hash_next; /* 同 hash 桶内下一个类型 id;0 表示链尾。不参与相等比较。 */
|
||||
} spl_lang_type_node_t;
|
||||
typedef VEC(spl_lang_type_node_t) spl_lang_type_vec_t;
|
||||
typedef MAP(usize, spl_lang_type_id_t) spl_lang_type_map_t;
|
||||
|
||||
typedef enum {
|
||||
SPL_DEF_ERROR,
|
||||
@@ -91,7 +91,7 @@ typedef VEC(spl_def_node_t) spl_def_node_vec_t;
|
||||
typedef struct {
|
||||
spl_type_t ir;
|
||||
spl_lang_type_vec_t lang_table;
|
||||
spl_lang_type_map_t lang_map;
|
||||
spl_fold_t lang_fold;
|
||||
spl_def_node_vec_t def_table;
|
||||
} spl_lang_type_t;
|
||||
|
||||
@@ -105,7 +105,7 @@ spl_type_id_t spl_lang_type_get_ir_type(spl_lang_type_t *type, spl_lang_type_id_
|
||||
|
||||
/* 前向引用支持:reserve 一个 type_table 空槽位(kind=ERROR)作为身份锚点,
|
||||
让 *Node / []Node 这类成员能拿到稳定 pointee;成员解析完后再调 define
|
||||
把真实内容填进去。占位槽位**不写 type_map**,不参与 hash-consing——
|
||||
把真实内容填进去。占位槽位**不写 type_fold**,不参与 hash-consing——
|
||||
后续相同形状的类型走 spl_type_node_push 会生成独立 id,语义等价。 */
|
||||
spl_type_id_t spl_lang_reserve_ir(spl_lang_type_t *type);
|
||||
void spl_lang_define_ir(spl_lang_type_t *type, spl_type_id_t id, spl_type_node_t *node);
|
||||
|
||||
@@ -1775,6 +1775,16 @@ static spl_lang_type_id_t sema_infer(spl_sema_t *sema, spl_ast_node_ref_t ref) {
|
||||
return bt;
|
||||
}
|
||||
case SPL_UNARY_OP_ADDRESS: {
|
||||
spl_ast_node_t *operand = spl_ast_node(sema->ast, n->unary.operand);
|
||||
if (operand && operand->kind == SPL_AST_EXPR_IDENT) {
|
||||
spl_def_node_t *def = spl_def_node(sema->type, operand->resolved_def_id);
|
||||
if (def && def->kind == SPL_DEF_FN) {
|
||||
spl_diag_error(sema->diag, SPL_DIAG_KIND_TYPE_MISMATCH, &n->dbg,
|
||||
"cannot take address of a function: the function name "
|
||||
"itself is a function pointer");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
spl_lang_type_id_t p = spl_lang_make_ptr(sema->type, op);
|
||||
n->resolved_lang_tid = p;
|
||||
return p;
|
||||
|
||||
+44
-31
@@ -1,7 +1,8 @@
|
||||
#include "spl_type.h"
|
||||
|
||||
static usize spl_type_hash(spl_type_node_t n) {
|
||||
usize hash = (usize)n.kind * 131;
|
||||
usize hash = spl_hash_seed();
|
||||
hash = spl_hash_mix(hash, (usize)n.kind);
|
||||
switch (n.kind) {
|
||||
case SPL_TYPE_ERROR:
|
||||
case SPL_TYPE_UNIT:
|
||||
@@ -13,38 +14,38 @@ static usize spl_type_hash(spl_type_node_t n) {
|
||||
case SPL_TYPE_BOOL:
|
||||
break;
|
||||
case SPL_TYPE_INT:
|
||||
hash += n.int_type.bits + (usize)n.int_type.is_signed;
|
||||
hash = spl_hash_mix(hash, n.int_type.bits);
|
||||
hash = spl_hash_mix(hash, (usize)n.int_type.is_signed);
|
||||
break;
|
||||
case SPL_TYPE_FLOAT:
|
||||
hash += n.float_type.bits;
|
||||
hash = spl_hash_mix(hash, n.float_type.bits);
|
||||
break;
|
||||
case SPL_TYPE_PTR:
|
||||
hash += n.ptr_type.pointee;
|
||||
hash = spl_hash_mix(hash, n.ptr_type.pointee);
|
||||
break;
|
||||
case SPL_TYPE_ARRAY:
|
||||
hash += n.array_type.element + n.array_type.len;
|
||||
hash = spl_hash_mix(hash, n.array_type.element);
|
||||
hash = spl_hash_mix(hash, n.array_type.len);
|
||||
break;
|
||||
case SPL_TYPE_STRUCT:
|
||||
case SPL_TYPE_UNION:
|
||||
case SPL_TYPE_ENUM:
|
||||
case SPL_TYPE_SHAPE:
|
||||
hash += (usize)n.layout.mode * 31 + n.layout.fixed_align_bits;
|
||||
hash += n.agg_type.tag_type;
|
||||
hash = spl_hash_mix(hash, (usize)n.layout.mode);
|
||||
hash = spl_hash_mix(hash, n.layout.fixed_align_bits);
|
||||
hash = spl_hash_mix(hash, n.agg_type.tag_type);
|
||||
hash = spl_hash_mix(hash, vec_size(n.agg_type.variants));
|
||||
for (usize i = 0; i < vec_size(n.agg_type.variants); i++) {
|
||||
spl_type_member_t *m = &n.agg_type.variants.data[i];
|
||||
hash += m->type_id;
|
||||
if (m->name) {
|
||||
const char *s = m->name;
|
||||
while (*s) {
|
||||
hash = hash * 31 + (usize)(*s++);
|
||||
}
|
||||
}
|
||||
spl_type_member_t *m = &vec_at(n.agg_type.variants, i);
|
||||
hash = spl_hash_mix(hash, m->type_id);
|
||||
hash = spl_hash_mix_str(hash, m->name);
|
||||
}
|
||||
break;
|
||||
case SPL_TYPE_FN:
|
||||
hash += n.fn_type.ret;
|
||||
hash = spl_hash_mix(hash, n.fn_type.ret);
|
||||
hash = spl_hash_mix(hash, vec_size(n.fn_type.params));
|
||||
for (usize i = 0; i < vec_size(n.fn_type.params); i++) {
|
||||
hash += vec_at(n.fn_type.params, i);
|
||||
hash = spl_hash_mix(hash, vec_at(n.fn_type.params, i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -110,9 +111,6 @@ static int spl_type_eq(spl_type_node_t n1, spl_type_node_t n2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static usize spl_type_map_hash(usize k) { return MAP_HASH_INT(k); }
|
||||
static int spl_type_map_cmp(usize a, usize b) { return MAP_CMP_INT(a, b); }
|
||||
|
||||
static void spl_type_node_free_vecs(spl_type_node_t *tn) {
|
||||
switch (tn->kind) {
|
||||
case SPL_TYPE_STRUCT:
|
||||
@@ -129,20 +127,34 @@ static void spl_type_node_free_vecs(spl_type_node_t *tn) {
|
||||
}
|
||||
}
|
||||
|
||||
/* spl_fold 回调:只在链内做结构比较(同桶已保证 hash 相同)。 */
|
||||
static int spl_type_fold_eq(void *ctx, spl_fold_id_t node, const void *probe) {
|
||||
spl_type_t *type = (spl_type_t *)ctx;
|
||||
return spl_type_eq(vec_at(type->type_table, node), *(const spl_type_node_t *)probe) == 0;
|
||||
}
|
||||
|
||||
static spl_fold_id_t spl_type_fold_next(void *ctx, spl_fold_id_t node) {
|
||||
spl_type_t *type = (spl_type_t *)ctx;
|
||||
return vec_at(type->type_table, node).hash_next;
|
||||
}
|
||||
|
||||
static void spl_type_fold_set_next(void *ctx, spl_fold_id_t node, spl_fold_id_t next) {
|
||||
spl_type_t *type = (spl_type_t *)ctx;
|
||||
vec_at(type->type_table, node).hash_next = next;
|
||||
}
|
||||
|
||||
spl_type_id_t spl_type_node_push(spl_type_t *type, spl_type_node_t *tn) {
|
||||
usize hash = spl_type_hash(*tn);
|
||||
usize idx = (usize)-1;
|
||||
spl_type_id_t cand = 0;
|
||||
while (map_get_continue(type->type_map, hash, &cand, &idx)) {
|
||||
spl_type_node_t *existing = &vec_at(type->type_table, cand);
|
||||
if (spl_type_eq(*existing, *tn) == 0) {
|
||||
spl_type_node_free_vecs(tn);
|
||||
return cand;
|
||||
}
|
||||
|
||||
spl_type_id_t existing = spl_fold_find(&type->type_fold, hash, tn);
|
||||
if (existing) {
|
||||
spl_type_node_free_vecs(tn);
|
||||
return existing;
|
||||
}
|
||||
|
||||
spl_type_id_t id = vec_size(type->type_table);
|
||||
vec_push(type->type_table, *tn);
|
||||
map_put_new(type->type_map, hash, id);
|
||||
spl_fold_insert(&type->type_fold, hash, id);
|
||||
tn->kind = SPL_TYPE_ERROR;
|
||||
return id;
|
||||
}
|
||||
@@ -151,7 +163,8 @@ void spl_type_init(spl_type_t *type) {
|
||||
vec_init(type->type_table);
|
||||
spl_type_node_t type_node = {0};
|
||||
vec_push(type->type_table, type_node);
|
||||
map_init(type->type_map, spl_type_map_hash, spl_type_map_cmp);
|
||||
spl_fold_init(&type->type_fold, type, spl_type_fold_eq, spl_type_fold_next,
|
||||
spl_type_fold_set_next);
|
||||
}
|
||||
|
||||
void spl_type_drop(spl_type_t *type) {
|
||||
@@ -159,7 +172,7 @@ void spl_type_drop(spl_type_t *type) {
|
||||
spl_type_node_t *n = &vec_at(type->type_table, i);
|
||||
spl_type_node_free_vecs(n);
|
||||
}
|
||||
map_free(type->type_map);
|
||||
spl_fold_drop(&type->type_fold);
|
||||
vec_free(type->type_table);
|
||||
}
|
||||
|
||||
|
||||
+23
-3
@@ -2,6 +2,27 @@
|
||||
#define __SPL_TYPE_H__
|
||||
|
||||
#include "../stage0/include/utils.h"
|
||||
#include "spl_fold.h"
|
||||
|
||||
/* 类型 intern 用的哈希混合(FNV-1a 风格,顺序敏感)。
|
||||
hash 只用于选择桶;相等判定始终由结构比较完成。 */
|
||||
static inline usize spl_hash_mix(usize h, usize x) {
|
||||
h ^= x;
|
||||
h *= (usize)1099511628211ULL;
|
||||
return h;
|
||||
}
|
||||
|
||||
static inline usize spl_hash_mix_str(usize h, const char *s) {
|
||||
if (!s)
|
||||
return spl_hash_mix(h, 0);
|
||||
while (*s) {
|
||||
h = spl_hash_mix(h, (usize)(unsigned char)*s);
|
||||
s++;
|
||||
}
|
||||
return spl_hash_mix(h, 0); /* 终止符参与混合,避免名称拼接歧义 */
|
||||
}
|
||||
|
||||
static inline usize spl_hash_seed(void) { return (usize)14695981039346656037ULL; }
|
||||
|
||||
typedef usize spl_type_id_t;
|
||||
typedef VEC(spl_type_id_t) spl_type_id_vec_t;
|
||||
@@ -73,14 +94,13 @@ typedef struct {
|
||||
struct {
|
||||
} shape_type;
|
||||
};
|
||||
usize hash_next; /* 同 hash 桶内下一个类型 id;0 表示链尾。不参与相等比较。 */
|
||||
} spl_type_node_t;
|
||||
typedef VEC(spl_type_node_t) spl_type_node_vec_t;
|
||||
|
||||
typedef MAP(usize, spl_type_id_t) spl_type_node_map_t;
|
||||
|
||||
typedef struct {
|
||||
spl_type_node_vec_t type_table;
|
||||
spl_type_node_map_t type_map;
|
||||
spl_fold_t type_fold;
|
||||
} spl_type_t;
|
||||
|
||||
void spl_type_init(spl_type_t *type);
|
||||
|
||||
Reference in new issue
Block a user