1 //===-- arm floating point env manipulation functions -----------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_ARM_FENVIMPL_H
10 #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_ARM_FENVIMPL_H
12 #include "hdr/fenv_macros.h"
13 #include "hdr/types/fenv_t.h"
14 #include "src/__support/FPUtil/FPBits.h"
15 #include "src/__support/macros/attributes.h" // For LIBC_INLINE
16 #include "src/__support/macros/config.h"
19 namespace LIBC_NAMESPACE_DECL
{
23 // Arm floating point state is all stored in a single 32-bit register named
26 static constexpr uint32_t RoundingControlBitPosition
= 22;
27 static constexpr uint32_t ExceptionControlBitPosition
= 8;
29 static constexpr uint32_t TONEAREST
= 0x0;
30 static constexpr uint32_t UPWARD
= 0x1;
31 static constexpr uint32_t DOWNWARD
= 0x2;
32 static constexpr uint32_t TOWARDZERO
= 0x3;
34 static constexpr uint32_t INVALID_ENABLE
= 0x1;
35 static constexpr uint32_t DIVBYZERO_ENABLE
= 0x2;
36 static constexpr uint32_t OVERFLOW_ENABLE
= 0x4;
37 static constexpr uint32_t UNDERFLOW_ENABLE
= 0x8;
38 static constexpr uint32_t INEXACT_ENABLE
= 0x10;
39 static constexpr uint32_t DENORMAL_ENABLE
= 0x20;
41 static constexpr uint32_t INVALID_STATUS
= 0x1;
42 static constexpr uint32_t DIVBYZERO_STATUS
= 0x2;
43 static constexpr uint32_t OVERFLOW_STATUS
= 0x4;
44 static constexpr uint32_t UNDERFLOW_STATUS
= 0x8;
45 static constexpr uint32_t INEXACT_STATUS
= 0x10;
46 static constexpr uint32_t DENORMAL_STATUS
= 0x80;
48 LIBC_INLINE
static uint32_t get_fpscr() { return __builtin_arm_get_fpscr(); }
49 LIBC_INLINE
static void set_fpscr(uint32_t val
) {
50 __builtin_arm_set_fpscr(val
);
53 LIBC_INLINE
static int exception_enable_bits_to_macro(uint32_t status
) {
54 return ((status
& INVALID_ENABLE
) ? FE_INVALID
: 0) |
55 ((status
& DIVBYZERO_ENABLE
) ? FE_DIVBYZERO
: 0) |
56 ((status
& OVERFLOW_ENABLE
) ? FE_OVERFLOW
: 0) |
57 ((status
& UNDERFLOW_ENABLE
) ? FE_UNDERFLOW
: 0) |
58 ((status
& INEXACT_ENABLE
) ? FE_INEXACT
: 0);
61 LIBC_INLINE
static uint32_t exception_macro_to_enable_bits(int except
) {
62 return ((except
& FE_INVALID
) ? INVALID_ENABLE
: 0) |
63 ((except
& FE_DIVBYZERO
) ? DIVBYZERO_ENABLE
: 0) |
64 ((except
& FE_OVERFLOW
) ? OVERFLOW_ENABLE
: 0) |
65 ((except
& FE_UNDERFLOW
) ? UNDERFLOW_ENABLE
: 0) |
66 ((except
& FE_INEXACT
) ? INEXACT_ENABLE
: 0);
69 LIBC_INLINE
static uint32_t exception_macro_to_status_bits(int except
) {
70 return ((except
& FE_INVALID
) ? INVALID_STATUS
: 0) |
71 ((except
& FE_DIVBYZERO
) ? DIVBYZERO_STATUS
: 0) |
72 ((except
& FE_OVERFLOW
) ? OVERFLOW_STATUS
: 0) |
73 ((except
& FE_UNDERFLOW
) ? UNDERFLOW_STATUS
: 0) |
74 ((except
& FE_INEXACT
) ? INEXACT_STATUS
: 0);
77 LIBC_INLINE
static uint32_t exception_status_bits_to_macro(int status
) {
78 return ((status
& INVALID_STATUS
) ? FE_INVALID
: 0) |
79 ((status
& DIVBYZERO_STATUS
) ? FE_DIVBYZERO
: 0) |
80 ((status
& OVERFLOW_STATUS
) ? FE_OVERFLOW
: 0) |
81 ((status
& UNDERFLOW_STATUS
) ? FE_UNDERFLOW
: 0) |
82 ((status
& INEXACT_STATUS
) ? FE_INEXACT
: 0);
86 // Enables exceptions in |excepts| and returns the previously set exceptions.
87 LIBC_INLINE
int enable_except(int excepts
) {
88 uint32_t new_excepts
= FEnv::exception_macro_to_enable_bits(excepts
);
89 uint32_t fpscr
= FEnv::get_fpscr();
90 int old
= (fpscr
>> FEnv::ExceptionControlBitPosition
) & 0x3F;
91 fpscr
|= (new_excepts
<< FEnv::ExceptionControlBitPosition
);
92 FEnv::set_fpscr(fpscr
);
93 return FEnv::exception_enable_bits_to_macro(old
);
96 // Disables exceptions in |excepts| and returns the previously set exceptions.
97 LIBC_INLINE
int disable_except(int excepts
) {
98 uint32_t disable_bits
= FEnv::exception_macro_to_enable_bits(excepts
);
99 uint32_t fpscr
= FEnv::get_fpscr();
100 int old
= (fpscr
>> FEnv::ExceptionControlBitPosition
) & 0x3F;
101 fpscr
&= ~(disable_bits
<< FEnv::ExceptionControlBitPosition
);
102 FEnv::set_fpscr(fpscr
);
103 return FEnv::exception_enable_bits_to_macro(old
);
106 // Returns the currently enabled exceptions.
107 LIBC_INLINE
int get_except() {
108 uint32_t fpscr
= FEnv::get_fpscr();
109 int enabled_excepts
= (fpscr
>> FEnv::ExceptionControlBitPosition
) & 0x3F;
110 return FEnv::exception_enable_bits_to_macro(enabled_excepts
);
113 // Clears the exceptions in |excepts|.
114 LIBC_INLINE
int clear_except(int excepts
) {
115 uint32_t fpscr
= FEnv::get_fpscr();
116 uint32_t to_clear
= FEnv::exception_macro_to_status_bits(excepts
);
118 FEnv::set_fpscr(fpscr
);
122 // Returns the set of exceptions which are from the input set |excepts|.
123 LIBC_INLINE
int test_except(int excepts
) {
124 uint32_t to_test
= FEnv::exception_macro_to_status_bits(excepts
);
125 uint32_t fpscr
= FEnv::get_fpscr();
126 return FEnv::exception_status_bits_to_macro(fpscr
& 0x9F & to_test
);
129 // Set the exceptions in |excepts|.
130 LIBC_INLINE
int set_except(int excepts
) {
131 uint32_t fpscr
= FEnv::get_fpscr();
132 FEnv::set_fpscr(fpscr
| FEnv::exception_macro_to_status_bits(excepts
));
136 LIBC_INLINE
int raise_except(int excepts
) {
139 float large_value
= FPBits
<float>::max_normal().get_val();
140 float small_value
= FPBits
<float>::min_normal().get_val();
141 auto divfunc
= [](float a
, float b
) {
142 __asm__
__volatile__("flds s0, %0\n\t"
144 "fdivs s0, s0, s1\n\t"
147 : "s0", "s1" /* s0 and s1 are clobbered */);
150 uint32_t to_raise
= FEnv::exception_macro_to_status_bits(excepts
);
153 if (to_raise
& FEnv::INVALID_STATUS
) {
155 uint32_t fpscr
= FEnv::get_fpscr();
156 if (!(fpscr
& FEnv::INVALID_STATUS
))
159 if (to_raise
& FEnv::DIVBYZERO_STATUS
) {
161 uint32_t fpscr
= FEnv::get_fpscr();
162 if (!(fpscr
& FEnv::DIVBYZERO_STATUS
))
165 if (to_raise
& FEnv::OVERFLOW_STATUS
) {
166 divfunc(large_value
, small_value
);
167 uint32_t fpscr
= FEnv::get_fpscr();
168 if (!(fpscr
& FEnv::OVERFLOW_STATUS
))
171 if (to_raise
& FEnv::UNDERFLOW_STATUS
) {
172 divfunc(small_value
, large_value
);
173 uint32_t fpscr
= FEnv::get_fpscr();
174 if (!(fpscr
& FEnv::UNDERFLOW_STATUS
))
177 if (to_raise
& FEnv::INEXACT_STATUS
) {
180 // 2.0 / 3.0 cannot be represented exactly in any radix 2 floating point
183 uint32_t fpscr
= FEnv::get_fpscr();
184 if (!(fpscr
& FEnv::INEXACT_STATUS
))
190 LIBC_INLINE
int get_round() {
191 uint32_t mode
= (FEnv::get_fpscr() >> FEnv::RoundingControlBitPosition
) & 0x3;
193 case FEnv::TONEAREST
:
199 case FEnv::TOWARDZERO
:
200 return FE_TOWARDZERO
;
202 return -1; // Error value.
207 LIBC_INLINE
int set_round(int mode
) {
211 bits
= FEnv::TONEAREST
;
214 bits
= FEnv::DOWNWARD
;
220 bits
= FEnv::TOWARDZERO
;
223 return 1; // To indicate failure
226 uint32_t fpscr
= FEnv::get_fpscr();
227 fpscr
&= ~(0x3 << FEnv::RoundingControlBitPosition
);
228 fpscr
|= (bits
<< FEnv::RoundingControlBitPosition
);
229 FEnv::set_fpscr(fpscr
);
234 LIBC_INLINE
int get_env(fenv_t
*envp
) {
235 FEnv
*state
= reinterpret_cast<FEnv
*>(envp
);
236 state
->fpscr
= FEnv::get_fpscr();
240 LIBC_INLINE
int set_env(const fenv_t
*envp
) {
241 if (envp
== FE_DFL_ENV
) {
242 uint32_t fpscr
= FEnv::get_fpscr();
243 // Default status implies:
244 // 1. Round to nearest rounding mode.
245 fpscr
&= ~(0x3 << FEnv::RoundingControlBitPosition
);
246 fpscr
|= (FEnv::TONEAREST
<< FEnv::RoundingControlBitPosition
);
247 // 2. All exceptions are disabled.
248 fpscr
&= ~(0x3F << FEnv::ExceptionControlBitPosition
);
249 // 3. All exceptions are cleared. There are two reserved bits
250 // at bit 5 and 6 so we just write one full byte (6 bits for
251 // the exceptions, and 2 reserved bits.)
252 fpscr
&= ~(static_cast<uint32_t>(0xFF));
254 FEnv::set_fpscr(fpscr
);
258 const FEnv
*state
= reinterpret_cast<const FEnv
*>(envp
);
259 FEnv::set_fpscr(state
->fpscr
);
263 } // namespace fputil
264 } // namespace LIBC_NAMESPACE_DECL
266 #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_ARM_FENVIMPL_H