diff options
Diffstat (limited to 'src/check_builtin.cpp')
| -rw-r--r-- | src/check_builtin.cpp | 194 |
1 files changed, 188 insertions, 6 deletions
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index a07c1f267..2373317c3 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -25,6 +25,7 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end - is_type_simple_compare, is_type_dereferenceable, is_type_valid_for_keys, + is_type_valid_for_matrix_elems, is_type_named, is_type_pointer, @@ -40,6 +41,7 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end - is_type_proc, is_type_bit_set, is_type_simd_vector, + is_type_matrix, is_type_polymorphic_record_specialized, is_type_polymorphic_record_unspecialized, @@ -1266,7 +1268,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 case BuiltinProc_conj: { // conj :: proc(x: type) -> type Operand *x = operand; - if (is_type_complex(x->type)) { + Type *t = x->type; + Type *elem = core_array_type(t); + + if (is_type_complex(t)) { if (x->mode == Addressing_Constant) { ExactValue v = exact_value_to_complex(x->value); f64 r = v.value_complex->real; @@ -1276,7 +1281,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } else { x->mode = Addressing_Value; } - } else if (is_type_quaternion(x->type)) { + } else if (is_type_quaternion(t)) { if (x->mode == Addressing_Constant) { ExactValue v = exact_value_to_quaternion(x->value); f64 r = +v.value_quaternion->real; @@ -1288,7 +1293,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } else { x->mode = Addressing_Value; } - } else { + } else if (is_type_array_like(t) && (is_type_complex(elem) || is_type_quaternion(elem))) { + x->mode = Addressing_Value; + } else if (is_type_matrix(t) && (is_type_complex(elem) || is_type_quaternion(elem))) { + x->mode = Addressing_Value; + }else { gbString s = type_to_string(x->type); error(call, "Expected a complex or quaternion, got '%s'", s); gb_string_free(s); @@ -1966,13 +1975,13 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return false; } if (!is_operand_value(x)) { - error(call, "'soa_unzip' expects an #soa slice"); + error(call, "'%.*s' expects an #soa slice", LIT(builtin_name)); 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); + error(call, "'%.*s' expects an #soa slice, got %s", LIT(builtin_name), s); gb_string_free(s); return false; } @@ -1987,7 +1996,180 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->mode = Addressing_Value; break; } - + + case BuiltinProc_transpose: { + Operand x = {}; + check_expr(c, &x, ce->args[0]); + if (x.mode == Addressing_Invalid) { + return false; + } + if (!is_operand_value(x)) { + error(call, "'%.*s' expects a matrix or array", LIT(builtin_name)); + return false; + } + Type *t = base_type(x.type); + if (!is_type_matrix(t) && !is_type_array(t)) { + gbString s = type_to_string(x.type); + error(call, "'%.*s' expects a matrix or array, got %s", LIT(builtin_name), s); + gb_string_free(s); + return false; + } + + operand->mode = Addressing_Value; + if (is_type_array(t)) { + // Do nothing + operand->type = x.type; + } else { + GB_ASSERT(t->kind == Type_Matrix); + operand->type = alloc_type_matrix(t->Matrix.elem, t->Matrix.column_count, t->Matrix.row_count); + } + operand->type = check_matrix_type_hint(operand->type, type_hint); + break; + } + + case BuiltinProc_outer_product: { + Operand x = {}; + Operand y = {}; + check_expr(c, &x, ce->args[0]); + if (x.mode == Addressing_Invalid) { + return false; + } + check_expr(c, &y, ce->args[1]); + if (y.mode == Addressing_Invalid) { + return false; + } + if (!is_operand_value(x) || !is_operand_value(y)) { + error(call, "'%.*s' expects only arrays", LIT(builtin_name)); + return false; + } + + if (!is_type_array(x.type) && !is_type_array(y.type)) { + gbString s1 = type_to_string(x.type); + gbString s2 = type_to_string(y.type); + error(call, "'%.*s' expects only arrays, got %s and %s", LIT(builtin_name), s1, s2); + gb_string_free(s2); + gb_string_free(s1); + return false; + } + + Type *xt = base_type(x.type); + Type *yt = base_type(y.type); + GB_ASSERT(xt->kind == Type_Array); + GB_ASSERT(yt->kind == Type_Array); + if (!are_types_identical(xt->Array.elem, yt->Array.elem)) { + gbString s1 = type_to_string(xt->Array.elem); + gbString s2 = type_to_string(yt->Array.elem); + error(call, "'%.*s' mismatched element types, got %s vs %s", LIT(builtin_name), s1, s2); + gb_string_free(s2); + gb_string_free(s1); + return false; + } + + Type *elem = xt->Array.elem; + + if (!is_type_valid_for_matrix_elems(elem)) { + gbString s = type_to_string(elem); + error(call, "Matrix elements types are limited to integers, floats, and complex, got %s", s); + gb_string_free(s); + } + + if (xt->Array.count == 0 || yt->Array.count == 0) { + gbString s1 = type_to_string(x.type); + gbString s2 = type_to_string(y.type); + error(call, "'%.*s' expects only arrays of non-zero length, got %s and %s", LIT(builtin_name), s1, s2); + gb_string_free(s2); + gb_string_free(s1); + return false; + } + + i64 max_count = xt->Array.count*yt->Array.count; + if (max_count > MATRIX_ELEMENT_COUNT_MAX) { + error(call, "Product of the array lengths exceed the maximum matrix element count, got %d, expected a maximum of %d", cast(int)max_count, MATRIX_ELEMENT_COUNT_MAX); + return false; + } + + operand->mode = Addressing_Value; + operand->type = alloc_type_matrix(elem, xt->Array.count, yt->Array.count); + operand->type = check_matrix_type_hint(operand->type, type_hint); + break; + } + + case BuiltinProc_hadamard_product: { + Operand x = {}; + Operand y = {}; + check_expr(c, &x, ce->args[0]); + if (x.mode == Addressing_Invalid) { + return false; + } + check_expr(c, &y, ce->args[1]); + if (y.mode == Addressing_Invalid) { + return false; + } + if (!is_operand_value(x) || !is_operand_value(y)) { + error(call, "'%.*s' expects a matrix or array types", LIT(builtin_name)); + return false; + } + if (!is_type_matrix(x.type) && !is_type_array(y.type)) { + gbString s1 = type_to_string(x.type); + gbString s2 = type_to_string(y.type); + error(call, "'%.*s' expects matrix or array values, got %s and %s", LIT(builtin_name), s1, s2); + gb_string_free(s2); + gb_string_free(s1); + return false; + } + + if (!are_types_identical(x.type, y.type)) { + gbString s1 = type_to_string(x.type); + gbString s2 = type_to_string(y.type); + error(call, "'%.*s' values of the same type, got %s and %s", LIT(builtin_name), s1, s2); + gb_string_free(s2); + gb_string_free(s1); + return false; + } + + Type *elem = core_array_type(x.type); + if (!is_type_valid_for_matrix_elems(elem)) { + gbString s = type_to_string(elem); + error(call, "'%.*s' expects elements to be types are limited to integers, floats, and complex, got %s", LIT(builtin_name), s); + gb_string_free(s); + } + + operand->mode = Addressing_Value; + operand->type = x.type; + operand->type = check_matrix_type_hint(operand->type, type_hint); + break; + } + + case BuiltinProc_matrix_flatten: { + Operand x = {}; + check_expr(c, &x, ce->args[0]); + if (x.mode == Addressing_Invalid) { + return false; + } + if (!is_operand_value(x)) { + error(call, "'%.*s' expects a matrix or array", LIT(builtin_name)); + return false; + } + Type *t = base_type(x.type); + if (!is_type_matrix(t) && !is_type_array(t)) { + gbString s = type_to_string(x.type); + error(call, "'%.*s' expects a matrix or array, got %s", LIT(builtin_name), s); + gb_string_free(s); + return false; + } + + operand->mode = Addressing_Value; + if (is_type_array(t)) { + // Do nothing + operand->type = x.type; + } else { + GB_ASSERT(t->kind == Type_Matrix); + operand->type = alloc_type_array(t->Matrix.elem, t->Matrix.row_count*t->Matrix.column_count); + } + operand->type = check_matrix_type_hint(operand->type, type_hint); + break; + } + case BuiltinProc_simd_vector: { Operand x = {}; Operand y = {}; |