1//! `i586`'s `xsave` and `xsaveopt` target feature intrinsics
2#![allow(clippy::module_name_repetitions)]
3
4#[cfg(test)]
5use stdarch_test::assert_instr;
6
7#[allow(improper_ctypes)]
8extern "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")]
41pub 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")]
57pub 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")]
65pub 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")]
77pub 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")]
89pub 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")]
106pub 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")]
122pub 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")]
139pub 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")]
158pub 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)]
163mod 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