mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-10 11:04:58 -06:00
target/ppc: rewrite f[n]m[add,sub] using float64_muladd
Use the softfloat api for fused multiply-add. Introduce routine to set the FPSCR flags VXNAN, VXIMZ nad VMISI. Signed-off-by: Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
ec975e839c
commit
992d7e976c
1 changed files with 46 additions and 167 deletions
|
@ -743,178 +743,62 @@ uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
|
||||||
return do_fri(env, arg, float_round_down);
|
return do_fri(env, arg, float_round_down);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fmadd - fmadd. */
|
static void float64_maddsub_update_excp(CPUPPCState *env, float64 arg1,
|
||||||
uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
|
float64 arg2, float64 arg3,
|
||||||
uint64_t arg3)
|
unsigned int madd_flags)
|
||||||
{
|
{
|
||||||
CPU_DoubleU farg1, farg2, farg3;
|
if (unlikely((float64_is_infinity(arg1) && float64_is_zero(arg2)) ||
|
||||||
|
(float64_is_zero(arg1) && float64_is_infinity(arg2)))) {
|
||||||
farg1.ll = arg1;
|
|
||||||
farg2.ll = arg2;
|
|
||||||
farg3.ll = arg3;
|
|
||||||
|
|
||||||
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
|
|
||||||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
|
|
||||||
/* Multiplication of zero by infinity */
|
/* Multiplication of zero by infinity */
|
||||||
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
|
arg1 = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
|
||||||
} else {
|
} else if (unlikely(float64_is_signaling_nan(arg1, &env->fp_status) ||
|
||||||
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
|
float64_is_signaling_nan(arg2, &env->fp_status) ||
|
||||||
float64_is_signaling_nan(farg2.d, &env->fp_status) ||
|
float64_is_signaling_nan(arg3, &env->fp_status))) {
|
||||||
float64_is_signaling_nan(farg3.d, &env->fp_status))) {
|
|
||||||
/* sNaN operation */
|
/* sNaN operation */
|
||||||
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
||||||
}
|
} else if ((float64_is_infinity(arg1) || float64_is_infinity(arg2)) &&
|
||||||
/* This is the way the PowerPC specification defines it */
|
float64_is_infinity(arg3)) {
|
||||||
float128 ft0_128, ft1_128;
|
uint8_t aSign, bSign, cSign;
|
||||||
|
|
||||||
ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
|
aSign = float64_is_neg(arg1);
|
||||||
ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
|
bSign = float64_is_neg(arg2);
|
||||||
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
|
cSign = float64_is_neg(arg3);
|
||||||
if (unlikely(float128_is_infinity(ft0_128) &&
|
if (madd_flags & float_muladd_negate_c) {
|
||||||
float64_is_infinity(farg3.d) &&
|
cSign ^= 1;
|
||||||
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
|
}
|
||||||
/* Magnitude subtraction of infinities */
|
if (aSign ^ bSign ^ cSign) {
|
||||||
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
|
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
|
||||||
} else {
|
|
||||||
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
|
|
||||||
ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
|
|
||||||
farg1.d = float128_to_float64(ft0_128, &env->fp_status);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return farg1.ll;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fmsub - fmsub. */
|
#define FPU_FMADD(op, madd_flags) \
|
||||||
uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
|
uint64_t helper_##op(CPUPPCState *env, uint64_t arg1, \
|
||||||
uint64_t arg3)
|
uint64_t arg2, uint64_t arg3) \
|
||||||
{
|
{ \
|
||||||
CPU_DoubleU farg1, farg2, farg3;
|
uint32_t flags; \
|
||||||
|
float64 ret = float64_muladd(arg1, arg2, arg3, madd_flags, \
|
||||||
farg1.ll = arg1;
|
&env->fp_status); \
|
||||||
farg2.ll = arg2;
|
flags = get_float_exception_flags(&env->fp_status); \
|
||||||
farg3.ll = arg3;
|
if (flags) { \
|
||||||
|
if (flags & float_flag_invalid) { \
|
||||||
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
|
float64_maddsub_update_excp(env, arg1, arg2, arg3, \
|
||||||
(float64_is_zero(farg1.d) &&
|
madd_flags); \
|
||||||
float64_is_infinity(farg2.d)))) {
|
} \
|
||||||
/* Multiplication of zero by infinity */
|
float_check_status(env); \
|
||||||
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
|
} \
|
||||||
} else {
|
return ret; \
|
||||||
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
|
|
||||||
float64_is_signaling_nan(farg2.d, &env->fp_status) ||
|
|
||||||
float64_is_signaling_nan(farg3.d, &env->fp_status))) {
|
|
||||||
/* sNaN operation */
|
|
||||||
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
|
||||||
}
|
|
||||||
/* This is the way the PowerPC specification defines it */
|
|
||||||
float128 ft0_128, ft1_128;
|
|
||||||
|
|
||||||
ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
|
|
||||||
ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
|
|
||||||
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
|
|
||||||
if (unlikely(float128_is_infinity(ft0_128) &&
|
|
||||||
float64_is_infinity(farg3.d) &&
|
|
||||||
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
|
|
||||||
/* Magnitude subtraction of infinities */
|
|
||||||
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
|
|
||||||
} else {
|
|
||||||
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
|
|
||||||
ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
|
|
||||||
farg1.d = float128_to_float64(ft0_128, &env->fp_status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return farg1.ll;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fnmadd - fnmadd. */
|
#define MADD_FLGS 0
|
||||||
uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
|
#define MSUB_FLGS float_muladd_negate_c
|
||||||
uint64_t arg3)
|
#define NMADD_FLGS float_muladd_negate_result
|
||||||
{
|
#define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
|
||||||
CPU_DoubleU farg1, farg2, farg3;
|
|
||||||
|
|
||||||
farg1.ll = arg1;
|
FPU_FMADD(fmadd, MADD_FLGS)
|
||||||
farg2.ll = arg2;
|
FPU_FMADD(fnmadd, NMADD_FLGS)
|
||||||
farg3.ll = arg3;
|
FPU_FMADD(fmsub, MSUB_FLGS)
|
||||||
|
FPU_FMADD(fnmsub, NMSUB_FLGS)
|
||||||
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
|
|
||||||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
|
|
||||||
/* Multiplication of zero by infinity */
|
|
||||||
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
|
|
||||||
} else {
|
|
||||||
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
|
|
||||||
float64_is_signaling_nan(farg2.d, &env->fp_status) ||
|
|
||||||
float64_is_signaling_nan(farg3.d, &env->fp_status))) {
|
|
||||||
/* sNaN operation */
|
|
||||||
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
|
||||||
}
|
|
||||||
/* This is the way the PowerPC specification defines it */
|
|
||||||
float128 ft0_128, ft1_128;
|
|
||||||
|
|
||||||
ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
|
|
||||||
ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
|
|
||||||
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
|
|
||||||
if (unlikely(float128_is_infinity(ft0_128) &&
|
|
||||||
float64_is_infinity(farg3.d) &&
|
|
||||||
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
|
|
||||||
/* Magnitude subtraction of infinities */
|
|
||||||
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
|
|
||||||
} else {
|
|
||||||
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
|
|
||||||
ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
|
|
||||||
farg1.d = float128_to_float64(ft0_128, &env->fp_status);
|
|
||||||
}
|
|
||||||
if (likely(!float64_is_any_nan(farg1.d))) {
|
|
||||||
farg1.d = float64_chs(farg1.d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return farg1.ll;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fnmsub - fnmsub. */
|
|
||||||
uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
|
|
||||||
uint64_t arg3)
|
|
||||||
{
|
|
||||||
CPU_DoubleU farg1, farg2, farg3;
|
|
||||||
|
|
||||||
farg1.ll = arg1;
|
|
||||||
farg2.ll = arg2;
|
|
||||||
farg3.ll = arg3;
|
|
||||||
|
|
||||||
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
|
|
||||||
(float64_is_zero(farg1.d) &&
|
|
||||||
float64_is_infinity(farg2.d)))) {
|
|
||||||
/* Multiplication of zero by infinity */
|
|
||||||
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
|
|
||||||
} else {
|
|
||||||
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
|
|
||||||
float64_is_signaling_nan(farg2.d, &env->fp_status) ||
|
|
||||||
float64_is_signaling_nan(farg3.d, &env->fp_status))) {
|
|
||||||
/* sNaN operation */
|
|
||||||
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
|
||||||
}
|
|
||||||
/* This is the way the PowerPC specification defines it */
|
|
||||||
float128 ft0_128, ft1_128;
|
|
||||||
|
|
||||||
ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
|
|
||||||
ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
|
|
||||||
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
|
|
||||||
if (unlikely(float128_is_infinity(ft0_128) &&
|
|
||||||
float64_is_infinity(farg3.d) &&
|
|
||||||
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
|
|
||||||
/* Magnitude subtraction of infinities */
|
|
||||||
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
|
|
||||||
} else {
|
|
||||||
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
|
|
||||||
ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
|
|
||||||
farg1.d = float128_to_float64(ft0_128, &env->fp_status);
|
|
||||||
}
|
|
||||||
if (likely(!float64_is_any_nan(farg1.d))) {
|
|
||||||
farg1.d = float64_chs(farg1.d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return farg1.ll;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* frsp - frsp. */
|
/* frsp - frsp. */
|
||||||
uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
|
uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
|
||||||
|
@ -2384,11 +2268,6 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
|
||||||
float_check_status(env); \
|
float_check_status(env); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MADD_FLGS 0
|
|
||||||
#define MSUB_FLGS float_muladd_negate_c
|
|
||||||
#define NMADD_FLGS float_muladd_negate_result
|
|
||||||
#define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
|
|
||||||
|
|
||||||
VSX_MADD(xsmaddadp, 1, float64, VsrD(0), MADD_FLGS, 1, 1, 0)
|
VSX_MADD(xsmaddadp, 1, float64, VsrD(0), MADD_FLGS, 1, 1, 0)
|
||||||
VSX_MADD(xsmaddmdp, 1, float64, VsrD(0), MADD_FLGS, 0, 1, 0)
|
VSX_MADD(xsmaddmdp, 1, float64, VsrD(0), MADD_FLGS, 0, 1, 0)
|
||||||
VSX_MADD(xsmsubadp, 1, float64, VsrD(0), MSUB_FLGS, 1, 1, 0)
|
VSX_MADD(xsmsubadp, 1, float64, VsrD(0), MSUB_FLGS, 1, 1, 0)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue