1 /* Internal math stuff.  MIPS version.
2    Copyright (C) 2013-2021 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 MIPS_FENV_PRIVATE_H
20 #define MIPS_FENV_PRIVATE_H 1
21 
22 /* Inline functions to speed up the math library implementation.  The
23    default versions of these routines are in generic/fenv_private.h
24    and call fesetround, feholdexcept, etc.  These routines use inlined
25    code instead.  */
26 
27 #include <fenv.h>
28 #include <fenv_libc.h>
29 #include <fpu_control.h>
30 
31 #define _FPU_MASK_ALL (_FPU_MASK_V | _FPU_MASK_Z | _FPU_MASK_O \
32 		       |_FPU_MASK_U | _FPU_MASK_I | FE_ALL_EXCEPT)
33 
34 static __always_inline void
libc_feholdexcept_mips(fenv_t * envp)35 libc_feholdexcept_mips (fenv_t *envp)
36 {
37   fpu_control_t cw;
38 
39   /* Save the current state.  */
40   _FPU_GETCW (cw);
41   envp->__fp_control_register = cw;
42 
43   /* Clear all exception enable bits and flags.  */
44   cw &= ~(_FPU_MASK_ALL);
45   _FPU_SETCW (cw);
46 }
47 #define libc_feholdexcept libc_feholdexcept_mips
48 #define libc_feholdexceptf libc_feholdexcept_mips
49 #define libc_feholdexceptl libc_feholdexcept_mips
50 
51 static __always_inline void
libc_fesetround_mips(int round)52 libc_fesetround_mips (int round)
53 {
54   fpu_control_t cw;
55 
56   /* Get current state.  */
57   _FPU_GETCW (cw);
58 
59   /* Set rounding bits.  */
60   cw &= ~_FPU_RC_MASK;
61   cw |= round;
62 
63   /* Set new state.  */
64   _FPU_SETCW (cw);
65 }
66 #define libc_fesetround libc_fesetround_mips
67 #define libc_fesetroundf libc_fesetround_mips
68 #define libc_fesetroundl libc_fesetround_mips
69 
70 static __always_inline void
libc_feholdexcept_setround_mips(fenv_t * envp,int round)71 libc_feholdexcept_setround_mips (fenv_t *envp, int round)
72 {
73   fpu_control_t cw;
74 
75   /* Save the current state.  */
76   _FPU_GETCW (cw);
77   envp->__fp_control_register = cw;
78 
79   /* Clear all exception enable bits and flags.  */
80   cw &= ~(_FPU_MASK_ALL);
81 
82   /* Set rounding bits.  */
83   cw &= ~_FPU_RC_MASK;
84   cw |= round;
85 
86   /* Set new state.  */
87   _FPU_SETCW (cw);
88 }
89 #define libc_feholdexcept_setround libc_feholdexcept_setround_mips
90 #define libc_feholdexcept_setroundf libc_feholdexcept_setround_mips
91 #define libc_feholdexcept_setroundl libc_feholdexcept_setround_mips
92 
93 #define libc_feholdsetround libc_feholdexcept_setround_mips
94 #define libc_feholdsetroundf libc_feholdexcept_setround_mips
95 #define libc_feholdsetroundl libc_feholdexcept_setround_mips
96 
97 static __always_inline void
libc_fesetenv_mips(fenv_t * envp)98 libc_fesetenv_mips (fenv_t *envp)
99 {
100   fpu_control_t cw __attribute__ ((unused));
101 
102   /* Read current state to flush fpu pipeline.  */
103   _FPU_GETCW (cw);
104 
105   _FPU_SETCW (envp->__fp_control_register);
106 }
107 #define libc_fesetenv libc_fesetenv_mips
108 #define libc_fesetenvf libc_fesetenv_mips
109 #define libc_fesetenvl libc_fesetenv_mips
110 
111 static __always_inline int
libc_feupdateenv_test_mips(fenv_t * envp,int excepts)112 libc_feupdateenv_test_mips (fenv_t *envp, int excepts)
113 {
114   /* int ret = fetestexcept (excepts); feupdateenv (envp); return ret; */
115   int cw, temp;
116 
117   /* Get current control word.  */
118   _FPU_GETCW (cw);
119 
120   /* Set flag bits (which are accumulative), and *also* set the
121      cause bits.  The setting of the cause bits is what actually causes
122      the hardware to generate the exception, if the corresponding enable
123      bit is set as well.  */
124   temp = cw & FE_ALL_EXCEPT;
125   temp |= envp->__fp_control_register | (temp << CAUSE_SHIFT);
126 
127   /* Set new state.  */
128   _FPU_SETCW (temp);
129 
130   return cw & excepts & FE_ALL_EXCEPT;
131 }
132 #define libc_feupdateenv_test libc_feupdateenv_test_mips
133 #define libc_feupdateenv_testf libc_feupdateenv_test_mips
134 #define libc_feupdateenv_testl libc_feupdateenv_test_mips
135 
136 static __always_inline void
libc_feupdateenv_mips(fenv_t * envp)137 libc_feupdateenv_mips (fenv_t *envp)
138 {
139   libc_feupdateenv_test_mips (envp, 0);
140 }
141 #define libc_feupdateenv libc_feupdateenv_mips
142 #define libc_feupdateenvf libc_feupdateenv_mips
143 #define libc_feupdateenvl libc_feupdateenv_mips
144 
145 #define libc_feresetround libc_feupdateenv_mips
146 #define libc_feresetroundf libc_feupdateenv_mips
147 #define libc_feresetroundl libc_feupdateenv_mips
148 
149 static __always_inline int
libc_fetestexcept_mips(int excepts)150 libc_fetestexcept_mips (int excepts)
151 {
152   int cw;
153 
154   /* Get current control word.  */
155   _FPU_GETCW (cw);
156 
157   return cw & excepts & FE_ALL_EXCEPT;
158 }
159 #define libc_fetestexcept libc_fetestexcept_mips
160 #define libc_fetestexceptf libc_fetestexcept_mips
161 #define libc_fetestexceptl libc_fetestexcept_mips
162 
163 /*  Enable support for rounding mode context.  */
164 #define HAVE_RM_CTX 1
165 
166 static __always_inline void
libc_feholdexcept_setround_mips_ctx(struct rm_ctx * ctx,int round)167 libc_feholdexcept_setround_mips_ctx (struct rm_ctx *ctx, int round)
168 {
169   fpu_control_t old, new;
170 
171   /* Save the current state.  */
172   _FPU_GETCW (old);
173   ctx->env.__fp_control_register = old;
174 
175   /* Clear all exception enable bits and flags.  */
176   new = old & ~(_FPU_MASK_ALL);
177 
178   /* Set rounding bits.  */
179   new = (new & ~_FPU_RC_MASK) | round;
180 
181   if (__glibc_unlikely (new != old))
182     {
183       _FPU_SETCW (new);
184       ctx->updated_status = true;
185     }
186   else
187     ctx->updated_status = false;
188 }
189 #define libc_feholdexcept_setround_ctx   libc_feholdexcept_setround_mips_ctx
190 #define libc_feholdexcept_setroundf_ctx  libc_feholdexcept_setround_mips_ctx
191 #define libc_feholdexcept_setroundl_ctx  libc_feholdexcept_setround_mips_ctx
192 
193 static __always_inline void
libc_fesetenv_mips_ctx(struct rm_ctx * ctx)194 libc_fesetenv_mips_ctx (struct rm_ctx *ctx)
195 {
196   libc_fesetenv_mips (&ctx->env);
197 }
198 #define libc_fesetenv_ctx                libc_fesetenv_mips_ctx
199 #define libc_fesetenvf_ctx               libc_fesetenv_mips_ctx
200 #define libc_fesetenvl_ctx               libc_fesetenv_mips_ctx
201 
202 static __always_inline void
libc_feupdateenv_mips_ctx(struct rm_ctx * ctx)203 libc_feupdateenv_mips_ctx (struct rm_ctx *ctx)
204 {
205   if (__glibc_unlikely (ctx->updated_status))
206     libc_feupdateenv_test_mips (&ctx->env, 0);
207 }
208 #define libc_feupdateenv_ctx             libc_feupdateenv_mips_ctx
209 #define libc_feupdateenvf_ctx            libc_feupdateenv_mips_ctx
210 #define libc_feupdateenvl_ctx            libc_feupdateenv_mips_ctx
211 #define libc_feresetround_ctx            libc_feupdateenv_mips_ctx
212 #define libc_feresetroundf_ctx           libc_feupdateenv_mips_ctx
213 #define libc_feresetroundl_ctx           libc_feupdateenv_mips_ctx
214 
215 static __always_inline void
libc_feholdsetround_mips_ctx(struct rm_ctx * ctx,int round)216 libc_feholdsetround_mips_ctx (struct rm_ctx *ctx, int round)
217 {
218   fpu_control_t old, new;
219 
220   /* Save the current state.  */
221   _FPU_GETCW (old);
222   ctx->env.__fp_control_register = old;
223 
224   /* Set rounding bits.  */
225   new = (old & ~_FPU_RC_MASK) | round;
226 
227   if (__glibc_unlikely (new != old))
228     {
229       _FPU_SETCW (new);
230       ctx->updated_status = true;
231     }
232   else
233     ctx->updated_status = false;
234 }
235 #define libc_feholdsetround_ctx          libc_feholdsetround_mips_ctx
236 #define libc_feholdsetroundf_ctx         libc_feholdsetround_mips_ctx
237 #define libc_feholdsetroundl_ctx         libc_feholdsetround_mips_ctx
238 
239 #include_next <fenv_private.h>
240 
241 #endif
242