Commit da1e7ac9d47edd9979df5a41e752679435ea40c9

Authored by aurel32
1 parent 17218d1f

target-ppc: fmadd/fmsub/fmnadd/fmnsub can generate VXIMZ or VXIZI exceptions

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6053 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 52 additions and 12 deletions
target-ppc/op_helper.c
... ... @@ -1295,6 +1295,10 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1295 1295 float64_is_signaling_nan(farg3.d))) {
1296 1296 /* sNaN operation */
1297 1297 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1298 + } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
  1299 + (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
  1300 + /* Multiplication of zero by infinity */
  1301 + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1298 1302 } else {
1299 1303 #ifdef FLOAT128
1300 1304 /* This is the way the PowerPC specification defines it */
... ... @@ -1303,9 +1307,15 @@ uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1303 1307 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1304 1308 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1305 1309 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1306   - ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1307   - ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1308   - farg1.d = float128_to_float64(ft0_128, &env->fp_status);
  1310 + if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
  1311 + float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
  1312 + /* Magnitude subtraction of infinities */
  1313 + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
  1314 + } else {
  1315 + ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
  1316 + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
  1317 + farg1.d = float128_to_float64(ft0_128, &env->fp_status);
  1318 + }
1309 1319 #else
1310 1320 /* This is OK on x86 hosts */
1311 1321 farg1.d = (farg1.d * farg2.d) + farg3.d;
... ... @@ -1332,6 +1342,10 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1332 1342 float64_is_signaling_nan(farg3.d))) {
1333 1343 /* sNaN operation */
1334 1344 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1345 + } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
  1346 + (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
  1347 + /* Multiplication of zero by infinity */
  1348 + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1335 1349 } else {
1336 1350 #ifdef FLOAT128
1337 1351 /* This is the way the PowerPC specification defines it */
... ... @@ -1340,9 +1354,15 @@ uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1340 1354 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1341 1355 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1342 1356 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1343   - ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1344   - ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1345   - farg1.d = float128_to_float64(ft0_128, &env->fp_status);
  1357 + if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
  1358 + float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
  1359 + /* Magnitude subtraction of infinities */
  1360 + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
  1361 + } else {
  1362 + ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
  1363 + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
  1364 + farg1.d = float128_to_float64(ft0_128, &env->fp_status);
  1365 + }
1346 1366 #else
1347 1367 /* This is OK on x86 hosts */
1348 1368 farg1.d = (farg1.d * farg2.d) - farg3.d;
... ... @@ -1369,6 +1389,10 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1369 1389 float64_is_signaling_nan(farg3.d))) {
1370 1390 /* sNaN operation */
1371 1391 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1392 + } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
  1393 + (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
  1394 + /* Multiplication of zero by infinity */
  1395 + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1372 1396 } else {
1373 1397 #if USE_PRECISE_EMULATION
1374 1398 #ifdef FLOAT128
... ... @@ -1378,9 +1402,15 @@ uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1378 1402 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1379 1403 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1380 1404 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1381   - ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1382   - ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1383   - farg1.d= float128_to_float64(ft0_128, &env->fp_status);
  1405 + if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
  1406 + float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
  1407 + /* Magnitude subtraction of infinities */
  1408 + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
  1409 + } else {
  1410 + ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
  1411 + ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
  1412 + farg1.d = float128_to_float64(ft0_128, &env->fp_status);
  1413 + }
1384 1414 #else
1385 1415 /* This is OK on x86 hosts */
1386 1416 farg1.d = (farg1.d * farg2.d) + farg3.d;
... ... @@ -1409,6 +1439,10 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1409 1439 float64_is_signaling_nan(farg3.d))) {
1410 1440 /* sNaN operation */
1411 1441 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
  1442 + } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
  1443 + (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
  1444 + /* Multiplication of zero by infinity */
  1445 + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1412 1446 } else {
1413 1447 #if USE_PRECISE_EMULATION
1414 1448 #ifdef FLOAT128
... ... @@ -1418,9 +1452,15 @@ uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1418 1452 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1419 1453 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1420 1454 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1421   - ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1422   - ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1423   - farg1.d = float128_to_float64(ft0_128, &env->fp_status);
  1455 + if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
  1456 + float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
  1457 + /* Magnitude subtraction of infinities */
  1458 + farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
  1459 + } else {
  1460 + ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
  1461 + ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
  1462 + farg1.d = float128_to_float64(ft0_128, &env->fp_status);
  1463 + }
1424 1464 #else
1425 1465 /* This is OK on x86 hosts */
1426 1466 farg1.d = (farg1.d * farg2.d) - farg3.d;
... ...