Fix addvdi3 and subvdi3 patterns
[official-gcc.git] / libgfortran / config / fpu-aarch64.h
blob47893908f604fc6361ab8ee5392902a08a49f8ae
1 /* FPU-related code for aarch64.
2 Copyright (C) 2020-2022 Free Software Foundation, Inc.
3 Contributed by Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
5 This file is part of the GNU Fortran runtime library (libgfortran).
7 Libgfortran is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 3 of the License, or (at your option) any later version.
12 Libgfortran is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
27 /* Rounding mask and modes */
29 #define FPCR_RM_MASK 0x0c00000
30 #define FE_TONEAREST 0x0000000
31 #define FE_UPWARD 0x0400000
32 #define FE_DOWNWARD 0x0800000
33 #define FE_TOWARDZERO 0x0c00000
34 #define FE_MAP_FZ 0x1000000
36 /* Exceptions */
38 #define FE_INVALID 1
39 #define FE_DIVBYZERO 2
40 #define FE_OVERFLOW 4
41 #define FE_UNDERFLOW 8
42 #define FE_INEXACT 16
44 #define FE_ALL_EXCEPT (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT)
45 #define FE_EXCEPT_SHIFT 8
49 /* This structure corresponds to the layout of the block
50 written by FSTENV. */
51 struct fenv
53 unsigned int __fpcr;
54 unsigned int __fpsr;
57 /* Check we can actually store the FPU state in the allocated size. */
58 _Static_assert (sizeof(struct fenv) <= (size_t) GFC_FPE_STATE_BUFFER_SIZE,
59 "GFC_FPE_STATE_BUFFER_SIZE is too small");
63 void
64 set_fpu (void)
66 if (options.fpe & GFC_FPE_DENORMAL)
67 estr_write ("Fortran runtime warning: Floating point 'denormal operand' "
68 "exception not supported.\n");
70 set_fpu_trap_exceptions (options.fpe, 0);
74 int
75 get_fpu_trap_exceptions (void)
77 unsigned int fpcr, exceptions;
78 int res = 0;
80 fpcr = __builtin_aarch64_get_fpcr();
81 exceptions = (fpcr >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT;
83 if (exceptions & FE_INVALID) res |= GFC_FPE_INVALID;
84 if (exceptions & FE_DIVBYZERO) res |= GFC_FPE_ZERO;
85 if (exceptions & FE_OVERFLOW) res |= GFC_FPE_OVERFLOW;
86 if (exceptions & FE_UNDERFLOW) res |= GFC_FPE_UNDERFLOW;
87 if (exceptions & FE_INEXACT) res |= GFC_FPE_INEXACT;
89 return res;
93 void set_fpu_trap_exceptions (int trap, int notrap)
95 unsigned int mode_set = 0, mode_clr = 0;
96 unsigned int fpsr, fpsr_new;
97 unsigned int fpcr, fpcr_new;
99 if (trap & GFC_FPE_INVALID)
100 mode_set |= FE_INVALID;
101 if (notrap & GFC_FPE_INVALID)
102 mode_clr |= FE_INVALID;
104 if (trap & GFC_FPE_ZERO)
105 mode_set |= FE_DIVBYZERO;
106 if (notrap & GFC_FPE_ZERO)
107 mode_clr |= FE_DIVBYZERO;
109 if (trap & GFC_FPE_OVERFLOW)
110 mode_set |= FE_OVERFLOW;
111 if (notrap & GFC_FPE_OVERFLOW)
112 mode_clr |= FE_OVERFLOW;
114 if (trap & GFC_FPE_UNDERFLOW)
115 mode_set |= FE_UNDERFLOW;
116 if (notrap & GFC_FPE_UNDERFLOW)
117 mode_clr |= FE_UNDERFLOW;
119 if (trap & GFC_FPE_INEXACT)
120 mode_set |= FE_INEXACT;
121 if (notrap & GFC_FPE_INEXACT)
122 mode_clr |= FE_INEXACT;
124 /* Clear stalled exception flags. */
125 fpsr = __builtin_aarch64_get_fpsr();
126 fpsr_new = fpsr & ~FE_ALL_EXCEPT;
127 if (fpsr_new != fpsr)
128 __builtin_aarch64_set_fpsr(fpsr_new);
130 fpcr_new = fpcr = __builtin_aarch64_get_fpcr();
131 fpcr_new |= (mode_set << FE_EXCEPT_SHIFT);
132 fpcr_new &= ~(mode_clr << FE_EXCEPT_SHIFT);
134 if (fpcr_new != fpcr)
135 __builtin_aarch64_set_fpcr(fpcr_new);
140 support_fpu_flag (int flag)
142 if (flag & GFC_FPE_DENORMAL)
143 return 0;
145 return 1;
150 support_fpu_trap (int flag)
152 if (flag & GFC_FPE_DENORMAL)
153 return 0;
155 return 1;
160 get_fpu_except_flags (void)
162 int result;
163 unsigned int fpsr;
165 result = 0;
166 fpsr = __builtin_aarch64_get_fpsr() & FE_ALL_EXCEPT;
168 if (fpsr & FE_INVALID)
169 result |= GFC_FPE_INVALID;
170 if (fpsr & FE_DIVBYZERO)
171 result |= GFC_FPE_ZERO;
172 if (fpsr & FE_OVERFLOW)
173 result |= GFC_FPE_OVERFLOW;
174 if (fpsr & FE_UNDERFLOW)
175 result |= GFC_FPE_UNDERFLOW;
176 if (fpsr & FE_INEXACT)
177 result |= GFC_FPE_INEXACT;
179 return result;
183 void
184 set_fpu_except_flags (int set, int clear)
186 unsigned int exc_set = 0, exc_clr = 0;
187 unsigned int fpsr, fpsr_new;
189 if (set & GFC_FPE_INVALID)
190 exc_set |= FE_INVALID;
191 else if (clear & GFC_FPE_INVALID)
192 exc_clr |= FE_INVALID;
194 if (set & GFC_FPE_ZERO)
195 exc_set |= FE_DIVBYZERO;
196 else if (clear & GFC_FPE_ZERO)
197 exc_clr |= FE_DIVBYZERO;
199 if (set & GFC_FPE_OVERFLOW)
200 exc_set |= FE_OVERFLOW;
201 else if (clear & GFC_FPE_OVERFLOW)
202 exc_clr |= FE_OVERFLOW;
204 if (set & GFC_FPE_UNDERFLOW)
205 exc_set |= FE_UNDERFLOW;
206 else if (clear & GFC_FPE_UNDERFLOW)
207 exc_clr |= FE_UNDERFLOW;
209 if (set & GFC_FPE_INEXACT)
210 exc_set |= FE_INEXACT;
211 else if (clear & GFC_FPE_INEXACT)
212 exc_clr |= FE_INEXACT;
214 fpsr_new = fpsr = __builtin_aarch64_get_fpsr();
215 fpsr_new &= ~exc_clr;
216 fpsr_new |= exc_set;
218 if (fpsr_new != fpsr)
219 __builtin_aarch64_set_fpsr(fpsr_new);
223 void
224 get_fpu_state (void *state)
226 struct fenv *envp = state;
227 envp->__fpcr = __builtin_aarch64_get_fpcr();
228 envp->__fpsr = __builtin_aarch64_get_fpsr();
232 void
233 set_fpu_state (void *state)
235 struct fenv *envp = state;
236 __builtin_aarch64_set_fpcr(envp->__fpcr);
237 __builtin_aarch64_set_fpsr(envp->__fpsr);
242 get_fpu_rounding_mode (void)
244 unsigned int fpcr = __builtin_aarch64_get_fpcr();
245 fpcr &= FPCR_RM_MASK;
247 switch (fpcr)
249 case FE_TONEAREST:
250 return GFC_FPE_TONEAREST;
251 case FE_UPWARD:
252 return GFC_FPE_UPWARD;
253 case FE_DOWNWARD:
254 return GFC_FPE_DOWNWARD;
255 case FE_TOWARDZERO:
256 return GFC_FPE_TOWARDZERO;
257 default:
258 return 0; /* Should be unreachable. */
263 void
264 set_fpu_rounding_mode (int round)
266 unsigned int fpcr, round_mode;
268 switch (round)
270 case GFC_FPE_TONEAREST:
271 round_mode = FE_TONEAREST;
272 break;
273 case GFC_FPE_UPWARD:
274 round_mode = FE_UPWARD;
275 break;
276 case GFC_FPE_DOWNWARD:
277 round_mode = FE_DOWNWARD;
278 break;
279 case GFC_FPE_TOWARDZERO:
280 round_mode = FE_TOWARDZERO;
281 break;
282 default:
283 return; /* Should be unreachable. */
286 fpcr = __builtin_aarch64_get_fpcr();
288 /* Only set FPCR if requested mode is different from current. */
289 round_mode = (fpcr ^ round_mode) & FPCR_RM_MASK;
290 if (round_mode != 0)
291 __builtin_aarch64_set_fpcr(fpcr ^ round_mode);
296 support_fpu_rounding_mode (int mode)
298 if (mode == GFC_FPE_AWAY)
299 return 0;
300 else
301 return 1;
306 support_fpu_underflow_control (int kind __attribute__((unused)))
308 /* Not supported for binary128. */
309 return (kind == 4 || kind == 8) ? 1 : 0;
314 get_fpu_underflow_mode (void)
316 unsigned int fpcr = __builtin_aarch64_get_fpcr();
318 /* Return 0 for abrupt underflow (flush to zero), 1 for gradual underflow. */
319 return (fpcr & FE_MAP_FZ) ? 0 : 1;
323 void
324 set_fpu_underflow_mode (int gradual __attribute__((unused)))
326 unsigned int fpcr = __builtin_aarch64_get_fpcr();
328 if (gradual)
329 fpcr &= ~FE_MAP_FZ;
330 else
331 fpcr |= FE_MAP_FZ;
333 __builtin_aarch64_set_fpcr(fpcr);