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)
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: excepts);
50}
51
52LIBC_INLINE int test_except(int excepts) {
53 LIBC_FENV_ACCESS_ON
54 return fetestexcept(excepts: excepts);
55}
56
57LIBC_INLINE int get_except() {
58 LIBC_FENV_ACCESS_ON
59 fexcept_t excepts = 0;
60 fegetexceptflag(flagp: &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(flagp: &exc, FE_ALL_EXCEPT);
68}
69
70LIBC_INLINE int raise_except(int excepts) {
71 LIBC_FENV_ACCESS_ON
72 return feraiseexcept(excepts: 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_direction: rounding_mode);
87}
88
89LIBC_INLINE int get_env(fenv_t *env) {
90 LIBC_FENV_ACCESS_ON
91 return fegetenv(envp: env);
92}
93
94LIBC_INLINE int set_env(const fenv_t *env) {
95 LIBC_FENV_ACCESS_ON
96 return fesetenv(envp: 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#else
123
124namespace LIBC_NAMESPACE_DECL {
125namespace fputil {
126
127// All dummy functions silently succeed.
128
129LIBC_INLINE int clear_except(int) { return 0; }
130
131LIBC_INLINE int test_except(int) { return 0; }
132
133LIBC_INLINE int get_except() { return 0; }
134
135LIBC_INLINE int set_except(int) { return 0; }
136
137LIBC_INLINE int raise_except(int) { return 0; }
138
139LIBC_INLINE int enable_except(int) { return 0; }
140
141LIBC_INLINE int disable_except(int) { return 0; }
142
143LIBC_INLINE int get_round() { return FE_TONEAREST; }
144
145LIBC_INLINE int set_round(int rounding_mode) {
146 return (rounding_mode == FE_TONEAREST) ? 0 : 1;
147}
148
149LIBC_INLINE int get_env(fenv_t *) { return 0; }
150
151LIBC_INLINE int set_env(const fenv_t *) { return 0; }
152
153} // namespace fputil
154} // namespace LIBC_NAMESPACE_DECL
155#endif
156
157#endif // LIBC_MATH_USE_SYSTEM_FENV
158
159namespace LIBC_NAMESPACE_DECL {
160namespace fputil {
161
162LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
163clear_except_if_required([[maybe_unused]] int excepts) {
164 if (cpp::is_constant_evaluated()) {
165 return 0;
166 } else {
167#ifndef LIBC_MATH_HAS_NO_EXCEPT
168 LIBC_FENV_ACCESS_ON
169 if (math_errhandling & MATH_ERREXCEPT)
170 return clear_except(excepts);
171#endif // LIBC_MATH_HAS_NO_EXCEPT
172 return 0;
173 }
174}
175
176LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
177set_except_if_required([[maybe_unused]] int excepts) {
178 if (cpp::is_constant_evaluated()) {
179 return 0;
180 } else {
181#ifndef LIBC_MATH_HAS_NO_EXCEPT
182 LIBC_FENV_ACCESS_ON
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 LIBC_FENV_ACCESS_ON
197 if (math_errhandling & MATH_ERREXCEPT)
198 return raise_except(excepts);
199#endif // LIBC_MATH_HAS_NO_EXCEPT
200 return 0;
201 }
202}
203
204LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void
205set_errno_if_required([[maybe_unused]] int err) {
206 if (!cpp::is_constant_evaluated()) {
207#ifndef LIBC_MATH_HAS_NO_ERRNO
208 if (math_errhandling & MATH_ERRNO)
209 libc_errno = err;
210#endif // LIBC_MATH_HAS_NO_ERRNO
211 }
212}
213
214template <typename T>
215LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void raise_overflow_except_if_required() {
216 raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
217}
218
219template <typename T>
220LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void raise_underflow_except_if_required() {
221 raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
222}
223
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
272} // namespace fputil
273} // namespace LIBC_NAMESPACE_DECL
274
275#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_FENVIMPL_H
276