diff --git a/build.bat b/build.bat index 2fe7a1cbd..8869dfb06 100644 --- a/build.bat +++ b/build.bat @@ -10,6 +10,7 @@ set compiler_flags= -nologo -Oi -TP -W4 -fp:fast -fp:except- -Gm- -MP -FC -Z7 -G if %release_mode% EQU 0 ( rem Debug set compiler_flags=%compiler_flags% -Od -MDd -Z7 + rem -DDISPLAY_TIMING ) else ( rem Release set compiler_flags=%compiler_flags% -O2 -MT ) diff --git a/examples/basic.odin b/examples/basic.odin index b41b77bb2..ced4df599 100644 --- a/examples/basic.odin +++ b/examples/basic.odin @@ -63,8 +63,8 @@ print_nl_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune "\ print_int_to_buffer :: proc(buf: ^[]byte, i: int) { print_int_base_to_buffer(buf, i, 10); } +PRINT__NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$" print_int_base_to_buffer :: proc(buffer: ^[]byte, i, base: int) { - NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$" buf: [65]byte len := 0 @@ -78,7 +78,7 @@ print_int_base_to_buffer :: proc(buffer: ^[]byte, i, base: int) { len++ } for i > 0 { - buf[len] = NUM_TO_CHAR_TABLE[i % base] + buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % base] len++; i /= base } @@ -96,8 +96,6 @@ print_uint_to_buffer :: proc(buffer: ^[]byte, i: uint) { print_uint_base_to_buffer(buffer, i, 10, 0, #rune " ") } print_uint_base_to_buffer :: proc(buffer: ^[]byte, i, base: uint, min_width: int, pad_char: byte) { - NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$" - buf: [65]byte len := 0 if i == 0 { @@ -105,7 +103,7 @@ print_uint_base_to_buffer :: proc(buffer: ^[]byte, i, base: uint, min_width: int len++ } for i > 0 { - buf[len] = NUM_TO_CHAR_TABLE[i % base] + buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % base] len++ i /= base } @@ -139,8 +137,6 @@ print__f64 :: proc(buffer: ^[]byte, f: f64, decimal_places: int) { } print_u64_to_buffer :: proc(buffer: ^[]byte, i: u64) { - NUM_TO_CHAR_TABLE :: "0123456789" - buf: [22]byte len := 0 if i == 0 { @@ -148,7 +144,7 @@ print__f64 :: proc(buffer: ^[]byte, f: f64, decimal_places: int) { len++ } for i > 0 { - buf[len] = NUM_TO_CHAR_TABLE[i % 10] + buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % 10] len++ i /= 10 } @@ -173,13 +169,14 @@ print__f64 :: proc(buffer: ^[]byte, f: f64, decimal_places: int) { -print_any_to_buffer :: proc(buf: ^[]byte ,arg: any) { +print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { using Type_Info match type arg.type_info -> info { case Named: - print_string_to_buffer(buf, "(") - print_string_to_buffer(buf, info.name) - print_string_to_buffer(buf, ")") + a: any + a.type_info = info.base + a.data = arg.data + print_any_to_buffer(buf, a) case Integer: if info.signed { @@ -250,7 +247,6 @@ print_any_to_buffer :: proc(buf: ^[]byte ,arg: any) { case Slice: print_string_to_buffer(buf, "(slice)") case Vector: print_string_to_buffer(buf, "(vector)") - case Struct: print_string_to_buffer(buf, "(struct)") case Union: print_string_to_buffer(buf, "(union)") case Raw_Union: print_string_to_buffer(buf, "(raw_union)") @@ -265,38 +261,22 @@ print_any_to_buffer :: proc(buf: ^[]byte ,arg: any) { print_to_buffer :: proc(buf: ^[]byte, args: ..any) { for i := 0; i < len(args); i++ { - arg := args[i] - if i > 0 { print_space_to_buffer(buf) } - print_any_to_buffer(buf, arg) + print_any_to_buffer(buf, args[i]) } - print_nl_to_buffer(buf) } println_to_buffer :: proc(buf: ^[]byte, args: ..any) { - for i := 0; i < len(args); i++ { - arg := args[i] - - if i > 0 { - print_space_to_buffer(buf) - } - print_any_to_buffer(buf, arg) - } + print_to_buffer(buf, ..args) + print_nl_to_buffer(buf) } print :: proc(args: ..any) { data: [4096]byte buf := data[:0] - for i := 0; i < len(args); i++ { - arg := args[i] - - if i > 0 { - print_space_to_buffer(^buf) - } - print_any_to_buffer(^buf, arg) - } + print_to_buffer(^buf, ..args) file_write(file_get_standard(File_Standard.OUTPUT), buf) } @@ -304,14 +284,6 @@ print :: proc(args: ..any) { println :: proc(args: ..any) { data: [4096]byte buf := data[:0] - for i := 0; i < len(args); i++ { - arg := args[i] - - if i > 0 { - print_space_to_buffer(^buf) - } - print_any_to_buffer(^buf, arg) - } - print_nl_to_buffer(^buf) + println_to_buffer(^buf, ..args) file_write(file_get_standard(File_Standard.OUTPUT), buf) } diff --git a/examples/demo.odin b/examples/demo.odin index 3dd9db53f..0e4c2b737 100644 --- a/examples/demo.odin +++ b/examples/demo.odin @@ -2,13 +2,6 @@ #load "math.odin" main :: proc() { - i: int - s: struct { - x, y, z: f32 - } - p := ^s - - a: any = i - + a: any = 1 println(137, "Hello", 1.25, true) } diff --git a/examples/math.odin b/examples/math.odin index d10bcd5d4..3a6f4595d 100644 --- a/examples/math.odin +++ b/examples/math.odin @@ -95,9 +95,9 @@ cross :: proc(x, y: Vec3) -> Vec3 { } -vec2_mag :: proc(v: Vec2) -> f32 { return fsqrt(v ''dot2 v) } -vec3_mag :: proc(v: Vec3) -> f32 { return fsqrt(v ''dot3 v) } -vec4_mag :: proc(v: Vec4) -> f32 { return fsqrt(v ''dot4 v) } +vec2_mag :: proc(v: Vec2) -> f32 { return fsqrt(dot2(v, v)) } +vec3_mag :: proc(v: Vec3) -> f32 { return fsqrt(dot3(v, v)) } +vec4_mag :: proc(v: Vec4) -> f32 { return fsqrt(dot4(v, v)) } vec2_norm :: proc(v: Vec2) -> Vec2 { return v / Vec2{vec2_mag(v)} } vec3_norm :: proc(v: Vec3) -> Vec3 { return v / Vec3{vec3_mag(v)} } diff --git a/examples/runtime.odin b/examples/runtime.odin index d94597880..4aff161eb 100644 --- a/examples/runtime.odin +++ b/examples/runtime.odin @@ -9,7 +9,7 @@ Type_Info :: union { offset: int } Record :: struct { - fields: []Member + fields: []Member // NOTE(bill): This will need to be allocated on the heap } @@ -50,6 +50,7 @@ Type_Info :: union { } + assume :: proc(cond: bool) #foreign "llvm.assume" __debug_trap :: proc() #foreign "llvm.debugtrap" @@ -276,7 +277,5 @@ __default_allocator :: proc() -> Allocator { __assert :: proc(msg: string) { file_write(file_get_standard(File_Standard.ERROR), msg as []byte) - // TODO(bill): Which is better? - // __trap() __debug_trap() } diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 65b2e4a6f..9fd61eec8 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -866,7 +866,7 @@ void check_parsed_files(Checker *c) { t_type_info_ptr = make_type_pointer(c->allocator, t_type_info); auto *record = &get_base_type(e->type)->Record; - GB_ASSERT(record->field_count == 15); + GB_ASSERT_MSG(record->field_count == 15, "Internal Compiler Error: Invalid `Type_Info` layout"); t_type_info_named = record->fields[ 1]->type; t_type_info_integer = record->fields[ 2]->type; t_type_info_float = record->fields[ 3]->type; @@ -881,6 +881,7 @@ void check_parsed_files(Checker *c) { t_type_info_union = record->fields[12]->type; t_type_info_raw_union = record->fields[13]->type; t_type_info_enum = record->fields[14]->type; + // t_type_info_any = record->fields[15]->type; } check_global_entity(c, Entity_Constant); diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp index dd978e810..a1a368b6a 100644 --- a/src/checker/entity.cpp +++ b/src/checker/entity.cpp @@ -6,7 +6,6 @@ enum BuiltinProcId; ENTITY_KIND(Invalid), \ ENTITY_KIND(Constant), \ ENTITY_KIND(Variable), \ - ENTITY_KIND(UsingVariable), \ ENTITY_KIND(TypeName), \ ENTITY_KIND(Procedure), \ ENTITY_KIND(Builtin), \ @@ -46,10 +45,12 @@ struct Entity { b8 used; // Variable is used b8 is_field; // Is struct field b8 anonymous; // Variable is an anonymous + b8 is_using; // `using` variable } Variable; - struct {} UsingVariable; struct {} TypeName; - struct { b8 used; } Procedure; + struct { + b8 pure; + } Procedure; struct { BuiltinProcId id; } Builtin; }; }; @@ -77,8 +78,9 @@ Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *typ Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) { GB_ASSERT(parent != NULL); - Entity *entity = alloc_entity(a, Entity_UsingVariable, parent->scope, token, type); + Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type); entity->using_parent = parent; + entity->Variable.is_using = true; return entity; } diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 5e97727fd..7bf131f05 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -91,8 +91,6 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu Type *s = operand->type; - - if (are_types_identical(s, type)) { return true; } @@ -179,6 +177,7 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n Type *target_type = type; if (type == NULL || is_type_any(type)) { + add_type_info_type(c, type); target_type = default_type(operand->type); } convert_to_typed(c, operand, target_type); @@ -795,11 +794,6 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl o->mode = Addressing_Builtin; break; - case Entity_UsingVariable: - // TODO(bill): Entity_UsingVariable: is this correct? - o->mode = Addressing_Variable; - break; - default: GB_PANIC("Compiler error: Unknown EntityKind"); break; diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index 636ccdb34..3001c6e5e 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -452,6 +452,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) { b32 is_foreign = (pd->tags & ProcTag_foreign) != 0; b32 is_inline = (pd->tags & ProcTag_inline) != 0; b32 is_no_inline = (pd->tags & ProcTag_no_inline) != 0; + b32 is_pure = (pd->tags & ProcTag_pure) != 0; @@ -1283,8 +1284,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { error(&c->error_collector, us->token, "`using` cannot be applied to a procedure"); break; - case Entity_Variable: - case Entity_UsingVariable: { + case Entity_Variable: { Type *t = get_base_type(type_deref(e->type)); if (is_type_struct(t) || is_type_raw_union(t)) { Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node)); diff --git a/src/checker/type.cpp b/src/checker/type.cpp index 8db89a38c..f2db752a0 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -369,6 +369,7 @@ gb_global Type *t_type_info_struct = NULL; gb_global Type *t_type_info_union = NULL; gb_global Type *t_type_info_raw_union = NULL; gb_global Type *t_type_info_enum = NULL; +gb_global Type *t_type_info_any = NULL; diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index aa7d49649..0340cd322 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -1532,7 +1532,6 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg ssaValue *type_info_data = *found; CheckerInfo *info = proc->module->info; - ssaValue *result = ssa_add_local_generated(proc, t_any); // NOTE(bill): Make copy on stack so I can reference it later @@ -1542,8 +1541,20 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg MapFindResult fr = map__find(&info->type_info_types, hash_pointer(src_type)); - GB_ASSERT(fr.entry_index >= 0); - ssaValue *ti = ssa_emit_struct_gep(proc, type_info_data, fr.entry_index, t_type_info_ptr); + isize entry_index = fr.entry_index; + if (entry_index < 0) { + // NOTE(bill): Do manual search + // TODO(bill): This is O(n) and can be very slow + gb_for_array(i, info->type_info_types.entries){ + auto *e = &info->type_info_types.entries[i]; + Type *t = e->value; + if (are_types_identical(t, src_type)) { + entry_index = i; + break; + } + } + } + ssaValue *ti = ssa_emit_struct_gep(proc, type_info_data, entry_index, t_type_info_ptr); ssaValue *gep0 = ssa_emit_struct_gep(proc, result, v_zero32, make_type_pointer(proc->module->allocator, t_type_info_ptr)); ssaValue *gep1 = ssa_emit_struct_gep(proc, result, v_one32, make_type_pointer(proc->module->allocator, t_rawptr)); @@ -2396,11 +2407,11 @@ ssaValue *ssa_build_expr(ssaProcedure *proc, AstNode *expr) { ssaValue *ssa_add_using_variable(ssaProcedure *proc, Entity *e) { - GB_ASSERT(e->kind == Entity_UsingVariable); + GB_ASSERT(e->kind == Entity_Variable && e->Variable.is_using); String name = e->token.string; Entity *parent = e->using_parent; ssaValue *p = NULL; - if (parent->kind == Entity_UsingVariable) { + if (parent->kind == Entity_Variable && parent->Variable.is_using) { p = ssa_add_using_variable(proc, parent); } @@ -2432,7 +2443,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { ssaValue **found = map_get(&proc->module->values, hash_pointer(e)); if (found) { v = *found; - } else if (e->kind == Entity_UsingVariable) { + } else if (e->kind == Entity_Variable && e->Variable.is_using) { v = ssa_add_using_variable(proc, e); } if (v == NULL) { @@ -2536,7 +2547,6 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int); v = ssa_emit_ptr_offset(proc, elem, index); - // gb_printf_err("HERE! %s -> %s\n", type_to_string(ssa_type(v)), expr_to_string(expr)); return ssa_make_addr(v, expr); case_end; diff --git a/src/main.cpp b/src/main.cpp index 06cfc73f2..e3d819ffb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,14 +41,14 @@ i32 win32_exec_command_line_app(char *fmt, ...) { } -#if 1 +#if defined(DISPLAY_TIMING) #define INIT_TIMER() u64 start_time, end_time = 0, total_time = 0; start_time = gb_utc_time_now() #define PRINT_TIMER(section) do { \ u64 diff; \ end_time = gb_utc_time_now(); \ diff = end_time - start_time; \ total_time += diff; \ - gb_printf_err("%s: %lld ms\n", section, diff/1000); \ + gb_printf_err("%s: %.1f ms\n", section, diff/1000.0f); \ start_time = gb_utc_time_now(); \ } while (0) diff --git a/src/parser.cpp b/src/parser.cpp index e0902d795..ec741ce1e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -62,6 +62,7 @@ enum ProcTag { ProcTag_foreign = GB_BIT(0), ProcTag_inline = GB_BIT(1), ProcTag_no_inline = GB_BIT(2), + ProcTag_pure = GB_BIT(3), }; enum VarDeclTag { @@ -1157,6 +1158,8 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name) { check_proc_add_tag(f, tag_expr, tags, ProcTag_inline, tag_name); } else if (are_strings_equal(tag_name, make_string("no_inline"))) { check_proc_add_tag(f, tag_expr, tags, ProcTag_no_inline, tag_name); + } else if (are_strings_equal(tag_name, make_string("pure"))) { + check_proc_add_tag(f, tag_expr, tags, ProcTag_pure, tag_name); } else { ast_file_err(f, ast_node_token(tag_expr), "Unknown procedure tag"); }