Browse Source

SOA support of Structures and Arrays; Runtime information for SOA structs; fmt printing support for SOA structs

gingerBill 5 years ago
parent
commit
ebf7926fa4
5 changed files with 172 additions and 49 deletions
  1. 64 18
      core/fmt/fmt.odin
  2. 3 0
      core/runtime/core.odin
  3. 67 24
      src/check_expr.cpp
  4. 21 7
      src/ir.cpp
  5. 17 0
      src/types.cpp

+ 64 - 18
core/fmt/fmt.odin

@@ -1085,8 +1085,11 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
 				strings.write_string(fi.buf, "{}");
 				strings.write_string(fi.buf, "{}");
 				return;
 				return;
 			};
 			};
+
+			is_soa := b.soa_base_type != nil;
+
 			strings.write_string(fi.buf, info.name);
 			strings.write_string(fi.buf, info.name);
-			strings.write_byte(fi.buf, '{');
+			strings.write_byte(fi.buf, is_soa ? '[' : '{');
 
 
 			hash   := fi.hash;   defer fi.hash = hash;
 			hash   := fi.hash;   defer fi.hash = hash;
 			indent := fi.indent; defer fi.indent -= 1;
 			indent := fi.indent; defer fi.indent -= 1;
@@ -1095,30 +1098,73 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
 			fi.indent += 1;
 			fi.indent += 1;
 
 
 			if hash	do strings.write_byte(fi.buf, '\n');
 			if hash	do strings.write_byte(fi.buf, '\n');
+			defer {
+				if hash do for in 0..<indent do strings.write_byte(fi.buf, '\t');
+				strings.write_byte(fi.buf, is_soa ? ']' : '}');
+			}
 
 
-			field_count := -1;
-			for name, i in b.names {
-				// if len(name) > 0 && name[0] == '_' do continue;
-				field_count += 1;
+			if is_soa {
+				indent := fi.indent; defer fi.indent -= 1;
+				fi.indent += 1;
 
 
-				if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
-				if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t');
+				base_type_name: string;
+				if v, ok := b.soa_base_type.variant.(runtime.Type_Info_Named); ok {
+					base_type_name = v.name;
+				}
 
 
-				strings.write_string(fi.buf, name);
-				strings.write_string(fi.buf, " = ");
+				for index in 0..<uintptr(b.soa_len) {
+					if !hash && index > 0 do strings.write_string(fi.buf, ", ");
 
 
-				if t := b.types[i]; reflect.is_any(t) {
-					strings.write_string(fi.buf, "any{}");
-				} else {
-					data := rawptr(uintptr(v.data) + b.offsets[i]);
-					fmt_arg(fi, any{data, t.id}, 'v');
+					field_count := -1;
+
+					if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
+
+					strings.write_string(fi.buf, base_type_name);
+					strings.write_byte(fi.buf, '{');
+					defer strings.write_byte(fi.buf, '}');
+
+					for name, i in b.names {
+						field_count += 1;
+
+						if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
+						if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t');
+
+						strings.write_string(fi.buf, name);
+						strings.write_string(fi.buf, " = ");
+
+						t := b.types[i].variant.(runtime.Type_Info_Array).elem;
+						t_size := uintptr(t.size);
+						if reflect.is_any(t) {
+							strings.write_string(fi.buf, "any{}");
+						} else {
+							data := rawptr(uintptr(v.data) + b.offsets[i] + index*t_size);
+							fmt_arg(fi, any{data, t.id}, 'v');
+						}
+
+						if hash do strings.write_string(fi.buf, ",\n");
+					}
 				}
 				}
+			} else {
+				field_count := -1;
+				for name, i in b.names {
+					field_count += 1;
 
 
-				if hash do strings.write_string(fi.buf, ",\n");
-			}
+					if !hash && field_count > 0 do strings.write_string(fi.buf, ", ");
+					if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t');
 
 
-			if hash do for in 0..<indent do strings.write_byte(fi.buf, '\t');
-			strings.write_byte(fi.buf, '}');
+					strings.write_string(fi.buf, name);
+					strings.write_string(fi.buf, " = ");
+
+					if t := b.types[i]; reflect.is_any(t) {
+						strings.write_string(fi.buf, "any{}");
+					} else {
+						data := rawptr(uintptr(v.data) + b.offsets[i]);
+						fmt_arg(fi, any{data, t.id}, 'v');
+					}
+
+					if hash do strings.write_string(fi.buf, ",\n");
+				}
+			}
 
 
 		case runtime.Type_Info_Bit_Set:
 		case runtime.Type_Info_Bit_Set:
 			fmt_bit_set(fi, v);
 			fmt_bit_set(fi, v);

