| 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 | unsafe extern "C"{ | 
|---|
| 9 | #[ link_name= "llvm.x86.xsave"] | 
|---|
| 10 | unsafefn xsave(p: *mut u8, hi: u32, lo: u32); | 
|---|
| 11 | #[ link_name= "llvm.x86.xrstor"] | 
|---|
| 12 | unsafefn xrstor(p: *const u8, hi: u32, lo: u32); | 
|---|
| 13 | #[ link_name= "llvm.x86.xsetbv"] | 
|---|
| 14 | unsafefn xsetbv(v: u32, hi: u32, lo: u32); | 
|---|
| 15 | #[ link_name= "llvm.x86.xgetbv"] | 
|---|
| 16 | unsafefn xgetbv(v: u32) -> i64; | 
|---|
| 17 | #[ link_name= "llvm.x86.xsaveopt"] | 
|---|
| 18 | unsafefn xsaveopt(p: *mut u8, hi: u32, lo: u32); | 
|---|
| 19 | #[ link_name= "llvm.x86.xsavec"] | 
|---|
| 20 | unsafefn xsavec(p: *mut u8, hi: u32, lo: u32); | 
|---|
| 21 | #[ link_name= "llvm.x86.xsaves"] | 
|---|
| 22 | unsafefn xsaves(p: *mut u8, hi: u32, lo: u32); | 
|---|
| 23 | #[ link_name= "llvm.x86.xrstors"] | 
|---|
| 24 | unsafefn 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 | #[ 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 | } | 
|---|
| 234 |  | 
|---|