2
0
Эх сурвалжийг харах

`intrinsics.vector` type (Experimental)

gingerBill 6 жил өмнө
parent
commit
4c51384ad6

+ 24 - 0
core/fmt/fmt.odin

@@ -1008,6 +1008,20 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
 			fmt_arg(fi, any{rawptr(data), info.elem.id}, verb);
 		}
 
+	case runtime.Type_Info_Simd_Vector:
+		if info.is_x86_mmx {
+			strings.write_string(fi.buf, "intrinsics.x86_mmx<>");
+		}
+		strings.write_byte(fi.buf, '<');
+		defer strings.write_byte(fi.buf, '>');
+		for i in 0..info.count-1 {
+			if i > 0 do strings.write_string(fi.buf, ", ");
+
+			data := uintptr(v.data) + uintptr(i*info.elem_size);
+			fmt_arg(fi, any{rawptr(data), info.elem.id}, verb);
+		}
+
+
 	case runtime.Type_Info_Slice:
 		strings.write_byte(fi.buf, '[');
 		defer strings.write_byte(fi.buf, ']');
@@ -1448,5 +1462,15 @@ write_type :: proc(buf: ^strings.Builder, ti: ^runtime.Type_Info) {
 		write_string(buf, "opaque ");
 		write_type(buf, info.elem);
 
+	case runtime.Type_Info_Simd_Vector:
+		if info.is_x86_mmx {
+			write_string(buf, "intrinsics.x86_mmx");
+		} else {
+			write_string(buf, "intrinsics.vector(");
+			write_i64(buf, i64(info.count));
+			write_string(buf, ", ");
+			write_type(buf, info.elem);
+			write_byte(buf, ')');
+		}
 	}
 }

+ 7 - 1
core/runtime/core.odin

@@ -112,9 +112,14 @@ Type_Info_Bit_Set :: struct {
 	lower:      i64,
 	upper:      i64,
 };
-
 Type_Info_Opaque :: struct {
 	elem: ^Type_Info,
+};
+Type_Info_Simd_Vector :: struct {
+	elem:       ^Type_Info,
+	elem_size:  int,
+	count:      int,
+	is_x86_mmx: bool,
 }
 
 Type_Info :: struct {
@@ -145,6 +150,7 @@ Type_Info :: struct {
 		Type_Info_Bit_Field,
 		Type_Info_Bit_Set,
 		Type_Info_Opaque,
+		Type_Info_Simd_Vector,
 	},
 }
 

+ 5 - 0
core/types/types.odin

@@ -267,3 +267,8 @@ is_opaque :: proc(info: ^rt.Type_Info) -> bool {
 	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Opaque);
 	return ok;
 }
+is_simd_vector :: proc(info: ^rt.Type_Info) -> bool {
+	if info == nil do return false;
+	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector);
+	return ok;
+}

+ 54 - 0
src/check_expr.cpp

@@ -4072,6 +4072,46 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		break;
 	}
 
+	case BuiltinProc_vector: {
+		Operand x = {};
+		Operand y = {};
+		x = *operand;
+		if (!is_type_integer(x.type) || x.mode != Addressing_Constant) {
+			error(call, "Expected a constant integer for 'intrinsics.vector'");
+			operand->mode = Addressing_Type;
+			operand->type = t_invalid;
+			return false;
+		}
+		if (x.value.value_integer.neg) {
+			error(call, "Negative vector 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.vector'");
+			operand->mode = Addressing_Type;
+			operand->type = t_invalid;
+			return false;
+		}
+		Type *elem = y.type;
+		if (!is_type_valid_vector_elem(elem)) {
+			gbString str = type_to_string(elem);
+			error(call, "Invalid element type for 'intrinsics.vector', expected an integer or float with no specific endianness, got '%s'", str);
+			gb_string_free(str);
+			operand->mode = Addressing_Type;
+			operand->type = t_invalid;
+			return false;
+		}
+
+		operand->mode = Addressing_Type;
+		operand->type = alloc_type_simd_vector(count, elem);
+		break;
+	}
+
 	case BuiltinProc_atomic_fence:
 	case BuiltinProc_atomic_fence_acq:
 	case BuiltinProc_atomic_fence_rel:
