Index: src/arm64/simulator-arm64.cc |
diff --git a/src/arm64/simulator-arm64.cc b/src/arm64/simulator-arm64.cc |
index 1ae57e9e2f1fcedba8cd1db7d3eb55e1372cde59..6cc9082a3380dc752383d62362d47ec3db0306b7 100644 |
--- a/src/arm64/simulator-arm64.cc |
+++ b/src/arm64/simulator-arm64.cc |
@@ -823,49 +823,30 @@ int Simulator::CodeFromName(const char* name) { |
// Helpers --------------------------------------------------------------------- |
-int64_t Simulator::AddWithCarry(unsigned reg_size, |
- bool set_flags, |
- int64_t src1, |
- int64_t src2, |
- int64_t carry_in) { |
+template <typename T> |
+T Simulator::AddWithCarry(bool set_flags, |
+ T src1, |
+ T src2, |
+ T carry_in) { |
+ typedef typename make_unsigned<T>::type unsignedT; |
ASSERT((carry_in == 0) || (carry_in == 1)); |
- ASSERT((reg_size == kXRegSizeInBits) || (reg_size == kWRegSizeInBits)); |
- uint64_t u1, u2; |
- int64_t result; |
- int64_t signed_sum = src1 + src2 + carry_in; |
+ T signed_sum = src1 + src2 + carry_in; |
+ T result = signed_sum; |
bool N, Z, C, V; |
- if (reg_size == kWRegSizeInBits) { |
- u1 = static_cast<uint64_t>(src1) & kWRegMask; |
- u2 = static_cast<uint64_t>(src2) & kWRegMask; |
- |
- result = signed_sum & kWRegMask; |
- // 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); |
+ // Compute the C flag |
Fritz
2014/05/27 23:07:03
Using the logic from the arm simulator here. I do
|
+ 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)))); |
- 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); |
- } |
+ // 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); |
+ N = CalcNFlag(result); |
Z = CalcZFlag(result); |
if (set_flags) { |
@@ -878,33 +859,42 @@ int64_t Simulator::AddWithCarry(unsigned reg_size, |
} |
-int64_t Simulator::ShiftOperand(unsigned reg_size, |
- int64_t value, |
- Shift shift_type, |
- unsigned amount) { |
+template<typename T> |
+void Simulator::AddSubWithCarry(Instruction* instr) { |
+ T op2 = reg<T>(instr->Rm()); |
+ T new_val; |
+ |
+ 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) { |
return value; |
} |
- int64_t mask = reg_size == kXRegSizeInBits ? kXRegMask : kWRegMask; |
+ |
switch (shift_type) { |
case LSL: |
- return (value << amount) & mask; |
+ return value << amount; |
case LSR: |
- return static_cast<uint64_t>(value) >> amount; |
- case ASR: { |
- // Shift used to restore the sign. |
- unsigned s_shift = kXRegSizeInBits - reg_size; |
- // Value with its sign restored. |
- int64_t s_value = (value << s_shift) >> s_shift; |
- 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)); |
- } |
+ return static_cast<unsignedT>(value) >> amount; |
+ case ASR: |
+ return value >> amount; |
+ case ROR: |
+ return (static_cast<unsignedT>(value) >> amount) | |
+ ((value & ((1L << amount) - 1L)) << |
+ (sizeof(unsignedT) * 8 - amount)); |
default: |
UNIMPLEMENTED(); |
return 0; |
@@ -912,10 +902,12 @@ int64_t Simulator::ShiftOperand(unsigned reg_size, |
} |
-int64_t Simulator::ExtendValue(unsigned reg_size, |
- int64_t value, |
- Extend extend_type, |
- unsigned left_shift) { |
+template <typename T> |
+T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) { |
+ const unsigned kSignExtendBShift = (sizeof(T) - 1) * 8; |
+ const unsigned kSignExtendHShift = (sizeof(T) - 2) * 8; |
+ const unsigned kSignExtendWShift = (sizeof(T) - 4) * 8; |
+ |
switch (extend_type) { |
case UXTB: |
value &= kByteMask; |
@@ -927,13 +919,13 @@ int64_t Simulator::ExtendValue(unsigned reg_size, |
value &= kWordMask; |
break; |
case SXTB: |
- value = (value << 56) >> 56; |
+ value = (value << kSignExtendBShift) >> kSignExtendBShift; |
break; |
case SXTH: |
- value = (value << 48) >> 48; |
+ value = (value << kSignExtendHShift) >> kSignExtendHShift; |
break; |
case SXTW: |
- value = (value << 32) >> 32; |
+ value = (value << kSignExtendWShift) >> kSignExtendWShift; |
break; |
case UXTX: |
case SXTX: |
@@ -941,8 +933,21 @@ int64_t Simulator::ExtendValue(unsigned reg_size, |
default: |
UNREACHABLE(); |
} |
- int64_t mask = (reg_size == kXRegSizeInBits) ? kXRegMask : kWRegMask; |
- return (value << left_shift) & mask; |
+ return value << left_shift; |
+} |
+ |
+ |
+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); |
} |
@@ -1256,110 +1261,110 @@ void Simulator::VisitCompareBranch(Instruction* instr) { |
} |
-void Simulator::AddSubHelper(Instruction* instr, int64_t op2) { |
- unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits |
- : kWRegSizeInBits; |
+template<typename T> |
+void Simulator::AddSubHelper(Instruction* instr, T op2) { |
bool set_flags = instr->FlagsUpdate(); |
- int64_t new_val = 0; |
+ T new_val = 0; |
Instr operation = instr->Mask(AddSubOpMask); |
switch (operation) { |
case ADD: |
case ADDS: { |
- new_val = AddWithCarry(reg_size, |
- set_flags, |
- reg(reg_size, instr->Rn(), instr->RnMode()), |
- op2); |
+ new_val = AddWithCarry<T>(set_flags, |
+ reg<T>(instr->Rn(), instr->RnMode()), |
+ op2); |
break; |
} |
case SUB: |
case SUBS: { |
- new_val = AddWithCarry(reg_size, |
- set_flags, |
- reg(reg_size, instr->Rn(), instr->RnMode()), |
- ~op2, |
- 1); |
+ new_val = AddWithCarry<T>(set_flags, |
+ reg<T>(instr->Rn(), instr->RnMode()), |
+ ~op2, |
+ 1); |
break; |
} |
default: UNREACHABLE(); |
} |
- set_reg(reg_size, instr->Rd(), new_val, instr->RdMode()); |
+ set_reg<T>(instr->Rd(), new_val, instr->RdMode()); |
} |
void Simulator::VisitAddSubShifted(Instruction* instr) { |
- unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits |
- : kWRegSizeInBits; |
- int64_t op2 = ShiftOperand(reg_size, |
- reg(reg_size, instr->Rm()), |
- static_cast<Shift>(instr->ShiftDP()), |
- instr->ImmDPShift()); |
- AddSubHelper(instr, op2); |
+ Shift shift_type = static_cast<Shift>(instr->ShiftDP()); |
+ unsigned shift_amount = instr->ImmDPShift(); |
+ |
+ if (instr->SixtyFourBits()) { |
+ int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount); |
+ AddSubHelper(instr, op2); |
+ } else { |
+ int32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount); |
+ AddSubHelper(instr, op2); |
+ } |
} |
void Simulator::VisitAddSubImmediate(Instruction* instr) { |
int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0); |
- AddSubHelper(instr, op2); |
+ if (instr->SixtyFourBits()) { |
+ AddSubHelper<int64_t>(instr, op2); |
+ } else { |
+ AddSubHelper<int32_t>(instr, op2); |
+ } |
} |
void Simulator::VisitAddSubExtended(Instruction* instr) { |
- unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits |
- : kWRegSizeInBits; |
- int64_t op2 = ExtendValue(reg_size, |
- reg(reg_size, instr->Rm()), |
- static_cast<Extend>(instr->ExtendMode()), |
- instr->ImmExtendShift()); |
- AddSubHelper(instr, op2); |
+ 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); |
+ AddSubHelper(instr, op2); |
+ } else { |
+ int32_t op2 = ExtendValue(wreg(instr->Rm()), ext, left_shift); |
+ AddSubHelper(instr, op2); |
+ } |
} |
void Simulator::VisitAddSubWithCarry(Instruction* instr) { |
- unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits |
- : kWRegSizeInBits; |
- int64_t op2 = reg(reg_size, instr->Rm()); |
- int64_t new_val; |
- |
- if ((instr->Mask(AddSubOpMask) == SUB) || instr->Mask(AddSubOpMask) == SUBS) { |
- op2 = ~op2; |
+ if (instr->SixtyFourBits()) { |
+ AddSubWithCarry<int64_t>(instr); |
+ } else { |
+ AddSubWithCarry<int32_t>(instr); |
} |
- |
- 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) { |
- unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits |
- : kWRegSizeInBits; |
Shift shift_type = static_cast<Shift>(instr->ShiftDP()); |
unsigned shift_amount = instr->ImmDPShift(); |
- int64_t op2 = ShiftOperand(reg_size, reg(reg_size, instr->Rm()), shift_type, |
- shift_amount); |
- if (instr->Mask(NOT) == NOT) { |
- op2 = ~op2; |
+ |
+ if (instr->SixtyFourBits()) { |
+ int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount); |
+ op2 = (instr->Mask(NOT) == NOT) ? ~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) { |
- LogicalHelper(instr, instr->ImmLogical()); |
+ if (instr->SixtyFourBits()) { |
+ LogicalHelper<int64_t>(instr, instr->ImmLogical()); |
+ } else { |
+ LogicalHelper<int32_t>(instr, instr->ImmLogical()); |
+ } |
} |
-void Simulator::LogicalHelper(Instruction* instr, int64_t op2) { |
- unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits |
- : kWRegSizeInBits; |
- int64_t op1 = reg(reg_size, instr->Rn()); |
- int64_t result = 0; |
+template<typename T> |
+void Simulator::LogicalHelper(Instruction* instr, T op2) { |
+ T op1 = reg<T>(instr->Rn()); |
+ T result = 0; |
bool update_flags = false; |
// Switch on the logical operation, stripping out the NOT bit, as it has a |
@@ -1374,41 +1379,46 @@ void Simulator::LogicalHelper(Instruction* instr, int64_t op2) { |
} |
if (update_flags) { |
- nzcv().SetN(CalcNFlag(result, reg_size)); |
+ nzcv().SetN(CalcNFlag(result)); |
nzcv().SetZ(CalcZFlag(result)); |
nzcv().SetC(0); |
nzcv().SetV(0); |
} |
- set_reg(reg_size, instr->Rd(), result, instr->RdMode()); |
+ set_reg<T>(instr->Rd(), result, instr->RdMode()); |
} |
void Simulator::VisitConditionalCompareRegister(Instruction* instr) { |
- unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits |
- : kWRegSizeInBits; |
- ConditionalCompareHelper(instr, reg(reg_size, instr->Rm())); |
+ if (instr->SixtyFourBits()) { |
+ ConditionalCompareHelper(instr, xreg(instr->Rm())); |
+ } else { |
+ ConditionalCompareHelper(instr, wreg(instr->Rm())); |
+ } |
} |
void Simulator::VisitConditionalCompareImmediate(Instruction* instr) { |
- ConditionalCompareHelper(instr, instr->ImmCondCmp()); |
+ if (instr->SixtyFourBits()) { |
+ ConditionalCompareHelper<int64_t>(instr, instr->ImmCondCmp()); |
+ } else { |
+ ConditionalCompareHelper<int32_t>(instr, instr->ImmCondCmp()); |
+ } |
} |
-void Simulator::ConditionalCompareHelper(Instruction* instr, int64_t op2) { |
- unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits |
- : kWRegSizeInBits; |
- int64_t op1 = reg(reg_size, instr->Rn()); |
+template<typename T> |
+void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) { |
+ T op1 = reg<T>(instr->Rn()); |
if (ConditionPassed(static_cast<Condition>(instr->Condition()))) { |
// If the condition passes, set the status flags to the result of comparing |
// the operands. |
if (instr->Mask(ConditionalCompareMask) == CCMP) { |
- AddWithCarry(reg_size, true, op1, ~op2, 1); |
+ AddWithCarry<T>(true, op1, ~op2, 1); |
} else { |
ASSERT(instr->Mask(ConditionalCompareMask) == CCMN); |
- AddWithCarry(reg_size, true, op1, op2, 0); |
+ AddWithCarry<T>(true, op1, op2, 0); |
} |
} else { |
// If the condition fails, set the status flags to the nzcv immediate. |
@@ -1443,8 +1453,7 @@ void Simulator::VisitLoadStoreRegisterOffset(Instruction* instr) { |
ASSERT((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX)); |
unsigned shift_amount = instr->ImmShiftLS() * instr->SizeLS(); |
- int64_t offset = ExtendValue(kXRegSizeInBits, xreg(instr->Rm()), ext, |
- shift_amount); |
+ int64_t offset = ExtendValue(xreg(instr->Rm()), ext, shift_amount); |
LoadStoreHelper(instr, offset, Offset); |
} |
@@ -1484,28 +1493,23 @@ void Simulator::LoadStoreHelper(Instruction* instr, |
case STR_w: |
case STR_x: MemoryWrite(address, xreg(srcdst), num_bytes); break; |
case LDRSB_w: { |
- set_wreg(srcdst, |
- ExtendValue(kWRegSizeInBits, MemoryRead8(address), SXTB)); |
+ set_wreg(srcdst, ExtendValue<int32_t>(MemoryRead8(address), SXTB)); |
break; |
} |
case LDRSB_x: { |
- set_xreg(srcdst, |
- ExtendValue(kXRegSizeInBits, MemoryRead8(address), SXTB)); |
+ set_xreg(srcdst, ExtendValue<int64_t>(MemoryRead8(address), SXTB)); |
break; |
} |
case LDRSH_w: { |
- set_wreg(srcdst, |
- ExtendValue(kWRegSizeInBits, MemoryRead16(address), SXTH)); |
+ set_wreg(srcdst, ExtendValue<int32_t>(MemoryRead16(address), SXTH)); |
break; |
} |
case LDRSH_x: { |
- set_xreg(srcdst, |
- ExtendValue(kXRegSizeInBits, MemoryRead16(address), SXTH)); |
+ set_xreg(srcdst, ExtendValue<int64_t>(MemoryRead16(address), SXTH)); |
break; |
} |
case LDRSW_x: { |
- set_xreg(srcdst, |
- ExtendValue(kXRegSizeInBits, MemoryRead32(address), SXTW)); |
+ set_xreg(srcdst, ExtendValue<int64_t>(MemoryRead32(address), SXTW)); |
break; |
} |
case LDR_s: set_sreg(srcdst, MemoryReadFP32(address)); break; |
@@ -1605,8 +1609,8 @@ void Simulator::LoadStorePairHelper(Instruction* instr, |
break; |
} |
case LDPSW_x: { |
- set_xreg(rt, ExtendValue(kXRegSizeInBits, MemoryRead32(address), SXTW)); |
- set_xreg(rt2, ExtendValue(kXRegSizeInBits, |
+ set_xreg(rt, ExtendValue<int64_t>(MemoryRead32(address), SXTW)); |
+ set_xreg(rt2, ExtendValue<int64_t>( |
MemoryRead32(address + kWRegSize), SXTW)); |
break; |
} |
@@ -1822,25 +1826,26 @@ void Simulator::VisitMoveWideImmediate(Instruction* instr) { |
void Simulator::VisitConditionalSelect(Instruction* instr) { |
- uint64_t new_val = xreg(instr->Rn()); |
- |
if (ConditionFailed(static_cast<Condition>(instr->Condition()))) { |
- new_val = xreg(instr->Rm()); |
+ uint64_t new_val = xreg(instr->Rm()); |
switch (instr->Mask(ConditionalSelectMask)) { |
- case CSEL_w: |
- case CSEL_x: break; |
- case CSINC_w: |
- case CSINC_x: new_val++; break; |
- case CSINV_w: |
- case CSINV_x: new_val = ~new_val; break; |
- case CSNEG_w: |
- case CSNEG_x: new_val = -new_val; break; |
+ case CSEL_w: set_wreg(instr->Rd(), new_val); break; |
+ case CSEL_x: set_xreg(instr->Rd(), new_val); break; |
+ case CSINC_w: set_wreg(instr->Rd(), new_val + 1); break; |
+ case CSINC_x: set_xreg(instr->Rd(), new_val + 1); break; |
+ case CSINV_w: set_wreg(instr->Rd(), ~new_val); break; |
+ case CSINV_x: set_xreg(instr->Rd(), ~new_val); break; |
+ case CSNEG_w: set_wreg(instr->Rd(), -new_val); break; |
+ case CSNEG_x: set_xreg(instr->Rd(), -new_val); break; |
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); |
} |
@@ -1911,28 +1916,17 @@ uint64_t Simulator::ReverseBytes(uint64_t value, ReverseByteMode mode) { |
} |
-void Simulator::VisitDataProcessing2Source(Instruction* instr) { |
+template <typename T> |
+void Simulator::DataProcessing2Source(Instruction* instr) { |
Shift shift_op = NO_SHIFT; |
- int64_t result = 0; |
+ T result = 0; |
switch (instr->Mask(DataProcessing2SourceMask)) { |
- 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_w: |
case SDIV_x: { |
- int64_t rn = xreg(instr->Rn()); |
- int64_t rm = xreg(instr->Rm()); |
- if ((rn == kXMinInt) && (rm == -1)) { |
- result = kXMinInt; |
+ T rn = reg<T>(instr->Rn()); |
+ T rm = reg<T>(instr->Rm()); |
+ if ((rn == std::numeric_limits<T>::min()) && (rm == -1)) { |
+ result = std::numeric_limits<T>::min(); |
} else if (rm == 0) { |
// Division by zero can be trapped, but not on A-class processors. |
result = 0; |
@@ -1941,20 +1935,11 @@ void Simulator::VisitDataProcessing2Source(Instruction* instr) { |
} |
break; |
} |
- 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_w: |
case UDIV_x: { |
- uint64_t rn = static_cast<uint64_t>(xreg(instr->Rn())); |
- uint64_t rm = static_cast<uint64_t>(xreg(instr->Rm())); |
+ typedef typename make_unsigned<T>::type unsignedT; |
+ unsignedT rn = static_cast<unsignedT>(reg<T>(instr->Rn())); |
+ unsignedT rm = static_cast<unsignedT>(reg<T>(instr->Rm())); |
if (rm == 0) { |
// Division by zero can be trapped, but not on A-class processors. |
result = 0; |
@@ -1974,18 +1959,27 @@ void Simulator::VisitDataProcessing2Source(Instruction* instr) { |
default: UNIMPLEMENTED(); |
} |
- unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits |
- : kWRegSizeInBits; |
if (shift_op != NO_SHIFT) { |
// Shift distance encoded in the least-significant five/six bits of the |
// register. |
- int mask = (instr->SixtyFourBits() == 1) ? kShiftAmountXRegMask |
- : kShiftAmountWRegMask; |
- unsigned shift = wreg(instr->Rm()) & mask; |
- result = ShiftOperand(reg_size, reg(reg_size, instr->Rn()), shift_op, |
- shift); |
+ unsigned shift = wreg(instr->Rm()); |
+ if (sizeof(T) == kWRegSize) { |
+ shift &= kShiftAmountWRegMask; |
+ } else { |
+ shift &= kShiftAmountXRegMask; |
+ } |
+ 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); |
} |
@@ -2012,9 +2006,6 @@ static int64_t MultiplyHighSigned(int64_t u, int64_t v) { |
void Simulator::VisitDataProcessing3Source(Instruction* instr) { |
- unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits |
- : kWRegSizeInBits; |
- |
int64_t result = 0; |
// Extract and sign- or zero-extend 32-bit arguments for widening operations. |
uint64_t rn_u32 = reg<uint32_t>(instr->Rn()); |
@@ -2040,21 +2031,26 @@ void Simulator::VisitDataProcessing3Source(Instruction* instr) { |
break; |
default: UNIMPLEMENTED(); |
} |
- set_reg(reg_size, instr->Rd(), result); |
+ |
+ if (instr->SixtyFourBits()) { |
+ set_xreg(instr->Rd(), result); |
+ } else { |
+ set_wreg(instr->Rd(), result); |
+ } |
} |
-void Simulator::VisitBitfield(Instruction* instr) { |
- unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits |
- : kWRegSizeInBits; |
- int64_t reg_mask = instr->SixtyFourBits() ? kXRegMask : kWRegMask; |
- int64_t R = instr->ImmR(); |
- int64_t S = instr->ImmS(); |
- int64_t diff = S - R; |
- int64_t mask; |
+template <typename T> |
+void Simulator::BitfieldHelper(Instruction* instr) { |
+ typedef typename make_unsigned<T>::type unsignedT; |
+ T reg_size = sizeof(T) * 8; |
+ T R = instr->ImmR(); |
+ T S = instr->ImmS(); |
+ T diff = S - R; |
+ T mask; |
if (diff >= 0) { |
- mask = diff < reg_size - 1 ? (1L << (diff + 1)) - 1 |
- : reg_mask; |
+ mask = diff < reg_size - 1 ? (static_cast<T>(1) << (diff + 1)) - 1 |
+ : static_cast<T>(-1); |
} else { |
mask = ((1L << (S + 1)) - 1); |
mask = (static_cast<uint64_t>(mask) >> R) | (mask << (reg_size - R)); |
@@ -2083,32 +2079,37 @@ void Simulator::VisitBitfield(Instruction* instr) { |
UNIMPLEMENTED(); |
} |
- int64_t dst = inzero ? 0 : reg(reg_size, instr->Rd()); |
- int64_t src = reg(reg_size, instr->Rn()); |
+ T dst = inzero ? 0 : reg<T>(instr->Rd()); |
+ T src = reg<T>(instr->Rn()); |
// Rotate source bitfield into place. |
- int64_t result = (static_cast<uint64_t>(src) >> R) | (src << (reg_size - R)); |
+ T result = (static_cast<unsignedT>(src) >> R) | (src << (reg_size - R)); |
// Determine the sign extension. |
- int64_t topbits_preshift = (1L << (reg_size - diff - 1)) - 1; |
- int64_t signbits = (extend && ((src >> S) & 1) ? topbits_preshift : 0) |
- << (diff + 1); |
+ T topbits_preshift = (static_cast<T>(1) << (reg_size - diff - 1)) - 1; |
+ T signbits = (extend && ((src >> S) & 1) ? topbits_preshift : 0) |
+ << (diff + 1); |
// Merge sign extension, dest/zero and bitfield. |
result = signbits | (result & mask) | (dst & ~mask); |
- set_reg(reg_size, instr->Rd(), result); |
+ set_reg<T>(instr->Rd(), result); |
} |
-void Simulator::VisitExtract(Instruction* instr) { |
- unsigned lsb = instr->ImmS(); |
- unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits |
- : kWRegSizeInBits; |
- uint64_t result = reg(reg_size, instr->Rm()); |
- if (lsb) { |
- result = (result >> lsb) | (reg(reg_size, instr->Rn()) << (reg_size - lsb)); |
+void Simulator::VisitBitfield(Instruction* instr) { |
+ if (instr->SixtyFourBits()) { |
+ BitfieldHelper<int64_t>(instr); |
+ } else { |
+ BitfieldHelper<int32_t>(instr); |
} |
+} |
+ |
- set_reg(reg_size, instr->Rd(), result); |
+void Simulator::VisitExtract(Instruction* instr) { |
+ if (instr->SixtyFourBits()) { |
+ Extract<uint64_t>(instr); |
+ } else { |
+ Extract<uint32_t>(instr); |
+ } |
} |