1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * LoongArch float point emulation helpers for QEMU
5 * Copyright (c) 2021 Loongson Technology Corporation Limited
8 #include "qemu/osdep.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"
16 #define FLOAT_TO_INT32_OVERFLOW 0x7fffffff
17 #define FLOAT_TO_INT64_OVERFLOW 0x7fffffffffffffffULL
19 static inline uint64_t nanbox_s(float32 fp)
21 return fp | MAKE_64BIT_MASK(32, 32);
24 /* Convert loongarch rounding mode in fcsr0 to IEEE library */
25 static const FloatRoundMode ieee_rm[4] = {
26 float_round_nearest_even,
32 void restore_fp_status(CPULoongArchState *env)
34 set_float_rounding_mode(ieee_rm[(env->fcsr0 >> FCSR0_RM) & 0x3],
36 set_flush_to_zero(0, &env->fp_status);
39 static int ieee_ex_to_loongarch(int xcpt)
42 if (xcpt & float_flag_invalid) {
45 if (xcpt & float_flag_overflow) {
48 if (xcpt & float_flag_underflow) {
51 if (xcpt & float_flag_divbyzero) {
54 if (xcpt & float_flag_inexact) {
60 static void update_fcsr0_mask(CPULoongArchState *env, uintptr_t pc, int mask)
62 int flags = get_float_exception_flags(&env->fp_status);
64 set_float_exception_flags(0, &env->fp_status);
69 SET_FP_CAUSE(env->fcsr0, flags);
72 flags = ieee_ex_to_loongarch(flags);
73 SET_FP_CAUSE(env->fcsr0, flags);
76 if (GET_FP_ENABLES(env->fcsr0) & flags) {
77 do_raise_exception(env, EXCCODE_FPE, pc);
79 UPDATE_FP_FLAGS(env->fcsr0, flags);
83 static void update_fcsr0(CPULoongArchState *env, uintptr_t pc)
85 update_fcsr0_mask(env, pc, 0);
88 uint64_t helper_fadd_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
92 fd = nanbox_s(float32_add((uint32_t)fj, (uint32_t)fk, &env->fp_status));
93 update_fcsr0(env, GETPC());
97 uint64_t helper_fadd_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
101 fd = float64_add(fj, fk, &env->fp_status);
102 update_fcsr0(env, GETPC());
106 uint64_t helper_fsub_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
110 fd = nanbox_s(float32_sub((uint32_t)fj, (uint32_t)fk, &env->fp_status));
111 update_fcsr0(env, GETPC());
115 uint64_t helper_fsub_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
119 fd = float64_sub(fj, fk, &env->fp_status);
120 update_fcsr0(env, GETPC());
124 uint64_t helper_fmul_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
128 fd = nanbox_s(float32_mul((uint32_t)fj, (uint32_t)fk, &env->fp_status));
129 update_fcsr0(env, GETPC());
133 uint64_t helper_fmul_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
137 fd = float64_mul(fj, fk, &env->fp_status);
138 update_fcsr0(env, GETPC());
142 uint64_t helper_fdiv_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
146 fd = nanbox_s(float32_div((uint32_t)fj, (uint32_t)fk, &env->fp_status));
147 update_fcsr0(env, GETPC());
151 uint64_t helper_fdiv_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
155 fd = float64_div(fj, fk, &env->fp_status);
156 update_fcsr0(env, GETPC());
160 uint64_t helper_fmax_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
164 fd = nanbox_s(float32_maxnum((uint32_t)fj, (uint32_t)fk, &env->fp_status));
165 update_fcsr0(env, GETPC());
169 uint64_t helper_fmax_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
173 fd = float64_maxnum(fj, fk, &env->fp_status);
174 update_fcsr0(env, GETPC());
178 uint64_t helper_fmin_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
182 fd = nanbox_s(float32_minnum((uint32_t)fj, (uint32_t)fk, &env->fp_status));
183 update_fcsr0(env, GETPC());
187 uint64_t helper_fmin_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
191 fd = float64_minnum(fj, fk, &env->fp_status);
192 update_fcsr0(env, GETPC());
196 uint64_t helper_fmaxa_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
200 fd = nanbox_s(float32_maxnummag((uint32_t)fj,
201 (uint32_t)fk, &env->fp_status));
202 update_fcsr0(env, GETPC());
206 uint64_t helper_fmaxa_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
210 fd = float64_maxnummag(fj, fk, &env->fp_status);
211 update_fcsr0(env, GETPC());
215 uint64_t helper_fmina_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
219 fd = nanbox_s(float32_minnummag((uint32_t)fj,
220 (uint32_t)fk, &env->fp_status));
221 update_fcsr0(env, GETPC());
225 uint64_t helper_fmina_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
229 fd = float64_minnummag(fj, fk, &env->fp_status);
230 update_fcsr0(env, GETPC());
234 uint64_t helper_fscaleb_s(CPULoongArchState *env, uint64_t fj, uint64_t fk)
237 int32_t n = (int32_t)fk;
239 fd = nanbox_s(float32_scalbn((uint32_t)fj,
241 n < -0x200 ? -0x200 : n,
243 update_fcsr0(env, GETPC());
247 uint64_t helper_fscaleb_d(CPULoongArchState *env, uint64_t fj, uint64_t fk)
250 int64_t n = (int64_t)fk;
252 fd = float64_scalbn(fj,
253 n > 0x1000 ? 0x1000 :
254 n < -0x1000 ? -0x1000 : n,
256 update_fcsr0(env, GETPC());
260 uint64_t helper_fsqrt_s(CPULoongArchState *env, uint64_t fj)
264 fd = nanbox_s(float32_sqrt((uint32_t)fj, &env->fp_status));
265 update_fcsr0(env, GETPC());
269 uint64_t helper_fsqrt_d(CPULoongArchState *env, uint64_t fj)
273 fd = float64_sqrt(fj, &env->fp_status);
274 update_fcsr0(env, GETPC());
278 uint64_t helper_frecip_s(CPULoongArchState *env, uint64_t fj)
282 fd = nanbox_s(float32_div(float32_one, (uint32_t)fj, &env->fp_status));
283 update_fcsr0(env, GETPC());
287 uint64_t helper_frecip_d(CPULoongArchState *env, uint64_t fj)
291 fd = float64_div(float64_one, fj, &env->fp_status);
292 update_fcsr0(env, GETPC());
296 uint64_t helper_frsqrt_s(CPULoongArchState *env, uint64_t fj)
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());
307 uint64_t helper_frsqrt_d(CPULoongArchState *env, uint64_t fj)
311 fp = float64_sqrt(fj, &env->fp_status);
312 fd = float64_div(float64_one, fp, &env->fp_status);
313 update_fcsr0(env, GETPC());
317 uint64_t helper_flogb_s(CPULoongArchState *env, uint64_t fj)
321 float_status *status = &env->fp_status;
322 FloatRoundMode old_mode = get_float_rounding_mode(status);
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);
332 uint64_t helper_flogb_d(CPULoongArchState *env, uint64_t fj)
335 float_status *status = &env->fp_status;
336 FloatRoundMode old_mode = get_float_rounding_mode(status);
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);
346 uint64_t helper_fclass_s(CPULoongArchState *env, uint64_t fj)
349 bool sign = float32_is_neg(f);
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;
361 return sign ? 1 << 3 : 1 << 7;
365 uint64_t helper_fclass_d(CPULoongArchState *env, uint64_t fj)
368 bool sign = float64_is_neg(f);
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;
380 return sign ? 1 << 3 : 1 << 7;
384 uint64_t helper_fmuladd_s(CPULoongArchState *env, uint64_t fj,
385 uint64_t fk, uint64_t fa, uint32_t flag)
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());
395 uint64_t helper_fmuladd_d(CPULoongArchState *env, uint64_t fj,
396 uint64_t fk, uint64_t fa, uint32_t flag)
400 fd = float64_muladd(fj, fk, fa, flag, &env->fp_status);
401 update_fcsr0(env, GETPC());