@@ -5902,6 +5942,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 		case Type_Slice:
 		case Type_Array:
 		case Type_DynamicArray:
+		case Type_SimdVector:
 		{
 			Type *elem_type = nullptr;
 			String context_name = {};
@@ -5922,6 +5963,10 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 
 				add_package_dependency(c, "runtime", "__dynamic_array_reserve");
 				add_package_dependency(c, "runtime", "__dynamic_array_append");
+			} else if (t->kind == Type_SimdVector) {
+				elem_type = t->SimdVector.elem;
+				context_name = str_lit("simd vector literal");
+				max_type_count = t->SimdVector.count;
 			} else {
 				GB_PANIC("unreachable");
 			}
@@ -5972,6 +6017,15 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
 					error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max);
 				}
 			}
+
+			if (t->kind == Type_SimdVector) {
+				if (!is_constant) {
+					error(node, "Expected all constant elements for a simd vector");
+				}
+				if (t->SimdVector.is_x86_mmx) {
+					error(node, "Compound literals are not allowed with intrinsics.x86_mmx");
+				}
+			}
 			break;
 		}
 

+ 19 - 0
src/checker.cpp

@@ -712,6 +712,15 @@ void init_universal(void) {
 		}
 	}
 
+	// TODO(bill): Set the correct arch for this
+	if (bc->metrics.arch == TargetArch_amd64 || bc->metrics.arch == TargetArch_386) {
+		t_vector_x86_mmx = alloc_type(Type_SimdVector);
+		t_vector_x86_mmx->SimdVector.is_x86_mmx = true;
+
+		Entity *entity = alloc_entity(Entity_TypeName, nullptr, make_token_ident(str_lit("x86_mmx")), t_vector_x86_mmx);
+		add_global_entity(entity, intrinsics_pkg->scope);
+	}
+
 
 	t_u8_ptr       = alloc_type_pointer(t_u8);
 	t_int_ptr      = alloc_type_pointer(t_int);
@@ -1248,6 +1257,10 @@ void add_type_info_type(CheckerContext *c, Type *t) {
 		add_type_info_type(c, bt->Proc.results);
 		break;
 
+	case Type_SimdVector:
+		add_type_info_type(c, bt->SimdVector.elem);
+		break;
+
 	default:
 		GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
 		break;
@@ -1419,6 +1432,10 @@ void add_min_dep_type_info(Checker *c, Type *t) {
 		add_min_dep_type_info(c, bt->Proc.results);
 		break;
 
+	case Type_SimdVector:
+		add_min_dep_type_info(c, bt->SimdVector.elem);
+		break;
+
 	default:
 		GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind]));
 		break;
