From 0eba4b46b5e554f1df01b63084ac4e78abfe3117 Mon Sep 17 00:00:00 2001 From: F0x1fy Date: Tue, 10 Nov 2020 10:16:22 -0700 Subject: Made sure the entry point is not generated when -no-entry-point is specified. --- src/ir.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 2b3bd35df..dc77906e8 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12646,7 +12646,7 @@ void ir_gen_tree(irGen *s) { #if defined(GB_SYSTEM_WINDOWS) - if (build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main) { + if (build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main && !build_context.no_entry_point) { // DllMain :: proc(inst: rawptr, reason: u32, reserved: rawptr) -> i32 String name = str_lit("DllMain"); Type *proc_params = alloc_type_tuple(); @@ -12717,7 +12717,7 @@ void ir_gen_tree(irGen *s) { ir_emit_return(proc, v_one32); } #endif - if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main)) { + if (!(build_context.build_mode == BuildMode_DynamicLibrary && !has_dll_main) && !build_context.no_entry_point) { // main :: proc(argc: i32, argv: ^^u8) -> i32 String name = str_lit("main"); @@ -12796,7 +12796,7 @@ void ir_gen_tree(irGen *s) { } #if defined(GB_SYSTEM_WINDOWS) - if (build_context.build_mode != BuildMode_DynamicLibrary && build_context.no_crt) { + if (build_context.build_mode != BuildMode_DynamicLibrary && build_context.no_crt && !build_context.no_entry_point) { s->print_chkstk = true; { -- cgit v1.2.3 From 30d922b05938ccde7e49f027e2e65ca28849b218 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Nov 2020 18:11:49 +0000 Subject: Make `set_procedure_abi_types` use the permanent_allocator --- src/check_expr.cpp | 4 ++-- src/check_type.cpp | 10 ++++++---- src/ir.cpp | 20 ++++++++++---------- src/ir_print.cpp | 8 ++++---- src/llvm_backend.cpp | 16 ++++++++-------- 5 files changed, 30 insertions(+), 28 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index a8e7550a1..cf4304053 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -89,7 +89,7 @@ Type * check_init_variable (CheckerContext *c, Entity *e, Operand * Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc); Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCallingConvention cc); bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type); -void set_procedure_abi_types(gbAllocator a, Type *type); +void set_procedure_abi_types(Type *type); void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type); @@ -1012,7 +1012,7 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source, } if (modify_type) { - set_procedure_abi_types(c->allocator, source); + set_procedure_abi_types(source); } return true; diff --git a/src/check_type.cpp b/src/check_type.cpp index ace1ef898..6c9e82aa1 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1390,7 +1390,7 @@ Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Oper if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) { if (show_error) { - set_procedure_abi_types(ctx->allocator, poly_type); + set_procedure_abi_types(poly_type); } return poly_type; } @@ -2508,7 +2508,7 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type return false; } -void set_procedure_abi_types(gbAllocator allocator, Type *type) { +void set_procedure_abi_types(Type *type) { type = base_type(type); if (type->kind != Type_Proc) { return; @@ -2518,6 +2518,8 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) { return; } + gbAllocator allocator = permanent_allocator(); + u32 flags = type->flags; type->flags |= TypeFlag_InProcessOfCheckingABI; @@ -2550,13 +2552,13 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) { for (i32 i = 0; i < type->Proc.param_count; i++) { Entity *e = type->Proc.params->Tuple.variables[i]; if (e->kind == Entity_Variable) { - set_procedure_abi_types(allocator, e->type); + set_procedure_abi_types(e->type); } } for (i32 i = 0; i < type->Proc.result_count; i++) { Entity *e = type->Proc.results->Tuple.variables[i]; if (e->kind == Entity_Variable) { - set_procedure_abi_types(allocator, e->type); + set_procedure_abi_types(e->type); } } diff --git a/src/ir.cpp b/src/ir.cpp index dc77906e8..ee177edd6 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1159,7 +1159,7 @@ irValue *ir_instr_atomic_cxchg(irProcedure *p, Type *type, irValue *address, irV GB_ASSERT(type->Tuple.variables.count == 2); Type *elem = type->Tuple.variables[0]->type; // LEAK TODO(bill): LLVM returns {T, i1} whilst Odin does {T, bool}, fix this mapping hack - gbAllocator a = heap_allocator(); + gbAllocator a = permanent_allocator(); Type *llvm_type = alloc_type_tuple(); array_init(&llvm_type->Tuple.variables, a, 0, 2); array_add (&llvm_type->Tuple.variables, alloc_entity_field(nullptr, blank_token, elem, false, 0)); @@ -1799,7 +1799,7 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, Ast *expr, bool zero_initial if (zero_initialized) { ir_emit_zero_init(proc, instr, expr); } - set_procedure_abi_types(heap_allocator(), e->type); + set_procedure_abi_types(e->type); // if (proc->module->generate_debug_info && expr != nullptr && proc->entity != nullptr) { // if (proc->module->generate_debug_info && proc->entity != nullptr) { @@ -3282,7 +3282,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &ar context_ptr = ir_find_or_generate_context_ptr(p); } - set_procedure_abi_types(heap_allocator(), pt); + set_procedure_abi_types(pt); bool is_c_vararg = pt->Proc.c_vararg; isize param_count = pt->Proc.param_count; @@ -6636,7 +6636,7 @@ void ir_mangle_add_sub_type_name(irModule *m, Entity *field, String parent) { return; } if (is_type_proc(field->type)) { - set_procedure_abi_types(heap_allocator(), field->type); + set_procedure_abi_types(field->type); } String cn = field->token.string; @@ -6733,7 +6733,7 @@ irValue *ir_gen_anonymous_proc_lit(irModule *m, String prefix_name, Ast *expr, i String name = make_string(name_text, name_len-1); Type *type = type_of_expr(expr); - set_procedure_abi_types(heap_allocator(), type); + set_procedure_abi_types(type); irValue *value = ir_value_procedure(m, nullptr, type, pl->type, pl->body, name); value->Proc.tags = pl->tags; @@ -7584,7 +7584,7 @@ irValue *ir_build_call_expr(irProcedure *proc, Ast *expr) { Type *proc_type_ = base_type(ir_type(value)); GB_ASSERT(proc_type_->kind == Type_Proc); TypeProc *pt = &proc_type_->Proc; - set_procedure_abi_types(heap_allocator(), proc_type_); + set_procedure_abi_types(proc_type_); if (is_call_expr_field_value(ce)) { auto args = array_make(ir_allocator(), pt->param_count); @@ -9574,7 +9574,7 @@ void ir_build_nested_proc(irProcedure *proc, AstProcLit *pd, Entity *e) { name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(pd_name), guid); String name = make_string(name_text, name_len-1); - set_procedure_abi_types(heap_allocator(), e->type); + set_procedure_abi_types(e->type); irValue *value = ir_value_procedure(proc->module, e, e->type, pd->type, pd->body, name); value->Proc.tags = pd->tags; @@ -9673,7 +9673,7 @@ void ir_build_constant_value_decl(irProcedure *proc, AstValueDecl *vd) { return; } - set_procedure_abi_types(heap_allocator(), e->type); + set_procedure_abi_types(e->type); irValue *value = ir_value_procedure(proc->module, e, e->type, pl->type, pl->body, name); value->Proc.tags = pl->tags; @@ -11471,7 +11471,7 @@ void ir_insert_code_before_proc(irProcedure* proc, irProcedure *parent) { void ir_build_proc(irValue *value, irProcedure *parent) { irProcedure *proc = &value->Proc; - set_procedure_abi_types(heap_allocator(), proc->type); + set_procedure_abi_types(proc->type); proc->parent = parent; @@ -12612,7 +12612,7 @@ void ir_gen_tree(irGen *s) { Ast *type_expr = pl->type; - set_procedure_abi_types(heap_allocator(), e->type); + set_procedure_abi_types(e->type); irValue *p = ir_value_procedure(m, e, e->type, type_expr, body, name); p->Proc.tags = pl->tags; p->Proc.inlining = pl->inlining; diff --git a/src/ir_print.cpp b/src/ir_print.cpp index ceb95c5c3..2d15f176b 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -296,7 +296,7 @@ void ir_print_alignment_prefix_hack(irFileBuffer *f, i64 alignment) { void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) { - set_procedure_abi_types(heap_allocator(), t); + set_procedure_abi_types(t); GB_ASSERT(is_type_proc(t)); t = base_type(t); @@ -325,7 +325,7 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) { void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) { - set_procedure_abi_types(heap_allocator(), t); + set_procedure_abi_types(t); i64 word_bits = 8*build_context.word_size; t = base_type(t); @@ -2189,7 +2189,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { irInstrCall *call = &instr->Call; Type *proc_type = base_type(ir_type(call->value)); GB_ASSERT(is_type_proc(proc_type)); - set_procedure_abi_types(heap_allocator(), proc_type); + set_procedure_abi_types(proc_type); bool is_c_vararg = proc_type->Proc.c_vararg; Type *result_type = call->type; @@ -2396,7 +2396,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { - set_procedure_abi_types(heap_allocator(), proc->type); + set_procedure_abi_types(proc->type); if (proc->body == nullptr) { ir_write_str_lit(f, "declare "); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 43f4125ba..121917740 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1421,7 +1421,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { return lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg); } } else { - set_procedure_abi_types(heap_allocator(), type); + set_procedure_abi_types(type); LLVMTypeRef return_type = LLVMVoidTypeInContext(ctx); if (type->Proc.return_by_pointer) { // Void @@ -1950,7 +1950,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { case Type_Proc: { return nullptr; - // set_procedure_abi_types(heap_allocator(), type); + // set_procedure_abi_types(type); // LLVMTypeRef return_type = LLVMVoidTypeInContext(ctx); // isize offset = 0; @@ -2141,7 +2141,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { Type *pt = base_type(entity->type); GB_ASSERT(pt->kind == Type_Proc); - set_procedure_abi_types(permanent_allocator(), entity->type); + set_procedure_abi_types(entity->type); p->type = entity->type; p->type_expr = decl->type_expr; @@ -2978,7 +2978,7 @@ void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) { name_len = gb_snprintf(name_text, name_len, "%.*s.%.*s-%d", LIT(p->name), LIT(pd_name), guid); String name = make_string(cast(u8 *)name_text, name_len-1); - set_procedure_abi_types(permanent_allocator(), e->type); + set_procedure_abi_types(e->type); e->Procedure.link_name = name; @@ -3115,7 +3115,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) { return; } - set_procedure_abi_types(permanent_allocator(), e->type); + set_procedure_abi_types(e->type); e->Procedure.link_name = name; lbProcedure *nested_proc = lb_create_procedure(p->module, e); @@ -7376,7 +7376,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, LLVMBuildUnreachable(p->builder); }); - set_procedure_abi_types(permanent_allocator(), pt); + set_procedure_abi_types(pt); bool is_c_vararg = pt->Proc.c_vararg; isize param_count = pt->Proc.param_count; @@ -8595,7 +8595,7 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) { Type *proc_type_ = base_type(value.type); GB_ASSERT(proc_type_->kind == Type_Proc); TypeProc *pt = &proc_type_->Proc; - set_procedure_abi_types(permanent_allocator(), proc_type_); + set_procedure_abi_types(proc_type_); if (is_call_expr_field_value(ce)) { auto args = array_make(permanent_allocator(), pt->param_count); @@ -9442,7 +9442,7 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A String name = make_string((u8 *)name_text, name_len-1); Type *type = type_of_expr(expr); - set_procedure_abi_types(permanent_allocator(), type); + set_procedure_abi_types(type); Token token = {}; -- cgit v1.2.3 From 17ec3e72a68b805fc202174722778545c956f433 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 15 Nov 2020 18:45:40 +0000 Subject: Add SCOPED_TEMPORARY_BLOCK for temporary allocations within a block --- src/check_decl.cpp | 9 ++++----- src/check_expr.cpp | 53 ++++++++++++++++++++++++++-------------------------- src/check_stmt.cpp | 30 ++++++++++++++--------------- src/check_type.cpp | 45 +++++++++++++++++++++----------------------- src/checker.cpp | 35 ++++++++++++++++------------------ src/checker.hpp | 2 -- src/common.cpp | 35 +++++++++++++++++++++++++++++++++- src/gb/gb.h | 2 +- src/ir.cpp | 31 ++++++++++++++---------------- src/ir_print.cpp | 6 +++--- src/llvm_backend.cpp | 28 +++++++++++++++++++++++---- src/main.cpp | 1 + 12 files changed, 159 insertions(+), 118 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 1aafa6e1c..bfe703853 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -121,8 +121,8 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Ar // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be // an extra allocation - auto operands = array_make(ctx->allocator, 0, 2*lhs_count); - defer (array_free(&operands)); + SCOPED_TEMPORARY_BLOCK(); + auto operands = array_make(temporary_allocator(), 0, 2*lhs_count); check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true, false); isize rhs_count = operands.count; @@ -317,7 +317,6 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) break; default: error(e->token, "Only struct types can have custom atom operations"); - gb_free(heap_allocator(), ac.atom_op_table); break; } } @@ -638,7 +637,7 @@ String handle_link_name(CheckerContext *ctx, Token token, String link_name, Stri error(token, "'link_name' and 'link_prefix' cannot be used together"); } else { isize len = link_prefix.len + token.string.len; - u8 *name = gb_alloc_array(ctx->allocator, u8, len+1); + u8 *name = gb_alloc_array(permanent_allocator(), u8, len+1); gb_memmove(name, &link_prefix[0], link_prefix.len); gb_memmove(name+link_prefix.len, &token.string[0], token.string.len); name[len] = 0; @@ -975,7 +974,7 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, DeclInfo *d) ast_node(pg, ProcGroup, d->init_expr); - pge->entities = array_make(ctx->allocator, 0, pg->args.count); + pge->entities = array_make(permanent_allocator(), 0, pg->args.count); // NOTE(bill): This must be set here to prevent cycles in checking if someone // places the entity within itself diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cf4304053..755ceb634 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -267,7 +267,7 @@ bool find_or_generate_polymorphic_procedure(CheckerContext *c, Entity *base_enti CheckerContext nctx = *c; - Scope *scope = create_scope(base_entity->scope, a); + Scope *scope = create_scope(base_entity->scope); scope->flags |= ScopeFlag_Proc; nctx.scope = scope; nctx.allow_polymorphic_types = true; @@ -366,7 +366,7 @@ bool find_or_generate_polymorphic_procedure(CheckerContext *c, Entity *base_enti u64 tags = base_entity->Procedure.tags; Ast *ident = clone_ast(base_entity->identifier); Token token = ident->Ident.token; - DeclInfo *d = make_decl_info(nctx.allocator, scope, old_decl->parent); + DeclInfo *d = make_decl_info(scope, old_decl->parent); d->gen_proc_type = final_proc_type; d->type_expr = pl->type; d->proc_lit = proc_lit; @@ -1832,12 +1832,9 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) { } + SCOPED_TEMPORARY_BLOCK(); gbString err_str = nullptr; - defer (if (err_str != nullptr) { - gb_string_free(err_str); - }); - if (check_is_assignable_to(c, x, y->type) || check_is_assignable_to(c, y, x->type)) { Type *err_type = x->type; @@ -1867,8 +1864,8 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) { } gbString type_string = type_to_string(err_type); defer (gb_string_free(type_string)); - err_str = gb_string_make(c->allocator, - gb_bprintf("operator '%.*s' not defined for type '%s'", LIT(token_strings[op]), type_string)); + err_str = gb_string_make(temporary_allocator(), + gb_bprintf("operator '%.*s' not defined for type '%s'", LIT(token_strings[op]), type_string)); } } else { gbString xt, yt; @@ -1882,8 +1879,7 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) { } else { yt = type_to_string(y->type); } - err_str = gb_string_make(c->allocator, - gb_bprintf("mismatched types '%s' and '%s'", xt, yt)); + err_str = gb_string_make(temporary_allocator(), gb_bprintf("mismatched types '%s' and '%s'", xt, yt)); gb_string_free(yt); gb_string_free(xt); } @@ -2978,9 +2974,10 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { case Type_Union: if (!is_operand_nil(*operand) && !is_operand_undef(*operand)) { + SCOPED_TEMPORARY_BLOCK(); + isize count = t->Union.variants.count; - ValidIndexAndScore *valids = gb_alloc_array(c->allocator, ValidIndexAndScore, count); - defer (gb_free(c->allocator, valids)); + ValidIndexAndScore *valids = gb_alloc_array(temporary_allocator(), ValidIndexAndScore, count); isize valid_count = 0; isize first_success_index = -1; for_array(i, t->Union.variants) { @@ -4739,7 +4736,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 gb_string_free(type_str); return false; } - gbAllocator a = c->allocator; + gbAllocator a = permanent_allocator(); Type *tuple = alloc_type_tuple(); @@ -5356,7 +5353,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 soa_struct->Struct.soa_elem = elem; soa_struct->Struct.soa_count = count; - scope = create_scope(c->scope, c->allocator); + scope = create_scope(c->scope); soa_struct->Struct.scope = scope; String params_xyzw[4] = { @@ -5389,7 +5386,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 soa_struct->Struct.soa_elem = elem; soa_struct->Struct.soa_count = count; - scope = create_scope(old_struct->Struct.scope->parent, c->allocator); + scope = create_scope(old_struct->Struct.scope->parent); soa_struct->Struct.scope = scope; for_array(i, old_struct->Struct.fields) { @@ -6539,11 +6536,11 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { bool show_error = show_error_mode == CallArgumentMode_ShowErrors; CallArgumentError err = CallArgumentError_None; + SCOPED_TEMPORARY_BLOCK(); + isize param_count = pt->param_count; - bool *visited = gb_alloc_array(c->allocator, bool, param_count); - defer (gb_free(c->allocator, visited)); - auto ordered_operands = array_make(c->allocator, param_count); - defer (array_free(&ordered_operands)); + bool *visited = gb_alloc_array(temporary_allocator(), bool, param_count); + auto ordered_operands = array_make(temporary_allocator(), param_count); defer ({ for_array(i, ordered_operands) { Operand const &o = ordered_operands[i]; @@ -7385,13 +7382,15 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper Array ordered_operands = operands; if (!named_fields) { - ordered_operands = array_make(c->allocator, param_count); + ordered_operands = array_make(permanent_allocator(), param_count); array_copy(&ordered_operands, operands, 0); } else { - bool *visited = gb_alloc_array(c->allocator, bool, param_count); + SCOPED_TEMPORARY_BLOCK(); + + bool *visited = gb_alloc_array(temporary_allocator(), bool, param_count); // LEAK(bill) - ordered_operands = array_make(c->allocator, param_count); + ordered_operands = array_make(permanent_allocator(), param_count); for_array(i, ce->args) { Ast *arg = ce->args[i]; @@ -7549,8 +7548,6 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper } { - gbAllocator a = c->allocator; - bool failure = false; Entity *found_entity = find_polymorphic_record_entity(c, original_type, param_count, ordered_operands, &failure); if (found_entity) { @@ -8213,7 +8210,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type Type *type = alloc_type(Type_Proc); check_open_scope(&ctx, pl->type); { - decl = make_decl_info(ctx.allocator, ctx.scope, ctx.decl); + decl = make_decl_info(ctx.scope, ctx.decl); decl->proc_lit = node; ctx.decl = decl; defer (ctx.decl = ctx.decl->parent); @@ -8510,7 +8507,9 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } if (cl->elems[0]->kind == Ast_FieldValue) { - bool *fields_visited = gb_alloc_array(c->allocator, bool, field_count); + SCOPED_TEMPORARY_BLOCK(); + + bool *fields_visited = gb_alloc_array(temporary_allocator(), bool, field_count); for_array(i, cl->elems) { Ast *elem = cl->elems[i]; @@ -10092,7 +10091,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type error(x.expr, "Expected a constant string for the inline asm constraints parameter"); } - Scope *scope = create_scope(c->scope, heap_allocator()); + Scope *scope = create_scope(c->scope); scope->flags |= ScopeFlag_Proc; Type *params = alloc_type_tuple(); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index e6902f6a3..d722ea8ee 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -640,9 +640,10 @@ void add_constant_switch_case(CheckerContext *ctx, Map *seen, Oper HashKey key = hash_exact_value(operand.value); TypeAndToken *found = map_get(seen, key); if (found != nullptr) { + SCOPED_TEMPORARY_BLOCK(); + isize count = multi_map_count(seen, key); - TypeAndToken *taps = gb_alloc_array(ctx->allocator, TypeAndToken, count); - defer (gb_free(ctx->allocator, taps)); + TypeAndToken *taps = gb_alloc_array(temporary_allocator(), TypeAndToken, count); multi_map_get_all(seen, key, taps); for (isize i = 0; i < count; i++) { @@ -859,7 +860,7 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { token.pos = ast_token(ss->body).pos; token.string = str_lit("true"); - x.expr = gb_alloc_item(ctx->allocator, Ast); + x.expr = gb_alloc_item(permanent_allocator(), Ast); x.expr->kind = Ast_Ident; x.expr->Ident.token = token; } @@ -1025,8 +1026,8 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { GB_ASSERT(is_type_enum(et)); auto fields = et->Enum.fields; - auto unhandled = array_make(ctx->allocator, 0, fields.count); - defer (array_free(&unhandled)); + SCOPED_TEMPORARY_BLOCK(); + auto unhandled = array_make(temporary_allocator(), 0, fields.count); for_array(i, fields) { Entity *f = fields[i]; @@ -1265,8 +1266,8 @@ void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { GB_ASSERT(is_type_union(ut)); auto variants = ut->Union.variants; - auto unhandled = array_make(ctx->allocator, 0, variants.count); - defer (array_free(&unhandled)); + SCOPED_TEMPORARY_BLOCK(); + auto unhandled = array_make(temporary_allocator(), 0, variants.count); for_array(i, variants) { Type *t = variants[i]; @@ -1433,12 +1434,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { return; } + SCOPED_TEMPORARY_BLOCK(); + // NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be // an extra allocation - auto lhs_operands = array_make(ctx->allocator, lhs_count); - auto rhs_operands = array_make(ctx->allocator, 0, 2*lhs_count); - defer (array_free(&lhs_operands)); - defer (array_free(&rhs_operands)); + auto lhs_operands = array_make(temporary_allocator(), lhs_count); + auto rhs_operands = array_make(temporary_allocator(), 0, 2*lhs_count); for_array(i, as->lhs) { if (is_blank_ident(as->lhs[i])) { @@ -1462,8 +1463,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { } } - auto lhs_to_ignore = array_make(ctx->allocator, lhs_count); - defer (array_free(&lhs_to_ignore)); + auto lhs_to_ignore = array_make(temporary_allocator(), lhs_count); isize max = gb_min(lhs_count, rhs_count); // NOTE(bill, 2020-05-02): This is an utter hack to get these custom atom operations working @@ -1878,7 +1878,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { DeclInfo *d = decl_info_of_entity(e); GB_ASSERT(d == nullptr); add_entity(ctx->checker, ctx->scope, e->identifier, e); - d = make_decl_info(ctx->allocator, ctx->scope, ctx->decl); + d = make_decl_info(ctx->scope, ctx->decl); add_entity_and_decl_info(ctx, e->identifier, e, d); } @@ -2036,7 +2036,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { case_ast_node(vd, ValueDecl, node); if (vd->is_mutable) { - Entity **entities = gb_alloc_array(ctx->allocator, Entity *, vd->names.count); + Entity **entities = gb_alloc_array(permanent_allocator(), Entity *, vd->names.count); isize entity_count = 0; isize new_name_count = 0; diff --git a/src/check_type.cpp b/src/check_type.cpp index 6c9e82aa1..af0c70119 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -400,7 +400,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< } } - auto entities = array_make(ctx->allocator, 0, variable_count); + auto entities = array_make(permanent_allocator(), 0, variable_count); for_array(i, params) { Ast *param = params[i]; @@ -596,7 +596,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array(ctx->allocator, 0, variant_count); + auto variants = array_make(permanent_allocator(), 0, variant_count); union_type->Union.scope = ctx->scope; @@ -618,7 +618,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array(ctx->allocator, 0, variable_count); + auto entities = array_make(permanent_allocator(), 0, variable_count); for_array(i, params) { Ast *param = params[i]; @@ -869,7 +869,7 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast enum_type->Enum.base_type = base_type; enum_type->Enum.scope = ctx->scope; - auto fields = array_make(ctx->allocator, 0, et->fields.count); + auto fields = array_make(permanent_allocator(), 0, et->fields.count); Type *constant_type = enum_type; if (named_type != nullptr) { @@ -986,9 +986,9 @@ void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, Ast *node) ast_node(bft, BitFieldType, node); GB_ASSERT(is_type_bit_field(bit_field_type)); - auto fields = array_make(ctx->allocator, 0, bft->fields.count); - auto sizes = array_make (ctx->allocator, 0, bft->fields.count); - auto offsets = array_make (ctx->allocator, 0, bft->fields.count); + auto fields = array_make(permanent_allocator(), 0, bft->fields.count); + auto sizes = array_make (permanent_allocator(), 0, bft->fields.count); + auto offsets = array_make (permanent_allocator(), 0, bft->fields.count); scope_reserve(ctx->scope, bft->fields.count); @@ -1549,7 +1549,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is bool is_variadic = false; isize variadic_index = -1; bool is_c_vararg = false; - auto variables = array_make(ctx->allocator, 0, variable_count); + auto variables = array_make(permanent_allocator(), 0, variable_count); for_array(i, params) { Ast *param = params[i]; if (param->kind != Ast_Field) { @@ -1891,7 +1891,7 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) { } } - auto variables = array_make(ctx->allocator, 0, variable_count); + auto variables = array_make(permanent_allocator(), 0, variable_count); for_array(i, results) { ast_node(field, Field, results[i]); Ast *default_value = unparen_expr(field->default_value); @@ -2781,7 +2781,6 @@ void init_map_entry_type(Type *type) { // NOTE(bill): The preload types may have not been set yet GB_ASSERT(t_map_key != nullptr); - gbAllocator a = heap_allocator(); Type *entry_type = alloc_type_struct(); /* @@ -2793,9 +2792,9 @@ void init_map_entry_type(Type *type) { } */ Ast *dummy_node = alloc_ast_node(nullptr, Ast_Invalid); - Scope *s = create_scope(builtin_pkg->scope, a); + Scope *s = create_scope(builtin_pkg->scope); - auto fields = array_make(a, 0, 3); + auto fields = array_make(permanent_allocator(), 0, 3); array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("key")), t_map_key, false, 0, EntityState_Resolved)); array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("next")), t_int, false, 1, EntityState_Resolved)); array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("value")), type->Map.value, false, 2, EntityState_Resolved)); @@ -2803,7 +2802,6 @@ void init_map_entry_type(Type *type) { entry_type->Struct.fields = fields; - // type_set_offsets(a, entry_type); type->Map.entry_type = entry_type; } @@ -2826,15 +2824,14 @@ void init_map_internal_types(Type *type) { entries: [dynamic]EntryType; } */ - gbAllocator a = heap_allocator(); Ast *dummy_node = alloc_ast_node(nullptr, Ast_Invalid); - Scope *s = create_scope(builtin_pkg->scope, a); + Scope *s = create_scope(builtin_pkg->scope); Type *hashes_type = alloc_type_slice(t_int); Type *entries_type = alloc_type_dynamic_array(type->Map.entry_type); - auto fields = array_make(a, 0, 2); + auto fields = array_make(permanent_allocator(), 0, 2); array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("hashes")), hashes_type, false, 0, EntityState_Resolved)); array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("entries")), entries_type, false, 1, EntityState_Resolved)); @@ -2902,7 +2899,7 @@ Type *make_soa_struct_fixed(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_ soa_struct->Struct.soa_elem = elem; soa_struct->Struct.soa_count = count; - scope = create_scope(ctx->scope, ctx->allocator); + scope = create_scope(ctx->scope); soa_struct->Struct.scope = scope; String params_xyzw[4] = { @@ -2935,7 +2932,7 @@ Type *make_soa_struct_fixed(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_ soa_struct->Struct.soa_elem = elem; soa_struct->Struct.soa_count = count; - scope = create_scope(old_struct->Struct.scope->parent, ctx->allocator); + scope = create_scope(old_struct->Struct.scope->parent); soa_struct->Struct.scope = scope; for_array(i, old_struct->Struct.fields) { @@ -2996,7 +2993,7 @@ Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_ soa_struct->Struct.soa_count = 0; soa_struct->Struct.is_polymorphic = true; - scope = create_scope(ctx->scope, ctx->allocator); + scope = create_scope(ctx->scope); soa_struct->Struct.scope = scope; } else if (is_type_array(elem)) { Type *old_array = base_type(elem); @@ -3010,7 +3007,7 @@ Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_ soa_struct->Struct.soa_elem = elem; soa_struct->Struct.soa_count = 0; - scope = create_scope(ctx->scope, ctx->allocator); + scope = create_scope(ctx->scope); soa_struct->Struct.scope = scope; String params_xyzw[4] = { @@ -3046,7 +3043,7 @@ Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_ soa_struct->Struct.soa_elem = elem; soa_struct->Struct.soa_count = 0; - scope = create_scope(old_struct->Struct.scope->parent, ctx->allocator); + scope = create_scope(old_struct->Struct.scope->parent); soa_struct->Struct.scope = scope; for_array(i, old_struct->Struct.fields) { @@ -3113,7 +3110,7 @@ Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, As soa_struct->Struct.soa_count = 0; soa_struct->Struct.is_polymorphic = true; - scope = create_scope(ctx->scope, ctx->allocator); + scope = create_scope(ctx->scope); soa_struct->Struct.scope = scope; } else if (is_type_array(elem)) { Type *old_array = base_type(elem); @@ -3127,7 +3124,7 @@ Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, As soa_struct->Struct.soa_elem = elem; soa_struct->Struct.soa_count = 0; - scope = create_scope(ctx->scope, ctx->allocator); + scope = create_scope(ctx->scope); soa_struct->Struct.scope = scope; String params_xyzw[4] = { @@ -3162,7 +3159,7 @@ Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, As soa_struct->Struct.soa_elem = elem; soa_struct->Struct.soa_count = 0; - scope = create_scope(old_struct->Struct.scope->parent, ctx->allocator); + scope = create_scope(old_struct->Struct.scope->parent); soa_struct->Struct.scope = scope; for_array(i, old_struct->Struct.fields) { diff --git a/src/checker.cpp b/src/checker.cpp index a07a3ffbe..76d8cceb3 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -187,8 +187,8 @@ void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { array_init (&d->labels, heap_allocator()); } -DeclInfo *make_decl_info(gbAllocator a, Scope *scope, DeclInfo *parent) { - DeclInfo *d = gb_alloc_item(a, DeclInfo); +DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) { + DeclInfo *d = gb_alloc_item(permanent_allocator(), DeclInfo); init_decl_info(d, scope, parent); return d; } @@ -219,8 +219,8 @@ bool decl_info_has_init(DeclInfo *d) { -Scope *create_scope(Scope *parent, gbAllocator allocator, isize init_elements_capacity=DEFAULT_SCOPE_CAPACITY) { - Scope *s = gb_alloc_item(allocator, Scope); +Scope *create_scope(Scope *parent, isize init_elements_capacity=DEFAULT_SCOPE_CAPACITY) { + Scope *s = gb_alloc_item(permanent_allocator(), Scope); s->parent = parent; string_map_init(&s->elements, heap_allocator(), init_elements_capacity); ptr_set_init(&s->imported, heap_allocator(), 0); @@ -244,7 +244,7 @@ Scope *create_scope_from_file(CheckerContext *c, AstFile *f) { GB_ASSERT(f->pkg != nullptr); GB_ASSERT(f->pkg->scope != nullptr); - Scope *s = create_scope(f->pkg->scope, c->allocator); + Scope *s = create_scope(f->pkg->scope); array_reserve(&s->delayed_imports, f->imports.count); array_reserve(&s->delayed_directives, f->directive_count); @@ -264,7 +264,7 @@ Scope *create_scope_from_package(CheckerContext *c, AstPackage *pkg) { decl_count += pkg->files[i]->decls.count; } isize init_elements_capacity = 2*decl_count; - Scope *s = create_scope(builtin_pkg->scope, c->allocator, init_elements_capacity); + Scope *s = create_scope(builtin_pkg->scope, init_elements_capacity); s->flags |= ScopeFlag_Pkg; s->pkg = pkg; @@ -324,7 +324,7 @@ void check_open_scope(CheckerContext *c, Ast *node) { GB_ASSERT(node->kind == Ast_Invalid || is_ast_stmt(node) || is_ast_type(node)); - Scope *scope = create_scope(c->scope, c->allocator); + Scope *scope = create_scope(c->scope); add_scope(c, node, scope); switch (node->kind) { case Ast_ProcType: @@ -699,7 +699,7 @@ void init_universal(void) { builtin_pkg->name = str_lit("builtin"); builtin_pkg->kind = Package_Normal; - builtin_pkg->scope = create_scope(nullptr, a); + builtin_pkg->scope = create_scope(nullptr); builtin_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global; builtin_pkg->scope->pkg = builtin_pkg; @@ -707,7 +707,7 @@ void init_universal(void) { intrinsics_pkg->name = str_lit("intrinsics"); intrinsics_pkg->kind = Package_Normal; - intrinsics_pkg->scope = create_scope(nullptr, a); + intrinsics_pkg->scope = create_scope(nullptr); intrinsics_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global; intrinsics_pkg->scope->pkg = intrinsics_pkg; @@ -715,7 +715,7 @@ void init_universal(void) { config_pkg->name = str_lit("config"); config_pkg->kind = Package_Normal; - config_pkg->scope = create_scope(nullptr, a); + config_pkg->scope = create_scope(nullptr); config_pkg->scope->flags |= ScopeFlag_Pkg | ScopeFlag_Global; config_pkg->scope->pkg = config_pkg; @@ -872,7 +872,6 @@ CheckerContext make_checker_context(Checker *c) { CheckerContext ctx = c->init_ctx; ctx.checker = c; ctx.info = &c->info; - ctx.allocator = c->allocator; ctx.scope = builtin_pkg->scope; ctx.pkg = builtin_pkg; @@ -906,8 +905,6 @@ bool init_checker(Checker *c, Parser *parser) { isize total_token_count = c->parser->total_token_count; isize arena_size = 2 * item_size * total_token_count; - c->allocator = heap_allocator(); - c->init_ctx = make_checker_context(c); return true; } @@ -2597,7 +2594,7 @@ DECL_ATTRIBUTE_PROC(type_decl_attribute) { if (valid && build_context.use_llvm_api) { if (ac->atom_op_table == nullptr) { - ac->atom_op_table = gb_alloc_item(heap_allocator(), TypeAtomOpTable); + ac->atom_op_table = gb_alloc_item(permanent_allocator(), TypeAtomOpTable); } ac->atom_op_table->op[TypeAtomOp_index_get] = e; } @@ -2656,7 +2653,7 @@ DECL_ATTRIBUTE_PROC(type_decl_attribute) { if (valid && build_context.use_llvm_api) { if (ac->atom_op_table == nullptr) { - ac->atom_op_table = gb_alloc_item(heap_allocator(), TypeAtomOpTable); + ac->atom_op_table = gb_alloc_item(permanent_allocator(), TypeAtomOpTable); } ac->atom_op_table->op[TypeAtomOp_index_set] = e; } @@ -2738,7 +2735,7 @@ DECL_ATTRIBUTE_PROC(type_decl_attribute) { if (valid && build_context.use_llvm_api) { if (ac->atom_op_table == nullptr) { - ac->atom_op_table = gb_alloc_item(heap_allocator(), TypeAtomOpTable); + ac->atom_op_table = gb_alloc_item(permanent_allocator(), TypeAtomOpTable); } ac->atom_op_table->op[TypeAtomOp_slice] = e; } @@ -3090,7 +3087,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { } Ast *init_expr = value; - DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl); + DeclInfo *d = make_decl_info(c->scope, c->decl); d->entity = e; d->type_expr = vd->type; d->init_expr = init_expr; @@ -3118,7 +3115,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { Token token = name->Ident.token; Ast *fl = c->foreign_context.curr_library; - DeclInfo *d = make_decl_info(c->allocator, c->scope, c->decl); + DeclInfo *d = make_decl_info(c->scope, c->decl); Entity *e = nullptr; d->attributes = vd->attributes; @@ -4317,7 +4314,7 @@ void check_parsed_files(Checker *c) { for_array(i, c->parser->packages) { AstPackage *p = c->parser->packages[i]; Scope *scope = create_scope_from_package(&c->init_ctx, p); - p->decl_info = make_decl_info(c->allocator, scope, c->init_ctx.decl); + p->decl_info = make_decl_info(scope, c->init_ctx.decl); string_map_set(&c->info.packages, p->fullpath, p); if (scope->flags&ScopeFlag_Init) { diff --git a/src/checker.hpp b/src/checker.hpp index 88e9451ee..ed4809748 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -301,7 +301,6 @@ struct CheckerContext { ProcCallingConvention curr_proc_calling_convention; bool in_proc_sig; ForeignContext foreign_context; - gbAllocator allocator; CheckerTypePath *type_path; isize type_level; // TODO(bill): Actually handle correctly @@ -331,7 +330,6 @@ struct Checker { Array procs_with_deferred_to_check; CheckerContext *curr_ctx; - gbAllocator allocator; CheckerContext init_ctx; }; diff --git a/src/common.cpp b/src/common.cpp index 567655c04..05ebdd4c5 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -451,7 +451,6 @@ void arena_free_all(Arena *arena) { - GB_ALLOCATOR_PROC(arena_allocator_proc); gbAllocator arena_allocator(Arena *arena) { @@ -492,6 +491,38 @@ GB_ALLOCATOR_PROC(arena_allocator_proc) { return ptr; } +struct SCOPED_TEMP_ARENA_MEMORY { + Arena *arena; + u8 * ptr; + u8 * end; + u8 * prev; + isize total_used; + isize block_count; + + SCOPED_TEMP_ARENA_MEMORY(Arena *the_arena) { + GB_ASSERT(!the_arena->use_mutex); + arena = the_arena; + ptr = arena->ptr; + end = arena->end; + prev = arena->prev; + total_used = arena->total_used; + block_count = arena->blocks.count; + } + ~SCOPED_TEMP_ARENA_MEMORY() { + if (arena->blocks.count != block_count) { + for (isize i = block_count; i < arena->blocks.count; i++) { + gb_free(arena->backing, arena->blocks[i]); + } + arena->blocks.count = block_count; + } + arena->ptr = ptr; + arena->end = end; + arena->prev = prev; + arena->total_used = total_used; + } +}; + + gb_global Arena permanent_arena = {}; @@ -504,6 +535,8 @@ gbAllocator temporary_allocator() { return arena_allocator(&temporary_arena); } +#define SCOPED_TEMPORARY_BLOCK() auto GB_DEFER_3(_SCOPED_TEMPORARY_BLOCK_) = SCOPED_TEMP_ARENA_MEMORY(&temporary_arena) + diff --git a/src/gb/gb.h b/src/gb/gb.h index 848f27628..f13693000 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -5156,7 +5156,7 @@ b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) { index = core * a->threads_per_core + thread_index; thread = pthread_self(); - + cpuset_t mn; CPU_ZERO(&mn); diff --git a/src/ir.cpp b/src/ir.cpp index ee177edd6..7b6301e30 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2132,7 +2132,7 @@ irDebugInfo *ir_add_debug_info_field(irModule *module, irDebugInfo *scope, Entit if (e->token.string.len == 0) { // If no name available for field, use its field index as its name. isize max_len = 8; - u8 *str = cast(u8 *)gb_alloc_array(heap_allocator(), u8, max_len); + u8 *str = cast(u8 *)gb_alloc_array(permanent_allocator(), u8, max_len); isize len = gb_snprintf(cast(char *)str, 8, "%d", index); di->DerivedType.name = make_string(str, len-1); } @@ -3293,7 +3293,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &ar GB_ASSERT_MSG(param_count == args.count, "%.*s %td == %td", LIT(p->entity->token.string), param_count, args.count); } - auto processed_args = array_make(heap_allocator(), 0, args.count); + auto processed_args = array_make(permanent_allocator(), 0, args.count); for (isize i = 0; i < param_count; i++) { Entity *e = pt->Proc.params->Tuple.variables[i]; @@ -3416,7 +3416,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &ar case DeferredProcedure_in_out: { auto out_args = ir_value_to_array(p, result); - array_init(&result_as_args, heap_allocator(), in_args.count + out_args.count); + array_init(&result_as_args, permanent_allocator(), in_args.count + out_args.count); array_copy(&result_as_args, in_args, 0); array_copy(&result_as_args, out_args, in_args.count); } @@ -4537,7 +4537,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * Type *ft = base_complex_elem_type(t_left); if (op == Token_Quo) { - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = left; args[1] = right; @@ -4615,7 +4615,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * return ir_emit_load(proc, res); } else if (op == Token_Mul) { - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = left; args[1] = right; @@ -4625,7 +4625,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * default: GB_PANIC("Unknown float type"); break; } } else if (op == Token_Quo) { - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = left; args[1] = right; @@ -4828,7 +4828,7 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue irValue *invalid_typeid = ir_value_constant(t_typeid, exact_value_i64(0)); return ir_emit_comp(proc, op_kind, x, invalid_typeid); } else if (is_type_bit_field(t)) { - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); irValue *lhs = ir_address_from_load_or_generate_local(proc, x); args[0] = ir_emit_conv(proc, lhs, t_rawptr); args[1] = ir_const_int(type_size_of(t)); @@ -4848,7 +4848,7 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue return ir_emit_comp(proc, op_kind, cap, v_zero); } } else if (is_type_struct(t) && type_has_nil(t)) { - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); irValue *lhs = ir_address_from_load_or_generate_local(proc, x); args[0] = ir_emit_conv(proc, lhs, t_rawptr); args[1] = ir_const_int(type_size_of(t)); @@ -4966,7 +4966,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal } else { if (is_type_simple_compare(tl) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) { // TODO(bill): Test to see if this is actually faster!!!! - auto args = array_make(heap_allocator(), 3); + auto args = array_make(permanent_allocator(), 3); args[0] = ir_emit_conv(proc, lhs, t_rawptr); args[1] = ir_emit_conv(proc, rhs, t_rawptr); args[2] = ir_const_int(type_size_of(tl)); @@ -7355,7 +7355,7 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu // "Intrinsics" case BuiltinProc_alloca: { - auto args = array_make(heap_allocator(), 2); + auto args = array_make(permanent_allocator(), 2); args[0] = ir_emit_conv(proc, ir_build_expr(proc, ce->args[0]), t_i32); args[1] = ir_build_expr(proc, ce->args[1]); return ir_emit(proc, ir_instr_inline_code(proc, id, args, t_u8_ptr)); @@ -9024,8 +9024,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { if (cl->elems.count > 0) { ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr))); - auto temp_data = array_make(heap_allocator(), 0, cl->elems.count); - defer (array_free(&temp_data)); + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); // NOTE(bill): Separate value, gep, store into their own chunks for_array(i, cl->elems) { @@ -9123,8 +9122,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { if (cl->elems.count > 0) { ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr))); - auto temp_data = array_make(heap_allocator(), 0, cl->elems.count); - defer (array_free(&temp_data)); + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); // NOTE(bill): Separate value, gep, store into their own chunks for_array(i, cl->elems) { @@ -9232,8 +9230,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { irValue *data = ir_emit_array_ep(proc, slice->ConstantSlice.backing_array, v_zero32); - auto temp_data = array_make(heap_allocator(), 0, cl->elems.count); - defer (array_free(&temp_data)); + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); for_array(i, cl->elems) { Ast *elem = cl->elems[i]; @@ -10179,7 +10176,7 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { String mangled_name = {}; { - gbString str = gb_string_make_length(heap_allocator(), proc->name.text, proc->name.len); + gbString str = gb_string_make_length(permanent_allocator(), proc->name.text, proc->name.len); str = gb_string_appendc(str, "-"); str = gb_string_append_fmt(str, ".%.*s-%llu", LIT(name), cast(long long)e->id); mangled_name.text = cast(u8 *)str; diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 2d15f176b..1a306365f 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -76,7 +76,8 @@ void ir_write_u64(irFileBuffer *f, u64 i) { } void ir_write_big_int(irFileBuffer *f, BigInt const &x, Type *type, bool swap_endian) { if (x.len == 2) { - gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator + SCOPED_TEMPORARY_BLOCK(); + u64 words[2] = {}; BigInt y = x; if (swap_endian) { @@ -88,9 +89,8 @@ void ir_write_big_int(irFileBuffer *f, BigInt const &x, Type *type, bool swap_en y.d.words = words; } - String s = big_int_to_string(a, &y, 10); + String s = big_int_to_string(temporary_allocator(), &y, 10); ir_write_string(f, s); - gb_free(a, s.text); } else { i64 i = 0; if (x.neg) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 121917740..0e0fa904b 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -781,6 +781,8 @@ void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbValue variant void lb_clone_struct_type(LLVMTypeRef dst, LLVMTypeRef src) { + SCOPED_TEMPORARY_BLOCK(); + unsigned field_count = LLVMCountStructElementTypes(src); LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); LLVMGetStructElementTypes(src, fields); @@ -1277,9 +1279,10 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { m->internal_type_level += 1; defer (m->internal_type_level -= 1); + SCOPED_TEMPORARY_BLOCK(); + unsigned field_count = cast(unsigned)(type->Struct.fields.count + offset); LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); - GB_ASSERT(fields != nullptr); for_array(i, type->Struct.fields) { Entity *field = type->Struct.fields[i]; @@ -1338,6 +1341,8 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { if (type->Tuple.variables.count == 1) { return lb_type(m, type->Tuple.variables[0]->type); } else { + SCOPED_TEMPORARY_BLOCK(); + unsigned field_count = cast(unsigned)(type->Tuple.variables.count); LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); @@ -1437,6 +1442,8 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { extra_param_count += 1; } + SCOPED_TEMPORARY_BLOCK(); + isize param_count = type->Proc.abi_compat_params.count + extra_param_count; auto param_types = array_make(temporary_allocator(), 0, param_count); @@ -1483,6 +1490,8 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { { LLVMTypeRef internal_type = nullptr; { + SCOPED_TEMPORARY_BLOCK(); + GB_ASSERT(type->BitField.fields.count == type->BitField.sizes.count); unsigned field_count = cast(unsigned)type->BitField.fields.count; LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); @@ -5279,8 +5288,9 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc return lb_const_nil(m, original_type); } if (cl->elems[0]->kind == Ast_FieldValue) { - // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand + SCOPED_TEMPORARY_BLOCK(); + // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->Array.count); isize value_index = 0; @@ -5338,6 +5348,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } else { GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); + SCOPED_TEMPORARY_BLOCK(); LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->Array.count); for (isize i = 0; i < elem_count; i++) { @@ -5360,8 +5371,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc return lb_const_nil(m, original_type); } if (cl->elems[0]->kind == Ast_FieldValue) { + SCOPED_TEMPORARY_BLOCK(); // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand - LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->EnumeratedArray.count); isize value_index = 0; @@ -5423,6 +5434,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } else { GB_ASSERT_MSG(elem_count == type->EnumeratedArray.count, "%td != %td", elem_count, type->EnumeratedArray.count); + SCOPED_TEMPORARY_BLOCK(); LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->EnumeratedArray.count); for (isize i = 0; i < elem_count; i++) { @@ -5447,6 +5459,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } GB_ASSERT(elem_type_can_be_constant(elem_type)); + SCOPED_TEMPORARY_BLOCK(); + isize total_elem_count = type->SimdVector.count; LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, total_elem_count); @@ -5473,6 +5487,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc offset = 1; } + SCOPED_TEMPORARY_BLOCK(); + isize value_count = type->Struct.fields.count + offset; LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, value_count); bool *visited = gb_alloc_array(temporary_allocator(), bool, value_count); @@ -10880,6 +10896,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { if (cl->elems.count > 0) { lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + SCOPED_TEMPORARY_BLOCK(); auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); // NOTE(bill): Separate value, gep, store into their own chunks @@ -10979,6 +10996,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { if (cl->elems.count > 0) { lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + SCOPED_TEMPORARY_BLOCK(); auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); // NOTE(bill): Separate value, gep, store into their own chunks @@ -11087,6 +11105,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { lbValue data = lb_slice_elem(p, slice); + SCOPED_TEMPORARY_BLOCK(); auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); for_array(i, cl->elems) { @@ -11935,6 +11954,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da str_lit("$enum_values"), cast(i64)entry_index); + SCOPED_TEMPORARY_BLOCK(); LLVMValueRef *name_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, fields.count); LLVMValueRef *value_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, fields.count); @@ -12894,7 +12914,7 @@ void lb_generate_code(lbGenerator *gen) { } - String filepath_ll = concatenate_strings(temporary_allocator(), gen->output_base, STR_LIT(".ll")); + String filepath_ll = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".ll")); TIME_SECTION("LLVM Procedure Generation"); for_array(i, m->procedures_to_generate) { diff --git a/src/main.cpp b/src/main.cpp index d0d2e2bbb..2dbac3390 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1646,6 +1646,7 @@ int main(int arg_count, char const **arg_ptr) { arena_init(&permanent_arena, heap_allocator()); arena_init(&temporary_arena, heap_allocator()); arena_init(&global_ast_arena, heap_allocator()); + permanent_arena.use_mutex = true; init_string_buffer_memory(); init_string_interner(); -- cgit v1.2.3 From ca4b0527e80bda39aa677f013415eff0c62f433d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 16 Nov 2020 15:18:25 +0000 Subject: Minimize memory usage for AST nodes by using Slice rather than Array when the parameter doesn't need to grow --- src/array.cpp | 89 ++++++++++++++++++++++++++++++++++++- src/check_decl.cpp | 2 +- src/check_expr.cpp | 24 +++++----- src/check_stmt.cpp | 6 +-- src/check_type.cpp | 10 ++--- src/checker.cpp | 12 ++--- src/checker.hpp | 2 +- src/entity.cpp | 4 +- src/ir.cpp | 6 +-- src/llvm_backend.cpp | 4 +- src/parser.cpp | 121 +++++++++++++++++++++++++++++---------------------- src/parser.hpp | 57 ++++++++++++------------ 12 files changed, 218 insertions(+), 119 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/array.cpp b/src/array.cpp index 6fe54b847..dc52eeb8d 100644 --- a/src/array.cpp +++ b/src/array.cpp @@ -43,11 +43,96 @@ template void array_set_capacity (Array *array, isize capac template Array array_slice (Array const &array, isize lo, isize hi); template Array array_clone (gbAllocator const &a, Array const &array); - - template void array_ordered_remove (Array *array, isize index); template void array_unordered_remove(Array *array, isize index); +template void array_copy(Array *array, Array const &data, isize offset); +template void array_copy(Array *array, Array const &data, isize offset, isize count); + +template T *array_end_ptr(Array *array); + + +template +struct Slice { + T *data; + isize count; + + T &operator[](isize index) { + #if !defined(NO_ARRAY_BOUNDS_CHECK) + GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count); + #endif + return data[index]; + } + + T const &operator[](isize index) const { + #if !defined(NO_ARRAY_BOUNDS_CHECK) + GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count); + #endif + return data[index]; + } +}; + +template Slice slice_from_array(Array const &a); + + + +template +Slice slice_make(gbAllocator const &allocator, isize count) { + Slice s = {}; + s.data = gb_alloc_array(allocator, T, count); + s.count = count; + return s; +} + + +template +Slice slice_from_array(Array const &a) { + return {a.data, a.count}; +} +template +Slice slice_clone(gbAllocator const &allocator, Slice const &a) { + T *data = cast(T *)gb_alloc_copy_align(allocator, a.data, a.count*gb_size_of(T), gb_align_of(T)); + return {data, a.count}; +} + +template +Slice slice_clone_from_array(gbAllocator const &allocator, Array const &a) { + auto c = array_clone(allocator, a); + return {c.data, c.count}; +} + + +template +void slice_copy(Slice *slice, Slice const &data, isize offset) { + gb_memmove(slice->data+offset, data.data, gb_size_of(T)*data.count); +} +template +void slice_copy(Slice *slice, Slice const &data, isize offset, isize count) { + gb_memmove(slice->data+offset, data.data, gb_size_of(T)*gb_min(data.count, count)); +} + + + +template +void slice_ordered_remove(Slice *array, isize index) { + GB_ASSERT(0 <= index && index < array->count); + + isize bytes = gb_size_of(T) * (array->count-(index+1)); + gb_memmove(array->data+index, array->data+index+1, bytes); + array->count -= 1; +} + +template +void slice_unordered_remove(Slice *array, isize index) { + GB_ASSERT(0 <= index && index < array->count); + + isize n = array->count-1; + if (index != n) { + gb_memmove(array->data+index, array->data+n, gb_size_of(T)); + } + array->count -= 1; +} + template void array_copy(Array *array, Array const &data, isize offset) { diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 248069b97..da07fe4bc 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -113,7 +113,7 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri return e->type; } -void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array const &inits, String context_name) { +void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Slice const &inits, String context_name) { if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) { return; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 11ccf2dab..94a3467d2 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -73,7 +73,7 @@ void update_expr_type (CheckerContext *c, Ast *e, Type *type, bool check_is_terminating (Ast *node, String const &label); bool check_has_break (Ast *stmt, String const &label, bool implicit); void check_stmt (CheckerContext *c, Ast *node, u32 flags); -void check_stmt_list (CheckerContext *c, Array const &stmts, u32 flags); +void check_stmt_list (CheckerContext *c, Slice const &stmts, u32 flags); void check_init_constant (CheckerContext *c, Entity *e, Operand *operand); bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Type *type, ExactValue *out_value); bool check_procedure_type (CheckerContext *c, Type *type, Ast *proc_type_node, Array *operands = nullptr); @@ -133,7 +133,7 @@ void error_operand_no_value(Operand *o) { } -void check_scope_decls(CheckerContext *c, Array const &nodes, isize reserve_size) { +void check_scope_decls(CheckerContext *c, Slice const &nodes, isize reserve_size) { Scope *s = c->scope; check_collect_entities(c, nodes); @@ -6062,7 +6062,7 @@ isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lhs, isize lhs } -bool check_assignment_arguments(CheckerContext *ctx, Array const &lhs, Array *operands, Array const &rhs) { +bool check_assignment_arguments(CheckerContext *ctx, Array const &lhs, Array *operands, Slice const &rhs) { bool optional_ok = false; isize tuple_index = 0; for_array(i, rhs) { @@ -6146,7 +6146,7 @@ bool check_assignment_arguments(CheckerContext *ctx, Array const &lhs, -bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Array const &rhs, bool allow_ok, bool is_variadic) { +bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Slice const &rhs, bool allow_ok, bool is_variadic) { bool optional_ok = false; isize tuple_index = 0; for_array(i, rhs) { @@ -6748,7 +6748,7 @@ Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize } -bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Scope *scope, Array *clauses, bool print_err) { +bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Scope *scope, Slice *clauses, bool print_err) { if (clauses != nullptr) { for_array(i, *clauses) { Ast *clause = (*clauses)[i]; @@ -6813,7 +6813,7 @@ bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Scope *scope, A } -CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type *proc_type, Ast *call, Array const &args) { +CallArgumentData check_call_arguments(CheckerContext *c, Operand *operand, Type *proc_type, Ast *call, Slice const &args) { ast_node(ce, CallExpr, call); CallArgumentCheckerType *call_checker = check_call_arguments_internal; @@ -7598,7 +7598,7 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper -ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Array const &args, ProcInlining inlining, Type *type_hint) { +ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice const &args, ProcInlining inlining, Type *type_hint) { if (proc != nullptr && proc->kind == Ast_BasicDirective) { ast_node(bd, BasicDirective, proc); @@ -8150,7 +8150,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(bl, BasicLit, node); Type *t = t_invalid; - switch (bl->value.kind) { + switch (node->tav.value.kind) { case ExactValue_String: t = t_untyped_string; break; case ExactValue_Float: t = t_untyped_float; break; case ExactValue_Complex: t = t_untyped_complex; break; @@ -8168,7 +8168,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type o->mode = Addressing_Constant; o->type = t; - o->value = bl->value; + o->value = node->tav.value; case_end; case_ast_node(bd, BasicDirective, node); @@ -9600,9 +9600,9 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type - auto modified_args = array_make(heap_allocator(), ce->args.count+1); + auto modified_args = slice_make(heap_allocator(), ce->args.count+1); modified_args[0] = first_arg; - array_copy(&modified_args, ce->args, 1); + slice_copy(&modified_args, ce->args, 1); ce->args = modified_args; se->modified_call = true; @@ -10210,7 +10210,7 @@ void check_expr_or_type(CheckerContext *c, Operand *o, Ast *e, Type *type_hint) gbString write_expr_to_string(gbString str, Ast *node); -gbString write_struct_fields_to_string(gbString str, Array const ¶ms) { +gbString write_struct_fields_to_string(gbString str, Slice const ¶ms) { for_array(i, params) { if (i > 0) { str = gb_string_appendc(str, ", "); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 4cafa8df5..ad72256c3 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -15,7 +15,7 @@ bool is_divigering_stmt(Ast *stmt) { return t->kind == Type_Proc && t->Proc.diverging; } -void check_stmt_list(CheckerContext *ctx, Array const &stmts, u32 flags) { +void check_stmt_list(CheckerContext *ctx, Slice const &stmts, u32 flags) { if (stmts.count == 0) { return; } @@ -78,7 +78,7 @@ void check_stmt_list(CheckerContext *ctx, Array const &stmts, u32 flags) } } -bool check_is_terminating_list(Array const &stmts, String const &label) { +bool check_is_terminating_list(Slice const &stmts, String const &label) { // Iterate backwards for (isize n = stmts.count-1; n >= 0; n--) { Ast *stmt = stmts[n]; @@ -96,7 +96,7 @@ bool check_is_terminating_list(Array const &stmts, String const &label) { return false; } -bool check_has_break_list(Array const &stmts, String const &label, bool implicit) { +bool check_has_break_list(Slice const &stmts, String const &label, bool implicit) { for_array(i, stmts) { Ast *stmt = stmts[i]; if (check_has_break(stmt, label, implicit)) { diff --git a/src/check_type.cpp b/src/check_type.cpp index af0c70119..6ea17eca6 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -117,7 +117,7 @@ bool does_field_type_allow_using(Type *t) { return false; } -void check_struct_fields(CheckerContext *ctx, Ast *node, Array *fields, Array *tags, Array const ¶ms, +void check_struct_fields(CheckerContext *ctx, Ast *node, Array *fields, Array *tags, Slice const ¶ms, isize init_field_capacity, Type *struct_type, String context) { *fields = array_make(heap_allocator(), 0, init_field_capacity); *tags = array_make(heap_allocator(), 0, init_field_capacity); @@ -389,7 +389,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< if (st->polymorphic_params != nullptr) { ast_node(field_list, FieldList, st->polymorphic_params); - Array params = field_list->list; + Slice params = field_list->list; if (params.count != 0) { isize variable_count = 0; for_array(i, params) { @@ -607,7 +607,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Arraypolymorphic_params != nullptr) { ast_node(field_list, FieldList, ut->polymorphic_params); - Array params = field_list->list; + Slice params = field_list->list; if (params.count != 0) { isize variable_count = 0; for_array(i, params) { @@ -1516,7 +1516,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is bool success = true; ast_node(field_list, FieldList, _params); - Array params = field_list->list; + Slice params = field_list->list; if (params.count == 0) { if (success_) *success_ = success; @@ -1875,7 +1875,7 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) { return nullptr; } ast_node(field_list, FieldList, _results); - Array results = field_list->list; + Slice results = field_list->list; if (results.count == 0) { return nullptr; diff --git a/src/checker.cpp b/src/checker.cpp index 380872f24..f02b927c3 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2854,7 +2854,7 @@ void check_decl_attributes(CheckerContext *c, Array const &attributes, De } -isize get_total_value_count(Array const &values) { +isize get_total_value_count(Slice const &values) { isize count = 0; for_array(i, values) { Type *t = type_of_expr(values[i]); @@ -3068,7 +3068,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { } else { entity_visibility_kind = kind; } - array_unordered_remove(elems, j); + slice_unordered_remove(elems, j); j -= 1; } } @@ -3252,7 +3252,7 @@ void check_add_foreign_block_decl(CheckerContext *ctx, Ast *decl) { } // NOTE(bill): If file_scopes == nullptr, this will act like a local scope -void check_collect_entities(CheckerContext *c, Array const &nodes) { +void check_collect_entities(CheckerContext *c, Slice const &nodes) { for_array(decl_index, nodes) { Ast *decl = nodes[decl_index]; if (!is_ast_decl(decl) && !is_ast_when_stmt(decl)) { @@ -3783,7 +3783,7 @@ void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { } } -bool collect_checked_packages_from_decl_list(Checker *c, Array const &decls) { +bool collect_checked_packages_from_decl_list(Checker *c, Slice const &decls) { bool new_files = false; for_array(i, decls) { Ast *decl = decls[i]; @@ -3805,7 +3805,7 @@ bool collect_checked_packages_from_decl_list(Checker *c, Array const &dec } // Returns true if a new package is present -bool collect_file_decls(CheckerContext *ctx, Array const &decls); +bool collect_file_decls(CheckerContext *ctx, Slice const &decls); bool collect_file_decls_from_when_stmt(CheckerContext *ctx, AstWhenStmt *ws); bool collect_when_stmt_from_file(CheckerContext *ctx, AstWhenStmt *ws) { @@ -3880,7 +3880,7 @@ bool collect_file_decls_from_when_stmt(CheckerContext *ctx, AstWhenStmt *ws) { return false; } -bool collect_file_decls(CheckerContext *ctx, Array const &decls) { +bool collect_file_decls(CheckerContext *ctx, Slice const &decls) { GB_ASSERT(ctx->scope->flags&ScopeFlag_File); if (collect_checked_packages_from_decl_list(ctx->checker, decls)) { diff --git a/src/checker.hpp b/src/checker.hpp index e6111d2af..9c9b77ac3 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -384,7 +384,7 @@ void check_add_foreign_import_decl(CheckerContext *c, Ast *decl); bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_global = false); -void check_collect_entities(CheckerContext *c, Array const &nodes); +void check_collect_entities(CheckerContext *c, Slice const &nodes); void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws); void check_delayed_file_import_entity(CheckerContext *c, Ast *decl); diff --git a/src/entity.cpp b/src/entity.cpp index 708b0862c..0aece39c3 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -165,7 +165,7 @@ struct Entity { Scope *scope; } ImportName; struct { - Array paths; + Slice paths; String name; } LibraryName; i32 Nil; @@ -333,7 +333,7 @@ Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type, } Entity *alloc_entity_library_name(Scope *scope, Token token, Type *type, - Array paths, String name) { + Slice paths, String name) { Entity *entity = alloc_entity(Entity_LibraryName, scope, token, type); entity->LibraryName.paths = paths; entity->LibraryName.name = name; diff --git a/src/ir.cpp b/src/ir.cpp index 7b6301e30..1f2819ccf 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6884,7 +6884,7 @@ irValue *ir_find_global_variable(irProcedure *proc, String name) { return *value; } -void ir_build_stmt_list(irProcedure *proc, Array stmts); +void ir_build_stmt_list(irProcedure *proc, Slice stmts); void ir_build_assign_op(irProcedure *proc, irAddr const &lhs, irValue *value, TokenKind op); bool is_double_pointer(Type *t) { @@ -9689,7 +9689,7 @@ void ir_build_constant_value_decl(irProcedure *proc, AstValueDecl *vd) { } } -void ir_build_stmt_list(irProcedure *proc, Array stmts) { +void ir_build_stmt_list(irProcedure *proc, Slice stmts) { // NOTE(bill): Precollect constant entities for_array(i, stmts) { Ast *stmt = stmts[i]; @@ -10899,7 +10899,7 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { ast_node(body, BlockStmt, ss->body); - Array default_stmts = {}; + Slice default_stmts = {}; irBlock *default_fall = nullptr; irBlock *default_block = nullptr; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 6542da69b..50d200551 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -3134,7 +3134,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) { } -void lb_build_stmt_list(lbProcedure *p, Array const &stmts) { +void lb_build_stmt_list(lbProcedure *p, Slice const &stmts) { for_array(i, stmts) { Ast *stmt = stmts[i]; switch (stmt->kind) { @@ -3865,7 +3865,7 @@ void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss) { ast_node(body, BlockStmt, ss->body); - Array default_stmts = {}; + Slice default_stmts = {}; lbBlock *default_fall = nullptr; lbBlock *default_block = nullptr; diff --git a/src/parser.cpp b/src/parser.cpp index 476504d52..cf464f149 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -126,7 +126,7 @@ Ast *alloc_ast_node(AstFile *f, AstKind kind) { } Ast *clone_ast(Ast *node); -Array clone_ast_array(Array array) { +Array clone_ast_array(Array const &array) { Array result = {}; if (array.count > 0) { result = array_make(ast_allocator(nullptr), array.count); @@ -136,6 +136,16 @@ Array clone_ast_array(Array array) { } return result; } +Slice clone_ast_array(Slice const &array) { + Slice result = {}; + if (array.count > 0) { + result = slice_clone(permanent_allocator(), array); + for_array(i, array) { + result[i] = clone_ast(array[i]); + } + } + return result; +} Ast *clone_ast(Ast *node) { if (node == nullptr) { @@ -537,10 +547,10 @@ Ast *ast_paren_expr(AstFile *f, Ast *expr, Token open, Token close) { return result; } -Ast *ast_call_expr(AstFile *f, Ast *proc, Array args, Token open, Token close, Token ellipsis) { +Ast *ast_call_expr(AstFile *f, Ast *proc, Array const &args, Token open, Token close, Token ellipsis) { Ast *result = alloc_ast_node(f, Ast_CallExpr); result->CallExpr.proc = proc; - result->CallExpr.args = args; + result->CallExpr.args = slice_from_array(args); result->CallExpr.open = open; result->CallExpr.close = close; result->CallExpr.ellipsis = ellipsis; @@ -624,7 +634,8 @@ Ast *ast_undef(AstFile *f, Token token) { Ast *ast_basic_lit(AstFile *f, Token basic_lit) { Ast *result = alloc_ast_node(f, Ast_BasicLit); result->BasicLit.token = basic_lit; - result->BasicLit.value = exact_value_from_basic_literal(basic_lit); + result->tav.mode = Addressing_Constant; + result->tav.value = exact_value_from_basic_literal(basic_lit); return result; } @@ -643,12 +654,12 @@ Ast *ast_ellipsis(AstFile *f, Token token, Ast *expr) { } -Ast *ast_proc_group(AstFile *f, Token token, Token open, Token close, Array args) { +Ast *ast_proc_group(AstFile *f, Token token, Token open, Token close, Array const &args) { Ast *result = alloc_ast_node(f, Ast_ProcGroup); result->ProcGroup.token = token; result->ProcGroup.open = open; result->ProcGroup.close = close; - result->ProcGroup.args = args; + result->ProcGroup.args = slice_from_array(args); return result; } @@ -658,7 +669,7 @@ Ast *ast_proc_lit(AstFile *f, Ast *type, Ast *body, u64 tags, Token where_token, result->ProcLit.body = body; result->ProcLit.tags = tags; result->ProcLit.where_token = where_token; - result->ProcLit.where_clauses = where_clauses; + result->ProcLit.where_clauses = slice_from_array(where_clauses); return result; } @@ -670,10 +681,10 @@ Ast *ast_field_value(AstFile *f, Ast *field, Ast *value, Token eq) { return result; } -Ast *ast_compound_lit(AstFile *f, Ast *type, Array elems, Token open, Token close) { +Ast *ast_compound_lit(AstFile *f, Ast *type, Array const &elems, Token open, Token close) { Ast *result = alloc_ast_node(f, Ast_CompoundLit); result->CompoundLit.type = type; - result->CompoundLit.elems = elems; + result->CompoundLit.elems = slice_from_array(elems); result->CompoundLit.open = open; result->CompoundLit.close = close; return result; @@ -736,7 +747,7 @@ Ast *ast_inline_asm_expr(AstFile *f, Token token, Token open, Token close, result->InlineAsmExpr.token = token; result->InlineAsmExpr.open = open; result->InlineAsmExpr.close = close; - result->InlineAsmExpr.param_types = param_types; + result->InlineAsmExpr.param_types = slice_from_array(param_types); result->InlineAsmExpr.return_type = return_type; result->InlineAsmExpr.asm_string = asm_string; result->InlineAsmExpr.constraints_string = constraints_string; @@ -768,18 +779,18 @@ Ast *ast_expr_stmt(AstFile *f, Ast *expr) { return result; } -Ast *ast_assign_stmt(AstFile *f, Token op, Array lhs, Array rhs) { +Ast *ast_assign_stmt(AstFile *f, Token op, Array const &lhs, Array const &rhs) { Ast *result = alloc_ast_node(f, Ast_AssignStmt); result->AssignStmt.op = op; - result->AssignStmt.lhs = lhs; - result->AssignStmt.rhs = rhs; + result->AssignStmt.lhs = slice_from_array(lhs); + result->AssignStmt.rhs = slice_from_array(rhs); return result; } -Ast *ast_block_stmt(AstFile *f, Array stmts, Token open, Token close) { +Ast *ast_block_stmt(AstFile *f, Array const &stmts, Token open, Token close) { Ast *result = alloc_ast_node(f, Ast_BlockStmt); - result->BlockStmt.stmts = stmts; + result->BlockStmt.stmts = slice_from_array(stmts); result->BlockStmt.open = open; result->BlockStmt.close = close; return result; @@ -805,10 +816,10 @@ Ast *ast_when_stmt(AstFile *f, Token token, Ast *cond, Ast *body, Ast *else_stmt } -Ast *ast_return_stmt(AstFile *f, Token token, Array results) { +Ast *ast_return_stmt(AstFile *f, Token token, Array const &results) { Ast *result = alloc_ast_node(f, Ast_ReturnStmt); result->ReturnStmt.token = token; - result->ReturnStmt.results = results; + result->ReturnStmt.results = slice_from_array(results); return result; } @@ -866,11 +877,11 @@ Ast *ast_type_switch_stmt(AstFile *f, Token token, Ast *tag, Ast *body) { return result; } -Ast *ast_case_clause(AstFile *f, Token token, Array list, Array stmts) { +Ast *ast_case_clause(AstFile *f, Token token, Array const &list, Array const &stmts) { Ast *result = alloc_ast_node(f, Ast_CaseClause); result->CaseClause.token = token; - result->CaseClause.list = list; - result->CaseClause.stmts = stmts; + result->CaseClause.list = slice_from_array(list); + result->CaseClause.stmts = slice_from_array(stmts); return result; } @@ -889,10 +900,10 @@ Ast *ast_branch_stmt(AstFile *f, Token token, Ast *label) { return result; } -Ast *ast_using_stmt(AstFile *f, Token token, Array list) { +Ast *ast_using_stmt(AstFile *f, Token token, Array const &list) { Ast *result = alloc_ast_node(f, Ast_UsingStmt); result->UsingStmt.token = token; - result->UsingStmt.list = list; + result->UsingStmt.list = slice_from_array(list); return result; } @@ -905,10 +916,10 @@ Ast *ast_bad_decl(AstFile *f, Token begin, Token end) { return result; } -Ast *ast_field(AstFile *f, Array names, Ast *type, Ast *default_value, u32 flags, Token tag, +Ast *ast_field(AstFile *f, Array const &names, Ast *type, Ast *default_value, u32 flags, Token tag, CommentGroup *docs, CommentGroup *comment) { Ast *result = alloc_ast_node(f, Ast_Field); - result->Field.names = names; + result->Field.names = slice_from_array(names); result->Field.type = type; result->Field.default_value = default_value; result->Field.flags = flags; @@ -918,10 +929,10 @@ Ast *ast_field(AstFile *f, Array names, Ast *type, Ast *default_value, u3 return result; } -Ast *ast_field_list(AstFile *f, Token token, Array list) { +Ast *ast_field_list(AstFile *f, Token token, Array const &list) { Ast *result = alloc_ast_node(f, Ast_FieldList); result->FieldList.token = token; - result->FieldList.list = list; + result->FieldList.list = slice_from_array(list); return result; } @@ -1002,7 +1013,7 @@ Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) { return result; } -Ast *ast_struct_type(AstFile *f, Token token, Array fields, isize field_count, +Ast *ast_struct_type(AstFile *f, Token token, Slice fields, isize field_count, Ast *polymorphic_params, bool is_packed, bool is_raw_union, Ast *align, Token where_token, Array const &where_clauses) { @@ -1015,38 +1026,38 @@ Ast *ast_struct_type(AstFile *f, Token token, Array fields, isize field_c result->StructType.is_raw_union = is_raw_union; result->StructType.align = align; result->StructType.where_token = where_token; - result->StructType.where_clauses = where_clauses; + result->StructType.where_clauses = slice_from_array(where_clauses); return result; } -Ast *ast_union_type(AstFile *f, Token token, Array variants, Ast *polymorphic_params, Ast *align, bool no_nil, bool maybe, +Ast *ast_union_type(AstFile *f, Token token, Array const &variants, Ast *polymorphic_params, Ast *align, bool no_nil, bool maybe, Token where_token, Array const &where_clauses) { Ast *result = alloc_ast_node(f, Ast_UnionType); result->UnionType.token = token; - result->UnionType.variants = variants; + result->UnionType.variants = slice_from_array(variants); result->UnionType.polymorphic_params = polymorphic_params; result->UnionType.align = align; result->UnionType.no_nil = no_nil; - result->UnionType.maybe = maybe; + result->UnionType.maybe = maybe; result->UnionType.where_token = where_token; - result->UnionType.where_clauses = where_clauses; + result->UnionType.where_clauses = slice_from_array(where_clauses); return result; } -Ast *ast_enum_type(AstFile *f, Token token, Ast *base_type, Array fields) { +Ast *ast_enum_type(AstFile *f, Token token, Ast *base_type, Array const &fields) { Ast *result = alloc_ast_node(f, Ast_EnumType); result->EnumType.token = token; result->EnumType.base_type = base_type; - result->EnumType.fields = fields; + result->EnumType.fields = slice_from_array(fields); return result; } -Ast *ast_bit_field_type(AstFile *f, Token token, Array fields, Ast *align) { +Ast *ast_bit_field_type(AstFile *f, Token token, Array const &fields, Ast *align) { Ast *result = alloc_ast_node(f, Ast_BitFieldType); result->BitFieldType.token = token; - result->BitFieldType.fields = fields; + result->BitFieldType.fields = slice_from_array(fields); result->BitFieldType.align = align; return result; } @@ -1069,7 +1080,7 @@ Ast *ast_map_type(AstFile *f, Token token, Ast *key, Ast *value) { Ast *ast_foreign_block_decl(AstFile *f, Token token, Ast *foreign_library, Ast *body, - CommentGroup *docs) { + CommentGroup *docs) { Ast *result = alloc_ast_node(f, Ast_ForeignBlockDecl); result->ForeignBlockDecl.token = token; result->ForeignBlockDecl.foreign_library = foreign_library; @@ -1087,12 +1098,12 @@ Ast *ast_label_decl(AstFile *f, Token token, Ast *name) { return result; } -Ast *ast_value_decl(AstFile *f, Array names, Ast *type, Array values, bool is_mutable, +Ast *ast_value_decl(AstFile *f, Array const &names, Ast *type, Array const &values, bool is_mutable, CommentGroup *docs, CommentGroup *comment) { Ast *result = alloc_ast_node(f, Ast_ValueDecl); - result->ValueDecl.names = names; + result->ValueDecl.names = slice_from_array(names); result->ValueDecl.type = type; - result->ValueDecl.values = values; + result->ValueDecl.values = slice_from_array(values); result->ValueDecl.is_mutable = is_mutable; result->ValueDecl.docs = docs; result->ValueDecl.comment = comment; @@ -1126,7 +1137,7 @@ Ast *ast_foreign_import_decl(AstFile *f, Token token, Array filepaths, To CommentGroup *docs, CommentGroup *comment) { Ast *result = alloc_ast_node(f, Ast_ForeignImportDecl); result->ForeignImportDecl.token = token; - result->ForeignImportDecl.filepaths = filepaths; + result->ForeignImportDecl.filepaths = slice_from_array(filepaths); result->ForeignImportDecl.library_name = library_name; result->ForeignImportDecl.docs = docs; result->ForeignImportDecl.comment = comment; @@ -1136,11 +1147,11 @@ Ast *ast_foreign_import_decl(AstFile *f, Token token, Array filepaths, To } -Ast *ast_attribute(AstFile *f, Token token, Token open, Token close, Array elems) { +Ast *ast_attribute(AstFile *f, Token token, Token open, Token close, Array const &elems) { Ast *result = alloc_ast_node(f, Ast_Attribute); result->Attribute.token = token; result->Attribute.open = open; - result->Attribute.elems = elems; + result->Attribute.elems = slice_from_array(elems); result->Attribute.close = close; return result; } @@ -1192,7 +1203,7 @@ CommentGroup *consume_comment_group(AstFile *f, isize n, isize *end_line_) { CommentGroup *comments = nullptr; if (list.count > 0) { comments = gb_alloc_item(heap_allocator(), CommentGroup); - comments->list = list; + comments->list = slice_from_array(list); array_add(&f->comments, comments); } return comments; @@ -2181,7 +2192,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { Ast *fields = parse_struct_field_list(f, &name_count); Token close = expect_token(f, Token_CloseBrace); - Array decls = {}; + Slice decls = {}; if (fields != nullptr) { GB_ASSERT(fields->kind == Ast_FieldList); decls = fields->FieldList.list; @@ -4887,7 +4898,7 @@ bool determine_path_from_string(gbMutex *file_mutex, Ast *node, String base_dir, -void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array &decls); +void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Slice &decls); void parse_setup_file_when_stmt(Parser *p, AstFile *f, String base_dir, AstWhenStmt *ws) { if (ws->body != nullptr) { @@ -4908,7 +4919,7 @@ void parse_setup_file_when_stmt(Parser *p, AstFile *f, String base_dir, AstWhenS } } -void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array &decls) { +void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Slice &decls) { for_array(i, decls) { Ast *node = decls[i]; if (!is_ast_decl(node) && @@ -4947,8 +4958,7 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array } else if (node->kind == Ast_ForeignImportDecl) { ast_node(fl, ForeignImportDecl, node); - fl->fullpaths.allocator = heap_allocator(); - array_reserve(&fl->fullpaths, fl->filepaths.count); + auto fullpaths = array_make(permanent_allocator(), 0, fl->filepaths.count); for_array(fp_idx, fl->filepaths) { String file_str = fl->filepaths[fp_idx].string; @@ -4962,14 +4972,17 @@ void parse_setup_file_decls(Parser *p, AstFile *f, String base_dir, Array } fullpath = foreign_path; } - array_add(&fl->fullpaths, fullpath); + array_add(&fullpaths, fullpath); } - if (fl->fullpaths.count == 0) { + if (fullpaths.count == 0) { syntax_error(decls[i], "No foreign paths found"); decls[i] = ast_bad_decl(f, fl->filepaths[0], fl->filepaths[fl->filepaths.count-1]); goto end; } + fl->fullpaths = slice_from_array(fullpaths); + + } else if (node->kind == Ast_WhenStmt) { ast_node(ws, WhenStmt, node); parse_setup_file_when_stmt(p, f, base_dir, ws); @@ -5131,12 +5144,12 @@ bool parse_file(Parser *p, AstFile *f) { f->pkg_decl = pd; if (f->error_count == 0) { - f->decls = array_make(heap_allocator()); + auto decls = array_make(heap_allocator()); while (f->curr_token.kind != Token_EOF) { Ast *stmt = parse_stmt(f); if (stmt && stmt->kind != Ast_EmptyStmt) { - array_add(&f->decls, stmt); + array_add(&decls, stmt); if (stmt->kind == Ast_ExprStmt && stmt->ExprStmt.expr != nullptr && stmt->ExprStmt.expr->kind == Ast_ProcLit) { @@ -5145,6 +5158,8 @@ bool parse_file(Parser *p, AstFile *f) { } } + f->decls = slice_from_array(decls); + parse_setup_file_decls(p, f, base_dir, f->decls); } diff --git a/src/parser.hpp b/src/parser.hpp index 9a7ddd4b9..3be7939fa 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -46,7 +46,7 @@ enum ParseFileError { }; struct CommentGroup { - Array list; // Token_Comment + Slice list; // Token_Comment }; @@ -98,8 +98,8 @@ struct AstFile { bool in_foreign_block; bool allow_type; - Array decls; - Array imports; // 'import' 'using import' + Slice decls; + Array imports; // 'import' isize directive_count; Ast * curr_proc; @@ -277,7 +277,6 @@ char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = { AST_KIND(Undef, "undef", Token) \ AST_KIND(BasicLit, "basic literal", struct { \ Token token; \ - ExactValue value; \ }) \ AST_KIND(BasicDirective, "basic directive", struct { \ Token token; \ @@ -291,7 +290,7 @@ char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = { Token token; \ Token open; \ Token close; \ - Array args; \ + Slice args; \ }) \ AST_KIND(ProcLit, "procedure literal", struct { \ Ast *type; \ @@ -299,12 +298,12 @@ char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = { u64 tags; \ ProcInlining inlining; \ Token where_token; \ - Array where_clauses; \ + Slice where_clauses; \ DeclInfo *decl; \ }) \ AST_KIND(CompoundLit, "compound literal", struct { \ Ast *type; \ - Array elems; \ + Slice elems; \ Token open, close; \ i64 max_count; \ }) \ @@ -327,7 +326,7 @@ AST_KIND(_ExprBegin, "", bool) \ }) \ AST_KIND(CallExpr, "call expression", struct { \ Ast * proc; \ - Array args; \ + Slice args; \ Token open; \ Token close; \ Token ellipsis; \ @@ -344,7 +343,7 @@ AST_KIND(_ExprBegin, "", bool) \ AST_KIND(InlineAsmExpr, "inline asm expression", struct { \ Token token; \ Token open, close; \ - Array param_types; \ + Slice param_types; \ Ast *return_type; \ Ast *asm_string; \ Ast *constraints_string; \ @@ -364,11 +363,11 @@ AST_KIND(_StmtBegin, "", bool) \ }) \ AST_KIND(AssignStmt, "assign statement", struct { \ Token op; \ - Array lhs, rhs; \ + Slice lhs, rhs; \ }) \ AST_KIND(_ComplexStmtBegin, "", bool) \ AST_KIND(BlockStmt, "block statement", struct { \ - Array stmts; \ + Slice stmts; \ Ast *label; \ Token open, close; \ }) \ @@ -390,7 +389,7 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ }) \ AST_KIND(ReturnStmt, "return statement", struct { \ Token token; \ - Array results; \ + Slice results; \ }) \ AST_KIND(ForStmt, "for statement", struct { \ Token token; \ @@ -420,8 +419,8 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ }) \ AST_KIND(CaseClause, "case clause", struct { \ Token token; \ - Array list; \ - Array stmts; \ + Slice list; \ + Slice stmts; \ Entity *implicit_entity; \ }) \ AST_KIND(SwitchStmt, "switch statement", struct { \ @@ -438,12 +437,12 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ Ast *tag; \ Ast *body; \ bool partial; \ -}) \ + }) \ AST_KIND(DeferStmt, "defer statement", struct { Token token; Ast *stmt; }) \ AST_KIND(BranchStmt, "branch statement", struct { Token token; Ast *label; }) \ AST_KIND(UsingStmt, "using statement", struct { \ Token token; \ - Array list; \ + Slice list; \ }) \ AST_KIND(_ComplexStmtEnd, "", bool) \ AST_KIND(_StmtEnd, "", bool) \ @@ -461,9 +460,9 @@ AST_KIND(_DeclBegin, "", bool) \ Ast *name; \ }) \ AST_KIND(ValueDecl, "value declaration", struct { \ - Array names; \ + Slice names; \ Ast * type; \ - Array values; \ + Slice values; \ Array attributes; \ CommentGroup *docs; \ CommentGroup *comment; \ @@ -488,10 +487,10 @@ AST_KIND(_DeclBegin, "", bool) \ }) \ AST_KIND(ForeignImportDecl, "foreign import declaration", struct { \ Token token; \ - Array filepaths; \ + Slice filepaths; \ Token library_name; \ String collection_name; \ - Array fullpaths; \ + Slice fullpaths; \ Array attributes; \ CommentGroup *docs; \ CommentGroup *comment; \ @@ -499,11 +498,11 @@ AST_KIND(_DeclBegin, "", bool) \ AST_KIND(_DeclEnd, "", bool) \ AST_KIND(Attribute, "attribute", struct { \ Token token; \ - Array elems; \ + Slice elems; \ Token open, close; \ }) \ AST_KIND(Field, "field", struct { \ - Array names; \ + Slice names; \ Ast * type; \ Ast * default_value; \ Token tag; \ @@ -513,7 +512,7 @@ AST_KIND(_DeclEnd, "", bool) \ }) \ AST_KIND(FieldList, "field list", struct { \ Token token; \ - Array list; \ + Slice list; \ }) \ AST_KIND(_TypeBegin, "", bool) \ AST_KIND(TypeidType, "typeid", struct { \ @@ -567,34 +566,34 @@ AST_KIND(_TypeBegin, "", bool) \ }) \ AST_KIND(StructType, "struct type", struct { \ Token token; \ - Array fields; \ + Slice fields; \ isize field_count; \ Ast *polymorphic_params; \ Ast *align; \ Token where_token; \ - Array where_clauses; \ + Slice where_clauses; \ bool is_packed; \ bool is_raw_union; \ }) \ AST_KIND(UnionType, "union type", struct { \ Token token; \ - Array variants; \ + Slice variants; \ Ast *polymorphic_params; \ Ast * align; \ bool maybe; \ bool no_nil; \ Token where_token; \ - Array where_clauses; \ + Slice where_clauses; \ }) \ AST_KIND(EnumType, "enum type", struct { \ Token token; \ Ast * base_type; \ - Array fields; /* FieldValue */ \ + Slice fields; /* FieldValue */ \ bool is_using; \ }) \ AST_KIND(BitFieldType, "bit field type", struct { \ Token token; \ - Array fields; /* FieldValue with : */ \ + Slice fields; /* FieldValue with : */ \ Ast * align; \ }) \ AST_KIND(BitSetType, "bit set type", struct { \ -- cgit v1.2.3 From 2bd0fd932a4eb1c2e6bc8702450c230186bb3c44 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 17 Nov 2020 18:50:30 +0000 Subject: Begin rudimentary work on implementing `odin test` tooling with `*_test.odin` files --- src/build_settings.cpp | 18 ++++++++++++++++-- src/checker.cpp | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/checker.hpp | 2 ++ src/ir.cpp | 13 ++++++++++--- src/llvm_backend.cpp | 18 ++++++++++++++---- src/main.cpp | 15 ++++++++++----- src/parser.hpp | 2 ++ 7 files changed, 102 insertions(+), 16 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 0e8f2c5bc..35dc9a7c1 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -111,9 +111,10 @@ enum CommandKind : u32 { Command_query = 1<<4, Command_doc = 1<<5, Command_version = 1<<6, + Command_test = 1<<7, - Command__does_check = Command_run|Command_build|Command_check|Command_query|Command_doc, - Command__does_build = Command_run|Command_build, + Command__does_check = Command_run|Command_build|Command_check|Command_query|Command_doc|Command_test, + Command__does_build = Command_run|Command_build|Command_test, Command_all = ~(u32)0, }; @@ -333,6 +334,19 @@ bool is_excluded_target_filename(String name) { String original_name = name; name = remove_extension_from_path(name); + if (string_starts_with(name, str_lit("."))) { + // Ignore .*.odin files + return true; + } + + String test_suffix = str_lit("_test"); + if (build_context.command_kind != Command_test) { + if (string_ends_with(name, test_suffix) && name != test_suffix) { + // Ignore *_test.odin files + return true; + } + } + String str1 = {}; String str2 = {}; isize n = 0; diff --git a/src/checker.cpp b/src/checker.cpp index 88aed4c62..61b1e4bae 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -839,6 +839,8 @@ void init_checker_info(CheckerInfo *i) { array_init(&i->variable_init_order, a); array_init(&i->required_foreign_imports_through_force, a); array_init(&i->required_global_variables, a); + array_init(&i->testing_procedures, a, 0, 0); + i->allow_identifier_uses = build_context.query_data_set_settings.kind == QueryDataSet_GoToDefinitions; if (i->allow_identifier_uses) { @@ -1854,7 +1856,50 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { } } - add_dependency_to_set(c, start); + if (build_context.command_kind == Command_test) { + AstPackage *pkg = c->info.init_package; + Scope *s = pkg->scope; + for_array(i, s->elements.entries) { + Entity *e = s->elements.entries[i].value; + if (e->kind != Entity_Procedure) { + continue; + } + String name = e->token.string; + String prefix = str_lit("test_"); + + + if (!string_starts_with(name, prefix)) { + continue; + } + + bool is_tester = false; + if (name != prefix) { + is_tester = true; + } else { + if (e->file && e->file->is_test) { + error(e->token, "Invalid testing procedure name: %.*s", LIT(name)); + } + } + + Type *t = base_type(e->type); + GB_ASSERT(t->kind == Type_Proc); + if (t->Proc.param_count == 0 && t->Proc.result_count == 0) { + // Good + } else { + gbString str = type_to_string(t); + error(e->token, "Testing procedures must have a signature type of proc(), got %s", str); + gb_string_free(str); + is_tester = false; + } + + if (is_tester) { + add_dependency_to_set(c, e); + array_add(&c->info.testing_procedures, e); + } + } + } else { + add_dependency_to_set(c, start); + } } bool is_entity_a_dependency(Entity *e) { @@ -4344,6 +4389,7 @@ void check_parsed_files(Checker *c) { string_map_set(&c->info.packages, p->fullpath, p); if (scope->flags&ScopeFlag_Init) { + c->info.init_package = p; c->info.init_scope = scope; } if (p->kind == Package_Runtime) { @@ -4613,7 +4659,7 @@ void check_parsed_files(Checker *c) { TIME_SECTION("check entry point"); - if (build_context.build_mode == BuildMode_Executable && !build_context.no_entry_point) { + if (build_context.build_mode == BuildMode_Executable && !build_context.no_entry_point && build_context.command_kind != Command_test) { Scope *s = c->info.init_scope; GB_ASSERT(s != nullptr); GB_ASSERT(s->flags&ScopeFlag_Init); diff --git a/src/checker.hpp b/src/checker.hpp index b986296e0..72c4b148c 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -273,6 +273,7 @@ struct CheckerInfo { AstPackage * builtin_package; AstPackage * runtime_package; + AstPackage * init_package; Scope * init_scope; Entity * entry_point; PtrSet minimum_dependency_set; @@ -283,6 +284,7 @@ struct CheckerInfo { Map atom_op_map; // Key: Ast * + Array testing_procedures; bool allow_identifier_uses; Array identifier_uses; // only used by 'odin query' diff --git a/src/ir.cpp b/src/ir.cpp index 1f2819ccf..819442030 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12781,11 +12781,18 @@ void ir_gen_tree(irGen *s) { ir_fill_slice(proc, global_args, argv, ir_emit_conv(proc, argc, t_int)); ir_emit(proc, ir_alloc_instr(proc, irInstr_StartupRuntime)); - { + Array empty_args = {}; + if (build_context.command_kind == Command_test) { + for_array(i, m->info->testing_procedures) { + Entity *e = m->info->testing_procedures[i]; + irValue **found = map_get(&proc->module->values, hash_entity(e)); + GB_ASSERT(found != nullptr); + ir_emit_call(proc, *found, empty_args); + } + } else { irValue **found = map_get(&proc->module->values, hash_entity(entry_point)); if (found != nullptr) { - Array args = {}; - ir_emit_call(proc, *found, args); + ir_emit_call(proc, *found, empty_args); } } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 50d200551..ea5081be4 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -12875,11 +12875,21 @@ void lb_generate_code(lbGenerator *gen) { lb_begin_procedure_body(p); - lbValue *found = map_get(&m->values, hash_entity(entry_point)); - GB_ASSERT(found != nullptr); - LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, startup_runtime->type)), startup_runtime->value, nullptr, 0, ""); - LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, found->type)), found->value, nullptr, 0, ""); + + if (build_context.command_kind == Command_test) { + for_array(i, m->info->testing_procedures) { + Entity *e = m->info->testing_procedures[i]; + lbValue *found = map_get(&m->values, hash_entity(e)); + GB_ASSERT(found != nullptr); + lb_emit_call(p, *found, {}); + } + } else { + lbValue *found = map_get(&m->values, hash_entity(entry_point)); + GB_ASSERT(found != nullptr); + LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, found->type)), found->value, nullptr, 0, ""); + } + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 0, false)); lb_end_procedure_body(p); diff --git a/src/main.cpp b/src/main.cpp index 5faedbccb..b83c420ae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -675,7 +675,7 @@ ExactValue build_param_to_exact_value(String name, String param) { bool parse_build_flags(Array args) { auto build_flags = array_make(heap_allocator(), 0, BuildFlag_COUNT); add_flag(&build_flags, BuildFlag_Help, str_lit("help"), BuildFlagParam_None, Command_all); - add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build &~ Command_test); add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"), BuildFlagParam_Integer, Command__does_build); add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ShowMoreTimings, str_lit("show-more-timings"), BuildFlagParam_None, Command__does_check); @@ -693,7 +693,7 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build); - add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test); add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_UseLLVMApi, str_lit("llvm-api"), BuildFlagParam_None, Command__does_build); @@ -1540,6 +1540,8 @@ void print_show_help(String const arg0, String const &command) { print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable."); } else if (command == "check") { print_usage_line(1, "check parse and type check .odin file"); + } else if (command == "test") { + print_usage_line(1, "test build ands runs 'test_*' procedures in the initial package"); } else if (command == "query") { print_usage_line(1, "query [experimental] parse, type check, and output a .json file containing information about the program"); } else if (command == "doc") { @@ -1550,9 +1552,9 @@ void print_show_help(String const arg0, String const &command) { bool doc = command == "doc"; bool build = command == "build"; - bool run_or_build = command == "run" || command == "build"; + bool run_or_build = command == "run" || command == "build" || command == "test"; bool check_only = command == "check"; - bool check = command == "run" || command == "build" || command == "check"; + bool check = run_or_build || command == "check"; print_usage_line(0, ""); print_usage_line(1, "Flags"); @@ -1850,12 +1852,15 @@ int main(int arg_count, char const **arg_ptr) { String run_args_string = {}; bool run_output = false; - if (command == "run") { + if (command == "run" || command == "test") { if (args.count < 3) { usage(args[0]); return 1; } build_context.command_kind = Command_run; + if (command == "test") { + build_context.command_kind = Command_test; + } Array run_args = array_make(heap_allocator(), 0, arg_count); defer (array_free(&run_args)); diff --git a/src/parser.hpp b/src/parser.hpp index 3be7939fa..48af0b293 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -107,6 +107,8 @@ struct AstFile { f64 time_to_tokenize; // seconds f64 time_to_parse; // seconds + bool is_test; + CommentGroup *lead_comment; // Comment (block) before the decl CommentGroup *line_comment; // Comment after the semicolon CommentGroup *docs; // current docs -- cgit v1.2.3 From 6416a6f39cce4c65c80e29bb4ff4b93a3e463947 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 20 Nov 2020 16:01:59 +0000 Subject: Allow string literals for `[N]byte` --- src/check_expr.cpp | 6 ++++++ src/ir.cpp | 4 +++- src/ir_print.cpp | 10 +++++++--- src/llvm_backend.cpp | 10 +++++++++- src/parser.hpp | 4 ++-- src/types.cpp | 7 +++++++ 6 files changed, 34 insertions(+), 7 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index aa3d67dae..f258253f5 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2955,6 +2955,12 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { if (check_is_assignable_to(c, operand, elem)) { operand->mode = Addressing_Value; } else { + if (operand->value.kind == ExactValue_String && is_type_u8_array(t)) { + String s = operand->value.value_string; + if (s.len == t->Array.count) { + break; + } + } operand->mode = Addressing_Invalid; convert_untyped_error(c, operand, target_type); return; diff --git a/src/ir.cpp b/src/ir.cpp index 819442030..e8378bb97 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7801,7 +7801,9 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { if (tv.value.kind != ExactValue_Invalid) { // NOTE(bill): Edge case - if (tv.value.kind != ExactValue_Compound && + if (is_type_u8_array(tv.type) && tv.value.kind == ExactValue_String) { + return ir_add_module_constant(proc->module, tv.type, tv.value); + } else if (tv.value.kind != ExactValue_Compound && is_type_array(tv.type)) { Type *elem = core_array_type(tv.type); ExactValue value = convert_exact_value_for_type(tv.value, elem); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 0605058ee..3ca9954ef 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -745,7 +745,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ir_write_byte(f, ']'); return; - } else if (is_type_array(type) && + } else if (is_type_array(type) && value.kind != ExactValue_Invalid && value.kind != ExactValue_String && value.kind != ExactValue_Compound) { @@ -796,7 +796,11 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * GB_ASSERT(is_type_array(type)); ir_write_str_lit(f, "c\""); ir_print_escape_string(f, str, false, false); - ir_write_str_lit(f, "\\00\""); + if (type->Array.count == str.len) { + ir_write_str_lit(f, "\""); + } else { + ir_write_str_lit(f, "\\00\""); + } } else if (is_type_cstring(t)) { // HACK NOTE(bill): This is a hack but it works because strings are created at the very end // of the .ll file @@ -810,7 +814,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ir_write_str_lit(f, ", "); ir_print_type(f, m, t_i32); ir_write_str_lit(f, " 0, i32 0)"); - }else { + } else { // HACK NOTE(bill): This is a hack but it works because strings are created at the very end // of the .ll file irValue *str_array = ir_add_global_string_array(m, str); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index ea5081be4..d47c45401 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -5126,7 +5126,15 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc LLVMValueRef data = LLVMConstStringInContext(ctx, cast(char const *)value.value_string.text, cast(unsigned)value.value_string.len, - false); + false /*DontNullTerminate*/); + res.value = data; + return res; + } else if (is_type_u8_array(type) && value.kind == ExactValue_String) { + GB_ASSERT(type->Array.count == value.value_string.len); + LLVMValueRef data = LLVMConstStringInContext(ctx, + cast(char const *)value.value_string.text, + cast(unsigned)value.value_string.len, + true /*DontNullTerminate*/); res.value = data; return res; } else if (is_type_array(type) && diff --git a/src/parser.hpp b/src/parser.hpp index aa288304e..cd0d59a48 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -646,7 +646,7 @@ struct AstCommonStuff { u16 viral_state_flags; AstFile * file; Scope * scope; - TypeAndValue tav; + TypeAndValue tav; // TODO(bill): Make this a pointer to minimize pointer size }; struct Ast { @@ -655,7 +655,7 @@ struct Ast { u16 viral_state_flags; AstFile * file; Scope * scope; - TypeAndValue tav; + TypeAndValue tav; // TODO(bill): Make this a pointer to minimize pointer size // IMPORTANT NOTE(bill): This must be at the end since the AST is allocated to be size of the variant union { diff --git a/src/types.cpp b/src/types.cpp index 1147beb33..8c39b9979 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1221,6 +1221,13 @@ bool is_type_u8_slice(Type *t) { } return false; } +bool is_type_u8_array(Type *t) { + t = base_type(t); + if (t->kind == Type_Array) { + return is_type_u8(t->Array.elem); + } + return false; +} bool is_type_u8_ptr(Type *t) { t = base_type(t); if (t->kind == Type_Pointer) { -- cgit v1.2.3 From 63e4a2341f1409eec1f2e58036cd01b24b66b8f0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 20 Nov 2020 16:24:23 +0000 Subject: Support string literals for fixed arrays of runes; Add %q support for arrays/slices of bytes --- core/fmt/fmt.odin | 4 ++-- src/check_expr.cpp | 13 ++++++++++--- src/ir.cpp | 8 +++++--- src/ir_print.cpp | 22 ++++++++++++++++++++++ src/llvm_backend.cpp | 26 ++++++++++++++++++++++++++ src/types.cpp | 52 +++++++++++++++++++++++++++++++--------------------- 6 files changed, 96 insertions(+), 29 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index fae380de5..79c62cc17 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1599,7 +1599,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { } case runtime.Type_Info_Array: - if verb == 's' && reflect.is_byte(info.elem) { + if (verb == 's' || verb == 'q') && reflect.is_byte(info.elem) { s := strings.string_from_ptr((^byte)(v.data), info.count); fmt_string(fi, s, verb); } else { @@ -1664,7 +1664,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Slice: slice := cast(^mem.Raw_Slice)v.data; - if verb == 's' && reflect.is_byte(info.elem) { + if (verb == 's' || verb == 'q') && reflect.is_byte(info.elem) { s := strings.string_from_ptr((^byte)(slice.data), slice.len); fmt_string(fi, s, verb); } else if verb == 'p' { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f258253f5..c67ad22b8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2955,10 +2955,17 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { if (check_is_assignable_to(c, operand, elem)) { operand->mode = Addressing_Value; } else { - if (operand->value.kind == ExactValue_String && is_type_u8_array(t)) { + if (operand->value.kind == ExactValue_String) { String s = operand->value.value_string; - if (s.len == t->Array.count) { - break; + if (is_type_u8_array(t)) { + if (s.len == t->Array.count) { + break; + } + } else if (is_type_rune_array(t)) { + isize rune_count = s.len; + if (rune_count == t->Array.count) { + break; + } } } operand->mode = Addressing_Invalid; diff --git a/src/ir.cpp b/src/ir.cpp index e8378bb97..24fe15afb 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7801,9 +7801,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { if (tv.value.kind != ExactValue_Invalid) { // NOTE(bill): Edge case - if (is_type_u8_array(tv.type) && tv.value.kind == ExactValue_String) { - return ir_add_module_constant(proc->module, tv.type, tv.value); - } else if (tv.value.kind != ExactValue_Compound && + if (is_type_u8_array(tv.type) && tv.value.kind == ExactValue_String) { + return ir_add_module_constant(proc->module, tv.type, tv.value); + } else if (is_type_rune_array(tv.type) && tv.value.kind == ExactValue_String) { + return ir_add_module_constant(proc->module, tv.type, tv.value); + } else if (tv.value.kind != ExactValue_Compound && is_type_array(tv.type)) { Type *elem = core_array_type(tv.type); ExactValue value = convert_exact_value_for_type(tv.value, elem); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 3ca9954ef..a6bfc75d3 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -734,6 +734,28 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) { i64 count = type->Array.count; Type *elem = type->Array.elem; + + if (is_type_rune_array(type)) { + Rune rune; + isize offset = 0; + isize width = 1; + String s = value.value_string; + ir_write_byte(f, '['); + for (i64 i = 0; i < count && offset < s.len; i++) { + width = gb_utf8_decode(s.text+offset, s.len-offset, &rune); + if (i > 0) ir_write_str_lit(f, ", "); + ir_print_type(f, m, elem); + ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_i64(rune), elem); + offset += width; + } + GB_ASSERT(offset == s.len); + + ir_write_byte(f, ']'); + return; + } + + ir_write_byte(f, '['); for (i64 i = 0; i < count; i++) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index d47c45401..62a0013bc 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -5123,6 +5123,32 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } } else if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) { + if (is_type_rune_array(type) && value.kind == ExactValue_String) { + i64 count = type->Array.count; + Type *elem = type->Array.elem; + LLVMTypeRef et = lb_type(m, elem); + + Rune rune; + isize offset = 0; + isize width = 1; + String s = value.value_string; + + LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, count); + + for (i64 i = 0; i < count && offset < s.len; i++) { + width = gb_utf8_decode(s.text+offset, s.len-offset, &rune); + offset += width; + + elems[i] = LLVMConstInt(et, rune, true); + + } + GB_ASSERT(offset == s.len); + + res.value = LLVMConstArray(et, elems, cast(unsigned)count); + return res; + } + GB_PANIC("HERE!\n"); + LLVMValueRef data = LLVMConstStringInContext(ctx, cast(char const *)value.value_string.text, cast(unsigned)value.value_string.len, diff --git a/src/types.cpp b/src/types.cpp index 8c39b9979..b381ba9c9 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1214,27 +1214,6 @@ bool is_type_slice(Type *t) { t = base_type(t); return t->kind == Type_Slice; } -bool is_type_u8_slice(Type *t) { - t = base_type(t); - if (t->kind == Type_Slice) { - return is_type_u8(t->Slice.elem); - } - return false; -} -bool is_type_u8_array(Type *t) { - t = base_type(t); - if (t->kind == Type_Array) { - return is_type_u8(t->Array.elem); - } - return false; -} -bool is_type_u8_ptr(Type *t) { - t = base_type(t); - if (t->kind == Type_Pointer) { - return is_type_u8(t->Slice.elem); - } - return false; -} bool is_type_proc(Type *t) { t = base_type(t); return t->kind == Type_Proc; @@ -1278,6 +1257,37 @@ bool is_type_relative_slice(Type *t) { return t->kind == Type_RelativeSlice; } +bool is_type_u8_slice(Type *t) { + t = base_type(t); + if (t->kind == Type_Slice) { + return is_type_u8(t->Slice.elem); + } + return false; +} +bool is_type_u8_array(Type *t) { + t = base_type(t); + if (t->kind == Type_Array) { + return is_type_u8(t->Array.elem); + } + return false; +} +bool is_type_u8_ptr(Type *t) { + t = base_type(t); + if (t->kind == Type_Pointer) { + return is_type_u8(t->Slice.elem); + } + return false; +} +bool is_type_rune_array(Type *t) { + t = base_type(t); + if (t->kind == Type_Array) { + return is_type_rune(t->Array.elem); + } + return false; +} + + + Type *core_array_type(Type *t) { for (;;) { -- cgit v1.2.3 From 9e42cb159543546ca549eeba6c943cf0f4c8410b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 23 Nov 2020 12:20:04 +0000 Subject: Add comparisons to structs where all fields are comparable `==` and `!=` --- core/runtime/internal.odin | 5 +- src/checker.cpp | 1 + src/ir.cpp | 115 ++++++++++++++++++++++++++++++++++++++++++++- src/llvm_abi.cpp | 60 ++++------------------- src/llvm_backend.cpp | 98 ++++++++++++++++++++++++++++++++++++++ src/llvm_backend.hpp | 2 + src/types.cpp | 64 +++++++++++++++++++++++++ 7 files changed, 292 insertions(+), 53 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index cd0c681b3..c313070ac 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -180,8 +180,9 @@ mem_resize :: inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = } return allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, 0, loc); } - - +memory_equal :: proc "contextless" (a, b: rawptr, n: int) -> bool { + return memory_compare(a, b, n) == 0; +} memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check { x := uintptr(a); y := uintptr(b); diff --git a/src/checker.cpp b/src/checker.cpp index 0559fd300..1a5a75152 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1768,6 +1768,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("memcpy"), str_lit("memmove"), + str_lit("memory_equal"), str_lit("memory_compare"), str_lit("memory_compare_zero"), diff --git a/src/ir.cpp b/src/ir.cpp index 24fe15afb..2d244f62c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -24,6 +24,7 @@ struct irModule { Map entity_names; // Key: Entity * of the typename Map debug_info; // Key: Unique pointer Map anonymous_proc_lits; // Key: Ast * + Map compare_procs; // Key: Type * irDebugInfo * debug_compile_unit; Array debug_location_stack; @@ -161,6 +162,7 @@ struct irProcedure { Ast * return_ptr_hint_ast; bool return_ptr_hint_used; + bool ignore_dead_instr; Array branch_blocks; @@ -525,6 +527,8 @@ struct irAddr { Type *ir_type(irValue *value); irValue *ir_gen_anonymous_proc_lit(irModule *m, String prefix_name, Ast *expr, irProcedure *proc = nullptr); +void ir_begin_procedure_body(irProcedure *proc); +void ir_end_procedure_body(irProcedure *proc); irAddr ir_addr(irValue *addr) { irAddr v = {irAddr_Default, addr}; @@ -4859,6 +4863,87 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue return nullptr; } +irValue *ir_get_compare_proc_for_type(irModule *m, Type *type) { + Type *original_type = type; + type = base_type(type); + GB_ASSERT(type->kind == Type_Struct); + type_set_offsets(type); + Type *pt = alloc_type_pointer(type); + + auto key = hash_type(type); + irValue **found = map_get(&m->compare_procs, key); + if (found) { + return *found; + } + static Type *proc_type = nullptr; + if (proc_type == nullptr) { + Type *args[2] = {t_rawptr, t_rawptr}; + proc_type = alloc_type_proc_from_types(args, 2, t_bool, false, ProcCC_Contextless); + set_procedure_abi_types(proc_type); + } + + static u32 proc_index = 0; + + char buf[16] = {}; + isize n = gb_snprintf(buf, 16, "__$cmp%u", ++proc_index); + char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); + String proc_name = make_string_c(str); + + + Ast *body = alloc_ast_node(nullptr, Ast_Invalid); + Entity *e = alloc_entity_procedure(nullptr, make_token_ident(proc_name), proc_type, 0); + e->Procedure.link_name = proc_name; + irValue *p = ir_value_procedure(m, e, proc_type, nullptr, body, proc_name); + map_set(&m->values, hash_entity(e), p); + string_map_set(&m->members, proc_name, p); + + irProcedure *proc = &p->Proc; + proc->is_startup = true; + proc->ignore_dead_instr = true; + ir_begin_procedure_body(proc); + // ir_start_block(proc, proc->decl_block); + GB_ASSERT(proc->curr_block != nullptr); + + irBlock *done = ir_new_block(proc, nullptr, "done"); // NOTE(bill): Append later + + irValue *x = proc->params[0]; + irValue *y = proc->params[1]; + irValue *lhs = ir_emit_conv(proc, x, pt); + irValue *rhs = ir_emit_conv(proc, y, pt); + + irBlock *block_false = ir_new_block(proc, nullptr, "bfalse"); + + for_array(i, type->Struct.fields) { + irBlock *next_block = ir_new_block(proc, nullptr, "btrue"); + + irValue *pleft = ir_emit_struct_ep(proc, lhs, cast(i32)i); + irValue *pright = ir_emit_struct_ep(proc, rhs, cast(i32)i); + irValue *left = ir_emit_load(proc, pleft); + irValue *right = ir_emit_load(proc, pright); + irValue *ok = ir_emit_comp(proc, Token_CmpEq, left, right); + + ir_emit_if(proc, ok, next_block, block_false); + + ir_emit_jump(proc, next_block); + ir_start_block(proc, next_block); + } + + ir_emit_jump(proc, done); + ir_start_block(proc, block_false); + + ir_emit(proc, ir_instr_return(proc, ir_const_bool(false))); + + ir_emit_jump(proc, done); + ir_start_block(proc, done); + ir_emit(proc, ir_instr_return(proc, ir_const_bool(true))); + + ir_end_procedure_body(proc); + + map_set(&m->compare_procs, key, p); + + return p; +} + irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right) { Type *a = base_type(ir_type(left)); Type *b = base_type(ir_type(right)); @@ -4992,6 +5077,30 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal } } + if (is_type_struct(a) && is_type_comparable(a)) { + irValue *left_ptr = ir_address_from_load_or_generate_local(proc, left); + irValue *right_ptr = ir_address_from_load_or_generate_local(proc, right); + irValue *res = {}; + if (is_type_simple_compare(a)) { + // TODO(bill): Test to see if this is actually faster!!!! + auto args = array_make(permanent_allocator(), 3); + args[0] = ir_emit_conv(proc, left_ptr, t_rawptr); + args[1] = ir_emit_conv(proc, right_ptr, t_rawptr); + args[2] = ir_const_int(type_size_of(a)); + res = ir_emit_runtime_call(proc, "memory_equal", args); + } else { + irValue *value = ir_get_compare_proc_for_type(proc->module, a); + auto args = array_make(permanent_allocator(), 2); + args[0] = ir_emit_conv(proc, left_ptr, t_rawptr); + args[1] = ir_emit_conv(proc, right_ptr, t_rawptr); + res = ir_emit_call(proc, value, args); + } + if (op_kind == Token_NotEq) { + res = ir_emit_unary_arith(proc, Token_Not, res, ir_type(res)); + } + return res; + } + if (is_type_string(a)) { if (is_type_cstring(a)) { left = ir_emit_conv(proc, left, t_string); @@ -11350,6 +11459,9 @@ void ir_begin_procedure_body(irProcedure *proc) { bool ir_remove_dead_instr(irProcedure *proc) { + if (proc->ignore_dead_instr) { + return false; + } isize elimination_count = 0; retry: #if 1 @@ -11476,7 +11588,7 @@ void ir_build_proc(irValue *value, irProcedure *parent) { proc->parent = parent; - if (proc->body != nullptr) { + if (proc->body != nullptr && proc->body->kind != Ast_Invalid) { u64 prev_state_flags = proc->module->state_flags; if (proc->tags != 0) { @@ -11578,6 +11690,7 @@ void ir_init_module(irModule *m, Checker *c) { map_init(&m->debug_info, heap_allocator()); map_init(&m->entity_names, heap_allocator()); map_init(&m->anonymous_proc_lits, heap_allocator()); + map_init(&m->compare_procs, heap_allocator()); array_init(&m->procs, heap_allocator()); array_init(&m->procs_to_generate, heap_allocator()); array_init(&m->foreign_library_paths, heap_allocator()); diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 7521ba2f7..77d4b42b0 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -267,56 +267,6 @@ i64 lb_alignof(LLVMTypeRef type) { return 1; } -Type *alloc_type_struct_from_field_types(Type **field_types, isize field_count, bool is_packed) { - Type *t = alloc_type_struct(); - t->Struct.fields = array_make(heap_allocator(), field_count); - - Scope *scope = nullptr; - for_array(i, t->Struct.fields) { - t->Struct.fields[i] = alloc_entity_field(scope, blank_token, field_types[i], false, cast(i32)i, EntityState_Resolved); - } - t->Struct.is_packed = is_packed; - - return t; -} - -Type *alloc_type_tuple_from_field_types(Type **field_types, isize field_count, bool is_packed, bool must_be_tuple) { - if (field_count == 0) { - return nullptr; - } - if (!must_be_tuple && field_count == 1) { - return field_types[0]; - } - - Type *t = alloc_type_tuple(); - t->Tuple.variables = array_make(heap_allocator(), field_count); - - Scope *scope = nullptr; - for_array(i, t->Tuple.variables) { - t->Tuple.variables[i] = alloc_entity_param(scope, blank_token, field_types[i], false, false); - } - t->Tuple.is_packed = is_packed; - - return t; -} - -Type *alloc_type_proc_from_types(Type **param_types, unsigned param_count, Type *results, bool is_c_vararg) { - - Type *params = alloc_type_tuple_from_field_types(param_types, param_count, false, true); - isize results_count = 0; - if (results != nullptr) { - if (results->kind != Type_Tuple) { - results = alloc_type_tuple_from_field_types(&results, 1, false, true); - } - results_count = results->Tuple.variables.count; - } - - Scope *scope = nullptr; - Type *t = alloc_type_proc(scope, params, param_count, results, results_count, false, /*not sure what to put here*/ProcCC_CDecl); - t->Proc.c_vararg = is_c_vararg; - return t; -} - #if 0 Type *lb_abi_to_odin_type(lbModule *m, LLVMTypeRef type, bool is_return, u32 level = 0) { Type **found = map_get(&m->llvm_types, hash_pointer(type)); @@ -959,6 +909,16 @@ namespace lbAbiAmd64SysV { }; +namespace lbAbiAarch64 { + LB_ABI_INFO(abi_info) { + lbFunctionType *ft = gb_alloc_item(heap_allocator(), lbFunctionType); + ft->ctx = c; + // ft->args = compute_arg_types(c, arg_types, arg_count); + // ft->ret = lbAbi386::compute_return_type(c, return_type, return_is_defined); + // ft->calling_convention = calling_convention; + return ft; + } +} LB_ABI_INFO(lb_get_abi_info) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 89a0ff667..665f9570a 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -9143,6 +9143,78 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { return {}; } +lbValue lb_get_compare_proc_for_type(lbModule *m, Type *type) { + Type *original_type = type; + type = base_type(type); + GB_ASSERT(type->kind == Type_Struct); + type_set_offsets(type); + Type *pt = alloc_type_pointer(type); + LLVMTypeRef ptr_type = lb_type(m, pt); + + auto key = hash_type(type); + lbProcedure **found = map_get(&m->compare_procs, key); + lbProcedure *compare_proc = nullptr; + if (found) { + compare_proc = *found; + } else { + static Type *proc_type = nullptr; + if (proc_type == nullptr) { + Type *args[2] = {t_rawptr, t_rawptr}; + proc_type = alloc_type_proc_from_types(args, 2, t_bool, false, ProcCC_Contextless); + set_procedure_abi_types(proc_type); + } + + static u32 proc_index = 0; + + char buf[16] = {}; + isize n = gb_snprintf(buf, 16, "__$cmp%u", ++proc_index); + char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); + String proc_name = make_string_c(str); + + lbProcedure *p = lb_create_dummy_procedure(m, proc_name, proc_type); + lb_begin_procedure_body(p); + + LLVMValueRef x = LLVMGetParam(p->value, 0); + LLVMValueRef y = LLVMGetParam(p->value, 1); + x = LLVMBuildPointerCast(p->builder, x, ptr_type, ""); + y = LLVMBuildPointerCast(p->builder, y, ptr_type, ""); + lbValue lhs = {x, pt}; + lbValue rhs = {y, pt}; + + lbBlock *block_false = lb_create_block(p, "bfalse"); + + lbValue res = lb_const_bool(m, t_bool, true); + for_array(i, type->Struct.fields) { + lbBlock *next_block = lb_create_block(p, "btrue"); + + lbValue pleft = lb_emit_struct_ep(p, lhs, cast(i32)i); + lbValue pright = lb_emit_struct_ep(p, rhs, cast(i32)i); + lbValue left = lb_emit_load(p, pleft); + lbValue right = lb_emit_load(p, pright); + lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + + lb_emit_if(p, ok, next_block, block_false); + + lb_emit_jump(p, next_block); + lb_start_block(p, next_block); + } + + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); + + lb_start_block(p, block_false); + + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 0, false)); + + lb_end_procedure_body(p); + + map_set(&m->compare_procs, key, p); + + compare_proc = p; + } + GB_ASSERT(compare_proc != nullptr); + + return {compare_proc->value, compare_proc->type}; +} lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right) { Type *a = core_type(left.type); @@ -9272,6 +9344,31 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } } + + if (is_type_struct(a) && is_type_comparable(a)) { + lbValue left_ptr = lb_address_from_load_or_generate_local(p, left); + lbValue right_ptr = lb_address_from_load_or_generate_local(p, right); + lbValue res = {}; + if (is_type_simple_compare(a)) { + // TODO(bill): Test to see if this is actually faster!!!! + auto args = array_make(permanent_allocator(), 3); + args[0] = lb_emit_conv(p, left_ptr, t_rawptr); + args[1] = lb_emit_conv(p, right_ptr, t_rawptr); + args[2] = lb_const_int(p->module, t_int, type_size_of(a)); + res = lb_emit_runtime_call(p, "memory_equal", args); + } else { + lbValue value = lb_get_compare_proc_for_type(p->module, a); + auto args = array_make(permanent_allocator(), 2); + args[0] = lb_emit_conv(p, left_ptr, t_rawptr); + args[1] = lb_emit_conv(p, right_ptr, t_rawptr); + res = lb_emit_call(p, value, args); + } + if (op_kind == Token_NotEq) { + res = lb_emit_unary_arith(p, Token_Not, res, res.type); + } + return res; + } + if (is_type_string(a)) { if (is_type_cstring(a)) { left = lb_emit_conv(p, left, t_string); @@ -11442,6 +11539,7 @@ void lb_init_module(lbModule *m, Checker *c) { string_map_init(&m->const_strings, a); map_init(&m->anonymous_proc_lits, a); map_init(&m->function_type_map, a); + map_init(&m->compare_procs, a); array_init(&m->procedures_to_generate, a); array_init(&m->foreign_library_paths, a); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 289f9d324..388176e9a 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -87,6 +87,8 @@ struct lbModule { Map anonymous_proc_lits; // Key: Ast * Map function_type_map; // Key: Type * + Map compare_procs; // Key: Type * + u32 global_array_index; u32 global_generated_index; u32 nested_type_name_guid; diff --git a/src/types.cpp b/src/types.cpp index b381ba9c9..80812e94b 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1942,6 +1942,15 @@ bool is_type_comparable(Type *t) { case Type_Opaque: return is_type_comparable(t->Opaque.elem); + + case Type_Struct: + for_array(i, t->Struct.fields) { + Entity *f = t->Struct.fields[i]; + if (!is_type_comparable(f->type)) { + return false; + } + } + return true; } return false; } @@ -3401,6 +3410,58 @@ Type *reduce_tuple_to_single_type(Type *original_type) { } +Type *alloc_type_struct_from_field_types(Type **field_types, isize field_count, bool is_packed) { + Type *t = alloc_type_struct(); + t->Struct.fields = array_make(heap_allocator(), field_count); + + Scope *scope = nullptr; + for_array(i, t->Struct.fields) { + t->Struct.fields[i] = alloc_entity_field(scope, blank_token, field_types[i], false, cast(i32)i, EntityState_Resolved); + } + t->Struct.is_packed = is_packed; + + return t; +} + +Type *alloc_type_tuple_from_field_types(Type **field_types, isize field_count, bool is_packed, bool must_be_tuple) { + if (field_count == 0) { + return nullptr; + } + if (!must_be_tuple && field_count == 1) { + return field_types[0]; + } + + Type *t = alloc_type_tuple(); + t->Tuple.variables = array_make(heap_allocator(), field_count); + + Scope *scope = nullptr; + for_array(i, t->Tuple.variables) { + t->Tuple.variables[i] = alloc_entity_param(scope, blank_token, field_types[i], false, false); + } + t->Tuple.is_packed = is_packed; + + return t; +} + +Type *alloc_type_proc_from_types(Type **param_types, unsigned param_count, Type *results, bool is_c_vararg, ProcCallingConvention calling_convention) { + + Type *params = alloc_type_tuple_from_field_types(param_types, param_count, false, true); + isize results_count = 0; + if (results != nullptr) { + if (results->kind != Type_Tuple) { + results = alloc_type_tuple_from_field_types(&results, 1, false, true); + } + results_count = results->Tuple.variables.count; + } + + Scope *scope = nullptr; + Type *t = alloc_type_proc(scope, params, param_count, results, results_count, false, calling_convention); + t->Proc.c_vararg = is_c_vararg; + return t; +} + + + gbString write_type_to_string(gbString str, Type *type) { if (type == nullptr) { return gb_string_appendc(str, ""); @@ -3719,3 +3780,6 @@ gbString type_to_string(Type *type) { return write_type_to_string(gb_string_make(heap_allocator(), ""), type); } + + + -- cgit v1.2.3 From 0b30c3dc5ad3f3908719af19e9f7e61daae37706 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 23 Nov 2020 14:35:31 +0000 Subject: Add `flags: Type_Info_Flags,` to `runtime.Type_Info` --- core/runtime/core.odin | 7 +++++++ src/checker.cpp | 5 +++-- src/checker.hpp | 4 ++++ src/ir.cpp | 9 +++++++-- src/llvm_backend.cpp | 10 ++++++++-- src/types.cpp | 23 +++++++++++++++++++++++ 6 files changed, 52 insertions(+), 6 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/runtime/core.odin b/core/runtime/core.odin index dfbe0d053..2989c4700 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -149,9 +149,16 @@ Type_Info_Relative_Slice :: struct { base_integer: ^Type_Info, }; +Type_Info_Flag :: enum u8 { + Comparable = 0, + Simple_Compare = 1, +}; +Type_Info_Flags :: distinct bit_set[Type_Info_Flag; u32]; + Type_Info :: struct { size: int, align: int, + flags: Type_Info_Flags, id: typeid, variant: union { diff --git a/src/checker.cpp b/src/checker.cpp index 1a5a75152..bba790cb2 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -899,6 +899,7 @@ bool init_checker(Checker *c, Parser *parser) { gbAllocator a = heap_allocator(); init_checker_info(&c->info); + c->info.checker = c; array_init(&c->procs_to_check, a); array_init(&c->procs_with_deferred_to_check, a); @@ -2179,9 +2180,9 @@ void init_core_type_info(Checker *c) { t_type_info_enum_value = type_info_enum_value->type; t_type_info_enum_value_ptr = alloc_type_pointer(t_type_info_enum_value); - GB_ASSERT(tis->fields.count == 4); + GB_ASSERT(tis->fields.count == 5); - Entity *type_info_variant = tis->fields[3]; + Entity *type_info_variant = tis->fields[4]; Type *tiv_type = type_info_variant->type; GB_ASSERT(is_type_union(tiv_type)); diff --git a/src/checker.hpp b/src/checker.hpp index 72c4b148c..168c00d33 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -252,8 +252,12 @@ struct AtomOpMapEntry { }; +struct CheckerContext; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { + Checker *checker; + Map untyped; // Key: Ast * | Expression -> ExprInfo // NOTE(bill): This needs to be a map and not on the Ast // as it needs to be iterated across diff --git a/src/ir.cpp b/src/ir.cpp index 2d244f62c..ce5dea86d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11974,6 +11974,8 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info // Useful types Type *t_i64_slice_ptr = alloc_type_pointer(alloc_type_slice(t_i64)); Type *t_string_slice_ptr = alloc_type_pointer(alloc_type_slice(t_string)); + Entity *type_info_flags_entity = find_core_entity(info->checker, str_lit("Type_Info_Flags")); + Type *t_type_info_flags = type_info_flags_entity->type; i32 type_info_member_types_index = 0; i32 type_info_member_names_index = 0; @@ -11993,11 +11995,14 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info irValue *tag = nullptr; irValue *ti_ptr = ir_emit_array_epi(proc, ir_global_type_info_data, cast(i32)entry_index); - irValue *variant_ptr = ir_emit_struct_ep(proc, ti_ptr, 3); + irValue *variant_ptr = ir_emit_struct_ep(proc, ti_ptr, 4); + + irValue *type_info_flags = ir_value_constant(t_type_info_flags, exact_value_i64(type_info_flags_of_type(t))); ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 0), ir_const_int(type_size_of(t))); ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 1), ir_const_int(type_align_of(t))); - ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 2), ir_typeid(proc->module, t)); + ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 2), type_info_flags); + ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 3), ir_typeid(proc->module, t)); switch (t->kind) { diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 665f9570a..a2727b012 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -11732,6 +11732,9 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da // Useful types Type *t_i64_slice_ptr = alloc_type_pointer(alloc_type_slice(t_i64)); Type *t_string_slice_ptr = alloc_type_pointer(alloc_type_slice(t_string)); + Entity *type_info_flags_entity = find_core_entity(info->checker, str_lit("Type_Info_Flags")); + Type *t_type_info_flags = type_info_flags_entity->type; + i32 type_info_member_types_index = 0; i32 type_info_member_names_index = 0; @@ -11751,11 +11754,14 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue tag = {}; lbValue ti_ptr = lb_emit_array_epi(p, lb_global_type_info_data.addr, cast(i32)entry_index); - lbValue variant_ptr = lb_emit_struct_ep(p, ti_ptr, 3); + lbValue variant_ptr = lb_emit_struct_ep(p, ti_ptr, 4); + + lbValue type_info_flags = lb_const_int(p->module, t_type_info_flags, type_info_flags_of_type(t)); lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 0), lb_const_int(m, t_int, type_size_of(t))); lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 1), lb_const_int(m, t_int, type_align_of(t))); - lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 2), lb_typeid(m, t)); + lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 2), type_info_flags); + lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 3), lb_typeid(m, t)); switch (t->kind) { diff --git a/src/types.cpp b/src/types.cpp index 80812e94b..09888f878 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -373,7 +373,28 @@ enum Typeid_Kind : u8 { Typeid_Relative_Slice, }; +// IMPORTANT NOTE(bill): This must match the same as the in core.odin +enum TypeInfoFlag : u32 { + TypeInfoFlag_Comparable = 1<<0, + TypeInfoFlag_Simple_Compare = 1<<1, +}; +bool is_type_comparable(Type *t); +bool is_type_simple_compare(Type *t); + +u32 type_info_flags_of_type(Type *type) { + if (type == nullptr) { + return 0; + } + u32 flags = 0; + if (is_type_comparable(type)) { + flags |= TypeInfoFlag_Comparable; + } + if (is_type_simple_compare(type)) { + flags |= TypeInfoFlag_Comparable; + } + return flags; +} // TODO(bill): Should I add extra information here specifying the kind of selection? @@ -1348,6 +1369,8 @@ bool is_type_simple_compare(Type *t) { return false; } + + Type *base_complex_elem_type(Type *t) { t = core_type(t); if (t->kind == Type_Basic) { -- cgit v1.2.3 From 4e370e6ed8d6cfe3dee306dfbc298ba68722f12e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 23 Nov 2020 15:53:49 +0000 Subject: Add `equal` procedure field to `runtime.Type_Info_Struct` --- core/reflect/reflect.odin | 78 +++++++++++++++++++++++++++++++++++++ core/runtime/core.odin | 5 +++ src/ir.cpp | 11 ++++-- src/llvm_backend.cpp | 14 ++++--- src/types.cpp | 97 ++++++++++++++++++++++++----------------------- 5 files changed, 149 insertions(+), 56 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 947a10771..df183e2fd 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -1206,3 +1206,81 @@ as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) { return; } + + +not_equal :: proc(a, b: any) -> bool { + return !equal(a, b); +} +equal :: proc(a, b: any) -> bool { + if a == nil && b == nil { + return true; + } + + if a.id != b.id { + return false; + } + + if a.data == b.data { + return true; + } + + t := type_info_of(a.id); + if .Comparable not_in t.flags { + return false; + } + + if t.size == 0 { + return true; + } + + if .Simple_Compare in t.flags { + return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0; + } + + t = runtime.type_info_core(t); + + #partial switch v in t.variant { + case Type_Info_String: + if v.is_cstring { + x := string((^cstring)(a.data)^); + y := string((^cstring)(b.data)^); + return x == y; + } else { + x := (^string)(a.data)^; + y := (^string)(b.data)^; + return x == y; + } + + case Type_Info_Array: + for i in 0.. bool; Type_Info_Struct :: struct { types: []^Type_Info, names: []string, @@ -97,6 +99,9 @@ Type_Info_Struct :: struct { is_packed: bool, is_raw_union: bool, custom_align: bool, + + equal: Type_Struct_Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set + // These are only set iff this structure is an SOA structure soa_kind: Type_Info_Struct_Soa_Kind, soa_base_type: ^Type_Info, diff --git a/src/ir.cpp b/src/ir.cpp index ce5dea86d..28edd5981 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12353,8 +12353,13 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align); + if (is_type_comparable(t) && !is_type_simple_compare(t)) { + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 8), ir_get_compare_proc_for_type(proc->module, t)); + } + + if (t->Struct.soa_kind != StructSoa_None) { - irValue *kind = ir_emit_struct_ep(proc, tag, 8); + irValue *kind = ir_emit_struct_ep(proc, tag, 9); Type *kind_type = type_deref(ir_type(kind)); irValue *soa_kind = ir_value_constant(kind_type, exact_value_i64(t->Struct.soa_kind)); @@ -12363,8 +12368,8 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info ir_emit_store(proc, kind, soa_kind); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 9), soa_type); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 10), soa_len); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 10), soa_type); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 11), soa_len); } } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index a2727b012..0272d1dfa 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -12178,7 +12178,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da case Type_Struct: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_struct_ptr); - LLVMValueRef vals[11] = {}; + LLVMValueRef vals[12] = {}; { @@ -12188,18 +12188,22 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da vals[5] = is_packed.value; vals[6] = is_raw_union.value; vals[7] = is_custom_align.value; + if (is_type_comparable(t) && !is_type_simple_compare(t)) { + vals[8] = lb_get_compare_proc_for_type(m, t).value; + } + if (t->Struct.soa_kind != StructSoa_None) { - lbValue kind = lb_emit_struct_ep(p, tag, 8); + lbValue kind = lb_emit_struct_ep(p, tag, 9); Type *kind_type = type_deref(kind.type); lbValue soa_kind = lb_const_value(m, kind_type, exact_value_i64(t->Struct.soa_kind)); lbValue soa_type = lb_type_info(m, t->Struct.soa_elem); lbValue soa_len = lb_const_int(m, t_int, t->Struct.soa_count); - vals[8] = soa_kind.value; - vals[9] = soa_type.value; - vals[10] = soa_len.value; + vals[9] = soa_kind.value; + vals[1] = soa_type.value; + vals[11] = soa_len.value; } } diff --git a/src/types.cpp b/src/types.cpp index 09888f878..b8b4b32f5 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1321,54 +1321,6 @@ Type *core_array_type(Type *t) { return t; } -// NOTE(bill): type can be easily compared using memcmp -bool is_type_simple_compare(Type *t) { - t = core_type(t); - switch (t->kind) { - case Type_Array: - return is_type_simple_compare(t->Array.elem); - - case Type_EnumeratedArray: - return is_type_simple_compare(t->EnumeratedArray.elem); - - case Type_Basic: - if (t->Basic.flags & BasicFlag_SimpleCompare) { - return true; - } - return false; - - case Type_Pointer: - case Type_Proc: - case Type_BitSet: - case Type_BitField: - return true; - - case Type_Struct: - for_array(i, t->Struct.fields) { - Entity *f = t->Struct.fields[i]; - if (!is_type_simple_compare(f->type)) { - return false; - } - } - return true; - - case Type_Union: - for_array(i, t->Union.variants) { - Type *v = t->Union.variants[i]; - if (!is_type_simple_compare(v)) { - return false; - } - } - return true; - - case Type_SimdVector: - return is_type_simple_compare(t->SimdVector.elem); - - } - - return false; -} - Type *base_complex_elem_type(Type *t) { @@ -1978,6 +1930,55 @@ bool is_type_comparable(Type *t) { return false; } +// NOTE(bill): type can be easily compared using memcmp +bool is_type_simple_compare(Type *t) { + t = core_type(t); + switch (t->kind) { + case Type_Array: + return is_type_simple_compare(t->Array.elem); + + case Type_EnumeratedArray: + return is_type_simple_compare(t->EnumeratedArray.elem); + + case Type_Basic: + if (t->Basic.flags & BasicFlag_SimpleCompare) { + return true; + } + return false; + + case Type_Pointer: + case Type_Proc: + case Type_BitSet: + case Type_BitField: + return true; + + case Type_Struct: + for_array(i, t->Struct.fields) { + Entity *f = t->Struct.fields[i]; + if (!is_type_simple_compare(f->type)) { + return false; + } + } + return true; + + case Type_Union: + for_array(i, t->Union.variants) { + Type *v = t->Union.variants[i]; + if (!is_type_simple_compare(v)) { + return false; + } + } + return true; + + case Type_SimdVector: + return is_type_simple_compare(t->SimdVector.elem); + + } + + return false; +} + + Type *strip_type_aliasing(Type *x) { if (x == nullptr) { return x; -- cgit v1.2.3 From 4762d2f2d15d64e012e2de876f1fd78c3ebd7c3e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 23 Nov 2020 16:56:31 +0000 Subject: map type internal reorganization --- core/runtime/core.odin | 42 ------------------------ core/runtime/dynamic_map_internal.odin | 60 +++++++++++++++++++++++++++++----- src/check_type.cpp | 17 +++++----- src/checker.cpp | 8 ++--- src/ir.cpp | 2 +- src/llvm_backend.cpp | 2 +- src/types.cpp | 2 +- 7 files changed, 66 insertions(+), 67 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 14d5c99ce..76454159c 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -351,48 +351,6 @@ Raw_Map :: struct { entries: Raw_Dynamic_Array, } -INITIAL_MAP_CAP :: 16; - -Map_Key :: struct { - hash: u64, - /* NOTE(bill) - size_of(Map_Key) == 16 Bytes on 32-bit systems - size_of(Map_Key) == 24 Bytes on 64-bit systems - - This does mean that an extra word is wasted for each map when a string is not used on 64-bit systems - however, this is probably not a huge problem in terms of memory usage - */ - key: struct #raw_union { - str: string, - val: u64, - }, -} - -Map_Find_Result :: struct { - hash_index: int, - entry_prev: int, - entry_index: int, -} - -Map_Entry_Header :: struct { - key: Map_Key, - next: int, -/* - value: Value_Type, -*/ -} - -Map_Header :: struct { - m: ^Raw_Map, - is_key_string: bool, - - entry_size: int, - entry_align: int, - - value_offset: uintptr, - value_size: int, -} - ///////////////////////////// // Init Startup Procedures // ///////////////////////////// diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index b4148e74e..71d3ba8f7 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -3,10 +3,52 @@ package runtime import "intrinsics" _ :: intrinsics; +INITIAL_MAP_CAP :: 16; + +Map_Hash :: struct { + hash: u64, + /* NOTE(bill) + size_of(Map_Hash) == 16 Bytes on 32-bit systems + size_of(Map_Hash) == 24 Bytes on 64-bit systems + + This does mean that an extra word is wasted for each map when a string is not used on 64-bit systems + however, this is probably not a huge problem in terms of memory usage + */ + key: struct #raw_union { + str: string, + val: u64, + }, +} + +Map_Find_Result :: struct { + hash_index: int, + entry_prev: int, + entry_index: int, +} + +Map_Entry_Header :: struct { + key: Map_Hash, + next: int, +/* + value: Value_Type, +*/ +} + +Map_Header :: struct { + m: ^Raw_Map, + is_key_string: bool, + + entry_size: int, + entry_align: int, + + value_offset: uintptr, + value_size: int, +} + __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { header := Map_Header{m = (^Raw_Map)(m)}; Entry :: struct { - key: Map_Key, + key: Map_Hash, next: int, value: V, }; @@ -19,9 +61,9 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { return header; } -__get_map_key :: proc "contextless" (k: $K) -> Map_Key { +__get_map_key :: proc "contextless" (k: $K) -> Map_Hash { key := k; - map_key: Map_Key; + map_key: Map_Hash; T :: intrinsics.type_core_type(K); @@ -169,7 +211,7 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #c header.m^ = nm; } -__dynamic_map_get :: proc(h: Map_Header, key: Map_Key) -> rawptr { +__dynamic_map_get :: proc(h: Map_Header, key: Map_Hash) -> rawptr { index := __dynamic_map_find(h, key).entry_index; if index >= 0 { data := uintptr(__dynamic_map_get_entry(h, index)); @@ -178,7 +220,7 @@ __dynamic_map_get :: proc(h: Map_Header, key: Map_Key) -> rawptr { return nil; } -__dynamic_map_set :: proc(h: Map_Header, key: Map_Key, value: rawptr, loc := #caller_location) #no_bounds_check { +__dynamic_map_set :: proc(h: Map_Header, key: Map_Hash, value: rawptr, loc := #caller_location) #no_bounds_check { index: int; assert(value != nil); @@ -223,7 +265,7 @@ __dynamic_map_full :: inline proc(using h: Map_Header) -> bool { } -__dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Key) -> bool { +__dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Hash) -> bool { if a.hash == b.hash { if h.is_key_string { return a.key.str == b.key.str; @@ -235,7 +277,7 @@ __dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Key) -> bool { return false; } -__dynamic_map_find :: proc(using h: Map_Header, key: Map_Key) -> Map_Find_Result #no_bounds_check { +__dynamic_map_find :: proc(using h: Map_Header, key: Map_Hash) -> Map_Find_Result #no_bounds_check { fr := Map_Find_Result{-1, -1, -1}; if n := u64(len(m.hashes)); n > 0 { fr.hash_index = int(key.hash % n); @@ -252,7 +294,7 @@ __dynamic_map_find :: proc(using h: Map_Header, key: Map_Key) -> Map_Find_Result return fr; } -__dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Key, loc := #caller_location) -> int { +__dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Hash, loc := #caller_location) -> int { prev := m.entries.len; c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc); if c != prev { @@ -263,7 +305,7 @@ __dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Key, loc := #calle return prev; } -__dynamic_map_delete_key :: proc(using h: Map_Header, key: Map_Key) { +__dynamic_map_delete_key :: proc(using h: Map_Header, key: Map_Hash) { fr := __dynamic_map_find(h, key); if fr.entry_index >= 0 { __dynamic_map_erase(h, fr); diff --git a/src/check_type.cpp b/src/check_type.cpp index dfd0f093d..a3b71a034 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2784,24 +2784,23 @@ void init_map_entry_type(Type *type) { if (type->Map.entry_type != nullptr) return; // NOTE(bill): The preload types may have not been set yet - GB_ASSERT(t_map_key != nullptr); + GB_ASSERT(t_map_hash != nullptr); Type *entry_type = alloc_type_struct(); /* struct { - hash: __MapKey; - next: int; - key: Key; - value: Value; + key: runtime.Map_Key, + next: int, + value: Value, } */ Ast *dummy_node = alloc_ast_node(nullptr, Ast_Invalid); Scope *s = create_scope(builtin_pkg->scope); - auto fields = array_make(permanent_allocator(), 0, 3); - array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("key")), t_map_key, false, 0, EntityState_Resolved)); - array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("next")), t_int, false, 1, EntityState_Resolved)); - array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("value")), type->Map.value, false, 2, EntityState_Resolved)); + auto fields = array_make(permanent_allocator(), 0, 4); + array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("key")), t_map_hash, false, cast(i32)fields.count, EntityState_Resolved)); + array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("next")), t_int, false, cast(i32)fields.count, EntityState_Resolved)); + array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("value")), type->Map.value, false, cast(i32)fields.count, EntityState_Resolved)); entry_type->Struct.fields = fields; diff --git a/src/checker.cpp b/src/checker.cpp index bba790cb2..efa7d76f7 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2278,14 +2278,14 @@ void init_core_source_code_location(Checker *c) { } void init_core_map_type(Checker *c) { - if (t_map_key == nullptr) { - Entity *e = find_core_entity(c, str_lit("Map_Key")); + if (t_map_hash == nullptr) { + Entity *e = find_core_entity(c, str_lit("Map_Hash")); if (e->state == EntityState_Unresolved) { auto ctx = c->init_ctx; check_entity_decl(&ctx, e, nullptr, nullptr); } - t_map_key = e->type; - GB_ASSERT(t_map_key != nullptr); + t_map_hash = e->type; + GB_ASSERT(t_map_hash != nullptr); } if (t_map_header == nullptr) { diff --git a/src/ir.cpp b/src/ir.cpp index 28edd5981..634e0a698 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3608,7 +3608,7 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val_ptr, Type *map_ty irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) { Type *hash_type = t_u64; - irValue *v = ir_add_local_generated(proc, t_map_key, true); + irValue *v = ir_add_local_generated(proc, t_map_hash, true); Type *t = base_type(ir_type(key)); key = ir_emit_conv(proc, key, key_type); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 0272d1dfa..1fb0891b5 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -10259,7 +10259,7 @@ lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { Type *hash_type = t_u64; - lbAddr v = lb_add_local_generated(p, t_map_key, true); + lbAddr v = lb_add_local_generated(p, t_map_hash, true); lbValue vp = lb_addr_get_ptr(p, v); Type *t = base_type(key.type); key = lb_emit_conv(p, key, key_type); diff --git a/src/types.cpp b/src/types.cpp index 0fc529213..7ca9a3cc2 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -684,7 +684,7 @@ gb_global Type *t_context_ptr = nullptr; gb_global Type *t_source_code_location = nullptr; gb_global Type *t_source_code_location_ptr = nullptr; -gb_global Type *t_map_key = nullptr; +gb_global Type *t_map_hash = nullptr; gb_global Type *t_map_header = nullptr; gb_global Type *t_vector_x86_mmx = nullptr; -- cgit v1.2.3 From 91758656f6027668d9a5c713812c012ac1b38008 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 23 Nov 2020 18:25:01 +0000 Subject: Change internal layout of `map[K]V` --- core/fmt/fmt.odin | 10 +-- core/runtime/core_builtin.odin | 3 +- core/runtime/dynamic_map_internal.odin | 118 ++++++++++++++++----------------- src/check_type.cpp | 14 ++-- src/ir.cpp | 44 ++++++------ src/llvm_backend.cpp | 39 +++++------ 6 files changed, 108 insertions(+), 120 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index ec664a2a9..0af7d2a8f 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1707,16 +1707,12 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { data := uintptr(entries.data) + uintptr(i*entry_size); header := cast(^runtime.Map_Entry_Header)data; - if reflect.is_string(info.key) { - strings.write_string(fi.buf, header.key.key.str); - } else { - fi := Info{buf = fi.buf}; - fmt_arg(&fi, any{rawptr(&header.key.key.val), info.key.id}, 'v'); - } + key := data + entry_type.offsets[2]; + fmt_arg(&Info{buf = fi.buf}, any{rawptr(key), info.key.id}, 'v'); strings.write_string(fi.buf, "="); - value := data + entry_type.offsets[2]; + value := data + entry_type.offsets[3]; fmt_arg(fi, any{rawptr(value), info.value.id}, 'v'); } } diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index 35d082ac9..fd6c7c9af 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -264,7 +264,8 @@ reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int) { @builtin delete_key :: proc(m: ^$T/map[$K]$V, key: K) { if m != nil { - __dynamic_map_delete_key(__get_map_header(m), __get_map_key(key)); + key := key; + __dynamic_map_delete_key(__get_map_header(m), __get_map_key(&key)); } } diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 71d3ba8f7..7d93bb918 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -7,17 +7,7 @@ INITIAL_MAP_CAP :: 16; Map_Hash :: struct { hash: u64, - /* NOTE(bill) - size_of(Map_Hash) == 16 Bytes on 32-bit systems - size_of(Map_Hash) == 24 Bytes on 64-bit systems - - This does mean that an extra word is wasted for each map when a string is not used on 64-bit systems - however, this is probably not a huge problem in terms of memory usage - */ - key: struct #raw_union { - str: string, - val: u64, - }, + key_ptr: rawptr, // address of Map_Entry_Header.key } Map_Find_Result :: struct { @@ -27,9 +17,10 @@ Map_Find_Result :: struct { } Map_Entry_Header :: struct { - key: Map_Hash, + hash: Map_Hash, next: int, /* + key: Key_Value, value: Value_Type, */ } @@ -41,6 +32,9 @@ Map_Header :: struct { entry_size: int, entry_align: int, + key_offset: uintptr, + key_size: int, + value_offset: uintptr, value_size: int, } @@ -48,57 +42,50 @@ Map_Header :: struct { __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { header := Map_Header{m = (^Raw_Map)(m)}; Entry :: struct { - key: Map_Hash, + hash: Map_Hash, next: int, + key: K, value: V, }; header.is_key_string = intrinsics.type_is_string(K); + header.entry_size = int(size_of(Entry)); header.entry_align = int(align_of(Entry)); + + header.key_offset = uintptr(offset_of(Entry, key)); + header.key_size = int(size_of(K)); + header.value_offset = uintptr(offset_of(Entry, value)); header.value_size = int(size_of(V)); return header; } -__get_map_key :: proc "contextless" (k: $K) -> Map_Hash { +__get_map_key :: proc "contextless" (k: ^$K) -> Map_Hash { key := k; - map_key: Map_Hash; + map_hash: Map_Hash; T :: intrinsics.type_core_type(K); + map_hash.key_ptr = k; + when intrinsics.type_is_integer(T) { - map_key.hash = default_hash_ptr(&key, size_of(T)); - - sz :: 8*size_of(T); - when sz == 8 { map_key.key.val = u64(( ^u8)(&key)^); } - else when sz == 16 { map_key.key.val = u64((^u16)(&key)^); } - else when sz == 32 { map_key.key.val = u64((^u32)(&key)^); } - else when sz == 64 { map_key.key.val = u64((^u64)(&key)^); } - else { #panic("Unhandled integer size"); } + map_hash.hash = default_hash_ptr(key, size_of(T)); } else when intrinsics.type_is_rune(T) { - map_key.hash = default_hash_ptr(&key, size_of(T)); - map_key.key.val = u64((^rune)(&key)^); + map_hash.hash = default_hash_ptr(key, size_of(T)); } else when intrinsics.type_is_pointer(T) { - map_key.hash = default_hash_ptr(&key, size_of(T)); - map_key.key.val = u64(uintptr((^rawptr)(&key)^)); + map_hash.hash = default_hash_ptr(key, size_of(T)); } else when intrinsics.type_is_float(T) { - map_key.hash = default_hash_ptr(&key, size_of(T)); - - sz :: 8*size_of(T); - when sz == 32 { map_key.key.val = u64((^u32)(&key)^); } - else when sz == 64 { map_key.key.val = u64((^u64)(&key)^); } - else { #panic("Unhandled float size"); } + map_hash.hash = default_hash_ptr(key, size_of(T)); } else when intrinsics.type_is_string(T) { #assert(T == string); - str := (^string)(&key)^; - map_key.hash = default_hash_string(str); - map_key.key.str = str; + str := (^string)(key)^; + map_hash.hash = default_hash_string(str); } else { #panic("Unhandled map key type"); } - return map_key; + return map_hash; } _fnv64a :: proc "contextless" (data: []byte, seed: u64 = 0xcbf29ce484222325) -> u64 { @@ -188,8 +175,8 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #c entry_header := __dynamic_map_get_entry(header, i); data := uintptr(entry_header); - fr := __dynamic_map_find(new_header, entry_header.key); - j := __dynamic_map_add_entry(new_header, entry_header.key, loc); + fr := __dynamic_map_find(new_header, entry_header.hash); + j := __dynamic_map_add_entry(new_header, entry_header.hash, loc); if fr.entry_prev < 0 { nm.hashes[fr.hash_index] = j; } else { @@ -199,8 +186,7 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #c e := __dynamic_map_get_entry(new_header, j); e.next = fr.entry_index; - ndata := uintptr(e); - mem_copy(rawptr(ndata+value_offset), rawptr(data+value_offset), value_size); + mem_copy(rawptr(uintptr(e)+value_offset), rawptr(data+value_offset), value_size); if __dynamic_map_full(new_header) { __dynamic_map_grow(new_header, loc); @@ -211,8 +197,8 @@ __dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #c header.m^ = nm; } -__dynamic_map_get :: proc(h: Map_Header, key: Map_Hash) -> rawptr { - index := __dynamic_map_find(h, key).entry_index; +__dynamic_map_get :: proc(h: Map_Header, hash: Map_Hash) -> rawptr { + index := __dynamic_map_find(h, hash).entry_index; if index >= 0 { data := uintptr(__dynamic_map_get_entry(h, index)); return rawptr(data + h.value_offset); @@ -220,7 +206,7 @@ __dynamic_map_get :: proc(h: Map_Header, key: Map_Hash) -> rawptr { return nil; } -__dynamic_map_set :: proc(h: Map_Header, key: Map_Hash, value: rawptr, loc := #caller_location) #no_bounds_check { +__dynamic_map_set :: proc(h: Map_Header, hash: Map_Hash, value: rawptr, loc := #caller_location) #no_bounds_check { index: int; assert(value != nil); @@ -229,11 +215,11 @@ __dynamic_map_set :: proc(h: Map_Header, key: Map_Hash, value: rawptr, loc := #c __dynamic_map_grow(h, loc); } - fr := __dynamic_map_find(h, key); + fr := __dynamic_map_find(h, hash); if fr.entry_index >= 0 { index = fr.entry_index; } else { - index = __dynamic_map_add_entry(h, key, loc); + index = __dynamic_map_add_entry(h, hash, loc); if fr.entry_prev >= 0 { entry := __dynamic_map_get_entry(h, fr.entry_prev); entry.next = index; @@ -243,9 +229,15 @@ __dynamic_map_set :: proc(h: Map_Header, key: Map_Hash, value: rawptr, loc := #c } { e := __dynamic_map_get_entry(h, index); - e.key = key; - val := (^byte)(uintptr(e) + h.value_offset); + + key := rawptr(uintptr(e) + h.key_offset); + mem_copy(key, hash.key_ptr, h.key_size); + + val := rawptr(uintptr(e) + h.value_offset); mem_copy(val, value, h.value_size); + + e.hash.hash = hash.hash; + e.hash.key_ptr = key; } if __dynamic_map_full(h) { @@ -267,24 +259,28 @@ __dynamic_map_full :: inline proc(using h: Map_Header) -> bool { __dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Hash) -> bool { if a.hash == b.hash { + if a.key_ptr == b.key_ptr { + return true; + } + if a.key_ptr == nil || b.key_ptr == nil { + return false; + } if h.is_key_string { - return a.key.str == b.key.str; - } else { - return a.key.val == b.key.val; + return (^string)(a.key_ptr)^ == (^string)(b.key_ptr)^; } - return true; + return memory_equal(a.key_ptr, b.key_ptr, h.key_size); } return false; } -__dynamic_map_find :: proc(using h: Map_Header, key: Map_Hash) -> Map_Find_Result #no_bounds_check { +__dynamic_map_find :: proc(using h: Map_Header, hash: Map_Hash) -> Map_Find_Result #no_bounds_check { fr := Map_Find_Result{-1, -1, -1}; if n := u64(len(m.hashes)); n > 0 { - fr.hash_index = int(key.hash % n); + fr.hash_index = int(hash.hash % n); fr.entry_index = m.hashes[fr.hash_index]; for fr.entry_index >= 0 { entry := __dynamic_map_get_entry(h, fr.entry_index); - if __dynamic_map_hash_equal(h, entry.key, key) { + if __dynamic_map_hash_equal(h, entry.hash, hash) { return fr; } fr.entry_prev = fr.entry_index; @@ -294,19 +290,21 @@ __dynamic_map_find :: proc(using h: Map_Header, key: Map_Hash) -> Map_Find_Resul return fr; } -__dynamic_map_add_entry :: proc(using h: Map_Header, key: Map_Hash, loc := #caller_location) -> int { +__dynamic_map_add_entry :: proc(using h: Map_Header, hash: Map_Hash, loc := #caller_location) -> int { prev := m.entries.len; c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc); if c != prev { end := __dynamic_map_get_entry(h, c-1); - end.key = key; + end.hash.hash = hash.hash; + end.hash.key_ptr = rawptr(uintptr(end) + key_offset); + mem_copy(end.hash.key_ptr, hash.key_ptr, key_size); end.next = -1; } return prev; } -__dynamic_map_delete_key :: proc(using h: Map_Header, key: Map_Hash) { - fr := __dynamic_map_find(h, key); +__dynamic_map_delete_key :: proc(using h: Map_Header, hash: Map_Hash) { + fr := __dynamic_map_find(h, hash); if fr.entry_index >= 0 { __dynamic_map_erase(h, fr); } @@ -332,7 +330,7 @@ __dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds end := __dynamic_map_get_entry(h, m.entries.len-1); mem_copy(old, end, entry_size); - if last := __dynamic_map_find(h, old.key); last.entry_prev >= 0 { + if last := __dynamic_map_find(h, old.hash); last.entry_prev >= 0 { last_entry := __dynamic_map_get_entry(h, last.entry_prev); last_entry.next = fr.entry_index; } else { diff --git a/src/check_type.cpp b/src/check_type.cpp index a3b71a034..bcc6b60db 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2789,18 +2789,20 @@ void init_map_entry_type(Type *type) { /* struct { - key: runtime.Map_Key, - next: int, - value: Value, + hash: runtime.Map_Hash, + next: int, + key: Key, + value: Value, } */ Ast *dummy_node = alloc_ast_node(nullptr, Ast_Invalid); Scope *s = create_scope(builtin_pkg->scope); auto fields = array_make(permanent_allocator(), 0, 4); - array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("key")), t_map_hash, false, cast(i32)fields.count, EntityState_Resolved)); - array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("next")), t_int, false, cast(i32)fields.count, EntityState_Resolved)); - array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("value")), type->Map.value, false, cast(i32)fields.count, EntityState_Resolved)); + array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("hash")), t_map_hash, false, cast(i32)fields.count, EntityState_Resolved)); + array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("next")), t_int, false, cast(i32)fields.count, EntityState_Resolved)); + array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("key")), type->Map.key, false, cast(i32)fields.count, EntityState_Resolved)); + array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("value")), type->Map.value, false, cast(i32)fields.count, EntityState_Resolved)); entry_type->Struct.fields = fields; diff --git a/src/ir.cpp b/src/ir.cpp index 634e0a698..e9f0b5647 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3595,18 +3595,22 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val_ptr, Type *map_ty i64 entry_size = type_size_of (map_type->Map.entry_type); i64 entry_align = type_align_of (map_type->Map.entry_type); - i64 value_offset = type_offset_of(map_type->Map.entry_type, 2); + i64 key_offset = type_offset_of(map_type->Map.entry_type, 2); + i64 key_size = type_size_of (map_type->Map.key); + i64 value_offset = type_offset_of(map_type->Map.entry_type, 3); i64 value_size = type_size_of (map_type->Map.value); ir_emit_store(proc, ir_emit_struct_ep(proc, h, 2), ir_const_int(entry_size)); ir_emit_store(proc, ir_emit_struct_ep(proc, h, 3), ir_const_int(entry_align)); - ir_emit_store(proc, ir_emit_struct_ep(proc, h, 4), ir_const_uintptr(value_offset)); - ir_emit_store(proc, ir_emit_struct_ep(proc, h, 5), ir_const_int(value_size)); + ir_emit_store(proc, ir_emit_struct_ep(proc, h, 4), ir_const_uintptr(key_offset)); + ir_emit_store(proc, ir_emit_struct_ep(proc, h, 5), ir_const_int(key_size)); + ir_emit_store(proc, ir_emit_struct_ep(proc, h, 6), ir_const_uintptr(value_offset)); + ir_emit_store(proc, ir_emit_struct_ep(proc, h, 7), ir_const_int(value_size)); return ir_emit_load(proc, h); } -irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) { +irValue *ir_gen_map_hash(irProcedure *proc, irValue *key, Type *key_type) { Type *hash_type = t_u64; irValue *v = ir_add_local_generated(proc, t_map_hash, true); Type *t = base_type(ir_type(key)); @@ -3627,10 +3631,6 @@ irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) { hashed_str = ir_emit_runtime_call(proc, "default_hash_string", args); } ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_str); - - irValue *key_data = ir_emit_struct_ep(proc, v, 1); - key_data = ir_emit_conv(proc, key_data, alloc_type_pointer(key_type)); - ir_emit_store(proc, key_data, str); } else { i64 sz = type_size_of(t); GB_ASSERT(sz <= 8); @@ -3640,16 +3640,17 @@ irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) { args[1] = ir_const_int(sz); irValue *hash = ir_emit_runtime_call(proc, "default_hash_ptr", args); - irValue *hash_ptr = ir_emit_struct_ep(proc, v, 0); - irValue *key_data = ir_emit_struct_ep(proc, v, 1); - key_data = ir_emit_conv(proc, key_data, alloc_type_pointer(key_type)); - ir_emit_store(proc, hash_ptr, hash); - ir_emit_store(proc, key_data, key); } } + irValue *key_ptr = ir_address_from_load_or_generate_local(proc, key); + key_ptr = ir_emit_conv(proc, key_ptr, t_rawptr); + + irValue *key_data = ir_emit_struct_ep(proc, v, 1); + ir_emit_store(proc, key_data, key_ptr); + return ir_emit_load(proc, v); } @@ -3705,7 +3706,7 @@ irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, T map_type = base_type(map_type); irValue *h = ir_gen_map_header(proc, addr, map_type); - irValue *key = ir_gen_map_key(proc, map_key, map_type->Map.key); + irValue *key = ir_gen_map_hash(proc, map_key, map_type->Map.key); irValue *v = ir_emit_conv(proc, map_value, map_type->Map.value); irValue *ptr = ir_add_local_generated(proc, ir_type(v), false); @@ -4062,7 +4063,7 @@ irValue *ir_addr_load(irProcedure *proc, irAddr const &addr) { Type *map_type = base_type(addr.map_type); irValue *v = ir_add_local_generated(proc, map_type->Map.lookup_result_type, true); irValue *h = ir_gen_map_header(proc, addr.addr, map_type); - irValue *key = ir_gen_map_key(proc, addr.map_key, map_type->Map.key); + irValue *key = ir_gen_map_hash(proc, addr.map_key, map_type->Map.key); auto args = array_make(ir_allocator(), 2); args[0] = h; @@ -4230,7 +4231,7 @@ irValue *ir_addr_get_ptr(irProcedure *proc, irAddr const &addr, bool allow_refer if (allow_reference) { Type *map_type = base_type(addr.map_type); irValue *h = ir_gen_map_header(proc, addr.addr, map_type); - irValue *key = ir_gen_map_key(proc, addr.map_key, map_type->Map.key); + irValue *key = ir_gen_map_hash(proc, addr.map_key, map_type->Map.key); auto args = array_make(ir_allocator(), 2); args[0] = h; @@ -8320,7 +8321,7 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { irValue *addr = ir_address_from_load_or_generate_local(proc, right); irValue *h = ir_gen_map_header(proc, addr, rt); - irValue *key = ir_gen_map_key(proc, left, rt->Map.key); + irValue *key = ir_gen_map_hash(proc, left, rt->Map.key); auto args = array_make(ir_allocator(), 2); args[0] = h; @@ -9954,13 +9955,8 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir elem = ir_emit_load(proc, elem); irValue *entry = ir_emit_ptr_offset(proc, elem, idx); - val = ir_emit_load(proc, ir_emit_struct_ep(proc, entry, 2)); - - irValue *key_raw = ir_emit_struct_ep(proc, entry, 0); - key_raw = ir_emit_struct_ep(proc, key_raw, 1); - irValue *key = ir_emit_conv(proc, key_raw, alloc_type_pointer(expr_type->Map.key)); - - idx = ir_emit_load(proc, key); + idx = ir_emit_load(proc, ir_emit_struct_ep(proc, entry, 2)); + val = ir_emit_load(proc, ir_emit_struct_ep(proc, entry, 3)); break; } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 1fb0891b5..f41f206b9 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -3361,13 +3361,8 @@ void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValu elem = lb_emit_load(p, elem); lbValue entry = lb_emit_ptr_offset(p, elem, idx); - val = lb_emit_load(p, lb_emit_struct_ep(p, entry, 2)); - - lbValue key_raw = lb_emit_struct_ep(p, entry, 0); - key_raw = lb_emit_struct_ep(p, key_raw, 1); - lbValue key = lb_emit_conv(p, key_raw, alloc_type_pointer(expr_type->Map.key)); - - idx = lb_emit_load(p, key); + idx = lb_emit_load(p, lb_emit_struct_ep(p, entry, 2)); + val = lb_emit_load(p, lb_emit_struct_ep(p, entry, 3)); break; } @@ -10246,13 +10241,19 @@ lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { i64 entry_size = type_size_of (map_type->Map.entry_type); i64 entry_align = type_align_of (map_type->Map.entry_type); - i64 value_offset = type_offset_of(map_type->Map.entry_type, 2); + + i64 key_offset = type_offset_of(map_type->Map.entry_type, 2); + i64 key_size = type_size_of (map_type->Map.key); + + i64 value_offset = type_offset_of(map_type->Map.entry_type, 3); i64 value_size = type_size_of (map_type->Map.value); lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 2), lb_const_int(p->module, t_int, entry_size)); lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 3), lb_const_int(p->module, t_int, entry_align)); - lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 4), lb_const_int(p->module, t_uintptr, value_offset)); - lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 5), lb_const_int(p->module, t_int, value_size)); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 4), lb_const_int(p->module, t_uintptr, key_offset)); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 5), lb_const_int(p->module, t_int, key_size)); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 6), lb_const_int(p->module, t_uintptr, value_offset)); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 7), lb_const_int(p->module, t_int, value_size)); return lb_addr_load(p, h); } @@ -10278,10 +10279,6 @@ lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { hashed_str = lb_emit_runtime_call(p, "default_hash_string", args); } lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_str); - - lbValue key_data = lb_emit_struct_ep(p, vp, 1); - key_data = lb_emit_conv(p, key_data, alloc_type_pointer(key_type)); - lb_emit_store(p, key_data, str); } else { i64 sz = type_size_of(t); GB_ASSERT(sz <= 8); @@ -10291,16 +10288,14 @@ lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { args[1] = lb_const_int(p->module, t_int, sz); lbValue hash = lb_emit_runtime_call(p, "default_hash_ptr", args); - - lbValue hash_ptr = lb_emit_struct_ep(p, vp, 0); - lbValue key_data = lb_emit_struct_ep(p, vp, 1); - key_data = lb_emit_conv(p, key_data, alloc_type_pointer(key_type)); - - lb_emit_store(p, hash_ptr, hash); - lb_emit_store(p, key_data, key); + lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hash); } } + lbValue key_ptr = lb_address_from_load_or_generate_local(p, key); + key_ptr = lb_emit_conv(p, key_ptr, t_rawptr); + lb_emit_store(p, lb_emit_struct_ep(p, vp, 1), key_ptr); + return lb_addr_load(p, v); } @@ -12202,7 +12197,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue soa_len = lb_const_int(m, t_int, t->Struct.soa_count); vals[9] = soa_kind.value; - vals[1] = soa_type.value; + vals[10] = soa_type.value; vals[11] = soa_len.value; } } -- cgit v1.2.3 From a55568b0c480b8a4ba7cf2f24ff2bb41cfc759ff Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 23 Nov 2020 19:14:36 +0000 Subject: Make hash internal key be `uintptr` rather than `u64` to reduce entry size --- core/runtime/core_builtin.odin | 2 +- core/runtime/dynamic_map_internal.odin | 68 +++++++++++++++++----------------- src/ir.cpp | 5 ++- src/llvm_backend.cpp | 6 ++- 4 files changed, 44 insertions(+), 37 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index fd6c7c9af..8a1be60d9 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -265,7 +265,7 @@ reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int) { delete_key :: proc(m: ^$T/map[$K]$V, key: K) { if m != nil { key := key; - __dynamic_map_delete_key(__get_map_header(m), __get_map_key(&key)); + __dynamic_map_delete_key(__get_map_header(m), __get_map_hash(&key)); } } diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 7d93bb918..051d4073d 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -6,7 +6,7 @@ _ :: intrinsics; INITIAL_MAP_CAP :: 16; Map_Hash :: struct { - hash: u64, + hash: uintptr, key_ptr: rawptr, // address of Map_Entry_Header.key } @@ -39,6 +39,37 @@ Map_Header :: struct { value_size: int, } +INITIAL_HASH_SEED :: 0xcbf29ce484222325; + +_fnv64a :: proc "contextless" (data: []byte, seed: u64 = INITIAL_HASH_SEED) -> u64 { + h: u64 = seed; + for b in data { + h = (h ~ u64(b)) * 0x100000001b3; + } + return h; +} + +default_hash :: inline proc "contextless" (data: []byte) -> uintptr { + return uintptr(_fnv64a(data)); +} +default_hash_string :: inline proc "contextless" (s: string) -> uintptr { + return default_hash(transmute([]byte)(s)); +} +default_hash_ptr :: inline proc "contextless" (data: rawptr, size: int) -> uintptr { + s := Raw_Slice{data, size}; + return default_hash(transmute([]byte)(s)); +} + + +source_code_location_hash :: proc(s: Source_Code_Location) -> uintptr { + hash := _fnv64a(transmute([]byte)s.file_path); + hash = hash ~ (u64(s.line) * 0x100000001b3); + hash = hash ~ (u64(s.column) * 0x100000001b3); + return uintptr(hash); +} + + + __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { header := Map_Header{m = (^Raw_Map)(m)}; Entry :: struct { @@ -58,10 +89,11 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { header.value_offset = uintptr(offset_of(Entry, value)); header.value_size = int(size_of(V)); + return header; } -__get_map_key :: proc "contextless" (k: ^$K) -> Map_Hash { +__get_map_hash :: proc "contextless" (k: ^$K) -> Map_Hash { key := k; map_hash: Map_Hash; @@ -88,36 +120,6 @@ __get_map_key :: proc "contextless" (k: ^$K) -> Map_Hash { return map_hash; } -_fnv64a :: proc "contextless" (data: []byte, seed: u64 = 0xcbf29ce484222325) -> u64 { - h: u64 = seed; - for b in data { - h = (h ~ u64(b)) * 0x100000001b3; - } - return h; -} - - -default_hash :: inline proc "contextless" (data: []byte) -> u64 { - return _fnv64a(data); -} -default_hash_string :: inline proc "contextless" (s: string) -> u64 { - return default_hash(transmute([]byte)(s)); -} -default_hash_ptr :: inline proc "contextless" (data: rawptr, size: int) -> u64 { - s := Raw_Slice{data, size}; - return default_hash(transmute([]byte)(s)); -} - - -source_code_location_hash :: proc(s: Source_Code_Location) -> u64 { - hash := _fnv64a(transmute([]byte)s.file_path); - hash = hash ~ (u64(s.line) * 0x100000001b3); - hash = hash ~ (u64(s.column) * 0x100000001b3); - return hash; -} - - - __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool { array := (^Raw_Slice)(array_); @@ -275,7 +277,7 @@ __dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Hash) -> bool { __dynamic_map_find :: proc(using h: Map_Header, hash: Map_Hash) -> Map_Find_Result #no_bounds_check { fr := Map_Find_Result{-1, -1, -1}; - if n := u64(len(m.hashes)); n > 0 { + if n := uintptr(len(m.hashes)); n > 0 { fr.hash_index = int(hash.hash % n); fr.entry_index = m.hashes[fr.hash_index]; for fr.entry_index >= 0 { diff --git a/src/ir.cpp b/src/ir.cpp index e9f0b5647..b545e7ce3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3624,7 +3624,10 @@ irValue *ir_gen_map_hash(irProcedure *proc, irValue *key, Type *key_type) { ExactValue ev = str->Constant.value; GB_ASSERT(ev.kind == ExactValue_String); u64 hs = fnv64a(ev.value_string.text, ev.value_string.len); - hashed_str = ir_value_constant(t_u64, exact_value_u64(hs)); + if (build_context.word_size == 4) { + hs &= 0xffffffff; + } + hashed_str = ir_value_constant(t_uintptr, exact_value_u64(hs)); } else { auto args = array_make(ir_allocator(), 1); args[0] = str; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index f41f206b9..5bbccc18a 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -10272,7 +10272,10 @@ lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { if (lb_is_const(str)) { String v = lb_get_const_string(p->module, str); u64 hs = fnv64a(v.text, v.len); - hashed_str = lb_const_int(p->module, t_u64, hs); + if (build_context.word_size == 4) { + hs &= 0xffffffff; + } + hashed_str = lb_const_int(p->module, t_uintptr, hs); } else { auto args = array_make(permanent_allocator(), 1); args[0] = str; @@ -10287,7 +10290,6 @@ lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { args[0] = lb_address_from_load_or_generate_local(p, key); args[1] = lb_const_int(p->module, t_int, sz); lbValue hash = lb_emit_runtime_call(p, "default_hash_ptr", args); - lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hash); } } -- cgit v1.2.3 From c77098a91c9d536f4aa1702050cabb7fb752c324 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 26 Nov 2020 10:19:45 +0000 Subject: Fix for in enum type --- src/ir.cpp | 2 +- src/llvm_backend.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index b545e7ce3..9607f8ce7 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10104,7 +10104,7 @@ void ir_build_range_enum(irProcedure *proc, Type *enum_type, Type *val_type, irV irValue *max_count = ir_const_int(enum_count); irValue *ti = ir_type_info(proc, t); - irValue *variant = ir_emit_struct_ep(proc, ti, 3); + irValue *variant = ir_emit_struct_ep(proc, ti, 4); irValue *eti_ptr = ir_emit_conv(proc, variant, t_type_info_enum_ptr); irValue *values = ir_emit_load(proc, ir_emit_struct_ep(proc, eti_ptr, 2)); irValue *values_data = ir_slice_elem(proc, values); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 2f84ce263..57385a9d6 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -3528,7 +3528,7 @@ void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValu lbValue max_count = lb_const_int(m, t_int, enum_count); lbValue ti = lb_type_info(m, t); - lbValue variant = lb_emit_struct_ep(p, ti, 3); + lbValue variant = lb_emit_struct_ep(p, ti, 4); lbValue eti_ptr = lb_emit_conv(p, variant, t_type_info_enum_ptr); lbValue values = lb_emit_load(p, lb_emit_struct_ep(p, eti_ptr, 2)); lbValue values_data = lb_slice_elem(p, values); -- cgit v1.2.3 From 39bed567b34a4bd74f7dfa99dd1ddb4621f67190 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 14:22:42 +0000 Subject: Add intrinsics.type_equal_proc; Make `map` use an internal equal procedure to compare keys --- core/intrinsics/intrinsics.odin | 3 ++ core/runtime/core.odin | 6 ++- core/runtime/dynamic_map_internal.odin | 15 ++---- src/check_expr.cpp | 21 +++++++++ src/checker.cpp | 8 ++++ src/checker_builtin_procs.hpp | 4 ++ src/ir.cpp | 84 ++++++++++++++++++++-------------- src/llvm_backend.cpp | 79 +++++++++++++++++++------------- src/llvm_backend.hpp | 2 + src/types.cpp | 2 + 10 files changed, 147 insertions(+), 77 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 3e20baecd..3738b57dd 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -1,4 +1,5 @@ // This is purely for documentation +//+ignore package intrinsics // Types @@ -152,3 +153,5 @@ type_polymorphic_record_parameter_value :: proc($T: typeid, index: int) -> $V -- type_field_index_of :: proc($T: typeid, $name: string) -> uintptr --- + +type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) --- diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 76454159c..1cc564ff2 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -42,6 +42,8 @@ Platform_Endianness :: enum u8 { Big = 2, } +Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool; + Type_Info_Struct_Soa_Kind :: enum u8 { None = 0, Fixed = 1, @@ -89,7 +91,6 @@ Type_Info_Tuple :: struct { // Only used for procedures parameters and results names: []string, }; -Type_Struct_Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool; Type_Info_Struct :: struct { types: []^Type_Info, names: []string, @@ -100,7 +101,7 @@ Type_Info_Struct :: struct { is_raw_union: bool, custom_align: bool, - equal: Type_Struct_Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set + equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set // These are only set iff this structure is an SOA structure soa_kind: Type_Info_Struct_Soa_Kind, @@ -351,6 +352,7 @@ Raw_Map :: struct { entries: Raw_Dynamic_Array, } + ///////////////////////////// // Init Startup Procedures // ///////////////////////////// diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 38618ea34..0c7146e25 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -63,13 +63,13 @@ Map_Entry_Header :: struct { Map_Header :: struct { m: ^Raw_Map, - is_key_string: bool, + equal: Equal_Proc, entry_size: int, entry_align: int, - key_offset: uintptr, - key_size: int, + key_offset: uintptr, + key_size: int, value_offset: uintptr, value_size: int, @@ -115,7 +115,7 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { value: V, }; - header.is_key_string = intrinsics.type_is_string(K); + header.equal = intrinsics.type_equal_proc(K); header.entry_size = int(size_of(Entry)); header.entry_align = int(align_of(Entry)); @@ -275,12 +275,7 @@ __dynamic_map_hash_equal :: proc(h: Map_Header, a, b: Map_Hash) -> bool { if a.key_ptr == b.key_ptr { return true; } - assert(a.key_ptr != nil && b.key_ptr != nil); - - if h.is_key_string { - return (^string)(a.key_ptr)^ == (^string)(b.key_ptr)^; - } - return memory_equal(a.key_ptr, b.key_ptr, h.key_size); + return h.equal(a.key_ptr, b.key_ptr); } return false; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4b17b4f27..e2a6089b9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6060,6 +6060,27 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } break; + + case BuiltinProc_type_equal_proc: + { + Operand op = {}; + Type *bt = check_type(c, ce->args[0]); + Type *type = base_type(bt); + if (type == nullptr || type == t_invalid) { + error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (!is_type_comparable(type)) { + gbString t = type_to_string(type); + error(ce->args[0], "Expected a comparable type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + operand->mode = Addressing_Value; + operand->type = t_equal_proc; + break; + } } return true; diff --git a/src/checker.cpp b/src/checker.cpp index efa7d76f7..ee3496fbf 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -726,6 +726,14 @@ void init_universal(void) { } add_global_type_entity(str_lit("byte"), &basic_types[Basic_u8]); + { + void set_procedure_abi_types(Type *type); + + Type *args[2] = {t_rawptr, t_rawptr}; + t_equal_proc = alloc_type_proc_from_types(args, 2, t_bool, false, ProcCC_Contextless); + set_procedure_abi_types(t_equal_proc); + } + // Constants add_global_constant(str_lit("true"), t_untyped_bool, exact_value_bool(true)); add_global_constant(str_lit("false"), t_untyped_bool, exact_value_bool(false)); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index d0e009cc0..9a5cdb1b8 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -183,6 +183,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_field_index_of, + BuiltinProc_type_equal_proc, + BuiltinProc__type_end, @@ -367,5 +369,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_field_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_equal_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, }; diff --git a/src/ir.cpp b/src/ir.cpp index 9607f8ce7..b1deda0b9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -529,6 +529,8 @@ Type *ir_type(irValue *value); irValue *ir_gen_anonymous_proc_lit(irModule *m, String prefix_name, Ast *expr, irProcedure *proc = nullptr); void ir_begin_procedure_body(irProcedure *proc); void ir_end_procedure_body(irProcedure *proc); +irValue *ir_get_equal_proc_for_type(irModule *m, Type *type); + irAddr ir_addr(irValue *addr) { irAddr v = {irAddr_Default, addr}; @@ -3591,7 +3593,6 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val_ptr, Type *map_ty irValue *m = ir_emit_conv(proc, map_val_ptr, type_deref(ir_type(gep0))); ir_emit_store(proc, gep0, m); - ir_emit_store(proc, ir_emit_struct_ep(proc, h, 1), ir_const_bool(is_type_string(key_type))); i64 entry_size = type_size_of (map_type->Map.entry_type); i64 entry_align = type_align_of (map_type->Map.entry_type); @@ -3600,6 +3601,7 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val_ptr, Type *map_ty i64 value_offset = type_offset_of(map_type->Map.entry_type, 3); i64 value_size = type_size_of (map_type->Map.value); + ir_emit_store(proc, ir_emit_struct_ep(proc, h, 1), ir_get_equal_proc_for_type(proc->module, key_type)); ir_emit_store(proc, ir_emit_struct_ep(proc, h, 2), ir_const_int(entry_size)); ir_emit_store(proc, ir_emit_struct_ep(proc, h, 3), ir_const_int(entry_align)); ir_emit_store(proc, ir_emit_struct_ep(proc, h, 4), ir_const_uintptr(key_offset)); @@ -4867,11 +4869,9 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue return nullptr; } -irValue *ir_get_compare_proc_for_type(irModule *m, Type *type) { +irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { Type *original_type = type; type = base_type(type); - GB_ASSERT(type->kind == Type_Struct); - type_set_offsets(type); Type *pt = alloc_type_pointer(type); auto key = hash_type(type); @@ -4879,12 +4879,6 @@ irValue *ir_get_compare_proc_for_type(irModule *m, Type *type) { if (found) { return *found; } - static Type *proc_type = nullptr; - if (proc_type == nullptr) { - Type *args[2] = {t_rawptr, t_rawptr}; - proc_type = alloc_type_proc_from_types(args, 2, t_bool, false, ProcCC_Contextless); - set_procedure_abi_types(proc_type); - } static u32 proc_index = 0; @@ -4895,9 +4889,9 @@ irValue *ir_get_compare_proc_for_type(irModule *m, Type *type) { Ast *body = alloc_ast_node(nullptr, Ast_Invalid); - Entity *e = alloc_entity_procedure(nullptr, make_token_ident(proc_name), proc_type, 0); + Entity *e = alloc_entity_procedure(nullptr, make_token_ident(proc_name), t_equal_proc, 0); e->Procedure.link_name = proc_name; - irValue *p = ir_value_procedure(m, e, proc_type, nullptr, body, proc_name); + irValue *p = ir_value_procedure(m, e, t_equal_proc, nullptr, body, proc_name); map_set(&m->values, hash_entity(e), p); string_map_set(&m->members, proc_name, p); @@ -4908,38 +4902,58 @@ irValue *ir_get_compare_proc_for_type(irModule *m, Type *type) { // ir_start_block(proc, proc->decl_block); GB_ASSERT(proc->curr_block != nullptr); - irBlock *done = ir_new_block(proc, nullptr, "done"); // NOTE(bill): Append later - irValue *x = proc->params[0]; irValue *y = proc->params[1]; irValue *lhs = ir_emit_conv(proc, x, pt); irValue *rhs = ir_emit_conv(proc, y, pt); - irBlock *block_false = ir_new_block(proc, nullptr, "bfalse"); + irBlock *block_same_ptr = ir_new_block(proc, nullptr, "same_ptr"); + irBlock *block_diff_ptr = ir_new_block(proc, nullptr, "diff_ptr"); - for_array(i, type->Struct.fields) { - irBlock *next_block = ir_new_block(proc, nullptr, "btrue"); + irValue *same_ptr = ir_emit_comp(proc, Token_CmpEq, lhs, rhs); + ir_emit_if(proc, same_ptr, block_same_ptr, block_diff_ptr); + ir_start_block(proc, block_same_ptr); + ir_emit(proc, ir_instr_return(proc, ir_const_bool(true))); - irValue *pleft = ir_emit_struct_ep(proc, lhs, cast(i32)i); - irValue *pright = ir_emit_struct_ep(proc, rhs, cast(i32)i); - irValue *left = ir_emit_load(proc, pleft); - irValue *right = ir_emit_load(proc, pright); - irValue *ok = ir_emit_comp(proc, Token_CmpEq, left, right); + ir_start_block(proc, block_diff_ptr); - ir_emit_if(proc, ok, next_block, block_false); + if (type->kind == Type_Struct) { + type_set_offsets(type); - ir_emit_jump(proc, next_block); - ir_start_block(proc, next_block); - } + irBlock *done = ir_new_block(proc, nullptr, "done"); // NOTE(bill): Append later - ir_emit_jump(proc, done); - ir_start_block(proc, block_false); + irBlock *block_false = ir_new_block(proc, nullptr, "bfalse"); - ir_emit(proc, ir_instr_return(proc, ir_const_bool(false))); + for_array(i, type->Struct.fields) { + irBlock *next_block = ir_new_block(proc, nullptr, "btrue"); - ir_emit_jump(proc, done); - ir_start_block(proc, done); - ir_emit(proc, ir_instr_return(proc, ir_const_bool(true))); + irValue *pleft = ir_emit_struct_ep(proc, lhs, cast(i32)i); + irValue *pright = ir_emit_struct_ep(proc, rhs, cast(i32)i); + irValue *left = ir_emit_load(proc, pleft); + irValue *right = ir_emit_load(proc, pright); + irValue *ok = ir_emit_comp(proc, Token_CmpEq, left, right); + + ir_emit_if(proc, ok, next_block, block_false); + + ir_emit_jump(proc, next_block); + ir_start_block(proc, next_block); + } + + ir_emit_jump(proc, done); + ir_start_block(proc, block_false); + + ir_emit(proc, ir_instr_return(proc, ir_const_bool(false))); + + ir_emit_jump(proc, done); + ir_start_block(proc, done); + ir_emit(proc, ir_instr_return(proc, ir_const_bool(true))); + } else { + irValue *left = ir_emit_load(proc, lhs); + irValue *right = ir_emit_load(proc, rhs); + irValue *ok = ir_emit_comp(proc, Token_CmpEq, left, right); + ok = ir_emit_conv(proc, ok, t_bool); + ir_emit(proc, ir_instr_return(proc, ok)); + } ir_end_procedure_body(proc); @@ -5093,7 +5107,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal args[2] = ir_const_int(type_size_of(a)); res = ir_emit_runtime_call(proc, "memory_equal", args); } else { - irValue *value = ir_get_compare_proc_for_type(proc->module, a); + irValue *value = ir_get_equal_proc_for_type(proc->module, a); auto args = array_make(permanent_allocator(), 2); args[0] = ir_emit_conv(proc, left_ptr, t_rawptr); args[1] = ir_emit_conv(proc, right_ptr, t_rawptr); @@ -7572,6 +7586,8 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu return ir_emit(proc, ir_instr_atomic_cxchg(proc, type, address, old_value, new_value, id)); } + case BuiltinProc_type_equal_proc: + return ir_get_equal_proc_for_type(proc->module, ce->args[0]->tav.type); } @@ -12353,7 +12369,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align); if (is_type_comparable(t) && !is_type_simple_compare(t)) { - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 8), ir_get_compare_proc_for_type(proc->module, t)); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 8), ir_get_equal_proc_for_type(proc->module, t)); } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 57385a9d6..39b4030af 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -8555,6 +8555,10 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, res.type = fix_typed; return res; } + + + case BuiltinProc_type_equal_proc: + return lb_get_equal_proc_for_type(p->module, ce->args[0]->tav.type); } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); @@ -9156,11 +9160,11 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { return {}; } -lbValue lb_get_compare_proc_for_type(lbModule *m, Type *type) { +lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type) { Type *original_type = type; type = base_type(type); - GB_ASSERT(type->kind == Type_Struct); - type_set_offsets(type); + GB_ASSERT(is_type_comparable(type)); + Type *pt = alloc_type_pointer(type); LLVMTypeRef ptr_type = lb_type(m, pt); @@ -9170,13 +9174,6 @@ lbValue lb_get_compare_proc_for_type(lbModule *m, Type *type) { if (found) { compare_proc = *found; } else { - static Type *proc_type = nullptr; - if (proc_type == nullptr) { - Type *args[2] = {t_rawptr, t_rawptr}; - proc_type = alloc_type_proc_from_types(args, 2, t_bool, false, ProcCC_Contextless); - set_procedure_abi_types(proc_type); - } - static u32 proc_index = 0; char buf[16] = {}; @@ -9184,7 +9181,7 @@ lbValue lb_get_compare_proc_for_type(lbModule *m, Type *type) { char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); String proc_name = make_string_c(str); - lbProcedure *p = lb_create_dummy_procedure(m, proc_name, proc_type); + lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc); lb_begin_procedure_body(p); LLVMValueRef x = LLVMGetParam(p->value, 0); @@ -9194,29 +9191,50 @@ lbValue lb_get_compare_proc_for_type(lbModule *m, Type *type) { lbValue lhs = {x, pt}; lbValue rhs = {y, pt}; - lbBlock *block_false = lb_create_block(p, "bfalse"); - lbValue res = lb_const_bool(m, t_bool, true); - for_array(i, type->Struct.fields) { - lbBlock *next_block = lb_create_block(p, "btrue"); + lbBlock *block_same_ptr = lb_create_block(p, "same_ptr"); + lbBlock *block_diff_ptr = lb_create_block(p, "diff_ptr"); - lbValue pleft = lb_emit_struct_ep(p, lhs, cast(i32)i); - lbValue pright = lb_emit_struct_ep(p, rhs, cast(i32)i); - lbValue left = lb_emit_load(p, pleft); - lbValue right = lb_emit_load(p, pright); - lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + lbValue same_ptr = lb_emit_comp(p, Token_CmpEq, lhs, rhs); + lb_emit_if(p, same_ptr, block_same_ptr, block_diff_ptr); + lb_start_block(p, block_same_ptr); + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); - lb_emit_if(p, ok, next_block, block_false); + lb_start_block(p, block_diff_ptr); - lb_emit_jump(p, next_block); - lb_start_block(p, next_block); - } + if (type->kind == Type_Struct) { + type_set_offsets(type); - LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); + lbBlock *block_false = lb_create_block(p, "bfalse"); + lbValue res = lb_const_bool(m, t_bool, true); + + for_array(i, type->Struct.fields) { + lbBlock *next_block = lb_create_block(p, "btrue"); + + lbValue pleft = lb_emit_struct_ep(p, lhs, cast(i32)i); + lbValue pright = lb_emit_struct_ep(p, rhs, cast(i32)i); + lbValue left = lb_emit_load(p, pleft); + lbValue right = lb_emit_load(p, pright); + lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + + lb_emit_if(p, ok, next_block, block_false); + + lb_emit_jump(p, next_block); + lb_start_block(p, next_block); + } - lb_start_block(p, block_false); + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); - LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 0, false)); + lb_start_block(p, block_false); + + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 0, false)); + } else { + lbValue left = lb_emit_load(p, lhs); + lbValue right = lb_emit_load(p, rhs); + lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + ok = lb_emit_conv(p, ok, t_bool); + LLVMBuildRet(p->builder, ok.value); + } lb_end_procedure_body(p); @@ -9370,7 +9388,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri args[2] = lb_const_int(p->module, t_int, type_size_of(a)); res = lb_emit_runtime_call(p, "memory_equal", args); } else { - lbValue value = lb_get_compare_proc_for_type(p->module, a); + lbValue value = lb_get_equal_proc_for_type(p->module, a); auto args = array_make(permanent_allocator(), 2); args[0] = lb_emit_conv(p, left_ptr, t_rawptr); args[1] = lb_emit_conv(p, right_ptr, t_rawptr); @@ -10255,8 +10273,6 @@ lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { lbValue m = lb_emit_conv(p, map_val_ptr, type_deref(gep0.type)); lb_emit_store(p, gep0, m); - lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 1), lb_const_bool(p->module, t_bool, is_type_string(key_type))); - i64 entry_size = type_size_of (map_type->Map.entry_type); i64 entry_align = type_align_of (map_type->Map.entry_type); @@ -10266,6 +10282,7 @@ lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { i64 value_offset = type_offset_of(map_type->Map.entry_type, 3); i64 value_size = type_size_of (map_type->Map.value); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 1), lb_get_equal_proc_for_type(p->module, key_type)); lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 2), lb_const_int(p->module, t_int, entry_size)); lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 3), lb_const_int(p->module, t_int, entry_align)); lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 4), lb_const_int(p->module, t_uintptr, key_offset)); @@ -12204,7 +12221,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da vals[6] = is_raw_union.value; vals[7] = is_custom_align.value; if (is_type_comparable(t) && !is_type_simple_compare(t)) { - vals[8] = lb_get_compare_proc_for_type(m, t).value; + vals[8] = lb_get_equal_proc_for_type(m, t).value; } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 09929c8cd..48ffd27a0 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -379,6 +379,8 @@ lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, To lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos); +lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type); +lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t); #define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" #define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info" diff --git a/src/types.cpp b/src/types.cpp index 7ca9a3cc2..75783f948 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -690,6 +690,8 @@ gb_global Type *t_map_header = nullptr; gb_global Type *t_vector_x86_mmx = nullptr; +gb_global Type *t_equal_proc = nullptr; + i64 type_size_of (Type *t); i64 type_align_of (Type *t); -- cgit v1.2.3 From 97c66c9c732af1e0735ee3f48a8af08b199bddf9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 15:27:53 +0000 Subject: Add `intrinsics.type_hasher_proc`; Make `map` work with generic hasher procedure --- core/intrinsics/intrinsics.odin | 3 +- core/runtime/core.odin | 5 +- core/runtime/dynamic_map_internal.odin | 64 +++++++----- src/check_expr.cpp | 25 ++++- src/check_type.cpp | 32 ++++-- src/checker.cpp | 8 +- src/checker_builtin_procs.hpp | 4 +- src/ir.cpp | 96 ++++++++++++++++- src/llvm_backend.cpp | 184 +++++++++++++++++++++++---------- src/llvm_backend.hpp | 4 +- src/types.cpp | 6 +- 11 files changed, 335 insertions(+), 96 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 3738b57dd..f817116f0 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -154,4 +154,5 @@ type_polymorphic_record_parameter_value :: proc($T: typeid, index: int) -> $V -- type_field_index_of :: proc($T: typeid, $name: string) -> uintptr --- -type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) --- +type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) --- +type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) --- diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 1cc564ff2..74b1338c7 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -42,7 +42,8 @@ Platform_Endianness :: enum u8 { Big = 2, } -Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool; +Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool; +Hasher_Proc :: distinct proc "contextless" (data: rawptr, seed: uintptr) -> uintptr; Type_Info_Struct_Soa_Kind :: enum u8 { None = 0, @@ -125,6 +126,8 @@ Type_Info_Map :: struct { key: ^Type_Info, value: ^Type_Info, generated_struct: ^Type_Info, + key_equal: Equal_Proc, + key_hasher: Hasher_Proc, }; Type_Info_Bit_Field :: struct { names: []string, diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 59661668f..99c2e92ee 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -11,31 +11,11 @@ Map_Hash :: struct { key_ptr: rawptr, // address of Map_Entry_Header.key } -__get_map_hash :: proc "contextless" (k: ^$K) -> Map_Hash { - key := k; - map_hash: Map_Hash; - - T :: intrinsics.type_core_type(K); - +__get_map_hash :: proc "contextless" (k: ^$K) -> (map_hash: Map_Hash) { + hasher := intrinsics.type_hasher_proc(K); map_hash.key_ptr = k; - - when intrinsics.type_is_integer(T) { - map_hash.hash = default_hash_ptr(key, size_of(T)); - } else when intrinsics.type_is_rune(T) { - map_hash.hash = default_hash_ptr(key, size_of(T)); - } else when intrinsics.type_is_pointer(T) { - map_hash.hash = default_hash_ptr(key, size_of(T)); - } else when intrinsics.type_is_float(T) { - map_hash.hash = default_hash_ptr(key, size_of(T)); - } else when intrinsics.type_is_string(T) { - #assert(T == string); - str := (^string)(key)^; - map_hash.hash = default_hash_string(str); - } else { - #panic("Unhandled map key type"); - } - - return map_hash; + map_hash.hash = hasher(k, 0); + return; } __get_map_hash_from_entry :: proc "contextless" (h: Map_Header, entry: ^Map_Entry_Header) -> (hash: Map_Hash) { @@ -96,6 +76,42 @@ default_hash_ptr :: inline proc "contextless" (data: rawptr, size: int) -> uintp return default_hash(transmute([]byte)(s)); } +_default_hasher_const :: inline proc "contextless" (data: rawptr, seed: uintptr, $N: uint) -> uintptr { + h := u64(seed) + 0xcbf29ce484222325; + p := uintptr(data); + inline for _ in 0.. uintptr { + h := u64(seed) + 0xcbf29ce484222325; + p := uintptr(data); + for _ in 0.. uintptr { return inline _default_hasher_const(data, seed, 1); } +default_hasher2 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 2); } +default_hasher4 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 4); } +default_hasher8 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 8); } +default_hasher16 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 16); } +default_hasher_string :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { + h := u64(seed) + 0xcbf29ce484222325; + str := (^[]byte)(data)^; + for b in str { + h = (h ~ u64(b)) * 0x100000001b3; + } + return uintptr(h); +} + + source_code_location_hash :: proc(s: Source_Code_Location) -> uintptr { hash := _fnv64a(transmute([]byte)s.file_path); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e2a6089b9..6ba25619f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -91,7 +91,7 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type); void set_procedure_abi_types(Type *type); void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type); - +void add_map_key_type_dependencies(CheckerContext *ctx, Type *key); Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem); Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem); @@ -6081,6 +6081,29 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->type = t_equal_proc; break; } + + case BuiltinProc_type_hasher_proc: + { + Operand op = {}; + Type *bt = check_type(c, ce->args[0]); + Type *type = base_type(bt); + if (type == nullptr || type == t_invalid) { + error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (!is_type_valid_for_keys(type)) { + gbString t = type_to_string(type); + error(ce->args[0], "Expected a valid type for map keys for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + add_map_key_type_dependencies(c, type); + + operand->mode = Addressing_Value; + operand->type = t_hasher_proc; + break; + } } return true; diff --git a/src/check_type.cpp b/src/check_type.cpp index 2d2a5b3f0..758d1969b 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2848,6 +2848,26 @@ void init_map_internal_types(Type *type) { type->Map.lookup_result_type = make_optional_ok_type(value); } +void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) { + if (is_type_string(key)) { + add_package_dependency(ctx, "runtime", "default_hash_string"); + add_package_dependency(ctx, "runtime", "default_hasher_string"); + } else if (!is_type_polymorphic(key)) { + add_package_dependency(ctx, "runtime", "default_hash_ptr"); + GB_ASSERT_MSG(is_type_simple_compare(key), "%s", type_to_string(key)); + + i64 sz = type_size_of(key); + switch (sz) { + case 1: add_package_dependency(ctx, "runtime", "default_hasher1"); break; + case 2: add_package_dependency(ctx, "runtime", "default_hasher2"); break; + case 4: add_package_dependency(ctx, "runtime", "default_hasher4"); break; + case 8: add_package_dependency(ctx, "runtime", "default_hasher8"); break; + case 16: add_package_dependency(ctx, "runtime", "default_hasher16"); break; + default: GB_PANIC("unhandled hasher for key type: %s", type_to_string(key)); + } + } +} + void check_map_type(CheckerContext *ctx, Type *type, Ast *node) { GB_ASSERT(type->kind == Type_Map); ast_node(mt, MapType, node); @@ -2864,16 +2884,16 @@ void check_map_type(CheckerContext *ctx, Type *type, Ast *node) { gb_string_free(str); } } + if (type_size_of(key) == 0) { + gbString str = type_to_string(key); + error(node, "Invalid type of a key for a map of size 0, got '%s'", str); + gb_string_free(str); + } type->Map.key = key; type->Map.value = value; - if (is_type_string(key)) { - add_package_dependency(ctx, "runtime", "default_hash_string"); - } else { - add_package_dependency(ctx, "runtime", "default_hash_ptr"); - } - + add_map_key_type_dependencies(ctx, key); init_core_map_type(ctx->checker); init_map_internal_types(type); diff --git a/src/checker.cpp b/src/checker.cpp index ee3496fbf..901f5439c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -729,9 +729,13 @@ void init_universal(void) { { void set_procedure_abi_types(Type *type); - Type *args[2] = {t_rawptr, t_rawptr}; - t_equal_proc = alloc_type_proc_from_types(args, 2, t_bool, false, ProcCC_Contextless); + Type *equal_args[2] = {t_rawptr, t_rawptr}; + t_equal_proc = alloc_type_proc_from_types(equal_args, 2, t_bool, false, ProcCC_Contextless); set_procedure_abi_types(t_equal_proc); + + Type *hasher_args[2] = {t_rawptr, t_uintptr}; + t_hasher_proc = alloc_type_proc_from_types(hasher_args, 2, t_uintptr, false, ProcCC_Contextless); + set_procedure_abi_types(t_hasher_proc); } // Constants diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 9a5cdb1b8..b2157b3c1 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -184,6 +184,7 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_field_index_of, BuiltinProc_type_equal_proc, + BuiltinProc_type_hasher_proc, BuiltinProc__type_end, @@ -369,7 +370,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_field_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_equal_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_equal_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_hasher_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, }; diff --git a/src/ir.cpp b/src/ir.cpp index b1deda0b9..0c0a92667 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -24,7 +24,9 @@ struct irModule { Map entity_names; // Key: Entity * of the typename Map debug_info; // Key: Unique pointer Map anonymous_proc_lits; // Key: Ast * - Map compare_procs; // Key: Type * + + Map equal_procs; // Key: Type * + Map hasher_procs; // Key: Type * irDebugInfo * debug_compile_unit; Array debug_location_stack; @@ -4875,7 +4877,7 @@ irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { Type *pt = alloc_type_pointer(type); auto key = hash_type(type); - irValue **found = map_get(&m->compare_procs, key); + irValue **found = map_get(&m->equal_procs, key); if (found) { return *found; } @@ -4883,7 +4885,7 @@ irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { static u32 proc_index = 0; char buf[16] = {}; - isize n = gb_snprintf(buf, 16, "__$cmp%u", ++proc_index); + isize n = gb_snprintf(buf, 16, "__$equal%u", ++proc_index); char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); String proc_name = make_string_c(str); @@ -4894,6 +4896,7 @@ irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { irValue *p = ir_value_procedure(m, e, t_equal_proc, nullptr, body, proc_name); map_set(&m->values, hash_entity(e), p); string_map_set(&m->members, proc_name, p); + map_set(&m->equal_procs, key, p); irProcedure *proc = &p->Proc; proc->is_startup = true; @@ -4957,7 +4960,83 @@ irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { ir_end_procedure_body(proc); - map_set(&m->compare_procs, key, p); + return p; +} + + +irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { + Type *original_type = type; + type = base_type(type); + Type *pt = alloc_type_pointer(type); + + GB_ASSERT(is_type_valid_for_keys(type)); + + auto key = hash_type(type); + irValue **found = map_get(&m->hasher_procs, key); + if (found) { + return *found; + } + + static u32 proc_index = 0; + + char buf[16] = {}; + isize n = gb_snprintf(buf, 16, "__$hasher%u", ++proc_index); + char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); + String proc_name = make_string_c(str); + + + Ast *body = alloc_ast_node(nullptr, Ast_Invalid); + Entity *e = alloc_entity_procedure(nullptr, make_token_ident(proc_name), t_hasher_proc, 0); + e->Procedure.link_name = proc_name; + irValue *p = ir_value_procedure(m, e, t_hasher_proc, nullptr, body, proc_name); + map_set(&m->values, hash_entity(e), p); + string_map_set(&m->members, proc_name, p); + map_set(&m->hasher_procs, key, p); + + irProcedure *proc = &p->Proc; + proc->is_startup = true; + proc->ignore_dead_instr = true; + ir_begin_procedure_body(proc); + // ir_start_block(proc, proc->decl_block); + GB_ASSERT(proc->curr_block != nullptr); + + irValue *data = proc->params[0]; + irValue *seed = proc->params[1]; + + if (type->kind == Type_Struct) { + type_set_offsets(type); + + GB_PANIC("Type_Struct"); + } else if (is_type_string(type)) { + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + irValue *res = ir_emit_runtime_call(proc, "default_hasher_string", args); + ir_emit(proc, ir_instr_return(proc, res)); + } else { + GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type)); + + i64 sz = type_size_of(type); + char const *name = nullptr; + switch (sz) { + case 1: name = "default_hasher1"; break; + case 2: name = "default_hasher2"; break; + case 4: name = "default_hasher4"; break; + case 8: name = "default_hasher8"; break; + case 16: name = "default_hasher16"; break; + default: GB_PANIC("unhandled hasher for key type: %s", type_to_string(type)); + } + GB_ASSERT(name != nullptr); + + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + irValue *res = ir_emit_runtime_call(proc, name, args); + ir_emit(proc, ir_instr_return(proc, res)); + } + + + ir_end_procedure_body(proc); return p; } @@ -7589,6 +7668,8 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu case BuiltinProc_type_equal_proc: return ir_get_equal_proc_for_type(proc->module, ce->args[0]->tav.type); + case BuiltinProc_type_hasher_proc: + return ir_get_hasher_proc_for_type(proc->module, ce->args[0]->tav.type); } GB_PANIC("Unhandled built-in procedure"); @@ -11705,7 +11786,8 @@ void ir_init_module(irModule *m, Checker *c) { map_init(&m->debug_info, heap_allocator()); map_init(&m->entity_names, heap_allocator()); map_init(&m->anonymous_proc_lits, heap_allocator()); - map_init(&m->compare_procs, heap_allocator()); + map_init(&m->equal_procs, heap_allocator()); + map_init(&m->hasher_procs, heap_allocator()); array_init(&m->procs, heap_allocator()); array_init(&m->procs_to_generate, heap_allocator()); array_init(&m->foreign_library_paths, heap_allocator()); @@ -12447,10 +12529,14 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info irValue *key = ir_emit_struct_ep(proc, tag, 0); irValue *value = ir_emit_struct_ep(proc, tag, 1); irValue *generated_struct = ir_emit_struct_ep(proc, tag, 2); + irValue *key_equal = ir_emit_struct_ep(proc, tag, 3); + irValue *key_hasher = ir_emit_struct_ep(proc, tag, 4); ir_emit_store(proc, key, ir_get_type_info_ptr(proc, t->Map.key)); ir_emit_store(proc, value, ir_get_type_info_ptr(proc, t->Map.value)); ir_emit_store(proc, generated_struct, ir_get_type_info_ptr(proc, t->Map.generated_struct_type)); + ir_emit_store(proc, key_equal, ir_get_equal_proc_for_type(proc->module, t->Map.key)); + ir_emit_store(proc, key_hasher, ir_get_hasher_proc_for_type(proc->module, t->Map.key)); break; } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 39b4030af..bc024ab8b 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -8559,6 +8559,9 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_type_equal_proc: return lb_get_equal_proc_for_type(p->module, ce->args[0]->tav.type); + + case BuiltinProc_type_hasher_proc: + return lb_get_hasher_proc_for_type(p->module, ce->args[0]->tav.type); } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); @@ -9169,84 +9172,156 @@ lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type) { LLVMTypeRef ptr_type = lb_type(m, pt); auto key = hash_type(type); - lbProcedure **found = map_get(&m->compare_procs, key); + lbProcedure **found = map_get(&m->equal_procs, key); lbProcedure *compare_proc = nullptr; if (found) { compare_proc = *found; - } else { - static u32 proc_index = 0; + GB_ASSERT(compare_proc != nullptr); + return {compare_proc->value, compare_proc->type}; + } - char buf[16] = {}; - isize n = gb_snprintf(buf, 16, "__$cmp%u", ++proc_index); - char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); - String proc_name = make_string_c(str); + static u32 proc_index = 0; - lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc); - lb_begin_procedure_body(p); + char buf[16] = {}; + isize n = gb_snprintf(buf, 16, "__$equal%u", ++proc_index); + char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); + String proc_name = make_string_c(str); + + lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc); + map_set(&m->equal_procs, key, p); + lb_begin_procedure_body(p); + + LLVMValueRef x = LLVMGetParam(p->value, 0); + LLVMValueRef y = LLVMGetParam(p->value, 1); + x = LLVMBuildPointerCast(p->builder, x, ptr_type, ""); + y = LLVMBuildPointerCast(p->builder, y, ptr_type, ""); + lbValue lhs = {x, pt}; + lbValue rhs = {y, pt}; + + + lbBlock *block_same_ptr = lb_create_block(p, "same_ptr"); + lbBlock *block_diff_ptr = lb_create_block(p, "diff_ptr"); + + lbValue same_ptr = lb_emit_comp(p, Token_CmpEq, lhs, rhs); + lb_emit_if(p, same_ptr, block_same_ptr, block_diff_ptr); + lb_start_block(p, block_same_ptr); + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); + + lb_start_block(p, block_diff_ptr); + + if (type->kind == Type_Struct) { + type_set_offsets(type); - LLVMValueRef x = LLVMGetParam(p->value, 0); - LLVMValueRef y = LLVMGetParam(p->value, 1); - x = LLVMBuildPointerCast(p->builder, x, ptr_type, ""); - y = LLVMBuildPointerCast(p->builder, y, ptr_type, ""); - lbValue lhs = {x, pt}; - lbValue rhs = {y, pt}; + lbBlock *block_false = lb_create_block(p, "bfalse"); + lbValue res = lb_const_bool(m, t_bool, true); + for_array(i, type->Struct.fields) { + lbBlock *next_block = lb_create_block(p, "btrue"); - lbBlock *block_same_ptr = lb_create_block(p, "same_ptr"); - lbBlock *block_diff_ptr = lb_create_block(p, "diff_ptr"); + lbValue pleft = lb_emit_struct_ep(p, lhs, cast(i32)i); + lbValue pright = lb_emit_struct_ep(p, rhs, cast(i32)i); + lbValue left = lb_emit_load(p, pleft); + lbValue right = lb_emit_load(p, pright); + lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + + lb_emit_if(p, ok, next_block, block_false); + + lb_emit_jump(p, next_block); + lb_start_block(p, next_block); + } - lbValue same_ptr = lb_emit_comp(p, Token_CmpEq, lhs, rhs); - lb_emit_if(p, same_ptr, block_same_ptr, block_diff_ptr); - lb_start_block(p, block_same_ptr); LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); - lb_start_block(p, block_diff_ptr); + lb_start_block(p, block_false); - if (type->kind == Type_Struct) { - type_set_offsets(type); + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 0, false)); + } else { + lbValue left = lb_emit_load(p, lhs); + lbValue right = lb_emit_load(p, rhs); + lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + ok = lb_emit_conv(p, ok, t_bool); + LLVMBuildRet(p->builder, ok.value); + } - lbBlock *block_false = lb_create_block(p, "bfalse"); - lbValue res = lb_const_bool(m, t_bool, true); + lb_end_procedure_body(p); - for_array(i, type->Struct.fields) { - lbBlock *next_block = lb_create_block(p, "btrue"); + compare_proc = p; + return {compare_proc->value, compare_proc->type}; +} + +lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { + Type *original_type = type; + type = base_type(type); + GB_ASSERT(is_type_valid_for_keys(type)); - lbValue pleft = lb_emit_struct_ep(p, lhs, cast(i32)i); - lbValue pright = lb_emit_struct_ep(p, rhs, cast(i32)i); - lbValue left = lb_emit_load(p, pleft); - lbValue right = lb_emit_load(p, pright); - lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + Type *pt = alloc_type_pointer(type); + LLVMTypeRef ptr_type = lb_type(m, pt); - lb_emit_if(p, ok, next_block, block_false); + auto key = hash_type(type); + lbProcedure **found = map_get(&m->hasher_procs, key); + lbProcedure *hasher_proc = nullptr; + if (found) { + hasher_proc = *found; + GB_ASSERT(hasher_proc != nullptr); + return {hasher_proc->value, hasher_proc->type}; + } - lb_emit_jump(p, next_block); - lb_start_block(p, next_block); - } + static u32 proc_index = 0; - LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); + char buf[16] = {}; + isize n = gb_snprintf(buf, 16, "__$hasher%u", ++proc_index); + char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); + String proc_name = make_string_c(str); - lb_start_block(p, block_false); + lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_hasher_proc); + map_set(&m->hasher_procs, key, p); + lb_begin_procedure_body(p); - LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 0, false)); - } else { - lbValue left = lb_emit_load(p, lhs); - lbValue right = lb_emit_load(p, rhs); - lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); - ok = lb_emit_conv(p, ok, t_bool); - LLVMBuildRet(p->builder, ok.value); - } + LLVMValueRef x = LLVMGetParam(p->value, 0); + LLVMValueRef y = LLVMGetParam(p->value, 1); + lbValue data = {x, t_rawptr}; + lbValue seed = {y, t_uintptr}; - lb_end_procedure_body(p); + if (type->kind == Type_Struct) { + type_set_offsets(type); - map_set(&m->compare_procs, key, p); + GB_PANIC("Type_Struct"); + } else if (is_type_string(type)) { + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + lbValue res = lb_emit_runtime_call(p, "default_hasher_string", args); + LLVMBuildRet(p->builder, res.value); + } else { + GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type)); + + i64 sz = type_size_of(type); + char const *name = nullptr; + switch (sz) { + case 1: name = "default_hasher1"; break; + case 2: name = "default_hasher2"; break; + case 4: name = "default_hasher4"; break; + case 8: name = "default_hasher8"; break; + case 16: name = "default_hasher16"; break; + default: GB_PANIC("unhandled hasher for key type: %s", type_to_string(type)); + } + GB_ASSERT(name != nullptr); - compare_proc = p; + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + lbValue res = lb_emit_runtime_call(p, name, args); + LLVMBuildRet(p->builder, res.value); } - GB_ASSERT(compare_proc != nullptr); - return {compare_proc->value, compare_proc->type}; + lb_end_procedure_body(p); + + hasher_proc = p; + return {hasher_proc->value, hasher_proc->type}; } + + lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right) { Type *a = core_type(left.type); Type *b = core_type(right.type); @@ -11571,7 +11646,8 @@ void lb_init_module(lbModule *m, Checker *c) { string_map_init(&m->const_strings, a); map_init(&m->anonymous_proc_lits, a); map_init(&m->function_type_map, a); - map_init(&m->compare_procs, a); + map_init(&m->equal_procs, a); + map_init(&m->hasher_procs, a); array_init(&m->procedures_to_generate, a); array_init(&m->foreign_library_paths, a); @@ -12307,10 +12383,12 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr); init_map_internal_types(t); - LLVMValueRef vals[3] = { + LLVMValueRef vals[5] = { lb_get_type_info_ptr(m, t->Map.key).value, lb_get_type_info_ptr(m, t->Map.value).value, lb_get_type_info_ptr(m, t->Map.generated_struct_type).value, + lb_get_equal_proc_for_type(m, t->Map.key).value, + lb_get_hasher_proc_for_type(m, t->Map.key).value }; lbValue res = {}; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 48ffd27a0..52b2b1e0f 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -106,7 +106,8 @@ struct lbModule { Map anonymous_proc_lits; // Key: Ast * Map function_type_map; // Key: Type * - Map compare_procs; // Key: Type * + Map equal_procs; // Key: Type * + Map hasher_procs; // Key: Type * u32 global_array_index; u32 global_generated_index; @@ -380,6 +381,7 @@ lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, To lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos); lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type); +lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type); lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t); #define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" diff --git a/src/types.cpp b/src/types.cpp index 75783f948..5c8db71e1 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -690,7 +690,8 @@ gb_global Type *t_map_header = nullptr; gb_global Type *t_vector_x86_mmx = nullptr; -gb_global Type *t_equal_proc = nullptr; +gb_global Type *t_equal_proc = nullptr; +gb_global Type *t_hasher_proc = nullptr; i64 type_size_of (Type *t); @@ -1949,6 +1950,9 @@ bool is_type_simple_compare(Type *t) { if (t->Basic.flags & BasicFlag_SimpleCompare) { return true; } + if (t->Basic.kind == Basic_typeid) { + return true; + } return false; case Type_Pointer: -- cgit v1.2.3 From 1dfe0cdd1de44d6c8b94c4e902a731655f8972c9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 15:50:29 +0000 Subject: Simplify hashing approach `map` --- core/runtime/core.odin | 6 ++-- core/runtime/dynamic_map_internal.odin | 10 +++++++ src/check_type.cpp | 6 ++-- src/ir.cpp | 50 +++++++++++----------------------- src/llvm_backend.cpp | 44 ++++++++++-------------------- src/types.cpp | 3 ++ 6 files changed, 51 insertions(+), 68 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 74b1338c7..b0c76720a 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -42,8 +42,10 @@ Platform_Endianness :: enum u8 { Big = 2, } -Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool; -Hasher_Proc :: distinct proc "contextless" (data: rawptr, seed: uintptr) -> uintptr; +// Procedure type to test whether two values of the same type are equal +Equal_Proc :: distinct proc "contextless" (rawptr, rawptr) -> bool; +// Procedure type to hash a value, default seed value is 0 +Hasher_Proc :: distinct proc "contextless" (data: rawptr, seed: uintptr = 0) -> uintptr; Type_Info_Struct_Soa_Kind :: enum u8 { None = 0, diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 99c2e92ee..8ae366db3 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -110,6 +110,16 @@ default_hasher_string :: proc "contextless" (data: rawptr, seed: uintptr) -> uin } return uintptr(h); } +default_hasher_cstring :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { + h := u64(seed) + 0xcbf29ce484222325; + ptr := (^uintptr)(data)^; + for (^byte)(ptr)^ != 0 { + b := (^byte)(ptr)^; + h = (h ~ u64(b)) * 0x100000001b3; + ptr += 1; + } + return uintptr(h); +} diff --git a/src/check_type.cpp b/src/check_type.cpp index 758d1969b..8da410fa9 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2849,11 +2849,11 @@ void init_map_internal_types(Type *type) { } void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) { - if (is_type_string(key)) { - add_package_dependency(ctx, "runtime", "default_hash_string"); + if (is_type_cstring(key)) { + add_package_dependency(ctx, "runtime", "default_hasher_cstring"); + } else if (is_type_string(key)) { add_package_dependency(ctx, "runtime", "default_hasher_string"); } else if (!is_type_polymorphic(key)) { - add_package_dependency(ctx, "runtime", "default_hash_ptr"); GB_ASSERT_MSG(is_type_simple_compare(key), "%s", type_to_string(key)); i64 sz = type_size_of(key); diff --git a/src/ir.cpp b/src/ir.cpp index 0c0a92667..90b0eda2a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -532,6 +532,7 @@ irValue *ir_gen_anonymous_proc_lit(irModule *m, String prefix_name, Ast *expr, i void ir_begin_procedure_body(irProcedure *proc); void ir_end_procedure_body(irProcedure *proc); irValue *ir_get_equal_proc_for_type(irModule *m, Type *type); +irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type); irAddr ir_addr(irValue *addr) { @@ -3620,43 +3621,18 @@ irValue *ir_gen_map_hash(irProcedure *proc, irValue *key, Type *key_type) { Type *t = base_type(ir_type(key)); key = ir_emit_conv(proc, key, key_type); - if (is_type_string(t)) { - irValue *str = ir_emit_conv(proc, key, t_string); - irValue *hashed_str = nullptr; - - if (str->kind == irValue_Constant) { - ExactValue ev = str->Constant.value; - GB_ASSERT(ev.kind == ExactValue_String); - u64 hs = fnv64a(ev.value_string.text, ev.value_string.len); - if (build_context.word_size == 4) { - hs &= 0xffffffff; - } - hashed_str = ir_value_constant(t_uintptr, exact_value_u64(hs)); - } else { - auto args = array_make(ir_allocator(), 1); - args[0] = str; - hashed_str = ir_emit_runtime_call(proc, "default_hash_string", args); - } - ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_str); - } else { - i64 sz = type_size_of(t); - GB_ASSERT(sz <= 8); - if (sz != 0) { - auto args = array_make(ir_allocator(), 2); - args[0] = ir_address_from_load_or_generate_local(proc, key); - args[1] = ir_const_int(sz); - irValue *hash = ir_emit_runtime_call(proc, "default_hash_ptr", args); - - irValue *hash_ptr = ir_emit_struct_ep(proc, v, 0); - ir_emit_store(proc, hash_ptr, hash); - } - } - irValue *key_ptr = ir_address_from_load_or_generate_local(proc, key); key_ptr = ir_emit_conv(proc, key_ptr, t_rawptr); - irValue *key_data = ir_emit_struct_ep(proc, v, 1); - ir_emit_store(proc, key_data, key_ptr); + irValue *hasher = ir_get_hasher_proc_for_type(proc->module, key_type); + + auto args = array_make(permanent_allocator(), 2); + args[0] = key_ptr; + args[1] = ir_value_constant(t_uintptr, exact_value_i64(0)); + irValue *hashed_key = ir_emit_call(proc, hasher, args); + + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_key); + ir_emit_store(proc, ir_emit_struct_ep(proc, v, 1), key_ptr); return ir_emit_load(proc, v); } @@ -5007,6 +4983,12 @@ irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { type_set_offsets(type); GB_PANIC("Type_Struct"); + } else if (is_type_cstring(type)) { + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + irValue *res = ir_emit_runtime_call(proc, "default_hasher_cstring", args); + ir_emit(proc, ir_instr_return(proc, res)); } else if (is_type_string(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index bc024ab8b..bea0beab9 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -9286,6 +9286,12 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { type_set_offsets(type); GB_PANIC("Type_Struct"); + } else if (is_type_cstring(type)) { + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + lbValue res = lb_emit_runtime_call(p, "default_hasher_cstring", args); + LLVMBuildRet(p->builder, res.value); } else if (is_type_string(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; @@ -10375,37 +10381,17 @@ lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { Type *t = base_type(key.type); key = lb_emit_conv(p, key, key_type); - if (is_type_string(t)) { - lbValue str = lb_emit_conv(p, key, t_string); - lbValue hashed_str = {}; - - if (lb_is_const(str)) { - String v = lb_get_const_string(p->module, str); - u64 hs = fnv64a(v.text, v.len); - if (build_context.word_size == 4) { - hs &= 0xffffffff; - } - hashed_str = lb_const_int(p->module, t_uintptr, hs); - } else { - auto args = array_make(permanent_allocator(), 1); - args[0] = str; - hashed_str = lb_emit_runtime_call(p, "default_hash_string", args); - } - lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_str); - } else { - i64 sz = type_size_of(t); - GB_ASSERT(sz <= 8); - if (sz != 0) { - auto args = array_make(permanent_allocator(), 2); - args[0] = lb_address_from_load_or_generate_local(p, key); - args[1] = lb_const_int(p->module, t_int, sz); - lbValue hash = lb_emit_runtime_call(p, "default_hash_ptr", args); - lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hash); - } - } - lbValue key_ptr = lb_address_from_load_or_generate_local(p, key); key_ptr = lb_emit_conv(p, key_ptr, t_rawptr); + + lbValue hasher = lb_get_hasher_proc_for_type(p->module, key_type); + + auto args = array_make(permanent_allocator(), 2); + args[0] = key_ptr; + args[1] = lb_const_int(p->module, t_uintptr, 0); + lbValue hashed_key = lb_emit_call(p, hasher, args); + + lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_key); lb_emit_store(p, lb_emit_struct_ep(p, vp, 1), key_ptr); return lb_addr_load(p, v); diff --git a/src/types.cpp b/src/types.cpp index 5c8db71e1..26f187a62 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1922,6 +1922,9 @@ bool is_type_comparable(Type *t) { return is_type_comparable(t->Opaque.elem); case Type_Struct: + if (type_size_of(t) == 0) { + return false; + } if (t->Struct.is_raw_union) { return is_type_simple_compare(t); } -- cgit v1.2.3 From 7fbc081119c57bf378a317fe6618eacd0465834d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 16:03:21 +0000 Subject: Improve const hash --- src/ir.cpp | 37 +++++++++++++++++++++++++++++++------ src/llvm_backend.cpp | 46 ++++++++++++++++++++++++++++++++++++---------- src/llvm_backend.hpp | 2 +- 3 files changed, 68 insertions(+), 17 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 90b0eda2a..cb60b9e3b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3615,6 +3615,29 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val_ptr, Type *map_ty return ir_emit_load(proc, h); } +irValue *ir_const_hash(irModule *m, irValue *key, Type *key_type) { + irValue *hashed_key = nullptr; + + if (key->kind == irValue_Constant) { + u64 hash = 0xcbf29ce484222325; + if (is_type_string(key_type)) { + GB_ASSERT(key->Constant.value.kind == ExactValue_String); + String s = key->Constant.value.value_string; + hash = fnv64a(s.text, s.len); + } else { + return nullptr; + } + // TODO(bill): other const hash types + + if (build_context.word_size == 4) { + hash &= 0xffffffffull; + } + hashed_key = ir_const_uintptr(hash); + } + + return hashed_key; +} + irValue *ir_gen_map_hash(irProcedure *proc, irValue *key, Type *key_type) { Type *hash_type = t_u64; irValue *v = ir_add_local_generated(proc, t_map_hash, true); @@ -3624,12 +3647,14 @@ irValue *ir_gen_map_hash(irProcedure *proc, irValue *key, Type *key_type) { irValue *key_ptr = ir_address_from_load_or_generate_local(proc, key); key_ptr = ir_emit_conv(proc, key_ptr, t_rawptr); - irValue *hasher = ir_get_hasher_proc_for_type(proc->module, key_type); - - auto args = array_make(permanent_allocator(), 2); - args[0] = key_ptr; - args[1] = ir_value_constant(t_uintptr, exact_value_i64(0)); - irValue *hashed_key = ir_emit_call(proc, hasher, args); + irValue *hashed_key = ir_const_hash(proc->module, key, key_type); + if (hashed_key == nullptr) { + irValue *hasher = ir_get_hasher_proc_for_type(proc->module, key_type); + auto args = array_make(permanent_allocator(), 2); + args[0] = key_ptr; + args[1] = ir_value_constant(t_uintptr, exact_value_i64(0)); + hashed_key = ir_emit_call(proc, hasher, args); + } ir_emit_store(proc, ir_emit_struct_ep(proc, v, 0), hashed_key); ir_emit_store(proc, ir_emit_struct_ep(proc, v, 1), key_ptr); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index bea0beab9..a4cd32efa 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -142,7 +142,7 @@ lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { case lbAddr_Map: { Type *map_type = base_type(addr.map.type); lbValue h = lb_gen_map_header(p, addr.addr, map_type); - lbValue key = lb_gen_map_key(p, addr.map.key, map_type->Map.key); + lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key); auto args = array_make(permanent_allocator(), 2); args[0] = h; @@ -592,7 +592,7 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { Type *map_type = base_type(addr.map.type); lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true); lbValue h = lb_gen_map_header(p, addr.addr, map_type); - lbValue key = lb_gen_map_key(p, addr.map.key, map_type->Map.key); + lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key); auto args = array_make(permanent_allocator(), 2); args[0] = h; @@ -6190,7 +6190,7 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { { lbValue addr = lb_address_from_load_or_generate_local(p, right); lbValue h = lb_gen_map_header(p, addr, rt); - lbValue key = lb_gen_map_key(p, left, rt->Map.key); + lbValue key = lb_gen_map_hash(p, left, rt->Map.key); auto args = array_make(permanent_allocator(), 2); args[0] = h; @@ -10374,7 +10374,30 @@ lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { return lb_addr_load(p, h); } -lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { +lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) { + lbValue hashed_key = {}; + + if (lb_is_const(key)) { + u64 hash = 0xcbf29ce484222325; + if (is_type_string(key_type)) { + size_t length = 0; + char const *text = LLVMGetAsString(key.value, &length); + hash = fnv64a(text, cast(isize)length); + } else { + return {}; + } + // TODO(bill): other const hash types + + if (build_context.word_size == 4) { + hash &= 0xffffffffull; + } + hashed_key = lb_const_int(m, t_uintptr, hash); + } + + return hashed_key; +} + +lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type) { Type *hash_type = t_u64; lbAddr v = lb_add_local_generated(p, t_map_hash, true); lbValue vp = lb_addr_get_ptr(p, v); @@ -10384,12 +10407,15 @@ lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { lbValue key_ptr = lb_address_from_load_or_generate_local(p, key); key_ptr = lb_emit_conv(p, key_ptr, t_rawptr); - lbValue hasher = lb_get_hasher_proc_for_type(p->module, key_type); + lbValue hashed_key = lb_const_hash(p->module, key, key_type); + if (hashed_key.value == nullptr) { + lbValue hasher = lb_get_hasher_proc_for_type(p->module, key_type); - auto args = array_make(permanent_allocator(), 2); - args[0] = key_ptr; - args[1] = lb_const_int(p->module, t_uintptr, 0); - lbValue hashed_key = lb_emit_call(p, hasher, args); + auto args = array_make(permanent_allocator(), 2); + args[0] = key_ptr; + args[1] = lb_const_int(p->module, t_uintptr, 0); + hashed_key = lb_emit_call(p, hasher, args); + } lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_key); lb_emit_store(p, lb_emit_struct_ep(p, vp, 1), key_ptr); @@ -10403,7 +10429,7 @@ void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_ GB_ASSERT(map_type->kind == Type_Map); lbValue h = lb_gen_map_header(p, addr.addr, map_type); - lbValue key = lb_gen_map_key(p, map_key, map_type->Map.key); + lbValue key = lb_gen_map_hash(p, map_key, map_type->Map.key); lbValue v = lb_emit_conv(p, map_value, map_type->Map.value); lbAddr value_addr = lb_add_local_generated(p, v.type, false); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 52b2b1e0f..34a5dfacf 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -370,7 +370,7 @@ String lb_get_const_string(lbModule *m, lbValue value); lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true); lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id); lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type); -lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type); +lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type); void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, lbValue map_key, lbValue map_value, Ast *node); -- cgit v1.2.3 From 57f5976ac1b5416093ef25d725c30ae5ff270809 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 16:12:21 +0000 Subject: Support map keys for simple compare types --- core/runtime/dynamic_map_internal.odin | 4 +++- src/check_type.cpp | 5 ++++- src/ir.cpp | 10 ++++++++-- src/llvm_backend.cpp | 10 ++++++++-- src/types.cpp | 4 +++- 5 files changed, 26 insertions(+), 7 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 8ae366db3..7d5ff017b 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -76,6 +76,7 @@ default_hash_ptr :: inline proc "contextless" (data: rawptr, size: int) -> uintp return default_hash(transmute([]byte)(s)); } +@(private) _default_hasher_const :: inline proc "contextless" (data: rawptr, seed: uintptr, $N: uint) -> uintptr { h := u64(seed) + 0xcbf29ce484222325; p := uintptr(data); @@ -86,7 +87,8 @@ _default_hasher_const :: inline proc "contextless" (data: rawptr, seed: uintptr, } return uintptr(h); } -_default_hasher_n :: inline proc "contextless" (data: rawptr, seed: uintptr, N: int) -> uintptr { + +default_hasher_n :: inline proc "contextless" (data: rawptr, seed: uintptr, N: int) -> uintptr { h := u64(seed) + 0xcbf29ce484222325; p := uintptr(data); for _ in 0..kind == Type_Struct) { type_set_offsets(type); - - GB_PANIC("Type_Struct"); + GB_ASSERT(is_type_simple_compare(type)); + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = ir_const_int(sz); + irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); + ir_emit(proc, ir_instr_return(proc, res)); } else if (is_type_cstring(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index a4cd32efa..4fe98bfcf 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -9284,8 +9284,14 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { if (type->kind == Type_Struct) { type_set_offsets(type); - - GB_PANIC("Type_Struct"); + GB_ASSERT(is_type_simple_compare(type)); + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = lb_const_int(m, t_int, sz); + lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); + LLVMBuildRet(p->builder, res.value); } else if (is_type_cstring(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; diff --git a/src/types.cpp b/src/types.cpp index 26f187a62..f8f7dd66e 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -964,7 +964,6 @@ bool is_type_valid_for_keys(Type *t); Type *alloc_type_map(i64 count, Type *key, Type *value) { if (key != nullptr) { - GB_ASSERT(is_type_valid_for_keys(key)); GB_ASSERT(value != nullptr); } Type *t = alloc_type(Type_Map); @@ -1558,6 +1557,9 @@ bool is_type_valid_for_keys(Type *t) { if (is_type_typeid(t)) { return true; } + if (is_type_simple_compare(t)) { + return true; + } return false; } -- cgit v1.2.3 From 5ab7ec5b16b08584764b1a02441299e18328df1e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 16:37:19 +0000 Subject: Support any comparable type for map keys --- src/check_type.cpp | 42 ++++++++++++++++------ src/ir.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++----- src/llvm_backend.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++++++----- src/types.cpp | 6 ++++ 4 files changed, 214 insertions(+), 28 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 10ffe076c..9c8308757 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2849,26 +2849,48 @@ void init_map_internal_types(Type *type) { } void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) { + key = core_type(key); + if (is_type_cstring(key)) { add_package_dependency(ctx, "runtime", "default_hasher_cstring"); } else if (is_type_string(key)) { add_package_dependency(ctx, "runtime", "default_hasher_string"); } else if (!is_type_polymorphic(key)) { - if (!is_type_simple_compare(key)) { + if (!is_type_comparable(key)) { return; } - if (is_type_struct(key)) { + if (key->kind == Type_Struct) { add_package_dependency(ctx, "runtime", "default_hasher_n"); - } + if (!is_type_simple_compare(key)) { + for_array(i, key->Struct.fields) { + Entity *field = key->Struct.fields[i]; + add_map_key_type_dependencies(ctx, field->type); + } + } + } else if (key->kind == Type_EnumeratedArray) { + add_package_dependency(ctx, "runtime", "default_hasher_n"); + if (!is_type_simple_compare(key->EnumeratedArray.elem)) { + add_map_key_type_dependencies(ctx, key->EnumeratedArray.elem); + } + } else if (key->kind == Type_Array) { + add_package_dependency(ctx, "runtime", "default_hasher_n"); + if (!is_type_simple_compare(key->Array.elem)) { + add_map_key_type_dependencies(ctx, key->Array.elem); + } + } else { + if (!is_type_simple_compare(key)) { + GB_PANIC("HERE"); + } - i64 sz = type_size_of(key); - switch (sz) { - case 1: add_package_dependency(ctx, "runtime", "default_hasher1"); break; - case 2: add_package_dependency(ctx, "runtime", "default_hasher2"); break; - case 4: add_package_dependency(ctx, "runtime", "default_hasher4"); break; - case 8: add_package_dependency(ctx, "runtime", "default_hasher8"); break; - case 16: add_package_dependency(ctx, "runtime", "default_hasher16"); break; + i64 sz = type_size_of(key); + switch (sz) { + case 1: add_package_dependency(ctx, "runtime", "default_hasher1"); break; + case 2: add_package_dependency(ctx, "runtime", "default_hasher2"); break; + case 4: add_package_dependency(ctx, "runtime", "default_hasher4"); break; + case 8: add_package_dependency(ctx, "runtime", "default_hasher8"); break; + case 16: add_package_dependency(ctx, "runtime", "default_hasher16"); break; + } } } } diff --git a/src/ir.cpp b/src/ir.cpp index 84f943eda..7e3050825 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4967,7 +4967,7 @@ irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { Type *original_type = type; - type = base_type(type); + type = core_type(type); Type *pt = alloc_type_pointer(type); GB_ASSERT(is_type_valid_for_keys(type)); @@ -5006,14 +5006,92 @@ irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { if (type->kind == Type_Struct) { type_set_offsets(type); - GB_ASSERT(is_type_simple_compare(type)); - i64 sz = type_size_of(type); - auto args = array_make(permanent_allocator(), 3); - args[0] = data; - args[1] = seed; - args[2] = ir_const_int(sz); - irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); - ir_emit(proc, ir_instr_return(proc, res)); + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = ir_const_int(sz); + irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); + ir_emit(proc, ir_instr_return(proc, res)); + } else { + data = ir_emit_conv(proc, data, t_u8_ptr); + + auto args = array_make(permanent_allocator(), 2); + for_array(i, type->Struct.fields) { + i64 offset = type->Struct.offsets[i]; + Entity *field = type->Struct.fields[i]; + irValue *field_hasher = ir_get_hasher_proc_for_type(m, field->type); + irValue *ptr = ir_emit_ptr_offset(proc, data, ir_const_uintptr(offset)); + + args[0] = ptr; + args[1] = seed; + seed = ir_emit_call(proc, field_hasher, args); + } + ir_emit(proc, ir_instr_return(proc, seed)); + } + } else if (type->kind == Type_Array) { + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = ir_const_int(sz); + irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); + ir_emit(proc, ir_instr_return(proc, res)); + } else { + irValue *pres = ir_add_local_generated(proc, t_uintptr, false); + ir_emit_store(proc, pres, seed); + + auto args = array_make(permanent_allocator(), 2); + irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem); + + auto loop_data = ir_loop_start(proc, type->Array.count, t_i32); + + data = ir_emit_conv(proc, data, pt); + + irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx); + args[0] = ptr; + args[1] = ir_emit_load(proc, pres); + irValue *new_seed = ir_emit_call(proc, elem_hasher, args); + ir_emit_store(proc, pres, new_seed); + + ir_loop_end(proc, loop_data); + + irValue *res = ir_emit_load(proc, pres); + ir_emit(proc, ir_instr_return(proc, res)); + } + } else if (type->kind == Type_EnumeratedArray) { + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = ir_const_int(sz); + irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); + ir_emit(proc, ir_instr_return(proc, res)); + } else { + irValue *pres = ir_add_local_generated(proc, t_uintptr, false); + ir_emit_store(proc, pres, seed); + + auto args = array_make(permanent_allocator(), 2); + irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem); + + auto loop_data = ir_loop_start(proc, type->Array.count, t_i32); + + data = ir_emit_conv(proc, data, pt); + + irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx); + args[0] = ptr; + args[1] = ir_emit_load(proc, pres); + irValue *new_seed = ir_emit_call(proc, elem_hasher, args); + ir_emit_store(proc, pres, new_seed); + + ir_loop_end(proc, loop_data); + + irValue *res = ir_emit_load(proc, pres); + ir_emit(proc, ir_instr_return(proc, res)); + } } else if (is_type_cstring(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 4fe98bfcf..140d01292 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -9251,7 +9251,7 @@ lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type) { lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { Type *original_type = type; - type = base_type(type); + type = core_type(type); GB_ASSERT(is_type_valid_for_keys(type)); Type *pt = alloc_type_pointer(type); @@ -9284,14 +9284,94 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { if (type->kind == Type_Struct) { type_set_offsets(type); - GB_ASSERT(is_type_simple_compare(type)); - i64 sz = type_size_of(type); - auto args = array_make(permanent_allocator(), 3); - args[0] = data; - args[1] = seed; - args[2] = lb_const_int(m, t_int, sz); - lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); - LLVMBuildRet(p->builder, res.value); + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = lb_const_int(m, t_int, sz); + lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); + LLVMBuildRet(p->builder, res.value); + } else { + data = lb_emit_conv(p, data, t_u8_ptr); + + auto args = array_make(permanent_allocator(), 2); + for_array(i, type->Struct.fields) { + i64 offset = type->Struct.offsets[i]; + Entity *field = type->Struct.fields[i]; + lbValue field_hasher = lb_get_hasher_proc_for_type(m, field->type); + lbValue ptr = lb_emit_ptr_offset(p, data, lb_const_int(m, t_uintptr, offset)); + + args[0] = ptr; + args[1] = seed; + seed = lb_emit_call(p, field_hasher, args); + } + LLVMBuildRet(p->builder, seed.value); + } + } else if (type->kind == Type_Array) { + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = lb_const_int(m, t_int, sz); + lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); + LLVMBuildRet(p->builder, res.value); + } else { + lbAddr pres = lb_add_local_generated(p, t_uintptr, false); + lb_addr_store(p, pres, seed); + + auto args = array_make(permanent_allocator(), 2); + lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->Array.elem); + + auto loop_data = lb_loop_start(p, type->Array.count, t_i32); + + data = lb_emit_conv(p, data, pt); + + lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx); + args[0] = ptr; + args[1] = lb_addr_load(p, pres); + lbValue new_seed = lb_emit_call(p, elem_hasher, args); + lb_addr_store(p, pres, new_seed); + + lb_loop_end(p, loop_data); + + lbValue res = lb_addr_load(p, pres); + LLVMBuildRet(p->builder, res.value); + } + } else if (type->kind == Type_EnumeratedArray) { + if (is_type_simple_compare(type)) { + i64 sz = type_size_of(type); + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = lb_const_int(m, t_int, sz); + lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); + LLVMBuildRet(p->builder, res.value); + } else { + lbAddr res = lb_add_local_generated(p, t_uintptr, false); + lb_addr_store(p, res, seed); + + auto args = array_make(permanent_allocator(), 2); + lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->EnumeratedArray.elem); + + auto loop_data = lb_loop_start(p, type->EnumeratedArray.count, t_i32); + + data = lb_emit_conv(p, data, pt); + + lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx); + args[0] = ptr; + args[1] = lb_addr_load(p, res); + lbValue new_seed = lb_emit_call(p, elem_hasher, args); + lb_addr_store(p, res, new_seed); + + lb_loop_end(p, loop_data); + + lbValue vres = lb_addr_load(p, res); + LLVMBuildRet(p->builder, vres.value); + } + + } else if (is_type_cstring(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; diff --git a/src/types.cpp b/src/types.cpp index f8f7dd66e..df87cb645 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1542,6 +1542,8 @@ bool is_type_valid_for_keys(Type *t) { if (is_type_untyped(t)) { return false; } + return is_type_comparable(t); +#if 0 if (is_type_integer(t)) { return true; } @@ -1560,8 +1562,12 @@ bool is_type_valid_for_keys(Type *t) { if (is_type_simple_compare(t)) { return true; } + if (is_type_comparable(t)) { + return true; + } return false; +#endif } bool is_type_valid_bit_set_elem(Type *t) { -- cgit v1.2.3 From 9e1341631246e752b7be703a6ef3e4398205b726 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 17:58:54 +0000 Subject: Simplify simple compare hasher code --- src/ir.cpp | 162 ++++++++++++++++++++++------------------------- src/llvm_backend.cpp | 174 ++++++++++++++++++++++----------------------------- 2 files changed, 150 insertions(+), 186 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 7e3050825..06d88ae5b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4965,6 +4965,32 @@ irValue *ir_get_equal_proc_for_type(irModule *m, Type *type) { } +irValue *ir_simple_compare_hash(irProcedure *p, Type *type, irValue *data, irValue *seed) { + GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type)); + + i64 sz = type_size_of(type); + char const *name = nullptr; + switch (sz) { + case 1: name = "default_hasher1"; break; + case 2: name = "default_hasher2"; break; + case 4: name = "default_hasher4"; break; + case 8: name = "default_hasher8"; break; + case 16: name = "default_hasher16"; break; + } + if (name != nullptr) { + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + return ir_emit_runtime_call(p, name, args); + } + + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = ir_const_int(type_size_of(type)); + return ir_emit_runtime_call(p, "default_hasher_n", args); +} + irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { Type *original_type = type; type = core_type(type); @@ -4998,100 +5024,78 @@ irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { proc->is_startup = true; proc->ignore_dead_instr = true; ir_begin_procedure_body(proc); + defer (ir_end_procedure_body(proc)); + // ir_start_block(proc, proc->decl_block); GB_ASSERT(proc->curr_block != nullptr); irValue *data = proc->params[0]; irValue *seed = proc->params[1]; + if (is_type_simple_compare(type)) { + irValue *res = ir_simple_compare_hash(proc, type, data, seed); + ir_emit(proc, ir_instr_return(proc, res)); + return p; + } + if (type->kind == Type_Struct) { type_set_offsets(type); - if (is_type_simple_compare(type)) { - i64 sz = type_size_of(type); - auto args = array_make(permanent_allocator(), 3); - args[0] = data; - args[1] = seed; - args[2] = ir_const_int(sz); - irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); - ir_emit(proc, ir_instr_return(proc, res)); - } else { - data = ir_emit_conv(proc, data, t_u8_ptr); + data = ir_emit_conv(proc, data, t_u8_ptr); - auto args = array_make(permanent_allocator(), 2); - for_array(i, type->Struct.fields) { - i64 offset = type->Struct.offsets[i]; - Entity *field = type->Struct.fields[i]; - irValue *field_hasher = ir_get_hasher_proc_for_type(m, field->type); - irValue *ptr = ir_emit_ptr_offset(proc, data, ir_const_uintptr(offset)); + auto args = array_make(permanent_allocator(), 2); + for_array(i, type->Struct.fields) { + i64 offset = type->Struct.offsets[i]; + Entity *field = type->Struct.fields[i]; + irValue *field_hasher = ir_get_hasher_proc_for_type(m, field->type); + irValue *ptr = ir_emit_ptr_offset(proc, data, ir_const_uintptr(offset)); - args[0] = ptr; - args[1] = seed; - seed = ir_emit_call(proc, field_hasher, args); - } - ir_emit(proc, ir_instr_return(proc, seed)); + args[0] = ptr; + args[1] = seed; + seed = ir_emit_call(proc, field_hasher, args); } + ir_emit(proc, ir_instr_return(proc, seed)); } else if (type->kind == Type_Array) { - if (is_type_simple_compare(type)) { - i64 sz = type_size_of(type); - auto args = array_make(permanent_allocator(), 3); - args[0] = data; - args[1] = seed; - args[2] = ir_const_int(sz); - irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); - ir_emit(proc, ir_instr_return(proc, res)); - } else { - irValue *pres = ir_add_local_generated(proc, t_uintptr, false); - ir_emit_store(proc, pres, seed); + irValue *pres = ir_add_local_generated(proc, t_uintptr, false); + ir_emit_store(proc, pres, seed); - auto args = array_make(permanent_allocator(), 2); - irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem); + auto args = array_make(permanent_allocator(), 2); + irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem); - auto loop_data = ir_loop_start(proc, type->Array.count, t_i32); + auto loop_data = ir_loop_start(proc, type->Array.count, t_i32); - data = ir_emit_conv(proc, data, pt); + data = ir_emit_conv(proc, data, pt); - irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx); - args[0] = ptr; - args[1] = ir_emit_load(proc, pres); - irValue *new_seed = ir_emit_call(proc, elem_hasher, args); - ir_emit_store(proc, pres, new_seed); + irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx); + args[0] = ptr; + args[1] = ir_emit_load(proc, pres); + irValue *new_seed = ir_emit_call(proc, elem_hasher, args); + ir_emit_store(proc, pres, new_seed); - ir_loop_end(proc, loop_data); + ir_loop_end(proc, loop_data); - irValue *res = ir_emit_load(proc, pres); - ir_emit(proc, ir_instr_return(proc, res)); - } + irValue *res = ir_emit_load(proc, pres); + ir_emit(proc, ir_instr_return(proc, res)); } else if (type->kind == Type_EnumeratedArray) { - if (is_type_simple_compare(type)) { - i64 sz = type_size_of(type); - auto args = array_make(permanent_allocator(), 3); - args[0] = data; - args[1] = seed; - args[2] = ir_const_int(sz); - irValue *res = ir_emit_runtime_call(proc, "default_hasher_n", args); - ir_emit(proc, ir_instr_return(proc, res)); - } else { - irValue *pres = ir_add_local_generated(proc, t_uintptr, false); - ir_emit_store(proc, pres, seed); + irValue *pres = ir_add_local_generated(proc, t_uintptr, false); + ir_emit_store(proc, pres, seed); - auto args = array_make(permanent_allocator(), 2); - irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem); + auto args = array_make(permanent_allocator(), 2); + irValue *elem_hasher = ir_get_hasher_proc_for_type(m, type->Array.elem); - auto loop_data = ir_loop_start(proc, type->Array.count, t_i32); + auto loop_data = ir_loop_start(proc, type->Array.count, t_i32); - data = ir_emit_conv(proc, data, pt); + data = ir_emit_conv(proc, data, pt); - irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx); - args[0] = ptr; - args[1] = ir_emit_load(proc, pres); - irValue *new_seed = ir_emit_call(proc, elem_hasher, args); - ir_emit_store(proc, pres, new_seed); + irValue *ptr = ir_emit_array_ep(proc, data, loop_data.idx); + args[0] = ptr; + args[1] = ir_emit_load(proc, pres); + irValue *new_seed = ir_emit_call(proc, elem_hasher, args); + ir_emit_store(proc, pres, new_seed); - ir_loop_end(proc, loop_data); + ir_loop_end(proc, loop_data); - irValue *res = ir_emit_load(proc, pres); - ir_emit(proc, ir_instr_return(proc, res)); - } + irValue *res = ir_emit_load(proc, pres); + ir_emit(proc, ir_instr_return(proc, res)); } else if (is_type_cstring(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; @@ -5105,25 +5109,7 @@ irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { irValue *res = ir_emit_runtime_call(proc, "default_hasher_string", args); ir_emit(proc, ir_instr_return(proc, res)); } else { - GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type)); - - i64 sz = type_size_of(type); - char const *name = nullptr; - switch (sz) { - case 1: name = "default_hasher1"; break; - case 2: name = "default_hasher2"; break; - case 4: name = "default_hasher4"; break; - case 8: name = "default_hasher8"; break; - case 16: name = "default_hasher16"; break; - default: GB_PANIC("unhandled hasher for key type: %s", type_to_string(type)); - } - GB_ASSERT(name != nullptr); - - auto args = array_make(permanent_allocator(), 2); - args[0] = data; - args[1] = seed; - irValue *res = ir_emit_runtime_call(proc, name, args); - ir_emit(proc, ir_instr_return(proc, res)); + GB_PANIC("Unhandled type for hasher: %s", type_to_string(type)); } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 140d01292..b37744b20 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -9249,6 +9249,32 @@ lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type) { return {compare_proc->value, compare_proc->type}; } +lbValue lb_simple_compare_hash(lbProcedure *p, Type *type, lbValue data, lbValue seed) { + GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type)); + + i64 sz = type_size_of(type); + char const *name = nullptr; + switch (sz) { + case 1: name = "default_hasher1"; break; + case 2: name = "default_hasher2"; break; + case 4: name = "default_hasher4"; break; + case 8: name = "default_hasher8"; break; + case 16: name = "default_hasher16"; break; + } + if (name != nullptr) { + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + return lb_emit_runtime_call(p, name, args); + } + + auto args = array_make(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = lb_const_int(p->module, t_int, type_size_of(type)); + return lb_emit_runtime_call(p, "default_hasher_n", args); +} + lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { Type *original_type = type; type = core_type(type); @@ -9259,11 +9285,9 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { auto key = hash_type(type); lbProcedure **found = map_get(&m->hasher_procs, key); - lbProcedure *hasher_proc = nullptr; if (found) { - hasher_proc = *found; - GB_ASSERT(hasher_proc != nullptr); - return {hasher_proc->value, hasher_proc->type}; + GB_ASSERT(*found != nullptr); + return {(*found)->value, (*found)->type}; } static u32 proc_index = 0; @@ -9276,102 +9300,77 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_hasher_proc); map_set(&m->hasher_procs, key, p); lb_begin_procedure_body(p); + defer (lb_end_procedure_body(p)); LLVMValueRef x = LLVMGetParam(p->value, 0); LLVMValueRef y = LLVMGetParam(p->value, 1); lbValue data = {x, t_rawptr}; lbValue seed = {y, t_uintptr}; + if (is_type_simple_compare(type)) { + lbValue res = lb_simple_compare_hash(p, type, data, seed); + LLVMBuildRet(p->builder, res.value); + return {p->value, p->type}; + } + if (type->kind == Type_Struct) { type_set_offsets(type); - if (is_type_simple_compare(type)) { - i64 sz = type_size_of(type); - auto args = array_make(permanent_allocator(), 3); - args[0] = data; - args[1] = seed; - args[2] = lb_const_int(m, t_int, sz); - lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); - LLVMBuildRet(p->builder, res.value); - } else { - data = lb_emit_conv(p, data, t_u8_ptr); + data = lb_emit_conv(p, data, t_u8_ptr); - auto args = array_make(permanent_allocator(), 2); - for_array(i, type->Struct.fields) { - i64 offset = type->Struct.offsets[i]; - Entity *field = type->Struct.fields[i]; - lbValue field_hasher = lb_get_hasher_proc_for_type(m, field->type); - lbValue ptr = lb_emit_ptr_offset(p, data, lb_const_int(m, t_uintptr, offset)); + auto args = array_make(permanent_allocator(), 2); + for_array(i, type->Struct.fields) { + i64 offset = type->Struct.offsets[i]; + Entity *field = type->Struct.fields[i]; + lbValue field_hasher = lb_get_hasher_proc_for_type(m, field->type); + lbValue ptr = lb_emit_ptr_offset(p, data, lb_const_int(m, t_uintptr, offset)); - args[0] = ptr; - args[1] = seed; - seed = lb_emit_call(p, field_hasher, args); - } - LLVMBuildRet(p->builder, seed.value); + args[0] = ptr; + args[1] = seed; + seed = lb_emit_call(p, field_hasher, args); } + LLVMBuildRet(p->builder, seed.value); } else if (type->kind == Type_Array) { - if (is_type_simple_compare(type)) { - i64 sz = type_size_of(type); - auto args = array_make(permanent_allocator(), 3); - args[0] = data; - args[1] = seed; - args[2] = lb_const_int(m, t_int, sz); - lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); - LLVMBuildRet(p->builder, res.value); - } else { - lbAddr pres = lb_add_local_generated(p, t_uintptr, false); - lb_addr_store(p, pres, seed); + lbAddr pres = lb_add_local_generated(p, t_uintptr, false); + lb_addr_store(p, pres, seed); - auto args = array_make(permanent_allocator(), 2); - lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->Array.elem); + auto args = array_make(permanent_allocator(), 2); + lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->Array.elem); - auto loop_data = lb_loop_start(p, type->Array.count, t_i32); + auto loop_data = lb_loop_start(p, type->Array.count, t_i32); - data = lb_emit_conv(p, data, pt); + data = lb_emit_conv(p, data, pt); - lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx); - args[0] = ptr; - args[1] = lb_addr_load(p, pres); - lbValue new_seed = lb_emit_call(p, elem_hasher, args); - lb_addr_store(p, pres, new_seed); + lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx); + args[0] = ptr; + args[1] = lb_addr_load(p, pres); + lbValue new_seed = lb_emit_call(p, elem_hasher, args); + lb_addr_store(p, pres, new_seed); - lb_loop_end(p, loop_data); + lb_loop_end(p, loop_data); - lbValue res = lb_addr_load(p, pres); - LLVMBuildRet(p->builder, res.value); - } + lbValue res = lb_addr_load(p, pres); + LLVMBuildRet(p->builder, res.value); } else if (type->kind == Type_EnumeratedArray) { - if (is_type_simple_compare(type)) { - i64 sz = type_size_of(type); - auto args = array_make(permanent_allocator(), 3); - args[0] = data; - args[1] = seed; - args[2] = lb_const_int(m, t_int, sz); - lbValue res = lb_emit_runtime_call(p, "default_hasher_n", args); - LLVMBuildRet(p->builder, res.value); - } else { - lbAddr res = lb_add_local_generated(p, t_uintptr, false); - lb_addr_store(p, res, seed); - - auto args = array_make(permanent_allocator(), 2); - lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->EnumeratedArray.elem); + lbAddr res = lb_add_local_generated(p, t_uintptr, false); + lb_addr_store(p, res, seed); - auto loop_data = lb_loop_start(p, type->EnumeratedArray.count, t_i32); + auto args = array_make(permanent_allocator(), 2); + lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->EnumeratedArray.elem); - data = lb_emit_conv(p, data, pt); + auto loop_data = lb_loop_start(p, type->EnumeratedArray.count, t_i32); - lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx); - args[0] = ptr; - args[1] = lb_addr_load(p, res); - lbValue new_seed = lb_emit_call(p, elem_hasher, args); - lb_addr_store(p, res, new_seed); + data = lb_emit_conv(p, data, pt); - lb_loop_end(p, loop_data); - - lbValue vres = lb_addr_load(p, res); - LLVMBuildRet(p->builder, vres.value); - } + lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx); + args[0] = ptr; + args[1] = lb_addr_load(p, res); + lbValue new_seed = lb_emit_call(p, elem_hasher, args); + lb_addr_store(p, res, new_seed); + lb_loop_end(p, loop_data); + lbValue vres = lb_addr_load(p, res); + LLVMBuildRet(p->builder, vres.value); } else if (is_type_cstring(type)) { auto args = array_make(permanent_allocator(), 2); args[0] = data; @@ -9385,31 +9384,10 @@ lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { lbValue res = lb_emit_runtime_call(p, "default_hasher_string", args); LLVMBuildRet(p->builder, res.value); } else { - GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type)); - - i64 sz = type_size_of(type); - char const *name = nullptr; - switch (sz) { - case 1: name = "default_hasher1"; break; - case 2: name = "default_hasher2"; break; - case 4: name = "default_hasher4"; break; - case 8: name = "default_hasher8"; break; - case 16: name = "default_hasher16"; break; - default: GB_PANIC("unhandled hasher for key type: %s", type_to_string(type)); - } - GB_ASSERT(name != nullptr); - - auto args = array_make(permanent_allocator(), 2); - args[0] = data; - args[1] = seed; - lbValue res = lb_emit_runtime_call(p, name, args); - LLVMBuildRet(p->builder, res.value); + GB_PANIC("Unhandled type for hasher: %s", type_to_string(type)); } - lb_end_procedure_body(p); - - hasher_proc = p; - return {hasher_proc->value, hasher_proc->type}; + return {p->value, p->type}; } -- cgit v1.2.3 From f06f33872ca22ca9afd1787b130ee3fb5fb2d723 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 18:17:21 +0000 Subject: Make 16 simple hasher cases for small types --- core/runtime/dynamic_map_internal.odin | 16 ++++++++++++- src/check_type.cpp | 42 +++++++++++++++------------------- src/ir.cpp | 42 ++++++++++++++-------------------- src/llvm_backend.cpp | 14 ++++-------- 4 files changed, 55 insertions(+), 59 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 7d5ff017b..667a56575 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -77,7 +77,7 @@ default_hash_ptr :: inline proc "contextless" (data: rawptr, size: int) -> uintp } @(private) -_default_hasher_const :: inline proc "contextless" (data: rawptr, seed: uintptr, $N: uint) -> uintptr { +_default_hasher_const :: inline proc "contextless" (data: rawptr, seed: uintptr, $N: uint) -> uintptr where N <= 16 { h := u64(seed) + 0xcbf29ce484222325; p := uintptr(data); inline for _ in 0.. uintptr { return inline _default_hasher_const(data, seed, 1); } default_hasher2 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 2); } +default_hasher3 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 3); } default_hasher4 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 4); } +default_hasher5 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 5); } +default_hasher6 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 6); } +default_hasher7 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 7); } default_hasher8 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 8); } +default_hasher9 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 9); } +default_hasher10 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 10); } +default_hasher11 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 11); } +default_hasher12 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 12); } +default_hasher13 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 13); } +default_hasher14 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 14); } +default_hasher15 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 15); } default_hasher16 :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { return inline _default_hasher_const(data, seed, 16); } + default_hasher_string :: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr { h := u64(seed) + 0xcbf29ce484222325; str := (^[]byte)(data)^; diff --git a/src/check_type.cpp b/src/check_type.cpp index 9c8308757..ab69c89bc 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2860,37 +2860,31 @@ void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) { return; } + if (is_type_simple_compare(key)) { + i64 sz = type_size_of(key); + if (1 <= sz && sz <= 16) { + char buf[20] = {}; + gb_snprintf(buf, 20, "default_hasher%d", cast(i32)sz); + add_package_dependency(ctx, "runtime", buf); + return; + } else { + add_package_dependency(ctx, "runtime", "default_hasher_n"); + return; + } + } + if (key->kind == Type_Struct) { add_package_dependency(ctx, "runtime", "default_hasher_n"); - if (!is_type_simple_compare(key)) { - for_array(i, key->Struct.fields) { - Entity *field = key->Struct.fields[i]; - add_map_key_type_dependencies(ctx, field->type); - } + for_array(i, key->Struct.fields) { + Entity *field = key->Struct.fields[i]; + add_map_key_type_dependencies(ctx, field->type); } } else if (key->kind == Type_EnumeratedArray) { add_package_dependency(ctx, "runtime", "default_hasher_n"); - if (!is_type_simple_compare(key->EnumeratedArray.elem)) { - add_map_key_type_dependencies(ctx, key->EnumeratedArray.elem); - } + add_map_key_type_dependencies(ctx, key->EnumeratedArray.elem); } else if (key->kind == Type_Array) { add_package_dependency(ctx, "runtime", "default_hasher_n"); - if (!is_type_simple_compare(key->Array.elem)) { - add_map_key_type_dependencies(ctx, key->Array.elem); - } - } else { - if (!is_type_simple_compare(key)) { - GB_PANIC("HERE"); - } - - i64 sz = type_size_of(key); - switch (sz) { - case 1: add_package_dependency(ctx, "runtime", "default_hasher1"); break; - case 2: add_package_dependency(ctx, "runtime", "default_hasher2"); break; - case 4: add_package_dependency(ctx, "runtime", "default_hasher4"); break; - case 8: add_package_dependency(ctx, "runtime", "default_hasher8"); break; - case 16: add_package_dependency(ctx, "runtime", "default_hasher16"); break; - } + add_map_key_type_dependencies(ctx, key->Array.elem); } } } diff --git a/src/ir.cpp b/src/ir.cpp index 06d88ae5b..0d9292a50 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4969,15 +4969,10 @@ irValue *ir_simple_compare_hash(irProcedure *p, Type *type, irValue *data, irVal GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type)); i64 sz = type_size_of(type); - char const *name = nullptr; - switch (sz) { - case 1: name = "default_hasher1"; break; - case 2: name = "default_hasher2"; break; - case 4: name = "default_hasher4"; break; - case 8: name = "default_hasher8"; break; - case 16: name = "default_hasher16"; break; - } - if (name != nullptr) { + if (1 <= sz && sz <= 16) { + char name[20] = {}; + gb_snprintf(name, 20, "default_hasher%d", cast(i32)sz); + auto args = array_make(permanent_allocator(), 2); args[0] = data; args[1] = seed; @@ -5038,7 +5033,19 @@ irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { return p; } - if (type->kind == Type_Struct) { + if (is_type_cstring(type)) { + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + irValue *res = ir_emit_runtime_call(proc, "default_hasher_cstring", args); + ir_emit(proc, ir_instr_return(proc, res)); + } else if (is_type_string(type)) { + auto args = array_make(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + irValue *res = ir_emit_runtime_call(proc, "default_hasher_string", args); + ir_emit(proc, ir_instr_return(proc, res)); + } else if (type->kind == Type_Struct) { type_set_offsets(type); data = ir_emit_conv(proc, data, t_u8_ptr); @@ -5096,25 +5103,10 @@ irValue *ir_get_hasher_proc_for_type(irModule *m, Type *type) { irValue *res = ir_emit_load(proc, pres); ir_emit(proc, ir_instr_return(proc, res)); - } else if (is_type_cstring(type)) { - auto args = array_make(permanent_allocator(), 2); - args[0] = data; - args[1] = seed; - irValue *res = ir_emit_runtime_call(proc, "default_hasher_cstring", args); - ir_emit(proc, ir_instr_return(proc, res)); - } else if (is_type_string(type)) { - auto args = array_make(permanent_allocator(), 2); - args[0] = data; - args[1] = seed; - irValue *res = ir_emit_runtime_call(proc, "default_hasher_string", args); - ir_emit(proc, ir_instr_return(proc, res)); } else { GB_PANIC("Unhandled type for hasher: %s", type_to_string(type)); } - - ir_end_procedure_body(proc); - return p; } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index b37744b20..001a44895 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -9253,15 +9253,11 @@ lbValue lb_simple_compare_hash(lbProcedure *p, Type *type, lbValue data, lbValue GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type)); i64 sz = type_size_of(type); - char const *name = nullptr; - switch (sz) { - case 1: name = "default_hasher1"; break; - case 2: name = "default_hasher2"; break; - case 4: name = "default_hasher4"; break; - case 8: name = "default_hasher8"; break; - case 16: name = "default_hasher16"; break; - } - if (name != nullptr) { + + if (1 <= sz && sz <= 16) { + char name[20] = {}; + gb_snprintf(name, 20, "default_hasher%d", cast(i32)sz); + auto args = array_make(permanent_allocator(), 2); args[0] = data; args[1] = seed; -- cgit v1.2.3 From 76e6624dbb065c0bba8d5512613cd3083dd79fda Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Dec 2020 19:21:00 +0000 Subject: Remove type name generation for procedures in ir.cpp --- src/ir.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 0d9292a50..867557e21 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7064,6 +7064,9 @@ void ir_gen_global_type_name(irModule *m, Entity *e, String name) { if (!ir_min_dep_entity(m, e)) { return; } + if (is_type_proc(e->type)) { + return; + } irValue *t = ir_value_type_name(name, e->type); ir_module_add_value(m, e, t); string_map_set(&m->members, name, t); -- cgit v1.2.3 From 1a8ea6113a16e1a762106ba97442c1e991041841 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Dec 2020 19:52:08 +0000 Subject: Remove `hash` field in runtime.Source_Code_Location --- core/runtime/core.odin | 1 - core/runtime/error_checks.odin | 10 +++++----- src/ir.cpp | 13 ------------- src/ir_print.cpp | 3 --- src/llvm_backend.cpp | 15 ++------------- 5 files changed, 7 insertions(+), 35 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/runtime/core.odin b/core/runtime/core.odin index b23358b5c..0dfef269c 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -257,7 +257,6 @@ Source_Code_Location :: struct { file_path: string, line, column: int, procedure: string, - hash: u64, } Assertion_Failure_Proc :: #type proc(prefix, message: string, loc: Source_Code_Location); diff --git a/core/runtime/error_checks.odin b/core/runtime/error_checks.odin index 7c442510e..38d6641ab 100644 --- a/core/runtime/error_checks.odin +++ b/core/runtime/error_checks.odin @@ -23,7 +23,7 @@ bounds_check_error :: proc "contextless" (file: string, line, column: int, index } handle_error :: proc "contextless" (file: string, line, column: int, index, count: int) { context = default_context(); - print_caller_location(Source_Code_Location{file, line, column, "", 0}); + print_caller_location(Source_Code_Location{file, line, column, ""}); print_string(" Index "); print_i64(i64(index)); print_string(" is out of bounds range 0:"); @@ -36,7 +36,7 @@ bounds_check_error :: proc "contextless" (file: string, line, column: int, index slice_handle_error :: proc "contextless" (file: string, line, column: int, lo, hi: int, len: int) -> ! { context = default_context(); - print_caller_location(Source_Code_Location{file, line, column, "", 0}); + print_caller_location(Source_Code_Location{file, line, column, ""}); print_string(" Invalid slice indices: "); print_i64(i64(lo)); print_string(":"); @@ -67,7 +67,7 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: int, } handle_error :: proc "contextless" (file: string, line, column: int, low, high, max: int) { context = default_context(); - print_caller_location(Source_Code_Location{file, line, column, "", 0}); + print_caller_location(Source_Code_Location{file, line, column, ""}); print_string(" Invalid dynamic array values: "); print_i64(i64(low)); print_string(":"); @@ -87,7 +87,7 @@ type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column } handle_error :: proc "contextless" (file: string, line, column: int, from, to: typeid) { context = default_context(); - print_caller_location(Source_Code_Location{file, line, column, "", 0}); + print_caller_location(Source_Code_Location{file, line, column, ""}); print_string(" Invalid type assertion from "); print_typeid(from); print_string(" to "); @@ -135,7 +135,7 @@ type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, colum actual := variant_type(from, from_data); - print_caller_location(Source_Code_Location{file, line, column, "", 0}); + print_caller_location(Source_Code_Location{file, line, column, ""}); print_string(" Invalid type assertion from "); print_typeid(from); print_string(" to "); diff --git a/src/ir.cpp b/src/ir.cpp index 867557e21..1e364c7ba 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -458,7 +458,6 @@ struct irValueSourceCodeLocation { irValue *line; irValue *column; irValue *procedure; - u64 hash; }; @@ -7176,17 +7175,6 @@ bool is_double_pointer(Type *t) { return is_type_pointer(td); } - -u64 ir_generate_source_code_location_hash(TokenPos pos) { - u64 h = 0xcbf29ce484222325; - for (isize i = 0; i < pos.file.len; i++) { - h = (h ^ u64(pos.file[i])) * 0x100000001b3; - } - h = h ^ (u64(pos.line) * 0x100000001b3); - h = h ^ (u64(pos.column) * 0x100000001b3); - return h; -} - irValue *ir_emit_source_code_location(irProcedure *proc, String procedure, TokenPos pos) { gbAllocator a = ir_allocator(); irValue *v = ir_alloc_value(irValue_SourceCodeLocation); @@ -7194,7 +7182,6 @@ irValue *ir_emit_source_code_location(irProcedure *proc, String procedure, Token v->SourceCodeLocation.line = ir_const_int(pos.line); v->SourceCodeLocation.column = ir_const_int(pos.column); v->SourceCodeLocation.procedure = ir_find_or_add_entity_string(proc->module, procedure); - v->SourceCodeLocation.hash = ir_generate_source_code_location_hash(pos); return v; } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index a04f7b657..a58ddbe0f 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1430,7 +1430,6 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin irValue *line = value->SourceCodeLocation.line; irValue *column = value->SourceCodeLocation.column; irValue *procedure = value->SourceCodeLocation.procedure; - u64 hash = value->SourceCodeLocation.hash; ir_write_byte(f, '{'); ir_print_type(f, m, t_string); ir_write_byte(f, ' '); ir_print_value(f, m, file, t_string); @@ -1440,8 +1439,6 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin ir_print_type(f, m, t_int); ir_write_byte(f, ' '); ir_print_value(f, m, column, t_int); ir_write_string(f, str_lit(", ")); ir_print_type(f, m, t_string); ir_write_byte(f, ' '); ir_print_value(f, m, procedure, t_string); - ir_write_string(f, str_lit(", ")); - ir_print_type(f, m, t_u64); ir_write_byte(f, ' '); ir_write_u64(f, hash); ir_write_byte(f, '}'); break; } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 8063bdc8b..213c05a52 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -5667,28 +5667,17 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc return lb_const_nil(m, original_type); } -u64 lb_generate_source_code_location_hash(TokenPos const &pos) { - u64 h = 0xcbf29ce484222325; - for (isize i = 0; i < pos.file.len; i++) { - h = (h ^ u64(pos.file[i])) * 0x100000001b3; - } - h = h ^ (u64(pos.line) * 0x100000001b3); - h = h ^ (u64(pos.column) * 0x100000001b3); - return h; -} - lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, TokenPos const &pos) { lbModule *m = p->module; - LLVMValueRef fields[5] = {}; + LLVMValueRef fields[4] = {}; fields[0]/*file*/ = lb_find_or_add_entity_string(p->module, pos.file).value; fields[1]/*line*/ = lb_const_int(m, t_int, pos.line).value; fields[2]/*column*/ = lb_const_int(m, t_int, pos.column).value; fields[3]/*procedure*/ = lb_find_or_add_entity_string(p->module, procedure).value; - fields[4]/*hash*/ = lb_const_int(m, t_u64, lb_generate_source_code_location_hash(pos)).value; lbValue res = {}; - res.value = LLVMConstNamedStruct(lb_type(m, t_source_code_location), fields, 5); + res.value = LLVMConstNamedStruct(lb_type(m, t_source_code_location), fields, gb_count_of(fields)); res.type = t_source_code_location; return res; } -- cgit v1.2.3 From 069c6cac3f42ec7a2428062b0e8c481b755534ad Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 5 Dec 2020 20:47:50 +0000 Subject: Add package name and source code location to `Type_Info_Named` --- core/runtime/core.odin | 7 ++++++- src/ir.cpp | 15 +++++++++++++++ src/llvm_backend.cpp | 23 ++++++++++++++++++++++- 3 files changed, 43 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 0dfef269c..2a744a241 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -55,7 +55,12 @@ Type_Info_Struct_Soa_Kind :: enum u8 { } // Variant Types -Type_Info_Named :: struct {name: string, base: ^Type_Info}; +Type_Info_Named :: struct { + name: string, + base: ^Type_Info, + pkg: string, + loc: Source_Code_Location, +}; Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness}; Type_Info_Rune :: struct {}; Type_Info_Float :: struct {endianness: Platform_Endianness}; diff --git a/src/ir.cpp b/src/ir.cpp index 1e364c7ba..e46eb27fb 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12172,6 +12172,21 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), name); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), gtip); + + if (t->Named.type_name->pkg) { + irValue *name = ir_const_string(proc->module, t->Named.type_name->pkg->name); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), name); + } + + String proc_name = {}; + if (t->Named.type_name->parent_proc_decl) { + DeclInfo *decl = t->Named.type_name->parent_proc_decl; + if (decl->entity && decl->entity->kind == Entity_Procedure) { + proc_name = decl->entity->token.string; + } + } + irValue *loc = ir_emit_source_code_location(proc, proc_name, t->Named.type_name->token.pos); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), loc); break; } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 213c05a52..d92108044 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -11973,9 +11973,30 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da switch (t->kind) { case Type_Named: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_named_ptr); - LLVMValueRef vals[2] = { + + LLVMValueRef pkg_name = nullptr; + if (t->Named.type_name->pkg) { + pkg_name = lb_const_string(m, t->Named.type_name->pkg->name).value; + } else { + pkg_name = LLVMConstNull(lb_type(m, t_string)); + } + + String proc_name = {}; + if (t->Named.type_name->parent_proc_decl) { + DeclInfo *decl = t->Named.type_name->parent_proc_decl; + if (decl->entity && decl->entity->kind == Entity_Procedure) { + proc_name = decl->entity->token.string; + } + } + TokenPos pos = t->Named.type_name->token.pos; + + lbValue loc = lb_emit_source_code_location(p, proc_name, pos); + + LLVMValueRef vals[4] = { lb_const_string(p->module, t->Named.type_name->token.string).value, lb_get_type_info_ptr(m, t->Named.base).value, + pkg_name, + loc.value }; lbValue res = {}; -- cgit v1.2.3