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