From f3bffb98101e3a584c8a5e8a6389c608ffe64c40 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Jul 2019 10:20:11 +0100 Subject: Improvement to the Odin calling conventions to pass certain things by "implicit reference" (`const &` in C++) --- src/ir.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 82f9fa755..8c5dcb963 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3004,9 +3004,8 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro if (are_types_identical(arg_type, new_type)) { // NOTE(bill): Done } else if (!are_types_identical(original_type, new_type)) { - if (is_type_pointer(new_type) && !is_type_pointer(original_type)) { - if (e->flags&EntityFlag_Value) { + if (e->flags&EntityFlag_ImplicitReference) { args[i] = ir_address_from_load_or_generate_local(p, args[i]); } else if (!is_type_pointer(arg_type)) { args[i] = ir_copy_value_to_ptr(p, args[i], original_type, 16); -- cgit v1.2.3 From 14059583cdb3039a16979f97c4fd1907fc069662 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Jul 2019 10:44:40 +0100 Subject: Fix array comparisons --- src/ir.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 8c5dcb963..973aa7476 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4111,14 +4111,17 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal if (inline_array_arith) { // inline + irValue *val = ir_add_local_generated(proc, t_bool, false); + ir_emit_store(proc, val, res); for (i32 i = 0; i < count; i++) { irValue *x = ir_emit_load(proc, ir_emit_array_epi(proc, lhs, i)); irValue *y = ir_emit_load(proc, ir_emit_array_epi(proc, rhs, i)); irValue *cmp = ir_emit_comp(proc, op_kind, x, y); - res = ir_emit_arith(proc, cmp_op, res, cmp, t_bool); + irValue *new_res = ir_emit_arith(proc, cmp_op, ir_emit_load(proc, val), cmp, t_bool); + ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool)); } - return ir_emit_conv(proc, res, t_bool); + return ir_emit_load(proc, val); } else { irValue *val = ir_add_local_generated(proc, t_bool, false); ir_emit_store(proc, val, res); @@ -4127,7 +4130,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, loop_data.idx)); irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, loop_data.idx)); irValue *cmp = ir_emit_comp(proc, op_kind, x, y); - irValue *new_res = ir_emit_arith(proc, cmp_op, res, cmp, t_bool); + irValue *new_res = ir_emit_arith(proc, cmp_op, res, ir_emit_load(proc, val), t_bool); ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool)); } ir_loop_end(proc, loop_data); -- cgit v1.2.3 From 912fc2890b1603ff8f6ffa09b15719322e852edf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Jul 2019 11:33:22 +0100 Subject: Fix array comparisons and fix f32 literal LLVM issue regarding accurate representation --- src/ir.cpp | 20 ++++++++++++-------- src/ir_print.cpp | 24 ++++++++++++++++++++---- 2 files changed, 32 insertions(+), 12 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 973aa7476..9f95db524 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3652,12 +3652,12 @@ struct irLoopData { irBlock *loop; }; -irLoopData ir_loop_start(irProcedure *proc, isize count) { +irLoopData ir_loop_start(irProcedure *proc, isize count, Type *index_type=t_int) { irLoopData data = {}; irValue *max = ir_const_int(count); - data.idx_addr = ir_add_local_generated(proc, t_int, true); + data.idx_addr = ir_add_local_generated(proc, index_type, true); data.body = ir_new_block(proc, nullptr, "loop.body"); data.done = ir_new_block(proc, nullptr, "loop.done"); @@ -3727,7 +3727,7 @@ irValue *ir_emit_unary_arith(irProcedure *proc, TokenKind op, irValue *x, Type * ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z); } } else { - auto loop_data = ir_loop_start(proc, count); + auto loop_data = ir_loop_start(proc, count, t_i32); irValue *e = ir_emit_load(proc, ir_emit_array_ep(proc, val, loop_data.idx)); irValue *z = ir_emit_unary_arith(proc, op, e, elem_type); @@ -3786,7 +3786,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z); } } else { - auto loop_data = ir_loop_start(proc, count); + auto loop_data = ir_loop_start(proc, count, t_i32); irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, loop_data.idx)); irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, loop_data.idx)); @@ -4104,6 +4104,9 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal if (op_kind == Token_NotEq) { res = v_false; cmp_op = Token_Or; + } else if (op_kind == Token_CmpEq) { + res = v_true; + cmp_op = Token_And; } bool inline_array_arith = type_size_of(tl) <= build_context.max_align; @@ -4125,12 +4128,13 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal } else { irValue *val = ir_add_local_generated(proc, t_bool, false); ir_emit_store(proc, val, res); - auto loop_data = ir_loop_start(proc, count); + auto loop_data = ir_loop_start(proc, count, t_i32); { - irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, loop_data.idx)); - irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, loop_data.idx)); + irValue *i = loop_data.idx; + irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, i)); + irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, i)); irValue *cmp = ir_emit_comp(proc, op_kind, x, y); - irValue *new_res = ir_emit_arith(proc, cmp_op, res, ir_emit_load(proc, val), t_bool); + irValue *new_res = ir_emit_arith(proc, cmp_op, ir_emit_load(proc, val), cmp, t_bool); ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool)); } ir_loop_end(proc, loop_data); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index b008fa682..a64f454d0 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -767,15 +767,17 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * case ExactValue_Float: { GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type)); type = core_type(type); - u64 u = bit_cast(value.value_float); + u64 u_64 = bit_cast(value.value_float); + u32 u_32 = bit_cast(cast(f32)value.value_float); + #if 0 switch (type->Basic.kind) { case Basic_f32: // IMPORTANT NOTE(bill): LLVM requires all floating point constants to be // a 64 bit number if bits_of(float type) <= 64. // https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M - // 64 bit mantissa: 52 bits - // 32 bit mantissa: 23 bits - // 16 bit mantissa: 10 bits + // 64 bit mantissa: 52 bits ==> 52-52 == 0 + // 32 bit mantissa: 23 bits ==> 52-23 == 29 + // 16 bit mantissa: 10 bits ==> 52=10 == 42 // 29 == 52-23 u >>= 29; u <<= 29; @@ -792,6 +794,20 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ir_fprintf(f, "0x%016llx", u); break; } + #else + switch (type->Basic.kind) { + case Basic_f32: { + ir_fprintf(f, "bitcast (i32 %u to float)", u_32); + break; + } + case Basic_f64: + ir_fprintf(f, "0x%016llx", u_64); + break; + default: + ir_fprintf(f, "0x%016llx", u_64); + break; + } + #endif break; } case ExactValue_Complex: { -- cgit v1.2.3 From 77734ea967d620541eadc770280477cf1550892e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 27 Jul 2019 11:59:50 +0100 Subject: Improve the performance of simple array comparisons --- core/runtime/internal.odin | 40 +++++++++++++++++++++++++++++++++++++++- src/checker.cpp | 2 ++ src/ir.cpp | 37 ++++++++++++++++++++++++------------- src/types.cpp | 23 +++++++++++++++++++++++ 4 files changed, 88 insertions(+), 14 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index d4d7ab84d..90d653c71 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -243,6 +243,44 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) { } } +memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check { + x := uintptr(a); + y := uintptr(b); + n := uintptr(n); + + SU :: size_of(uintptr); + fast := uintptr(n/SU + 1); + offset := (fast-1)*SU; + curr_block := uintptr(0); + if n < SU { + fast = 0; + } + + for /**/; curr_block < fast; curr_block += 1 { + va := (^uintptr)(x + curr_block * size_of(uintptr))^; + vb := (^uintptr)(y + curr_block * size_of(uintptr))^; + if va ~ vb != 0 { + for pos := curr_block*SU; pos < n; pos += 1 { + a := (^byte)(x+pos)^; + b := (^byte)(y+pos)^; + if a ~ b != 0 { + return (int(a) - int(b)) < 0 ? -1 : +1; + } + } + } + } + + for /**/; offset < n; offset += 1 { + a := (^byte)(x+offset)^; + b := (^byte)(y+offset)^; + if a ~ b != 0 { + return (int(a) - int(b)) < 0 ? -1 : +1; + } + } + + return 0; +} + string_eq :: proc "contextless" (a, b: string) -> bool { switch { case len(a) != len(b): return false; @@ -253,7 +291,7 @@ string_eq :: proc "contextless" (a, b: string) -> bool { } string_cmp :: proc "contextless" (a, b: string) -> int { - return mem.compare_byte_ptrs(&a[0], &b[0], min(len(a), len(b))); + return memory_compare(&a[0], &b[0], min(len(a), len(b))); } string_ne :: inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b); } diff --git a/src/checker.cpp b/src/checker.cpp index f68e2ab15..ba13b2237 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1613,6 +1613,8 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("umodti3"), str_lit("udivti3"), + + str_lit("memory_compare"), }; for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) { add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i])); diff --git a/src/ir.cpp b/src/ir.cpp index 9f95db524..1105eac29 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4126,20 +4126,31 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal return ir_emit_load(proc, val); } else { - irValue *val = ir_add_local_generated(proc, t_bool, false); - ir_emit_store(proc, val, res); - auto loop_data = ir_loop_start(proc, count, t_i32); - { - irValue *i = loop_data.idx; - irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, i)); - irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, i)); - irValue *cmp = ir_emit_comp(proc, op_kind, x, y); - irValue *new_res = ir_emit_arith(proc, cmp_op, ir_emit_load(proc, val), cmp, t_bool); - ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool)); - } - ir_loop_end(proc, loop_data); + if (is_type_simple_compare(tl) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) { + // TODO(bill): Test to see if this is actually faster!!!! + auto args = array_make(heap_allocator(), 3); + args[0] = ir_emit_conv(proc, lhs, t_rawptr); + args[1] = ir_emit_conv(proc, rhs, t_rawptr); + args[2] = ir_const_int(type_size_of(tl)); + irValue *val = ir_emit_runtime_call(proc, "memory_compare", args); + irValue *res = ir_emit_comp(proc, op_kind, val, v_zero); + return ir_emit_conv(proc, res, t_bool); + } else { + irValue *val = ir_add_local_generated(proc, t_bool, false); + ir_emit_store(proc, val, res); + auto loop_data = ir_loop_start(proc, count, t_i32); + { + irValue *i = loop_data.idx; + irValue *x = ir_emit_load(proc, ir_emit_array_ep(proc, lhs, i)); + irValue *y = ir_emit_load(proc, ir_emit_array_ep(proc, rhs, i)); + irValue *cmp = ir_emit_comp(proc, op_kind, x, y); + irValue *new_res = ir_emit_arith(proc, cmp_op, ir_emit_load(proc, val), cmp, t_bool); + ir_emit_store(proc, val, ir_emit_conv(proc, new_res, t_bool)); + } + ir_loop_end(proc, loop_data); - return ir_emit_load(proc, val); + return ir_emit_load(proc, val); + } } } diff --git a/src/types.cpp b/src/types.cpp index dc7ecb946..5cf86d6b6 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1037,6 +1037,29 @@ Type *core_array_type(Type *t) { return t; } +// NOTE(bill): type can be easily compared using memcmp +bool is_type_simple_compare(Type *t) { + t = core_type(t); + switch (t->kind) { + case Type_Array: + return is_type_simple_compare(t->Array.elem); + + case Type_Basic: + if (t->Basic.flags & (BasicFlag_Integer|BasicFlag_Float|BasicFlag_Complex|BasicFlag_Rune|BasicFlag_Pointer)) { + return true; + } + return false; + + case Type_Pointer: + case Type_Proc: + case Type_BitSet: + case Type_BitField: + return true; + } + + return false; +} + Type *base_complex_elem_type(Type *t) { t = core_type(t); if (is_type_complex(t)) { -- cgit v1.2.3 From 2c5c8192f8fcb40fdef183c25a8d799f23f23439 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 28 Jul 2019 22:58:56 +0100 Subject: Fix parsing for procedure literals expression statements; improve assert performance; other minor fixes --- core/odin/parser/parser.odin | 1 + core/runtime/core.odin | 12 +++++++----- core/sys/win32/kernel32.odin | 2 +- core/sys/win32/user32.odin | 2 +- core/time/time_windows.odin | 2 +- src/ir.cpp | 2 +- src/parser.cpp | 1 + 7 files changed, 13 insertions(+), 9 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 077e04cc9..0c011e07e 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -955,6 +955,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { switch p.curr_tok.kind { // Operands case token.Context, // Also allows for 'context = ' + token.Proc, token.Inline, token.No_Inline, token.Ident, token.Integer, token.Float, token.Imag, diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 623f3725a..02578da3b 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -666,11 +666,13 @@ card :: proc(s: $S/bit_set[$E; $U]) -> int { @builtin assert :: proc(condition: bool, message := "", loc := #caller_location) -> bool { if !condition { - p := context.assertion_failure_proc; - if p == nil { - p = default_assertion_failure_proc; - } - p("Runtime assertion", message, loc); + proc(message: string, loc: Source_Code_Location) { + p := context.assertion_failure_proc; + if p == nil { + p = default_assertion_failure_proc; + } + p("Runtime assertion", message, loc); + }(message, loc); } return condition; } diff --git a/core/sys/win32/kernel32.odin b/core/sys/win32/kernel32.odin index 036fc016a..f647ab7e0 100644 --- a/core/sys/win32/kernel32.odin +++ b/core/sys/win32/kernel32.odin @@ -23,7 +23,7 @@ foreign kernel32 { @(link_name="GetModuleFileNameA") get_module_file_name_a :: proc(module: Hmodule, filename: cstring, size: u32) -> u32 ---; @(link_name="GetModuleFileNameW") get_module_file_name_w :: proc(module: Hmodule, filename: Wstring, size: u32) -> u32 ---; - @(link_name="Sleep") sleep :: proc(ms: i32) -> i32 ---; + @(link_name="Sleep") sleep :: proc(ms: u32) ---; @(link_name="QueryPerformanceFrequency") query_performance_frequency :: proc(result: ^i64) -> i32 ---; @(link_name="QueryPerformanceCounter") query_performance_counter :: proc(result: ^i64) -> i32 ---; @(link_name="OutputDebugStringA") output_debug_string_a :: proc(c_str: cstring) ---; diff --git a/core/sys/win32/user32.odin b/core/sys/win32/user32.odin index b8969faf3..5165d9389 100644 --- a/core/sys/win32/user32.odin +++ b/core/sys/win32/user32.odin @@ -182,7 +182,7 @@ foreign user32 { @(link_name="DestroyIcon") destroy_icon :: proc(icon: Hicon) -> Bool ---; @(link_name="LoadCursorA") load_cursor_a :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---; - @(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: cstring) -> Hcursor ---; + @(link_name="LoadCursorW") load_cursor_w :: proc(instance: Hinstance, cursor_name: Wstring) -> Hcursor ---; @(link_name="GetCursor") get_cursor :: proc() -> Hcursor ---; @(link_name="SetCursor") set_cursor :: proc(cursor: Hcursor) -> Hcursor ---; diff --git a/core/time/time_windows.odin b/core/time/time_windows.odin index 31fbca769..f6bfdd678 100644 --- a/core/time/time_windows.odin +++ b/core/time/time_windows.odin @@ -20,5 +20,5 @@ now :: proc() -> Time { sleep :: proc(d: Duration) { - win32.sleep(i32(d/Millisecond)); + win32.sleep(u32(d/Millisecond)); } diff --git a/src/ir.cpp b/src/ir.cpp index 1105eac29..0a5dc7528 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3053,7 +3053,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro if (value->kind == irValue_Proc) { irProcedure *the_proc = &value->Proc; Entity *e = the_proc->entity; - if (entity_has_deferred_procedure(e)) { + if (e != nullptr && entity_has_deferred_procedure(e)) { DeferredProcedureKind kind = e->Procedure.deferred_procedure.kind; Entity *deferred_entity = e->Procedure.deferred_procedure.entity; irValue **deferred_found = map_get(&p->module->values, hash_entity(deferred_entity)); diff --git a/src/parser.cpp b/src/parser.cpp index a377b773c..d1fd94c1d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3759,6 +3759,7 @@ Ast *parse_stmt(AstFile *f) { switch (token.kind) { // Operands case Token_context: // Also allows for `context =` + case Token_proc: case Token_inline: case Token_no_inline: case Token_Ident: -- cgit v1.2.3 From 65d41d4248b61e6ef79ed02c2ce4f3be305149a5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 9 Aug 2019 20:31:11 +0100 Subject: Fix bit_field comparison against nil #414 --- core/runtime/internal.odin | 34 ++++++++++++++++++++++++++++++++++ src/checker.cpp | 1 + src/ir.cpp | 9 +++++++++ 3 files changed, 44 insertions(+) (limited to 'src/ir.cpp') diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 90d653c71..c33d5f62c 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -281,6 +281,40 @@ memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_ch return 0; } +memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check { + x := uintptr(a); + n := uintptr(n); + + SU :: size_of(uintptr); + fast := uintptr(n/SU + 1); + offset := (fast-1)*SU; + curr_block := uintptr(0); + if n < SU { + fast = 0; + } + + for /**/; curr_block < fast; curr_block += 1 { + va := (^uintptr)(x + curr_block * size_of(uintptr))^; + if va ~ 0 != 0 { + for pos := curr_block*SU; pos < n; pos += 1 { + a := (^byte)(x+pos)^; + if a ~ 0 != 0 { + return int(a) < 0 ? -1 : +1; + } + } + } + } + + for /**/; offset < n; offset += 1 { + a := (^byte)(x+offset)^; + if a ~ 0 != 0 { + return int(a) < 0 ? -1 : +1; + } + } + + return 0; +} + string_eq :: proc "contextless" (a, b: string) -> bool { switch { case len(a) != len(b): return false; diff --git a/src/checker.cpp b/src/checker.cpp index ba13b2237..45b661a58 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1615,6 +1615,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("udivti3"), str_lit("memory_compare"), + str_lit("memory_compare_zero"), }; for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) { add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i])); diff --git a/src/ir.cpp b/src/ir.cpp index 0a5dc7528..ee67c0ea8 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4017,6 +4017,15 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue } else if (is_type_typeid(t)) { irValue *invalid_typeid = ir_value_constant(t_typeid, exact_value_i64(0)); return ir_emit_comp(proc, op_kind, x, invalid_typeid); + } else if (is_type_bit_field(t)) { + auto args = array_make(heap_allocator(), 2); + irValue *lhs = ir_address_from_load_or_generate_local(proc, x); + args[0] = ir_emit_conv(proc, lhs, t_rawptr); + args[1] = ir_const_int(type_size_of(t)); + irValue *val = ir_emit_runtime_call(proc, "memory_compare_zero", args); + irValue *res = ir_emit_comp(proc, op_kind, val, v_zero); + return ir_emit_conv(proc, res, t_bool); + } return nullptr; } -- cgit v1.2.3 From 9c632128245e9a51bb63273d0d4531ba28773629 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 9 Aug 2019 21:59:58 +0100 Subject: Struct field tags --- core/odin/ast/ast.odin | 20 ++++++++++++-------- core/odin/parser/parser.odin | 24 +++++++++++++++++------- core/runtime/core.odin | 5 +++-- examples/demo/demo.odin | 25 +++++++++++++++++++++++++ src/check_type.cpp | 6 ++++-- src/ir.cpp | 37 +++++++++++++++++++++++++++++++++---- src/parser.cpp | 37 +++++++++++++++++++++++++++++-------- src/parser.hpp | 4 +++- src/types.cpp | 1 + 9 files changed, 127 insertions(+), 32 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index c0d2948ee..3655a601d 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -435,7 +435,9 @@ Field_Flag :: enum { C_Vararg, Auto_Cast, In, + Results, + Tags, Default_Parameters, Typeid_Token, } @@ -443,18 +445,19 @@ Field_Flag :: enum { Field_Flags :: distinct bit_set[Field_Flag]; Field_Flags_Struct :: Field_Flags{ - Field_Flag.Using, + .Using, + .Tags, }; Field_Flags_Record_Poly_Params :: Field_Flags{ - Field_Flag.Typeid_Token, + .Typeid_Token, }; Field_Flags_Signature :: Field_Flags{ - Field_Flag.Ellipsis, - Field_Flag.Using, - Field_Flag.No_Alias, - Field_Flag.C_Vararg, - Field_Flag.Auto_Cast, - Field_Flag.Default_Parameters, + .Ellipsis, + .Using, + .No_Alias, + .C_Vararg, + .Auto_Cast, + .Default_Parameters, }; Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token}; @@ -483,6 +486,7 @@ Field :: struct { names: []^Expr, // Could be polymorphic type: ^Expr, default_value: ^Expr, + tag: token.Token, flags: Field_Flags, comment: ^Comment_Group, } diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 0c011e07e..2d8e42720 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1388,19 +1388,18 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se for flag in ast.Field_Flag { if flag notin allowed_flags && flag in flags { - using ast.Field_Flag; #complete switch flag { - case Using: + case .Using: error(p, p.curr_tok.pos, "'using' is not allowed within this field list"); - case No_Alias: + case .No_Alias: error(p, p.curr_tok.pos, "'#no_alias' is not allowed within this field list"); - case C_Vararg: + case .C_Vararg: error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list"); - case Auto_Cast: + case .Auto_Cast: error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list"); - case In: + case .In: error(p, p.curr_tok.pos, "'in' is not allowed within this field list"); - case Ellipsis, Results, Default_Parameters, Typeid_Token: + case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token: panic("Impossible prefixes"); } flags &~= {flag}; @@ -1540,6 +1539,7 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel type: ^ast.Expr; default_value: ^ast.Expr; + tag: token.Token; expect_token_after(p, token.Colon, "field list"); if p.curr_tok.kind != token.Eq { @@ -1579,9 +1579,19 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel error(p, p.curr_tok.pos, "extra parameter after ellipsis without a default value"); } + if type != nil && default_value == nil { + if p.curr_tok.kind == token.String { + tag = expect_token(p, token.String); + if .Tags notin allowed_flags { + error(p, tag.pos, "Field tags are only allowed within structures"); + } + } + } + ok := expect_field_separator(p, type); field := new_ast_field(names, type, default_value); + field.tag = tag; field.docs = docs; field.flags = flags; field.comment = p.line_comment; diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 02578da3b..28767cc2d 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -79,8 +79,9 @@ Type_Info_Tuple :: struct { // Only really used for procedures Type_Info_Struct :: struct { types: []^Type_Info, names: []string, - offsets: []uintptr, // offsets may not be used in tuples - usings: []bool, // usings may not be used in tuples + offsets: []uintptr, + usings: []bool, + tags: []string, is_packed: bool, is_raw_union: bool, custom_align: bool, diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 206fa4a2d..21f889746 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -3,6 +3,7 @@ package main import "core:fmt" import "core:mem" import "core:os" +import "core:runtime" when os.OS == "windows" { import "core:thread" @@ -945,6 +946,29 @@ deferred_procedure_associations :: proc() { } } +struct_field_tags :: proc() { + fmt.println("# struct_field_tags"); + + Foo :: struct { + x: int `tag1`, + y: string `tag2`, + z: bool, // no tag + } + + f: Foo; + ti := runtime.type_info_base(type_info_of(Foo)); + s := ti.variant.(runtime.Type_Info_Struct); + fmt.println("Foo :: struct {"); + for _, i in s.names { + if tag := s.tags[i]; tag != "" { + fmt.printf("\t%s: %T `%s`,\n", s.names[i], s.types[i], tag); + } else { + fmt.printf("\t%s: %T,\n", s.names[i], s.types[i]); + } + } + fmt.println("}"); +} + main :: proc() { when true { general_stuff(); @@ -963,5 +987,6 @@ main :: proc() { bit_set_type(); diverging_procedures(); deferred_procedure_associations(); + struct_field_tags(); } } diff --git a/src/check_type.cpp b/src/check_type.cpp index 36d8cf0f8..a9c1d3fe3 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -110,9 +110,10 @@ bool does_field_type_allow_using(Type *t) { return false; } -void check_struct_fields(CheckerContext *ctx, Ast *node, Array *fields, Array const ¶ms, +void check_struct_fields(CheckerContext *ctx, Ast *node, Array *fields, Array *tags, Array const ¶ms, isize init_field_capacity, Type *struct_type, String context) { *fields = array_make(heap_allocator(), 0, init_field_capacity); + *tags = array_make(heap_allocator(), 0, init_field_capacity); GB_ASSERT(node->kind == Ast_StructType); GB_ASSERT(struct_type->kind == Type_Struct); @@ -171,6 +172,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Array *fields Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index); add_entity(ctx->checker, ctx->scope, name, field); array_add(fields, field); + array_add(tags, p->tag.string); field_src_index += 1; } @@ -504,7 +506,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array< if (!is_polymorphic) { - check_struct_fields(ctx, node, &struct_type->Struct.fields, st->fields, min_field_count, struct_type, context); + check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context); } if (st->align != nullptr) { diff --git a/src/ir.cpp b/src/ir.cpp index ee67c0ea8..2499b848f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -174,6 +174,7 @@ gbAllocator ir_allocator(void) { #define IR_TYPE_INFO_NAMES_NAME "__$type_info_names_data" #define IR_TYPE_INFO_OFFSETS_NAME "__$type_info_offsets_data" #define IR_TYPE_INFO_USINGS_NAME "__$type_info_usings_data" +#define IR_TYPE_INFO_TAGS_NAME "__$type_info_tags_data" #define IR_INSTR_KINDS \ @@ -5271,12 +5272,14 @@ gb_global irValue *ir_global_type_info_member_types = nullptr; gb_global irValue *ir_global_type_info_member_names = nullptr; gb_global irValue *ir_global_type_info_member_offsets = nullptr; gb_global irValue *ir_global_type_info_member_usings = nullptr; +gb_global irValue *ir_global_type_info_member_tags = nullptr; gb_global i32 ir_global_type_info_data_index = 0; gb_global i32 ir_global_type_info_member_types_index = 0; gb_global i32 ir_global_type_info_member_names_index = 0; gb_global i32 ir_global_type_info_member_offsets_index = 0; gb_global i32 ir_global_type_info_member_usings_index = 0; +gb_global i32 ir_global_type_info_member_tags_index = 0; isize ir_type_info_count(CheckerInfo *info) { return info->minimum_dependency_type_info_set.entries.count+1; @@ -9587,6 +9590,16 @@ void ir_init_module(irModule *m, Checker *c) { map_set(&m->members, hash_string(name), g); ir_global_type_info_member_usings = g; } + + { + String name = str_lit(IR_TYPE_INFO_TAGS_NAME); + Entity *e = alloc_entity_variable(nullptr, make_token_ident(name), + alloc_type_array(t_string, count), false); + irValue *g = ir_value_global(e, nullptr); + ir_module_add_value(m, e, g); + map_set(&m->members, hash_string(name), g); + ir_global_type_info_member_tags = g; + } } } } @@ -9720,6 +9733,11 @@ irValue *ir_type_info_member_usings_offset(irProcedure *proc, isize count) { ir_global_type_info_member_usings_index += cast(i32)count; return offset; } +irValue *ir_type_info_member_tags_offset(irProcedure *proc, isize count) { + irValue *offset = ir_emit_array_epi(proc, ir_global_type_info_member_tags, ir_global_type_info_member_tags_index); + ir_global_type_info_member_tags_index += cast(i32)count; + return offset; +} @@ -10065,9 +10083,9 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info irValue *is_packed = ir_const_bool(t->Struct.is_packed); irValue *is_raw_union = ir_const_bool(t->Struct.is_raw_union); irValue *is_custom_align = ir_const_bool(t->Struct.custom_align != 0); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), is_packed); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_raw_union); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_custom_align); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_packed); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align); } isize count = t->Struct.fields.count; @@ -10076,6 +10094,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info irValue *memory_names = ir_type_info_member_names_offset (proc, count); irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, count); irValue *memory_usings = ir_type_info_member_usings_offset (proc, count); + irValue *memory_tags = ir_type_info_member_tags_offset (proc, count); type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet for (isize source_index = 0; source_index < count; source_index++) { @@ -10091,7 +10110,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info irValue *index = ir_const_int(source_index); irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index); irValue *offset = ir_emit_ptr_offset(proc, memory_offsets, index); - irValue *is_using = ir_emit_ptr_offset(proc, memory_usings, index); + irValue *is_using = ir_emit_ptr_offset(proc, memory_usings, index); ir_emit_store(proc, type_info, ir_type_info(proc, f->type)); if (f->token.string.len > 0) { @@ -10100,6 +10119,15 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info } ir_emit_store(proc, offset, ir_const_uintptr(foffset)); ir_emit_store(proc, is_using, ir_const_bool((f->flags&EntityFlag_Using) != 0)); + + if (t->Struct.tags.count > 0) { + String tag_string = t->Struct.tags[source_index]; + if (tag_string.len > 0) { + irValue *tag_ptr = ir_emit_ptr_offset(proc, memory_tags, index); + ir_emit_store(proc, tag_ptr, ir_const_string(tag_string)); + } + } + } irValue *cv = ir_const_int(count); @@ -10107,6 +10135,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, cv); ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, cv); ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 3), memory_usings, cv); + ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 4), memory_tags, cv); } break; } diff --git a/src/parser.cpp b/src/parser.cpp index d1fd94c1d..9aebc78d6 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -805,13 +805,14 @@ Ast *ast_bad_decl(AstFile *f, Token begin, Token end) { return result; } -Ast *ast_field(AstFile *f, Array names, Ast *type, Ast *default_value, u32 flags, - CommentGroup *docs, CommentGroup *comment) { +Ast *ast_field(AstFile *f, Array names, Ast *type, Ast *default_value, u32 flags, Token tag, + CommentGroup *docs, CommentGroup *comment) { Ast *result = alloc_ast_node(f, Ast_Field); result->Field.names = names; result->Field.type = type; result->Field.default_value = default_value; result->Field.flags = flags; + result->Field.tag = tag; result->Field.docs = docs; result->Field.comment = comment; return result; @@ -2740,7 +2741,8 @@ Ast *parse_results(AstFile *f, bool *diverging) { Array empty_names = {}; auto list = array_make(heap_allocator(), 0, 1); Ast *type = parse_type(f); - array_add(&list, ast_field(f, empty_names, type, nullptr, 0, nullptr, nullptr)); + Token tag = {}; + array_add(&list, ast_field(f, empty_names, type, nullptr, 0, tag, nullptr, nullptr)); return ast_field_list(f, begin_token, list); } @@ -3095,6 +3097,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi Ast *type = nullptr; Ast *default_value = nullptr; + Token tag = {}; expect_token_after(f, Token_Colon, "field list"); if (f->curr_token.kind != Token_Eq) { @@ -3132,16 +3135,25 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value"); } + if (type != nullptr && default_value == nullptr) { + if (f->curr_token.kind == Token_String) { + tag = expect_token(f, Token_String); + if ((allowed_flags & FieldFlag_Tags) == 0) { + syntax_error(tag, "Field tags are only allowed within structures"); + } + } + } + parse_expect_field_separator(f, type); - Ast *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment); + Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment); array_add(¶ms, param); while (f->curr_token.kind != follow && f->curr_token.kind != Token_EOF) { CommentGroup *docs = f->lead_comment; - u32 set_flags = parse_field_prefixes(f); + Token tag = {}; Array names = parse_ident_list(f, allow_poly_names); if (names.count == 0) { syntax_error(f->curr_token, "Empty field declaration"); @@ -3184,9 +3196,18 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value"); } + if (type != nullptr && default_value == nullptr) { + if (f->curr_token.kind == Token_String) { + tag = expect_token(f, Token_String); + if ((allowed_flags & FieldFlag_Tags) == 0) { + syntax_error(tag, "Field tags are only allowed within structures"); + } + } + } + bool ok = parse_expect_field_separator(f, param); - Ast *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment); + Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment); array_add(¶ms, param); if (!ok) { @@ -3210,8 +3231,8 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi token.pos = ast_token(type).pos; names[0] = ast_ident(f, token); u32 flags = check_field_prefixes(f, list.count, allowed_flags, list[i].flags); - - Ast *param = ast_field(f, names, list[i].node, nullptr, flags, docs, f->line_comment); + Token tag = {}; + Ast *param = ast_field(f, names, list[i].node, nullptr, flags, tag, docs, f->line_comment); array_add(¶ms, param); } diff --git a/src/parser.hpp b/src/parser.hpp index 9f4f68a7b..3489f1a9b 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -186,11 +186,12 @@ enum FieldFlag { FieldFlag_c_vararg = 1<<3, FieldFlag_auto_cast = 1<<4, + FieldFlag_Tags = 1<<10, FieldFlag_Results = 1<<16, FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast, - FieldFlag_Struct = FieldFlag_using, + FieldFlag_Struct = FieldFlag_using|FieldFlag_Tags, }; enum StmtAllowFlag { @@ -412,6 +413,7 @@ AST_KIND(_DeclEnd, "", bool) \ Array names; \ Ast * type; \ Ast * default_value; \ + Token tag; \ u32 flags; \ CommentGroup * docs; \ CommentGroup * comment; \ diff --git a/src/types.cpp b/src/types.cpp index e5d2509e0..1197ba974 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -107,6 +107,7 @@ struct BasicType { struct TypeStruct { Array fields; + Array tags; Ast *node; Scope * scope; -- cgit v1.2.3 From 7bc146e6fde909298a7184fdf00cec91868ffc00 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 26 Aug 2019 11:33:05 +0100 Subject: Built-in Quaternions (Not just an April Fool's Joke any more) --- core/fmt/fmt.odin | 29 +++++ core/reflect/reflect.odin | 2 + core/runtime/core.odin | 23 ++-- core/runtime/internal.odin | 70 +++++++++++- examples/demo/demo.odin | 60 +++++++++-- src/check_expr.cpp | 242 +++++++++++++++++++++++++++++++++++++++-- src/checker.cpp | 6 ++ src/checker_builtin_procs.hpp | 6 ++ src/exact_value.cpp | 184 +++++++++++++++++++++++++++++-- src/ir.cpp | 245 ++++++++++++++++++++++++++++++++++++++++-- src/ir_print.cpp | 53 +++++++-- src/tokenizer.cpp | 5 +- src/types.cpp | 50 +++++++-- 13 files changed, 909 insertions(+), 66 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 5dbebf972..a2f1166ac 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1129,6 +1129,7 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Rune: fmt_arg(fi, v, verb); case runtime.Type_Info_Float: fmt_arg(fi, v, verb); case runtime.Type_Info_Complex: fmt_arg(fi, v, verb); + case runtime.Type_Info_Quaternion: fmt_arg(fi, v, verb); case runtime.Type_Info_String: fmt_arg(fi, v, verb); case runtime.Type_Info_Pointer: @@ -1386,6 +1387,31 @@ fmt_complex :: proc(fi: ^Info, c: complex128, bits: int, verb: rune) { } } +fmt_quaternion :: proc(fi: ^Info, q: quaternion256, bits: int, verb: rune) { + switch verb { + case 'f', 'F', 'v', 'h', 'H': + r, i, j, k := real(q), imag(q), jmag(q), kmag(q); + + fmt_float(fi, r, bits/4, verb); + + if !fi.plus && i >= 0 do strings.write_rune(fi.buf, '+'); + fmt_float(fi, i, bits/4, verb); + strings.write_rune(fi.buf, 'i'); + + if !fi.plus && j >= 0 do strings.write_rune(fi.buf, '+'); + fmt_float(fi, j, bits/4, verb); + strings.write_rune(fi.buf, 'j'); + + if !fi.plus && k >= 0 do strings.write_rune(fi.buf, '+'); + fmt_float(fi, k, bits/4, verb); + strings.write_rune(fi.buf, 'k'); + + case: + fmt_bad_verb(fi, verb); + return; + } +} + fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { if arg == nil { strings.write_string(fi.buf, ""); @@ -1434,6 +1460,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { case complex64: fmt_complex(fi, complex128(a), 64, verb); case complex128: fmt_complex(fi, a, 128, verb); + case quaternion128: fmt_quaternion(fi, quaternion256(a), 128, verb); + case quaternion256: fmt_quaternion(fi, a, 256, verb); + case i8: fmt_int(fi, u64(a), true, 8, verb); case u8: fmt_int(fi, u64(a), false, 8, verb); case i16: fmt_int(fi, u64(a), true, 16, verb); diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index a4450490f..4bc9a2225 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -12,6 +12,7 @@ Type_Kind :: enum { Rune, Float, Complex, + Quaternion, String, Boolean, Any, @@ -42,6 +43,7 @@ type_kind :: proc(T: typeid) -> Type_Kind { case runtime.Type_Info_Rune: return .Rune; case runtime.Type_Info_Float: return .Float; case runtime.Type_Info_Complex: return .Complex; + case runtime.Type_Info_Quaternion: return .Quaternion; case runtime.Type_Info_String: return .String; case runtime.Type_Info_Boolean: return .Boolean; case runtime.Type_Info_Any: return .Any; diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 047281b10..022a84e9e 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -47,16 +47,17 @@ Type_Info_Endianness :: enum u8 { } // Variant Types -Type_Info_Named :: struct {name: string, base: ^Type_Info}; -Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness}; -Type_Info_Rune :: struct {}; -Type_Info_Float :: struct {}; -Type_Info_Complex :: struct {}; -Type_Info_String :: struct {is_cstring: bool}; -Type_Info_Boolean :: struct {}; -Type_Info_Any :: struct {}; -Type_Info_Type_Id :: struct {}; -Type_Info_Pointer :: struct { +Type_Info_Named :: struct {name: string, base: ^Type_Info}; +Type_Info_Integer :: struct {signed: bool, endianness: Type_Info_Endianness}; +Type_Info_Rune :: struct {}; +Type_Info_Float :: struct {}; +Type_Info_Complex :: struct {}; +Type_Info_Quaternion :: struct {}; +Type_Info_String :: struct {is_cstring: bool}; +Type_Info_Boolean :: struct {}; +Type_Info_Any :: struct {}; +Type_Info_Type_Id :: struct {}; +Type_Info_Pointer :: struct { elem: ^Type_Info // nil -> rawptr }; Type_Info_Procedure :: struct { @@ -135,6 +136,7 @@ Type_Info :: struct { Type_Info_Rune, Type_Info_Float, Type_Info_Complex, + Type_Info_Quaternion, Type_Info_String, Type_Info_Boolean, Type_Info_Any, @@ -163,6 +165,7 @@ Typeid_Kind :: enum u8 { Rune, Float, Complex, + Quaternion, String, Boolean, Any, diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index c33d5f62c..a5099944b 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -357,6 +357,11 @@ complex128_eq :: inline proc "contextless" (a, b: complex128) -> bool { return r complex128_ne :: inline proc "contextless" (a, b: complex128) -> bool { return real(a) != real(b) || imag(a) != imag(b); } +quaternion128_eq :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); } +quaternion128_ne :: inline proc "contextless" (a, b: quaternion128) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); } + +quaternion256_eq :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) == real(b) && imag(a) == imag(b) && jmag(a) == jmag(b) && kmag(a) == kmag(b); } +quaternion256_ne :: inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b); } bounds_check_error :: proc "contextless" (file: string, line, column: int, index, count: int) { @@ -546,9 +551,16 @@ abs_complex128 :: inline proc "contextless" (x: complex128) -> f64 { r, i := real(x), imag(x); return _sqrt_f64(r*r + i*i); } +abs_quaternion128 :: inline proc "contextless" (x: quaternion128) -> f32 { + r, i, j, k := real(x), imag(x), jmag(x), kmag(x); + return _sqrt_f32(r*r + i*i + j*j + k*k); +} +abs_quaternion256 :: inline proc "contextless" (x: quaternion256) -> f64 { + r, i, j, k := real(x), imag(x), jmag(x), kmag(x); + return _sqrt_f64(r*r + i*i + j*j + k*k); +} - -quo_complex64 :: proc(n, m: complex64) -> complex64 { +quo_complex64 :: proc "contextless" (n, m: complex64) -> complex64 { e, f: f32; if abs(real(m)) >= abs(imag(m)) { @@ -566,7 +578,7 @@ quo_complex64 :: proc(n, m: complex64) -> complex64 { return complex(e, f); } -quo_complex128 :: proc(n, m: complex128) -> complex128 { +quo_complex128 :: proc "contextless" (n, m: complex128) -> complex128 { e, f: f64; if abs(real(m)) >= abs(imag(m)) { @@ -583,3 +595,55 @@ quo_complex128 :: proc(n, m: complex128) -> complex128 { return complex(e, f); } + +mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { + q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q); + r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r); + + t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3; + t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2; + t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1; + t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0; + + return quaternion(t0, t1, t2, t3); +} + +mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { + q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q); + r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r); + + t0 := r0*q0 - r1*q1 - r2*q2 - r3*q3; + t1 := r0*q1 + r1*q0 - r2*q3 + r3*q2; + t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1; + t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0; + + return quaternion(t0, t1, t2, t3); +} + +quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { + q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q); + r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r); + + invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3); + + t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2; + t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2; + t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2; + t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2; + + return quaternion(t0, t1, t2, t3); +} + +quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { + q0, q1, q2, q3 := real(q), imag(q), jmag(q), kmag(q); + r0, r1, r2, r3 := real(r), imag(r), jmag(r), kmag(r); + + invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3); + + t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2; + t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2; + t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2; + t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2; + + return quaternion(t0, t1, t2, t3); +} diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 343c50ff7..a96056b61 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -326,7 +326,7 @@ union_type :: proc() { } parametric_polymorphism :: proc() { - fmt.println("# parametric_polymorphism"); + fmt.println("\n# parametric_polymorphism"); print_value :: proc(value: $T) { fmt.printf("print_value: %T %v\n", value, value); @@ -561,7 +561,7 @@ prefix_table := [?]string{ threading_example :: proc() { when os.OS == "windows" { - fmt.println("# threading_example"); + fmt.println("\n# threading_example"); worker_proc :: proc(t: ^thread.Thread) -> int { for iteration in 1..5 { @@ -601,7 +601,7 @@ threading_example :: proc() { } array_programming :: proc() { - fmt.println("# array_programming"); + fmt.println("\n# array_programming"); { a := [3]f32{1, 2, 3}; b := [3]f32{5, 6, 7}; @@ -646,7 +646,7 @@ array_programming :: proc() { } named_proc_return_parameters :: proc() { - fmt.println("# named proc return parameters"); + fmt.println("\n# named proc return parameters"); foo0 :: proc() -> int { return 123; @@ -668,7 +668,7 @@ named_proc_return_parameters :: proc() { using_enum :: proc() { - fmt.println("# using enum"); + fmt.println("\n# using enum"); using Foo :: enum {A, B, C}; @@ -680,7 +680,7 @@ using_enum :: proc() { } map_type :: proc() { - fmt.println("# map type"); + fmt.println("\n# map type"); // enums of type u16, u32, i16 & i32 also work Enum_u8 :: enum u8 { @@ -735,7 +735,7 @@ map_type :: proc() { } implicit_selector_expression :: proc() { - fmt.println("# implicit selector expression"); + fmt.println("\n# implicit selector expression"); Foo :: enum {A, B, C}; @@ -763,7 +763,7 @@ implicit_selector_expression :: proc() { } explicit_procedure_overloading :: proc() { - fmt.println("# explicit procedure overloading"); + fmt.println("\n# explicit procedure overloading"); add_ints :: proc(a, b: int) -> int { x := a + b; @@ -797,7 +797,7 @@ explicit_procedure_overloading :: proc() { } complete_switch :: proc() { - fmt.println("# complete_switch"); + fmt.println("\n# complete_switch"); { // enum using Foo :: enum { A, @@ -947,7 +947,7 @@ deferred_procedure_associations :: proc() { } reflection :: proc() { - fmt.println("# reflection"); + fmt.println("\n# reflection"); Foo :: struct { x: int `tag1`, @@ -981,6 +981,45 @@ reflection :: proc() { } } +quaternions :: proc() { + fmt.println("\n# quaternions"); + + { // Quaternion operations + q := 1 + 2i + 3j + 4k; + r := quaternion(5, 6, 7, 8); + t := q * r; + fmt.printf("(%v) * (%v) = %v\n", q, r, t); + v := q / r; + fmt.printf("(%v) / (%v) = %v\n", q, r, v); + u := q + r; + fmt.printf("(%v) + (%v) = %v\n", q, r, u); + s := q - r; + fmt.printf("(%v) - (%v) = %v\n", q, r, s); + } + { // The quaternion types + q128: quaternion128; // 4xf32 + q256: quaternion256; // 4xf64 + q128 = quaternion(1, 0, 0, 0); + q256 = 1; // quaternion(1, 0, 0, 0); + } + { // Built-in procedures + q := 1 + 2i + 3j + 4k; + fmt.println("q =", q); + fmt.println("real(q) =", real(q)); + fmt.println("imag(q) =", imag(q)); + fmt.println("jmag(q) =", jmag(q)); + fmt.println("kmag(q) =", kmag(q)); + fmt.println("conj(q) =", conj(q)); + fmt.println("abs(q) =", abs(q)); + } + { // Conversion of a complex type to a quaternion type + c := 1 + 2i; + q := quaternion256(c); + fmt.println(c); + fmt.println(q); + } +} + main :: proc() { when true { general_stuff(); @@ -1000,5 +1039,6 @@ main :: proc() { diverging_procedures(); deferred_procedure_associations(); reflection(); + quaternions(); } } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 24a130d62..6a9a53275 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -497,6 +497,14 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type if (is_type_complex(dst)) { return 1; } + if (is_type_quaternion(dst)) { + return 2; + } + break; + case Basic_UntypedQuaternion: + if (is_type_quaternion(dst)) { + return 1; + } break; } } @@ -1438,7 +1446,7 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ ExactValue imag = exact_value_imag(v); if (real.kind != ExactValue_Invalid && imag.kind != ExactValue_Invalid) { - if (out_value) *out_value = exact_binary_operator_value(Token_Add, real, exact_value_make_imag(imag)); + if (out_value) *out_value = exact_value_complex(exact_value_to_f64(real), exact_value_to_f64(imag)); return true; } break; @@ -1449,6 +1457,36 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ default: GB_PANIC("Compiler error: Unknown complex type!"); break; } + return false; + } else if (is_type_quaternion(type)) { + ExactValue v = exact_value_to_quaternion(in_value); + if (v.kind != ExactValue_Quaternion) { + return false; + } + + switch (type->Basic.kind) { + case Basic_quaternion128: + case Basic_quaternion256: { + ExactValue real = exact_value_real(v); + ExactValue imag = exact_value_imag(v); + ExactValue jmag = exact_value_jmag(v); + ExactValue kmag = exact_value_kmag(v); + if (real.kind != ExactValue_Invalid && + imag.kind != ExactValue_Invalid) { + if (out_value) *out_value = exact_value_quaternion(exact_value_to_f64(real), exact_value_to_f64(imag), exact_value_to_f64(jmag), exact_value_to_f64(kmag)); + return true; + } + break; + } + case Basic_UntypedComplex: + if (out_value) *out_value = exact_value_to_quaternion(*out_value); + return true; + case Basic_UntypedQuaternion: + return true; + + default: GB_PANIC("Compiler error: Unknown complex type!"); break; + } + return false; } else if (is_type_pointer(type)) { if (in_value.kind == ExactValue_Pointer) { @@ -1481,10 +1519,14 @@ void check_is_expressible(CheckerContext *c, Operand *o, Type *type) { if (!is_type_integer(o->type) && is_type_integer(type)) { error(o->expr, "'%s' truncated to '%s'", a, b); } else { + #if 0 gbAllocator ha = heap_allocator(); String str = big_int_to_string(ha, &o->value.value_integer); defer (gb_free(ha, str.text)); error(o->expr, "'%s = %.*s' overflows '%s'", a, LIT(str), b); + #else + error(o->expr, "Cannot convert '%s' to '%s'", a, b); + #endif } } else { error(o->expr, "Cannot convert '%s' to '%s'", a, b); @@ -1759,6 +1801,21 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) { } break; } + } else if (is_type_quaternion(x->type) || is_type_quaternion(y->type)) { + switch (op) { + case Token_CmpEq: + switch (8*size) { + case 128: add_package_dependency(c, "runtime", "quaternion128_eq"); break; + case 256: add_package_dependency(c, "runtime", "quaternion256_eq"); break; + } + break; + case Token_NotEq: + switch (8*size) { + case 128: add_package_dependency(c, "runtime", "quaternion128_ne"); break; + case 256: add_package_dependency(c, "runtime", "quaternion256_ne"); break; + } + break; + } } } @@ -1978,6 +2035,14 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { return true; } + if (is_type_complex(src) && is_type_quaternion(dst)) { + return true; + } + + if (is_type_quaternion(src) && is_type_quaternion(dst)) { + return true; + } + if (is_type_bit_field_value(src) && is_type_integer(dst)) { return true; } @@ -2557,6 +2622,8 @@ ExactValue convert_exact_value_for_type(ExactValue v, Type *type) { v = exact_value_to_integer(v); } else if (is_type_complex(t)) { v = exact_value_to_complex(v); + } else if (is_type_quaternion(t)) { + v = exact_value_to_quaternion(v); } return v; } @@ -2652,6 +2719,7 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { case Basic_UntypedInteger: case Basic_UntypedFloat: case Basic_UntypedComplex: + case Basic_UntypedQuaternion: case Basic_UntypedRune: if (!is_type_numeric(target_type)) { operand->mode = Addressing_Invalid; @@ -3769,10 +3837,98 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } + case BuiltinProc_quaternion: { + // quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type + Operand x = *operand; + Operand y = {}; + Operand z = {}; + Operand w = {}; + + // NOTE(bill): Invalid will be the default till fixed + operand->type = t_invalid; + operand->mode = Addressing_Invalid; + + check_expr(c, &y, ce->args[1]); + if (y.mode == Addressing_Invalid) { + return false; + } + check_expr(c, &z, ce->args[2]); + if (y.mode == Addressing_Invalid) { + return false; + } + check_expr(c, &w, ce->args[3]); + if (y.mode == Addressing_Invalid) { + return false; + } + + convert_to_typed(c, &x, y.type); if (x.mode == Addressing_Invalid) return false; + convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false; + convert_to_typed(c, &z, x.type); if (z.mode == Addressing_Invalid) return false; + convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false; + if (x.mode == Addressing_Constant && + y.mode == Addressing_Constant && + z.mode == Addressing_Constant && + w.mode == Addressing_Constant) { + if (is_type_numeric(x.type) && exact_value_imag(x.value).value_float == 0) { + x.type = t_untyped_float; + } + if (is_type_numeric(y.type) && exact_value_imag(y.value).value_float == 0) { + y.type = t_untyped_float; + } + if (is_type_numeric(z.type) && exact_value_imag(z.value).value_float == 0) { + z.type = t_untyped_float; + } + if (is_type_numeric(w.type) && exact_value_imag(w.value).value_float == 0) { + w.type = t_untyped_float; + } + } + + if (!(are_types_identical(x.type, y.type) && are_types_identical(x.type, z.type) && are_types_identical(x.type, w.type))) { + gbString tx = type_to_string(x.type); + gbString ty = type_to_string(y.type); + gbString tz = type_to_string(z.type); + gbString tw = type_to_string(w.type); + error(call, "Mismatched types to 'quaternion', '%s' vs '%s' vs '%s' vs '%s'", tx, ty, tz, tw); + gb_string_free(tw); + gb_string_free(tz); + gb_string_free(ty); + gb_string_free(tx); + return false; + } + + if (!is_type_float(x.type)) { + gbString s = type_to_string(x.type); + error(call, "Arguments have type '%s', expected a floating point", s); + gb_string_free(s); + return false; + } + + if (x.mode == Addressing_Constant && y.mode == Addressing_Constant && z.mode == Addressing_Constant && w.mode == Addressing_Constant) { + f64 r = exact_value_to_float(x.value).value_float; + f64 i = exact_value_to_float(y.value).value_float; + f64 j = exact_value_to_float(z.value).value_float; + f64 k = exact_value_to_float(w.value).value_float; + operand->value = exact_value_quaternion(r, i, j, k); + operand->mode = Addressing_Constant; + } else { + operand->mode = Addressing_Value; + } + + BasicKind kind = core_type(x.type)->Basic.kind; + switch (kind) { + case Basic_f32: operand->type = t_quaternion128; break; + case Basic_f64: operand->type = t_quaternion256; break; + case Basic_UntypedFloat: operand->type = t_untyped_quaternion; break; + default: GB_PANIC("Invalid type"); break; + } + + break; + } + case BuiltinProc_real: case BuiltinProc_imag: { // real :: proc(x: type) -> float_type - // proc imag(x: type) -> float_type + // imag :: proc(x: type) -> float_type Operand *x = operand; if (is_type_untyped(x->type)) { @@ -3780,7 +3936,12 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (is_type_numeric(x->type)) { x->type = t_untyped_complex; } - } else { + } else if (is_type_quaternion(x->type)) { + convert_to_typed(c, x, t_quaternion256); + if (x->mode == Addressing_Invalid) { + return false; + } + } else{ convert_to_typed(c, x, t_complex128); if (x->mode == Addressing_Invalid) { return false; @@ -3788,9 +3949,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } } - if (!is_type_complex(x->type)) { + if (!is_type_complex(x->type) && !is_type_quaternion(x->type)) { gbString s = type_to_string(x->type); - error(call, "Argument has type '%s', expected a complex type", s); + error(call, "Argument has type '%s', expected a complex or quaternion type", s); gb_string_free(s); return false; } @@ -3808,7 +3969,57 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 switch (kind) { case Basic_complex64: x->type = t_f32; break; case Basic_complex128: x->type = t_f64; break; + case Basic_quaternion128: x->type = t_f32; break; + case Basic_quaternion256: x->type = t_f64; break; case Basic_UntypedComplex: x->type = t_untyped_float; break; + case Basic_UntypedQuaternion: x->type = t_untyped_float; break; + default: GB_PANIC("Invalid type"); break; + } + + break; + } + + case BuiltinProc_jmag: + case BuiltinProc_kmag: { + // jmag :: proc(x: type) -> float_type + // kmag :: proc(x: type) -> float_type + + Operand *x = operand; + if (is_type_untyped(x->type)) { + if (x->mode == Addressing_Constant) { + if (is_type_numeric(x->type)) { + x->type = t_untyped_complex; + } + } else{ + convert_to_typed(c, x, t_quaternion256); + if (x->mode == Addressing_Invalid) { + return false; + } + } + } + + if (!is_type_quaternion(x->type)) { + gbString s = type_to_string(x->type); + error(call, "Argument has type '%s', expected a quaternion type", s); + gb_string_free(s); + return false; + } + + if (x->mode == Addressing_Constant) { + switch (id) { + case BuiltinProc_jmag: x->value = exact_value_jmag(x->value); break; + case BuiltinProc_kmag: x->value = exact_value_kmag(x->value); break; + } + } else { + x->mode = Addressing_Value; + } + + BasicKind kind = core_type(x->type)->Basic.kind; + switch (kind) { + case Basic_quaternion128: x->type = t_f32; break; + case Basic_quaternion256: x->type = t_f64; break; + case Basic_UntypedComplex: x->type = t_untyped_float; break; + case Basic_UntypedQuaternion: x->type = t_untyped_float; break; default: GB_PANIC("Invalid type"); break; } @@ -3822,12 +4033,24 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (x->mode == Addressing_Constant) { ExactValue v = exact_value_to_complex(x->value); f64 r = v.value_complex.real; - f64 i = v.value_complex.imag; + f64 i = -v.value_complex.imag; x->value = exact_value_complex(r, i); x->mode = Addressing_Constant; } else { x->mode = Addressing_Value; } + } else if (is_type_quaternion(x->type)) { + if (x->mode == Addressing_Constant) { + ExactValue v = exact_value_to_quaternion(x->value); + f64 r = v.value_quaternion.real; + f64 i = -v.value_quaternion.imag; + f64 j = -v.value_quaternion.jmag; + f64 k = -v.value_quaternion.kmag; + x->value = exact_value_quaternion(r, i, j, k); + x->mode = Addressing_Constant; + } else { + x->mode = Addressing_Value; + } } else { gbString s = type_to_string(x->type); error(call, "Expected a complex or quaternion, got '%s'", s); @@ -4226,6 +4449,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (are_types_identical(bt, t_f64)) add_package_dependency(c, "runtime", "abs_f64"); if (are_types_identical(bt, t_complex64)) add_package_dependency(c, "runtime", "abs_complex64"); if (are_types_identical(bt, t_complex128)) add_package_dependency(c, "runtime", "abs_complex128"); + if (are_types_identical(bt, t_quaternion128)) add_package_dependency(c, "runtime", "abs_quaternion128"); + if (are_types_identical(bt, t_quaternion256)) add_package_dependency(c, "runtime", "abs_quaternion256"); } } @@ -6232,8 +6457,11 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case Token_Imag: { String s = bl->token.string; Rune r = s[s.len-1]; + // NOTE(bill, 2019-08-25): Allow for quaternions by having j and k imaginary numbers switch (r) { - case 'i': t = t_untyped_complex; break; + case 'i': t = t_untyped_complex; break; + case 'j': t = t_untyped_quaternion; break; + case 'k': t = t_untyped_quaternion; break; } break; diff --git a/src/checker.cpp b/src/checker.cpp index 45b661a58..d6f5ad402 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1610,6 +1610,10 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("quo_complex64"), str_lit("quo_complex128"), + str_lit("mul_quaternion128"), + str_lit("mul_quaternion256"), + str_lit("quo_quaternion128"), + str_lit("quo_quaternion256"), str_lit("umodti3"), str_lit("udivti3"), @@ -1891,6 +1895,7 @@ void init_core_type_info(Checker *c) { t_type_info_integer = find_core_type(c, str_lit("Type_Info_Integer")); t_type_info_rune = find_core_type(c, str_lit("Type_Info_Rune")); t_type_info_float = find_core_type(c, str_lit("Type_Info_Float")); + t_type_info_quaternion = find_core_type(c, str_lit("Type_Info_Quaternion")); t_type_info_complex = find_core_type(c, str_lit("Type_Info_Complex")); t_type_info_string = find_core_type(c, str_lit("Type_Info_String")); t_type_info_boolean = find_core_type(c, str_lit("Type_Info_Boolean")); @@ -1915,6 +1920,7 @@ void init_core_type_info(Checker *c) { t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer); t_type_info_rune_ptr = alloc_type_pointer(t_type_info_rune); t_type_info_float_ptr = alloc_type_pointer(t_type_info_float); + t_type_info_quaternion_ptr = alloc_type_pointer(t_type_info_quaternion); t_type_info_complex_ptr = alloc_type_pointer(t_type_info_complex); t_type_info_string_ptr = alloc_type_pointer(t_type_info_string); t_type_info_boolean_ptr = alloc_type_pointer(t_type_info_boolean); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 536d47616..0135b3c50 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -16,8 +16,11 @@ enum BuiltinProcId { BuiltinProc_swizzle, BuiltinProc_complex, + BuiltinProc_quaternion, BuiltinProc_real, BuiltinProc_imag, + BuiltinProc_jmag, + BuiltinProc_kmag, BuiltinProc_conj, BuiltinProc_expand_to_tuple, @@ -172,8 +175,11 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("swizzle"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("complex"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("quaternion"), 4, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("real"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("imag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("jmag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("kmag"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("expand_to_tuple"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 520812e44..54d4ef6f2 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -12,6 +12,19 @@ bool are_types_identical(Type *x, Type *y); struct Complex128 { f64 real, imag; }; +struct Quaternion256 { + f64 imag, jmag, kmag, real; +}; + +Quaternion256 quaternion256_inverse(Quaternion256 x) { + f64 invmag2 = 1.0 / (x.real*x.real + x.imag*x.imag + x.jmag*x.jmag + x.kmag*x.kmag); + x.real = +x.real * invmag2; + x.imag = -x.imag * invmag2; + x.jmag = -x.jmag * invmag2; + x.kmag = -x.kmag * invmag2; + return x; +} + enum ExactValueKind { ExactValue_Invalid, @@ -21,6 +34,7 @@ enum ExactValueKind { ExactValue_Integer, ExactValue_Float, ExactValue_Complex, + ExactValue_Quaternion, ExactValue_Pointer, ExactValue_Compound, // TODO(bill): Is this good enough? ExactValue_Procedure, // TODO(bill): Is this good enough? @@ -37,6 +51,7 @@ struct ExactValue { f64 value_float; i64 value_pointer; Complex128 value_complex; + Quaternion256 value_quaternion; Ast * value_compound; Ast * value_procedure; }; @@ -61,7 +76,8 @@ HashKey hash_exact_value(ExactValue v) { return hash_integer(v.value_pointer); case ExactValue_Complex: return hashing_proc(&v.value_complex, gb_size_of(Complex128)); - + case ExactValue_Quaternion: + return hashing_proc(&v.value_quaternion, gb_size_of(Quaternion256)); case ExactValue_Compound: return hash_pointer(v.value_compound); case ExactValue_Procedure: @@ -116,6 +132,15 @@ ExactValue exact_value_complex(f64 real, f64 imag) { return result; } +ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) { + ExactValue result = {ExactValue_Quaternion}; + result.value_quaternion.real = real; + result.value_quaternion.imag = imag; + result.value_quaternion.jmag = jmag; + result.value_quaternion.kmag = kmag; + return result; +} + ExactValue exact_value_pointer(i64 ptr) { ExactValue result = {ExactValue_Pointer}; result.value_pointer = ptr; @@ -253,8 +278,10 @@ ExactValue exact_value_from_basic_literal(Token token) { str.len--; // Ignore the 'i|j|k' f64 imag = float_from_string(str); - if (last_rune == 'i') { - return exact_value_complex(0, imag); + switch (last_rune) { + case 'i': return exact_value_complex(0, imag); + case 'j': return exact_value_quaternion(0, 0, imag, 0); + case 'k': return exact_value_quaternion(0, 0, 0, imag); } } case Token_Rune: { @@ -318,11 +345,26 @@ ExactValue exact_value_to_complex(ExactValue v) { return exact_value_complex(v.value_float, 0); case ExactValue_Complex: return v; + // case ExactValue_Quaternion: + // return exact_value_complex(v.value_quaternion.real, v.value_quaternion.imag); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} +ExactValue exact_value_to_quaternion(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + return exact_value_quaternion(big_int_to_f64(&v.value_integer), 0, 0, 0); + case ExactValue_Float: + return exact_value_quaternion(v.value_float, 0, 0, 0); + case ExactValue_Complex: + return exact_value_quaternion(v.value_complex.real, v.value_complex.imag, 0, 0); + case ExactValue_Quaternion: + return v; } ExactValue r = {ExactValue_Invalid}; return r; } - ExactValue exact_value_real(ExactValue v) { switch (v.kind) { @@ -331,6 +373,8 @@ ExactValue exact_value_real(ExactValue v) { return v; case ExactValue_Complex: return exact_value_float(v.value_complex.real); + case ExactValue_Quaternion: + return exact_value_float(v.value_quaternion.real); } ExactValue r = {ExactValue_Invalid}; return r; @@ -343,6 +387,34 @@ ExactValue exact_value_imag(ExactValue v) { return exact_value_i64(0); case ExactValue_Complex: return exact_value_float(v.value_complex.imag); + case ExactValue_Quaternion: + return exact_value_float(v.value_quaternion.imag); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} + +ExactValue exact_value_jmag(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + case ExactValue_Float: + case ExactValue_Complex: + return exact_value_i64(0); + case ExactValue_Quaternion: + return exact_value_float(v.value_quaternion.jmag); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} + +ExactValue exact_value_kmag(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + case ExactValue_Float: + case ExactValue_Complex: + return exact_value_i64(0); + case ExactValue_Quaternion: + return exact_value_float(v.value_quaternion.kmag); } ExactValue r = {ExactValue_Invalid}; return r; @@ -361,6 +433,32 @@ ExactValue exact_value_make_imag(ExactValue v) { return r; } +ExactValue exact_value_make_jmag(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0); + case ExactValue_Float: + return exact_value_quaternion(0, 0, v.value_float, 0); + default: + GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'"); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} + +ExactValue exact_value_make_kmag(ExactValue v) { + switch (v.kind) { + case ExactValue_Integer: + return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float); + case ExactValue_Float: + return exact_value_quaternion(0, 0, 0, v.value_float); + default: + GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'"); + } + ExactValue r = {ExactValue_Invalid}; + return r; +} + i64 exact_value_to_i64(ExactValue v) { v = exact_value_to_integer(v); if (v.kind == ExactValue_Integer) { @@ -389,6 +487,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision, case ExactValue_Integer: case ExactValue_Float: case ExactValue_Complex: + case ExactValue_Quaternion: return v; } break; @@ -413,6 +512,13 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision, f64 imag = v.value_complex.imag; return exact_value_complex(-real, -imag); } + case ExactValue_Quaternion: { + f64 real = v.value_quaternion.real; + f64 imag = v.value_quaternion.imag; + f64 jmag = v.value_quaternion.jmag; + f64 kmag = v.value_quaternion.kmag; + return exact_value_quaternion(-real, -imag, -jmag, -kmag); + } } break; } @@ -463,8 +569,10 @@ i32 exact_value_order(ExactValue const &v) { return 3; case ExactValue_Complex: return 4; - case ExactValue_Pointer: + case ExactValue_Quaternion: return 5; + case ExactValue_Pointer: + return 6; default: GB_PANIC("How'd you get here? Invalid Value.kind"); @@ -485,7 +593,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) { case ExactValue_Bool: case ExactValue_String: - case ExactValue_Complex: + case ExactValue_Quaternion: return; case ExactValue_Integer: @@ -499,6 +607,9 @@ void match_exact_values(ExactValue *x, ExactValue *y) { case ExactValue_Complex: *x = exact_value_complex(big_int_to_f64(&x->value_integer), 0); return; + case ExactValue_Quaternion: + *x = exact_value_quaternion(big_int_to_f64(&x->value_integer), 0, 0, 0); + return; } break; @@ -509,6 +620,17 @@ void match_exact_values(ExactValue *x, ExactValue *y) { case ExactValue_Complex: *x = exact_value_to_complex(*x); return; + case ExactValue_Quaternion: + *x = exact_value_to_quaternion(*x); + return; + } + break; + + case ExactValue_Complex: + switch (y->kind) { + case ExactValue_Quaternion: + *x = exact_value_to_quaternion(*x); + return; } break; } @@ -606,6 +728,56 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) break; } + case ExactValue_Quaternion: { + y = exact_value_to_quaternion(y); + f64 xr = x.value_quaternion.real; + f64 xi = x.value_quaternion.imag; + f64 xj = x.value_quaternion.jmag; + f64 xk = x.value_quaternion.kmag; + f64 yr = y.value_quaternion.real; + f64 yi = y.value_quaternion.imag; + f64 yj = y.value_quaternion.jmag; + f64 yk = y.value_quaternion.kmag; + + + f64 real = 0; + f64 imag = 0; + f64 jmag = 0; + f64 kmag = 0; + + switch (op) { + case Token_Add: + real = xr + yr; + imag = xi + yi; + jmag = xj + yj; + kmag = xk + yk; + break; + case Token_Sub: + real = xr - yr; + imag = xi - yi; + jmag = xj - yj; + kmag = xk - yk; + break; + case Token_Mul: + imag = xr * yi + xi * yr + xj * yk - xk * yj; + jmag = xr * yj - xi * yk + xj * yr + xk * yi; + kmag = xr * yk + xi * yj - xj * yi + xk * yr; + real = xr * yr - xi * yi - xj * yj - xk * yk; + break; + case Token_Quo: { + f64 invmag2 = 1.0 / (yr*yr + yi*yi + yj*yj + yk*yk); + imag = (xr * -yi + xi * +yr + xj * -yk - xk * -yj) * invmag2; + jmag = (xr * -yj - xi * -yk + xj * +yr + xk * -yi) * invmag2; + kmag = (xr * -yk + xi * -yj - xj * -yi + xk * +yr) * invmag2; + real = (xr * +yr - xi * -yi - xj * -yj - xk * -yk) * invmag2; + break; + } + default: goto error; + } + return exact_value_quaternion(real, imag, jmag, kmag); + break; + } + case ExactValue_String: { if (op != Token_Add) goto error; diff --git a/src/ir.cpp b/src/ir.cpp index 2499b848f..2a4bb028b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3853,6 +3853,60 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * return ir_emit_load(proc, res); } + if (is_type_quaternion(t_left)) { + ir_emit_comment(proc, str_lit("complex.arith.begin")); + defer (ir_emit_comment(proc, str_lit("complex.arith.end"))); + + right = ir_emit_conv(proc, right, t_left); + + Type *ft = base_complex_elem_type(t_left); + + if (op == Token_Add || op == Token_Sub) { + irValue *res = ir_add_local_generated(proc, type, false); // NOTE: initialized in full later + irValue *x0 = ir_emit_struct_ev(proc, left, 0); + irValue *x1 = ir_emit_struct_ev(proc, left, 1); + irValue *x2 = ir_emit_struct_ev(proc, left, 2); + irValue *x3 = ir_emit_struct_ev(proc, left, 3); + + irValue *y0 = ir_emit_struct_ev(proc, right, 0); + irValue *y1 = ir_emit_struct_ev(proc, right, 1); + irValue *y2 = ir_emit_struct_ev(proc, right, 2); + irValue *y3 = ir_emit_struct_ev(proc, right, 3); + + irValue *z0 = ir_emit_arith(proc, op, x0, y0, ft); + irValue *z1 = ir_emit_arith(proc, op, x1, y1, ft); + irValue *z2 = ir_emit_arith(proc, op, x2, y2, ft); + irValue *z3 = ir_emit_arith(proc, op, x3, y3, ft); + + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), z0); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), z1); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), z2); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), z3); + + return ir_emit_load(proc, res); + } else if (op == Token_Mul) { + auto args = array_make(heap_allocator(), 2); + args[0] = left; + args[1] = right; + + switch (8*type_size_of(ft)) { + case 32: return ir_emit_runtime_call(proc, "mul_quaternion128", args); + case 64: return ir_emit_runtime_call(proc, "mul_quaternion256", args); + default: GB_PANIC("Unknown float type"); break; + } + } else if (op == Token_Quo) { + auto args = array_make(heap_allocator(), 2); + args[0] = left; + args[1] = right; + + switch (8*type_size_of(ft)) { + case 32: return ir_emit_runtime_call(proc, "quo_quaternion128", args); + case 64: return ir_emit_runtime_call(proc, "quo_quaternion256", args); + default: GB_PANIC("Unknown float type"); break; + } + } + } + #if 0 if (op == Token_Add) { @@ -4188,7 +4242,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal } if (is_type_complex(a)) { - char *runtime_proc = ""; + char const *runtime_proc = ""; i64 sz = 8*type_size_of(a); switch (sz) { case 64: @@ -4212,6 +4266,31 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal return ir_emit_runtime_call(proc, runtime_proc, args); } + if (is_type_quaternion(a)) { + char const *runtime_proc = ""; + i64 sz = 8*type_size_of(a); + switch (sz) { + case 128: + switch (op_kind) { + case Token_CmpEq: runtime_proc = "quaternion128_eq"; break; + case Token_NotEq: runtime_proc = "quaternion128_ne"; break; + } + break; + case 256: + switch (op_kind) { + case Token_CmpEq: runtime_proc = "quaternion256_eq"; break; + case Token_NotEq: runtime_proc = "quaternion256_ne"; break; + } + break; + } + GB_ASSERT(runtime_proc != nullptr); + + auto args = array_make(ir_allocator(), 2); + args[0] = left; + args[1] = right; + return ir_emit_runtime_call(proc, runtime_proc, args); + } + if (is_type_bit_set(a)) { switch (op_kind) { case Token_Lt: @@ -4295,11 +4374,18 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) { case 0: result_type = alloc_type_pointer(ft); break; case 1: result_type = alloc_type_pointer(ft); break; } + } else if (is_type_quaternion(t)) { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = alloc_type_pointer(ft); break; + case 1: result_type = alloc_type_pointer(ft); break; + case 2: result_type = alloc_type_pointer(ft); break; + case 3: result_type = alloc_type_pointer(ft); break; + } } else if (is_type_slice(t)) { switch (index) { case 0: result_type = alloc_type_pointer(alloc_type_pointer(t->Slice.elem)); break; case 1: result_type = alloc_type_pointer(t_int); break; - case 2: result_type = alloc_type_pointer(t_int); break; } } else if (is_type_string(t)) { switch (index) { @@ -4370,6 +4456,17 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) { } break; } + case Basic_quaternion128: case Basic_quaternion256: + { + Type *ft = base_complex_elem_type(t); + switch (index) { + case 0: result_type = ft; break; + case 1: result_type = ft; break; + case 2: result_type = ft; break; + case 3: result_type = ft; break; + } + break; + } } break; case Type_Struct: @@ -4752,6 +4849,8 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { ev = exact_value_to_float(ev); } else if (is_type_complex(dst)) { ev = exact_value_to_complex(ev); + } else if (is_type_quaternion(dst)) { + ev = exact_value_to_quaternion(ev); } else if (is_type_string(dst)) { // Handled elsewhere GB_ASSERT_MSG(ev.kind == ExactValue_String, "%d", ev.kind); @@ -4875,6 +4974,49 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { return ir_emit_load(proc, gen); } + if (is_type_quaternion(src) && is_type_quaternion(dst)) { + // @QuaternionLayout + Type *ft = base_complex_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst, false); + irValue *q0 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 0), ft); + irValue *q1 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 1), ft); + irValue *q2 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 2), ft); + irValue *q3 = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 3), ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), q0); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 1), q1); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 2), q2); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), q3); + return ir_emit_load(proc, gen); + } + + if (is_type_float(src) && is_type_complex(dst)) { + Type *ft = base_complex_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst, true); + irValue *real = ir_emit_conv(proc, value, ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), real); + return ir_emit_load(proc, gen); + } + if (is_type_float(src) && is_type_quaternion(dst)) { + Type *ft = base_complex_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst, true); + irValue *real = ir_emit_conv(proc, value, ft); + // @QuaternionLayout + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), real); + return ir_emit_load(proc, gen); + } + if (is_type_complex(src) && is_type_quaternion(dst)) { + Type *ft = base_complex_elem_type(dst); + irValue *gen = ir_add_local_generated(proc, dst, true); + irValue *real = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 0), ft); + irValue *imag = ir_emit_conv(proc, ir_emit_struct_ev(proc, value, 1), ft); + // @QuaternionLayout + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 3), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, gen, 0), imag); + return ir_emit_load(proc, gen); + } + + + // float <-> integer if (is_type_float(src) && is_type_integer(dst)) { irConvKind kind = irConv_fptosi; @@ -5315,6 +5457,7 @@ enum Typeid_Kind : u8 { Typeid_Rune, Typeid_Float, Typeid_Complex, + Typeid_Quaternion, Typeid_String, Typeid_Boolean, Typeid_Any, @@ -6067,17 +6210,77 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu return ir_emit_load(proc, dst); } + case BuiltinProc_quaternion: { + ir_emit_comment(proc, str_lit("quaternion")); + irValue *real = ir_build_expr(proc, ce->args[0]); + irValue *imag = ir_build_expr(proc, ce->args[1]); + irValue *jmag = ir_build_expr(proc, ce->args[2]); + irValue *kmag = ir_build_expr(proc, ce->args[3]); + + // @QuaternionLayout + irValue *dst = ir_add_local_generated(proc, tv.type, false); + Type *ft = base_complex_elem_type(tv.type); + real = ir_emit_conv(proc, real, ft); + imag = ir_emit_conv(proc, imag, ft); + jmag = ir_emit_conv(proc, jmag, ft); + kmag = ir_emit_conv(proc, kmag, ft); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 3), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 0), imag); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 1), jmag); + ir_emit_store(proc, ir_emit_struct_ep(proc, dst, 2), kmag); + + return ir_emit_load(proc, dst); + } + case BuiltinProc_real: { ir_emit_comment(proc, str_lit("real")); irValue *val = ir_build_expr(proc, ce->args[0]); - irValue *real = ir_emit_struct_ev(proc, val, 0); - return ir_emit_conv(proc, real, tv.type); + if (is_type_complex(ir_type(val))) { + irValue *real = ir_emit_struct_ev(proc, val, 0); + return ir_emit_conv(proc, real, tv.type); + } else if (is_type_quaternion(ir_type(val))) { + // @QuaternionLayout + irValue *real = ir_emit_struct_ev(proc, val, 3); + return ir_emit_conv(proc, real, tv.type); + } + GB_PANIC("invalid type for real"); + return nullptr; } case BuiltinProc_imag: { ir_emit_comment(proc, str_lit("imag")); irValue *val = ir_build_expr(proc, ce->args[0]); - irValue *imag = ir_emit_struct_ev(proc, val, 1); - return ir_emit_conv(proc, imag, tv.type); + if (is_type_complex(ir_type(val))) { + irValue *imag = ir_emit_struct_ev(proc, val, 1); + return ir_emit_conv(proc, imag, tv.type); + } else if (is_type_quaternion(ir_type(val))) { + // @QuaternionLayout + irValue *imag = ir_emit_struct_ev(proc, val, 0); + return ir_emit_conv(proc, imag, tv.type); + } + GB_PANIC("invalid type for imag"); + return nullptr; + } + case BuiltinProc_jmag: { + ir_emit_comment(proc, str_lit("jmag")); + irValue *val = ir_build_expr(proc, ce->args[0]); + if (is_type_quaternion(ir_type(val))) { + // @QuaternionLayout + irValue *imag = ir_emit_struct_ev(proc, val, 1); + return ir_emit_conv(proc, imag, tv.type); + } + GB_PANIC("invalid type for jmag"); + return nullptr; + } + case BuiltinProc_kmag: { + ir_emit_comment(proc, str_lit("kmag")); + irValue *val = ir_build_expr(proc, ce->args[0]); + if (is_type_quaternion(ir_type(val))) { + // @QuaternionLayout + irValue *imag = ir_emit_struct_ev(proc, val, 2); + return ir_emit_conv(proc, imag, tv.type); + } + GB_PANIC("invalid type for kmag"); + return nullptr; } case BuiltinProc_conj: { @@ -6092,6 +6295,20 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag)); ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), real); ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), imag); + } else if (is_type_quaternion(t)) { + // @QuaternionLayout + res = ir_add_local_generated(proc, tv.type, false); + irValue *real = ir_emit_struct_ev(proc, val, 3); + irValue *imag = ir_emit_struct_ev(proc, val, 0); + irValue *jmag = ir_emit_struct_ev(proc, val, 1); + irValue *kmag = ir_emit_struct_ev(proc, val, 2); + imag = ir_emit_unary_arith(proc, Token_Sub, imag, ir_type(imag)); + jmag = ir_emit_unary_arith(proc, Token_Sub, jmag, ir_type(jmag)); + kmag = ir_emit_unary_arith(proc, Token_Sub, kmag, ir_type(kmag)); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 3), real); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 0), imag); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 1), jmag); + ir_emit_store(proc, ir_emit_struct_ep(proc, res, 2), kmag); } return ir_emit_load(proc, res); } @@ -6162,7 +6379,16 @@ irValue *ir_build_builtin_proc(irProcedure *proc, Ast *expr, TypeAndValue tv, Bu return x; } ir_emit_comment(proc, str_lit("abs")); - if (is_type_complex(t)) { + if (is_type_quaternion(t)) { + i64 sz = 8*type_size_of(t); + auto args = array_make(ir_allocator(), 1); + args[0] = x; + switch (sz) { + case 128: return ir_emit_runtime_call(proc, "abs_quaternion128", args); + case 256: return ir_emit_runtime_call(proc, "abs_quaternion256", args); + } + GB_PANIC("Unknown complex type"); + } else if (is_type_complex(t)) { i64 sz = 8*type_size_of(t); auto args = array_make(ir_allocator(), 1); args[0] = x; @@ -9876,6 +10102,11 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info tag = ir_emit_conv(proc, variant_ptr, t_type_info_complex_ptr); break; + case Basic_quaternion128: + case Basic_quaternion256: + tag = ir_emit_conv(proc, variant_ptr, t_type_info_quaternion_ptr); + break; + case Basic_rawptr: tag = ir_emit_conv(proc, variant_ptr, t_type_info_pointer_ptr); break; diff --git a/src/ir_print.cpp b/src/ir_print.cpp index c1e41c4b0..30ad914a9 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -418,20 +418,23 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) { } return; - // case Basic_f16: ir_write_str_lit(f, "half"); return; - case Basic_f32: ir_write_str_lit(f, "float"); return; - case Basic_f64: ir_write_str_lit(f, "double"); return; + // case Basic_f16: ir_write_str_lit(f, "half"); return; + case Basic_f32: ir_write_str_lit(f, "float"); return; + case Basic_f64: ir_write_str_lit(f, "double"); return; - // case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return; - case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return; - case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return; + // case Basic_complex32: ir_write_str_lit(f, "%%..complex32"); return; + case Basic_complex64: ir_write_str_lit(f, "%..complex64"); return; + case Basic_complex128: ir_write_str_lit(f, "%..complex128"); return; - case Basic_any: ir_write_str_lit(f, "%..any"); return; - case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return; - case Basic_string: ir_write_str_lit(f, "%..string"); return; - case Basic_cstring: ir_write_str_lit(f, "i8*"); return; + case Basic_quaternion128: ir_write_str_lit(f, "%..quaternion128"); return; + case Basic_quaternion256: ir_write_str_lit(f, "%..quaternion256"); return; - case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return; + case Basic_any: ir_write_str_lit(f, "%..any"); return; + case Basic_rawptr: ir_write_str_lit(f, "%..rawptr"); return; + case Basic_string: ir_write_str_lit(f, "%..string"); return; + case Basic_cstring: ir_write_str_lit(f, "i8*"); return; + + case Basic_typeid: ir_write_str_lit(f, "%..typeid"); return; } break; @@ -811,6 +814,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * break; } case ExactValue_Complex: { + // xy/ri format type = core_type(type); GB_ASSERT_MSG(is_type_complex(type), "%s", type_to_string(type)); Type *ft = base_complex_elem_type(type); @@ -823,6 +827,26 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ir_write_byte(f, '}'); break; } + + case ExactValue_Quaternion: { + // xyzw/ijkr format + type = core_type(type); + GB_ASSERT_MSG(is_type_quaternion(type), "%s", type_to_string(type)); + Type *ft = base_complex_elem_type(type); + ir_write_byte(f, ' '); + ir_write_byte(f, '{'); + ir_print_type(f, m, ft); ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.imag), ft); + ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.jmag), ft); + ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.kmag), ft); + ir_write_str_lit(f, ", "); ir_print_type(f, m, ft); ir_write_byte(f, ' '); + ir_print_exact_value(f, m, exact_value_float(value.value_quaternion.real), ft); + ir_write_byte(f, '}'); + break; + } + case ExactValue_Pointer: if (value.value_pointer == 0) { if (is_type_typeid(type)) { @@ -2246,6 +2270,13 @@ void print_llvm_ir(irGen *ir) { ir_print_encoded_local(f, str_lit("..complex128")); ir_write_str_lit(f, " = type {double, double} ; Basic_complex128\n"); + ir_print_encoded_local(f, str_lit("..quaternion64")); + ir_write_str_lit(f, " = type {half, half, half, half} ; Basic_quaternion64\n"); + ir_print_encoded_local(f, str_lit("..quaternion128")); + ir_write_str_lit(f, " = type {float, float, float, float} ; Basic_quaternion128\n"); + ir_print_encoded_local(f, str_lit("..quaternion256")); + ir_write_str_lit(f, " = type {double, double, double, double} ; Basic_quaternion256\n"); + ir_print_encoded_local(f, str_lit("..typeid")); ir_write_str_lit(f, " = type "); ir_print_type(f, m, t_uintptr); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index a551f0545..5ba402858 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -745,7 +745,10 @@ exponent: scan_mantissa(t, 10); } - if (t->curr_rune == 'i') { + switch (t->curr_rune) { + case 'i': + case 'j': + case 'k': token.kind = Token_Imag; advance_to_next_rune(t); } diff --git a/src/types.cpp b/src/types.cpp index b5c9152b6..94b89d8f5 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -32,6 +32,9 @@ enum BasicKind { Basic_complex64, Basic_complex128, + Basic_quaternion128, + Basic_quaternion256, + Basic_int, Basic_uint, Basic_uintptr, @@ -66,6 +69,7 @@ enum BasicKind { Basic_UntypedInteger, Basic_UntypedFloat, Basic_UntypedComplex, + Basic_UntypedQuaternion, Basic_UntypedString, Basic_UntypedRune, Basic_UntypedNil, @@ -82,17 +86,18 @@ enum BasicFlag { BasicFlag_Unsigned = GB_BIT(2), BasicFlag_Float = GB_BIT(3), BasicFlag_Complex = GB_BIT(4), - BasicFlag_Pointer = GB_BIT(5), - BasicFlag_String = GB_BIT(6), - BasicFlag_Rune = GB_BIT(7), - BasicFlag_Untyped = GB_BIT(8), + BasicFlag_Quaternion = GB_BIT(5), + BasicFlag_Pointer = GB_BIT(6), + BasicFlag_String = GB_BIT(7), + BasicFlag_Rune = GB_BIT(8), + BasicFlag_Untyped = GB_BIT(9), - BasicFlag_LLVM = GB_BIT(10), + BasicFlag_LLVM = GB_BIT(11), BasicFlag_EndianLittle = GB_BIT(13), BasicFlag_EndianBig = GB_BIT(14), - BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex, + BasicFlag_Numeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Complex | BasicFlag_Quaternion, BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune, BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Rune, BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune, @@ -342,6 +347,9 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_complex64, BasicFlag_Complex, 8, STR_LIT("complex64")}}, {Type_Basic, {Basic_complex128, BasicFlag_Complex, 16, STR_LIT("complex128")}}, + {Type_Basic, {Basic_quaternion128, BasicFlag_Quaternion, 16, STR_LIT("quaternion128")}}, + {Type_Basic, {Basic_quaternion256, BasicFlag_Quaternion, 32, STR_LIT("quaternion256")}}, + {Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}}, {Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}}, {Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}}, @@ -377,6 +385,7 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}}, {Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, 0, STR_LIT("untyped float")}}, {Type_Basic, {Basic_UntypedComplex, BasicFlag_Complex | BasicFlag_Untyped, 0, STR_LIT("untyped complex")}}, + {Type_Basic, {Basic_UntypedQuaternion, BasicFlag_Quaternion | BasicFlag_Untyped, 0, STR_LIT("untyped quaternion")}}, {Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}}, {Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}}, {Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}}, @@ -412,6 +421,9 @@ gb_global Type *t_f64 = &basic_types[Basic_f64]; gb_global Type *t_complex64 = &basic_types[Basic_complex64]; gb_global Type *t_complex128 = &basic_types[Basic_complex128]; +gb_global Type *t_quaternion128 = &basic_types[Basic_quaternion128]; +gb_global Type *t_quaternion256 = &basic_types[Basic_quaternion256]; + gb_global Type *t_int = &basic_types[Basic_int]; gb_global Type *t_uint = &basic_types[Basic_uint]; gb_global Type *t_uintptr = &basic_types[Basic_uintptr]; @@ -446,6 +458,7 @@ gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool]; gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger]; gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat]; gb_global Type *t_untyped_complex = &basic_types[Basic_UntypedComplex]; +gb_global Type *t_untyped_quaternion = &basic_types[Basic_UntypedQuaternion]; gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString]; gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune]; gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil]; @@ -472,6 +485,7 @@ gb_global Type *t_type_info_integer = nullptr; gb_global Type *t_type_info_rune = nullptr; gb_global Type *t_type_info_float = nullptr; gb_global Type *t_type_info_complex = nullptr; +gb_global Type *t_type_info_quaternion = nullptr; gb_global Type *t_type_info_any = nullptr; gb_global Type *t_type_info_typeid = nullptr; gb_global Type *t_type_info_string = nullptr; @@ -496,6 +510,7 @@ gb_global Type *t_type_info_integer_ptr = nullptr; gb_global Type *t_type_info_rune_ptr = nullptr; gb_global Type *t_type_info_float_ptr = nullptr; gb_global Type *t_type_info_complex_ptr = nullptr; +gb_global Type *t_type_info_quaternion_ptr = nullptr; gb_global Type *t_type_info_any_ptr = nullptr; gb_global Type *t_type_info_typeid_ptr = nullptr; gb_global Type *t_type_info_string_ptr = nullptr; @@ -924,6 +939,13 @@ bool is_type_complex(Type *t) { } return false; } +bool is_type_quaternion(Type *t) { + t = core_type(t); + if (t->kind == Type_Basic) { + return (t->Basic.flags & BasicFlag_Quaternion) != 0; + } + return false; +} bool is_type_f32(Type *t) { t = core_type(t); if (t->kind == Type_Basic) { @@ -1063,12 +1085,15 @@ bool is_type_simple_compare(Type *t) { Type *base_complex_elem_type(Type *t) { t = core_type(t); - if (is_type_complex(t)) { + if (t->kind == Type_Basic) { switch (t->Basic.kind) { - // case Basic_complex32: return t_f16; - case Basic_complex64: return t_f32; - case Basic_complex128: return t_f64; - case Basic_UntypedComplex: return t_untyped_float; + // case Basic_complex32: return t_f16; + case Basic_complex64: return t_f32; + case Basic_complex128: return t_f64; + case Basic_quaternion128: return t_f32; + case Basic_quaternion256: return t_f64; + case Basic_UntypedComplex: return t_untyped_float; + case Basic_UntypedQuaternion: return t_untyped_float; } } GB_PANIC("Invalid complex type"); @@ -1818,6 +1843,7 @@ Type *default_type(Type *type) { case Basic_UntypedInteger: return t_int; case Basic_UntypedFloat: return t_f64; case Basic_UntypedComplex: return t_complex128; + case Basic_UntypedQuaternion: return t_quaternion256; case Basic_UntypedString: return t_string; case Basic_UntypedRune: return t_rune; } @@ -2358,6 +2384,8 @@ i64 type_align_of_internal(Type *t, TypePath *path) { case Basic_complex64: case Basic_complex128: return type_size_of_internal(t, path) / 2; + case Basic_quaternion128: case Basic_quaternion256: + return type_size_of_internal(t, path) / 4; } } break; -- cgit v1.2.3 From 01c10aa9447d135bdda5dc25583a5e1f94cbda6d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 26 Aug 2019 13:54:35 +0100 Subject: `inline for` loops (only for 'in' based for loops) --- examples/demo/demo.odin | 39 +++++++ src/check_stmt.cpp | 272 ++++++++++++++++++++++++++++++++++++++++++++---- src/checker.hpp | 3 + src/exact_value.cpp | 4 + src/ir.cpp | 144 +++++++++++++++++++++++++ src/parser.cpp | 83 ++++++++++++++- src/parser.hpp | 9 ++ 7 files changed, 530 insertions(+), 24 deletions(-) (limited to 'src/ir.cpp') diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index a96056b61..cef814a56 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1018,6 +1018,44 @@ quaternions :: proc() { fmt.println(c); fmt.println(q); } + { // Memory layout of Quaternions + q := 1 + 2i + 3j + 4k; + a := transmute([4]f64)q; + fmt.println("Quaternion memory layout: xyzw/(ijkr)"); + fmt.println(q); // 1.000+2.000i+3.000j+4.000k + fmt.println(a); // [2.000, 3.000, 4.000, 1.000] + } +} + +inline_for_statement :: proc() { + fmt.println("\n#inline for statements"); + + fmt.println("Ranges"); + inline for x, i in 1..<4 { + fmt.println(x, i); + } + + fmt.println("Strings"); + inline for r, i in "Hello, 世界" { + fmt.println(r, i); + } + + fmt.println("Arrays"); + inline for elem, idx in ([4]int{1, 4, 9, 16}) { + fmt.println(elem, idx); + } + + + Foo_Enum :: enum { + A = 1, + B, + C = 6, + D, + } + fmt.println("Enum types"); + inline for elem, idx in Foo_Enum { + fmt.println(elem, idx); + } } main :: proc() { @@ -1040,5 +1078,6 @@ main :: proc() { deferred_procedure_associations(); reflection(); quaternions(); + inline_for_statement(); } } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 2787aa436..88661558d 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -132,6 +132,10 @@ bool check_is_terminating(Ast *node) { } case_end; + case_ast_node(rs, InlineRangeStmt, node); + return false; + case_end; + case_ast_node(rs, RangeStmt, node); return false; case_end; @@ -587,6 +591,236 @@ void add_constant_switch_case(CheckerContext *ctx, Map *seen, Oper multi_map_insert(seen, key, tap); } +void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { + ast_node(irs, InlineRangeStmt, node); + check_open_scope(ctx, node); + + Type *val0 = nullptr; + Type *val1 = nullptr; + Entity *entities[2] = {}; + isize entity_count = 0; + + Ast *expr = unparen_expr(irs->expr); + + ExactValue inline_for_depth = exact_value_i64(0); + + if (is_ast_range(expr)) { + ast_node(ie, BinaryExpr, expr); + Operand x = {Addressing_Invalid}; + Operand y = {Addressing_Invalid}; + + check_expr(ctx, &x, ie->left); + if (x.mode == Addressing_Invalid) { + goto skip_expr; + } + check_expr(ctx, &y, ie->right); + if (y.mode == Addressing_Invalid) { + goto skip_expr; + } + + convert_to_typed(ctx, &x, y.type); + if (x.mode == Addressing_Invalid) { + goto skip_expr; + } + convert_to_typed(ctx, &y, x.type); + if (y.mode == Addressing_Invalid) { + goto skip_expr; + } + + convert_to_typed(ctx, &x, default_type(y.type)); + if (x.mode == Addressing_Invalid) { + goto skip_expr; + } + convert_to_typed(ctx, &y, default_type(x.type)); + if (y.mode == Addressing_Invalid) { + goto skip_expr; + } + + if (!are_types_identical(x.type, y.type)) { + if (x.type != t_invalid && + y.type != t_invalid) { + gbString xt = type_to_string(x.type); + gbString yt = type_to_string(y.type); + gbString expr_str = expr_to_string(x.expr); + error(ie->op, "Mismatched types in interval expression '%s' : '%s' vs '%s'", expr_str, xt, yt); + gb_string_free(expr_str); + gb_string_free(yt); + gb_string_free(xt); + } + goto skip_expr; + } + + Type *type = x.type; + if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) { + error(ie->op, "Only numerical and pointer types are allowed within interval expressions"); + goto skip_expr; + } + + if (x.mode == Addressing_Constant && + y.mode == Addressing_Constant) { + ExactValue a = x.value; + ExactValue b = y.value; + + GB_ASSERT(are_types_identical(x.type, y.type)); + + TokenKind op = Token_Lt; + switch (ie->op.kind) { + case Token_Ellipsis: op = Token_LtEq; break; + case Token_RangeHalf: op = Token_Lt; break; + default: error(ie->op, "Invalid range operator"); break; + } + bool ok = compare_exact_values(op, a, b); + if (!ok) { + // TODO(bill): Better error message + error(ie->op, "Invalid interval range"); + goto skip_expr; + } + + inline_for_depth = exact_value_sub(b, a); + if (ie->op.kind == Token_Ellipsis) { + inline_for_depth = exact_value_increment_one(inline_for_depth); + } + + } else { + error(ie->op, "Interval expressions must be constant"); + goto skip_expr; + } + + add_type_and_value(&ctx->checker->info, ie->left, x.mode, x.type, x.value); + add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value); + val0 = type; + val1 = t_int; + } else { + Operand operand = {Addressing_Invalid}; + check_expr_or_type(ctx, &operand, irs->expr); + + if (operand.mode == Addressing_Type) { + if (!is_type_enum(operand.type)) { + gbString t = type_to_string(operand.type); + error(operand.expr, "Cannot iterate over the type '%s'", t); + gb_string_free(t); + goto skip_expr; + } else { + val0 = operand.type; + val1 = t_int; + add_type_info_type(ctx, operand.type); + + Type *bt = base_type(operand.type); + inline_for_depth = exact_value_i64(bt->Enum.fields.count); + goto skip_expr; + } + } else if (operand.mode != Addressing_Invalid) { + Type *t = base_type(operand.type); + switch (t->kind) { + case Type_Basic: + if (is_type_string(t) && t->Basic.kind != Basic_cstring) { + val0 = t_rune; + val1 = t_int; + inline_for_depth = exact_value_i64(operand.value.value_string.len); + } + break; + case Type_Array: + val0 = t->Array.elem; + val1 = t_int; + inline_for_depth = exact_value_i64(t->Array.count); + break; + } + } + + if (val0 == nullptr) { + gbString s = expr_to_string(operand.expr); + gbString t = type_to_string(operand.type); + error(operand.expr, "Cannot iterate over '%s' of type '%s' in an 'inline for' statement", s, t); + gb_string_free(t); + gb_string_free(s); + } else if (operand.mode != Addressing_Constant) { + error(operand.expr, "An 'inline for' expression must be known at compile time"); + } + } + + skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird. + + Ast * lhs[2] = {irs->val0, irs->val1}; + Type *rhs[2] = {val0, val1}; + + for (isize i = 0; i < 2; i++) { + if (lhs[i] == nullptr) { + continue; + } + Ast * name = lhs[i]; + Type *type = rhs[i]; + + Entity *entity = nullptr; + if (name->kind == Ast_Ident) { + Token token = name->Ident.token; + String str = token.string; + Entity *found = nullptr; + + if (!is_blank_ident(str)) { + found = scope_lookup_current(ctx->scope, str); + } + if (found == nullptr) { + bool is_immutable = true; + entity = alloc_entity_variable(ctx->scope, token, type, is_immutable, EntityState_Resolved); + entity->flags |= EntityFlag_Value; + add_entity_definition(&ctx->checker->info, name, entity); + } else { + TokenPos pos = found->token.pos; + error(token, + "Redeclaration of '%.*s' in this scope\n" + "\tat %.*s(%td:%td)", + LIT(str), LIT(pos.file), pos.line, pos.column); + entity = found; + } + } else { + error(name, "A variable declaration must be an identifier"); + } + + if (entity == nullptr) { + entity = alloc_entity_dummy_variable(builtin_pkg->scope, ast_token(name)); + } + + entities[entity_count++] = entity; + + if (type == nullptr) { + entity->type = t_invalid; + entity->flags |= EntityFlag_Used; + } + } + + for (isize i = 0; i < entity_count; i++) { + add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]); + } + + + // NOTE(bill): Minimize the amount of nesting of an 'inline for' + i64 prev_inline_for_depth = ctx->inline_for_depth; + defer (ctx->inline_for_depth = prev_inline_for_depth); + { + i64 v = exact_value_to_i64(inline_for_depth); + if (v <= 0) { + // Do nothing + } else { + ctx->inline_for_depth = gb_max(ctx->inline_for_depth, 1) * v; + } + + if (ctx->inline_for_depth >= MAX_INLINE_FOR_DEPTH && prev_inline_for_depth < MAX_INLINE_FOR_DEPTH) { + if (prev_inline_for_depth > 0) { + error(node, "Nested 'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH); + } else { + error(node, "'inline for' loop cannot be inlined as it exceeds the maximum inline for depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH); + } + error_line("\tUse a normal 'for' loop instead by removing the 'inline' prefix\n"); + ctx->inline_for_depth = MAX_INLINE_FOR_DEPTH; + } + } + + check_stmt(ctx, irs->body, mod_flags); + + + check_close_scope(ctx); +} + void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { ast_node(ss, SwitchStmt, node); @@ -1298,6 +1532,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { check_close_scope(ctx); case_end; + case_ast_node(rs, RangeStmt, node); u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed; @@ -1320,29 +1555,29 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { check_expr(ctx, &x, ie->left); if (x.mode == Addressing_Invalid) { - goto skip_expr; + goto skip_expr_range_stmt; } check_expr(ctx, &y, ie->right); if (y.mode == Addressing_Invalid) { - goto skip_expr; + goto skip_expr_range_stmt; } convert_to_typed(ctx, &x, y.type); if (x.mode == Addressing_Invalid) { - goto skip_expr; + goto skip_expr_range_stmt; } convert_to_typed(ctx, &y, x.type); if (y.mode == Addressing_Invalid) { - goto skip_expr; + goto skip_expr_range_stmt; } convert_to_typed(ctx, &x, default_type(y.type)); if (x.mode == Addressing_Invalid) { - goto skip_expr; + goto skip_expr_range_stmt; } convert_to_typed(ctx, &y, default_type(x.type)); if (y.mode == Addressing_Invalid) { - goto skip_expr; + goto skip_expr_range_stmt; } if (!are_types_identical(x.type, y.type)) { @@ -1356,13 +1591,13 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { gb_string_free(yt); gb_string_free(xt); } - goto skip_expr; + goto skip_expr_range_stmt; } Type *type = x.type; if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) { error(ie->op, "Only numerical and pointer types are allowed within interval expressions"); - goto skip_expr; + goto skip_expr_range_stmt; } if (x.mode == Addressing_Constant && @@ -1382,18 +1617,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { if (!ok) { // TODO(bill): Better error message error(ie->op, "Invalid interval range"); - goto skip_expr; + goto skip_expr_range_stmt; } } - if (x.mode != Addressing_Constant) { - x.value = empty_exact_value; - } - if (y.mode != Addressing_Constant) { - y.value = empty_exact_value; - } - - add_type_and_value(&ctx->checker->info, ie->left, x.mode, x.type, x.value); add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value); val0 = type; @@ -1407,12 +1634,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { gbString t = type_to_string(operand.type); error(operand.expr, "Cannot iterate over the type '%s'", t); gb_string_free(t); - goto skip_expr; + goto skip_expr_range_stmt; } else { val0 = operand.type; val1 = t_int; add_type_info_type(ctx, operand.type); - goto skip_expr; + goto skip_expr_range_stmt; } } else if (operand.mode != Addressing_Invalid) { bool is_ptr = is_type_pointer(operand.type); @@ -1457,7 +1684,8 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { } } - skip_expr:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird. + skip_expr_range_stmt:; // NOTE(zhiayang): again, declaring a variable immediately after a label... weird. + Ast * lhs[2] = {rs->val0, rs->val1}; Type *rhs[2] = {val0, val1}; @@ -1515,6 +1743,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { check_close_scope(ctx); case_end; + case_ast_node(irs, InlineRangeStmt, node); + check_inline_range_stmt(ctx, node, mod_flags); + case_end; + case_ast_node(ss, SwitchStmt, node); check_switch_stmt(ctx, node, mod_flags); case_end; diff --git a/src/checker.hpp b/src/checker.hpp index 4e4a8cfe1..a37a87b87 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -276,6 +276,9 @@ struct CheckerContext { CheckerPolyPath *poly_path; isize poly_level; // TODO(bill): Actually handle correctly +#define MAX_INLINE_FOR_DEPTH 1024ll + i64 inline_for_depth; + bool in_enum_type; bool collect_delayed_decls; bool allow_polymorphic_types; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 54d4ef6f2..fcc6f1973 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -813,6 +813,10 @@ gb_inline ExactValue exact_value_shift(TokenKind op, ExactValue const &x, ExactV return exact_binary_operator_value(op, x, y); } +gb_inline ExactValue exact_value_increment_one(ExactValue const &x) { + return exact_binary_operator_value(Token_Add, x, exact_value_i64(1)); +} + i32 cmp_f64(f64 a, f64 b) { return (a > b) - (a < b); diff --git a/src/ir.cpp b/src/ir.cpp index 2a4bb028b..7dc5988e3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9061,6 +9061,150 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { ir_start_block(proc, done); case_end; + case_ast_node(rs, InlineRangeStmt, node); + ir_emit_comment(proc, str_lit("InlineRangeStmt")); + ir_open_scope(proc); // Open scope here + + Type *val0_type = nullptr; + Type *val1_type = nullptr; + if (rs->val0 != nullptr && !is_blank_ident(rs->val0)) { + val0_type = type_of_expr(rs->val0); + } + if (rs->val1 != nullptr && !is_blank_ident(rs->val1)) { + val1_type = type_of_expr(rs->val1); + } + + if (val0_type != nullptr) { + ir_add_local_for_identifier(proc, rs->val0, true); + } + if (val1_type != nullptr) { + ir_add_local_for_identifier(proc, rs->val1, true); + } + + irValue *val = nullptr; + irValue *key = nullptr; + irBlock *loop = nullptr; + irBlock *done = nullptr; + Ast *expr = unparen_expr(rs->expr); + + TypeAndValue tav = type_and_value_of_expr(expr); + + if (is_ast_range(expr)) { + + irAddr val0_addr = {}; + irAddr val1_addr = {}; + if (val0_type) val0_addr = ir_build_addr(proc, rs->val0); + if (val1_type) val1_addr = ir_build_addr(proc, rs->val1); + + TokenKind op = expr->BinaryExpr.op.kind; + Ast *start_expr = expr->BinaryExpr.left; + Ast *end_expr = expr->BinaryExpr.right; + GB_ASSERT(start_expr->tav.mode == Addressing_Constant); + GB_ASSERT(end_expr->tav.mode == Addressing_Constant); + + ExactValue start = start_expr->tav.value; + ExactValue end = end_expr->tav.value; + if (op == Token_Ellipsis) { // .. [start, end] + ExactValue index = exact_value_i64(0); + for (ExactValue val = start; + compare_exact_values(Token_LtEq, val, end); + val = exact_value_increment_one(val), index = exact_value_increment_one(index)) { + + if (val0_type) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, val)); + if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, index)); + + ir_build_stmt(proc, rs->body); + } + } else if (op == Token_RangeHalf) { // ..< [start, end) + ExactValue index = exact_value_i64(0); + for (ExactValue val = start; + compare_exact_values(Token_Lt, val, end); + val = exact_value_increment_one(val), index = exact_value_increment_one(index)) { + + if (val0_type) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, val)); + if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, index)); + + ir_build_stmt(proc, rs->body); + } + } + + + } else if (tav.mode == Addressing_Type) { + GB_ASSERT(is_type_enum(type_deref(tav.type))); + Type *et = type_deref(tav.type); + Type *bet = base_type(et); + + irAddr val0_addr = {}; + irAddr val1_addr = {}; + if (val0_type) val0_addr = ir_build_addr(proc, rs->val0); + if (val1_type) val1_addr = ir_build_addr(proc, rs->val1); + + for_array(i, bet->Enum.fields) { + Entity *field = bet->Enum.fields[i]; + GB_ASSERT(field->kind == Entity_Constant); + if (val0_type) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, field->Constant.value)); + if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, exact_value_i64(i))); + + ir_build_stmt(proc, rs->body); + } + } else { + irAddr val0_addr = {}; + irAddr val1_addr = {}; + if (val0_type) val0_addr = ir_build_addr(proc, rs->val0); + if (val1_type) val1_addr = ir_build_addr(proc, rs->val1); + + GB_ASSERT(expr->tav.mode == Addressing_Constant); + + Type *t = base_type(expr->tav.type); + + + switch (t->kind) { + case Type_Basic: + GB_ASSERT(is_type_string(t)); + { + ExactValue value = expr->tav.value; + GB_ASSERT(value.kind == ExactValue_String); + String str = value.value_string; + Rune codepoint = 0; + isize offset = 0; + do { + isize width = gb_utf8_decode(str.text+offset, str.len-offset, &codepoint); + if (val0_type) ir_addr_store(proc, val0_addr, ir_value_constant(val0_type, exact_value_i64(codepoint))); + if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, exact_value_i64(offset))); + ir_build_stmt(proc, rs->body); + + offset += width; + } while (offset < str.len); + } + break; + case Type_Array: + if (t->Array.count > 0) { + irValue *val = ir_build_expr(proc, expr); + irValue *val_addr = ir_address_from_load_or_generate_local(proc, val); + + for (i64 i = 0; i < t->Array.count; i++) { + if (val0_type) { + // NOTE(bill): Due to weird legacy issues in LLVM, this needs to be an i32 + irValue *elem = ir_emit_array_epi(proc, val_addr, cast(i32)i); + ir_addr_store(proc, val0_addr, ir_emit_load(proc, elem)); + } + if (val1_type) ir_addr_store(proc, val1_addr, ir_value_constant(val1_type, exact_value_i64(i))); + + ir_build_stmt(proc, rs->body); + } + + } + break; + default: + GB_PANIC("Invalid inline for type"); + break; + } + } + + + ir_close_scope(proc, irDeferExit_Default, nullptr); + case_end; + case_ast_node(ss, SwitchStmt, node); ir_emit_comment(proc, str_lit("SwitchStmt")); if (ss->init != nullptr) { diff --git a/src/parser.cpp b/src/parser.cpp index 9aebc78d6..8c32f35ff 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -51,6 +51,7 @@ Token ast_token(Ast *node) { case Ast_ReturnStmt: return node->ReturnStmt.token; case Ast_ForStmt: return node->ForStmt.token; case Ast_RangeStmt: return node->RangeStmt.token; + case Ast_InlineRangeStmt: return node->InlineRangeStmt.inline_token; case Ast_CaseClause: return node->CaseClause.token; case Ast_SwitchStmt: return node->SwitchStmt.token; case Ast_TypeSwitchStmt: return node->TypeSwitchStmt.token; @@ -257,6 +258,12 @@ Ast *clone_ast(Ast *node) { n->RangeStmt.expr = clone_ast(n->RangeStmt.expr); n->RangeStmt.body = clone_ast(n->RangeStmt.body); break; + case Ast_InlineRangeStmt: + n->InlineRangeStmt.val0 = clone_ast(n->InlineRangeStmt.val0); + n->InlineRangeStmt.val1 = clone_ast(n->InlineRangeStmt.val1); + n->InlineRangeStmt.expr = clone_ast(n->InlineRangeStmt.expr); + n->InlineRangeStmt.body = clone_ast(n->InlineRangeStmt.body); + break; case Ast_CaseClause: n->CaseClause.list = clone_ast_array(n->CaseClause.list); n->CaseClause.stmts = clone_ast_array(n->CaseClause.stmts); @@ -748,6 +755,18 @@ Ast *ast_range_stmt(AstFile *f, Token token, Ast *val0, Ast *val1, Token in_toke return result; } +Ast *ast_inline_range_stmt(AstFile *f, Token inline_token, Token for_token, Ast *val0, Ast *val1, Token in_token, Ast *expr, Ast *body) { + Ast *result = alloc_ast_node(f, Ast_InlineRangeStmt); + result->InlineRangeStmt.inline_token = inline_token; + result->InlineRangeStmt.for_token = for_token; + result->InlineRangeStmt.val0 = val0; + result->InlineRangeStmt.val1 = val1; + result->InlineRangeStmt.in_token = in_token; + result->InlineRangeStmt.expr = expr; + result->InlineRangeStmt.body = body; + return result; +} + Ast *ast_switch_stmt(AstFile *f, Token token, Ast *init, Ast *tag, Ast *body) { Ast *result = alloc_ast_node(f, Ast_SwitchStmt); result->SwitchStmt.token = token; @@ -1119,6 +1138,17 @@ Token advance_token(AstFile *f) { return prev; } +bool peek_token_kind(AstFile *f, TokenKind kind) { + for (isize i = f->curr_token_index+1; i < f->tokens.count; i++) { + Token tok = f->tokens[i]; + if (kind != Token_Comment && tok.kind == Token_Comment) { + continue; + } + return tok.kind == kind; + } + return false; +} + Token expect_token(AstFile *f, TokenKind kind) { Token prev = f->curr_token; if (prev.kind != kind) { @@ -2092,7 +2122,7 @@ Ast *parse_operand(AstFile *f, bool lhs) { bool prev_allow_range = f->allow_range; f->allow_range = true; - elem = parse_expr(f, false); + elem = parse_expr(f, true); f->allow_range = prev_allow_range; if (allow_token(f, Token_Semicolon)) { underlying = parse_type(f); @@ -2650,7 +2680,7 @@ Ast *parse_simple_stmt(AstFile *f, u32 flags) { allow_token(f, Token_in); bool prev_allow_range = f->allow_range; f->allow_range = true; - Ast *expr = parse_expr(f, false); + Ast *expr = parse_expr(f, true); f->allow_range = prev_allow_range; auto rhs = array_make(heap_allocator(), 0, 1); @@ -3779,10 +3809,55 @@ Ast *parse_stmt(AstFile *f) { Token token = f->curr_token; switch (token.kind) { // Operands - case Token_context: // Also allows for `context =` - case Token_proc: case Token_inline: + if (peek_token_kind(f, Token_for)) { + Token inline_token = expect_token(f, Token_inline); + Token for_token = expect_token(f, Token_for); + Ast *val0 = nullptr; + Ast *val1 = nullptr; + Token in_token = {}; + Ast *expr = nullptr; + Ast *body = nullptr; + + bool bad_stmt = false; + + if (f->curr_token.kind != Token_in) { + Array idents = parse_ident_list(f, false); + switch (idents.count) { + case 1: + val0 = idents[0]; + break; + case 2: + val0 = idents[0]; + val1 = idents[1]; + break; + default: + syntax_error(for_token, "Expected either 1 or 2 identifiers"); + bad_stmt = true; + break; + } + } + in_token = expect_token(f, Token_in); + + bool prev_allow_range = f->allow_range; + f->allow_range = true; + expr = parse_expr(f, true); + f->allow_range = prev_allow_range; + + if (allow_token(f, Token_do)) { + body = convert_stmt_to_body(f, parse_stmt(f)); + } else { + body = parse_block_stmt(f, false); + } + if (bad_stmt) { + return ast_bad_stmt(f, inline_token, f->curr_token); + } + return ast_inline_range_stmt(f, inline_token, for_token, val0, val1, in_token, expr, body); + } + /* fallthrough */ case Token_no_inline: + case Token_context: // Also allows for `context =` + case Token_proc: case Token_Ident: case Token_Integer: case Token_Float: diff --git a/src/parser.hpp b/src/parser.hpp index 3489f1a9b..32398592e 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -326,6 +326,15 @@ AST_KIND(_ComplexStmtBegin, "", bool) \ Ast *expr; \ Ast *body; \ }) \ + AST_KIND(InlineRangeStmt, "inline range statement", struct { \ + Token inline_token; \ + Token for_token; \ + Ast *val0; \ + Ast *val1; \ + Token in_token; \ + Ast *expr; \ + Ast *body; \ + }) \ AST_KIND(CaseClause, "case clause", struct { \ Token token; \ Array list; \ -- cgit v1.2.3 From f1a7b31209d68f71256ad524d6d1a6ed15cb7c12 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 28 Aug 2019 13:34:55 +0100 Subject: Fix nested raw_union with using #428 --- src/ir.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 7dc5988e3..7fa3f296a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1873,10 +1873,12 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { case Basic_string: case Basic_any: case Basic_rawptr: + case Basic_quaternion128: + case Basic_quaternion256: break; // not a "DIBasicType" } - GB_PANIC("Unreachable"); + GB_PANIC("Unreachable %d", kind); return irDebugBasicEncoding_Invalid; } @@ -4525,13 +4527,14 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel) { if (is_type_pointer(type)) { type = type_deref(type); e = ir_emit_load(proc, e); - e = ir_emit_ptr_offset(proc, e, v_zero); // TODO(bill): Do I need these copies? + // e = ir_emit_ptr_offset(proc, e, v_zero); // TODO(bill): Do I need these copies? } type = core_type(type); if (is_type_raw_union(type)) { type = type->Struct.fields[index]->type; - e = ir_emit_conv(proc, e, alloc_type_pointer(type)); + GB_ASSERT(is_type_pointer(ir_type(e))); + e = ir_emit_bitcast(proc, e, alloc_type_pointer(type)); } else if (is_type_struct(type)) { type = type->Struct.fields[index]->type; e = ir_emit_struct_ep(proc, e, index); -- cgit v1.2.3 From 614d209824f005aa11a399bbe1bbf2b3b9e76687 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 29 Aug 2019 10:39:03 +0100 Subject: Add debug information for quaternion types (fixes #428) --- src/ir.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 12 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 7fa3f296a..62519c259 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2224,14 +2224,7 @@ irDebugInfo *ir_add_debug_info_type_complex(irModule *module, Type *type) { di->CompositeType.tag = irDebugBasicEncoding_structure_type; di->CompositeType.size = ir_debug_size_bits(type); - Type *field_type = nullptr; - if (type->Basic.kind == Basic_complex64) { - field_type = t_f32; - } else if (type->Basic.kind == Basic_complex128) { - field_type = t_f64; - } else { - GB_PANIC("Unreachable"); - } + Type *field_type = base_complex_elem_type(type); // Field "real" irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type, @@ -2256,6 +2249,40 @@ irDebugInfo *ir_add_debug_info_type_complex(irModule *module, Type *type) { return di; } +irDebugInfo *ir_add_debug_info_type_quaternion(irModule *module, Type *type) { + GB_ASSERT(type->kind == Type_Basic && is_type_quaternion(type)); + + irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompositeType); + map_set(&module->debug_info, hash_type(type), di); + + di->CompositeType.name = type->Basic.name; + di->CompositeType.tag = irDebugBasicEncoding_structure_type; + di->CompositeType.size = ir_debug_size_bits(type); + + Type *field_type = base_complex_elem_type(type); + + // @QuaternionLayout + irDebugInfo *imag_di = ir_add_debug_info_field_internal(module, str_lit("imag"), field_type, 0*cast(i32)type_size_of(field_type), nullptr, di); + irDebugInfo *jmag_di = ir_add_debug_info_field_internal(module, str_lit("jmag"), field_type, 1*cast(i32)type_size_of(field_type), nullptr, di); + irDebugInfo *kmag_di = ir_add_debug_info_field_internal(module, str_lit("kmag"), field_type, 2*cast(i32)type_size_of(field_type), nullptr, di); + irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type, 3*cast(i32)type_size_of(field_type), nullptr, di); + + map_set(&module->debug_info, hash_pointer(imag_di), imag_di); + map_set(&module->debug_info, hash_pointer(jmag_di), jmag_di); + map_set(&module->debug_info, hash_pointer(kmag_di), kmag_di); + map_set(&module->debug_info, hash_pointer(real_di), real_di); + + irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 4); + array_add(&elements_di->DebugInfoArray.elements, imag_di); + array_add(&elements_di->DebugInfoArray.elements, jmag_di); + array_add(&elements_di->DebugInfoArray.elements, kmag_di); + array_add(&elements_di->DebugInfoArray.elements, real_di); + di->CompositeType.elements = elements_di; + map_set(&module->debug_info, hash_pointer(elements_di), elements_di); + + return di; +} + irDebugInfo *ir_add_debug_info_proc_type(irModule *module, Type *type) { GB_ASSERT(type->kind == Type_Proc); @@ -2380,10 +2407,14 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD if (type->kind == Type_Basic) { switch (type->Basic.kind) { // Composite basic types - case Basic_complex64: - case Basic_complex128: return ir_add_debug_info_type_complex(module, type); - case Basic_string: return ir_add_debug_info_type_string(module, scope, e, type); - case Basic_any: return ir_add_debug_info_type_any(module); + case Basic_complex64: case Basic_complex128: + return ir_add_debug_info_type_complex(module, type); + case Basic_quaternion128: case Basic_quaternion256: + return ir_add_debug_info_type_quaternion(module, type); + case Basic_string: + return ir_add_debug_info_type_string(module, scope, e, type); + case Basic_any: + return ir_add_debug_info_type_any(module); // Derived basic types case Basic_cstring: -- cgit v1.2.3 From c89fc35e941275085332ba16b453432b5b7a5086 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 29 Aug 2019 14:36:42 +0100 Subject: Fix global variable initialization ordering (related to #427) --- src/check_decl.cpp | 5 +++-- src/check_stmt.cpp | 7 ++++++- src/checker.cpp | 57 ++++++++++++++++++++++++++++++-------------------- src/ir.cpp | 13 ++---------- src/priority_queue.cpp | 4 ++-- 5 files changed, 47 insertions(+), 39 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index cf3cb8e97..d87e6def0 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -791,7 +791,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } } -void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) { +void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) { GB_ASSERT(e->type == nullptr); GB_ASSERT(e->kind == Entity_Variable); @@ -805,6 +805,7 @@ void check_var_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_ex ac.init_expr_list_count = init_expr != nullptr ? 1 : 0; DeclInfo *decl = decl_info_of_entity(e); + GB_ASSERT(decl == ctx->decl); if (decl != nullptr) { check_decl_attributes(ctx, decl->attributes, var_decl_attribute, &ac); } @@ -1051,7 +1052,7 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_ switch (e->kind) { case Entity_Variable: - check_var_decl(&c, e, d->type_expr, d->init_expr); + check_global_variable_decl(&c, e, d->type_expr, d->init_expr); break; case Entity_Constant: check_const_decl(&c, e, d->type_expr, d->init_expr, named_type); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 88661558d..6945fb00e 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1735,7 +1735,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { } for (isize i = 0; i < entity_count; i++) { - add_entity(ctx->checker, ctx->scope, entities[i]->identifier, entities[i]); + Entity *e = entities[i]; + DeclInfo *d = decl_info_of_entity(e); + GB_ASSERT(d == nullptr); + add_entity(ctx->checker, ctx->scope, e->identifier, e); + d = make_decl_info(ctx->allocator, ctx->scope, ctx->decl); + add_entity_and_decl_info(ctx, e->identifier, e, d); } check_stmt(ctx, rs->body, new_flags); diff --git a/src/checker.cpp b/src/checker.cpp index d6f5ad402..fc8cb5c63 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -85,9 +85,13 @@ int entity_graph_node_cmp(EntityGraphNode **data, isize i, isize j) { EntityGraphNode *y = data[j]; isize a = x->entity->order_in_src; isize b = y->entity->order_in_src; - if (x->dep_count < y->dep_count) return -1; - if (x->dep_count > y->dep_count) return +1; - return a < b ? -1 : b > a; + if (x->dep_count < y->dep_count) { + return -1; + } + if (x->dep_count == y->dep_count) { + return a < b ? -1 : b > a; + } + return +1; } void entity_graph_node_swap(EntityGraphNode **data, isize i, isize j) { @@ -1164,6 +1168,7 @@ void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, Dec add_entity_definition(&c->checker->info, identifier, e); GB_ASSERT(e->decl_info == nullptr); e->decl_info = d; + d->entity = e; array_add(&c->checker->info.entities, e); e->order_in_src = c->checker->info.entities.count; e->pkg = c->pkg; @@ -1602,6 +1607,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("args__"), str_lit("type_table"), + str_lit("__type_info_of"), str_lit("global_scratch_allocator"), str_lit("Type_Info"), @@ -1688,9 +1694,10 @@ bool is_entity_a_dependency(Entity *e) { if (e == nullptr) return false; switch (e->kind) { case Entity_Procedure: - case Entity_Variable: - case Entity_Constant: return true; + case Entity_Constant: + case Entity_Variable: + return e->pkg != nullptr; } return false; } @@ -1717,18 +1724,17 @@ Array generate_entity_dependency_graph(CheckerInfo *info) { EntityGraphNode *n = M.entries[i].value; DeclInfo *decl = decl_info_of_entity(e); - if (decl != nullptr) { - for_array(j, decl->deps.entries) { - auto entry = decl->deps.entries[j]; - Entity *dep = entry.ptr; - if (dep && is_entity_a_dependency(dep)) { - EntityGraphNode **m_ = map_get(&M, hash_pointer(dep)); - if (m_ != nullptr) { - EntityGraphNode *m = *m_; - entity_graph_node_set_add(&n->succ, m); - entity_graph_node_set_add(&m->pred, n); - } - } + GB_ASSERT(decl != nullptr); + + for_array(j, decl->deps.entries) { + Entity *dep = decl->deps.entries[j].ptr; + GB_ASSERT(dep != nullptr); + if (is_entity_a_dependency(dep)) { + EntityGraphNode **m_ = map_get(&M, hash_pointer(dep)); + GB_ASSERT(m_ != nullptr); + EntityGraphNode *m = *m_; + entity_graph_node_set_add(&n->succ, m); + entity_graph_node_set_add(&m->pred, n); } } } @@ -2562,6 +2568,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { Ast *init_expr = value; DeclInfo *d = make_decl_info(heap_allocator(), c->scope, c->decl); + d->entity = e; d->type_expr = vd->type; d->init_expr = init_expr; d->attributes = vd->attributes; @@ -3576,7 +3583,6 @@ void calculate_global_init_order(Checker *c) { #define TIME_SECTION(str) #endif - CheckerInfo *info = &c->info; TIME_SECTION("generate entity dependency graph"); @@ -3618,21 +3624,26 @@ void calculate_global_init_order(Checker *c) { for_array(i, n->pred.entries) { EntityGraphNode *p = n->pred.entries[i].ptr; - p->dep_count -= gb_max(p->dep_count-1, 0); + p->dep_count -= 1; + p->dep_count = gb_max(p->dep_count, 0); priority_queue_fix(&pq, p->index); } - if (e == nullptr || e->kind != Entity_Variable) { + DeclInfo *d = decl_info_of_entity(e); + if (e->kind != Entity_Variable) { continue; } - DeclInfo *d = decl_info_of_entity(e); - + // IMPORTANT NOTE(bill, 2019-08-29): Just add it regardless of the ordering + // because it does not need any initialization other than zero + // if (!decl_info_has_init(d)) { + // continue; + // } if (ptr_set_exists(&emitted, d)) { continue; } ptr_set_add(&emitted, d); - d->entity = e; + array_add(&info->variable_init_order, d); } diff --git a/src/ir.cpp b/src/ir.cpp index 62519c259..26f787976 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2226,18 +2226,9 @@ irDebugInfo *ir_add_debug_info_type_complex(irModule *module, Type *type) { Type *field_type = base_complex_elem_type(type); - // Field "real" - irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type, - 0, - nullptr, - di); + irDebugInfo *real_di = ir_add_debug_info_field_internal(module, str_lit("real"), field_type, 0*cast(i32)type_size_of(field_type), nullptr, di); + irDebugInfo *imag_di = ir_add_debug_info_field_internal(module, str_lit("imag"), field_type, 1*cast(i32)type_size_of(field_type), nullptr, di); map_set(&module->debug_info, hash_pointer(real_di), real_di); - - // Field "imag" - irDebugInfo *imag_di = ir_add_debug_info_field_internal(module, str_lit("imag"), field_type, - real_di->DerivedType.size, - nullptr, - di); map_set(&module->debug_info, hash_pointer(imag_di), imag_di); irDebugInfo *elements_di = ir_add_debug_info_array(module, 0, 2); diff --git a/src/priority_queue.cpp b/src/priority_queue.cpp index 7c36e6a22..aee2061b5 100644 --- a/src/priority_queue.cpp +++ b/src/priority_queue.cpp @@ -20,7 +20,7 @@ bool priority_queue_shift_down(PriorityQueue *pq, isize i0, isize n) { if (j2 < n && pq->cmp(&pq->queue[0], j2, j1) < 0) { j = j2; } - if (pq->cmp(&pq->queue[0], i, j) < 0) break; + if (pq->cmp(&pq->queue[0], j, i) >= 0) break; pq->swap(&pq->queue[0], i, j); i = j; @@ -32,7 +32,7 @@ template void priority_queue_shift_up(PriorityQueue *pq, isize j) { while (0 <= j && j < pq->queue.count) { isize i = (j-1)/2; - if (i == j || pq->cmp(&pq->queue[0], i, j) < 0) { + if (i == j || pq->cmp(&pq->queue[0], j, i) >= 0) { break; } pq->swap(&pq->queue[0], i, j); -- cgit v1.2.3 From 22e982c8fbec797f2fb48a7df5ab28efc0ee16c9 Mon Sep 17 00:00:00 2001 From: nakst Date: Mon, 2 Sep 2019 16:46:50 +0100 Subject: New Essence OS layer; cross-compiling improvements --- core/os/os_essence.odin | 1456 +++++++++++++++++++++++++++++---- core/sys/essence_linker_userland64.ld | 24 - core/time/time_essence.odin | 2 + src/build_settings.cpp | 40 +- src/ir.cpp | 2 + src/main.cpp | 92 +-- 6 files changed, 1393 insertions(+), 223 deletions(-) delete mode 100644 core/sys/essence_linker_userland64.ld create mode 100644 core/time/time_essence.odin (limited to 'src/ir.cpp') diff --git a/core/os/os_essence.odin b/core/os/os_essence.odin index 2fe62b873..e087a3de3 100644 --- a/core/os/os_essence.odin +++ b/core/os/os_essence.odin @@ -1,180 +1,1350 @@ -package os +package os; +EsData :: struct { _private : [4]rawptr, } +EsGeneric :: rawptr; +EsElement :: struct { _private : u8, }; +EsObject :: rawptr; +EsLongDouble :: struct { value : [10]u8, }; +EsNodeType :: u64; +EsError :: int; +EsHandle :: uint; +EsResponse :: i32; +EsFileOffset :: u64; +EsListViewIndex :: i32; +EsThreadEntryFunction :: distinct #type proc (EsGeneric); +EsComparisonCallbackFunction :: distinct #type proc (rawptr, rawptr, EsGeneric) -> i32; +EsSwapCallbackFunction :: distinct #type proc (rawptr, rawptr, EsGeneric); +EsCRTComparisonCallback :: distinct #type proc (rawptr, rawptr) -> i32; +EsMessageCallbackFunction :: distinct #type proc (EsObject, ^EsMessage, ^EsResponse); +EsUICallbackFunction :: distinct #type proc (^EsElement, ^EsMessage, ^EsResponse); +ES_SCANCODE_A :: (0x1C); +ES_SCANCODE_B :: (0x32); +ES_SCANCODE_C :: (0x21); +ES_SCANCODE_D :: (0x23); +ES_SCANCODE_E :: (0x24); +ES_SCANCODE_F :: (0x2B); +ES_SCANCODE_G :: (0x34); +ES_SCANCODE_H :: (0x33); +ES_SCANCODE_I :: (0x43); +ES_SCANCODE_J :: (0x3B); +ES_SCANCODE_K :: (0x42); +ES_SCANCODE_L :: (0x4B); +ES_SCANCODE_M :: (0x3A); +ES_SCANCODE_N :: (0x31); +ES_SCANCODE_O :: (0x44); +ES_SCANCODE_P :: (0x4D); +ES_SCANCODE_Q :: (0x15); +ES_SCANCODE_R :: (0x2D); +ES_SCANCODE_S :: (0x1B); +ES_SCANCODE_T :: (0x2C); +ES_SCANCODE_U :: (0x3C); +ES_SCANCODE_V :: (0x2A); +ES_SCANCODE_W :: (0x1D); +ES_SCANCODE_X :: (0x22); +ES_SCANCODE_Y :: (0x35); +ES_SCANCODE_Z :: (0x1A); +ES_SCANCODE_0 :: (0x45); +ES_SCANCODE_1 :: (0x16); +ES_SCANCODE_2 :: (0x1E); +ES_SCANCODE_3 :: (0x26); +ES_SCANCODE_4 :: (0x25); +ES_SCANCODE_5 :: (0x2E); +ES_SCANCODE_6 :: (0x36); +ES_SCANCODE_7 :: (0x3D); +ES_SCANCODE_8 :: (0x3E); +ES_SCANCODE_9 :: (0x46); +ES_SCANCODE_CAPS_LOCK :: (0x58); +ES_SCANCODE_SCROLL_LOCK :: (0x7E); +ES_SCANCODE_NUM_LOCK :: (0x77) ; +ES_SCANCODE_LEFT_SHIFT :: (0x12); +ES_SCANCODE_LEFT_CTRL :: (0x14); +ES_SCANCODE_LEFT_ALT :: (0x11); +ES_SCANCODE_LEFT_FLAG :: (0x11F); +ES_SCANCODE_RIGHT_SHIFT :: (0x59); +ES_SCANCODE_RIGHT_CTRL :: (0x114); +ES_SCANCODE_RIGHT_ALT :: (0x111); +ES_SCANCODE_PAUSE :: (0xE1); +ES_SCANCODE_CONTEXT_MENU :: (0x127); +ES_SCANCODE_BACKSPACE :: (0x66); +ES_SCANCODE_ESCAPE :: (0x76); +ES_SCANCODE_INSERT :: (0x170); +ES_SCANCODE_HOME :: (0x16C); +ES_SCANCODE_PAGE_UP :: (0x17D); +ES_SCANCODE_DELETE :: (0x171); +ES_SCANCODE_END :: (0x169); +ES_SCANCODE_PAGE_DOWN :: (0x17A); +ES_SCANCODE_UP_ARROW :: (0x175); +ES_SCANCODE_LEFT_ARROW :: (0x16B); +ES_SCANCODE_DOWN_ARROW :: (0x172); +ES_SCANCODE_RIGHT_ARROW :: (0x174); +ES_SCANCODE_SPACE :: (0x29); +ES_SCANCODE_TAB :: (0x0D); +ES_SCANCODE_ENTER :: (0x5A); +ES_SCANCODE_SLASH :: (0x4A); +ES_SCANCODE_BACKSLASH :: (0x5D); +ES_SCANCODE_LEFT_BRACE :: (0x54); +ES_SCANCODE_RIGHT_BRACE :: (0x5B); +ES_SCANCODE_EQUALS :: (0x55); +ES_SCANCODE_BACKTICK :: (0x0E); +ES_SCANCODE_HYPHEN :: (0x4E); +ES_SCANCODE_SEMICOLON :: (0x4C); +ES_SCANCODE_QUOTE :: (0x52); +ES_SCANCODE_COMMA :: (0x41); +ES_SCANCODE_PERIOD :: (0x49); +ES_SCANCODE_NUM_DIVIDE :: (0x14A); +ES_SCANCODE_NUM_MULTIPLY :: (0x7C); +ES_SCANCODE_NUM_SUBTRACT :: (0x7B); +ES_SCANCODE_NUM_ADD :: (0x79); +ES_SCANCODE_NUM_ENTER :: (0x15A); +ES_SCANCODE_NUM_POINT :: (0x71); +ES_SCANCODE_NUM_0 :: (0x70); +ES_SCANCODE_NUM_1 :: (0x69); +ES_SCANCODE_NUM_2 :: (0x72); +ES_SCANCODE_NUM_3 :: (0x7A); +ES_SCANCODE_NUM_4 :: (0x6B); +ES_SCANCODE_NUM_5 :: (0x73); +ES_SCANCODE_NUM_6 :: (0x74); +ES_SCANCODE_NUM_7 :: (0x6C); +ES_SCANCODE_NUM_8 :: (0x75); +ES_SCANCODE_NUM_9 :: (0x7D); +ES_SCANCODE_PRINT_SCREEN_1 :: (0x112) ; +ES_SCANCODE_PRINT_SCREEN_2 :: (0x17C); +ES_SCANCODE_F1 :: (0x05); +ES_SCANCODE_F2 :: (0x06); +ES_SCANCODE_F3 :: (0x04); +ES_SCANCODE_F4 :: (0x0C); +ES_SCANCODE_F5 :: (0x03); +ES_SCANCODE_F6 :: (0x0B); +ES_SCANCODE_F7 :: (0x83); +ES_SCANCODE_F8 :: (0x0A); +ES_SCANCODE_F9 :: (0x01); +ES_SCANCODE_F10 :: (0x09); +ES_SCANCODE_F11 :: (0x78); +ES_SCANCODE_F12 :: (0x07); +ES_SCANCODE_ACPI_POWER :: (0x137); +ES_SCANCODE_ACPI_SLEEP :: (0x13F); +ES_SCANCODE_ACPI_WAKE :: (0x15E); +ES_SCANCODE_MM_NEXT :: (0x14D); +ES_SCANCODE_MM_PREVIOUS :: (0x115); +ES_SCANCODE_MM_STOP :: (0x13B); +ES_SCANCODE_MM_PAUSE :: (0x134); +ES_SCANCODE_MM_MUTE :: (0x123); +ES_SCANCODE_MM_QUIETER :: (0x121); +ES_SCANCODE_MM_LOUDER :: (0x132); +ES_SCANCODE_MM_SELECT :: (0x150); +ES_SCANCODE_MM_EMAIL :: (0x148); +ES_SCANCODE_MM_CALC :: (0x12B); +ES_SCANCODE_MM_FILES :: (0x140); +ES_SCANCODE_WWW_SEARCH :: (0x110); +ES_SCANCODE_WWW_HOME :: (0x13A); +ES_SCANCODE_WWW_BACK :: (0x138); +ES_SCANCODE_WWW_FORWARD :: (0x130); +ES_SCANCODE_WWW_STOP :: (0x128); +ES_SCANCODE_WWW_REFRESH :: (0x120); +ES_SCANCODE_WWW_STARRED :: (0x118); +ES_PROCESS_STATE_ALL_THREADS_TERMINATED :: (1); +ES_PROCESS_STATE_TERMINATING :: (2); +ES_PROCESS_STATE_CRASHED :: (4); +ES_FLAGS_DEFAULT :: (0); +ES_SUCCESS :: (-1); +ES_ERROR_BUFFER_TOO_SMALL :: (-2); +ES_ERROR_UNKNOWN_OPERATION_FAILURE :: (-7); +ES_ERROR_NO_MESSAGES_AVAILABLE :: (-9); +ES_ERROR_MESSAGE_QUEUE_FULL :: (-10); +ES_ERROR_MESSAGE_NOT_HANDLED_BY_GUI :: (-13); +ES_ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME :: (-14); +ES_ERROR_PATH_NOT_TRAVERSABLE :: (-15); +ES_ERROR_FILE_ALREADY_EXISTS :: (-19); +ES_ERROR_FILE_DOES_NOT_EXIST :: (-20); +ES_ERROR_DRIVE_ERROR_FILE_DAMAGED :: (-21) ; +ES_ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS :: (-22) ; +ES_ERROR_FILE_PERMISSION_NOT_GRANTED :: (-23); +ES_ERROR_FILE_IN_EXCLUSIVE_USE :: (-24); +ES_ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE :: (-25); +ES_ERROR_INCORRECT_NODE_TYPE :: (-26); +ES_ERROR_EVENT_NOT_SET :: (-27); +ES_ERROR_TIMEOUT_REACHED :: (-29); +ES_ERROR_REQUEST_CLOSED_BEFORE_COMPLETE :: (-30); +ES_ERROR_NO_CHARACTER_AT_COORDINATE :: (-31); +ES_ERROR_FILE_ON_READ_ONLY_VOLUME :: (-32); +ES_ERROR_USER_CANCELED_IO :: (-33); +ES_ERROR_INVALID_DIMENSIONS :: (-34); +ES_ERROR_DRIVE_CONTROLLER_REPORTED :: (-35); +ES_ERROR_COULD_NOT_ISSUE_PACKET :: (-36); +ES_ERROR_HANDLE_TABLE_FULL :: (-37); +ES_ERROR_COULD_NOT_RESIZE_FILE :: (-38); +ES_ERROR_DIRECTORY_NOT_EMPTY :: (-39); +ES_ERROR_UNSUPPORTED_FILESYSTEM :: (-40); +ES_ERROR_NODE_ALREADY_DELETED :: (-41); +ES_ERROR_NODE_IS_ROOT :: (-42); +ES_ERROR_VOLUME_MISMATCH :: (-43); +ES_ERROR_TARGET_WITHIN_SOURCE :: (-44); +ES_ERROR_TARGET_INVALID_TYPE :: (-45); +ES_ERROR_NOTHING_TO_DRAW :: (-46); +ES_ERROR_MALFORMED_NODE_PATH :: (-47); +ES_ERROR_OUT_OF_CACHE_RESOURCES :: (-48); +ES_ERROR_TARGET_IS_SOURCE :: (-49); +ES_ERROR_INVALID_NAME :: (-50); +ES_ERROR_CORRUPT_DATA :: (-51); +ES_ERROR_INSUFFICIENT_RESOURCES :: (-52); +ES_ERROR_UNSUPPORTED_FEATURE :: (-53); +ES_ERROR_FILE_TOO_FRAGMENTED :: (-54); +ES_ERROR_DRIVE_FULL :: (-55); +ES_ERROR_COULD_NOT_RESOLVE_SYMBOL :: (-56); +ES_ERROR_ALREADY_EMBEDDED :: (-57); +ES_SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND :: (0); +ES_SYSTEM_CONSTANT_NO_FANCY_GRAPHICS :: (2); +ES_SYSTEM_CONSTANT_REPORTED_PROBLEMS :: (3); +ES_INVALID_HANDLE :: ((EsHandle) (0)); +ES_CURRENT_THREAD :: ((EsHandle) (0x10)); +ES_CURRENT_PROCESS :: ((EsHandle) (0x11)); +ES_SURFACE_UI_SHEET :: ((EsHandle) (0x20)); +ES_SURFACE_WALLPAPER :: ((EsHandle) (0x21)); +ES_DRAW_ALPHA_OVERWRITE :: (0x100); +ES_DRAW_ALPHA_FULL :: (0x200) ; +ES_WAIT_NO_TIMEOUT :: (-1); +ES_MAX_WAIT_COUNT :: (16); +ES_MAX_DIRECTORY_CHILD_NAME_LENGTH :: (256); +ES_PROCESS_EXECUTABLE_NOT_LOADED :: 0; +ES_PROCESS_EXECUTABLE_FAILED_TO_LOAD :: 1; +ES_PROCESS_EXECUTABLE_LOADED :: 2; +ES_SNAPSHOT_MAX_PROCESS_NAME_LENGTH :: (80); +ES_SYSTEM_SNAPSHOT_PROCESSES :: (1); +ES_SYSTEM_SNAPSHOT_DRIVES :: (2); +ES_NOT_HANDLED :: (-1); +ES_HANDLED :: (0); +ES_REJECTED :: (-2); +ES_SHARED_MEMORY_MAXIMUM_SIZE :: ( (1024) * 1024 * 1024 * 1024); +ES_SHARED_MEMORY_NAME_MAX_LENGTH :: (32); +ES_MAP_OBJECT_ALL :: (0); +ES_DRAW_STRING_HALIGN_LEFT :: (1); +ES_DRAW_STRING_HALIGN_RIGHT :: (2); +ES_DRAW_STRING_HALIGN_CENTER :: (3); +ES_DRAW_STRING_VALIGN_TOP :: (4); +ES_DRAW_STRING_VALIGN_BOTTOM :: (8); +ES_DRAW_STRING_VALIGN_CENTER :: (12); +ES_DRAW_STRING_CLIP :: (0); +ES_DRAW_STRING_WORD_WRAP :: (16); +ES_DRAW_STRING_ELLIPSIS :: (32); +ES_NODE_READ_NONE :: (0x0); +ES_NODE_READ_BLOCK :: (0x1); +ES_NODE_READ_ACCESS :: (0x2); +ES_NODE_READ_EXCLUSIVE :: (0x3); +ES_NODE_WRITE_NONE :: (0x00); +ES_NODE_WRITE_BLOCK :: (0x10); +ES_NODE_WRITE_ACCESS :: (0x20); +ES_NODE_WRITE_EXCLUSIVE :: (0x30); +ES_NODE_RESIZE_NONE :: (0x000); +ES_NODE_RESIZE_BLOCK :: (0x100); +ES_NODE_RESIZE_ACCESS :: (0x200); +ES_NODE_RESIZE_EXCLUSIVE :: (0x300); +ES_NODE_FAIL_IF_FOUND :: (0x1000); +ES_NODE_FAIL_IF_NOT_FOUND :: (0x2000); +ES_NODE_CREATE_DIRECTORIES :: (0x8000) ; +ES_NODE_POSIX_NAMESPACE :: (0x10000) ; +ES_DIRECTORY_CHILDREN_UNKNOWN :: ( (-1)); +ES_MEMORY_OPEN_FAIL_IF_FOUND :: (0x1000); +ES_MEMORY_OPEN_FAIL_IF_NOT_FOUND :: (0x2000); +ES_MAP_OBJECT_READ_WRITE :: (0); +ES_MAP_OBJECT_READ_ONLY :: (1); +ES_MAP_OBJECT_COPY_ON_WRITE :: (2); +ES_BOX_STYLE_OUTWARDS :: (0x01) ; +ES_BOX_STYLE_INWARDS :: (0x02) ; +ES_BOX_STYLE_NEUTRAL :: (0x03) ; +ES_BOX_STYLE_FLAT :: (0x04) ; +ES_BOX_STYLE_NONE :: (0x05) ; +ES_BOX_STYLE_SELECTED :: (0x06) ; +ES_BOX_STYLE_PUSHED :: (0x07) ; +ES_BOX_STYLE_DOTTED :: (0x80); +ES_BOX_COLOR_GRAY :: (0xC0C0C0); +ES_BOX_COLOR_DARK_GRAY :: (0x808080); +ES_BOX_COLOR_WHITE :: (0xFFFFFF); +ES_BOX_COLOR_BLUE :: (0x000080); +ES_BOX_COLOR_TRANSPARENT :: (0xFF00FF); +ES_BOX_COLOR_BLACK :: (0x000000); +ES_STRING_FORMAT_ENOUGH_SPACE :: ( (-1)); +ES_POSIX_SYSCALL_GET_POSIX_FD_PATH :: (0x10000); +ES_SURFACE_FULL_ALPHA :: (1); +ES_PERMISSION_ACCESS_SYSTEM_FILES :: (1 << 0); +ES_PERMISSION_ACCESS_USER_FILES :: (1 << 1); +ES_PERMISSION_PROCESS_CREATE :: (1 << 2); +ES_PERMISSION_PROCESS_OPEN :: (1 << 3); +ES_PERMISSION_SCREEN_MODIFY :: (1 << 4) ; +ES_PERMISSION_SHUTDOWN :: (1 << 5); +ES_PERMISSION_TAKE_SYSTEM_SNAPSHOT :: (1 << 6); +ES_PERMISSION_WINDOW_OPEN :: (1 << 7); +ES_PERMISSION_ALL :: ( (-1)); +ES_PERMISSION_INHERIT :: ( (1 << 63)); +ES_PANEL_WRAP :: ( (0x0001) << 32); +ES_PANEL_H_LEFT :: ( (0x0010) << 32); +ES_PANEL_H_RIGHT :: ( (0x0020) << 32); +ES_PANEL_H_CENTER :: ( (0x0040) << 32); +ES_PANEL_H_JUSTIFY :: ( (0x0080) << 32); +ES_PANEL_V_TOP :: ( (0x0100) << 32); +ES_PANEL_V_BOTTOM :: ( (0x0200) << 32); +ES_PANEL_V_CENTER :: ( (0x0400) << 32); +ES_PANEL_V_JUSTIFY :: ( (0x0800) << 32); +ES_PANEL_H_SCROLL :: ( (0x1000) << 32); +ES_PANEL_V_SCROLL :: ( (0x2000) << 32); +ES_CELL_H_PUSH :: ( (0x0001) << 16); +ES_CELL_H_EXPAND :: ( (0x0002) << 16); +ES_CELL_H_LEFT :: ( (0x0004) << 16); +ES_CELL_H_RIGHT :: ( (0x0008) << 16); +ES_CELL_H_SHRINK :: ( (0x0010) << 16); +ES_CELL_V_PUSH :: ( (0x0100) << 16); +ES_CELL_V_EXPAND :: ( (0x0200) << 16); +ES_CELL_V_TOP :: ( (0x0400) << 16); +ES_CELL_V_BOTTOM :: ( (0x0800) << 16); +ES_CELL_V_SHRINK :: ( (0x1000) << 16); +ES_CELL_NEW_BAND :: ( (0x8000) << 16); +ES_CELL_HIDDEN :: ( (0xFFFF) << 16); +ES_ELEMENT_DO_NOT_FREE_STYLE_OVERRIDE :: (1 << 0); +ES_ELEMENT_RICH_TEXT :: (1 << 1); +ES_ELEMENT_FOCUSABLE :: (1 << 2); +ES_ELEMENT_Z_STACK :: (1 << 3) ; +ES_ELEMENT_HIDDEN :: (1 << 4); +ES_ELEMENT_USE_CHILD_AS_PARENT :: (1 << 5) ; +ES_TEXTBOX_MULTILINE :: (1 << 0); +ES_TEXTBOX_BORDERED :: (1 << 1); +ES_BUTTON_DEFAULT :: ( (1) << 32); +ES_BUTTON_DANGEROUS :: ( (1) << 33); +ES_SCROLLBAR_VERTICAL :: ( (0) << 32); +ES_SCROLLBAR_HORIZONTAL :: ( (1) << 32); +ES_LIST_VIEW_INDEX_GROUP_HEADER :: (-1); +ES_LIST_VIEW_ITEM_CONTENT_TEXT :: (1 << 0); +ES_LIST_VIEW_ITEM_CONTENT_ICON :: (1 << 1); +ES_LIST_VIEW_ITEM_CONTENT_INDENTATION :: (1 << 2); +ES_LIST_VIEW_ITEM_STATE_SELECTED :: (1 << 0); +ES_LIST_VIEW_ITEM_STATE_CHECKED :: (1 << 1); +ES_LIST_VIEW_ITEM_STATE_HIDDEN :: (1 << 2); +ES_LIST_VIEW_ITEM_STATE_EXPANDABLE :: (1 << 3); +ES_LIST_VIEW_ITEM_STATE_CHECKABLE :: (1 << 4); +ES_LIST_VIEW_ITEM_STATE_DROP_TARGET :: (1 << 5); +ES_LIST_VIEW_ITEM_STATE_COLLAPSABLE :: (1 << 6); +ES_LIST_VIEW_ITEM_STATE_PARTIAL_CHECK :: (1 << 7); +ES_LIST_VIEW_ITEM_STATE_DRAG_SOURCE :: (1 << 8); +ES_LIST_VIEW_ITEM_STATE_CUT :: (1 << 9); +ES_LIST_VIEW_FIND_ITEM_FROM_Y_POSITION :: (0); +ES_LIST_VIEW_FIND_ITEM_FROM_TEXT_PREFIX :: (1); +ES_LIST_VIEW_FIND_ITEM_NON_HIDDEN :: (2); +ES_LIST_VIEW_FIND_ITEM_PARENT :: (3); +ES_LIST_VIEW_COLUMN_DEFAULT_WIDTH_PRIMARY :: (300); +ES_LIST_VIEW_COLUMN_DEFAULT_WIDTH_SECONDARY :: (150); +ES_LIST_VIEW_COLUMN_PRIMARY :: (1); +ES_LIST_VIEW_COLUMN_RIGHT_ALIGNED :: (2); +ES_LIST_VIEW_COLUMN_SORT_ASCENDING :: (8); +ES_LIST_VIEW_COLUMN_SORT_DESCENDING :: (16); +ES_LIST_VIEW_COLUMN_SORTABLE :: (32); +ES_LIST_VIEW_SINGLE_SELECT :: (1 << 0) ; +ES_LIST_VIEW_MULTI_SELECT :: (1 << 1) ; +ES_LIST_VIEW_HAS_COLUMNS :: (1 << 2) ; +ES_LIST_VIEW_HAS_GROUPS :: (1 << 3) ; +ES_LIST_VIEW_FIXED_HEIGHT :: (1 << 4) ; +ES_LIST_VIEW_VARIABLE_HEIGHT :: (1 << 5) ; +ES_LIST_VIEW_TREE :: (1 << 6) ; +ES_LIST_VIEW_TILED :: (1 << 7) ; +ES_LIST_VIEW_ALT_BACKGROUND :: (1 << 8) ; +ES_LIST_VIEW_BORDERED :: (1 << 9) ; +ES_LIST_VIEW_NO_BACKGROUND :: (1 << 10) ; +ES_LIST_VIEW_DROP_TARGET_ORDERED :: (1 << 11) ; +ES_LIST_VIEW_DROP_TARGET_UNORDERED :: (1 << 12) ; +ES_LIST_VIEW_ROW_DIVIDERS :: (1 << 13) ; +ES_LIST_VIEW_STATIC_GROUP_HEADERS :: (1 << 14) ; +ES_LIST_VIEW_COLLAPSABLE_GROUPS :: (1 << 15) ; +ES_LIST_VIEW_INTERNAL_SELECTION_STORAGE :: (1 << 16) ; +ES_LIST_VIEW_HAND_CURSOR :: (1 << 17) ; +ES_LIST_VIEW_NO_ITEM_BACKGROUNDS :: (1 << 18) ; +ES_LIST_VIEW_RICH_TEXT :: (1 << 20) ; +ES_LIST_VIEW_LABELS_BELOW :: (1 << 21) ; +ES_LIST_VIEW_MAXIMUM_ITEMS :: (10 * 1000 * 1000); +ES_LIST_VIEW_MAXIMUM_GROUPS :: (10 * 1000); +ES_LIST_VIEW_TRANSITION_BACKWARDS :: (1); +ES_LIST_VIEW_TRANSITION_DRAW_NEW_CONTENTS_ONCE :: (2) ; +EsFatalError :: enum { + ES_FATAL_ERROR_INVALID_BUFFER, + ES_FATAL_ERROR_UNKNOWN_SYSCALL, + ES_FATAL_ERROR_INVALID_MEMORY_REGION, + ES_FATAL_ERROR_MEMORY_REGION_LOCKED_BY_KERNEL, + ES_FATAL_ERROR_PATH_LENGTH_EXCEEDS_LIMIT, + ES_FATAL_ERROR_INVALID_HANDLE, + ES_FATAL_ERROR_MUTEX_NOT_ACQUIRED_BY_THREAD, + ES_FATAL_ERROR_MUTEX_ALREADY_ACQUIRED, + ES_FATAL_ERROR_BUFFER_NOT_ACCESSIBLE, + ES_FATAL_ERROR_SHARED_MEMORY_REGION_TOO_LARGE, + ES_FATAL_ERROR_SHARED_MEMORY_STILL_MAPPED, + ES_FATAL_ERROR_COULD_NOT_LOAD_FONT, + ES_FATAL_ERROR_COULD_NOT_DRAW_FONT, + ES_FATAL_ERROR_COULD_NOT_ALLOCATE_MEMORY, + ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, + ES_FATAL_ERROR_TOO_MANY_WAIT_OBJECTS, + ES_FATAL_ERROR_INCORRECT_NODE_TYPE, + ES_FATAL_ERROR_PROCESSOR_EXCEPTION, + ES_FATAL_ERROR_UNKNOWN, + ES_FATAL_ERROR_RECURSIVE_BATCH, + ES_FATAL_ERROR_CORRUPT_HEAP, + ES_FATAL_ERROR_CORRUPT_LINKED_LIST, + ES_FATAL_ERROR_INDEX_OUT_OF_BOUNDS, + ES_FATAL_ERROR_INVALID_STRING_LENGTH, + ES_FATAL_ERROR_SPINLOCK_NOT_ACQUIRED, + ES_FATAL_ERROR_UNKNOWN_SNAPSHOT_TYPE, + ES_FATAL_ERROR_PROCESS_ALREADY_ATTACHED, + ES_FATAL_ERROR_INTERNAL, + ES_FATAL_ERROR_INSUFFICIENT_PERMISSIONS, + ES_FATAL_ERROR_ABORT, + ES_FATAL_ERROR_COUNT, +} -OS :: "essence"; +EsSyscallType :: enum { + ES_SYSCALL_ALLOCATE, + ES_SYSCALL_FREE, + ES_SYSCALL_SHARE_MEMORY, + ES_SYSCALL_MAP_OBJECT, + ES_SYSCALL_OPEN_SHARED_MEMORY, + ES_SYSCALL_CREATE_PROCESS, + ES_SYSCALL_GET_CREATION_ARGUMENT, + ES_SYSCALL_TERMINATE_THREAD, + ES_SYSCALL_CREATE_THREAD, + ES_SYSCALL_WAIT, + ES_SYSCALL_TERMINATE_PROCESS, + ES_SYSCALL_CREATE_EVENT, + ES_SYSCALL_SET_EVENT, + ES_SYSCALL_RESET_EVENT, + ES_SYSCALL_POLL_EVENT, + ES_SYSCALL_PAUSE_PROCESS, + ES_SYSCALL_CRASH_PROCESS, + ES_SYSCALL_GET_THREAD_ID, + ES_SYSCALL_GET_PROCESS_STATE, + ES_SYSCALL_YIELD_SCHEDULER, + ES_SYSCALL_SLEEP, + ES_SYSCALL_OPEN_PROCESS, + ES_SYSCALL_SET_TLS, + ES_SYSCALL_TIMER_SET, + ES_SYSCALL_TIMER_CREATE, + ES_SYSCALL_GET_PROCESS_STATUS, + ES_SYSCALL_CREATE_SURFACE, + ES_SYSCALL_GET_LINEAR_BUFFER, + ES_SYSCALL_INVALIDATE_RECTANGLE, + ES_SYSCALL_COPY_TO_SCREEN, + ES_SYSCALL_FORCE_SCREEN_UPDATE, + ES_SYSCALL_FILL_RECTANGLE, + ES_SYSCALL_COPY_SURFACE, + ES_SYSCALL_CLEAR_MODIFIED_REGION, + ES_SYSCALL_DRAW_SURFACE, + ES_SYSCALL_REDRAW_ALL, + ES_SYSCALL_DRAW_BOX, + ES_SYSCALL_DRAW_BITMAP, + ES_SYSCALL_SURFACE_RESET, + ES_SYSCALL_SURFACE_SHARE, + ES_SYSCALL_DRAW_STYLED_BOX, + ES_SYSCALL_SURFACE_SCROLL, + ES_SYSCALL_RESIZE_SURFACE, + ES_SYSCALL_GET_MESSAGE, + ES_SYSCALL_POST_MESSAGE, + ES_SYSCALL_POST_MESSAGE_REMOTE, + ES_SYSCALL_WAIT_MESSAGE, + ES_SYSCALL_CREATE_WINDOW, + ES_SYSCALL_UPDATE_WINDOW, + ES_SYSCALL_SET_CURSOR_STYLE, + ES_SYSCALL_MOVE_WINDOW, + ES_SYSCALL_GET_WINDOW_BOUNDS, + ES_SYSCALL_RESET_CLICK_CHAIN, + ES_SYSCALL_GET_CURSOR_POSITION, + ES_SYSCALL_SET_CURSOR_POSITION, + ES_SYSCALL_COPY, + ES_SYSCALL_GET_CLIPBOARD_HEADER, + ES_SYSCALL_PASTE_TEXT, + ES_SYSCALL_SET_FOCUSED_WINDOW, + ES_SYSCALL_SET_WINDOW_TITLE, + ES_SYSCALL_GET_SCREEN_BOUNDS, + ES_SYSCALL_WINDOW_OPEN, + ES_SYSCALL_WINDOW_SET_BLEND_BOUNDS, + ES_SYSCALL_WINDOW_GET_BLEND_BOUNDS, + ES_SYSCALL_WINDOW_GET_ID, + ES_SYSCALL_SET_WINDOW_ALPHA, + ES_SYSCALL_DOCKED_WINDOW_CREATE, + ES_SYSCALL_WINDOW_SHARE, + ES_SYSCALL_SET_EMBED_WINDOW, + ES_SYSCALL_OPEN_NODE, + ES_SYSCALL_READ_FILE_SYNC, + ES_SYSCALL_WRITE_FILE_SYNC, + ES_SYSCALL_RESIZE_FILE, + ES_SYSCALL_REFRESH_NODE_INFORMATION, + ES_SYSCALL_ENUMERATE_DIRECTORY_CHILDREN, + ES_SYSCALL_DELETE_NODE, + ES_SYSCALL_MOVE_NODE, + ES_SYSCALL_READ_CONSTANT_BUFFER, + ES_SYSCALL_SHARE_CONSTANT_BUFFER, + ES_SYSCALL_CREATE_CONSTANT_BUFFER, + ES_SYSCALL_EXECUTE, + ES_SYSCALL_INSTANCE_CREATE_REMOTE, + ES_SYSCALL_MAILSLOT_SEND_DATA, + ES_SYSCALL_MAILSLOT_SEND_MESSAGE, + ES_SYSCALL_MAILSLOT_SHARE, + ES_SYSCALL_PIPE_CREATE, + ES_SYSCALL_PIPE_WRITE, + ES_SYSCALL_PIPE_READ, + ES_SYSCALL_USER_GET_HOME_FOLDER, + ES_SYSCALL_USER_LOGIN, + ES_SYSCALL_GET_SYSTEM_CONSTANTS, + ES_SYSCALL_TAKE_SYSTEM_SNAPSHOT, + ES_SYSCALL_SET_SYSTEM_CONSTANT, + ES_SYSCALL_GET_SYSTEM_INFORMATION, + ES_SYSCALL_PRINT, + ES_SYSCALL_CLOSE_HANDLE, + ES_SYSCALL_BATCH, + ES_SYSCALL_SHUTDOWN, + ES_SYSCALL_POSIX, + ES_SYSCALL_COUNT, +} -foreign import api "system:api" +EsStandardFont :: enum { + ES_STANDARD_FONT_REGULAR, + ES_STANDARD_FONT_BOLD, + ES_STANDARD_FONT_MONOSPACED, +} -Handle :: distinct int; -Errno :: distinct int; +EsMessageType :: enum { + ES_MESSAGE_WM_START = 0x1000, + ES_MESSAGE_MOUSE_MOVED = 0x1001, + ES_MESSAGE_WINDOW_ACTIVATED = 0x1003, + ES_MESSAGE_WINDOW_DEACTIVATED = 0x1004, + ES_MESSAGE_WINDOW_DESTROYED = 0x1005, + ES_MESSAGE_MOUSE_EXIT = 0x1006 , + ES_MESSAGE_CLICK_REPEAT = 0x1009, + ES_MESSAGE_WINDOW_RESIZED = 0x100B, + ES_MESSAGE_MOUSE_LEFT_PRESSED = 0x100C , + ES_MESSAGE_MOUSE_LEFT_RELEASED = 0x100D, + ES_MESSAGE_MOUSE_RIGHT_PRESSED = 0x100E, + ES_MESSAGE_MOUSE_RIGHT_RELEASED = 0x100F, + ES_MESSAGE_MOUSE_MIDDLE_PRESSED = 0x1010, + ES_MESSAGE_MOUSE_MIDDLE_RELEASED = 0x1011 , + ES_MESSAGE_KEY_PRESSED = 0x1012, + ES_MESSAGE_KEY_RELEASED = 0x1013, + ES_MESSAGE_UPDATE_WINDOW = 0x1014, + ES_MESSAGE_WM_END = 0x13FF, + ES_MESSAGE_PAINT = 0x2000 , + ES_MESSAGE_DESTROY = 0x2001 , + ES_MESSAGE_MEASURE = 0x2002 , + ES_MESSAGE_SIZE = 0x2003 , + ES_MESSAGE_ADD_CHILD = 0x2004 , + ES_MESSAGE_REMOVE_CHILD = 0x2005 , + ES_MESSAGE_HIT_TEST = 0x2006 , + ES_MESSAGE_HOVERED_START = 0x2007 , + ES_MESSAGE_HOVERED_END = 0x2008 , + ES_MESSAGE_PRESSED_START = 0x2009 , + ES_MESSAGE_PRESSED_END = 0x200A , + ES_MESSAGE_FOCUSED_START = 0x200B , + ES_MESSAGE_FOCUSED_END = 0x200C , + ES_MESSAGE_FOCUS_WITHIN_START = 0x200D , + ES_MESSAGE_FOCUS_WITHIN_END = 0x200E , + ES_MESSAGE_Z_ORDER = 0x2010 , + ES_MESSAGE_ANIMATE = 0x2011 , + ES_MESSAGE_MOUSE_DRAGGED = 0x2012 , + ES_MESSAGE_KEY_TYPED = 0x2013 , + ES_MESSAGE_PAINT_BACKGROUND = 0x2014 , + ES_MESSAGE_PAINT_FOREGROUND = 0x2015 , + ES_MESSAGE_ENSURE_VISIBLE = 0x2016 , + ES_MESSAGE_GET_CURSOR = 0x2017 , + ES_MESSAGE_WINDOW_CREATED = 0x2018 , + ES_MESSAGE_CLICKED = 0x3000 , + ES_MESSAGE_SCROLLBAR_MOVED = 0x3001 , + ES_MESSAGE_RECALCULATE_CONTENT_SIZE = 0x3002 , + ES_MESSAGE_DESKTOP_EXECUTE = 0x4800, + ES_MESSAGE_POWER_BUTTON_PRESSED = 0x4801, + ES_MESSAGE_TASKBAR_WINDOW_ADD = 0x4804, + ES_MESSAGE_TASKBAR_WINDOW_REMOVE = 0x4805, + ES_MESSAGE_TASKBAR_WINDOW_ACTIVATE = 0x4806, + ES_MESSAGE_TASKBAR_WINDOW_SET_TITLE = 0x4807, + ES_MESSAGE_DOCKED_WINDOW_CREATE = 0x4808, + ES_MESSAGE_PROGRAM_CRASH = 0x4C00, + ES_MESSAGE_PROGRAM_FAILED_TO_START = 0x4C01, + ES_MESSAGE_RECEIVE_DATA = 0x5100, + ES_MESSAGE_MAILSLOT_CLOSED = 0x5101, + ES_MESSAGE_CLIPBOARD_UPDATED = 0x5001, + ES_MESSAGE_SYSTEM_CONSTANT_UPDATED = 0x5004, + ES_MESSAGE_TIMER = 0x5006, + ES_MESSAGE_OBJECT_DESTROY = 0x5007, + ES_MESSAGE_LIST_VIEW_GET_ITEM_CONTENT = 0x6000, + ES_MESSAGE_LIST_VIEW_SET_ITEM_STATE = 0x6001, + ES_MESSAGE_LIST_VIEW_GET_ITEM_STATE = 0x6002, + ES_MESSAGE_LIST_VIEW_PAINT_ITEM = 0x6003 , + ES_MESSAGE_LIST_VIEW_PAINT_CELL = 0x6004 , + ES_MESSAGE_LIST_VIEW_SORT_COLUMN = 0x6005, + ES_MESSAGE_LIST_VIEW_CHOOSE_ITEM = 0x6006, + ES_MESSAGE_LIST_VIEW_FIND_ITEM = 0x6007, + ES_MESSAGE_LIST_VIEW_TOGGLE_DISCLOSURE = 0x6008, + ES_MESSAGE_LIST_VIEW_MEASURE_ITEM_HEIGHT = 0x6009, + ES_MESSAGE_LIST_VIEW_LAYOUT_ITEM = 0x600A, + ES_MESSAGE_LIST_VIEW_SET_ITEM_VISIBILITY = 0x600B, + ES_MESSAGE_LIST_VIEW_RELAY_MESSAGE = 0x600C, + ES_MESSAGE_LIST_VIEW_SET_ITEM_POSITION = 0x600D, + ES_MESSAGE_USER_START = 0x8000, + ES_MESSAGE_USER_END = 0xBFFF, +} -O_RDONLY :: 0x00001; -O_WRONLY :: 0x00002; -O_RDWR :: 0x00003; -O_CREATE :: 0x00040; -O_EXCL :: 0x00080; -O_TRUNC :: 0x00200; -O_APPEND :: 0x00400; +EsDrawMode :: enum { + ES_DRAW_MODE_REPEAT_FIRST = 1 , + ES_DRAW_MODE_STRECH, + ES_DRAW_MODE_REPEAT, + ES_DRAW_MODE_NONE, +} -ERROR_NONE :: Errno(-1); -ERROR_UNKNOWN_OPERATION_FAILURE :: Errno(-7); -ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME :: Errno(-14); -ERROR_PATH_NOT_FOUND :: Errno(-15); -ERROR_FILE_EXISTS :: Errno(-19); -ERROR_FILE_NOT_FOUND :: Errno(-20); -ERROR_DRIVE_ERROR_FILE_DAMAGED :: Errno(-21); -ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS :: Errno(-22); -ERROR_ACCESS_DENIED :: Errno(-23); -ERROR_FILE_IN_EXCLUSIVE_USE :: Errno(-24); -ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE :: Errno(-25); -ERROR_INCORRECT_NODE_TYPE :: Errno(-26); -ERROR_EVENT_NOT_SET :: Errno(-27); -ERROR_TIMEOUT_REACHED :: Errno(-29); -ERROR_REQUEST_CLOSED_BEFORE_COMPLETE :: Errno(-30); -ERROR_NO_CHARACTER_AT_COORDINATE :: Errno(-31); -ERROR_FILE_ON_READ_ONLY_VOLUME :: Errno(-32); -ERROR_USER_CANCELED_IO :: Errno(-33); -ERROR_DRIVE_CONTROLLER_REPORTED :: Errno(-35); -ERROR_COULD_NOT_ISSUE_PACKET :: Errno(-36); - -ERROR_NOT_IMPLEMENTED :: Errno(1); - -OS_Node_Type :: enum i32 { - File = 0, - Directory = 1, -} - -OS_Node_Information :: struct { - handle: Handle, - id: [16]byte, - ntype: OS_Node_Type, - size: i64, - - // Our additions.. - position: i64, -} - -foreign api { - @(link_name="OSPrintDirect") OSPrintDirect :: proc(str: ^u8, length: int) ---; - @(link_name="malloc") OSMalloc :: proc(bytes: int) -> rawptr ---; - @(link_name="free") OSFree :: proc(address: rawptr) ---; - @(link_name="OSOpenNode") OSOpenNode :: proc(path: ^u8, path_length: int, flags: u64, information: ^OS_Node_Information) -> Errno ---; - @(link_name="OSResizeFile") OSResizeFile :: proc(handle: Handle, new_size: u64) -> Errno ---; - @(link_name="OSCloseHandle") OSCloseHandle :: proc(handle: Handle) ---; - @(link_name="OSWriteFileSync") OSWriteFileSync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---; - @(link_name="OSReadFileSync") OSReadFileSync :: proc(handle: Handle, offset: i64, size: i64, buffer: rawptr) -> i64 ---; - @(link_name="realloc") OSRealloc :: proc(address: rawptr, size: int) -> rawptr ---; - @(link_name="OSGetThreadID") OSGetThreadID :: proc(handle: Handle) -> int ---; - @(link_name="OSRefreshNodeInformation") OSRefreshNodeInformation :: proc(information: ^OS_Node_Information) ---; -} - -stdin := Handle(-1); // Not implemented -stdout := Handle(0); -stderr := Handle(0); - -is_path_separator :: proc(r: rune) -> bool { - return r == '/'; +EsClipboardFormat :: enum { + ES_CLIPBOARD_FORMAT_EMPTY, + ES_CLIPBOARD_FORMAT_TEXT, + ES_CLIPBOARD_FORMAT_FILE_LIST, } -current_thread_id :: proc "contextless" () -> int { - return OSGetThreadID(Handle(0x1000)); +EsColorFormat :: enum { + ES_COLOR_FORMAT_32_XRGB, } -heap_alloc :: proc(size: int) -> rawptr { - return OSMalloc(size); +EsCursorStyle :: enum { + ES_CURSOR_NORMAL, + ES_CURSOR_TEXT, + ES_CURSOR_RESIZE_VERTICAL, + ES_CURSOR_RESIZE_HORIZONTAL, + ES_CURSOR_RESIZE_DIAGONAL_1, + ES_CURSOR_RESIZE_DIAGONAL_2, + ES_CURSOR_SPLIT_VERTICAL, + ES_CURSOR_SPLIT_HORIZONTAL, + ES_CURSOR_HAND_HOVER, + ES_CURSOR_HAND_DRAG, + ES_CURSOR_HAND_POINT, + ES_CURSOR_SCROLL_UP_LEFT, + ES_CURSOR_SCROLL_UP, + ES_CURSOR_SCROLL_UP_RIGHT, + ES_CURSOR_SCROLL_LEFT, + ES_CURSOR_SCROLL_CENTER, + ES_CURSOR_SCROLL_RIGHT, + ES_CURSOR_SCROLL_DOWN_LEFT, + ES_CURSOR_SCROLL_DOWN, + ES_CURSOR_SCROLL_DOWN_RIGHT, + ES_CURSOR_SELECT_LINES, + ES_CURSOR_DROP_TEXT, + ES_CURSOR_CROSS_HAIR_PICK, + ES_CURSOR_CROSS_HAIR_RESIZE, + ES_CURSOR_MOVE_HOVER, + ES_CURSOR_MOVE_DRAG, + ES_CURSOR_ROTATE_HOVER, + ES_CURSOR_ROTATE_DRAG, + ES_CURSOR_BLANK, } -heap_free :: proc(address: rawptr) { - OSFree(address); +EsWindowStyle :: enum { + ES_WINDOW_NORMAL, + ES_WINDOW_CONTAINER, + ES_WINDOW_MENU, } -heap_resize :: proc(address: rawptr, new_size: int) -> rawptr { - return OSRealloc(address, new_size); +ES_NODE_FILE :: (0); +ES_NODE_DIRECTORY :: (0x4000); +ES_NODE_INVALID :: (0x8000); +EsBatchCall :: struct { + index :EsSyscallType, + stopBatchIfError :bool, + using _ : struct #raw_union { + argument0 :uintptr, + returnValue :uintptr, + }, + + argument1 :uintptr, + argument2 :uintptr, + argument3 :uintptr, } -open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) { - flags : u64 = 0; +EsThreadInformation :: struct { + handle :EsHandle, + tid :uintptr, +} - if mode & O_CREATE == O_CREATE { - flags = flags | 0x9000; // Fail if found and create directories leading to the file if they don't exist - } else { - flags = flags | 0x2000; // Fail if not found - } +EsProcessInformation :: struct { + handle :EsHandle, + pid :uintptr, + mainThread :EsThreadInformation, +} - if mode & O_EXCL == O_EXCL { - flags = flags | 0x111; // Block opening the node for any reason - } +EsUniqueIdentifier :: struct { + using _ : struct #raw_union { + d :[16]u8, + }, - if mode & O_RDONLY == O_RDONLY { - flags = flags | 0x2; // Read access - } +} - if mode & O_WRONLY == O_WRONLY { - flags = flags | 0x220; // Write and resize access - } +EsNodeInformation :: struct { + handle :EsHandle, + type :EsNodeType, + using _ : struct #raw_union { + fileSize :EsFileOffset, + directoryChildren :EsFileOffset, + }, - if mode & O_TRUNC == O_TRUNC { - flags = flags | 0x200; // Resize access - } +} - information := new(OS_Node_Information); - error := OSOpenNode(&path[0], len(path), flags, information); +EsDirectoryChild :: struct { + name :[ES_MAX_DIRECTORY_CHILD_NAME_LENGTH]i8, + nameBytes :uintptr, + information :EsNodeInformation, +} + +EsPoint :: struct { + x :i32, + y :i32, +} + +EsRectangle :: struct { + left :i32, + right :i32, + top :i32, + bottom :i32, +} - if error < ERROR_NONE { - free(information); - return 0, error; - } +EsRectangle16 :: struct { + left :i16, + right :i16, + top :i16, + bottom :i16, +} - if mode & O_TRUNC == O_TRUNC { - error := OSResizeFile(information.handle, 0); - if error < ERROR_NONE do return 0, ERROR_UNKNOWN_OPERATION_FAILURE; - } +EsColor :: struct { + using _ : struct #raw_union { + using _ : struct { + blue :u8, + green :u8, + red :u8, + }, - if mode & O_APPEND == O_APPEND { - information.position = information.size; - } else { - information.position = 0; - } + combined :u32, + }, - return Handle(uintptr(information)), ERROR_NONE; } -close :: proc(fd: Handle) { - information := (^OS_Node_Information)(uintptr(fd)); - OSCloseHandle(information.handle); - free(information); +EsLinearBuffer :: struct { + width :uintptr, + height :uintptr, + stride :uintptr, + colorFormat :EsColorFormat, + handle :EsHandle, + flags :u32, } -file_size :: proc(fd: Handle) -> (i64, Errno) { - x: OS_Node_Information; - OSRefreshNodeInformation(&x); - return x.size, ERROR_NONE; +_EsRectangleAndColor :: struct { + rectangle :EsRectangle, + color :EsColor, } -write :: proc(fd: Handle, data: []byte) -> (int, Errno) { - if fd == 0 { - OSPrintDirect(&data[0], len(data)); - return len(data), ERROR_NONE; - } else if fd == 1 { - assert(false); - return 0, ERROR_NOT_IMPLEMENTED; - } +_EsStyledBoxData :: struct { + backgroundColor :u32, + borderColor :u32, + borderSize :u8, + cornerRadius :u8, + roundedCornersToExclude :u8, + ox :i32, + oy :i32, + width :i32, + height :i32, + clip :EsRectangle, +} + +_EsInstanceCreateRemoteArguments :: struct { + what :^i8, + argument :^i8, + whatBytes :uintptr, + argumentBytes :uintptr, + modalWindowParent :EsHandle, + apiInstance :^rawptr, +} + +_EsDrawSurfaceArguments :: struct { + source :EsRectangle, + destination :EsRectangle, + border :EsRectangle, + alpha :u16, +} + +EsSpinlock :: struct { + state :u8, +} + +EsMutex :: struct { + event :EsHandle, + spinlock :EsSpinlock, + state :u8, + queued :u32, +} + +EsCrashReason :: struct { + errorCode :EsError, +} + +EsProcessState :: struct { + crashReason :EsCrashReason, + creationArgument :EsGeneric, + id :uintptr, + executableState :uintptr, + flags :u8, +} + +EsIORequestProgress :: struct { + accessed :EsFileOffset, + progress :EsFileOffset, + completed :bool, + cancelled :bool, + error :EsError, +} + +EsClipboardHeader :: struct { + customBytes :uintptr, + format :EsClipboardFormat, + textBytes :uintptr, + unused :uintptr, +} + +EsPainter :: struct { + surface :EsHandle, + clip :EsRectangle, + offsetX :i32, + offsetY :i32, +} + +EsMessage :: struct { + type :EsMessageType, + _context :EsGeneric, + using _ : struct #raw_union { + _argument :^rawptr, + mouseMoved : struct { + oldPositionX :i32, + newPositionX :i32, + oldPositionY :i32, + newPositionY :i32, + newPositionXScreen :i32, + newPositionYScreen :i32, + }, + + mouseDragged : struct { + oldPositionX :i32, + newPositionX :i32, + oldPositionY :i32, + newPositionY :i32, + originalPositionX :i32, + originalPositionY :i32, + }, + + mousePressed : struct { + positionX :i32, + positionY :i32, + positionXScreen :i32, + positionYScreen :i32, + clickChainCount :u8, + activationClick :u8, + alt :u8, + ctrl :u8, + shift :u8, + }, + + keyboard : struct { + scancode :u32, + alt :u8, + ctrl :u8, + shift :u8, + numpad :u8, + notHandledBy :EsObject, + }, + + crash : struct { + reason :EsCrashReason, + process :EsHandle, + processNameBuffer :EsHandle, + processNameBytes :uintptr, + pid :uintptr, + }, + + clipboard :EsClipboardHeader, + receive : struct { + buffer :EsHandle, + bytes :uintptr, + }, + + animate : struct { + deltaMcs :i64, + waitMcs :i64, + complete :bool, + }, + + systemConstantUpdated : struct { + index :uintptr, + newValue :u64, + }, + + desktopExecute : struct { + whatBuffer :EsHandle, + argumentBuffer :EsHandle, + mailslot :EsHandle, + whatBytes :uintptr, + argumentBytes :uintptr, + modalWindowParent :u64, + }, + + dockedWindowCreate : struct { + pipe :EsHandle, + }, + + taskbar : struct { + id :u64, + buffer :EsHandle, + bytes :uintptr, + }, + + windowResized : struct { + content :EsRectangle, + }, + + painter :^EsPainter, + measure : struct { + width :i32, + height :i32, + }, + + child :EsObject, + size : struct { + width :i32, + height :i32, + }, + + hitTest : struct { + x :i32, + y :i32, + inside :bool, + }, + + zOrder : struct { + index :uintptr, + child :^EsElement, + }, + + scrollbarMoved : struct { + scroll :i32, + }, + + ensureVisible : struct { + child :^EsElement, + }, + + cursorStyle :EsCursorStyle, + getItemContent : struct { + mask :u32, + index :EsListViewIndex, + column :EsListViewIndex, + group :EsListViewIndex, + text :^i8, + textBytes :uintptr, + iconHash :u32, + iconWidth :u16, + iconHeight :u16, + indentation :u16, + spaceAfterIcon :u16, + }, + + accessItemState : struct { + mask :u32, + state :u32, + iIndexFrom :EsListViewIndex, + eIndexTo :EsListViewIndex, + group :EsListViewIndex, + }, + + measureItemHeight : struct { + iIndexFrom :EsListViewIndex, + eIndexTo :EsListViewIndex, + group :EsListViewIndex, + height :i32, + }, - information := (^OS_Node_Information)(uintptr(fd)); - count := OSWriteFileSync(information.handle, information.position, i64(len(data)), &data[0]); - if count < 0 do return 0, 1; - information.position += count; - return int(count), 0; + layoutItem : struct { + index :EsListViewIndex, + group :EsListViewIndex, + knownIndex :EsListViewIndex, + knownGroup :EsListViewIndex, + bounds :EsRectangle, + }, + + toggleItemDisclosure : struct { + index :EsListViewIndex, + group :EsListViewIndex, + }, + + findItem : struct { + type :u8, + backwards :u8, + inclusive :bool, + indexFrom :EsListViewIndex, + groupFrom :EsListViewIndex, + foundIndex :EsListViewIndex, + foundGroup :EsListViewIndex, + using _ : struct #raw_union { + using _ : struct { + prefix :^i8, + prefixBytes :uintptr, + }, + + using _ : struct { + yPosition :i32, + yPositionOfIndexFrom :i32, + offsetIntoItem :i32, + }, + + }, + + }, + + listViewColumn : struct { + index :EsListViewIndex, + descending :bool, + }, + + setItemVisibility : struct { + index :EsListViewIndex, + group :EsListViewIndex, + visible :bool, + }, + + setItemPosition : struct { + index :EsListViewIndex, + group :EsListViewIndex, + bounds :EsRectangle, + }, + + listViewPaint : struct { + surface :EsHandle, + bounds :EsRectangle, + clip :EsRectangle, + index :EsListViewIndex, + group :EsListViewIndex, + column :EsListViewIndex, + _internal :^rawptr, + }, + + }, + +} + +EsDebuggerMessage :: struct { + process :EsHandle, + reason :EsCrashReason, +} + +EsDriveInformation :: struct { + name :[64]i8, + nameBytes :uintptr, + mountpoint :[256]i8, + mountpointBytes :uintptr, +} + +EsSnapshotProcessesItem :: struct { + pid :i64, + memoryUsage :i64, + cpuTimeSlices :i64, + name :[ES_SNAPSHOT_MAX_PROCESS_NAME_LENGTH]i8, + nameLength :uintptr, + internal :u64, +} + +EsSystemInformation :: struct { + processCount :uintptr, + threadCount :uintptr, + handleCount :uintptr, + commitLimit :uintptr, + commit :uintptr, + countZeroedPages :uintptr, + countFreePages :uintptr, + countStandbyPages :uintptr, + countModifiedPages :uintptr, + countActivePages :uintptr, + coreHeapSize :uintptr, + coreHeapAllocations :uintptr, + fixedHeapSize :uintptr, + fixedHeapAllocations :uintptr, + coreRegions :uintptr, + kernelRegions :uintptr, +} + +EsSnapshotProcesses :: struct { + count :uintptr, + processes :[]EsSnapshotProcessesItem, +} + +_EsPOSIXSyscall :: struct { + index :int, + arguments :[7]int, +} + +EsProcessCreationArguments :: struct { + executablePath :^i8, + executablePathBytes :uintptr, + environmentBlock :^rawptr, + environmentBlockBytes :uintptr, + creationArgument :EsGeneric, + permissions :u64, +} + +_EsUserLoginArguments :: struct { + name :^i8, + nameBytes :uintptr, + home :^i8, + homeBytes :uintptr, +} + +EsInstance :: struct { + _private :^rawptr, +} + +EsListViewColumn :: struct { + title :^i8, + titleBytes :uintptr, + width :i32, + minimumWidth :i32, + flags :u32, +} + +EsListViewStyle :: struct { + flags :u32, + fixedWidth :i32, + fixedHeight :i32, + groupHeaderHeight :i32, + gapX :i32, + gapY :i32, + margin :EsRectangle16, + columns :^EsListViewColumn, + columnCount :uintptr, + emptyMessage :^i8, + emptyMessageBytes :uintptr, } +EsBatch :: inline proc (calls :^EsBatchCall, count :uintptr){ ((proc (^EsBatchCall, uintptr))(rawptr(uintptr(0x1000 + 0 * size_of(int)))))(calls, count); } +EsProcessCreate :: inline proc (executablePath :^i8, executablePathLength :uintptr, information :^EsProcessInformation, argument :EsGeneric) -> EsError{ return ((proc (^i8, uintptr, ^EsProcessInformation, EsGeneric) -> EsError)(rawptr(uintptr(0x1000 + 1 * size_of(int)))))(executablePath, executablePathLength, information, argument); } +EsThreadCreate :: inline proc (entryFunction :EsThreadEntryFunction, information :^EsThreadInformation, argument :EsGeneric) -> EsError{ return ((proc (EsThreadEntryFunction, ^EsThreadInformation, EsGeneric) -> EsError)(rawptr(uintptr(0x1000 + 2 * size_of(int)))))(entryFunction, information, argument); } +EsSurfaceCreate :: inline proc (width :uintptr, height :uintptr, flags :u32) -> EsHandle{ return ((proc (uintptr, uintptr, u32) -> EsHandle)(rawptr(uintptr(0x1000 + 3 * size_of(int)))))(width, height, flags); } +EsEventCreate :: inline proc (autoReset :bool) -> EsHandle{ return ((proc (bool) -> EsHandle)(rawptr(uintptr(0x1000 + 4 * size_of(int)))))(autoReset); } +EsThreadLocalStorageSetAddress :: inline proc (address :^rawptr){ ((proc (^rawptr))(rawptr(uintptr(0x1000 + 5 * size_of(int)))))(address); } +EsConstantBufferRead :: inline proc (constantBuffer :EsHandle, output :^rawptr){ ((proc (EsHandle, ^rawptr))(rawptr(uintptr(0x1000 + 6 * size_of(int)))))(constantBuffer, output); } +EsConstantBufferShare :: inline proc (constantBuffer :EsHandle, targetProcess :EsHandle) -> EsHandle{ return ((proc (EsHandle, EsHandle) -> EsHandle)(rawptr(uintptr(0x1000 + 7 * size_of(int)))))(constantBuffer, targetProcess); } +EsConstantBufferCreate :: inline proc (data :^rawptr, dataBytes :uintptr, targetProcess :EsHandle) -> EsHandle{ return ((proc (^rawptr, uintptr, EsHandle) -> EsHandle)(rawptr(uintptr(0x1000 + 8 * size_of(int)))))(data, dataBytes, targetProcess); } +EsProcessOpen :: inline proc (pid :u64) -> EsHandle{ return ((proc (u64) -> EsHandle)(rawptr(uintptr(0x1000 + 9 * size_of(int)))))(pid); } +EsHandleClose :: inline proc (handle :EsHandle) -> EsError{ return ((proc (EsHandle) -> EsError)(rawptr(uintptr(0x1000 + 10 * size_of(int)))))(handle); } +EsTakeSystemSnapshot :: inline proc (type :i32, bufferSize :^uintptr) -> EsHandle{ return ((proc (i32, ^uintptr) -> EsHandle)(rawptr(uintptr(0x1000 + 11 * size_of(int)))))(type, bufferSize); } +EsGetSystemInformation :: inline proc (systemInformation :^EsSystemInformation){ ((proc (^EsSystemInformation))(rawptr(uintptr(0x1000 + 12 * size_of(int)))))(systemInformation); } +EsNodeOpen :: inline proc (path :^i8, pathLength :uintptr, flags :u64, information :^EsNodeInformation) -> EsError{ return ((proc (^i8, uintptr, u64, ^EsNodeInformation) -> EsError)(rawptr(uintptr(0x1000 + 13 * size_of(int)))))(path, pathLength, flags, information); } +EsNodeFindUniqueName :: inline proc (buffer :^i8, originalBytes :uintptr, bufferBytes :uintptr) -> uintptr{ return ((proc (^i8, uintptr, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 14 * size_of(int)))))(buffer, originalBytes, bufferBytes); } +EsFileReadAll :: inline proc (filePath :^i8, filePathLength :uintptr, fileSize :^uintptr){ ((proc (^i8, uintptr, ^uintptr))(rawptr(uintptr(0x1000 + 15 * size_of(int)))))(filePath, filePathLength, fileSize); } +EsFileReadSync :: inline proc (file :EsHandle, offset :EsFileOffset, size :uintptr, buffer :^rawptr) -> uintptr{ return ((proc (EsHandle, EsFileOffset, uintptr, ^rawptr) -> uintptr)(rawptr(uintptr(0x1000 + 16 * size_of(int)))))(file, offset, size, buffer); } +EsFileWriteSync :: inline proc (file :EsHandle, offset :EsFileOffset, size :uintptr, buffer :^rawptr) -> uintptr{ return ((proc (EsHandle, EsFileOffset, uintptr, ^rawptr) -> uintptr)(rawptr(uintptr(0x1000 + 17 * size_of(int)))))(file, offset, size, buffer); } +EsFileResize :: inline proc (file :EsHandle, newSize :EsFileOffset) -> EsError{ return ((proc (EsHandle, EsFileOffset) -> EsError)(rawptr(uintptr(0x1000 + 18 * size_of(int)))))(file, newSize); } +EsNodeRefreshInformation :: inline proc (information :^EsNodeInformation){ ((proc (^EsNodeInformation))(rawptr(uintptr(0x1000 + 19 * size_of(int)))))(information); } +EsDirectoryEnumerateChildren :: inline proc (directory :EsHandle, buffer :^EsDirectoryChild, bufferCount :uintptr) -> int{ return ((proc (EsHandle, ^EsDirectoryChild, uintptr) -> int)(rawptr(uintptr(0x1000 + 20 * size_of(int)))))(directory, buffer, bufferCount); } +EsNodeDelete :: inline proc (node :EsHandle) -> EsError{ return ((proc (EsHandle) -> EsError)(rawptr(uintptr(0x1000 + 21 * size_of(int)))))(node); } +EsNodeMove :: inline proc (node :EsHandle, newDirectory :EsHandle, newName :^i8, newNameLength :uintptr) -> EsError{ return ((proc (EsHandle, EsHandle, ^i8, uintptr) -> EsError)(rawptr(uintptr(0x1000 + 22 * size_of(int)))))(node, newDirectory, newName, newNameLength); } +EsThreadTerminate :: inline proc (thread :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 23 * size_of(int)))))(thread); } +EsProcessTerminate :: inline proc (process :EsHandle, status :i32){ ((proc (EsHandle, i32))(rawptr(uintptr(0x1000 + 24 * size_of(int)))))(process, status); } +EsProcessTerminateCurrent :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 25 * size_of(int)))))(); } +EsProcessPause :: inline proc (process :EsHandle, resume :bool){ ((proc (EsHandle, bool))(rawptr(uintptr(0x1000 + 26 * size_of(int)))))(process, resume); } +EsProcessCrash :: inline proc (error :EsError, message :^i8, messageBytes :uintptr){ ((proc (EsError, ^i8, uintptr))(rawptr(uintptr(0x1000 + 27 * size_of(int)))))(error, message, messageBytes); } +EsThreadGetID :: inline proc (thread :EsHandle) -> uintptr{ return ((proc (EsHandle) -> uintptr)(rawptr(uintptr(0x1000 + 28 * size_of(int)))))(thread); } +EsProcessGetID :: inline proc (process :EsHandle) -> uintptr{ return ((proc (EsHandle) -> uintptr)(rawptr(uintptr(0x1000 + 29 * size_of(int)))))(process); } +EsSpinlockRelease :: inline proc (spinlock :^EsSpinlock){ ((proc (^EsSpinlock))(rawptr(uintptr(0x1000 + 30 * size_of(int)))))(spinlock); } +EsSpinlockAcquire :: inline proc (spinlock :^EsSpinlock){ ((proc (^EsSpinlock))(rawptr(uintptr(0x1000 + 31 * size_of(int)))))(spinlock); } +EsMutexRelease :: inline proc (mutex :^EsMutex){ ((proc (^EsMutex))(rawptr(uintptr(0x1000 + 32 * size_of(int)))))(mutex); } +EsMutexAcquire :: inline proc (mutex :^EsMutex){ ((proc (^EsMutex))(rawptr(uintptr(0x1000 + 33 * size_of(int)))))(mutex); } +EsMutexDestroy :: inline proc (mutex :^EsMutex){ ((proc (^EsMutex))(rawptr(uintptr(0x1000 + 34 * size_of(int)))))(mutex); } +EsSchedulerYield :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 35 * size_of(int)))))(); } +EsEventSet :: inline proc (event :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 36 * size_of(int)))))(event); } +EsEventReset :: inline proc (event :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 37 * size_of(int)))))(event); } +EsEventPoll :: inline proc (event :EsHandle) -> EsError{ return ((proc (EsHandle) -> EsError)(rawptr(uintptr(0x1000 + 38 * size_of(int)))))(event); } +EsWait :: inline proc (objects :^EsHandle, objectCount :uintptr, timeoutMs :uintptr) -> uintptr{ return ((proc (^EsHandle, uintptr, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 39 * size_of(int)))))(objects, objectCount, timeoutMs); } +EsSleep :: inline proc (milliseconds :u64){ ((proc (u64))(rawptr(uintptr(0x1000 + 40 * size_of(int)))))(milliseconds); } +EsMemoryOpen :: inline proc (size :uintptr, name :^i8, nameLength :uintptr, flags :u32) -> EsHandle{ return ((proc (uintptr, ^i8, uintptr, u32) -> EsHandle)(rawptr(uintptr(0x1000 + 41 * size_of(int)))))(size, name, nameLength, flags); } +EsMemoryShare :: inline proc (sharedMemoryRegion :EsHandle, targetProcess :EsHandle, readOnly :bool) -> EsHandle{ return ((proc (EsHandle, EsHandle, bool) -> EsHandle)(rawptr(uintptr(0x1000 + 42 * size_of(int)))))(sharedMemoryRegion, targetProcess, readOnly); } +EsObjectMap :: inline proc (object :EsHandle, offset :uintptr, size :uintptr, flags :u32){ ((proc (EsHandle, uintptr, uintptr, u32))(rawptr(uintptr(0x1000 + 43 * size_of(int)))))(object, offset, size, flags); } +EsMemoryAllocate :: inline proc (size :uintptr){ ((proc (uintptr))(rawptr(uintptr(0x1000 + 44 * size_of(int)))))(size); } +EsMemoryFree :: inline proc (address :^rawptr) -> EsError{ return ((proc (^rawptr) -> EsError)(rawptr(uintptr(0x1000 + 45 * size_of(int)))))(address); } +EsGetCreationArgument :: inline proc (object :EsHandle) -> EsGeneric{ return ((proc (EsHandle) -> EsGeneric)(rawptr(uintptr(0x1000 + 46 * size_of(int)))))(object); } +EsProcessGetState :: inline proc (process :EsHandle, state :^EsProcessState){ ((proc (EsHandle, ^EsProcessState))(rawptr(uintptr(0x1000 + 47 * size_of(int)))))(process, state); } +EsSurfaceGetLinearBuffer :: inline proc (surface :EsHandle, linearBuffer :^EsLinearBuffer){ ((proc (EsHandle, ^EsLinearBuffer))(rawptr(uintptr(0x1000 + 48 * size_of(int)))))(surface, linearBuffer); } +EsRectangleInvalidate :: inline proc (surface :EsHandle, rectangle :EsRectangle){ ((proc (EsHandle, EsRectangle))(rawptr(uintptr(0x1000 + 49 * size_of(int)))))(surface, rectangle); } +EsCopyToScreen :: inline proc (source :EsHandle, point :EsPoint, depth :u16){ ((proc (EsHandle, EsPoint, u16))(rawptr(uintptr(0x1000 + 50 * size_of(int)))))(source, point, depth); } +EsForceScreenUpdate :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 51 * size_of(int)))))(); } +EsDrawRectangle :: inline proc (surface :EsHandle, rectangle :EsRectangle, color :EsColor){ ((proc (EsHandle, EsRectangle, EsColor))(rawptr(uintptr(0x1000 + 52 * size_of(int)))))(surface, rectangle, color); } +EsDrawRectangleClipped :: inline proc (surface :EsHandle, rectangle :EsRectangle, color :EsColor, clipRegion :EsRectangle){ ((proc (EsHandle, EsRectangle, EsColor, EsRectangle))(rawptr(uintptr(0x1000 + 53 * size_of(int)))))(surface, rectangle, color, clipRegion); } +EsDrawSurfaceBlit :: inline proc (destination :EsHandle, source :EsHandle, destinationPoint :EsPoint){ ((proc (EsHandle, EsHandle, EsPoint))(rawptr(uintptr(0x1000 + 54 * size_of(int)))))(destination, source, destinationPoint); } +EsDrawSurface :: inline proc (destination :EsHandle, source :EsHandle, destinationRegion :EsRectangle, sourceRegion :EsRectangle, borderRegion :EsRectangle, mode :EsDrawMode, alpha :u16) -> EsError{ return ((proc (EsHandle, EsHandle, EsRectangle, EsRectangle, EsRectangle, EsDrawMode, u16) -> EsError)(rawptr(uintptr(0x1000 + 55 * size_of(int)))))(destination, source, destinationRegion, sourceRegion, borderRegion, mode, alpha); } +EsDrawSurfaceClipped :: inline proc (destination :EsHandle, source :EsHandle, destinationRegion :EsRectangle, sourceRegion :EsRectangle, borderRegion :EsRectangle, mode :EsDrawMode, alpha :u16, clipRegion :EsRectangle) -> EsError{ return ((proc (EsHandle, EsHandle, EsRectangle, EsRectangle, EsRectangle, EsDrawMode, u16, EsRectangle) -> EsError)(rawptr(uintptr(0x1000 + 56 * size_of(int)))))(destination, source, destinationRegion, sourceRegion, borderRegion, mode, alpha, clipRegion); } +EsDrawBitmap :: inline proc (destination :EsHandle, destinationPoint :EsPoint, bitmap :^rawptr, width :uintptr, height :uintptr, stride :uintptr, colorFormat :EsColorFormat){ ((proc (EsHandle, EsPoint, ^rawptr, uintptr, uintptr, uintptr, EsColorFormat))(rawptr(uintptr(0x1000 + 57 * size_of(int)))))(destination, destinationPoint, bitmap, width, height, stride, colorFormat); } +EsSurfaceClearInvalidatedRegion :: inline proc (surface :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 58 * size_of(int)))))(surface); } +EsRectangleClip :: inline proc (parent :EsRectangle, rectangle :EsRectangle, output :^EsRectangle) -> bool{ return ((proc (EsRectangle, EsRectangle, ^EsRectangle) -> bool)(rawptr(uintptr(0x1000 + 59 * size_of(int)))))(parent, rectangle, output); } +EsDrawBox :: inline proc (surface :EsHandle, rectangle :EsRectangle, style :u8, color :u32, clipRegion :EsRectangle){ ((proc (EsHandle, EsRectangle, u8, u32, EsRectangle))(rawptr(uintptr(0x1000 + 60 * size_of(int)))))(surface, rectangle, style, color, clipRegion); } +EsRedrawAll :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 61 * size_of(int)))))(); } +EsMessagePost :: inline proc (message :^EsMessage) -> EsError{ return ((proc (^EsMessage) -> EsError)(rawptr(uintptr(0x1000 + 62 * size_of(int)))))(message); } +EsMessagePostRemote :: inline proc (process :EsHandle, message :^EsMessage) -> EsError{ return ((proc (EsHandle, ^EsMessage) -> EsError)(rawptr(uintptr(0x1000 + 63 * size_of(int)))))(process, message); } +EsExtractArguments :: inline proc (string :^i8, bytes :uintptr, delimiterByte :u8, replacementDelimiter :u8, argvAllocated :uintptr, argv :^^i8, argc :^uintptr) -> bool{ return ((proc (^i8, uintptr, u8, u8, uintptr, ^^i8, ^uintptr) -> bool)(rawptr(uintptr(0x1000 + 64 * size_of(int)))))(string, bytes, delimiterByte, replacementDelimiter, argvAllocated, argv, argc); } +EsCStringLength :: inline proc (string :^i8) -> uintptr{ return ((proc (^i8) -> uintptr)(rawptr(uintptr(0x1000 + 65 * size_of(int)))))(string); } +EsStringLength :: inline proc (string :^i8, end :u8) -> uintptr{ return ((proc (^i8, u8) -> uintptr)(rawptr(uintptr(0x1000 + 66 * size_of(int)))))(string, end); } +EsMemoryCopy :: inline proc (destination :^rawptr, source :^rawptr, bytes :uintptr){ ((proc (^rawptr, ^rawptr, uintptr))(rawptr(uintptr(0x1000 + 67 * size_of(int)))))(destination, source, bytes); } +EsMemoryMove :: inline proc (_start :^rawptr, _end :^rawptr, amount :int, zeroEmptySpace :bool){ ((proc (^rawptr, ^rawptr, int, bool))(rawptr(uintptr(0x1000 + 68 * size_of(int)))))(_start, _end, amount, zeroEmptySpace); } +EsMemoryCopyReverse :: inline proc (_destination :^rawptr, _source :^rawptr, bytes :uintptr){ ((proc (^rawptr, ^rawptr, uintptr))(rawptr(uintptr(0x1000 + 69 * size_of(int)))))(_destination, _source, bytes); } +EsMemoryZero :: inline proc (destination :^rawptr, bytes :uintptr){ ((proc (^rawptr, uintptr))(rawptr(uintptr(0x1000 + 70 * size_of(int)))))(destination, bytes); } +EsMemoryCompare :: inline proc (a :^rawptr, b :^rawptr, bytes :uintptr) -> i32{ return ((proc (^rawptr, ^rawptr, uintptr) -> i32)(rawptr(uintptr(0x1000 + 71 * size_of(int)))))(a, b, bytes); } +EsMemorySumBytes :: inline proc (data :^u8, bytes :uintptr) -> u8{ return ((proc (^u8, uintptr) -> u8)(rawptr(uintptr(0x1000 + 72 * size_of(int)))))(data, bytes); } +EsPrintDirect :: inline proc (string :^i8, stringLength :uintptr){ ((proc (^i8, uintptr))(rawptr(uintptr(0x1000 + 73 * size_of(int)))))(string, stringLength); } +EsStringFormat :: inline proc (buffer :^i8, bufferLength :uintptr, format :^i8, args : ..any) -> uintptr{ return ((proc (^i8, uintptr, ^i8, ..any) -> uintptr)(rawptr(uintptr(0x1000 + 74 * size_of(int)))))(buffer, bufferLength, format, ); } +EsStringFormatAppend :: inline proc (buffer :^i8, bufferLength :uintptr, bufferPosition :^uintptr, format :^i8, args : ..any){ ((proc (^i8, uintptr, ^uintptr, ^i8, ..any))(rawptr(uintptr(0x1000 + 75 * size_of(int)))))(buffer, bufferLength, bufferPosition, format, ); } +EsPrintHelloWorld :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 76 * size_of(int)))))(); } +EsGetRandomByte :: inline proc () -> u8{ return ((proc () -> u8)(rawptr(uintptr(0x1000 + 77 * size_of(int)))))(); } +EsSort :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :EsComparisonCallbackFunction, argument :EsGeneric){ ((proc (^rawptr, uintptr, uintptr, EsComparisonCallbackFunction, EsGeneric))(rawptr(uintptr(0x1000 + 78 * size_of(int)))))(_base, nmemb, size, compar, argument); } +EsSortWithSwapCallback :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :EsComparisonCallbackFunction, argument :EsGeneric, swap :EsSwapCallbackFunction){ ((proc (^rawptr, uintptr, uintptr, EsComparisonCallbackFunction, EsGeneric, EsSwapCallbackFunction))(rawptr(uintptr(0x1000 + 79 * size_of(int)))))(_base, nmemb, size, compar, argument, swap); } +EsStringCompare :: inline proc (s1 :^i8, s2 :^i8, length1 :uintptr, length2 :uintptr) -> i32{ return ((proc (^i8, ^i8, uintptr, uintptr) -> i32)(rawptr(uintptr(0x1000 + 80 * size_of(int)))))(s1, s2, length1, length2); } +EsIntegerParse :: inline proc (text :^i8, bytes :uintptr) -> i64{ return ((proc (^i8, uintptr) -> i64)(rawptr(uintptr(0x1000 + 81 * size_of(int)))))(text, bytes); } +EsCRTmemset :: inline proc (s :^rawptr, c :i32, n :uintptr){ ((proc (^rawptr, i32, uintptr))(rawptr(uintptr(0x1000 + 82 * size_of(int)))))(s, c, n); } +EsCRTmemcpy :: inline proc (dest :^rawptr, src :^rawptr, n :uintptr){ ((proc (^rawptr, ^rawptr, uintptr))(rawptr(uintptr(0x1000 + 83 * size_of(int)))))(dest, src, n); } +EsCRTmemmove :: inline proc (dest :^rawptr, src :^rawptr, n :uintptr){ ((proc (^rawptr, ^rawptr, uintptr))(rawptr(uintptr(0x1000 + 84 * size_of(int)))))(dest, src, n); } +EsCRTstrlen :: inline proc (s :^i8) -> uintptr{ return ((proc (^i8) -> uintptr)(rawptr(uintptr(0x1000 + 85 * size_of(int)))))(s); } +EsCRTstrnlen :: inline proc (s :^i8, maxlen :uintptr) -> uintptr{ return ((proc (^i8, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 86 * size_of(int)))))(s, maxlen); } +EsCRTmalloc :: inline proc (size :uintptr){ ((proc (uintptr))(rawptr(uintptr(0x1000 + 87 * size_of(int)))))(size); } +EsCRTcalloc :: inline proc (num :uintptr, size :uintptr){ ((proc (uintptr, uintptr))(rawptr(uintptr(0x1000 + 88 * size_of(int)))))(num, size); } +EsCRTfree :: inline proc (ptr :^rawptr){ ((proc (^rawptr))(rawptr(uintptr(0x1000 + 89 * size_of(int)))))(ptr); } +EsCRTabs :: inline proc (n :i32) -> i32{ return ((proc (i32) -> i32)(rawptr(uintptr(0x1000 + 90 * size_of(int)))))(n); } +EsCRTrealloc :: inline proc (ptr :^rawptr, size :uintptr){ ((proc (^rawptr, uintptr))(rawptr(uintptr(0x1000 + 91 * size_of(int)))))(ptr, size); } +EsCRTgetenv :: inline proc (name :^i8) -> ^i8{ return ((proc (^i8) -> ^i8)(rawptr(uintptr(0x1000 + 92 * size_of(int)))))(name); } +EsCRTstrncmp :: inline proc (s1 :^i8, s2 :^i8, n :uintptr) -> i32{ return ((proc (^i8, ^i8, uintptr) -> i32)(rawptr(uintptr(0x1000 + 93 * size_of(int)))))(s1, s2, n); } +EsCRTmemcmp :: inline proc (s1 :^rawptr, s2 :^rawptr, n :uintptr) -> i32{ return ((proc (^rawptr, ^rawptr, uintptr) -> i32)(rawptr(uintptr(0x1000 + 94 * size_of(int)))))(s1, s2, n); } +EsCRTqsort :: inline proc (_base :^rawptr, nmemb :uintptr, size :uintptr, compar :EsCRTComparisonCallback){ ((proc (^rawptr, uintptr, uintptr, EsCRTComparisonCallback))(rawptr(uintptr(0x1000 + 95 * size_of(int)))))(_base, nmemb, size, compar); } +EsCRTstrcmp :: inline proc (s1 :^i8, s2 :^i8) -> i32{ return ((proc (^i8, ^i8) -> i32)(rawptr(uintptr(0x1000 + 96 * size_of(int)))))(s1, s2); } +EsCRTstrstr :: inline proc (haystack :^i8, needle :^i8) -> ^i8{ return ((proc (^i8, ^i8) -> ^i8)(rawptr(uintptr(0x1000 + 97 * size_of(int)))))(haystack, needle); } +EsCRTstrcpy :: inline proc (dest :^i8, src :^i8) -> ^i8{ return ((proc (^i8, ^i8) -> ^i8)(rawptr(uintptr(0x1000 + 98 * size_of(int)))))(dest, src); } +EsCRTisalpha :: inline proc (c :i32) -> i32{ return ((proc (i32) -> i32)(rawptr(uintptr(0x1000 + 99 * size_of(int)))))(c); } +EsCRTmemchr :: inline proc (_s :^rawptr, _c :i32, n :uintptr){ ((proc (^rawptr, i32, uintptr))(rawptr(uintptr(0x1000 + 100 * size_of(int)))))(_s, _c, n); } +EsCRTisdigit :: inline proc (c :i32) -> i32{ return ((proc (i32) -> i32)(rawptr(uintptr(0x1000 + 101 * size_of(int)))))(c); } +EsCRTstrcat :: inline proc (dest :^i8, src :^i8) -> ^i8{ return ((proc (^i8, ^i8) -> ^i8)(rawptr(uintptr(0x1000 + 102 * size_of(int)))))(dest, src); } +EsCRTtolower :: inline proc (c :i32) -> i32{ return ((proc (i32) -> i32)(rawptr(uintptr(0x1000 + 103 * size_of(int)))))(c); } +EsCRTstrncpy :: inline proc (dest :^i8, src :^i8, n :uintptr) -> ^i8{ return ((proc (^i8, ^i8, uintptr) -> ^i8)(rawptr(uintptr(0x1000 + 104 * size_of(int)))))(dest, src, n); } +EsCRTstrtoul :: inline proc (nptr :^i8, endptr :^^i8, base :i32) -> u64{ return ((proc (^i8, ^^i8, i32) -> u64)(rawptr(uintptr(0x1000 + 105 * size_of(int)))))(nptr, endptr, base); } +EsExecute :: inline proc (what :^i8, whatBytes :uintptr, argument :^i8, argumentBytes :uintptr){ ((proc (^i8, uintptr, ^i8, uintptr))(rawptr(uintptr(0x1000 + 106 * size_of(int)))))(what, whatBytes, argument, argumentBytes); } +EsAbort :: inline proc (){ ((proc ())(rawptr(uintptr(0x1000 + 107 * size_of(int)))))(); } +EsMailslotSendData :: inline proc (mailslot :EsHandle, data :^rawptr, bytes :uintptr) -> bool{ return ((proc (EsHandle, ^rawptr, uintptr) -> bool)(rawptr(uintptr(0x1000 + 108 * size_of(int)))))(mailslot, data, bytes); } +EsCRTfloorf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 109 * size_of(int)))))(x); } +EsCRTceilf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 110 * size_of(int)))))(x); } +EsCRTsinf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 111 * size_of(int)))))(x); } +EsCRTcosf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 112 * size_of(int)))))(x); } +EsCRTatan2f :: inline proc (y :f32, x :f32) -> f32{ return ((proc (f32, f32) -> f32)(rawptr(uintptr(0x1000 + 113 * size_of(int)))))(y, x); } +EsCRTfmodf :: inline proc (x :f32, y :f32) -> f32{ return ((proc (f32, f32) -> f32)(rawptr(uintptr(0x1000 + 114 * size_of(int)))))(x, y); } +EsCRTacosf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 115 * size_of(int)))))(x); } +EsCRTasinf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 116 * size_of(int)))))(x); } +EsCRTatanf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 117 * size_of(int)))))(x); } +EsRandomSeed :: inline proc (x :u64){ ((proc (u64))(rawptr(uintptr(0x1000 + 118 * size_of(int)))))(x); } +EsCRTsqrtf :: inline proc (x :f32) -> f32{ return ((proc (f32) -> f32)(rawptr(uintptr(0x1000 + 119 * size_of(int)))))(x); } +EsCRTsqrtl :: inline proc (x :EsLongDouble) -> EsLongDouble{ return ((proc (EsLongDouble) -> EsLongDouble)(rawptr(uintptr(0x1000 + 120 * size_of(int)))))(x); } +EsCRTfabsl :: inline proc (x :EsLongDouble) -> EsLongDouble{ return ((proc (EsLongDouble) -> EsLongDouble)(rawptr(uintptr(0x1000 + 121 * size_of(int)))))(x); } +_EsSyscall :: inline proc (a :uintptr, b :uintptr, c :uintptr, d :uintptr, e :uintptr, f :uintptr) -> uintptr{ return ((proc (uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 122 * size_of(int)))))(a, b, c, d, e, f); } +EsProcessorReadTimeStamp :: inline proc () -> u64{ return ((proc () -> u64)(rawptr(uintptr(0x1000 + 123 * size_of(int)))))(); } +EsHeapAllocate :: inline proc (size :uintptr, zeroMemory :bool){ ((proc (uintptr, bool))(rawptr(uintptr(0x1000 + 124 * size_of(int)))))(size, zeroMemory); } +EsHeapFree :: inline proc (address :^rawptr){ ((proc (^rawptr))(rawptr(uintptr(0x1000 + 125 * size_of(int)))))(address); } +EsPrint :: inline proc (format :^i8, args : ..any){ ((proc (^i8, ..any))(rawptr(uintptr(0x1000 + 126 * size_of(int)))))(format, ); } +EsMemoryFill :: inline proc (from :^rawptr, to :^rawptr, byte :u8){ ((proc (^rawptr, ^rawptr, u8))(rawptr(uintptr(0x1000 + 127 * size_of(int)))))(from, to, byte); } +EsInitialiseCStandardLibrary :: inline proc (argc :^i32, argv :^^^i8){ ((proc (^i32, ^^^i8))(rawptr(uintptr(0x1000 + 128 * size_of(int)))))(argc, argv); } +EsMakeLinuxSystemCall2 :: inline proc (n :int, a1 :int, a2 :int, a3 :int, a4 :int, a5 :int, a6 :int) -> int{ return ((proc (int, int, int, int, int, int, int) -> int)(rawptr(uintptr(0x1000 + 129 * size_of(int)))))(n, a1, a2, a3, a4, a5, a6); } +EsProcessCreate2 :: inline proc (arguments :^EsProcessCreationArguments, information :^EsProcessInformation) -> EsError{ return ((proc (^EsProcessCreationArguments, ^EsProcessInformation) -> EsError)(rawptr(uintptr(0x1000 + 130 * size_of(int)))))(arguments, information); } +EsCRTatoi :: inline proc (string :^i8) -> i32{ return ((proc (^i8) -> i32)(rawptr(uintptr(0x1000 + 131 * size_of(int)))))(string); } +EsProcessGetExitStatus :: inline proc (process :EsHandle) -> i32{ return ((proc (EsHandle) -> i32)(rawptr(uintptr(0x1000 + 132 * size_of(int)))))(process); } +EsSurfaceReset :: inline proc (surface :EsHandle){ ((proc (EsHandle))(rawptr(uintptr(0x1000 + 133 * size_of(int)))))(surface); } +EsTimerCreate :: inline proc () -> EsHandle{ return ((proc () -> EsHandle)(rawptr(uintptr(0x1000 + 134 * size_of(int)))))(); } +EsTimerSet :: inline proc (handle :EsHandle, afterMs :u64, object :EsObject, argument :EsGeneric){ ((proc (EsHandle, u64, EsObject, EsGeneric))(rawptr(uintptr(0x1000 + 135 * size_of(int)))))(handle, afterMs, object, argument); } +EsFileWriteAll :: inline proc (filePath :^i8, filePathLength :uintptr, data :^rawptr, fileSize :uintptr) -> EsError{ return ((proc (^i8, uintptr, ^rawptr, uintptr) -> EsError)(rawptr(uintptr(0x1000 + 136 * size_of(int)))))(filePath, filePathLength, data, fileSize); } +EsUserGetHomeFolder :: inline proc (buffer :^i8, bufferBytes :uintptr) -> uintptr{ return ((proc (^i8, uintptr) -> uintptr)(rawptr(uintptr(0x1000 + 137 * size_of(int)))))(buffer, bufferBytes); } +EsAssert :: inline proc (expression :bool, failureMessage :^i8){ ((proc (bool, ^i8))(rawptr(uintptr(0x1000 + 138 * size_of(int)))))(expression, failureMessage); } +EsResizeArray :: inline proc (array :^^rawptr, allocated :^uintptr, needed :uintptr, itemSize :uintptr){ ((proc (^^rawptr, ^uintptr, uintptr, uintptr))(rawptr(uintptr(0x1000 + 139 * size_of(int)))))(array, allocated, needed, itemSize); } +EsMessageLoopEnter :: inline proc (callback :EsMessageCallbackFunction){ ((proc (EsMessageCallbackFunction))(rawptr(uintptr(0x1000 + 140 * size_of(int)))))(callback); } +_EsInstanceCreate :: inline proc (bytes :uintptr) -> ^EsInstance{ return ((proc (uintptr) -> ^EsInstance)(rawptr(uintptr(0x1000 + 141 * size_of(int)))))(bytes); } +EsMouseGetPosition :: inline proc (relativeWindow :^EsElement) -> EsPoint{ return ((proc (^EsElement) -> EsPoint)(rawptr(uintptr(0x1000 + 142 * size_of(int)))))(relativeWindow); } +EsMouseSetPosition :: inline proc (relativeWindow :^EsElement, x :i32, y :i32){ ((proc (^EsElement, i32, i32))(rawptr(uintptr(0x1000 + 143 * size_of(int)))))(relativeWindow, x, y); } +EsNewWindow :: inline proc (instance :^EsInstance, style :EsWindowStyle) -> ^EsElement{ return ((proc (^EsInstance, EsWindowStyle) -> ^EsElement)(rawptr(uintptr(0x1000 + 144 * size_of(int)))))(instance, style); } +EsNewPanel :: inline proc (parent :^EsElement, style :EsData, flags :u64) -> ^EsElement{ return ((proc (^EsElement, EsData, u64) -> ^EsElement)(rawptr(uintptr(0x1000 + 145 * size_of(int)))))(parent, style, flags); } +EsNewScrollbar :: inline proc (parent :^EsElement, flags :u64, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, u64, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 146 * size_of(int)))))(parent, flags, userCallback, _context); } +EsNewButton :: inline proc (parent :^EsElement, label :^i8, labelBytes :int, flags :u64, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, ^i8, int, u64, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 147 * size_of(int)))))(parent, label, labelBytes, flags, userCallback, _context); } +EsNewTextbox :: inline proc (parent :^EsElement, flags :u64, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, u64, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 148 * size_of(int)))))(parent, flags, userCallback, _context); } +EsNewNumericEntry :: inline proc (parent :^EsElement, flags :u64, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, u64, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 149 * size_of(int)))))(parent, flags, userCallback, _context); } +EsNewListView :: inline proc (parent :^EsElement, flags :u64, style :^EsListViewStyle, userCallback :EsUICallbackFunction, _context :EsGeneric) -> ^EsElement{ return ((proc (^EsElement, u64, ^EsListViewStyle, EsUICallbackFunction, EsGeneric) -> ^EsElement)(rawptr(uintptr(0x1000 + 150 * size_of(int)))))(parent, flags, style, userCallback, _context); } +EsElementGetInstance :: inline proc (element :^EsElement) -> ^EsInstance{ return ((proc (^EsElement) -> ^EsInstance)(rawptr(uintptr(0x1000 + 151 * size_of(int)))))(element); } +EsElementFocus :: inline proc (element :^EsElement, ensureVisible :bool){ ((proc (^EsElement, bool))(rawptr(uintptr(0x1000 + 152 * size_of(int)))))(element, ensureVisible); } +EsScrollbarSetMeasurements :: inline proc (scrollbar :^EsElement, viewportSize :i32, contentSize :i32){ ((proc (^EsElement, i32, i32))(rawptr(uintptr(0x1000 + 153 * size_of(int)))))(scrollbar, viewportSize, contentSize); } +EsScrollbarSetPosition :: inline proc (scrollbar :^EsElement, position :f32, sendMovedMessage :bool, smoothScroll :bool){ ((proc (^EsElement, f32, bool, bool))(rawptr(uintptr(0x1000 + 154 * size_of(int)))))(scrollbar, position, sendMovedMessage, smoothScroll); } +EsWindowGetBounds :: inline proc (window :^EsElement, bounds :^EsRectangle){ ((proc (^EsElement, ^EsRectangle))(rawptr(uintptr(0x1000 + 155 * size_of(int)))))(window, bounds); } +EsListViewInsert :: inline proc (listView :^EsElement, group :EsListViewIndex, index :EsListViewIndex, count :uintptr){ ((proc (^EsElement, EsListViewIndex, EsListViewIndex, uintptr))(rawptr(uintptr(0x1000 + 156 * size_of(int)))))(listView, group, index, count); } +EsListViewInsertGroup :: inline proc (listView :^EsElement, group :EsListViewIndex){ ((proc (^EsElement, EsListViewIndex))(rawptr(uintptr(0x1000 + 157 * size_of(int)))))(listView, group); } +EsListViewRemove :: inline proc (listView :^EsElement, group :EsListViewIndex, index :EsListViewIndex, count :int, removedHeight :i32){ ((proc (^EsElement, EsListViewIndex, EsListViewIndex, int, i32))(rawptr(uintptr(0x1000 + 158 * size_of(int)))))(listView, group, index, count, removedHeight); } +EsListViewRemoveGroup :: inline proc (listView :^EsElement, group :EsListViewIndex){ ((proc (^EsElement, EsListViewIndex))(rawptr(uintptr(0x1000 + 159 * size_of(int)))))(listView, group); } +EsListViewInvalidate :: inline proc (listView :^EsElement, deltaHeight :i32, recalculateHeight :bool){ ((proc (^EsElement, i32, bool))(rawptr(uintptr(0x1000 + 160 * size_of(int)))))(listView, deltaHeight, recalculateHeight); } +EsListViewEnsureVisible :: inline proc (listView :^EsElement, group :EsListViewIndex, index :EsListViewIndex){ ((proc (^EsElement, EsListViewIndex, EsListViewIndex))(rawptr(uintptr(0x1000 + 161 * size_of(int)))))(listView, group, index); } +EsListViewResetSearchBuffer :: inline proc (object :^EsElement){ ((proc (^EsElement))(rawptr(uintptr(0x1000 + 162 * size_of(int)))))(object); } +EsDataParse :: inline proc (cFormat :^i8, args : ..any) -> EsData{ return ((proc (^i8, ..any) -> EsData)(rawptr(uintptr(0x1000 + 163 * size_of(int)))))(cFormat, ); } +EsDataNone :: inline proc () -> EsData{ return ((proc () -> EsData)(rawptr(uintptr(0x1000 + 164 * size_of(int)))))(); } + +////////////////////////////////////////////////////// + +Handle :: distinct i32; +Errno :: distinct i32; + +INVALID_HANDLE :: ~Handle(0); + +stdin: Handle = 0; +stdout: Handle = 1; +stderr: Handle = 2; + +O_RDONLY :: 0x00000; +O_WRONLY :: 0x00001; +O_RDWR :: 0x00002; +O_CREATE :: 0x00040; +O_EXCL :: 0x00080; +O_NOCTTY :: 0x00100; +O_TRUNC :: 0x00200; +O_NONBLOCK :: 0x00800; +O_APPEND :: 0x00400; +O_SYNC :: 0x01000; +O_ASYNC :: 0x02000; +O_CLOEXEC :: 0x80000; + +ERROR_UNSUPPORTED :: 1; + read :: proc(fd: Handle, data: []byte) -> (int, Errno) { - if (fd == 0 || fd == 1) { - assert(false); - return 0, ERROR_NOT_IMPLEMENTED; - } + return -1, ERROR_UNSUPPORTED; +} + +write :: proc(fd: Handle, data: []byte) -> (int, Errno) { + return -1, ERROR_UNSUPPORTED; +} + +open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { + return -1, ERROR_UNSUPPORTED; +} + +close :: proc(fd: Handle) -> Errno { + return ERROR_UNSUPPORTED; +} + +file_size :: proc(fd: Handle) -> (i64, Errno) { + return 0, ERROR_UNSUPPORTED; +} + +heap_alloc :: proc(size: int) -> rawptr { + return nil; +} + +heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { + return nil; +} + +heap_free :: proc(ptr: rawptr) { +} - information := (^OS_Node_Information)(uintptr(fd)); - count := OSReadFileSync(information.handle, information.position, i64(len(data)), &data[0]); - if count < 0 do return 0, ERROR_UNKNOWN_OPERATION_FAILURE; - information.position += count; - return int(count), ERROR_NONE; +current_thread_id :: proc "contextless" () -> int { + // return int(EsThreadGetID(ES_CURRENT_THREAD)); + return -1; } + +OS :: "essence"; diff --git a/core/sys/essence_linker_userland64.ld b/core/sys/essence_linker_userland64.ld deleted file mode 100644 index 5f6d92791..000000000 --- a/core/sys/essence_linker_userland64.ld +++ /dev/null @@ -1,24 +0,0 @@ -ENTRY(_start) - -SECTIONS -{ - . = 0x100000; - .text BLOCK(4K) : ALIGN(4K) - { - *(.text) - } - .rodata BLOCK(4K) : ALIGN(4K) - { - *(.rodata) - } - .data BLOCK(4K) : ALIGN(4K) - { - *(.data) - } - - .bss BLOCK(4K) : ALIGN(4K) - { - *(COMMON) - *(.bss) - } -} diff --git a/core/time/time_essence.odin b/core/time/time_essence.odin new file mode 100644 index 000000000..11713d84b --- /dev/null +++ b/core/time/time_essence.odin @@ -0,0 +1,2 @@ +package time +IS_SUPPORTED :: false; diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 992443f7c..956ffe1ed 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -56,8 +56,6 @@ TargetEndianKind target_endians[TargetArch_COUNT] = { String const ODIN_VERSION = str_lit("0.10.1"); -String cross_compile_target = str_lit(""); -String cross_compile_lib_dir = str_lit(""); @@ -66,6 +64,7 @@ struct TargetMetrics { TargetArchKind arch; isize word_size; isize max_align; + String target_triplet; }; @@ -109,6 +108,7 @@ struct BuildContext { bool has_resource; String opt_flags; String llc_flags; + String target_triplet; String link_flags; bool is_dll; bool generate_docs; @@ -121,6 +121,7 @@ struct BuildContext { bool no_crt; bool use_lld; bool vet; + bool cross_compiling; QueryDataSetSettings query_data_set_settings; @@ -135,18 +136,19 @@ struct BuildContext { gb_global BuildContext build_context = {0}; - gb_global TargetMetrics target_windows_386 = { TargetOs_windows, TargetArch_386, 4, 8, + str_lit("i686-pc-windows"), }; gb_global TargetMetrics target_windows_amd64 = { TargetOs_windows, TargetArch_amd64, 8, 16, + str_lit("x86_64-pc-windows-gnu"), }; gb_global TargetMetrics target_linux_386 = { @@ -154,12 +156,14 @@ gb_global TargetMetrics target_linux_386 = { TargetArch_386, 4, 8, + str_lit("i686-pc-linux-gnu"), }; gb_global TargetMetrics target_linux_amd64 = { TargetOs_linux, TargetArch_amd64, 8, 16, + str_lit("x86_64-pc-linux-gnu"), }; gb_global TargetMetrics target_osx_amd64 = { @@ -167,10 +171,32 @@ gb_global TargetMetrics target_osx_amd64 = { TargetArch_amd64, 8, 16, + str_lit("x86_64-apple-darwin"), +}; + +gb_global TargetMetrics target_essence_amd64 = { + TargetOs_essence, + TargetArch_amd64, + 8, + 16, + str_lit("x86_64-pc-none-elf"), }; +struct NamedTargetMetrics { + String name; + TargetMetrics *metrics; +}; +gb_global NamedTargetMetrics named_targets[] = { + { str_lit("essence_amd64"), &target_essence_amd64 }, + { str_lit("macos_amd64"), &target_osx_amd64 }, + { str_lit("linux_386"), &target_linux_386 }, + { str_lit("linux_amd64"), &target_linux_amd64 }, + { str_lit("windows_386"), &target_windows_386 }, + { str_lit("windows_amd64"), &target_windows_amd64 }, +}; +NamedTargetMetrics *selected_target_metrics; TargetOsKind get_target_os_from_string(String str) { for (isize i = 0; i < TargetOs_COUNT; i++) { @@ -522,7 +548,7 @@ String get_fullpath_core(gbAllocator a, String path) { -void init_build_context(void) { +void init_build_context(TargetMetrics *cross_target) { BuildContext *bc = &build_context; gb_affinity_init(&bc->affinity); @@ -554,8 +580,9 @@ void init_build_context(void) { #endif #endif - if (cross_compile_target.len) { - bc->ODIN_OS = cross_compile_target; + if (cross_target) { + metrics = *cross_target; + bc->cross_compiling = true; } GB_ASSERT(metrics.os != TargetOs_Invalid); @@ -573,6 +600,7 @@ void init_build_context(void) { bc->max_align = metrics.max_align; bc->link_flags = str_lit(" "); bc->opt_flags = str_lit(" "); + bc->target_triplet = metrics.target_triplet; gbString llc_flags = gb_string_make_reserve(heap_allocator(), 64); diff --git a/src/ir.cpp b/src/ir.cpp index 26f787976..9e44b837f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10937,12 +10937,14 @@ void ir_gen_tree(irGen *s) { // main :: proc(argc: i32, argv: ^^u8) -> i32 String name = str_lit("main"); +#if 0 if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) { // This is a bit hacky, // because this makes this function the first function run in the executable // so it won't actually have the argc/argv arguments. name = str_lit("ProgramEntry"); } +#endif Type *proc_params = alloc_type_tuple(); Type *proc_results = alloc_type_tuple(); diff --git a/src/main.cpp b/src/main.cpp index 05fa6c366..539480bf4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -75,7 +75,7 @@ i32 system_exec_command_line_app(char *name, char *fmt, ...) { va_end(va); cmd = make_string(cast(u8 *)&cmd_line, cmd_len-1); - //printf("do: %s\n", cmd_line); + // printf("do: %s\n", cmd_line); exit_code = system(&cmd_line[0]); // pid_t pid = fork(); @@ -210,9 +210,8 @@ enum BuildFlagKind { BuildFlag_Collection, BuildFlag_Define, BuildFlag_BuildMode, + BuildFlag_Target, BuildFlag_Debug, - BuildFlag_CrossCompile, - BuildFlag_CrossLibDir, BuildFlag_NoBoundsCheck, BuildFlag_NoCRT, BuildFlag_UseLLD, @@ -298,9 +297,8 @@ bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String); + add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None); - add_flag(&build_flags, BuildFlag_CrossCompile, str_lit("cross-compile"), BuildFlagParam_String); - add_flag(&build_flags, BuildFlag_CrossLibDir, str_lit("cross-lib-dir"), BuildFlagParam_String); add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None); add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None); @@ -478,33 +476,6 @@ bool parse_build_flags(Array args) { build_context.keep_temp_files = true; break; - case BuildFlag_CrossCompile: { - GB_ASSERT(value.kind == ExactValue_String); - cross_compile_target = value.value_string; - #if defined(GB_SYSTEM_UNIX) && defined(GB_ARCH_64_BIT) - if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) { - - } else - #endif - { - gb_printf_err("Unsupported cross compilation target '%.*s'\n", LIT(cross_compile_target)); - gb_printf_err("Currently supported targets: Essence (from 64-bit Unixes only)\n"); - bad_flags = true; - } - break; - } - - case BuildFlag_CrossLibDir: { - GB_ASSERT(value.kind == ExactValue_String); - if (cross_compile_lib_dir.len) { - gb_printf_err("Multiple cross compilation library directories\n"); - bad_flags = true; - } else { - cross_compile_lib_dir = concatenate_strings(heap_allocator(), str_lit("-L"), value.value_string); - } - break; - } - case BuildFlag_Collection: { GB_ASSERT(value.kind == ExactValue_String); String str = value.value_string; @@ -623,7 +594,25 @@ bool parse_build_flags(Array args) { break; } + case BuildFlag_Target: { + String str = value.value_string; + bool found = false; + + for (int i = 0; i < sizeof(named_targets) / sizeof(named_targets[0]); i++) { + if (str_eq_ignore_case(str, named_targets[i].name)) { + found = true; + selected_target_metrics = named_targets + i; + break; + } + } + + if (!found) { + gb_printf_err("Unknown target '%.*s'\n", LIT(str)); + bad_flags = true; + } + break; + } case BuildFlag_BuildMode: { GB_ASSERT(value.kind == ExactValue_String); @@ -889,8 +878,8 @@ i32 exec_llvm_opt(String output_base) { } i32 exec_llvm_llc(String output_base) { -#if defined(GB_SYSTEM_WINDOWS) // For more arguments: http://llvm.org/docs/CommandGuide/llc.html +#if defined(GB_SYSTEM_WINDOWS) return system_exec_command_line_app("llvm-llc", "\"%.*sbin\\llc\" \"%.*s.bc\" -filetype=obj -O%d " "-o \"%.*s.obj\" " @@ -903,21 +892,19 @@ i32 exec_llvm_llc(String output_base) { LIT(build_context.llc_flags)); #else // NOTE(zangent): Linux / Unix is unfinished and not tested very well. - // For more arguments: http://llvm.org/docs/CommandGuide/llc.html return system_exec_command_line_app("llc", "llc \"%.*s.bc\" -filetype=obj -relocation-model=pic -O%d " "%.*s " - "%s" - "", + "%s%.*s", LIT(output_base), build_context.optimization_level, LIT(build_context.llc_flags), - str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-mtriple=x86_64-pc-none-elf" : ""); + build_context.cross_compiling ? "-mtriple=" : "", + (int) (build_context.cross_compiling ? build_context.target_triplet.len : 0), + build_context.target_triplet.text); #endif } - - int main(int arg_count, char **arg_ptr) { if (arg_count < 2) { usage(make_string_c(arg_ptr[0])); @@ -1026,7 +1013,7 @@ int main(int arg_count, char **arg_ptr) { } - init_build_context(); + init_build_context(selected_target_metrics ? selected_target_metrics->metrics : nullptr); if (build_context.word_size == 4) { print_usage_line(0, "%s 32-bit is not yet supported", args[0]); return 1; @@ -1121,6 +1108,17 @@ int main(int arg_count, char **arg_ptr) { return exit_code; } + if (build_context.cross_compiling) { + if (0) { +#ifdef GB_SYSTEM_UNIX + } else if (selected_target_metrics->metrics == &target_essence_amd64) { + system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s", + LIT(output_base), LIT(output_base), LIT(build_context.link_flags)); +#endif + } else { + gb_printf_err("Don't know how to cross compile to selected target.\n"); + } + } else { #if defined(GB_SYSTEM_WINDOWS) timings_start_section(&timings, str_lit("msvc-link")); @@ -1309,11 +1307,7 @@ int main(int arg_count, char **arg_ptr) { // It probably has to do with including the entire CRT, but // that's quite a complicated issue to solve while remaining distro-agnostic. // Clang can figure out linker flags for us, and that's good enough _for now_. - if (str_eq_ignore_case(cross_compile_target, str_lit("Essence"))) { - linker = "x86_64-elf-gcc -T core/sys/essence_linker_userland64.ld -ffreestanding -nostdlib -lgcc -g -z max-page-size=0x1000 -Wno-unused-command-line-argument"; - } else { - linker = "clang -Wno-unused-command-line-argument"; - } + linker = "clang -Wno-unused-command-line-argument"; #endif exit_code = system_exec_command_line_app("ld-link", @@ -1321,7 +1315,6 @@ int main(int arg_count, char **arg_ptr) { " %s " " %.*s " " %s " - " %.*s " #if defined(GB_SYSTEM_OSX) // This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit. // NOTE: If you change this (although this minimum is as low as you can go with Odin working) @@ -1332,11 +1325,9 @@ int main(int arg_count, char **arg_ptr) { #endif , linker, LIT(output_base), LIT(output_base), LIT(output_ext), lib_str, - str_eq_ignore_case(cross_compile_target, str_lit("Essence")) ? "-lfreetype -lglue" : "-lc -lm", + "-lc -lm", LIT(build_context.link_flags), - link_settings, - LIT(cross_compile_lib_dir) - ); + link_settings); if (exit_code != 0) { return exit_code; } @@ -1369,6 +1360,7 @@ int main(int arg_count, char **arg_ptr) { system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); } #endif + } return 0; } -- cgit v1.2.3 From 1370c10d1b9012bd914cf35347f8f6d9ac1a0da0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Sep 2019 18:59:07 +0100 Subject: Fix Converting addresses to function pointers produces llvm-opt error #431 --- src/ir.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 26f787976..4d5a55814 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6967,7 +6967,34 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { } // NOTE(bill): Regular call - irValue *value = ir_build_expr(proc, ce->proc); + irValue *value = nullptr; + Ast *proc_expr = unparen_expr(ce->proc); + if (proc_expr->tav.mode == Addressing_Constant) { + ExactValue v = proc_expr->tav.value; + switch (v.kind) { + case ExactValue_Integer: + { + u64 u = big_int_to_u64(&v.value_integer); + irValue *x = ir_const_uintptr(u); + x = ir_emit_conv(proc, x, t_rawptr); + value = ir_emit_conv(proc, x, proc_expr->tav.type); + break; + } + case ExactValue_Pointer: + { + u64 u = cast(u64)v.value_pointer; + irValue *x = ir_const_uintptr(u); + x = ir_emit_conv(proc, x, t_rawptr); + value = ir_emit_conv(proc, x, proc_expr->tav.type); + break; + } + } + } + + if (value == nullptr) { + value = ir_build_expr(proc, proc_expr); + } + GB_ASSERT(value != nullptr); Type *proc_type_ = base_type(ir_type(value)); GB_ASSERT(proc_type_->kind == Type_Proc); -- cgit v1.2.3 From f4f6e9ad49d6992712815bc7b2e94c8333f33523 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 25 Sep 2019 21:07:56 +0100 Subject: Fix -debug crash on windows caused by missing debug info for files. --- core/os/os_windows.odin | 2 +- src/ir.cpp | 13 ++++++++++++- src/ir_print.cpp | 6 ++++-- 3 files changed, 17 insertions(+), 4 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 9618f83be..e45cf9f5f 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -322,4 +322,4 @@ is_windows_8_1 :: proc() -> bool { is_windows_10 :: proc() -> bool { osvi := get_windows_version_ansi(); return (osvi.major_version == 10 && osvi.minor_version == 0); -} \ No newline at end of file +} diff --git a/src/ir.cpp b/src/ir.cpp index 1c326359b..758267c24 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10028,7 +10028,11 @@ void ir_init_module(irModule *m, Checker *c) { { irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_CompileUnit); - di->CompileUnit.file = m->info->files.entries[0].value; // Zeroth is the init file + + GB_ASSERT(m->info->files.entries.count > 0); + AstFile *file = m->info->files.entries[0].value; + + di->CompileUnit.file = file; // Zeroth is the init file di->CompileUnit.producer = str_lit("odin"); map_set(&m->debug_info, hash_pointer(m), di); @@ -10047,6 +10051,13 @@ void ir_init_module(irModule *m, Checker *c) { array_init(&m->debug_location_stack, heap_allocator()); // TODO(lachsinc): ir_allocator() ?? } + + { + for_array(i, m->info->files.entries) { + AstFile *file = m->info->files.entries[i].value; + ir_add_debug_info_file(m, file); + } + } } void ir_destroy_module(irModule *m) { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 30ad914a9..9414a2338 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -2450,11 +2450,13 @@ void print_llvm_ir(irGen *ir) { for_array(di_index, m->debug_info.entries) { irDebugInfo *di = m->debug_info.entries[di_index].value; + GB_ASSERT_MSG(di != nullptr, "Invalid irDebugInfo"); ir_fprintf(f, "!%d = ", di->id); - switch (di->kind) { case irDebugInfo_CompileUnit: { - irDebugInfo *file = *map_get(&m->debug_info, hash_pointer(di->CompileUnit.file)); + irDebugInfo **found = map_get(&m->debug_info, hash_pointer(di->CompileUnit.file)); + GB_ASSERT_MSG(found != nullptr, "Missing debug info for: %.*s\n", LIT(di->CompileUnit.file->fullpath)); + irDebugInfo *file = *found; ir_fprintf(f, "distinct !DICompileUnit(" "language: DW_LANG_C_plus_plus" // Is this good enough? -- cgit v1.2.3 From 6c69e8c043e7dcf9d9965c7b28c7bdae44e0537c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 6 Oct 2019 14:55:25 +0100 Subject: Make `typeid` semantics consistent across variables and constants --- src/check_decl.cpp | 54 ++++++++++++++++++++++++++++++++--------------- src/check_expr.cpp | 61 +++++++++++++++++++++++++++++++++++++++++------------ src/checker.cpp | 16 ++++++-------- src/exact_value.cpp | 18 ++++++++++++++++ src/ir.cpp | 5 +++++ src/parser.cpp | 4 ---- 6 files changed, 113 insertions(+), 45 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 166b6e715..5e8479a7f 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -41,11 +41,20 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri } if (operand->mode == Addressing_Type) { - gbString t = type_to_string(operand->type); - error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string)); - gb_string_free(t); - e->type = operand->type; - return nullptr; + if (e->type != nullptr && is_type_typeid(e->type)) { + add_type_info_type(ctx, operand->type); + add_type_and_value(ctx->info, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type)); + return e->type; + } else { + gbString t = type_to_string(operand->type); + defer (gb_string_free(t)); + error(operand->expr, "Cannot assign a type '%s' to variable '%.*s'", t, LIT(e->token.string)); + if (e->type == nullptr) { + error_line("\tThe type of the variable '%.*s' cannot be inferred as a type does not have a type\n", LIT(e->token.string)); + } + e->type = operand->type; + return nullptr; + } } @@ -240,7 +249,7 @@ isize total_attribute_count(DeclInfo *decl) { } -void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) { +void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) { GB_ASSERT(e->type == nullptr); DeclInfo *decl = decl_info_of_entity(e); @@ -248,9 +257,8 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) check_decl_attributes(ctx, decl->attributes, const_decl_attribute, nullptr); } - - bool is_distinct = is_type_distinct(type_expr); - Ast *te = remove_type_alias_clutter(type_expr); + bool is_distinct = is_type_distinct(init_expr); + Ast *te = remove_type_alias_clutter(init_expr); e->type = t_invalid; String name = e->token.string; Type *named = alloc_type_named(name, nullptr, e); @@ -266,7 +274,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) named->Named.base = base_type(bt); if (is_distinct && is_type_typeid(e->type)) { - error(type_expr, "'distinct' cannot be applied to 'typeid'"); + error(init_expr, "'distinct' cannot be applied to 'typeid'"); is_distinct = false; } if (!is_distinct) { @@ -275,6 +283,19 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Type *def) e->TypeName.is_type_alias = true; } + + if (decl->type_expr != nullptr) { + Type *t = check_type(ctx, decl->type_expr); + if (t != nullptr && !is_type_typeid(t)) { + Operand operand = {}; + operand.mode = Addressing_Type; + operand.type = e->type; + operand.expr = init_expr; + check_assignment(ctx, &operand, t, str_lit("constant declaration")); + } + } + + // using decl if (decl->is_using) { // NOTE(bill): Must be an enum declaration @@ -363,15 +384,14 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, switch (operand.mode) { case Addressing_Type: { + if (e->type != nullptr && !is_type_typeid(e->type)) { + check_assignment(ctx, &operand, e->type, str_lit("constant declaration")); + } + e->kind = Entity_TypeName; e->type = nullptr; - DeclInfo *d = ctx->decl; - if (d->type_expr != nullptr) { - error(e->token, "A type declaration cannot have an type parameter"); - } - d->type_expr = d->init_expr; - check_type_decl(ctx, e, d->type_expr, named_type); + check_type_decl(ctx, e, ctx->decl->init_expr, named_type); return; } @@ -1070,7 +1090,7 @@ void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_ check_const_decl(&c, e, d->type_expr, d->init_expr, named_type); break; case Entity_TypeName: { - check_type_decl(&c, e, d->type_expr, named_type); + check_type_decl(&c, e, d->init_expr, named_type); break; } case Entity_Procedure: diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 697abef5f..6a0d8221f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -442,6 +442,10 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type } if (operand->mode == Addressing_Type) { + if (is_type_typeid(type)) { + add_type_info_type(c, operand->type); + return 4; + } return -1; } @@ -755,7 +759,12 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co return; } - if (!check_is_assignable_to(c, operand, type)) { + if (check_is_assignable_to(c, operand, type)) { + if (operand->mode == Addressing_Type && is_type_typeid(type)) { + add_type_info_type(c, operand->type); + add_type_and_value(c->info, operand->expr, Addressing_Value, type, exact_value_typeid(operand->type)); + } + } else { gbString expr_str = expr_to_string(operand->expr); gbString op_type_str = type_to_string(operand->type); gbString type_str = type_to_string(type); @@ -1734,6 +1743,23 @@ void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) { return; } + if (x->mode == Addressing_Type && is_type_typeid(y->type)) { + add_type_info_type(c, x->type); + add_type_and_value(c->info, x->expr, Addressing_Value, y->type, exact_value_typeid(x->type)); + + x->mode = Addressing_Value; + x->type = t_untyped_bool; + return; + } else if (is_type_typeid(x->type) && y->mode == Addressing_Type) { + add_type_info_type(c, y->type); + add_type_and_value(c->info, y->expr, Addressing_Value, x->type, exact_value_typeid(y->type)); + + x->mode = Addressing_Value; + x->type = t_untyped_bool; + return; + } + + gbString err_str = nullptr; defer (if (err_str != nullptr) { @@ -2324,8 +2350,16 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint // If only one is a type, this is an error if (xt ^ yt) { GB_ASSERT(xt != yt); - if (xt) error_operand_not_expression(x); - if (yt) error_operand_not_expression(y); + if (xt) { + if (!is_type_typeid(y->type)) { + error_operand_not_expression(x); + } + } + if (yt) { + if (!is_type_typeid(x->type)) { + error_operand_not_expression(y); + } + } } break; @@ -5254,6 +5288,11 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { } } score += s; + + if (o.mode == Addressing_Type && is_type_typeid(e->type)) { + add_type_info_type(c, o.type); + add_type_and_value(c->info, o.expr, Addressing_Value, e->type, exact_value_typeid(o.type)); + } } if (variadic) { @@ -5496,6 +5535,11 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { } score += s; } + + if (o->mode == Addressing_Type && is_type_typeid(e->type)) { + add_type_info_type(c, o->type); + add_type_and_value(c->info, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type)); + } } if (data) { @@ -6432,17 +6476,6 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) { } } - // NOTE(bill): Should this be here or on the `add_entity_use`? - // if (ce->proc != nullptr) { - // Entity *e = entity_of_node(&c->info, ce->proc); - // if (e != nullptr && e->kind == Entity_Procedure) { - // String msg = e->Procedure.deprecated_message; - // if (msg.len > 0) { - // warning(call, "%.*s is deprecated: %.*s", LIT(e->token.string), LIT(msg)); - // } - // } - // } - CallArgumentData data = check_call_arguments(c, operand, proc_type, call); Type *result_type = data.result_type; gb_zero_item(operand); diff --git a/src/checker.cpp b/src/checker.cpp index 994e0776d..f30273439 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2613,14 +2613,14 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { Entity *e = nullptr; d->attributes = vd->attributes; + d->type_expr = vd->type; + d->init_expr = init; if (is_ast_type(init)) { e = alloc_entity_type_name(d->scope, token, nullptr); - if (vd->type != nullptr) { - error(name, "A type declaration cannot have an type parameter"); - } - d->type_expr = init; - d->init_expr = init; + // if (vd->type != nullptr) { + // error(name, "A type declaration cannot have an type parameter"); + // } } else if (init->kind == Ast_ProcLit) { if (c->scope->flags&ScopeFlag_Type) { error(name, "Procedure declarations are not allowed within a struct"); @@ -2647,19 +2647,15 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) { pl->type->ProcType.calling_convention = cc; } d->proc_lit = init; - d->type_expr = vd->type; + d->init_expr = init; } else if (init->kind == Ast_ProcGroup) { ast_node(pg, ProcGroup, init); e = alloc_entity_proc_group(d->scope, token, nullptr); if (fl != nullptr) { error(name, "Procedure groups are not allowed within a foreign block"); } - d->init_expr = init; - d->type_expr = vd->type; } else { e = alloc_entity_constant(d->scope, token, nullptr, empty_exact_value); - d->type_expr = vd->type; - d->init_expr = init; } e->identifier = name; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index fcc6f1973..95d04d93b 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -38,6 +38,7 @@ enum ExactValueKind { ExactValue_Pointer, ExactValue_Compound, // TODO(bill): Is this good enough? ExactValue_Procedure, // TODO(bill): Is this good enough? + ExactValue_Typeid, ExactValue_Count, }; @@ -54,6 +55,7 @@ struct ExactValue { Quaternion256 value_quaternion; Ast * value_compound; Ast * value_procedure; + Type * value_typeid; }; }; @@ -82,6 +84,8 @@ HashKey hash_exact_value(ExactValue v) { return hash_pointer(v.value_compound); case ExactValue_Procedure: return hash_pointer(v.value_procedure); + case ExactValue_Typeid: + return hash_pointer(v.value_typeid); } return hashing_proc(&v, gb_size_of(ExactValue)); @@ -154,6 +158,13 @@ ExactValue exact_value_procedure(Ast *node) { } +ExactValue exact_value_typeid(Type *type) { + ExactValue result = {ExactValue_Typeid}; + result.value_typeid = type; + return result; +} + + ExactValue exact_value_integer_from_string(String const &string) { ExactValue result = {ExactValue_Integer}; big_int_from_string(&result.value_integer, string); @@ -889,6 +900,13 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) { } break; } + + case ExactValue_Typeid: + switch (op) { + case Token_CmpEq: return are_types_identical(x.value_typeid, y.value_typeid); + case Token_NotEq: return !are_types_identical(x.value_typeid, y.value_typeid); + } + break; } GB_PANIC("Invalid comparison"); diff --git a/src/ir.cpp b/src/ir.cpp index 758267c24..f29d389f4 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6592,6 +6592,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { return ir_emit_conv(proc, x, tv.type); } + if (tv.value.kind == ExactValue_Typeid) { + irValue *v = ir_typeid(proc->module, tv.value.value_typeid); + return ir_emit_conv(proc, v, tv.type); + } + return ir_add_module_constant(proc->module, tv.type, tv.value); } diff --git a/src/parser.cpp b/src/parser.cpp index 204ff3984..fb093ffd9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1923,10 +1923,6 @@ Ast *parse_operand(AstFile *f, bool lhs) { case Token_typeid: { Token token = expect_token(f, Token_typeid); - // Ast *specialization = nullptr; - // if (allow_token(f, Token_Quo)) { - // specialization = parse_type(f); - // } return ast_typeid_type(f, token, nullptr); } break; -- cgit v1.2.3 From 5b52fed268b3544bea562f4263d447b96ebacd3a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 10 Oct 2019 20:41:16 +0100 Subject: Correct (experimental) System V AMD64 ABI support --- src/check_type.cpp | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/ir.cpp | 111 ++++++++++++++++++++++++++-------- src/ir_print.cpp | 84 ++++++++++++++++++-------- 3 files changed, 317 insertions(+), 52 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 65e0bc880..fe5825c47 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1837,6 +1837,168 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) { return tuple; } +Array systemv_distribute_struct_fields(Type *t, i32 level=0) { + t = base_type(t); + GB_ASSERT_MSG(t->kind == Type_Struct, "%s %d", type_to_string(t), level); + TypeStruct *ts = &t->Struct; + + auto distributed = array_make(heap_allocator(), 0, ts->fields.count); + + for_array(field_index, ts->fields) { + Entity *f = ts->fields[field_index]; + Type *bt = core_type(f->type); + switch (bt->kind) { + case Type_Struct: + if (bt->Struct.is_raw_union) { + goto DEFAULT; + } else { + // IMPORTANT TOOD(bill): handle #packed structs correctly + // IMPORTANT TODO(bill): handle #align structs correctly + auto nested = systemv_distribute_struct_fields(f->type, level+1); + for_array(i, nested) { + array_add(&distributed, nested[i]); + } + array_free(&nested); + } + break; + + case Type_Array: + for (i64 i = 0; i < bt->Array.count; i++) { + array_add(&distributed, bt->Array.elem); + } + break; + + case Type_BitSet: + array_add(&distributed, bit_set_to_int(bt)); + break; + + case Type_Tuple: + GB_PANIC("Invalid struct field type"); + break; + + case Type_Slice: + case Type_DynamicArray: + case Type_Map: + case Type_Union: + case Type_BitField: // TODO(bill): Ignore? + // NOTE(bill, 2019-10-10): Odin specific, don't worry about C calling convention yet + goto DEFAULT; + + case Type_Pointer: + case Type_Proc: + case Type_SimdVector: // TODO(bill): Is this correct logic? + default: + DEFAULT:; + if (type_size_of(bt) > 0) { + array_add(&distributed, bt); + } + break; + } + } + + return distributed; +} + +Type *struct_type_from_systemv_distribute_struct_fields(Type *abi_type) { + GB_ASSERT(is_type_tuple(abi_type)); + Type *final_type = alloc_type_struct(); + final_type->Struct.fields = abi_type->Tuple.variables; + return final_type; +} + + +Type *handle_single_distributed_type_parameter(Array const &types, bool packed, isize *offset) { + GB_ASSERT(types.count > 0); + + if (types.count == 1) { + if (offset) *offset = 1; + if (is_type_float(types[0])) { + return types[0]; + } else if (type_size_of(types[0]) == 8) { + return types[0]; + } else { + return t_u64; + } + } else if (types.count >= 2) { + if (types[0] == t_f32 && types[1] == t_f32) { + if (offset) *offset = 2; + return alloc_type_simd_vector(2, t_f32); + } else if (type_size_of(types[0]) == 8) { + if (offset) *offset = 1; + return types[0]; + } + + i64 total_size = 0; + isize i = 0; + if (packed) { + for (; i < types.count && total_size < 8; i += 1) { + Type *t = types[i]; + i64 s = type_size_of(t); + total_size += s; + } + } else { + for (; i < types.count && total_size < 8; i += 1) { + Type *t = types[i]; + i64 s = gb_max(type_size_of(t), 0); + i64 a = gb_max(type_align_of(t), 1); + isize ts = align_formula(total_size, a); + if (ts >= 8) { + break; + } + total_size = ts + s; + } + } + if (offset) *offset = i; + return t_u64; + } + + return nullptr; +} + +Type *handle_struct_system_v_amd64_abi_type(Type *t) { + GB_ASSERT(is_type_struct(t)); + Type *bt = core_type(t); + i64 size = type_size_of(bt); + + if (!bt->Struct.is_raw_union) { + auto field_types = systemv_distribute_struct_fields(bt); + defer (array_free(&field_types)); + + GB_ASSERT(field_types.count <= 16); + + Type *final_type = nullptr; + + if (field_types.count == 0) { + // Do nothing + } else if (field_types.count == 1) { + final_type = field_types[0]; + } else { + if (size <= 8) { + isize offset = 0; + final_type = handle_single_distributed_type_parameter(field_types, bt->Struct.is_packed, &offset); + } else { + isize offset = 0; + isize next_offset = 0; + Type *two_types[2] = {}; + + two_types[0] = handle_single_distributed_type_parameter(field_types, bt->Struct.is_packed, &offset); + auto remaining = array_slice(field_types, offset, field_types.count); + two_types[1] = handle_single_distributed_type_parameter(remaining, bt->Struct.is_packed, &next_offset); + GB_ASSERT(offset + next_offset == field_types.count); + + auto variables = array_make(heap_allocator(), 2); + variables[0] = alloc_entity_param(nullptr, empty_token, two_types[0], false, false); + variables[1] = alloc_entity_param(nullptr, empty_token, two_types[1], false, false); + final_type = alloc_type_tuple(); + final_type->Tuple.variables = variables; + } + } + return final_type; + } else { + return t; + } +} + Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc) { Type *new_type = original_type; @@ -1901,6 +2063,7 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall { i64 align = type_align_of(original_type); i64 size = type_size_of(original_type); + switch (8*size) { case 8: new_type = t_u8; break; case 16: new_type = t_u16; break; @@ -1944,6 +2107,15 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall i64 size = type_size_of(original_type); if (8*size > 16) { new_type = alloc_type_pointer(original_type); + } else if (build_context.ODIN_ARCH == "amd64") { + // NOTE(bill): System V AMD64 ABI + if (bt->Struct.is_raw_union) { + // TODO(bill): Handle raw union correctly for + break; + } + + new_type = handle_struct_system_v_amd64_abi_type(bt); + return new_type; } break; @@ -2018,7 +2190,7 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCal } } else if (build_context.ODIN_OS == "linux" || build_context.ODIN_OS == "darwin") { if (build_context.ODIN_ARCH == "amd64") { - + } } else { // IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for diff --git a/src/ir.cpp b/src/ir.cpp index f29d389f4..16a017407 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -147,6 +147,7 @@ struct irProcedure { Array context_stack; + i32 parameter_count; irValue *return_ptr_hint_value; Ast * return_ptr_hint_ast; @@ -425,6 +426,7 @@ enum irParamPasskind { irParamPass_Integer, // Pass as an integer of the same size irParamPass_ConstRef, // Pass as a pointer but the value is immutable irParamPass_BitCast, // Pass by value and bit cast to the correct type + irParamPass_Tuple, // Pass across multiple parameters (System V AMD64, up to 2) }; struct irValueParam { @@ -433,6 +435,7 @@ struct irValueParam { Entity * entity; Type * type; Type * original_type; + i32 index; Array referrers; }; @@ -914,15 +917,18 @@ irValue *ir_value_global(Entity *e, irValue *value) { if (value) value->uses += 1; return v; } -irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type) { +irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type, i32 index) { irValue *v = ir_alloc_value(irValue_Param); v->Param.kind = irParamPass_Value; v->Param.parent = parent; - v->Param.entity = e; - v->Param.original_type = e->type; + if (e != nullptr) { + v->Param.entity = e; + v->Param.original_type = e->type; + } v->Param.type = abi_type; + v->Param.index = index; - if (abi_type != e->type) { + if (e != nullptr && abi_type != e->type) { if (is_type_pointer(abi_type)) { GB_ASSERT(e->kind == Entity_Variable); v->Param.kind = irParamPass_Pointer; @@ -935,8 +941,12 @@ irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type) { v->Param.kind = irParamPass_Value; } else if (is_type_simd_vector(abi_type)) { v->Param.kind = irParamPass_BitCast; + } else if (is_type_float(abi_type)) { + v->Param.kind = irParamPass_BitCast; + } else if (is_type_tuple(abi_type)) { + v->Param.kind = irParamPass_Tuple; } else { - GB_PANIC("Invalid abi type pass kind"); + GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type)); } } array_init(&v->Param.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here @@ -1429,7 +1439,7 @@ irValue *ir_value_procedure(irModule *m, Entity *entity, Type *type, Ast *type_e Type *t = base_type(type); GB_ASSERT(is_type_proc(t)); - array_init(&v->Proc.params, ir_allocator(), 0, t->Proc.param_count); + array_init(&v->Proc.params, heap_allocator(), 0, t->Proc.param_count); return v; } @@ -1499,7 +1509,9 @@ void ir_start_block(irProcedure *proc, irBlock *block) { } - +irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t); +irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val); +irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index); @@ -1713,9 +1725,12 @@ irValue *ir_add_global_generated(irModule *m, Type *type, irValue *value) { irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type, i32 index) { - irValue *v = ir_value_param(proc, e, abi_type); + irValue *v = ir_value_param(proc, e, abi_type, index); + array_add(&proc->params, v); irValueParam *p = &v->Param; + irValue *res = nullptr; + ir_push_debug_location(proc->module, e ? e->identifier : nullptr, proc->debug_scope, e); defer (ir_pop_debug_location(proc->module)); @@ -1750,6 +1765,24 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type, i ir_emit_store(proc, l, x); return x; } + case irParamPass_Tuple: { + irValue *l = ir_add_local(proc, e, expr, true, index); + Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type); + irValue *ptr = ir_emit_bitcast(proc, l, alloc_type_pointer(st)); + if (abi_type->Tuple.variables.count > 0) { + array_pop(&proc->params); + } + for_array(i, abi_type->Tuple.variables) { + Type *t = abi_type->Tuple.variables[i]->type; + + irValue *elem = ir_value_param(proc, nullptr, t, index+cast(i32)i); + array_add(&proc->params, elem); + + irValue *dst = ir_emit_struct_ep(proc, ptr, cast(i32)i); + ir_emit_store(proc, dst, elem); + } + return ir_emit_load(proc, l); + } } @@ -2945,10 +2978,6 @@ void ir_emit_unreachable(irProcedure *proc) { ir_emit(proc, ir_instr_unreachable(proc)); } -irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t); -irValue *ir_address_from_load_or_generate_local(irProcedure *proc, irValue *val); -irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index); - irValue *ir_get_package_value(irModule *m, String package_name, String entity_name) { AstPackage *rt_pkg = get_core_package(m->info, package_name); @@ -2998,7 +3027,7 @@ Array ir_value_to_array(irProcedure *p, irValue *value) { } -irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false) { +irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false) { Type *pt = base_type(ir_type(value)); GB_ASSERT(pt->kind == Type_Proc); Type *results = pt->Proc.results; @@ -3008,6 +3037,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro context_ptr = ir_find_or_generate_context_ptr(p); } + bool is_c_vararg = pt->Proc.c_vararg; isize param_count = pt->Proc.param_count; if (is_c_vararg) { @@ -3016,9 +3046,13 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro } else { GB_ASSERT_MSG(param_count == args.count, "%td == %td", param_count, args.count); } + + auto processed_args = array_make(heap_allocator(), 0, args.count); + for (isize i = 0; i < param_count; i++) { Entity *e = pt->Proc.params->Tuple.variables[i]; if (e->kind != Entity_Variable) { + array_add(&processed_args, args[i]); continue; } GB_ASSERT(e->flags & EntityFlag_Param); @@ -3027,20 +3061,29 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro Type *new_type = pt->Proc.abi_compat_params[i]; Type *arg_type = ir_type(args[i]); if (are_types_identical(arg_type, new_type)) { + array_add(&processed_args, args[i]); // NOTE(bill): Done } else if (!are_types_identical(original_type, new_type)) { if (is_type_pointer(new_type) && !is_type_pointer(original_type)) { if (e->flags&EntityFlag_ImplicitReference) { - args[i] = ir_address_from_load_or_generate_local(p, args[i]); + array_add(&processed_args, ir_address_from_load_or_generate_local(p, args[i])); } else if (!is_type_pointer(arg_type)) { - args[i] = ir_copy_value_to_ptr(p, args[i], original_type, 16); + array_add(&processed_args, ir_copy_value_to_ptr(p, args[i], original_type, 16)); } } else if (is_type_integer(new_type)) { - args[i] = ir_emit_transmute(p, args[i], new_type); + array_add(&processed_args, ir_emit_transmute(p, args[i], new_type)); } else if (new_type == t_llvm_bool) { - args[i] = ir_emit_conv(p, args[i], new_type); + array_add(&processed_args, ir_emit_conv(p, args[i], new_type)); } else if (is_type_simd_vector(new_type)) { - args[i] = ir_emit_bitcast(p, args[i], new_type); + array_add(&processed_args, ir_emit_bitcast(p, args[i], new_type)); + } else if (is_type_tuple(new_type)) { + Type *abi_type = pt->Proc.abi_compat_params[i]; + Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type); + irValue *x = ir_emit_transmute(p, args[i], st); + for (isize j = 0; j < new_type->Tuple.variables.count; j++) { + irValue *xx = ir_emit_struct_ev(p, x, cast(i32)j); + array_add(&processed_args, xx); + } } } } @@ -3066,10 +3109,10 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro return_ptr = ir_add_local_generated(p, rt, true); } GB_ASSERT(is_type_pointer(ir_type(return_ptr))); - ir_emit(p, ir_instr_call(p, value, return_ptr, args, nullptr, context_ptr, inlining)); + ir_emit(p, ir_instr_call(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining)); result = ir_emit_load(p, return_ptr); } else { - result = ir_emit(p, ir_instr_call(p, value, nullptr, args, abi_rt, context_ptr, inlining)); + result = ir_emit(p, ir_instr_call(p, value, nullptr, processed_args, abi_rt, context_ptr, inlining)); if (abi_rt != results) { result = ir_emit_transmute(p, result, rt); } @@ -9540,6 +9583,7 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) { //////////////////////////////////////////////////////////////// void ir_number_proc_registers(irProcedure *proc) { + // i32 reg_index = proc->parameter_count; i32 reg_index = 0; for_array(i, proc->blocks) { irBlock *b = proc->blocks[i]; @@ -9595,13 +9639,15 @@ void ir_begin_procedure_body(irProcedure *proc) { proc->entry_block = ir_new_block(proc, proc->type_expr, "entry"); ir_start_block(proc, proc->entry_block); + i32 parameter_index = 0; + if (proc->type->Proc.return_by_pointer) { // NOTE(bill): this must be the first parameter stored Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(proc->type->Proc.results)); Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false); e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; - irValue *param = ir_value_param(proc, e, ptr_type); + irValue *param = ir_value_param(proc, e, ptr_type, -1); param->Param.kind = irParamPass_Pointer; ir_module_add_value(proc->module, e, param); @@ -9630,13 +9676,19 @@ void ir_begin_procedure_body(irProcedure *proc) { Entity *e = params->variables[i]; if (e->kind != Entity_Variable) { + parameter_index += 1; continue; } Type *abi_type = proc->type->Proc.abi_compat_params[i]; if (e->token.string != "" && !is_blank_ident(e->token)) { - irValue *param = ir_add_param(proc, e, name, abi_type, cast(i32)(i+1)); - array_add(&proc->params, param); + ir_add_param(proc, e, name, abi_type, parameter_index); + } + + if (is_type_tuple(abi_type)) { + parameter_index += cast(i32)abi_type->Tuple.variables.count; + } else { + parameter_index += 1; } } } else { @@ -9645,6 +9697,7 @@ void ir_begin_procedure_body(irProcedure *proc) { for_array(i, params->variables) { Entity *e = params->variables[i]; if (e->kind != Entity_Variable) { + parameter_index += 1; continue; } Type *abi_type = e->type; @@ -9652,8 +9705,12 @@ void ir_begin_procedure_body(irProcedure *proc) { abi_type = abi_types[i]; } if (e->token.string != "" && !is_blank_ident(e->token)) { - irValue *param = ir_add_param(proc, e, nullptr, abi_type, cast(i32)(i+1)); - array_add(&proc->params, param); + ir_add_param(proc, e, nullptr, abi_type, parameter_index); + } + if (is_type_tuple(abi_type)) { + parameter_index += cast(i32)abi_type->Tuple.variables.count; + } else { + parameter_index += 1; } } } @@ -9695,11 +9752,13 @@ void ir_begin_procedure_body(irProcedure *proc) { if (proc->type->Proc.calling_convention == ProcCC_Odin) { Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("__.context_ptr")), t_context_ptr, false, false); e->flags |= EntityFlag_NoAlias; - irValue *param = ir_value_param(proc, e, e->type); + irValue *param = ir_value_param(proc, e, e->type, -1); ir_module_add_value(proc->module, e, param); irContextData ctx = {param, proc->scope_index}; array_add(&proc->context_stack, ctx); } + + proc->parameter_count = parameter_index; } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index db9eb1bfb..f76539fd6 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1130,7 +1130,11 @@ void ir_print_value(irFileBuffer *f, irModule *m, irValue *value, Type *type_hin break; } case irValue_Param: - ir_print_encoded_local(f, value->Param.entity->token.string); + if (value->Param.index >= 0) { + ir_fprintf(f, "%%_.%d", value->Param.index); + } else { + ir_print_encoded_local(f, value->Param.entity->token.string); + } break; case irValue_SourceCodeLocation: { irValue *file = value->SourceCodeLocation.file; @@ -1936,9 +1940,6 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { } ir_write_byte(f, ' '); irValue *arg = call->args[i]; - if (is_type_boolean(t)) { - - } ir_print_value(f, m, arg, t); param_index++; } @@ -1953,24 +1954,43 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { param_index++; } } else { - GB_ASSERT(call->args.count == params->variables.count); + // GB_ASSERT(call->args.count == params->variables.count); + isize arg_index = 0; for_array(i, params->variables) { Entity *e = params->variables[i]; GB_ASSERT(e != nullptr); - if (e->kind != Entity_Variable) continue; + if (e->kind != Entity_Variable) { + arg_index++; + continue; + } if (param_index > 0) ir_write_str_lit(f, ", "); - irValue *arg = call->args[i]; Type *t = proc_type->Proc.abi_compat_params[i]; - - ir_print_type(f, m, t); - if (e->flags&EntityFlag_NoAlias) { - ir_write_str_lit(f, " noalias"); + if (is_type_tuple(t)) { + for_array(j, t->Tuple.variables) { + if (j > 0) ir_write_str_lit(f, ", "); + + irValue *arg = call->args[arg_index++]; + + ir_print_type(f, m, t->Tuple.variables[j]->type); + if (e->flags&EntityFlag_NoAlias) { + ir_write_str_lit(f, " noalias"); + } + ir_write_byte(f, ' '); + ir_print_value(f, m, arg, t); + param_index++; + } + } else { + irValue *arg = call->args[arg_index++]; + ir_print_type(f, m, t); + if (e->flags&EntityFlag_NoAlias) { + ir_write_str_lit(f, " noalias"); + } + ir_write_byte(f, ' '); + ir_print_value(f, m, arg, t); + param_index++; } - ir_write_byte(f, ' '); - ir_print_value(f, m, arg, t); - param_index++; } } } @@ -2089,7 +2109,8 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { if (param_count > 0) { TypeTuple *params = &proc_type->params->Tuple; - for (isize i = 0; i < param_count; i++) { + isize parameter_index = 0; + for (isize i = 0; i < param_count; i++, parameter_index++) { Entity *e = params->variables[i]; Type *original_type = e->type; Type *abi_type = proc_type->abi_compat_params[i]; @@ -2099,16 +2120,29 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { if (i+1 == params->variables.count && proc_type->c_vararg) { ir_write_str_lit(f, " ..."); } else { - ir_print_type(f, m, abi_type); - if (e->flags&EntityFlag_NoAlias) { - ir_write_str_lit(f, " noalias"); - } - if (proc->body != nullptr) { - if (e->token.string != "" && !is_blank_ident(e->token)) { - ir_write_byte(f, ' '); - ir_print_encoded_local(f, e->token.string); - } else { - ir_fprintf(f, " %%_.param_%td", i); + if (is_type_tuple(abi_type)) { + for_array(j, abi_type->Tuple.variables) { + if (j > 0) ir_write_string(f, str_lit(", ")); + + Type *tft = abi_type->Tuple.variables[j]->type; + ir_print_type(f, m, tft); + if (e->flags&EntityFlag_NoAlias) { + ir_write_str_lit(f, " noalias"); + } + + if (proc->body != nullptr) { + ir_fprintf(f, " %%_.%td", parameter_index+j); + } + } + parameter_index += abi_type->Tuple.variables.count-1; + param_index += abi_type->Tuple.variables.count-1; + } else { + ir_print_type(f, m, abi_type); + if (e->flags&EntityFlag_NoAlias) { + ir_write_str_lit(f, " noalias"); + } + if (proc->body != nullptr) { + ir_fprintf(f, " %%_.%td", parameter_index); } } } -- cgit v1.2.3 From abfa8945661f24006e4f8506c1ec2861569228ec Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 10 Oct 2019 20:52:07 +0100 Subject: Fix general IR parameter case --- src/check_type.cpp | 16 +++++++++------- src/ir.cpp | 5 ++++- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index fe5825c47..89ee15666 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2108,14 +2108,16 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCall if (8*size > 16) { new_type = alloc_type_pointer(original_type); } else if (build_context.ODIN_ARCH == "amd64") { - // NOTE(bill): System V AMD64 ABI - if (bt->Struct.is_raw_union) { - // TODO(bill): Handle raw union correctly for - break; - } + if (is_type_struct(bt)) { + // NOTE(bill): System V AMD64 ABI + if (bt->Struct.is_raw_union) { + // TODO(bill): Handle raw union correctly for + break; + } - new_type = handle_struct_system_v_amd64_abi_type(bt); - return new_type; + new_type = handle_struct_system_v_amd64_abi_type(bt); + return new_type; + } } break; diff --git a/src/ir.cpp b/src/ir.cpp index 16a017407..017a12025 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3061,8 +3061,8 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &ar Type *new_type = pt->Proc.abi_compat_params[i]; Type *arg_type = ir_type(args[i]); if (are_types_identical(arg_type, new_type)) { - array_add(&processed_args, args[i]); // NOTE(bill): Done + array_add(&processed_args, args[i]); } else if (!are_types_identical(original_type, new_type)) { if (is_type_pointer(new_type) && !is_type_pointer(original_type)) { if (e->flags&EntityFlag_ImplicitReference) { @@ -3085,6 +3085,9 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &ar array_add(&processed_args, xx); } } + } else { + irValue *x = ir_emit_conv(p, args[i], new_type); + array_add(&processed_args, x); } } -- cgit v1.2.3 From 03053a18ce78e567cf1ee596c4975e69790d3def Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 13 Oct 2019 12:51:47 +0100 Subject: Fix IR generation bug for nested foreign procedure declaration --- src/ir.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 017a12025..0bf706f67 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8265,24 +8265,27 @@ void ir_build_constant_value_decl(irProcedure *proc, AstValueDecl *vd) { name = e->Procedure.link_name; } + HashKey key = hash_string(name); + irValue **prev_value = map_get(&proc->module->members, key); + if (prev_value != nullptr) { + // NOTE(bill): Don't do mutliple declarations in the IR + return; + } + + irValue *value = ir_value_procedure(proc->module, e, e->type, pl->type, pl->body, name); value->Proc.tags = pl->tags; value->Proc.inlining = pl->inlining; - ir_module_add_value(proc->module, e, value); - ir_build_proc(value, proc); - if (value->Proc.is_foreign || value->Proc.is_export) { - HashKey key = hash_string(name); - irValue **prev_value = map_get(&proc->module->members, key); - if (prev_value == nullptr) { - // NOTE(bill): Don't do mutliple declarations in the IR - map_set(&proc->module->members, key, value); - } + map_set(&proc->module->members, key, value); } else { array_add(&proc->children, &value->Proc); } + + ir_module_add_value(proc->module, e, value); + ir_build_proc(value, proc); } } } -- cgit v1.2.3 From f12ded54f2b1a390f556e67a17ff0bf4c301a8e3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 20 Oct 2019 13:11:28 +0100 Subject: Support for named indices for array-like compound literals `{3 = a, 1 = b}` --- src/check_expr.cpp | 103 +++++++++++++++++++++++++++++++++++++----------- src/ir.cpp | 112 +++++++++++++++++++++++++++++++++++++++-------------- src/ir_print.cpp | 60 +++++++++++++++++++++------- src/parser.hpp | 1 + 4 files changed, 213 insertions(+), 63 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b2a2528dd..60c057ae9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7066,7 +7066,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type i64 max = 0; - isize index = 0; Type *bet = base_type(elem_type); if (!elem_type_can_be_constant(bet)) { @@ -7077,40 +7076,100 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type break; } - for (; index < cl->elems.count; index++) { - Ast *e = cl->elems[index]; - if (e == nullptr) { - error(node, "Invalid literal element"); - continue; - } + if (cl->elems[0]->kind == Ast_FieldValue) { + if (is_type_simd_vector(t)) { + error(cl->elems[0], "'field = value' is not allowed for SIMD vector literals"); + } else { + Map seen = {}; + map_init(&seen, heap_allocator()); + defer (map_destroy(&seen)); - if (e->kind == Ast_FieldValue) { - error(e, "'field = value' is only allowed in struct literals"); - continue; - } + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind != Ast_FieldValue) { + error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } + ast_node(fv, FieldValue, elem); + + Operand op_index = {}; + check_expr(c, &op_index, fv->field); + + if (op_index.mode != Addressing_Constant || !is_type_integer(core_type(op_index.type))) { + error(elem, "Expected a constant integer as an array field"); + continue; + } + + i64 index = exact_value_to_i64(op_index.value); + + if (max_type_count >= 0 && (index < 0 || index >= max_type_count)) { + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", index, max_type_count, LIT(context_name)); + continue; + } + + if (map_get(&seen, hash_integer(u64(index))) != nullptr) { + error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name)); + continue; + } + map_set(&seen, hash_integer(u64(index)), true); + + if (max < index) { + max = index; + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, fv->value, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + } - if (0 <= max_type_count && max_type_count <= index) { - error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name)); + cl->max_index = max; } - Operand operand = {}; - check_expr_with_type_hint(c, &operand, e, elem_type); - check_assignment(c, &operand, elem_type, context_name); - is_constant = is_constant && operand.mode == Addressing_Constant; - } - if (max < index) { - max = index; + } else { + isize index = 0; + for (; index < cl->elems.count; index++) { + Ast *e = cl->elems[index]; + if (e == nullptr) { + error(node, "Invalid literal element"); + continue; + } + + if (e->kind == Ast_FieldValue) { + error(e, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } + + if (0 <= max_type_count && max_type_count <= index) { + error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name)); + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, e, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + } + + if (max < index) { + max = index; + } } + if (t->kind == Type_Array) { if (is_to_be_determined_array_count) { t->Array.count = max; - } else if (0 < max && max < t->Array.count) { - error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max); + } else if (cl->elems[0]->kind != Ast_FieldValue) { + if (0 < max && max < t->Array.count) { + error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max); + } } } + if (t->kind == Type_SimdVector) { if (!is_constant) { error(node, "Expected all constant elements for a simd vector"); diff --git a/src/ir.cpp b/src/ir.cpp index 0bf706f67..bea9ee8b3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1552,6 +1552,7 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) { if (count == 0) { return ir_value_nil(type); } + count = gb_max(cl->max_index+1, count); Type *elem = base_type(type)->Slice.elem; Type *t = alloc_type_array(elem, count); irValue *backing_array = ir_add_module_constant(m, t, value); @@ -7859,13 +7860,29 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { // NOTE(bill): Separate value, gep, store into their own chunks for_array(i, cl->elems) { Ast *elem = cl->elems[i]; - if (ir_is_elem_const(proc->module, elem, et)) { - continue; + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + if (ir_is_elem_const(proc->module, fv->value, et)) { + continue; + } + auto tav = fv->field->tav; + GB_ASSERT(tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(tav.value); + + irCompoundLitElemTempData data = {}; + data.expr = fv->value; + data.elem_index = cast(i32)index; + array_add(&temp_data, data); + + } else { + if (ir_is_elem_const(proc->module, elem, et)) { + continue; + } + irCompoundLitElemTempData data = {}; + data.expr = elem; + data.elem_index = cast(i32)i; + array_add(&temp_data, data); } - irCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); } for_array(i, temp_data) { @@ -7881,6 +7898,9 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { defer (proc->return_ptr_hint_used = return_ptr_hint_used); Ast *expr = temp_data[i].expr; + if (expr == nullptr) { + continue; + } proc->return_ptr_hint_value = temp_data[i].gep; proc->return_ptr_hint_ast = unparen_expr(expr); @@ -7918,18 +7938,40 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { for_array(i, cl->elems) { Ast *elem = cl->elems[i]; - if (ir_is_elem_const(proc->module, elem, et)) { - continue; - } - irValue *field_expr = ir_build_expr(proc, elem); - Type *t = ir_type(field_expr); - GB_ASSERT(t->kind != Type_Tuple); - irValue *ev = ir_emit_conv(proc, field_expr, et); + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); - irCompoundLitElemTempData data = {}; - data.value = ev; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); + if (ir_is_elem_const(proc->module, fv->value, et)) { + continue; + } + + + GB_ASSERT(fv->field->tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(fv->field->tav.value); + + irValue *field_expr = ir_build_expr(proc, fv->value); + GB_ASSERT(!is_type_tuple(ir_type(field_expr))); + + irValue *ev = ir_emit_conv(proc, field_expr, et); + + irCompoundLitElemTempData data = {}; + data.value = ev; + data.elem_index = cast(i32)index; + array_add(&temp_data, data); + } else { + if (ir_is_elem_const(proc->module, elem, et)) { + continue; + } + irValue *field_expr = ir_build_expr(proc, elem); + GB_ASSERT(!is_type_tuple(ir_type(field_expr))); + + irValue *ev = ir_emit_conv(proc, field_expr, et); + + irCompoundLitElemTempData data = {}; + data.value = ev; + data.elem_index = cast(i32)i; + array_add(&temp_data, data); + } } for_array(i, temp_data) { @@ -7950,28 +7992,42 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { if (cl->elems.count == 0) { break; } - Type *elem = bt->DynamicArray.elem; + Type *et = bt->DynamicArray.elem; gbAllocator a = ir_allocator(); - irValue *size = ir_const_int(type_size_of(elem)); - irValue *align = ir_const_int(type_align_of(elem)); + irValue *size = ir_const_int(type_size_of(et)); + irValue *align = ir_const_int(type_align_of(et)); + + i64 item_count = gb_max(cl->max_index+1, cl->elems.count); { + auto args = array_make(a, 5); args[0] = ir_emit_conv(proc, v, t_rawptr); args[1] = size; args[2] = align; - args[3] = ir_const_int(2*cl->elems.count); + args[3] = ir_const_int(2*item_count); // TODO(bill): Is this too much waste? args[4] = ir_emit_source_code_location(proc, proc_name, pos); ir_emit_runtime_call(proc, "__dynamic_array_reserve", args); } - i64 item_count = cl->elems.count; - irValue *items = ir_generate_array(proc->module, elem, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr); + irValue *items = ir_generate_array(proc->module, et, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr); - for_array(field_index, cl->elems) { - Ast *f = cl->elems[field_index]; - irValue *value = ir_emit_conv(proc, ir_build_expr(proc, f), elem); - irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index); - ir_emit_store(proc, ep, value); + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + GB_ASSERT(fv->field->tav.mode == Addressing_Constant); + + i64 field_index = exact_value_to_i64(fv->field->tav.value); + + irValue *ev = ir_build_expr(proc, fv->value); + irValue *value = ir_emit_conv(proc, ev, et); + irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index); + ir_emit_store(proc, ep, value); + } else { + irValue *value = ir_emit_conv(proc, ir_build_expr(proc, elem), et); + irValue *ep = ir_emit_array_epi(proc, items, cast(i32)i); + ir_emit_store(proc, ep, value); + } } { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index f76539fd6..cece0c1db 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -876,22 +876,56 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * ir_write_str_lit(f, "zeroinitializer"); break; } - GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); + if (cl->elems[0]->kind == Ast_FieldValue) { + // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand + ir_write_byte(f, '['); + for (i64 i = 0; i < type->Array.count; i++) { + if (i > 0) ir_write_str_lit(f, ", "); + + bool found = false; + + for (isize j = 0; j < elem_count; j++) { + Ast *elem = cl->elems[j]; + ast_node(fv, FieldValue, elem); + TypeAndValue index_tav = fv->field->tav; + GB_ASSERT(index_tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(index_tav.value); + if (index == i) { + TypeAndValue tav = fv->value->tav; + if (tav.mode != Addressing_Constant) { + break; + } + ir_print_compound_element(f, m, tav.value, elem_type); + found = true; + break; + } + } - ir_write_byte(f, '['); + if (!found) { + ir_print_type(f, m, elem_type); + ir_write_byte(f, ' '); + ir_write_str_lit(f, "zeroinitializer"); + } + } + ir_write_byte(f, ']'); + } else { + GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); - for (isize i = 0; i < elem_count; i++) { - if (i > 0) ir_write_str_lit(f, ", "); - TypeAndValue tav = cl->elems[i]->tav; - GB_ASSERT(tav.mode != Addressing_Invalid); - ir_print_compound_element(f, m, tav.value, elem_type); - } - for (isize i = elem_count; i < type->Array.count; i++) { - if (i >= elem_count) ir_write_str_lit(f, ", "); - ir_print_compound_element(f, m, empty_exact_value, elem_type); - } + ir_write_byte(f, '['); - ir_write_byte(f, ']'); + for (isize i = 0; i < elem_count; i++) { + if (i > 0) ir_write_str_lit(f, ", "); + TypeAndValue tav = cl->elems[i]->tav; + GB_ASSERT(tav.mode != Addressing_Invalid); + ir_print_compound_element(f, m, tav.value, elem_type); + } + for (isize i = elem_count; i < type->Array.count; i++) { + if (i >= elem_count) ir_write_str_lit(f, ", "); + ir_print_compound_element(f, m, empty_exact_value, elem_type); + } + + ir_write_byte(f, ']'); + } } else if (is_type_simd_vector(type)) { ast_node(cl, CompoundLit, value.value_compound); diff --git a/src/parser.hpp b/src/parser.hpp index 419cf9da3..9c3f733e5 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -249,6 +249,7 @@ enum StmtAllowFlag { Ast *type; \ Array elems; \ Token open, close; \ + i64 max_index; \ }) \ AST_KIND(_ExprBegin, "", bool) \ AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \ -- cgit v1.2.3 From 94879ed14997c4d2745ddb669d08b34437ceff75 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 12:14:04 +0100 Subject: Fix Compiler assertion when applying `using` to `_` procedure parameter. #451 --- src/check_decl.cpp | 3 +-- src/check_stmt.cpp | 7 +++---- src/entity.cpp | 3 ++- src/ir.cpp | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 5e8479a7f..ebfc29899 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1167,11 +1167,10 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty for_array(i, scope->elements.entries) { Entity *f = scope->elements.entries[i].value; if (f->kind == Entity_Variable) { - Entity *uvar = alloc_entity_using_variable(e, f->token, f->type); + Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr); uvar->Variable.is_immutable = is_immutable; if (is_value) uvar->flags |= EntityFlag_Value; - ProcUsingVar puv = {e, uvar}; array_add(&using_entities, puv); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 26e3f8c26..72913903d 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -496,8 +496,7 @@ bool check_using_stmt_entity(CheckerContext *ctx, AstUsingStmt *us, Ast *expr, b for_array(i, found->elements.entries) { Entity *f = found->elements.entries[i].value; if (f->kind == Entity_Variable) { - Entity *uvar = alloc_entity_using_variable(e, f->token, f->type); - uvar->using_expr = expr; + Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, expr); Entity *prev = scope_insert(ctx->scope, uvar); if (prev != nullptr) { gbString expr_str = expr_to_string(expr); @@ -2052,7 +2051,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { // TODO(bill): Should a 'continue' happen here? } - for (isize entity_index = 0; entity_index < entity_count; entity_index++) { + for (isize entity_index = 0; entity_index < 1; entity_index++) { Entity *e = entities[entity_index]; if (e == nullptr) { continue; @@ -2071,7 +2070,7 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { for_array(i, scope->elements.entries) { Entity *f = scope->elements.entries[i].value; if (f->kind == Entity_Variable) { - Entity *uvar = alloc_entity_using_variable(e, f->token, f->type); + Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr); uvar->Variable.is_immutable = is_immutable; Entity *prev = scope_insert(ctx->scope, uvar); if (prev != nullptr) { diff --git a/src/entity.cpp b/src/entity.cpp index 78726171d..bbea68e8b 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -221,12 +221,13 @@ Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, bool is_imm return entity; } -Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type) { +Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast *using_expr) { GB_ASSERT(parent != nullptr); token.pos = parent->token.pos; Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type); entity->using_parent = parent; entity->parent_proc_decl = parent->parent_proc_decl; + entity->using_expr = using_expr; entity->flags |= EntityFlag_Using; entity->flags |= EntityFlag_Used; entity->state = EntityState_Resolved; diff --git a/src/ir.cpp b/src/ir.cpp index bea9ee8b3..c654e2bf8 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9743,7 +9743,7 @@ void ir_begin_procedure_body(irProcedure *proc) { } Type *abi_type = proc->type->Proc.abi_compat_params[i]; - if (e->token.string != "" && !is_blank_ident(e->token)) { + if (e->token.string != "") { ir_add_param(proc, e, name, abi_type, parameter_index); } @@ -9766,7 +9766,7 @@ void ir_begin_procedure_body(irProcedure *proc) { if (abi_types.count > 0) { abi_type = abi_types[i]; } - if (e->token.string != "" && !is_blank_ident(e->token)) { + if (e->token.string != "") { ir_add_param(proc, e, nullptr, abi_type, parameter_index); } if (is_type_tuple(abi_type)) { -- cgit v1.2.3 From 7fae890ef9eb72f3131914f9af2469f9bfb1e59e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 14:06:29 +0100 Subject: Allow ranges for array-like compound literals --- core/odin/parser/parser.odin | 3 + src/check_expr.cpp | 229 ++++++++++++++++++++++++++++++++++--------- src/check_stmt.cpp | 84 +--------------- src/common.cpp | 3 + src/exact_value.cpp | 2 +- src/ir.cpp | 124 ++++++++++++++++++----- src/ir_print.cpp | 48 +++++++-- src/parser.cpp | 11 ++- src/parser.hpp | 1 + 9 files changed, 340 insertions(+), 165 deletions(-) (limited to 'src/ir.cpp') diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index fee9b7bdc..fb3a87e8b 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2391,6 +2391,9 @@ parse_value :: proc(p: ^Parser) -> ^ast.Expr { if p.curr_tok.kind == .Open_Brace { return parse_literal_value(p, nil); } + prev_allow_range = p.allow_range; + defer p.allow_range = prev_allow_range; + p.allow_range = true; return parse_expr(p, false); } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ea9248089..f07ebe09c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6635,6 +6635,98 @@ bool ternary_compare_types(Type *x, Type *y) { } +bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValue *inline_for_depth_) { + if (!is_ast_range(node)) { + return false; + } + + ast_node(ie, BinaryExpr, node); + + check_expr(c, x, ie->left); + if (x->mode == Addressing_Invalid) { + return false; + } + check_expr(c, y, ie->right); + if (y->mode == Addressing_Invalid) { + return false; + } + + convert_to_typed(c, x, y->type); + if (x->mode == Addressing_Invalid) { + return false; + } + convert_to_typed(c, y, x->type); + if (y->mode == Addressing_Invalid) { + return false; + } + + convert_to_typed(c, x, default_type(y->type)); + if (x->mode == Addressing_Invalid) { + return false; + } + convert_to_typed(c, y, default_type(x->type)); + if (y->mode == Addressing_Invalid) { + return false; + } + + if (!are_types_identical(x->type, y->type)) { + if (x->type != t_invalid && + y->type != t_invalid) { + gbString xt = type_to_string(x->type); + gbString yt = type_to_string(y->type); + gbString expr_str = expr_to_string(x->expr); + error(ie->op, "Mismatched types in interval expression '%s' : '%s' vs '%s'", expr_str, xt, yt); + gb_string_free(expr_str); + gb_string_free(yt); + gb_string_free(xt); + } + return false; + } + + Type *type = x->type; + if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) { + error(ie->op, "Only numerical and pointer types are allowed within interval expressions"); + return false; + } + + if (x->mode == Addressing_Constant && + y->mode == Addressing_Constant) { + ExactValue a = x->value; + ExactValue b = y->value; + + GB_ASSERT(are_types_identical(x->type, y->type)); + + TokenKind op = Token_Lt; + switch (ie->op.kind) { + case Token_Ellipsis: op = Token_LtEq; break; + case Token_RangeHalf: op = Token_Lt; break; + default: error(ie->op, "Invalid range operator"); break; + } + bool ok = compare_exact_values(op, a, b); + if (!ok) { + // TODO(bill): Better error message + error(ie->op, "Invalid interval range"); + return false; + } + + ExactValue inline_for_depth = exact_value_sub(b, a); + if (ie->op.kind == Token_Ellipsis) { + inline_for_depth = exact_value_increment_one(inline_for_depth); + } + + if (inline_for_depth_) *inline_for_depth_ = inline_for_depth; + } else { + error(ie->op, "Interval expressions must be constant"); + return false; + } + + add_type_and_value(&c->checker->info, ie->left, x->mode, x->type, x->value); + add_type_and_value(&c->checker->info, ie->right, y->mode, y->type, y->value); + + return true; +} + + ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Stmt; @@ -6697,35 +6789,26 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type case_ast_node(bl, BasicLit, node); - // NOTE(bill, 2018-06-17): Placing this in the parser is slower than - // placing it here for some reason. So don't move it to the parsing - // stage if you _think_ it will be faster, only do it if you _know_ it - // will be faster. Type *t = t_invalid; - switch (bl->token.kind) { - case Token_Integer: t = t_untyped_integer; break; - case Token_Float: t = t_untyped_float; break; - case Token_String: t = t_untyped_string; break; - case Token_Rune: t = t_untyped_rune; break; - case Token_Imag: { - String s = bl->token.string; - Rune r = s[s.len-1]; - // NOTE(bill, 2019-08-25): Allow for quaternions by having j and k imaginary numbers - switch (r) { - case 'i': t = t_untyped_complex; break; - case 'j': t = t_untyped_quaternion; break; - case 'k': t = t_untyped_quaternion; break; + switch (bl->value.kind) { + case ExactValue_String: t = t_untyped_string; break; + case ExactValue_Float: t = t_untyped_float; break; + case ExactValue_Complex: t = t_untyped_complex; break; + case ExactValue_Quaternion: t = t_untyped_quaternion; break; + case ExactValue_Integer: + t = t_untyped_integer; + if (bl->token.kind == Token_Rune) { + t = t_untyped_rune; } - break; - } default: - GB_PANIC("Unknown literal"); + GB_PANIC("Unhandled value type for basic literal"); break; } + o->mode = Addressing_Constant; o->type = t; - o->value = exact_value_from_basic_literal(bl->token); + o->value = bl->value; case_end; case_ast_node(bd, BasicDirective, node); @@ -7090,9 +7173,8 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (is_type_simd_vector(t)) { error(cl->elems[0], "'field = value' is not allowed for SIMD vector literals"); } else { - Map seen = {}; - map_init(&seen, heap_allocator()); - defer (map_destroy(&seen)); + RangeCache rc = range_cache_make(heap_allocator()); + defer (range_cache_destroy(&rc)); for_array(i, cl->elems) { Ast *elem = cl->elems[i]; @@ -7102,36 +7184,89 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } ast_node(fv, FieldValue, elem); - Operand op_index = {}; - check_expr(c, &op_index, fv->field); + if (is_ast_range(fv->field)) { + Token op = fv->field->BinaryExpr.op; - if (op_index.mode != Addressing_Constant || !is_type_integer(core_type(op_index.type))) { - error(elem, "Expected a constant integer as an array field"); - continue; - } + Operand x = {}; + Operand y = {}; + bool ok = check_range(c, fv->field, &x, &y, nullptr); + if (!ok) { + continue; + } + if (x.mode != Addressing_Constant || !is_type_integer(core_type(x.type))) { + error(x.expr, "Expected a constant integer as an array field"); + continue; + } - i64 index = exact_value_to_i64(op_index.value); + if (y.mode != Addressing_Constant || !is_type_integer(core_type(y.type))) { + error(y.expr, "Expected a constant integer as an array field"); + continue; + } - if (max_type_count >= 0 && (index < 0 || index >= max_type_count)) { - error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", index, max_type_count, LIT(context_name)); - continue; - } + i64 lo = exact_value_to_i64(x.value); + i64 hi = exact_value_to_i64(y.value); + if (op.kind == Token_RangeHalf) { + hi -= 1; + } + i64 max_index = hi; - if (map_get(&seen, hash_integer(u64(index))) != nullptr) { - error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name)); - continue; - } - map_set(&seen, hash_integer(u64(index)), true); + bool new_range = range_cache_add_range(&rc, lo, hi); + if (!new_range) { + error(elem, "Overlapping field range index %lld %.*s %lld for %.*s", lo, LIT(op.string), hi, LIT(context_name)); + continue; + } - if (max < index) { - max = index; - } - Operand operand = {}; - check_expr_with_type_hint(c, &operand, fv->value, elem_type); - check_assignment(c, &operand, elem_type, context_name); + if (max_type_count >= 0 && (lo < 0 || lo >= max_type_count)) { + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", lo, max_type_count, LIT(context_name)); + continue; + } + if (max_type_count >= 0 && (hi < 0 || hi >= max_type_count)) { + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", hi, max_type_count, LIT(context_name)); + continue; + } + + if (max < max_index) { + max = max_index; + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, fv->value, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + } else { + Operand op_index = {}; + check_expr(c, &op_index, fv->field); + + if (op_index.mode != Addressing_Constant || !is_type_integer(core_type(op_index.type))) { + error(elem, "Expected a constant integer as an array field"); + continue; + } - is_constant = is_constant && operand.mode == Addressing_Constant; + i64 index = exact_value_to_i64(op_index.value); + + if (max_type_count >= 0 && (index < 0 || index >= max_type_count)) { + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", index, max_type_count, LIT(context_name)); + continue; + } + + bool new_index = range_cache_add_index(&rc, index); + if (!new_index) { + error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name)); + continue; + } + + if (max < index) { + max = index; + } + + Operand operand = {}; + check_expr_with_type_hint(c, &operand, fv->value, elem_type); + check_assignment(c, &operand, elem_type, context_name); + + is_constant = is_constant && operand.mode == Addressing_Constant; + } } cl->max_index = max; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 72913903d..d4398664b 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -605,89 +605,15 @@ void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { if (is_ast_range(expr)) { ast_node(ie, BinaryExpr, expr); - Operand x = {Addressing_Invalid}; - Operand y = {Addressing_Invalid}; + Operand x = {}; + Operand y = {}; - check_expr(ctx, &x, ie->left); - if (x.mode == Addressing_Invalid) { - goto skip_expr; - } - check_expr(ctx, &y, ie->right); - if (y.mode == Addressing_Invalid) { - goto skip_expr; - } - - convert_to_typed(ctx, &x, y.type); - if (x.mode == Addressing_Invalid) { - goto skip_expr; - } - convert_to_typed(ctx, &y, x.type); - if (y.mode == Addressing_Invalid) { - goto skip_expr; - } - - convert_to_typed(ctx, &x, default_type(y.type)); - if (x.mode == Addressing_Invalid) { - goto skip_expr; - } - convert_to_typed(ctx, &y, default_type(x.type)); - if (y.mode == Addressing_Invalid) { - goto skip_expr; - } - - if (!are_types_identical(x.type, y.type)) { - if (x.type != t_invalid && - y.type != t_invalid) { - gbString xt = type_to_string(x.type); - gbString yt = type_to_string(y.type); - gbString expr_str = expr_to_string(x.expr); - error(ie->op, "Mismatched types in interval expression '%s' : '%s' vs '%s'", expr_str, xt, yt); - gb_string_free(expr_str); - gb_string_free(yt); - gb_string_free(xt); - } - goto skip_expr; - } - - Type *type = x.type; - if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) { - error(ie->op, "Only numerical and pointer types are allowed within interval expressions"); - goto skip_expr; - } - - if (x.mode == Addressing_Constant && - y.mode == Addressing_Constant) { - ExactValue a = x.value; - ExactValue b = y.value; - - GB_ASSERT(are_types_identical(x.type, y.type)); - - TokenKind op = Token_Lt; - switch (ie->op.kind) { - case Token_Ellipsis: op = Token_LtEq; break; - case Token_RangeHalf: op = Token_Lt; break; - default: error(ie->op, "Invalid range operator"); break; - } - bool ok = compare_exact_values(op, a, b); - if (!ok) { - // TODO(bill): Better error message - error(ie->op, "Invalid interval range"); - goto skip_expr; - } - - inline_for_depth = exact_value_sub(b, a); - if (ie->op.kind == Token_Ellipsis) { - inline_for_depth = exact_value_increment_one(inline_for_depth); - } - - } else { - error(ie->op, "Interval expressions must be constant"); + bool ok = check_range(ctx, expr, &x, &y, &inline_for_depth); + if (!ok) { goto skip_expr; } - add_type_and_value(&ctx->checker->info, ie->left, x.mode, x.type, x.value); - add_type_and_value(&ctx->checker->info, ie->right, y.mode, y.type, y.value); - val0 = type; + val0 = x.type; val1 = t_int; } else { Operand operand = {Addressing_Invalid}; diff --git a/src/common.cpp b/src/common.cpp index db6505a36..b034ad720 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -143,6 +143,9 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) { #define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++) +#include "range_cache.cpp" + + u64 fnv64a(void const *data, isize len) { u8 const *bytes = cast(u8 const *)data; diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 95d04d93b..42b22c8ef 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -293,12 +293,12 @@ ExactValue exact_value_from_basic_literal(Token token) { case 'i': return exact_value_complex(0, imag); case 'j': return exact_value_quaternion(0, 0, imag, 0); case 'k': return exact_value_quaternion(0, 0, 0, imag); + default: GB_PANIC("Invalid imaginary basic literal"); } } case Token_Rune: { Rune r = GB_RUNE_INVALID; gb_utf8_decode(token.string.text, token.string.len, &r); - // gb_printf("%.*s rune: %d\n", LIT(token.string), r); return exact_value_i64(r); } default: diff --git a/src/ir.cpp b/src/ir.cpp index c654e2bf8..5eeba91a2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7865,14 +7865,40 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { if (ir_is_elem_const(proc->module, fv->value, et)) { continue; } - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } - irCompoundLitElemTempData data = {}; - data.expr = fv->value; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); + irValue *value = ir_build_expr(proc, fv->value); + + for (i64 k = lo; k < hi; k++) { + irCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = cast(i32)k; + array_add(&temp_data, data); + } + + } else { + auto tav = fv->field->tav; + GB_ASSERT(tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(tav.value); + + irCompoundLitElemTempData data = {}; + data.value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et); + data.expr = fv->value; + data.elem_index = cast(i32)index; + array_add(&temp_data, data); + } } else { if (ir_is_elem_const(proc->module, elem, et)) { @@ -7897,15 +7923,15 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { defer (proc->return_ptr_hint_value = return_ptr_hint_value); defer (proc->return_ptr_hint_used = return_ptr_hint_used); + irValue *field_expr = temp_data[i].value; Ast *expr = temp_data[i].expr; - if (expr == nullptr) { - continue; - } proc->return_ptr_hint_value = temp_data[i].gep; proc->return_ptr_hint_ast = unparen_expr(expr); - irValue *field_expr = ir_build_expr(proc, expr); + if (field_expr == nullptr) { + field_expr = ir_build_expr(proc, expr); + } Type *t = ir_type(field_expr); GB_ASSERT(t->kind != Type_Tuple); irValue *ev = ir_emit_conv(proc, field_expr, et); @@ -7945,19 +7971,43 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { continue; } + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } - GB_ASSERT(fv->field->tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(fv->field->tav.value); + irValue *value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et); - irValue *field_expr = ir_build_expr(proc, fv->value); - GB_ASSERT(!is_type_tuple(ir_type(field_expr))); + for (i64 k = lo; k < hi; k++) { + irCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = cast(i32)k; + array_add(&temp_data, data); + } - irValue *ev = ir_emit_conv(proc, field_expr, et); + } else { + GB_ASSERT(fv->field->tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(fv->field->tav.value); - irCompoundLitElemTempData data = {}; - data.value = ev; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); + irValue *field_expr = ir_build_expr(proc, fv->value); + GB_ASSERT(!is_type_tuple(ir_type(field_expr))); + + irValue *ev = ir_emit_conv(proc, field_expr, et); + + irCompoundLitElemTempData data = {}; + data.value = ev; + data.elem_index = cast(i32)index; + array_add(&temp_data, data); + } } else { if (ir_is_elem_const(proc->module, elem, et)) { continue; @@ -8015,14 +8065,36 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { Ast *elem = cl->elems[i]; if (elem->kind == Ast_FieldValue) { ast_node(fv, FieldValue, elem); - GB_ASSERT(fv->field->tav.mode == Addressing_Constant); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } - i64 field_index = exact_value_to_i64(fv->field->tav.value); + irValue *value = ir_emit_conv(proc, ir_build_expr(proc, fv->value), et); - irValue *ev = ir_build_expr(proc, fv->value); - irValue *value = ir_emit_conv(proc, ev, et); - irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index); - ir_emit_store(proc, ep, value); + for (i64 k = lo; k < hi; k++) { + irValue *ep = ir_emit_array_epi(proc, items, cast(i32)k); + ir_emit_store(proc, ep, value); + } + } else { + GB_ASSERT(fv->field->tav.mode == Addressing_Constant); + + i64 field_index = exact_value_to_i64(fv->field->tav.value); + + irValue *ev = ir_build_expr(proc, fv->value); + irValue *value = ir_emit_conv(proc, ev, et); + irValue *ep = ir_emit_array_epi(proc, items, cast(i32)field_index); + ir_emit_store(proc, ep, value); + } } else { irValue *value = ir_emit_conv(proc, ir_build_expr(proc, elem), et); irValue *ep = ir_emit_array_epi(proc, items, cast(i32)i); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index cece0c1db..1d0c8af35 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -887,17 +887,47 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * for (isize j = 0; j < elem_count; j++) { Ast *elem = cl->elems[j]; ast_node(fv, FieldValue, elem); - TypeAndValue index_tav = fv->field->tav; - GB_ASSERT(index_tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(index_tav.value); - if (index == i) { - TypeAndValue tav = fv->value->tav; - if (tav.mode != Addressing_Constant) { + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op == Token_Ellipsis) { + hi += 1; + } + if (lo == i) { + TypeAndValue tav = fv->value->tav; + if (tav.mode != Addressing_Constant) { + break; + } + for (i64 k = lo; k < hi; k++) { + if (k > lo) ir_write_str_lit(f, ", "); + + ir_print_compound_element(f, m, tav.value, elem_type); + } + + found = true; + i += (hi-lo-1); + break; + } + } else { + TypeAndValue index_tav = fv->field->tav; + GB_ASSERT(index_tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(index_tav.value); + if (index == i) { + TypeAndValue tav = fv->value->tav; + if (tav.mode != Addressing_Constant) { + break; + } + ir_print_compound_element(f, m, tav.value, elem_type); + found = true; break; } - ir_print_compound_element(f, m, tav.value, elem_type); - found = true; - break; } } diff --git a/src/parser.cpp b/src/parser.cpp index 7f866922a..10aa10119 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -588,6 +588,7 @@ Ast *ast_undef(AstFile *f, Token token) { Ast *ast_basic_lit(AstFile *f, Token basic_lit) { Ast *result = alloc_ast_node(f, Ast_BasicLit); result->BasicLit.token = basic_lit; + result->BasicLit.value = exact_value_from_basic_literal(basic_lit); return result; } @@ -1509,8 +1510,11 @@ Ast *parse_value(AstFile *f) { if (f->curr_token.kind == Token_OpenBrace) { return parse_literal_value(f, nullptr); } - - Ast *value = parse_expr(f, false); + Ast *value; + bool prev_allow_range = f->allow_range; + f->allow_range = true; + value = parse_expr(f, false); + f->allow_range = prev_allow_range; return value; } @@ -1735,7 +1739,8 @@ Ast *parse_operand(AstFile *f, bool lhs) { operand = ast_bad_expr(f, token, f->curr_token); } operand->stmt_state_flags |= StmtStateFlag_no_deferred; - } */ else if (name.string == "file") { return ast_basic_directive(f, token, name.string); + } */ else if (name.string == "file") { + return ast_basic_directive(f, token, name.string); } else if (name.string == "line") { return ast_basic_directive(f, token, name.string); } else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string); } else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string); diff --git a/src/parser.hpp b/src/parser.hpp index 9c3f733e5..83df7a9d6 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -222,6 +222,7 @@ enum StmtAllowFlag { AST_KIND(Undef, "undef", Token) \ AST_KIND(BasicLit, "basic literal", struct { \ Token token; \ + ExactValue value; \ }) \ AST_KIND(BasicDirective, "basic directive", struct { \ Token token; \ -- cgit v1.2.3 From 14e8b299b73c87d5c48e73add91d7a427d554d75 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 26 Oct 2019 14:43:06 +0100 Subject: Fix slice and dynamic array lengths determined from ranged compound literals --- src/check_expr.cpp | 7 ++----- src/ir.cpp | 4 ++-- src/parser.hpp | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7491094c8..3c4d737a4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7209,9 +7209,6 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (op.kind == Token_RangeHalf) { hi -= 1; } - if (op.kind == Token_Ellipsis) { - max_index += 1; - } bool new_range = range_cache_add_range(&rc, lo, hi); if (!new_range) { @@ -7229,7 +7226,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type continue; } - if (max < max_index) { + if (max < hi) { max = max_index; } @@ -7272,7 +7269,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type } } - cl->max_index = max; + cl->max_count = max; } diff --git a/src/ir.cpp b/src/ir.cpp index 5eeba91a2..ae60be7e3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1552,7 +1552,7 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) { if (count == 0) { return ir_value_nil(type); } - count = gb_max(cl->max_index+1, count); + count = gb_max(cl->max_count, count); Type *elem = base_type(type)->Slice.elem; Type *t = alloc_type_array(elem, count); irValue *backing_array = ir_add_module_constant(m, t, value); @@ -8047,7 +8047,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) { irValue *size = ir_const_int(type_size_of(et)); irValue *align = ir_const_int(type_align_of(et)); - i64 item_count = gb_max(cl->max_index+1, cl->elems.count); + i64 item_count = gb_max(cl->max_count, cl->elems.count); { auto args = array_make(a, 5); diff --git a/src/parser.hpp b/src/parser.hpp index 83df7a9d6..f07f3ce0d 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -250,7 +250,7 @@ enum StmtAllowFlag { Ast *type; \ Array elems; \ Token open, close; \ - i64 max_index; \ + i64 max_count; \ }) \ AST_KIND(_ExprBegin, "", bool) \ AST_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \ -- cgit v1.2.3 From ee8d3e03f89b1f8065fc9563d84830482bc3f387 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Oct 2019 18:25:39 +0000 Subject: Delay determination of procedure abi types until as late as possible to prevent type undetermination in self-referential data types #454 --- src/check_expr.cpp | 4 ++-- src/check_type.cpp | 20 ++++++++++++-------- src/ir.cpp | 3 +++ src/ir_print.cpp | 5 +++++ src/types.cpp | 9 +++++++-- 5 files changed, 29 insertions(+), 12 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b5d24e008..51497af7e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -89,7 +89,7 @@ Type * check_init_variable (CheckerContext *c, Entity *e, Operand * Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type, ProcCallingConvention cc); Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type, ProcCallingConvention cc); bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type); -void set_procedure_abi_types(CheckerContext *c, Type *type); +void set_procedure_abi_types(gbAllocator a, Type *type); void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type); Entity *entity_from_expr(Ast *expr) { @@ -963,7 +963,7 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source, } if (modify_type) { - set_procedure_abi_types(c, source); + set_procedure_abi_types(c->allocator, source); } return true; diff --git a/src/check_type.cpp b/src/check_type.cpp index de33cc1a5..45c59f2bc 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1273,7 +1273,7 @@ Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Oper if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) { if (show_error) { - set_procedure_abi_types(ctx, poly_type); + set_procedure_abi_types(ctx->allocator, poly_type); } return poly_type; } @@ -2362,18 +2362,22 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type return false; } -void set_procedure_abi_types(CheckerContext *c, Type *type) { +void set_procedure_abi_types(gbAllocator allocator, Type *type) { type = base_type(type); if (type->kind != Type_Proc) { return; } - type->Proc.abi_compat_params = array_make(c->allocator, cast(isize)type->Proc.param_count); + if (type->Proc.abi_types_set) { + return; + } + + type->Proc.abi_compat_params = array_make(allocator, cast(isize)type->Proc.param_count); for (i32 i = 0; i < type->Proc.param_count; i++) { Entity *e = type->Proc.params->Tuple.variables[i]; if (e->kind == Entity_Variable) { Type *original_type = e->type; - Type *new_type = type_to_abi_compat_param_type(c->allocator, original_type, type->Proc.calling_convention); + Type *new_type = type_to_abi_compat_param_type(allocator, original_type, type->Proc.calling_convention); type->Proc.abi_compat_params[i] = new_type; switch (type->Proc.calling_convention) { case ProcCC_Odin: @@ -2387,8 +2391,10 @@ void set_procedure_abi_types(CheckerContext *c, Type *type) { } // NOTE(bill): The types are the same - type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results, type->Proc.calling_convention); - type->Proc.return_by_pointer = abi_compat_return_by_pointer(c->allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type); + type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(allocator, type->Proc.results, type->Proc.calling_convention); + type->Proc.return_by_pointer = abi_compat_return_by_pointer(allocator, type->Proc.calling_convention, type->Proc.abi_compat_result_type); + + type->Proc.abi_types_set = true; } // NOTE(bill): 'operands' is for generating non generic procedure type @@ -2486,8 +2492,6 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, } type->Proc.is_polymorphic = is_polymorphic; - set_procedure_abi_types(c, type); - return success; } diff --git a/src/ir.cpp b/src/ir.cpp index ae60be7e3..d4aecebf0 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3038,6 +3038,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &ar context_ptr = ir_find_or_generate_context_ptr(p); } + set_procedure_abi_types(heap_allocator(), pt); bool is_c_vararg = pt->Proc.c_vararg; isize param_count = pt->Proc.param_count; @@ -10019,6 +10020,8 @@ void ir_insert_code_before_proc(irProcedure* proc, irProcedure *parent) { void ir_build_proc(irValue *value, irProcedure *parent) { irProcedure *proc = &value->Proc; + set_procedure_abi_types(heap_allocator(), proc->type); + proc->parent = parent; if (proc->body != nullptr) { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 1d0c8af35..d47dfc898 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -323,12 +323,15 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) { void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) { + set_procedure_abi_types(heap_allocator(), t); + i64 word_bits = 8*build_context.word_size; t = base_type(t); GB_ASSERT(is_type_proc(t)); isize param_count = t->Proc.param_count; isize result_count = t->Proc.result_count; + ir_print_proc_results(f, m, t); ir_write_string(f, str_lit(" (")); if (t->Proc.return_by_pointer) { @@ -2125,6 +2128,8 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { + set_procedure_abi_types(heap_allocator(), proc->type); + if (proc->body == nullptr) { ir_write_str_lit(f, "declare "); // if (proc->tags & ProcTag_dll_import) { diff --git a/src/types.cpp b/src/types.cpp index 8ad352f62..bef69ee30 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -205,6 +205,7 @@ struct TypeUnion { Type * abi_compat_result_type; \ i32 variadic_index; \ bool variadic; \ + bool abi_types_set; \ bool require_results; \ bool c_vararg; \ bool is_polymorphic; \ @@ -2360,7 +2361,9 @@ i64 type_size_of(Type *t) { return 0; } // NOTE(bill): Always calculate the size when it is a Type_Basic - if (t->kind != Type_Basic && t->cached_size >= 0) { + if (t->kind == Type_Named && t->cached_size >= 0) { + + } else if (t->kind != Type_Basic && t->cached_size >= 0) { return t->cached_size; } TypePath path = {0}; @@ -2375,7 +2378,9 @@ i64 type_align_of(Type *t) { return 1; } // NOTE(bill): Always calculate the size when it is a Type_Basic - if (t->kind != Type_Basic && t->cached_align > 0) { + if (t->kind == Type_Named && t->cached_align >= 0) { + + } if (t->kind != Type_Basic && t->cached_align > 0) { return t->cached_align; } -- cgit v1.2.3 From 01dfb1dac8b71b2b84bb585395063c52779f5674 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 31 Oct 2019 20:17:50 +0000 Subject: Fix double calling of lhs of logical binary expressions --- src/check_expr.cpp | 8 ++++++-- src/check_type.cpp | 29 +++++++++++++++++++---------- src/ir.cpp | 15 ++++++++------- 3 files changed, 33 insertions(+), 19 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 51497af7e..8612167c9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -62,7 +62,7 @@ Type * make_optional_ok_type (Type *value); void check_type_decl (CheckerContext *c, Entity *e, Ast *type_expr, Type *def); Entity * check_selector (CheckerContext *c, Operand *operand, Ast *node, Type *type_hint); Entity * check_ident (CheckerContext *c, Operand *o, Ast *n, Type *named_type, Type *type_hint, bool allow_import_name); -Entity * find_polymorphic_record_entity (CheckerContext *c, Type *original_type, isize param_count, Array ordered_operands); +Entity * find_polymorphic_record_entity (CheckerContext *c, Type *original_type, isize param_count, Array const &ordered_operands, bool *failure); void check_not_tuple (CheckerContext *c, Operand *operand); void convert_to_typed (CheckerContext *c, Operand *operand, Type *target_type); gbString expr_to_string (Ast *expression); @@ -6336,12 +6336,16 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper { gbAllocator a = c->allocator; - Entity *found_entity = find_polymorphic_record_entity(c, original_type, param_count, ordered_operands); + bool failure = false; + Entity *found_entity = find_polymorphic_record_entity(c, original_type, param_count, ordered_operands, &failure); if (found_entity) { operand->mode = Addressing_Type; operand->type = found_entity->type; return err; } + if (failure) { + return CallArgumentError_NoneConstantParameter; + } String generated_name = make_string_c(expr_to_string(call)); diff --git a/src/check_type.cpp b/src/check_type.cpp index 45c59f2bc..ef68203ab 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -248,38 +248,47 @@ bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) { } -Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array ordered_operands) { +Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array const &ordered_operands, bool *failure) { auto *found_gen_types = map_get(&ctx->checker->info.gen_types, hash_pointer(original_type)); if (found_gen_types != nullptr) { for_array(i, *found_gen_types) { Entity *e = (*found_gen_types)[i]; Type *t = base_type(e->type); TypeTuple *tuple = get_record_polymorphic_params(t); - bool ok = true; GB_ASSERT(param_count == tuple->variables.count); + + bool skip = false; + for (isize j = 0; j < param_count; j++) { Entity *p = tuple->variables[j]; Operand o = ordered_operands[j]; if (p->kind == Entity_TypeName) { if (is_type_polymorphic(o.type)) { // NOTE(bill): Do not add polymorphic version to the gen_types - ok = false; - } - if (!are_types_identical(o.type, p->type)) { - ok = false; + skip = true; + break; + } else if (!are_types_identical(o.type, p->type)) { + skip = true; + break; } } else if (p->kind == Entity_Constant) { - if (!are_types_identical(o.type, p->type)) { - ok = false; + if (o.mode != Addressing_Constant) { + if (failure) *failure = true; + skip = true; + break; } if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) { - ok = false; + skip = true; + break; + } else if (!are_types_identical(o.type, p->type)) { + skip = true; + break; } } else { GB_PANIC("Unknown entity kind"); } } - if (ok) { + if (!skip) { return e; } } diff --git a/src/ir.cpp b/src/ir.cpp index d4aecebf0..e7317a960 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5647,7 +5647,8 @@ irValue *ir_emit_logical_binary_expr(irProcedure *proc, TokenKind op, Ast *left, } ir_start_block(proc, rhs); - array_add(&edges, ir_build_expr(proc, right)); + irValue *edge = ir_build_expr(proc, right); + array_add(&edges, edge); ir_emit_jump(proc, done); ir_start_block(proc, done); @@ -5656,8 +5657,6 @@ irValue *ir_emit_logical_binary_expr(irProcedure *proc, TokenKind op, Ast *left, irValue *ir_emit_logical_binary_expr(irProcedure *proc, Ast *expr) { ast_node(be, BinaryExpr, expr); - irBlock *rhs = ir_new_block(proc, nullptr, "logical.cmp.rhs"); - irBlock *done = ir_new_block(proc, nullptr, "logical.cmp.done"); Type *type = type_of_expr(expr); type = default_type(type); @@ -6879,9 +6878,6 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { case_end; case_ast_node(be, BinaryExpr, expr); - irValue *left = ir_build_expr(proc, be->left); - Type *type = default_type(tv.type); - switch (be->op.kind) { case Token_Add: case Token_Sub: @@ -6895,6 +6891,8 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { case Token_AndNot: case Token_Shl: case Token_Shr: { + irValue *left = ir_build_expr(proc, be->left); + Type *type = default_type(tv.type); irValue *right = ir_build_expr(proc, be->right); return ir_emit_arith(proc, be->op.kind, left, right, type); } @@ -6906,10 +6904,11 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { case Token_LtEq: case Token_Gt: case Token_GtEq: { + irValue *left = ir_build_expr(proc, be->left); + Type *type = default_type(tv.type); irValue *right = ir_build_expr(proc, be->right); irValue *cmp = ir_emit_comp(proc, be->op.kind, left, right); return ir_emit_conv(proc, cmp, type); - break; } case Token_CmpAnd: @@ -6919,6 +6918,8 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) { case Token_in: case Token_notin: { + irValue *left = ir_build_expr(proc, be->left); + Type *type = default_type(tv.type); irValue *right = ir_build_expr(proc, be->right); Type *rt = base_type(ir_type(right)); switch (rt->kind) { -- cgit v1.2.3