Skip to content

Commit e730686

Browse files
authored
Merge pull request #336 from jarkkojs/master
registers: MXCSR
2 parents 5014113 + d2ad56a commit e730686

File tree

4 files changed

+150
-0
lines changed

4 files changed

+150
-0
lines changed

src/asm/asm.s

+16
Original file line numberDiff line numberDiff line change
@@ -334,3 +334,19 @@ _x86_64_asm_xsetbv:
334334
movl %esi, %eax # Second param is the low 32-bits
335335
xsetbv # Third param (high 32-bits) is already in %edx
336336
retq
337+
338+
.global _x86_64_asm_write_mxcsr
339+
.p2align 4
340+
_x86_64_asm_write_mxcsr:
341+
pushq %rdi
342+
ldmxcsr (%rsp)
343+
popq %rdi
344+
retq
345+
346+
.global _x86_64_asm_read_mxcsr
347+
.p2align 4
348+
_x86_64_asm_read_mxcsr:
349+
pushq $0
350+
stmxcsr (%rsp)
351+
popq %rax
352+
retq

src/asm/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -299,4 +299,16 @@ extern "sysv64" {
299299
link_name = "_x86_64_asm_xsetbv"
300300
)]
301301
pub(crate) fn x86_64_asm_xsetbv(xcr: u32, low: u32, high: u32);
302+
303+
#[cfg_attr(
304+
any(target_env = "gnu", target_env = "musl"),
305+
link_name = "_x86_64_asm_read_mxcsr"
306+
)]
307+
pub(crate) fn x86_64_asm_read_mxcsr() -> u32;
308+
309+
#[cfg_attr(
310+
any(target_env = "gnu", target_env = "musl"),
311+
link_name = "_x86_64_asm_write_mxcsr"
312+
)]
313+
pub(crate) fn x86_64_asm_write_mxcsr(val: u32);
302314
}

src/registers/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
pub mod control;
44
pub mod model_specific;
5+
pub mod mxcsr;
56
pub mod rflags;
67
pub mod segmentation;
78
pub mod xcontrol;

src/registers/mxcsr.rs

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//! Functions to read and write MXCSR register.
2+
3+
#[cfg(feature = "instructions")]
4+
pub use self::x86_64::*;
5+
6+
use bitflags::bitflags;
7+
8+
bitflags! {
9+
/// MXCSR register.
10+
#[repr(transparent)]
11+
pub struct MxCsr: u32 {
12+
/// Invalid operation
13+
const INVALID_OPERATION = 1 << 0;
14+
/// Denormal
15+
const DENORMAL = 1 << 1;
16+
/// Divide-by-zero
17+
const DIVIDE_BY_ZERO = 1 << 2;
18+
/// Overflow
19+
const OVERFLOW = 1 << 3;
20+
/// Underflow
21+
const UNDERFLOW = 1 << 4;
22+
/// Precision
23+
const PRECISION = 1 << 5;
24+
/// Denormals are zeros
25+
const DENORMALS_ARE_ZEROS = 1 << 6;
26+
/// Invalid operation mask
27+
const INVALID_OPERATION_MASK = 1 << 7;
28+
/// Denormal mask
29+
const DENORMAL_MASK = 1 << 8;
30+
/// Divide-by-zero mask
31+
const DIVIDE_BY_ZERO_MASK = 1 << 9;
32+
/// Overflow mask
33+
const OVERFLOW_MASK = 1 << 10;
34+
/// Underflow mask
35+
const UNDERFLOW_MASK = 1 << 11;
36+
/// Precision mask
37+
const PRECISION_MASK = 1 << 12;
38+
/// Toward negative infinity
39+
const ROUNDING_CONTROL_NEGATIVE = 1 << 13;
40+
/// Toward positive infinity
41+
const ROUNDING_CONTROL_POSITIVE = 1 << 14;
42+
/// Toward zero (positive + negative)
43+
const ROUNDING_CONTROL_ZERO = 3 << 13;
44+
/// Flush to zero
45+
const FLUSH_TO_ZERO = 1 << 15;
46+
}
47+
}
48+
49+
impl Default for MxCsr {
50+
/// Return the default MXCSR value at reset, as documented in Intel SDM volume 2A.
51+
#[inline]
52+
fn default() -> Self {
53+
MxCsr::INVALID_OPERATION_MASK
54+
| MxCsr::DENORMAL_MASK
55+
| MxCsr::DIVIDE_BY_ZERO_MASK
56+
| MxCsr::OVERFLOW_MASK
57+
| MxCsr::UNDERFLOW_MASK
58+
| MxCsr::PRECISION_MASK
59+
}
60+
}
61+
62+
#[cfg(feature = "instructions")]
63+
mod x86_64 {
64+
use super::*;
65+
#[cfg(feature = "inline_asm")]
66+
use core::arch::asm;
67+
68+
/// Read the value of MXCSR.
69+
#[inline]
70+
pub fn read() -> MxCsr {
71+
#[cfg(feature = "inline_asm")]
72+
{
73+
let mut mxcsr: u32 = 0;
74+
unsafe {
75+
asm!("stmxcsr [{}]", in(reg) &mut mxcsr, options(nostack, preserves_flags));
76+
}
77+
MxCsr::from_bits_truncate(mxcsr)
78+
}
79+
#[cfg(not(feature = "inline_asm"))]
80+
unsafe {
81+
MxCsr::from_bits_truncate(crate::asm::x86_64_asm_read_mxcsr())
82+
}
83+
}
84+
85+
/// Write MXCSR.
86+
#[inline]
87+
pub fn write(mxcsr: MxCsr) {
88+
#[cfg(feature = "inline_asm")]
89+
unsafe {
90+
asm!("ldmxcsr [{}]", in(reg) &mxcsr, options(nostack, readonly));
91+
}
92+
#[cfg(not(feature = "inline_asm"))]
93+
unsafe {
94+
crate::asm::x86_64_asm_write_mxcsr(mxcsr.bits());
95+
}
96+
}
97+
98+
#[cfg(test)]
99+
mod test {
100+
use crate::registers::mxcsr::*;
101+
102+
#[test]
103+
fn mxcsr_default() {
104+
let mxcsr = read();
105+
assert_eq!(mxcsr, MxCsr::from_bits_truncate(0x1F80));
106+
}
107+
108+
#[test]
109+
fn mxcsr_read() {
110+
let mxcsr = read();
111+
assert_eq!(mxcsr, MxCsr::default());
112+
}
113+
114+
#[test]
115+
fn mxcsr_write() {
116+
let mxcsr = read();
117+
write(mxcsr);
118+
assert_eq!(mxcsr, read());
119+
}
120+
}
121+
}

0 commit comments

Comments
 (0)