core/stdarch/crates/core_arch/src/x86/xsave.rs
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)]
8unsafe 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")]
41pub unsafe fn _xsave(mem_addr: *mut u8, save_mask: u64) {
42 xsave(mem_addr, (save_mask >> 32) as u32, 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(mem_addr, (rs_mask >> 32) as u32, 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(a, (val >> 32) as u32, 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(mem_addr, (save_mask >> 32) as u32, 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(mem_addr, (save_mask >> 32) as u32, 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(mem_addr, (save_mask >> 32) as u32, 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(mem_addr, (rs_mask >> 32) as u32, 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 #[derive(Debug)]
171 struct XsaveArea {
172 // max size for 256-bit registers is 800 bytes:
173 // see https://software.intel.com/en-us/node/682996
174 // max size for 512-bit registers is 2560 bytes:
175 // FIXME: add source
176 data: [u8; 2560],
177 }
178
179 impl XsaveArea {
180 fn new() -> XsaveArea {
181 XsaveArea { data: [0; 2560] }
182 }
183 fn ptr(&mut self) -> *mut u8 {
184 self.data.as_mut_ptr()
185 }
186 }
187
188 #[simd_test(enable = "xsave")]
189 #[cfg_attr(miri, ignore)] // Register saving/restoring is not supported in Miri
190 unsafe fn test_xsave() {
191 let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers
192 let mut a = XsaveArea::new();
193 let mut b = XsaveArea::new();
194
195 _xsave(a.ptr(), m);
196 _xrstor(a.ptr(), m);
197 _xsave(b.ptr(), m);
198 }
199
200 #[simd_test(enable = "xsave")]
201 #[cfg_attr(miri, ignore)] // Register saving/restoring is not supported in Miri
202 unsafe fn test_xgetbv() {
203 let xcr_n: u32 = _XCR_XFEATURE_ENABLED_MASK;
204
205 let xcr: u64 = _xgetbv(xcr_n);
206 let xcr_cpy: u64 = _xgetbv(xcr_n);
207 assert_eq!(xcr, xcr_cpy);
208 }
209
210 #[simd_test(enable = "xsave,xsaveopt")]
211 #[cfg_attr(miri, ignore)] // Register saving/restoring is not supported in Miri
212 unsafe fn test_xsaveopt() {
213 let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers
214 let mut a = XsaveArea::new();
215 let mut b = XsaveArea::new();
216
217 _xsaveopt(a.ptr(), m);
218 _xrstor(a.ptr(), m);
219 _xsaveopt(b.ptr(), m);
220 }
221
222 #[simd_test(enable = "xsave,xsavec")]
223 #[cfg_attr(miri, ignore)] // Register saving/restoring is not supported in Miri
224 unsafe fn test_xsavec() {
225 let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers
226 let mut a = XsaveArea::new();
227 let mut b = XsaveArea::new();
228
229 _xsavec(a.ptr(), m);
230 _xrstor(a.ptr(), m);
231 _xsavec(b.ptr(), m);
232 }
233}