1 | //! `x86_64`'s `xsave` and `xsaveopt` target feature intrinsics |
2 | |
3 | #![allow (clippy::module_name_repetitions)] |
4 | |
5 | #[cfg (test)] |
6 | use stdarch_test::assert_instr; |
7 | |
8 | #[allow (improper_ctypes)] |
9 | extern "C" { |
10 | #[link_name = "llvm.x86.xsave64" ] |
11 | fn xsave64(p: *mut u8, hi: u32, lo: u32); |
12 | #[link_name = "llvm.x86.xrstor64" ] |
13 | fn xrstor64(p: *const u8, hi: u32, lo: u32); |
14 | #[link_name = "llvm.x86.xsaveopt64" ] |
15 | fn xsaveopt64(p: *mut u8, hi: u32, lo: u32); |
16 | #[link_name = "llvm.x86.xsavec64" ] |
17 | fn xsavec64(p: *mut u8, hi: u32, lo: u32); |
18 | #[link_name = "llvm.x86.xsaves64" ] |
19 | fn xsaves64(p: *mut u8, hi: u32, lo: u32); |
20 | #[link_name = "llvm.x86.xrstors64" ] |
21 | fn xrstors64(p: *const u8, hi: u32, lo: u32); |
22 | } |
23 | |
24 | /// Performs a full or partial save of the enabled processor states to memory at |
25 | /// `mem_addr`. |
26 | /// |
27 | /// State is saved based on bits `[62:0]` in `save_mask` and XCR0. |
28 | /// `mem_addr` must be aligned on a 64-byte boundary. |
29 | /// |
30 | /// The format of the XSAVE area is detailed in Section 13.4, “XSAVE Area,” of |
31 | /// Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1. |
32 | /// |
33 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xsave64) |
34 | #[inline ] |
35 | #[target_feature (enable = "xsave" )] |
36 | #[cfg_attr (test, assert_instr(xsave64))] |
37 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
38 | pub unsafe fn _xsave64(mem_addr: *mut u8, save_mask: u64) { |
39 | xsave64(p:mem_addr, (save_mask >> 32) as u32, lo:save_mask as u32); |
40 | } |
41 | |
42 | /// Performs a full or partial restore of the enabled processor states using |
43 | /// the state information stored in memory at `mem_addr`. |
44 | /// |
45 | /// State is restored based on bits `[62:0]` in `rs_mask`, `XCR0`, and |
46 | /// `mem_addr.HEADER.XSTATE_BV`. `mem_addr` must be aligned on a 64-byte |
47 | /// boundary. |
48 | /// |
49 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xrstor64) |
50 | #[inline ] |
51 | #[target_feature (enable = "xsave" )] |
52 | #[cfg_attr (test, assert_instr(xrstor64))] |
53 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
54 | pub unsafe fn _xrstor64(mem_addr: *const u8, rs_mask: u64) { |
55 | xrstor64(p:mem_addr, (rs_mask >> 32) as u32, lo:rs_mask as u32); |
56 | } |
57 | |
58 | /// Performs a full or partial save of the enabled processor states to memory at |
59 | /// `mem_addr`. |
60 | /// |
61 | /// State is saved based on bits `[62:0]` in `save_mask` and `XCR0`. |
62 | /// `mem_addr` must be aligned on a 64-byte boundary. The hardware may optimize |
63 | /// the manner in which data is saved. The performance of this instruction will |
64 | /// be equal to or better than using the `XSAVE64` instruction. |
65 | /// |
66 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xsaveopt64) |
67 | #[inline ] |
68 | #[target_feature (enable = "xsave,xsaveopt" )] |
69 | #[cfg_attr (test, assert_instr(xsaveopt64))] |
70 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
71 | pub unsafe fn _xsaveopt64(mem_addr: *mut u8, save_mask: u64) { |
72 | xsaveopt64(p:mem_addr, (save_mask >> 32) as u32, lo:save_mask as u32); |
73 | } |
74 | |
75 | /// Performs a full or partial save of the enabled processor states to memory |
76 | /// at `mem_addr`. |
77 | /// |
78 | /// `xsavec` differs from `xsave` in that it uses compaction and that it may |
79 | /// use init optimization. State is saved based on bits `[62:0]` in `save_mask` |
80 | /// and `XCR0`. `mem_addr` must be aligned on a 64-byte boundary. |
81 | /// |
82 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xsavec64) |
83 | #[inline ] |
84 | #[target_feature (enable = "xsave,xsavec" )] |
85 | #[cfg_attr (test, assert_instr(xsavec64))] |
86 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
87 | pub unsafe fn _xsavec64(mem_addr: *mut u8, save_mask: u64) { |
88 | xsavec64(p:mem_addr, (save_mask >> 32) as u32, lo:save_mask as u32); |
89 | } |
90 | |
91 | /// Performs a full or partial save of the enabled processor states to memory at |
92 | /// `mem_addr` |
93 | /// |
94 | /// `xsaves` differs from xsave in that it can save state components |
95 | /// corresponding to bits set in `IA32_XSS` `MSR` and that it may use the |
96 | /// modified optimization. State is saved based on bits `[62:0]` in `save_mask` |
97 | /// and `XCR0`. `mem_addr` must be aligned on a 64-byte boundary. |
98 | /// |
99 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xsaves64) |
100 | #[inline ] |
101 | #[target_feature (enable = "xsave,xsaves" )] |
102 | #[cfg_attr (test, assert_instr(xsaves64))] |
103 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
104 | pub unsafe fn _xsaves64(mem_addr: *mut u8, save_mask: u64) { |
105 | xsaves64(p:mem_addr, (save_mask >> 32) as u32, lo:save_mask as u32); |
106 | } |
107 | |
108 | /// Performs a full or partial restore of the enabled processor states using the |
109 | /// state information stored in memory at `mem_addr`. |
110 | /// |
111 | /// `xrstors` differs from `xrstor` in that it can restore state components |
112 | /// corresponding to bits set in the `IA32_XSS` `MSR`; `xrstors` cannot restore |
113 | /// from an `xsave` area in which the extended region is in the standard form. |
114 | /// State is restored based on bits `[62:0]` in `rs_mask`, `XCR0`, and |
115 | /// `mem_addr.HEADER.XSTATE_BV`. `mem_addr` must be aligned on a 64-byte |
116 | /// boundary. |
117 | /// |
118 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xrstors64) |
119 | #[inline ] |
120 | #[target_feature (enable = "xsave,xsaves" )] |
121 | #[cfg_attr (test, assert_instr(xrstors64))] |
122 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
123 | pub unsafe fn _xrstors64(mem_addr: *const u8, rs_mask: u64) { |
124 | xrstors64(p:mem_addr, (rs_mask >> 32) as u32, lo:rs_mask as u32); |
125 | } |
126 | |
127 | // FIXME: https://github.com/rust-lang/stdarch/issues/209 |
128 | // All these tests fail with Intel SDE. |
129 | /* |
130 | #[cfg(test)] |
131 | mod tests { |
132 | use crate::core_arch::x86::x86_64::xsave; |
133 | use stdarch_test::simd_test; |
134 | use std::fmt; |
135 | |
136 | // FIXME: https://github.com/rust-lang/stdarch/issues/209 |
137 | #[repr(align(64))] |
138 | struct XsaveArea { |
139 | // max size for 256-bit registers is 800 bytes: |
140 | // see https://software.intel.com/en-us/node/682996 |
141 | // max size for 512-bit registers is 2560 bytes: |
142 | // FIXME: add source |
143 | data: [u8; 2560], |
144 | } |
145 | |
146 | impl XsaveArea { |
147 | fn new() -> XsaveArea { |
148 | XsaveArea { data: [0; 2560] } |
149 | } |
150 | fn ptr(&mut self) -> *mut u8 { |
151 | &mut self.data[0] as *mut _ as *mut u8 |
152 | } |
153 | } |
154 | |
155 | impl PartialEq<XsaveArea> for XsaveArea { |
156 | fn eq(&self, other: &XsaveArea) -> bool { |
157 | for i in 0..self.data.len() { |
158 | if self.data[i] != other.data[i] { |
159 | return false; |
160 | } |
161 | } |
162 | true |
163 | } |
164 | } |
165 | |
166 | impl fmt::Debug for XsaveArea { |
167 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
168 | write!(f, "[")?; |
169 | for i in 0..self.data.len() { |
170 | write!(f, "{}", self.data[i])?; |
171 | if i != self.data.len() - 1 { |
172 | write!(f, ", ")?; |
173 | } |
174 | } |
175 | write!(f, "]") |
176 | } |
177 | } |
178 | |
179 | #[simd_test(enable = "xsave")] |
180 | #[cfg_attr(miri, ignore)] // Register saving/restoring is not supported in Miri |
181 | unsafe fn xsave64() { |
182 | let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers |
183 | let mut a = XsaveArea::new(); |
184 | let mut b = XsaveArea::new(); |
185 | |
186 | xsave::_xsave64(a.ptr(), m); |
187 | xsave::_xrstor64(a.ptr(), m); |
188 | xsave::_xsave64(b.ptr(), m); |
189 | assert_eq!(a, b); |
190 | } |
191 | |
192 | #[simd_test(enable = "xsave,xsaveopt")] |
193 | #[cfg_attr(miri, ignore)] // Register saving/restoring is not supported in Miri |
194 | unsafe fn xsaveopt64() { |
195 | let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers |
196 | let mut a = XsaveArea::new(); |
197 | let mut b = XsaveArea::new(); |
198 | |
199 | xsave::_xsaveopt64(a.ptr(), m); |
200 | xsave::_xrstor64(a.ptr(), m); |
201 | xsave::_xsaveopt64(b.ptr(), m); |
202 | assert_eq!(a, b); |
203 | } |
204 | |
205 | #[simd_test(enable = "xsave,xsavec")] |
206 | #[cfg_attr(miri, ignore)] // Register saving/restoring is not supported in Miri |
207 | unsafe fn xsavec64() { |
208 | let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers |
209 | let mut a = XsaveArea::new(); |
210 | let mut b = XsaveArea::new(); |
211 | |
212 | xsave::_xsavec64(a.ptr(), m); |
213 | xsave::_xrstor64(a.ptr(), m); |
214 | xsave::_xsavec64(b.ptr(), m); |
215 | assert_eq!(a, b); |
216 | } |
217 | |
218 | #[simd_test(enable = "xsave,xsaves")] |
219 | #[cfg_attr(miri, ignore)] // Register saving/restoring is not supported in Miri |
220 | unsafe fn xsaves64() { |
221 | let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers |
222 | let mut a = XsaveArea::new(); |
223 | let mut b = XsaveArea::new(); |
224 | |
225 | xsave::_xsaves64(a.ptr(), m); |
226 | xsave::_xrstors64(a.ptr(), m); |
227 | xsave::_xsaves64(b.ptr(), m); |
228 | assert_eq!(a, b); |
229 | } |
230 | } |
231 | */ |
232 | |