+ 3 - 0
core/runtime/core.odin

@@ -87,6 +87,9 @@ Type_Info_Struct :: struct {
 	is_packed:    bool,
 	is_packed:    bool,
 	is_raw_union: bool,
 	is_raw_union: bool,
 	custom_align: bool,
 	custom_align: bool,
+	// These are only set iff this structure is an SOA structure
+	soa_base_type: ^Type_Info,
+	soa_len:       int,
 };
 };
 Type_Info_Union :: struct {
 Type_Info_Union :: struct {
 	variants:     []^Type_Info,
 	variants:     []^Type_Info,

+ 67 - 24
src/check_expr.cpp

@@ -3616,6 +3616,13 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 			mode  = Addressing_Constant;
 			mode  = Addressing_Constant;
 			value = exact_value_i64(bt->Enum.fields.count);
 			value = exact_value_i64(bt->Enum.fields.count);
 			type  = t_untyped_integer;
 			type  = t_untyped_integer;
+		} else if (is_type_struct(op_type)) {
+			Type *bt = base_type(op_type);
+			if (bt->Struct.is_soa) {
+				mode  = Addressing_Constant;
+				value = exact_value_i64(bt->Struct.soa_count);
+				type  = t_untyped_integer;
+			}
 		}
 		}
 
 
 		if (mode == Addressing_Invalid) {
 		if (mode == Addressing_Invalid) {
@@ -4761,9 +4768,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 			return false;
 			return false;
 		}
 		}
 		Type *elem = y.type;
 		Type *elem = y.type;
-		if (!is_type_struct(elem) && !is_type_raw_union(elem)) {
+		Type *bt_elem = base_type(elem);
+		if (!is_type_struct(elem) && !is_type_raw_union(elem) && !(is_type_array(elem) && bt_elem->Array.count <= 4)) {
 			gbString str = type_to_string(elem);
 			gbString str = type_to_string(elem);
-			error(call, "Invalid type for 'intrinsics.soa_struct', expected a struct, got '%s'", str);
+			error(call, "Invalid type for 'intrinsics.soa_struct', expected a struct or array of length 4 or below, got '%s'", str);
 			gb_string_free(str);
 			gb_string_free(str);
 			operand->mode = Addressing_Type;
 			operand->mode = Addressing_Type;
 			operand->type = t_invalid;
 			operand->type = t_invalid;
@@ -4771,33 +4779,68 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		}
 		}
 
 
 		operand->mode = Addressing_Type;
 		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);
+		Type *soa_struct = nullptr;
+		Scope *scope = nullptr;
+
+		if (is_type_array(elem)) {
+			Type *old_array = base_type(elem);
+			soa_struct = alloc_type_struct();
+			soa_struct->Struct.fields = array_make<Entity *>(heap_allocator(), old_array->Array.count);
+			soa_struct->Struct.tags = array_make<String>(heap_allocator(), old_array->Array.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 = create_scope(c->scope, c->allocator);
+			soa_struct->Struct.scope = scope;
+
+			String params_xyzw[4] = {
+				str_lit("x"),
+				str_lit("y"),
+				str_lit("z"),
+				str_lit("w")
+			};
+
+			for (i64 i = 0; i < old_array->Array.count; i++) {
+				Type *array_type = alloc_type_array(old_array->Array.elem, count);
+				Token token = {};
+				token.string = params_xyzw[i];
+
+				Entity *new_field = alloc_entity_field(scope, token, array_type, false, cast(i32)i);
 				soa_struct->Struct.fields[i] = new_field;
 				soa_struct->Struct.fields[i] = new_field;
 				add_entity(c->checker, scope, nullptr, 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];
-		}
+		} else {
+			GB_ASSERT(is_type_struct(elem));
+
+			Type *old_struct = base_type(elem);
+			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 = 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 token = {};
 		token.string = str_lit("Base_Type");
 		token.string = str_lit("Base_Type");

+ 21 - 7
src/ir.cpp

@@ -4553,6 +4553,8 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
 		case 0: result_type = alloc_type_pointer(gst->Struct.fields[0]->type); break;
 		case 0: result_type = alloc_type_pointer(gst->Struct.fields[0]->type); break;
 		case 1: result_type = alloc_type_pointer(gst->Struct.fields[1]->type); break;
 		case 1: result_type = alloc_type_pointer(gst->Struct.fields[1]->type); break;
 		}
 		}
