diff --git a/lib/std/math.c3 b/lib/std/math.c3 index 355c14cae..856f8b2f9 100644 --- a/lib/std/math.c3 +++ b/lib/std/math.c3 @@ -272,6 +272,10 @@ macro float float.round(float x) = $$round(x); macro float float.roundeven(float x) = $$roundeven(x); macro float float.trunc(float x) = $$trunc(x); +macro float float[<*>].sum(float[<*>] x, float start = 0.0) = $$reduce_fadd(x, start); +macro float float[<*>].product(float[<*>] x, float start = 1.0) = $$reduce_fmul(x, start); +macro float float[<*>].max(float[<*>] x) = $$reduce_max(x); +macro float float[<*>].min(float[<*>] x) = $$reduce_min(x); macro float[<*>] float[<*>].ceil(float[<*>] x) = $$ceil(x); macro float[<*>] float[<*>].clamp(float[<*>] x, float[<*>] lower, float[<*>] upper) = $$max(lower, $$min(x, upper)); macro float[<*>] float[<*>].copysign(float[<*>] mag, float[<*>] sgn) = $$copysign(mag, sgn); @@ -297,6 +301,10 @@ macro double double.round(double x) = $$round(x); macro double double.roundeven(double x) = $$roundeven(x); macro double double.trunc(double x) = $$trunc(x); +macro double double[<*>].sum(double[<*>] x, double start = 0.0) = $$reduce_add(x, start); +macro double double[<*>].product(double[<*>] x, double start = 1.0) = $$reduce_mul(x, start); +macro double double[<*>].max(double[<*>] x) = $$reduce_fmax(x); +macro double double[<*>].min(double[<*>] x) = $$reduce_fmin(x); macro double[<*>] double[<*>].ceil(double[<*>] x) = $$ceil(x); macro double[<*>] double[<*>].clamp(double[<*>] x, double[<*>] lower, double[<*>] upper) = $$max(lower, $$min(x, upper)); macro double[<*>] double[<*>].copysign(double[<*>] mag, double[<*>] sgn) = $$copysign(mag, sgn); @@ -309,6 +317,102 @@ macro double[<*>] double[<*>].round(double[<*>] x) = $$round(x); macro double[<*>] double[<*>].roundeven(double[<*>] x) = $$roundeven(x); macro double[<*>] double[<*>].trunc(double[<*>] x) = $$trunc(x); +macro ichar ichar[<*>].sum(ichar[<*>] x) = $$reduce_add(x); +macro ichar ichar[<*>].product(ichar[<*>] x) = $$reduce_mul(x); +macro ichar ichar[<*>].and(ichar[<*>] x) = $$reduce_and(x); +macro ichar ichar[<*>].or(ichar[<*>] x) = $$reduce_or(x); +macro ichar ichar[<*>].xor(ichar[<*>] x) = $$reduce_xor(x); +macro ichar ichar[<*>].max(ichar[<*>] x) = $$reduce_max(x); +macro ichar ichar[<*>].min(ichar[<*>] x) = $$reduce_min(x); + +macro short short[<*>].sum(short[<*>] x) = $$reduce_add(x); +macro short short[<*>].product(short[<*>] x) = $$reduce_mul(x); +macro short short[<*>].and(short[<*>] x) = $$reduce_and(x); +macro short short[<*>].or(short[<*>] x) = $$reduce_or(x); +macro short short[<*>].xor(short[<*>] x) = $$reduce_xor(x); +macro short short[<*>].max(short[<*>] x) = $$reduce_max(x); +macro short short[<*>].min(short[<*>] x) = $$reduce_min(x); + +macro bool[<*>] int[<*>].comp_lt(int[<*>] x, int[<*>] y) = $$veccomplt(x, y); +macro bool[<*>] int[<*>].comp_le(int[<*>] x, int[<*>] y) = $$veccomple(x, y); +macro bool[<*>] int[<*>].comp_eq(int[<*>] x, int[<*>] y) = $$veccompeq(x, y); +macro bool[<*>] int[<*>].comp_gt(int[<*>] x, int[<*>] y) = $$veccompgt(x, y); +macro bool[<*>] int[<*>].comp_ge(int[<*>] x, int[<*>] y) = $$veccompge(x, y); +macro bool[<*>] int[<*>].comp_ne(int[<*>] x, int[<*>] y) = $$veccompne(x, y); + +macro int int[<*>].sum(int[<*>] x) = $$reduce_add(x); +macro int int[<*>].product(int[<*>] x) = $$reduce_mul(x); +macro int int[<*>].and(int[<*>] x) = $$reduce_and(x); +macro int int[<*>].or(int[<*>] x) = $$reduce_or(x); +macro int int[<*>].xor(int[<*>] x) = $$reduce_xor(x); +macro int int[<*>].max(int[<*>] x) = $$reduce_max(x); +macro int int[<*>].min(int[<*>] x) = $$reduce_min(x); + +macro long long[<*>].sum(long[<*>] x) = $$reduce_add(x); +macro long long[<*>].product(long[<*>] x) = $$reduce_mul(x); +macro long long[<*>].and(long[<*>] x) = $$reduce_and(x); +macro long long[<*>].or(long[<*>] x) = $$reduce_or(x); +macro long long[<*>].xor(long[<*>] x) = $$reduce_xor(x); +macro long long[<*>].max(long[<*>] x) = $$reduce_max(x); +macro long long[<*>].min(long[<*>] x) = $$reduce_min(x); + +macro int128 int128[<*>].sum(int128[<*>] x) = $$reduce_add(x); +macro int128 int128[<*>].product(int128[<*>] x) = $$reduce_mul(x); +macro int128 int128[<*>].and(int128[<*>] x) = $$reduce_and(x); +macro int128 int128[<*>].or(int128[<*>] x) = $$reduce_or(x); +macro int128 int128[<*>].xor(int128[<*>] x) = $$reduce_xor(x); +macro int128 int128[<*>].max(int128[<*>] x) = $$reduce_max(x); +macro int128 int128[<*>].min(int128[<*>] x) = $$reduce_min(x); + +macro bool bool[<*>].sum(bool[<*>] x) = $$reduce_add(x); +macro bool bool[<*>].product(bool[<*>] x) = $$reduce_mul(x); +macro bool bool[<*>].and(bool[<*>] x) = $$reduce_and(x); +macro bool bool[<*>].or(bool[<*>] x) = $$reduce_or(x); +macro bool bool[<*>].xor(bool[<*>] x) = $$reduce_xor(x); +macro bool bool[<*>].max(bool[<*>] x) = $$reduce_max(x); +macro bool bool[<*>].min(bool[<*>] x) = $$reduce_min(x); + +macro char char[<*>].sum(char[<*>] x) = $$reduce_add(x); +macro char char[<*>].product(char[<*>] x) = $$reduce_mul(x); +macro char char[<*>].and(char[<*>] x) = $$reduce_and(x); +macro char char[<*>].or(char[<*>] x) = $$reduce_or(x); +macro char char[<*>].xor(char[<*>] x) = $$reduce_xor(x); +macro char char[<*>].max(char[<*>] x) = $$reduce_max(x); +macro char char[<*>].min(char[<*>] x) = $$reduce_min(x); + + +macro ushort ushort[<*>].sum(ushort[<*>] x) = $$reduce_add(x); +macro ushort ushort[<*>].product(ushort[<*>] x) = $$reduce_mul(x); +macro ushort ushort[<*>].and(ushort[<*>] x) = $$reduce_and(x); +macro ushort ushort[<*>].or(ushort[<*>] x) = $$reduce_or(x); +macro ushort ushort[<*>].xor(ushort[<*>] x) = $$reduce_xor(x); +macro ushort ushort[<*>].max(ushort[<*>] x) = $$reduce_max(x); +macro ushort ushort[<*>].min(ushort[<*>] x) = $$reduce_min(x); + +macro uint uint[<*>].sum(uint[<*>] x) = $$reduce_add(x); +macro uint uint[<*>].product(uint[<*>] x) = $$reduce_mul(x); +macro uint uint[<*>].and(uint[<*>] x) = $$reduce_and(x); +macro uint uint[<*>].or(uint[<*>] x) = $$reduce_or(x); +macro uint uint[<*>].xor(uint[<*>] x) = $$reduce_xor(x); +macro uint uint[<*>].max(uint[<*>] x) = $$reduce_max(x); +macro uint uint[<*>].min(uint[<*>] x) = $$reduce_min(x); + +macro ulong ulong[<*>].sum(ulong[<*>] x) = $$reduce_add(x); +macro ulong ulong[<*>].product(ulong[<*>] x) = $$reduce_mul(x); +macro ulong ulong[<*>].and(ulong[<*>] x) = $$reduce_and(x); +macro ulong ulong[<*>].or(ulong[<*>] x) = $$reduce_or(x); +macro ulong ulong[<*>].xor(ulong[<*>] x) = $$reduce_xor(x); +macro ulong ulong[<*>].max(ulong[<*>] x) = $$reduce_max(x); +macro ulong ulong[<*>].min(ulong[<*>] x) = $$reduce_min(x); + +macro uint128 uint128[<*>].sum(uint128[<*>] x) = $$reduce_add(x); +macro uint128 uint128[<*>].product(uint128[<*>] x) = $$reduce_mul(x); +macro uint128 uint128[<*>].and(uint128[<*>] x) = $$reduce_and(x); +macro uint128 uint128[<*>].or(uint128[<*>] x) = $$reduce_or(x); +macro uint128 uint128[<*>].xor(uint128[<*>] x) = $$reduce_xor(x); +macro uint128 uint128[<*>].max(uint128[<*>] x) = $$reduce_max(x); +macro uint128 uint128[<*>].min(uint128[<*>] x) = $$reduce_min(x); + /** * @checked x & 1 */ diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index cda4669c3..f22f17baf 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2308,6 +2308,7 @@ bool type_is_user_defined(Type *type); bool type_is_structurally_equivalent(Type *type1, Type *type); bool type_flat_is_floatlike(Type *type); bool type_flat_is_intlike(Type *type); +bool type_flat_is_boolintlike(Type *type); bool type_flat_is_numlike(Type *type); bool type_may_have_sub_elements(Type *type); bool type_may_have_method(Type *type); @@ -2327,6 +2328,7 @@ INLINE bool type_is_substruct(Type *type); INLINE Type *type_flatten_for_bitstruct(Type *type); INLINE const char *type_invalid_storage_type_name(Type *type); INLINE bool type_is_float(Type *type); +INLINE bool type_is_floatlike(Type *type); INLINE bool type_is_optional(Type *type); INLINE bool type_is_optional_type(Type *type); INLINE bool type_is_optional_any(Type *type); @@ -2577,6 +2579,14 @@ INLINE bool type_is_float(Type *type) return kind >= TYPE_FLOAT_FIRST && kind <= TYPE_FLOAT_LAST; } +INLINE bool type_is_floatlike(Type *type) +{ + type = type->canonical; + TypeKind kind = type->type_kind; + if (kind == TYPE_VECTOR && type_is_float(type->array.base)) return true; + return kind >= TYPE_FLOAT_FIRST && kind <= TYPE_FLOAT_LAST; +} + INLINE const char *type_invalid_storage_type_name(Type *type) { switch (type->type_kind) @@ -2638,9 +2648,9 @@ INLINE Type *type_new(TypeKind kind, const char *name) INLINE bool type_convert_will_trunc(Type *destination, Type *source) { - assert(type_is_builtin(destination->canonical->type_kind)); - assert(type_is_builtin(source->canonical->type_kind)); - return (unsigned)destination->canonical->builtin.bitsize < (unsigned)source->canonical->builtin.bitsize; + assert(type_flat_is_vector(destination) || type_is_builtin(destination->canonical->type_kind)); + assert(type_flat_is_vector(destination) || type_is_builtin(source->canonical->type_kind)); + return type_size(destination) < type_size(source); } @@ -2786,6 +2796,17 @@ INLINE bool type_flat_is_vector(Type *type) return type_flatten(type)->type_kind == TYPE_VECTOR; } +INLINE bool type_kind_is_any_vector(TypeKind kind) +{ + return kind == TYPE_VECTOR || kind == TYPE_INFERRED_VECTOR || kind == TYPE_SCALED_VECTOR; +} + +INLINE bool type_flat_is_bool_vector(Type *type) +{ + Type *flat = type_flatten(type); + return flat->type_kind == TYPE_VECTOR && type_flatten(flat->array.base) == type_bool; +} + INLINE bool type_is_union_or_strukt(Type *type) { DECL_TYPE_KIND_REAL(kind, type); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 159ffc85f..03883f854 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -95,6 +95,7 @@ typedef enum CAST_PTRBOOL, CAST_BOOLINT, CAST_BOOLFP, + CAST_BOOLVECINT, CAST_BOOLBOOL, CAST_FPBOOL, CAST_INTBOOL, diff --git a/src/compiler/expr.c b/src/compiler/expr.c index 7d61e90fc..9729a3bb6 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -369,6 +369,7 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_ case CAST_STST: case CAST_VECARR: case CAST_ARRVEC: + case CAST_BOOLVECINT: if (eval_kind != CONSTANT_EVAL_NO_SIDE_EFFECTS) return false; return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind); case CAST_XIPTR: diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 1ea946b06..2d016f044 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -771,15 +771,9 @@ void llvm_set_linkage(GenContext *c, Decl *decl, LLVMValueRef value) LLVMSetLinkage(value, LLVMLinkerPrivateLinkage); break; } - } - - - - - void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value) { value->value = llvm_value; @@ -788,6 +782,14 @@ void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value) value->type = type_bool; } +void llvm_value_set_bool_vector(BEValue *value, LLVMValueRef llvm_value, Type *type) +{ + value->value = llvm_value; + value->alignment = type_abi_alignment(type); + value->kind = BE_BOOLVECTOR; + value->type = type; +} + void llvm_value_set_int(GenContext *c, BEValue *value, Type *type, uint64_t i) { llvm_value_set(value, llvm_const_int(c, type, i), type); diff --git a/src/compiler/llvm_codegen_builtins.c b/src/compiler/llvm_codegen_builtins.c index 3a35feb45..b4f02576b 100644 --- a/src/compiler/llvm_codegen_builtins.c +++ b/src/compiler/llvm_codegen_builtins.c @@ -481,7 +481,7 @@ static void llvm_emit_veccomp(GenContext *c, BEValue *value, Expr *expr, Builtin } else { - bool is_signed = type_is_signed(value->type); + bool is_signed = type_is_signed(args[0]->type); switch (fn) { case BUILTIN_VECCOMPEQ: @@ -508,9 +508,7 @@ static void llvm_emit_veccomp(GenContext *c, BEValue *value, Expr *expr, Builtin UNREACHABLE } } - Type *result_type = type_get_vector_bool(value->type); - res = LLVMBuildSExt(c->builder, res, llvm_get_type(c, result_type), ""); - llvm_value_set(value, res, result_type); + llvm_value_set_bool_vector(value, res, expr->type); return; } diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 56435dd6f..43765cee9 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -1164,6 +1164,15 @@ void llvm_emit_array_to_vector_cast(GenContext *c, BEValue *value, Type *to_type llvm_value_set(value, vector, to_type); } +void llvm_emit_bool_to_intvec_cast(GenContext *c, BEValue *value, Type *to_type, Type *from_type) +{ + llvm_value_rvalue(c, value); + LLVMTypeRef type = llvm_get_type(c, to_type); + LLVMValueRef res = LLVMBuildSExt(c->builder, value->value, type, ""); + llvm_value_set(value, res, to_type); +} + + void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *value, Type *to_type, Type *from_type) { Type *to_type_original = to_type; @@ -1172,6 +1181,9 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu switch (cast_kind) { + case CAST_BOOLVECINT: + llvm_emit_bool_to_intvec_cast(c, value, to_type, from_type); + return; case CAST_ARRVEC: llvm_emit_array_to_vector_cast(c, value, to_type, from_type); return; @@ -1304,7 +1316,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu case CAST_INTBOOL: llvm_value_rvalue(c, value); value->value = LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, from_type), "intbool"); - value->kind = BE_BOOLEAN; + value->kind = type_kind_is_any_vector(value->type->type_kind) ? BE_BOOLVECTOR : BE_BOOLEAN; break; case CAST_FPFP: llvm_value_rvalue(c, value); diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index e04d4c9d9..11eaed70e 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -22,6 +22,7 @@ typedef enum BE_ADDRESS, BE_ADDRESS_FAILABLE, BE_BOOLEAN, + BE_BOOLVECTOR, } BackendValueKind; typedef struct @@ -258,6 +259,7 @@ static inline bool llvm_value_is_bool(BEValue *value) { return value->kind == BE bool llvm_value_is_const(BEValue *value); void llvm_value_rvalue(GenContext *context, BEValue *value); void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value); +void llvm_value_set_bool_vector(BEValue *value, LLVMValueRef llvm_value, Type *type); void llvm_value_set(BEValue *value, LLVMValueRef llvm_value, Type *type); void llvm_value_set_int(GenContext *c, BEValue *value, Type *type, uint64_t i); void llvm_value_set_address(BEValue *value, LLVMValueRef llvm_value, Type *type, AlignSize alignment); diff --git a/src/compiler/llvm_codegen_internal_impl.h b/src/compiler/llvm_codegen_internal_impl.h index 92ff0964c..a38cf3c6f 100644 --- a/src/compiler/llvm_codegen_internal_impl.h +++ b/src/compiler/llvm_codegen_internal_impl.h @@ -102,6 +102,11 @@ INLINE LLVMValueRef llvm_emit_lshr(GenContext *c, LLVMValueRef value, LLVMValueR INLINE LLVMValueRef llvm_emit_trunc_bool(GenContext *c, LLVMValueRef value) { + LLVMTypeRef type = LLVMTypeOf(value); + if (LLVMGetTypeKind(type) == LLVMVectorTypeKind) + { + return LLVMBuildTrunc(c->builder, value, LLVMVectorType(c->bool_type, LLVMGetVectorSize(type)), ""); + } return LLVMBuildTrunc(c->builder, value, c->bool_type, ""); } diff --git a/src/compiler/llvm_codegen_storeload.c b/src/compiler/llvm_codegen_storeload.c index 9ab863b3b..4138c67d9 100644 --- a/src/compiler/llvm_codegen_storeload.c +++ b/src/compiler/llvm_codegen_storeload.c @@ -30,6 +30,10 @@ LLVMValueRef llvm_store_to_ptr_aligned(GenContext *c, LLVMValueRef destination, } switch (value->kind) { + case BE_BOOLVECTOR: + value->value = LLVMBuildSExt(c->builder, value->value, llvm_get_type(c, value->type), ""); + value->kind = BE_VALUE; + return llvm_store_to_ptr_raw_aligned(c, destination, value->value, alignment); case BE_BOOLEAN: value->value = LLVMBuildZExt(c->builder, value->value, c->byte_type, ""); value->kind = BE_VALUE; @@ -85,6 +89,7 @@ LLVMValueRef llvm_load_value(GenContext *c, BEValue *value) llvm_value_fold_optional(c, value); switch (value->kind) { + case BE_BOOLVECTOR: case BE_BOOLEAN: case BE_VALUE: return value->value; @@ -99,6 +104,10 @@ LLVMValueRef llvm_load_value(GenContext *c, BEValue *value) LLVMValueRef llvm_load_value_store(GenContext *c, BEValue *value) { LLVMValueRef val = llvm_load_value(c, value); + if (value->kind == BE_BOOLVECTOR) + { + return LLVMBuildSExt(c->builder, val, llvm_get_type(c, type_get_vector_bool(value->type)), ""); + } if (value->kind != BE_BOOLEAN) return val; return LLVMBuildZExt(c->builder, val, c->byte_type, ""); } diff --git a/src/compiler/llvm_codegen_value.c b/src/compiler/llvm_codegen_value.c index 68e3be25e..9161c280a 100644 --- a/src/compiler/llvm_codegen_value.c +++ b/src/compiler/llvm_codegen_value.c @@ -50,9 +50,14 @@ void llvm_value_rvalue(GenContext *c, BEValue *value) { if (value->type->type_kind == TYPE_BOOL && value->kind != BE_BOOLEAN) { - value->value = LLVMBuildTrunc(c->builder, value->value, c->bool_type, ""); + value->value = llvm_emit_trunc_bool(c, value->value); value->kind = BE_BOOLEAN; } + if (type_flat_is_bool_vector(value->type) && value->kind != BE_BOOLVECTOR) + { + value->value = llvm_emit_trunc_bool(c, value->value); + value->kind = BE_BOOLVECTOR; + } return; } llvm_value_fold_optional(c, value); @@ -67,6 +72,12 @@ void llvm_value_rvalue(GenContext *c, BEValue *value) value->kind = BE_BOOLEAN; return; } + if (type_flat_is_bool_vector(value->type)) + { + value->value = llvm_emit_trunc_bool(c, value->value); + value->kind = BE_BOOLVECTOR; + return; + } value->kind = BE_VALUE; } diff --git a/src/compiler/sema_builtins.c b/src/compiler/sema_builtins.c index 1c293cb62..a86e1ec30 100644 --- a/src/compiler/sema_builtins.c +++ b/src/compiler/sema_builtins.c @@ -14,6 +14,7 @@ typedef enum BA_FLOAT, BA_INTLIKE, BA_NUMLIKE, + BA_BOOLINTVEC, BA_INTVEC, BA_FLOATVEC, BA_VEC, @@ -109,12 +110,21 @@ static bool sema_check_builtin_args(Expr **args, BuiltinArg *arg_type, size_t ar } break; case BA_INTVEC: + if (type->type_kind != TYPE_VECTOR || !type_flat_is_intlike(type->array.base)) { SEMA_ERROR(args[i], "Expected an integer vector."); return false; } break; + case BA_BOOLINTVEC: + + if (type->type_kind != TYPE_VECTOR || !type_flat_is_boolintlike(type->array.base)) + { + SEMA_ERROR(args[i], "Expected a boolean or integer vector."); + return false; + } + break; case BA_FLOATVEC: if (type->type_kind != TYPE_VECTOR || !type_flat_is_floatlike(type->array.base)) { @@ -326,7 +336,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) (BuiltinArg[]) { BA_VEC, BA_VEC }, arg_count)) return false; if (!sema_check_builtin_args_match(args, 2)) return false; - rtype = type_get_vector_bool(args[0]->type); + rtype = type_get_vector(type_bool, type_flatten(args[0]->type)->array.len); break; case BUILTIN_OVERFLOW_ADD: case BUILTIN_OVERFLOW_MUL: @@ -492,7 +502,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) case BUILTIN_REDUCE_XOR: case BUILTIN_REDUCE_MUL: if (!sema_check_builtin_args(args, - (BuiltinArg[]) { BA_INTVEC }, + (BuiltinArg[]) { BA_BOOLINTVEC }, arg_count)) return false; rtype = args[0]->type->canonical->array.base; break; diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index f9c4e6b85..fee43fe17 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -14,6 +14,7 @@ static Expr *recursive_may_narrow_int(Expr *expr, Type *type); static void recursively_rewrite_untyped_list(Expr *expr, Expr **list); static inline bool cast_may_implicit_ptr(Type *from_pointee, Type *to_pointee); static inline bool cast_may_array(Type *from, Type *to, bool is_explicit); +static inline bool cast_may_vector(Type *from, Type *to, bool is_explicit, bool is_const, CastOption option); static inline bool insert_cast(Expr *expr, CastKind kind, Type *type) { @@ -468,6 +469,10 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability, // 2. Same underlying type, always ok if (from_type == to_type) return true; + if (type_kind_is_any_vector(to_type->type_kind) && type_kind_is_any_vector(from_type->type_kind)) + { + return cast_may_vector(from_type, to_type, true, is_const, CAST_OPTION_NONE); + } if (type_is_any_arraylike(to_type) && type_is_any_arraylike(from_type)) { return cast_may_array(from_type, to_type, true); @@ -568,6 +573,24 @@ bool type_may_convert_to_anyerr(Type *type) return type->failable->canonical == type_void; } +static inline bool cast_may_vector(Type *from, Type *to, bool is_explicit, bool is_const, CastOption option) +{ + if (to->array.len != from->array.len) return false; + Type *to_inner = to->array.base; + Type *from_inner = from->array.base; + if (is_explicit) + { + to_inner = type_flatten(to_inner); + from_inner = type_flatten(from_inner); + } + if (to_inner == from_inner) return true; + if (from_inner == type_bool && type_is_integer(to_inner)) return true; + if (is_explicit) + { + return cast_may_explicit(from_inner, to_inner, true, is_const); + } + return cast_may_implicit(from_inner, to_inner, option); +} static inline bool cast_may_array(Type *from, Type *to, bool is_explicit) { @@ -807,6 +830,11 @@ bool cast_may_implicit(Type *from_type, Type *to_type, CastOption option) return false; } + if (type_kind_is_any_vector(to->type_kind) && to->type_kind == from->type_kind) + { + return cast_may_vector(from, to, false, false, option); + } + if (type_is_any_arraylike(to) && type_is_any_arraylike(from)) { return cast_may_array(from, to, false); @@ -1439,6 +1467,101 @@ static bool vec_to_arr(Expr *expr, Type *to_type) return true; } +static void vec_const_init_to_type(ConstInitializer *initializer, Type *to_type) +{ + switch (initializer->kind) + { + case CONST_INIT_ARRAY: + { + Type *element_type = type_flatten(to_type)->array.base; + FOREACH_BEGIN(ConstInitializer *element, initializer->init_array.elements) + vec_const_init_to_type(element, element_type); + FOREACH_END(); + break; + } + case CONST_INIT_ARRAY_FULL: + { + Type *element_type = type_flatten(to_type)->array.base; + FOREACH_BEGIN(ConstInitializer *element, initializer->init_array_full) + vec_const_init_to_type(element, element_type); + FOREACH_END(); + break; + } + case CONST_INIT_VALUE: + { + Type *to_flat = type_flatten(to_type); + bool is_neg_conversion = to_flat && type_flatten(initializer->type) == type_bool; + if (is_neg_conversion) + { + bool is_true = initializer->init_value->const_expr.b; + initializer->init_value->const_expr.ixx = (Int) + { .i = is_true ? (Int128) { UINT64_MAX, UINT64_MAX } : (Int128) { 0, 0 }, + .type = to_flat->type_kind }; + initializer->init_value->type = to_type; + } + else + { + cast(initializer->init_value, to_type); + } + break; + } + case CONST_INIT_ZERO: + break; + case CONST_INIT_UNION: + case CONST_INIT_STRUCT: + UNREACHABLE + case CONST_INIT_ARRAY_VALUE: + vec_const_init_to_type(initializer->init_array_value.element, to_type); + break; + } + initializer->type = to_type; +} +static bool vec_to_vec(Expr *expr, Type *to_type) +{ + if (expr->expr_kind != EXPR_CONST) + { + Type *from_type = type_flatten(expr->type); + Type *from_element = from_type->array.base; + to_type = type_flatten(to_type); + Type *to_element = to_type->array.base; + if (type_is_float(from_element)) + { + if (to_element == type_bool) return insert_cast(expr, CAST_FPBOOL, to_type); + if (type_is_unsigned(to_element)) return insert_cast(expr, CAST_FPUI, to_type); + if (type_is_signed(to_element)) return insert_cast(expr, CAST_FPSI, to_type); + if (type_is_float(to_element)) return insert_cast(expr, CAST_FPFP, to_type); + UNREACHABLE; + } + if (from_element == type_bool) + { + if (type_is_integer(to_element)) return insert_cast(expr, CAST_BOOLVECINT, to_type); + if (type_is_float(to_element)) return insert_cast(expr, CAST_FPFP, to_type); + UNREACHABLE; + } + if (type_is_signed(from_element)) + { + if (to_element == type_bool) return insert_cast(expr, CAST_INTBOOL, to_type); + if (type_is_unsigned(to_element)) return insert_cast(expr, CAST_SIUI, to_type); + if (type_is_signed(to_element)) return insert_cast(expr, CAST_SISI, to_type); + if (type_is_float(to_element)) return insert_cast(expr, CAST_SIFP, to_type); + UNREACHABLE + } + assert(type_is_unsigned(from_element)); + if (to_element == type_bool) return insert_cast(expr, CAST_INTBOOL, to_type); + if (type_is_unsigned(to_element)) return insert_cast(expr, CAST_UIUI, to_type); + if (type_is_signed(to_element)) return insert_cast(expr, CAST_UISI, to_type); + if (type_is_float(to_element)) return insert_cast(expr, CAST_UIFP, to_type); + UNREACHABLE + } + + assert(expr->const_expr.const_kind == CONST_INITIALIZER); + + ConstInitializer *list = expr->const_expr.initializer; + vec_const_init_to_type(list, to_type); + expr->type = to_type; + return true; +} + static bool err_to_anyerr(Expr *expr, Type *to_type) { expr->type = to_type; @@ -1587,6 +1710,7 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) break; case TYPE_VECTOR: if (to->type_kind == TYPE_ARRAY) return vec_to_arr(expr, to_type); + if (to->type_kind == TYPE_VECTOR) return vec_to_vec(expr, to_type); break; } UNREACHABLE diff --git a/src/compiler/types.c b/src/compiler/types.c index 894337392..739280012 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -351,6 +351,14 @@ bool type_flat_is_intlike(Type *type) return kind >= TYPE_INTEGER_FIRST && kind <= TYPE_INTEGER_LAST; } +bool type_flat_is_boolintlike(Type *type) +{ + type = type_flatten(type); + if (type->type_kind == TYPE_VECTOR) type = type->array.base; + TypeKind kind = type->type_kind; + return kind == TYPE_BOOL || (kind >= TYPE_INTEGER_FIRST && kind <= TYPE_INTEGER_LAST); +} + bool type_is_int128(Type *type) { diff --git a/test/unit/regression/vector_method_reduce.c3 b/test/unit/regression/vector_method_reduce.c3 new file mode 100644 index 000000000..2258c4b97 --- /dev/null +++ b/test/unit/regression/vector_method_reduce.c3 @@ -0,0 +1,18 @@ +import std::math; + +fn void! vector_method_reduce() @test +{ + float[<3>] x = { 1, 2.0, 4.0 }; + int[<*>] y = { -23, 1, 4 }; + assert(y.sum() == -18); + assert(y.product() == -92); + assert(y.max() == 4); + assert(y.and() == 0); + assert(y.xor() == -20); + assert(y.min() == -23); + assert(y.or() == -19); + assert(x.sum(1.2) - 8.2 < 0.000001); + assert(x.product(1.2) - 9.6 < 0.000001); + assert(x.min() == 1.0); + assert(x.max() == 4.0); +} \ No newline at end of file diff --git a/test/unit/regression/vector_ops.c3 b/test/unit/regression/vector_ops.c3 index 8fcd60a5f..0b1a4d104 100644 --- a/test/unit/regression/vector_ops.c3 +++ b/test/unit/regression/vector_ops.c3 @@ -1,11 +1,30 @@ -import libc; +import std::io; -fn void! test_div() @test +fn void! test_conv() @test { float[<4>] y = { 1, 2, 3, 4 }; float[<4>] z = { 0, 2, 2, -100 }; - + int[<4>] w = { -1, 2, 3, 4 }; + float[<4>] yy = w; + assert(yy == { -1.0, 2.0, 3.0, 4.0 }); + ulong[<4>] ww = w; + assert(ww == { (ulong)-1, 2, 3, 4 }); + int[<4>] g = (int[<4>])ww; + assert(g == w); + ww = (long[<4>])y; + assert(ww == { 1, 2, 3, 4 }); + bool[<2>] b = { true, false }; + int[<2>] gh = b; + assert(gh == { -1, 0 }); + var $k = bool[<2>] { true, false }; + var $gh = (int[<2>])$k; + $assert($gh[0] == -1); + var $gh2 = (char[<2>])$gh; + $assert($gh2[0] == 255); + b = (bool[<2>])gh; + assert(b == { true, false }); } + fn void! testf() @test { float[<4>] y = { 1, 2, 3, 4 };