mirror of
https://github.com/odin-lang/Odin.git
synced 2026-07-16 12:41:09 +00:00
Add simd.interleave + simd.deinterleave
This commit is contained in:
@@ -367,8 +367,11 @@ simd_odd_even :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
// Returns the sums of N consecutive lanes
|
||||
simd_sums_of_n :: proc(a: #simd[LANES]T, $N: uint) -> #simd[LANES/N]T where is_power_of_two(N) ---
|
||||
|
||||
simd_pairwise_add :: proc(a, b: #simd[LANES]T) -> #simd[LANES/N]T ---
|
||||
simd_pairwise_sub :: proc(a, b: #simd[LANES]T) -> #simd[LANES/N]T ---
|
||||
simd_pairwise_add :: proc(a, b: #simd[LANES]T) -> #simd[LANES]T where LANES % 2 == 0 ---
|
||||
simd_pairwise_sub :: proc(a, b: #simd[LANES]T) -> #simd[LANES]T where LANES % 2 == 0 ---
|
||||
|
||||
simd_interleave :: proc(a, ..#simd[LANES/N]T) -> #simd[LANES]T where N >= 1 ---
|
||||
simd_deinterleave :: proc(a: #simd[LANES]T, $N: uint) -> (#simd[LANES/N]T, #simd[LANES/N]T, ..., #simd[LANES/N]T) where N >= 1, LANES % N == 0 ---
|
||||
|
||||
|
||||
// Checks if the current target supports the given target features.
|
||||
|
||||
@@ -2886,3 +2886,6 @@ abs_diff :: #force_inline proc "contextless" (a, b: $T/#simd[$LANES]$E) -> T whe
|
||||
|
||||
pairwise_add :: intrinsics.simd_pairwise_add
|
||||
pairwise_sub :: intrinsics.simd_pairwise_add
|
||||
|
||||
interleave :: intrinsics.simd_interleave
|
||||
deinterleave :: intrinsics.simd_deinterleave
|
||||
@@ -1868,6 +1868,90 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
|
||||
return true;
|
||||
}
|
||||
|
||||
case BuiltinProc_simd_interleave:
|
||||
{
|
||||
Operand x = {};
|
||||
check_expr(c, &x, ce->args[0]); if (x.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;
|
||||
}
|
||||
|
||||
for (isize i = 1; i < ce->args.count; i++) {
|
||||
Operand y = {};
|
||||
check_expr_with_type_hint(c, &y, ce->args[i], x.type); if (y.mode == Addressing_Invalid) 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 a = type_to_string(x.type);
|
||||
gbString b = type_to_string(y.type);
|
||||
error(y.expr, "'%.*s' all argument types must match, expected %s, got %s", LIT(builtin_name), a, b);
|
||||
gb_string_free(b);
|
||||
gb_string_free(a);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Type *elem = base_array_type(x.type);
|
||||
i64 base_count = get_array_type_count(x.type);
|
||||
i64 count = base_count * cast(i64)ce->args.count;
|
||||
|
||||
i64 max_count = 64;
|
||||
if (count > max_count) {
|
||||
error(ce->proc, "'%.*s' exceeds the maximum #simd count %lld, got %lld", cast(long long)max_count, cast(long long)count);
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->type = alloc_type_simd_vector(count, elem);
|
||||
operand->mode = Addressing_Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
case BuiltinProc_simd_deinterleave:
|
||||
{
|
||||
Operand x = {};
|
||||
check_expr(c, &x, ce->args[0]); if (x.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;
|
||||
}
|
||||
|
||||
Type *elem = base_array_type(x.type);
|
||||
i64 max_count = get_array_type_count(x.type);
|
||||
|
||||
Operand n = {};
|
||||
check_expr(c, &n, ce->args[1]); if (n.mode == Addressing_Invalid) return false;
|
||||
if (n.mode != Addressing_Constant) {
|
||||
error(n.expr, "'%.*s' expected a constant integer divisible by the count of the #simd vector", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
if (n.value.kind != ExactValue_Integer) {
|
||||
error(n.expr, "'%.*s' expected a constant integer divisible by the count of the #simd vector", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
i64 divisor = exact_value_to_i64(n.value);
|
||||
if (divisor < 1 || divisor > max_count || (max_count % divisor != 0)) {
|
||||
error(n.expr, "'%.*s' expected a constant integer divisible by the count of the #simd vector , got %lld, which must have been divisible by %lld", LIT(builtin_name), cast(long long)divisor, cast(long long)max_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *base_vector = alloc_type_simd_vector(max_count / divisor, elem);
|
||||
|
||||
Type **field_types = temporary_alloc_array<Type *>(cast(isize)divisor);
|
||||
for (i64 i = 0; i < divisor; i++) {
|
||||
field_types[i] = base_vector;
|
||||
}
|
||||
|
||||
operand->type = alloc_type_tuple_from_field_types(field_types, divisor, false, false);
|
||||
operand->mode = Addressing_Value;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case BuiltinProc_simd_x86__MM_SHUFFLE:
|
||||
{
|
||||
Operand x[4] = {};
|
||||
|
||||
@@ -235,6 +235,9 @@ BuiltinProc__simd_begin,
|
||||
|
||||
BuiltinProc_simd_indices,
|
||||
|
||||
BuiltinProc_simd_interleave,
|
||||
BuiltinProc_simd_deinterleave,
|
||||
|
||||
|
||||
// Platform specific SIMD intrinsics
|
||||
BuiltinProc_simd_x86__MM_SHUFFLE,
|
||||
@@ -641,6 +644,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
|
||||
{STR_LIT("simd_indices"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("simd_interleave"), 1, true, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("simd_deinterleave"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("simd_x86__MM_SHUFFLE"), 4, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
|
||||
@@ -1445,7 +1445,7 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn
|
||||
Type *elem = type->SimdVector.elem;
|
||||
|
||||
i64 count = type->SimdVector.count;
|
||||
LLVMValueRef *scalars = gb_alloc_array(temporary_allocator(), LLVMValueRef, count);
|
||||
LLVMValueRef *scalars = temporary_alloc_array<LLVMValueRef>(count);
|
||||
for (i64 i = 0; i < count; i++) {
|
||||
scalars[i] = lb_const_value(m, elem, exact_value_i64(i)).value;
|
||||
}
|
||||
@@ -1453,6 +1453,55 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn
|
||||
res.value = LLVMConstVector(scalars, cast(unsigned)count);
|
||||
return res;
|
||||
}
|
||||
|
||||
case BuiltinProc_simd_interleave:
|
||||
{
|
||||
int n = cast(int)ce->args.count;
|
||||
|
||||
if (n == 1) {
|
||||
lbValue arg = lb_build_expr(p, ce->args[0]);
|
||||
res.value = arg.value;
|
||||
return res;
|
||||
}
|
||||
|
||||
Type *vector_type = type_of_expr(ce->args[0]);
|
||||
|
||||
LLVMValueRef *args = temporary_alloc_array<LLVMValueRef>(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
lbValue arg = lb_build_expr(p, ce->args[i]);
|
||||
arg = lb_emit_conv(p, arg, vector_type);
|
||||
args[i] = arg.value;
|
||||
}
|
||||
|
||||
gbString name = gb_string_make(heap_allocator(), "");
|
||||
name = gb_string_append_fmt(name, "llvm.vector.interleave%d", n);
|
||||
defer (gb_string_free(name));
|
||||
|
||||
LLVMTypeRef types[1] = {lb_type(m, tv.type)};
|
||||
res.value = lb_call_intrinsic(p, name, args, n, types, gb_count_of(types));
|
||||
return res;
|
||||
}
|
||||
|
||||
case BuiltinProc_simd_deinterleave:
|
||||
{
|
||||
lbValue arg0 = lb_build_expr(p, ce->args[0]);
|
||||
LLVMTypeRef types[1] = {lb_type(m, arg0.type)};
|
||||
|
||||
GB_ASSERT(ce->args[1]->tav.value.kind == ExactValue_Integer);
|
||||
int n = cast(int)exact_value_to_i64(ce->args[1]->tav.value);
|
||||
|
||||
if (n == 1) {
|
||||
res.value = arg0.value;
|
||||
return res;
|
||||
}
|
||||
|
||||
gbString name = gb_string_make(heap_allocator(), "");
|
||||
name = gb_string_append_fmt(name, "llvm.vector.deinterleave%d", n);
|
||||
defer (gb_string_free(name));
|
||||
|
||||
res.value = lb_call_intrinsic(p, name, &arg0.value, 1, types, gb_count_of(types));
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
lbValue arg0 = {}; if (ce->args.count > 0) arg0 = lb_build_expr(p, ce->args[0]);
|
||||
|
||||
Reference in New Issue
Block a user