diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index c4a535d77..0df06c0ec 100644 --- a/core/fmt/fmt.odin +++ b/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, ')'); + } } } diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 9307b5589..38dd8f225 100644 --- a/core/runtime/core.odin +++ b/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, }, } diff --git a/core/types/types.odin b/core/types/types.odin index 485530fea..dc4db549f 100644 --- a/core/types/types.odin +++ b/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; +} diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 79f980a79..75c16b705 100644 --- a/src/check_expr.cpp +++ b/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; } diff --git a/src/checker.cpp b/src/checker.cpp index 9cac82911..7900555a5 100644 --- a/src/checker.cpp +++ b/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) { diff --git a/src/checker.hpp b/src/checker.hpp index abc349129..de491671e 100644 --- a/src/checker.hpp +++ b/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}, diff --git a/src/ir.cpp b/src/ir.cpp index cd7e8d99a..4df6665f7 100644 --- a/src/ir.cpp +++ b/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; } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index c6e717f74..0cc9f52e3 100644 --- a/src/ir_print.cpp +++ b/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)); diff --git a/src/types.cpp b/src/types.cpp index 859805f29..6dcbf029f 100644 --- a/src/types.cpp +++ b/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;