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