stage1 解决重构哈希 nob优化支持头文件缓存以及win下exe缓存
This commit is contained in:
1 parent
70ac7380e9
commit
fb0ff9b663
8 files changed
+236
-98
No files matched your search
@@ -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__ */
|
||||
+40
-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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+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