1//! `x86_64`'s `xsave` and `xsaveopt` target feature intrinsics
2
3#![allow(clippy::module_name_repetitions)]
4
5#[cfg(test)]
6use stdarch_test::assert_instr;
7
8#[allow(improper_ctypes)]
9extern "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")]
38pub 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")]
54pub 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")]
71pub 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")]
87pub 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")]
104pub 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")]
123pub 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)]
131mod 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 unsafe fn xsave64() {
181 let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers
182 let mut a = XsaveArea::new();
183 let mut b = XsaveArea::new();
184
185 xsave::_xsave64(a.ptr(), m);
186 xsave::_xrstor64(a.ptr(), m);
187 xsave::_xsave64(b.ptr(), m);
188 assert_eq!(a, b);
189 }
190
191 #[simd_test(enable = "xsave,xsaveopt")]
192 unsafe fn xsaveopt64() {
193 let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers
194 let mut a = XsaveArea::new();
195 let mut b = XsaveArea::new();
196
197 xsave::_xsaveopt64(a.ptr(), m);
198 xsave::_xrstor64(a.ptr(), m);
199 xsave::_xsaveopt64(b.ptr(), m);
200 assert_eq!(a, b);
201 }
202
203 #[simd_test(enable = "xsave,xsavec")]
204 unsafe fn xsavec64() {
205 let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers
206 let mut a = XsaveArea::new();
207 let mut b = XsaveArea::new();
208
209 xsave::_xsavec64(a.ptr(), m);
210 xsave::_xrstor64(a.ptr(), m);
211 xsave::_xsavec64(b.ptr(), m);
212 assert_eq!(a, b);
213 }
214
215 #[simd_test(enable = "xsave,xsaves")]
216 unsafe fn xsaves64() {
217 let m = 0xFFFFFFFFFFFFFFFF_u64; //< all registers
218 let mut a = XsaveArea::new();
219 let mut b = XsaveArea::new();
220
221 xsave::_xsaves64(a.ptr(), m);
222 xsave::_xrstors64(a.ptr(), m);
223 xsave::_xsaves64(b.ptr(), m);
224 assert_eq!(a, b);
225 }
226}
227*/
228