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 get_round() {
75 LIBC_FENV_ACCESS_ON
76 return fegetround();
77}
78
79LIBC_INLINE int set_round(int rounding_mode) {
80 LIBC_FENV_ACCESS_ON
81 return fesetround(rounding_direction: rounding_mode);
82}
83
84} // namespace fputil
85} // namespace LIBC_NAMESPACE_DECL
86
87#else // !LIBC_MATH_USE_SYSTEM_FENV
88
89#if defined(LIBC_TARGET_ARCH_IS_AARCH64) && defined(__ARM_FP)
90#if defined(__APPLE__)
91#include "aarch64/fenv_darwin_impl.h"
92#else
93#include "aarch64/FEnvImpl.h"
94#endif
95
96// The extra !defined(APPLE) condition is to cause x86_64 MacOS builds to use
97// the dummy implementations below. Once a proper x86_64 darwin fenv is set up,
98// the apple condition here should be removed.
99// TODO: fully support fenv for MSVC.
100#elif defined(LIBC_TARGET_ARCH_IS_X86) && !defined(__APPLE__)
101#include "x86_64/FEnvImpl.h"
102#elif defined(LIBC_TARGET_ARCH_IS_ARM) && defined(__ARM_FP) && \
103 !defined(LIBC_COMPILER_IS_MSVC)
104#include "arm/FEnvImpl.h"
105#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) && defined(__riscv_flen)
106#include "riscv/FEnvImpl.h"
107#else
108
109namespace LIBC_NAMESPACE_DECL {
110namespace fputil {
111
112// All dummy functions silently succeed.
113
114LIBC_INLINE int clear_except(int) { return 0; }
115
116LIBC_INLINE int test_except(int) { return 0; }
117
118LIBC_INLINE int get_except() { return 0; }
119
120LIBC_INLINE int set_except(int) { return 0; }
121
122LIBC_INLINE int raise_except(int) { return 0; }
123
124LIBC_INLINE int enable_except(int) { return 0; }
125
126LIBC_INLINE int disable_except(int) { return 0; }
127
128LIBC_INLINE int get_round() { return FE_TONEAREST; }
129
130LIBC_INLINE int set_round(int rounding_mode) {
131 return (rounding_mode == FE_TONEAREST) ? 0 : 1;
132}
133
134LIBC_INLINE int get_env(fenv_t *) { return 0; }
135
136LIBC_INLINE int set_env(const fenv_t *) { return 0; }
137
138} // namespace fputil
139} // namespace LIBC_NAMESPACE_DECL
140#endif
141
142#endif // LIBC_MATH_USE_SYSTEM_FENV
143
144namespace LIBC_NAMESPACE_DECL {
145namespace fputil {
146
147LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
148clear_except_if_required([[maybe_unused]] int excepts) {
149 if (cpp::is_constant_evaluated()) {
150 return 0;
151 } else {
152#ifndef LIBC_MATH_HAS_NO_EXCEPT
153 LIBC_FENV_ACCESS_ON
154 if (math_errhandling & MATH_ERREXCEPT)
155 return clear_except(excepts);
156#endif // LIBC_MATH_HAS_NO_EXCEPT
157 return 0;
158 }
159}
160
161LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
162set_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 set_except(excepts);
170#endif // LIBC_MATH_HAS_NO_EXCEPT
171 return 0;
172 }
173}
174
175LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int
176raise_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 raise_except(excepts);
184#endif // LIBC_MATH_HAS_NO_EXCEPT
185 return 0;
186 }
187}
188
189LIBC_INLINE LIBC_CONSTEXPR_DEFAULT void
190set_errno_if_required([[maybe_unused]] int err) {
191 if (!cpp::is_constant_evaluated()) {
192#ifndef LIBC_MATH_HAS_NO_ERRNO
193 if (math_errhandling & MATH_ERRNO)
194 libc_errno = err;
195#endif // LIBC_MATH_HAS_NO_ERRNO
196 }
197}
198
199} // namespace fputil
200} // namespace LIBC_NAMESPACE_DECL
201
202#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_FENVIMPL_H
203