1 /* Private floating point rounding and exceptions handling. RISC-V version.
2 Copyright (C) 2014-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19 #ifndef RISCV_FENV_PRIVATE_H
20 #define RISCV_FENV_PRIVATE_H 1
21
22 #include <fenv.h>
23 #include <fpu_control.h>
24 #include <get-rounding-mode.h>
25
26 static __always_inline int
riscv_getround(void)27 riscv_getround (void)
28 {
29 return get_rounding_mode ();
30 }
31
32 static __always_inline void
riscv_setround(int rm)33 riscv_setround (int rm)
34 {
35 asm volatile ("fsrm %z0" : : "rJ" (rm));
36 }
37
38 static __always_inline int
riscv_getflags(void)39 riscv_getflags (void)
40 {
41 int flags;
42 asm volatile ("frflags %0" : "=r" (flags));
43 return flags;
44 }
45
46 static __always_inline void
riscv_setflags(int flags)47 riscv_setflags (int flags)
48 {
49 asm volatile ("fsflags %z0" : : "rJ" (flags));
50 }
51
52 static __always_inline void
libc_feholdexcept_riscv(fenv_t * envp)53 libc_feholdexcept_riscv (fenv_t *envp)
54 {
55 asm volatile ("csrrc %0, fcsr, %1" : "=r" (*envp) : "i" (FE_ALL_EXCEPT));
56 }
57
58 #define libc_feholdexcept libc_feholdexcept_riscv
59 #define libc_feholdexceptf libc_feholdexcept_riscv
60 #define libc_feholdexceptl libc_feholdexcept_riscv
61
62 static __always_inline void
libc_fesetround_riscv(int round)63 libc_fesetround_riscv (int round)
64 {
65 riscv_setround (round);
66 }
67
68 #define libc_fesetround libc_fesetround_riscv
69 #define libc_fesetroundf libc_fesetround_riscv
70 #define libc_fesetroundl libc_fesetround_riscv
71
72 static __always_inline void
libc_feholdexcept_setround_riscv(fenv_t * envp,int round)73 libc_feholdexcept_setround_riscv (fenv_t *envp, int round)
74 {
75 libc_feholdexcept_riscv (envp);
76 libc_fesetround_riscv (round);
77 }
78
79 #define libc_feholdexcept_setround libc_feholdexcept_setround_riscv
80 #define libc_feholdexcept_setroundf libc_feholdexcept_setround_riscv
81 #define libc_feholdexcept_setroundl libc_feholdexcept_setround_riscv
82
83 static __always_inline int
libc_fetestexcept_riscv(int ex)84 libc_fetestexcept_riscv (int ex)
85 {
86 return riscv_getflags () & ex;
87 }
88
89 #define libc_fetestexcept libc_fetestexcept_riscv
90 #define libc_fetestexceptf libc_fetestexcept_riscv
91 #define libc_fetestexceptl libc_fetestexcept_riscv
92
93 static __always_inline void
libc_fesetenv_riscv(const fenv_t * envp)94 libc_fesetenv_riscv (const fenv_t *envp)
95 {
96 long int env = (long int) envp - (long int) FE_DFL_ENV;
97 if (env != 0)
98 env = *envp;
99
100 _FPU_SETCW (env);
101 }
102
103 #define libc_fesetenv libc_fesetenv_riscv
104 #define libc_fesetenvf libc_fesetenv_riscv
105 #define libc_fesetenvl libc_fesetenv_riscv
106 #define libc_feresetround_noex libc_fesetenv_riscv
107 #define libc_feresetround_noexf libc_fesetenv_riscv
108 #define libc_feresetround_noexl libc_fesetenv_riscv
109
110 static __always_inline int
libc_feupdateenv_test_riscv(const fenv_t * envp,int ex)111 libc_feupdateenv_test_riscv (const fenv_t *envp, int ex)
112 {
113 fenv_t env = *envp;
114 int flags = riscv_getflags ();
115 asm volatile ("csrw fcsr, %z0" : : "rJ" (env | flags));
116 return flags & ex;
117 }
118
119 #define libc_feupdateenv_test libc_feupdateenv_test_riscv
120 #define libc_feupdateenv_testf libc_feupdateenv_test_riscv
121 #define libc_feupdateenv_testl libc_feupdateenv_test_riscv
122
123 static __always_inline void
libc_feupdateenv_riscv(const fenv_t * envp)124 libc_feupdateenv_riscv (const fenv_t *envp)
125 {
126 _FPU_SETCW (*envp | riscv_getflags ());
127 }
128
129 #define libc_feupdateenv libc_feupdateenv_riscv
130 #define libc_feupdateenvf libc_feupdateenv_riscv
131 #define libc_feupdateenvl libc_feupdateenv_riscv
132
133 static __always_inline void
libc_feholdsetround_riscv(fenv_t * envp,int round)134 libc_feholdsetround_riscv (fenv_t *envp, int round)
135 {
136 /* Note this implementation makes an improperly-formatted fenv_t and
137 so should only be used in conjunction with libc_feresetround. */
138 int old_round;
139 asm volatile ("csrrw %0, frm, %z1" : "=r" (old_round) : "rJ" (round));
140 *envp = old_round;
141 }
142
143 #define libc_feholdsetround libc_feholdsetround_riscv
144 #define libc_feholdsetroundf libc_feholdsetround_riscv
145 #define libc_feholdsetroundl libc_feholdsetround_riscv
146
147 static __always_inline void
libc_feresetround_riscv(fenv_t * envp)148 libc_feresetround_riscv (fenv_t *envp)
149 {
150 /* Note this implementation takes an improperly-formatted fenv_t and
151 so should only be used in conjunction with libc_feholdsetround. */
152 riscv_setround (*envp);
153 }
154
155 #define libc_feresetround libc_feresetround_riscv
156 #define libc_feresetroundf libc_feresetround_riscv
157 #define libc_feresetroundl libc_feresetround_riscv
158
159 #include_next <fenv_private.h>
160
161 #endif
162