core::arch::x86

Function _mm_setcsr

1.27.0 · source
pub unsafe fn _mm_setcsr(val: u32)
👎Deprecated since 1.75.0: see _mm_setcsr documentation - use inline assembly instead
Available on (x86 or x86-64) and target feature sse and x86 only.
Expand description

Sets the MXCSR register with the 32-bit unsigned integer value.

This register controls how SIMD instructions handle floating point operations. Modifying this register only affects the current thread.

It contains several groups of flags:

  • Exception flags report which exceptions occurred since last they were reset.

  • Masking flags can be used to mask (ignore) certain exceptions. By default these flags are all set to 1, so all exceptions are masked. When an an exception is masked, the processor simply sets the exception flag and continues the operation. If the exception is unmasked, the flag is also set but additionally an exception handler is invoked.

  • Rounding mode flags control the rounding mode of floating point instructions.

  • The denormals-are-zero mode flag turns all numbers which would be denormalized (exponent bits are all zeros) into zeros.

Note that modifying the masking flags, rounding mode, or denormals-are-zero mode flags leads to immediate Undefined Behavior: Rust assumes that these are always in their default state and will optimize accordingly. This even applies when the register is altered and later reset to its original value without any floating-point operations appearing in the source code between those operations (since floating-point operations appearing earlier or later can be reordered).

If you need to perform some floating-point operations under a different masking flags, rounding mode, or denormals-are-zero mode, use an inline assembly block and make sure to restore the original MXCSR register state before the end of the block.

§Exception Flags

  • _MM_EXCEPT_INVALID: An invalid operation was performed (e.g., dividing Infinity by Infinity).

  • _MM_EXCEPT_DENORM: An operation attempted to operate on a denormalized number. Mainly this can cause loss of precision.

  • _MM_EXCEPT_DIV_ZERO: Division by zero occurred.

  • _MM_EXCEPT_OVERFLOW: A numeric overflow exception occurred, i.e., a result was too large to be represented (e.g., an f32 with absolute value greater than 2^128).

  • _MM_EXCEPT_UNDERFLOW: A numeric underflow exception occurred, i.e., a result was too small to be represented in a normalized way (e.g., an f32 with absulte value smaller than 2^-126.)

  • _MM_EXCEPT_INEXACT: An inexact-result exception occurred (a.k.a. precision exception). This means some precision was lost due to rounding. For example, the fraction 1/3 cannot be represented accurately in a 32 or 64 bit float and computing it would cause this exception to be raised. Precision exceptions are very common, so they are usually masked.

Exception flags can be read and set using the convenience functions _MM_GET_EXCEPTION_STATE and _MM_SET_EXCEPTION_STATE. For example, to check if an operation caused some overflow:

_MM_SET_EXCEPTION_STATE(0); // clear all exception flags
                            // perform calculations
if _MM_GET_EXCEPTION_STATE() & _MM_EXCEPT_OVERFLOW != 0 {
    // handle overflow
}

§Masking Flags

There is one masking flag for each exception flag: _MM_MASK_INVALID, _MM_MASK_DENORM, _MM_MASK_DIV_ZERO, _MM_MASK_OVERFLOW, _MM_MASK_UNDERFLOW, _MM_MASK_INEXACT.

A single masking bit can be set via

_MM_SET_EXCEPTION_MASK(_MM_MASK_UNDERFLOW);

However, since mask bits are by default all set to 1, it is more common to want to disable certain bits. For example, to unmask the underflow exception, use:

_mm_setcsr(_mm_getcsr() & !_MM_MASK_UNDERFLOW); // unmask underflow
exception

Warning: an unmasked exception will cause an exception handler to be called. The standard handler will simply terminate the process. So, in this case any underflow exception would terminate the current process with something like signal: 8, SIGFPE: erroneous arithmetic operation.

§Rounding Mode

The rounding mode is describe using two bits. It can be read and set using the convenience wrappers _MM_GET_ROUNDING_MODE() and _MM_SET_ROUNDING_MODE(mode).

The rounding modes are:

  • _MM_ROUND_NEAREST: (default) Round to closest to the infinite precision value. If two values are equally close, round to even (i.e., least significant bit will be zero).

  • _MM_ROUND_DOWN: Round toward negative Infinity.

  • _MM_ROUND_UP: Round toward positive Infinity.

  • _MM_ROUND_TOWARD_ZERO: Round towards zero (truncate).

Example:

_MM_SET_ROUNDING_MODE(_MM_ROUND_DOWN)

§Denormals-are-zero/Flush-to-zero Mode

If this bit is set, values that would be denormalized will be set to zero instead. This is turned off by default.

You can read and enable/disable this mode via the helper functions _MM_GET_FLUSH_ZERO_MODE() and _MM_SET_FLUSH_ZERO_MODE():

_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF); // turn off (default)
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); // turn on

Intel’s documentation