Fixing FPU control word on Win32

On Win32 fixing of control word is also possible, but done differently, as Win32 uses SEH (structured exception handlers) to handle hardware faults, and some magic is required to let fault really restart.
#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <stdlib.h>
#include <float.h>

long original_fpcw = 0;

LONG WINAPI exceptionFilter(struct _EXCEPTION_POINTERS\* exceptionInfo) {
    DWORD ec = exceptionInfo->ExceptionRecord->ExceptionCode; 
	
    if (ec == EXCEPTION_FLT_UNDERFLOW || ec == EXCEPTION_FLT_INEXACT_RESULT) {
	  PCONTEXT ctx = exceptionInfo->ContextRecord;
          // mask underflow, precision, invalid
          ctx->FloatSave.ControlWord = original_fpcw | 0xffff0031;
	  ctx->FloatSave.StatusWord &= ctx->FloatSave.ControlWord | 0xffffff80;
          return EXCEPTION_CONTINUE_EXECUTION;
    }

    return EXCEPTION_CONTINUE_SEARCH;
}

int _tmain(int argc, _TCHAR\* argv[]) 
{
__try {
       
        float d=0.1,v=1;
        int i;
        original_fpcw = _control87(0, 0);
        _control87(_EM_INEXACT, MCW_EM);

        for (i=0; i < 1000; i++) {
            v \*= d;
        }
        printf("v = %0.60f\\n",v);
    } __except(exceptionFilter(
               (_EXCEPTION_POINTERS\*)GetExceptionInformation())) {
    }
    return 0;
}

PS: for references, FPU control word bits mean (fpu_control.h):
 \*     15-13    12  11-10  9-8     7-6     5    4    3    2    1    0
 \* | reserved | IC | RC  | PC | reserved | PM | UM | OM | ZM | DM | IM
 \*
 \* IM: Invalid operation mask
 \* DM: Denormalized operand mask
 \* ZM: Zero-divide mask
 \* OM: Overflow mask
 \* UM: Underflow mask
 \* PM: Precision (inexact result) mask
 \*
 \* Mask bit is 1 means no interrupt.
 \*
 \* PC: Precision control
 \* 11 - round to extended precision
 \* 10 - round to double precision
 \* 00 - round to single precision
 \*
 \* RC: Rounding control
 \* 00 - rounding to nearest
 \* 01 - rounding down (toward - infinity)
 \* 10 - rounding up (toward + infinity)
 \* 11 - rounding toward zero
 \*
 \*
 \* IC: Infinity control
 \* That is for 8087 and 80287 only.
Comments:

Seems to be enough and more accurate just to do this: ctx->FloatSave.ControlWord = original_fpcw | xffffFFC0; ctx->FloatSave.StatusWord &= 0xffffff00; At least the test survives with this change.

Posted by Ivan Krylov on July 03, 2007 at 11:05 AM MSD #

On Win64 you'll need to restore value of ctx->MxCsr

Posted by Ivan Krylov on August 01, 2007 at 08:27 AM MSD #

Post a Comment:
  • HTML Syntax: NOT allowed
About

nike

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today