diff options
Diffstat (limited to 'deps/v8/src/mips64/simulator-mips64.cc')
-rw-r--r-- | deps/v8/src/mips64/simulator-mips64.cc | 603 |
1 files changed, 452 insertions, 151 deletions
diff --git a/deps/v8/src/mips64/simulator-mips64.cc b/deps/v8/src/mips64/simulator-mips64.cc index 4a7fd7c10f..7fa96442f9 100644 --- a/deps/v8/src/mips64/simulator-mips64.cc +++ b/deps/v8/src/mips64/simulator-mips64.cc @@ -146,7 +146,7 @@ void MipsDebugger::Stop(Instruction* instr) { #else // GENERATED_CODE_COVERAGE -#define UNSUPPORTED() printf("Unsupported instruction.\n"); +#define UNSUPPORTED() printf("Sim: Unsupported instruction.\n"); static void InitializeCoverage() {} @@ -519,7 +519,7 @@ void MipsDebugger::Debug() { reinterpret_cast<intptr_t>(cur), *cur, *cur); HeapObject* obj = reinterpret_cast<HeapObject*>(*cur); int64_t value = *cur; - Heap* current_heap = v8::internal::Isolate::Current()->heap(); + Heap* current_heap = sim_->isolate_->heap(); if (((value & 1) == 0) || current_heap->Contains(obj)) { PrintF(" ("); if ((value & 1) == 0) { @@ -898,7 +898,12 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) { for (int i = 0; i < kNumFPURegisters; i++) { FPUregisters_[i] = 0; } - FCSR_ = 0; + + if (kArchVariant == kMips64r6) { + FCSR_ = kFCSRNaN2008FlagMask; + } else { + FCSR_ = 0; + } // The sp is initialized to point to the bottom (high address) of the // allocated stack area. To be safe in potential stack underflows we leave @@ -926,12 +931,12 @@ Simulator::~Simulator() { free(stack_); } // offset from the swi instruction so the simulator knows what to call. class Redirection { public: - Redirection(void* external_function, ExternalReference::Type type) + Redirection(Isolate* isolate, void* external_function, + ExternalReference::Type type) : external_function_(external_function), swi_instruction_(rtCallRedirInstr), type_(type), next_(NULL) { - Isolate* isolate = Isolate::Current(); next_ = isolate->simulator_redirection(); Simulator::current(isolate)-> FlushICache(isolate->simulator_i_cache(), @@ -947,14 +952,13 @@ class Redirection { void* external_function() { return external_function_; } ExternalReference::Type type() { return type_; } - static Redirection* Get(void* external_function, + static Redirection* Get(Isolate* isolate, void* external_function, ExternalReference::Type type) { - Isolate* isolate = Isolate::Current(); Redirection* current = isolate->simulator_redirection(); for (; current != NULL; current = current->next_) { if (current->external_function_ == external_function) return current; } - return new Redirection(external_function, type); + return new Redirection(isolate, external_function, type); } static Redirection* FromSwiInstruction(Instruction* swi_instruction) { @@ -999,9 +1003,10 @@ void Simulator::TearDown(HashMap* i_cache, Redirection* first) { } -void* Simulator::RedirectExternalReference(void* external_function, +void* Simulator::RedirectExternalReference(Isolate* isolate, + void* external_function, ExternalReference::Type type) { - Redirection* redirection = Redirection::Get(external_function, type); + Redirection* redirection = Redirection::Get(isolate, external_function, type); return redirection->address_of_swi_instruction(); } @@ -1256,6 +1261,8 @@ bool Simulator::set_fcsr_round_error(double original, double rounded) { // Returns true if the operation was invalid. bool Simulator::set_fcsr_round64_error(double original, double rounded) { bool ret = false; + // The value of INT64_MAX (2^63-1) can't be represented as double exactly, + // loading the most accurate representation into max_int64, which is 2^63. double max_int64 = std::numeric_limits<int64_t>::max(); double min_int64 = std::numeric_limits<int64_t>::min(); @@ -1273,7 +1280,7 @@ bool Simulator::set_fcsr_round64_error(double original, double rounded) { ret = true; } - if (rounded > max_int64 || rounded < min_int64) { + if (rounded >= max_int64 || rounded < min_int64) { set_fcsr_bit(kFCSROverflowFlagBit, true); // The reference is not really clear but it seems this is required: set_fcsr_bit(kFCSRInvalidOpFlagBit, true); @@ -1315,11 +1322,135 @@ bool Simulator::set_fcsr_round_error(float original, float rounded) { return ret; } +void Simulator::set_fpu_register_word_invalid_result(float original, + float rounded) { + if (FCSR_ & kFCSRNaN2008FlagMask) { + double max_int32 = std::numeric_limits<int32_t>::max(); + double min_int32 = std::numeric_limits<int32_t>::min(); + if (std::isnan(original)) { + set_fpu_register_word(fd_reg(), 0); + } else if (rounded > max_int32) { + set_fpu_register_word(fd_reg(), kFPUInvalidResult); + } else if (rounded < min_int32) { + set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative); + } else { + UNREACHABLE(); + } + } else { + set_fpu_register_word(fd_reg(), kFPUInvalidResult); + } +} + + +void Simulator::set_fpu_register_invalid_result(float original, float rounded) { + if (FCSR_ & kFCSRNaN2008FlagMask) { + double max_int32 = std::numeric_limits<int32_t>::max(); + double min_int32 = std::numeric_limits<int32_t>::min(); + if (std::isnan(original)) { + set_fpu_register(fd_reg(), 0); + } else if (rounded > max_int32) { + set_fpu_register(fd_reg(), kFPUInvalidResult); + } else if (rounded < min_int32) { + set_fpu_register(fd_reg(), kFPUInvalidResultNegative); + } else { + UNREACHABLE(); + } + } else { + set_fpu_register(fd_reg(), kFPUInvalidResult); + } +} + + +void Simulator::set_fpu_register_invalid_result64(float original, + float rounded) { + if (FCSR_ & kFCSRNaN2008FlagMask) { + // The value of INT64_MAX (2^63-1) can't be represented as double exactly, + // loading the most accurate representation into max_int64, which is 2^63. + double max_int64 = std::numeric_limits<int64_t>::max(); + double min_int64 = std::numeric_limits<int64_t>::min(); + if (std::isnan(original)) { + set_fpu_register(fd_reg(), 0); + } else if (rounded >= max_int64) { + set_fpu_register(fd_reg(), kFPU64InvalidResult); + } else if (rounded < min_int64) { + set_fpu_register(fd_reg(), kFPU64InvalidResultNegative); + } else { + UNREACHABLE(); + } + } else { + set_fpu_register(fd_reg(), kFPU64InvalidResult); + } +} + + +void Simulator::set_fpu_register_word_invalid_result(double original, + double rounded) { + if (FCSR_ & kFCSRNaN2008FlagMask) { + double max_int32 = std::numeric_limits<int32_t>::max(); + double min_int32 = std::numeric_limits<int32_t>::min(); + if (std::isnan(original)) { + set_fpu_register_word(fd_reg(), 0); + } else if (rounded > max_int32) { + set_fpu_register_word(fd_reg(), kFPUInvalidResult); + } else if (rounded < min_int32) { + set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative); + } else { + UNREACHABLE(); + } + } else { + set_fpu_register_word(fd_reg(), kFPUInvalidResult); + } +} + + +void Simulator::set_fpu_register_invalid_result(double original, + double rounded) { + if (FCSR_ & kFCSRNaN2008FlagMask) { + double max_int32 = std::numeric_limits<int32_t>::max(); + double min_int32 = std::numeric_limits<int32_t>::min(); + if (std::isnan(original)) { + set_fpu_register(fd_reg(), 0); + } else if (rounded > max_int32) { + set_fpu_register(fd_reg(), kFPUInvalidResult); + } else if (rounded < min_int32) { + set_fpu_register(fd_reg(), kFPUInvalidResultNegative); + } else { + UNREACHABLE(); + } + } else { + set_fpu_register(fd_reg(), kFPUInvalidResult); + } +} + + +void Simulator::set_fpu_register_invalid_result64(double original, + double rounded) { + if (FCSR_ & kFCSRNaN2008FlagMask) { + // The value of INT64_MAX (2^63-1) can't be represented as double exactly, + // loading the most accurate representation into max_int64, which is 2^63. + double max_int64 = std::numeric_limits<int64_t>::max(); + double min_int64 = std::numeric_limits<int64_t>::min(); + if (std::isnan(original)) { + set_fpu_register(fd_reg(), 0); + } else if (rounded >= max_int64) { + set_fpu_register(fd_reg(), kFPU64InvalidResult); + } else if (rounded < min_int64) { + set_fpu_register(fd_reg(), kFPU64InvalidResultNegative); + } else { + UNREACHABLE(); + } + } else { + set_fpu_register(fd_reg(), kFPU64InvalidResult); + } +} + // Sets the rounding error codes in FCSR based on the result of the rounding. // Returns true if the operation was invalid. bool Simulator::set_fcsr_round64_error(float original, float rounded) { bool ret = false; + // The value of INT64_MAX (2^63-1) can't be represented as double exactly, + // loading the most accurate representation into max_int64, which is 2^63. double max_int64 = std::numeric_limits<int64_t>::max(); double min_int64 = std::numeric_limits<int64_t>::min(); @@ -1337,7 +1468,7 @@ bool Simulator::set_fcsr_round64_error(float original, float rounded) { ret = true; } - if (rounded > max_int64 || rounded < min_int64) { + if (rounded >= max_int64 || rounded < min_int64) { set_fcsr_bit(kFCSROverflowFlagBit, true); // The reference is not really clear but it seems this is required: set_fcsr_bit(kFCSRInvalidOpFlagBit, true); @@ -2259,10 +2390,12 @@ void Simulator::DecodeTypeRegisterSRsType() { set_fpu_register_float(fd_reg(), -fs); break; case SQRT_S: - set_fpu_register_float(fd_reg(), fast_sqrt(fs)); + lazily_initialize_fast_sqrt(isolate_); + set_fpu_register_float(fd_reg(), fast_sqrt(fs, isolate_)); break; case RSQRT_S: { - float result = 1.0 / fast_sqrt(fs); + lazily_initialize_fast_sqrt(isolate_); + float result = 1.0 / fast_sqrt(fs, isolate_); set_fpu_register_float(fd_reg(), result); break; } @@ -2369,7 +2502,7 @@ void Simulator::DecodeTypeRegisterSRsType() { round64_according_to_fcsr(fs, rounded, result, fs); set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPU64InvalidResult); + set_fpu_register_invalid_result64(fs, rounded); } break; } @@ -2379,7 +2512,7 @@ void Simulator::DecodeTypeRegisterSRsType() { round_according_to_fcsr(fs, rounded, result, fs); set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register_word(fd_reg(), kFPUInvalidResult); + set_fpu_register_word_invalid_result(fs, rounded); } break; } @@ -2388,7 +2521,7 @@ void Simulator::DecodeTypeRegisterSRsType() { int32_t result = static_cast<int32_t>(rounded); set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register_word(fd_reg(), kFPUInvalidResult); + set_fpu_register_word_invalid_result(fs, rounded); } } break; case TRUNC_L_S: { // Mips64r2 instruction. @@ -2396,7 +2529,7 @@ void Simulator::DecodeTypeRegisterSRsType() { int64_t result = static_cast<int64_t>(rounded); set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPU64InvalidResult); + set_fpu_register_invalid_result64(fs, rounded); } break; } @@ -2410,7 +2543,7 @@ void Simulator::DecodeTypeRegisterSRsType() { } set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register_word(fd_reg(), kFPUInvalidResult); + set_fpu_register_word_invalid_result(fs, rounded); } break; } @@ -2425,7 +2558,7 @@ void Simulator::DecodeTypeRegisterSRsType() { int64_t i64 = static_cast<int64_t>(result); set_fpu_register(fd_reg(), i64); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPU64InvalidResult); + set_fpu_register_invalid_result64(fs, rounded); } break; } @@ -2434,7 +2567,7 @@ void Simulator::DecodeTypeRegisterSRsType() { int64_t result = static_cast<int64_t>(rounded); set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPU64InvalidResult); + set_fpu_register_invalid_result64(fs, rounded); } break; } @@ -2444,7 +2577,7 @@ void Simulator::DecodeTypeRegisterSRsType() { int32_t result = static_cast<int32_t>(rounded); set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register_word(fd_reg(), kFPUInvalidResult); + set_fpu_register_word_invalid_result(fs, rounded); } } break; case CEIL_W_S: // Round double to word towards positive infinity. @@ -2453,7 +2586,7 @@ void Simulator::DecodeTypeRegisterSRsType() { int32_t result = static_cast<int32_t>(rounded); set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPUInvalidResult); + set_fpu_register_invalid_result(fs, rounded); } } break; case CEIL_L_S: { // Mips64r2 instruction. @@ -2461,7 +2594,7 @@ void Simulator::DecodeTypeRegisterSRsType() { int64_t result = static_cast<int64_t>(rounded); set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPU64InvalidResult); + set_fpu_register_invalid_result64(fs, rounded); } break; } @@ -2764,10 +2897,12 @@ void Simulator::DecodeTypeRegisterDRsType() { set_fpu_register_double(fd_reg(), -fs); break; case SQRT_D: - set_fpu_register_double(fd_reg(), fast_sqrt(fs)); + lazily_initialize_fast_sqrt(isolate_); + set_fpu_register_double(fd_reg(), fast_sqrt(fs, isolate_)); break; case RSQRT_D: { - double result = 1.0 / fast_sqrt(fs); + lazily_initialize_fast_sqrt(isolate_); + double result = 1.0 / fast_sqrt(fs, isolate_); set_fpu_register_double(fd_reg(), result); break; } @@ -2803,7 +2938,7 @@ void Simulator::DecodeTypeRegisterDRsType() { round_according_to_fcsr(fs, rounded, result, fs); set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register_word(fd_reg(), kFPUInvalidResult); + set_fpu_register_word_invalid_result(fs, rounded); } break; } @@ -2818,7 +2953,7 @@ void Simulator::DecodeTypeRegisterDRsType() { } set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPUInvalidResult); + set_fpu_register_invalid_result(fs, rounded); } } break; case TRUNC_W_D: // Truncate double to word (round towards 0). @@ -2827,7 +2962,7 @@ void Simulator::DecodeTypeRegisterDRsType() { int32_t result = static_cast<int32_t>(rounded); set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPUInvalidResult); + set_fpu_register_invalid_result(fs, rounded); } } break; case FLOOR_W_D: // Round double to word towards negative infinity. @@ -2836,7 +2971,7 @@ void Simulator::DecodeTypeRegisterDRsType() { int32_t result = static_cast<int32_t>(rounded); set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPUInvalidResult); + set_fpu_register_invalid_result(fs, rounded); } } break; case CEIL_W_D: // Round double to word towards positive infinity. @@ -2845,7 +2980,7 @@ void Simulator::DecodeTypeRegisterDRsType() { int32_t result = static_cast<int32_t>(rounded); set_fpu_register_word(fd_reg(), result); if (set_fcsr_round_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPUInvalidResult); + set_fpu_register_invalid_result(fs, rounded); } } break; case CVT_S_D: // Convert double to float (single). @@ -2857,7 +2992,7 @@ void Simulator::DecodeTypeRegisterDRsType() { round64_according_to_fcsr(fs, rounded, result, fs); set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPU64InvalidResult); + set_fpu_register_invalid_result64(fs, rounded); } break; } @@ -2872,7 +3007,7 @@ void Simulator::DecodeTypeRegisterDRsType() { int64_t i64 = static_cast<int64_t>(result); set_fpu_register(fd_reg(), i64); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPU64InvalidResult); + set_fpu_register_invalid_result64(fs, rounded); } break; } @@ -2881,7 +3016,7 @@ void Simulator::DecodeTypeRegisterDRsType() { int64_t result = static_cast<int64_t>(rounded); set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPU64InvalidResult); + set_fpu_register_invalid_result64(fs, rounded); } break; } @@ -2890,7 +3025,7 @@ void Simulator::DecodeTypeRegisterDRsType() { int64_t result = static_cast<int64_t>(rounded); set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPU64InvalidResult); + set_fpu_register_invalid_result64(fs, rounded); } break; } @@ -2899,7 +3034,7 @@ void Simulator::DecodeTypeRegisterDRsType() { int64_t result = static_cast<int64_t>(rounded); set_fpu_register(fd_reg(), result); if (set_fcsr_round64_error(fs, rounded)) { - set_fpu_register(fd_reg(), kFPU64InvalidResult); + set_fpu_register_invalid_result64(fs, rounded); } break; } @@ -3184,11 +3319,18 @@ void Simulator::DecodeTypeRegisterCOP1() { case MFHC1: set_register(rt_reg(), get_fpu_register_hi_word(fs_reg())); break; - case CTC1: + case CTC1: { // At the moment only FCSR is supported. DCHECK(fs_reg() == kFCSRRegister); - FCSR_ = static_cast<uint32_t>(rt()); + uint32_t reg = static_cast<uint32_t>(rt()); + if (kArchVariant == kMips64r6) { + FCSR_ = reg | kFCSRNaN2008FlagMask; + } else { + DCHECK(kArchVariant == kMips64r2); + FCSR_ = reg & ~kFCSRNaN2008FlagMask; + } break; + } case MTC1: // Hardware writes upper 32-bits to zero on mtc1. set_fpu_register_hi_word(fs_reg(), 0); @@ -3352,6 +3494,20 @@ void Simulator::DecodeTypeRegisterSPECIAL() { case DSRAV: SetResult(rd_reg(), rt() >> rs()); break; + case LSA: { + DCHECK(kArchVariant == kMips64r6); + int8_t sa = lsa_sa() + 1; + int32_t _rt = static_cast<int32_t>(rt()); + int32_t _rs = static_cast<int32_t>(rs()); + int32_t res = _rs << sa; + res += _rt; + SetResult(rd_reg(), static_cast<int64_t>(res)); + break; + } + case DLSA: + DCHECK(kArchVariant == kMips64r6); + SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt()); + break; case MFHI: // MFHI == CLZ on R6. if (kArchVariant != kMips64r6) { DCHECK(sa() == 0); @@ -3692,7 +3848,19 @@ void Simulator::DecodeTypeRegisterSPECIAL2() { void Simulator::DecodeTypeRegisterSPECIAL3() { int64_t alu_out; switch (get_instr()->FunctionFieldRaw()) { - case INS: { // Mips32r2 instruction. + case INS: { // Mips64r2 instruction. + // Interpret rd field as 5-bit msb of insert. + uint16_t msb = rd_reg(); + // Interpret sa field as 5-bit lsb of insert. + uint16_t lsb = sa(); + uint16_t size = msb - lsb + 1; + uint64_t mask = (1ULL << size) - 1; + alu_out = static_cast<int32_t>((rt_u() & ~(mask << lsb)) | + ((rs_u() & mask) << lsb)); + SetResult(rt_reg(), alu_out); + break; + } + case DINS: { // Mips64r2 instruction. // Interpret rd field as 5-bit msb of insert. uint16_t msb = rd_reg(); // Interpret sa field as 5-bit lsb of insert. @@ -3703,7 +3871,7 @@ void Simulator::DecodeTypeRegisterSPECIAL3() { SetResult(rt_reg(), alu_out); break; } - case EXT: { // Mips32r2 instruction. + case EXT: { // Mips64r2 instruction. // Interpret rd field as 5-bit msb of extract. uint16_t msb = rd_reg(); // Interpret sa field as 5-bit lsb of extract. @@ -3714,11 +3882,33 @@ void Simulator::DecodeTypeRegisterSPECIAL3() { SetResult(rt_reg(), alu_out); break; } - case DEXT: { // Mips32r2 instruction. + case DEXT: { // Mips64r2 instruction. + // Interpret rd field as 5-bit msb of extract. + uint16_t msb = rd_reg(); + // Interpret sa field as 5-bit lsb of extract. + uint16_t lsb = sa(); + uint16_t size = msb + 1; + uint64_t mask = (1ULL << size) - 1; + alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb); + SetResult(rt_reg(), alu_out); + break; + } + case DEXTM: { // Interpret rd field as 5-bit msb of extract. uint16_t msb = rd_reg(); // Interpret sa field as 5-bit lsb of extract. uint16_t lsb = sa(); + uint16_t size = msb + 33; + uint64_t mask = (1ULL << size) - 1; + alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb); + SetResult(rt_reg(), alu_out); + break; + } + case DEXTU: { + // Interpret rd field as 5-bit msb of extract. + uint16_t msb = rd_reg(); + // Interpret sa field as 5-bit lsb of extract. + uint16_t lsb = sa() + 32; uint16_t size = msb + 1; uint64_t mask = (1ULL << size) - 1; alu_out = static_cast<int64_t>((rs_u() & (mask << lsb)) >> lsb); @@ -3905,27 +4095,7 @@ void Simulator::DecodeTypeRegister(Instruction* instr) { } -// Branch instructions common part. -#define BranchAndLinkHelper(do_branch) \ - execute_branch_delay_instruction = true; \ - if (do_branch) { \ - next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; \ - set_register(31, current_pc + kBranchReturnOffset); \ - } else { \ - next_pc = current_pc + kBranchReturnOffset; \ - } - - -#define BranchHelper(do_branch) \ - execute_branch_delay_instruction = true; \ - if (do_branch) { \ - next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; \ - } else { \ - next_pc = current_pc + kBranchReturnOffset; \ - } - - -// Type 2: instructions using a 16 bytes immediate. (e.g. addi, beq). +// Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc). void Simulator::DecodeTypeImmediate(Instruction* instr) { // Instruction fields. Opcode op = instr->OpcodeFieldRaw(); @@ -3936,21 +4106,15 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { int64_t rt = get_register(rt_reg); int16_t imm16 = instr->Imm16Value(); int32_t imm18 = instr->Imm18Value(); - int32_t imm21 = instr->Imm21Value(); - int32_t imm26 = instr->Imm26Value(); int32_t ft_reg = instr->FtValue(); // Destination register. - int64_t ft = get_fpu_register(ft_reg); // Zero extended immediate. uint64_t oe_imm16 = 0xffff & imm16; // Sign extended immediate. int64_t se_imm16 = imm16; int64_t se_imm18 = imm18 | ((imm18 & 0x20000) ? 0xfffffffffffc0000 : 0); - int64_t se_imm26 = imm26 | ((imm26 & 0x2000000) ? 0xfffffffffc000000 : 0); - // Get current pc. - int64_t current_pc = get_pc(); // Next pc. int64_t next_pc = bad_ra; @@ -3965,7 +4129,57 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { // Alignment for 32-bit integers used in LWL, LWR, etc. const int kInt32AlignmentMask = sizeof(uint32_t) - 1; - // ---------- Configuration (and execution for REGIMM). + // 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 BranchHelper = [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; + } else { + next_pc = current_pc + 2 * Instruction::kInstrSize; + } + }; + + auto BranchAndLinkCompactHelper = [this, instr, &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); + imm <<= 32 - bits; + imm >>= 32 - bits; + next_pc = current_pc + (imm << 2) + Instruction::kInstrSize; + set_register(31, current_pc + Instruction::kInstrSize); + } + }; + + auto BranchCompactHelper = [&next_pc, this, instr](bool do_branch, int bits) { + int64_t current_pc = get_pc(); + CheckForbiddenSlot(current_pc); + if (do_branch) { + int32_t imm = instr->ImmValue(bits); + imm <<= 32 - bits; + imm >>= 32 - bits; + next_pc = get_pc() + (imm << 2) + Instruction::kInstrSize; + } + }; + switch (op) { // ------------- COP1. Coprocessor instructions. case COP1: @@ -3975,32 +4189,14 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { 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; - execute_branch_delay_instruction = true; - // Set next_pc. - if (do_branch) { - next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; - } else { - next_pc = current_pc + kBranchReturnOffset; - } + BranchHelper(do_branch); break; } case BC1EQZ: - execute_branch_delay_instruction = true; - // Set next_pc. - if (!(ft & 0x1)) { - next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; - } else { - next_pc = current_pc + kBranchReturnOffset; - } + BranchHelper(!(get_fpu_register(ft_reg) & 0x1)); break; case BC1NEZ: - execute_branch_delay_instruction = true; - // Set next_pc. - if (ft & 0x1) { - next_pc = current_pc + (imm16 << 2) + Instruction::kInstrSize; - } else { - next_pc = current_pc + kBranchReturnOffset; - } + BranchHelper(get_fpu_register(ft_reg) & 0x1); break; default: UNREACHABLE(); @@ -4021,6 +4217,12 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { case BGEZAL: BranchAndLinkHelper(rs >= 0); break; + case DAHI: + SetResult(rs_reg, rs + (se_imm16 << 32)); + break; + case DATI: + SetResult(rs_reg, rs + (se_imm16 << 48)); + break; default: UNREACHABLE(); } @@ -4034,55 +4236,156 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { case BNE: BranchHelper(rs != rt); break; - case BLEZ: - BranchHelper(rs <= 0); - break; - case BGTZ: - BranchHelper(rs > 0); - break; - case POP66: { - if (rs_reg) { // BEQZC - int32_t se_imm21 = - static_cast<int32_t>(imm21 << (kOpcodeBits + kRsBits)); - se_imm21 = se_imm21 >> (kOpcodeBits + kRsBits); - if (rs == 0) - next_pc = current_pc + 4 + (se_imm21 << 2); - else - next_pc = current_pc + 4; + case POP06: // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6) + if (kArchVariant == kMips64r6) { + if (rt_reg != 0) { + if (rs_reg == 0) { // BLEZALC + BranchAndLinkCompactHelper(rt <= 0, 16); + } else { + if (rs_reg == rt_reg) { // BGEZALC + BranchAndLinkCompactHelper(rt >= 0, 16); + } else { // BGEUC + BranchCompactHelper( + static_cast<uint64_t>(rs) >= static_cast<uint64_t>(rt), 16); + } + } + } else { // BLEZ + BranchHelper(rs <= 0); + } + } else { // BLEZ + BranchHelper(rs <= 0); + } + break; + case POP07: // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6) + if (kArchVariant == kMips64r6) { + if (rt_reg != 0) { + if (rs_reg == 0) { // BGTZALC + BranchAndLinkCompactHelper(rt > 0, 16); + } else { + if (rt_reg == rs_reg) { // BLTZALC + BranchAndLinkCompactHelper(rt < 0, 16); + } else { // BLTUC + BranchCompactHelper( + static_cast<uint64_t>(rs) < static_cast<uint64_t>(rt), 16); + } + } + } else { // BGTZ + BranchHelper(rs > 0); + } + } else { // BGTZ + BranchHelper(rs > 0); + } + break; + case POP26: // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6) + if (kArchVariant == kMips64r6) { + if (rt_reg != 0) { + if (rs_reg == 0) { // BLEZC + BranchCompactHelper(rt <= 0, 16); + } else { + if (rs_reg == rt_reg) { // BGEZC + BranchCompactHelper(rt >= 0, 16); + } else { // BGEC/BLEC + BranchCompactHelper(rs >= rt, 16); + } + } + } + } else { // BLEZL + BranchAndLinkHelper(rs <= 0); + } + break; + case POP27: // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6) + if (kArchVariant == kMips64r6) { + if (rt_reg != 0) { + if (rs_reg == 0) { // BGTZC + BranchCompactHelper(rt > 0, 16); + } else { + if (rs_reg == rt_reg) { // BLTZC + BranchCompactHelper(rt < 0, 16); + } else { // BLTC/BGTC + BranchCompactHelper(rs < rt, 16); + } + } + } + } else { // BGTZL + BranchAndLinkHelper(rs > 0); + } + break; + case POP66: // BEQZC, JIC + if (rs_reg != 0) { // BEQZC + BranchCompactHelper(rs == 0, 21); } else { // JIC next_pc = rt + imm16; } break; - } - case BC: { - next_pc = current_pc + 4 + (se_imm26 << 2); - set_pc(next_pc); - pc_modified_ = true; + case POP76: // BNEZC, JIALC + if (rs_reg != 0) { // BNEZC + BranchCompactHelper(rs != 0, 21); + } else { // JIALC + int64_t current_pc = get_pc(); + set_register(31, current_pc + Instruction::kInstrSize); + next_pc = rt + imm16; + } break; - } - case BALC: { - set_register(31, current_pc + 4); - next_pc = current_pc + 4 + (se_imm26 << 2); - set_pc(next_pc); - pc_modified_ = true; + case BC: + BranchCompactHelper(true, 26); break; - } - // ------------- Arithmetic instructions. - case ADDI: - case DADDI: - if (HaveSameSign(rs, se_imm16)) { - if (rs > 0) { - if (rs > Registers::kMaxValue - se_imm16) { - SignalException(kIntegerOverflow); + case BALC: + BranchAndLinkCompactHelper(true, 26); + break; + case POP10: // BOVC, BEQZALC, BEQC / ADDI (pre-r6) + if (kArchVariant == kMips64r6) { + if (rs_reg >= rt_reg) { // BOVC + if (HaveSameSign(rs, rt)) { + if (rs > 0) { + BranchCompactHelper(rs > Registers::kMaxValue - rt, 16); + } else if (rs < 0) { + BranchCompactHelper(rs < Registers::kMinValue - rt, 16); + } } - } else if (rs < 0) { - if (rs < Registers::kMinValue - se_imm16) { - SignalException(kIntegerUnderflow); + } else { + if (rs_reg == 0) { // BEQZALC + BranchAndLinkCompactHelper(rt == 0, 16); + } else { // BEQC + BranchCompactHelper(rt == rs, 16); } } + } else { // ADDI + if (HaveSameSign(rs, se_imm16)) { + if (rs > 0) { + if (rs <= Registers::kMaxValue - se_imm16) { + SignalException(kIntegerOverflow); + } + } else if (rs < 0) { + if (rs >= Registers::kMinValue - se_imm16) { + SignalException(kIntegerUnderflow); + } + } + } + SetResult(rt_reg, rs + se_imm16); } - SetResult(rt_reg, rs + se_imm16); break; + case POP30: // BNVC, BNEZALC, BNEC / DADDI (pre-r6) + if (kArchVariant == kMips64r6) { + if (rs_reg >= rt_reg) { // BNVC + if (!HaveSameSign(rs, rt) || rs == 0 || rt == 0) { + BranchCompactHelper(true, 16); + } else { + if (rs > 0) { + BranchCompactHelper(rs <= Registers::kMaxValue - rt, 16); + } else if (rs < 0) { + BranchCompactHelper(rs >= Registers::kMinValue - rt, 16); + } + } + } else { + if (rs_reg == 0) { // BNEZALC + BranchAndLinkCompactHelper(rt != 0, 16); + } else { // BNEC + BranchCompactHelper(rt != rs, 16); + } + } + } + break; + // ------------- Arithmetic instructions. case ADDIU: { int32_t alu32_out = static_cast<int32_t>(rs + se_imm16); // Sign-extend result of 32bit operation into 64bit register. @@ -4107,12 +4410,24 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { case XORI: SetResult(rt_reg, rs ^ oe_imm16); break; - case LUI: { - int32_t alu32_out = static_cast<int32_t>(oe_imm16 << 16); - // Sign-extend result of 32bit operation into 64bit register. - SetResult(rt_reg, static_cast<int64_t>(alu32_out)); + case LUI: + if (rs_reg != 0) { + // AUI instruction. + DCHECK(kArchVariant == kMips64r6); + int32_t alu32_out = static_cast<int32_t>(rs + (se_imm16 << 16)); + SetResult(rt_reg, static_cast<int64_t>(alu32_out)); + } else { + // LUI instruction. + int32_t alu32_out = static_cast<int32_t>(oe_imm16 << 16); + // Sign-extend result of 32bit operation into 64bit register. + SetResult(rt_reg, static_cast<int64_t>(alu32_out)); + } + break; + case DAUI: + DCHECK(kArchVariant == kMips64r6); + DCHECK(rs_reg != 0); + SetResult(rt_reg, rs + (se_imm16 << 16)); break; - } // ------------- Memory instructions. case LB: set_register(rt_reg, ReadB(rs + se_imm16)); @@ -4205,22 +4520,11 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { case SDC1: WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr); break; - // ------------- JIALC and BNEZC instructions. - case POP76: { - // Next pc. - next_pc = rt + se_imm16; - // The instruction after the jump is NOT executed. - uint16_t pc_increment = Instruction::kInstrSize; - if (instr->IsLinkingInstruction()) { - set_register(31, current_pc + pc_increment); - } - set_pc(next_pc); - pc_modified_ = true; - break; - } // ------------- PC-Relative instructions. case PCREL: { // rt field: checking 5-bits. + int32_t imm21 = instr->Imm21Value(); + int64_t current_pc = get_pc(); uint8_t rt = (imm21 >> kImm16Bits); switch (rt) { case ALUIPC: @@ -4290,7 +4594,7 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { // We don't check for end_sim_pc. First it should not be met as the current // pc is valid. Secondly a jump should always execute its branch delay slot. Instruction* branch_delay_instr = - reinterpret_cast<Instruction*>(current_pc+Instruction::kInstrSize); + reinterpret_cast<Instruction*>(get_pc() + Instruction::kInstrSize); BranchDelayInstructionDecode(branch_delay_instr); } @@ -4300,9 +4604,6 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) { } } -#undef BranchHelper -#undef BranchAndLinkHelper - // Type 3: instructions using a 26 bytes immediate. (e.g. j, jal). void Simulator::DecodeTypeJump(Instruction* instr) { @@ -4393,7 +4694,7 @@ void Simulator::Execute() { while (program_counter != end_sim_pc) { Instruction* instr = reinterpret_cast<Instruction*>(program_counter); icount_++; - if (icount_ == static_cast<int64_t>(::v8::internal::FLAG_stop_sim_at)) { + if (icount_ == static_cast<uint64_t>(::v8::internal::FLAG_stop_sim_at)) { MipsDebugger dbg(this); dbg.Debug(); } else { |