123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- /*
- * src/fpu.cc
- *
- * This work was supported by the Director, Office of Science, Division
- * of Mathematical, Information, and Computational Sciences of the
- * U.S. Department of Energy under contract number DE-AC03-76SF00098.
- *
- * Copyright (c) 2000-2001
- *
- * Contains functions to set and restore the round-to-double flag in the
- * control word of a x86 FPU.
- */
- #include "config.h"
- #include <qd/fpu.h>
- #ifdef X86
- #ifdef _WIN32
- #include <float.h>
- #else
- #ifdef HAVE_FPU_CONTROL_H
- #include <fpu_control.h>
- #endif
- #ifndef _FPU_GETCW
- #define _FPU_GETCW(x) asm volatile ("fnstcw %0":"=m" (x));
- #endif
- #ifndef _FPU_SETCW
- #define _FPU_SETCW(x) asm volatile ("fldcw %0": :"m" (x));
- #endif
- #ifndef _FPU_EXTENDED
- #define _FPU_EXTENDED 0x0300
- #endif
- #ifndef _FPU_DOUBLE
- #define _FPU_DOUBLE 0x0200
- #endif
- #endif
- #endif /* X86 */
- extern "C" {
- void fpu_fix_start(unsigned int *old_cw) {
- #ifdef X86
- #ifdef _WIN32
- #ifdef __BORLANDC__
- /* Win 32 Borland C */
- unsigned short cw = _control87(0, 0);
- _control87(0x0200, 0x0300);
- if (old_cw) {
- *old_cw = cw;
- }
- #else
- /* Win 32 MSVC */
- unsigned int cw = _control87(0, 0);
- _control87(0x00010000, 0x00030000);
- if (old_cw) {
- *old_cw = cw;
- }
- #endif
- #else
- /* Linux */
- volatile unsigned short cw, new_cw;
- _FPU_GETCW(cw);
- new_cw = (cw & ~_FPU_EXTENDED) | _FPU_DOUBLE;
- _FPU_SETCW(new_cw);
-
- if (old_cw) {
- *old_cw = cw;
- }
- #endif
- #endif
- }
- void fpu_fix_end(unsigned int *old_cw) {
- #ifdef X86
- #ifdef _WIN32
- #ifdef __BORLANDC__
- /* Win 32 Borland C */
- if (old_cw) {
- unsigned short cw = (unsigned short) *old_cw;
- _control87(cw, 0xFFFF);
- }
- #else
- /* Win 32 MSVC */
- if (old_cw) {
- _control87(*old_cw, 0xFFFFFFFF);
- }
- #endif
- #else
- /* Linux */
- if (old_cw) {
- int cw;
- cw = *old_cw;
- _FPU_SETCW(cw);
- }
- #endif
- #endif
- }
- #ifdef HAVE_FORTRAN
- #define f_fpu_fix_start FC_FUNC_(f_fpu_fix_start, F_FPU_FIX_START)
- #define f_fpu_fix_end FC_FUNC_(f_fpu_fix_end, F_FPU_FIX_END)
- void f_fpu_fix_start(unsigned int *old_cw) {
- fpu_fix_start(old_cw);
- }
- void f_fpu_fix_end(unsigned int *old_cw) {
- fpu_fix_end(old_cw);
- }
- #endif
- }
-
|