| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 <stdlib.h> | 5 #include <stdlib.h> |
| 6 #include <cmath> | 6 #include <cmath> |
| 7 #include <cstdarg> | 7 #include <cstdarg> |
| 8 | 8 |
| 9 #if V8_TARGET_ARCH_ARM64 | 9 #if V8_TARGET_ARCH_ARM64 |
| 10 | 10 |
| (...skipping 870 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 881 } | 881 } |
| 882 if ((strcmp("csp", name) == 0) || (strcmp("wcsp", name) == 0)) { | 882 if ((strcmp("csp", name) == 0) || (strcmp("wcsp", name) == 0)) { |
| 883 return kSPRegInternalCode; | 883 return kSPRegInternalCode; |
| 884 } | 884 } |
| 885 return -1; | 885 return -1; |
| 886 } | 886 } |
| 887 | 887 |
| 888 | 888 |
| 889 // Helpers --------------------------------------------------------------------- | 889 // Helpers --------------------------------------------------------------------- |
| 890 template <typename T> | 890 template <typename T> |
| 891 T Simulator::AddWithCarry(bool set_flags, | 891 T Simulator::AddWithCarry(bool set_flags, T left, T right, int carry_in) { |
| 892 T src1, | 892 // Use unsigned types to avoid implementation-defined overflow behaviour. |
| 893 T src2, | 893 static_assert(std::is_unsigned<T>::value, "operands must be unsigned"); |
| 894 T carry_in) { | 894 static_assert((sizeof(T) == kWRegSize) || (sizeof(T) == kXRegSize), |
| 895 typedef typename make_unsigned<T>::type unsignedT; | 895 "Only W- or X-sized operands are tested"); |
| 896 |
| 896 DCHECK((carry_in == 0) || (carry_in == 1)); | 897 DCHECK((carry_in == 0) || (carry_in == 1)); |
| 897 | 898 T result = left + right + carry_in; |
| 898 T signed_sum = src1 + src2 + carry_in; | |
| 899 T result = signed_sum; | |
| 900 | |
| 901 bool N, Z, C, V; | |
| 902 | |
| 903 // Compute the C flag | |
| 904 unsignedT u1 = static_cast<unsignedT>(src1); | |
| 905 unsignedT u2 = static_cast<unsignedT>(src2); | |
| 906 unsignedT urest = std::numeric_limits<unsignedT>::max() - u1; | |
| 907 C = (u2 > urest) || (carry_in && (((u2 + 1) > urest) || (u2 > (urest - 1)))); | |
| 908 | |
| 909 // Overflow iff the sign bit is the same for the two inputs and different | |
| 910 // for the result. | |
| 911 V = ((src1 ^ src2) >= 0) && ((src1 ^ result) < 0); | |
| 912 | |
| 913 N = CalcNFlag(result); | |
| 914 Z = CalcZFlag(result); | |
| 915 | 899 |
| 916 if (set_flags) { | 900 if (set_flags) { |
| 917 nzcv().SetN(N); | 901 nzcv().SetN(CalcNFlag(result)); |
| 918 nzcv().SetZ(Z); | 902 nzcv().SetZ(CalcZFlag(result)); |
| 919 nzcv().SetC(C); | 903 |
| 920 nzcv().SetV(V); | 904 // Compute the C flag by comparing the result to the max unsigned integer. |
| 905 T max_uint_2op = std::numeric_limits<T>::max() - carry_in; |
| 906 nzcv().SetC((left > max_uint_2op) || ((max_uint_2op - left) < right)); |
| 907 |
| 908 // Overflow iff the sign bit is the same for the two inputs and different |
| 909 // for the result. |
| 910 T sign_mask = T(1) << (sizeof(T) * 8 - 1); |
| 911 T left_sign = left & sign_mask; |
| 912 T right_sign = right & sign_mask; |
| 913 T result_sign = result & sign_mask; |
| 914 nzcv().SetV((left_sign == right_sign) && (left_sign != result_sign)); |
| 915 |
| 921 LogSystemRegister(NZCV); | 916 LogSystemRegister(NZCV); |
| 922 } | 917 } |
| 923 return result; | 918 return result; |
| 924 } | 919 } |
| 925 | 920 |
| 926 | 921 |
| 927 template<typename T> | 922 template<typename T> |
| 928 void Simulator::AddSubWithCarry(Instruction* instr) { | 923 void Simulator::AddSubWithCarry(Instruction* instr) { |
| 924 // Use unsigned types to avoid implementation-defined overflow behaviour. |
| 925 static_assert(std::is_unsigned<T>::value, "operands must be unsigned"); |
| 926 |
| 929 T op2 = reg<T>(instr->Rm()); | 927 T op2 = reg<T>(instr->Rm()); |
| 930 T new_val; | 928 T new_val; |
| 931 | 929 |
| 932 if ((instr->Mask(AddSubOpMask) == SUB) || instr->Mask(AddSubOpMask) == SUBS) { | 930 if ((instr->Mask(AddSubOpMask) == SUB) || instr->Mask(AddSubOpMask) == SUBS) { |
| 933 op2 = ~op2; | 931 op2 = ~op2; |
| 934 } | 932 } |
| 935 | 933 |
| 936 new_val = AddWithCarry<T>(instr->FlagsUpdate(), | 934 new_val = AddWithCarry<T>(instr->FlagsUpdate(), |
| 937 reg<T>(instr->Rn()), | 935 reg<T>(instr->Rn()), |
| 938 op2, | 936 op2, |
| (...skipping 472 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1411 default: UNIMPLEMENTED(); | 1409 default: UNIMPLEMENTED(); |
| 1412 } | 1410 } |
| 1413 if (take_branch) { | 1411 if (take_branch) { |
| 1414 set_pc(instr->ImmPCOffsetTarget()); | 1412 set_pc(instr->ImmPCOffsetTarget()); |
| 1415 } | 1413 } |
| 1416 } | 1414 } |
| 1417 | 1415 |
| 1418 | 1416 |
| 1419 template<typename T> | 1417 template<typename T> |
| 1420 void Simulator::AddSubHelper(Instruction* instr, T op2) { | 1418 void Simulator::AddSubHelper(Instruction* instr, T op2) { |
| 1419 // Use unsigned types to avoid implementation-defined overflow behaviour. |
| 1420 static_assert(std::is_unsigned<T>::value, "operands must be unsigned"); |
| 1421 |
| 1421 bool set_flags = instr->FlagsUpdate(); | 1422 bool set_flags = instr->FlagsUpdate(); |
| 1422 T new_val = 0; | 1423 T new_val = 0; |
| 1423 Instr operation = instr->Mask(AddSubOpMask); | 1424 Instr operation = instr->Mask(AddSubOpMask); |
| 1424 | 1425 |
| 1425 switch (operation) { | 1426 switch (operation) { |
| 1426 case ADD: | 1427 case ADD: |
| 1427 case ADDS: { | 1428 case ADDS: { |
| 1428 new_val = AddWithCarry<T>(set_flags, | 1429 new_val = AddWithCarry<T>(set_flags, |
| 1429 reg<T>(instr->Rn(), instr->RnMode()), | 1430 reg<T>(instr->Rn(), instr->RnMode()), |
| 1430 op2); | 1431 op2); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1443 | 1444 |
| 1444 set_reg<T>(instr->Rd(), new_val, instr->RdMode()); | 1445 set_reg<T>(instr->Rd(), new_val, instr->RdMode()); |
| 1445 } | 1446 } |
| 1446 | 1447 |
| 1447 | 1448 |
| 1448 void Simulator::VisitAddSubShifted(Instruction* instr) { | 1449 void Simulator::VisitAddSubShifted(Instruction* instr) { |
| 1449 Shift shift_type = static_cast<Shift>(instr->ShiftDP()); | 1450 Shift shift_type = static_cast<Shift>(instr->ShiftDP()); |
| 1450 unsigned shift_amount = instr->ImmDPShift(); | 1451 unsigned shift_amount = instr->ImmDPShift(); |
| 1451 | 1452 |
| 1452 if (instr->SixtyFourBits()) { | 1453 if (instr->SixtyFourBits()) { |
| 1453 int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount); | 1454 uint64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount); |
| 1454 AddSubHelper(instr, op2); | 1455 AddSubHelper(instr, op2); |
| 1455 } else { | 1456 } else { |
| 1456 int32_t op2 = static_cast<int32_t>( | 1457 uint32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount); |
| 1457 ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount)); | |
| 1458 AddSubHelper(instr, op2); | 1458 AddSubHelper(instr, op2); |
| 1459 } | 1459 } |
| 1460 } | 1460 } |
| 1461 | 1461 |
| 1462 | 1462 |
| 1463 void Simulator::VisitAddSubImmediate(Instruction* instr) { | 1463 void Simulator::VisitAddSubImmediate(Instruction* instr) { |
| 1464 int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0); | 1464 int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0); |
| 1465 if (instr->SixtyFourBits()) { | 1465 if (instr->SixtyFourBits()) { |
| 1466 AddSubHelper<int64_t>(instr, op2); | 1466 AddSubHelper(instr, static_cast<uint64_t>(op2)); |
| 1467 } else { | 1467 } else { |
| 1468 AddSubHelper<int32_t>(instr, static_cast<int32_t>(op2)); | 1468 AddSubHelper(instr, static_cast<uint32_t>(op2)); |
| 1469 } | 1469 } |
| 1470 } | 1470 } |
| 1471 | 1471 |
| 1472 | 1472 |
| 1473 void Simulator::VisitAddSubExtended(Instruction* instr) { | 1473 void Simulator::VisitAddSubExtended(Instruction* instr) { |
| 1474 Extend ext = static_cast<Extend>(instr->ExtendMode()); | 1474 Extend ext = static_cast<Extend>(instr->ExtendMode()); |
| 1475 unsigned left_shift = instr->ImmExtendShift(); | 1475 unsigned left_shift = instr->ImmExtendShift(); |
| 1476 if (instr->SixtyFourBits()) { | 1476 if (instr->SixtyFourBits()) { |
| 1477 int64_t op2 = ExtendValue(xreg(instr->Rm()), ext, left_shift); | 1477 uint64_t op2 = ExtendValue(xreg(instr->Rm()), ext, left_shift); |
| 1478 AddSubHelper(instr, op2); | 1478 AddSubHelper(instr, op2); |
| 1479 } else { | 1479 } else { |
| 1480 int32_t op2 = ExtendValue(wreg(instr->Rm()), ext, left_shift); | 1480 uint32_t op2 = ExtendValue(wreg(instr->Rm()), ext, left_shift); |
| 1481 AddSubHelper(instr, op2); | 1481 AddSubHelper(instr, op2); |
| 1482 } | 1482 } |
| 1483 } | 1483 } |
| 1484 | 1484 |
| 1485 | 1485 |
| 1486 void Simulator::VisitAddSubWithCarry(Instruction* instr) { | 1486 void Simulator::VisitAddSubWithCarry(Instruction* instr) { |
| 1487 if (instr->SixtyFourBits()) { | 1487 if (instr->SixtyFourBits()) { |
| 1488 AddSubWithCarry<int64_t>(instr); | 1488 AddSubWithCarry<uint64_t>(instr); |
| 1489 } else { | 1489 } else { |
| 1490 AddSubWithCarry<int32_t>(instr); | 1490 AddSubWithCarry<uint32_t>(instr); |
| 1491 } | 1491 } |
| 1492 } | 1492 } |
| 1493 | 1493 |
| 1494 | 1494 |
| 1495 void Simulator::VisitLogicalShifted(Instruction* instr) { | 1495 void Simulator::VisitLogicalShifted(Instruction* instr) { |
| 1496 Shift shift_type = static_cast<Shift>(instr->ShiftDP()); | 1496 Shift shift_type = static_cast<Shift>(instr->ShiftDP()); |
| 1497 unsigned shift_amount = instr->ImmDPShift(); | 1497 unsigned shift_amount = instr->ImmDPShift(); |
| 1498 | 1498 |
| 1499 if (instr->SixtyFourBits()) { | 1499 if (instr->SixtyFourBits()) { |
| 1500 int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount); | 1500 uint64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount); |
| 1501 op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2; | 1501 op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2; |
| 1502 LogicalHelper<int64_t>(instr, op2); | 1502 LogicalHelper(instr, op2); |
| 1503 } else { | 1503 } else { |
| 1504 int32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount); | 1504 uint32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount); |
| 1505 op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2; | 1505 op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2; |
| 1506 LogicalHelper<int32_t>(instr, op2); | 1506 LogicalHelper(instr, op2); |
| 1507 } | 1507 } |
| 1508 } | 1508 } |
| 1509 | 1509 |
| 1510 | 1510 |
| 1511 void Simulator::VisitLogicalImmediate(Instruction* instr) { | 1511 void Simulator::VisitLogicalImmediate(Instruction* instr) { |
| 1512 if (instr->SixtyFourBits()) { | 1512 if (instr->SixtyFourBits()) { |
| 1513 LogicalHelper<int64_t>(instr, instr->ImmLogical()); | 1513 LogicalHelper(instr, static_cast<uint64_t>(instr->ImmLogical())); |
| 1514 } else { | 1514 } else { |
| 1515 LogicalHelper<int32_t>(instr, static_cast<int32_t>(instr->ImmLogical())); | 1515 LogicalHelper(instr, static_cast<uint32_t>(instr->ImmLogical())); |
| 1516 } | 1516 } |
| 1517 } | 1517 } |
| 1518 | 1518 |
| 1519 | 1519 |
| 1520 template<typename T> | 1520 template<typename T> |
| 1521 void Simulator::LogicalHelper(Instruction* instr, T op2) { | 1521 void Simulator::LogicalHelper(Instruction* instr, T op2) { |
| 1522 T op1 = reg<T>(instr->Rn()); | 1522 T op1 = reg<T>(instr->Rn()); |
| 1523 T result = 0; | 1523 T result = 0; |
| 1524 bool update_flags = false; | 1524 bool update_flags = false; |
| 1525 | 1525 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1541 nzcv().SetV(0); | 1541 nzcv().SetV(0); |
| 1542 LogSystemRegister(NZCV); | 1542 LogSystemRegister(NZCV); |
| 1543 } | 1543 } |
| 1544 | 1544 |
| 1545 set_reg<T>(instr->Rd(), result, instr->RdMode()); | 1545 set_reg<T>(instr->Rd(), result, instr->RdMode()); |
| 1546 } | 1546 } |
| 1547 | 1547 |
| 1548 | 1548 |
| 1549 void Simulator::VisitConditionalCompareRegister(Instruction* instr) { | 1549 void Simulator::VisitConditionalCompareRegister(Instruction* instr) { |
| 1550 if (instr->SixtyFourBits()) { | 1550 if (instr->SixtyFourBits()) { |
| 1551 ConditionalCompareHelper(instr, xreg(instr->Rm())); | 1551 ConditionalCompareHelper(instr, static_cast<uint64_t>(xreg(instr->Rm()))); |
| 1552 } else { | 1552 } else { |
| 1553 ConditionalCompareHelper(instr, wreg(instr->Rm())); | 1553 ConditionalCompareHelper(instr, static_cast<uint32_t>(wreg(instr->Rm()))); |
| 1554 } | 1554 } |
| 1555 } | 1555 } |
| 1556 | 1556 |
| 1557 | 1557 |
| 1558 void Simulator::VisitConditionalCompareImmediate(Instruction* instr) { | 1558 void Simulator::VisitConditionalCompareImmediate(Instruction* instr) { |
| 1559 if (instr->SixtyFourBits()) { | 1559 if (instr->SixtyFourBits()) { |
| 1560 ConditionalCompareHelper<int64_t>(instr, instr->ImmCondCmp()); | 1560 ConditionalCompareHelper(instr, static_cast<uint64_t>(instr->ImmCondCmp())); |
| 1561 } else { | 1561 } else { |
| 1562 ConditionalCompareHelper<int32_t>(instr, instr->ImmCondCmp()); | 1562 ConditionalCompareHelper(instr, static_cast<uint32_t>(instr->ImmCondCmp())); |
| 1563 } | 1563 } |
| 1564 } | 1564 } |
| 1565 | 1565 |
| 1566 | 1566 |
| 1567 template<typename T> | 1567 template<typename T> |
| 1568 void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) { | 1568 void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) { |
| 1569 // Use unsigned types to avoid implementation-defined overflow behaviour. |
| 1570 static_assert(std::is_unsigned<T>::value, "operands must be unsigned"); |
| 1571 |
| 1569 T op1 = reg<T>(instr->Rn()); | 1572 T op1 = reg<T>(instr->Rn()); |
| 1570 | 1573 |
| 1571 if (ConditionPassed(static_cast<Condition>(instr->Condition()))) { | 1574 if (ConditionPassed(static_cast<Condition>(instr->Condition()))) { |
| 1572 // If the condition passes, set the status flags to the result of comparing | 1575 // If the condition passes, set the status flags to the result of comparing |
| 1573 // the operands. | 1576 // the operands. |
| 1574 if (instr->Mask(ConditionalCompareMask) == CCMP) { | 1577 if (instr->Mask(ConditionalCompareMask) == CCMP) { |
| 1575 AddWithCarry<T>(true, op1, ~op2, 1); | 1578 AddWithCarry<T>(true, op1, ~op2, 1); |
| 1576 } else { | 1579 } else { |
| 1577 DCHECK(instr->Mask(ConditionalCompareMask) == CCMN); | 1580 DCHECK(instr->Mask(ConditionalCompareMask) == CCMN); |
| 1578 AddWithCarry<T>(true, op1, op2, 0); | 1581 AddWithCarry<T>(true, op1, op2, 0); |
| (...skipping 2294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3873 delete[] format; | 3876 delete[] format; |
| 3874 } | 3877 } |
| 3875 | 3878 |
| 3876 | 3879 |
| 3877 #endif // USE_SIMULATOR | 3880 #endif // USE_SIMULATOR |
| 3878 | 3881 |
| 3879 } // namespace internal | 3882 } // namespace internal |
| 3880 } // namespace v8 | 3883 } // namespace v8 |
| 3881 | 3884 |
| 3882 #endif // V8_TARGET_ARCH_ARM64 | 3885 #endif // V8_TARGET_ARCH_ARM64 |
| OLD | NEW |