diff options
| author | 2016-05-16 10:55:00 +0200 | |
|---|---|---|
| committer | 2016-05-18 15:24:42 +0200 | |
| commit | 7dde13f87544c59807436e2eefe0f1b65fad841c (patch) | |
| tree | 2cace6621980d9499decddee45ba9fc3e0617061 /src/core/arm/skyeye_common | |
| parent | Merge pull request #1814 from JayFoxRox/fix-read-after-write (diff) | |
| download | yuzu-7dde13f87544c59807436e2eefe0f1b65fad841c.tar.gz yuzu-7dde13f87544c59807436e2eefe0f1b65fad841c.tar.xz yuzu-7dde13f87544c59807436e2eefe0f1b65fad841c.zip | |
Fix exception propagation for VFP double precision
Diffstat (limited to 'src/core/arm/skyeye_common')
| -rw-r--r-- | src/core/arm/skyeye_common/vfp/vfp_helper.h | 8 | ||||
| -rw-r--r-- | src/core/arm/skyeye_common/vfp/vfpdouble.cpp | 65 |
2 files changed, 39 insertions, 34 deletions
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h index 210972917..c1cc4fd7e 100644 --- a/src/core/arm/skyeye_common/vfp/vfp_helper.h +++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h | |||
| @@ -357,8 +357,9 @@ inline int vfp_double_type(const vfp_double* s) | |||
| 357 | // Unpack a double-precision float. Note that this returns the magnitude | 357 | // Unpack a double-precision float. Note that this returns the magnitude |
| 358 | // of the double-precision float mantissa with the 1. if necessary, | 358 | // of the double-precision float mantissa with the 1. if necessary, |
| 359 | // aligned to bit 62. | 359 | // aligned to bit 62. |
| 360 | inline void vfp_double_unpack(vfp_double* s, s64 val, u32* fpscr) | 360 | inline u32 vfp_double_unpack(vfp_double* s, s64 val, u32 fpscr) |
| 361 | { | 361 | { |
| 362 | u32 exceptions = 0; | ||
| 362 | s->sign = vfp_double_packed_sign(val) >> 48; | 363 | s->sign = vfp_double_packed_sign(val) >> 48; |
| 363 | s->exponent = vfp_double_packed_exponent(val); | 364 | s->exponent = vfp_double_packed_exponent(val); |
| 364 | 365 | ||
| @@ -369,12 +370,13 @@ inline void vfp_double_unpack(vfp_double* s, s64 val, u32* fpscr) | |||
| 369 | 370 | ||
| 370 | // If flush-to-zero mode is enabled, turn the denormal into zero. | 371 | // If flush-to-zero mode is enabled, turn the denormal into zero. |
| 371 | // On a VFPv2 architecture, the sign of the zero is always positive. | 372 | // On a VFPv2 architecture, the sign of the zero is always positive. |
| 372 | if ((*fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_double_type(s) & VFP_DENORMAL) != 0) { | 373 | if ((fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_double_type(s) & VFP_DENORMAL) != 0) { |
| 373 | s->sign = 0; | 374 | s->sign = 0; |
| 374 | s->exponent = 0; | 375 | s->exponent = 0; |
| 375 | s->significand = 0; | 376 | s->significand = 0; |
| 376 | *fpscr |= FPSCR_IDC; | 377 | exceptions |= FPSCR_IDC; |
| 377 | } | 378 | } |
| 379 | return exceptions; | ||
| 378 | } | 380 | } |
| 379 | 381 | ||
| 380 | // Re-pack a double-precision float. This assumes that the float is | 382 | // Re-pack a double-precision float. This assumes that the float is |
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp index 45914d479..0182b90b8 100644 --- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp | |||
| @@ -291,8 +291,9 @@ static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 | |||
| 291 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); | 291 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 292 | vfp_double vdm, vdd, *vdp; | 292 | vfp_double vdm, vdd, *vdp; |
| 293 | int ret, tm; | 293 | int ret, tm; |
| 294 | u32 exceptions = 0; | ||
| 294 | 295 | ||
| 295 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 296 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); |
| 296 | 297 | ||
| 297 | tm = vfp_double_type(&vdm); | 298 | tm = vfp_double_type(&vdm); |
| 298 | if (tm & (VFP_NAN|VFP_INFINITY)) { | 299 | if (tm & (VFP_NAN|VFP_INFINITY)) { |
| @@ -369,7 +370,9 @@ sqrt_invalid: | |||
| 369 | } | 370 | } |
| 370 | vdd.significand = vfp_shiftright64jamming(vdd.significand, 1); | 371 | vdd.significand = vfp_shiftright64jamming(vdd.significand, 1); |
| 371 | 372 | ||
| 372 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt"); | 373 | exceptions |= vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt"); |
| 374 | |||
| 375 | return exceptions; | ||
| 373 | } | 376 | } |
| 374 | 377 | ||
| 375 | /* | 378 | /* |
| @@ -475,7 +478,7 @@ static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 475 | u32 exceptions = 0; | 478 | u32 exceptions = 0; |
| 476 | 479 | ||
| 477 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); | 480 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 478 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 481 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); |
| 479 | 482 | ||
| 480 | tm = vfp_double_type(&vdm); | 483 | tm = vfp_double_type(&vdm); |
| 481 | 484 | ||
| @@ -545,7 +548,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 545 | int tm; | 548 | int tm; |
| 546 | 549 | ||
| 547 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); | 550 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 548 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 551 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); |
| 549 | 552 | ||
| 550 | /* | 553 | /* |
| 551 | * Do we have a denormalised number? | 554 | * Do we have a denormalised number? |
| @@ -626,7 +629,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 626 | int tm; | 629 | int tm; |
| 627 | 630 | ||
| 628 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); | 631 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 629 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 632 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); |
| 630 | vfp_double_dump("VDM", &vdm); | 633 | vfp_double_dump("VDM", &vdm); |
| 631 | 634 | ||
| 632 | /* | 635 | /* |
| @@ -892,21 +895,21 @@ static u32 | |||
| 892 | vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, const char *func) | 895 | vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, const char *func) |
| 893 | { | 896 | { |
| 894 | struct vfp_double vdd, vdp, vdn, vdm; | 897 | struct vfp_double vdd, vdp, vdn, vdm; |
| 895 | u32 exceptions; | 898 | u32 exceptions = 0; |
| 896 | 899 | ||
| 897 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 900 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); |
| 898 | if (vdn.exponent == 0 && vdn.significand) | 901 | if (vdn.exponent == 0 && vdn.significand) |
| 899 | vfp_double_normalise_denormal(&vdn); | 902 | vfp_double_normalise_denormal(&vdn); |
| 900 | 903 | ||
| 901 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 904 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); |
| 902 | if (vdm.exponent == 0 && vdm.significand) | 905 | if (vdm.exponent == 0 && vdm.significand) |
| 903 | vfp_double_normalise_denormal(&vdm); | 906 | vfp_double_normalise_denormal(&vdm); |
| 904 | 907 | ||
| 905 | exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr); | 908 | exceptions |= vfp_double_multiply(&vdp, &vdn, &vdm, fpscr); |
| 906 | if (negate & NEG_MULTIPLY) | 909 | if (negate & NEG_MULTIPLY) |
| 907 | vdp.sign = vfp_sign_negate(vdp.sign); | 910 | vdp.sign = vfp_sign_negate(vdp.sign); |
| 908 | 911 | ||
| 909 | vfp_double_unpack(&vdn, vfp_get_double(state, dd), &fpscr); | 912 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dd), fpscr); |
| 910 | if (vdn.exponent == 0 && vdn.significand != 0) | 913 | if (vdn.exponent == 0 && vdn.significand != 0) |
| 911 | vfp_double_normalise_denormal(&vdn); | 914 | vfp_double_normalise_denormal(&vdn); |
| 912 | 915 | ||
| @@ -964,18 +967,18 @@ static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpsc | |||
| 964 | static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | 967 | static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) |
| 965 | { | 968 | { |
| 966 | struct vfp_double vdd, vdn, vdm; | 969 | struct vfp_double vdd, vdn, vdm; |
| 967 | u32 exceptions; | 970 | u32 exceptions = 0; |
| 968 | 971 | ||
| 969 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); | 972 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 970 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 973 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); |
| 971 | if (vdn.exponent == 0 && vdn.significand) | 974 | if (vdn.exponent == 0 && vdn.significand) |
| 972 | vfp_double_normalise_denormal(&vdn); | 975 | vfp_double_normalise_denormal(&vdn); |
| 973 | 976 | ||
| 974 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 977 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); |
| 975 | if (vdm.exponent == 0 && vdm.significand) | 978 | if (vdm.exponent == 0 && vdm.significand) |
| 976 | vfp_double_normalise_denormal(&vdm); | 979 | vfp_double_normalise_denormal(&vdm); |
| 977 | 980 | ||
| 978 | exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); | 981 | exceptions |= vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); |
| 979 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul"); | 982 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul"); |
| 980 | } | 983 | } |
| 981 | 984 | ||
| @@ -985,18 +988,18 @@ static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 985 | static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | 988 | static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) |
| 986 | { | 989 | { |
| 987 | struct vfp_double vdd, vdn, vdm; | 990 | struct vfp_double vdd, vdn, vdm; |
| 988 | u32 exceptions; | 991 | u32 exceptions = 0; |
| 989 | 992 | ||
| 990 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); | 993 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 991 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 994 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); |
| 992 | if (vdn.exponent == 0 && vdn.significand) | 995 | if (vdn.exponent == 0 && vdn.significand) |
| 993 | vfp_double_normalise_denormal(&vdn); | 996 | vfp_double_normalise_denormal(&vdn); |
| 994 | 997 | ||
| 995 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 998 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); |
| 996 | if (vdm.exponent == 0 && vdm.significand) | 999 | if (vdm.exponent == 0 && vdm.significand) |
| 997 | vfp_double_normalise_denormal(&vdm); | 1000 | vfp_double_normalise_denormal(&vdm); |
| 998 | 1001 | ||
| 999 | exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); | 1002 | exceptions |= vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); |
| 1000 | vdd.sign = vfp_sign_negate(vdd.sign); | 1003 | vdd.sign = vfp_sign_negate(vdd.sign); |
| 1001 | 1004 | ||
| 1002 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul"); | 1005 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul"); |
| @@ -1008,18 +1011,18 @@ static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpsc | |||
| 1008 | static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | 1011 | static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) |
| 1009 | { | 1012 | { |
| 1010 | struct vfp_double vdd, vdn, vdm; | 1013 | struct vfp_double vdd, vdn, vdm; |
| 1011 | u32 exceptions; | 1014 | u32 exceptions = 0; |
| 1012 | 1015 | ||
| 1013 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); | 1016 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 1014 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 1017 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); |
| 1015 | if (vdn.exponent == 0 && vdn.significand) | 1018 | if (vdn.exponent == 0 && vdn.significand) |
| 1016 | vfp_double_normalise_denormal(&vdn); | 1019 | vfp_double_normalise_denormal(&vdn); |
| 1017 | 1020 | ||
| 1018 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 1021 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); |
| 1019 | if (vdm.exponent == 0 && vdm.significand) | 1022 | if (vdm.exponent == 0 && vdm.significand) |
| 1020 | vfp_double_normalise_denormal(&vdm); | 1023 | vfp_double_normalise_denormal(&vdm); |
| 1021 | 1024 | ||
| 1022 | exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); | 1025 | exceptions |= vfp_double_add(&vdd, &vdn, &vdm, fpscr); |
| 1023 | 1026 | ||
| 1024 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd"); | 1027 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd"); |
| 1025 | } | 1028 | } |
| @@ -1030,14 +1033,14 @@ static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 1030 | static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | 1033 | static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) |
| 1031 | { | 1034 | { |
| 1032 | struct vfp_double vdd, vdn, vdm; | 1035 | struct vfp_double vdd, vdn, vdm; |
| 1033 | u32 exceptions; | 1036 | u32 exceptions = 0; |
| 1034 | 1037 | ||
| 1035 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); | 1038 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 1036 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 1039 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); |
| 1037 | if (vdn.exponent == 0 && vdn.significand) | 1040 | if (vdn.exponent == 0 && vdn.significand) |
| 1038 | vfp_double_normalise_denormal(&vdn); | 1041 | vfp_double_normalise_denormal(&vdn); |
| 1039 | 1042 | ||
| 1040 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 1043 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); |
| 1041 | if (vdm.exponent == 0 && vdm.significand) | 1044 | if (vdm.exponent == 0 && vdm.significand) |
| 1042 | vfp_double_normalise_denormal(&vdm); | 1045 | vfp_double_normalise_denormal(&vdm); |
| 1043 | 1046 | ||
| @@ -1046,7 +1049,7 @@ static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 1046 | */ | 1049 | */ |
| 1047 | vdm.sign = vfp_sign_negate(vdm.sign); | 1050 | vdm.sign = vfp_sign_negate(vdm.sign); |
| 1048 | 1051 | ||
| 1049 | exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); | 1052 | exceptions |= vfp_double_add(&vdd, &vdn, &vdm, fpscr); |
| 1050 | 1053 | ||
| 1051 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub"); | 1054 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub"); |
| 1052 | } | 1055 | } |
| @@ -1061,8 +1064,8 @@ static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 1061 | int tm, tn; | 1064 | int tm, tn; |
| 1062 | 1065 | ||
| 1063 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); | 1066 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 1064 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 1067 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); |
| 1065 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 1068 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); |
| 1066 | 1069 | ||
| 1067 | vdd.sign = vdn.sign ^ vdm.sign; | 1070 | vdd.sign = vdn.sign ^ vdm.sign; |
| 1068 | 1071 | ||
| @@ -1134,13 +1137,13 @@ static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 1134 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv"); | 1137 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv"); |
| 1135 | 1138 | ||
| 1136 | vdn_nan: | 1139 | vdn_nan: |
| 1137 | exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr); | 1140 | exceptions |= vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr); |
| 1138 | pack: | 1141 | pack: |
| 1139 | vfp_put_double(state, vfp_double_pack(&vdd), dd); | 1142 | vfp_put_double(state, vfp_double_pack(&vdd), dd); |
| 1140 | return exceptions; | 1143 | return exceptions; |
| 1141 | 1144 | ||
| 1142 | vdm_nan: | 1145 | vdm_nan: |
| 1143 | exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr); | 1146 | exceptions |= vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr); |
| 1144 | goto pack; | 1147 | goto pack; |
| 1145 | 1148 | ||
| 1146 | zero: | 1149 | zero: |
| @@ -1149,7 +1152,7 @@ zero: | |||
| 1149 | goto pack; | 1152 | goto pack; |
| 1150 | 1153 | ||
| 1151 | divzero: | 1154 | divzero: |
| 1152 | exceptions = FPSCR_DZC; | 1155 | exceptions |= FPSCR_DZC; |
| 1153 | infinity: | 1156 | infinity: |
| 1154 | vdd.exponent = 2047; | 1157 | vdd.exponent = 2047; |
| 1155 | vdd.significand = 0; | 1158 | vdd.significand = 0; |