From c26cb470a22e1985bbb7ec878a402ad8f78ef75e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 9 Nov 2020 10:27:27 +0000 Subject: Fix LLVM-API type cycle for procedures of named procedures --- src/check_type.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 93040e493..62b5fd8e1 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2209,6 +2209,11 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall return new_type; } + if (is_type_proc(original_type)) { + // NOTE(bill): Force a cast to prevent a possible type cycle + return t_rawptr; + } + if (cc == ProcCC_None || cc == ProcCC_PureNone || cc == ProcCC_InlineAsm) { return new_type; } @@ -2332,6 +2337,11 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal return new_type; } + if (is_type_proc(single_type)) { + // NOTE(bill): Force a cast to prevent a possible type cycle + return t_rawptr; + } + if (is_type_simd_vector(single_type)) { return new_type; } @@ -2451,22 +2461,29 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) { return; } - if (type->Proc.abi_types_set) { + if (type->Proc.abi_types_set || type->flags & TypeFlag_InProcessOfCheckingABI) { return; } + u32 flags = type->flags; + type->flags |= TypeFlag_InProcessOfCheckingABI; + type->Proc.abi_compat_params = array_make(allocator, cast(isize)type->Proc.param_count); for (i32 i = 0; i < type->Proc.param_count; i++) { Entity *e = type->Proc.params->Tuple.variables[i]; if (e->kind == Entity_Variable) { Type *original_type = e->type; + if (is_type_named(original_type) && is_type_proc(original_type)) { + continue; + } + Type *new_type = type_to_abi_compat_param_type(allocator, original_type, type->Proc.calling_convention); type->Proc.abi_compat_params[i] = new_type; switch (type->Proc.calling_convention) { case ProcCC_Odin: case ProcCC_Contextless: case ProcCC_Pure: - if (is_type_pointer(new_type) & !is_type_pointer(e->type)) { + if (is_type_pointer(new_type) && !is_type_pointer(e->type) && !is_type_proc(e->type)) { e->flags |= EntityFlag_ImplicitReference; } break; @@ -2474,7 +2491,7 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) { if (build_context.ODIN_OS == "linux" || build_context.ODIN_OS == "darwin") { - if (is_type_pointer(new_type) & !is_type_pointer(e->type)) { + if (is_type_pointer(new_type) & !is_type_pointer(e->type) && !is_type_proc(e->type)) { e->flags |= EntityFlag_ByVal; } } @@ -2499,6 +2516,7 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) { type->Proc.return_by_pointer = abi_compat_return_by_pointer(allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type); type->Proc.abi_types_set = true; + type->flags = flags; } // NOTE(bill): 'operands' is for generating non generic procedure type -- cgit v1.2.3 From 7909a9f5a599af020cfb151f99fe740d62517def Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 9 Nov 2020 10:36:09 +0000 Subject: Remove debug code causing bug --- src/check_type.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 62b5fd8e1..2b9bcdb33 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2473,10 +2473,6 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) { Entity *e = type->Proc.params->Tuple.variables[i]; if (e->kind == Entity_Variable) { Type *original_type = e->type; - if (is_type_named(original_type) && is_type_proc(original_type)) { - continue; - } - Type *new_type = type_to_abi_compat_param_type(allocator, original_type, type->Proc.calling_convention); type->Proc.abi_compat_params[i] = new_type; switch (type->Proc.calling_convention) { -- cgit v1.2.3 From 31f4590f4b291bd5a21248d2c27ab8630b3e5fd9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 9 Nov 2020 13:04:36 +0000 Subject: Fix default parameters on record types --- src/check_expr.cpp | 63 +++++++++++++++++++++++----- src/check_type.cpp | 119 ++++++++++++++++++++++++++++++++++++++--------------- src/entity.cpp | 1 + src/parser.cpp | 4 +- 4 files changed, 142 insertions(+), 45 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 02b54c80a..01e971ac7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7338,6 +7338,7 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper Entity *e = params->variables[i]; if (e->kind == Entity_Constant) { check_expr_with_type_hint(c, &operands[i], fv->value, e->type); + continue; } } @@ -7371,9 +7372,22 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper TypeTuple *tuple = get_record_polymorphic_params(original_type); isize param_count = tuple->variables.count; + isize minimum_param_count = param_count; + for (minimum_param_count = tuple->variables.count-1; minimum_param_count >= 0; minimum_param_count--) { + Entity *e = tuple->variables[minimum_param_count]; + if (e->kind != Entity_Constant) { + break; + } + if (e->Constant.param_value.kind == ParameterValue_Invalid) { + break; + } + } Array ordered_operands = operands; - if (named_fields) { + if (!named_fields) { + ordered_operands = array_make(c->allocator, param_count); + array_copy(&ordered_operands, operands, 0); + } else { bool *visited = gb_alloc_array(c->allocator, bool, param_count); // LEAK(bill) @@ -7440,26 +7454,55 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper return err; } - if (param_count < ordered_operands.count) { - error(call, "Too many polymorphic type arguments, expected %td, got %td", param_count, ordered_operands.count); - err = CallArgumentError_TooManyArguments; - } else if (param_count > ordered_operands.count) { - error(call, "Too few polymorphic type arguments, expected %td, got %td", param_count, ordered_operands.count); - err = CallArgumentError_TooFewArguments; + if (minimum_param_count != param_count) { + if (param_count < ordered_operands.count) { + error(call, "Too many polymorphic type arguments, expected a maximum of %td, got %td", param_count, ordered_operands.count); + err = CallArgumentError_TooManyArguments; + } else if (minimum_param_count > ordered_operands.count) { + error(call, "Too few polymorphic type arguments, expected a minimum of %td, got %td", minimum_param_count, ordered_operands.count); + err = CallArgumentError_TooFewArguments; + } + } else { + if (param_count < ordered_operands.count) { + error(call, "Too many polymorphic type arguments, expected %td, got %td", param_count, ordered_operands.count); + err = CallArgumentError_TooManyArguments; + } else if (param_count > ordered_operands.count) { + error(call, "Too few polymorphic type arguments, expected %td, got %td", param_count, ordered_operands.count); + err = CallArgumentError_TooFewArguments; + } } if (err != 0) { return err; } + if (minimum_param_count != param_count) { + isize missing_count = 0; + // NOTE(bill): Replace missing operands with the default values (if possible) + for_array(i, ordered_operands) { + Operand *o = &ordered_operands[i]; + if (o->expr == nullptr) { + Entity *e = tuple->variables[i]; + if (e->kind == Entity_Constant) { + missing_count += 1; + o->mode = Addressing_Constant; + o->type = default_type(e->type); + o->expr = unparen_expr(e->Constant.param_value.original_ast_expr); + if (e->Constant.param_value.kind == ParameterValue_Constant) { + o->value = e->Constant.param_value.value; + } + } + } + } + } + i64 score = 0; for (isize i = 0; i < param_count; i++) { + Entity *e = tuple->variables[i]; Operand *o = &ordered_operands[i]; if (o->mode == Addressing_Invalid) { continue; } - Entity *e = tuple->variables[i]; - if (e->kind == Entity_TypeName) { if (o->mode != Addressing_Type) { if (show_error) { @@ -7800,7 +7843,7 @@ void check_expr_with_type_hint(CheckerContext *c, Operand *o, Ast *e, Type *t) { err_str = "used as a value"; break; case Addressing_Type: - err_str = "is not an expression"; + err_str = "is not an expression but a"; break; case Addressing_Builtin: err_str = "must be called"; diff --git a/src/check_type.cpp b/src/check_type.cpp index 2b9bcdb33..ace1ef898 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1,3 +1,4 @@ +ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location); void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) { t = base_type(t); @@ -408,32 +409,50 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< } ast_node(p, Field, param); Ast *type_expr = p->type; + Ast *default_value = unparen_expr(p->default_value); Type *type = nullptr; bool is_type_param = false; bool is_type_polymorphic_type = false; - if (type_expr == nullptr) { + if (type_expr == nullptr && default_value == nullptr) { error(param, "Expected a type for this parameter"); continue; } - if (type_expr->kind == Ast_Ellipsis) { - type_expr = type_expr->Ellipsis.expr; - error(param, "A polymorphic parameter cannot be variadic"); + + if (type_expr != nullptr) { + if (type_expr->kind == Ast_Ellipsis) { + type_expr = type_expr->Ellipsis.expr; + error(param, "A polymorphic parameter cannot be variadic"); + } + if (type_expr->kind == Ast_TypeidType) { + is_type_param = true; + Type *specialization = nullptr; + if (type_expr->TypeidType.specialization != nullptr) { + Ast *s = type_expr->TypeidType.specialization; + specialization = check_type(ctx, s); + } + type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization); + } else { + type = check_type(ctx, type_expr); + if (is_type_polymorphic(type)) { + is_type_polymorphic_type = true; + } + } } - if (type_expr->kind == Ast_TypeidType) { - is_type_param = true; - Type *specialization = nullptr; - if (type_expr->TypeidType.specialization != nullptr) { - Ast *s = type_expr->TypeidType.specialization; - specialization = check_type(ctx, s); + + ParameterValue param_value = {}; + if (default_value != nullptr) { + Type *out_type = nullptr; + param_value = handle_parameter_value(ctx, type, &out_type, default_value, false); + if (type == nullptr && out_type != nullptr) { + type = out_type; } - type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization); - } else { - type = check_type(ctx, type_expr); - if (is_type_polymorphic(type)) { - is_type_polymorphic_type = true; + if (param_value.kind != ParameterValue_Constant && param_value.kind != ParameterValue_Nil) { + error(default_value, "Invalid parameter value"); + param_value = {}; } } + if (type == nullptr) { error(params[i], "Invalid parameter type"); type = t_invalid; @@ -471,7 +490,14 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< Token token = name->Ident.token; if (poly_operands != nullptr) { - Operand operand = (*poly_operands)[entities.count]; + Operand operand = {}; + operand.type = t_invalid; + if (entities.count < poly_operands->count) { + operand = (*poly_operands)[entities.count]; + } else if (param_value.kind != ParameterValue_Invalid) { + operand.mode = Addressing_Constant; + operand.value = param_value.value; + } if (is_type_param) { if (is_type_polymorphic(base_type(operand.type))) { is_polymorphic = true; @@ -486,6 +512,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< } if (e == nullptr) { e = alloc_entity_constant(scope, token, operand.type, operand.value); + e->Constant.param_value = param_value; } } } else { @@ -493,7 +520,8 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< e = alloc_entity_type_name(scope, token, type); e->TypeName.is_type_alias = true; } else { - e = alloc_entity_constant(scope, token, type, empty_exact_value); + e = alloc_entity_constant(scope, token, type, param_value.value); + e->Constant.param_value = param_value; } } @@ -599,29 +627,45 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Arraytype; + Ast *default_value = unparen_expr(p->default_value); Type *type = nullptr; bool is_type_param = false; bool is_type_polymorphic_type = false; - if (type_expr == nullptr) { + if (type_expr == nullptr && default_value == nullptr) { error(param, "Expected a type for this parameter"); continue; } - if (type_expr->kind == Ast_Ellipsis) { - type_expr = type_expr->Ellipsis.expr; - error(param, "A polymorphic parameter cannot be variadic"); + if (type_expr != nullptr) { + if (type_expr->kind == Ast_Ellipsis) { + type_expr = type_expr->Ellipsis.expr; + error(param, "A polymorphic parameter cannot be variadic"); + } + if (type_expr->kind == Ast_TypeidType) { + is_type_param = true; + Type *specialization = nullptr; + if (type_expr->TypeidType.specialization != nullptr) { + Ast *s = type_expr->TypeidType.specialization; + specialization = check_type(ctx, s); + } + type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization); + } else { + type = check_type(ctx, type_expr); + if (is_type_polymorphic(type)) { + is_type_polymorphic_type = true; + } + } } - if (type_expr->kind == Ast_TypeidType) { - is_type_param = true; - Type *specialization = nullptr; - if (type_expr->TypeidType.specialization != nullptr) { - Ast *s = type_expr->TypeidType.specialization; - specialization = check_type(ctx, s); + + ParameterValue param_value = {}; + if (default_value != nullptr) { + Type *out_type = nullptr; + param_value = handle_parameter_value(ctx, type, &out_type, default_value, false); + if (type == nullptr && out_type != nullptr) { + type = out_type; } - type = alloc_type_generic(ctx->scope, 0, str_lit(""), specialization); - } else { - type = check_type(ctx, type_expr); - if (is_type_polymorphic(type)) { - is_type_polymorphic_type = true; + if (param_value.kind != ParameterValue_Constant && param_value.kind != ParameterValue_Nil) { + error(default_value, "Invalid parameter value"); + param_value = {}; } } @@ -662,7 +706,14 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, ArrayIdent.token; if (poly_operands != nullptr) { - Operand operand = (*poly_operands)[entities.count]; + Operand operand = {}; + operand.type = t_invalid; + if (entities.count < poly_operands->count) { + operand = (*poly_operands)[entities.count]; + } else if (param_value.kind != ParameterValue_Invalid) { + operand.mode = Addressing_Constant; + operand.value = param_value.value; + } if (is_type_param) { GB_ASSERT(operand.mode == Addressing_Type || operand.mode == Addressing_Invalid); @@ -675,6 +726,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, ArrayConstant.param_value = param_value; } } else { if (is_type_param) { @@ -682,6 +734,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, ArrayTypeName.is_type_alias = true; } else { e = alloc_entity_constant(scope, token, type, empty_exact_value); + e->Constant.param_value = param_value; } } diff --git a/src/entity.cpp b/src/entity.cpp index 3d354b9c8..a9d598735 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -120,6 +120,7 @@ struct Entity { union { struct { ExactValue value; + ParameterValue param_value; } Constant; struct { Ast *init_expr; // only used for some variables within procedure bodies diff --git a/src/parser.cpp b/src/parser.cpp index 330d78263..794ff231d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2122,7 +2122,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { if (allow_token(f, Token_OpenParen)) { isize param_count = 0; - polymorphic_params = parse_field_list(f, ¶m_count, 0, Token_CloseParen, false, true); + polymorphic_params = parse_field_list(f, ¶m_count, 0, Token_CloseParen, true, true); if (param_count == 0) { syntax_error(polymorphic_params, "Expected at least 1 polymorphic parameter"); polymorphic_params = nullptr; @@ -2203,7 +2203,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { if (allow_token(f, Token_OpenParen)) { isize param_count = 0; - polymorphic_params = parse_field_list(f, ¶m_count, 0, Token_CloseParen, false, true); + polymorphic_params = parse_field_list(f, ¶m_count, 0, Token_CloseParen, true, true); if (param_count == 0) { syntax_error(polymorphic_params, "Expected at least 1 polymorphic parametric"); polymorphic_params = nullptr; -- 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/check_type.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/check_type.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/check_type.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 a2461bdf6b2e5ab9db5ded4206857df74ba4d1cd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 22 Nov 2020 21:38:45 +0000 Subject: Modify llvm_abi.cpp to work correctly for win64 abi of `i128` types. (it's a pain) --- src/check_type.cpp | 6 +- src/llvm_abi.cpp | 62 +++++++---- src/llvm_backend.cpp | 293 +++++++++++++++++++++++++++------------------------ src/llvm_backend.hpp | 1 + 4 files changed, 202 insertions(+), 160 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 6ea17eca6..dfd0f093d 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2279,7 +2279,11 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall return new_type; } if (build_context.ODIN_ARCH == "amd64") { - if (is_type_integer_128bit(original_type)) { + bool is_128 = is_type_integer_128bit(original_type); + if (!is_128 && is_type_bit_set(original_type) && type_size_of(original_type) == 16) { + // is_128 = true; + } + if (is_128) { if (build_context.ODIN_OS == "windows") { return alloc_type_simd_vector(2, t_u64); } else { diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 9722bf302..258b90eb5 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -40,6 +40,9 @@ i64 llvm_align_formula(i64 off, i64 a) { bool lb_is_type_kind(LLVMTypeRef type, LLVMTypeKind kind) { + if (type == nullptr) { + return false; + } return LLVMGetTypeKind(type) == kind; } @@ -124,6 +127,7 @@ void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCa if (offset != 0 && ft->ret.kind == lbArg_Indirect && ft->ret.attribute != nullptr) { LLVMAddAttributeAtIndex(fn, offset, ft->ret.attribute); + LLVMAddAttributeAtIndex(fn, offset, noalias_attr); } lbCallingConventionKind cc_kind = lbCallingConvention_C; @@ -313,7 +317,14 @@ Type *alloc_type_proc_from_types(Type **param_types, unsigned param_count, Type return t; } -Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) { +#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)); + if (found) { + return *found; + } + GB_ASSERT_MSG(level < 64, "%s %d", LLVMPrintTypeToString(type), is_return); + LLVMTypeKind kind = LLVMGetTypeKind(type); switch (kind) { case LLVMVoidTypeKind: @@ -351,16 +362,16 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) { defer (gb_free(heap_allocator(), param_types)); for (unsigned i = 0; i < param_count; i++) { - param_types[i] = lb_abi_to_odin_type(params[i], false, /*level*/0); + param_types[i] = lb_abi_to_odin_type(m, params[i], false, level+1); } LLVMTypeRef ret = LLVMGetReturnType(elem); - Type *ret_type = lb_abi_to_odin_type(ret, true, /*level*/0); + Type *ret_type = lb_abi_to_odin_type(m, ret, true, level+1); bool is_c_vararg = !!LLVMIsFunctionVarArg(elem); return alloc_type_proc_from_types(param_types, param_count, ret_type, is_c_vararg); } - return alloc_type_pointer(lb_abi_to_odin_type(elem, false, level)); + return alloc_type_pointer(lb_abi_to_odin_type(m, elem, false, level+1)); } case LLVMFunctionTypeKind: GB_PANIC("LLVMFunctionTypeKind should not be seen on its own"); @@ -371,7 +382,12 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) { unsigned field_count = LLVMCountStructElementTypes(type); Type **fields = gb_alloc_array(heap_allocator(), Type *, field_count); for (unsigned i = 0; i < field_count; i++) { - fields[i] = lb_abi_to_odin_type(LLVMStructGetTypeAtIndex(type, i), false, level+1); + LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(type, i); + if (lb_is_type_kind(field_type, LLVMPointerTypeKind) && level > 0) { + fields[i] = t_rawptr; + } else { + fields[i] = lb_abi_to_odin_type(m, field_type, false, level+1); + } } if (is_return) { return alloc_type_tuple_from_field_types(fields, field_count, !!LLVMIsPackedStruct(type), false); @@ -384,7 +400,7 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) { { i64 count = LLVMGetArrayLength(type); - Type *elem = lb_abi_to_odin_type(LLVMGetElementType(type), false, level+1); + Type *elem = lb_abi_to_odin_type(m, LLVMGetElementType(type), false, level+1); return alloc_type_array(elem, count); } break; @@ -394,7 +410,7 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) { case LLVMVectorTypeKind: { i64 count = LLVMGetVectorSize(type); - Type *elem = lb_abi_to_odin_type(LLVMGetElementType(type), false, level+1); + Type *elem = lb_abi_to_odin_type(m, LLVMGetElementType(type), false, level+1); return alloc_type_simd_vector(count, elem); } @@ -403,7 +419,7 @@ Type *lb_abi_to_odin_type(LLVMTypeRef type, bool is_return, u32 level = 0) { return 0; } - +#endif #define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, ProcCallingConvention calling_convention) @@ -424,22 +440,24 @@ namespace lbAbi386 { return ft; } - lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) { - if (build_context.metrics.os == TargetOs_windows && - build_context.word_size == 8 && - lb_is_type_kind(type, LLVMIntegerTypeKind) && - lb_sizeof(type) == 16) { + lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) { + if (!is_return && lb_sizeof(type) > 8) { + return lb_arg_type_indirect(type, nullptr); + } + if (build_context.metrics.os == TargetOs_windows && + build_context.word_size == 8 && + lb_is_type_kind(type, LLVMIntegerTypeKind) && + type == LLVMIntTypeInContext(c, 128)) { + // NOTE(bill): Because Windows AMD64 is weird LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2); return lb_arg_type_direct(type, cast_type, nullptr, nullptr); } - - LLVMAttributeRef attr = nullptr; LLVMTypeRef i1 = LLVMInt1TypeInContext(c); if (type == i1) { - attr = lb_create_enum_attribute(c, "zeroext", true); + // attr = lb_create_enum_attribute(c, "zeroext", true); // return lb_arg_type_direct(type, i1, nullptr, attr); } return lb_arg_type_direct(type, nullptr, nullptr, attr); @@ -451,15 +469,15 @@ namespace lbAbi386 { for (unsigned i = 0; i < arg_count; i++) { LLVMTypeRef t = arg_types[i]; LLVMTypeKind kind = LLVMGetTypeKind(t); + i64 sz = lb_sizeof(t); if (kind == LLVMStructTypeKind) { - i64 sz = lb_sizeof(t); if (sz == 0) { args[i] = lb_arg_type_ignore(t); } else { args[i] = lb_arg_type_indirect(t, lb_create_enum_attribute(c, "byval", true)); } } else { - args[i] = non_struct(c, t); + args[i] = non_struct(c, t, false); } } return args; @@ -478,7 +496,7 @@ namespace lbAbi386 { } return lb_arg_type_indirect(return_type, lb_create_enum_attribute(c, "sret", true)); } - return non_struct(c, return_type); + return non_struct(c, return_type, true); } }; @@ -515,7 +533,7 @@ namespace lbAbiAmd64Win64 { break; } } else { - args[i] = lbAbi386::non_struct(c, t); + args[i] = lbAbi386::non_struct(c, t, false); } } return args; @@ -623,7 +641,7 @@ namespace lbAbiAmd64SysV { if (is_register(type)) { LLVMAttributeRef attribute = nullptr; if (type == LLVMInt1TypeInContext(c)) { - attribute = lb_create_enum_attribute(c, "zeroext", true); + // attribute = lb_create_enum_attribute(c, "zeroext", true); } return lb_arg_type_direct(type, nullptr, nullptr, attribute); } @@ -646,7 +664,7 @@ namespace lbAbiAmd64SysV { LLVMAttributeRef attr = nullptr; LLVMTypeRef i1 = LLVMInt1TypeInContext(c); if (type == i1) { - attr = lb_create_enum_attribute(c, "zeroext", true); + // attr = lb_create_enum_attribute(c, "zeroext", true); } return lb_arg_type_direct(type, nullptr, nullptr, attr); } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 62a0013bc..89a0ff667 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1114,7 +1114,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { return type; } - case Basic_typeid: return LLVMIntType(8*cast(unsigned)build_context.word_size); + case Basic_typeid: return LLVMIntTypeInContext(m->ctx, 8*cast(unsigned)build_context.word_size); // Endian Specific Types case Basic_i16le: return LLVMInt16TypeInContext(ctx); @@ -1353,130 +1353,144 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } case Type_Proc: - if (USE_LLVM_ABI) { - if (m->internal_type_level > 1) { - return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0); - } else { - unsigned param_count = 0; - if (type->Proc.calling_convention == ProcCC_Odin) { - param_count += 1; - } - - if (type->Proc.param_count != 0) { - GB_ASSERT(type->Proc.params->kind == Type_Tuple); - for_array(i, type->Proc.params->Tuple.variables) { - Entity *e = type->Proc.params->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - continue; - } + { + if (USE_LLVM_ABI) { + if (m->internal_type_level > 5) { // TODO HACK(bill): is this really enough? + return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0); + } else { + unsigned param_count = 0; + if (type->Proc.calling_convention == ProcCC_Odin) { param_count += 1; } - } - LLVMTypeRef ret = nullptr; - LLVMTypeRef *params = gb_alloc_array(heap_allocator(), LLVMTypeRef, param_count); - if (type->Proc.result_count != 0) { - Type *single_ret = reduce_tuple_to_single_type(type->Proc.results); - ret = lb_type(m, single_ret); - if (ret != nullptr) { - if (is_calling_convention_none(type->Proc.calling_convention) && - is_type_boolean(single_ret) && - type_size_of(single_ret) <= 1) { - ret = LLVMInt1TypeInContext(m->ctx); + if (type->Proc.param_count != 0) { + GB_ASSERT(type->Proc.params->kind == Type_Tuple); + for_array(i, type->Proc.params->Tuple.variables) { + Entity *e = type->Proc.params->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + param_count += 1; } } - } - - isize param_index = 0; - if (type->Proc.param_count != 0) { - GB_ASSERT(type->Proc.params->kind == Type_Tuple); - for_array(i, type->Proc.params->Tuple.variables) { - Entity *e = type->Proc.params->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - continue; + m->internal_type_level += 1; + defer (m->internal_type_level -= 1); + + LLVMTypeRef ret = nullptr; + LLVMTypeRef *params = gb_alloc_array(heap_allocator(), LLVMTypeRef, param_count); + if (type->Proc.result_count != 0) { + Type *single_ret = reduce_tuple_to_single_type(type->Proc.results); + ret = lb_type(m, single_ret); + if (ret != nullptr) { + if (is_type_boolean(single_ret) && + is_calling_convention_none(type->Proc.calling_convention) && + type_size_of(single_ret) <= 1) { + ret = LLVMInt1TypeInContext(m->ctx); + } } + } - Type *e_type = reduce_tuple_to_single_type(e->type); + isize param_index = 0; + if (type->Proc.param_count != 0) { + GB_ASSERT(type->Proc.params->kind == Type_Tuple); + for_array(i, type->Proc.params->Tuple.variables) { + Entity *e = type->Proc.params->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + continue; + } - LLVMTypeRef param_type = nullptr; - if (is_calling_convention_none(type->Proc.calling_convention) && - is_type_boolean(e_type) && - type_size_of(e_type) <= 1) { - param_type = LLVMInt1TypeInContext(m->ctx); - } else { - param_type = lb_type(m, e_type); + Type *e_type = reduce_tuple_to_single_type(e->type); + + LLVMTypeRef param_type = nullptr; + if (is_type_boolean(e_type) && + type_size_of(e_type) <= 1) { + param_type = LLVMInt1TypeInContext(m->ctx); + } else { + param_type = lb_type(m, e_type); + } + params[param_index++] = param_type; } - params[param_index++] = param_type; } - } - if (param_index < param_count) { - params[param_index++] = lb_type(m, t_context_ptr); - } - GB_ASSERT(param_index == param_count); + if (param_index < param_count) { + params[param_index++] = lb_type(m, t_context_ptr); + } + GB_ASSERT(param_index == param_count); - lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention); - map_set(&m->function_type_map, hash_type(type), ft); - return lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg); - } - } else { - set_procedure_abi_types(type); - LLVMTypeRef return_type = LLVMVoidTypeInContext(ctx); - if (type->Proc.return_by_pointer) { - // Void - } else if (type->Proc.abi_compat_result_type != nullptr) { - return_type = lb_type(m, type->Proc.abi_compat_result_type); - } + lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention); + map_set(&m->function_type_map, hash_type(type), ft); + LLVMTypeRef new_abi_fn_ptr_type = lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg); + LLVMTypeRef new_abi_fn_type = LLVMGetElementType(new_abi_fn_ptr_type); - isize extra_param_count = 0; - if (type->Proc.return_by_pointer) { - extra_param_count += 1; - } - if (type->Proc.calling_convention == ProcCC_Odin) { - extra_param_count += 1; - } + // LLVMTypeRef new_ret = LLVMGetReturnType(new_abi_fn_type); + // LLVMTypeRef old_ret = LLVMGetReturnType(old_abi_fn_type); + // unsigned new_count = LLVMCountParamTypes(new_abi_fn_type); + // unsigned old_count = LLVMCountParamTypes(old_abi_fn_type); + // GB_ASSERT_MSG(new_count == old_count, "%u %u, %s %s", new_count, old_count, LLVMPrintTypeToString(new_abi_fn_type), LLVMPrintTypeToString(old_abi_fn_type)); + return new_abi_fn_ptr_type; + } + } else { + LLVMTypeRef old_abi_fn_type = nullptr; + + set_procedure_abi_types(type); + LLVMTypeRef return_type = LLVMVoidTypeInContext(ctx); + if (type->Proc.return_by_pointer) { + // Void + } else if (type->Proc.abi_compat_result_type != nullptr) { + return_type = lb_type(m, type->Proc.abi_compat_result_type); + } - isize param_count = type->Proc.abi_compat_params.count + extra_param_count; - auto param_types = array_make(temporary_allocator(), 0, param_count); + isize extra_param_count = 0; + if (type->Proc.return_by_pointer) { + extra_param_count += 1; + } + if (type->Proc.calling_convention == ProcCC_Odin) { + extra_param_count += 1; + } - if (type->Proc.return_by_pointer) { - array_add(¶m_types, LLVMPointerType(lb_type(m, type->Proc.abi_compat_result_type), 0)); - } + isize param_count = type->Proc.abi_compat_params.count + extra_param_count; + auto param_types = array_make(temporary_allocator(), 0, param_count); - for_array(i, type->Proc.abi_compat_params) { - Type *param = type->Proc.abi_compat_params[i]; - if (param == nullptr) { - continue; - } - if (type->Proc.params->Tuple.variables[i]->flags & EntityFlag_CVarArg) { - GB_ASSERT(i+1 == type->Proc.abi_compat_params.count); - break; - } - if (is_type_tuple(param)) { - param = base_type(param); - for_array(j, param->Tuple.variables) { - Entity *v = param->Tuple.variables[j]; - if (v->kind != Entity_Variable) { - // Sanity check + if (type->Proc.return_by_pointer) { + array_add(¶m_types, LLVMPointerType(lb_type(m, type->Proc.abi_compat_result_type), 0)); + } + + for_array(i, type->Proc.abi_compat_params) { + Type *param = type->Proc.abi_compat_params[i]; + if (param == nullptr) { continue; } - LLVMTypeRef t = lb_type(m, v->type); - array_add(¶m_types, t); + if (type->Proc.params->Tuple.variables[i]->flags & EntityFlag_CVarArg) { + GB_ASSERT(i+1 == type->Proc.abi_compat_params.count); + break; + } + if (is_type_tuple(param)) { + param = base_type(param); + for_array(j, param->Tuple.variables) { + Entity *v = param->Tuple.variables[j]; + if (v->kind != Entity_Variable) { + // Sanity check + continue; + } + LLVMTypeRef t = lb_type(m, v->type); + array_add(¶m_types, t); + } + } else { + array_add(¶m_types, lb_type(m, param)); + } + } + if (type->Proc.calling_convention == ProcCC_Odin) { + array_add(¶m_types, lb_type(m, t_context_ptr)); } - } else { - array_add(¶m_types, lb_type(m, param)); - } - } - if (type->Proc.calling_convention == ProcCC_Odin) { - array_add(¶m_types, lb_type(m, t_context_ptr)); - } - LLVMTypeRef t = LLVMFunctionType(return_type, param_types.data, cast(unsigned)param_types.count, type->Proc.c_vararg); - return LLVMPointerType(t, 0); + old_abi_fn_type = LLVMFunctionType(return_type, param_types.data, cast(unsigned)param_types.count, type->Proc.c_vararg); + return LLVMPointerType(old_abi_fn_type, 0); + } } + break; case Type_BitFieldValue: - return LLVMIntType(type->BitFieldValue.bits); + return LLVMIntTypeInContext(m->ctx, type->BitFieldValue.bits); case Type_BitField: { @@ -1488,7 +1502,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { for_array(i, type->BitField.sizes) { u32 size = type->BitField.sizes[i]; - fields[i] = LLVMIntType(size); + fields[i] = LLVMIntTypeInContext(m->ctx, size); } internal_type = LLVMStructTypeInContext(ctx, fields, field_count, true); @@ -1507,7 +1521,11 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } break; case Type_BitSet: - return LLVMIntType(8*cast(unsigned)type_size_of(type)); + { + Type *ut = bit_set_to_int(type); + return lb_type(m, ut); + } + case Type_SimdVector: if (type->SimdVector.is_x86_mmx) { return LLVMX86MMXTypeInContext(ctx); @@ -1548,6 +1566,9 @@ LLVMTypeRef lb_type(lbModule *m, Type *type) { m->internal_type_level -= 1; if (USE_LLVM_ABI && m->internal_type_level == 0) { map_set(&m->types, hash_type(type), llvm_type); + if (is_type_named(type)) { + map_set(&m->llvm_types, hash_pointer(llvm_type), type); + } } return llvm_type; } @@ -1989,7 +2010,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { break; case Type_BitFieldValue: return nullptr; - // return LLVMIntType(type->BitFieldValue.bits); + // return LLVMIntTypeInContext(m->ctx, type->BitFieldValue.bits); case Type_BitField: { @@ -2003,7 +2024,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { // for_array(i, type->BitField.sizes) { // u32 size = type->BitField.sizes[i]; - // fields[i] = LLVMIntType(size); + // fields[i] = LLVMIntTypeInContext(m->ctx, size); // } // internal_type = LLVMStructTypeInContext(ctx, fields, field_count, true); @@ -2023,7 +2044,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { break; case Type_BitSet: return nullptr; - // return LLVMIntType(8*cast(unsigned)type_size_of(type)); + // return LLVMIntTypeInContext(m->ctx, 8*cast(unsigned)type_size_of(type)); case Type_SimdVector: return nullptr; // if (type->SimdVector.is_x86_mmx) { @@ -2507,9 +2528,25 @@ void lb_start_block(lbProcedure *p, lbBlock *b) { } LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRef dst_type) { + LLVMContextRef ctx = p->module->ctx; + LLVMTypeRef src_type = LLVMTypeOf(val); + + if (src_type == dst_type) { + return val; + } + i64 src_size = lb_sizeof(src_type); i64 dst_size = lb_sizeof(dst_type); + + if (dst_type == LLVMInt1TypeInContext(ctx)) { + GB_ASSERT(lb_is_type_kind(src_type, LLVMIntegerTypeKind)); + return LLVMBuildICmp(p->builder, LLVMIntNE, val, LLVMConstNull(src_type), ""); + } else if (src_type == LLVMInt1TypeInContext(ctx)) { + GB_ASSERT(lb_is_type_kind(src_type, LLVMIntegerTypeKind)); + return LLVMBuildZExtOrBitCast(p->builder, val, dst_type, ""); + } + if (src_size != dst_size && (lb_is_type_kind(src_type, LLVMVectorTypeKind) ^ lb_is_type_kind(dst_type, LLVMVectorTypeKind))) { // Okay } else { @@ -2627,11 +2664,7 @@ void lb_begin_procedure_body(lbProcedure *p) { } LLVMValueRef value = LLVMGetParam(p->value, param_offset+param_index); - if (USE_LLVM_ABI && LLVMTypeOf(value) == LLVMInt1TypeInContext(p->module->ctx)) { - value = LLVMBuildZExtOrBitCast(p->builder, value, param_type, ""); - } else { - value = OdinLLVMBuildTransmute(p, value, param_type); - } + value = OdinLLVMBuildTransmute(p, value, param_type); lbValue param = {}; param.value = value; @@ -4554,9 +4587,11 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { LLVMBuildRetVoid(p->builder); } else { LLVMValueRef ret_val = res.value; + ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.type); if (p->abi_function_type->ret.cast_type != nullptr) { ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.cast_type); } + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); LLVMBuildRet(p->builder, ret_val); } @@ -7458,18 +7493,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, if (xt == abi_type) { array_add(&processed_args, x); } else { - Type *at = lb_abi_to_odin_type(abi_type, false); - if (at == t_llvm_bool) { - x = lb_emit_conv(p, x, at); - } else if (is_type_simd_vector(at) && lb_sizeof(abi_type) > lb_sizeof(xt)) { - lbAddr v = lb_add_local_generated(p, at, false); - lbValue ptr = lb_addr_get_ptr(p, v); - ptr = lb_emit_conv(p, ptr, alloc_type_pointer(x.type)); - lb_emit_store(p, ptr, x); - x = lb_addr_load(p, v); - } else { - x = lb_emit_transmute(p, x, at); - } + x.value = OdinLLVMBuildTransmute(p, x.value, abi_type); array_add(&processed_args, x); } @@ -7509,20 +7533,14 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining); result = lb_emit_load(p, return_ptr); } else if (rt != nullptr) { - LLVMTypeRef ret_type = ft->ret.cast_type; - if (!ret_type) { - ret_type = ft->ret.type; + result = lb_emit_call_internal(p, value, {}, processed_args, rt, context_ptr, inlining); + if (ft->ret.cast_type) { + result.value = OdinLLVMBuildTransmute(p, result.value, ft->ret.cast_type); } - Type *abi_rt = lb_abi_to_odin_type(ret_type, true); - result = lb_emit_call_internal(p, value, {}, processed_args, abi_rt, context_ptr, inlining); - if (ret_type != lb_type(m, rt)) { - if (is_type_simd_vector(abi_rt) && lb_sizeof(ret_type) > type_size_of(rt)) { - lbValue ptr = lb_address_from_load_or_generate_local(p, result); - ptr = lb_emit_conv(p, ptr, alloc_type_pointer(rt)); - result = lb_emit_load(p, ptr); - } else { - result = lb_emit_transmute(p, result, rt); - } + result.value = OdinLLVMBuildTransmute(p, result.value, ft->ret.type); + result.type = rt; + if (LLVMTypeOf(result.value) == LLVMInt1TypeInContext(p->module->ctx)) { + result.type = t_llvm_bool; } if (!is_type_tuple(rt)) { result = lb_emit_conv(p, result, rt); @@ -11416,6 +11434,7 @@ void lb_init_module(lbModule *m, Checker *c) { gb_mutex_init(&m->mutex); gbAllocator a = heap_allocator(); map_init(&m->types, a); + map_init(&m->llvm_types, a); map_init(&m->values, a); string_map_init(&m->members, a); map_init(&m->procedure_values, a); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index fc5968c93..289f9d324 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -74,6 +74,7 @@ struct lbModule { gbMutex mutex; Map types; // Key: Type * + Map llvm_types; // Key: LLVMTypeRef i32 internal_type_level; Map values; // Key: Entity * -- 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/check_type.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/check_type.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 9959a069fcc016aa9d01f90cc33bf9dd57f9b1ae Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 12:48:33 +0000 Subject: Simplify internals of `map[K]V` --- core/runtime/dynamic_map_internal.odin | 101 ++++++++++++++++----------------- src/check_type.cpp | 4 +- 2 files changed, 51 insertions(+), 54 deletions(-) (limited to 'src/check_type.cpp') diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index be52ff285..cef33cbeb 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -5,11 +5,47 @@ _ :: intrinsics; INITIAL_MAP_CAP :: 16; +// Temporary data structure for comparing hashes and keys Map_Hash :: struct { hash: uintptr, 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); + + 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; +} + +__get_map_hash_from_entry :: proc "contextless" (h: Map_Header, entry: ^Map_Entry_Header) -> (hash: Map_Hash) { + hash.hash = entry.hash; + hash.key_ptr = rawptr(uintptr(entry) + h.key_offset); + return; +} + + + Map_Find_Result :: struct { hash_index: int, entry_prev: int, @@ -17,7 +53,7 @@ Map_Find_Result :: struct { } Map_Entry_Header :: struct { - hash: Map_Hash, + hash: uintptr, next: int, /* key: Key_Value, @@ -73,7 +109,7 @@ source_code_location_hash :: proc(s: Source_Code_Location) -> uintptr { __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { header := Map_Header{m = (^Raw_Map)(m)}; Entry :: struct { - hash: Map_Hash, + hash: uintptr, next: int, key: K, value: V, @@ -93,33 +129,6 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header { return header; } -__get_map_hash :: proc "contextless" (k: ^$K) -> Map_Hash { - key := k; - map_hash: Map_Hash; - - T :: intrinsics.type_core_type(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; -} - __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool { array := (^Raw_Slice)(array_); @@ -141,17 +150,8 @@ __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, l return true; } -__dynamic_map_fix_keys :: proc(h: Map_Header) { - e := (^Map_Entry_Header)(h.m.entries.data); - for _ in 0.. Map_Find_Resu 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.hash, hash) { + entry_hash := __get_map_hash_from_entry(h, entry); + if __dynamic_map_hash_equal(h, entry_hash, hash) { return fr; } fr.entry_prev = fr.entry_index; @@ -307,14 +307,10 @@ __dynamic_map_add_entry :: proc(using h: Map_Header, hash: Map_Hash, loc := #cal prev := m.entries.len; prev_data := m.entries.data; c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc); - if m.entries.data != prev_data { - __dynamic_map_fix_keys(h); - } if c != prev { end := __dynamic_map_get_entry(h, c-1); - 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.hash = hash.hash; + mem_copy(rawptr(uintptr(end) + key_offset), hash.key_ptr, key_size); end.next = -1; } return prev; @@ -334,7 +330,6 @@ __dynamic_map_get_entry :: proc(using h: Map_Header, index: int) -> ^Map_Entry_H __dynamic_map_copy_entry :: proc(h: Map_Header, new, old: ^Map_Entry_Header) { mem_copy(new, old, h.entry_size); - new.hash.key_ptr = rawptr(uintptr(new) + h.key_offset); } __dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds_check { @@ -352,7 +347,9 @@ __dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds end := __dynamic_map_get_entry(h, m.entries.len-1); __dynamic_map_copy_entry(h, old, end); - if last := __dynamic_map_find(h, old.hash); last.entry_prev >= 0 { + old_hash := __get_map_hash_from_entry(h, old); + + 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 bcc6b60db..2d2a5b3f0 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2799,9 +2799,9 @@ void init_map_entry_type(Type *type) { 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("hash")), t_map_hash, false, cast(i32)fields.count, EntityState_Resolved)); + array_add(&fields, alloc_entity_field(s, make_token_ident(str_lit("hash")), t_uintptr, 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("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)); -- 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/check_type.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/check_type.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 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/check_type.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 b922398a962734b97d65f93db2784939bce36288 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 29 Nov 2020 16:13:16 +0000 Subject: Sanity check for map key --- src/check_type.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 453348aa6..10ffe076c 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2854,7 +2854,9 @@ void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) { } else if (is_type_string(key)) { add_package_dependency(ctx, "runtime", "default_hasher_string"); } else if (!is_type_polymorphic(key)) { - GB_ASSERT_MSG(is_type_simple_compare(key), "%s", type_to_string(key)); + if (!is_type_simple_compare(key)) { + return; + } if (is_type_struct(key)) { add_package_dependency(ctx, "runtime", "default_hasher_n"); -- 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/check_type.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 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/check_type.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