diff options
Diffstat (limited to 'deps/v8/src/mips64/simulator-mips64.cc')
-rw-r--r-- | deps/v8/src/mips64/simulator-mips64.cc | 998 |
1 files changed, 811 insertions, 187 deletions
diff --git a/deps/v8/src/mips64/simulator-mips64.cc b/deps/v8/src/mips64/simulator-mips64.cc index 65ed498e5a..e992efebf5 100644 --- a/deps/v8/src/mips64/simulator-mips64.cc +++ b/deps/v8/src/mips64/simulator-mips64.cc @@ -13,6 +13,7 @@ #include "src/base/bits.h" #include "src/codegen.h" #include "src/disasm.h" +#include "src/macro-assembler.h" #include "src/mips64/constants-mips64.h" #include "src/mips64/simulator-mips64.h" #include "src/ostreams.h" @@ -163,7 +164,7 @@ bool MipsDebugger::GetValue(const char* desc, int64_t* value) { bool MipsDebugger::SetBreakpoint(Instruction* breakpc) { // Check if a breakpoint can be set. If not return without any side-effects. - if (sim_->break_pc_ != NULL) { + if (sim_->break_pc_ != nullptr) { return false; } @@ -177,25 +178,25 @@ bool MipsDebugger::SetBreakpoint(Instruction* breakpc) { bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) { - if (sim_->break_pc_ != NULL) { + if (sim_->break_pc_ != nullptr) { sim_->break_pc_->SetInstructionBits(sim_->break_instr_); } - sim_->break_pc_ = NULL; + sim_->break_pc_ = nullptr; sim_->break_instr_ = 0; return true; } void MipsDebugger::UndoBreakpoints() { - if (sim_->break_pc_ != NULL) { + if (sim_->break_pc_ != nullptr) { sim_->break_pc_->SetInstructionBits(sim_->break_instr_); } } void MipsDebugger::RedoBreakpoints() { - if (sim_->break_pc_ != NULL) { + if (sim_->break_pc_ != nullptr) { sim_->break_pc_->SetInstructionBits(kBreakpointInstr); } } @@ -333,11 +334,11 @@ void MipsDebugger::Debug() { last_pc = sim_->get_pc(); } char* line = ReadLine("sim> "); - if (line == NULL) { + if (line == nullptr) { break; } else { char* last_input = sim_->last_debugger_input(); - if (strcmp(line, "\n") == 0 && last_input != NULL) { + if (strcmp(line, "\n") == 0 && last_input != nullptr) { line = last_input; } else { // Ownership is transferred to sim_; @@ -434,8 +435,8 @@ void MipsDebugger::Debug() { PrintF("printobject <value>\n"); } } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) { - int64_t* cur = NULL; - int64_t* end = NULL; + int64_t* cur = nullptr; + int64_t* end = nullptr; int next_arg = 1; if (strcmp(cmd, "stack") == 0) { @@ -488,8 +489,8 @@ void MipsDebugger::Debug() { // Use a reasonably large buffer. v8::internal::EmbeddedVector<char, 256> buffer; - byte* cur = NULL; - byte* end = NULL; + byte* cur = nullptr; + byte* end = nullptr; if (argc == 1) { cur = reinterpret_cast<byte*>(sim_->get_pc()); @@ -546,7 +547,7 @@ void MipsDebugger::Debug() { PrintF("break <address>\n"); } } else if (strcmp(cmd, "del") == 0) { - if (!DeleteBreakpoint(NULL)) { + if (!DeleteBreakpoint(nullptr)) { PrintF("deleting breakpoint failed\n"); } } else if (strcmp(cmd, "flags") == 0) { @@ -622,8 +623,8 @@ void MipsDebugger::Debug() { // Use a reasonably large buffer. v8::internal::EmbeddedVector<char, 256> buffer; - byte* cur = NULL; - byte* end = NULL; + byte* cur = nullptr; + byte* end = nullptr; if (argc == 1) { cur = reinterpret_cast<byte*>(sim_->get_pc()); @@ -716,8 +717,8 @@ void MipsDebugger::Debug() { static bool ICacheMatch(void* one, void* two) { - DCHECK((reinterpret_cast<intptr_t>(one) & CachePage::kPageMask) == 0); - DCHECK((reinterpret_cast<intptr_t>(two) & CachePage::kPageMask) == 0); + DCHECK_EQ(reinterpret_cast<intptr_t>(one) & CachePage::kPageMask, 0); + DCHECK_EQ(reinterpret_cast<intptr_t>(two) & CachePage::kPageMask, 0); return one == two; } @@ -763,7 +764,7 @@ void Simulator::FlushICache(base::CustomMatcherHashMap* i_cache, CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache, void* page) { base::HashMap::Entry* entry = i_cache->LookupOrInsert(page, ICacheHash(page)); - if (entry->value == NULL) { + if (entry->value == nullptr) { CachePage* new_page = new CachePage(); entry->value = new_page; } @@ -774,10 +775,10 @@ CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache, // Flush from start up to and not including start + size. void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start, size_t size) { - DCHECK(size <= CachePage::kPageSize); + DCHECK_LE(size, CachePage::kPageSize); DCHECK(AllOnOnePage(start, size - 1)); - DCHECK((start & CachePage::kLineMask) == 0); - DCHECK((size & CachePage::kLineMask) == 0); + DCHECK_EQ(start & CachePage::kLineMask, 0); + DCHECK_EQ(size & CachePage::kLineMask, 0); void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask)); int offset = (start & CachePage::kPageMask); CachePage* cache_page = GetCachePage(i_cache, page); @@ -818,7 +819,7 @@ void Simulator::Initialize(Isolate* isolate) { Simulator::Simulator(Isolate* isolate) : isolate_(isolate) { i_cache_ = isolate_->simulator_i_cache(); - if (i_cache_ == NULL) { + if (i_cache_ == nullptr) { i_cache_ = new base::CustomMatcherHashMap(&ICacheMatch); isolate_->set_simulator_i_cache(i_cache_); } @@ -830,7 +831,7 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) { pc_modified_ = false; icount_ = 0; break_count_ = 0; - break_pc_ = NULL; + break_pc_ = nullptr; break_instr_ = 0; // Set up architecture state. @@ -859,7 +860,7 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) { registers_[pc] = bad_ra; registers_[ra] = bad_ra; - last_debugger_input_ = NULL; + last_debugger_input_ = nullptr; } @@ -880,7 +881,7 @@ class Redirection { : external_function_(external_function), swi_instruction_(rtCallRedirInstr), type_(type), - next_(NULL) { + next_(nullptr) { next_ = isolate->simulator_redirection(); Simulator::current(isolate)-> FlushICache(isolate->simulator_i_cache(), @@ -899,8 +900,11 @@ class Redirection { static Redirection* Get(Isolate* isolate, void* external_function, ExternalReference::Type type) { Redirection* current = isolate->simulator_redirection(); - for (; current != NULL; current = current->next_) { - if (current->external_function_ == external_function) return current; + for (; current != nullptr; current = current->next_) { + if (current->external_function_ == external_function && + current->type_ == type) { + return current; + } } return new Redirection(isolate, external_function, type); } @@ -962,11 +966,11 @@ void* Simulator::RedirectExternalReference(Isolate* isolate, Simulator* Simulator::current(Isolate* isolate) { v8::internal::Isolate::PerIsolateThreadData* isolate_data = isolate->FindOrAllocatePerThreadDataForThisThread(); - DCHECK(isolate_data != NULL); - DCHECK(isolate_data != NULL); + DCHECK_NOT_NULL(isolate_data); + DCHECK_NOT_NULL(isolate_data); Simulator* sim = isolate_data->simulator(); - if (sim == NULL) { + if (sim == nullptr) { // TODO(146): delete the simulator object when a thread/isolate goes away. sim = new Simulator(isolate); isolate_data->set_simulator(sim); @@ -1971,7 +1975,7 @@ void Simulator::TraceMemWr(int64_t addr, T value) { // on all the ReadXX functions, I don't think re-interpret cast does it. int32_t Simulator::ReadW(int64_t addr, Instruction* instr, TraceType t) { if (addr >=0 && addr < 0x400) { - // This has to be a NULL-dereference, drop into debugger. + // This has to be a nullptr-dereference, drop into debugger. PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR " \n", addr, reinterpret_cast<intptr_t>(instr)); @@ -1991,7 +1995,7 @@ int32_t Simulator::ReadW(int64_t addr, Instruction* instr, TraceType t) { uint32_t Simulator::ReadWU(int64_t addr, Instruction* instr) { if (addr >=0 && addr < 0x400) { - // This has to be a NULL-dereference, drop into debugger. + // This has to be a nullptr-dereference, drop into debugger. PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR " \n", addr, reinterpret_cast<intptr_t>(instr)); @@ -2011,7 +2015,7 @@ uint32_t Simulator::ReadWU(int64_t addr, Instruction* instr) { void Simulator::WriteW(int64_t addr, int32_t value, Instruction* instr) { if (addr >= 0 && addr < 0x400) { - // This has to be a NULL-dereference, drop into debugger. + // This has to be a nullptr-dereference, drop into debugger. PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR " \n", addr, reinterpret_cast<intptr_t>(instr)); @@ -2031,7 +2035,7 @@ void Simulator::WriteW(int64_t addr, int32_t value, Instruction* instr) { int64_t Simulator::Read2W(int64_t addr, Instruction* instr) { if (addr >=0 && addr < 0x400) { - // This has to be a NULL-dereference, drop into debugger. + // This has to be a nullptr-dereference, drop into debugger. PrintF("Memory read from bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR " \n", addr, reinterpret_cast<intptr_t>(instr)); @@ -2051,7 +2055,7 @@ int64_t Simulator::Read2W(int64_t addr, Instruction* instr) { void Simulator::Write2W(int64_t addr, int64_t value, Instruction* instr) { if (addr >= 0 && addr < 0x400) { - // This has to be a NULL-dereference, drop into debugger. + // This has to be a nullptr-dereference, drop into debugger. PrintF("Memory write to bad address: 0x%08" PRIx64 " , pc=0x%08" PRIxPTR "\n", addr, reinterpret_cast<intptr_t>(instr)); @@ -2520,8 +2524,8 @@ bool Simulator::IsStopInstruction(Instruction* instr) { bool Simulator::IsEnabledStop(uint64_t code) { - DCHECK(code <= kMaxStopCode); - DCHECK(code > kMaxWatchpointCode); + DCHECK_LE(code, kMaxStopCode); + DCHECK_GT(code, kMaxWatchpointCode); return !(watched_stops_[code].count & kStopDisabledBit); } @@ -2541,7 +2545,7 @@ void Simulator::DisableStop(uint64_t code) { void Simulator::IncreaseStopCounter(uint64_t code) { - DCHECK(code <= kMaxStopCode); + DCHECK_LE(code, kMaxStopCode); if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) { PrintF("Stop counter for code %" PRId64 " has overflowed.\n" @@ -2725,7 +2729,7 @@ void Simulator::DecodeTypeRegisterSRsType() { fcsr_cc = get_fcsr_condition_bit(cc); switch (instr_.FunctionFieldRaw()) { case RINT: { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); float result, temp_result; double temp; float upper = std::ceil(fs); @@ -2775,11 +2779,11 @@ void Simulator::DecodeTypeRegisterSRsType() { fs, ft)); break; case MADDF_S: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUFloatResult(fd_reg(), std::fma(fs, ft, fd)); break; case MSUBF_S: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUFloatResult(fd_reg(), std::fma(-fs, ft, fd)); break; case MUL_S: @@ -2913,7 +2917,7 @@ void Simulator::DecodeTypeRegisterSRsType() { (posInf << 6) | (negZero << 5) | (negSubnorm << 4) | (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan; - DCHECK(result != 0); + DCHECK_NE(result, 0); fResult = bit_cast<float>(result); SetFPUFloatResult(fd_reg(), fResult); @@ -3022,46 +3026,46 @@ void Simulator::DecodeTypeRegisterSRsType() { break; } case MINA: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUFloatResult(fd_reg(), FPUMinA(ft, fs)); break; case MAXA: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUFloatResult(fd_reg(), FPUMaxA(ft, fs)); break; case MIN: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUFloatResult(fd_reg(), FPUMin(ft, fs)); break; case MAX: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUFloatResult(fd_reg(), FPUMax(ft, fs)); break; case SEL: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUFloatResult(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft); break; case SELEQZ_C: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUFloatResult( fd_reg(), (ft_int & 0x1) == 0 ? get_fpu_register_float(fs_reg()) : 0.0); break; case SELNEZ_C: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUFloatResult( fd_reg(), (ft_int & 0x1) != 0 ? get_fpu_register_float(fs_reg()) : 0.0); break; case MOVZ_C: { - DCHECK(kArchVariant == kMips64r2); + DCHECK_EQ(kArchVariant, kMips64r2); if (rt() == 0) { SetFPUFloatResult(fd_reg(), fs); } break; } case MOVN_C: { - DCHECK(kArchVariant == kMips64r2); + DCHECK_EQ(kArchVariant, kMips64r2); if (rt() != 0) { SetFPUFloatResult(fd_reg(), fs); } @@ -3102,7 +3106,7 @@ void Simulator::DecodeTypeRegisterDRsType() { int64_t fd_int = bit_cast<int64_t>(fd); switch (instr_.FunctionFieldRaw()) { case RINT: { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); double result, temp, temp_result; double upper = std::ceil(fs); double lower = std::floor(fs); @@ -3139,26 +3143,26 @@ void Simulator::DecodeTypeRegisterDRsType() { break; } case SEL: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUDoubleResult(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft); break; case SELEQZ_C: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUDoubleResult(fd_reg(), (ft_int & 0x1) == 0 ? fs : 0.0); break; case SELNEZ_C: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUDoubleResult(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0); break; case MOVZ_C: { - DCHECK(kArchVariant == kMips64r2); + DCHECK_EQ(kArchVariant, kMips64r2); if (rt() == 0) { SetFPUDoubleResult(fd_reg(), fs); } break; } case MOVN_C: { - DCHECK(kArchVariant == kMips64r2); + DCHECK_EQ(kArchVariant, kMips64r2); if (rt() != 0) { SetFPUDoubleResult(fd_reg(), fs); } @@ -3178,19 +3182,19 @@ void Simulator::DecodeTypeRegisterDRsType() { break; } case MINA: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUDoubleResult(fd_reg(), FPUMinA(ft, fs)); break; case MAXA: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUDoubleResult(fd_reg(), FPUMaxA(ft, fs)); break; case MIN: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUDoubleResult(fd_reg(), FPUMin(ft, fs)); break; case MAX: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUDoubleResult(fd_reg(), FPUMax(ft, fs)); break; case ADD_D: @@ -3206,11 +3210,11 @@ void Simulator::DecodeTypeRegisterDRsType() { [](double lhs, double rhs) { return lhs - rhs; }, fs, ft)); break; case MADDF_D: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUDoubleResult(fd_reg(), std::fma(fs, ft, fd)); break; case MSUBF_D: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetFPUDoubleResult(fd_reg(), std::fma(-fs, ft, fd)); break; case MUL_D: @@ -3444,7 +3448,7 @@ void Simulator::DecodeTypeRegisterDRsType() { (posInf << 6) | (negZero << 5) | (negSubnorm << 4) | (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan; - DCHECK(result != 0); + DCHECK_NE(result, 0); dResult = bit_cast<double>(result); SetFPUDoubleResult(fd_reg(), dResult); @@ -3654,7 +3658,7 @@ void Simulator::DecodeTypeRegisterCOP1() { break; case CFC1: // At the moment only FCSR is supported. - DCHECK(fs_reg() == kFCSRRegister); + DCHECK_EQ(fs_reg(), kFCSRRegister); SetResult(rt_reg(), FCSR_); break; case MFC1: @@ -3670,12 +3674,12 @@ void Simulator::DecodeTypeRegisterCOP1() { break; case CTC1: { // At the moment only FCSR is supported. - DCHECK(fs_reg() == kFCSRRegister); + DCHECK_EQ(fs_reg(), kFCSRRegister); uint32_t reg = static_cast<uint32_t>(rt()); if (kArchVariant == kMips64r6) { FCSR_ = reg | kFCSRNaN2008FlagMask; } else { - DCHECK(kArchVariant == kMips64r2); + DCHECK_EQ(kArchVariant, kMips64r2); FCSR_ = reg & ~kFCSRNaN2008FlagMask; } TraceRegWr(FCSR_); @@ -3715,7 +3719,7 @@ void Simulator::DecodeTypeRegisterCOP1() { void Simulator::DecodeTypeRegisterCOP1X() { switch (instr_.FunctionFieldRaw()) { case MADD_S: { - DCHECK(kArchVariant == kMips64r2); + DCHECK_EQ(kArchVariant, kMips64r2); float fr, ft, fs; fr = get_fpu_register_float(fr_reg()); fs = get_fpu_register_float(fs_reg()); @@ -3724,7 +3728,7 @@ void Simulator::DecodeTypeRegisterCOP1X() { break; } case MSUB_S: { - DCHECK(kArchVariant == kMips64r2); + DCHECK_EQ(kArchVariant, kMips64r2); float fr, ft, fs; fr = get_fpu_register_float(fr_reg()); fs = get_fpu_register_float(fs_reg()); @@ -3733,7 +3737,7 @@ void Simulator::DecodeTypeRegisterCOP1X() { break; } case MADD_D: { - DCHECK(kArchVariant == kMips64r2); + DCHECK_EQ(kArchVariant, kMips64r2); double fr, ft, fs; fr = get_fpu_register_double(fr_reg()); fs = get_fpu_register_double(fs_reg()); @@ -3742,7 +3746,7 @@ void Simulator::DecodeTypeRegisterCOP1X() { break; } case MSUB_D: { - DCHECK(kArchVariant == kMips64r2); + DCHECK_EQ(kArchVariant, kMips64r2); double fr, ft, fs; fr = get_fpu_register_double(fr_reg()); fs = get_fpu_register_double(fs_reg()); @@ -3764,11 +3768,11 @@ void Simulator::DecodeTypeRegisterSPECIAL() { switch (instr_.FunctionFieldRaw()) { case SELEQZ_S: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetResult(rd_reg(), rt() == 0 ? rs() : 0); break; case SELNEZ_S: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetResult(rd_reg(), rt() != 0 ? rs() : 0); break; case JR: { @@ -3904,7 +3908,7 @@ void Simulator::DecodeTypeRegisterSPECIAL() { SetResult(rd_reg(), rt() >> rs()); break; case LSA: { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); int8_t sa = lsa_sa() + 1; int32_t _rt = static_cast<int32_t>(rt()); int32_t _rs = static_cast<int32_t>(rs()); @@ -3914,29 +3918,29 @@ void Simulator::DecodeTypeRegisterSPECIAL() { break; } case DLSA: - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt()); break; case MFHI: // MFHI == CLZ on R6. if (kArchVariant != kMips64r6) { - DCHECK(sa() == 0); + DCHECK_EQ(sa(), 0); alu_out = get_register(HI); } else { // MIPS spec: If no bits were set in GPR rs(), the result written to // GPR rd() is 32. - DCHECK(sa() == 1); + DCHECK_EQ(sa(), 1); alu_out = base::bits::CountLeadingZeros32(static_cast<int32_t>(rs_u())); } SetResult(rd_reg(), alu_out); break; case MFLO: // MFLO == DCLZ on R6. if (kArchVariant != kMips64r6) { - DCHECK(sa() == 0); + DCHECK_EQ(sa(), 0); alu_out = get_register(LO); } else { // MIPS spec: If no bits were set in GPR rs(), the result written to // GPR rd() is 64. - DCHECK(sa() == 1); + DCHECK_EQ(sa(), 1); alu_out = base::bits::CountLeadingZeros64(static_cast<int64_t>(rs_u())); } SetResult(rd_reg(), alu_out); @@ -4640,7 +4644,7 @@ int Simulator::DecodeMsaDataFormat() { } void Simulator::DecodeTypeMsaI8() { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); DCHECK(CpuFeatures::IsSupported(MIPS_SIMD)); uint32_t opcode = instr_.InstructionBits() & kMsaI8Mask; int8_t i8 = instr_.MsaImm8Value(); @@ -4790,7 +4794,7 @@ T Simulator::MsaI5InstrHelper(uint32_t opcode, T ws, int32_t i5) { } void Simulator::DecodeTypeMsaI5() { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); DCHECK(CpuFeatures::IsSupported(MIPS_SIMD)); uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask; msa_reg_t ws, wd; @@ -4826,7 +4830,7 @@ void Simulator::DecodeTypeMsaI5() { } void Simulator::DecodeTypeMsaI10() { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); DCHECK(CpuFeatures::IsSupported(MIPS_SIMD)); uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask; int64_t s10 = (static_cast<int64_t>(instr_.MsaImm10Value()) << 54) >> 54; @@ -4863,25 +4867,28 @@ void Simulator::DecodeTypeMsaI10() { } void Simulator::DecodeTypeMsaELM() { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); DCHECK(CpuFeatures::IsSupported(MIPS_SIMD)); uint32_t opcode = instr_.InstructionBits() & kMsaLongerELMMask; int32_t n = instr_.MsaElmNValue(); int64_t alu_out; switch (opcode) { case CTCMSA: - DCHECK(sa() == kMSACSRRegister); + DCHECK_EQ(sa(), kMSACSRRegister); MSACSR_ = bit_cast<uint32_t>( static_cast<int32_t>(registers_[rd_reg()] & kMaxUInt32)); TraceRegWr(static_cast<int32_t>(MSACSR_)); break; case CFCMSA: - DCHECK(rd_reg() == kMSACSRRegister); + DCHECK_EQ(rd_reg(), kMSACSRRegister); SetResult(sa(), static_cast<int64_t>(bit_cast<int32_t>(MSACSR_))); break; - case MOVE_V: - UNIMPLEMENTED(); - break; + case MOVE_V: { + msa_reg_t ws; + get_msa_register(ws_reg(), &ws); + set_msa_register(wd_reg(), &ws); + TraceMSARegWr(&ws); + } break; default: opcode &= kMsaELMMask; switch (opcode) { @@ -4890,28 +4897,28 @@ void Simulator::DecodeTypeMsaELM() { msa_reg_t ws; switch (DecodeMsaDataFormat()) { case MSA_BYTE: - DCHECK(n < kMSALanesByte); + DCHECK_LT(n, kMSALanesByte); get_msa_register(instr_.WsValue(), ws.b); alu_out = static_cast<int32_t>(ws.b[n]); SetResult(wd_reg(), (opcode == COPY_U) ? alu_out & 0xFFu : alu_out); break; case MSA_HALF: - DCHECK(n < kMSALanesHalf); + DCHECK_LT(n, kMSALanesHalf); get_msa_register(instr_.WsValue(), ws.h); alu_out = static_cast<int32_t>(ws.h[n]); SetResult(wd_reg(), (opcode == COPY_U) ? alu_out & 0xFFFFu : alu_out); break; case MSA_WORD: - DCHECK(n < kMSALanesWord); + DCHECK_LT(n, kMSALanesWord); get_msa_register(instr_.WsValue(), ws.w); alu_out = static_cast<int32_t>(ws.w[n]); SetResult(wd_reg(), (opcode == COPY_U) ? alu_out & 0xFFFFFFFFu : alu_out); break; case MSA_DWORD: - DCHECK(n < kMSALanesDword); + DCHECK_LT(n, kMSALanesDword); get_msa_register(instr_.WsValue(), ws.d); alu_out = static_cast<int64_t>(ws.d[n]); SetResult(wd_reg(), alu_out); @@ -4924,7 +4931,7 @@ void Simulator::DecodeTypeMsaELM() { msa_reg_t wd; switch (DecodeMsaDataFormat()) { case MSA_BYTE: { - DCHECK(n < kMSALanesByte); + DCHECK_LT(n, kMSALanesByte); int64_t rs = get_register(instr_.WsValue()); get_msa_register(instr_.WdValue(), wd.b); wd.b[n] = rs & 0xFFu; @@ -4933,7 +4940,7 @@ void Simulator::DecodeTypeMsaELM() { break; } case MSA_HALF: { - DCHECK(n < kMSALanesHalf); + DCHECK_LT(n, kMSALanesHalf); int64_t rs = get_register(instr_.WsValue()); get_msa_register(instr_.WdValue(), wd.h); wd.h[n] = rs & 0xFFFFu; @@ -4942,7 +4949,7 @@ void Simulator::DecodeTypeMsaELM() { break; } case MSA_WORD: { - DCHECK(n < kMSALanesWord); + DCHECK_LT(n, kMSALanesWord); int64_t rs = get_register(instr_.WsValue()); get_msa_register(instr_.WdValue(), wd.w); wd.w[n] = rs & 0xFFFFFFFFu; @@ -4951,7 +4958,7 @@ void Simulator::DecodeTypeMsaELM() { break; } case MSA_DWORD: { - DCHECK(n < kMSALanesDword); + DCHECK_LT(n, kMSALanesDword); int64_t rs = get_register(instr_.WsValue()); get_msa_register(instr_.WdValue(), wd.d); wd.d[n] = rs; @@ -4963,7 +4970,50 @@ void Simulator::DecodeTypeMsaELM() { UNREACHABLE(); } } break; - case SLDI: + case SLDI: { + uint8_t v[32]; + msa_reg_t ws; + msa_reg_t wd; + get_msa_register(ws_reg(), &ws); + get_msa_register(wd_reg(), &wd); +#define SLDI_DF(s, k) \ + for (unsigned i = 0; i < s; i++) { \ + v[i] = ws.b[s * k + i]; \ + v[i + s] = wd.b[s * k + i]; \ + } \ + for (unsigned i = 0; i < s; i++) { \ + wd.b[s * k + i] = v[i + n]; \ + } + switch (DecodeMsaDataFormat()) { + case MSA_BYTE: + DCHECK(n < kMSALanesByte); + SLDI_DF(kMSARegSize / sizeof(int8_t) / kBitsPerByte, 0) + break; + case MSA_HALF: + DCHECK(n < kMSALanesHalf); + for (int k = 0; k < 2; ++k) { + SLDI_DF(kMSARegSize / sizeof(int16_t) / kBitsPerByte, k) + } + break; + case MSA_WORD: + DCHECK(n < kMSALanesWord); + for (int k = 0; k < 4; ++k) { + SLDI_DF(kMSARegSize / sizeof(int32_t) / kBitsPerByte, k) + } + break; + case MSA_DWORD: + DCHECK(n < kMSALanesDword); + for (int k = 0; k < 8; ++k) { + SLDI_DF(kMSARegSize / sizeof(int64_t) / kBitsPerByte, k) + } + break; + default: + UNREACHABLE(); + } + set_msa_register(wd_reg(), &wd); + TraceMSARegWr(&wd); + } break; +#undef SLDI_DF case SPLATI: case INSVE: UNIMPLEMENTED(); @@ -5063,7 +5113,7 @@ T Simulator::MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m) { } void Simulator::DecodeTypeMsaBIT() { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); DCHECK(CpuFeatures::IsSupported(MIPS_SIMD)); uint32_t opcode = instr_.InstructionBits() & kMsaBITMask; int32_t m = instr_.MsaBitMValue(); @@ -5100,10 +5150,11 @@ void Simulator::DecodeTypeMsaBIT() { default: UNREACHABLE(); } +#undef MSA_BIT_DF } void Simulator::DecodeTypeMsaMI10() { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); DCHECK(CpuFeatures::IsSupported(MIPS_SIMD)); uint32_t opcode = instr_.InstructionBits() & kMsaMI10Mask; int64_t s10 = (static_cast<int64_t>(instr_.MsaImmMI10Value()) << 54) >> 54; @@ -5382,13 +5433,6 @@ T Simulator::Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt) { case DPSUB_U: case SLD: case SPLAT: - case PCKEV: - case PCKOD: - case ILVL: - case ILVR: - case ILVEV: - case ILVOD: - case VSHF: UNIMPLEMENTED(); break; case SRAR: { @@ -5400,108 +5444,616 @@ T Simulator::Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt) { int bit = wt_modulo == 0 ? 0 : (wsu >> (wt_modulo - 1)) & 1; res = static_cast<T>((wsu >> wt_modulo) + bit); } break; + default: + UNREACHABLE(); + } + return res; +} +template <typename T_int, typename T_reg> +void Msa3RInstrHelper_shuffle(const uint32_t opcode, T_reg ws, T_reg wt, + T_reg wd, const int i, const int num_of_lanes) { + T_int *ws_p, *wt_p, *wd_p; + ws_p = reinterpret_cast<T_int*>(ws); + wt_p = reinterpret_cast<T_int*>(wt); + wd_p = reinterpret_cast<T_int*>(wd); + switch (opcode) { + case PCKEV: + wd_p[i] = wt_p[2 * i]; + wd_p[i + num_of_lanes / 2] = ws_p[2 * i]; + break; + case PCKOD: + wd_p[i] = wt_p[2 * i + 1]; + wd_p[i + num_of_lanes / 2] = ws_p[2 * i + 1]; + break; + case ILVL: + wd_p[2 * i] = wt_p[i + num_of_lanes / 2]; + wd_p[2 * i + 1] = ws_p[i + num_of_lanes / 2]; + break; + case ILVR: + wd_p[2 * i] = wt_p[i]; + wd_p[2 * i + 1] = ws_p[i]; + break; + case ILVEV: + wd_p[2 * i] = wt_p[2 * i]; + wd_p[2 * i + 1] = ws_p[2 * i]; + break; + case ILVOD: + wd_p[2 * i] = wt_p[2 * i + 1]; + wd_p[2 * i + 1] = ws_p[2 * i + 1]; + break; + case VSHF: { + const int mask_not_valid = 0xc0; + const int mask_6_bits = 0x3f; + if ((wd_p[i] & mask_not_valid)) { + wd_p[i] = 0; + } else { + int k = (wd_p[i] & mask_6_bits) % (num_of_lanes * 2); + wd_p[i] = k >= num_of_lanes ? ws_p[k - num_of_lanes] : wt_p[k]; + } + } break; + default: + UNREACHABLE(); + } +} + +template <typename T_int, typename T_smaller_int, typename T_reg> +void Msa3RInstrHelper_horizontal(const uint32_t opcode, T_reg ws, T_reg wt, + T_reg wd, const int i, + const int num_of_lanes) { + typedef typename std::make_unsigned<T_int>::type T_uint; + typedef typename std::make_unsigned<T_smaller_int>::type T_smaller_uint; + T_int* wd_p; + T_smaller_int *ws_p, *wt_p; + ws_p = reinterpret_cast<T_smaller_int*>(ws); + wt_p = reinterpret_cast<T_smaller_int*>(wt); + wd_p = reinterpret_cast<T_int*>(wd); + T_uint* wd_pu; + T_smaller_uint *ws_pu, *wt_pu; + ws_pu = reinterpret_cast<T_smaller_uint*>(ws); + wt_pu = reinterpret_cast<T_smaller_uint*>(wt); + wd_pu = reinterpret_cast<T_uint*>(wd); + switch (opcode) { case HADD_S: + wd_p[i] = + static_cast<T_int>(ws_p[2 * i + 1]) + static_cast<T_int>(wt_p[2 * i]); + break; case HADD_U: + wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) + + static_cast<T_uint>(wt_pu[2 * i]); + break; case HSUB_S: + wd_p[i] = + static_cast<T_int>(ws_p[2 * i + 1]) - static_cast<T_int>(wt_p[2 * i]); + break; case HSUB_U: - UNIMPLEMENTED(); + wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) - + static_cast<T_uint>(wt_pu[2 * i]); break; default: UNREACHABLE(); } - return res; } void Simulator::DecodeTypeMsa3R() { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); DCHECK(CpuFeatures::IsSupported(MIPS_SIMD)); uint32_t opcode = instr_.InstructionBits() & kMsa3RMask; msa_reg_t ws, wd, wt; - + get_msa_register(ws_reg(), &ws); + get_msa_register(wt_reg(), &wt); + get_msa_register(wd_reg(), &wd); + switch (opcode) { + case HADD_S: + case HADD_U: + case HSUB_S: + case HSUB_U: +#define HORIZONTAL_ARITHMETIC_DF(num_of_lanes, int_type, lesser_int_type) \ + for (int i = 0; i < num_of_lanes; ++i) { \ + Msa3RInstrHelper_horizontal<int_type, lesser_int_type>( \ + opcode, &ws, &wt, &wd, i, num_of_lanes); \ + } + switch (DecodeMsaDataFormat()) { + case MSA_HALF: + HORIZONTAL_ARITHMETIC_DF(kMSALanesHalf, int16_t, int8_t); + break; + case MSA_WORD: + HORIZONTAL_ARITHMETIC_DF(kMSALanesWord, int32_t, int16_t); + break; + case MSA_DWORD: + HORIZONTAL_ARITHMETIC_DF(kMSALanesDword, int64_t, int32_t); + break; + default: + UNREACHABLE(); + } + break; +#undef HORIZONTAL_ARITHMETIC_DF + case VSHF: +#define VSHF_DF(num_of_lanes, int_type) \ + for (int i = 0; i < num_of_lanes; ++i) { \ + Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \ + num_of_lanes); \ + } + switch (DecodeMsaDataFormat()) { + case MSA_BYTE: + VSHF_DF(kMSALanesByte, int8_t); + break; + case MSA_HALF: + VSHF_DF(kMSALanesHalf, int16_t); + break; + case MSA_WORD: + VSHF_DF(kMSALanesWord, int32_t); + break; + case MSA_DWORD: + VSHF_DF(kMSALanesDword, int64_t); + break; + default: + UNREACHABLE(); + } +#undef VSHF_DF + break; + case PCKEV: + case PCKOD: + case ILVL: + case ILVR: + case ILVEV: + case ILVOD: +#define INTERLEAVE_PACK_DF(num_of_lanes, int_type) \ + for (int i = 0; i < num_of_lanes / 2; ++i) { \ + Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \ + num_of_lanes); \ + } + switch (DecodeMsaDataFormat()) { + case MSA_BYTE: + INTERLEAVE_PACK_DF(kMSALanesByte, int8_t); + break; + case MSA_HALF: + INTERLEAVE_PACK_DF(kMSALanesHalf, int16_t); + break; + case MSA_WORD: + INTERLEAVE_PACK_DF(kMSALanesWord, int32_t); + break; + case MSA_DWORD: + INTERLEAVE_PACK_DF(kMSALanesDword, int64_t); + break; + default: + UNREACHABLE(); + } + break; +#undef INTERLEAVE_PACK_DF + default: #define MSA_3R_DF(elem, num_of_lanes) \ - get_msa_register(instr_.WdValue(), wd.elem); \ - get_msa_register(instr_.WsValue(), ws.elem); \ - get_msa_register(instr_.WtValue(), wt.elem); \ for (int i = 0; i < num_of_lanes; i++) { \ wd.elem[i] = Msa3RInstrHelper(opcode, wd.elem[i], ws.elem[i], wt.elem[i]); \ - } \ - set_msa_register(instr_.WdValue(), wd.elem); \ - TraceMSARegWr(wd.elem); + } - switch (DecodeMsaDataFormat()) { - case MSA_BYTE: - MSA_3R_DF(b, kMSALanesByte); + switch (DecodeMsaDataFormat()) { + case MSA_BYTE: + MSA_3R_DF(b, kMSALanesByte); + break; + case MSA_HALF: + MSA_3R_DF(h, kMSALanesHalf); + break; + case MSA_WORD: + MSA_3R_DF(w, kMSALanesWord); + break; + case MSA_DWORD: + MSA_3R_DF(d, kMSALanesDword); + break; + default: + UNREACHABLE(); + } +#undef MSA_3R_DF break; - case MSA_HALF: - MSA_3R_DF(h, kMSALanesHalf); + } + set_msa_register(wd_reg(), &wd); + TraceMSARegWr(&wd); +} + +template <typename T_int, typename T_fp, typename T_reg> +void Msa3RFInstrHelper(uint32_t opcode, T_reg ws, T_reg wt, T_reg& wd) { + const T_int all_ones = static_cast<T_int>(-1); + const T_fp s_element = *reinterpret_cast<T_fp*>(&ws); + const T_fp t_element = *reinterpret_cast<T_fp*>(&wt); + switch (opcode) { + case FCUN: { + if (std::isnan(s_element) || std::isnan(t_element)) { + wd = all_ones; + } else { + wd = 0; + } + } break; + case FCEQ: { + if (s_element != t_element || std::isnan(s_element) || + std::isnan(t_element)) { + wd = 0; + } else { + wd = all_ones; + } + } break; + case FCUEQ: { + if (s_element == t_element || std::isnan(s_element) || + std::isnan(t_element)) { + wd = all_ones; + } else { + wd = 0; + } + } break; + case FCLT: { + if (s_element >= t_element || std::isnan(s_element) || + std::isnan(t_element)) { + wd = 0; + } else { + wd = all_ones; + } + } break; + case FCULT: { + if (s_element < t_element || std::isnan(s_element) || + std::isnan(t_element)) { + wd = all_ones; + } else { + wd = 0; + } + } break; + case FCLE: { + if (s_element > t_element || std::isnan(s_element) || + std::isnan(t_element)) { + wd = 0; + } else { + wd = all_ones; + } + } break; + case FCULE: { + if (s_element <= t_element || std::isnan(s_element) || + std::isnan(t_element)) { + wd = all_ones; + } else { + wd = 0; + } + } break; + case FCOR: { + if (std::isnan(s_element) || std::isnan(t_element)) { + wd = 0; + } else { + wd = all_ones; + } + } break; + case FCUNE: { + if (s_element != t_element || std::isnan(s_element) || + std::isnan(t_element)) { + wd = all_ones; + } else { + wd = 0; + } + } break; + case FCNE: { + if (s_element == t_element || std::isnan(s_element) || + std::isnan(t_element)) { + wd = 0; + } else { + wd = all_ones; + } + } break; + case FADD: + wd = bit_cast<T_int>(s_element + t_element); break; - case MSA_WORD: - MSA_3R_DF(w, kMSALanesWord); + case FSUB: + wd = bit_cast<T_int>(s_element - t_element); break; - case MSA_DWORD: - MSA_3R_DF(d, kMSALanesDword); + case FMUL: + wd = bit_cast<T_int>(s_element * t_element); + break; + case FDIV: { + if (t_element == 0) { + wd = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN()); + } else { + wd = bit_cast<T_int>(s_element / t_element); + } + } break; + case FMADD: + wd = bit_cast<T_int>( + std::fma(s_element, t_element, *reinterpret_cast<T_fp*>(&wd))); + break; + case FMSUB: + wd = bit_cast<T_int>( + std::fma(-s_element, t_element, *reinterpret_cast<T_fp*>(&wd))); + break; + case FEXP2: + wd = bit_cast<T_int>(std::ldexp(s_element, static_cast<int>(wt))); + break; + case FMIN: + wd = bit_cast<T_int>(std::min(s_element, t_element)); + break; + case FMAX: + wd = bit_cast<T_int>(std::max(s_element, t_element)); + break; + case FMIN_A: { + wd = bit_cast<T_int>( + std::fabs(s_element) < std::fabs(t_element) ? s_element : t_element); + } break; + case FMAX_A: { + wd = bit_cast<T_int>( + std::fabs(s_element) > std::fabs(t_element) ? s_element : t_element); + } break; + case FSOR: + case FSUNE: + case FSNE: + case FSAF: + case FSUN: + case FSEQ: + case FSUEQ: + case FSLT: + case FSULT: + case FSLE: + case FSULE: + UNIMPLEMENTED(); break; default: UNREACHABLE(); } -#undef MSA_3R_DF +} + +template <typename T_int, typename T_int_dbl, typename T_reg> +void Msa3RFInstrHelper2(uint32_t opcode, T_reg ws, T_reg wt, T_reg& wd) { + // typedef typename std::make_unsigned<T_int>::type T_uint; + typedef typename std::make_unsigned<T_int_dbl>::type T_uint_dbl; + const T_int max_int = std::numeric_limits<T_int>::max(); + const T_int min_int = std::numeric_limits<T_int>::min(); + const int shift = kBitsPerByte * sizeof(T_int) - 1; + const T_int_dbl reg_s = ws; + const T_int_dbl reg_t = wt; + T_int_dbl product, result; + product = reg_s * reg_t; + switch (opcode) { + case MUL_Q: { + const T_int_dbl min_fix_dbl = + bit_cast<T_uint_dbl>(std::numeric_limits<T_int_dbl>::min()) >> 1U; + const T_int_dbl max_fix_dbl = std::numeric_limits<T_int_dbl>::max() >> 1U; + if (product == min_fix_dbl) { + product = max_fix_dbl; + } + wd = static_cast<T_int>(product >> shift); + } break; + case MADD_Q: { + result = (product + (static_cast<T_int_dbl>(wd) << shift)) >> shift; + wd = static_cast<T_int>( + result > max_int ? max_int : result < min_int ? min_int : result); + } break; + case MSUB_Q: { + result = (-product + (static_cast<T_int_dbl>(wd) << shift)) >> shift; + wd = static_cast<T_int>( + result > max_int ? max_int : result < min_int ? min_int : result); + } break; + case MULR_Q: { + const T_int_dbl min_fix_dbl = + bit_cast<T_uint_dbl>(std::numeric_limits<T_int_dbl>::min()) >> 1U; + const T_int_dbl max_fix_dbl = std::numeric_limits<T_int_dbl>::max() >> 1U; + if (product == min_fix_dbl) { + wd = static_cast<T_int>(max_fix_dbl >> shift); + break; + } + wd = static_cast<T_int>((product + (1 << (shift - 1))) >> shift); + } break; + case MADDR_Q: { + result = (product + (static_cast<T_int_dbl>(wd) << shift) + + (1 << (shift - 1))) >> + shift; + wd = static_cast<T_int>( + result > max_int ? max_int : result < min_int ? min_int : result); + } break; + case MSUBR_Q: { + result = (-product + (static_cast<T_int_dbl>(wd) << shift) + + (1 << (shift - 1))) >> + shift; + wd = static_cast<T_int>( + result > max_int ? max_int : result < min_int ? min_int : result); + } break; + default: + UNREACHABLE(); + } } void Simulator::DecodeTypeMsa3RF() { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); DCHECK(CpuFeatures::IsSupported(MIPS_SIMD)); uint32_t opcode = instr_.InstructionBits() & kMsa3RFMask; + msa_reg_t wd, ws, wt; + if (opcode != FCAF) { + get_msa_register(ws_reg(), &ws); + get_msa_register(wt_reg(), &wt); + } switch (opcode) { case FCAF: - case FCUN: - case FCEQ: - case FCUEQ: - case FCLT: - case FCULT: - case FCLE: - case FCULE: - case FSAF: - case FSUN: - case FSEQ: - case FSUEQ: - case FSLT: - case FSULT: - case FSLE: - case FSULE: - case FADD: - case FSUB: - case FMUL: - case FDIV: - case FMADD: - case FMSUB: - case FEXP2: + wd.d[0] = 0; + wd.d[1] = 0; + break; case FEXDO: +#define PACK_FLOAT16(sign, exp, frac) \ + static_cast<uint16_t>(((sign) << 15) + ((exp) << 10) + (frac)) +#define FEXDO_DF(source, dst) \ + do { \ + element = source; \ + aSign = element >> 31; \ + aExp = element >> 23 & 0xFF; \ + aFrac = element & 0x007FFFFF; \ + if (aExp == 0xFF) { \ + if (aFrac) { \ + /* Input is a NaN */ \ + dst = 0x7DFFU; \ + break; \ + } \ + /* Infinity */ \ + dst = PACK_FLOAT16(aSign, 0x1f, 0); \ + break; \ + } else if (aExp == 0 && aFrac == 0) { \ + dst = PACK_FLOAT16(aSign, 0, 0); \ + break; \ + } else { \ + int maxexp = 29; \ + uint32_t mask; \ + uint32_t increment; \ + bool rounding_bumps_exp; \ + aFrac |= 0x00800000; \ + aExp -= 0x71; \ + if (aExp < 1) { \ + /* Will be denormal in halfprec */ \ + mask = 0x00ffffff; \ + if (aExp >= -11) { \ + mask >>= 11 + aExp; \ + } \ + } else { \ + /* Normal number in halfprec */ \ + mask = 0x00001fff; \ + } \ + switch (MSACSR_ & 3) { \ + case kRoundToNearest: \ + increment = (mask + 1) >> 1; \ + if ((aFrac & mask) == increment) { \ + increment = aFrac & (increment << 1); \ + } \ + break; \ + case kRoundToPlusInf: \ + increment = aSign ? 0 : mask; \ + break; \ + case kRoundToMinusInf: \ + increment = aSign ? mask : 0; \ + break; \ + case kRoundToZero: \ + increment = 0; \ + break; \ + } \ + rounding_bumps_exp = (aFrac + increment >= 0x01000000); \ + if (aExp > maxexp || (aExp == maxexp && rounding_bumps_exp)) { \ + dst = PACK_FLOAT16(aSign, 0x1f, 0); \ + break; \ + } \ + aFrac += increment; \ + if (rounding_bumps_exp) { \ + aFrac >>= 1; \ + aExp++; \ + } \ + if (aExp < -10) { \ + dst = PACK_FLOAT16(aSign, 0, 0); \ + break; \ + } \ + if (aExp < 0) { \ + aFrac >>= -aExp; \ + aExp = 0; \ + } \ + dst = PACK_FLOAT16(aSign, aExp, aFrac >> 13); \ + } \ + } while (0); + switch (DecodeMsaDataFormat()) { + case MSA_HALF: + for (int i = 0; i < kMSALanesWord; i++) { + uint_fast32_t element; + uint_fast32_t aSign, aFrac; + int_fast32_t aExp; + FEXDO_DF(ws.uw[i], wd.uh[i + kMSALanesHalf / 2]) + FEXDO_DF(wt.uw[i], wd.uh[i]) + } + break; + case MSA_WORD: + for (int i = 0; i < kMSALanesDword; i++) { + wd.w[i + kMSALanesWord / 2] = bit_cast<int32_t>( + static_cast<float>(bit_cast<double>(ws.d[i]))); + wd.w[i] = bit_cast<int32_t>( + static_cast<float>(bit_cast<double>(wt.d[i]))); + } + break; + default: + UNREACHABLE(); + } + break; +#undef PACK_FLOAT16 +#undef FEXDO_DF case FTQ: - case FMIN: - case FMIN_A: - case FMAX: - case FMAX_A: - case FCOR: - case FCUNE: - case FCNE: - case MUL_Q: +#define FTQ_DF(source, dst, fp_type, int_type) \ + element = bit_cast<fp_type>(source) * \ + (1U << (sizeof(int_type) * kBitsPerByte - 1)); \ + if (element > std::numeric_limits<int_type>::max()) { \ + dst = std::numeric_limits<int_type>::max(); \ + } else if (element < std::numeric_limits<int_type>::min()) { \ + dst = std::numeric_limits<int_type>::min(); \ + } else if (std::isnan(element)) { \ + dst = 0; \ + } else { \ + int_type fixed_point; \ + round_according_to_msacsr(element, element, fixed_point); \ + dst = fixed_point; \ + } + + switch (DecodeMsaDataFormat()) { + case MSA_HALF: + for (int i = 0; i < kMSALanesWord; i++) { + float element; + FTQ_DF(ws.w[i], wd.h[i + kMSALanesHalf / 2], float, int16_t) + FTQ_DF(wt.w[i], wd.h[i], float, int16_t) + } + break; + case MSA_WORD: + double element; + for (int i = 0; i < kMSALanesDword; i++) { + FTQ_DF(ws.d[i], wd.w[i + kMSALanesWord / 2], double, int32_t) + FTQ_DF(wt.d[i], wd.w[i], double, int32_t) + } + break; + default: + UNREACHABLE(); + } + break; +#undef FTQ_DF +#define MSA_3RF_DF(T1, T2, Lanes, ws, wt, wd) \ + for (int i = 0; i < Lanes; i++) { \ + Msa3RFInstrHelper<T1, T2>(opcode, ws, wt, wd); \ + } +#define MSA_3RF_DF2(T1, T2, Lanes, ws, wt, wd) \ + for (int i = 0; i < Lanes; i++) { \ + Msa3RFInstrHelper2<T1, T2>(opcode, ws, wt, wd); \ + } case MADD_Q: case MSUB_Q: - case FSOR: - case FSUNE: - case FSNE: - case MULR_Q: case MADDR_Q: case MSUBR_Q: - UNIMPLEMENTED(); + get_msa_register(wd_reg(), &wd); // fall-through + case MUL_Q: + case MULR_Q: + switch (DecodeMsaDataFormat()) { + case MSA_HALF: + MSA_3RF_DF2(int16_t, int32_t, kMSALanesHalf, ws.h[i], wt.h[i], + wd.h[i]) + break; + case MSA_WORD: + MSA_3RF_DF2(int32_t, int64_t, kMSALanesWord, ws.w[i], wt.w[i], + wd.w[i]) + break; + default: + UNREACHABLE(); + } break; default: - UNREACHABLE(); + if (opcode == FMADD || opcode == FMSUB) { + get_msa_register(wd_reg(), &wd); + } + switch (DecodeMsaDataFormat()) { + case MSA_WORD: + MSA_3RF_DF(int32_t, float, kMSALanesWord, ws.w[i], wt.w[i], wd.w[i]) + break; + case MSA_DWORD: + MSA_3RF_DF(int64_t, double, kMSALanesDword, ws.d[i], wt.d[i], wd.d[i]) + break; + default: + UNREACHABLE(); + } + break; +#undef MSA_3RF_DF +#undef MSA_3RF_DF2 } + set_msa_register(wd_reg(), &wd); + TraceMSARegWr(&wd); } void Simulator::DecodeTypeMsaVec() { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); DCHECK(CpuFeatures::IsSupported(MIPS_SIMD)); uint32_t opcode = instr_.InstructionBits() & kMsaVECMask; msa_reg_t wd, ws, wt; @@ -5544,7 +6096,7 @@ void Simulator::DecodeTypeMsaVec() { } void Simulator::DecodeTypeMsa2R() { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); DCHECK(CpuFeatures::IsSupported(MIPS_SIMD)); uint32_t opcode = instr_.InstructionBits() & kMsa2RMask; msa_reg_t wd, ws; @@ -5594,7 +6146,7 @@ void Simulator::DecodeTypeMsa2R() { get_msa_register(instr_.WsValue(), ws.elem); \ for (int i = 0; i < num_of_lanes; i++) { \ uint64_t u64elem = static_cast<uint64_t>(ws.elem[i]); \ - wd.elem[i] = base::bits::CountPopulation64(u64elem); \ + wd.elem[i] = base::bits::CountPopulation(u64elem); \ } \ set_msa_register(instr_.WdValue(), wd.elem); \ TraceMSARegWr(wd.elem) @@ -5766,8 +6318,8 @@ T_int Msa2RFInstrHelper(uint32_t opcode, T_src src, T_dst& dst, const T_int min_int = std::numeric_limits<T_int>::min(); if (std::isnan(element)) { dst = 0; - } else if (element > max_int || element < min_int) { - dst = element > max_int ? max_int : min_int; + } else if (element >= max_int || element <= min_int) { + dst = element >= max_int ? max_int : min_int; } else { dst = static_cast<T_int>(std::trunc(element)); } @@ -5778,8 +6330,8 @@ T_int Msa2RFInstrHelper(uint32_t opcode, T_src src, T_dst& dst, const T_uint max_int = std::numeric_limits<T_uint>::max(); if (std::isnan(element)) { dst = 0; - } else if (element > max_int || element < 0) { - dst = element > max_int ? max_int : 0; + } else if (element >= max_int || element <= 0) { + dst = element >= max_int ? max_int : 0; } else { dst = static_cast<T_uint>(std::trunc(element)); } @@ -5888,8 +6440,8 @@ T_int Msa2RFInstrHelper(uint32_t opcode, T_src src, T_dst& dst, return 0; } -template <typename T_int, typename T_fp, typename T_reg, typename T_i> -T_int Msa2RFInstrHelper2(uint32_t opcode, T_reg ws, T_i i) { +template <typename T_int, typename T_fp, typename T_reg> +T_int Msa2RFInstrHelper2(uint32_t opcode, T_reg ws, int i) { switch (opcode) { #define EXTRACT_FLOAT16_SIGN(fp16) (fp16 >> 15) #define EXTRACT_FLOAT16_EXP(fp16) (fp16 >> 10 & 0x1f) @@ -5965,7 +6517,7 @@ T_int Msa2RFInstrHelper2(uint32_t opcode, T_reg ws, T_i i) { } void Simulator::DecodeTypeMsa2RF() { - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); DCHECK(CpuFeatures::IsSupported(MIPS_SIMD)); uint32_t opcode = instr_.InstructionBits() & kMsa2RFMask; msa_reg_t wd, ws; @@ -6119,6 +6671,30 @@ void Simulator::DecodeTypeImmediate() { } }; + auto BranchHelper_MSA = [this, &next_pc, imm16, + &execute_branch_delay_instruction](bool do_branch) { + execute_branch_delay_instruction = true; + int64_t current_pc = get_pc(); + const int32_t bitsIn16Int = sizeof(int16_t) * kBitsPerByte; + if (do_branch) { + if (FLAG_debug_code) { + int16_t bits = imm16 & 0xfc; + if (imm16 >= 0) { + CHECK_EQ(bits, 0); + } else { + CHECK_EQ(bits ^ 0xfc, 0); + } + } + // jump range :[pc + kInstrSize - 512 * kInstrSize, + // pc + kInstrSize + 511 * kInstrSize] + int16_t offset = static_cast<int16_t>(imm16 << (bitsIn16Int - 10)) >> + (bitsIn16Int - 12); + next_pc = current_pc + offset + Instruction::kInstrSize; + } else { + next_pc = current_pc + 2 * Instruction::kInstrSize; + } + }; + auto BranchAndLinkCompactHelper = [this, &next_pc](bool do_branch, int bits) { int64_t current_pc = get_pc(); CheckForbiddenSlot(current_pc); @@ -6160,18 +6736,66 @@ void Simulator::DecodeTypeImmediate() { case BC1NEZ: BranchHelper(get_fpu_register(ft_reg) & 0x1); break; - case BZ_V: + case BZ_V: { + msa_reg_t wt; + get_msa_register(wt_reg(), &wt); + BranchHelper_MSA(wt.d[0] == 0 && wt.d[1] == 0); + } break; +#define BZ_DF(witdh, lanes) \ + { \ + msa_reg_t wt; \ + get_msa_register(wt_reg(), &wt); \ + int i; \ + for (i = 0; i < lanes; ++i) { \ + if (wt.witdh[i] == 0) { \ + break; \ + } \ + } \ + BranchHelper_MSA(i != lanes); \ + } case BZ_B: + BZ_DF(b, kMSALanesByte) + break; case BZ_H: + BZ_DF(h, kMSALanesHalf) + break; case BZ_W: + BZ_DF(w, kMSALanesWord) + break; case BZ_D: - case BNZ_V: + BZ_DF(d, kMSALanesDword) + break; +#undef BZ_DF + case BNZ_V: { + msa_reg_t wt; + get_msa_register(wt_reg(), &wt); + BranchHelper_MSA(wt.d[0] != 0 || wt.d[1] != 0); + } break; +#define BNZ_DF(witdh, lanes) \ + { \ + msa_reg_t wt; \ + get_msa_register(wt_reg(), &wt); \ + int i; \ + for (i = 0; i < lanes; ++i) { \ + if (wt.witdh[i] == 0) { \ + break; \ + } \ + } \ + BranchHelper_MSA(i == lanes); \ + } case BNZ_B: + BNZ_DF(b, kMSALanesByte) + break; case BNZ_H: + BNZ_DF(h, kMSALanesHalf) + break; case BNZ_W: + BNZ_DF(w, kMSALanesWord) + break; case BNZ_D: - UNIMPLEMENTED(); + BNZ_DF(d, kMSALanesDword) break; +#undef BNZ_DF default: UNREACHABLE(); } @@ -6376,7 +7000,7 @@ void Simulator::DecodeTypeImmediate() { case LUI: if (rs_reg != 0) { // AUI instruction. - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); int32_t alu32_out = static_cast<int32_t>(rs + (se_imm16 << 16)); SetResult(rt_reg, static_cast<int64_t>(alu32_out)); } else { @@ -6387,8 +7011,8 @@ void Simulator::DecodeTypeImmediate() { } break; case DAUI: - DCHECK(kArchVariant == kMips64r6); - DCHECK(rs_reg != 0); + DCHECK_EQ(kArchVariant, kMips64r6); + DCHECK_NE(rs_reg, 0); SetResult(rt_reg, rs + (se_imm16 << 16)); break; // ------------- Memory instructions. @@ -6513,26 +7137,26 @@ void Simulator::DecodeTypeImmediate() { } case LL: { // LL/SC sequence cannot be simulated properly - DCHECK(kArchVariant == kMips64r2); + DCHECK_EQ(kArchVariant, kMips64r2); set_register(rt_reg, ReadW(rs + se_imm16, instr_.instr())); break; } case SC: { // LL/SC sequence cannot be simulated properly - DCHECK(kArchVariant == kMips64r2); + DCHECK_EQ(kArchVariant, kMips64r2); WriteW(rs + se_imm16, static_cast<int32_t>(rt), instr_.instr()); set_register(rt_reg, 1); break; } case LLD: { // LL/SC sequence cannot be simulated properly - DCHECK(kArchVariant == kMips64r2); + DCHECK_EQ(kArchVariant, kMips64r2); set_register(rt_reg, ReadD(rs + se_imm16, instr_.instr())); break; } case SCD: { // LL/SC sequence cannot be simulated properly - DCHECK(kArchVariant == kMips64r2); + DCHECK_EQ(kArchVariant, kMips64r2); WriteD(rs + se_imm16, rt, instr_.instr()); set_register(rt_reg, 1); break; @@ -6624,7 +7248,7 @@ void Simulator::DecodeTypeImmediate() { switch (instr_.FunctionFieldRaw()) { case LL_R6: { // LL/SC sequence cannot be simulated properly - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); int64_t base = get_register(instr_.BaseValue()); int32_t offset9 = instr_.Imm9Value(); set_register(rt_reg, ReadW(base + offset9, instr_.instr())); @@ -6632,7 +7256,7 @@ void Simulator::DecodeTypeImmediate() { } case LLD_R6: { // LL/SC sequence cannot be simulated properly - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); int64_t base = get_register(instr_.BaseValue()); int32_t offset9 = instr_.Imm9Value(); set_register(rt_reg, ReadD(base + offset9, instr_.instr())); @@ -6640,7 +7264,7 @@ void Simulator::DecodeTypeImmediate() { } case SC_R6: { // LL/SC sequence cannot be simulated properly - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); int64_t base = get_register(instr_.BaseValue()); int32_t offset9 = instr_.Imm9Value(); WriteW(base + offset9, static_cast<int32_t>(rt), instr_.instr()); @@ -6649,7 +7273,7 @@ void Simulator::DecodeTypeImmediate() { } case SCD_R6: { // LL/SC sequence cannot be simulated properly - DCHECK(kArchVariant == kMips64r6); + DCHECK_EQ(kArchVariant, kMips64r6); int64_t base = get_register(instr_.BaseValue()); int32_t offset9 = instr_.Imm9Value(); WriteD(base + offset9, rt, instr_.instr()); @@ -6888,7 +7512,7 @@ int64_t Simulator::Call(byte* entry, int argument_count, ...) { // Set up arguments. // First four arguments passed in registers in both ABI's. - DCHECK(argument_count >= 4); + DCHECK_GE(argument_count, 4); set_register(a0, va_arg(parameters, int64_t)); set_register(a1, va_arg(parameters, int64_t)); set_register(a2, va_arg(parameters, int64_t)); |