From e0ecdd4b24896d907b337d60ae1f929357dff956 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 2 Aug 2022 11:13:53 +0100 Subject: Simplify logic of `append` of zero sized elements --- core/runtime/core_builtin.odin | 56 +++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 25 deletions(-) (limited to 'core/runtime') diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index 4f698a270..e9fc2a91e 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -339,19 +339,22 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) { if array == nil { return } - - if cap(array) < len(array)+1 { - cap := 2 * cap(array) + max(8, 1) - _ = reserve(array, cap, loc) - } - if cap(array)-len(array) > 0 { - a := (^Raw_Dynamic_Array)(array) - when size_of(E) != 0 { - data := ([^]E)(a.data) - assert(condition=data != nil, loc=loc) - data[a.len] = arg - } + when size_of(E) == 0 { a.len += 1 + } else { + if cap(array) < len(array)+1 { + cap := 2 * cap(array) + max(8, 1) + _ = reserve(array, cap, loc) + } + if cap(array)-len(array) > 0 { + a := (^Raw_Dynamic_Array)(array) + when size_of(E) != 0 { + data := ([^]E)(a.data) + assert(condition=data != nil, loc=loc) + data[a.len] = arg + } + a.len += 1 + } } } @@ -366,20 +369,23 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) return } - - if cap(array) < len(array)+arg_len { - cap := 2 * cap(array) + max(8, arg_len) - _ = reserve(array, cap, loc) - } - arg_len = min(cap(array)-len(array), arg_len) - if arg_len > 0 { - a := (^Raw_Dynamic_Array)(array) - when size_of(E) != 0 { - data := ([^]E)(a.data) - assert(condition=data != nil, loc=loc) - intrinsics.mem_copy(&data[a.len], raw_data(args), size_of(E) * arg_len) - } + when size_of(E) == 0 { a.len += arg_len + } else { + if cap(array) < len(array)+arg_len { + cap := 2 * cap(array) + max(8, arg_len) + _ = reserve(array, cap, loc) + } + arg_len = min(cap(array)-len(array), arg_len) + if arg_len > 0 { + a := (^Raw_Dynamic_Array)(array) + when size_of(E) != 0 { + data := ([^]E)(a.data) + assert(condition=data != nil, loc=loc) + intrinsics.mem_copy(&data[a.len], raw_data(args), size_of(E) * arg_len) + } + a.len += arg_len + } } } -- cgit v1.2.3 From 28ec50d567c748e9e0deb14f6d1ff6993e02a329 Mon Sep 17 00:00:00 2001 From: Atanas Dimitrov Date: Wed, 3 Aug 2022 16:09:36 +0300 Subject: Fix string orderings to account for prefix-equal strings --- core/runtime/internal.odin | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'core/runtime') diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 30798f623..16af84ebc 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -341,7 +341,12 @@ string_eq :: proc "contextless" (lhs, rhs: string) -> bool { string_cmp :: proc "contextless" (a, b: string) -> int { x := transmute(Raw_String)a y := transmute(Raw_String)b - return memory_compare(x.data, y.data, min(x.len, y.len)) + + ret := memory_compare(x.data, y.data, min(x.len, y.len)) + if ret == 0 && x.len != y.len { + return -1 if x.len < y.len else +1 + } + return ret } string_ne :: #force_inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b) } -- cgit v1.2.3 From 576914aee1565618d8448a2bbc3cbef0c4acc4d1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 5 Aug 2022 11:57:33 +0100 Subject: Make `unreachable()` a built-in compiler-level procedure --- core/runtime/core_builtin.odin | 14 -------------- src/check_builtin.cpp | 1 + src/check_stmt.cpp | 13 ++++++++----- src/checker_builtin_procs.hpp | 6 +++++- src/llvm_backend_proc.cpp | 5 +++++ 5 files changed, 19 insertions(+), 20 deletions(-) (limited to 'core/runtime') diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index e9fc2a91e..3b8a0fab3 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -785,17 +785,3 @@ unimplemented :: proc(message := "", loc := #caller_location) -> ! { } p("not yet implemented", message, loc) } - -@builtin -@(disabled=ODIN_DISABLE_ASSERT) -unreachable :: proc(message := "", loc := #caller_location) -> ! { - p := context.assertion_failure_proc - if p == nil { - p = default_assertion_failure_proc - } - if message != "" { - p("internal error", message, loc) - } else { - p("internal error", "entered unreachable code", loc) - } -} diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 8108604ba..8f8f7f9e2 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3569,6 +3569,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->mode = Addressing_NoValue; break; + case BuiltinProc_unreachable: case BuiltinProc_trap: case BuiltinProc_debug_trap: operand->mode = Addressing_NoValue; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index a6f6f1a7d..451325324 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1,8 +1,5 @@ -bool is_diverging_stmt(Ast *stmt) { - if (stmt->kind != Ast_ExprStmt) { - return false; - } - Ast *expr = unparen_expr(stmt->ExprStmt.expr); +bool is_diverging_expr(Ast *expr) { + expr = unparen_expr(expr); if (expr->kind != Ast_CallExpr) { return false; } @@ -26,6 +23,12 @@ bool is_diverging_stmt(Ast *stmt) { t = base_type(t); return t != nullptr && t->kind == Type_Proc && t->Proc.diverging; } +bool is_diverging_stmt(Ast *stmt) { + if (stmt->kind != Ast_ExprStmt) { + return false; + } + return is_diverging_expr(stmt->ExprStmt.expr); +} bool contains_deferred_call(Ast *node) { if (node->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 3ea6fcdd5..8dd021255 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -40,6 +40,8 @@ enum BuiltinProcId { BuiltinProc_hadamard_product, BuiltinProc_matrix_flatten, + BuiltinProc_unreachable, + BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures // "Intrinsics" @@ -330,6 +332,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("hadamard_product"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("matrix_flatten"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("unreachable"), 0, false, Expr_Expr, BuiltinProcPkg_builtin, /*diverging*/true}, + {STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE @@ -341,7 +345,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("alloca"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("cpu_relax"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("trap"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics, /*diverging*/true}, + {STR_LIT("trap"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics, /*diverging*/true}, {STR_LIT("debug_trap"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics, /*diverging*/false}, {STR_LIT("read_cycle_counter"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 0b0c0794b..a026356a2 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1851,6 +1851,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, return lb_emit_matrix_flatten(p, m, tv.type); } + case BuiltinProc_unreachable: + LLVMBuildUnreachable(p->builder); + return {}; + + // "Intrinsics" case BuiltinProc_alloca: -- cgit v1.2.3 From 4aca9372a6292729c042242728800e0b619ecd96 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 8 Aug 2022 12:11:10 +0100 Subject: Improve `resize` call --- core/mem/alloc.odin | 63 +++++--------------------------- core/runtime/dynamic_array_internal.odin | 10 +++-- core/runtime/dynamic_map_internal.odin | 13 ++++--- core/runtime/internal.odin | 41 ++++++++++++++------- 4 files changed, 51 insertions(+), 76 deletions(-) (limited to 'core/runtime') diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin index 7416ebdb7..818a21026 100644 --- a/core/mem/alloc.odin +++ b/core/mem/alloc.odin @@ -67,7 +67,7 @@ alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := contex if allocator.procedure == nil { return nil } - data, err := allocator.procedure(allocator.data, Allocator_Mode.Alloc, size, alignment, nil, 0, loc) + data, err := allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc) _ = err return raw_data(data) } @@ -79,7 +79,7 @@ alloc_bytes :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := if allocator.procedure == nil { return nil, nil } - return allocator.procedure(allocator.data, Allocator_Mode.Alloc, size, alignment, nil, 0, loc) + return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc) } free :: proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { @@ -89,7 +89,7 @@ free :: proc(ptr: rawptr, allocator := context.allocator, loc := #caller_locatio if allocator.procedure == nil { return nil } - _, err := allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, 0, loc) + _, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc) return err } @@ -100,75 +100,30 @@ free_bytes :: proc(bytes: []byte, allocator := context.allocator, loc := #caller if allocator.procedure == nil { return nil } - _, err := allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, raw_data(bytes), len(bytes), loc) + _, err := allocator.procedure(allocator.data, .Free, 0, 0, raw_data(bytes), len(bytes), loc) return err } free_all :: proc(allocator := context.allocator, loc := #caller_location) -> Allocator_Error { if allocator.procedure != nil { - _, err := allocator.procedure(allocator.data, Allocator_Mode.Free_All, 0, 0, nil, 0, loc) + _, err := allocator.procedure(allocator.data, .Free_All, 0, 0, nil, 0, loc) return err } return nil } resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { - if allocator.procedure == nil { - return nil - } - if new_size == 0 { - if ptr != nil { - allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc) - } - return nil - } else if ptr == nil { - _, err := allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc) - _ = err - return nil - } - data, err := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, loc) - if err == .Mode_Not_Implemented { - data, err = allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc) - if err != nil { - return nil - } - runtime.copy(data, byte_slice(ptr, old_size)) - _, err = allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc) - return raw_data(data) - } + data, _ := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc) return raw_data(data) } resize_bytes :: proc(old_data: []byte, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { - if allocator.procedure == nil { - return nil, nil - } - ptr := raw_data(old_data) - old_size := len(old_data) - if new_size == 0 { - if ptr != nil { - _, err := allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc) - return nil, err - } - return nil, nil - } else if ptr == nil { - return allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc) - } - data, err := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, loc) - if err == .Mode_Not_Implemented { - data, err = allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc) - if err != nil { - return data, err - } - runtime.copy(data, old_data) - _, err = allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc) - } - return data, err + return runtime.mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc) } query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) { if allocator.procedure != nil { - allocator.procedure(allocator.data, Allocator_Mode.Query_Features, 0, 0, &set, 0, loc) + allocator.procedure(allocator.data, .Query_Features, 0, 0, &set, 0, loc) return set } return nil @@ -177,7 +132,7 @@ query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: A query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_location) -> (props: Allocator_Query_Info) { props.pointer = pointer if allocator.procedure != nil { - allocator.procedure(allocator.data, Allocator_Mode.Query_Info, 0, 0, &props, 0, loc) + allocator.procedure(allocator.data, .Query_Info, 0, 0, &props, 0, loc) } return } diff --git a/core/runtime/dynamic_array_internal.odin b/core/runtime/dynamic_array_internal.odin index d39c2dd0b..b6a685fcf 100644 --- a/core/runtime/dynamic_array_internal.odin +++ b/core/runtime/dynamic_array_internal.odin @@ -29,11 +29,15 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap: new_size := cap * elem_size allocator := array.allocator - new_data, err := allocator.procedure(allocator.data, .Resize, new_size, elem_align, array.data, old_size, loc) + new_data, err := mem_resize(array.data, old_size, new_size, elem_align, allocator, loc) if err != nil { return false } - if new_data != nil || elem_size == 0 { + if elem_size == 0 { + array.data = raw_data(new_data) + array.cap = cap + return true + } else if new_data != nil { array.data = raw_data(new_data) array.cap = min(cap, len(new_data)/elem_size) return true @@ -59,7 +63,7 @@ __dynamic_array_shrink :: proc(array_: rawptr, elem_size, elem_align: int, new_c new_size := new_cap * elem_size allocator := array.allocator - new_data, err := allocator.procedure(allocator.data, .Resize, new_size, elem_align, array.data, old_size, loc) + new_data, err := mem_resize(array.data, old_size, new_size, elem_align, allocator, loc) if err != nil { return } diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index fee0f570f..02ecf9354 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -194,12 +194,15 @@ __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, l new_size := new_count*size_of(T) new_data, err := mem_resize(array.data, old_size, new_size, align_of(T), allocator, loc) - if new_data == nil || err != nil { + if err != nil { return false } - array.data = new_data - array.len = new_count - return true + if new_data != nil || elem_size == 0 { + array.data = raw_data(new_data) + array.len = new_count + return true + } + return false } __dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_location) { @@ -207,7 +210,7 @@ __dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_loc m.hashes[i] = -1 } - for i in 0 ..< m.entries.len { + for i in 0.. (new_ptr: rawptr, err: Allocator_Error) { - new_data: []byte - switch { - case allocator.procedure == nil: - return - case new_size == 0: - new_data, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc) - case ptr == nil: - new_data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc) - case: - new_data, err = allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc) - } - new_ptr = raw_data(new_data) - return +mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { + if allocator.procedure == nil { + return nil, nil + } + if new_size == 0 { + if ptr != nil { + _, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc) + return nil, err + } + return nil, nil + } else if ptr == nil { + return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc) + } else if old_size == new_size && uintptr(ptr) % uintptr(alignment) == 0 { + return ([^]byte)(ptr)[:old_size], nil + } + + data, err := allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc) + if err == .Mode_Not_Implemented { + data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc) + if err != nil { + return data, err + } + copy(data, ([^]byte)(ptr)[:old_size]) + _, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc) + } + return data, err } + memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool { switch { case n == 0: return true -- cgit v1.2.3 From c97a8418dc9e99a0f39c74512cbc9d011f84426c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 8 Aug 2022 12:23:19 +0100 Subject: Clean-up and unification for the allocation procedures --- core/mem/alloc.odin | 41 ++++--------------------------- core/runtime/dynamic_map_internal.odin | 2 +- core/runtime/internal.odin | 44 ++++++++++++++++------------------ core/strings/intern.odin | 22 ++++++++--------- 4 files changed, 38 insertions(+), 71 deletions(-) (limited to 'core/runtime') diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin index 818a21026..54004d333 100644 --- a/core/mem/alloc.odin +++ b/core/mem/alloc.odin @@ -61,55 +61,24 @@ DEFAULT_PAGE_SIZE :: 4 * 1024 alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { - if size == 0 { - return nil - } - if allocator.procedure == nil { - return nil - } - data, err := allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc) - _ = err + data, _ := runtime.mem_alloc(size, alignment, allocator, loc) return raw_data(data) } alloc_bytes :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { - if size == 0 { - return nil, nil - } - if allocator.procedure == nil { - return nil, nil - } - return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc) + return runtime.mem_alloc(size, alignment, allocator, loc) } free :: proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { - if ptr == nil { - return nil - } - if allocator.procedure == nil { - return nil - } - _, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc) - return err + return runtime.mem_free(ptr, allocator, loc) } free_bytes :: proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { - if bytes == nil { - return nil - } - if allocator.procedure == nil { - return nil - } - _, err := allocator.procedure(allocator.data, .Free, 0, 0, raw_data(bytes), len(bytes), loc) - return err + return runtime.mem_free_bytes(bytes, allocator, loc) } free_all :: proc(allocator := context.allocator, loc := #caller_location) -> Allocator_Error { - if allocator.procedure != nil { - _, err := allocator.procedure(allocator.data, .Free_All, 0, 0, nil, 0, loc) - return err - } - return nil + return runtime.mem_free_all(allocator, loc) } resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { diff --git a/core/runtime/dynamic_map_internal.odin b/core/runtime/dynamic_map_internal.odin index 02ecf9354..35b42d488 100644 --- a/core/runtime/dynamic_map_internal.odin +++ b/core/runtime/dynamic_map_internal.odin @@ -197,7 +197,7 @@ __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, l if err != nil { return false } - if new_data != nil || elem_size == 0 { + if new_data != nil || size_of(E) == 0 { array.data = raw_data(new_data) array.len = new_count return true diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index c82d7b2cc..55f600d68 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -103,7 +103,7 @@ mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr { if data == nil { return nil } - if len < 0 { + if len <= 0 { return data } intrinsics.mem_zero(data, len) @@ -111,22 +111,18 @@ mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr { } mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { - if src == nil { - return dst + if src != nil && dst != src && len > 0 { + // NOTE(bill): This _must_ be implemented like C's memmove + intrinsics.mem_copy(dst, src, len) } - - // NOTE(bill): This _must_ be implemented like C's memmove - intrinsics.mem_copy(dst, src, len) return dst } mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { - if src == nil { - return dst + if src != nil && dst != src && len > 0 { + // NOTE(bill): This _must_ be implemented like C's memcpy + intrinsics.mem_copy_non_overlapping(dst, src, len) } - - // NOTE(bill): This _must_ be implemented like C's memcpy - intrinsics.mem_copy_non_overlapping(dst, src, len) return dst } @@ -142,28 +138,30 @@ mem_alloc_bytes :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNM return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc) } -mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) { - if size == 0 { - return nil, nil - } - if allocator.procedure == nil { +mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { + if size == 0 || allocator.procedure == nil { return nil, nil } - data, err := allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc) - return raw_data(data), err + return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc) } mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { - if ptr == nil { - return .None - } - if allocator.procedure == nil { - return .None + if ptr == nil || allocator.procedure == nil { + return nil } _, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc) return err } +mem_free_bytes :: #force_inline proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { + if bytes == nil || allocator.procedure == nil { + return nil + } + _, err := allocator.procedure(allocator.data, .Free, 0, 0, raw_data(bytes), len(bytes), loc) + return err +} + + mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) { if allocator.procedure != nil { _, err = allocator.procedure(allocator.data, .Free_All, 0, 0, nil, 0, loc) diff --git a/core/strings/intern.odin b/core/strings/intern.odin index 1e9577e61..5e9193a0d 100644 --- a/core/strings/intern.odin +++ b/core/strings/intern.odin @@ -31,31 +31,31 @@ intern_destroy :: proc(m: ^Intern) { // returns the `text` string from the intern map - gets set if it didnt exist yet // the returned string lives as long as the map entry lives -intern_get :: proc(m: ^Intern, text: string) -> string { - entry := _intern_get_entry(m, text) - #no_bounds_check return string(entry.str[:entry.len]) +intern_get :: proc(m: ^Intern, text: string) -> (str: string, err: runtime.Allocator_Error) { + entry := _intern_get_entry(m, text) or_return + #no_bounds_check return string(entry.str[:entry.len]), nil } // returns the `text` cstring from the intern map - gets set if it didnt exist yet // the returned cstring lives as long as the map entry lives -intern_get_cstring :: proc(m: ^Intern, text: string) -> cstring { - entry := _intern_get_entry(m, text) - return cstring(&entry.str[0]) +intern_get_cstring :: proc(m: ^Intern, text: string) -> (str: cstring, err: runtime.Allocator_Error) { + entry := _intern_get_entry(m, text) or_return + return cstring(&entry.str[0]), nil } // looks up wether the `text` string exists in the map, returns the entry // sets & allocates the entry if it wasnt set yet -_intern_get_entry :: proc(m: ^Intern, text: string) -> ^Intern_Entry #no_bounds_check { +_intern_get_entry :: proc(m: ^Intern, text: string) -> (new_entry: ^Intern_Entry, err: runtime.Allocator_Error) #no_bounds_check { if prev, ok := m.entries[text]; ok { - return prev + return prev, nil } if m.allocator.procedure == nil { m.allocator = context.allocator } entry_size := int(offset_of(Intern_Entry, str)) + len(text) + 1 - ptr, _ := runtime.mem_alloc(entry_size, align_of(Intern_Entry), m.allocator) - new_entry := (^Intern_Entry)(ptr) + bytes := runtime.mem_alloc(entry_size, align_of(Intern_Entry), m.allocator) or_return + new_entry = (^Intern_Entry)(raw_data(bytes)) new_entry.len = len(text) copy(new_entry.str[:new_entry.len], text) @@ -63,5 +63,5 @@ _intern_get_entry :: proc(m: ^Intern, text: string) -> ^Intern_Entry #no_bounds_ key := string(new_entry.str[:new_entry.len]) m.entries[key] = new_entry - return new_entry + return new_entry, nil } -- cgit v1.2.3 From 5e3cf45df3e781b0e5e01a55490a32bed0d9c7e3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 8 Aug 2022 15:07:00 +0100 Subject: Add `#soa` pointer type to aid with refactoring to `#soa` data types a: #soa[16]Foo p := &a[6] #assert(type_of(p) == #soa^#soa[16]Foo) p^.x = 123 p.x = 123 --- core/encoding/json/marshal.odin | 3 ++ core/fmt/fmt.odin | 13 +++++++++ core/mem/raw.odin | 1 + core/odin/ast/ast.odin | 1 + core/odin/ast/clone.odin | 1 + core/odin/doc-format/doc_format.odin | 2 ++ core/odin/parser/parser.odin | 16 ++++++++++- core/reflect/reflect.odin | 5 ++++ core/reflect/types.odin | 13 +++++++++ core/runtime/core.odin | 10 +++++++ core/runtime/print.odin | 3 ++ src/check_decl.cpp | 2 +- src/check_expr.cpp | 22 ++++++++++---- src/check_type.cpp | 28 +++++++++++++++--- src/checker.cpp | 11 +++++++ src/docs_format.cpp | 1 + src/docs_writer.cpp | 4 +++ src/llvm_backend_expr.cpp | 33 ++++++++++++++++++--- src/llvm_backend_general.cpp | 15 ++++++++++ src/llvm_backend_type.cpp | 15 ++++++++++ src/llvm_backend_utility.cpp | 35 +++++++++++++++++++++- src/parser.cpp | 6 ++-- src/parser.hpp | 3 +- src/types.cpp | 56 ++++++++++++++++++++++++++++++++---- 24 files changed, 275 insertions(+), 24 deletions(-) (limited to 'core/runtime') diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 54fab44c6..c0e70c85c 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -147,6 +147,9 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) { case runtime.Type_Info_Multi_Pointer: return .Unsupported_Type + case runtime.Type_Info_Soa_Pointer: + return .Unsupported_Type + case runtime.Type_Info_Procedure: return .Unsupported_Type diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 4db140afa..0973e7366 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1031,6 +1031,15 @@ fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) { } } +fmt_soa_pointer :: proc(fi: ^Info, p: runtime.Raw_Soa_Pointer, verb: rune) { + io.write_string(fi.writer, "#soa{0x", &fi.n) + _fmt_int(fi, u64(uintptr(p.data)), 16, false, 8*size_of(rawptr), __DIGITS_UPPER) + io.write_string(fi.writer, ", ", &fi.n) + _fmt_int(fi, u64(p.index), 10, false, 8*size_of(rawptr), __DIGITS_UPPER) + io.write_string(fi.writer, "}", &fi.n) +} + + enum_value_to_string :: proc(val: any) -> (string, bool) { v := val v.id = runtime.typeid_base(v.id) @@ -1867,6 +1876,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { fmt_pointer(fi, ptr, verb) } + case runtime.Type_Info_Soa_Pointer: + ptr := (^runtime.Raw_Soa_Pointer)(v.data)^ + fmt_soa_pointer(fi, ptr, verb) + case runtime.Type_Info_Multi_Pointer: ptr := (^rawptr)(v.data)^ if ptr == nil { diff --git a/core/mem/raw.odin b/core/mem/raw.odin index 2bce2d7aa..8322ace30 100644 --- a/core/mem/raw.odin +++ b/core/mem/raw.odin @@ -8,6 +8,7 @@ Raw_Cstring :: runtime.Raw_Cstring Raw_Slice :: runtime.Raw_Slice Raw_Dynamic_Array :: runtime.Raw_Dynamic_Array Raw_Map :: runtime.Raw_Map +Raw_Soa_Pointer :: runtime.Raw_Soa_Pointer Raw_Complex64 :: struct {real, imag: f32} Raw_Complex128 :: struct {real, imag: f64} diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index d1b91a829..c8f73a31b 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -700,6 +700,7 @@ Proc_Type :: struct { Pointer_Type :: struct { using node: Expr, + tag: ^Expr, pointer: tokenizer.Pos, elem: ^Expr, } diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index 400c064f5..5ec6bc335 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -286,6 +286,7 @@ clone_node :: proc(node: ^Node) -> ^Node { r.results = auto_cast clone(r.results) case ^Pointer_Type: r.elem = clone(r.elem) + r.tag = clone(r.tag) case ^Multi_Pointer_Type: r.elem = clone(r.elem) case ^Array_Type: diff --git a/core/odin/doc-format/doc_format.odin b/core/odin/doc-format/doc_format.odin index 62682004d..895fcf70d 100644 --- a/core/odin/doc-format/doc_format.odin +++ b/core/odin/doc-format/doc_format.odin @@ -186,6 +186,7 @@ Type_Kind :: enum u32le { Relative_Slice = 21, Multi_Pointer = 22, Matrix = 23, + Soa_Pointer = 24, } Type_Elems_Cap :: 4 @@ -245,6 +246,7 @@ Type :: struct { // .Relative_Slice - 2 types: 0=slice type, 1=base integer // .Multi_Pointer - 1 type: 0=element // .Matrix - 1 type: 0=element + // .Soa_Pointer - 1 type: 0=element types: Array(Type_Index), // Used by: diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 69f42b8ec..470aaccbd 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2235,7 +2235,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { return parse_call_expr(p, bd) - case "soa", "simd": + case "soa": bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name)) bd.tok = tok bd.name = name.text @@ -2244,6 +2244,20 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { #partial switch t in type.derived_expr { case ^ast.Array_Type: t.tag = bd case ^ast.Dynamic_Array_Type: t.tag = bd + case ^ast.Pointer_Type: t.tag = bd + case: + error(p, original_type.pos, "expected an array or pointer type after #%s", name.text) + } + return original_type + + case "simd": + bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name)) + bd.tok = tok + bd.name = name.text + original_type := parse_type(p) + type := ast.unparen_expr(original_type) + #partial switch t in type.derived_expr { + case ^ast.Array_Type: t.tag = bd case: error(p, original_type.pos, "expected an array type after #%s", name.text) } diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 27a83e680..794f9668a 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -34,6 +34,7 @@ Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer Type_Info_Relative_Slice :: runtime.Type_Info_Relative_Slice Type_Info_Matrix :: runtime.Type_Info_Matrix +Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value @@ -68,6 +69,7 @@ Type_Kind :: enum { Relative_Pointer, Relative_Slice, Matrix, + Soa_Pointer, } @@ -102,6 +104,7 @@ type_kind :: proc(T: typeid) -> Type_Kind { case Type_Info_Relative_Pointer: return .Relative_Pointer case Type_Info_Relative_Slice: return .Relative_Slice case Type_Info_Matrix: return .Matrix + case Type_Info_Soa_Pointer: return .Soa_Pointer } } @@ -194,6 +197,7 @@ typeid_elem :: proc(id: typeid) -> typeid { } case Type_Info_Pointer: return v.elem.id case Type_Info_Multi_Pointer: return v.elem.id + case Type_Info_Soa_Pointer: return v.elem.id case Type_Info_Array: return v.elem.id case Type_Info_Enumerated_Array: return v.elem.id case Type_Info_Slice: return v.elem.id @@ -1419,6 +1423,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_ Type_Info_Enum, Type_Info_Simd_Vector, Type_Info_Relative_Pointer, + Type_Info_Soa_Pointer, Type_Info_Matrix: return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0 diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 7be7ff812..edd4f7a26 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -68,6 +68,11 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { y := b.variant.(Type_Info_Multi_Pointer) or_return return are_types_identical(x.elem, y.elem) + case Type_Info_Soa_Pointer: + y := b.variant.(Type_Info_Soa_Pointer) or_return + return are_types_identical(x.elem, y.elem) + + case Type_Info_Procedure: y := b.variant.(Type_Info_Procedure) or_return switch { @@ -256,6 +261,11 @@ is_multi_pointer :: proc(info: ^Type_Info) -> bool { _, ok := type_info_base(info).variant.(Type_Info_Multi_Pointer) return ok } +is_soa_pointer :: proc(info: ^Type_Info) -> bool { + if info == nil { return false } + _, ok := type_info_base(info).variant.(Type_Info_Soa_Pointer) + return ok +} is_pointer_internally :: proc(info: ^Type_Info) -> bool { if info == nil { return false } #partial switch v in info.variant { @@ -437,6 +447,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) - case Type_Info_Multi_Pointer: io.write_string(w, "[^]", &n) or_return write_type(w, info.elem, &n) or_return + case Type_Info_Soa_Pointer: + io.write_string(w, "#soa ^", &n) or_return + write_type(w, info.elem, &n) or_return case Type_Info_Procedure: io.write_string(w, "proc", &n) or_return if info.params == nil { diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 8fb3d7210..0310aff6d 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -176,6 +176,9 @@ Type_Info_Matrix :: struct { column_count: int, // Total element count = column_count * elem_stride } +Type_Info_Soa_Pointer :: struct { + elem: ^Type_Info, +} Type_Info_Flag :: enum u8 { Comparable = 0, @@ -217,6 +220,7 @@ Type_Info :: struct { Type_Info_Relative_Pointer, Type_Info_Relative_Slice, Type_Info_Matrix, + Type_Info_Soa_Pointer, }, } @@ -403,6 +407,12 @@ Raw_Cstring :: struct { data: [^]byte, } +Raw_Soa_Pointer :: struct { + data: rawptr, + index: int, +} + + /* // Defined internally by the compiler diff --git a/core/runtime/print.odin b/core/runtime/print.odin index 89c196fc2..959dad3a9 100644 --- a/core/runtime/print.odin +++ b/core/runtime/print.odin @@ -228,6 +228,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) { case Type_Info_Multi_Pointer: print_string("[^]") print_type(info.elem) + case Type_Info_Soa_Pointer: + print_string("#soa ^") + print_type(info.elem) case Type_Info_Procedure: print_string("proc") if info.params == nil { diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 86280b6cb..9d043e60a 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -320,7 +320,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) } else if (is_type_any(e->type)) { error(init_expr, "'distinct' cannot be applied to 'any'"); is_distinct = false; - } else if (is_type_simd_vector(e->type)) { + } else if (is_type_simd_vector(e->type) || is_type_soa_pointer(e->type)) { gbString str = type_to_string(e->type); error(init_expr, "'distinct' cannot be applied to '%s'", str); gb_string_free(str); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 96adde013..b2f3567ba 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2052,7 +2052,7 @@ bool check_is_not_addressable(CheckerContext *c, Operand *o) { return false; } - return o->mode != Addressing_Variable; + return o->mode != Addressing_Variable && o->mode != Addressing_SoaVariable; } void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) { @@ -2069,9 +2069,6 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) { error(op, "Cannot take the pointer address of '%s' which is a procedure parameter", str); } else { switch (o->mode) { - case Addressing_SoaVariable: - error(op, "Cannot take the pointer address of '%s' as it is an indirect index of an SOA struct", str); - break; case Addressing_Constant: error(op, "Cannot take the pointer address of '%s' which is a constant", str); break; @@ -2099,7 +2096,19 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) { return; } - o->type = alloc_type_pointer(o->type); + if (o->mode == Addressing_SoaVariable) { + ast_node(ue, UnaryExpr, node); + if (ast_node_expect(ue->expr, Ast_IndexExpr)) { + ast_node(ie, IndexExpr, ue->expr); + Type *soa_type = type_of_expr(ie->expr); + GB_ASSERT(is_type_soa_struct(soa_type)); + o->type = alloc_type_soa_pointer(soa_type); + } else { + o->type = alloc_type_pointer(o->type); + } + } else { + o->type = alloc_type_pointer(o->type); + } switch (o->mode) { case Addressing_OptionalOk: @@ -9378,6 +9387,9 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (t->kind == Type_Pointer && !is_type_empty_union(t->Pointer.elem)) { o->mode = Addressing_Variable; o->type = t->Pointer.elem; + } else if (t->kind == Type_SoaPointer) { + o->mode = Addressing_SoaVariable; + o->type = type_deref(t); } else if (t->kind == Type_RelativePointer) { if (o->mode != Addressing_Variable) { gbString str = expr_to_string(o->expr); diff --git a/src/check_type.cpp b/src/check_type.cpp index 5d37ff208..da0a9706b 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2693,9 +2693,12 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t case_ast_node(ue, UnaryExpr, e); switch (ue->op.kind) { case Token_Pointer: - *type = alloc_type_pointer(check_type(ctx, ue->expr)); - set_base_type(named_type, *type); - return true; + { + Type *elem = check_type(ctx, ue->expr); + *type = alloc_type_pointer(elem); + set_base_type(named_type, *type); + return true; + } } case_end; @@ -2721,7 +2724,24 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t elem = o.type; } - *type = alloc_type_pointer(elem); + if (pt->tag != nullptr) { + GB_ASSERT(pt->tag->kind == Ast_BasicDirective); + String name = pt->tag->BasicDirective.name.string; + if (name == "soa") { + // TODO(bill): generic #soa pointers + if (is_type_soa_struct(elem)) { + *type = alloc_type_soa_pointer(elem); + } else { + error(pt->tag, "#soa pointers require an #soa record type as the element"); + *type = alloc_type_pointer(elem); + } + } else { + error(pt->tag, "Invalid tag applied to pointer, got #%.*s", LIT(name)); + *type = alloc_type_pointer(elem); + } + } else { + *type = alloc_type_pointer(elem); + } set_base_type(named_type, *type); return true; case_end; diff --git a/src/checker.cpp b/src/checker.cpp index 874839ece..c75fc86af 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1947,6 +1947,11 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) { add_type_info_type_internal(c, bt->Matrix.elem); break; + case Type_SoaPointer: + add_type_info_type_internal(c, bt->SoaPointer.elem); + break; + + default: GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind); break; @@ -2164,6 +2169,10 @@ void add_min_dep_type_info(Checker *c, Type *t) { add_min_dep_type_info(c, bt->Matrix.elem); break; + case Type_SoaPointer: + add_min_dep_type_info(c, bt->SoaPointer.elem); + break; + default: GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind])); break; @@ -2756,6 +2765,7 @@ void init_core_type_info(Checker *c) { t_type_info_relative_pointer = find_core_type(c, str_lit("Type_Info_Relative_Pointer")); t_type_info_relative_slice = find_core_type(c, str_lit("Type_Info_Relative_Slice")); t_type_info_matrix = find_core_type(c, str_lit("Type_Info_Matrix")); + t_type_info_soa_pointer = find_core_type(c, str_lit("Type_Info_Soa_Pointer")); t_type_info_named_ptr = alloc_type_pointer(t_type_info_named); t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer); @@ -2784,6 +2794,7 @@ void init_core_type_info(Checker *c) { t_type_info_relative_pointer_ptr = alloc_type_pointer(t_type_info_relative_pointer); t_type_info_relative_slice_ptr = alloc_type_pointer(t_type_info_relative_slice); t_type_info_matrix_ptr = alloc_type_pointer(t_type_info_matrix); + t_type_info_soa_pointer_ptr = alloc_type_pointer(t_type_info_soa_pointer); } void init_mem_allocator(Checker *c) { diff --git a/src/docs_format.cpp b/src/docs_format.cpp index b1c3c87e7..b13b8b364 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -83,6 +83,7 @@ enum OdinDocTypeKind : u32 { OdinDocType_RelativeSlice = 21, OdinDocType_MultiPointer = 22, OdinDocType_Matrix = 23, + OdinDocType_SoaPointer = 24, }; enum OdinDocTypeFlag_Basic : u32 { diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 2f531a45c..1b8e1fc34 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -532,6 +532,10 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { doc_type.kind = OdinDocType_MultiPointer; doc_type.types = odin_doc_type_as_slice(w, type->MultiPointer.elem); break; + case Type_SoaPointer: + doc_type.kind = OdinDocType_SoaPointer; + doc_type.types = odin_doc_type_as_slice(w, type->SoaPointer.elem); + break; case Type_Array: doc_type.kind = OdinDocType_Array; doc_type.elem_count_len = 1; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 07c3224de..83ee2785e 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2803,7 +2803,15 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { return {}; } - +lbValue lb_make_soa_pointer(lbProcedure *p, Type *type, lbValue const &addr, lbValue const &index) { + lbAddr v = lb_add_local_generated(p, type, false); + lbValue ptr = lb_emit_struct_ep(p, v.addr, 0); + lbValue idx = lb_emit_struct_ep(p, v.addr, 1); + lb_emit_store(p, ptr, addr); + lb_emit_store(p, idx, index); + + return lb_addr_load(p, v); +} lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { ast_node(ue, UnaryExpr, expr); @@ -2842,7 +2850,17 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { lb_emit_store(p, gep1, ok); return lb_addr_load(p, res); - } if (ue_expr->kind == Ast_CompoundLit) { + } else if (is_type_soa_pointer(tv.type)) { + ast_node(ie, IndexExpr, ue_expr); + lbValue addr = lb_build_addr_ptr(p, ie->expr); + lbValue index = lb_build_expr(p, ie->index); + + if (!build_context.no_bounds_check) { + // TODO(bill): soa bounds checking + } + + return lb_make_soa_pointer(p, tv.type, addr, index); + } else if (ue_expr->kind == Ast_CompoundLit) { lbValue v = lb_build_expr(p, ue->expr); Type *type = v.type; @@ -3604,6 +3622,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { // NOTE(bill): just patch the index in place sel.index[0] = addr.swizzle.indices[sel.index[0]]; } + lbValue a = lb_addr_get_ptr(p, addr); a = lb_emit_deep_field_gep(p, a, sel); return lb_addr(a); @@ -4093,10 +4112,16 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { case_end; case_ast_node(de, DerefExpr, expr); - if (is_type_relative_pointer(type_of_expr(de->expr))) { + Type *t = type_of_expr(de->expr); + if (is_type_relative_pointer(t)) { lbAddr addr = lb_build_addr(p, de->expr); addr.relative.deref = true; - return addr;\ + return addr; + } else if (is_type_soa_pointer(t)) { + lbValue value = lb_build_expr(p, de->expr); + lbValue ptr = lb_emit_struct_ev(p, value, 0); + lbValue idx = lb_emit_struct_ev(p, value, 1); + return lb_addr_soa_variable(ptr, idx, nullptr); } lbValue addr = lb_build_expr(p, de->expr); return lb_addr(addr); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index b61439238..a83c4ebcf 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -916,7 +916,13 @@ lbValue lb_emit_load(lbProcedure *p, lbValue value) { Type *t = vt->MultiPointer.elem; LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); return lbValue{v, t}; + } else if (is_type_soa_pointer(value.type)) { + lbValue ptr = lb_emit_struct_ev(p, value, 0); + lbValue idx = lb_emit_struct_ev(p, value, 1); + lbAddr addr = lb_addr_soa_variable(ptr, idx, nullptr); + return lb_addr_load(p, addr); } + GB_ASSERT(is_type_pointer(value.type)); Type *t = type_deref(value.type); LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); @@ -2055,6 +2061,15 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { m->internal_type_level += 1; return t; } + + case Type_SoaPointer: + { + unsigned field_count = 2; + LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count); + fields[0] = LLVMPointerType(lb_type(m, type->Pointer.elem), 0); + fields[1] = LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size); + return LLVMStructTypeInContext(ctx, fields, field_count, false); + } } diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 2e7b2788a..5e7fcc399 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -57,6 +57,7 @@ lbValue lb_typeid(lbModule *m, Type *type) { case Type_SimdVector: kind = Typeid_Simd_Vector; break; case Type_RelativePointer: kind = Typeid_Relative_Pointer; break; case Type_RelativeSlice: kind = Typeid_Relative_Slice; break; + case Type_SoaPointer: kind = Typeid_SoaPointer; break; } if (is_type_cstring(type)) { @@ -445,6 +446,20 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lb_emit_store(p, tag, res); break; } + case Type_SoaPointer: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_soa_pointer_ptr); + lbValue gep = lb_get_type_info_ptr(m, t->SoaPointer.elem); + + LLVMValueRef vals[1] = { + gep.value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + break; + } case Type_Array: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_array_ptr); i64 ez = type_size_of(t->Array.elem); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index bbacce7a2..f1c74925e 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1007,6 +1007,11 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { case 0: result_type = t->RelativeSlice.base_integer; break; case 1: result_type = t->RelativeSlice.base_integer; break; } + } else if (is_type_soa_pointer(t)) { + switch (index) { + case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break; + case 1: result_type = t_int; break; + } } else { GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(s.type), index); } @@ -1137,6 +1142,13 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { result_type = t->Array.elem; break; + case Type_SoaPointer: + switch (index) { + case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break; + case 1: result_type = t_int; break; + } + break; + default: GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(s.type), index); break; @@ -1164,7 +1176,28 @@ lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) { } type = core_type(type); - if (is_type_quaternion(type)) { + if (type->kind == Type_SoaPointer) { + lbValue addr = lb_emit_struct_ep(p, e, 0); + lbValue index = lb_emit_struct_ep(p, e, 1); + addr = lb_emit_load(p, addr); + index = lb_emit_load(p, index); + + i32 first_index = sel.index[0]; + Selection sub_sel = sel; + sub_sel.index.data += 1; + sub_sel.index.count -= 1; + + lbValue arr = lb_emit_struct_ep(p, addr, first_index); + + Type *t = base_type(type_deref(addr.type)); + GB_ASSERT(is_type_soa_struct(t)); + + if (t->Struct.soa_kind == StructSoa_Fixed) { + e = lb_emit_array_ep(p, arr, index); + } else { + e = lb_emit_ptr_offset(p, lb_emit_load(p, arr), index); + } + } else if (is_type_quaternion(type)) { e = lb_emit_struct_ep(p, e, index); } else if (is_type_raw_union(type)) { type = get_struct_field_type(type, index); diff --git a/src/parser.cpp b/src/parser.cpp index ac3acef8a..9a5531289 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -356,6 +356,7 @@ Ast *clone_ast(Ast *node) { break; case Ast_PointerType: n->PointerType.type = clone_ast(n->PointerType.type); + n->PointerType.tag = clone_ast(n->PointerType.tag); break; case Ast_MultiPointerType: n->MultiPointerType.type = clone_ast(n->MultiPointerType.type); @@ -2167,10 +2168,11 @@ Ast *parse_operand(AstFile *f, bool lhs) { Ast *original_type = parse_type(f); Ast *type = unparen_expr(original_type); switch (type->kind) { - case Ast_ArrayType: type->ArrayType.tag = tag; break; + case Ast_ArrayType: type->ArrayType.tag = tag; break; case Ast_DynamicArrayType: type->DynamicArrayType.tag = tag; break; + case Ast_PointerType: type->PointerType.tag = tag; break; default: - syntax_error(type, "Expected an array type after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[type->kind])); + syntax_error(type, "Expected an array or pointer type after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[type->kind])); break; } return original_type; diff --git a/src/parser.hpp b/src/parser.hpp index 156991e24..bfdae58a5 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -650,7 +650,8 @@ AST_KIND(_TypeBegin, "", bool) \ }) \ AST_KIND(PointerType, "pointer type", struct { \ Token token; \ - Ast *type; \ + Ast *type; \ + Ast *tag; \ }) \ AST_KIND(RelativeType, "relative type", struct { \ Ast *tag; \ diff --git a/src/types.cpp b/src/types.cpp index 5f112ce09..cba27fd6f 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -278,7 +278,8 @@ struct TypeProc { Type *generic_row_count; \ Type *generic_column_count; \ i64 stride_in_bytes; \ - }) + }) \ + TYPE_KIND(SoaPointer, struct { Type *elem; }) enum TypeKind { @@ -350,6 +351,7 @@ enum Typeid_Kind : u8 { Typeid_Relative_Pointer, Typeid_Relative_Slice, Typeid_Matrix, + Typeid_SoaPointer, }; // IMPORTANT NOTE(bill): This must match the same as the in core.odin @@ -644,6 +646,7 @@ gb_global Type *t_type_info_simd_vector = nullptr; gb_global Type *t_type_info_relative_pointer = nullptr; gb_global Type *t_type_info_relative_slice = nullptr; gb_global Type *t_type_info_matrix = nullptr; +gb_global Type *t_type_info_soa_pointer = nullptr; gb_global Type *t_type_info_named_ptr = nullptr; gb_global Type *t_type_info_integer_ptr = nullptr; @@ -672,6 +675,7 @@ gb_global Type *t_type_info_simd_vector_ptr = nullptr; gb_global Type *t_type_info_relative_pointer_ptr = nullptr; gb_global Type *t_type_info_relative_slice_ptr = nullptr; gb_global Type *t_type_info_matrix_ptr = nullptr; +gb_global Type *t_type_info_soa_pointer_ptr = nullptr; gb_global Type *t_allocator = nullptr; gb_global Type *t_allocator_ptr = nullptr; @@ -735,6 +739,7 @@ Type * bit_set_to_int(Type *t); bool are_types_identical(Type *x, Type *y); bool is_type_pointer(Type *t); +bool is_type_soa_pointer(Type *t); bool is_type_proc(Type *t); bool is_type_slice(Type *t); bool is_type_integer(Type *t); @@ -917,6 +922,13 @@ Type *alloc_type_multi_pointer(Type *elem) { return t; } +Type *alloc_type_soa_pointer(Type *elem) { + Type *t = alloc_type(Type_SoaPointer); + t->SoaPointer.elem = elem; + return t; +} + + Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = nullptr) { if (generic_count != nullptr) { Type *t = alloc_type(Type_Array); @@ -1109,11 +1121,17 @@ Type *type_deref(Type *t) { if (bt == nullptr) { return nullptr; } - if (bt->kind == Type_Pointer) { + switch (bt->kind) { + case Type_Pointer: return bt->Pointer.elem; - } - if (bt->kind == Type_RelativePointer) { + case Type_RelativePointer: return type_deref(bt->RelativePointer.pointer_type); + case Type_SoaPointer: + { + Type *elem = base_type(bt->SoaPointer.elem); + GB_ASSERT(elem->kind == Type_Struct && elem->Struct.soa_kind != StructSoa_None); + return elem->Struct.soa_elem; + } } } return t; @@ -1327,6 +1345,10 @@ bool is_type_pointer(Type *t) { } return t->kind == Type_Pointer; } +bool is_type_soa_pointer(Type *t) { + t = base_type(t); + return t->kind == Type_SoaPointer; +} bool is_type_multi_pointer(Type *t) { t = base_type(t); return t->kind == Type_MultiPointer; @@ -1804,7 +1826,7 @@ bool is_type_dereferenceable(Type *t) { if (is_type_rawptr(t)) { return false; } - return is_type_pointer(t); + return is_type_pointer(t) || is_type_soa_pointer(t); } @@ -2079,6 +2101,9 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) { case Type_Pointer: return is_type_polymorphic(t->Pointer.elem, or_specialized); + case Type_SoaPointer: + return is_type_polymorphic(t->SoaPointer.elem, or_specialized); + case Type_EnumeratedArray: if (is_type_polymorphic(t->EnumeratedArray.index, or_specialized)) { return true; @@ -2196,6 +2221,7 @@ bool type_has_nil(Type *t) { case Type_Slice: case Type_Proc: case Type_Pointer: + case Type_SoaPointer: case Type_MultiPointer: case Type_DynamicArray: case Type_Map: @@ -2262,6 +2288,8 @@ bool is_type_comparable(Type *t) { return true; case Type_Pointer: return true; + case Type_SoaPointer: + return true; case Type_MultiPointer: return true; case Type_Enum: @@ -2335,6 +2363,7 @@ bool is_type_simple_compare(Type *t) { case Type_Pointer: case Type_MultiPointer: + case Type_SoaPointer: case Type_Proc: case Type_BitSet: return true; @@ -2558,6 +2587,12 @@ bool are_types_identical_internal(Type *x, Type *y, bool check_tuple_names) { } break; + case Type_SoaPointer: + if (y->kind == Type_SoaPointer) { + return are_types_identical(x->SoaPointer.elem, y->SoaPointer.elem); + } + break; + case Type_Named: if (y->kind == Type_Named) { return x->Named.type_name == y->Named.type_name; @@ -3475,6 +3510,9 @@ i64 type_align_of_internal(Type *t, TypePath *path) { return type_align_of_internal(t->RelativePointer.base_integer, path); case Type_RelativeSlice: return type_align_of_internal(t->RelativeSlice.base_integer, path); + + case Type_SoaPointer: + return build_context.word_size; } // return gb_clamp(next_pow2(type_size_of(t)), 1, build_context.max_align); @@ -3580,6 +3618,9 @@ i64 type_size_of_internal(Type *t, TypePath *path) { case Type_MultiPointer: return build_context.word_size; + case Type_SoaPointer: + return build_context.word_size*2; + case Type_Array: { i64 count, align, size, alignment; count = t->Array.count; @@ -4017,6 +4058,11 @@ gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) { str = write_type_to_string(str, type->Pointer.elem); break; + case Type_SoaPointer: + str = gb_string_appendc(str, "#soa ^"); + str = write_type_to_string(str, type->SoaPointer.elem); + break; + case Type_MultiPointer: str = gb_string_appendc(str, "[^]"); str = write_type_to_string(str, type->Pointer.elem); -- cgit v1.2.3 From 659c3c528dbcb0d4121f511f2fe89c885f5998c9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 8 Aug 2022 15:16:18 +0100 Subject: Update `delete` to pass size in bytes to free when possible --- core/log/log_allocator.odin | 21 +++++++++++++++------ core/runtime/core_builtin.odin | 15 +++++++++++---- core/runtime/internal.odin | 8 ++++++++ 3 files changed, 34 insertions(+), 10 deletions(-) (limited to 'core/runtime') diff --git a/core/log/log_allocator.odin b/core/log/log_allocator.odin index e703ee1a9..ea0ec37ba 100644 --- a/core/log/log_allocator.odin +++ b/core/log/log_allocator.odin @@ -36,12 +36,21 @@ log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, location = location, ) case .Free: - logf( - level=la.level, - fmt_str = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%d)", - args = {la.prefix, " " if la.prefix != "" else "", old_memory, old_size}, - location = location, - ) + if old_size != 0 { + logf( + level=la.level, + fmt_str = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%d)", + args = {la.prefix, " " if la.prefix != "" else "", old_memory, old_size}, + location = location, + ) + } else { + logf( + level=la.level, + fmt_str = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p)", + args = {la.prefix, " " if la.prefix != "" else "", old_memory}, + location = location, + ) + } case .Free_All: logf( level=la.level, diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index 3b8a0fab3..b779ffade 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -143,7 +143,7 @@ free_all :: proc{mem_free_all} @builtin delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { - return mem_free(raw_data(str), allocator, loc) + return mem_free_with_size(raw_data(str), len(str), allocator, loc) } @builtin delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { @@ -151,17 +151,24 @@ delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #cal } @builtin delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error { - return mem_free(raw_data(array), array.allocator, loc) + return mem_free_with_size(raw_data(array), cap(array)*size_of(E), array.allocator, loc) } @builtin delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { - return mem_free(raw_data(array), allocator, loc) + return mem_free_with_size(raw_data(array), len(array)*size_of(E), allocator, loc) } @builtin delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error { + Entry :: struct { + hash: uintptr, + next: int, + key: K, + value: V, + } + raw := transmute(Raw_Map)m err := delete_slice(raw.hashes, raw.entries.allocator, loc) - err1 := mem_free(raw.entries.data, raw.entries.allocator, loc) + err1 := mem_free_with_size(raw.entries.data, raw.entries.cap*size_of(Entry), raw.entries.allocator, loc) if err == nil { err = err1 } diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index 55f600d68..048bff7ca 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -153,6 +153,14 @@ mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc return err } +mem_free_with_size :: #force_inline proc(ptr: rawptr, byte_count: int, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { + if ptr == nil || allocator.procedure == nil { + return nil + } + _, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, byte_count, loc) + return err +} + mem_free_bytes :: #force_inline proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { if bytes == nil || allocator.procedure == nil { return nil -- cgit v1.2.3 From b3e3b6c6565d6211ffd8ccef7a3866e03a978fee Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 20 Aug 2022 11:17:47 +0100 Subject: Fix #1965 --- core/runtime/procs.odin | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'core/runtime') diff --git a/core/runtime/procs.odin b/core/runtime/procs.odin index 782efa773..510abcbb9 100644 --- a/core/runtime/procs.odin +++ b/core/runtime/procs.odin @@ -6,7 +6,7 @@ when ODIN_NO_CRT && ODIN_OS == .Windows { @(private="file") @(default_calling_convention="stdcall") foreign lib { - RtlMoveMemory :: proc(dst, src: rawptr, length: int) --- + RtlMoveMemory :: proc(dst, s: rawptr, length: int) --- RtlFillMemory :: proc(dst: rawptr, length: int, fill: i32) --- } @@ -40,24 +40,34 @@ when ODIN_NO_CRT && ODIN_OS == .Windows { @(link_name="memmove", linkage="strong", require) memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr { - if dst != src { - d, s := ([^]byte)(dst), ([^]byte)(src) + d, s := ([^]byte)(dst), ([^]byte)(src) + if d == s || len == 0 { + return dst + } + if d > s && uintptr(d)-uintptr(s) < uintptr(len) { for i := len-1; i >= 0; i -= 1 { d[i] = s[i] } + return dst } - return dst - + + if s > d && uintptr(s)-uintptr(d) < uintptr(len) { + for i := 0; i < len; i += 1 { + d[i] = s[i] + } + return dst + } + return memcpy(dst, src, len) } @(link_name="memcpy", linkage="strong", require) memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr { - if dst != src { - d, s := ([^]byte)(dst), ([^]byte)(src) - for i := len-1; i >= 0; i -= 1 { + d, s := ([^]byte)(dst), ([^]byte)(src) + if d != s { + for i := 0; i < len; i += 1 { d[i] = s[i] } } - return dst + return d } } else { -- cgit v1.2.3 From 8c1dfabb6beedbc4d93bb7030ac724446c82b93c Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 23 Aug 2022 16:00:14 +0200 Subject: Fix `append` for size_of(E) == 0 --- core/runtime/core_builtin.odin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'core/runtime') diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index b779ffade..aa5c2ca8f 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -347,7 +347,7 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) { return } when size_of(E) == 0 { - a.len += 1 + array.len += 1 } else { if cap(array) < len(array)+1 { cap := 2 * cap(array) + max(8, 1) @@ -377,7 +377,7 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) } when size_of(E) == 0 { - a.len += arg_len + array.len += arg_len } else { if cap(array) < len(array)+arg_len { cap := 2 * cap(array) + max(8, arg_len) -- cgit v1.2.3 From ffa87f55c4cda1b7f356204a89e5bb485c002446 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 26 Aug 2022 16:20:47 +0100 Subject: Add a return value to `append` that states the number of elements that were returned --- core/runtime/core_builtin.odin | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'core/runtime') diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index aa5c2ca8f..b87492c52 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -342,12 +342,13 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value: @builtin -append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) { +append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> int { if array == nil { - return + return 0 } when size_of(E) == 0 { array.len += 1 + return 1 } else { if cap(array) < len(array)+1 { cap := 2 * cap(array) + max(8, 1) @@ -361,23 +362,26 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) { data[a.len] = arg } a.len += 1 + return 1 } + return 0 } } @builtin -append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) { +append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> int { if array == nil { - return + return 0 } arg_len := len(args) if arg_len <= 0 { - return + return 0 } when size_of(E) == 0 { array.len += arg_len + return arg_len } else { if cap(array) < len(array)+arg_len { cap := 2 * cap(array) + max(8, arg_len) @@ -393,23 +397,25 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) } a.len += arg_len } + return arg_len } } // The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type @builtin -append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) { +append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> int { args := transmute([]E)arg - append_elems(array=array, args=args, loc=loc) + return append_elems(array=array, args=args, loc=loc) } // The append_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type @builtin -append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) { +append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int) { for arg in args { - append(array = array, args = transmute([]E)(arg), loc = loc) + n += append(array = array, args = transmute([]E)(arg), loc = loc) } + return } // The append built-in procedure appends elements to the end of a dynamic array @@ -417,11 +423,13 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_ @builtin -append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) { +append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> int { if array == nil { return } + prev_len := len(array) resize(array, len(array)+1) + return len(array)-prev_len } -- cgit v1.2.3 From 96be4947306cbeb7fa792d5f36c40d8a3704e4c1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 26 Aug 2022 22:21:19 +0100 Subject: Fix `append_nothing` --- core/runtime/core_builtin.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'core/runtime') diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index b87492c52..e3960088d 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -425,7 +425,7 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_ @builtin append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> int { if array == nil { - return + return 0 } prev_len := len(array) resize(array, len(array)+1) -- cgit v1.2.3