More mocking out of the Sea of Nodes based backend

This commit is contained in:
gingerBill
2026-04-16 18:28:32 +01:00
parent b9076e919a
commit df2f2efbc3
3 changed files with 995 additions and 132 deletions

View File

@@ -1,18 +1,103 @@
#include "cg.hpp"
#include "cg_worklist.cpp"
gb_internal void cg_opt(cgProcedure *p, cgWorklist *worklist, bool preserve_types) {
if (worklist == nullptr) {
return;
}
}
gb_internal gb_inline cgNode *cg_peep(cgGraphBuilder *b, cgNode *n) {
if (n == nullptr) {
return nullptr;
}
return b->peep_callback(b->p, n);
}
gb_internal bool cg_can_gvn(cgNode *n) {
if (n->kind == cgNode_Local) {
return false;
}
switch (n->kind) {
case cgNode_Local:
return false;
case cgNode_Region:
case cgNode_If:
case cgNode_DebugBreak:
case cgNode_Trap:
case cgNode_Unreachable:
case cgNode_Call:
case cgNode_Tailcall:
case cgNode_Syscall:
case cgNode_DebugLocation:
return false;
case cgNode_Blackhole:
return false;
}
return true;
}
gb_internal CG_PEEP_PROC(cg_opt_gvn_node) {
if (!cg_can_gvn(n)) {
return n;
}
return n;
}
template <typename T>
gb_internal T *cg_alloc_node(cgProcedure *p, cgType type, isize input_count, isize input_capacity, Type *odin_type) {
GB_ASSERT(input_count >= 0);
GB_ASSERT(input_count < UINT16_MAX);
if (input_capacity <= 0) {
input_capacity = input_count;
}
GB_ASSERT(input_count <= input_capacity);
GB_ASSERT(input_capacity <= UINT16_MAX);
void *mem = arena_alloc(&p->arena, gb_size_of(T), gb_align_of(T));
new(mem) T{};
T *n = cast(T *)n;
n->input_count = input_count;
n->input_capacity = input_capacity;
n->input_count = cast(u16)input_count;
n->input_capacity = cast(u16)input_capacity;
n->type = type;
n->gvn = p->node_count++;
n->gvn = ++p->node_count;
n->odin_type = odin_type;
if (n->input_capacity > 0) {
n->inputs = arena_alloc_array<cgNode *>(&p->arena, n->input_capacity);
} else {
n->inputs = nullptr;
}
n->user_count = 0;
n->user_capacity = 4;
n->users = arena_alloc_array<cgUser>(&p->arena, n->user_capacity);
return n;
}
template <typename T>
gb_internal T *cg_alloc_node_with_kind(cgProcedure *p, cgNodeKind kind, cgType type, isize input_count, isize input_capacity, Type *odin_type) {
GB_ASSERT(input_count >= 0);
GB_ASSERT(input_count < UINT16_MAX);
if (input_capacity <= 0) {
input_capacity = input_count;
}
GB_ASSERT(input_count <= input_capacity);
GB_ASSERT(input_capacity <= UINT16_MAX);
void *mem = arena_alloc(&p->arena, gb_size_of(T), gb_align_of(T));
new(mem) T{kind};
T *n = cast(T *)n;
n->input_count = cast(u16)input_count;
n->input_capacity = cast(u16)input_capacity;
n->type = type;
n->gvn = ++p->node_count;
n->odin_type = odin_type;
if (n->input_capacity > 0) {
@@ -29,172 +114,671 @@ gb_internal T *cg_alloc_node(cgProcedure *p, cgType type, isize input_count, isi
}
gb_internal cgGraphBuilder *cg_builder_enter(cgProcedure *p, Type *odin_signature) {
return nullptr;
gb_internal void cg_add_user(cgProcedure *p, cgNode *n, cgNode *in, u16 slot) {
if (in->user_count >= in->user_capacity) { // resize
isize new_capacity = 2 * cast(isize)in->user_capacity;
if (new_capacity >= UINT16_MAX) {
GB_ASSERT("TOO MANY USERS to one cgNode");
}
cgUser *users = arena_alloc_array<cgUser>(&p->arena, new_capacity);
gb_memcopy(users, in->users, in->user_count * gb_size_of(cgUser));
in->user_capacity = cast(u16)new_capacity;
in->users = users;
}
in->users[in->user_count].node = n;
in->users[in->user_count].slot = slot;
in->user_count += 1;
}
gb_internal void cg_remove_user(cgProcedure *p, cgNode *n, u16 slot) {
if (n->inputs[slot] == nullptr) {
return;
}
cgNode *old = n->inputs[slot];
cgUser *old_use = old->users;
for (u16 i = 0; i < old->user_count; i++) {
if (old_use[i].node == n && old_use[i].slot == slot) {
old->user_count -= 1;
old_use[i] = old_use[old->user_count];
if (old->user_count == 0 && p->worklist) {
cg_worklist_push(p->worklist, old);
}
return;
}
}
GB_PANIC("failed to remove non-existent user %p from %p (slot %u)", old, n, slot);
}
gb_internal void cg_set_input(cgProcedure *p, cgNode *n, cgNode *in, u16 slot) {
GB_ASSERT(slot < n->input_count);
cg_remove_user(p, n, slot);
n->inputs[slot] = in;
if (in != nullptr) {
cg_add_user(p, n, in, slot);
}
}
gb_internal u32 cg_type_bit_size(cgModule *m, cgTypeKind kind) {
switch (kind) {
case cgType_void: return 0;
case cgType_bool: return 1;
case cgType_i8: return 8;
case cgType_i16: return 16;
case cgType_i32: return 32;
case cgType_i64: return 64;
case cgType_ptr:
return cast(u32)build_context.metrics.ptr_size;
case cgType_f16: return 16;
case cgType_f32: return 32;
case cgType_f64: return 64;
case cgType_v64: return 64;
case cgType_v128: return 128;
case cgType_v256: return 256;
case cgType_v512: return 512;
case cgType_control:
case cgType_memory:
case cgType_tuple:
GB_ASSERT("Unknown bit size");
return 0;
}
}
gb_internal void cg_kill_node(cgProcedure *p, cgNode *n) {
for (u16 i = 0; i < n->input_count; i++) {
cg_remove_user(p, n, i);
n->inputs[i] = nullptr;
}
n->input_count = 0;
n->kind = cgNode_NULL;
}
gb_internal void cg_kill_violently(cgProcedure *p, cgNode *n) {
// NOTE(bill): kill this node violently. It's not murder, luckily.
for (u16 i = 0; i < n->input_count; i++) {
cg_remove_user(p, n, i);
n->inputs[i] = nullptr;
}
GB_ASSERT(n->user_count == 0);
n->user_count = 0;
n->user_capacity = 0;
n->users = nullptr;
n->input_count = 0;
n->kind = cgNode_NULL;
}
gb_internal cgGraphBuilder *cg_builder_enter(cgProcedure *p, Type *odin_signature, cgWorklist *wl) {
p->worklist = wl;
auto *b = arena_alloc_item<cgGraphBuilder>(&p->arena);
b->p = p;
b->arena = &p->temp_arena;
b->peep_callback = cg_opt_gvn_node;
return b;
}
gb_internal void cg_builder_exit(cgGraphBuilder *b) {
return;
if (b->curr) {
cgNode *n = b->curr;
b->curr = nullptr;
cg_builder_label_kill(b, n);
}
if (b->start_symbol_table != b->curr) {
cg_builder_label_kill(b, b->start_symbol_table);
}
cgProcedure *p = b->p;
cgNode *ret = p->root_node->inputs[1];
if (ret->kind == cgNode_Return &&
ret->inputs[0]->kind == cgNode_Region &&
ret->inputs[0]->input_count == 0) {
cg_kill_node(p, ret->inputs[0]);
GB_ASSERT(p->root_node->input_count > 0);
u16 last = p->root_node->input_count-1;
GB_ASSERT(last != 1);
cgNode *last_n = p->root_node->inputs[last];
cg_set_input(p, p->root_node, nullptr, last);
cg_set_input(p, p->root_node, last_n, 1);
p->root_node->input_count -= 1;
cg_kill_node(p, ret);
}
arena_free_all(b->arena);
if (p->worklist != nullptr) {
cg_worklist_clear(p->worklist);
cg_opt(p, p->worklist, false);
}
}
gb_internal cgNode *cg_builder_bool(cgGraphBuilder *b, bool x) {
return nullptr;
auto *n = cg_alloc_node<cgNodeInt>(b->p, CG_TYPE_BOOL, 1);
cg_set_input(b->p, n, b->p->root_node, 0);
n->val = cast(u64)x;
return cg_peep(b, n);
}
gb_internal cgNode *cg_builder_uint(cgGraphBuilder *b, cgType type, u64 x) {
return nullptr;
GB_ASSERT(type.is_int_or_ptr());
u32 bits = cg_type_bit_size(b->p->module, type.kind);
if (bits < 64) {
u64 mask = (~cast(u64)0ull) >> (64 - bits);
x &= mask;
}
auto *n = cg_alloc_node<cgNodeInt>(b->p, type, 1);
cg_set_input(b->p, n, b->p->root_node, 0);
n->val = cast(u64)x;
return cg_peep(b, n);
}
gb_internal cgNode *cg_builder_int (cgGraphBuilder *b, cgType type, i64 x) {
return nullptr;
gb_internal cgNode *cg_builder_int(cgGraphBuilder *b, cgType type, i64 x) {
GB_ASSERT(type.is_int_or_ptr());
auto *n = cg_alloc_node<cgNodeInt>(b->p, type, 1);
cg_set_input(b->p, n, b->p->root_node, 0);
n->val = cast(u64)x;
return cg_peep(b, n);
}
gb_internal cgNode *cg_builder_f16(cgGraphBuilder *b, u16 x) {
return nullptr;
auto *n = cg_alloc_node<cgNodeF16>(b->p, CG_TYPE_F16, 1);
cg_set_input(b->p, n, b->p->root_node, 0);
n->val = x;
return cg_peep(b, n);
}
gb_internal cgNode *cg_builder_f32(cgGraphBuilder *b, f32 x) {
return nullptr;
auto *n = cg_alloc_node<cgNodeF32>(b->p, CG_TYPE_F32, 1);
cg_set_input(b->p, n, b->p->root_node, 0);
n->val = x;
return cg_peep(b, n);
}
gb_internal cgNode *cg_builder_f64(cgGraphBuilder *b, f64 x) {
return nullptr;
auto *n = cg_alloc_node<cgNodeF64>(b->p, CG_TYPE_F64, 1);
cg_set_input(b->p, n, b->p->root_node, 0);
n->val = x;
return cg_peep(b, n);
}
gb_internal cgNode *cg_builder_symbol(cgGraphBuilder *b, cgSymbol *s) {
return nullptr;
auto *n = cg_alloc_node<cgNodeSymbol>(b->p, CG_TYPE_PTR, 1);
cg_set_input(b->p, n, b->p->root_node, 0);
n->symbol = s;
return cg_peep(b, n);
}
gb_internal cgNode *cg_builder_string_ptr(cgGraphBuilder *b, String str) {
GB_ASSERT(str.len >= 0);
GB_PANIC("TODO(bill): cg_builder_string_ptr");
return nullptr;
}
gb_internal u64 cg_const_sign_ext(cgModule *m, cgType type, u64 src) {
u32 src_bits = cg_type_bit_size(m, type);
u32 dst_bits = 64;
if (src_bits == dst_bits) {
return src;
}
gb_internal cgNode *cg_builder_binary_op_int(cgGraphBuilder *b, cgBinaryOpInt op, cgNode *x, cgNode *y) {
u64 mask = ((u64)1ull)<<(src_bits-1);
return (src ^ mask) - mask;
}
gb_internal cgNode *cg_builder_binary_op_int(cgGraphBuilder *b, cgNodeKind op, cgNode *x, cgNode *y) {
return nullptr;
}
gb_internal cgNode *cg_builder_binary_op_float(cgGraphBuilder *b, cgBinaryOpInt op, cgNode *x, cgNode *y) {
gb_internal cgNode *cg_builder_binary_op_float(cgGraphBuilder *b, cgNodeKind op, cgNode *x, cgNode *y) {
return nullptr;
}
gb_internal cgNode *cg_builder_select(cgGraphBuilder *b, cgNode *cond, cgNode *x, cgNode *y) {
return nullptr;
GB_ASSERT(x->type == y->type);
auto *n = cg_alloc_node<cgNodeSelect>(b->p, x->type, 4);
cg_set_input(b->p, n, cond, 1);
cg_set_input(b->p, n, x, 2);
cg_set_input(b->p, n, y, 3);
return cg_peep(b, n);
}
gb_internal cgNode *cg_builder_cast(cgGraphBuilder *b, cgType type, cgCastOp op, cgNode *src) {
return nullptr;
gb_internal cgNode *cg_builder_cast(cgGraphBuilder *b, cgType type, cgNodeKind op, cgNode *src) {
GB_ASSERT(cgNode_Bitcast <= op && op <= cgNode_FloatToUint);
if (src->kind == cgNode_Int) {
auto *iconst = src->downcast<cgNodeInt>();
if (op == cgNode_ZeroExt) {
u32 bits = cg_type_bit_size(b->p->module, src->type.kind);
u64 val = iconst->val;
return cg_builder_uint(b, src->type, val & (~cast(u64)0) >> (64 - bits));
} else if (op == cgNode_SignExt) {
u64 val = iconst->val;
val = cg_const_sign_ext(b->p->module, src->type, val);
return cg_builder_uint(b, src->type, val);
}
}
auto *n = cg_alloc_node_with_kind<cgNodeCast>(b->p, op, src->type, 2);
cg_set_input(b->p, n, src, 1);
return cg_peep(b, n);
}
gb_internal cgNode *cg_builder_unary(cgGraphBuilder *b, cgUnaryOp op, cgNode *src) {
return nullptr;
gb_internal cgNode *cg_builder_unary(cgGraphBuilder *b, cgNodeKind op, cgNode *src) {
GB_ASSERT(op == cgNode_FNeg);
auto *n = cg_alloc_node_with_kind<cgNodeUnary>(b->p, op, src->type, 2);
cg_set_input(b->p, n, src, 1);
return cg_peep(b, n);
}
gb_internal cgNode *cg_builder_neg(cgGraphBuilder *b, cgNode *src) {
return nullptr;
if (src->type.is_float()) {
return cg_builder_unary(b, cgNode_FNeg, src);
} else {
return cg_builder_binary_op_int(b, cgNode_Sub, cg_builder_int(b, src->type, 0), src);
}
}
gb_internal cgNode *cg_builder_not(cgGraphBuilder *b, cgNode *src) {
return nullptr;
return cg_builder_binary_op_int(b, cgNode_Xor, src, cg_builder_int(b, src->type, -1));
}
gb_internal cgNode *cg_builder_cmp(cgGraphBuilder *b, cgCompareOp op, cgNode *x, cgNode *y) {
gb_internal cgNode *cg_builder_cmp(cgGraphBuilder *b, cgNodeKind op, cgNode *x, cgNode *y) {
GB_ASSERT(x->type == y->type);
GB_ASSERT(cgNode_Cmp_EQ <= op && op <= cgNode_Cmp_FLE);
return nullptr;
}
// base + index*stride
gb_internal cgNode *cg_builder_ptr_array(cgGraphBuilder *b, cgNode *base, cgNode *index, i64 stride) {
return nullptr;
gb_internal cgNode *cg_builder_ptr_array(cgGraphBuilder *b, cgNode *base, cgNode *index, u64 stride) {
GB_ASSERT(base->type.is_ptr());
GB_ASSERT(index->type.is_int());
if (stride == 0) {
return base;
}
cgNode *selection = index;
if (index->kind == cgNode_Int) {
u64 offset = index->downcast<cgNodeInt>()->val * stride;
if (base->kind == cgNode_PtrOffset && base->inputs[2]->kind == cgNode_Int) {
offset += base->inputs[2]->downcast<cgNodeInt>()->val;
base = base->inputs[1];
}
selection = cg_builder_uint(b, index->type, offset);
} else if (stride != 1) {
cgNode *s = cg_builder_int(b, CG_TYPE_I64, stride);
selection = cg_builder_binary_op_int(b, cgNode_Mul, index, s);
}
auto *n = cg_alloc_node_with_kind<cgNode>(b->p, cgNode_PtrOffset, base->type, 3);
cg_set_input(b->p, n, base, 1);
cg_set_input(b->p, n, selection, 2);
return cg_peep(b, n);
}
// base + offset
gb_internal cgNode *cg_builder_ptr_member(cgGraphBuilder *b, cgNode *base, i64 offset) {
return nullptr;
if (offset = 0) {
return base;
}
if (base->kind == cgNode_PtrOffset && base->inputs[2]->kind == cgNode_Int) {
offset += base->inputs[2]->downcast<cgNodeInt>()->val;
base = base->inputs[1];
}
auto *selection = cg_builder_int(b, CG_TYPE_I64, offset);
auto *n = cg_alloc_node_with_kind<cgNode>(b->p, cgNode_PtrOffset, base->type, 3);
cg_set_input(b->p, n, base, 1);
cg_set_input(b->p, n, selection, 1);
return cg_peep(b, n);
}
gb_internal cgNode *cg_peek_mem(cgGraphBuilder *b, int mem_var) {
return b->curr->inputs[2 + mem_var];
}
gb_internal cgNode *cg_transfer_mem(cgGraphBuilder *b, cgNode *n, int mem_var) {
cgNode *old = b->curr->inputs[2 + mem_var];
GB_ASSERT(old->type.kind == cgType_memory);
cg_set_input(b->p, b->curr, n, cast(u16)(2 + mem_var));
return old;
}
gb_internal cgNode *cg_transfer_ctrl(cgGraphBuilder *b, cgNode *n) {
cgNode *old = b->curr->inputs[0];
cg_set_input(b->p, b->curr, n, 0);
return old;
}
gb_internal cgNode *cg_internal_make_proj(cgProcedure *p, cgType type, cgNode *src, i32 index) {
GB_ASSERT(src->type.kind == cgType_tuple);
auto *proj = cg_alloc_node<cgNodeProj>(p, type, 1);
cg_set_input(p, proj, src, 0);
proj->index = index;
return proj;
}
gb_internal cgNode *cg_builder_load(cgGraphBuilder *b, int mem_var, bool ctrl_dep, cgType type, cgNode *addr, u32 align, bool is_volatile) {
return nullptr;
GB_ASSERT(addr->type.is_ptr());
auto *n = cg_alloc_node_with_kind<cgNodeMemAccess>(b->p, cgNode_Load, type, 3);
n->align = gb_max(align, 1);
if (ctrl_dep) {
cg_set_input(b->p, n, b->curr->inputs[0], 0);
}
cg_set_input(b->p, n, cg_peek_mem(b, mem_var), 1);
cg_set_input(b->p, n, addr, 2);
n = cg_peep(b, n)->downcast<cgNodeMemAccess>();
if (is_volatile) {
auto *barrier = cg_alloc_node_with_kind<cgNodeMemAccess>(b->p, cgNode_VolatileBarrier, CG_TYPE_MEMORY, 3);
cg_set_input(b->p, barrier, b->curr->inputs[0], 0);
cg_set_input(b->p, barrier, cg_transfer_mem(b, barrier, mem_var), 1);
cg_set_input(b->p, barrier, n, 2);
}
return n;
}
gb_internal cgNode *cg_builder_store(cgGraphBuilder *b, int mem_var, bool ctrl_dep, cgType type, cgNode *addr, cgNode *val, u32 align, bool is_volatile) {
return nullptr;
GB_ASSERT(addr->type.is_ptr());
auto *n = cg_alloc_node_with_kind<cgNodeMemAccess>(b->p, cgNode_Store, CG_TYPE_MEMORY, 3);
n->align = gb_max(align, 1);
cg_set_input(b->p, n, b->curr->inputs[0], 0);
cg_set_input(b->p, n, cg_transfer_mem(b, n, mem_var), 1);
cg_set_input(b->p, n, addr, 2);
cg_set_input(b->p, n, val, 3);
if (is_volatile) {
auto *barrier = cg_alloc_node_with_kind<cgNodeMemAccess>(b->p, cgNode_VolatileBarrier, CG_TYPE_MEMORY, 2);
cg_set_input(b->p, barrier, b->curr->inputs[0], 0);
cg_set_input(b->p, barrier, cg_transfer_mem(b, barrier, mem_var), 1);
}
return n;
}
gb_internal cgNode *cg_builder_memcpy(cgGraphBuilder *b, int mem_var, bool ctrl_dep, cgType type, cgNode *dst, cgNode *src, cgNode *size, u32 align, bool is_volatile) {
return nullptr;
GB_ASSERT(dst->type.is_ptr());
GB_ASSERT(src->type.is_ptr());
auto *n = cg_alloc_node_with_kind<cgNodeMemAccess>(b->p, cgNode_Memcpy, CG_TYPE_MEMORY, 5);
n->align = align;
cg_set_input(b->p, n, b->curr->inputs[0], 0);
cg_set_input(b->p, n, cg_transfer_mem(b, n, mem_var), 1);
cg_set_input(b->p, n, dst, 2);
cg_set_input(b->p, n, src, 3);
cg_set_input(b->p, n, size, 4);
return n;
}
gb_internal cgNode *cg_builder_memmove(cgGraphBuilder *b, int mem_var, bool ctrl_dep, cgType type, cgNode *dst, cgNode *src, cgNode *size, u32 align, bool is_volatile) {
return nullptr;
GB_ASSERT(dst->type.is_ptr());
GB_ASSERT(src->type.is_ptr());
auto *n = cg_alloc_node_with_kind<cgNodeMemAccess>(b->p, cgNode_Memmove, CG_TYPE_MEMORY, 5);
n->align = align;
cg_set_input(b->p, n, b->curr->inputs[0], 0);
cg_set_input(b->p, n, cg_transfer_mem(b, n, mem_var), 1);
cg_set_input(b->p, n, dst, 2);
cg_set_input(b->p, n, src, 3);
cg_set_input(b->p, n, size, 4);
return n;
}
gb_internal cgNode *cg_builder_memzero(cgGraphBuilder *b, int mem_var, bool ctrl_dep, cgType type, cgNode *dst, cgNode *size, u32 align, bool is_volatile) {
return nullptr;
GB_ASSERT(dst->type.is_ptr());
auto *n = cg_alloc_node_with_kind<cgNodeMemAccess>(b->p, cgNode_Memzero, CG_TYPE_MEMORY, 4);
n->align = align;
cg_set_input(b->p, n, b->curr->inputs[0], 0);
cg_set_input(b->p, n, cg_transfer_mem(b, n, mem_var), 1);
cg_set_input(b->p, n, dst, 2);
cg_set_input(b->p, n, size, 3);
return n;
}
gb_internal cgNode *cg_builder_local(cgGraphBuilder *b, u32 size, u32 align) {
return nullptr;
GB_ASSERT(align > 0);
auto *n = cg_alloc_node<cgNodeLocal>(b->p, CG_TYPE_PTR, 1);
n->size = size;
n->align = align;
return n;
}
gb_internal cgNode *cg_builder_local_debug(cgGraphBuilder *b, cgNode *n, String name, Type *odin_type) {
return nullptr;
gb_internal cgNode *cg_builder_local_debug(cgGraphBuilder *b, String name, Type *odin_type) {
GB_ASSERT(odin_type != nullptr);
i64 size = type_size_of(odin_type);
i64 align = type_align_of(odin_type);
GB_ASSERT(size <= UINT32_MAX);
GB_ASSERT(align <= UINT32_MAX);
auto *n = cg_alloc_node<cgNodeLocal>(b->p, CG_TYPE_PTR, 1);
n->size = cast(u32)size;
n->align = cast(u32)align;
n->name = string_interner_insert(name);
n->odin_type = alloc_type_pointer(odin_type);
return n;
}
gb_internal cgNode *cg_builder_frame_ptr(cgGraphBuilder *b) {
return nullptr;
auto *n = cg_alloc_node_with_kind<cgNode>(b->p, cgNode_FramePtr, CG_TYPE_PTR, 1);
cg_set_input(b->p, n, b->p->root_node, 0);
return cg_peep(b, n);
}
gb_internal cgNode *cg_builder_label(cgGraphBuilder *b, cgNode *label, bool allow_backward_jumps) {
if (label == nullptr) {
GB_ASSERT(allow_backward_jumps == false);
auto *r = cg_alloc_node<cgNodeRegion> (b->p, CG_TYPE_CONTROL, 0, 2);
auto *st = cg_alloc_node<cgNodeSymbolTable>(b->p, CG_TYPE_VOID, b->curr->input_count);
cg_set_input(b->p, st, r, 0);
cg_set_input(b->p, st, r, 1);
return st;
}
auto *r = cg_alloc_node<cgNodeRegion> (b->p, CG_TYPE_CONTROL, 0, 2);
auto *st = cg_alloc_node<cgNodeSymbolTable>(b->p, CG_TYPE_VOID, label->input_count);
cg_set_input(b->p, st, r, 0);
cg_set_input(b->p, st, r, 1);
if (allow_backward_jumps) {
for (u16 i = 2; i < label->input_count; i++) {
auto *n = cg_alloc_node<cgNodePhi>(b->p, label->inputs[i]->type, 1, 3);
cg_set_input(b->p, n, r, 0);
cg_set_input(b->p, st, n, i);
}
st->complete = true;
}
return st;
}
gb_internal cgNode *cg_phi_identity(cgProcedure *p, cgNode *n) {
GB_PANIC("TODO(bill): cg_phi_identity");
return nullptr;
}
gb_internal cgNode *cg_builder_label_complete(cgGraphBuilder *b, cgNode *label) {
gb_internal cgNode *cg_subsume_node(cgProcedure *p, cgNode *old_n, cgNode *new_n) {
GB_PANIC("TODO(bill): cg_subsume_node");
return nullptr;
}
gb_internal void cg_builder_label_complete(cgGraphBuilder *b, cgNode *label) {
cgProcedure *p = b->p;
GB_ASSERT(label->kind == cgNode_SymbolTable);
auto *st = label->downcast<cgNodeSymbolTable>();
if (st->complete) {
return;
}
st->complete = true;
cgNode *top_ctrl = label->inputs[1];
if (top_ctrl->kind == cgNode_Region) {
for (u16 i = 0; i < top_ctrl->user_count; i++) {
cgUser *u = &top_ctrl->users[i];
if (u->node->kind == cgNode_Phi) {
GB_ASSERT(u->slot == 0);
cgNode *k = cg_phi_identity(p, u->node);
if (k != u->node) {
cg_subsume_node(p, u->node, k);
}
}
}
}
if (top_ctrl->input_count != 0) {
for (u16 i = 2; i < label->input_count; i++) {
cg_peep(b, label->inputs[i]); // nullptr will be skipped
}
}
}
gb_internal void cg_builder_label_kill(cgGraphBuilder *b, cgNode *label) {
return;
if (label->kind != cgNode_NULL) {
GB_ASSERT(label->kind == cgNode_SymbolTable);
GB_ASSERT_MSG(label != b->curr, "Cannot kill the label that is being currently used");
cg_kill_violently(b->p, label);
}
}
gb_internal cgNode *cg_builder_if(cgGraphBuilder *b, cgNode *cond, cgNode *x, cgNode *y) {
return nullptr;
gb_internal cgNode *cg_builder_if(cgGraphBuilder *b, cgNode *cond, cgNode *paths[2]) {
cgProcedure *p = b->p;
auto *n = cg_alloc_node<cgNodeIf>(p, CG_TYPE_TUPLE, 2);
n->prob = 0.5f;
cg_set_input(p, n, cg_transfer_ctrl(b, n), 0);
cg_set_input(p, n, cond, 1);
cgNode *cproj[2];
cproj[0] = cg_internal_make_proj(p, CG_TYPE_CONTROL, n, 0);
cproj[1] = cg_internal_make_proj(p, CG_TYPE_CONTROL, n, 1);
cgNode *curr = b->curr;
b->curr = nullptr;
for (isize i = 0; i < 2; i++) {
auto *st = cg_alloc_node<cgNodeSymbolTable>(p, CG_TYPE_VOID, curr->input_count);
cg_set_input(p, st, cproj[i], 0);
cg_set_input(p, st, cproj[i], 1);
st->complete = true;
for (u16 j = 2; j < curr->input_count; j++) {
cg_set_input(p, st, curr->inputs[j], j);
}
paths[i] = st;
}
return n;
}
gb_internal void cg_builder_jump(cgGraphBuilder *b, cgNode *target) {
auto *st = b->curr->downcast<cgNodeSymbolTable>();
if (st == nullptr) {
return;
}
GB_PANIC("TODO(bill): cg_builder_jump");
return;
}
gb_internal cgNode *cg_builder_loop(cgGraphBuilder *b) {
GB_PANIC("TODO(bill): cg_builder_loop");
return nullptr;
}
gb_internal cgNode *cg_builder_phi(cgGraphBuilder *b, Slice<cgNode *> vals) {
GB_PANIC("TODO(bill): cg_builder_phi");
return nullptr;
}
gb_internal cgNode *cg_builder_switch(cgGraphBuilder *b, cgNode *cond) {
GB_PANIC("TODO(bill): cg_builder_switch");
return nullptr;
}
gb_internal cgNode *cg_builder_case_default(cgGraphBuilder *b, cgNode *br_syms) {
GB_PANIC("TODO(bill): cg_builder_case_default");
return nullptr;
}
gb_internal cgNode *cg_builder_case_key(cgGraphBuilder *b, cgNode *br_syms, u64 key) {
GB_PANIC("TODO(bill): cg_builder_case_key");
return nullptr;
}
gb_internal void cg_add_input_late(cgProcedure *p, cgNode *n, cgNode *in) {
GB_PANIC("TODO(bill): cg_add_input_late");
}
gb_internal void cg_builder_ret(cgGraphBuilder *b, int mem_var, Slice<cgNode *> args) {
GB_PANIC("TODO(bill): cg_builder_ret");
return;
}
gb_internal void cg_builder_unreachable(cgGraphBuilder *b, int mem_var) {
return;
auto *n = cg_alloc_node_with_kind<cgNode>(b->p, cgNode_Unreachable, CG_TYPE_CONTROL, 2);
cg_set_input(b->p, n, cg_transfer_ctrl(b, n), 0);
cg_set_input(b->p, n, cg_peek_mem(b, mem_var), 1);
cg_add_input_late(b->p, b->p->root_node, n);
b->curr = nullptr;
}
gb_internal void cg_builder_trap(cgGraphBuilder *b, int mem_var) {
return;
auto *n = cg_alloc_node_with_kind<cgNode>(b->p, cgNode_Trap, CG_TYPE_CONTROL, 2);
cg_set_input(b->p, n, cg_transfer_ctrl(b, n), 0);
cg_set_input(b->p, n, cg_peek_mem(b, mem_var), 1);
cg_add_input_late(b->p, b->p->root_node, n);
b->curr = nullptr;
}
gb_internal void cg_builder_debug_trap(cgGraphBuilder *b, int mem_var) {
return;
gb_internal void cg_builder_debug_break(cgGraphBuilder *b, int mem_var) {
auto *n = cg_alloc_node_with_kind<cgNode>(b->p, cgNode_DebugBreak, CG_TYPE_CONTROL, 2);
cg_set_input(b->p, n, cg_transfer_ctrl(b, n), 0);
cg_set_input(b->p, n, cg_peek_mem(b, mem_var), 1);
}
gb_internal void cg_builder_black_hole(cgGraphBuilder *b, Slice<cgNode *> args) {
GB_PANIC("TODO(bill): cg_builder_black_hole");
return;
}
gb_internal cgNode *cg_builder_call(cgGraphBuilder *b, Type *odin_signature, int mem_var, cgNode *target, Slice<cgNode *> args) {
GB_PANIC("TODO(bill): cg_builder_call");
return nullptr;
}
gb_internal cgNode *cg_builder_syscall(cgGraphBuilder *b, cgType dt, int mem_var, cgNode *target, Slice<cgNode *> args) {
GB_PANIC("TODO(bill): cg_builder_syscall");
return nullptr;
}
gb_internal cgNode *cg_builder_atomic_rmw(cgGraphBuilder *b, int mem_var, int op, cgNode *addr, cgNode *val, cgMemoryOrder order) {
GB_PANIC("TODO(bill): cg_builder_atomic_rmw");
return nullptr;
}
gb_internal cgNode *cg_builder_atomic_load(cgGraphBuilder *b, int mem_var, cgType type, cgNode *addr, cgMemoryOrder order) {
GB_PANIC("TODO(bill): cg_builder_atomic_load");
return nullptr;
}
gb_internal bool cg_node_is_constant_zero(cgGraphBuilder *b, cgNode *n) {
GB_PANIC("TODO(bill): cg_node_is_constant_zero");
return nullptr;
}

View File

@@ -18,24 +18,63 @@ enum cgTypeKind : u8 {
cgType_i16,
cgType_i32,
cgType_i64,
// cgType_i128,
cgType_ptr,
cgType_f16,
cgType_f32,
cgType_f64,
cgType_v64,
cgType_v128,
cgType_v256,
cgType_v512,
cgType_control,
cgType_memory,
cgType_tuple,
};
struct cgType {
cgTypeKind kind;
bool is_int() const {
switch (this->kind) {
case cgType_i8:
case cgType_i16:
case cgType_i32:
case cgType_i64:
return true;
}
return false;
}
bool is_int_or_ptr() const {
switch (this->kind) {
case cgType_bool:
case cgType_i8:
case cgType_i16:
case cgType_i32:
case cgType_i64:
case cgType_ptr:
return true;
}
return false;
}
bool is_float() const {
switch (this->kind) {
case cgType_f16:
case cgType_f32:
case cgType_f64:
return true;
}
return false;
}
bool is_ptr() const {
return this->kind == cgType_ptr;
}
};
gb_internal gb_inline bool operator==(cgType x, cgType y) {
@@ -48,7 +87,6 @@ gb_global cgType const CG_TYPE_I8 = cgType{cgType_i8};
gb_global cgType const CG_TYPE_I16 = cgType{cgType_i16};
gb_global cgType const CG_TYPE_I32 = cgType{cgType_i32};
gb_global cgType const CG_TYPE_I64 = cgType{cgType_i64};
// gb_global cgType const CG_TYPE_I128 = cgType{cgType_i128};
gb_global cgType const CG_TYPE_PTR = cgType{cgType_ptr};
gb_global cgType const CG_TYPE_F16 = cgType{cgType_f16};
gb_global cgType const CG_TYPE_F32 = cgType{cgType_f32};
@@ -88,31 +126,6 @@ struct cgSymbol {
i64 ordinal;
};
enum cgCompareOp : u8 {
cgCompareOp_Unknown,
cgCompareOp_COUNT,
};
enum cgBinaryOpInt : u8 {
cgBinaryOpInt_Unknown,
cgBinaryOpInt_COUNT,
};
enum cgUnaryOp : u8 {
cgUnaryOp_Unknown,
cgUnaryOp_COUNT,
};
enum cgBinaryOpFloat : u8 {
cgBinaryOpFloat_Unknown,
cgBinaryOpFloat_COUNT,
};
enum cgCastOp : u8 {
cgCastOp_Unknown,
cgCastOp_COUNT,
};
struct cgUser {
cgNode *node;
i32 slot;
@@ -131,38 +144,143 @@ struct cgSafepoint {
enum cgNodeKind : u8 {
cgNode_NULL,
cgNode_Branch,
cgNode_If,
cgNode_Proj,
cgNode_BranchProj,
cgNode_SymbolTable,
cgNode_Local,
// Constants
cgNode_Int,
cgNode_Int128,
cgNode_F16,
cgNode_F32,
cgNode_F64,
cgNode_Symbol,
cgNode_Compare,
cgNode_BinaryOpInt,
// Projections
// extract a single field of a tuple
cgNode_Proj,
cgNode_BranchProj,
cgNode_MemAccess,
cgNode_DebugLoc,
cgNode_Atomic,
// Misc
cgNode_SymbolTable,
cgNode_Safepoint,
cgNode_FramePtr,
cgNode_Blackhole,
// Control
cgNode_Root,
cgNode_Return,
cgNode_Region,
cgNode_Phi,
cgNode_Branch,
cgNode_If,
cgNode_DebugBreak,
cgNode_Trap,
cgNode_Unreachable,
cgNode_Dead,
cgNode_DeadStore,
// Control + Memory
cgNode_Call,
cgNode_Syscall,
cgNode_Tailcall,
cgNode_DebugLocation,
// Memory
cgNode_Load,
cgNode_Store,
cgNode_Memcpy,
cgNode_Memmove,
cgNode_Memzero,
cgNode_SplitMem,
cgNode_MergeMem,
cgNode_AtomicLoad,
cgNode_AtomicStore,
cgNode_AtomicXchg,
cgNode_AtomicAdd,
cgNode_AtomicAnd,
cgNode_AtomicXor,
cgNode_AtomicOr,
cgNode_AtomicPtrOff,
cgNode_AtomicCas,
cgNode_VolatileBarrier,
// Pointers
cgNode_Local,
cgNode_Symbol,
cgNode_PtrOffset,
// Conversions
cgNode_Bitcast,
cgNode_Truncate,
cgNode_FloatTruncate,
cgNode_FloatExt,
cgNode_SignExt,
cgNode_ZeroExt,
cgNode_UintToFloat,
cgNode_IntToFloat,
cgNode_FloatToInt,
cgNode_FloatToUint,
// Select
cgNode_Select,
// Bitwise Operations
cgNode_ByteSwap,
cgNode_CountLeadingZeros,
cgNode_CountTrailingZeros,
cgNode_CountOnes,
// Unary Operation
cgNode_FNeg,
// Integer Arithmetic
cgNode_And,
cgNode_Or,
cgNode_Xor,
cgNode_Add,
cgNode_Sub,
cgNode_Mul,
cgNode_Shl,
cgNode_Shr,
cgNode_Ashr,
cgNode_ROL,
cgNode_ROR,
cgNode_UDiv,
cgNode_IDiv,
cgNode_UMod,
cgNode_IMod,
// Float Arithmetic
cgNode_FAdd,
cgNode_FSub,
cgNode_FMul,
cgNode_FDiv,
cgNode_FMin,
cgNode_FMax,
// Comparisons
cgNode_Cmp_EQ,
cgNode_Cmp_NE,
cgNode_Cmp_ULT,
cgNode_Cmp_ULE,
cgNode_Cmp_ILT,
cgNode_Cmp_ILE,
cgNode_Cmp_FLT,
cgNode_Cmp_FLE,
// Float Intrinsics
cgNode_FSqrt,
cgNode_FusedMulAdd,
// 128-bit operations
cgNode_UMul64Pair,
cgNode_IMul64Pair,
// Vector Operations
cgNode_VBroadcast,
cgNode_VShuffle,
cgNode_Region,
cgNode_COUNT,
};
@@ -186,26 +304,16 @@ struct cgNode {
// ordered use-def edges
// after input_count (and up to input_capacity) goes an unordered set of nodes
// which act as extra deps, storing things like anti-deps and other scheduling related edges
cgNode **inputs_;
cgNode **inputs;
// def-use edges, unordered
cgUser * users_;
cgUser * users;
Type *odin_type; // usually `nullptr`
cgNode *inputs(isize index) {
GB_ASSERT(0 <= index && index < this->input_count);
return this->inputs_[index];
}
cgNode *unordered_inputs(isize index) {
GB_ASSERT(0 <= index && index < (this->input_capacity - this->input_count));
return this->inputs_[index+this->input_count];
}
template <typename T> T * downcast() { return reinterpret_cast<T *>(this); }
template <typename T> T const *downcast() const { return reinterpret_cast<T *>(this); }
cgUser &users(isize index) {
GB_ASSERT(0 <= index && index < this->user_count);
return this->users_[index];
}
};
struct cgNodeBranch : cgNode {
@@ -231,6 +339,11 @@ struct cgNodeBranchProj : cgNode {
u64 taken;
i64 key;
};
struct cgNodeSelect : cgNode {
cgNodeSelect() : cgNode{cgNode_Select} {}
};
struct cgNodeSymbolTable : cgNode {
cgNodeSymbolTable() : cgNode{cgNode_SymbolTable} {}
@@ -252,7 +365,7 @@ struct cgNodeLocal : cgNode {
struct cgNodeInt : cgNode {
cgNodeInt() : cgNode{cgNode_Int} {}
u64 value;
u64 val;
};
struct cgNodeInt128 : cgNode {
cgNodeInt128() : cgNode{cgNode_Int128} {}
@@ -278,30 +391,31 @@ struct cgNodeF64 : cgNode {
};
struct cgNodeSymbol : cgNode {
cgNodeSymbol() : cgNode{cgNode_Symbol} {}
};
struct cgNodeCompare : cgNode {
cgNodeCompare() : cgNode{cgNode_Compare} {}
cgCompareOp op;
cgType type;
cgSymbol *symbol;
};
struct cgNodeBinaryOpInt : cgNode {
cgNodeBinaryOpInt() : cgNode{cgNode_BinaryOpInt} {}
cgBinaryOpInt op;
struct cgNodeCast : cgNode {
explicit cgNodeCast(cgNodeKind kind) : cgNode{kind} {}
};
struct cgNodeUnary : cgNode {
explicit cgNodeUnary(cgNodeKind kind) : cgNode{kind} {}
};
struct cgNodeBinary : cgNode {
explicit cgNodeBinary(cgNodeKind kind) : cgNode{kind} {}
};
struct cgNodeMemAccess : cgNode {
cgNodeMemAccess() : cgNode{cgNode_MemAccess} {}
explicit cgNodeMemAccess(cgNodeKind kind) : cgNode{kind} {}
u32 align;
};
struct cgNodeDebugLoc : cgNode {
cgNodeDebugLoc() : cgNode{cgNode_DebugLoc} {}
struct cgNodeDebugLocation : cgNode {
cgNodeDebugLocation() : cgNode{cgNode_DebugLocation} {}
TokenPos pos;
};
struct cgNodeAtomic : cgNode {
cgNodeAtomic() : cgNode{cgNode_Atomic} {}
explicit cgNodeAtomic(cgNodeKind kind) : cgNode{kind} {}
cgMemoryOrder order;
cgMemoryOrder order_fail;
@@ -329,15 +443,38 @@ struct cgNodeRegion : cgNode {
String name;
};
struct cgNodePhi : cgNode {
cgNodePhi() : cgNode{cgNode_Phi} {}
};
template <typename T>
gb_internal T *cg_alloc_node(cgProcedure *p, cgType type, isize input_count, isize input_capacity, Type *odin_type=nullptr);
gb_internal T *cg_alloc_node(cgProcedure *p, cgType type, isize input_count, isize input_capacity=0, Type *odin_type=nullptr);
template <typename T>
gb_internal T *cg_alloc_node_with_kind(cgProcedure *p, cgNodeKind kind, cgType type, isize input_count, isize input_capacity=0, Type *odin_type=nullptr);
/////////////////
// Builder API //
/////////////////
#define CG_PEEP_PROC(name) cgNode *name(cgProcedure *p, cgNode *n)
typedef CG_PEEP_PROC(cgPeepProc);
struct cgGraphBuilder {
cgProcedure *p;
Arena *arena;
cgNode *curr;
cgNodeSymbolTable *start_symbol_table;
cgPeepProc *peep_callback;
Slice<cgNode *> params;
};
gb_internal cgGraphBuilder *cg_builder_enter(cgProcedure *p, Type *odin_signature);
gb_internal void cg_builder_exit(cgGraphBuilder *b);
@@ -352,20 +489,20 @@ gb_internal cgNode *cg_builder_symbol(cgGraphBuilder *b, cgSymbol *s);
gb_internal cgNode *cg_builder_string_ptr(cgGraphBuilder *b, String str);
gb_internal cgNode *cg_builder_binary_op_int(cgGraphBuilder *b, cgBinaryOpInt op, cgNode *x, cgNode *y);
gb_internal cgNode *cg_builder_binary_op_float(cgGraphBuilder *b, cgBinaryOpInt op, cgNode *x, cgNode *y);
gb_internal cgNode *cg_builder_binary_op_int(cgGraphBuilder *b, cgNodeKind op, cgNode *x, cgNode *y);
gb_internal cgNode *cg_builder_binary_op_float(cgGraphBuilder *b, cgNodeKind op, cgNode *x, cgNode *y);
gb_internal cgNode *cg_builder_select(cgGraphBuilder *b, cgNode *cond, cgNode *x, cgNode *y);
gb_internal cgNode *cg_builder_cast(cgGraphBuilder *b, cgType type, cgCastOp op, cgNode *src);
gb_internal cgNode *cg_builder_cast(cgGraphBuilder *b, cgType type, cgNodeKind op, cgNode *src);
gb_internal cgNode *cg_builder_unary(cgGraphBuilder *b, cgUnaryOp op, cgNode *src);
gb_internal cgNode *cg_builder_unary(cgGraphBuilder *b, cgNodeKind op, cgNode *src);
gb_internal cgNode *cg_builder_neg(cgGraphBuilder *b, cgNode *src);
gb_internal cgNode *cg_builder_not(cgGraphBuilder *b, cgNode *src);
gb_internal cgNode *cg_builder_cmp(cgGraphBuilder *b, cgCompareOp op, cgNode *x, cgNode *y);
gb_internal cgNode *cg_builder_cmp(cgGraphBuilder *b, cgNodeKind op, cgNode *x, cgNode *y);
// base + index*stride
gb_internal cgNode *cg_builder_ptr_array(cgGraphBuilder *b, cgNode *base, cgNode *index, i64 stride);
gb_internal cgNode *cg_builder_ptr_array(cgGraphBuilder *b, cgNode *base, cgNode *index, u64 stride);
// base + offset
gb_internal cgNode *cg_builder_ptr_member(cgGraphBuilder *b, cgNode *base, i64 offset);
@@ -378,7 +515,7 @@ gb_internal cgNode *cg_builder_memzero(cgGraphBuilder *b, int mem_var, bool ctrl
gb_internal cgNode *cg_builder_local(cgGraphBuilder *b, u32 size, u32 align);
gb_internal cgNode *cg_builder_local_debug(cgGraphBuilder *b, cgNode *n, String name, Type *odin_type);
gb_internal cgNode *cg_builder_local_debug(cgGraphBuilder *b, String name, Type *odin_type);
gb_internal cgNode *cg_builder_frame_ptr(cgGraphBuilder *b);
@@ -386,13 +523,12 @@ gb_internal cgNode *cg_builder_frame_ptr(cgGraphBuilder *b);
// Control Flow Primitives using Regions
gb_internal cgNode *cg_builder_label(cgGraphBuilder *b, cgNode *label=nullptr, bool allow_backward_jumps=false);
// Once a labe is complete, you can no longer insert jumps into it.
// Once a label is complete, you can no longer insert jumps into it.
// The phi nodes are placed and you can then insert code into the label's body.
gb_internal cgNode *cg_builder_label_complete(cgGraphBuilder *b, cgNode *label);
gb_internal void cg_builder_label_complete(cgGraphBuilder *b, cgNode *label);
gb_internal void cg_builder_label_kill(cgGraphBuilder *b, cgNode *label);
gb_internal cgNode *cg_builder_if(cgGraphBuilder *b, cgNode *cond, cgNode *x, cgNode *y);
gb_internal cgNode *cg_builder_if(cgGraphBuilder *b, cgNode *cond, cgNode *paths[2]);
gb_internal void cg_builder_jump(cgGraphBuilder *b, cgNode *target);
gb_internal cgNode *cg_builder_loop(cgGraphBuilder *b);
gb_internal cgNode *cg_builder_phi(cgGraphBuilder *b, Slice<cgNode *> vals);
@@ -405,7 +541,7 @@ gb_internal cgNode *cg_builder_case_key(cgGraphBuilder *b, cgNode *br_syms, u64
gb_internal void cg_builder_ret(cgGraphBuilder *b, int mem_var, Slice<cgNode *> args);
gb_internal void cg_builder_unreachable(cgGraphBuilder *b, int mem_var);
gb_internal void cg_builder_trap(cgGraphBuilder *b, int mem_var);
gb_internal void cg_builder_debug_trap(cgGraphBuilder *b, int mem_var);
gb_internal void cg_builder_debug_break(cgGraphBuilder *b, int mem_var);
// All the passed arguments have their lifetimes anchored to this points
gb_internal void cg_builder_black_hole(cgGraphBuilder *b, Slice<cgNode *> args);
@@ -529,12 +665,20 @@ struct cgGlobal : cgSymbol {
};
struct cgWorklist {
Array<cgNode *> items;
Slice<u64> visited; // bit-array, with gvn as key
};
struct cgProcedure : cgSymbol {
Arena arena;
Arena temp_arena;
u32 flags;
u16 state_flags;
u32 node_count;
cgProcedure *parent;
Array<cgProcedure *> children;
@@ -553,6 +697,10 @@ struct cgProcedure : cgSymbol {
bool is_entry_point;
bool is_startup;
cgWorklist *worklist;
cgNode *root_node;
cgValue value;
};
@@ -562,4 +710,23 @@ struct cgModule {
Array<cgProcedure *> procedures;
};
};
gb_internal void cg_worklist_clear_visited(cgWorklist *wl);
gb_internal void cg_worklist_clear (cgWorklist *wl);
gb_internal void cg_worklist_remove (cgWorklist *wl, cgNode *n);
gb_internal bool cg_worklist_test (cgWorklist *wl, cgNode *n);
gb_internal bool cg_worklist_test_and_set (cgWorklist *wl, cgNode *n);
gb_internal void cg_worklist_push (cgWorklist *wl, cgNode *n);
gb_internal cgNode * cg_worklist_pop (cgWorklist *wl);
gb_internal void cg_worklist_replace (cgWorklist *wl, cgNode *n, cgNode *k);
gb_internal void cg_worklist_init (cgWorklist *wl, isize capacity);
gb_internal void cg_worklist_deinit (cgWorklist *wl);
gb_internal cgWorklist *cg_worklist_create ();
gb_internal void cg_worklist_destroy (cgWorklist *wl);
gb_internal u32 cg_type_bit_size(cgModule *m, cgTypeKind type);
gb_internal u32 cg_type_bit_size(cgModule *m, cgType type) { return cg_type_bit_size(m, type.kind); }

112
src/cg/cg_worklist.cpp Normal file
View File

@@ -0,0 +1,112 @@
gb_internal void cg_worklist_clear_visited(cgWorklist *wl) {
for_array(i, wl->visited) {
wl->visited[i] = 0;
}
}
gb_internal void cg_worklist_clear(cgWorklist *wl) {
cg_worklist_clear_visited(wl);
array_clear(&wl->items);
}
gb_internal void cg_worklist_remove(cgWorklist *wl, cgNode *n) {
u64 gvn_word = n->gvn / 64;
if (gvn_word >= cast(u64)wl->visited.count) {
return;
}
u64 gvn_mask = 1ull << (n->gvn % 64);
wl->visited[gvn_word] &= ~gvn_mask;
}
gb_internal bool cg_worklist_test(cgWorklist *wl, cgNode *n) {
u64 gvn_word = n->gvn / 64;
if (gvn_word >= cast(u64)wl->visited.count) {
return false;
}
u64 gvn_mask = 1ull << (n->gvn % 64);
return (wl->visited[gvn_word] & gvn_mask) != 0;
}
gb_internal bool cg_worklist_test_and_set(cgWorklist *wl, cgNode *n) {
u64 gvn_word = n->gvn / 64;
if (gvn_word >= cast(u64)wl->visited.count) {
isize new_capacity = gvn_word + 16;
resize_array_raw(&wl->visited.data, heap_allocator(), wl->visited.count*gb_size_of(u64), new_capacity*gb_size_of(u64));
for (isize i = wl->visited.count; i < new_capacity; i++) {
wl->visited.data[i] = 0;
}
wl->visited.count = new_capacity;
}
u64 gvn_mask = 1ull << (n->gvn % 64);
if (wl->visited[gvn_word] & gvn_mask) {
return true;
} else {
wl->visited[gvn_word] |= gvn_mask;
return false;
}
}
gb_internal void cg_worklist_push(cgWorklist *wl, cgNode *n) {
if (!cg_worklist_test_and_set(wl, n)) {
array_add(&wl->items, n);
}
}
gb_internal cgNode *cg_worklist_pop(cgWorklist *wl) {
if (wl->items.count == 0) {
return nullptr;
}
cgNode *n = array_pop(&wl->items);
u64 gvn_word = n->gvn / 64;
u64 gvn_mask = 1ull << (n->gvn % 64);
wl->visited[gvn_word] &= ~gvn_mask;
return n;
}
gb_internal void cg_worklist_replace(cgWorklist *wl, cgNode *n, cgNode *k) {
if (cg_worklist_test(wl, n)) {
for_array(i, wl->items) {
if (wl->items[i] == n) {
cg_worklist_remove(wl, n);
cg_worklist_test_and_set(wl, k);
wl->items[i] = k;
break;
}
}
}
}
gb_internal void cg_worklist_init(cgWorklist *wl, isize capacity) {
isize visited_capacity = (capacity + 63)/64;
wl->visited = slice_make<u64>(heap_allocator(), visited_capacity);
wl->items = array_make<cgNode *>(heap_allocator(), visited_capacity * 64);
cg_worklist_clear_visited(wl);
}
gb_internal void cg_worklist_deinit(cgWorklist *wl) {
array_free(&wl->items);
gb_free(heap_allocator(), wl->visited.data);
*wl = {};
}
gb_internal cgWorklist *cg_worklist_create() {
cgWorklist *wl = gb_alloc_item(heap_allocator(), cgWorklist);
cg_worklist_init(wl, 512);
return wl;
}
gb_internal void cg_worklist_destroy(cgWorklist *wl) {
cg_worklist_deinit(wl);
gb_free(heap_allocator(), wl);
}