Commit da1e7ac9d47edd9979df5a41e752679435ea40c9
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; | ... | ... |