1 | //! FXSR floating-point context fast save and restore. |
2 | |
3 | #[cfg (test)] |
4 | use stdarch_test::assert_instr; |
5 | |
6 | #[allow (improper_ctypes)] |
7 | extern "C" { |
8 | #[link_name = "llvm.x86.fxsave" ] |
9 | fn fxsave(p: *mut u8); |
10 | #[link_name = "llvm.x86.fxrstor" ] |
11 | fn fxrstor(p: *const u8); |
12 | } |
13 | |
14 | /// Saves the `x87` FPU, `MMX` technology, `XMM`, and `MXCSR` registers to the |
15 | /// 512-byte-long 16-byte-aligned memory region `mem_addr`. |
16 | /// |
17 | /// A misaligned destination operand raises a general-protection (#GP) or an |
18 | /// alignment check exception (#AC). |
19 | /// |
20 | /// See [`FXSAVE`][fxsave] and [`FXRSTOR`][fxrstor]. |
21 | /// |
22 | /// [fxsave]: http://www.felixcloutier.com/x86/FXSAVE.html |
23 | /// [fxrstor]: http://www.felixcloutier.com/x86/FXRSTOR.html |
24 | /// |
25 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_fxsave) |
26 | #[inline ] |
27 | #[target_feature (enable = "fxsr" )] |
28 | #[cfg_attr (test, assert_instr(fxsave))] |
29 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
30 | pub unsafe fn _fxsave(mem_addr: *mut u8) { |
31 | fxsave(mem_addr) |
32 | } |
33 | |
34 | /// Restores the `XMM`, `MMX`, `MXCSR`, and `x87` FPU registers from the |
35 | /// 512-byte-long 16-byte-aligned memory region `mem_addr`. |
36 | /// |
37 | /// The contents of this memory region should have been written to by a |
38 | /// previous |
39 | /// `_fxsave` or `_fxsave64` intrinsic. |
40 | /// |
41 | /// A misaligned destination operand raises a general-protection (#GP) or an |
42 | /// alignment check exception (#AC). |
43 | /// |
44 | /// See [`FXSAVE`][fxsave] and [`FXRSTOR`][fxrstor]. |
45 | /// |
46 | /// [fxsave]: http://www.felixcloutier.com/x86/FXSAVE.html |
47 | /// [fxrstor]: http://www.felixcloutier.com/x86/FXRSTOR.html |
48 | /// |
49 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_fxrstor) |
50 | #[inline ] |
51 | #[target_feature (enable = "fxsr" )] |
52 | #[cfg_attr (test, assert_instr(fxrstor))] |
53 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
54 | pub unsafe fn _fxrstor(mem_addr: *const u8) { |
55 | fxrstor(mem_addr) |
56 | } |
57 | |
58 | #[cfg (test)] |
59 | mod tests { |
60 | use crate::core_arch::x86::*; |
61 | use std::{cmp::PartialEq, fmt}; |
62 | use stdarch_test::simd_test; |
63 | |
64 | #[repr (align(16))] |
65 | struct FxsaveArea { |
66 | data: [u8; 512], // 512 bytes |
67 | } |
68 | |
69 | impl FxsaveArea { |
70 | fn new() -> FxsaveArea { |
71 | FxsaveArea { data: [0; 512] } |
72 | } |
73 | fn ptr(&mut self) -> *mut u8 { |
74 | self.data.as_mut_ptr() |
75 | } |
76 | } |
77 | |
78 | impl PartialEq<FxsaveArea> for FxsaveArea { |
79 | fn eq(&self, other: &FxsaveArea) -> bool { |
80 | for i in 0..self.data.len() { |
81 | if self.data[i] != other.data[i] { |
82 | return false; |
83 | } |
84 | } |
85 | true |
86 | } |
87 | } |
88 | |
89 | impl fmt::Debug for FxsaveArea { |
90 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
91 | write!(f, "[" )?; |
92 | for i in 0..self.data.len() { |
93 | write!(f, " {}" , self.data[i])?; |
94 | if i != self.data.len() - 1 { |
95 | write!(f, ", " )?; |
96 | } |
97 | } |
98 | write!(f, "]" ) |
99 | } |
100 | } |
101 | |
102 | #[simd_test(enable = "fxsr" )] |
103 | #[cfg_attr (miri, ignore)] // Register saving/restoring is not supported in Miri |
104 | unsafe fn fxsave() { |
105 | let mut a = FxsaveArea::new(); |
106 | let mut b = FxsaveArea::new(); |
107 | |
108 | fxsr::_fxsave(a.ptr()); |
109 | fxsr::_fxrstor(a.ptr()); |
110 | fxsr::_fxsave(b.ptr()); |
111 | assert_eq!(a, b); |
112 | } |
113 | } |
114 | |