@@ -1795,6 +1812,7 @@ void init_core_type_info(Checker *c) {
 	t_type_info_bit_field     = find_core_type(c, str_lit("Type_Info_Bit_Field"));
 	t_type_info_bit_set       = find_core_type(c, str_lit("Type_Info_Bit_Set"));
 	t_type_info_opaque        = find_core_type(c, str_lit("Type_Info_Opaque"));
+	t_type_info_simd_vector   = find_core_type(c, str_lit("Type_Info_Simd_Vector"));
 
 	t_type_info_named_ptr         = alloc_type_pointer(t_type_info_named);
 	t_type_info_integer_ptr       = alloc_type_pointer(t_type_info_integer);
@@ -1818,6 +1836,7 @@ void init_core_type_info(Checker *c) {
 	t_type_info_bit_field_ptr     = alloc_type_pointer(t_type_info_bit_field);
 	t_type_info_bit_set_ptr       = alloc_type_pointer(t_type_info_bit_set);
 	t_type_info_opaque_ptr        = alloc_type_pointer(t_type_info_opaque);
+	t_type_info_simd_vector_ptr   = alloc_type_pointer(t_type_info_simd_vector);
 }
 
 void init_mem_allocator(Checker *c) {

+ 5 - 0
src/checker.hpp

@@ -89,6 +89,8 @@ enum BuiltinProcId {
 	BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
 
 	// "Intrinsics"
+	BuiltinProc_vector,
+
 	BuiltinProc_atomic_fence,
 	BuiltinProc_atomic_fence_acq,
 	BuiltinProc_atomic_fence_rel,
@@ -194,6 +196,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 
 
 	// "Intrinsics"
+	{STR_LIT("vector"), 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},
 	{STR_LIT("atomic_fence_rel"),    0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},

+ 13 - 0
src/ir.cpp

@@ -7268,6 +7268,7 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 		case Type_Array:  et = bt->Array.elem;  break;
 		case Type_Slice:  et = bt->Slice.elem;  break;
 		case Type_BitSet: et = bt->BitSet.elem; break;
+		case Type_SimdVector: et = bt->SimdVector.elem; break;
 		}
 
 		String proc_name = {};
@@ -9995,6 +9996,18 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
 			tag = ir_emit_conv(proc, variant_ptr, t_type_info_opaque_ptr);
 			ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->Opaque.elem));
 			break;
+
+		case Type_SimdVector:
+			ir_emit_comment(proc, str_lit("Type_SimdVector"));
+			tag = ir_emit_conv(proc, variant_ptr, t_type_info_simd_vector_ptr);
+			if (t->SimdVector.is_x86_mmx) {
+				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), v_true);
+			} else {
+				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->SimdVector.elem));
+				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), ir_const_int(type_size_of(t->SimdVector.elem)));
+				ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), ir_const_int(t->SimdVector.count));
+			}
+			break;
 		}
 
 

+ 35 - 0
src/ir_print.cpp

@@ -574,6 +574,16 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
 	case Type_Opaque:
 		ir_print_type(f, m, strip_opaque_type(t));
 		return;
+
+	case Type_SimdVector:
+		if (t->SimdVector.is_x86_mmx) {
+			ir_write_str_lit(f, "x86_mmx");
+		} else {
+			ir_fprintf(f, "<%lld x ", t->SimdVector.count);;
+			ir_print_type(f, m, t->SimdVector.elem);
+			ir_write_byte(f, '>');
+		}
+		return;
 	}
 }
 
@@ -802,6 +812,31 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
 			}
 
 			ir_write_byte(f, ']');
+		} else if (is_type_simd_vector(type)) {
+			ast_node(cl, CompoundLit, value.value_compound);
+
+			Type *elem_type = type->SimdVector.elem;
+			isize elem_count = cl->elems.count;
+			if (elem_count == 0) {
+				ir_write_str_lit(f, "zeroinitializer");
+				break;
+			}
+			GB_ASSERT_MSG(elem_count == type->SimdVector.count, "%td != %td", elem_count, type->SimdVector.count);
+
+			ir_write_byte(f, '<');
+
+			for (isize i = 0; i < elem_count; i++) {
+				if (i > 0) ir_write_str_lit(f, ", ");
+				TypeAndValue tav = cl->elems[i]->tav;
+				GB_ASSERT(tav.mode != Addressing_Invalid);
+				ir_print_compound_element(f, m, tav.value, elem_type);
+			}
+			for (isize i = elem_count; i < type->SimdVector.count; i++) {
+				if (i >= elem_count) ir_write_str_lit(f, ", ");
+				ir_print_compound_element(f, m, empty_exact_value, elem_type);
+			}
+
+			ir_write_byte(f, '>');
 		} else if (is_type_struct(type)) {
 			gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
 			defer (gb_temp_arena_memory_end(tmp));

+ 84 - 60
src/types.cpp

@@ -215,6 +215,12 @@ struct TypeUnion {
 		i64   lower;                                      \
 		i64   upper;                                      \
 	})                                                    \
