From 96cb6d5a5894e5a44612a09c4f49ceb76fddaf80 Mon Sep 17 00:00:00 2001 From: "balazs.kilvady" Date: Thu, 29 Sep 2016 04:25:03 -0700 Subject: [PATCH] MIPS64: Improve performance of simulator in debug mode. BUG= Review-Url: https://codereview.chromium.org/2375673002 Cr-Commit-Position: refs/heads/master@{#39860} --- src/mips64/constants-mips64.cc | 112 ---------- src/mips64/constants-mips64.h | 368 ++++++++++++++++++++++----------- src/mips64/simulator-mips64.cc | 204 +++++++++--------- src/mips64/simulator-mips64.h | 65 ++++-- 4 files changed, 399 insertions(+), 350 deletions(-) diff --git a/src/mips64/constants-mips64.cc b/src/mips64/constants-mips64.cc index c0e98eb623..11ae2421b0 100644 --- a/src/mips64/constants-mips64.cc +++ b/src/mips64/constants-mips64.cc @@ -121,118 +121,6 @@ int FPURegisters::Number(const char* name) { // No Cregister with the reguested name found. return kInvalidFPURegister; } - - -// ----------------------------------------------------------------------------- -// Instructions. - -bool Instruction::IsForbiddenAfterBranchInstr(Instr instr) { - Opcode opcode = static_cast(instr & kOpcodeMask); - switch (opcode) { - case J: - case JAL: - case BEQ: - case BNE: - case BLEZ: // POP06 bgeuc/bleuc, blezalc, bgezalc - case BGTZ: // POP07 bltuc/bgtuc, bgtzalc, bltzalc - case BEQL: - case BNEL: - case BLEZL: // POP26 bgezc, blezc, bgec/blec - case BGTZL: // POP27 bgtzc, bltzc, bltc/bgtc - case BC: - case BALC: - case POP10: // beqzalc, bovc, beqc - case POP30: // bnezalc, bnvc, bnec - case POP66: // beqzc, jic - case POP76: // bnezc, jialc - return true; - case REGIMM: - switch (instr & kRtFieldMask) { - case BLTZ: - case BGEZ: - case BLTZAL: - case BGEZAL: - return true; - default: - return false; - } - break; - case SPECIAL: - switch (instr & kFunctionFieldMask) { - case JR: - case JALR: - return true; - default: - return false; - } - break; - case COP1: - switch (instr & kRsFieldMask) { - case BC1: - case BC1EQZ: - case BC1NEZ: - return true; - break; - default: - return false; - } - break; - default: - return false; - } -} - - -bool Instruction::IsLinkingInstruction() const { - switch (OpcodeFieldRaw()) { - case JAL: - return true; - case POP76: - if (RsFieldRawNoAssert() == JIALC) - return true; // JIALC - else - return false; // BNEZC - case REGIMM: - switch (RtFieldRaw()) { - case BGEZAL: - case BLTZAL: - return true; - default: - return false; - } - case SPECIAL: - switch (FunctionFieldRaw()) { - case JALR: - return true; - default: - return false; - } - default: - return false; - } -} - - -bool Instruction::IsTrap() const { - if (OpcodeFieldRaw() != SPECIAL) { - return false; - } else { - switch (FunctionFieldRaw()) { - case BREAK: - case TGE: - case TGEU: - case TLT: - case TLTU: - case TEQ: - case TNE: - return true; - default: - return false; - } - } -} - - } // namespace internal } // namespace v8 diff --git a/src/mips64/constants-mips64.h b/src/mips64/constants-mips64.h index 76794688cf..2d78d2947f 100644 --- a/src/mips64/constants-mips64.h +++ b/src/mips64/constants-mips64.h @@ -899,8 +899,7 @@ static constexpr uint64_t OpcodeToBitNumber(Opcode opcode) { return 1ULL << (static_cast(opcode) >> kOpcodeShift); } - -class Instruction { +class InstructionBase { public: enum { kInstrSize = 4, @@ -910,6 +909,9 @@ class Instruction { kPCReadOffset = 0 }; + // Instruction type. + enum Type { kRegisterType, kImmediateType, kJumpType, kUnsupported = -1 }; + // Get the raw instruction bits. inline Instr InstructionBits() const { return *reinterpret_cast(this); @@ -930,14 +932,6 @@ class Instruction { return (InstructionBits() >> lo) & ((2U << (hi - lo)) - 1); } - // Instruction type. - enum Type { - kRegisterType, - kImmediateType, - kJumpType, - kUnsupported = -1 - }; - enum TypeChecks { NORMAL, EXTRA }; static constexpr uint64_t kOpcodeImmediateTypeMask = @@ -996,9 +990,6 @@ class Instruction { FunctionFieldToBitNumber(MOVCI) | FunctionFieldToBitNumber(SELEQZ_S) | FunctionFieldToBitNumber(SELNEZ_S) | FunctionFieldToBitNumber(SYNC); - // Get the encoding type of the instruction. - inline Type InstructionType(TypeChecks checks = NORMAL) const; - // Accessors for the different named fields used in the MIPS encoding. inline Opcode OpcodeValue() const { @@ -1006,78 +997,8 @@ class Instruction { Bits(kOpcodeShift + kOpcodeBits - 1, kOpcodeShift)); } - inline int RsValue() const { - DCHECK(InstructionType() == kRegisterType || - InstructionType() == kImmediateType); - return Bits(kRsShift + kRsBits - 1, kRsShift); - } - - inline int RtValue() const { - DCHECK(InstructionType() == kRegisterType || - InstructionType() == kImmediateType); - return Bits(kRtShift + kRtBits - 1, kRtShift); - } - - inline int RdValue() const { - DCHECK(InstructionType() == kRegisterType); - return Bits(kRdShift + kRdBits - 1, kRdShift); - } - - inline int SaValue() const { - DCHECK(InstructionType() == kRegisterType); - return Bits(kSaShift + kSaBits - 1, kSaShift); - } - - inline int LsaSaValue() const { - DCHECK(InstructionType() == kRegisterType); - return Bits(kSaShift + kLsaSaBits - 1, kSaShift); - } - - inline int FunctionValue() const { - DCHECK(InstructionType() == kRegisterType || - InstructionType() == kImmediateType); - return Bits(kFunctionShift + kFunctionBits - 1, kFunctionShift); - } - - inline int FdValue() const { - return Bits(kFdShift + kFdBits - 1, kFdShift); - } - - inline int FsValue() const { - return Bits(kFsShift + kFsBits - 1, kFsShift); - } - - inline int FtValue() const { - return Bits(kFtShift + kFtBits - 1, kFtShift); - } - - inline int FrValue() const { - return Bits(kFrShift + kFrBits -1, kFrShift); - } - - inline int Bp2Value() const { - DCHECK(InstructionType() == kRegisterType); - return Bits(kBp2Shift + kBp2Bits - 1, kBp2Shift); - } - - inline int Bp3Value() const { - DCHECK(InstructionType() == kRegisterType); - return Bits(kBp3Shift + kBp3Bits - 1, kBp3Shift); - } - - // Float Compare condition code instruction bits. - inline int FCccValue() const { - return Bits(kFCccShift + kFCccBits - 1, kFCccShift); - } - - // Float Branch condition code instruction bits. - inline int FBccValue() const { - return Bits(kFBccShift + kFBccBits - 1, kFBccShift); - } - - // Float Branch true/false instruction bit. - inline int FBtrueValue() const { - return Bits(kFBtrueShift + kFBtrueBits - 1, kFBtrueShift); + inline int FunctionFieldRaw() const { + return InstructionBits() & kFunctionFieldMask; } // Return the fields at their original place in the instruction encoding. @@ -1085,39 +1006,135 @@ class Instruction { return static_cast(InstructionBits() & kOpcodeMask); } - inline int RsFieldRaw() const { - DCHECK(InstructionType() == kRegisterType || - InstructionType() == kImmediateType); - return InstructionBits() & kRsFieldMask; - } - - // Same as above function, but safe to call within InstructionType(). + // Safe to call within InstructionType(). inline int RsFieldRawNoAssert() const { return InstructionBits() & kRsFieldMask; } + inline int SaFieldRaw() const { return InstructionBits() & kSaFieldMask; } + + // Get the encoding type of the instruction. + inline Type InstructionType(TypeChecks checks = NORMAL) const; + + protected: + InstructionBase() {} +}; + +template +class InstructionGetters : public T { + public: + inline int RsValue() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType || + this->InstructionType() == InstructionBase::kImmediateType); + return this->Bits(kRsShift + kRsBits - 1, kRsShift); + } + + inline int RtValue() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType || + this->InstructionType() == InstructionBase::kImmediateType); + return this->Bits(kRtShift + kRtBits - 1, kRtShift); + } + + inline int RdValue() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType); + return this->Bits(kRdShift + kRdBits - 1, kRdShift); + } + + inline int SaValue() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType); + return this->Bits(kSaShift + kSaBits - 1, kSaShift); + } + + inline int LsaSaValue() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType); + return this->Bits(kSaShift + kLsaSaBits - 1, kSaShift); + } + + inline int FunctionValue() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType || + this->InstructionType() == InstructionBase::kImmediateType); + return this->Bits(kFunctionShift + kFunctionBits - 1, kFunctionShift); + } + + inline int FdValue() const { + return this->Bits(kFdShift + kFdBits - 1, kFdShift); + } + + inline int FsValue() const { + return this->Bits(kFsShift + kFsBits - 1, kFsShift); + } + + inline int FtValue() const { + return this->Bits(kFtShift + kFtBits - 1, kFtShift); + } + + inline int FrValue() const { + return this->Bits(kFrShift + kFrBits - 1, kFrShift); + } + + inline int Bp2Value() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType); + return this->Bits(kBp2Shift + kBp2Bits - 1, kBp2Shift); + } + + inline int Bp3Value() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType); + return this->Bits(kBp3Shift + kBp3Bits - 1, kBp3Shift); + } + + // Float Compare condition code instruction bits. + inline int FCccValue() const { + return this->Bits(kFCccShift + kFCccBits - 1, kFCccShift); + } + + // Float Branch condition code instruction bits. + inline int FBccValue() const { + return this->Bits(kFBccShift + kFBccBits - 1, kFBccShift); + } + + // Float Branch true/false instruction bit. + inline int FBtrueValue() const { + return this->Bits(kFBtrueShift + kFBtrueBits - 1, kFBtrueShift); + } + + // Return the fields at their original place in the instruction encoding. + inline Opcode OpcodeFieldRaw() const { + return static_cast(this->InstructionBits() & kOpcodeMask); + } + + inline int RsFieldRaw() const { + DCHECK(this->InstructionType() == InstructionBase::kRegisterType || + this->InstructionType() == InstructionBase::kImmediateType); + return this->InstructionBits() & kRsFieldMask; + } + + // Same as above function, but safe to call within InstructionType(). + inline int RsFieldRawNoAssert() const { + return this->InstructionBits() & kRsFieldMask; + } + inline int RtFieldRaw() const { - DCHECK(InstructionType() == kRegisterType || - InstructionType() == kImmediateType); - return InstructionBits() & kRtFieldMask; + DCHECK(this->InstructionType() == InstructionBase::kRegisterType || + this->InstructionType() == InstructionBase::kImmediateType); + return this->InstructionBits() & kRtFieldMask; } inline int RdFieldRaw() const { - DCHECK(InstructionType() == kRegisterType); - return InstructionBits() & kRdFieldMask; + DCHECK(this->InstructionType() == InstructionBase::kRegisterType); + return this->InstructionBits() & kRdFieldMask; } inline int SaFieldRaw() const { - return InstructionBits() & kSaFieldMask; + return this->InstructionBits() & kSaFieldMask; } inline int FunctionFieldRaw() const { - return InstructionBits() & kFunctionFieldMask; + return this->InstructionBits() & kFunctionFieldMask; } // Get the secondary field according to the opcode. inline int SecondaryValue() const { - Opcode op = OpcodeFieldRaw(); + Opcode op = this->OpcodeFieldRaw(); switch (op) { case SPECIAL: case SPECIAL2: @@ -1132,34 +1149,34 @@ class Instruction { } inline int32_t ImmValue(int bits) const { - DCHECK(InstructionType() == kImmediateType); - return Bits(bits - 1, 0); + DCHECK(this->InstructionType() == InstructionBase::kImmediateType); + return this->Bits(bits - 1, 0); } inline int32_t Imm16Value() const { - DCHECK(InstructionType() == kImmediateType); - return Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift); + DCHECK(this->InstructionType() == InstructionBase::kImmediateType); + return this->Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift); } inline int32_t Imm18Value() const { - DCHECK(InstructionType() == kImmediateType); - return Bits(kImm18Shift + kImm18Bits - 1, kImm18Shift); + DCHECK(this->InstructionType() == InstructionBase::kImmediateType); + return this->Bits(kImm18Shift + kImm18Bits - 1, kImm18Shift); } inline int32_t Imm19Value() const { - DCHECK(InstructionType() == kImmediateType); - return Bits(kImm19Shift + kImm19Bits - 1, kImm19Shift); + DCHECK(this->InstructionType() == InstructionBase::kImmediateType); + return this->Bits(kImm19Shift + kImm19Bits - 1, kImm19Shift); } inline int32_t Imm21Value() const { - DCHECK(InstructionType() == kImmediateType); - return Bits(kImm21Shift + kImm21Bits - 1, kImm21Shift); + DCHECK(this->InstructionType() == InstructionBase::kImmediateType); + return this->Bits(kImm21Shift + kImm21Bits - 1, kImm21Shift); } inline int32_t Imm26Value() const { - DCHECK((InstructionType() == kJumpType) || - (InstructionType() == kImmediateType)); - return Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift); + DCHECK((this->InstructionType() == InstructionBase::kJumpType) || + (this->InstructionType() == InstructionBase::kImmediateType)); + return this->Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift); } static bool IsForbiddenAfterBranchInstr(Instr instr); @@ -1167,14 +1184,21 @@ class Instruction { // Say if the instruction should not be used in a branch delay slot or // immediately after a compact branch. inline bool IsForbiddenAfterBranch() const { - return IsForbiddenAfterBranchInstr(InstructionBits()); + return IsForbiddenAfterBranchInstr(this->InstructionBits()); + } + + inline bool IsForbiddenInBranchDelay() const { + return IsForbiddenAfterBranch(); } // Say if the instruction 'links'. e.g. jal, bal. bool IsLinkingInstruction() const; // Say if the instruction is a break or a trap. bool IsTrap() const; +}; +class Instruction : public InstructionGetters { + public: // Instructions are read of out a code stream. The only way to get a // reference to an instruction is to convert a pointer. There is no way // to allocate or create instances of class Instruction. @@ -1202,8 +1226,8 @@ const int kCArgsSlotsSize = kCArgSlotCount * Instruction::kInstrSize * 2; const int kInvalidStackOffset = -1; const int kBranchReturnOffset = 2 * Instruction::kInstrSize; - -Instruction::Type Instruction::InstructionType(TypeChecks checks) const { +InstructionBase::Type InstructionBase::InstructionType( + TypeChecks checks) const { if (checks == EXTRA) { if (OpcodeToBitNumber(OpcodeFieldRaw()) & kOpcodeImmediateTypeMask) { return kImmediateType; @@ -1306,9 +1330,119 @@ Instruction::Type Instruction::InstructionType(TypeChecks checks) const { } return kUnsupported; } - #undef OpcodeToBitNumber #undef FunctionFieldToBitNumber + +// ----------------------------------------------------------------------------- +// Instructions. + +template +bool InstructionGetters

