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

source code of flang/lib/Testing/fp-testing.cpp