1// Copyright 2011 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/execution/mips/simulator-mips.h"
6
7// Only build the simulator if not compiling for real MIPS hardware.
8#if defined(USE_SIMULATOR)
9
10#include <limits.h>
11#include <stdarg.h>
12#include <stdlib.h>
13
14#include <cmath>
15
16#include "src/base/bits.h"
17#include "src/base/lazy-instance.h"
18#include "src/base/platform/platform.h"
19#include "src/base/platform/wrappers.h"
20#include "src/base/vector.h"
21#include "src/codegen/assembler-inl.h"
22#include "src/codegen/macro-assembler.h"
23#include "src/codegen/mips/constants-mips.h"
24#include "src/diagnostics/disasm.h"
25#include "src/heap/combined-heap.h"
26#include "src/runtime/runtime-utils.h"
27#include "src/utils/ostreams.h"
28
29namespace v8 {
30namespace internal {
31
32DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor,
33                                Simulator::GlobalMonitor::Get)
34
35// Utils functions.
36bool HaveSameSign(int32_t a, int32_t b) { return ((a ^ b) >= 0); }
37
38uint32_t get_fcsr_condition_bit(uint32_t cc) {
39  if (cc == 0) {
40    return 23;
41  } else {
42    return 24 + cc;
43  }
44}
45
46// This macro provides a platform independent use of sscanf. The reason for
47// SScanF not being implemented in a platform independent was through
48// ::v8::internal::OS in the same way as SNPrintF is that the Windows C Run-Time
49// Library does not provide vsscanf.
50#define SScanF sscanf
51
52// The MipsDebugger class is used by the simulator while debugging simulated
53// code.
54class MipsDebugger {
55 public:
56  explicit MipsDebugger(Simulator* sim) : sim_(sim) {}
57
58  void Stop(Instruction* instr);
59  void Debug();
60  // Print all registers with a nice formatting.
61  void PrintAllRegs();
62  void PrintAllRegsIncludingFPU();
63
64 private:
65  // We set the breakpoint code to 0xFFFFF to easily recognize it.
66  static const Instr kBreakpointInstr = SPECIAL | BREAK | 0xFFFFF << 6;
67  static const Instr kNopInstr = 0x0;
68
69  Simulator* sim_;
70
71  int32_t GetRegisterValue(int regnum);
72  int32_t GetFPURegisterValue32(int regnum);
73  int64_t GetFPURegisterValue64(int regnum);
74  float GetFPURegisterValueFloat(int regnum);
75  double GetFPURegisterValueDouble(int regnum);
76  bool GetValue(const char* desc, int32_t* value);
77  bool GetValue(const char* desc, int64_t* value);
78
79  // Set or delete a breakpoint. Returns true if successful.
80  bool SetBreakpoint(Instruction* breakpc);
81  bool DeleteBreakpoint(Instruction* breakpc);
82
83  // Undo and redo all breakpoints. This is needed to bracket disassembly and
84  // execution to skip past breakpoints when run from the debugger.
85  void UndoBreakpoints();
86  void RedoBreakpoints();
87};
88
89#define UNSUPPORTED() printf("Sim: Unsupported instruction.\n");
90
91void MipsDebugger::Stop(Instruction* instr) {
92  // Get the stop code.
93  uint32_t code = instr->Bits(25, 6);
94  PrintF("Simulator hit (%u)\n", code);
95  Debug();
96}
97
98int32_t MipsDebugger::GetRegisterValue(int regnum) {
99  if (regnum == kNumSimuRegisters) {
100    return sim_->get_pc();
101  } else {
102    return sim_->get_register(regnum);
103  }
104}
105
106int32_t MipsDebugger::GetFPURegisterValue32(int regnum) {
107  if (regnum == kNumFPURegisters) {
108    return sim_->get_pc();
109  } else {
110    return sim_->get_fpu_register_word(regnum);
111  }
112}
113
114int64_t MipsDebugger::GetFPURegisterValue64(int regnum) {
115  if (regnum == kNumFPURegisters) {
116    return sim_->get_pc();
117  } else {
118    return sim_->get_fpu_register(regnum);
119  }
120}
121
122float MipsDebugger::GetFPURegisterValueFloat(int regnum) {
123  if (regnum == kNumFPURegisters) {
124    return sim_->get_pc();
125  } else {
126    return sim_->get_fpu_register_float(regnum);
127  }
128}
129
130double MipsDebugger::GetFPURegisterValueDouble(int regnum) {
131  if (regnum == kNumFPURegisters) {
132    return sim_->get_pc();
133  } else {
134    return sim_->get_fpu_register_double(regnum);
135  }
136}
137
138bool MipsDebugger::GetValue(const char* desc, int32_t* value) {
139  int regnum = Registers::Number(desc);
140  int fpuregnum = FPURegisters::Number(desc);
141
142  if (regnum != kInvalidRegister) {
143    *value = GetRegisterValue(regnum);
144    return true;
145  } else if (fpuregnum != kInvalidFPURegister) {
146    *value = GetFPURegisterValue32(fpuregnum);
147    return true;
148  } else if (strncmp(desc, "0x", 2) == 0) {
149    return SScanF(desc, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
150  } else {
151    return SScanF(desc, "%i", value) == 1;
152  }
153}
154
155bool MipsDebugger::GetValue(const char* desc, int64_t* value) {
156  int regnum = Registers::Number(desc);
157  int fpuregnum = FPURegisters::Number(desc);
158
159  if (regnum != kInvalidRegister) {
160    *value = GetRegisterValue(regnum);
161    return true;
162  } else if (fpuregnum != kInvalidFPURegister) {
163    *value = GetFPURegisterValue64(fpuregnum);
164    return true;
165  } else if (strncmp(desc, "0x", 2) == 0) {
166    return SScanF(desc + 2, "%" SCNx64, reinterpret_cast<uint64_t*>(value)) ==
167           1;
168  } else {
169    return SScanF(desc, "%" SCNu64, reinterpret_cast<uint64_t*>(value)) == 1;
170  }
171}
172
173bool MipsDebugger::SetBreakpoint(Instruction* breakpc) {
174  // Check if a breakpoint can be set. If not return without any side-effects.
175  if (sim_->break_pc_ != nullptr) {
176    return false;
177  }
178
179  // Set the breakpoint.
180  sim_->break_pc_ = breakpc;
181  sim_->break_instr_ = breakpc->InstructionBits();
182  // Not setting the breakpoint instruction in the code itself. It will be set
183  // when the debugger shell continues.
184  return true;
185}
186
187bool MipsDebugger::DeleteBreakpoint(Instruction* breakpc) {
188  if (sim_->break_pc_ != nullptr) {
189    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
190  }
191
192  sim_->break_pc_ = nullptr;
193  sim_->break_instr_ = 0;
194  return true;
195}
196
197void MipsDebugger::UndoBreakpoints() {
198  if (sim_->break_pc_ != nullptr) {
199    sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
200  }
201}
202
203void MipsDebugger::RedoBreakpoints() {
204  if (sim_->break_pc_ != nullptr) {
205    sim_->break_pc_->SetInstructionBits(kBreakpointInstr);
206  }
207}
208
209void MipsDebugger::PrintAllRegs() {
210#define REG_INFO(n) Registers::Name(n), GetRegisterValue(n), GetRegisterValue(n)
211
212  PrintF("\n");
213  // at, v0, a0.
214  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", REG_INFO(1),
215         REG_INFO(2), REG_INFO(4));
216  // v1, a1.
217  PrintF("%26s\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", "", REG_INFO(3),
218         REG_INFO(5));
219  // a2.
220  PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(6));
221  // a3.
222  PrintF("%26s\t%26s\t%3s: 0x%08x %10d\n", "", "", REG_INFO(7));
223  PrintF("\n");
224  // t0-t7, s0-s7
225  for (int i = 0; i < 8; i++) {
226    PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", REG_INFO(8 + i),
227           REG_INFO(16 + i));
228  }
229  PrintF("\n");
230  // t8, k0, LO.
231  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", REG_INFO(24),
232         REG_INFO(26), REG_INFO(32));
233  // t9, k1, HI.
234  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", REG_INFO(25),
235         REG_INFO(27), REG_INFO(33));
236  // sp, fp, gp.
237  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", REG_INFO(29),
238         REG_INFO(30), REG_INFO(28));
239  // pc.
240  PrintF("%3s: 0x%08x %10d\t%3s: 0x%08x %10d\n", REG_INFO(31), REG_INFO(34));
241
242#undef REG_INFO
243}
244
245void MipsDebugger::PrintAllRegsIncludingFPU() {
246#define FPU_REG_INFO32(n)                                     \
247  FPURegisters::Name(n), FPURegisters::Name(n + 1),           \
248      GetFPURegisterValue32(n + 1), GetFPURegisterValue32(n), \
249      GetFPURegisterValueDouble(n)
250
251#define FPU_REG_INFO64(n) \
252  FPURegisters::Name(n), GetFPURegisterValue64(n), GetFPURegisterValueDouble(n)
253
254  PrintAllRegs();
255
256  PrintF("\n\n");
257  // f0, f1, f2, ... f31.
258  // This must be a compile-time switch,
259  // compiler will throw out warnings otherwise.
260  if (kFpuMode == kFP64) {
261    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(0));
262    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(1));
263    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(2));
264    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(3));
265    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(4));
266    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(5));
267    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(6));
268    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(7));
269    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(8));
270    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(9));
271    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(10));
272    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(11));
273    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(12));
274    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(13));
275    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(14));
276    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(15));
277    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(16));
278    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(17));
279    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(18));
280    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(19));
281    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(20));
282    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(21));
283    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(22));
284    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(23));
285    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(24));
286    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(25));
287    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(26));
288    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(27));
289    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(28));
290    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(29));
291    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(30));
292    PrintF("%3s: 0x%016llx %16.4e\n", FPU_REG_INFO64(31));
293  } else {
294    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(0));
295    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(2));
296    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(4));
297    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(6));
298    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(8));
299    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(10));
300    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(12));
301    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(14));
302    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(16));
303    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(18));
304    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(20));
305    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(22));
306    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(24));
307    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(26));
308    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(28));
309    PrintF("%3s,%3s: 0x%08x%08x %16.4e\n", FPU_REG_INFO32(30));
310  }
311
312#undef FPU_REG_INFO32
313#undef FPU_REG_INFO64
314}
315
316void MipsDebugger::Debug() {
317  intptr_t last_pc = -1;
318  bool done = false;
319
320#define COMMAND_SIZE 63
321#define ARG_SIZE 255
322
323#define STR(a) #a
324#define XSTR(a) STR(a)
325
326  char cmd[COMMAND_SIZE + 1];
327  char arg1[ARG_SIZE + 1];
328  char arg2[ARG_SIZE + 1];
329  char* argv[3] = {cmd, arg1, arg2};
330
331  // Make sure to have a proper terminating character if reaching the limit.
332  cmd[COMMAND_SIZE] = 0;
333  arg1[ARG_SIZE] = 0;
334  arg2[ARG_SIZE] = 0;
335
336  // Undo all set breakpoints while running in the debugger shell. This will
337  // make them invisible to all commands.
338  UndoBreakpoints();
339
340  while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
341    if (last_pc != sim_->get_pc()) {
342      disasm::NameConverter converter;
343      disasm::Disassembler dasm(converter);
344      // Use a reasonably large buffer.
345      v8::base::EmbeddedVector<char, 256> buffer;
346      dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(sim_->get_pc()));
347      PrintF("  0x%08x  %s\n", sim_->get_pc(), buffer.begin());
348      last_pc = sim_->get_pc();
349    }
350    char* line = ReadLine("sim> ");
351    if (line == nullptr) {
352      break;
353    } else {
354      char* last_input = sim_->last_debugger_input();
355      if (strcmp(line, "\n") == 0 && last_input != nullptr) {
356        line = last_input;
357      } else {
358        // Ownership is transferred to sim_;
359        sim_->set_last_debugger_input(line);
360      }
361      // Use sscanf to parse the individual parts of the command line. At the
362      // moment no command expects more than two parameters.
363      int argc = SScanF(line,
364                        "%" XSTR(COMMAND_SIZE) "s "
365                        "%" XSTR(ARG_SIZE) "s "
366                        "%" XSTR(ARG_SIZE) "s",
367                        cmd, arg1, arg2);
368      if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
369        Instruction* instr = reinterpret_cast<Instruction*>(sim_->get_pc());
370        if (!(instr->IsTrap()) ||
371            instr->InstructionBits() == rtCallRedirInstr) {
372          sim_->InstructionDecode(
373              reinterpret_cast<Instruction*>(sim_->get_pc()));
374        } else {
375          // Allow si to jump over generated breakpoints.
376          PrintF("/!\\ Jumping over generated breakpoint.\n");
377          sim_->set_pc(sim_->get_pc() + kInstrSize);
378        }
379      } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
380        // Execute the one instruction we broke at with breakpoints disabled.
381        sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
382        // Leave the debugger shell.
383        done = true;
384      } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
385        if (argc == 2) {
386          if (strcmp(arg1, "all") == 0) {
387            PrintAllRegs();
388          } else if (strcmp(arg1, "allf") == 0) {
389            PrintAllRegsIncludingFPU();
390          } else {
391            int regnum = Registers::Number(arg1);
392            int fpuregnum = FPURegisters::Number(arg1);
393
394            if (regnum != kInvalidRegister) {
395              int32_t value;
396              value = GetRegisterValue(regnum);
397              PrintF("%s: 0x%08x %d \n", arg1, value, value);
398            } else if (fpuregnum != kInvalidFPURegister) {
399              if (IsFp64Mode()) {
400                int64_t value;
401                double dvalue;
402                value = GetFPURegisterValue64(fpuregnum);
403                dvalue = GetFPURegisterValueDouble(fpuregnum);
404                PrintF("%3s: 0x%016llx %16.4e\n", FPURegisters::Name(fpuregnum),
405                       value, dvalue);
406              } else {
407                if (fpuregnum % 2 == 1) {
408                  int32_t value;
409                  float fvalue;
410                  value = GetFPURegisterValue32(fpuregnum);
411                  fvalue = GetFPURegisterValueFloat(fpuregnum);
412                  PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
413                } else {
414                  double dfvalue;
415                  int32_t lvalue1 = GetFPURegisterValue32(fpuregnum);
416                  int32_t lvalue2 = GetFPURegisterValue32(fpuregnum + 1);
417                  dfvalue = GetFPURegisterValueDouble(fpuregnum);
418                  PrintF("%3s,%3s: 0x%08x%08x %16.4e\n",
419                         FPURegisters::Name(fpuregnum + 1),
420                         FPURegisters::Name(fpuregnum), lvalue1, lvalue2,
421                         dfvalue);
422                }
423              }
424            } else {
425              PrintF("%s unrecognized\n", arg1);
426            }
427          }
428        } else {
429          if (argc == 3) {
430            if (strcmp(arg2, "single") == 0) {
431              int32_t value;
432              float fvalue;
433              int fpuregnum = FPURegisters::Number(arg1);
434
435              if (fpuregnum != kInvalidFPURegister) {
436                value = GetFPURegisterValue32(fpuregnum);
437                fvalue = GetFPURegisterValueFloat(fpuregnum);
438                PrintF("%s: 0x%08x %11.4e\n", arg1, value, fvalue);
439              } else {
440                PrintF("%s unrecognized\n", arg1);
441              }
442            } else {
443              PrintF("print <fpu register> single\n");
444            }
445          } else {
446            PrintF("print <register> or print <fpu register> single\n");
447          }
448        }
449      } else if ((strcmp(cmd, "po") == 0) ||
450                 (strcmp(cmd, "printobject") == 0)) {
451        if (argc == 2) {
452          int32_t value;
453          StdoutStream os;
454          if (GetValue(arg1, &value)) {
455            Object obj(value);
456            os << arg1 << ": \n";
457#ifdef DEBUG
458            obj.Print(os);
459            os << "\n";
460#else
461            os << Brief(obj) << "\n";
462#endif
463          } else {
464            os << arg1 << " unrecognized\n";
465          }
466        } else {
467          PrintF("printobject <value>\n");
468        }
469      } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0 ||
470                 strcmp(cmd, "dump") == 0) {
471        int32_t* cur = nullptr;
472        int32_t* end = nullptr;
473        int next_arg = 1;
474
475        if (strcmp(cmd, "stack") == 0) {
476          cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
477        } else {  // Command "mem".
478          int32_t value;
479          if (!GetValue(arg1, &value)) {
480            PrintF("%s unrecognized\n", arg1);
481            continue;
482          }
483          cur = reinterpret_cast<int32_t*>(value);
484          next_arg++;
485        }
486
487        // TODO(palfia): optimize this.
488        if (IsFp64Mode()) {
489          int64_t words;
490          if (argc == next_arg) {
491            words = 10;
492          } else {
493            if (!GetValue(argv[next_arg], &words)) {
494              words = 10;
495            }
496          }
497          end = cur + words;
498        } else {
499          int32_t words;
500          if (argc == next_arg) {
501            words = 10;
502          } else {
503            if (!GetValue(argv[next_arg], &words)) {
504              words = 10;
505            }
506          }
507          end = cur + words;
508        }
509
510        bool skip_obj_print = (strcmp(cmd, "dump") == 0);
511        while (cur < end) {
512          PrintF("  0x%08" PRIxPTR ":  0x%08x %10d",
513                 reinterpret_cast<intptr_t>(cur), *cur, *cur);
514          Object obj(*cur);
515          Heap* current_heap = sim_->isolate_->heap();
516          if (!skip_obj_print) {
517            if (obj.IsSmi() ||
518                IsValidHeapObject(current_heap, HeapObject::cast(obj))) {
519              PrintF(" (");
520              if (obj.IsSmi()) {
521                PrintF("smi %d", Smi::ToInt(obj));
522              } else {
523                obj.ShortPrint();
524              }
525              PrintF(")");
526            }
527          }
528          PrintF("\n");
529          cur++;
530        }
531
532      } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0) ||
533                 (strcmp(cmd, "di") == 0)) {
534        disasm::NameConverter converter;
535        disasm::Disassembler dasm(converter);
536        // Use a reasonably large buffer.
537        v8::base::EmbeddedVector<char, 256> buffer;
538
539        byte* cur = nullptr;
540        byte* end = nullptr;
541
542        if (argc == 1) {
543          cur = reinterpret_cast<byte*>(sim_->get_pc());
544          end = cur + (10 * kInstrSize);
545        } else if (argc == 2) {
546          int regnum = Registers::Number(arg1);
547          if (regnum != kInvalidRegister || strncmp(arg1, "0x", 2) == 0) {
548            // The argument is an address or a register name.
549            int32_t value;
550            if (GetValue(arg1, &value)) {
551              cur = reinterpret_cast<byte*>(value);
552              // Disassemble 10 instructions at <arg1>.
553              end = cur + (10 * kInstrSize);
554            }
555          } else {
556            // The argument is the number of instructions.
557            int32_t value;
558            if (GetValue(arg1, &value)) {
559              cur = reinterpret_cast<byte*>(sim_->get_pc());
560              // Disassemble <arg1> instructions.
561              end = cur + (value * kInstrSize);
562            }
563          }
564        } else {
565          int32_t value1;
566          int32_t value2;
567          if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
568            cur = reinterpret_cast<byte*>(value1);
569            end = cur + (value2 * kInstrSize);
570          }
571        }
572
573        while (cur < end) {
574          dasm.InstructionDecode(buffer, cur);
575          PrintF("  0x%08" PRIxPTR "  %s\n", reinterpret_cast<intptr_t>(cur),
576                 buffer.begin());
577          cur += kInstrSize;
578        }
579      } else if (strcmp(cmd, "gdb") == 0) {
580        PrintF("relinquishing control to gdb\n");
581        v8::base::OS::DebugBreak();
582        PrintF("regaining control from gdb\n");
583      } else if (strcmp(cmd, "break") == 0) {
584        if (argc == 2) {
585          int32_t value;
586          if (GetValue(arg1, &value)) {
587            if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
588              PrintF("setting breakpoint failed\n");
589            }
590          } else {
591            PrintF("%s unrecognized\n", arg1);
592          }
593        } else {
594          PrintF("break <address>\n");
595        }
596      } else if (strcmp(cmd, "del") == 0) {
597        if (!DeleteBreakpoint(nullptr)) {
598          PrintF("deleting breakpoint failed\n");
599        }
600      } else if (strcmp(cmd, "flags") == 0) {
601        PrintF("No flags on MIPS !\n");
602      } else if (strcmp(cmd, "stop") == 0) {
603        int32_t value;
604        intptr_t stop_pc = sim_->get_pc() - 2 * kInstrSize;
605        Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
606        Instruction* msg_address =
607            reinterpret_cast<Instruction*>(stop_pc + kInstrSize);
608        if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
609          // Remove the current stop.
610          if (sim_->IsStopInstruction(stop_instr)) {
611            stop_instr->SetInstructionBits(kNopInstr);
612            msg_address->SetInstructionBits(kNopInstr);
613          } else {
614            PrintF("Not at debugger stop.\n");
615          }
616        } else if (argc == 3) {
617          // Print information about all/the specified breakpoint(s).
618          if (strcmp(arg1, "info") == 0) {
619            if (strcmp(arg2, "all") == 0) {
620              PrintF("Stop information:\n");
621              for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
622                   i++) {
623                sim_->PrintStopInfo(i);
624              }
625            } else if (GetValue(arg2, &value)) {
626              sim_->PrintStopInfo(value);
627            } else {
628              PrintF("Unrecognized argument.\n");
629            }
630          } else if (strcmp(arg1, "enable") == 0) {
631            // Enable all/the specified breakpoint(s).
632            if (strcmp(arg2, "all") == 0) {
633              for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
634                   i++) {
635                sim_->EnableStop(i);
636              }
637            } else if (GetValue(arg2, &value)) {
638              sim_->EnableStop(value);
639            } else {
640              PrintF("Unrecognized argument.\n");
641            }
642          } else if (strcmp(arg1, "disable") == 0) {
643            // Disable all/the specified breakpoint(s).
644            if (strcmp(arg2, "all") == 0) {
645              for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
646                   i++) {
647                sim_->DisableStop(i);
648              }
649            } else if (GetValue(arg2, &value)) {
650              sim_->DisableStop(value);
651            } else {
652              PrintF("Unrecognized argument.\n");
653            }
654          }
655        } else {
656          PrintF("Wrong usage. Use help command for more information.\n");
657        }
658      } else if ((strcmp(cmd, "stat") == 0) || (strcmp(cmd, "st") == 0)) {
659        // Print registers and disassemble.
660        PrintAllRegs();
661        PrintF("\n");
662
663        disasm::NameConverter converter;
664        disasm::Disassembler dasm(converter);
665        // Use a reasonably large buffer.
666        v8::base::EmbeddedVector<char, 256> buffer;
667
668        byte* cur = nullptr;
669        byte* end = nullptr;
670
671        if (argc == 1) {
672          cur = reinterpret_cast<byte*>(sim_->get_pc());
673          end = cur + (10 * kInstrSize);
674        } else if (argc == 2) {
675          int32_t value;
676          if (GetValue(arg1, &value)) {
677            cur = reinterpret_cast<byte*>(value);
678            // no length parameter passed, assume 10 instructions
679            end = cur + (10 * kInstrSize);
680          }
681        } else {
682          int32_t value1;
683          int32_t value2;
684          if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
685            cur = reinterpret_cast<byte*>(value1);
686            end = cur + (value2 * kInstrSize);
687          }
688        }
689
690        while (cur < end) {
691          dasm.InstructionDecode(buffer, cur);
692          PrintF("  0x%08" PRIxPTR "  %s\n", reinterpret_cast<intptr_t>(cur),
693                 buffer.begin());
694          cur += kInstrSize;
695        }
696      } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
697        PrintF("cont\n");
698        PrintF("  continue execution (alias 'c')\n");
699        PrintF("stepi\n");
700        PrintF("  step one instruction (alias 'si')\n");
701        PrintF("print <register>\n");
702        PrintF("  print register content (alias 'p')\n");
703        PrintF("  use register name 'all' to print all registers\n");
704        PrintF("printobject <register>\n");
705        PrintF("  print an object from a register (alias 'po')\n");
706        PrintF("stack [<words>]\n");
707        PrintF("  dump stack content, default dump 10 words)\n");
708        PrintF("mem <address> [<words>]\n");
709        PrintF("  dump memory content, default dump 10 words)\n");
710        PrintF("dump [<words>]\n");
711        PrintF(
712            "  dump memory content without pretty printing JS objects, default "
713            "dump 10 words)\n");
714        PrintF("flags\n");
715        PrintF("  print flags\n");
716        PrintF("disasm [<instructions>]\n");
717        PrintF("disasm [<address/register>]\n");
718        PrintF("disasm [[<address/register>] <instructions>]\n");
719        PrintF("  disassemble code, default is 10 instructions\n");
720        PrintF("  from pc (alias 'di')\n");
721        PrintF("gdb\n");
722        PrintF("  enter gdb\n");
723        PrintF("break <address>\n");
724        PrintF("  set a break point on the address\n");
725        PrintF("del\n");
726        PrintF("  delete the breakpoint\n");
727        PrintF("stop feature:\n");
728        PrintF("  Description:\n");
729        PrintF("    Stops are debug instructions inserted by\n");
730        PrintF("    the Assembler::stop() function.\n");
731        PrintF("    When hitting a stop, the Simulator will\n");
732        PrintF("    stop and give control to the Debugger.\n");
733        PrintF("    All stop codes are watched:\n");
734        PrintF("    - They can be enabled / disabled: the Simulator\n");
735        PrintF("       will / won't stop when hitting them.\n");
736        PrintF("    - The Simulator keeps track of how many times they \n");
737        PrintF("      are met. (See the info command.) Going over a\n");
738        PrintF("      disabled stop still increases its counter. \n");
739        PrintF("  Commands:\n");
740        PrintF("    stop info all/<code> : print infos about number <code>\n");
741        PrintF("      or all stop(s).\n");
742        PrintF("    stop enable/disable all/<code> : enables / disables\n");
743        PrintF("      all or number <code> stop(s)\n");
744        PrintF("    stop unstop\n");
745        PrintF("      ignore the stop instruction at the current location\n");
746        PrintF("      from now on\n");
747      } else {
748        PrintF("Unknown command: %s\n", cmd);
749      }
750    }
751  }
752
753  // Add all the breakpoints back to stop execution and enter the debugger
754  // shell when hit.
755  RedoBreakpoints();
756
757#undef COMMAND_SIZE
758#undef ARG_SIZE
759
760#undef STR
761#undef XSTR
762}
763
764bool Simulator::ICacheMatch(void* one, void* two) {
765  DCHECK_EQ(reinterpret_cast<intptr_t>(one) & CachePage::kPageMask, 0);
766  DCHECK_EQ(reinterpret_cast<intptr_t>(two) & CachePage::kPageMask, 0);
767  return one == two;
768}
769
770static uint32_t ICacheHash(void* key) {
771  return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
772}
773
774static bool AllOnOnePage(uintptr_t start, int size) {
775  intptr_t start_page = (start & ~CachePage::kPageMask);
776  intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
777  return start_page == end_page;
778}
779
780void Simulator::set_last_debugger_input(char* input) {
781  DeleteArray(last_debugger_input_);
782  last_debugger_input_ = input;
783}
784
785void Simulator::SetRedirectInstruction(Instruction* instruction) {
786  instruction->SetInstructionBits(rtCallRedirInstr);
787}
788
789void Simulator::FlushICache(base::CustomMatcherHashMap* i_cache,
790                            void* start_addr, size_t size) {
791  intptr_t start = reinterpret_cast<intptr_t>(start_addr);
792  int intra_line = (start & CachePage::kLineMask);
793  start -= intra_line;
794  size += intra_line;
795  size = ((size - 1) | CachePage::kLineMask) + 1;
796  int offset = (start & CachePage::kPageMask);
797  while (!AllOnOnePage(start, size - 1)) {
798    int bytes_to_flush = CachePage::kPageSize - offset;
799    FlushOnePage(i_cache, start, bytes_to_flush);
800    start += bytes_to_flush;
801    size -= bytes_to_flush;
802    DCHECK_EQ(0, start & CachePage::kPageMask);
803    offset = 0;
804  }
805  if (size != 0) {
806    FlushOnePage(i_cache, start, size);
807  }
808}
809
810CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache,
811                                   void* page) {
812  base::CustomMatcherHashMap::Entry* entry =
813      i_cache->LookupOrInsert(page, ICacheHash(page));
814  if (entry->value == nullptr) {
815    CachePage* new_page = new CachePage();
816    entry->value = new_page;
817  }
818  return reinterpret_cast<CachePage*>(entry->value);
819}
820
821// Flush from start up to and not including start + size.
822void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache,
823                             intptr_t start, int size) {
824  DCHECK_LE(size, CachePage::kPageSize);
825  DCHECK(AllOnOnePage(start, size - 1));
826  DCHECK_EQ(start & CachePage::kLineMask, 0);
827  DCHECK_EQ(size & CachePage::kLineMask, 0);
828  void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
829  int offset = (start & CachePage::kPageMask);
830  CachePage* cache_page = GetCachePage(i_cache, page);
831  char* valid_bytemap = cache_page->ValidityByte(offset);
832  memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
833}
834
835void Simulator::CheckICache(base::CustomMatcherHashMap* i_cache,
836                            Instruction* instr) {
837  intptr_t address = reinterpret_cast<intptr_t>(instr);
838  void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
839  void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
840  int offset = (address & CachePage::kPageMask);
841  CachePage* cache_page = GetCachePage(i_cache, page);
842  char* cache_valid_byte = cache_page->ValidityByte(offset);
843  bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
844  char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
845  if (cache_hit) {
846    // Check that the data in memory matches the contents of the I-cache.
847    CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
848                       cache_page->CachedData(offset), kInstrSize));
849  } else {
850    // Cache miss.  Load memory into the cache.
851    memcpy(cached_line, line, CachePage::kLineLength);
852    *cache_valid_byte = CachePage::LINE_VALID;
853  }
854}
855
856Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
857  // Set up simulator support first. Some of this information is needed to
858  // setup the architecture state.
859  stack_size_ = FLAG_sim_stack_size * KB;
860  stack_ = reinterpret_cast<char*>(base::Malloc(stack_size_));
861  pc_modified_ = false;
862  icount_ = 0;
863  break_count_ = 0;
864  break_pc_ = nullptr;
865  break_instr_ = 0;
866
867  // Set up architecture state.
868  // All registers are initialized to zero to start with.
869  for (int i = 0; i < kNumSimuRegisters; i++) {
870    registers_[i] = 0;
871  }
872  for (int i = 0; i < kNumFPURegisters; i++) {
873    FPUregisters_[2 * i] = 0;
874    FPUregisters_[2 * i + 1] = 0;  // upper part for MSA ASE
875  }
876  if (IsMipsArchVariant(kMips32r6)) {
877    FCSR_ = kFCSRNaN2008FlagMask;
878    MSACSR_ = 0;
879  } else {
880    DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
881    FCSR_ = 0;
882  }
883
884  // The sp is initialized to point to the bottom (high address) of the
885  // allocated stack area. To be safe in potential stack underflows we leave
886  // some buffer below.
887  registers_[sp] = reinterpret_cast<int32_t>(stack_) + stack_size_ - 64;
888  // The ra and pc are initialized to a known bad value that will cause an
889  // access violation if the simulator ever tries to execute it.
890  registers_[pc] = bad_ra;
891  registers_[ra] = bad_ra;
892  last_debugger_input_ = nullptr;
893}
894
895Simulator::~Simulator() {
896  GlobalMonitor::Get()->RemoveLinkedAddress(&global_monitor_thread_);
897  base::Free(stack_);
898}
899
900// Get the active Simulator for the current thread.
901Simulator* Simulator::current(Isolate* isolate) {
902  v8::internal::Isolate::PerIsolateThreadData* isolate_data =
903      isolate->FindOrAllocatePerThreadDataForThisThread();
904  DCHECK_NOT_NULL(isolate_data);
905
906  Simulator* sim = isolate_data->simulator();
907  if (sim == nullptr) {
908    // TODO(146): delete the simulator object when a thread/isolate goes away.
909    sim = new Simulator(isolate);
910    isolate_data->set_simulator(sim);
911  }
912  return sim;
913}
914
915// Sets the register in the architecture state. It will also deal with updating
916// Simulator internal state for special registers such as PC.
917void Simulator::set_register(int reg, int32_t value) {
918  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
919  if (reg == pc) {
920    pc_modified_ = true;
921  }
922
923  // Zero register always holds 0.
924  registers_[reg] = (reg == 0) ? 0 : value;
925}
926
927void Simulator::set_dw_register(int reg, const int* dbl) {
928  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
929  registers_[reg] = dbl[0];
930  registers_[reg + 1] = dbl[1];
931}
932
933void Simulator::set_fpu_register(int fpureg, int64_t value) {
934  DCHECK(IsFp64Mode());
935  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
936  FPUregisters_[fpureg * 2] = value;
937}
938
939void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
940  // Set ONLY lower 32-bits, leaving upper bits untouched.
941  // TODO(plind): big endian issue.
942  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
943  int32_t* pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2]);
944  *pword = value;
945}
946
947void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
948  // Set ONLY upper 32-bits, leaving lower bits untouched.
949  // TODO(plind): big endian issue.
950  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
951  int32_t* phiword =
952      (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2])) + 1;
953  *phiword = value;
954}
955
956void Simulator::set_fpu_register_float(int fpureg, float value) {
957  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
958  *bit_cast<float*>(&FPUregisters_[fpureg * 2]) = value;
959}
960
961void Simulator::set_fpu_register_double(int fpureg, double value) {
962  if (IsFp64Mode()) {
963    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
964    *bit_cast<double*>(&FPUregisters_[fpureg * 2]) = value;
965  } else {
966    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
967    int64_t i64 = bit_cast<int64_t>(value);
968    set_fpu_register_word(fpureg, i64 & 0xFFFFFFFF);
969    set_fpu_register_word(fpureg + 1, i64 >> 32);
970  }
971}
972
973// Get the register from the architecture state. This function does handle
974// the special case of accessing the PC register.
975int32_t Simulator::get_register(int reg) const {
976  DCHECK((reg >= 0) && (reg < kNumSimuRegisters));
977  if (reg == 0)
978    return 0;
979  else
980    return registers_[reg] + ((reg == pc) ? Instruction::kPCReadOffset : 0);
981}
982
983double Simulator::get_double_from_register_pair(int reg) {
984  // TODO(plind): bad ABI stuff, refactor or remove.
985  DCHECK((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
986
987  double dm_val = 0.0;
988  // Read the bits from the unsigned integer register_[] array
989  // into the double precision floating point value and return it.
990  char buffer[2 * sizeof(registers_[0])];
991  memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
992  memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
993  return (dm_val);
994}
995
996int64_t Simulator::get_fpu_register(int fpureg) const {
997  if (IsFp64Mode()) {
998    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
999    return FPUregisters_[fpureg * 2];
1000  } else {
1001    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1002    uint64_t i64;
1003    i64 = static_cast<uint32_t>(get_fpu_register_word(fpureg));
1004    i64 |= static_cast<uint64_t>(get_fpu_register_word(fpureg + 1)) << 32;
1005    return static_cast<int64_t>(i64);
1006  }
1007}
1008
1009int32_t Simulator::get_fpu_register_word(int fpureg) const {
1010  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1011  return static_cast<int32_t>(FPUregisters_[fpureg * 2] & 0xFFFFFFFF);
1012}
1013
1014int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
1015  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1016  return static_cast<int32_t>(FPUregisters_[fpureg * 2] & 0xFFFFFFFF);
1017}
1018
1019int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
1020  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1021  return static_cast<int32_t>((FPUregisters_[fpureg * 2] >> 32) & 0xFFFFFFFF);
1022}
1023
1024float Simulator::get_fpu_register_float(int fpureg) const {
1025  DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1026  return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg * 2]));
1027}
1028
1029double Simulator::get_fpu_register_double(int fpureg) const {
1030  if (IsFp64Mode()) {
1031    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
1032    return *bit_cast<double*>(&FPUregisters_[fpureg * 2]);
1033  } else {
1034    DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
1035    int64_t i64;
1036    i64 = static_cast<uint32_t>(get_fpu_register_word(fpureg));
1037    i64 |= static_cast<uint64_t>(get_fpu_register_word(fpureg + 1)) << 32;
1038    return bit_cast<double>(i64);
1039  }
1040}
1041
1042template <typename T>
1043void Simulator::get_msa_register(int wreg, T* value) {
1044  DCHECK((wreg >= 0) && (wreg < kNumMSARegisters));
1045  memcpy(value, FPUregisters_ + wreg * 2, kSimd128Size);
1046}
1047
1048template <typename T>
1049void Simulator::set_msa_register(int wreg, const T* value) {
1050  DCHECK((wreg >= 0) && (wreg < kNumMSARegisters));
1051  memcpy(FPUregisters_ + wreg * 2, value, kSimd128Size);
1052}
1053
1054// Runtime FP routines take up to two double arguments and zero
1055// or one integer arguments. All are constructed here,
1056// from a0-a3 or f12 and f14.
1057void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
1058  if (!IsMipsSoftFloatABI) {
1059    *x = get_fpu_register_double(12);
1060    *y = get_fpu_register_double(14);
1061    *z = get_register(a2);
1062  } else {
1063    // TODO(plind): bad ABI stuff, refactor or remove.
1064    // We use a char buffer to get around the strict-aliasing rules which
1065    // otherwise allow the compiler to optimize away the copy.
1066    char buffer[sizeof(*x)];
1067    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1068
1069    // Registers a0 and a1 -> x.
1070    reg_buffer[0] = get_register(a0);
1071    reg_buffer[1] = get_register(a1);
1072    memcpy(x, buffer, sizeof(buffer));
1073    // Registers a2 and a3 -> y.
1074    reg_buffer[0] = get_register(a2);
1075    reg_buffer[1] = get_register(a3);
1076    memcpy(y, buffer, sizeof(buffer));
1077    // Register 2 -> z.
1078    reg_buffer[0] = get_register(a2);
1079    memcpy(z, buffer, sizeof(*z));
1080  }
1081}
1082
1083// The return value is either in v0/v1 or f0.
1084void Simulator::SetFpResult(const double& result) {
1085  if (!IsMipsSoftFloatABI) {
1086    set_fpu_register_double(0, result);
1087  } else {
1088    char buffer[2 * sizeof(registers_[0])];
1089    int32_t* reg_buffer = reinterpret_cast<int32_t*>(buffer);
1090    memcpy(buffer, &result, sizeof(buffer));
1091    // Copy result to v0 and v1.
1092    set_register(v0, reg_buffer[0]);
1093    set_register(v1, reg_buffer[1]);
1094  }
1095}
1096
1097// Helper functions for setting and testing the FCSR register's bits.
1098void Simulator::set_fcsr_bit(uint32_t cc, bool value) {
1099  if (value) {
1100    FCSR_ |= (1 << cc);
1101  } else {
1102    FCSR_ &= ~(1 << cc);
1103  }
1104}
1105
1106bool Simulator::test_fcsr_bit(uint32_t cc) { return FCSR_ & (1 << cc); }
1107
1108void Simulator::clear_fcsr_cause() {
1109  FCSR_ &= ~kFCSRCauseMask;
1110}
1111
1112void Simulator::set_fcsr_rounding_mode(FPURoundingMode mode) {
1113  FCSR_ |= mode & kFPURoundingModeMask;
1114}
1115
1116void Simulator::set_msacsr_rounding_mode(FPURoundingMode mode) {
1117  MSACSR_ |= mode & kFPURoundingModeMask;
1118}
1119
1120unsigned int Simulator::get_fcsr_rounding_mode() {
1121  return FCSR_ & kFPURoundingModeMask;
1122}
1123
1124unsigned int Simulator::get_msacsr_rounding_mode() {
1125  return MSACSR_ & kFPURoundingModeMask;
1126}
1127
1128void Simulator::set_fpu_register_word_invalid_result(float original,
1129                                                     float rounded) {
1130  if (FCSR_ & kFCSRNaN2008FlagMask) {
1131    double max_int32 = std::numeric_limits<int32_t>::max();
1132    double min_int32 = std::numeric_limits<int32_t>::min();
1133    if (std::isnan(original)) {
1134      set_fpu_register_word(fd_reg(), 0);
1135    } else if (rounded > max_int32) {
1136      set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1137    } else if (rounded < min_int32) {
1138      set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1139    } else {
1140      UNREACHABLE();
1141    }
1142  } else {
1143    set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1144  }
1145}
1146
1147void Simulator::set_fpu_register_invalid_result(float original, float rounded) {
1148  if (FCSR_ & kFCSRNaN2008FlagMask) {
1149    double max_int32 = std::numeric_limits<int32_t>::max();
1150    double min_int32 = std::numeric_limits<int32_t>::min();
1151    if (std::isnan(original)) {
1152      set_fpu_register(fd_reg(), 0);
1153    } else if (rounded > max_int32) {
1154      set_fpu_register(fd_reg(), kFPUInvalidResult);
1155    } else if (rounded < min_int32) {
1156      set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1157    } else {
1158      UNREACHABLE();
1159    }
1160  } else {
1161    set_fpu_register(fd_reg(), kFPUInvalidResult);
1162  }
1163}
1164
1165void Simulator::set_fpu_register_invalid_result64(float original,
1166                                                  float rounded) {
1167  if (FCSR_ & kFCSRNaN2008FlagMask) {
1168    // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1169    // loading the most accurate representation into max_int64, which is 2^63.
1170    double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1171    double min_int64 = std::numeric_limits<int64_t>::min();
1172    if (std::isnan(original)) {
1173      set_fpu_register(fd_reg(), 0);
1174    } else if (rounded >= max_int64) {
1175      set_fpu_register(fd_reg(), kFPU64InvalidResult);
1176    } else if (rounded < min_int64) {
1177      set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1178    } else {
1179      UNREACHABLE();
1180    }
1181  } else {
1182    set_fpu_register(fd_reg(), kFPU64InvalidResult);
1183  }
1184}
1185
1186void Simulator::set_fpu_register_word_invalid_result(double original,
1187                                                     double rounded) {
1188  if (FCSR_ & kFCSRNaN2008FlagMask) {
1189    double max_int32 = std::numeric_limits<int32_t>::max();
1190    double min_int32 = std::numeric_limits<int32_t>::min();
1191    if (std::isnan(original)) {
1192      set_fpu_register_word(fd_reg(), 0);
1193    } else if (rounded > max_int32) {
1194      set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1195    } else if (rounded < min_int32) {
1196      set_fpu_register_word(fd_reg(), kFPUInvalidResultNegative);
1197    } else {
1198      UNREACHABLE();
1199    }
1200  } else {
1201    set_fpu_register_word(fd_reg(), kFPUInvalidResult);
1202  }
1203}
1204
1205void Simulator::set_fpu_register_invalid_result(double original,
1206                                                double rounded) {
1207  if (FCSR_ & kFCSRNaN2008FlagMask) {
1208    double max_int32 = std::numeric_limits<int32_t>::max();
1209    double min_int32 = std::numeric_limits<int32_t>::min();
1210    if (std::isnan(original)) {
1211      set_fpu_register(fd_reg(), 0);
1212    } else if (rounded > max_int32) {
1213      set_fpu_register(fd_reg(), kFPUInvalidResult);
1214    } else if (rounded < min_int32) {
1215      set_fpu_register(fd_reg(), kFPUInvalidResultNegative);
1216    } else {
1217      UNREACHABLE();
1218    }
1219  } else {
1220    set_fpu_register(fd_reg(), kFPUInvalidResult);
1221  }
1222}
1223
1224void Simulator::set_fpu_register_invalid_result64(double original,
1225                                                  double rounded) {
1226  if (FCSR_ & kFCSRNaN2008FlagMask) {
1227    // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1228    // loading the most accurate representation into max_int64, which is 2^63.
1229    double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1230    double min_int64 = std::numeric_limits<int64_t>::min();
1231    if (std::isnan(original)) {
1232      set_fpu_register(fd_reg(), 0);
1233    } else if (rounded >= max_int64) {
1234      set_fpu_register(fd_reg(), kFPU64InvalidResult);
1235    } else if (rounded < min_int64) {
1236      set_fpu_register(fd_reg(), kFPU64InvalidResultNegative);
1237    } else {
1238      UNREACHABLE();
1239    }
1240  } else {
1241    set_fpu_register(fd_reg(), kFPU64InvalidResult);
1242  }
1243}
1244
1245// Sets the rounding error codes in FCSR based on the result of the rounding.
1246// Returns true if the operation was invalid.
1247bool Simulator::set_fcsr_round_error(double original, double rounded) {
1248  bool ret = false;
1249  double max_int32 = std::numeric_limits<int32_t>::max();
1250  double min_int32 = std::numeric_limits<int32_t>::min();
1251
1252  clear_fcsr_cause();
1253
1254  if (!std::isfinite(original) || !std::isfinite(rounded)) {
1255    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1256    set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1257    ret = true;
1258  }
1259
1260  if (original != rounded) {
1261    set_fcsr_bit(kFCSRInexactFlagBit, true);
1262    set_fcsr_bit(kFCSRInexactCauseBit, true);
1263  }
1264
1265  if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1266    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1267    set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1268    ret = true;
1269  }
1270
1271  if (rounded > max_int32 || rounded < min_int32) {
1272    set_fcsr_bit(kFCSROverflowFlagBit, true);
1273    set_fcsr_bit(kFCSROverflowCauseBit, true);
1274    // The reference is not really clear but it seems this is required:
1275    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1276    set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1277    ret = true;
1278  }
1279
1280  return ret;
1281}
1282
1283// Sets the rounding error codes in FCSR based on the result of the rounding.
1284// Returns true if the operation was invalid.
1285bool Simulator::set_fcsr_round64_error(double original, double rounded) {
1286  bool ret = false;
1287  // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1288  // loading the most accurate representation into max_int64, which is 2^63.
1289  double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1290  double min_int64 = std::numeric_limits<int64_t>::min();
1291
1292  clear_fcsr_cause();
1293
1294  if (!std::isfinite(original) || !std::isfinite(rounded)) {
1295    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1296    set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1297    ret = true;
1298  }
1299
1300  if (original != rounded) {
1301    set_fcsr_bit(kFCSRInexactFlagBit, true);
1302    set_fcsr_bit(kFCSRInexactCauseBit, true);
1303  }
1304
1305  if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1306    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1307    set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1308    ret = true;
1309  }
1310
1311  if (rounded >= max_int64 || rounded < min_int64) {
1312    set_fcsr_bit(kFCSROverflowFlagBit, true);
1313    set_fcsr_bit(kFCSROverflowCauseBit, true);
1314    // The reference is not really clear but it seems this is required:
1315    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1316    set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1317    ret = true;
1318  }
1319
1320  return ret;
1321}
1322
1323// Sets the rounding error codes in FCSR based on the result of the rounding.
1324// Returns true if the operation was invalid.
1325bool Simulator::set_fcsr_round_error(float original, float rounded) {
1326  bool ret = false;
1327  double max_int32 = std::numeric_limits<int32_t>::max();
1328  double min_int32 = std::numeric_limits<int32_t>::min();
1329
1330  clear_fcsr_cause();
1331
1332  if (!std::isfinite(original) || !std::isfinite(rounded)) {
1333    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1334    set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1335    ret = true;
1336  }
1337
1338  if (original != rounded) {
1339    set_fcsr_bit(kFCSRInexactFlagBit, true);
1340    set_fcsr_bit(kFCSRInexactCauseBit, true);
1341  }
1342
1343  if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1344    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1345    set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1346    ret = true;
1347  }
1348
1349  if (rounded > max_int32 || rounded < min_int32) {
1350    set_fcsr_bit(kFCSROverflowFlagBit, true);
1351    set_fcsr_bit(kFCSROverflowCauseBit, true);
1352    // The reference is not really clear but it seems this is required:
1353    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1354    set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1355    ret = true;
1356  }
1357
1358  return ret;
1359}
1360
1361// Sets the rounding error codes in FCSR based on the result of the rounding.
1362// Returns true if the operation was invalid.
1363bool Simulator::set_fcsr_round64_error(float original, float rounded) {
1364  bool ret = false;
1365  // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1366  // loading the most accurate representation into max_int64, which is 2^63.
1367  double max_int64 = static_cast<double>(std::numeric_limits<int64_t>::max());
1368  double min_int64 = std::numeric_limits<int64_t>::min();
1369
1370  clear_fcsr_cause();
1371
1372  if (!std::isfinite(original) || !std::isfinite(rounded)) {
1373    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1374    set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1375    ret = true;
1376  }
1377
1378  if (original != rounded) {
1379    set_fcsr_bit(kFCSRInexactFlagBit, true);
1380    set_fcsr_bit(kFCSRInexactCauseBit, true);
1381  }
1382
1383  if (rounded < FLT_MIN && rounded > -FLT_MIN && rounded != 0) {
1384    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
1385    set_fcsr_bit(kFCSRUnderflowCauseBit, true);
1386    ret = true;
1387  }
1388
1389  if (rounded >= max_int64 || rounded < min_int64) {
1390    set_fcsr_bit(kFCSROverflowFlagBit, true);
1391    set_fcsr_bit(kFCSROverflowCauseBit, true);
1392    // The reference is not really clear but it seems this is required:
1393    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
1394    set_fcsr_bit(kFCSRInvalidOpCauseBit, true);
1395    ret = true;
1396  }
1397
1398  return ret;
1399}
1400
1401void Simulator::round_according_to_fcsr(double toRound, double* rounded,
1402                                        int32_t* rounded_int, double fs) {
1403  // 0 RN (round to nearest): Round a result to the nearest
1404  // representable value; if the result is exactly halfway between
1405  // two representable values, round to zero. Behave like round_w_d.
1406
1407  // 1 RZ (round toward zero): Round a result to the closest
1408  // representable value whose absolute value is less than or
1409  // equal to the infinitely accurate result. Behave like trunc_w_d.
1410
1411  // 2 RP (round up, or toward  infinity): Round a result to the
1412  // next representable value up. Behave like ceil_w_d.
1413
1414  // 3 RD (round down, or toward −infinity): Round a result to
1415  // the next representable value down. Behave like floor_w_d.
1416  switch (get_fcsr_rounding_mode()) {
1417    case kRoundToNearest:
1418      *rounded = std::floor(fs + 0.5);
1419      *rounded_int = static_cast<int32_t>(*rounded);
1420      if ((*rounded_int & 1) != 0 && *rounded_int - fs == 0.5) {
1421        // If the number is halfway between two integers,
1422        // round to the even one.
1423        *rounded_int -= 1;
1424        *rounded -= 1.;
1425      }
1426      break;
1427    case kRoundToZero:
1428      *rounded = trunc(fs);
1429      *rounded_int = static_cast<int32_t>(*rounded);
1430      break;
1431    case kRoundToPlusInf:
1432      *rounded = std::ceil(fs);
1433      *rounded_int = static_cast<int32_t>(*rounded);
1434      break;
1435    case kRoundToMinusInf:
1436      *rounded = std::floor(fs);
1437      *rounded_int = static_cast<int32_t>(*rounded);
1438      break;
1439  }
1440}
1441
1442void Simulator::round_according_to_fcsr(float toRound, float* rounded,
1443                                        int32_t* rounded_int, float fs) {
1444  // 0 RN (round to nearest): Round a result to the nearest
1445  // representable value; if the result is exactly halfway between
1446  // two representable values, round to zero. Behave like round_w_d.
1447
1448  // 1 RZ (round toward zero): Round a result to the closest
1449  // representable value whose absolute value is less than or
1450  // equal to the infinitely accurate result. Behave like trunc_w_d.
1451
1452  // 2 RP (round up, or toward  infinity): Round a result to the
1453  // next representable value up. Behave like ceil_w_d.
1454
1455  // 3 RD (round down, or toward −infinity): Round a result to
1456  // the next representable value down. Behave like floor_w_d.
1457  switch (get_fcsr_rounding_mode()) {
1458    case kRoundToNearest:
1459      *rounded = std::floor(fs + 0.5);
1460      *rounded_int = static_cast<int32_t>(*rounded);
1461      if ((*rounded_int & 1) != 0 && *rounded_int - fs == 0.5) {
1462        // If the number is halfway between two integers,
1463        // round to the even one.
1464        *rounded_int -= 1;
1465        *rounded -= 1.f;
1466      }
1467      break;
1468    case kRoundToZero:
1469      *rounded = trunc(fs);
1470      *rounded_int = static_cast<int32_t>(*rounded);
1471      break;
1472    case kRoundToPlusInf:
1473      *rounded = std::ceil(fs);
1474      *rounded_int = static_cast<int32_t>(*rounded);
1475      break;
1476    case kRoundToMinusInf:
1477      *rounded = std::floor(fs);
1478      *rounded_int = static_cast<int32_t>(*rounded);
1479      break;
1480  }
1481}
1482
1483template <typename T_fp, typename T_int>
1484void Simulator::round_according_to_msacsr(T_fp toRound, T_fp* rounded,
1485                                          T_int* rounded_int) {
1486  // 0 RN (round to nearest): Round a result to the nearest
1487  // representable value; if the result is exactly halfway between
1488  // two representable values, round to zero. Behave like round_w_d.
1489
1490  // 1 RZ (round toward zero): Round a result to the closest
1491  // representable value whose absolute value is less than or
1492  // equal to the infinitely accurate result. Behave like trunc_w_d.
1493
1494  // 2 RP (round up, or toward  infinity): Round a result to the
1495  // next representable value up. Behave like ceil_w_d.
1496
1497  // 3 RD (round down, or toward −infinity): Round a result to
1498  // the next representable value down. Behave like floor_w_d.
1499  switch (get_msacsr_rounding_mode()) {
1500    case kRoundToNearest:
1501      *rounded = std::floor(toRound + 0.5);
1502      *rounded_int = static_cast<T_int>(*rounded);
1503      if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
1504        // If the number is halfway between two integers,
1505        // round to the even one.
1506        *rounded_int -= 1;
1507        *rounded -= 1;
1508      }
1509      break;
1510    case kRoundToZero:
1511      *rounded = trunc(toRound);
1512      *rounded_int = static_cast<T_int>(*rounded);
1513      break;
1514    case kRoundToPlusInf:
1515      *rounded = std::ceil(toRound);
1516      *rounded_int = static_cast<T_int>(*rounded);
1517      break;
1518    case kRoundToMinusInf:
1519      *rounded = std::floor(toRound);
1520      *rounded_int = static_cast<T_int>(*rounded);
1521      break;
1522  }
1523}
1524
1525void Simulator::round64_according_to_fcsr(double toRound, double* rounded,
1526                                          int64_t* rounded_int, double fs) {
1527  // 0 RN (round to nearest): Round a result to the nearest
1528  // representable value; if the result is exactly halfway between
1529  // two representable values, round to zero. Behave like round_w_d.
1530
1531  // 1 RZ (round toward zero): Round a result to the closest
1532  // representable value whose absolute value is less than or.
1533  // equal to the infinitely accurate result. Behave like trunc_w_d.
1534
1535  // 2 RP (round up, or toward +infinity): Round a result to the
1536  // next representable value up. Behave like ceil_w_d.
1537
1538  // 3 RN (round down, or toward −infinity): Round a result to
1539  // the next representable value down. Behave like floor_w_d.
1540  switch (FCSR_ & 3) {
1541    case kRoundToNearest:
1542      *rounded = std::floor(fs + 0.5);
1543      *rounded_int = static_cast<int64_t>(*rounded);
1544      if ((*rounded_int & 1) != 0 && *rounded_int - fs == 0.5) {
1545        // If the number is halfway between two integers,
1546        // round to the even one.
1547        *rounded_int -= 1;
1548        *rounded -= 1.;
1549      }
1550      break;
1551    case kRoundToZero:
1552      *rounded = trunc(fs);
1553      *rounded_int = static_cast<int64_t>(*rounded);
1554      break;
1555    case kRoundToPlusInf:
1556      *rounded = std::ceil(fs);
1557      *rounded_int = static_cast<int64_t>(*rounded);
1558      break;
1559    case kRoundToMinusInf:
1560      *rounded = std::floor(fs);
1561      *rounded_int = static_cast<int64_t>(*rounded);
1562      break;
1563  }
1564}
1565
1566void Simulator::round64_according_to_fcsr(float toRound, float* rounded,
1567                                          int64_t* rounded_int, float fs) {
1568  // 0 RN (round to nearest): Round a result to the nearest
1569  // representable value; if the result is exactly halfway between
1570  // two representable values, round to zero. Behave like round_w_d.
1571
1572  // 1 RZ (round toward zero): Round a result to the closest
1573  // representable value whose absolute value is less than or.
1574  // equal to the infinitely accurate result. Behave like trunc_w_d.
1575
1576  // 2 RP (round up, or toward +infinity): Round a result to the
1577  // next representable value up. Behave like ceil_w_d.
1578
1579  // 3 RN (round down, or toward −infinity): Round a result to
1580  // the next representable value down. Behave like floor_w_d.
1581  switch (FCSR_ & 3) {
1582    case kRoundToNearest:
1583      *rounded = std::floor(fs + 0.5);
1584      *rounded_int = static_cast<int64_t>(*rounded);
1585      if ((*rounded_int & 1) != 0 && *rounded_int - fs == 0.5) {
1586        // If the number is halfway between two integers,
1587        // round to the even one.
1588        *rounded_int -= 1;
1589        *rounded -= 1.f;
1590      }
1591      break;
1592    case kRoundToZero:
1593      *rounded = trunc(fs);
1594      *rounded_int = static_cast<int64_t>(*rounded);
1595      break;
1596    case kRoundToPlusInf:
1597      *rounded = std::ceil(fs);
1598      *rounded_int = static_cast<int64_t>(*rounded);
1599      break;
1600    case kRoundToMinusInf:
1601      *rounded = std::floor(fs);
1602      *rounded_int = static_cast<int64_t>(*rounded);
1603      break;
1604  }
1605}
1606
1607// Raw access to the PC register.
1608void Simulator::set_pc(int32_t value) {
1609  pc_modified_ = true;
1610  registers_[pc] = value;
1611}
1612
1613bool Simulator::has_bad_pc() const {
1614  return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1615}
1616
1617// Raw access to the PC register without the special adjustment when reading.
1618int32_t Simulator::get_pc() const { return registers_[pc]; }
1619
1620// The MIPS cannot do unaligned reads and writes.  On some MIPS platforms an
1621// interrupt is caused.  On others it does a funky rotation thing.  For now we
1622// simply disallow unaligned reads, but at some point we may want to move to
1623// emulating the rotate behaviour.  Note that simulator runs have the runtime
1624// system running directly on the host system and only generated code is
1625// executed in the simulator.  Since the host is typically IA32 we will not
1626// get the correct MIPS-like behaviour on unaligned accesses.
1627
1628void Simulator::TraceRegWr(int32_t value, TraceType t) {
1629  if (::v8::internal::FLAG_trace_sim) {
1630    union {
1631      int32_t fmt_int32;
1632      float fmt_float;
1633    } v;
1634    v.fmt_int32 = value;
1635
1636    switch (t) {
1637      case WORD:
1638        SNPrintF(trace_buf_,
1639                 "%08" PRIx32 "    (%" PRIu64 ")    int32:%" PRId32
1640                 " uint32:%" PRIu32,
1641                 value, icount_, value, value);
1642        break;
1643      case FLOAT:
1644        SNPrintF(trace_buf_, "%08" PRIx32 "    (%" PRIu64 ")    flt:%e",
1645                 v.fmt_int32, icount_, v.fmt_float);
1646        break;
1647      default:
1648        UNREACHABLE();
1649    }
1650  }
1651}
1652
1653void Simulator::TraceRegWr(int64_t value, TraceType t) {
1654  if (::v8::internal::FLAG_trace_sim) {
1655    union {
1656      int64_t fmt_int64;
1657      double fmt_double;
1658    } v;
1659    v.fmt_int64 = value;
1660
1661    switch (t) {
1662      case DWORD:
1663        SNPrintF(trace_buf_,
1664                 "%016" PRIx64 "    (%" PRIu64 ")    int64:%" PRId64
1665                 " uint64:%" PRIu64,
1666                 value, icount_, value, value);
1667        break;
1668      case DOUBLE:
1669        SNPrintF(trace_buf_, "%016" PRIx64 "    (%" PRIu64 ")    dbl:%e",
1670                 v.fmt_int64, icount_, v.fmt_double);
1671        break;
1672      default:
1673        UNREACHABLE();
1674    }
1675  }
1676}
1677
1678template <typename T>
1679void Simulator::TraceMSARegWr(T* value, TraceType t) {
1680  if (::v8::internal::FLAG_trace_sim) {
1681    union {
1682      uint8_t b[16];
1683      uint16_t h[8];
1684      uint32_t w[4];
1685      uint64_t d[2];
1686      float f[4];
1687      double df[2];
1688    } v;
1689    memcpy(v.b, value, kSimd128Size);
1690    switch (t) {
1691      case BYTE:
1692        SNPrintF(trace_buf_,
1693                 "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64 ")",
1694                 v.d[0], v.d[1], icount_);
1695        break;
1696      case HALF:
1697        SNPrintF(trace_buf_,
1698                 "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64 ")",
1699                 v.d[0], v.d[1], icount_);
1700        break;
1701      case WORD:
1702        SNPrintF(trace_buf_,
1703                 "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64
1704                 ")    int32[0..3]:%" PRId32 "  %" PRId32 "  %" PRId32
1705                 "  %" PRId32,
1706                 v.d[0], v.d[1], icount_, v.w[0], v.w[1], v.w[2], v.w[3]);
1707        break;
1708      case DWORD:
1709        SNPrintF(trace_buf_,
1710                 "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64 ")",
1711                 v.d[0], v.d[1], icount_);
1712        break;
1713      case FLOAT:
1714        SNPrintF(trace_buf_,
1715                 "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64
1716                 ")    flt[0..3]:%e  %e  %e  %e",
1717                 v.d[0], v.d[1], icount_, v.f[0], v.f[1], v.f[2], v.f[3]);
1718        break;
1719      case DOUBLE:
1720        SNPrintF(trace_buf_,
1721                 "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64
1722                 ")    dbl[0..1]:%e  %e",
1723                 v.d[0], v.d[1], icount_, v.df[0], v.df[1]);
1724        break;
1725      default:
1726        UNREACHABLE();
1727    }
1728  }
1729}
1730
1731template <typename T>
1732void Simulator::TraceMSARegWr(T* value) {
1733  if (::v8::internal::FLAG_trace_sim) {
1734    union {
1735      uint8_t b[kMSALanesByte];
1736      uint16_t h[kMSALanesHalf];
1737      uint32_t w[kMSALanesWord];
1738      uint64_t d[kMSALanesDword];
1739      float f[kMSALanesWord];
1740      double df[kMSALanesDword];
1741    } v;
1742    memcpy(v.b, value, kMSALanesByte);
1743
1744    if (std::is_same<T, int32_t>::value) {
1745      SNPrintF(trace_buf_,
1746               "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64
1747               ")    int32[0..3]:%" PRId32 "  %" PRId32 "  %" PRId32
1748               "  %" PRId32,
1749               v.d[0], v.d[1], icount_, v.w[0], v.w[1], v.w[2], v.w[3]);
1750    } else if (std::is_same<T, float>::value) {
1751      SNPrintF(trace_buf_,
1752               "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64
1753               ")    flt[0..3]:%e  %e  %e  %e",
1754               v.d[0], v.d[1], icount_, v.f[0], v.f[1], v.f[2], v.f[3]);
1755    } else if (std::is_same<T, double>::value) {
1756      SNPrintF(trace_buf_,
1757               "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64
1758               ")    dbl[0..1]:%e  %e",
1759               v.d[0], v.d[1], icount_, v.df[0], v.df[1]);
1760    } else {
1761      SNPrintF(trace_buf_,
1762               "LO: %016" PRIx64 "  HI: %016" PRIx64 "    (%" PRIu64 ")",
1763               v.d[0], v.d[1], icount_);
1764    }
1765  }
1766}
1767
1768// TODO(plind): consider making icount_ printing a flag option.
1769void Simulator::TraceMemRd(int32_t addr, int32_t value, TraceType t) {
1770  if (::v8::internal::FLAG_trace_sim) {
1771    union {
1772      int32_t fmt_int32;
1773      float fmt_float;
1774    } v;
1775    v.fmt_int32 = value;
1776
1777    switch (t) {
1778      case WORD:
1779        SNPrintF(trace_buf_,
1780                 "%08" PRIx32 " <-- [%08" PRIx32 "]    (%" PRIu64
1781                 ")    int32:%" PRId32 " uint32:%" PRIu32,
1782                 value, addr, icount_, value, value);
1783        break;
1784      case FLOAT:
1785        SNPrintF(trace_buf_,
1786                 "%08" PRIx32 " <-- [%08" PRIx32 "]    (%" PRIu64 ")    flt:%e",
1787                 v.fmt_int32, addr, icount_, v.fmt_float);
1788        break;
1789      default:
1790        UNREACHABLE();
1791    }
1792  }
1793}
1794
1795void Simulator::TraceMemWr(int32_t addr, int32_t value, TraceType t) {
1796  if (::v8::internal::FLAG_trace_sim) {
1797    switch (t) {
1798      case BYTE:
1799        SNPrintF(trace_buf_,
1800                 "      %02" PRIx8 " --> [%08" PRIx32 "]    (%" PRIu64 ")",
1801                 static_cast<uint8_t>(value), addr, icount_);
1802        break;
1803      case HALF:
1804        SNPrintF(trace_buf_,
1805                 "    %04" PRIx16 " --> [%08" PRIx32 "]    (%" PRIu64 ")",
1806                 static_cast<uint16_t>(value), addr, icount_);
1807        break;
1808      case WORD:
1809        SNPrintF(trace_buf_,
1810                 "%08" PRIx32 " --> [%08" PRIx32 "]    (%" PRIu64 ")", value,
1811                 addr, icount_);
1812        break;
1813      default:
1814        UNREACHABLE();
1815    }
1816  }
1817}
1818
1819template <typename T>
1820void Simulator::TraceMemRd(int32_t addr, T value) {
1821  if (::v8::internal::FLAG_trace_sim) {
1822    switch (sizeof(T)) {
1823      case 1:
1824        SNPrintF(trace_buf_,
1825                 "%08" PRIx8 " <-- [%08" PRIx32 "]    (%" PRIu64
1826                 ")    int8:%" PRId8 " uint8:%" PRIu8,
1827                 static_cast<uint8_t>(value), addr, icount_,
1828                 static_cast<int8_t>(value), static_cast<uint8_t>(value));
1829        break;
1830      case 2:
1831        SNPrintF(trace_buf_,
1832                 "%08" PRIx16 " <-- [%08" PRIx32 "]    (%" PRIu64
1833                 ")    int16:%" PRId16 " uint16:%" PRIu16,
1834                 static_cast<uint16_t>(value), addr, icount_,
1835                 static_cast<int16_t>(value), static_cast<uint16_t>(value));
1836        break;
1837      case 4:
1838        SNPrintF(trace_buf_,
1839                 "%08" PRIx32 " <-- [%08" PRIx32 "]    (%" PRIu64
1840                 ")    int32:%" PRId32 " uint32:%" PRIu32,
1841                 static_cast<uint32_t>(value), addr, icount_,
1842                 static_cast<int32_t>(value), static_cast<uint32_t>(value));
1843        break;
1844      case 8:
1845        SNPrintF(trace_buf_,
1846                 "%08" PRIx64 " <-- [%08" PRIx32 "]    (%" PRIu64
1847                 ")    int64:%" PRId64 " uint64:%" PRIu64,
1848                 static_cast<uint64_t>(value), addr, icount_,
1849                 static_cast<int64_t>(value), static_cast<uint64_t>(value));
1850        break;
1851      default:
1852        UNREACHABLE();
1853    }
1854  }
1855}
1856
1857template <typename T>
1858void Simulator::TraceMemWr(int32_t addr, T value) {
1859  if (::v8::internal::FLAG_trace_sim) {
1860    switch (sizeof(T)) {
1861      case 1:
1862        SNPrintF(trace_buf_,
1863                 "      %02" PRIx8 " --> [%08" PRIx32 "]    (%" PRIu64 ")",
1864                 static_cast<uint8_t>(value), addr, icount_);
1865        break;
1866      case 2:
1867        SNPrintF(trace_buf_,
1868                 "    %04" PRIx16 " --> [%08" PRIx32 "]    (%" PRIu64 ")",
1869                 static_cast<uint16_t>(value), addr, icount_);
1870        break;
1871      case 4:
1872        SNPrintF(trace_buf_,
1873                 "%08" PRIx32 " --> [%08" PRIx32 "]    (%" PRIu64 ")",
1874                 static_cast<uint32_t>(value), addr, icount_);
1875        break;
1876      case 8:
1877        SNPrintF(trace_buf_,
1878                 "%16" PRIx64 " --> [%08" PRIx32 "]    (%" PRIu64 ")",
1879                 static_cast<uint64_t>(value), addr, icount_);
1880        break;
1881      default:
1882        UNREACHABLE();
1883    }
1884  }
1885}
1886
1887void Simulator::TraceMemRd(int32_t addr, int64_t value, TraceType t) {
1888  if (::v8::internal::FLAG_trace_sim) {
1889    union {
1890      int64_t fmt_int64;
1891      int32_t fmt_int32[2];
1892      float fmt_float[2];
1893      double fmt_double;
1894    } v;
1895    v.fmt_int64 = value;
1896
1897    switch (t) {
1898      case DWORD:
1899        SNPrintF(trace_buf_,
1900                 "%016" PRIx64 " <-- [%08" PRIx32 "]    (%" PRIu64
1901                 ")    int64:%" PRId64 " uint64:%" PRIu64,
1902                 v.fmt_int64, addr, icount_, v.fmt_int64, v.fmt_int64);
1903        break;
1904      case DOUBLE:
1905        SNPrintF(trace_buf_,
1906                 "%016" PRIx64 " <-- [%08" PRIx32 "]    (%" PRIu64
1907                 ")    dbl:%e",
1908                 v.fmt_int64, addr, icount_, v.fmt_double);
1909        break;
1910      case FLOAT_DOUBLE:
1911        SNPrintF(trace_buf_,
1912                 "%08" PRIx32 " <-- [%08" PRIx32 "]    (%" PRIu64
1913                 ")    flt:%e dbl:%e",
1914                 v.fmt_int32[1], addr, icount_, v.fmt_float[1], v.fmt_double);
1915        break;
1916      default:
1917        UNREACHABLE();
1918    }
1919  }
1920}
1921
1922void Simulator::TraceMemWr(int32_t addr, int64_t value, TraceType t) {
1923  if (::v8::internal::FLAG_trace_sim) {
1924    switch (t) {
1925      case DWORD:
1926        SNPrintF(trace_buf_,
1927                 "%016" PRIx64 " --> [%08" PRIx32 "]    (%" PRIu64 ")", value,
1928                 addr, icount_);
1929        break;
1930      default:
1931        UNREACHABLE();
1932    }
1933  }
1934}
1935
1936int Simulator::ReadW(int32_t addr, Instruction* instr, TraceType t) {
1937  if (addr >= 0 && addr < 0x400) {
1938    // This has to be a nullptr-dereference, drop into debugger.
1939    PrintF("Memory read from bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
1940           reinterpret_cast<intptr_t>(instr));
1941    MipsDebugger dbg(this);
1942    dbg.Debug();
1943  }
1944  if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
1945    local_monitor_.NotifyLoad();
1946    intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1947    switch (t) {
1948      case WORD:
1949        TraceMemRd(addr, static_cast<int32_t>(*ptr), t);
1950        break;
1951      case FLOAT:
1952        // This TraceType is allowed but tracing for this value will be omitted.
1953        break;
1954      default:
1955        UNREACHABLE();
1956    }
1957    return *ptr;
1958  }
1959  PrintF("Unaligned read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", addr,
1960         reinterpret_cast<intptr_t>(instr));
1961  MipsDebugger dbg(this);
1962  dbg.Debug();
1963  return 0;
1964}
1965
1966void Simulator::WriteW(int32_t addr, int value, Instruction* instr) {
1967  if (addr >= 0 && addr < 0x400) {
1968    // This has to be a nullptr-dereference, drop into debugger.
1969    PrintF("Memory write to bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
1970           reinterpret_cast<intptr_t>(instr));
1971    MipsDebugger dbg(this);
1972    dbg.Debug();
1973  }
1974  if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
1975    local_monitor_.NotifyStore();
1976    base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
1977    GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
1978    intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1979    TraceMemWr(addr, value, WORD);
1980    *ptr = value;
1981    return;
1982  }
1983  PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", addr,
1984         reinterpret_cast<intptr_t>(instr));
1985  MipsDebugger dbg(this);
1986  dbg.Debug();
1987}
1988
1989void Simulator::WriteConditionalW(int32_t addr, int32_t value,
1990                                  Instruction* instr, int32_t rt_reg) {
1991  if (addr >= 0 && addr < 0x400) {
1992    // This has to be a nullptr-dereference, drop into debugger.
1993    PrintF("Memory write to bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr,
1994           reinterpret_cast<intptr_t>(instr));
1995    MipsDebugger dbg(this);
1996    dbg.Debug();
1997  }
1998  if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
1999    base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2000    if (local_monitor_.NotifyStoreConditional(addr, TransactionSize::Word) &&
2001        GlobalMonitor::Get()->NotifyStoreConditional_Locked(
2002            addr, &global_monitor_thread_)) {
2003      local_monitor_.NotifyStore();
2004      GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2005      TraceMemWr(addr, value, WORD);
2006      int* ptr = reinterpret_cast<int*>(addr);
2007      *ptr = value;
2008      set_register(rt_reg, 1);
2009    } else {
2010      set_register(rt_reg, 0);
2011    }
2012    return;
2013  }
2014  PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", addr,
2015         reinterpret_cast<intptr_t>(instr));
2016  MipsDebugger dbg(this);
2017  dbg.Debug();
2018}
2019
2020double Simulator::ReadD(int32_t addr, Instruction* instr) {
2021  if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
2022    local_monitor_.NotifyLoad();
2023    double* ptr = reinterpret_cast<double*>(addr);
2024    return *ptr;
2025  }
2026  PrintF("Unaligned (double) read at 0x%08x, pc=0x%08" V8PRIxPTR "\n", addr,
2027         reinterpret_cast<intptr_t>(instr));
2028  base::OS::Abort();
2029}
2030
2031void Simulator::WriteD(int32_t addr, double value, Instruction* instr) {
2032  if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) {
2033    local_monitor_.NotifyStore();
2034    base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2035    GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2036    double* ptr = reinterpret_cast<double*>(addr);
2037    *ptr = value;
2038    return;
2039  }
2040  PrintF("Unaligned (double) write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", addr,
2041         reinterpret_cast<intptr_t>(instr));
2042  base::OS::Abort();
2043}
2044
2045uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) {
2046  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
2047    local_monitor_.NotifyLoad();
2048    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
2049    TraceMemRd(addr, static_cast<int32_t>(*ptr));
2050    return *ptr;
2051  }
2052  PrintF("Unaligned unsigned halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
2053         addr, reinterpret_cast<intptr_t>(instr));
2054  base::OS::Abort();
2055}
2056
2057int16_t Simulator::ReadH(int32_t addr, Instruction* instr) {
2058  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
2059    local_monitor_.NotifyLoad();
2060    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
2061    TraceMemRd(addr, static_cast<int32_t>(*ptr));
2062    return *ptr;
2063  }
2064  PrintF("Unaligned signed halfword read at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
2065         addr, reinterpret_cast<intptr_t>(instr));
2066  base::OS::Abort();
2067}
2068
2069void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) {
2070  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
2071    local_monitor_.NotifyStore();
2072    base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2073    GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2074    uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
2075    TraceMemWr(addr, value, HALF);
2076    *ptr = value;
2077    return;
2078  }
2079  PrintF("Unaligned unsigned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
2080         addr, reinterpret_cast<intptr_t>(instr));
2081  base::OS::Abort();
2082}
2083
2084void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) {
2085  if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) {
2086    local_monitor_.NotifyStore();
2087    base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2088    GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2089    int16_t* ptr = reinterpret_cast<int16_t*>(addr);
2090    TraceMemWr(addr, value, HALF);
2091    *ptr = value;
2092    return;
2093  }
2094  PrintF("Unaligned halfword write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", addr,
2095         reinterpret_cast<intptr_t>(instr));
2096  base::OS::Abort();
2097}
2098
2099uint32_t Simulator::ReadBU(int32_t addr) {
2100  local_monitor_.NotifyLoad();
2101  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
2102  TraceMemRd(addr, static_cast<int32_t>(*ptr));
2103  return *ptr & 0xFF;
2104}
2105
2106int32_t Simulator::ReadB(int32_t addr) {
2107  local_monitor_.NotifyLoad();
2108  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
2109  TraceMemRd(addr, static_cast<int32_t>(*ptr));
2110  return *ptr;
2111}
2112
2113void Simulator::WriteB(int32_t addr, uint8_t value) {
2114  local_monitor_.NotifyStore();
2115  base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2116  GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2117  uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
2118  TraceMemWr(addr, value, BYTE);
2119  *ptr = value;
2120}
2121
2122void Simulator::WriteB(int32_t addr, int8_t value) {
2123  local_monitor_.NotifyStore();
2124  base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2125  GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2126  int8_t* ptr = reinterpret_cast<int8_t*>(addr);
2127  TraceMemWr(addr, value, BYTE);
2128  *ptr = value;
2129}
2130
2131template <typename T>
2132T Simulator::ReadMem(int32_t addr, Instruction* instr) {
2133  int alignment_mask = (1 << sizeof(T)) - 1;
2134  if ((addr & alignment_mask) == 0 || IsMipsArchVariant(kMips32r6)) {
2135    local_monitor_.NotifyLoad();
2136    T* ptr = reinterpret_cast<T*>(addr);
2137    TraceMemRd(addr, *ptr);
2138    return *ptr;
2139  }
2140  PrintF("Unaligned read of type sizeof(%d) at 0x%08x, pc=0x%08" V8PRIxPTR "\n",
2141         sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
2142  base::OS::Abort();
2143  return 0;
2144}
2145
2146template <typename T>
2147void Simulator::WriteMem(int32_t addr, T value, Instruction* instr) {
2148  local_monitor_.NotifyStore();
2149  base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
2150  GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_);
2151  int alignment_mask = (1 << sizeof(T)) - 1;
2152  if ((addr & alignment_mask) == 0 || IsMipsArchVariant(kMips32r6)) {
2153    T* ptr = reinterpret_cast<T*>(addr);
2154    *ptr = value;
2155    TraceMemWr(addr, value);
2156    return;
2157  }
2158  PrintF("Unaligned write of type sizeof(%d) at 0x%08x, pc=0x%08" V8PRIxPTR
2159         "\n",
2160         sizeof(T), addr, reinterpret_cast<intptr_t>(instr));
2161  base::OS::Abort();
2162}
2163
2164// Returns the limit of the stack area to enable checking for stack overflows.
2165uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
2166  // The simulator uses a separate JS stack. If we have exhausted the C stack,
2167  // we also drop down the JS limit to reflect the exhaustion on the JS stack.
2168  if (base::Stack::GetCurrentStackPosition() < c_limit) {
2169    return reinterpret_cast<uintptr_t>(get_sp());
2170  }
2171
2172  // Otherwise the limit is the JS stack. Leave a safety margin of 1024 bytes
2173  // to prevent overrunning the stack when pushing values.
2174  return reinterpret_cast<uintptr_t>(stack_) + 1024;
2175}
2176
2177// Unsupported instructions use Format to print an error and stop execution.
2178void Simulator::Format(Instruction* instr, const char* format) {
2179  PrintF("Simulator found unsupported instruction:\n 0x%08" PRIxPTR ": %s\n",
2180         reinterpret_cast<intptr_t>(instr), format);
2181  UNIMPLEMENTED_MIPS();
2182}
2183
2184// Calls into the V8 runtime are based on this very simple interface.
2185// Note: To be able to return two values from some calls the code in runtime.cc
2186// uses the ObjectPair which is essentially two 32-bit values stuffed into a
2187// 64-bit value. With the code below we assume that all runtime calls return
2188// 64 bits of result. If they don't, the v1 result register contains a bogus
2189// value, which is fine because it is caller-saved.
2190using SimulatorRuntimeCall = int64_t (*)(
2191    int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4,
2192    int32_t arg5, int32_t arg6, int32_t arg7, int32_t arg8, int32_t arg9,
2193    int32_t arg10, int32_t arg11, int32_t arg12, int32_t arg13, int32_t arg14,
2194    int32_t arg15, int32_t arg16, int32_t arg17, int32_t arg18, int32_t arg19);
2195
2196// These prototypes handle the four types of FP calls.
2197using SimulatorRuntimeCompareCall = int64_t (*)(double darg0, double darg1);
2198using SimulatorRuntimeFPFPCall = double (*)(double darg0, double darg1);
2199using SimulatorRuntimeFPCall = double (*)(double darg0);
2200using SimulatorRuntimeFPIntCall = double (*)(double darg0, int32_t arg0);
2201
2202// This signature supports direct call in to API function native callback
2203// (refer to InvocationCallback in v8.h).
2204using SimulatorRuntimeDirectApiCall = void (*)(int32_t arg0);
2205using SimulatorRuntimeProfilingApiCall = void (*)(int32_t arg0, void* arg1);
2206
2207// This signature supports direct call to accessor getter callback.
2208using SimulatorRuntimeDirectGetterCall = void (*)(int32_t arg0, int32_t arg1);
2209using SimulatorRuntimeProfilingGetterCall = void (*)(int32_t arg0, int32_t arg1,
2210                                                     void* arg2);
2211
2212// Software interrupt instructions are used by the simulator to call into the
2213// C-based V8 runtime. They are also used for debugging with simulator.
2214void Simulator::SoftwareInterrupt() {
2215  // There are several instructions that could get us here,
2216  // the break_ instruction, or several variants of traps. All
2217  // Are "SPECIAL" class opcode, and are distinuished by function.
2218  int32_t func = instr_.FunctionFieldRaw();
2219  uint32_t code = (func == BREAK) ? instr_.Bits(25, 6) : -1;
2220
2221  // We first check if we met a call_rt_redirected.
2222  if (instr_.InstructionBits() == rtCallRedirInstr) {
2223    Redirection* redirection = Redirection::FromInstruction(instr_.instr());
2224    int32_t arg0 = get_register(a0);
2225    int32_t arg1 = get_register(a1);
2226    int32_t arg2 = get_register(a2);
2227    int32_t arg3 = get_register(a3);
2228
2229    int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
2230    // Args 4 and 5 are on the stack after the reserved space for args 0..3.
2231    int32_t arg4 = stack_pointer[4];
2232    int32_t arg5 = stack_pointer[5];
2233    int32_t arg6 = stack_pointer[6];
2234    int32_t arg7 = stack_pointer[7];
2235    int32_t arg8 = stack_pointer[8];
2236    int32_t arg9 = stack_pointer[9];
2237    int32_t arg10 = stack_pointer[10];
2238    int32_t arg11 = stack_pointer[11];
2239    int32_t arg12 = stack_pointer[12];
2240    int32_t arg13 = stack_pointer[13];
2241    int32_t arg14 = stack_pointer[14];
2242    int32_t arg15 = stack_pointer[15];
2243    int32_t arg16 = stack_pointer[16];
2244    int32_t arg17 = stack_pointer[17];
2245    int32_t arg18 = stack_pointer[18];
2246    int32_t arg19 = stack_pointer[19];
2247    STATIC_ASSERT(kMaxCParameters == 20);
2248
2249    bool fp_call =
2250        (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
2251        (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
2252        (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
2253        (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL);
2254
2255    if (!IsMipsSoftFloatABI) {
2256      // With the hard floating point calling convention, double
2257      // arguments are passed in FPU registers. Fetch the arguments
2258      // from there and call the builtin using soft floating point
2259      // convention.
2260      switch (redirection->type()) {
2261        case ExternalReference::BUILTIN_FP_FP_CALL:
2262        case ExternalReference::BUILTIN_COMPARE_CALL:
2263          if (IsFp64Mode()) {
2264            arg0 = get_fpu_register_word(f12);
2265            arg1 = get_fpu_register_hi_word(f12);
2266            arg2 = get_fpu_register_word(f14);
2267            arg3 = get_fpu_register_hi_word(f14);
2268          } else {
2269            arg0 = get_fpu_register_word(f12);
2270            arg1 = get_fpu_register_word(f13);
2271            arg2 = get_fpu_register_word(f14);
2272            arg3 = get_fpu_register_word(f15);
2273          }
2274          break;
2275        case ExternalReference::BUILTIN_FP_CALL:
2276          if (IsFp64Mode()) {
2277            arg0 = get_fpu_register_word(f12);
2278            arg1 = get_fpu_register_hi_word(f12);
2279          } else {
2280            arg0 = get_fpu_register_word(f12);
2281            arg1 = get_fpu_register_word(f13);
2282          }
2283          break;
2284        case ExternalReference::BUILTIN_FP_INT_CALL:
2285          if (IsFp64Mode()) {
2286            arg0 = get_fpu_register_word(f12);
2287            arg1 = get_fpu_register_hi_word(f12);
2288          } else {
2289            arg0 = get_fpu_register_word(f12);
2290            arg1 = get_fpu_register_word(f13);
2291          }
2292          arg2 = get_register(a2);
2293          break;
2294        default:
2295          break;
2296      }
2297    }
2298
2299    // This is dodgy but it works because the C entry stubs are never moved.
2300    // See comment in codegen-arm.cc and bug 1242173.
2301    int32_t saved_ra = get_register(ra);
2302
2303    intptr_t external =
2304        reinterpret_cast<intptr_t>(redirection->external_function());
2305
2306    // Based on CpuFeatures::IsSupported(FPU), Mips will use either hardware
2307    // FPU, or gcc soft-float routines. Hardware FPU is simulated in this
2308    // simulator. Soft-float has additional abstraction of ExternalReference,
2309    // to support serialization.
2310    if (fp_call) {
2311      double dval0, dval1;  // one or two double parameters
2312      int32_t ival;         // zero or one integer parameters
2313      int64_t iresult = 0;  // integer return value
2314      double dresult = 0;   // double return value
2315      GetFpArgs(&dval0, &dval1, &ival);
2316      SimulatorRuntimeCall generic_target =
2317          reinterpret_cast<SimulatorRuntimeCall>(external);
2318      if (::v8::internal::FLAG_trace_sim) {
2319        switch (redirection->type()) {
2320          case ExternalReference::BUILTIN_FP_FP_CALL:
2321          case ExternalReference::BUILTIN_COMPARE_CALL:
2322            PrintF("Call to host function at %p with args %f, %f",
2323                   reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2324                   dval0, dval1);
2325            break;
2326          case ExternalReference::BUILTIN_FP_CALL:
2327            PrintF("Call to host function at %p with arg %f",
2328                   reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2329                   dval0);
2330            break;
2331          case ExternalReference::BUILTIN_FP_INT_CALL:
2332            PrintF("Call to host function at %p with args %f, %d",
2333                   reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
2334                   dval0, ival);
2335            break;
2336          default:
2337            UNREACHABLE();
2338        }
2339      }
2340      switch (redirection->type()) {
2341        case ExternalReference::BUILTIN_COMPARE_CALL: {
2342          SimulatorRuntimeCompareCall target =
2343              reinterpret_cast<SimulatorRuntimeCompareCall>(external);
2344          iresult = target(dval0, dval1);
2345          set_register(v0, static_cast<int32_t>(iresult));
2346          set_register(v1, static_cast<int32_t>(iresult >> 32));
2347          break;
2348        }
2349        case ExternalReference::BUILTIN_FP_FP_CALL: {
2350          SimulatorRuntimeFPFPCall target =
2351              reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
2352          dresult = target(dval0, dval1);
2353          SetFpResult(dresult);
2354          break;
2355        }
2356        case ExternalReference::BUILTIN_FP_CALL: {
2357          SimulatorRuntimeFPCall target =
2358              reinterpret_cast<SimulatorRuntimeFPCall>(external);
2359          dresult = target(dval0);
2360          SetFpResult(dresult);
2361          break;
2362        }
2363        case ExternalReference::BUILTIN_FP_INT_CALL: {
2364          SimulatorRuntimeFPIntCall target =
2365              reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
2366          dresult = target(dval0, ival);
2367          SetFpResult(dresult);
2368          break;
2369        }
2370        default:
2371          UNREACHABLE();
2372      }
2373      if (::v8::internal::FLAG_trace_sim) {
2374        switch (redirection->type()) {
2375          case ExternalReference::BUILTIN_COMPARE_CALL:
2376            PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
2377            break;
2378          case ExternalReference::BUILTIN_FP_FP_CALL:
2379          case ExternalReference::BUILTIN_FP_CALL:
2380          case ExternalReference::BUILTIN_FP_INT_CALL:
2381            PrintF("Returned %f\n", dresult);
2382            break;
2383          default:
2384            UNREACHABLE();
2385        }
2386      }
2387    } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
2388      if (::v8::internal::FLAG_trace_sim) {
2389        PrintF("Call to host function at %p args %08x\n",
2390               reinterpret_cast<void*>(external), arg0);
2391      }
2392      SimulatorRuntimeDirectApiCall target =
2393          reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
2394      target(arg0);
2395    } else if (redirection->type() == ExternalReference::PROFILING_API_CALL) {
2396      if (::v8::internal::FLAG_trace_sim) {
2397        PrintF("Call to host function at %p args %08x %08x\n",
2398               reinterpret_cast<void*>(external), arg0, arg1);
2399      }
2400      SimulatorRuntimeProfilingApiCall target =
2401          reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
2402      target(arg0, Redirection::ReverseRedirection(arg1));
2403    } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
2404      if (::v8::internal::FLAG_trace_sim) {
2405        PrintF("Call to host function at %p args %08x %08x\n",
2406               reinterpret_cast<void*>(external), arg0, arg1);
2407      }
2408      SimulatorRuntimeDirectGetterCall target =
2409          reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
2410      target(arg0, arg1);
2411    } else if (redirection->type() ==
2412               ExternalReference::PROFILING_GETTER_CALL) {
2413      if (::v8::internal::FLAG_trace_sim) {
2414        PrintF("Call to host function at %p args %08x %08x %08x\n",
2415               reinterpret_cast<void*>(external), arg0, arg1, arg2);
2416      }
2417      SimulatorRuntimeProfilingGetterCall target =
2418          reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
2419      target(arg0, arg1, Redirection::ReverseRedirection(arg2));
2420    } else {
2421      DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
2422             redirection->type() == ExternalReference::BUILTIN_CALL_PAIR);
2423      SimulatorRuntimeCall target =
2424          reinterpret_cast<SimulatorRuntimeCall>(external);
2425      if (::v8::internal::FLAG_trace_sim) {
2426        PrintF(
2427            "Call to host function at %p "
2428            "args %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08xi, "
2429            "%08xi, %08xi, %08xi, %08xi, %08xi, %08xi, %08xi, %08xi, %08xi, "
2430            "%08xi\n",
2431            reinterpret_cast<void*>(FUNCTION_ADDR(target)), arg0, arg1, arg2,
2432            arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12,
2433            arg13, arg14, arg15, arg16, arg17, arg18, arg19);
2434      }
2435      int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
2436                              arg8, arg9, arg10, arg11, arg12, arg13, arg14,
2437                              arg15, arg16, arg17, arg18, arg19);
2438      set_register(v0, static_cast<int32_t>(result));
2439      set_register(v1, static_cast<int32_t>(result >> 32));
2440    }
2441    if (::v8::internal::FLAG_trace_sim) {
2442      PrintF("Returned %08x : %08x\n", get_register(v1), get_register(v0));
2443    }
2444    set_register(ra, saved_ra);
2445    set_pc(get_register(ra));
2446
2447  } else if (func == BREAK && code <= kMaxStopCode) {
2448    if (IsWatchpoint(code)) {
2449      PrintWatchpoint(code);
2450    } else {
2451      IncreaseStopCounter(code);
2452      HandleStop(code, instr_.instr());
2453    }
2454  } else {
2455    // All remaining break_ codes, and all traps are handled here.
2456    MipsDebugger dbg(this);
2457    dbg.Debug();
2458  }
2459}
2460
2461// Stop helper functions.
2462bool Simulator::IsWatchpoint(uint32_t code) {
2463  return (code <= kMaxWatchpointCode);
2464}
2465
2466void Simulator::PrintWatchpoint(uint32_t code) {
2467  MipsDebugger dbg(this);
2468  ++break_count_;
2469  PrintF("\n---- break %d marker: %3d  (instr count: %" PRIu64
2470         ") ----------"
2471         "----------------------------------",
2472         code, break_count_, icount_);
2473  dbg.PrintAllRegs();  // Print registers and continue running.
2474}
2475
2476void Simulator::HandleStop(uint32_t code, Instruction* instr) {
2477  // Stop if it is enabled, otherwise go on jumping over the stop
2478  // and the message address.
2479  if (IsEnabledStop(code)) {
2480    MipsDebugger dbg(this);
2481    dbg.Stop(instr);
2482  }
2483}
2484
2485bool Simulator::IsStopInstruction(Instruction* instr) {
2486  int32_t func = instr->FunctionFieldRaw();
2487  uint32_t code = static_cast<uint32_t>(instr->Bits(25, 6));
2488  return (func == BREAK) && code > kMaxWatchpointCode && code <= kMaxStopCode;
2489}
2490
2491bool Simulator::IsEnabledStop(uint32_t code) {
2492  DCHECK_LE(code, kMaxStopCode);
2493  DCHECK_GT(code, kMaxWatchpointCode);
2494  return !(watched_stops_[code].count & kStopDisabledBit);
2495}
2496
2497void Simulator::EnableStop(uint32_t code) {
2498  if (!IsEnabledStop(code)) {
2499    watched_stops_[code].count &= ~kStopDisabledBit;
2500  }
2501}
2502
2503void Simulator::DisableStop(uint32_t code) {
2504  if (IsEnabledStop(code)) {
2505    watched_stops_[code].count |= kStopDisabledBit;
2506  }
2507}
2508
2509void Simulator::IncreaseStopCounter(uint32_t code) {
2510  DCHECK_LE(code, kMaxStopCode);
2511  if ((watched_stops_[code].count & ~(1 << 31)) == 0x7FFFFFFF) {
2512    PrintF(
2513        "Stop counter for code %i has overflowed.\n"
2514        "Enabling this code and reseting the counter to 0.\n",
2515        code);
2516    watched_stops_[code].count = 0;
2517    EnableStop(code);
2518  } else {
2519    watched_stops_[code].count++;
2520  }
2521}
2522
2523// Print a stop status.
2524void Simulator::PrintStopInfo(uint32_t code) {
2525  if (code <= kMaxWatchpointCode) {
2526    PrintF("That is a watchpoint, not a stop.\n");
2527    return;
2528  } else if (code > kMaxStopCode) {
2529    PrintF("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
2530    return;
2531  }
2532  const char* state = IsEnabledStop(code) ? "Enabled" : "Disabled";
2533  int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
2534  // Don't print the state of unused breakpoints.
2535  if (count != 0) {
2536    if (watched_stops_[code].desc) {
2537      PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", code, code, state,
2538             count, watched_stops_[code].desc);
2539    } else {
2540      PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state,
2541             count);
2542    }
2543  }
2544}
2545
2546void Simulator::SignalException(Exception e) {
2547  FATAL("Error: Exception %i raised.", static_cast<int>(e));
2548}
2549
2550// Min/Max template functions for Double and Single arguments.
2551
2552template <typename T>
2553static T FPAbs(T a);
2554
2555template <>
2556double FPAbs<double>(double a) {
2557  return fabs(a);
2558}
2559
2560template <>
2561float FPAbs<float>(float a) {
2562  return fabsf(a);
2563}
2564
2565template <typename T>
2566static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T* result) {
2567  if (std::isnan(a) && std::isnan(b)) {
2568    *result = a;
2569  } else if (std::isnan(a)) {
2570    *result = b;
2571  } else if (std::isnan(b)) {
2572    *result = a;
2573  } else if (b == a) {
2574    // Handle -0.0 == 0.0 case.
2575    // std::signbit() returns int 0 or 1 so subtracting MaxMinKind::kMax
2576    // negates the result.
2577    *result = std::signbit(b) - static_cast<int>(kind) ? b : a;
2578  } else {
2579    return false;
2580  }
2581  return true;
2582}
2583
2584template <typename T>
2585static T FPUMin(T a, T b) {
2586  T result;
2587  if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
2588    return result;
2589  } else {
2590    return b < a ? b : a;
2591  }
2592}
2593
2594template <typename T>
2595static T FPUMax(T a, T b) {
2596  T result;
2597  if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, &result)) {
2598    return result;
2599  } else {
2600    return b > a ? b : a;
2601  }
2602}
2603
2604template <typename T>
2605static T FPUMinA(T a, T b) {
2606  T result;
2607  if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
2608    if (FPAbs(a) < FPAbs(b)) {
2609      result = a;
2610    } else if (FPAbs(b) < FPAbs(a)) {
2611      result = b;
2612    } else {
2613      result = a < b ? a : b;
2614    }
2615  }
2616  return result;
2617}
2618
2619template <typename T>
2620static T FPUMaxA(T a, T b) {
2621  T result;
2622  if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
2623    if (FPAbs(a) > FPAbs(b)) {
2624      result = a;
2625    } else if (FPAbs(b) > FPAbs(a)) {
2626      result = b;
2627    } else {
2628      result = a > b ? a : b;
2629    }
2630  }
2631  return result;
2632}
2633
2634enum class KeepSign : bool { no = false, yes };
2635
2636template <typename T, typename std::enable_if<std::is_floating_point<T>::value,
2637                                              int>::type = 0>
2638T FPUCanonalizeNaNArg(T result, T arg, KeepSign keepSign = KeepSign::no) {
2639  DCHECK(std::isnan(arg));
2640  T qNaN = std::numeric_limits<T>::quiet_NaN();
2641  if (keepSign == KeepSign::yes) {
2642    return std::copysign(qNaN, result);
2643  }
2644  return qNaN;
2645}
2646
2647template <typename T>
2648T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first) {
2649  if (std::isnan(first)) {
2650    return FPUCanonalizeNaNArg(result, first, keepSign);
2651  }
2652  return result;
2653}
2654
2655template <typename T, typename... Args>
2656T FPUCanonalizeNaNArgs(T result, KeepSign keepSign, T first, Args... args) {
2657  if (std::isnan(first)) {
2658    return FPUCanonalizeNaNArg(result, first, keepSign);
2659  }
2660  return FPUCanonalizeNaNArgs(result, keepSign, args...);
2661}
2662
2663template <typename Func, typename T, typename... Args>
2664T FPUCanonalizeOperation(Func f, T first, Args... args) {
2665  return FPUCanonalizeOperation(f, KeepSign::no, first, args...);
2666}
2667
2668template <typename Func, typename T, typename... Args>
2669T FPUCanonalizeOperation(Func f, KeepSign keepSign, T first, Args... args) {
2670  T result = f(first, args...);
2671  if (std::isnan(result)) {
2672    result = FPUCanonalizeNaNArgs(result, keepSign, first, args...);
2673  }
2674  return result;
2675}
2676
2677// Handle execution based on instruction types.
2678
2679void Simulator::DecodeTypeRegisterDRsType() {
2680  double ft, fs, fd;
2681  uint32_t cc, fcsr_cc;
2682  int64_t i64;
2683  fs = get_fpu_register_double(fs_reg());
2684  ft = (instr_.FunctionFieldRaw() != MOVF) ? get_fpu_register_double(ft_reg())
2685                                           : 0.0;
2686  fd = get_fpu_register_double(fd_reg());
2687  int64_t ft_int = bit_cast<int64_t>(ft);
2688  int64_t fd_int = bit_cast<int64_t>(fd);
2689  cc = instr_.FCccValue();
2690  fcsr_cc = get_fcsr_condition_bit(cc);
2691  switch (instr_.FunctionFieldRaw()) {
2692    case RINT: {
2693      DCHECK(IsMipsArchVariant(kMips32r6));
2694      double result, temp, temp_result;
2695      double upper = std::ceil(fs);
2696      double lower = std::floor(fs);
2697      switch (get_fcsr_rounding_mode()) {
2698        case kRoundToNearest:
2699          if (upper - fs < fs - lower) {
2700            result = upper;
2701          } else if (upper - fs > fs - lower) {
2702            result = lower;
2703          } else {
2704            temp_result = upper / 2;
2705            double reminder = modf(temp_result, &temp);
2706            if (reminder == 0) {
2707              result = upper;
2708            } else {
2709              result = lower;
2710            }
2711          }
2712          break;
2713        case kRoundToZero:
2714          result = (fs > 0 ? lower : upper);
2715          break;
2716        case kRoundToPlusInf:
2717          result = upper;
2718          break;
2719        case kRoundToMinusInf:
2720          result = lower;
2721          break;
2722      }
2723      SetFPUDoubleResult(fd_reg(), result);
2724      if (result != fs) {
2725        set_fcsr_bit(kFCSRInexactFlagBit, true);
2726      }
2727      break;
2728    }
2729    case SEL:
2730      DCHECK(IsMipsArchVariant(kMips32r6));
2731      SetFPUDoubleResult(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
2732      break;
2733    case SELEQZ_C:
2734      DCHECK(IsMipsArchVariant(kMips32r6));
2735      SetFPUDoubleResult(fd_reg(), (ft_int & 0x1) == 0 ? fs : 0.0);
2736      break;
2737    case SELNEZ_C:
2738      DCHECK(IsMipsArchVariant(kMips32r6));
2739      SetFPUDoubleResult(fd_reg(), (ft_int & 0x1) != 0 ? fs : 0.0);
2740      break;
2741    case MOVZ_C: {
2742      DCHECK(IsMipsArchVariant(kMips32r2));
2743      if (rt() == 0) {
2744        SetFPUDoubleResult(fd_reg(), fs);
2745      }
2746      break;
2747    }
2748    case MOVN_C: {
2749      DCHECK(IsMipsArchVariant(kMips32r2));
2750      int32_t rt_reg = instr_.RtValue();
2751      int32_t rt = get_register(rt_reg);
2752      if (rt != 0) {
2753        SetFPUDoubleResult(fd_reg(), fs);
2754      }
2755      break;
2756    }
2757    case MOVF: {
2758      // Same function field for MOVT.D and MOVF.D
2759      uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
2760      ft_cc = get_fcsr_condition_bit(ft_cc);
2761      if (instr_.Bit(16)) {  // Read Tf bit.
2762        // MOVT.D
2763        if (test_fcsr_bit(ft_cc)) SetFPUDoubleResult(fd_reg(), fs);
2764      } else {
2765        // MOVF.D
2766        if (!test_fcsr_bit(ft_cc)) SetFPUDoubleResult(fd_reg(), fs);
2767      }
2768      break;
2769    }
2770    case MIN:
2771      DCHECK(IsMipsArchVariant(kMips32r6));
2772      SetFPUDoubleResult(fd_reg(), FPUMin(ft, fs));
2773      break;
2774    case MAX:
2775      DCHECK(IsMipsArchVariant(kMips32r6));
2776      SetFPUDoubleResult(fd_reg(), FPUMax(ft, fs));
2777      break;
2778    case MINA:
2779      DCHECK(IsMipsArchVariant(kMips32r6));
2780      SetFPUDoubleResult(fd_reg(), FPUMinA(ft, fs));
2781      break;
2782    case MAXA:
2783      DCHECK(IsMipsArchVariant(kMips32r6));
2784      SetFPUDoubleResult(fd_reg(), FPUMaxA(ft, fs));
2785      break;
2786    case ADD_D:
2787      SetFPUDoubleResult(
2788          fd_reg(),
2789          FPUCanonalizeOperation(
2790              [](double lhs, double rhs) { return lhs + rhs; }, fs, ft));
2791      break;
2792    case SUB_D:
2793      SetFPUDoubleResult(
2794          fd_reg(),
2795          FPUCanonalizeOperation(
2796              [](double lhs, double rhs) { return lhs - rhs; }, fs, ft));
2797      break;
2798    case MADDF_D:
2799      DCHECK(IsMipsArchVariant(kMips32r6));
2800      SetFPUDoubleResult(fd_reg(), std::fma(fs, ft, fd));
2801      break;
2802    case MSUBF_D:
2803      DCHECK(IsMipsArchVariant(kMips32r6));
2804      SetFPUDoubleResult(fd_reg(), std::fma(-fs, ft, fd));
2805      break;
2806    case MUL_D:
2807      SetFPUDoubleResult(
2808          fd_reg(),
2809          FPUCanonalizeOperation(
2810              [](double lhs, double rhs) { return lhs * rhs; }, fs, ft));
2811      break;
2812    case DIV_D:
2813      SetFPUDoubleResult(
2814          fd_reg(),
2815          FPUCanonalizeOperation(
2816              [](double lhs, double rhs) { return lhs / rhs; }, fs, ft));
2817      break;
2818    case ABS_D:
2819      SetFPUDoubleResult(
2820          fd_reg(),
2821          FPUCanonalizeOperation([](double fs) { return FPAbs(fs); }, fs));
2822      break;
2823    case MOV_D:
2824      SetFPUDoubleResult(fd_reg(), fs);
2825      break;
2826    case NEG_D:
2827      SetFPUDoubleResult(fd_reg(),
2828                         FPUCanonalizeOperation([](double src) { return -src; },
2829                                                KeepSign::yes, fs));
2830      break;
2831    case SQRT_D:
2832      SetFPUDoubleResult(
2833          fd_reg(),
2834          FPUCanonalizeOperation([](double fs) { return std::sqrt(fs); }, fs));
2835      break;
2836    case RSQRT_D:
2837      SetFPUDoubleResult(
2838          fd_reg(), FPUCanonalizeOperation(
2839                        [](double fs) { return 1.0 / std::sqrt(fs); }, fs));
2840      break;
2841    case RECIP_D:
2842      SetFPUDoubleResult(fd_reg(), FPUCanonalizeOperation(
2843                                       [](double fs) { return 1.0 / fs; }, fs));
2844      break;
2845    case C_UN_D:
2846      set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
2847      TraceRegWr(test_fcsr_bit(fcsr_cc));
2848      break;
2849    case C_EQ_D:
2850      set_fcsr_bit(fcsr_cc, (fs == ft));
2851      TraceRegWr(test_fcsr_bit(fcsr_cc));
2852      break;
2853    case C_UEQ_D:
2854      set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
2855      TraceRegWr(test_fcsr_bit(fcsr_cc));
2856      break;
2857    case C_OLT_D:
2858      set_fcsr_bit(fcsr_cc, (fs < ft));
2859      TraceRegWr(test_fcsr_bit(fcsr_cc));
2860      break;
2861    case C_ULT_D:
2862      set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
2863      TraceRegWr(test_fcsr_bit(fcsr_cc));
2864      break;
2865    case C_OLE_D:
2866      set_fcsr_bit(fcsr_cc, (fs <= ft));
2867      TraceRegWr(test_fcsr_bit(fcsr_cc));
2868      break;
2869    case C_ULE_D:
2870      set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
2871      TraceRegWr(test_fcsr_bit(fcsr_cc));
2872      break;
2873    case CVT_W_D: {  // Convert double to word.
2874      double rounded;
2875      int32_t result;
2876      round_according_to_fcsr(fs, &rounded, &result, fs);
2877      SetFPUWordResult(fd_reg(), result);
2878      if (set_fcsr_round_error(fs, rounded)) {
2879        set_fpu_register_word_invalid_result(fs, rounded);
2880      }
2881    } break;
2882    case ROUND_W_D:  // Round double to word (round half to even).
2883    {
2884      double rounded = std::floor(fs + 0.5);
2885      int32_t result = static_cast<int32_t>(rounded);
2886      if ((result & 1) != 0 && result - fs == 0.5) {
2887        // If the number is halfway between two integers,
2888        // round to the even one.
2889        result--;
2890      }
2891      SetFPUWordResult(fd_reg(), result);
2892      if (set_fcsr_round_error(fs, rounded)) {
2893        set_fpu_register_word_invalid_result(fs, rounded);
2894      }
2895    } break;
2896    case TRUNC_W_D:  // Truncate double to word (round towards 0).
2897    {
2898      double rounded = trunc(fs);
2899      int32_t result = static_cast<int32_t>(rounded);
2900      SetFPUWordResult(fd_reg(), result);
2901      if (set_fcsr_round_error(fs, rounded)) {
2902        set_fpu_register_word_invalid_result(fs, rounded);
2903      }
2904    } break;
2905    case FLOOR_W_D:  // Round double to word towards negative infinity.
2906    {
2907      double rounded = std::floor(fs);
2908      int32_t result = static_cast<int32_t>(rounded);
2909      SetFPUWordResult(fd_reg(), result);
2910      if (set_fcsr_round_error(fs, rounded)) {
2911        set_fpu_register_word_invalid_result(fs, rounded);
2912      }
2913    } break;
2914    case CEIL_W_D:  // Round double to word towards positive infinity.
2915    {
2916      double rounded = std::ceil(fs);
2917      int32_t result = static_cast<int32_t>(rounded);
2918      SetFPUWordResult(fd_reg(), result);
2919      if (set_fcsr_round_error(fs, rounded)) {
2920        set_fpu_register_word_invalid_result(fs, rounded);
2921      }
2922    } break;
2923    case CVT_S_D:  // Convert double to float (single).
2924      SetFPUFloatResult(fd_reg(), static_cast<float>(fs));
2925      break;
2926    case CVT_L_D: {  // Mips32r2: Truncate double to 64-bit long-word.
2927      if (IsFp64Mode()) {
2928        int64_t result;
2929        double rounded;
2930        round64_according_to_fcsr(fs, &rounded, &result, fs);
2931        SetFPUResult(fd_reg(), result);
2932        if (set_fcsr_round64_error(fs, rounded)) {
2933          set_fpu_register_invalid_result64(fs, rounded);
2934        }
2935      } else {
2936        UNSUPPORTED();
2937      }
2938      break;
2939    }
2940    case TRUNC_L_D: {  // Mips32r2 instruction.
2941      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2942      double rounded = trunc(fs);
2943      i64 = static_cast<int64_t>(rounded);
2944      if (IsFp64Mode()) {
2945        SetFPUResult(fd_reg(), i64);
2946        if (set_fcsr_round64_error(fs, rounded)) {
2947          set_fpu_register_invalid_result64(fs, rounded);
2948        }
2949      } else {
2950        UNSUPPORTED();
2951      }
2952      break;
2953    }
2954    case ROUND_L_D: {  // Mips32r2 instruction.
2955      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2956      double rounded = std::floor(fs + 0.5);
2957      int64_t result = static_cast<int64_t>(rounded);
2958      if ((result & 1) != 0 && result - fs == 0.5) {
2959        // If the number is halfway between two integers,
2960        // round to the even one.
2961        result--;
2962      }
2963      int64_t i64 = static_cast<int64_t>(result);
2964      if (IsFp64Mode()) {
2965        SetFPUResult(fd_reg(), i64);
2966        if (set_fcsr_round64_error(fs, rounded)) {
2967          set_fpu_register_invalid_result64(fs, rounded);
2968        }
2969      } else {
2970        UNSUPPORTED();
2971      }
2972      break;
2973    }
2974    case FLOOR_L_D: {  // Mips32r2 instruction.
2975      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2976      double rounded = std::floor(fs);
2977      int64_t i64 = static_cast<int64_t>(rounded);
2978      if (IsFp64Mode()) {
2979        SetFPUResult(fd_reg(), i64);
2980        if (set_fcsr_round64_error(fs, rounded)) {
2981          set_fpu_register_invalid_result64(fs, rounded);
2982        }
2983      } else {
2984        UNSUPPORTED();
2985      }
2986      break;
2987    }
2988    case CEIL_L_D: {  // Mips32r2 instruction.
2989      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
2990      double rounded = std::ceil(fs);
2991      int64_t i64 = static_cast<int64_t>(rounded);
2992      if (IsFp64Mode()) {
2993        SetFPUResult(fd_reg(), i64);
2994        if (set_fcsr_round64_error(fs, rounded)) {
2995          set_fpu_register_invalid_result64(fs, rounded);
2996        }
2997      } else {
2998        UNSUPPORTED();
2999      }
3000      break;
3001    }
3002    case CLASS_D: {  // Mips32r6 instruction
3003      // Convert double input to uint64_t for easier bit manipulation
3004      uint64_t classed = bit_cast<uint64_t>(fs);
3005
3006      // Extracting sign, exponent and mantissa from the input double
3007      uint32_t sign = (classed >> 63) & 1;
3008      uint32_t exponent = (classed >> 52) & 0x00000000000007FF;
3009      uint64_t mantissa = classed & 0x000FFFFFFFFFFFFF;
3010      uint64_t result;
3011      double dResult;
3012
3013      // Setting flags if input double is negative infinity,
3014      // positive infinity, negative zero or positive zero
3015      bool negInf = (classed == 0xFFF0000000000000);
3016      bool posInf = (classed == 0x7FF0000000000000);
3017      bool negZero = (classed == 0x8000000000000000);
3018      bool posZero = (classed == 0x0000000000000000);
3019
3020      bool signalingNan;
3021      bool quietNan;
3022      bool negSubnorm;
3023      bool posSubnorm;
3024      bool negNorm;
3025      bool posNorm;
3026
3027      // Setting flags if double is NaN
3028      signalingNan = false;
3029      quietNan = false;
3030      if (!negInf && !posInf && exponent == 0x7FF) {
3031        quietNan = ((mantissa & 0x0008000000000000) != 0) &&
3032                   ((mantissa & (0x0008000000000000 - 1)) == 0);
3033        signalingNan = !quietNan;
3034      }
3035
3036      // Setting flags if double is subnormal number
3037      posSubnorm = false;
3038      negSubnorm = false;
3039      if ((exponent == 0) && (mantissa != 0)) {
3040        DCHECK(sign == 0 || sign == 1);
3041        posSubnorm = (sign == 0);
3042        negSubnorm = (sign == 1);
3043      }
3044
3045      // Setting flags if double is normal number
3046      posNorm = false;
3047      negNorm = false;
3048      if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
3049          !quietNan && !negZero && !posZero) {
3050        DCHECK(sign == 0 || sign == 1);
3051        posNorm = (sign == 0);
3052        negNorm = (sign == 1);
3053      }
3054
3055      // Calculating result according to description of CLASS.D instruction
3056      result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
3057               (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
3058               (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
3059
3060      DCHECK_NE(result, 0);
3061
3062      dResult = bit_cast<double>(result);
3063      SetFPUDoubleResult(fd_reg(), dResult);
3064
3065      break;
3066    }
3067    case C_F_D: {
3068      set_fcsr_bit(fcsr_cc, false);
3069      TraceRegWr(test_fcsr_bit(fcsr_cc));
3070      break;
3071    }
3072    default:
3073      UNREACHABLE();
3074  }
3075}
3076
3077void Simulator::DecodeTypeRegisterWRsType() {
3078  float fs = get_fpu_register_float(fs_reg());
3079  float ft = get_fpu_register_float(ft_reg());
3080  int32_t alu_out = 0x12345678;
3081  switch (instr_.FunctionFieldRaw()) {
3082    case CVT_S_W:  // Convert word to float (single).
3083      alu_out = get_fpu_register_signed_word(fs_reg());
3084      SetFPUFloatResult(fd_reg(), static_cast<float>(alu_out));
3085      break;
3086    case CVT_D_W:  // Convert word to double.
3087      alu_out = get_fpu_register_signed_word(fs_reg());
3088      SetFPUDoubleResult(fd_reg(), static_cast<double>(alu_out));
3089      break;
3090    case CMP_AF:
3091      SetFPUWordResult(fd_reg(), 0);
3092      break;
3093    case CMP_UN:
3094      if (std::isnan(fs) || std::isnan(ft)) {
3095        SetFPUWordResult(fd_reg(), -1);
3096      } else {
3097        SetFPUWordResult(fd_reg(), 0);
3098      }
3099      break;
3100    case CMP_EQ:
3101      if (fs == ft) {
3102        SetFPUWordResult(fd_reg(), -1);
3103      } else {
3104        SetFPUWordResult(fd_reg(), 0);
3105      }
3106      break;
3107    case CMP_UEQ:
3108      if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3109        SetFPUWordResult(fd_reg(), -1);
3110      } else {
3111        SetFPUWordResult(fd_reg(), 0);
3112      }
3113      break;
3114    case CMP_LT:
3115      if (fs < ft) {
3116        SetFPUWordResult(fd_reg(), -1);
3117      } else {
3118        SetFPUWordResult(fd_reg(), 0);
3119      }
3120      break;
3121    case CMP_ULT:
3122      if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3123        SetFPUWordResult(fd_reg(), -1);
3124      } else {
3125        SetFPUWordResult(fd_reg(), 0);
3126      }
3127      break;
3128    case CMP_LE:
3129      if (fs <= ft) {
3130        SetFPUWordResult(fd_reg(), -1);
3131      } else {
3132        SetFPUWordResult(fd_reg(), 0);
3133      }
3134      break;
3135    case CMP_ULE:
3136      if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3137        SetFPUWordResult(fd_reg(), -1);
3138      } else {
3139        SetFPUWordResult(fd_reg(), 0);
3140      }
3141      break;
3142    case CMP_OR:
3143      if (!std::isnan(fs) && !std::isnan(ft)) {
3144        SetFPUWordResult(fd_reg(), -1);
3145      } else {
3146        SetFPUWordResult(fd_reg(), 0);
3147      }
3148      break;
3149    case CMP_UNE:
3150      if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3151        SetFPUWordResult(fd_reg(), -1);
3152      } else {
3153        SetFPUWordResult(fd_reg(), 0);
3154      }
3155      break;
3156    case CMP_NE:
3157      if (fs != ft) {
3158        SetFPUWordResult(fd_reg(), -1);
3159      } else {
3160        SetFPUWordResult(fd_reg(), 0);
3161      }
3162      break;
3163    default:
3164      UNREACHABLE();
3165  }
3166}
3167
3168void Simulator::DecodeTypeRegisterSRsType() {
3169  float fs, ft, fd;
3170  fs = get_fpu_register_float(fs_reg());
3171  ft = get_fpu_register_float(ft_reg());
3172  fd = get_fpu_register_float(fd_reg());
3173  int32_t ft_int = bit_cast<int32_t>(ft);
3174  int32_t fd_int = bit_cast<int32_t>(fd);
3175  uint32_t cc, fcsr_cc;
3176  cc = instr_.FCccValue();
3177  fcsr_cc = get_fcsr_condition_bit(cc);
3178  switch (instr_.FunctionFieldRaw()) {
3179    case RINT: {
3180      DCHECK(IsMipsArchVariant(kMips32r6));
3181      float result, temp_result;
3182      double temp;
3183      float upper = std::ceil(fs);
3184      float lower = std::floor(fs);
3185      switch (get_fcsr_rounding_mode()) {
3186        case kRoundToNearest:
3187          if (upper - fs < fs - lower) {
3188            result = upper;
3189          } else if (upper - fs > fs - lower) {
3190            result = lower;
3191          } else {
3192            temp_result = upper / 2;
3193            float reminder = modf(temp_result, &temp);
3194            if (reminder == 0) {
3195              result = upper;
3196            } else {
3197              result = lower;
3198            }
3199          }
3200          break;
3201        case kRoundToZero:
3202          result = (fs > 0 ? lower : upper);
3203          break;
3204        case kRoundToPlusInf:
3205          result = upper;
3206          break;
3207        case kRoundToMinusInf:
3208          result = lower;
3209          break;
3210      }
3211      SetFPUFloatResult(fd_reg(), result);
3212      if (result != fs) {
3213        set_fcsr_bit(kFCSRInexactFlagBit, true);
3214      }
3215      break;
3216    }
3217    case ADD_S:
3218      SetFPUFloatResult(
3219          fd_reg(),
3220          FPUCanonalizeOperation([](float lhs, float rhs) { return lhs + rhs; },
3221                                 fs, ft));
3222      break;
3223    case SUB_S:
3224      SetFPUFloatResult(
3225          fd_reg(),
3226          FPUCanonalizeOperation([](float lhs, float rhs) { return lhs - rhs; },
3227                                 fs, ft));
3228      break;
3229    case MADDF_S:
3230      DCHECK(IsMipsArchVariant(kMips32r6));
3231      SetFPUFloatResult(fd_reg(), std::fma(fs, ft, fd));
3232      break;
3233    case MSUBF_S:
3234      DCHECK(IsMipsArchVariant(kMips32r6));
3235      SetFPUFloatResult(fd_reg(), std::fma(-fs, ft, fd));
3236      break;
3237    case MUL_S:
3238      SetFPUFloatResult(
3239          fd_reg(),
3240          FPUCanonalizeOperation([](float lhs, float rhs) { return lhs * rhs; },
3241                                 fs, ft));
3242      break;
3243    case DIV_S:
3244      SetFPUFloatResult(
3245          fd_reg(),
3246          FPUCanonalizeOperation([](float lhs, float rhs) { return lhs / rhs; },
3247                                 fs, ft));
3248      break;
3249    case ABS_S:
3250      SetFPUFloatResult(fd_reg(), FPUCanonalizeOperation(
3251                                      [](float fs) { return FPAbs(fs); }, fs));
3252      break;
3253    case MOV_S:
3254      SetFPUFloatResult(fd_reg(), fs);
3255      break;
3256    case NEG_S:
3257      SetFPUFloatResult(fd_reg(),
3258                        FPUCanonalizeOperation([](float src) { return -src; },
3259                                               KeepSign::yes, fs));
3260      break;
3261    case SQRT_S:
3262      SetFPUFloatResult(
3263          fd_reg(),
3264          FPUCanonalizeOperation([](float src) { return std::sqrt(src); }, fs));
3265      break;
3266    case RSQRT_S:
3267      SetFPUFloatResult(
3268          fd_reg(), FPUCanonalizeOperation(
3269                        [](float src) { return 1.0 / std::sqrt(src); }, fs));
3270      break;
3271    case RECIP_S:
3272      SetFPUFloatResult(fd_reg(), FPUCanonalizeOperation(
3273                                      [](float src) { return 1.0 / src; }, fs));
3274      break;
3275    case C_F_D:
3276      set_fcsr_bit(fcsr_cc, false);
3277      TraceRegWr(test_fcsr_bit(fcsr_cc));
3278      break;
3279    case C_UN_D:
3280      set_fcsr_bit(fcsr_cc, std::isnan(fs) || std::isnan(ft));
3281      TraceRegWr(test_fcsr_bit(fcsr_cc));
3282      break;
3283    case C_EQ_D:
3284      set_fcsr_bit(fcsr_cc, (fs == ft));
3285      TraceRegWr(test_fcsr_bit(fcsr_cc));
3286      break;
3287    case C_UEQ_D:
3288      set_fcsr_bit(fcsr_cc, (fs == ft) || (std::isnan(fs) || std::isnan(ft)));
3289      TraceRegWr(test_fcsr_bit(fcsr_cc));
3290      break;
3291    case C_OLT_D:
3292      set_fcsr_bit(fcsr_cc, (fs < ft));
3293      TraceRegWr(test_fcsr_bit(fcsr_cc));
3294      break;
3295    case C_ULT_D:
3296      set_fcsr_bit(fcsr_cc, (fs < ft) || (std::isnan(fs) || std::isnan(ft)));
3297      TraceRegWr(test_fcsr_bit(fcsr_cc));
3298      break;
3299    case C_OLE_D:
3300      set_fcsr_bit(fcsr_cc, (fs <= ft));
3301      TraceRegWr(test_fcsr_bit(fcsr_cc));
3302      break;
3303    case C_ULE_D:
3304      set_fcsr_bit(fcsr_cc, (fs <= ft) || (std::isnan(fs) || std::isnan(ft)));
3305      TraceRegWr(test_fcsr_bit(fcsr_cc));
3306      break;
3307    case CVT_D_S:
3308      SetFPUDoubleResult(fd_reg(), static_cast<double>(fs));
3309      break;
3310    case SEL:
3311      DCHECK(IsMipsArchVariant(kMips32r6));
3312      SetFPUFloatResult(fd_reg(), (fd_int & 0x1) == 0 ? fs : ft);
3313      break;
3314    case CLASS_S: {  // Mips32r6 instruction
3315      // Convert float input to uint32_t for easier bit manipulation
3316      float fs = get_fpu_register_float(fs_reg());
3317      uint32_t classed = bit_cast<uint32_t>(fs);
3318
3319      // Extracting sign, exponent and mantissa from the input float
3320      uint32_t sign = (classed >> 31) & 1;
3321      uint32_t exponent = (classed >> 23) & 0x000000FF;
3322      uint32_t mantissa = classed & 0x007FFFFF;
3323      uint32_t result;
3324      float fResult;
3325
3326      // Setting flags if input float is negative infinity,
3327      // positive infinity, negative zero or positive zero
3328      bool negInf = (classed == 0xFF800000);
3329      bool posInf = (classed == 0x7F800000);
3330      bool negZero = (classed == 0x80000000);
3331      bool posZero = (classed == 0x00000000);
3332
3333      bool signalingNan;
3334      bool quietNan;
3335      bool negSubnorm;
3336      bool posSubnorm;
3337      bool negNorm;
3338      bool posNorm;
3339
3340      // Setting flags if float is NaN
3341      signalingNan = false;
3342      quietNan = false;
3343      if (!negInf && !posInf && (exponent == 0xFF)) {
3344        quietNan = ((mantissa & 0x00200000) == 0) &&
3345                   ((mantissa & (0x00200000 - 1)) == 0);
3346        signalingNan = !quietNan;
3347      }
3348
3349      // Setting flags if float is subnormal number
3350      posSubnorm = false;
3351      negSubnorm = false;
3352      if ((exponent == 0) && (mantissa != 0)) {
3353        DCHECK(sign == 0 || sign == 1);
3354        posSubnorm = (sign == 0);
3355        negSubnorm = (sign == 1);
3356      }
3357
3358      // Setting flags if float is normal number
3359      posNorm = false;
3360      negNorm = false;
3361      if (!posSubnorm && !negSubnorm && !posInf && !negInf && !signalingNan &&
3362          !quietNan && !negZero && !posZero) {
3363        DCHECK(sign == 0 || sign == 1);
3364        posNorm = (sign == 0);
3365        negNorm = (sign == 1);
3366      }
3367
3368      // Calculating result according to description of CLASS.S instruction
3369      result = (posZero << 9) | (posSubnorm << 8) | (posNorm << 7) |
3370               (posInf << 6) | (negZero << 5) | (negSubnorm << 4) |
3371               (negNorm << 3) | (negInf << 2) | (quietNan << 1) | signalingNan;
3372
3373      DCHECK_NE(result, 0);
3374
3375      fResult = bit_cast<float>(result);
3376      SetFPUFloatResult(fd_reg(), fResult);
3377
3378      break;
3379    }
3380    case SELEQZ_C:
3381      DCHECK(IsMipsArchVariant(kMips32r6));
3382      SetFPUFloatResult(fd_reg(), (ft_int & 0x1) == 0
3383                                      ? get_fpu_register_float(fs_reg())
3384                                      : 0.0);
3385      break;
3386    case SELNEZ_C:
3387      DCHECK(IsMipsArchVariant(kMips32r6));
3388      SetFPUFloatResult(fd_reg(), (ft_int & 0x1) != 0
3389                                      ? get_fpu_register_float(fs_reg())
3390                                      : 0.0);
3391      break;
3392    case MOVZ_C: {
3393      DCHECK(IsMipsArchVariant(kMips32r2));
3394      if (rt() == 0) {
3395        SetFPUFloatResult(fd_reg(), fs);
3396      }
3397      break;
3398    }
3399    case MOVN_C: {
3400      DCHECK(IsMipsArchVariant(kMips32r2));
3401      if (rt() != 0) {
3402        SetFPUFloatResult(fd_reg(), fs);
3403      }
3404      break;
3405    }
3406    case MOVF: {
3407      // Same function field for MOVT.D and MOVF.D
3408      uint32_t ft_cc = (ft_reg() >> 2) & 0x7;
3409      ft_cc = get_fcsr_condition_bit(ft_cc);
3410
3411      if (instr_.Bit(16)) {  // Read Tf bit.
3412        // MOVT.D
3413        if (test_fcsr_bit(ft_cc)) SetFPUFloatResult(fd_reg(), fs);
3414      } else {
3415        // MOVF.D
3416        if (!test_fcsr_bit(ft_cc)) SetFPUFloatResult(fd_reg(), fs);
3417      }
3418      break;
3419    }
3420    case TRUNC_W_S: {  // Truncate single to word (round towards 0).
3421      float rounded = trunc(fs);
3422      int32_t result = static_cast<int32_t>(rounded);
3423      SetFPUWordResult(fd_reg(), result);
3424      if (set_fcsr_round_error(fs, rounded)) {
3425        set_fpu_register_word_invalid_result(fs, rounded);
3426      }
3427    } break;
3428    case TRUNC_L_S: {  // Mips32r2 instruction.
3429      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3430      float rounded = trunc(fs);
3431      int64_t i64 = static_cast<int64_t>(rounded);
3432      if (IsFp64Mode()) {
3433        SetFPUResult(fd_reg(), i64);
3434        if (set_fcsr_round64_error(fs, rounded)) {
3435          set_fpu_register_invalid_result64(fs, rounded);
3436        }
3437      } else {
3438        UNSUPPORTED();
3439      }
3440      break;
3441    }
3442    case FLOOR_W_S:  // Round double to word towards negative infinity.
3443    {
3444      float rounded = std::floor(fs);
3445      int32_t result = static_cast<int32_t>(rounded);
3446      SetFPUWordResult(fd_reg(), result);
3447      if (set_fcsr_round_error(fs, rounded)) {
3448        set_fpu_register_word_invalid_result(fs, rounded);
3449      }
3450    } break;
3451    case FLOOR_L_S: {  // Mips32r2 instruction.
3452      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3453      float rounded = std::floor(fs);
3454      int64_t i64 = static_cast<int64_t>(rounded);
3455      if (IsFp64Mode()) {
3456        SetFPUResult(fd_reg(), i64);
3457        if (set_fcsr_round64_error(fs, rounded)) {
3458          set_fpu_register_invalid_result64(fs, rounded);
3459        }
3460      } else {
3461        UNSUPPORTED();
3462      }
3463      break;
3464    }
3465    case ROUND_W_S: {
3466      float rounded = std::floor(fs + 0.5);
3467      int32_t result = static_cast<int32_t>(rounded);
3468      if ((result & 1) != 0 && result - fs == 0.5) {
3469        // If the number is halfway between two integers,
3470        // round to the even one.
3471        result--;
3472      }
3473      SetFPUWordResult(fd_reg(), result);
3474      if (set_fcsr_round_error(fs, rounded)) {
3475        set_fpu_register_word_invalid_result(fs, rounded);
3476      }
3477      break;
3478    }
3479    case ROUND_L_S: {  // Mips32r2 instruction.
3480      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3481      float rounded = std::floor(fs + 0.5);
3482      int64_t result = static_cast<int64_t>(rounded);
3483      if ((result & 1) != 0 && result - fs == 0.5) {
3484        // If the number is halfway between two integers,
3485        // round to the even one.
3486        result--;
3487      }
3488      int64_t i64 = static_cast<int64_t>(result);
3489      if (IsFp64Mode()) {
3490        SetFPUResult(fd_reg(), i64);
3491        if (set_fcsr_round64_error(fs, rounded)) {
3492          set_fpu_register_invalid_result64(fs, rounded);
3493        }
3494      } else {
3495        UNSUPPORTED();
3496      }
3497      break;
3498    }
3499    case CEIL_W_S:  // Round double to word towards positive infinity.
3500    {
3501      float rounded = std::ceil(fs);
3502      int32_t result = static_cast<int32_t>(rounded);
3503      SetFPUWordResult(fd_reg(), result);
3504      if (set_fcsr_round_error(fs, rounded)) {
3505        set_fpu_register_word_invalid_result(fs, rounded);
3506      }
3507    } break;
3508    case CEIL_L_S: {  // Mips32r2 instruction.
3509      DCHECK(IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6));
3510      float rounded = std::ceil(fs);
3511      int64_t i64 = static_cast<int64_t>(rounded);
3512      if (IsFp64Mode()) {
3513        SetFPUResult(fd_reg(), i64);
3514        if (set_fcsr_round64_error(fs, rounded)) {
3515          set_fpu_register_invalid_result64(fs, rounded);
3516        }
3517      } else {
3518        UNSUPPORTED();
3519      }
3520      break;
3521    }
3522    case MIN:
3523      DCHECK(IsMipsArchVariant(kMips32r6));
3524      SetFPUFloatResult(fd_reg(), FPUMin(ft, fs));
3525      break;
3526    case MAX:
3527      DCHECK(IsMipsArchVariant(kMips32r6));
3528      SetFPUFloatResult(fd_reg(), FPUMax(ft, fs));
3529      break;
3530    case MINA:
3531      DCHECK(IsMipsArchVariant(kMips32r6));
3532      SetFPUFloatResult(fd_reg(), FPUMinA(ft, fs));
3533      break;
3534    case MAXA:
3535      DCHECK(IsMipsArchVariant(kMips32r6));
3536      SetFPUFloatResult(fd_reg(), FPUMaxA(ft, fs));
3537      break;
3538    case CVT_L_S: {
3539      if (IsFp64Mode()) {
3540        int64_t result;
3541        float rounded;
3542        round64_according_to_fcsr(fs, &rounded, &result, fs);
3543        SetFPUResult(fd_reg(), result);
3544        if (set_fcsr_round64_error(fs, rounded)) {
3545          set_fpu_register_invalid_result64(fs, rounded);
3546        }
3547      } else {
3548        UNSUPPORTED();
3549      }
3550      break;
3551    }
3552    case CVT_W_S: {
3553      float rounded;
3554      int32_t result;
3555      round_according_to_fcsr(fs, &rounded, &result, fs);
3556      SetFPUWordResult(fd_reg(), result);
3557      if (set_fcsr_round_error(fs, rounded)) {
3558        set_fpu_register_word_invalid_result(fs, rounded);
3559      }
3560      break;
3561    }
3562    default:
3563      // CVT_W_S CVT_L_S  ROUND_W_S ROUND_L_S FLOOR_W_S FLOOR_L_S
3564      // CEIL_W_S CEIL_L_S CVT_PS_S are unimplemented.
3565      UNREACHABLE();
3566  }
3567}
3568
3569void Simulator::DecodeTypeRegisterLRsType() {
3570  double fs = get_fpu_register_double(fs_reg());
3571  double ft = get_fpu_register_double(ft_reg());
3572  switch (instr_.FunctionFieldRaw()) {
3573    case CVT_D_L:  // Mips32r2 instruction.
3574      // Watch the signs here, we want 2 32-bit vals
3575      // to make a sign-64.
3576      int64_t i64;
3577      if (IsFp64Mode()) {
3578        i64 = get_fpu_register(fs_reg());
3579      } else {
3580        i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg()));
3581        i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32;
3582      }
3583      SetFPUDoubleResult(fd_reg(), static_cast<double>(i64));
3584      break;
3585    case CVT_S_L:
3586      if (IsFp64Mode()) {
3587        i64 = get_fpu_register(fs_reg());
3588      } else {
3589        i64 = static_cast<uint32_t>(get_fpu_register_word(fs_reg()));
3590        i64 |= static_cast<int64_t>(get_fpu_register_word(fs_reg() + 1)) << 32;
3591      }
3592      SetFPUFloatResult(fd_reg(), static_cast<float>(i64));
3593      break;
3594    case CMP_AF:  // Mips64r6 CMP.D instructions.
3595      SetFPUResult(fd_reg(), 0);
3596      break;
3597    case CMP_UN:
3598      if (std::isnan(fs) || std::isnan(ft)) {
3599        SetFPUResult(fd_reg(), -1);
3600      } else {
3601        SetFPUResult(fd_reg(), 0);
3602      }
3603      break;
3604    case CMP_EQ:
3605      if (fs == ft) {
3606        SetFPUResult(fd_reg(), -1);
3607      } else {
3608        SetFPUResult(fd_reg(), 0);
3609      }
3610      break;
3611    case CMP_UEQ:
3612      if ((fs == ft) || (std::isnan(fs) || std::isnan(ft))) {
3613        SetFPUResult(fd_reg(), -1);
3614      } else {
3615        SetFPUResult(fd_reg(), 0);
3616      }
3617      break;
3618    case CMP_LT:
3619      if (fs < ft) {
3620        SetFPUResult(fd_reg(), -1);
3621      } else {
3622        SetFPUResult(fd_reg(), 0);
3623      }
3624      break;
3625    case CMP_ULT:
3626      if ((fs < ft) || (std::isnan(fs) || std::isnan(ft))) {
3627        SetFPUResult(fd_reg(), -1);
3628      } else {
3629        SetFPUResult(fd_reg(), 0);
3630      }
3631      break;
3632    case CMP_LE:
3633      if (fs <= ft) {
3634        SetFPUResult(fd_reg(), -1);
3635      } else {
3636        SetFPUResult(fd_reg(), 0);
3637      }
3638      break;
3639    case CMP_ULE:
3640      if ((fs <= ft) || (std::isnan(fs) || std::isnan(ft))) {
3641        SetFPUResult(fd_reg(), -1);
3642      } else {
3643        SetFPUResult(fd_reg(), 0);
3644      }
3645      break;
3646    case CMP_OR:
3647      if (!std::isnan(fs) && !std::isnan(ft)) {
3648        SetFPUResult(fd_reg(), -1);
3649      } else {
3650        SetFPUResult(fd_reg(), 0);
3651      }
3652      break;
3653    case CMP_UNE:
3654      if ((fs != ft) || (std::isnan(fs) || std::isnan(ft))) {
3655        SetFPUResult(fd_reg(), -1);
3656      } else {
3657        SetFPUResult(fd_reg(), 0);
3658      }
3659      break;
3660    case CMP_NE:
3661      if (fs != ft && (!std::isnan(fs) && !std::isnan(ft))) {
3662        SetFPUResult(fd_reg(), -1);
3663      } else {
3664        SetFPUResult(fd_reg(), 0);
3665      }
3666      break;
3667    default:
3668      UNREACHABLE();
3669  }
3670}
3671
3672void Simulator::DecodeTypeRegisterCOP1() {
3673  switch (instr_.RsFieldRaw()) {
3674    case CFC1:
3675      // At the moment only FCSR is supported.
3676      DCHECK_EQ(fs_reg(), kFCSRRegister);
3677      SetResult(rt_reg(), FCSR_);
3678      break;
3679    case MFC1:
3680      SetResult(rt_reg(), get_fpu_register_word(fs_reg()));
3681      break;
3682    case MFHC1:
3683      if (IsFp64Mode()) {
3684        SetResult(rt_reg(), get_fpu_register_hi_word(fs_reg()));
3685      } else {
3686        SetResult(rt_reg(), get_fpu_register_word(fs_reg() + 1));
3687      }
3688      break;
3689    case CTC1: {
3690      // At the moment only FCSR is supported.
3691      DCHECK_EQ(fs_reg(), kFCSRRegister);
3692      int32_t reg = registers_[rt_reg()];
3693      if (IsMipsArchVariant(kMips32r6)) {
3694        FCSR_ = reg | kFCSRNaN2008FlagMask;
3695      } else {
3696        DCHECK(IsMipsArchVariant(kMips32r1) || IsMipsArchVariant(kMips32r2));
3697        FCSR_ = reg & ~kFCSRNaN2008FlagMask;
3698      }
3699      TraceRegWr(static_cast<int32_t>(FCSR_));
3700      break;
3701    }
3702    case MTC1:
3703      // Hardware writes upper 32-bits to zero on mtc1.
3704      set_fpu_register_hi_word(fs_reg(), 0);
3705      set_fpu_register_word(fs_reg(), registers_[rt_reg()]);
3706      TraceRegWr(get_fpu_register_word(fs_reg()), FLOAT);
3707      break;
3708    case MTHC1:
3709      if (IsFp64Mode()) {
3710        set_fpu_register_hi_word(fs_reg(), registers_[rt_reg()]);
3711        TraceRegWr(get_fpu_register(fs_reg()), DOUBLE);
3712      } else {
3713        set_fpu_register_word(fs_reg() + 1, registers_[rt_reg()]);
3714        if (fs_reg() % 2) {
3715          TraceRegWr(get_fpu_register_word(fs_reg() + 1), FLOAT);
3716        } else {
3717          TraceRegWr(get_fpu_register(fs_reg()), DOUBLE);
3718        }
3719      }
3720      break;
3721    case S: {
3722      DecodeTypeRegisterSRsType();
3723      break;
3724    }
3725    case D:
3726      DecodeTypeRegisterDRsType();
3727      break;
3728    case W:
3729      DecodeTypeRegisterWRsType();
3730      break;
3731    case L:
3732      DecodeTypeRegisterLRsType();
3733      break;
3734    case PS:
3735      // Not implemented.
3736      UNREACHABLE();
3737    default:
3738      UNREACHABLE();
3739  }
3740}
3741
3742void Simulator::DecodeTypeRegisterCOP1X() {
3743  switch (instr_.FunctionFieldRaw()) {
3744    case MADD_S: {
3745      DCHECK(IsMipsArchVariant(kMips32r2));
3746      float fr, ft, fs;
3747      fr = get_fpu_register_float(fr_reg());
3748      fs = get_fpu_register_float(fs_reg());
3749      ft = get_fpu_register_float(ft_reg());
3750      SetFPUFloatResult(fd_reg(), fs * ft + fr);
3751      break;
3752    }
3753    case MSUB_S: {
3754      DCHECK(IsMipsArchVariant(kMips32r2));
3755      float fr, ft, fs;
3756      fr = get_fpu_register_float(fr_reg());
3757      fs = get_fpu_register_float(fs_reg());
3758      ft = get_fpu_register_float(ft_reg());
3759      SetFPUFloatResult(fd_reg(), fs * ft - fr);
3760      break;
3761    }
3762    case MADD_D: {
3763      DCHECK(IsMipsArchVariant(kMips32r2));
3764      double fr, ft, fs;
3765      fr = get_fpu_register_double(fr_reg());
3766      fs = get_fpu_register_double(fs_reg());
3767      ft = get_fpu_register_double(ft_reg());
3768      SetFPUDoubleResult(fd_reg(), fs * ft + fr);
3769      break;
3770    }
3771    case MSUB_D: {
3772      DCHECK(IsMipsArchVariant(kMips32r2));
3773      double fr, ft, fs;
3774      fr = get_fpu_register_double(fr_reg());
3775      fs = get_fpu_register_double(fs_reg());
3776      ft = get_fpu_register_double(ft_reg());
3777      SetFPUDoubleResult(fd_reg(), fs * ft - fr);
3778      break;
3779    }
3780    default:
3781      UNREACHABLE();
3782  }
3783}
3784
3785void Simulator::DecodeTypeRegisterSPECIAL() {
3786  int64_t alu_out = 0x12345678;
3787  int64_t i64hilo = 0;
3788  uint64_t u64hilo = 0;
3789  bool do_interrupt = false;
3790
3791  switch (instr_.FunctionFieldRaw()) {
3792    case SELEQZ_S:
3793      DCHECK(IsMipsArchVariant(kMips32r6));
3794      SetResult(rd_reg(), rt() == 0 ? rs() : 0);
3795      break;
3796    case SELNEZ_S:
3797      DCHECK(IsMipsArchVariant(kMips32r6));
3798      SetResult(rd_reg(), rt() != 0 ? rs() : 0);
3799      break;
3800    case JR: {
3801      int32_t next_pc = rs();
3802      int32_t current_pc = get_pc();
3803      Instruction* branch_delay_instr =
3804          reinterpret_cast<Instruction*>(current_pc + kInstrSize);
3805      BranchDelayInstructionDecode(branch_delay_instr);
3806      set_pc(next_pc);
3807      pc_modified_ = true;
3808      break;
3809    }
3810    case JALR: {
3811      int32_t next_pc = rs();
3812      int32_t return_addr_reg = rd_reg();
3813      int32_t current_pc = get_pc();
3814      Instruction* branch_delay_instr =
3815          reinterpret_cast<Instruction*>(current_pc + kInstrSize);
3816      BranchDelayInstructionDecode(branch_delay_instr);
3817      set_register(return_addr_reg, current_pc + 2 * kInstrSize);
3818      set_pc(next_pc);
3819      pc_modified_ = true;
3820      break;
3821    }
3822    case SLL:
3823      alu_out = rt() << sa();
3824      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3825      break;
3826    case SRL:
3827      if (rs_reg() == 0) {
3828        // Regular logical right shift of a word by a fixed number of
3829        // bits instruction. RS field is always equal to 0.
3830        alu_out = rt_u() >> sa();
3831      } else {
3832        // Logical right-rotate of a word by a fixed number of bits. This
3833        // is special case of SRL instruction, added in MIPS32 Release 2.
3834        // RS field is equal to 00001.
3835        alu_out = base::bits::RotateRight32(rt_u(), sa());
3836      }
3837      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3838      break;
3839    case SRA:
3840      alu_out = rt() >> sa();
3841      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3842      break;
3843    case SLLV:
3844      alu_out = rt() << rs();
3845      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3846      break;
3847    case SRLV:
3848      if (sa() == 0) {
3849        // Regular logical right-shift of a word by a variable number of
3850        // bits instruction. SA field is always equal to 0.
3851        alu_out = rt_u() >> rs();
3852      } else {
3853        // Logical right-rotate of a word by a variable number of bits.
3854        // This is special case od SRLV instruction, added in MIPS32
3855        // Release 2. SA field is equal to 00001.
3856        alu_out = base::bits::RotateRight32(rt_u(), rs_u());
3857      }
3858      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3859      break;
3860    case SRAV:
3861      SetResult(rd_reg(), rt() >> rs());
3862      break;
3863    case LSA: {
3864      DCHECK(IsMipsArchVariant(kMips32r6));
3865      int8_t sa = lsa_sa() + 1;
3866      int32_t _rt = rt();
3867      int32_t _rs = rs();
3868      int32_t res = _rs << sa;
3869      res += _rt;
3870      DCHECK_EQ(res, (rs() << (lsa_sa() + 1)) + rt());
3871      USE(res);
3872      SetResult(rd_reg(), (rs() << (lsa_sa() + 1)) + rt());
3873      break;
3874    }
3875    case MFHI:  // MFHI == CLZ on R6.
3876      if (!IsMipsArchVariant(kMips32r6)) {
3877        DCHECK_EQ(sa(), 0);
3878        alu_out = get_register(HI);
3879      } else {
3880        // MIPS spec: If no bits were set in GPR rs, the result written to
3881        // GPR rd is 32.
3882        DCHECK_EQ(sa(), 1);
3883        alu_out = base::bits::CountLeadingZeros32(rs_u());
3884      }
3885      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3886      break;
3887    case MFLO:
3888      alu_out = get_register(LO);
3889      SetResult(rd_reg(), static_cast<int32_t>(alu_out));
3890      break;
3891    // Instructions using HI and LO registers.
3892    case MULT:
3893      i64hilo = static_cast<int64_t>(rs()) * static_cast<int64_t>(rt());
3894      if (!IsMipsArchVariant(kMips32r6)) {
3895        set_register(LO, static_cast<int32_t>(i64hilo & 0xFFFFFFFF));
3896        set_register(HI, static_cast<int32_t>(i64hilo >> 32));
3897      } else {
3898        switch (sa()) {
3899          case MUL_OP:
3900            SetResult(rd_reg(), static_cast<int32_t>(i64hilo & 0xFFFFFFFF));
3901            break;
3902          case MUH_OP:
3903            SetResult(rd_reg(), static_cast<int32_t>(i64hilo >> 32));
3904            break;
3905          default:
3906            UNIMPLEMENTED_MIPS();
3907            break;
3908        }
3909      }
3910      break;
3911    case MULTU:
3912      u64hilo = static_cast<uint64_t>(rs_u()) * static_cast<uint64_t>(rt_u());
3913      if (!IsMipsArchVariant(kMips32r6)) {
3914        set_register(LO, static_cast<int32_t>(u64hilo & 0xFFFFFFFF));
3915        set_register(HI, static_cast<int32_t>(u64hilo >> 32));
3916      } else {
3917        switch (sa()) {
3918          case MUL_OP:
3919            SetResult(rd_reg(), static_cast<int32_t>(u64hilo & 0xFFFFFFFF));
3920            break;
3921          case MUH_OP:
3922            SetResult(rd_reg(), static_cast<int32_t>(u64hilo >> 32));
3923            break;
3924          default:
3925            UNIMPLEMENTED_MIPS();
3926            break;
3927        }
3928      }
3929      break;
3930    case DIV:
3931      if (IsMipsArchVariant(kMips32r6)) {
3932        switch (sa()) {
3933          case DIV_OP:
3934            if (rs() == INT_MIN && rt() == -1) {
3935              SetResult(rd_reg(), INT_MIN);
3936            } else if (rt() != 0) {
3937              SetResult(rd_reg(), rs() / rt());
3938            }
3939            break;
3940          case MOD_OP:
3941            if (rs() == INT_MIN && rt() == -1) {
3942              SetResult(rd_reg(), 0);
3943            } else if (rt() != 0) {
3944              SetResult(rd_reg(), rs() % rt());
3945            }
3946            break;
3947          default:
3948            UNIMPLEMENTED_MIPS();
3949            break;
3950        }
3951      } else {
3952        // Divide by zero and overflow was not checked in the
3953        // configuration step - div and divu do not raise exceptions. On
3954        // division by 0 the result will be UNPREDICTABLE. On overflow
3955        // (INT_MIN/-1), return INT_MIN which is what the hardware does.
3956        if (rs() == INT_MIN && rt() == -1) {
3957          set_register(LO, INT_MIN);
3958          set_register(HI, 0);
3959        } else if (rt() != 0) {
3960          set_register(LO, rs() / rt());
3961          set_register(HI, rs() % rt());
3962        }
3963      }
3964      break;
3965    case DIVU:
3966      if (IsMipsArchVariant(kMips32r6)) {
3967        switch (sa()) {
3968          case DIV_OP:
3969            if (rt_u() != 0) {
3970              SetResult(rd_reg(), rs_u() / rt_u());
3971            }
3972            break;
3973          case MOD_OP:
3974            if (rt_u() != 0) {
3975              SetResult(rd_reg(), rs_u() % rt_u());
3976            }
3977            break;
3978          default:
3979            UNIMPLEMENTED_MIPS();
3980            break;
3981        }
3982      } else {
3983        if (rt_u() != 0) {
3984          set_register(LO, rs_u() / rt_u());
3985          set_register(HI, rs_u() % rt_u());
3986        }
3987      }
3988      break;
3989    case ADD:
3990      if (HaveSameSign(rs(), rt())) {
3991        if (rs() > 0) {
3992          if (rs() <= (Registers::kMaxValue - rt())) {
3993            SignalException(kIntegerOverflow);
3994          }
3995        } else if (rs() < 0) {
3996          if (rs() >= (Registers::kMinValue - rt())) {
3997            SignalException(kIntegerUnderflow);
3998          }
3999        }
4000      }
4001      SetResult(rd_reg(), rs() + rt());
4002      break;
4003    case ADDU:
4004      SetResult(rd_reg(), rs() + rt());
4005      break;
4006    case SUB:
4007      if (!HaveSameSign(rs(), rt())) {
4008        if (rs() > 0) {
4009          if (rs() <= (Registers::kMaxValue + rt())) {
4010            SignalException(kIntegerOverflow);
4011          }
4012        } else if (rs() < 0) {
4013          if (rs() >= (Registers::kMinValue + rt())) {
4014            SignalException(kIntegerUnderflow);
4015          }
4016        }
4017      }
4018      SetResult(rd_reg(), rs() - rt());
4019      break;
4020    case SUBU:
4021      SetResult(rd_reg(), rs() - rt());
4022      break;
4023    case AND:
4024      SetResult(rd_reg(), rs() & rt());
4025      break;
4026    case OR:
4027      SetResult(rd_reg(), rs() | rt());
4028      break;
4029    case XOR:
4030      SetResult(rd_reg(), rs() ^ rt());
4031      break;
4032    case NOR:
4033      SetResult(rd_reg(), ~(rs() | rt()));
4034      break;
4035    case SLT:
4036      SetResult(rd_reg(), rs() < rt() ? 1 : 0);
4037      break;
4038    case SLTU:
4039      SetResult(rd_reg(), rs_u() < rt_u() ? 1 : 0);
4040      break;
4041    // Break and trap instructions.
4042    case BREAK:
4043      do_interrupt = true;
4044      break;
4045    case TGE:
4046      do_interrupt = rs() >= rt();
4047      break;
4048    case TGEU:
4049      do_interrupt = rs_u() >= rt_u();
4050      break;
4051    case TLT:
4052      do_interrupt = rs() < rt();
4053      break;
4054    case TLTU:
4055      do_interrupt = rs_u() < rt_u();
4056      break;
4057    case TEQ:
4058      do_interrupt = rs() == rt();
4059      break;
4060    case TNE:
4061      do_interrupt = rs() != rt();
4062      break;
4063    case SYNC:
4064      // TODO(palfia): Ignore sync instruction for now.
4065      break;
4066    // Conditional moves.
4067    case MOVN:
4068      if (rt()) {
4069        SetResult(rd_reg(), rs());
4070      }
4071      break;
4072    case MOVCI: {
4073      uint32_t cc = instr_.FBccValue();
4074      uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
4075      if (instr_.Bit(16)) {  // Read Tf bit.
4076        if (test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
4077      } else {
4078        if (!test_fcsr_bit(fcsr_cc)) set_register(rd_reg(), rs());
4079      }
4080      break;
4081    }
4082    case MOVZ:
4083      if (!rt()) {
4084        SetResult(rd_reg(), rs());
4085      }
4086      break;
4087    default:
4088      UNREACHABLE();
4089  }
4090  if (do_interrupt) {
4091    SoftwareInterrupt();
4092  }
4093}
4094
4095void Simulator::DecodeTypeRegisterSPECIAL2() {
4096  int32_t alu_out;
4097  switch (instr_.FunctionFieldRaw()) {
4098    case MUL:
4099      // Only the lower 32 bits are kept.
4100      alu_out = rs_u() * rt_u();
4101      // HI and LO are UNPREDICTABLE after the operation.
4102      set_register(LO, Unpredictable);
4103      set_register(HI, Unpredictable);
4104      break;
4105    case CLZ:
4106      // MIPS32 spec: If no bits were set in GPR rs, the result written to
4107      // GPR rd is 32.
4108      alu_out = base::bits::CountLeadingZeros32(rs_u());
4109      break;
4110    default:
4111      alu_out = 0x12345678;
4112      UNREACHABLE();
4113  }
4114  SetResult(rd_reg(), alu_out);
4115}
4116
4117void Simulator::DecodeTypeRegisterSPECIAL3() {
4118  int32_t alu_out;
4119  switch (instr_.FunctionFieldRaw()) {
4120    case INS: {  // Mips32r2 instruction.
4121      // Interpret rd field as 5-bit msb of insert.
4122      uint16_t msb = rd_reg();
4123      // Interpret sa field as 5-bit lsb of insert.
4124      uint16_t lsb = sa();
4125      uint16_t size = msb - lsb + 1;
4126      uint32_t mask;
4127      if (size < 32) {
4128        mask = (1 << size) - 1;
4129      } else {
4130        mask = std::numeric_limits<uint32_t>::max();
4131      }
4132      alu_out = (rt_u() & ~(mask << lsb)) | ((rs_u() & mask) << lsb);
4133      // Ins instr leaves result in Rt, rather than Rd.
4134      SetResult(rt_reg(), alu_out);
4135      break;
4136    }
4137    case EXT: {  // Mips32r2 instruction.
4138      // Interpret rd field as 5-bit msb of extract.
4139      uint16_t msb = rd_reg();
4140      // Interpret sa field as 5-bit lsb of extract.
4141      uint16_t lsb = sa();
4142      uint16_t size = msb + 1;
4143      uint32_t mask;
4144      if (size < 32) {
4145        mask = (1 << size) - 1;
4146      } else {
4147        mask = std::numeric_limits<uint32_t>::max();
4148      }
4149      alu_out = (rs_u() & (mask << lsb)) >> lsb;
4150      SetResult(rt_reg(), alu_out);
4151      break;
4152    }
4153    case BSHFL: {
4154      int sa = instr_.SaFieldRaw() >> kSaShift;
4155      switch (sa) {
4156        case BITSWAP: {
4157          uint32_t input = static_cast<uint32_t>(rt());
4158          uint32_t output = 0;
4159          uint8_t i_byte, o_byte;
4160
4161          // Reverse the bit in byte for each individual byte
4162          for (int i = 0; i < 4; i++) {
4163            output = output >> 8;
4164            i_byte = input & 0xFF;
4165
4166            // Fast way to reverse bits in byte
4167            // Devised by Sean Anderson, July 13, 2001
4168            o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
4169                                           (i_byte * 0x8020LU & 0x88440LU)) *
4170                                              0x10101LU >>
4171                                          16);
4172
4173            output = output | (static_cast<uint32_t>(o_byte << 24));
4174            input = input >> 8;
4175          }
4176
4177          alu_out = static_cast<int32_t>(output);
4178          break;
4179        }
4180        case SEB: {
4181          uint8_t input = static_cast<uint8_t>(rt());
4182          uint32_t output = input;
4183          uint32_t mask = 0x00000080;
4184
4185          // Extending sign
4186          if (mask & input) {
4187            output |= 0xFFFFFF00;
4188          }
4189
4190          alu_out = static_cast<int32_t>(output);
4191          break;
4192        }
4193        case SEH: {
4194          uint16_t input = static_cast<uint16_t>(rt());
4195          uint32_t output = input;
4196          uint32_t mask = 0x00008000;
4197
4198          // Extending sign
4199          if (mask & input) {
4200            output |= 0xFFFF0000;
4201          }
4202
4203          alu_out = static_cast<int32_t>(output);
4204          break;
4205        }
4206        case WSBH: {
4207          uint32_t input = static_cast<uint32_t>(rt());
4208          uint32_t output = 0;
4209
4210          uint32_t mask = 0xFF000000;
4211          for (int i = 0; i < 4; i++) {
4212            uint32_t tmp = mask & input;
4213            if (i % 2 == 0) {
4214              tmp = tmp >> 8;
4215            } else {
4216              tmp = tmp << 8;
4217            }
4218            output = output | tmp;
4219            mask = mask >> 8;
4220          }
4221
4222          alu_out = static_cast<int32_t>(output);
4223          break;
4224        }
4225        default: {
4226          const uint8_t bp = instr_.Bp2Value();
4227          sa >>= kBp2Bits;
4228          switch (sa) {
4229            case ALIGN: {
4230              if (bp == 0) {
4231                alu_out = static_cast<int32_t>(rt());
4232              } else {
4233                uint32_t rt_hi = rt() << (8 * bp);
4234                uint32_t rs_lo = rs() >> (8 * (4 - bp));
4235                alu_out = static_cast<int32_t>(rt_hi | rs_lo);
4236              }
4237              break;
4238            }
4239            default:
4240              alu_out = 0x12345678;
4241              UNREACHABLE();
4242          }
4243        }
4244      }
4245      SetResult(rd_reg(), alu_out);
4246      break;
4247    }
4248    default:
4249      UNREACHABLE();
4250  }
4251}
4252
4253int Simulator::DecodeMsaDataFormat() {
4254  int df = -1;
4255  if (instr_.IsMSABranchInstr()) {
4256    switch (instr_.RsFieldRaw()) {
4257      case BZ_V:
4258      case BNZ_V:
4259        df = MSA_VECT;
4260        break;
4261      case BZ_B:
4262      case BNZ_B:
4263        df = MSA_BYTE;
4264        break;
4265      case BZ_H:
4266      case BNZ_H:
4267        df = MSA_HALF;
4268        break;
4269      case BZ_W:
4270      case BNZ_W:
4271        df = MSA_WORD;
4272        break;
4273      case BZ_D:
4274      case BNZ_D:
4275        df = MSA_DWORD;
4276        break;
4277      default:
4278        UNREACHABLE();
4279    }
4280  } else {
4281    int DF[] = {MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD};
4282    switch (instr_.MSAMinorOpcodeField()) {
4283      case kMsaMinorI5:
4284      case kMsaMinorI10:
4285      case kMsaMinor3R:
4286        df = DF[instr_.Bits(22, 21)];
4287        break;
4288      case kMsaMinorMI10:
4289        df = DF[instr_.Bits(1, 0)];
4290        break;
4291      case kMsaMinorBIT:
4292        df = DF[instr_.MsaBitDf()];
4293        break;
4294      case kMsaMinorELM:
4295        df = DF[instr_.MsaElmDf()];
4296        break;
4297      case kMsaMinor3RF: {
4298        uint32_t opcode = instr_.InstructionBits() & kMsa3RFMask;
4299        switch (opcode) {
4300          case FEXDO:
4301          case FTQ:
4302          case MUL_Q:
4303          case MADD_Q:
4304          case MSUB_Q:
4305          case MULR_Q:
4306          case MADDR_Q:
4307          case MSUBR_Q:
4308            df = DF[1 + instr_.Bit(21)];
4309            break;
4310          default:
4311            df = DF[2 + instr_.Bit(21)];
4312            break;
4313        }
4314      } break;
4315      case kMsaMinor2R:
4316        df = DF[instr_.Bits(17, 16)];
4317        break;
4318      case kMsaMinor2RF:
4319        df = DF[2 + instr_.Bit(16)];
4320        break;
4321      default:
4322        UNREACHABLE();
4323    }
4324  }
4325  return df;
4326}
4327
4328void Simulator::DecodeTypeMsaI8() {
4329  DCHECK(IsMipsArchVariant(kMips32r6));
4330  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4331  uint32_t opcode = instr_.InstructionBits() & kMsaI8Mask;
4332  int8_t i8 = instr_.MsaImm8Value();
4333  msa_reg_t ws, wd;
4334
4335  switch (opcode) {
4336    case ANDI_B:
4337      get_msa_register(instr_.WsValue(), ws.b);
4338      for (int i = 0; i < kMSALanesByte; i++) {
4339        wd.b[i] = ws.b[i] & i8;
4340      }
4341      set_msa_register(instr_.WdValue(), wd.b);
4342      TraceMSARegWr(wd.b);
4343      break;
4344    case ORI_B:
4345      get_msa_register(instr_.WsValue(), ws.b);
4346      for (int i = 0; i < kMSALanesByte; i++) {
4347        wd.b[i] = ws.b[i] | i8;
4348      }
4349      set_msa_register(instr_.WdValue(), wd.b);
4350      TraceMSARegWr(wd.b);
4351      break;
4352    case NORI_B:
4353      get_msa_register(instr_.WsValue(), ws.b);
4354      for (int i = 0; i < kMSALanesByte; i++) {
4355        wd.b[i] = ~(ws.b[i] | i8);
4356      }
4357      set_msa_register(instr_.WdValue(), wd.b);
4358      TraceMSARegWr(wd.b);
4359      break;
4360    case XORI_B:
4361      get_msa_register(instr_.WsValue(), ws.b);
4362      for (int i = 0; i < kMSALanesByte; i++) {
4363        wd.b[i] = ws.b[i] ^ i8;
4364      }
4365      set_msa_register(instr_.WdValue(), wd.b);
4366      TraceMSARegWr(wd.b);
4367      break;
4368    case BMNZI_B:
4369      get_msa_register(instr_.WsValue(), ws.b);
4370      get_msa_register(instr_.WdValue(), wd.b);
4371      for (int i = 0; i < kMSALanesByte; i++) {
4372        wd.b[i] = (ws.b[i] & i8) | (wd.b[i] & ~i8);
4373      }
4374      set_msa_register(instr_.WdValue(), wd.b);
4375      TraceMSARegWr(wd.b);
4376      break;
4377    case BMZI_B:
4378      get_msa_register(instr_.WsValue(), ws.b);
4379      get_msa_register(instr_.WdValue(), wd.b);
4380      for (int i = 0; i < kMSALanesByte; i++) {
4381        wd.b[i] = (ws.b[i] & ~i8) | (wd.b[i] & i8);
4382      }
4383      set_msa_register(instr_.WdValue(), wd.b);
4384      TraceMSARegWr(wd.b);
4385      break;
4386    case BSELI_B:
4387      get_msa_register(instr_.WsValue(), ws.b);
4388      get_msa_register(instr_.WdValue(), wd.b);
4389      for (int i = 0; i < kMSALanesByte; i++) {
4390        wd.b[i] = (ws.b[i] & ~wd.b[i]) | (wd.b[i] & i8);
4391      }
4392      set_msa_register(instr_.WdValue(), wd.b);
4393      TraceMSARegWr(wd.b);
4394      break;
4395    case SHF_B:
4396      get_msa_register(instr_.WsValue(), ws.b);
4397      for (int i = 0; i < kMSALanesByte; i++) {
4398        int j = i % 4;
4399        int k = (i8 >> (2 * j)) & 0x3;
4400        wd.b[i] = ws.b[i - j + k];
4401      }
4402      set_msa_register(instr_.WdValue(), wd.b);
4403      TraceMSARegWr(wd.b);
4404      break;
4405    case SHF_H:
4406      get_msa_register(instr_.WsValue(), ws.h);
4407      for (int i = 0; i < kMSALanesHalf; i++) {
4408        int j = i % 4;
4409        int k = (i8 >> (2 * j)) & 0x3;
4410        wd.h[i] = ws.h[i - j + k];
4411      }
4412      set_msa_register(instr_.WdValue(), wd.h);
4413      TraceMSARegWr(wd.h);
4414      break;
4415    case SHF_W:
4416      get_msa_register(instr_.WsValue(), ws.w);
4417      for (int i = 0; i < kMSALanesWord; i++) {
4418        int j = (i8 >> (2 * i)) & 0x3;
4419        wd.w[i] = ws.w[j];
4420      }
4421      set_msa_register(instr_.WdValue(), wd.w);
4422      TraceMSARegWr(wd.w);
4423      break;
4424    default:
4425      UNREACHABLE();
4426  }
4427}
4428
4429template <typename T>
4430T Simulator::MsaI5InstrHelper(uint32_t opcode, T ws, int32_t i5) {
4431  T res;
4432  uint32_t ui5 = i5 & 0x1Fu;
4433  uint64_t ws_u64 = static_cast<uint64_t>(ws);
4434  uint64_t ui5_u64 = static_cast<uint64_t>(ui5);
4435
4436  switch (opcode) {
4437    case ADDVI:
4438      res = static_cast<T>(ws + ui5);
4439      break;
4440    case SUBVI:
4441      res = static_cast<T>(ws - ui5);
4442      break;
4443    case MAXI_S:
4444      res = static_cast<T>(std::max(ws, static_cast<T>(i5)));
4445      break;
4446    case MINI_S:
4447      res = static_cast<T>(std::min(ws, static_cast<T>(i5)));
4448      break;
4449    case MAXI_U:
4450      res = static_cast<T>(std::max(ws_u64, ui5_u64));
4451      break;
4452    case MINI_U:
4453      res = static_cast<T>(std::min(ws_u64, ui5_u64));
4454      break;
4455    case CEQI:
4456      res = static_cast<T>(!Compare(ws, static_cast<T>(i5)) ? -1ull : 0ull);
4457      break;
4458    case CLTI_S:
4459      res = static_cast<T>((Compare(ws, static_cast<T>(i5)) == -1) ? -1ull
4460                                                                   : 0ull);
4461      break;
4462    case CLTI_U:
4463      res = static_cast<T>((Compare(ws_u64, ui5_u64) == -1) ? -1ull : 0ull);
4464      break;
4465    case CLEI_S:
4466      res =
4467          static_cast<T>((Compare(ws, static_cast<T>(i5)) != 1) ? -1ull : 0ull);
4468      break;
4469    case CLEI_U:
4470      res = static_cast<T>((Compare(ws_u64, ui5_u64) != 1) ? -1ull : 0ull);
4471      break;
4472    default:
4473      UNREACHABLE();
4474  }
4475  return res;
4476}
4477
4478void Simulator::DecodeTypeMsaI5() {
4479  DCHECK(IsMipsArchVariant(kMips32r6));
4480  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4481  uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask;
4482  msa_reg_t ws, wd;
4483
4484  // sign extend 5bit value to int32_t
4485  int32_t i5 = static_cast<int32_t>(instr_.MsaImm5Value() << 27) >> 27;
4486
4487#define MSA_I5_DF(elem, num_of_lanes)                      \
4488  get_msa_register(instr_.WsValue(), ws.elem);             \
4489  for (int i = 0; i < num_of_lanes; i++) {                 \
4490    wd.elem[i] = MsaI5InstrHelper(opcode, ws.elem[i], i5); \
4491  }                                                        \
4492  set_msa_register(instr_.WdValue(), wd.elem);             \
4493  TraceMSARegWr(wd.elem)
4494
4495  switch (DecodeMsaDataFormat()) {
4496    case MSA_BYTE:
4497      MSA_I5_DF(b, kMSALanesByte);
4498      break;
4499    case MSA_HALF:
4500      MSA_I5_DF(h, kMSALanesHalf);
4501      break;
4502    case MSA_WORD:
4503      MSA_I5_DF(w, kMSALanesWord);
4504      break;
4505    case MSA_DWORD:
4506      MSA_I5_DF(d, kMSALanesDword);
4507      break;
4508    default:
4509      UNREACHABLE();
4510  }
4511#undef MSA_I5_DF
4512}
4513
4514void Simulator::DecodeTypeMsaI10() {
4515  DCHECK(IsMipsArchVariant(kMips32r6));
4516  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4517  uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask;
4518  int64_t s10 = (static_cast<int64_t>(instr_.MsaImm10Value()) << 54) >> 54;
4519  msa_reg_t wd;
4520
4521#define MSA_I10_DF(elem, num_of_lanes, T)      \
4522  for (int i = 0; i < num_of_lanes; ++i) {     \
4523    wd.elem[i] = static_cast<T>(s10);          \
4524  }                                            \
4525  set_msa_register(instr_.WdValue(), wd.elem); \
4526  TraceMSARegWr(wd.elem)
4527
4528  if (opcode == LDI) {
4529    switch (DecodeMsaDataFormat()) {
4530      case MSA_BYTE:
4531        MSA_I10_DF(b, kMSALanesByte, int8_t);
4532        break;
4533      case MSA_HALF:
4534        MSA_I10_DF(h, kMSALanesHalf, int16_t);
4535        break;
4536      case MSA_WORD:
4537        MSA_I10_DF(w, kMSALanesWord, int32_t);
4538        break;
4539      case MSA_DWORD:
4540        MSA_I10_DF(d, kMSALanesDword, int64_t);
4541        break;
4542      default:
4543        UNREACHABLE();
4544    }
4545  } else {
4546    UNREACHABLE();
4547  }
4548#undef MSA_I10_DF
4549}
4550
4551void Simulator::DecodeTypeMsaELM() {
4552  DCHECK(IsMipsArchVariant(kMips32r6));
4553  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4554  uint32_t opcode = instr_.InstructionBits() & kMsaLongerELMMask;
4555  int32_t n = instr_.MsaElmNValue();
4556  int32_t alu_out;
4557  switch (opcode) {
4558    case CTCMSA:
4559      DCHECK_EQ(sa(), kMSACSRRegister);
4560      MSACSR_ = bit_cast<uint32_t>(registers_[rd_reg()]);
4561      TraceRegWr(static_cast<int32_t>(MSACSR_));
4562      break;
4563    case CFCMSA:
4564      DCHECK_EQ(rd_reg(), kMSACSRRegister);
4565      SetResult(sa(), bit_cast<int32_t>(MSACSR_));
4566      break;
4567    case MOVE_V: {
4568      msa_reg_t ws;
4569      get_msa_register(ws_reg(), &ws);
4570      set_msa_register(wd_reg(), &ws);
4571      TraceMSARegWr(&ws);
4572    } break;
4573    default:
4574      opcode &= kMsaELMMask;
4575      switch (opcode) {
4576        case COPY_S:
4577        case COPY_U: {
4578          msa_reg_t ws;
4579          switch (DecodeMsaDataFormat()) {
4580            case MSA_BYTE: {
4581              DCHECK_LT(n, kMSALanesByte);
4582              get_msa_register(instr_.WsValue(), ws.b);
4583              alu_out = static_cast<int32_t>(ws.b[n]);
4584              SetResult(wd_reg(),
4585                        (opcode == COPY_U) ? alu_out & 0xFFu : alu_out);
4586              break;
4587            }
4588            case MSA_HALF: {
4589              DCHECK_LT(n, kMSALanesHalf);
4590              get_msa_register(instr_.WsValue(), ws.h);
4591              alu_out = static_cast<int32_t>(ws.h[n]);
4592              SetResult(wd_reg(),
4593                        (opcode == COPY_U) ? alu_out & 0xFFFFu : alu_out);
4594              break;
4595            }
4596            case MSA_WORD: {
4597              DCHECK_LT(n, kMSALanesWord);
4598              get_msa_register(instr_.WsValue(), ws.w);
4599              alu_out = static_cast<int32_t>(ws.w[n]);
4600              SetResult(wd_reg(), alu_out);
4601              break;
4602            }
4603            default:
4604              UNREACHABLE();
4605          }
4606        } break;
4607        case INSERT: {
4608          msa_reg_t wd;
4609          switch (DecodeMsaDataFormat()) {
4610            case MSA_BYTE: {
4611              DCHECK_LT(n, kMSALanesByte);
4612              int32_t rs = get_register(instr_.WsValue());
4613              get_msa_register(instr_.WdValue(), wd.b);
4614              wd.b[n] = rs & 0xFFu;
4615              set_msa_register(instr_.WdValue(), wd.b);
4616              TraceMSARegWr(wd.b);
4617              break;
4618            }
4619            case MSA_HALF: {
4620              DCHECK_LT(n, kMSALanesHalf);
4621              int32_t rs = get_register(instr_.WsValue());
4622              get_msa_register(instr_.WdValue(), wd.h);
4623              wd.h[n] = rs & 0xFFFFu;
4624              set_msa_register(instr_.WdValue(), wd.h);
4625              TraceMSARegWr(wd.h);
4626              break;
4627            }
4628            case MSA_WORD: {
4629              DCHECK_LT(n, kMSALanesWord);
4630              int32_t rs = get_register(instr_.WsValue());
4631              get_msa_register(instr_.WdValue(), wd.w);
4632              wd.w[n] = rs;
4633              set_msa_register(instr_.WdValue(), wd.w);
4634              TraceMSARegWr(wd.w);
4635              break;
4636            }
4637            default:
4638              UNREACHABLE();
4639          }
4640        } break;
4641        case SLDI: {
4642          uint8_t v[32];
4643          msa_reg_t ws;
4644          msa_reg_t wd;
4645          get_msa_register(ws_reg(), &ws);
4646          get_msa_register(wd_reg(), &wd);
4647#define SLDI_DF(s, k)                \
4648  for (unsigned i = 0; i < s; i++) { \
4649    v[i] = ws.b[s * k + i];          \
4650    v[i + s] = wd.b[s * k + i];      \
4651  }                                  \
4652  for (unsigned i = 0; i < s; i++) { \
4653    wd.b[s * k + i] = v[i + n];      \
4654  }
4655          switch (DecodeMsaDataFormat()) {
4656            case MSA_BYTE:
4657              DCHECK(n < kMSALanesByte);
4658              SLDI_DF(kMSARegSize / sizeof(int8_t) / kBitsPerByte, 0)
4659              break;
4660            case MSA_HALF:
4661              DCHECK(n < kMSALanesHalf);
4662              for (int k = 0; k < 2; ++k) {
4663                SLDI_DF(kMSARegSize / sizeof(int16_t) / kBitsPerByte, k)
4664              }
4665              break;
4666            case MSA_WORD:
4667              DCHECK(n < kMSALanesWord);
4668              for (int k = 0; k < 4; ++k) {
4669                SLDI_DF(kMSARegSize / sizeof(int32_t) / kBitsPerByte, k)
4670              }
4671              break;
4672            case MSA_DWORD:
4673              DCHECK(n < kMSALanesDword);
4674              for (int k = 0; k < 8; ++k) {
4675                SLDI_DF(kMSARegSize / sizeof(int64_t) / kBitsPerByte, k)
4676              }
4677              break;
4678            default:
4679              UNREACHABLE();
4680          }
4681          set_msa_register(wd_reg(), &wd);
4682          TraceMSARegWr(&wd);
4683        } break;
4684#undef SLDI_DF
4685        case SPLATI:
4686        case INSVE:
4687          UNIMPLEMENTED();
4688        default:
4689          UNREACHABLE();
4690      }
4691      break;
4692  }
4693}
4694
4695template <typename T>
4696T Simulator::MsaBitInstrHelper(uint32_t opcode, T wd, T ws, int32_t m) {
4697  using uT = typename std::make_unsigned<T>::type;
4698  T res;
4699  switch (opcode) {
4700    case SLLI:
4701      res = static_cast<T>(ws << m);
4702      break;
4703    case SRAI:
4704      res = static_cast<T>(ArithmeticShiftRight(ws, m));
4705      break;
4706    case SRLI:
4707      res = static_cast<T>(static_cast<uT>(ws) >> m);
4708      break;
4709    case BCLRI:
4710      res = static_cast<T>(static_cast<T>(~(1ull << m)) & ws);
4711      break;
4712    case BSETI:
4713      res = static_cast<T>(static_cast<T>(1ull << m) | ws);
4714      break;
4715    case BNEGI:
4716      res = static_cast<T>(static_cast<T>(1ull << m) ^ ws);
4717      break;
4718    case BINSLI: {
4719      int elem_size = 8 * sizeof(T);
4720      int bits = m + 1;
4721      if (bits == elem_size) {
4722        res = static_cast<T>(ws);
4723      } else {
4724        uint64_t mask = ((1ull << bits) - 1) << (elem_size - bits);
4725        res = static_cast<T>((static_cast<T>(mask) & ws) |
4726                             (static_cast<T>(~mask) & wd));
4727      }
4728    } break;
4729    case BINSRI: {
4730      int elem_size = 8 * sizeof(T);
4731      int bits = m + 1;
4732      if (bits == elem_size) {
4733        res = static_cast<T>(ws);
4734      } else {
4735        uint64_t mask = (1ull << bits) - 1;
4736        res = static_cast<T>((static_cast<T>(mask) & ws) |
4737                             (static_cast<T>(~mask) & wd));
4738      }
4739    } break;
4740    case SAT_S: {
4741#define M_MAX_INT(x) static_cast<int64_t>((1LL << ((x)-1)) - 1)
4742#define M_MIN_INT(x) static_cast<int64_t>(-(1LL << ((x)-1)))
4743      int shift = 64 - 8 * sizeof(T);
4744      int64_t ws_i64 = (static_cast<int64_t>(ws) << shift) >> shift;
4745      res = static_cast<T>(ws_i64 < M_MIN_INT(m + 1)
4746                               ? M_MIN_INT(m + 1)
4747                               : ws_i64 > M_MAX_INT(m + 1) ? M_MAX_INT(m + 1)
4748                                                           : ws_i64);
4749#undef M_MAX_INT
4750#undef M_MIN_INT
4751    } break;
4752    case SAT_U: {
4753#define M_MAX_UINT(x) static_cast<uint64_t>(-1ULL >> (64 - (x)))
4754      uint64_t mask = static_cast<uint64_t>(-1ULL >> (64 - 8 * sizeof(T)));
4755      uint64_t ws_u64 = static_cast<uint64_t>(ws) & mask;
4756      res = static_cast<T>(ws_u64 < M_MAX_UINT(m + 1) ? ws_u64
4757                                                      : M_MAX_UINT(m + 1));
4758#undef M_MAX_UINT
4759    } break;
4760    case SRARI:
4761      if (!m) {
4762        res = static_cast<T>(ws);
4763      } else {
4764        res = static_cast<T>(ArithmeticShiftRight(ws, m)) +
4765              static_cast<T>((ws >> (m - 1)) & 0x1);
4766      }
4767      break;
4768    case SRLRI:
4769      if (!m) {
4770        res = static_cast<T>(ws);
4771      } else {
4772        res = static_cast<T>(static_cast<uT>(ws) >> m) +
4773              static_cast<T>((ws >> (m - 1)) & 0x1);
4774      }
4775      break;
4776    default:
4777      UNREACHABLE();
4778  }
4779  return res;
4780}
4781
4782void Simulator::DecodeTypeMsaBIT() {
4783  DCHECK(IsMipsArchVariant(kMips32r6));
4784  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4785  uint32_t opcode = instr_.InstructionBits() & kMsaBITMask;
4786  int32_t m = instr_.MsaBitMValue();
4787  msa_reg_t wd, ws;
4788
4789#define MSA_BIT_DF(elem, num_of_lanes)                                 \
4790  get_msa_register(instr_.WsValue(), ws.elem);                         \
4791  if (opcode == BINSLI || opcode == BINSRI) {                          \
4792    get_msa_register(instr_.WdValue(), wd.elem);                       \
4793  }                                                                    \
4794  for (int i = 0; i < num_of_lanes; i++) {                             \
4795    wd.elem[i] = MsaBitInstrHelper(opcode, wd.elem[i], ws.elem[i], m); \
4796  }                                                                    \
4797  set_msa_register(instr_.WdValue(), wd.elem);                         \
4798  TraceMSARegWr(wd.elem)
4799
4800  switch (DecodeMsaDataFormat()) {
4801    case MSA_BYTE:
4802      DCHECK(m < kMSARegSize / kMSALanesByte);
4803      MSA_BIT_DF(b, kMSALanesByte);
4804      break;
4805    case MSA_HALF:
4806      DCHECK(m < kMSARegSize / kMSALanesHalf);
4807      MSA_BIT_DF(h, kMSALanesHalf);
4808      break;
4809    case MSA_WORD:
4810      DCHECK(m < kMSARegSize / kMSALanesWord);
4811      MSA_BIT_DF(w, kMSALanesWord);
4812      break;
4813    case MSA_DWORD:
4814      DCHECK(m < kMSARegSize / kMSALanesDword);
4815      MSA_BIT_DF(d, kMSALanesDword);
4816      break;
4817    default:
4818      UNREACHABLE();
4819  }
4820#undef MSA_BIT_DF
4821}
4822
4823void Simulator::DecodeTypeMsaMI10() {
4824  DCHECK(IsMipsArchVariant(kMips32r6));
4825  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
4826  uint32_t opcode = instr_.InstructionBits() & kMsaMI10Mask;
4827  int32_t s10 = (static_cast<int32_t>(instr_.MsaImmMI10Value()) << 22) >> 22;
4828  int32_t rs = get_register(instr_.WsValue());
4829  int32_t addr;
4830  msa_reg_t wd;
4831
4832#define MSA_MI10_LOAD(elem, num_of_lanes, T)       \
4833  for (int i = 0; i < num_of_lanes; ++i) {         \
4834    addr = rs + (s10 + i) * sizeof(T);             \
4835    wd.elem[i] = ReadMem<T>(addr, instr_.instr()); \
4836  }                                                \
4837  set_msa_register(instr_.WdValue(), wd.elem);
4838
4839#define MSA_MI10_STORE(elem, num_of_lanes, T)      \
4840  get_msa_register(instr_.WdValue(), wd.elem);     \
4841  for (int i = 0; i < num_of_lanes; ++i) {         \
4842    addr = rs + (s10 + i) * sizeof(T);             \
4843    WriteMem<T>(addr, wd.elem[i], instr_.instr()); \
4844  }
4845
4846  if (opcode == MSA_LD) {
4847    switch (DecodeMsaDataFormat()) {
4848      case MSA_BYTE:
4849        MSA_MI10_LOAD(b, kMSALanesByte, int8_t);
4850        break;
4851      case MSA_HALF:
4852        MSA_MI10_LOAD(h, kMSALanesHalf, int16_t);
4853        break;
4854      case MSA_WORD:
4855        MSA_MI10_LOAD(w, kMSALanesWord, int32_t);
4856        break;
4857      case MSA_DWORD:
4858        MSA_MI10_LOAD(d, kMSALanesDword, int64_t);
4859        break;
4860      default:
4861        UNREACHABLE();
4862    }
4863  } else if (opcode == MSA_ST) {
4864    switch (DecodeMsaDataFormat()) {
4865      case MSA_BYTE:
4866        MSA_MI10_STORE(b, kMSALanesByte, int8_t);
4867        break;
4868      case MSA_HALF:
4869        MSA_MI10_STORE(h, kMSALanesHalf, int16_t);
4870        break;
4871      case MSA_WORD:
4872        MSA_MI10_STORE(w, kMSALanesWord, int32_t);
4873        break;
4874      case MSA_DWORD:
4875        MSA_MI10_STORE(d, kMSALanesDword, int64_t);
4876        break;
4877      default:
4878        UNREACHABLE();
4879    }
4880  } else {
4881    UNREACHABLE();
4882  }
4883
4884#undef MSA_MI10_LOAD
4885#undef MSA_MI10_STORE
4886}
4887
4888template <typename T>
4889T Simulator::Msa3RInstrHelper(uint32_t opcode, T wd, T ws, T wt) {
4890  using uT = typename std::make_unsigned<T>::type;
4891  T res;
4892  T wt_modulo = wt % (sizeof(T) * 8);
4893  switch (opcode) {
4894    case SLL_MSA:
4895      res = static_cast<T>(ws << wt_modulo);
4896      break;
4897    case SRA_MSA:
4898      res = static_cast<T>(ArithmeticShiftRight(ws, wt_modulo));
4899      break;
4900    case SRL_MSA:
4901      res = static_cast<T>(static_cast<uT>(ws) >> wt_modulo);
4902      break;
4903    case BCLR:
4904      res = static_cast<T>(static_cast<T>(~(1ull << wt_modulo)) & ws);
4905      break;
4906    case BSET:
4907      res = static_cast<T>(static_cast<T>(1ull << wt_modulo) | ws);
4908      break;
4909    case BNEG:
4910      res = static_cast<T>(static_cast<T>(1ull << wt_modulo) ^ ws);
4911      break;
4912    case BINSL: {
4913      int elem_size = 8 * sizeof(T);
4914      int bits = wt_modulo + 1;
4915      if (bits == elem_size) {
4916        res = static_cast<T>(ws);
4917      } else {
4918        uint64_t mask = ((1ull << bits) - 1) << (elem_size - bits);
4919        res = static_cast<T>((static_cast<T>(mask) & ws) |
4920                             (static_cast<T>(~mask) & wd));
4921      }
4922    } break;
4923    case BINSR: {
4924      int elem_size = 8 * sizeof(T);
4925      int bits = wt_modulo + 1;
4926      if (bits == elem_size) {
4927        res = static_cast<T>(ws);
4928      } else {
4929        uint64_t mask = (1ull << bits) - 1;
4930        res = static_cast<T>((static_cast<T>(mask) & ws) |
4931                             (static_cast<T>(~mask) & wd));
4932      }
4933    } break;
4934    case ADDV:
4935      res = ws + wt;
4936      break;
4937    case SUBV:
4938      res = ws - wt;
4939      break;
4940    case MAX_S:
4941      res = std::max(ws, wt);
4942      break;
4943    case MAX_U:
4944      res = static_cast<T>(std::max(static_cast<uT>(ws), static_cast<uT>(wt)));
4945      break;
4946    case MIN_S:
4947      res = std::min(ws, wt);
4948      break;
4949    case MIN_U:
4950      res = static_cast<T>(std::min(static_cast<uT>(ws), static_cast<uT>(wt)));
4951      break;
4952    case MAX_A:
4953      // We use negative abs in order to avoid problems
4954      // with corner case for MIN_INT
4955      res = Nabs(ws) < Nabs(wt) ? ws : wt;
4956      break;
4957    case MIN_A:
4958      // We use negative abs in order to avoid problems
4959      // with corner case for MIN_INT
4960      res = Nabs(ws) > Nabs(wt) ? ws : wt;
4961      break;
4962    case CEQ:
4963      res = static_cast<T>(!Compare(ws, wt) ? -1ull : 0ull);
4964      break;
4965    case CLT_S:
4966      res = static_cast<T>((Compare(ws, wt) == -1) ? -1ull : 0ull);
4967      break;
4968    case CLT_U:
4969      res = static_cast<T>(
4970          (Compare(static_cast<uT>(ws), static_cast<uT>(wt)) == -1) ? -1ull
4971                                                                    : 0ull);
4972      break;
4973    case CLE_S:
4974      res = static_cast<T>((Compare(ws, wt) != 1) ? -1ull : 0ull);
4975      break;
4976    case CLE_U:
4977      res = static_cast<T>(
4978          (Compare(static_cast<uT>(ws), static_cast<uT>(wt)) != 1) ? -1ull
4979                                                                   : 0ull);
4980      break;
4981    case ADD_A:
4982      res = static_cast<T>(Abs(ws) + Abs(wt));
4983      break;
4984    case ADDS_A: {
4985      T ws_nabs = Nabs(ws);
4986      T wt_nabs = Nabs(wt);
4987      if (ws_nabs < -std::numeric_limits<T>::max() - wt_nabs) {
4988        res = std::numeric_limits<T>::max();
4989      } else {
4990        res = -(ws_nabs + wt_nabs);
4991      }
4992    } break;
4993    case ADDS_S:
4994      res = SaturateAdd(ws, wt);
4995      break;
4996    case ADDS_U: {
4997      uT ws_u = static_cast<uT>(ws);
4998      uT wt_u = static_cast<uT>(wt);
4999      res = static_cast<T>(SaturateAdd(ws_u, wt_u));
5000    } break;
5001    case AVE_S:
5002      res = static_cast<T>((wt & ws) + ((wt ^ ws) >> 1));
5003      break;
5004    case AVE_U: {
5005      uT ws_u = static_cast<uT>(ws);
5006      uT wt_u = static_cast<uT>(wt);
5007      res = static_cast<T>((wt_u & ws_u) + ((wt_u ^ ws_u) >> 1));
5008    } break;
5009    case AVER_S:
5010      res = static_cast<T>((wt | ws) - ((wt ^ ws) >> 1));
5011      break;
5012    case AVER_U: {
5013      uT ws_u = static_cast<uT>(ws);
5014      uT wt_u = static_cast<uT>(wt);
5015      res = static_cast<T>((wt_u | ws_u) - ((wt_u ^ ws_u) >> 1));
5016    } break;
5017    case SUBS_S:
5018      res = SaturateSub(ws, wt);
5019      break;
5020    case SUBS_U: {
5021      uT ws_u = static_cast<uT>(ws);
5022      uT wt_u = static_cast<uT>(wt);
5023      res = static_cast<T>(SaturateSub(ws_u, wt_u));
5024    } break;
5025    case SUBSUS_U: {
5026      uT wsu = static_cast<uT>(ws);
5027      if (wt > 0) {
5028        uT wtu = static_cast<uT>(wt);
5029        if (wtu > wsu) {
5030          res = 0;
5031        } else {
5032          res = static_cast<T>(wsu - wtu);
5033        }
5034      } else {
5035        if (wsu > std::numeric_limits<uT>::max() + wt) {
5036          res = static_cast<T>(std::numeric_limits<uT>::max());
5037        } else {
5038          res = static_cast<T>(wsu - wt);
5039        }
5040      }
5041    } break;
5042    case SUBSUU_S: {
5043      uT wsu = static_cast<uT>(ws);
5044      uT wtu = static_cast<uT>(wt);
5045      uT wdu;
5046      if (wsu > wtu) {
5047        wdu = wsu - wtu;
5048        if (wdu > std::numeric_limits<T>::max()) {
5049          res = std::numeric_limits<T>::max();
5050        } else {
5051          res = static_cast<T>(wdu);
5052        }
5053      } else {
5054        wdu = wtu - wsu;
5055        CHECK(-std::numeric_limits<T>::max() ==
5056              std::numeric_limits<T>::min() + 1);
5057        if (wdu <= std::numeric_limits<T>::max()) {
5058          res = -static_cast<T>(wdu);
5059        } else {
5060          res = std::numeric_limits<T>::min();
5061        }
5062      }
5063    } break;
5064    case ASUB_S:
5065      res = static_cast<T>(Abs(ws - wt));
5066      break;
5067    case ASUB_U: {
5068      uT wsu = static_cast<uT>(ws);
5069      uT wtu = static_cast<uT>(wt);
5070      res = static_cast<T>(wsu > wtu ? wsu - wtu : wtu - wsu);
5071    } break;
5072    case MULV:
5073      res = ws * wt;
5074      break;
5075    case MADDV:
5076      res = wd + ws * wt;
5077      break;
5078    case MSUBV:
5079      res = wd - ws * wt;
5080      break;
5081    case DIV_S_MSA:
5082      res = wt != 0 ? ws / wt : static_cast<T>(Unpredictable);
5083      break;
5084    case DIV_U:
5085      res = wt != 0 ? static_cast<T>(static_cast<uT>(ws) / static_cast<uT>(wt))
5086                    : static_cast<T>(Unpredictable);
5087      break;
5088    case MOD_S:
5089      res = wt != 0 ? ws % wt : static_cast<T>(Unpredictable);
5090      break;
5091    case MOD_U:
5092      res = wt != 0 ? static_cast<T>(static_cast<uT>(ws) % static_cast<uT>(wt))
5093                    : static_cast<T>(Unpredictable);
5094      break;
5095    case DOTP_S:
5096    case DOTP_U:
5097    case DPADD_S:
5098    case DPADD_U:
5099    case DPSUB_S:
5100    case DPSUB_U:
5101    case SLD:
5102    case SPLAT:
5103      UNIMPLEMENTED();
5104      break;
5105    case SRAR: {
5106      int bit = wt_modulo == 0 ? 0 : (ws >> (wt_modulo - 1)) & 1;
5107      res = static_cast<T>(ArithmeticShiftRight(ws, wt_modulo) + bit);
5108    } break;
5109    case SRLR: {
5110      uT wsu = static_cast<uT>(ws);
5111      int bit = wt_modulo == 0 ? 0 : (wsu >> (wt_modulo - 1)) & 1;
5112      res = static_cast<T>((wsu >> wt_modulo) + bit);
5113    } break;
5114    default:
5115      UNREACHABLE();
5116  }
5117  return res;
5118}
5119
5120template <typename T_int, typename T_reg>
5121void Msa3RInstrHelper_shuffle(const uint32_t opcode, T_reg ws, T_reg wt,
5122                              T_reg wd, const int i, const int num_of_lanes) {
5123  T_int *ws_p, *wt_p, *wd_p;
5124  ws_p = reinterpret_cast<T_int*>(ws);
5125  wt_p = reinterpret_cast<T_int*>(wt);
5126  wd_p = reinterpret_cast<T_int*>(wd);
5127  switch (opcode) {
5128    case PCKEV:
5129      wd_p[i] = wt_p[2 * i];
5130      wd_p[i + num_of_lanes / 2] = ws_p[2 * i];
5131      break;
5132    case PCKOD:
5133      wd_p[i] = wt_p[2 * i + 1];
5134      wd_p[i + num_of_lanes / 2] = ws_p[2 * i + 1];
5135      break;
5136    case ILVL:
5137      wd_p[2 * i] = wt_p[i + num_of_lanes / 2];
5138      wd_p[2 * i + 1] = ws_p[i + num_of_lanes / 2];
5139      break;
5140    case ILVR:
5141      wd_p[2 * i] = wt_p[i];
5142      wd_p[2 * i + 1] = ws_p[i];
5143      break;
5144    case ILVEV:
5145      wd_p[2 * i] = wt_p[2 * i];
5146      wd_p[2 * i + 1] = ws_p[2 * i];
5147      break;
5148    case ILVOD:
5149      wd_p[2 * i] = wt_p[2 * i + 1];
5150      wd_p[2 * i + 1] = ws_p[2 * i + 1];
5151      break;
5152    case VSHF: {
5153      const int mask_not_valid = 0xC0;
5154      const int mask_6_bits = 0x3F;
5155      if ((wd_p[i] & mask_not_valid)) {
5156        wd_p[i] = 0;
5157      } else {
5158        int k = (wd_p[i] & mask_6_bits) % (num_of_lanes * 2);
5159        wd_p[i] = k >= num_of_lanes ? ws_p[k - num_of_lanes] : wt_p[k];
5160      }
5161    } break;
5162    default:
5163      UNREACHABLE();
5164  }
5165}
5166
5167template <typename T_int, typename T_smaller_int, typename T_reg>
5168void Msa3RInstrHelper_horizontal(const uint32_t opcode, T_reg ws, T_reg wt,
5169                                 T_reg wd, const int i,
5170                                 const int num_of_lanes) {
5171  using T_uint = typename std::make_unsigned<T_int>::type;
5172  using T_smaller_uint = typename std::make_unsigned<T_smaller_int>::type;
5173  T_int* wd_p;
5174  T_smaller_int *ws_p, *wt_p;
5175  ws_p = reinterpret_cast<T_smaller_int*>(ws);
5176  wt_p = reinterpret_cast<T_smaller_int*>(wt);
5177  wd_p = reinterpret_cast<T_int*>(wd);
5178  T_uint* wd_pu;
5179  T_smaller_uint *ws_pu, *wt_pu;
5180  ws_pu = reinterpret_cast<T_smaller_uint*>(ws);
5181  wt_pu = reinterpret_cast<T_smaller_uint*>(wt);
5182  wd_pu = reinterpret_cast<T_uint*>(wd);
5183  switch (opcode) {
5184    case HADD_S:
5185      wd_p[i] =
5186          static_cast<T_int>(ws_p[2 * i + 1]) + static_cast<T_int>(wt_p[2 * i]);
5187      break;
5188    case HADD_U:
5189      wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) +
5190                 static_cast<T_uint>(wt_pu[2 * i]);
5191      break;
5192    case HSUB_S:
5193      wd_p[i] =
5194          static_cast<T_int>(ws_p[2 * i + 1]) - static_cast<T_int>(wt_p[2 * i]);
5195      break;
5196    case HSUB_U:
5197      wd_pu[i] = static_cast<T_uint>(ws_pu[2 * i + 1]) -
5198                 static_cast<T_uint>(wt_pu[2 * i]);
5199      break;
5200    default:
5201      UNREACHABLE();
5202  }
5203}
5204
5205void Simulator::DecodeTypeMsa3R() {
5206  DCHECK(IsMipsArchVariant(kMips32r6));
5207  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
5208  uint32_t opcode = instr_.InstructionBits() & kMsa3RMask;
5209  msa_reg_t ws, wd, wt;
5210  get_msa_register(ws_reg(), &ws);
5211  get_msa_register(wt_reg(), &wt);
5212  get_msa_register(wd_reg(), &wd);
5213  switch (opcode) {
5214    case HADD_S:
5215    case HADD_U:
5216    case HSUB_S:
5217    case HSUB_U:
5218#define HORIZONTAL_ARITHMETIC_DF(num_of_lanes, int_type, lesser_int_type) \
5219  for (int i = 0; i < num_of_lanes; ++i) {                                \
5220    Msa3RInstrHelper_horizontal<int_type, lesser_int_type>(               \
5221        opcode, &ws, &wt, &wd, i, num_of_lanes);                          \
5222  }
5223      switch (DecodeMsaDataFormat()) {
5224        case MSA_HALF:
5225          HORIZONTAL_ARITHMETIC_DF(kMSALanesHalf, int16_t, int8_t);
5226          break;
5227        case MSA_WORD:
5228          HORIZONTAL_ARITHMETIC_DF(kMSALanesWord, int32_t, int16_t);
5229          break;
5230        case MSA_DWORD:
5231          HORIZONTAL_ARITHMETIC_DF(kMSALanesDword, int64_t, int32_t);
5232          break;
5233        default:
5234          UNREACHABLE();
5235      }
5236      break;
5237#undef HORIZONTAL_ARITHMETIC_DF
5238    case VSHF:
5239#define VSHF_DF(num_of_lanes, int_type)                          \
5240  for (int i = 0; i < num_of_lanes; ++i) {                       \
5241    Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \
5242                                       num_of_lanes);            \
5243  }
5244      switch (DecodeMsaDataFormat()) {
5245        case MSA_BYTE:
5246          VSHF_DF(kMSALanesByte, int8_t);
5247          break;
5248        case MSA_HALF:
5249          VSHF_DF(kMSALanesHalf, int16_t);
5250          break;
5251        case MSA_WORD:
5252          VSHF_DF(kMSALanesWord, int32_t);
5253          break;
5254        case MSA_DWORD:
5255          VSHF_DF(kMSALanesDword, int64_t);
5256          break;
5257        default:
5258          UNREACHABLE();
5259      }
5260#undef VSHF_DF
5261      break;
5262    case PCKEV:
5263    case PCKOD:
5264    case ILVL:
5265    case ILVR:
5266    case ILVEV:
5267    case ILVOD:
5268#define INTERLEAVE_PACK_DF(num_of_lanes, int_type)               \
5269  for (int i = 0; i < num_of_lanes / 2; ++i) {                   \
5270    Msa3RInstrHelper_shuffle<int_type>(opcode, &ws, &wt, &wd, i, \
5271                                       num_of_lanes);            \
5272  }
5273      switch (DecodeMsaDataFormat()) {
5274        case MSA_BYTE:
5275          INTERLEAVE_PACK_DF(kMSALanesByte, int8_t);
5276          break;
5277        case MSA_HALF:
5278          INTERLEAVE_PACK_DF(kMSALanesHalf, int16_t);
5279          break;
5280        case MSA_WORD:
5281          INTERLEAVE_PACK_DF(kMSALanesWord, int32_t);
5282          break;
5283        case MSA_DWORD:
5284          INTERLEAVE_PACK_DF(kMSALanesDword, int64_t);
5285          break;
5286        default:
5287          UNREACHABLE();
5288      }
5289      break;
5290#undef INTERLEAVE_PACK_DF
5291    default:
5292#define MSA_3R_DF(elem, num_of_lanes)                                          \
5293  for (int i = 0; i < num_of_lanes; i++) {                                     \
5294    wd.elem[i] = Msa3RInstrHelper(opcode, wd.elem[i], ws.elem[i], wt.elem[i]); \
5295  }
5296
5297      switch (DecodeMsaDataFormat()) {
5298        case MSA_BYTE:
5299          MSA_3R_DF(b, kMSALanesByte);
5300          break;
5301        case MSA_HALF:
5302          MSA_3R_DF(h, kMSALanesHalf);
5303          break;
5304        case MSA_WORD:
5305          MSA_3R_DF(w, kMSALanesWord);
5306          break;
5307        case MSA_DWORD:
5308          MSA_3R_DF(d, kMSALanesDword);
5309          break;
5310        default:
5311          UNREACHABLE();
5312      }
5313#undef MSA_3R_DF
5314      break;
5315  }
5316  set_msa_register(wd_reg(), &wd);
5317  TraceMSARegWr(&wd);
5318}
5319
5320template <typename T_int, typename T_fp, typename T_reg>
5321void Msa3RFInstrHelper(uint32_t opcode, T_reg ws, T_reg wt, T_reg* wd) {
5322  const T_int all_ones = static_cast<T_int>(-1);
5323  const T_fp s_element = *reinterpret_cast<T_fp*>(&ws);
5324  const T_fp t_element = *reinterpret_cast<T_fp*>(&wt);
5325  switch (opcode) {
5326    case FCUN: {
5327      if (std::isnan(s_element) || std::isnan(t_element)) {
5328        *wd = all_ones;
5329      } else {
5330        *wd = 0;
5331      }
5332    } break;
5333    case FCEQ: {
5334      if (s_element != t_element || std::isnan(s_element) ||
5335          std::isnan(t_element)) {
5336        *wd = 0;
5337      } else {
5338        *wd = all_ones;
5339      }
5340    } break;
5341    case FCUEQ: {
5342      if (s_element == t_element || std::isnan(s_element) ||
5343          std::isnan(t_element)) {
5344        *wd = all_ones;
5345      } else {
5346        *wd = 0;
5347      }
5348    } break;
5349    case FCLT: {
5350      if (s_element >= t_element || std::isnan(s_element) ||
5351          std::isnan(t_element)) {
5352        *wd = 0;
5353      } else {
5354        *wd = all_ones;
5355      }
5356    } break;
5357    case FCULT: {
5358      if (s_element < t_element || std::isnan(s_element) ||
5359          std::isnan(t_element)) {
5360        *wd = all_ones;
5361      } else {
5362        *wd = 0;
5363      }
5364    } break;
5365    case FCLE: {
5366      if (s_element > t_element || std::isnan(s_element) ||
5367          std::isnan(t_element)) {
5368        *wd = 0;
5369      } else {
5370        *wd = all_ones;
5371      }
5372    } break;
5373    case FCULE: {
5374      if (s_element <= t_element || std::isnan(s_element) ||
5375          std::isnan(t_element)) {
5376        *wd = all_ones;
5377      } else {
5378        *wd = 0;
5379      }
5380    } break;
5381    case FCOR: {
5382      if (std::isnan(s_element) || std::isnan(t_element)) {
5383        *wd = 0;
5384      } else {
5385        *wd = all_ones;
5386      }
5387    } break;
5388    case FCUNE: {
5389      if (s_element != t_element || std::isnan(s_element) ||
5390          std::isnan(t_element)) {
5391        *wd = all_ones;
5392      } else {
5393        *wd = 0;
5394      }
5395    } break;
5396    case FCNE: {
5397      if (s_element == t_element || std::isnan(s_element) ||
5398          std::isnan(t_element)) {
5399        *wd = 0;
5400      } else {
5401        *wd = all_ones;
5402      }
5403    } break;
5404    case FADD:
5405      *wd = bit_cast<T_int>(s_element + t_element);
5406      break;
5407    case FSUB:
5408      *wd = bit_cast<T_int>(s_element - t_element);
5409      break;
5410    case FMUL:
5411      *wd = bit_cast<T_int>(s_element * t_element);
5412      break;
5413    case FDIV: {
5414      if (t_element == 0) {
5415        *wd = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
5416      } else {
5417        *wd = bit_cast<T_int>(s_element / t_element);
5418      }
5419    } break;
5420    case FMADD:
5421      *wd = bit_cast<T_int>(
5422          std::fma(s_element, t_element, *reinterpret_cast<T_fp*>(wd)));
5423      break;
5424    case FMSUB:
5425      *wd = bit_cast<T_int>(
5426          std::fma(s_element, -t_element, *reinterpret_cast<T_fp*>(wd)));
5427      break;
5428    case FEXP2:
5429      *wd = bit_cast<T_int>(std::ldexp(s_element, static_cast<int>(wt)));
5430      break;
5431    case FMIN:
5432      *wd = bit_cast<T_int>(std::min(s_element, t_element));
5433      break;
5434    case FMAX:
5435      *wd = bit_cast<T_int>(std::max(s_element, t_element));
5436      break;
5437    case FMIN_A: {
5438      *wd = bit_cast<T_int>(
5439          std::fabs(s_element) < std::fabs(t_element) ? s_element : t_element);
5440    } break;
5441    case FMAX_A: {
5442      *wd = bit_cast<T_int>(
5443          std::fabs(s_element) > std::fabs(t_element) ? s_element : t_element);
5444    } break;
5445    case FSOR:
5446    case FSUNE:
5447    case FSNE:
5448    case FSAF:
5449    case FSUN:
5450    case FSEQ:
5451    case FSUEQ:
5452    case FSLT:
5453    case FSULT:
5454    case FSLE:
5455    case FSULE:
5456      UNIMPLEMENTED();
5457      break;
5458    default:
5459      UNREACHABLE();
5460  }
5461}
5462
5463template <typename T_int, typename T_int_dbl, typename T_reg>
5464void Msa3RFInstrHelper2(uint32_t opcode, T_reg ws, T_reg wt, T_reg* wd) {
5465  //  using T_uint = typename std::make_unsigned<T_int>::type;
5466  using T_uint_dbl = typename std::make_unsigned<T_int_dbl>::type;
5467  const T_int max_int = std::numeric_limits<T_int>::max();
5468  const T_int min_int = std::numeric_limits<T_int>::min();
5469  const int shift = kBitsPerByte * sizeof(T_int) - 1;
5470  const T_int_dbl reg_s = ws;
5471  const T_int_dbl reg_t = wt;
5472  T_int_dbl product, result;
5473  product = reg_s * reg_t;
5474  switch (opcode) {
5475    case MUL_Q: {
5476      const T_int_dbl min_fix_dbl =
5477          bit_cast<T_uint_dbl>(std::numeric_limits<T_int_dbl>::min()) >> 1U;
5478      const T_int_dbl max_fix_dbl = std::numeric_limits<T_int_dbl>::max() >> 1U;
5479      if (product == min_fix_dbl) {
5480        product = max_fix_dbl;
5481      }
5482      *wd = static_cast<T_int>(product >> shift);
5483    } break;
5484    case MADD_Q: {
5485      result = (product + (static_cast<T_int_dbl>(*wd) << shift)) >> shift;
5486      *wd = static_cast<T_int>(
5487          result > max_int ? max_int : result < min_int ? min_int : result);
5488    } break;
5489    case MSUB_Q: {
5490      result = (-product + (static_cast<T_int_dbl>(*wd) << shift)) >> shift;
5491      *wd = static_cast<T_int>(
5492          result > max_int ? max_int : result < min_int ? min_int : result);
5493    } break;
5494    case MULR_Q: {
5495      const T_int_dbl min_fix_dbl =
5496          bit_cast<T_uint_dbl>(std::numeric_limits<T_int_dbl>::min()) >> 1U;
5497      const T_int_dbl max_fix_dbl = std::numeric_limits<T_int_dbl>::max() >> 1U;
5498      if (product == min_fix_dbl) {
5499        *wd = static_cast<T_int>(max_fix_dbl >> shift);
5500        break;
5501      }
5502      *wd = static_cast<T_int>((product + (1 << (shift - 1))) >> shift);
5503    } break;
5504    case MADDR_Q: {
5505      result = (product + (static_cast<T_int_dbl>(*wd) << shift) +
5506                (1 << (shift - 1))) >>
5507               shift;
5508      *wd = static_cast<T_int>(
5509          result > max_int ? max_int : result < min_int ? min_int : result);
5510    } break;
5511    case MSUBR_Q: {
5512      result = (-product + (static_cast<T_int_dbl>(*wd) << shift) +
5513                (1 << (shift - 1))) >>
5514               shift;
5515      *wd = static_cast<T_int>(
5516          result > max_int ? max_int : result < min_int ? min_int : result);
5517    } break;
5518    default:
5519      UNREACHABLE();
5520  }
5521}
5522
5523void Simulator::DecodeTypeMsa3RF() {
5524  DCHECK(IsMipsArchVariant(kMips32r6));
5525  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
5526  uint32_t opcode = instr_.InstructionBits() & kMsa3RFMask;
5527  msa_reg_t wd, ws, wt;
5528  if (opcode != FCAF) {
5529    get_msa_register(ws_reg(), &ws);
5530    get_msa_register(wt_reg(), &wt);
5531  }
5532  switch (opcode) {
5533    case FCAF:
5534      wd.d[0] = 0;
5535      wd.d[1] = 0;
5536      break;
5537    case FEXDO:
5538#define PACK_FLOAT16(sign, exp, frac) \
5539  static_cast<uint16_t>(((sign) << 15) + ((exp) << 10) + (frac))
5540#define FEXDO_DF(source, dst)                                        \
5541  do {                                                               \
5542    element = source;                                                \
5543    aSign = element >> 31;                                           \
5544    aExp = element >> 23 & 0xFF;                                     \
5545    aFrac = element & 0x007FFFFF;                                    \
5546    if (aExp == 0xFF) {                                              \
5547      if (aFrac) {                                                   \
5548        /* Input is a NaN */                                         \
5549        dst = 0x7DFFU;                                               \
5550        break;                                                       \
5551      }                                                              \
5552      /* Infinity */                                                 \
5553      dst = PACK_FLOAT16(aSign, 0x1F, 0);                            \
5554      break;                                                         \
5555    } else if (aExp == 0 && aFrac == 0) {                            \
5556      dst = PACK_FLOAT16(aSign, 0, 0);                               \
5557      break;                                                         \
5558    } else {                                                         \
5559      int maxexp = 29;                                               \
5560      uint32_t mask;                                                 \
5561      uint32_t increment;                                            \
5562      bool rounding_bumps_exp;                                       \
5563      aFrac |= 0x00800000;                                           \
5564      aExp -= 0x71;                                                  \
5565      if (aExp < 1) {                                                \
5566        /* Will be denormal in halfprec */                           \
5567        mask = 0x00FFFFFF;                                           \
5568        if (aExp >= -11) {                                           \
5569          mask >>= 11 + aExp;                                        \
5570        }                                                            \
5571      } else {                                                       \
5572        /* Normal number in halfprec */                              \
5573        mask = 0x00001FFF;                                           \
5574      }                                                              \
5575      switch (MSACSR_ & 3) {                                         \
5576        case kRoundToNearest:                                        \
5577          increment = (mask + 1) >> 1;                               \
5578          if ((aFrac & mask) == increment) {                         \
5579            increment = aFrac & (increment << 1);                    \
5580          }                                                          \
5581          break;                                                     \
5582        case kRoundToPlusInf:                                        \
5583          increment = aSign ? 0 : mask;                              \
5584          break;                                                     \
5585        case kRoundToMinusInf:                                       \
5586          increment = aSign ? mask : 0;                              \
5587          break;                                                     \
5588        case kRoundToZero:                                           \
5589          increment = 0;                                             \
5590          break;                                                     \
5591      }                                                              \
5592      rounding_bumps_exp = (aFrac + increment >= 0x01000000);        \
5593      if (aExp > maxexp || (aExp == maxexp && rounding_bumps_exp)) { \
5594        dst = PACK_FLOAT16(aSign, 0x1F, 0);                          \
5595        break;                                                       \
5596      }                                                              \
5597      aFrac += increment;                                            \
5598      if (rounding_bumps_exp) {                                      \
5599        aFrac >>= 1;                                                 \
5600        aExp++;                                                      \
5601      }                                                              \
5602      if (aExp < -10) {                                              \
5603        dst = PACK_FLOAT16(aSign, 0, 0);                             \
5604        break;                                                       \
5605      }                                                              \
5606      if (aExp < 0) {                                                \
5607        aFrac >>= -aExp;                                             \
5608        aExp = 0;                                                    \
5609      }                                                              \
5610      dst = PACK_FLOAT16(aSign, aExp, aFrac >> 13);                  \
5611    }                                                                \
5612  } while (0);
5613      switch (DecodeMsaDataFormat()) {
5614        case MSA_HALF:
5615          for (int i = 0; i < kMSALanesWord; i++) {
5616            uint_fast32_t element;
5617            uint_fast32_t aSign, aFrac;
5618            int_fast32_t aExp;
5619            FEXDO_DF(ws.uw[i], wd.uh[i + kMSALanesHalf / 2])
5620            FEXDO_DF(wt.uw[i], wd.uh[i])
5621          }
5622          break;
5623        case MSA_WORD:
5624          for (int i = 0; i < kMSALanesDword; i++) {
5625            wd.w[i + kMSALanesWord / 2] = bit_cast<int32_t>(
5626                static_cast<float>(bit_cast<double>(ws.d[i])));
5627            wd.w[i] = bit_cast<int32_t>(
5628                static_cast<float>(bit_cast<double>(wt.d[i])));
5629          }
5630          break;
5631        default:
5632          UNREACHABLE();
5633      }
5634      break;
5635#undef PACK_FLOAT16
5636#undef FEXDO_DF
5637    case FTQ:
5638#define FTQ_DF(source, dst, fp_type, int_type)                  \
5639  element = bit_cast<fp_type>(source) *                         \
5640            (1U << (sizeof(int_type) * kBitsPerByte - 1));      \
5641  if (element > std::numeric_limits<int_type>::max()) {         \
5642    dst = std::numeric_limits<int_type>::max();                 \
5643  } else if (element < std::numeric_limits<int_type>::min()) {  \
5644    dst = std::numeric_limits<int_type>::min();                 \
5645  } else if (std::isnan(element)) {                             \
5646    dst = 0;                                                    \
5647  } else {                                                      \
5648    int_type fixed_point;                                       \
5649    round_according_to_msacsr(element, &element, &fixed_point); \
5650    dst = fixed_point;                                          \
5651  }
5652
5653      switch (DecodeMsaDataFormat()) {
5654        case MSA_HALF:
5655          for (int i = 0; i < kMSALanesWord; i++) {
5656            float element;
5657            FTQ_DF(ws.w[i], wd.h[i + kMSALanesHalf / 2], float, int16_t)
5658            FTQ_DF(wt.w[i], wd.h[i], float, int16_t)
5659          }
5660          break;
5661        case MSA_WORD:
5662          double element;
5663          for (int i = 0; i < kMSALanesDword; i++) {
5664            FTQ_DF(ws.d[i], wd.w[i + kMSALanesWord / 2], double, int32_t)
5665            FTQ_DF(wt.d[i], wd.w[i], double, int32_t)
5666          }
5667          break;
5668        default:
5669          UNREACHABLE();
5670      }
5671      break;
5672#undef FTQ_DF
5673#define MSA_3RF_DF(T1, T2, Lanes, ws, wt, wd)         \
5674  for (int i = 0; i < Lanes; i++) {                   \
5675    Msa3RFInstrHelper<T1, T2>(opcode, ws, wt, &(wd)); \
5676  }
5677#define MSA_3RF_DF2(T1, T2, Lanes, ws, wt, wd)         \
5678  for (int i = 0; i < Lanes; i++) {                    \
5679    Msa3RFInstrHelper2<T1, T2>(opcode, ws, wt, &(wd)); \
5680  }
5681    case MADD_Q:
5682    case MSUB_Q:
5683    case MADDR_Q:
5684    case MSUBR_Q:
5685      get_msa_register(wd_reg(), &wd);
5686      V8_FALLTHROUGH;
5687    case MUL_Q:
5688    case MULR_Q:
5689      switch (DecodeMsaDataFormat()) {
5690        case MSA_HALF:
5691          MSA_3RF_DF2(int16_t, int32_t, kMSALanesHalf, ws.h[i], wt.h[i],
5692                      wd.h[i])
5693          break;
5694        case MSA_WORD:
5695          MSA_3RF_DF2(int32_t, int64_t, kMSALanesWord, ws.w[i], wt.w[i],
5696                      wd.w[i])
5697          break;
5698        default:
5699          UNREACHABLE();
5700      }
5701      break;
5702    default:
5703      if (opcode == FMADD || opcode == FMSUB) {
5704        get_msa_register(wd_reg(), &wd);
5705      }
5706      switch (DecodeMsaDataFormat()) {
5707        case MSA_WORD:
5708          MSA_3RF_DF(int32_t, float, kMSALanesWord, ws.w[i], wt.w[i], wd.w[i])
5709          break;
5710        case MSA_DWORD:
5711          MSA_3RF_DF(int64_t, double, kMSALanesDword, ws.d[i], wt.d[i], wd.d[i])
5712          break;
5713        default:
5714          UNREACHABLE();
5715      }
5716      break;
5717#undef MSA_3RF_DF
5718#undef MSA_3RF_DF2
5719  }
5720  set_msa_register(wd_reg(), &wd);
5721  TraceMSARegWr(&wd);
5722}
5723
5724void Simulator::DecodeTypeMsaVec() {
5725  DCHECK(IsMipsArchVariant(kMips32r6));
5726  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
5727  uint32_t opcode = instr_.InstructionBits() & kMsaVECMask;
5728  msa_reg_t wd, ws, wt;
5729
5730  get_msa_register(instr_.WsValue(), ws.w);
5731  get_msa_register(instr_.WtValue(), wt.w);
5732  if (opcode == BMNZ_V || opcode == BMZ_V || opcode == BSEL_V) {
5733    get_msa_register(instr_.WdValue(), wd.w);
5734  }
5735
5736  for (int i = 0; i < kMSALanesWord; i++) {
5737    switch (opcode) {
5738      case AND_V:
5739        wd.w[i] = ws.w[i] & wt.w[i];
5740        break;
5741      case OR_V:
5742        wd.w[i] = ws.w[i] | wt.w[i];
5743        break;
5744      case NOR_V:
5745        wd.w[i] = ~(ws.w[i] | wt.w[i]);
5746        break;
5747      case XOR_V:
5748        wd.w[i] = ws.w[i] ^ wt.w[i];
5749        break;
5750      case BMNZ_V:
5751        wd.w[i] = (wt.w[i] & ws.w[i]) | (~wt.w[i] & wd.w[i]);
5752        break;
5753      case BMZ_V:
5754        wd.w[i] = (~wt.w[i] & ws.w[i]) | (wt.w[i] & wd.w[i]);
5755        break;
5756      case BSEL_V:
5757        wd.w[i] = (~wd.w[i] & ws.w[i]) | (wd.w[i] & wt.w[i]);
5758        break;
5759      default:
5760        UNREACHABLE();
5761    }
5762  }
5763  set_msa_register(instr_.WdValue(), wd.w);
5764  TraceMSARegWr(wd.d);
5765}
5766
5767void Simulator::DecodeTypeMsa2R() {
5768  DCHECK(IsMipsArchVariant(kMips32r6));
5769  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
5770  uint32_t opcode = instr_.InstructionBits() & kMsa2RMask;
5771  msa_reg_t wd, ws;
5772  switch (opcode) {
5773    case FILL:
5774      switch (DecodeMsaDataFormat()) {
5775        case MSA_BYTE: {
5776          int32_t rs = get_register(instr_.WsValue());
5777          for (int i = 0; i < kMSALanesByte; i++) {
5778            wd.b[i] = rs & 0xFFu;
5779          }
5780          set_msa_register(instr_.WdValue(), wd.b);
5781          TraceMSARegWr(wd.b);
5782          break;
5783        }
5784        case MSA_HALF: {
5785          int32_t rs = get_register(instr_.WsValue());
5786          for (int i = 0; i < kMSALanesHalf; i++) {
5787            wd.h[i] = rs & 0xFFFFu;
5788          }
5789          set_msa_register(instr_.WdValue(), wd.h);
5790          TraceMSARegWr(wd.h);
5791          break;
5792        }
5793        case MSA_WORD: {
5794          int32_t rs = get_register(instr_.WsValue());
5795          for (int i = 0; i < kMSALanesWord; i++) {
5796            wd.w[i] = rs;
5797          }
5798          set_msa_register(instr_.WdValue(), wd.w);
5799          TraceMSARegWr(wd.w);
5800          break;
5801        }
5802        default:
5803          UNREACHABLE();
5804      }
5805      break;
5806    case PCNT:
5807#define PCNT_DF(elem, num_of_lanes)                       \
5808  get_msa_register(instr_.WsValue(), ws.elem);            \
5809  for (int i = 0; i < num_of_lanes; i++) {                \
5810    uint64_t u64elem = static_cast<uint64_t>(ws.elem[i]); \
5811    wd.elem[i] = base::bits::CountPopulation(u64elem);    \
5812  }                                                       \
5813  set_msa_register(instr_.WdValue(), wd.elem);            \
5814  TraceMSARegWr(wd.elem)
5815
5816      switch (DecodeMsaDataFormat()) {
5817        case MSA_BYTE:
5818          PCNT_DF(ub, kMSALanesByte);
5819          break;
5820        case MSA_HALF:
5821          PCNT_DF(uh, kMSALanesHalf);
5822          break;
5823        case MSA_WORD:
5824          PCNT_DF(uw, kMSALanesWord);
5825          break;
5826        case MSA_DWORD:
5827          PCNT_DF(ud, kMSALanesDword);
5828          break;
5829        default:
5830          UNREACHABLE();
5831      }
5832#undef PCNT_DF
5833      break;
5834    case NLOC:
5835#define NLOC_DF(elem, num_of_lanes)                                         \
5836  get_msa_register(instr_.WsValue(), ws.elem);                              \
5837  for (int i = 0; i < num_of_lanes; i++) {                                  \
5838    const uint64_t mask = (num_of_lanes == kMSALanesDword)                  \
5839                              ? UINT64_MAX                                  \
5840                              : (1ULL << (kMSARegSize / num_of_lanes)) - 1; \
5841    uint64_t u64elem = static_cast<uint64_t>(~ws.elem[i]) & mask;           \
5842    wd.elem[i] = base::bits::CountLeadingZeros64(u64elem) -                 \
5843                 (64 - kMSARegSize / num_of_lanes);                         \
5844  }                                                                         \
5845  set_msa_register(instr_.WdValue(), wd.elem);                              \
5846  TraceMSARegWr(wd.elem)
5847
5848      switch (DecodeMsaDataFormat()) {
5849        case MSA_BYTE:
5850          NLOC_DF(ub, kMSALanesByte);
5851          break;
5852        case MSA_HALF:
5853          NLOC_DF(uh, kMSALanesHalf);
5854          break;
5855        case MSA_WORD:
5856          NLOC_DF(uw, kMSALanesWord);
5857          break;
5858        case MSA_DWORD:
5859          NLOC_DF(ud, kMSALanesDword);
5860          break;
5861        default:
5862          UNREACHABLE();
5863      }
5864#undef NLOC_DF
5865      break;
5866    case NLZC:
5867#define NLZC_DF(elem, num_of_lanes)                         \
5868  get_msa_register(instr_.WsValue(), ws.elem);              \
5869  for (int i = 0; i < num_of_lanes; i++) {                  \
5870    uint64_t u64elem = static_cast<uint64_t>(ws.elem[i]);   \
5871    wd.elem[i] = base::bits::CountLeadingZeros64(u64elem) - \
5872                 (64 - kMSARegSize / num_of_lanes);         \
5873  }                                                         \
5874  set_msa_register(instr_.WdValue(), wd.elem);              \
5875  TraceMSARegWr(wd.elem)
5876
5877      switch (DecodeMsaDataFormat()) {
5878        case MSA_BYTE:
5879          NLZC_DF(ub, kMSALanesByte);
5880          break;
5881        case MSA_HALF:
5882          NLZC_DF(uh, kMSALanesHalf);
5883          break;
5884        case MSA_WORD:
5885          NLZC_DF(uw, kMSALanesWord);
5886          break;
5887        case MSA_DWORD:
5888          NLZC_DF(ud, kMSALanesDword);
5889          break;
5890        default:
5891          UNREACHABLE();
5892      }
5893#undef NLZC_DF
5894      break;
5895    default:
5896      UNREACHABLE();
5897  }
5898}
5899
5900#define BIT(n) (0x1LL << n)
5901#define QUIET_BIT_S(nan) (bit_cast<int32_t>(nan) & BIT(22))
5902#define QUIET_BIT_D(nan) (bit_cast<int64_t>(nan) & BIT(51))
5903static inline bool isSnan(float fp) { return !QUIET_BIT_S(fp); }
5904static inline bool isSnan(double fp) { return !QUIET_BIT_D(fp); }
5905#undef QUIET_BIT_S
5906#undef QUIET_BIT_D
5907
5908template <typename T_int, typename T_fp, typename T_src, typename T_dst>
5909T_int Msa2RFInstrHelper(uint32_t opcode, T_src src, T_dst* dst,
5910                        Simulator* sim) {
5911  using T_uint = typename std::make_unsigned<T_int>::type;
5912  switch (opcode) {
5913    case FCLASS: {
5914#define SNAN_BIT BIT(0)
5915#define QNAN_BIT BIT(1)
5916#define NEG_INFINITY_BIT BIT(2)
5917#define NEG_NORMAL_BIT BIT(3)
5918#define NEG_SUBNORMAL_BIT BIT(4)
5919#define NEG_ZERO_BIT BIT(5)
5920#define POS_INFINITY_BIT BIT(6)
5921#define POS_NORMAL_BIT BIT(7)
5922#define POS_SUBNORMAL_BIT BIT(8)
5923#define POS_ZERO_BIT BIT(9)
5924      T_fp element = *reinterpret_cast<T_fp*>(&src);
5925      switch (std::fpclassify(element)) {
5926        case FP_INFINITE:
5927          if (std::signbit(element)) {
5928            *dst = NEG_INFINITY_BIT;
5929          } else {
5930            *dst = POS_INFINITY_BIT;
5931          }
5932          break;
5933        case FP_NAN:
5934          if (isSnan(element)) {
5935            *dst = SNAN_BIT;
5936          } else {
5937            *dst = QNAN_BIT;
5938          }
5939          break;
5940        case FP_NORMAL:
5941          if (std::signbit(element)) {
5942            *dst = NEG_NORMAL_BIT;
5943          } else {
5944            *dst = POS_NORMAL_BIT;
5945          }
5946          break;
5947        case FP_SUBNORMAL:
5948          if (std::signbit(element)) {
5949            *dst = NEG_SUBNORMAL_BIT;
5950          } else {
5951            *dst = POS_SUBNORMAL_BIT;
5952          }
5953          break;
5954        case FP_ZERO:
5955          if (std::signbit(element)) {
5956            *dst = NEG_ZERO_BIT;
5957          } else {
5958            *dst = POS_ZERO_BIT;
5959          }
5960          break;
5961        default:
5962          UNREACHABLE();
5963      }
5964      break;
5965    }
5966#undef BIT
5967#undef SNAN_BIT
5968#undef QNAN_BIT
5969#undef NEG_INFINITY_BIT
5970#undef NEG_NORMAL_BIT
5971#undef NEG_SUBNORMAL_BIT
5972#undef NEG_ZERO_BIT
5973#undef POS_INFINITY_BIT
5974#undef POS_NORMAL_BIT
5975#undef POS_SUBNORMAL_BIT
5976#undef POS_ZERO_BIT
5977    case FTRUNC_S: {
5978      T_fp element = bit_cast<T_fp>(src);
5979      const T_int max_int = std::numeric_limits<T_int>::max();
5980      const T_int min_int = std::numeric_limits<T_int>::min();
5981      if (std::isnan(element)) {
5982        *dst = 0;
5983      } else if (element >= static_cast<T_fp>(max_int) || element <= min_int) {
5984        *dst = element >= static_cast<T_fp>(max_int) ? max_int : min_int;
5985      } else {
5986        *dst = static_cast<T_int>(std::trunc(element));
5987      }
5988      break;
5989    }
5990    case FTRUNC_U: {
5991      T_fp element = bit_cast<T_fp>(src);
5992      const T_uint max_int = std::numeric_limits<T_uint>::max();
5993      if (std::isnan(element)) {
5994        *dst = 0;
5995      } else if (element >= static_cast<T_fp>(max_int) || element <= 0) {
5996        *dst = element >= static_cast<T_fp>(max_int) ? max_int : 0;
5997      } else {
5998        *dst = static_cast<T_uint>(std::trunc(element));
5999      }
6000      break;
6001    }
6002    case FSQRT: {
6003      T_fp element = bit_cast<T_fp>(src);
6004      if (element < 0 || std::isnan(element)) {
6005        *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6006      } else {
6007        *dst = bit_cast<T_int>(std::sqrt(element));
6008      }
6009      break;
6010    }
6011    case FRSQRT: {
6012      T_fp element = bit_cast<T_fp>(src);
6013      if (element < 0 || std::isnan(element)) {
6014        *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6015      } else {
6016        *dst = bit_cast<T_int>(1 / std::sqrt(element));
6017      }
6018      break;
6019    }
6020    case FRCP: {
6021      T_fp element = bit_cast<T_fp>(src);
6022      if (std::isnan(element)) {
6023        *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6024      } else {
6025        *dst = bit_cast<T_int>(1 / element);
6026      }
6027      break;
6028    }
6029    case FRINT: {
6030      T_fp element = bit_cast<T_fp>(src);
6031      if (std::isnan(element)) {
6032        *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6033      } else {
6034        T_int dummy;
6035        sim->round_according_to_msacsr<T_fp, T_int>(element, &element, &dummy);
6036        *dst = bit_cast<T_int>(element);
6037      }
6038      break;
6039    }
6040    case FLOG2: {
6041      T_fp element = bit_cast<T_fp>(src);
6042      switch (std::fpclassify(element)) {
6043        case FP_NORMAL:
6044        case FP_SUBNORMAL:
6045          *dst = bit_cast<T_int>(std::logb(element));
6046          break;
6047        case FP_ZERO:
6048          *dst = bit_cast<T_int>(-std::numeric_limits<T_fp>::infinity());
6049          break;
6050        case FP_NAN:
6051          *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6052          break;
6053        case FP_INFINITE:
6054          if (element < 0) {
6055            *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::quiet_NaN());
6056          } else {
6057            *dst = bit_cast<T_int>(std::numeric_limits<T_fp>::infinity());
6058          }
6059          break;
6060        default:
6061          UNREACHABLE();
6062      }
6063      break;
6064    }
6065    case FTINT_S: {
6066      T_fp element = bit_cast<T_fp>(src);
6067      const T_int max_int = std::numeric_limits<T_int>::max();
6068      const T_int min_int = std::numeric_limits<T_int>::min();
6069      if (std::isnan(element)) {
6070        *dst = 0;
6071      } else if (element < min_int || element > static_cast<T_fp>(max_int)) {
6072        *dst = element > static_cast<T_fp>(max_int) ? max_int : min_int;
6073      } else {
6074        sim->round_according_to_msacsr<T_fp, T_int>(element, &element, dst);
6075      }
6076      break;
6077    }
6078    case FTINT_U: {
6079      T_fp element = bit_cast<T_fp>(src);
6080      const T_uint max_uint = std::numeric_limits<T_uint>::max();
6081      if (std::isnan(element)) {
6082        *dst = 0;
6083      } else if (element < 0 || element > static_cast<T_fp>(max_uint)) {
6084        *dst = element > static_cast<T_fp>(max_uint) ? max_uint : 0;
6085      } else {
6086        T_uint res;
6087        sim->round_according_to_msacsr<T_fp, T_uint>(element, &element, &res);
6088        *dst = *reinterpret_cast<T_int*>(&res);
6089      }
6090      break;
6091    }
6092    case FFINT_S:
6093      *dst = bit_cast<T_int>(static_cast<T_fp>(src));
6094      break;
6095    case FFINT_U:
6096      using uT_src = typename std::make_unsigned<T_src>::type;
6097      *dst = bit_cast<T_int>(static_cast<T_fp>(bit_cast<uT_src>(src)));
6098      break;
6099    default:
6100      UNREACHABLE();
6101  }
6102  return 0;
6103}
6104
6105template <typename T_int, typename T_fp, typename T_reg>
6106T_int Msa2RFInstrHelper2(uint32_t opcode, T_reg ws, int i) {
6107  switch (opcode) {
6108#define EXTRACT_FLOAT16_SIGN(fp16) (fp16 >> 15)
6109#define EXTRACT_FLOAT16_EXP(fp16) (fp16 >> 10 & 0x1F)
6110#define EXTRACT_FLOAT16_FRAC(fp16) (fp16 & 0x3FF)
6111#define PACK_FLOAT32(sign, exp, frac) \
6112  static_cast<uint32_t>(((sign) << 31) + ((exp) << 23) + (frac))
6113#define FEXUP_DF(src_index)                                                   \
6114  uint_fast16_t element = ws.uh[src_index];                                   \
6115  uint_fast32_t aSign, aFrac;                                                 \
6116  int_fast32_t aExp;                                                          \
6117  aSign = EXTRACT_FLOAT16_SIGN(element);                                      \
6118  aExp = EXTRACT_FLOAT16_EXP(element);                                        \
6119  aFrac = EXTRACT_FLOAT16_FRAC(element);                                      \
6120  if (V8_LIKELY(aExp && aExp != 0x1F)) {                                      \
6121    return PACK_FLOAT32(aSign, aExp + 0x70, aFrac << 13);                     \
6122  } else if (aExp == 0x1F) {                                                  \
6123    if (aFrac) {                                                              \
6124      return bit_cast<int32_t>(std::numeric_limits<float>::quiet_NaN());      \
6125    } else {                                                                  \
6126      return bit_cast<uint32_t>(std::numeric_limits<float>::infinity()) |     \
6127             static_cast<uint32_t>(aSign) << 31;                              \
6128    }                                                                         \
6129  } else {                                                                    \
6130    if (aFrac == 0) {                                                         \
6131      return PACK_FLOAT32(aSign, 0, 0);                                       \
6132    } else {                                                                  \
6133      int_fast16_t shiftCount =                                               \
6134          base::bits::CountLeadingZeros32(static_cast<uint32_t>(aFrac)) - 21; \
6135      aFrac <<= shiftCount;                                                   \
6136      aExp = -shiftCount;                                                     \
6137      return PACK_FLOAT32(aSign, aExp + 0x70, aFrac << 13);                   \
6138    }                                                                         \
6139  }
6140    case FEXUPL:
6141      if (std::is_same<int32_t, T_int>::value) {
6142        FEXUP_DF(i + kMSALanesWord)
6143      } else {
6144        return bit_cast<int64_t>(
6145            static_cast<double>(bit_cast<float>(ws.w[i + kMSALanesDword])));
6146      }
6147    case FEXUPR:
6148      if (std::is_same<int32_t, T_int>::value) {
6149        FEXUP_DF(i)
6150      } else {
6151        return bit_cast<int64_t>(static_cast<double>(bit_cast<float>(ws.w[i])));
6152      }
6153    case FFQL: {
6154      if (std::is_same<int32_t, T_int>::value) {
6155        return bit_cast<int32_t>(static_cast<float>(ws.h[i + kMSALanesWord]) /
6156                                 (1U << 15));
6157      } else {
6158        return bit_cast<int64_t>(static_cast<double>(ws.w[i + kMSALanesDword]) /
6159                                 (1U << 31));
6160      }
6161      break;
6162    }
6163    case FFQR: {
6164      if (std::is_same<int32_t, T_int>::value) {
6165        return bit_cast<int32_t>(static_cast<float>(ws.h[i]) / (1U << 15));
6166      } else {
6167        return bit_cast<int64_t>(static_cast<double>(ws.w[i]) / (1U << 31));
6168      }
6169      break;
6170      default:
6171        UNREACHABLE();
6172    }
6173  }
6174#undef EXTRACT_FLOAT16_SIGN
6175#undef EXTRACT_FLOAT16_EXP
6176#undef EXTRACT_FLOAT16_FRAC
6177#undef PACK_FLOAT32
6178#undef FEXUP_DF
6179}
6180
6181void Simulator::DecodeTypeMsa2RF() {
6182  DCHECK(IsMipsArchVariant(kMips32r6));
6183  DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
6184  uint32_t opcode = instr_.InstructionBits() & kMsa2RFMask;
6185  msa_reg_t wd, ws;
6186  get_msa_register(ws_reg(), &ws);
6187  if (opcode == FEXUPL || opcode == FEXUPR || opcode == FFQL ||
6188      opcode == FFQR) {
6189    switch (DecodeMsaDataFormat()) {
6190      case MSA_WORD:
6191        for (int i = 0; i < kMSALanesWord; i++) {
6192          wd.w[i] = Msa2RFInstrHelper2<int32_t, float>(opcode, ws, i);
6193        }
6194        break;
6195      case MSA_DWORD:
6196        for (int i = 0; i < kMSALanesDword; i++) {
6197          wd.d[i] = Msa2RFInstrHelper2<int64_t, double>(opcode, ws, i);
6198        }
6199        break;
6200      default:
6201        UNREACHABLE();
6202    }
6203  } else {
6204    switch (DecodeMsaDataFormat()) {
6205      case MSA_WORD:
6206        for (int i = 0; i < kMSALanesWord; i++) {
6207          Msa2RFInstrHelper<int32_t, float>(opcode, ws.w[i], &wd.w[i], this);
6208        }
6209        break;
6210      case MSA_DWORD:
6211        for (int i = 0; i < kMSALanesDword; i++) {
6212          Msa2RFInstrHelper<int64_t, double>(opcode, ws.d[i], &wd.d[i], this);
6213        }
6214        break;
6215      default:
6216        UNREACHABLE();
6217    }
6218  }
6219  set_msa_register(wd_reg(), &wd);
6220  TraceMSARegWr(&wd);
6221}
6222
6223void Simulator::DecodeTypeRegister() {
6224  // ---------- Execution.
6225  switch (instr_.OpcodeFieldRaw()) {
6226    case COP1:
6227      DecodeTypeRegisterCOP1();
6228      break;
6229    case COP1X:
6230      DecodeTypeRegisterCOP1X();
6231      break;
6232    case SPECIAL:
6233      DecodeTypeRegisterSPECIAL();
6234      break;
6235    case SPECIAL2:
6236      DecodeTypeRegisterSPECIAL2();
6237      break;
6238    case SPECIAL3:
6239      DecodeTypeRegisterSPECIAL3();
6240      break;
6241    case MSA:
6242      switch (instr_.MSAMinorOpcodeField()) {
6243        case kMsaMinor3R:
6244          DecodeTypeMsa3R();
6245          break;
6246        case kMsaMinor3RF:
6247          DecodeTypeMsa3RF();
6248          break;
6249        case kMsaMinorVEC:
6250          DecodeTypeMsaVec();
6251          break;
6252        case kMsaMinor2R:
6253          DecodeTypeMsa2R();
6254          break;
6255        case kMsaMinor2RF:
6256          DecodeTypeMsa2RF();
6257          break;
6258        case kMsaMinorELM:
6259          DecodeTypeMsaELM();
6260          break;
6261        default:
6262          UNREACHABLE();
6263      }
6264      break;
6265    default:
6266      UNREACHABLE();
6267  }
6268}
6269
6270// Type 2: instructions using a 16, 21 or 26 bits immediate. (e.g. beq, beqc).
6271void Simulator::DecodeTypeImmediate() {
6272  // Instruction fields.
6273  Opcode op = instr_.OpcodeFieldRaw();
6274  int32_t rs_reg = instr_.RsValue();
6275  int32_t rs = get_register(instr_.RsValue());
6276  uint32_t rs_u = static_cast<uint32_t>(rs);
6277  int32_t rt_reg = instr_.RtValue();  // Destination register.
6278  int32_t rt = get_register(rt_reg);
6279  int16_t imm16 = instr_.Imm16Value();
6280
6281  int32_t ft_reg = instr_.FtValue();  // Destination register.
6282
6283  // Zero extended immediate.
6284  uint32_t oe_imm16 = 0xFFFF & imm16;
6285  // Sign extended immediate.
6286  int32_t se_imm16 = imm16;
6287
6288  // Next pc.
6289  int32_t next_pc = bad_ra;
6290
6291  // Used for conditional branch instructions.
6292  bool execute_branch_delay_instruction = false;
6293
6294  // Used for arithmetic instructions.
6295  int32_t alu_out = 0;
6296
6297  // Used for memory instructions.
6298  int32_t addr = 0x0;
6299
6300  // Branch instructions common part.
6301  auto BranchAndLinkHelper =
6302      [this, &next_pc, &execute_branch_delay_instruction](bool do_branch) {
6303        execute_branch_delay_instruction = true;
6304        int32_t current_pc = get_pc();
6305        set_register(31, current_pc + 2 * kInstrSize);
6306        if (do_branch) {
6307          int16_t imm16 = this->instr_.Imm16Value();
6308          next_pc = current_pc + (imm16 << 2) + kInstrSize;
6309        } else {
6310          next_pc = current_pc + 2 * kInstrSize;
6311        }
6312      };
6313
6314  auto BranchHelper = [this, &next_pc,
6315                       &execute_branch_delay_instruction](bool do_branch) {
6316    execute_branch_delay_instruction = true;
6317    int32_t current_pc = get_pc();
6318    if (do_branch) {
6319      int16_t imm16 = this->instr_.Imm16Value();
6320      next_pc = current_pc + (imm16 << 2) + kInstrSize;
6321    } else {
6322      next_pc = current_pc + 2 * kInstrSize;
6323    }
6324  };
6325
6326  auto BranchHelper_MSA = [this, &next_pc, imm16,
6327                           &execute_branch_delay_instruction](bool do_branch) {
6328    execute_branch_delay_instruction = true;
6329    int32_t current_pc = get_pc();
6330    const int32_t bitsIn16Int = sizeof(int16_t) * kBitsPerByte;
6331    if (do_branch) {
6332      if (FLAG_debug_code) {
6333        int16_t bits = imm16 & 0xFC;
6334        if (imm16 >= 0) {
6335          CHECK_EQ(bits, 0);
6336        } else {
6337          CHECK_EQ(bits ^ 0xFC, 0);
6338        }
6339      }
6340      // jump range :[pc + kInstrSize - 512 * kInstrSize,
6341      //              pc + kInstrSize + 511 * kInstrSize]
6342      int16_t offset = static_cast<int16_t>(imm16 << (bitsIn16Int - 10)) >>
6343                       (bitsIn16Int - 12);
6344      next_pc = current_pc + offset + kInstrSize;
6345    } else {
6346      next_pc = current_pc + 2 * kInstrSize;
6347    }
6348  };
6349
6350  auto BranchAndLinkCompactHelper = [this, &next_pc](bool do_branch, int bits) {
6351    int32_t current_pc = get_pc();
6352    CheckForbiddenSlot(current_pc);
6353    if (do_branch) {
6354      int32_t imm = this->instr_.ImmValue(bits);
6355      imm <<= 32 - bits;
6356      imm >>= 32 - bits;
6357      next_pc = current_pc + (imm << 2) + kInstrSize;
6358      set_register(31, current_pc + kInstrSize);
6359    }
6360  };
6361
6362  auto BranchCompactHelper = [this, &next_pc](bool do_branch, int bits) {
6363    int32_t current_pc = get_pc();
6364    CheckForbiddenSlot(current_pc);
6365    if (do_branch) {
6366      int32_t imm = this->instr_.ImmValue(bits);
6367      imm <<= 32 - bits;
6368      imm >>= 32 - bits;
6369      next_pc = get_pc() + (imm << 2) + kInstrSize;
6370    }
6371  };
6372
6373  switch (op) {
6374    // ------------- COP1. Coprocessor instructions.
6375    case COP1:
6376      switch (instr_.RsFieldRaw()) {
6377        case BC1: {  // Branch on coprocessor condition.
6378          // Floating point.
6379          uint32_t cc = instr_.FBccValue();
6380          uint32_t fcsr_cc = get_fcsr_condition_bit(cc);
6381          uint32_t cc_value = test_fcsr_bit(fcsr_cc);
6382          bool do_branch = (instr_.FBtrueValue()) ? cc_value : !cc_value;
6383          BranchHelper(do_branch);
6384          break;
6385        }
6386        case BC1EQZ:
6387          BranchHelper(!(get_fpu_register(ft_reg) & 0x1));
6388          break;
6389        case BC1NEZ:
6390          BranchHelper(get_fpu_register(ft_reg) & 0x1);
6391          break;
6392        case BZ_V: {
6393          msa_reg_t wt;
6394          get_msa_register(wt_reg(), &wt);
6395          BranchHelper_MSA(wt.d[0] == 0 && wt.d[1] == 0);
6396        } break;
6397#define BZ_DF(witdh, lanes)          \
6398  {                                  \
6399    msa_reg_t wt;                    \
6400    get_msa_register(wt_reg(), &wt); \
6401    int i;                           \
6402    for (i = 0; i < lanes; ++i) {    \
6403      if (wt.witdh[i] == 0) {        \
6404        break;                       \
6405      }                              \
6406    }                                \
6407    BranchHelper_MSA(i != lanes);    \
6408  }
6409        case BZ_B:
6410          BZ_DF(b, kMSALanesByte)
6411          break;
6412        case BZ_H:
6413          BZ_DF(h, kMSALanesHalf)
6414          break;
6415        case BZ_W:
6416          BZ_DF(w, kMSALanesWord)
6417          break;
6418        case BZ_D:
6419          BZ_DF(d, kMSALanesDword)
6420          break;
6421#undef BZ_DF
6422        case BNZ_V: {
6423          msa_reg_t wt;
6424          get_msa_register(wt_reg(), &wt);
6425          BranchHelper_MSA(wt.d[0] != 0 || wt.d[1] != 0);
6426        } break;
6427#define BNZ_DF(witdh, lanes)         \
6428  {                                  \
6429    msa_reg_t wt;                    \
6430    get_msa_register(wt_reg(), &wt); \
6431    int i;                           \
6432    for (i = 0; i < lanes; ++i) {    \
6433      if (wt.witdh[i] == 0) {        \
6434        break;                       \
6435      }                              \
6436    }                                \
6437    BranchHelper_MSA(i == lanes);    \
6438  }
6439        case BNZ_B:
6440          BNZ_DF(b, kMSALanesByte)
6441          break;
6442        case BNZ_H:
6443          BNZ_DF(h, kMSALanesHalf)
6444          break;
6445        case BNZ_W:
6446          BNZ_DF(w, kMSALanesWord)
6447          break;
6448        case BNZ_D:
6449          BNZ_DF(d, kMSALanesDword)
6450          break;
6451#undef BNZ_DF
6452        default:
6453          UNREACHABLE();
6454      }
6455      break;
6456    // ------------- REGIMM class.
6457    case REGIMM:
6458      switch (instr_.RtFieldRaw()) {
6459        case BLTZ:
6460          BranchHelper(rs < 0);
6461          break;
6462        case BGEZ:
6463          BranchHelper(rs >= 0);
6464          break;
6465        case BLTZAL:
6466          BranchAndLinkHelper(rs < 0);
6467          break;
6468        case BGEZAL:
6469          BranchAndLinkHelper(rs >= 0);
6470          break;
6471        default:
6472          UNREACHABLE();
6473      }
6474      break;  // case REGIMM.
6475    // ------------- Branch instructions.
6476    // When comparing to zero, the encoding of rt field is always 0, so we don't
6477    // need to replace rt with zero.
6478    case BEQ:
6479      BranchHelper(rs == rt);
6480      break;
6481    case BNE:
6482      BranchHelper(rs != rt);
6483      break;
6484    case POP06:  // BLEZALC, BGEZALC, BGEUC, BLEZ (pre-r6)
6485      if (IsMipsArchVariant(kMips32r6)) {
6486        if (rt_reg != 0) {
6487          if (rs_reg == 0) {  // BLEZALC
6488            BranchAndLinkCompactHelper(rt <= 0, 16);
6489          } else {
6490            if (rs_reg == rt_reg) {  // BGEZALC
6491              BranchAndLinkCompactHelper(rt >= 0, 16);
6492            } else {  // BGEUC
6493              BranchCompactHelper(
6494                  static_cast<uint32_t>(rs) >= static_cast<uint32_t>(rt), 16);
6495            }
6496          }
6497        } else {  // BLEZ
6498          BranchHelper(rs <= 0);
6499        }
6500      } else {  // BLEZ
6501        BranchHelper(rs <= 0);
6502      }
6503      break;
6504    case POP07:  // BGTZALC, BLTZALC, BLTUC, BGTZ (pre-r6)
6505      if (IsMipsArchVariant(kMips32r6)) {
6506        if (rt_reg != 0) {
6507          if (rs_reg == 0) {  // BGTZALC
6508            BranchAndLinkCompactHelper(rt > 0, 16);
6509          } else {
6510            if (rt_reg == rs_reg) {  // BLTZALC
6511              BranchAndLinkCompactHelper(rt < 0, 16);
6512            } else {  // BLTUC
6513              BranchCompactHelper(
6514                  static_cast<uint32_t>(rs) < static_cast<uint32_t>(rt), 16);
6515            }
6516          }
6517        } else {  // BGTZ
6518          BranchHelper(rs > 0);
6519        }
6520      } else {  // BGTZ
6521        BranchHelper(rs > 0);
6522      }
6523      break;
6524    case POP26:  // BLEZC, BGEZC, BGEC/BLEC / BLEZL (pre-r6)
6525      if (IsMipsArchVariant(kMips32r6)) {
6526        if (rt_reg != 0) {
6527          if (rs_reg == 0) {  // BLEZC
6528            BranchCompactHelper(rt <= 0, 16);
6529          } else {
6530            if (rs_reg == rt_reg) {  // BGEZC
6531              BranchCompactHelper(rt >= 0, 16);
6532            } else {  // BGEC/BLEC
6533              BranchCompactHelper(rs >= rt, 16);
6534            }
6535          }
6536        }
6537      } else {  // BLEZL
6538        BranchAndLinkHelper(rs <= 0);
6539      }
6540      break;
6541    case POP27:  // BGTZC, BLTZC, BLTC/BGTC / BGTZL (pre-r6)
6542      if (IsMipsArchVariant(kMips32r6)) {
6543        if (rt_reg != 0) {
6544          if (rs_reg == 0) {  // BGTZC
6545            BranchCompactHelper(rt > 0, 16);
6546          } else {
6547            if (rs_reg == rt_reg) {  // BLTZC
6548              BranchCompactHelper(rt < 0, 16);
6549            } else {  // BLTC/BGTC
6550              BranchCompactHelper(rs < rt, 16);
6551            }
6552          }
6553        }
6554      } else {  // BGTZL
6555        BranchAndLinkHelper(rs > 0);
6556      }
6557      break;
6558    case POP66:           // BEQZC, JIC
6559      if (rs_reg != 0) {  // BEQZC
6560        BranchCompactHelper(rs == 0, 21);
6561      } else {  // JIC
6562        next_pc = rt + imm16;
6563      }
6564      break;
6565    case POP76:           // BNEZC, JIALC
6566      if (rs_reg != 0) {  // BNEZC
6567        BranchCompactHelper(rs != 0, 21);
6568      } else {  // JIALC
6569        set_register(31, get_pc() + kInstrSize);
6570        next_pc = rt + imm16;
6571      }
6572      break;
6573    case BC:
6574      BranchCompactHelper(true, 26);
6575      break;
6576    case BALC:
6577      BranchAndLinkCompactHelper(true, 26);
6578      break;
6579    case POP10:  // BOVC, BEQZALC, BEQC / ADDI (pre-r6)
6580      if (IsMipsArchVariant(kMips32r6)) {
6581        if (rs_reg >= rt_reg) {  // BOVC
6582          if (HaveSameSign(rs, rt)) {
6583            if (rs > 0) {
6584              BranchCompactHelper(rs > Registers::kMaxValue - rt, 16);
6585            } else if (rs < 0) {
6586              BranchCompactHelper(rs < Registers::kMinValue - rt, 16);
6587            }
6588          }
6589        } else {
6590          if (rs_reg == 0) {  // BEQZALC
6591            BranchAndLinkCompactHelper(rt == 0, 16);
6592          } else {  // BEQC
6593            BranchCompactHelper(rt == rs, 16);
6594          }
6595        }
6596      } else {  // ADDI
6597        if (HaveSameSign(rs, se_imm16)) {
6598          if (rs > 0) {
6599            if (rs <= Registers::kMaxValue - se_imm16) {
6600              SignalException(kIntegerOverflow);
6601            }
6602          } else if (rs < 0) {
6603            if (rs >= Registers::kMinValue - se_imm16) {
6604              SignalException(kIntegerUnderflow);
6605            }
6606          }
6607        }
6608        SetResult(rt_reg, rs + se_imm16);
6609      }
6610      break;
6611    case POP30:  // BNVC, BNEZALC, BNEC / DADDI (pre-r6)
6612      if (IsMipsArchVariant(kMips32r6)) {
6613        if (rs_reg >= rt_reg) {  // BNVC
6614          if (!HaveSameSign(rs, rt) || rs == 0 || rt == 0) {
6615            BranchCompactHelper(true, 16);
6616          } else {
6617            if (rs > 0) {
6618              BranchCompactHelper(rs <= Registers::kMaxValue - rt, 16);
6619            } else if (rs < 0) {
6620              BranchCompactHelper(rs >= Registers::kMinValue - rt, 16);
6621            }
6622          }
6623        } else {
6624          if (rs_reg == 0) {  // BNEZALC
6625            BranchAndLinkCompactHelper(rt != 0, 16);
6626          } else {  // BNEC
6627            BranchCompactHelper(rt != rs, 16);
6628          }
6629        }
6630      }
6631      break;
6632    // ------------- Arithmetic instructions.
6633    case ADDIU:
6634      SetResult(rt_reg, rs + se_imm16);
6635      break;
6636    case SLTI:
6637      SetResult(rt_reg, rs < se_imm16 ? 1 : 0);
6638      break;
6639    case SLTIU:
6640      SetResult(rt_reg, rs_u < static_cast<uint32_t>(se_imm16) ? 1 : 0);
6641      break;
6642    case ANDI:
6643      SetResult(rt_reg, rs & oe_imm16);
6644      break;
6645    case ORI:
6646      SetResult(rt_reg, rs | oe_imm16);
6647      break;
6648    case XORI:
6649      SetResult(rt_reg, rs ^ oe_imm16);
6650      break;
6651    case LUI:
6652      if (rs_reg != 0) {
6653        // AUI
6654        DCHECK(IsMipsArchVariant(kMips32r6));
6655        SetResult(rt_reg, rs + (se_imm16 << 16));
6656      } else {
6657        // LUI
6658        SetResult(rt_reg, oe_imm16 << 16);
6659      }
6660      break;
6661    // ------------- Memory instructions.
6662    case LB:
6663      set_register(rt_reg, ReadB(rs + se_imm16));
6664      break;
6665    case LH:
6666      set_register(rt_reg, ReadH(rs + se_imm16, instr_.instr()));
6667      break;
6668    case LWL: {
6669      // al_offset is offset of the effective address within an aligned word.
6670      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
6671      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
6672      uint32_t mask = (1 << byte_shift * 8) - 1;
6673      addr = rs + se_imm16 - al_offset;
6674      alu_out = ReadW(addr, instr_.instr());
6675      alu_out <<= byte_shift * 8;
6676      alu_out |= rt & mask;
6677      set_register(rt_reg, alu_out);
6678      break;
6679    }
6680    case LW:
6681      set_register(rt_reg, ReadW(rs + se_imm16, instr_.instr()));
6682      break;
6683    case LBU:
6684      set_register(rt_reg, ReadBU(rs + se_imm16));
6685      break;
6686    case LHU:
6687      set_register(rt_reg, ReadHU(rs + se_imm16, instr_.instr()));
6688      break;
6689    case LWR: {
6690      // al_offset is offset of the effective address within an aligned word.
6691      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
6692      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
6693      uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
6694      addr = rs + se_imm16 - al_offset;
6695      alu_out = ReadW(addr, instr_.instr());
6696      alu_out = static_cast<uint32_t>(alu_out) >> al_offset * 8;
6697      alu_out |= rt & mask;
6698      set_register(rt_reg, alu_out);
6699      break;
6700    }
6701    case SB:
6702      WriteB(rs + se_imm16, static_cast<int8_t>(rt));
6703      break;
6704    case SH:
6705      WriteH(rs + se_imm16, static_cast<uint16_t>(rt), instr_.instr());
6706      break;
6707    case SWL: {
6708      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
6709      uint8_t byte_shift = kPointerAlignmentMask - al_offset;
6710      uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
6711      addr = rs + se_imm16 - al_offset;
6712      // Value to be written in memory.
6713      uint32_t mem_value = ReadW(addr, instr_.instr()) & mask;
6714      mem_value |= static_cast<uint32_t>(rt) >> byte_shift * 8;
6715      WriteW(addr, mem_value, instr_.instr());
6716      break;
6717    }
6718    case SW:
6719      WriteW(rs + se_imm16, rt, instr_.instr());
6720      break;
6721    case SWR: {
6722      uint8_t al_offset = (rs + se_imm16) & kPointerAlignmentMask;
6723      uint32_t mask = (1 << al_offset * 8) - 1;
6724      addr = rs + se_imm16 - al_offset;
6725      uint32_t mem_value = ReadW(addr, instr_.instr());
6726      mem_value = (rt << al_offset * 8) | (mem_value & mask);
6727      WriteW(addr, mem_value, instr_.instr());
6728      break;
6729    }
6730    case LL: {
6731      DCHECK(!IsMipsArchVariant(kMips32r6));
6732      base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
6733      addr = rs + se_imm16;
6734      set_register(rt_reg, ReadW(addr, instr_.instr()));
6735      local_monitor_.NotifyLoadLinked(addr, TransactionSize::Word);
6736      GlobalMonitor::Get()->NotifyLoadLinked_Locked(addr,
6737                                                    &global_monitor_thread_);
6738      break;
6739    }
6740    case SC: {
6741      DCHECK(!IsMipsArchVariant(kMips32r6));
6742      addr = rs + se_imm16;
6743      WriteConditionalW(addr, rt, instr_.instr(), rt_reg);
6744      break;
6745    }
6746    case LWC1:
6747      set_fpu_register_hi_word(ft_reg, 0);
6748      set_fpu_register_word(ft_reg,
6749                            ReadW(rs + se_imm16, instr_.instr(), FLOAT));
6750      if (ft_reg % 2) {
6751        TraceMemRd(rs + se_imm16, get_fpu_register(ft_reg - 1), FLOAT_DOUBLE);
6752      } else {
6753        TraceMemRd(rs + se_imm16, get_fpu_register_word(ft_reg), FLOAT);
6754      }
6755      break;
6756    case LDC1:
6757      set_fpu_register_double(ft_reg, ReadD(rs + se_imm16, instr_.instr()));
6758      TraceMemRd(rs + se_imm16, get_fpu_register(ft_reg), DOUBLE);
6759      break;
6760    case SWC1:
6761      WriteW(rs + se_imm16, get_fpu_register_word(ft_reg), instr_.instr());
6762      TraceMemWr(rs + se_imm16, get_fpu_register_word(ft_reg));
6763      break;
6764    case SDC1:
6765      WriteD(rs + se_imm16, get_fpu_register_double(ft_reg), instr_.instr());
6766      TraceMemWr(rs + se_imm16, get_fpu_register(ft_reg));
6767      break;
6768    // ------------- PC-Relative instructions.
6769    case PCREL: {
6770      // rt field: checking 5-bits.
6771      int32_t imm21 = instr_.Imm21Value();
6772      int32_t current_pc = get_pc();
6773      uint8_t rt = (imm21 >> kImm16Bits);
6774      switch (rt) {
6775        case ALUIPC:
6776          addr = current_pc + (se_imm16 << 16);
6777          alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
6778          break;
6779        case AUIPC:
6780          alu_out = current_pc + (se_imm16 << 16);
6781          break;
6782        default: {
6783          int32_t imm19 = instr_.Imm19Value();
6784          // rt field: checking the most significant 2-bits.
6785          rt = (imm21 >> kImm19Bits);
6786          switch (rt) {
6787            case LWPC: {
6788              // Set sign.
6789              imm19 <<= (kOpcodeBits + kRsBits + 2);
6790              imm19 >>= (kOpcodeBits + kRsBits + 2);
6791              addr = current_pc + (imm19 << 2);
6792              uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
6793              alu_out = *ptr;
6794              break;
6795            }
6796            case ADDIUPC: {
6797              int32_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xFFF80000 : 0);
6798              alu_out = current_pc + (se_imm19 << 2);
6799              break;
6800            }
6801            default:
6802              UNREACHABLE();
6803          }
6804        }
6805      }
6806      SetResult(rs_reg, alu_out);
6807      break;
6808    }
6809    case SPECIAL3: {
6810      switch (instr_.FunctionFieldRaw()) {
6811        case LL_R6: {
6812          DCHECK(IsMipsArchVariant(kMips32r6));
6813          base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex);
6814          int32_t base = get_register(instr_.BaseValue());
6815          int32_t offset9 = instr_.Imm9Value();
6816          addr = base + offset9;
6817          DCHECK_EQ(addr & kPointerAlignmentMask, 0);
6818          set_register(rt_reg, ReadW(base + offset9, instr_.instr()));
6819          local_monitor_.NotifyLoadLinked(addr, TransactionSize::Word);
6820          GlobalMonitor::Get()->NotifyLoadLinked_Locked(
6821              addr, &global_monitor_thread_);
6822          break;
6823        }
6824        case SC_R6: {
6825          DCHECK(IsMipsArchVariant(kMips32r6));
6826          int32_t base = get_register(instr_.BaseValue());
6827          int32_t offset9 = instr_.Imm9Value();
6828          addr = base + offset9;
6829          DCHECK_EQ(addr & kPointerAlignmentMask, 0);
6830          WriteConditionalW(addr, rt, instr_.instr(), rt_reg);
6831          break;
6832        }
6833        default:
6834          UNREACHABLE();
6835      }
6836      break;
6837    }
6838    case MSA:
6839      switch (instr_.MSAMinorOpcodeField()) {
6840        case kMsaMinorI8:
6841          DecodeTypeMsaI8();
6842          break;
6843        case kMsaMinorI5:
6844          DecodeTypeMsaI5();
6845          break;
6846        case kMsaMinorI10:
6847          DecodeTypeMsaI10();
6848          break;
6849        case kMsaMinorELM:
6850          DecodeTypeMsaELM();
6851          break;
6852        case kMsaMinorBIT:
6853          DecodeTypeMsaBIT();
6854          break;
6855        case kMsaMinorMI10:
6856          DecodeTypeMsaMI10();
6857          break;
6858        default:
6859          UNREACHABLE();
6860      }
6861      break;
6862    default:
6863      UNREACHABLE();
6864  }
6865
6866  if (execute_branch_delay_instruction) {
6867    // Execute branch delay slot
6868    // We don't check for end_sim_pc. First it should not be met as the current
6869    // pc is valid. Secondly a jump should always execute its branch delay slot.
6870    Instruction* branch_delay_instr =
6871        reinterpret_cast<Instruction*>(get_pc() + kInstrSize);
6872    BranchDelayInstructionDecode(branch_delay_instr);
6873  }
6874
6875  // If needed update pc after the branch delay execution.
6876  if (next_pc != bad_ra) {
6877    set_pc(next_pc);
6878  }
6879}
6880
6881// Type 3: instructions using a 26 bytes immediate. (e.g. j, jal).
6882void Simulator::DecodeTypeJump() {
6883  // instr_ will be overwritten by BranchDelayInstructionDecode(), so we save
6884  // the result of IsLinkingInstruction now.
6885  bool isLinkingInstr = instr_.IsLinkingInstruction();
6886  // Get current pc.
6887  int32_t current_pc = get_pc();
6888  // Get unchanged bits of pc.
6889  int32_t pc_high_bits = current_pc & 0xF0000000;
6890  // Next pc.
6891
6892  int32_t next_pc = pc_high_bits | (instr_.Imm26Value() << 2);
6893
6894  // Execute branch delay slot.
6895  // We don't check for end_sim_pc. First it should not be met as the current pc
6896  // is valid. Secondly a jump should always execute its branch delay slot.
6897  Instruction* branch_delay_instr =
6898      reinterpret_cast<Instruction*>(current_pc + kInstrSize);
6899  BranchDelayInstructionDecode(branch_delay_instr);
6900
6901  // Update pc and ra if necessary.
6902  // Do this after the branch delay execution.
6903  if (isLinkingInstr) {
6904    set_register(31, current_pc + 2 * kInstrSize);
6905  }
6906  set_pc(next_pc);
6907  pc_modified_ = true;
6908}
6909
6910// Executes the current instruction.
6911void Simulator::InstructionDecode(Instruction* instr) {
6912  if (v8::internal::FLAG_check_icache) {
6913    CheckICache(i_cache(), instr);
6914  }
6915  pc_modified_ = false;
6916  v8::base::EmbeddedVector<char, 256> buffer;
6917  if (::v8::internal::FLAG_trace_sim) {
6918    SNPrintF(trace_buf_, "%s", "");
6919    disasm::NameConverter converter;
6920    disasm::Disassembler dasm(converter);
6921    dasm.InstructionDecode(buffer, reinterpret_cast<byte*>(instr));
6922  }
6923
6924  instr_ = instr;
6925  switch (instr_.InstructionType()) {
6926    case Instruction::kRegisterType:
6927      DecodeTypeRegister();
6928      break;
6929    case Instruction::kImmediateType:
6930      DecodeTypeImmediate();
6931      break;
6932    case Instruction::kJumpType:
6933      DecodeTypeJump();
6934      break;
6935    default:
6936      UNSUPPORTED();
6937  }
6938  if (::v8::internal::FLAG_trace_sim) {
6939    PrintF("  0x%08" PRIxPTR "  %-44s   %s\n",
6940           reinterpret_cast<intptr_t>(instr), buffer.begin(),
6941           trace_buf_.begin());
6942  }
6943  if (!pc_modified_) {
6944    set_register(pc, reinterpret_cast<int32_t>(instr) + kInstrSize);
6945  }
6946}
6947
6948void Simulator::Execute() {
6949  // Get the PC to simulate. Cannot use the accessor here as we need the
6950  // raw PC value and not the one used as input to arithmetic instructions.
6951  int program_counter = get_pc();
6952  if (::v8::internal::FLAG_stop_sim_at == 0) {
6953    // Fast version of the dispatch loop without checking whether the simulator
6954    // should be stopping at a particular executed instruction.
6955    while (program_counter != end_sim_pc) {
6956      Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
6957      icount_++;
6958      InstructionDecode(instr);
6959      program_counter = get_pc();
6960    }
6961  } else {
6962    // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
6963    // we reach the particular instruction count.
6964    while (program_counter != end_sim_pc) {
6965      Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
6966      icount_++;
6967      if (icount_ == static_cast<uint64_t>(::v8::internal::FLAG_stop_sim_at)) {
6968        MipsDebugger dbg(this);
6969        dbg.Debug();
6970      } else {
6971        InstructionDecode(instr);
6972      }
6973      program_counter = get_pc();
6974    }
6975  }
6976}
6977
6978void Simulator::CallInternal(Address entry) {
6979  // Adjust JS-based stack limit to C-based stack limit.
6980  isolate_->stack_guard()->AdjustStackLimitForSimulator();
6981
6982  // Prepare to execute the code at entry.
6983  set_register(pc, static_cast<int32_t>(entry));
6984  // Put down marker for end of simulation. The simulator will stop simulation
6985  // when the PC reaches this value. By saving the "end simulation" value into
6986  // the LR the simulation stops when returning to this call point.
6987  set_register(ra, end_sim_pc);
6988
6989  // Remember the values of callee-saved registers.
6990  // The code below assumes that r9 is not used as sb (static base) in
6991  // simulator code and therefore is regarded as a callee-saved register.
6992  int32_t s0_val = get_register(s0);
6993  int32_t s1_val = get_register(s1);
6994  int32_t s2_val = get_register(s2);
6995  int32_t s3_val = get_register(s3);
6996  int32_t s4_val = get_register(s4);
6997  int32_t s5_val = get_register(s5);
6998  int32_t s6_val = get_register(s6);
6999  int32_t s7_val = get_register(s7);
7000  int32_t gp_val = get_register(gp);
7001  int32_t sp_val = get_register(sp);
7002  int32_t fp_val = get_register(fp);
7003
7004  // Set up the callee-saved registers with a known value. To be able to check
7005  // that they are preserved properly across JS execution.
7006  int32_t callee_saved_value = static_cast<int32_t>(icount_);
7007  set_register(s0, callee_saved_value);
7008  set_register(s1, callee_saved_value);
7009  set_register(s2, callee_saved_value);
7010  set_register(s3, callee_saved_value);
7011  set_register(s4, callee_saved_value);
7012  set_register(s5, callee_saved_value);
7013  set_register(s6, callee_saved_value);
7014  set_register(s7, callee_saved_value);
7015  set_register(gp, callee_saved_value);
7016  set_register(fp, callee_saved_value);
7017
7018  // Start the simulation.
7019  Execute();
7020
7021  // Check that the callee-saved registers have been preserved.
7022  CHECK_EQ(callee_saved_value, get_register(s0));
7023  CHECK_EQ(callee_saved_value, get_register(s1));
7024  CHECK_EQ(callee_saved_value, get_register(s2));
7025  CHECK_EQ(callee_saved_value, get_register(s3));
7026  CHECK_EQ(callee_saved_value, get_register(s4));
7027  CHECK_EQ(callee_saved_value, get_register(s5));
7028  CHECK_EQ(callee_saved_value, get_register(s6));
7029  CHECK_EQ(callee_saved_value, get_register(s7));
7030  CHECK_EQ(callee_saved_value, get_register(gp));
7031  CHECK_EQ(callee_saved_value, get_register(fp));
7032
7033  // Restore callee-saved registers with the original value.
7034  set_register(s0, s0_val);
7035  set_register(s1, s1_val);
7036  set_register(s2, s2_val);
7037  set_register(s3, s3_val);
7038  set_register(s4, s4_val);
7039  set_register(s5, s5_val);
7040  set_register(s6, s6_val);
7041  set_register(s7, s7_val);
7042  set_register(gp, gp_val);
7043  set_register(sp, sp_val);
7044  set_register(fp, fp_val);
7045}
7046
7047intptr_t Simulator::CallImpl(Address entry, int argument_count,
7048                             const intptr_t* arguments) {
7049  // Set up arguments.
7050
7051  // First four arguments passed in registers.
7052  int reg_arg_count = std::min(4, argument_count);
7053  if (reg_arg_count > 0) set_register(a0, arguments[0]);
7054  if (reg_arg_count > 1) set_register(a1, arguments[1]);
7055  if (reg_arg_count > 2) set_register(a2, arguments[2]);
7056  if (reg_arg_count > 3) set_register(a3, arguments[3]);
7057
7058  // Remaining arguments passed on stack.
7059  int original_stack = get_register(sp);
7060  // Compute position of stack on entry to generated code.
7061  int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t) -
7062                     kCArgsSlotsSize);
7063  if (base::OS::ActivationFrameAlignment() != 0) {
7064    entry_stack &= -base::OS::ActivationFrameAlignment();
7065  }
7066  // Store remaining arguments on stack, from low to high memory.
7067  intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
7068  memcpy(stack_argument + kCArgSlotCount, arguments + reg_arg_count,
7069         (argument_count - reg_arg_count) * sizeof(*arguments));
7070  set_register(sp, entry_stack);
7071
7072  CallInternal(entry);
7073
7074  // Pop stack passed arguments.
7075  CHECK_EQ(entry_stack, get_register(sp));
7076  set_register(sp, original_stack);
7077
7078  return get_register(v0);
7079}
7080
7081double Simulator::CallFP(Address entry, double d0, double d1) {
7082  if (!IsMipsSoftFloatABI) {
7083    set_fpu_register_double(f12, d0);
7084    set_fpu_register_double(f14, d1);
7085  } else {
7086    int buffer[2];
7087    DCHECK(sizeof(buffer[0]) * 2 == sizeof(d0));
7088    memcpy(buffer, &d0, sizeof(d0));
7089    set_dw_register(a0, buffer);
7090    memcpy(buffer, &d1, sizeof(d1));
7091    set_dw_register(a2, buffer);
7092  }
7093  CallInternal(entry);
7094  if (!IsMipsSoftFloatABI) {
7095    return get_fpu_register_double(f0);
7096  } else {
7097    return get_double_from_register_pair(v0);
7098  }
7099}
7100
7101uintptr_t Simulator::PushAddress(uintptr_t address) {
7102  int new_sp = get_register(sp) - sizeof(uintptr_t);
7103  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
7104  *stack_slot = address;
7105  set_register(sp, new_sp);
7106  return new_sp;
7107}
7108
7109uintptr_t Simulator::PopAddress() {
7110  int current_sp = get_register(sp);
7111  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
7112  uintptr_t address = *stack_slot;
7113  set_register(sp, current_sp + sizeof(uintptr_t));
7114  return address;
7115}
7116
7117Simulator::LocalMonitor::LocalMonitor()
7118    : access_state_(MonitorAccess::Open),
7119      tagged_addr_(0),
7120      size_(TransactionSize::None) {}
7121
7122void Simulator::LocalMonitor::Clear() {
7123  access_state_ = MonitorAccess::Open;
7124  tagged_addr_ = 0;
7125  size_ = TransactionSize::None;
7126}
7127
7128void Simulator::LocalMonitor::NotifyLoad() {
7129  if (access_state_ == MonitorAccess::RMW) {
7130    // A non linked load could clear the local monitor. As a result, it's
7131    // most strict to unconditionally clear the local monitor on load.
7132    Clear();
7133  }
7134}
7135
7136void Simulator::LocalMonitor::NotifyLoadLinked(uintptr_t addr,
7137                                               TransactionSize size) {
7138  access_state_ = MonitorAccess::RMW;
7139  tagged_addr_ = addr;
7140  size_ = size;
7141}
7142
7143void Simulator::LocalMonitor::NotifyStore() {
7144  if (access_state_ == MonitorAccess::RMW) {
7145    // A non exclusive store could clear the local monitor. As a result, it's
7146    // most strict to unconditionally clear the local monitor on store.
7147    Clear();
7148  }
7149}
7150
7151bool Simulator::LocalMonitor::NotifyStoreConditional(uintptr_t addr,
7152                                                     TransactionSize size) {
7153  if (access_state_ == MonitorAccess::RMW) {
7154    if (addr == tagged_addr_ && size_ == size) {
7155      Clear();
7156      return true;
7157    } else {
7158      return false;
7159    }
7160  } else {
7161    DCHECK(access_state_ == MonitorAccess::Open);
7162    return false;
7163  }
7164}
7165
7166Simulator::GlobalMonitor::LinkedAddress::LinkedAddress()
7167    : access_state_(MonitorAccess::Open),
7168      tagged_addr_(0),
7169      next_(nullptr),
7170      prev_(nullptr),
7171      failure_counter_(0) {}
7172
7173void Simulator::GlobalMonitor::LinkedAddress::Clear_Locked() {
7174  access_state_ = MonitorAccess::Open;
7175  tagged_addr_ = 0;
7176}
7177
7178void Simulator::GlobalMonitor::LinkedAddress::NotifyLoadLinked_Locked(
7179    uintptr_t addr) {
7180  access_state_ = MonitorAccess::RMW;
7181  tagged_addr_ = addr;
7182}
7183
7184void Simulator::GlobalMonitor::LinkedAddress::NotifyStore_Locked() {
7185  if (access_state_ == MonitorAccess::RMW) {
7186    // A non exclusive store could clear the global monitor. As a result, it's
7187    // most strict to unconditionally clear global monitors on store.
7188    Clear_Locked();
7189  }
7190}
7191
7192bool Simulator::GlobalMonitor::LinkedAddress::NotifyStoreConditional_Locked(
7193    uintptr_t addr, bool is_requesting_processor) {
7194  if (access_state_ == MonitorAccess::RMW) {
7195    if (is_requesting_processor) {
7196      if (addr == tagged_addr_) {
7197        Clear_Locked();
7198        // Introduce occasional sc/scd failures. This is to simulate the
7199        // behavior of hardware, which can randomly fail due to background
7200        // cache evictions.
7201        if (failure_counter_++ >= kMaxFailureCounter) {
7202          failure_counter_ = 0;
7203          return false;
7204        } else {
7205          return true;
7206        }
7207      }
7208    } else if ((addr & kExclusiveTaggedAddrMask) ==
7209               (tagged_addr_ & kExclusiveTaggedAddrMask)) {
7210      // Check the masked addresses when responding to a successful lock by
7211      // another thread so the implementation is more conservative (i.e. the
7212      // granularity of locking is as large as possible.)
7213      Clear_Locked();
7214      return false;
7215    }
7216  }
7217  return false;
7218}
7219
7220void Simulator::GlobalMonitor::NotifyLoadLinked_Locked(
7221    uintptr_t addr, LinkedAddress* linked_address) {
7222  linked_address->NotifyLoadLinked_Locked(addr);
7223  PrependProcessor_Locked(linked_address);
7224}
7225
7226void Simulator::GlobalMonitor::NotifyStore_Locked(
7227    LinkedAddress* linked_address) {
7228  // Notify each thread of the store operation.
7229  for (LinkedAddress* iter = head_; iter; iter = iter->next_) {
7230    iter->NotifyStore_Locked();
7231  }
7232}
7233
7234bool Simulator::GlobalMonitor::NotifyStoreConditional_Locked(
7235    uintptr_t addr, LinkedAddress* linked_address) {
7236  DCHECK(IsProcessorInLinkedList_Locked(linked_address));
7237  if (linked_address->NotifyStoreConditional_Locked(addr, true)) {
7238    // Notify the other processors that this StoreConditional succeeded.
7239    for (LinkedAddress* iter = head_; iter; iter = iter->next_) {
7240      if (iter != linked_address) {
7241        iter->NotifyStoreConditional_Locked(addr, false);
7242      }
7243    }
7244    return true;
7245  } else {
7246    return false;
7247  }
7248}
7249
7250bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked(
7251    LinkedAddress* linked_address) const {
7252  return head_ == linked_address || linked_address->next_ ||
7253         linked_address->prev_;
7254}
7255
7256void Simulator::GlobalMonitor::PrependProcessor_Locked(
7257    LinkedAddress* linked_address) {
7258  if (IsProcessorInLinkedList_Locked(linked_address)) {
7259    return;
7260  }
7261
7262  if (head_) {
7263    head_->prev_ = linked_address;
7264  }
7265  linked_address->prev_ = nullptr;
7266  linked_address->next_ = head_;
7267  head_ = linked_address;
7268}
7269
7270void Simulator::GlobalMonitor::RemoveLinkedAddress(
7271    LinkedAddress* linked_address) {
7272  base::MutexGuard lock_guard(&mutex);
7273  if (!IsProcessorInLinkedList_Locked(linked_address)) {
7274    return;
7275  }
7276
7277  if (linked_address->prev_) {
7278    linked_address->prev_->next_ = linked_address->next_;
7279  } else {
7280    head_ = linked_address->next_;
7281  }
7282  if (linked_address->next_) {
7283    linked_address->next_->prev_ = linked_address->prev_;
7284  }
7285  linked_address->prev_ = nullptr;
7286  linked_address->next_ = nullptr;
7287}
7288
7289#undef UNSUPPORTED
7290#undef SScanF
7291
7292}  // namespace internal
7293}  // namespace v8
7294
7295#endif  // USE_SIMULATOR
7296