From eec3b3009f0005090ddd5a7901e5f3c38cf31ce1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 22 Jul 2023 10:16:28 +0100 Subject: Begin work on builtin procedures --- src/tilde_builtin.cpp | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 src/tilde_builtin.cpp (limited to 'src/tilde_builtin.cpp') diff --git a/src/tilde_builtin.cpp b/src/tilde_builtin.cpp new file mode 100644 index 000000000..08c3f7bdd --- /dev/null +++ b/src/tilde_builtin.cpp @@ -0,0 +1,147 @@ +gb_internal cgValue cg_builtin_len(cgProcedure *p, cgValue value) { + Type *t = base_type(value.type); + + switch (t->kind) { + case Type_Basic: + switch (t->Basic.kind) { + case Basic_string: + { + GB_ASSERT(value.kind == cgValue_Addr); + cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); + cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1); + return cg_emit_load(p, len_ptr); + } + case Basic_cstring: + break; + } + break; + case Type_Array: + return cg_const_int(p, t_int, t->Array.count); + case Type_EnumeratedArray: + return cg_const_int(p, t_int, t->EnumeratedArray.count); + case Type_Slice: + { + GB_ASSERT(value.kind == cgValue_Addr); + cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); + cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1); + return cg_emit_load(p, len_ptr); + } + case Type_DynamicArray: + { + GB_ASSERT(value.kind == cgValue_Addr); + cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); + cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1); + return cg_emit_load(p, len_ptr); + } + case Type_Map: + { + GB_ASSERT(value.kind == cgValue_Addr); + cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); + cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1); + return cg_emit_conv(p, cg_emit_load(p, len_ptr), t_int); + } + 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)); + return {}; +} + +gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &value) { + Type *t = base_type(value.type); + cgValue res = {}; + switch (t->kind) { + case Type_Slice: + { + GB_ASSERT(value.kind == cgValue_Addr); + 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); + } + break; + case Type_DynamicArray: + { + GB_ASSERT(value.kind == cgValue_Addr); + 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); + } + break; + case Type_Basic: + if (t->Basic.kind == Basic_string) { + GB_ASSERT(value.kind == cgValue_Addr); + 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); + } else if (t->Basic.kind == Basic_cstring) { + res = cg_emit_conv(p, value, t_u8_multi_ptr); + } + break; + case Type_Pointer: + case Type_MultiPointer: + GB_PANIC("TODO(bill) %s", type_to_string(value.type)); + // res = cg_emit_conv(p, value, tv.type); + break; + } + GB_ASSERT(res.node != nullptr); + return res; +} + +gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr) { + ast_node(ce, CallExpr, expr); + + if (BuiltinProc__simd_begin < id && id < BuiltinProc__simd_end) { + GB_PANIC("TODO(bill): cg_build_builtin_simd_proc"); + // return cg_build_builtin_simd_proc(p, expr, tv, id); + } + + String builtin_name = builtin_procs[id].name; + + switch (id) { + case BuiltinProc_DIRECTIVE: { + ast_node(bd, BasicDirective, ce->proc); + String name = bd->name.string; + GB_ASSERT(name == "location"); + String procedure = p->entity->token.string; + TokenPos pos = ast_token(ce->proc).pos; + if (ce->args.count > 0) { + Ast *ident = unselector_expr(ce->args[0]); + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_node(ident); + GB_ASSERT(e != nullptr); + + if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) { + procedure = e->parent_proc_decl->entity->token.string; + } else { + procedure = str_lit(""); + } + 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); + } break; + + case BuiltinProc_len: { + cgValue v = cg_build_expr(p, ce->args[0]); + Type *t = base_type(v.type); + if (is_type_pointer(t)) { + // IMPORTANT TODO(bill): Should there be a nil pointer check? + v = cg_emit_load(p, v); + t = type_deref(t); + } + return cg_builtin_len(p, v); + } + + + } + + + GB_PANIC("TODO(bill): builtin procs %d %.*s", id, LIT(builtin_name)); + return {}; +} + -- 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_builtin.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_builtin.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 2f9c5d2d0b500518acecb9badd4b6947db6fd536 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 23 Jul 2023 22:07:21 +0100 Subject: Minor clean up to builtin procs --- src/tilde_builtin.cpp | 136 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 120 insertions(+), 16 deletions(-) (limited to 'src/tilde_builtin.cpp') diff --git a/src/tilde_builtin.cpp b/src/tilde_builtin.cpp index c55cfbb75..6deaf0e9b 100644 --- a/src/tilde_builtin.cpp +++ b/src/tilde_builtin.cpp @@ -12,6 +12,7 @@ gb_internal cgValue cg_builtin_len(cgProcedure *p, cgValue value) { return cg_emit_load(p, len_ptr); } case Basic_cstring: + GB_PANIC("TODO(bill): len(cstring)"); break; } break; @@ -51,6 +52,69 @@ gb_internal cgValue cg_builtin_len(cgProcedure *p, cgValue value) { return {}; } +gb_internal cgValue cg_builtin_cap(cgProcedure *p, cgValue value) { + Type *t = base_type(value.type); + + switch (t->kind) { + case Type_Basic: + switch (t->Basic.kind) { + case Basic_string: + { + GB_ASSERT(value.kind == cgValue_Addr); + cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); + cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1); + return cg_emit_load(p, len_ptr); + } + case Basic_cstring: + GB_PANIC("TODO(bill): cap(cstring)"); + break; + } + break; + case Type_Array: + return cg_const_int(p, t_int, t->Array.count); + case Type_EnumeratedArray: + return cg_const_int(p, t_int, t->EnumeratedArray.count); + case Type_Slice: + { + GB_ASSERT(value.kind == cgValue_Addr); + cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); + cgValue len_ptr = cg_emit_struct_ep(p, ptr, 1); + return cg_emit_load(p, len_ptr); + } + case Type_DynamicArray: + { + GB_ASSERT(value.kind == cgValue_Addr); + cgValue ptr = cg_value(value.node, alloc_type_pointer(value.type)); + cgValue len_ptr = cg_emit_struct_ep(p, ptr, 2); + return cg_emit_load(p, len_ptr); + } + case Type_Map: + { + TB_DataType dt_uintptr = cg_data_type(t_uintptr); + TB_Node *zero = tb_inst_uint(p->func, dt_uintptr, 0); + TB_Node *one = tb_inst_uint(p->func, dt_uintptr, 0); + TB_Node *mask = tb_inst_uint(p->func, dt_uintptr, MAP_CACHE_LINE_SIZE-1); + + TB_Node *data = cg_emit_struct_ev(p, value, 0).node; + TB_Node *log2_cap = tb_inst_and(p->func, data, mask); + TB_Node *cap = tb_inst_shl(p->func, one, log2_cap, cast(TB_ArithmeticBehavior)0); + TB_Node *cmp = tb_inst_cmp_eq(p->func, data, zero); + + cgValue res = cg_value(tb_inst_select(p->func, cmp, zero, cap), t_uintptr); + return cg_emit_conv(p, res, t_int); + } + 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)); + return {}; +} + + gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &value) { Type *t = base_type(value.type); cgValue res = {}; @@ -108,7 +172,7 @@ 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) { +gb_internal cgValue cg_builtin_abs(cgProcedure *p, cgValue const &x) { if (is_type_unsigned(x.type)) { return x; } @@ -138,6 +202,39 @@ gb_internal cgValue cg_builtin_abs(cgProcedure *p, cgValue x) { return cg_emit_select(p, cond, neg, x); } +gb_internal cgValue cg_builtin_clamp(cgProcedure *p, Type *t, cgValue const &x, cgValue const &min, cgValue const &max) { + cgValue z = x; + z = cg_builtin_max(p, t, z, min); + z = cg_builtin_min(p, t, z, max); + return z; +} + + + +gb_internal cgValue cg_builtin_mem_zero(cgProcedure *p, cgValue const &ptr, cgValue const &len) { + GB_ASSERT(ptr.kind == cgValue_Value); + GB_ASSERT(len.kind == cgValue_Value); + tb_inst_memzero(p->func, ptr.node, len.node, 1, false); + return ptr; +} + +gb_internal cgValue cg_builtin_mem_copy(cgProcedure *p, cgValue const &dst, cgValue const &src, cgValue const &len) { + 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 dst; +} + +gb_internal cgValue cg_builtin_mem_copy_non_overlapping(cgProcedure *p, cgValue const &dst, cgValue const &src, cgValue const &len) { + 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 dst; +} + gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr) { @@ -186,6 +283,17 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr return cg_builtin_len(p, v); } + case BuiltinProc_cap: { + cgValue v = cg_build_expr(p, ce->args[0]); + Type *t = base_type(v.type); + if (is_type_pointer(t)) { + // IMPORTANT TODO(bill): Should there be a nil pointer check? + v = cg_emit_load(p, v); + t = type_deref(t); + } + return cg_builtin_cap(p, v); + } + case BuiltinProc_raw_data: { cgValue v = cg_build_expr(p, ce->args[0]); @@ -225,6 +333,14 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr return cg_builtin_abs(p, x); } + case BuiltinProc_clamp: + { + cgValue x = cg_build_expr(p, ce->args[0]); + cgValue min = cg_build_expr(p, ce->args[1]); + cgValue max = cg_build_expr(p, ce->args[2]); + return cg_builtin_clamp(p, type_of_expr(expr), x, min, max); + } + case BuiltinProc_debug_trap: tb_inst_debugbreak(p->func); return {}; @@ -236,10 +352,7 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr { 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 {}; + return cg_builtin_mem_zero(p, ptr, len); } case BuiltinProc_mem_copy: @@ -247,12 +360,7 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr 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 {}; + return cg_builtin_mem_copy(p, dst, src, len); } case BuiltinProc_mem_copy_non_overlapping: @@ -260,11 +368,7 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr 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 {}; + return cg_builtin_mem_copy_non_overlapping(p, dst, src, len); } -- cgit v1.2.3 From 4051dd95223f9662c78c05d09e01b925d2d99ac0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 24 Jul 2023 11:30:07 +0100 Subject: Update Tilde to get basic "Hello World" working with `runtime.print_string` --- src/tilde/tb.lib | Bin 4161458 -> 4161494 bytes src/tilde_builtin.cpp | 14 ++++++++++---- src/tilde_proc.cpp | 6 +++--- 3 files changed, 13 insertions(+), 7 deletions(-) (limited to 'src/tilde_builtin.cpp') diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib index 64b6f492d..b35b28fc0 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 6deaf0e9b..b40eacc7f 100644 --- a/src/tilde_builtin.cpp +++ b/src/tilde_builtin.cpp @@ -303,12 +303,15 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr 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])); + cgValue x = cg_build_expr(p, ce->args[0]); + cgValue y = cg_build_expr(p, ce->args[1]); + return cg_builtin_min(p, t, x, y); } 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])); + cgValue y = cg_build_expr(p, ce->args[i]); + x = cg_builtin_min(p, t, x, y); } return x; } @@ -316,12 +319,15 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr 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])); + cgValue x = cg_build_expr(p, ce->args[0]); + cgValue y = cg_build_expr(p, ce->args[1]); + return cg_builtin_max(p, t, x, y); } 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])); + cgValue y = cg_build_expr(p, ce->args[i]); + x = cg_builtin_max(p, t, x, y); } return x; } diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index e75c621ee..8143c9a6e 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -334,8 +334,8 @@ gb_internal void cg_procedure_end(cgProcedure *p) { } bool emit_asm = false; - if (string_starts_with(p->name, str_lit("bug@"))) { - emit_asm = true; + if (string_starts_with(p->name, str_lit("runtime@_os_write"))) { + // emit_asm = true; } TB_FunctionOutput *output = tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST, emit_asm); @@ -358,7 +358,7 @@ gb_internal void cg_procedure_generate(cgProcedure *p) { cg_procedure_end(p); if ( - // string_starts_with(p->name, str_lit("bug@")) || + string_starts_with(p->name, str_lit("runtime@_os_write")) || false ) { // IR Printing TB_Arena *arena = tb_default_arena(); -- 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_builtin.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_builtin.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 4a71603a777783a2ee4cd78368f1b1fbe76d7773 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 3 Aug 2023 14:46:22 +0100 Subject: Add hasher proc generation --- src/tilde.hpp | 7 +- src/tilde_builtin.cpp | 6 ++ src/tilde_expr.cpp | 42 +++++++++++ src/tilde_proc.cpp | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 241 insertions(+), 2 deletions(-) (limited to 'src/tilde_builtin.cpp') diff --git a/src/tilde.hpp b/src/tilde.hpp index a70d03a6c..5944c9ef7 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -350,9 +350,12 @@ 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_unary_arith(cgProcedure *p, TokenKind op, cgValue x, Type *type); +gb_internal void cg_emit_increment(cgProcedure *p, cgValue addr); -gb_internal cgProcedure *cg_equal_proc_for_type(cgModule *m, Type *type); - +gb_internal cgProcedure *cg_equal_proc_for_type (cgModule *m, Type *type); +gb_internal cgProcedure *cg_hasher_proc_for_type(cgModule *m, Type *type); +gb_internal cgValue cg_hasher_proc_value_for_type(cgProcedure *p, Type *type); +gb_internal cgValue cg_equal_proc_value_for_type(cgProcedure *p, 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_builtin.cpp b/src/tilde_builtin.cpp index edf436424..9dbc3f7c5 100644 --- a/src/tilde_builtin.cpp +++ b/src/tilde_builtin.cpp @@ -432,6 +432,12 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr return cg_emit_runtime_call(p, "__type_info_of", args); } + + case BuiltinProc_type_equal_proc: + return cg_equal_proc_value_for_type(p, ce->args[0]->tav.type); + + case BuiltinProc_type_hasher_proc: + return cg_hasher_proc_value_for_type(p, ce->args[0]->tav.type); } diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index fdd26e3db..b654eb5e9 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -1780,6 +1780,48 @@ gb_internal void cg_emit_if(cgProcedure *p, cgValue const &cond, TB_Node *true_r tb_inst_if(p->func, cond.node, true_region, false_region); } + +struct cgLoopData { + cgAddr index_addr; + cgValue index; + TB_Node *body; + TB_Node *done; + TB_Node *loop; +}; + +gb_internal cgLoopData cg_loop_start(cgProcedure *p, isize count, Type *index_type) { + cgLoopData data = {}; + + cgValue max = cg_const_int(p, index_type, count); + + data.index_addr = cg_add_local(p, index_type, nullptr, true); + + data.body = cg_control_region(p, "loop_body"); + data.done = cg_control_region(p, "loop_done"); + data.loop = cg_control_region(p, "loop_loop"); + + cg_emit_goto(p, data.loop); + tb_inst_set_control(p->func, data.loop); + + data.index = cg_addr_load(p, data.index_addr); + + cgValue cond = cg_emit_comp(p, Token_Lt, data.index, max); + cg_emit_if(p, cond, data.body, data.done); + tb_inst_set_control(p->func, data.body); + + return data; +} + +gb_internal void cg_loop_end(cgProcedure *p, cgLoopData const &data) { + if (data.index_addr.addr.node != nullptr) { + cg_emit_increment(p, data.index_addr.addr); + cg_emit_goto(p, data.loop); + tb_inst_set_control(p->func, data.done); + } +} + + + gb_internal void cg_build_try_lhs_rhs(cgProcedure *p, Ast *arg, Type *final_type, cgValue *lhs_, cgValue *rhs_) { cgValue lhs = {}; cgValue rhs = {}; diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 00062d708..1981d32ce 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -984,6 +984,17 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) { +gb_internal cgValue cg_hasher_proc_value_for_type(cgProcedure *p, Type *type) { + cgProcedure *found = cg_hasher_proc_for_type(p->module, type); + return cg_value(tb_inst_get_symbol_address(p->func, found->symbol), found->type); +} + +gb_internal cgValue cg_equal_proc_value_for_type(cgProcedure *p, Type *type) { + cgProcedure *found = cg_equal_proc_for_type(p->module, type); + return cg_value(tb_inst_get_symbol_address(p->func, found->symbol), found->type); +} + + gb_internal cgProcedure *cg_equal_proc_for_type(cgModule *m, Type *type) { type = base_type(type); @@ -1115,5 +1126,182 @@ gb_internal cgProcedure *cg_equal_proc_for_type(cgModule *m, Type *type) { cg_procedure_end(p); + return p; +} + + +gb_internal cgValue cg_simple_compare_hash(cgProcedure *p, Type *type, cgValue data, cgValue seed) { + TEMPORARY_ALLOCATOR_GUARD(); + + GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type)); + + auto args = slice_make(temporary_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = cg_const_int(p, t_int, type_size_of(type)); + return cg_emit_runtime_call(p, "default_hasher", args); +} + + + + + +gb_internal cgProcedure *cg_hasher_proc_for_type(cgModule *m, Type *type) { + type = base_type(type); + GB_ASSERT(is_type_valid_for_keys(type)); + + mutex_lock(&m->generated_procs_mutex); + defer (mutex_unlock(&m->generated_procs_mutex)); + + cgProcedure **found = map_get(&m->hasher_procs, type); + if (found) { + return *found; + } + + static std::atomic proc_index; + + char buf[32] = {}; + isize n = gb_snprintf(buf, 32, "__$hasher%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_hasher_proc); + map_set(&m->hasher_procs, type, p); + + cg_procedure_begin(p); + defer (cg_procedure_end(p)); + + TB_Node *x = tb_inst_param(p->func, 0); // data + TB_Node *y = tb_inst_param(p->func, 1); // seed + + cgValue data = cg_value(x, t_rawptr); + cgValue seed = cg_value(y, t_uintptr); + + if (is_type_simple_compare(type)) { + cgValue res = cg_simple_compare_hash(p, type, data, seed); + cg_build_return_stmt_internal_single(p, res); + return p; + } + + TEMPORARY_ALLOCATOR_GUARD(); + + auto args = slice_make(temporary_allocator(), 2); + + if (type->kind == Type_Struct) { + type_set_offsets(type); + for_array(i, type->Struct.fields) { + i64 offset = type->Struct.offsets[i]; + Entity *field = type->Struct.fields[i]; + cgValue field_hasher = cg_hasher_proc_value_for_type(p, field->type); + + TB_Node *ptr = tb_inst_member_access(p->func, data.node, offset); + + args[0] = cg_value(ptr, alloc_type_pointer(field->type)); + args[1] = seed; + seed = cg_emit_call(p, field_hasher, args); + } + + cg_build_return_stmt_internal_single(p, seed); + } else if (type->kind == Type_Union) { + if (type_size_of(type) == 0) { + cg_build_return_stmt_internal_single(p, seed); + } else if (is_type_union_maybe_pointer(type)) { + Type *v = type->Union.variants[0]; + cgValue variant_hasher = cg_hasher_proc_value_for_type(p, v); + + args[0] = data; + args[1] = seed; + cgValue res = cg_emit_call(p, variant_hasher, args); + cg_build_return_stmt_internal_single(p, seed); + } else { + TB_Node *end_region = cg_control_region(p, "bend"); + TB_Node *switch_region = cg_control_region(p, "bswitch"); + + cg_emit_goto(p, switch_region); + + size_t entry_count = type->Union.variants.count; + TB_SwitchEntry *keys = gb_alloc_array(temporary_allocator(), TB_SwitchEntry, entry_count); + for (size_t i = 0; i < entry_count; i++) { + TB_Node *region = cg_control_region(p, "bcase"); + Type *variant = type->Union.variants[i]; + keys[i].key = union_variant_index(type, variant); + keys[i].value = region; + + tb_inst_set_control(p->func, region); + + cgValue variant_hasher = cg_hasher_proc_value_for_type(p, variant); + + args[0] = data; + args[1] = seed; + cgValue res = cg_emit_call(p, variant_hasher, args); + cg_build_return_stmt_internal_single(p, res); + } + + tb_inst_set_control(p->func, switch_region); + + cgValue tag_ptr = cg_emit_union_tag_ptr(p, data); + cgValue tag = cg_emit_load(p, tag_ptr); + + TB_DataType tag_dt = cg_data_type(tag.type); + GB_ASSERT(tag.kind == cgValue_Value); + tb_inst_branch(p->func, tag_dt, tag.node, end_region, entry_count, keys); + + tb_inst_set_control(p->func, end_region); + cg_build_return_stmt_internal_single(p, seed); + } + } else if (type->kind == Type_Array) { + cgAddr pres = cg_add_local(p, t_uintptr, nullptr, false); + cg_addr_store(p, pres, seed); + + cgValue elem_hasher = cg_hasher_proc_value_for_type(p, type->Array.elem); + + auto loop_data = cg_loop_start(p, type->Array.count, t_int); + + i64 stride = type_size_of(type->Array.elem); + TB_Node *ptr = tb_inst_array_access(p->func, data.node, loop_data.index.node, stride); + args[0] = cg_value(ptr, alloc_type_pointer(type->Array.elem)); + args[1] = cg_addr_load(p, pres); + + cgValue new_seed = cg_emit_call(p, elem_hasher, args); + cg_addr_store(p, pres, new_seed); + + cg_loop_end(p, loop_data); + + cgValue res = cg_addr_load(p, pres); + cg_build_return_stmt_internal_single(p, res); + } else if (type->kind == Type_EnumeratedArray) { + cgAddr pres = cg_add_local(p, t_uintptr, nullptr, false); + cg_addr_store(p, pres, seed); + + cgValue elem_hasher = cg_hasher_proc_value_for_type(p, type->EnumeratedArray.elem); + + auto loop_data = cg_loop_start(p, type->EnumeratedArray.count, t_int); + + i64 stride = type_size_of(type->EnumeratedArray.elem); + TB_Node *ptr = tb_inst_array_access(p->func, data.node, loop_data.index.node, stride); + args[0] = cg_value(ptr, alloc_type_pointer(type->EnumeratedArray.elem)); + args[1] = cg_addr_load(p, pres); + + cgValue new_seed = cg_emit_call(p, elem_hasher, args); + cg_addr_store(p, pres, new_seed); + + cg_loop_end(p, loop_data); + + cgValue res = cg_addr_load(p, pres); + cg_build_return_stmt_internal_single(p, res); + } else if (is_type_cstring(type)) { + args[0] = data; + args[1] = seed; + cgValue res = cg_emit_runtime_call(p, "default_hasher_cstring", args); + cg_build_return_stmt_internal_single(p, seed); + } else if (is_type_string(type)) { + args[0] = data; + args[1] = seed; + cgValue res = cg_emit_runtime_call(p, "default_hasher_string", args); + cg_build_return_stmt_internal_single(p, seed); + } else { + GB_PANIC("Unhandled type for hasher: %s", type_to_string(type)); + } return p; } \ No newline at end of file -- 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_builtin.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