diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index d1e60fe8e..4d249671f 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -144,6 +144,16 @@ macro prefetch(void* ptr, PrefetchLocality $locality = VERY_NEAR, bool $write = $$prefetch(ptr, $write ? 1 : 0, $locality.ordinal); } +macro swizzle(v, ...) @builtin +{ + return $$swizzle(v, $vasplat()); +} + +macro swizzle2(v, v2, ...) @builtin +{ + return $$swizzle2(v, v2, $vasplat()); +} + macro bool @castable(#expr, $To) @builtin { return $checks(($To)#expr); diff --git a/lib/std/math/math_vector.c3 b/lib/std/math/math_vector.c3 index e4f7cb500..2485063e5 100644 --- a/lib/std/math/math_vector.c3 +++ b/lib/std/math/math_vector.c3 @@ -131,8 +131,8 @@ private macro perpendicular3(v) private macro cross3(v1, v2) { - var a = $$shufflevector(v1, v1, { 1, 2, 0 }) * $$shufflevector(v2, v2, { 2, 0, 1 }); - var b = $$shufflevector(v1, v1, { 2, 0, 1 }) * $$shufflevector(v2, v2, { 1, 2, 0 }); + var a = v1.yzx * v2.zxy; + var b = v1.zxy * v2.yzx; return a - b; } diff --git a/src/compiler/enums.h b/src/compiler/enums.h index f1d5bb0bf..5581b63ee 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -879,7 +879,8 @@ typedef enum BUILTIN_SAT_SHL, BUILTIN_SAT_SUB, BUILTIN_SET_ROUNDING_MODE, - BUILTIN_SHUFFLEVECTOR, + BUILTIN_SWIZZLE, + BUILTIN_SWIZZLE2, BUILTIN_SIN, BUILTIN_SQRT, BUILTIN_STACKTRACE, diff --git a/src/compiler/llvm_codegen_builtins.c b/src/compiler/llvm_codegen_builtins.c index 01f7380b6..f66f18f99 100644 --- a/src/compiler/llvm_codegen_builtins.c +++ b/src/compiler/llvm_codegen_builtins.c @@ -24,7 +24,7 @@ INLINE void llvm_emit_reverse(GenContext *c, BEValue *result_value, Expr *expr) llvm_value_set(result_value, LLVMBuildShuffleVector(c->builder, arg1, arg2, mask, "reverse"), rtype); } -INLINE void llvm_emit_shufflevector(GenContext *c, BEValue *result_value, Expr *expr) +INLINE void llvm_emit_swizzle(GenContext *c, BEValue *result_value, Expr *expr, bool swizzle_two) { Expr **args = expr->call_expr.arguments; unsigned count = vec_size(args); @@ -33,24 +33,36 @@ INLINE void llvm_emit_shufflevector(GenContext *c, BEValue *result_value, Expr * LLVMValueRef mask; llvm_emit_expr(c, result_value, args[0]); llvm_value_rvalue(c, result_value); - Type *rtype = result_value->type; arg1 = result_value->value; - llvm_emit_expr(c, result_value, args[count - 1]); - llvm_value_rvalue(c, result_value); - mask = result_value->value; - assert(LLVMIsConstant(mask)); - if (count == 2) - { - arg2 = LLVMGetPoison(LLVMTypeOf(arg1)); - } - else + unsigned mask_start = 1; + if (swizzle_two) { + mask_start = 2; llvm_emit_expr(c, result_value, args[1]); llvm_value_rvalue(c, result_value); arg2 = result_value->value; } - LLVMValueRef val = LLVMBuildShuffleVector(c->builder, arg1, arg2, mask, "shuffle"); - llvm_value_set(result_value, val, rtype); + else + { + arg2 = LLVMGetPoison(LLVMTypeOf(arg1)); + } +#define MASK_VALS 256 + LLVMValueRef mask_cache[MASK_VALS]; + LLVMValueRef *mask_val = mask_cache; + unsigned mask_len = count - mask_start; + if (mask_len > MASK_VALS) + { + mask_val = malloc(sizeof(LLVMValueRef) * (mask_len)); + } + for (unsigned i = mask_start; i < count; i++) + { + llvm_emit_expr(c, result_value, args[i]); + llvm_value_rvalue(c, result_value); + mask_val[i - mask_start] = result_value->value; + } + LLVMValueRef mask_value = LLVMConstVector(mask_val, mask_len); + LLVMValueRef val = LLVMBuildShuffleVector(c->builder, arg1, arg2, mask_value, "shuffle"); + llvm_value_set(result_value, val, expr->type); return; } @@ -572,8 +584,11 @@ void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr) case BUILTIN_UNREACHABLE: llvm_emit_unreachable(c, result_value, expr); return; - case BUILTIN_SHUFFLEVECTOR: - llvm_emit_shufflevector(c, result_value, expr); + case BUILTIN_SWIZZLE: + llvm_emit_swizzle(c, result_value, expr, false); + return; + case BUILTIN_SWIZZLE2: + llvm_emit_swizzle(c, result_value, expr, true); return; case BUILTIN_COMPARE_EXCHANGE: llvm_emit_compare_exchange(c, result_value, expr); diff --git a/src/compiler/sema_builtins.c b/src/compiler/sema_builtins.c index d53a4622f..df09032aa 100644 --- a/src/compiler/sema_builtins.c +++ b/src/compiler/sema_builtins.c @@ -23,7 +23,7 @@ typedef enum static bool sema_check_builtin_args_match(Expr **args, size_t arg_len); static bool sema_check_builtin_args_const(Expr **args, size_t arg_len); static bool sema_check_builtin_args(Expr **args, BuiltinArg *arg_type, size_t arg_len); -static inline bool sema_expr_analyse_shufflevector(SemaContext *context, Expr *expr); +static inline bool sema_expr_analyse_swizzle(SemaContext *context, Expr *expr, bool swizzle_two); static inline unsigned builtin_expected_args(BuiltinFunction func); static bool sema_check_builtin_args_match(Expr **args, size_t arg_len) @@ -159,80 +159,45 @@ static bool sema_check_builtin_args(Expr **args, BuiltinArg *arg_type, size_t ar return true; } -static inline bool sema_expr_analyse_shufflevector(SemaContext *context, Expr *expr) +static inline bool sema_expr_analyse_swizzle(SemaContext *context, Expr *expr, bool swizzle_two) { Expr **args = expr->call_expr.arguments; unsigned arg_count = vec_size(args); - if (arg_count < 2 || arg_count > 3) + if (swizzle_two && arg_count < 3) { - SEMA_ERROR(expr, "Expected 2 or 3 arguments."); + SEMA_ERROR(expr, "Expected at least 3 arguments."); + return false; + } + else if (arg_count < 2) + { + SEMA_ERROR(expr, "Expected at least 2 arguments."); return false; } bool optional = false; - Expr *mask = args[arg_count - 1]; - unsigned len = 0; - if (expr_is_const_initializer(mask)) - { - ConstInitializer *init = mask->const_expr.initializer; - len = init->kind == CONST_INIT_ARRAY_FULL ? vec_size(init->init_array_full) : 0; - } - else if (mask->expr_kind == EXPR_INITIALIZER_LIST) - { - len = vec_size(mask->initializer_list); - } - if (len) - { - if (!sema_analyse_expr_rhs(context, type_get_vector(type_int, len), mask, true)) return false; - } - for (unsigned i = 0; i < arg_count; i++) + int first_mask_value = swizzle_two ? 2 : 1; + for (unsigned i = 0; i < first_mask_value; i++) { if (!sema_analyse_expr(context, args[i])) return false; optional = optional || type_is_optional(args[i]->type); } - - if (!sema_check_builtin_args(args, - arg_count == 2 ? (BuiltinArg[]) { BA_VEC, BA_INTVEC } : (BuiltinArg[]) { BA_VEC, BA_VEC, BA_INTVEC }, - arg_count)) return false; - if (arg_count == 3 && type_flatten(args[0]->type) != type_flatten(args[1]->type)) + unsigned components = type_flatten(args[0]->type)->array.len; + if (swizzle_two) components *= 2; + for (unsigned i = first_mask_value; i < arg_count; i++) { - SEMA_ERROR(args[1], "Both vector types must match."); - return false; - } - if (type_flatten(args[0]->type)->array.len != type_flatten(mask->type)->array.len) - { - SEMA_ERROR(args[2], "Mask vector length must match operands."); - return false; - } - Type *vec_type = type_flatten(mask->type); - ArraySize max_size = vec_type->array.len; - if (arg_count == 3) max_size *= 2; - if (vec_type->array.base != type_int && vec_type->array.base != type_uint) - { - SEMA_ERROR(mask, "Mask must be an int or uint vector."); - return false; - } - if (mask->expr_kind != EXPR_CONST) - { - SEMA_ERROR(mask, "The mask must be a compile time constant."); - return false; - } - ConstInitializer *init = mask->const_expr.initializer; - if (init->kind != CONST_INIT_ARRAY_FULL) - { - SEMA_ERROR(mask, "The mask must be a fully specified list."); - return false; - } - - FOREACH_BEGIN(ConstInitializer *val, init->init_array_full) - assert(val->kind == CONST_INIT_VALUE); - uint64_t index = int_to_u64(val->init_value->const_expr.ixx); - if (index >= max_size) + Expr *mask_val = args[i]; + if (!sema_analyse_expr_rhs(context, type_int, mask_val, false)) return false; + if (!expr_is_const_int(mask_val)) { - SEMA_ERROR(val->init_value, "Index is out of bounds, expected a value between 0 and %u.", max_size - 1); + SEMA_ERROR(mask_val, "The swizzle positions must be compile time constants."); return false; } - FOREACH_END(); - expr->type = type_add_optional(args[0]->type, optional); + if (mask_val->const_expr.ixx.i.low >= components) + { + SEMA_ERROR(mask_val, "The swizzle position must be between 0 and %d.", components - 1); + return false; + } + } + expr->type = type_add_optional(type_get_vector(type_get_indexed_type(args[0]->type), arg_count - first_mask_value), optional); return true; } @@ -249,10 +214,11 @@ bool is_valid_atomicity(Expr* expr) bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) { expr->call_expr.is_builtin = true; + expr->call_expr.arguments = sema_expand_vasplat_exprs(context, expr->call_expr.arguments); BuiltinFunction func = exprptr(expr->call_expr.function)->builtin_expr.builtin; - if (func == BUILTIN_SHUFFLEVECTOR) + if (func == BUILTIN_SWIZZLE || func == BUILTIN_SWIZZLE2) { - return sema_expr_analyse_shufflevector(context, expr); + return sema_expr_analyse_swizzle(context, expr, func == BUILTIN_SWIZZLE2); } unsigned expected_args = builtin_expected_args(func); Expr **args = expr->call_expr.arguments; @@ -293,7 +259,8 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) Type *rtype = NULL; switch (func) { - case BUILTIN_SHUFFLEVECTOR: + case BUILTIN_SWIZZLE2: + case BUILTIN_SWIZZLE: UNREACHABLE; case BUILTIN_TRAP: case BUILTIN_UNREACHABLE: @@ -710,7 +677,8 @@ static inline unsigned builtin_expected_args(BuiltinFunction func) return 5; case BUILTIN_COMPARE_EXCHANGE: return 8; - case BUILTIN_SHUFFLEVECTOR: + case BUILTIN_SWIZZLE2: + case BUILTIN_SWIZZLE: case BUILTIN_NONE: UNREACHABLE } diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index afcb8135f..6a89967dc 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -242,7 +242,8 @@ void symtab_init(uint32_t capacity) builtin_list[BUILTIN_SAT_SUB] = KW_DEF("sat_sub"); builtin_list[BUILTIN_SET_ROUNDING_MODE] = KW_DEF("set_rounding_mode"); builtin_list[BUILTIN_SIN] = KW_DEF("sin"); - builtin_list[BUILTIN_SHUFFLEVECTOR] = KW_DEF("shufflevector"); + builtin_list[BUILTIN_SWIZZLE] = KW_DEF("swizzle"); + builtin_list[BUILTIN_SWIZZLE2] = KW_DEF("swizzle2"); builtin_list[BUILTIN_SQRT] = KW_DEF("sqrt"); builtin_list[BUILTIN_STACKTRACE] = KW_DEF("stacktrace"); builtin_list[BUILTIN_SYSCALL] = KW_DEF("syscall"); diff --git a/src/version.h b/src/version.h index ebd300783..02e0282e7 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.17" \ No newline at end of file +#define COMPILER_VERSION "0.4.18" \ No newline at end of file diff --git a/test/test_suite/builtins/shufflevector.c3t b/test/test_suite/builtins/shufflevector.c3t index 4a4d80f5c..d252a1711 100644 --- a/test/test_suite/builtins/shufflevector.c3t +++ b/test/test_suite/builtins/shufflevector.c3t @@ -39,9 +39,9 @@ fn float[<2>] apply2(Matrix2x2* mat, float[<2>] vec) fn float[<2>] apply3(Matrix2x2* mat, float[<2>] vec) { - float[<2>] a = $$shufflevector(mat.m0, mat.m1, { 0, 3 }); - float[<2>] b = $$shufflevector(mat.m0, mat.m1, { 1, 2 }); - float[<2>] flip = $$shufflevector(vec, { 1, 0 }); + float[<2>] a = $$swizzle2(mat.m0, mat.m1, 0, 3); + float[<2>] b = $$swizzle2(mat.m0, mat.m1, 1, 2); + float[<2>] flip = $$swizzle(vec, 1, 0); return a * vec + b * flip; } diff --git a/test/test_suite14/builtins/shufflevector.c3t b/test/test_suite14/builtins/shufflevector.c3t index 3e591ae14..725a336eb 100644 --- a/test/test_suite14/builtins/shufflevector.c3t +++ b/test/test_suite14/builtins/shufflevector.c3t @@ -39,9 +39,9 @@ fn float[<2>] apply2(Matrix2x2* mat, float[<2>] vec) fn float[<2>] apply3(Matrix2x2* mat, float[<2>] vec) { - float[<2>] a = $$shufflevector(mat.m0, mat.m1, { 0, 3 }); - float[<2>] b = $$shufflevector(mat.m0, mat.m1, { 1, 2 }); - float[<2>] flip = $$shufflevector(vec, { 1, 0 }); + float[<2>] a = $$swizzle2(mat.m0, mat.m1, 0, 3); + float[<2>] b = $$swizzle2(mat.m0, mat.m1, 1, 2); + float[<2>] flip = $$swizzle(vec, 1, 0); return a * vec + b * flip; }