diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 53ae0ae9f..35fb937fd 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -551,6 +551,8 @@ void destroy_checker_info(CheckerInfo *i) { void init_checker(Checker *c, Parser *parser, BaseTypeSizes sizes) { + PROF_PROC(); + gbAllocator a = gb_heap_allocator(); c->parser = parser; @@ -890,6 +892,8 @@ Map generate_minimum_dependency_map(CheckerInfo *info, Entity *start) #include "stmt.cpp" void init_preload_types(Checker *c) { + PROF_PROC(); + if (t_type_info == NULL) { Entity *e = current_scope_lookup_entity(c->global_scope, make_string("Type_Info")); if (e == NULL) { @@ -947,7 +951,6 @@ void init_preload_types(Checker *c) { } void check_parsed_files(Checker *c) { - Array import_decls; array_init(&import_decls, gb_heap_allocator()); defer (array_free(&import_decls)); @@ -983,6 +986,8 @@ void check_parsed_files(Checker *c) { // Collect Entities for_array(i, c->parser->files) { + PROF_SCOPED("Collect Entities"); + AstFile *f = &c->parser->files[i]; add_curr_ast_file(c, f); @@ -1090,6 +1095,8 @@ void check_parsed_files(Checker *c) { } for_array(i, c->parser->files) { + PROF_SCOPED("Import Entities"); + AstFile *f = &c->parser->files[i]; add_curr_ast_file(c, f); @@ -1186,6 +1193,7 @@ void check_parsed_files(Checker *c) { } auto check_global_entity = [](Checker *c, EntityKind kind) { + PROF_SCOPED("check_global_entity"); for_array(i, c->info.entities.entries) { auto *entry = &c->info.entities.entries[i]; Entity *e = cast(Entity *)cast(uintptr)entry->key.key; @@ -1242,24 +1250,10 @@ void check_parsed_files(Checker *c) { check_proc_body(c, pi->token, pi->decl, pi->type, pi->body); } - if (false) { - gb_printf("Dependency graph:\n"); - for_array(i, c->info.entities.entries) { - auto *entry = &c->info.entities.entries[i]; - Entity *e = cast(Entity *)cast(uintptr)entry->key.key; - DeclInfo *d = entry->value; - if (d->deps.entries.count > 0) { - gb_printf("\t%.*s depends on\n", LIT(e->token.string)); - for_array(j, d->deps.entries) { - Entity *e = cast(Entity *)cast(uintptr)d->deps.entries[j].key.key; - gb_printf("\t\t%.*s\n", LIT(e->token.string)); - } - } - } - } - // Add untyped expression values for_array(i, c->info.untyped.entries) { + PROF_SCOPED("Untyped expr values"); + auto *entry = &c->info.untyped.entries[i]; HashKey key = entry->key; AstNode *expr = cast(AstNode *)cast(uintptr)key.key; diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 48359b434..9c605761b 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -47,6 +47,8 @@ b32 check_is_assignable_to_using_subtype(Type *dst, Type *src) { b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argument = false) { + PROF_PROC(); + if (operand->mode == Addressing_Invalid || type == t_invalid) { return true; @@ -151,6 +153,8 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu // NOTE(bill): `content_name` is for debugging and error messages void check_assignment(Checker *c, Operand *operand, Type *type, String context_name, b32 is_argument = false) { + PROF_PROC(); + check_not_tuple(c, operand); if (operand->mode == Addressing_Invalid) return; @@ -206,6 +210,8 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map *entity_map) { + PROF_PROC(); + t = base_type(type_deref(t)); gbString str = expr_to_string(node); defer (gb_string_free(str)); @@ -239,6 +245,7 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls, Entity **fields, isize field_count, Entity **other_fields, isize other_field_count, CycleChecker *cycle_checker, String context) { + PROF_PROC(); Map entity_map = {}; map_init(&entity_map, gb_heap_allocator()); @@ -487,6 +494,8 @@ GB_COMPARE_PROC(cmp_struct_entity_size) { } void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecker *cycle_checker) { + PROF_PROC(); + GB_ASSERT(is_type_struct(struct_type)); ast_node(st, StructType, node); @@ -549,6 +558,8 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecke } void check_union_type(Checker *c, Type *union_type, AstNode *node, CycleChecker *cycle_checker) { + PROF_PROC(); + GB_ASSERT(is_type_union(union_type)); ast_node(ut, UnionType, node); @@ -583,6 +594,8 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node, CycleChecker } void check_raw_union_type(Checker *c, Type *union_type, AstNode *node, CycleChecker *cycle_checker) { + PROF_PROC(); + GB_ASSERT(node->kind == AstNode_RawUnionType); GB_ASSERT(is_type_raw_union(union_type)); ast_node(ut, RawUnionType, node); @@ -639,6 +652,8 @@ GB_COMPARE_PROC(cmp_enum_order) { void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *node) { + PROF_PROC(); + GB_ASSERT(node->kind == AstNode_EnumType); GB_ASSERT(is_type_enum(enum_type)); ast_node(et, EnumType, node); @@ -749,6 +764,8 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod } Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, b32 *is_variadic_) { + PROF_PROC(); + if (params.count == 0) { return NULL; } @@ -809,6 +826,8 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, b32 *is_va } Type *check_get_results(Checker *c, Scope *scope, AstNodeArray results) { + PROF_PROC(); + if (results.count == 0) { return NULL; } @@ -834,6 +853,8 @@ Type *check_get_results(Checker *c, Scope *scope, AstNodeArray results) { void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { + PROF_PROC(); + ast_node(pt, ProcType, proc_type_node); b32 variadic = false; @@ -857,6 +878,8 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, CycleChecker *cycle_checker) { + PROF_PROC(); + GB_ASSERT(n->kind == AstNode_Ident); o->mode = Addressing_Invalid; o->expr = n; @@ -959,6 +982,8 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl } i64 check_array_count(Checker *c, AstNode *e) { + PROF_PROC(); + if (e == NULL) { return 0; } @@ -986,6 +1011,8 @@ i64 check_array_count(Checker *c, AstNode *e) { } Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_checker) { + PROF_PROC(); + ExactValue null_value = {ExactValue_Invalid}; Type *type = NULL; gbString err_str = NULL; @@ -1258,6 +1285,8 @@ b32 check_binary_op(Checker *c, Operand *o, Token op) { } b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value) { + PROF_PROC(); + if (in_value.kind == ExactValue_Invalid) { // NOTE(bill): There's already been an error return true; @@ -1334,6 +1363,8 @@ b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exac } void check_is_expressible(Checker *c, Operand *o, Type *type) { + PROF_PROC(); + GB_ASSERT(type->kind == Type_Basic); GB_ASSERT(o->mode == Addressing_Constant); if (!check_value_is_expressible(c, o->value, type, &o->value)) { @@ -1369,6 +1400,8 @@ b32 check_is_expr_vector_index(Checker *c, AstNode *expr) { } void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) { + PROF_PROC(); + switch (op.kind) { case Token_Pointer: { // Pointer address if (o->mode != Addressing_Variable || @@ -1442,6 +1475,8 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) { } void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { + PROF_PROC(); + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); defer (gb_temp_arena_memory_end(tmp)); @@ -1506,10 +1541,11 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { } void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { + PROF_PROC(); + GB_ASSERT(node->kind == AstNode_BinaryExpr); ast_node(be, BinaryExpr, node); - ExactValue x_val = {}; if (x->mode == Addressing_Constant) { x_val = exact_value_to_integer(x->value); @@ -1600,8 +1636,11 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { } b32 check_is_castable_to(Checker *c, Operand *operand, Type *y) { - if (check_is_assignable_to(c, operand, y)) + PROF_PROC(); + + if (check_is_assignable_to(c, operand, y)) { return true; + } Type *x = operand->type; Type *xb = base_type(x); @@ -1690,6 +1729,8 @@ String check_down_cast_name(Type *dst_, Type *src_) { } void check_binary_expr(Checker *c, Operand *x, AstNode *node) { + PROF_PROC(); + GB_ASSERT(node->kind == AstNode_BinaryExpr); Operand y_ = {}, *y = &y_; gbString err_str = NULL; @@ -1956,6 +1997,8 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { void update_expr_type(Checker *c, AstNode *e, Type *type, b32 final) { + PROF_PROC(); + HashKey key = hash_pointer(e); ExpressionInfo *found = map_get(&c->info.untyped, key); if (found == NULL) @@ -2029,6 +2072,8 @@ void convert_untyped_error(Checker *c, Operand *operand, Type *target_type) { } void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level) { + PROF_PROC(); + GB_ASSERT_NOT_NULL(target_type); if (operand->mode == Addressing_Invalid || is_type_typed(operand->type) || @@ -2109,6 +2154,8 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level } b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *value) { + PROF_PROC(); + Operand operand = {Addressing_Invalid}; check_expr(c, &operand, index_value); if (operand.mode == Addressing_Invalid) { @@ -2163,6 +2210,8 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu } Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { + PROF_PROC(); + ast_node(se, SelectorExpr, node); b32 check_op_expr = true; @@ -2266,6 +2315,8 @@ error: } b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) { + PROF_PROC(); + GB_ASSERT(call->kind == AstNode_CallExpr); ast_node(ce, CallExpr, call); BuiltinProc *bp = &builtin_procs[id]; @@ -3064,6 +3115,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) { + PROF_PROC(); + GB_ASSERT(call->kind == AstNode_CallExpr); GB_ASSERT(proc_type->kind == Type_Proc); ast_node(ce, CallExpr, call); @@ -3188,6 +3241,8 @@ Entity *find_using_index_expr(Type *t) { } ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { + PROF_PROC(); + GB_ASSERT(call->kind == AstNode_CallExpr); ast_node(ce, CallExpr, call); check_expr_or_type(c, operand, ce->proc); @@ -3318,6 +3373,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case_end; case_ast_node(cl, CompoundLit, node); + PROF_SCOPED("check__expr_base - CompoundLit"); + Type *type = type_hint; b32 ellipsis_array = false; b32 is_constant = true; @@ -3557,6 +3614,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case_ast_node(ie, IndexExpr, node); + PROF_SCOPED("check__expr_base - IndexExpr"); + check_expr(c, o, ie->expr); if (o->mode == Addressing_Invalid) { goto error; @@ -3638,6 +3697,8 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case_ast_node(se, SliceExpr, node); + PROF_SCOPED("check__expr_base - SliceExpr"); + check_expr(c, o, se->expr); if (o->mode == Addressing_Invalid) goto error; diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index ca397503a..495e3a6e4 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -123,6 +123,8 @@ b32 check_has_break_list(AstNodeArray stmts, b32 implicit) { b32 check_has_break(AstNode *stmt, b32 implicit) { + PROF_PROC(); + switch (stmt->kind) { case AstNode_BranchStmt: if (stmt->BranchStmt.token.kind == Token_break) { @@ -152,6 +154,8 @@ b32 check_has_break(AstNode *stmt, b32 implicit) { // TODO(bill): This is a mild hack and should be probably handled properly // TODO(bill): Warn/err against code after `return` that it won't be executed b32 check_is_terminating(AstNode *node) { + PROF_PROC(); + switch (node->kind) { case_ast_node(rs, ReturnStmt, node); return true; @@ -224,6 +228,8 @@ b32 check_is_terminating(AstNode *node) { } Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { + PROF_PROC(); + if (op_a->mode == Addressing_Invalid || op_a->type == t_invalid) { return NULL; @@ -289,6 +295,8 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) { // NOTE(bill): `content_name` is for debugging Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) { + PROF_PROC(); + if (operand->mode == Addressing_Invalid || operand->type == t_invalid || e->type == t_invalid) { @@ -336,6 +344,8 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex } void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArray inits, String context_name) { + PROF_PROC(); + if ((lhs == NULL || lhs_count == 0) && inits.count == 0) { return; } @@ -382,6 +392,8 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra } void check_init_constant(Checker *c, Entity *e, Operand *operand) { + PROF_PROC(); + if (operand->mode == Addressing_Invalid || operand->type == t_invalid || e->type == t_invalid) { @@ -425,6 +437,8 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) { void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr) { + PROF_PROC(); + GB_ASSERT(e->type == NULL); if (e->Variable.visited) { @@ -454,6 +468,8 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e } void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker) { + PROF_PROC(); + GB_ASSERT(e->type == NULL); Type *named = make_type_named(c->allocator, e->token.string, NULL, e); named->Named.type_name = e; @@ -517,12 +533,14 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod } push_procedure(c, type); - ast_node(bs, BlockStmt, body); - // TODO(bill): Check declarations first (except mutable variable declarations) - check_stmt_list(c, bs->stmts, 0); - if (type->Proc.result_count > 0) { - if (!check_is_terminating(body)) { - error(bs->close, "Missing return statement at the end of the procedure"); + { + ast_node(bs, BlockStmt, body); + // TODO(bill): Check declarations first (except mutable variable declarations) + check_stmt_list(c, bs->stmts, 0); + if (type->Proc.result_count > 0) { + if (!check_is_terminating(body)) { + error(bs->close, "Missing return statement at the end of the procedure"); + } } } pop_procedure(c); @@ -570,6 +588,8 @@ b32 are_signatures_similar_enough(Type *a_, Type *b_) { } void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { + PROF_PROC(); + GB_ASSERT(e->type == NULL); Type *proc_type = make_type_proc(c->allocator, e->scope, NULL, 0, NULL, 0, false); @@ -665,6 +685,8 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) { } void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr) { + PROF_PROC(); + GB_ASSERT(e->type == NULL); GB_ASSERT(e->kind == Entity_Variable); @@ -704,6 +726,8 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, CycleChecker *cycle_checker) { + PROF_PROC(); + if (e->type != NULL) { return; } @@ -745,6 +769,8 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc void check_var_decl_node(Checker *c, AstNode *node) { + PROF_PROC(); + ast_node(vd, VarDecl, node); isize entity_count = vd->names.count; isize entity_index = 0; @@ -839,6 +865,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_ast_node(_, BadDecl, node); case_end; case_ast_node(es, ExprStmt, node) + PROF_SCOPED("check_stmt - ExprStmt"); + Operand operand = {Addressing_Invalid}; ExprKind kind = check_expr_base(c, &operand, es->expr); switch (operand.mode) { @@ -869,6 +897,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_end; case_ast_node(ids, IncDecStmt, node); + PROF_SCOPED("check_stmt - IncDecStmt"); + Token op = ids->op; switch (ids->op.kind) { case Token_Increment: @@ -908,6 +938,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_end; case_ast_node(as, AssignStmt, node); + PROF_SCOPED("check_stmt - AssignStmt"); + switch (as->op.kind) { case Token_Eq: { // a, b, c = 1, 2, 3; // Multisided @@ -988,6 +1020,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_end; case_ast_node(is, IfStmt, node); + PROF_SCOPED("check_stmt - IfStmt"); + check_open_scope(c, node); defer (check_close_scope(c)); @@ -1019,6 +1053,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_end; case_ast_node(rs, ReturnStmt, node); + PROF_SCOPED("check_stmt - ReturnStmt"); + GB_ASSERT(c->proc_stack.count > 0); if (c->in_defer) { @@ -1052,6 +1088,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_end; case_ast_node(fs, ForStmt, node); + PROF_SCOPED("check_stmt - ForStmt"); + u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed; check_open_scope(c, node); defer (check_close_scope(c)); @@ -1073,6 +1111,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_end; case_ast_node(ms, MatchStmt, node); + PROF_SCOPED("check_stmt - MatchStmt"); + Operand x = {}; mod_flags |= Stmt_BreakAllowed; @@ -1215,6 +1255,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_end; case_ast_node(ms, TypeMatchStmt, node); + PROF_SCOPED("check_stmt - TypeMatchStmt"); + Operand x = {}; mod_flags |= Stmt_BreakAllowed; @@ -1366,6 +1408,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_end; case_ast_node(us, UsingStmt, node); + PROF_SCOPED("check_stmt - UsingStmt"); + switch (us->node->kind) { case_ast_node(es, ExprStmt, us->node); // TODO(bill): Allow for just a LHS expression list rather than this silly code @@ -1485,6 +1529,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_end; case_ast_node(vd, VarDecl, us->node); + PROF_SCOPED("check_stmt - VarDecl"); + if (vd->names.count > 1 && vd->type != NULL) { error(us->token, "`using` can only be applied to one variable of the same type"); } @@ -1559,6 +1605,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_end; case_ast_node(pd, ProcDecl, node); + PROF_SCOPED("check_stmt - ProcDecl"); + // NOTE(bill): This must be handled here so it has access to the parent scope stuff // e.g. using Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL); diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 8e1367f95..c077ed94d 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -918,7 +918,9 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ String str = f->token.string; if (field_name == str) { - Selection sel = {f, {}, i}; + Selection sel = {}; + sel.entity = f; + selection_add_index(&sel, i); return sel; } } @@ -930,7 +932,9 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ String str = f->token.string; if (field_name == str) { - Selection sel = {f, {}, i}; + Selection sel = {}; + sel.entity = f; + selection_add_index(&sel, i); return sel; } } diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index 7a182c9e8..366343318 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -1421,6 +1421,7 @@ void ssa_end_procedure_body(ssaProcedure *proc) { ssa_emit_jump(proc, proc->entry_block); ssa_optimize_blocks(proc); +#if 0 ssa_build_referrers(proc); ssa_build_dom_tree(proc); @@ -1430,7 +1431,7 @@ void ssa_end_procedure_body(ssaProcedure *proc) { // [ ] Local stored once? Replace loads with dominating store // [ ] Convert to phi nodes ssa_opt_mem2reg(proc); - +#endif // Number registers i32 reg_index = 0; diff --git a/src/main.cpp b/src/main.cpp index 76b0d9346..3460ee221 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,5 @@ -// #define DISPLAY_TIMING - #include "common.cpp" +#include "profiler.cpp" #include "unicode.cpp" #include "tokenizer.cpp" #include "parser.cpp" @@ -8,7 +7,9 @@ #include "checker/checker.cpp" #include "codegen/codegen.cpp" -i32 win32_exec_command_line_app(char *fmt, ...) { +i32 win32_exec_command_line_app(char *name, char *fmt, ...) { + // PROF_SCOPED_STR(name); + STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)}; PROCESS_INFORMATION pi = {}; char cmd_line[2048] = {}; @@ -51,25 +52,6 @@ i32 win32_exec_command_line_app(char *fmt, ...) { } } -#if defined(DISPLAY_TIMING) -#define INIT_TIMER() f64 start_time = gb_time_now(), end_time = 0, total_time = 0 -#define PRINT_TIMER(section) do { \ - f64 diff; \ - end_time = gb_time_now(); \ - diff = end_time - start_time; \ - total_time += diff; \ - gb_printf_err("%s: %.1f ms\n", section, diff*1000.0); \ - start_time = gb_time_now(); \ -} while (0) - -#define PRINT_ACCUMULATION() do { \ - gb_printf_err("Total compilation time: %.1f ms\n", total_time*1000.0); \ -} while (0) -#else -#define INIT_TIMER() -#define PRINT_TIMER(section) -#define PRINT_ACCUMULATION() -#endif enum ArchKind { @@ -113,14 +95,14 @@ int main(int argc, char **argv) { gb_printf_err("using: %s [run] \n", argv[0]); return 1; } + prof_init(); #if 1 init_string_buffer_memory(); init_global_error_collector(); - String module_dir = get_module_dir(); - INIT_TIMER(); + String module_dir = get_module_dir(); init_universal_scope(); @@ -142,7 +124,6 @@ int main(int argc, char **argv) { return 1; } - PRINT_TIMER("Syntax Parser"); #if 1 Checker checker = {}; @@ -154,7 +135,6 @@ int main(int argc, char **argv) { check_parsed_files(&checker); - PRINT_TIMER("Semantic Checker"); #endif #if 1 ssaGen ssa = {}; @@ -165,11 +145,11 @@ int main(int argc, char **argv) { ssa_gen_tree(&ssa); - PRINT_TIMER("SSA Tree"); // TODO(bill): Speedup writing to file for IR code ssa_gen_ir(&ssa); - PRINT_TIMER("SSA IR"); + prof_print_all(); + #if 1 char const *output_name = ssa.output_file.filename; @@ -181,7 +161,7 @@ int main(int argc, char **argv) { i32 exit_code = 0; // For more passes arguments: http://llvm.org/docs/Passes.html - exit_code = win32_exec_command_line_app( + exit_code = win32_exec_command_line_app("llvm-opt", "%.*sbin/opt %s -o %.*s.bc " "-mem2reg " "-memcpyopt " @@ -196,10 +176,9 @@ int main(int argc, char **argv) { return exit_code; } - PRINT_TIMER("llvm-opt"); // For more arguments: http://llvm.org/docs/CommandGuide/llc.html - exit_code = win32_exec_command_line_app( + exit_code = win32_exec_command_line_app("llvm-llc", "%.*sbin/llc %.*s.bc -filetype=obj -O%d " "%.*s " // "-debug-pass=Arguments " @@ -212,7 +191,6 @@ int main(int argc, char **argv) { return exit_code; } - PRINT_TIMER("llvm-llc"); gbString lib_str = gb_string_make(gb_heap_allocator(), "Kernel32.lib"); // defer (gb_string_free(lib_str)); @@ -223,7 +201,7 @@ int main(int argc, char **argv) { " %.*s.lib", LIT(lib)); lib_str = gb_string_appendc(lib_str, lib_str_buf); } - exit_code = win32_exec_command_line_app( + exit_code = win32_exec_command_line_app("msvc-link", "link %.*s.obj -OUT:%.*s.exe %s " "/defaultlib:libcmt " "/nologo /incremental:no /opt:ref /subsystem:console " @@ -234,15 +212,15 @@ int main(int argc, char **argv) { if (exit_code != 0) { return exit_code; } - - PRINT_TIMER("msvc-link"); - PRINT_ACCUMULATION(); + // prof_print_all(); if (run_output) { - win32_exec_command_line_app("%.*s.exe", cast(int)base_name_len, output_name); + win32_exec_command_line_app("odin run", "%.*s.exe", cast(int)base_name_len, output_name); } #endif #endif #endif + + return 0; } diff --git a/src/parser.cpp b/src/parser.cpp index fb93c4609..32287af03 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2848,15 +2848,18 @@ ParseFileError init_ast_file(AstFile *f, String fullpath) { TokenizerInitError err = init_tokenizer(&f->tokenizer, fullpath); if (err == TokenizerInit_None) { array_init(&f->tokens, gb_heap_allocator()); - for (;;) { - Token token = tokenizer_get_token(&f->tokenizer); - if (token.kind == Token_Invalid) { - return ParseFile_InvalidToken; - } - array_add(&f->tokens, token); + { + PROF_SCOPED("Tokenize file"); + for (;;) { + Token token = tokenizer_get_token(&f->tokenizer); + if (token.kind == Token_Invalid) { + return ParseFile_InvalidToken; + } + array_add(&f->tokens, token); - if (token.kind == Token_EOF) { - break; + if (token.kind == Token_EOF) { + break; + } } } @@ -3044,6 +3047,8 @@ String get_filepath_extension(String path) { } void parse_file(Parser *p, AstFile *f) { + PROF_PROC(); + String filepath = f->tokenizer.fullpath; String base_dir = filepath; for (isize i = filepath.len-1; i >= 0; i--) { diff --git a/src/profiler.cpp b/src/profiler.cpp new file mode 100644 index 000000000..388e99b4f --- /dev/null +++ b/src/profiler.cpp @@ -0,0 +1,120 @@ +// #define PROF_TIMINGS + +struct ProfInfo { + String name; + HashKey hash; + i32 count; + i64 total_time; +}; + +struct Profiler { + Map info; // Key: String + isize max_name_len; + i64 start_time; +}; + +gb_global Profiler global_profiler; + +i64 prof_get_timestamp(void) { + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + return counter.QuadPart; +} + +void prof_init(void) { +#if defined(PROF_TIMINGS) + map_init(&global_profiler.info, gb_heap_allocator()); + global_profiler.start_time = prof_get_timestamp(); +#endif +} + + + + +ProfInfo prof_begin(String name) { + ProfInfo info = {}; + info.name = name; + info.hash = hash_pointer(name.text); // NOTE(bill): Requires it to be unique + + info.total_time = prof_get_timestamp(); + return info; +} + +void prof_end(ProfInfo info) { + i64 dt = prof_get_timestamp() - info.total_time; + info.total_time = dt; + + auto *found = map_get(&global_profiler.info, info.hash); + if (found) { + found->count++; + found->total_time += info.total_time; + } else { + info.count++; + map_set(&global_profiler.info, info.hash, info); + if (global_profiler.max_name_len < info.name.len) { + global_profiler.max_name_len = info.name.len; + } + } +} + +struct ScopedProfInfo { + ProfInfo info; + ScopedProfInfo(String name) { + info = prof_begin(name); + } + ~ScopedProfInfo() { + prof_end(info); + } +}; + +#if defined(PROF_TIMINGS) +#define PROF_SCOPED(msg) ScopedProfInfo scoped_prof_info_##__COUNTER__ = ScopedProfInfo(make_string(cast(u8 *)msg, gb_size_of(msg)-1)) +#else +#define PROF_SCOPED(msg) do {} while (0) +#endif +#define PROF_PROC() PROF_SCOPED(__FUNCTION__) + +void prof_print_all(void) { +#if defined(PROF_TIMINGS) + LARGE_INTEGER win32_perf_count_freq = {0}; + QueryPerformanceFrequency(&win32_perf_count_freq); + GB_ASSERT(win32_perf_count_freq.QuadPart != 0); + + gb_printf("Profiler Timings\n"); + + i32 string_offset = cast(int)global_profiler.max_name_len; + char spaces[] = " "; + char dashses[] = "--------------------------------------------------------------------------------"; + isize pad_len = gb_size_of(spaces)-1; + + isize info_count = global_profiler.info.entries.count; + ProfInfo *info_data = gb_alloc_array(gb_heap_allocator(), ProfInfo, info_count); + defer (gb_free(gb_heap_allocator(), info_data)); + for (isize i = 0; i < info_count; i++) { + info_data[i] = global_profiler.info.entries[i].value; + } + + gb_sort_array(info_data, info_count, gb_i64_cmp(gb_offset_of(ProfInfo, total_time))); + + for (isize i = info_count-1; i >= 0; i--) { + auto entry = info_data + i; + f64 dt = (1000.0*entry->total_time / cast(f64)win32_perf_count_freq.QuadPart); + int pad = global_profiler.max_name_len - entry->name.len; + pad = gb_max(pad, 0); + gb_printf("%.*s%*.*s - %.3f ms - %.3f us\n", + LIT(entry->name), + pad, pad, spaces, + dt, 1000.0*dt/cast(f64)entry->count); + } + + i64 total_time = prof_get_timestamp() - global_profiler.start_time; + f64 total_time_ms = (1000.0*total_time / cast(f64)win32_perf_count_freq.QuadPart); + + + gb_printf("%*.*s\n" + "%*.*s %.3f ms\n", + global_profiler.max_name_len, global_profiler.max_name_len, dashses, + global_profiler.max_name_len, global_profiler.max_name_len, spaces, + total_time_ms); +#endif +} diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index c7c423512..f7a4d5cf1 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -346,6 +346,8 @@ void advance_to_next_rune(Tokenizer *t) { } TokenizerInitError init_tokenizer(Tokenizer *t, String fullpath) { + PROF_PROC(); + char *c_str = gb_alloc_array(gb_heap_allocator(), char, fullpath.len+1); memcpy(c_str, fullpath.text, fullpath.len); c_str[fullpath.len] = '\0';