mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-26 15:01:31 +00:00
Add _append_elem_ptr to optimize for append when the element is internally pointer-like
This commit is contained in:
@@ -185,6 +185,8 @@ type_is_simd_vector :: proc($T: typeid) -> bool ---
|
||||
type_is_matrix :: proc($T: typeid) -> bool ---
|
||||
type_is_fixed_capacity_dynamic_array :: proc($T: typeid) -> bool ---
|
||||
|
||||
type_is_internally_pointer_like :: proc($T: typeid) -> bool ---
|
||||
|
||||
type_has_nil :: proc($T: typeid) -> bool ---
|
||||
|
||||
type_is_matrix_row_major :: proc($T: typeid) -> bool where type_is_matrix(T) ---
|
||||
|
||||
@@ -739,6 +739,29 @@ _append_elem :: #force_no_inline proc(array: ^Raw_Dynamic_Array, size_of_elem, a
|
||||
return
|
||||
}
|
||||
|
||||
_append_elem_ptr :: #force_no_inline proc(array: ^Raw_Dynamic_Array, arg: rawptr, should_zero: bool, loc := #caller_location) -> (num_appended: int, err: Allocator_Error) #optional_allocator_error {
|
||||
if array == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if array.cap < array.len+1 {
|
||||
// Same behavior as _append_elems but there's only one arg, so we always just add DEFAULT_DYNAMIC_ARRAY_CAPACITY.
|
||||
cap := max(2 * array.cap, DEFAULT_DYNAMIC_ARRAY_CAPACITY)
|
||||
|
||||
// do not 'or_return' here as it could be a partial success
|
||||
err = _reserve_dynamic_array_unsafe(array, size_of(rawptr), align_of(rawptr), cap, should_zero, loc)
|
||||
}
|
||||
if array.cap-array.len > 0 {
|
||||
data := ([^]rawptr)(array.data)
|
||||
assert(data != nil, loc=loc)
|
||||
data[array.len] = arg
|
||||
array.len += 1
|
||||
num_appended = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// `append_elem` appends an element to the end of a dynamic array.
|
||||
@builtin
|
||||
append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc := #caller_location) -> (num_appended: int, err: Allocator_Error) #optional_allocator_error {
|
||||
@@ -748,9 +771,11 @@ append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc := #caller
|
||||
}
|
||||
(^Raw_Dynamic_Array)(array).len += 1
|
||||
return 1, nil
|
||||
} else when intrinsics.type_is_internally_pointer_like(E) {
|
||||
return _append_elem_ptr((^Raw_Dynamic_Array)(array), rawptr(arg), should_zero=true, loc=loc)
|
||||
} else when ODIN_OPTIMIZATION_MODE <= .Size {
|
||||
arg := arg
|
||||
return _append_elem((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), &arg, true, loc=loc)
|
||||
return _append_elem((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), &arg, should_zero=true, loc=loc)
|
||||
} else {
|
||||
if array == nil {
|
||||
return
|
||||
@@ -762,7 +787,7 @@ append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc := #caller
|
||||
cap := max(2 * arr.cap, DEFAULT_DYNAMIC_ARRAY_CAPACITY)
|
||||
|
||||
// do not 'or_return' here as it could be a partial success
|
||||
err = _reserve_dynamic_array_unsafe(arr, size_of(E), align_of(E), cap, true, loc)
|
||||
err = _reserve_dynamic_array_unsafe(arr, size_of(E), align_of(E), cap, should_zero=true, loc)
|
||||
}
|
||||
if arr.cap-arr.len > 0 {
|
||||
// NOTE(bill, 2026-06-19): When this is in the hot path with -o:speed or -o:aggressive enabled,
|
||||
@@ -785,9 +810,34 @@ non_zero_append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc :
|
||||
when size_of(E) == 0 {
|
||||
(^Raw_Dynamic_Array)(array).len += 1
|
||||
return 1, nil
|
||||
} else {
|
||||
} else when intrinsics.type_is_internally_pointer_like(E) {
|
||||
return _append_elem_ptr((^Raw_Dynamic_Array)(array), rawptr(arg), should_zero=false, loc=loc)
|
||||
} else when ODIN_OPTIMIZATION_MODE <= .Size {
|
||||
arg := arg
|
||||
return _append_elem((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), &arg, false, loc=loc)
|
||||
return _append_elem((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), &arg, should_zero=false, loc=loc)
|
||||
} else {
|
||||
if array == nil {
|
||||
return
|
||||
}
|
||||
arg := arg
|
||||
arr := (^Raw_Dynamic_Array)(array)
|
||||
if arr.cap < arr.len+1 {
|
||||
// Same behavior as _append_elems but there's only one arg, so we always just add DEFAULT_DYNAMIC_ARRAY_CAPACITY.
|
||||
cap := max(2 * arr.cap, DEFAULT_DYNAMIC_ARRAY_CAPACITY)
|
||||
|
||||
// do not 'or_return' here as it could be a partial success
|
||||
err = _reserve_dynamic_array_unsafe(arr, size_of(E), align_of(E), cap, should_zero=false, loc)
|
||||
}
|
||||
if arr.cap-arr.len > 0 {
|
||||
// NOTE(bill, 2026-06-19): When this is in the hot path with -o:speed or -o:aggressive enabled,
|
||||
// this code path cannot rely on type erasure and `mem_copy_non_overlapping`.
|
||||
// So directly inlining the call and storing the argument like this helps the optimize a lot
|
||||
assert(arr.data != nil, loc=loc)
|
||||
([^]E)(arr.data)[arr.len] = arg
|
||||
arr.len += 1
|
||||
num_appended = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,8 @@ gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_bool
|
||||
is_type_raw_union,
|
||||
is_type_fixed_capacity_dynamic_array,
|
||||
|
||||
is_type_internally_pointer_like,
|
||||
|
||||
is_type_polymorphic_record_specialized,
|
||||
is_type_polymorphic_record_unspecialized,
|
||||
|
||||
@@ -7060,6 +7062,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
case BuiltinProc_type_is_simd_vector:
|
||||
case BuiltinProc_type_is_matrix:
|
||||
case BuiltinProc_type_is_raw_union:
|
||||
case BuiltinProc_type_is_fixed_capacity_dynamic_array:
|
||||
case BuiltinProc_type_is_internally_pointer_like:
|
||||
case BuiltinProc_type_is_specialized_polymorphic_record:
|
||||
case BuiltinProc_type_is_unspecialized_polymorphic_record:
|
||||
case BuiltinProc_type_has_nil:
|
||||
|
||||
@@ -314,6 +314,7 @@ BuiltinProc__type_simple_boolean_begin,
|
||||
BuiltinProc_type_is_raw_union,
|
||||
BuiltinProc_type_is_fixed_capacity_dynamic_array,
|
||||
|
||||
BuiltinProc_type_is_internally_pointer_like,
|
||||
|
||||
BuiltinProc_type_is_specialized_polymorphic_record,
|
||||
BuiltinProc_type_is_unspecialized_polymorphic_record,
|
||||
@@ -719,6 +720,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT("type_is_raw_union"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_fixed_capacity_dynamic_array"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("type_is_internally_pointer_like"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("type_is_specialized_polymorphic_record"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_unspecialized_polymorphic_record"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user