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 |