1//===-- Floating point environment manipulation functions -------*- 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#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_FENVIMPL_H
10#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FENVIMPL_H
11
12#include "hdr/fenv_macros.h"
13#include "hdr/math_macros.h"
14#include "hdr/types/fenv_t.h"
15#include "src/__support/CPP/type_traits.h"
16#include "src/__support/libc_errno.h"
17#include "src/__support/macros/attributes.h" // LIBC_INLINE
18#include "src/__support/macros/config.h"
19#include "src/__support/macros/optimization.h"
20#include "src/__support/macros/properties/architectures.h"
21#include "src/__support/macros/properties/compiler.h"
22#include "src/__support/macros/properties/cpu_features.h"
23
24#ifdef LIBC_COMPILER_HAS_STDC_FENV_ACCESS
25#define LIBC_FENV_ACCESS_ON _Pragma("STDC FENV_ACCESS ON")
26#else
27#define LIBC_FENV_ACCESS_ON
28#endif
29
30// In full build mode we are the system fenv in libc.
31#if defined(LIBC_FULL_BUILD)
32#undef LIBC_MATH_USE_SYSTEM_FENV
33#endif // LIBC_FULL_BUILD
34
35#if defined(LIBC_MATH_USE_SYSTEM_FENV) && !defined(LIBC_MATH_HAS_NO_EXCEPT)
36
37// Simply call the system libc fenv.h functions, only for those that are used in
38// math function implementations.
39// To be used as an option for math function implementation, not to be used to
40// implement fenv.h functions themselves.
41
42#include <fenv.h>
43
44namespace LIBC_NAMESPACE_DECL {
45namespace fputil {
46
47LIBC_INLINE int clear_except(int excepts) {
48 LIBC_FENV_ACCESS_ON
49 return feclearexcept(excepts);
50}
51
52LIBC_INLINE int test_except(int excepts) {
53 LIBC_FENV_ACCESS_ON
54 return fetestexcept(excepts);
55}
56
57LIBC_INLINE int get_except() {
58 LIBC_FENV_ACCESS_ON
59 fexcept_t excepts = 0;
60 fegetexceptflag(&excepts, FE_ALL_EXCEPT);
61 return static_cast<int>(excepts);
62}
63
64LIBC_INLINE int set_except(int excepts) {
65 LIBC_FENV_ACCESS_ON
66 fexcept_t exc = static_cast<fexcept_t>(excepts);
67 return fesetexceptflag(&exc, FE_ALL_EXCEPT);
68}
69
70LIBC_INLINE int raise_except(int excepts) {
71 LIBC_FENV_ACCESS_ON
72 return feraiseexcept(excepts);
73}
74
75LIBC_INLINE int enable_except(int) { return 0; }
76
77LIBC_INLINE int disable_except(int) { return 0; }
78
79LIBC_INLINE int get_round() {
80 LIBC_FENV_ACCESS_ON
81 return fegetround();
82}
83
84LIBC_INLINE int set_round(int rounding_mode) {
85 LIBC_FENV_ACCESS_ON
86 return fesetround(rounding_mode);
87}
88
89LIBC_INLINE int get_env(fenv_t *env) {
90 LIBC_FENV_ACCESS_ON
91 return fegetenv(env);
92}
93
94LIBC_INLINE int set_env(const fenv_t *env) {
95 LIBC_FENV_ACCESS_ON
96 return fesetenv(env);
97}
98
99} // namespace fputil
100} // namespace LIBC_NAMESPACE_DECL
101
102#else // !LIBC_MATH_USE_SYSTEM_FENV
103
104#if defined(LIBC_TARGET_ARCH_IS_AARCH64) && defined(__ARM_FP)
105#if defined(__APPLE__)
106#include "aarch64/fenv_darwin_impl.h"
107#else
108#include "aarch64/FEnvImpl.h"
109#endif
110
111// The extra !defined(APPLE) condition is to cause x86_64 MacOS builds to use
112// the dummy implementations below. Once a proper x86_64 darwin fenv is set up,
113// the apple condition here should be removed.
114// TODO: fully support fenv for MSVC.
115#elif defined(LIBC_TARGET_ARCH_IS_X86) && !defined(__APPLE__)
116#include "x86_64/FEnvImpl.h"
117#elif defined(LIBC_TARGET_ARCH_IS_ARM) && defined(__ARM_FP) && \
118 !defined(LIBC_COMPILER_IS_MSVC)
119#include "arm/FEnvImpl.h"
120#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) && defined(__riscv_flen)
121#include "riscv/FEnvImpl.h"
122#elif defined(LIBC_TARGET_ARCH_IS_HEXAGON)
123#include "hexagon/FEnvImpl.h"
124#else
125
126namespace LIBC_NAMESPACE_DECL {
127namespace fputil {
128
129// All dummy functions silently succeed.
130
131LIBC_INLINE int clear_except(int) { return 0; }
132
133LIBC_INLINE int test_except(int) { return 0; }
134
135LIBC_INLINE int get_except() { return 0; }
136
137LIBC_INLINE int set_except(int) { return 0; }
138
139LIBC_INLINE int raise_except(int) { return 0; }
140
141LIBC_INLINE int enable_except(int) { return 0; }
142
143LIBC_INLINE int disable_except(int) { return 0; }
144
145LIBC_INLINE int get_round() { return FE_TONEAREST; }
146
147LIBC_INLINE int set_round(int rounding_mode) {
148 return (rounding_mode == FE_TONEAREST) ? 0 : 1;
149}
150
151LIBC_INLINE int get_env(fenv_t *) { return 0; }
152
153LIBC_INLINE int set_env(const fenv_t *) { return 0; }
154
155} // namespace fputil
156} // namespace LIBC_NAMESPACE_DECL
157#endif
158
159#endif // LIBC_MATH_USE_SYSTEM_FENV
160
161namespace LIBC_NAMESPACE_DECL {
162namespace fputil {
163
164LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
165clear_except_if_required([[maybe_unused]] int excepts) {
166 if (cpp::is_constant_evaluated()) {
167 return 0;
168 } else {
169#ifndef LIBC_MATH_HAS_NO_EXCEPT
170 if (math_errhandling & MATH_ERREXCEPT)
171 return clear_except(excepts);
172#endif // LIBC_MATH_HAS_NO_EXCEPT
173 return 0;
174 }
175}
176
177LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
178set_except_if_required([[maybe_unused]] int excepts) {
179 if (cpp::is_constant_evaluated()) {
180 return 0;
181 } else {
182#ifndef LIBC_MATH_HAS_NO_EXCEPT
183 if (math_errhandling & MATH_ERREXCEPT)
184 return set_except(excepts);
185#endif // LIBC_MATH_HAS_NO_EXCEPT
186 return 0;
187 }
188}
189
190LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
191raise_except_if_required([[maybe_unused]] int excepts) {
192 if (cpp::is_constant_evaluated()) {
193 return 0;
194 } else {
195#ifndef LIBC_MATH_HAS_NO_EXCEPT
196 if (math_errhandling & MATH_ERREXCEPT)
197 return raise_except(excepts);
198#endif // LIBC_MATH_HAS_NO_EXCEPT
199 return 0;
200 }
201}
202
203LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void
204set_errno_if_required([[maybe_unused]] int err) {
205 if (!cpp::is_constant_evaluated()) {
206#ifndef LIBC_MATH_HAS_NO_ERRNO
207 if (math_errhandling & MATH_ERRNO)
208 libc_errno = err;
209#endif // LIBC_MATH_HAS_NO_ERRNO
210 }
211}
212
213template <typename T>
214LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void raise_overflow_except_if_required() {
215 raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
216}
217
218template <typename T>
219LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void raise_underflow_except_if_required() {
220 raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
221}
222
223#ifndef LIBC_MATH_HAS_NO_EXCEPT
224#if defined(LIBC_TARGET_CPU_HAS_FPU_FLOAT)
225template <>
226LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void
227raise_overflow_except_if_required<float>() {
228 if (cpp::is_constant_evaluated()) {
229 return;
230 } else {
231 volatile float x = 0x1.0p127f;
232 x = x * 2.0f;
233 }
234}
235
236template <>
237LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void
238raise_underflow_except_if_required<float>() {
239 if (cpp::is_constant_evaluated()) {
240 return;
241 } else {
242 volatile float x = 0x1.0p-126f;
243 x = x * 0x1.0p-50f;
244 }
245}
246#endif // LIBC_TARGET_CPU_HAS_FPU_FLOAT
247
248#if defined(LIBC_TARGET_CPU_HAS_FPU_DOUBLE)
249template <>
250LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void
251raise_overflow_except_if_required<double>() {
252 if (cpp::is_constant_evaluated()) {
253 return;
254 } else {
255 volatile double x = 0x1.0p1023;
256 x = x * 2.0;
257 }
258}
259
260template <>
261LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void
262raise_underflow_except_if_required<double>() {
263 if (cpp::is_constant_evaluated()) {
264 return;
265 } else {
266 volatile double x = 0x1.0p-1022;
267 x = x * 0x1.0p-100;
268 }
269}
270#endif // LIBC_TARGET_CPU_HAS_FPU_DOUBLE
271#endif // !LIBC_MATH_HAS_NO_EXCEPT
272
273} // namespace fputil
274} // namespace LIBC_NAMESPACE_DECL
275
276#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_FENVIMPL_H
277