]> Git Repo - qemu.git/blame - target/loongarch/fpu_helper.c
target/loongarch: Add floating point comparison instruction translation
[qemu.git] / target / loongarch / fpu_helper.c
CommitLineData
d578ca6c
SG
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
19static 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 */
25static 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
32void 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
39static 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
60static 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
83static void update_fcsr0(CPULoongArchState *env, uintptr_t pc)
84{
85 update_fcsr0_mask(env, pc, 0);
86}
87
88uint64_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
97uint64_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
106uint64_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
115uint64_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
124uint64_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
133uint64_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
142uint64_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
151uint64_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
160uint64_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
169uint64_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
178uint64_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
187uint64_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
196uint64_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
206uint64_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
215uint64_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
225uint64_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
234uint64_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
247uint64_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
260uint64_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
269uint64_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
278uint64_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
287uint64_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
296uint64_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
307uint64_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
317uint64_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
332uint64_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
346uint64_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
365uint64_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
384uint64_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
395uint64_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}
9b741076
SG
404
405static 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 */
432uint64_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 */
441uint64_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 */
450uint64_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 */
458uint64_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.068717 seconds and 4 git commands to generate.