Browse Source

Implement `soa_unzip`

gingerBill 4 years ago
parent
commit
7028797d53
3 changed files with 66 additions and 1 deletions
  1. 34 0
      src/check_expr.cpp
  2. 3 1
      src/checker_builtin_procs.hpp
  3. 29 0
      src/llvm_backend.cpp

+ 34 - 0
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<Type *>(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 = {};

+ 3 - 1
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
 

+ 29 - 0
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"