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#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 if (math_errhandling & MATH_ERREXCEPT)
169 return clear_except(excepts);
170#endif // LIBC_MATH_HAS_NO_EXCEPT
171 return 0;
172 }
173}
174
175LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
176set_except_if_required([[maybe_unused]] int excepts) {
177 if (cpp::is_constant_evaluated()) {
178 return 0;
179 } else {
180#ifndef LIBC_MATH_HAS_NO_EXCEPT
181 if (math_errhandling & MATH_ERREXCEPT)
182 return set_except(excepts);
183#endif // LIBC_MATH_HAS_NO_EXCEPT
184 return 0;
185 }
186}
187
188LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
189raise_except_if_required([[maybe_unused]] int excepts) {
190 if (cpp::is_constant_evaluated()) {
191 return 0;
192 } else {
193#ifndef LIBC_MATH_HAS_NO_EXCEPT
194 if (math_errhandling & MATH_ERREXCEPT)
195 return raise_except(excepts);
196#endif // LIBC_MATH_HAS_NO_EXCEPT
197 return 0;
198 }
199}
200
201LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void
202set_errno_if_required([[maybe_unused]] int err) {
203 if (!cpp::is_constant_evaluated()) {
204#ifndef LIBC_MATH_HAS_NO_ERRNO
205 if (math_errhandling & MATH_ERRNO)
206 libc_errno = err;
207#endif // LIBC_MATH_HAS_NO_ERRNO
208 }
209}
210
211template <typename T>
212LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void raise_overflow_except_if_required() {
213 raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
214}
215
216template <typename T>
217LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void raise_underflow_except_if_required() {
218 raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
219}
220
221#if defined(LIBC_TARGET_CPU_HAS_FPU_FLOAT)
222template <>
223LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void
224raise_overflow_except_if_required<float>() {
225 if (cpp::is_constant_evaluated()) {
226 return;
227 } else {
228 volatile float x = 0x1.0p127f;
229 x = x * 2.0f;
230 }
231}
232
233template <>
234LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void
235raise_underflow_except_if_required<float>() {
236 if (cpp::is_constant_evaluated()) {
237 return;
238 } else {
239 volatile float x = 0x1.0p-126f;
240 x = x * 0x1.0p-50f;
241 }
242}
243#endif // LIBC_TARGET_CPU_HAS_FPU_FLOAT
244
245#if defined(LIBC_TARGET_CPU_HAS_FPU_DOUBLE)
246template <>
247LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void
248raise_overflow_except_if_required<double>() {
249 if (cpp::is_constant_evaluated()) {
250 return;
251 } else {
252 volatile double x = 0x1.0p1023;
253 x = x * 2.0;
254 }
255}
256
257template <>
258LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void
259raise_underflow_except_if_required<double>() {
260 if (cpp::is_constant_evaluated()) {
261 return;
262 } else {
263 volatile double x = 0x1.0p-1022;
264 x = x * 0x1.0p-100;
265 }
266}
267#endif // LIBC_TARGET_CPU_HAS_FPU_DOUBLE
268
269} // namespace fputil
270} // namespace LIBC_NAMESPACE_DECL
271
272#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_FENVIMPL_H
273