From b2fdb69b4dd7f52f42414139a257b3800eb51a90 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Sun, 11 Jun 2017 12:01:40 +0100 Subject: [PATCH] Named procedure calls --- src/check_decl.cpp | 6 +- src/check_expr.cpp | 453 ++++++++++++++++++++++++++++++-------------- src/check_stmt.cpp | 2 +- src/checker.cpp | 6 +- src/common.cpp | 10 +- src/integer128.cpp | 59 +++++- src/ir.cpp | 41 +++- src/map.cpp | 7 +- src/murmurhash3.cpp | 39 ++-- src/parser.cpp | 5 + src/ssa.cpp | 2 +- src/timings.cpp | 2 +- 12 files changed, 448 insertions(+), 184 deletions(-) diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 28aa41b8e..57fb2c7f4 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -13,7 +13,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex // TODO(bill): is this a good enough error message? // TODO(bill): Actually allow built in procedures to be passed around and thus be created on use error_node(operand->expr, - "Cannot assign builtin procedure `%s` in %.*s", + "Cannot assign built-in procedure `%s` in %.*s", expr_str, LIT(context_name)); @@ -145,7 +145,7 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def) { // gb_printf_err("%.*s %p\n", LIT(e->token.string), e); - Type *bt = check_type_extra(c, type_expr, named); + Type *bt = check_type(c, type_expr, named); named->Named.base = base_type(bt); if (named->Named.base == t_invalid) { // gb_printf("check_type_decl: %s\n", type_to_string(named)); @@ -408,7 +408,7 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count e->flags |= EntityFlag_Visited; if (type_expr != NULL) { - e->type = check_type_extra(c, type_expr, NULL); + e->type = check_type(c, type_expr); } if (init_expr == NULL) { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5043f9b38..d967ff504 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2,8 +2,7 @@ void check_expr (Checker *c, Operand *operand, AstNode * void check_multi_expr (Checker *c, Operand *operand, AstNode *expression); void check_expr_or_type (Checker *c, Operand *operand, AstNode *expression); ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint); -Type * check_type_extra (Checker *c, AstNode *expression, Type *named_type); -Type * check_type (Checker *c, AstNode *expression); +Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL); void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def); Entity * check_selector (Checker *c, Operand *operand, AstNode *node, Type *type_hint); void check_not_tuple (Checker *c, Operand *operand); @@ -22,11 +21,6 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type * Type * check_call_arguments (Checker *c, Operand *operand, Type *proc_type, AstNode *call); -gb_inline Type *check_type(Checker *c, AstNode *expression) { - return check_type_extra(c, expression, NULL); -} - - void error_operand_not_expression(Operand *o) { if (o->mode == Addressing_Type) { gbString err = expr_to_string(o->expr); @@ -326,7 +320,7 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n // TODO(bill): is this a good enough error message? // TODO(bill): Actually allow built in procedures to be passed around and thus be created on use error_node(operand->expr, - "Cannot assign builtin procedure `%s` in %.*s", + "Cannot assign built-in procedure `%s` in %.*s", expr_str, LIT(context_name)); } else { @@ -1605,8 +1599,8 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { ast_node(mt, MapType, node); i64 count = check_array_or_map_count(c, mt->count, true); - Type *key = check_type_extra(c, mt->key, NULL); - Type *value = check_type_extra(c, mt->value, NULL); + Type *key = check_type(c, mt->key); + Type *value = check_type(c, mt->value); if (!is_type_valid_for_keys(key)) { if (is_type_boolean(key)) { @@ -1702,7 +1696,7 @@ void check_map_type(Checker *c, Type *type, AstNode *node) { // error_node(node, "`map` types are not yet implemented"); } -bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_type) { +bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) { GB_ASSERT_NOT_NULL(type); if (e == NULL) { *type = t_invalid; @@ -1759,7 +1753,7 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_ case_end; case_ast_node(pe, ParenExpr, e); - *type = check_type_extra(c, pe->expr, named_type); + *type = check_type(c, pe->expr, named_type); return true; case_end; @@ -1794,7 +1788,7 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_ case_ast_node(at, ArrayType, e); if (at->count != NULL) { - Type *elem = check_type_extra(c, at->elem, NULL); + Type *elem = check_type(c, at->elem, NULL); i64 count = check_array_or_map_count(c, at->count, false); if (count < 0) { error_node(at->count, ".. can only be used in conjuction with compound literals"); @@ -1825,7 +1819,7 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_ case_end; case_ast_node(dat, DynamicArrayType, e); - Type *elem = check_type_extra(c, dat->elem, NULL); + Type *elem = check_type(c, dat->elem); i64 esz = type_size_of(c->allocator, elem); #if 0 if (esz == 0) { @@ -1934,9 +1928,9 @@ bool check_type_extra_internal(Checker *c, AstNode *e, Type **type, Type *named_ -Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) { +Type *check_type(Checker *c, AstNode *e, Type *named_type) { Type *type = NULL; - bool ok = check_type_extra_internal(c, e, &type, named_type); + bool ok = check_type_internal(c, e, &type, named_type); if (!ok) { gbString err_str = expr_to_string(e); @@ -3533,6 +3527,14 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } } + if (ce->args.count > 0) { + if (ce->args[0]->kind == AstNode_FieldValue) { + error_node(call, "`field = value` calling is not allowed on built-in procedures"); + return false; + } + } + + bool vari_expand = (ce->ellipsis.pos.line != 0); if (vari_expand && id != BuiltinProc_append) { error(ce->ellipsis, "Invalid use of `..` with built-in procedure `append`"); @@ -3556,7 +3558,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id switch (id) { default: - GB_PANIC("Implement builtin procedure: %.*s", LIT(builtin_procs[id].name)); + GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_procs[id].name)); break; case BuiltinProc_len: @@ -4707,6 +4709,10 @@ enum CallArgumentError { CallArgumentError_ArgumentCount, CallArgumentError_TooFewArguments, CallArgumentError_TooManyArguments, + CallArgumentError_InvalidFieldValue, + CallArgumentError_ParameterNotFound, + CallArgumentError_ParameterMissing, + CallArgumentError_DuplicateParameter, }; enum CallArgumentErrorMode { @@ -4714,114 +4720,6 @@ enum CallArgumentErrorMode { CallArgumentMode_ShowErrors, }; -CallArgumentError check_call_arguments_internal(Checker *c, AstNode *call, Type *proc_type, Operand *operands, isize operand_count, - CallArgumentErrorMode show_error_mode, i64 *score_) { - ast_node(ce, CallExpr, call); - isize param_count = 0; - bool variadic = proc_type->Proc.variadic; - bool vari_expand = (ce->ellipsis.pos.line != 0); - i64 score = 0; - bool show_error = show_error_mode == CallArgumentMode_ShowErrors; - - if (proc_type->Proc.params != NULL) { - param_count = proc_type->Proc.params->Tuple.variable_count; - if (variadic) { - param_count--; - } - } - - if (vari_expand && !variadic) { - if (show_error) { - error(ce->ellipsis, - "Cannot use `..` in call to a non-variadic procedure: `%.*s`", - LIT(ce->proc->Ident.string)); - } - if (score_) *score_ = score; - return CallArgumentError_NonVariadicExpand; - } - - if (operand_count == 0 && param_count == 0) { - if (score_) *score_ = score; - return CallArgumentError_None; - } - - i32 error_code = 0; - if (operand_count < param_count) { - error_code = -1; - } else if (!variadic && operand_count > param_count) { - error_code = +1; - } - if (error_code != 0) { - CallArgumentError err = CallArgumentError_TooManyArguments; - char *err_fmt = "Too many arguments for `%s`, expected %td arguments"; - if (error_code < 0) { - err = CallArgumentError_TooFewArguments; - err_fmt = "Too few arguments for `%s`, expected %td arguments"; - } - - if (show_error) { - gbString proc_str = expr_to_string(ce->proc); - error_node(call, err_fmt, proc_str, param_count); - gb_string_free(proc_str); - } - if (score_) *score_ = score; - return err; - } - - CallArgumentError err = CallArgumentError_None; - - GB_ASSERT(proc_type->Proc.params != NULL); - Entity **sig_params = proc_type->Proc.params->Tuple.variables; - isize operand_index = 0; - for (; operand_index < param_count; operand_index++) { - Type *t = sig_params[operand_index]->type; - Operand o = operands[operand_index]; - if (variadic) { - o = operands[operand_index]; - } - i64 s = 0; - if (!check_is_assignable_to_with_score(c, &o, t, &s)) { - if (show_error) { - check_assignment(c, &o, t, str_lit("argument")); - } - err = CallArgumentError_WrongTypes; - } - score += s; - } - - if (variadic) { - bool variadic_expand = false; - Type *slice = sig_params[param_count]->type; - GB_ASSERT(is_type_slice(slice)); - Type *elem = base_type(slice)->Slice.elem; - Type *t = elem; - for (; operand_index < operand_count; operand_index++) { - Operand o = operands[operand_index]; - if (vari_expand) { - variadic_expand = true; - t = slice; - if (operand_index != param_count) { - if (show_error) { - error_node(o.expr, "`..` in a variadic procedure can only have one variadic argument at the end"); - } - if (score_) *score_ = score; - return CallArgumentError_MultipleVariadicExpand; - } - } - i64 s = 0; - if (!check_is_assignable_to_with_score(c, &o, t, &s)) { - if (show_error) { - check_assignment(c, &o, t, str_lit("argument")); - } - err = CallArgumentError_WrongTypes; - } - score += s; - } - } - - if (score_) *score_ = score; - return err; -} struct ValidProcAndScore { isize index; @@ -4870,14 +4768,248 @@ bool check_unpack_arguments(Checker *c, isize lhs_count, Array *operand return optional_ok; } -Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) { - GB_ASSERT(call->kind == AstNode_CallExpr); +#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(Checker *c, AstNode *call, Type *proc_type, Array operands, CallArgumentErrorMode show_error_mode, i64 *score_) +typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType); + +CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { + ast_node(ce, CallExpr, call); + isize param_count = 0; + bool variadic = proc_type->Proc.variadic; + bool vari_expand = (ce->ellipsis.pos.line != 0); + i64 score = 0; + bool show_error = show_error_mode == CallArgumentMode_ShowErrors; + + if (proc_type->Proc.params != NULL) { + param_count = proc_type->Proc.params->Tuple.variable_count; + if (variadic) { + param_count--; + } + } + + if (vari_expand && !variadic) { + if (show_error) { + error(ce->ellipsis, + "Cannot use `..` in call to a non-variadic procedure: `%.*s`", + LIT(ce->proc->Ident.string)); + } + if (score_) *score_ = score; + return CallArgumentError_NonVariadicExpand; + } + + if (operands.count == 0 && param_count == 0) { + if (score_) *score_ = score; + return CallArgumentError_None; + } + + i32 error_code = 0; + if (operands.count < param_count) { + error_code = -1; + } else if (!variadic && operands.count > param_count) { + error_code = +1; + } + if (error_code != 0) { + CallArgumentError err = CallArgumentError_TooManyArguments; + char *err_fmt = "Too many arguments for `%s`, expected %td arguments"; + if (error_code < 0) { + err = CallArgumentError_TooFewArguments; + err_fmt = "Too few arguments for `%s`, expected %td arguments"; + } + + if (show_error) { + gbString proc_str = expr_to_string(ce->proc); + error_node(call, err_fmt, proc_str, param_count); + gb_string_free(proc_str); + } + if (score_) *score_ = score; + return err; + } + + CallArgumentError err = CallArgumentError_None; + + GB_ASSERT(proc_type->Proc.params != NULL); + Entity **sig_params = proc_type->Proc.params->Tuple.variables; + isize operand_index = 0; + for (; operand_index < param_count; operand_index++) { + Type *t = sig_params[operand_index]->type; + Operand o = operands[operand_index]; + if (variadic) { + o = operands[operand_index]; + } + i64 s = 0; + if (!check_is_assignable_to_with_score(c, &o, t, &s)) { + if (show_error) { + check_assignment(c, &o, t, str_lit("argument")); + } + err = CallArgumentError_WrongTypes; + } + score += s; + } + + if (variadic) { + bool variadic_expand = false; + Type *slice = sig_params[param_count]->type; + GB_ASSERT(is_type_slice(slice)); + Type *elem = base_type(slice)->Slice.elem; + Type *t = elem; + for (; operand_index < operands.count; operand_index++) { + Operand o = operands[operand_index]; + if (vari_expand) { + variadic_expand = true; + t = slice; + if (operand_index != param_count) { + if (show_error) { + error_node(o.expr, "`..` in a variadic procedure can only have one variadic argument at the end"); + } + if (score_) *score_ = score; + return CallArgumentError_MultipleVariadicExpand; + } + } + i64 s = 0; + if (!check_is_assignable_to_with_score(c, &o, t, &s)) { + if (show_error) { + check_assignment(c, &o, t, str_lit("argument")); + } + err = CallArgumentError_WrongTypes; + } + score += s; + } + } + + if (score_) *score_ = score; + return err; +} + +bool is_call_expr_field_value(AstNodeCallExpr *ce) { + GB_ASSERT(ce != NULL); + + if (ce->args.count == 0) { + return false; + } + return ce->args[0]->kind == AstNode_FieldValue; +} + +isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) { + isize param_count = pt->param_count; + for (isize i = 0; i < param_count; i++) { + Entity *e = pt->params->Tuple.variables[i]; + String name = e->token.string; + if (name == "_") { + continue; + } + if (name == parameter_name) { + return i; + } + } + return -1; +} + +CALL_ARGUMENT_CHECKER(check_named_call_arguments) { + ast_node(ce, CallExpr, call); + GB_ASSERT(is_type_proc(proc_type)); + TypeProc *pt = &base_type(proc_type)->Proc; + + i64 score = 0; + bool show_error = show_error_mode == CallArgumentMode_ShowErrors; + CallArgumentError err = CallArgumentError_None; + + isize param_count = pt->param_count; + bool *params_visited = gb_alloc_array(c->allocator, bool, param_count); + + for_array(i, ce->args) { + AstNode *arg = ce->args[i]; + ast_node(fv, FieldValue, arg); + if (fv->field->kind != AstNode_Ident) { + if (show_error) { + gbString expr_str = expr_to_string(fv->field); + error_node(arg, "Invalid parameter name `%s` in procedure call", expr_str); + gb_string_free(expr_str); + } + err = CallArgumentError_InvalidFieldValue; + continue; + } + String name = fv->field->Ident.string; + isize index = lookup_procedure_parameter(pt, name); + if (index < 0) { + if (show_error) { + error_node(arg, "No parameter named `%.*s` for this procedure type", LIT(name)); + } + err = CallArgumentError_ParameterNotFound; + continue; + } + if (params_visited[index]) { + if (show_error) { + error_node(arg, "Duplicate parameter `%.*s` in procedure call", LIT(name)); + } + err = CallArgumentError_DuplicateParameter; + continue; + } + + params_visited[index] = true; + Operand *o = &operands[i]; + + Type *param_type = pt->params->Tuple.variables[index]->type; + + i64 s = 0; + if (!check_is_assignable_to_with_score(c, o, param_type, &s)) { + if (show_error) { + check_assignment(c, o, param_type, str_lit("procedure argument")); + } + err = CallArgumentError_WrongTypes; + } + score += s; + } + + +#if 1 + isize param_count_to_check = param_count; + if (pt->variadic) { + param_count_to_check--; + } + for (isize i = 0; i < param_count_to_check; i++) { + if (!params_visited[i]) { + if (show_error) { + Entity *e = pt->params->Tuple.variables[i]; + gbString str = type_to_string(e->type); + error_node(call, "Parameter `%.*s` of type `%s` is missing in procedure call", + LIT(e->token.string), str); + gb_string_free(str); + } + err = CallArgumentError_ParameterMissing; + } + } +#endif + + if (score_) *score_ = score; + + return err; +} + + +Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) { ast_node(ce, CallExpr, call); - Array operands; - array_init(&operands, heap_allocator(), 2*ce->args.count); - check_unpack_arguments(c, -1, &operands, ce->args, false); + CallArgumentCheckerType *call_checker = NULL; + Array operands = {}; + defer (array_free(&operands)); + + if (is_call_expr_field_value(ce)) { + call_checker = check_named_call_arguments; + + array_init_count(&operands, heap_allocator(), ce->args.count); + for_array(i, ce->args) { + AstNode *arg = ce->args[i]; + ast_node(fv, FieldValue, arg); + check_expr(c, &operands[i], fv->value); + } + } else { + call_checker = check_call_arguments_internal; + + array_init(&operands, heap_allocator(), 2*ce->args.count); + check_unpack_arguments(c, -1, &operands, ce->args, false); + } + + GB_ASSERT(call_checker != NULL); if (operand->mode == Addressing_Overload) { GB_ASSERT(operand->overload_entities != NULL && @@ -4888,6 +5020,9 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod ValidProcAndScore *valids = gb_alloc_array(heap_allocator(), ValidProcAndScore, overload_count); isize valid_count = 0; + defer (gb_free(heap_allocator(), procs)); + defer (gb_free(heap_allocator(), valids)); + String name = procs[0]->token.string; for (isize i = 0; i < overload_count; i++) { @@ -4903,7 +5038,7 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod Type *proc_type = base_type(p->type); if (proc_type != NULL && is_type_proc(proc_type)) { i64 score = 0; - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.data, operands.count, CallArgumentMode_NoErrors, &score); + CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_NoErrors, &score); if (err == CallArgumentError_None) { valids[valid_count].index = i; valids[valid_count].score = score; @@ -4948,16 +5083,14 @@ Type *check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNod add_entity_use(c, expr, e); proc_type = e->type; i64 score = 0; - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.data, operands.count, CallArgumentMode_ShowErrors, &score); + CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_ShowErrors, &score); } - - gb_free(heap_allocator(), valids); - gb_free(heap_allocator(), procs); } else { i64 score = 0; - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, operands.data, operands.count, CallArgumentMode_ShowErrors, &score); - array_free(&operands); + CallArgumentError err = call_checker(c, call, proc_type, operands, CallArgumentMode_ShowErrors, &score); } + + return proc_type; } @@ -4990,9 +5123,37 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { ast_node(ce, CallExpr, call); check_expr_or_type(c, operand, ce->proc); + if (ce->args.count > 0) { + bool fail = false; + bool first_is_field_value = (ce->args[0]->kind == AstNode_FieldValue); + for_array(i, ce->args) { + AstNode *arg = ce->args[i]; + bool mix = false; + if (first_is_field_value) { + mix = arg->kind != AstNode_FieldValue; + } else { + mix = arg->kind == AstNode_FieldValue; + } + if (mix) { + error_node(arg, "Mixture of `field = value` and value elements in a procedure all is not allowed"); + fail = true; + } + } + + if (fail) { + operand->mode = Addressing_Invalid; + operand->expr = call; + return Expr_Stmt; + } + } + if (operand->mode == Addressing_Invalid) { for_array(i, ce->args) { - check_expr_base(c, operand, ce->args[i], NULL); + AstNode *arg = ce->args[i]; + if (arg->kind == AstNode_FieldValue) { + arg = arg->FieldValue.value; + } + check_expr_base(c, operand, arg, NULL); } operand->mode = Addressing_Invalid; operand->expr = call; @@ -5005,14 +5166,20 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { operand->mode = Addressing_Invalid; isize arg_count = ce->args.count; switch (arg_count) { - case 0: error_node(call, "Missing argument in convertion to `%s`", str); break; - default: error_node(call, "Too many arguments in convertion to `%s`", str); break; - case 1: - check_expr(c, operand, ce->args[0]); + case 0: error_node(call, "Missing argument in conversion to `%s`", str); break; + default: error_node(call, "Too many arguments in conversion to `%s`", str); break; + case 1: { + AstNode *arg = ce->args[0]; + if (arg->kind == AstNode_FieldValue) { + error_node(call, "`field = value` cannot be used in a type conversion"); + arg = arg->FieldValue.value; + // NOTE(bill): Carry on the cast regardless + } + check_expr(c, operand, arg); if (operand->mode != Addressing_Invalid) { check_cast(c, operand, t); } - break; + } break; } gb_string_free(str); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index d35a49478..80233a38f 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1583,7 +1583,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { Type *init_type = NULL; if (vd->type) { - init_type = check_type_extra(c, vd->type, NULL); + init_type = check_type(c, vd->type, NULL); if (init_type == NULL) { init_type = t_invalid; } diff --git a/src/checker.cpp b/src/checker.cpp index dd0b60a9c..05503c608 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1631,7 +1631,7 @@ void check_all_global_entities(Checker *c) { for_array(i, c->info.entities.entries) { auto *entry = &c->info.entities.entries[i]; - Entity *e = cast(Entity *)cast(uintptr)entry->key.key; + Entity *e = cast(Entity *)entry->key.ptr; DeclInfo *d = entry->value; if (d->scope != e->scope) { @@ -1669,7 +1669,7 @@ void check_all_global_entities(Checker *c) { for_array(i, c->info.entities.entries) { auto *entry = &c->info.entities.entries[i]; - Entity *e = cast(Entity *)cast(uintptr)entry->key.key; + Entity *e = cast(Entity *)entry->key.ptr; if (e->kind != Entity_Procedure) { continue; } @@ -2063,7 +2063,7 @@ void check_parsed_files(Checker *c) { for_array(i, c->info.untyped.entries) { auto *entry = &c->info.untyped.entries[i]; HashKey key = entry->key; - AstNode *expr = cast(AstNode *)cast(uintptr)key.key; + AstNode *expr = cast(AstNode *)key.ptr; ExprInfo *info = &entry->value; if (info != NULL && expr != NULL) { if (is_type_typed(info->type)) { diff --git a/src/common.cpp b/src/common.cpp index a38af63f4..0c096a40d 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -3,7 +3,7 @@ #include #endif -#define GB_NO_DEFER +// #define GB_NO_DEFER #define GB_IMPLEMENTATION #include "gb/gb.h" @@ -18,18 +18,22 @@ gbAllocator heap_allocator(void) { #include "array.cpp" #include "integer128.cpp" #include "murmurhash3.cpp" -#include "map.cpp" u128 fnv128a(void const *data, isize len) { u128 o = u128_lo_hi(0x13bull, 0x1000000ull); u128 h = u128_lo_hi(0x62b821756295c58dull, 0x6c62272e07bb0142ull); u8 const *bytes = cast(u8 const *)data; for (isize i = 0; i < len; i++) { - h = u128_mul(u128_xor(h, u128_from_u64(bytes[i])), o); + h.lo ^= bytes[i]; + h = h * o; } return h; } +#include "map.cpp" + + + gb_global String global_module_path = {0}; gb_global bool global_module_path_set = false; diff --git a/src/integer128.cpp b/src/integer128.cpp index 73cd1c7a0..35023a220 100644 --- a/src/integer128.cpp +++ b/src/integer128.cpp @@ -1,3 +1,10 @@ + +#if defined(GB_COMPILER_MSVC) && defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86) + #define MSVC_AMD64_INTRINSICS + #include + #pragma intrinsic(_mul128) +#endif + #define BIT128_U64_HIGHBIT 0x8000000000000000ull #define BIT128_U64_BITS62 0x7fffffffffffffffull #define BIT128_U64_ALLBITS 0xffffffffffffffffull @@ -376,7 +383,11 @@ u128 u128_shl(u128 a, u32 n) { if (n >= 128) { return u128_lo_hi(0, 0); } - +#if 0 && defined(MSVC_AMD64_INTRINSICS) + a.hi = __shiftleft128(a.lo, a.hi, n); + a.lo = a.lo << n; + return a; +#else if (n >= 64) { n -= 64; a.hi = a.lo; @@ -391,13 +402,18 @@ u128 u128_shl(u128 a, u32 n) { a.lo <<= n; } return a; +#endif } u128 u128_shr(u128 a, u32 n) { if (n >= 128) { return u128_lo_hi(0, 0); } - +#if 0 && defined(MSVC_AMD64_INTRINSICS) + a.lo = __shiftright128(a.lo, a.hi, n); + a.hi = a.hi >> n; + return a; +#else if (n >= 64) { n -= 64; a.lo = a.hi; @@ -411,6 +427,7 @@ u128 u128_shr(u128 a, u32 n) { a.hi >>= n; } return a; +#endif } @@ -427,6 +444,14 @@ u128 u128_mul(u128 a, u128 b) { return a; } + +#if defined(MSVC_AMD64_INTRINSICS) + if (a.hi == 0 && b.hi == 0) { + a.lo = _umul128(a.lo, b.lo, &a.hi); + return a; + } +#endif + u128 res = {0}; u128 t = b; for (u32 i = 0; i < 128; i++) { @@ -440,6 +465,8 @@ u128 u128_mul(u128 a, u128 b) { return res; } +bool u128_hibit(u128 *d) { return (d->hi & BIT128_U64_HIGHBIT) != 0; } + void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) { if (u128_eq(den, U128_ZERO)) { if (quo) *quo = u128_from_u64(num.lo/den.lo); @@ -450,7 +477,7 @@ void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) { u128 x = U128_ONE; u128 r = U128_ZERO; - while (u128_ge(n, d) && ((u128_shr(d, 128-1).lo&1) == 0)) { + while (u128_ge(n, d) && !u128_hibit(&d)) { x = u128_shl(x, 1); d = u128_shl(d, 1); } @@ -471,11 +498,18 @@ void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) { } u128 u128_quo(u128 a, u128 b) { + if (a.hi == 0 && b.hi == 0) { + return u128_from_u64(a.lo/b.lo); + } + u128 res = {0}; u128_divide(a, b, &res, NULL); return res; } u128 u128_mod(u128 a, u128 b) { + if (a.hi == 0 && b.hi == 0) { + return u128_from_u64(a.lo%b.lo); + } u128 res = {0}; u128_divide(a, b, NULL, &res); return res; @@ -535,6 +569,11 @@ i128 i128_shl(i128 a, u32 n) { return i128_lo_hi(0, 0); } +#if 0 && defined(MSVC_AMD64_INTRINSICS) + a.hi = __shiftleft128(a.lo, a.hi, n); + a.lo = a.lo << n; + return a; +#else if (n >= 64) { n -= 64; a.hi = a.lo; @@ -549,6 +588,7 @@ i128 i128_shl(i128 a, u32 n) { a.lo <<= n; } return a; +#endif } i128 i128_shr(i128 a, u32 n) { @@ -556,6 +596,11 @@ i128 i128_shr(i128 a, u32 n) { return i128_lo_hi(0, 0); } +#if 0 && defined(MSVC_AMD64_INTRINSICS) + a.lo = __shiftright128(a.lo, a.hi, n); + a.hi = a.hi >> n; + return a; +#else if (n >= 64) { n -= 64; a.lo = a.hi; @@ -569,6 +614,7 @@ i128 i128_shr(i128 a, u32 n) { a.hi >>= n; } return a; +#endif } @@ -585,6 +631,13 @@ i128 i128_mul(i128 a, i128 b) { return a; } +#if defined(MSVC_AMD64_INTRINSICS) + if (a.hi == 0 && b.hi == 0) { + a.lo = _mul128(a.lo, b.lo, &a.hi); + return a; + } +#endif + i128 res = {0}; i128 t = b; for (u32 i = 0; i < 128; i++) { diff --git a/src/ir.cpp b/src/ir.cpp index bcea8a515..a8cfb0649 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4599,6 +4599,35 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { GB_ASSERT(proc_type_->kind == Type_Proc); TypeProc *type = &proc_type_->Proc; + if (is_call_expr_field_value(ce)) { + isize param_count = type->param_count; + irValue **args = gb_alloc_array(proc->module->allocator, irValue *, param_count); + + for_array(arg_index, ce->args) { + AstNode *arg = ce->args[arg_index]; + ast_node(fv, FieldValue, arg); + GB_ASSERT(fv->field->kind == AstNode_Ident); + String name = fv->field->Ident.string; + isize index = lookup_procedure_parameter(type, name); + GB_ASSERT(index >= 0); + irValue *expr = ir_build_expr(proc, fv->value); + args[index] = expr; + + } + TypeTuple *pt = &type->params->Tuple; + for (isize i = 0; i < param_count; i++) { + Type *param_type = pt->variables[i]->type; + if (args[i] == NULL) { + args[i] = ir_value_nil(proc->module->allocator, param_type); + } else { + args[i] = ir_emit_conv(proc, args[i], param_type); + } + } + + return ir_emit_call(proc, value, args, param_count); + // GB_PANIC("HERE!\n"); + } + isize arg_index = 0; isize arg_count = 0; @@ -4612,7 +4641,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { } } irValue **args = gb_alloc_array(proc->module->allocator, irValue *, arg_count); - bool variadic = proc_type_->Proc.variadic; + bool variadic = type->variadic; bool vari_expand = ce->ellipsis.pos.line != 0; for_array(i, ce->args) { @@ -6855,7 +6884,7 @@ void ir_init_module(irModule *m, Checker *c) { isize max_index = -1; for_array(type_info_map_index, m->info->type_info_map.entries) { auto *entry = &m->info->type_info_map.entries[type_info_map_index]; - Type *t = cast(Type *)cast(uintptr)entry->key.key; + Type *t = cast(Type *)entry->key.ptr; t = default_type(t); isize entry_index = ir_type_info_index(m->info, t); if (max_index < entry_index) { @@ -6880,7 +6909,7 @@ void ir_init_module(irModule *m, Checker *c) { for_array(entry_index, m->info->type_info_map.entries) { auto *entry = &m->info->type_info_map.entries[entry_index]; - Type *t = cast(Type *)cast(uintptr)entry->key.key; + Type *t = cast(Type *)entry->key.ptr; switch (t->kind) { case Type_Record: @@ -7083,7 +7112,7 @@ void ir_gen_tree(irGen *s) { for_array(i, info->entities.entries) { auto *entry = &info->entities.entries[i]; - Entity *e = cast(Entity *)cast(uintptr)entry->key.key; + Entity *e = cast(Entity *)entry->key.ptr; String name = e->token.string; if (e->kind == Entity_Variable) { global_variable_max_count++; @@ -7446,7 +7475,7 @@ void ir_gen_tree(irGen *s) { for_array(type_info_map_index, info->type_info_map.entries) { auto *entry = &info->type_info_map.entries[type_info_map_index]; - Type *t = cast(Type *)cast(uintptr)entry->key.key; + Type *t = cast(Type *)entry->key.ptr; t = default_type(t); isize entry_index = ir_type_info_index(info, t); @@ -7909,7 +7938,7 @@ void ir_gen_tree(irGen *s) { for_array(type_info_map_index, info->type_info_map.entries) { auto *entry = &info->type_info_map.entries[type_info_map_index]; - Type *t = cast(Type *)cast(uintptr)entry->key.key; + Type *t = cast(Type *)entry->key.ptr; t = default_type(t); isize entry_index = entry->value; diff --git a/src/map.cpp b/src/map.cpp index d45d2bccb..57942365a 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -19,6 +19,7 @@ enum HashKeyKind { struct HashKey { HashKeyKind kind; + // u128 key; u64 key; union { String string; // if String, s.len > 0 @@ -29,9 +30,8 @@ struct HashKey { gb_inline HashKey hashing_proc(void const *data, isize len) { HashKey h = {HashKey_Default}; h.kind = HashKey_Default; - // h.key = gb_murmur64(data, len); + // h.key = u128_from_u64(gb_fnv64a(data, len)); h.key = gb_fnv64a(data, len); - // h.key = MurmurHash3_128(data, len, 0x3803cb8e); return h; } @@ -136,7 +136,8 @@ template gb_internal MapFindResult map__find(Map *h, HashKey key) { MapFindResult fr = {-1, -1, -1}; if (h->hashes.count > 0) { - fr.hash_index = key.key % h->hashes.count; + // fr.hash_index = u128_to_i64(key.key % u128_from_i64(h->hashes.count)); + fr.hash_index = key.key % h->hashes.count; fr.entry_index = h->hashes[fr.hash_index]; while (fr.entry_index >= 0) { if (hash_key_equal(h->entries[fr.entry_index].key, key)) { diff --git a/src/murmurhash3.cpp b/src/murmurhash3.cpp index 23c9ac454..7eacdc060 100644 --- a/src/murmurhash3.cpp +++ b/src/murmurhash3.cpp @@ -41,15 +41,15 @@ gb_inline u64 fmix64(u64 k) { return k; } -gb_inline u32 mm3_getblock32(u32 *const p, isize i) { +gb_inline u32 mm3_getblock32(u32 const *p, isize i) { return p[i]; } -gb_inline u64 mm3_getblock64(u64 *const p, isize i) { +gb_inline u64 mm3_getblock64(u64 const *p, isize i) { return p[i]; } -u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) { - u8 *const data = cast(u8 *const)key; +void MurmurHash3_x64_128(void const *key, isize len, u32 seed, void *out) { + u8 const * data = cast(u8 const *)key; isize nblocks = len / 16; u64 h1 = seed; @@ -58,7 +58,7 @@ u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) { u64 const c1 = 0x87c37b91114253d5ULL; u64 const c2 = 0x4cf5ad432745937fULL; - u64 *const blocks = cast(u64 *const)data; + u64 const * blocks = cast(u64 const *)data; for (isize i = 0; i < nblocks; i++) { u64 k1 = mm3_getblock64(blocks, i*2 + 0); @@ -70,7 +70,7 @@ u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) { h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5; } - u8 *const tail = cast(u8 *const)(data + nblocks*16); + u8 const * tail = cast(u8 const *)(data + nblocks*16); u64 k1 = 0; u64 k2 = 0; @@ -108,11 +108,12 @@ u128 MurmurHash3_x64_128(void *const key, isize len, u32 seed) { h1 += h2; h2 += h1; - return u128_lo_hi(h1, h2); + ((u64 *)out)[0] = h1; + ((u64 *)out)[1] = h2; } -u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) { - u8 *const data = cast(u8 * const)key; +void MurmurHash3_x86_128(void const *key, isize len, u32 seed, void *out) { + u8 const * data = cast(u8 * const)key; isize nblocks = len / 16; u32 h1 = seed; @@ -128,7 +129,7 @@ u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) { //---------- // body - u32 *const blocks = cast(u32 *const)(data + nblocks*16); + u32 const * blocks = cast(u32 const *)(data + nblocks*16); for (isize i = -nblocks; i != 0; i++) { u32 k1 = mm3_getblock32(blocks, i*4 + 0); @@ -156,7 +157,7 @@ u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) { //---------- // tail - u8 *const tail = cast(u8 *const)(data + nblocks*16); + u8 const * tail = cast(u8 const *)(data + nblocks*16); u32 k1 = 0; u32 k2 = 0; @@ -204,17 +205,21 @@ u128 MurmurHash3_x86_128(void *const key, isize len, u32 seed) { h1 += h2; h1 += h3; h1 += h4; h2 += h1; h3 += h1; h4 += h1; - u64 lo = (u64)h1 | ((u64)h2 << 32); - u64 hi = (u64)h3 | ((u64)h4 << 32); - return u128_lo_hi(lo, hi); + + ((u32 *)out)[0] = h1; + ((u32 *)out)[1] = h2; + ((u32 *)out)[2] = h3; + ((u32 *)out)[3] = h4; } -gb_inline u128 MurmurHash3_128(void *const key, isize len, u32 seed) { +gb_inline u128 MurmurHash3_128(void const *key, isize len, u32 seed) { + u128 res; #if defined(GB_ARCH_64_BIT) - return MurmurHash3_x64_128(key, len, seed); + MurmurHash3_x64_128(key, len, seed, &res); #else - return MurmurHash3_x86_128(key, len, seed); + MurmurHash3_x86_128(key, len, seed, &res); #endif + return res; } diff --git a/src/parser.cpp b/src/parser.cpp index 120bb63cc..d741e569f 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2128,6 +2128,11 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) { } AstNode *arg = parse_expr(f, false); + if (f->curr_token.kind == Token_Eq) { + Token eq = expect_token(f, Token_Eq); + AstNode *value = parse_value(f); + arg = ast_field_value(f, arg, value, eq); + } array_add(&args, arg); if (!allow_token(f, Token_Comma)) { diff --git a/src/ssa.cpp b/src/ssa.cpp index b9ed4e75a..f3c187222 100644 --- a/src/ssa.cpp +++ b/src/ssa.cpp @@ -2493,7 +2493,7 @@ bool ssa_generate(Parser *parser, CheckerInfo *info) { for_array(i, info->entities.entries) { auto *entry = &info->entities.entries[i]; - Entity *e = cast(Entity *)cast(uintptr)entry->key.key; + Entity *e = cast(Entity *)entry->key.ptr; String name = e->token.string; if (e->kind == Entity_Variable) { global_variable_max_count++; diff --git a/src/timings.cpp b/src/timings.cpp index d00d5d0ba..27ee1f3a4 100644 --- a/src/timings.cpp +++ b/src/timings.cpp @@ -110,7 +110,7 @@ f64 time_stamp_as_ms(TimeStamp ts, u64 freq) { void timings_print_all(Timings *t) { char const SPACES[] = " "; - isize max_len, i; + isize max_len; timings__stop_current_section(t); t->total.finish = time_stamp_time_now();