fenv.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /* Copyright (C) 2013-2022 Free Software Foundation, Inc.
  2. This file is part of the GNU Atomic Library (libatomic).
  3. Libatomic is free software; you can redistribute it and/or modify it
  4. under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. Libatomic is distributed in the hope that it will be useful, but WITHOUT ANY
  8. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9. FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  10. more details.
  11. Under Section 7 of GPL version 3, you are granted additional
  12. permissions described in the GCC Runtime Library Exception, version
  13. 3.1, as published by the Free Software Foundation.
  14. You should have received a copy of the GNU General Public License and
  15. a copy of the GCC Runtime Library Exception along with this program;
  16. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  17. <http://www.gnu.org/licenses/>. */
  18. #include "libatomic_i.h"
  19. #define FE_INVALID 0x01
  20. #define FE_DENORM 0x02
  21. #define FE_DIVBYZERO 0x04
  22. #define FE_OVERFLOW 0x08
  23. #define FE_UNDERFLOW 0x10
  24. #define FE_INEXACT 0x20
  25. struct fenv
  26. {
  27. unsigned short int __control_word;
  28. unsigned short int __unused1;
  29. unsigned short int __status_word;
  30. unsigned short int __unused2;
  31. unsigned short int __tags;
  32. unsigned short int __unused3;
  33. unsigned int __eip;
  34. unsigned short int __cs_selector;
  35. unsigned int __opcode:11;
  36. unsigned int __unused4:5;
  37. unsigned int __data_offset;
  38. unsigned short int __data_selector;
  39. unsigned short int __unused5;
  40. } __attribute__ ((gcc_struct));
  41. #ifdef __SSE_MATH__
  42. # define __math_force_eval_div(x, y) \
  43. do { asm ("" : "+x" (x)); asm volatile ("" : : "x" (x / y)); } while (0)
  44. #else
  45. # define __math_force_eval_div(x, y) \
  46. do { asm ("" : "+t" (x)); asm volatile ("" : : "f" (x / y)); } while (0)
  47. #endif
  48. /* Raise the supported floating-point exceptions from EXCEPTS. Other
  49. bits in EXCEPTS are ignored. */
  50. void
  51. __atomic_feraiseexcept (int excepts)
  52. {
  53. struct fenv temp;
  54. if (excepts & FE_INVALID)
  55. {
  56. float f = 0.0f;
  57. __math_force_eval_div (f, f);
  58. }
  59. if (excepts & FE_DENORM)
  60. {
  61. asm volatile ("fnstenv\t%0" : "=m" (temp));
  62. temp.__status_word |= FE_DENORM;
  63. asm volatile ("fldenv\t%0" : : "m" (temp));
  64. asm volatile ("fwait");
  65. }
  66. if (excepts & FE_DIVBYZERO)
  67. {
  68. float f = 1.0f, g = 0.0f;
  69. __math_force_eval_div (f, g);
  70. }
  71. if (excepts & FE_OVERFLOW)
  72. {
  73. asm volatile ("fnstenv\t%0" : "=m" (temp));
  74. temp.__status_word |= FE_OVERFLOW;
  75. asm volatile ("fldenv\t%0" : : "m" (temp));
  76. asm volatile ("fwait");
  77. }
  78. if (excepts & FE_UNDERFLOW)
  79. {
  80. asm volatile ("fnstenv\t%0" : "=m" (temp));
  81. temp.__status_word |= FE_UNDERFLOW;
  82. asm volatile ("fldenv\t%0" : : "m" (temp));
  83. asm volatile ("fwait");
  84. }
  85. if (excepts & FE_INEXACT)
  86. {
  87. float f = 1.0f, g = 3.0f;
  88. __math_force_eval_div (f, g);
  89. }
  90. }