From cfabc0e61f2c3dc00fd367e3f9bf1a89461971ef Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 28 Nov 2017 22:12:33 +0000 Subject: [PATCH] Remove `using` in arrays; Remove `_` non-exported struct fields Start determining slow parts of the compiler --- src/check_expr.cpp | 84 ---------- src/check_stmt.cpp | 400 +++++++++++++++++++++++---------------------- src/check_type.cpp | 62 +------ src/checker.cpp | 37 ++++- src/ir.cpp | 15 +- src/ir_print.cpp | 2 - src/main.cpp | 5 +- src/timings.cpp | 50 ++++-- src/types.cpp | 13 +- 9 files changed, 299 insertions(+), 369 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 359e1e069..b65f760a7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2541,27 +2541,6 @@ isize entity_overload_count(Scope *s, String name) { return 1; } -bool check_is_field_exported(Checker *c, Entity *field) { - if (field == nullptr) { - // NOTE(bill): Just incase - return true; - } - if (field->kind != Entity_Variable) { - return true; - } - Scope *file_scope = field->scope; - if (file_scope == nullptr) { - return true; - } - while (file_scope->file == nullptr) { - file_scope = file_scope->parent; - } - if (!is_entity_exported(field) && file_scope != c->context.file_scope) { - return false; - } - return true; -} - Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_hint) { ast_node(se, SelectorExpr, node); @@ -2730,13 +2709,6 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h if (entity == nullptr && selector->kind == AstNode_Ident) { String field_name = selector->Ident.token.string; sel = lookup_field(c->allocator, operand->type, field_name, operand->mode == Addressing_Type); - - if (operand->mode != Addressing_Type && !check_is_field_exported(c, sel.entity)) { - error(op_expr, "'%.*s' is an unexported field", LIT(field_name)); - operand->mode = Addressing_Invalid; - operand->expr = node; - return nullptr; - } entity = sel.entity; // NOTE(bill): Add type info needed for fields like 'names' @@ -4718,29 +4690,6 @@ CallArgumentData check_call_arguments(Checker *c, Operand *operand, Type *proc_t } -Entity *find_using_index_expr(Type *t) { - t = base_type(t); - if (t->kind != Type_Struct) { - return nullptr; - } - - for_array(i, t->Struct.fields) { - Entity *f = t->Struct.fields[i]; - if (f->kind == Entity_Variable && - (f->flags & EntityFlag_Field) != 0 && - (f->flags & EntityFlag_Using) != 0) { - if (is_type_indexable(f->type)) { - return f; - } - Entity *res = find_using_index_expr(f->type); - if (res != nullptr) { - return res; - } - } - } - return nullptr; -} - isize lookup_polymorphic_struct_parameter(TypeStruct *st, String parameter_name) { if (!st->is_polymorphic) return -1; @@ -5531,11 +5480,6 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t error(elem, "Unknown field '%.*s' in structure literal", LIT(name)); continue; } - if (!is_unknown && !check_is_field_exported(c, sel.entity)) { - error(elem, "Cannot assign to an unexported field '%.*s' in structure literal", LIT(name)); - continue; - } - if (sel.index.count > 1) { error(elem, "Cannot assign to an anonymous field '%.*s' in a structure literal (at the moment)", LIT(name)); @@ -5564,15 +5508,6 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t check_assignment(c, o, field->type, str_lit("structure literal")); } } else { - bool all_fields_are_blank = true; - for_array(i, t->Struct.fields_in_src_order) { - Entity *field = t->Struct.fields_in_src_order[i]; - if (!is_blank_ident(field->token)) { - all_fields_are_blank = false; - break; - } - } - bool seen_field_value = false; for_array(index, cl->elems) { @@ -5594,21 +5529,9 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t if (field == nullptr) { field = t->Struct.fields_in_src_order[index]; } - if (!all_fields_are_blank && is_blank_ident(field->token)) { - // NOTE(bill): Ignore blank identifiers - continue; - } check_expr_with_type_hint(c, o, elem, field->type); - if (!check_is_field_exported(c, field)) { - gbString t = type_to_string(type); - error(o->expr, "Implicit assignment to an unexported field '%.*s' in '%s' literal", - LIT(field->token.string), t); - gb_string_free(t); - continue; - } - if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type)) { is_constant = false; } @@ -6032,13 +5955,6 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t valid = false; } - if (!valid && t->kind == Type_Struct) { - Entity *found = find_using_index_expr(t); - if (found != nullptr) { - valid = check_set_index_data(o, found->type, is_type_pointer(found->type), &max_count); - } - } - if (!valid) { gbString str = expr_to_string(o->expr); gbString type_str = type_to_string(o->type); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index bbc1aaab3..24c82545e 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -41,7 +41,6 @@ void check_stmt_list(Checker *c, Array stmts, u32 flags) { check_stmt(c, n, new_flags); } - } bool check_is_terminating_list(Array stmts) { @@ -576,6 +575,207 @@ bool check_using_stmt_entity(Checker *c, AstNodeUsingStmt *us, AstNode *expr, bo return true; } +void check_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) { + ast_node(ss, SwitchStmt, node); + + Operand x = {}; + + mod_flags |= Stmt_BreakAllowed | Stmt_FallthroughAllowed; + check_open_scope(c, node); + defer (check_close_scope(c)); + + check_label(c, ss->label); // TODO(bill): What should the label's "scope" be? + + if (ss->init != nullptr) { + check_stmt(c, ss->init, 0); + } + if (ss->tag != nullptr) { + check_expr(c, &x, ss->tag); + check_assignment(c, &x, nullptr, str_lit("switch expression")); + } else { + x.mode = Addressing_Constant; + x.type = t_bool; + x.value = exact_value_bool(true); + + Token token = {}; + token.pos = ast_node_token(ss->body).pos; + token.string = str_lit("true"); + x.expr = ast_ident(c->curr_ast_file, token); + } + if (is_type_vector(x.type)) { + gbString str = type_to_string(x.type); + error(x.expr, "Invalid switch expression type: %s", str); + gb_string_free(str); + return; + } + + + // NOTE(bill): Check for multiple defaults + AstNode *first_default = nullptr; + ast_node(bs, BlockStmt, ss->body); + for_array(i, bs->stmts) { + AstNode *stmt = bs->stmts[i]; + AstNode *default_stmt = nullptr; + if (stmt->kind == AstNode_CaseClause) { + ast_node(cc, CaseClause, stmt); + if (cc->list.count == 0) { + default_stmt = stmt; + } + } else { + error(stmt, "Invalid AST - expected case clause"); + } + + if (default_stmt != nullptr) { + if (first_default != nullptr) { + TokenPos pos = ast_node_token(first_default).pos; + error(stmt, + "multiple default clauses\n" + "\tfirst at %.*s(%td:%td)", + LIT(pos.file), pos.line, pos.column); + } else { + first_default = default_stmt; + } + } + } + + Map seen = {}; // NOTE(bill): Multimap + map_init(&seen, heap_allocator()); + defer (map_destroy(&seen)); + + for_array(stmt_index, bs->stmts) { + AstNode *stmt = bs->stmts[stmt_index]; + if (stmt->kind != AstNode_CaseClause) { + // NOTE(bill): error handled by above multiple default checker + continue; + } + ast_node(cc, CaseClause, stmt); + + for_array(j, cc->list) { + AstNode *expr = unparen_expr(cc->list[j]); + + if (is_ast_node_a_range(expr)) { + ast_node(ie, BinaryExpr, expr); + Operand lhs = {}; + Operand rhs = {}; + check_expr(c, &lhs, ie->left); + if (x.mode == Addressing_Invalid) { + continue; + } + if (lhs.mode == Addressing_Invalid) { + continue; + } + check_expr(c, &rhs, ie->right); + if (rhs.mode == Addressing_Invalid) { + continue; + } + + if (!is_type_ordered(x.type)) { + gbString str = type_to_string(x.type); + error(expr, "Unordered type '%s', is invalid for an interval expression", str); + gb_string_free(str); + continue; + } + + + TokenKind op = Token_Invalid; + + Operand a = lhs; + Operand b = rhs; + check_comparison(c, &a, &x, Token_LtEq); + if (a.mode == Addressing_Invalid) { + continue; + } + switch (ie->op.kind) { + case Token_Ellipsis: op = Token_GtEq; break; + case Token_HalfClosed: op = Token_Gt; break; + default: error(ie->op, "Invalid interval operator"); continue; + } + + check_comparison(c, &b, &x, op); + if (b.mode == Addressing_Invalid) { + continue; + } + + switch (ie->op.kind) { + case Token_Ellipsis: op = Token_LtEq; break; + case Token_HalfClosed: op = Token_Lt; break; + default: error(ie->op, "Invalid interval operator"); continue; + } + + Operand a1 = lhs; + Operand b1 = rhs; + check_comparison(c, &a1, &b1, op); + } else { + Operand y = {}; + check_expr(c, &y, expr); + + if (x.mode == Addressing_Invalid || + y.mode == Addressing_Invalid) { + continue; + } + + convert_to_typed(c, &y, x.type); + if (y.mode == Addressing_Invalid) { + continue; + } + + // NOTE(bill): the ordering here matters + Operand z = y; + check_comparison(c, &z, &x, Token_CmpEq); + if (z.mode == Addressing_Invalid) { + continue; + } + if (y.mode != Addressing_Constant) { + continue; + } + + + if (y.value.kind != ExactValue_Invalid) { + HashKey key = hash_exact_value(y.value); + TypeAndToken *found = map_get(&seen, key); + if (found != nullptr) { + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); + defer (gb_temp_arena_memory_end(tmp)); + + isize count = multi_map_count(&seen, key); + TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count); + + multi_map_get_all(&seen, key, taps); + bool continue_outer = false; + + for (isize i = 0; i < count; i++) { + TypeAndToken tap = taps[i]; + if (are_types_identical(y.type, tap.type)) { + TokenPos pos = tap.token.pos; + gbString expr_str = expr_to_string(y.expr); + error(y.expr, + "Duplicate case '%s'\n" + "\tprevious case at %.*s(%td:%td)", + expr_str, + LIT(pos.file), pos.line, pos.column); + gb_string_free(expr_str); + continue_outer = true; + break; + } + } + + + if (continue_outer) { + continue; + } + } + TypeAndToken tap = {y.type, ast_node_token(y.expr)}; + multi_map_insert(&seen, key, tap); + } + } + } + + check_open_scope(c, stmt); + check_stmt_list(c, cc->stmts, mod_flags); + check_close_scope(c); + } +} + void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { u32 mod_flags = flags & (~Stmt_FallthroughAllowed); switch (node->kind) { @@ -940,7 +1140,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { check_assignment(c, &operands[i], e->type, str_lit("return statement")); } } - case_end; case_ast_node(fs, ForStmt, node); @@ -1193,202 +1392,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { case_end; case_ast_node(ss, SwitchStmt, node); - Operand x = {}; - - mod_flags |= Stmt_BreakAllowed | Stmt_FallthroughAllowed; - check_open_scope(c, node); - defer (check_close_scope(c)); - - check_label(c, ss->label); // TODO(bill): What should the label's "scope" be? - - if (ss->init != nullptr) { - check_stmt(c, ss->init, 0); - } - if (ss->tag != nullptr) { - check_expr(c, &x, ss->tag); - check_assignment(c, &x, nullptr, str_lit("switch expression")); - } else { - x.mode = Addressing_Constant; - x.type = t_bool; - x.value = exact_value_bool(true); - - Token token = {}; - token.pos = ast_node_token(ss->body).pos; - token.string = str_lit("true"); - x.expr = ast_ident(c->curr_ast_file, token); - } - if (is_type_vector(x.type)) { - gbString str = type_to_string(x.type); - error(x.expr, "Invalid switch expression type: %s", str); - gb_string_free(str); - break; - } - - - // NOTE(bill): Check for multiple defaults - AstNode *first_default = nullptr; - ast_node(bs, BlockStmt, ss->body); - for_array(i, bs->stmts) { - AstNode *stmt = bs->stmts[i]; - AstNode *default_stmt = nullptr; - if (stmt->kind == AstNode_CaseClause) { - ast_node(cc, CaseClause, stmt); - if (cc->list.count == 0) { - default_stmt = stmt; - } - } else { - error(stmt, "Invalid AST - expected case clause"); - } - - if (default_stmt != nullptr) { - if (first_default != nullptr) { - TokenPos pos = ast_node_token(first_default).pos; - error(stmt, - "multiple default clauses\n" - "\tfirst at %.*s(%td:%td)", - LIT(pos.file), pos.line, pos.column); - } else { - first_default = default_stmt; - } - } - } - - Map seen = {}; // NOTE(bill): Multimap - map_init(&seen, heap_allocator()); - defer (map_destroy(&seen)); - - for_array(stmt_index, bs->stmts) { - AstNode *stmt = bs->stmts[stmt_index]; - if (stmt->kind != AstNode_CaseClause) { - // NOTE(bill): error handled by above multiple default checker - continue; - } - ast_node(cc, CaseClause, stmt); - - for_array(j, cc->list) { - AstNode *expr = unparen_expr(cc->list[j]); - - if (is_ast_node_a_range(expr)) { - ast_node(ie, BinaryExpr, expr); - Operand lhs = {}; - Operand rhs = {}; - check_expr(c, &lhs, ie->left); - if (x.mode == Addressing_Invalid) { - continue; - } - if (lhs.mode == Addressing_Invalid) { - continue; - } - check_expr(c, &rhs, ie->right); - if (rhs.mode == Addressing_Invalid) { - continue; - } - - if (!is_type_ordered(x.type)) { - gbString str = type_to_string(x.type); - error(expr, "Unordered type '%s', is invalid for an interval expression", str); - gb_string_free(str); - continue; - } - - - TokenKind op = Token_Invalid; - - Operand a = lhs; - Operand b = rhs; - check_comparison(c, &a, &x, Token_LtEq); - if (a.mode == Addressing_Invalid) { - continue; - } - switch (ie->op.kind) { - case Token_Ellipsis: op = Token_GtEq; break; - case Token_HalfClosed: op = Token_Gt; break; - default: error(ie->op, "Invalid interval operator"); continue; - } - - check_comparison(c, &b, &x, op); - if (b.mode == Addressing_Invalid) { - continue; - } - - switch (ie->op.kind) { - case Token_Ellipsis: op = Token_LtEq; break; - case Token_HalfClosed: op = Token_Lt; break; - default: error(ie->op, "Invalid interval operator"); continue; - } - - Operand a1 = lhs; - Operand b1 = rhs; - check_comparison(c, &a1, &b1, op); - } else { - Operand y = {}; - check_expr(c, &y, expr); - - if (x.mode == Addressing_Invalid || - y.mode == Addressing_Invalid) { - continue; - } - - convert_to_typed(c, &y, x.type); - if (y.mode == Addressing_Invalid) { - continue; - } - - // NOTE(bill): the ordering here matters - Operand z = y; - check_comparison(c, &z, &x, Token_CmpEq); - if (z.mode == Addressing_Invalid) { - continue; - } - if (y.mode != Addressing_Constant) { - continue; - } - - - if (y.value.kind != ExactValue_Invalid) { - HashKey key = hash_exact_value(y.value); - TypeAndToken *found = map_get(&seen, key); - if (found != nullptr) { - gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); - defer (gb_temp_arena_memory_end(tmp)); - - isize count = multi_map_count(&seen, key); - TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count); - - multi_map_get_all(&seen, key, taps); - bool continue_outer = false; - - for (isize i = 0; i < count; i++) { - TypeAndToken tap = taps[i]; - if (are_types_identical(y.type, tap.type)) { - TokenPos pos = tap.token.pos; - gbString expr_str = expr_to_string(y.expr); - error(y.expr, - "Duplicate case '%s'\n" - "\tprevious case at %.*s(%td:%td)", - expr_str, - LIT(pos.file), pos.line, pos.column); - gb_string_free(expr_str); - continue_outer = true; - break; - } - } - - - if (continue_outer) { - continue; - } - } - TypeAndToken tap = {y.type, ast_node_token(y.expr)}; - multi_map_insert(&seen, key, tap); - } - } - } - - check_open_scope(c, stmt); - check_stmt_list(c, cc->stmts, mod_flags); - check_close_scope(c); - } + check_switch_stmt(c, node, mod_flags); case_end; case_ast_node(ss, TypeSwitchStmt, node); diff --git a/src/check_type.cpp b/src/check_type.cpp index 7d4f8ca6e..8842596b3 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -208,7 +208,6 @@ void check_struct_field_decl(Checker *c, AstNode *decl, Array *fields, } - Entity *using_index_expr = nullptr; if (is_using && fields->count > 0) { Type *first_type = (*fields)[fields->count-1]->type; @@ -217,32 +216,10 @@ void check_struct_field_decl(Checker *c, AstNode *decl, Array *fields, vd->names.count >= 1 && vd->names[0]->kind == AstNode_Ident) { Token name_token = vd->names[0]->Ident.token; - if (is_type_indexable(t)) { - bool ok = true; - for_array(emi, entity_map->entries) { - Entity *e = entity_map->entries[emi].value; - if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { - if (is_type_indexable(e->type)) { - if (e->identifier != vd->names[0]) { - ok = false; - using_index_expr = e; - break; - } - } - } - } - if (ok) { - using_index_expr = (*fields)[fields->count-1]; - } else { - (*fields)[fields->count-1]->flags &= ~EntityFlag_Using; - error(name_token, "Previous 'using' for an index expression '%.*s'", LIT(name_token.string)); - } - } else { - gbString type_str = type_to_string(first_type); - error(name_token, "'using' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str); - gb_string_free(type_str); - return; - } + gbString type_str = type_to_string(first_type); + error(name_token, "'using' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str); + gb_string_free(type_str); + return; } populate_using_entity_map(c, struct_node, type, entity_map); @@ -408,7 +385,6 @@ Array check_struct_fields(Checker *c, AstNode *node, Array field_src_index += 1; } - Entity *using_index_expr = nullptr; if (is_using && p->names.count > 0) { Type *first_type = fields[fields.count-1]->type; @@ -418,32 +394,10 @@ Array check_struct_fields(Checker *c, AstNode *node, Array p->names.count >= 1 && p->names[0]->kind == AstNode_Ident) { Token name_token = p->names[0]->Ident.token; - if (is_type_indexable(t)) { - bool ok = true; - for_array(emi, entity_map.entries) { - Entity *e = entity_map.entries[emi].value; - if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { - if (is_type_indexable(e->type)) { - if (e->identifier != p->names[0]) { - ok = false; - using_index_expr = e; - break; - } - } - } - } - if (ok) { - using_index_expr = fields[fields.count-1]; - } else { - fields[fields.count-1]->flags &= ~EntityFlag_Using; - error(name_token, "Previous 'using' for an index expression '%.*s'", LIT(name_token.string)); - } - } else { - gbString type_str = type_to_string(first_type); - error(name_token, "'using' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str); - gb_string_free(type_str); - continue; - } + gbString type_str = type_to_string(first_type); + error(name_token, "'using' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str); + gb_string_free(type_str); + continue; } populate_using_entity_map(c, node, type, &entity_map); diff --git a/src/checker.cpp b/src/checker.cpp index 88ad773c0..da8ed4e7d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1551,18 +1551,18 @@ Array generate_entity_dependency_graph(CheckerInfo *info) { } Array G = {}; - array_init(&G, a); + array_init(&G, a, 2*M.entries.count); for_array(i, M.entries) { auto *entry = &M.entries[i]; - Entity * e = cast(Entity *)entry->key.ptr; + auto *e = cast(Entity *)entry->key.ptr; EntityGraphNode *n = entry->value; if (e->kind == Entity_Procedure) { // Connect each pred 'p' of 'n' with each succ 's' and from // the procedure node for_array(j, n->pred.entries) { - EntityGraphNode *p = cast(EntityGraphNode *)n->pred.entries[j].ptr; + EntityGraphNode *p = n->pred.entries[j].ptr; // Ignore self-cycles if (p != n) { @@ -1594,6 +1594,7 @@ Array generate_entity_dependency_graph(CheckerInfo *info) { GB_ASSERT(n->dep_count >= 0); } + return G; } @@ -3335,6 +3336,20 @@ void calculate_global_init_order(Checker *c) { void check_parsed_files(Checker *c) { +#if 0 + Timings timings = {}; + timings_init(&timings, str_lit("check_parsed_files"), 16); + defer ({ + timings_print_all(&timings); + timings_destroy(&timings); + }); +#define TIME_SECTION(str) timings_start_section(&timings, str_lit(str)) +#else +#define TIME_SECTION(str) +#endif + + TIME_SECTION("map full filepaths to scope"); + add_type_info_type(c, t_invalid); // Map full filepaths to Scopes @@ -3351,6 +3366,7 @@ void check_parsed_files(Checker *c) { } } + TIME_SECTION("collect entities"); // Collect Entities for_array(i, c->parser->files) { AstFile *f = c->parser->files[i]; @@ -3360,10 +3376,16 @@ void check_parsed_files(Checker *c) { c->context = prev_context; } + TIME_SECTION("import entities"); check_import_entities(c); + + TIME_SECTION("check all global entities"); check_all_global_entities(c); + + TIME_SECTION("init preload"); init_preload(c); // NOTE(bill): This could be setup previously through the use of 'type_info_of' + TIME_SECTION("check procedure bodies"); // Check procedure bodies // NOTE(bill): Nested procedures bodies will be added to this "queue" for_array(i, c->procs.entries) { @@ -3397,12 +3419,16 @@ void check_parsed_files(Checker *c) { check_proc_body(c, pi->token, pi->decl, pi->type, pi->body); } + TIME_SECTION("generate minimum dependency set"); c->info.minimum_dependency_set = generate_minimum_dependency_set(&c->info, c->info.entry_point); + TIME_SECTION("calculate global init order"); // Calculate initialization order of global variables calculate_global_init_order(c); + + TIME_SECTION("add untyped expression values"); // Add untyped expression values for_array(i, c->info.untyped.entries) { auto *entry = &c->info.untyped.entries[i]; @@ -3420,6 +3446,8 @@ void check_parsed_files(Checker *c) { // TODO(bill): Check for unused imports (and remove) or even warn/err // TODO(bill): Any other checks? + + TIME_SECTION("add type information"); // Add "Basic" type information for (isize i = 0; i < gb_count_of(basic_types)-1; i++) { Type *t = &basic_types[i]; @@ -3440,6 +3468,7 @@ void check_parsed_files(Checker *c) { } } + TIME_SECTION("check entry poiny"); if (!build_context.is_dll) { Scope *s = c->info.init_scope; GB_ASSERT(s != nullptr); @@ -3458,4 +3487,6 @@ void check_parsed_files(Checker *c) { error(token, "Undefined entry point procedure 'main'"); } } + +#undef TIME_SECTION } diff --git a/src/ir.cpp b/src/ir.cpp index b8efb563e..3128bfd5d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5335,7 +5335,7 @@ bool ir_is_elem_const(irModule *m, AstNode *elem, Type *elem_type) { elem = elem->FieldValue.value; } TypeAndValue tav = type_and_value_of_expr(m->info, elem); - GB_ASSERT(tav.mode != Addressing_Invalid); + GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s", expr_to_string(elem), type_to_string(tav.type)); return tav.value.kind != ExactValue_Invalid; } @@ -5517,6 +5517,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { bool deref = is_type_pointer(t); t = base_type(type_deref(t)); + GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr)); if (is_type_map(t)) { irValue *map_val = ir_build_addr_ptr(proc, ie->expr); @@ -5532,18 +5533,6 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { } irValue *using_addr = nullptr; - if (!is_type_indexable(t)) { - // Using index expression - Entity *using_field = find_using_index_expr(t); - if (using_field != nullptr) { - Selection sel = lookup_field(a, t, using_field->token.string, false); - irValue *e = ir_build_addr_ptr(proc, ie->expr); - using_addr = ir_emit_deep_field_gep(proc, e, sel); - - t = using_field->type; - } - } - switch (t->kind) { case Type_Vector: { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 0b0e5d97b..40346075a 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -880,8 +880,6 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin ir_print_type(f, m, t_int); ir_write_string(f, " 0, i32 0), "); ir_print_type(f, m, t_int); - ir_fprintf(f, " %lld, ", cs->count); - ir_print_type(f, m, t_int); ir_fprintf(f, " %lld}", cs->count); } break; diff --git a/src/main.cpp b/src/main.cpp index eff12cc40..6dd5ad1f9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -558,7 +558,7 @@ void show_timings(Checker *c, Timings *t) { { TimeStamp ts = t->sections[0]; GB_ASSERT(ts.label == "parse files"); - f64 parse_time = time_stamp_as_second(ts, t->freq); + f64 parse_time = time_stamp_as_s(ts, t->freq); gb_printf("Parse pass\n"); gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time); gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines); @@ -610,6 +610,7 @@ int main(int arg_count, char **arg_ptr) { Timings timings = {0}; timings_init(&timings, str_lit("Total Time"), 128); defer (timings_destroy(&timings)); + init_string_buffer_memory(); init_scratch_memory(gb_megabytes(10)); init_global_error_collector(); @@ -853,7 +854,6 @@ int main(int arg_count, char **arg_ptr) { if (run_output) { system_exec_command_line_app("odin run", false, "%.*s.exe", LIT(output_base)); } - #else // NOTE(zangent): Linux / Unix is unfinished and not tested very well. @@ -993,7 +993,6 @@ int main(int arg_count, char **arg_ptr) { if (run_output) { system_exec_command_line_app("odin run", false, "%.*s", LIT(output_base)); } - #endif #endif #endif diff --git a/src/timings.cpp b/src/timings.cpp index 5422fd212..a5d6296a7 100644 --- a/src/timings.cpp +++ b/src/timings.cpp @@ -104,16 +104,40 @@ void timings_start_section(Timings *t, String label) { array_add(&t->sections, make_time_stamp(label)); } -f64 time_stamp_as_second(TimeStamp ts, u64 freq) { +f64 time_stamp_as_s(TimeStamp const &ts, u64 freq) { GB_ASSERT_MSG(ts.finish >= ts.start, "time_stamp_as_ms - %.*s", LIT(ts.label)); return cast(f64)(ts.finish - ts.start) / cast(f64)freq; } -f64 time_stamp_as_ms(TimeStamp ts, u64 freq) { - return 1000.0*time_stamp_as_second(ts, freq); +f64 time_stamp_as_ms(TimeStamp const &ts, u64 freq) { + return 1000.0*time_stamp_as_s(ts, freq); } -void timings_print_all(Timings *t) { +f64 time_stamp_as_us(TimeStamp const &ts, u64 freq) { + return 1000000.0*time_stamp_as_s(ts, freq); +} + +enum TimingUnit { + TimingUnit_Second, + TimingUnit_Millisecond, + TimingUnit_Microsecond, + + TimingUnit_COUNT, +}; + +char const *timing_unit_strings[TimingUnit_COUNT] = {"s", "ms", "us"}; + +f64 time_stamp(TimeStamp const &ts, u64 freq, TimingUnit unit) { + f64 total_time = 0; + switch (unit) { + case TimingUnit_Millisecond: return time_stamp_as_ms(ts, freq); + case TimingUnit_Microsecond: return time_stamp_as_us(ts, freq); + default: /*fallthrough*/ + case TimingUnit_Second: return time_stamp_as_s (ts, freq); + } +} + +void timings_print_all(Timings *t, TimingUnit unit = TimingUnit_Millisecond) { char const SPACES[] = " "; isize max_len; @@ -121,6 +145,7 @@ void timings_print_all(Timings *t) { t->total.finish = time_stamp_time_now(); max_len = t->total.label.len; + max_len = 36; for_array(i, t->sections) { TimeStamp ts = t->sections[i]; max_len = gb_max(max_len, ts.label.len); @@ -128,22 +153,25 @@ void timings_print_all(Timings *t) { GB_ASSERT(max_len <= gb_size_of(SPACES)-1); - t->total_time_seconds = time_stamp_as_second(t->total, t->freq); + t->total_time_seconds = time_stamp_as_s(t->total, t->freq); - f64 total_ms = time_stamp_as_ms(t->total, t->freq); + f64 total_time = time_stamp(t->total, t->freq, unit); - gb_printf("%.*s%.*s - % 9.3f ms - %6.2f%%\n", + gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n", LIT(t->total.label), cast(int)(max_len-t->total.label.len), SPACES, - total_ms, + total_time, + timing_unit_strings[unit], cast(f64)100.0); for_array(i, t->sections) { TimeStamp ts = t->sections[i]; - f64 section_ms = time_stamp_as_ms(ts, t->freq); - gb_printf("%.*s%.*s - % 9.3f ms - %6.2f%%\n", + f64 section_time = time_stamp(ts, t->freq, unit); + gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n", LIT(ts.label), cast(int)(max_len-ts.label.len), SPACES, - section_ms, 100*section_ms/total_ms); + section_time, + timing_unit_strings[unit], + 100.0*section_time/total_time); } } diff --git a/src/types.cpp b/src/types.cpp index 8dae03451..225f01bd8 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -950,7 +950,18 @@ bool is_type_valid_for_keys(Type *t) { bool is_type_indexable(Type *t) { - return is_type_array(t) || is_type_slice(t) || is_type_vector(t) || is_type_string(t); + Type *bt = base_type(t); + switch (bt->kind) { + case Type_Basic: + return is_type_string(bt); + case Type_Array: + case Type_Slice: + case Type_Vector: + case Type_DynamicArray: + case Type_Map: + return true; + } + return false; } bool is_type_polymorphic_struct(Type *t) {