]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/riscv/rvf/math_private.h
RISC-V: Fix rounding save/restore bug.
[thirdparty/glibc.git] / sysdeps / riscv / rvf / math_private.h
CommitLineData
b2cb5e02
PD
1/* Private floating point rounding and exceptions handling. RISC-V version.
2 Copyright (C) 2014-2018 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 <http://www.gnu.org/licenses/>. */
18
19#ifndef RISCV_MATH_PRIVATE_H
20#define RISCV_MATH_PRIVATE_H 1
21
22#include <fenv.h>
23#include <fpu_control.h>
24#include <get-rounding-mode.h>
25
26static __always_inline int
27riscv_getround (void)
28{
29 return get_rounding_mode ();
30}
31
32static __always_inline void
33riscv_setround (int rm)
34{
35 asm volatile ("fsrm %z0" : : "rJ" (rm));
36}
37
38static __always_inline int
39riscv_getflags (void)
40{
41 int flags;
42 asm volatile ("frflags %0" : "=r" (flags));
43 return flags;
44}
45
46static __always_inline void
47riscv_setflags (int flags)
48{
49 asm volatile ("fsflags %z0" : : "rJ" (flags));
50}
51
52static __always_inline void
53libc_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
62static __always_inline void
63libc_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
72static __always_inline void
73libc_feholdexcept_setround_riscv (fenv_t *envp, int round)
74{
b2cb5e02 75 libc_feholdexcept_riscv (envp);
bf418187 76 libc_fesetround_riscv (round);
b2cb5e02
PD
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
83static __always_inline int
84libc_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
93static __always_inline void
94libc_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
110static __always_inline int
111libc_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
123static __always_inline void
124libc_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
133static __always_inline void
134libc_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
147static __always_inline void
148libc_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 <math_private.h>
160
161#endif