From 2a10c8fe5c9d27e1a110346ef423c1cadc95daa3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 14 Jul 2023 13:01:17 +0100 Subject: Begin work on building statements --- src/tilde_stmt.cpp | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 src/tilde_stmt.cpp (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp new file mode 100644 index 000000000..c277eae03 --- /dev/null +++ b/src/tilde_stmt.cpp @@ -0,0 +1,287 @@ +gb_internal cgBranchBlocks cg_lookup_branch_blocks(cgProcedure *p, Ast *ident) { + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_node(ident); + GB_ASSERT(e->kind == Entity_Label); + for (cgBranchBlocks const &b : p->branch_blocks) { + if (b.label == e->Label.node) { + return b; + } + } + + GB_PANIC("Unreachable"); + cgBranchBlocks empty = {}; + return empty; +} + +gb_internal cgTargetList *cg_push_target_list(cgProcedure *p, Ast *label, TB_Node *break_, TB_Node *continue_, TB_Node *fallthrough_) { + cgTargetList *tl = gb_alloc_item(permanent_allocator(), cgTargetList); + tl->prev = p->target_list; + tl->break_ = break_; + tl->continue_ = continue_; + tl->fallthrough_ = fallthrough_; + p->target_list = tl; + + if (label != nullptr) { // Set label blocks + GB_ASSERT(label->kind == Ast_Label); + + for (cgBranchBlocks &b : p->branch_blocks) { + GB_ASSERT(b.label != nullptr && label != nullptr); + GB_ASSERT(b.label->kind == Ast_Label); + if (b.label == label) { + b.break_ = break_; + b.continue_ = continue_; + return tl; + } + } + + GB_PANIC("Unreachable"); + } + + return tl; +} + +gb_internal void cg_pop_target_list(cgProcedure *p) { + p->target_list = p->target_list->prev; +} + +gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init) { + char const *name = ""; + if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { + // NOTE(bill): for debugging purposes only + name = alloc_cstring(permanent_allocator(), e->token.string); + } + + isize size = type_size_of(type); + TB_CharUnits alignment = cast(TB_CharUnits)type_align_of(type); + if (is_type_matrix(type)) { + alignment *= 2; // NOTE(bill): Just in case + } + + TB_Node *local = tb_inst_local(p->func, cast(u32)size, alignment); + + if (zero_init) { + bool is_volatile = false; + TB_Node *zero = tb_inst_uint(p->func, TB_TYPE_I8, 0); + TB_Node *count = tb_inst_uint(p->func, TB_TYPE_I32, cast(u64)size); + tb_inst_memset(p->func, local, zero, count, alignment, is_volatile); + } + + return cg_addr(cg_value(local, alloc_type_pointer(type))); +} + + +gb_internal void cg_scope_open(cgProcedure *p, Scope *scope) { + // TODO(bill): cg_scope_open +} + +gb_internal void cg_scope_close(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region, bool pop_stack=true) { + // TODO(bill): cg_scope_close +} + +gb_internal void cg_emit_defer_stmts(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region) { + // TODO(bill): cg_emit_defer_stmts +} + +gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { + Ast *prev_stmt = p->curr_stmt; + defer (p->curr_stmt = prev_stmt); + p->curr_stmt = node; + + // TODO(bill): check if last instruction was a terminating one or not + + { + TokenPos pos = ast_token(node).pos; + TB_FileID *file_id = map_get(&p->module->file_id_map, cast(uintptr)pos.file_id); + if (file_id) { + tb_inst_set_location(p->func, *file_id, pos.line); + } + } + + u16 prev_state_flags = p->state_flags; + defer (p->state_flags = prev_state_flags); + + if (node->state_flags != 0) { + u16 in = node->state_flags; + u16 out = p->state_flags; + + if (in & StateFlag_bounds_check) { + out |= StateFlag_bounds_check; + out &= ~StateFlag_no_bounds_check; + } else if (in & StateFlag_no_bounds_check) { + out |= StateFlag_no_bounds_check; + out &= ~StateFlag_bounds_check; + } + if (in & StateFlag_no_type_assert) { + out |= StateFlag_no_type_assert; + out &= ~StateFlag_type_assert; + } else if (in & StateFlag_type_assert) { + out |= StateFlag_type_assert; + out &= ~StateFlag_no_type_assert; + } + + p->state_flags = out; + } + + switch (node->kind) { + case_ast_node(bs, EmptyStmt, node); + case_end; + + case_ast_node(us, UsingStmt, node); + case_end; + + case_ast_node(ws, WhenStmt, node); + cg_build_when_stmt(p, ws); + case_end; + + case_ast_node(bs, BlockStmt, node); + TB_Node *done = nullptr; + if (bs->label != nullptr) { + done = tb_inst_region(p->func); + tb_inst_set_region_name(done, -1, "block.done"); + cgTargetList *tl = cg_push_target_list(p, bs->label, done, nullptr, nullptr); + tl->is_block = true; + } + + cg_scope_open(p, bs->scope); + cg_build_stmt_list(p, bs->stmts); + cg_scope_close(p, cgDeferExit_Default, nullptr); + + if (done != nullptr) { + tb_inst_goto(p->func, done); + tb_inst_set_control(p->func, done); + } + + if (bs->label != nullptr) { + cg_pop_target_list(p); + } + case_end; + + case_ast_node(vd, ValueDecl, node); + if (!vd->is_mutable) { + return; + } + + bool is_static = false; + if (vd->names.count > 0) { + for (Ast *name : vd->names) { + if (!is_blank_ident(name)) { + GB_ASSERT(name->kind == Ast_Ident); + Entity *e = entity_of_node(name); + TokenPos pos = ast_token(name).pos; + GB_ASSERT_MSG(e != nullptr, "\n%s missing entity for %.*s", token_pos_to_string(pos), LIT(name->Ident.token.string)); + if (e->flags & EntityFlag_Static) { + // NOTE(bill): If one of the entities is static, they all are + is_static = true; + break; + } + } + } + } + if (is_static) { + GB_PANIC("TODO(bill): build static variables"); + return; + } + + TEMPORARY_ALLOCATOR_GUARD(); + + auto const &values = vd->values; + if (values.count == 0) { + for (Ast *name : vd->names) { + if (!is_blank_ident(name)) { + Entity *e = entity_of_node(name); + bool zero_init = true; + cgAddr addr = cg_add_local(p, e->type, e, zero_init); + gb_unused(addr); + } + } + } else { + GB_PANIC("TODO multiple variables"); + } + case_end; + + case_ast_node(bs, BranchStmt, node); + TB_Node *prev_block = tb_inst_get_control(p->func); + + TB_Node *block = nullptr; + + if (bs->label != nullptr) { + cgBranchBlocks bb = cg_lookup_branch_blocks(p, bs->label); + switch (bs->token.kind) { + case Token_break: block = bb.break_; break; + case Token_continue: block = bb.continue_; break; + case Token_fallthrough: + GB_PANIC("fallthrough cannot have a label"); + break; + } + } else { + for (cgTargetList *t = p->target_list; t != nullptr && block == nullptr; t = t->prev) { + if (t->is_block) { + continue; + } + + switch (bs->token.kind) { + case Token_break: block = t->break_; break; + case Token_continue: block = t->continue_; break; + case Token_fallthrough: block = t->fallthrough_; break; + } + } + } + if (block != nullptr) { + cg_emit_defer_stmts(p, cgDeferExit_Branch, block); + } + + + tb_inst_goto(p->func, block); + tb_inst_set_control(p->func, block); + tb_inst_unreachable(p->func); + + tb_inst_set_control(p->func, prev_block); + case_end; + + default: + GB_PANIC("TODO cg_build_stmt %.*s", LIT(ast_strings[node->kind])); + break; + } +} + + +gb_internal void cg_build_stmt_list(cgProcedure *p, Slice const &stmts) { + for (Ast *stmt : stmts) { + switch (stmt->kind) { + case_ast_node(vd, ValueDecl, stmt); + // TODO(bill) + // cg_build_constant_value_decl(p, vd); + case_end; + case_ast_node(fb, ForeignBlockDecl, stmt); + ast_node(block, BlockStmt, fb->body); + cg_build_stmt_list(p, block->stmts); + case_end; + } + } + for (Ast *stmt : stmts) { + cg_build_stmt(p, stmt); + } +} + + +gb_internal void cg_build_when_stmt(cgProcedure *p, AstWhenStmt *ws) { + TypeAndValue tv = type_and_value_of_expr(ws->cond); + GB_ASSERT(is_type_boolean(tv.type)); + GB_ASSERT(tv.value.kind == ExactValue_Bool); + if (tv.value.value_bool) { + cg_build_stmt_list(p, ws->body->BlockStmt.stmts); + } else if (ws->else_stmt) { + switch (ws->else_stmt->kind) { + case Ast_BlockStmt: + cg_build_stmt_list(p, ws->else_stmt->BlockStmt.stmts); + break; + case Ast_WhenStmt: + cg_build_when_stmt(p, &ws->else_stmt->WhenStmt); + break; + default: + GB_PANIC("Invalid 'else' statement in 'when' statement"); + break; + } + } +} + -- cgit v1.2.3 From 6545cc2d48553e3129ef8e925531a1ca7e03e8a6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 14 Jul 2023 14:54:49 +0100 Subject: Stub out expr and const files --- src/tilde_backend.cpp | 167 ++++++++++++++++++++++++++++++++------------------ src/tilde_backend.hpp | 2 + src/tilde_const.cpp | 5 ++ src/tilde_expr.cpp | 68 ++++++++++++++++++++ src/tilde_stmt.cpp | 105 +++++++++++++++++++++++++++++-- 5 files changed, 283 insertions(+), 64 deletions(-) create mode 100644 src/tilde_const.cpp create mode 100644 src/tilde_expr.cpp (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index dd3c8e537..8009a7703 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -458,6 +458,22 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty case Basic_f64be: param.dt = TB_TYPE_F64; break; } + case Type_Pointer: + case Type_MultiPointer: + case Type_Proc: + param.dt = TB_TYPE_PTR; + break; + + default: + switch (sz) { + case 1: param.dt = TB_TYPE_I8; break; + case 2: param.dt = TB_TYPE_I16; break; + case 4: param.dt = TB_TYPE_I32; break; + case 8: param.dt = TB_TYPE_I64; break; + default: + param.dt = TB_TYPE_PTR; + break; + } } if (param.dt.width != 0) { @@ -468,7 +484,13 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty } } - return tb_prototype_create(m->mod, TB_CDECL, params.count, params.data, 0, nullptr, false); + auto results = array_make(heap_allocator(), 0, pt->result_count); + // if (pt->results) for (Entity *e : pt->params->Tuple.variables) { + // // TODO(bill): + // } + + + return tb_prototype_create(m->mod, TB_CDECL, params.count, params.data, results.count, results.data, pt->c_vararg); } gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool ignore_body=false) { @@ -619,7 +641,8 @@ gb_internal void cg_procedure_generate(cgProcedure *p) { cg_procedure_begin(p); defer (cg_procedure_end(p)); - if (p->name != "bug.main") { + if (p->name != "bug.main" && + p->name != "main") { return; } if (p->body != nullptr) { @@ -628,8 +651,12 @@ gb_internal void cg_procedure_generate(cgProcedure *p) { } +#include "tilde_const.cpp" +#include "tilde_expr.cpp" #include "tilde_stmt.cpp" + + gb_internal bool cg_generate_code(Checker *c) { TIME_SECTION("Tilde Module Initializtion"); @@ -722,88 +749,110 @@ gb_internal bool cg_generate_code(Checker *c) { cg_procedure_generate(m->procedures_to_generate[i]); } + TB_DebugFormat debug_format = TB_DEBUGFMT_NONE; + if (build_context.ODIN_DEBUG) { + switch (build_context.metrics.os) { + case TargetOs_windows: + debug_format = TB_DEBUGFMT_CODEVIEW; + break; + case TargetOs_darwin: + case TargetOs_linux: + case TargetOs_essence: + case TargetOs_freebsd: + case TargetOs_openbsd: + debug_format = TB_DEBUGFMT_DWARF; + break; + } + } + TB_ExportBuffer export_buffer = tb_module_object_export(m->mod, debug_format); + defer (tb_export_buffer_free(export_buffer)); + + char const *path = "W:/Odin/tilde_main.obj"; + GB_ASSERT(tb_export_buffer_to_file(export_buffer, path)); //////////////////////////////////////////////////////////////////////////////////// - TB_Arena *arena = tb_default_arena(); + // TB_Arena *arena = tb_default_arena(); - TB_Global *str = nullptr; - { - TB_Global *str_data = nullptr; - { - str_data = tb_global_create(m->mod, "csb$1", nullptr, TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_data, 8, 1, 1); - void *region = tb_global_add_region(m->mod, str_data, 0, 8); - memcpy(region, "Hellope\x00", 8); - } + // TB_Global *str = nullptr; + // { + // TB_Global *str_data = nullptr; + // { + // str_data = tb_global_create(m->mod, "csb$1", nullptr, TB_LINKAGE_PRIVATE); + // tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_data, 8, 1, 1); + // void *region = tb_global_add_region(m->mod, str_data, 0, 8); + // memcpy(region, "Hellope\x00", 8); + // } - str = tb_global_create(m->mod, "global$str", nullptr, TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str, 16, 8, 2); - tb_global_add_symbol_reloc(m->mod, str, 0, cast(TB_Symbol *)str_data); - void *len = tb_global_add_region(m->mod, str, 8, 8); - *cast(i64 *)len = 7; - } + // str = tb_global_create(m->mod, "global$str", nullptr, TB_LINKAGE_PRIVATE); + // tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str, 16, 8, 2); + // tb_global_add_symbol_reloc(m->mod, str, 0, cast(TB_Symbol *)str_data); + // void *len = tb_global_add_region(m->mod, str, 8, 8); + // *cast(i64 *)len = 7; + // } - { - TB_PrototypeParam printf_ret = {TB_TYPE_I32}; - TB_PrototypeParam printf_params = {TB_TYPE_PTR}; - TB_FunctionPrototype *printf_proto = tb_prototype_create(m->mod, TB_STDCALL, 1, &printf_params, 1, &printf_ret, true); - TB_External *printf_proc = tb_extern_create(m->mod, "printf", TB_EXTERNAL_SO_LOCAL); + // { + // TB_PrototypeParam printf_ret = {TB_TYPE_I32}; + // TB_PrototypeParam printf_params = {TB_TYPE_PTR}; + // TB_FunctionPrototype *printf_proto = tb_prototype_create(m->mod, TB_STDCALL, 1, &printf_params, 1, &printf_ret, true); + // TB_External *printf_proc = tb_extern_create(m->mod, "printf", TB_EXTERNAL_SO_LOCAL); - TB_PrototypeParam main_ret = {TB_TYPE_I32}; - TB_FunctionPrototype *main_proto = tb_prototype_create(m->mod, TB_STDCALL, 0, nullptr, 1, &main_ret, false); - TB_Function * p = tb_function_create(m->mod, "main", TB_LINKAGE_PUBLIC, TB_COMDAT_NONE); - tb_function_set_prototype(p, main_proto, arena); + // TB_PrototypeParam main_ret = {TB_TYPE_I32}; + // TB_FunctionPrototype *main_proto = tb_prototype_create(m->mod, TB_STDCALL, 0, nullptr, 1, &main_ret, false); + // TB_Function * p = tb_function_create(m->mod, "main", TB_LINKAGE_PUBLIC, TB_COMDAT_NONE); + // tb_function_set_prototype(p, main_proto, arena); - auto str_ptr = tb_inst_get_symbol_address(p, cast(TB_Symbol *)str); - auto str_data_ptr_ptr = tb_inst_member_access(p, str_ptr, 0); - auto str_data_ptr = tb_inst_load(p, TB_TYPE_PTR, str_data_ptr_ptr, 1, false); - auto str_len_ptr = tb_inst_member_access(p, str_ptr, 8); - auto str_len = tb_inst_load(p, TB_TYPE_I64, str_len_ptr, 8, false); + // auto str_ptr = tb_inst_get_symbol_address(p, cast(TB_Symbol *)str); + // auto str_data_ptr_ptr = tb_inst_member_access(p, str_ptr, 0); + // auto str_data_ptr = tb_inst_load(p, TB_TYPE_PTR, str_data_ptr_ptr, 1, false); + // auto str_len_ptr = tb_inst_member_access(p, str_ptr, 8); + // auto str_len = tb_inst_load(p, TB_TYPE_I64, str_len_ptr, 8, false); - TB_Node *params[4] = {}; - params[0] = tb_inst_cstring(p, "%.*s %s!\n"); - params[1] = tb_inst_trunc(p, str_len, TB_TYPE_I32); - params[2] = str_data_ptr; - params[3] = tb_inst_cstring(p, "World"); - TB_MultiOutput output = tb_inst_call(p, printf_proto, tb_inst_get_symbol_address(p, cast(TB_Symbol *)printf_proc), gb_count_of(params), params); - gb_unused(output); - TB_Node *printf_return_value = output.single; + // TB_Node *params[4] = {}; + // params[0] = tb_inst_cstring(p, "%.*s %s!\n"); + // params[1] = tb_inst_trunc(p, str_len, TB_TYPE_I32); + // params[2] = str_data_ptr; + // params[3] = tb_inst_cstring(p, "World"); + // TB_MultiOutput output = tb_inst_call(p, printf_proto, tb_inst_get_symbol_address(p, cast(TB_Symbol *)printf_proc), gb_count_of(params), params); + // gb_unused(output); + // TB_Node *printf_return_value = output.single; - TB_Node *zero = tb_inst_uint(p, TB_TYPE_I32, 0); - TB_Node *one = tb_inst_uint(p, TB_TYPE_I32, 1); + // TB_Node *zero = tb_inst_uint(p, TB_TYPE_I32, 0); + // TB_Node *one = tb_inst_uint(p, TB_TYPE_I32, 1); - TB_Node *prev_case = tb_inst_get_control(p); + // TB_Node *prev_case = tb_inst_get_control(p); - TB_Node *true_case = tb_inst_region(p); - TB_Node *false_case = tb_inst_region(p); + // TB_Node *true_case = tb_inst_region(p); + // TB_Node *false_case = tb_inst_region(p); - TB_Node *cond = tb_inst_cmp_igt(p, printf_return_value, zero, true); - tb_inst_if(p, cond, true_case, false_case); + // TB_Node *cond = tb_inst_cmp_igt(p, printf_return_value, zero, true); + // tb_inst_if(p, cond, true_case, false_case); - tb_inst_set_control(p, true_case); - tb_inst_ret(p, 1, &zero); + // tb_inst_set_control(p, true_case); + // tb_inst_ret(p, 1, &zero); - tb_inst_set_control(p, false_case); - tb_inst_ret(p, 1, &one); + // tb_inst_set_control(p, false_case); + // tb_inst_ret(p, 1, &one); - tb_inst_set_control(p, prev_case); + // tb_inst_set_control(p, prev_case); - tb_module_compile_function(m->mod, p, TB_ISEL_FAST); + // tb_module_compile_function(m->mod, p, TB_ISEL_FAST); - tb_function_print(p, tb_default_print_callback, stdout); + // tb_function_print(p, tb_default_print_callback, stdout); - TB_ExportBuffer export_buffer = tb_module_object_export(m->mod, TB_DEBUGFMT_NONE); - defer (tb_export_buffer_free(export_buffer)); - char const *path = "W:/Odin/tilde_main.obj"; - GB_ASSERT(tb_export_buffer_to_file(export_buffer, path)); - } + // TB_DebugFormat debug_format = TB_DEBUGFMT_NONE; + // TB_ExportBuffer export_buffer = tb_module_object_export(m->mod, debug_format); + // defer (tb_export_buffer_free(export_buffer)); + + // char const *path = "W:/Odin/tilde_main.obj"; + // GB_ASSERT(tb_export_buffer_to_file(export_buffer, path)); + // } return true; } diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 6e4f792a7..48404daec 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -188,6 +188,8 @@ gb_internal cgValue cg_value(TB_Node * node, Type *type); gb_internal cgAddr cg_addr(cgValue const &value); +gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value); + gb_internal void cg_build_stmt(cgProcedure *p, Ast *stmt); gb_internal void cg_build_stmt_list(cgProcedure *p, Slice const &stmts); diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp new file mode 100644 index 000000000..e59c6f8ab --- /dev/null +++ b/src/tilde_const.cpp @@ -0,0 +1,5 @@ +gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value) { + TB_Node *node = nullptr; + + return cg_value(node, type); +} \ No newline at end of file diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp new file mode 100644 index 000000000..3fa084e1a --- /dev/null +++ b/src/tilde_expr.cpp @@ -0,0 +1,68 @@ +gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr); +gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr) { + u16 prev_state_flags = p->state_flags; + defer (p->state_flags = prev_state_flags); + + if (expr->state_flags != 0) { + u16 in = expr->state_flags; + u16 out = p->state_flags; + + if (in & StateFlag_bounds_check) { + out |= StateFlag_bounds_check; + out &= ~StateFlag_no_bounds_check; + } else if (in & StateFlag_no_bounds_check) { + out |= StateFlag_no_bounds_check; + out &= ~StateFlag_bounds_check; + } + + if (in & StateFlag_type_assert) { + out |= StateFlag_type_assert; + out &= ~StateFlag_no_type_assert; + } else if (in & StateFlag_no_type_assert) { + out |= StateFlag_no_type_assert; + out &= ~StateFlag_type_assert; + } + + p->state_flags = out; + } + + + // IMPORTANT NOTE(bill): + // Selector Call Expressions (foo->bar(...)) + // must only evaluate `foo` once as it gets transformed into + // `foo.bar(foo, ...)` + // And if `foo` is a procedure call or something more complex, storing the value + // once is a very good idea + // If a stored value is found, it must be removed from the cache + if (expr->state_flags & StateFlag_SelectorCallExpr) { + // cgValue *pp = map_get(&p->selector_values, expr); + // if (pp != nullptr) { + // cgValue res = *pp; + // map_remove(&p->selector_values, expr); + // return res; + // } + // cgAddr *pa = map_get(&p->selector_addr, expr); + // if (pa != nullptr) { + // cgAddr res = *pa; + // map_remove(&p->selector_addr, expr); + // return cg_addr_load(p, res); + // } + } + + cgValue res = cg_build_expr_internal(p, expr); + + if (expr->state_flags & StateFlag_SelectorCallExpr) { + // map_set(&p->selector_values, expr, res); + } + return res; +} + + +gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { + return {}; +} + + +gb_internal cgAddr cg_build_addr(cgProcedure *p, Ast *expr) { + return {}; +} diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index c277eae03..831741559 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -44,12 +44,13 @@ gb_internal void cg_pop_target_list(cgProcedure *p) { p->target_list = p->target_list->prev; } +gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type) { + // TODO(bill): cg_debug_type + return tb_debug_get_void(m->mod); +} + gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init) { - char const *name = ""; - if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { - // NOTE(bill): for debugging purposes only - name = alloc_cstring(permanent_allocator(), e->token.string); - } + GB_ASSERT(type != nullptr); isize size = type_size_of(type); TB_CharUnits alignment = cast(TB_CharUnits)type_align_of(type); @@ -59,6 +60,14 @@ gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero TB_Node *local = tb_inst_local(p->func, cast(u32)size, alignment); + if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { + // NOTE(bill): for debugging purposes only + char const *name = alloc_cstring(permanent_allocator(), e->token.string); + + TB_DebugType *debug_type = cg_debug_type(p->module, type); + tb_function_attrib_variable(p->func, local, name, debug_type); + } + if (zero_init) { bool is_volatile = false; TB_Node *zero = tb_inst_uint(p->func, TB_TYPE_I8, 0); @@ -82,6 +91,80 @@ gb_internal void cg_emit_defer_stmts(cgProcedure *p, cgDeferExitKind kind, TB_No // TODO(bill): cg_emit_defer_stmts } +gb_internal void cg_build_assignment(cgProcedure *p, Array const &lhs, Slice const &rhs) { + +} + + +gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) { + if (as->op.kind == Token_Eq) { + auto lvals = array_make(permanent_allocator(), 0, as->lhs.count); + + for (Ast *lhs : as->lhs) { + cgAddr lval = {}; + if (!is_blank_ident(lhs)) { + lval = cg_build_addr(p, lhs); + } + array_add(&lvals, lval); + } + cg_build_assignment(p, lvals, as->rhs); + return; + } + + GB_ASSERT(as->lhs.count == 1); + GB_ASSERT(as->rhs.count == 1); + // NOTE(bill): Only 1 += 1 is allowed, no tuples + // +=, -=, etc + + GB_PANIC("do += etc assignments"); + + i32 op_ = cast(i32)as->op.kind; + op_ += Token_Add - Token_AddEq; // Convert += to + + TokenKind op = cast(TokenKind)op_; + + gb_unused(op); +/* + if (op == Token_CmpAnd || op == Token_CmpOr) { + Type *type = as->lhs[0]->tav.type; + cgValue new_value = lb_emit_logical_binary_expr(p, op, as->lhs[0], as->rhs[0], type); + + cgAddr lhs = lb_build_addr(p, as->lhs[0]); + lb_addr_store(p, lhs, new_value); + } else { + cgAddr lhs = lb_build_addr(p, as->lhs[0]); + lbValue value = lb_build_expr(p, as->rhs[0]); + Type *lhs_type = lb_addr_type(lhs); + + // NOTE(bill): Allow for the weird edge case of: + // array *= matrix + if (op == Token_Mul && is_type_matrix(value.type) && is_type_array(lhs_type)) { + lbValue old_value = lb_addr_load(p, lhs); + Type *type = old_value.type; + lbValue new_value = lb_emit_vector_mul_matrix(p, old_value, value, type); + lb_addr_store(p, lhs, new_value); + return; + } + + if (is_type_array(lhs_type)) { + lb_build_assign_stmt_array(p, op, lhs, value); + return; + } else { + lbValue old_value = lb_addr_load(p, lhs); + Type *type = old_value.type; + + lbValue change = lb_emit_conv(p, value, type); + lbValue new_value = lb_emit_arith(p, op, old_value, change, type); + lb_addr_store(p, lhs, new_value); + } + } +*/ +} + +gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return_results) { + +} + + gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { Ast *prev_stmt = p->curr_stmt; defer (p->curr_stmt = prev_stmt); @@ -238,6 +321,18 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { tb_inst_set_control(p->func, prev_block); case_end; + case_ast_node(es, ExprStmt, node); + cg_build_expr(p, es->expr); + case_end; + + case_ast_node(as, AssignStmt, node); + cg_build_assign_stmt(p, as); + case_end; + + case_ast_node(rs, ReturnStmt, node); + cg_build_return_stmt(p, rs->results); + case_end; + default: GB_PANIC("TODO cg_build_stmt %.*s", LIT(ast_strings[node->kind])); break; -- cgit v1.2.3 From a8afcf1ca950eded2d9c45750debd287f7998d1c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 14 Jul 2023 16:03:21 +0100 Subject: cg_emit_load/cg_emit_store --- src/tilde_backend.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/tilde_backend.hpp | 3 ++ src/tilde_expr.cpp | 4 +++ src/tilde_stmt.cpp | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index 8009a7703..9b0c9105b 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -1,5 +1,88 @@ #include "tilde_backend.hpp" +// returns TB_TYPE_VOID if not trivially possible +gb_internal TB_DataType cg_data_type(Type *t) { + GB_ASSERT(t != nullptr); + t = core_type(t); + switch (t->kind) { + case Type_Basic: + switch (t->Basic.kind) { + case Basic_bool: return TB_TYPE_BOOL; + case Basic_b8: return TB_TYPE_BOOL; + case Basic_b16: return TB_TYPE_I16; + case Basic_b32: return TB_TYPE_I32; + case Basic_b64: return TB_TYPE_I64; + + case Basic_i8: return TB_TYPE_I8; + case Basic_u8: return TB_TYPE_I8; + case Basic_i16: return TB_TYPE_I16; + case Basic_u16: return TB_TYPE_I16; + case Basic_i32: return TB_TYPE_I32; + case Basic_u32: return TB_TYPE_I32; + case Basic_i64: return TB_TYPE_I64; + case Basic_u64: return TB_TYPE_I64; + case Basic_i128: return TB_TYPE_I128; + case Basic_u128: return TB_TYPE_I128; + + case Basic_rune: return TB_TYPE_I32; + + case Basic_f16: return TB_TYPE_I16; + case Basic_f32: return TB_TYPE_F32; + case Basic_f64: return TB_TYPE_F64; + + case Basic_int: return TB_TYPE_INTN(cast(u16)build_context.int_size); + case Basic_uint: return TB_TYPE_INTN(cast(u16)build_context.int_size); + case Basic_uintptr: return TB_TYPE_INTN(cast(u16)build_context.ptr_size); + case Basic_rawptr: return TB_TYPE_PTR; + case Basic_cstring: return TB_TYPE_PTR; + + case Basic_typeid: return TB_TYPE_INTN(cast(u16)build_context.ptr_size); + + // Endian Specific Types + case Basic_i16le: return TB_TYPE_I16; + case Basic_u16le: return TB_TYPE_I16; + case Basic_i32le: return TB_TYPE_I32; + case Basic_u32le: return TB_TYPE_I32; + case Basic_i64le: return TB_TYPE_I64; + case Basic_u64le: return TB_TYPE_I64; + case Basic_i128le: return TB_TYPE_I128; + case Basic_u128le: return TB_TYPE_I128; + + case Basic_i16be: return TB_TYPE_I16; + case Basic_u16be: return TB_TYPE_I16; + case Basic_i32be: return TB_TYPE_I32; + case Basic_u32be: return TB_TYPE_I32; + case Basic_i64be: return TB_TYPE_I64; + case Basic_u64be: return TB_TYPE_I64; + case Basic_i128be: return TB_TYPE_I128; + case Basic_u128be: return TB_TYPE_I128; + + case Basic_f16le: return TB_TYPE_I16; + case Basic_f32le: return TB_TYPE_F32; + case Basic_f64le: return TB_TYPE_F64; + + case Basic_f16be: return TB_TYPE_I16; + case Basic_f32be: return TB_TYPE_F32; + case Basic_f64be: return TB_TYPE_F64; + } + + case Type_Pointer: + case Type_MultiPointer: + case Type_Proc: + return TB_TYPE_PTR; + + case Type_BitSet: + return cg_data_type(bit_set_to_int(t)); + + case Type_RelativePointer: + return cg_data_type(t->RelativePointer.base_integer); + } + + // unknown + return {}; +} + + gb_internal cgValue cg_value(TB_Global *g, Type *type) { return cg_value((TB_Symbol *)g, type); } diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 48404daec..9d13a87d5 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -7,6 +7,9 @@ #include "tilde/tb.h" +#define TB_TYPE_I128 TB_DataType{ { TB_INT, 0, 128 } } + + #if defined(GB_SYSTEM_WINDOWS) #pragma warning(pop) #endif diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 3fa084e1a..9910801bd 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -50,6 +50,10 @@ gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr) { } cgValue res = cg_build_expr_internal(p, expr); + if (res.kind == cgValue_Symbol) { + GB_ASSERT(is_type_pointer(res.type)); + res = cg_value(tb_inst_get_symbol_address(p->func, res.symbol), res.type); + } if (expr->state_flags & StateFlag_SelectorCallExpr) { // map_set(&p->selector_values, expr, res); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 831741559..a2a6923c4 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -96,6 +96,90 @@ gb_internal void cg_build_assignment(cgProcedure *p, Array const &lhs, S } +gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile=false) { + GB_ASSERT(is_type_pointer(ptr.type)); + Type *type = type_deref(ptr.type); + TB_DataType dt = cg_data_type(type); + + if (TB_IS_VOID_TYPE(dt)) { + switch (ptr.kind) { + case cgValue_Value: + return cg_lvalue_addr(ptr.node, type); + case cgValue_Addr: + GB_PANIC("NOT POSSIBLE"); + break; + case cgValue_Symbol: + return cg_lvalue_addr(tb_inst_get_symbol_address(p->func, ptr.symbol), type); + } + } + + TB_CharUnits alignment = 1; // for the time being + + TB_Node *the_ptr = nullptr; + switch (ptr.kind) { + case cgValue_Value: + the_ptr = ptr.node; + break; + case cgValue_Addr: + the_ptr = tb_inst_load(p->func, TB_TYPE_PTR, ptr.node, alignment, is_volatile); + break; + case cgValue_Symbol: + the_ptr = tb_inst_get_symbol_address(p->func, ptr.symbol); + break; + } + return cg_value(tb_inst_load(p->func, dt, the_ptr, alignment, is_volatile), type); +} + +gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile=false) { + if (dst.kind == cgValue_Addr) { + dst = cg_emit_load(p, dst, is_volatile); + } else if (dst.kind = cgValue_Symbol) { + dst = cg_value(tb_inst_get_symbol_address(p->func, dst.symbol), dst.type); + } + + GB_ASSERT(is_type_pointer(dst.type)); + Type *dst_type = type_deref(dst.type); + + GB_ASSERT_MSG(are_types_identical(dst_type, src.type), "%s vs %s", type_to_string(dst_type), type_to_string(src.type)); + + TB_DataType dt = cg_data_type(dst_type); + TB_DataType st = cg_data_type(src.type); + GB_ASSERT(dt.raw == st.raw); + + if (TB_IS_VOID_TYPE(dt)) { + // TODO(bill): needs to be memmove + GB_PANIC("todo emit store to aggregate type"); + return; + } + + TB_CharUnits alignment = 1; // for the time being + + switch (dst.kind) { + case cgValue_Value: + switch (dst.kind) { + case cgValue_Value: + tb_inst_store(p->func, dt, dst.node, src.node, alignment, is_volatile); + return; + case cgValue_Addr: + tb_inst_store(p->func, dt, dst.node, + tb_inst_load(p->func, st, src.node, alignment, is_volatile), + alignment, is_volatile); + return; + case cgValue_Symbol: + tb_inst_store(p->func, dt, dst.node, + tb_inst_get_symbol_address(p->func, src.symbol), + alignment, is_volatile); + return; + } + case cgValue_Addr: + case cgValue_Symbol: + GB_PANIC("should be handled above"); + break; + } +} + + + gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) { if (as->op.kind == Token_Eq) { auto lvals = array_make(permanent_allocator(), 0, as->lhs.count); -- cgit v1.2.3 From b17ebeb6f66f5f7e24b5a1ca32baf6855185eea8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 14 Jul 2023 17:03:28 +0100 Subject: Mock out more of the addr related stuff --- src/tilde_backend.cpp | 81 +++++++------ src/tilde_backend.hpp | 6 +- src/tilde_const.cpp | 40 +++++++ src/tilde_expr.cpp | 6 + src/tilde_stmt.cpp | 325 +++++++++++++++++++++++++++++++++++--------------- 5 files changed, 323 insertions(+), 135 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index 9b0c9105b..0dee72fe3 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -4,58 +4,61 @@ gb_internal TB_DataType cg_data_type(Type *t) { GB_ASSERT(t != nullptr); t = core_type(t); + i64 sz = type_size_of(t); switch (t->kind) { case Type_Basic: switch (t->Basic.kind) { - case Basic_bool: return TB_TYPE_BOOL; - case Basic_b8: return TB_TYPE_BOOL; - case Basic_b16: return TB_TYPE_I16; - case Basic_b32: return TB_TYPE_I32; - case Basic_b64: return TB_TYPE_I64; - - case Basic_i8: return TB_TYPE_I8; - case Basic_u8: return TB_TYPE_I8; - case Basic_i16: return TB_TYPE_I16; - case Basic_u16: return TB_TYPE_I16; - case Basic_i32: return TB_TYPE_I32; - case Basic_u32: return TB_TYPE_I32; - case Basic_i64: return TB_TYPE_I64; - case Basic_u64: return TB_TYPE_I64; - case Basic_i128: return TB_TYPE_I128; - case Basic_u128: return TB_TYPE_I128; - - case Basic_rune: return TB_TYPE_I32; + case Basic_bool: + case Basic_b8: + case Basic_b16: + case Basic_b32: + case Basic_b64: + + case Basic_i8: + case Basic_u8: + case Basic_i16: + case Basic_u16: + case Basic_i32: + case Basic_u32: + case Basic_i64: + case Basic_u64: + case Basic_i128: + case Basic_u128: + + case Basic_rune: + + case Basic_int: + case Basic_uint: + case Basic_uintptr: + case Basic_typeid: + return TB_TYPE_INTN(cast(u16)(8*sz)); case Basic_f16: return TB_TYPE_I16; case Basic_f32: return TB_TYPE_F32; case Basic_f64: return TB_TYPE_F64; - case Basic_int: return TB_TYPE_INTN(cast(u16)build_context.int_size); - case Basic_uint: return TB_TYPE_INTN(cast(u16)build_context.int_size); - case Basic_uintptr: return TB_TYPE_INTN(cast(u16)build_context.ptr_size); case Basic_rawptr: return TB_TYPE_PTR; case Basic_cstring: return TB_TYPE_PTR; - case Basic_typeid: return TB_TYPE_INTN(cast(u16)build_context.ptr_size); // Endian Specific Types - case Basic_i16le: return TB_TYPE_I16; - case Basic_u16le: return TB_TYPE_I16; - case Basic_i32le: return TB_TYPE_I32; - case Basic_u32le: return TB_TYPE_I32; - case Basic_i64le: return TB_TYPE_I64; - case Basic_u64le: return TB_TYPE_I64; - case Basic_i128le: return TB_TYPE_I128; - case Basic_u128le: return TB_TYPE_I128; - - case Basic_i16be: return TB_TYPE_I16; - case Basic_u16be: return TB_TYPE_I16; - case Basic_i32be: return TB_TYPE_I32; - case Basic_u32be: return TB_TYPE_I32; - case Basic_i64be: return TB_TYPE_I64; - case Basic_u64be: return TB_TYPE_I64; - case Basic_i128be: return TB_TYPE_I128; - case Basic_u128be: return TB_TYPE_I128; + case Basic_i16le: + case Basic_u16le: + case Basic_i32le: + case Basic_u32le: + case Basic_i64le: + case Basic_u64le: + case Basic_i128le: + case Basic_u128le: + case Basic_i16be: + case Basic_u16be: + case Basic_i32be: + case Basic_u32be: + case Basic_i64be: + case Basic_u64be: + case Basic_i128be: + case Basic_u128be: + return TB_TYPE_INTN(cast(u16)(8*sz)); case Basic_f16le: return TB_TYPE_I16; case Basic_f32le: return TB_TYPE_F32; diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 9d13a87d5..24a352fe1 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -7,8 +7,9 @@ #include "tilde/tb.h" -#define TB_TYPE_I128 TB_DataType{ { TB_INT, 0, 128 } } - +#define TB_TYPE_I128 TB_DataType{ { TB_INT, 0, 128 } } +#define TB_TYPE_INT TB_TYPE_INTN(cast(u16)build_context.int_size) +#define TB_TYPE_INTPTR TB_TYPE_INTN(cast(u16)build_context.ptr_size) #if defined(GB_SYSTEM_WINDOWS) #pragma warning(pop) @@ -162,6 +163,7 @@ struct cgModule { PtrMap file_id_map; // Key: AstFile.id (i32 cast to uintptr) std::atomic nested_type_name_guid; + std::atomic const_nil_guid; }; #ifndef ABI_PKG_NAME_SEPARATOR diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index e59c6f8ab..6f9736554 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -1,5 +1,45 @@ +gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type) { + Type *original_type = type; + type = core_type(type); + i64 size = type_size_of(type); + i64 align = type_align_of(type); + TB_DataType dt = cg_data_type(type); + if (TB_IS_VOID_TYPE(dt)) { + TB_Module *m = p->module->mod; + char name[32] = {}; + gb_snprintf(name, 31, "cnil$%u", 1+p->module->const_nil_guid.fetch_add(1)); + TB_Global *global = tb_global_create(m, name, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m, tb_module_get_rdata(m), global, size, align, 0); + + TB_Symbol *symbol = cast(TB_Symbol *)global; + TB_Node *node = tb_inst_get_symbol_address(p->func, symbol); + return cg_lvalue_addr(node, type); + } + + if (is_type_internally_pointer_like(type)) { + return cg_value(tb_inst_ptr(p->func, 0), type); + } else if (is_type_integer(type) || is_type_boolean(type) || is_type_bit_set(type)) { + return cg_value(tb_inst_uint(p->func, dt, 0), type); + } else if (is_type_float(type)) { + switch (size) { + case 2: + return cg_value(tb_inst_uint(p->func, dt, 0), type); + case 4: + return cg_value(tb_inst_float32(p->func, 0), type); + case 8: + return cg_value(tb_inst_float64(p->func, 0), type); + } + } + GB_PANIC("TODO(bill): cg_const_nil %s", type_to_string(original_type)); + return {}; +} + gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value) { TB_Node *node = nullptr; + if (value.kind == ExactValue_Invalid) { + return cg_const_nil(p, type); + } + return cg_value(node, type); } \ No newline at end of file diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 9910801bd..4aae872cf 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -1,3 +1,9 @@ +gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *type) { + // TODO(bill): cg_emit_conv + return value; +} + + gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr); gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr) { u16 prev_state_flags = p->state_flags; diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index a2a6923c4..52bbb3ab9 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1,3 +1,223 @@ + +gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile=false) { + GB_ASSERT(is_type_pointer(ptr.type)); + Type *type = type_deref(ptr.type); + TB_DataType dt = cg_data_type(type); + + if (TB_IS_VOID_TYPE(dt)) { + switch (ptr.kind) { + case cgValue_Value: + return cg_lvalue_addr(ptr.node, type); + case cgValue_Addr: + GB_PANIC("NOT POSSIBLE"); + break; + case cgValue_Symbol: + return cg_lvalue_addr(tb_inst_get_symbol_address(p->func, ptr.symbol), type); + } + } + + TB_CharUnits alignment = 1; // for the time being + + TB_Node *the_ptr = nullptr; + switch (ptr.kind) { + case cgValue_Value: + the_ptr = ptr.node; + break; + case cgValue_Addr: + the_ptr = tb_inst_load(p->func, TB_TYPE_PTR, ptr.node, alignment, is_volatile); + break; + case cgValue_Symbol: + the_ptr = tb_inst_get_symbol_address(p->func, ptr.symbol); + break; + } + return cg_value(tb_inst_load(p->func, dt, the_ptr, alignment, is_volatile), type); +} + +gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile=false) { + if (dst.kind == cgValue_Addr) { + dst = cg_emit_load(p, dst, is_volatile); + } else if (dst.kind = cgValue_Symbol) { + dst = cg_value(tb_inst_get_symbol_address(p->func, dst.symbol), dst.type); + } + + GB_ASSERT(is_type_pointer(dst.type)); + Type *dst_type = type_deref(dst.type); + + GB_ASSERT_MSG(are_types_identical(dst_type, src.type), "%s vs %s", type_to_string(dst_type), type_to_string(src.type)); + + TB_DataType dt = cg_data_type(dst_type); + TB_DataType st = cg_data_type(src.type); + GB_ASSERT(dt.raw == st.raw); + + TB_CharUnits alignment = 1; // for the time being + + if (TB_IS_VOID_TYPE(dt)) { + TB_Node *dst_ptr = nullptr; + TB_Node *src_ptr = nullptr; + + switch (dst.kind) { + case cgValue_Value: + dst_ptr = dst.node; + break; + case cgValue_Addr: + GB_PANIC("DST cgValue_Addr should be handled above"); + break; + case cgValue_Symbol: + dst_ptr = tb_inst_get_symbol_address(p->func, dst.symbol); + break; + } + + switch (src.kind) { + case cgValue_Value: + GB_PANIC("SRC cgValue_Value should be handled above"); + break; + case cgValue_Symbol: + GB_PANIC("SRC cgValue_Symbol should be handled above"); + break; + case cgValue_Addr: + src_ptr = src.node; + break; + } + + // IMPORTANT TODO(bill): needs to be memmove + i64 sz = type_size_of(dst_type); + TB_Node *count = tb_inst_uint(p->func, TB_TYPE_INT, cast(u64)sz); + tb_inst_memcpy(p->func, dst_ptr, src_ptr, count, alignment, is_volatile); + return; + } + + switch (dst.kind) { + case cgValue_Value: + switch (dst.kind) { + case cgValue_Value: + tb_inst_store(p->func, dt, dst.node, src.node, alignment, is_volatile); + return; + case cgValue_Addr: + tb_inst_store(p->func, dt, dst.node, + tb_inst_load(p->func, st, src.node, alignment, is_volatile), + alignment, is_volatile); + return; + case cgValue_Symbol: + tb_inst_store(p->func, dt, dst.node, + tb_inst_get_symbol_address(p->func, src.symbol), + alignment, is_volatile); + return; + } + case cgValue_Addr: + GB_PANIC("cgValue_Addr should be handled above"); + break; + case cgValue_Symbol: + GB_PANIC(" cgValue_Symbol should be handled above"); + break; + } +} + + +gb_internal cgValue cg_address_from_load(cgProcedure *p, cgValue value) { + switch (value.kind) { + case cgValue_Value: + { + TB_Node *load_inst = value.node; + GB_ASSERT_MSG(load_inst->type == TB_LOAD, "expected a load instruction"); + TB_Node *ptr = load_inst->inputs[1]; + return cg_value(ptr, alloc_type_pointer(value.type)); + } + case cgValue_Addr: + return cg_value(value.node, alloc_type_pointer(value.type)); + case cgValue_Symbol: + GB_PANIC("Symbol is an invalid use case for cg_address_from_load"); + return {}; + } +} + +gb_internal bool cg_addr_is_empty(cgAddr const &addr) { + switch (addr.kind) { + case cgValue_Value: + case cgValue_Addr: + return addr.addr.node == nullptr; + case cgValue_Symbol: + return addr.addr.symbol == nullptr; + } + return true; +} + +gb_internal Type *cg_addr_type(cgAddr const &addr) { + if (cg_addr_is_empty(addr)) { + return nullptr; + } + switch (addr.kind) { + case cgAddr_Map: + { + Type *t = base_type(addr.map.type); + GB_ASSERT(is_type_map(t)); + return t->Map.value; + } + case cgAddr_Swizzle: + return addr.swizzle.type; + case cgAddr_SwizzleLarge: + return addr.swizzle_large.type; + case cgAddr_Context: + if (addr.ctx.sel.index.count > 0) { + Type *t = t_context; + for_array(i, addr.ctx.sel.index) { + GB_ASSERT(is_type_struct(t)); + t = base_type(t)->Struct.fields[addr.ctx.sel.index[i]]->type; + } + return t; + } + break; + } + return type_deref(addr.addr.type); +} + +gb_internal cgValue cg_addr_load(cgProcedure *p, cgAddr addr) { + GB_PANIC("TODO(bill): cg_addr_load"); + return {}; +} + + +gb_internal void cg_addr_store(cgProcedure *p, cgAddr addr, cgValue value) { + if (cg_addr_is_empty(addr)) { + return; + } + GB_ASSERT(value.type != nullptr); + if (is_type_untyped_uninit(value.type)) { + Type *t = cg_addr_type(addr); + value = cg_value(tb_inst_poison(p->func), t); + // TODO(bill): IS THIS EVEN A GOOD IDEA? + } else if (is_type_untyped_nil(value.type)) { + Type *t = cg_addr_type(addr); + value = cg_const_nil(p, t); + } + + if (addr.kind == cgAddr_RelativePointer && addr.relative.deref) { + addr = cg_addr(cg_address_from_load(p, cg_addr_load(p, addr))); + } + + if (addr.kind == cgAddr_RelativePointer) { + GB_PANIC("TODO(bill): cgAddr_RelativePointer"); + } else if (addr.kind == cgAddr_RelativeSlice) { + GB_PANIC("TODO(bill): cgAddr_RelativeSlice"); + } else if (addr.kind == cgAddr_Map) { + GB_PANIC("TODO(bill): cgAddr_Map"); + } else if (addr.kind == cgAddr_Context) { + GB_PANIC("TODO(bill): cgAddr_Context"); + } else if (addr.kind == cgAddr_SoaVariable) { + GB_PANIC("TODO(bill): cgAddr_SoaVariable"); + } else if (addr.kind == cgAddr_Swizzle) { + GB_ASSERT(addr.swizzle.count <= 4); + GB_PANIC("TODO(bill): cgAddr_Swizzle"); + } else if (addr.kind == cgAddr_SwizzleLarge) { + GB_PANIC("TODO(bill): cgAddr_SwizzleLarge"); + } + + value = cg_emit_conv(p, value, cg_addr_type(addr)); + cg_emit_store(p, addr.addr, value); +} + + + + gb_internal cgBranchBlocks cg_lookup_branch_blocks(cgProcedure *p, Ast *ident) { GB_ASSERT(ident->kind == Ast_Ident); Entity *e = entity_of_node(ident); @@ -91,95 +311,12 @@ gb_internal void cg_emit_defer_stmts(cgProcedure *p, cgDeferExitKind kind, TB_No // TODO(bill): cg_emit_defer_stmts } -gb_internal void cg_build_assignment(cgProcedure *p, Array const &lhs, Slice const &rhs) { - -} - - -gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile=false) { - GB_ASSERT(is_type_pointer(ptr.type)); - Type *type = type_deref(ptr.type); - TB_DataType dt = cg_data_type(type); - - if (TB_IS_VOID_TYPE(dt)) { - switch (ptr.kind) { - case cgValue_Value: - return cg_lvalue_addr(ptr.node, type); - case cgValue_Addr: - GB_PANIC("NOT POSSIBLE"); - break; - case cgValue_Symbol: - return cg_lvalue_addr(tb_inst_get_symbol_address(p->func, ptr.symbol), type); - } - } - - TB_CharUnits alignment = 1; // for the time being - - TB_Node *the_ptr = nullptr; - switch (ptr.kind) { - case cgValue_Value: - the_ptr = ptr.node; - break; - case cgValue_Addr: - the_ptr = tb_inst_load(p->func, TB_TYPE_PTR, ptr.node, alignment, is_volatile); - break; - case cgValue_Symbol: - the_ptr = tb_inst_get_symbol_address(p->func, ptr.symbol); - break; - } - return cg_value(tb_inst_load(p->func, dt, the_ptr, alignment, is_volatile), type); -} - -gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile=false) { - if (dst.kind == cgValue_Addr) { - dst = cg_emit_load(p, dst, is_volatile); - } else if (dst.kind = cgValue_Symbol) { - dst = cg_value(tb_inst_get_symbol_address(p->func, dst.symbol), dst.type); - } - - GB_ASSERT(is_type_pointer(dst.type)); - Type *dst_type = type_deref(dst.type); - - GB_ASSERT_MSG(are_types_identical(dst_type, src.type), "%s vs %s", type_to_string(dst_type), type_to_string(src.type)); - - TB_DataType dt = cg_data_type(dst_type); - TB_DataType st = cg_data_type(src.type); - GB_ASSERT(dt.raw == st.raw); - - if (TB_IS_VOID_TYPE(dt)) { - // TODO(bill): needs to be memmove - GB_PANIC("todo emit store to aggregate type"); +gb_internal void cg_build_assignment(cgProcedure *p, Array const &lvals, Slice const &values) { + if (values.count == 0) { return; } - - TB_CharUnits alignment = 1; // for the time being - - switch (dst.kind) { - case cgValue_Value: - switch (dst.kind) { - case cgValue_Value: - tb_inst_store(p->func, dt, dst.node, src.node, alignment, is_volatile); - return; - case cgValue_Addr: - tb_inst_store(p->func, dt, dst.node, - tb_inst_load(p->func, st, src.node, alignment, is_volatile), - alignment, is_volatile); - return; - case cgValue_Symbol: - tb_inst_store(p->func, dt, dst.node, - tb_inst_get_symbol_address(p->func, src.symbol), - alignment, is_volatile); - return; - } - case cgValue_Addr: - case cgValue_Symbol: - GB_PANIC("should be handled above"); - break; - } } - - gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) { if (as->op.kind == Token_Eq) { auto lvals = array_make(permanent_allocator(), 0, as->lhs.count); @@ -213,19 +350,19 @@ gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) { cgValue new_value = lb_emit_logical_binary_expr(p, op, as->lhs[0], as->rhs[0], type); cgAddr lhs = lb_build_addr(p, as->lhs[0]); - lb_addr_store(p, lhs, new_value); + cg_addr_store(p, lhs, new_value); } else { cgAddr lhs = lb_build_addr(p, as->lhs[0]); - lbValue value = lb_build_expr(p, as->rhs[0]); + cgValue value = lb_build_expr(p, as->rhs[0]); Type *lhs_type = lb_addr_type(lhs); // NOTE(bill): Allow for the weird edge case of: // array *= matrix if (op == Token_Mul && is_type_matrix(value.type) && is_type_array(lhs_type)) { - lbValue old_value = lb_addr_load(p, lhs); + cgValue old_value = lb_addr_load(p, lhs); Type *type = old_value.type; - lbValue new_value = lb_emit_vector_mul_matrix(p, old_value, value, type); - lb_addr_store(p, lhs, new_value); + cgValue new_value = lb_emit_vector_mul_matrix(p, old_value, value, type); + cg_addr_store(p, lhs, new_value); return; } @@ -233,12 +370,12 @@ gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) { lb_build_assign_stmt_array(p, op, lhs, value); return; } else { - lbValue old_value = lb_addr_load(p, lhs); + cgValue old_value = lb_addr_load(p, lhs); Type *type = old_value.type; - lbValue change = lb_emit_conv(p, value, type); - lbValue new_value = lb_emit_arith(p, op, old_value, change, type); - lb_addr_store(p, lhs, new_value); + cgValue change = lb_emit_conv(p, value, type); + cgValue new_value = lb_emit_arith(p, op, old_value, change, type); + cg_addr_store(p, lhs, new_value); } } */ -- cgit v1.2.3 From ca442defbbaae4269ff947dfc14059f69a5cdaec Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 14 Jul 2023 17:34:00 +0100 Subject: Mocking out call related stuff --- src/tilde_backend.cpp | 8 +-- src/tilde_backend.hpp | 18 +++++- src/tilde_const.cpp | 9 ++- src/tilde_expr.cpp | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/tilde_proc.cpp | 5 ++ src/tilde_stmt.cpp | 7 +- 6 files changed, 207 insertions(+), 14 deletions(-) create mode 100644 src/tilde_proc.cpp (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index 0dee72fe3..d695c846c 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -708,14 +708,12 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { if (p == nullptr || p->func == nullptr) { return; } - gb_printf_err("cg_procedure_begin %.*s\n", LIT(p->name)); } gb_internal void cg_procedure_end(cgProcedure *p) { if (p == nullptr || p->func == nullptr) { return; } - gb_printf_err("cg_procedure_end %.*s\n", LIT(p->name)); tb_inst_ret(p->func, 0, nullptr); tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST); } @@ -731,18 +729,16 @@ gb_internal void cg_procedure_generate(cgProcedure *p) { p->name != "main") { return; } - if (p->body != nullptr) { - cg_build_stmt(p, p->body); - } + cg_build_stmt(p, p->body); } #include "tilde_const.cpp" #include "tilde_expr.cpp" +#include "tilde_proc.cpp" #include "tilde_stmt.cpp" - gb_internal bool cg_generate_code(Checker *c) { TIME_SECTION("Tilde Module Initializtion"); diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 24a352fe1..44591190a 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -194,8 +194,22 @@ gb_internal cgAddr cg_addr(cgValue const &value); gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value); - +gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type); gb_internal void cg_build_stmt(cgProcedure *p, Ast *stmt); gb_internal void cg_build_stmt_list(cgProcedure *p, Slice const &stmts); -gb_internal void cg_build_when_stmt(cgProcedure *p, AstWhenStmt *ws); \ No newline at end of file +gb_internal void cg_build_when_stmt(cgProcedure *p, AstWhenStmt *ws); + +gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr); +gb_internal cgAddr cg_build_addr(cgProcedure *p, Ast *expr); + +gb_internal Type * cg_addr_type(cgAddr const &addr); +gb_internal cgValue cg_addr_load(cgProcedure *p, cgAddr addr); +gb_internal void cg_addr_store(cgProcedure *p, cgAddr addr, cgValue value); + +gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile=false); +gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile=false); + +gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init); + +gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); \ No newline at end of file diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index 6f9736554..7a8be70c7 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -17,7 +17,7 @@ gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type) { } if (is_type_internally_pointer_like(type)) { - return cg_value(tb_inst_ptr(p->func, 0), type); + return cg_value(tb_inst_uint(p->func, dt, 0), type); } else if (is_type_integer(type) || is_type_boolean(type) || is_type_bit_set(type)) { return cg_value(tb_inst_uint(p->func, dt, 0), type); } else if (is_type_float(type)) { @@ -34,7 +34,7 @@ gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type) { return {}; } -gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value) { +gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, ExactValue const &value) { TB_Node *node = nullptr; if (value.kind == ExactValue_Invalid) { @@ -42,4 +42,9 @@ gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const } return cg_value(node, type); +} + +gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value) { + GB_ASSERT(p != nullptr); + return cg_const_value(p->module, p, type, value); } \ No newline at end of file diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 4aae872cf..ccd126747 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -1,8 +1,52 @@ +gb_internal cgValue cg_typeid(cgModule *m, Type *t) { + GB_ASSERT("TODO(bill): cg_typeid"); + return {}; +} + + gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *type) { // TODO(bill): cg_emit_conv return value; } +gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type) { + GB_ASSERT(type_size_of(value.type) == type_size_of(type)); + + if (value.kind == cgValue_Symbol) { + GB_ASSERT(is_type_pointer(value.type)); + value = cg_value(tb_inst_get_symbol_address(p->func, value.symbol), type); + } + + i64 src_align = type_align_of(value.type); + i64 dst_align = type_align_of(type); + + if (dst_align > src_align) { + cgAddr local = cg_add_local(p, type, nullptr, false); + cgValue dst = local.addr; + dst.type = alloc_type_pointer(value.type); + cg_emit_store(p, dst, value); + return cg_addr_load(p, local); + } + + TB_DataType dt = cg_data_type(type); + switch (value.kind) { + case cgValue_Value: + GB_ASSERT(!TB_IS_VOID_TYPE(dt)); + value.type = type; + value.node = tb_inst_bitcast(p->func, value.node, dt); + return value; + case cgValue_Addr: + value.type = type; + return value; + case cgValue_Symbol: + GB_PANIC("should be handled above"); + break; + } + return value; + +} + + gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr); gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr) { @@ -68,8 +112,138 @@ gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr) { } + gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { + cgModule *m = p->module; + + expr = unparen_expr(expr); + + TokenPos expr_pos = ast_token(expr).pos; + TypeAndValue tv = type_and_value_of_expr(expr); + Type *type = type_of_expr(expr); + GB_ASSERT_MSG(tv.mode != Addressing_Invalid, "invalid expression '%s' (tv.mode = %d, tv.type = %s) @ %s\n Current Proc: %.*s : %s", expr_to_string(expr), tv.mode, type_to_string(tv.type), token_pos_to_string(expr_pos), LIT(p->name), type_to_string(p->type)); + + if (tv.value.kind != ExactValue_Invalid) { + // NOTE(bill): The commented out code below is just for debug purposes only + // if (is_type_untyped(type)) { + // gb_printf_err("%s %s : %s @ %p\n", token_pos_to_string(expr_pos), expr_to_string(expr), type_to_string(expr->tav.type), expr); + // GB_PANIC("%s\n", type_to_string(tv.type)); + // } + + // NOTE(bill): Short on constant values + return cg_const_value(p, type, tv.value); + } else if (tv.mode == Addressing_Type) { + // NOTE(bill, 2023-01-16): is this correct? I hope so at least + return cg_typeid(m, tv.type); + } + + switch (expr->kind) { + case_ast_node(bl, BasicLit, expr); + TokenPos pos = bl->token.pos; + GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(token_strings[bl->token.kind])); + case_end; + + case_ast_node(bd, BasicDirective, expr); + TokenPos pos = bd->token.pos; + GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name.string)); + case_end; + + case_ast_node(i, Ident, expr); + Entity *e = entity_from_expr(expr); + e = strip_entity_wrapping(e); + + GB_ASSERT_MSG(e != nullptr, "%s in %.*s %p", expr_to_string(expr), LIT(p->name), expr); + + if (e->kind == Entity_Builtin) { + Token token = ast_token(expr); + GB_PANIC("TODO(bill): lb_build_expr Entity_Builtin '%.*s'\n" + "\t at %s", LIT(builtin_procs[e->Builtin.id].name), + token_pos_to_string(token.pos)); + return {}; + } else if (e->kind == Entity_Nil) { + // TODO(bill): is this correct? + return cg_value(cast(TB_Node *)nullptr, e->type); + } + GB_ASSERT(e->kind != Entity_ProcGroup); + // return cg_find_ident(p, m, e, expr); + GB_PANIC("TODO: cg_find_ident"); + return {}; + case_end; + + case_ast_node(i, Implicit, expr); + return cg_addr_load(p, cg_build_addr(p, expr)); + case_end; + + case_ast_node(u, Uninit, expr); + if (is_type_untyped(type)) { + return cg_value(cast(TB_Node *)nullptr, t_untyped_uninit); + } + return cg_value(tb_inst_poison(p->func), type); + case_end; + + case_ast_node(de, DerefExpr, expr); + return cg_addr_load(p, cg_build_addr(p, expr)); + case_end; + + + case_ast_node(se, SelectorExpr, expr); + TypeAndValue tav = type_and_value_of_expr(expr); + GB_ASSERT(tav.mode != Addressing_Invalid); + return cg_addr_load(p, cg_build_addr(p, expr)); + case_end; + + case_ast_node(ise, ImplicitSelectorExpr, expr); + TypeAndValue tav = type_and_value_of_expr(expr); + GB_ASSERT(tav.mode == Addressing_Constant); + + return cg_const_value(p, type, tv.value); + case_end; + + + case_ast_node(se, SelectorCallExpr, expr); + GB_ASSERT(se->modified_call); + return cg_build_call_expr(p, se->call); + case_end; + + case_ast_node(i, CallExpr, expr); + return cg_build_call_expr(p, expr); + case_end; + + + case_ast_node(te, TernaryIfExpr, expr); + GB_PANIC("TODO(bill): TernaryIfExpr"); + case_end; + + case_ast_node(te, TernaryWhenExpr, expr); + TypeAndValue tav = type_and_value_of_expr(te->cond); + GB_ASSERT(tav.mode == Addressing_Constant); + GB_ASSERT(tav.value.kind == ExactValue_Bool); + if (tav.value.value_bool) { + return cg_build_expr(p, te->x); + } else { + return cg_build_expr(p, te->y); + } + case_end; + + case_ast_node(tc, TypeCast, expr); + cgValue e = cg_build_expr(p, tc->expr); + switch (tc->token.kind) { + case Token_cast: + return cg_emit_conv(p, e, type); + case Token_transmute: + return cg_emit_transmute(p, e, type); + } + GB_PANIC("Invalid AST TypeCast"); + case_end; + + case_ast_node(ac, AutoCast, expr); + cgValue value = cg_build_expr(p, ac->expr); + return cg_emit_conv(p, value, type); + case_end; + } + GB_PANIC("TODO(bill): cg_build_expr_internal %.*s", LIT(ast_strings[expr->kind])); return {}; + } diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp new file mode 100644 index 000000000..306852db3 --- /dev/null +++ b/src/tilde_proc.cpp @@ -0,0 +1,5 @@ +gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + // TODO(bill): cg_build_call_expr + return {}; +} \ No newline at end of file diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 52bbb3ab9..f7e68d483 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1,5 +1,4 @@ - -gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile=false) { +gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile) { GB_ASSERT(is_type_pointer(ptr.type)); Type *type = type_deref(ptr.type); TB_DataType dt = cg_data_type(type); @@ -33,10 +32,10 @@ gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_vol return cg_value(tb_inst_load(p->func, dt, the_ptr, alignment, is_volatile), type); } -gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile=false) { +gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile) { if (dst.kind == cgValue_Addr) { dst = cg_emit_load(p, dst, is_volatile); - } else if (dst.kind = cgValue_Symbol) { + } else if (dst.kind == cgValue_Symbol) { dst = cg_value(tb_inst_get_symbol_address(p->func, dst.symbol), dst.type); } -- cgit v1.2.3 From e2e5641a450f4d7ea67eae468f1bd479361ec198 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jul 2023 13:15:50 +0100 Subject: Update TB; Fix calling nullptr TB_Node* problems --- src/tilde/tb.h | 56 +++++++++++----------- src/tilde/tb.lib | Bin 4295348 -> 4120106 bytes src/tilde_backend.cpp | 32 +++++++------ src/tilde_backend.hpp | 4 +- src/tilde_const.cpp | 14 +++++- src/tilde_expr.cpp | 3 +- src/tilde_proc.cpp | 126 +++++++++++++++++++++++++++++++++++++++++++++++++- src/tilde_stmt.cpp | 19 ++++---- 8 files changed, 196 insertions(+), 58 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde/tb.h b/src/tilde/tb.h index 0f0aaf4c6..8b698ff30 100644 --- a/src/tilde/tb.h +++ b/src/tilde/tb.h @@ -439,7 +439,7 @@ struct TB_Node { typedef struct { // TB_BRANCH // avoid empty structs with flexible members int64_t _; - int64_t keys[/* input_count - 1 */]; + int64_t keys[]; } TB_NodeBranch; typedef struct { // TB_PROJ @@ -538,19 +538,6 @@ typedef struct { TB_Node* value; } TB_SwitchEntry; -typedef struct TB_Loop { - // refers to another entry in TB_LoopInfo... unless it's -1 - ptrdiff_t parent_loop; - - TB_Node* header; - TB_Node* backedge; -} TB_Loop; - -typedef struct TB_LoopInfo { - size_t count; - TB_Loop* loops; -} TB_LoopInfo; - typedef enum { TB_EXECUTABLE_UNKNOWN, TB_EXECUTABLE_PE, @@ -648,7 +635,7 @@ TB_API void tb_module_destroy(TB_Module* m); // When targetting windows & thread local storage, you'll need to bind a tls index // which is usually just a global that the runtime support has initialized, if you // dont and the tls_index is used, it'll crash -TB_API void tb_module_set_tls_index(TB_Module* m, const char* name); +TB_API void tb_module_set_tls_index(TB_Module* m, ptrdiff_t len, const char* name); // You don't need to manually call this unless you want to resolve locations before // exporting. @@ -756,7 +743,7 @@ TB_API TB_External* tb_next_external(TB_External* e); TB_API TB_ExternalType tb_extern_get_type(TB_External* e); TB_Global* tb_extern_transmute(TB_External* e, TB_DebugType* dbg_type, TB_Linkage linkage); -TB_API TB_External* tb_extern_create(TB_Module* m, const char* name, TB_ExternalType type); +TB_API TB_External* tb_extern_create(TB_Module* m, ptrdiff_t len, const char* name, TB_ExternalType type); TB_API TB_FileID tb_file_create(TB_Module* m, const char* path); // Called once you're done with TB operations on a thread (or i guess when it's @@ -798,7 +785,7 @@ TB_API TB_FunctionPrototype* tb_prototype_create(TB_Module* m, TB_CallingConv cc //////////////////////////////// // Globals //////////////////////////////// -TB_API TB_Global* tb_global_create(TB_Module* m, const char* name, TB_DebugType* dbg_type, TB_Linkage linkage); +TB_API TB_Global* tb_global_create(TB_Module* m, ptrdiff_t len, const char* name, TB_DebugType* dbg_type, TB_Linkage linkage); // allocate space for the global TB_API void tb_global_set_storage(TB_Module* m, TB_ModuleSection* section, TB_Global* global, size_t size, size_t align, size_t max_objects); @@ -818,8 +805,11 @@ TB_API TB_ModuleSection* tb_module_get_tls(TB_Module* m); //////////////////////////////// // Function Attributes //////////////////////////////// +TB_API void tb_node_append_attrib(TB_Node* n, TB_Attrib* a); + // These are parts of a function that describe metadata for instructions -TB_API void tb_function_attrib_variable(TB_Function* f, TB_Node* n, const char* name, TB_DebugType* type); +TB_API TB_Attrib* tb_function_attrib_variable(TB_Function* f, ptrdiff_t len, const char* name, TB_DebugType* type); +TB_API TB_Attrib* tb_function_attrib_scope(TB_Function* f, TB_Attrib* parent_scope); //////////////////////////////// // Debug info Generation @@ -830,9 +820,9 @@ TB_API TB_DebugType* tb_debug_get_integer(TB_Module* m, bool is_signed, int bits TB_API TB_DebugType* tb_debug_get_float(TB_Module* m, TB_FloatFormat fmt); TB_API TB_DebugType* tb_debug_create_ptr(TB_Module* m, TB_DebugType* base); TB_API TB_DebugType* tb_debug_create_array(TB_Module* m, TB_DebugType* base, size_t count); -TB_API TB_DebugType* tb_debug_create_struct(TB_Module* m, const char* tag); -TB_API TB_DebugType* tb_debug_create_union(TB_Module* m, const char* tag); -TB_API TB_DebugType* tb_debug_create_field(TB_Module* m, TB_DebugType* type, const char* name, TB_CharUnits offset); +TB_API TB_DebugType* tb_debug_create_struct(TB_Module* m, ptrdiff_t len, const char* tag); +TB_API TB_DebugType* tb_debug_create_union(TB_Module* m, ptrdiff_t len, const char* tag); +TB_API TB_DebugType* tb_debug_create_field(TB_Module* m, TB_DebugType* type, ptrdiff_t len, const char* name, TB_CharUnits offset); TB_API void tb_debug_complete_record(TB_DebugType* type, TB_DebugType** members, size_t count, TB_CharUnits size, TB_CharUnits align); //////////////////////////////// @@ -869,12 +859,14 @@ TB_API void tb_inst_set_location(TB_Function* f, TB_FileID file, int line); TB_API TB_DataType tb_vector_type(TB_DataTypeEnum type, int width); // if section is NULL, default to .text -TB_API TB_Function* tb_function_create(TB_Module* m, const char* name, TB_Linkage linkage, TB_ComdatType comdat); +TB_API TB_Function* tb_function_create(TB_Module* m, ptrdiff_t len, const char* name, TB_Linkage linkage, TB_ComdatType comdat); TB_API void* tb_function_get_jit_pos(TB_Function* f); +// if len is -1, it's null terminated +TB_API void tb_symbol_set_name(TB_Symbol* s, ptrdiff_t len, const char* name); + TB_API void tb_symbol_bind_ptr(TB_Symbol* s, void* ptr); -TB_API void tb_symbol_set_name(TB_Symbol* s, const char* name); TB_API const char* tb_symbol_get_name(TB_Symbol* s); // if arena is NULL, defaults to module arena which is freed on tb_free_thread_resources @@ -915,7 +907,6 @@ TB_API TB_Node* tb_inst_load(TB_Function* f, TB_DataType dt, TB_Node* addr, TB_C TB_API void tb_inst_store(TB_Function* f, TB_DataType dt, TB_Node* addr, TB_Node* val, TB_CharUnits align, bool is_volatile); TB_API TB_Node* tb_inst_bool(TB_Function* f, bool imm); -TB_API TB_Node* tb_inst_ptr(TB_Function* f, uint64_t imm); TB_API TB_Node* tb_inst_sint(TB_Function* f, TB_DataType dt, int64_t imm); TB_API TB_Node* tb_inst_uint(TB_Function* f, TB_DataType dt, uint64_t imm); TB_API TB_Node* tb_inst_float32(TB_Function* f, float imm); @@ -923,9 +914,12 @@ TB_API TB_Node* tb_inst_float64(TB_Function* f, double imm); TB_API TB_Node* tb_inst_cstring(TB_Function* f, const char* str); TB_API TB_Node* tb_inst_string(TB_Function* f, size_t len, const char* str); -// Broadcasts 'val' across 'count' elements starting 'dst' +// write 'val' over 'count' bytes on 'dst' TB_API void tb_inst_memset(TB_Function* f, TB_Node* dst, TB_Node* val, TB_Node* count, TB_CharUnits align, bool is_volatile); +// zero 'count' bytes on 'dst' +TB_API void tb_inst_memzero(TB_Function* f, TB_Node* dst, TB_Node* val, TB_Node* count, TB_CharUnits align, bool is_volatile); + // performs a copy of 'count' elements from one memory location to another // both locations cannot overlap. TB_API void tb_inst_memcpy(TB_Function* f, TB_Node* dst, TB_Node* src, TB_Node* count, TB_CharUnits align, bool is_volatile); @@ -1052,13 +1046,15 @@ TB_API TB_FuncOpt* tb_funcopt_enter(TB_Function* f, TB_Arena* arena); TB_API void tb_funcopt_exit(TB_FuncOpt* opt); TB_API bool tb_funcopt_peephole(TB_FuncOpt* opt); -TB_API bool tb_funcopt_mem2reg(TB_FuncOpt* f); -TB_API bool tb_funcopt_loop(TB_FuncOpt* f); +TB_API bool tb_funcopt_mem2reg(TB_FuncOpt* opt); +TB_API bool tb_funcopt_loop(TB_FuncOpt* opt); -TB_API void tb_funcopt_kill(TB_FuncOpt* restrict queue, TB_Node* n); +// isn't an optimization, just does the name flat form of IR printing +TB_API bool tb_funcopt_print(TB_FuncOpt* opt); -TB_API bool tb_funcopt_mark(TB_FuncOpt* restrict queue, TB_Node* n); -TB_API void tb_funcopt_mark_users(TB_FuncOpt* restrict queue, TB_Node* n); +TB_API void tb_funcopt_kill(TB_FuncOpt* opt, TB_Node* n); +TB_API bool tb_funcopt_mark(TB_FuncOpt* opt, TB_Node* n); +TB_API void tb_funcopt_mark_users(TB_FuncOpt* opt, TB_Node* n); //////////////////////////////// // IR access diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index a1f893968..a6ac5cbff 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index d695c846c..0572e2fd0 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -184,7 +184,7 @@ gb_internal void cg_create_global_variables(cgModule *m) { // gb_printf_err("max_type_info_count: %td\n", max_type_info_count); Type *t = alloc_type_array(t_type_info, max_type_info_count); - TB_Global *g = tb_global_create(m->mod, CG_TYPE_INFO_DATA_NAME, nullptr, TB_LINKAGE_PRIVATE); + TB_Global *g = tb_global_create(m->mod, -1, CG_TYPE_INFO_DATA_NAME, nullptr, TB_LINKAGE_PRIVATE); tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, max_type_info_count); cgValue value = cg_value(g, alloc_type_pointer(t)); @@ -219,7 +219,7 @@ gb_internal void cg_create_global_variables(cgModule *m) { { char const *name = CG_TYPE_INFO_TYPES_NAME; Type *t = alloc_type_array(t_type_info_ptr, count); - TB_Global *g = tb_global_create(m->mod, name, nullptr, TB_LINKAGE_PRIVATE); + TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); cg_global_type_info_member_types = cg_addr(cg_value(g, alloc_type_pointer(t))); @@ -227,14 +227,14 @@ gb_internal void cg_create_global_variables(cgModule *m) { { char const *name = CG_TYPE_INFO_NAMES_NAME; Type *t = alloc_type_array(t_string, count); - TB_Global *g = tb_global_create(m->mod, name, nullptr, TB_LINKAGE_PRIVATE); + TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); cg_global_type_info_member_names = cg_addr(cg_value(g, alloc_type_pointer(t))); } { char const *name = CG_TYPE_INFO_OFFSETS_NAME; Type *t = alloc_type_array(t_uintptr, count); - TB_Global *g = tb_global_create(m->mod, name, nullptr, TB_LINKAGE_PRIVATE); + TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); cg_global_type_info_member_offsets = cg_addr(cg_value(g, alloc_type_pointer(t))); } @@ -242,7 +242,7 @@ gb_internal void cg_create_global_variables(cgModule *m) { { char const *name = CG_TYPE_INFO_USINGS_NAME; Type *t = alloc_type_array(t_bool, count); - TB_Global *g = tb_global_create(m->mod, name, nullptr, TB_LINKAGE_PRIVATE); + TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); cg_global_type_info_member_usings = cg_addr(cg_value(g, alloc_type_pointer(t))); } @@ -250,7 +250,7 @@ gb_internal void cg_create_global_variables(cgModule *m) { { char const *name = CG_TYPE_INFO_TAGS_NAME; Type *t = alloc_type_array(t_string, count); - TB_Global *g = tb_global_create(m->mod, name, nullptr, TB_LINKAGE_PRIVATE); + TB_Global *g = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), g, type_size_of(t), 16, count); cg_global_type_info_member_tags = cg_addr(cg_value(g, alloc_type_pointer(t))); } @@ -268,7 +268,7 @@ cgModule *cg_module_create(Checker *c) { TB_FeatureSet feature_set = {}; bool is_jit = false; m->mod = tb_module_create(TB_ARCH_X86_64, TB_SYSTEM_WINDOWS, &feature_set, is_jit); - tb_module_set_tls_index(m->mod, "_tls_index"); + tb_module_set_tls_index(m->mod, 10, "_tls_index"); map_init(&m->values); array_init(&m->procedures_to_generate, heap_allocator()); @@ -634,8 +634,6 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i // p->scope_stack.allocator = a; // map_init(&p->tuple_fix_map, 0); - char const *link_name_c = alloc_cstring(temporary_allocator(), link_name); - TB_Linkage linkage = TB_LINKAGE_PRIVATE; if (p->is_export) { linkage = TB_LINKAGE_PUBLIC; @@ -643,11 +641,11 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i if (ignore_body) { linkage = TB_LINKAGE_PUBLIC; } - p->symbol = cast(TB_Symbol *)tb_extern_create(m->mod, link_name_c, TB_EXTERNAL_SO_LOCAL); + p->symbol = cast(TB_Symbol *)tb_extern_create(m->mod, link_name.len, cast(char const *)link_name.text, TB_EXTERNAL_SO_LOCAL); } if (p->symbol == nullptr) { - p->func = tb_function_create(m->mod, link_name_c, linkage, TB_COMDAT_NONE); + p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE); tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena()); p->symbol = cast(TB_Symbol *)p->func; } @@ -688,12 +686,9 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li // map_init(&p->tuple_fix_map, 0); - - char const *link_name_c = alloc_cstring(temporary_allocator(), link_name); - TB_Linkage linkage = TB_LINKAGE_PRIVATE; - p->func = tb_function_create(m->mod, link_name_c, linkage, TB_COMDAT_NONE); + p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE); tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena()); p->symbol = cast(TB_Symbol *)p->func; @@ -715,6 +710,13 @@ gb_internal void cg_procedure_end(cgProcedure *p) { return; } tb_inst_ret(p->func, 0, nullptr); + if (p->name == "main") { + TB_Arena *arena = tb_default_arena(); + defer (arena->free(arena)); + TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena); + defer (tb_funcopt_exit(opt)); + tb_funcopt_print(opt); + } tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST); } diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 44591190a..6c17f8ba3 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -212,4 +212,6 @@ gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init); -gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); \ No newline at end of file +gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); + +gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e); \ No newline at end of file diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index 7a8be70c7..97fee838e 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -8,7 +8,7 @@ gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type) { TB_Module *m = p->module->mod; char name[32] = {}; gb_snprintf(name, 31, "cnil$%u", 1+p->module->const_nil_guid.fetch_add(1)); - TB_Global *global = tb_global_create(m, name, nullptr, TB_LINKAGE_PRIVATE); + TB_Global *global = tb_global_create(m, -1, name, nullptr, TB_LINKAGE_PRIVATE); tb_global_set_storage(m, tb_module_get_rdata(m), global, size, align, 0); TB_Symbol *symbol = cast(TB_Symbol *)global; @@ -41,6 +41,18 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac return cg_const_nil(p, type); } + if (value.kind == ExactValue_Procedure) { + Ast *expr = unparen_expr(value.value_procedure); + Entity *e = entity_of_node(expr); + if (e != nullptr) { + cgValue found = cg_find_procedure_value_from_entity(m, e); + GB_ASSERT(are_types_identical(type, found.type)); + return found; + } + + } + + GB_ASSERT(node != nullptr); return cg_value(node, type); } diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index ccd126747..702cb42ad 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -101,7 +101,7 @@ gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr) { cgValue res = cg_build_expr_internal(p, expr); if (res.kind == cgValue_Symbol) { - GB_ASSERT(is_type_pointer(res.type)); + GB_ASSERT(is_type_internally_pointer_like(res.type)); res = cg_value(tb_inst_get_symbol_address(p->func, res.symbol), res.type); } @@ -161,6 +161,7 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { token_pos_to_string(token.pos)); return {}; } else if (e->kind == Entity_Nil) { + GB_PANIC("TODO: cg_find_ident nil"); // TODO(bill): is this correct? return cg_value(cast(TB_Node *)nullptr, e->type); } diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 306852db3..dbebae853 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -1,5 +1,127 @@ +gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e) { + GB_ASSERT(is_type_proc(e->type)); + e = strip_entity_wrapping(e); + GB_ASSERT(e != nullptr); + GB_ASSERT(e->kind == Entity_Procedure); + + cgValue *found = nullptr; + rw_mutex_shared_lock(&m->values_mutex); + found = map_get(&m->values, e); + rw_mutex_shared_unlock(&m->values_mutex); + if (found) { + return *found; + } + + GB_PANIC("Error in: %s, missing procedure %.*s\n", token_pos_to_string(e->token.pos), LIT(e->token.string)); + return {}; +} + + + +gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr); gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr) { + expr = unparen_expr(expr); ast_node(ce, CallExpr, expr); - // TODO(bill): cg_build_call_expr + + cgValue res = cg_build_call_expr_internal(p, expr); + + if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures + GB_PANIC("Handle optional_ok_one"); + // GB_ASSERT(is_type_tuple(res.type)); + // GB_ASSERT(res.type->Tuple.variables.count == 2); + // return cg_emit_struct_ev(p, res, 0); + } + return res; +} + +gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice args) { + if (value.kind == cgValue_Symbol) { + value = cg_value(tb_inst_get_symbol_address(p->func, value.symbol), value.type); + } + GB_ASSERT(value.kind == cgValue_Value); + + TB_FunctionPrototype *proto = cg_procedure_type_as_prototype(p->module, value.type); + TB_Node *target = value.node; + auto params = slice_make(temporary_allocator(), 0); + + GB_ASSERT(target != nullptr); + TB_MultiOutput multi_output = tb_inst_call(p->func, proto, target, 0, nullptr); + gb_unused(multi_output); return {}; -} \ No newline at end of file +} + +gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + + TypeAndValue tv = type_and_value_of_expr(expr); + + TypeAndValue proc_tv = type_and_value_of_expr(ce->proc); + AddressingMode proc_mode = proc_tv.mode; + if (proc_mode == Addressing_Type) { + GB_ASSERT(ce->args.count == 1); + cgValue x = cg_build_expr(p, ce->args[0]); + return cg_emit_conv(p, x, tv.type); + } + + Ast *proc_expr = unparen_expr(ce->proc); + if (proc_mode == Addressing_Builtin) { + Entity *e = entity_of_node(proc_expr); + BuiltinProcId id = BuiltinProc_Invalid; + if (e != nullptr) { + id = cast(BuiltinProcId)e->Builtin.id; + } else { + id = BuiltinProc_DIRECTIVE; + } + if (id == BuiltinProc___entry_point) { + if (p->module->info->entry_point) { + cgValue entry_point = cg_find_procedure_value_from_entity(p->module, p->module->info->entry_point); + GB_ASSERT(entry_point.node != nullptr); + cg_emit_call(p, entry_point, {}); + } + return {}; + } + GB_PANIC("TODO(bill): builtin procs %d %.*s", id, LIT(builtin_procs[id].name)); + } + + // NOTE(bill): Regular call + cgValue value = {}; + + Entity *proc_entity = entity_of_node(proc_expr); + if (proc_entity != nullptr) { + if (proc_entity->flags & EntityFlag_Disabled) { + GB_ASSERT(tv.type == nullptr); + return {}; + } + } + + if (proc_expr->tav.mode == Addressing_Constant) { + ExactValue v = proc_expr->tav.value; + switch (v.kind) { + case ExactValue_Integer: + { + u64 u = big_int_to_u64(&v.value_integer); + cgValue x = cg_value(tb_inst_uint(p->func, TB_TYPE_PTR, u), t_rawptr); + value = cg_emit_conv(p, x, proc_expr->tav.type); + break; + } + case ExactValue_Pointer: + { + u64 u = cast(u64)v.value_pointer; + cgValue x = cg_value(tb_inst_uint(p->func, TB_TYPE_PTR, u), t_rawptr); + value = cg_emit_conv(p, x, proc_expr->tav.type); + break; + } + } + } + + if (value.node == nullptr) { + value = cg_build_expr(p, proc_expr); + } + if (value.kind == cgValue_Addr) { + value = cg_emit_load(p, value); + } + GB_ASSERT(value.kind == cgValue_Value); + GB_ASSERT(is_type_proc(value.type)); + + return cg_emit_call(p, value, {}); +} diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index f7e68d483..07bfc0555 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -8,14 +8,16 @@ gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_vol case cgValue_Value: return cg_lvalue_addr(ptr.node, type); case cgValue_Addr: - GB_PANIC("NOT POSSIBLE"); + GB_PANIC("NOT POSSIBLE - Cannot load an lvalue to begin with"); break; case cgValue_Symbol: return cg_lvalue_addr(tb_inst_get_symbol_address(p->func, ptr.symbol), type); } } - TB_CharUnits alignment = 1; // for the time being + // use the natural alignment + // if people need a special alignment, they can use `intrinsics.unaligned_load` + TB_CharUnits alignment = cast(TB_CharUnits)type_align_of(type); TB_Node *the_ptr = nullptr; switch (ptr.kind) { @@ -48,7 +50,9 @@ gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, TB_DataType st = cg_data_type(src.type); GB_ASSERT(dt.raw == st.raw); - TB_CharUnits alignment = 1; // for the time being + // use the natural alignment + // if people need a special alignment, they can use `intrinsics.unaligned_store` + TB_CharUnits alignment = cast(TB_CharUnits)type_align_of(dst_type); if (TB_IS_VOID_TYPE(dt)) { TB_Node *dst_ptr = nullptr; @@ -281,10 +285,9 @@ gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { // NOTE(bill): for debugging purposes only - char const *name = alloc_cstring(permanent_allocator(), e->token.string); - - TB_DebugType *debug_type = cg_debug_type(p->module, type); - tb_function_attrib_variable(p->func, local, name, debug_type); + // String name = e->token.string; + // TB_DebugType *debug_type = cg_debug_type(p->module, type); + // tb_function_attrib_variable(p->func, name.len, cast(char const *)name.text, debug_type); } if (zero_init) { @@ -546,7 +549,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { case_end; case_ast_node(as, AssignStmt, node); - cg_build_assign_stmt(p, as); + // cg_build_assign_stmt(p, as); case_end; case_ast_node(rs, ReturnStmt, node); -- cgit v1.2.3 From ccb736411bc61a0ccde6835cbbf1876a2616e3e1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jul 2023 13:30:31 +0100 Subject: Basic `context` creation --- src/tilde_backend.cpp | 289 ------------------------------------------------- src/tilde_backend.hpp | 16 ++- src/tilde_expr.cpp | 147 ++++++++++++++++++++++++- src/tilde_proc.cpp | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/tilde_stmt.cpp | 2 +- 5 files changed, 451 insertions(+), 293 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index 0572e2fd0..97f92e3db 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -446,295 +446,6 @@ struct cgGlobalVariable { bool is_initialized; }; - -gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Type *type) { - GB_ASSERT(type != nullptr); - type = base_type(type); - GB_ASSERT(type->kind == Type_Proc); - TypeProc *pt = &type->Proc; - - auto params = array_make(heap_allocator(), 0, pt->param_count); - if (pt->params) for (Entity *e : pt->params->Tuple.variables) { - TB_PrototypeParam param = {}; - - Type *t = core_type(e->type); - i64 sz = type_size_of(t); - switch (t->kind) { - case Type_Basic: - switch (t->Basic.kind) { - case Basic_bool: - case Basic_b8: - case Basic_b16: - case Basic_b32: - case Basic_b64: - case Basic_i8: - case Basic_u8: - case Basic_i16: - case Basic_u16: - case Basic_i32: - case Basic_u32: - case Basic_i64: - case Basic_u64: - case Basic_i128: - case Basic_u128: - case Basic_rune: - case Basic_int: - case Basic_uint: - case Basic_uintptr: - param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); - break; - - case Basic_f16: param.dt = TB_TYPE_I16; break; - case Basic_f32: param.dt = TB_TYPE_F32; break; - case Basic_f64: param.dt = TB_TYPE_F64; break; - - case Basic_complex32: - case Basic_complex64: - case Basic_complex128: - case Basic_quaternion64: - case Basic_quaternion128: - case Basic_quaternion256: - param.dt = TB_TYPE_PTR; - break; - - - case Basic_rawptr: - param.dt = TB_TYPE_PTR; - break; - case Basic_string: // ^u8 + int - param.dt = TB_TYPE_PTR; - break; - case Basic_cstring: // ^u8 - param.dt = TB_TYPE_PTR; - break; - case Basic_any: // rawptr + ^Type_Info - param.dt = TB_TYPE_PTR; - break; - - case Basic_typeid: - param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); - break; - - // Endian Specific Types - case Basic_i16le: - case Basic_u16le: - case Basic_i32le: - case Basic_u32le: - case Basic_i64le: - case Basic_u64le: - case Basic_i128le: - case Basic_u128le: - case Basic_i16be: - case Basic_u16be: - case Basic_i32be: - case Basic_u32be: - case Basic_i64be: - case Basic_u64be: - case Basic_i128be: - case Basic_u128be: - param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); - break; - - case Basic_f16le: param.dt = TB_TYPE_I16; break; - case Basic_f32le: param.dt = TB_TYPE_F32; break; - case Basic_f64le: param.dt = TB_TYPE_F64; break; - - case Basic_f16be: param.dt = TB_TYPE_I16; break; - case Basic_f32be: param.dt = TB_TYPE_F32; break; - case Basic_f64be: param.dt = TB_TYPE_F64; break; - } - - case Type_Pointer: - case Type_MultiPointer: - case Type_Proc: - param.dt = TB_TYPE_PTR; - break; - - default: - switch (sz) { - case 1: param.dt = TB_TYPE_I8; break; - case 2: param.dt = TB_TYPE_I16; break; - case 4: param.dt = TB_TYPE_I32; break; - case 8: param.dt = TB_TYPE_I64; break; - default: - param.dt = TB_TYPE_PTR; - break; - } - } - - if (param.dt.width != 0) { - if (is_blank_ident(e->token)) { - param.name = alloc_cstring(temporary_allocator(), e->token.string); - } - array_add(¶ms, param); - } - } - - auto results = array_make(heap_allocator(), 0, pt->result_count); - // if (pt->results) for (Entity *e : pt->params->Tuple.variables) { - // // TODO(bill): - // } - - - return tb_prototype_create(m->mod, TB_CDECL, params.count, params.data, results.count, results.data, pt->c_vararg); -} - -gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool ignore_body=false) { - GB_ASSERT(entity != nullptr); - GB_ASSERT(entity->kind == Entity_Procedure); - if (!entity->Procedure.is_foreign) { - if ((entity->flags & EntityFlag_ProcBodyChecked) == 0) { - GB_PANIC("%.*s :: %s (was parapoly: %d %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true), is_type_polymorphic(entity->type, false)); - } - } - - String link_name = cg_get_entity_name(m, entity); - - cgProcedure *p = nullptr; - { - StringHashKey key = string_hash_string(link_name); - cgValue *found = string_map_get(&m->members, key); - if (found) { - cg_add_entity(m, entity, *found); - p = string_map_must_get(&m->procedures, key); - if (!ignore_body && p->func != nullptr) { - return nullptr; - } - } - } - - if (p == nullptr) { - p = gb_alloc_item(permanent_allocator(), cgProcedure); - } - - p->module = m; - p->entity = entity; - p->name = link_name; - - DeclInfo *decl = entity->decl_info; - - ast_node(pl, ProcLit, decl->proc_lit); - Type *pt = base_type(entity->type); - GB_ASSERT(pt->kind == Type_Proc); - - p->type = entity->type; - p->type_expr = decl->type_expr; - p->body = pl->body; - p->inlining = pl->inlining; - p->is_foreign = entity->Procedure.is_foreign; - p->is_export = entity->Procedure.is_export; - p->is_entry_point = false; - - gbAllocator a = heap_allocator(); - p->children.allocator = a; - // p->defer_stmts.allocator = a; - // p->blocks.allocator = a; - // p->branch_blocks.allocator = a; - // p->context_stack.allocator = a; - // p->scope_stack.allocator = a; - // map_init(&p->tuple_fix_map, 0); - - TB_Linkage linkage = TB_LINKAGE_PRIVATE; - if (p->is_export) { - linkage = TB_LINKAGE_PUBLIC; - } else if (p->is_foreign || ignore_body) { - if (ignore_body) { - linkage = TB_LINKAGE_PUBLIC; - } - p->symbol = cast(TB_Symbol *)tb_extern_create(m->mod, link_name.len, cast(char const *)link_name.text, TB_EXTERNAL_SO_LOCAL); - } - - if (p->symbol == nullptr) { - p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE); - tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena()); - p->symbol = cast(TB_Symbol *)p->func; - } - - cgValue proc_value = cg_value(p->symbol, p->type); - cg_add_entity(m, entity, proc_value); - cg_add_member(m, p->name, proc_value); - cg_add_procedure_value(m, p); - - - return p; -} - -gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &link_name, Type *type) { - auto *prev_found = string_map_get(&m->members, link_name); - GB_ASSERT_MSG(prev_found == nullptr, "failed to create dummy procedure for: %.*s", LIT(link_name)); - - cgProcedure *p = gb_alloc_item(permanent_allocator(), cgProcedure); - - p->module = m; - p->name = link_name; - - p->type = type; - p->type_expr = nullptr; - p->body = nullptr; - p->tags = 0; - p->inlining = ProcInlining_none; - p->is_foreign = false; - p->is_export = false; - p->is_entry_point = false; - - gbAllocator a = heap_allocator(); - p->children.allocator = a; - // p->defer_stmts.allocator = a; - // p->blocks.allocator = a; - // p->branch_blocks.allocator = a; - // p->context_stack.allocator = a; - // map_init(&p->tuple_fix_map, 0); - - - TB_Linkage linkage = TB_LINKAGE_PRIVATE; - - p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE); - tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena()); - p->symbol = cast(TB_Symbol *)p->func; - - cgValue proc_value = cg_value(p->symbol, p->type); - cg_add_member(m, p->name, proc_value); - cg_add_procedure_value(m, p); - - return p; -} - -gb_internal void cg_procedure_begin(cgProcedure *p) { - if (p == nullptr || p->func == nullptr) { - return; - } -} - -gb_internal void cg_procedure_end(cgProcedure *p) { - if (p == nullptr || p->func == nullptr) { - return; - } - tb_inst_ret(p->func, 0, nullptr); - if (p->name == "main") { - TB_Arena *arena = tb_default_arena(); - defer (arena->free(arena)); - TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena); - defer (tb_funcopt_exit(opt)); - tb_funcopt_print(opt); - } - tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST); -} - -gb_internal void cg_procedure_generate(cgProcedure *p) { - if (p->body == nullptr) { - return; - } - cg_procedure_begin(p); - defer (cg_procedure_end(p)); - - if (p->name != "bug.main" && - p->name != "main") { - return; - } - cg_build_stmt(p, p->body); -} - - #include "tilde_const.cpp" #include "tilde_expr.cpp" #include "tilde_proc.cpp" diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 6c17f8ba3..1f7300d73 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -113,7 +113,11 @@ enum cgDeferExitKind { cgDeferExit_Branch, }; - +struct cgContextData { + cgAddr ctx; + isize scope_index; + isize uses; +}; struct cgProcedure { u32 flags; @@ -144,6 +148,12 @@ struct cgProcedure { cgTargetList * target_list; Array branch_blocks; + + Scope *curr_scope; + i32 scope_index; + + Array scope_stack; + Array context_stack; }; @@ -214,4 +224,6 @@ gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); -gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e); \ No newline at end of file +gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e); + +gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type); \ No newline at end of file diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 702cb42ad..22da43cbd 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -1,3 +1,89 @@ +gb_internal cgContextData *cg_push_context_onto_stack(cgProcedure *p, cgAddr ctx) { + ctx.kind = cgAddr_Context; + cgContextData *cd = array_add_and_get(&p->context_stack); + cd->ctx = ctx; + cd->scope_index = p->scope_index; + return cd; +} + +gb_internal cgAddr cg_find_or_generate_context_ptr(cgProcedure *p) { + if (p->context_stack.count > 0) { + return p->context_stack[p->context_stack.count-1].ctx; + } + + Type *pt = base_type(p->type); + GB_ASSERT(pt->kind == Type_Proc); + GB_ASSERT(pt->Proc.calling_convention != ProcCC_Odin); + + cgAddr c = cg_add_local(p, t_context, nullptr, true); + tb_node_append_attrib(c.addr.node, tb_function_attrib_variable(p->func, -1, "context", cg_debug_type(p->module, t_context))); + c.kind = cgAddr_Context; + // lb_emit_init_context(p, c); + cg_push_context_onto_stack(p, c); + // lb_add_debug_context_variable(p, c); + + return c; +} + +gb_internal cgValue cg_find_value_from_entity(cgModule *m, Entity *e) { + e = strip_entity_wrapping(e); + GB_ASSERT(e != nullptr); + + GB_ASSERT(e->token.string != "_"); + + if (e->kind == Entity_Procedure) { + return cg_find_procedure_value_from_entity(m, e); + } + + cgValue *found = nullptr; + rw_mutex_shared_lock(&m->values_mutex); + found = map_get(&m->values, e); + rw_mutex_shared_unlock(&m->values_mutex); + if (found) { + return *found; + } + + // GB_PANIC("\n\tError in: %s, missing value '%.*s'\n", token_pos_to_string(e->token.pos), LIT(e->token.string)); + return {}; +} + +gb_internal cgAddr cg_build_addr_from_entity(cgProcedure *p, Entity *e, Ast *expr) { + GB_ASSERT(e != nullptr); + if (e->kind == Entity_Constant) { + Type *t = default_type(type_of_expr(expr)); + cgValue v = cg_const_value(p, t, e->Constant.value); + GB_PANIC("TODO(bill): cg_add_global_generated"); + // return cg_add_global_generated(p->module, t, v); + return {}; + } + + + cgValue v = {}; + + cgModule *m = p->module; + + rw_mutex_lock(&m->values_mutex); + cgValue *found = map_get(&m->values, e); + rw_mutex_unlock(&m->values_mutex); + if (found) { + v = *found; + } else if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { + GB_PANIC("TODO(bill): cg_get_using_variable"); + // NOTE(bill): Calculate the using variable every time + // v = cg_get_using_variable(p, e); + } else if (e->flags & EntityFlag_SoaPtrField) { + GB_PANIC("TODO(bill): cg_get_soa_variable_addr"); + // return cg_get_soa_variable_addr(p, e); + } + + + if (v.node == nullptr) { + return cg_addr(cg_find_value_from_entity(m, e)); + } + + return cg_addr(v); +} + gb_internal cgValue cg_typeid(cgModule *m, Type *t) { GB_ASSERT("TODO(bill): cg_typeid"); return {}; @@ -248,6 +334,65 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { } +gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr); gb_internal cgAddr cg_build_addr(cgProcedure *p, Ast *expr) { - return {}; + expr = unparen_expr(expr); + + // IMPORTANT NOTE(bill): + // Selector Call Expressions (foo->bar(...)) + // must only evaluate `foo` once as it gets transformed into + // `foo.bar(foo, ...)` + // And if `foo` is a procedure call or something more complex, storing the value + // once is a very good idea + // If a stored value is found, it must be removed from the cache + if (expr->state_flags & StateFlag_SelectorCallExpr) { + // lbAddr *pp = map_get(&p->selector_addr, expr); + // if (pp != nullptr) { + // lbAddr res = *pp; + // map_remove(&p->selector_addr, expr); + // return res; + // } + } + cgAddr addr = cg_build_addr_internal(p, expr); + if (expr->state_flags & StateFlag_SelectorCallExpr) { + // map_set(&p->selector_addr, expr, addr); + } + return addr; } + + +gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) { + switch (expr->kind) { + case_ast_node(i, Implicit, expr); + cgAddr v = {}; + switch (i->kind) { + case Token_context: + v = cg_find_or_generate_context_ptr(p); + break; + } + + GB_ASSERT(v.addr.node != nullptr); + return v; + case_end; + + case_ast_node(i, Ident, expr); + if (is_blank_ident(expr)) { + cgAddr val = {}; + return val; + } + String name = i->token.string; + Entity *e = entity_of_node(expr); + return cg_build_addr_from_entity(p, e, expr); + case_end; + } + + TokenPos token_pos = ast_token(expr).pos; + GB_PANIC("Unexpected address expression\n" + "\tAst: %.*s @ " + "%s\n", + LIT(ast_strings[expr->kind]), + token_pos_to_string(token_pos)); + + + return {}; +} \ No newline at end of file diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index dbebae853..b60e797c3 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -1,3 +1,293 @@ +gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Type *type) { + GB_ASSERT(type != nullptr); + type = base_type(type); + GB_ASSERT(type->kind == Type_Proc); + TypeProc *pt = &type->Proc; + + auto params = array_make(heap_allocator(), 0, pt->param_count); + if (pt->params) for (Entity *e : pt->params->Tuple.variables) { + TB_PrototypeParam param = {}; + + Type *t = core_type(e->type); + i64 sz = type_size_of(t); + switch (t->kind) { + case Type_Basic: + switch (t->Basic.kind) { + case Basic_bool: + case Basic_b8: + case Basic_b16: + case Basic_b32: + case Basic_b64: + case Basic_i8: + case Basic_u8: + case Basic_i16: + case Basic_u16: + case Basic_i32: + case Basic_u32: + case Basic_i64: + case Basic_u64: + case Basic_i128: + case Basic_u128: + case Basic_rune: + case Basic_int: + case Basic_uint: + case Basic_uintptr: + param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + break; + + case Basic_f16: param.dt = TB_TYPE_I16; break; + case Basic_f32: param.dt = TB_TYPE_F32; break; + case Basic_f64: param.dt = TB_TYPE_F64; break; + + case Basic_complex32: + case Basic_complex64: + case Basic_complex128: + case Basic_quaternion64: + case Basic_quaternion128: + case Basic_quaternion256: + param.dt = TB_TYPE_PTR; + break; + + + case Basic_rawptr: + param.dt = TB_TYPE_PTR; + break; + case Basic_string: // ^u8 + int + param.dt = TB_TYPE_PTR; + break; + case Basic_cstring: // ^u8 + param.dt = TB_TYPE_PTR; + break; + case Basic_any: // rawptr + ^Type_Info + param.dt = TB_TYPE_PTR; + break; + + case Basic_typeid: + param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + break; + + // Endian Specific Types + case Basic_i16le: + case Basic_u16le: + case Basic_i32le: + case Basic_u32le: + case Basic_i64le: + case Basic_u64le: + case Basic_i128le: + case Basic_u128le: + case Basic_i16be: + case Basic_u16be: + case Basic_i32be: + case Basic_u32be: + case Basic_i64be: + case Basic_u64be: + case Basic_i128be: + case Basic_u128be: + param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + break; + + case Basic_f16le: param.dt = TB_TYPE_I16; break; + case Basic_f32le: param.dt = TB_TYPE_F32; break; + case Basic_f64le: param.dt = TB_TYPE_F64; break; + + case Basic_f16be: param.dt = TB_TYPE_I16; break; + case Basic_f32be: param.dt = TB_TYPE_F32; break; + case Basic_f64be: param.dt = TB_TYPE_F64; break; + } + + case Type_Pointer: + case Type_MultiPointer: + case Type_Proc: + param.dt = TB_TYPE_PTR; + break; + + default: + switch (sz) { + case 1: param.dt = TB_TYPE_I8; break; + case 2: param.dt = TB_TYPE_I16; break; + case 4: param.dt = TB_TYPE_I32; break; + case 8: param.dt = TB_TYPE_I64; break; + default: + param.dt = TB_TYPE_PTR; + break; + } + } + + if (param.dt.width != 0) { + if (is_blank_ident(e->token)) { + param.name = alloc_cstring(temporary_allocator(), e->token.string); + } + array_add(¶ms, param); + } + } + + auto results = array_make(heap_allocator(), 0, pt->result_count); + // if (pt->results) for (Entity *e : pt->params->Tuple.variables) { + // // TODO(bill): + // } + + + return tb_prototype_create(m->mod, TB_CDECL, params.count, params.data, results.count, results.data, pt->c_vararg); +} + +gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool ignore_body=false) { + GB_ASSERT(entity != nullptr); + GB_ASSERT(entity->kind == Entity_Procedure); + if (!entity->Procedure.is_foreign) { + if ((entity->flags & EntityFlag_ProcBodyChecked) == 0) { + GB_PANIC("%.*s :: %s (was parapoly: %d %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true), is_type_polymorphic(entity->type, false)); + } + } + + String link_name = cg_get_entity_name(m, entity); + + cgProcedure *p = nullptr; + { + StringHashKey key = string_hash_string(link_name); + cgValue *found = string_map_get(&m->members, key); + if (found) { + cg_add_entity(m, entity, *found); + p = string_map_must_get(&m->procedures, key); + if (!ignore_body && p->func != nullptr) { + return nullptr; + } + } + } + + if (p == nullptr) { + p = gb_alloc_item(permanent_allocator(), cgProcedure); + } + + p->module = m; + p->entity = entity; + p->name = link_name; + + DeclInfo *decl = entity->decl_info; + + ast_node(pl, ProcLit, decl->proc_lit); + Type *pt = base_type(entity->type); + GB_ASSERT(pt->kind == Type_Proc); + + p->type = entity->type; + p->type_expr = decl->type_expr; + p->body = pl->body; + p->inlining = pl->inlining; + p->is_foreign = entity->Procedure.is_foreign; + p->is_export = entity->Procedure.is_export; + p->is_entry_point = false; + + gbAllocator a = heap_allocator(); + p->children.allocator = a; + // p->defer_stmts.allocator = a; + // p->blocks.allocator = a; + // p->branch_blocks.allocator = a; + p->context_stack.allocator = a; + p->scope_stack.allocator = a; + // map_init(&p->tuple_fix_map, 0); + + TB_Linkage linkage = TB_LINKAGE_PRIVATE; + if (p->is_export) { + linkage = TB_LINKAGE_PUBLIC; + } else if (p->is_foreign || ignore_body) { + if (ignore_body) { + linkage = TB_LINKAGE_PUBLIC; + } + p->symbol = cast(TB_Symbol *)tb_extern_create(m->mod, link_name.len, cast(char const *)link_name.text, TB_EXTERNAL_SO_LOCAL); + } + + if (p->symbol == nullptr) { + p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE); + tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena()); + p->symbol = cast(TB_Symbol *)p->func; + } + + cgValue proc_value = cg_value(p->symbol, p->type); + cg_add_entity(m, entity, proc_value); + cg_add_member(m, p->name, proc_value); + cg_add_procedure_value(m, p); + + + return p; +} + +gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &link_name, Type *type) { + auto *prev_found = string_map_get(&m->members, link_name); + GB_ASSERT_MSG(prev_found == nullptr, "failed to create dummy procedure for: %.*s", LIT(link_name)); + + cgProcedure *p = gb_alloc_item(permanent_allocator(), cgProcedure); + + p->module = m; + p->name = link_name; + + p->type = type; + p->type_expr = nullptr; + p->body = nullptr; + p->tags = 0; + p->inlining = ProcInlining_none; + p->is_foreign = false; + p->is_export = false; + p->is_entry_point = false; + + gbAllocator a = heap_allocator(); + p->children.allocator = a; + // p->defer_stmts.allocator = a; + // p->blocks.allocator = a; + // p->branch_blocks.allocator = a; + p->scope_stack.allocator = a; + p->context_stack.allocator = a; + // map_init(&p->tuple_fix_map, 0); + + + TB_Linkage linkage = TB_LINKAGE_PRIVATE; + + p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE); + tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena()); + p->symbol = cast(TB_Symbol *)p->func; + + cgValue proc_value = cg_value(p->symbol, p->type); + cg_add_member(m, p->name, proc_value); + cg_add_procedure_value(m, p); + + return p; +} + +gb_internal void cg_procedure_begin(cgProcedure *p) { + if (p == nullptr || p->func == nullptr) { + return; + } +} + +gb_internal void cg_procedure_end(cgProcedure *p) { + if (p == nullptr || p->func == nullptr) { + return; + } + tb_inst_ret(p->func, 0, nullptr); + if (p->name == "main") { + TB_Arena *arena = tb_default_arena(); + defer (arena->free(arena)); + TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena); + defer (tb_funcopt_exit(opt)); + tb_funcopt_print(opt); + } + tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST); +} + +gb_internal void cg_procedure_generate(cgProcedure *p) { + if (p->body == nullptr) { + return; + } + cg_procedure_begin(p); + defer (cg_procedure_end(p)); + + if (p->name != "bug.main" && + p->name != "main") { + return; + } + cg_build_stmt(p, p->body); +} + + + gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e) { GB_ASSERT(is_type_proc(e->type)); e = strip_entity_wrapping(e); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 07bfc0555..7c3dfcef8 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -549,7 +549,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { case_end; case_ast_node(as, AssignStmt, node); - // cg_build_assign_stmt(p, as); + cg_build_assign_stmt(p, as); case_end; case_ast_node(rs, ReturnStmt, node); -- cgit v1.2.3 From ee8372145d62bf90c0fe43c78b96a02b6247321e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 15 Jul 2023 14:26:47 +0100 Subject: Begin working on proper expressions --- src/tilde/tb.lib | Bin 4120106 -> 4112646 bytes src/tilde_backend.cpp | 178 ++++++++++++++++++++++++--------- src/tilde_backend.hpp | 11 ++- src/tilde_const.cpp | 97 ++++++++++++++---- src/tilde_expr.cpp | 265 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/tilde_proc.cpp | 84 +++++++++++++++- src/tilde_stmt.cpp | 75 ++++++++++++-- 7 files changed, 630 insertions(+), 80 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index a6ac5cbff..bad51e7e6 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index 97f92e3db..dfe39c385 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -33,7 +33,7 @@ gb_internal TB_DataType cg_data_type(Type *t) { case Basic_typeid: return TB_TYPE_INTN(cast(u16)(8*sz)); - case Basic_f16: return TB_TYPE_I16; + case Basic_f16: return TB_TYPE_F16; case Basic_f32: return TB_TYPE_F32; case Basic_f64: return TB_TYPE_F64; @@ -60,11 +60,11 @@ gb_internal TB_DataType cg_data_type(Type *t) { case Basic_u128be: return TB_TYPE_INTN(cast(u16)(8*sz)); - case Basic_f16le: return TB_TYPE_I16; + case Basic_f16le: return TB_TYPE_F16; case Basic_f32le: return TB_TYPE_F32; case Basic_f64le: return TB_TYPE_F64; - case Basic_f16be: return TB_TYPE_I16; + case Basic_f16be: return TB_TYPE_F16; case Basic_f32be: return TB_TYPE_F32; case Basic_f64be: return TB_TYPE_F64; } @@ -173,9 +173,128 @@ gb_internal isize cg_type_info_index(CheckerInfo *info, Type *type, bool err_on_ return -1; } -gb_internal void cg_create_global_variables(cgModule *m) { +struct cgGlobalVariable { + cgValue var; + cgValue init; + DeclInfo *decl; + bool is_initialized; +}; + +// Returns already_has_entry_point +gb_internal bool cg_global_variables_create(cgModule *m) { + isize global_variable_max_count = 0; + bool already_has_entry_point = false; + + for (Entity *e : m->info->entities) { + String name = e->token.string; + + if (e->kind == Entity_Variable) { + global_variable_max_count++; + } else if (e->kind == Entity_Procedure) { + if ((e->scope->flags&ScopeFlag_Init) && name == "main") { + GB_ASSERT(e == m->info->entry_point); + } + if (build_context.command_kind == Command_test && + (e->Procedure.is_export || e->Procedure.link_name.len > 0)) { + String link_name = e->Procedure.link_name; + if (e->pkg->kind == Package_Runtime) { + if (link_name == "main" || + link_name == "DllMain" || + link_name == "WinMain" || + link_name == "wWinMain" || + link_name == "mainCRTStartup" || + link_name == "_start") { + already_has_entry_point = true; + } + } + } + } + } + auto global_variables = array_make(permanent_allocator(), 0, global_variable_max_count); + + auto *min_dep_set = &m->info->minimum_dependency_set; + + for (DeclInfo *d : m->info->variable_init_order) { + Entity *e = d->entity; + + if ((e->scope->flags & ScopeFlag_File) == 0) { + continue; + } + + if (!ptr_set_exists(min_dep_set, e)) { + continue; + } + + DeclInfo *decl = decl_info_of_entity(e); + if (decl == nullptr) { + continue; + } + GB_ASSERT(e->kind == Entity_Variable); + + bool is_foreign = e->Variable.is_foreign; + bool is_export = e->Variable.is_export; + + String name = cg_get_entity_name(m, e); + + TB_Linkage linkage = TB_LINKAGE_PRIVATE; + + if (is_foreign) { + linkage = TB_LINKAGE_PUBLIC; + // lb_add_foreign_library_path(m, e->Variable.foreign_library); + // lb_set_wasm_import_attributes(g.value, e, name); + } else if (is_export) { + linkage = TB_LINKAGE_PUBLIC; + } + // lb_set_linkage_from_entity_flags(m, g.value, e->flags); + + TB_DebugType *debug_type = cg_debug_type(m, e->type); + TB_Global *global = tb_global_create(m->mod, name.len, cast(char const *)name.text, debug_type, linkage); + cgValue g = cg_value(global, alloc_type_pointer(e->type)); + + TB_ModuleSection *section = tb_module_get_data(m->mod); + + if (e->Variable.thread_local_model != "") { + section = tb_module_get_tls(m->mod); + } + if (e->Variable.link_section.len > 0) { + // TODO(bill): custom module sections + // LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section)); + } + + size_t max_objects = 0; + tb_global_set_storage(m->mod, section, global, type_size_of(e->type), type_align_of(e->type), max_objects); + + cgGlobalVariable var = {}; + var.var = g; + var.decl = decl; + + if (decl->init_expr != nullptr) { + // TypeAndValue tav = type_and_value_of_expr(decl->init_expr); + // if (!is_type_any(e->type) && !is_type_union(e->type)) { + // if (tav.mode != Addressing_Invalid) { + // if (tav.value.kind != ExactValue_Invalid) { + // ExactValue v = tav.value; + // lbValue init = lb_const_value(m, tav.type, v); + // LLVMSetInitializer(g.value, init.value); + // var.is_initialized = true; + // } + // } + // } + // if (!var.is_initialized && is_type_untyped_nil(tav.type)) { + // var.is_initialized = true; + // } + } + + array_add(&global_variables, var); + + cg_add_entity(m, e, g); + cg_add_member(m, name, g); + } + + + if (build_context.no_rtti) { - return; + return already_has_entry_point; } CheckerInfo *info = m->info; @@ -256,9 +375,11 @@ gb_internal void cg_create_global_variables(cgModule *m) { } } } + + return already_has_entry_point; } -cgModule *cg_module_create(Checker *c) { +gb_internal cgModule *cg_module_create(Checker *c) { cgModule *m = gb_alloc_item(permanent_allocator(), cgModule); m->checker = c; @@ -286,7 +407,7 @@ cgModule *cg_module_create(Checker *c) { return m; } -void cg_module_destroy(cgModule *m) { +gb_internal void cg_module_destroy(cgModule *m) { map_destroy(&m->values); array_free(&m->procedures_to_generate); map_destroy(&m->file_id_map); @@ -391,7 +512,7 @@ gb_internal String cg_mangle_name(cgModule *m, Entity *e) { return mangled_name; } -String cg_get_entity_name(cgModule *m, Entity *e) { +gb_internal String cg_get_entity_name(cgModule *m, Entity *e) { if (e != nullptr && e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) { return e->TypeName.ir_mangled_name; } @@ -438,14 +559,6 @@ String cg_get_entity_name(cgModule *m, Entity *e) { return name; } - -struct cgGlobalVariable { - cgValue var; - cgValue init; - DeclInfo *decl; - bool is_initialized; -}; - #include "tilde_const.cpp" #include "tilde_expr.cpp" #include "tilde_proc.cpp" @@ -463,37 +576,8 @@ gb_internal bool cg_generate_code(Checker *c) { TIME_SECTION("Tilde Global Variables"); - cg_create_global_variables(m); - - // isize global_variable_max_count = 0; - // bool already_has_entry_point = false; - - // for (Entity *e : info->entities) { - // String name = e->token.string; - - // if (e->kind == Entity_Variable) { - // global_variable_max_count++; - // } else if (e->kind == Entity_Procedure) { - // if ((e->scope->flags&ScopeFlag_Init) && name == "main") { - // GB_ASSERT(e == info->entry_point); - // } - // if (build_context.command_kind == Command_test && - // (e->Procedure.is_export || e->Procedure.link_name.len > 0)) { - // String link_name = e->Procedure.link_name; - // if (e->pkg->kind == Package_Runtime) { - // if (link_name == "main" || - // link_name == "DllMain" || - // link_name == "WinMain" || - // link_name == "wWinMain" || - // link_name == "mainCRTStartup" || - // link_name == "_start") { - // already_has_entry_point = true; - // } - // } - // } - // } - // } - // auto global_variables = array_make(permanent_allocator(), 0, global_variable_max_count); + bool already_has_entry_point = cg_global_variables_create(m); + gb_unused(already_has_entry_point); if (true) { Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 1f7300d73..228afb6af 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -7,6 +7,7 @@ #include "tilde/tb.h" +#define TB_TYPE_F16 TB_DataType{ { TB_INT, 0, 16 } } #define TB_TYPE_I128 TB_DataType{ { TB_INT, 0, 128 } } #define TB_TYPE_INT TB_TYPE_INTN(cast(u16)build_context.int_size) #define TB_TYPE_INTPTR TB_TYPE_INTN(cast(u16)build_context.ptr_size) @@ -127,6 +128,7 @@ struct cgProcedure { Array children; TB_Function *func; + TB_FunctionPrototype *proto; TB_Symbol *symbol; Entity * entity; @@ -151,9 +153,12 @@ struct cgProcedure { Scope *curr_scope; i32 scope_index; + bool in_multi_assignment; Array scope_stack; Array context_stack; + + PtrMap variable_map; }; @@ -226,4 +231,8 @@ gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e); -gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type); \ No newline at end of file +gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type); + +gb_internal String cg_get_entity_name(cgModule *m, Entity *e); + +gb_internal cgValue cg_typeid(cgModule *m, Type *t); \ No newline at end of file diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index 97fee838e..35c87641f 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -1,19 +1,31 @@ -gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type) { +gb_internal bool cg_is_expr_constant_zero(Ast *expr) { + GB_ASSERT(expr != nullptr); + auto v = exact_value_to_integer(expr->tav.value); + if (v.kind == ExactValue_Integer) { + return big_int_cmp_zero(&v.value_integer) == 0; + } + return false; +} + +gb_internal cgValue cg_const_nil(cgModule *m, cgProcedure *p, Type *type) { Type *original_type = type; type = core_type(type); i64 size = type_size_of(type); i64 align = type_align_of(type); TB_DataType dt = cg_data_type(type); if (TB_IS_VOID_TYPE(dt)) { - TB_Module *m = p->module->mod; char name[32] = {}; - gb_snprintf(name, 31, "cnil$%u", 1+p->module->const_nil_guid.fetch_add(1)); - TB_Global *global = tb_global_create(m, -1, name, nullptr, TB_LINKAGE_PRIVATE); - tb_global_set_storage(m, tb_module_get_rdata(m), global, size, align, 0); + gb_snprintf(name, 31, "cnil$%u", 1+m->const_nil_guid.fetch_add(1)); + TB_Global *global = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, size, align, 0); TB_Symbol *symbol = cast(TB_Symbol *)global; - TB_Node *node = tb_inst_get_symbol_address(p->func, symbol); - return cg_lvalue_addr(node, type); + if (p) { + TB_Node *node = tb_inst_get_symbol_address(p->func, symbol); + return cg_lvalue_addr(node, type); + } else { + GB_PANIC("TODO(bill): cg_const_nil"); + } } if (is_type_internally_pointer_like(type)) { @@ -34,24 +46,71 @@ gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type) { return {}; } -gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, ExactValue const &value) { +gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type) { + return cg_const_nil(p->module, p, type); +} + +gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, ExactValue const &value, bool allow_local = true) { TB_Node *node = nullptr; - if (value.kind == ExactValue_Invalid) { + bool is_local = allow_local && p != nullptr; + gb_unused(is_local); + + TB_DataType dt = cg_data_type(type); + + switch (value.kind) { + case ExactValue_Invalid: return cg_const_nil(p, type); + + case ExactValue_Typeid: + return cg_typeid(m, value.value_typeid); + + case ExactValue_Procedure: + { + Ast *expr = unparen_expr(value.value_procedure); + Entity *e = entity_of_node(expr); + if (e != nullptr) { + cgValue found = cg_find_procedure_value_from_entity(m, e); + GB_ASSERT(are_types_identical(type, found.type)); + return found; + } + GB_PANIC("TODO(bill): cg_const_value ExactValue_Procedure"); + } + break; } - if (value.kind == ExactValue_Procedure) { - Ast *expr = unparen_expr(value.value_procedure); - Entity *e = entity_of_node(expr); - if (e != nullptr) { - cgValue found = cg_find_procedure_value_from_entity(m, e); - GB_ASSERT(are_types_identical(type, found.type)); - return found; + GB_ASSERT(!TB_IS_VOID_TYPE(dt)); + + switch (value.kind) { + case ExactValue_Bool: + return cg_value(tb_inst_uint(p->func, dt, value.value_bool), type); + + case ExactValue_Integer: + GB_ASSERT(dt.raw != TB_TYPE_I128.raw); + if (is_type_unsigned(type)) { + u64 i = exact_value_to_u64(value); + return cg_value(tb_inst_uint(p->func, dt, i), type); + } else { + i64 i = exact_value_to_i64(value); + return cg_value(tb_inst_sint(p->func, dt, i), type); } + break; + case ExactValue_Float: + GB_ASSERT(dt.raw != TB_TYPE_F16.raw); + GB_ASSERT(!is_type_different_to_arch_endianness(type)); + { + f64 f = exact_value_to_f64(value); + if (type_size_of(type) == 8) { + return cg_value(tb_inst_float64(p->func, f), type); + } else { + return cg_value(tb_inst_float32(p->func, cast(f32)f), type); + } + } + break; } + GB_ASSERT(node != nullptr); return cg_value(node, type); } @@ -59,4 +118,8 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value) { GB_ASSERT(p != nullptr); return cg_const_value(p->module, p, type, value); -} \ No newline at end of file +} + +gb_internal cgValue cg_const_int(cgProcedure *p, Type *type, i64 i) { + return cg_const_value(p, type, exact_value_i64(i)); +} diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 22da43cbd..fc22e12d9 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -1,3 +1,11 @@ +gb_internal cgValue cg_flatten_value(cgProcedure *p, cgValue value) { + if (value.kind == cgValue_Symbol) { + GB_ASSERT(is_type_internally_pointer_like(value.type)); + value = cg_value(tb_inst_get_symbol_address(p->func, value.symbol), value.type); + } + return value; +} + gb_internal cgContextData *cg_push_context_onto_stack(cgProcedure *p, cgAddr ctx) { ctx.kind = cgAddr_Context; cgContextData *cd = array_add_and_get(&p->context_stack); @@ -43,7 +51,7 @@ gb_internal cgValue cg_find_value_from_entity(cgModule *m, Entity *e) { return *found; } - // GB_PANIC("\n\tError in: %s, missing value '%.*s'\n", token_pos_to_string(e->token.pos), LIT(e->token.string)); + GB_PANIC("\n\tError in: %s, missing value '%.*s'\n", token_pos_to_string(e->token.pos), LIT(e->token.string)); return {}; } @@ -57,6 +65,10 @@ gb_internal cgAddr cg_build_addr_from_entity(cgProcedure *p, Entity *e, Ast *exp return {}; } + cgAddr *local_found = map_get(&p->variable_map, e); + if (local_found) { + return *local_found; + } cgValue v = {}; @@ -78,7 +90,9 @@ gb_internal cgAddr cg_build_addr_from_entity(cgProcedure *p, Entity *e, Ast *exp if (v.node == nullptr) { - return cg_addr(cg_find_value_from_entity(m, e)); + cgValue v = cg_find_value_from_entity(m, e); + v = cg_flatten_value(p, v); + return cg_addr(v); } return cg_addr(v); @@ -90,6 +104,17 @@ gb_internal cgValue cg_typeid(cgModule *m, Type *t) { } +gb_internal cgValue cg_correct_endianness(cgProcedure *p, cgValue value) { + Type *src = core_type(value.type); + GB_ASSERT(is_type_integer(src) || is_type_float(src)); + if (is_type_different_to_arch_endianness(src)) { + GB_PANIC("TODO(bill): cg_correct_endianness"); + // Type *platform_src_type = integer_endian_type_to_platform_type(src); + // value = cg_emit_byte_swap(p, value, platform_src_type); + } + return value; +} + gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *type) { // TODO(bill): cg_emit_conv return value; @@ -98,10 +123,7 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *type) { gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type) { GB_ASSERT(type_size_of(value.type) == type_size_of(type)); - if (value.kind == cgValue_Symbol) { - GB_ASSERT(is_type_pointer(value.type)); - value = cg_value(tb_inst_get_symbol_address(p->func, value.symbol), type); - } + value = cg_flatten_value(p, value); i64 src_align = type_align_of(value.type); i64 dst_align = type_align_of(type); @@ -133,6 +155,217 @@ gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type) } +gb_internal cgAddr cg_build_addr_slice_expr(cgProcedure *p, Ast *expr) { + ast_node(se, SliceExpr, expr); + + cgValue low = cg_const_int(p, t_int, 0); + cgValue high = {}; + + if (se->low != nullptr) { + low = cg_correct_endianness(p, cg_build_expr(p, se->low)); + } + if (se->high != nullptr) { + high = cg_correct_endianness(p, cg_build_expr(p, se->high)); + } + + bool no_indices = se->low == nullptr && se->high == nullptr; + gb_unused(no_indices); + + cgAddr addr = cg_build_addr(p, se->expr); + cgValue base = cg_addr_load(p, addr); + Type *type = base_type(base.type); + + if (is_type_pointer(type)) { + type = base_type(type_deref(type)); + addr = cg_addr(base); + base = cg_addr_load(p, addr); + } + + switch (type->kind) { + case Type_Slice: { + // Type *slice_type = type; + // cgValue len = cg_slice_len(p, base); + // if (high.value == nullptr) high = len; + + // if (!no_indices) { + // cg_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + // } + + // cgValue elem = cg_emit_ptr_offset(p, cg_slice_elem(p, base), low); + // cgValue new_len = cg_emit_arith(p, Token_Sub, high, low, t_int); + + // cgAddr slice = cg_add_local_generated(p, slice_type, false); + // cg_fill_slice(p, slice, elem, new_len); + // return slice; + GB_PANIC("cg_build_addr_slice_expr Type_Slice"); + break; + } + + case Type_RelativeSlice: + GB_PANIC("TODO(bill): Type_RelativeSlice should be handled above already on the cg_addr_load"); + break; + + case Type_DynamicArray: { + // Type *elem_type = type->DynamicArray.elem; + // Type *slice_type = alloc_type_slice(elem_type); + + // lbValue len = lb_dynamic_array_len(p, base); + // if (high.value == nullptr) high = len; + + // if (!no_indices) { + // lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + // } + + // lbValue elem = lb_emit_ptr_offset(p, lb_dynamic_array_elem(p, base), low); + // lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + // lbAddr slice = lb_add_local_generated(p, slice_type, false); + // lb_fill_slice(p, slice, elem, new_len); + // return slice; + GB_PANIC("cg_build_addr_slice_expr Type_DynamicArray"); + break; + } + + case Type_MultiPointer: { + // lbAddr res = lb_add_local_generated(p, type_of_expr(expr), false); + // if (se->high == nullptr) { + // lbValue offset = base; + // LLVMValueRef indices[1] = {low.value}; + // offset.value = LLVMBuildGEP2(p->builder, lb_type(p->module, offset.type->MultiPointer.elem), offset.value, indices, 1, ""); + // lb_addr_store(p, res, offset); + // } else { + // low = lb_emit_conv(p, low, t_int); + // high = lb_emit_conv(p, high, t_int); + + // lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); + + // LLVMValueRef indices[1] = {low.value}; + // LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base.type->MultiPointer.elem), base.value, indices, 1, ""); + // LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, ""); + + // LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value; + // LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value; + // LLVMBuildStore(p->builder, ptr, gep0); + // LLVMBuildStore(p->builder, len, gep1); + // } + // return res; + GB_PANIC("cg_build_addr_slice_expr Type_MultiPointer"); + break; + } + + case Type_Array: { + // Type *slice_type = alloc_type_slice(type->Array.elem); + // lbValue len = lb_const_int(p->module, t_int, type->Array.count); + + // if (high.value == nullptr) high = len; + + // bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant; + // bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant; + + // if (!low_const || !high_const) { + // if (!no_indices) { + // lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + // } + // } + // lbValue elem = lb_emit_ptr_offset(p, lb_array_elem(p, lb_addr_get_ptr(p, addr)), low); + // lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + // lbAddr slice = lb_add_local_generated(p, slice_type, false); + // lb_fill_slice(p, slice, elem, new_len); + // return slice; + GB_PANIC("cg_build_addr_slice_expr Type_Array"); + break; + } + + case Type_Basic: { + // GB_ASSERT(type == t_string); + // lbValue len = lb_string_len(p, base); + // if (high.value == nullptr) high = len; + + // if (!no_indices) { + // lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + // } + + // lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low); + // lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + // lbAddr str = lb_add_local_generated(p, t_string, false); + // lb_fill_string(p, str, elem, new_len); + // return str; + GB_PANIC("cg_build_addr_slice_expr Type_Basic"); + break; + } + + + case Type_Struct: + // if (is_type_soa_struct(type)) { + // lbValue len = lb_soa_struct_len(p, lb_addr_get_ptr(p, addr)); + // if (high.value == nullptr) high = len; + + // if (!no_indices) { + // lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + // } + // #if 1 + + // lbAddr dst = lb_add_local_generated(p, type_of_expr(expr), true); + // if (type->Struct.soa_kind == StructSoa_Fixed) { + // i32 field_count = cast(i32)type->Struct.fields.count; + // for (i32 i = 0; i < field_count; i++) { + // lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + // lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i); + // field_src = lb_emit_array_ep(p, field_src, low); + // lb_emit_store(p, field_dst, field_src); + // } + + // lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + // lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + // lb_emit_store(p, len_dst, new_len); + // } else if (type->Struct.soa_kind == StructSoa_Slice) { + // if (no_indices) { + // lb_addr_store(p, dst, base); + // } else { + // i32 field_count = cast(i32)type->Struct.fields.count - 1; + // for (i32 i = 0; i < field_count; i++) { + // lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + // lbValue field_src = lb_emit_struct_ev(p, base, i); + // field_src = lb_emit_ptr_offset(p, field_src, low); + // lb_emit_store(p, field_dst, field_src); + // } + + + // lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + // lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + // lb_emit_store(p, len_dst, new_len); + // } + // } else if (type->Struct.soa_kind == StructSoa_Dynamic) { + // i32 field_count = cast(i32)type->Struct.fields.count - 3; + // for (i32 i = 0; i < field_count; i++) { + // lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + // lbValue field_src = lb_emit_struct_ev(p, base, i); + // field_src = lb_emit_ptr_offset(p, field_src, low); + // lb_emit_store(p, field_dst, field_src); + // } + + + // lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + // lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + // lb_emit_store(p, len_dst, new_len); + // } + + // return dst; + // #endif + // } + GB_PANIC("cg_build_addr_slice_expr Type_Struct"); + break; + + } + + GB_PANIC("Unknown slicable type"); + return {}; +} + + + gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr); gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr) { @@ -252,6 +485,11 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { return cg_value(cast(TB_Node *)nullptr, e->type); } GB_ASSERT(e->kind != Entity_ProcGroup); + + cgAddr *addr = map_get(&p->variable_map, e); + if (addr) { + return cg_addr_load(p, *addr); + } // return cg_find_ident(p, m, e, expr); GB_PANIC("TODO: cg_find_ident"); return {}; @@ -327,6 +565,17 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { cgValue value = cg_build_expr(p, ac->expr); return cg_emit_conv(p, value, type); case_end; + + case_ast_node(se, SliceExpr, expr); + if (is_type_slice(type_of_expr(se->expr))) { + // NOTE(bill): Quick optimization + if (se->high == nullptr && + (se->low == nullptr || cg_is_expr_constant_zero(se->low))) { + return cg_build_expr(p, se->expr); + } + } + return cg_addr_load(p, cg_build_addr(p, expr)); + case_end; } GB_PANIC("TODO(bill): cg_build_expr_internal %.*s", LIT(ast_strings[expr->kind])); return {}; @@ -384,6 +633,10 @@ gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) { Entity *e = entity_of_node(expr); return cg_build_addr_from_entity(p, e, expr); case_end; + + case_ast_node(se, SliceExpr, expr); + return cg_build_addr_slice_expr(p, expr); + case_end; } TokenPos token_pos = ast_token(expr).pos; diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index b60e797c3..99b70a6a8 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -113,7 +113,7 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty } } - if (param.dt.width != 0) { + if (param.dt.raw != 0) { if (is_blank_ident(e->token)) { param.name = alloc_cstring(temporary_allocator(), e->token.string); } @@ -183,6 +183,7 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i // p->branch_blocks.allocator = a; p->context_stack.allocator = a; p->scope_stack.allocator = a; + map_init(&p->variable_map); // map_init(&p->tuple_fix_map, 0); TB_Linkage linkage = TB_LINKAGE_PRIVATE; @@ -196,8 +197,10 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i } if (p->symbol == nullptr) { + TB_Arena *arena = tb_default_arena(); p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE); - tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena()); + p->proto = cg_procedure_type_as_prototype(m, p->type); + tb_function_set_prototype(p->func, p->proto, arena); p->symbol = cast(TB_Symbol *)p->func; } @@ -235,13 +238,16 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li // p->branch_blocks.allocator = a; p->scope_stack.allocator = a; p->context_stack.allocator = a; + map_init(&p->variable_map); // map_init(&p->tuple_fix_map, 0); TB_Linkage linkage = TB_LINKAGE_PRIVATE; + TB_Arena *arena = tb_default_arena(); p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE); - tb_function_set_prototype(p->func, cg_procedure_type_as_prototype(m, p->type), tb_default_arena()); + p->proto = cg_procedure_type_as_prototype(m, p->type); + tb_function_set_prototype(p->func, p->proto, arena); p->symbol = cast(TB_Symbol *)p->func; cgValue proc_value = cg_value(p->symbol, p->type); @@ -255,6 +261,78 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { if (p == nullptr || p->func == nullptr) { return; } + + if (p->body == nullptr) { + return; + } + + GB_ASSERT(p->type->kind == Type_Proc); + TypeProc *pt = &p->type->Proc; + if (pt->params) { + int param_index = 0; + for (Entity *e : pt->params->Tuple.variables) { + if (e->kind != Entity_Variable) { + continue; + } + + if (param_index >= p->proto->param_count) { + break; + } + + TB_Node *ptr = tb_inst_param_addr(p->func, param_index); + cgValue local = cg_value(ptr, alloc_type_pointer(e->type)); + + if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { + // NOTE(bill): for debugging purposes only + String name = e->token.string; + TB_DebugType *debug_type = cg_debug_type(p->module, e->type); + tb_node_append_attrib(ptr, tb_function_attrib_variable(p->func, name.len, cast(char const *)name.text, debug_type)); + + } + cgAddr addr = cg_addr(local); + if (e) { + map_set(&p->variable_map, e, addr); + } + + // if (arg_type->kind == lbArg_Ignore) { + // continue; + // } else if (arg_type->kind == lbArg_Direct) { + // if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { + // LLVMTypeRef param_type = lb_type(p->module, e->type); + // LLVMValueRef original_value = LLVMGetParam(p->value, param_offset+param_index); + // LLVMValueRef value = OdinLLVMBuildTransmute(p, original_value, param_type); + + // lbValue param = {}; + // param.value = value; + // param.type = e->type; + + // map_set(&p->direct_parameters, e, param); + + // lbValue ptr = lb_address_from_load_or_generate_local(p, param); + // GB_ASSERT(LLVMIsAAllocaInst(ptr.value)); + // lb_add_entity(p->module, e, ptr); + + // lbBlock *block = p->decl_block; + // if (original_value != value) { + // block = p->curr_block; + // } + // LLVMValueRef debug_storage_value = value; + // if (original_value != value && LLVMIsALoadInst(value)) { + // debug_storage_value = LLVMGetOperand(value, 0); + // } + // lb_add_debug_param_variable(p, debug_storage_value, e->type, e->token, param_index+1, block, arg_type->kind); + // } + // } else if (arg_type->kind == lbArg_Indirect) { + // if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { + // lbValue ptr = {}; + // ptr.value = LLVMGetParam(p->value, param_offset+param_index); + // ptr.type = alloc_type_pointer(e->type); + // lb_add_entity(p->module, e, ptr); + // lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block, arg_type->kind); + // } + // } + } + } } gb_internal void cg_procedure_end(cgProcedure *p) { diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 7c3dfcef8..2952539ca 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -131,6 +131,9 @@ gb_internal cgValue cg_address_from_load(cgProcedure *p, cgValue value) { GB_PANIC("Symbol is an invalid use case for cg_address_from_load"); return {}; } + GB_PANIC("Invalid cgValue for cg_address_from_load"); + return {}; + } gb_internal bool cg_addr_is_empty(cgAddr const &addr) { @@ -174,7 +177,14 @@ gb_internal Type *cg_addr_type(cgAddr const &addr) { } gb_internal cgValue cg_addr_load(cgProcedure *p, cgAddr addr) { - GB_PANIC("TODO(bill): cg_addr_load"); + if (addr.addr.node == nullptr) { + return {}; + } + switch (addr.kind) { + case cgAddr_Default: + return cg_emit_load(p, addr.addr); + } + GB_PANIC("TODO(bill): cg_addr_load %p", addr.addr.node); return {}; } @@ -285,19 +295,23 @@ gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { // NOTE(bill): for debugging purposes only - // String name = e->token.string; - // TB_DebugType *debug_type = cg_debug_type(p->module, type); - // tb_function_attrib_variable(p->func, name.len, cast(char const *)name.text, debug_type); + String name = e->token.string; + TB_DebugType *debug_type = cg_debug_type(p->module, type); + tb_node_append_attrib(local, tb_function_attrib_variable(p->func, name.len, cast(char const *)name.text, debug_type)); } if (zero_init) { bool is_volatile = false; - TB_Node *zero = tb_inst_uint(p->func, TB_TYPE_I8, 0); + TB_Node *zero = tb_inst_uint(p->func, TB_TYPE_I8, 0); TB_Node *count = tb_inst_uint(p->func, TB_TYPE_I32, cast(u64)size); tb_inst_memset(p->func, local, zero, count, alignment, is_volatile); } - return cg_addr(cg_value(local, alloc_type_pointer(type))); + cgAddr addr = cg_addr(cg_value(local, alloc_type_pointer(type))); + if (e) { + map_set(&p->variable_map, e, addr); + } + return addr; } @@ -313,10 +327,59 @@ gb_internal void cg_emit_defer_stmts(cgProcedure *p, cgDeferExitKind kind, TB_No // TODO(bill): cg_emit_defer_stmts } + +gb_internal isize cg_append_tuple_values(cgProcedure *p, Array *dst_values, cgValue src_value) { + isize init_count = dst_values->count; + Type *t = src_value.type; + if (t && t->kind == Type_Tuple) { + GB_PANIC("TODO(bill): tuple assignments"); + // cgTupleFix *tf = map_get(&p->tuple_fix_map, src_value.value); + // if (tf) { + // for (cgValue const &value : tf->values) { + // array_add(dst_values, value); + // } + // } else { + // for_array(i, t->Tuple.variables) { + // cgValue v = cg_emit_tuple_ev(p, src_value, cast(i32)i); + // array_add(dst_values, v); + // } + // } + } else { + array_add(dst_values, src_value); + } + return dst_values->count - init_count; +} gb_internal void cg_build_assignment(cgProcedure *p, Array const &lvals, Slice const &values) { if (values.count == 0) { return; } + + auto inits = array_make(permanent_allocator(), 0, lvals.count); + + for (Ast *rhs : values) { + cgValue init = cg_build_expr(p, rhs); + cg_append_tuple_values(p, &inits, init); + } + + bool prev_in_assignment = p->in_multi_assignment; + + isize lval_count = 0; + for (cgAddr const &lval : lvals) { + if (!cg_addr_is_empty(lval)) { + // check if it is not a blank identifier + lval_count += 1; + } + } + p->in_multi_assignment = lval_count > 1; + + GB_ASSERT(lvals.count == inits.count); + for_array(i, inits) { + cgAddr lval = lvals[i]; + cgValue init = inits[i]; + cg_addr_store(p, lval, init); + } + + p->in_multi_assignment = prev_in_assignment; } gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) { -- cgit v1.2.3 From d2d243cca8954e686a82f15a37a149c7938362d2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 16 Jul 2023 23:41:51 +0100 Subject: Mock out `cg_emit_conv` --- src/tilde_backend.hpp | 4 +- src/tilde_expr.cpp | 444 ++++++++++++++++++++++++++++++++++++++++++++++---- src/tilde_proc.cpp | 149 ++++++++++++++++- src/tilde_stmt.cpp | 4 + src/types.cpp | 1 + 5 files changed, 562 insertions(+), 40 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 228afb6af..ec051b105 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -9,8 +9,8 @@ #define TB_TYPE_F16 TB_DataType{ { TB_INT, 0, 16 } } #define TB_TYPE_I128 TB_DataType{ { TB_INT, 0, 128 } } -#define TB_TYPE_INT TB_TYPE_INTN(cast(u16)build_context.int_size) -#define TB_TYPE_INTPTR TB_TYPE_INTN(cast(u16)build_context.ptr_size) +#define TB_TYPE_INT TB_TYPE_INTN(cast(u16)(8*build_context.int_size)) +#define TB_TYPE_INTPTR TB_TYPE_INTN(cast(u16)(8*build_context.ptr_size)) #if defined(GB_SYSTEM_WINDOWS) #pragma warning(pop) diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index fc22e12d9..39fcdd591 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -115,16 +115,19 @@ gb_internal cgValue cg_correct_endianness(cgProcedure *p, cgValue value) { return value; } -gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *type) { - // TODO(bill): cg_emit_conv - return value; -} - gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type) { GB_ASSERT(type_size_of(value.type) == type_size_of(type)); value = cg_flatten_value(p, value); + if (are_types_identical(value.type, type)) { + return value; + } + if (are_types_identical(core_type(value.type), core_type(type))) { + value.type = type; + return value; + } + i64 src_align = type_align_of(value.type); i64 dst_align = type_align_of(type); @@ -153,6 +156,380 @@ gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type) return value; } +gb_internal cgValue cg_emit_byte_swap(cgProcedure *p, cgValue value, Type *end_type) { + GB_ASSERT(type_size_of(value.type) == type_size_of(end_type)); + + if (type_size_of(value.type) < 2) { + return value; + } + + if (is_type_float(value.type)) { + i64 sz = type_size_of(value.type); + Type *integer_type = nullptr; + switch (sz) { + case 2: integer_type = t_u16; break; + case 4: integer_type = t_u32; break; + case 8: integer_type = t_u64; break; + } + GB_ASSERT(integer_type != nullptr); + value = cg_emit_transmute(p, value, integer_type); + } + + GB_ASSERT(value.kind == cgValue_Value); + + value.node = tb_inst_bswap(p->func, value.node); + return cg_emit_transmute(p, value, end_type); +} + +gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { + t = reduce_tuple_to_single_type(t); + + value = cg_flatten_value(p, value); + + Type *src_type = value.type; + if (are_types_identical(t, src_type)) { + return value; + } + + Type *src = core_type(src_type); + Type *dst = core_type(t); + GB_ASSERT(src != nullptr); + GB_ASSERT(dst != nullptr); + + if (are_types_identical(src, dst)) { + return cg_emit_transmute(p, value, t); + } + + TB_DataType st = cg_data_type(src); + TB_DataType dt = cg_data_type(t); + + if (is_type_integer(src) && is_type_integer(dst)) { + GB_ASSERT(src->kind == Type_Basic && + dst->kind == Type_Basic); + GB_ASSERT(value.kind == cgValue_Value); + + i64 sz = type_size_of(default_type(src)); + i64 dz = type_size_of(default_type(dst)); + + if (sz == dz) { + if (dz > 1 && !types_have_same_internal_endian(src, dst)) { + return cg_emit_byte_swap(p, value, t); + } + value.type = t; + return value; + } + + if (sz > 1 && is_type_different_to_arch_endianness(src)) { + Type *platform_src_type = integer_endian_type_to_platform_type(src); + value = cg_emit_byte_swap(p, value, platform_src_type); + } + + TB_Node* (*op)(TB_Function* f, TB_Node* src, TB_DataType dt) = tb_inst_trunc; + + if (dz < sz) { + op = tb_inst_trunc; + } else if (dz == sz) { + op = tb_inst_bitcast; + } else if (dz > sz) { + op = is_type_unsigned(src) ? tb_inst_zxt : tb_inst_sxt; // zero extent + } + + if (dz > 1 && is_type_different_to_arch_endianness(dst)) { + Type *platform_dst_type = integer_endian_type_to_platform_type(dst); + + cgValue res = cg_value(op(p->func, value.node, cg_data_type(platform_dst_type)), platform_dst_type); + return cg_emit_byte_swap(p, res, t); + } else { + return cg_value(op(p->func, value.node, dt), t); + } + } + + // boolean -> boolean/integer + if (is_type_boolean(src) && (is_type_boolean(dst) || is_type_integer(dst))) { + TB_Node *v = tb_inst_cmp_ne(p->func, value.node, tb_inst_uint(p->func, st, 0)); + return cg_value(tb_inst_zxt(p->func, v, dt), t); + } + + // integer -> boolean + if (is_type_integer(src) && is_type_boolean(dst)) { + TB_Node *v = tb_inst_cmp_ne(p->func, value.node, tb_inst_uint(p->func, st, 0)); + return cg_value(tb_inst_zxt(p->func, v, dt), t); + } + + if (is_type_cstring(src) && is_type_u8_ptr(dst)) { + return cg_emit_transmute(p, value, dst); + } + if (is_type_u8_ptr(src) && is_type_cstring(dst)) { + return cg_emit_transmute(p, value, dst); + } + if (is_type_cstring(src) && is_type_u8_multi_ptr(dst)) { + return cg_emit_transmute(p, value, dst); + } + if (is_type_u8_multi_ptr(src) && is_type_cstring(dst)) { + return cg_emit_transmute(p, value, dst); + } + if (is_type_cstring(src) && is_type_rawptr(dst)) { + return cg_emit_transmute(p, value, dst); + } + if (is_type_rawptr(src) && is_type_cstring(dst)) { + return cg_emit_transmute(p, value, dst); + } + + + if (are_types_identical(src, t_cstring) && are_types_identical(dst, t_string)) { + GB_PANIC("TODO(bill): cstring_to_string call"); + // TEMPORARY_ALLOCATOR_GUARD(); + // lbValue c = lb_emit_conv(p, value, t_cstring); + // auto args = array_make(temporary_allocator(), 1); + // args[0] = c; + // lbValue s = lb_emit_runtime_call(p, "cstring_to_string", args); + // return lb_emit_conv(p, s, dst); + } + + // float -> float + if (is_type_float(src) && is_type_float(dst)) { + i64 sz = type_size_of(src); + i64 dz = type_size_of(dst); + + if (sz == 2 || dz == 2) { + GB_PANIC("TODO(bill): f16 conversions"); + } + + + if (dz == sz) { + if (types_have_same_internal_endian(src, dst)) { + return cg_value(value.node, t); + } else { + return cg_emit_byte_swap(p, value, t); + } + } + + if (is_type_different_to_arch_endianness(src) || is_type_different_to_arch_endianness(dst)) { + Type *platform_src_type = integer_endian_type_to_platform_type(src); + Type *platform_dst_type = integer_endian_type_to_platform_type(dst); + cgValue res = {}; + res = cg_emit_conv(p, value, platform_src_type); + res = cg_emit_conv(p, res, platform_dst_type); + if (is_type_different_to_arch_endianness(dst)) { + res = cg_emit_byte_swap(p, res, t); + } + return cg_emit_conv(p, res, t); + } + + + if (dz >= sz) { + return cg_value(tb_inst_fpxt(p->func, value.node, dt), t); + } + return cg_value(tb_inst_trunc(p->func, value.node, dt), t); + } + + if (is_type_complex(src) && is_type_complex(dst)) { + GB_PANIC("TODO(bill): complex -> complex"); + } + + if (is_type_quaternion(src) && is_type_quaternion(dst)) { + // @QuaternionLayout + GB_PANIC("TODO(bill): quaternion -> quaternion"); + } + if (is_type_integer(src) && is_type_complex(dst)) { + GB_PANIC("TODO(bill): int -> complex"); + } + if (is_type_float(src) && is_type_complex(dst)) { + GB_PANIC("TODO(bill): float -> complex"); + } + if (is_type_integer(src) && is_type_quaternion(dst)) { + GB_PANIC("TODO(bill): int -> quaternion"); + } + if (is_type_float(src) && is_type_quaternion(dst)) { + GB_PANIC("TODO(bill): float -> quaternion"); + } + if (is_type_complex(src) && is_type_quaternion(dst)) { + GB_PANIC("TODO(bill): complex -> quaternion"); + } + + + // float <-> integer + if (is_type_float(src) && is_type_integer(dst)) { + if (is_type_different_to_arch_endianness(src) || is_type_different_to_arch_endianness(dst)) { + Type *platform_src_type = integer_endian_type_to_platform_type(src); + Type *platform_dst_type = integer_endian_type_to_platform_type(dst); + cgValue res = {}; + res = cg_emit_conv(p, value, platform_src_type); + res = cg_emit_conv(p, res, platform_dst_type); + return cg_emit_conv(p, res, t); + } + + // if (is_type_integer_128bit(dst)) { + // TEMPORARY_ALLOCATOR_GUARD(); + + // auto args = array_make(temporary_allocator(), 1); + // args[0] = value; + // char const *call = "fixunsdfdi"; + // if (is_type_unsigned(dst)) { + // call = "fixunsdfti"; + // } + // lbValue res_i128 = lb_emit_runtime_call(p, call, args); + // return lb_emit_conv(p, res_i128, t); + // } + + bool is_signed = !is_type_unsigned(dst); + return cg_value(tb_inst_float2int(p->func, value.node, dt, is_signed), t); + } + if (is_type_integer(src) && is_type_float(dst)) { + if (is_type_different_to_arch_endianness(src) || is_type_different_to_arch_endianness(dst)) { + Type *platform_src_type = integer_endian_type_to_platform_type(src); + Type *platform_dst_type = integer_endian_type_to_platform_type(dst); + cgValue res = {}; + res = cg_emit_conv(p, value, platform_src_type); + res = cg_emit_conv(p, res, platform_dst_type); + if (is_type_different_to_arch_endianness(dst)) { + res = cg_emit_byte_swap(p, res, t); + } + return cg_emit_conv(p, res, t); + } + + // if (is_type_integer_128bit(src)) { + // TEMPORARY_ALLOCATOR_GUARD(); + + // auto args = array_make(temporary_allocator(), 1); + // args[0] = value; + // char const *call = "floattidf"; + // if (is_type_unsigned(src)) { + // call = "floattidf_unsigned"; + // } + // lbValue res_f64 = lb_emit_runtime_call(p, call, args); + // return lb_emit_conv(p, res_f64, t); + // } + + bool is_signed = !is_type_unsigned(dst); + return cg_value(tb_inst_int2float(p->func, value.node, dt, is_signed), t); + } + + if (is_type_simd_vector(dst)) { + GB_PANIC("TODO(bill): ? -> #simd vector"); + } + + + // Pointer <-> uintptr + if (is_type_pointer(src) && is_type_uintptr(dst)) { + return cg_value(tb_inst_ptr2int(p->func, value.node, dt), t); + } + if (is_type_uintptr(src) && is_type_pointer(dst)) { + return cg_value(tb_inst_int2ptr(p->func, value.node), t); + } + if (is_type_multi_pointer(src) && is_type_uintptr(dst)) { + return cg_value(tb_inst_ptr2int(p->func, value.node, dt), t); + } + if (is_type_uintptr(src) && is_type_multi_pointer(dst)) { + return cg_value(tb_inst_int2ptr(p->func, value.node), t); + } + + if (is_type_union(dst)) { + GB_PANIC("TODO(bill): ? -> union"); + } + + // NOTE(bill): This has to be done before 'Pointer <-> Pointer' as it's + // subtype polymorphism casting + if (check_is_assignable_to_using_subtype(src_type, t)) { + GB_PANIC("TODO(bill): ? -> subtyping"); + } + + // Pointer <-> Pointer + if (is_type_pointer(src) && is_type_pointer(dst)) { + return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + } + if (is_type_multi_pointer(src) && is_type_pointer(dst)) { + return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + } + if (is_type_pointer(src) && is_type_multi_pointer(dst)) { + return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + } + if (is_type_multi_pointer(src) && is_type_multi_pointer(dst)) { + return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + } + + // proc <-> proc + if (is_type_proc(src) && is_type_proc(dst)) { + return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + } + + // pointer -> proc + if (is_type_pointer(src) && is_type_proc(dst)) { + return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + } + // proc -> pointer + if (is_type_proc(src) && is_type_pointer(dst)) { + return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + } + + // []byte/[]u8 <-> string + if (is_type_u8_slice(src) && is_type_string(dst)) { + return cg_emit_transmute(p, value, t); + } + if (is_type_string(src) && is_type_u8_slice(dst)) { + return cg_emit_transmute(p, value, t); + } + + if (is_type_matrix(dst) && !is_type_matrix(src)) { + GB_PANIC("TODO(bill): !matrix -> matrix"); + } + + if (is_type_matrix(dst) && is_type_matrix(src)) { + GB_PANIC("TODO(bill): matrix -> matrix"); + } + + if (is_type_any(dst)) { + GB_PANIC("TODO(bill): ? -> any"); + } + + i64 src_sz = type_size_of(src); + i64 dst_sz = type_size_of(dst); + + if (src_sz == dst_sz) { + // bit_set <-> integer + if (is_type_integer(src) && is_type_bit_set(dst)) { + cgValue v = cg_emit_conv(p, value, bit_set_to_int(dst)); + return cg_emit_transmute(p, v, t); + } + if (is_type_bit_set(src) && is_type_integer(dst)) { + cgValue bs = cg_emit_transmute(p, value, bit_set_to_int(src)); + return cg_emit_conv(p, bs, dst); + } + + // typeid <-> integer + if (is_type_integer(src) && is_type_typeid(dst)) { + return cg_emit_transmute(p, value, dst); + } + if (is_type_typeid(src) && is_type_integer(dst)) { + return cg_emit_transmute(p, value, dst); + } + } + + + if (is_type_untyped(src)) { + if (is_type_string(src) && is_type_string(dst)) { + cgAddr result = cg_add_local(p, t, nullptr, false); + cg_addr_store(p, result, value); + return cg_addr_load(p, result); + } + } + + + gb_printf_err("%.*s\n", LIT(p->name)); + gb_printf_err("cg_emit_conv: src -> dst\n"); + gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t)); + gb_printf_err("Not Identical %s != %s\n", type_to_string(src), type_to_string(dst)); + gb_printf_err("Not Identical %p != %p\n", src_type, t); + gb_printf_err("Not Identical %p != %p\n", src, dst); + + + GB_PANIC("Invalid type conversion: '%s' to '%s' for procedure '%.*s'", + type_to_string(src_type), type_to_string(t), + LIT(p->name)); + + return {}; +} + gb_internal cgAddr cg_build_addr_slice_expr(cgProcedure *p, Ast *expr) { @@ -227,30 +604,39 @@ gb_internal cgAddr cg_build_addr_slice_expr(cgProcedure *p, Ast *expr) { } case Type_MultiPointer: { - // lbAddr res = lb_add_local_generated(p, type_of_expr(expr), false); - // if (se->high == nullptr) { - // lbValue offset = base; - // LLVMValueRef indices[1] = {low.value}; - // offset.value = LLVMBuildGEP2(p->builder, lb_type(p->module, offset.type->MultiPointer.elem), offset.value, indices, 1, ""); - // lb_addr_store(p, res, offset); - // } else { - // low = lb_emit_conv(p, low, t_int); - // high = lb_emit_conv(p, high, t_int); - - // lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); - - // LLVMValueRef indices[1] = {low.value}; - // LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base.type->MultiPointer.elem), base.value, indices, 1, ""); - // LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, ""); - - // LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value; - // LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value; - // LLVMBuildStore(p->builder, ptr, gep0); - // LLVMBuildStore(p->builder, len, gep1); - // } - // return res; - GB_PANIC("cg_build_addr_slice_expr Type_MultiPointer"); - break; + Type *res_type = type_of_expr(expr); + if (se->high == nullptr) { + cgAddr res = cg_add_local(p, res_type, nullptr, false); + GB_ASSERT(base.kind == cgValue_Value); + GB_ASSERT(low.kind == cgValue_Value); + + i64 stride = type_size_of(type->MultiPointer.elem); + cgValue offset = cg_value(tb_inst_array_access(p->func, base.node, low.node, stride), base.type); + cg_addr_store(p, res, offset); + return res; + } else { + cgAddr res = cg_add_local(p, res_type, nullptr, true); + low = cg_emit_conv(p, low, t_int); + high = cg_emit_conv(p, high, t_int); + + // cg_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); + + i64 stride = type_size_of(type->MultiPointer.elem); + TB_Node *offset = tb_inst_array_access(p->func, base.node, low.node, stride); + TB_Node *len = tb_inst_sub(p->func, high.node, low.node, cast(TB_ArithmeticBehavior)0); + + TB_Node *data_ptr = tb_inst_member_access(p->func, res.addr.node, type_offset_of(res_type, 0)); + TB_Node *len_ptr = tb_inst_member_access(p->func, res.addr.node, type_offset_of(res_type, 1)); + + tb_inst_store(p->func, TB_TYPE_PTR, data_ptr, offset, cast(TB_CharUnits)build_context.ptr_size, false); + tb_inst_store(p->func, TB_TYPE_INT, len_ptr, len, cast(TB_CharUnits)build_context.int_size, false); + + // LLVMValueRef gep0 = cg_emit_struct_ep(p, res.addr, 0).value; + // LLVMValueRef gep1 = cg_emit_struct_ep(p, res.addr, 1).value; + // LLVMBuildStore(p->builder, ptr, gep0); + // LLVMBuildStore(p->builder, len, gep1); + return res; + } } case Type_Array: { diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 99b70a6a8..d763e2f8c 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -1,4 +1,7 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Type *type) { + // TODO(bill): cache the procedure type generation + GB_ASSERT(build_context.metrics.os == TargetOs_windows); + GB_ASSERT(type != nullptr); type = base_type(type); GB_ASSERT(type->kind == Type_Proc); @@ -35,7 +38,7 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); break; - case Basic_f16: param.dt = TB_TYPE_I16; break; + case Basic_f16: param.dt = TB_TYPE_F16; break; case Basic_f32: param.dt = TB_TYPE_F32; break; case Basic_f64: param.dt = TB_TYPE_F64; break; @@ -86,11 +89,11 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); break; - case Basic_f16le: param.dt = TB_TYPE_I16; break; + case Basic_f16le: param.dt = TB_TYPE_F16; break; case Basic_f32le: param.dt = TB_TYPE_F32; break; case Basic_f64le: param.dt = TB_TYPE_F64; break; - case Basic_f16be: param.dt = TB_TYPE_I16; break; + case Basic_f16be: param.dt = TB_TYPE_F16; break; case Basic_f32be: param.dt = TB_TYPE_F32; break; case Basic_f64be: param.dt = TB_TYPE_F64; break; } @@ -117,15 +120,139 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty if (is_blank_ident(e->token)) { param.name = alloc_cstring(temporary_allocator(), e->token.string); } + param.debug_type = cg_debug_type(m, e->type); array_add(¶ms, param); } } - auto results = array_make(heap_allocator(), 0, pt->result_count); - // if (pt->results) for (Entity *e : pt->params->Tuple.variables) { - // // TODO(bill): - // } + auto results = array_make(heap_allocator(), 0, 1); + + Type *result_type = reduce_tuple_to_single_type(pt->results); + + if (result_type) { + bool return_is_tuple = result_type->kind == Type_Tuple && is_calling_convention_odin(pt->calling_convention); + if (return_is_tuple) { + for (isize i = 0; i < result_type->Tuple.variables.count-1; i++) { + Entity *e = result_type->Tuple.variables[i]; + TB_PrototypeParam param = {}; + param.dt = TB_TYPE_PTR; + param.debug_type = cg_debug_type(m, alloc_type_pointer(e->type)); + array_add(¶ms, param); + } + + result_type = result_type->Tuple.variables[result_type->Tuple.variables.count-1]->type; + } + + Type *rt = core_type(result_type); + i64 sz = type_size_of(rt); + + TB_PrototypeParam result = {}; + + switch (rt->kind) { + case Type_Basic: + switch (rt->Basic.kind) { + case Basic_bool: + case Basic_b8: + case Basic_b16: + case Basic_b32: + case Basic_b64: + case Basic_i8: + case Basic_u8: + case Basic_i16: + case Basic_u16: + case Basic_i32: + case Basic_u32: + case Basic_i64: + case Basic_u64: + case Basic_i128: + case Basic_u128: + case Basic_rune: + case Basic_int: + case Basic_uint: + case Basic_uintptr: + result.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + break; + + case Basic_f16: result.dt = TB_TYPE_I16; break; + case Basic_f32: result.dt = TB_TYPE_F32; break; + case Basic_f64: result.dt = TB_TYPE_F64; break; + + case Basic_rawptr: + result.dt = TB_TYPE_PTR; + break; + case Basic_cstring: // ^u8 + result.dt = TB_TYPE_PTR; + break; + + case Basic_typeid: + result.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + break; + + // Endian Specific Types + case Basic_i16le: + case Basic_u16le: + case Basic_i32le: + case Basic_u32le: + case Basic_i64le: + case Basic_u64le: + case Basic_i128le: + case Basic_u128le: + case Basic_i16be: + case Basic_u16be: + case Basic_i32be: + case Basic_u32be: + case Basic_i64be: + case Basic_u64be: + case Basic_i128be: + case Basic_u128be: + result.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + break; + + case Basic_f16le: result.dt = TB_TYPE_I16; break; + case Basic_f32le: result.dt = TB_TYPE_F32; break; + case Basic_f64le: result.dt = TB_TYPE_F64; break; + + case Basic_f16be: result.dt = TB_TYPE_I16; break; + case Basic_f32be: result.dt = TB_TYPE_F32; break; + case Basic_f64be: result.dt = TB_TYPE_F64; break; + } + + case Type_Pointer: + case Type_MultiPointer: + case Type_Proc: + result.dt = TB_TYPE_PTR; + break; + + default: + switch (sz) { + case 1: result.dt = TB_TYPE_I8; break; + case 2: result.dt = TB_TYPE_I16; break; + case 4: result.dt = TB_TYPE_I32; break; + case 8: result.dt = TB_TYPE_I64; break; + } + } + + if (result.dt.raw != 0) { + result.debug_type = cg_debug_type(m, result_type); + array_add(&results, result); + } else { + result.debug_type = cg_debug_type(m, alloc_type_pointer(result_type)); + result.dt = TB_TYPE_PTR; + + array_resize(¶ms, params.count+1); + array_copy(¶ms, params, 1); + params[0] = result; + } + } + + if (pt->calling_convention == ProcCC_Odin) { + TB_PrototypeParam param = {}; + param.dt = TB_TYPE_PTR; + param.debug_type = cg_debug_type(m, t_context_ptr); + param.name = "__.context_ptr"; + array_add(¶ms, param); + } return tb_prototype_create(m->mod, TB_CDECL, params.count, params.data, results.count, results.data, pt->c_vararg); } @@ -408,12 +535,16 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice } GB_ASSERT(value.kind == cgValue_Value); + // TODO(bill): abstract out the function prototype stuff so that you handle the ABI correctly (at least for win64 at the moment) TB_FunctionPrototype *proto = cg_procedure_type_as_prototype(p->module, value.type); TB_Node *target = value.node; - auto params = slice_make(temporary_allocator(), 0); + auto params = slice_make(temporary_allocator(), 0 /*proto->param_count*/); + for_array(i, params) { + // params[i] = proto + } GB_ASSERT(target != nullptr); - TB_MultiOutput multi_output = tb_inst_call(p->func, proto, target, 0, nullptr); + TB_MultiOutput multi_output = tb_inst_call(p->func, proto, target, params.count, params.data); gb_unused(multi_output); return {}; } diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 2952539ca..2f2bdd55f 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -376,6 +376,10 @@ gb_internal void cg_build_assignment(cgProcedure *p, Array const &lvals, for_array(i, inits) { cgAddr lval = lvals[i]; cgValue init = inits[i]; + if (init.type == nullptr) { + // TODO(bill): figure out how to do this + continue; + } cg_addr_store(p, lval, init); } diff --git a/src/types.cpp b/src/types.cpp index 385ca926d..98be2b6cf 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3952,6 +3952,7 @@ gb_internal i64 type_offset_of(Type *t, i32 index) { case -1: return align_formula(t->Union.variant_block_size, build_context.ptr_size); // __type_info } } + GB_ASSERT(index == 0); return 0; } -- cgit v1.2.3 From 66a20264ab8f0abfddcda6a2c48a447119f22f33 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jul 2023 00:06:03 +0100 Subject: Mock out `cg_emit_arith` --- src/tilde_backend.hpp | 3 +- src/tilde_expr.cpp | 293 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/tilde_stmt.cpp | 55 ++++++++++ 3 files changed, 350 insertions(+), 1 deletion(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index ec051b105..6449bf49f 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -221,6 +221,7 @@ gb_internal cgAddr cg_build_addr(cgProcedure *p, Ast *expr); gb_internal Type * cg_addr_type(cgAddr const &addr); gb_internal cgValue cg_addr_load(cgProcedure *p, cgAddr addr); gb_internal void cg_addr_store(cgProcedure *p, cgAddr addr, cgValue value); +gb_internal cgValue cg_addr_get_ptr(cgProcedure *p, cgAddr const &addr); gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile=false); gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile=false); @@ -235,4 +236,4 @@ gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type); gb_internal String cg_get_entity_name(cgModule *m, Entity *e); -gb_internal cgValue cg_typeid(cgModule *m, Type *t); \ No newline at end of file +gb_internal cgValue cg_typeid(cgModule *m, Type *t); diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 39fcdd591..26c52f1bb 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -191,6 +191,14 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { return value; } + if (is_type_untyped_uninit(src_type)) { + // return cg_const_undef(m, t); + return cg_const_nil(p, t); + } + if (is_type_untyped_nil(src_type)) { + return cg_const_nil(p, t); + } + Type *src = core_type(src_type); Type *dst = core_type(t); GB_ASSERT(src != nullptr); @@ -530,6 +538,158 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { return {}; } +gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgValue rhs, Type *type) { + if (is_type_array_like(lhs.type) || is_type_array_like(rhs.type)) { + GB_PANIC("TODO(bill): cg_emit_arith_array"); + } else if (is_type_matrix(lhs.type) || is_type_matrix(rhs.type)) { + GB_PANIC("TODO(bill): cg_emit_arith_matrix"); + } else if (is_type_complex(type)) { + GB_PANIC("TODO(bill): cg_emit_arith complex"); + } else if (is_type_quaternion(type)) { + GB_PANIC("TODO(bill): cg_emit_arith quaternion"); + } + + lhs = cg_flatten_value(p, cg_emit_conv(p, lhs, type)); + rhs = cg_flatten_value(p, cg_emit_conv(p, rhs, type)); + GB_ASSERT(lhs.kind == cgValue_Value); + GB_ASSERT(rhs.kind == cgValue_Value); + + if (is_type_integer(type) && is_type_different_to_arch_endianness(type)) { + switch (op) { + case Token_AndNot: + case Token_And: + case Token_Or: + case Token_Xor: + goto handle_op; + } + + Type *platform_type = integer_endian_type_to_platform_type(type); + cgValue x = cg_emit_byte_swap(p, lhs, integer_endian_type_to_platform_type(lhs.type)); + cgValue y = cg_emit_byte_swap(p, rhs, integer_endian_type_to_platform_type(rhs.type)); + + cgValue res = cg_emit_arith(p, op, x, y, platform_type); + + return cg_emit_byte_swap(p, res, type); + } + + if (is_type_float(type) && is_type_different_to_arch_endianness(type)) { + Type *platform_type = integer_endian_type_to_platform_type(type); + cgValue x = cg_emit_conv(p, lhs, integer_endian_type_to_platform_type(lhs.type)); + cgValue y = cg_emit_conv(p, rhs, integer_endian_type_to_platform_type(rhs.type)); + + cgValue res = cg_emit_arith(p, op, x, y, platform_type); + + return cg_emit_byte_swap(p, res, type); + } + +handle_op:; + + // NOTE(bill): Bit Set Aliases for + and - + if (is_type_bit_set(type)) { + switch (op) { + case Token_Add: op = Token_Or; break; + case Token_Sub: op = Token_AndNot; break; + } + } + + TB_ArithmeticBehavior arith_behavior = cast(TB_ArithmeticBehavior)50; + + Type *integral_type = type; + if (is_type_simd_vector(integral_type)) { + GB_PANIC("TODO(bill): cg_emit_arith #simd vector"); + // integral_type = core_array_type(integral_type); + } + + switch (op) { + case Token_Add: + if (is_type_float(integral_type)) { + return cg_value(tb_inst_fadd(p->func, lhs.node, rhs.node), type); + } + return cg_value(tb_inst_add(p->func, lhs.node, rhs.node, arith_behavior), type); + case Token_Sub: + if (is_type_float(integral_type)) { + return cg_value(tb_inst_fsub(p->func, lhs.node, rhs.node), type); + } + return cg_value(tb_inst_sub(p->func, lhs.node, rhs.node, arith_behavior), type); + case Token_Mul: + if (is_type_float(integral_type)) { + return cg_value(tb_inst_fmul(p->func, lhs.node, rhs.node), type); + } + return cg_value(tb_inst_mul(p->func, lhs.node, rhs.node, arith_behavior), type); + case Token_Quo: + if (is_type_float(integral_type)) { + return cg_value(tb_inst_fdiv(p->func, lhs.node, rhs.node), type); + } + return cg_value(tb_inst_div(p->func, lhs.node, rhs.node, !is_type_unsigned(integral_type)), type); + case Token_Mod: + if (is_type_float(integral_type)) { + GB_PANIC("TODO(bill): float %% float"); + } + return cg_value(tb_inst_mod(p->func, lhs.node, rhs.node, !is_type_unsigned(integral_type)), type); + case Token_ModMod: + if (is_type_unsigned(integral_type)) { + return cg_value(tb_inst_mod(p->func, lhs.node, rhs.node, false), type); + } else { + TB_Node *a = tb_inst_mod(p->func, lhs.node, rhs.node, true); + TB_Node *b = tb_inst_add(p->func, a, rhs.node, arith_behavior); + TB_Node *c = tb_inst_mod(p->func, b, rhs.node, true); + return cg_value(c, type); + } + + case Token_And: + return cg_value(tb_inst_and(p->func, lhs.node, rhs.node), type); + case Token_Or: + return cg_value(tb_inst_or(p->func, lhs.node, rhs.node), type); + case Token_Xor: + return cg_value(tb_inst_xor(p->func, lhs.node, rhs.node), type); + case Token_Shl: + { + rhs = cg_emit_conv(p, rhs, lhs.type); + TB_DataType dt = cg_data_type(lhs.type); + TB_Node *lhsval = lhs.node; + TB_Node *bits = rhs.node; + + TB_Node *bit_size = tb_inst_uint(p->func, dt, 8*type_size_of(lhs.type)); + TB_Node *zero = tb_inst_uint(p->func, dt, 0); + + TB_Node *width_test = tb_inst_cmp_ilt(p->func, bits, bit_size, false); + + TB_Node *res = tb_inst_shl(p->func, lhsval, bits, arith_behavior); + res = tb_inst_select(p->func, width_test, res, zero); + return cg_value(res, type); + } + case Token_Shr: + { + rhs = cg_emit_conv(p, rhs, lhs.type); + TB_DataType dt = cg_data_type(lhs.type); + TB_Node *lhsval = lhs.node; + TB_Node *bits = rhs.node; + + TB_Node *bit_size = tb_inst_uint(p->func, dt, 8*type_size_of(lhs.type)); + TB_Node *zero = tb_inst_uint(p->func, dt, 0); + + TB_Node *width_test = tb_inst_cmp_ilt(p->func, bits, bit_size, false); + + TB_Node *res = nullptr; + + if (is_type_unsigned(integral_type)) { + res = tb_inst_shr(p->func, lhsval, bits); + } else { + res = tb_inst_sar(p->func, lhsval, bits); + } + + + res = tb_inst_select(p->func, width_test, res, zero); + return cg_value(res, type); + } + case Token_AndNot: + return cg_value(tb_inst_and(p->func, lhs.node, tb_inst_not(p->func, rhs.node)), type); + } + + GB_PANIC("unhandled operator of cg_emit_arith"); + + return {}; +} gb_internal cgAddr cg_build_addr_slice_expr(cgProcedure *p, Ast *expr) { @@ -962,6 +1122,15 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { } return cg_addr_load(p, cg_build_addr(p, expr)); case_end; + + case_ast_node(ie, IndexExpr, expr); + return cg_addr_load(p, cg_build_addr(p, expr)); + case_end; + + case_ast_node(ie, MatrixIndexExpr, expr); + return cg_addr_load(p, cg_build_addr(p, expr)); + case_end; + } GB_PANIC("TODO(bill): cg_build_expr_internal %.*s", LIT(ast_strings[expr->kind])); return {}; @@ -1023,6 +1192,130 @@ gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) { case_ast_node(se, SliceExpr, expr); return cg_build_addr_slice_expr(p, expr); case_end; + + case_ast_node(se, SelectorExpr, expr); + Ast *sel_node = unparen_expr(se->selector); + if (sel_node->kind != Ast_Ident) { + GB_PANIC("Unsupported selector expression"); + } + String selector = sel_node->Ident.token.string; + TypeAndValue tav = type_and_value_of_expr(se->expr); + + if (tav.mode == Addressing_Invalid) { + // NOTE(bill): Imports + Entity *imp = entity_of_node(se->expr); + if (imp != nullptr) { + GB_ASSERT(imp->kind == Entity_ImportName); + } + return cg_build_addr(p, unparen_expr(se->selector)); + } + + + Type *type = base_type(tav.type); + if (tav.mode == Addressing_Type) { // Addressing_Type + Selection sel = lookup_field(tav.type, selector, true); + if (sel.pseudo_field) { + GB_ASSERT(sel.entity->kind == Entity_Procedure); + return cg_addr(cg_find_value_from_entity(p->module, sel.entity)); + } + GB_PANIC("Unreachable %.*s", LIT(selector)); + } + + if (se->swizzle_count > 0) { + Type *array_type = base_type(type_deref(tav.type)); + GB_ASSERT(array_type->kind == Type_Array); + u8 swizzle_count = se->swizzle_count; + u8 swizzle_indices_raw = se->swizzle_indices; + u8 swizzle_indices[4] = {}; + for (u8 i = 0; i < swizzle_count; i++) { + u8 index = swizzle_indices_raw>>(i*2) & 3; + swizzle_indices[i] = index; + } + cgValue a = {}; + if (is_type_pointer(tav.type)) { + a = cg_build_expr(p, se->expr); + } else { + cgAddr addr = cg_build_addr(p, se->expr); + a = cg_addr_get_ptr(p, addr); + } + + GB_ASSERT(is_type_array(expr->tav.type)); + GB_PANIC("TODO(bill): cg_addr_swizzle"); + // return cg_addr_swizzle(a, expr->tav.type, swizzle_count, swizzle_indices); + } + + Selection sel = lookup_field(type, selector, false); + GB_ASSERT(sel.entity != nullptr); + if (sel.pseudo_field) { + GB_ASSERT(sel.entity->kind == Entity_Procedure); + Entity *e = entity_of_node(sel_node); + return cg_addr(cg_find_value_from_entity(p->module, e)); + } + + { + cgAddr addr = cg_build_addr(p, se->expr); + if (addr.kind == cgAddr_Map) { + cgValue v = cg_addr_load(p, addr); + cgValue a = {}; GB_PANIC("TODO(bill): cg_address_from_load_or_generate_local"); + // cgValue a = cg_address_from_load_or_generate_local(p, v); + GB_PANIC("TODO(bill): cg_emit_deep_field_gep"); + // a = cg_emit_deep_field_gep(p, a, sel); + return cg_addr(a); + } else if (addr.kind == cgAddr_Context) { + GB_ASSERT(sel.index.count > 0); + if (addr.ctx.sel.index.count >= 0) { + sel = selection_combine(addr.ctx.sel, sel); + } + addr.ctx.sel = sel; + addr.kind = cgAddr_Context; + return addr; + } else if (addr.kind == cgAddr_SoaVariable) { + cgValue index = addr.soa.index; + i32 first_index = sel.index[0]; + Selection sub_sel = sel; + sub_sel.index.data += 1; + sub_sel.index.count -= 1; + + cgValue arr = {}; GB_PANIC("TODO(bill): cg_emit_struct_ep"); + gb_unused(first_index); + // cgValue arr = cg_emit_struct_ep(p, addr.addr, first_index); + + // Type *t = base_type(type_deref(addr.addr.type)); + // GB_ASSERT(is_type_soa_struct(t)); + + // if (addr.soa.index_expr != nullptr && (!cg_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed)) { + // cgValue len = cg_soa_struct_len(p, addr.addr); + // cg_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len); + // } + + // cgValue item = {}; + + // if (t->Struct.soa_kind == StructSoa_Fixed) { + // item = cg_emit_array_ep(p, arr, index); + // } else { + // item = cg_emit_ptr_offset(p, cg_emit_load(p, arr), index); + // } + // if (sub_sel.index.count > 0) { + // item = cg_emit_deep_field_gep(p, item, sub_sel); + // } + // return cg_addr(item); + } else if (addr.kind == cgAddr_Swizzle) { + GB_ASSERT(sel.index.count > 0); + // NOTE(bill): just patch the index in place + sel.index[0] = addr.swizzle.indices[sel.index[0]]; + } else if (addr.kind == cgAddr_SwizzleLarge) { + GB_ASSERT(sel.index.count > 0); + // NOTE(bill): just patch the index in place + sel.index[0] = addr.swizzle.indices[sel.index[0]]; + } + + cgValue a = cg_addr_get_ptr(p, addr); + GB_PANIC("TODO(bill): cg_emit_deep_field_gep"); + // a = cg_emit_deep_field_gep(p, a, sel); + return cg_addr(a); + } + case_end; + } TokenPos token_pos = ast_token(expr).pos; diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 2f2bdd55f..f70dba115 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -228,6 +228,61 @@ gb_internal void cg_addr_store(cgProcedure *p, cgAddr addr, cgValue value) { cg_emit_store(p, addr.addr, value); } +gb_internal cgValue cg_addr_get_ptr(cgProcedure *p, cgAddr const &addr) { + if (cg_addr_is_empty(addr)) { + GB_PANIC("Illegal addr -> nullptr"); + return {}; + } + + switch (addr.kind) { + case cgAddr_Map: + GB_PANIC("TODO(bill): cg_addr_get_ptr cgAddr_Map"); + // return cg_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key); + break; + + case cgAddr_RelativePointer: { + Type *rel_ptr = base_type(cg_addr_type(addr)); + GB_ASSERT(rel_ptr->kind == Type_RelativePointer); + + cgValue ptr = cg_emit_conv(p, addr.addr, t_uintptr); + cgValue offset = cg_emit_conv(p, ptr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); + offset = cg_emit_load(p, offset); + + if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) { + offset = cg_emit_conv(p, offset, t_i64); + } + offset = cg_emit_conv(p, offset, t_uintptr); + + GB_PANIC("TODO(bill): cg_addr_get_ptr cgAddr_RelativePointer"); + // cgValue absolute_ptr = cg_emit_arith(p, Token_Add, ptr, offset, t_uintptr); + // absolute_ptr = cg_emit_conv(p, absolute_ptr, rel_ptr->RelativePointer.pointer_type); + + // cgValue cond = cg_emit_comp(p, Token_CmpEq, offset, cg_const_nil(p->module, rel_ptr->RelativePointer.base_integer)); + + // // NOTE(bill): nil check + // cgValue nil_ptr = cg_const_nil(p->module, rel_ptr->RelativePointer.pointer_type); + // cgValue final_ptr = cg_emit_select(p, cond, nil_ptr, absolute_ptr); + // return final_ptr; + break; + } + + case cgAddr_SoaVariable: + // TODO(bill): FIX THIS HACK + return cg_address_from_load(p, cg_addr_load(p, addr)); + + case cgAddr_Context: + GB_PANIC("cgAddr_Context should be handled elsewhere"); + break; + + case cgAddr_Swizzle: + case cgAddr_SwizzleLarge: + // TOOD(bill): is this good enough logic? + break; + } + + return addr.addr; +} + -- cgit v1.2.3 From 45b3ae31af0cf4805af2a226ebf0610c7c97bf17 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jul 2023 00:31:44 +0100 Subject: Mock out more of the `ep` procedures --- src/tilde_backend.hpp | 9 ++ src/tilde_expr.cpp | 45 ++++------ src/tilde_stmt.cpp | 238 +++++++++++++++++++++++++++++++++++++++++++++++++- src/types.cpp | 77 +++++++++++----- 4 files changed, 316 insertions(+), 53 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 6449bf49f..073e81f5d 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -211,6 +211,8 @@ gb_internal cgAddr cg_addr(cgValue const &value); gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value); gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type); +gb_internal cgValue cg_flatten_value(cgProcedure *p, cgValue value); + gb_internal void cg_build_stmt(cgProcedure *p, Ast *stmt); gb_internal void cg_build_stmt_list(cgProcedure *p, Slice const &stmts); gb_internal void cg_build_when_stmt(cgProcedure *p, AstWhenStmt *ws); @@ -227,6 +229,7 @@ gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_vol gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile=false); gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init); +gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgValue value); gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); @@ -237,3 +240,9 @@ gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type); gb_internal String cg_get_entity_name(cgModule *m, Entity *e); gb_internal cgValue cg_typeid(cgModule *m, Type *t); + +gb_internal cgValue cg_emit_ptr_offset(cgProcedure *p, cgValue ptr, cgValue index); +gb_internal cgValue cg_emit_array_ep(cgProcedure *p, cgValue s, cgValue index); +gb_internal cgValue cg_emit_array_epi(cgProcedure *p, cgValue s, i64 index); +gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index); +gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection const &sel); \ No newline at end of file diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 26c52f1bb..4e43089b2 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -790,11 +790,6 @@ gb_internal cgAddr cg_build_addr_slice_expr(cgProcedure *p, Ast *expr) { tb_inst_store(p->func, TB_TYPE_PTR, data_ptr, offset, cast(TB_CharUnits)build_context.ptr_size, false); tb_inst_store(p->func, TB_TYPE_INT, len_ptr, len, cast(TB_CharUnits)build_context.int_size, false); - - // LLVMValueRef gep0 = cg_emit_struct_ep(p, res.addr, 0).value; - // LLVMValueRef gep1 = cg_emit_struct_ep(p, res.addr, 1).value; - // LLVMBuildStore(p->builder, ptr, gep0); - // LLVMBuildStore(p->builder, len, gep1); return res; } } @@ -1256,10 +1251,8 @@ gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) { cgAddr addr = cg_build_addr(p, se->expr); if (addr.kind == cgAddr_Map) { cgValue v = cg_addr_load(p, addr); - cgValue a = {}; GB_PANIC("TODO(bill): cg_address_from_load_or_generate_local"); - // cgValue a = cg_address_from_load_or_generate_local(p, v); - GB_PANIC("TODO(bill): cg_emit_deep_field_gep"); - // a = cg_emit_deep_field_gep(p, a, sel); + cgValue a = cg_address_from_load_or_generate_local(p, v); + a = cg_emit_deep_field_gep(p, a, sel); return cg_addr(a); } else if (addr.kind == cgAddr_Context) { GB_ASSERT(sel.index.count > 0); @@ -1271,34 +1264,33 @@ gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) { return addr; } else if (addr.kind == cgAddr_SoaVariable) { cgValue index = addr.soa.index; - i32 first_index = sel.index[0]; + i64 first_index = sel.index[0]; Selection sub_sel = sel; sub_sel.index.data += 1; sub_sel.index.count -= 1; - cgValue arr = {}; GB_PANIC("TODO(bill): cg_emit_struct_ep"); - gb_unused(first_index); - // cgValue arr = cg_emit_struct_ep(p, addr.addr, first_index); + cgValue arr = cg_emit_struct_ep(p, addr.addr, first_index); - // Type *t = base_type(type_deref(addr.addr.type)); - // GB_ASSERT(is_type_soa_struct(t)); + Type *t = base_type(type_deref(addr.addr.type)); + GB_ASSERT(is_type_soa_struct(t)); + // TODO(bill): bounds checking for soa variable // if (addr.soa.index_expr != nullptr && (!cg_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed)) { // cgValue len = cg_soa_struct_len(p, addr.addr); // cg_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len); // } - // cgValue item = {}; + cgValue item = {}; - // if (t->Struct.soa_kind == StructSoa_Fixed) { - // item = cg_emit_array_ep(p, arr, index); - // } else { - // item = cg_emit_ptr_offset(p, cg_emit_load(p, arr), index); - // } - // if (sub_sel.index.count > 0) { - // item = cg_emit_deep_field_gep(p, item, sub_sel); - // } - // return cg_addr(item); + if (t->Struct.soa_kind == StructSoa_Fixed) { + item = cg_emit_array_ep(p, arr, index); + } else { + item = cg_emit_ptr_offset(p, cg_emit_load(p, arr), index); + } + if (sub_sel.index.count > 0) { + item = cg_emit_deep_field_gep(p, item, sub_sel); + } + return cg_addr(item); } else if (addr.kind == cgAddr_Swizzle) { GB_ASSERT(sel.index.count > 0); // NOTE(bill): just patch the index in place @@ -1310,8 +1302,7 @@ gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) { } cgValue a = cg_addr_get_ptr(p, addr); - GB_PANIC("TODO(bill): cg_emit_deep_field_gep"); - // a = cg_emit_deep_field_gep(p, a, sel); + a = cg_emit_deep_field_gep(p, a, sel); return cg_addr(a); } case_end; diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index f70dba115..a38886c2e 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -253,13 +253,13 @@ gb_internal cgValue cg_addr_get_ptr(cgProcedure *p, cgAddr const &addr) { } offset = cg_emit_conv(p, offset, t_uintptr); - GB_PANIC("TODO(bill): cg_addr_get_ptr cgAddr_RelativePointer"); - // cgValue absolute_ptr = cg_emit_arith(p, Token_Add, ptr, offset, t_uintptr); - // absolute_ptr = cg_emit_conv(p, absolute_ptr, rel_ptr->RelativePointer.pointer_type); + cgValue absolute_ptr = cg_emit_arith(p, Token_Add, ptr, offset, t_uintptr); + absolute_ptr = cg_emit_conv(p, absolute_ptr, rel_ptr->RelativePointer.pointer_type); + GB_PANIC("TODO(bill): cg_addr_get_ptr cgAddr_RelativePointer"); // cgValue cond = cg_emit_comp(p, Token_CmpEq, offset, cg_const_nil(p->module, rel_ptr->RelativePointer.base_integer)); - // // NOTE(bill): nil check + // NOTE(bill): nil check // cgValue nil_ptr = cg_const_nil(p->module, rel_ptr->RelativePointer.pointer_type); // cgValue final_ptr = cg_emit_select(p, cond, nil_ptr, absolute_ptr); // return final_ptr; @@ -283,6 +283,219 @@ gb_internal cgValue cg_addr_get_ptr(cgProcedure *p, cgAddr const &addr) { return addr.addr; } +gb_internal cgValue cg_emit_ptr_offset(cgProcedure *p, cgValue ptr, cgValue index) { + GB_ASSERT(ptr.kind == cgValue_Value); + GB_ASSERT(index.kind == cgValue_Value); + GB_ASSERT(is_type_pointer(ptr.type) || is_type_multi_pointer(ptr.type)); + GB_ASSERT(is_type_integer(index.type)); + + Type *elem = type_deref(ptr.type, true); + i64 stride = type_size_of(elem); + ptr.node = tb_inst_array_access(p->func, ptr.node, index.node, stride); + return ptr; +} +gb_internal cgValue cg_emit_array_ep(cgProcedure *p, cgValue s, cgValue index) { + GB_ASSERT(s.kind == cgValue_Value); + GB_ASSERT(index.kind == cgValue_Value); + + Type *t = s.type; + GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t)); + Type *st = base_type(type_deref(t)); + GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); + GB_ASSERT_MSG(is_type_integer(core_type(index.type)), "%s", type_to_string(index.type)); + + + Type *elem = base_array_type(st); + i64 stride = type_size_of(elem); + s.node = tb_inst_array_access(p->func, s.node, index.node, stride); + return s; +} +gb_internal cgValue cg_emit_array_epi(cgProcedure *p, cgValue s, i64 index) { + return cg_emit_array_ep(p, s, cg_const_int(p, t_int, index)); +} + + +gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index) { + s = cg_flatten_value(p, s); + + GB_ASSERT(is_type_pointer(s.type)); + Type *t = base_type(type_deref(s.type)); + Type *result_type = nullptr; + + if (is_type_relative_pointer(t)) { + s = cg_addr_get_ptr(p, cg_addr(s)); + } + + if (is_type_struct(t)) { + result_type = get_struct_field_type(t, index); + } else if (is_type_union(t)) { + GB_ASSERT(index == -1); + GB_PANIC("TODO(bill): cg_emit_union_tag_ptr"); + // return cg_emit_union_tag_ptr(p, s); + } else if (is_type_tuple(t)) { + GB_PANIC("TODO(bill): cg_emit_tuple_ep"); + // return cg_emit_tuple_ep(p, s, index); + // return cg_emit_tuple_ep(p, s, index); + } else if (is_type_complex(t)) { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = ft; break; + case 1: result_type = ft; break; + } + } else if (is_type_quaternion(t)) { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = ft; break; + case 1: result_type = ft; break; + case 2: result_type = ft; break; + case 3: result_type = ft; break; + } + } else if (is_type_slice(t)) { + switch (index) { + case 0: result_type = alloc_type_pointer(t->Slice.elem); break; + case 1: result_type = t_int; break; + } + } else if (is_type_string(t)) { + switch (index) { + case 0: result_type = t_u8_ptr; break; + case 1: result_type = t_int; break; + } + } else if (is_type_any(t)) { + switch (index) { + case 0: result_type = t_rawptr; break; + case 1: result_type = t_typeid; break; + } + } else if (is_type_dynamic_array(t)) { + switch (index) { + case 0: result_type = alloc_type_pointer(t->DynamicArray.elem); break; + case 1: result_type = t_int; break; + case 2: result_type = t_int; break; + case 3: result_type = t_allocator; break; + } + } else if (is_type_map(t)) { + init_map_internal_types(t); + Type *itp = alloc_type_pointer(t_raw_map); + s = cg_emit_transmute(p, s, itp); + + switch (index) { + case 0: result_type = get_struct_field_type(t_raw_map, 0); break; + case 1: result_type = get_struct_field_type(t_raw_map, 1); break; + case 2: result_type = get_struct_field_type(t_raw_map, 2); break; + } + } else if (is_type_array(t)) { + return cg_emit_array_epi(p, s, index); + } else if (is_type_relative_slice(t)) { + switch (index) { + case 0: result_type = t->RelativeSlice.base_integer; break; + case 1: result_type = t->RelativeSlice.base_integer; break; + } + } else if (is_type_soa_pointer(t)) { + switch (index) { + case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break; + case 1: result_type = t_int; break; + } + } else { + GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(s.type), index); + } + + GB_ASSERT_MSG(result_type != nullptr, "%s %d", type_to_string(t), index); + + GB_PANIC("TODO(bill): cg_emit_struct_ep_internal"); + // return cg_emit_struct_ep_internal(p, s, index, result_type); + return {}; +} + +gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection const &sel) { + GB_ASSERT(sel.index.count > 0); + Type *type = type_deref(e.type); + + for_array(i, sel.index) { + i64 index = sel.index[i]; + if (is_type_pointer(type)) { + type = type_deref(type); + e = cg_emit_load(p, e); + } + type = core_type(type); + + if (type->kind == Type_SoaPointer) { + cgValue addr = cg_emit_struct_ep(p, e, 0); + cgValue index = cg_emit_struct_ep(p, e, 1); + addr = cg_emit_load(p, addr); + index = cg_emit_load(p, index); + + i64 first_index = sel.index[0]; + Selection sub_sel = sel; + sub_sel.index.data += 1; + sub_sel.index.count -= 1; + + cgValue arr = cg_emit_struct_ep(p, addr, first_index); + + Type *t = base_type(type_deref(addr.type)); + GB_ASSERT(is_type_soa_struct(t)); + + if (t->Struct.soa_kind == StructSoa_Fixed) { + e = cg_emit_array_ep(p, arr, index); + } else { + e = cg_emit_ptr_offset(p, cg_emit_load(p, arr), index); + } + } else if (is_type_quaternion(type)) { + e = cg_emit_struct_ep(p, e, index); + } else if (is_type_raw_union(type)) { + type = get_struct_field_type(type, index); + GB_ASSERT(is_type_pointer(e.type)); + e = cg_emit_transmute(p, e, alloc_type_pointer(type)); + } else if (is_type_struct(type)) { + type = get_struct_field_type(type, index); + e = cg_emit_struct_ep(p, e, index); + } else if (type->kind == Type_Union) { + GB_ASSERT(index == -1); + type = t_type_info_ptr; + e = cg_emit_struct_ep(p, e, index); + } else if (type->kind == Type_Tuple) { + type = type->Tuple.variables[index]->type; + e = cg_emit_struct_ep(p, e, index); + } else if (type->kind == Type_Basic) { + switch (type->Basic.kind) { + case Basic_any: { + if (index == 0) { + type = t_rawptr; + } else if (index == 1) { + type = t_type_info_ptr; + } + e = cg_emit_struct_ep(p, e, index); + break; + } + + case Basic_string: + e = cg_emit_struct_ep(p, e, index); + break; + + default: + GB_PANIC("un-gep-able type %s", type_to_string(type)); + break; + } + } else if (type->kind == Type_Slice) { + e = cg_emit_struct_ep(p, e, index); + } else if (type->kind == Type_DynamicArray) { + e = cg_emit_struct_ep(p, e, index); + } else if (type->kind == Type_Array) { + e = cg_emit_array_epi(p, e, index); + } else if (type->kind == Type_Map) { + e = cg_emit_struct_ep(p, e, index); + } else if (type->kind == Type_RelativePointer) { + e = cg_emit_struct_ep(p, e, index); + } else { + GB_PANIC("un-gep-able type %s", type_to_string(type)); + } + } + + return e; +} + + + + + @@ -369,6 +582,23 @@ gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero return addr; } +gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgValue value) { + switch (value.kind) { + case cgValue_Value: + if (value.node->type == TB_LOAD) { + TB_Node *ptr = value.node->inputs[1]; + return cg_value(ptr, alloc_type_pointer(value.type)); + } + break; + case cgValue_Addr: + return cg_value(value.node, alloc_type_pointer(value.type)); + } + + cgAddr res = cg_add_local(p, value.type, nullptr, false); + cg_addr_store(p, res, value); + return res.addr; +} + gb_internal void cg_scope_open(cgProcedure *p, Scope *scope) { // TODO(bill): cg_scope_open diff --git a/src/types.cpp b/src/types.cpp index 98be2b6cf..a0881b3d1 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -725,7 +725,7 @@ struct TypePath; gb_internal i64 type_size_of (Type *t); gb_internal i64 type_align_of (Type *t); -gb_internal i64 type_offset_of (Type *t, i32 index); +gb_internal i64 type_offset_of (Type *t, i32 index, Type **field_type_=nullptr); gb_internal gbString type_to_string (Type *type, bool shorthand=true); gb_internal gbString type_to_string (Type *type, gbAllocator allocator, bool shorthand=true); gb_internal i64 type_size_of_internal(Type *t, TypePath *path); @@ -3907,50 +3907,83 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { return build_context.ptr_size; } -gb_internal i64 type_offset_of(Type *t, i32 index) { +gb_internal i64 type_offset_of(Type *t, i32 index, Type **field_type_) { t = base_type(t); - if (t->kind == Type_Struct) { + switch (t->kind) { + case Type_Struct: type_set_offsets(t); if (gb_is_between(index, 0, t->Struct.fields.count-1)) { GB_ASSERT(t->Struct.offsets != nullptr); + if (field_type_) *field_type_ = t->Struct.fields[index]->type; return t->Struct.offsets[index]; } - } else if (t->kind == Type_Tuple) { + break; + case Type_Tuple: type_set_offsets(t); if (gb_is_between(index, 0, t->Tuple.variables.count-1)) { GB_ASSERT(t->Tuple.offsets != nullptr); + if (field_type_) *field_type_ = t->Tuple.variables[index]->type; return t->Tuple.offsets[index]; } - } else if (t->kind == Type_Basic) { + break; + case Type_Basic: if (t->Basic.kind == Basic_string) { switch (index) { - case 0: return 0; // data - case 1: return build_context.int_size; // len + case 0: + if (field_type_) *field_type_ = t_u8_ptr; + return 0; // data + case 1: + if (field_type_) *field_type_ = t_int; + return build_context.int_size; // len } } else if (t->Basic.kind == Basic_any) { switch (index) { - case 0: return 0; // type_info - case 1: return build_context.ptr_size; // data + case 0: + if (field_type_) *field_type_ = t_rawptr; + return 0; // data + case 1: + if (field_type_) *field_type_ = t_typeid; + return build_context.ptr_size; // id } } - } else if (t->kind == Type_Slice) { + break; + case Type_Slice: switch (index) { - case 0: return 0; // data - case 1: return 1*build_context.int_size; // len - case 2: return 2*build_context.int_size; // cap + case 0: + if (field_type_) *field_type_ = alloc_type_multi_pointer(t->Slice.elem); + return 0; // data + case 1: + if (field_type_) *field_type_ = t_int; + return 1*build_context.int_size; // len } - } else if (t->kind == Type_DynamicArray) { + break; + case Type_DynamicArray: switch (index) { - case 0: return 0; // data - case 1: return 1*build_context.int_size; // len - case 2: return 2*build_context.int_size; // cap - case 3: return 3*build_context.int_size; // allocator + case 0: + if (field_type_) *field_type_ = alloc_type_multi_pointer(t->DynamicArray.elem); + return 0; // data + case 1: + if (field_type_) *field_type_ = t_int; + return 1*build_context.int_size; // len + case 2: + if (field_type_) *field_type_ = t_int; + return 2*build_context.int_size; // cap + case 3: + if (field_type_) *field_type_ = t_allocator; + return 3*build_context.int_size; // allocator } - } else if (t->kind == Type_Union) { - /* i64 s = */ type_size_of(t); - switch (index) { - case -1: return align_formula(t->Union.variant_block_size, build_context.ptr_size); // __type_info + break; + case Type_Union: + if (!is_type_union_maybe_pointer(t)) { + /* i64 s = */ type_size_of(t); + switch (index) { + case -1: + if (field_type_) *field_type_ = union_tag_type(t); + union_tag_size(t); + return t->Union.variant_block_size; + } } + break; } GB_ASSERT(index == 0); return 0; -- cgit v1.2.3 From bd73834e196d21aaed0bb1fd0a3d84e323b8aba7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jul 2023 16:56:10 +0100 Subject: Update Tilde; mock out `cg_build_return_stmt` 128-bit types are broken --- src/tilde/tb.h | 26 +++++++--- src/tilde/tb.lib | Bin 4112646 -> 4113018 bytes src/tilde_backend.cpp | 4 +- src/tilde_backend.hpp | 3 +- src/tilde_const.cpp | 2 +- src/tilde_proc.cpp | 139 ++++++++++++++++++++++++++------------------------ src/tilde_stmt.cpp | 28 +++++++++- 7 files changed, 125 insertions(+), 77 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde/tb.h b/src/tilde/tb.h index 8b698ff30..4fb5d30ef 100644 --- a/src/tilde/tb.h +++ b/src/tilde/tb.h @@ -195,8 +195,6 @@ typedef union TB_DataType { typedef enum TB_NodeTypeEnum { TB_NULL = 0, - TB_RETURN, // fn(r: region, x: data) - // only one per function TB_START, // fn() @@ -823,7 +821,16 @@ TB_API TB_DebugType* tb_debug_create_array(TB_Module* m, TB_DebugType* base, siz TB_API TB_DebugType* tb_debug_create_struct(TB_Module* m, ptrdiff_t len, const char* tag); TB_API TB_DebugType* tb_debug_create_union(TB_Module* m, ptrdiff_t len, const char* tag); TB_API TB_DebugType* tb_debug_create_field(TB_Module* m, TB_DebugType* type, ptrdiff_t len, const char* name, TB_CharUnits offset); -TB_API void tb_debug_complete_record(TB_DebugType* type, TB_DebugType** members, size_t count, TB_CharUnits size, TB_CharUnits align); + +// returns the array you need to fill with fields +TB_API TB_DebugType** tb_debug_record_begin(TB_DebugType* type, size_t count); +TB_API void tb_debug_record_end(TB_DebugType* type, TB_CharUnits size, TB_CharUnits align); + +TB_API TB_DebugType* tb_debug_create_func(TB_Module* m, TB_CallingConv cc, size_t param_count, size_t return_count, bool has_varargs); + +// you'll need to fill these if you make a function +TB_API TB_DebugType** tb_debug_func_params(TB_DebugType* type); +TB_API TB_DebugType** tb_debug_func_returns(TB_DebugType* type); //////////////////////////////// // IR access @@ -850,6 +857,8 @@ TB_API TB_Global* tb_symbol_as_global(TB_Symbol* s); //////////////////////////////// // Function IR Generation //////////////////////////////// +TB_API void tb_get_data_type_size(TB_Module* mod, TB_DataType dt, size_t* size, size_t* align); + // the user_data is expected to be a valid FILE* TB_API void tb_default_print_callback(void* user_data, const char* fmt, ...); @@ -869,6 +878,12 @@ TB_API void tb_symbol_set_name(TB_Symbol* s, ptrdiff_t len, const char* name); TB_API void tb_symbol_bind_ptr(TB_Symbol* s, void* ptr); TB_API const char* tb_symbol_get_name(TB_Symbol* s); +// same as tb_function_set_prototype except it will handle lowering from types like the TB_DebugType +// into the correct ABI and exposing sane looking nodes to the parameters. +// +// returns the parameters +TB_API TB_Node** tb_function_set_prototype_from_dbg(TB_Function* f, TB_DebugType* dbg, TB_Arena* arena, size_t* out_param_count); + // if arena is NULL, defaults to module arena which is freed on tb_free_thread_resources TB_API void tb_function_set_prototype(TB_Function* f, TB_FunctionPrototype* p, TB_Arena* arena); TB_API TB_FunctionPrototype* tb_function_get_prototype(TB_Function* f); @@ -890,7 +905,6 @@ TB_API void tb_inst_keep_alive(TB_Function* f, TB_Node* src); TB_API TB_Node* tb_inst_poison(TB_Function* f); TB_API TB_Node* tb_inst_param(TB_Function* f, int param_id); -TB_API TB_Node* tb_inst_param_addr(TB_Function* f, int param_id); TB_API TB_Node* tb_inst_fpxt(TB_Function* f, TB_Node* src, TB_DataType dt); TB_API TB_Node* tb_inst_sxt(TB_Function* f, TB_Node* src, TB_DataType dt); @@ -902,7 +916,7 @@ TB_API TB_Node* tb_inst_int2float(TB_Function* f, TB_Node* src, TB_DataType dt, TB_API TB_Node* tb_inst_float2int(TB_Function* f, TB_Node* src, TB_DataType dt, bool is_signed); TB_API TB_Node* tb_inst_bitcast(TB_Function* f, TB_Node* src, TB_DataType dt); -TB_API TB_Node* tb_inst_local(TB_Function* f, uint32_t size, TB_CharUnits align); +TB_API TB_Node* tb_inst_local(TB_Function* f, TB_CharUnits size, TB_CharUnits align); TB_API TB_Node* tb_inst_load(TB_Function* f, TB_DataType dt, TB_Node* addr, TB_CharUnits align, bool is_volatile); TB_API void tb_inst_store(TB_Function* f, TB_DataType dt, TB_Node* addr, TB_Node* val, TB_CharUnits align, bool is_volatile); @@ -918,7 +932,7 @@ TB_API TB_Node* tb_inst_string(TB_Function* f, size_t len, const char* str); TB_API void tb_inst_memset(TB_Function* f, TB_Node* dst, TB_Node* val, TB_Node* count, TB_CharUnits align, bool is_volatile); // zero 'count' bytes on 'dst' -TB_API void tb_inst_memzero(TB_Function* f, TB_Node* dst, TB_Node* val, TB_Node* count, TB_CharUnits align, bool is_volatile); +TB_API void tb_inst_memzero(TB_Function* f, TB_Node* dst, TB_Node* count, TB_CharUnits align, bool is_volatile); // performs a copy of 'count' elements from one memory location to another // both locations cannot overlap. diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index bad51e7e6..b52ce4c55 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index dfe39c385..db759b767 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -31,7 +31,7 @@ gb_internal TB_DataType cg_data_type(Type *t) { case Basic_uint: case Basic_uintptr: case Basic_typeid: - return TB_TYPE_INTN(cast(u16)(8*sz)); + return TB_TYPE_INTN(cast(u16)gb_min(8*sz, 64)); case Basic_f16: return TB_TYPE_F16; case Basic_f32: return TB_TYPE_F32; @@ -58,7 +58,7 @@ gb_internal TB_DataType cg_data_type(Type *t) { case Basic_u64be: case Basic_i128be: case Basic_u128be: - return TB_TYPE_INTN(cast(u16)(8*sz)); + return TB_TYPE_INTN(cast(u16)gb_min(8*sz, 64)); case Basic_f16le: return TB_TYPE_F16; case Basic_f32le: return TB_TYPE_F32; diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 073e81f5d..b2192cce4 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -8,7 +8,8 @@ #include "tilde/tb.h" #define TB_TYPE_F16 TB_DataType{ { TB_INT, 0, 16 } } -#define TB_TYPE_I128 TB_DataType{ { TB_INT, 0, 128 } } +// #define TB_TYPE_I128 TB_DataType{ { TB_INT, 0, 128 } } +#define TB_TYPE_I128 TB_TYPE_INTN(64) #define TB_TYPE_INT TB_TYPE_INTN(cast(u16)(8*build_context.int_size)) #define TB_TYPE_INTPTR TB_TYPE_INTN(cast(u16)(8*build_context.ptr_size)) diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index 35c87641f..75b66567e 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -86,7 +86,7 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac return cg_value(tb_inst_uint(p->func, dt, value.value_bool), type); case ExactValue_Integer: - GB_ASSERT(dt.raw != TB_TYPE_I128.raw); + // GB_ASSERT(dt.raw != TB_TYPE_I128.raw); if (is_type_unsigned(type)) { u64 i = exact_value_to_u64(value); return cg_value(tb_inst_uint(p->func, dt, i), type); diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index d763e2f8c..af9bee189 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -35,7 +35,7 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty case Basic_int: case Basic_uint: case Basic_uintptr: - param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + param.dt = TB_TYPE_INTN(cast(u16)gb_min(64, 8*sz)); break; case Basic_f16: param.dt = TB_TYPE_F16; break; @@ -66,7 +66,7 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty break; case Basic_typeid: - param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + param.dt = TB_TYPE_INTN(cast(u16)gb_min(64, 8*sz)); break; // Endian Specific Types @@ -86,7 +86,7 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty case Basic_u64be: case Basic_i128be: case Basic_u128be: - param.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + param.dt = TB_TYPE_INTN(cast(u16)gb_min(64, 8*sz)); break; case Basic_f16le: param.dt = TB_TYPE_F16; break; @@ -171,7 +171,7 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty case Basic_int: case Basic_uint: case Basic_uintptr: - result.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + result.dt = TB_TYPE_INTN(cast(u16)gb_min(64, 8*sz)); break; case Basic_f16: result.dt = TB_TYPE_I16; break; @@ -186,7 +186,7 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty break; case Basic_typeid: - result.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + result.dt = TB_TYPE_INTN(cast(u16)gb_min(64, 8*sz)); break; // Endian Specific Types @@ -206,7 +206,7 @@ gb_internal TB_FunctionPrototype *cg_procedure_type_as_prototype(cgModule *m, Ty case Basic_u64be: case Basic_i128be: case Basic_u128be: - result.dt = TB_TYPE_INTN(cast(u16)(8*sz)); + result.dt = TB_TYPE_INTN(cast(u16)gb_min(64, 8*sz)); break; case Basic_f16le: result.dt = TB_TYPE_I16; break; @@ -395,70 +395,75 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { GB_ASSERT(p->type->kind == Type_Proc); TypeProc *pt = &p->type->Proc; - if (pt->params) { - int param_index = 0; - for (Entity *e : pt->params->Tuple.variables) { - if (e->kind != Entity_Variable) { - continue; - } - - if (param_index >= p->proto->param_count) { - break; - } + if (pt->params == nullptr) { + return; + } + int param_index = 0; + for (Entity *e : pt->params->Tuple.variables) { + if (e->kind != Entity_Variable) { + continue; + } - TB_Node *ptr = tb_inst_param_addr(p->func, param_index); - cgValue local = cg_value(ptr, alloc_type_pointer(e->type)); + if (param_index >= p->proto->param_count) { + break; + } - if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { - // NOTE(bill): for debugging purposes only - String name = e->token.string; - TB_DebugType *debug_type = cg_debug_type(p->module, e->type); - tb_node_append_attrib(ptr, tb_function_attrib_variable(p->func, name.len, cast(char const *)name.text, debug_type)); + // TB_Node *ptr = tb_inst_param_addr(p->func, param_index); + TB_Node *param = tb_inst_param(p->func, param_index); + TB_Node *ptr = tb_inst_local(p->func, cast(TB_CharUnits)type_size_of(e->type), cast(TB_CharUnits)type_align_of(e->type)); + TB_DataType dt = cg_data_type(e->type); + tb_inst_store(p->func, dt, ptr, param, cast(TB_CharUnits)type_align_of(e->type), false); + cgValue local = cg_value(ptr, alloc_type_pointer(e->type)); - } - cgAddr addr = cg_addr(local); - if (e) { - map_set(&p->variable_map, e, addr); - } + if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { + // NOTE(bill): for debugging purposes only + String name = e->token.string; + TB_DebugType *debug_type = cg_debug_type(p->module, e->type); + tb_node_append_attrib(ptr, tb_function_attrib_variable(p->func, name.len, cast(char const *)name.text, debug_type)); - // if (arg_type->kind == lbArg_Ignore) { - // continue; - // } else if (arg_type->kind == lbArg_Direct) { - // if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { - // LLVMTypeRef param_type = lb_type(p->module, e->type); - // LLVMValueRef original_value = LLVMGetParam(p->value, param_offset+param_index); - // LLVMValueRef value = OdinLLVMBuildTransmute(p, original_value, param_type); - - // lbValue param = {}; - // param.value = value; - // param.type = e->type; - - // map_set(&p->direct_parameters, e, param); - - // lbValue ptr = lb_address_from_load_or_generate_local(p, param); - // GB_ASSERT(LLVMIsAAllocaInst(ptr.value)); - // lb_add_entity(p->module, e, ptr); - - // lbBlock *block = p->decl_block; - // if (original_value != value) { - // block = p->curr_block; - // } - // LLVMValueRef debug_storage_value = value; - // if (original_value != value && LLVMIsALoadInst(value)) { - // debug_storage_value = LLVMGetOperand(value, 0); - // } - // lb_add_debug_param_variable(p, debug_storage_value, e->type, e->token, param_index+1, block, arg_type->kind); - // } - // } else if (arg_type->kind == lbArg_Indirect) { - // if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { - // lbValue ptr = {}; - // ptr.value = LLVMGetParam(p->value, param_offset+param_index); - // ptr.type = alloc_type_pointer(e->type); - // lb_add_entity(p->module, e, ptr); - // lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block, arg_type->kind); - // } - // } } + cgAddr addr = cg_addr(local); + if (e) { + map_set(&p->variable_map, e, addr); + } + + // if (arg_type->kind == lbArg_Ignore) { + // continue; + // } else if (arg_type->kind == lbArg_Direct) { + // if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { + // LLVMTypeRef param_type = lb_type(p->module, e->type); + // LLVMValueRef original_value = LLVMGetParam(p->value, param_offset+param_index); + // LLVMValueRef value = OdinLLVMBuildTransmute(p, original_value, param_type); + + // lbValue param = {}; + // param.value = value; + // param.type = e->type; + + // map_set(&p->direct_parameters, e, param); + + // lbValue ptr = lb_address_from_load_or_generate_local(p, param); + // GB_ASSERT(LLVMIsAAllocaInst(ptr.value)); + // lb_add_entity(p->module, e, ptr); + + // lbBlock *block = p->decl_block; + // if (original_value != value) { + // block = p->curr_block; + // } + // LLVMValueRef debug_storage_value = value; + // if (original_value != value && LLVMIsALoadInst(value)) { + // debug_storage_value = LLVMGetOperand(value, 0); + // } + // lb_add_debug_param_variable(p, debug_storage_value, e->type, e->token, param_index+1, block, arg_type->kind); + // } + // } else if (arg_type->kind == lbArg_Indirect) { + // if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { + // lbValue ptr = {}; + // ptr.value = LLVMGetParam(p->value, param_offset+param_index); + // ptr.type = alloc_type_pointer(e->type); + // lb_add_entity(p->module, e, ptr); + // lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block, arg_type->kind); + // } + // } } } @@ -466,7 +471,9 @@ gb_internal void cg_procedure_end(cgProcedure *p) { if (p == nullptr || p->func == nullptr) { return; } - tb_inst_ret(p->func, 0, nullptr); + if (tb_inst_get_control(p->func)) { + tb_inst_ret(p->func, 0, nullptr); + } if (p->name == "main") { TB_Arena *arena = tb_default_arena(); defer (arena->free(arena)); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index a38886c2e..787b94a58 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -736,7 +736,33 @@ gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) { } gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return_results) { - + TypeTuple *tuple = &p->type->Proc.results->Tuple; + isize return_count = p->type->Proc.result_count; + gb_unused(tuple); + isize res_count = return_results.count; + gb_unused(res_count); + + if (return_count == 0) { + tb_inst_ret(p->func, 0, nullptr); + return; + } else if (return_count == 1) { + Entity *e = tuple->variables[0]; + if (res_count == 0) { + cgValue zero = cg_const_nil(p, tuple->variables[0]->type); + if (zero.kind == cgValue_Value) { + tb_inst_ret(p->func, 1, &zero.node); + } + return; + } + cgValue res = cg_build_expr(p, return_results[0]); + res = cg_emit_conv(p, res, e->type); + if (res.kind == cgValue_Value) { + tb_inst_ret(p->func, 1, &res.node); + } + return; + } else { + GB_PANIC("TODO(bill): MUTLIPLE RETURN VALUES"); + } } -- cgit v1.2.3 From b5b3f1fb421ee2c127d96719bfcf77c5ce7fa9e4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jul 2023 17:28:12 +0100 Subject: Mock out struct_ep calls --- src/tilde/tb.h | 2 +- src/tilde_stmt.cpp | 260 +++++++++++++++++++++++++++++++++++------------------ 2 files changed, 173 insertions(+), 89 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde/tb.h b/src/tilde/tb.h index 4fb5d30ef..f49b28c38 100644 --- a/src/tilde/tb.h +++ b/src/tilde/tb.h @@ -941,7 +941,7 @@ TB_API void tb_inst_memcpy(TB_Function* f, TB_Node* dst, TB_Node* src, TB_Node* // result = base + (index * stride) TB_API TB_Node* tb_inst_array_access(TB_Function* f, TB_Node* base, TB_Node* index, int64_t stride); -// result = base + offset +// result = base + // where base is a pointer TB_API TB_Node* tb_inst_member_access(TB_Function* f, TB_Node* base, int64_t offset); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 787b94a58..6c0e8cf76 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -325,84 +325,167 @@ gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index) { if (is_type_relative_pointer(t)) { s = cg_addr_get_ptr(p, cg_addr(s)); } + i64 offset = -1; + i64 int_size = build_context.int_size; + i64 ptr_size = build_context.ptr_size; - if (is_type_struct(t)) { - result_type = get_struct_field_type(t, index); - } else if (is_type_union(t)) { + switch (t->kind) { + case Type_Struct: + { + type_set_offsets(t); + result_type = t->Struct.fields[index]->type; + offset = t->Struct.offsets[index]; + } + break; + case Type_Union: GB_ASSERT(index == -1); GB_PANIC("TODO(bill): cg_emit_union_tag_ptr"); + break; // return cg_emit_union_tag_ptr(p, s); - } else if (is_type_tuple(t)) { + case Type_Tuple: GB_PANIC("TODO(bill): cg_emit_tuple_ep"); + break; // return cg_emit_tuple_ep(p, s, index); - // return cg_emit_tuple_ep(p, s, index); - } else if (is_type_complex(t)) { - Type *ft = base_complex_elem_type(t); + case Type_Slice: switch (index) { - case 0: result_type = ft; break; - case 1: result_type = ft; break; - } - } else if (is_type_quaternion(t)) { - Type *ft = base_complex_elem_type(t); - switch (index) { - case 0: result_type = ft; break; - case 1: result_type = ft; break; - case 2: result_type = ft; break; - case 3: result_type = ft; break; - } - } else if (is_type_slice(t)) { - switch (index) { - case 0: result_type = alloc_type_pointer(t->Slice.elem); break; - case 1: result_type = t_int; break; - } - } else if (is_type_string(t)) { - switch (index) { - case 0: result_type = t_u8_ptr; break; - case 1: result_type = t_int; break; + case 0: + result_type = alloc_type_pointer(t->Slice.elem); + offset = 0; + break; + case 1: + result_type = t_int; + offset = int_size; + break; } - } else if (is_type_any(t)) { - switch (index) { - case 0: result_type = t_rawptr; break; - case 1: result_type = t_typeid; break; + break; + case Type_Basic: + switch (t->Basic.kind) { + case Basic_string: + switch (index) { + case 0: + result_type = t_u8_ptr; + offset = 0; + break; + case 1: + result_type = t_int; + offset = int_size; + break; + } + break; + case Basic_any: + switch (index) { + case 0: + result_type = t_rawptr; + offset = 0; + break; + case 1: + result_type = t_typeid; + offset = ptr_size; + break; + } + break; + + case Basic_complex32: + case Basic_complex64: + case Basic_complex128: + { + Type *ft = base_complex_elem_type(t); + i64 sz = type_size_of(ft); + switch (index) { + case 0: case 1: + result_type = ft; offset = sz * index; break; + default: goto error_case; + } + break; + } + case Basic_quaternion64: + case Basic_quaternion128: + case Basic_quaternion256: + { + Type *ft = base_complex_elem_type(t); + i64 sz = type_size_of(ft); + switch (index) { + case 0: case 1: case 2: case 3: + result_type = ft; offset = sz * index; break; + default: goto error_case; + } + } + break; + default: + goto error_case; } - } else if (is_type_dynamic_array(t)) { + break; + case Type_DynamicArray: switch (index) { - case 0: result_type = alloc_type_pointer(t->DynamicArray.elem); break; - case 1: result_type = t_int; break; - case 2: result_type = t_int; break; - case 3: result_type = t_allocator; break; + case 0: + result_type = alloc_type_pointer(t->DynamicArray.elem); + offset = index*int_size; + break; + case 1: case 2: + result_type = t_int; + offset = index*int_size; + break; + case 3: + result_type = t_allocator; + offset = index*int_size; + break; + default: goto error_case; } - } else if (is_type_map(t)) { - init_map_internal_types(t); - Type *itp = alloc_type_pointer(t_raw_map); - s = cg_emit_transmute(p, s, itp); + break; + case Type_Map: + { + init_map_internal_types(t); + Type *itp = alloc_type_pointer(t_raw_map); + s = cg_emit_transmute(p, s, itp); - switch (index) { - case 0: result_type = get_struct_field_type(t_raw_map, 0); break; - case 1: result_type = get_struct_field_type(t_raw_map, 1); break; - case 2: result_type = get_struct_field_type(t_raw_map, 2); break; + Type *rms = base_type(t_raw_map); + GB_ASSERT(rms->kind == Type_Struct); + + if (0 <= index && index < 3) { + result_type = rms->Struct.fields[index]->type; + offset = rms->Struct.offsets[index]; + } else { + goto error_case; + } + break; } - } else if (is_type_array(t)) { + case Type_Array: return cg_emit_array_epi(p, s, index); - } else if (is_type_relative_slice(t)) { - switch (index) { - case 0: result_type = t->RelativeSlice.base_integer; break; - case 1: result_type = t->RelativeSlice.base_integer; break; + case Type_RelativeSlice: + { + Type *bi = t->RelativeSlice.base_integer; + i64 sz = type_size_of(bi); + switch (index) { + case 0: + case 1: + result_type = bi; + offset = sz * index; + break; + default: + goto error_case; + } } - } else if (is_type_soa_pointer(t)) { + break; + case Type_SoaPointer: switch (index) { case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break; case 1: result_type = t_int; break; } - } else { + break; + default: + error_case:; GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(s.type), index); + break; } GB_ASSERT_MSG(result_type != nullptr, "%s %d", type_to_string(t), index); + GB_ASSERT(offset >= 0); - GB_PANIC("TODO(bill): cg_emit_struct_ep_internal"); - // return cg_emit_struct_ep_internal(p, s, index, result_type); - return {}; + GB_ASSERT(s.kind == cgValue_Value); + return cg_value( + tb_inst_member_access(p->func, s.node, offset), + alloc_type_pointer(result_type) + ); } gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection const &sel) { @@ -417,7 +500,8 @@ gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection } type = core_type(type); - if (type->kind == Type_SoaPointer) { + switch (type->kind) { + case Type_SoaPointer: { cgValue addr = cg_emit_struct_ep(p, e, 0); cgValue index = cg_emit_struct_ep(p, e, 1); addr = cg_emit_load(p, addr); @@ -438,25 +522,11 @@ gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection } else { e = cg_emit_ptr_offset(p, cg_emit_load(p, arr), index); } - } else if (is_type_quaternion(type)) { - e = cg_emit_struct_ep(p, e, index); - } else if (is_type_raw_union(type)) { - type = get_struct_field_type(type, index); - GB_ASSERT(is_type_pointer(e.type)); - e = cg_emit_transmute(p, e, alloc_type_pointer(type)); - } else if (is_type_struct(type)) { - type = get_struct_field_type(type, index); - e = cg_emit_struct_ep(p, e, index); - } else if (type->kind == Type_Union) { - GB_ASSERT(index == -1); - type = t_type_info_ptr; - e = cg_emit_struct_ep(p, e, index); - } else if (type->kind == Type_Tuple) { - type = type->Tuple.variables[index]->type; - e = cg_emit_struct_ep(p, e, index); - } else if (type->kind == Type_Basic) { + break; + } + case Type_Basic: switch (type->Basic.kind) { - case Basic_any: { + case Basic_any: if (index == 0) { type = t_rawptr; } else if (index == 1) { @@ -464,28 +534,42 @@ gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection } e = cg_emit_struct_ep(p, e, index); break; - } - - case Basic_string: - e = cg_emit_struct_ep(p, e, index); - break; - default: - GB_PANIC("un-gep-able type %s", type_to_string(type)); + e = cg_emit_struct_ep(p, e, index); break; } - } else if (type->kind == Type_Slice) { - e = cg_emit_struct_ep(p, e, index); - } else if (type->kind == Type_DynamicArray) { + break; + case Type_Struct: + if (type->Struct.is_raw_union) { + type = get_struct_field_type(type, index); + GB_ASSERT(is_type_pointer(e.type)); + e = cg_emit_transmute(p, e, alloc_type_pointer(type)); + } else { + type = get_struct_field_type(type, index); + e = cg_emit_struct_ep(p, e, index); + } + break; + case Type_Union: + GB_ASSERT(index == -1); + type = t_type_info_ptr; e = cg_emit_struct_ep(p, e, index); - } else if (type->kind == Type_Array) { - e = cg_emit_array_epi(p, e, index); - } else if (type->kind == Type_Map) { + break; + case Type_Tuple: + type = type->Tuple.variables[index]->type; e = cg_emit_struct_ep(p, e, index); - } else if (type->kind == Type_RelativePointer) { + break; + case Type_Slice: + case Type_DynamicArray: + case Type_Map: + case Type_RelativePointer: e = cg_emit_struct_ep(p, e, index); - } else { + break; + case Type_Array: + e = cg_emit_array_epi(p, e, index); + break; + default: GB_PANIC("un-gep-able type %s", type_to_string(type)); + break; } } -- cgit v1.2.3 From b2c75dc3a22f72bcf7b4a47348bd46e4ddb05200 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jul 2023 22:18:15 +0100 Subject: Mostly fill in `cg_debug_type` --- src/tilde_backend.cpp | 3 + src/tilde_backend.hpp | 3 + src/tilde_proc.cpp | 2 +- src/tilde_stmt.cpp | 338 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 345 insertions(+), 1 deletion(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index db759b767..798f51bb3 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -396,6 +396,8 @@ gb_internal cgModule *cg_module_create(Checker *c) { map_init(&m->file_id_map); + map_init(&m->debug_type_map); + for_array(id, global_files) { if (AstFile *f = global_files[id]) { @@ -411,6 +413,7 @@ gb_internal void cg_module_destroy(cgModule *m) { map_destroy(&m->values); array_free(&m->procedures_to_generate); map_destroy(&m->file_id_map); + map_destroy(&m->debug_type_map); tb_module_destroy(m->mod); } diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index b2192cce4..032229193 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -176,6 +176,9 @@ struct cgModule { PtrMap procedure_values; Array procedures_to_generate; + RecursiveMutex debug_type_mutex; + PtrMap debug_type_map; + PtrMap file_id_map; // Key: AstFile.id (i32 cast to uintptr) std::atomic nested_type_name_guid; diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index af9bee189..49af695ee 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -409,7 +409,7 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { } // TB_Node *ptr = tb_inst_param_addr(p->func, param_index); - TB_Node *param = tb_inst_param(p->func, param_index); + TB_Node *param = tb_inst_param(p->func, param_index++); TB_Node *ptr = tb_inst_local(p->func, cast(TB_CharUnits)type_size_of(e->type), cast(TB_CharUnits)type_align_of(e->type)); TB_DataType dt = cg_data_type(e->type); tb_inst_store(p->func, dt, ptr, param, cast(TB_CharUnits)type_align_of(e->type), false); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 6c0e8cf76..4e49199f9 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -629,7 +629,345 @@ gb_internal void cg_pop_target_list(cgProcedure *p) { p->target_list = p->target_list->prev; } +gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type); gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type) { + mutex_lock(&m->debug_type_mutex); + defer (mutex_unlock(&m->debug_type_mutex)); + TB_DebugType **found = map_get(&m->debug_type_map, type); + if (found) { + return *found; + } + + TB_DebugType *res = cg_debug_type_internal(m, type); + map_set(&m->debug_type_map, type, res); + return res; +} + +gb_internal TB_DebugType *cg_debug_type_internal_record(cgModule *m, Type *type, String const &record_name) { + Type *bt = base_type(type); + switch (bt->kind) { + case Type_Struct: + { + type_set_offsets(bt); + + TB_DebugType *record = nullptr; + if (bt->Struct.is_raw_union) { + record = tb_debug_create_union(m->mod, record_name.len, cast(char const *)record_name.text); + } else { + record = tb_debug_create_struct(m->mod, record_name.len, cast(char const *)record_name.text); + } + if (record_name.len != 0) { + map_set(&m->debug_type_map, type, record); + } + + TB_DebugType **fields = tb_debug_record_begin(record, bt->Struct.fields.count); + for_array(i, bt->Struct.fields) { + Entity *e = bt->Struct.fields[i]; + Type *type = e->type; + if (is_type_proc(type)) { + type = t_rawptr; + } + TB_DebugType *field_type = cg_debug_type(m, type); + String name = e->token.string; + TB_CharUnits offset = cast(TB_CharUnits)bt->Struct.offsets[i]; + if (name.len == 0) { + name = str_lit("_"); + } + + fields[i] = tb_debug_create_field(m->mod, field_type, name.len, cast(char const *)name.text, offset); + } + tb_debug_record_end( + record, + cast(TB_CharUnits)type_size_of(type), + cast(TB_CharUnits)type_align_of(type) + ); + return record; + } + break; + case Type_Union: + { + TB_DebugType *record = tb_debug_create_struct(m->mod, record_name.len, cast(char const *)record_name.text); + if (record_name.len != 0) { + map_set(&m->debug_type_map, type, record); + } + + i64 variant_count = bt->Union.variants.count; + if (is_type_union_maybe_pointer(bt)) { + // NO TAG + GB_ASSERT(variant_count == 1); + TB_DebugType **fields = tb_debug_record_begin(record, variant_count); + TB_DebugType *variant_type = cg_debug_type(m, bt->Union.variants[0]); + fields[0] = tb_debug_create_field(m->mod, variant_type, -1, "v0", 0); + tb_debug_record_end( + record, + cast(TB_CharUnits)type_size_of(type), + cast(TB_CharUnits)type_align_of(type) + ); + } else { + TB_DebugType **fields = tb_debug_record_begin(record, variant_count+1); + for_array(i, bt->Union.variants) { + Type *v = bt->Union.variants[i]; + TB_DebugType *variant_type = cg_debug_type(m, v); + char name[32] = {}; + u32 v_index = cast(u32)i; + if (bt->Union.kind != UnionType_no_nil) { + v_index += 1; + } + gb_snprintf(name, 31, "v%u", v_index); + fields[i] = tb_debug_create_field(m->mod, variant_type, -1, name, 0); + } + + TB_DebugType *tag_type = cg_debug_type(m, union_tag_type(bt)); + fields[variant_count] = tb_debug_create_field(m->mod, tag_type, -1, "tag", cast(TB_CharUnits)bt->Union.variant_block_size); + + } + tb_debug_record_end( + record, + cast(TB_CharUnits)type_size_of(type), + cast(TB_CharUnits)type_align_of(type) + ); + return record; + } + break; + } + return nullptr; +} + + +gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type) { + if (type == nullptr) { + return tb_debug_get_void(m->mod); + } + if (type->kind == Type_Named) { + String name = type->Named.name; + TB_DebugType *res = cg_debug_type_internal_record(m, type, name); + if (res) { + return res; + } + type = base_type(type->Named.base); + } + + TB_CharUnits int_size = cast(TB_CharUnits)build_context.int_size; + TB_CharUnits ptr_size = cast(TB_CharUnits)build_context.ptr_size; + TB_CharUnits size = cast(TB_CharUnits)type_size_of(type); + TB_CharUnits align = cast(TB_CharUnits)type_align_of(type); + int bits = cast(int)(8*size); + bool is_signed = is_type_integer(core_type(type)) && !is_type_unsigned(core_type(type)); + + switch (type->kind) { + case Type_Basic: + switch (type->Basic.kind) { + case Basic_bool: return tb_debug_get_bool(m->mod); + case Basic_b8: return tb_debug_get_bool(m->mod); + case Basic_b16: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_b32: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_b64: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i8: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u8: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i16: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u16: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i32: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u32: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i64: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u64: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i128: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_u128: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_rune: return tb_debug_get_integer(m->mod, is_signed, bits); + + case Basic_f16: return tb_debug_get_integer(m->mod, false, bits); + case Basic_f32: return tb_debug_get_float(m->mod, TB_FLT_32); + case Basic_f64: return tb_debug_get_float(m->mod,TB_FLT_64); + + case Basic_complex32: + case Basic_complex64: + case Basic_complex128: + { + String name = basic_types[type->Basic.kind].Basic.name; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + Type *et = base_complex_elem_type(type); + TB_CharUnits elem_size = cast(TB_CharUnits)type_size_of(et); + TB_DebugType *elem = cg_debug_type(m, et); + + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, elem, -1, "real", 0*elem_size); + fields[1] = tb_debug_create_field(m->mod, elem, -1, "imag", 1*elem_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Basic_quaternion64: + case Basic_quaternion128: + case Basic_quaternion256: + { + String name = basic_types[type->Basic.kind].Basic.name; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + Type *et = base_complex_elem_type(type); + TB_CharUnits elem_size = cast(TB_CharUnits)type_size_of(et); + TB_DebugType *elem = cg_debug_type(m, et); + + // @QuaternionLayout + TB_DebugType **fields = tb_debug_record_begin(record, 4); + fields[0] = tb_debug_create_field(m->mod, elem, -1, "imag", 0*elem_size); + fields[1] = tb_debug_create_field(m->mod, elem, -1, "jmag", 1*elem_size); + fields[2] = tb_debug_create_field(m->mod, elem, -1, "kmag", 2*elem_size); + fields[3] = tb_debug_create_field(m->mod, elem, -1, "real", 3*elem_size); + + tb_debug_record_end(record, size, align); + return record; + } + + case Basic_int: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_uint: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_uintptr: return tb_debug_get_integer(m->mod, is_signed, bits); + + case Basic_rawptr: return tb_debug_create_ptr(m->mod, tb_debug_get_void(m->mod)); + case Basic_string: + { + String name = basic_types[type->Basic.kind].Basic.name; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + // @QuaternionLayout + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, t_u8_ptr), -1, "data", 0*int_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Basic_cstring: + return tb_debug_create_ptr(m->mod, tb_debug_get_integer(m->mod, false, 8)); + + case Basic_any: + { + String name = basic_types[type->Basic.kind].Basic.name; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + // @QuaternionLayout + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, t_rawptr), -1, "data", 0*ptr_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_typeid), -1, "id", 1*ptr_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Basic_typeid: return tb_debug_get_integer(m->mod, is_signed, bits); + + case Basic_i16le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u16le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i32le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u32le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i64le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u64le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i128le: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_u128le: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_i16be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u16be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i32be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u32be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i64be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u64be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i128be: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_u128be: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + + case Basic_f16le: return tb_debug_get_integer(m->mod, false, bits); + case Basic_f32le: return tb_debug_get_float(m->mod, TB_FLT_32); + case Basic_f64le: return tb_debug_get_float(m->mod,TB_FLT_64); + case Basic_f16be: return tb_debug_get_integer(m->mod, false, bits); + case Basic_f32be: return tb_debug_get_float(m->mod, TB_FLT_32); + case Basic_f64be: return tb_debug_get_float(m->mod,TB_FLT_64); + } + break; + case Type_Generic: + GB_PANIC("SHOULD NEVER HIT"); + break; + case Type_Pointer: + return tb_debug_create_ptr(m->mod, cg_debug_type(m, type->Pointer.elem)); + case Type_MultiPointer: + return tb_debug_create_ptr(m->mod, cg_debug_type(m, type->MultiPointer.elem)); + case Type_Array: + return tb_debug_create_array(m->mod, cg_debug_type(m, type->Array.elem), type->Array.count); + case Type_EnumeratedArray: + return tb_debug_create_array(m->mod, cg_debug_type(m, type->EnumeratedArray.elem), type->EnumeratedArray.count); + case Type_Slice: + { + String name = {}; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->Slice.elem)), -1, "data", 0*int_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Type_DynamicArray: + { + String name = {}; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + TB_DebugType **fields = tb_debug_record_begin(record, 4); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->Slice.elem)), -1, "data", 0*int_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); + fields[2] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "cap", 2*int_size); + fields[3] = tb_debug_create_field(m->mod, cg_debug_type(m, t_allocator), -1, "allocator", 3*int_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Type_Map: + return cg_debug_type(m, t_raw_map); + case Type_Struct: + return cg_debug_type_internal_record(m, type, {}); + case Type_Union: + return cg_debug_type_internal_record(m, type, {}); + case Type_Enum: + return tb_debug_get_integer(m->mod, is_signed, bits); + case Type_Tuple: + GB_PANIC("SHOULD NEVER HIT"); + break; + case Type_Proc: + { + TypeProc *pt = &type->Proc; + isize param_count = 0; + isize return_count = 0; + TB_DebugType *func = tb_debug_create_func(m->mod, TB_CDECL, param_count, return_count, pt->c_vararg); + return func; + } + break; + case Type_BitSet: + return cg_debug_type(m, bit_set_to_int(type)); + case Type_SimdVector: + return tb_debug_create_array(m->mod, cg_debug_type(m, type->SimdVector.elem), type->SimdVector.count); + case Type_RelativePointer: + return cg_debug_type(m, type->RelativePointer.base_integer); + case Type_RelativeSlice: + { + String name = {}; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + + TB_DebugType *base_integer = cg_debug_type(m, type->RelativeSlice.base_integer); + TB_CharUnits bi_size = cast(TB_CharUnits)type_size_of(type->RelativeSlice.base_integer); + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, base_integer, -1, "data", 0*bi_size); + fields[1] = tb_debug_create_field(m->mod, base_integer, -1, "len", 1*bi_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Type_Matrix: + { + i64 count = matrix_type_total_internal_elems(type); + return tb_debug_create_array(m->mod, cg_debug_type(m, type->Matrix.elem), count); + } + case Type_SoaPointer: + { + String name = {}; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->SoaPointer.elem)), -1, "ptr", 0*int_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "offset", 1*int_size); + + tb_debug_record_end(record, size, align); + return record; + } + } + // TODO(bill): cg_debug_type return tb_debug_get_void(m->mod); } -- cgit v1.2.3 From 0b697b24bdd6fa014876c0f00b84838c6f35d904 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jul 2023 22:33:13 +0100 Subject: Implement debug type for `proc`s --- src/tilde_stmt.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 5 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 4e49199f9..dc6819b89 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -684,6 +684,37 @@ gb_internal TB_DebugType *cg_debug_type_internal_record(cgModule *m, Type *type, return record; } break; + + case Type_Tuple: + { + GB_ASSERT(record_name.len == 0); + type_set_offsets(bt); + + TB_DebugType *record = tb_debug_create_struct(m->mod, 0, ""); + TB_DebugType **fields = tb_debug_record_begin(record, bt->Tuple.variables.count); + for_array(i, bt->Tuple.variables) { + Entity *e = bt->Tuple.variables[i]; + Type *type = e->type; + if (is_type_proc(type)) { + type = t_rawptr; + } + TB_DebugType *field_type = cg_debug_type(m, type); + String name = e->token.string; + TB_CharUnits offset = cast(TB_CharUnits)bt->Tuple.offsets[i]; + if (name.len == 0) { + name = str_lit("_"); + } + + fields[i] = tb_debug_create_field(m->mod, field_type, name.len, cast(char const *)name.text, offset); + } + tb_debug_record_end( + record, + cast(TB_CharUnits)type_size_of(type), + cast(TB_CharUnits)type_align_of(type) + ); + return record; + } + break; case Type_Union: { TB_DebugType *record = tb_debug_create_struct(m->mod, record_name.len, cast(char const *)record_name.text); @@ -738,6 +769,7 @@ gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type) { if (type == nullptr) { return tb_debug_get_void(m->mod); } + Type *original_type = type; if (type->kind == Type_Named) { String name = type->Named.name; TB_DebugType *res = cg_debug_type_internal_record(m, type, name); @@ -912,22 +944,99 @@ gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type) { } case Type_Map: return cg_debug_type(m, t_raw_map); + case Type_Struct: - return cg_debug_type_internal_record(m, type, {}); + case Type_Tuple: case Type_Union: return cg_debug_type_internal_record(m, type, {}); + case Type_Enum: return tb_debug_get_integer(m->mod, is_signed, bits); - case Type_Tuple: - GB_PANIC("SHOULD NEVER HIT"); - break; + case Type_Proc: { TypeProc *pt = &type->Proc; isize param_count = 0; isize return_count = 0; + + bool is_odin_cc = is_calling_convention_odin(pt->calling_convention); + + if (pt->params) for (Entity *e : pt->params->Tuple.variables) { + if (e->kind == Entity_Variable) { + param_count += 1; + } + } + + if (pt->results) { + if (is_odin_cc) { + param_count += pt->result_count-1; + return_count = 1; + } else { + return_count = 1; + } + } + + if (is_odin_cc) { + // `context` ptr + param_count += 1; + } + TB_DebugType *func = tb_debug_create_func(m->mod, TB_CDECL, param_count, return_count, pt->c_vararg); - return func; + TB_DebugType *func_ptr = tb_debug_create_ptr(m->mod, func); + map_set(&m->debug_type_map, original_type, func_ptr); + map_set(&m->debug_type_map, type, func_ptr); + + TB_DebugType **params = tb_debug_func_params(func); + TB_DebugType **returns = tb_debug_func_returns(func); + + isize param_index = 0; + isize return_index = 0; + if (pt->params) for (Entity *e : pt->params->Tuple.variables) { + if (e->kind == Entity_Variable) { + Type *type = e->type; + if (is_type_proc(type)) { + type = t_rawptr; + } + String name = e->token.string; + if (name.len == 0) { + name = str_lit("_"); + } + params[param_index++] = tb_debug_create_field(m->mod, cg_debug_type(m, type), name.len, cast(char const *)name.text, 0); + } + } + + if (pt->results) { + if (is_odin_cc) { + for (isize i = 0; i < pt->results->Tuple.variables.count-1; i++) { + Entity *e = pt->results->Tuple.variables[i]; + GB_ASSERT(e->kind == Entity_Variable); + Type *type = e->type; + if (is_type_proc(e->type)) { + type = t_rawptr; + } + type = alloc_type_pointer(type); + + String name = e->token.string; + if (name.len == 0) { + name = str_lit("_"); + } + params[param_index++] = tb_debug_create_field(m->mod, cg_debug_type(m, type), name.len, cast(char const *)name.text, 0); + } + + Type *last_type = pt->results->Tuple.variables[pt->results->Tuple.variables.count-1]->type; + if (is_type_proc(last_type)) { + last_type = t_rawptr; + } + returns[return_index++] = cg_debug_type(m, last_type); + } else { + returns[return_index++] = cg_debug_type(m, pt->results); + } + } + + GB_ASSERT(param_index == param_count); + GB_ASSERT(return_index == return_count); + + return func_ptr; } break; case Type_BitSet: -- cgit v1.2.3 From d72f8da6d7427641b277d4287a5f163c416da42f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jul 2023 22:37:40 +0100 Subject: Move debug type code its own file --- src/tilde_backend.cpp | 3 + src/tilde_backend.hpp | 1 + src/tilde_debug.cpp | 455 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/tilde_stmt.cpp | 453 ------------------------------------------------- 4 files changed, 459 insertions(+), 453 deletions(-) create mode 100644 src/tilde_debug.cpp (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index 798f51bb3..00e665b62 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -397,6 +397,7 @@ gb_internal cgModule *cg_module_create(Checker *c) { map_init(&m->file_id_map); map_init(&m->debug_type_map); + map_init(&m->proc_debug_type_map); for_array(id, global_files) { @@ -414,6 +415,7 @@ gb_internal void cg_module_destroy(cgModule *m) { array_free(&m->procedures_to_generate); map_destroy(&m->file_id_map); map_destroy(&m->debug_type_map); + map_destroy(&m->proc_debug_type_map); tb_module_destroy(m->mod); } @@ -563,6 +565,7 @@ gb_internal String cg_get_entity_name(cgModule *m, Entity *e) { } #include "tilde_const.cpp" +#include "tilde_debug.cpp" #include "tilde_expr.cpp" #include "tilde_proc.cpp" #include "tilde_stmt.cpp" diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 032229193..4bc0a90fb 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -178,6 +178,7 @@ struct cgModule { RecursiveMutex debug_type_mutex; PtrMap debug_type_map; + PtrMap proc_debug_type_map; // not pointer to PtrMap file_id_map; // Key: AstFile.id (i32 cast to uintptr) diff --git a/src/tilde_debug.cpp b/src/tilde_debug.cpp new file mode 100644 index 000000000..a1ed04aaa --- /dev/null +++ b/src/tilde_debug.cpp @@ -0,0 +1,455 @@ +gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type); +gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type) { + mutex_lock(&m->debug_type_mutex); + defer (mutex_unlock(&m->debug_type_mutex)); + TB_DebugType **found = map_get(&m->debug_type_map, type); + if (found) { + return *found; + } + + TB_DebugType *res = cg_debug_type_internal(m, type); + map_set(&m->debug_type_map, type, res); + return res; +} + +gb_internal TB_DebugType *cg_debug_type_internal_record(cgModule *m, Type *type, String const &record_name) { + Type *bt = base_type(type); + switch (bt->kind) { + case Type_Struct: + { + type_set_offsets(bt); + + TB_DebugType *record = nullptr; + if (bt->Struct.is_raw_union) { + record = tb_debug_create_union(m->mod, record_name.len, cast(char const *)record_name.text); + } else { + record = tb_debug_create_struct(m->mod, record_name.len, cast(char const *)record_name.text); + } + if (record_name.len != 0) { + map_set(&m->debug_type_map, type, record); + } + + TB_DebugType **fields = tb_debug_record_begin(record, bt->Struct.fields.count); + for_array(i, bt->Struct.fields) { + Entity *e = bt->Struct.fields[i]; + Type *type = e->type; + if (is_type_proc(type)) { + type = t_rawptr; + } + TB_DebugType *field_type = cg_debug_type(m, type); + String name = e->token.string; + TB_CharUnits offset = cast(TB_CharUnits)bt->Struct.offsets[i]; + if (name.len == 0) { + name = str_lit("_"); + } + + fields[i] = tb_debug_create_field(m->mod, field_type, name.len, cast(char const *)name.text, offset); + } + tb_debug_record_end( + record, + cast(TB_CharUnits)type_size_of(type), + cast(TB_CharUnits)type_align_of(type) + ); + return record; + } + break; + + case Type_Tuple: + { + GB_ASSERT(record_name.len == 0); + type_set_offsets(bt); + + TB_DebugType *record = tb_debug_create_struct(m->mod, 0, ""); + TB_DebugType **fields = tb_debug_record_begin(record, bt->Tuple.variables.count); + for_array(i, bt->Tuple.variables) { + Entity *e = bt->Tuple.variables[i]; + Type *type = e->type; + if (is_type_proc(type)) { + type = t_rawptr; + } + TB_DebugType *field_type = cg_debug_type(m, type); + String name = e->token.string; + TB_CharUnits offset = cast(TB_CharUnits)bt->Tuple.offsets[i]; + if (name.len == 0) { + name = str_lit("_"); + } + + fields[i] = tb_debug_create_field(m->mod, field_type, name.len, cast(char const *)name.text, offset); + } + tb_debug_record_end( + record, + cast(TB_CharUnits)type_size_of(type), + cast(TB_CharUnits)type_align_of(type) + ); + return record; + } + break; + case Type_Union: + { + TB_DebugType *record = tb_debug_create_struct(m->mod, record_name.len, cast(char const *)record_name.text); + if (record_name.len != 0) { + map_set(&m->debug_type_map, type, record); + } + + i64 variant_count = bt->Union.variants.count; + if (is_type_union_maybe_pointer(bt)) { + // NO TAG + GB_ASSERT(variant_count == 1); + TB_DebugType **fields = tb_debug_record_begin(record, variant_count); + TB_DebugType *variant_type = cg_debug_type(m, bt->Union.variants[0]); + fields[0] = tb_debug_create_field(m->mod, variant_type, -1, "v0", 0); + tb_debug_record_end( + record, + cast(TB_CharUnits)type_size_of(type), + cast(TB_CharUnits)type_align_of(type) + ); + } else { + TB_DebugType **fields = tb_debug_record_begin(record, variant_count+1); + for_array(i, bt->Union.variants) { + Type *v = bt->Union.variants[i]; + TB_DebugType *variant_type = cg_debug_type(m, v); + char name[32] = {}; + u32 v_index = cast(u32)i; + if (bt->Union.kind != UnionType_no_nil) { + v_index += 1; + } + gb_snprintf(name, 31, "v%u", v_index); + fields[i] = tb_debug_create_field(m->mod, variant_type, -1, name, 0); + } + + TB_DebugType *tag_type = cg_debug_type(m, union_tag_type(bt)); + fields[variant_count] = tb_debug_create_field(m->mod, tag_type, -1, "tag", cast(TB_CharUnits)bt->Union.variant_block_size); + + } + tb_debug_record_end( + record, + cast(TB_CharUnits)type_size_of(type), + cast(TB_CharUnits)type_align_of(type) + ); + return record; + } + break; + } + return nullptr; +} + + +gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type) { + if (type == nullptr) { + return tb_debug_get_void(m->mod); + } + Type *original_type = type; + if (type->kind == Type_Named) { + String name = type->Named.name; + TB_DebugType *res = cg_debug_type_internal_record(m, type, name); + if (res) { + return res; + } + type = base_type(type->Named.base); + } + + TB_CharUnits int_size = cast(TB_CharUnits)build_context.int_size; + TB_CharUnits ptr_size = cast(TB_CharUnits)build_context.ptr_size; + TB_CharUnits size = cast(TB_CharUnits)type_size_of(type); + TB_CharUnits align = cast(TB_CharUnits)type_align_of(type); + int bits = cast(int)(8*size); + bool is_signed = is_type_integer(core_type(type)) && !is_type_unsigned(core_type(type)); + + switch (type->kind) { + case Type_Basic: + switch (type->Basic.kind) { + case Basic_bool: return tb_debug_get_bool(m->mod); + case Basic_b8: return tb_debug_get_bool(m->mod); + case Basic_b16: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_b32: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_b64: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i8: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u8: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i16: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u16: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i32: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u32: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i64: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u64: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i128: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_u128: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_rune: return tb_debug_get_integer(m->mod, is_signed, bits); + + case Basic_f16: return tb_debug_get_integer(m->mod, false, bits); + case Basic_f32: return tb_debug_get_float(m->mod, TB_FLT_32); + case Basic_f64: return tb_debug_get_float(m->mod,TB_FLT_64); + + case Basic_complex32: + case Basic_complex64: + case Basic_complex128: + { + String name = basic_types[type->Basic.kind].Basic.name; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + Type *et = base_complex_elem_type(type); + TB_CharUnits elem_size = cast(TB_CharUnits)type_size_of(et); + TB_DebugType *elem = cg_debug_type(m, et); + + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, elem, -1, "real", 0*elem_size); + fields[1] = tb_debug_create_field(m->mod, elem, -1, "imag", 1*elem_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Basic_quaternion64: + case Basic_quaternion128: + case Basic_quaternion256: + { + String name = basic_types[type->Basic.kind].Basic.name; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + Type *et = base_complex_elem_type(type); + TB_CharUnits elem_size = cast(TB_CharUnits)type_size_of(et); + TB_DebugType *elem = cg_debug_type(m, et); + + // @QuaternionLayout + TB_DebugType **fields = tb_debug_record_begin(record, 4); + fields[0] = tb_debug_create_field(m->mod, elem, -1, "imag", 0*elem_size); + fields[1] = tb_debug_create_field(m->mod, elem, -1, "jmag", 1*elem_size); + fields[2] = tb_debug_create_field(m->mod, elem, -1, "kmag", 2*elem_size); + fields[3] = tb_debug_create_field(m->mod, elem, -1, "real", 3*elem_size); + + tb_debug_record_end(record, size, align); + return record; + } + + case Basic_int: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_uint: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_uintptr: return tb_debug_get_integer(m->mod, is_signed, bits); + + case Basic_rawptr: return tb_debug_create_ptr(m->mod, tb_debug_get_void(m->mod)); + case Basic_string: + { + String name = basic_types[type->Basic.kind].Basic.name; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + // @QuaternionLayout + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, t_u8_ptr), -1, "data", 0*int_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Basic_cstring: + return tb_debug_create_ptr(m->mod, tb_debug_get_integer(m->mod, false, 8)); + + case Basic_any: + { + String name = basic_types[type->Basic.kind].Basic.name; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + // @QuaternionLayout + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, t_rawptr), -1, "data", 0*ptr_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_typeid), -1, "id", 1*ptr_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Basic_typeid: return tb_debug_get_integer(m->mod, is_signed, bits); + + case Basic_i16le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u16le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i32le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u32le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i64le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u64le: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i128le: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_u128le: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_i16be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u16be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i32be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u32be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i64be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_u64be: return tb_debug_get_integer(m->mod, is_signed, bits); + case Basic_i128be: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + case Basic_u128be: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); + + case Basic_f16le: return tb_debug_get_integer(m->mod, false, bits); + case Basic_f32le: return tb_debug_get_float(m->mod, TB_FLT_32); + case Basic_f64le: return tb_debug_get_float(m->mod,TB_FLT_64); + case Basic_f16be: return tb_debug_get_integer(m->mod, false, bits); + case Basic_f32be: return tb_debug_get_float(m->mod, TB_FLT_32); + case Basic_f64be: return tb_debug_get_float(m->mod,TB_FLT_64); + } + break; + case Type_Generic: + GB_PANIC("SHOULD NEVER HIT"); + break; + case Type_Pointer: + return tb_debug_create_ptr(m->mod, cg_debug_type(m, type->Pointer.elem)); + case Type_MultiPointer: + return tb_debug_create_ptr(m->mod, cg_debug_type(m, type->MultiPointer.elem)); + case Type_Array: + return tb_debug_create_array(m->mod, cg_debug_type(m, type->Array.elem), type->Array.count); + case Type_EnumeratedArray: + return tb_debug_create_array(m->mod, cg_debug_type(m, type->EnumeratedArray.elem), type->EnumeratedArray.count); + case Type_Slice: + { + String name = {}; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->Slice.elem)), -1, "data", 0*int_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Type_DynamicArray: + { + String name = {}; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + TB_DebugType **fields = tb_debug_record_begin(record, 4); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->Slice.elem)), -1, "data", 0*int_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); + fields[2] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "cap", 2*int_size); + fields[3] = tb_debug_create_field(m->mod, cg_debug_type(m, t_allocator), -1, "allocator", 3*int_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Type_Map: + return cg_debug_type(m, t_raw_map); + + case Type_Struct: + case Type_Tuple: + case Type_Union: + return cg_debug_type_internal_record(m, type, {}); + + case Type_Enum: + return tb_debug_get_integer(m->mod, is_signed, bits); + + case Type_Proc: + { + TypeProc *pt = &type->Proc; + isize param_count = 0; + isize return_count = 0; + + bool is_odin_cc = is_calling_convention_odin(pt->calling_convention); + + if (pt->params) for (Entity *e : pt->params->Tuple.variables) { + if (e->kind == Entity_Variable) { + param_count += 1; + } + } + + if (pt->results) { + if (is_odin_cc) { + param_count += pt->result_count-1; + return_count = 1; + } else { + return_count = 1; + } + } + + if (is_odin_cc) { + // `context` ptr + param_count += 1; + } + + TB_DebugType *func = tb_debug_create_func(m->mod, TB_CDECL, param_count, return_count, pt->c_vararg); + + map_set(&m->proc_debug_type_map, original_type, func); + map_set(&m->proc_debug_type_map, type, func); + + TB_DebugType *func_ptr = tb_debug_create_ptr(m->mod, func); + map_set(&m->debug_type_map, original_type, func_ptr); + map_set(&m->debug_type_map, type, func_ptr); + + TB_DebugType **params = tb_debug_func_params(func); + TB_DebugType **returns = tb_debug_func_returns(func); + + isize param_index = 0; + isize return_index = 0; + if (pt->params) for (Entity *e : pt->params->Tuple.variables) { + if (e->kind == Entity_Variable) { + Type *type = e->type; + if (is_type_proc(type)) { + type = t_rawptr; + } + String name = e->token.string; + if (name.len == 0) { + name = str_lit("_"); + } + params[param_index++] = tb_debug_create_field(m->mod, cg_debug_type(m, type), name.len, cast(char const *)name.text, 0); + } + } + + if (pt->results) { + if (is_odin_cc) { + for (isize i = 0; i < pt->results->Tuple.variables.count-1; i++) { + Entity *e = pt->results->Tuple.variables[i]; + GB_ASSERT(e->kind == Entity_Variable); + Type *type = e->type; + if (is_type_proc(e->type)) { + type = t_rawptr; + } + type = alloc_type_pointer(type); + + String name = e->token.string; + if (name.len == 0) { + name = str_lit("_"); + } + params[param_index++] = tb_debug_create_field(m->mod, cg_debug_type(m, type), name.len, cast(char const *)name.text, 0); + } + + Type *last_type = pt->results->Tuple.variables[pt->results->Tuple.variables.count-1]->type; + if (is_type_proc(last_type)) { + last_type = t_rawptr; + } + returns[return_index++] = cg_debug_type(m, last_type); + } else { + returns[return_index++] = cg_debug_type(m, pt->results); + } + } + + GB_ASSERT(param_index == param_count); + GB_ASSERT(return_index == return_count); + + return func_ptr; + } + break; + case Type_BitSet: + return cg_debug_type(m, bit_set_to_int(type)); + case Type_SimdVector: + return tb_debug_create_array(m->mod, cg_debug_type(m, type->SimdVector.elem), type->SimdVector.count); + case Type_RelativePointer: + return cg_debug_type(m, type->RelativePointer.base_integer); + case Type_RelativeSlice: + { + String name = {}; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + + TB_DebugType *base_integer = cg_debug_type(m, type->RelativeSlice.base_integer); + TB_CharUnits bi_size = cast(TB_CharUnits)type_size_of(type->RelativeSlice.base_integer); + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, base_integer, -1, "data", 0*bi_size); + fields[1] = tb_debug_create_field(m->mod, base_integer, -1, "len", 1*bi_size); + + tb_debug_record_end(record, size, align); + return record; + } + case Type_Matrix: + { + i64 count = matrix_type_total_internal_elems(type); + return tb_debug_create_array(m->mod, cg_debug_type(m, type->Matrix.elem), count); + } + case Type_SoaPointer: + { + String name = {}; + TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); + TB_DebugType **fields = tb_debug_record_begin(record, 2); + fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->SoaPointer.elem)), -1, "ptr", 0*int_size); + fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "offset", 1*int_size); + + tb_debug_record_end(record, size, align); + return record; + } + } + + // TODO(bill): cg_debug_type + return tb_debug_get_void(m->mod); +} diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index dc6819b89..afc915115 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -628,459 +628,6 @@ gb_internal cgTargetList *cg_push_target_list(cgProcedure *p, Ast *label, TB_Nod gb_internal void cg_pop_target_list(cgProcedure *p) { p->target_list = p->target_list->prev; } - -gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type); -gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type) { - mutex_lock(&m->debug_type_mutex); - defer (mutex_unlock(&m->debug_type_mutex)); - TB_DebugType **found = map_get(&m->debug_type_map, type); - if (found) { - return *found; - } - - TB_DebugType *res = cg_debug_type_internal(m, type); - map_set(&m->debug_type_map, type, res); - return res; -} - -gb_internal TB_DebugType *cg_debug_type_internal_record(cgModule *m, Type *type, String const &record_name) { - Type *bt = base_type(type); - switch (bt->kind) { - case Type_Struct: - { - type_set_offsets(bt); - - TB_DebugType *record = nullptr; - if (bt->Struct.is_raw_union) { - record = tb_debug_create_union(m->mod, record_name.len, cast(char const *)record_name.text); - } else { - record = tb_debug_create_struct(m->mod, record_name.len, cast(char const *)record_name.text); - } - if (record_name.len != 0) { - map_set(&m->debug_type_map, type, record); - } - - TB_DebugType **fields = tb_debug_record_begin(record, bt->Struct.fields.count); - for_array(i, bt->Struct.fields) { - Entity *e = bt->Struct.fields[i]; - Type *type = e->type; - if (is_type_proc(type)) { - type = t_rawptr; - } - TB_DebugType *field_type = cg_debug_type(m, type); - String name = e->token.string; - TB_CharUnits offset = cast(TB_CharUnits)bt->Struct.offsets[i]; - if (name.len == 0) { - name = str_lit("_"); - } - - fields[i] = tb_debug_create_field(m->mod, field_type, name.len, cast(char const *)name.text, offset); - } - tb_debug_record_end( - record, - cast(TB_CharUnits)type_size_of(type), - cast(TB_CharUnits)type_align_of(type) - ); - return record; - } - break; - - case Type_Tuple: - { - GB_ASSERT(record_name.len == 0); - type_set_offsets(bt); - - TB_DebugType *record = tb_debug_create_struct(m->mod, 0, ""); - TB_DebugType **fields = tb_debug_record_begin(record, bt->Tuple.variables.count); - for_array(i, bt->Tuple.variables) { - Entity *e = bt->Tuple.variables[i]; - Type *type = e->type; - if (is_type_proc(type)) { - type = t_rawptr; - } - TB_DebugType *field_type = cg_debug_type(m, type); - String name = e->token.string; - TB_CharUnits offset = cast(TB_CharUnits)bt->Tuple.offsets[i]; - if (name.len == 0) { - name = str_lit("_"); - } - - fields[i] = tb_debug_create_field(m->mod, field_type, name.len, cast(char const *)name.text, offset); - } - tb_debug_record_end( - record, - cast(TB_CharUnits)type_size_of(type), - cast(TB_CharUnits)type_align_of(type) - ); - return record; - } - break; - case Type_Union: - { - TB_DebugType *record = tb_debug_create_struct(m->mod, record_name.len, cast(char const *)record_name.text); - if (record_name.len != 0) { - map_set(&m->debug_type_map, type, record); - } - - i64 variant_count = bt->Union.variants.count; - if (is_type_union_maybe_pointer(bt)) { - // NO TAG - GB_ASSERT(variant_count == 1); - TB_DebugType **fields = tb_debug_record_begin(record, variant_count); - TB_DebugType *variant_type = cg_debug_type(m, bt->Union.variants[0]); - fields[0] = tb_debug_create_field(m->mod, variant_type, -1, "v0", 0); - tb_debug_record_end( - record, - cast(TB_CharUnits)type_size_of(type), - cast(TB_CharUnits)type_align_of(type) - ); - } else { - TB_DebugType **fields = tb_debug_record_begin(record, variant_count+1); - for_array(i, bt->Union.variants) { - Type *v = bt->Union.variants[i]; - TB_DebugType *variant_type = cg_debug_type(m, v); - char name[32] = {}; - u32 v_index = cast(u32)i; - if (bt->Union.kind != UnionType_no_nil) { - v_index += 1; - } - gb_snprintf(name, 31, "v%u", v_index); - fields[i] = tb_debug_create_field(m->mod, variant_type, -1, name, 0); - } - - TB_DebugType *tag_type = cg_debug_type(m, union_tag_type(bt)); - fields[variant_count] = tb_debug_create_field(m->mod, tag_type, -1, "tag", cast(TB_CharUnits)bt->Union.variant_block_size); - - } - tb_debug_record_end( - record, - cast(TB_CharUnits)type_size_of(type), - cast(TB_CharUnits)type_align_of(type) - ); - return record; - } - break; - } - return nullptr; -} - - -gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type) { - if (type == nullptr) { - return tb_debug_get_void(m->mod); - } - Type *original_type = type; - if (type->kind == Type_Named) { - String name = type->Named.name; - TB_DebugType *res = cg_debug_type_internal_record(m, type, name); - if (res) { - return res; - } - type = base_type(type->Named.base); - } - - TB_CharUnits int_size = cast(TB_CharUnits)build_context.int_size; - TB_CharUnits ptr_size = cast(TB_CharUnits)build_context.ptr_size; - TB_CharUnits size = cast(TB_CharUnits)type_size_of(type); - TB_CharUnits align = cast(TB_CharUnits)type_align_of(type); - int bits = cast(int)(8*size); - bool is_signed = is_type_integer(core_type(type)) && !is_type_unsigned(core_type(type)); - - switch (type->kind) { - case Type_Basic: - switch (type->Basic.kind) { - case Basic_bool: return tb_debug_get_bool(m->mod); - case Basic_b8: return tb_debug_get_bool(m->mod); - case Basic_b16: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_b32: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_b64: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i8: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u8: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i16: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u16: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i32: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u32: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i64: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u64: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i128: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); - case Basic_u128: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); - case Basic_rune: return tb_debug_get_integer(m->mod, is_signed, bits); - - case Basic_f16: return tb_debug_get_integer(m->mod, false, bits); - case Basic_f32: return tb_debug_get_float(m->mod, TB_FLT_32); - case Basic_f64: return tb_debug_get_float(m->mod,TB_FLT_64); - - case Basic_complex32: - case Basic_complex64: - case Basic_complex128: - { - String name = basic_types[type->Basic.kind].Basic.name; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - Type *et = base_complex_elem_type(type); - TB_CharUnits elem_size = cast(TB_CharUnits)type_size_of(et); - TB_DebugType *elem = cg_debug_type(m, et); - - TB_DebugType **fields = tb_debug_record_begin(record, 2); - fields[0] = tb_debug_create_field(m->mod, elem, -1, "real", 0*elem_size); - fields[1] = tb_debug_create_field(m->mod, elem, -1, "imag", 1*elem_size); - - tb_debug_record_end(record, size, align); - return record; - } - case Basic_quaternion64: - case Basic_quaternion128: - case Basic_quaternion256: - { - String name = basic_types[type->Basic.kind].Basic.name; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - Type *et = base_complex_elem_type(type); - TB_CharUnits elem_size = cast(TB_CharUnits)type_size_of(et); - TB_DebugType *elem = cg_debug_type(m, et); - - // @QuaternionLayout - TB_DebugType **fields = tb_debug_record_begin(record, 4); - fields[0] = tb_debug_create_field(m->mod, elem, -1, "imag", 0*elem_size); - fields[1] = tb_debug_create_field(m->mod, elem, -1, "jmag", 1*elem_size); - fields[2] = tb_debug_create_field(m->mod, elem, -1, "kmag", 2*elem_size); - fields[3] = tb_debug_create_field(m->mod, elem, -1, "real", 3*elem_size); - - tb_debug_record_end(record, size, align); - return record; - } - - case Basic_int: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_uint: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_uintptr: return tb_debug_get_integer(m->mod, is_signed, bits); - - case Basic_rawptr: return tb_debug_create_ptr(m->mod, tb_debug_get_void(m->mod)); - case Basic_string: - { - String name = basic_types[type->Basic.kind].Basic.name; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - // @QuaternionLayout - TB_DebugType **fields = tb_debug_record_begin(record, 2); - fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, t_u8_ptr), -1, "data", 0*int_size); - fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); - - tb_debug_record_end(record, size, align); - return record; - } - case Basic_cstring: - return tb_debug_create_ptr(m->mod, tb_debug_get_integer(m->mod, false, 8)); - - case Basic_any: - { - String name = basic_types[type->Basic.kind].Basic.name; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - // @QuaternionLayout - TB_DebugType **fields = tb_debug_record_begin(record, 2); - fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, t_rawptr), -1, "data", 0*ptr_size); - fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_typeid), -1, "id", 1*ptr_size); - - tb_debug_record_end(record, size, align); - return record; - } - case Basic_typeid: return tb_debug_get_integer(m->mod, is_signed, bits); - - case Basic_i16le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u16le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i32le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u32le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i64le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u64le: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i128le: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); - case Basic_u128le: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); - case Basic_i16be: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u16be: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i32be: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u32be: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i64be: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_u64be: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_i128be: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); - case Basic_u128be: return tb_debug_get_integer(m->mod, is_signed, 64/*bits*/); - - case Basic_f16le: return tb_debug_get_integer(m->mod, false, bits); - case Basic_f32le: return tb_debug_get_float(m->mod, TB_FLT_32); - case Basic_f64le: return tb_debug_get_float(m->mod,TB_FLT_64); - case Basic_f16be: return tb_debug_get_integer(m->mod, false, bits); - case Basic_f32be: return tb_debug_get_float(m->mod, TB_FLT_32); - case Basic_f64be: return tb_debug_get_float(m->mod,TB_FLT_64); - } - break; - case Type_Generic: - GB_PANIC("SHOULD NEVER HIT"); - break; - case Type_Pointer: - return tb_debug_create_ptr(m->mod, cg_debug_type(m, type->Pointer.elem)); - case Type_MultiPointer: - return tb_debug_create_ptr(m->mod, cg_debug_type(m, type->MultiPointer.elem)); - case Type_Array: - return tb_debug_create_array(m->mod, cg_debug_type(m, type->Array.elem), type->Array.count); - case Type_EnumeratedArray: - return tb_debug_create_array(m->mod, cg_debug_type(m, type->EnumeratedArray.elem), type->EnumeratedArray.count); - case Type_Slice: - { - String name = {}; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - TB_DebugType **fields = tb_debug_record_begin(record, 2); - fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->Slice.elem)), -1, "data", 0*int_size); - fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); - - tb_debug_record_end(record, size, align); - return record; - } - case Type_DynamicArray: - { - String name = {}; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - TB_DebugType **fields = tb_debug_record_begin(record, 4); - fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->Slice.elem)), -1, "data", 0*int_size); - fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "len", 1*int_size); - fields[2] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "cap", 2*int_size); - fields[3] = tb_debug_create_field(m->mod, cg_debug_type(m, t_allocator), -1, "allocator", 3*int_size); - - tb_debug_record_end(record, size, align); - return record; - } - case Type_Map: - return cg_debug_type(m, t_raw_map); - - case Type_Struct: - case Type_Tuple: - case Type_Union: - return cg_debug_type_internal_record(m, type, {}); - - case Type_Enum: - return tb_debug_get_integer(m->mod, is_signed, bits); - - case Type_Proc: - { - TypeProc *pt = &type->Proc; - isize param_count = 0; - isize return_count = 0; - - bool is_odin_cc = is_calling_convention_odin(pt->calling_convention); - - if (pt->params) for (Entity *e : pt->params->Tuple.variables) { - if (e->kind == Entity_Variable) { - param_count += 1; - } - } - - if (pt->results) { - if (is_odin_cc) { - param_count += pt->result_count-1; - return_count = 1; - } else { - return_count = 1; - } - } - - if (is_odin_cc) { - // `context` ptr - param_count += 1; - } - - TB_DebugType *func = tb_debug_create_func(m->mod, TB_CDECL, param_count, return_count, pt->c_vararg); - TB_DebugType *func_ptr = tb_debug_create_ptr(m->mod, func); - map_set(&m->debug_type_map, original_type, func_ptr); - map_set(&m->debug_type_map, type, func_ptr); - - TB_DebugType **params = tb_debug_func_params(func); - TB_DebugType **returns = tb_debug_func_returns(func); - - isize param_index = 0; - isize return_index = 0; - if (pt->params) for (Entity *e : pt->params->Tuple.variables) { - if (e->kind == Entity_Variable) { - Type *type = e->type; - if (is_type_proc(type)) { - type = t_rawptr; - } - String name = e->token.string; - if (name.len == 0) { - name = str_lit("_"); - } - params[param_index++] = tb_debug_create_field(m->mod, cg_debug_type(m, type), name.len, cast(char const *)name.text, 0); - } - } - - if (pt->results) { - if (is_odin_cc) { - for (isize i = 0; i < pt->results->Tuple.variables.count-1; i++) { - Entity *e = pt->results->Tuple.variables[i]; - GB_ASSERT(e->kind == Entity_Variable); - Type *type = e->type; - if (is_type_proc(e->type)) { - type = t_rawptr; - } - type = alloc_type_pointer(type); - - String name = e->token.string; - if (name.len == 0) { - name = str_lit("_"); - } - params[param_index++] = tb_debug_create_field(m->mod, cg_debug_type(m, type), name.len, cast(char const *)name.text, 0); - } - - Type *last_type = pt->results->Tuple.variables[pt->results->Tuple.variables.count-1]->type; - if (is_type_proc(last_type)) { - last_type = t_rawptr; - } - returns[return_index++] = cg_debug_type(m, last_type); - } else { - returns[return_index++] = cg_debug_type(m, pt->results); - } - } - - GB_ASSERT(param_index == param_count); - GB_ASSERT(return_index == return_count); - - return func_ptr; - } - break; - case Type_BitSet: - return cg_debug_type(m, bit_set_to_int(type)); - case Type_SimdVector: - return tb_debug_create_array(m->mod, cg_debug_type(m, type->SimdVector.elem), type->SimdVector.count); - case Type_RelativePointer: - return cg_debug_type(m, type->RelativePointer.base_integer); - case Type_RelativeSlice: - { - String name = {}; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - - TB_DebugType *base_integer = cg_debug_type(m, type->RelativeSlice.base_integer); - TB_CharUnits bi_size = cast(TB_CharUnits)type_size_of(type->RelativeSlice.base_integer); - TB_DebugType **fields = tb_debug_record_begin(record, 2); - fields[0] = tb_debug_create_field(m->mod, base_integer, -1, "data", 0*bi_size); - fields[1] = tb_debug_create_field(m->mod, base_integer, -1, "len", 1*bi_size); - - tb_debug_record_end(record, size, align); - return record; - } - case Type_Matrix: - { - i64 count = matrix_type_total_internal_elems(type); - return tb_debug_create_array(m->mod, cg_debug_type(m, type->Matrix.elem), count); - } - case Type_SoaPointer: - { - String name = {}; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - TB_DebugType **fields = tb_debug_record_begin(record, 2); - fields[0] = tb_debug_create_field(m->mod, cg_debug_type(m, alloc_type_pointer(type->SoaPointer.elem)), -1, "ptr", 0*int_size); - fields[1] = tb_debug_create_field(m->mod, cg_debug_type(m, t_int), -1, "offset", 1*int_size); - - tb_debug_record_end(record, size, align); - return record; - } - } - - // TODO(bill): cg_debug_type - return tb_debug_get_void(m->mod); -} - gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init) { GB_ASSERT(type != nullptr); -- cgit v1.2.3 From 55733171c19aa53aebbe343d7541c3c5a1597c46 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 17 Jul 2023 23:16:50 +0100 Subject: Planning for multi-valued expressions in the tilde backend --- src/tilde_backend.cpp | 13 +++++++++++++ src/tilde_backend.hpp | 9 +++++++++ src/tilde_expr.cpp | 4 ++++ src/tilde_proc.cpp | 9 ++++----- src/tilde_stmt.cpp | 15 +++++++++++++++ 5 files changed, 45 insertions(+), 5 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index 00e665b62..97f2dcccd 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -118,7 +118,20 @@ gb_internal cgValue cg_lvalue_addr(TB_Node *node, Type *type) { return v; } +gb_internal cgValue cg_value_multi(cgValueMultiNodes *multi_nodes, Type *type) { + GB_ASSERT(type->kind == Type_Tuple); + GB_ASSERT(multi_nodes != nullptr); + GB_ASSERT(type->Tuple.variables.count > 1); + GB_ASSERT(multi_nodes->nodes.count == type->Tuple.variables.count); + cgValue v = {}; + v.kind = cgValue_Multi; + v.type = type; + v.multi_nodes = multi_nodes; + return v; +} + gb_internal cgAddr cg_addr(cgValue const &value) { + GB_ASSERT(value.kind != cgValue_Multi); cgAddr addr = {}; addr.kind = cgAddr_Default; addr.addr = value; diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 9e88cb4c7..54d84302d 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -34,6 +34,11 @@ enum cgValueKind : u32 { cgValue_Value, cgValue_Addr, cgValue_Symbol, + cgValue_Multi, +}; + +struct cgValueMultiNodes { + Slice nodes; }; struct cgValue { @@ -42,6 +47,7 @@ struct cgValue { union { TB_Symbol *symbol; TB_Node * node; + cgValueMultiNodes *multi_nodes; }; }; @@ -132,6 +138,9 @@ struct cgProcedure { TB_FunctionPrototype *proto; TB_Symbol *symbol; + // includes parameters, pointers to return values, and context ptr + Slice param_nodes; + Entity * entity; cgModule *module; String name; diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 4e43089b2..473baf763 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -1,4 +1,5 @@ gb_internal cgValue cg_flatten_value(cgProcedure *p, cgValue value) { + GB_ASSERT(value.kind != cgValue_Multi); if (value.kind == cgValue_Symbol) { GB_ASSERT(is_type_internally_pointer_like(value.type)); value = cg_value(tb_inst_get_symbol_address(p->func, value.symbol), value.type); @@ -152,6 +153,9 @@ gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type) case cgValue_Symbol: GB_PANIC("should be handled above"); break; + case cgValue_Multi: + GB_PANIC("cannot transmute multiple values at once"); + break; } return value; diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 078c2ef9c..d08f611fc 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -333,7 +333,7 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i size_t out_param_count = 0; p->debug_type = cg_debug_type_for_proc(m, p->type); TB_Node **params = tb_function_set_prototype_from_dbg(p->func, p->debug_type, arena, &out_param_count); - gb_unused(params); + p->param_nodes = {params, cast(isize)out_param_count}; p->proto = tb_function_get_prototype(p->func); p->symbol = cast(TB_Symbol *)p->func; @@ -387,7 +387,7 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li size_t out_param_count = 0; p->debug_type = cg_debug_type_for_proc(m, p->type); TB_Node **params = tb_function_set_prototype_from_dbg(p->func, p->debug_type, arena, &out_param_count); - gb_unused(params); + p->param_nodes = {params, cast(isize)out_param_count}; p->proto = tb_function_get_prototype(p->func); @@ -420,12 +420,11 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { continue; } - if (param_index >= p->proto->param_count) { + if (param_index >= p->param_nodes.count) { break; } - // TB_Node *ptr = tb_inst_param_addr(p->func, param_index); - TB_Node *param = tb_inst_param(p->func, param_index++); + TB_Node *param = p->param_nodes[param_index++]; TB_Node *ptr = tb_inst_local(p->func, cast(TB_CharUnits)type_size_of(e->type), cast(TB_CharUnits)type_align_of(e->type)); TB_DataType dt = cg_data_type(e->type); tb_inst_store(p->func, dt, ptr, param, cast(TB_CharUnits)type_align_of(e->type), false); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index afc915115..6680277ed 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -10,6 +10,9 @@ gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_vol case cgValue_Addr: GB_PANIC("NOT POSSIBLE - Cannot load an lvalue to begin with"); break; + case cgValue_Multi: + GB_PANIC("NOT POSSIBLE - Cannot load multiple values at once"); + break; case cgValue_Symbol: return cg_lvalue_addr(tb_inst_get_symbol_address(p->func, ptr.symbol), type); } @@ -27,6 +30,9 @@ gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_vol case cgValue_Addr: the_ptr = tb_inst_load(p->func, TB_TYPE_PTR, ptr.node, alignment, is_volatile); break; + case cgValue_Multi: + GB_PANIC("NOT POSSIBLE - Cannot load multiple values at once"); + break; case cgValue_Symbol: the_ptr = tb_inst_get_symbol_address(p->func, ptr.symbol); break; @@ -35,6 +41,8 @@ gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_vol } gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile) { + GB_ASSERT_MSG(dst.kind != cgValue_Multi, "cannot store to multiple values at once"); + if (dst.kind == cgValue_Addr) { dst = cg_emit_load(p, dst, is_volatile); } else if (dst.kind == cgValue_Symbol) { @@ -130,6 +138,9 @@ gb_internal cgValue cg_address_from_load(cgProcedure *p, cgValue value) { case cgValue_Symbol: GB_PANIC("Symbol is an invalid use case for cg_address_from_load"); return {}; + case cgValue_Multi: + GB_PANIC("Multi is an invalid use case for cg_address_from_load"); + break; } GB_PANIC("Invalid cgValue for cg_address_from_load"); return {}; @@ -143,6 +154,8 @@ gb_internal bool cg_addr_is_empty(cgAddr const &addr) { return addr.addr.node == nullptr; case cgValue_Symbol: return addr.addr.symbol == nullptr; + case cgValue_Multi: + return addr.addr.multi_nodes == nullptr; } return true; } @@ -670,6 +683,8 @@ gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgVal break; case cgValue_Addr: return cg_value(value.node, alloc_type_pointer(value.type)); + case cgValue_Multi: + GB_PANIC("cgValue_Multi not allowed"); } cgAddr res = cg_add_local(p, value.type, nullptr, false); -- cgit v1.2.3 From c6593e8cdee3bbe3057be7a4728db3293265b663 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Jul 2023 13:27:47 +0100 Subject: Mock out binary expressions and variable declarations --- src/tilde_expr.cpp | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tilde_proc.cpp | 3 +- src/tilde_stmt.cpp | 25 +++++++- 3 files changed, 206 insertions(+), 4 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 473baf763..33a1b5379 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -7,6 +7,19 @@ gb_internal cgValue cg_flatten_value(cgProcedure *p, cgValue value) { return value; } +gb_internal bool cg_is_expr_untyped_const(Ast *expr) { + auto const &tv = type_and_value_of_expr(expr); + if (is_type_untyped(tv.type)) { + return tv.value.kind != ExactValue_Invalid; + } + return false; +} +gb_internal cgValue cg_expr_untyped_const_to_typed(cgProcedure *p, Ast *expr, Type *t) { + GB_ASSERT(is_type_typed(t)); + auto const &tv = type_and_value_of_expr(expr); + return cg_const_value(p, t, tv.value); +} + gb_internal cgContextData *cg_push_context_onto_stack(cgProcedure *p, cgAddr ctx) { ctx.kind = cgAddr_Context; cgContextData *cd = array_add_and_get(&p->context_stack); @@ -909,7 +922,173 @@ gb_internal cgAddr cg_build_addr_slice_expr(cgProcedure *p, Ast *expr) { return {}; } +gb_internal cgValue cg_build_binary_expr(cgProcedure *p, Ast *expr) { + ast_node(be, BinaryExpr, expr); + + TypeAndValue tv = type_and_value_of_expr(expr); + + if (is_type_matrix(be->left->tav.type) || is_type_matrix(be->right->tav.type)) { + cgValue left = cg_build_expr(p, be->left); + cgValue right = cg_build_expr(p, be->right); + GB_PANIC("TODO(bill): cg_emit_arith_matrix"); + // return cg_emit_arith_matrix(p, be->op.kind, left, right, default_type(tv.type), false); + } + + + switch (be->op.kind) { + case Token_Add: + case Token_Sub: + case Token_Mul: + case Token_Quo: + case Token_Mod: + case Token_ModMod: + case Token_And: + case Token_Or: + case Token_Xor: + case Token_AndNot: { + Type *type = default_type(tv.type); + cgValue left = cg_build_expr(p, be->left); + cgValue right = cg_build_expr(p, be->right); + return cg_emit_arith(p, be->op.kind, left, right, type); + } + + case Token_Shl: + case Token_Shr: { + cgValue left, right; + Type *type = default_type(tv.type); + left = cg_build_expr(p, be->left); + + if (cg_is_expr_untyped_const(be->right)) { + // NOTE(bill): RHS shift operands can still be untyped + // Just bypass the standard cg_build_expr + right = cg_expr_untyped_const_to_typed(p, be->right, type); + } else { + right = cg_build_expr(p, be->right); + } + return cg_emit_arith(p, be->op.kind, left, right, type); + } + + case Token_CmpEq: + case Token_NotEq: + GB_PANIC("TODO(bill): comparisons"); + // if (is_type_untyped_nil(be->right->tav.type)) { + // // `x == nil` or `x != nil` + // cgValue left = cg_build_expr(p, be->left); + // cgValue cmp = cg_emit_comp_against_nil(p, be->op.kind, left); + // Type *type = default_type(tv.type); + // return cg_emit_conv(p, cmp, type); + // } else if (is_type_untyped_nil(be->left->tav.type)) { + // // `nil == x` or `nil != x` + // cgValue right = cg_build_expr(p, be->right); + // cgValue cmp = cg_emit_comp_against_nil(p, be->op.kind, right); + // Type *type = default_type(tv.type); + // return cg_emit_conv(p, cmp, type); + // } else if (cg_is_empty_string_constant(be->right)) { + // // `x == ""` or `x != ""` + // cgValue s = cg_build_expr(p, be->left); + // s = cg_emit_conv(p, s, t_string); + // cgValue len = cg_string_len(p, s); + // cgValue cmp = cg_emit_comp(p, be->op.kind, len, cg_const_int(p->module, t_int, 0)); + // Type *type = default_type(tv.type); + // return cg_emit_conv(p, cmp, type); + // } else if (cg_is_empty_string_constant(be->left)) { + // // `"" == x` or `"" != x` + // cgValue s = cg_build_expr(p, be->right); + // s = cg_emit_conv(p, s, t_string); + // cgValue len = cg_string_len(p, s); + // cgValue cmp = cg_emit_comp(p, be->op.kind, len, cg_const_int(p->module, t_int, 0)); + // Type *type = default_type(tv.type); + // return cg_emit_conv(p, cmp, type); + // } + /*fallthrough*/ + case Token_Lt: + case Token_LtEq: + case Token_Gt: + case Token_GtEq: + { + cgValue left = {}; + cgValue right = {}; + + if (be->left->tav.mode == Addressing_Type) { + left = cg_typeid(p->module, be->left->tav.type); + } + if (be->right->tav.mode == Addressing_Type) { + right = cg_typeid(p->module, be->right->tav.type); + } + if (left.node == nullptr) left = cg_build_expr(p, be->left); + if (right.node == nullptr) right = cg_build_expr(p, be->right); + GB_PANIC("TODO(bill): cg_emit_comp"); + // cgValue cmp = cg_emit_comp(p, be->op.kind, left, right); + // Type *type = default_type(tv.type); + // return cg_emit_conv(p, cmp, type); + } + case Token_CmpAnd: + case Token_CmpOr: + GB_PANIC("TODO(bill): cg_emit_logical_binary_expr"); + // return cg_emit_logical_binary_expr(p, be->op.kind, be->left, be->right, tv.type); + + case Token_in: + case Token_not_in: + { + cgValue left = cg_build_expr(p, be->left); + cgValue right = cg_build_expr(p, be->right); + Type *rt = base_type(right.type); + if (is_type_pointer(rt)) { + right = cg_emit_load(p, right); + rt = base_type(type_deref(rt)); + } + + switch (rt->kind) { + case Type_Map: + { + GB_PANIC("TODO(bill): in/not_in for maps"); + // cgValue map_ptr = cg_address_from_load_or_generate_local(p, right); + // cgValue key = left; + // cgValue ptr = cg_internal_dynamic_map_get_ptr(p, map_ptr, key); + // if (be->op.kind == Token_in) { + // return cg_emit_conv(p, cg_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool); + // } else { + // return cg_emit_conv(p, cg_emit_comp_against_nil(p, Token_CmpEq, ptr), t_bool); + // } + } + break; + case Type_BitSet: + { + Type *key_type = rt->BitSet.elem; + GB_ASSERT(are_types_identical(left.type, key_type)); + + Type *it = bit_set_to_int(rt); + left = cg_emit_conv(p, left, it); + if (is_type_different_to_arch_endianness(it)) { + left = cg_emit_byte_swap(p, left, integer_endian_type_to_platform_type(it)); + } + + cgValue lower = cg_const_value(p, left.type, exact_value_i64(rt->BitSet.lower)); + cgValue key = cg_emit_arith(p, Token_Sub, left, lower, left.type); + cgValue bit = cg_emit_arith(p, Token_Shl, cg_const_int(p, left.type, 1), key, left.type); + bit = cg_emit_conv(p, bit, it); + + cgValue old_value = cg_emit_transmute(p, right, it); + cgValue new_value = cg_emit_arith(p, Token_And, old_value, bit, it); + + GB_PANIC("TODO(bill): cg_emit_comp"); + // TokenKind op = (be->op.kind == Token_in) ? Token_NotEq : Token_CmpEq; + // return cg_emit_conv(p, cg_emit_comp(p, op, new_value, cg_const_int(p, new_value.type, 0)), t_bool); + } + break; + default: + GB_PANIC("Invalid 'in' type"); + } + break; + } + break; + default: + GB_PANIC("Invalid binary expression"); + break; + } + return {}; +} gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr); @@ -1130,6 +1309,9 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { return cg_addr_load(p, cg_build_addr(p, expr)); case_end; + case_ast_node(ie, BinaryExpr, expr); + return cg_build_binary_expr(p, expr); + case_end; } GB_PANIC("TODO(bill): cg_build_expr_internal %.*s", LIT(ast_strings[expr->kind])); return {}; diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 2862f1345..85219ae44 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -242,7 +242,8 @@ gb_internal void cg_procedure_end(cgProcedure *p) { if (tb_inst_get_control(p->func)) { tb_inst_ret(p->func, 0, nullptr); } - if (p->name == "main") { + // if (p->name == "main") { + if (p->name == "bug.main") { TB_Arena *arena = tb_default_arena(); defer (arena->free(arena)); TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 6680277ed..cc15c2abc 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -966,13 +966,32 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { for (Ast *name : vd->names) { if (!is_blank_ident(name)) { Entity *e = entity_of_node(name); - bool zero_init = true; - cgAddr addr = cg_add_local(p, e->type, e, zero_init); + cgAddr addr = cg_add_local(p, e->type, e, true); gb_unused(addr); } } } else { - GB_PANIC("TODO multiple variables"); + auto lvals = slice_make(temporary_allocator(), vd->names.count); + auto inits = array_make(temporary_allocator(), 0, lvals.count); + for (Ast *rhs : values) { + rhs = unparen_expr(rhs); + cgValue init = cg_build_expr(p, rhs); + cg_append_tuple_values(p, &inits, init); + } + + for_array(i, vd->names) { + Ast *name = vd->names[i]; + if (!is_blank_ident(name)) { + Entity *e = entity_of_node(name); + lvals[i] = cg_add_local(p, e->type, e, true); + } + } + GB_ASSERT(lvals.count == inits.count); + for_array(i, inits) { + cgAddr lval = lvals[i]; + cgValue init = inits[i]; + cg_addr_store(p, lval, init); + } } case_end; -- cgit v1.2.3 From feda213c0c83761612f1ecd947dcf95e07d13b5f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 18 Jul 2023 13:30:59 +0100 Subject: Mock out `cg_append_tuple_values` --- src/tilde_backend.cpp | 8 ++++---- src/tilde_backend.hpp | 11 +++++++---- src/tilde_stmt.cpp | 20 +++++++------------- 3 files changed, 18 insertions(+), 21 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index 9c4b9b9a2..9ac2d2f12 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -118,15 +118,15 @@ gb_internal cgValue cg_lvalue_addr(TB_Node *node, Type *type) { return v; } -gb_internal cgValue cg_value_multi(cgValueMultiNodes *multi_nodes, Type *type) { +gb_internal cgValue cg_value_multi(cgValueMulti *multi, Type *type) { GB_ASSERT(type->kind == Type_Tuple); - GB_ASSERT(multi_nodes != nullptr); + GB_ASSERT(multi != nullptr); GB_ASSERT(type->Tuple.variables.count > 1); - GB_ASSERT(multi_nodes->nodes.count == type->Tuple.variables.count); + GB_ASSERT(multi->values.count == type->Tuple.variables.count); cgValue v = {}; v.kind = cgValue_Multi; v.type = type; - v.multi_nodes = multi_nodes; + v.multi = multi; return v; } diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index f84a6feae..d84158066 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -36,9 +36,7 @@ enum cgValueKind : u32 { cgValue_Multi, }; -struct cgValueMultiNodes { - Slice nodes; -}; +struct cgValueMulti; struct cgValue { cgValueKind kind; @@ -46,10 +44,15 @@ struct cgValue { union { TB_Symbol *symbol; TB_Node * node; - cgValueMultiNodes *multi_nodes; + cgValueMulti *multi; }; }; +struct cgValueMulti { + Slice values; +}; + + enum cgAddrKind { cgAddr_Default, cgAddr_Map, diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index cc15c2abc..ff4c007ea 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -155,7 +155,7 @@ gb_internal bool cg_addr_is_empty(cgAddr const &addr) { case cgValue_Symbol: return addr.addr.symbol == nullptr; case cgValue_Multi: - return addr.addr.multi_nodes == nullptr; + return addr.addr.multi == nullptr; } return true; } @@ -710,18 +710,12 @@ gb_internal isize cg_append_tuple_values(cgProcedure *p, Array *dst_val isize init_count = dst_values->count; Type *t = src_value.type; if (t && t->kind == Type_Tuple) { - GB_PANIC("TODO(bill): tuple assignments"); - // cgTupleFix *tf = map_get(&p->tuple_fix_map, src_value.value); - // if (tf) { - // for (cgValue const &value : tf->values) { - // array_add(dst_values, value); - // } - // } else { - // for_array(i, t->Tuple.variables) { - // cgValue v = cg_emit_tuple_ev(p, src_value, cast(i32)i); - // array_add(dst_values, v); - // } - // } + GB_ASSERT(src_value.kind == cgValue_Multi); + GB_ASSERT(src_value.multi != nullptr); + GB_ASSERT(src_value.multi->values.count == t->Tuple.variables.count); + for (cgValue const &value : src_value.multi->values) { + array_add(dst_values, value); + } } else { array_add(dst_values, src_value); } -- cgit v1.2.3 From 32ac319525832794f3758daf3a08869deca30770 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jul 2023 12:55:44 +0100 Subject: Implement if statements --- src/tilde_backend.hpp | 10 +++++++-- src/tilde_expr.cpp | 15 +++++-------- src/tilde_proc.cpp | 4 ++-- src/tilde_stmt.cpp | 58 +++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 71 insertions(+), 16 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index 8fc02e3fa..bed3fd6a7 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -203,7 +203,7 @@ struct cgModule { }; #ifndef ABI_PKG_NAME_SEPARATOR -#define ABI_PKG_NAME_SEPARATOR "." +#define ABI_PKG_NAME_SEPARATOR "@" #endif gb_global Entity *cg_global_type_info_data_entity = {}; @@ -271,4 +271,10 @@ gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t); gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, cgValue x); gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right); -gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgValue rhs, Type *type); \ No newline at end of file +gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgValue rhs, Type *type); + +gb_internal TB_Node *tb_inst_region_with_name(TB_Function *f, ptrdiff_t n, char const *name) { + TB_Node *region = tb_inst_region(f); + tb_inst_set_region_name(region, n, name); + return region; +} diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index e754d473f..61dabbb52 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -1850,15 +1850,13 @@ gb_internal cgValue cg_build_cond(cgProcedure *p, Ast *cond, TB_Node *true_block case_ast_node(be, BinaryExpr, cond); if (be->op.kind == Token_CmpAnd) { - TB_Node *block = tb_inst_region(p->func); - tb_inst_set_region_name(block, -1, "cmp.and"); + TB_Node *block = tb_inst_region_with_name(p->func, -1, "cmp_and"); cg_build_cond(p, be->left, block, false_block); tb_inst_set_control(p->func, block); cg_build_cond(p, be->right, true_block, false_block); return no_comptime_short_circuit; } else if (be->op.kind == Token_CmpOr) { - TB_Node *block = tb_inst_region(p->func); - tb_inst_set_region_name(block, -1, "cmp.or"); + TB_Node *block = tb_inst_region_with_name(p->func, -1, "cmp_or"); cg_build_cond(p, be->left, true_block, block); tb_inst_set_control(p->func, block); cg_build_cond(p, be->right, true_block, false_block); @@ -2053,12 +2051,9 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { cgValue incoming_values[2] = {}; TB_Node *incoming_regions[2] = {}; - TB_Node *then = tb_inst_region(p->func); - TB_Node *done = tb_inst_region(p->func); - TB_Node *else_ = tb_inst_region(p->func); - tb_inst_set_region_name(then, -1, "if.then"); - tb_inst_set_region_name(done, -1, "if.done"); - tb_inst_set_region_name(else_, -1, "if.else"); + TB_Node *then = tb_inst_region_with_name(p->func, -1, "if_then"); + TB_Node *done = tb_inst_region_with_name(p->func, -1, "if_done"); + TB_Node *else_ = tb_inst_region_with_name(p->func, -1, "if_else"); cg_build_cond(p, te->cond, then, else_); tb_inst_set_control(p->func, then); diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index c925ee692..7f67f3a5c 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -243,7 +243,7 @@ gb_internal void cg_procedure_end(cgProcedure *p) { tb_inst_ret(p->func, 0, nullptr); } // if (p->name == "main") { - if (p->name == "bug.main") { + if (p->name == "bug" ABI_PKG_NAME_SEPARATOR "main") { TB_Arena *arena = tb_default_arena(); defer (arena->free(arena)); TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena); @@ -262,7 +262,7 @@ gb_internal void cg_procedure_generate(cgProcedure *p) { cg_procedure_begin(p); defer (cg_procedure_end(p)); - if (p->name != "bug.main" && + if (p->name != "bug" ABI_PKG_NAME_SEPARATOR "main" && p->name != "main") { return; } diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index ff4c007ea..bd856e542 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -852,6 +852,57 @@ gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return } } +gb_internal void cg_build_if_stmt(cgProcedure *p, Ast *node) { + ast_node(is, IfStmt, node); + cg_scope_open(p, is->scope); // Scope #1 + defer (cg_scope_close(p, cgDeferExit_Default, nullptr)); + + if (is->init != nullptr) { + TB_Node *init = tb_inst_region_with_name(p->func, -1, "if_init"); + tb_inst_goto(p->func, init); + tb_inst_set_control(p->func, init); + cg_build_stmt(p, is->init); + } + + TB_Node *then = tb_inst_region_with_name(p->func, -1, "if_then"); + TB_Node *done = tb_inst_region_with_name(p->func, -1, "if_done"); + TB_Node *else_ = done; + if (is->else_stmt != nullptr) { + else_ = tb_inst_region_with_name(p->func, -1, "if_else"); + } + + cgValue cond = cg_build_cond(p, is->cond, then, else_); + gb_unused(cond); + + if (is->label != nullptr) { + cgTargetList *tl = cg_push_target_list(p, is->label, done, nullptr, nullptr); + tl->is_block = true; + } + + // TODO(bill): should we do a constant check? + // Which philosophy are we following? + // - IR represents what the code represents (probably this) + // - IR represents what the code executes + + tb_inst_set_control(p->func, then); + + cg_build_stmt(p, is->body); + + tb_inst_goto(p->func, done); + + if (is->else_stmt != nullptr) { + tb_inst_set_control(p->func, else_); + + cg_scope_open(p, scope_of_node(is->else_stmt)); + cg_build_stmt(p, is->else_stmt); + cg_scope_close(p, cgDeferExit_Default, nullptr); + + tb_inst_goto(p->func, done); + } + + tb_inst_set_control(p->func, done); +} + gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { Ast *prev_stmt = p->curr_stmt; @@ -907,8 +958,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { case_ast_node(bs, BlockStmt, node); TB_Node *done = nullptr; if (bs->label != nullptr) { - done = tb_inst_region(p->func); - tb_inst_set_region_name(done, -1, "block.done"); + done = tb_inst_region_with_name(p->func, -1, "block_done"); cgTargetList *tl = cg_push_target_list(p, bs->label, done, nullptr, nullptr); tl->is_block = true; } @@ -1040,6 +1090,10 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { cg_build_return_stmt(p, rs->results); case_end; + case_ast_node(is, IfStmt, node); + cg_build_if_stmt(p, node); + case_end; + default: GB_PANIC("TODO cg_build_stmt %.*s", LIT(ast_strings[node->kind])); break; -- cgit v1.2.3 From 533f6a552cc319b700061f61f9472c6d41cda46c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jul 2023 13:15:13 +0100 Subject: Add `for` and `+=` assignments --- src/tilde_backend.hpp | 12 +++++++ src/tilde_expr.cpp | 15 ++++----- src/tilde_stmt.cpp | 91 ++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 88 insertions(+), 30 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index bed3fd6a7..ab8270c90 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -274,6 +274,18 @@ gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgValue rhs, Type *type); gb_internal TB_Node *tb_inst_region_with_name(TB_Function *f, ptrdiff_t n, char const *name) { + #if 1 + if (n < 0) { + n = gb_strlen(name); + } + static std::atomic id; + + char *new_name = gb_alloc_array(temporary_allocator(), char, n+12); + n = -1 + gb_snprintf(new_name, n+11, "%.*s_%u", cast(int)n, name, 1+id.fetch_add(1)); + + name = new_name; + #endif + TB_Node *region = tb_inst_region(f); tb_inst_set_region_name(region, n, name); return region; diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 61dabbb52..24881b386 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -283,12 +283,12 @@ gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left // TokenKind cmp_op = Token_And; - // lbValue res = lb_const_bool(p->module, t_llvm_bool, true); + // lbValue res = lb_const_bool(p->module, t_bool, true); // if (op_kind == Token_NotEq) { - // res = lb_const_bool(p->module, t_llvm_bool, false); + // res = lb_const_bool(p->module, t_bool, false); // cmp_op = Token_Or; // } else if (op_kind == Token_CmpEq) { - // res = lb_const_bool(p->module, t_llvm_bool, true); + // res = lb_const_bool(p->module, t_bool, true); // cmp_op = Token_And; // } @@ -706,9 +706,9 @@ gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, GB_PANIC("TODO(bill): cg_emit_struct_ev"); // if (type_size_of(t) == 0) { // if (op_kind == Token_CmpEq) { - // return cg_const_bool(p->module, t_llvm_bool, true); + // return cg_const_bool(p->module, t_bool, true); // } else if (op_kind == Token_NotEq) { - // return cg_const_bool(p->module, t_llvm_bool, false); + // return cg_const_bool(p->module, t_bool, false); // } // } else if (is_type_union_maybe_pointer(t)) { // cgValue tag = cg_emit_transmute(p, x, t_rawptr); @@ -1867,13 +1867,12 @@ gb_internal cgValue cg_build_cond(cgProcedure *p, Ast *cond, TB_Node *true_block cgValue v = {}; if (cg_is_expr_untyped_const(cond)) { - v = cg_expr_untyped_const_to_typed(p, cond, t_llvm_bool); + v = cg_expr_untyped_const_to_typed(p, cond, t_bool); } else { v = cg_build_expr(p, cond); } - v = cg_emit_conv(p, v, t_llvm_bool); - + GB_ASSERT(v.kind == cgValue_Value); tb_inst_if(p->func, v.node, true_block, false_block); return v; diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index bd856e542..25f8c044b 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -778,48 +778,46 @@ gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) { // NOTE(bill): Only 1 += 1 is allowed, no tuples // +=, -=, etc - GB_PANIC("do += etc assignments"); - i32 op_ = cast(i32)as->op.kind; op_ += Token_Add - Token_AddEq; // Convert += to + TokenKind op = cast(TokenKind)op_; - gb_unused(op); -/* if (op == Token_CmpAnd || op == Token_CmpOr) { - Type *type = as->lhs[0]->tav.type; - cgValue new_value = lb_emit_logical_binary_expr(p, op, as->lhs[0], as->rhs[0], type); + GB_PANIC("TODO(bill): cg_emit_logical_binary_expr"); + // Type *type = as->lhs[0]->tav.type; + // cgValue new_value = cg_emit_logical_binary_expr(p, op, as->lhs[0], as->rhs[0], type); - cgAddr lhs = lb_build_addr(p, as->lhs[0]); - cg_addr_store(p, lhs, new_value); + // cgAddr lhs = cg_build_addr(p, as->lhs[0]); + // cg_addr_store(p, lhs, new_value); } else { - cgAddr lhs = lb_build_addr(p, as->lhs[0]); - cgValue value = lb_build_expr(p, as->rhs[0]); - Type *lhs_type = lb_addr_type(lhs); + cgAddr lhs = cg_build_addr(p, as->lhs[0]); + cgValue value = cg_build_expr(p, as->rhs[0]); + Type *lhs_type = cg_addr_type(lhs); // NOTE(bill): Allow for the weird edge case of: // array *= matrix if (op == Token_Mul && is_type_matrix(value.type) && is_type_array(lhs_type)) { - cgValue old_value = lb_addr_load(p, lhs); - Type *type = old_value.type; - cgValue new_value = lb_emit_vector_mul_matrix(p, old_value, value, type); - cg_addr_store(p, lhs, new_value); - return; + GB_PANIC("TODO(bill): array *= matrix"); + // cgValue old_value = cg_addr_load(p, lhs); + // Type *type = old_value.type; + // cgValue new_value = cg_emit_vector_mul_matrix(p, old_value, value, type); + // cg_addr_store(p, lhs, new_value); + // return; } if (is_type_array(lhs_type)) { - lb_build_assign_stmt_array(p, op, lhs, value); - return; + GB_PANIC("TODO(bill): cg_build_assign_stmt_array"); + // cg_build_assign_stmt_array(p, op, lhs, value); + // return; } else { - cgValue old_value = lb_addr_load(p, lhs); + cgValue old_value = cg_addr_load(p, lhs); Type *type = old_value.type; - cgValue change = lb_emit_conv(p, value, type); - cgValue new_value = lb_emit_arith(p, op, old_value, change, type); + cgValue change = cg_emit_conv(p, value, type); + cgValue new_value = cg_emit_arith(p, op, old_value, change, type); cg_addr_store(p, lhs, new_value); } } -*/ } gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return_results) { @@ -903,6 +901,51 @@ gb_internal void cg_build_if_stmt(cgProcedure *p, Ast *node) { tb_inst_set_control(p->func, done); } +gb_internal void cg_build_for_stmt(cgProcedure *p, Ast *node) { + ast_node(fs, ForStmt, node); + + cg_scope_open(p, fs->scope); + defer (cg_scope_close(p, cgDeferExit_Default, nullptr)); + + if (fs->init != nullptr) { + TB_Node *init = tb_inst_region_with_name(p->func, -1, "for_init"); + tb_inst_goto(p->func, init); + tb_inst_set_control(p->func, init); + cg_build_stmt(p, fs->init); + } + TB_Node *body = tb_inst_region_with_name(p->func, -1, "for_body"); + TB_Node *done = tb_inst_region_with_name(p->func, -1, "for_done"); + TB_Node *loop = body; + if (fs->cond != nullptr) { + loop = tb_inst_region_with_name(p->func, -1, "for_loop"); + } + TB_Node *post = loop; + if (fs->post != nullptr) { + post = tb_inst_region_with_name(p->func, -1, "for_post"); + } + + tb_inst_goto(p->func, loop); + tb_inst_set_control(p->func, loop); + + if (loop != body) { + cg_build_cond(p, fs->cond, body, done); + tb_inst_set_control(p->func, body); + } + + cg_push_target_list(p, fs->label, done, post, nullptr); + cg_build_stmt(p, fs->body); + cg_pop_target_list(p); + + tb_inst_goto(p->func, post); + + if (fs->post != nullptr) { + tb_inst_set_control(p->func, post); + cg_build_stmt(p, fs->post); + tb_inst_goto(p->func, loop); + } + tb_inst_set_control(p->func, done); +} + gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { Ast *prev_stmt = p->curr_stmt; @@ -1094,6 +1137,10 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { cg_build_if_stmt(p, node); case_end; + case_ast_node(fs, ForStmt, node); + cg_build_for_stmt(p, node); + case_end; + default: GB_PANIC("TODO cg_build_stmt %.*s", LIT(ast_strings[node->kind])); break; -- cgit v1.2.3 From 73f25ed182288eb311abc75cc4b69f1421bfd94a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jul 2023 13:37:56 +0100 Subject: Add basic `switch` statement Implement as naive if-else chain --- src/tilde_const.cpp | 3 ++ src/tilde_stmt.cpp | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index 75b66567e..7f6de50c7 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -123,3 +123,6 @@ gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const gb_internal cgValue cg_const_int(cgProcedure *p, Type *type, i64 i) { return cg_const_value(p, type, exact_value_i64(i)); } +gb_internal cgValue cg_const_bool(cgProcedure *p, Type *type, bool v) { + return cg_value(tb_inst_bool(p->func, v), type); +} diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 25f8c044b..de936ae3d 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -945,6 +945,130 @@ gb_internal void cg_build_for_stmt(cgProcedure *p, Ast *node) { } tb_inst_set_control(p->func, done); } +gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { + ast_node(ss, SwitchStmt, node); + cg_scope_open(p, ss->scope); + + if (ss->init != nullptr) { + cg_build_stmt(p, ss->init); + } + cgValue tag = {}; + if (ss->tag != nullptr) { + tag = cg_build_expr(p, ss->tag); + } else { + tag = cg_const_bool(p, t_bool, true); + } + + TB_Node *done = tb_inst_region_with_name(p->func, -1, "switch_done"); + + ast_node(body, BlockStmt, ss->body); + + isize case_count = body->stmts.count; + Slice default_stmts = {}; + TB_Node *default_fall = nullptr; + TB_Node *default_block = nullptr; + Scope * default_scope = nullptr; + TB_Node *fall = nullptr; + + auto body_blocks = slice_make(permanent_allocator(), body->stmts.count); + auto body_scopes = slice_make(permanent_allocator(), body->stmts.count); + for_array(i, body->stmts) { + Ast *clause = body->stmts[i]; + ast_node(cc, CaseClause, clause); + + body_blocks[i] = tb_inst_region_with_name(p->func, -1, cc->list.count == 0 ? "switch_default_body" : "switch_case_body"); + body_scopes[i] = cc->scope; + if (cc->list.count == 0) { + default_block = body_blocks[i]; + default_scope = cc->scope; + } + } + + for_array(i, body->stmts) { + Ast *clause = body->stmts[i]; + ast_node(cc, CaseClause, clause); + + TB_Node *body = body_blocks[i]; + Scope *body_scope = body_scopes[i]; + fall = done; + if (i+1 < case_count) { + fall = body_blocks[i+1]; + } + + if (cc->list.count == 0) { + // default case + default_stmts = cc->stmts; + default_fall = fall; + default_block = body; + continue; + } + + TB_Node *next_cond = nullptr; + for (Ast *expr : cc->list) { + expr = unparen_expr(expr); + + next_cond = tb_inst_region_with_name(p->func, -1, "switch_case_next"); + + cgValue cond = {}; + if (is_ast_range(expr)) { + ast_node(ie, BinaryExpr, expr); + TokenKind op = Token_Invalid; + switch (ie->op.kind) { + case Token_Ellipsis: op = Token_LtEq; break; + case Token_RangeFull: op = Token_LtEq; break; + case Token_RangeHalf: op = Token_Lt; break; + default: GB_PANIC("Invalid interval operator"); break; + } + cgValue lhs = cg_build_expr(p, ie->left); + cgValue rhs = cg_build_expr(p, ie->right); + + cgValue cond_lhs = cg_emit_comp(p, Token_LtEq, lhs, tag); + cgValue cond_rhs = cg_emit_comp(p, op, tag, rhs); + cond = cg_emit_arith(p, Token_And, cond_lhs, cond_rhs, t_bool); + } else { + if (expr->tav.mode == Addressing_Type) { + GB_ASSERT(is_type_typeid(tag.type)); + cgValue e = cg_typeid(p->module, expr->tav.type); + e = cg_emit_conv(p, e, tag.type); + cond = cg_emit_comp(p, Token_CmpEq, tag, e); + } else { + cond = cg_emit_comp(p, Token_CmpEq, tag, cg_build_expr(p, expr)); + } + } + + GB_ASSERT(cond.kind == cgValue_Value); + tb_inst_if(p->func, cond.node, body, next_cond); + tb_inst_set_control(p->func, next_cond); + } + + tb_inst_set_control(p->func, body); + + cg_push_target_list(p, ss->label, done, nullptr, fall); + cg_scope_open(p, body_scope); + cg_build_stmt_list(p, cc->stmts); + cg_scope_close(p, cgDeferExit_Default, body); + cg_pop_target_list(p); + + tb_inst_goto(p->func, done); + tb_inst_set_control(p->func, next_cond); + } + + if (default_block != nullptr) { + tb_inst_goto(p->func, default_block); + tb_inst_set_control(p->func, default_block); + + cg_push_target_list(p, ss->label, done, nullptr, default_fall); + cg_scope_open(p, default_scope); + cg_build_stmt_list(p, default_stmts); + cg_scope_close(p, cgDeferExit_Default, default_block); + cg_pop_target_list(p); + } + + tb_inst_goto(p->func, done); + tb_inst_set_control(p->func, done); + + cg_scope_close(p, cgDeferExit_Default, done); +} gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { @@ -1141,6 +1265,10 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { cg_build_for_stmt(p, node); case_end; + case_ast_node(fs, SwitchStmt, node); + cg_build_switch_stmt(p, node); + case_end; + default: GB_PANIC("TODO cg_build_stmt %.*s", LIT(ast_strings[node->kind])); break; -- cgit v1.2.3 From 184563bbe1f55be17f39cdc13cb784a562419b75 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jul 2023 13:58:56 +0100 Subject: Add trivial `switch` statement check to use a jump table --- src/tilde_backend.hpp | 2 +- src/tilde_const.cpp | 2 +- src/tilde_expr.cpp | 10 ++--- src/tilde_stmt.cpp | 121 +++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 115 insertions(+), 20 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index ab8270c90..bb029ef1c 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -260,7 +260,7 @@ gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type); gb_internal String cg_get_entity_name(cgModule *m, Entity *e); -gb_internal cgValue cg_typeid(cgModule *m, Type *t); +gb_internal cgValue cg_typeid(cgProcedure *m, Type *t); gb_internal cgValue cg_emit_ptr_offset(cgProcedure *p, cgValue ptr, cgValue index); gb_internal cgValue cg_emit_array_ep(cgProcedure *p, cgValue s, cgValue index); diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index 7f6de50c7..a036d928c 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -63,7 +63,7 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac return cg_const_nil(p, type); case ExactValue_Typeid: - return cg_typeid(m, value.value_typeid); + return cg_typeid(p, value.value_typeid); case ExactValue_Procedure: { diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 24881b386..526bc4de3 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -120,7 +120,7 @@ gb_internal cgAddr cg_build_addr_from_entity(cgProcedure *p, Entity *e, Ast *exp return cg_addr(v); } -gb_internal cgValue cg_typeid(cgModule *m, Type *t) { +gb_internal cgValue cg_typeid(cgProcedure *p, Type *t) { GB_ASSERT("TODO(bill): cg_typeid"); return {}; } @@ -1747,10 +1747,10 @@ gb_internal cgValue cg_build_binary_expr(cgProcedure *p, Ast *expr) { cgValue right = {}; if (be->left->tav.mode == Addressing_Type) { - left = cg_typeid(p->module, be->left->tav.type); + left = cg_typeid(p, be->left->tav.type); } if (be->right->tav.mode == Addressing_Type) { - right = cg_typeid(p->module, be->right->tav.type); + right = cg_typeid(p, be->right->tav.type); } if (left.node == nullptr) left = cg_build_expr(p, be->left); if (right.node == nullptr) right = cg_build_expr(p, be->right); @@ -1944,8 +1944,6 @@ gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr) { gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { - cgModule *m = p->module; - expr = unparen_expr(expr); TokenPos expr_pos = ast_token(expr).pos; @@ -1964,7 +1962,7 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { return cg_const_value(p, type, tv.value); } else if (tv.mode == Addressing_Type) { // NOTE(bill, 2023-01-16): is this correct? I hope so at least - return cg_typeid(m, tv.type); + return cg_typeid(p, tv.type); } switch (expr->kind) { diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index de936ae3d..06be4f111 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -945,6 +945,57 @@ gb_internal void cg_build_for_stmt(cgProcedure *p, Ast *node) { } tb_inst_set_control(p->func, done); } + +gb_internal bool cg_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss) { + if (ss->tag == nullptr) { + return false; + } + bool is_typeid = false; + TypeAndValue tv = type_and_value_of_expr(ss->tag); + if (is_type_integer(core_type(tv.type))) { + if (type_size_of(tv.type) > 8) { + return false; + } + // okay + } else if (is_type_typeid(tv.type)) { + // okay + is_typeid = true; + } else { + return false; + } + + ast_node(body, BlockStmt, ss->body); + for (Ast *clause : body->stmts) { + ast_node(cc, CaseClause, clause); + + if (cc->list.count == 0) { + continue; + } + + for (Ast *expr : cc->list) { + expr = unparen_expr(expr); + if (is_ast_range(expr)) { + return false; + } + if (expr->tav.mode == Addressing_Type) { + GB_ASSERT(is_typeid); + continue; + } + tv = type_and_value_of_expr(expr); + if (tv.mode != Addressing_Constant) { + return false; + } + if (!is_type_integer(core_type(tv.type))) { + return false; + } + } + + } + + return true; +} + + gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { ast_node(ss, SwitchStmt, node); cg_scope_open(p, ss->scope); @@ -970,41 +1021,85 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { Scope * default_scope = nullptr; TB_Node *fall = nullptr; - auto body_blocks = slice_make(permanent_allocator(), body->stmts.count); + + auto body_regions = slice_make(permanent_allocator(), body->stmts.count); auto body_scopes = slice_make(permanent_allocator(), body->stmts.count); for_array(i, body->stmts) { Ast *clause = body->stmts[i]; ast_node(cc, CaseClause, clause); - body_blocks[i] = tb_inst_region_with_name(p->func, -1, cc->list.count == 0 ? "switch_default_body" : "switch_case_body"); + body_regions[i] = tb_inst_region_with_name(p->func, -1, cc->list.count == 0 ? "switch_default_body" : "switch_case_body"); body_scopes[i] = cc->scope; if (cc->list.count == 0) { - default_block = body_blocks[i]; + default_block = body_regions[i]; default_scope = cc->scope; } } + bool is_trivial = cg_switch_stmt_can_be_trivial_jump_table(ss); + if (is_trivial) { + isize key_count = 0; + for (Ast *clause : body->stmts) { + ast_node(cc, CaseClause, clause); + key_count += cc->list.count; + } + TB_SwitchEntry *keys = gb_alloc_array(temporary_allocator(), TB_SwitchEntry, key_count); + isize key_index = 0; + for_array(i, body->stmts) { + Ast *clause = body->stmts[i]; + ast_node(cc, CaseClause, clause); + + TB_Node *region = body_regions[i]; + for (Ast *expr : cc->list) { + i64 key = 0; + expr = unparen_expr(expr); + GB_ASSERT(!is_ast_range(expr)); + if (expr->tav.mode == Addressing_Type) { + GB_PANIC("TODO(bill): cg_typeid as i64"); + // key = cg_typeid(p, expr->tav.value.value_typeid); + } else { + auto tv = type_and_value_of_expr(expr); + GB_ASSERT(tv.mode == Addressing_Constant); + key = exact_value_to_i64(tv.value); + } + keys[key_index++] = {key, region}; + } + } + GB_ASSERT(key_index == key_count); + + TB_Node *end_block = done; + if (default_block) { + end_block = default_block; + } + + TB_DataType dt = cg_data_type(tag.type); + GB_ASSERT(tag.kind == cgValue_Value); + GB_ASSERT(!TB_IS_VOID_TYPE(dt)); + + tb_inst_branch(p->func, dt, tag.node, end_block, key_count, keys); + } + for_array(i, body->stmts) { Ast *clause = body->stmts[i]; ast_node(cc, CaseClause, clause); - TB_Node *body = body_blocks[i]; + TB_Node *body_region = body_regions[i]; Scope *body_scope = body_scopes[i]; fall = done; if (i+1 < case_count) { - fall = body_blocks[i+1]; + fall = body_regions[i+1]; } if (cc->list.count == 0) { // default case default_stmts = cc->stmts; default_fall = fall; - default_block = body; + GB_ASSERT(default_block == body_region); continue; } TB_Node *next_cond = nullptr; - for (Ast *expr : cc->list) { + if (!is_trivial) for (Ast *expr : cc->list) { expr = unparen_expr(expr); next_cond = tb_inst_region_with_name(p->func, -1, "switch_case_next"); @@ -1028,7 +1123,7 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { } else { if (expr->tav.mode == Addressing_Type) { GB_ASSERT(is_type_typeid(tag.type)); - cgValue e = cg_typeid(p->module, expr->tav.type); + cgValue e = cg_typeid(p, expr->tav.type); e = cg_emit_conv(p, e, tag.type); cond = cg_emit_comp(p, Token_CmpEq, tag, e); } else { @@ -1037,16 +1132,16 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { } GB_ASSERT(cond.kind == cgValue_Value); - tb_inst_if(p->func, cond.node, body, next_cond); + tb_inst_if(p->func, cond.node, body_region, next_cond); tb_inst_set_control(p->func, next_cond); } - tb_inst_set_control(p->func, body); + tb_inst_set_control(p->func, body_region); cg_push_target_list(p, ss->label, done, nullptr, fall); cg_scope_open(p, body_scope); cg_build_stmt_list(p, cc->stmts); - cg_scope_close(p, cgDeferExit_Default, body); + cg_scope_close(p, cgDeferExit_Default, body_region); cg_pop_target_list(p); tb_inst_goto(p->func, done); @@ -1054,7 +1149,9 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { } if (default_block != nullptr) { - tb_inst_goto(p->func, default_block); + if (!is_trivial) { + tb_inst_goto(p->func, default_block); + } tb_inst_set_control(p->func, default_block); cg_push_target_list(p, ss->label, done, nullptr, default_fall); -- cgit v1.2.3 From b2edab193f26355020c5c13af432145712d8cf0f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jul 2023 14:19:01 +0100 Subject: Support branch statements `break`/`continue`/`fallthrough` --- src/tilde_proc.cpp | 14 ++++++++++++-- src/tilde_stmt.cpp | 8 ++------ 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 7f67f3a5c..f51435390 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -68,7 +68,7 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i p->children.allocator = a; // p->defer_stmts.allocator = a; // p->blocks.allocator = a; - // p->branch_blocks.allocator = a; + p->branch_blocks.allocator = a; p->context_stack.allocator = a; p->scope_stack.allocator = a; map_init(&p->variable_map); @@ -128,7 +128,7 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li p->children.allocator = a; // p->defer_stmts.allocator = a; // p->blocks.allocator = a; - // p->branch_blocks.allocator = a; + p->branch_blocks.allocator = a; p->scope_stack.allocator = a; p->context_stack.allocator = a; map_init(&p->variable_map); @@ -165,6 +165,16 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { return; } + + DeclInfo *decl = decl_info_of_entity(p->entity); + if (decl != nullptr) { + for_array(i, decl->labels) { + BlockLabel bl = decl->labels[i]; + cgBranchBlocks bb = {bl.label, nullptr, nullptr}; + array_add(&p->branch_blocks, bb); + } + } + GB_ASSERT(p->type->kind == Type_Proc); TypeProc *pt = &p->type->Proc; if (pt->params == nullptr) { diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 06be4f111..e94ac5d18 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1330,14 +1330,10 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { } } } - if (block != nullptr) { - cg_emit_defer_stmts(p, cgDeferExit_Branch, block); - } - + GB_ASSERT(block != nullptr); + cg_emit_defer_stmts(p, cgDeferExit_Branch, block); tb_inst_goto(p->func, block); - tb_inst_set_control(p->func, block); - tb_inst_unreachable(p->func); tb_inst_set_control(p->func, prev_block); case_end; -- cgit v1.2.3 From 7f97274ecc0cfe445988f87c8806d08618f6671a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jul 2023 14:31:32 +0100 Subject: Wrap Tilde's goto pseudo-instruction --- src/tilde_backend.hpp | 6 ++++-- src/tilde_expr.cpp | 4 ++-- src/tilde_stmt.cpp | 39 ++++++++++++++++++++++----------------- 3 files changed, 28 insertions(+), 21 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index bb029ef1c..a203bd729 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -247,9 +247,9 @@ gb_internal void cg_addr_store(cgProcedure *p, cgAddr addr, cgValue value); gb_internal cgValue cg_addr_get_ptr(cgProcedure *p, cgAddr const &addr); gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile=false); -gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile=false); +gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile=false); -gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init); +gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init); gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgValue value); gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); @@ -273,6 +273,8 @@ gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right); gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgValue rhs, Type *type); +gb_internal bool cg_emit_goto(cgProcedure *p, TB_Node *control_region); + gb_internal TB_Node *tb_inst_region_with_name(TB_Function *f, ptrdiff_t n, char const *name) { #if 1 if (n < 0) { diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 526bc4de3..e584d67e3 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -2060,13 +2060,13 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { incoming_values [0] = cg_emit_conv(p, cg_build_expr(p, te->x), type); incoming_regions[0] = tb_inst_get_control(p->func); - tb_inst_goto(p->func, done); + cg_emit_goto(p, done); tb_inst_set_control(p->func, else_); incoming_values [1] = cg_emit_conv(p, cg_build_expr(p, te->y), type); incoming_regions[1] = tb_inst_get_control(p->func); - tb_inst_goto(p->func, done); + cg_emit_goto(p, done); tb_inst_set_control(p->func, done); GB_ASSERT(incoming_values[0].kind == cgValue_Value || diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index e94ac5d18..0f12ddf9c 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1,3 +1,11 @@ +gb_internal bool cg_emit_goto(cgProcedure *p, TB_Node *control_region) { + if (tb_inst_get_control(p->func)) { + tb_inst_goto(p->func, control_region); + return true; + } + return false; +} + gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile) { GB_ASSERT(is_type_pointer(ptr.type)); Type *type = type_deref(ptr.type); @@ -857,7 +865,7 @@ gb_internal void cg_build_if_stmt(cgProcedure *p, Ast *node) { if (is->init != nullptr) { TB_Node *init = tb_inst_region_with_name(p->func, -1, "if_init"); - tb_inst_goto(p->func, init); + cg_emit_goto(p, init); tb_inst_set_control(p->func, init); cg_build_stmt(p, is->init); } @@ -886,7 +894,7 @@ gb_internal void cg_build_if_stmt(cgProcedure *p, Ast *node) { cg_build_stmt(p, is->body); - tb_inst_goto(p->func, done); + cg_emit_goto(p, done); if (is->else_stmt != nullptr) { tb_inst_set_control(p->func, else_); @@ -895,7 +903,7 @@ gb_internal void cg_build_if_stmt(cgProcedure *p, Ast *node) { cg_build_stmt(p, is->else_stmt); cg_scope_close(p, cgDeferExit_Default, nullptr); - tb_inst_goto(p->func, done); + cg_emit_goto(p, done); } tb_inst_set_control(p->func, done); @@ -909,7 +917,7 @@ gb_internal void cg_build_for_stmt(cgProcedure *p, Ast *node) { if (fs->init != nullptr) { TB_Node *init = tb_inst_region_with_name(p->func, -1, "for_init"); - tb_inst_goto(p->func, init); + cg_emit_goto(p, init); tb_inst_set_control(p->func, init); cg_build_stmt(p, fs->init); } @@ -924,7 +932,7 @@ gb_internal void cg_build_for_stmt(cgProcedure *p, Ast *node) { post = tb_inst_region_with_name(p->func, -1, "for_post"); } - tb_inst_goto(p->func, loop); + cg_emit_goto(p, loop); tb_inst_set_control(p->func, loop); if (loop != body) { @@ -936,12 +944,12 @@ gb_internal void cg_build_for_stmt(cgProcedure *p, Ast *node) { cg_build_stmt(p, fs->body); cg_pop_target_list(p); - tb_inst_goto(p->func, post); + cg_emit_goto(p, post); if (fs->post != nullptr) { tb_inst_set_control(p->func, post); cg_build_stmt(p, fs->post); - tb_inst_goto(p->func, loop); + cg_emit_goto(p, loop); } tb_inst_set_control(p->func, done); } @@ -1144,13 +1152,13 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { cg_scope_close(p, cgDeferExit_Default, body_region); cg_pop_target_list(p); - tb_inst_goto(p->func, done); + cg_emit_goto(p, done); tb_inst_set_control(p->func, next_cond); } if (default_block != nullptr) { if (!is_trivial) { - tb_inst_goto(p->func, default_block); + cg_emit_goto(p, default_block); } tb_inst_set_control(p->func, default_block); @@ -1161,7 +1169,8 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { cg_pop_target_list(p); } - tb_inst_goto(p->func, done); + + cg_emit_goto(p, done); tb_inst_set_control(p->func, done); cg_scope_close(p, cgDeferExit_Default, done); @@ -1232,7 +1241,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { cg_scope_close(p, cgDeferExit_Default, nullptr); if (done != nullptr) { - tb_inst_goto(p->func, done); + cg_emit_goto(p, done); tb_inst_set_control(p->func, done); } @@ -1304,9 +1313,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { case_end; case_ast_node(bs, BranchStmt, node); - TB_Node *prev_block = tb_inst_get_control(p->func); - - TB_Node *block = nullptr; + TB_Node *block = nullptr; if (bs->label != nullptr) { cgBranchBlocks bb = cg_lookup_branch_blocks(p, bs->label); @@ -1333,9 +1340,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { GB_ASSERT(block != nullptr); cg_emit_defer_stmts(p, cgDeferExit_Branch, block); - tb_inst_goto(p->func, block); - - tb_inst_set_control(p->func, prev_block); + cg_emit_goto(p, block); case_end; case_ast_node(es, ExprStmt, node); -- cgit v1.2.3 From 9abf43b0d29abf3c560cd26081fb4adf0b38a5c6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jul 2023 15:24:07 +0100 Subject: Mock out `defer` handling logic (before handling `defer` statements) --- src/tilde_backend.hpp | 55 +++++++++++-------- src/tilde_expr.cpp | 10 ++-- src/tilde_proc.cpp | 28 +++++----- src/tilde_stmt.cpp | 146 +++++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 177 insertions(+), 62 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.hpp b/src/tilde_backend.hpp index a203bd729..99a97a664 100644 --- a/src/tilde_backend.hpp +++ b/src/tilde_backend.hpp @@ -111,7 +111,7 @@ struct cgTargetList { TB_Node * fallthrough_; }; -struct cgBranchBlocks { +struct cgBranchRegions { Ast * label; TB_Node *break_; TB_Node *continue_; @@ -123,12 +123,37 @@ enum cgDeferExitKind { cgDeferExit_Branch, }; +enum cgDeferKind { + cgDefer_Node, + cgDefer_Proc, +}; + +struct cgDefer { + cgDeferKind kind; + isize scope_index; + isize context_stack_count; + TB_Node * control_region; + union { + Ast *stmt; + struct { + cgValue deferred; + Slice result_as_args; + } proc; + }; +}; + + struct cgContextData { cgAddr ctx; isize scope_index; isize uses; }; +struct cgControlRegion { + TB_Node *control_region; + isize scope_index; +}; + struct cgProcedure { u32 flags; u16 state_flags; @@ -162,15 +187,18 @@ struct cgProcedure { Ast *curr_stmt; - cgTargetList * target_list; - Array branch_blocks; + cgTargetList * target_list; + Array defer_stack; + Array scope_stack; + Array context_stack; + + Array control_regions; + Array branch_regions; Scope *curr_scope; i32 scope_index; bool in_multi_assignment; - Array scope_stack; - Array context_stack; PtrMap variable_map; }; @@ -275,20 +303,5 @@ gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgV gb_internal bool cg_emit_goto(cgProcedure *p, TB_Node *control_region); -gb_internal TB_Node *tb_inst_region_with_name(TB_Function *f, ptrdiff_t n, char const *name) { - #if 1 - if (n < 0) { - n = gb_strlen(name); - } - static std::atomic id; - - char *new_name = gb_alloc_array(temporary_allocator(), char, n+12); - n = -1 + gb_snprintf(new_name, n+11, "%.*s_%u", cast(int)n, name, 1+id.fetch_add(1)); - - name = new_name; - #endif - TB_Node *region = tb_inst_region(f); - tb_inst_set_region_name(region, n, name); - return region; -} +gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name); \ No newline at end of file diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index e584d67e3..c2453b571 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -1850,13 +1850,13 @@ gb_internal cgValue cg_build_cond(cgProcedure *p, Ast *cond, TB_Node *true_block case_ast_node(be, BinaryExpr, cond); if (be->op.kind == Token_CmpAnd) { - TB_Node *block = tb_inst_region_with_name(p->func, -1, "cmp_and"); + TB_Node *block = cg_control_region(p, "cmp_and"); cg_build_cond(p, be->left, block, false_block); tb_inst_set_control(p->func, block); cg_build_cond(p, be->right, true_block, false_block); return no_comptime_short_circuit; } else if (be->op.kind == Token_CmpOr) { - TB_Node *block = tb_inst_region_with_name(p->func, -1, "cmp_or"); + TB_Node *block = cg_control_region(p, "cmp_or"); cg_build_cond(p, be->left, true_block, block); tb_inst_set_control(p->func, block); cg_build_cond(p, be->right, true_block, false_block); @@ -2048,9 +2048,9 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { cgValue incoming_values[2] = {}; TB_Node *incoming_regions[2] = {}; - TB_Node *then = tb_inst_region_with_name(p->func, -1, "if_then"); - TB_Node *done = tb_inst_region_with_name(p->func, -1, "if_done"); - TB_Node *else_ = tb_inst_region_with_name(p->func, -1, "if_else"); + TB_Node *then = cg_control_region(p, "if_then"); + TB_Node *done = cg_control_region(p, "if_done"); + TB_Node *else_ = cg_control_region(p, "if_else"); cg_build_cond(p, te->cond, then, else_); tb_inst_set_control(p->func, then); diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index f51435390..2bb18a2de 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -66,13 +66,15 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i gbAllocator a = heap_allocator(); p->children.allocator = a; - // p->defer_stmts.allocator = a; - // p->blocks.allocator = a; - p->branch_blocks.allocator = a; - p->context_stack.allocator = a; + + p->defer_stack.allocator = a; p->scope_stack.allocator = a; + p->context_stack.allocator = a; + + p->control_regions.allocator = a; + p->branch_regions.allocator = a; + map_init(&p->variable_map); - // map_init(&p->tuple_fix_map, 0); TB_Linkage linkage = TB_LINKAGE_PRIVATE; if (p->is_export) { @@ -126,13 +128,15 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li gbAllocator a = heap_allocator(); p->children.allocator = a; - // p->defer_stmts.allocator = a; - // p->blocks.allocator = a; - p->branch_blocks.allocator = a; - p->scope_stack.allocator = a; + + p->defer_stack.allocator = a; + p->scope_stack.allocator = a; p->context_stack.allocator = a; + + p->control_regions.allocator = a; + p->branch_regions.allocator = a; + map_init(&p->variable_map); - // map_init(&p->tuple_fix_map, 0); TB_Linkage linkage = TB_LINKAGE_PRIVATE; @@ -170,8 +174,8 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { if (decl != nullptr) { for_array(i, decl->labels) { BlockLabel bl = decl->labels[i]; - cgBranchBlocks bb = {bl.label, nullptr, nullptr}; - array_add(&p->branch_blocks, bb); + cgBranchRegions bb = {bl.label, nullptr, nullptr}; + array_add(&p->branch_regions, bb); } } diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 0f12ddf9c..85e719f29 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -6,6 +6,23 @@ gb_internal bool cg_emit_goto(cgProcedure *p, TB_Node *control_region) { return false; } +gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name) { + TEMPORARY_ALLOCATOR_GUARD(); + + isize n = gb_strlen(name); + + char *new_name = gb_alloc_array(temporary_allocator(), char, n+12); + n = -1 + gb_snprintf(new_name, n+11, "%.*s_%u", cast(int)n, name, p->control_regions.count); + + TB_Node *region = tb_inst_region(p->func); + tb_inst_set_region_name(region, n, new_name); + + GB_ASSERT(p->scope_index >= 0); + array_add(&p->control_regions, cgControlRegion{region, p->scope_index}); + + return region; +} + gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile) { GB_ASSERT(is_type_pointer(ptr.type)); Type *type = type_deref(ptr.type); @@ -604,18 +621,18 @@ gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection -gb_internal cgBranchBlocks cg_lookup_branch_blocks(cgProcedure *p, Ast *ident) { +gb_internal cgBranchRegions cg_lookup_branch_regions(cgProcedure *p, Ast *ident) { GB_ASSERT(ident->kind == Ast_Ident); Entity *e = entity_of_node(ident); GB_ASSERT(e->kind == Entity_Label); - for (cgBranchBlocks const &b : p->branch_blocks) { + for (cgBranchRegions const &b : p->branch_regions) { if (b.label == e->Label.node) { return b; } } GB_PANIC("Unreachable"); - cgBranchBlocks empty = {}; + cgBranchRegions empty = {}; return empty; } @@ -630,7 +647,7 @@ gb_internal cgTargetList *cg_push_target_list(cgProcedure *p, Ast *label, TB_Nod if (label != nullptr) { // Set label blocks GB_ASSERT(label->kind == Ast_Label); - for (cgBranchBlocks &b : p->branch_blocks) { + for (cgBranchRegions &b : p->branch_regions) { GB_ASSERT(b.label != nullptr && label != nullptr); GB_ASSERT(b.label->kind == Ast_Label); if (b.label == label) { @@ -701,16 +718,97 @@ gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgVal } -gb_internal void cg_scope_open(cgProcedure *p, Scope *scope) { - // TODO(bill): cg_scope_open -} +gb_internal void cg_build_defer_stmt(cgProcedure *p, cgDefer const &d) { + TB_Node *curr_region = tb_inst_get_control(p->func); + if (curr_region == nullptr) { + return; + } + + // NOTE(bill): The prev block may defer injection before it's terminator + TB_Node *last_instr = nullptr; + if (curr_region->input_count) { + last_instr = *(curr_region->inputs + curr_region->input_count); + } + if (last_instr && TB_IS_NODE_TERMINATOR(last_instr->type)) { + // NOTE(bill): ReturnStmt defer stuff will be handled previously + return; + } -gb_internal void cg_scope_close(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region, bool pop_stack=true) { - // TODO(bill): cg_scope_close + isize prev_context_stack_count = p->context_stack.count; + GB_ASSERT(prev_context_stack_count <= p->context_stack.capacity); + defer (p->context_stack.count = prev_context_stack_count); + p->context_stack.count = d.context_stack_count; + + TB_Node *b = cg_control_region(p, "defer"); + if (last_instr == nullptr) { + cg_emit_goto(p, b); + } + + tb_inst_set_control(p->func, b); + if (d.kind == cgDefer_Node) { + cg_build_stmt(p, d.stmt); + } else if (d.kind == cgDefer_Proc) { + cg_emit_call(p, d.proc.deferred, d.proc.result_as_args); + } } + gb_internal void cg_emit_defer_stmts(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region) { - // TODO(bill): cg_emit_defer_stmts + isize count = p->defer_stack.count; + isize i = count; + while (i --> 0) { + cgDefer const &d = p->defer_stack[i]; + + if (kind == cgDeferExit_Default) { + if (p->scope_index == d.scope_index && + d.scope_index > 0) { + cg_build_defer_stmt(p, d); + array_pop(&p->defer_stack); + continue; + } else { + break; + } + } else if (kind == cgDeferExit_Return) { + cg_build_defer_stmt(p, d); + } else if (kind == cgDeferExit_Branch) { + GB_PANIC("TODO(bill): cgDeferExit_Branch"); + GB_ASSERT(control_region != nullptr); + isize lower_limit = -1; + for (auto const &cr : p->control_regions) { + if (cr.control_region == control_region) { + lower_limit = cr.scope_index; + break; + } + } + GB_ASSERT(lower_limit >= 0); + if (lower_limit < d.scope_index) { + cg_build_defer_stmt(p, d); + } + } + } +} + +gb_internal void cg_scope_open(cgProcedure *p, Scope *scope) { + // TODO(bill): debug scope information + + p->scope_index += 1; + array_add(&p->scope_stack, scope); +} + +gb_internal void cg_scope_close(cgProcedure *p, cgDeferExitKind kind, TB_Node *control_region) { + cg_emit_defer_stmts(p, kind, control_region); + GB_ASSERT(p->scope_index > 0); + + while (p->context_stack.count > 0) { + auto *ctx = &p->context_stack[p->context_stack.count-1]; + if (ctx->scope_index < p->scope_index) { + break; + } + array_pop(&p->context_stack); + } + + p->scope_index -= 1; + array_pop(&p->scope_stack); } @@ -864,17 +962,17 @@ gb_internal void cg_build_if_stmt(cgProcedure *p, Ast *node) { defer (cg_scope_close(p, cgDeferExit_Default, nullptr)); if (is->init != nullptr) { - TB_Node *init = tb_inst_region_with_name(p->func, -1, "if_init"); + TB_Node *init = cg_control_region(p, "if_init"); cg_emit_goto(p, init); tb_inst_set_control(p->func, init); cg_build_stmt(p, is->init); } - TB_Node *then = tb_inst_region_with_name(p->func, -1, "if_then"); - TB_Node *done = tb_inst_region_with_name(p->func, -1, "if_done"); + TB_Node *then = cg_control_region(p, "if_then"); + TB_Node *done = cg_control_region(p, "if_done"); TB_Node *else_ = done; if (is->else_stmt != nullptr) { - else_ = tb_inst_region_with_name(p->func, -1, "if_else"); + else_ = cg_control_region(p, "if_else"); } cgValue cond = cg_build_cond(p, is->cond, then, else_); @@ -916,20 +1014,20 @@ gb_internal void cg_build_for_stmt(cgProcedure *p, Ast *node) { defer (cg_scope_close(p, cgDeferExit_Default, nullptr)); if (fs->init != nullptr) { - TB_Node *init = tb_inst_region_with_name(p->func, -1, "for_init"); + TB_Node *init = cg_control_region(p, "for_init"); cg_emit_goto(p, init); tb_inst_set_control(p->func, init); cg_build_stmt(p, fs->init); } - TB_Node *body = tb_inst_region_with_name(p->func, -1, "for_body"); - TB_Node *done = tb_inst_region_with_name(p->func, -1, "for_done"); + TB_Node *body = cg_control_region(p, "for_body"); + TB_Node *done = cg_control_region(p, "for_done"); TB_Node *loop = body; if (fs->cond != nullptr) { - loop = tb_inst_region_with_name(p->func, -1, "for_loop"); + loop = cg_control_region(p, "for_loop"); } TB_Node *post = loop; if (fs->post != nullptr) { - post = tb_inst_region_with_name(p->func, -1, "for_post"); + post = cg_control_region(p, "for_post"); } cg_emit_goto(p, loop); @@ -1018,7 +1116,7 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { tag = cg_const_bool(p, t_bool, true); } - TB_Node *done = tb_inst_region_with_name(p->func, -1, "switch_done"); + TB_Node *done = cg_control_region(p, "switch_done"); ast_node(body, BlockStmt, ss->body); @@ -1036,7 +1134,7 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { Ast *clause = body->stmts[i]; ast_node(cc, CaseClause, clause); - body_regions[i] = tb_inst_region_with_name(p->func, -1, cc->list.count == 0 ? "switch_default_body" : "switch_case_body"); + body_regions[i] = cg_control_region(p, cc->list.count == 0 ? "switch_default_body" : "switch_case_body"); body_scopes[i] = cc->scope; if (cc->list.count == 0) { default_block = body_regions[i]; @@ -1110,7 +1208,7 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { if (!is_trivial) for (Ast *expr : cc->list) { expr = unparen_expr(expr); - next_cond = tb_inst_region_with_name(p->func, -1, "switch_case_next"); + next_cond = cg_control_region(p, "switch_case_next"); cgValue cond = {}; if (is_ast_range(expr)) { @@ -1231,7 +1329,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { case_ast_node(bs, BlockStmt, node); TB_Node *done = nullptr; if (bs->label != nullptr) { - done = tb_inst_region_with_name(p->func, -1, "block_done"); + done = cg_control_region(p, "block_done"); cgTargetList *tl = cg_push_target_list(p, bs->label, done, nullptr, nullptr); tl->is_block = true; } @@ -1316,7 +1414,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { TB_Node *block = nullptr; if (bs->label != nullptr) { - cgBranchBlocks bb = cg_lookup_branch_blocks(p, bs->label); + cgBranchRegions bb = cg_lookup_branch_regions(p, bs->label); switch (bs->token.kind) { case Token_break: block = bb.break_; break; case Token_continue: block = bb.continue_; break; -- cgit v1.2.3 From fb041033528ca03d1a3240cd1e4712b0d57a959c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jul 2023 15:37:33 +0100 Subject: Add `defer` statements; add implicit `context` pointer to context stack --- src/tilde_proc.cpp | 27 +++++++++++++++++++++++---- src/tilde_stmt.cpp | 36 ++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 14 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 2bb18a2de..e2764bc50 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -181,11 +181,8 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { GB_ASSERT(p->type->kind == Type_Proc); TypeProc *pt = &p->type->Proc; - if (pt->params == nullptr) { - return; - } int param_index = 0; - for (Entity *e : pt->params->Tuple.variables) { + if (pt->params != nullptr) for (Entity *e : pt->params->Tuple.variables) { if (e->kind != Entity_Variable) { continue; } @@ -247,6 +244,28 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { // } // } } + + if (p->type->Proc.calling_convention == ProcCC_Odin) { + // NOTE(bill): Push context on to stack from implicit parameter + + String name = str_lit("__.context_ptr"); + + Entity *e = alloc_entity_param(nullptr, make_token_ident(name), t_context_ptr, false, false); + e->flags |= EntityFlag_NoAlias; + + TB_Node *param = p->param_nodes[p->param_nodes.count-1]; + param = tb_inst_load(p->func, TB_TYPE_PTR, param, cast(TB_CharUnits)build_context.ptr_size, false); + + cgValue local = cg_value(param, t_context_ptr); + cgAddr addr = cg_addr(local); + map_set(&p->variable_map, e, addr); + + + cgContextData *cd = array_add_and_get(&p->context_stack); + cd->ctx = addr; + cd->scope_index = -1; + cd->uses = +1; // make sure it has been used already + } } gb_internal void cg_procedure_end(cgProcedure *p) { diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 85e719f29..996506c84 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -725,14 +725,14 @@ gb_internal void cg_build_defer_stmt(cgProcedure *p, cgDefer const &d) { } // NOTE(bill): The prev block may defer injection before it's terminator - TB_Node *last_instr = nullptr; - if (curr_region->input_count) { - last_instr = *(curr_region->inputs + curr_region->input_count); - } - if (last_instr && TB_IS_NODE_TERMINATOR(last_instr->type)) { - // NOTE(bill): ReturnStmt defer stuff will be handled previously - return; - } + TB_Node *last_inst = nullptr; + // if (curr_region->input_count) { + // last_inst = *(curr_region->inputs + curr_region->input_count); + // } + // if (last_inst && TB_IS_NODE_TERMINATOR(last_inst->type)) { + // // NOTE(bill): ReturnStmt defer stuff will be handled previously + // return; + // } isize prev_context_stack_count = p->context_stack.count; GB_ASSERT(prev_context_stack_count <= p->context_stack.capacity); @@ -740,7 +740,7 @@ gb_internal void cg_build_defer_stmt(cgProcedure *p, cgDefer const &d) { p->context_stack.count = d.context_stack_count; TB_Node *b = cg_control_region(p, "defer"); - if (last_instr == nullptr) { + if (last_inst == nullptr) { cg_emit_goto(p, b); } @@ -771,7 +771,6 @@ gb_internal void cg_emit_defer_stmts(cgProcedure *p, cgDeferExitKind kind, TB_No } else if (kind == cgDeferExit_Return) { cg_build_defer_stmt(p, d); } else if (kind == cgDeferExit_Branch) { - GB_PANIC("TODO(bill): cgDeferExit_Branch"); GB_ASSERT(control_region != nullptr); isize lower_limit = -1; for (auto const &cr : p->control_regions) { @@ -1465,6 +1464,23 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { cg_build_switch_stmt(p, node); case_end; + case_ast_node(ds, DeferStmt, node); + Type *pt = base_type(p->type); + GB_ASSERT(pt->kind == Type_Proc); + if (pt->Proc.calling_convention == ProcCC_Odin) { + GB_ASSERT(p->context_stack.count != 0); + } + + cgDefer *d = array_add_and_get(&p->defer_stack); + d->kind = cgDefer_Node; + d->scope_index = p->scope_index; + d->context_stack_count = p->context_stack.count; + d->control_region = tb_inst_get_control(p->func); + GB_ASSERT(d->control_region != nullptr); + d->stmt = ds->stmt; + case_end; + + default: GB_PANIC("TODO cg_build_stmt %.*s", LIT(ast_strings[node->kind])); break; -- cgit v1.2.3 From 19633ece8059c32f1b2571097e5234c5903c7f2d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jul 2023 15:51:56 +0100 Subject: Simplification of the ValueDecl code --- src/tilde_stmt.cpp | 85 +++++++++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 42 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 996506c84..d2b57749a 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1353,19 +1353,15 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { } bool is_static = false; - if (vd->names.count > 0) { - for (Ast *name : vd->names) { - if (!is_blank_ident(name)) { - GB_ASSERT(name->kind == Ast_Ident); - Entity *e = entity_of_node(name); - TokenPos pos = ast_token(name).pos; - GB_ASSERT_MSG(e != nullptr, "\n%s missing entity for %.*s", token_pos_to_string(pos), LIT(name->Ident.token.string)); - if (e->flags & EntityFlag_Static) { - // NOTE(bill): If one of the entities is static, they all are - is_static = true; - break; - } - } + for (Ast *name : vd->names) if (!is_blank_ident(name)) { + // NOTE(bill): Sanity check to check for the existence of the variable's Entity + GB_ASSERT(name->kind == Ast_Ident); + Entity *e = entity_of_node(name); + TokenPos pos = ast_token(name).pos; + GB_ASSERT_MSG(e != nullptr, "\n%s missing entity for %.*s", token_pos_to_string(pos), LIT(name->Ident.token.string)); + if (e->flags & EntityFlag_Static) { + // NOTE(bill): If one of the entities is static, they all are + is_static = true; } } if (is_static) { @@ -1375,37 +1371,26 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { TEMPORARY_ALLOCATOR_GUARD(); - auto const &values = vd->values; - if (values.count == 0) { - for (Ast *name : vd->names) { - if (!is_blank_ident(name)) { - Entity *e = entity_of_node(name); - cgAddr addr = cg_add_local(p, e->type, e, true); - gb_unused(addr); - } - } - } else { - auto lvals = slice_make(temporary_allocator(), vd->names.count); - auto inits = array_make(temporary_allocator(), 0, lvals.count); - for (Ast *rhs : values) { - rhs = unparen_expr(rhs); - cgValue init = cg_build_expr(p, rhs); - cg_append_tuple_values(p, &inits, init); + auto lvals = slice_make(temporary_allocator(), vd->names.count); + for_array(i, vd->names) { + Ast *name = vd->names[i]; + if (!is_blank_ident(name)) { + Entity *e = entity_of_node(name); + lvals[i] = cg_add_local(p, e->type, e, true); } + } - for_array(i, vd->names) { - Ast *name = vd->names[i]; - if (!is_blank_ident(name)) { - Entity *e = entity_of_node(name); - lvals[i] = cg_add_local(p, e->type, e, true); - } - } - GB_ASSERT(lvals.count == inits.count); - for_array(i, inits) { - cgAddr lval = lvals[i]; - cgValue init = inits[i]; - cg_addr_store(p, lval, init); - } + auto inits = array_make(temporary_allocator(), 0, vd->values.count != 0 ? lvals.count : 0); + for (Ast *rhs : vd->values) { + cgValue init = cg_build_expr(p, rhs); + cg_append_tuple_values(p, &inits, init); + } + + GB_ASSERT(vd->values.count == 0 || lvals.count == inits.count); + for_array(i, inits) { + cgAddr lval = lvals[i]; + cgValue init = inits[i]; + cg_addr_store(p, lval, init); } case_end; @@ -1460,10 +1445,25 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { cg_build_for_stmt(p, node); case_end; + case_ast_node(rs, RangeStmt, node); + GB_PANIC("TODO(bill): cg_build_range_stmt"); + // cg_build_range_stmt(p, rs, rs->scope); + case_end; + + case_ast_node(rs, UnrollRangeStmt, node); + GB_PANIC("TODO(bill): lb_build_unroll_range_stmt"); + // cg_build_range_stmt(p, rs, rs->scope); + case_end; + case_ast_node(fs, SwitchStmt, node); cg_build_switch_stmt(p, node); case_end; + case_ast_node(ss, TypeSwitchStmt, node); + GB_PANIC("TODO(bill): cg_build_type_switch_stmt"); + // cg_build_type_switch_stmt(p, ss); + case_end; + case_ast_node(ds, DeferStmt, node); Type *pt = base_type(p->type); GB_ASSERT(pt->kind == Type_Proc); @@ -1481,6 +1481,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { case_end; + default: GB_PANIC("TODO cg_build_stmt %.*s", LIT(ast_strings[node->kind])); break; -- cgit v1.2.3 From 5fb98609cd9d5d7efea6d54a722181ff46413333 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jul 2023 18:03:42 +0100 Subject: Implement type `switch` statement for `union`s --- src/tilde/tb.lib | Bin 4146174 -> 4146648 bytes src/tilde_expr.cpp | 38 ++++++-- src/tilde_stmt.cpp | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 284 insertions(+), 11 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index c42e02d98..81c925854 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index c2453b571..f3801682d 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -125,6 +125,26 @@ gb_internal cgValue cg_typeid(cgProcedure *p, Type *t) { return {}; } +gb_internal cgValue cg_emit_union_tag_ptr(cgProcedure *p, cgValue const &parent_ptr) { + Type *t = parent_ptr.type; + Type *ut = base_type(type_deref(t)); + GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t)); + GB_ASSERT_MSG(ut->kind == Type_Union, "%s", type_to_string(t)); + + GB_ASSERT(!is_type_union_maybe_pointer_original_alignment(ut)); + GB_ASSERT(!is_type_union_maybe_pointer(ut)); + GB_ASSERT(type_size_of(ut) > 0); + + Type *tag_type = union_tag_type(ut); + i64 tag_offset = ut->Union.variant_block_size; + + GB_ASSERT(parent_ptr.kind == cgValue_Value); + TB_Node *ptr = parent_ptr.node; + TB_Node *tag_ptr = tb_inst_member_access(p->func, ptr, tag_offset); + return cg_value(tag_ptr, alloc_type_pointer(tag_type)); +} + + gb_internal cgValue cg_correct_endianness(cgProcedure *p, cgValue value) { Type *src = core_type(value.type); @@ -166,7 +186,9 @@ gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type) case cgValue_Value: GB_ASSERT(!TB_IS_VOID_TYPE(dt)); value.type = type; - value.node = tb_inst_bitcast(p->func, value.node, dt); + if (value.node->dt.raw != dt.raw) { + value.node = tb_inst_bitcast(p->func, value.node, dt); + } return value; case cgValue_Addr: value.type = type; @@ -1037,30 +1059,30 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { // Pointer <-> Pointer if (is_type_pointer(src) && is_type_pointer(dst)) { - return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + return cg_value(value.node, t); } if (is_type_multi_pointer(src) && is_type_pointer(dst)) { - return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + return cg_value(value.node, t); } if (is_type_pointer(src) && is_type_multi_pointer(dst)) { - return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + return cg_value(value.node, t); } if (is_type_multi_pointer(src) && is_type_multi_pointer(dst)) { - return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + return cg_value(value.node, t); } // proc <-> proc if (is_type_proc(src) && is_type_proc(dst)) { - return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + return cg_value(value.node, t); } // pointer -> proc if (is_type_pointer(src) && is_type_proc(dst)) { - return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + return cg_value(value.node, t); } // proc -> pointer if (is_type_proc(src) && is_type_pointer(dst)) { - return cg_value(tb_inst_bitcast(p->func, value.node, dt), t); + return cg_value(value.node, t); } // []byte/[]u8 <-> string diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index d2b57749a..a2dfa0257 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1273,6 +1273,258 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { cg_scope_close(p, cgDeferExit_Default, done); } +gb_internal void cg_type_case_body(cgProcedure *p, Ast *label, Ast *clause, TB_Node *body_region, TB_Node *done_region) { + // ast_node(cc, CaseClause, clause); + + // cg_push_target_list(p, label, done, nullptr, nullptr); + // cg_build_stmt_list(p, cc->stmts); + // cg_scope_close(p, cgDeferExit_Default, body_region); + // cg_pop_target_list(p); + + // cg_emit_goto(p, done_region); +} + +gb_internal void cg_build_type_switch_stmt(cgProcedure *p, Ast *node) { + ast_node(ss, TypeSwitchStmt, node); + + cg_scope_open(p, ss->scope); + + ast_node(as, AssignStmt, ss->tag); + GB_ASSERT(as->lhs.count == 1); + GB_ASSERT(as->rhs.count == 1); + + cgValue parent = cg_build_expr(p, as->rhs[0]); + bool is_parent_ptr = is_type_pointer(parent.type); + Type *parent_base_type = type_deref(parent.type); + gb_unused(parent_base_type); + + TypeSwitchKind switch_kind = check_valid_type_switch_type(parent.type); + GB_ASSERT(switch_kind != TypeSwitch_Invalid); + + + cgValue parent_value = parent; + + cgValue parent_ptr = parent; + if (!is_parent_ptr) { + parent_ptr = cg_address_from_load_or_generate_local(p, parent); + } + + cgValue tag = {}; + cgValue union_data = {}; + if (switch_kind == TypeSwitch_Union) { + union_data = cg_emit_conv(p, parent_ptr, t_rawptr); + Type *union_type = type_deref(parent_ptr.type); + if (is_type_union_maybe_pointer(union_type)) { + tag = cg_emit_conv(p, cg_emit_comp_against_nil(p, Token_NotEq, union_data), t_int); + } else if (union_tag_size(union_type) == 0) { + tag = {}; // there is no tag for a zero sized union + } else { + cgValue tag_ptr = cg_emit_union_tag_ptr(p, parent_ptr); + tag = cg_emit_load(p, tag_ptr); + } + } else if (switch_kind == TypeSwitch_Any) { + GB_PANIC("TODO(bill): type switch any"); + tag = cg_emit_load(p, cg_emit_struct_ep(p, parent_ptr, 1)); + } else { + GB_PANIC("Unknown switch kind"); + } + + ast_node(body, BlockStmt, ss->body); + + TB_Node *done_region = cg_control_region(p, "typeswitch_done"); + TB_Node *else_region = done_region; + TB_Node *default_region = nullptr; + isize num_cases = 0; + + for (Ast *clause : body->stmts) { + ast_node(cc, CaseClause, clause); + num_cases += cc->list.count; + if (cc->list.count == 0) { + GB_ASSERT(default_region == nullptr); + default_region = cg_control_region(p, "typeswitch_default_body"); + else_region = default_region; + } + } + + bool all_by_reference = false; + for (Ast *clause : body->stmts) { + ast_node(cc, CaseClause, clause); + if (cc->list.count != 1) { + continue; + } + Entity *case_entity = implicit_entity_of_node(clause); + all_by_reference |= (case_entity->flags & EntityFlag_Value) == 0; + break; + } + + TB_Node *backing_ptr = nullptr; + if (!all_by_reference) { + bool variants_found = false; + i64 max_size = 0; + i64 max_align = 1; + for (Ast *clause : body->stmts) { + ast_node(cc, CaseClause, clause); + if (cc->list.count != 1) { + continue; + } + Entity *case_entity = implicit_entity_of_node(clause); + if (!is_type_untyped_nil(case_entity->type)) { + max_size = gb_max(max_size, type_size_of(case_entity->type)); + max_align = gb_max(max_align, type_align_of(case_entity->type)); + variants_found = true; + } + } + if (variants_found) { + backing_ptr = tb_inst_local(p->func, cast(TB_CharUnits)max_size, cast(TB_CharUnits)max_align); + } + } + + TEMPORARY_ALLOCATOR_GUARD(); + TB_Node **control_regions = gb_alloc_array(temporary_allocator(), TB_Node *, body->stmts.count); + TB_SwitchEntry *switch_entries = gb_alloc_array(temporary_allocator(), TB_SwitchEntry, num_cases); + + isize case_index = 0; + for_array(i, body->stmts) { + Ast *clause = body->stmts[i]; + ast_node(cc, CaseClause, clause); + if (cc->list.count == 0) { + control_regions[i] = default_region; + continue; + } + + TB_Node *region = cg_control_region(p, "typeswitch_body"); + control_regions[i] = region; + + for (Ast *type_expr : cc->list) { + Type *case_type = type_of_expr(type_expr); + i64 key = -1; + if (switch_kind == TypeSwitch_Union) { + Type *ut = base_type(type_deref(parent.type)); + if (is_type_untyped_nil(case_type)) { + key = 0; + } else { + key = union_variant_index(ut, case_type); + } + } else if (switch_kind == TypeSwitch_Any) { + GB_PANIC("TODO(bill): any"); + // if (is_type_untyped_nil(case_type)) { + // saw_nil = true; + // on_val = lb_const_nil(m, t_typeid); + // } else { + // on_val = lb_typeid(m, case_type); + // } + } + GB_ASSERT(key >= 0); + + switch_entries[case_index++] = TB_SwitchEntry{key, region}; + } + } + + GB_ASSERT(case_index == num_cases); + + { + TB_DataType dt = {}; + TB_Node *key = nullptr; + if (type_size_of(parent_base_type) == 0) { + GB_ASSERT(tag.node == nullptr); + key = tb_inst_bool(p->func, false); + dt = cg_data_type(t_bool); + } else { + GB_ASSERT(tag.kind == cgValue_Value && tag.node != nullptr); + dt = cg_data_type(tag.type); + key = tag.node; + } + + GB_ASSERT(!TB_IS_VOID_TYPE(dt)); + tb_inst_branch(p->func, dt, key, else_region, num_cases, switch_entries); + } + + + for_array(i, body->stmts) { + Ast *clause = body->stmts[i]; + ast_node(cc, CaseClause, clause); + + bool saw_nil = false; + for (Ast *type_expr : cc->list) { + Type *case_type = type_of_expr(type_expr); + if (is_type_untyped_nil(case_type)) { + saw_nil = true; + } + } + + Entity *case_entity = implicit_entity_of_node(clause); + bool by_reference = (case_entity->flags & EntityFlag_Value) == 0; + + cg_scope_open(p, cc->scope); + + TB_Node *body_region = control_regions[i]; + tb_inst_set_control(p->func, body_region); + + if (cc->list.count == 1 && !saw_nil) { + cgValue data = {}; + if (switch_kind == TypeSwitch_Union) { + data = union_data; + } else if (switch_kind == TypeSwitch_Any) { + data = cg_emit_load(p, cg_emit_struct_ep(p, parent_ptr, 0)); + } + GB_ASSERT(data.kind == cgValue_Value); + + Type *ct = case_entity->type; + Type *ct_ptr = alloc_type_pointer(ct); + + cgValue ptr = {}; + + if (backing_ptr) { // by value + GB_ASSERT(!by_reference); + + i64 size = type_size_of(case_entity->type); + i64 align = type_align_of(case_entity->type); + + // make a copy of the case value + tb_inst_memcpy(p->func, + backing_ptr, // dst + data.node, // src + tb_inst_uint(p->func, TB_TYPE_INT, size), + cast(TB_CharUnits)align, + false + ); + + ptr = cg_value(backing_ptr, ct_ptr); + + } else { // by reference + GB_ASSERT(by_reference); + ptr = cg_emit_conv(p, data, ct_ptr); + } + GB_ASSERT(are_types_identical(case_entity->type, type_deref(ptr.type))); + + cg_add_entity(p->module, case_entity, ptr); + String name = case_entity->token.string; + TB_Attrib *dbg = tb_function_attrib_variable(p->func, name.len, cast(char const *)name.text, cg_debug_type(p->module, ct)); + tb_node_append_attrib(ptr.node, dbg); + } else { + if (case_entity->flags & EntityFlag_Value) { + // by value + cgAddr x = cg_add_local(p, case_entity->type, case_entity, false); + cg_addr_store(p, x, parent_value); + } else { + // by reference + cg_add_entity(p->module, case_entity, parent_value); + } + } + + cg_push_target_list(p, ss->label, done_region, nullptr, nullptr); + cg_build_stmt_list(p, cc->stmts); + cg_scope_close(p, cgDeferExit_Default, body_region); + cg_pop_target_list(p); + + cg_emit_goto(p, done_region); + } + + cg_emit_goto(p, done_region); + tb_inst_set_control(p->func, done_region); + cg_scope_close(p, cgDeferExit_Default, done_region); +} + gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { Ast *prev_stmt = p->curr_stmt; @@ -1459,9 +1711,8 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { cg_build_switch_stmt(p, node); case_end; - case_ast_node(ss, TypeSwitchStmt, node); - GB_PANIC("TODO(bill): cg_build_type_switch_stmt"); - // cg_build_type_switch_stmt(p, ss); + case_ast_node(ts, TypeSwitchStmt, node); + cg_build_type_switch_stmt(p, node); case_end; case_ast_node(ds, DeferStmt, node); -- cgit v1.2.3 From f32d71eca05983520fb5e39cd9c7802200353adb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 19 Jul 2023 20:44:37 +0100 Subject: Mock out `any` type `switch` statement --- src/tilde_backend.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/tilde_expr.cpp | 5 ---- src/tilde_stmt.cpp | 13 ++++----- 3 files changed, 85 insertions(+), 13 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_backend.cpp b/src/tilde_backend.cpp index 9ac2d2f12..e76912895 100644 --- a/src/tilde_backend.cpp +++ b/src/tilde_backend.cpp @@ -186,6 +186,86 @@ gb_internal isize cg_type_info_index(CheckerInfo *info, Type *type, bool err_on_ return -1; } + +gb_internal u64 cg_typeid_as_u64(cgModule *m, Type *type) { + GB_ASSERT(!build_context.no_rtti); + + type = default_type(type); + + u64 id = cast(u64)cg_type_info_index(m->info, type); + GB_ASSERT(id >= 0); + + u64 kind = Typeid_Invalid; + u64 named = is_type_named(type) && type->kind != Type_Basic; + u64 special = 0; + u64 reserved = 0; + + Type *bt = base_type(type); + TypeKind tk = bt->kind; + switch (tk) { + case Type_Basic: { + u32 flags = bt->Basic.flags; + if (flags & BasicFlag_Boolean) kind = Typeid_Boolean; + if (flags & BasicFlag_Integer) kind = Typeid_Integer; + if (flags & BasicFlag_Unsigned) kind = Typeid_Integer; + if (flags & BasicFlag_Float) kind = Typeid_Float; + if (flags & BasicFlag_Complex) kind = Typeid_Complex; + if (flags & BasicFlag_Pointer) kind = Typeid_Pointer; + if (flags & BasicFlag_String) kind = Typeid_String; + if (flags & BasicFlag_Rune) kind = Typeid_Rune; + } break; + case Type_Pointer: kind = Typeid_Pointer; break; + case Type_MultiPointer: kind = Typeid_Multi_Pointer; break; + case Type_Array: kind = Typeid_Array; break; + case Type_Matrix: kind = Typeid_Matrix; break; + case Type_EnumeratedArray: kind = Typeid_Enumerated_Array; break; + case Type_Slice: kind = Typeid_Slice; break; + case Type_DynamicArray: kind = Typeid_Dynamic_Array; break; + case Type_Map: kind = Typeid_Map; break; + case Type_Struct: kind = Typeid_Struct; break; + case Type_Enum: kind = Typeid_Enum; break; + case Type_Union: kind = Typeid_Union; break; + case Type_Tuple: kind = Typeid_Tuple; break; + case Type_Proc: kind = Typeid_Procedure; break; + case Type_BitSet: kind = Typeid_Bit_Set; break; + case Type_SimdVector: kind = Typeid_Simd_Vector; break; + case Type_RelativePointer: kind = Typeid_Relative_Pointer; break; + case Type_RelativeSlice: kind = Typeid_Relative_Slice; break; + case Type_SoaPointer: kind = Typeid_SoaPointer; break; + } + + if (is_type_cstring(type)) { + special = 1; + } else if (is_type_integer(type) && !is_type_unsigned(type)) { + special = 1; + } + + u64 data = 0; + if (build_context.ptr_size == 4) { + GB_ASSERT(id <= (1u<<24u)); + data |= (id &~ (1u<<24)) << 0u; // index + data |= (kind &~ (1u<<5)) << 24u; // kind + data |= (named &~ (1u<<1)) << 29u; // named + data |= (special &~ (1u<<1)) << 30u; // special + data |= (reserved &~ (1u<<1)) << 31u; // reserved + } else { + GB_ASSERT(build_context.ptr_size == 8); + GB_ASSERT(id <= (1ull<<56u)); + data |= (id &~ (1ull<<56)) << 0ul; // index + data |= (kind &~ (1ull<<5)) << 56ull; // kind + data |= (named &~ (1ull<<1)) << 61ull; // named + data |= (special &~ (1ull<<1)) << 62ull; // special + data |= (reserved &~ (1ull<<1)) << 63ull; // reserved + } + return data; +} + +gb_internal cgValue cg_typeid(cgProcedure *p, Type *t) { + u64 x = cg_typeid_as_u64(p->module, t); + return cg_value(tb_inst_uint(p->func, cg_data_type(t_typeid), x), t_typeid); +} + + struct cgGlobalVariable { cgValue var; cgValue init; diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index f3801682d..2d4b11336 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -120,11 +120,6 @@ gb_internal cgAddr cg_build_addr_from_entity(cgProcedure *p, Entity *e, Ast *exp return cg_addr(v); } -gb_internal cgValue cg_typeid(cgProcedure *p, Type *t) { - GB_ASSERT("TODO(bill): cg_typeid"); - return {}; -} - gb_internal cgValue cg_emit_union_tag_ptr(cgProcedure *p, cgValue const &parent_ptr) { Type *t = parent_ptr.type; Type *ut = base_type(type_deref(t)); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index a2dfa0257..c5aaa9161 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1323,7 +1323,6 @@ gb_internal void cg_build_type_switch_stmt(cgProcedure *p, Ast *node) { tag = cg_emit_load(p, tag_ptr); } } else if (switch_kind == TypeSwitch_Any) { - GB_PANIC("TODO(bill): type switch any"); tag = cg_emit_load(p, cg_emit_struct_ep(p, parent_ptr, 1)); } else { GB_PANIC("Unknown switch kind"); @@ -1406,13 +1405,11 @@ gb_internal void cg_build_type_switch_stmt(cgProcedure *p, Ast *node) { key = union_variant_index(ut, case_type); } } else if (switch_kind == TypeSwitch_Any) { - GB_PANIC("TODO(bill): any"); - // if (is_type_untyped_nil(case_type)) { - // saw_nil = true; - // on_val = lb_const_nil(m, t_typeid); - // } else { - // on_val = lb_typeid(m, case_type); - // } + if (is_type_untyped_nil(case_type)) { + key = 0; + } else { + key = cast(i64)cg_typeid_as_u64(p->module, case_type); + } } GB_ASSERT(key >= 0); -- cgit v1.2.3 From ec0a9a5f8a68e03650958acca19f96b3dfd4744e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Jul 2023 13:05:39 +0100 Subject: Copy lvalues on multi-valued assignments to allow for `a, b = b, a` on large types (minor bodge) --- src/tilde/tb.h | 22 ++++++++++------------ src/tilde/tb.lib | Bin 4146648 -> 4158782 bytes src/tilde_stmt.cpp | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 14 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde/tb.h b/src/tilde/tb.h index 3924bbe8e..c2dc3922b 100644 --- a/src/tilde/tb.h +++ b/src/tilde/tb.h @@ -196,6 +196,11 @@ typedef union TB_DataType { typedef enum TB_NodeTypeEnum { TB_NULL = 0, + // Immediates + TB_INTEGER_CONST, + TB_FLOAT32_CONST, + TB_FLOAT64_CONST, + // only one per function TB_START, // fn() @@ -253,11 +258,6 @@ typedef enum TB_NodeTypeEnum { TB_MEMBER_ACCESS, TB_ARRAY_ACCESS, - // Immediates - TB_INTEGER_CONST, - TB_FLOAT32_CONST, - TB_FLOAT64_CONST, - // Conversions TB_TRUNCATE, TB_FLOAT_EXT, @@ -295,6 +295,8 @@ typedef enum TB_NodeTypeEnum { TB_SHL, TB_SHR, TB_SAR, + TB_ROL, + TB_ROR, TB_UDIV, TB_SDIV, TB_UMOD, @@ -336,9 +338,6 @@ typedef enum TB_NodeTypeEnum { } TB_NodeTypeEnum; typedef uint8_t TB_NodeType; -#define TB_IS_NODE_SIDE_EFFECT(type) ((type) >= TB_LINE_INFO && (type) <= TB_DEBUGBREAK) -#define TB_IS_NODE_TERMINATOR(type) ((type) >= TB_BRANCH && (type) <= TB_TRAP) - typedef int TB_Label; // just represents some region of bytes, usually in file parsing crap @@ -980,6 +979,8 @@ TB_API TB_Node* tb_inst_xor(TB_Function* f, TB_Node* a, TB_Node* b); TB_API TB_Node* tb_inst_sar(TB_Function* f, TB_Node* a, TB_Node* b); TB_API TB_Node* tb_inst_shl(TB_Function* f, TB_Node* a, TB_Node* b, TB_ArithmeticBehavior arith_behavior); TB_API TB_Node* tb_inst_shr(TB_Function* f, TB_Node* a, TB_Node* b); +TB_API TB_Node* tb_inst_rol(TB_Function* f, TB_Node* a, TB_Node* b); +TB_API TB_Node* tb_inst_ror(TB_Function* f, TB_Node* a, TB_Node* b); // Atomics // By default you can use TB_MEM_ORDER_SEQ_CST for the memory order to get @@ -1052,10 +1053,7 @@ TB_API void tb_inst_ret(TB_Function* f, size_t count, TB_Node** values); //////////////////////////////// // Optimizer //////////////////////////////// - -// Function-level optimizations are managed via TB_FuncOpt, it's tied -// to a single TB_Function and it'll can be used to run peepholes incrementally -// between whatever passes TB may have. +// Function analysis, optimizations, and codegen are all part of this typedef struct TB_FuncOpt TB_FuncOpt; // the arena is used to allocate the nodes diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index 81c925854..5a1cd67dd 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index c5aaa9161..6aa906288 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -850,11 +850,39 @@ gb_internal void cg_build_assignment(cgProcedure *p, Array const &lvals, p->in_multi_assignment = lval_count > 1; GB_ASSERT(lvals.count == inits.count); - for_array(i, inits) { + + + if (inits.count > 1) for_array(i, inits) { cgAddr lval = lvals[i]; + cgValue init = cg_flatten_value(p, inits[i]); + + GB_ASSERT(init.kind != cgValue_Multi); + if (init.type == nullptr) { + continue; + } + + Type *type = cg_addr_type(lval); + GB_ASSERT(are_types_identical(type, init.type)); + if (init.kind == cgValue_Addr && + !cg_addr_is_empty(lval)) { + // NOTE(bill): This is needed for certain constructs such as this: + // a, b = b, a + // NOTE(bill): This is a bodge and not necessarily a good way of doing things whatsoever + TB_CharUnits size = cast(TB_CharUnits)type_size_of(type); + TB_CharUnits align = cast(TB_CharUnits)type_align_of(type); + TB_Node *copy = tb_inst_local(p->func, size, align); + tb_inst_memcpy(p->func, copy, init.node, tb_inst_uint(p->func, TB_TYPE_INT, size), align, false); + // use the copy instead + init.node = copy; + } + inits[i] = init; + } + + for_array(i, inits) { + cgAddr lval = lvals[i]; cgValue init = inits[i]; + GB_ASSERT(init.kind != cgValue_Multi); if (init.type == nullptr) { - // TODO(bill): figure out how to do this continue; } cg_addr_store(p, lval, init); -- cgit v1.2.3 From e5f9458905f27b027403a5a0b94cc7762984a08e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 22 Jul 2023 07:56:13 +0100 Subject: Update Tilde to get procedure passing rules --- src/tilde.cpp | 95 +++++--------------------------------- src/tilde.hpp | 3 ++ src/tilde/tb.h | 62 +++++++++++++++++-------- src/tilde/tb.lib | Bin 4158782 -> 4162738 bytes src/tilde_proc.cpp | 132 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/tilde_stmt.cpp | 40 +++++++++++++++- 6 files changed, 217 insertions(+), 115 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde.cpp b/src/tilde.cpp index 188f5e0d0..78aa3640d 100644 --- a/src/tilde.cpp +++ b/src/tilde.cpp @@ -1,5 +1,12 @@ #include "tilde.hpp" + +gb_global Slice global_tb_arenas; + +gb_internal TB_Arena *cg_arena(void) { + return global_tb_arenas[current_thread_index()]; +} + // returns TB_TYPE_VOID if not trivially possible gb_internal TB_DataType cg_data_type(Type *t) { GB_ASSERT(t != nullptr); @@ -672,6 +679,11 @@ gb_internal bool cg_generate_code(Checker *c) { CheckerInfo *info = &c->info; gb_unused(info); + global_tb_arenas = slice_make(permanent_allocator(), global_thread_pool.threads.count); + for_array(i, global_tb_arenas) { + global_tb_arenas[i] = tb_default_arena(); + } + cgModule *m = cg_module_create(c); defer (cg_module_destroy(m)); @@ -750,89 +762,6 @@ gb_internal bool cg_generate_code(Checker *c) { char const *path = "W:/Odin/tilde_main.obj"; GB_ASSERT(tb_export_buffer_to_file(export_buffer, path)); - - //////////////////////////////////////////////////////////////////////////////////// - - - // TB_Arena *arena = tb_default_arena(); - - // TB_Global *str = nullptr; - // { - // TB_Global *str_data = nullptr; - // { - // str_data = tb_global_create(m->mod, "csb$1", nullptr, TB_LINKAGE_PRIVATE); - // tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_data, 8, 1, 1); - // void *region = tb_global_add_region(m->mod, str_data, 0, 8); - // memcpy(region, "Hellope\x00", 8); - // } - - // str = tb_global_create(m->mod, "global$str", nullptr, TB_LINKAGE_PRIVATE); - // tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str, 16, 8, 2); - // tb_global_add_symbol_reloc(m->mod, str, 0, cast(TB_Symbol *)str_data); - // void *len = tb_global_add_region(m->mod, str, 8, 8); - // *cast(i64 *)len = 7; - // } - - // { - // TB_PrototypeParam printf_ret = {TB_TYPE_I32}; - // TB_PrototypeParam printf_params = {TB_TYPE_PTR}; - // TB_FunctionPrototype *printf_proto = tb_prototype_create(m->mod, TB_STDCALL, 1, &printf_params, 1, &printf_ret, true); - // TB_External *printf_proc = tb_extern_create(m->mod, "printf", TB_EXTERNAL_SO_LOCAL); - - // TB_PrototypeParam main_ret = {TB_TYPE_I32}; - // TB_FunctionPrototype *main_proto = tb_prototype_create(m->mod, TB_STDCALL, 0, nullptr, 1, &main_ret, false); - // TB_Function * p = tb_function_create(m->mod, "main", TB_LINKAGE_PUBLIC, TB_COMDAT_NONE); - // tb_function_set_prototype(p, main_proto, arena); - - - // auto str_ptr = tb_inst_get_symbol_address(p, cast(TB_Symbol *)str); - // auto str_data_ptr_ptr = tb_inst_member_access(p, str_ptr, 0); - // auto str_data_ptr = tb_inst_load(p, TB_TYPE_PTR, str_data_ptr_ptr, 1, false); - // auto str_len_ptr = tb_inst_member_access(p, str_ptr, 8); - // auto str_len = tb_inst_load(p, TB_TYPE_I64, str_len_ptr, 8, false); - - - // TB_Node *params[4] = {}; - // params[0] = tb_inst_cstring(p, "%.*s %s!\n"); - // params[1] = tb_inst_trunc(p, str_len, TB_TYPE_I32); - // params[2] = str_data_ptr; - // params[3] = tb_inst_cstring(p, "World"); - // TB_MultiOutput output = tb_inst_call(p, printf_proto, tb_inst_get_symbol_address(p, cast(TB_Symbol *)printf_proc), gb_count_of(params), params); - // gb_unused(output); - // TB_Node *printf_return_value = output.single; - - // TB_Node *zero = tb_inst_uint(p, TB_TYPE_I32, 0); - // TB_Node *one = tb_inst_uint(p, TB_TYPE_I32, 1); - - // TB_Node *prev_case = tb_inst_get_control(p); - - // TB_Node *true_case = tb_inst_region(p); - // TB_Node *false_case = tb_inst_region(p); - - // TB_Node *cond = tb_inst_cmp_igt(p, printf_return_value, zero, true); - // tb_inst_if(p, cond, true_case, false_case); - - // tb_inst_set_control(p, true_case); - // tb_inst_ret(p, 1, &zero); - - // tb_inst_set_control(p, false_case); - // tb_inst_ret(p, 1, &one); - - // tb_inst_set_control(p, prev_case); - - - // tb_module_compile_function(m->mod, p, TB_ISEL_FAST); - - // tb_function_print(p, tb_default_print_callback, stdout); - - - // TB_DebugFormat debug_format = TB_DEBUGFMT_NONE; - // TB_ExportBuffer export_buffer = tb_module_object_export(m->mod, debug_format); - // defer (tb_export_buffer_free(export_buffer)); - - // char const *path = "W:/Odin/tilde_main.obj"; - // GB_ASSERT(tb_export_buffer_to_file(export_buffer, path)); - // } return true; } diff --git a/src/tilde.hpp b/src/tilde.hpp index 99a97a664..633eb63db 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -248,6 +248,9 @@ gb_global isize cg_global_type_info_member_offsets_index = 0; gb_global isize cg_global_type_info_member_usings_index = 0; gb_global isize cg_global_type_info_member_tags_index = 0; + +gb_internal TB_Arena *cg_arena(void); + gb_internal cgValue cg_value(TB_Global * g, Type *type); gb_internal cgValue cg_value(TB_External *e, Type *type); gb_internal cgValue cg_value(TB_Function *f, Type *type); diff --git a/src/tilde/tb.h b/src/tilde/tb.h index c2dc3922b..048fce598 100644 --- a/src/tilde/tb.h +++ b/src/tilde/tb.h @@ -210,9 +210,6 @@ typedef enum TB_NodeTypeEnum { // projection TB_PROJ, - // metadata - TB_KEEPALIVE, - TB_CALL, // normal call TB_SCALL, // system call @@ -640,14 +637,32 @@ TB_API void tb_module_set_tls_index(TB_Module* m, ptrdiff_t len, const char* nam TB_API void tb_module_layout_sections(TB_Module* m); //////////////////////////////// -// Exporter +// Compiled code introspection //////////////////////////////// +enum { TB_ASSEMBLY_CHUNK_CAP = 4*1024 - sizeof(size_t[2]) }; + +typedef struct TB_Assembly TB_Assembly; +struct TB_Assembly { + TB_Assembly* next; + + // nice chunk of text here + size_t length; + char data[]; +}; // this is where the machine code and other relevant pieces go. typedef struct TB_FunctionOutput TB_FunctionOutput; // returns NULL if it fails -TB_API TB_FunctionOutput* tb_module_compile_function(TB_Module* m, TB_Function* f, TB_ISelMode isel_mode); +TB_API TB_FunctionOutput* tb_module_compile_function(TB_Module* m, TB_Function* f, TB_ISelMode isel_mode, bool emit_asm); + +TB_API uint8_t* tb_output_get_code(TB_FunctionOutput* out, size_t* out_length); + +// returns NULL if no assembly was generated +TB_API TB_Assembly* tb_output_get_asm(TB_FunctionOutput* out); + +// this is relative to the start of the function (the start of the prologue) +TB_API TB_Safepoint* tb_safepoint_get(TB_Function* f, uint32_t relative_ip); //////////////////////////////// // Exporter @@ -780,6 +795,27 @@ struct TB_FunctionPrototype { // matching signatures. TB_API TB_FunctionPrototype* tb_prototype_create(TB_Module* m, TB_CallingConv cc, size_t param_count, const TB_PrototypeParam* params, size_t return_count, const TB_PrototypeParam* returns, bool has_varargs); +// same as tb_function_set_prototype except it will handle lowering from types like the TB_DebugType +// into the correct ABI and exposing sane looking nodes to the parameters. +// +// returns the parameters +TB_API TB_Node** tb_function_set_prototype_from_dbg(TB_Function* f, TB_DebugType* dbg, TB_Arena* arena, size_t* out_param_count); +TB_API TB_FunctionPrototype* tb_prototype_from_dbg(TB_Module* m, TB_DebugType* dbg); + +// used for ABI parameter passing +typedef enum { + // needs a direct value + TB_PASSING_DIRECT, + + // needs an address to the value + TB_PASSING_INDIRECT, + + // doesn't use this parameter + TB_PASSING_IGNORE, +} TB_PassingRule; + +TB_API TB_PassingRule tb_get_passing_rule_from_dbg(TB_Module* mod, TB_DebugType* param_type, bool is_return); + //////////////////////////////// // Globals //////////////////////////////// @@ -829,6 +865,8 @@ TB_API void tb_debug_record_end(TB_DebugType* type, TB_CharUnits size, TB_CharUn TB_API TB_DebugType* tb_debug_create_func(TB_Module* m, TB_CallingConv cc, size_t param_count, size_t return_count, bool has_varargs); +TB_API TB_DebugType* tb_debug_field_type(TB_DebugType* type); + // you'll need to fill these if you make a function TB_API TB_DebugType** tb_debug_func_params(TB_DebugType* type); TB_API TB_DebugType** tb_debug_func_returns(TB_DebugType* type); @@ -839,12 +877,6 @@ TB_API TB_DebugType** tb_debug_func_returns(TB_DebugType* type); // it is an index to the input #define TB_FOR_INPUT_IN_NODE(it, parent) for (TB_Node **it = parent->inputs, **__end = it + (parent)->input_count; it != __end; it++) -//////////////////////////////// -// Compiled code introspection -//////////////////////////////// -// this is relative to the start of the function (the start of the prologue) -TB_API TB_Safepoint* tb_safepoint_get(TB_Function* f, uint32_t relative_ip); - //////////////////////////////// // Symbols //////////////////////////////// @@ -879,13 +911,6 @@ TB_API void tb_symbol_set_name(TB_Symbol* s, ptrdiff_t len, const char* name); TB_API void tb_symbol_bind_ptr(TB_Symbol* s, void* ptr); TB_API const char* tb_symbol_get_name(TB_Symbol* s); -// same as tb_function_set_prototype except it will handle lowering from types like the TB_DebugType -// into the correct ABI and exposing sane looking nodes to the parameters. -// -// returns the parameters -TB_API TB_Node** tb_function_set_prototype_from_dbg(TB_Function* f, TB_DebugType* dbg, TB_Arena* arena, size_t* out_param_count); -TB_API TB_FunctionPrototype* tb_prototype_from_dbg(TB_Module* m, TB_DebugType* dbg); - // if arena is NULL, defaults to module arena which is freed on tb_free_thread_resources TB_API void tb_function_set_prototype(TB_Function* f, TB_FunctionPrototype* p, TB_Arena* arena); TB_API TB_FunctionPrototype* tb_function_get_prototype(TB_Function* f); @@ -903,7 +928,6 @@ TB_API void tb_inst_set_region_name(TB_Node* n, ptrdiff_t len, const char* name) TB_API void tb_inst_unreachable(TB_Function* f); TB_API void tb_inst_debugbreak(TB_Function* f); TB_API void tb_inst_trap(TB_Function* f); -TB_API void tb_inst_keep_alive(TB_Function* f, TB_Node* src); TB_API TB_Node* tb_inst_poison(TB_Function* f); TB_API TB_Node* tb_inst_param(TB_Function* f, int param_id); diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index 5a1cd67dd..b9b9dbd44 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index e2764bc50..e7210382c 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -87,12 +87,11 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i } if (p->symbol == nullptr) { - TB_Arena *arena = tb_default_arena(); p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE); size_t out_param_count = 0; p->debug_type = cg_debug_type_for_proc(m, p->type); - TB_Node **params = tb_function_set_prototype_from_dbg(p->func, p->debug_type, arena, &out_param_count); + TB_Node **params = tb_function_set_prototype_from_dbg(p->func, p->debug_type, cg_arena(), &out_param_count); p->param_nodes = {params, cast(isize)out_param_count}; p->proto = tb_function_get_prototype(p->func); @@ -141,12 +140,11 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li TB_Linkage linkage = TB_LINKAGE_PRIVATE; - TB_Arena *arena = tb_default_arena(); p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE); size_t out_param_count = 0; p->debug_type = cg_debug_type_for_proc(m, p->type); - TB_Node **params = tb_function_set_prototype_from_dbg(p->func, p->debug_type, arena, &out_param_count); + TB_Node **params = tb_function_set_prototype_from_dbg(p->func, p->debug_type, cg_arena(), &out_param_count); p->param_nodes = {params, cast(isize)out_param_count}; p->proto = tb_function_get_prototype(p->func); @@ -275,17 +273,32 @@ gb_internal void cg_procedure_end(cgProcedure *p) { if (tb_inst_get_control(p->func)) { tb_inst_ret(p->func, 0, nullptr); } + bool emit_asm = false; // if (p->name == "main") { - if (p->name == "bug" ABI_PKG_NAME_SEPARATOR "main") { + if ( + // p->name == "bug" ABI_PKG_NAME_SEPARATOR "main" || + p->name == "main" || + false + ) { TB_Arena *arena = tb_default_arena(); defer (arena->free(arena)); TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena); defer (tb_funcopt_exit(opt)); tb_funcopt_print(opt); + // emit_asm = true; + + // GraphViz printing // tb_function_print(p->func, tb_default_print_callback, stdout); } - tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST); + TB_FunctionOutput *output = tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST, emit_asm); + if (emit_asm) { + TB_Assembly *assembly = tb_output_get_asm(output); + for (TB_Assembly *node = assembly; node != nullptr; node = node->next) { + gb_printf_err("%.*s", cast(int)node->length, node->data); + } + gb_printf_err("\n"); + } } gb_internal void cg_procedure_generate(cgProcedure *p) { @@ -332,7 +345,9 @@ gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr) { cgValue res = cg_build_call_expr_internal(p, expr); if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures - GB_PANIC("Handle optional_ok_one"); + GB_ASSERT(res.kind == cgValue_Multi); + GB_ASSERT(res.multi->values.count == 2); + return res.multi->values[0]; // GB_ASSERT(is_type_tuple(res.type)); // GB_ASSERT(res.type->Tuple.variables.count == 2); // return cg_emit_struct_ev(p, res, 0); @@ -345,18 +360,111 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice value = cg_value(tb_inst_get_symbol_address(p->func, value.symbol), value.type); } GB_ASSERT(value.kind == cgValue_Value); + TEMPORARY_ALLOCATOR_GUARD(); + + TB_Module *m = p->module->mod; - // TODO(bill): abstract out the function prototype stuff so that you handle the ABI correctly (at least for win64 at the moment) - TB_FunctionPrototype *proto = cg_procedure_type_as_prototype(p->module, value.type); + + Type *type = base_type(value.type); + GB_ASSERT(type->kind == Type_Proc); + TypeProc *pt = &type->Proc; + gb_unused(pt); + + TB_FunctionPrototype *proto = cg_procedure_type_as_prototype(p->module, type); TB_Node *target = value.node; - auto params = slice_make(temporary_allocator(), 0 /*proto->param_count*/); - for_array(i, params) { - // params[i] = proto + auto params = slice_make(temporary_allocator(), proto->param_count); + + + GB_ASSERT(build_context.metrics.os == TargetOs_windows); + // TODO(bill): Support more than Win64 ABI + + bool is_odin_like_cc = is_calling_convention_odin(pt->calling_convention); + GB_ASSERT(is_odin_like_cc); + + bool return_is_indirect = false; + + isize param_index = 0; + if (pt->result_count != 0) { + Type *last_result = pt->results->Tuple.variables[pt->results->Tuple.variables.count-1]->type; + + TB_DebugType *dbg = cg_debug_type(p->module, last_result); + TB_PassingRule rule = tb_get_passing_rule_from_dbg(m, dbg, true); + if (rule == TB_PASSING_INDIRECT) { + return_is_indirect = true; + TB_CharUnits size = cast(TB_CharUnits)type_size_of(last_result); + TB_CharUnits align = cast(TB_CharUnits)type_align_of(last_result); + params[param_index++] = tb_inst_local(p->func, size, align); + } + } + for (cgValue arg : args) { + Type *param_type = pt->params->Tuple.variables[param_index]->type; + arg = cg_emit_conv(p, arg, param_type); + arg = cg_flatten_value(p, arg); + + TB_Node *param = nullptr; + + TB_DebugType *dbg = cg_debug_type(p->module, param_type); + TB_PassingRule rule = tb_get_passing_rule_from_dbg(m, dbg, false); + switch (rule) { + case TB_PASSING_DIRECT: + GB_ASSERT(arg.kind == cgValue_Value); + param = arg.node; + break; + case TB_PASSING_INDIRECT: + { + // indirect + cgValue arg_ptr = cg_address_from_load_or_generate_local(p, arg); + GB_ASSERT(arg_ptr.kind == cgValue_Value); + param = arg_ptr.node; + } + break; + case TB_PASSING_IGNORE: + continue; + } + + params[param_index++] = param; + } + + // Split returns + for (isize i = 0; i < pt->result_count-1; i++) { + Type *result = pt->results->Tuple.variables[i]->type; + TB_CharUnits size = cast(TB_CharUnits)type_size_of(result); + TB_CharUnits align = cast(TB_CharUnits)type_align_of(result); + params[param_index++] = tb_inst_local(p->func, size, align); + } + + if (pt->calling_convention == ProcCC_Odin) { + cgValue ctx_ptr = cg_find_or_generate_context_ptr(p).addr; + GB_ASSERT(ctx_ptr.kind == cgValue_Value); + params[param_index++] = ctx_ptr.node; + } + GB_ASSERT_MSG(param_index == params.count, "%td vs %td\n %s %u %u", + param_index, params.count, + type_to_string(type), + proto->return_count, + proto->param_count); + + for (TB_Node *param : params) { + GB_ASSERT(param != nullptr); } GB_ASSERT(target != nullptr); TB_MultiOutput multi_output = tb_inst_call(p->func, proto, target, params.count, params.data); gb_unused(multi_output); + + switch (pt->result_count) { + case 0: + return {}; + case 1: + if (return_is_indirect) { + return cg_lvalue_addr(params[0], pt->results->Tuple.variables[0]->type); + } + GB_ASSERT(multi_output.count == 1); + return cg_value(multi_output.single, pt->results->Tuple.variables[0]->type); + } + + + return {}; } diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 6aa906288..2cdedbacf 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -252,7 +252,45 @@ gb_internal void cg_addr_store(cgProcedure *p, cgAddr addr, cgValue value) { } else if (addr.kind == cgAddr_Map) { GB_PANIC("TODO(bill): cgAddr_Map"); } else if (addr.kind == cgAddr_Context) { - GB_PANIC("TODO(bill): cgAddr_Context"); + cgAddr old_addr = cg_find_or_generate_context_ptr(p); + + bool create_new = true; + for_array(i, p->context_stack) { + cgContextData *ctx_data = &p->context_stack[i]; + if (ctx_data->ctx.addr.node == old_addr.addr.node) { + if (ctx_data->uses > 0) { + create_new = true; + } else if (p->scope_index > ctx_data->scope_index) { + create_new = true; + } else { + // gb_printf_err("%.*s (curr:%td) (ctx:%td) (uses:%td)\n", LIT(p->name), p->scope_index, ctx_data->scope_index, ctx_data->uses); + create_new = false; + } + break; + } + } + + cgValue next = {}; + if (create_new) { + cgValue old = cg_addr_load(p, old_addr); + cgAddr next_addr = cg_add_local(p, t_context, nullptr, true); + cg_addr_store(p, next_addr, old); + cg_push_context_onto_stack(p, next_addr); + next = next_addr.addr; + } else { + next = old_addr.addr; + } + + if (addr.ctx.sel.index.count > 0) { + cgValue lhs = cg_emit_deep_field_gep(p, next, addr.ctx.sel); + cgValue rhs = cg_emit_conv(p, value, type_deref(lhs.type)); + cg_emit_store(p, lhs, rhs); + } else { + cgValue lhs = next; + cgValue rhs = cg_emit_conv(p, value, cg_addr_type(addr)); + cg_emit_store(p, lhs, rhs); + } + return; } else if (addr.kind == cgAddr_SoaVariable) { GB_PANIC("TODO(bill): cgAddr_SoaVariable"); } else if (addr.kind == cgAddr_Swizzle) { -- cgit v1.2.3 From b09ea17f0ecbfc30d9f41bd450fd2010820db28c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 22 Jul 2023 08:48:13 +0100 Subject: Support multiple return values for non-odin calling conventions --- src/tilde.hpp | 1 + src/tilde_proc.cpp | 64 +++++++++++++++++++++++++++++++++++++++--------------- src/tilde_stmt.cpp | 14 ++++++++++++ 3 files changed, 61 insertions(+), 18 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde.hpp b/src/tilde.hpp index 633eb63db..d548de78e 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -282,6 +282,7 @@ gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &sr gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init); gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgValue value); +gb_internal cgValue cg_copy_value_to_ptr(cgProcedure *p, cgValue value, Type *original_type, isize min_alignment); gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index ec37617fd..8f7b1972e 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -379,7 +379,6 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice // TODO(bill): Support more than Win64 ABI bool is_odin_like_cc = is_calling_convention_odin(pt->calling_convention); - GB_ASSERT_MSG(is_odin_like_cc, "TODO(bill): non-odin like procedures"); bool return_is_indirect = false; @@ -394,16 +393,19 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice isize param_index = 0; if (pt->result_count != 0) { - Type *last_result = result_entities[result_entities.count-1]->type; - - TB_DebugType *dbg = cg_debug_type(p->module, last_result); + Type *return_type = nullptr; + if (is_odin_like_cc) { + return_type = result_entities[result_entities.count-1]->type; + } else { + return_type = pt->results; + } + TB_DebugType *dbg = cg_debug_type(p->module, return_type); TB_PassingRule rule = tb_get_passing_rule_from_dbg(m, dbg, true); if (rule == TB_PASSING_INDIRECT) { return_is_indirect = true; - TB_CharUnits size = cast(TB_CharUnits)type_size_of(last_result); - TB_CharUnits align = cast(TB_CharUnits)gb_max(type_align_of(last_result), 16); + TB_CharUnits size = cast(TB_CharUnits)type_size_of(return_type); + TB_CharUnits align = cast(TB_CharUnits)gb_max(type_align_of(return_type), 16); TB_Node *local = tb_inst_local(p->func, size, align); - // TODO(bill): Should this need to be zeroed any way? tb_inst_memzero(p->func, local, tb_inst_uint(p->func, TB_TYPE_INT, size), align, false); params[param_index++] = local; } @@ -424,8 +426,13 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice break; case TB_PASSING_INDIRECT: { + cgValue arg_ptr = {}; // indirect - cgValue arg_ptr = cg_address_from_load_or_generate_local(p, arg); + if (is_odin_like_cc) { + arg_ptr = cg_address_from_load_or_generate_local(p, arg); + } else { + arg_ptr = cg_copy_value_to_ptr(p, arg, param_type, 16); + } GB_ASSERT(arg_ptr.kind == cgValue_Value); param = arg_ptr.node; } @@ -438,15 +445,18 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice } // Split returns - isize split_offset = param_index; - for (isize i = 0; i < pt->result_count-1; i++) { - Type *result = result_entities[i]->type; - TB_CharUnits size = cast(TB_CharUnits)type_size_of(result); - TB_CharUnits align = cast(TB_CharUnits)gb_max(type_align_of(result), 16); - TB_Node *local = tb_inst_local(p->func, size, align); - // TODO(bill): Should this need to be zeroed any way? - tb_inst_memzero(p->func, local, tb_inst_uint(p->func, TB_TYPE_INT, size), align, false); - params[param_index++] = local; + isize split_offset = -1; + if (is_odin_like_cc) { + split_offset = param_index; + for (isize i = 0; i < pt->result_count-1; i++) { + Type *result = result_entities[i]->type; + TB_CharUnits size = cast(TB_CharUnits)type_size_of(result); + TB_CharUnits align = cast(TB_CharUnits)gb_max(type_align_of(result), 16); + TB_Node *local = tb_inst_local(p->func, size, align); + // TODO(bill): Should this need to be zeroed any way? + tb_inst_memzero(p->func, local, tb_inst_uint(p->func, TB_TYPE_INT, size), align, false); + params[param_index++] = local; + } } if (pt->calling_convention == ProcCC_Odin) { @@ -483,6 +493,7 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice multi->values = slice_make(permanent_allocator(), pt->result_count); if (is_odin_like_cc) { + GB_ASSERT(split_offset >= 0); for (isize i = 0; i < pt->result_count-1; i++) { multi->values[i] = cg_lvalue_addr(params[split_offset+i], result_entities[i]->type); } @@ -506,7 +517,24 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice } } } else { - GB_PANIC("TODO non-odin like multiple return stuff"); + TB_Node *the_tuple = {}; + if (return_is_indirect) { + the_tuple = params[0]; + } else { + GB_ASSERT(multi_output.count == 1); + TB_Node *res = multi_output.single; + + // struct-like returns passed in registers + TB_CharUnits size = cast(TB_CharUnits)type_size_of(pt->results); + TB_CharUnits align = cast(TB_CharUnits)type_align_of(pt->results); + the_tuple = tb_inst_local(p->func, size, align); + tb_inst_store(p->func, res->dt, the_tuple, res, align, false); + } + for (isize i = 0; i < pt->result_count; i++) { + i64 offset = type_offset_of(pt->results, i, nullptr); + TB_Node *ptr = tb_inst_member_access(p->func, the_tuple, offset); + multi->values[i] = cg_lvalue_addr(ptr, result_entities[i]->type); + } } return cg_value_multi(multi, pt->results); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 2cdedbacf..f0203e724 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -736,6 +736,20 @@ gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero return addr; } +gb_internal cgValue cg_copy_value_to_ptr(cgProcedure *p, cgValue value, Type *original_type, isize min_alignment) { + TB_CharUnits size = cast(TB_CharUnits)type_size_of(original_type); + TB_CharUnits align = cast(TB_CharUnits)gb_max(type_align_of(original_type), min_alignment); + TB_Node *copy = tb_inst_local(p->func, size, align); + if (value.kind == cgValue_Value) { + tb_inst_store(p->func, cg_data_type(original_type), copy, value.node, align, false); + } else { + GB_ASSERT(value.kind == cgValue_Addr); + tb_inst_memcpy(p->func, copy, value.node, tb_inst_uint(p->func, TB_TYPE_INT, size), align, false); + } + + return cg_value(copy, alloc_type_pointer(original_type)); +} + gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgValue value) { switch (value.kind) { case cgValue_Value: -- cgit v1.2.3 From 6c12156b1a47cb3c39e5c12d443e482af2a218bb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 22 Jul 2023 11:16:29 +0100 Subject: Simplify procedure argument handling --- src/tilde.cpp | 1 + src/tilde.hpp | 5 +-- src/tilde/tb.h | 3 +- src/tilde/tb.lib | Bin 4162738 -> 4157412 bytes src/tilde_const.cpp | 2 +- src/tilde_expr.cpp | 2 +- src/tilde_proc.cpp | 113 +++++++++++++++++++++++++++++++++++++++------------- src/tilde_stmt.cpp | 5 ++- 8 files changed, 95 insertions(+), 36 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde.cpp b/src/tilde.cpp index 1969deaec..26bd69f4f 100644 --- a/src/tilde.cpp +++ b/src/tilde.cpp @@ -75,6 +75,7 @@ gb_internal TB_DataType cg_data_type(Type *t) { case Basic_f32be: return TB_TYPE_F32; case Basic_f64be: return TB_TYPE_F64; } + break; case Type_Pointer: case Type_MultiPointer: diff --git a/src/tilde.hpp b/src/tilde.hpp index f0e45bb97..0e5b3b551 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -166,9 +166,6 @@ struct cgProcedure { TB_FunctionPrototype *proto; TB_Symbol *symbol; - // includes parameters, pointers to return values, and context ptr - Slice param_nodes; - Entity * entity; cgModule *module; String name; @@ -309,11 +306,11 @@ gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgV gb_internal bool cg_emit_goto(cgProcedure *p, TB_Node *control_region); - gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name); gb_internal isize cg_append_tuple_values(cgProcedure *p, Array *dst_values, cgValue src_value); +gb_internal cgValue cg_handle_param_value(cgProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos); gb_internal cgValue cg_builtin_len(cgProcedure *p, cgValue value); gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &x); \ No newline at end of file diff --git a/src/tilde/tb.h b/src/tilde/tb.h index 8e5bc5567..abe3c5a1a 100644 --- a/src/tilde/tb.h +++ b/src/tilde/tb.h @@ -83,7 +83,6 @@ typedef enum TB_ABI { typedef enum TB_OutputFlavor { TB_FLAVOR_OBJECT, // .o .obj - TB_FLAVOR_ASSEMBLY, // .s .asm TB_FLAVOR_SHARED, // .so .dll TB_FLAVOR_STATIC, // .a .lib TB_FLAVOR_EXECUTABLE, // .exe @@ -951,7 +950,7 @@ TB_API TB_Node* tb_inst_sint(TB_Function* f, TB_DataType dt, int64_t imm); TB_API TB_Node* tb_inst_uint(TB_Function* f, TB_DataType dt, uint64_t imm); TB_API TB_Node* tb_inst_float32(TB_Function* f, float imm); TB_API TB_Node* tb_inst_float64(TB_Function* f, double imm); -TB_API TB_Node* tb_inst_cstring(TB_Function* f, const char* srt); +TB_API TB_Node* tb_inst_cstring(TB_Function* f, const char* str); TB_API TB_Node* tb_inst_string(TB_Function* f, size_t len, const char* str); // write 'val' over 'count' bytes on 'dst' diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index b9b9dbd44..a3c6ba044 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index e066c72a3..6b1fb5c92 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -851,7 +851,7 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac TB_Node *node = tb_inst_get_symbol_address(p->func, symbol); return cg_lvalue_addr(node, type); } else { - return cg_value(symbol, type); + return cg_value(symbol, alloc_type_pointer(type)); } } diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index c0ddc4e70..3d9054803 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -179,7 +179,7 @@ gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type) TB_DataType dt = cg_data_type(type); switch (value.kind) { case cgValue_Value: - GB_ASSERT_MSG(!TB_IS_VOID_TYPE(dt), "%s", type_to_string(type)); + GB_ASSERT_MSG(!TB_IS_VOID_TYPE(dt), "%d %s -> %s", dt.type, type_to_string(value.type), type_to_string(type)); value.type = type; if (value.node->dt.raw != dt.raw) { value.node = tb_inst_bitcast(p->func, value.node, dt); diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 8016e4dba..7c7bda197 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -89,11 +89,9 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i if (p->symbol == nullptr) { p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE); - size_t out_param_count = 0; p->debug_type = cg_debug_type_for_proc(m, p->type); - TB_Node **params = tb_function_set_prototype_from_dbg(p->func, p->debug_type, cg_arena(), &out_param_count); - p->param_nodes = {params, cast(isize)out_param_count}; - p->proto = tb_function_get_prototype(p->func); + p->proto = tb_prototype_from_dbg(m->mod, p->debug_type); + tb_function_set_prototype(p->func, p->proto, cg_arena()); p->symbol = cast(TB_Symbol *)p->func; } @@ -142,12 +140,9 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE); - size_t out_param_count = 0; p->debug_type = cg_debug_type_for_proc(m, p->type); - TB_Node **params = tb_function_set_prototype_from_dbg(p->func, p->debug_type, cg_arena(), &out_param_count); - p->param_nodes = {params, cast(isize)out_param_count}; - p->proto = tb_function_get_prototype(p->func); - + p->proto = tb_prototype_from_dbg(m->mod, p->debug_type); + tb_function_set_prototype(p->func, p->proto, cg_arena()); p->symbol = cast(TB_Symbol *)p->func; @@ -179,25 +174,59 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { GB_ASSERT(p->type->kind == Type_Proc); TypeProc *pt = &p->type->Proc; + bool is_odin_like_cc = is_calling_convention_odin(pt->calling_convention); int param_index = 0; + int param_count = p->proto->param_count; + + if (pt->results) { + Type *result_type = nullptr; + if (is_odin_like_cc) { + result_type = pt->results->Tuple.variables[pt->results->Tuple.variables.count-1]->type; + } else { + result_type = pt->results; + } + TB_DebugType *debug_type = cg_debug_type(p->module, result_type); + TB_PassingRule rule = tb_get_passing_rule_from_dbg(p->module->mod, debug_type, true); + if (rule == TB_PASSING_INDIRECT) { + param_index++; + } + } + if (pt->params != nullptr) for (Entity *e : pt->params->Tuple.variables) { if (e->kind != Entity_Variable) { continue; } - if (param_index >= p->param_nodes.count) { + GB_ASSERT_MSG(param_index < param_count, "%d < %d %.*s :: %s", param_index, param_count, LIT(p->name), type_to_string(p->type)); + + TB_Node *param_ptr = nullptr; + + TB_CharUnits size = cast(TB_CharUnits)type_size_of(e->type); + TB_CharUnits align = cast(TB_CharUnits)type_align_of(e->type); + TB_DebugType *debug_type = cg_debug_type(p->module, e->type); + TB_PassingRule rule = tb_get_passing_rule_from_dbg(p->module->mod, debug_type, false); + switch (rule) { + case TB_PASSING_DIRECT: { + TB_Node *param = tb_inst_param(p->func, param_index++); + param_ptr = tb_inst_local(p->func, size, align); + tb_inst_store(p->func, param->dt, param_ptr, param, align, false); + } break; + case TB_PASSING_INDIRECT: + // TODO(bill): does this need a copy? for non-odin calling convention stuff? + param_ptr = tb_inst_param(p->func, param_index++); break; + case TB_PASSING_IGNORE: + continue; } - TB_Node *param = p->param_nodes[param_index++]; - cgValue local = cg_value(param, alloc_type_pointer(e->type)); + GB_ASSERT(param_ptr->dt.type == TB_PTR); + + cgValue local = cg_value(param_ptr, alloc_type_pointer(e->type)); if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { // NOTE(bill): for debugging purposes only String name = e->token.string; - TB_DebugType *debug_type = cg_debug_type(p->module, e->type); - tb_node_append_attrib(param, tb_function_attrib_variable(p->func, name.len, cast(char const *)name.text, debug_type)); - + tb_node_append_attrib(param_ptr, tb_function_attrib_variable(p->func, name.len, cast(char const *)name.text, debug_type)); } cgAddr addr = cg_addr(local); if (e) { @@ -243,7 +272,9 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { // } } - if (p->type->Proc.calling_convention == ProcCC_Odin) { + // isize split_offset = param_index; + + if (pt->calling_convention == ProcCC_Odin) { // NOTE(bill): Push context on to stack from implicit parameter String name = str_lit("__.context_ptr"); @@ -251,10 +282,8 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { Entity *e = alloc_entity_param(nullptr, make_token_ident(name), t_context_ptr, false, false); e->flags |= EntityFlag_NoAlias; - TB_Node *param = p->param_nodes[p->param_nodes.count-1]; - param = tb_inst_load(p->func, TB_TYPE_PTR, param, cast(TB_CharUnits)build_context.ptr_size, false); - - cgValue local = cg_value(param, t_context_ptr); + TB_Node *param_ptr = tb_inst_param(p->func, param_count-1); + cgValue local = cg_value(param_ptr, t_context_ptr); cgAddr addr = cg_addr(local); map_set(&p->variable_map, e, addr); @@ -264,6 +293,26 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { cd->scope_index = -1; cd->uses = +1; // make sure it has been used already } + + if (pt->has_named_results) { + auto const &results = pt->results->Tuple.variables; + for_array(i, results) { + Entity *e = results[i]; + GB_ASSERT(e->kind == Entity_Variable); + + if (e->token.string == "") { + continue; + } + GB_ASSERT(!is_blank_ident(e->token)); + + cgAddr res = cg_add_local(p, e->type, e, true); + + if (e->Variable.param_value.kind != ParameterValue_Invalid) { + cgValue c = cg_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos); + cg_addr_store(p, res, c); + } + } + } } gb_internal void cg_procedure_end(cgProcedure *p) { @@ -276,7 +325,8 @@ gb_internal void cg_procedure_end(cgProcedure *p) { bool emit_asm = false; // if (p->name == "main") { if ( - p->name == "bug" ABI_PKG_NAME_SEPARATOR "main" || + p->name == "runtime" ABI_PKG_NAME_SEPARATOR "print_string" || + // p->name == "bug" ABI_PKG_NAME_SEPARATOR "main" || // p->name == "main" || false ) { @@ -301,18 +351,27 @@ gb_internal void cg_procedure_end(cgProcedure *p) { } } +gb_global String procedures_to_generate_list[] = { + str_lit("bug" ABI_PKG_NAME_SEPARATOR "main"), + str_lit("main"), +}; + gb_internal void cg_procedure_generate(cgProcedure *p) { if (p->body == nullptr) { return; } - cg_procedure_begin(p); - defer (cg_procedure_end(p)); - if (p->name != "bug" ABI_PKG_NAME_SEPARATOR "main" && - p->name != "main") { - return; + if ( + p->name == "runtime" ABI_PKG_NAME_SEPARATOR "print_string" || + // p->name == "bug" ABI_PKG_NAME_SEPARATOR "main" || + // p->name == "main" || + false + ) { + cg_procedure_begin(p); + cg_build_stmt(p, p->body); } - cg_build_stmt(p, p->body); + + cg_procedure_end(p); } diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index f0203e724..4fc00dd28 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -914,7 +914,10 @@ gb_internal void cg_build_assignment(cgProcedure *p, Array const &lvals, } Type *type = cg_addr_type(lval); - GB_ASSERT(are_types_identical(type, init.type)); + if (!cg_addr_is_empty(lval)) { + GB_ASSERT_MSG(are_types_identical(init.type, type), "%s = %s", type_to_string(init.type), type_to_string(type)); + } + if (init.kind == cgValue_Addr && !cg_addr_is_empty(lval)) { // NOTE(bill): This is needed for certain constructs such as this: -- cgit v1.2.3 From d82c2ce50ff37ca624d32208f2e0249966b5542d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 22 Jul 2023 12:21:29 +0100 Subject: Update Tilde; Add `min` and `max` --- src/tilde.hpp | 2 ++ src/tilde/tb.lib | Bin 4157412 -> 4162054 bytes src/tilde_builtin.cpp | 38 +++++++++++++++++++++ src/tilde_debug.cpp | 5 ++- src/tilde_expr.cpp | 69 ++++++++++++++++++++----------------- src/tilde_proc.cpp | 49 ++++++++++++++------------- src/tilde_stmt.cpp | 92 +++++++++++++++++++++++++++++++++++++++++--------- 7 files changed, 184 insertions(+), 71 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde.hpp b/src/tilde.hpp index 0e5b3b551..b8434ce4b 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -196,6 +196,8 @@ struct cgProcedure { Scope *curr_scope; i32 scope_index; bool in_multi_assignment; + isize split_returns_index; + bool return_by_ptr; PtrMap variable_map; diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index a3c6ba044..f50666cff 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_builtin.cpp b/src/tilde_builtin.cpp index 08c3f7bdd..d6e161ec3 100644 --- a/src/tilde_builtin.cpp +++ b/src/tilde_builtin.cpp @@ -91,6 +91,18 @@ gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &value) { return res; } +gb_internal cgValue cg_builtin_min(cgProcedure *p, Type *t, cgValue x, cgValue y) { + x = cg_emit_conv(p, x, t); + y = cg_emit_conv(p, y, t); + return cg_emit_select(p, cg_emit_comp(p, Token_Lt, x, y), x, y); +} +gb_internal cgValue cg_builtin_max(cgProcedure *p, Type *t, cgValue x, cgValue y) { + x = cg_emit_conv(p, x, t); + y = cg_emit_conv(p, y, t); + return cg_emit_select(p, cg_emit_comp(p, Token_Gt, x, y), x, y); +} + + gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr) { ast_node(ce, CallExpr, expr); @@ -137,6 +149,32 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr return cg_builtin_len(p, v); } + case BuiltinProc_min: + if (ce->args.count == 2) { + Type *t = type_of_expr(expr); + return cg_builtin_min(p, t, cg_build_expr(p, ce->args[0]), cg_build_expr(p, ce->args[1])); + } else { + Type *t = type_of_expr(expr); + cgValue x = cg_build_expr(p, ce->args[0]); + for (isize i = 1; i < ce->args.count; i++) { + x = cg_builtin_min(p, t, x, cg_build_expr(p, ce->args[i])); + } + return x; + } + break; + case BuiltinProc_max: + if (ce->args.count == 2) { + Type *t = type_of_expr(expr); + return cg_builtin_max(p, t, cg_build_expr(p, ce->args[0]), cg_build_expr(p, ce->args[1])); + } else { + Type *t = type_of_expr(expr); + cgValue x = cg_build_expr(p, ce->args[0]); + for (isize i = 1; i < ce->args.count; i++) { + x = cg_builtin_max(p, t, x, cg_build_expr(p, ce->args[i])); + } + return x; + } + break; } diff --git a/src/tilde_debug.cpp b/src/tilde_debug.cpp index e3b45ff1b..21594ef07 100644 --- a/src/tilde_debug.cpp +++ b/src/tilde_debug.cpp @@ -1,5 +1,7 @@ gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type); gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type) { + type = reduce_tuple_to_single_type(type); + mutex_lock(&m->debug_type_mutex); defer (mutex_unlock(&m->debug_type_mutex)); TB_DebugType **found = map_get(&m->debug_type_map, type); @@ -235,7 +237,8 @@ gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type) { case Basic_uint: return tb_debug_get_integer(m->mod, is_signed, bits); case Basic_uintptr: return tb_debug_get_integer(m->mod, is_signed, bits); - case Basic_rawptr: return tb_debug_create_ptr(m->mod, tb_debug_get_void(m->mod)); + case Basic_rawptr: + return tb_debug_create_ptr(m->mod, tb_debug_get_void(m->mod)); case Basic_string: { String name = basic_types[type->Basic.kind].Basic.name; diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 3d9054803..b6dbce181 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -15,6 +15,15 @@ gb_internal cgValue cg_flatten_value(cgProcedure *p, cgValue value) { return value; } +gb_internal cgValue cg_emit_select(cgProcedure *p, cgValue const &cond, cgValue const &x, cgValue const &y) { + GB_ASSERT(x.kind == y.kind); + GB_ASSERT(cond.kind == cgValue_Value); + cgValue res = x; + res.node = tb_inst_select(p->func, cond.node, x.node, y.node); + return res; +} + + gb_internal bool cg_is_expr_untyped_const(Ast *expr) { auto const &tv = type_and_value_of_expr(expr); if (is_type_untyped(tv.type)) { @@ -1724,36 +1733,35 @@ gb_internal cgValue cg_build_binary_expr(cgProcedure *p, Ast *expr) { case Token_CmpEq: case Token_NotEq: - GB_PANIC("TODO(bill): comparisons"); - // if (is_type_untyped_nil(be->right->tav.type)) { - // // `x == nil` or `x != nil` - // cgValue left = cg_build_expr(p, be->left); - // cgValue cmp = cg_emit_comp_against_nil(p, be->op.kind, left); - // Type *type = default_type(tv.type); - // return cg_emit_conv(p, cmp, type); - // } else if (is_type_untyped_nil(be->left->tav.type)) { - // // `nil == x` or `nil != x` - // cgValue right = cg_build_expr(p, be->right); - // cgValue cmp = cg_emit_comp_against_nil(p, be->op.kind, right); - // Type *type = default_type(tv.type); - // return cg_emit_conv(p, cmp, type); - // } else if (cg_is_empty_string_constant(be->right)) { - // // `x == ""` or `x != ""` - // cgValue s = cg_build_expr(p, be->left); - // s = cg_emit_conv(p, s, t_string); - // cgValue len = cg_string_len(p, s); - // cgValue cmp = cg_emit_comp(p, be->op.kind, len, cg_const_int(p->module, t_int, 0)); - // Type *type = default_type(tv.type); - // return cg_emit_conv(p, cmp, type); - // } else if (cg_is_empty_string_constant(be->left)) { - // // `"" == x` or `"" != x` - // cgValue s = cg_build_expr(p, be->right); - // s = cg_emit_conv(p, s, t_string); - // cgValue len = cg_string_len(p, s); - // cgValue cmp = cg_emit_comp(p, be->op.kind, len, cg_const_int(p->module, t_int, 0)); - // Type *type = default_type(tv.type); - // return cg_emit_conv(p, cmp, type); - // } + if (is_type_untyped_nil(be->right->tav.type)) { + // `x == nil` or `x != nil` + cgValue left = cg_build_expr(p, be->left); + cgValue cmp = cg_emit_comp_against_nil(p, be->op.kind, left); + Type *type = default_type(tv.type); + return cg_emit_conv(p, cmp, type); + } else if (is_type_untyped_nil(be->left->tav.type)) { + // `nil == x` or `nil != x` + cgValue right = cg_build_expr(p, be->right); + cgValue cmp = cg_emit_comp_against_nil(p, be->op.kind, right); + Type *type = default_type(tv.type); + return cg_emit_conv(p, cmp, type); + }/* else if (cg_is_empty_string_constant(be->right)) { + // `x == ""` or `x != ""` + cgValue s = cg_build_expr(p, be->left); + s = cg_emit_conv(p, s, t_string); + cgValue len = cg_string_len(p, s); + cgValue cmp = cg_emit_comp(p, be->op.kind, len, cg_const_int(p->module, t_int, 0)); + Type *type = default_type(tv.type); + return cg_emit_conv(p, cmp, type); + } else if (cg_is_empty_string_constant(be->left)) { + // `"" == x` or `"" != x` + cgValue s = cg_build_expr(p, be->right); + s = cg_emit_conv(p, s, t_string); + cgValue len = cg_string_len(p, s); + cgValue cmp = cg_emit_comp(p, be->op.kind, len, cg_const_int(p->module, t_int, 0)); + Type *type = default_type(tv.type); + return cg_emit_conv(p, cmp, type); + }*/ /*fallthrough*/ case Token_Lt: case Token_LtEq: @@ -2255,7 +2263,6 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { token_pos_to_string(token.pos)); return {}; } else if (e->kind == Entity_Nil) { - GB_PANIC("TODO: cg_find_ident nil"); // TODO(bill): is this correct? return cg_value(cast(TB_Node *)nullptr, e->type); } diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 7c7bda197..41c185dc6 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -63,6 +63,7 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i p->is_foreign = entity->Procedure.is_foreign; p->is_export = entity->Procedure.is_export; p->is_entry_point = false; + p->split_returns_index = -1; gbAllocator a = heap_allocator(); p->children.allocator = a; @@ -122,6 +123,7 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li p->is_foreign = false; p->is_export = false; p->is_entry_point = false; + p->split_returns_index = -1; gbAllocator a = heap_allocator(); p->children.allocator = a; @@ -188,6 +190,7 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { TB_DebugType *debug_type = cg_debug_type(p->module, result_type); TB_PassingRule rule = tb_get_passing_rule_from_dbg(p->module->mod, debug_type, true); if (rule == TB_PASSING_INDIRECT) { + p->return_by_ptr = true; param_index++; } } @@ -272,7 +275,7 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { // } } - // isize split_offset = param_index; + p->split_returns_index = param_index; if (pt->calling_convention == ProcCC_Odin) { // NOTE(bill): Push context on to stack from implicit parameter @@ -323,24 +326,6 @@ gb_internal void cg_procedure_end(cgProcedure *p) { tb_inst_ret(p->func, 0, nullptr); } bool emit_asm = false; - // if (p->name == "main") { - if ( - p->name == "runtime" ABI_PKG_NAME_SEPARATOR "print_string" || - // p->name == "bug" ABI_PKG_NAME_SEPARATOR "main" || - // p->name == "main" || - false - ) { - TB_Arena *arena = tb_default_arena(); - defer (arena->free(arena)); - TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena); - defer (tb_funcopt_exit(opt)); - tb_funcopt_print(opt); - - // emit_asm = true; - - // GraphViz printing - // tb_function_print(p->func, tb_default_print_callback, stdout); - } TB_FunctionOutput *output = tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST, emit_asm); if (emit_asm) { TB_Assembly *assembly = tb_output_get_asm(output); @@ -361,17 +346,33 @@ gb_internal void cg_procedure_generate(cgProcedure *p) { return; } + bool build_body = false; + if ( - p->name == "runtime" ABI_PKG_NAME_SEPARATOR "print_string" || + string_starts_with(p->name, str_lit("runtime" ABI_PKG_NAME_SEPARATOR "_os_write")) || // p->name == "bug" ABI_PKG_NAME_SEPARATOR "main" || // p->name == "main" || false ) { + build_body = true; + } + + if (build_body) { cg_procedure_begin(p); cg_build_stmt(p, p->body); } - cg_procedure_end(p); + + if (build_body) { + TB_Arena *arena = tb_default_arena(); + defer (arena->free(arena)); + TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena); + defer (tb_funcopt_exit(opt)); + tb_funcopt_print(opt); + + // GraphViz printing + // tb_function_print(p->func, tb_default_print_callback, stdout); + } } @@ -543,9 +544,11 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice case 1: if (return_is_indirect) { return cg_lvalue_addr(params[0], pt->results->Tuple.variables[0]->type); + } else { + GB_ASSERT(multi_output.count == 1); + TB_Node *node = multi_output.single; + return cg_value(node, pt->results->Tuple.variables[0]->type); } - GB_ASSERT(multi_output.count == 1); - return cg_value(multi_output.single, pt->results->Tuple.variables[0]->type); } cgValueMulti *multi = gb_alloc_item(permanent_allocator(), cgValueMulti); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 4fc00dd28..074d2674c 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1011,31 +1011,91 @@ gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) { gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return_results) { TypeTuple *tuple = &p->type->Proc.results->Tuple; isize return_count = p->type->Proc.result_count; - gb_unused(tuple); - isize res_count = return_results.count; - gb_unused(res_count); if (return_count == 0) { tb_inst_ret(p->func, 0, nullptr); return; - } else if (return_count == 1) { - Entity *e = tuple->variables[0]; - if (res_count == 0) { - cgValue zero = cg_const_nil(p, tuple->variables[0]->type); - if (zero.kind == cgValue_Value) { - tb_inst_ret(p->func, 1, &zero.node); + } + TEMPORARY_ALLOCATOR_GUARD(); + + auto results = array_make(temporary_allocator(), 0, return_count); + + if (return_results.count != 0) { + for (isize i = 0; i < return_results.count; i++) { + cgValue res = cg_build_expr(p, return_results[i]); + cg_append_tuple_values(p, &results, res); + } + } else { + for_array(i, tuple->variables) { + Entity *e = tuple->variables[i]; + cgAddr addr = map_must_get(&p->variable_map, e); + cgValue res = cg_addr_load(p, addr); + array_add(&results, res); + } + } + GB_ASSERT(results.count == return_count); + + if (return_results.count != 0 && p->type->Proc.has_named_results) { + // NOTE(bill): store the named values before returning + for_array(i, tuple->variables) { + Entity *e = tuple->variables[i]; + cgAddr addr = map_must_get(&p->variable_map, e); + cg_addr_store(p, addr, results[i]); + } + } + for_array(i, tuple->variables) { + Entity *e = tuple->variables[i]; + results[i] = cg_emit_conv(p, results[i], e->type); + } + + + if (p->split_returns_index >= 0) { + GB_ASSERT(is_calling_convention_odin(p->type->Proc.calling_convention)); + + for (isize i = 0; i < return_count-1; i++) { + Entity *e = tuple->variables[i]; + TB_Node *ret_ptr = tb_inst_param(p->func, cast(int)(p->split_returns_index+i)); + cgValue ptr = cg_value(ret_ptr, alloc_type_pointer(e->type)); + cg_emit_store(p, ptr, results[i]); + } + + if (p->return_by_ptr) { + Entity *e = tuple->variables[return_count-1]; + TB_Node *ret_ptr = tb_inst_param(p->func, 0); + cgValue ptr = cg_value(ret_ptr, alloc_type_pointer(e->type)); + cg_emit_store(p, ptr, results[return_count-1]); + + tb_inst_ret(p->func, 0, nullptr); + return; + } else { + GB_ASSERT(p->proto->return_count == 1); + TB_DataType dt = TB_PROTOTYPE_RETURNS(p->proto)->dt; + + cgValue result = cg_flatten_value(p, results[0]); + TB_Node *final_res = nullptr; + if (result.kind == cgValue_Addr) { + TB_CharUnits align = cast(TB_CharUnits)type_align_of(result.type); + final_res = tb_inst_load(p->func, dt, result.node, align, false); + } else { + GB_ASSERT(result.kind == cgValue_Value); + if (result.node->dt.raw == dt.raw) { + final_res = result.node; + } else { + final_res = tb_inst_bitcast(p->func, result.node, dt); + } } + GB_ASSERT(final_res != nullptr); + + tb_inst_ret(p->func, 1, &final_res); return; } - cgValue res = cg_build_expr(p, return_results[0]); - res = cg_emit_conv(p, res, e->type); - if (res.kind == cgValue_Value) { - tb_inst_ret(p->func, 1, &res.node); - } - return; + } else { - GB_PANIC("TODO(bill): MUTLIPLE RETURN VALUES"); + GB_ASSERT(!is_calling_convention_odin(p->type->Proc.calling_convention)); } + + + GB_PANIC("TODO(bill): %.*s MUTLIPLE RETURN VALUES %td %td", LIT(p->name), results.count, return_results.count); } gb_internal void cg_build_if_stmt(cgProcedure *p, Ast *node) { -- cgit v1.2.3 From 99c812b02d31d8f827e299ff7bb4a5d0c59bed4b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 23 Jul 2023 12:21:27 +0100 Subject: Begin working on a minimum build --- src/checker.cpp | 3 + src/tilde.cpp | 44 ++- src/tilde.hpp | 9 +- src/tilde/tb.lib | Bin 4162054 -> 4163308 bytes src/tilde_builtin.cpp | 133 +++++++ src/tilde_const.cpp | 109 ++++-- src/tilde_debug.cpp | 6 +- src/tilde_expr.cpp | 932 +++++++++++++++++++++++++++++++++++++++++++------- src/tilde_proc.cpp | 102 ++++-- src/tilde_stmt.cpp | 273 ++++++++++++--- 10 files changed, 1355 insertions(+), 256 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/checker.cpp b/src/checker.cpp index 01b8b6b2a..21fa80d9f 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1046,6 +1046,7 @@ gb_internal void init_universal(void) { add_global_bool_constant("ODIN_NO_RTTI", bc->no_rtti); add_global_bool_constant("ODIN_VALGRIND_SUPPORT", bc->ODIN_VALGRIND_SUPPORT); + add_global_bool_constant("ODIN_TILDE", bc->tilde_backend); add_global_constant("ODIN_COMPILE_TIMESTAMP", t_untyped_integer, exact_value_i64(odin_compile_timestamp())); @@ -2311,7 +2312,9 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("memory_equal"), str_lit("memory_compare"), str_lit("memory_compare_zero"), + ); + FORCE_ADD_RUNTIME_ENTITIES(!build_context.tilde_backend, // Extended data type internal procedures str_lit("umodti3"), str_lit("udivti3"), diff --git a/src/tilde.cpp b/src/tilde.cpp index 26bd69f4f..ff2a540f5 100644 --- a/src/tilde.cpp +++ b/src/tilde.cpp @@ -126,6 +126,19 @@ gb_internal cgValue cg_lvalue_addr(TB_Node *node, Type *type) { return v; } +gb_internal cgValue cg_lvalue_addr_to_value(cgValue v) { + if (v.kind == cgValue_Value) { + GB_ASSERT(is_type_pointer(v.type)); + GB_ASSERT(v.node->dt.type == TB_PTR); + } else { + GB_ASSERT(v.kind == cgValue_Addr); + GB_ASSERT(v.node->dt.type == TB_PTR); + v.kind = cgValue_Value; + v.type = alloc_type_pointer(v.type); + } + return v; +} + gb_internal cgValue cg_value_multi(cgValueMulti *multi, Type *type) { GB_ASSERT(type->kind == Type_Tuple); GB_ASSERT(multi != nullptr); @@ -138,6 +151,24 @@ gb_internal cgValue cg_value_multi(cgValueMulti *multi, Type *type) { return v; } +gb_internal cgValue cg_value_multi(Slice const &values, Type *type) { + cgValueMulti *multi = gb_alloc_item(permanent_allocator(), cgValueMulti); + multi->values = values; + return cg_value_multi(multi, type); +} + + +gb_internal cgValue cg_value_multi2(cgValue const &x, cgValue const &y, Type *type) { + GB_ASSERT(type->kind == Type_Tuple); + GB_ASSERT(type->Tuple.variables.count == 2); + cgValueMulti *multi = gb_alloc_item(permanent_allocator(), cgValueMulti); + multi->values = slice_make(permanent_allocator(), 2); + multi->values[0] = x; + multi->values[1] = y; + return cg_value_multi(multi, type); +} + + gb_internal cgAddr cg_addr(cgValue const &value) { GB_ASSERT(value.kind != cgValue_Multi); cgAddr addr = {}; @@ -151,10 +182,21 @@ gb_internal cgAddr cg_addr(cgValue const &value) { return addr; } +gb_internal void cg_set_debug_pos_from_node(cgProcedure *p, Ast *node) { + if (node) { + TokenPos pos = ast_token(node).pos; + TB_FileID *file_id = map_get(&p->module->file_id_map, cast(uintptr)pos.file_id); + if (file_id) { + tb_inst_set_location(p->func, *file_id, pos.line); + } + } +} + gb_internal void cg_add_entity(cgModule *m, Entity *e, cgValue const &val) { if (e) { rw_mutex_lock(&m->values_mutex); + GB_ASSERT(val.node != nullptr); map_set(&m->values, e, val); rw_mutex_unlock(&m->values_mutex); } @@ -744,7 +786,7 @@ gb_internal bool cg_generate_code(Checker *c) { } TB_DebugFormat debug_format = TB_DEBUGFMT_NONE; - if (build_context.ODIN_DEBUG) { + if (build_context.ODIN_DEBUG || true) { switch (build_context.metrics.os) { case TargetOs_windows: debug_format = TB_DEBUGFMT_CODEVIEW; diff --git a/src/tilde.hpp b/src/tilde.hpp index b8434ce4b..8a29d4c90 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -272,6 +272,7 @@ gb_internal void cg_build_when_stmt(cgProcedure *p, AstWhenStmt *ws); gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr); gb_internal cgAddr cg_build_addr(cgProcedure *p, Ast *expr); gb_internal cgValue cg_build_addr_ptr(cgProcedure *p, Ast *expr); +gb_internal cgValue cg_build_cond(cgProcedure *p, Ast *cond, TB_Node *true_block, TB_Node *false_block); gb_internal Type * cg_addr_type(cgAddr const &addr); gb_internal cgValue cg_addr_load(cgProcedure *p, cgAddr addr); @@ -279,13 +280,15 @@ gb_internal void cg_addr_store(cgProcedure *p, cgAddr addr, cgValue value); gb_internal cgValue cg_addr_get_ptr(cgProcedure *p, cgAddr const &addr); gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile=false); -gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile=false); +gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue src, bool is_volatile=false); gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init); gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgValue value); gb_internal cgValue cg_copy_value_to_ptr(cgProcedure *p, cgValue value, Type *original_type, isize min_alignment); gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); +gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return_results); +gb_internal void cg_build_return_stmt_internal(cgProcedure *p, Slice const &results); gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e); @@ -300,6 +303,7 @@ gb_internal cgValue cg_emit_array_ep(cgProcedure *p, cgValue s, cgValue index); gb_internal cgValue cg_emit_array_epi(cgProcedure *p, cgValue s, i64 index); gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index); gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection const &sel); +gb_internal cgValue cg_emit_struct_ev(cgProcedure *p, cgValue s, i64 index); gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t); gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, cgValue x); @@ -315,4 +319,5 @@ gb_internal isize cg_append_tuple_values(cgProcedure *p, Array *dst_val gb_internal cgValue cg_handle_param_value(cgProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos); gb_internal cgValue cg_builtin_len(cgProcedure *p, cgValue value); -gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &x); \ No newline at end of file +gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &x); + diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index f50666cff..936675fda 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_builtin.cpp b/src/tilde_builtin.cpp index d6e161ec3..c55cfbb75 100644 --- a/src/tilde_builtin.cpp +++ b/src/tilde_builtin.cpp @@ -61,6 +61,7 @@ gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &value) { cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); cgValue data_ptr = cg_emit_struct_ep(p, ptr, 0); res = cg_emit_load(p, data_ptr); + GB_ASSERT(is_type_multi_pointer(res.type)); } break; case Type_DynamicArray: @@ -82,7 +83,12 @@ gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &value) { } break; case Type_Pointer: + GB_ASSERT(is_type_array_like(t->Pointer.elem)); + GB_ASSERT(value.kind == cgValue_Value); + res = cg_value(value.node, alloc_type_multi_pointer(base_array_type(t->Pointer.elem))); + break; case Type_MultiPointer: + GB_PANIC("TODO(bill) %s", type_to_string(value.type)); // res = cg_emit_conv(p, value, tv.type); break; @@ -102,6 +108,37 @@ gb_internal cgValue cg_builtin_max(cgProcedure *p, Type *t, cgValue x, cgValue y return cg_emit_select(p, cg_emit_comp(p, Token_Gt, x, y), x, y); } +gb_internal cgValue cg_builtin_abs(cgProcedure *p, cgValue x) { + if (is_type_unsigned(x.type)) { + return x; + } + + if (is_type_quaternion(x.type)) { + GB_PANIC("TODO(bill): abs quaternion"); + } else if (is_type_complex(x.type)) { + GB_PANIC("TODO(bill): abs complex"); + } + + TB_DataType dt = cg_data_type(x.type); + GB_ASSERT(!TB_IS_VOID_TYPE(dt)); + TB_Node *zero = nullptr; + if (dt.type == TB_FLOAT) { + if (dt.data == 32) { + zero = tb_inst_float32(p->func, 0); + } else if (dt.data == 64) { + zero = tb_inst_float64(p->func, 0); + } + } else { + zero = tb_inst_uint(p->func, dt, 0); + } + GB_ASSERT(zero != nullptr); + + cgValue cond = cg_emit_comp(p, Token_Lt, x, cg_value(zero, x.type)); + cgValue neg = cg_emit_unary_arith(p, Token_Sub, x, x.type); + return cg_emit_select(p, cond, neg, x); +} + + gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr) { ast_node(ce, CallExpr, expr); @@ -149,6 +186,12 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr return cg_builtin_len(p, v); } + case BuiltinProc_raw_data: + { + cgValue v = cg_build_expr(p, ce->args[0]); + return cg_builtin_raw_data(p, v); + } + case BuiltinProc_min: if (ce->args.count == 2) { Type *t = type_of_expr(expr); @@ -176,6 +219,96 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr } break; + case BuiltinProc_abs: + { + cgValue x = cg_build_expr(p, ce->args[0]); + return cg_builtin_abs(p, x); + } + + case BuiltinProc_debug_trap: + tb_inst_debugbreak(p->func); + return {}; + case BuiltinProc_trap: + tb_inst_trap(p->func); + return {}; + + case BuiltinProc_mem_zero: + { + cgValue ptr = cg_build_expr(p, ce->args[0]); + cgValue len = cg_build_expr(p, ce->args[1]); + GB_ASSERT(ptr.kind == cgValue_Value); + GB_ASSERT(len.kind == cgValue_Value); + tb_inst_memzero(p->func, ptr.node, len.node, 1, false); + return {}; + } + + case BuiltinProc_mem_copy: + { + cgValue dst = cg_build_expr(p, ce->args[0]); + cgValue src = cg_build_expr(p, ce->args[1]); + cgValue len = cg_build_expr(p, ce->args[2]); + GB_ASSERT(dst.kind == cgValue_Value); + GB_ASSERT(src.kind == cgValue_Value); + GB_ASSERT(len.kind == cgValue_Value); + // TODO(bill): This needs to be memmove + tb_inst_memcpy(p->func, dst.node, src.node, len.node, 1, false); + return {}; + } + + case BuiltinProc_mem_copy_non_overlapping: + { + cgValue dst = cg_build_expr(p, ce->args[0]); + cgValue src = cg_build_expr(p, ce->args[1]); + cgValue len = cg_build_expr(p, ce->args[2]); + GB_ASSERT(dst.kind == cgValue_Value); + GB_ASSERT(src.kind == cgValue_Value); + GB_ASSERT(len.kind == cgValue_Value); + tb_inst_memcpy(p->func, dst.node, src.node, len.node, 1, false); + return {}; + } + + + case BuiltinProc_overflow_add: + { + Type *res_type = type_of_expr(expr); + GB_ASSERT(res_type->kind == Type_Tuple); + GB_ASSERT(res_type->Tuple.variables.count == 2); + // TODO(bill): do a proper overflow add + Type *type = res_type->Tuple.variables[0]->type; + Type *ok_type = res_type->Tuple.variables[1]->type; + cgValue x = cg_build_expr(p, ce->args[0]); + cgValue y = cg_build_expr(p, ce->args[1]); + x = cg_emit_conv(p, x, type); + y = cg_emit_conv(p, y, type); + cgValue res = cg_emit_arith(p, Token_Add, x, y, type); + cgValue ok = cg_const_int(p, ok_type, false); + + return cg_value_multi2(res, ok, res_type); + } + + + case BuiltinProc_ptr_offset: + { + cgValue ptr = cg_build_expr(p, ce->args[0]); + cgValue len = cg_build_expr(p, ce->args[1]); + len = cg_emit_conv(p, len, t_int); + return cg_emit_ptr_offset(p, ptr, len); + } + case BuiltinProc_ptr_sub: + { + Type *elem0 = type_deref(type_of_expr(ce->args[0])); + Type *elem1 = type_deref(type_of_expr(ce->args[1])); + GB_ASSERT(are_types_identical(elem0, elem1)); + Type *elem = elem0; + + cgValue ptr0 = cg_emit_conv(p, cg_build_expr(p, ce->args[0]), t_uintptr); + cgValue ptr1 = cg_emit_conv(p, cg_build_expr(p, ce->args[1]), t_uintptr); + + cgValue diff = cg_emit_arith(p, Token_Sub, ptr0, ptr1, t_uintptr); + diff = cg_emit_conv(p, diff, t_int); + return cg_emit_arith(p, Token_Quo, diff, cg_const_int(p, t_int, type_size_of(elem)), t_int); + } + } diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index 6b1fb5c92..bb4a294a5 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -52,6 +52,13 @@ gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type) { } +gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, String const &proc_name, TokenPos pos) { + // TODO(bill): cg_emit_source_code_location_as_global + return cg_const_nil(p, t_source_code_location); +} + + + gb_internal void cg_write_big_int_at_ptr(void *dst, BigInt const *a, Type *original_type) { GB_ASSERT(build_context.endian_kind == TargetEndian_Little); size_t sz = cast(size_t)type_size_of(original_type); @@ -109,7 +116,6 @@ gb_internal TB_Global *cg_global_const_string(cgModule *m, String const &str, Ty char name[32] = {}; gb_snprintf(name, 31, "csb$%u", 1+m->const_nil_guid.fetch_add(1)); - TB_Global *str_global = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); i64 size = str.len+1; tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_global, size, 1, 1); @@ -125,6 +131,7 @@ gb_internal TB_Global *cg_global_const_string(cgModule *m, String const &str, Ty } if (global == nullptr) { + gb_snprintf(name, 31, "cstr$%u", 1+m->const_nil_guid.fetch_add(1)); global = tb_global_create(m->mod, -1, name, cg_debug_type(m, type), TB_LINKAGE_PRIVATE); tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, type_size_of(type), type_align_of(type), 2); } @@ -778,18 +785,47 @@ gb_internal TB_Global *cg_global_const_comp_literal(cgModule *m, Type *original_ } -gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, ExactValue const &value) { +gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value) { + GB_ASSERT(p != nullptr); TB_Node *node = nullptr; + if (is_type_untyped(type)) { + // TODO(bill): THIS IS A COMPLETE HACK, WHY DOES THIS NOT A TYPE? + GB_ASSERT(type->kind == Type_Basic); + switch (type->Basic.kind) { + case Basic_UntypedBool: + type = t_bool; + break; + case Basic_UntypedInteger: + type = t_i64; + break; + case Basic_UntypedFloat: + type = t_f64; + break; + case Basic_UntypedComplex: + type = t_complex128; + break; + case Basic_UntypedQuaternion: + type = t_quaternion256; + break; + case Basic_UntypedString: + type = t_string; + break; + case Basic_UntypedRune: + type = t_rune; + break; + case Basic_UntypedNil: + case Basic_UntypedUninit: + return cg_value(cast(TB_Node *)nullptr, type); + } + } TB_DataType dt = cg_data_type(type); switch (value.kind) { case ExactValue_Invalid: - GB_ASSERT(p != nullptr); return cg_const_nil(p, type); case ExactValue_Typeid: - GB_ASSERT(p != nullptr); return cg_typeid(p, value.value_typeid); case ExactValue_Procedure: @@ -797,13 +833,13 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac Ast *expr = unparen_expr(value.value_procedure); Entity *e = entity_of_node(expr); if (e != nullptr) { - cgValue found = cg_find_procedure_value_from_entity(m, e); - GB_ASSERT(are_types_identical(type, found.type)); + cgValue found = cg_find_procedure_value_from_entity(p->module, e); + GB_ASSERT_MSG(are_types_identical(type, found.type), + "%.*s %s == %s", + LIT(p->name), + type_to_string(type), type_to_string(found.type)); GB_ASSERT(found.kind == cgValue_Symbol); - if (p) { - return cg_flatten_value(p, found); - } - return found; + return cg_flatten_value(p, found); } GB_PANIC("TODO(bill): cg_const_value ExactValue_Procedure"); } @@ -812,12 +848,10 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac switch (value.kind) { case ExactValue_Bool: - GB_ASSERT(p != nullptr); GB_ASSERT(!TB_IS_VOID_TYPE(dt)); return cg_value(tb_inst_uint(p->func, dt, value.value_bool), type); case ExactValue_Integer: - GB_ASSERT(p != nullptr); GB_ASSERT(!TB_IS_VOID_TYPE(dt)); // GB_ASSERT(dt.raw != TB_TYPE_I128.raw); if (is_type_unsigned(type)) { @@ -830,7 +864,6 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac break; case ExactValue_Float: - GB_ASSERT(p != nullptr); GB_ASSERT(!TB_IS_VOID_TYPE(dt)); GB_ASSERT(dt.raw != TB_TYPE_F16.raw); GB_ASSERT(!is_type_different_to_arch_endianness(type)); @@ -846,13 +879,36 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac case ExactValue_String: { - TB_Symbol *symbol = cast(TB_Symbol *)cg_global_const_string(m, value.value_string, type, nullptr, 0); - if (p) { - TB_Node *node = tb_inst_get_symbol_address(p->func, symbol); - return cg_lvalue_addr(node, type); - } else { - return cg_value(symbol, alloc_type_pointer(type)); + GB_ASSERT(is_type_string(type)); + cgModule *m = p->module; + + String str = value.value_string; + + char name[32] = {}; + gb_snprintf(name, 31, "csb$%u", 1+m->const_nil_guid.fetch_add(1)); + TB_Global *cstr_global = tb_global_create(m->mod, -1, name, nullptr, TB_LINKAGE_PRIVATE); + i64 size = str.len+1; + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), cstr_global, size, 1, 1); + u8 *data = cast(u8 *)tb_global_add_region(m->mod, cstr_global, 0, size); + gb_memcopy(data, str.text, str.len); + data[str.len] = 0; + + if (is_type_cstring(type)) { + cgValue s = cg_value(cstr_global, type); + return cg_flatten_value(p, s); } + + gb_snprintf(name, 31, "str$%u", 1+m->const_nil_guid.fetch_add(1)); + TB_Global *str_global = tb_global_create(m->mod, -1, name, cg_debug_type(m, type), TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_global, type_size_of(type), type_align_of(type), 2); + + tb_global_add_symbol_reloc(m->mod, str_global, 0, cast(TB_Symbol *)cstr_global); + void *len_ptr = tb_global_add_region(m->mod, str_global, build_context.int_size, build_context.int_size); + cg_write_int_at_ptr(len_ptr, str.len, t_int); + + TB_Node *s = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)str_global); + return cg_lvalue_addr(s, type); + } case ExactValue_Pointer: @@ -860,13 +916,9 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac case ExactValue_Compound: { - TB_Symbol *symbol = cast(TB_Symbol *)cg_global_const_comp_literal(m, type, value, nullptr, 0); - if (p) { - TB_Node *node = tb_inst_get_symbol_address(p->func, symbol); - return cg_lvalue_addr(node, type); - } else { - return cg_value(symbol, type); - } + TB_Symbol *symbol = cast(TB_Symbol *)cg_global_const_comp_literal(p->module, type, value, nullptr, 0); + TB_Node *node = tb_inst_get_symbol_address(p->func, symbol); + return cg_lvalue_addr(node, type); } break; } @@ -876,11 +928,6 @@ gb_internal cgValue cg_const_value(cgModule *m, cgProcedure *p, Type *type, Exac return cg_value(node, type); } -gb_internal cgValue cg_const_value(cgProcedure *p, Type *type, ExactValue const &value) { - GB_ASSERT(p != nullptr); - return cg_const_value(p->module, p, type, value); -} - gb_internal cgValue cg_const_int(cgProcedure *p, Type *type, i64 i) { return cg_const_value(p, type, exact_value_i64(i)); } diff --git a/src/tilde_debug.cpp b/src/tilde_debug.cpp index 21594ef07..e6e60be96 100644 --- a/src/tilde_debug.cpp +++ b/src/tilde_debug.cpp @@ -368,7 +368,11 @@ gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type) { param_count += 1; } - TB_DebugType *func = tb_debug_create_func(m->mod, TB_CDECL, param_count, return_count, pt->c_vararg); + TB_CallingConv tb_cc = TB_CDECL; + if (pt->calling_convention == ProcCC_StdCall) { + tb_cc = TB_STDCALL; + } + TB_DebugType *func = tb_debug_create_func(m->mod, tb_cc, param_count, return_count, pt->c_vararg); map_set(&m->proc_debug_type_map, original_type, func); map_set(&m->proc_debug_type_map, type, func); diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index b6dbce181..822c637ca 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -648,21 +648,22 @@ gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, break; case Basic_any: { - GB_PANIC("TODO(bill): cg_emit_struct_ev"); + GB_ASSERT(x.kind == cgValue_Addr); // // TODO(bill): is this correct behaviour for nil comparison for any? - // cgValue data = cg_emit_struct_ev(p, x, 0); - // cgValue ti = cg_emit_struct_ev(p, x, 1); - // if (op_kind == Token_CmpEq) { - // LLVMValueRef a = LLVMBuildIsNull(p->builder, data.value, ""); - // LLVMValueRef b = LLVMBuildIsNull(p->builder, ti.value, ""); - // res.value = LLVMBuildOr(p->builder, a, b, ""); - // return res; - // } else if (op_kind == Token_NotEq) { - // LLVMValueRef a = LLVMBuildIsNotNull(p->builder, data.value, ""); - // LLVMValueRef b = LLVMBuildIsNotNull(p->builder, ti.value, ""); - // res.value = LLVMBuildAnd(p->builder, a, b, ""); - // return res; - // } + cgValue data = cg_emit_struct_ev(p, x, 0); + cgValue id = cg_emit_struct_ev(p, x, 1); + + if (op_kind == Token_CmpEq) { + TB_Node *a = tb_inst_cmp_eq(p->func, data.node, tb_inst_uint(p->func, data.node->dt, 0)); + TB_Node *b = tb_inst_cmp_eq(p->func, id.node, tb_inst_uint(p->func, id.node->dt, 0)); + TB_Node *c = tb_inst_or(p->func, a, b); + return cg_value(c, t_bool); + } else if (op_kind == Token_NotEq) { + TB_Node *a = tb_inst_cmp_ne(p->func, data.node, tb_inst_uint(p->func, data.node->dt, 0)); + TB_Node *b = tb_inst_cmp_ne(p->func, id.node, tb_inst_uint(p->func, id.node->dt, 0)); + TB_Node *c = tb_inst_and(p->func, a, b); + return cg_value(c, t_bool); + } } break; case Basic_typeid: @@ -685,64 +686,33 @@ gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, break; case Type_Slice: - { - GB_PANIC("TODO(bill): cg_emit_struct_ev"); - // cgValue data = cg_emit_struct_ev(p, x, 0); - // if (op_kind == Token_CmpEq) { - // res.value = LLVMBuildIsNull(p->builder, data.value, ""); - // return res; - // } else if (op_kind == Token_NotEq) { - // res.value = LLVMBuildIsNotNull(p->builder, data.value, ""); - // return res; - // } - } - break; - case Type_DynamicArray: - { - GB_PANIC("TODO(bill): cg_emit_struct_ev"); - // cgValue data = cg_emit_struct_ev(p, x, 0); - // if (op_kind == Token_CmpEq) { - // res.value = LLVMBuildIsNull(p->builder, data.value, ""); - // return res; - // } else if (op_kind == Token_NotEq) { - // res.value = LLVMBuildIsNotNull(p->builder, data.value, ""); - // return res; - // } - } - break; - case Type_Map: { - GB_PANIC("TODO(bill): cg_emit_struct_ev"); - // cgValue data_ptr = cg_emit_struct_ev(p, x, 0); - - // if (op_kind == Token_CmpEq) { - // res.value = LLVMBuildIsNull(p->builder, data_ptr.value, ""); - // return res; - // } else { - // res.value = LLVMBuildIsNotNull(p->builder, data_ptr.value, ""); - // return res; - // } + // NOTE(bill): all of their data "pointer-like" fields are at the 0-index + cgValue data = cg_emit_struct_ev(p, x, 0); + if (op_kind == Token_CmpEq) { + TB_Node *a = tb_inst_cmp_eq(p->func, data.node, tb_inst_uint(p->func, data.node->dt, 0)); + return cg_value(a, t_bool); + } else if (op_kind == Token_NotEq) { + TB_Node *a = tb_inst_cmp_ne(p->func, data.node, tb_inst_uint(p->func, data.node->dt, 0)); + return cg_value(a, t_bool); + } } break; case Type_Union: { - GB_PANIC("TODO(bill): cg_emit_struct_ev"); - // if (type_size_of(t) == 0) { - // if (op_kind == Token_CmpEq) { - // return cg_const_bool(p->module, t_bool, true); - // } else if (op_kind == Token_NotEq) { - // return cg_const_bool(p->module, t_bool, false); - // } - // } else if (is_type_union_maybe_pointer(t)) { - // cgValue tag = cg_emit_transmute(p, x, t_rawptr); - // return cg_emit_comp_against_nil(p, op_kind, tag); - // } else { - // cgValue tag = cg_emit_union_tag_value(p, x); - // return cg_emit_comp(p, op_kind, tag, cg_zero(p->module, tag.type)); - // } + if (type_size_of(t) == 0) { + return cg_const_bool(p, t_bool, op_kind == Token_CmpEq); + } else if (is_type_union_maybe_pointer(t)) { + cgValue tag = cg_emit_transmute(p, x, t_rawptr); + return cg_emit_comp_against_nil(p, op_kind, tag); + } else { + GB_ASSERT("TODO(bill): cg_emit_union_tag_value"); + // cgValue tag = cg_emit_union_tag_value(p, x); + // return cg_emit_comp(p, op_kind, tag, cg_zero(p->module, tag.type)); + } } break; case Type_Struct: @@ -1311,6 +1281,17 @@ handle_op:; } +gb_internal void cg_fill_slice(cgProcedure *p, cgAddr const &slice, cgValue data, cgValue len) { + cgValue slice_ptr = cg_addr_get_ptr(p, slice); + cgValue data_ptr = cg_emit_struct_ep(p, slice_ptr, 0); + cgValue len_ptr = cg_emit_struct_ep(p, slice_ptr, 1); + + data = cg_emit_conv(p, data, type_deref(data_ptr.type)); + len = cg_emit_conv(p, len, t_int); + cg_emit_store(p, data_ptr, data); + cg_emit_store(p, len_ptr, len); +} + gb_internal cgAddr cg_build_addr_slice_expr(cgProcedure *p, Ast *expr) { ast_node(se, SliceExpr, expr); @@ -1338,23 +1319,28 @@ gb_internal cgAddr cg_build_addr_slice_expr(cgProcedure *p, Ast *expr) { } switch (type->kind) { + case Type_Basic: case Type_Slice: { - // Type *slice_type = type; - // cgValue len = cg_slice_len(p, base); - // if (high.value == nullptr) high = len; + if (type->kind == Type_Basic) { + GB_ASSERT(type->Basic.kind == Basic_string); + } - // if (!no_indices) { - // cg_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - // } + Type *slice_type = type; + if (high.node == nullptr) { + cgValue len = cg_builtin_len(p, base); + high = len; + } - // cgValue elem = cg_emit_ptr_offset(p, cg_slice_elem(p, base), low); - // cgValue new_len = cg_emit_arith(p, Token_Sub, high, low, t_int); + if (!no_indices) { + // cg_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } - // cgAddr slice = cg_add_local_generated(p, slice_type, false); - // cg_fill_slice(p, slice, elem, new_len); - // return slice; - GB_PANIC("cg_build_addr_slice_expr Type_Slice"); - break; + cgValue elem = cg_emit_ptr_offset(p, cg_builtin_raw_data(p, base), low); + cgValue new_len = cg_emit_arith(p, Token_Sub, high, low, t_int); + + cgAddr slice = cg_add_local(p, slice_type, nullptr, true); + cg_fill_slice(p, slice, elem, new_len); + return slice; } case Type_RelativeSlice: @@ -1414,46 +1400,24 @@ gb_internal cgAddr cg_build_addr_slice_expr(cgProcedure *p, Ast *expr) { } case Type_Array: { - // Type *slice_type = alloc_type_slice(type->Array.elem); - // lbValue len = lb_const_int(p->module, t_int, type->Array.count); - - // if (high.value == nullptr) high = len; + Type *slice_type = type_of_expr(expr); + GB_ASSERT(is_type_slice(slice_type)); + cgValue len = cg_const_int(p, t_int, type->Array.count); + if (high.node == nullptr) high = len; // bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant; // bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant; - // if (!low_const || !high_const) { // if (!no_indices) { // lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); // } // } - // lbValue elem = lb_emit_ptr_offset(p, lb_array_elem(p, lb_addr_get_ptr(p, addr)), low); - // lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + cgValue elem = cg_emit_ptr_offset(p, cg_builtin_raw_data(p, cg_addr_get_ptr(p, addr)), low); + cgValue new_len = cg_emit_arith(p, Token_Sub, high, low, t_int); - // lbAddr slice = lb_add_local_generated(p, slice_type, false); - // lb_fill_slice(p, slice, elem, new_len); - // return slice; - GB_PANIC("cg_build_addr_slice_expr Type_Array"); - break; - } - - case Type_Basic: { - // GB_ASSERT(type == t_string); - // lbValue len = lb_string_len(p, base); - // if (high.value == nullptr) high = len; - - // if (!no_indices) { - // lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - // } - - // lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low); - // lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - // lbAddr str = lb_add_local_generated(p, t_string, false); - // lb_fill_string(p, str, elem, new_len); - // return str; - GB_PANIC("cg_build_addr_slice_expr Type_Basic"); - break; + cgAddr slice = cg_add_local(p, slice_type, nullptr, true); + cg_fill_slice(p, slice, elem, new_len); + return slice; } @@ -1685,6 +1649,207 @@ gb_internal cgValue cg_emit_unary_arith(cgProcedure *p, TokenKind op, cgValue x, return res; } +gb_internal void cg_emit_if(cgProcedure *p, cgValue const &cond, TB_Node *true_region, TB_Node *false_region) { + GB_ASSERT(cond.kind == cgValue_Value); + tb_inst_if(p->func, cond.node, true_region, false_region); +} + +gb_internal void cg_build_try_lhs_rhs(cgProcedure *p, Ast *arg, Type *final_type, cgValue *lhs_, cgValue *rhs_) { + cgValue lhs = {}; + cgValue rhs = {}; + + cgValue value = cg_build_expr(p, arg); + if (value.kind == cgValue_Multi) { + auto const &values = value.multi->values; + if (values.count == 2) { + lhs = values[0]; + rhs = values[1]; + } else { + rhs = values[values.count-1]; + if (values.count > 1) { + lhs = cg_value_multi(slice(values, 0, values.count-1), final_type); + } + } + } else { + rhs = value; + } + + GB_ASSERT(rhs.node != nullptr); + + if (lhs_) *lhs_ = lhs; + if (rhs_) *rhs_ = rhs; +} + +gb_internal cgValue cg_emit_try_has_value(cgProcedure *p, cgValue rhs) { + cgValue has_value = {}; + if (is_type_boolean(rhs.type)) { + has_value = rhs; + } else { + GB_ASSERT_MSG(type_has_nil(rhs.type), "%s", type_to_string(rhs.type)); + has_value = cg_emit_comp_against_nil(p, Token_CmpEq, rhs); + } + GB_ASSERT(has_value.node != nullptr); + return has_value; +} + +gb_internal cgValue cg_build_or_return(cgProcedure *p, Ast *arg, Type *final_type) { + cgValue lhs = {}; + cgValue rhs = {}; + cg_build_try_lhs_rhs(p, arg, final_type, &lhs, &rhs); + + TB_Node *return_region = cg_control_region(p, "or_return_return"); + TB_Node *continue_region = cg_control_region(p, "or_return_continue"); + + cgValue cond = cg_emit_try_has_value(p, rhs); + cg_emit_if(p, cond, continue_region, return_region); + tb_inst_set_control(p->func, return_region); + { + Type *proc_type = base_type(p->type); + Type *results = proc_type->Proc.results; + GB_ASSERT(results != nullptr && results->kind == Type_Tuple); + TypeTuple *tuple = &results->Tuple; + + GB_ASSERT(tuple->variables.count != 0); + + Entity *end_entity = tuple->variables[tuple->variables.count-1]; + rhs = cg_emit_conv(p, rhs, end_entity->type); + if (p->type->Proc.has_named_results) { + GB_ASSERT(end_entity->token.string.len != 0); + + // NOTE(bill): store the named values before returning + cgAddr found = map_must_get(&p->variable_map, end_entity); + cg_addr_store(p, found, rhs); + + cg_build_return_stmt(p, {}); + } else { + GB_ASSERT(tuple->variables.count == 1); + Slice results = {}; + results.data = &rhs; + results.count = 1;; + cg_build_return_stmt_internal(p, results); + } + } + tb_inst_set_control(p->func, continue_region); + if (final_type != nullptr && !is_type_tuple(final_type)) { + return cg_emit_conv(p, lhs, final_type); + } + return {}; +} + +gb_internal cgValue cg_build_or_else(cgProcedure *p, Ast *arg, Ast *else_expr, Type *final_type) { + if (arg->state_flags & StateFlag_DirectiveWasFalse) { + return cg_build_expr(p, else_expr); + } + + cgValue lhs = {}; + cgValue rhs = {}; + cg_build_try_lhs_rhs(p, arg, final_type, &lhs, &rhs); + + GB_ASSERT(else_expr != nullptr); + + if (is_diverging_expr(else_expr)) { + TB_Node *then = cg_control_region(p, "or_else_then"); + TB_Node *else_ = cg_control_region(p, "or_else_else"); + + cg_emit_if(p, cg_emit_try_has_value(p, rhs), then, else_); + // NOTE(bill): else block needs to be straight afterwards to make sure that the actual value is used + // from the then block + tb_inst_set_control(p->func, else_); + + cg_build_expr(p, else_expr); + + tb_inst_set_control(p->func, then); + return cg_emit_conv(p, lhs, final_type); + } else { + TB_Node *incoming_values[2] = {}; + TB_Node *incoming_regions[2] = {}; + + TB_Node *then = cg_control_region(p, "or_else_then"); + TB_Node *done = cg_control_region(p, "or_else_done"); // NOTE(bill): Append later + TB_Node *else_ = cg_control_region(p, "or_else_else"); + + cg_emit_if(p, cg_emit_try_has_value(p, rhs), then, else_); + tb_inst_set_control(p->func, then); + + cgValue x = cg_emit_conv(p, lhs, final_type); + incoming_values[0] = x.node; + incoming_regions[0] = tb_inst_get_control(p->func); + + tb_inst_goto(p->func, done); + tb_inst_set_control(p->func, else_); + + cgValue y = cg_emit_conv(p, cg_build_expr(p, else_expr), final_type); + incoming_values[1] = y.node; + incoming_regions[1] = tb_inst_get_control(p->func); + + tb_inst_goto(p->func, done); + tb_inst_set_control(p->func, done); + + GB_ASSERT(x.kind == y.kind); + GB_ASSERT(incoming_values[0]->dt.raw == incoming_values[1]->dt.raw); + cgValue res = {}; + res.kind = x.kind; + res.type = final_type; + + res.node = tb_inst_incomplete_phi(p->func, incoming_values[0]->dt, done, 2); + tb_inst_add_phi_operand(p->func, res.node, incoming_regions[0], incoming_values[0]); + tb_inst_add_phi_operand(p->func, res.node, incoming_regions[1], incoming_values[1]); + return res; + } +} + + +gb_internal isize cg_control_region_pred_count(TB_Node *region) { + GB_ASSERT(region->type == TB_REGION); + GB_ASSERT(region->input_count > 0); + return region->input_count; +} + +gb_internal cgValue cg_build_logical_binary_expr(cgProcedure *p, TokenKind op, Ast *left, Ast *right, Type *final_type) { + TB_Node *rhs = cg_control_region(p, "logical_cmp_rhs"); + TB_Node *done = cg_control_region(p, "logical_cmp_done"); + + cgValue short_circuit = {}; + if (op == Token_CmpAnd) { + cg_build_cond(p, left, rhs, done); + short_circuit = cg_const_bool(p, t_bool, false); + } else if (op == Token_CmpOr) { + cg_build_cond(p, left, done, rhs); + short_circuit = cg_const_bool(p, t_bool, true); + } + + if (rhs->input_count == 0) { + tb_inst_set_control(p->func, done); + return cg_emit_conv(p, short_circuit, final_type); + } + + if (done->input_count == 0) { + tb_inst_set_control(p->func, rhs); + return cg_build_expr(p, right); + } + + tb_inst_set_control(p->func, rhs); + cgValue edge = cg_build_expr(p, right); + TB_Node *edge_region = tb_inst_get_control(p->func); + + tb_inst_goto(p->func, done); + tb_inst_set_control(p->func, done); + + TB_DataType dt = edge.node->dt; + TB_Node *phi = tb_inst_incomplete_phi(p->func, dt, done, done->input_count); + for (size_t i = 0; i < done->input_count; i++) { + TB_Node *val = short_circuit.node; + TB_Node *region = done->inputs[i]; + if (region == edge_region) { + val = edge.node; + } + tb_inst_add_phi_operand(p->func, phi, region, val); + } + return cg_emit_conv(p, cg_value(phi, t_bool), final_type); +} + + + gb_internal cgValue cg_build_binary_expr(cgProcedure *p, Ast *expr) { ast_node(be, BinaryExpr, expr); @@ -1786,8 +1951,7 @@ gb_internal cgValue cg_build_binary_expr(cgProcedure *p, Ast *expr) { case Token_CmpAnd: case Token_CmpOr: - GB_PANIC("TODO(bill): cg_emit_logical_binary_expr"); - // return cg_emit_logical_binary_expr(p, be->op.kind, be->left, be->right, tv.type); + return cg_build_logical_binary_expr(p, be->op.kind, be->left, be->right, tv.type); case Token_in: case Token_not_in: @@ -1896,15 +2060,14 @@ gb_internal cgValue cg_build_cond(cgProcedure *p, Ast *cond, TB_Node *true_block } else { v = cg_build_expr(p, cond); } - - GB_ASSERT(v.kind == cgValue_Value); - tb_inst_if(p->func, v.node, true_block, false_block); - + cg_emit_if(p, v, true_block, false_block); return v; } gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr); gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr) { + cg_set_debug_pos_from_node(p, expr); + u16 prev_state_flags = p->state_flags; defer (p->state_flags = prev_state_flags); @@ -2003,6 +2166,468 @@ gb_internal cgValue cg_find_ident(cgProcedure *p, Entity *e, Ast *expr) { return {}; } +cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) { + struct cgCompoundLitElemTempData { + Ast * expr; + cgValue value; + i64 elem_index; + i64 elem_length; + cgValue gep; + }; + + + auto const &populate = [](cgProcedure *p, Slice const &elems, Array *temp_data, Type *compound_type) { + Type *bt = base_type(compound_type); + Type *et = nullptr; + switch (bt->kind) { + case Type_Array: et = bt->Array.elem; break; + case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; + case Type_Slice: et = bt->Slice.elem; break; + case Type_BitSet: et = bt->BitSet.elem; break; + case Type_DynamicArray: et = bt->DynamicArray.elem; break; + case Type_SimdVector: et = bt->SimdVector.elem; break; + case Type_Matrix: et = bt->Matrix.elem; break; + } + GB_ASSERT(et != nullptr); + + + // NOTE(bill): Separate value, gep, store into their own chunks + for_array(i, elems) { + Ast *elem = elems[i]; + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op != Token_RangeHalf) { + hi += 1; + } + + cgValue value = cg_emit_conv(p, cg_build_expr(p, fv->value), et); + + GB_ASSERT((hi-lo) > 0); + + if (bt->kind == Type_Matrix) { + GB_PANIC("TODO(bill): Type_Matrix"); + // for (i64 k = lo; k < hi; k++) { + // cgCompoundLitElemTempData data = {}; + // data.value = value; + + // data.elem_index = matrix_row_major_index_to_offset(bt, k); + // array_add(temp_data, data); + // } + } else { + enum {MAX_ELEMENT_AMOUNT = 32}; + if ((hi-lo) <= MAX_ELEMENT_AMOUNT) { + for (i64 k = lo; k < hi; k++) { + cgCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = k; + array_add(temp_data, data); + } + } else { + cgCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = lo; + data.elem_length = hi-lo; + array_add(temp_data, data); + } + } + } else { + auto tav = fv->field->tav; + GB_ASSERT(tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(tav.value); + + cgValue value = cg_emit_conv(p, cg_build_expr(p, fv->value), et); + GB_ASSERT(!is_type_tuple(value.type)); + + cgCompoundLitElemTempData data = {}; + data.value = value; + data.expr = fv->value; + if (bt->kind == Type_Matrix) { + GB_PANIC("TODO(bill): Type_Matrix"); + // data.elem_index = matrix_row_major_index_to_offset(bt, index); + } else { + data.elem_index = index; + } + array_add(temp_data, data); + } + + } else { + // if (bt->kind != Type_DynamicArray && lb_is_elem_const(elem, et)) { + // continue; + // } + + cgValue field_expr = cg_build_expr(p, elem); + GB_ASSERT(!is_type_tuple(field_expr.type)); + + cgValue ev = cg_emit_conv(p, field_expr, et); + + cgCompoundLitElemTempData data = {}; + data.value = ev; + if (bt->kind == Type_Matrix) { + GB_PANIC("TODO(bill): Type_Matrix"); + // data.elem_index = matrix_row_major_index_to_offset(bt, i); + } else { + data.elem_index = i; + } + array_add(temp_data, data); + } + } + }; + + auto const &assign_array = [](cgProcedure *p, Array const &temp_data) { + for (auto const &td : temp_data) if (td.value.node != nullptr) { + if (td.elem_length > 0) { + GB_PANIC("TODO(bill): range"); + // auto loop_data = cg_loop_start(p, cast(isize)td.elem_length, t_i32); + // { + // cgValue dst = td.gep; + // dst = cg_emit_ptr_offset(p, dst, loop_data.idx); + // cg_emit_store(p, dst, td.value); + // } + // cg_loop_end(p, loop_data); + } else { + cg_emit_store(p, td.gep, td.value); + } + } + }; + + + + ast_node(cl, CompoundLit, expr); + + Type *type = type_of_expr(expr); + Type *bt = base_type(type); + + cgAddr v = cg_add_local(p, type, nullptr, true); + + if (cl->elems.count == 0) { + // No need to create it + return v; + } + + TEMPORARY_ALLOCATOR_GUARD(); + + Type *et = nullptr; + switch (bt->kind) { + case Type_Array: et = bt->Array.elem; break; + case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; + case Type_Slice: et = bt->Slice.elem; break; + case Type_BitSet: et = bt->BitSet.elem; break; + case Type_SimdVector: et = bt->SimdVector.elem; break; + case Type_Matrix: et = bt->Matrix.elem; break; + } + + String proc_name = {}; + if (p->entity) { + proc_name = p->entity->token.string; + } + TokenPos pos = ast_token(expr).pos; + + if (cl->elems.count == 0) { + } + + switch (bt->kind) { + default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; + + case Type_Struct: { + TypeStruct *st = &bt->Struct; + cgValue comp_lit_ptr = cg_addr_get_ptr(p, v); + + for_array(field_index, cl->elems) { + Ast *elem = cl->elems[field_index]; + + cgValue field_expr = {}; + Entity *field = nullptr; + isize index = field_index; + + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + String name = fv->field->Ident.token.string; + Selection sel = lookup_field(bt, name, false); + GB_ASSERT(!sel.indirect); + + elem = fv->value; + if (sel.index.count > 1) { + cgValue dst = cg_emit_deep_field_gep(p, comp_lit_ptr, sel); + field_expr = cg_build_expr(p, elem); + field_expr = cg_emit_conv(p, field_expr, sel.entity->type); + cg_emit_store(p, dst, field_expr); + continue; + } + + index = sel.index[0]; + } else { + Selection sel = lookup_field_from_index(bt, st->fields[field_index]->Variable.field_index); + GB_ASSERT(sel.index.count == 1); + GB_ASSERT(!sel.indirect); + index = sel.index[0]; + } + + field = st->fields[index]; + Type *ft = field->type; + + field_expr = cg_build_expr(p, elem); + + cgValue gep = {}; + if (st->is_raw_union) { + gep = cg_emit_conv(p, comp_lit_ptr, alloc_type_pointer(ft)); + } else { + gep = cg_emit_struct_ep(p, comp_lit_ptr, cast(i32)index); + } + + Type *fet = field_expr.type; + GB_ASSERT(fet->kind != Type_Tuple); + + // HACK TODO(bill): THIS IS A MASSIVE HACK!!!! + if (is_type_union(ft) && !are_types_identical(fet, ft) && !is_type_untyped(fet)) { + GB_ASSERT_MSG(union_variant_index(ft, fet) >= 0, "%s", type_to_string(fet)); + + GB_PANIC("TODO(bill): cg_emit_store_union_variant"); + // cg_emit_store_union_variant(p, gep, field_expr, fet); + } else { + cgValue fv = cg_emit_conv(p, field_expr, ft); + cg_emit_store(p, gep, fv); + } + } + return v; + } + + // case Type_Map: { + // GB_ASSERT(!build_context.no_dynamic_literals); + + // cgValue err = cg_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos); + // gb_unused(err); + + // for (Ast *elem : cl->elems) { + // ast_node(fv, FieldValue, elem); + + // cgValue key = cg_build_expr(p, fv->field); + // cgValue value = cg_build_expr(p, fv->value); + // cg_internal_dynamic_map_set(p, v.addr, type, key, value, elem); + // } + // break; + // } + + // case Type_Array: { + // cg_addr_store(p, v, cg_const_value(p->module, type, exact_value_compound(expr))); + + // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + + // populate(p, cl->elems, &temp_data, type); + + // cgValue dst_ptr = cg_addr_get_ptr(p, v); + // for_array(i, temp_data) { + // i32 index = cast(i32)(temp_data[i].elem_index); + // temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, index); + // } + + // assign_array(p, temp_data); + // break; + // } + // case Type_EnumeratedArray: { + // cg_addr_store(p, v, cg_const_value(p->module, type, exact_value_compound(expr))); + + // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + + // populate(p, cl->elems, &temp_data, type); + + // cgValue dst_ptr = cg_addr_get_ptr(p, v); + // i64 index_offset = exact_value_to_i64(*bt->EnumeratedArray.min_value); + // for_array(i, temp_data) { + // i32 index = cast(i32)(temp_data[i].elem_index - index_offset); + // temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, index); + // } + + // assign_array(p, temp_data); + // break; + // } + case Type_Slice: { + isize count = gb_max(cl->elems.count, cl->max_count); + + TB_CharUnits backing_size = cast(TB_CharUnits)(type_size_of(bt->Slice.elem) * count); + TB_CharUnits align = cast(TB_CharUnits)type_align_of(bt->Slice.elem); + TB_Node *backing = tb_inst_local(p->func, backing_size, align); + + cgValue data = cg_value(backing, alloc_type_multi_pointer(bt->Slice.elem)); + + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + populate(p, cl->elems, &temp_data, type); + + + for_array(i, temp_data) { + temp_data[i].gep = cg_emit_ptr_offset(p, data, cg_const_int(p, t_int, temp_data[i].elem_index)); + } + + assign_array(p, temp_data); + cg_fill_slice(p, v, data, cg_const_int(p, t_int, cl->max_count)); + return v; + } + + // case Type_DynamicArray: { + // GB_ASSERT(!build_context.no_dynamic_literals); + + // Type *et = bt->DynamicArray.elem; + // cgValue size = cg_const_int(p->module, t_int, type_size_of(et)); + // cgValue align = cg_const_int(p->module, t_int, type_align_of(et)); + + // i64 item_count = gb_max(cl->max_count, cl->elems.count); + // { + + // auto args = array_make(temporary_allocator(), 5); + // args[0] = cg_emit_conv(p, cg_addr_get_ptr(p, v), t_rawptr); + // args[1] = size; + // args[2] = align; + // args[3] = cg_const_int(p->module, t_int, item_count); + // args[4] = cg_emit_source_code_location_as_global(p, proc_name, pos); + // cg_emit_runtime_call(p, "__dynamic_array_reserve", args); + // } + + // cgValue items = cg_generate_local_array(p, et, item_count); + + // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + // populate(p, cl->elems, &temp_data, type); + + // for_array(i, temp_data) { + // temp_data[i].gep = cg_emit_array_epi(p, items, temp_data[i].elem_index); + // } + // assign_array(p, temp_data); + + // { + // auto args = array_make(temporary_allocator(), 6); + // args[0] = cg_emit_conv(p, v.addr, t_rawptr); + // args[1] = size; + // args[2] = align; + // args[3] = cg_emit_conv(p, items, t_rawptr); + // args[4] = cg_const_int(p->module, t_int, item_count); + // args[5] = cg_emit_source_code_location_as_global(p, proc_name, pos); + // cg_emit_runtime_call(p, "__dynamic_array_append", args); + // } + // break; + // } + + // case Type_Basic: { + // GB_ASSERT(is_type_any(bt)); + // cg_addr_store(p, v, cg_const_value(p->module, type, exact_value_compound(expr))); + // String field_names[2] = { + // str_lit("data"), + // str_lit("id"), + // }; + // Type *field_types[2] = { + // t_rawptr, + // t_typeid, + // }; + + // for_array(field_index, cl->elems) { + // Ast *elem = cl->elems[field_index]; + + // cgValue field_expr = {}; + // isize index = field_index; + + // if (elem->kind == Ast_FieldValue) { + // ast_node(fv, FieldValue, elem); + // Selection sel = lookup_field(bt, fv->field->Ident.token.string, false); + // index = sel.index[0]; + // elem = fv->value; + // } else { + // TypeAndValue tav = type_and_value_of_expr(elem); + // Selection sel = lookup_field(bt, field_names[field_index], false); + // index = sel.index[0]; + // } + + // field_expr = cg_build_expr(p, elem); + + // GB_ASSERT(field_expr.type->kind != Type_Tuple); + + // Type *ft = field_types[index]; + // cgValue fv = cg_emit_conv(p, field_expr, ft); + // cgValue gep = cg_emit_struct_ep(p, cg_addr_get_ptr(p, v), cast(i32)index); + // cg_emit_store(p, gep, fv); + // } + // break; + // } + + case Type_BitSet: { + i64 sz = type_size_of(type); + if (sz == 0) { + return v; + } + cgValue lower = cg_const_value(p, t_int, exact_value_i64(bt->BitSet.lower)); + Type *it = bit_set_to_int(bt); + cgValue one = cg_const_value(p, it, exact_value_i64(1)); + for (Ast *elem : cl->elems) { + GB_ASSERT(elem->kind != Ast_FieldValue); + + cgValue expr = cg_build_expr(p, elem); + GB_ASSERT(expr.type->kind != Type_Tuple); + + cgValue e = cg_emit_conv(p, expr, it); + e = cg_emit_arith(p, Token_Sub, e, lower, it); + e = cg_emit_arith(p, Token_Shl, one, e, it); + + cgValue old_value = cg_emit_transmute(p, cg_addr_load(p, v), it); + cgValue new_value = cg_emit_arith(p, Token_Or, old_value, e, it); + new_value = cg_emit_transmute(p, new_value, type); + cg_addr_store(p, v, new_value); + } + return v; + } + + // case Type_Matrix: { + // cg_addr_store(p, v, cg_const_value(p->module, type, exact_value_compound(expr))); + + // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + + // populate(p, cl->elems, &temp_data, type); + + // cgValue dst_ptr = cg_addr_get_ptr(p, v); + // for_array(i, temp_data) { + // temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, temp_data[i].elem_index); + // } + + // assign_array(p, temp_data); + // break; + // } + + // case Type_SimdVector: { + // cgValue vector_value = cg_const_value(p->module, type, exact_value_compound(expr)); + // defer (cg_addr_store(p, v, vector_value)); + + // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + + // populate(p, cl->elems, &temp_data, type); + + // // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector` + // // might be a better option + // for (auto const &td : temp_data) { + // if (td.value.value != nullptr) { + // if (td.elem_length > 0) { + // for (i64 k = 0; k < td.elem_length; k++) { + // LLVMValueRef index = cg_const_int(p->module, t_u32, td.elem_index + k).value; + // vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, ""); + // } + // } else { + // LLVMValueRef index = cg_const_int(p->module, t_u32, td.elem_index).value; + // vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, ""); + + // } + // } + // } + // break; + // } + } + + return v; +} + gb_internal cgValue cg_build_unary_and(cgProcedure *p, Ast *expr) { ast_node(ue, UnaryExpr, expr); auto tv = type_and_value_of_expr(expr); @@ -2020,12 +2645,12 @@ gb_internal cgValue cg_build_unary_and(cgProcedure *p, Ast *expr) { // GB_ASSERT(t->kind == Type_Map); // ast_node(ie, IndexExpr, ue_expr); - // lbValue map_val = lb_build_addr_ptr(p, ie->expr); + // cgValue map_val = cg_build_addr_ptr(p, ie->expr); // if (deref) { - // map_val = lb_emit_load(p, map_val); + // map_val = cg_emit_load(p, map_val); // } - // lbValue key = lb_build_expr(p, ie->index); + // cgValue key = lb_build_expr(p, ie->index); // key = lb_emit_conv(p, key, t->Map.key); // lbAddr addr = lb_addr_map(map_val, key, t, alloc_type_pointer(t->Map.value)); @@ -2053,18 +2678,8 @@ gb_internal cgValue cg_build_unary_and(cgProcedure *p, Ast *expr) { // return lb_make_soa_pointer(p, tv.type, addr, index); } else if (ue_expr->kind == Ast_CompoundLit) { - cgValue v = cg_build_expr(p, ue->expr); - - Type *type = v.type; - cgAddr addr = {}; - // if (p->is_startup) { - // addr = cg_add_global_generated(p->module, type, v); - // } else { - addr = cg_add_local(p, type, nullptr, false); - // } - cg_addr_store(p, addr, v); + cgAddr addr = cg_build_addr_compound_lit(p, expr); return addr.addr; - } else if (ue_expr->kind == Ast_TypeAssertion) { GB_PANIC("TODO(bill): &v.(T)"); // if (is_type_tuple(tv.type)) { @@ -2225,7 +2840,8 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { Type *type = type_of_expr(expr); GB_ASSERT_MSG(tv.mode != Addressing_Invalid, "invalid expression '%s' (tv.mode = %d, tv.type = %s) @ %s\n Current Proc: %.*s : %s", expr_to_string(expr), tv.mode, type_to_string(tv.type), token_pos_to_string(expr_pos), LIT(p->name), type_to_string(p->type)); - if (tv.value.kind != ExactValue_Invalid) { + if (tv.value.kind != ExactValue_Invalid && + expr->kind != Ast_CompoundLit) { // NOTE(bill): The commented out code below is just for debug purposes only // if (is_type_untyped(type)) { // gb_printf_err("%s %s : %s @ %p\n", token_pos_to_string(expr_pos), expr_to_string(expr), type_to_string(expr->tav.type), expr); @@ -2314,6 +2930,11 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { return cg_build_call_expr(p, expr); case_end; + case_ast_node(cl, CompoundLit, expr); + cgAddr addr = cg_build_addr_compound_lit(p, expr); + return cg_addr_load(p, addr); + case_end; + case_ast_node(te, TernaryIfExpr, expr); cgValue incoming_values[2] = {}; @@ -2413,6 +3034,14 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { case_ast_node(be, BinaryExpr, expr); return cg_build_binary_expr(p, expr); case_end; + + case_ast_node(oe, OrReturnExpr, expr); + return cg_build_or_return(p, oe->expr, tv.type); + case_end; + + case_ast_node(oe, OrElseExpr, expr); + return cg_build_or_else(p, oe->x, oe->y, tv.type); + case_end; } GB_PANIC("TODO(bill): cg_build_expr_internal %.*s", LIT(ast_strings[expr->kind])); return {}; @@ -2580,6 +3209,7 @@ gb_internal cgAddr cg_build_addr_index_expr(cgProcedure *p, Ast *expr) { // cgValue len = cg_builtin_len(p, slice); // cg_emit_bounds_check(p, ast_token(ie->index), index, len); cgValue v = cg_emit_ptr_offset(p, elem, index); + v.type = alloc_type_pointer(type_deref(v.type, true)); return cg_addr(v); } @@ -2592,7 +3222,9 @@ gb_internal cgAddr cg_build_addr_index_expr(cgProcedure *p, Ast *expr) { cgValue index = cg_build_expr(p, ie->index); index = cg_emit_conv(p, index, t_int); - return cg_addr(cg_emit_ptr_offset(p, multi_ptr, index)); + cgValue v = cg_emit_ptr_offset(p, multi_ptr, index); + v.type = alloc_type_pointer(type_deref(v.type, true)); + return cg_addr(v); } case Type_RelativeSlice: { @@ -2624,6 +3256,7 @@ gb_internal cgAddr cg_build_addr_index_expr(cgProcedure *p, Ast *expr) { // cgValue len = cg_dynamic_array_len(p, dynamic_array); // cg_emit_bounds_check(p, ast_token(ie->index), index, len); cgValue v = cg_emit_ptr_offset(p, elem, index); + v.type = alloc_type_pointer(type_deref(v.type, true)); return cg_addr(v); } @@ -2664,7 +3297,9 @@ gb_internal cgAddr cg_build_addr_index_expr(cgProcedure *p, Ast *expr) { index = cg_emit_conv(p, cg_build_expr(p, ie->index), t_int); // cg_emit_bounds_check(p, ast_token(ie->index), index, len); - return cg_addr(cg_emit_ptr_offset(p, elem, index)); + cgValue v = cg_emit_ptr_offset(p, elem, index); + v.type = alloc_type_pointer(type_deref(v.type, true)); + return cg_addr(v); } } return {}; @@ -2694,6 +3329,23 @@ gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) { return cg_build_addr_from_entity(p, e, expr); case_end; + case_ast_node(de, DerefExpr, expr); + Type *t = type_of_expr(de->expr); + if (is_type_relative_pointer(t)) { + cgAddr addr = cg_build_addr(p, de->expr); + addr.relative.deref = true; + return addr; + } else if (is_type_soa_pointer(t)) { + cgValue value = cg_build_expr(p, de->expr); + cgValue ptr = cg_emit_struct_ev(p, value, 0); + cgValue idx = cg_emit_struct_ev(p, value, 1); + GB_PANIC("TODO(bill): cg_addr_soa_variable"); + // return cg_addr_soa_variable(ptr, idx, nullptr); + } + cgValue addr = cg_build_expr(p, de->expr); + return cg_addr(addr); + case_end; + case_ast_node(ie, IndexExpr, expr); return cg_build_addr_index_expr(p, expr); case_end; @@ -2804,6 +3456,7 @@ gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) { if (sub_sel.index.count > 0) { item = cg_emit_deep_field_gep(p, item, sub_sel); } + item.type = alloc_type_pointer(type_deref(item.type, true)); return cg_addr(item); } else if (addr.kind == cgAddr_Swizzle) { GB_ASSERT(sel.index.count > 0); @@ -2821,6 +3474,23 @@ gb_internal cgAddr cg_build_addr_internal(cgProcedure *p, Ast *expr) { } case_end; + case_ast_node(ce, CallExpr, expr); + cgValue res = cg_build_expr(p, expr); + switch (res.kind) { + case cgValue_Value: + return cg_addr(cg_address_from_load_or_generate_local(p, res)); + case cgValue_Addr: + return cg_addr(res); + case cgValue_Multi: + GB_PANIC("cannot address a multi-valued expression"); + break; + } + case_end; + + case_ast_node(cl, CompoundLit, expr); + return cg_build_addr_compound_lit(p, expr); + case_end; + } TokenPos token_pos = ast_token(expr).pos; diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 41c185dc6..610d715ae 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -86,6 +86,10 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i } p->symbol = cast(TB_Symbol *)tb_extern_create(m->mod, link_name.len, cast(char const *)link_name.text, TB_EXTERNAL_SO_LOCAL); } + if (p->name == "main") { + // TODO(bill): figure out when this should be public or not + linkage = TB_LINKAGE_PUBLIC; + } if (p->symbol == nullptr) { p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE); @@ -97,9 +101,9 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i p->symbol = cast(TB_Symbol *)p->func; } - cgValue proc_value = cg_value(p->symbol, p->type); - cg_add_entity(m, entity, proc_value); - cg_add_member(m, p->name, proc_value); + p->value = cg_value(p->symbol, p->type); + cg_add_entity(m, entity, p->value); + cg_add_member(m, p->name, p->value); cg_add_procedure_value(m, p); @@ -275,7 +279,9 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { // } } - p->split_returns_index = param_index; + if (is_odin_like_cc) { + p->split_returns_index = param_index; + } if (pt->calling_convention == ProcCC_Odin) { // NOTE(bill): Push context on to stack from implicit parameter @@ -323,9 +329,15 @@ gb_internal void cg_procedure_end(cgProcedure *p) { return; } if (tb_inst_get_control(p->func)) { + GB_ASSERT(p->type->Proc.result_count == 0); tb_inst_ret(p->func, 0, nullptr); } bool emit_asm = false; + + if (string_starts_with(p->name, str_lit("bug@main"))) { + // emit_asm = true; + } + TB_FunctionOutput *output = tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST, emit_asm); if (emit_asm) { TB_Assembly *assembly = tb_output_get_asm(output); @@ -336,47 +348,70 @@ gb_internal void cg_procedure_end(cgProcedure *p) { } } -gb_global String procedures_to_generate_list[] = { - str_lit("bug" ABI_PKG_NAME_SEPARATOR "main"), - str_lit("main"), -}; - gb_internal void cg_procedure_generate(cgProcedure *p) { if (p->body == nullptr) { return; } - bool build_body = false; - - if ( - string_starts_with(p->name, str_lit("runtime" ABI_PKG_NAME_SEPARATOR "_os_write")) || - // p->name == "bug" ABI_PKG_NAME_SEPARATOR "main" || - // p->name == "main" || - false - ) { - build_body = true; - } - - if (build_body) { - cg_procedure_begin(p); - cg_build_stmt(p, p->body); - } + cg_procedure_begin(p); + cg_build_stmt(p, p->body); cg_procedure_end(p); - if (build_body) { + if (string_starts_with(p->name, str_lit("bug@main"))) { // IR Printing TB_Arena *arena = tb_default_arena(); defer (arena->free(arena)); TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena); defer (tb_funcopt_exit(opt)); tb_funcopt_print(opt); + fprintf(stdout, "\n"); + } + if (false) { // GraphViz printing + tb_function_print(p->func, tb_default_print_callback, stdout); + } +} + +gb_internal void cg_build_nested_proc(cgProcedure *p, AstProcLit *pd, Entity *e) { + GB_ASSERT(pd->body != nullptr); + cgModule *m = p->module; + auto *min_dep_set = &m->info->minimum_dependency_set; + + if (ptr_set_exists(min_dep_set, e) == false) { + // NOTE(bill): Nothing depends upon it so doesn't need to be built + return; + } - // GraphViz printing - // tb_function_print(p->func, tb_default_print_callback, stdout); + // NOTE(bill): Generate a new name + // parent.name-guid + String original_name = e->token.string; + String pd_name = original_name; + if (e->Procedure.link_name.len > 0) { + pd_name = e->Procedure.link_name; } + + + isize name_len = p->name.len + 1 + pd_name.len + 1 + 10 + 1; + char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); + + i32 guid = cast(i32)p->children.count; + name_len = gb_snprintf(name_text, name_len, "%.*s" ABI_PKG_NAME_SEPARATOR "%.*s-%d", LIT(p->name), LIT(pd_name), guid); + String name = make_string(cast(u8 *)name_text, name_len-1); + + e->Procedure.link_name = name; + + cgProcedure *nested_proc = cg_procedure_create(p->module, e); + e->cg_procedure = nested_proc; + + cgValue value = nested_proc->value; + + cg_add_entity(m, e, value); + array_add(&p->children, nested_proc); + array_add(&m->procedures_to_generate, nested_proc); } + + gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e) { GB_ASSERT(is_type_proc(e->type)); e = strip_entity_wrapping(e); @@ -388,6 +423,7 @@ gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e) found = map_get(&m->values, e); rw_mutex_shared_unlock(&m->values_mutex); if (found) { + GB_ASSERT(found->node != nullptr); return *found; } @@ -408,9 +444,6 @@ gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr) { GB_ASSERT(res.kind == cgValue_Multi); GB_ASSERT(res.multi->values.count == 2); return res.multi->values[0]; - // GB_ASSERT(is_type_tuple(res.type)); - // GB_ASSERT(res.type->Tuple.variables.count == 2); - // return cg_emit_struct_ev(p, res, 0); } return res; } @@ -470,8 +503,9 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice params[param_index++] = local; } } - for (cgValue arg : args) { - Type *param_type = param_entities[param_index]->type; + for_array(i, args) { + Type *param_type = param_entities[i]->type; + cgValue arg = args[i]; arg = cg_emit_conv(p, arg, param_type); arg = cg_flatten_value(p, arg); @@ -629,9 +663,7 @@ gb_internal cgValue cg_handle_param_value(cgProcedure *p, Type *parameter_type, if (p->entity != nullptr) { proc_name = p->entity->token.string; } - GB_PANIC("TODO(bill): cg_emit_source_code_location_as_global"); - // return cg_emit_source_code_location_as_global(p, proc_name, pos); - break; + return cg_emit_source_code_location_as_global(p, proc_name, pos); } case ParameterValue_Value: return cg_build_expr(p, param_value.ast_value); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 074d2674c..b25be089d 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -65,7 +65,7 @@ gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_vol return cg_value(tb_inst_load(p->func, dt, the_ptr, alignment, is_volatile), type); } -gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, bool is_volatile) { +gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue src, bool is_volatile) { GB_ASSERT_MSG(dst.kind != cgValue_Multi, "cannot store to multiple values at once"); if (dst.kind == cgValue_Addr) { @@ -122,10 +122,14 @@ gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue const &src, return; } + switch (dst.kind) { case cgValue_Value: - switch (dst.kind) { + switch (src.kind) { case cgValue_Value: + if (src.node->dt.type == TB_INT && src.node->dt.data == 1) { + src.node = tb_inst_zxt(p->func, src.node, dt); + } tb_inst_store(p->func, dt, dst.node, src.node, alignment, is_volatile); return; case cgValue_Addr: @@ -367,8 +371,7 @@ gb_internal cgValue cg_emit_ptr_offset(cgProcedure *p, cgValue ptr, cgValue inde Type *elem = type_deref(ptr.type, true); i64 stride = type_size_of(elem); - ptr.node = tb_inst_array_access(p->func, ptr.node, index.node, stride); - return ptr; + return cg_value(tb_inst_array_access(p->func, ptr.node, index.node, stride), alloc_type_pointer(elem)); } gb_internal cgValue cg_emit_array_ep(cgProcedure *p, cgValue s, cgValue index) { GB_ASSERT(s.kind == cgValue_Value); @@ -383,8 +386,7 @@ gb_internal cgValue cg_emit_array_ep(cgProcedure *p, cgValue s, cgValue index) { Type *elem = base_array_type(st); i64 stride = type_size_of(elem); - s.node = tb_inst_array_access(p->func, s.node, index.node, stride); - return s; + return cg_value(tb_inst_array_access(p->func, s.node, index.node, stride), alloc_type_pointer(elem)); } gb_internal cgValue cg_emit_array_epi(cgProcedure *p, cgValue s, i64 index) { return cg_emit_array_ep(p, s, cg_const_int(p, t_int, index)); @@ -425,7 +427,7 @@ gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index) { case Type_Slice: switch (index) { case 0: - result_type = alloc_type_pointer(t->Slice.elem); + result_type = alloc_type_multi_pointer(t->Slice.elem); offset = 0; break; case 1: @@ -439,7 +441,7 @@ gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index) { case Basic_string: switch (index) { case 0: - result_type = t_u8_ptr; + result_type = t_u8_multi_ptr; offset = 0; break; case 1: @@ -494,7 +496,7 @@ gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index) { case Type_DynamicArray: switch (index) { case 0: - result_type = alloc_type_pointer(t->DynamicArray.elem); + result_type = alloc_type_multi_pointer(t->DynamicArray.elem); offset = index*int_size; break; case 1: case 2: @@ -564,6 +566,14 @@ gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index) { ); } + +gb_internal cgValue cg_emit_struct_ev(cgProcedure *p, cgValue s, i64 index) { + s = cg_address_from_load_or_generate_local(p, s); + cgValue ptr = cg_emit_struct_ep(p, s, index); + return cg_flatten_value(p, cg_emit_load(p, ptr)); +} + + gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection const &sel) { GB_ASSERT(sel.index.count > 0); Type *type = type_deref(e.type); @@ -1008,7 +1018,7 @@ gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) { } } -gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return_results) { +gb_internal void cg_build_return_stmt_internal(cgProcedure *p, Slice const &results) { TypeTuple *tuple = &p->type->Proc.results->Tuple; isize return_count = p->type->Proc.result_count; @@ -1016,38 +1026,6 @@ gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return tb_inst_ret(p->func, 0, nullptr); return; } - TEMPORARY_ALLOCATOR_GUARD(); - - auto results = array_make(temporary_allocator(), 0, return_count); - - if (return_results.count != 0) { - for (isize i = 0; i < return_results.count; i++) { - cgValue res = cg_build_expr(p, return_results[i]); - cg_append_tuple_values(p, &results, res); - } - } else { - for_array(i, tuple->variables) { - Entity *e = tuple->variables[i]; - cgAddr addr = map_must_get(&p->variable_map, e); - cgValue res = cg_addr_load(p, addr); - array_add(&results, res); - } - } - GB_ASSERT(results.count == return_count); - - if (return_results.count != 0 && p->type->Proc.has_named_results) { - // NOTE(bill): store the named values before returning - for_array(i, tuple->variables) { - Entity *e = tuple->variables[i]; - cgAddr addr = map_must_get(&p->variable_map, e); - cg_addr_store(p, addr, results[i]); - } - } - for_array(i, tuple->variables) { - Entity *e = tuple->variables[i]; - results[i] = cg_emit_conv(p, results[i], e->type); - } - if (p->split_returns_index >= 0) { GB_ASSERT(is_calling_convention_odin(p->type->Proc.calling_convention)); @@ -1071,15 +1049,20 @@ gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return GB_ASSERT(p->proto->return_count == 1); TB_DataType dt = TB_PROTOTYPE_RETURNS(p->proto)->dt; - cgValue result = cg_flatten_value(p, results[0]); + cgValue result = results[return_count-1]; + result = cg_flatten_value(p, result); TB_Node *final_res = nullptr; if (result.kind == cgValue_Addr) { TB_CharUnits align = cast(TB_CharUnits)type_align_of(result.type); final_res = tb_inst_load(p->func, dt, result.node, align, false); } else { GB_ASSERT(result.kind == cgValue_Value); - if (result.node->dt.raw == dt.raw) { + TB_DataType st = result.node->dt; + GB_ASSERT(st.type == dt.type); + if (st.raw == dt.raw) { final_res = result.node; + } else if (st.type == TB_INT && st.data == 1) { + final_res = tb_inst_zxt(p->func, result.node, dt); } else { final_res = tb_inst_bitcast(p->func, result.node, dt); } @@ -1092,10 +1075,94 @@ gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return } else { GB_ASSERT(!is_calling_convention_odin(p->type->Proc.calling_convention)); + + if (p->return_by_ptr) { + Entity *e = tuple->variables[return_count-1]; + TB_Node *ret_ptr = tb_inst_param(p->func, 0); + cgValue ptr = cg_value(ret_ptr, alloc_type_pointer(e->type)); + cg_emit_store(p, ptr, results[return_count-1]); + + tb_inst_ret(p->func, 0, nullptr); + return; + } else { + GB_ASSERT(p->proto->return_count == 1); + TB_DataType dt = TB_PROTOTYPE_RETURNS(p->proto)->dt; + if (results.count == 1) { + cgValue result = results[0]; + result = cg_flatten_value(p, result); + + TB_Node *final_res = nullptr; + if (result.kind == cgValue_Addr) { + TB_CharUnits align = cast(TB_CharUnits)type_align_of(result.type); + final_res = tb_inst_load(p->func, dt, result.node, align, false); + } else { + GB_ASSERT(result.kind == cgValue_Value); + TB_DataType st = result.node->dt; + GB_ASSERT(st.type == dt.type); + if (st.raw == dt.raw) { + final_res = result.node; + } else if (st.type == TB_INT && st.data == 1) { + final_res = tb_inst_zxt(p->func, result.node, dt); + } else { + final_res = tb_inst_bitcast(p->func, result.node, dt); + } + } + + GB_ASSERT(final_res != nullptr); + + tb_inst_ret(p->func, 1, &final_res); + return; + } else { + GB_ASSERT_MSG(results.count == 1, "TODO(bill): multi-return values for the return"); + return; + } + } + } +} + + +gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return_results) { + TypeTuple *tuple = &p->type->Proc.results->Tuple; + isize return_count = p->type->Proc.result_count; + if (return_count == 0) { + tb_inst_ret(p->func, 0, nullptr); + return; + } + TEMPORARY_ALLOCATOR_GUARD(); - GB_PANIC("TODO(bill): %.*s MUTLIPLE RETURN VALUES %td %td", LIT(p->name), results.count, return_results.count); + auto results = array_make(temporary_allocator(), 0, return_count); + + if (return_results.count != 0) { + for (isize i = 0; i < return_results.count; i++) { + cgValue res = cg_build_expr(p, return_results[i]); + cg_append_tuple_values(p, &results, res); + } + } else { + for_array(i, tuple->variables) { + Entity *e = tuple->variables[i]; + cgAddr addr = map_must_get(&p->variable_map, e); + cgValue res = cg_addr_load(p, addr); + array_add(&results, res); + } + } + GB_ASSERT(results.count == return_count); + + if (return_results.count != 0 && p->type->Proc.has_named_results) { + // NOTE(bill): store the named values before returning + for_array(i, tuple->variables) { + Entity *e = tuple->variables[i]; + cgAddr addr = map_must_get(&p->variable_map, e); + cg_addr_store(p, addr, results[i]); + } + } + for_array(i, tuple->variables) { + Entity *e = tuple->variables[i]; + results[i] = cg_emit_conv(p, results[i], e->type); + } + + cg_build_return_stmt_internal(p, slice_from_array(results)); } gb_internal void cg_build_if_stmt(cgProcedure *p, Ast *node) { @@ -1673,13 +1740,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { // TODO(bill): check if last instruction was a terminating one or not - { - TokenPos pos = ast_token(node).pos; - TB_FileID *file_id = map_get(&p->module->file_id_map, cast(uintptr)pos.file_id); - if (file_id) { - tb_inst_set_location(p->func, *file_id, pos.line); - } - } + cg_set_debug_pos_from_node(p, node); u16 prev_state_flags = p->state_flags; defer (p->state_flags = prev_state_flags); @@ -1838,7 +1899,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { case_end; case_ast_node(rs, RangeStmt, node); - GB_PANIC("TODO(bill): cg_build_range_stmt"); + GB_PANIC("TODO(bill): cg_build_range_stmt %.*s", LIT(p->name)); // cg_build_range_stmt(p, rs, rs->scope); case_end; @@ -1879,13 +1940,115 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { } } +gb_internal void cg_build_constant_value_decl(cgProcedure *p, AstValueDecl *vd) { + if (vd == nullptr || vd->is_mutable) { + return; + } + + auto *min_dep_set = &p->module->info->minimum_dependency_set; + + static i32 global_guid = 0; + + for (Ast *ident : vd->names) { + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_node(ident); + GB_ASSERT(e != nullptr); + if (e->kind != Entity_TypeName) { + continue; + } + + bool polymorphic_struct = false; + if (e->type != nullptr && e->kind == Entity_TypeName) { + Type *bt = base_type(e->type); + if (bt->kind == Type_Struct) { + polymorphic_struct = bt->Struct.is_polymorphic; + } + } + + if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { + continue; + } + + if (e->TypeName.ir_mangled_name.len != 0) { + // NOTE(bill): Already set + continue; + } + + cg_set_nested_type_name_ir_mangled_name(e, p); + } + + for_array(i, vd->names) { + Ast *ident = vd->names[i]; + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_node(ident); + GB_ASSERT(e != nullptr); + if (e->kind != Entity_Procedure) { + continue; + } + GB_ASSERT (vd->values[i] != nullptr); + + Ast *value = unparen_expr(vd->values[i]); + if (value->kind != Ast_ProcLit) { + continue; // It's an alias + } + + DeclInfo *decl = decl_info_of_entity(e); + ast_node(pl, ProcLit, decl->proc_lit); + if (pl->body != nullptr) { + GenProcsData *gpd = e->Procedure.gen_procs; + if (gpd) { + rw_mutex_shared_lock(&gpd->mutex); + for (Entity *e : gpd->procs) { + if (!ptr_set_exists(min_dep_set, e)) { + continue; + } + DeclInfo *d = decl_info_of_entity(e); + cg_build_nested_proc(p, &d->proc_lit->ProcLit, e); + } + rw_mutex_shared_unlock(&gpd->mutex); + } else { + cg_build_nested_proc(p, pl, e); + } + } else { + + // FFI - Foreign function interace + String original_name = e->token.string; + String name = original_name; + + if (e->Procedure.is_foreign) { + GB_PANIC("cg_add_foreign_library_path"); + // cg_add_foreign_library_path(p->module, e->Procedure.foreign_library); + } + + if (e->Procedure.link_name.len > 0) { + name = e->Procedure.link_name; + } + + cgValue *prev_value = string_map_get(&p->module->members, name); + if (prev_value != nullptr) { + // NOTE(bill): Don't do mutliple declarations in the IR + return; + } + + e->Procedure.link_name = name; + + cgProcedure *nested_proc = cg_procedure_create(p->module, e); + + cgValue value = p->value; + + array_add(&p->module->procedures_to_generate, nested_proc); + array_add(&p->children, nested_proc); + string_map_set(&p->module->members, name, value); + } + } +} + gb_internal void cg_build_stmt_list(cgProcedure *p, Slice const &stmts) { for (Ast *stmt : stmts) { switch (stmt->kind) { case_ast_node(vd, ValueDecl, stmt); - // TODO(bill) - // cg_build_constant_value_decl(p, vd); + cg_build_constant_value_decl(p, vd); case_end; case_ast_node(fb, ForeignBlockDecl, stmt); ast_node(block, BlockStmt, fb->body); -- cgit v1.2.3 From d8445fd9dfe5bcf9b694c2b83791c88cafcdf322 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Jul 2023 12:53:16 +0100 Subject: Multithread tilde backend --- src/tilde.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++---------- src/tilde.hpp | 14 ++++++++----- src/tilde/tb.lib | Bin 4393788 -> 4161494 bytes src/tilde_proc.cpp | 44 +++++++++++++++++++++++++-------------- src/tilde_stmt.cpp | 2 +- 5 files changed, 88 insertions(+), 32 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde.cpp b/src/tilde.cpp index 4fd891b17..8bd7e0b43 100644 --- a/src/tilde.cpp +++ b/src/tilde.cpp @@ -7,6 +7,13 @@ gb_internal TB_Arena *cg_arena(void) { return global_tb_arenas[current_thread_index()]; } +gb_internal void cg_global_arena_init(void) { + global_tb_arenas = slice_make(permanent_allocator(), global_thread_pool.threads.count); + for_array(i, global_tb_arenas) { + global_tb_arenas[i] = tb_default_arena(); + } +} + // returns TB_TYPE_VOID if not trivially possible gb_internal TB_DataType cg_data_type(Type *t) { GB_ASSERT(t != nullptr); @@ -535,7 +542,6 @@ gb_internal cgModule *cg_module_create(Checker *c) { tb_module_set_tls_index(m->mod, 10, "_tls_index"); map_init(&m->values); - array_init(&m->procedures_to_generate, heap_allocator()); map_init(&m->file_id_map); @@ -543,6 +549,8 @@ gb_internal cgModule *cg_module_create(Checker *c) { map_init(&m->proc_debug_type_map); map_init(&m->proc_proto_map); + array_init(&m->single_threaded_procedure_queue, heap_allocator()); + for_array(id, global_files) { if (AstFile *f = global_files[id]) { @@ -556,12 +564,13 @@ gb_internal cgModule *cg_module_create(Checker *c) { gb_internal void cg_module_destroy(cgModule *m) { map_destroy(&m->values); - array_free(&m->procedures_to_generate); map_destroy(&m->file_id_map); map_destroy(&m->debug_type_map); map_destroy(&m->proc_debug_type_map); map_destroy(&m->proc_proto_map); + array_free(&m->single_threaded_procedure_queue); + tb_module_destroy(m->mod); } @@ -772,6 +781,21 @@ gb_internal String cg_filepath_obj_for_module(cgModule *m) { } +gb_internal WORKER_TASK_PROC(cg_procedure_generate_worker_proc) { + cgProcedure *p = cast(cgProcedure *)data; + cg_procedure_generate(p); + return 0; +} + +gb_internal void cg_add_procedure_to_queue(cgProcedure *p) { + cgModule *m = p->module; + if (m->do_threading) { + thread_pool_add_task(cg_procedure_generate_worker_proc, p); + } else { + array_add(&m->single_threaded_procedure_queue, p); + } +} + gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) { TIME_SECTION("Tilde Module Initializtion"); @@ -779,14 +803,13 @@ gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) { linker_data_init(linker_data, info, c->parser->init_fullpath); - global_tb_arenas = slice_make(permanent_allocator(), global_thread_pool.threads.count); - for_array(i, global_tb_arenas) { - global_tb_arenas[i] = tb_default_arena(); - } + cg_global_arena_init(); cgModule *m = cg_module_create(c); defer (cg_module_destroy(m)); + m->do_threading = true; + TIME_SECTION("Tilde Global Variables"); bool already_has_entry_point = cg_global_variables_create(m); @@ -798,6 +821,7 @@ gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) { p->is_startup = true; cg_procedure_begin(p); + tb_inst_ret(p->func, 0, nullptr); cg_procedure_end(p); } @@ -807,14 +831,19 @@ gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) { p->is_startup = true; cg_procedure_begin(p); + tb_inst_ret(p->func, 0, nullptr); cg_procedure_end(p); } auto *min_dep_set = &info->minimum_dependency_set; + Array procedures_to_generate = {}; + array_init(&procedures_to_generate, heap_allocator()); + defer (array_free(&procedures_to_generate)); + for (Entity *e : info->entities) { - String name = e->token.string; - Scope * scope = e->scope; + String name = e->token.string; + Scope *scope = e->scope; if ((scope->flags & ScopeFlag_File) == 0) { continue; @@ -832,15 +861,24 @@ gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) { continue; } if (cgProcedure *p = cg_procedure_create(m, e)) { - array_add(&m->procedures_to_generate, p); + array_add(&procedures_to_generate, p); } } + for (cgProcedure *p : procedures_to_generate) { + cg_add_procedure_to_queue(p); + } - for (isize i = 0; i < m->procedures_to_generate.count; i++) { - cg_procedure_generate(m->procedures_to_generate[i]); + if (!m->do_threading) { + for (isize i = 0; i < m->single_threaded_procedure_queue.count; i++) { + cgProcedure *p = m->single_threaded_procedure_queue[i]; + cg_procedure_generate(p); + } } + thread_pool_wait(); + + TB_DebugFormat debug_format = TB_DEBUGFMT_NONE; if (build_context.ODIN_DEBUG || true) { switch (build_context.metrics.os) { diff --git a/src/tilde.hpp b/src/tilde.hpp index 44da86c35..ce87f2dfe 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -210,13 +210,14 @@ struct cgModule { CheckerInfo *info; LinkerData * linker_data; - RwMutex values_mutex; - PtrMap values; - StringMap members; + bool do_threading; + Array single_threaded_procedure_queue; - StringMap procedures; + RwMutex values_mutex; + PtrMap values; + StringMap members; + StringMap procedures; PtrMap procedure_values; - Array procedures_to_generate; RecursiveMutex debug_type_mutex; PtrMap debug_type_map; @@ -225,6 +226,7 @@ struct cgModule { RecursiveMutex proc_proto_mutex; PtrMap proc_proto_map; + // NOTE(bill): no need to protect this with a mutex PtrMap file_id_map; // Key: AstFile.id (i32 cast to uintptr) std::atomic nested_type_name_guid; @@ -252,6 +254,8 @@ gb_global isize cg_global_type_info_member_tags_index = 0; gb_internal TB_Arena *cg_arena(void); +gb_internal void cg_add_procedure_to_queue(cgProcedure *p); + gb_internal cgValue cg_value(TB_Global * g, Type *type); gb_internal cgValue cg_value(TB_External *e, Type *type); gb_internal cgValue cg_value(TB_Function *f, Type *type); diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index f5464cab0..a60475d1c 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index fec77733d..fe9c6c766 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -35,7 +35,9 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i cgValue *found = string_map_get(&m->members, key); if (found) { cg_add_entity(m, entity, *found); + rw_mutex_lock(&m->values_mutex); p = string_map_must_get(&m->procedures, key); + rw_mutex_unlock(&m->values_mutex); if (!ignore_body && p->func != nullptr) { return nullptr; } @@ -96,7 +98,6 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i p->debug_type = cg_debug_type_for_proc(m, p->type); p->proto = tb_prototype_from_dbg(m->mod, p->debug_type); - tb_function_set_prototype(p->func, p->proto, cg_arena()); p->symbol = cast(TB_Symbol *)p->func; } @@ -148,7 +149,6 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li p->debug_type = cg_debug_type_for_proc(m, p->type); p->proto = tb_prototype_from_dbg(m->mod, p->debug_type); - tb_function_set_prototype(p->func, p->proto, cg_arena()); p->symbol = cast(TB_Symbol *)p->func; @@ -164,6 +164,8 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { return; } + tb_function_set_prototype(p->func, p->proto, cg_arena()); + if (p->body == nullptr) { return; } @@ -324,19 +326,11 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { } } -gb_internal void cg_procedure_end(cgProcedure *p) { - if (p == nullptr || p->func == nullptr) { - return; - } - if (tb_inst_get_control(p->func)) { - GB_ASSERT(p->type->Proc.result_count == 0); - tb_inst_ret(p->func, 0, nullptr); - } - bool emit_asm = false; - if (string_starts_with(p->name, str_lit("runtime@_os_write"))) { - // emit_asm = true; - } +gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) { + cgProcedure *p = cast(cgProcedure *)data; + + bool emit_asm = false; TB_FunctionOutput *output = tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST, emit_asm); if (emit_asm) { @@ -346,6 +340,24 @@ gb_internal void cg_procedure_end(cgProcedure *p) { } gb_printf_err("\n"); } + + return 0; +} + +gb_internal void cg_procedure_end(cgProcedure *p) { + if (p == nullptr || p->func == nullptr) { + return; + } + if (tb_inst_get_control(p->func)) { + GB_ASSERT(p->type->Proc.result_count == 0); + tb_inst_ret(p->func, 0, nullptr); + } + + if (p->module->do_threading) { + thread_pool_add_task(cg_procedure_compile_worker_proc, p); + } else { + cg_procedure_compile_worker_proc(p); + } } gb_internal void cg_procedure_generate(cgProcedure *p) { @@ -353,10 +365,12 @@ gb_internal void cg_procedure_generate(cgProcedure *p) { return; } + cg_procedure_begin(p); cg_build_stmt(p, p->body); cg_procedure_end(p); + if ( // string_starts_with(p->name, str_lit("runtime@_os_write")) || false @@ -408,7 +422,7 @@ gb_internal void cg_build_nested_proc(cgProcedure *p, AstProcLit *pd, Entity *e) cg_add_entity(m, e, value); array_add(&p->children, nested_proc); - array_add(&m->procedures_to_generate, nested_proc); + cg_add_procedure_to_queue(nested_proc); } diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index b25be089d..6cef37ad4 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -2036,9 +2036,9 @@ gb_internal void cg_build_constant_value_decl(cgProcedure *p, AstValueDecl *vd) cgValue value = p->value; - array_add(&p->module->procedures_to_generate, nested_proc); array_add(&p->children, nested_proc); string_map_set(&p->module->members, name, value); + cg_add_procedure_to_queue(nested_proc); } } } -- cgit v1.2.3 From 5a50afa1fd863caa5459f516b2d6a482611cd4c7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Jul 2023 15:28:51 +0100 Subject: Implement for in interval statements --- src/tilde.hpp | 4 ++ src/tilde_stmt.cpp | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 163 insertions(+), 2 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde.hpp b/src/tilde.hpp index d22043918..a548252d9 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -277,6 +277,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *stmt); gb_internal void cg_build_stmt_list(cgProcedure *p, Slice const &stmts); gb_internal void cg_build_when_stmt(cgProcedure *p, AstWhenStmt *ws); + gb_internal cgValue cg_build_expr(cgProcedure *p, Ast *expr); gb_internal cgAddr cg_build_addr(cgProcedure *p, Ast *expr); gb_internal cgValue cg_build_addr_ptr(cgProcedure *p, Ast *expr); @@ -295,8 +296,11 @@ gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgVal gb_internal cgValue cg_copy_value_to_ptr(cgProcedure *p, cgValue value, Type *original_type, isize min_alignment); gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); + gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return_results); gb_internal void cg_build_return_stmt_internal(cgProcedure *p, Slice const &results); +gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node); + gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 6cef37ad4..7ad6a9417 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1261,6 +1261,164 @@ gb_internal void cg_build_for_stmt(cgProcedure *p, Ast *node) { tb_inst_set_control(p->func, done); } + +gb_internal Ast *cg_strip_and_prefix(Ast *ident) { + if (ident != nullptr) { + if (ident->kind == Ast_UnaryExpr && ident->UnaryExpr.op.kind == Token_And) { + ident = ident->UnaryExpr.expr; + } + GB_ASSERT(ident->kind == Ast_Ident); + } + return ident; +} + +gb_internal void cg_emit_increment(cgProcedure *p, cgValue addr) { + GB_ASSERT(is_type_pointer(addr.type)); + Type *type = type_deref(addr.type); + cgValue v_one = cg_const_value(p, type, exact_value_i64(1)); + cg_emit_store(p, addr, cg_emit_arith(p, Token_Add, cg_emit_load(p, addr), v_one, type)); + +} + +gb_internal void cg_build_range_stmt_interval(cgProcedure *p, AstBinaryExpr *node, + AstRangeStmt *rs, Scope *scope) { + bool ADD_EXTRA_WRAPPING_CHECK = true; + + cg_scope_open(p, scope); + + Ast *val0 = rs->vals.count > 0 ? cg_strip_and_prefix(rs->vals[0]) : nullptr; + Ast *val1 = rs->vals.count > 1 ? cg_strip_and_prefix(rs->vals[1]) : nullptr; + Type *val0_type = nullptr; + Type *val1_type = nullptr; + if (val0 != nullptr && !is_blank_ident(val0)) { + val0_type = type_of_expr(val0); + } + if (val1 != nullptr && !is_blank_ident(val1)) { + val1_type = type_of_expr(val1); + } + + TokenKind op = Token_Lt; + switch (node->op.kind) { + case Token_Ellipsis: op = Token_LtEq; break; + case Token_RangeFull: op = Token_LtEq; break; + case Token_RangeHalf: op = Token_Lt; break; + default: GB_PANIC("Invalid interval operator"); break; + } + + + cgValue lower = cg_build_expr(p, node->left); + cgValue upper = {}; // initialized each time in the loop + + cgAddr value; + if (val0_type != nullptr) { + value = cg_add_local(p, val0_type, entity_of_node(val0), false); + } else { + value = cg_add_local(p, lower.type, nullptr, false); + } + cg_addr_store(p, value, lower); + + cgAddr index; + if (val1_type != nullptr) { + index = cg_add_local(p, val1_type, entity_of_node(val1), false); + } else { + index = cg_add_local(p, t_int, nullptr, false); + } + cg_addr_store(p, index, cg_const_int(p, t_int, 0)); + + TB_Node *loop = cg_control_region(p, "for_interval_loop"); + TB_Node *body = cg_control_region(p, "for_interval_body"); + TB_Node *done = cg_control_region(p, "for_interval_done"); + + cg_emit_goto(p, loop); + tb_inst_set_control(p->func, loop); + + upper = cg_build_expr(p, node->right); + cgValue curr_value = cg_addr_load(p, value); + cgValue cond = cg_emit_comp(p, op, curr_value, upper); + cg_emit_if(p, cond, body, done); + tb_inst_set_control(p->func, body); + + cgValue val = cg_addr_load(p, value); + cgValue idx = cg_addr_load(p, index); + + auto const &store_val = [](cgProcedure *p, Ast *stmt_val, cgValue const &value) { + Entity *e = entity_of_node(stmt_val); + if (e == nullptr) { + return; + } + + if (e->flags & EntityFlag_Value) { + if (value.kind == cgValue_Addr) { + cgValue ptr = cg_address_from_load_or_generate_local(p, value); + cg_add_entity(p->module, e, ptr); + return; + } + } + + cgAddr addr = cg_add_local(p, e->type, e, false); + cg_addr_store(p, addr, value); + return; + }; + + if (val0_type) store_val(p, val0, val); + if (val1_type) store_val(p, val1, idx); + + + { + // NOTE: this check block will most likely be optimized out, and is here + // to make this code easier to read + TB_Node *check = nullptr; + TB_Node *post = cg_control_region(p, "for_interval_post"); + + TB_Node *continue_block = post; + + if (ADD_EXTRA_WRAPPING_CHECK && + op == Token_LtEq) { + check = cg_control_region(p, "for_interval_check"); + continue_block = check; + } + + cg_push_target_list(p, rs->label, done, continue_block, nullptr); + + cg_build_stmt(p, rs->body); + + cg_scope_close(p, cgDeferExit_Default, nullptr); + cg_pop_target_list(p); + + if (check != nullptr) { + cg_emit_goto(p, check); + tb_inst_set_control(p->func, check); + + cgValue check_cond = cg_emit_comp(p, Token_NotEq, curr_value, upper); + cg_emit_if(p, check_cond, post, done); + } else { + cg_emit_goto(p, post); + } + + tb_inst_set_control(p->func, post); + cg_emit_increment(p, value.addr); + cg_emit_increment(p, index.addr); + cg_emit_goto(p, loop); + } + + tb_inst_set_control(p->func, done); + +} + +gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) { + ast_node(rs, RangeStmt, node); + + Ast *expr = unparen_expr(rs->expr); + + + if (is_ast_range(expr)) { + cg_build_range_stmt_interval(p, &expr->BinaryExpr, rs, rs->scope); + return; + } + + GB_PANIC("TODO(bill): cg_build_range_stmt"); +} + gb_internal bool cg_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss) { if (ss->tag == nullptr) { return false; @@ -1899,8 +2057,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { case_end; case_ast_node(rs, RangeStmt, node); - GB_PANIC("TODO(bill): cg_build_range_stmt %.*s", LIT(p->name)); - // cg_build_range_stmt(p, rs, rs->scope); + cg_build_range_stmt(p, node); case_end; case_ast_node(rs, UnrollRangeStmt, node); -- cgit v1.2.3 From 78116e0ea24aef3f663832edfb5f9cd6aa7b6e57 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Jul 2023 15:46:54 +0100 Subject: Implement for in statements for array-like values --- src/tilde_expr.cpp | 26 ++--- src/tilde_proc.cpp | 2 +- src/tilde_stmt.cpp | 318 +++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 308 insertions(+), 38 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 07e60f1a6..993270c14 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -2417,22 +2417,20 @@ cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) { // break; // } - // case Type_Array: { - // cg_addr_store(p, v, cg_const_value(p->module, type, exact_value_compound(expr))); - - // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + case Type_Array: { + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - // populate(p, cl->elems, &temp_data, type); + populate(p, cl->elems, &temp_data, type); - // cgValue dst_ptr = cg_addr_get_ptr(p, v); - // for_array(i, temp_data) { - // i32 index = cast(i32)(temp_data[i].elem_index); - // temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, index); - // } + cgValue dst_ptr = cg_addr_get_ptr(p, v); + for_array(i, temp_data) { + i32 index = cast(i32)(temp_data[i].elem_index); + temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, index); + } - // assign_array(p, temp_data); - // break; - // } + assign_array(p, temp_data); + break; + } // case Type_EnumeratedArray: { // cg_addr_store(p, v, cg_const_value(p->module, type, exact_value_compound(expr))); @@ -2468,7 +2466,7 @@ cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) { } assign_array(p, temp_data); - cg_fill_slice(p, v, data, cg_const_int(p, t_int, cl->max_count)); + cg_fill_slice(p, v, data, cg_const_int(p, t_int, count)); return v; } diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index b3c81a7d5..ed28f5016 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -396,7 +396,7 @@ gb_internal void cg_procedure_generate(cgProcedure *p) { if ( - // string_starts_with(p->name, str_lit("runtime@_os_write")) || + // string_starts_with(p->name, str_lit("bug@main")) || false ) { // IR Printing TB_Arena *arena = tb_default_arena(); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 7ad6a9417..f89dbdf03 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1280,6 +1280,25 @@ gb_internal void cg_emit_increment(cgProcedure *p, cgValue addr) { } +gb_internal void cg_range_stmt_store_val(cgProcedure *p, Ast *stmt_val, cgValue const &value) { + Entity *e = entity_of_node(stmt_val); + if (e == nullptr) { + return; + } + + if (e->flags & EntityFlag_Value) { + if (value.kind == cgValue_Addr) { + cgValue ptr = cg_address_from_load_or_generate_local(p, value); + cg_add_entity(p->module, e, ptr); + return; + } + } + + cgAddr addr = cg_add_local(p, e->type, e, false); + cg_addr_store(p, addr, value); + return; +} + gb_internal void cg_build_range_stmt_interval(cgProcedure *p, AstBinaryExpr *node, AstRangeStmt *rs, Scope *scope) { bool ADD_EXTRA_WRAPPING_CHECK = true; @@ -1341,27 +1360,8 @@ gb_internal void cg_build_range_stmt_interval(cgProcedure *p, AstBinaryExpr *nod cgValue val = cg_addr_load(p, value); cgValue idx = cg_addr_load(p, index); - auto const &store_val = [](cgProcedure *p, Ast *stmt_val, cgValue const &value) { - Entity *e = entity_of_node(stmt_val); - if (e == nullptr) { - return; - } - - if (e->flags & EntityFlag_Value) { - if (value.kind == cgValue_Addr) { - cgValue ptr = cg_address_from_load_or_generate_local(p, value); - cg_add_entity(p->module, e, ptr); - return; - } - } - - cgAddr addr = cg_add_local(p, e->type, e, false); - cg_addr_store(p, addr, value); - return; - }; - - if (val0_type) store_val(p, val0, val); - if (val1_type) store_val(p, val1, idx); + if (val0_type) cg_range_stmt_store_val(p, val0, val); + if (val1_type) cg_range_stmt_store_val(p, val1, idx); { @@ -1402,6 +1402,147 @@ gb_internal void cg_build_range_stmt_interval(cgProcedure *p, AstBinaryExpr *nod } tb_inst_set_control(p->func, done); +} + +gb_internal void cg_build_range_stmt_indexed(cgProcedure *p, cgValue expr, Type *val_type, cgValue count_ptr, + cgValue *val_, cgValue *idx_, TB_Node **loop_, TB_Node **done_, + bool is_reverse) { + cgValue count = {}; + Type *expr_type = base_type(type_deref(expr.type)); + switch (expr_type->kind) { + case Type_Array: + count = cg_const_int(p, t_int, expr_type->Array.count); + break; + } + + cgValue val = {}; + cgValue idx = {}; + TB_Node *loop = nullptr; + TB_Node *done = nullptr; + TB_Node *body = nullptr; + + loop = cg_control_region(p, "for_index_loop"); + body = cg_control_region(p, "for_index_body"); + done = cg_control_region(p, "for_index_done"); + + cgAddr index = cg_add_local(p, t_int, nullptr, false); + + if (!is_reverse) { + /* + for x, i in array { + ... + } + + i := -1 + for { + i += 1 + if !(i < len(array)) { + break + } + #no_bounds_check x := array[i] + ... + } + */ + + cg_addr_store(p, index, cg_const_int(p, t_int, cast(u64)-1)); + + cg_emit_goto(p, loop); + tb_inst_set_control(p->func, loop); + + cgValue incr = cg_emit_arith(p, Token_Add, cg_addr_load(p, index), cg_const_int(p, t_int, 1), t_int); + cg_addr_store(p, index, incr); + + if (count.node == nullptr) { + GB_ASSERT(count_ptr.node != nullptr); + count = cg_emit_load(p, count_ptr); + } + cgValue cond = cg_emit_comp(p, Token_Lt, incr, count); + cg_emit_if(p, cond, body, done); + } else { + // NOTE(bill): REVERSED LOGIC + /* + #reverse for x, i in array { + ... + } + + i := len(array) + for { + i -= 1 + if i < 0 { + break + } + #no_bounds_check x := array[i] + ... + } + */ + + if (count.node == nullptr) { + GB_ASSERT(count_ptr.node != nullptr); + count = cg_emit_load(p, count_ptr); + } + count = cg_emit_conv(p, count, t_int); + cg_addr_store(p, index, count); + + cg_emit_goto(p, loop); + tb_inst_set_control(p->func, loop); + + cgValue incr = cg_emit_arith(p, Token_Sub, cg_addr_load(p, index), cg_const_int(p, t_int, 1), t_int); + cg_addr_store(p, index, incr); + + cgValue anti_cond = cg_emit_comp(p, Token_Lt, incr, cg_const_int(p, t_int, 0)); + cg_emit_if(p, anti_cond, done, body); + } + + tb_inst_set_control(p->func, body); + + idx = cg_addr_load(p, index); + switch (expr_type->kind) { + case Type_Array: { + if (val_type != nullptr) { + val = cg_emit_load(p, cg_emit_array_ep(p, expr, idx)); + } + break; + } + case Type_EnumeratedArray: { + if (val_type != nullptr) { + val = cg_emit_load(p, cg_emit_array_ep(p, expr, idx)); + // NOTE(bill): Override the idx value for the enumeration + Type *index_type = expr_type->EnumeratedArray.index; + if (compare_exact_values(Token_NotEq, *expr_type->EnumeratedArray.min_value, exact_value_u64(0))) { + idx = cg_emit_arith(p, Token_Add, idx, cg_const_value(p, index_type, *expr_type->EnumeratedArray.min_value), index_type); + } + } + break; + } + case Type_Slice: { + if (val_type != nullptr) { + cgValue elem = cg_builtin_raw_data(p, expr); + val = cg_emit_load(p, cg_emit_ptr_offset(p, elem, idx)); + } + break; + } + case Type_DynamicArray: { + if (val_type != nullptr) { + cgValue elem = cg_emit_struct_ep(p, expr, 0); + elem = cg_emit_load(p, elem); + val = cg_emit_load(p, cg_emit_ptr_offset(p, elem, idx)); + } + break; + } + case Type_Struct: { + GB_ASSERT(is_type_soa_struct(expr_type)); + break; + } + + default: + GB_PANIC("Cannot do range_indexed of %s", type_to_string(expr_type)); + break; + } + + if (val_) *val_ = val; + if (idx_) *idx_ = idx; + if (loop_) *loop_ = loop; + if (done_) *done_ = done; } @@ -1410,13 +1551,144 @@ gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) { Ast *expr = unparen_expr(rs->expr); - if (is_ast_range(expr)) { cg_build_range_stmt_interval(p, &expr->BinaryExpr, rs, rs->scope); return; } - GB_PANIC("TODO(bill): cg_build_range_stmt"); + Type *expr_type = type_of_expr(expr); + if (expr_type != nullptr) { + Type *et = base_type(type_deref(expr_type)); + if (is_type_soa_struct(et)) { + GB_PANIC("TODO(bill): #soa array range statements"); + // cg_build_range_stmt_struct_soa(p, rs, scope); + return; + } + } + + cg_scope_open(p, rs->scope); + + + Ast *val0 = rs->vals.count > 0 ? cg_strip_and_prefix(rs->vals[0]) : nullptr; + Ast *val1 = rs->vals.count > 1 ? cg_strip_and_prefix(rs->vals[1]) : nullptr; + Type *val0_type = nullptr; + Type *val1_type = nullptr; + if (val0 != nullptr && !is_blank_ident(val0)) { + val0_type = type_of_expr(val0); + } + if (val1 != nullptr && !is_blank_ident(val1)) { + val1_type = type_of_expr(val1); + } + + cgValue val = {}; + cgValue key = {}; + TB_Node *loop = nullptr; + TB_Node *done = nullptr; + bool is_map = false; + TypeAndValue tav = type_and_value_of_expr(expr); + + if (tav.mode == Addressing_Type) { + GB_PANIC("TODO(bill): range statement over enum type"); + } else { + Type *expr_type = type_of_expr(expr); + Type *et = base_type(type_deref(expr_type)); + switch (et->kind) { + case Type_Map: { + is_map = true; + cgValue map = cg_build_addr_ptr(p, expr); + if (is_type_pointer(type_deref(map.type))) { + map = cg_emit_load(p, map); + } + GB_PANIC("TODO(bill): cg_build_range_map"); + // cg_build_range_map(p, map, val1_type, &val, &key, &loop, &done); + break; + } + case Type_Array: { + cgValue array = cg_build_addr_ptr(p, expr); + if (is_type_pointer(type_deref(array.type))) { + array = cg_emit_load(p, array); + } + cgAddr count_ptr = cg_add_local(p, t_int, nullptr, false); + cg_addr_store(p, count_ptr, cg_const_int(p, t_int, et->Array.count)); + cg_build_range_stmt_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse); + break; + } + case Type_EnumeratedArray: { + cgValue array = cg_build_addr_ptr(p, expr); + if (is_type_pointer(type_deref(array.type))) { + array = cg_emit_load(p, array); + } + cgAddr count_ptr = cg_add_local(p, t_int, nullptr, false); + cg_addr_store(p, count_ptr, cg_const_int(p, t_int, et->EnumeratedArray.count)); + cg_build_range_stmt_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse); + break; + } + case Type_DynamicArray: { + cgValue count_ptr = {}; + cgValue array = cg_build_addr_ptr(p, expr); + if (is_type_pointer(type_deref(array.type))) { + array = cg_emit_load(p, array); + } + count_ptr = cg_emit_struct_ep(p, array, 1); + GB_PANIC("TODO(bill): cg_build_range_stmt_indexed"); + // cg_build_range_stmt_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse); + break; + } + case Type_Slice: { + cgValue count_ptr = {}; + cgValue slice = cg_build_expr(p, expr); + if (is_type_pointer(slice.type)) { + count_ptr = cg_emit_struct_ep(p, slice, 1); + slice = cg_emit_load(p, slice); + } else { + count_ptr = cg_add_local(p, t_int, nullptr, false).addr; + cg_emit_store(p, count_ptr, cg_builtin_len(p, slice)); + } + cg_build_range_stmt_indexed(p, slice, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse); + break; + } + case Type_Basic: { + cgValue string = cg_build_expr(p, expr); + if (is_type_pointer(string.type)) { + string = cg_emit_load(p, string); + } + if (is_type_untyped(expr_type)) { + cgAddr s = cg_add_local(p, default_type(string.type), nullptr, false); + cg_addr_store(p, s, string); + string = cg_addr_load(p, s); + } + Type *t = base_type(string.type); + GB_ASSERT(!is_type_cstring(t)); + GB_PANIC("TODO(bill): cg_build_range_string"); + // cg_build_range_string(p, string, val0_type, &val, &key, &loop, &done, rs->reverse); + break; + } + case Type_Tuple: + GB_PANIC("TODO(bill): cg_build_range_tuple"); + // cg_build_range_tuple(p, expr, val0_type, val1_type, &val, &key, &loop, &done); + break; + default: + GB_PANIC("Cannot range over %s", type_to_string(expr_type)); + break; + } + } + + if (is_map) { + if (val0_type) cg_range_stmt_store_val(p, val0, key); + if (val1_type) cg_range_stmt_store_val(p, val1, val); + } else { + if (val0_type) cg_range_stmt_store_val(p, val0, val); + if (val1_type) cg_range_stmt_store_val(p, val1, key); + } + + cg_push_target_list(p, rs->label, done, loop, nullptr); + + cg_build_stmt(p, rs->body); + + cg_scope_close(p, cgDeferExit_Default, nullptr); + cg_pop_target_list(p); + cg_emit_goto(p, loop); + tb_inst_set_control(p->func, done); } gb_internal bool cg_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss) { -- cgit v1.2.3 From 28fca190ee11f5c19d30007f20caa4c7bf89f655 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Jul 2023 16:09:01 +0100 Subject: Fix `transmute(uintptr)ptr` etc --- src/tilde.cpp | 18 ++++++++++++++++++ src/tilde.hpp | 5 ++++- src/tilde_builtin.cpp | 16 +++++++++++++++- src/tilde_expr.cpp | 41 ++++++++++++++++++++++++++++++++++++++++- src/tilde_proc.cpp | 6 ++++++ src/tilde_stmt.cpp | 3 +-- 6 files changed, 84 insertions(+), 5 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde.cpp b/src/tilde.cpp index 89075da75..7574ea6b9 100644 --- a/src/tilde.cpp +++ b/src/tilde.cpp @@ -243,6 +243,24 @@ gb_internal isize cg_type_info_index(CheckerInfo *info, Type *type, bool err_on_ return -1; } +gb_internal cgValue cg_global_type_info_data_ptr(cgProcedure *p) { + cgValue v = cg_find_value_from_entity(p->module, cg_global_type_info_data_entity); + return cg_flatten_value(p, v); +} + + +gb_internal cgValue cg_type_info(cgProcedure *p, Type *type) { + GB_ASSERT(!build_context.no_rtti); + + type = default_type(type); + + isize index = cg_type_info_index(p->module->info, type); + GB_ASSERT(index >= 0); + + cgValue data = cg_global_type_info_data_ptr(p); + return cg_emit_array_epi(p, data, index); +} + gb_internal u64 cg_typeid_as_u64(cgModule *m, Type *type) { GB_ASSERT(!build_context.no_rtti); diff --git a/src/tilde.hpp b/src/tilde.hpp index a548252d9..2d7b2e1c3 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -301,7 +301,7 @@ gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return gb_internal void cg_build_return_stmt_internal(cgProcedure *p, Slice const &results); gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node); - +gb_internal cgValue cg_find_value_from_entity(cgModule *m, Entity *e); gb_internal cgValue cg_find_procedure_value_from_entity(cgModule *m, Entity *e); gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type); @@ -322,6 +322,9 @@ gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right); gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgValue rhs, Type *type); +gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice const &args); +gb_internal cgValue cg_emit_runtime_call(cgProcedure *p, char const *name, Slice const &args); + gb_internal bool cg_emit_goto(cgProcedure *p, TB_Node *control_region); gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name); diff --git a/src/tilde_builtin.cpp b/src/tilde_builtin.cpp index b40eacc7f..e30ff1cb0 100644 --- a/src/tilde_builtin.cpp +++ b/src/tilde_builtin.cpp @@ -236,7 +236,6 @@ gb_internal cgValue cg_builtin_mem_copy_non_overlapping(cgProcedure *p, cgValue } - gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr) { ast_node(ce, CallExpr, expr); @@ -419,6 +418,21 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr return cg_emit_arith(p, Token_Quo, diff, cg_const_int(p, t_int, type_size_of(elem)), t_int); } + case BuiltinProc_type_info_of: + { + Ast *arg = ce->args[0]; + TypeAndValue tav = type_and_value_of_expr(arg); + if (tav.mode == Addressing_Type) { + Type *t = default_type(type_of_expr(arg)); + return cg_type_info(p, t); + } + GB_ASSERT(is_type_typeid(tav.type)); + + auto args = slice_make(permanent_allocator(), 1); + args[0] = cg_build_expr(p, arg); + return cg_emit_runtime_call(p, "__type_info_of", args); + } + } diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 993270c14..8737e75cd 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -191,7 +191,46 @@ gb_internal cgValue cg_emit_transmute(cgProcedure *p, cgValue value, Type *type) GB_ASSERT_MSG(!TB_IS_VOID_TYPE(dt), "%d %s -> %s", dt.type, type_to_string(value.type), type_to_string(type)); value.type = type; if (value.node->dt.raw != dt.raw) { - value.node = tb_inst_bitcast(p->func, value.node, dt); + switch (value.node->dt.type) { + case TB_INT: + switch (value.node->dt.type) { + case TB_INT: + break; + case TB_FLOAT: + value.node = tb_inst_bitcast(p->func, value.node, dt); + break; + case TB_PTR: + value.node = tb_inst_int2ptr(p->func, value.node); + break; + } + break; + case TB_FLOAT: + switch (value.node->dt.type) { + case TB_INT: + value.node = tb_inst_bitcast(p->func, value.node, dt); + break; + case TB_FLOAT: + break; + case TB_PTR: + value.node = tb_inst_bitcast(p->func, value.node, TB_TYPE_INTPTR); + value.node = tb_inst_int2ptr(p->func, value.node); + break; + } + break; + case TB_PTR: + switch (value.node->dt.type) { + case TB_INT: + value.node = tb_inst_ptr2int(p->func, value.node, dt); + break; + case TB_FLOAT: + value.node = tb_inst_ptr2int(p->func, value.node, TB_TYPE_INTPTR); + value.node = tb_inst_bitcast(p->func, value.node, dt); + break; + case TB_PTR: + break; + } + break; + } } return value; case cgValue_Addr: diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index ed28f5016..acc31ce67 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -677,6 +677,12 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice return cg_value_multi(multi, pt->results); } +gb_internal cgValue cg_emit_runtime_call(cgProcedure *p, char const *name, Slice const &args) { + AstPackage *pkg = p->module->info->runtime_package; + Entity *e = scope_lookup_current(pkg->scope, make_string_c(name)); + cgValue value = cg_find_procedure_value_from_entity(p->module, e); + return cg_emit_call(p, value, args); +} gb_internal cgValue cg_handle_param_value(cgProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos) { switch (param_value.kind) { diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index f89dbdf03..8b577dfeb 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1630,8 +1630,7 @@ gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) { array = cg_emit_load(p, array); } count_ptr = cg_emit_struct_ep(p, array, 1); - GB_PANIC("TODO(bill): cg_build_range_stmt_indexed"); - // cg_build_range_stmt_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse); + cg_build_range_stmt_indexed(p, array, val0_type, count_ptr, &val, &key, &loop, &done, rs->reverse); break; } case Type_Slice: { -- cgit v1.2.3 From b934e4b564e58c62b8c6848a71fe99b02c588a94 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Jul 2023 00:33:43 +0100 Subject: Implement basic runtime type information This allows for `runtime.println_any` to work! --- src/tilde.cpp | 2 +- src/tilde/tb.lib | Bin 4164088 -> 4164640 bytes src/tilde_builtin.cpp | 3 +- src/tilde_const.cpp | 81 ++++++++++------- src/tilde_expr.cpp | 229 +++++++++++++++++++++++++++++++++++++++++++++--- src/tilde_proc.cpp | 5 +- src/tilde_stmt.cpp | 43 ++++----- src/tilde_type_info.cpp | 167 +++++++++++++++++++++++++++++++++++ 8 files changed, 459 insertions(+), 71 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde.cpp b/src/tilde.cpp index 82d30215e..729b8fa1e 100644 --- a/src/tilde.cpp +++ b/src/tilde.cpp @@ -260,7 +260,7 @@ gb_internal isize cg_type_info_index(CheckerInfo *info, Type *type, bool err_on_ } } if (err_on_not_found) { - GB_PANIC("NOT FOUND lb_type_info_index %s @ index %td", type_to_string(type), index); + GB_PANIC("NOT FOUND lb_type_info_index '%s' @ index %td", type_to_string(type), index); } return -1; } diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index 7ec145bda..78e661bf8 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_builtin.cpp b/src/tilde_builtin.cpp index e30ff1cb0..edf436424 100644 --- a/src/tilde_builtin.cpp +++ b/src/tilde_builtin.cpp @@ -267,8 +267,7 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr pos = e->token.pos; } - GB_PANIC("TODO(bill): cg_emit_source_code_location_as_global"); - // return cg_emit_source_code_location_as_global(p, procedure, pos); + return cg_emit_source_code_location_as_global(p, procedure, pos); } break; case BuiltinProc_len: { diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index 60f8e636b..30038cfdf 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -31,7 +31,7 @@ gb_internal cgValue cg_const_nil(cgModule *m, cgProcedure *p, Type *type) { if (is_type_internally_pointer_like(type)) { return cg_value(tb_inst_uint(p->func, dt, 0), type); - } else if (is_type_integer(type) || is_type_boolean(type) || is_type_bit_set(type)) { + } else if (is_type_integer(type) || is_type_boolean(type) || is_type_bit_set(type) || is_type_typeid(type)) { return cg_value(tb_inst_uint(p->func, dt, 0), type); } else if (is_type_float(type)) { switch (size) { @@ -51,10 +51,49 @@ gb_internal cgValue cg_const_nil(cgProcedure *p, Type *type) { return cg_const_nil(p->module, p, type); } +gb_internal TB_Global *cg_global_const_string(cgModule *m, String const &str, Type *type, TB_Global *global, i64 offset); +gb_internal void cg_write_int_at_ptr(void *dst, i64 i, Type *original_type); + +gb_internal void cg_global_source_code_location_const(cgModule *m, String const &proc_name, TokenPos pos, TB_Global *global, i64 offset) { + // Source_Code_Location :: struct { + // file_path: string, + // line, column: i32, + // procedure: string, + // } + + i64 file_path_offset = type_offset_of(t_source_code_location, 0); + i64 line_offset = type_offset_of(t_source_code_location, 1); + i64 column_offset = type_offset_of(t_source_code_location, 2); + i64 procedure_offset = type_offset_of(t_source_code_location, 3); + + String file_path = get_file_path_string(pos.file_id); + if (file_path.len != 0) { + cg_global_const_string(m, file_path, t_string, global, offset+file_path_offset); + } + + void *line_ptr = tb_global_add_region(m->mod, global, offset+line_offset, 4); + void *column_ptr = tb_global_add_region(m->mod, global, offset+column_offset, 4); + cg_write_int_at_ptr(line_ptr, pos.line, t_i32); + cg_write_int_at_ptr(column_ptr, pos.column, t_i32); + + if (proc_name.len != 0) { + cg_global_const_string(m, proc_name, t_string, global, offset+procedure_offset); + } +} + gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, String const &proc_name, TokenPos pos) { - // TODO(bill): cg_emit_source_code_location_as_global - return cg_const_nil(p, t_source_code_location); + cgModule *m = p->module; + char name[32] = {}; + gb_snprintf(name, 31, "scl$%u", 1+m->const_nil_guid.fetch_add(1)); + + TB_Global *global = tb_global_create(m->mod, -1, name, cg_debug_type(m, t_source_code_location), TB_LINKAGE_PRIVATE); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, type_size_of(t_source_code_location), type_align_of(t_source_code_location), 6); + + cg_global_source_code_location_const(m, proc_name, pos, global, 0); + + TB_Node *ptr = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)global); + return cg_lvalue_addr(ptr, t_source_code_location); } @@ -143,33 +182,6 @@ gb_internal TB_Global *cg_global_const_string(cgModule *m, String const &str, Ty return global; } -gb_internal void cg_global_source_code_location_const(cgModule *m, String const &proc_name, TokenPos pos, TB_Global *global, i64 offset) { - // Source_Code_Location :: struct { - // file_path: string, - // line, column: i32, - // procedure: string, - // } - - i64 file_path_offset = type_offset_of(t_source_code_location, 0); - i64 line_offset = type_offset_of(t_source_code_location, 1); - i64 column_offset = type_offset_of(t_source_code_location, 2); - i64 procedure_offset = type_offset_of(t_source_code_location, 3); - - String file_path = get_file_path_string(pos.file_id); - if (file_path.len != 0) { - cg_global_const_string(m, file_path, t_string, global, offset+file_path_offset); - } - - void *line_ptr = tb_global_add_region(m->mod, global, offset+line_offset, 4); - void *column_ptr = tb_global_add_region(m->mod, global, offset+column_offset, 4); - cg_write_int_at_ptr(line_ptr, pos.line, t_i32); - cg_write_int_at_ptr(column_ptr, pos.column, t_i32); - - if (proc_name.len != 0) { - cg_global_const_string(m, proc_name, t_string, global, offset+procedure_offset); - } -} - gb_internal bool cg_elem_type_can_be_constant(Type *t) { t = base_type(t); if (t == t_invalid) { @@ -1003,3 +1015,12 @@ gb_internal cgValue cg_const_int(cgProcedure *p, Type *type, i64 i) { gb_internal cgValue cg_const_bool(cgProcedure *p, Type *type, bool v) { return cg_value(tb_inst_bool(p->func, v), type); } + +gb_internal cgValue cg_const_string(cgProcedure *p, Type *type, String const &str) { + return cg_const_value(p, type, exact_value_string(str)); +} + +gb_internal cgValue cg_const_union_tag(cgProcedure *p, Type *u, Type *v) { + return cg_const_value(p, union_tag_type(u), exact_value_i64(union_variant_index(u, v))); +} + diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 8737e75cd..551ffbfbb 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -267,7 +267,8 @@ gb_internal cgValue cg_emit_byte_swap(cgProcedure *p, cgValue value, Type *end_t GB_ASSERT(value.kind == cgValue_Value); - value.node = tb_inst_bswap(p->func, value.node); + // TODO(bill): bswap + // value.node = tb_inst_bswap(p->func, value.node); return cg_emit_transmute(p, value, end_type); } @@ -913,13 +914,12 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { if (are_types_identical(src, t_cstring) && are_types_identical(dst, t_string)) { - GB_PANIC("TODO(bill): cstring_to_string call"); - // TEMPORARY_ALLOCATOR_GUARD(); - // lbValue c = lb_emit_conv(p, value, t_cstring); - // auto args = array_make(temporary_allocator(), 1); - // args[0] = c; - // lbValue s = lb_emit_runtime_call(p, "cstring_to_string", args); - // return lb_emit_conv(p, s, dst); + TEMPORARY_ALLOCATOR_GUARD(); + cgValue c = cg_emit_conv(p, value, t_cstring); + auto args = slice_make(temporary_allocator(), 1); + args[0] = c; + cgValue s = cg_emit_runtime_call(p, "cstring_to_string", args); + return cg_emit_conv(p, s, dst); } // float -> float @@ -1115,7 +1115,29 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { } if (is_type_any(dst)) { - GB_PANIC("TODO(bill): ? -> any"); + if (is_type_untyped_nil(src) || + is_type_untyped_uninit(src)) { + return cg_const_nil(p, t); + } + + cgAddr result = cg_add_local(p, t, nullptr, false); + + Type *st = default_type(src_type); + + cgValue data = cg_address_from_load_or_generate_local(p, value); + GB_ASSERT(is_type_pointer(data.type)); + GB_ASSERT(is_type_typed(st)); + + data = cg_emit_conv(p, data, t_rawptr); + + cgValue id = cg_typeid(p, st); + cgValue data_ptr = cg_emit_struct_ep(p, result.addr, 0); + cgValue id_ptr = cg_emit_struct_ep(p, result.addr, 1); + + cg_emit_store(p, data_ptr, data); + cg_emit_store(p, id_ptr, id); + + return cg_addr_load(p, result); } i64 src_sz = type_size_of(src); @@ -2868,6 +2890,190 @@ gb_internal cgValue cg_build_unary_and(cgProcedure *p, Ast *expr) { return cg_build_addr_ptr(p, ue->expr); } +gb_internal cgValue cg_emit_cast_union(cgProcedure *p, cgValue value, Type *type, TokenPos pos) { + Type *src_type = value.type; + bool is_ptr = is_type_pointer(src_type); + + bool is_tuple = true; + Type *tuple = type; + if (type->kind != Type_Tuple) { + is_tuple = false; + tuple = make_optional_ok_type(type); + } + + + if (is_ptr) { + value = cg_emit_load(p, value); + } + Type *src = base_type(type_deref(src_type)); + GB_ASSERT_MSG(is_type_union(src), "%s", type_to_string(src_type)); + Type *dst = tuple->Tuple.variables[0]->type; + + cgValue value_ = cg_address_from_load_or_generate_local(p, value); + + if ((p->state_flags & StateFlag_no_type_assert) != 0 && !is_tuple) { + // just do a bit cast of the data at the front + cgValue ptr = cg_emit_conv(p, value_, alloc_type_pointer(type)); + return cg_emit_load(p, ptr); + } + + + cgValue tag = {}; + cgValue dst_tag = {}; + cgValue cond = {}; + cgValue data = {}; + + cgValue gep0 = cg_add_local(p, tuple->Tuple.variables[0]->type, nullptr, true).addr; + cgValue gep1 = cg_add_local(p, tuple->Tuple.variables[1]->type, nullptr, true).addr; + + if (is_type_union_maybe_pointer(src)) { + data = cg_emit_load(p, cg_emit_conv(p, value_, gep0.type)); + } else { + tag = cg_emit_load(p, cg_emit_union_tag_ptr(p, value_)); + dst_tag = cg_const_union_tag(p, src, dst); + } + + TB_Node *ok_block = cg_control_region(p, "union_cast_ok"); + TB_Node *end_block = cg_control_region(p, "union_cast_end"); + + if (data.node != nullptr) { + GB_ASSERT(is_type_union_maybe_pointer(src)); + cond = cg_emit_comp_against_nil(p, Token_NotEq, data); + } else { + cond = cg_emit_comp(p, Token_CmpEq, tag, dst_tag); + } + + cg_emit_if(p, cond, ok_block, end_block); + tb_inst_set_control(p->func, ok_block); + + if (data.node == nullptr) { + data = cg_emit_load(p, cg_emit_conv(p, value_, gep0.type)); + } + cg_emit_store(p, gep0, data); + cg_emit_store(p, gep1, cg_const_bool(p, t_bool, true)); + + cg_emit_goto(p, end_block); + tb_inst_set_control(p->func, end_block); + + if (!is_tuple) { + GB_ASSERT((p->state_flags & StateFlag_no_type_assert) == 0); + // NOTE(bill): Panic on invalid conversion + Type *dst_type = tuple->Tuple.variables[0]->type; + + isize arg_count = 7; + if (build_context.no_rtti) { + arg_count = 4; + } + + cgValue ok = cg_emit_load(p, gep1); + auto args = slice_make(permanent_allocator(), arg_count); + args[0] = ok; + + args[1] = cg_const_string(p, t_string, get_file_path_string(pos.file_id)); + args[2] = cg_const_int(p, t_i32, pos.line); + args[3] = cg_const_int(p, t_i32, pos.column); + + if (!build_context.no_rtti) { + args[4] = cg_typeid(p, src_type); + args[5] = cg_typeid(p, dst_type); + args[6] = cg_emit_conv(p, value_, t_rawptr); + } + cg_emit_runtime_call(p, "type_assertion_check2", args); + + return cg_emit_load(p, gep0); + } + + return cg_value_multi2(cg_emit_load(p, gep0), cg_emit_load(p, gep1), tuple); +} + +gb_internal cgValue cg_emit_cast_any(cgProcedure *p, cgValue value, Type *type, TokenPos pos) { + Type *src_type = value.type; + + if (is_type_pointer(src_type)) { + value = cg_emit_load(p, value); + } + + bool is_tuple = true; + Type *tuple = type; + if (type->kind != Type_Tuple) { + is_tuple = false; + tuple = make_optional_ok_type(type); + } + Type *dst_type = tuple->Tuple.variables[0]->type; + + if ((p->state_flags & StateFlag_no_type_assert) != 0 && !is_tuple) { + // just do a bit cast of the data at the front + cgValue ptr = cg_emit_struct_ev(p, value, 0); + ptr = cg_emit_conv(p, ptr, alloc_type_pointer(type)); + return cg_emit_load(p, ptr); + } + + cgValue dst_typeid = cg_typeid(p, dst_type); + cgValue any_typeid = cg_emit_struct_ev(p, value, 1); + + + TB_Node *ok_block = cg_control_region(p, "any_cast_ok"); + TB_Node *end_block = cg_control_region(p, "any_cast_end"); + cgValue cond = cg_emit_comp(p, Token_CmpEq, any_typeid, dst_typeid); + cg_emit_if(p, cond, ok_block, end_block); + tb_inst_set_control(p->func, ok_block); + + cgValue gep0 = cg_add_local(p, tuple->Tuple.variables[0]->type, nullptr, true).addr; + cgValue gep1 = cg_add_local(p, tuple->Tuple.variables[1]->type, nullptr, true).addr; + + cgValue any_data = cg_emit_struct_ev(p, value, 0); + cgValue ptr = cg_emit_conv(p, any_data, alloc_type_pointer(dst_type)); + cg_emit_store(p, gep0, cg_emit_load(p, ptr)); + cg_emit_store(p, gep1, cg_const_bool(p, t_bool, true)); + + cg_emit_goto(p, end_block); + tb_inst_set_control(p->func, end_block); + + if (!is_tuple) { + // NOTE(bill): Panic on invalid conversion + cgValue ok = cg_emit_load(p, gep1); + + isize arg_count = 7; + if (build_context.no_rtti) { + arg_count = 4; + } + auto args = slice_make(permanent_allocator(), arg_count); + args[0] = ok; + + args[1] = cg_const_string(p, t_string, get_file_path_string(pos.file_id)); + args[2] = cg_const_int(p, t_i32, pos.line); + args[3] = cg_const_int(p, t_i32, pos.column); + + if (!build_context.no_rtti) { + args[4] = any_typeid; + args[5] = dst_typeid; + args[6] = cg_emit_struct_ev(p, value, 0); + } + cg_emit_runtime_call(p, "type_assertion_check2", args); + + return cg_emit_load(p, gep0); + } + + return cg_value_multi2(cg_emit_load(p, gep0), cg_emit_load(p, gep1), tuple); +} + + +gb_internal cgValue cg_build_type_assertion(cgProcedure *p, Ast *expr, Type *type) { + ast_node(ta, TypeAssertion, expr); + + TokenPos pos = ast_token(expr).pos; + cgValue e = cg_build_expr(p, ta->expr); + Type *t = type_deref(e.type); + + if (is_type_union(t)) { + return cg_emit_cast_union(p, e, type, pos); + } else if (is_type_any(t)) { + return cg_emit_cast_any(p, e, type, pos); + } + GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type)); + return {}; +} + gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { expr = unparen_expr(expr); @@ -3079,8 +3285,11 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) { case_ast_node(oe, OrElseExpr, expr); return cg_build_or_else(p, oe->x, oe->y, tv.type); case_end; + + case_ast_node(ta, TypeAssertion, expr); + return cg_build_type_assertion(p, expr, tv.type); + case_end; } - GB_PANIC("TODO(bill): cg_build_expr_internal %.*s", LIT(ast_strings[expr->kind])); return {}; } diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index a805b2985..398148965 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -352,7 +352,7 @@ gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) { bool emit_asm = false; if ( - // string_starts_with(p->name, str_lit("runtime@_os_write")) || + // string_starts_with(p->name, str_lit("bug@main")) || false ) { emit_asm = true; @@ -866,8 +866,7 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) { cgValue base_elem = cg_emit_array_epi(p, base_array.addr, 0); cgValue len = cg_const_int(p, t_int, slice_len); - GB_PANIC("TODO(bill): cg_fill_slice"); - // cg_fill_slice(p, slice, base_elem, len); + cg_fill_slice(p, slice, base_elem, len); variadic_args = cg_addr_load(p, slice); } diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 8b577dfeb..a663a401d 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -409,11 +409,9 @@ gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index) { switch (t->kind) { case Type_Struct: - { - type_set_offsets(t); - result_type = t->Struct.fields[index]->type; - offset = t->Struct.offsets[index]; - } + type_set_offsets(t); + result_type = t->Struct.fields[index]->type; + offset = t->Struct.offsets[index]; break; case Type_Union: GB_ASSERT(index == -1); @@ -421,7 +419,10 @@ gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index) { break; // return cg_emit_union_tag_ptr(p, s); case Type_Tuple: - GB_PANIC("TODO(bill): cg_emit_tuple_ep"); + type_set_offsets(t); + result_type = t->Tuple.variables[index]->type; + offset = t->Tuple.offsets[index]; + GB_PANIC("TODO(bill): cg_emit_tuple_ep %d", s.kind); break; // return cg_emit_tuple_ep(p, s, index); case Type_Slice: @@ -1799,8 +1800,11 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { expr = unparen_expr(expr); GB_ASSERT(!is_ast_range(expr)); if (expr->tav.mode == Addressing_Type) { - GB_PANIC("TODO(bill): cg_typeid as i64"); - // key = cg_typeid(p, expr->tav.value.value_typeid); + Type *type = expr->tav.value.value_typeid; + if (type == nullptr || type == t_invalid) { + type = expr->tav.type; + } + key = cg_typeid_as_u64(p->module, type); } else { auto tv = type_and_value_of_expr(expr); GB_ASSERT(tv.mode == Addressing_Constant); @@ -1912,21 +1916,16 @@ gb_internal void cg_build_switch_stmt(cgProcedure *p, Ast *node) { cg_scope_close(p, cgDeferExit_Default, done); } -gb_internal void cg_type_case_body(cgProcedure *p, Ast *label, Ast *clause, TB_Node *body_region, TB_Node *done_region) { - // ast_node(cc, CaseClause, clause); - - // cg_push_target_list(p, label, done, nullptr, nullptr); - // cg_build_stmt_list(p, cc->stmts); - // cg_scope_close(p, cgDeferExit_Default, body_region); - // cg_pop_target_list(p); - - // cg_emit_goto(p, done_region); -} - gb_internal void cg_build_type_switch_stmt(cgProcedure *p, Ast *node) { ast_node(ss, TypeSwitchStmt, node); + TB_Node *done_region = cg_control_region(p, "typeswitch_done"); + TB_Node *else_region = done_region; + TB_Node *default_region = nullptr; + isize num_cases = 0; + cg_scope_open(p, ss->scope); + defer (cg_scope_close(p, cgDeferExit_Default, done_region)); ast_node(as, AssignStmt, ss->tag); GB_ASSERT(as->lhs.count == 1); @@ -1969,11 +1968,6 @@ gb_internal void cg_build_type_switch_stmt(cgProcedure *p, Ast *node) { ast_node(body, BlockStmt, ss->body); - TB_Node *done_region = cg_control_region(p, "typeswitch_done"); - TB_Node *else_region = done_region; - TB_Node *default_region = nullptr; - isize num_cases = 0; - for (Ast *clause : body->stmts) { ast_node(cc, CaseClause, clause); num_cases += cc->list.count; @@ -2158,7 +2152,6 @@ gb_internal void cg_build_type_switch_stmt(cgProcedure *p, Ast *node) { cg_emit_goto(p, done_region); tb_inst_set_control(p->func, done_region); - cg_scope_close(p, cgDeferExit_Default, done_region); } diff --git a/src/tilde_type_info.cpp b/src/tilde_type_info.cpp index 1e86f6644..adad2cace 100644 --- a/src/tilde_type_info.cpp +++ b/src/tilde_type_info.cpp @@ -340,6 +340,173 @@ gb_internal void cg_setup_type_info_data(cgModule *m) { break; } break; + + case Type_Pointer: + tag_type = t_type_info_pointer; + cg_global_const_type_info_ptr(m, type_table_array, t->Pointer.elem, global, offset+0); + break; + case Type_MultiPointer: + tag_type = t_type_info_multi_pointer; + cg_global_const_type_info_ptr(m, type_table_array, t->MultiPointer.elem, global, offset+0); + break; + case Type_SoaPointer: + tag_type = t_type_info_soa_pointer; + cg_global_const_type_info_ptr(m, type_table_array, t->SoaPointer.elem, global, offset+0); + break; + + case Type_Array: + { + tag_type = t_type_info_array; + + cg_global_const_type_info_ptr(m, type_table_array, t->Array.elem, global, offset+0); + void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+1*build_context.int_size, build_context.int_size); + void *count_ptr = tb_global_add_region(m->mod, global, offset+2*build_context.int_size, build_context.int_size); + + cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->Array.elem), t_int); + cg_write_int_at_ptr(count_ptr, t->Array.count, t_int); + } + break; + + case Type_EnumeratedArray: + { + tag_type = t_type_info_enumerated_array; + + i64 elem_offset = type_offset_of(tag_type, 0); + i64 index_offset = type_offset_of(tag_type, 1); + i64 elem_size_offset = type_offset_of(tag_type, 2); + i64 count_offset = type_offset_of(tag_type, 3); + i64 min_value_offset = type_offset_of(tag_type, 4); + i64 max_value_offset = type_offset_of(tag_type, 5); + i64 is_sparse_offset = type_offset_of(tag_type, 6); + + cg_global_const_type_info_ptr(m, type_table_array, t->EnumeratedArray.elem, global, offset+elem_offset); + cg_global_const_type_info_ptr(m, type_table_array, t->EnumeratedArray.index, global, offset+index_offset); + + void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+elem_size_offset, build_context.int_size); + void *count_ptr = tb_global_add_region(m->mod, global, offset+count_offset, build_context.int_size); + + void *min_value_ptr = tb_global_add_region(m->mod, global, offset+min_value_offset, type_size_of(t_type_info_enum_value)); + void *max_value_ptr = tb_global_add_region(m->mod, global, offset+max_value_offset, type_size_of(t_type_info_enum_value)); + void *is_sparse_ptr = tb_global_add_region(m->mod, global, offset+is_sparse_offset, 1); + + cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->EnumeratedArray.elem), t_int); + cg_write_int_at_ptr(count_ptr, t->EnumeratedArray.count, t_int); + + cg_write_int_at_ptr(min_value_ptr, exact_value_to_i64(*t->EnumeratedArray.min_value), t_type_info_enum_value); + cg_write_int_at_ptr(max_value_ptr, exact_value_to_i64(*t->EnumeratedArray.max_value), t_type_info_enum_value); + *(bool *)is_sparse_ptr = t->EnumeratedArray.is_sparse; + } + break; + + case Type_DynamicArray: + { + tag_type = t_type_info_dynamic_array; + + cg_global_const_type_info_ptr(m, type_table_array, t->DynamicArray.elem, global, offset+0); + void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+1*build_context.int_size, build_context.int_size); + cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->DynamicArray.elem), t_int); + } + break; + case Type_Slice: + { + tag_type = t_type_info_slice; + + cg_global_const_type_info_ptr(m, type_table_array, t->Slice.elem, global, offset+0); + void *elem_size_ptr = tb_global_add_region(m->mod, global, offset+1*build_context.int_size, build_context.int_size); + cg_write_int_at_ptr(elem_size_ptr, type_size_of(t->Slice.elem), t_int); + } + break; + + case Type_Proc: + { + tag_type = t_type_info_procedure; + + i64 params_offset = type_offset_of(tag_type, 0); + i64 results_offset = type_offset_of(tag_type, 1); + i64 variadic_offset = type_offset_of(tag_type, 2); + i64 convention_offset = type_offset_of(tag_type, 3); + + if (t->Proc.params) { + cg_global_const_type_info_ptr(m, type_table_array, t->Proc.params, global, offset+params_offset); + } + if (t->Proc.results) { + cg_global_const_type_info_ptr(m, type_table_array, t->Proc.results, global, offset+results_offset); + } + + bool *variadic_ptr = cast(bool *)tb_global_add_region(m->mod, global, offset+variadic_offset, 1); + u8 * convention_ptr = cast(u8 *) tb_global_add_region(m->mod, global, offset+convention_offset, 1); + + *variadic_ptr = t->Proc.variadic; + *convention_ptr = cast(u8)t->Proc.calling_convention; + } + break; + + case Type_Tuple: + { + tag_type = t_type_info_parameters; + + // TODO(bill): Type_Info_Parameters + } + break; + + case Type_Enum: + { + tag_type = t_type_info_enum; + + // TODO(bill): Type_Info_Enum + } + break; + case Type_Struct: + { + tag_type = t_type_info_struct; + + // TODO(bill): Type_Info_Struct + } + break; + case Type_Union: + { + tag_type = t_type_info_union; + + // TODO(bill): Type_Info_Union + } + break; + case Type_Map: + { + tag_type = t_type_info_map; + + // TODO(bill): Type_Info_Map + } + break; + case Type_BitSet: + { + tag_type = t_type_info_bit_set; + + // TODO(bill): Type_Info_Bit_Set + } + break; + case Type_SimdVector: + { + tag_type = t_type_info_simd_vector; + + // TODO(bill): Type_Info_Simd_Vector + } + break; + + case Type_RelativePointer: + { + tag_type = t_type_info_relative_pointer; + } + break; + case Type_RelativeSlice: + { + tag_type = t_type_info_relative_slice; + } + break; + case Type_Matrix: + { + tag_type = t_type_info_matrix; + } + break; } if (tag_type != nullptr) { -- cgit v1.2.3 From e4006eb58343d35e7e26177a1adf41b0d9665b10 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Jul 2023 01:11:57 +0100 Subject: Update tilde --- src/tilde/tb.lib | Bin 4164640 -> 4162070 bytes src/tilde_proc.cpp | 54 +++++++++++++++-------------------------------------- src/tilde_stmt.cpp | 34 +++++++++++++++++++++++++++------ 3 files changed, 43 insertions(+), 45 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index 78e661bf8..adf355d07 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 398148965..08cbcc631 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -260,44 +260,6 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { if (e) { map_set(&p->variable_map, e, addr); } - - // if (arg_type->kind == lbArg_Ignore) { - // continue; - // } else if (arg_type->kind == lbArg_Direct) { - // if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { - // LLVMTypeRef param_type = lb_type(p->module, e->type); - // LLVMValueRef original_value = LLVMGetParam(p->value, param_offset+param_index); - // LLVMValueRef value = OdinLLVMBuildTransmute(p, original_value, param_type); - - // lbValue param = {}; - // param.value = value; - // param.type = e->type; - - // map_set(&p->direct_parameters, e, param); - - // lbValue ptr = lb_address_from_load_or_generate_local(p, param); - // GB_ASSERT(LLVMIsAAllocaInst(ptr.value)); - // lb_add_entity(p->module, e, ptr); - - // lbBlock *block = p->decl_block; - // if (original_value != value) { - // block = p->curr_block; - // } - // LLVMValueRef debug_storage_value = value; - // if (original_value != value && LLVMIsALoadInst(value)) { - // debug_storage_value = LLVMGetOperand(value, 0); - // } - // lb_add_debug_param_variable(p, debug_storage_value, e->type, e->token, param_index+1, block, arg_type->kind); - // } - // } else if (arg_type->kind == lbArg_Indirect) { - // if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { - // lbValue ptr = {}; - // ptr.value = LLVMGetParam(p->value, param_offset+param_index); - // ptr.type = alloc_type_pointer(e->type); - // lb_add_entity(p->module, e, ptr); - // lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block, arg_type->kind); - // } - // } } if (is_odin_like_cc) { @@ -351,6 +313,20 @@ gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) { bool emit_asm = false; + if (false && + string_starts_with(p->name, str_lit("bug@main"))) { + TB_Arena *arena = cg_arena(); + TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena); + defer (tb_funcopt_exit(opt)); + + tb_funcopt_peephole(opt); + tb_funcopt_mem2reg(opt); + tb_funcopt_peephole(opt); + + emit_asm = true; + } + + if ( // string_starts_with(p->name, str_lit("bug@main")) || false @@ -398,7 +374,7 @@ gb_internal void cg_procedure_generate(cgProcedure *p) { if ( - // string_starts_with(p->name, str_lit("bug@main")) || + string_starts_with(p->name, str_lit("bug@main")) || false ) { // IR Printing TB_Arena *arena = tb_default_arena(); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index a663a401d..794061335 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -2246,20 +2246,42 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { TEMPORARY_ALLOCATOR_GUARD(); + auto inits = array_make(temporary_allocator(), 0, vd->values.count != 0 ? vd->names.count : 0); + for (Ast *rhs : vd->values) { + cgValue init = cg_build_expr(p, rhs); + cg_append_tuple_values(p, &inits, init); + } + + auto lvals = slice_make(temporary_allocator(), vd->names.count); for_array(i, vd->names) { Ast *name = vd->names[i]; if (!is_blank_ident(name)) { Entity *e = entity_of_node(name); - lvals[i] = cg_add_local(p, e->type, e, true); + bool zero_init = vd->values.count == 0; + if (vd->names.count == vd->values.count) { + Ast *expr = unparen_expr(vd->values[i]); + if (expr->kind == Ast_CompoundLit && + inits[i].kind == cgValue_Addr) { + TB_Node *ptr = inits[i].node; + + if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { + // NOTE(bill): for debugging purposes only + String name = e->token.string; + TB_DebugType *debug_type = cg_debug_type(p->module, e->type); + tb_node_append_attrib(ptr, tb_function_attrib_variable(p->func, name.len, cast(char const *)name.text, debug_type)); + } + + cgAddr addr = cg_addr(inits[i]); + map_set(&p->variable_map, e, addr); + continue; + } + } + + lvals[i] = cg_add_local(p, e->type, e, zero_init); } } - auto inits = array_make(temporary_allocator(), 0, vd->values.count != 0 ? lvals.count : 0); - for (Ast *rhs : vd->values) { - cgValue init = cg_build_expr(p, rhs); - cg_append_tuple_values(p, &inits, init); - } GB_ASSERT(vd->values.count == 0 || lvals.count == inits.count); for_array(i, inits) { -- cgit v1.2.3 From ab398f37042af66069e746f4f1bf5b214da1b371 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Jul 2023 13:46:40 +0100 Subject: Implement `@(static)` local variables --- src/tilde.cpp | 4 +++- src/tilde_const.cpp | 11 +++++----- src/tilde_stmt.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 68 insertions(+), 7 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde.cpp b/src/tilde.cpp index 9550374e8..a8c398a69 100644 --- a/src/tilde.cpp +++ b/src/tilde.cpp @@ -250,7 +250,9 @@ gb_internal TB_Symbol *cg_find_symbol_from_entity(cgModule *m, Entity *e) { String link_name = cg_get_entity_name(m, e); cgProcedure **proc_found = string_map_get(&m->procedures, link_name); if (proc_found) { - return (*proc_found)->symbol; + TB_Symbol *symbol = (*proc_found)->symbol; + map_set(&m->symbols, e, symbol); + return symbol; } GB_PANIC("could not find entity's symbol %.*s", LIT(e->token.string)); return nullptr; diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index 05b57a97a..d37edb89a 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -347,22 +347,23 @@ gb_internal isize cg_global_const_calculate_region_count(ExactValue const &value case ExactValue_Bool: case ExactValue_Integer: case ExactValue_Float: - case ExactValue_Pointer: case ExactValue_Typeid: case ExactValue_Complex: case ExactValue_Quaternion: return 1; + case ExactValue_Pointer: + return 2; case ExactValue_Procedure: return 1; case ExactValue_String: if (is_type_string(type)) { - return 2; + return 3; } else if (is_type_cstring(type) || is_type_array_like(type)) { - return 1; + return 2; } - return 2; + return 3; case ExactValue_Compound: { ast_node(cl, CompoundLit, value.value_compound); @@ -455,7 +456,7 @@ gb_internal isize cg_global_const_calculate_region_count(ExactValue const &value return 1; case Type_Slice: - return 2; + return 3; default: GB_PANIC("TODO(bill): %s", type_to_string(type)); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 794061335..caa622b4d 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -2240,7 +2240,65 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { } } if (is_static) { - GB_PANIC("TODO(bill): build static variables"); + for_array(i, vd->names) { + Ast *ident = vd->names[i]; + GB_ASSERT(!is_blank_ident(ident)); + Entity *e = entity_of_node(ident); + GB_ASSERT(e->flags & EntityFlag_Static); + String name = e->token.string; + + String mangled_name = {}; + { + gbString str = gb_string_make_length(permanent_allocator(), p->name.text, p->name.len); + str = gb_string_appendc(str, "-"); + str = gb_string_append_fmt(str, ".%.*s-%llu", LIT(name), cast(long long)e->id); + mangled_name.text = cast(u8 *)str; + mangled_name.len = gb_string_length(str); + } + + cgModule *m = p->module; + + TB_DebugType *debug_type = cg_debug_type(m, e->type); + TB_Global *global = tb_global_create(m->mod, mangled_name.len, cast(char const *)mangled_name.text, debug_type, TB_LINKAGE_PRIVATE); + + TB_ModuleSection *section = tb_module_get_data(m->mod); + if (e->Variable.thread_local_model != "") { + section = tb_module_get_tls(m->mod); + String model = e->Variable.thread_local_model; + if (model == "default") { + // TODO(bill): Thread Local Storage models + } else if (model == "localdynamic") { + // TODO(bill): Thread Local Storage models + } else if (model == "initialexec") { + // TODO(bill): Thread Local Storage models + } else if (model == "localexec") { + // TODO(bill): Thread Local Storage models + } else { + GB_PANIC("Unhandled thread local mode %.*s", LIT(model)); + } + } + + i64 max_objects = 0; + ExactValue value = {}; + + if (vd->values.count > 0) { + GB_ASSERT(vd->names.count == vd->values.count); + Ast *ast_value = vd->values[i]; + GB_ASSERT(ast_value->tav.mode == Addressing_Constant || + ast_value->tav.mode == Addressing_Invalid); + + value = ast_value->tav.value; + max_objects = cg_global_const_calculate_region_count(value, e->type); + } + tb_global_set_storage(m->mod, section, global, type_size_of(e->type), type_align_of(e->type), max_objects); + + cg_global_const_add_region(m, value, e->type, global, 0); + + TB_Node *node = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)global); + cgValue global_val = cg_value(node, alloc_type_pointer(e->type)); + cg_add_entity(p->module, e, global_val); + cg_add_member(p->module, mangled_name, global_val); + } return; } -- cgit v1.2.3 From c6e4b8ed5cf4a203e4454e2ee50befcea73968e9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Jul 2023 13:49:19 +0100 Subject: Move mutable value decl stuff to a separate procedure --- src/tilde_stmt.cpp | 255 +++++++++++++++++++++++++++-------------------------- 1 file changed, 131 insertions(+), 124 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index caa622b4d..88c266689 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -2155,6 +2155,136 @@ gb_internal void cg_build_type_switch_stmt(cgProcedure *p, Ast *node) { } +gb_internal void cg_build_mutable_value_decl(cgProcedure *p, Ast *node) { + ast_node(vd, ValueDecl, node); + if (!vd->is_mutable) { + return; + } + + bool is_static = false; + for (Ast *name : vd->names) if (!is_blank_ident(name)) { + // NOTE(bill): Sanity check to check for the existence of the variable's Entity + GB_ASSERT(name->kind == Ast_Ident); + Entity *e = entity_of_node(name); + TokenPos pos = ast_token(name).pos; + GB_ASSERT_MSG(e != nullptr, "\n%s missing entity for %.*s", token_pos_to_string(pos), LIT(name->Ident.token.string)); + if (e->flags & EntityFlag_Static) { + // NOTE(bill): If one of the entities is static, they all are + is_static = true; + } + } + + if (is_static) { + for_array(i, vd->names) { + Ast *ident = vd->names[i]; + GB_ASSERT(!is_blank_ident(ident)); + Entity *e = entity_of_node(ident); + GB_ASSERT(e->flags & EntityFlag_Static); + String name = e->token.string; + + String mangled_name = {}; + { + gbString str = gb_string_make_length(permanent_allocator(), p->name.text, p->name.len); + str = gb_string_appendc(str, "-"); + str = gb_string_append_fmt(str, ".%.*s-%llu", LIT(name), cast(long long)e->id); + mangled_name.text = cast(u8 *)str; + mangled_name.len = gb_string_length(str); + } + + cgModule *m = p->module; + + TB_DebugType *debug_type = cg_debug_type(m, e->type); + TB_Global *global = tb_global_create(m->mod, mangled_name.len, cast(char const *)mangled_name.text, debug_type, TB_LINKAGE_PRIVATE); + + TB_ModuleSection *section = tb_module_get_data(m->mod); + if (e->Variable.thread_local_model != "") { + section = tb_module_get_tls(m->mod); + String model = e->Variable.thread_local_model; + if (model == "default") { + // TODO(bill): Thread Local Storage models + } else if (model == "localdynamic") { + // TODO(bill): Thread Local Storage models + } else if (model == "initialexec") { + // TODO(bill): Thread Local Storage models + } else if (model == "localexec") { + // TODO(bill): Thread Local Storage models + } else { + GB_PANIC("Unhandled thread local mode %.*s", LIT(model)); + } + } + + i64 max_objects = 0; + ExactValue value = {}; + + if (vd->values.count > 0) { + GB_ASSERT(vd->names.count == vd->values.count); + Ast *ast_value = vd->values[i]; + GB_ASSERT(ast_value->tav.mode == Addressing_Constant || + ast_value->tav.mode == Addressing_Invalid); + + value = ast_value->tav.value; + max_objects = cg_global_const_calculate_region_count(value, e->type); + } + tb_global_set_storage(m->mod, section, global, type_size_of(e->type), type_align_of(e->type), max_objects); + + cg_global_const_add_region(m, value, e->type, global, 0); + + TB_Node *node = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)global); + cgValue global_val = cg_value(node, alloc_type_pointer(e->type)); + cg_add_entity(p->module, e, global_val); + cg_add_member(p->module, mangled_name, global_val); + } + return; + } + + TEMPORARY_ALLOCATOR_GUARD(); + + auto inits = array_make(temporary_allocator(), 0, vd->values.count != 0 ? vd->names.count : 0); + for (Ast *rhs : vd->values) { + cgValue init = cg_build_expr(p, rhs); + cg_append_tuple_values(p, &inits, init); + } + + + auto lvals = slice_make(temporary_allocator(), vd->names.count); + for_array(i, vd->names) { + Ast *name = vd->names[i]; + if (!is_blank_ident(name)) { + Entity *e = entity_of_node(name); + bool zero_init = vd->values.count == 0; + if (vd->names.count == vd->values.count) { + Ast *expr = unparen_expr(vd->values[i]); + if (expr->kind == Ast_CompoundLit && + inits[i].kind == cgValue_Addr) { + TB_Node *ptr = inits[i].node; + + if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { + // NOTE(bill): for debugging purposes only + String name = e->token.string; + TB_DebugType *debug_type = cg_debug_type(p->module, e->type); + tb_node_append_attrib(ptr, tb_function_attrib_variable(p->func, name.len, cast(char const *)name.text, debug_type)); + } + + cgAddr addr = cg_addr(inits[i]); + map_set(&p->variable_map, e, addr); + continue; + } + } + + lvals[i] = cg_add_local(p, e->type, e, zero_init); + } + } + + + GB_ASSERT(vd->values.count == 0 || lvals.count == inits.count); + for_array(i, inits) { + cgAddr lval = lvals[i]; + cgValue init = inits[i]; + cg_addr_store(p, lval, init); + } +} + + gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { Ast *prev_stmt = p->curr_stmt; defer (p->curr_stmt = prev_stmt); @@ -2223,130 +2353,7 @@ gb_internal void cg_build_stmt(cgProcedure *p, Ast *node) { case_end; case_ast_node(vd, ValueDecl, node); - if (!vd->is_mutable) { - return; - } - - bool is_static = false; - for (Ast *name : vd->names) if (!is_blank_ident(name)) { - // NOTE(bill): Sanity check to check for the existence of the variable's Entity - GB_ASSERT(name->kind == Ast_Ident); - Entity *e = entity_of_node(name); - TokenPos pos = ast_token(name).pos; - GB_ASSERT_MSG(e != nullptr, "\n%s missing entity for %.*s", token_pos_to_string(pos), LIT(name->Ident.token.string)); - if (e->flags & EntityFlag_Static) { - // NOTE(bill): If one of the entities is static, they all are - is_static = true; - } - } - if (is_static) { - for_array(i, vd->names) { - Ast *ident = vd->names[i]; - GB_ASSERT(!is_blank_ident(ident)); - Entity *e = entity_of_node(ident); - GB_ASSERT(e->flags & EntityFlag_Static); - String name = e->token.string; - - String mangled_name = {}; - { - gbString str = gb_string_make_length(permanent_allocator(), p->name.text, p->name.len); - str = gb_string_appendc(str, "-"); - str = gb_string_append_fmt(str, ".%.*s-%llu", LIT(name), cast(long long)e->id); - mangled_name.text = cast(u8 *)str; - mangled_name.len = gb_string_length(str); - } - - cgModule *m = p->module; - - TB_DebugType *debug_type = cg_debug_type(m, e->type); - TB_Global *global = tb_global_create(m->mod, mangled_name.len, cast(char const *)mangled_name.text, debug_type, TB_LINKAGE_PRIVATE); - - TB_ModuleSection *section = tb_module_get_data(m->mod); - if (e->Variable.thread_local_model != "") { - section = tb_module_get_tls(m->mod); - String model = e->Variable.thread_local_model; - if (model == "default") { - // TODO(bill): Thread Local Storage models - } else if (model == "localdynamic") { - // TODO(bill): Thread Local Storage models - } else if (model == "initialexec") { - // TODO(bill): Thread Local Storage models - } else if (model == "localexec") { - // TODO(bill): Thread Local Storage models - } else { - GB_PANIC("Unhandled thread local mode %.*s", LIT(model)); - } - } - - i64 max_objects = 0; - ExactValue value = {}; - - if (vd->values.count > 0) { - GB_ASSERT(vd->names.count == vd->values.count); - Ast *ast_value = vd->values[i]; - GB_ASSERT(ast_value->tav.mode == Addressing_Constant || - ast_value->tav.mode == Addressing_Invalid); - - value = ast_value->tav.value; - max_objects = cg_global_const_calculate_region_count(value, e->type); - } - tb_global_set_storage(m->mod, section, global, type_size_of(e->type), type_align_of(e->type), max_objects); - - cg_global_const_add_region(m, value, e->type, global, 0); - - TB_Node *node = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)global); - cgValue global_val = cg_value(node, alloc_type_pointer(e->type)); - cg_add_entity(p->module, e, global_val); - cg_add_member(p->module, mangled_name, global_val); - } - return; - } - - TEMPORARY_ALLOCATOR_GUARD(); - - auto inits = array_make(temporary_allocator(), 0, vd->values.count != 0 ? vd->names.count : 0); - for (Ast *rhs : vd->values) { - cgValue init = cg_build_expr(p, rhs); - cg_append_tuple_values(p, &inits, init); - } - - - auto lvals = slice_make(temporary_allocator(), vd->names.count); - for_array(i, vd->names) { - Ast *name = vd->names[i]; - if (!is_blank_ident(name)) { - Entity *e = entity_of_node(name); - bool zero_init = vd->values.count == 0; - if (vd->names.count == vd->values.count) { - Ast *expr = unparen_expr(vd->values[i]); - if (expr->kind == Ast_CompoundLit && - inits[i].kind == cgValue_Addr) { - TB_Node *ptr = inits[i].node; - - if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { - // NOTE(bill): for debugging purposes only - String name = e->token.string; - TB_DebugType *debug_type = cg_debug_type(p->module, e->type); - tb_node_append_attrib(ptr, tb_function_attrib_variable(p->func, name.len, cast(char const *)name.text, debug_type)); - } - - cgAddr addr = cg_addr(inits[i]); - map_set(&p->variable_map, e, addr); - continue; - } - } - - lvals[i] = cg_add_local(p, e->type, e, zero_init); - } - } - - - GB_ASSERT(vd->values.count == 0 || lvals.count == inits.count); - for_array(i, inits) { - cgAddr lval = lvals[i]; - cgValue init = inits[i]; - cg_addr_store(p, lval, init); - } + cg_build_mutable_value_decl(p, node); case_end; case_ast_node(bs, BranchStmt, node); -- cgit v1.2.3 From 0f217c715ecd9fc265b1c6a3d579b99ecf849139 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Jul 2023 15:15:35 +0100 Subject: Fix dependency issue; Allow polymorphic procedures in tilde --- src/check_expr.cpp | 3 +- src/tilde.hpp | 3 +- src/tilde_debug.cpp | 11 ++- src/tilde_expr.cpp | 278 ++++++++++++++++++++++++++-------------------------- src/tilde_proc.cpp | 55 +++++++---- src/tilde_stmt.cpp | 28 ++++++ src/types.cpp | 30 ++++-- 7 files changed, 233 insertions(+), 175 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 98154f33d..d5e5f7952 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5985,8 +5985,8 @@ gb_internal bool check_call_arguments_single(CheckerContext *c, Ast *call, Opera } Entity *entity_to_use = data->gen_entity != nullptr ? data->gen_entity : e; + add_entity_use(c, ident, entity_to_use); if (!return_on_failure && entity_to_use != nullptr) { - add_entity_use(c, ident, entity_to_use); update_untyped_expr_type(c, operand->expr, entity_to_use->type, true); add_type_and_value(c, operand->expr, operand->mode, entity_to_use->type, operand->value); } @@ -7174,6 +7174,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c c->decl->defer_used += 1; } } + add_entity_use(c, operand->expr, initial_entity); } if (operand->mode != Addressing_ProcGroup) { diff --git a/src/tilde.hpp b/src/tilde.hpp index 72d5048bb..7f2ee8076 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -309,7 +309,8 @@ gb_internal cgValue cg_addr_get_ptr(cgProcedure *p, cgAddr const &addr); gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile=false); gb_internal void cg_emit_store(cgProcedure *p, cgValue dst, cgValue src, bool is_volatile=false); -gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero_init); +gb_internal cgAddr cg_add_local (cgProcedure *p, Type *type, Entity *e, bool zero_init); +gb_internal cgAddr cg_add_global(cgProcedure *p, Type *type, Entity *e); gb_internal cgValue cg_address_from_load_or_generate_local(cgProcedure *p, cgValue value); gb_internal cgValue cg_copy_value_to_ptr(cgProcedure *p, cgValue value, Type *original_type, isize min_alignment); diff --git a/src/tilde_debug.cpp b/src/tilde_debug.cpp index e6e60be96..708476377 100644 --- a/src/tilde_debug.cpp +++ b/src/tilde_debug.cpp @@ -76,9 +76,18 @@ gb_internal TB_DebugType *cg_debug_type_internal_record(cgModule *m, Type *type, type_set_offsets(bt); TB_DebugType *record = tb_debug_create_struct(m->mod, 0, ""); - TB_DebugType **fields = tb_debug_record_begin(record, bt->Tuple.variables.count); + isize record_count = 0; + for (Entity *e : bt->Tuple.variables) { + if (e->kind == Entity_Variable) { + record_count += 1; + } + } + TB_DebugType **fields = tb_debug_record_begin(record, record_count); for_array(i, bt->Tuple.variables) { Entity *e = bt->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + continue; + } Type *type = e->type; if (is_type_proc(type)) { type = t_rawptr; diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 96f17bfcf..1966dcd8e 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -2399,7 +2399,12 @@ cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) { Type *type = type_of_expr(expr); Type *bt = base_type(type); - cgAddr v = cg_add_local(p, type, nullptr, true); + cgAddr v = {}; + if (p->is_startup) { + v = cg_add_global(p, type, nullptr); + } else { + v = cg_add_local(p, type, nullptr, true); + } if (cl->elems.count == 0) { // No need to create it @@ -2424,8 +2429,6 @@ cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) { } TokenPos pos = ast_token(expr).pos; - if (cl->elems.count == 0) { - } switch (bt->kind) { default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; @@ -2493,21 +2496,22 @@ cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) { return v; } - // case Type_Map: { - // GB_ASSERT(!build_context.no_dynamic_literals); + case Type_Map: { + GB_ASSERT(!build_context.no_dynamic_literals); + GB_PANIC("TODO(bill): map literals"); - // cgValue err = cg_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos); - // gb_unused(err); + // cgValue err = cg_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos); + // gb_unused(err); - // for (Ast *elem : cl->elems) { - // ast_node(fv, FieldValue, elem); + // for (Ast *elem : cl->elems) { + // ast_node(fv, FieldValue, elem); - // cgValue key = cg_build_expr(p, fv->field); - // cgValue value = cg_build_expr(p, fv->value); - // cg_internal_dynamic_map_set(p, v.addr, type, key, value, elem); - // } - // break; - // } + // cgValue key = cg_build_expr(p, fv->field); + // cgValue value = cg_build_expr(p, fv->value); + // cg_internal_dynamic_map_set(p, v.addr, type, key, value, elem); + // } + break; + } case Type_Array: { auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); @@ -2523,23 +2527,21 @@ cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) { assign_array(p, temp_data); break; } - // case Type_EnumeratedArray: { - // cg_addr_store(p, v, cg_const_value(p->module, type, exact_value_compound(expr))); - - // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + case Type_EnumeratedArray: { + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - // populate(p, cl->elems, &temp_data, type); + populate(p, cl->elems, &temp_data, type); - // cgValue dst_ptr = cg_addr_get_ptr(p, v); - // i64 index_offset = exact_value_to_i64(*bt->EnumeratedArray.min_value); - // for_array(i, temp_data) { - // i32 index = cast(i32)(temp_data[i].elem_index - index_offset); - // temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, index); - // } + cgValue dst_ptr = cg_addr_get_ptr(p, v); + i64 index_offset = exact_value_to_i64(*bt->EnumeratedArray.min_value); + for_array(i, temp_data) { + i32 index = cast(i32)(temp_data[i].elem_index - index_offset); + temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, index); + } - // assign_array(p, temp_data); - // break; - // } + assign_array(p, temp_data); + break; + } case Type_Slice: { isize count = gb_max(cl->elems.count, cl->max_count); @@ -2570,88 +2572,89 @@ cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) { return v; } - // case Type_DynamicArray: { - // GB_ASSERT(!build_context.no_dynamic_literals); + case Type_DynamicArray: { + GB_ASSERT(!build_context.no_dynamic_literals); - // Type *et = bt->DynamicArray.elem; - // cgValue size = cg_const_int(p->module, t_int, type_size_of(et)); - // cgValue align = cg_const_int(p->module, t_int, type_align_of(et)); + Type *et = bt->DynamicArray.elem; + cgValue size = cg_const_int(p, t_int, type_size_of(et)); + cgValue align = cg_const_int(p, t_int, type_align_of(et)); - // i64 item_count = gb_max(cl->max_count, cl->elems.count); - // { + i64 item_count = gb_max(cl->max_count, cl->elems.count); + { - // auto args = array_make(temporary_allocator(), 5); - // args[0] = cg_emit_conv(p, cg_addr_get_ptr(p, v), t_rawptr); - // args[1] = size; - // args[2] = align; - // args[3] = cg_const_int(p->module, t_int, item_count); - // args[4] = cg_emit_source_code_location_as_global(p, proc_name, pos); - // cg_emit_runtime_call(p, "__dynamic_array_reserve", args); - // } + auto args = slice_make(temporary_allocator(), 5); + args[0] = cg_emit_conv(p, cg_addr_get_ptr(p, v), t_rawptr); + args[1] = size; + args[2] = align; + args[3] = cg_const_int(p, t_int, item_count); + args[4] = cg_emit_source_code_location_as_global(p, proc_name, pos); + cg_emit_runtime_call(p, "__dynamic_array_reserve", args); + } - // cgValue items = cg_generate_local_array(p, et, item_count); + Type *array_type = alloc_type_array(et, item_count); + cgAddr items_addr = cg_add_local(p, array_type, nullptr, true); + cgValue items = cg_addr_get_ptr(p, items_addr); - // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - // populate(p, cl->elems, &temp_data, type); + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + populate(p, cl->elems, &temp_data, type); - // for_array(i, temp_data) { - // temp_data[i].gep = cg_emit_array_epi(p, items, temp_data[i].elem_index); - // } - // assign_array(p, temp_data); - - // { - // auto args = array_make(temporary_allocator(), 6); - // args[0] = cg_emit_conv(p, v.addr, t_rawptr); - // args[1] = size; - // args[2] = align; - // args[3] = cg_emit_conv(p, items, t_rawptr); - // args[4] = cg_const_int(p->module, t_int, item_count); - // args[5] = cg_emit_source_code_location_as_global(p, proc_name, pos); - // cg_emit_runtime_call(p, "__dynamic_array_append", args); - // } - // break; - // } + for_array(i, temp_data) { + temp_data[i].gep = cg_emit_array_epi(p, items, temp_data[i].elem_index); + } + assign_array(p, temp_data); - // case Type_Basic: { - // GB_ASSERT(is_type_any(bt)); - // cg_addr_store(p, v, cg_const_value(p->module, type, exact_value_compound(expr))); - // String field_names[2] = { - // str_lit("data"), - // str_lit("id"), - // }; - // Type *field_types[2] = { - // t_rawptr, - // t_typeid, - // }; - - // for_array(field_index, cl->elems) { - // Ast *elem = cl->elems[field_index]; - - // cgValue field_expr = {}; - // isize index = field_index; - - // if (elem->kind == Ast_FieldValue) { - // ast_node(fv, FieldValue, elem); - // Selection sel = lookup_field(bt, fv->field->Ident.token.string, false); - // index = sel.index[0]; - // elem = fv->value; - // } else { - // TypeAndValue tav = type_and_value_of_expr(elem); - // Selection sel = lookup_field(bt, field_names[field_index], false); - // index = sel.index[0]; - // } - - // field_expr = cg_build_expr(p, elem); - - // GB_ASSERT(field_expr.type->kind != Type_Tuple); - - // Type *ft = field_types[index]; - // cgValue fv = cg_emit_conv(p, field_expr, ft); - // cgValue gep = cg_emit_struct_ep(p, cg_addr_get_ptr(p, v), cast(i32)index); - // cg_emit_store(p, gep, fv); - // } - // break; - // } + { + auto args = slice_make(temporary_allocator(), 6); + args[0] = cg_emit_conv(p, v.addr, t_rawptr); + args[1] = size; + args[2] = align; + args[3] = cg_emit_conv(p, items, t_rawptr); + args[4] = cg_const_int(p, t_int, item_count); + args[5] = cg_emit_source_code_location_as_global(p, proc_name, pos); + cg_emit_runtime_call(p, "__dynamic_array_append", args); + } + break; + } + + case Type_Basic: { + GB_ASSERT(is_type_any(bt)); + String field_names[2] = { + str_lit("data"), + str_lit("id"), + }; + Type *field_types[2] = { + t_rawptr, + t_typeid, + }; + + for_array(field_index, cl->elems) { + Ast *elem = cl->elems[field_index]; + + cgValue field_expr = {}; + isize index = field_index; + + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + Selection sel = lookup_field(bt, fv->field->Ident.token.string, false); + index = sel.index[0]; + elem = fv->value; + } else { + TypeAndValue tav = type_and_value_of_expr(elem); + Selection sel = lookup_field(bt, field_names[field_index], false); + index = sel.index[0]; + } + + field_expr = cg_build_expr(p, elem); + + GB_ASSERT(field_expr.type->kind != Type_Tuple); + + Type *ft = field_types[index]; + cgValue fv = cg_emit_conv(p, field_expr, ft); + cgValue gep = cg_emit_struct_ep(p, cg_addr_get_ptr(p, v), index); + cg_emit_store(p, gep, fv); + } + break; + } case Type_BitSet: { i64 sz = type_size_of(type); @@ -2679,48 +2682,41 @@ cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) { return v; } - // case Type_Matrix: { - // cg_addr_store(p, v, cg_const_value(p->module, type, exact_value_compound(expr))); + case Type_Matrix: { + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + populate(p, cl->elems, &temp_data, type); - // populate(p, cl->elems, &temp_data, type); + cgValue dst_ptr = cg_addr_get_ptr(p, v); + for_array(i, temp_data) { + temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, temp_data[i].elem_index); + } - // cgValue dst_ptr = cg_addr_get_ptr(p, v); - // for_array(i, temp_data) { - // temp_data[i].gep = cg_emit_array_epi(p, dst_ptr, temp_data[i].elem_index); - // } + assign_array(p, temp_data); + break; + } - // assign_array(p, temp_data); - // break; - // } + case Type_SimdVector: { + // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - // case Type_SimdVector: { - // cgValue vector_value = cg_const_value(p->module, type, exact_value_compound(expr)); - // defer (cg_addr_store(p, v, vector_value)); - - // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - // populate(p, cl->elems, &temp_data, type); - - // // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector` - // // might be a better option - // for (auto const &td : temp_data) { - // if (td.value.value != nullptr) { - // if (td.elem_length > 0) { - // for (i64 k = 0; k < td.elem_length; k++) { - // LLVMValueRef index = cg_const_int(p->module, t_u32, td.elem_index + k).value; - // vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, ""); - // } - // } else { - // LLVMValueRef index = cg_const_int(p->module, t_u32, td.elem_index).value; - // vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, ""); - - // } - // } - // } - // break; - // } + // populate(p, cl->elems, &temp_data, type); + + // // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector` + // // might be a better option + // for (auto const &td : temp_data) if (td.value.node != nullptr) { + // if (td.elem_length > 0) { + // for (i64 k = 0; k < td.elem_length; k++) { + // LLVMValueRef index = cg_const_int(p->module, t_u32, td.elem_index + k).value; + // vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, ""); + // } + // } else { + // LLVMValueRef index = cg_const_int(p->module, t_u32, td.elem_index).value; + // vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, ""); + + // } + // } + break; + } } return v; diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 80948adea..7e751ac82 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -582,8 +582,13 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice params[param_index++] = local; } } + isize param_entity_index = 0; for_array(i, args) { - Type *param_type = param_entities[i]->type; + Entity *param_entity = nullptr; + do { + param_entity = param_entities[param_entity_index++]; + } while (param_entity->kind != Entity_Variable); + Type *param_type = param_entity->type; cgValue arg = args[i]; arg = cg_emit_conv(p, arg, param_type); arg = cg_flatten_value(p, arg); @@ -839,7 +844,15 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) { GB_ASSERT(ce->split_args != nullptr); - auto args = array_make(temporary_allocator(), 0, pt->param_count); + isize internal_param_count = 0; + if (pt->params) for (Entity *e : pt->params->Tuple.variables) { + if (e->kind == Entity_Variable) { + internal_param_count += 1; + } + } + GB_ASSERT(internal_param_count <= pt->param_count); + + auto args = array_make(temporary_allocator(), 0, internal_param_count); bool vari_expand = (ce->ellipsis.pos.line != 0); bool is_c_vararg = pt->c_vararg; @@ -918,7 +931,7 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) { } if (!is_c_vararg) { - array_resize(&args, pt->param_count); + array_resize(&args, internal_param_count); } for (Ast *arg : ce->split_args->named) { @@ -938,39 +951,39 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) { if (pt->params != nullptr) { - isize min_count = pt->params->Tuple.variables.count; + isize min_count = internal_param_count; if (is_c_vararg) { min_count -= 1; } - GB_ASSERT(args.count >= min_count); - for_array(arg_index, pt->params->Tuple.variables) { - Entity *e = pt->params->Tuple.variables[arg_index]; - if (pt->variadic && arg_index == pt->variadic_index) { + GB_ASSERT_MSG(args.count >= min_count, "in %.*s", LIT(p->name)); + isize arg_index = 0; + for_array(param_index, pt->params->Tuple.variables) { + Entity *e = pt->params->Tuple.variables[param_index]; + if (e->kind == Entity_TypeName) { + continue; + } else if (e->kind == Entity_Constant) { + continue; + } + GB_ASSERT(e->kind == Entity_Variable); + + if (pt->variadic && param_index == pt->variadic_index) { if (!is_c_vararg && args[arg_index].node == nullptr) { - args[arg_index] = cg_const_nil(p, e->type); + args[arg_index++] = cg_const_nil(p, e->type); } continue; } cgValue arg = args[arg_index]; if (arg.node == nullptr) { - switch (e->kind) { - case Entity_TypeName: - case Entity_Constant: - break; - case Entity_Variable: - args[arg_index] = cg_handle_param_value(p, e->type, e->Variable.param_value, pos); - break; - default: - GB_PANIC("Unknown entity kind %.*s\n", LIT(entity_strings[e->kind])); - } + GB_ASSERT(e->kind == Entity_Variable); + args[arg_index++] = cg_handle_param_value(p, e->type, e->Variable.param_value, pos); } else { - args[arg_index] = cg_emit_conv(p, arg, e->type); + args[arg_index++] = cg_emit_conv(p, arg, e->type); } } } - isize final_count = is_c_vararg ? args.count : pt->param_count; + isize final_count = is_c_vararg ? args.count : internal_param_count; auto call_args = slice(args, 0, final_count); return cg_emit_call(p, value, call_args); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 88c266689..0b5f122d4 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -747,6 +747,34 @@ gb_internal cgAddr cg_add_local(cgProcedure *p, Type *type, Entity *e, bool zero return addr; } +gb_internal cgAddr cg_add_global(cgProcedure *p, Type *type, Entity *e) { + GB_ASSERT(type != nullptr); + + isize size = type_size_of(type); + TB_CharUnits alignment = cast(TB_CharUnits)type_align_of(type); + if (is_type_matrix(type)) { + alignment *= 2; // NOTE(bill): Just in case + } + + TB_Global *global = tb_global_create(p->module->mod, 0, "", nullptr, TB_LINKAGE_PRIVATE); + tb_global_set_storage(p->module->mod, tb_module_get_data(p->module->mod), global, size, alignment, 0); + TB_Node *local = tb_inst_get_symbol_address(p->func, cast(TB_Symbol *)global); + + if (e != nullptr && e->token.string.len > 0 && e->token.string != "_") { + // NOTE(bill): for debugging purposes only + String name = e->token.string; + TB_DebugType *debug_type = cg_debug_type(p->module, type); + tb_node_append_attrib(local, tb_function_attrib_variable(p->func, name.len, cast(char const *)name.text, debug_type)); + } + + cgAddr addr = cg_addr(cg_value(local, alloc_type_pointer(type))); + if (e) { + map_set(&p->variable_map, e, addr); + } + return addr; +} + + gb_internal cgValue cg_copy_value_to_ptr(cgProcedure *p, cgValue value, Type *original_type, isize min_alignment) { TB_CharUnits size = cast(TB_CharUnits)type_size_of(original_type); TB_CharUnits align = cast(TB_CharUnits)gb_max(type_align_of(original_type), min_alignment); diff --git a/src/types.cpp b/src/types.cpp index 17945b109..f6e377cdc 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3646,18 +3646,26 @@ gb_internal i64 *type_set_offsets_of(Slice const &fields, bool is_pack } } else if (is_packed) { for_array(i, fields) { - i64 size = type_size_of(fields[i]->type); - offsets[i] = curr_offset; - curr_offset += size; + if (fields[i]->kind != Entity_Variable) { + offsets[i] = -1; + } else { + i64 size = type_size_of(fields[i]->type); + offsets[i] = curr_offset; + curr_offset += size; + } } } else { for_array(i, fields) { - Type *t = fields[i]->type; - i64 align = gb_max(type_align_of(t), 1); - i64 size = gb_max(type_size_of( t), 0); - curr_offset = align_formula(curr_offset, align); - offsets[i] = curr_offset; - curr_offset += size; + if (fields[i]->kind != Entity_Variable) { + offsets[i] = -1; + } else { + Type *t = fields[i]->type; + i64 align = gb_max(type_align_of(t), 1); + i64 size = gb_max(type_size_of( t), 0); + curr_offset = align_formula(curr_offset, align); + offsets[i] = curr_offset; + curr_offset += size; + } } } return offsets; @@ -3924,7 +3932,9 @@ gb_internal i64 type_offset_of(Type *t, i64 index, Type **field_type_) { if (gb_is_between(index, 0, t->Tuple.variables.count-1)) { GB_ASSERT(t->Tuple.offsets != nullptr); if (field_type_) *field_type_ = t->Tuple.variables[index]->type; - return t->Tuple.offsets[index]; + i64 offset = t->Tuple.offsets[index]; + GB_ASSERT(offset >= 0); + return offset; } break; -- cgit v1.2.3 From c39a3603720917d6970026e5c0595d468ea9b372 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 28 Jul 2023 14:57:04 +0100 Subject: Update Tilde for the new TB_Passes approach --- core/runtime/os_specific_windows.odin | 15 ++-- core/runtime/print.odin | 10 ++- src/tilde.cpp | 44 ++++++---- src/tilde.hpp | 12 +++ src/tilde/tb.h | 106 +++++++++++------------ src/tilde/tb.lib | Bin 4162224 -> 4177320 bytes src/tilde/tb_arena.h | 76 ++++++++++++++++ src/tilde_expr.cpp | 42 ++++++++- src/tilde_proc.cpp | 158 ++++++++++++++++++++++++++-------- src/tilde_stmt.cpp | 8 ++ 10 files changed, 345 insertions(+), 126 deletions(-) create mode 100644 src/tilde/tb_arena.h (limited to 'src/tilde_stmt.cpp') diff --git a/core/runtime/os_specific_windows.odin b/core/runtime/os_specific_windows.odin index 732715793..9f001fa5a 100644 --- a/core/runtime/os_specific_windows.odin +++ b/core/runtime/os_specific_windows.odin @@ -1,9 +1,6 @@ -//+private //+build windows package runtime -import "core:intrinsics" - foreign import kernel32 "system:Kernel32.lib" @(private="file") @@ -102,12 +99,12 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol allocated_mem: rawptr if old_ptr != nil { - original_old_ptr := intrinsics.ptr_offset((^rawptr)(old_ptr), -1)^ + original_old_ptr := ([^]rawptr)(old_ptr)[-1] allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr)) } else { allocated_mem = heap_alloc(space+size_of(rawptr), zero_memory) } - aligned_mem := rawptr(intrinsics.ptr_offset((^u8)(allocated_mem), size_of(rawptr))) + aligned_mem := ([^]u8)(allocated_mem)[size_of(rawptr):] ptr := uintptr(aligned_mem) aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a) @@ -116,10 +113,10 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol return nil, .Out_Of_Memory } - aligned_mem = rawptr(aligned_ptr) - intrinsics.ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem + aligned_mem = ([^]byte)(aligned_ptr) + ([^]rawptr)(aligned_mem)[-1] = allocated_mem - return byte_slice(aligned_mem, size), nil + return aligned_mem[:size], nil } _windows_default_alloc :: proc "contextless" (size, alignment: int, zero_memory := true) -> ([]byte, Allocator_Error) { @@ -129,7 +126,7 @@ _windows_default_alloc :: proc "contextless" (size, alignment: int, zero_memory _windows_default_free :: proc "contextless" (ptr: rawptr) { if ptr != nil { - heap_free(intrinsics.ptr_offset((^rawptr)(ptr), -1)^) + heap_free(([^]rawptr)(ptr)[-1]) } } diff --git a/core/runtime/print.odin b/core/runtime/print.odin index 20788b66f..035d47f15 100644 --- a/core/runtime/print.odin +++ b/core/runtime/print.odin @@ -8,6 +8,11 @@ _INTEGER_DIGITS_VAR := _INTEGER_DIGITS when !ODIN_NO_RTTI { print_any_single :: proc "contextless" (arg: any) { x := arg + if x.data == nil { + print_string("nil") + return + } + if loc, ok := x.(Source_Code_Location); ok { print_caller_location(loc) return @@ -48,6 +53,7 @@ when !ODIN_NO_RTTI { case int: print_int(v) case uint: print_uint(v) case uintptr: print_uintptr(v) + case rawptr: print_uintptr(uintptr(v)) case bool: print_string("true" if v else "false") case b8: print_string("true" if v else "false") @@ -58,7 +64,7 @@ when !ODIN_NO_RTTI { case: ti := type_info_of(x.id) #partial switch v in ti.variant { - case Type_Info_Pointer: + case Type_Info_Pointer, Type_Info_Multi_Pointer: print_uintptr((^uintptr)(x.data)^) return } @@ -67,7 +73,9 @@ when !ODIN_NO_RTTI { } } println_any :: proc "contextless" (args: ..any) { + context = default_context() loop: for arg, i in args { + assert(arg.id != nil) if i != 0 { print_string(" ") } diff --git a/src/tilde.cpp b/src/tilde.cpp index fc51a1156..0cbc975c4 100644 --- a/src/tilde.cpp +++ b/src/tilde.cpp @@ -1,16 +1,16 @@ #include "tilde.hpp" -gb_global Slice global_tb_arenas; +gb_global Slice global_tb_arenas; gb_internal TB_Arena *cg_arena(void) { - return global_tb_arenas[current_thread_index()]; + return &global_tb_arenas[current_thread_index()]; } gb_internal void cg_global_arena_init(void) { - global_tb_arenas = slice_make(permanent_allocator(), global_thread_pool.threads.count); + global_tb_arenas = slice_make(permanent_allocator(), global_thread_pool.threads.count); for_array(i, global_tb_arenas) { - global_tb_arenas[i] = tb_default_arena(); + tb_arena_create(&global_tb_arenas[i], 2ull<<20); } } @@ -426,14 +426,15 @@ gb_internal cgModule *cg_module_create(Checker *c) { map_init(&m->values); map_init(&m->symbols); - map_init(&m->file_id_map); - map_init(&m->debug_type_map); map_init(&m->proc_debug_type_map); map_init(&m->proc_proto_map); - map_init(&m->anonymous_proc_lits_map); + map_init(&m->equal_procs); + map_init(&m->hasher_procs); + map_init(&m->map_get_procs); + map_init(&m->map_set_procs); array_init(&m->single_threaded_procedure_queue, heap_allocator()); @@ -456,6 +457,10 @@ gb_internal void cg_module_destroy(cgModule *m) { map_destroy(&m->proc_debug_type_map); map_destroy(&m->proc_proto_map); map_destroy(&m->anonymous_proc_lits_map); + map_destroy(&m->equal_procs); + map_destroy(&m->hasher_procs); + map_destroy(&m->map_get_procs); + map_destroy(&m->map_set_procs); array_free(&m->single_threaded_procedure_queue); @@ -751,6 +756,19 @@ gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) { array_add(&procedures_to_generate, p); } } + for (cgProcedure *p : procedures_to_generate) { + cg_add_procedure_to_queue(p); + } + + if (!m->do_threading) { + for (isize i = 0; i < m->single_threaded_procedure_queue.count; i++) { + cgProcedure *p = m->single_threaded_procedure_queue[i]; + cg_procedure_generate(p); + } + } + + thread_pool_wait(); + { cgProcedure *p = cg_startup_runtime_proc; cg_procedure_begin(p); @@ -765,18 +783,6 @@ gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) { cg_procedure_end(p); } - for (cgProcedure *p : procedures_to_generate) { - cg_add_procedure_to_queue(p); - } - - if (!m->do_threading) { - for (isize i = 0; i < m->single_threaded_procedure_queue.count; i++) { - cgProcedure *p = m->single_threaded_procedure_queue[i]; - cg_procedure_generate(p); - } - } - - thread_pool_wait(); TB_DebugFormat debug_format = TB_DEBUGFMT_NONE; diff --git a/src/tilde.hpp b/src/tilde.hpp index 6ff5602b5..a70d03a6c 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -6,6 +6,7 @@ #endif #include "tilde/tb.h" +#include "tilde/tb_arena.h" #define TB_TYPE_F16 TB_DataType{ { TB_INT, 0, 16 } } #define TB_TYPE_I128 TB_DataType{ { TB_INT, 0, 128 } } @@ -230,6 +231,12 @@ struct cgModule { BlockingMutex anonymous_proc_lits_mutex; PtrMap anonymous_proc_lits_map; + RecursiveMutex generated_procs_mutex; + PtrMap equal_procs; + PtrMap hasher_procs; + PtrMap map_get_procs; + PtrMap map_set_procs; + // NOTE(bill): no need to protect this with a mutex PtrMap file_id_map; // Key: AstFile.id (i32 cast to uintptr) @@ -319,6 +326,7 @@ gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr); gb_internal void cg_build_return_stmt(cgProcedure *p, Slice const &return_results); gb_internal void cg_build_return_stmt_internal(cgProcedure *p, Slice const &results); +gb_internal void cg_build_return_stmt_internal_single(cgProcedure *p, cgValue result); gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node); gb_internal cgValue cg_find_value_from_entity(cgModule *m, Entity *e); @@ -341,6 +349,10 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t); gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, cgValue x); gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right); gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgValue rhs, Type *type); +gb_internal cgValue cg_emit_unary_arith(cgProcedure *p, TokenKind op, cgValue x, Type *type); + +gb_internal cgProcedure *cg_equal_proc_for_type(cgModule *m, Type *type); + gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice const &args); gb_internal cgValue cg_emit_runtime_call(cgProcedure *p, char const *name, Slice const &args); diff --git a/src/tilde/tb.h b/src/tilde/tb.h index a68f06554..b20b98b35 100644 --- a/src/tilde/tb.h +++ b/src/tilde/tb.h @@ -15,20 +15,21 @@ #define TB_VERSION_MINOR 2 #define TB_VERSION_PATCH 0 -#ifdef __cplusplus -#define TB_EXTERN extern "C" -#else -#define TB_EXTERN -#endif - -#ifdef TB_DLL -# ifdef TB_IMPORT_DLL -# define TB_API TB_EXTERN __declspec(dllimport) +#ifndef TB_API +# ifdef __cplusplus +# define TB_EXTERN extern "C" # else -# define TB_API TB_EXTERN __declspec(dllexport) +# define TB_EXTERN +# endif +# ifdef TB_DLL +# ifdef TB_IMPORT_DLL +# define TB_API TB_EXTERN __declspec(dllimport) +# else +# define TB_API TB_EXTERN __declspec(dllexport) +# endif +# else +# define TB_API TB_EXTERN # endif -#else -# define TB_API TB_EXTERN #endif // These are flags @@ -171,7 +172,6 @@ typedef enum TB_FloatFormat { typedef union TB_DataType { struct { uint8_t type; - // 2^N where N is the width value. // Only integers and floats can be wide. uint8_t width; // for integers it's the bitwidth @@ -406,8 +406,6 @@ typedef struct TB_Symbol { typedef int TB_Reg; -#define TB_NULL_REG NULL - typedef struct TB_Node TB_Node; struct TB_Node { TB_NodeType type; @@ -586,29 +584,13 @@ typedef struct { typedef void (*TB_PrintCallback)(void* user_data, const char* fmt, ...); -//////////////////////////////// -// Arena -//////////////////////////////// -// the goal is to move more things to transparent arenas, for now it's just function -// IR which is a big one if you're interested in freeing them in whatever organization -// you please. - -// allocations can make no guarentees about being sequential -// tho it would be greatly appreciated at least to some degree. +// defined in common/arena.h typedef struct TB_Arena TB_Arena; -struct TB_Arena { - // alignment never goes past max_align_t - void* (*alloc)(TB_Arena* arena, size_t size, size_t align); - // clearing but we're not done with it yet, cheap - void (*clear)(TB_Arena* arena); - - // frees everything within the arena, potentially expensive - void (*free)(TB_Arena* arena); -}; - -// allocates in 16MiB chunks and does linear allocation in 'em -TB_API TB_Arena* tb_default_arena(void); +// 0 for default +TB_API void tb_arena_create(TB_Arena* restrict arena, size_t chunk_size); +TB_API void tb_arena_destroy(TB_Arena* restrict arena); +TB_API bool tb_arena_is_empty(TB_Arena* arena); //////////////////////////////// // Module management @@ -651,8 +633,7 @@ struct TB_Assembly { // this is where the machine code and other relevant pieces go. typedef struct TB_FunctionOutput TB_FunctionOutput; -// returns NULL if it fails -TB_API TB_FunctionOutput* tb_module_compile_function(TB_Module* m, TB_Function* f, TB_ISelMode isel_mode, bool emit_asm); +TB_API void tb_output_print_asm(TB_FunctionOutput* out, FILE* fp); TB_API uint8_t* tb_output_get_code(TB_FunctionOutput* out, size_t* out_length); @@ -865,6 +846,9 @@ TB_API TB_DebugType* tb_debug_create_func(TB_Module* m, TB_CallingConv cc, size_ TB_API TB_DebugType* tb_debug_field_type(TB_DebugType* type); +TB_API size_t tb_debug_func_return_count(TB_DebugType* type); +TB_API size_t tb_debug_func_param_count(TB_DebugType* type); + // you'll need to fill these if you make a function TB_API TB_DebugType** tb_debug_func_params(TB_DebugType* type); TB_API TB_DebugType** tb_debug_func_returns(TB_DebugType* type); @@ -895,9 +879,6 @@ TB_API void tb_default_print_callback(void* user_data, const char* fmt, ...); TB_API void tb_inst_set_location(TB_Function* f, TB_FileID file, int line); -// this only allows for power of two vector types -TB_API TB_DataType tb_vector_type(TB_DataTypeEnum type, int width); - // if section is NULL, default to .text TB_API TB_Function* tb_function_create(TB_Module* m, ptrdiff_t len, const char* name, TB_Linkage linkage, TB_ComdatType comdat); @@ -1073,25 +1054,40 @@ TB_API void tb_inst_branch(TB_Function* f, TB_DataType dt, TB_Node* key, TB_Node TB_API void tb_inst_ret(TB_Function* f, size_t count, TB_Node** values); //////////////////////////////// -// Optimizer +// Passes //////////////////////////////// // Function analysis, optimizations, and codegen are all part of this -typedef struct TB_FuncOpt TB_FuncOpt; +typedef struct TB_Passes TB_Passes; -// the arena is used to allocate the nodes -TB_API TB_FuncOpt* tb_funcopt_enter(TB_Function* f, TB_Arena* arena); -TB_API void tb_funcopt_exit(TB_FuncOpt* opt); +// the arena is used to allocate the nodes while passes are being done. +TB_API TB_Passes* tb_pass_enter(TB_Function* f, TB_Arena* arena); +TB_API void tb_pass_exit(TB_Passes* opt); -TB_API bool tb_funcopt_peephole(TB_FuncOpt* opt); -TB_API bool tb_funcopt_mem2reg(TB_FuncOpt* opt); -TB_API bool tb_funcopt_loop(TB_FuncOpt* opt); +// transformation passes: +// peephole: runs most simple reductions on the code, +// should be run after any bigger passes (it's incremental +// so it's not that bad) +// +// mem2reg: lowers TB_LOCALs into SSA values, this makes more +// data flow analysis possible on the code and allows to codegen +// to place variables into registers. +// +// loop: NOT READY +// +TB_API bool tb_pass_peephole(TB_Passes* opt); +TB_API bool tb_pass_mem2reg(TB_Passes* opt); +TB_API bool tb_pass_loop(TB_Passes* opt); -// isn't an optimization, just does the name flat form of IR printing -TB_API bool tb_funcopt_print(TB_FuncOpt* opt); +// analysis +// print: prints IR in a flattened text form. +TB_API bool tb_pass_print(TB_Passes* opt); -TB_API void tb_funcopt_kill(TB_FuncOpt* opt, TB_Node* n); -TB_API bool tb_funcopt_mark(TB_FuncOpt* opt, TB_Node* n); -TB_API void tb_funcopt_mark_users(TB_FuncOpt* opt, TB_Node* n); +// codegen +TB_API TB_FunctionOutput* tb_pass_codegen(TB_Passes* opt, bool emit_asm); + +TB_API void tb_pass_kill_node(TB_Passes* opt, TB_Node* n); +TB_API bool tb_pass_mark(TB_Passes* opt, TB_Node* n); +TB_API void tb_pass_mark_users(TB_Passes* opt, TB_Node* n); //////////////////////////////// // IR access @@ -1099,8 +1095,6 @@ TB_API void tb_funcopt_mark_users(TB_FuncOpt* opt, TB_Node* n); TB_API const char* tb_node_get_name(TB_Node* n); TB_API TB_Node* tb_get_parent_region(TB_Node* n); -TB_API bool tb_has_effects(TB_Node* n); - TB_API bool tb_node_is_constant_non_zero(TB_Node* n); TB_API bool tb_node_is_constant_zero(TB_Node* n); diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index 43e477536..b0886ebfb 100644 Binary files a/src/tilde/tb.lib and b/src/tilde/tb.lib differ diff --git a/src/tilde/tb_arena.h b/src/tilde/tb_arena.h new file mode 100644 index 000000000..d50e777da --- /dev/null +++ b/src/tilde/tb_arena.h @@ -0,0 +1,76 @@ +#pragma once +#include +#include + +#ifndef TB_API +# ifdef __cplusplus +# define TB_EXTERN extern "C" +# else +# define TB_EXTERN +# endif +# ifdef TB_DLL +# ifdef TB_IMPORT_DLL +# define TB_API TB_EXTERN __declspec(dllimport) +# else +# define TB_API TB_EXTERN __declspec(dllexport) +# endif +# else +# define TB_API TB_EXTERN +# endif +#endif + +enum { + TB_ARENA_SMALL_CHUNK_SIZE = 4 * 1024, + TB_ARENA_MEDIUM_CHUNK_SIZE = 512 * 1024, + TB_ARENA_LARGE_CHUNK_SIZE = 2 * 1024 * 1024, + + TB_ARENA_ALIGNMENT = 16, +}; + +typedef struct TB_ArenaChunk TB_ArenaChunk; +struct TB_ArenaChunk { + TB_ArenaChunk* next; + size_t pad; + char data[]; +}; + +typedef struct TB_Arena { + size_t chunk_size; + TB_ArenaChunk* base; + TB_ArenaChunk* top; + + // top of the allocation space + char* watermark; + char* high_point; // &top->data[chunk_size] +} TB_Arena; + +typedef struct TB_ArenaSavepoint { + TB_ArenaChunk* top; + char* watermark; +} TB_ArenaSavepoint; + +#define TB_ARENA_FOR(it, arena) for (TB_ArenaChunk* it = (arena)->base; it != NULL; it = it->next) + +#define TB_ARENA_ALLOC(arena, T) tb_arena_alloc(arena, sizeof(T)) +#define TB_ARENA_ARR_ALLOC(arena, count, T) tb_arena_alloc(arena, (count) * sizeof(T)) + +TB_API void tb_arena_create(TB_Arena* restrict arena, size_t chunk_size); +TB_API void tb_arena_destroy(TB_Arena* restrict arena); + +TB_API void* tb_arena_unaligned_alloc(TB_Arena* restrict arena, size_t size); +TB_API void* tb_arena_alloc(TB_Arena* restrict arena, size_t size); + +// asserts if ptr+size != watermark +TB_API void tb_arena_pop(TB_Arena* restrict arena, void* ptr, size_t size); + +// in case you wanna mix unaligned and aligned arenas +TB_API void tb_arena_realign(TB_Arena* restrict arena); + +TB_API bool tb_arena_is_empty(TB_Arena* arena); + +// savepoints +TB_API TB_ArenaSavepoint tb_arena_save(TB_Arena* arena); +TB_API void tb_arena_restore(TB_Arena* arena, TB_ArenaSavepoint sp); + +// resets to only having one chunk +TB_API void tb_arena_clear(TB_Arena* arena); diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 1966dcd8e..fdd26e3db 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -304,6 +304,42 @@ gb_internal cgValue cg_emit_byte_swap(cgProcedure *p, cgValue value, Type *end_t return cg_emit_transmute(p, value, end_type); } +gb_internal cgValue cg_emit_comp_records(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right, Type *type) { + GB_ASSERT((is_type_struct(type) || is_type_union(type)) && is_type_comparable(type)); + cgValue left_ptr = cg_address_from_load_or_generate_local(p, left); + cgValue right_ptr = cg_address_from_load_or_generate_local(p, right); + cgValue res = {}; + if (type_size_of(type) == 0) { + switch (op_kind) { + case Token_CmpEq: + return cg_const_bool(p, t_bool, true); + case Token_NotEq: + return cg_const_bool(p, t_bool, false); + } + GB_PANIC("invalid operator"); + } + TEMPORARY_ALLOCATOR_GUARD(); + if (is_type_simple_compare(type)) { + // TODO(bill): Test to see if this is actually faster!!!! + auto args = slice_make(temporary_allocator(), 3); + args[0] = cg_emit_conv(p, left_ptr, t_rawptr); + args[1] = cg_emit_conv(p, right_ptr, t_rawptr); + args[2] = cg_const_int(p, t_int, type_size_of(type)); + res = cg_emit_runtime_call(p, "memory_equal", args); + } else { + cgProcedure *equal_proc = cg_equal_proc_for_type(p->module, type); + cgValue value = cg_value(tb_inst_get_symbol_address(p->func, equal_proc->symbol), equal_proc->type); + auto args = slice_make(temporary_allocator(), 2); + args[0] = cg_emit_conv(p, left_ptr, t_rawptr); + args[1] = cg_emit_conv(p, right_ptr, t_rawptr); + res = cg_emit_call(p, value, args); + } + if (op_kind == Token_NotEq) { + res = cg_emit_unary_arith(p, Token_Not, res, res.type); + } + return res; +} + gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right) { GB_ASSERT(gb_is_between(op_kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1)); @@ -440,13 +476,11 @@ gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left } if ((is_type_struct(a) || is_type_union(a)) && is_type_comparable(a)) { - GB_PANIC("TODO(bill): cg_compare_records"); - // return cg_compare_records(p, op_kind, left, right, a); + return cg_emit_comp_records(p, op_kind, left, right, a); } if ((is_type_struct(b) || is_type_union(b)) && is_type_comparable(b)) { - GB_PANIC("TODO(bill): cg_compare_records"); - // return cg_compare_records(p, op_kind, left, right, b); + return cg_emit_comp_records(p, op_kind, left, right, b); } if (is_type_string(a)) { diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 8cfc564a7..26c70b508 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -368,22 +368,17 @@ gb_internal void cg_procedure_begin(cgProcedure *p) { gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) { cgProcedure *p = cast(cgProcedure *)data; - bool emit_asm = false; - - if (false && - string_starts_with(p->name, str_lit("bug@main"))) { - TB_Arena *arena = cg_arena(); - TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena); - defer (tb_funcopt_exit(opt)); - - tb_funcopt_peephole(opt); - tb_funcopt_mem2reg(opt); - tb_funcopt_peephole(opt); - - emit_asm = true; + TB_Passes *opt = tb_pass_enter(p->func, cg_arena()); + defer (tb_pass_exit(opt)); + + // optimization passes + if (false) { + tb_pass_peephole(opt); + tb_pass_mem2reg(opt); + tb_pass_peephole(opt); } - + bool emit_asm = false; if ( // string_starts_with(p->name, str_lit("runtime@_windows_default_alloc_or_resize")) || false @@ -391,12 +386,27 @@ gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) { emit_asm = true; } - TB_FunctionOutput *output = tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST, emit_asm); + // emit ir + if ( + // string_starts_with(p->name, str_lit("bug@main")) || + // p->name == str_lit("runtime@_windows_default_alloc_or_resize") || + false + ) { // IR Printing + TB_Arena *arena = cg_arena(); + TB_Passes *passes = tb_pass_enter(p->func, arena); + defer (tb_pass_exit(passes)); + + tb_pass_print(passes); + fprintf(stdout, "\n"); + } + if (false) { // GraphViz printing + tb_function_print(p->func, tb_default_print_callback, stdout); + } + + // compile + TB_FunctionOutput *output = tb_pass_codegen(opt, emit_asm); if (emit_asm) { - TB_Assembly *assembly = tb_output_get_asm(output); - for (TB_Assembly *node = assembly; node != nullptr; node = node->next) { - fprintf(stdout, "%.*s", cast(int)node->length, node->data); - } + tb_output_print_asm(output, stdout); fprintf(stdout, "\n"); } @@ -427,27 +437,9 @@ gb_internal void cg_procedure_generate(cgProcedure *p) { return; } - cg_procedure_begin(p); cg_build_stmt(p, p->body); cg_procedure_end(p); - - - if ( - // string_starts_with(p->name, str_lit("runtime@_windows_default_alloc")) || - // p->name == str_lit("runtime@_windows_default_alloc_or_resize") || - false - ) { // IR Printing - TB_Arena *arena = tb_default_arena(); - defer (arena->free(arena)); - TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena); - defer (tb_funcopt_exit(opt)); - tb_funcopt_print(opt); - fprintf(stdout, "\n"); - } - if (false) { // GraphViz printing - tb_function_print(p->func, tb_default_print_callback, stdout); - } } gb_internal void cg_build_nested_proc(cgProcedure *p, AstProcLit *pd, Entity *e) { @@ -989,3 +981,95 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) { return cg_emit_call(p, value, call_args); } + + + + +gb_internal cgProcedure *cg_equal_proc_for_type(cgModule *m, Type *type) { + type = base_type(type); + GB_ASSERT(is_type_comparable(type)); + + mutex_lock(&m->generated_procs_mutex); + defer (mutex_unlock(&m->generated_procs_mutex)); + + cgProcedure **found = map_get(&m->equal_procs, type); + if (found) { + return *found; + } + + static std::atomic proc_index; + + char buf[32] = {}; + isize n = gb_snprintf(buf, 32, "__$equal%u", 1+proc_index.fetch_add(1)); + char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); + String proc_name = make_string_c(str); + + + cgProcedure *p = cg_procedure_create_dummy(m, proc_name, t_equal_proc); + map_set(&m->equal_procs, type, p); + + cg_procedure_begin(p); + + TB_Node *x = tb_inst_param(p->func, 0); + TB_Node *y = tb_inst_param(p->func, 1); + GB_ASSERT(x->dt.type == TB_PTR); + GB_ASSERT(y->dt.type == TB_PTR); + + TB_DataType ret_dt = TB_PROTOTYPE_RETURNS(p->proto)->dt; + + TB_Node *node_true = tb_inst_uint(p->func, ret_dt, true); + TB_Node *node_false = tb_inst_uint(p->func, ret_dt, false); + + TB_Node *same_ptr_region = cg_control_region(p, "same_ptr"); + TB_Node *diff_ptr_region = cg_control_region(p, "diff_ptr"); + + TB_Node *is_same_ptr = tb_inst_cmp_eq(p->func, x, y); + tb_inst_if(p->func, is_same_ptr, same_ptr_region, diff_ptr_region); + + tb_inst_set_control(p->func, same_ptr_region); + tb_inst_ret(p->func, 1, &node_true); + + tb_inst_set_control(p->func, diff_ptr_region); + + Type *pt = alloc_type_pointer(type); + cgValue lhs = cg_value(x, pt); + cgValue rhs = cg_value(y, pt); + + if (type->kind == Type_Struct) { + type_set_offsets(type); + + TB_Node *false_region = cg_control_region(p, "bfalse"); + cgValue res = cg_const_bool(p, t_bool, true); + + for_array(i, type->Struct.fields) { + TB_Node *next_region = cg_control_region(p, "btrue"); + + cgValue plhs = cg_emit_struct_ep(p, lhs, i); + cgValue prhs = cg_emit_struct_ep(p, rhs, i); + cgValue left = cg_emit_load(p, plhs); + cgValue right = cg_emit_load(p, prhs); + cgValue ok = cg_emit_comp(p, Token_CmpEq, left, right); + + cg_emit_if(p, ok, next_region, false_region); + + cg_emit_goto(p, next_region); + tb_inst_set_control(p->func, next_region); + } + + tb_inst_ret(p->func, 1, &node_true); + tb_inst_set_control(p->func, false_region); + tb_inst_ret(p->func, 1, &node_false); + + } else if (type->kind == Type_Union) { + GB_PANIC("TODO(bill): union comparison"); + } else { + cgValue left = cg_lvalue_addr(x, type); + cgValue right = cg_lvalue_addr(y, type); + cgValue ok = cg_emit_comp(p, Token_CmpEq, left, right); + cg_build_return_stmt_internal_single(p, ok); + } + + cg_procedure_end(p); + + return p; +} \ No newline at end of file diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 0b5f122d4..382b4c02d 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -1047,6 +1047,14 @@ gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) { } } +gb_internal void cg_build_return_stmt_internal_single(cgProcedure *p, cgValue result) { + Slice results = {}; + results.data = &result; + results.count = 1; + cg_build_return_stmt_internal(p, results); +} + + gb_internal void cg_build_return_stmt_internal(cgProcedure *p, Slice const &results) { TypeTuple *tuple = &p->type->Proc.results->Tuple; isize return_count = p->type->Proc.result_count; -- cgit v1.2.3 From c91898a8889604617140ad15c70f4d68494fa0a1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Aug 2023 16:05:39 +0100 Subject: Remove #relative slices; Replace with #relative multi-pointers --- core/encoding/json/marshal.odin | 2 +- core/fmt/fmt.odin | 27 +---- core/odin/doc-format/doc_format.odin | 50 ++++----- core/reflect/reflect.odin | 119 ++++++++++---------- core/reflect/types.odin | 15 ++- core/runtime/core.odin | 10 +- core/runtime/print.odin | 4 +- src/check_builtin.cpp | 2 +- src/check_expr.cpp | 43 ++++---- src/check_type.cpp | 8 +- src/checker.cpp | 16 +-- src/docs_format.cpp | 50 ++++----- src/docs_writer.cpp | 8 +- src/error.cpp | 4 +- src/llvm_backend.hpp | 1 - src/llvm_backend_debug.cpp | 17 +-- src/llvm_backend_expr.cpp | 39 ++++--- src/llvm_backend_general.cpp | 203 +++++++++++++++-------------------- src/llvm_backend_proc.cpp | 4 +- src/llvm_backend_type.cpp | 12 ++- src/llvm_backend_utility.cpp | 7 +- src/parser.cpp | 6 +- src/tilde_builtin.cpp | 4 - src/tilde_const.cpp | 6 +- src/tilde_debug.cpp | 16 +-- src/tilde_expr.cpp | 32 +++--- src/tilde_stmt.cpp | 15 --- src/tilde_type_info.cpp | 46 ++++---- src/types.cpp | 55 +++++----- 29 files changed, 368 insertions(+), 453 deletions(-) (limited to 'src/tilde_stmt.cpp') diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index d25015ac7..77a5bf8df 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -207,7 +207,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: case runtime.Type_Info_Relative_Pointer: return .Unsupported_Type - case runtime.Type_Info_Relative_Slice: + case runtime.Type_Info_Relative_Multi_Pointer: return .Unsupported_Type case runtime.Type_Info_Matrix: diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index e64b621bf..b380cac18 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -2535,32 +2535,11 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { fmt_value(fi, absolute_ptr, verb) - case runtime.Type_Info_Relative_Slice: + case runtime.Type_Info_Relative_Multi_Pointer: ptr := reflect.relative_pointer_to_absolute_raw(v.data, info.base_integer.id) + absolute_ptr := any{ptr, info.pointer.id} - if verb == 'p' { - fmt_pointer(fi, ptr, 'p') - } else if ptr == nil { - io.write_string(fi.writer, "[]", &fi.n) - } else { - len_ptr := uintptr(v.data) + uintptr(info.base_integer.size) - len_any := any{rawptr(len_ptr), info.base_integer.id} - len, _ := reflect.as_int(len_any) - slice_type := reflect.type_info_base(info.slice).variant.(runtime.Type_Info_Slice) - - fi.record_level += 1 - defer fi.record_level -= 1 - - io.write_byte(fi.writer, '[', &fi.n) - defer io.write_byte(fi.writer, ']', &fi.n) - - for i in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - - data := uintptr(ptr) + uintptr(i*slice_type.elem_size) - fmt_arg(fi, any{rawptr(data), slice_type.elem.id}, verb) - } - } + fmt_value(fi, absolute_ptr, verb) case runtime.Type_Info_Matrix: fmt_matrix(fi, v, verb, info) diff --git a/core/odin/doc-format/doc_format.odin b/core/odin/doc-format/doc_format.odin index 895fcf70d..d22dafd27 100644 --- a/core/odin/doc-format/doc_format.odin +++ b/core/odin/doc-format/doc_format.odin @@ -162,31 +162,31 @@ Attribute :: struct { } Type_Kind :: enum u32le { - Invalid = 0, - Basic = 1, - Named = 2, - Generic = 3, - Pointer = 4, - Array = 5, - Enumerated_Array = 6, - Slice = 7, - Dynamic_Array = 8, - Map = 9, - Struct = 10, - Union = 11, - Enum = 12, - Tuple = 13, - Proc = 14, - Bit_Set = 15, - Simd_Vector = 16, - SOA_Struct_Fixed = 17, - SOA_Struct_Slice = 18, - SOA_Struct_Dynamic = 19, - Relative_Pointer = 20, - Relative_Slice = 21, - Multi_Pointer = 22, - Matrix = 23, - Soa_Pointer = 24, + Invalid = 0, + Basic = 1, + Named = 2, + Generic = 3, + Pointer = 4, + Array = 5, + Enumerated_Array = 6, + Slice = 7, + Dynamic_Array = 8, + Map = 9, + Struct = 10, + Union = 11, + Enum = 12, + Tuple = 13, + Proc = 14, + Bit_Set = 15, + Simd_Vector = 16, + SOA_Struct_Fixed = 17, + SOA_Struct_Slice = 18, + SOA_Struct_Dynamic = 19, + Relative_Pointer = 20, + Relative_Multi_Pointer = 21, + Multi_Pointer = 22, + Matrix = 23, + Soa_Pointer = 24, } Type_Elems_Cap :: 4 diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index a88557e0e..24a826f04 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -8,35 +8,35 @@ _ :: intrinsics Type_Info :: runtime.Type_Info -Type_Info_Named :: runtime.Type_Info_Named -Type_Info_Integer :: runtime.Type_Info_Integer -Type_Info_Rune :: runtime.Type_Info_Rune -Type_Info_Float :: runtime.Type_Info_Float -Type_Info_Complex :: runtime.Type_Info_Complex -Type_Info_Quaternion :: runtime.Type_Info_Quaternion -Type_Info_String :: runtime.Type_Info_String -Type_Info_Boolean :: runtime.Type_Info_Boolean -Type_Info_Any :: runtime.Type_Info_Any -Type_Info_Type_Id :: runtime.Type_Info_Type_Id -Type_Info_Pointer :: runtime.Type_Info_Pointer -Type_Info_Multi_Pointer :: runtime.Type_Info_Multi_Pointer -Type_Info_Procedure :: runtime.Type_Info_Procedure -Type_Info_Array :: runtime.Type_Info_Array -Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array -Type_Info_Dynamic_Array :: runtime.Type_Info_Dynamic_Array -Type_Info_Slice :: runtime.Type_Info_Slice -Type_Info_Parameters :: runtime.Type_Info_Parameters -Type_Info_Tuple :: runtime.Type_Info_Parameters -Type_Info_Struct :: runtime.Type_Info_Struct -Type_Info_Union :: runtime.Type_Info_Union -Type_Info_Enum :: runtime.Type_Info_Enum -Type_Info_Map :: runtime.Type_Info_Map -Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set -Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector -Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer -Type_Info_Relative_Slice :: runtime.Type_Info_Relative_Slice -Type_Info_Matrix :: runtime.Type_Info_Matrix -Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer +Type_Info_Named :: runtime.Type_Info_Named +Type_Info_Integer :: runtime.Type_Info_Integer +Type_Info_Rune :: runtime.Type_Info_Rune +Type_Info_Float :: runtime.Type_Info_Float +Type_Info_Complex :: runtime.Type_Info_Complex +Type_Info_Quaternion :: runtime.Type_Info_Quaternion +Type_Info_String :: runtime.Type_Info_String +Type_Info_Boolean :: runtime.Type_Info_Boolean +Type_Info_Any :: runtime.Type_Info_Any +Type_Info_Type_Id :: runtime.Type_Info_Type_Id +Type_Info_Pointer :: runtime.Type_Info_Pointer +Type_Info_Multi_Pointer :: runtime.Type_Info_Multi_Pointer +Type_Info_Procedure :: runtime.Type_Info_Procedure +Type_Info_Array :: runtime.Type_Info_Array +Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array +Type_Info_Dynamic_Array :: runtime.Type_Info_Dynamic_Array +Type_Info_Slice :: runtime.Type_Info_Slice +Type_Info_Parameters :: runtime.Type_Info_Parameters +Type_Info_Tuple :: runtime.Type_Info_Parameters +Type_Info_Struct :: runtime.Type_Info_Struct +Type_Info_Union :: runtime.Type_Info_Union +Type_Info_Enum :: runtime.Type_Info_Enum +Type_Info_Map :: runtime.Type_Info_Map +Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set +Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector +Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer +Type_Info_Relative_Multi_Pointer :: runtime.Type_Info_Relative_Multi_Pointer +Type_Info_Matrix :: runtime.Type_Info_Matrix +Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value @@ -69,7 +69,7 @@ Type_Kind :: enum { Bit_Set, Simd_Vector, Relative_Pointer, - Relative_Slice, + Relative_Multi_Pointer, Matrix, Soa_Pointer, } @@ -80,34 +80,34 @@ type_kind :: proc(T: typeid) -> Type_Kind { ti := type_info_of(T) if ti != nil { switch _ in ti.variant { - case Type_Info_Named: return .Named - case Type_Info_Integer: return .Integer - case Type_Info_Rune: return .Rune - case Type_Info_Float: return .Float - case Type_Info_Complex: return .Complex - case Type_Info_Quaternion: return .Quaternion - case Type_Info_String: return .String - case Type_Info_Boolean: return .Boolean - case Type_Info_Any: return .Any - case Type_Info_Type_Id: return .Type_Id - case Type_Info_Pointer: return .Pointer - case Type_Info_Multi_Pointer: return .Multi_Pointer - case Type_Info_Procedure: return .Procedure - case Type_Info_Array: return .Array - case Type_Info_Enumerated_Array: return .Enumerated_Array - case Type_Info_Dynamic_Array: return .Dynamic_Array - case Type_Info_Slice: return .Slice - case Type_Info_Parameters: return .Tuple - case Type_Info_Struct: return .Struct - case Type_Info_Union: return .Union - case Type_Info_Enum: return .Enum - case Type_Info_Map: return .Map - case Type_Info_Bit_Set: return .Bit_Set - case Type_Info_Simd_Vector: return .Simd_Vector - case Type_Info_Relative_Pointer: return .Relative_Pointer - case Type_Info_Relative_Slice: return .Relative_Slice - case Type_Info_Matrix: return .Matrix - case Type_Info_Soa_Pointer: return .Soa_Pointer + case Type_Info_Named: return .Named + case Type_Info_Integer: return .Integer + case Type_Info_Rune: return .Rune + case Type_Info_Float: return .Float + case Type_Info_Complex: return .Complex + case Type_Info_Quaternion: return .Quaternion + case Type_Info_String: return .String + case Type_Info_Boolean: return .Boolean + case Type_Info_Any: return .Any + case Type_Info_Type_Id: return .Type_Id + case Type_Info_Pointer: return .Pointer + case Type_Info_Multi_Pointer: return .Multi_Pointer + case Type_Info_Procedure: return .Procedure + case Type_Info_Array: return .Array + case Type_Info_Enumerated_Array: return .Enumerated_Array + case Type_Info_Dynamic_Array: return .Dynamic_Array + case Type_Info_Slice: return .Slice + case Type_Info_Parameters: return .Tuple + case Type_Info_Struct: return .Struct + case Type_Info_Union: return .Union + case Type_Info_Enum: return .Enum + case Type_Info_Map: return .Map + case Type_Info_Bit_Set: return .Bit_Set + case Type_Info_Simd_Vector: return .Simd_Vector + case Type_Info_Relative_Pointer: return .Relative_Pointer + case Type_Info_Relative_Multi_Pointer: return .Relative_Multi_Pointer + case Type_Info_Matrix: return .Matrix + case Type_Info_Soa_Pointer: return .Soa_Pointer } } @@ -1457,8 +1457,6 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_ return equal(va, vb, including_indirect_array_recursion, recursion_level+1) case Type_Info_Map: return false - case Type_Info_Relative_Slice: - return false case Type_Info_Boolean, Type_Info_Integer, @@ -1474,6 +1472,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_ Type_Info_Enum, Type_Info_Simd_Vector, Type_Info_Relative_Pointer, + Type_Info_Relative_Multi_Pointer, Type_Info_Soa_Pointer, Type_Info_Matrix: return runtime.memory_compare(a.data, b.data, t.size) == 0 diff --git a/core/reflect/types.odin b/core/reflect/types.odin index cad9b1f66..21f75580c 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -165,9 +165,9 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { y := b.variant.(Type_Info_Relative_Pointer) or_return return x.base_integer == y.base_integer && x.pointer == y.pointer - case Type_Info_Relative_Slice: - y := b.variant.(Type_Info_Relative_Slice) or_return - return x.base_integer == y.base_integer && x.slice == y.slice + case Type_Info_Relative_Multi_Pointer: + y := b.variant.(Type_Info_Relative_Multi_Pointer) or_return + return x.base_integer == y.base_integer && x.pointer == y.pointer case Type_Info_Matrix: y := b.variant.(Type_Info_Matrix) or_return @@ -383,9 +383,9 @@ is_relative_pointer :: proc(info: ^Type_Info) -> bool { return ok } @(require_results) -is_relative_slice :: proc(info: ^Type_Info) -> bool { +is_relative_multi_pointer :: proc(info: ^Type_Info) -> bool { if info == nil { return false } - _, ok := type_info_base(info).variant.(Type_Info_Relative_Slice) + _, ok := type_info_base(info).variant.(Type_Info_Relative_Multi_Pointer) return ok } @@ -395,7 +395,6 @@ is_relative_slice :: proc(info: ^Type_Info) -> bool { - write_typeid_builder :: proc(buf: ^strings.Builder, id: typeid, n_written: ^int = nil) -> (n: int, err: io.Error) { return write_type_writer(strings.to_writer(buf), type_info_of(id)) } @@ -652,11 +651,11 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) - io.write_string(w, ") ", &n) or_return write_type(w, info.pointer, &n) or_return - case Type_Info_Relative_Slice: + case Type_Info_Relative_Multi_Pointer: io.write_string(w, "#relative(", &n) or_return write_type(w, info.base_integer, &n) or_return io.write_string(w, ") ", &n) or_return - write_type(w, info.slice, &n) or_return + write_type(w, info.pointer, &n) or_return case Type_Info_Matrix: io.write_string(w, "matrix[", &n) or_return diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 83504c9ee..f76c77581 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -162,11 +162,11 @@ Type_Info_Simd_Vector :: struct { count: int, } Type_Info_Relative_Pointer :: struct { - pointer: ^Type_Info, + pointer: ^Type_Info, // ^T base_integer: ^Type_Info, } -Type_Info_Relative_Slice :: struct { - slice: ^Type_Info, +Type_Info_Relative_Multi_Pointer :: struct { + pointer: ^Type_Info, // [^]T base_integer: ^Type_Info, } Type_Info_Matrix :: struct { @@ -219,7 +219,7 @@ Type_Info :: struct { Type_Info_Bit_Set, Type_Info_Simd_Vector, Type_Info_Relative_Pointer, - Type_Info_Relative_Slice, + Type_Info_Relative_Multi_Pointer, Type_Info_Matrix, Type_Info_Soa_Pointer, }, @@ -252,7 +252,7 @@ Typeid_Kind :: enum u8 { Bit_Set, Simd_Vector, Relative_Pointer, - Relative_Slice, + Relative_Multi_Pointer, Matrix, } #assert(len(Typeid_Kind) < 32) diff --git a/core/runtime/print.odin b/core/runtime/print.odin index 035d47f15..6b1555f52 100644 --- a/core/runtime/print.odin +++ b/core/runtime/print.odin @@ -471,11 +471,11 @@ print_type :: proc "contextless" (ti: ^Type_Info) { print_string(") ") print_type(info.pointer) - case Type_Info_Relative_Slice: + case Type_Info_Relative_Multi_Pointer: print_string("#relative(") print_type(info.base_integer) print_string(") ") - print_type(info.slice) + print_type(info.pointer) case Type_Info_Matrix: print_string("matrix[") diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 7f9f4ab13..2e65c5750 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1748,7 +1748,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As mode = Addressing_Constant; value = exact_value_i64(at->EnumeratedArray.count); type = t_untyped_integer; - } else if ((is_type_slice(op_type) || is_type_relative_slice(op_type)) && id == BuiltinProc_len) { + } else if (is_type_slice(op_type) && id == BuiltinProc_len) { mode = Addressing_Value; } else if (is_type_dynamic_array(op_type)) { mode = Addressing_Value; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5b6e8be3d..14a4eebc8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -856,8 +856,8 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand } } - if (is_type_relative_slice(dst)) { - i64 score = check_distance_between_types(c, operand, dst->RelativeSlice.slice_type); + if (is_type_relative_multi_pointer(dst)) { + i64 score = check_distance_between_types(c, operand, dst->RelativeMultiPointer.pointer_type); if (score >= 0) { return score+2; } @@ -1005,8 +1005,8 @@ gb_internal AstPackage *get_package_of_type(Type *type) { case Type_RelativePointer: type = type->RelativePointer.pointer_type; continue; - case Type_RelativeSlice: - type = type->RelativeSlice.slice_type; + case Type_RelativeMultiPointer: + type = type->RelativeMultiPointer.pointer_type; continue; } return nullptr; @@ -7366,11 +7366,11 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 } return true; - case Type_RelativeSlice: + case Type_RelativeMultiPointer: { - Type *slice_type = base_type(t->RelativeSlice.slice_type); - GB_ASSERT(slice_type->kind == Type_Slice); - o->type = slice_type->Slice.elem; + Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type); + GB_ASSERT(pointer_type->kind == Type_MultiPointer); + o->type = pointer_type->MultiPointer.elem; if (o->mode != Addressing_Constant) { o->mode = Addressing_Variable; } @@ -9502,14 +9502,14 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, if (is_const) { if (is_type_array(t)) { - // OKay + // Okay } else if (is_type_slice(t)) { // Okay } else if (is_type_enumerated_array(t)) { // Okay } else if (is_type_string(t)) { // Okay - } else if (is_type_relative_slice(t)) { + } else if (is_type_relative_multi_pointer(t)) { // Okay } else if (is_type_matrix(t)) { // Okay @@ -9647,17 +9647,9 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, } break; - case Type_RelativeSlice: + case Type_RelativeMultiPointer: valid = true; - o->type = t->RelativeSlice.slice_type; - if (o->mode != Addressing_Variable) { - gbString str = expr_to_string(node); - error(node, "Cannot relative slice '%s', as value is not addressable", str); - gb_string_free(str); - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } + o->type = type_deref(o->type); break; case Type_EnumeratedArray: @@ -9736,8 +9728,19 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, x[i:n] -> []T */ o->type = alloc_type_slice(t->MultiPointer.elem); + } else if (t->kind == Type_RelativeMultiPointer && se->high != nullptr) { + /* + x[:] -> [^]T + x[i:] -> [^]T + x[:n] -> []T + x[i:n] -> []T + */ + Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type); + GB_ASSERT(pointer_type->kind == Type_MultiPointer); + o->type = alloc_type_slice(pointer_type->MultiPointer.elem); } + o->mode = Addressing_Value; if (is_type_string(t) && max_count >= 0) { diff --git a/src/check_type.cpp b/src/check_type.cpp index 4704f8b9b..cae3ba22e 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2778,16 +2778,16 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T Type *relative_type = nullptr; Type *base_type = check_type(ctx, rt->type); - if (!is_type_pointer(base_type) && !is_type_slice(base_type)) { - error(rt->type, "#relative types can only be a pointer or slice"); + if (!is_type_pointer(base_type) && !is_type_multi_pointer(base_type)) { + error(rt->type, "#relative types can only be a pointer or multi-pointer"); relative_type = base_type; } else if (base_integer == nullptr) { relative_type = base_type; } else { if (is_type_pointer(base_type)) { relative_type = alloc_type_relative_pointer(base_type, base_integer); - } else if (is_type_slice(base_type)) { - relative_type = alloc_type_relative_slice(base_type, base_integer); + } else if (is_type_multi_pointer(base_type)) { + relative_type = alloc_type_relative_multi_pointer(base_type, base_integer); } } GB_ASSERT(relative_type != nullptr); diff --git a/src/checker.cpp b/src/checker.cpp index e1860b1fe..7fa7a9c36 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1969,9 +1969,9 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { add_type_info_type_internal(c, bt->RelativePointer.base_integer); break; - case Type_RelativeSlice: - add_type_info_type_internal(c, bt->RelativeSlice.slice_type); - add_type_info_type_internal(c, bt->RelativeSlice.base_integer); + case Type_RelativeMultiPointer: + add_type_info_type_internal(c, bt->RelativeMultiPointer.pointer_type); + add_type_info_type_internal(c, bt->RelativeMultiPointer.base_integer); break; case Type_Matrix: @@ -2210,9 +2210,9 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { add_min_dep_type_info(c, bt->RelativePointer.base_integer); break; - case Type_RelativeSlice: - add_min_dep_type_info(c, bt->RelativeSlice.slice_type); - add_min_dep_type_info(c, bt->RelativeSlice.base_integer); + case Type_RelativeMultiPointer: + add_min_dep_type_info(c, bt->RelativeMultiPointer.pointer_type); + add_min_dep_type_info(c, bt->RelativeMultiPointer.base_integer); break; case Type_Matrix: @@ -2800,7 +2800,7 @@ gb_internal void init_core_type_info(Checker *c) { t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set")); t_type_info_simd_vector = find_core_type(c, str_lit("Type_Info_Simd_Vector")); t_type_info_relative_pointer = find_core_type(c, str_lit("Type_Info_Relative_Pointer")); - t_type_info_relative_slice = find_core_type(c, str_lit("Type_Info_Relative_Slice")); + t_type_info_relative_multi_pointer = find_core_type(c, str_lit("Type_Info_Relative_Multi_Pointer")); t_type_info_matrix = find_core_type(c, str_lit("Type_Info_Matrix")); t_type_info_soa_pointer = find_core_type(c, str_lit("Type_Info_Soa_Pointer")); @@ -2829,7 +2829,7 @@ gb_internal void init_core_type_info(Checker *c) { t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set); t_type_info_simd_vector_ptr = alloc_type_pointer(t_type_info_simd_vector); t_type_info_relative_pointer_ptr = alloc_type_pointer(t_type_info_relative_pointer); - t_type_info_relative_slice_ptr = alloc_type_pointer(t_type_info_relative_slice); + t_type_info_relative_multi_pointer_ptr = alloc_type_pointer(t_type_info_relative_multi_pointer); t_type_info_matrix_ptr = alloc_type_pointer(t_type_info_matrix); t_type_info_soa_pointer_ptr = alloc_type_pointer(t_type_info_soa_pointer); } diff --git a/src/docs_format.cpp b/src/docs_format.cpp index 34114f08e..d0bca214b 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -59,31 +59,31 @@ struct OdinDocPosition { }; enum OdinDocTypeKind : u32 { - OdinDocType_Invalid = 0, - OdinDocType_Basic = 1, - OdinDocType_Named = 2, - OdinDocType_Generic = 3, - OdinDocType_Pointer = 4, - OdinDocType_Array = 5, - OdinDocType_EnumeratedArray = 6, - OdinDocType_Slice = 7, - OdinDocType_DynamicArray = 8, - OdinDocType_Map = 9, - OdinDocType_Struct = 10, - OdinDocType_Union = 11, - OdinDocType_Enum = 12, - OdinDocType_Tuple = 13, - OdinDocType_Proc = 14, - OdinDocType_BitSet = 15, - OdinDocType_SimdVector = 16, - OdinDocType_SOAStructFixed = 17, - OdinDocType_SOAStructSlice = 18, - OdinDocType_SOAStructDynamic = 19, - OdinDocType_RelativePointer = 20, - OdinDocType_RelativeSlice = 21, - OdinDocType_MultiPointer = 22, - OdinDocType_Matrix = 23, - OdinDocType_SoaPointer = 24, + OdinDocType_Invalid = 0, + OdinDocType_Basic = 1, + OdinDocType_Named = 2, + OdinDocType_Generic = 3, + OdinDocType_Pointer = 4, + OdinDocType_Array = 5, + OdinDocType_EnumeratedArray = 6, + OdinDocType_Slice = 7, + OdinDocType_DynamicArray = 8, + OdinDocType_Map = 9, + OdinDocType_Struct = 10, + OdinDocType_Union = 11, + OdinDocType_Enum = 12, + OdinDocType_Tuple = 13, + OdinDocType_Proc = 14, + OdinDocType_BitSet = 15, + OdinDocType_SimdVector = 16, + OdinDocType_SOAStructFixed = 17, + OdinDocType_SOAStructSlice = 18, + OdinDocType_SOAStructDynamic = 19, + OdinDocType_RelativePointer = 20, + OdinDocType_RelativeMultiPointer = 21, + OdinDocType_MultiPointer = 22, + OdinDocType_Matrix = 23, + OdinDocType_SoaPointer = 24, }; enum OdinDocTypeFlag_Basic : u32 { diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 2dd2f338b..6b42d2e7a 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -771,12 +771,12 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { doc_type.types = odin_write_slice(w, types, gb_count_of(types)); } break; - case Type_RelativeSlice: - doc_type.kind = OdinDocType_RelativeSlice; + case Type_RelativeMultiPointer: + doc_type.kind = OdinDocType_RelativeMultiPointer; { OdinDocTypeIndex types[2] = {}; - types[0] = odin_doc_type(w, type->RelativeSlice.slice_type); - types[1] = odin_doc_type(w, type->RelativeSlice.base_integer); + types[0] = odin_doc_type(w, type->RelativeMultiPointer.pointer_type); + types[1] = odin_doc_type(w, type->RelativeMultiPointer.base_integer); doc_type.types = odin_write_slice(w, types, gb_count_of(types)); } break; diff --git a/src/error.cpp b/src/error.cpp index eb010eb36..6a039006b 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -411,7 +411,7 @@ gb_internal void error_line_va(char const *fmt, va_list va) { gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) { mutex_lock(&global_error_collector.mutex); - global_error_collector.count++; + global_error_collector.count.fetch_add(1); // NOTE(bill): Duplicate error, skip it if (pos.line == 0) { error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red); @@ -425,7 +425,7 @@ gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_li error_out_va(fmt, va); } mutex_unlock(&global_error_collector.mutex); - if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) { + if (global_error_collector.count.load() > MAX_ERROR_COLLECTOR_COUNT()) { gb_exit(1); } } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index e05bf8025..3178ac9db 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -69,7 +69,6 @@ enum lbAddrKind { lbAddr_SoaVariable, lbAddr_RelativePointer, - lbAddr_RelativeSlice, lbAddr_Swizzle, lbAddr_SwizzleLarge, diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index b9c6c606e..e053c5b40 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -442,19 +442,12 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { gbString name = type_to_string(type, temporary_allocator()); return LLVMDIBuilderCreateTypedef(m->debug_builder, base_integer, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type))); } + case Type_RelativeMultiPointer: { + LLVMMetadataRef base_integer = lb_debug_type(m, type->RelativeMultiPointer.base_integer); + gbString name = type_to_string(type, temporary_allocator()); + return LLVMDIBuilderCreateTypedef(m->debug_builder, base_integer, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type))); + } - case Type_RelativeSlice: - { - unsigned element_count = 0; - LLVMMetadataRef elements[2] = {}; - Type *base_integer = type->RelativeSlice.base_integer; - unsigned base_bits = cast(unsigned)(8*type_size_of(base_integer)); - elements[0] = lb_debug_struct_field(m, str_lit("data_offset"), base_integer, 0); - elements[1] = lb_debug_struct_field(m, str_lit("len"), base_integer, base_bits); - gbString name = type_to_string(type, temporary_allocator()); - return LLVMDIBuilderCreateStructType(m->debug_builder, nullptr, name, gb_string_length(name), nullptr, 0, 2*base_bits, base_bits, LLVMDIFlagZero, nullptr, elements, element_count, 0, nullptr, "", 0); - } - case Type_Matrix: { LLVMMetadataRef subscripts[1] = {}; subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder, diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 5e6831fc2..33768cc12 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2863,7 +2863,6 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { ast_node(ue, UnaryExpr, expr); auto tv = type_and_value_of_expr(expr); - Ast *ue_expr = unparen_expr(ue->expr); if (ue_expr->kind == Ast_IndexExpr && tv.mode == Addressing_OptionalOkPtr && is_type_tuple(tv.type)) { Type *tuple = tv.type; @@ -3803,25 +3802,32 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { lbValue v = {}; LLVMValueRef indices[1] = {index.value}; - v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, t->MultiPointer.elem), multi_ptr.value, indices, 1, "foo"); + v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, t->MultiPointer.elem), multi_ptr.value, indices, 1, ""); v.type = alloc_type_pointer(t->MultiPointer.elem); return lb_addr(v); } - case Type_RelativeSlice: { - lbAddr slice_addr = {}; + case Type_RelativeMultiPointer: { + lbAddr rel_ptr_addr = {}; if (deref) { - slice_addr = lb_addr(lb_build_expr(p, ie->expr)); + lbValue rel_ptr_ptr = lb_build_expr(p, ie->expr); + rel_ptr_addr = lb_addr(rel_ptr_ptr); } else { - slice_addr = lb_build_addr(p, ie->expr); + rel_ptr_addr = lb_build_addr(p, ie->expr); } - lbValue slice = lb_addr_load(p, slice_addr); + lbValue rel_ptr = lb_relative_pointer_to_pointer(p, rel_ptr_addr); - lbValue elem = lb_slice_elem(p, slice); - lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lbValue len = lb_slice_len(p, slice); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - lbValue v = lb_emit_ptr_offset(p, elem, index); + lbValue index = lb_build_expr(p, ie->index); + index = lb_emit_conv(p, index, t_int); + lbValue v = {}; + + Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type); + GB_ASSERT(pointer_type->kind == Type_MultiPointer); + Type *elem = pointer_type->MultiPointer.elem; + + LLVMValueRef indices[1] = {index.value}; + v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, elem), rel_ptr.value, indices, 1, ""); + v.type = alloc_type_pointer(elem); return lb_addr(v); } @@ -3925,8 +3931,11 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { return slice; } - case Type_RelativeSlice: - GB_PANIC("TODO(bill): Type_RelativeSlice should be handled above already on the lb_addr_load"); + case Type_RelativePointer: + GB_PANIC("TODO(bill): Type_RelativePointer should be handled above already on the lb_addr_load"); + break; + case Type_RelativeMultiPointer: + GB_PANIC("TODO(bill): Type_RelativeMultiPointer should be handled above already on the lb_addr_load"); break; case Type_DynamicArray: { @@ -3996,7 +4005,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { } case Type_Basic: { - GB_ASSERT(type == t_string); + GB_ASSERT_MSG(type == t_string, "got %s", type_to_string(type)); lbValue len = lb_string_len(p, base); if (high.value == nullptr) high = len; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index cd8041661..5dfc7aff9 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -349,9 +349,10 @@ gb_internal lbAddr lb_addr(lbValue addr) { if (addr.type != nullptr && is_type_relative_pointer(type_deref(addr.type))) { GB_ASSERT(is_type_pointer(addr.type)); v.kind = lbAddr_RelativePointer; - } else if (addr.type != nullptr && is_type_relative_slice(type_deref(addr.type))) { - GB_ASSERT(is_type_pointer(addr.type)); - v.kind = lbAddr_RelativeSlice; + } else if (addr.type != nullptr && is_type_relative_multi_pointer(type_deref(addr.type))) { + GB_ASSERT(is_type_pointer(addr.type) || + is_type_multi_pointer(addr.type)); + v.kind = lbAddr_RelativePointer; } return v; } @@ -424,6 +425,43 @@ gb_internal Type *lb_addr_type(lbAddr const &addr) { return type_deref(addr.addr.type); } + +gb_internal lbValue lb_relative_pointer_to_pointer(lbProcedure *p, lbAddr const &addr) { + GB_ASSERT(addr.kind == lbAddr_RelativePointer); + + Type *t = base_type(lb_addr_type(addr)); + GB_ASSERT(is_type_relative_pointer(t) || is_type_relative_multi_pointer(t)); + + Type *pointer_type = nullptr; + Type *base_integer = nullptr; + if (t->kind == Type_RelativePointer) { + pointer_type = t->RelativePointer.pointer_type; + base_integer = t->RelativePointer.base_integer; + } else if (t->kind == Type_RelativeMultiPointer) { + pointer_type = t->RelativeMultiPointer.pointer_type; + base_integer = t->RelativeMultiPointer.base_integer; + } + + lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr); + lbValue offset = lb_emit_conv(p, ptr, alloc_type_pointer(base_integer)); + offset = lb_emit_load(p, offset); + + if (!is_type_unsigned(base_integer)) { + offset = lb_emit_conv(p, offset, t_i64); + } + offset = lb_emit_conv(p, offset, t_uintptr); + lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr); + absolute_ptr = lb_emit_conv(p, absolute_ptr, pointer_type); + + lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, base_integer)); + + // NOTE(bill): nil check + lbValue nil_ptr = lb_const_nil(p->module, pointer_type); + lbValue final_ptr = lb_emit_select(p, cond, nil_ptr, absolute_ptr); + return final_ptr; +} + + gb_internal lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { if (addr.addr.value == nullptr) { GB_PANIC("Illegal addr -> nullptr"); @@ -434,28 +472,8 @@ gb_internal lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { case lbAddr_Map: return lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key); - case lbAddr_RelativePointer: { - Type *rel_ptr = base_type(lb_addr_type(addr)); - GB_ASSERT(rel_ptr->kind == Type_RelativePointer); - - lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr); - lbValue offset = lb_emit_conv(p, ptr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); - offset = lb_emit_load(p, offset); - - if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) { - offset = lb_emit_conv(p, offset, t_i64); - } - offset = lb_emit_conv(p, offset, t_uintptr); - lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr); - absolute_ptr = lb_emit_conv(p, absolute_ptr, rel_ptr->RelativePointer.pointer_type); - - lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, rel_ptr->RelativePointer.base_integer)); - - // NOTE(bill): nil check - lbValue nil_ptr = lb_const_nil(p->module, rel_ptr->RelativePointer.pointer_type); - lbValue final_ptr = lb_emit_select(p, cond, nil_ptr, absolute_ptr); - return final_ptr; - } + case lbAddr_RelativePointer: + return lb_relative_pointer_to_pointer(p, addr); case lbAddr_SoaVariable: // TODO(bill): FIX THIS HACK @@ -477,6 +495,9 @@ gb_internal lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { gb_internal lbValue lb_build_addr_ptr(lbProcedure *p, Ast *expr) { lbAddr addr = lb_build_addr(p, expr); + if (addr.kind == lbAddr_RelativePointer) { + return addr.addr; + } return lb_addr_get_ptr(p, addr); } @@ -685,9 +706,20 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { if (addr.kind == lbAddr_RelativePointer) { Type *rel_ptr = base_type(lb_addr_type(addr)); - GB_ASSERT(rel_ptr->kind == Type_RelativePointer); + GB_ASSERT(rel_ptr->kind == Type_RelativePointer || + rel_ptr->kind == Type_RelativeMultiPointer); + Type *pointer_type = nullptr; + Type *base_integer = nullptr; - value = lb_emit_conv(p, value, rel_ptr->RelativePointer.pointer_type); + if (rel_ptr->kind == Type_RelativePointer) { + pointer_type = rel_ptr->RelativePointer.pointer_type; + base_integer = rel_ptr->RelativePointer.base_integer; + } else if (rel_ptr->kind == Type_RelativeMultiPointer) { + pointer_type = rel_ptr->RelativeMultiPointer.pointer_type; + base_integer = rel_ptr->RelativeMultiPointer.base_integer; + } + + value = lb_emit_conv(p, value, pointer_type); GB_ASSERT(is_type_pointer(addr.addr.type)); lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr); @@ -696,54 +728,20 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { offset.value = LLVMBuildSub(p->builder, val_ptr.value, ptr.value, ""); offset.type = t_uintptr; - if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) { + if (!is_type_unsigned(base_integer)) { offset = lb_emit_conv(p, offset, t_i64); } - offset = lb_emit_conv(p, offset, rel_ptr->RelativePointer.base_integer); + offset = lb_emit_conv(p, offset, base_integer); - lbValue offset_ptr = lb_emit_conv(p, addr.addr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); + lbValue offset_ptr = lb_emit_conv(p, addr.addr, alloc_type_pointer(base_integer)); offset = lb_emit_select(p, lb_emit_comp(p, Token_CmpEq, val_ptr, lb_const_nil(p->module, t_uintptr)), - lb_const_nil(p->module, rel_ptr->RelativePointer.base_integer), + lb_const_nil(p->module, base_integer), offset ); LLVMBuildStore(p->builder, offset.value, offset_ptr.value); return; - } else if (addr.kind == lbAddr_RelativeSlice) { - Type *rel_ptr = base_type(lb_addr_type(addr)); - GB_ASSERT(rel_ptr->kind == Type_RelativeSlice); - - value = lb_emit_conv(p, value, rel_ptr->RelativeSlice.slice_type); - - GB_ASSERT(is_type_pointer(addr.addr.type)); - lbValue ptr = lb_emit_conv(p, lb_emit_struct_ep(p, addr.addr, 0), t_uintptr); - lbValue val_ptr = lb_emit_conv(p, lb_slice_elem(p, value), t_uintptr); - lbValue offset = {}; - offset.value = LLVMBuildSub(p->builder, val_ptr.value, ptr.value, ""); - offset.type = t_uintptr; - - if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) { - offset = lb_emit_conv(p, offset, t_i64); - } - offset = lb_emit_conv(p, offset, rel_ptr->RelativePointer.base_integer); - - - lbValue offset_ptr = lb_emit_conv(p, addr.addr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); - offset = lb_emit_select(p, - lb_emit_comp(p, Token_CmpEq, val_ptr, lb_const_nil(p->module, t_uintptr)), - lb_const_nil(p->module, rel_ptr->RelativePointer.base_integer), - offset - ); - LLVMBuildStore(p->builder, offset.value, offset_ptr.value); - - lbValue len = lb_slice_len(p, value); - len = lb_emit_conv(p, len, rel_ptr->RelativePointer.base_integer); - - lbValue len_ptr = lb_emit_struct_ep(p, addr.addr, 1); - LLVMBuildStore(p->builder, len.value, len_ptr.value); - - return; } else if (addr.kind == lbAddr_Map) { lb_internal_dynamic_map_set(p, addr.addr, addr.map.type, addr.map.key, value, p->curr_stmt); return; @@ -1020,67 +1018,43 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { if (addr.kind == lbAddr_RelativePointer) { Type *rel_ptr = base_type(lb_addr_type(addr)); - GB_ASSERT(rel_ptr->kind == Type_RelativePointer); + Type *base_integer = nullptr; + Type *pointer_type = nullptr; + GB_ASSERT(rel_ptr->kind == Type_RelativePointer || + rel_ptr->kind == Type_RelativeMultiPointer); + + if (rel_ptr->kind == Type_RelativePointer) { + base_integer = rel_ptr->RelativePointer.base_integer; + pointer_type = rel_ptr->RelativePointer.pointer_type; + } else if (rel_ptr->kind == Type_RelativeMultiPointer) { + base_integer = rel_ptr->RelativeMultiPointer.base_integer; + pointer_type = rel_ptr->RelativeMultiPointer.pointer_type; + } lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr); - lbValue offset = lb_emit_conv(p, ptr, alloc_type_pointer(rel_ptr->RelativePointer.base_integer)); + lbValue offset = lb_emit_conv(p, ptr, alloc_type_pointer(base_integer)); offset = lb_emit_load(p, offset); - if (!is_type_unsigned(rel_ptr->RelativePointer.base_integer)) { + if (!is_type_unsigned(base_integer)) { offset = lb_emit_conv(p, offset, t_i64); } offset = lb_emit_conv(p, offset, t_uintptr); lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr); - absolute_ptr = lb_emit_conv(p, absolute_ptr, rel_ptr->RelativePointer.pointer_type); + absolute_ptr = lb_emit_conv(p, absolute_ptr, pointer_type); - lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, rel_ptr->RelativePointer.base_integer)); + lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, base_integer)); // NOTE(bill): nil check - lbValue nil_ptr = lb_const_nil(p->module, rel_ptr->RelativePointer.pointer_type); + lbValue nil_ptr = lb_const_nil(p->module, pointer_type); lbValue final_ptr = {}; final_ptr.type = absolute_ptr.type; final_ptr.value = LLVMBuildSelect(p->builder, cond.value, nil_ptr.value, absolute_ptr.value, ""); - return lb_emit_load(p, final_ptr); - - } else if (addr.kind == lbAddr_RelativeSlice) { - Type *rel_ptr = base_type(lb_addr_type(addr)); - GB_ASSERT(rel_ptr->kind == Type_RelativeSlice); - - lbValue offset_ptr = lb_emit_struct_ep(p, addr.addr, 0); - lbValue ptr = lb_emit_conv(p, offset_ptr, t_uintptr); - lbValue offset = lb_emit_load(p, offset_ptr); - - - if (!is_type_unsigned(rel_ptr->RelativeSlice.base_integer)) { - offset = lb_emit_conv(p, offset, t_i64); + if (rel_ptr->kind == Type_RelativeMultiPointer) { + return final_ptr; } - offset = lb_emit_conv(p, offset, t_uintptr); - lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr); - - Type *slice_type = base_type(rel_ptr->RelativeSlice.slice_type); - GB_ASSERT(rel_ptr->RelativeSlice.slice_type->kind == Type_Slice); - Type *slice_elem = slice_type->Slice.elem; - Type *slice_elem_ptr = alloc_type_pointer(slice_elem); - - absolute_ptr = lb_emit_conv(p, absolute_ptr, slice_elem_ptr); - - lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, rel_ptr->RelativeSlice.base_integer)); - - // NOTE(bill): nil check - lbValue nil_ptr = lb_const_nil(p->module, slice_elem_ptr); - lbValue data = {}; - data.type = absolute_ptr.type; - data.value = LLVMBuildSelect(p->builder, cond.value, nil_ptr.value, absolute_ptr.value, ""); - - lbValue len = lb_emit_load(p, lb_emit_struct_ep(p, addr.addr, 1)); - len = lb_emit_conv(p, len, t_int); - - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, data, len); - return lb_addr_load(p, slice); - + return lb_emit_load(p, final_ptr); } else if (addr.kind == lbAddr_Map) { Type *map_type = base_type(type_deref(addr.addr.type)); @@ -2139,17 +2113,10 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { case Type_RelativePointer: return lb_type_internal(m, type->RelativePointer.base_integer); + case Type_RelativeMultiPointer: + return lb_type_internal(m, type->RelativeMultiPointer.base_integer); - case Type_RelativeSlice: - { - LLVMTypeRef base_integer = lb_type_internal(m, type->RelativeSlice.base_integer); - unsigned field_count = 2; - LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count); - fields[0] = base_integer; - fields[1] = base_integer; - return LLVMStructTypeInContext(ctx, fields, field_count, false); - } case Type_Matrix: { diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 7e3a9133b..66edda825 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1710,7 +1710,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu return lb_string_len(p, v); } else if (is_type_array(t)) { GB_PANIC("Array lengths are constant"); - } else if (is_type_slice(t) || is_type_relative_slice(t)) { + } else if (is_type_slice(t)) { return lb_slice_len(p, v); } else if (is_type_dynamic_array(t)) { return lb_dynamic_array_len(p, v); @@ -1735,7 +1735,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu GB_PANIC("Unreachable"); } else if (is_type_array(t)) { GB_PANIC("Array lengths are constant"); - } else if (is_type_slice(t) || is_type_relative_slice(t)) { + } else if (is_type_slice(t)) { return lb_slice_len(p, v); } else if (is_type_dynamic_array(t)) { return lb_dynamic_array_cap(p, v); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index c85840517..62a67f96a 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -57,7 +57,7 @@ gb_internal lbValue lb_typeid(lbModule *m, Type *type) { case Type_BitSet: kind = Typeid_Bit_Set; break; case Type_SimdVector: kind = Typeid_Simd_Vector; break; case Type_RelativePointer: kind = Typeid_Relative_Pointer; break; - case Type_RelativeSlice: kind = Typeid_Relative_Slice; break; + case Type_RelativeMultiPointer: kind = Typeid_Relative_Multi_Pointer; break; case Type_SoaPointer: kind = Typeid_SoaPointer; break; } @@ -857,12 +857,13 @@ gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup lb_emit_store(p, tag, res); } break; - case Type_RelativeSlice: + + case Type_RelativeMultiPointer: { - tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_slice_ptr); + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_multi_pointer_ptr); LLVMValueRef vals[2] = { - lb_type_info(m, t->RelativeSlice.slice_type).value, - lb_type_info(m, t->RelativeSlice.base_integer).value, + lb_type_info(m, t->RelativeMultiPointer.pointer_type).value, + lb_type_info(m, t->RelativeMultiPointer.base_integer).value, }; lbValue res = {}; @@ -871,6 +872,7 @@ gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup lb_emit_store(p, tag, res); } break; + case Type_Matrix: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_matrix_ptr); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 2ecad1703..8dd6b14b6 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1124,11 +1124,6 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { } } else if (is_type_array(t)) { return lb_emit_array_epi(p, s, index); - } else if (is_type_relative_slice(t)) { - switch (index) { - case 0: result_type = t->RelativeSlice.base_integer; break; - case 1: result_type = t->RelativeSlice.base_integer; break; - } } else if (is_type_soa_pointer(t)) { switch (index) { case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break; @@ -1547,7 +1542,7 @@ gb_internal lbValue lb_slice_elem(lbProcedure *p, lbValue slice) { return lb_emit_struct_ev(p, slice, 0); } gb_internal lbValue lb_slice_len(lbProcedure *p, lbValue slice) { - GB_ASSERT(is_type_slice(slice.type) || is_type_relative_slice(slice.type)); + GB_ASSERT(is_type_slice(slice.type)); return lb_emit_struct_ev(p, slice, 1); } gb_internal lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da) { diff --git a/src/parser.cpp b/src/parser.cpp index aa8969103..56d1e2d6c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2235,7 +2235,11 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { return parse_check_directive_for_statement(operand, name, StateFlag_no_type_assert); } else if (name.string == "relative") { Ast *tag = ast_basic_directive(f, token, name); - tag = parse_call_expr(f, tag); + if (f->curr_token.kind != Token_OpenParen) { + syntax_error(tag, "expected #relative() "); + } else { + tag = parse_call_expr(f, tag); + } Ast *type = parse_type(f); return ast_relative_type(f, tag, type); } else if (name.string == "force_inline" || diff --git a/src/tilde_builtin.cpp b/src/tilde_builtin.cpp index 9dbc3f7c5..f036ce583 100644 --- a/src/tilde_builtin.cpp +++ b/src/tilde_builtin.cpp @@ -44,8 +44,6 @@ gb_internal cgValue cg_builtin_len(cgProcedure *p, cgValue value) { case Type_Struct: GB_ASSERT(is_type_soa_struct(t)); break; - case Type_RelativeSlice: - break; } GB_PANIC("TODO(bill): cg_builtin_len %s", type_to_string(t)); @@ -106,8 +104,6 @@ gb_internal cgValue cg_builtin_cap(cgProcedure *p, cgValue value) { case Type_Struct: GB_ASSERT(is_type_soa_struct(t)); break; - case Type_RelativeSlice: - break; } GB_PANIC("TODO(bill): cg_builtin_cap %s", type_to_string(t)); diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index 5b34480f4..f9187e3e1 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -255,9 +255,9 @@ gb_internal i64 cg_global_const_calculate_region_count_from_basic_type(Type *typ return 1; case Type_RelativePointer: - return 1; - case Type_RelativeSlice: - return 1; // technically 1 + case Type_RelativeMultiPointer: + return 2; // allows for offsets + case Type_Matrix: return 1; diff --git a/src/tilde_debug.cpp b/src/tilde_debug.cpp index 708476377..926cf9cd0 100644 --- a/src/tilde_debug.cpp +++ b/src/tilde_debug.cpp @@ -457,20 +457,8 @@ gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type) { return tb_debug_create_array(m->mod, cg_debug_type(m, type->SimdVector.elem), type->SimdVector.count); case Type_RelativePointer: return cg_debug_type(m, type->RelativePointer.base_integer); - case Type_RelativeSlice: - { - String name = {}; - TB_DebugType *record = tb_debug_create_struct(m->mod, name.len, cast(char const *)name.text); - - TB_DebugType *base_integer = cg_debug_type(m, type->RelativeSlice.base_integer); - TB_CharUnits bi_size = cast(TB_CharUnits)type_size_of(type->RelativeSlice.base_integer); - TB_DebugType **fields = tb_debug_record_begin(record, 2); - fields[0] = tb_debug_create_field(m->mod, base_integer, -1, "data", 0*bi_size); - fields[1] = tb_debug_create_field(m->mod, base_integer, -1, "len", 1*bi_size); - - tb_debug_record_end(record, size, align); - return record; - } + case Type_RelativeMultiPointer: + return cg_debug_type(m, type->RelativeMultiPointer.base_integer); case Type_Matrix: { i64 count = matrix_type_total_internal_elems(type); diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index b654eb5e9..6ff912dd9 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -1469,8 +1469,8 @@ gb_internal cgAddr cg_build_addr_slice_expr(cgProcedure *p, Ast *expr) { return slice; } - case Type_RelativeSlice: - GB_PANIC("TODO(bill): Type_RelativeSlice should be handled above already on the cg_addr_load"); + case Type_RelativeMultiPointer: + GB_PANIC("TODO(bill): Type_RelativeMultiPointer should be handled above already on the cg_addr_load"); break; case Type_DynamicArray: { @@ -3598,22 +3598,18 @@ gb_internal cgAddr cg_build_addr_index_expr(cgProcedure *p, Ast *expr) { return cg_addr(v); } - case Type_RelativeSlice: { - GB_PANIC("TODO(bill): relative slice"); - // lbAddr slice_addr = {}; - // if (deref) { - // slice_addr = lb_addr(lb_build_expr(p, ie->expr)); - // } else { - // slice_addr = lb_build_addr(p, ie->expr); - // } - // lbValue slice = lb_addr_load(p, slice_addr); - - // lbValue elem = lb_slice_elem(p, slice); - // lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - // lbValue len = lb_slice_len(p, slice); - // lb_emit_bounds_check(p, ast_token(ie->index), index, len); - // lbValue v = lb_emit_ptr_offset(p, elem, index); - // return lb_addr(v); + case Type_RelativeMultiPointer: { + cgValue multi_ptr = {}; + multi_ptr = cg_build_expr(p, ie->expr); + if (deref) { + multi_ptr = cg_emit_load(p, multi_ptr); + } + cgValue index = cg_build_expr(p, ie->index); + index = cg_emit_conv(p, index, t_int); + + cgValue v = cg_emit_ptr_offset(p, multi_ptr, index); + v.type = alloc_type_pointer(type_deref(v.type, true)); + return cg_addr(v); } case Type_DynamicArray: { diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index 382b4c02d..2a2aa31aa 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -530,21 +530,6 @@ gb_internal cgValue cg_emit_struct_ep(cgProcedure *p, cgValue s, i64 index) { } case Type_Array: return cg_emit_array_epi(p, s, index); - case Type_RelativeSlice: - { - Type *bi = t->RelativeSlice.base_integer; - i64 sz = type_size_of(bi); - switch (index) { - case 0: - case 1: - result_type = bi; - offset = sz * index; - break; - default: - goto error_case; - } - } - break; case Type_SoaPointer: switch (index) { case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break; diff --git a/src/tilde_type_info.cpp b/src/tilde_type_info.cpp index 0dd014bd1..16fe5fd3e 100644 --- a/src/tilde_type_info.cpp +++ b/src/tilde_type_info.cpp @@ -75,24 +75,24 @@ gb_internal u64 cg_typeid_as_u64(cgModule *m, Type *type) { if (flags & BasicFlag_String) kind = Typeid_String; if (flags & BasicFlag_Rune) kind = Typeid_Rune; } break; - case Type_Pointer: kind = Typeid_Pointer; break; - case Type_MultiPointer: kind = Typeid_Multi_Pointer; break; - case Type_Array: kind = Typeid_Array; break; - case Type_Matrix: kind = Typeid_Matrix; break; - case Type_EnumeratedArray: kind = Typeid_Enumerated_Array; break; - case Type_Slice: kind = Typeid_Slice; break; - case Type_DynamicArray: kind = Typeid_Dynamic_Array; break; - case Type_Map: kind = Typeid_Map; break; - case Type_Struct: kind = Typeid_Struct; break; - case Type_Enum: kind = Typeid_Enum; break; - case Type_Union: kind = Typeid_Union; break; - case Type_Tuple: kind = Typeid_Tuple; break; - case Type_Proc: kind = Typeid_Procedure; break; - case Type_BitSet: kind = Typeid_Bit_Set; break; - case Type_SimdVector: kind = Typeid_Simd_Vector; break; - case Type_RelativePointer: kind = Typeid_Relative_Pointer; break; - case Type_RelativeSlice: kind = Typeid_Relative_Slice; break; - case Type_SoaPointer: kind = Typeid_SoaPointer; break; + case Type_Pointer: kind = Typeid_Pointer; break; + case Type_MultiPointer: kind = Typeid_Multi_Pointer; break; + case Type_Array: kind = Typeid_Array; break; + case Type_Matrix: kind = Typeid_Matrix; break; + case Type_EnumeratedArray: kind = Typeid_Enumerated_Array; break; + case Type_Slice: kind = Typeid_Slice; break; + case Type_DynamicArray: kind = Typeid_Dynamic_Array; break; + case Type_Map: kind = Typeid_Map; break; + case Type_Struct: kind = Typeid_Struct; break; + case Type_Enum: kind = Typeid_Enum; break; + case Type_Union: kind = Typeid_Union; break; + case Type_Tuple: kind = Typeid_Tuple; break; + case Type_Proc: kind = Typeid_Procedure; break; + case Type_BitSet: kind = Typeid_Bit_Set; break; + case Type_SimdVector: kind = Typeid_Simd_Vector; break; + case Type_RelativePointer: kind = Typeid_Relative_Pointer; break; + case Type_RelativeMultiPointer: kind = Typeid_Relative_Multi_Pointer; break; + case Type_SoaPointer: kind = Typeid_SoaPointer; break; } if (is_type_cstring(type)) { @@ -935,15 +935,15 @@ gb_internal void cg_setup_type_info_data(cgModule *m) { cg_global_const_type_info_ptr(m, t->RelativePointer.base_integer, global, offset+base_integer_offset); } break; - case Type_RelativeSlice: + case Type_RelativeMultiPointer: { - tag_type = t_type_info_relative_slice; + tag_type = t_type_info_relative_multi_pointer; - i64 slice_offset = type_offset_of(tag_type, 0); + i64 pointer_offset = type_offset_of(tag_type, 0); i64 base_integer_offset = type_offset_of(tag_type, 1); - cg_global_const_type_info_ptr(m, t->RelativeSlice.slice_type, global, offset+slice_offset); - cg_global_const_type_info_ptr(m, t->RelativeSlice.base_integer, global, offset+base_integer_offset); + cg_global_const_type_info_ptr(m, t->RelativePointer.pointer_type, global, offset+pointer_offset); + cg_global_const_type_info_ptr(m, t->RelativePointer.base_integer, global, offset+base_integer_offset); } break; case Type_Matrix: diff --git a/src/types.cpp b/src/types.cpp index a4856f767..22deca1dc 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -267,8 +267,8 @@ struct TypeProc { Type *pointer_type; \ Type *base_integer; \ }) \ - TYPE_KIND(RelativeSlice, struct { \ - Type *slice_type; \ + TYPE_KIND(RelativeMultiPointer, struct { \ + Type *pointer_type; \ Type *base_integer; \ }) \ TYPE_KIND(Matrix, struct { \ @@ -349,7 +349,7 @@ enum Typeid_Kind : u8 { Typeid_Bit_Set, Typeid_Simd_Vector, Typeid_Relative_Pointer, - Typeid_Relative_Slice, + Typeid_Relative_Multi_Pointer, Typeid_Matrix, Typeid_SoaPointer, }; @@ -635,7 +635,7 @@ gb_global Type *t_type_info_map = nullptr; gb_global Type *t_type_info_bit_set = nullptr; gb_global Type *t_type_info_simd_vector = nullptr; gb_global Type *t_type_info_relative_pointer = nullptr; -gb_global Type *t_type_info_relative_slice = nullptr; +gb_global Type *t_type_info_relative_multi_pointer = nullptr; gb_global Type *t_type_info_matrix = nullptr; gb_global Type *t_type_info_soa_pointer = nullptr; @@ -664,7 +664,7 @@ gb_global Type *t_type_info_map_ptr = nullptr; gb_global Type *t_type_info_bit_set_ptr = nullptr; gb_global Type *t_type_info_simd_vector_ptr = nullptr; gb_global Type *t_type_info_relative_pointer_ptr = nullptr; -gb_global Type *t_type_info_relative_slice_ptr = nullptr; +gb_global Type *t_type_info_relative_multi_pointer_ptr = nullptr; gb_global Type *t_type_info_matrix_ptr = nullptr; gb_global Type *t_type_info_soa_pointer_ptr = nullptr; @@ -737,6 +737,7 @@ gb_internal Type * bit_set_to_int(Type *t); gb_internal bool are_types_identical(Type *x, Type *y); gb_internal bool is_type_pointer(Type *t); +gb_internal bool is_type_multi_pointer(Type *t); gb_internal bool is_type_soa_pointer(Type *t); gb_internal bool is_type_proc(Type *t); gb_internal bool is_type_slice(Type *t); @@ -1035,12 +1036,12 @@ gb_internal Type *alloc_type_relative_pointer(Type *pointer_type, Type *base_int return t; } -gb_internal Type *alloc_type_relative_slice(Type *slice_type, Type *base_integer) { - GB_ASSERT(is_type_slice(slice_type)); +gb_internal Type *alloc_type_relative_multi_pointer(Type *pointer_type, Type *base_integer) { + GB_ASSERT(is_type_multi_pointer(pointer_type)); GB_ASSERT(is_type_integer(base_integer)); - Type *t = alloc_type(Type_RelativeSlice); - t->RelativeSlice.slice_type = slice_type; - t->RelativeSlice.base_integer = base_integer; + Type *t = alloc_type(Type_RelativeMultiPointer); + t->RelativeMultiPointer.pointer_type = pointer_type; + t->RelativeMultiPointer.base_integer = base_integer; return t; } @@ -1551,9 +1552,9 @@ gb_internal bool is_type_relative_pointer(Type *t) { t = base_type(t); return t->kind == Type_RelativePointer; } -gb_internal bool is_type_relative_slice(Type *t) { +gb_internal bool is_type_relative_multi_pointer(Type *t) { t = base_type(t); - return t->kind == Type_RelativeSlice; + return t->kind == Type_RelativeMultiPointer; } gb_internal bool is_type_u8_slice(Type *t) { @@ -1970,7 +1971,7 @@ gb_internal bool is_type_indexable(Type *t) { return true; case Type_EnumeratedArray: return true; - case Type_RelativeSlice: + case Type_RelativeMultiPointer: return true; case Type_Matrix: return true; @@ -1989,7 +1990,7 @@ gb_internal bool is_type_sliceable(Type *t) { return true; case Type_EnumeratedArray: return false; - case Type_RelativeSlice: + case Type_RelativeMultiPointer: return true; case Type_Matrix: return false; @@ -2195,12 +2196,12 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) { } break; - case Type_RelativeSlice: - if (is_type_polymorphic(t->RelativeSlice.slice_type, or_specialized)) { + case Type_RelativeMultiPointer: + if (is_type_polymorphic(t->RelativeMultiPointer.pointer_type, or_specialized)) { return true; } - if (t->RelativeSlice.base_integer != nullptr && - is_type_polymorphic(t->RelativeSlice.base_integer, or_specialized)) { + if (t->RelativeMultiPointer.base_integer != nullptr && + is_type_polymorphic(t->RelativeMultiPointer.base_integer, or_specialized)) { return true; } break; @@ -2258,7 +2259,7 @@ gb_internal bool type_has_nil(Type *t) { return false; case Type_RelativePointer: - case Type_RelativeSlice: + case Type_RelativeMultiPointer: return true; } return false; @@ -2425,7 +2426,7 @@ gb_internal bool is_type_load_safe(Type *type) { return true; case Type_RelativePointer: - case Type_RelativeSlice: + case Type_RelativeMultiPointer: return true; case Type_Pointer: @@ -3629,8 +3630,8 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) { case Type_RelativePointer: return type_align_of_internal(t->RelativePointer.base_integer, path); - case Type_RelativeSlice: - return type_align_of_internal(t->RelativeSlice.base_integer, path); + case Type_RelativeMultiPointer: + return type_align_of_internal(t->RelativeMultiPointer.base_integer, path); case Type_SoaPointer: return build_context.int_size; @@ -3912,8 +3913,8 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { case Type_RelativePointer: return type_size_of_internal(t->RelativePointer.base_integer, path); - case Type_RelativeSlice: - return 2*type_size_of_internal(t->RelativeSlice.base_integer, path); + case Type_RelativeMultiPointer: + return type_size_of_internal(t->RelativeMultiPointer.base_integer, path); } // Catch all @@ -4466,11 +4467,11 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_append_fmt(str, ") "); str = write_type_to_string(str, type->RelativePointer.pointer_type); break; - case Type_RelativeSlice: + case Type_RelativeMultiPointer: str = gb_string_append_fmt(str, "#relative("); - str = write_type_to_string(str, type->RelativeSlice.base_integer); + str = write_type_to_string(str, type->RelativePointer.base_integer); str = gb_string_append_fmt(str, ") "); - str = write_type_to_string(str, type->RelativeSlice.slice_type); + str = write_type_to_string(str, type->RelativePointer.pointer_type); break; case Type_Matrix: -- cgit v1.2.3