diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4a7bb7947..08bb2f457 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5384,6 +5384,40 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; } + case BuiltinProc_soa_unzip: { + if (!build_context.use_llvm_api) { + error(call, "'soa_unzip' is not supported with this backend"); + return false; + } + + Operand x = {}; + check_expr(c, &x, ce->args[0]); + if (x.mode == Addressing_Invalid) { + return false; + } + if (!is_operand_value(x)) { + error(call, "'soa_unzip' expects an #soa slice"); + return false; + } + Type *t = base_type(x.type); + if (!is_type_soa_struct(t) || t->Struct.soa_kind != StructSoa_Slice) { + gbString s = type_to_string(x.type); + error(call, "'soa_unzip' expects an #soa slice, got %s", s); + gb_string_free(s); + return false; + } + auto types = slice_make(permanent_allocator(), t->Struct.fields.count-1); + for_array(i, types) { + Entity *f = t->Struct.fields[i]; + GB_ASSERT(f->type->kind == Type_Pointer); + types[i] = alloc_type_slice(f->type->Pointer.elem); + } + + operand->type = alloc_type_tuple_from_field_types(types.data, types.count, false, false); + operand->mode = Addressing_Value; + break; + } + case BuiltinProc_simd_vector: { Operand x = {}; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 84a3d571b..0c7c6bed1 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -31,6 +31,7 @@ enum BuiltinProcId { BuiltinProc_clamp, BuiltinProc_soa_zip, + BuiltinProc_soa_unzip, BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures @@ -227,7 +228,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("abs"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("clamp"), 3, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("soa_zip"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("soa_zip"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("soa_unzip"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index db86a8dac..9ab2609e9 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -8281,6 +8281,33 @@ lbValue lb_soa_zip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) { return lb_addr_load(p, res); } +lbValue lb_soa_unzip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) { + GB_ASSERT(ce->args.count == 1); + + lbValue arg = lb_build_expr(p, ce->args[0]); + Type *t = base_type(arg.type); + GB_ASSERT(is_type_soa_struct(t) && t->Struct.soa_kind == StructSoa_Slice); + + lbValue len = lb_soa_struct_len(p, arg); + + lbAddr res = lb_add_local_generated(p, tv.type, true); + if (is_type_tuple(tv.type)) { + lbValue rp = lb_addr_get_ptr(p, res); + for (i32 i = 0; i < cast(i32)(t->Struct.fields.count-1); i++) { + lbValue ptr = lb_emit_struct_ev(p, arg, i); + lbAddr dst = lb_addr(lb_emit_struct_ep(p, rp, i)); + lb_fill_slice(p, dst, ptr, len); + } + } else { + GB_ASSERT(is_type_slice(tv.type)); + lbValue ptr = lb_emit_struct_ev(p, arg, 0); + lb_fill_slice(p, res, ptr, len); + } + + return lb_addr_load(p, res); +} + + lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, BuiltinProcId id) { ast_node(ce, CallExpr, expr); @@ -8672,6 +8699,8 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_soa_zip: return lb_soa_zip(p, ce, tv); + case BuiltinProc_soa_unzip: + return lb_soa_unzip(p, ce, tv); // "Intrinsics"