| Index: src/arm64/simulator-arm64.cc
|
| diff --git a/src/arm64/simulator-arm64.cc b/src/arm64/simulator-arm64.cc
|
| index aa10eb2956377a575882da45335717ad842cac77..f5595a8ed12b139f36017bab2c70b1ecb3f46bef 100644
|
| --- a/src/arm64/simulator-arm64.cc
|
| +++ b/src/arm64/simulator-arm64.cc
|
| @@ -888,36 +888,31 @@ int Simulator::CodeFromName(const char* name) {
|
|
|
| // Helpers ---------------------------------------------------------------------
|
| template <typename T>
|
| -T Simulator::AddWithCarry(bool set_flags,
|
| - T src1,
|
| - T src2,
|
| - T carry_in) {
|
| - typedef typename make_unsigned<T>::type unsignedT;
|
| +T Simulator::AddWithCarry(bool set_flags, T left, T right, int carry_in) {
|
| + // Use unsigned types to avoid implementation-defined overflow behaviour.
|
| + static_assert(std::is_unsigned<T>::value, "operands must be unsigned");
|
| + static_assert((sizeof(T) == kWRegSize) || (sizeof(T) == kXRegSize),
|
| + "Only W- or X-sized operands are tested");
|
| +
|
| DCHECK((carry_in == 0) || (carry_in == 1));
|
| -
|
| - T signed_sum = src1 + src2 + carry_in;
|
| - T result = signed_sum;
|
| -
|
| - bool N, Z, C, V;
|
| -
|
| - // Compute the C flag
|
| - unsignedT u1 = static_cast<unsignedT>(src1);
|
| - unsignedT u2 = static_cast<unsignedT>(src2);
|
| - unsignedT urest = std::numeric_limits<unsignedT>::max() - u1;
|
| - C = (u2 > urest) || (carry_in && (((u2 + 1) > urest) || (u2 > (urest - 1))));
|
| -
|
| - // Overflow iff the sign bit is the same for the two inputs and different
|
| - // for the result.
|
| - V = ((src1 ^ src2) >= 0) && ((src1 ^ result) < 0);
|
| -
|
| - N = CalcNFlag(result);
|
| - Z = CalcZFlag(result);
|
| + T result = left + right + carry_in;
|
|
|
| if (set_flags) {
|
| - nzcv().SetN(N);
|
| - nzcv().SetZ(Z);
|
| - nzcv().SetC(C);
|
| - nzcv().SetV(V);
|
| + nzcv().SetN(CalcNFlag(result));
|
| + nzcv().SetZ(CalcZFlag(result));
|
| +
|
| + // Compute the C flag by comparing the result to the max unsigned integer.
|
| + T max_uint_2op = std::numeric_limits<T>::max() - carry_in;
|
| + nzcv().SetC((left > max_uint_2op) || ((max_uint_2op - left) < right));
|
| +
|
| + // Overflow iff the sign bit is the same for the two inputs and different
|
| + // for the result.
|
| + T sign_mask = T(1) << (sizeof(T) * 8 - 1);
|
| + T left_sign = left & sign_mask;
|
| + T right_sign = right & sign_mask;
|
| + T result_sign = result & sign_mask;
|
| + nzcv().SetV((left_sign == right_sign) && (left_sign != result_sign));
|
| +
|
| LogSystemRegister(NZCV);
|
| }
|
| return result;
|
| @@ -926,6 +921,9 @@ T Simulator::AddWithCarry(bool set_flags,
|
|
|
| template<typename T>
|
| void Simulator::AddSubWithCarry(Instruction* instr) {
|
| + // Use unsigned types to avoid implementation-defined overflow behaviour.
|
| + static_assert(std::is_unsigned<T>::value, "operands must be unsigned");
|
| +
|
| T op2 = reg<T>(instr->Rm());
|
| T new_val;
|
|
|
| @@ -1418,6 +1416,9 @@ void Simulator::VisitCompareBranch(Instruction* instr) {
|
|
|
| template<typename T>
|
| void Simulator::AddSubHelper(Instruction* instr, T op2) {
|
| + // Use unsigned types to avoid implementation-defined overflow behaviour.
|
| + static_assert(std::is_unsigned<T>::value, "operands must be unsigned");
|
| +
|
| bool set_flags = instr->FlagsUpdate();
|
| T new_val = 0;
|
| Instr operation = instr->Mask(AddSubOpMask);
|
| @@ -1450,11 +1451,10 @@ void Simulator::VisitAddSubShifted(Instruction* instr) {
|
| unsigned shift_amount = instr->ImmDPShift();
|
|
|
| if (instr->SixtyFourBits()) {
|
| - int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
|
| + uint64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
|
| AddSubHelper(instr, op2);
|
| } else {
|
| - int32_t op2 = static_cast<int32_t>(
|
| - ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount));
|
| + uint32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
|
| AddSubHelper(instr, op2);
|
| }
|
| }
|
| @@ -1463,9 +1463,9 @@ void Simulator::VisitAddSubShifted(Instruction* instr) {
|
| void Simulator::VisitAddSubImmediate(Instruction* instr) {
|
| int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0);
|
| if (instr->SixtyFourBits()) {
|
| - AddSubHelper<int64_t>(instr, op2);
|
| + AddSubHelper(instr, static_cast<uint64_t>(op2));
|
| } else {
|
| - AddSubHelper<int32_t>(instr, static_cast<int32_t>(op2));
|
| + AddSubHelper(instr, static_cast<uint32_t>(op2));
|
| }
|
| }
|
|
|
| @@ -1474,10 +1474,10 @@ void Simulator::VisitAddSubExtended(Instruction* instr) {
|
| Extend ext = static_cast<Extend>(instr->ExtendMode());
|
| unsigned left_shift = instr->ImmExtendShift();
|
| if (instr->SixtyFourBits()) {
|
| - int64_t op2 = ExtendValue(xreg(instr->Rm()), ext, left_shift);
|
| + uint64_t op2 = ExtendValue(xreg(instr->Rm()), ext, left_shift);
|
| AddSubHelper(instr, op2);
|
| } else {
|
| - int32_t op2 = ExtendValue(wreg(instr->Rm()), ext, left_shift);
|
| + uint32_t op2 = ExtendValue(wreg(instr->Rm()), ext, left_shift);
|
| AddSubHelper(instr, op2);
|
| }
|
| }
|
| @@ -1485,9 +1485,9 @@ void Simulator::VisitAddSubExtended(Instruction* instr) {
|
|
|
| void Simulator::VisitAddSubWithCarry(Instruction* instr) {
|
| if (instr->SixtyFourBits()) {
|
| - AddSubWithCarry<int64_t>(instr);
|
| + AddSubWithCarry<uint64_t>(instr);
|
| } else {
|
| - AddSubWithCarry<int32_t>(instr);
|
| + AddSubWithCarry<uint32_t>(instr);
|
| }
|
| }
|
|
|
| @@ -1497,22 +1497,22 @@ void Simulator::VisitLogicalShifted(Instruction* instr) {
|
| unsigned shift_amount = instr->ImmDPShift();
|
|
|
| if (instr->SixtyFourBits()) {
|
| - int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
|
| + uint64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
|
| op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2;
|
| - LogicalHelper<int64_t>(instr, op2);
|
| + LogicalHelper(instr, op2);
|
| } else {
|
| - int32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
|
| + uint32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
|
| op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2;
|
| - LogicalHelper<int32_t>(instr, op2);
|
| + LogicalHelper(instr, op2);
|
| }
|
| }
|
|
|
|
|
| void Simulator::VisitLogicalImmediate(Instruction* instr) {
|
| if (instr->SixtyFourBits()) {
|
| - LogicalHelper<int64_t>(instr, instr->ImmLogical());
|
| + LogicalHelper(instr, static_cast<uint64_t>(instr->ImmLogical()));
|
| } else {
|
| - LogicalHelper<int32_t>(instr, static_cast<int32_t>(instr->ImmLogical()));
|
| + LogicalHelper(instr, static_cast<uint32_t>(instr->ImmLogical()));
|
| }
|
| }
|
|
|
| @@ -1548,24 +1548,27 @@ void Simulator::LogicalHelper(Instruction* instr, T op2) {
|
|
|
| void Simulator::VisitConditionalCompareRegister(Instruction* instr) {
|
| if (instr->SixtyFourBits()) {
|
| - ConditionalCompareHelper(instr, xreg(instr->Rm()));
|
| + ConditionalCompareHelper(instr, static_cast<uint64_t>(xreg(instr->Rm())));
|
| } else {
|
| - ConditionalCompareHelper(instr, wreg(instr->Rm()));
|
| + ConditionalCompareHelper(instr, static_cast<uint32_t>(wreg(instr->Rm())));
|
| }
|
| }
|
|
|
|
|
| void Simulator::VisitConditionalCompareImmediate(Instruction* instr) {
|
| if (instr->SixtyFourBits()) {
|
| - ConditionalCompareHelper<int64_t>(instr, instr->ImmCondCmp());
|
| + ConditionalCompareHelper(instr, static_cast<uint64_t>(instr->ImmCondCmp()));
|
| } else {
|
| - ConditionalCompareHelper<int32_t>(instr, instr->ImmCondCmp());
|
| + ConditionalCompareHelper(instr, static_cast<uint32_t>(instr->ImmCondCmp()));
|
| }
|
| }
|
|
|
|
|
| template<typename T>
|
| void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) {
|
| + // Use unsigned types to avoid implementation-defined overflow behaviour.
|
| + static_assert(std::is_unsigned<T>::value, "operands must be unsigned");
|
| +
|
| T op1 = reg<T>(instr->Rn());
|
|
|
| if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
|
|
|