diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 3b61603bf..33ca80d81 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2143,6 +2143,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_numlike(Type *type); bool type_may_have_sub_elements(Type *type); const char *type_to_error_string(Type *type); const char *type_quoted_error_string(Type *type); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index acdb9e8e5..c0ca33f98 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -569,7 +569,8 @@ typedef enum TYPE_BOOL, TYPE_I8, TYPE_INTEGER_FIRST = TYPE_I8, - TYPE_INT_FIRST = TYPE_I8, + TYPE_NUM_FIRST = TYPE_INTEGER_FIRST, + TYPE_INT_FIRST = TYPE_INTEGER_FIRST, TYPE_I16, TYPE_I32, TYPE_I64, @@ -589,6 +590,7 @@ typedef enum TYPE_F64, TYPE_F128, TYPE_FLOAT_LAST = TYPE_F128, + TYPE_NUM_LAST = TYPE_FLOAT_LAST, TYPE_ANY, TYPE_ANYERR, TYPE_TYPEID, diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 925ed120f..90ef6e754 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -4544,6 +4544,7 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr) if (func == BUILTIN_MAX) { Type *type = type_flatten(expr->call_expr.arguments[0]->type); + RETRY: switch (type->type_kind) { case ALL_SIGNED_INTS: @@ -4556,6 +4557,9 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr) case ALL_FLOATS: intrinsic = intrinsic_id.maxnum; break; + case TYPE_VECTOR: + type = type->array.base; + goto RETRY; default: UNREACHABLE } @@ -4563,6 +4567,7 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr) else if (func == BUILTIN_MIN) { Type *type = type_flatten(expr->call_expr.arguments[0]->type); + RETRY2: switch (type->type_kind) { case ALL_SIGNED_INTS: @@ -4575,6 +4580,9 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr) case ALL_FLOATS: intrinsic = intrinsic_id.minnum; break; + case TYPE_VECTOR: + type = type->array.base; + goto RETRY2; default: UNREACHABLE } diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 89127a3c4..79425c935 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2504,6 +2504,7 @@ typedef enum BA_CHAR, BA_FLOATLIKE, BA_INTLIKE, + BA_NUMLIKE, } BuiltinArg; static bool sema_check_builtin_args_match(Expr **args, size_t arg_len) @@ -2567,6 +2568,13 @@ static bool sema_check_builtin_args(Expr **args, BuiltinArg *arg_type, size_t ar return false; } break; + case BA_NUMLIKE: + if (!type_flat_is_numlike(type)) + { + SEMA_ERROR(args[i], "Expected a number or vector."); + return false; + } + break; case BA_FLOATLIKE: if (!type_flat_is_floatlike(type)) { @@ -2711,14 +2719,7 @@ static inline bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *ex break; case BUILTIN_MAX: case BUILTIN_MIN: - if (type_is_integer(args[0]->type)) - { - if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_INTLIKE, BA_INTLIKE }, arg_count)) return false; - } - else - { - if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_FLOATLIKE, BA_FLOATLIKE }, arg_count)) return false; - } + if (!sema_check_builtin_args(args, (BuiltinArg[]) { BA_NUMLIKE, BA_NUMLIKE }, arg_count)) return false; if (!sema_check_builtin_args_match(args, arg_count)) return false; rtype = args[0]->type; break; diff --git a/src/compiler/types.c b/src/compiler/types.c index 0e826b3d6..cfc60c931 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -320,6 +320,14 @@ RETRY: } +bool type_flat_is_numlike(Type *type) +{ + type = type_flatten(type); + if (type->type_kind == TYPE_VECTOR) type = type->array.base; + TypeKind kind = type->type_kind; + return kind >= TYPE_NUM_FIRST && kind <= TYPE_NUM_LAST; +} + bool type_flat_is_floatlike(Type *type) { type = type_flatten(type); diff --git a/src/version.h b/src/version.h index d68677ecb..76bd411a3 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.33" \ No newline at end of file +#define COMPILER_VERSION "0.3.34" \ No newline at end of file diff --git a/test/test_suite/builtins/builtin_vector_min_max.c3t b/test/test_suite/builtins/builtin_vector_min_max.c3t new file mode 100644 index 000000000..ff05001aa --- /dev/null +++ b/test/test_suite/builtins/builtin_vector_min_max.c3t @@ -0,0 +1,24 @@ +// #target: macos-x64 +module test; +fn void main() +{ + { + float[<2>] vf1 = { 1, -1 }; + float[<2>] vf2 = { 1, 1 }; + float[<2>] max = $$max(vf1, vf2); + float[<2>] min = $$min(vf1, vf2); + } + { + int[<2>] v1 = { 1, -1 }; + int[<2>] v2 = { 1, 1 }; + int[<2>] max = $$max(v1, v2); + int[<2>] min = $$min(v1, v2); + } +} + +/* #expect: test.ll + + %2 = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %0, <2 x float> %1) + %5 = call <2 x float> @llvm.minnum.v2f32(<2 x float> %3, <2 x float> %4) + %8 = call <2 x i32> @llvm.smax.v2i32(<2 x i32> %6, <2 x i32> %7) + %11 = call <2 x i32> @llvm.smin.v2i32(<2 x i32> %9, <2 x i32> %10) diff --git a/test/test_suite2/builtins/builtin_vector_min_max.c3t b/test/test_suite2/builtins/builtin_vector_min_max.c3t new file mode 100644 index 000000000..ff05001aa --- /dev/null +++ b/test/test_suite2/builtins/builtin_vector_min_max.c3t @@ -0,0 +1,24 @@ +// #target: macos-x64 +module test; +fn void main() +{ + { + float[<2>] vf1 = { 1, -1 }; + float[<2>] vf2 = { 1, 1 }; + float[<2>] max = $$max(vf1, vf2); + float[<2>] min = $$min(vf1, vf2); + } + { + int[<2>] v1 = { 1, -1 }; + int[<2>] v2 = { 1, 1 }; + int[<2>] max = $$max(v1, v2); + int[<2>] min = $$min(v1, v2); + } +} + +/* #expect: test.ll + + %2 = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %0, <2 x float> %1) + %5 = call <2 x float> @llvm.minnum.v2f32(<2 x float> %3, <2 x float> %4) + %8 = call <2 x i32> @llvm.smax.v2i32(<2 x i32> %6, <2 x i32> %7) + %11 = call <2 x i32> @llvm.smin.v2i32(<2 x i32> %9, <2 x i32> %10)