xref: /aosp_15_r20/external/llvm-libc/src/__support/FPUtil/riscv/FEnvImpl.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
1 //===-- riscv floating point env 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_RISCV_FENVIMPL_H
10 #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_RISCV_FENVIMPL_H
11 
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_ASM
16 #include "src/__support/macros/config.h"     // For LIBC_INLINE
17 
18 #include <stdint.h>
19 
20 namespace LIBC_NAMESPACE_DECL {
21 namespace fputil {
22 
23 struct FEnv {
24   // We will ignore RMM and DYN rounding modes.
25   static constexpr uint32_t TONEAREST = 0x0;
26   static constexpr uint32_t TOWARDZERO = 0x1;
27   static constexpr uint32_t DOWNWARD = 0x2;
28   static constexpr uint32_t UPWARD = 0x3;
29 
30   // These are the bit locations of the corresponding exceptions in fcsr.
31   static constexpr uint32_t INEXACT = 0x1;
32   static constexpr uint32_t UNDERFLOW = 0x2;
33   static constexpr uint32_t OVERFLOW = 0x4;
34   static constexpr uint32_t DIVBYZERO = 0x8;
35   static constexpr uint32_t INVALID = 0x10;
36 
get_frmFEnv37   LIBC_INLINE static uint32_t get_frm() {
38     unsigned int rm;
39     LIBC_INLINE_ASM("frrm %0\n\t" : "=r"(rm));
40     return rm;
41   }
42 
set_frmFEnv43   LIBC_INLINE static void set_frm(uint32_t rm) {
44     LIBC_INLINE_ASM("fsrm %0, %0\n\t" : "+r"(rm));
45   }
46 
get_fflagsFEnv47   LIBC_INLINE static uint32_t get_fflags() {
48     unsigned int flags;
49     LIBC_INLINE_ASM("frflags %0\n\t" : "=r"(flags));
50     return flags;
51   }
52 
set_fflagsFEnv53   LIBC_INLINE static void set_fflags(uint32_t flags) {
54     LIBC_INLINE_ASM("fsflags %0, %0\n\t" : "+r"(flags));
55   }
56 
get_fcsrFEnv57   LIBC_INLINE static uint32_t get_fcsr() {
58     unsigned int fcsr;
59     LIBC_INLINE_ASM("frcsr %0\n\t" : "=r"(fcsr));
60     return fcsr;
61   }
62 
set_fcsrFEnv63   LIBC_INLINE static void set_fcsr(uint32_t fcsr) {
64     LIBC_INLINE_ASM("fscsr %0, %0\n\t" : "+r"(fcsr));
65   }
66 
exception_bits_to_macroFEnv67   LIBC_INLINE static int exception_bits_to_macro(uint32_t status) {
68     return ((status & INVALID) ? FE_INVALID : 0) |
69            ((status & DIVBYZERO) ? FE_DIVBYZERO : 0) |
70            ((status & OVERFLOW) ? FE_OVERFLOW : 0) |
71            ((status & UNDERFLOW) ? FE_UNDERFLOW : 0) |
72            ((status & INEXACT) ? FE_INEXACT : 0);
73   }
74 
exception_macro_to_bitsFEnv75   LIBC_INLINE static uint32_t exception_macro_to_bits(int except) {
76     return ((except & FE_INVALID) ? INVALID : 0) |
77            ((except & FE_DIVBYZERO) ? DIVBYZERO : 0) |
78            ((except & FE_OVERFLOW) ? OVERFLOW : 0) |
79            ((except & FE_UNDERFLOW) ? UNDERFLOW : 0) |
80            ((except & FE_INEXACT) ? INEXACT : 0);
81   }
82 };
83 
84 // Since RISCV does not have exception enable bits, we will just return
85 // the failure indicator.
enable_except(int)86 LIBC_INLINE int enable_except(int) { return -1; }
87 
88 // Always succeed.
disable_except(int)89 LIBC_INLINE int disable_except(int) { return 0; }
90 
91 // Always return "no exceptions enabled".
get_except()92 LIBC_INLINE int get_except() { return 0; }
93 
clear_except(int excepts)94 LIBC_INLINE int clear_except(int excepts) {
95   uint32_t flags = FEnv::get_fflags();
96   uint32_t to_clear = FEnv::exception_macro_to_bits(excepts);
97   flags &= ~to_clear;
98   FEnv::set_fflags(flags);
99   return 0;
100 }
101 
test_except(int excepts)102 LIBC_INLINE int test_except(int excepts) {
103   uint32_t to_test = FEnv::exception_macro_to_bits(excepts);
104   uint32_t flags = FEnv::get_fflags();
105   return FEnv::exception_bits_to_macro(flags & to_test);
106 }
107 
set_except(int excepts)108 LIBC_INLINE int set_except(int excepts) {
109   uint32_t flags = FEnv::get_fflags();
110   FEnv::set_fflags(flags | FEnv::exception_macro_to_bits(excepts));
111   return 0;
112 }
113 
raise_except(int excepts)114 LIBC_INLINE int raise_except(int excepts) {
115   // Since there are no traps, we just set the exception flags.
116   uint32_t flags = FEnv::get_fflags();
117   FEnv::set_fflags(flags | FEnv::exception_macro_to_bits(excepts));
118   return 0;
119 }
120 
get_round()121 LIBC_INLINE int get_round() {
122   uint32_t rm = FEnv::get_frm();
123   switch (rm) {
124   case FEnv::TONEAREST:
125     return FE_TONEAREST;
126   case FEnv::DOWNWARD:
127     return FE_DOWNWARD;
128   case FEnv::UPWARD:
129     return FE_UPWARD;
130   case FEnv::TOWARDZERO:
131     return FE_TOWARDZERO;
132   default:
133     return -1; // Error value.
134   }
135   return 0;
136 }
137 
set_round(int mode)138 LIBC_INLINE int set_round(int mode) {
139   uint32_t rm;
140   switch (mode) {
141   case FE_TONEAREST:
142     rm = FEnv::TONEAREST;
143     break;
144   case FE_DOWNWARD:
145     rm = FEnv::DOWNWARD;
146     break;
147   case FE_UPWARD:
148     rm = FEnv::UPWARD;
149     break;
150   case FE_TOWARDZERO:
151     rm = FEnv::TOWARDZERO;
152     break;
153   default:
154     return -1; // To indicate failure
155   }
156   FEnv::set_frm(rm);
157   return 0;
158 }
159 
get_env(fenv_t * envp)160 LIBC_INLINE int get_env(fenv_t *envp) {
161   uint32_t *state = reinterpret_cast<uint32_t *>(envp);
162   *state = FEnv::get_fcsr();
163   return 0;
164 }
165 
set_env(const fenv_t * envp)166 LIBC_INLINE int set_env(const fenv_t *envp) {
167   if (envp == FE_DFL_ENV) {
168     FEnv::set_frm(FEnv::TONEAREST);
169     FEnv::set_fflags(0);
170     return 0;
171   }
172   uint32_t status = *reinterpret_cast<const uint32_t *>(envp);
173   // We have to do the masking to preserve the reserved bits.
174   FEnv::set_fcsr((status & 0xFF) | (FEnv::get_fcsr() & 0xFFFFFF00));
175   return 0;
176 }
177 
178 } // namespace fputil
179 } // namespace LIBC_NAMESPACE_DECL
180 
181 #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_RISCV_FENVIMPL_H
182