1 | //! `i586`'s `xsave` and `xsaveopt` target feature intrinsics |
2 | #![allow (clippy::module_name_repetitions)] |
3 | |
4 | #[cfg (test)] |
5 | use stdarch_test::assert_instr; |
6 | |
7 | #[allow (improper_ctypes)] |
8 | extern "C" { |
9 | #[link_name = "llvm.x86.xsave" ] |
10 | fn xsave(p: *mut u8, hi: u32, lo: u32); |
11 | #[link_name = "llvm.x86.xrstor" ] |
12 | fn xrstor(p: *const u8, hi: u32, lo: u32); |
13 | #[link_name = "llvm.x86.xsetbv" ] |
14 | fn xsetbv(v: u32, hi: u32, lo: u32); |
15 | #[link_name = "llvm.x86.xgetbv" ] |
16 | fn xgetbv(v: u32) -> i64; |
17 | #[link_name = "llvm.x86.xsaveopt" ] |
18 | fn xsaveopt(p: *mut u8, hi: u32, lo: u32); |
19 | #[link_name = "llvm.x86.xsavec" ] |
20 | fn xsavec(p: *mut u8, hi: u32, lo: u32); |
21 | #[link_name = "llvm.x86.xsaves" ] |
22 | fn xsaves(p: *mut u8, hi: u32, lo: u32); |
23 | #[link_name = "llvm.x86.xrstors" ] |
24 | fn xrstors(p: *const u8, hi: u32, lo: u32); |
25 | } |
26 | |
27 | /// Performs a full or partial save of the enabled processor states to memory at |
28 | /// `mem_addr`. |
29 | /// |
30 | /// State is saved based on bits `[62:0]` in `save_mask` and XCR0. |
31 | /// `mem_addr` must be aligned on a 64-byte boundary. |
32 | /// |
33 | /// The format of the XSAVE area is detailed in Section 13.4, “XSAVE Area,” of |
34 | /// Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1. |
35 | /// |
36 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xsave) |
37 | #[inline ] |
38 | #[target_feature (enable = "xsave" )] |
39 | #[cfg_attr (test, assert_instr(xsave))] |
40 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
41 | pub unsafe fn _xsave(mem_addr: *mut u8, save_mask: u64) { |
42 | xsave(p:mem_addr, (save_mask >> 32) as u32, lo:save_mask as u32); |
43 | } |
44 | |
45 | /// Performs a full or partial restore of the enabled processor states using |
46 | /// the state information stored in memory at `mem_addr`. |
47 | /// |
48 | /// State is restored based on bits `[62:0]` in `rs_mask`, `XCR0`, and |
49 | /// `mem_addr.HEADER.XSTATE_BV`. `mem_addr` must be aligned on a 64-byte |
50 | /// boundary. |
51 | /// |
52 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xrstor) |
53 | #[inline ] |
54 | #[target_feature (enable = "xsave" )] |
55 | #[cfg_attr (test, assert_instr(xrstor))] |
56 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
57 | pub unsafe fn _xrstor(mem_addr: *const u8, rs_mask: u64) { |
58 | xrstor(p:mem_addr, (rs_mask >> 32) as u32, lo:rs_mask as u32); |
59 | } |
60 | |
61 | /// `XFEATURE_ENABLED_MASK` for `XCR` |
62 | /// |
63 | /// This intrinsic maps to `XSETBV` instruction. |
64 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
65 | pub const _XCR_XFEATURE_ENABLED_MASK: u32 = 0; |
66 | |
67 | /// Copies 64-bits from `val` to the extended control register (`XCR`) specified |
68 | /// by `a`. |
69 | /// |
70 | /// Currently only `XFEATURE_ENABLED_MASK` `XCR` is supported. |
71 | /// |
72 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xsetbv) |
73 | #[inline ] |
74 | #[target_feature (enable = "xsave" )] |
75 | #[cfg_attr (test, assert_instr(xsetbv))] |
76 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
77 | pub unsafe fn _xsetbv(a: u32, val: u64) { |
78 | xsetbv(v:a, (val >> 32) as u32, lo:val as u32); |
79 | } |
80 | |
81 | /// Reads the contents of the extended control register `XCR` |
82 | /// specified in `xcr_no`. |
83 | /// |
84 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xgetbv) |
85 | #[inline ] |
86 | #[target_feature (enable = "xsave" )] |
87 | #[cfg_attr (test, assert_instr(xgetbv))] |
88 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
89 | pub unsafe fn _xgetbv(xcr_no: u32) -> u64 { |
90 | xgetbv(xcr_no) as u64 |
91 | } |
92 | |
93 | /// Performs a full or partial save of the enabled processor states to memory at |
94 | /// `mem_addr`. |
95 | /// |
96 | /// State is saved based on bits `[62:0]` in `save_mask` and `XCR0`. |
97 | /// `mem_addr` must be aligned on a 64-byte boundary. The hardware may optimize |
98 | /// the manner in which data is saved. The performance of this instruction will |
99 | /// be equal to or better than using the `XSAVE` instruction. |
100 | /// |
101 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xsaveopt) |
102 | #[inline ] |
103 | #[target_feature (enable = "xsave,xsaveopt" )] |
104 | #[cfg_attr (test, assert_instr(xsaveopt))] |
105 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
106 | pub unsafe fn _xsaveopt(mem_addr: *mut u8, save_mask: u64) { |
107 | xsaveopt(p:mem_addr, (save_mask >> 32) as u32, lo:save_mask as u32); |
108 | } |
109 | |
110 | /// Performs a full or partial save of the enabled processor states to memory |
111 | /// at `mem_addr`. |
112 | /// |
113 | /// `xsavec` differs from `xsave` in that it uses compaction and that it may |
114 | /// use init optimization. State is saved based on bits `[62:0]` in `save_mask` |
115 | /// and `XCR0`. `mem_addr` must be aligned on a 64-byte boundary. |
116 | /// |
117 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xsavec) |
118 | #[inline ] |
119 | #[target_feature (enable = "xsave,xsavec" )] |
120 | #[cfg_attr (test, assert_instr(xsavec))] |
121 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
122 | pub unsafe fn _xsavec(mem_addr: *mut u8, save_mask: u64) { |
123 | xsavec(p:mem_addr, (save_mask >> 32) as u32, lo:save_mask as u32); |
124 | } |
125 | |
126 | /// Performs a full or partial save of the enabled processor states to memory at |
127 | /// `mem_addr` |
128 | /// |
129 | /// `xsaves` differs from xsave in that it can save state components |
130 | /// corresponding to bits set in `IA32_XSS` `MSR` and that it may use the |
131 | /// modified optimization. State is saved based on bits `[62:0]` in `save_mask` |
132 | /// and `XCR0`. `mem_addr` must be aligned on a 64-byte boundary. |
133 | /// |
134 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xsaves) |
135 | #[inline ] |
136 | #[target_feature (enable = "xsave,xsaves" )] |
137 | #[cfg_attr (test, assert_instr(xsaves))] |
138 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
139 | pub unsafe fn _xsaves(mem_addr: *mut u8, save_mask: u64) { |
140 | xsaves(p:mem_addr, (save_mask >> 32) as u32, lo:save_mask as u32); |
141 | } |
142 | |
143 | /// Performs a full or partial restore of the enabled processor states using the |
144 | /// state information stored in memory at `mem_addr`. |
145 | /// |
146 | /// `xrstors` differs from `xrstor` in that it can restore state components |
147 | /// corresponding to bits set in the `IA32_XSS` `MSR`; `xrstors` cannot restore |
148 | /// from an `xsave` area in which the extended region is in the standard form. |
149 | /// State is restored based on bits `[62:0]` in `rs_mask`, `XCR0`, and |
150 | /// `mem_addr.HEADER.XSTATE_BV`. `mem_addr` must be aligned on a 64-byte |
151 | /// boundary. |
152 | /// |
153 | /// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_xrstors) |
154 | #[inline ] |
155 | #[target_feature (enable = "xsave,xsaves" )] |
156 | #[cfg_attr (test, assert_instr(xrstors))] |
157 | #[stable (feature = "simd_x86" , since = "1.27.0" )] |
158 | pub unsafe fn _xrstors(mem_addr: *const u8, rs_mask: u64) { |
159 | xrstors(p:mem_addr, (rs_mask >> 32) as u32, lo:rs_mask as u32); |
160 | } |
161 | |
162 | #[cfg (test)] |
163 | mod tests { |
164 | use std::{fmt, prelude::v1::*}; |
165 | |
166 | use crate::core_arch::x86::*; |
167 | use stdarch_test::simd_test; |
168 | |
169 | #[repr (align(64))] |
170 | struct XsaveArea { |
171 | // max size for 256-bit registers is 800 bytes: |
172 | // see https://software.intel.com/en-us/node/682996 |
173 | // max size for 512-bit registers is 2560 bytes: |
174 | // FIXME: add source |
175 | data: [u8; 2560], |
176 | } |
177 | |
178 | impl XsaveArea { |
179 | fn new() -> XsaveArea { |
180 | XsaveArea { data: [0; 2560] } |
181 | } |
182 | fn ptr(&mut self) -> *mut u8 { |
183 | self.data.as_mut_ptr() |
184 | } |
185 | } |
186 | |
187 | impl PartialEq<XsaveArea> for XsaveArea { |
188 | fn eq(&self, other: &XsaveArea) -> bool { |
189 | for i in 0..self.data.len() { |
190 | if self.data[i] != other.data[i] { |
191 | return false; |
192 | } |
193 | } |
194 | true |
195 | } |
196 | } |
197 | |
198 | impl fmt::Debug for XsaveArea { |
199 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
200 | write!(f, "[" )?; |
201 | for i in 0..self.data.len() { |
202 | write!(f, " {}" , self.data[i])?; |
203 | if i != self.data.len() - 1 { |
204 | write!(f, ", " )?; |
205 | } |
206 | } |
207 | write!(f, "]" ) |
208 | } |
209 | } |
210 | |
211 | // FIXME: https://github.com/rust-lang/stdarch/issues/209 |
212 | /* |
213 | #[simd_test(enable = "xsave")] |
214 | #[cfg_attr(miri, ignore)] // Register saving/restoring is not supported in Miri |
215 | unsafe fn xsave() { |
216 | let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers |
217 | let mut a = XsaveArea::new(); |
218 | let mut b = XsaveArea::new(); |
219 | |
220 | _xsave(a.ptr(), m); |
221 | _xrstor(a.ptr(), m); |
222 | _xsave(b.ptr(), m); |
223 | assert_eq!(a, b); |
224 | } |
225 | */ |
226 | |
227 | #[simd_test(enable = "xsave" )] |
228 | #[cfg_attr (miri, ignore)] // Register saving/restoring is not supported in Miri |
229 | unsafe fn xgetbv_xsetbv() { |
230 | let xcr_n: u32 = _XCR_XFEATURE_ENABLED_MASK; |
231 | |
232 | let xcr: u64 = _xgetbv(xcr_n); |
233 | // FIXME: XSETBV is a privileged instruction we should only test this |
234 | // when running in privileged mode: |
235 | // |
236 | // _xsetbv(xcr_n, xcr); |
237 | let xcr_cpy: u64 = _xgetbv(xcr_n); |
238 | assert_eq!(xcr, xcr_cpy); |
239 | } |
240 | |
241 | // FIXME: https://github.com/rust-lang/stdarch/issues/209 |
242 | /* |
243 | #[simd_test(enable = "xsave,xsaveopt")] |
244 | #[cfg_attr(miri, ignore)] // Register saving/restoring is not supported in Miri |
245 | unsafe fn xsaveopt() { |
246 | let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers |
247 | let mut a = XsaveArea::new(); |
248 | let mut b = XsaveArea::new(); |
249 | |
250 | _xsaveopt(a.ptr(), m); |
251 | _xrstor(a.ptr(), m); |
252 | _xsaveopt(b.ptr(), m); |
253 | assert_eq!(a, b); |
254 | } |
255 | */ |
256 | |
257 | // FIXME: this looks like a bug in Intel's SDE: |
258 | #[cfg (not(stdarch_intel_sde))] |
259 | #[simd_test(enable = "xsave,xsavec" )] |
260 | #[cfg_attr (miri, ignore)] // Register saving/restoring is not supported in Miri |
261 | unsafe fn xsavec() { |
262 | let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers |
263 | let mut a = XsaveArea::new(); |
264 | let mut b = XsaveArea::new(); |
265 | |
266 | _xsavec(a.ptr(), m); |
267 | _xrstor(a.ptr(), m); |
268 | _xsavec(b.ptr(), m); |
269 | assert_eq!(a, b); |
270 | } |
271 | |
272 | // FIXME: https://github.com/rust-lang/stdarch/issues/209 |
273 | /* |
274 | #[simd_test(enable = "xsave,xsaves")] |
275 | unsafe fn xsaves() { |
276 | let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers |
277 | let mut a = XsaveArea::new(); |
278 | let mut b = XsaveArea::new(); |
279 | |
280 | _xsaves(a.ptr(), m); |
281 | _xrstors(a.ptr(), m); |
282 | _xsaves(b.ptr(), m); |
283 | assert_eq!(a, b); |
284 | } |
285 | */ |
286 | } |
287 | |