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

@@ -379,6 +379,7 @@ simd_pairwise_sub :: proc(a, b: #simd[LANES]T) -> #simd[LANES]T where LANES % 2
simd_interleave :: proc(a, ..#simd[LANES/N]T) -> #simd[LANES]T where N >= 1 ---
simd_deinterleave :: proc(a: #simd[LANES]T, $N: uint) -> (..#simd[LANES/N]T) where N >= 1, LANES % N == 0 --- // returns N multiple vectors
soa_copy_from_slice :: proc(ptr: ^$A/#soa[dynamic]$E, offset: int, args: []$E) ---
// Checks if the current target supports the given target features.
//

View File

@@ -491,257 +491,27 @@ _append_soa_elems :: proc(#no_alias array: ^$T/#soa[dynamic]$E, zero_memory: boo
// (Note that offset and the multipointers must be read after _reserve_soa, because any growth moves them.)
offset := footer.len
FIELD_COUNT :: len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)
when FIELD_COUNT <= 16 {
when ODIN_OPTIMIZATION_MODE <= .Size {
// Use the compiler's #soa element store lowering.
// Note that #no_bounds_check is not optional, we write at index == len.
#no_bounds_check {
for j in 0..<arg_len {
array[offset + j] = args[j]
}
}
} else when FIELD_COUNT >= 1 { // nothing to do if field count is 0
_append_soa_elems_per_field_expanded(array, offset, args[:arg_len])
}
} else { // FIELD_COUNT > 16
ti := type_info_base(type_info_of(typeid_of(T)))
si := &ti.variant.(Type_Info_Struct)
// si describes the SOA struct (fields are multipointers), so E's
// field offsets are not available in it; read them from E's own RTTI (si.soa_base_type).
// Note that basing on default struct layout here instead
// would misplace the fields of #packed elements.
// (> 16 fields is struct-only: array element types are capped at length 4.)
se := &type_info_base(si.soa_base_type).variant.(Type_Info_Struct)
src_base := uintptr(raw_data(args))
for i in 0..<uintptr(FIELD_COUNT) {
type := si.types[i].variant.(Type_Info_Multi_Pointer).elem
dst := uintptr(([^]rawptr)(array)[i]) + uintptr(type.size*offset)
src := src_base + se.offsets[i]
footer.len += arg_len
when FIELD_COUNT == 0 {
// do nothing
} else when FIELD_COUNT <= 16 && ODIN_OPTIMIZATION_MODE <= .Size {
// Use the compiler's #soa element store lowering.
// Note that #no_bounds_check is not optional, we write at index == len.
#no_bounds_check {
for j in 0..<arg_len {
mem_copy(rawptr(dst + uintptr(j*type.size)), rawptr(src + uintptr(j*size_of(E))), type.size)
array[offset + j] = args[j]
}
}
}
}
footer.len += arg_len
return arg_len, err
}
// 1..16-field expnaded copy arms for _append_soa_elems.
// this only exists to keep _append_soa_elems more readable.
// args MUST already be clamped to capacity by the caller.
_append_soa_elems_per_field_expanded :: #force_inline proc(#no_alias array: ^$T/#soa[dynamic]$E, offset: int, #no_broadcast args: []E) {
arg_len := len(args)
FIELD_COUNT :: len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E)
when FIELD_COUNT == 1 {
// here and below the ignored last 3 values comprise the footer
p0, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v := expand_values(args[j]); p0[offset+j] = v }
}
} else when FIELD_COUNT == 2 {
p0, p1, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v := expand_values(args[j]); p1[offset+j] = v }
}
} else when FIELD_COUNT == 3 {
p0, p1, p2, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v := expand_values(args[j]); p2[offset+j] = v }
}
} else when FIELD_COUNT == 4 {
p0, p1, p2, p3, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v, _ := expand_values(args[j]); p2[offset+j] = v }
for j in 0..<arg_len { _, _, _, v := expand_values(args[j]); p3[offset+j] = v }
}
} else when FIELD_COUNT == 5 {
p0, p1, p2, p3, p4, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _, _, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v, _, _ := expand_values(args[j]); p2[offset+j] = v }
for j in 0..<arg_len { _, _, _, v, _ := expand_values(args[j]); p3[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, v := expand_values(args[j]); p4[offset+j] = v }
}
} else when FIELD_COUNT == 6 {
p0, p1, p2, p3, p4, p5, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _, _, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _, _, _, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v, _, _, _ := expand_values(args[j]); p2[offset+j] = v }
for j in 0..<arg_len { _, _, _, v, _, _ := expand_values(args[j]); p3[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, v, _ := expand_values(args[j]); p4[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, v := expand_values(args[j]); p5[offset+j] = v }
}
} else when FIELD_COUNT == 7 {
p0, p1, p2, p3, p4, p5, p6, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _, _, _, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _, _, _, _, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v, _, _, _, _ := expand_values(args[j]); p2[offset+j] = v }
for j in 0..<arg_len { _, _, _, v, _, _, _ := expand_values(args[j]); p3[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, v, _, _ := expand_values(args[j]); p4[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, v, _ := expand_values(args[j]); p5[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, v := expand_values(args[j]); p6[offset+j] = v }
}
} else when FIELD_COUNT == 8 {
p0, p1, p2, p3, p4, p5, p6, p7, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _, _, _, _, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _, _, _, _, _, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v, _, _, _, _, _ := expand_values(args[j]); p2[offset+j] = v }
for j in 0..<arg_len { _, _, _, v, _, _, _, _ := expand_values(args[j]); p3[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, v, _, _, _ := expand_values(args[j]); p4[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, v, _, _ := expand_values(args[j]); p5[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, v, _ := expand_values(args[j]); p6[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, v := expand_values(args[j]); p7[offset+j] = v }
}
} else when FIELD_COUNT == 9 {
p0, p1, p2, p3, p4, p5, p6, p7, p8, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _, _, _, _, _, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _, _, _, _, _, _, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v, _, _, _, _, _, _ := expand_values(args[j]); p2[offset+j] = v }
for j in 0..<arg_len { _, _, _, v, _, _, _, _, _ := expand_values(args[j]); p3[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, v, _, _, _, _ := expand_values(args[j]); p4[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, v, _, _, _ := expand_values(args[j]); p5[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, v, _, _ := expand_values(args[j]); p6[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, v, _ := expand_values(args[j]); p7[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, v := expand_values(args[j]); p8[offset+j] = v }
}
} else when FIELD_COUNT == 10 {
p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _, _, _, _, _, _, _, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v, _, _, _, _, _, _, _ := expand_values(args[j]); p2[offset+j] = v }
for j in 0..<arg_len { _, _, _, v, _, _, _, _, _, _ := expand_values(args[j]); p3[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, v, _, _, _, _, _ := expand_values(args[j]); p4[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, v, _, _, _, _ := expand_values(args[j]); p5[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, v, _, _, _ := expand_values(args[j]); p6[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, v, _, _ := expand_values(args[j]); p7[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, v, _ := expand_values(args[j]); p8[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, v := expand_values(args[j]); p9[offset+j] = v }
}
} else when FIELD_COUNT == 11 {
p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v, _, _, _, _, _, _, _, _ := expand_values(args[j]); p2[offset+j] = v }
for j in 0..<arg_len { _, _, _, v, _, _, _, _, _, _, _ := expand_values(args[j]); p3[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, v, _, _, _, _, _, _ := expand_values(args[j]); p4[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, v, _, _, _, _, _ := expand_values(args[j]); p5[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, v, _, _, _, _ := expand_values(args[j]); p6[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, v, _, _, _ := expand_values(args[j]); p7[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, v, _, _ := expand_values(args[j]); p8[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, v, _ := expand_values(args[j]); p9[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, v := expand_values(args[j]); p10[offset+j] = v }
}
} else when FIELD_COUNT == 12 {
p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p2[offset+j] = v }
for j in 0..<arg_len { _, _, _, v, _, _, _, _, _, _, _, _ := expand_values(args[j]); p3[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, v, _, _, _, _, _, _, _ := expand_values(args[j]); p4[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, v, _, _, _, _, _, _ := expand_values(args[j]); p5[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, v, _, _, _, _, _ := expand_values(args[j]); p6[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, v, _, _, _, _ := expand_values(args[j]); p7[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, v, _, _, _ := expand_values(args[j]); p8[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, v, _, _ := expand_values(args[j]); p9[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, v, _ := expand_values(args[j]); p10[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, v := expand_values(args[j]); p11[offset+j] = v }
}
} else when FIELD_COUNT == 13 {
p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p2[offset+j] = v }
for j in 0..<arg_len { _, _, _, v, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p3[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, v, _, _, _, _, _, _, _, _ := expand_values(args[j]); p4[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, v, _, _, _, _, _, _, _ := expand_values(args[j]); p5[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, v, _, _, _, _, _, _ := expand_values(args[j]); p6[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, v, _, _, _, _, _ := expand_values(args[j]); p7[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, v, _, _, _, _ := expand_values(args[j]); p8[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, v, _, _, _ := expand_values(args[j]); p9[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, v, _, _ := expand_values(args[j]); p10[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, v, _ := expand_values(args[j]); p11[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, _, v := expand_values(args[j]); p12[offset+j] = v }
}
} else when FIELD_COUNT == 14 {
p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p2[offset+j] = v }
for j in 0..<arg_len { _, _, _, v, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p3[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, v, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p4[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, v, _, _, _, _, _, _, _, _ := expand_values(args[j]); p5[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, v, _, _, _, _, _, _, _ := expand_values(args[j]); p6[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, v, _, _, _, _, _, _ := expand_values(args[j]); p7[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, v, _, _, _, _, _ := expand_values(args[j]); p8[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, v, _, _, _, _ := expand_values(args[j]); p9[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, v, _, _, _ := expand_values(args[j]); p10[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, v, _, _ := expand_values(args[j]); p11[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, _, v, _ := expand_values(args[j]); p12[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, _, _, v := expand_values(args[j]); p13[offset+j] = v }
}
} else when FIELD_COUNT == 15 {
p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _, _, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _, _, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v, _, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p2[offset+j] = v }
for j in 0..<arg_len { _, _, _, v, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p3[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, v, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p4[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, v, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p5[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, v, _, _, _, _, _, _, _, _ := expand_values(args[j]); p6[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, v, _, _, _, _, _, _, _ := expand_values(args[j]); p7[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, v, _, _, _, _, _, _ := expand_values(args[j]); p8[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, v, _, _, _, _, _ := expand_values(args[j]); p9[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, v, _, _, _, _ := expand_values(args[j]); p10[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, v, _, _, _ := expand_values(args[j]); p11[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, _, v, _, _ := expand_values(args[j]); p12[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, _, _, v, _ := expand_values(args[j]); p13[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, _, _, _, v := expand_values(args[j]); p14[offset+j] = v }
}
} else when FIELD_COUNT == 16 {
p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, _, _, _ := expand_values(array^)
#no_bounds_check {
for j in 0..<arg_len { v, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p0[offset+j] = v }
for j in 0..<arg_len { _, v, _, _, _, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p1[offset+j] = v }
for j in 0..<arg_len { _, _, v, _, _, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p2[offset+j] = v }
for j in 0..<arg_len { _, _, _, v, _, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p3[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, v, _, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p4[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, v, _, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p5[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, v, _, _, _, _, _, _, _, _, _ := expand_values(args[j]); p6[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, v, _, _, _, _, _, _, _, _ := expand_values(args[j]); p7[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, v, _, _, _, _, _, _, _ := expand_values(args[j]); p8[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, v, _, _, _, _, _, _ := expand_values(args[j]); p9[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, v, _, _, _, _, _ := expand_values(args[j]); p10[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, v, _, _, _, _ := expand_values(args[j]); p11[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, _, v, _, _, _ := expand_values(args[j]); p12[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, _, _, v, _, _ := expand_values(args[j]); p13[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, _, _, _, v, _ := expand_values(args[j]); p14[offset+j] = v }
for j in 0..<arg_len { _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, v := expand_values(args[j]); p15[offset+j] = v }
} else {
intrinsics.soa_copy_from_slice(array, offset, args[:arg_len])
}
} else {
#panic("_append_soa_elems_per_field_expanded instantiated with an unsupported field count")
footer.len += arg_len
}
return arg_len, err
}
// The append_soa built-in procedure appends elements to the end of an #soa dynamic array
@builtin
append_soa :: proc{

View File

@@ -5282,6 +5282,62 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
break;
}
case BuiltinProc_soa_copy_from_slice: {
Operand array_ptr = {};
Operand offset = {};
Operand args = {};
check_expr(c, &array_ptr, ce->args[0]);
if (array_ptr.mode == Addressing_Invalid) {
return false;
}
if (!is_type_pointer(array_ptr.type)) {
gbString s = type_to_string(array_ptr.type);
error(array_ptr.expr, "Expected a pointer to a #soa dynamic array, got %s", s);
gb_string_free(s);
return false;
}
Type *array_type = type_deref(array_ptr.type);
if (!is_type_soa_dynamic_array(array_type)) {
gbString s = type_to_string(array_ptr.type);
error(array_ptr.expr, "Expected a pointer to a #soa dynamic array, got %s", s);
gb_string_free(s);
return false;
}
Type *at = base_type(array_type);
GB_ASSERT(at->kind == Type_Struct);
Type *elem = at->Struct.soa_elem;
check_expr_with_type_hint(c, &offset, ce->args[1], t_int);
if (offset.mode == Addressing_Invalid) {
return false;
}
if (!is_type_integer(offset.type)) {
gbString s = type_to_string(array_ptr.type);
error(array_ptr.expr, "Expected an integer as the offset for '%.*s', got %s", s, LIT(builtin_name));
gb_string_free(s);
return false;
}
Type *slice_hint = alloc_type_slice(elem);
check_expr_with_type_hint(c, &args, ce->args[2], slice_hint);
if (args.mode == Addressing_Invalid) {
return false;
}
if (!are_types_identical(base_type(args.type), slice_hint)) {
gbString s = type_to_string(slice_hint);
gbString t = type_to_string(args.type);
error(array_ptr.expr, "Expected a %s to use as the slice '%.*s', got %s", s, LIT(builtin_name), t);
gb_string_free(t);
gb_string_free(s);
return false;
}
operand->mode = Addressing_NoValue;
operand->type = nullptr;
break;
}
case BuiltinProc_concatenate: {
Operand lhs = {};

View File

@@ -60,6 +60,7 @@ enum BuiltinProcId {
BuiltinProc_matrix_flatten,
BuiltinProc_soa_struct,
BuiltinProc_soa_copy_from_slice,
BuiltinProc_concatenate,
@@ -99,12 +100,12 @@ enum BuiltinProcId {
BuiltinProc_volatile_store,
BuiltinProc_volatile_load,
BuiltinProc_unaligned_store,
BuiltinProc_unaligned_load,
BuiltinProc_non_temporal_store,
BuiltinProc_non_temporal_load,
BuiltinProc_prefetch_read_instruction,
BuiltinProc_prefetch_read_data,
BuiltinProc_prefetch_write_instruction,
@@ -242,7 +243,7 @@ BuiltinProc__simd_begin,
// Platform specific SIMD intrinsics
BuiltinProc_simd_x86__MM_SHUFFLE,
BuiltinProc__simd_end,
// Platform specific intrinsics
BuiltinProc_syscall,
BuiltinProc_syscall_bsd,
@@ -328,7 +329,7 @@ BuiltinProc__type_simple_boolean_end,
BuiltinProc_type_has_field,
BuiltinProc_type_field_type,
BuiltinProc_type_field_bit_offset,
BuiltinProc_type_field_bit_size,
@@ -467,8 +468,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("outer_product"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("hadamard_product"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("matrix_flatten"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("soa_struct"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
{STR_LIT("soa_copy_from_slice"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("concatenate"), 2, true, Expr_Expr, BuiltinProcPkg_intrinsics},

View File

@@ -330,6 +330,29 @@ gb_internal lbLoopData lb_loop_start(lbProcedure *p, isize count, Type *index_ty
return data;
}
gb_internal lbLoopData lb_loop_start_runtime(lbProcedure *p, lbValue count) {
lbLoopData data = {};
lbValue max = count;
data.idx_addr = lb_add_local_generated(p, count.type, true);
data.body = lb_create_block(p, "loop.body");
data.done = lb_create_block(p, "loop.done");
data.loop = lb_create_block(p, "loop.loop");
lb_emit_jump(p, data.loop);
lb_start_block(p, data.loop);
data.idx = lb_addr_load(p, data.idx_addr);
lbValue cond = lb_emit_comp(p, Token_Lt, data.idx, max);
lb_emit_if(p, cond, data.body, data.done);
lb_start_block(p, data.body);
return data;
}
gb_internal void lb_loop_end(lbProcedure *p, lbLoopData const &data) {
if (data.idx_addr.addr.value != nullptr) {
lb_emit_increment(p, data.idx_addr.addr);

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

View File

@@ -2001,6 +2001,11 @@ gb_internal bool is_type_soa_struct(Type *t) {
if (t == nullptr) { return false; }
return t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None;
}
gb_internal bool is_type_soa_dynamic_array(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
return t->kind == Type_Struct && t->Struct.soa_kind == StructSoa_Dynamic;
}
gb_internal bool is_type_raw_union(Type *t) {
t = base_type(t);