فهرست منبع

SOA Struct support `intrinsics.soa_struct`

gingerBill 5 سال پیش
والد
کامیت
dfb3101ecf
7فایلهای تغییر یافته به همراه217 افزوده شده و 3 حذف شده
  1. 88 1
      src/check_expr.cpp
  2. 3 0
      src/check_stmt.cpp
  3. 17 1
      src/checker.cpp
  4. 4 1
      src/checker_builtin_procs.hpp
  5. 101 0
      src/ir.cpp
  6. 1 0
      src/parser.hpp
  7. 3 0
      src/types.cpp

+ 88 - 1
src/check_expr.cpp

@@ -3216,7 +3216,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
 			}
 		} else if (operand->mode == Addressing_MapIndex) {
 			operand->mode = Addressing_Value;
-		} else if (sel.indirect || operand->mode != Addressing_Value) {
+		} else if (sel.indirect || operand->mode != Addressing_Value || operand->mode == Addressing_SoaVariable) {
 			operand->mode = Addressing_Variable;
 		} else {
 			operand->mode = Addressing_Value;
@@ -4735,6 +4735,81 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		break;
 	}
 
+	case BuiltinProc_soa_struct: {
+		Operand x = {};
+		Operand y = {};
+		x = *operand;
+		if (!is_type_integer(x.type) || x.mode != Addressing_Constant) {
+			error(call, "Expected a constant integer for 'intrinsics.soa_struct'");
+			operand->mode = Addressing_Type;
+			operand->type = t_invalid;
+			return false;
+		}
+		if (x.value.value_integer.neg) {
+			error(call, "Negative array element length");
+			operand->mode = Addressing_Type;
+			operand->type = t_invalid;
+			return false;
+		}
+		i64 count = big_int_to_i64(&x.value.value_integer);
+
+		check_expr_or_type(c, &y, ce->args[1]);
+		if (y.mode != Addressing_Type) {
+			error(call, "Expected a type 'intrinsics.soa_struct'");
+			operand->mode = Addressing_Type;
+			operand->type = t_invalid;
+			return false;
+		}
+		Type *elem = y.type;
+		if (!is_type_struct(elem) && !is_type_raw_union(elem)) {
+			gbString str = type_to_string(elem);
+			error(call, "Invalid type for 'intrinsics.soa_struct', expected a struct, got '%s'", str);
+			gb_string_free(str);
+			operand->mode = Addressing_Type;
+			operand->type = t_invalid;
+			return false;
+		}
+
+		operand->mode = Addressing_Type;
+
+		Type *old_struct = base_type(elem);
+		Type *soa_struct = alloc_type_struct();
+		soa_struct->Struct.fields = array_make<Entity *>(heap_allocator(), old_struct->Struct.fields.count);
+		soa_struct->Struct.tags = array_make<String>(heap_allocator(), old_struct->Struct.tags.count);
+		soa_struct->Struct.node = operand->expr;
+		soa_struct->Struct.is_soa = true;
+		soa_struct->Struct.soa_elem = elem;
+		soa_struct->Struct.soa_count = count;
+
+		Scope *scope = create_scope(old_struct->Struct.scope->parent, c->allocator);
+		soa_struct->Struct.scope = scope;
+
+		for_array(i, old_struct->Struct.fields) {
+			Entity *old_field = old_struct->Struct.fields[i];
+			if (old_field->kind == Entity_Variable) {
+				Type *array_type = alloc_type_array(old_field->type, count);
+				Entity *new_field = alloc_entity_field(scope, old_field->token, array_type, false, old_field->Variable.field_src_index);
+				soa_struct->Struct.fields[i] = new_field;
+				add_entity(c->checker, scope, nullptr, new_field);
+			} else {
+				soa_struct->Struct.fields[i] = old_field;
+			}
+
+			soa_struct->Struct.tags[i] = old_struct->Struct.tags[i];
+		}
+
+
+		Token token = {};
+		token.string = str_lit("Base_Type");
+		Entity *base_type_entity = alloc_entity_type_name(scope, token, elem, EntityState_Resolved);
+		add_entity(c->checker, scope, nullptr, base_type_entity);
+
+		add_type_info_type(c, soa_struct);
+
+		operand->type = soa_struct;
+		break;
+	}
+
 	case BuiltinProc_atomic_fence:
 	case BuiltinProc_atomic_fence_acq:
 	case BuiltinProc_atomic_fence_rel:
@@ -6640,6 +6715,18 @@ bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 *max_count)
 			o->mode = Addressing_Variable;
 		}
 		return true;
+	case Type_Struct:
+		if (t->Struct.is_soa) {
+			*max_count = t->Struct.soa_count;
+			o->type = t->Struct.soa_elem;
+			if (o->mode == Addressing_SoaVariable || o->mode == Addressing_Variable) {
+				o->mode = Addressing_SoaVariable;
+			} else {
+				o->mode = Addressing_Value;
+			}
+			return true;
+		}
+		return false;
 	}
 
 	return false;

+ 3 - 0
src/check_stmt.cpp

@@ -293,6 +293,9 @@ Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs)
 		break;
 	}
 
