mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
Merge pull request #1807 from odin-lang/simd-dev
Generic #simd type and intrinsics
This commit is contained in:
@@ -6,12 +6,14 @@ package intrinsics
|
||||
is_package_imported :: proc(package_name: string) -> bool ---
|
||||
|
||||
// Types
|
||||
simd_vector :: proc($N: int, $T: typeid) -> type/#simd[N]T
|
||||
soa_struct :: proc($N: int, $T: typeid) -> type/#soa[N]T
|
||||
|
||||
// Volatile
|
||||
volatile_load :: proc(dst: ^$T) -> T ---
|
||||
volatile_store :: proc(dst: ^$T, val: T) -> T ---
|
||||
volatile_store :: proc(dst: ^$T, val: T) ---
|
||||
|
||||
non_temporal_load :: proc(dst: ^$T) -> T ---
|
||||
non_temporal_store :: proc(dst: ^$T, val: T) ---
|
||||
|
||||
// Trapping
|
||||
debug_trap :: proc() ---
|
||||
@@ -23,18 +25,20 @@ alloca :: proc(size, align: int) -> [^]u8 ---
|
||||
cpu_relax :: proc() ---
|
||||
read_cycle_counter :: proc() -> i64 ---
|
||||
|
||||
count_ones :: proc(x: $T) -> T where type_is_integer(T) ---
|
||||
count_zeros :: proc(x: $T) -> T where type_is_integer(T) ---
|
||||
count_trailing_zeros :: proc(x: $T) -> T where type_is_integer(T) ---
|
||||
count_leading_zeros :: proc(x: $T) -> T where type_is_integer(T) ---
|
||||
reverse_bits :: proc(x: $T) -> T where type_is_integer(T) ---
|
||||
count_ones :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) ---
|
||||
count_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) ---
|
||||
count_trailing_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) ---
|
||||
count_leading_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) ---
|
||||
reverse_bits :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) ---
|
||||
byte_swap :: proc(x: $T) -> T where type_is_integer(T) || type_is_float(T) ---
|
||||
|
||||
overflow_add :: proc(lhs, rhs: $T) -> (T, bool) #optional_ok ---
|
||||
overflow_sub :: proc(lhs, rhs: $T) -> (T, bool) #optional_ok ---
|
||||
overflow_mul :: proc(lhs, rhs: $T) -> (T, bool) #optional_ok ---
|
||||
|
||||
sqrt :: proc(x: $T) -> T where type_is_float(T) ---
|
||||
sqrt :: proc(x: $T) -> T where type_is_float(T) || (type_is_simd_vector(T) && type_is_float(type_elem_type(T))) ---
|
||||
|
||||
fused_mul_add :: proc(a, b, c: $T) -> T where type_is_float(T) || (type_is_simd_vector(T) && type_is_float(type_elem_type(T))) ---
|
||||
|
||||
mem_copy :: proc(dst, src: rawptr, len: int) ---
|
||||
mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) ---
|
||||
@@ -186,6 +190,81 @@ type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawpt
|
||||
|
||||
constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
|
||||
|
||||
// SIMD related
|
||||
simd_add :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_sub :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_mul :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_div :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_rem :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
// Keeps Odin's Behaviour
|
||||
// (x << y) if y <= mask else 0
|
||||
simd_shl :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T ---
|
||||
simd_shr :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T ---
|
||||
|
||||
// Similar to C's Behaviour
|
||||
// x << (y & mask)
|
||||
simd_shl_masked :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T ---
|
||||
simd_shr_masked :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T ---
|
||||
|
||||
simd_add_sat :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_sub_sat :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
simd_and :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_or :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_xor :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_and_not :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
simd_neg :: proc(a: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
simd_abs :: proc(a: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
simd_min :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_max :: proc(a, b: #simd[N]T) -> #simd[N]T ---
|
||||
simd_clamp :: proc(v, min, max: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
// Return an unsigned integer of the same size as the input type
|
||||
// NOT A BOOLEAN
|
||||
// element-wise:
|
||||
// false => 0x00...00
|
||||
// true => 0xff...ff
|
||||
simd_lanes_eq :: proc(a, b: #simd[N]T) -> #simd[N]Integer ---
|
||||
simd_lanes_ne :: proc(a, b: #simd[N]T) -> #simd[N]Integer ---
|
||||
simd_lanes_lt :: proc(a, b: #simd[N]T) -> #simd[N]Integer ---
|
||||
simd_lanes_le :: proc(a, b: #simd[N]T) -> #simd[N]Integer ---
|
||||
simd_lanes_gt :: proc(a, b: #simd[N]T) -> #simd[N]Integer ---
|
||||
simd_lanes_ge :: proc(a, b: #simd[N]T) -> #simd[N]Integer ---
|
||||
|
||||
simd_extract :: proc(a: #simd[N]T, idx: uint) -> T ---
|
||||
simd_replace :: proc(a: #simd[N]T, idx: uint, elem: T) -> #simd[N]T ---
|
||||
|
||||
simd_reduce_add_ordered :: proc(a: #simd[N]T) -> T ---
|
||||
simd_reduce_mul_ordered :: proc(a: #simd[N]T) -> T ---
|
||||
simd_reduce_min :: proc(a: #simd[N]T) -> T ---
|
||||
simd_reduce_max :: proc(a: #simd[N]T) -> T ---
|
||||
simd_reduce_and :: proc(a: #simd[N]T) -> T ---
|
||||
simd_reduce_or :: proc(a: #simd[N]T) -> T ---
|
||||
simd_reduce_xor :: proc(a: #simd[N]T) -> T ---
|
||||
|
||||
simd_shuffle :: proc(a, b: #simd[N]T, indices: ..int) -> #simd[len(indices)]T ---
|
||||
simd_select :: proc(cond: #simd[N]boolean_or_integer, true, false: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
// Lane-wise operations
|
||||
simd_ceil :: proc(a: #simd[N]any_float) -> #simd[N]any_float ---
|
||||
simd_floor :: proc(a: #simd[N]any_float) -> #simd[N]any_float ---
|
||||
simd_trunc :: proc(a: #simd[N]any_float) -> #simd[N]any_float ---
|
||||
// rounding to the nearest integral value; if two values are equally near, rounds to the even one
|
||||
simd_nearest :: proc(a: #simd[N]any_float) -> #simd[N]any_float ---
|
||||
|
||||
simd_to_bits :: proc(v: #simd[N]T) -> #simd[N]Integer where size_of(T) == size_of(Integer), type_is_unsigned(Integer) ---
|
||||
|
||||
// equivalent a swizzle with descending indices, e.g. reserve(a, 3, 2, 1, 0)
|
||||
simd_reverse :: proc(a: #simd[N]T) -> #simd[N]T ---
|
||||
|
||||
simd_rotate_left :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T ---
|
||||
simd_rotate_right :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T ---
|
||||
|
||||
|
||||
// WASM targets only
|
||||
wasm_memory_grow :: proc(index, delta: uintptr) -> int ---
|
||||
wasm_memory_size :: proc(index: uintptr) -> int ---
|
||||
@@ -199,6 +278,10 @@ wasm_memory_size :: proc(index: uintptr) -> int ---
|
||||
wasm_memory_atomic_wait32 :: proc(ptr: ^u32, expected: u32, timeout_ns: i64) -> u32 ---
|
||||
wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) ---
|
||||
|
||||
// x86 Targets (i386, amd64)
|
||||
x86_cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) ---
|
||||
x86_xgetbv :: proc(cx: u32) -> (eax, edx: u32) ---
|
||||
|
||||
|
||||
// Darwin targets only
|
||||
objc_object :: struct{}
|
||||
|
||||
@@ -21,6 +21,7 @@ make_any :: proc "contextless" (data: rawptr, id: typeid) -> any {
|
||||
}
|
||||
|
||||
raw_array_data :: runtime.raw_array_data
|
||||
raw_simd_data :: runtime.raw_simd_data
|
||||
raw_string_data :: runtime.raw_string_data
|
||||
raw_slice_data :: runtime.raw_slice_data
|
||||
raw_dynamic_array_data :: runtime.raw_dynamic_array_data
|
||||
|
||||
@@ -604,6 +604,10 @@ raw_array_data :: proc "contextless" (a: $P/^($T/[$N]$E)) -> [^]E {
|
||||
return ([^]E)(a)
|
||||
}
|
||||
@builtin
|
||||
raw_simd_data :: proc "contextless" (a: $P/^($T/#simd[$N]$E)) -> [^]E {
|
||||
return ([^]E)(a)
|
||||
}
|
||||
@builtin
|
||||
raw_slice_data :: proc "contextless" (s: $S/[]$E) -> [^]E {
|
||||
ptr := (transmute(Raw_Slice)s).data
|
||||
return ([^]E)(ptr)
|
||||
@@ -619,7 +623,7 @@ raw_string_data :: proc "contextless" (s: $S/string) -> [^]u8 {
|
||||
}
|
||||
|
||||
@builtin
|
||||
raw_data :: proc{raw_array_data, raw_slice_data, raw_dynamic_array_data, raw_string_data}
|
||||
raw_data :: proc{raw_array_data, raw_slice_data, raw_dynamic_array_data, raw_string_data, raw_simd_data}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
package simd
|
||||
|
||||
import "core:builtin"
|
||||
import "core:intrinsics"
|
||||
|
||||
// 128-bit vector aliases
|
||||
u8x16 :: #simd[16]u8
|
||||
i8x16 :: #simd[16]i8
|
||||
u16x8 :: #simd[8]u16
|
||||
i16x8 :: #simd[8]i16
|
||||
u32x4 :: #simd[4]u32
|
||||
i32x4 :: #simd[4]i32
|
||||
u64x2 :: #simd[2]u64
|
||||
i64x2 :: #simd[2]i64
|
||||
f32x4 :: #simd[4]f32
|
||||
f64x2 :: #simd[2]f64
|
||||
|
||||
boolx16 :: #simd[16]bool
|
||||
b8x16 :: #simd[16]b8
|
||||
b16x8 :: #simd[8]b16
|
||||
b32x4 :: #simd[4]b32
|
||||
b64x2 :: #simd[2]b64
|
||||
|
||||
// 256-bit vector aliases
|
||||
u8x32 :: #simd[32]u8
|
||||
i8x32 :: #simd[32]i8
|
||||
u16x16 :: #simd[16]u16
|
||||
i16x16 :: #simd[16]i16
|
||||
u32x8 :: #simd[8]u32
|
||||
i32x8 :: #simd[8]i32
|
||||
u64x4 :: #simd[4]u64
|
||||
i64x4 :: #simd[4]i64
|
||||
f32x8 :: #simd[8]f32
|
||||
f64x4 :: #simd[4]f64
|
||||
|
||||
boolx32 :: #simd[32]bool
|
||||
b8x32 :: #simd[32]b8
|
||||
b16x16 :: #simd[16]b16
|
||||
b32x8 :: #simd[8]b32
|
||||
b64x4 :: #simd[4]b64
|
||||
|
||||
// 512-bit vector aliases
|
||||
u8x64 :: #simd[64]u8
|
||||
i8x64 :: #simd[64]i8
|
||||
u16x32 :: #simd[32]u16
|
||||
i16x32 :: #simd[32]i16
|
||||
u32x16 :: #simd[16]u32
|
||||
i32x16 :: #simd[16]i32
|
||||
u64x8 :: #simd[8]u64
|
||||
i64x8 :: #simd[8]i64
|
||||
f32x16 :: #simd[16]f32
|
||||
f64x8 :: #simd[8]f64
|
||||
|
||||
boolx64 :: #simd[64]bool
|
||||
b8x64 :: #simd[64]b8
|
||||
b16x32 :: #simd[32]b16
|
||||
b32x16 :: #simd[16]b32
|
||||
b64x8 :: #simd[8]b64
|
||||
|
||||
|
||||
add :: intrinsics.simd_add
|
||||
sub :: intrinsics.simd_sub
|
||||
mul :: intrinsics.simd_mul
|
||||
div :: intrinsics.simd_div
|
||||
rem :: intrinsics.simd_rem // integers only
|
||||
|
||||
// Keeps Odin's Behaviour
|
||||
// (x << y) if y <= mask else 0
|
||||
shl :: intrinsics.simd_shl
|
||||
shr :: intrinsics.simd_shr
|
||||
|
||||
// Similar to C's Behaviour
|
||||
// x << (y & mask)
|
||||
shl_masked :: intrinsics.simd_shl_masked
|
||||
shr_masked :: intrinsics.simd_shr_masked
|
||||
|
||||
// Saturation Arithmetic
|
||||
add_sat :: intrinsics.simd_add_sat
|
||||
sub_sat :: intrinsics.simd_sub_sat
|
||||
|
||||
and :: intrinsics.simd_and
|
||||
or :: intrinsics.simd_or
|
||||
xor :: intrinsics.simd_xor
|
||||
and_not :: intrinsics.simd_and_not
|
||||
|
||||
neg :: intrinsics.simd_neg
|
||||
|
||||
abs :: intrinsics.simd_abs
|
||||
|
||||
min :: intrinsics.simd_min
|
||||
max :: intrinsics.simd_max
|
||||
clamp :: intrinsics.simd_clamp
|
||||
|
||||
// Return an unsigned integer of the same size as the input type
|
||||
// NOT A BOOLEAN
|
||||
// element-wise:
|
||||
// false => 0x00...00
|
||||
// true => 0xff...ff
|
||||
lanes_eq :: intrinsics.simd_lanes_eq
|
||||
lanes_ne :: intrinsics.simd_lanes_ne
|
||||
lanes_lt :: intrinsics.simd_lanes_lt
|
||||
lanes_le :: intrinsics.simd_lanes_le
|
||||
lanes_gt :: intrinsics.simd_lanes_gt
|
||||
lanes_ge :: intrinsics.simd_lanes_ge
|
||||
|
||||
// extract :: proc(a: #simd[N]T, idx: uint) -> T
|
||||
extract :: intrinsics.simd_extract
|
||||
// replace :: proc(a: #simd[N]T, idx: uint, elem: T) -> #simd[N]T
|
||||
replace :: intrinsics.simd_replace
|
||||
|
||||
reduce_add_ordered :: intrinsics.simd_reduce_add_ordered
|
||||
reduce_mul_ordered :: intrinsics.simd_reduce_mul_ordered
|
||||
reduce_min :: intrinsics.simd_reduce_min
|
||||
reduce_max :: intrinsics.simd_reduce_max
|
||||
reduce_and :: intrinsics.simd_reduce_and
|
||||
reduce_or :: intrinsics.simd_reduce_or
|
||||
reduce_xor :: intrinsics.simd_reduce_xor
|
||||
|
||||
// swizzle :: proc(a: #simd[N]T, indices: ..int) -> #simd[len(indices)]T
|
||||
swizzle :: builtin.swizzle
|
||||
|
||||
// shuffle :: proc(a, b: #simd[N]T, indices: #simd[max 2*N]u32) -> #simd[len(indices)]T
|
||||
shuffle :: intrinsics.simd_shuffle
|
||||
|
||||
// select :: proc(cond: #simd[N]boolean_or_integer, true, false: #simd[N]T) -> #simd[N]T
|
||||
select :: intrinsics.simd_select
|
||||
|
||||
|
||||
sqrt :: intrinsics.sqrt
|
||||
ceil :: intrinsics.simd_ceil
|
||||
floor :: intrinsics.simd_floor
|
||||
trunc :: intrinsics.simd_trunc
|
||||
nearest :: intrinsics.simd_nearest
|
||||
|
||||
to_bits :: intrinsics.simd_to_bits
|
||||
|
||||
lanes_reverse :: intrinsics.simd_lanes_reverse
|
||||
|
||||
lanes_rotate_left :: intrinsics.simd_lanes_rotate_left
|
||||
lanes_rotate_right :: intrinsics.simd_lanes_rotate_right
|
||||
|
||||
count_ones :: intrinsics.count_ones
|
||||
count_zeros :: intrinsics.count_zeros
|
||||
count_trailing_zeros :: intrinsics.count_trailing_zeros
|
||||
count_leading_zeros :: intrinsics.count_leading_zeros
|
||||
reverse_bits :: intrinsics.reverse_bits
|
||||
|
||||
fused_mul_add :: intrinsics.fused_mul_add
|
||||
fma :: intrinsics.fused_mul_add
|
||||
|
||||
to_array_ptr :: #force_inline proc "contextless" (v: ^#simd[$LANES]$E) -> ^[LANES]E {
|
||||
return (^[LANES]E)(v)
|
||||
}
|
||||
to_array :: #force_inline proc "contextless" (v: #simd[$LANES]$E) -> [LANES]E {
|
||||
return transmute([LANES]E)(v)
|
||||
}
|
||||
from_array :: #force_inline proc "contextless" (v: $A/[$LANES]$E) -> #simd[LANES]E {
|
||||
return transmute(#simd[LANES]E)v
|
||||
}
|
||||
|
||||
from_slice :: proc($T: typeid/#simd[$LANES]$E, slice: []E) -> T {
|
||||
assert(len(slice) >= LANES, "slice length must be a least the number of lanes")
|
||||
array: [LANES]E
|
||||
#no_bounds_check for i in 0..<LANES {
|
||||
array[i] = slice[i]
|
||||
}
|
||||
return transmute(T)array
|
||||
}
|
||||
|
||||
bit_not :: #force_inline proc "contextless" (v: $T/#simd[$LANES]$E) -> T where intrinsics.type_is_integer(E) {
|
||||
return xor(v, T(~E(0)))
|
||||
}
|
||||
|
||||
copysign :: #force_inline proc "contextless" (v, sign: $T/#simd[$LANES]$E) -> T where intrinsics.type_is_float(E) {
|
||||
neg_zero := to_bits(T(-0.0))
|
||||
sign_bit := to_bits(sign) & neg_zero
|
||||
magnitude := to_bits(v) &~ neg_zero
|
||||
return transmute(T)(sign_bit|magnitude)
|
||||
}
|
||||
|
||||
signum :: #force_inline proc "contextless" (v: $T/#simd[$LANES]$E) -> T where intrinsics.type_is_float(E) {
|
||||
is_nan := lanes_ne(v, v)
|
||||
return select(is_nan, v, copysign(T(1), v))
|
||||
}
|
||||
|
||||
recip :: #force_inline proc "contextless" (v: $T/#simd[$LANES]$E) -> T where intrinsics.type_is_float(E) {
|
||||
return T(1) / v
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
@(require_results, enable_target_feature="lzcnt")
|
||||
_lzcnt_u32 :: #force_inline proc "c" (x: u32) -> u32 {
|
||||
return intrinsics.count_leading_zeros(x)
|
||||
}
|
||||
@(require_results, enable_target_feature="popcnt")
|
||||
_popcnt32 :: #force_inline proc "c" (x: u32) -> i32 {
|
||||
return i32(intrinsics.count_ones(x))
|
||||
}
|
||||
|
||||
when ODIN_ARCH == .amd64 {
|
||||
@(require_results, enable_target_feature="lzcnt")
|
||||
_lzcnt_u64 :: #force_inline proc "c" (x: u64) -> u64 {
|
||||
return intrinsics.count_leading_zeros(x)
|
||||
}
|
||||
@(require_results, enable_target_feature="popcnt")
|
||||
_popcnt64 :: #force_inline proc "c" (x: u64) -> i32 {
|
||||
return i32(intrinsics.count_ones(x))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
@(require_results)
|
||||
_addcarry_u32 :: #force_inline proc "c" (c_in: u8, a: u32, b: u32, out: ^u32) -> u8 {
|
||||
x, y := llvm_addcarry_u32(c_in, a, b)
|
||||
out^ = y
|
||||
return x
|
||||
}
|
||||
@(require_results)
|
||||
_addcarryx_u32 :: #force_inline proc "c" (c_in: u8, a: u32, b: u32, out: ^u32) -> u8 {
|
||||
return llvm_addcarryx_u32(c_in, a, b, out)
|
||||
}
|
||||
@(require_results)
|
||||
_subborrow_u32 :: #force_inline proc "c" (c_in: u8, a: u32, b: u32, out: ^u32) -> u8 {
|
||||
x, y := llvm_subborrow_u32(c_in, a, b)
|
||||
out^ = y
|
||||
return x
|
||||
}
|
||||
|
||||
when ODIN_ARCH == .amd64 {
|
||||
@(require_results)
|
||||
_addcarry_u64 :: #force_inline proc "c" (c_in: u8, a: u64, b: u64, out: ^u64) -> u8 {
|
||||
x, y := llvm_addcarry_u64(c_in, a, b)
|
||||
out^ = y
|
||||
return x
|
||||
}
|
||||
@(require_results)
|
||||
_addcarryx_u64 :: #force_inline proc "c" (c_in: u8, a: u64, b: u64, out: ^u64) -> u8 {
|
||||
return llvm_addcarryx_u64(c_in, a, b, out)
|
||||
}
|
||||
@(require_results)
|
||||
_subborrow_u64 :: #force_inline proc "c" (c_in: u8, a: u64, b: u64, out: ^u64) -> u8 {
|
||||
x, y := llvm_subborrow_u64(c_in, a, b)
|
||||
out^ = y
|
||||
return x
|
||||
}
|
||||
}
|
||||
|
||||
@(private, default_calling_convention="c")
|
||||
foreign _ {
|
||||
@(link_name="llvm.x86.addcarry.32")
|
||||
llvm_addcarry_u32 :: proc(a: u8, b: u32, c: u32) -> (u8, u32) ---
|
||||
@(link_name="llvm.x86.addcarryx.u32")
|
||||
llvm_addcarryx_u32 :: proc(a: u8, b: u32, c: u32, d: rawptr) -> u8 ---
|
||||
@(link_name="llvm.x86.subborrow.32")
|
||||
llvm_subborrow_u32 :: proc(a: u8, b: u32, c: u32) -> (u8, u32) ---
|
||||
|
||||
// amd64 only
|
||||
@(link_name="llvm.x86.addcarry.64")
|
||||
llvm_addcarry_u64 :: proc(a: u8, b: u64, c: u64) -> (u8, u64) ---
|
||||
@(link_name="llvm.x86.addcarryx.u64")
|
||||
llvm_addcarryx_u64 :: proc(a: u8, b: u64, c: u64, d: rawptr) -> u8 ---
|
||||
@(link_name="llvm.x86.subborrow.64")
|
||||
llvm_subborrow_u64 :: proc(a: u8, b: u64, c: u64) -> (u8, u64) ---
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
//+build amd64
|
||||
package simd_x86
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
cmpxchg16b :: #force_inline proc "c" (dst: ^u128, old, new: u128, $success, $failure: intrinsics.Atomic_Memory_Order) -> (val: u128) {
|
||||
return intrinsics.atomic_compare_exchange_strong_explicit(dst, old, new, success, failure)
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
// cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) ---
|
||||
cpuid :: intrinsics.x86_cpuid
|
||||
|
||||
// xgetbv :: proc(cx: u32) -> (eax, edx: u32) ---
|
||||
xgetbv :: intrinsics.x86_xgetbv
|
||||
|
||||
|
||||
CPU_Feature :: enum u64 {
|
||||
aes, // AES hardware implementation (AES NI)
|
||||
adx, // Multi-precision add-carry instruction extensions
|
||||
avx, // Advanced vector extension
|
||||
avx2, // Advanced vector extension 2
|
||||
bmi1, // Bit manipulation instruction set 1
|
||||
bmi2, // Bit manipulation instruction set 2
|
||||
erms, // Enhanced REP for MOVSB and STOSB
|
||||
fma, // Fused-multiply-add instructions
|
||||
os_xsave, // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
|
||||
pclmulqdq, // PCLMULQDQ instruction - most often used for AES-GCM
|
||||
popcnt, // Hamming weight instruction POPCNT.
|
||||
rdrand, // RDRAND instruction (on-chip random number generator)
|
||||
rdseed, // RDSEED instruction (on-chip random number generator)
|
||||
sse2, // Streaming SIMD extension 2 (always available on amd64)
|
||||
sse3, // Streaming SIMD extension 3
|
||||
ssse3, // Supplemental streaming SIMD extension 3
|
||||
sse41, // Streaming SIMD extension 4 and 4.1
|
||||
sse42, // Streaming SIMD extension 4 and 4.2
|
||||
}
|
||||
|
||||
CPU_Features :: distinct bit_set[CPU_Feature; u64]
|
||||
|
||||
cpu_features: Maybe(CPU_Features)
|
||||
|
||||
@(init, private)
|
||||
init_cpu_features :: proc "c" () {
|
||||
is_set :: #force_inline proc "c" (hwc: u32, value: u32) -> bool {
|
||||
return hwc&value != 0
|
||||
}
|
||||
try_set :: #force_inline proc "c" (set: ^CPU_Features, feature: CPU_Feature, hwc: u32, value: u32) {
|
||||
if is_set(hwc, value) {
|
||||
set^ += {feature}
|
||||
}
|
||||
}
|
||||
|
||||
max_id, _, _, _ := cpuid(0, 0)
|
||||
if max_id < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
set: CPU_Features
|
||||
|
||||
_, _, ecx1, edx1 := cpuid(1, 0)
|
||||
|
||||
try_set(&set, .sse2, 26, edx1)
|
||||
try_set(&set, .sse3, 0, ecx1)
|
||||
try_set(&set, .pclmulqdq, 1, ecx1)
|
||||
try_set(&set, .ssse3, 9, ecx1)
|
||||
try_set(&set, .fma, 12, ecx1)
|
||||
try_set(&set, .sse41, 19, ecx1)
|
||||
try_set(&set, .sse42, 20, ecx1)
|
||||
try_set(&set, .popcnt, 23, ecx1)
|
||||
try_set(&set, .aes, 25, ecx1)
|
||||
try_set(&set, .os_xsave, 27, ecx1)
|
||||
try_set(&set, .rdrand, 30, ecx1)
|
||||
|
||||
os_supports_avx := false
|
||||
if .os_xsave in set {
|
||||
eax, _ := xgetbv(0)
|
||||
os_supports_avx = is_set(1, eax) && is_set(2, eax)
|
||||
}
|
||||
if os_supports_avx {
|
||||
try_set(&set, .avx, 28, ecx1)
|
||||
}
|
||||
|
||||
if max_id < 7 {
|
||||
return
|
||||
}
|
||||
|
||||
_, ebx7, _, _ := cpuid(7, 0)
|
||||
try_set(&set, .bmi1, 3, ebx7)
|
||||
if os_supports_avx {
|
||||
try_set(&set, .avx2, 5, ebx7)
|
||||
}
|
||||
try_set(&set, .bmi2, 8, ebx7)
|
||||
try_set(&set, .erms, 9, ebx7)
|
||||
try_set(&set, .rdseed, 18, ebx7)
|
||||
try_set(&set, .adx, 19, ebx7)
|
||||
|
||||
cpu_features = set
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
@(enable_target_feature="fxsr")
|
||||
_fxsave :: #force_inline proc "c" (mem_addr: rawptr) {
|
||||
fxsave(mem_addr)
|
||||
}
|
||||
@(enable_target_feature="fxsr")
|
||||
_fxrstor :: #force_inline proc "c" (mem_addr: rawptr) {
|
||||
fxrstor(mem_addr)
|
||||
}
|
||||
|
||||
when ODIN_ARCH == .amd64 {
|
||||
@(enable_target_feature="fxsr")
|
||||
_fxsave64 :: #force_inline proc "c" (mem_addr: rawptr) {
|
||||
fxsave64(mem_addr)
|
||||
}
|
||||
@(enable_target_feature="fxsr")
|
||||
_fxrstor64 :: #force_inline proc "c" (mem_addr: rawptr) {
|
||||
fxrstor64(mem_addr)
|
||||
}
|
||||
}
|
||||
|
||||
@(private, default_calling_convention="c")
|
||||
foreign _ {
|
||||
@(link_name="llvm.x86.fxsave")
|
||||
fxsave :: proc(p: rawptr) ---
|
||||
@(link_name="llvm.x86.fxrstor")
|
||||
fxrstor :: proc(p: rawptr) ---
|
||||
|
||||
// amd64 only
|
||||
@(link_name="llvm.x86.fxsave64")
|
||||
fxsave64 :: proc(p: rawptr) ---
|
||||
@(link_name="llvm.x86.fxrstor64")
|
||||
fxrstor64 :: proc(p: rawptr) ---
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
@(require_results, enable_target_feature="pclmulqdq")
|
||||
_mm_clmulepi64_si128 :: #force_inline proc "c" (a, b: __m128i, $IMM8: u8) -> __m128i {
|
||||
return pclmulqdq(a, b, u8(IMM8))
|
||||
}
|
||||
|
||||
@(private, default_calling_convention="c")
|
||||
foreign _ {
|
||||
@(link_name="llvm.x86.pclmulqdq")
|
||||
pclmulqdq :: proc(a, round_key: __m128i, #const imm8: u8) -> __m128i ---
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
@(require_results)
|
||||
_rdtsc :: #force_inline proc "c" () -> u64 {
|
||||
return rdtsc()
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
__rdtscp :: #force_inline proc "c" (aux: ^u32) -> u64 {
|
||||
return rdtscp(aux)
|
||||
}
|
||||
|
||||
@(private, default_calling_convention="c")
|
||||
foreign _ {
|
||||
@(link_name="llvm.x86.rdtsc")
|
||||
rdtsc :: proc() -> u64 ---
|
||||
@(link_name="llvm.x86.rdtscp")
|
||||
rdtscp :: proc(aux: rawptr) -> u64 ---
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
@(require_results, enable_target_feature="sha")
|
||||
_mm_sha1msg1_epu32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)sha1msg1(transmute(i32x4)a, transmute(i32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sha")
|
||||
_mm_sha1msg2_epu32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)sha1msg2(transmute(i32x4)a, transmute(i32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sha")
|
||||
_mm_sha1nexte_epu32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)sha1nexte(transmute(i32x4)a, transmute(i32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sha")
|
||||
_mm_sha1rnds4_epu32 :: #force_inline proc "c" (a, b: __m128i, $FUNC: u32) -> __m128i where 0 <= FUNC, FUNC <= 3 {
|
||||
return transmute(__m128i)sha1rnds4(transmute(i32x4)a, transmute(i32x4)b, u8(FUNC & 0xff))
|
||||
}
|
||||
@(require_results, enable_target_feature="sha")
|
||||
_mm_sha256msg1_epu32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)sha256msg1(transmute(i32x4)a, transmute(i32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sha")
|
||||
_mm_sha256msg2_epu32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)sha256msg2(transmute(i32x4)a, transmute(i32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sha")
|
||||
_mm_sha256rnds2_epu32 :: #force_inline proc "c" (a, b, k: __m128i) -> __m128i {
|
||||
return transmute(__m128i)sha256rnds2(transmute(i32x4)a, transmute(i32x4)b, transmute(i32x4)k)
|
||||
}
|
||||
|
||||
@(private, default_calling_convention="c")
|
||||
foreign _ {
|
||||
@(link_name="llvm.x86.sha1msg1")
|
||||
sha1msg1 :: proc(a, b: i32x4) -> i32x4 ---
|
||||
@(link_name="llvm.x86.sha1msg2")
|
||||
sha1msg2 :: proc(a, b: i32x4) -> i32x4 ---
|
||||
@(link_name="llvm.x86.sha1nexte")
|
||||
sha1nexte :: proc(a, b: i32x4) -> i32x4 ---
|
||||
@(link_name="llvm.x86.sha1rnds4")
|
||||
sha1rnds4 :: proc(a, b: i32x4, #const c: u8) -> i32x4 ---
|
||||
@(link_name="llvm.x86.sha256msg1")
|
||||
sha256msg1 :: proc(a, b: i32x4) -> i32x4 ---
|
||||
@(link_name="llvm.x86.sha256msg2")
|
||||
sha256msg2 :: proc(a, b: i32x4) -> i32x4 ---
|
||||
@(link_name="llvm.x86.sha256rnds2")
|
||||
sha256rnds2 :: proc(a, b, k: i32x4) -> i32x4 ---
|
||||
}
|
||||
@@ -0,0 +1,618 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:simd"
|
||||
|
||||
// _MM_SHUFFLE(z, y, x, w) -> (z<<6 | y<<4 | x<<2 | w)
|
||||
_MM_SHUFFLE :: intrinsics.simd_x86__MM_SHUFFLE
|
||||
|
||||
_MM_HINT_T0 :: 3
|
||||
_MM_HINT_T1 :: 2
|
||||
_MM_HINT_T2 :: 1
|
||||
_MM_HINT_NTA :: 0
|
||||
_MM_HINT_ET0 :: 7
|
||||
_MM_HINT_ET1 :: 6
|
||||
|
||||
|
||||
_MM_EXCEPT_INVALID :: 0x0001
|
||||
_MM_EXCEPT_DENORM :: 0x0002
|
||||
_MM_EXCEPT_DIV_ZERO :: 0x0004
|
||||
_MM_EXCEPT_OVERFLOW :: 0x0008
|
||||
_MM_EXCEPT_UNDERFLOW :: 0x0010
|
||||
_MM_EXCEPT_INEXACT :: 0x0020
|
||||
_MM_EXCEPT_MASK :: 0x003f
|
||||
|
||||
_MM_MASK_INVALID :: 0x0080
|
||||
_MM_MASK_DENORM :: 0x0100
|
||||
_MM_MASK_DIV_ZERO :: 0x0200
|
||||
_MM_MASK_OVERFLOW :: 0x0400
|
||||
_MM_MASK_UNDERFLOW :: 0x0800
|
||||
_MM_MASK_INEXACT :: 0x1000
|
||||
_MM_MASK_MASK :: 0x1f80
|
||||
|
||||
_MM_ROUND_NEAREST :: 0x0000
|
||||
_MM_ROUND_DOWN :: 0x2000
|
||||
_MM_ROUND_UP :: 0x4000
|
||||
_MM_ROUND_TOWARD_ZERO :: 0x6000
|
||||
|
||||
_MM_ROUND_MASK :: 0x6000
|
||||
|
||||
_MM_FLUSH_ZERO_MASK :: 0x8000
|
||||
_MM_FLUSH_ZERO_ON :: 0x8000
|
||||
_MM_FLUSH_ZERO_OFF :: 0x0000
|
||||
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_add_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return addss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_add_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return simd.add(a, b)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_sub_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return subss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_sub_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return simd.sub(a, b)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_mul_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return mulss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_mul_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return simd.mul(a, b)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_div_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return divss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_div_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return simd.div(a, b)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_sqrt_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return sqrtss(a)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_sqrt_ps :: #force_inline proc "c" (a: __m128) -> __m128 {
|
||||
return sqrtps(a)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_rcp_ss :: #force_inline proc "c" (a: __m128) -> __m128 {
|
||||
return rcpss(a)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_rcp_ps :: #force_inline proc "c" (a: __m128) -> __m128 {
|
||||
return rcpps(a)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_rsqrt_ss :: #force_inline proc "c" (a: __m128) -> __m128 {
|
||||
return rsqrtss(a)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_rsqrt_ps :: #force_inline proc "c" (a: __m128) -> __m128 {
|
||||
return rsqrtps(a)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_min_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return minss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_min_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return minps(a, b)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_max_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return maxss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_max_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return maxps(a, b)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_and_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return transmute(__m128)simd.and(transmute(__m128i)a, transmute(__m128i)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_andnot_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return transmute(__m128)simd.and_not(transmute(__m128i)a, transmute(__m128i)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_or_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return transmute(__m128)simd.or(transmute(__m128i)a, transmute(__m128i)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_xor_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return transmute(__m128)simd.xor(transmute(__m128i)a, transmute(__m128i)b)
|
||||
}
|
||||
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpeq_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpss(a, b, 0)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmplt_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpss(a, b, 1)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmple_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpss(a, b, 2)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpgt_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return simd.shuffle(a, cmpss(b, a, 1), 4, 1, 2, 3)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpge_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return simd.shuffle(a, cmpss(b, a, 2), 4, 1, 2, 3)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpneq_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpss(a, b, 4)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpnlt_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpss(a, b, 5)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpnle_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpss(a, b, 6)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpngt_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return simd.shuffle(a, cmpss(b, a, 5), 4, 1, 2, 3)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpnge_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return simd.shuffle(a, cmpss(b, a, 6), 4, 1, 2, 3)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpord_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpss(a, b, 7)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpunord_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpss(a, b, 3)
|
||||
}
|
||||
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpeq_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpps(a, b, 0)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmplt_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpps(a, b, 1)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmple_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpps(a, b, 2)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpgt_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpps(b, a, 1)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpge_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpps(b, a, 2)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpneq_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpps(a, b, 4)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpnlt_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpps(a, b, 5)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpnle_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpps(a, b, 6)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpngt_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpps(b, a, 5)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpnge_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpps(b, a, 6)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpord_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpps(b, a, 7)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cmpunord_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return cmpps(b, a, 3)
|
||||
}
|
||||
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_comieq_ss :: #force_inline proc "c" (a, b: __m128) -> b32 {
|
||||
return comieq_ss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_comilt_ss :: #force_inline proc "c" (a, b: __m128) -> b32 {
|
||||
return comilt_ss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_comile_ss :: #force_inline proc "c" (a, b: __m128) -> b32 {
|
||||
return comile_ss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_comigt_ss :: #force_inline proc "c" (a, b: __m128) -> b32 {
|
||||
return comigt_ss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_comige_ss :: #force_inline proc "c" (a, b: __m128) -> b32 {
|
||||
return comige_ss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_comineq_ss :: #force_inline proc "c" (a, b: __m128) -> b32 {
|
||||
return comineq_ss(a, b)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_ucomieq_ss :: #force_inline proc "c" (a, b: __m128) -> b32 {
|
||||
return ucomieq_ss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_ucomilt_ss :: #force_inline proc "c" (a, b: __m128) -> b32 {
|
||||
return ucomilt_ss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_ucomile_ss :: #force_inline proc "c" (a, b: __m128) -> b32 {
|
||||
return ucomile_ss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_ucomigt_ss :: #force_inline proc "c" (a, b: __m128) -> b32 {
|
||||
return ucomigt_ss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_ucomige_ss :: #force_inline proc "c" (a, b: __m128) -> b32 {
|
||||
return ucomige_ss(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_ucomineq_ss :: #force_inline proc "c" (a, b: __m128) -> b32 {
|
||||
return ucomineq_ss(a, b)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cvtss_si32 :: #force_inline proc "c" (a: __m128) -> i32 {
|
||||
return cvtss2si(a)
|
||||
}
|
||||
_mm_cvt_ss2si :: _mm_cvtss_si32
|
||||
_mm_cvttss_si32 :: _mm_cvtss_si32
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cvtss_f32 :: #force_inline proc "c" (a: __m128) -> f32 {
|
||||
return simd.extract(a, 0)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cvtsi32_ss :: #force_inline proc "c" (a: __m128, b: i32) -> __m128 {
|
||||
return cvtsi2ss(a, b)
|
||||
}
|
||||
_mm_cvt_si2ss :: _mm_cvtsi32_ss
|
||||
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_set_ss :: #force_inline proc "c" (a: f32) -> __m128 {
|
||||
return __m128{a, 0, 0, 0}
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_set1_ps :: #force_inline proc "c" (a: f32) -> __m128 {
|
||||
return __m128(a)
|
||||
}
|
||||
_mm_set_ps1 :: _mm_set1_ps
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_set_ps :: #force_inline proc "c" (a, b, c, d: f32) -> __m128 {
|
||||
return __m128{d, c, b, a}
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_setr_ps :: #force_inline proc "c" (a, b, c, d: f32) -> __m128 {
|
||||
return __m128{a, b, c, d}
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_setzero_ps :: #force_inline proc "c" () -> __m128 {
|
||||
return __m128{0, 0, 0, 0}
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_shuffle_ps :: #force_inline proc "c" (a, b: __m128, $MASK: u32) -> __m128 {
|
||||
return simd.shuffle(
|
||||
a, b,
|
||||
u32(MASK) & 0b11,
|
||||
(u32(MASK)>>2) & 0b11,
|
||||
((u32(MASK)>>4) & 0b11)+4,
|
||||
((u32(MASK)>>6) & 0b11)+4)
|
||||
}
|
||||
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_unpackhi_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return simd.shuffle(a, b, 2, 6, 3, 7)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_unpacklo_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return simd.shuffle(a, b, 0, 4, 1, 5)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_movehl_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return simd.shuffle(a, b, 6, 7, 2, 3)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_movelh_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return simd.shuffle(a, b, 0, 1, 4, 5)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_movemask_ps :: #force_inline proc "c" (a: __m128) -> u32 {
|
||||
return movmskps(a)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_load_ss :: #force_inline proc "c" (p: ^f32) -> __m128 {
|
||||
return __m128{p^, 0, 0, 0}
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_load1_ps :: #force_inline proc "c" (p: ^f32) -> __m128 {
|
||||
a := p^
|
||||
return __m128(a)
|
||||
}
|
||||
_mm_load_ps1 :: _mm_load1_ps
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_load_ps :: #force_inline proc "c" (p: [^]f32) -> __m128 {
|
||||
return (^__m128)(p)^
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_loadu_ps :: #force_inline proc "c" (p: [^]f32) -> __m128 {
|
||||
dst := _mm_undefined_ps()
|
||||
intrinsics.mem_copy_non_overlapping(&dst, p, size_of(__m128))
|
||||
return dst
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_loadr_ps :: #force_inline proc "c" (p: [^]f32) -> __m128 {
|
||||
return simd.lanes_reverse(_mm_load_ps(p))
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_loadu_si64 :: #force_inline proc "c" (mem_addr: rawptr) -> __m128i {
|
||||
a := intrinsics.unaligned_load((^i64)(mem_addr))
|
||||
return __m128i{a, 0}
|
||||
}
|
||||
|
||||
@(enable_target_feature="sse")
|
||||
_mm_store_ss :: #force_inline proc "c" (p: ^f32, a: __m128) {
|
||||
p^ = simd.extract(a, 0)
|
||||
}
|
||||
|
||||
@(enable_target_feature="sse")
|
||||
_mm_store1_ps :: #force_inline proc "c" (p: [^]f32, a: __m128) {
|
||||
b := simd.swizzle(a, 0, 0, 0, 0)
|
||||
(^__m128)(p)^ = b
|
||||
}
|
||||
_mm_store_ps1 :: _mm_store1_ps
|
||||
|
||||
|
||||
@(enable_target_feature="sse")
|
||||
_mm_store_ps :: #force_inline proc "c" (p: [^]f32, a: __m128) {
|
||||
(^__m128)(p)^ = a
|
||||
}
|
||||
@(enable_target_feature="sse")
|
||||
_mm_storeu_ps :: #force_inline proc "c" (p: [^]f32, a: __m128) {
|
||||
b := a
|
||||
intrinsics.mem_copy_non_overlapping(p, &b, size_of(__m128))
|
||||
}
|
||||
@(enable_target_feature="sse")
|
||||
_mm_storer_ps :: #force_inline proc "c" (p: [^]f32, a: __m128) {
|
||||
(^__m128)(p)^ = simd.lanes_reverse(a)
|
||||
}
|
||||
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_move_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return simd.shuffle(a, b, 4, 1, 2, 3)
|
||||
}
|
||||
|
||||
@(enable_target_feature="sse")
|
||||
_mm_sfence :: #force_inline proc "c" () {
|
||||
sfence()
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_getcsr :: #force_inline proc "c" () -> (result: u32) {
|
||||
stmxcsr(&result)
|
||||
return result
|
||||
}
|
||||
|
||||
@(enable_target_feature="sse")
|
||||
_mm_setcsr :: #force_inline proc "c" (val: u32) {
|
||||
val := val
|
||||
ldmxcsr(&val)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_MM_GET_EXCEPTION_MASK :: #force_inline proc "c" () -> u32 {
|
||||
return _mm_getcsr() & _MM_MASK_MASK
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_MM_GET_EXCEPTION_STATE :: #force_inline proc "c" () -> u32 {
|
||||
return _mm_getcsr() & _MM_EXCEPT_MASK
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_MM_GET_FLUSH_ZERO_MODE :: #force_inline proc "c" () -> u32 {
|
||||
return _mm_getcsr() & _MM_FLUSH_ZERO_MASK
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_MM_GET_ROUNDING_MODE :: #force_inline proc "c" () -> u32 {
|
||||
return _mm_getcsr() & _MM_ROUND_MASK
|
||||
}
|
||||
|
||||
@(enable_target_feature="sse")
|
||||
_MM_SET_EXCEPTION_MASK :: #force_inline proc "c" (x: u32) {
|
||||
_mm_setcsr((_mm_getcsr() &~ _MM_MASK_MASK) | x)
|
||||
}
|
||||
@(enable_target_feature="sse")
|
||||
_MM_SET_EXCEPTION_STATE :: #force_inline proc "c" (x: u32) {
|
||||
_mm_setcsr((_mm_getcsr() &~ _MM_EXCEPT_MASK) | x)
|
||||
}
|
||||
@(enable_target_feature="sse")
|
||||
_MM_SET_FLUSH_ZERO_MODE :: #force_inline proc "c" (x: u32) {
|
||||
_mm_setcsr((_mm_getcsr() &~ _MM_FLUSH_ZERO_MASK) | x)
|
||||
}
|
||||
@(enable_target_feature="sse")
|
||||
_MM_SET_ROUNDING_MODE :: #force_inline proc "c" (x: u32) {
|
||||
_mm_setcsr((_mm_getcsr() &~ _MM_ROUND_MASK) | x)
|
||||
}
|
||||
|
||||
@(enable_target_feature="sse")
|
||||
_mm_prefetch :: #force_inline proc "c" (p: rawptr, $STRATEGY: u32) {
|
||||
prefetch(p, (STRATEGY>>2)&1, STRATEGY&3, 1)
|
||||
}
|
||||
|
||||
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_undefined_ps :: #force_inline proc "c" () -> __m128 {
|
||||
return _mm_set1_ps(0)
|
||||
}
|
||||
|
||||
@(enable_target_feature="sse")
|
||||
_MM_TRANSPOSE4_PS :: #force_inline proc "c" (row0, row1, row2, row3: ^__m128) {
|
||||
tmp0 := _mm_unpacklo_ps(row0^, row1^)
|
||||
tmp1 := _mm_unpacklo_ps(row2^, row3^)
|
||||
tmp2 := _mm_unpackhi_ps(row0^, row1^)
|
||||
tmp3 := _mm_unpackhi_ps(row2^, row3^)
|
||||
|
||||
row0^ = _mm_movelh_ps(tmp0, tmp2)
|
||||
row1^ = _mm_movelh_ps(tmp2, tmp0)
|
||||
row2^ = _mm_movelh_ps(tmp1, tmp3)
|
||||
row3^ = _mm_movelh_ps(tmp3, tmp1)
|
||||
}
|
||||
|
||||
@(enable_target_feature="sse")
|
||||
_mm_stream_ps :: #force_inline proc "c" (addr: [^]f32, a: __m128) {
|
||||
intrinsics.non_temporal_store((^__m128)(addr), a)
|
||||
}
|
||||
|
||||
when ODIN_ARCH == .amd64 {
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cvtss_si64 :: #force_inline proc "c"(a: __m128) -> i64 {
|
||||
return cvtss2si64(a)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cvttss_si64 :: #force_inline proc "c"(a: __m128) -> i64 {
|
||||
return cvttss2si64(a)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse")
|
||||
_mm_cvtsi64_ss :: #force_inline proc "c"(a: __m128, b: i64) -> __m128 {
|
||||
return cvtsi642ss(a, b)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@(private, default_calling_convention="c")
|
||||
foreign _ {
|
||||
@(link_name="llvm.x86.sse.add.ss")
|
||||
addss :: proc(a, b: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.sub.ss")
|
||||
subss :: proc(a, b: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.mul.ss")
|
||||
mulss :: proc(a, b: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.div.ss")
|
||||
divss :: proc(a, b: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.sqrt.ss")
|
||||
sqrtss :: proc(a: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.sqrt.ps")
|
||||
sqrtps :: proc(a: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.rcp.ss")
|
||||
rcpss :: proc(a: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.rcp.ps")
|
||||
rcpps :: proc(a: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.rsqrt.ss")
|
||||
rsqrtss :: proc(a: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.rsqrt.ps")
|
||||
rsqrtps :: proc(a: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.min.ss")
|
||||
minss :: proc(a, b: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.min.ps")
|
||||
minps :: proc(a, b: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.max.ss")
|
||||
maxss :: proc(a, b: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.max.ps")
|
||||
maxps :: proc(a, b: __m128) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.movmsk.ps")
|
||||
movmskps :: proc(a: __m128) -> u32 ---
|
||||
@(link_name="llvm.x86.sse.cmp.ps")
|
||||
cmpps :: proc(a, b: __m128, #const imm8: u8) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.comieq.ss")
|
||||
comieq_ss :: proc(a, b: __m128) -> b32 ---
|
||||
@(link_name="llvm.x86.sse.comilt.ss")
|
||||
comilt_ss :: proc(a, b: __m128) -> b32 ---
|
||||
@(link_name="llvm.x86.sse.comile.ss")
|
||||
comile_ss :: proc(a, b: __m128) -> b32 ---
|
||||
@(link_name="llvm.x86.sse.comigt.ss")
|
||||
comigt_ss :: proc(a, b: __m128) -> b32 ---
|
||||
@(link_name="llvm.x86.sse.comige.ss")
|
||||
comige_ss :: proc(a, b: __m128) -> b32 ---
|
||||
@(link_name="llvm.x86.sse.comineq.ss")
|
||||
comineq_ss :: proc(a, b: __m128) -> b32 ---
|
||||
@(link_name="llvm.x86.sse.ucomieq.ss")
|
||||
ucomieq_ss :: proc(a, b: __m128) -> b32 ---
|
||||
@(link_name="llvm.x86.sse.ucomilt.ss")
|
||||
ucomilt_ss :: proc(a, b: __m128) -> b32 ---
|
||||
@(link_name="llvm.x86.sse.ucomile.ss")
|
||||
ucomile_ss :: proc(a, b: __m128) -> b32 ---
|
||||
@(link_name="llvm.x86.sse.ucomigt.ss")
|
||||
ucomigt_ss :: proc(a, b: __m128) -> b32 ---
|
||||
@(link_name="llvm.x86.sse.ucomige.ss")
|
||||
ucomige_ss :: proc(a, b: __m128) -> b32 ---
|
||||
@(link_name="llvm.x86.sse.ucomineq.ss")
|
||||
ucomineq_ss :: proc(a, b: __m128) -> b32 ---
|
||||
@(link_name="llvm.x86.sse.cvtss2si")
|
||||
cvtss2si :: proc(a: __m128) -> i32 ---
|
||||
@(link_name="llvm.x86.sse.cvttss2si")
|
||||
cvttss2si :: proc(a: __m128) -> i32 ---
|
||||
@(link_name="llvm.x86.sse.cvtsi2ss")
|
||||
cvtsi2ss :: proc(a: __m128, b: i32) -> __m128 ---
|
||||
@(link_name="llvm.x86.sse.sfence")
|
||||
sfence :: proc() ---
|
||||
@(link_name="llvm.x86.sse.stmxcsr")
|
||||
stmxcsr :: proc(p: rawptr) ---
|
||||
@(link_name="llvm.x86.sse.ldmxcsr")
|
||||
ldmxcsr :: proc(p: rawptr) ---
|
||||
@(link_name="llvm.prefetch")
|
||||
prefetch :: proc(p: rawptr, #const rw, loc, ty: u32) ---
|
||||
@(link_name="llvm.x86.sse.cmp.ss")
|
||||
cmpss :: proc(a, b: __m128, #const imm8: u8) -> __m128 ---
|
||||
|
||||
|
||||
// amd64 only
|
||||
@(link_name="llvm.x86.sse.cvtss2si64")
|
||||
cvtss2si64 :: proc(a: __m128) -> i64 ---
|
||||
@(link_name="llvm.x86.sse.cvttss2si64")
|
||||
cvttss2si64 :: proc(a: __m128) -> i64 ---
|
||||
@(link_name="llvm.x86.sse.cvtsi642ss")
|
||||
cvtsi642ss :: proc(a: __m128, b: i64) -> __m128 ---
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,68 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:simd"
|
||||
|
||||
@(require_results, enable_target_feature="sse3")
|
||||
_mm_addsub_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return addsubps(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse3")
|
||||
_mm_addsub_pd :: #force_inline proc "c" (a: __m128d, b: __m128d) -> __m128d {
|
||||
return addsubpd(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse3")
|
||||
_mm_hadd_pd :: #force_inline proc "c" (a: __m128d, b: __m128d) -> __m128d {
|
||||
return haddpd(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse3")
|
||||
_mm_hadd_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return haddps(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse3")
|
||||
_mm_hsub_pd :: #force_inline proc "c" (a: __m128d, b: __m128d) -> __m128d {
|
||||
return hsubpd(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse3")
|
||||
_mm_hsub_ps :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return hsubps(a, b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse3")
|
||||
_mm_lddqu_si128 :: #force_inline proc "c" (mem_addr: ^__m128i) -> __m128i {
|
||||
return transmute(__m128i)lddqu(mem_addr)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse3")
|
||||
_mm_movedup_pd :: #force_inline proc "c" (a: __m128d) -> __m128d {
|
||||
return simd.shuffle(a, a, 0, 0)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse3")
|
||||
_mm_loaddup_pd :: #force_inline proc "c" (mem_addr: [^]f64) -> __m128d {
|
||||
return _mm_load1_pd(mem_addr)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse3")
|
||||
_mm_movehdup_ps :: #force_inline proc "c" (a: __m128) -> __m128 {
|
||||
return simd.shuffle(a, a, 1, 1, 3, 3)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse3")
|
||||
_mm_moveldup_ps :: #force_inline proc "c" (a: __m128) -> __m128 {
|
||||
return simd.shuffle(a, a, 0, 0, 2, 2)
|
||||
}
|
||||
|
||||
@(private, default_calling_convention="c")
|
||||
foreign _ {
|
||||
@(link_name = "llvm.x86.sse3.addsub.ps")
|
||||
addsubps :: proc(a, b: __m128) -> __m128 ---
|
||||
@(link_name = "llvm.x86.sse3.addsub.pd")
|
||||
addsubpd :: proc(a: __m128d, b: __m128d) -> __m128d ---
|
||||
@(link_name = "llvm.x86.sse3.hadd.pd")
|
||||
haddpd :: proc(a: __m128d, b: __m128d) -> __m128d ---
|
||||
@(link_name = "llvm.x86.sse3.hadd.ps")
|
||||
haddps :: proc(a, b: __m128) -> __m128 ---
|
||||
@(link_name = "llvm.x86.sse3.hsub.pd")
|
||||
hsubpd :: proc(a: __m128d, b: __m128d) -> __m128d ---
|
||||
@(link_name = "llvm.x86.sse3.hsub.ps")
|
||||
hsubps :: proc(a, b: __m128) -> __m128 ---
|
||||
@(link_name = "llvm.x86.sse3.ldu.dq")
|
||||
lddqu :: proc(mem_addr: rawptr) -> i8x16 ---
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
import "core:simd"
|
||||
|
||||
// SSE4 rounding constants
|
||||
_MM_FROUND_TO_NEAREST_INT :: 0x00
|
||||
_MM_FROUND_TO_NEG_INF :: 0x01
|
||||
_MM_FROUND_TO_POS_INF :: 0x02
|
||||
_MM_FROUND_TO_ZERO :: 0x03
|
||||
_MM_FROUND_CUR_DIRECTION :: 0x04
|
||||
_MM_FROUND_RAISE_EXC :: 0x00
|
||||
_MM_FROUND_NO_EXC :: 0x08
|
||||
_MM_FROUND_NINT :: 0x00
|
||||
_MM_FROUND_FLOOR :: _MM_FROUND_RAISE_EXC | _MM_FROUND_TO_NEG_INF
|
||||
_MM_FROUND_CEIL :: _MM_FROUND_RAISE_EXC | _MM_FROUND_TO_POS_INF
|
||||
_MM_FROUND_TRUNC :: _MM_FROUND_RAISE_EXC | _MM_FROUND_TO_ZERO
|
||||
_MM_FROUND_RINT :: _MM_FROUND_RAISE_EXC | _MM_FROUND_CUR_DIRECTION
|
||||
_MM_FROUND_NEARBYINT :: _MM_FROUND_NO_EXC | _MM_FROUND_CUR_DIRECTION
|
||||
|
||||
|
||||
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_blendv_epi8 :: #force_inline proc "c" (a, b, mask: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pblendvb(transmute(i8x16)a, transmute(i8x16)b, transmute(i8x16)mask)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_blend_epi16 :: #force_inline proc "c" (a, b: __m128i, $IMM8: u8) -> __m128i {
|
||||
return transmute(__m128i)pblendw(transmute(i16x8)a, transmute(i16x8)b, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_blendv_pd :: #force_inline proc "c" (a, b, mask: __m128d) -> __m128d {
|
||||
return blendvpd(a, b, mask)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_blendv_ps :: #force_inline proc "c" (a, b, mask: __m128) -> __m128 {
|
||||
return blendvps(a, b, mask)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_blend_pd :: #force_inline proc "c" (a, b: __m128d, $IMM2: u8) -> __m128d {
|
||||
return blendpd(a, b, IMM2)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_blend_ps :: #force_inline proc "c" (a, b: __m128, $IMM4: u8) -> __m128 {
|
||||
return blendps(a, b, IMM4)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_extract_ps :: #force_inline proc "c" (a: __m128, $IMM8: u32) -> i32 {
|
||||
return transmute(i32)simd.extract(a, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_extract_epi8 :: #force_inline proc "c" (a: __m128i, $IMM8: u32) -> i32 {
|
||||
return i32(simd.extract(transmute(u8x16)a, IMM8))
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_extract_epi32 :: #force_inline proc "c" (a: __m128i, $IMM8: u32) -> i32 {
|
||||
return simd.extract(transmute(i32x4)a, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_insert_ps :: #force_inline proc "c" (a, b: __m128, $IMM8: u8) -> __m128 {
|
||||
return insertps(a, b, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_insert_epi8 :: #force_inline proc "c" (a: __m128i, i: i32, $IMM8: u32) -> __m128i {
|
||||
return transmute(__m128i)simd.replace(transmute(i8x16)a, IMM8, i8(i))
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_insert_epi32 :: #force_inline proc "c" (a: __m128i, i: i32, $IMM8: u32) -> __m128i {
|
||||
return transmute(__m128i)simd.replace(transmute(i32x4)a, IMM8, i)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_max_epi8 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pmaxsb(transmute(i8x16)a, transmute(i8x16)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_max_epu16 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pmaxuw(transmute(u16x8)a, transmute(u16x8)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_max_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pmaxsd(transmute(i32x4)a, transmute(i32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_max_epu32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pmaxud(transmute(u32x4)a, transmute(u32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_min_epi8 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pminsb(transmute(i8x16)a, transmute(i8x16)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_min_epu16 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pminuw(transmute(u16x8)a, transmute(u16x8)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_min_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pminsd(transmute(i32x4)a, transmute(i32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_min_epu32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pminud(transmute(u32x4)a, transmute(u32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_packus_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)packusdw(transmute(i32x4)a, transmute(i32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_cmpeq_epi64 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)simd.lanes_eq(transmute(i64x2)a, transmute(i64x2)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_cvtepi8_epi16 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
x := transmute(i8x16)a
|
||||
y := simd.shuffle(x, x, 0, 1, 2, 3, 4, 5, 6, 7)
|
||||
return transmute(__m128i)i16x8(y)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_cvtepi8_epi32 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
x := transmute(i8x16)a
|
||||
y := simd.shuffle(x, x, 0, 1, 2, 3)
|
||||
return transmute(__m128i)i32x4(y)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_cvtepi8_epi64 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
x := transmute(i8x16)a
|
||||
y := simd.shuffle(x, x, 0, 1)
|
||||
return transmute(__m128i)i64x2(y)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_cvtepi16_epi32 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
x := transmute(i16x8)a
|
||||
y := simd.shuffle(x, x, 0, 1, 2, 3)
|
||||
return transmute(__m128i)i32x4(y)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_cvtepi16_epi64 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
x := transmute(i16x8)a
|
||||
y := simd.shuffle(x, x, 0, 1)
|
||||
return transmute(__m128i)i64x2(y)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_cvtepi32_epi64 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
x := transmute(i32x4)a
|
||||
y := simd.shuffle(x, x, 0, 1)
|
||||
return transmute(__m128i)i64x2(y)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_cvtepu8_epi16 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
x := transmute(u8x16)a
|
||||
y := simd.shuffle(x, x, 0, 1, 2, 3, 4, 5, 6, 7)
|
||||
return transmute(__m128i)i16x8(y)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_cvtepu8_epi32 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
x := transmute(u8x16)a
|
||||
y := simd.shuffle(x, x, 0, 1, 2, 3)
|
||||
return transmute(__m128i)i32x4(y)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_cvtepu8_epi64 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
x := transmute(u8x16)a
|
||||
y := simd.shuffle(x, x, 0, 1)
|
||||
return transmute(__m128i)i64x2(y)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_cvtepu16_epi32 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
x := transmute(u16x8)a
|
||||
y := simd.shuffle(x, x, 0, 1, 2, 3)
|
||||
return transmute(__m128i)i32x4(y)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_cvtepu16_epi64 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
x := transmute(u16x8)a
|
||||
y := simd.shuffle(x, x, 0, 1)
|
||||
return transmute(__m128i)i64x2(y)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_cvtepu32_epi64 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
x := transmute(u32x4)a
|
||||
y := simd.shuffle(x, x, 0, 1)
|
||||
return transmute(__m128i)i64x2(y)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_dp_pd :: #force_inline proc "c" (a, b: __m128d, $IMM8: u8) -> __m128d {
|
||||
return dppd(a, b, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_dp_ps :: #force_inline proc "c" (a, b: __m128, $IMM8: u8) -> __m128 {
|
||||
return dpps(a, b, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_floor_pd :: #force_inline proc "c" (a: __m128d) -> __m128d {
|
||||
return simd.floor(a)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_floor_ps :: #force_inline proc "c" (a: __m128) -> __m128 {
|
||||
return simd.floor(a)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_floor_sd :: #force_inline proc "c" (a, b: __m128d) -> __m128d {
|
||||
return roundsd(a, b, _MM_FROUND_FLOOR)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_floor_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return roundss(a, b, _MM_FROUND_FLOOR)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_ceil_pd :: #force_inline proc "c" (a: __m128d) -> __m128d {
|
||||
return simd.ceil(a)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_ceil_ps :: #force_inline proc "c" (a: __m128) -> __m128 {
|
||||
return simd.ceil(a)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_ceil_sd :: #force_inline proc "c" (a, b: __m128d) -> __m128d {
|
||||
return roundsd(a, b, _MM_FROUND_CEIL)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_ceil_ss :: #force_inline proc "c" (a, b: __m128) -> __m128 {
|
||||
return roundss(a, b, _MM_FROUND_CEIL)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_round_pd :: #force_inline proc "c" (a: __m128d, $ROUNDING: i32) -> __m128d {
|
||||
return roundpd(a, ROUNDING)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_round_ps :: #force_inline proc "c" (a: __m128, $ROUNDING: i32) -> __m128 {
|
||||
return roundps(a, ROUNDING)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_round_sd :: #force_inline proc "c" (a, b: __m128d, $ROUNDING: i32) -> __m128d {
|
||||
return roundsd(a, b, ROUNDING)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_round_ss :: #force_inline proc "c" (a, b: __m128, $ROUNDING: i32) -> __m128 {
|
||||
return roundss(a, b, ROUNDING)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_minpos_epu16 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
return transmute(__m128i)phminposuw(transmute(u16x8)a)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_mul_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pmuldq(transmute(i32x4)a, transmute(i32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_mullo_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)simd.mul(transmute(i32x4)a, transmute(i32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_mpsadbw_epu8 :: #force_inline proc "c" (a, b: __m128i, $IMM8: u8) -> __m128i {
|
||||
return transmute(__m128i)mpsadbw(transmute(u8x16)a, transmute(u8x16)b, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_testz_si128 :: #force_inline proc "c" (a: __m128i, mask: __m128i) -> i32 {
|
||||
return ptestz(transmute(i64x2)a, transmute(i64x2)mask)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_testc_si128 :: #force_inline proc "c" (a: __m128i, mask: __m128i) -> i32 {
|
||||
return ptestc(transmute(i64x2)a, transmute(i64x2)mask)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_testnzc_si128 :: #force_inline proc "c" (a: __m128i, mask: __m128i) -> i32 {
|
||||
return ptestnzc(transmute(i64x2)a, transmute(i64x2)mask)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_test_all_zeros :: #force_inline proc "c" (a: __m128i, mask: __m128i) -> i32 {
|
||||
return _mm_testz_si128(a, mask)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_test_all_ones :: #force_inline proc "c" (a: __m128i) -> i32 {
|
||||
return _mm_testc_si128(a, _mm_cmpeq_epi32(a, a))
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_test_mix_ones_zeros :: #force_inline proc "c" (a: __m128i, mask: __m128i) -> i32 {
|
||||
return _mm_testnzc_si128(a, mask)
|
||||
}
|
||||
|
||||
|
||||
when ODIN_ARCH == .amd64 {
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_extract_epi64 :: #force_inline proc "c" (a: __m128i, $IMM1: u32) -> i64 {
|
||||
return simd.extract(transmute(i64x2)a, IMM1)
|
||||
}
|
||||
|
||||
@(require_results, enable_target_feature="sse4.1")
|
||||
_mm_insert_epi64 :: #force_inline proc "c" (a: __m128i, i: i64, $IMM1: u32) -> __m128i {
|
||||
return transmute(__m128i)simd.replace(transmute(i64x2)a, IMM1, i)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@(private, default_calling_convention="c")
|
||||
foreign _ {
|
||||
@(link_name = "llvm.x86.sse41.pblendvb")
|
||||
pblendvb :: proc(a, b: i8x16, mask: i8x16) -> i8x16 ---
|
||||
@(link_name = "llvm.x86.sse41.blendvpd")
|
||||
blendvpd :: proc(a, b, mask: __m128d) -> __m128d ---
|
||||
@(link_name = "llvm.x86.sse41.blendvps")
|
||||
blendvps :: proc(a, b, mask: __m128) -> __m128 ---
|
||||
@(link_name = "llvm.x86.sse41.blendpd")
|
||||
blendpd :: proc(a, b: __m128d, #const imm2: u8) -> __m128d ---
|
||||
@(link_name = "llvm.x86.sse41.blendps")
|
||||
blendps :: proc(a, b: __m128, #const imm4: u8) -> __m128 ---
|
||||
@(link_name = "llvm.x86.sse41.pblendw")
|
||||
pblendw :: proc(a: i16x8, b: i16x8, #const imm8: u8) -> i16x8 ---
|
||||
@(link_name = "llvm.x86.sse41.insertps")
|
||||
insertps :: proc(a, b: __m128, #const imm8: u8) -> __m128 ---
|
||||
@(link_name = "llvm.x86.sse41.pmaxsb")
|
||||
pmaxsb :: proc(a, b: i8x16) -> i8x16 ---
|
||||
@(link_name = "llvm.x86.sse41.pmaxuw")
|
||||
pmaxuw :: proc(a, b: u16x8) -> u16x8 ---
|
||||
@(link_name = "llvm.x86.sse41.pmaxsd")
|
||||
pmaxsd :: proc(a, b: i32x4) -> i32x4 ---
|
||||
@(link_name = "llvm.x86.sse41.pmaxud")
|
||||
pmaxud :: proc(a, b: u32x4) -> u32x4 ---
|
||||
@(link_name = "llvm.x86.sse41.pminsb")
|
||||
pminsb :: proc(a, b: i8x16) -> i8x16 ---
|
||||
@(link_name = "llvm.x86.sse41.pminuw")
|
||||
pminuw :: proc(a, b: u16x8) -> u16x8 ---
|
||||
@(link_name = "llvm.x86.sse41.pminsd")
|
||||
pminsd :: proc(a, b: i32x4) -> i32x4 ---
|
||||
@(link_name = "llvm.x86.sse41.pminud")
|
||||
pminud :: proc(a, b: u32x4) -> u32x4 ---
|
||||
@(link_name = "llvm.x86.sse41.packusdw")
|
||||
packusdw :: proc(a, b: i32x4) -> u16x8 ---
|
||||
@(link_name = "llvm.x86.sse41.dppd")
|
||||
dppd :: proc(a, b: __m128d, #const imm8: u8) -> __m128d ---
|
||||
@(link_name = "llvm.x86.sse41.dpps")
|
||||
dpps :: proc(a, b: __m128, #const imm8: u8) -> __m128 ---
|
||||
@(link_name = "llvm.x86.sse41.round.pd")
|
||||
roundpd :: proc(a: __m128d, rounding: i32) -> __m128d ---
|
||||
@(link_name = "llvm.x86.sse41.round.ps")
|
||||
roundps :: proc(a: __m128, rounding: i32) -> __m128 ---
|
||||
@(link_name = "llvm.x86.sse41.round.sd")
|
||||
roundsd :: proc(a, b: __m128d, rounding: i32) -> __m128d ---
|
||||
@(link_name = "llvm.x86.sse41.round.ss")
|
||||
roundss :: proc(a, b: __m128, rounding: i32) -> __m128 ---
|
||||
@(link_name = "llvm.x86.sse41.phminposuw")
|
||||
phminposuw :: proc(a: u16x8) -> u16x8 ---
|
||||
@(link_name = "llvm.x86.sse41.pmuldq")
|
||||
pmuldq :: proc(a, b: i32x4) -> i64x2 ---
|
||||
@(link_name = "llvm.x86.sse41.mpsadbw")
|
||||
mpsadbw :: proc(a, b: u8x16, #const imm8: u8) -> u16x8 ---
|
||||
@(link_name = "llvm.x86.sse41.ptestz")
|
||||
ptestz :: proc(a, mask: i64x2) -> i32 ---
|
||||
@(link_name = "llvm.x86.sse41.ptestc")
|
||||
ptestc :: proc(a, mask: i64x2) -> i32 ---
|
||||
@(link_name = "llvm.x86.sse41.ptestnzc")
|
||||
ptestnzc :: proc(a, mask: i64x2) -> i32 ---
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
import "core:simd"
|
||||
|
||||
_SIDD_UBYTE_OPS :: 0b0000_0000
|
||||
_SIDD_UWORD_OPS :: 0b0000_0001
|
||||
_SIDD_SBYTE_OPS :: 0b0000_0010
|
||||
_SIDD_SWORD_OPS :: 0b0000_0011
|
||||
|
||||
_SIDD_CMP_EQUAL_ANY :: 0b0000_0000
|
||||
_SIDD_CMP_RANGES :: 0b0000_0100
|
||||
_SIDD_CMP_EQUAL_EACH :: 0b0000_1000
|
||||
_SIDD_CMP_EQUAL_ORDERED :: 0b0000_1100
|
||||
|
||||
_SIDD_POSITIVE_POLARITY :: 0b0000_0000
|
||||
_SIDD_NEGATIVE_POLARITY :: 0b0001_0000
|
||||
_SIDD_MASKED_POSITIVE_POLARITY :: 0b0010_0000
|
||||
_SIDD_MASKED_NEGATIVE_POLARITY :: 0b0011_0000
|
||||
|
||||
_SIDD_LEAST_SIGNIFICANT :: 0b0000_0000
|
||||
_SIDD_MOST_SIGNIFICANT :: 0b0100_0000
|
||||
|
||||
_SIDD_BIT_MASK :: 0b0000_0000
|
||||
_SIDD_UNIT_MASK :: 0b0100_0000
|
||||
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpistrm :: #force_inline proc "c" (a: __m128i, b: __m128i, $IMM8: i8) -> __m128i {
|
||||
return transmute(__m128i)pcmpistrm128(transmute(i8x16)a, transmute(i8x16)b, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpistri :: #force_inline proc "c" (a: __m128i, b: __m128i, $IMM8: i8) -> i32 {
|
||||
return pcmpistri128(transmute(i8x16)a, transmute(i8x16)b, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpistrz :: #force_inline proc "c" (a: __m128i, b: __m128i, $IMM8: i8) -> i32 {
|
||||
return pcmpistriz128(transmute(i8x16)a, transmute(i8x16)b, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpistrc :: #force_inline proc "c" (a: __m128i, b: __m128i, $IMM8: i8) -> i32 {
|
||||
return pcmpistric128(transmute(i8x16)a, transmute(i8x16)b, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpistrs :: #force_inline proc "c" (a: __m128i, b: __m128i, $IMM8: i8) -> i32 {
|
||||
return pcmpistris128(transmute(i8x16)a, transmute(i8x16)b, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpistro :: #force_inline proc "c" (a: __m128i, b: __m128i, $IMM8: i8) -> i32 {
|
||||
return pcmpistrio128(transmute(i8x16)a, transmute(i8x16)b, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpistra :: #force_inline proc "c" (a: __m128i, b: __m128i, $IMM8: i8) -> i32 {
|
||||
return pcmpistria128(transmute(i8x16)a, transmute(i8x16)b, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpestrm :: #force_inline proc "c" (a: __m128i, la: i32, b: __m128i, lb: i32, $IMM8: i8) -> __m128i {
|
||||
return transmute(__m128i)pcmpestrm128(transmute(i8x16)a, la, transmute(i8x16)b, lb, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpestri :: #force_inline proc "c" (a: __m128i, la: i32, b: __m128i, lb: i32, $IMM8: i8) -> i32 {
|
||||
return pcmpestri128(transmute(i8x16)a, la, transmute(i8x16)b, lb, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpestrz :: #force_inline proc "c" (a: __m128i, la: i32, b: __m128i, lb: i32, $IMM8: i8) -> i32 {
|
||||
return pcmpestriz128(transmute(i8x16)a, la, transmute(i8x16)b, lb, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpestrc :: #force_inline proc "c" (a: __m128i, la: i32, b: __m128i, lb: i32, $IMM8: i8) -> i32 {
|
||||
return pcmpestric128(transmute(i8x16)a, la, transmute(i8x16)b, lb, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpestrs :: #force_inline proc "c" (a: __m128i, la: i32, b: __m128i, lb: i32, $IMM8: i8) -> i32 {
|
||||
return pcmpestris128(transmute(i8x16)a, la, transmute(i8x16)b, lb, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpestro :: #force_inline proc "c" (a: __m128i, la: i32, b: __m128i, lb: i32, $IMM8: i8) -> i32 {
|
||||
return pcmpestrio128(transmute(i8x16)a, la, transmute(i8x16)b, lb, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpestra :: #force_inline proc "c" (a: __m128i, la: i32, b: __m128i, lb: i32, $IMM8: i8) -> i32 {
|
||||
return pcmpestria128(transmute(i8x16)a, la, transmute(i8x16)b, lb, IMM8)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_crc32_u8 :: #force_inline proc "c" (crc: u32, v: u8) -> u32 {
|
||||
return crc32_32_8(crc, v)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_crc32_u16 :: #force_inline proc "c" (crc: u32, v: u16) -> u32 {
|
||||
return crc32_32_16(crc, v)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_crc32_u32 :: #force_inline proc "c" (crc: u32, v: u32) -> u32 {
|
||||
return crc32_32_32(crc, v)
|
||||
}
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_cmpgt_epi64 :: #force_inline proc "c" (a: __m128i, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)simd.lanes_gt(transmute(i64x2)a, transmute(i64x2)b)
|
||||
}
|
||||
|
||||
when ODIN_ARCH == .amd64 {
|
||||
@(require_results, enable_target_feature="sse4.2")
|
||||
_mm_crc32_u64 :: #force_inline proc "c" (crc: u64, v: u64) -> u64 {
|
||||
return crc32_64_64(crc, v)
|
||||
}
|
||||
}
|
||||
|
||||
@(private, default_calling_convention="c")
|
||||
foreign _ {
|
||||
// SSE 4.2 string and text comparison ops
|
||||
@(link_name="llvm.x86.sse42.pcmpestrm128")
|
||||
pcmpestrm128 :: proc(a: i8x16, la: i32, b: i8x16, lb: i32, #const imm8: i8) -> u8x16 ---
|
||||
@(link_name="llvm.x86.sse42.pcmpestri128")
|
||||
pcmpestri128 :: proc(a: i8x16, la: i32, b: i8x16, lb: i32, #const imm8: i8) -> i32 ---
|
||||
@(link_name="llvm.x86.sse42.pcmpestriz128")
|
||||
pcmpestriz128 :: proc(a: i8x16, la: i32, b: i8x16, lb: i32, #const imm8: i8) -> i32 ---
|
||||
@(link_name="llvm.x86.sse42.pcmpestric128")
|
||||
pcmpestric128 :: proc(a: i8x16, la: i32, b: i8x16, lb: i32, #const imm8: i8) -> i32 ---
|
||||
@(link_name="llvm.x86.sse42.pcmpestris128")
|
||||
pcmpestris128 :: proc(a: i8x16, la: i32, b: i8x16, lb: i32, #const imm8: i8) -> i32 ---
|
||||
@(link_name="llvm.x86.sse42.pcmpestrio128")
|
||||
pcmpestrio128 :: proc(a: i8x16, la: i32, b: i8x16, lb: i32, #const imm8: i8) -> i32 ---
|
||||
@(link_name="llvm.x86.sse42.pcmpestria128")
|
||||
pcmpestria128 :: proc(a: i8x16, la: i32, b: i8x16, lb: i32, #const imm8: i8) -> i32 ---
|
||||
@(link_name="llvm.x86.sse42.pcmpistrm128")
|
||||
pcmpistrm128 :: proc(a, b: i8x16, #const imm8: i8) -> i8x16 ---
|
||||
@(link_name="llvm.x86.sse42.pcmpistri128")
|
||||
pcmpistri128 :: proc(a, b: i8x16, #const imm8: i8) -> i32 ---
|
||||
@(link_name="llvm.x86.sse42.pcmpistriz128")
|
||||
pcmpistriz128 :: proc(a, b: i8x16, #const imm8: i8) -> i32 ---
|
||||
@(link_name="llvm.x86.sse42.pcmpistric128")
|
||||
pcmpistric128 :: proc(a, b: i8x16, #const imm8: i8) -> i32 ---
|
||||
@(link_name="llvm.x86.sse42.pcmpistris128")
|
||||
pcmpistris128 :: proc(a, b: i8x16, #const imm8: i8) -> i32 ---
|
||||
@(link_name="llvm.x86.sse42.pcmpistrio128")
|
||||
pcmpistrio128 :: proc(a, b: i8x16, #const imm8: i8) -> i32 ---
|
||||
@(link_name="llvm.x86.sse42.pcmpistria128")
|
||||
pcmpistria128 :: proc(a, b: i8x16, #const imm8: i8) -> i32 ---
|
||||
// SSE 4.2 CRC instructions
|
||||
@(link_name="llvm.x86.sse42.crc32.32.8")
|
||||
crc32_32_8 :: proc(crc: u32, v: u8) -> u32 ---
|
||||
@(link_name="llvm.x86.sse42.crc32.32.16")
|
||||
crc32_32_16 :: proc(crc: u32, v: u16) -> u32 ---
|
||||
@(link_name="llvm.x86.sse42.crc32.32.32")
|
||||
crc32_32_32 :: proc(crc: u32, v: u32) -> u32 ---
|
||||
|
||||
// AMD64 Only
|
||||
@(link_name="llvm.x86.sse42.crc32.64.64")
|
||||
crc32_64_64 :: proc(crc: u64, v: u64) -> u64 ---
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:simd"
|
||||
_ :: simd
|
||||
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_abs_epi8 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pabsb128(transmute(i8x16)a)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_abs_epi16 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pabsw128(transmute(i16x8)a)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_abs_epi32 :: #force_inline proc "c" (a: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pabsd128(transmute(i32x4)a)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_shuffle_epi8 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pshufb128(transmute(u8x16)a, transmute(u8x16)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_alignr_epi8 :: #force_inline proc "c" (a, b: __m128i, $IMM8: u32) -> __m128i {
|
||||
shift :: IMM8
|
||||
|
||||
// If palignr is shifting the pair of vectors more than the size of two
|
||||
// lanes, emit zero.
|
||||
if shift > 32 {
|
||||
return _mm_set1_epi8(0)
|
||||
}
|
||||
a, b := a, b
|
||||
if shift > 16 {
|
||||
a, b = _mm_set1_epi8(0), a
|
||||
}
|
||||
|
||||
return transmute(__m128i)simd.shuffle(
|
||||
transmute(i8x16)b,
|
||||
transmute(i8x16)a,
|
||||
0 when shift > 32 else shift - 16 + 0 when shift > 16 else shift + 0,
|
||||
1 when shift > 32 else shift - 16 + 1 when shift > 16 else shift + 1,
|
||||
2 when shift > 32 else shift - 16 + 2 when shift > 16 else shift + 2,
|
||||
3 when shift > 32 else shift - 16 + 3 when shift > 16 else shift + 3,
|
||||
4 when shift > 32 else shift - 16 + 4 when shift > 16 else shift + 4,
|
||||
5 when shift > 32 else shift - 16 + 5 when shift > 16 else shift + 5,
|
||||
6 when shift > 32 else shift - 16 + 6 when shift > 16 else shift + 6,
|
||||
7 when shift > 32 else shift - 16 + 7 when shift > 16 else shift + 7,
|
||||
8 when shift > 32 else shift - 16 + 8 when shift > 16 else shift + 8,
|
||||
9 when shift > 32 else shift - 16 + 9 when shift > 16 else shift + 9,
|
||||
10 when shift > 32 else shift - 16 + 10 when shift > 16 else shift + 10,
|
||||
11 when shift > 32 else shift - 16 + 11 when shift > 16 else shift + 11,
|
||||
12 when shift > 32 else shift - 16 + 12 when shift > 16 else shift + 12,
|
||||
13 when shift > 32 else shift - 16 + 13 when shift > 16 else shift + 13,
|
||||
14 when shift > 32 else shift - 16 + 14 when shift > 16 else shift + 14,
|
||||
15 when shift > 32 else shift - 16 + 15 when shift > 16 else shift + 15,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_hadd_epi16 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)phaddw128(transmute(i16x8)a, transmute(i16x8)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_hadds_epi16 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)phaddsw128(transmute(i16x8)a, transmute(i16x8)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_hadd_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)phaddd128(transmute(i32x4)a, transmute(i32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_hsub_epi16 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)phsubw128(transmute(i16x8)a, transmute(i16x8)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_hsubs_epi16 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)phsubsw128(transmute(i16x8)a, transmute(i16x8)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_hsub_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)phsubd128(transmute(i32x4)a, transmute(i32x4)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_maddubs_epi16 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pmaddubsw128(transmute(u8x16)a, transmute(i8x16)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_mulhrs_epi16 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)pmulhrsw128(transmute(i16x8)a, transmute(i16x8)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_sign_epi8 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)psignb128(transmute(i8x16)a, transmute(i8x16)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_sign_epi16 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)psignw128(transmute(i16x8)a, transmute(i16x8)b)
|
||||
}
|
||||
@(require_results, enable_target_feature="ssse3")
|
||||
_mm_sign_epi32 :: #force_inline proc "c" (a, b: __m128i) -> __m128i {
|
||||
return transmute(__m128i)psignd128(transmute(i32x4)a, transmute(i32x4)b)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(private, default_calling_convention="c")
|
||||
foreign _ {
|
||||
@(link_name = "llvm.x86.ssse3.pabs.b.128")
|
||||
pabsb128 :: proc(a: i8x16) -> u8x16 ---
|
||||
@(link_name = "llvm.x86.ssse3.pabs.w.128")
|
||||
pabsw128 :: proc(a: i16x8) -> u16x8 ---
|
||||
@(link_name = "llvm.x86.ssse3.pabs.d.128")
|
||||
pabsd128 :: proc(a: i32x4) -> u32x4 ---
|
||||
@(link_name = "llvm.x86.ssse3.pshuf.b.128")
|
||||
pshufb128 :: proc(a, b: u8x16) -> u8x16 ---
|
||||
@(link_name = "llvm.x86.ssse3.phadd.w.128")
|
||||
phaddw128 :: proc(a, b: i16x8) -> i16x8 ---
|
||||
@(link_name = "llvm.x86.ssse3.phadd.sw.128")
|
||||
phaddsw128 :: proc(a, b: i16x8) -> i16x8 ---
|
||||
@(link_name = "llvm.x86.ssse3.phadd.d.128")
|
||||
phaddd128 :: proc(a, b: i32x4) -> i32x4 ---
|
||||
@(link_name = "llvm.x86.ssse3.phsub.w.128")
|
||||
phsubw128 :: proc(a, b: i16x8) -> i16x8 ---
|
||||
@(link_name = "llvm.x86.ssse3.phsub.sw.128")
|
||||
phsubsw128 :: proc(a, b: i16x8) -> i16x8 ---
|
||||
@(link_name = "llvm.x86.ssse3.phsub.d.128")
|
||||
phsubd128 :: proc(a, b: i32x4) -> i32x4 ---
|
||||
@(link_name = "llvm.x86.ssse3.pmadd.ub.sw.128")
|
||||
pmaddubsw128 :: proc(a: u8x16, b: i8x16) -> i16x8 ---
|
||||
@(link_name = "llvm.x86.ssse3.pmul.hr.sw.128")
|
||||
pmulhrsw128 :: proc(a, b: i16x8) -> i16x8 ---
|
||||
@(link_name = "llvm.x86.ssse3.psign.b.128")
|
||||
psignb128 :: proc(a, b: i8x16) -> i8x16 ---
|
||||
@(link_name = "llvm.x86.ssse3.psign.w.128")
|
||||
psignw128 :: proc(a, b: i16x8) -> i16x8 ---
|
||||
@(link_name = "llvm.x86.ssse3.psign.d.128")
|
||||
psignd128 :: proc(a, b: i32x4) -> i32x4 ---
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
|
||||
import "core:simd"
|
||||
|
||||
bf16 :: u16
|
||||
|
||||
__m128i :: #simd[2]i64
|
||||
__m128 :: #simd[4]f32
|
||||
__m128d :: #simd[2]f64
|
||||
|
||||
__m256i :: #simd[4]i64
|
||||
__m256 :: #simd[8]f32
|
||||
__m256d :: #simd[4]f64
|
||||
|
||||
__m512i :: #simd[8]i64
|
||||
__m512 :: #simd[16]f32
|
||||
__m512d :: #simd[8]f64
|
||||
|
||||
__m128bh :: #simd[8]bf16
|
||||
__m256bh :: #simd[16]bf16
|
||||
__m512bh :: #simd[32]bf16
|
||||
|
||||
|
||||
/// The `__mmask64` type used in AVX-512 intrinsics, a 64-bit integer
|
||||
__mmask64 :: u64
|
||||
|
||||
/// The `__mmask32` type used in AVX-512 intrinsics, a 32-bit integer
|
||||
__mmask32 :: u32
|
||||
|
||||
/// The `__mmask16` type used in AVX-512 intrinsics, a 16-bit integer
|
||||
__mmask16 :: u16
|
||||
|
||||
/// The `__mmask8` type used in AVX-512 intrinsics, a 8-bit integer
|
||||
__mmask8 :: u8
|
||||
|
||||
/// The `_MM_CMPINT_ENUM` type used to specify comparison operations in AVX-512 intrinsics.
|
||||
_MM_CMPINT_ENUM :: i32
|
||||
|
||||
/// The `MM_MANTISSA_NORM_ENUM` type used to specify mantissa normalized operations in AVX-512 intrinsics.
|
||||
_MM_MANTISSA_NORM_ENUM :: i32
|
||||
|
||||
/// The `MM_MANTISSA_SIGN_ENUM` type used to specify mantissa signed operations in AVX-512 intrinsics.
|
||||
_MM_MANTISSA_SIGN_ENUM :: i32
|
||||
|
||||
_MM_PERM_ENUM :: i32
|
||||
|
||||
@(private) u8x16 :: simd.u8x16
|
||||
@(private) i8x16 :: simd.i8x16
|
||||
@(private) u16x8 :: simd.u16x8
|
||||
@(private) i16x8 :: simd.i16x8
|
||||
@(private) u32x4 :: simd.u32x4
|
||||
@(private) i32x4 :: simd.i32x4
|
||||
@(private) u64x2 :: simd.u64x2
|
||||
@(private) i64x2 :: simd.i64x2
|
||||
@(private) f32x4 :: simd.f32x4
|
||||
@(private) f64x2 :: simd.f64x2
|
||||
@@ -1,33 +0,0 @@
|
||||
package sys_cpu
|
||||
|
||||
Cache_Line_Pad :: struct {_: [_cache_line_size]byte};
|
||||
|
||||
initialized: bool;
|
||||
|
||||
x86: struct {
|
||||
_: Cache_Line_Pad,
|
||||
has_aes: bool, // AES hardware implementation (AES NI)
|
||||
has_adx: bool, // Multi-precision add-carry instruction extensions
|
||||
has_avx: bool, // Advanced vector extension
|
||||
has_avx2: bool, // Advanced vector extension 2
|
||||
has_bmi1: bool, // Bit manipulation instruction set 1
|
||||
has_bmi2: bool, // Bit manipulation instruction set 2
|
||||
has_erms: bool, // Enhanced REP for MOVSB and STOSB
|
||||
has_fma: bool, // Fused-multiply-add instructions
|
||||
has_os_xsave: bool, // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
|
||||
has_pclmulqdq: bool, // PCLMULQDQ instruction - most often used for AES-GCM
|
||||
has_popcnt: bool, // Hamming weight instruction POPCNT.
|
||||
has_rdrand: bool, // RDRAND instruction (on-chip random number generator)
|
||||
has_rdseed: bool, // RDSEED instruction (on-chip random number generator)
|
||||
has_sse2: bool, // Streaming SIMD extension 2 (always available on amd64)
|
||||
has_sse3: bool, // Streaming SIMD extension 3
|
||||
has_ssse3: bool, // Supplemental streaming SIMD extension 3
|
||||
has_sse41: bool, // Streaming SIMD extension 4 and 4.1
|
||||
has_sse42: bool, // Streaming SIMD extension 4 and 4.2
|
||||
_: Cache_Line_Pad,
|
||||
};
|
||||
|
||||
|
||||
init :: proc() {
|
||||
_init();
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
//+build i386, amd64
|
||||
package sys_cpu
|
||||
|
||||
_cache_line_size :: 64;
|
||||
|
||||
cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) {
|
||||
return expand_to_tuple(asm(u32, u32) -> struct{eax, ebc, ecx, edx: u32} {
|
||||
"cpuid",
|
||||
"={ax},={bx},={cx},={dx},{ax},{cx}",
|
||||
}(ax, cx));
|
||||
}
|
||||
|
||||
xgetbv :: proc() -> (eax, edx: u32) {
|
||||
return expand_to_tuple(asm(u32) -> struct{eax, edx: u32} {
|
||||
"xgetbv",
|
||||
"={ax},={dx},{cx}",
|
||||
}(0));
|
||||
}
|
||||
|
||||
_init :: proc() {
|
||||
is_set :: proc(hwc: u32, value: u32) -> bool {
|
||||
return hwc&value != 0;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
||||
max_id, _, _, _ := cpuid(0, 0);
|
||||
|
||||
if max_id < 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
_, _, ecx1, edx1 := cpuid(1, 0);
|
||||
|
||||
x86.has_sse2 = is_set(26, edx1);
|
||||
|
||||
x86.has_sse3 = is_set(0, ecx1);
|
||||
x86.has_pclmulqdq = is_set(1, ecx1);
|
||||
x86.has_ssse3 = is_set(9, ecx1);
|
||||
x86.has_fma = is_set(12, ecx1);
|
||||
x86.has_sse41 = is_set(19, ecx1);
|
||||
x86.has_sse42 = is_set(20, ecx1);
|
||||
x86.has_popcnt = is_set(23, ecx1);
|
||||
x86.has_aes = is_set(25, ecx1);
|
||||
x86.has_os_xsave = is_set(27, ecx1);
|
||||
x86.has_rdrand = is_set(30, ecx1);
|
||||
|
||||
os_supports_avx := false;
|
||||
if x86.has_os_xsave {
|
||||
eax, _ := xgetbv();
|
||||
os_supports_avx = is_set(1, eax) && is_set(2, eax);
|
||||
}
|
||||
|
||||
x86.has_avx = is_set(28, ecx1) && os_supports_avx;
|
||||
|
||||
if max_id < 7 {
|
||||
return;
|
||||
}
|
||||
|
||||
_, ebx7, _, _ := cpuid(7, 0);
|
||||
x86.has_bmi1 = is_set(3, ebx7);
|
||||
x86.has_avx2 = is_set(5, ebx7) && os_supports_avx;
|
||||
x86.has_bmi2 = is_set(8, ebx7);
|
||||
x86.has_erms = is_set(9, ebx7);
|
||||
x86.has_rdseed = is_set(18, ebx7);
|
||||
x86.has_adx = is_set(19, ebx7);
|
||||
}
|
||||
Reference in New Issue
Block a user