From 835d7dcab23b71a580e705b829a2ba41df504325 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 7 Aug 2018 11:36:18 +0100 Subject: [PATCH] `make` as a user-level procedure rather than a built-in procedure --- core/mem/alloc.odin | 28 +++ core/runtime/core.odin | 9 + src/check_expr.cpp | 490 ++++------------------------------------- src/checker.hpp | 24 -- src/ir.cpp | 400 --------------------------------- 5 files changed, 85 insertions(+), 866 deletions(-) diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin index 7cdccdf14..45c813c2a 100644 --- a/core/mem/alloc.odin +++ b/core/mem/alloc.odin @@ -102,6 +102,34 @@ new_clone_with_allocator :: inline proc(a: Allocator, data: $T, loc := #caller_l } +make_slice :: proc(T: type/[]$E, len: int) -> T { + data := alloc(size_of(E)*len, align_of(E)); + s := Raw_Slice{data, len}; + return transmute(T)s; +} +make_dynamic_array_len :: proc(T: type/[dynamic]$E, len: int = 16) -> T { + return make_dynamic_array(T, len, len); +} +make_dynamic_array :: proc(T: type/[dynamic]$E, len, cap: int) -> T { + data := alloc(size_of(E)*cap, align_of(E)); + s := Raw_Dynamic_Array{data, len, cap, context.allocator}; + return transmute(T)s; +} +make_map :: proc(T: type/map[$K]$E, cap: int = 16) -> T { + m: T; + reserve_map(&m, cap); + return m; +} + +make :: proc[ + make_slice, + make_dynamic_array_len, + make_dynamic_array, + make_map, +]; + + + default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int, loc := #caller_location) -> rawptr { if old_memory == nil do return alloc(new_size, alignment, loc); diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 154ffed16..8eb830048 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -325,6 +325,15 @@ delete :: proc[ mem.delete_map, ]; +@(builtin) +make :: proc[ + mem.make_slice, + mem.make_dynamic_array_len, + mem.make_dynamic_array, + mem.make_map, +]; + + @(builtin) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c5b8b80c5..c3f252cf7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2794,8 +2794,6 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } switch (id) { - // case BuiltinProc_new: - case BuiltinProc_make: case BuiltinProc_size_of: case BuiltinProc_align_of: case BuiltinProc_offset_of: @@ -2933,294 +2931,6 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } - #if 0 - case BuiltinProc_new: { - // new :: proc(Type) -> ^Type - Operand op = {}; - check_expr_or_type(c, &op, ce->args[0]); - Type *type = op.type; - if ((op.mode != Addressing_Type && type == nullptr) || type == t_invalid) { - error(ce->args[0], "Expected a type for 'new'"); - return false; - } - operand->mode = Addressing_Value; - operand->type = alloc_type_pointer(type); - - break; - } - #endif - #if 0 - case BuiltinProc_new_slice: { - // new_slice :: proc(Type, len: int) -> []Type - // proc new_slice(Type, len, cap: int) -> []Type - Operand op = {}; - check_expr_or_type(c, &op, ce->args[0]); - Type *type = op.type; - if ((op.mode != Addressing_Type && type == nullptr) || type == t_invalid) { - error(ce->args[0], "Expected a type for 'new_slice'"); - return false; - } - - isize arg_count = ce->args.count; - if (arg_count < 2 || 3 < arg_count) { - error(ce->args[0], "'new_slice' expects 2 or 3 arguments, found %td", arg_count); - // NOTE(bill): Return the correct type to reduce errors - } else { - // If any are constant - i64 sizes[2] = {}; - isize size_count = 0; - for (isize i = 1; i < arg_count; i++) { - i64 val = 0; - bool ok = check_index_value(c, ce->args[i], -1, &val); - if (ok && val >= 0) { - GB_ASSERT(size_count < gb_count_of(sizes)); - sizes[size_count++] = val; - } - } - - if (size_count == 2 && sizes[0] > sizes[1]) { - error(ce->args[1], "'new_slice' count and capacity are swapped"); - // No need quit - } - } - - operand->mode = Addressing_Value; - operand->type = alloc_type_slice(type); - - break; - } - #endif - case BuiltinProc_make: { - // make :: proc(Type, len: int) -> Type - // proc make(Type, len, cap: int) -> Type - Operand op = {}; - check_expr_or_type(c, &op, ce->args[0]); - Type *type = op.type; - if ((op.mode != Addressing_Type && type == nullptr) || type == t_invalid) { - error(ce->args[0], "Expected a type for 'make'"); - return false; - } - - isize min_args = 0; - isize max_args = 1; - if (is_type_slice(type)) { - min_args = 2; - max_args = 2; - add_package_dependency(c, "mem", "alloc"); - } else if (is_type_map(type)) { - min_args = 1; - max_args = 2; - add_package_dependency(c, "runtime", "__dynamic_map_reserve"); - } else if (is_type_dynamic_array(type)) { - min_args = 1; - max_args = 3; - add_package_dependency(c, "runtime", "__dynamic_array_make"); - } else { - gbString str = type_to_string(type); - error(call, "Cannot 'make' %s; type must be a slice, map, or dynamic array", str); - gb_string_free(str); - return false; - } - - isize arg_count = ce->args.count; - if (arg_count < min_args || max_args < arg_count) { - error(ce->args[0], "'make' expects %td or %d argument, found %td", min_args, max_args, arg_count); - return false; - } - - // If any are constant - i64 sizes[4] = {}; - isize size_count = 0; - for (isize i = 1; i < arg_count; i++) { - i64 val = 0; - bool ok = check_index_value(c, false, ce->args[i], -1, &val); - if (ok && val >= 0) { - GB_ASSERT(size_count < gb_count_of(sizes)); - sizes[size_count++] = val; - } - } - - if (size_count == 2 && sizes[0] > sizes[1]) { - error(ce->args[1], "'make' count and capacity are swapped"); - // No need quit - } - - operand->mode = Addressing_Value; - operand->type = type; - - break; - } - - #if 0 - case BuiltinProc_free: { - // free :: proc(^Type) - // proc free([]Type) - // proc free(string) - // proc free(map[K]T) - Type *type = operand->type; - bool ok = false; - if (is_type_pointer(type)) { - ok = true; - } else if (is_type_slice(type)) { - ok = true; - } else if (is_type_string(type)) { - ok = true; - } else if (is_type_dynamic_array(type)) { - ok = true; - } else if (is_type_dynamic_map(type)) { - ok = true; - } - - if (!ok) { - gbString type_str = type_to_string(type); - error(operand->expr, "Invalid type for 'free', got '%s'", type_str); - gb_string_free(type_str); - return false; - } - - - operand->mode = Addressing_NoValue; - - break; - } - #endif - - - #if 0 - case BuiltinProc_reserve: { - // reserve :: proc([dynamic]Type, count: int) { - // reserve :: proc(map[Key]Type, count: int) { - Type *type = operand->type; - if (!is_type_dynamic_array(type) && !is_type_dynamic_map(type)) { - gbString str = type_to_string(type); - error(operand->expr, "Expected a dynamic array or dynamic map, got '%s'", str); - gb_string_free(str); - return false; - } - - Ast *capacity = ce->args[1]; - Operand op = {}; - check_expr(c, &op, capacity); - if (op.mode == Addressing_Invalid) { - return false; - } - Type *arg_type = base_type(op.type); - if (!is_type_integer(arg_type)) { - error(operand->expr, "'reserve' capacities must be an integer"); - return false; - } - - operand->type = nullptr; - operand->mode = Addressing_NoValue; - - break; - } - #endif - #if 0 - case BuiltinProc_clear: { - Type *type = operand->type; - bool is_pointer = is_type_pointer(type); - type = base_type(type_deref(type)); - if (!is_type_dynamic_array(type) && !is_type_map(type) && !is_type_slice(type)) { - gbString str = type_to_string(type); - error(operand->expr, "Invalid type for 'clear', got '%s'", str); - gb_string_free(str); - return false; - } - - operand->type = nullptr; - operand->mode = Addressing_NoValue; - - break; - } - #endif - #if 0 - case BuiltinProc_append: { - // append :: proc([dynamic]Type, item: ..Type) - // proc append([]Type, item: ..Type) - Operand prev_operand = *operand; - - Type *type = operand->type; - bool is_pointer = is_type_pointer(type); - type = base_type(type_deref(type)); - if (!is_type_dynamic_array(type) && !is_type_slice(type)) { - gbString str = type_to_string(type); - error(operand->expr, "Expected a slice or dynamic array, got '%s'", str); - gb_string_free(str); - return false; - } - - bool is_addressable = operand->mode == Addressing_Variable; - if (is_pointer) { - is_addressable = true; - } - if (!is_addressable) { - error(operand->expr, "'append' can only operate on addressable values"); - return false; - } - - Type *elem = nullptr; - if (is_type_dynamic_array(type)) { - elem = type->DynamicArray.elem; - } else { - elem = type->Slice.elem; - } - Type *slice_elem = alloc_type_slice(elem); - - Type *proc_type_params = alloc_type_tuple(c->allocator); - proc_type_params->Tuple.variables = gb_alloc_array(c->allocator, Entity *, 2); - proc_type_params->Tuple.variable_count = 2; - proc_type_params->Tuple.variables[0] = alloc_entity_param(c->allocator, nullptr, blank_token, operand->type, false, false); - proc_type_params->Tuple.variables[1] = alloc_entity_param(c->allocator, nullptr, blank_token, slice_elem, false, false); - Type *proc_type = alloc_type_proc(nullptr, proc_type_params, 2, nullptr, false, true, ProcCC_Odin); - - check_call_arguments(c, &prev_operand, proc_type, call); - - if (prev_operand.mode == Addressing_Invalid) { - return false; - } - operand->mode = Addressing_Value; - operand->type = t_int; - - break; - } - #endif - #if 0 - case BuiltinProc_delete: { - // delete :: proc(map[Key]Value, key: Key) - Type *type = operand->type; - if (!is_type_map(type)) { - gbString str = type_to_string(type); - error(operand->expr, "Expected a map, got '%s'", str); - gb_string_free(str); - return false; - } - - Type *key = base_type(type)->Map.key; - Operand x = {Addressing_Invalid}; - Ast *key_node = ce->args[1]; - Operand op = {}; - check_expr(c, &op, key_node); - if (op.mode == Addressing_Invalid) { - return false; - } - - if (!check_is_assignable_to(c, &op, key)) { - gbString kt = type_to_string(key); - gbString ot = type_to_string(op.type); - error(operand->expr, "Expected a key of type '%s', got '%s'", key, ot); - gb_string_free(ot); - gb_string_free(kt); - return false; - } - - operand->mode = Addressing_NoValue; - - break; - } - #endif - - case BuiltinProc_size_of: { // size_of :: proc(Type or expr) -> untyped int Operand o = {}; @@ -3604,72 +3314,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return false; } - -break; - } - - #if 0 - case BuiltinProc_slice_ptr: { - // slice_ptr :: proc(a: ^T, len: int) -> []T - // proc slice_ptr(a: ^T, len, cap: int) -> []T - // ^T cannot be rawptr - Type *ptr_type = base_type(operand->type); - if (!is_type_pointer(ptr_type)) { - gbString type_str = type_to_string(operand->type); - error(call, "Expected a pointer to 'slice_ptr', got '%s'", type_str); - gb_string_free(type_str); - return false; - } - - if (ptr_type == t_rawptr) { - error(call, "'rawptr' cannot have pointer arithmetic"); - return false; - } - - isize arg_count = ce->args.count; - if (arg_count < 2 || 3 < arg_count) { - error(ce->args[0], "'slice_ptr' expects 2 or 3 arguments, found %td", arg_count); - // NOTE(bill): Return the correct type to reduce errors - } else { - // If any are constant - i64 sizes[2] = {}; - isize size_count = 0; - for (isize i = 1; i < arg_count; i++) { - i64 val = 0; - bool ok = check_index_value(c, false, ce->args[i], -1, &val); - if (ok && val >= 0) { - GB_ASSERT(size_count < gb_count_of(sizes)); - sizes[size_count++] = val; - } - } - - if (size_count == 2 && sizes[0] > sizes[1]) { - error(ce->args[1], "'slice_ptr' count and capacity are swapped"); - // No need quit - } - } - operand->type = alloc_type_slice(ptr_type->Pointer.elem); - operand->mode = Addressing_Value; - break; } - case BuiltinProc_slice_to_bytes: { - // slice_to_bytes :: proc(a: []T) -> []u8 - Type *slice_type = base_type(operand->type); - if (!is_type_slice(slice_type)) { - gbString type_str = type_to_string(operand->type); - error(call, "Expected a slice type, got '%s'", type_str); - gb_string_free(type_str); - return false; - } - - operand->type = t_u8_slice; - operand->mode = Addressing_Value; - - break; - } - #endif case BuiltinProc_expand_to_tuple: { Type *type = base_type(operand->type); if (!is_type_struct(type) && !is_type_array(type)) { @@ -3773,7 +3420,7 @@ break; } -break; + break; } case BuiltinProc_max: { @@ -3849,7 +3496,7 @@ break; } -break; + break; } case BuiltinProc_abs: { @@ -4002,59 +3649,6 @@ break; break; } - #if 0 - case BuiltinProc_transmute: { - Operand op = {}; - check_expr_or_type(c, &op, ce->args[0]); - Type *t = op.type; - if ((op.mode != Addressing_Type && t == nullptr) || t == t_invalid) { - error(ce->args[0], "Expected a type for 'transmute'"); - return false; - } - Ast *expr = ce->args[1]; - Operand *o = operand; - check_expr(c, o, expr); - if (o->mode == Addressing_Invalid) { - return false; - } - - if (o->mode == Addressing_Constant) { - gbString expr_str = expr_to_string(o->expr); - error(o->expr, "Cannot transmute a constant expression: '%s'", expr_str); - gb_string_free(expr_str); - o->mode = Addressing_Invalid; - o->expr = expr; - return false; - } - - if (is_type_untyped(o->type)) { - gbString expr_str = expr_to_string(o->expr); - error(o->expr, "Cannot transmute untyped expression: '%s'", expr_str); - gb_string_free(expr_str); - o->mode = Addressing_Invalid; - o->expr = expr; - return false; - } - - i64 srcz = type_size_of(o->type); - i64 dstz = type_size_of(t); - if (srcz != dstz) { - gbString expr_str = expr_to_string(o->expr); - gbString type_str = type_to_string(t); - error(o->expr, "Cannot transmute '%s' to '%s', %lld vs %lld bytes", expr_str, type_str, srcz, dstz); - gb_string_free(type_str); - gb_string_free(expr_str); - o->mode = Addressing_Invalid; - o->expr = expr; - return false; - } - - o->mode = Addressing_Value; - o->type = t; - - break; - } - #endif } return true; @@ -4246,6 +3840,8 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { gen_entity = poly_proc_data.gen_entity; GB_ASSERT(is_type_proc(gen_entity->type)); final_proc_type = gen_entity->type; + } else { + err = CallArgumentError_WrongTypes; } } @@ -4614,44 +4210,54 @@ CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type if (valid_count == 0) { - error(operand->expr, "No procedures or ambiguous call for procedure group '%s' that match with the given arguments", expr_name); - gb_printf_err("\tGiven argument types: ("); + bool all_invalid_type = true; for_array(i, operands) { Operand o = operands[i]; - if (i > 0) gb_printf_err(", "); - gbString type = type_to_string(o.type); - defer (gb_string_free(type)); - gb_printf_err("%s", type); - } - gb_printf_err(")\n"); - - if (procs.count > 0) { - gb_printf_err("Did you mean to use one of the following:\n"); - } - for_array(i, procs) { - Entity *proc = procs[i]; - TokenPos pos = proc->token.pos; - Type *t = base_type(proc->type); - if (t == t_invalid) continue; - GB_ASSERT(t->kind == Type_Proc); - gbString pt; - defer (gb_string_free(pt)); - if (t->Proc.node != nullptr) { - pt = expr_to_string(t->Proc.node); - } else { - pt = type_to_string(t); + if (o.type != t_invalid) { + all_invalid_type = false; + break; } - String name = proc->token.string; - - char const *sep = "::"; - if (proc->kind == Entity_Variable) { - sep = ":="; - } - // gb_printf_err("\t%.*s %s %s at %.*s(%td:%td) with score %lld\n", LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column, cast(long long)valids[i].score); - gb_printf_err("\t%.*s %s %s at %.*s(%td:%td)\n", LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column); } - if (procs.count > 0) { - gb_printf_err("\n"); + if (!all_invalid_type) { + error(operand->expr, "No procedures or ambiguous call for procedure group '%s' that match with the given arguments", expr_name); + gb_printf_err("\tGiven argument types: ("); + for_array(i, operands) { + Operand o = operands[i]; + if (i > 0) gb_printf_err(", "); + gbString type = type_to_string(o.type); + defer (gb_string_free(type)); + gb_printf_err("%s", type); + } + gb_printf_err(")\n"); + + if (procs.count > 0) { + gb_printf_err("Did you mean to use one of the following:\n"); + } + for_array(i, procs) { + Entity *proc = procs[i]; + TokenPos pos = proc->token.pos; + Type *t = base_type(proc->type); + if (t == t_invalid) continue; + GB_ASSERT(t->kind == Type_Proc); + gbString pt; + defer (gb_string_free(pt)); + if (t->Proc.node != nullptr) { + pt = expr_to_string(t->Proc.node); + } else { + pt = type_to_string(t); + } + String name = proc->token.string; + + char const *sep = "::"; + if (proc->kind == Entity_Variable) { + sep = ":="; + } + // gb_printf_err("\t%.*s %s %s at %.*s(%td:%td) with score %lld\n", LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column, cast(long long)valids[i].score); + gb_printf_err("\t%.*s %s %s at %.*s(%td:%td)\n", LIT(name), sep, pt, LIT(pos.file), pos.line, pos.column); + } + if (procs.count > 0) { + gb_printf_err("\n"); + } } result_type = t_invalid; } else if (valid_count > 1) { diff --git a/src/checker.hpp b/src/checker.hpp index 310a99542..7f1960bfb 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -58,15 +58,6 @@ enum BuiltinProcId { BuiltinProc_len, BuiltinProc_cap, - // BuiltinProc_new, - BuiltinProc_make, - // BuiltinProc_free, - - // BuiltinProc_reserve, - // BuiltinProc_clear, - // BuiltinProc_append, - // BuiltinProc_delete, - BuiltinProc_size_of, BuiltinProc_align_of, BuiltinProc_offset_of, @@ -81,9 +72,6 @@ enum BuiltinProcId { BuiltinProc_imag, BuiltinProc_conj, - // BuiltinProc_slice_ptr, - // BuiltinProc_slice_to_bytes, - BuiltinProc_expand_to_tuple, BuiltinProc_min, @@ -101,15 +89,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("len"), 1, false, Expr_Expr}, {STR_LIT("cap"), 1, false, Expr_Expr}, - // {STR_LIT("new"), 1, false, Expr_Expr}, - {STR_LIT("make"), 1, true, Expr_Expr}, - // {STR_LIT("free"), 1, false, Expr_Stmt}, - - // {STR_LIT("reserve"), 2, false, Expr_Stmt}, - // {STR_LIT("clear"), 1, false, Expr_Stmt}, - // {STR_LIT("append"), 1, true, Expr_Expr}, - // {STR_LIT("delete"), 2, false, Expr_Stmt}, - {STR_LIT("size_of"), 1, false, Expr_Expr}, {STR_LIT("align_of"), 1, false, Expr_Expr}, {STR_LIT("offset_of"), 2, false, Expr_Expr}, @@ -124,9 +103,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("imag"), 1, false, Expr_Expr}, {STR_LIT("conj"), 1, false, Expr_Expr}, - // {STR_LIT("slice_ptr"), 2, true, Expr_Expr}, - // {STR_LIT("slice_to_bytes"), 1, false, Expr_Expr}, - {STR_LIT("expand_to_tuple"), 1, false, Expr_Expr}, {STR_LIT("min"), 2, false, Expr_Expr}, diff --git a/src/ir.cpp b/src/ir.cpp index d11812455..fc7b42f7d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4424,406 +4424,6 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu break; } - #if 0 - case BuiltinProc_new: { - ir_emit_comment(proc, str_lit("new")); - // proc new(Type) -> ^Type - gbAllocator a = ir_allocator(); - - Type *type = type_of_expr(ce->args[0]); - Type *allocation_type = type; - i32 variant_index = 0; - if (is_type_struct(type)) { - Type *st = base_type(type); - if (st->Struct.variant_parent != nullptr) { - allocation_type = st->Struct.variant_parent; - variant_index = st->Struct.variant_index; - GB_ASSERT(allocation_type != nullptr); - } - } - Type *ptr_type = alloc_type_pointer(type); - - i64 size = type_size_of(allocation_type); - i64 align = type_align_of(allocation_type); - - irValue **args = gb_alloc_array(a, irValue *, 2); - args[0] = ir_const_int(size); - args[1] = ir_const_int(align); - irValue *call = ir_emit_runtime_call(proc, "alloc", args, 2); - irValue *v = ir_emit_conv(proc, call, ptr_type); - if (type != allocation_type) { - Type *u = base_type(allocation_type); - Type *uptr_type = alloc_type_pointer(u); - irValue *parent = ir_emit_conv(proc, call, uptr_type); - irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent); - ir_emit_store(proc, tag_ptr, ir_const_int(variant_index)); - } - return v; - break; - } - #endif - - case BuiltinProc_make: { - ir_emit_comment(proc, str_lit("make")); - gbAllocator a = ir_allocator(); - Type *type = type_of_expr(ce->args[0]); - - String proc_name = {}; - if (proc->entity != nullptr) { - proc_name = proc->entity->token.string; - } - - if (is_type_slice(type)) { - Type *elem_type = core_type(type)->Slice.elem; - Type *elem_ptr_type = alloc_type_pointer(elem_type); - - i64 esz = type_size_of(elem_type); - i64 eal = type_align_of(elem_type); - - irValue *elem_size = ir_const_int(esz); - irValue *elem_align = ir_const_int(eal); - - irValue *len = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int); - - ir_emit_slice_bounds_check(proc, ast_token(ce->args[1]), v_zero, len, len, false); - - irValue *slice_size = len; - if (esz != 1) { - slice_size = ir_emit_arith(proc, Token_Mul, elem_size, len, t_int); - } - - TokenPos pos = ast_token(ce->args[0]).pos; - - auto args = array_make(ir_allocator(), 3); - args[0] = slice_size; - args[1] = elem_align; - args[2] = ir_emit_source_code_location(proc, proc_name, pos); - irValue *call = ir_emit_package_call(proc, "mem", "alloc", args); - - irValue *ptr = ir_emit_conv(proc, call, elem_ptr_type); - irValue *slice = ir_add_local_generated(proc, type); - ir_fill_slice(proc, slice, ptr, len); - return ir_emit_load(proc, slice); - } else if (is_type_map(type)) { - irValue *int_16 = ir_const_int(16); - irValue *cap = int_16; - if (ce->args.count == 2) { - cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int); - } - - irValue *cond = ir_emit_comp(proc, Token_Gt, cap, v_zero); - cap = ir_emit_select(proc, cond, cap, int_16); - - irValue *map = ir_add_local_generated(proc, type); - irValue *header = ir_gen_map_header(proc, map, base_type(type)); - - auto args = array_make(ir_allocator(), 3); - args[0] = header; - args[1] = cap; - args[2] = ir_emit_source_code_location(proc, ce->args[0]); - ir_emit_runtime_call(proc, "__dynamic_map_reserve", args); - - return ir_emit_load(proc, map); - } else if (is_type_dynamic_array(type)) { - Type *elem_type = base_type(type)->DynamicArray.elem; - irValue *len = v_zero; - if (ce->args.count > 1) { - len = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int); - } - irValue *cap = len; - if (ce->args.count > 2) { - cap = ir_emit_conv(proc, ir_build_expr(proc, ce->args[2]), t_int); - } - - ir_emit_dynamic_array_bounds_check(proc, ast_token(ce->args[0]), v_zero, len, cap); - - irValue *array = ir_add_local_generated(proc, type); - - auto args = array_make(ir_allocator(), 6); - args[0] = ir_emit_conv(proc, array, t_rawptr); - args[1] = ir_const_int(type_size_of(elem_type)); - args[2] = ir_const_int(type_align_of(elem_type)); - args[3] = len; - args[4] = cap; - args[5] = ir_emit_source_code_location(proc, ce->args[0]); - ir_emit_runtime_call(proc, "__dynamic_array_make", args); - return ir_emit_load(proc, array); - } - break; - } - - #if 0 - case BuiltinProc_free: { - ir_emit_comment(proc, str_lit("free")); - - gbAllocator a = ir_allocator(); - - Ast *node = ce->args[0]; - TypeAndValue tav = type_and_value_of_expr(node); - Type *type = base_type(tav.type); - - if (is_type_dynamic_array(type)) { - irValue *val = ir_build_expr(proc, node); - irValue *da_allocator = ir_emit_struct_ev(proc, val, 3); - - irValue *ptr = ir_emit_struct_ev(proc, val, 0); - ptr = ir_emit_conv(proc, ptr, t_rawptr); - - irValue **args = gb_alloc_array(a, irValue *, 1); - args[0] = da_allocator; - args[1] = ptr; - return ir_emit_runtime_call(proc, "free_ptr_with_allocator", args, 2); - } else if (is_type_map(type)) { - irValue *map = ir_build_expr(proc, node); - irValue *map_ptr = ir_address_from_load_or_generate_local(proc, map); - - { - irValue *array = ir_emit_struct_ep(proc, map_ptr, 0); - - irValue *da_allocator = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 3)); - irValue *da_ptr = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 0)); - da_ptr = ir_emit_conv(proc, da_ptr, t_rawptr); - - irValue **args = gb_alloc_array(a, irValue *, 1); - args[0] = da_allocator; - args[1] = da_ptr; - ir_emit_runtime_call(proc, "free_ptr_with_allocator", args, 2); - } - { - irValue *array = ir_emit_struct_ep(proc, map_ptr, 1); - - irValue *da_allocator = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 3)); - irValue *da_ptr = ir_emit_load(proc, ir_emit_struct_ep(proc, array, 0)); - da_ptr = ir_emit_conv(proc, da_ptr, t_rawptr); - - irValue **args = gb_alloc_array(a, irValue *, 1); - args[0] = da_allocator; - args[1] = da_ptr; - ir_emit_runtime_call(proc, "free_ptr_with_allocator", args, 2); - } - return nullptr; - } - - irValue *val = ir_build_expr(proc, node); - irValue *ptr = nullptr; - if (is_type_pointer(type)) { - ptr = val; - } else if (is_type_slice(type)) { - ptr = ir_slice_elem(proc, val); - } else if (is_type_string(type)) { - ptr = ir_string_elem(proc, val); - } else { - GB_PANIC("Invalid type to 'free'"); - } - - if (ptr == nullptr) { - return nullptr; - } - - ptr = ir_emit_conv(proc, ptr, t_rawptr); - - irValue **args = gb_alloc_array(a, irValue *, 1); - args[0] = ptr; - return ir_emit_runtime_call(proc, "free_ptr", args, 1); - break; - } - #endif - #if 0 - case BuiltinProc_reserve: { - ir_emit_comment(proc, str_lit("reserve")); - gbAllocator a = ir_allocator(); - - irValue *ptr = ir_build_addr_ptr(proc, ce->args[0]); - Type *type = ir_type(ptr); - GB_ASSERT(is_type_pointer(type)); - type = base_type(type_deref(type)); - - irValue *capacity = ir_emit_conv(proc, ir_build_expr(proc, ce->args[1]), t_int); - - if (is_type_dynamic_array(type)) { - Type *elem = type->DynamicArray.elem; - - irValue *elem_size = ir_const_int(type_size_of(elem)); - irValue *elem_align = ir_const_int(type_align_of(elem)); - - ptr = ir_emit_conv(proc, ptr, t_rawptr); - - irValue **args = gb_alloc_array(a, irValue *, 4); - args[0] = ptr; - args[1] = elem_size; - args[2] = elem_align; - args[3] = capacity; - return ir_emit_runtime_call(proc, "__dynamic_array_reserve", args, 4); - } else if (is_type_map(type)) { - irValue **args = gb_alloc_array(a, irValue *, 2); - args[0] = ir_gen_map_header(proc, ptr, type); - args[1] = capacity; - return ir_emit_runtime_call(proc, "__dynamic_map_reserve", args, 2); - } else { - GB_PANIC("Unknown type for 'reserve'"); - } - break; - } - #endif - #if 0 - case BuiltinProc_clear: { - ir_emit_comment(proc, str_lit("clear")); - Type *original_type = type_of_expr(ce->args[0]); - irAddr const &addr = ir_build_addr(proc, ce->args[0]); - irValue *ptr = addr.addr; - if (is_double_pointer(ir_type(ptr))) { - ptr = ir_addr_load(proc, addr); - } - Type *t = base_type(type_deref(original_type)); - if (is_type_dynamic_array(t)) { - irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1); - ir_emit_store(proc, count_ptr, v_zero); - } else if (is_type_map(t)) { - irValue *ha = ir_emit_struct_ep(proc, ptr, 0); - irValue *ea = ir_emit_struct_ep(proc, ptr, 1); - ir_emit_store(proc, ir_emit_struct_ep(proc, ha, 1), v_zero); - ir_emit_store(proc, ir_emit_struct_ep(proc, ea, 1), v_zero); - } else if (is_type_slice(t)) { - irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1); - ir_emit_store(proc, count_ptr, v_zero); - } else { - GB_PANIC("TODO(bill): ir clear for '%s'", type_to_string(t)); - } - return nullptr; - break; - } - #endif - #if 0 - case BuiltinProc_append: { - ir_emit_comment(proc, str_lit("append")); - gbAllocator a = ir_allocator(); - - Type *value_type = type_of_expr(ce->args[0]); - irAddr array_addr = ir_build_addr(proc, ce->args[0]); - irValue *array_ptr = array_addr.addr; - if (is_double_pointer(ir_type(array_ptr))) { - array_ptr = ir_addr_load(proc, array_addr); - } - Type *type = ir_type(array_ptr); - { - TokenPos pos = ast_token(ce->args[0]).pos; - GB_ASSERT_MSG(is_type_pointer(type), "%.*s(%td) %s", - LIT(pos.file), pos.line, - type_to_string(type)); - } - type = base_type(type_deref(type)); - Type *elem_type = nullptr; - bool is_slice = false; - if (is_type_dynamic_array(type)) { - elem_type = type->DynamicArray.elem; - } else if (is_type_slice(type)) { - is_slice = true; - elem_type = type->Slice.elem; - } else { - GB_PANIC("Invalid type to append"); - } - - irValue *elem_size = ir_const_int(type_size_of(elem_type)); - irValue *elem_align = ir_const_int(type_align_of(elem_type)); - - array_ptr = ir_emit_conv(proc, array_ptr, t_rawptr); - - isize arg_index = 0; - isize arg_count = 0; - for_array(i, ce->args) { - Ast *a = ce->args[i]; - Type *at = base_type(type_of_expr(a)); - if (at->kind == Type_Tuple) { - arg_count += at->Tuple.variable_count; - } else { - arg_count++; - } - } - - irValue **args = gb_alloc_array(ir_allocator(), irValue *, arg_count); - bool vari_expand = ce->ellipsis.pos.line != 0; - - for_array(i, ce->args) { - irValue *a = ir_build_expr(proc, ce->args[i]); - Type *at = ir_type(a); - if (at->kind == Type_Tuple) { - for (isize i = 0; i < at->Tuple.variable_count; i++) { - Entity *e = at->Tuple.variables[i]; - irValue *v = ir_emit_struct_ev(proc, a, i); - args[arg_index++] = v; - } - } else { - args[arg_index++] = a; - } - } - - if (!vari_expand) { - for (isize i = 1; i < arg_count; i++) { - args[i] = ir_emit_conv(proc, args[i], elem_type); - } - } - - if (!vari_expand) { - ir_emit_comment(proc, str_lit("variadic call argument generation")); - Type *slice_type = alloc_type_slice(elem_type); - irValue *slice = ir_add_local_generated(proc, slice_type); - isize slice_len = arg_count-1; - - if (slice_len > 0) { - irValue *base_array = ir_add_local_generated(proc, alloc_type_array(elem_type, slice_len)); - - for (isize i = 1; i < arg_count; i++) { - irValue *addr = ir_emit_array_epi(proc, base_array, i-1); - ir_emit_store(proc, addr, args[i]); - } - - irValue *base_elem = ir_emit_array_epi(proc, base_array, 0); - irValue *len = ir_const_int(slice_len); - ir_fill_slice(proc, slice, base_elem, len, len); - } - - arg_count = 2; - args[arg_count-1] = ir_emit_load(proc, slice); - } - - irValue *item_slice = args[1]; - irValue *items = ir_slice_elem(proc, item_slice); - irValue *item_count = ir_slice_len(proc, item_slice); - - irValue **daa_args = gb_alloc_array(a, irValue *, 5); - daa_args[0] = array_ptr; - daa_args[1] = elem_size; - daa_args[2] = elem_align; - daa_args[3] = ir_emit_conv(proc, items, t_rawptr); - daa_args[4] = ir_emit_conv(proc, item_count, t_int); - - if (is_slice) { - return ir_emit_runtime_call(proc, "__slice_append", daa_args, 5); - } - return ir_emit_runtime_call(proc, "__dynamic_array_append", daa_args, 5); - break; - } - #endif - #if 0 - case BuiltinProc_delete: { - ir_emit_comment(proc, str_lit("delete")); - irValue *map = ir_build_expr(proc, ce->args[0]); - irValue *key = ir_build_expr(proc, ce->args[1]); - Type *map_type = ir_type(map); - GB_ASSERT(is_type_map(map_type)); - Type *key_type = base_type(map_type)->Map.key; - - irValue *addr = ir_address_from_load_or_generate_local(proc, map); - - gbAllocator a = ir_allocator(); - irValue **args = gb_alloc_array(a, irValue *, 2); - args[0] = ir_gen_map_header(proc, addr, map_type); - args[1] = ir_gen_map_key(proc, key, key_type); - return ir_emit_runtime_call(proc, "__dynamic_map_delete", args, 2); - break; - } - #endif - case BuiltinProc_swizzle: { ir_emit_comment(proc, str_lit("swizzle.begin")); irAddr const &addr = ir_build_addr(proc, ce->args[0]);