fpu.cpp 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * src/fpu.cc
  3. *
  4. * This work was supported by the Director, Office of Science, Division
  5. * of Mathematical, Information, and Computational Sciences of the
  6. * U.S. Department of Energy under contract number DE-AC03-76SF00098.
  7. *
  8. * Copyright (c) 2000-2001
  9. *
  10. * Contains functions to set and restore the round-to-double flag in the
  11. * control word of a x86 FPU.
  12. */
  13. #include "config.h"
  14. #include <qd/fpu.h>
  15. #ifdef X86
  16. #ifdef _WIN32
  17. #include <float.h>
  18. #else
  19. #ifdef HAVE_FPU_CONTROL_H
  20. #include <fpu_control.h>
  21. #endif
  22. #ifndef _FPU_GETCW
  23. #define _FPU_GETCW(x) asm volatile ("fnstcw %0":"=m" (x));
  24. #endif
  25. #ifndef _FPU_SETCW
  26. #define _FPU_SETCW(x) asm volatile ("fldcw %0": :"m" (x));
  27. #endif
  28. #ifndef _FPU_EXTENDED
  29. #define _FPU_EXTENDED 0x0300
  30. #endif
  31. #ifndef _FPU_DOUBLE
  32. #define _FPU_DOUBLE 0x0200
  33. #endif
  34. #endif
  35. #endif /* X86 */
  36. extern "C" {
  37. void fpu_fix_start(unsigned int *old_cw) {
  38. #ifdef X86
  39. #ifdef _WIN32
  40. #ifdef __BORLANDC__
  41. /* Win 32 Borland C */
  42. unsigned short cw = _control87(0, 0);
  43. _control87(0x0200, 0x0300);
  44. if (old_cw) {
  45. *old_cw = cw;
  46. }
  47. #else
  48. /* Win 32 MSVC */
  49. unsigned int cw = _control87(0, 0);
  50. _control87(0x00010000, 0x00030000);
  51. if (old_cw) {
  52. *old_cw = cw;
  53. }
  54. #endif
  55. #else
  56. /* Linux */
  57. volatile unsigned short cw, new_cw;
  58. _FPU_GETCW(cw);
  59. new_cw = (cw & ~_FPU_EXTENDED) | _FPU_DOUBLE;
  60. _FPU_SETCW(new_cw);
  61. if (old_cw) {
  62. *old_cw = cw;
  63. }
  64. #endif
  65. #endif
  66. }
  67. void fpu_fix_end(unsigned int *old_cw) {
  68. #ifdef X86
  69. #ifdef _WIN32
  70. #ifdef __BORLANDC__
  71. /* Win 32 Borland C */
  72. if (old_cw) {
  73. unsigned short cw = (unsigned short) *old_cw;
  74. _control87(cw, 0xFFFF);
  75. }
  76. #else
  77. /* Win 32 MSVC */
  78. if (old_cw) {
  79. _control87(*old_cw, 0xFFFFFFFF);
  80. }
  81. #endif
  82. #else
  83. /* Linux */
  84. if (old_cw) {
  85. int cw;
  86. cw = *old_cw;
  87. _FPU_SETCW(cw);
  88. }
  89. #endif
  90. #endif
  91. }
  92. #ifdef HAVE_FORTRAN
  93. #define f_fpu_fix_start FC_FUNC_(f_fpu_fix_start, F_FPU_FIX_START)
  94. #define f_fpu_fix_end FC_FUNC_(f_fpu_fix_end, F_FPU_FIX_END)
  95. void f_fpu_fix_start(unsigned int *old_cw) {
  96. fpu_fix_start(old_cw);
  97. }
  98. void f_fpu_fix_end(unsigned int *old_cw) {
  99. fpu_fix_end(old_cw);
  100. }
  101. #endif
  102. }