OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <limits.h> | 5 #include <limits.h> |
6 #include <stdarg.h> | 6 #include <stdarg.h> |
7 #include <stdlib.h> | 7 #include <stdlib.h> |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "src/v8.h" | 10 #include "src/v8.h" |
(...skipping 1170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1181 FCSR_ &= ~(1 << cc); | 1181 FCSR_ &= ~(1 << cc); |
1182 } | 1182 } |
1183 } | 1183 } |
1184 | 1184 |
1185 | 1185 |
1186 bool Simulator::test_fcsr_bit(uint32_t cc) { | 1186 bool Simulator::test_fcsr_bit(uint32_t cc) { |
1187 return FCSR_ & (1 << cc); | 1187 return FCSR_ & (1 << cc); |
1188 } | 1188 } |
1189 | 1189 |
1190 | 1190 |
| 1191 void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) { |
| 1192 FCSR_ |= mode & kFPURoundingModeMask; |
| 1193 } |
| 1194 |
| 1195 |
| 1196 unsigned int Simulator::get_fcsr_rounding_mode() { |
| 1197 return FCSR_ & kFPURoundingModeMask; |
| 1198 } |
| 1199 |
| 1200 |
1191 // Sets the rounding error codes in FCSR based on the result of the rounding. | 1201 // Sets the rounding error codes in FCSR based on the result of the rounding. |
1192 // Returns true if the operation was invalid. | 1202 // Returns true if the operation was invalid. |
1193 bool Simulator::set_fcsr_round_error(double original, double rounded) { | 1203 bool Simulator::set_fcsr_round_error(double original, double rounded) { |
1194 bool ret = false; | 1204 bool ret = false; |
1195 double max_int32 = std::numeric_limits<int32_t>::max(); | 1205 double max_int32 = std::numeric_limits<int32_t>::max(); |
1196 double min_int32 = std::numeric_limits<int32_t>::min(); | 1206 double min_int32 = std::numeric_limits<int32_t>::min(); |
1197 | 1207 |
1198 if (!std::isfinite(original) || !std::isfinite(rounded)) { | 1208 if (!std::isfinite(original) || !std::isfinite(rounded)) { |
1199 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); | 1209 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); |
1200 ret = true; | 1210 ret = true; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1245 set_fcsr_bit(kFCSROverflowFlagBit, true); | 1255 set_fcsr_bit(kFCSROverflowFlagBit, true); |
1246 // The reference is not really clear but it seems this is required: | 1256 // The reference is not really clear but it seems this is required: |
1247 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); | 1257 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); |
1248 ret = true; | 1258 ret = true; |
1249 } | 1259 } |
1250 | 1260 |
1251 return ret; | 1261 return ret; |
1252 } | 1262 } |
1253 | 1263 |
1254 | 1264 |
| 1265 bool Simulator::set_fcsr_round_error(float original, float rounded) { |
| 1266 bool ret = false; |
| 1267 double max_int32 = std::numeric_limits<int32_t>::max(); |
| 1268 double min_int32 = std::numeric_limits<int32_t>::min(); |
| 1269 |
| 1270 if (!std::isfinite(original) || !std::isfinite(rounded)) { |
| 1271 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); |
| 1272 ret = true; |
| 1273 } |
| 1274 |
| 1275 if (original != rounded) { |
| 1276 set_fcsr_bit(kFCSRInexactFlagBit, true); |
| 1277 } |
| 1278 |
| 1279 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) { |
| 1280 set_fcsr_bit(kFCSRUnderflowFlagBit, true); |
| 1281 ret = true; |
| 1282 } |
| 1283 |
| 1284 if (rounded > max_int32 || rounded < min_int32) { |
| 1285 set_fcsr_bit(kFCSROverflowFlagBit, true); |
| 1286 // The reference is not really clear but it seems this is required: |
| 1287 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); |
| 1288 ret = true; |
| 1289 } |
| 1290 |
| 1291 return ret; |
| 1292 } |
| 1293 |
| 1294 |
| 1295 // Sets the rounding error codes in FCSR based on the result of the rounding. |
| 1296 // Returns true if the operation was invalid. |
| 1297 bool Simulator::set_fcsr_round64_error(float original, float rounded) { |
| 1298 bool ret = false; |
| 1299 double max_int64 = std::numeric_limits<int64_t>::max(); |
| 1300 double min_int64 = std::numeric_limits<int64_t>::min(); |
| 1301 |
| 1302 if (!std::isfinite(original) || !std::isfinite(rounded)) { |
| 1303 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); |
| 1304 ret = true; |
| 1305 } |
| 1306 |
| 1307 if (original != rounded) { |
| 1308 set_fcsr_bit(kFCSRInexactFlagBit, true); |
| 1309 } |
| 1310 |
| 1311 if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) { |
| 1312 set_fcsr_bit(kFCSRUnderflowFlagBit, true); |
| 1313 ret = true; |
| 1314 } |
| 1315 |
| 1316 if (rounded > max_int64 || rounded < min_int64) { |
| 1317 set_fcsr_bit(kFCSROverflowFlagBit, true); |
| 1318 // The reference is not really clear but it seems this is required: |
| 1319 set_fcsr_bit(kFCSRInvalidOpFlagBit, true); |
| 1320 ret = true; |
| 1321 } |
| 1322 |
| 1323 return ret; |
| 1324 } |
| 1325 |
| 1326 |
1255 // for cvt instructions only | 1327 // for cvt instructions only |
1256 void Simulator::round_according_to_fcsr(double toRound, double& rounded, | 1328 void Simulator::round_according_to_fcsr(double toRound, double& rounded, |
1257 int32_t& rounded_int, double fs) { | 1329 int32_t& rounded_int, double fs) { |
1258 // 0 RN (round to nearest): Round a result to the nearest | 1330 // 0 RN (round to nearest): Round a result to the nearest |
1259 // representable value; if the result is exactly halfway between | 1331 // representable value; if the result is exactly halfway between |
1260 // two representable values, round to zero. Behave like round_w_d. | 1332 // two representable values, round to zero. Behave like round_w_d. |
1261 | 1333 |
1262 // 1 RZ (round toward zero): Round a result to the closest | 1334 // 1 RZ (round toward zero): Round a result to the closest |
1263 // representable value whose absolute value is less than or | 1335 // representable value whose absolute value is less than or |
1264 // equal to the infinitely accurate result. Behave like trunc_w_d. | 1336 // equal to the infinitely accurate result. Behave like trunc_w_d. |
(...skipping 1084 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2349 default: | 2421 default: |
2350 UNREACHABLE(); | 2422 UNREACHABLE(); |
2351 } | 2423 } |
2352 } | 2424 } |
2353 | 2425 |
2354 | 2426 |
2355 void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, | 2427 void Simulator::DecodeTypeRegisterSRsType(Instruction* instr, |
2356 const int32_t& fs_reg, | 2428 const int32_t& fs_reg, |
2357 const int32_t& ft_reg, | 2429 const int32_t& ft_reg, |
2358 const int32_t& fd_reg) { | 2430 const int32_t& fd_reg) { |
2359 float fs, ft; | 2431 float fs, ft, fd; |
2360 fs = get_fpu_register_float(fs_reg); | 2432 fs = get_fpu_register_float(fs_reg); |
2361 ft = get_fpu_register_float(ft_reg); | 2433 ft = get_fpu_register_float(ft_reg); |
| 2434 fd = get_fpu_register_float(fd_reg); |
| 2435 int32_t ft_int = bit_cast<int32_t>(ft); |
| 2436 int32_t fd_int = bit_cast<int32_t>(fd); |
2362 uint32_t cc, fcsr_cc; | 2437 uint32_t cc, fcsr_cc; |
2363 cc = instr->FCccValue(); | 2438 cc = instr->FCccValue(); |
2364 fcsr_cc = get_fcsr_condition_bit(cc); | 2439 fcsr_cc = get_fcsr_condition_bit(cc); |
2365 switch (instr->FunctionFieldRaw()) { | 2440 switch (instr->FunctionFieldRaw()) { |
2366 case ADD_D: | 2441 case RINT: { |
| 2442 DCHECK(kArchVariant == kMips64r6); |
| 2443 float result, temp_result; |
| 2444 double temp; |
| 2445 float upper = std::ceil(fs); |
| 2446 float lower = std::floor(fs); |
| 2447 switch (get_fcsr_rounding_mode()) { |
| 2448 case kRoundToNearest: |
| 2449 if (upper - fs < fs - lower) { |
| 2450 result = upper; |
| 2451 } else if (upper - fs > fs - lower) { |
| 2452 result = lower; |
| 2453 } else { |
| 2454 temp_result = upper / 2; |
| 2455 float reminder = modf(temp_result, &temp); |
| 2456 if (reminder == 0) { |
| 2457 result = upper; |
| 2458 } else { |
| 2459 result = lower; |
| 2460 } |
| 2461 } |
| 2462 break; |
| 2463 case kRoundToZero: |
| 2464 result = (fs > 0 ? lower : upper); |
| 2465 break; |
| 2466 case kRoundToPlusInf: |
| 2467 result = upper; |
| 2468 break; |
| 2469 case kRoundToMinusInf: |
| 2470 result = lower; |
| 2471 break; |
| 2472 } |
| 2473 set_fpu_register_float(fd_reg, result); |
| 2474 if (result != fs) { |
| 2475 set_fcsr_bit(kFCSRInexactFlagBit, true); |
| 2476 } |
| 2477 break; |
| 2478 } |
| 2479 case ADD_S: |
2367 set_fpu_register_float(fd_reg, fs + ft); | 2480 set_fpu_register_float(fd_reg, fs + ft); |
2368 break; | 2481 break; |
2369 case SUB_D: | 2482 case SUB_S: |
2370 set_fpu_register_float(fd_reg, fs - ft); | 2483 set_fpu_register_float(fd_reg, fs - ft); |
2371 break; | 2484 break; |
2372 case MUL_D: | 2485 case MUL_S: |
2373 set_fpu_register_float(fd_reg, fs * ft); | 2486 set_fpu_register_float(fd_reg, fs * ft); |
2374 break; | 2487 break; |
2375 case DIV_D: | 2488 case DIV_S: |
2376 set_fpu_register_float(fd_reg, fs / ft); | 2489 set_fpu_register_float(fd_reg, fs / ft); |
2377 break; | 2490 break; |
2378 case ABS_D: | 2491 case ABS_S: |
2379 set_fpu_register_float(fd_reg, fabs(fs)); | 2492 set_fpu_register_float(fd_reg, fabs(fs)); |
2380 break; | 2493 break; |
2381 case MOV_D: | 2494 case MOV_S: |
2382 set_fpu_register_float(fd_reg, fs); | 2495 set_fpu_register_float(fd_reg, fs); |
2383 break; | 2496 break; |
2384 case NEG_D: | 2497 case NEG_S: |
2385 set_fpu_register_float(fd_reg, -fs); | 2498 set_fpu_register_float(fd_reg, -fs); |
2386 break; | 2499 break; |
2387 case SQRT_D: | 2500 case SQRT_S: |
2388 set_fpu_register_float(fd_reg, fast_sqrt(fs)); | 2501 set_fpu_register_float(fd_reg, fast_sqrt(fs)); |
2389 break; | 2502 break; |
| 2503 case RSQRT_S: { |
| 2504 float result = 1.0 / fast_sqrt(fs); |
| 2505 set_fpu_register_float(fd_reg, result); |
| 2506 break; |
| 2507 } |
| 2508 case RECIP_S: { |
| 2509 float result = 1.0 / fs; |
| 2510 set_fpu_register_float(fd_reg, result); |
| 2511 break; |
| 2512 } |
2390 case C_UN_D: | 2513 case C_UN_D: |
2391 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft)); | 2514 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft)); |
2392 break; | 2515 break; |
2393 case C_EQ_D: | 2516 case C_EQ_D: |
2394 set_fcsr_bit(fcsr_cc, (fs == ft)); | 2517 set_fcsr_bit(fcsr_cc, (fs == ft)); |
2395 break; | 2518 break; |
2396 case C_UEQ_D: | 2519 case C_UEQ_D: |
2397 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft))); | 2520 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft))); |
2398 break; | 2521 break; |
2399 case C_OLT_D: | 2522 case C_OLT_D: |
2400 set_fcsr_bit(fcsr_cc, (fs < ft)); | 2523 set_fcsr_bit(fcsr_cc, (fs < ft)); |
2401 break; | 2524 break; |
2402 case C_ULT_D: | 2525 case C_ULT_D: |
2403 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft))); | 2526 set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft))); |
2404 break; | 2527 break; |
2405 case C_OLE_D: | 2528 case C_OLE_D: |
2406 set_fcsr_bit(fcsr_cc, (fs <= ft)); | 2529 set_fcsr_bit(fcsr_cc, (fs <= ft)); |
2407 break; | 2530 break; |
2408 case C_ULE_D: | 2531 case C_ULE_D: |
2409 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft))); | 2532 set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft))); |
2410 break; | 2533 break; |
2411 case CVT_D_S: | 2534 case CVT_D_S: |
2412 set_fpu_register_double(fd_reg, static_cast<double>(fs)); | 2535 set_fpu_register_double(fd_reg, static_cast<double>(fs)); |
2413 break; | 2536 break; |
| 2537 case TRUNC_W_S: { // Truncate single to word (round towards 0). |
| 2538 float rounded = trunc(fs); |
| 2539 int32_t result = static_cast<int32_t>(rounded); |
| 2540 set_fpu_register_word(fd_reg, result); |
| 2541 if (set_fcsr_round_error(fs, rounded)) { |
| 2542 set_fpu_register_word(fd_reg, kFPUInvalidResult); |
| 2543 } |
| 2544 } break; |
| 2545 case TRUNC_L_S: { // Mips64r2 instruction. |
| 2546 float rounded = trunc(fs); |
| 2547 int64_t result = static_cast<int64_t>(rounded); |
| 2548 set_fpu_register(fd_reg, result); |
| 2549 if (set_fcsr_round64_error(fs, rounded)) { |
| 2550 set_fpu_register(fd_reg, kFPU64InvalidResult); |
| 2551 } |
| 2552 break; |
| 2553 } |
| 2554 case ROUND_W_S: { |
| 2555 float rounded = std::floor(fs + 0.5); |
| 2556 int32_t result = static_cast<int32_t>(rounded); |
| 2557 if ((result & 1) != 0 && result - fs == 0.5) { |
| 2558 // If the number is halfway between two integers, |
| 2559 // round to the even one. |
| 2560 result--; |
| 2561 } |
| 2562 set_fpu_register_word(fd_reg, result); |
| 2563 if (set_fcsr_round_error(fs, rounded)) { |
| 2564 set_fpu_register_word(fd_reg, kFPUInvalidResult); |
| 2565 } |
| 2566 break; |
| 2567 } |
| 2568 case ROUND_L_S: { // Mips64r2 instruction. |
| 2569 float rounded = std::floor(fs + 0.5); |
| 2570 int64_t result = static_cast<int64_t>(rounded); |
| 2571 if ((result & 1) != 0 && result - fs == 0.5) { |
| 2572 // If the number is halfway between two integers, |
| 2573 // round to the even one. |
| 2574 result--; |
| 2575 } |
| 2576 int64_t i64 = static_cast<int64_t>(result); |
| 2577 set_fpu_register(fd_reg, i64); |
| 2578 if (set_fcsr_round64_error(fs, rounded)) { |
| 2579 set_fpu_register(fd_reg, kFPU64InvalidResult); |
| 2580 } |
| 2581 break; |
| 2582 } |
| 2583 case FLOOR_L_S: { // Mips64r2 instruction. |
| 2584 float rounded = floor(fs); |
| 2585 int64_t result = static_cast<int64_t>(rounded); |
| 2586 set_fpu_register(fd_reg, result); |
| 2587 if (set_fcsr_round64_error(fs, rounded)) { |
| 2588 set_fpu_register(fd_reg, kFPU64InvalidResult); |
| 2589 } |
| 2590 break; |
| 2591 } |
| 2592 case FLOOR_W_S: // Round double to word towards negative infinity. |
| 2593 { |
| 2594 float rounded = std::floor(fs); |
| 2595 int32_t result = static_cast<int32_t>(rounded); |
| 2596 set_fpu_register_word(fd_reg, result); |
| 2597 if (set_fcsr_round_error(fs, rounded)) { |
| 2598 set_fpu_register_word(fd_reg, kFPUInvalidResult); |
| 2599 } |
| 2600 } break; |
| 2601 case CEIL_W_S: // Round double to word towards positive infinity. |
| 2602 { |
| 2603 float rounded = std::ceil(fs); |
| 2604 int32_t result = static_cast<int32_t>(rounded); |
| 2605 set_fpu_register_word(fd_reg, result); |
| 2606 if (set_fcsr_round_error(fs, rounded)) { |
| 2607 set_fpu_register(fd_reg, kFPUInvalidResult); |
| 2608 } |
| 2609 } break; |
| 2610 case CEIL_L_S: { // Mips64r2 instruction. |
| 2611 float rounded = ceil(fs); |
| 2612 int64_t result = static_cast<int64_t>(rounded); |
| 2613 set_fpu_register(fd_reg, result); |
| 2614 if (set_fcsr_round64_error(fs, rounded)) { |
| 2615 set_fpu_register(fd_reg, kFPU64InvalidResult); |
| 2616 } |
| 2617 break; |
| 2618 } |
| 2619 case MINA: |
| 2620 DCHECK(kArchVariant == kMips64r6); |
| 2621 fs = get_fpu_register_float(fs_reg); |
| 2622 if (std::isnan(fs) && std::isnan(ft)) { |
| 2623 set_fpu_register_float(fd_reg, fs); |
| 2624 } else if (std::isnan(fs) && !std::isnan(ft)) { |
| 2625 set_fpu_register_float(fd_reg, ft); |
| 2626 } else if (!std::isnan(fs) && std::isnan(ft)) { |
| 2627 set_fpu_register_float(fd_reg, fs); |
| 2628 } else { |
| 2629 float result; |
| 2630 if (fabs(fs) > fabs(ft)) { |
| 2631 result = ft; |
| 2632 } else if (fabs(fs) < fabs(ft)) { |
| 2633 result = fs; |
| 2634 } else { |
| 2635 result = (fs > ft ? fs : ft); |
| 2636 } |
| 2637 set_fpu_register_float(fd_reg, result); |
| 2638 } |
| 2639 break; |
| 2640 case MAXA: |
| 2641 DCHECK(kArchVariant == kMips64r6); |
| 2642 fs = get_fpu_register_float(fs_reg); |
| 2643 if (std::isnan(fs) && std::isnan(ft)) { |
| 2644 set_fpu_register_float(fd_reg, fs); |
| 2645 } else if (std::isnan(fs) && !std::isnan(ft)) { |
| 2646 set_fpu_register_float(fd_reg, ft); |
| 2647 } else if (!std::isnan(fs) && std::isnan(ft)) { |
| 2648 set_fpu_register_float(fd_reg, fs); |
| 2649 } else { |
| 2650 float result; |
| 2651 if (fabs(fs) < fabs(ft)) { |
| 2652 result = ft; |
| 2653 } else if (fabs(fs) > fabs(ft)) { |
| 2654 result = fs; |
| 2655 } else { |
| 2656 result = (fs > ft ? fs : ft); |
| 2657 } |
| 2658 set_fpu_register_float(fd_reg, result); |
| 2659 } |
| 2660 break; |
| 2661 case MIN: |
| 2662 DCHECK(kArchVariant == kMips64r6); |
| 2663 fs = get_fpu_register_float(fs_reg); |
| 2664 if (std::isnan(fs) && std::isnan(ft)) { |
| 2665 set_fpu_register_float(fd_reg, fs); |
| 2666 } else if (std::isnan(fs) && !std::isnan(ft)) { |
| 2667 set_fpu_register_float(fd_reg, ft); |
| 2668 } else if (!std::isnan(fs) && std::isnan(ft)) { |
| 2669 set_fpu_register_float(fd_reg, fs); |
| 2670 } else { |
| 2671 set_fpu_register_float(fd_reg, (fs >= ft) ? ft : fs); |
| 2672 } |
| 2673 break; |
| 2674 case MAX: |
| 2675 DCHECK(kArchVariant == kMips64r6); |
| 2676 fs = get_fpu_register_float(fs_reg); |
| 2677 if (std::isnan(fs) && std::isnan(ft)) { |
| 2678 set_fpu_register_float(fd_reg, fs); |
| 2679 } else if (std::isnan(fs) && !std::isnan(ft)) { |
| 2680 set_fpu_register_float(fd_reg, ft); |
| 2681 } else if (!std::isnan(fs) && std::isnan(ft)) { |
| 2682 set_fpu_register_float(fd_reg, fs); |
| 2683 } else { |
| 2684 set_fpu_register_float(fd_reg, (fs <= ft) ? ft : fs); |
| 2685 } |
| 2686 break; |
| 2687 case SEL: |
| 2688 DCHECK(kArchVariant == kMips64r6); |
| 2689 set_fpu_register_float(fd_reg, (fd_int & 0x1) == 0 ? fs : ft); |
| 2690 break; |
| 2691 case SELEQZ_C: |
| 2692 DCHECK(kArchVariant == kMips64r6); |
| 2693 set_fpu_register_float( |
| 2694 fd_reg, (ft_int & 0x1) == 0 ? get_fpu_register_float(fs_reg) : 0.0); |
| 2695 break; |
| 2696 case SELNEZ_C: |
| 2697 DCHECK(kArchVariant == kMips64r6); |
| 2698 set_fpu_register_float( |
| 2699 fd_reg, (ft_int & 0x1) != 0 ? get_fpu_register_float(fs_reg) : 0.0); |
| 2700 break; |
| 2701 case MOVZ_C: { |
| 2702 DCHECK(kArchVariant == kMips64r2); |
| 2703 int32_t rt_reg = instr->RtValue(); |
| 2704 int64_t rt = get_register(rt_reg); |
| 2705 if (rt == 0) { |
| 2706 set_fpu_register_float(fd_reg, fs); |
| 2707 } |
| 2708 break; |
| 2709 } |
| 2710 case MOVN_C: { |
| 2711 DCHECK(kArchVariant == kMips64r2); |
| 2712 int32_t rt_reg = instr->RtValue(); |
| 2713 int64_t rt = get_register(rt_reg); |
| 2714 if (rt != 0) { |
| 2715 set_fpu_register_float(fd_reg, fs); |
| 2716 } |
| 2717 break; |
| 2718 } |
| 2719 case MOVF: { |
| 2720 // Same function field for MOVT.D and MOVF.D |
| 2721 uint32_t ft_cc = (ft_reg >> 2) & 0x7; |
| 2722 ft_cc = get_fcsr_condition_bit(ft_cc); |
| 2723 |
| 2724 if (instr->Bit(16)) { // Read Tf bit. |
| 2725 // MOVT.D |
| 2726 if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg, fs); |
| 2727 } else { |
| 2728 // MOVF.D |
| 2729 if (!test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg, fs); |
| 2730 } |
| 2731 break; |
| 2732 } |
2414 default: | 2733 default: |
2415 // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S | 2734 // CVT_W_S CVT_L_S TRUNC_W_S ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S |
2416 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented. | 2735 // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented. |
2417 UNREACHABLE(); | 2736 UNREACHABLE(); |
2418 } | 2737 } |
2419 } | 2738 } |
2420 | 2739 |
2421 | 2740 |
2422 void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, | 2741 void Simulator::DecodeTypeRegisterDRsType(Instruction* instr, |
2423 const int32_t& fs_reg, | 2742 const int32_t& fs_reg, |
2424 const int32_t& ft_reg, | 2743 const int32_t& ft_reg, |
2425 const int32_t& fd_reg) { | 2744 const int32_t& fd_reg) { |
2426 double ft, fs, fd; | 2745 double ft, fs, fd; |
2427 uint32_t cc, fcsr_cc; | 2746 uint32_t cc, fcsr_cc; |
2428 fs = get_fpu_register_double(fs_reg); | 2747 fs = get_fpu_register_double(fs_reg); |
2429 ft = get_fpu_register_double(ft_reg); | 2748 if (instr->FunctionFieldRaw() != MOVF) { |
| 2749 ft = get_fpu_register_double(ft_reg); |
| 2750 } |
2430 fd = get_fpu_register_double(fd_reg); | 2751 fd = get_fpu_register_double(fd_reg); |
2431 cc = instr->FCccValue(); | 2752 cc = instr->FCccValue(); |
2432 fcsr_cc = get_fcsr_condition_bit(cc); | 2753 fcsr_cc = get_fcsr_condition_bit(cc); |
2433 int64_t ft_int = bit_cast<int64_t>(ft); | 2754 int64_t ft_int = bit_cast<int64_t>(ft); |
2434 int64_t fd_int = bit_cast<int64_t>(fd); | 2755 int64_t fd_int = bit_cast<int64_t>(fd); |
2435 switch (instr->FunctionFieldRaw()) { | 2756 switch (instr->FunctionFieldRaw()) { |
2436 case RINT: { | 2757 case RINT: { |
2437 DCHECK(kArchVariant == kMips64r6); | 2758 DCHECK(kArchVariant == kMips64r6); |
2438 double result, temp, temp_result; | 2759 double result, temp, temp_result; |
2439 double upper = std::ceil(fs); | 2760 double upper = std::ceil(fs); |
2440 double lower = std::floor(fs); | 2761 double lower = std::floor(fs); |
2441 switch (FCSR_ & 0x3) { | 2762 switch (get_fcsr_rounding_mode()) { |
2442 case kRoundToNearest: | 2763 case kRoundToNearest: |
2443 if (upper - fs < fs - lower) { | 2764 if (upper - fs < fs - lower) { |
2444 result = upper; | 2765 result = upper; |
2445 } else if (upper - fs > fs - lower) { | 2766 } else if (upper - fs > fs - lower) { |
2446 result = lower; | 2767 result = lower; |
2447 } else { | 2768 } else { |
2448 temp_result = upper / 2; | 2769 temp_result = upper / 2; |
2449 double reminder = modf(temp_result, &temp); | 2770 double reminder = modf(temp_result, &temp); |
2450 if (reminder == 0) { | 2771 if (reminder == 0) { |
2451 result = upper; | 2772 result = upper; |
(...skipping 23 matching lines...) Expand all Loading... |
2475 set_fpu_register_double(fd_reg, (fd_int & 0x1) == 0 ? fs : ft); | 2796 set_fpu_register_double(fd_reg, (fd_int & 0x1) == 0 ? fs : ft); |
2476 break; | 2797 break; |
2477 case SELEQZ_C: | 2798 case SELEQZ_C: |
2478 DCHECK(kArchVariant == kMips64r6); | 2799 DCHECK(kArchVariant == kMips64r6); |
2479 set_fpu_register_double(fd_reg, (ft_int & 0x1) == 0 ? fs : 0.0); | 2800 set_fpu_register_double(fd_reg, (ft_int & 0x1) == 0 ? fs : 0.0); |
2480 break; | 2801 break; |
2481 case SELNEZ_C: | 2802 case SELNEZ_C: |
2482 DCHECK(kArchVariant == kMips64r6); | 2803 DCHECK(kArchVariant == kMips64r6); |
2483 set_fpu_register_double(fd_reg, (ft_int & 0x1) != 0 ? fs : 0.0); | 2804 set_fpu_register_double(fd_reg, (ft_int & 0x1) != 0 ? fs : 0.0); |
2484 break; | 2805 break; |
| 2806 case MOVZ_C: { |
| 2807 DCHECK(kArchVariant == kMips64r2); |
| 2808 int32_t rt_reg = instr->RtValue(); |
| 2809 int64_t rt = get_register(rt_reg); |
| 2810 if (rt == 0) { |
| 2811 set_fpu_register_double(fd_reg, fs); |
| 2812 } |
| 2813 break; |
| 2814 } |
| 2815 case MOVN_C: { |
| 2816 DCHECK(kArchVariant == kMips64r2); |
| 2817 int32_t rt_reg = instr->RtValue(); |
| 2818 int64_t rt = get_register(rt_reg); |
| 2819 if (rt != 0) { |
| 2820 set_fpu_register_double(fd_reg, fs); |
| 2821 } |
| 2822 break; |
| 2823 } |
| 2824 case MOVF: { |
| 2825 // Same function field for MOVT.D and MOVF.D |
| 2826 uint32_t ft_cc = (ft_reg >> 2) & 0x7; |
| 2827 ft_cc = get_fcsr_condition_bit(ft_cc); |
| 2828 if (instr->Bit(16)) { // Read Tf bit. |
| 2829 // MOVT.D |
| 2830 if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg, fs); |
| 2831 } else { |
| 2832 // MOVF.D |
| 2833 if (!test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg, fs); |
| 2834 } |
| 2835 break; |
| 2836 } |
| 2837 case MINA: |
| 2838 DCHECK(kArchVariant == kMips64r6); |
| 2839 fs = get_fpu_register_double(fs_reg); |
| 2840 if (std::isnan(fs) && std::isnan(ft)) { |
| 2841 set_fpu_register_double(fd_reg, fs); |
| 2842 } else if (std::isnan(fs) && !std::isnan(ft)) { |
| 2843 set_fpu_register_double(fd_reg, ft); |
| 2844 } else if (!std::isnan(fs) && std::isnan(ft)) { |
| 2845 set_fpu_register_double(fd_reg, fs); |
| 2846 } else { |
| 2847 double result; |
| 2848 if (fabs(fs) > fabs(ft)) { |
| 2849 result = ft; |
| 2850 } else if (fabs(fs) < fabs(ft)) { |
| 2851 result = fs; |
| 2852 } else { |
| 2853 result = (fs > ft ? fs : ft); |
| 2854 } |
| 2855 set_fpu_register_double(fd_reg, result); |
| 2856 } |
| 2857 break; |
| 2858 case MAXA: |
| 2859 DCHECK(kArchVariant == kMips64r6); |
| 2860 fs = get_fpu_register_double(fs_reg); |
| 2861 if (std::isnan(fs) && std::isnan(ft)) { |
| 2862 set_fpu_register_double(fd_reg, fs); |
| 2863 } else if (std::isnan(fs) && !std::isnan(ft)) { |
| 2864 set_fpu_register_double(fd_reg, ft); |
| 2865 } else if (!std::isnan(fs) && std::isnan(ft)) { |
| 2866 set_fpu_register_double(fd_reg, fs); |
| 2867 } else { |
| 2868 double result; |
| 2869 if (fabs(fs) < fabs(ft)) { |
| 2870 result = ft; |
| 2871 } else if (fabs(fs) > fabs(ft)) { |
| 2872 result = fs; |
| 2873 } else { |
| 2874 result = (fs > ft ? fs : ft); |
| 2875 } |
| 2876 set_fpu_register_double(fd_reg, result); |
| 2877 } |
| 2878 break; |
2485 case MIN: | 2879 case MIN: |
2486 DCHECK(kArchVariant == kMips64r6); | 2880 DCHECK(kArchVariant == kMips64r6); |
2487 fs = get_fpu_register_double(fs_reg); | 2881 fs = get_fpu_register_double(fs_reg); |
2488 if (std::isnan(fs) && std::isnan(ft)) { | 2882 if (std::isnan(fs) && std::isnan(ft)) { |
2489 set_fpu_register_double(fd_reg, fs); | 2883 set_fpu_register_double(fd_reg, fs); |
2490 } else if (std::isnan(fs) && !std::isnan(ft)) { | 2884 } else if (std::isnan(fs) && !std::isnan(ft)) { |
2491 set_fpu_register_double(fd_reg, ft); | 2885 set_fpu_register_double(fd_reg, ft); |
2492 } else if (!std::isnan(fs) && std::isnan(ft)) { | 2886 } else if (!std::isnan(fs) && std::isnan(ft)) { |
2493 set_fpu_register_double(fd_reg, fs); | 2887 set_fpu_register_double(fd_reg, fs); |
2494 } else { | 2888 } else { |
(...skipping 30 matching lines...) Expand all Loading... |
2525 break; | 2919 break; |
2526 case MOV_D: | 2920 case MOV_D: |
2527 set_fpu_register_double(fd_reg, fs); | 2921 set_fpu_register_double(fd_reg, fs); |
2528 break; | 2922 break; |
2529 case NEG_D: | 2923 case NEG_D: |
2530 set_fpu_register_double(fd_reg, -fs); | 2924 set_fpu_register_double(fd_reg, -fs); |
2531 break; | 2925 break; |
2532 case SQRT_D: | 2926 case SQRT_D: |
2533 set_fpu_register_double(fd_reg, fast_sqrt(fs)); | 2927 set_fpu_register_double(fd_reg, fast_sqrt(fs)); |
2534 break; | 2928 break; |
| 2929 case RSQRT_D: { |
| 2930 double result = 1.0 / fast_sqrt(fs); |
| 2931 set_fpu_register_double(fd_reg, result); |
| 2932 break; |
| 2933 } |
| 2934 case RECIP_D: { |
| 2935 double result = 1.0 / fs; |
| 2936 set_fpu_register_double(fd_reg, result); |
| 2937 break; |
| 2938 } |
2535 case C_UN_D: | 2939 case C_UN_D: |
2536 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft)); | 2940 set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft)); |
2537 break; | 2941 break; |
2538 case C_EQ_D: | 2942 case C_EQ_D: |
2539 set_fcsr_bit(fcsr_cc, (fs == ft)); | 2943 set_fcsr_bit(fcsr_cc, (fs == ft)); |
2540 break; | 2944 break; |
2541 case C_UEQ_D: | 2945 case C_UEQ_D: |
2542 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft))); | 2946 set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft))); |
2543 break; | 2947 break; |
2544 case C_OLT_D: | 2948 case C_OLT_D: |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2611 double rounded; | 3015 double rounded; |
2612 int64_t result; | 3016 int64_t result; |
2613 round64_according_to_fcsr(fs, rounded, result, fs); | 3017 round64_according_to_fcsr(fs, rounded, result, fs); |
2614 set_fpu_register(fd_reg, result); | 3018 set_fpu_register(fd_reg, result); |
2615 if (set_fcsr_round64_error(fs, rounded)) { | 3019 if (set_fcsr_round64_error(fs, rounded)) { |
2616 set_fpu_register(fd_reg, kFPUInvalidResult); | 3020 set_fpu_register(fd_reg, kFPUInvalidResult); |
2617 } | 3021 } |
2618 break; | 3022 break; |
2619 } | 3023 } |
2620 case ROUND_L_D: { // Mips64r2 instruction. | 3024 case ROUND_L_D: { // Mips64r2 instruction. |
2621 // check error cases | 3025 double rounded = std::floor(fs + 0.5); |
2622 double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5); | |
2623 int64_t result = static_cast<int64_t>(rounded); | 3026 int64_t result = static_cast<int64_t>(rounded); |
2624 set_fpu_register(fd_reg, result); | 3027 if ((result & 1) != 0 && result - fs == 0.5) { |
| 3028 // If the number is halfway between two integers, |
| 3029 // round to the even one. |
| 3030 result--; |
| 3031 } |
| 3032 int64_t i64 = static_cast<int64_t>(result); |
| 3033 set_fpu_register(fd_reg, i64); |
2625 if (set_fcsr_round64_error(fs, rounded)) { | 3034 if (set_fcsr_round64_error(fs, rounded)) { |
2626 set_fpu_register(fd_reg, kFPU64InvalidResult); | 3035 set_fpu_register(fd_reg, kFPU64InvalidResult); |
2627 } | 3036 } |
2628 break; | 3037 break; |
2629 } | 3038 } |
2630 case TRUNC_L_D: { // Mips64r2 instruction. | 3039 case TRUNC_L_D: { // Mips64r2 instruction. |
2631 double rounded = trunc(fs); | 3040 double rounded = trunc(fs); |
2632 int64_t result = static_cast<int64_t>(rounded); | 3041 int64_t result = static_cast<int64_t>(rounded); |
2633 set_fpu_register(fd_reg, result); | 3042 set_fpu_register(fd_reg, result); |
2634 if (set_fcsr_round64_error(fs, rounded)) { | 3043 if (set_fcsr_round64_error(fs, rounded)) { |
(...skipping 1116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3751 return address; | 4160 return address; |
3752 } | 4161 } |
3753 | 4162 |
3754 | 4163 |
3755 #undef UNSUPPORTED | 4164 #undef UNSUPPORTED |
3756 } } // namespace v8::internal | 4165 } } // namespace v8::internal |
3757 | 4166 |
3758 #endif // USE_SIMULATOR | 4167 #endif // USE_SIMULATOR |
3759 | 4168 |
3760 #endif // V8_TARGET_ARCH_MIPS64 | 4169 #endif // V8_TARGET_ARCH_MIPS64 |
OLD | NEW |