test-fenv-x87.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /* Test x86-specific floating-point environment (bug 16068): x87 part.
  2. Copyright (C) 2015-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <fenv.h>
  16. #include <float.h>
  17. #include <fpu_control.h>
  18. #include <stdint.h>
  19. #include <stdio.h>
  20. static uint16_t
  21. get_x87_cw (void)
  22. {
  23. fpu_control_t cw;
  24. _FPU_GETCW (cw);
  25. return cw;
  26. }
  27. static void
  28. set_x87_cw (uint16_t val)
  29. {
  30. fpu_control_t cw = val;
  31. _FPU_SETCW (cw);
  32. }
  33. static void
  34. set_x87_cw_bits (uint16_t mask, uint16_t bits)
  35. {
  36. uint16_t cw = get_x87_cw ();
  37. cw = (cw & ~mask) | bits;
  38. set_x87_cw (cw);
  39. }
  40. static int
  41. test_x87_cw_bits (const char *test, uint16_t mask, uint16_t bits)
  42. {
  43. uint16_t cw = get_x87_cw ();
  44. printf ("Testing %s: cw = %x\n", test, cw);
  45. if ((cw & mask) == bits)
  46. {
  47. printf ("PASS: %s\n", test);
  48. return 0;
  49. }
  50. else
  51. {
  52. printf ("FAIL: %s\n", test);
  53. return 1;
  54. }
  55. }
  56. static uint16_t
  57. get_x87_sw (void)
  58. {
  59. uint16_t temp;
  60. __asm__ __volatile__ ("fnstsw %0" : "=a" (temp));
  61. return temp;
  62. }
  63. static void
  64. set_x87_sw_bits (uint16_t mask, uint16_t bits)
  65. {
  66. fenv_t temp;
  67. __asm__ __volatile__ ("fnstenv %0" : "=m" (temp));
  68. temp.__status_word = (temp.__status_word & ~mask) | bits;
  69. __asm__ __volatile__ ("fldenv %0" : : "m" (temp));
  70. }
  71. static int
  72. test_x87_sw_bits (const char *test, uint16_t mask, uint16_t bits)
  73. {
  74. uint16_t sw = get_x87_sw ();
  75. printf ("Testing %s: sw = %x\n", test, sw);
  76. if ((sw & mask) == bits)
  77. {
  78. printf ("PASS: %s\n", test);
  79. return 0;
  80. }
  81. else
  82. {
  83. printf ("FAIL: %s\n", test);
  84. return 1;
  85. }
  86. }
  87. #define X87_CW_PREC_MASK _FPU_EXTENDED
  88. static int
  89. do_test (void)
  90. {
  91. int result = 0;
  92. fenv_t env1, env2;
  93. /* Test precision mask. */
  94. fegetenv (&env1);
  95. set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_SINGLE);
  96. fegetenv (&env2);
  97. fesetenv (&env1);
  98. result |= test_x87_cw_bits ("fesetenv precision restoration",
  99. X87_CW_PREC_MASK, _FPU_EXTENDED);
  100. set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_EXTENDED);
  101. fesetenv (&env2);
  102. result |= test_x87_cw_bits ("fesetenv precision restoration 2",
  103. X87_CW_PREC_MASK, _FPU_SINGLE);
  104. set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_DOUBLE);
  105. fesetenv (FE_NOMASK_ENV);
  106. result |= test_x87_cw_bits ("fesetenv (FE_NOMASK_ENV) precision restoration",
  107. X87_CW_PREC_MASK, _FPU_EXTENDED);
  108. set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_SINGLE);
  109. fesetenv (FE_DFL_ENV);
  110. result |= test_x87_cw_bits ("fesetenv (FE_DFL_ENV) precision restoration",
  111. X87_CW_PREC_MASK, _FPU_EXTENDED);
  112. /* Test x87 denormal operand masking. */
  113. set_x87_cw_bits (_FPU_MASK_DM, 0);
  114. fegetenv (&env2);
  115. fesetenv (&env1);
  116. result |= test_x87_cw_bits ("fesetenv denormal mask restoration",
  117. _FPU_MASK_DM, _FPU_MASK_DM);
  118. set_x87_cw_bits (_FPU_MASK_DM, _FPU_MASK_DM);
  119. fesetenv (&env2);
  120. result |= test_x87_cw_bits ("fesetenv denormal mask restoration 2",
  121. _FPU_MASK_DM, 0);
  122. set_x87_cw_bits (_FPU_MASK_DM, 0);
  123. /* Presume FE_NOMASK_ENV should leave the "denormal operand"
  124. exception masked, as not a standard exception. */
  125. fesetenv (FE_NOMASK_ENV);
  126. result |= test_x87_cw_bits ("fesetenv (FE_NOMASK_ENV) denormal mask "
  127. "restoration",
  128. _FPU_MASK_DM, _FPU_MASK_DM);
  129. set_x87_cw_bits (_FPU_MASK_DM, 0);
  130. fesetenv (FE_DFL_ENV);
  131. result |= test_x87_cw_bits ("fesetenv (FE_DFL_ENV) denormal mask "
  132. "restoration",
  133. _FPU_MASK_DM, _FPU_MASK_DM);
  134. /* Test x87 denormal operand exception. */
  135. set_x87_sw_bits (__FE_DENORM, __FE_DENORM);
  136. fegetenv (&env2);
  137. fesetenv (&env1);
  138. result |= test_x87_sw_bits ("fesetenv denormal exception restoration",
  139. __FE_DENORM, 0);
  140. set_x87_sw_bits (__FE_DENORM, 0);
  141. fesetenv (&env2);
  142. result |= test_x87_sw_bits ("fesetenv denormal exception restoration 2",
  143. __FE_DENORM, __FE_DENORM);
  144. set_x87_sw_bits (__FE_DENORM, __FE_DENORM);
  145. fesetenv (FE_NOMASK_ENV);
  146. result |= test_x87_sw_bits ("fesetenv (FE_NOMASK_ENV) exception restoration",
  147. __FE_DENORM, 0);
  148. set_x87_sw_bits (__FE_DENORM, __FE_DENORM);
  149. fesetenv (FE_DFL_ENV);
  150. result |= test_x87_sw_bits ("fesetenv (FE_DFL_ENV) exception restoration",
  151. __FE_DENORM, 0);
  152. return result;
  153. }
  154. #define TEST_FUNCTION do_test ()
  155. #include <test-skeleton.c>