]> Git Repo - qemu.git/blob - target/loongarch/fpu_helper.c
1e514cce74ec01b2667946f517ab4708b0ec22dc
[qemu.git] / target / loongarch / fpu_helper.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * LoongArch float point emulation helpers for QEMU
4  *
5  * Copyright (c) 2021 Loongson Technology Corporation Limited
6  */
7
8 #include "qemu/osdep.h"
9 #include "cpu.h"
10 #include "exec/helper-proto.h"
11 #include "exec/exec-all.h"
12 #include "exec/cpu_ldst.h"
13 #include "fpu/softfloat.h"
14 #include "internals.h"
15
16 #define FLOAT_TO_INT32_OVERFLOW 0x7fffffff
17 #define FLOAT_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
18
19 static inline uint64_t nanbox_s(float32 fp)
20 {
21     return fp | MAKE_64BIT_MASK(32, 32);
22 }
23
24 /* Convert loongarch rounding mode in fcsr0 to IEEE library */
25 static const FloatRoundMode ieee_rm[4] = {
26     float_round_nearest_even,
27     float_round_to_zero,
28     float_round_up,
29     float_round_down
30 };
31
32 void restore_fp_status(CPULoongArchState *env)
33 {
34     set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3],
35                             &env->fp_status);
36     set_flush_to_zero(0, &env->fp_status);
37 }
38
39 static int ieee_ex_to_loongarch(int xcpt)
40 {
41     int ret = 0;
42     if (xcpt & float_flag_invalid) {
43         ret |= FP_INVALID;
44     }
45     if (xcpt & float_flag_overflow) {
46         ret |= FP_OVERFLOW;
47     }
48     if (xcpt & float_flag_underflow) {
49         ret |= FP_UNDERFLOW;
50     }
51     if (xcpt & float_flag_divbyzero) {
52         ret |= FP_DIV0;
53     }
54     if (xcpt & float_flag_inexact) {
55         ret |= FP_INEXACT;
56     }
57     return ret;
58 }
59
60 static void update_fcsr0_mask(CPULoongArchState *env, uintptr_t pc, int mask)
61 {
62     int flags = get_float_exception_flags(&env->fp_status);
63
64     set_float_exception_flags(0, &env->fp_status);
65
66     flags &= ~mask;
67
68     if (!flags) {
69         SET_FP_CAUSE(env->fcsr0, flags);
70         return;
71     } else {
72         flags = ieee_ex_to_loongarch(flags);
73         SET_FP_CAUSE(env->fcsr0, flags);
74     }
75
76     if (GET_FP_ENABLES(env->fcsr0) & flags) {
77         do_raise_exception(env, EXCCODE_FPE, pc);
78     } else {
79         UPDATE_FP_FLAGS(env->fcsr0, flags);
80     }
81 }
82
83 static void update_fcsr0(CPULoongArchState *env, uintptr_t pc)
84 {
85     update_fcsr0_mask(env, pc, 0);
86 }
87
88 uint64_t helper_fadd_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
89 {
90     uint64_t fd;
91
92     fd = nanbox_s(float32_add((uint32_t)fj, (uint32_t)fk, &env->fp_status));
93     update_fcsr0(env, GETPC());
94     return fd;
95 }
96
97 uint64_t helper_fadd_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
98 {
99     uint64_t fd;
100
101     fd = float64_add(fj, fk, &env->fp_status);
102     update_fcsr0(env, GETPC());
103     return fd;
104 }
105
106 uint64_t helper_fsub_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
107 {
108     uint64_t fd;
109
110     fd = nanbox_s(float32_sub((uint32_t)fj, (uint32_t)fk, &env->fp_status));
111     update_fcsr0(env, GETPC());
112     return fd;
113 }
114
115 uint64_t helper_fsub_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
116 {
117     uint64_t fd;
118
119     fd = float64_sub(fj, fk, &env->fp_status);
120     update_fcsr0(env, GETPC());
121     return fd;
122 }
123
124 uint64_t helper_fmul_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
125 {
126     uint64_t fd;
127
128     fd = nanbox_s(float32_mul((uint32_t)fj, (uint32_t)fk, &env->fp_status));
129     update_fcsr0(env, GETPC());
130     return fd;
131 }
132
133 uint64_t helper_fmul_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
134 {
135     uint64_t fd;
136
137     fd = float64_mul(fj, fk, &env->fp_status);
138     update_fcsr0(env, GETPC());
139     return fd;
140 }
141
142 uint64_t helper_fdiv_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
143 {
144     uint64_t fd;
145
146     fd = nanbox_s(float32_div((uint32_t)fj, (uint32_t)fk, &env->fp_status));
147     update_fcsr0(env, GETPC());
148     return fd;
149 }
150
151 uint64_t helper_fdiv_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
152 {
153     uint64_t fd;
154
155     fd = float64_div(fj, fk, &env->fp_status);
156     update_fcsr0(env, GETPC());
157     return fd;
158 }
159
160 uint64_t helper_fmax_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
161 {
162     uint64_t fd;
163
164     fd = nanbox_s(float32_maxnum((uint32_t)fj, (uint32_t)fk, &env->fp_status));
165     update_fcsr0(env, GETPC());
166     return fd;
167 }
168
169 uint64_t helper_fmax_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
170 {
171     uint64_t fd;
172
173     fd = float64_maxnum(fj, fk, &env->fp_status);
174     update_fcsr0(env, GETPC());
175     return fd;
176 }
177
178 uint64_t helper_fmin_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
179 {
180     uint64_t fd;
181
182     fd = nanbox_s(float32_minnum((uint32_t)fj, (uint32_t)fk, &env->fp_status));
183     update_fcsr0(env, GETPC());
184     return fd;
185 }
186
187 uint64_t helper_fmin_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
188 {
189     uint64_t fd;
190
191     fd = float64_minnum(fj, fk, &env->fp_status);
192     update_fcsr0(env, GETPC());
193     return fd;
194 }
195
196 uint64_t helper_fmaxa_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
197 {
198     uint64_t fd;
199
200     fd = nanbox_s(float32_maxnummag((uint32_t)fj,
201                                     (uint32_t)fk, &env->fp_status));
202     update_fcsr0(env, GETPC());
203     return fd;
204 }
205
206 uint64_t helper_fmaxa_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
207 {
208     uint64_t fd;
209
210     fd = float64_maxnummag(fj, fk, &env->fp_status);
211     update_fcsr0(env, GETPC());
212     return fd;
213 }
214
215 uint64_t helper_fmina_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
216 {
217     uint64_t fd;
218
219     fd = nanbox_s(float32_minnummag((uint32_t)fj,
220                                     (uint32_t)fk, &env->fp_status));
221     update_fcsr0(env, GETPC());
222     return fd;
223 }
224
225 uint64_t helper_fmina_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
226 {
227     uint64_t fd;
228
229     fd = float64_minnummag(fj, fk, &env->fp_status);
230     update_fcsr0(env, GETPC());
231     return fd;
232 }
233
234 uint64_t helper_fscaleb_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
235 {
236     uint64_t fd;
237     int32_t n = (int32_t)fk;
238
239     fd = nanbox_s(float32_scalbn((uint32_t)fj,
240                                  n >  0x200 ?  0x200 :
241                                  n < -0x200 ? -0x200 : n,
242                                  &env->fp_status));
243     update_fcsr0(env, GETPC());
244     return fd;
245 }
246
247 uint64_t helper_fscaleb_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
248 {
249     uint64_t fd;
250     int64_t n = (int64_t)fk;
251
252     fd = float64_scalbn(fj,
253                         n >  0x1000 ?  0x1000 :
254                         n < -0x1000 ? -0x1000 : n,
255                         &env->fp_status);
256     update_fcsr0(env, GETPC());
257     return fd;
258 }
259
260 uint64_t helper_fsqrt_s(CPULoongArchState *env, uint64_t fj)
261 {
262     uint64_t fd;
263
264     fd = nanbox_s(float32_sqrt((uint32_t)fj, &env->fp_status));
265     update_fcsr0(env, GETPC());
266     return fd;
267 }
268
269 uint64_t helper_fsqrt_d(CPULoongArchState *env, uint64_t fj)
270 {
271     uint64_t fd;
272
273     fd = float64_sqrt(fj, &env->fp_status);
274     update_fcsr0(env, GETPC());
275     return fd;
276 }
277
278 uint64_t helper_frecip_s(CPULoongArchState *env, uint64_t fj)
279 {
280     uint64_t fd;
281
282     fd = nanbox_s(float32_div(float32_one, (uint32_t)fj, &env->fp_status));
283     update_fcsr0(env, GETPC());
284     return fd;
285 }
286
287 uint64_t helper_frecip_d(CPULoongArchState *env, uint64_t fj)
288 {
289     uint64_t fd;
290
291     fd = float64_div(float64_one, fj, &env->fp_status);
292     update_fcsr0(env, GETPC());
293     return fd;
294 }
295
296 uint64_t helper_frsqrt_s(CPULoongArchState *env, uint64_t fj)
297 {
298     uint64_t fd;
299     uint32_t fp;
300
301     fp = float32_sqrt((uint32_t)fj, &env->fp_status);
302     fd = nanbox_s(float32_div(float32_one, fp, &env->fp_status));
303     update_fcsr0(env, GETPC());
304     return fd;
305 }
306
307 uint64_t helper_frsqrt_d(CPULoongArchState *env, uint64_t fj)
308 {
309     uint64_t fp, fd;
310
311     fp = float64_sqrt(fj, &env->fp_status);
312     fd = float64_div(float64_one, fp, &env->fp_status);
313     update_fcsr0(env, GETPC());
314     return fd;
315 }
316
317 uint64_t helper_flogb_s(CPULoongArchState *env, uint64_t fj)
318 {
319     uint64_t fd;
320     uint32_t fp;
321     float_status *status = &env->fp_status;
322     FloatRoundMode old_mode = get_float_rounding_mode(status);
323
324     set_float_rounding_mode(float_round_down, status);
325     fp = float32_log2((uint32_t)fj, status);
326     fd = nanbox_s(float32_round_to_int(fp, status));
327     set_float_rounding_mode(old_mode, status);
328     update_fcsr0_mask(env, GETPC(), float_flag_inexact);
329     return fd;
330 }
331
332 uint64_t helper_flogb_d(CPULoongArchState *env, uint64_t fj)
333 {
334     uint64_t fd;
335     float_status *status = &env->fp_status;
336     FloatRoundMode old_mode = get_float_rounding_mode(status);
337
338     set_float_rounding_mode(float_round_down, status);
339     fd = float64_log2(fj, status);
340     fd = float64_round_to_int(fd, status);
341     set_float_rounding_mode(old_mode, status);
342     update_fcsr0_mask(env, GETPC(), float_flag_inexact);
343     return fd;
344 }
345
346 uint64_t helper_fclass_s(CPULoongArchState *env, uint64_t fj)
347 {
348     float32 f = fj;
349     bool sign = float32_is_neg(f);
350
351     if (float32_is_infinity(f)) {
352         return sign ? 1 << 2 : 1 << 6;
353     } else if (float32_is_zero(f)) {
354         return sign ? 1 << 5 : 1 << 9;
355     } else if (float32_is_zero_or_denormal(f)) {
356         return sign ? 1 << 4 : 1 << 8;
357     } else if (float32_is_any_nan(f)) {
358         float_status s = { }; /* for snan_bit_is_one */
359         return float32_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0;
360     } else {
361         return sign ? 1 << 3 : 1 << 7;
362     }
363 }
364
365 uint64_t helper_fclass_d(CPULoongArchState *env, uint64_t fj)
366 {
367     float64 f = fj;
368     bool sign = float64_is_neg(f);
369
370     if (float64_is_infinity(f)) {
371         return sign ? 1 << 2 : 1 << 6;
372     } else if (float64_is_zero(f)) {
373         return sign ? 1 << 5 : 1 << 9;
374     } else if (float64_is_zero_or_denormal(f)) {
375         return sign ? 1 << 4 : 1 << 8;
376     } else if (float64_is_any_nan(f)) {
377         float_status s = { }; /* for snan_bit_is_one */
378         return float64_is_quiet_nan(f, &s) ? 1 << 1 : 1 << 0;
379     } else {
380         return sign ? 1 << 3 : 1 << 7;
381     }
382 }
383
384 uint64_t helper_fmuladd_s(CPULoongArchState *env, uint64_t fj,
385                           uint64_t fk, uint64_t fa, uint32_t flag)
386 {
387     uint64_t fd;
388
389     fd = nanbox_s(float32_muladd((uint32_t)fj, (uint32_t)fk,
390                                  (uint32_t)fa, flag, &env->fp_status));
391     update_fcsr0(env, GETPC());
392     return fd;
393 }
394
395 uint64_t helper_fmuladd_d(CPULoongArchState *env, uint64_t fj,
396                           uint64_t fk, uint64_t fa, uint32_t flag)
397 {
398     uint64_t fd;
399
400     fd = float64_muladd(fj, fk, fa, flag, &env->fp_status);
401     update_fcsr0(env, GETPC());
402     return fd;
403 }
404
405 static uint64_t fcmp_common(CPULoongArchState *env, FloatRelation cmp,
406                             uint32_t flags)
407 {
408     bool ret;
409
410     switch (cmp) {
411     case float_relation_less:
412         ret = (flags & FCMP_LT);
413         break;
414     case float_relation_equal:
415         ret = (flags & FCMP_EQ);
416         break;
417     case float_relation_greater:
418         ret = (flags & FCMP_GT);
419         break;
420     case float_relation_unordered:
421         ret = (flags & FCMP_UN);
422         break;
423     default:
424         g_assert_not_reached();
425     }
426     update_fcsr0(env, GETPC());
427
428     return ret;
429 }
430
431 /* fcmp_cXXX_s */
432 uint64_t helper_fcmp_c_s(CPULoongArchState *env, uint64_t fj,
433                          uint64_t fk, uint32_t flags)
434 {
435     FloatRelation cmp = float32_compare_quiet((uint32_t)fj,
436                                               (uint32_t)fk, &env->fp_status);
437     return fcmp_common(env, cmp, flags);
438 }
439
440 /* fcmp_sXXX_s */
441 uint64_t helper_fcmp_s_s(CPULoongArchState *env, uint64_t fj,
442                          uint64_t fk, uint32_t flags)
443 {
444     FloatRelation cmp = float32_compare((uint32_t)fj,
445                                         (uint32_t)fk, &env->fp_status);
446     return fcmp_common(env, cmp, flags);
447 }
448
449 /* fcmp_cXXX_d */
450 uint64_t helper_fcmp_c_d(CPULoongArchState *env, uint64_t fj,
451                          uint64_t fk, uint32_t flags)
452 {
453     FloatRelation cmp = float64_compare_quiet(fj, fk, &env->fp_status);
454     return fcmp_common(env, cmp, flags);
455 }
456
457 /* fcmp_sXXX_d */
458 uint64_t helper_fcmp_s_d(CPULoongArchState *env, uint64_t fj,
459                          uint64_t fk, uint32_t flags)
460 {
461     FloatRelation cmp = float64_compare(fj, fk, &env->fp_status);
462     return fcmp_common(env, cmp, flags);
463 }
This page took 0.039601 seconds and 2 git commands to generate.