Version: SMASH-1.5
fpenvironment.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (c) 2015-2018
4  * SMASH Team
5  *
6  * GNU General Public License (GPLv3 or later)
7  *
8  */
9 
10 #include "smash/fpenvironment.h"
11 
12 #if defined __SSE__
13 #include <xmmintrin.h>
14 #endif
15 
16 #include <csignal>
17 
18 #include "smash/logging.h"
19 
20 namespace smash {
21 
22 #if !defined _GNU_SOURCE && defined __SSE__ && !defined __clang__
23 bool enable_float_traps(int femask) {
24  static_assert(FE_INVALID == 0x01,
25  "incorrect assumption that FE_INVALID == 0x01");
26  static_assert(FE_DIVBYZERO == 0x04,
27  "incorrect assumption that FE_DIVBYZERO == 0x04");
28  static_assert(FE_OVERFLOW == 0x08,
29  "incorrect assumption that FE_OVERFLOW == 0x08");
30  static_assert(FE_UNDERFLOW == 0x10,
31  "incorrect assumption that FE_UNDERFLOW == 0x10");
32  static_assert(FE_INEXACT == 0x20,
33  "incorrect assumption that FE_INEXACT == 0x20");
34 
35  // only accept supported values
36  femask &= FE_ALL_EXCEPT;
37 
38 #if defined __GNUC__ /*for inline asm*/
39  // get the current FPU control word
40  uint16_t fpucw;
41  asm volatile("fstcw %0" : "=m"(fpucw));
42 
43  // clear the bits where the FPU should trap
44  fpucw &= ~femask;
45 
46  // load the FPU control word back
47  asm volatile("fldcw %0" ::"m"(fpucw));
48 #endif
49 
50  // the SSE CSR has the bit positions 7 bit positions further to the left
51  femask <<= 7;
52 
53  /* Get the current CSR, mask of the relevant bits, and load it back into the
54  * SSE CSR.*/
55  _mm_setcsr(_mm_getcsr() & ~femask);
56 
57  // we did something, so return true
58  return true;
59 }
60 #endif
61 
63  if (!enable_float_traps(mask)) {
64  const auto &log = logger<LogArea::Fpe>();
65  log.warn("Failed to setup traps on ", mask);
66  }
67 }
68 
70  {
71  const auto &log = logger<LogArea::Fpe>();
72 
73  // pole error occurred in a floating-point operation:
74  if (!enable_float_traps(FE_DIVBYZERO)) {
75  log.warn("Failed to setup trap on pole error.");
76  }
77 
78  // domain error occurred in an earlier floating-point operation:
79  if (!enable_float_traps(FE_INVALID)) {
80  log.warn("Failed to setup trap on domain error.");
81  }
82 
83  /* The result of the earlier floating-point operation was too large to be
84  * representable: */
85  if (!enable_float_traps(FE_OVERFLOW)) {
86  log.warn("Failed to setup trap on overflow.");
87  }
88 
89  /* There's also FE_UNDERFLOW, where the result of the earlier
90  * floating-point operation was subnormal with a loss of precision.
91  * We do not consider this an error by default.
92  * Furthermore, there's FE_INEXACT, but this traps if "rounding was
93  * necessary to store the result of an earlier floating-point
94  * operation". This is common and not really an error condition. */
95  }
96 
97 // Install the signal handler if we have the functionality.
98 #if (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L) || \
99  (defined _XOPEN_SOURCE && _XOPEN_SOURCE) || \
100  (defined _POSIX_SOURCE && _POSIX_SOURCE)
101 /* The missing-fields-initializers warning says that not all fields of this
102  * struct were explicitly initialized. That's exactly what is the intention
103  * here, because then they are default-initialized, which is zero. */
104 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
105  struct sigaction action = {};
106  action.sa_flags = SA_SIGINFO;
107  action.sa_sigaction = [](int signal, siginfo_t *info, void *) {
108  const auto &log = logger<LogArea::Fpe>();
109  if (signal == SIGFPE) {
110  const char *msg = nullptr;
111  switch (info->si_code) {
112  case FPE_FLTDIV:
113  msg = "Division by Zero (NaN)";
114  break;
115  case FPE_FLTUND:
116  msg = "Underflow (result was subnormal with a loss of precision)";
117  break;
118  case FPE_FLTOVF:
119  msg = "Overflow (result was too large to be representable)";
120  break;
121  case FPE_FLTINV:
122  msg = "Invalid (domain error occurred)";
123  break;
124  case FPE_FLTRES:
125  msg =
126  "Inexact Result (rounding was necessary to store the result of "
127  "an earlier floating-point operation)";
128  break;
129  default:
130  msg = "unknown";
131  break;
132  }
133  log.fatal("Floating point trap was raised: ", msg);
134  } else {
135  log.fatal("Unexpected Signal ", signal,
136  " received in the FPE signal handler. Aborting.");
137  }
138  abort();
139  };
140  sigaction(SIGFPE, &action, nullptr);
141 #endif
142 }
143 
144 } // namespace smash
void setup_default_float_traps()
Setup the floating-point traps used throughout SMASH.
void reenable_traps(int mask)
Reenables the given traps.
bool enable_float_traps(int)
Fallback that fails to set the trap.
Definition: fpenvironment.h:40
Definition: action.h:24