void ssa_module_add_value(ssaModule *m, Entity *e, ssaValue *v); ssaValue *ssa_emit_zero_init(ssaProcedure *p, ssaValue *address); ssaValue *ssa_emit_comment(ssaProcedure *p, String text); ssaValue *ssa_emit_store(ssaProcedure *p, ssaValue *address, ssaValue *value); ssaValue *ssa_emit_load(ssaProcedure *p, ssaValue *address); ssaValue *ssa_alloc_value(gbAllocator a, ssaValueKind kind) { ssaValue *v = gb_alloc_item(a, ssaValue); v->kind = kind; return v; } ssaValue *ssa_alloc_instr(ssaProcedure *proc, ssaInstrKind kind) { ssaValue *v = ssa_alloc_value(proc->module->allocator, ssaValue_Instr); v->Instr.kind = kind; proc->instr_count++; return v; } ssaDebugInfo *ssa_alloc_debug_info(gbAllocator a, ssaDebugInfoKind kind) { ssaDebugInfo *di = gb_alloc_item(a, ssaDebugInfo); di->kind = kind; return di; } ssaValue *ssa_make_value_type_name(gbAllocator a, String name, Type *type) { ssaValue *v = ssa_alloc_value(a, ssaValue_TypeName); v->TypeName.name = name; v->TypeName.type = type; return v; } ssaValue *ssa_make_value_global(gbAllocator a, Entity *e, ssaValue *value) { ssaValue *v = ssa_alloc_value(a, ssaValue_Global); v->Global.entity = e; v->Global.type = make_type_pointer(a, e->type); v->Global.value = value; array_init(&v->Global.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here return v; } ssaValue *ssa_make_value_param(gbAllocator a, ssaProcedure *parent, Entity *e) { ssaValue *v = ssa_alloc_value(a, ssaValue_Param); v->Param.parent = parent; v->Param.entity = e; v->Param.type = e->type; array_init(&v->Param.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here return v; } ssaValue *ssa_make_value_nil(gbAllocator a, Type *type) { ssaValue *v = ssa_alloc_value(a, ssaValue_Nil); v->Nil.type = type; return v; } ssaValue *ssa_make_instr_local(ssaProcedure *p, Entity *e, b32 zero_initialized) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_Local); ssaInstr *i = &v->Instr; i->Local.entity = e; i->Local.type = make_type_pointer(p->module->allocator, e->type); i->Local.zero_initialized = zero_initialized; array_init(&i->Local.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here ssa_module_add_value(p->module, e, v); return v; } ssaValue *ssa_make_instr_store(ssaProcedure *p, ssaValue *address, ssaValue *value) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_Store); ssaInstr *i = &v->Instr; i->Store.address = address; i->Store.value = value; return v; } ssaValue *ssa_make_instr_zero_init(ssaProcedure *p, ssaValue *address) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_ZeroInit); ssaInstr *i = &v->Instr; i->ZeroInit.address = address; return v; } ssaValue *ssa_make_instr_load(ssaProcedure *p, ssaValue *address) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_Load); ssaInstr *i = &v->Instr; i->Load.address = address; i->Load.type = type_deref(ssa_type(address)); return v; } ssaValue *ssa_make_instr_array_element_ptr(ssaProcedure *p, ssaValue *address, ssaValue *elem_index) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_ArrayElementPtr); ssaInstr *i = &v->Instr; Type *t = ssa_type(address); GB_ASSERT(is_type_pointer(t)); t = base_type(type_deref(t)); GB_ASSERT(is_type_array(t)); Type *result_type = make_type_pointer(p->module->allocator, t->Array.elem); i->ArrayElementPtr.address = address; i->ArrayElementPtr.elem_index = elem_index; i->ArrayElementPtr.result_type = result_type; GB_ASSERT_MSG(is_type_pointer(ssa_type(address)), "%s", type_to_string(ssa_type(address))); return v; } ssaValue *ssa_make_instr_struct_element_ptr(ssaProcedure *p, ssaValue *address, i32 elem_index, Type *result_type) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_StructElementPtr); ssaInstr *i = &v->Instr; i->StructElementPtr.address = address; i->StructElementPtr.elem_index = elem_index; i->StructElementPtr.result_type = result_type; GB_ASSERT_MSG(is_type_pointer(ssa_type(address)), "%s", type_to_string(ssa_type(address))); return v; } ssaValue *ssa_make_instr_ptr_offset(ssaProcedure *p, ssaValue *address, ssaValue *offset) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_PtrOffset); ssaInstr *i = &v->Instr; i->PtrOffset.address = address; i->PtrOffset.offset = offset; GB_ASSERT_MSG(is_type_pointer(ssa_type(address)), "%s", type_to_string(ssa_type(address))); GB_ASSERT_MSG(is_type_integer(ssa_type(offset)), "%s", type_to_string(ssa_type(address))); return v; } ssaValue *ssa_make_instr_array_extract_value(ssaProcedure *p, ssaValue *address, i32 index) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_ArrayExtractValue); ssaInstr *i = &v->Instr; i->ArrayExtractValue.address = address; i->ArrayExtractValue.index = index; Type *t = base_type(ssa_type(address)); GB_ASSERT(is_type_array(t)); i->ArrayExtractValue.result_type = t->Array.elem; return v; } ssaValue *ssa_make_instr_struct_extract_value(ssaProcedure *p, ssaValue *address, i32 index, Type *result_type) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_StructExtractValue); ssaInstr *i = &v->Instr; i->StructExtractValue.address = address; i->StructExtractValue.index = index; i->StructExtractValue.result_type = result_type; return v; } ssaValue *ssa_make_instr_binary_op(ssaProcedure *p, TokenKind op, ssaValue *left, ssaValue *right, Type *type) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_BinaryOp); ssaInstr *i = &v->Instr; i->BinaryOp.op = op; i->BinaryOp.left = left; i->BinaryOp.right = right; i->BinaryOp.type = type; return v; } ssaValue *ssa_make_instr_jump(ssaProcedure *p, ssaBlock *block) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_Jump); ssaInstr *i = &v->Instr; i->Jump.block = block; return v; } ssaValue *ssa_make_instr_if(ssaProcedure *p, ssaValue *cond, ssaBlock *true_block, ssaBlock *false_block) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_If); ssaInstr *i = &v->Instr; i->If.cond = cond; i->If.true_block = true_block; i->If.false_block = false_block; return v; } ssaValue *ssa_make_instr_phi(ssaProcedure *p, Array edges, Type *type) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_Phi); ssaInstr *i = &v->Instr; i->Phi.edges = edges; i->Phi.type = type; return v; } ssaValue *ssa_make_instr_unreachable(ssaProcedure *p) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_Unreachable); return v; } ssaValue *ssa_make_instr_return(ssaProcedure *p, ssaValue *value) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_Return); v->Instr.Return.value = value; return v; } ssaValue *ssa_make_instr_select(ssaProcedure *p, ssaValue *cond, ssaValue *t, ssaValue *f) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_Select); v->Instr.Select.cond = cond; v->Instr.Select.true_value = t; v->Instr.Select.false_value = f; return v; } ssaValue *ssa_make_instr_call(ssaProcedure *p, ssaValue *value, ssaValue **args, isize arg_count, Type *result_type) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_Call); v->Instr.Call.value = value; v->Instr.Call.args = args; v->Instr.Call.arg_count = arg_count; v->Instr.Call.type = result_type; return v; } ssaValue *ssa_make_instr_conv(ssaProcedure *p, ssaConvKind kind, ssaValue *value, Type *from, Type *to) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_Conv); v->Instr.Conv.kind = kind; v->Instr.Conv.value = value; v->Instr.Conv.from = from; v->Instr.Conv.to = to; return v; } ssaValue *ssa_make_instr_extract_element(ssaProcedure *p, ssaValue *vector, ssaValue *index) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_VectorExtractElement); v->Instr.VectorExtractElement.vector = vector; v->Instr.VectorExtractElement.index = index; return v; } ssaValue *ssa_make_instr_insert_element(ssaProcedure *p, ssaValue *vector, ssaValue *elem, ssaValue *index) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_VectorInsertElement); v->Instr.VectorInsertElement.vector = vector; v->Instr.VectorInsertElement.elem = elem; v->Instr.VectorInsertElement.index = index; return v; } ssaValue *ssa_make_instr_vector_shuffle(ssaProcedure *p, ssaValue *vector, i32 *indices, isize index_count) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_VectorShuffle); v->Instr.VectorShuffle.vector = vector; v->Instr.VectorShuffle.indices = indices; v->Instr.VectorShuffle.index_count = index_count; Type *vt = base_type(ssa_type(vector)); v->Instr.VectorShuffle.type = make_type_vector(p->module->allocator, vt->Vector.elem, index_count); return v; } ssaValue *ssa_make_instr_comment(ssaProcedure *p, String text) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_Comment); v->Instr.Comment.text = text; return v; } ssaValue *ssa_make_instr_bounds_check(ssaProcedure *p, TokenPos pos, ssaValue *index, ssaValue *len) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_BoundsCheck); v->Instr.BoundsCheck.pos = pos; v->Instr.BoundsCheck.index = index; v->Instr.BoundsCheck.len = len; return v; } ssaValue *ssa_make_instr_slice_bounds_check(ssaProcedure *p, TokenPos pos, ssaValue *low, ssaValue *high, ssaValue *max, b32 is_substring) { ssaValue *v = ssa_alloc_instr(p, ssaInstr_SliceBoundsCheck); v->Instr.SliceBoundsCheck.pos = pos; v->Instr.SliceBoundsCheck.low = low; v->Instr.SliceBoundsCheck.high = high; v->Instr.SliceBoundsCheck.max = max; v->Instr.SliceBoundsCheck.is_substring = is_substring; return v; } ssaValue *ssa_make_value_constant(gbAllocator a, Type *type, ExactValue value) { ssaValue *v = ssa_alloc_value(a, ssaValue_Constant); v->Constant.type = type; v->Constant.value = value; return v; } ssaValue *ssa_make_value_constant_slice(gbAllocator a, Type *type, ssaValue *backing_array, i64 count) { ssaValue *v = ssa_alloc_value(a, ssaValue_ConstantSlice); v->ConstantSlice.type = type; v->ConstantSlice.backing_array = backing_array; v->ConstantSlice.count = count; return v; } ssaValue *ssa_make_const_int(gbAllocator a, i64 i) { return ssa_make_value_constant(a, t_int, make_exact_value_integer(i)); } ssaValue *ssa_make_const_i32(gbAllocator a, i64 i) { return ssa_make_value_constant(a, t_i32, make_exact_value_integer(i)); } ssaValue *ssa_make_const_i64(gbAllocator a, i64 i) { return ssa_make_value_constant(a, t_i64, make_exact_value_integer(i)); } ssaValue *ssa_make_const_bool(gbAllocator a, b32 b) { return ssa_make_value_constant(a, t_bool, make_exact_value_bool(b != 0)); } ssaValue *ssa_make_const_string(gbAllocator a, String s) { return ssa_make_value_constant(a, t_string, make_exact_value_string(s)); } ssaValue *ssa_make_value_procedure(gbAllocator a, ssaModule *m, Entity *entity, Type *type, AstNode *type_expr, AstNode *body, String name) { ssaValue *v = ssa_alloc_value(a, ssaValue_Proc); v->Proc.module = m; v->Proc.entity = entity; v->Proc.type = type; v->Proc.type_expr = type_expr; v->Proc.body = body; v->Proc.name = name; array_init(&v->Proc.referrers, heap_allocator(), 0); // TODO(bill): replace heap allocator Type *t = base_type(type); GB_ASSERT(is_type_proc(t)); array_init(&v->Proc.params, heap_allocator(), t->Proc.param_count); return v; } ssaBlock *ssa_add_block(ssaProcedure *proc, AstNode *node, char *label) { Scope *scope = NULL; if (node != NULL) { Scope **found = map_get(&proc->module->info->scopes, hash_pointer(node)); if (found) { scope = *found; } else { GB_PANIC("Block scope not found for %.*s", LIT(ast_node_strings[node->kind])); } } ssaValue *v = ssa_alloc_value(proc->module->allocator, ssaValue_Block); v->Block.label = make_string(label); v->Block.node = node; v->Block.scope = scope; v->Block.parent = proc; array_init(&v->Block.instrs, heap_allocator()); array_init(&v->Block.locals, heap_allocator()); array_init(&v->Block.preds, heap_allocator()); array_init(&v->Block.succs, heap_allocator()); ssaBlock *block = &v->Block; array_add(&proc->blocks, block); proc->block_count++; return block; } ssaDefer ssa_add_defer_node(ssaProcedure *proc, isize scope_index, AstNode *stmt) { ssaDefer d = {ssaDefer_Node}; d.scope_index = scope_index; d.block = proc->curr_block; d.stmt = stmt; array_add(&proc->defer_stmts, d); return d; } ssaDefer ssa_add_defer_instr(ssaProcedure *proc, isize scope_index, ssaValue *instr) { ssaDefer d = {ssaDefer_Instr}; d.scope_index = proc->scope_index; d.block = proc->curr_block; d.instr = instr; // NOTE(bill): It will make a copy everytime it is called array_add(&proc->defer_stmts, d); return d; } ssaValue *ssa_add_module_constant(ssaModule *m, Type *type, ExactValue value) { if (is_type_slice(type)) { ast_node(cl, CompoundLit, value.value_compound); gbAllocator a = m->allocator; isize count = cl->elems.count; if (count == 0) { return ssa_make_value_nil(a, type); } Type *elem = base_type(type)->Slice.elem; Type *t = make_type_array(a, elem, count); ssaValue *backing_array = ssa_add_module_constant(m, t, value); isize max_len = 7+8+1; u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len); isize len = gb_snprintf(cast(char *)str, max_len, "__csba$%x", m->global_array_index); m->global_array_index++; String name = make_string(str, len-1); Entity *e = make_entity_constant(a, NULL, make_token_ident(name), t, value); ssaValue *g = ssa_make_value_global(a, e, backing_array); ssa_module_add_value(m, e, g); map_set(&m->members, hash_string(name), g); return ssa_make_value_constant_slice(a, type, g, count); } return ssa_make_value_constant(m->allocator, type, value); } ssaValue *ssa_add_global_string_array(ssaModule *m, String string) { gbAllocator a = m->allocator; isize max_len = 6+8+1; u8 *str = cast(u8 *)gb_alloc_array(a, u8, max_len); isize len = gb_snprintf(cast(char *)str, max_len, "__str$%x", m->global_string_index); m->global_string_index++; String name = make_string(str, len-1); Token token = {Token_String}; token.string = name; Type *type = make_type_array(a, t_u8, string.len); ExactValue ev = make_exact_value_string(string); Entity *entity = make_entity_constant(a, NULL, token, type, ev); ssaValue *g = ssa_make_value_global(a, entity, ssa_add_module_constant(m, type, ev)); g->Global.is_private = true; // g->Global.is_unnamed_addr = true; // g->Global.is_constant = true; ssa_module_add_value(m, entity, g); map_set(&m->members, hash_string(name), g); return g; } ssaValue *ssa_add_local(ssaProcedure *proc, Entity *e, b32 zero_initialized = true) { ssaBlock *b = proc->decl_block; // all variables must be in the first block ssaValue *instr = ssa_make_instr_local(proc, e, zero_initialized); instr->Instr.parent = b; array_add(&b->instrs, instr); array_add(&b->locals, instr); proc->local_count++; // if (zero_initialized) { ssa_emit_zero_init(proc, instr); // } return instr; } ssaValue *ssa_add_local_for_identifier(ssaProcedure *proc, AstNode *name, b32 zero_initialized) { Entity **found = map_get(&proc->module->info->definitions, hash_pointer(name)); if (found) { Entity *e = *found; ssa_emit_comment(proc, e->token.string); return ssa_add_local(proc, e, zero_initialized); } return NULL; } ssaValue *ssa_add_local_generated(ssaProcedure *proc, Type *type) { GB_ASSERT(type != NULL); Scope *scope = NULL; if (proc->curr_block) { scope = proc->curr_block->scope; } Entity *e = make_entity_variable(proc->module->allocator, scope, empty_token, type); return ssa_add_local(proc, e, true); } ssaValue *ssa_add_param(ssaProcedure *proc, Entity *e) { ssaValue *v = ssa_make_value_param(proc->module->allocator, proc, e); #if 1 ssaValue *l = ssa_add_local(proc, e); ssa_emit_store(proc, l, v); #else ssa_module_add_value(proc->module, e, v); #endif return v; }