From: svenpanne@chromium.org Date: Fri, 23 May 2014 07:14:04 +0000 (+0000) Subject: Revert "Do away with variable length memcpy to Set/Get registers in simulator" X-Git-Tag: upstream/4.7.83~9013 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8398781323bd1d4976704be3fdc35e6d856f5fae;p=platform%2Fupstream%2Fv8.git 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 --- diff --git a/src/arm64/simulator-arm64.cc b/src/arm64/simulator-arm64.cc index 9b66586..c7c9f6c 100644 --- a/src/arm64/simulator-arm64.cc +++ b/src/arm64/simulator-arm64.cc @@ -823,29 +823,49 @@ int Simulator::CodeFromName(const char* name) { // Helpers --------------------------------------------------------------------- -template -T Simulator::AddWithCarry(bool set_flags, - T src1, - T src2, - T carry_in) { - typedef typename make_unsigned::type unsignedT; +int64_t Simulator::AddWithCarry(unsigned reg_size, + bool set_flags, + int64_t src1, + int64_t src2, + int64_t carry_in) { ASSERT((carry_in == 0) || (carry_in == 1)); + ASSERT((reg_size == kXRegSizeInBits) || (reg_size == kWRegSizeInBits)); - T signed_sum = src1 + src2 + carry_in; - T result = signed_sum; + uint64_t u1, u2; + int64_t result; + int64_t signed_sum = src1 + src2 + carry_in; bool N, Z, C, V; - unsignedT u1 = static_cast(src1); - unsignedT u2 = static_cast(src2); - // Compute the C flag by comparing the sum to the max unsigned integer. - C = ((std::numeric_limits::max() - u1) < (u2 + carry_in)) || - ((std::numeric_limits::max() - 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); + if (reg_size == kWRegSizeInBits) { + u1 = static_cast(src1) & kWRegMask; + u2 = static_cast(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(src1); + u2 = static_cast(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); if (set_flags) { @@ -858,42 +878,33 @@ T Simulator::AddWithCarry(bool set_flags, } -template -void Simulator::AddSubWithCarry(Instruction* instr) { - T op2 = reg(instr->Rm()); - T new_val; - - if ((instr->Mask(AddSubOpMask) == SUB) || instr->Mask(AddSubOpMask) == SUBS) { - op2 = ~op2; - } - - new_val = AddWithCarry(instr->FlagsUpdate(), - reg(instr->Rn()), - op2, - nzcv().C()); - - set_reg(instr->Rd(), new_val); -} - -template -T Simulator::ShiftOperand(T value, Shift shift_type, unsigned amount) { - typedef typename make_unsigned::type unsignedT; - +int64_t Simulator::ShiftOperand(unsigned reg_size, + int64_t value, + Shift shift_type, + unsigned amount) { if (amount == 0) { return value; } - + int64_t mask = reg_size == kXRegSizeInBits ? kXRegMask : kWRegMask; switch (shift_type) { case LSL: - return value << amount; + return (value << amount) & mask; case LSR: - return static_cast(value) >> amount; - case ASR: - return value >> amount; - case ROR: - return (static_cast(value) >> amount) | - ((value & ((1L << amount) - 1L)) << - (sizeof(unsignedT) * 8 - amount)); + return static_cast(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(value) >> amount) | + ((value & ((1L << amount) - 1L)) << (reg_size - amount)); + } default: UNIMPLEMENTED(); return 0; @@ -901,12 +912,10 @@ T Simulator::ShiftOperand(T value, Shift shift_type, unsigned amount) { } -template -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; - +int64_t Simulator::ExtendValue(unsigned reg_size, + int64_t value, + Extend extend_type, + unsigned left_shift) { switch (extend_type) { case UXTB: value &= kByteMask; @@ -918,13 +927,13 @@ T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) { value &= kWordMask; break; case SXTB: - value = (value << kSignExtendBShift) >> kSignExtendBShift; + value = (value << 56) >> 56; break; case SXTH: - value = (value << kSignExtendHShift) >> kSignExtendHShift; + value = (value << 48) >> 48; break; case SXTW: - value = (value << kSignExtendWShift) >> kSignExtendWShift; + value = (value << 32) >> 32; break; case UXTX: case SXTX: @@ -932,21 +941,8 @@ T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) { default: UNREACHABLE(); } - return value << left_shift; -} - - -template -void Simulator::Extract(Instruction* instr) { - unsigned lsb = instr->ImmS(); - T op2 = reg(instr->Rm()); - T result = op2; - - if (lsb) { - T op1 = reg(instr->Rn()); - result = op2 >> lsb | (op1 << ((sizeof(T) * 8) - lsb)); - } - set_reg(instr->Rd(), result); + int64_t mask = (reg_size == kXRegSizeInBits) ? kXRegMask : kWRegMask; + return (value << left_shift) & mask; } @@ -1260,110 +1256,110 @@ void Simulator::VisitCompareBranch(Instruction* instr) { } -template -void Simulator::AddSubHelper(Instruction* instr, T op2) { +void Simulator::AddSubHelper(Instruction* instr, int64_t op2) { + unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits + : kWRegSizeInBits; bool set_flags = instr->FlagsUpdate(); - T new_val = 0; + int64_t new_val = 0; Instr operation = instr->Mask(AddSubOpMask); switch (operation) { case ADD: case ADDS: { - new_val = AddWithCarry(set_flags, - reg(instr->Rn(), instr->RnMode()), - op2); + new_val = AddWithCarry(reg_size, + set_flags, + reg(reg_size, instr->Rn(), instr->RnMode()), + op2); break; } case SUB: case SUBS: { - new_val = AddWithCarry(set_flags, - reg(instr->Rn(), instr->RnMode()), - ~op2, - 1); + new_val = AddWithCarry(reg_size, + set_flags, + reg(reg_size, instr->Rn(), instr->RnMode()), + ~op2, + 1); break; } default: UNREACHABLE(); } - set_reg(instr->Rd(), new_val, instr->RdMode()); + set_reg(reg_size, instr->Rd(), new_val, instr->RdMode()); } void Simulator::VisitAddSubShifted(Instruction* instr) { - Shift shift_type = static_cast(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); - } + unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits + : kWRegSizeInBits; + int64_t op2 = ShiftOperand(reg_size, + reg(reg_size, instr->Rm()), + static_cast(instr->ShiftDP()), + instr->ImmDPShift()); + AddSubHelper(instr, op2); } void Simulator::VisitAddSubImmediate(Instruction* instr) { int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0); - if (instr->SixtyFourBits()) { - AddSubHelper(instr, op2); - } else { - AddSubHelper(instr, op2); - } + AddSubHelper(instr, op2); } void Simulator::VisitAddSubExtended(Instruction* instr) { - Extend ext = static_cast(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); - } + unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits + : kWRegSizeInBits; + int64_t op2 = ExtendValue(reg_size, + reg(reg_size, instr->Rm()), + static_cast(instr->ExtendMode()), + instr->ImmExtendShift()); + AddSubHelper(instr, op2); } void Simulator::VisitAddSubWithCarry(Instruction* instr) { - if (instr->SixtyFourBits()) { - AddSubWithCarry(instr); - } else { - AddSubWithCarry(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; } + + 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(instr->ShiftDP()); unsigned shift_amount = instr->ImmDPShift(); - - if (instr->SixtyFourBits()) { - int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount); - op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2; - LogicalHelper(instr, op2); - } else { - int32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount); - op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2; - LogicalHelper(instr, op2); + int64_t op2 = ShiftOperand(reg_size, reg(reg_size, instr->Rm()), shift_type, + shift_amount); + if (instr->Mask(NOT) == NOT) { + op2 = ~op2; } + LogicalHelper(instr, op2); } void Simulator::VisitLogicalImmediate(Instruction* instr) { - if (instr->SixtyFourBits()) { - LogicalHelper(instr, instr->ImmLogical()); - } else { - LogicalHelper(instr, instr->ImmLogical()); - } + LogicalHelper(instr, instr->ImmLogical()); } -template -void Simulator::LogicalHelper(Instruction* instr, T op2) { - T op1 = reg(instr->Rn()); - T result = 0; +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; bool update_flags = false; // 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) { } if (update_flags) { - nzcv().SetN(CalcNFlag(result)); + nzcv().SetN(CalcNFlag(result, reg_size)); nzcv().SetZ(CalcZFlag(result)); nzcv().SetC(0); nzcv().SetV(0); } - set_reg(instr->Rd(), result, instr->RdMode()); + set_reg(reg_size, instr->Rd(), result, instr->RdMode()); } void Simulator::VisitConditionalCompareRegister(Instruction* instr) { - if (instr->SixtyFourBits()) { - ConditionalCompareHelper(instr, xreg(instr->Rm())); - } else { - ConditionalCompareHelper(instr, wreg(instr->Rm())); - } + unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits + : kWRegSizeInBits; + ConditionalCompareHelper(instr, reg(reg_size, instr->Rm())); } void Simulator::VisitConditionalCompareImmediate(Instruction* instr) { - if (instr->SixtyFourBits()) { - ConditionalCompareHelper(instr, instr->ImmCondCmp()); - } else { - ConditionalCompareHelper(instr, instr->ImmCondCmp()); - } + ConditionalCompareHelper(instr, instr->ImmCondCmp()); } -template -void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) { - T op1 = reg(instr->Rn()); +void Simulator::ConditionalCompareHelper(Instruction* instr, int64_t op2) { + unsigned reg_size = instr->SixtyFourBits() ? kXRegSizeInBits + : kWRegSizeInBits; + int64_t op1 = reg(reg_size, instr->Rn()); if (ConditionPassed(static_cast(instr->Condition()))) { // If the condition passes, set the status flags to the result of comparing // the operands. if (instr->Mask(ConditionalCompareMask) == CCMP) { - AddWithCarry(true, op1, ~op2, 1); + AddWithCarry(reg_size, true, op1, ~op2, 1); } else { ASSERT(instr->Mask(ConditionalCompareMask) == CCMN); - AddWithCarry(true, op1, op2, 0); + AddWithCarry(reg_size, true, op1, op2, 0); } } else { // If the condition fails, set the status flags to the nzcv immediate. @@ -1452,7 +1443,8 @@ 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(xreg(instr->Rm()), ext, shift_amount); + int64_t offset = ExtendValue(kXRegSizeInBits, xreg(instr->Rm()), ext, + shift_amount); LoadStoreHelper(instr, offset, Offset); } @@ -1492,23 +1484,28 @@ 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(MemoryRead8(address), SXTB)); + set_wreg(srcdst, + ExtendValue(kWRegSizeInBits, MemoryRead8(address), SXTB)); break; } case LDRSB_x: { - set_xreg(srcdst, ExtendValue(MemoryRead8(address), SXTB)); + set_xreg(srcdst, + ExtendValue(kXRegSizeInBits, MemoryRead8(address), SXTB)); break; } case LDRSH_w: { - set_wreg(srcdst, ExtendValue(MemoryRead16(address), SXTH)); + set_wreg(srcdst, + ExtendValue(kWRegSizeInBits, MemoryRead16(address), SXTH)); break; } case LDRSH_x: { - set_xreg(srcdst, ExtendValue(MemoryRead16(address), SXTH)); + set_xreg(srcdst, + ExtendValue(kXRegSizeInBits, MemoryRead16(address), SXTH)); break; } case LDRSW_x: { - set_xreg(srcdst, ExtendValue(MemoryRead32(address), SXTW)); + set_xreg(srcdst, + ExtendValue(kXRegSizeInBits, MemoryRead32(address), SXTW)); break; } case LDR_s: set_sreg(srcdst, MemoryReadFP32(address)); break; @@ -1608,8 +1605,8 @@ void Simulator::LoadStorePairHelper(Instruction* instr, break; } case LDPSW_x: { - set_xreg(rt, ExtendValue(MemoryRead32(address), SXTW)); - set_xreg(rt2, ExtendValue( + set_xreg(rt, ExtendValue(kXRegSizeInBits, MemoryRead32(address), SXTW)); + set_xreg(rt2, ExtendValue(kXRegSizeInBits, MemoryRead32(address + kWRegSize), SXTW)); break; } @@ -1825,26 +1822,25 @@ void Simulator::VisitMoveWideImmediate(Instruction* instr) { void Simulator::VisitConditionalSelect(Instruction* instr) { + uint64_t new_val = xreg(instr->Rn()); + if (ConditionFailed(static_cast(instr->Condition()))) { - uint64_t new_val = xreg(instr->Rm()); + new_val = xreg(instr->Rm()); switch (instr->Mask(ConditionalSelectMask)) { - 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; + 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; 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) { } -template -void Simulator::DataProcessing2Source(Instruction* instr) { +void Simulator::VisitDataProcessing2Source(Instruction* instr) { Shift shift_op = NO_SHIFT; - T result = 0; + int64_t result = 0; 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: { - T rn = reg(instr->Rn()); - T rm = reg(instr->Rm()); - if ((rn == std::numeric_limits::min()) && (rm == -1)) { - result = std::numeric_limits::min(); + int64_t rn = xreg(instr->Rn()); + int64_t rm = xreg(instr->Rm()); + if ((rn == kXMinInt) && (rm == -1)) { + result = kXMinInt; } else if (rm == 0) { // Division by zero can be trapped, but not on A-class processors. result = 0; @@ -1934,11 +1941,20 @@ void Simulator::DataProcessing2Source(Instruction* instr) { } break; } - case UDIV_w: + case UDIV_w: { + uint32_t rn = static_cast(wreg(instr->Rn())); + uint32_t rm = static_cast(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: { - typedef typename make_unsigned::type unsignedT; - unsignedT rn = static_cast(reg(instr->Rn())); - unsignedT rm = static_cast(reg(instr->Rm())); + uint64_t rn = static_cast(xreg(instr->Rn())); + uint64_t rm = static_cast(xreg(instr->Rm())); if (rm == 0) { // Division by zero can be trapped, but not on A-class processors. result = 0; @@ -1958,27 +1974,18 @@ void Simulator::DataProcessing2Source(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. - unsigned shift = wreg(instr->Rm()); - if (sizeof(T) == kWRegSize) { - shift &= kShiftAmountWRegMask; - } else { - shift &= kShiftAmountXRegMask; - } - result = ShiftOperand(reg(instr->Rn()), shift_op, shift); - } - set_reg(instr->Rd(), result); -} - - -void Simulator::VisitDataProcessing2Source(Instruction* instr) { - if (instr->SixtyFourBits()) { - DataProcessing2Source(instr); - } else { - DataProcessing2Source(instr); + 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); } + set_reg(reg_size, instr->Rd(), result); } @@ -2005,6 +2012,9 @@ 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(instr->Rn()); @@ -2030,26 +2040,21 @@ void Simulator::VisitDataProcessing3Source(Instruction* instr) { break; default: UNIMPLEMENTED(); } - - if (instr->SixtyFourBits()) { - set_xreg(instr->Rd(), result); - } else { - set_wreg(instr->Rd(), result); - } + set_reg(reg_size, instr->Rd(), result); } -template -void Simulator::BitfieldHelper(Instruction* instr) { - typedef typename make_unsigned::type unsignedT; - T reg_size = sizeof(T) * 8; - T R = instr->ImmR(); - T S = instr->ImmS(); - T diff = S - R; - T mask; +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; if (diff >= 0) { - mask = diff < reg_size - 1 ? (static_cast(1) << (diff + 1)) - 1 - : static_cast(-1); + mask = diff < reg_size - 1 ? (1L << (diff + 1)) - 1 + : reg_mask; } else { mask = ((1L << (S + 1)) - 1); mask = (static_cast(mask) >> R) | (mask << (reg_size - R)); @@ -2078,37 +2083,30 @@ void Simulator::BitfieldHelper(Instruction* instr) { UNIMPLEMENTED(); } - T dst = inzero ? 0 : reg(instr->Rd()); - T src = reg(instr->Rn()); + int64_t dst = inzero ? 0 : reg(reg_size, instr->Rd()); + int64_t src = reg(reg_size, instr->Rn()); // Rotate source bitfield into place. - T result = (static_cast(src) >> R) | (src << (reg_size - R)); + int64_t result = (static_cast(src) >> R) | (src << (reg_size - R)); // Determine the sign extension. - T topbits_preshift = (static_cast(1) << (reg_size - diff - 1)) - 1; - T signbits = (extend && ((src >> S) & 1) ? topbits_preshift : 0) - << (diff + 1); + int64_t topbits_preshift = (1L << (reg_size - diff - 1)) - 1; + int64_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(instr->Rd(), result); -} - - -void Simulator::VisitBitfield(Instruction* instr) { - if (instr->SixtyFourBits()) { - BitfieldHelper(instr); - } else { - BitfieldHelper(instr); - } + set_reg(reg_size, instr->Rd(), result); } void Simulator::VisitExtract(Instruction* instr) { - if (instr->SixtyFourBits()) { - Extract(instr); - } else { - Extract(instr); - } + unsigned lsb = instr->ImmS(); + unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits + : kWRegSizeInBits; + set_reg(reg_size, + instr->Rd(), + (static_cast(reg(reg_size, instr->Rm())) >> lsb) | + (reg(reg_size, instr->Rn()) << (reg_size - lsb))); } diff --git a/src/arm64/simulator-arm64.h b/src/arm64/simulator-arm64.h index 0dc534c..29a6583 100644 --- a/src/arm64/simulator-arm64.h +++ b/src/arm64/simulator-arm64.h @@ -133,28 +133,35 @@ class SimSystemRegister { // Represent a register (r0-r31, v0-v31). +template class SimRegisterBase { public: template - void Set(T new_value) { - value_ = 0; - memcpy(&value_, &new_value, sizeof(T)); + void Set(T new_value, unsigned size = sizeof(T)) { + ASSERT(size <= kSizeInBytes); + 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 - T Get() const { + T Get(unsigned size = sizeof(T)) const { + ASSERT(size <= kSizeInBytes); T result; - memcpy(&result, &value_, sizeof(T)); + memset(&result, 0, sizeof(result)); + memcpy(&result, value_, size); return result; } protected: - int64_t value_; + uint8_t value_[kSizeInBytes]; }; - - -typedef SimRegisterBase SimRegister; // r0-r31 -typedef SimRegisterBase SimFPRegister; // v0-v31 +typedef SimRegisterBase SimRegister; // r0-r31 +typedef SimRegisterBase SimFPRegister; // v0-v31 class Simulator : public DecoderVisitor { @@ -321,53 +328,86 @@ class Simulator : public DecoderVisitor { VISITOR_LIST(DECLARE) #undef DECLARE - bool IsZeroRegister(unsigned code, Reg31Mode r31mode) const { - return ((code == 31) && (r31mode == Reg31IsZeroRegister)); - } - // Register accessors. + // Return 'size' bits of the value of an integer register, as the specified // type. The value is zero-extended to fill the result. // + // The only supported values of 'size' are kXRegSizeInBits and + // kWRegSizeInBits. template - 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); - if (IsZeroRegister(code, r31mode)) { - return 0; + + if ((code == 31) && (r31mode == Reg31IsZeroRegister)) { + T result; + memset(&result, 0, sizeof(result)); + return result; } - return registers_[code].Get(); + return registers_[code].Get(size_in_bytes); + } + + // Like reg(), but infer the access size from the template type. + template + T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { + return reg(sizeof(T) * 8, code, r31mode); } // 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(code, r31mode); } - int64_t xreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { + int64_t xreg(unsigned code, + Reg31Mode r31mode = Reg31IsZeroRegister) const { return reg(code, r31mode); } + int64_t reg(unsigned size, unsigned code, + Reg31Mode r31mode = Reg31IsZeroRegister) const { + return reg(size, code, r31mode); + } + // Write 'size' bits of 'value' into an integer register. The value is // zero-extended. This behaviour matches AArch64 register writes. + // + // The only supported values of 'size' are kXRegSizeInBits and + // kWRegSizeInBits. + template + 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. template void set_reg(unsigned code, T value, Reg31Mode r31mode = Reg31IsZeroRegister) { - ASSERT(code < kNumberOfRegisters); - if (!IsZeroRegister(code, r31mode)) - registers_[code].Set(value); + set_reg(sizeof(value) * 8, code, value, r31mode); } // Common specialized accessors for the set_reg() template. void set_wreg(unsigned code, int32_t value, Reg31Mode r31mode = Reg31IsZeroRegister) { - set_reg(code, value, r31mode); + set_reg(kWRegSizeInBits, code, value, r31mode); } void set_xreg(unsigned code, int64_t value, Reg31Mode r31mode = Reg31IsZeroRegister) { - set_reg(code, value, r31mode); + set_reg(kXRegSizeInBits, code, value, r31mode); } // Commonly-used special cases. @@ -392,10 +432,24 @@ class Simulator : public DecoderVisitor { Address get_sp() { return reg
(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 + 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(size_in_bytes); + } + + // Like fpreg(), but infer the access size from the template type. template T fpreg(unsigned code) const { - ASSERT(code < kNumberOfRegisters); - return fpregisters_[code].Get(); + return fpreg(sizeof(T) * 8, code); } // Common specialized accessors for the fpreg() template. @@ -431,7 +485,7 @@ class Simulator : public DecoderVisitor { void set_fpreg(unsigned code, T value) { ASSERT((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize)); ASSERT(code < kNumberOfFPRegisters); - fpregisters_[code].Set(value); + fpregisters_[code].Set(value, sizeof(value)); } // Common specialized accessors for the set_fpreg() template. @@ -571,19 +625,14 @@ class Simulator : public DecoderVisitor { return !ConditionPassed(cond); } - template - void AddSubHelper(Instruction* instr, T op2); - template - T AddWithCarry(bool set_flags, - T src1, - T src2, - T carry_in = 0); - template - void AddSubWithCarry(Instruction* instr); - template - void LogicalHelper(Instruction* instr, T op2); - template - void ConditionalCompareHelper(Instruction* instr, T op2); + void AddSubHelper(Instruction* instr, int64_t op2); + int64_t AddWithCarry(unsigned reg_size, + bool set_flags, + int64_t src1, + int64_t src2, + int64_t carry_in = 0); + void LogicalHelper(Instruction* instr, int64_t op2); + void ConditionalCompareHelper(Instruction* instr, int64_t op2); void LoadStoreHelper(Instruction* instr, int64_t offset, AddrMode addrmode); @@ -610,21 +659,18 @@ class Simulator : public DecoderVisitor { void MemoryWrite64(uint8_t* address, uint64_t value); void MemoryWriteFP64(uint8_t* address, double value); - - template - T ShiftOperand(T value, + int64_t ShiftOperand(unsigned reg_size, + int64_t value, + Shift shift_type, + unsigned amount); + int64_t Rotate(unsigned reg_width, + int64_t value, Shift shift_type, unsigned amount); - template - T ExtendValue(T value, - Extend extend_type, - unsigned left_shift = 0); - template - void Extract(Instruction* instr); - template - void DataProcessing2Source(Instruction* instr); - template - void BitfieldHelper(Instruction* instr); + int64_t ExtendValue(unsigned reg_width, + int64_t value, + Extend extend_type, + unsigned left_shift = 0); uint64_t ReverseBits(uint64_t value, unsigned num_bits); uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode); @@ -750,9 +796,8 @@ class Simulator : public DecoderVisitor { // is irrelevant, and is not checked here. } - template - static int CalcNFlag(T result) { - return (result >> (sizeof(T) * 8 - 1)) & 1; + static int CalcNFlag(uint64_t result, unsigned reg_size) { + return (result >> (reg_size - 1)) & 1; } static int CalcZFlag(uint64_t result) { diff --git a/src/utils.h b/src/utils.h index 8acb6d4..115f784 100644 --- a/src/utils.h +++ b/src/utils.h @@ -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 -struct make_unsigned { - typedef T type; -}; - - -// Template specializations necessary to have make_unsigned work -template<> struct make_unsigned { - typedef uint32_t type; -}; - - -template<> struct make_unsigned { - typedef uint64_t type; -}; - - // ---------------------------------------------------------------------------- // BitField is a help template for encoding and decode bitfield with // unsigned content.