From: svenpanne@chromium.org Date: Thu, 12 Jun 2014 11:20:31 +0000 (+0000) Subject: Do away with variable length memcpy to Set/Get registers in simulator X-Git-Tag: upstream/4.7.83~8709 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3419aefe5d36b75281686627d8cea954f0f88f82;p=platform%2Fupstream%2Fv8.git Do away with variable length memcpy to Set/Get registers in simulator About a 32% boost. Before - 5:31 Richards: 84.5 DeltaBlue: 128 Crypto: 65.3 RayTrace: 203 EarleyBoyer: 149 RegExp: 23.4 Splay: 121 NavierStokes: 98.9 ---- Score (version 7): 93.8 After - 4:10 Richards: 107 DeltaBlue: 175 Crypto: 93.9 RayTrace: 258 EarleyBoyer: 186 RegExp: 32.7 Splay: 165 NavierStokes: 124 ---- Score (version 7): 124 R=jacob.bramley@arm.com, svenpanne@chromium.org Committed: https://code.google.com/p/v8/source/detail?r=21448 Review URL: https://codereview.chromium.org/213943002 Patch from Fritz Koenig . git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21804 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/arm64/simulator-arm64.cc b/src/arm64/simulator-arm64.cc index 8fbbf9c..488b91e 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 +T Simulator::AddWithCarry(bool set_flags, + T src1, + T src2, + T carry_in) { + typedef typename make_unsigned::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(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); + // Compute the C flag + unsignedT u1 = static_cast(src1); + unsignedT u2 = static_cast(src2); + unsignedT urest = std::numeric_limits::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 +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; + 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(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)); - } + 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)); 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 +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 +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); } @@ -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 +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(set_flags, + reg(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(set_flags, + reg(instr->Rn(), instr->RnMode()), + ~op2, + 1); break; } default: UNREACHABLE(); } - set_reg(reg_size, instr->Rd(), new_val, instr->RdMode()); + set_reg(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(instr->ShiftDP()), - instr->ImmDPShift()); - AddSubHelper(instr, op2); + 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); + } } void Simulator::VisitAddSubImmediate(Instruction* instr) { int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0); - AddSubHelper(instr, op2); + if (instr->SixtyFourBits()) { + AddSubHelper(instr, op2); + } else { + AddSubHelper(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(instr->ExtendMode()), - instr->ImmExtendShift()); - AddSubHelper(instr, op2); + 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); + } } 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(instr); + } else { + AddSubWithCarry(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(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(instr, op2); + } else { + int32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount); + op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2; + LogicalHelper(instr, op2); } - LogicalHelper(instr, op2); } void Simulator::VisitLogicalImmediate(Instruction* instr) { - LogicalHelper(instr, instr->ImmLogical()); + if (instr->SixtyFourBits()) { + LogicalHelper(instr, instr->ImmLogical()); + } else { + LogicalHelper(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 +void Simulator::LogicalHelper(Instruction* instr, T op2) { + T op1 = reg(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(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(instr, instr->ImmCondCmp()); + } else { + ConditionalCompareHelper(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 +void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) { + T op1 = reg(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(reg_size, true, op1, ~op2, 1); + AddWithCarry(true, op1, ~op2, 1); } else { ASSERT(instr->Mask(ConditionalCompareMask) == CCMN); - AddWithCarry(reg_size, true, op1, op2, 0); + AddWithCarry(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(MemoryRead8(address), SXTB)); break; } case LDRSB_x: { - set_xreg(srcdst, - ExtendValue(kXRegSizeInBits, MemoryRead8(address), SXTB)); + set_xreg(srcdst, ExtendValue(MemoryRead8(address), SXTB)); break; } case LDRSH_w: { - set_wreg(srcdst, - ExtendValue(kWRegSizeInBits, MemoryRead16(address), SXTH)); + set_wreg(srcdst, ExtendValue(MemoryRead16(address), SXTH)); break; } case LDRSH_x: { - set_xreg(srcdst, - ExtendValue(kXRegSizeInBits, MemoryRead16(address), SXTH)); + set_xreg(srcdst, ExtendValue(MemoryRead16(address), SXTH)); break; } case LDRSW_x: { - set_xreg(srcdst, - ExtendValue(kXRegSizeInBits, MemoryRead32(address), SXTW)); + set_xreg(srcdst, ExtendValue(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(MemoryRead32(address), SXTW)); + set_xreg(rt2, ExtendValue( 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(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 +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(instr->Rn()); + T rm = reg(instr->Rm()); + if ((rn == std::numeric_limits::min()) && (rm == -1)) { + result = std::numeric_limits::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(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_w: case UDIV_x: { - uint64_t rn = static_cast(xreg(instr->Rn())); - uint64_t rm = static_cast(xreg(instr->Rm())); + typedef typename make_unsigned::type unsignedT; + unsignedT rn = static_cast(reg(instr->Rn())); + unsignedT rm = static_cast(reg(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(instr->Rn()), shift_op, shift); + } + set_reg(instr->Rd(), result); +} + + +void Simulator::VisitDataProcessing2Source(Instruction* instr) { + if (instr->SixtyFourBits()) { + DataProcessing2Source(instr); + } else { + DataProcessing2Source(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(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 +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; if (diff >= 0) { - mask = diff < reg_size - 1 ? (1L << (diff + 1)) - 1 - : reg_mask; + mask = diff < reg_size - 1 ? (static_cast(1) << (diff + 1)) - 1 + : static_cast(-1); } else { mask = ((1L << (S + 1)) - 1); mask = (static_cast(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(instr->Rd()); + T src = reg(instr->Rn()); // Rotate source bitfield into place. - int64_t result = (static_cast(src) >> R) | (src << (reg_size - R)); + T result = (static_cast(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(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(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(instr); + } else { + BitfieldHelper(instr); } +} + - set_reg(reg_size, instr->Rd(), result); +void Simulator::VisitExtract(Instruction* instr) { + if (instr->SixtyFourBits()) { + Extract(instr); + } else { + Extract(instr); + } } diff --git a/src/arm64/simulator-arm64.h b/src/arm64/simulator-arm64.h index 0ac1a90..bf74de85 100644 --- a/src/arm64/simulator-arm64.h +++ b/src/arm64/simulator-arm64.h @@ -133,35 +133,28 @@ class SimSystemRegister { // Represent a register (r0-r31, v0-v31). -template class SimRegisterBase { public: template - 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); + void Set(T new_value) { + value_ = 0; + memcpy(&value_, &new_value, sizeof(T)); } - // Copy 'size' bytes of the register to the result, and zero-extend to fill - // the result. template - T Get(unsigned size = sizeof(T)) const { - ASSERT(size <= kSizeInBytes); + T Get() const { T result; - memset(&result, 0, sizeof(result)); - memcpy(&result, value_, size); + memcpy(&result, &value_, sizeof(T)); return result; } protected: - uint8_t value_[kSizeInBytes]; + int64_t value_; }; -typedef SimRegisterBase SimRegister; // r0-r31 -typedef SimRegisterBase SimFPRegister; // v0-v31 + + +typedef SimRegisterBase SimRegister; // r0-r31 +typedef SimRegisterBase SimFPRegister; // v0-v31 class Simulator : public DecoderVisitor { @@ -328,86 +321,53 @@ class Simulator : public DecoderVisitor { VISITOR_LIST(DECLARE) #undef DECLARE - // Register accessors. + 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 size, unsigned code, - Reg31Mode r31mode = Reg31IsZeroRegister) const { - unsigned size_in_bytes = size / 8; - ASSERT(size_in_bytes <= sizeof(T)); - ASSERT((size == kXRegSizeInBits) || (size == kWRegSizeInBits)); + T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { ASSERT(code < kNumberOfRegisters); - - if ((code == 31) && (r31mode == Reg31IsZeroRegister)) { - T result; - memset(&result, 0, sizeof(result)); - return result; + if (IsZeroRegister(code, r31mode)) { + return 0; } - 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); + return registers_[code].Get(); } // 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) { - set_reg(sizeof(value) * 8, code, value, r31mode); + ASSERT(code < kNumberOfRegisters); + if (!IsZeroRegister(code, r31mode)) + registers_[code].Set(value); } // Common specialized accessors for the set_reg() template. void set_wreg(unsigned code, int32_t value, Reg31Mode r31mode = Reg31IsZeroRegister) { - set_reg(kWRegSizeInBits, code, value, r31mode); + set_reg(code, value, r31mode); } void set_xreg(unsigned code, int64_t value, Reg31Mode r31mode = Reg31IsZeroRegister) { - set_reg(kXRegSizeInBits, code, value, r31mode); + set_reg(code, value, r31mode); } // Commonly-used special cases. @@ -432,24 +392,10 @@ 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 { - return fpreg(sizeof(T) * 8, code); + ASSERT(code < kNumberOfRegisters); + return fpregisters_[code].Get(); } // Common specialized accessors for the fpreg() template. @@ -485,7 +431,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, sizeof(value)); + fpregisters_[code].Set(value); } // Common specialized accessors for the set_fpreg() template. @@ -625,14 +571,19 @@ class Simulator : public DecoderVisitor { return !ConditionPassed(cond); } - 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); + 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 LoadStoreHelper(Instruction* instr, int64_t offset, AddrMode addrmode); @@ -659,18 +610,21 @@ class Simulator : public DecoderVisitor { void MemoryWrite64(uint8_t* address, uint64_t value); void MemoryWriteFP64(uint8_t* address, double value); - int64_t ShiftOperand(unsigned reg_size, - int64_t value, - Shift shift_type, - unsigned amount); - int64_t Rotate(unsigned reg_width, - int64_t value, + + template + T ShiftOperand(T value, Shift shift_type, unsigned amount); - int64_t ExtendValue(unsigned reg_width, - int64_t value, - Extend extend_type, - unsigned left_shift = 0); + 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); uint64_t ReverseBits(uint64_t value, unsigned num_bits); uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode); @@ -796,8 +750,9 @@ class Simulator : public DecoderVisitor { // is irrelevant, and is not checked here. } - static int CalcNFlag(uint64_t result, unsigned reg_size) { - return (result >> (reg_size - 1)) & 1; + template + static int CalcNFlag(T result) { + return (result >> (sizeof(T) * 8 - 1)) & 1; } static int CalcZFlag(uint64_t result) { diff --git a/src/utils.h b/src/utils.h index 8f07ab3..a2e3be5 100644 --- a/src/utils.h +++ b/src/utils.h @@ -234,6 +234,25 @@ 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.