Revert "Do away with variable length memcpy to Set/Get registers in simulator"

This reverts r21148, it broke tests in debug mode, e.g.
mjsunit/regress/regress-observe-map-cache or mjsunit/debug-stepout-scope-part5.

TBR=bmeurer@chromium.org

Review URL: https://codereview.chromium.org/296823014

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21449 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent e61b69f5
...@@ -823,29 +823,49 @@ int Simulator::CodeFromName(const char* name) { ...@@ -823,29 +823,49 @@ int Simulator::CodeFromName(const char* name) {
// Helpers --------------------------------------------------------------------- // Helpers ---------------------------------------------------------------------
template <typename T> int64_t Simulator::AddWithCarry(unsigned reg_size,
T Simulator::AddWithCarry(bool set_flags, bool set_flags,
T src1, int64_t src1,
T src2, int64_t src2,
T carry_in) { int64_t carry_in) {
typedef typename make_unsigned<T>::type unsignedT;
ASSERT((carry_in == 0) || (carry_in == 1)); ASSERT((carry_in == 0) || (carry_in == 1));
ASSERT((reg_size == kXRegSizeInBits) || (reg_size == kWRegSizeInBits));
T signed_sum = src1 + src2 + carry_in; uint64_t u1, u2;
T result = signed_sum; int64_t result;
int64_t signed_sum = src1 + src2 + carry_in;
bool N, Z, C, V; bool N, Z, C, V;
unsignedT u1 = static_cast<unsignedT>(src1);
unsignedT u2 = static_cast<unsignedT>(src2);
// Compute the C flag by comparing the sum to the max unsigned integer. if (reg_size == kWRegSizeInBits) {
C = ((std::numeric_limits<unsignedT>::max() - u1) < (u2 + carry_in)) || u1 = static_cast<uint64_t>(src1) & kWRegMask;
((std::numeric_limits<unsignedT>::max() - u1 - carry_in) < u2); u2 = static_cast<uint64_t>(src2) & kWRegMask;
// Overflow iff the sign bit is the same for the two inputs and different
// for the result. result = signed_sum & kWRegMask;
V = ((src1 ^ src2) >= 0) && ((src1 ^ result) < 0); // Compute the C flag by comparing the sum to the max unsigned integer.
C = ((kWMaxUInt - u1) < (u2 + carry_in)) ||
((kWMaxUInt - u1 - carry_in) < u2);
// Overflow iff the sign bit is the same for the two inputs and different
// for the result.
int64_t s_src1 = src1 << (kXRegSizeInBits - kWRegSizeInBits);
int64_t s_src2 = src2 << (kXRegSizeInBits - kWRegSizeInBits);
int64_t s_result = result << (kXRegSizeInBits - kWRegSizeInBits);
V = ((s_src1 ^ s_src2) >= 0) && ((s_src1 ^ s_result) < 0);
} else {
u1 = static_cast<uint64_t>(src1);
u2 = static_cast<uint64_t>(src2);
N = CalcNFlag(result); result = signed_sum;
// Compute the C flag by comparing the sum to the max unsigned integer.
C = ((kXMaxUInt - u1) < (u2 + carry_in)) ||
((kXMaxUInt - u1 - carry_in) < u2);
// 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, reg_size);
Z = CalcZFlag(result); Z = CalcZFlag(result);
if (set_flags) { if (set_flags) {
...@@ -858,42 +878,33 @@ T Simulator::AddWithCarry(bool set_flags, ...@@ -858,42 +878,33 @@ T Simulator::AddWithCarry(bool set_flags,
} }
template<typename T> int64_t Simulator::ShiftOperand(unsigned reg_size,
void Simulator::AddSubWithCarry(Instruction* instr) { int64_t value,
T op2 = reg<T>(instr->Rm()); Shift shift_type,
T new_val; unsigned amount) {
if ((instr->Mask(AddSubOpMask) == SUB) || instr->Mask(AddSubOpMask) == SUBS) {
op2 = ~op2;
}
new_val = AddWithCarry<T>(instr->FlagsUpdate(),
reg<T>(instr->Rn()),
op2,
nzcv().C());
set_reg<T>(instr->Rd(), new_val);
}
template <typename T>
T Simulator::ShiftOperand(T value, Shift shift_type, unsigned amount) {
typedef typename make_unsigned<T>::type unsignedT;
if (amount == 0) { if (amount == 0) {
return value; return value;
} }
int64_t mask = reg_size == kXRegSizeInBits ? kXRegMask : kWRegMask;
switch (shift_type) { switch (shift_type) {
case LSL: case LSL:
return value << amount; return (value << amount) & mask;
case LSR: case LSR:
return static_cast<unsignedT>(value) >> amount; return static_cast<uint64_t>(value) >> amount;
case ASR: case ASR: {
return value >> amount; // Shift used to restore the sign.
case ROR: unsigned s_shift = kXRegSizeInBits - reg_size;
return (static_cast<unsignedT>(value) >> amount) | // Value with its sign restored.
((value & ((1L << amount) - 1L)) << int64_t s_value = (value << s_shift) >> s_shift;
(sizeof(unsignedT) * 8 - amount)); return (s_value >> amount) & mask;
}
case ROR: {
if (reg_size == kWRegSizeInBits) {
value &= kWRegMask;
}
return (static_cast<uint64_t>(value) >> amount) |
((value & ((1L << amount) - 1L)) << (reg_size - amount));
}
default: default:
UNIMPLEMENTED(); UNIMPLEMENTED();
return 0; return 0;
...@@ -901,12 +912,10 @@ T Simulator::ShiftOperand(T value, Shift shift_type, unsigned amount) { ...@@ -901,12 +912,10 @@ T Simulator::ShiftOperand(T value, Shift shift_type, unsigned amount) {
} }
template <typename T> int64_t Simulator::ExtendValue(unsigned reg_size,
T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) { int64_t value,
const unsigned kSignExtendBShift = (sizeof(T) - 1) * 8; Extend extend_type,
const unsigned kSignExtendHShift = (sizeof(T) - 2) * 8; unsigned left_shift) {
const unsigned kSignExtendWShift = (sizeof(T) - 4) * 8;
switch (extend_type) { switch (extend_type) {
case UXTB: case UXTB:
value &= kByteMask; value &= kByteMask;
...@@ -918,13 +927,13 @@ T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) { ...@@ -918,13 +927,13 @@ T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) {
value &= kWordMask; value &= kWordMask;
break; break;
case SXTB: case SXTB:
value = (value << kSignExtendBShift) >> kSignExtendBShift; value = (value << 56) >> 56;
break; break;
case SXTH: case SXTH:
value = (value << kSignExtendHShift) >> kSignExtendHShift; value = (value << 48) >> 48;
break; break;
case SXTW: case SXTW:
value = (value << kSignExtendWShift) >> kSignExtendWShift; value = (value << 32) >> 32;
break; break;
case UXTX: case UXTX:
case SXTX: case SXTX:
...@@ -932,21 +941,8 @@ T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) { ...@@ -932,21 +941,8 @@ T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) {
default: default:
UNREACHABLE(); UNREACHABLE();
} }
return value << left_shift; int64_t mask = (reg_size == kXRegSizeInBits) ? kXRegMask : kWRegMask;
} return (value << left_shift) & mask;
template <typename T>
void Simulator::Extract(Instruction* instr) {
unsigned lsb = instr->ImmS();
T op2 = reg<T>(instr->Rm());
T result = op2;
if (lsb) {
T op1 = reg<T>(instr->Rn());
result = op2 >> lsb | (op1 << ((sizeof(T) * 8) - lsb));
}
set_reg<T>(instr->Rd(), result);
} }
...@@ -1260,110 +1256,110 @@ void Simulator::VisitCompareBranch(Instruction* instr) { ...@@ -1260,110 +1256,110 @@ void Simulator::VisitCompareBranch(Instruction* instr) {
} }
template<typename T> void Simulator::AddSubHelper(Instruction* instr, int64_t op2) {
void Simulator::AddSubHelper(Instruction* instr, T op2) { unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
: kWRegSizeInBits;
bool set_flags = instr->FlagsUpdate(); bool set_flags = instr->FlagsUpdate();
T new_val = 0; int64_t new_val = 0;
Instr operation = instr->Mask(AddSubOpMask); Instr operation = instr->Mask(AddSubOpMask);
switch (operation) { switch (operation) {
case ADD: case ADD:
case ADDS: { case ADDS: {
new_val = AddWithCarry<T>(set_flags, new_val = AddWithCarry(reg_size,
reg<T>(instr->Rn(), instr->RnMode()), set_flags,
op2); reg(reg_size, instr->Rn(), instr->RnMode()),
op2);
break; break;
} }
case SUB: case SUB:
case SUBS: { case SUBS: {
new_val = AddWithCarry<T>(set_flags, new_val = AddWithCarry(reg_size,
reg<T>(instr->Rn(), instr->RnMode()), set_flags,
~op2, reg(reg_size, instr->Rn(), instr->RnMode()),
1); ~op2,
1);
break; break;
} }
default: UNREACHABLE(); default: UNREACHABLE();
} }
set_reg<T>(instr->Rd(), new_val, instr->RdMode()); set_reg(reg_size, instr->Rd(), new_val, instr->RdMode());
} }
void Simulator::VisitAddSubShifted(Instruction* instr) { void Simulator::VisitAddSubShifted(Instruction* instr) {
Shift shift_type = static_cast<Shift>(instr->ShiftDP()); unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
unsigned shift_amount = instr->ImmDPShift(); : kWRegSizeInBits;
int64_t op2 = ShiftOperand(reg_size,
if (instr->SixtyFourBits()) { reg(reg_size, instr->Rm()),
int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount); static_cast<Shift>(instr->ShiftDP()),
AddSubHelper(instr, op2); instr->ImmDPShift());
} else { AddSubHelper(instr, op2);
int32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
AddSubHelper(instr, op2);
}
} }
void Simulator::VisitAddSubImmediate(Instruction* instr) { void Simulator::VisitAddSubImmediate(Instruction* instr) {
int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0); int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0);
if (instr->SixtyFourBits()) { AddSubHelper(instr, op2);
AddSubHelper<int64_t>(instr, op2);
} else {
AddSubHelper<int32_t>(instr, op2);
}
} }
void Simulator::VisitAddSubExtended(Instruction* instr) { void Simulator::VisitAddSubExtended(Instruction* instr) {
Extend ext = static_cast<Extend>(instr->ExtendMode()); unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
unsigned left_shift = instr->ImmExtendShift(); : kWRegSizeInBits;
if (instr->SixtyFourBits()) { int64_t op2 = ExtendValue(reg_size,
int64_t op2 = ExtendValue(xreg(instr->Rm()), ext, left_shift); reg(reg_size, instr->Rm()),
AddSubHelper(instr, op2); static_cast<Extend>(instr->ExtendMode()),
} else { instr->ImmExtendShift());
int32_t op2 = ExtendValue(wreg(instr->Rm()), ext, left_shift); AddSubHelper(instr, op2);
AddSubHelper(instr, op2);
}
} }
void Simulator::VisitAddSubWithCarry(Instruction* instr) { void Simulator::VisitAddSubWithCarry(Instruction* instr) {
if (instr->SixtyFourBits()) { unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
AddSubWithCarry<int64_t>(instr); : kWRegSizeInBits;
} else { int64_t op2 = reg(reg_size, instr->Rm());
AddSubWithCarry<int32_t>(instr); int64_t new_val;
if ((instr->Mask(AddSubOpMask) == SUB) || instr->Mask(AddSubOpMask) == SUBS) {
op2 = ~op2;
} }
new_val = AddWithCarry(reg_size,
instr->FlagsUpdate(),
reg(reg_size, instr->Rn()),
op2,
nzcv().C());
set_reg(reg_size, instr->Rd(), new_val);
} }
void Simulator::VisitLogicalShifted(Instruction* instr) { void Simulator::VisitLogicalShifted(Instruction* instr) {
unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
: kWRegSizeInBits;
Shift shift_type = static_cast<Shift>(instr->ShiftDP()); Shift shift_type = static_cast<Shift>(instr->ShiftDP());
unsigned shift_amount = instr->ImmDPShift(); unsigned shift_amount = instr->ImmDPShift();
int64_t op2 = ShiftOperand(reg_size, reg(reg_size, instr->Rm()), shift_type,
if (instr->SixtyFourBits()) { shift_amount);
int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount); if (instr->Mask(NOT) == NOT) {
op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2; op2 = ~op2;
LogicalHelper<int64_t>(instr, op2);
} else {
int32_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) { void Simulator::VisitLogicalImmediate(Instruction* instr) {
if (instr->SixtyFourBits()) { LogicalHelper(instr, instr->ImmLogical());
LogicalHelper<int64_t>(instr, instr->ImmLogical());
} else {
LogicalHelper<int32_t>(instr, instr->ImmLogical());
}
} }
template<typename T> void Simulator::LogicalHelper(Instruction* instr, int64_t op2) {
void Simulator::LogicalHelper(Instruction* instr, T op2) { unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
T op1 = reg<T>(instr->Rn()); : kWRegSizeInBits;
T result = 0; int64_t op1 = reg(reg_size, instr->Rn());
int64_t result = 0;
bool update_flags = false; bool update_flags = false;
// Switch on the logical operation, stripping out the NOT bit, as it has a // Switch on the logical operation, stripping out the NOT bit, as it has a
...@@ -1378,46 +1374,41 @@ void Simulator::LogicalHelper(Instruction* instr, T op2) { ...@@ -1378,46 +1374,41 @@ void Simulator::LogicalHelper(Instruction* instr, T op2) {
} }
if (update_flags) { if (update_flags) {
nzcv().SetN(CalcNFlag(result)); nzcv().SetN(CalcNFlag(result, reg_size));
nzcv().SetZ(CalcZFlag(result)); nzcv().SetZ(CalcZFlag(result));
nzcv().SetC(0); nzcv().SetC(0);
nzcv().SetV(0); nzcv().SetV(0);
} }
set_reg<T>(instr->Rd(), result, instr->RdMode()); set_reg(reg_size, instr->Rd(), result, instr->RdMode());
} }
void Simulator::VisitConditionalCompareRegister(Instruction* instr) { void Simulator::VisitConditionalCompareRegister(Instruction* instr) {
if (instr->SixtyFourBits()) { unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
ConditionalCompareHelper(instr, xreg(instr->Rm())); : kWRegSizeInBits;
} else { ConditionalCompareHelper(instr, reg(reg_size, instr->Rm()));
ConditionalCompareHelper(instr, wreg(instr->Rm()));
}
} }
void Simulator::VisitConditionalCompareImmediate(Instruction* instr) { void Simulator::VisitConditionalCompareImmediate(Instruction* instr) {
if (instr->SixtyFourBits()) { ConditionalCompareHelper(instr, instr->ImmCondCmp());
ConditionalCompareHelper<int64_t>(instr, instr->ImmCondCmp());
} else {
ConditionalCompareHelper<int32_t>(instr, instr->ImmCondCmp());
}
} }
template<typename T> void Simulator::ConditionalCompareHelper(Instruction* instr, int64_t op2) {
void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) { unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
T op1 = reg<T>(instr->Rn()); : kWRegSizeInBits;
int64_t op1 = reg(reg_size, instr->Rn());
if (ConditionPassed(static_cast<Condition>(instr->Condition()))) { if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
// If the condition passes, set the status flags to the result of comparing // If the condition passes, set the status flags to the result of comparing
// the operands. // the operands.
if (instr->Mask(ConditionalCompareMask) == CCMP) { if (instr->Mask(ConditionalCompareMask) == CCMP) {
AddWithCarry<T>(true, op1, ~op2, 1); AddWithCarry(reg_size, true, op1, ~op2, 1);
} else { } else {
ASSERT(instr->Mask(ConditionalCompareMask) == CCMN); ASSERT(instr->Mask(ConditionalCompareMask) == CCMN);
AddWithCarry<T>(true, op1, op2, 0); AddWithCarry(reg_size, true, op1, op2, 0);
} }
} else { } else {
// If the condition fails, set the status flags to the nzcv immediate. // If the condition fails, set the status flags to the nzcv immediate.
...@@ -1452,7 +1443,8 @@ void Simulator::VisitLoadStoreRegisterOffset(Instruction* instr) { ...@@ -1452,7 +1443,8 @@ void Simulator::VisitLoadStoreRegisterOffset(Instruction* instr) {
ASSERT((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX)); ASSERT((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX));
unsigned shift_amount = instr->ImmShiftLS() * instr->SizeLS(); unsigned shift_amount = instr->ImmShiftLS() * instr->SizeLS();
int64_t offset = ExtendValue(xreg(instr->Rm()), ext, shift_amount); int64_t offset = ExtendValue(kXRegSizeInBits, xreg(instr->Rm()), ext,
shift_amount);
LoadStoreHelper(instr, offset, Offset); LoadStoreHelper(instr, offset, Offset);
} }
...@@ -1492,23 +1484,28 @@ void Simulator::LoadStoreHelper(Instruction* instr, ...@@ -1492,23 +1484,28 @@ void Simulator::LoadStoreHelper(Instruction* instr,
case STR_w: case STR_w:
case STR_x: MemoryWrite(address, xreg(srcdst), num_bytes); break; case STR_x: MemoryWrite(address, xreg(srcdst), num_bytes); break;
case LDRSB_w: { case LDRSB_w: {
set_wreg(srcdst, ExtendValue<int32_t>(MemoryRead8(address), SXTB)); set_wreg(srcdst,
ExtendValue(kWRegSizeInBits, MemoryRead8(address), SXTB));
break; break;
} }
case LDRSB_x: { case LDRSB_x: {
set_xreg(srcdst, ExtendValue<int64_t>(MemoryRead8(address), SXTB)); set_xreg(srcdst,
ExtendValue(kXRegSizeInBits, MemoryRead8(address), SXTB));
break; break;
} }
case LDRSH_w: { case LDRSH_w: {
set_wreg(srcdst, ExtendValue<int32_t>(MemoryRead16(address), SXTH)); set_wreg(srcdst,
ExtendValue(kWRegSizeInBits, MemoryRead16(address), SXTH));
break; break;
} }
case LDRSH_x: { case LDRSH_x: {
set_xreg(srcdst, ExtendValue<int64_t>(MemoryRead16(address), SXTH)); set_xreg(srcdst,
ExtendValue(kXRegSizeInBits, MemoryRead16(address), SXTH));
break; break;
} }
case LDRSW_x: { case LDRSW_x: {
set_xreg(srcdst, ExtendValue<int64_t>(MemoryRead32(address), SXTW)); set_xreg(srcdst,
ExtendValue(kXRegSizeInBits, MemoryRead32(address), SXTW));
break; break;
} }
case LDR_s: set_sreg(srcdst, MemoryReadFP32(address)); break; case LDR_s: set_sreg(srcdst, MemoryReadFP32(address)); break;
...@@ -1608,8 +1605,8 @@ void Simulator::LoadStorePairHelper(Instruction* instr, ...@@ -1608,8 +1605,8 @@ void Simulator::LoadStorePairHelper(Instruction* instr,
break; break;
} }
case LDPSW_x: { case LDPSW_x: {
set_xreg(rt, ExtendValue<int64_t>(MemoryRead32(address), SXTW)); set_xreg(rt, ExtendValue(kXRegSizeInBits, MemoryRead32(address), SXTW));
set_xreg(rt2, ExtendValue<int64_t>( set_xreg(rt2, ExtendValue(kXRegSizeInBits,
MemoryRead32(address + kWRegSize), SXTW)); MemoryRead32(address + kWRegSize), SXTW));
break; break;
} }
...@@ -1825,26 +1822,25 @@ void Simulator::VisitMoveWideImmediate(Instruction* instr) { ...@@ -1825,26 +1822,25 @@ void Simulator::VisitMoveWideImmediate(Instruction* instr) {
void Simulator::VisitConditionalSelect(Instruction* instr) { void Simulator::VisitConditionalSelect(Instruction* instr) {
uint64_t new_val = xreg(instr->Rn());
if (ConditionFailed(static_cast<Condition>(instr->Condition()))) { if (ConditionFailed(static_cast<Condition>(instr->Condition()))) {
uint64_t new_val = xreg(instr->Rm()); new_val = xreg(instr->Rm());
switch (instr->Mask(ConditionalSelectMask)) { switch (instr->Mask(ConditionalSelectMask)) {
case CSEL_w: set_wreg(instr->Rd(), new_val); break; case CSEL_w:
case CSEL_x: set_xreg(instr->Rd(), new_val); break; case CSEL_x: break;
case CSINC_w: set_wreg(instr->Rd(), new_val + 1); break; case CSINC_w:
case CSINC_x: set_xreg(instr->Rd(), new_val + 1); break; case CSINC_x: new_val++; break;
case CSINV_w: set_wreg(instr->Rd(), ~new_val); break; case CSINV_w:
case CSINV_x: set_xreg(instr->Rd(), ~new_val); break; case CSINV_x: new_val = ~new_val; break;
case CSNEG_w: set_wreg(instr->Rd(), -new_val); break; case CSNEG_w:
case CSNEG_x: set_xreg(instr->Rd(), -new_val); break; case CSNEG_x: new_val = -new_val; break;
default: UNIMPLEMENTED(); default: UNIMPLEMENTED();
} }
} else {
if (instr->SixtyFourBits()) {
set_xreg(instr->Rd(), xreg(instr->Rn()));
} else {
set_wreg(instr->Rd(), wreg(instr->Rn()));
}
} }
unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
: kWRegSizeInBits;
set_reg(reg_size, instr->Rd(), new_val);
} }
...@@ -1915,17 +1911,28 @@ uint64_t Simulator::ReverseBytes(uint64_t value, ReverseByteMode mode) { ...@@ -1915,17 +1911,28 @@ uint64_t Simulator::ReverseBytes(uint64_t value, ReverseByteMode mode) {
} }
template <typename T> void Simulator::VisitDataProcessing2Source(Instruction* instr) {
void Simulator::DataProcessing2Source(Instruction* instr) {
Shift shift_op = NO_SHIFT; Shift shift_op = NO_SHIFT;
T result = 0; int64_t result = 0;
switch (instr->Mask(DataProcessing2SourceMask)) { switch (instr->Mask(DataProcessing2SourceMask)) {
case SDIV_w: case SDIV_w: {
int32_t rn = wreg(instr->Rn());
int32_t rm = wreg(instr->Rm());
if ((rn == kWMinInt) && (rm == -1)) {
result = kWMinInt;
} else if (rm == 0) {
// Division by zero can be trapped, but not on A-class processors.
result = 0;
} else {
result = rn / rm;
}
break;
}
case SDIV_x: { case SDIV_x: {
T rn = reg<T>(instr->Rn()); int64_t rn = xreg(instr->Rn());
T rm = reg<T>(instr->Rm()); int64_t rm = xreg(instr->Rm());
if ((rn == std::numeric_limits<T>::min()) && (rm == -1)) { if ((rn == kXMinInt) && (rm == -1)) {
result = std::numeric_limits<T>::min(); result = kXMinInt;
} else if (rm == 0) { } else if (rm == 0) {
// Division by zero can be trapped, but not on A-class processors. // Division by zero can be trapped, but not on A-class processors.
result = 0; result = 0;
...@@ -1934,11 +1941,20 @@ void Simulator::DataProcessing2Source(Instruction* instr) { ...@@ -1934,11 +1941,20 @@ void Simulator::DataProcessing2Source(Instruction* instr) {
} }
break; break;
} }
case UDIV_w: case UDIV_w: {
uint32_t rn = static_cast<uint32_t>(wreg(instr->Rn()));
uint32_t rm = static_cast<uint32_t>(wreg(instr->Rm()));
if (rm == 0) {
// Division by zero can be trapped, but not on A-class processors.
result = 0;
} else {
result = rn / rm;
}
break;
}
case UDIV_x: { case UDIV_x: {
typedef typename make_unsigned<T>::type unsignedT; uint64_t rn = static_cast<uint64_t>(xreg(instr->Rn()));
unsignedT rn = static_cast<unsignedT>(reg<T>(instr->Rn())); uint64_t rm = static_cast<uint64_t>(xreg(instr->Rm()));
unsignedT rm = static_cast<unsignedT>(reg<T>(instr->Rm()));
if (rm == 0) { if (rm == 0) {
// Division by zero can be trapped, but not on A-class processors. // Division by zero can be trapped, but not on A-class processors.
result = 0; result = 0;
...@@ -1958,27 +1974,18 @@ void Simulator::DataProcessing2Source(Instruction* instr) { ...@@ -1958,27 +1974,18 @@ void Simulator::DataProcessing2Source(Instruction* instr) {
default: UNIMPLEMENTED(); default: UNIMPLEMENTED();
} }
unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
: kWRegSizeInBits;
if (shift_op != NO_SHIFT) { if (shift_op != NO_SHIFT) {
// Shift distance encoded in the least-significant five/six bits of the // Shift distance encoded in the least-significant five/six bits of the
// register. // register.
unsigned shift = wreg(instr->Rm()); int mask = (instr->SixtyFourBits() == 1) ? kShiftAmountXRegMask
if (sizeof(T) == kWRegSize) { : kShiftAmountWRegMask;
shift &= kShiftAmountWRegMask; unsigned shift = wreg(instr->Rm()) & mask;
} else { result = ShiftOperand(reg_size, reg(reg_size, instr->Rn()), shift_op,
shift &= kShiftAmountXRegMask; shift);
}
result = ShiftOperand(reg<T>(instr->Rn()), shift_op, shift);
}
set_reg<T>(instr->Rd(), result);
}
void Simulator::VisitDataProcessing2Source(Instruction* instr) {
if (instr->SixtyFourBits()) {
DataProcessing2Source<int64_t>(instr);
} else {
DataProcessing2Source<int32_t>(instr);
} }
set_reg(reg_size, instr->Rd(), result);
} }
...@@ -2005,6 +2012,9 @@ static int64_t MultiplyHighSigned(int64_t u, int64_t v) { ...@@ -2005,6 +2012,9 @@ static int64_t MultiplyHighSigned(int64_t u, int64_t v) {
void Simulator::VisitDataProcessing3Source(Instruction* instr) { void Simulator::VisitDataProcessing3Source(Instruction* instr) {
unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
: kWRegSizeInBits;
int64_t result = 0; int64_t result = 0;
// Extract and sign- or zero-extend 32-bit arguments for widening operations. // Extract and sign- or zero-extend 32-bit arguments for widening operations.
uint64_t rn_u32 = reg<uint32_t>(instr->Rn()); uint64_t rn_u32 = reg<uint32_t>(instr->Rn());
...@@ -2030,26 +2040,21 @@ void Simulator::VisitDataProcessing3Source(Instruction* instr) { ...@@ -2030,26 +2040,21 @@ void Simulator::VisitDataProcessing3Source(Instruction* instr) {
break; break;
default: UNIMPLEMENTED(); default: UNIMPLEMENTED();
} }
set_reg(reg_size, instr->Rd(), result);
if (instr->SixtyFourBits()) {
set_xreg(instr->Rd(), result);
} else {
set_wreg(instr->Rd(), result);
}
} }
template <typename T> void Simulator::VisitBitfield(Instruction* instr) {
void Simulator::BitfieldHelper(Instruction* instr) { unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits
typedef typename make_unsigned<T>::type unsignedT; : kWRegSizeInBits;
T reg_size = sizeof(T) * 8; int64_t reg_mask = instr->SixtyFourBits() ? kXRegMask : kWRegMask;
T R = instr->ImmR(); int64_t R = instr->ImmR();
T S = instr->ImmS(); int64_t S = instr->ImmS();
T diff = S - R; int64_t diff = S - R;
T mask; int64_t mask;
if (diff >= 0) { if (diff >= 0) {
mask = diff < reg_size - 1 ? (static_cast<T>(1) << (diff + 1)) - 1 mask = diff < reg_size - 1 ? (1L << (diff + 1)) - 1
: static_cast<T>(-1); : reg_mask;
} else { } else {
mask = ((1L << (S + 1)) - 1); mask = ((1L << (S + 1)) - 1);
mask = (static_cast<uint64_t>(mask) >> R) | (mask << (reg_size - R)); mask = (static_cast<uint64_t>(mask) >> R) | (mask << (reg_size - R));
...@@ -2078,37 +2083,30 @@ void Simulator::BitfieldHelper(Instruction* instr) { ...@@ -2078,37 +2083,30 @@ void Simulator::BitfieldHelper(Instruction* instr) {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
T dst = inzero ? 0 : reg<T>(instr->Rd()); int64_t dst = inzero ? 0 : reg(reg_size, instr->Rd());
T src = reg<T>(instr->Rn()); int64_t src = reg(reg_size, instr->Rn());
// Rotate source bitfield into place. // Rotate source bitfield into place.
T result = (static_cast<unsignedT>(src) >> R) | (src << (reg_size - R)); int64_t result = (static_cast<uint64_t>(src) >> R) | (src << (reg_size - R));
// Determine the sign extension. // Determine the sign extension.
T topbits_preshift = (static_cast<T>(1) << (reg_size - diff - 1)) - 1; int64_t topbits_preshift = (1L << (reg_size - diff - 1)) - 1;
T signbits = (extend && ((src >> S) & 1) ? topbits_preshift : 0) int64_t signbits = (extend && ((src >> S) & 1) ? topbits_preshift : 0)
<< (diff + 1); << (diff + 1);
// Merge sign extension, dest/zero and bitfield. // Merge sign extension, dest/zero and bitfield.
result = signbits | (result & mask) | (dst & ~mask); result = signbits | (result & mask) | (dst & ~mask);
set_reg<T>(instr->Rd(), result); set_reg(reg_size, instr->Rd(), result);
}
void Simulator::VisitBitfield(Instruction* instr) {
if (instr->SixtyFourBits()) {
BitfieldHelper<int64_t>(instr);
} else {
BitfieldHelper<int32_t>(instr);
}
} }
void Simulator::VisitExtract(Instruction* instr) { void Simulator::VisitExtract(Instruction* instr) {
if (instr->SixtyFourBits()) { unsigned lsb = instr->ImmS();
Extract<uint64_t>(instr); unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits
} else { : kWRegSizeInBits;
Extract<uint32_t>(instr); set_reg(reg_size,
} instr->Rd(),
(static_cast<uint64_t>(reg(reg_size, instr->Rm())) >> lsb) |
(reg(reg_size, instr->Rn()) << (reg_size - lsb)));
} }
......
...@@ -133,28 +133,35 @@ class SimSystemRegister { ...@@ -133,28 +133,35 @@ class SimSystemRegister {
// Represent a register (r0-r31, v0-v31). // Represent a register (r0-r31, v0-v31).
template<int kSizeInBytes>
class SimRegisterBase { class SimRegisterBase {
public: public:
template<typename T> template<typename T>
void Set(T new_value) { void Set(T new_value, unsigned size = sizeof(T)) {
value_ = 0; ASSERT(size <= kSizeInBytes);
memcpy(&value_, &new_value, sizeof(T)); ASSERT(size <= sizeof(new_value));
// All AArch64 registers are zero-extending; Writing a W register clears the
// top bits of the corresponding X register.
memset(value_, 0, kSizeInBytes);
memcpy(value_, &new_value, size);
} }
// Copy 'size' bytes of the register to the result, and zero-extend to fill
// the result.
template<typename T> template<typename T>
T Get() const { T Get(unsigned size = sizeof(T)) const {
ASSERT(size <= kSizeInBytes);
T result; T result;
memcpy(&result, &value_, sizeof(T)); memset(&result, 0, sizeof(result));
memcpy(&result, value_, size);
return result; return result;
} }
protected: protected:
int64_t value_; uint8_t value_[kSizeInBytes];
}; };
typedef SimRegisterBase<kXRegSize> SimRegister; // r0-r31
typedef SimRegisterBase<kDRegSize> SimFPRegister; // v0-v31
typedef SimRegisterBase SimRegister; // r0-r31
typedef SimRegisterBase SimFPRegister; // v0-v31
class Simulator : public DecoderVisitor { class Simulator : public DecoderVisitor {
...@@ -321,53 +328,86 @@ class Simulator : public DecoderVisitor { ...@@ -321,53 +328,86 @@ class Simulator : public DecoderVisitor {
VISITOR_LIST(DECLARE) VISITOR_LIST(DECLARE)
#undef DECLARE #undef DECLARE
bool IsZeroRegister(unsigned code, Reg31Mode r31mode) const {
return ((code == 31) && (r31mode == Reg31IsZeroRegister));
}
// Register accessors. // Register accessors.
// Return 'size' bits of the value of an integer register, as the specified // Return 'size' bits of the value of an integer register, as the specified
// type. The value is zero-extended to fill the result. // type. The value is zero-extended to fill the result.
// //
// The only supported values of 'size' are kXRegSizeInBits and
// kWRegSizeInBits.
template<typename T> template<typename T>
T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { T reg(unsigned size, unsigned code,
Reg31Mode r31mode = Reg31IsZeroRegister) const {
unsigned size_in_bytes = size / 8;
ASSERT(size_in_bytes <= sizeof(T));
ASSERT((size == kXRegSizeInBits) || (size == kWRegSizeInBits));
ASSERT(code < kNumberOfRegisters); ASSERT(code < kNumberOfRegisters);
if (IsZeroRegister(code, r31mode)) {
return 0; if ((code == 31) && (r31mode == Reg31IsZeroRegister)) {
T result;
memset(&result, 0, sizeof(result));
return result;
} }
return registers_[code].Get<T>(); return registers_[code].Get<T>(size_in_bytes);
}
// Like reg(), but infer the access size from the template type.
template<typename T>
T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
return reg<T>(sizeof(T) * 8, code, r31mode);
} }
// Common specialized accessors for the reg() template. // Common specialized accessors for the reg() template.
int32_t wreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { int32_t wreg(unsigned code,
Reg31Mode r31mode = Reg31IsZeroRegister) const {
return reg<int32_t>(code, r31mode); return reg<int32_t>(code, r31mode);
} }
int64_t xreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { int64_t xreg(unsigned code,
Reg31Mode r31mode = Reg31IsZeroRegister) const {
return reg<int64_t>(code, r31mode); return reg<int64_t>(code, r31mode);
} }
int64_t reg(unsigned size, unsigned code,
Reg31Mode r31mode = Reg31IsZeroRegister) const {
return reg<int64_t>(size, code, r31mode);
}
// Write 'size' bits of 'value' into an integer register. The value is // Write 'size' bits of 'value' into an integer register. The value is
// zero-extended. This behaviour matches AArch64 register writes. // zero-extended. This behaviour matches AArch64 register writes.
//
// The only supported values of 'size' are kXRegSizeInBits and
// kWRegSizeInBits.
template<typename T>
void set_reg(unsigned size, unsigned code, T value,
Reg31Mode r31mode = Reg31IsZeroRegister) {
unsigned size_in_bytes = size / 8;
ASSERT(size_in_bytes <= sizeof(T));
ASSERT((size == kXRegSizeInBits) || (size == kWRegSizeInBits));
ASSERT(code < kNumberOfRegisters);
if ((code == 31) && (r31mode == Reg31IsZeroRegister)) {
return;
}
return registers_[code].Set(value, size_in_bytes);
}
// Like set_reg(), but infer the access size from the template type. // Like set_reg(), but infer the access size from the template type.
template<typename T> template<typename T>
void set_reg(unsigned code, T value, void set_reg(unsigned code, T value,
Reg31Mode r31mode = Reg31IsZeroRegister) { Reg31Mode r31mode = Reg31IsZeroRegister) {
ASSERT(code < kNumberOfRegisters); set_reg(sizeof(value) * 8, code, value, r31mode);
if (!IsZeroRegister(code, r31mode))
registers_[code].Set(value);
} }
// Common specialized accessors for the set_reg() template. // Common specialized accessors for the set_reg() template.
void set_wreg(unsigned code, int32_t value, void set_wreg(unsigned code, int32_t value,
Reg31Mode r31mode = Reg31IsZeroRegister) { Reg31Mode r31mode = Reg31IsZeroRegister) {
set_reg(code, value, r31mode); set_reg(kWRegSizeInBits, code, value, r31mode);
} }
void set_xreg(unsigned code, int64_t value, void set_xreg(unsigned code, int64_t value,
Reg31Mode r31mode = Reg31IsZeroRegister) { Reg31Mode r31mode = Reg31IsZeroRegister) {
set_reg(code, value, r31mode); set_reg(kXRegSizeInBits, code, value, r31mode);
} }
// Commonly-used special cases. // Commonly-used special cases.
...@@ -392,10 +432,24 @@ class Simulator : public DecoderVisitor { ...@@ -392,10 +432,24 @@ class Simulator : public DecoderVisitor {
Address get_sp() { return reg<Address>(31, Reg31IsStackPointer); } Address get_sp() { return reg<Address>(31, Reg31IsStackPointer); }
// Return 'size' bits of the value of a floating-point register, as the
// specified type. The value is zero-extended to fill the result.
//
// The only supported values of 'size' are kDRegSizeInBits and
// kSRegSizeInBits.
template<typename T>
T fpreg(unsigned size, unsigned code) const {
unsigned size_in_bytes = size / 8;
ASSERT(size_in_bytes <= sizeof(T));
ASSERT((size == kDRegSizeInBits) || (size == kSRegSizeInBits));
ASSERT(code < kNumberOfFPRegisters);
return fpregisters_[code].Get<T>(size_in_bytes);
}
// Like fpreg(), but infer the access size from the template type.
template<typename T> template<typename T>
T fpreg(unsigned code) const { T fpreg(unsigned code) const {
ASSERT(code < kNumberOfRegisters); return fpreg<T>(sizeof(T) * 8, code);
return fpregisters_[code].Get<T>();
} }
// Common specialized accessors for the fpreg() template. // Common specialized accessors for the fpreg() template.
...@@ -431,7 +485,7 @@ class Simulator : public DecoderVisitor { ...@@ -431,7 +485,7 @@ class Simulator : public DecoderVisitor {
void set_fpreg(unsigned code, T value) { void set_fpreg(unsigned code, T value) {
ASSERT((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize)); ASSERT((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize));
ASSERT(code < kNumberOfFPRegisters); ASSERT(code < kNumberOfFPRegisters);
fpregisters_[code].Set(value); fpregisters_[code].Set(value, sizeof(value));
} }
// Common specialized accessors for the set_fpreg() template. // Common specialized accessors for the set_fpreg() template.
...@@ -571,19 +625,14 @@ class Simulator : public DecoderVisitor { ...@@ -571,19 +625,14 @@ class Simulator : public DecoderVisitor {
return !ConditionPassed(cond); return !ConditionPassed(cond);
} }
template<typename T> void AddSubHelper(Instruction* instr, int64_t op2);
void AddSubHelper(Instruction* instr, T op2); int64_t AddWithCarry(unsigned reg_size,
template<typename T> bool set_flags,
T AddWithCarry(bool set_flags, int64_t src1,
T src1, int64_t src2,
T src2, int64_t carry_in = 0);
T carry_in = 0); void LogicalHelper(Instruction* instr, int64_t op2);
template<typename T> void ConditionalCompareHelper(Instruction* instr, int64_t op2);
void AddSubWithCarry(Instruction* instr);
template<typename T>
void LogicalHelper(Instruction* instr, T op2);
template<typename T>
void ConditionalCompareHelper(Instruction* instr, T op2);
void LoadStoreHelper(Instruction* instr, void LoadStoreHelper(Instruction* instr,
int64_t offset, int64_t offset,
AddrMode addrmode); AddrMode addrmode);
...@@ -610,21 +659,18 @@ class Simulator : public DecoderVisitor { ...@@ -610,21 +659,18 @@ class Simulator : public DecoderVisitor {
void MemoryWrite64(uint8_t* address, uint64_t value); void MemoryWrite64(uint8_t* address, uint64_t value);
void MemoryWriteFP64(uint8_t* address, double value); void MemoryWriteFP64(uint8_t* address, double value);
int64_t ShiftOperand(unsigned reg_size,
template <typename T> int64_t value,
T ShiftOperand(T value, Shift shift_type,
unsigned amount);
int64_t Rotate(unsigned reg_width,
int64_t value,
Shift shift_type, Shift shift_type,
unsigned amount); unsigned amount);
template <typename T> int64_t ExtendValue(unsigned reg_width,
T ExtendValue(T value, int64_t value,
Extend extend_type, Extend extend_type,
unsigned left_shift = 0); unsigned left_shift = 0);
template <typename T>
void Extract(Instruction* instr);
template <typename T>
void DataProcessing2Source(Instruction* instr);
template <typename T>
void BitfieldHelper(Instruction* instr);
uint64_t ReverseBits(uint64_t value, unsigned num_bits); uint64_t ReverseBits(uint64_t value, unsigned num_bits);
uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode); uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode);
...@@ -750,9 +796,8 @@ class Simulator : public DecoderVisitor { ...@@ -750,9 +796,8 @@ class Simulator : public DecoderVisitor {
// is irrelevant, and is not checked here. // is irrelevant, and is not checked here.
} }
template <typename T> static int CalcNFlag(uint64_t result, unsigned reg_size) {
static int CalcNFlag(T result) { return (result >> (reg_size - 1)) & 1;
return (result >> (sizeof(T) * 8 - 1)) & 1;
} }
static int CalcZFlag(uint64_t result) { static int CalcZFlag(uint64_t result) {
......
...@@ -233,25 +233,6 @@ inline int32_t WhichPowerOf2Abs(int32_t x) { ...@@ -233,25 +233,6 @@ inline int32_t WhichPowerOf2Abs(int32_t x) {
} }
// Obtains the unsigned type corresponding to T
// available in C++11 as std::make_unsigned
template<typename T>
struct make_unsigned {
typedef T type;
};
// Template specializations necessary to have make_unsigned work
template<> struct make_unsigned<int32_t> {
typedef uint32_t type;
};
template<> struct make_unsigned<int64_t> {
typedef uint64_t type;
};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// BitField is a help template for encoding and decode bitfield with // BitField is a help template for encoding and decode bitfield with
// unsigned content. // unsigned content.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment