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
23#ifdef LIBC_COMPILER_HAS_STDC_FENV_ACCESS
24#define LIBC_FENV_ACCESS_ON _Pragma("STDC FENV_ACCESS ON")
25#else
26#define LIBC_FENV_ACCESS_ON
27#endif
28
29// In full build mode we are the system fenv in libc.
30#if defined(LIBC_FULL_BUILD)
31#undef LIBC_MATH_USE_SYSTEM_FENV
32#endif // LIBC_FULL_BUILD
33
34#if defined(LIBC_MATH_USE_SYSTEM_FENV)
35
36// Simply call the system libc fenv.h functions, only for those that are used in
37// math function implementations.
38// To be used as an option for math function implementation, not to be used to
39// implement fenv.h functions themselves.
40
41#include <fenv.h>
42
43namespace LIBC_NAMESPACE_DECL {
44namespace fputil {
45
46LIBC_INLINE int clear_except(int excepts) {
47 LIBC_FENV_ACCESS_ON
48 return feclearexcept(excepts: excepts);
49}
50
51LIBC_INLINE int test_except(int excepts) {
52 LIBC_FENV_ACCESS_ON
53 return fetestexcept(excepts: excepts);
54}
55
56LIBC_INLINE int get_except() {
57 LIBC_FENV_ACCESS_ON
58 fexcept_t excepts = 0;
59 fegetexceptflag(flagp: &excepts, FE_ALL_EXCEPT);
60 return static_cast<int>(excepts);
61}
62
63LIBC_INLINE int set_except(int excepts) {
64 LIBC_FENV_ACCESS_ON
65 fexcept_t exc = static_cast<fexcept_t>(excepts);
66 return fesetexceptflag(flagp: &exc, FE_ALL_EXCEPT);
67}
68
69LIBC_INLINE int raise_except(int excepts) {
70 LIBC_FENV_ACCESS_ON
71 return feraiseexcept(excepts: excepts);
72}
73
74LIBC_INLINE int enable_except(int) { return 0; }
75
76LIBC_INLINE int disable_except(int) { return 0; }
77
78LIBC_INLINE int get_round() {
79 LIBC_FENV_ACCESS_ON
80 return fegetround();
81}
82
83LIBC_INLINE int set_round(int rounding_mode) {
84 LIBC_FENV_ACCESS_ON
85 return fesetround(rounding_direction: rounding_mode);
86}
87
88LIBC_INLINE int get_env(fenv_t *env) {
89 LIBC_FENV_ACCESS_ON
90 return fegetenv(envp: env);
91}
92
93LIBC_INLINE int set_env(const fenv_t *env) {
94 LIBC_FENV_ACCESS_ON
95 return fesetenv(envp: env);
96}
97
98} // namespace fputil
99} // namespace LIBC_NAMESPACE_DECL
100
101#else // !LIBC_MATH_USE_SYSTEM_FENV
102
103#if defined(LIBC_TARGET_ARCH_IS_AARCH64) && defined(__ARM_FP)
104#if defined(__APPLE__)
105#include "aarch64/fenv_darwin_impl.h"
106#else
107#include "aarch64/FEnvImpl.h"
108#endif
109
110// The extra !defined(APPLE) condition is to cause x86_64 MacOS builds to use
111// the dummy implementations below. Once a proper x86_64 darwin fenv is set up,
112// the apple condition here should be removed.
113// TODO: fully support fenv for MSVC.
114#elif defined(LIBC_TARGET_ARCH_IS_X86) && !defined(__APPLE__)
115#include "x86_64/FEnvImpl.h"
116#elif defined(LIBC_TARGET_ARCH_IS_ARM) && defined(__ARM_FP) && \
117 !defined(LIBC_COMPILER_IS_MSVC)
118#include "arm/FEnvImpl.h"
119#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) && defined(__riscv_flen)
120#include "riscv/FEnvImpl.h"
121#else
122
123namespace LIBC_NAMESPACE_DECL {
124namespace fputil {
125
126// All dummy functions silently succeed.
127
128LIBC_INLINE int clear_except(int) { return 0; }
129
130LIBC_INLINE int test_except(int) { return 0; }
131
132LIBC_INLINE int get_except() { return 0; }
133
134LIBC_INLINE int set_except(int) { return 0; }
135
136LIBC_INLINE int raise_except(int) { return 0; }
137
138LIBC_INLINE int enable_except(int) { return 0; }
139
140LIBC_INLINE int disable_except(int) { return 0; }
141
142LIBC_INLINE int get_round() { return FE_TONEAREST; }
143
144LIBC_INLINE int set_round(int rounding_mode) {
145 return (rounding_mode == FE_TONEAREST) ? 0 : 1;
146}
147
148LIBC_INLINE int get_env(fenv_t *) { return 0; }
149
150LIBC_INLINE int set_env(const fenv_t *) { return 0; }
151
152} // namespace fputil
153} // namespace LIBC_NAMESPACE_DECL
154#endif
155
156#endif // LIBC_MATH_USE_SYSTEM_FENV
157
158namespace LIBC_NAMESPACE_DECL {
159namespace fputil {
160
161LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
162clear_except_if_required([[maybe_unused]] int excepts) {
163 if (cpp::is_constant_evaluated()) {
164 return 0;
165 } else {
166#ifndef LIBC_MATH_HAS_NO_EXCEPT
167 LIBC_FENV_ACCESS_ON
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 LIBC_FENV_ACCESS_ON
182 if (math_errhandling & MATH_ERREXCEPT)
183 return set_except(excepts);
184#endif // LIBC_MATH_HAS_NO_EXCEPT
185 return 0;
186 }
187}
188
189LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
190raise_except_if_required([[maybe_unused]] int excepts) {
191 if (cpp::is_constant_evaluated()) {
192 return 0;
193 } else {
194#ifndef LIBC_MATH_HAS_NO_EXCEPT
195 LIBC_FENV_ACCESS_ON
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
213} // namespace fputil
214} // namespace LIBC_NAMESPACE_DECL
215
216#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_FENVIMPL_H
217