Add intrinsics.soa_copy_from_slice and use it within _append_soa_elems replacing the old handwritten unrolled approach

This commit is contained in:
gingerBill
2026-08-03 14:41:04 +01:00
parent a38d3abbcb
commit 9914a57fc7
7 changed files with 193 additions and 247 deletions

View File

@@ -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]);