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()))) { |