<<<    Index    >>>
F-14
GUIDELINES FOR WRITING SIMD FLOATING-POINT EXCEPTION 
typedef struct {
  unsigned int operation; // Streaming SIMD Extensions operation: ADDPS, ADDSS, ...
  float operand1_fval; // first operand value
  float operand2_fval; // second operand value (if any)
  float result_fval; // result value (if any)
  unsigned int rounding_mode; // rounding mode
  unsigned int exc_masks; // exception masks, in the order P, U, O, Z, D, I
  unsigned int exception_cause; // exception cause
  unsigned int status_flag_inexact; // inexact status flag
  unsigned int status_flag_underflow; // underflow status flag
  unsigned int status_flag_overflow; // overflow status flag
  unsigned int status_flag_divide_by_zero; // divide by zero status flag
  unsigned int status_flag_denormal_operand; // denormal operand status flag
  unsigned int status_flag_invalid_operation; // invalid operation status flag
  unsigned int ftz; // flush-to-zero flag
} EXC_ENV;
The arithmetic operations exemplified are emulated as follows:
1.Perform the operation using IA-32 FPU instructions, with exceptions disabled, the original
user rounding mode, and single precision; this will reveal invalid, denormal, or divide-by-
zero exceptions (if there are any); store the result in memory as a double precision value
(whose exponent range is large enough to look like “unbounded” to the result of the single
precision computation).
2.If no unmasked exceptions were detected, determine if the result is tiny (less than the
smallest normal number that can be represented in single precision format), or huge
(greater than the largest normal number that can be represented in single precision format);
if an unmasked overflow or underflow occur, calculate the scaled result that will be handed
to the user exception handler, as specified by the IEEE-754 Standard for Binary Floating-
Point Computations.
3.If no exception was raised above, calculate the result with “bounded” exponent; if the
result was tiny, it will require denormalization (shifting right the significand while incre-
menting the exponent to bring it into the admissible range of [-126,+127] for single
precision floating-point numbers); the result obtained in step A above cannot be used
because it might incur a double rounding error (it was rounded to 24 bits in step A, and
might have to be rounded again in the denormalization process); the way to overcome this
is to calculate the result as a double precision value, and then to store it to memory in
single precision format - rounding first to 53 bits in the significand, and then to 24 will
never cause a double rounding error (exact properties exist that state when double-
rounding error does not occur, but for the elementary arithmetic operations, the rule of
thumb is that if we round an infinitely precise result to 2p+1 bits and then again to p bits,
the result is the same as when rounding directly to p bits, which means that no double
rounding error occurs).
4.If the result is inexact and the inexact exceptions are unmasked, the result calculated in
step C will be delivered to the user floating-point exception handler.
5.Finally, the flush-to-zero case is dealt with if the result is tiny.
<<<    Index    >>>