mirror of
https://github.com/odin-lang/Odin.git
synced 2026-09-08 21:27:20 +00:00
395 lines
12 KiB
C++
395 lines
12 KiB
C++
void ssa_module_add_value(ssaModule *m, Entity *e, ssaValue *v);
|
|
|
|
|
|
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;
|
|
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<ssaValue *> 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_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_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) {
|
|
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);
|
|
} else {
|
|
return ssa_make_value_constant_slice(a, type, NULL, 0);
|
|
}
|
|
}
|
|
|
|
return ssa_make_value_constant(m->allocator, type, value);
|
|
}
|
|
|
|
|
|
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
|
|
return v;
|
|
}
|
|
|
|
ssaValue *ssa_make_value_block(ssaProcedure *proc, AstNode *node, Scope *scope, String label) {
|
|
ssaValue *v = ssa_alloc_value(proc->module->allocator, ssaValue_Block);
|
|
v->Block.label = 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());
|
|
|
|
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 *value = ssa_make_value_block(proc, node, scope, make_string(label));
|
|
ssaBlock *block = &value->Block;
|
|
array_add(&proc->blocks, block);
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|