[arm64] Avoid signed arithmetic in AddWithCarry.
This avoids implementation-defined signed overflow in the simulator's AddWithCarry implementation. The implementation of AddWithCarry now uses unsigned arithmetic exclusively. Testing coverage is also significantly improved. BUG= Review-Url: https://codereview.chromium.org/2157283003 Cr-Commit-Position: refs/heads/master@{#37895}
This commit is contained in:
parent
f52263ece7
commit
6ae7f2b5d8
@ -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()))) {
|
||||
|
@ -652,11 +652,8 @@ class Simulator : public DecoderVisitor {
|
||||
|
||||
template<typename T>
|
||||
void AddSubHelper(Instruction* instr, T op2);
|
||||
template<typename T>
|
||||
T AddWithCarry(bool set_flags,
|
||||
T src1,
|
||||
T src2,
|
||||
T carry_in = 0);
|
||||
template <typename T>
|
||||
T AddWithCarry(bool set_flags, T left, T right, int carry_in = 0);
|
||||
template<typename T>
|
||||
void AddSubWithCarry(Instruction* instr);
|
||||
template<typename T>
|
||||
|
@ -3819,6 +3819,375 @@ TEST(neg) {
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename Op>
|
||||
static void AdcsSbcsHelper(Op op, T left, T right, int carry, T expected,
|
||||
StatusFlags expected_flags) {
|
||||
int reg_size = sizeof(T) * 8;
|
||||
auto left_reg = Register::Create(0, reg_size);
|
||||
auto right_reg = Register::Create(1, reg_size);
|
||||
auto result_reg = Register::Create(2, reg_size);
|
||||
|
||||
SETUP();
|
||||
START();
|
||||
|
||||
__ Mov(left_reg, left);
|
||||
__ Mov(right_reg, right);
|
||||
__ Mov(x10, (carry ? CFlag : NoFlag));
|
||||
|
||||
__ Msr(NZCV, x10);
|
||||
(masm.*op)(result_reg, left_reg, right_reg);
|
||||
|
||||
END();
|
||||
RUN();
|
||||
|
||||
CHECK_EQUAL_64(left, left_reg.X());
|
||||
CHECK_EQUAL_64(right, right_reg.X());
|
||||
CHECK_EQUAL_64(expected, result_reg.X());
|
||||
CHECK_EQUAL_NZCV(expected_flags);
|
||||
|
||||
TEARDOWN();
|
||||
}
|
||||
|
||||
|
||||
TEST(adcs_sbcs_x) {
|
||||
INIT_V8();
|
||||
uint64_t inputs[] = {
|
||||
0x0000000000000000, 0x0000000000000001, 0x7ffffffffffffffe,
|
||||
0x7fffffffffffffff, 0x8000000000000000, 0x8000000000000001,
|
||||
0xfffffffffffffffe, 0xffffffffffffffff,
|
||||
};
|
||||
static const size_t input_count = sizeof(inputs) / sizeof(inputs[0]);
|
||||
|
||||
struct Expected {
|
||||
uint64_t carry0_result;
|
||||
StatusFlags carry0_flags;
|
||||
uint64_t carry1_result;
|
||||
StatusFlags carry1_flags;
|
||||
};
|
||||
|
||||
static const Expected expected_adcs_x[input_count][input_count] = {
|
||||
{{0x0000000000000000, ZFlag, 0x0000000000000001, NoFlag},
|
||||
{0x0000000000000001, NoFlag, 0x0000000000000002, NoFlag},
|
||||
{0x7ffffffffffffffe, NoFlag, 0x7fffffffffffffff, NoFlag},
|
||||
{0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
|
||||
{0x8000000000000000, NFlag, 0x8000000000000001, NFlag},
|
||||
{0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
|
||||
{0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag}},
|
||||
{{0x0000000000000001, NoFlag, 0x0000000000000002, NoFlag},
|
||||
{0x0000000000000002, NoFlag, 0x0000000000000003, NoFlag},
|
||||
{0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
|
||||
{0x8000000000000000, NVFlag, 0x8000000000000001, NVFlag},
|
||||
{0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
|
||||
{0x8000000000000002, NFlag, 0x8000000000000003, NFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag}},
|
||||
{{0x7ffffffffffffffe, NoFlag, 0x7fffffffffffffff, NoFlag},
|
||||
{0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
|
||||
{0xfffffffffffffffc, NVFlag, 0xfffffffffffffffd, NVFlag},
|
||||
{0xfffffffffffffffd, NVFlag, 0xfffffffffffffffe, NVFlag},
|
||||
{0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0x7ffffffffffffffc, CFlag, 0x7ffffffffffffffd, CFlag},
|
||||
{0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag}},
|
||||
{{0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
|
||||
{0x8000000000000000, NVFlag, 0x8000000000000001, NVFlag},
|
||||
{0xfffffffffffffffd, NVFlag, 0xfffffffffffffffe, NVFlag},
|
||||
{0xfffffffffffffffe, NVFlag, 0xffffffffffffffff, NVFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
|
||||
{0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
|
||||
{0x7ffffffffffffffe, CFlag, 0x7fffffffffffffff, CFlag}},
|
||||
{{0x8000000000000000, NFlag, 0x8000000000000001, NFlag},
|
||||
{0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
|
||||
{0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0x0000000000000000, ZCVFlag, 0x0000000000000001, CVFlag},
|
||||
{0x0000000000000001, CVFlag, 0x0000000000000002, CVFlag},
|
||||
{0x7ffffffffffffffe, CVFlag, 0x7fffffffffffffff, CVFlag},
|
||||
{0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag}},
|
||||
{{0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
|
||||
{0x8000000000000002, NFlag, 0x8000000000000003, NFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
|
||||
{0x0000000000000001, CVFlag, 0x0000000000000002, CVFlag},
|
||||
{0x0000000000000002, CVFlag, 0x0000000000000003, CVFlag},
|
||||
{0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
|
||||
{0x8000000000000000, NCFlag, 0x8000000000000001, NCFlag}},
|
||||
{{0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0x7ffffffffffffffc, CFlag, 0x7ffffffffffffffd, CFlag},
|
||||
{0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
|
||||
{0x7ffffffffffffffe, CVFlag, 0x7fffffffffffffff, CVFlag},
|
||||
{0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
|
||||
{0xfffffffffffffffc, NCFlag, 0xfffffffffffffffd, NCFlag},
|
||||
{0xfffffffffffffffd, NCFlag, 0xfffffffffffffffe, NCFlag}},
|
||||
{{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
|
||||
{0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
|
||||
{0x7ffffffffffffffe, CFlag, 0x7fffffffffffffff, CFlag},
|
||||
{0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
|
||||
{0x8000000000000000, NCFlag, 0x8000000000000001, NCFlag},
|
||||
{0xfffffffffffffffd, NCFlag, 0xfffffffffffffffe, NCFlag},
|
||||
{0xfffffffffffffffe, NCFlag, 0xffffffffffffffff, NCFlag}}};
|
||||
|
||||
static const Expected expected_sbcs_x[input_count][input_count] = {
|
||||
{{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
|
||||
{0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
|
||||
{0x8000000000000000, NFlag, 0x8000000000000001, NFlag},
|
||||
{0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
|
||||
{0x7ffffffffffffffe, NoFlag, 0x7fffffffffffffff, NoFlag},
|
||||
{0x0000000000000001, NoFlag, 0x0000000000000002, NoFlag},
|
||||
{0x0000000000000000, ZFlag, 0x0000000000000001, NoFlag}},
|
||||
{{0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0x8000000000000002, NFlag, 0x8000000000000003, NFlag},
|
||||
{0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
|
||||
{0x8000000000000000, NVFlag, 0x8000000000000001, NVFlag},
|
||||
{0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
|
||||
{0x0000000000000002, NoFlag, 0x0000000000000003, NoFlag},
|
||||
{0x0000000000000001, NoFlag, 0x0000000000000002, NoFlag}},
|
||||
{{0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
|
||||
{0x7ffffffffffffffc, CFlag, 0x7ffffffffffffffd, CFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
|
||||
{0xfffffffffffffffd, NVFlag, 0xfffffffffffffffe, NVFlag},
|
||||
{0xfffffffffffffffc, NVFlag, 0xfffffffffffffffd, NVFlag},
|
||||
{0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag},
|
||||
{0x7ffffffffffffffe, NoFlag, 0x7fffffffffffffff, NoFlag}},
|
||||
{{0x7ffffffffffffffe, CFlag, 0x7fffffffffffffff, CFlag},
|
||||
{0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
|
||||
{0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0xfffffffffffffffe, NVFlag, 0xffffffffffffffff, NVFlag},
|
||||
{0xfffffffffffffffd, NVFlag, 0xfffffffffffffffe, NVFlag},
|
||||
{0x8000000000000000, NVFlag, 0x8000000000000001, NVFlag},
|
||||
{0x7fffffffffffffff, NoFlag, 0x8000000000000000, NVFlag}},
|
||||
{{0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
|
||||
{0x7ffffffffffffffe, CVFlag, 0x7fffffffffffffff, CVFlag},
|
||||
{0x0000000000000001, CVFlag, 0x0000000000000002, CVFlag},
|
||||
{0x0000000000000000, ZCVFlag, 0x0000000000000001, CVFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag},
|
||||
{0x8000000000000001, NFlag, 0x8000000000000002, NFlag},
|
||||
{0x8000000000000000, NFlag, 0x8000000000000001, NFlag}},
|
||||
{{0x8000000000000000, NCFlag, 0x8000000000000001, NCFlag},
|
||||
{0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
|
||||
{0x0000000000000002, CVFlag, 0x0000000000000003, CVFlag},
|
||||
{0x0000000000000001, CVFlag, 0x0000000000000002, CVFlag},
|
||||
{0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0x8000000000000002, NFlag, 0x8000000000000003, NFlag},
|
||||
{0x8000000000000001, NFlag, 0x8000000000000002, NFlag}},
|
||||
{{0xfffffffffffffffd, NCFlag, 0xfffffffffffffffe, NCFlag},
|
||||
{0xfffffffffffffffc, NCFlag, 0xfffffffffffffffd, NCFlag},
|
||||
{0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
|
||||
{0x7ffffffffffffffe, CVFlag, 0x7fffffffffffffff, CVFlag},
|
||||
{0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
|
||||
{0x7ffffffffffffffc, CFlag, 0x7ffffffffffffffd, CFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag},
|
||||
{0xfffffffffffffffe, NFlag, 0xffffffffffffffff, NFlag}},
|
||||
{{0xfffffffffffffffe, NCFlag, 0xffffffffffffffff, NCFlag},
|
||||
{0xfffffffffffffffd, NCFlag, 0xfffffffffffffffe, NCFlag},
|
||||
{0x8000000000000000, NCFlag, 0x8000000000000001, NCFlag},
|
||||
{0x7fffffffffffffff, CVFlag, 0x8000000000000000, NCFlag},
|
||||
{0x7ffffffffffffffe, CFlag, 0x7fffffffffffffff, CFlag},
|
||||
{0x7ffffffffffffffd, CFlag, 0x7ffffffffffffffe, CFlag},
|
||||
{0x0000000000000000, ZCFlag, 0x0000000000000001, CFlag},
|
||||
{0xffffffffffffffff, NFlag, 0x0000000000000000, ZCFlag}}};
|
||||
|
||||
for (size_t left = 0; left < input_count; left++) {
|
||||
for (size_t right = 0; right < input_count; right++) {
|
||||
const Expected& expected = expected_adcs_x[left][right];
|
||||
AdcsSbcsHelper(&MacroAssembler::Adcs, inputs[left], inputs[right], 0,
|
||||
expected.carry0_result, expected.carry0_flags);
|
||||
AdcsSbcsHelper(&MacroAssembler::Adcs, inputs[left], inputs[right], 1,
|
||||
expected.carry1_result, expected.carry1_flags);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t left = 0; left < input_count; left++) {
|
||||
for (size_t right = 0; right < input_count; right++) {
|
||||
const Expected& expected = expected_sbcs_x[left][right];
|
||||
AdcsSbcsHelper(&MacroAssembler::Sbcs, inputs[left], inputs[right], 0,
|
||||
expected.carry0_result, expected.carry0_flags);
|
||||
AdcsSbcsHelper(&MacroAssembler::Sbcs, inputs[left], inputs[right], 1,
|
||||
expected.carry1_result, expected.carry1_flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(adcs_sbcs_w) {
|
||||
INIT_V8();
|
||||
uint32_t inputs[] = {
|
||||
0x00000000, 0x00000001, 0x7ffffffe, 0x7fffffff,
|
||||
0x80000000, 0x80000001, 0xfffffffe, 0xffffffff,
|
||||
};
|
||||
static const size_t input_count = sizeof(inputs) / sizeof(inputs[0]);
|
||||
|
||||
struct Expected {
|
||||
uint32_t carry0_result;
|
||||
StatusFlags carry0_flags;
|
||||
uint32_t carry1_result;
|
||||
StatusFlags carry1_flags;
|
||||
};
|
||||
|
||||
static const Expected expected_adcs_w[input_count][input_count] = {
|
||||
{{0x00000000, ZFlag, 0x00000001, NoFlag},
|
||||
{0x00000001, NoFlag, 0x00000002, NoFlag},
|
||||
{0x7ffffffe, NoFlag, 0x7fffffff, NoFlag},
|
||||
{0x7fffffff, NoFlag, 0x80000000, NVFlag},
|
||||
{0x80000000, NFlag, 0x80000001, NFlag},
|
||||
{0x80000001, NFlag, 0x80000002, NFlag},
|
||||
{0xfffffffe, NFlag, 0xffffffff, NFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag}},
|
||||
{{0x00000001, NoFlag, 0x00000002, NoFlag},
|
||||
{0x00000002, NoFlag, 0x00000003, NoFlag},
|
||||
{0x7fffffff, NoFlag, 0x80000000, NVFlag},
|
||||
{0x80000000, NVFlag, 0x80000001, NVFlag},
|
||||
{0x80000001, NFlag, 0x80000002, NFlag},
|
||||
{0x80000002, NFlag, 0x80000003, NFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0x00000000, ZCFlag, 0x00000001, CFlag}},
|
||||
{{0x7ffffffe, NoFlag, 0x7fffffff, NoFlag},
|
||||
{0x7fffffff, NoFlag, 0x80000000, NVFlag},
|
||||
{0xfffffffc, NVFlag, 0xfffffffd, NVFlag},
|
||||
{0xfffffffd, NVFlag, 0xfffffffe, NVFlag},
|
||||
{0xfffffffe, NFlag, 0xffffffff, NFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0x7ffffffc, CFlag, 0x7ffffffd, CFlag},
|
||||
{0x7ffffffd, CFlag, 0x7ffffffe, CFlag}},
|
||||
{{0x7fffffff, NoFlag, 0x80000000, NVFlag},
|
||||
{0x80000000, NVFlag, 0x80000001, NVFlag},
|
||||
{0xfffffffd, NVFlag, 0xfffffffe, NVFlag},
|
||||
{0xfffffffe, NVFlag, 0xffffffff, NVFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0x00000000, ZCFlag, 0x00000001, CFlag},
|
||||
{0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
|
||||
{0x7ffffffe, CFlag, 0x7fffffff, CFlag}},
|
||||
{{0x80000000, NFlag, 0x80000001, NFlag},
|
||||
{0x80000001, NFlag, 0x80000002, NFlag},
|
||||
{0xfffffffe, NFlag, 0xffffffff, NFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0x00000000, ZCVFlag, 0x00000001, CVFlag},
|
||||
{0x00000001, CVFlag, 0x00000002, CVFlag},
|
||||
{0x7ffffffe, CVFlag, 0x7fffffff, CVFlag},
|
||||
{0x7fffffff, CVFlag, 0x80000000, NCFlag}},
|
||||
{{0x80000001, NFlag, 0x80000002, NFlag},
|
||||
{0x80000002, NFlag, 0x80000003, NFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0x00000000, ZCFlag, 0x00000001, CFlag},
|
||||
{0x00000001, CVFlag, 0x00000002, CVFlag},
|
||||
{0x00000002, CVFlag, 0x00000003, CVFlag},
|
||||
{0x7fffffff, CVFlag, 0x80000000, NCFlag},
|
||||
{0x80000000, NCFlag, 0x80000001, NCFlag}},
|
||||
{{0xfffffffe, NFlag, 0xffffffff, NFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0x7ffffffc, CFlag, 0x7ffffffd, CFlag},
|
||||
{0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
|
||||
{0x7ffffffe, CVFlag, 0x7fffffff, CVFlag},
|
||||
{0x7fffffff, CVFlag, 0x80000000, NCFlag},
|
||||
{0xfffffffc, NCFlag, 0xfffffffd, NCFlag},
|
||||
{0xfffffffd, NCFlag, 0xfffffffe, NCFlag}},
|
||||
{{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0x00000000, ZCFlag, 0x00000001, CFlag},
|
||||
{0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
|
||||
{0x7ffffffe, CFlag, 0x7fffffff, CFlag},
|
||||
{0x7fffffff, CVFlag, 0x80000000, NCFlag},
|
||||
{0x80000000, NCFlag, 0x80000001, NCFlag},
|
||||
{0xfffffffd, NCFlag, 0xfffffffe, NCFlag},
|
||||
{0xfffffffe, NCFlag, 0xffffffff, NCFlag}}};
|
||||
|
||||
static const Expected expected_sbcs_w[input_count][input_count] = {
|
||||
{{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0xfffffffe, NFlag, 0xffffffff, NFlag},
|
||||
{0x80000001, NFlag, 0x80000002, NFlag},
|
||||
{0x80000000, NFlag, 0x80000001, NFlag},
|
||||
{0x7fffffff, NoFlag, 0x80000000, NVFlag},
|
||||
{0x7ffffffe, NoFlag, 0x7fffffff, NoFlag},
|
||||
{0x00000001, NoFlag, 0x00000002, NoFlag},
|
||||
{0x00000000, ZFlag, 0x00000001, NoFlag}},
|
||||
{{0x00000000, ZCFlag, 0x00000001, CFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0x80000002, NFlag, 0x80000003, NFlag},
|
||||
{0x80000001, NFlag, 0x80000002, NFlag},
|
||||
{0x80000000, NVFlag, 0x80000001, NVFlag},
|
||||
{0x7fffffff, NoFlag, 0x80000000, NVFlag},
|
||||
{0x00000002, NoFlag, 0x00000003, NoFlag},
|
||||
{0x00000001, NoFlag, 0x00000002, NoFlag}},
|
||||
{{0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
|
||||
{0x7ffffffc, CFlag, 0x7ffffffd, CFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0xfffffffe, NFlag, 0xffffffff, NFlag},
|
||||
{0xfffffffd, NVFlag, 0xfffffffe, NVFlag},
|
||||
{0xfffffffc, NVFlag, 0xfffffffd, NVFlag},
|
||||
{0x7fffffff, NoFlag, 0x80000000, NVFlag},
|
||||
{0x7ffffffe, NoFlag, 0x7fffffff, NoFlag}},
|
||||
{{0x7ffffffe, CFlag, 0x7fffffff, CFlag},
|
||||
{0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
|
||||
{0x00000000, ZCFlag, 0x00000001, CFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0xfffffffe, NVFlag, 0xffffffff, NVFlag},
|
||||
{0xfffffffd, NVFlag, 0xfffffffe, NVFlag},
|
||||
{0x80000000, NVFlag, 0x80000001, NVFlag},
|
||||
{0x7fffffff, NoFlag, 0x80000000, NVFlag}},
|
||||
{{0x7fffffff, CVFlag, 0x80000000, NCFlag},
|
||||
{0x7ffffffe, CVFlag, 0x7fffffff, CVFlag},
|
||||
{0x00000001, CVFlag, 0x00000002, CVFlag},
|
||||
{0x00000000, ZCVFlag, 0x00000001, CVFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0xfffffffe, NFlag, 0xffffffff, NFlag},
|
||||
{0x80000001, NFlag, 0x80000002, NFlag},
|
||||
{0x80000000, NFlag, 0x80000001, NFlag}},
|
||||
{{0x80000000, NCFlag, 0x80000001, NCFlag},
|
||||
{0x7fffffff, CVFlag, 0x80000000, NCFlag},
|
||||
{0x00000002, CVFlag, 0x00000003, CVFlag},
|
||||
{0x00000001, CVFlag, 0x00000002, CVFlag},
|
||||
{0x00000000, ZCFlag, 0x00000001, CFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0x80000002, NFlag, 0x80000003, NFlag},
|
||||
{0x80000001, NFlag, 0x80000002, NFlag}},
|
||||
{{0xfffffffd, NCFlag, 0xfffffffe, NCFlag},
|
||||
{0xfffffffc, NCFlag, 0xfffffffd, NCFlag},
|
||||
{0x7fffffff, CVFlag, 0x80000000, NCFlag},
|
||||
{0x7ffffffe, CVFlag, 0x7fffffff, CVFlag},
|
||||
{0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
|
||||
{0x7ffffffc, CFlag, 0x7ffffffd, CFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag},
|
||||
{0xfffffffe, NFlag, 0xffffffff, NFlag}},
|
||||
{{0xfffffffe, NCFlag, 0xffffffff, NCFlag},
|
||||
{0xfffffffd, NCFlag, 0xfffffffe, NCFlag},
|
||||
{0x80000000, NCFlag, 0x80000001, NCFlag},
|
||||
{0x7fffffff, CVFlag, 0x80000000, NCFlag},
|
||||
{0x7ffffffe, CFlag, 0x7fffffff, CFlag},
|
||||
{0x7ffffffd, CFlag, 0x7ffffffe, CFlag},
|
||||
{0x00000000, ZCFlag, 0x00000001, CFlag},
|
||||
{0xffffffff, NFlag, 0x00000000, ZCFlag}}};
|
||||
|
||||
for (size_t left = 0; left < input_count; left++) {
|
||||
for (size_t right = 0; right < input_count; right++) {
|
||||
const Expected& expected = expected_adcs_w[left][right];
|
||||
AdcsSbcsHelper(&MacroAssembler::Adcs, inputs[left], inputs[right], 0,
|
||||
expected.carry0_result, expected.carry0_flags);
|
||||
AdcsSbcsHelper(&MacroAssembler::Adcs, inputs[left], inputs[right], 1,
|
||||
expected.carry1_result, expected.carry1_flags);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t left = 0; left < input_count; left++) {
|
||||
for (size_t right = 0; right < input_count; right++) {
|
||||
const Expected& expected = expected_sbcs_w[left][right];
|
||||
AdcsSbcsHelper(&MacroAssembler::Sbcs, inputs[left], inputs[right], 0,
|
||||
expected.carry0_result, expected.carry0_flags);
|
||||
AdcsSbcsHelper(&MacroAssembler::Sbcs, inputs[left], inputs[right], 1,
|
||||
expected.carry1_result, expected.carry1_flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(adc_sbc_shift) {
|
||||
INIT_V8();
|
||||
SETUP();
|
||||
@ -3887,132 +4256,6 @@ TEST(adc_sbc_shift) {
|
||||
CHECK_EQUAL_32(0x91111110 + 1, w26);
|
||||
CHECK_EQUAL_32(0x9a222221 + 1, w27);
|
||||
|
||||
// Check that adc correctly sets the condition flags.
|
||||
START();
|
||||
__ Mov(x0, 1);
|
||||
__ Mov(x1, 0xffffffffffffffffL);
|
||||
// Clear the C flag.
|
||||
__ Adds(x0, x0, Operand(0));
|
||||
__ Adcs(x10, x0, Operand(x1));
|
||||
END();
|
||||
|
||||
RUN();
|
||||
|
||||
CHECK_EQUAL_NZCV(ZCFlag);
|
||||
CHECK_EQUAL_64(0, x10);
|
||||
|
||||
START();
|
||||
__ Mov(x0, 1);
|
||||
__ Mov(x1, 0x8000000000000000L);
|
||||
// Clear the C flag.
|
||||
__ Adds(x0, x0, Operand(0));
|
||||
__ Adcs(x10, x0, Operand(x1, ASR, 63));
|
||||
END();
|
||||
|
||||
RUN();
|
||||
|
||||
CHECK_EQUAL_NZCV(ZCFlag);
|
||||
CHECK_EQUAL_64(0, x10);
|
||||
|
||||
START();
|
||||
__ Mov(x0, 0x10);
|
||||
__ Mov(x1, 0x07ffffffffffffffL);
|
||||
// Clear the C flag.
|
||||
__ Adds(x0, x0, Operand(0));
|
||||
__ Adcs(x10, x0, Operand(x1, LSL, 4));
|
||||
END();
|
||||
|
||||
RUN();
|
||||
|
||||
CHECK_EQUAL_NZCV(NVFlag);
|
||||
CHECK_EQUAL_64(0x8000000000000000L, x10);
|
||||
|
||||
// Check that sbc correctly sets the condition flags.
|
||||
START();
|
||||
__ Mov(x0, 0);
|
||||
__ Mov(x1, 0xffffffffffffffffL);
|
||||
// Clear the C flag.
|
||||
__ Adds(x0, x0, Operand(0));
|
||||
__ Sbcs(x10, x0, Operand(x1));
|
||||
END();
|
||||
|
||||
RUN();
|
||||
|
||||
CHECK_EQUAL_NZCV(ZFlag);
|
||||
CHECK_EQUAL_64(0, x10);
|
||||
|
||||
START();
|
||||
__ Mov(x0, 1);
|
||||
__ Mov(x1, 0xffffffffffffffffL);
|
||||
// Clear the C flag.
|
||||
__ Adds(x0, x0, Operand(0));
|
||||
__ Sbcs(x10, x0, Operand(x1, LSR, 1));
|
||||
END();
|
||||
|
||||
RUN();
|
||||
|
||||
CHECK_EQUAL_NZCV(NFlag);
|
||||
CHECK_EQUAL_64(0x8000000000000001L, x10);
|
||||
|
||||
START();
|
||||
__ Mov(x0, 0);
|
||||
// Clear the C flag.
|
||||
__ Adds(x0, x0, Operand(0));
|
||||
__ Sbcs(x10, x0, Operand(0xffffffffffffffffL));
|
||||
END();
|
||||
|
||||
RUN();
|
||||
|
||||
CHECK_EQUAL_NZCV(ZFlag);
|
||||
CHECK_EQUAL_64(0, x10);
|
||||
|
||||
START()
|
||||
__ Mov(w0, 0x7fffffff);
|
||||
// Clear the C flag.
|
||||
__ Adds(x0, x0, Operand(0));
|
||||
__ Ngcs(w10, w0);
|
||||
END();
|
||||
|
||||
RUN();
|
||||
|
||||
CHECK_EQUAL_NZCV(NFlag);
|
||||
CHECK_EQUAL_64(0x80000000, x10);
|
||||
|
||||
START();
|
||||
// Clear the C flag.
|
||||
__ Adds(x0, x0, Operand(0));
|
||||
__ Ngcs(x10, 0x7fffffffffffffffL);
|
||||
END();
|
||||
|
||||
RUN();
|
||||
|
||||
CHECK_EQUAL_NZCV(NFlag);
|
||||
CHECK_EQUAL_64(0x8000000000000000L, x10);
|
||||
|
||||
START()
|
||||
__ Mov(x0, 0);
|
||||
// Set the C flag.
|
||||
__ Cmp(x0, Operand(x0));
|
||||
__ Sbcs(x10, x0, Operand(1));
|
||||
END();
|
||||
|
||||
RUN();
|
||||
|
||||
CHECK_EQUAL_NZCV(NFlag);
|
||||
CHECK_EQUAL_64(0xffffffffffffffffL, x10);
|
||||
|
||||
START()
|
||||
__ Mov(x0, 0);
|
||||
// Set the C flag.
|
||||
__ Cmp(x0, Operand(x0));
|
||||
__ Ngcs(x10, 0x7fffffffffffffffL);
|
||||
END();
|
||||
|
||||
RUN();
|
||||
|
||||
CHECK_EQUAL_NZCV(NFlag);
|
||||
CHECK_EQUAL_64(0x8000000000000001L, x10);
|
||||
|
||||
TEARDOWN();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user