mirror of
https://github.com/odin-lang/Odin.git
synced 2026-08-27 07:21:31 +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:
@@ -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 = {};
|
||||
|
||||
|
||||
@@ -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},
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user