1#include "fp-testing.h"
2#include "llvm/Support/Errno.h"
3#include <cstdio>
4#include <cstdlib>
5#include <cstring>
6#if __x86_64__
7#include <xmmintrin.h>
8#endif
9
10using Fortran::common::RoundingMode;
11using Fortran::evaluate::RealFlag;
12
13ScopedHostFloatingPointEnvironment::ScopedHostFloatingPointEnvironment(
14#if __x86_64__
15 bool treatSubnormalOperandsAsZero, bool flushSubnormalResultsToZero
16#else
17 bool, bool
18#endif
19) {
20 errno = 0;
21 if (feholdexcept(envp: &originalFenv_) != 0) {
22 std::fprintf(stderr, format: "feholdexcept() failed: %s\n",
23 llvm::sys::StrError(errno).c_str());
24 std::abort();
25 }
26 fenv_t currentFenv;
27 if (fegetenv(envp: &currentFenv) != 0) {
28 std::fprintf(
29 stderr, format: "fegetenv() failed: %s\n", llvm::sys::StrError(errno).c_str());
30 std::abort();
31 }
32
33#if __x86_64__
34 originalMxcsr = _mm_getcsr();
35 unsigned int currentMxcsr{originalMxcsr};
36 if (treatSubnormalOperandsAsZero) {
37 currentMxcsr |= 0x0040;
38 } else {
39 currentMxcsr &= ~0x0040;
40 }
41 if (flushSubnormalResultsToZero) {
42 currentMxcsr |= 0x8000;
43 } else {
44 currentMxcsr &= ~0x8000;
45 }
46#else
47 // TODO others
48#endif
49 errno = 0;
50 if (fesetenv(envp: &currentFenv) != 0) {
51 std::fprintf(
52 stderr, format: "fesetenv() failed: %s\n", llvm::sys::StrError(errno).c_str());
53 std::abort();
54 }
55#if __x86_64__
56 _mm_setcsr(i: currentMxcsr);
57#endif
58}
59
60ScopedHostFloatingPointEnvironment::~ScopedHostFloatingPointEnvironment() {
61 errno = 0;
62 if (fesetenv(envp: &originalFenv_) != 0) {
63 std::fprintf(
64 stderr, format: "fesetenv() failed: %s\n", llvm::sys::StrError(errno).c_str());
65 std::abort();
66 }
67#if __x86_64__
68 _mm_setcsr(i: originalMxcsr);
69#endif
70}
71
72void ScopedHostFloatingPointEnvironment::ClearFlags() const {
73 feclearexcept(FE_ALL_EXCEPT);
74}
75
76RealFlags ScopedHostFloatingPointEnvironment::CurrentFlags() {
77 int exceptions = fetestexcept(FE_ALL_EXCEPT);
78 RealFlags flags;
79 if (exceptions & FE_INVALID) {
80 flags.set(RealFlag::InvalidArgument);
81 }
82 if (exceptions & FE_DIVBYZERO) {
83 flags.set(RealFlag::DivideByZero);
84 }
85 if (exceptions & FE_OVERFLOW) {
86 flags.set(RealFlag::Overflow);
87 }
88 if (exceptions & FE_UNDERFLOW) {
89 flags.set(RealFlag::Underflow);
90 }
91 if (exceptions & FE_INEXACT) {
92 flags.set(RealFlag::Inexact);
93 }
94 return flags;
95}
96
97void ScopedHostFloatingPointEnvironment::SetRounding(Rounding rounding) {
98 switch (rounding.mode) {
99 case RoundingMode::TiesToEven:
100 fesetround(FE_TONEAREST);
101 break;
102 case RoundingMode::ToZero:
103 fesetround(FE_TOWARDZERO);
104 break;
105 case RoundingMode::Up:
106 fesetround(FE_UPWARD);
107 break;
108 case RoundingMode::Down:
109 fesetround(FE_DOWNWARD);
110 break;
111 case RoundingMode::TiesAwayFromZero:
112 std::fprintf(stderr, format: "SetRounding: TiesAwayFromZero not available");
113 std::abort();
114 break;
115 }
116}
117

source code of flang/unittests/Evaluate/fp-testing.cpp