diff --git a/core/simd/simd.odin b/core/simd/simd.odin index 52c97cc45..02a00a47d 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -2579,6 +2579,27 @@ Reverse the bit pattern of a SIMD vector. */ reverse_bits :: intrinsics.reverse_bits +/* +**Operation** + + #assert(len(a) == len(b)) + res := 0 + N :: len(a) + for i in 0 ..< N/2 { + res[i] = a[2*i + 1] + } + for i in 0 ..< N/2 { + res[i + N/2] = b[2*i] + } + return res +*/ +odd_even :: intrinsics.simd_odd_even + +@(require_results) +add_sub :: #force_inline proc "contextless" (a, b: $T/#simd[$LANES]$E) -> T where intrinsics.type_is_integer(E) { + return odd_even(add(a, b), sub(a, b)) +} + /* Perform a FMA (Fused multiply-add) operation on each lane of SIMD vectors. @@ -2606,6 +2627,41 @@ Returns: */ fused_mul_add :: intrinsics.fused_mul_add + +@(require_results) +fused_neg_mul_add :: #force_inline proc "contextless" (a, b, c: $T/#simd[$LANES]$E) -> T { + return fused_mul_add(neg(a), b, c) +} + +@(require_results) +fused_mul_sub :: #force_inline proc "contextless" (a, b, c: $T/#simd[$LANES]$E) -> T { + return fused_mul_add(a, b, neg(c)) +} + +@(require_results) +fused_neg_mul_sub :: #force_inline proc "contextless" (a, b, c: $T/#simd[$LANES]$E) -> T { + return fused_mul_add(neg(a), b, neg(c)) +} + +@(require_results) +fused_mul_add_sub :: #force_inline proc "contextless" (a, b, c: $T/#simd[$LANES]$E) -> T { + odd := fused_mul_add(a, b, c) + even := fused_mul_sub(a, b, c) + return odd_even(odd, even) +} + +@(require_results) +fused_mul_sub_add :: #force_inline proc "contextless" (a, b, c: $T/#simd[$LANES]$E) -> T { + odd := fused_mul_sub(a, b, c) + even := fused_mul_add(a, b, c) + return odd_even(odd, even) +} + + + + + + /* Perform a FMA (Fused multiply-add) operation on each lane of SIMD vectors. @@ -2769,4 +2825,34 @@ Operation: res[i] = i } */ -indices :: intrinsics.simd_indices \ No newline at end of file +indices :: intrinsics.simd_indices + +/* +Create a vector where each lane contains the index of that lane. +Inputs: +- `V`: The type of the vector to create. +Result: +- A vector of the given type, where each lane contains the index of that lane. +Operation: + for i in 0 ..< N { + res[i] = i + } +*/ +iota :: intrinsics.simd_indices + + + +@(require_results) +saturating_neg :: #force_inline proc "contextless" (v: $T/#simd[$LANES]$E) -> T where intrinsics.type_is_integer(E) { + return saturating_sub(T(0), v) +} + +@(require_results) +saturating_abs :: #force_inline proc "contextless" (v: $T/#simd[$LANES]$E) -> T where intrinsics.type_is_integer(E) { + return max(v, saturating_sub(T(0), v)) +} + +@(require_results) +abs_diff :: #force_inline proc "contextless" (a, b: $T/#simd[$LANES]$E) -> T where intrinsics.type_is_integer(E) { + return abs(sub(a, b)) +} diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index e4907dfd0..634370fd9 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1387,6 +1387,35 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan return true; } + case BuiltinProc_simd_odd_even: + { + Operand x = {}; + Operand y = {}; + check_expr(c, &x, ce->args[0]); if (x.mode == Addressing_Invalid) return false; + check_expr_with_type_hint(c, &y, ce->args[1], x.type); if (y.mode == Addressing_Invalid) return false; + convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false; + if (!is_type_simd_vector(x.type)) { + error(x.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); + return false; + } + if (!is_type_simd_vector(y.type)) { + error(y.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); + return false; + } + if (!are_types_identical(x.type, y.type)) { + gbString xs = type_to_string(x.type); + gbString ys = type_to_string(y.type); + error(x.expr, "'%.*s' expected 2 arguments of the same type, got '%s' vs '%s'", LIT(builtin_name), xs, ys); + gb_string_free(ys); + gb_string_free(xs); + return false; + } + + operand->mode = Addressing_Value; + operand->type = x.type; + return true; + } + case BuiltinProc_simd_select: { Operand cond = {}; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index c0333e91c..36e983476 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -204,6 +204,7 @@ BuiltinProc__simd_begin, BuiltinProc_simd_shuffle, BuiltinProc_simd_select, BuiltinProc_simd_runtime_swizzle, + BuiltinProc_simd_odd_even, BuiltinProc_simd_ceil, BuiltinProc_simd_floor, @@ -595,6 +596,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_shuffle"), 2, true, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_select"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_runtime_swizzle"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_odd_even"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_ceil") , 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_floor"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 7d0379e9a..2960a4306 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1738,6 +1738,30 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn return res; } + case BuiltinProc_simd_odd_even: + { + Type *vt = arg0.type; + GB_ASSERT(vt->kind == Type_SimdVector); + + u64 indices_count = cast(u64)vt->SimdVector.count; + + LLVMValueRef *vals = gb_alloc_array(temporary_allocator(), LLVMValueRef, indices_count); + + for (u64 i = 0; i < indices_count/2; i++) { + u64 val = 2*i + 1; + vals[i] = LLVMConstInt(lb_type(p->module, t_u32), val, false); + } + for (u64 i = 0; i < indices_count/2; i++) { + u64 val = 2*i + indices_count; + vals[i+indices_count/2] = LLVMConstInt(lb_type(p->module, t_u32), val, false); + } + + LLVMValueRef indices = LLVMConstVector(vals, cast(unsigned)indices_count); + + res.value = LLVMBuildShuffleVector(p->builder, arg0.value, arg1.value, indices, ""); + return res; + } + case BuiltinProc_simd_select: { LLVMValueRef cond = arg0.value;