#![allow(clippy::module_name_repetitions)]
#[cfg(test)]
use stdsimd_test::assert_instr;
#[allow(improper_ctypes)]
extern "C" {
#[link_name = "llvm.x86.xsave"]
fn xsave(p: *mut u8, hi: u32, lo: u32) -> ();
#[link_name = "llvm.x86.xrstor"]
fn xrstor(p: *const u8, hi: u32, lo: u32) -> ();
#[link_name = "llvm.x86.xsetbv"]
fn xsetbv(v: u32, hi: u32, lo: u32) -> ();
#[link_name = "llvm.x86.xsaveopt"]
fn xsaveopt(p: *mut u8, hi: u32, lo: u32) -> ();
#[link_name = "llvm.x86.xsavec"]
fn xsavec(p: *mut u8, hi: u32, lo: u32) -> ();
#[link_name = "llvm.x86.xsaves"]
fn xsaves(p: *mut u8, hi: u32, lo: u32) -> ();
#[link_name = "llvm.x86.xrstors"]
fn xrstors(p: *const u8, hi: u32, lo: u32) -> ();
}
#[inline]
#[target_feature(enable = "xsave")]
#[cfg_attr(test, assert_instr(xsave))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _xsave(mem_addr: *mut u8, save_mask: u64) {
xsave(mem_addr, (save_mask >> 32) as u32, save_mask as u32);
}
#[inline]
#[target_feature(enable = "xsave")]
#[cfg_attr(test, assert_instr(xrstor))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _xrstor(mem_addr: *const u8, rs_mask: u64) {
xrstor(mem_addr, (rs_mask >> 32) as u32, rs_mask as u32);
}
#[stable(feature = "simd_x86", since = "1.27.0")]
pub const _XCR_XFEATURE_ENABLED_MASK: u32 = 0;
#[inline]
#[target_feature(enable = "xsave")]
#[cfg_attr(test, assert_instr(xsetbv))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _xsetbv(a: u32, val: u64) {
xsetbv(a, (val >> 32) as u32, val as u32);
}
#[inline]
#[target_feature(enable = "xsave")]
#[cfg_attr(test, assert_instr(xgetbv))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _xgetbv(xcr_no: u32) -> u64 {
let eax: u32;
let edx: u32;
asm!("xgetbv" : "={eax}"(eax), "={edx}"(edx) : "{ecx}"(xcr_no));
((edx as u64) << 32) | (eax as u64)
}
#[inline]
#[target_feature(enable = "xsave,xsaveopt")]
#[cfg_attr(test, assert_instr(xsaveopt))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _xsaveopt(mem_addr: *mut u8, save_mask: u64) {
xsaveopt(mem_addr, (save_mask >> 32) as u32, save_mask as u32);
}
#[inline]
#[target_feature(enable = "xsave,xsavec")]
#[cfg_attr(test, assert_instr(xsavec))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _xsavec(mem_addr: *mut u8, save_mask: u64) {
xsavec(mem_addr, (save_mask >> 32) as u32, save_mask as u32);
}
#[inline]
#[target_feature(enable = "xsave,xsaves")]
#[cfg_attr(test, assert_instr(xsaves))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _xsaves(mem_addr: *mut u8, save_mask: u64) {
xsaves(mem_addr, (save_mask >> 32) as u32, save_mask as u32);
}
#[inline]
#[target_feature(enable = "xsave,xsaves")]
#[cfg_attr(test, assert_instr(xrstors))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn _xrstors(mem_addr: *const u8, rs_mask: u64) {
xrstors(mem_addr, (rs_mask >> 32) as u32, rs_mask as u32);
}
#[cfg(test)]
mod tests {
use std::fmt;
use std::prelude::v1::*;
use crate::core_arch::x86::*;
use stdsimd_test::simd_test;
#[repr(align(64))]
struct XsaveArea {
data: [u8; 2560],
}
impl XsaveArea {
fn new() -> XsaveArea {
XsaveArea { data: [0; 2560] }
}
fn ptr(&mut self) -> *mut u8 {
&mut self.data[0] as *mut _ as *mut u8
}
}
impl PartialEq<XsaveArea> for XsaveArea {
fn eq(&self, other: &XsaveArea) -> bool {
for i in 0..self.data.len() {
if self.data[i] != other.data[i] {
return false;
}
}
true
}
}
impl fmt::Debug for XsaveArea {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[")?;
for i in 0..self.data.len() {
write!(f, "{}", self.data[i])?;
if i != self.data.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
#[simd_test(enable = "xsave")]
unsafe fn xgetbv_xsetbv() {
let xcr_n: u32 = _XCR_XFEATURE_ENABLED_MASK;
let xcr: u64 = _xgetbv(xcr_n);
let xcr_cpy: u64 = _xgetbv(xcr_n);
assert_eq!(xcr, xcr_cpy);
}
#[cfg(not(stdsimd_intel_sde))]
#[simd_test(enable = "xsave,xsavec")]
unsafe fn xsavec() {
let m = 0xFFFFFFFFFFFFFFFF_u64; let mut a = XsaveArea::new();
let mut b = XsaveArea::new();
_xsavec(a.ptr(), m);
_xrstor(a.ptr(), m);
_xsavec(b.ptr(), m);
assert_eq!(a, b);
}
}