Chromium Code Reviews| Index: src/arm64/simulator-arm64.cc |
| diff --git a/src/arm64/simulator-arm64.cc b/src/arm64/simulator-arm64.cc |
| index c7c9f6cedd9105aef766f45f273dfcf8226d9fc1..3d7cf97dd15d398bd350d4ed0548133200f7dd34 100644 |
| --- a/src/arm64/simulator-arm64.cc |
| +++ b/src/arm64/simulator-arm64.cc |
| @@ -878,32 +878,38 @@ int64_t Simulator::AddWithCarry(unsigned reg_size, |
| } |
| -int64_t Simulator::ShiftOperand(unsigned reg_size, |
| - int64_t value, |
| - Shift shift_type, |
| - unsigned amount) { |
| +template<> struct make_unsigned<int32_t> { |
| + public: |
| + typedef uint32_t type; |
| +}; |
| + |
| + |
| +template<> struct make_unsigned<int64_t> { |
| + public: |
|
jbramley
2014/05/16 14:05:50
Is 'public' necessary here?
Fritz
2014/05/16 18:11:46
Yes. Below it is accessed make_unsigned<T>::type
Sven Panne
2014/05/19 08:12:26
Huh? struct = class + public, so this shouldn't be
Fritz
2014/05/20 19:44:24
Your correct. My mistake.
Done.
|
| + typedef uint64_t type; |
| +}; |
| + |
| + |
| +template <typename T> |
| +T Simulator::ShiftOperand(T value, Shift shift_type, unsigned amount) { |
| + typedef typename make_unsigned<T>::type unsignedT; |
|
jbramley
2014/05/16 14:05:50
I don't like this mechanism I'm afraid; it's not a
Fritz
2014/05/16 18:11:46
I haven't found away around this yet.
Propagating
|
| + |
| 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; |
| + return static_cast<unsignedT>(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; |
| + return value >> amount; |
| } |
| 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) | |
| + ((value & ((1L << amount) - 1L)) << |
| + (sizeof(unsignedT) * 8 - amount)); |
| } |
| default: |
| UNIMPLEMENTED(); |
| @@ -1289,12 +1295,17 @@ void Simulator::AddSubHelper(Instruction* instr, int64_t op2) { |
| 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()); |
| + int64_t op2 = 0; |
| + if (instr->SixtyFourBits()) { |
| + op2 = ShiftOperand(xreg(instr->Rm()), |
| + static_cast<Shift>(instr->ShiftDP()), |
| + instr->ImmDPShift()); |
| + } else { |
| + op2 = ShiftOperand(wreg(instr->Rm()), |
| + static_cast<Shift>(instr->ShiftDP()), |
| + instr->ImmDPShift()); |
|
jbramley
2014/05/16 14:05:50
This would be clearer (and fit on one line) if it
Fritz
2014/05/16 18:11:46
Done.
|
| + op2 &= kWRegMask; |
| + } |
| AddSubHelper(instr, op2); |
| } |
| @@ -1337,12 +1348,17 @@ void Simulator::VisitAddSubWithCarry(Instruction* instr) { |
| 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); |
| + int64_t op2 = 0; |
| + |
| + if (instr->SixtyFourBits()) { |
| + op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount); |
| + } else { |
| + op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount); |
| + op2 &= kWRegMask; |
|
jbramley
2014/05/16 14:05:50
Doesn't the new ShiftOperand apply that mask? If s
Fritz
2014/05/16 18:11:46
ShiftOperand was returning a signed int64_t. It's
|
| + } |
| + |
| if (instr->Mask(NOT) == NOT) { |
| op2 = ~op2; |
| } |
| @@ -1910,29 +1926,19 @@ uint64_t Simulator::ReverseBytes(uint64_t value, ReverseByteMode mode) { |
| return result; |
| } |
| - |
| -void Simulator::VisitDataProcessing2Source(Instruction* instr) { |
| +template <typename T> |
| +void Simulator::DataProcessing2Source(Instruction* instr) { |
| + typedef typename make_unsigned<T>::type unsignedT; |
| Shift shift_op = NO_SHIFT; |
| - int64_t result = 0; |
| + T result = 0; |
| + const T kMinimumInteger = static_cast<T>(1) << (sizeof(T) * 8 - 1); |
|
jbramley
2014/05/16 14:05:50
Consider adding a helper function to do this (perh
Fritz
2014/05/16 18:11:46
Thanks, great idea.
Sven Panne
2014/05/19 08:12:26
Even better idea: Use <limits>: http://www.cpluspl
Fritz
2014/05/20 19:44:24
Done.
|
| 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 == kMinimumInteger) && (rm == -1)) { |
| + result = kMinimumInteger; |
| } else if (rm == 0) { |
| // Division by zero can be trapped, but not on A-class processors. |
| result = 0; |
| @@ -1941,20 +1947,10 @@ 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())); |
| + 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 +1970,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); |
| } |