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 "src/__support/FPUtil/FPBits.h"
13 #include "src/__support/macros/config.h" // For LIBC_INLINE
18 namespace __llvm_libc
{
22 // Arm floating point state is all stored in a single 32-bit register named
25 static constexpr uint32_t RoundingControlBitPosition
= 22;
26 static constexpr uint32_t ExceptionControlBitPosition
= 8;
28 static constexpr uint32_t TONEAREST
= 0x0;
29 static constexpr uint32_t UPWARD
= 0x1;
30 static constexpr uint32_t DOWNWARD
= 0x2;
31 static constexpr uint32_t TOWARDZERO
= 0x3;
33 static constexpr uint32_t INVALID_ENABLE
= 0x1;
34 static constexpr uint32_t DIVBYZERO_ENABLE
= 0x2;
35 static constexpr uint32_t OVERFLOW_ENABLE
= 0x4;
36 static constexpr uint32_t UNDERFLOW_ENABLE
= 0x8;
37 static constexpr uint32_t INEXACT_ENABLE
= 0x10;
38 static constexpr uint32_t DENORMAL_ENABLE
= 0x20;
40 static constexpr uint32_t INVALID_STATUS
= 0x1;
41 static constexpr uint32_t DIVBYZERO_STATUS
= 0x2;
42 static constexpr uint32_t OVERFLOW_STATUS
= 0x4;
43 static constexpr uint32_t UNDERFLOW_STATUS
= 0x8;
44 static constexpr uint32_t INEXACT_STATUS
= 0x10;
45 static constexpr uint32_t DENORMAL_STATUS
= 0x80;
47 LIBC_INLINE
static uint32_t get_fpscr() { return __builtin_arm_get_fpscr(); }
48 LIBC_INLINE
static void set_fpscr(uint32_t val
) {
49 __builtin_arm_set_fpscr(val
);
52 LIBC_INLINE
static int exception_enable_bits_to_macro(uint32_t status
) {
53 return (status
& INVALID_ENABLE
? FE_INVALID
: 0) |
54 (status
& DIVBYZERO_ENABLE
? FE_DIVBYZERO
: 0) |
55 (status
& OVERFLOW_ENABLE
? FE_OVERFLOW
: 0) |
56 (status
& UNDERFLOW_ENABLE
? FE_UNDERFLOW
: 0) |
57 (status
& INEXACT_ENABLE
? FE_INEXACT
: 0);
60 LIBC_INLINE
static uint32_t exception_macro_to_enable_bits(int except
) {
61 return (except
& FE_INVALID
? INVALID_ENABLE
: 0) |
62 (except
& FE_DIVBYZERO
? DIVBYZERO_ENABLE
: 0) |
63 (except
& FE_OVERFLOW
? OVERFLOW_ENABLE
: 0) |
64 (except
& FE_UNDERFLOW
? UNDERFLOW_ENABLE
: 0) |
65 (except
& FE_INEXACT
? INEXACT_ENABLE
: 0);
68 LIBC_INLINE
static uint32_t exception_macro_to_status_bits(int except
) {
69 return (except
& FE_INVALID
? INVALID_STATUS
: 0) |
70 (except
& FE_DIVBYZERO
? DIVBYZERO_STATUS
: 0) |
71 (except
& FE_OVERFLOW
? OVERFLOW_STATUS
: 0) |
72 (except
& FE_UNDERFLOW
? UNDERFLOW_STATUS
: 0) |
73 (except
& FE_INEXACT
? INEXACT_STATUS
: 0);
76 LIBC_INLINE
static uint32_t exception_status_bits_to_macro(int status
) {
77 return (status
& INVALID_STATUS
? FE_INVALID
: 0) |
78 (status
& DIVBYZERO_STATUS
? FE_DIVBYZERO
: 0) |
79 (status
& OVERFLOW_STATUS
? FE_OVERFLOW
: 0) |
80 (status
& UNDERFLOW_STATUS
? FE_UNDERFLOW
: 0) |
81 (status
& INEXACT_STATUS
? FE_INEXACT
: 0);
85 // Enables exceptions in |excepts| and returns the previously set exceptions.
86 LIBC_INLINE
int enable_except(int excepts
) {
87 uint32_t new_excepts
= FEnv::exception_macro_to_enable_bits(excepts
);
88 uint32_t fpscr
= FEnv::get_fpscr();
89 int old
= (fpscr
>> FEnv::ExceptionControlBitPosition
) & 0x3F;
90 fpscr
|= (new_excepts
<< FEnv::ExceptionControlBitPosition
);
91 FEnv::set_fpscr(fpscr
);
92 return FEnv::exception_enable_bits_to_macro(old
);
95 // Disables exceptions in |excepts| and returns the previously set exceptions.
96 LIBC_INLINE
int disable_except(int excepts
) {
97 uint32_t disable_bits
= FEnv::exception_macro_to_enable_bits(excepts
);
98 uint32_t fpscr
= FEnv::get_fpscr();
99 int old
= (fpscr
>> FEnv::ExceptionControlBitPosition
) & 0x3F;
100 fpscr
&= ~(disable_bits
<< FEnv::ExceptionControlBitPosition
);
101 FEnv::set_fpscr(fpscr
);
102 return FEnv::exception_enable_bits_to_macro(old
);
105 // Returns the currently enabled exceptions.
106 LIBC_INLINE
int get_except() {
107 uint32_t fpscr
= FEnv::get_fpscr();
108 int enabled_excepts
= (fpscr
>> FEnv::ExceptionControlBitPosition
) & 0x3F;
109 return FEnv::exception_enable_bits_to_macro(enabled_excepts
);
112 // Clears the exceptions in |excepts|.
113 LIBC_INLINE
int clear_except(int excepts
) {
114 uint32_t fpscr
= FEnv::get_fpscr();
115 uint32_t to_clear
= FEnv::exception_macro_to_status_bits(excepts
);
117 FEnv::set_fpscr(fpscr
);
121 // Returns the set of exceptions which are from the input set |excepts|.
122 LIBC_INLINE
int test_except(int excepts
) {
123 uint32_t to_test
= FEnv::exception_macro_to_status_bits(excepts
);
124 uint32_t fpscr
= FEnv::get_fpscr();
125 return FEnv::exception_status_bits_to_macro(fpscr
& 0x9F & to_test
);
128 // Set the exceptions in |excepts|.
129 LIBC_INLINE
int set_except(int excepts
) {
130 uint32_t fpscr
= FEnv::get_fpscr();
131 FEnv::set_fpscr(fpscr
| FEnv::exception_macro_to_status_bits(excepts
));
135 LIBC_INLINE
int raise_except(int excepts
) {
138 float large_value
= float(FPBits
<float>(FPBits
<float>::MAX_NORMAL
));
139 float small_value
= float(FPBits
<float>(FPBits
<float>::MIN_NORMAL
));
140 auto divfunc
= [](float a
, float b
) {
141 __asm__
__volatile__("flds s0, %0\n\t"
143 "fdivs s0, s0, s1\n\t"
146 : "s0", "s1" /* s0 and s1 are clobbered */);
149 uint32_t to_raise
= FEnv::exception_macro_to_status_bits(excepts
);
152 if (to_raise
& FEnv::INVALID_STATUS
) {
154 uint32_t fpscr
= FEnv::get_fpscr();
155 if (!(fpscr
& FEnv::INVALID_STATUS
))
158 if (to_raise
& FEnv::DIVBYZERO_STATUS
) {
160 uint32_t fpscr
= FEnv::get_fpscr();
161 if (!(fpscr
& FEnv::DIVBYZERO_STATUS
))
164 if (to_raise
& FEnv::OVERFLOW_STATUS
) {
165 divfunc(large_value
, small_value
);
166 uint32_t fpscr
= FEnv::get_fpscr();
167 if (!(fpscr
& FEnv::OVERFLOW_STATUS
))
170 if (to_raise
& FEnv::UNDERFLOW_STATUS
) {
171 divfunc(small_value
, large_value
);
172 uint32_t fpscr
= FEnv::get_fpscr();
173 if (!(fpscr
& FEnv::UNDERFLOW_STATUS
))
176 if (to_raise
& FEnv::INEXACT_STATUS
) {
179 // 2.0 / 3.0 cannot be represented exactly in any radix 2 floating point
182 uint32_t fpscr
= FEnv::get_fpscr();
183 if (!(fpscr
& FEnv::INEXACT_STATUS
))
189 LIBC_INLINE
int get_round() {
190 uint32_t mode
= (FEnv::get_fpscr() >> FEnv::RoundingControlBitPosition
) & 0x3;
192 case FEnv::TONEAREST
:
198 case FEnv::TOWARDZERO
:
199 return FE_TOWARDZERO
;
201 return -1; // Error value.
206 LIBC_INLINE
int set_round(int mode
) {
210 bits
= FEnv::TONEAREST
;
213 bits
= FEnv::DOWNWARD
;
219 bits
= FEnv::TOWARDZERO
;
222 return 1; // To indicate failure
225 uint32_t fpscr
= FEnv::get_fpscr();
226 fpscr
&= ~(0x3 << FEnv::RoundingControlBitPosition
);
227 fpscr
|= (bits
<< FEnv::RoundingControlBitPosition
);
228 FEnv::set_fpscr(fpscr
);
233 LIBC_INLINE
int get_env(fenv_t
*envp
) {
234 FEnv
*state
= reinterpret_cast<FEnv
*>(envp
);
235 state
->fpscr
= FEnv::get_fpscr();
239 LIBC_INLINE
int set_env(const fenv_t
*envp
) {
240 if (envp
== FE_DFL_ENV
) {
241 uint32_t fpscr
= FEnv::get_fpscr();
242 // Default status implies:
243 // 1. Round to nearest rounding mode.
244 fpscr
&= ~(0x3 << FEnv::RoundingControlBitPosition
);
245 fpscr
|= (FEnv::TONEAREST
<< FEnv::RoundingControlBitPosition
);
246 // 2. All exceptions are disabled.
247 fpscr
&= ~(0x3F << FEnv::ExceptionControlBitPosition
);
248 // 3. All exceptions are cleared. There are two reserved bits
249 // at bit 5 and 6 so we just write one full byte (6 bits for
250 // the exceptions, and 2 reserved bits.)
251 fpscr
&= ~(static_cast<uint32_t>(0xFF));
253 FEnv::set_fpscr(fpscr
);
257 const FEnv
*state
= reinterpret_cast<const FEnv
*>(envp
);
258 FEnv::set_fpscr(state
->fpscr
);
262 } // namespace fputil
263 } // namespace __llvm_libc
265 #endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_ARM_FENVIMPL_H