mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-15 18:19:15 +00:00
Add intrinsics.soa_copy_from_slice and use it within _append_soa_elems replacing the old handwritten unrolled approach
This commit is contained in:
@@ -3355,6 +3355,95 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
|
||||
// "Intrinsics"
|
||||
|
||||
case BuiltinProc_soa_copy_from_slice:
|
||||
{
|
||||
lbValue ptr = lb_build_expr(p, ce->args[0]);
|
||||
lbValue offset = lb_build_expr(p, ce->args[1]);
|
||||
lbValue args = lb_build_expr(p, ce->args[2]);
|
||||
|
||||
Type *ptr_type = base_type(ptr.type);
|
||||
Type *array_type = base_type(type_deref(ptr_type));
|
||||
GB_ASSERT(is_type_soa_dynamic_array(array_type));
|
||||
|
||||
Type *elem = array_type->Struct.soa_elem;
|
||||
|
||||
i32 field_count = 0;
|
||||
if (is_type_array(elem)) {
|
||||
field_count = cast(i32)get_array_type_count(elem);
|
||||
} else {
|
||||
Type *bt = base_type(elem);
|
||||
GB_ASSERT(bt->kind == Type_Struct);
|
||||
field_count = cast(i32)bt->Struct.fields.count;
|
||||
}
|
||||
if (field_count == 0) {
|
||||
return {};
|
||||
}
|
||||
GB_ASSERT(field_count >= 1);
|
||||
|
||||
Type *slice_type = base_type(args.type);
|
||||
GB_ASSERT(slice_type->kind == Type_Slice);
|
||||
GB_ASSERT(are_types_identical(slice_type->Slice.elem, elem));
|
||||
|
||||
lbValue arg_ptr = lb_slice_elem(p, args);
|
||||
lbValue arg_len = lb_slice_len(p, args);
|
||||
|
||||
lbValue soa_array_len = lb_soa_struct_len(p, ptr);
|
||||
|
||||
offset = lb_emit_conv(p, offset, t_int);
|
||||
lbValue max_soa_len = lb_emit_arith(p, Token_Sub, soa_array_len, offset, t_int);
|
||||
lbValue max_len = lb_emit_min(p, t_int, arg_len, max_soa_len);
|
||||
|
||||
if (field_count <= 16) {
|
||||
lbValue *ps = gb_alloc_array(temporary_allocator(), lbValue, field_count);
|
||||
for (i32 field_index = 0; field_index < field_count; field_index++) {
|
||||
ps[field_index] = lb_emit_load(p, lb_emit_struct_ep(p, ptr, field_index));
|
||||
}
|
||||
|
||||
for (i32 field_index = 0; field_index < field_count; field_index++) {
|
||||
auto loop_data = lb_loop_start_runtime(p, max_len);
|
||||
|
||||
lbValue j = loop_data.idx;
|
||||
lbValue index = lb_emit_arith(p, Token_Add, j, offset, t_int);
|
||||
|
||||
lbValue dst = lb_emit_ptr_offset(p, ps[field_index], index);
|
||||
// make sure it's ^T and not [^]T
|
||||
dst.type = alloc_type_multi_pointer_to_pointer(dst.type);
|
||||
|
||||
lbValue src_ptr = lb_emit_ptr_offset(p, arg_ptr, j);
|
||||
src_ptr = lb_emit_struct_ep(p, src_ptr, field_index);
|
||||
|
||||
lbValue src = lb_emit_load(p, src_ptr);
|
||||
lb_emit_store(p, dst, src);
|
||||
|
||||
lb_loop_end(p, loop_data);
|
||||
}
|
||||
} else {
|
||||
for (i32 field_index = 0; field_index < field_count; field_index++) {
|
||||
Type *type = array_type->Struct.fields[field_index]->type;
|
||||
GB_ASSERT(type->kind == Type_MultiPointer);
|
||||
type = type->MultiPointer.elem;
|
||||
|
||||
lbValue dst = lb_emit_load(p, lb_emit_struct_ep(p, ptr, field_index));
|
||||
dst = lb_emit_ptr_offset(p, dst, offset);
|
||||
dst.type = alloc_type_multi_pointer_to_pointer(dst.type);
|
||||
|
||||
auto loop_data = lb_loop_start_runtime(p, max_len);
|
||||
|
||||
lbValue src = lb_emit_ptr_offset(p, arg_ptr, loop_data.idx);
|
||||
|
||||
lbValue d = lb_emit_ptr_offset(p, dst, loop_data.idx);
|
||||
lbValue s = lb_emit_struct_ep(p, src, field_index);
|
||||
|
||||
GB_ASSERT(are_types_identical(d.type, s.type));
|
||||
|
||||
lb_mem_copy_non_overlapping(p, d, s, lb_const_int(p->module, t_int, type_size_of(type)), false);
|
||||
|
||||
lb_loop_end(p, loop_data);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
case BuiltinProc_alloca:
|
||||
{
|
||||
lbValue sz = lb_build_expr(p, ce->args[0]);
|
||||
|
||||
Reference in New Issue
Block a user