#![allow(improper_ctypes)]
use super::*;
use super::{simd_shuffle2, simd_shuffle4};
extern "platform-intrinsic" {
fn x86_mm_addsub_pd(x: m128d, y: m128d) -> m128d;
fn x86_mm_addsub_ps(x: m128, y: m128) -> m128;
fn x86_mm_hadd_pd(x: m128d, y: m128d) -> m128d;
fn x86_mm_hadd_ps(x: m128, y: m128) -> m128;
fn x86_mm_hsub_pd(x: m128d, y: m128d) -> m128d;
fn x86_mm_hsub_ps(x: m128, y: m128) -> m128;
}
extern {
#[link_name = "llvm.x86.sse3.ldu.dq"]
fn sse3_ldu_dq(a: *mut u8) -> i8x16;
}
#[inline]
pub fn mm_addsub_pd(a: m128d, b: m128d) -> m128d {
unsafe { x86_mm_addsub_pd(a, b) }
}
#[inline]
pub fn mm_addsub_ps(a: m128, b: m128) -> m128 {
unsafe { x86_mm_addsub_ps(a, b) }
}
#[inline]
pub fn mm_hadd_pd(a: m128d, b: m128d) -> m128d {
unsafe { x86_mm_hadd_pd(a, b) }
}
#[inline]
pub fn mm_hadd_ps(a: m128, b: m128) -> m128 {
unsafe { x86_mm_hadd_ps(a, b) }
}
#[inline]
pub fn mm_hsub_pd(a: m128d, b: m128d) -> m128d {
unsafe { x86_mm_hsub_pd(a, b) }
}
#[inline]
pub fn mm_hsub_ps(a: m128, b: m128) -> m128 {
unsafe { x86_mm_hsub_ps(a, b) }
}
#[inline]
pub unsafe fn mm_lddqu_si128(mem_addr: *const m128i) -> m128i {
sse3_ldu_dq(mem_addr as *mut u8).as_m128i()
}
#[inline]
pub unsafe fn mm_loaddup_pd(mem_addr: *const f64) -> m128d {
mm_load1_pd(mem_addr)
}
#[inline]
pub fn mm_movedup_pd(a: m128d) -> m128d {
let a64 = a.as_f64x2();
unsafe { simd_shuffle2(a64, a64, [0, 0]) }
}
#[inline]
pub fn mm_movehdup_ps(a: m128) -> m128 {
let a32 = a.as_f32x4();
unsafe { simd_shuffle4(a32, a32, [1, 1, 3, 3]) }
}
#[inline]
pub fn mm_moveldup_ps(a: m128) -> m128 {
let a32 = a.as_f32x4();
unsafe { simd_shuffle4(a32, a32, [0, 0, 2, 2]) }
}
pub const MM_DENORMALS_ZERO_ON: u32 = 0x0040;
pub const MM_DENORMALS_ZERO_OFF: u32 = 0x0000;
pub const MM_DENORMALS_ZERO_MASK: u32 = 0x0040;
#[inline]
pub fn mm_get_denormals_zero_mode() -> u32 {
mm_getcsr() & MM_DENORMALS_ZERO_MASK
}
#[inline]
pub fn mm_set_denormals_zero_mode(x: u32) {
mm_setcsr((mm_getcsr() & !MM_DENORMALS_ZERO_MASK) | x)
}
#[cfg(test)]
mod test {
use super::super::*;
#[test]
fn test_arith_ps() {
let x = mm_setr_ps(1.0, 2.0, 3.0, 4.0);
let y = mm_setr_ps(2.0, 1.0, 2.0, 4.0);
assert_eq!(mm_addsub_ps(x, y).as_f32x4().as_array(), [-1.0, 3.0, 1.0, 8.0]);
assert_eq!(mm_hadd_ps(x, y).as_f32x4().as_array(), [3.0, 7.0, 3.0, 6.0]);
assert_eq!(mm_hsub_ps(x, y).as_f32x4().as_array(), [-1.0, -1.0, 1.0, -2.0]);
}
#[test]
fn test_arith_pd() {
let x = mm_setr_pd(1.0, 2.0);
let y = mm_setr_pd(3.0, 5.0);
assert_eq!(mm_addsub_pd(x, y).as_f64x2().as_array(), [-2.0, 7.0]);
assert_eq!(mm_hadd_pd(x, y).as_f64x2().as_array(), [3.0, 8.0]);
assert_eq!(mm_hsub_pd(x, y).as_f64x2().as_array(), [-1.0, -2.0]);
}
#[test]
fn test_move_pd() {
let x = mm_setr_pd(1.0, 2.0);
assert_eq!(mm_movedup_pd(x).as_f64x2().as_array(), [1.0, 1.0]);
}
#[test]
fn test_move_ps() {
let x = mm_setr_ps(1.0, 2.0, 3.0, 4.0);
assert_eq!(mm_movehdup_ps(x).as_f32x4().as_array(), [2.0, 2.0, 4.0, 4.0]);
assert_eq!(mm_moveldup_ps(x).as_f32x4().as_array(), [1.0, 1.0, 3.0, 3.0]);
}
#[test]
fn test_lddqu() {
let x = mm_setr_epi32(1, 2, 3, 4);
let p = &x as *const m128i;
let r = unsafe { mm_lddqu_si128(p) };
assert_eq!(r.as_i32x4().as_array(), [1, 2, 3, 4]);
}
#[test]
fn test_denormal() {
let initial = mm_get_denormals_zero_mode();
mm_set_denormals_zero_mode(MM_DENORMALS_ZERO_ON);
assert_eq!(mm_get_denormals_zero_mode(), MM_DENORMALS_ZERO_ON);
mm_set_denormals_zero_mode(MM_DENORMALS_ZERO_OFF);
assert_eq!(mm_get_denormals_zero_mode(), MM_DENORMALS_ZERO_OFF);
mm_set_denormals_zero_mode(initial);
}
}