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