::IsLinkingInstruction() const { + switch (OpcodeFieldRaw()) { + case JAL: + return true; + case POP76: + if (RsFieldRawNoAssert() == JIALC) + return true; // JIALC + else + return false; // BNEZC + case REGIMM: + switch (RtFieldRaw()) { + case BGEZAL: + case BLTZAL: + return true; + default: + return false; + } + case SPECIAL: + switch (FunctionFieldRaw()) { + case JALR: + return true; + default: + return false; + } + default: + return false; + } +} + +template +bool InstructionGetters

::IsTrap() const { + if (OpcodeFieldRaw() != SPECIAL) { + return false; + } else { + switch (FunctionFieldRaw()) { + case BREAK: + case TGE: + case TGEU: + case TLT: + case TLTU: + case TEQ: + case TNE: + return true; + default: + return false; + } + } +} + +// static +template +bool InstructionGetters::IsForbiddenAfterBranchInstr(Instr instr) { + Opcode opcode = static_cast(instr & kOpcodeMask); + switch (opcode) { + case J: + case JAL: + case BEQ: + case BNE: + case BLEZ: // POP06 bgeuc/bleuc, blezalc, bgezalc + case BGTZ: // POP07 bltuc/bgtuc, bgtzalc, bltzalc + case BEQL: + case BNEL: + case BLEZL: // POP26 bgezc, blezc, bgec/blec + case BGTZL: // POP27 bgtzc, bltzc, bltc/bgtc + case BC: + case BALC: + case POP10: // beqzalc, bovc, beqc + case POP30: // bnezalc, bnvc, bnec + case POP66: // beqzc, jic + case POP76: // bnezc, jialc + return true; + case REGIMM: + switch (instr & kRtFieldMask) { + case BLTZ: + case BGEZ: + case BLTZAL: + case BGEZAL: + return true; + default: + return false; + } + break; + case SPECIAL: + switch (instr & kFunctionFieldMask) { + case JR: + case JALR: + return true; + default: + return false; + } + break; + case COP1: + switch (instr & kRsFieldMask) { + case BC1: + case BC1EQZ: + case BC1NEZ: + return true; + break; + default: + return false; + } + break; + default: + return false; + } +} } // namespace internal } // namespace v8 diff --git a/src/mips64/simulator-mips64.cc b/src/mips64/simulator-mips64.cc index 082950d393..248031606f 100644 --- a/src/mips64/simulator-mips64.cc +++ b/src/mips64/simulator-mips64.cc @@ -96,7 +96,7 @@ class MipsDebugger { void RedoBreakpoints(); }; -#define UNSUPPORTED() printf("Sim: Unsupported instruction.\n"); +inline void UNSUPPORTED() { printf("Sim: Unsupported instruction.\n"); } void MipsDebugger::Stop(Instruction* instr) { // Get the stop code. @@ -1935,15 +1935,15 @@ typedef void (*SimulatorRuntimeProfilingGetterCall)( // Software interrupt instructions are used by the simulator to call into the // C-based V8 runtime. They are also used for debugging with simulator. -void Simulator::SoftwareInterrupt(Instruction* instr) { +void Simulator::SoftwareInterrupt() { // There are several instructions that could get us here, // the break_ instruction, or several variants of traps. All // Are "SPECIAL" class opcode, and are distinuished by function. - int32_t func = instr->FunctionFieldRaw(); - uint32_t code = (func == BREAK) ? instr->Bits(25, 6) : -1; + int32_t func = instr_.FunctionFieldRaw(); + uint32_t code = (func == BREAK) ? instr_.Bits(25, 6) : -1; // We first check if we met a call_rt_redirected. - if (instr->InstructionBits() == rtCallRedirInstr) { - Redirection* redirection = Redirection::FromSwiInstruction(instr); + if (instr_.InstructionBits() == rtCallRedirInstr) { + Redirection* redirection = Redirection::FromSwiInstruction(instr_.instr()); int64_t arg0 = get_register(a0); int64_t arg1 = get_register(a1); int64_t arg2 = get_register(a2); @@ -2169,7 +2169,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) { PrintWatchpoint(code); } else { IncreaseStopCounter(code); - HandleStop(code, instr); + HandleStop(code, instr_.instr()); } } else { // All remaining break_ codes, and all traps are handled here. @@ -2417,9 +2417,9 @@ void Simulator::DecodeTypeRegisterSRsType() { int32_t ft_int = bit_cast(ft); int32_t fd_int = bit_cast(fd); uint32_t cc, fcsr_cc; - cc = get_instr()->FCccValue(); + cc = instr_.FCccValue(); fcsr_cc = get_fcsr_condition_bit(cc); - switch (get_instr()->FunctionFieldRaw()) { + switch (instr_.FunctionFieldRaw()) { case RINT: { DCHECK(kArchVariant == kMips64r6); float result, temp_result; @@ -2763,7 +2763,7 @@ void Simulator::DecodeTypeRegisterSRsType() { uint32_t ft_cc = (ft_reg() >> 2) & 0x7; ft_cc = get_fcsr_condition_bit(ft_cc); - if (get_instr()->Bit(16)) { // Read Tf bit. + if (instr_.Bit(16)) { // Read Tf bit. // MOVT.D if (test_fcsr_bit(ft_cc)) set_fpu_register_float(fd_reg(), fs); } else { @@ -2784,15 +2784,14 @@ void Simulator::DecodeTypeRegisterDRsType() { double ft, fs, fd; uint32_t cc, fcsr_cc; fs = get_fpu_register_double(fs_reg()); - ft = (get_instr()->FunctionFieldRaw() != MOVF) - ? get_fpu_register_double(ft_reg()) - : 0.0; + ft = (instr_.FunctionFieldRaw() != MOVF) ? get_fpu_register_double(ft_reg()) + : 0.0; fd = get_fpu_register_double(fd_reg()); - cc = get_instr()->FCccValue(); + cc = instr_.FCccValue(); fcsr_cc = get_fcsr_condition_bit(cc); int64_t ft_int = bit_cast(ft); int64_t fd_int = bit_cast(fd); - switch (get_instr()->FunctionFieldRaw()) { + switch (instr_.FunctionFieldRaw()) { case RINT: { DCHECK(kArchVariant == kMips64r6); double result, temp, temp_result; @@ -2860,7 +2859,7 @@ void Simulator::DecodeTypeRegisterDRsType() { // Same function field for MOVT.D and MOVF.D uint32_t ft_cc = (ft_reg() >> 2) & 0x7; ft_cc = get_fcsr_condition_bit(ft_cc); - if (get_instr()->Bit(16)) { // Read Tf bit. + if (instr_.Bit(16)) { // Read Tf bit. // MOVT.D if (test_fcsr_bit(ft_cc)) set_fpu_register_double(fd_reg(), fs); } else { @@ -3151,7 +3150,7 @@ void Simulator::DecodeTypeRegisterWRsType() { float fs = get_fpu_register_float(fs_reg()); float ft = get_fpu_register_float(ft_reg()); int64_t alu_out = 0x12345678; - switch (get_instr()->FunctionFieldRaw()) { + switch (instr_.FunctionFieldRaw()) { case CVT_S_W: // Convert word to float (single). alu_out = get_fpu_register_signed_word(fs_reg()); set_fpu_register_float(fd_reg(), static_cast(alu_out)); @@ -3243,7 +3242,7 @@ void Simulator::DecodeTypeRegisterLRsType() { double fs = get_fpu_register_double(fs_reg()); double ft = get_fpu_register_double(ft_reg()); int64_t i64; - switch (get_instr()->FunctionFieldRaw()) { + switch (instr_.FunctionFieldRaw()) { case CVT_D_L: // Mips32r2 instruction. i64 = get_fpu_register(fs_reg()); set_fpu_register_double(fd_reg(), static_cast(i64)); @@ -3332,7 +3331,7 @@ void Simulator::DecodeTypeRegisterLRsType() { void Simulator::DecodeTypeRegisterCOP1() { - switch (get_instr()->RsFieldRaw()) { + switch (instr_.RsFieldRaw()) { case BC1: // Branch on coprocessor condition. case BC1EQZ: case BC1NEZ: @@ -3395,7 +3394,7 @@ void Simulator::DecodeTypeRegisterCOP1() { void Simulator::DecodeTypeRegisterCOP1X() { - switch (get_instr()->FunctionFieldRaw()) { + switch (instr_.FunctionFieldRaw()) { case MADD_S: { DCHECK(kArchVariant == kMips64r2); float fr, ft, fs; @@ -3444,7 +3443,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() { int64_t alu_out; bool do_interrupt = false; - switch (get_instr()->FunctionFieldRaw()) { + switch (instr_.FunctionFieldRaw()) { case SELEQZ_S: DCHECK(kArchVariant == kMips64r6); set_register(rd_reg(), rt() == 0 ? rs() : 0); @@ -3690,7 +3689,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() { case DIV: case DDIV: { const int64_t int_min_value = - get_instr()->FunctionFieldRaw() == DIV ? INT_MIN : LONG_MIN; + instr_.FunctionFieldRaw() == DIV ? INT_MIN : LONG_MIN; switch (kArchVariant) { case kMips64r2: // Divide by zero and overflow was not checked in the @@ -3736,7 +3735,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() { case kMips64r6: { uint32_t rt_u_32 = static_cast(rt_u()); uint32_t rs_u_32 = static_cast(rs_u()); - switch (get_instr()->SaValue()) { + switch (sa()) { case DIV_OP: if (rt_u_32 != 0) { set_register(rd_reg(), rs_u_32 / rt_u_32); @@ -3765,7 +3764,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() { case DDIVU: switch (kArchVariant) { case kMips64r6: { - switch (get_instr()->SaValue()) { + switch (instr_.SaValue()) { case DIV_OP: if (rt_u() != 0) { set_register(rd_reg(), rs_u() / rt_u()); @@ -3887,9 +3886,9 @@ void Simulator::DecodeTypeRegisterSPECIAL() { } break; case MOVCI: { - uint32_t cc = get_instr()->FBccValue(); + uint32_t cc = instr_.FBccValue(); uint32_t fcsr_cc = get_fcsr_condition_bit(cc); - if (get_instr()->Bit(16)) { // Read Tf bit. + if (instr_.Bit(16)) { // Read Tf bit. if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs()); } else { if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs()); @@ -3905,14 +3904,14 @@ void Simulator::DecodeTypeRegisterSPECIAL() { UNREACHABLE(); } if (do_interrupt) { - SoftwareInterrupt(get_instr()); + SoftwareInterrupt(); } } void Simulator::DecodeTypeRegisterSPECIAL2() { int64_t alu_out; - switch (get_instr()->FunctionFieldRaw()) { + switch (instr_.FunctionFieldRaw()) { case MUL: alu_out = static_cast(rs_u()) * static_cast(rt_u()); SetResult(rd_reg(), alu_out); @@ -3941,7 +3940,7 @@ void Simulator::DecodeTypeRegisterSPECIAL2() { void Simulator::DecodeTypeRegisterSPECIAL3() { int64_t alu_out; - switch (get_instr()->FunctionFieldRaw()) { + switch (instr_.FunctionFieldRaw()) { case INS: { // Mips64r2 instruction. // Interpret rd field as 5-bit msb of insert. uint16_t msb = rd_reg(); @@ -4010,7 +4009,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() { break; } case BSHFL: { - int32_t sa = get_instr()->SaFieldRaw() >> kSaShift; + int32_t sa = instr_.SaFieldRaw() >> kSaShift; switch (sa) { case BITSWAP: { uint32_t input = static_cast(rt()); @@ -4088,7 +4087,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() { break; } default: { - const uint8_t bp2 = get_instr()->Bp2Value(); + const uint8_t bp2 = instr_.Bp2Value(); sa >>= kBp2Bits; switch (sa) { case ALIGN: { @@ -4113,7 +4112,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() { break; } case DBSHFL: { - int32_t sa = get_instr()->SaFieldRaw() >> kSaShift; + int32_t sa = instr_.SaFieldRaw() >> kSaShift; switch (sa) { case DBITSWAP: { switch (sa) { @@ -4187,7 +4186,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() { break; } default: { - const uint8_t bp3 = get_instr()->Bp3Value(); + const uint8_t bp3 = instr_.Bp3Value(); sa >>= kBp3Bits; switch (sa) { case DALIGN: { @@ -4216,12 +4215,9 @@ void Simulator::DecodeTypeRegisterSPECIAL3() { } } - -void Simulator::DecodeTypeRegister(Instruction* instr) { - set_instr(instr); - +void Simulator::DecodeTypeRegister() { // ---------- Execution. - switch (instr->OpcodeFieldRaw()) { + switch (instr_.OpcodeFieldRaw()) { case COP1: DecodeTypeRegisterCOP1(); break; @@ -4247,18 +4243,18 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { // Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc). -void Simulator::DecodeTypeImmediate(Instruction* instr) { +void Simulator::DecodeTypeImmediate() { // Instruction fields. - Opcode op = instr->OpcodeFieldRaw(); - int32_t rs_reg = instr->RsValue(); - int64_t rs = get_register(instr->RsValue()); + Opcode op = instr_.OpcodeFieldRaw(); + int32_t rs_reg = instr_.RsValue(); + int64_t rs = get_register(instr_.RsValue()); uint64_t rs_u = static_cast(rs); - int32_t rt_reg = instr->RtValue(); // Destination register. + int32_t rt_reg = instr_.RtValue(); // Destination register. int64_t rt = get_register(rt_reg); - int16_t imm16 = instr->Imm16Value(); - int32_t imm18 = instr->Imm18Value(); + int16_t imm16 = instr_.Imm16Value(); + int32_t imm18 = instr_.Imm18Value(); - int32_t ft_reg = instr->FtValue(); // Destination register. + int32_t ft_reg = instr_.FtValue(); // Destination register. // Zero extended immediate. uint64_t oe_imm16 = 0xffff & imm16; @@ -4283,38 +4279,36 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { const int kInt64AlignmentMask = sizeof(uint64_t) - 1; // Branch instructions common part. - auto BranchAndLinkHelper = [this, instr, &next_pc, - &execute_branch_delay_instruction]( - bool do_branch) { - execute_branch_delay_instruction = true; - int64_t current_pc = get_pc(); - if (do_branch) { - int16_t imm16 = instr->Imm16Value(); - next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; - set_register(31, current_pc + 2 * Instruction::kInstrSize); - } else { - next_pc = current_pc + 2 * Instruction::kInstrSize; - } - }; + auto BranchAndLinkHelper = + [this, &next_pc, &execute_branch_delay_instruction](bool do_branch) { + execute_branch_delay_instruction = true; + int64_t current_pc = get_pc(); + if (do_branch) { + int16_t imm16 = instr_.Imm16Value(); + next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; + set_register(31, current_pc + 2 * Instruction::kInstrSize); + } else { + next_pc = current_pc + 2 * Instruction::kInstrSize; + } + }; - auto BranchHelper = [this, instr, &next_pc, + auto BranchHelper = [this, &next_pc, &execute_branch_delay_instruction](bool do_branch) { execute_branch_delay_instruction = true; int64_t current_pc = get_pc(); if (do_branch) { - int16_t imm16 = instr->Imm16Value(); + int16_t imm16 = instr_.Imm16Value(); next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; } else { next_pc = current_pc + 2 * Instruction::kInstrSize; } }; - auto BranchAndLinkCompactHelper = [this, instr, &next_pc](bool do_branch, - int bits) { + auto BranchAndLinkCompactHelper = [this, &next_pc](bool do_branch, int bits) { int64_t current_pc = get_pc(); CheckForbiddenSlot(current_pc); if (do_branch) { - int32_t imm = instr->ImmValue(bits); + int32_t imm = instr_.ImmValue(bits); imm <<= 32 - bits; imm >>= 32 - bits; next_pc = current_pc + (imm << 2) + Instruction::kInstrSize; @@ -4322,11 +4316,11 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { } }; - auto BranchCompactHelper = [&next_pc, this, instr](bool do_branch, int bits) { + auto BranchCompactHelper = [this, &next_pc](bool do_branch, int bits) { int64_t current_pc = get_pc(); CheckForbiddenSlot(current_pc); if (do_branch) { - int32_t imm = instr->ImmValue(bits); + int32_t imm = instr_.ImmValue(bits); imm <<= 32 - bits; imm >>= 32 - bits; next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize; @@ -4336,12 +4330,12 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { switch (op) { // ------------- COP1. Coprocessor instructions. case COP1: - switch (instr->RsFieldRaw()) { + switch (instr_.RsFieldRaw()) { case BC1: { // Branch on coprocessor condition. - uint32_t cc = instr->FBccValue(); + uint32_t cc = instr_.FBccValue(); uint32_t fcsr_cc = get_fcsr_condition_bit(cc); uint32_t cc_value = test_fcsr_bit(fcsr_cc); - bool do_branch = (instr->FBtrueValue()) ? cc_value : !cc_value; + bool do_branch = (instr_.FBtrueValue()) ? cc_value : !cc_value; BranchHelper(do_branch); break; } @@ -4357,7 +4351,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { break; // ------------- REGIMM class. case REGIMM: - switch (instr->RtFieldRaw()) { + switch (instr_.RtFieldRaw()) { case BLTZ: BranchHelper(rs < 0); break; @@ -4575,7 +4569,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { set_register(rt_reg, ReadB(rs + se_imm16)); break; case LH: - set_register(rt_reg, ReadH(rs + se_imm16, instr)); + set_register(rt_reg, ReadH(rs + se_imm16, instr_.instr())); break; case LWL: { // al_offset is offset of the effective address within an aligned word. @@ -4583,26 +4577,26 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { uint8_t byte_shift = kInt32AlignmentMask - al_offset; uint32_t mask = (1 << byte_shift * 8) - 1; addr = rs + se_imm16 - al_offset; - int32_t val = ReadW(addr, instr); + int32_t val = ReadW(addr, instr_.instr()); val <<= byte_shift * 8; val |= rt & mask; set_register(rt_reg, static_cast(val)); break; } case LW: - set_register(rt_reg, ReadW(rs + se_imm16, instr)); + set_register(rt_reg, ReadW(rs + se_imm16, instr_.instr())); break; case LWU: - set_register(rt_reg, ReadWU(rs + se_imm16, instr)); + set_register(rt_reg, ReadWU(rs + se_imm16, instr_.instr())); break; case LD: - set_register(rt_reg, Read2W(rs + se_imm16, instr)); + set_register(rt_reg, Read2W(rs + se_imm16, instr_.instr())); break; case LBU: set_register(rt_reg, ReadBU(rs + se_imm16)); break; case LHU: - set_register(rt_reg, ReadHU(rs + se_imm16, instr)); + set_register(rt_reg, ReadHU(rs + se_imm16, instr_.instr())); break; case LWR: { // al_offset is offset of the effective address within an aligned word. @@ -4610,7 +4604,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { uint8_t byte_shift = kInt32AlignmentMask - al_offset; uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0; addr = rs + se_imm16 - al_offset; - alu_out = ReadW(addr, instr); + alu_out = ReadW(addr, instr_.instr()); alu_out = static_cast (alu_out) >> al_offset * 8; alu_out |= rt & mask; set_register(rt_reg, alu_out); @@ -4622,7 +4616,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { uint8_t byte_shift = kInt64AlignmentMask - al_offset; uint64_t mask = (1UL << byte_shift * 8) - 1; addr = rs + se_imm16 - al_offset; - alu_out = Read2W(addr, instr); + alu_out = Read2W(addr, instr_.instr()); alu_out <<= byte_shift * 8; alu_out |= rt & mask; set_register(rt_reg, alu_out); @@ -4634,7 +4628,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { uint8_t byte_shift = kInt64AlignmentMask - al_offset; uint64_t mask = al_offset ? (~0UL << (byte_shift + 1) * 8) : 0UL; addr = rs + se_imm16 - al_offset; - alu_out = Read2W(addr, instr); + alu_out = Read2W(addr, instr_.instr()); alu_out = alu_out >> al_offset * 8; alu_out |= rt & mask; set_register(rt_reg, alu_out); @@ -4644,31 +4638,31 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { WriteB(rs + se_imm16, static_cast(rt)); break; case SH: - WriteH(rs + se_imm16, static_cast(rt), instr); + WriteH(rs + se_imm16, static_cast(rt), instr_.instr()); break; case SWL: { uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask; uint8_t byte_shift = kInt32AlignmentMask - al_offset; uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0; addr = rs + se_imm16 - al_offset; - uint64_t mem_value = ReadW(addr, instr) & mask; + uint64_t mem_value = ReadW(addr, instr_.instr()) & mask; mem_value |= static_cast(rt) >> byte_shift * 8; - WriteW(addr, static_cast(mem_value), instr); + WriteW(addr, static_cast(mem_value), instr_.instr()); break; } case SW: - WriteW(rs + se_imm16, static_cast(rt), instr); + WriteW(rs + se_imm16, static_cast(rt), instr_.instr()); break; case SD: - Write2W(rs + se_imm16, rt, instr); + Write2W(rs + se_imm16, rt, instr_.instr()); break; case SWR: { uint8_t al_offset = (rs + se_imm16) & kInt32AlignmentMask; uint32_t mask = (1 << al_offset * 8) - 1; addr = rs + se_imm16 - al_offset; - uint64_t mem_value = ReadW(addr, instr); + uint64_t mem_value = ReadW(addr, instr_.instr()); mem_value = (rt << al_offset * 8) | (mem_value & mask); - WriteW(addr, static_cast(mem_value), instr); + WriteW(addr, static_cast(mem_value), instr_.instr()); break; } case SDL: { @@ -4676,39 +4670,39 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { uint8_t byte_shift = kInt64AlignmentMask - al_offset; uint64_t mask = byte_shift ? (~0UL << (al_offset + 1) * 8) : 0; addr = rs + se_imm16 - al_offset; - uint64_t mem_value = Read2W(addr, instr) & mask; + uint64_t mem_value = Read2W(addr, instr_.instr()) & mask; mem_value |= rt >> byte_shift * 8; - Write2W(addr, mem_value, instr); + Write2W(addr, mem_value, instr_.instr()); break; } case SDR: { uint8_t al_offset = (rs + se_imm16) & kInt64AlignmentMask; uint64_t mask = (1UL << al_offset * 8) - 1; addr = rs + se_imm16 - al_offset; - uint64_t mem_value = Read2W(addr, instr); + uint64_t mem_value = Read2W(addr, instr_.instr()); mem_value = (rt << al_offset * 8) | (mem_value & mask); - Write2W(addr, mem_value, instr); + Write2W(addr, mem_value, instr_.instr()); break; } case LWC1: set_fpu_register(ft_reg, kFPUInvalidResult); // Trash upper 32 bits. - set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr)); + set_fpu_register_word(ft_reg, ReadW(rs + se_imm16, instr_.instr())); break; case LDC1: - set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr)); + set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr_.instr())); break; case SWC1: { int32_t alu_out_32 = static_cast(get_fpu_register(ft_reg)); - WriteW(rs + se_imm16, alu_out_32, instr); + WriteW(rs + se_imm16, alu_out_32, instr_.instr()); break; } case SDC1: - WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr); + WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr_.instr()); break; // ------------- PC-Relative instructions. case PCREL: { // rt field: checking 5-bits. - int32_t imm21 = instr->Imm21Value(); + int32_t imm21 = instr_.Imm21Value(); int64_t current_pc = get_pc(); uint8_t rt = (imm21 >> kImm16Bits); switch (rt) { @@ -4720,14 +4714,14 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { alu_out = current_pc + (se_imm16 << 16); break; default: { - int32_t imm19 = instr->Imm19Value(); + int32_t imm19 = instr_.Imm19Value(); // rt field: checking the most significant 3-bits. rt = (imm21 >> kImm18Bits); switch (rt) { case LDPC: addr = (current_pc & static_cast(~0x7)) + (se_imm18 << 3); - alu_out = Read2W(addr, instr); + alu_out = Read2W(addr, instr_.instr()); break; default: { // rt field: checking the most significant 2-bits. @@ -4791,13 +4785,14 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { // Type 3: instructions using a 26 bytes immediate. (e.g. j, jal). -void Simulator::DecodeTypeJump(Instruction* instr) { +void Simulator::DecodeTypeJump() { + SimInstruction simInstr = instr_; // Get current pc. int64_t current_pc = get_pc(); // Get unchanged bits of pc. int64_t pc_high_bits = current_pc & 0xfffffffff0000000; // Next pc. - int64_t next_pc = pc_high_bits | (instr->Imm26Value() << 2); + int64_t next_pc = pc_high_bits | (simInstr.Imm26Value() << 2); // Execute branch delay slot. // We don't check for end_sim_pc. First it should not be met as the current pc @@ -4808,7 +4803,7 @@ void Simulator::DecodeTypeJump(Instruction* instr) { // Update pc and ra if necessary. // Do this after the branch delay execution. - if (instr->IsLinkingInstruction()) { + if (simInstr.IsLinkingInstruction()) { set_register(31, current_pc + 2 * Instruction::kInstrSize); } set_pc(next_pc); @@ -4833,15 +4828,16 @@ void Simulator::InstructionDecode(Instruction* instr) { dasm.InstructionDecode(buffer, reinterpret_cast(instr)); } - switch (instr->InstructionType(Instruction::TypeChecks::EXTRA)) { + instr_ = instr; + switch (instr_.InstructionType()) { case Instruction::kRegisterType: - DecodeTypeRegister(instr); + DecodeTypeRegister(); break; case Instruction::kImmediateType: - DecodeTypeImmediate(instr); + DecodeTypeImmediate(); break; case Instruction::kJumpType: - DecodeTypeJump(instr); + DecodeTypeJump(); break; default: UNSUPPORTED(); diff --git a/src/mips64/simulator-mips64.h b/src/mips64/simulator-mips64.h index cd606e2402..dd050f1f10 100644 --- a/src/mips64/simulator-mips64.h +++ b/src/mips64/simulator-mips64.h @@ -122,6 +122,39 @@ class CachePage { char validity_map_[kValidityMapSize]; // One byte per line. }; +class SimInstructionBase : public InstructionBase { + public: + Type InstructionType() const { return type_; } + inline Instruction* instr() const { return instr_; } + inline int32_t operand() const { return operand_; } + + protected: + SimInstructionBase() : operand_(-1), instr_(nullptr), type_(kUnsupported) {} + explicit SimInstructionBase(Instruction* instr) {} + + int32_t operand_; + Instruction* instr_; + Type type_; + + private: + DISALLOW_ASSIGN(SimInstructionBase); +}; + +class SimInstruction : public InstructionGetters { + public: + SimInstruction() {} + + explicit SimInstruction(Instruction* instr) { *this = instr; } + + SimInstruction& operator=(Instruction* instr) { + operand_ = *reinterpret_cast(instr); + instr_ = instr; + type_ = InstructionBase::InstructionType(EXTRA); + DCHECK(reinterpret_cast(&operand_) == this); + return *this; + } +}; + class Simulator { public: friend class MipsDebugger; @@ -314,6 +347,8 @@ class Simulator { inline int32_t SetDoubleHIW(double* addr); inline int32_t SetDoubleLOW(double* addr); + SimInstruction instr_; + // functions called from DecodeTypeRegister. void DecodeTypeRegisterCOP1(); @@ -335,40 +370,36 @@ class Simulator { void DecodeTypeRegisterLRsType(); // Executing is handled based on the instruction type. - void DecodeTypeRegister(Instruction* instr); + void DecodeTypeRegister(); - Instruction* currentInstr_; - inline Instruction* get_instr() const { return currentInstr_; } - inline void set_instr(Instruction* instr) { currentInstr_ = instr; } - - inline int32_t rs_reg() const { return currentInstr_->RsValue(); } + inline int32_t rs_reg() const { return instr_.RsValue(); } inline int64_t rs() const { return get_register(rs_reg()); } inline uint64_t rs_u() const { return static_cast(get_register(rs_reg())); } - inline int32_t rt_reg() const { return currentInstr_->RtValue(); } + inline int32_t rt_reg() const { return instr_.RtValue(); } inline int64_t rt() const { return get_register(rt_reg()); } inline uint64_t rt_u() const { return static_cast(get_register(rt_reg())); } - inline int32_t rd_reg() const { return currentInstr_->RdValue(); } - inline int32_t fr_reg() const { return currentInstr_->FrValue(); } - inline int32_t fs_reg() const { return currentInstr_->FsValue(); } - inline int32_t ft_reg() const { return currentInstr_->FtValue(); } - inline int32_t fd_reg() const { return currentInstr_->FdValue(); } - inline int32_t sa() const { return currentInstr_->SaValue(); } - inline int32_t lsa_sa() const { return currentInstr_->LsaSaValue(); } + inline int32_t rd_reg() const { return instr_.RdValue(); } + inline int32_t fr_reg() const { return instr_.FrValue(); } + inline int32_t fs_reg() const { return instr_.FsValue(); } + inline int32_t ft_reg() const { return instr_.FtValue(); } + inline int32_t fd_reg() const { return instr_.FdValue(); } + inline int32_t sa() const { return instr_.SaValue(); } + inline int32_t lsa_sa() const { return instr_.LsaSaValue(); } inline void SetResult(const int32_t rd_reg, const int64_t alu_out) { set_register(rd_reg, alu_out); TraceRegWr(alu_out); } - void DecodeTypeImmediate(Instruction* instr); - void DecodeTypeJump(Instruction* instr); + void DecodeTypeImmediate(); + void DecodeTypeJump(); // Used for breakpoints and traps. - void SoftwareInterrupt(Instruction* instr); + void SoftwareInterrupt(); // Compact branch guard. void CheckForbiddenSlot(int64_t current_pc) {