+	TYPE_KIND(SimdVector, struct {                        \
+		i64   count;                                      \
+		Type *elem;                                       \
+		bool is_x86_mmx;                                  \
+	})                                                    \
+
 
 
 
@@ -460,13 +466,13 @@ gb_global Type *t_type_info_map               = nullptr;
 gb_global Type *t_type_info_bit_field         = nullptr;
 gb_global Type *t_type_info_bit_set           = nullptr;
 gb_global Type *t_type_info_opaque            = nullptr;
+gb_global Type *t_type_info_simd_vector       = nullptr;
 
 gb_global Type *t_type_info_named_ptr         = nullptr;
 gb_global Type *t_type_info_integer_ptr       = nullptr;
 gb_global Type *t_type_info_rune_ptr          = nullptr;
 gb_global Type *t_type_info_float_ptr         = nullptr;
 gb_global Type *t_type_info_complex_ptr       = nullptr;
-gb_global Type *t_type_info_quaternion_ptr    = nullptr;
 gb_global Type *t_type_info_any_ptr           = nullptr;
 gb_global Type *t_type_info_typeid_ptr        = nullptr;
 gb_global Type *t_type_info_string_ptr        = nullptr;
@@ -484,6 +490,7 @@ gb_global Type *t_type_info_map_ptr           = nullptr;
 gb_global Type *t_type_info_bit_field_ptr     = nullptr;
 gb_global Type *t_type_info_bit_set_ptr       = nullptr;
 gb_global Type *t_type_info_opaque_ptr        = nullptr;
+gb_global Type *t_type_info_simd_vector_ptr   = nullptr;
 
 gb_global Type *t_allocator                   = nullptr;
 gb_global Type *t_allocator_ptr               = nullptr;
@@ -496,6 +503,8 @@ gb_global Type *t_source_code_location_ptr    = nullptr;
 gb_global Type *t_map_key                     = nullptr;
 gb_global Type *t_map_header                  = nullptr;
 
+gb_global Type *t_vector_x86_mmx              = nullptr;
+
 
 
 i64      type_size_of               (Type *t);