+	} else if (is_type_array(t)) {
+		return ir_emit_array_epi(proc, s, index);
 	} else {
 	} else {
 		GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(ir_type(s)), index);
 		GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(ir_type(s)), index);
 	}
 	}
@@ -4632,15 +4634,20 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
 		}
 		}
 		break;
 		break;
 
 
-	case Type_Map: {
-		init_map_internal_types(t);
-		Type *gst = t->Map.generated_struct_type;
-		switch (index) {
-		case 0: result_type = gst->Struct.fields[0]->type; break;
-		case 1: result_type = gst->Struct.fields[1]->type; break;
+	case Type_Map:
+		{
+			init_map_internal_types(t);
+			Type *gst = t->Map.generated_struct_type;
+			switch (index) {
+			case 0: result_type = gst->Struct.fields[0]->type; break;
+			case 1: result_type = gst->Struct.fields[1]->type; break;
+			}
 		}
 		}
 		break;
 		break;
-	}
+
+	case Type_Array:
+		result_type = t->Array.elem;
+		break;
 
 
 	default:
 	default:
 		GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(ir_type(s)), index);
 		GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(ir_type(s)), index);
@@ -10849,6 +10856,13 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
 				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_packed);
 				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_packed);
 				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union);
 				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union);
 				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align);
 				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align);
+
+				if (t->Struct.is_soa) {
+					irValue *soa_type = ir_type_info(proc, t->Struct.soa_elem);
+					irValue *soa_len = ir_const_int(t->Struct.soa_count);
+					ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 8), soa_type);
+					ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 9), soa_len);
+				}
 			}
 			}
 
 
 			isize count = t->Struct.fields.count;
 			isize count = t->Struct.fields.count;

+ 17 - 0
src/types.cpp

@@ -1133,6 +1133,10 @@ bool is_type_union(Type *t) {
 	t = base_type(t);
 	t = base_type(t);
 	return t->kind == Type_Union;
 	return t->kind == Type_Union;
 }
 }
+bool is_type_soa_struct(Type *t) {
+	t = base_type(t);
+	return t->kind == Type_Struct && t->Struct.is_soa;
+}
 
 
 bool is_type_raw_union(Type *t) {
 bool is_type_raw_union(Type *t) {
 	t = base_type(t);
 	t = base_type(t);
@@ -2194,6 +2198,19 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
 				sel.index.count = prev_count;
 				sel.index.count = prev_count;
 			}
 			}
 		}
 		}
+
+		bool is_soa = type->Struct.is_soa;
+		bool is_soa_of_array = is_soa && is_type_array(type->Struct.soa_elem);
+
+		if (is_soa_of_array) {
+			String mapped_field_name = {};
+			     if (field_name == "r") mapped_field_name = str_lit("x");
+			else if (field_name == "g") mapped_field_name = str_lit("y");
+			else if (field_name == "b") mapped_field_name = str_lit("z");
+			else if (field_name == "a") mapped_field_name = str_lit("w");
+			return lookup_field_with_selection(type, mapped_field_name, is_type, sel, allow_blank_ident);
+		}
+
 	} else if (type->kind == Type_BitField) {
 	} else if (type->kind == Type_BitField) {
 		for_array(i, type->BitField.fields) {
 		for_array(i, type->BitField.fields) {
 			Entity *f = type->BitField.fields[i];
 			Entity *f = type->BitField.fields[i];