+	case Addressing_SoaVariable:
+		break;
+
 	default: {
 		if (lhs->expr->kind == Ast_SelectorExpr) {
 			// NOTE(bill): Extra error checks

+ 17 - 1
src/checker.cpp

@@ -13,6 +13,7 @@ bool is_operand_value(Operand o) {
 	case Addressing_Constant:
 	case Addressing_MapIndex:
 	case Addressing_OptionalOk:
+	case Addressing_SoaVariable:
 		return true;
 	}
 	return false;
@@ -1255,6 +1256,9 @@ void add_type_info_type(CheckerContext *c, Type *t) {
 		break;
 	case Type_Basic:
 		switch (bt->Basic.kind) {
+		case Basic_cstring:
+			add_type_info_type(c, t_u8_ptr);
+			break;
 		case Basic_string:
 			add_type_info_type(c, t_u8_ptr);
 			add_type_info_type(c, t_int);
@@ -1274,6 +1278,14 @@ void add_type_info_type(CheckerContext *c, Type *t) {
 			add_type_info_type(c, t_type_info_float);
 			add_type_info_type(c, t_f64);
 			break;
+		case Basic_quaternion128:
+			add_type_info_type(c, t_type_info_float);
+			add_type_info_type(c, t_f32);
+			break;
+		case Basic_quaternion256:
+			add_type_info_type(c, t_type_info_float);
+			add_type_info_type(c, t_f64);
+			break;
 		}
 		break;
 
@@ -1328,7 +1340,11 @@ void add_type_info_type(CheckerContext *c, Type *t) {
 		if (bt->Struct.scope != nullptr) {
 			for_array(i, bt->Struct.scope->elements.entries) {
 				Entity *e = bt->Struct.scope->elements.entries[i].value;
-				add_type_info_type(c, e->type);
+				if (bt->Struct.is_soa) {
+					add_type_info_type(c, alloc_type_pointer(e->type));
+				} else {
+					add_type_info_type(c, e->type);
+				}
 			}
 		}
 		for_array(i, bt->Struct.fields) {

+ 4 - 1
src/checker_builtin_procs.hpp

@@ -34,6 +34,7 @@ enum BuiltinProcId {
 
 	// "Intrinsics"
 	BuiltinProc_vector,
+	BuiltinProc_soa_struct,
 
 	BuiltinProc_atomic_fence,
 	BuiltinProc_atomic_fence_acq,
@@ -159,6 +160,7 @@ BuiltinProc__type_begin,
 
 BuiltinProc__type_end,
 
+
 	BuiltinProc_COUNT,
 };
 gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
@@ -195,7 +197,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 
 
 	// "Intrinsics"
-	{STR_LIT("vector"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
+	{STR_LIT("vector"),     2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
+	{STR_LIT("soa_struct"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type
 
 	{STR_LIT("atomic_fence"),        0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
 	{STR_LIT("atomic_fence_acq"),    0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},

+ 101 - 0
src/ir.cpp

@@ -483,6 +483,7 @@ enum irAddrKind {
 	irAddr_Map,
 	irAddr_BitField,
 	irAddr_Context,
+	irAddr_SoaVariable,
 };
 
 struct irAddr {
@@ -500,6 +501,10 @@ struct irAddr {
 		struct {
 			Selection sel;
 		} ctx;
+		struct {
+			irValue *index;
+			Ast *index_expr;
+		} soa;
 	};
 };
 
@@ -530,6 +535,14 @@ irAddr ir_addr_bit_field(irValue *addr, i32 bit_field_value_index) {
 	return v;
 }
 
+irAddr ir_addr_soa_variable(irValue *addr, irValue *index, Ast *index_expr) {
+	irAddr v = {irAddr_SoaVariable, addr};
+	v.soa.index = index;
+	v.soa.index_expr = index_expr;
+	return v;
+}
+
+
 enum irDebugEncoding {
 	irDebugBasicEncoding_Invalid       = 0,
 
@@ -3397,6 +3410,8 @@ irValue *ir_emit_source_code_location(irProcedure *proc, Ast *node);
 irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset);
 irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type);
 irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel);
+void ir_emit_bounds_check(irProcedure *proc, Token token, irValue *index, irValue *len);
+
 
 irValue *ir_insert_dynamic_map_key_and_value(irProcedure *proc, irValue *addr, Type *map_type,
                                              irValue *map_key, irValue *map_value) {
@@ -3532,6 +3547,28 @@ void ir_addr_store(irProcedure *proc, irAddr const &addr, irValue *value) {
 			ir_emit_store(proc, lhs, rhs);
 		}
 
+		return;
+	} else if (addr.kind == irAddr_SoaVariable) {
+		Type *t = type_deref(ir_type(addr.addr));
+		t = base_type(t);
+		GB_ASSERT(t->kind == Type_Struct && t->Struct.is_soa);
+		value = ir_emit_conv(proc, value, t->Struct.soa_elem);
+
+		irValue *index = addr.soa.index;
+		if (index->kind != irValue_Constant) {
+			Type *t = base_type(type_deref(ir_type(addr.addr)));
+			GB_ASSERT(t->kind == Type_Struct && t->Struct.is_soa);
+			i64 count = t->Struct.soa_count;
+			irValue *len = ir_const_int(count);
+			ir_emit_bounds_check(proc, ast_token(addr.soa.index_expr), index, len);
+		}
+
+		for_array(i, t->Struct.fields) {
+			irValue *dst = ir_emit_struct_ep(proc, addr.addr, cast(i32)i);
+			dst = ir_emit_array_ep(proc, dst, index);
+			irValue *src = ir_emit_struct_ev(proc, value, cast(i32)i);
+			ir_emit_store(proc, dst, src);
+		}
 		return;
 	}
 
@@ -3642,6 +3679,35 @@ irValue *ir_addr_load(irProcedure *proc, irAddr const &addr) {
 			irValue *b = ir_emit_deep_field_gep(proc, a, addr.ctx.sel);
 			return ir_emit_load(proc, b);
 		}
+	} else if (addr.kind == irAddr_SoaVariable) {
+		Type *t = type_deref(ir_type(addr.addr));
+		t = base_type(t);
+		GB_ASSERT(t->kind == Type_Struct && t->Struct.is_soa);
+		Type *elem = t->Struct.soa_elem;;
+		i32 count = cast(i32)t->Struct.soa_count;
+
+		irValue *res = ir_add_local_generated(proc, elem, true);
+
+		if (addr.soa.index->kind != irValue_Constant) {
+			irValue *len = ir_const_int(count);
+			ir_emit_bounds_check(proc, ast_token(addr.soa.index_expr), addr.soa.index, len);
+		}
+
+		for_array(i, t->Struct.fields) {
+			Entity *field = t->Struct.fields[i];
+			Type *base_type = field->type;
+			GB_ASSERT(base_type->kind == Type_Array);
+			Type *elem = base_type->Array.elem;
+
+
+			irValue *dst = ir_emit_struct_ep(proc, res, cast(i32)i);
+			irValue *src_ptr = ir_emit_struct_ep(proc, addr.addr, cast(i32)i);
+			src_ptr = ir_emit_array_ep(proc, src_ptr, addr.soa.index);
+			irValue *src = ir_emit_load(proc, src_ptr);
+			ir_emit_store(proc, dst, src);
+		}
+
+		return ir_emit_load(proc, res);
 	}
 
 	Type *t = base_type(ir_type(addr.addr));
@@ -7459,6 +7525,28 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 					addr.ctx.sel = sel;
 
 					return addr;
+				} else if (addr.kind == irAddr_SoaVariable) {
+					irValue *index = addr.soa.index;
+					i32 first_index = sel.index[0];
+					Selection sub_sel = sel;
+					sub_sel.index.data += 1;
+					sub_sel.index.count -= 1;
+
+					irValue *arr = ir_emit_struct_ep(proc, addr.addr, first_index);
+
+					if (addr.soa.index->kind != irValue_Constant) {
+						Type *t = base_type(type_deref(ir_type(addr.addr)));
+						GB_ASSERT(t->kind == Type_Struct && t->Struct.is_soa);
+						i64 count = t->Struct.soa_count;
+						irValue *len = ir_const_int(count);
+						ir_emit_bounds_check(proc, ast_token(addr.soa.index_expr), addr.soa.index, len);
+					}
+
+					irValue *item = ir_emit_array_ep(proc, arr, index);
+					if (sub_sel.index.count > 0) {
+						item = ir_emit_deep_field_gep(proc, item, sub_sel);
+					}
+					return ir_addr(item);
 				}
 				irValue *a = ir_addr_get_ptr(proc, addr);
 				a = ir_emit_deep_field_gep(proc, a, sel);
@@ -7515,6 +7603,19 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 
 		bool deref = is_type_pointer(t);
 		t = base_type(type_deref(t));
+		if (t->kind == Type_Struct && t->Struct.is_soa) {
+			// SOA STRUCTURES!!!!
+			Type *elem = t->Struct.soa_elem;
+
+			irValue *val = ir_build_addr_ptr(proc, ie->expr);
+			if (deref) {
+				val = ir_emit_load(proc, val);
+			}
+
+			irValue *index = ir_build_expr(proc, ie->index);
+			return ir_addr_soa_variable(val, index, ie->index);
+		}
+
 		GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr));
 
 		if (is_type_map(t)) {

+ 1 - 0
src/parser.hpp

@@ -21,6 +21,7 @@ enum AddressingMode {
 	                          // 	lhs: acts like a Variable
 	                          // 	rhs: acts like OptionalOk
 	Addressing_OptionalOk,    // rhs: acts like a value with an optional boolean part (for existence check)
+	Addressing_SoaVariable,   // Struct-Of-Arrays indexed variable
 };
 
 struct TypeAndValue {

+ 3 - 0
src/types.cpp

@@ -129,6 +129,9 @@ struct TypeStruct {
 	bool is_raw_union;
 	bool is_polymorphic;
 	bool is_poly_specialized;
+	bool is_soa;
+	Type *soa_elem;
+	i64   soa_count;
 };
 
 struct TypeUnion {