@@ -722,6 +731,13 @@ Type *alloc_type_bit_set() {
 
 
 
+Type *alloc_type_simd_vector(i64 count, Type *elem) {
+	Type *t = alloc_type(Type_SimdVector);
+	t->SimdVector.count = count;
+	t->SimdVector.elem = elem;
+	return t;
+}
+
 
 
 ////////////////////////////////////////////////////////////////
@@ -971,6 +987,11 @@ bool is_type_generic(Type *t) {
 	return t->kind == Type_Generic;
 }
 
+bool is_type_simd_vector(Type *t) {
+	t = base_type(t);
+	return t->kind == Type_SimdVector;
+}
+
 
 Type *core_array_type(Type *t) {
 	for (;;) {
@@ -1193,6 +1214,25 @@ Type *bit_set_to_int(Type *t) {
 	return nullptr;
 }
 
+bool is_type_valid_vector_elem(Type *t) {
+	t = base_type(t);
+	if (t->kind == Type_Basic) {
+		if (t->Basic.flags & BasicFlag_EndianLittle) {
+			return false;
+		}
+		if (t->Basic.flags & BasicFlag_EndianBig) {
+			return false;
+		}
+		if (is_type_integer(t)) {
+			return true;
+		}
+		if (is_type_float(t)) {
+			return true;
+		}
+	}
+	return false;
+}
+
 
 bool is_type_indexable(Type *t) {
 	Type *bt = base_type(t);
@@ -1637,6 +1677,18 @@ bool are_types_identical(Type *x, Type *y) {
 			       are_types_identical(x->Map.value, y->Map.value);
 		}
 		break;
+
+	case Type_SimdVector:
+		if (y->kind == Type_SimdVector) {
+			if (x->SimdVector.is_x86_mmx == y->SimdVector.is_x86_mmx) {
+				if (x->SimdVector.is_x86_mmx) {
+					return true;
+				} else if (x->SimdVector.count == y->SimdVector.count) {
+					return are_types_identical(x->SimdVector.elem, y->SimdVector.elem);
+				}
+			}
+		}
+		break;
 	}
 
 	return false;
@@ -1681,65 +1733,6 @@ Type *default_type(Type *type) {
 	return type;
 }
 
-/*
-// NOTE(bill): Valid Compile time execution #run type
-bool is_type_cte_safe(Type *type) {
-	type = default_type(base_type(type));
-	switch (type->kind) {
-	case Type_Basic:
-		switch (type->Basic.kind) {
-		case Basic_rawptr:
-		case Basic_any:
-			return false;
-		}
-		return true;
-
-	case Type_Pointer:
-		return false;
-
-	case Type_Array:
-		return is_type_cte_safe(type->Array.elem);
-
-	case Type_DynamicArray:
-		return false;
-	case Type_Map:
-		return false;
-
-	case Type_Slice:
-		return false;
-
-	case Type_Struct: {
-		if (type->Struct.is_raw_union) {
-			return false;
-		}
-		for_array(i, type->Struct.fields) {
-			Entity *v = type->Struct.fields[i];
-			if (!is_type_cte_safe(v->type)) {
-				return false;
-			}
-		}
-		return true;
-	}
-
-	case Type_Tuple: {
-		for_array(i, type->Tuple.variables) {
-			Entity *v = type->Tuple.variables[i];
-			if (!is_type_cte_safe(v->type)) {
-				return false;
-			}
-		}
-		return true;
-	}
-
-	case Type_Proc:
-		// TODO(bill): How should I handle procedures in the CTE stage?
-		// return type->Proc.calling_convention == ProcCC_Odin;
-		return false;
-	}
-
-	return false;
-}
- */
 i64 union_variant_index(Type *u, Type *v) {
 	u = base_type(u);
 	GB_ASSERT(u->kind == Type_Union);
@@ -2389,7 +2382,18 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
 		if (bits <= 32) return 4;
 		if (bits <= 64) return 8;
 		return 8; // NOTE(bill): Could be an invalid range so limit it for now
+	}
 
+	case Type_SimdVector: {
+		if (t->SimdVector.is_x86_mmx) {
+			return 8;
+		}
+		// align of
+		i64 count = t->SimdVector.count;
+		Type *elem = t->SimdVector.elem;
+		i64 size = count * type_size_of_internal(elem, path);
+		// IMPORTANT TODO(bill): Figure out the alignment of vector types
+		return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align);
 	}
 	}
 
@@ -2622,6 +2626,15 @@ i64 type_size_of_internal(Type *t, TypePath *path) {
 		if (bits <= 64) return 8;
 		return 8; // NOTE(bill): Could be an invalid range so limit it for now
 	}
+
+	case Type_SimdVector: {
+		if (t->SimdVector.is_x86_mmx) {
+			return 8;
+		}
+		i64 count = t->SimdVector.count;
+		Type *elem = t->SimdVector.elem;
+		return count * type_size_of_internal(elem, path);
+	}
 	}
 
 	// Catch all
@@ -2950,6 +2963,17 @@ gbString write_type_to_string(gbString str, Type *type) {
 		}
 		str = gb_string_appendc(str, "]");
 		break;
+
+	case Type_SimdVector:
+		if (type->SimdVector.is_x86_mmx) {
+			return "intrinsics.x86_mmx";
+		} else {
+			str = gb_string_appendc(str, "intrinsics.vector(");
+			str = gb_string_append_fmt(str, "%d, ", cast(int)type->SimdVector.count);
+			str = write_type_to_string(str, type->SimdVector.elem);
+			str = gb_string_appendc(str, ")");
+		}
+		break;
 	}
 
 	return str;