intrinsics.to_bits_signed; simd.signbit

This commit is contained in:
gingerBill
2026-04-07 15:25:41 +01:00
parent 5de18d30f3
commit 6e09ce9a04
6 changed files with 100 additions and 15 deletions

View File

@@ -1,4 +1,4 @@
// This is purely for documentation
7// This is purely for documentation
#+build ignore
package intrinsics
@@ -351,7 +351,8 @@ simd_nearest :: proc(a: #simd[N]any_float) -> #simd[N]any_float ---
simd_approx_recip :: proc(x: #simd[N]T) -> #simd[N]T where type_is_float(T)) ---
simd_approx_recip_sqrt :: proc(x: #simd[N]T) -> #simd[N]T where type_is_float(T)) ---
simd_to_bits :: proc(v: #simd[N]T) -> #simd[N]Integer where size_of(T) == size_of(Integer), type_is_unsigned(Integer) ---
simd_to_bits :: proc(v: #simd[N]T) -> #simd[N]Integer where size_of(T) == size_of(Integer), type_is_unsigned(Integer) ---
simd_to_bits_signed :: proc(v: #simd[N]T) -> #simd[N]Integer where size_of(T) == size_of(Integer), !type_is_unsigned(Integer) ---
// equivalent to a swizzle with descending indices, e.g. reserve(a, 3, 2, 1, 0)
simd_lanes_reverse :: proc(a: #simd[N]T) -> #simd[N]T ---

View File

@@ -2517,10 +2517,16 @@ Compute the nearest integer of each lane in a SIMD vector.
nearest :: intrinsics.simd_nearest
/*
Transmute a SIMD vector into an integer vector.
Transmute a SIMD vector into an unsigned integer vector.
*/
to_bits :: intrinsics.simd_to_bits
/*
Transmute a SIMD vector into a signed integer vector.
*/
to_bits_signed :: intrinsics.simd_to_bits_signed
/*
Reverse the lanes of a SIMD vector.
@@ -2779,6 +2785,15 @@ signum :: #force_inline proc "contextless" (v: $T/#simd[$LANES]$E) -> T where in
return select(is_nan, v, copysign(T(1), v))
}
@(require_results)
signbit :: #force_inline proc "contextless" (v: $T/#simd[$LANES]$E) -> (res: type_of(intrinsics.simd_to_bits(T{}))) {
BITS :: 8*size_of(E)
val := to_bits(v)
mask := type_of(val)(1<<(BITS-1))
masked := bit_and(val, mask)
return to_bits(shr(to_bits_signed(masked), BITS-1))
}
/*
Calculate reciprocals of SIMD lanes.
@@ -2848,7 +2863,6 @@ iota :: intrinsics.simd_indices
sums_of_n :: intrinsics.simd_sums_of_n
@(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)

View File

@@ -887,14 +887,24 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
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;
check_expr(c, &y, ce->args[1]); 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));
if (is_type_untyped(y.type) || is_type_unsigned(y.type)) {
Type *rhs_type = type_unsigned_equivalent(x.type);
convert_to_typed(c, &y, rhs_type); if (y.mode == Addressing_Invalid) return false;
} else {
convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false;
}
}
if (!is_type_simd_vector(y.type)) {
gbString s = type_to_string(y.type);
error(y.expr, "'%.*s' expected a simd vector type or unsigned integer, got %s", LIT(builtin_name), s);
gb_string_free(s);
return false;
}
GB_ASSERT(x.type->kind == Type_SimdVector);
@@ -1706,15 +1716,25 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
}
Type *elem = base_array_type(x.type);
i64 count = get_array_type_count(x.type);
i64 sz = type_size_of(elem);
Type *bit_elem = nullptr;
switch (sz) {
case 1: bit_elem = t_u8; break;
case 2: bit_elem = t_u16; break;
case 4: bit_elem = t_u32; break;
case 8: bit_elem = t_u64; break;
Type *bit_elem = type_unsigned_equivalent(elem);
operand->type = alloc_type_simd_vector(count, bit_elem);
operand->mode = Addressing_Value;
return true;
}
case BuiltinProc_simd_to_bits_signed:
{
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;
}
GB_ASSERT(bit_elem != nullptr);
Type *elem = base_array_type(x.type);
i64 count = get_array_type_count(x.type);
Type *bit_elem = type_signed_equivalent(elem);
operand->type = alloc_type_simd_vector(count, bit_elem);
operand->mode = Addressing_Value;

View File

@@ -217,6 +217,7 @@ BuiltinProc__simd_begin,
BuiltinProc_simd_approx_recip_sqrt,
BuiltinProc_simd_to_bits,
BuiltinProc_simd_to_bits_signed,
BuiltinProc_simd_lanes_reverse,
BuiltinProc_simd_lanes_rotate_left,
@@ -614,6 +615,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("simd_approx_recip_sqrt"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_to_bits"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_to_bits_signed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_lanes_reverse"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_lanes_rotate_left"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},

View File

@@ -2500,6 +2500,7 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn
}
case BuiltinProc_simd_to_bits:
case BuiltinProc_simd_to_bits_signed:
{
res.value = LLVMBuildBitCast(p->builder, arg0.value, lb_type(m, tv.type), "");
return res;

View File

@@ -1332,6 +1332,8 @@ gb_internal bool is_type_integer_or_float(Type *t) {
return false;
}
gb_internal bool is_type_numeric(Type *t) {
t = base_type(t);
if (t == nullptr) { return false; }
@@ -1709,6 +1711,51 @@ gb_internal bool is_type_simd_vector(Type *t) {
return t->kind == Type_SimdVector;
}
gb_internal Type *type_unsigned_equivalent(Type *t) {
Type *original_type = t;
t = base_type(t);
if (is_type_simd_vector(t)) {
if (is_type_unsigned(t->SimdVector.elem)) {
return original_type;
}
return alloc_type_simd_vector(t->SimdVector.count, type_unsigned_equivalent(t->SimdVector.elem));
}
i64 sz = type_size_of(t);
switch (sz) {
case 1: return t_u8;
case 2: return t_u16;
case 4: return t_u32;
case 8: return t_u64;
case 16: return t_u128;
}
GB_PANIC("No known equivalent unsigned integer sized for %s", type_to_string(t));
return nullptr;
}
gb_internal Type *type_signed_equivalent(Type *t) {
Type *original_type = t;
t = base_type(t);
if (is_type_simd_vector(t)) {
if (!is_type_unsigned(t->SimdVector.elem)) {
return original_type;
}
return alloc_type_simd_vector(t->SimdVector.count, type_signed_equivalent(t->SimdVector.elem));
}
;
i64 sz = type_size_of(t);
switch (sz) {
case 1: return t_i8;
case 2: return t_i16;
case 4: return t_i32;
case 8: return t_i64;
case 16: return t_i128;
}
GB_PANIC("No known equivalent signed integer sized for %s", type_to_string(t));
return nullptr;
}
gb_internal Type *base_array_type(Type *t) {
Type *bt = base_type(t);
if (is_type_array(bt)) {