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 &mut self.data[0] as *mut _ as *mut u8
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 unsafe fn xsave() {
215 let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers
216 let mut a = XsaveArea::new();
217 let mut b = XsaveArea::new();
218
219 _xsave(a.ptr(), m);
220 _xrstor(a.ptr(), m);
221 _xsave(b.ptr(), m);
222 assert_eq!(a, b);
223 }
224 */
225
226 #[simd_test(enable = "xsave")]
227 unsafe fn xgetbv_xsetbv() {
228 let xcr_n: u32 = _XCR_XFEATURE_ENABLED_MASK;
229
230 let xcr: u64 = _xgetbv(xcr_n);
231 // FIXME: XSETBV is a privileged instruction we should only test this
232 // when running in privileged mode:
233 //
234 // _xsetbv(xcr_n, xcr);
235 let xcr_cpy: u64 = _xgetbv(xcr_n);
236 assert_eq!(xcr, xcr_cpy);
237 }
238
239 // FIXME: https://github.com/rust-lang/stdarch/issues/209
240 /*
241 #[simd_test(enable = "xsave,xsaveopt")]
242 unsafe fn xsaveopt() {
243 let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers
244 let mut a = XsaveArea::new();
245 let mut b = XsaveArea::new();
246
247 _xsaveopt(a.ptr(), m);
248 _xrstor(a.ptr(), m);
249 _xsaveopt(b.ptr(), m);
250 assert_eq!(a, b);
251 }
252 */
253
254 // FIXME: this looks like a bug in Intel's SDE:
255 #[cfg(not(stdarch_intel_sde))]
256 #[simd_test(enable = "xsave,xsavec")]
257 unsafe fn xsavec() {
258 let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers
259 let mut a = XsaveArea::new();
260 let mut b = XsaveArea::new();
261
262 _xsavec(a.ptr(), m);
263 _xrstor(a.ptr(), m);
264 _xsavec(b.ptr(), m);
265 assert_eq!(a, b);
266 }
267
268 // FIXME: https://github.com/rust-lang/stdarch/issues/209
269 /*
270 #[simd_test(enable = "xsave,xsaves")]
271 unsafe fn xsaves() {
272 let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers
273 let mut a = XsaveArea::new();
274 let mut b = XsaveArea::new();
275
276 _xsaves(a.ptr(), m);
277 _xrstors(a.ptr(), m);
278 _xsaves(b.ptr(), m);
279 assert_eq!(a, b);
280 }
281 */
282}
283