v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
simulator-arm.cc
Go to the documentation of this file.
1// Copyright 2012 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#include "src/base/logging.h"
8
9#if defined(USE_SIMULATOR)
10
11#include <stdarg.h>
12#include <stdlib.h>
13
14#include <cmath>
15
16#include "src/base/bits.h"
18#include "src/base/memory.h"
22#include "src/base/vector.h"
27#include "src/heap/base/stack.h"
29#include "src/heap/heap-inl.h" // For CodeSpaceMemoryModificationScope.
32#include "src/utils/ostreams.h"
33#include "src/utils/utils.h"
34
35// Only build the simulator if not compiling for real ARM hardware.
36namespace v8 {
37namespace internal {
38
39DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor,
40 Simulator::GlobalMonitor::Get)
41
42// This macro provides a platform independent use of sscanf. The reason for
43// SScanF not being implemented in a platform independent way through
44// ::v8::internal::OS in the same way as SNPrintF is that the
45// Windows C Run-Time Library does not provide vsscanf.
46#define SScanF sscanf
47
48// The ArmDebugger class is used by the simulator while debugging simulated ARM
49// code.
50class ArmDebugger {
51 public:
52 explicit ArmDebugger(Simulator* sim) : sim_(sim) {}
53 void Debug();
54 bool ExecDebugCommand(ArrayUniquePtr<char> line_ptr);
55
56 private:
57 static const Instr kBreakpointInstr =
58 (al | (7 * B25) | (1 * B24) | kBreakpoint);
59 static const Instr kNopInstr = (al | (13 * B21));
60
61 Simulator* sim_;
62
63 int32_t GetRegisterValue(int regnum);
64 double GetRegisterPairDoubleValue(int regnum);
65 double GetVFPDoubleRegisterValue(int regnum);
66 bool GetValue(const char* desc, int32_t* value);
67 bool GetVFPSingleValue(const char* desc, float* value);
68 bool GetVFPDoubleValue(const char* desc, double* value);
69
70 // Set or delete breakpoint (there can be only one).
71 bool SetBreakpoint(Instruction* breakpc);
72 void DeleteBreakpoint();
73
74 // Undo and redo the breakpoint. This is needed to bracket disassembly and
75 // execution to skip past the breakpoint when run from the debugger.
76 void UndoBreakpoint();
77 void RedoBreakpoint();
78};
79
80void Simulator::DebugAtNextPC() {
81 PrintF("Starting debugger on the next instruction:\n");
82 set_pc(get_pc() + kInstrSize);
83 ArmDebugger(this).Debug();
84}
85
86void Simulator::AdvancedSIMDElementOrStructureLoadStoreWriteback(int Rn, int Rm,
87 int ebytes) {
88 if (Rm != 15) {
89 if (Rm == 13) {
90 set_register(Rn, get_register(Rn) + ebytes);
91 } else {
92 set_register(Rn, get_register(Rn) + get_register(Rm));
93 }
94 }
95}
96
97int32_t ArmDebugger::GetRegisterValue(int regnum) {
98 if (regnum == kPCRegister) {
99 return sim_->get_pc();
100 } else {
101 return sim_->get_register(regnum);
102 }
103}
104
105double ArmDebugger::GetRegisterPairDoubleValue(int regnum) {
106 return sim_->get_double_from_register_pair(regnum);
107}
108
109double ArmDebugger::GetVFPDoubleRegisterValue(int regnum) {
110 return sim_->get_double_from_d_register(regnum).get_scalar();
111}
112
113bool ArmDebugger::GetValue(const char* desc, int32_t* value) {
114 int regnum = Registers::Number(desc);
115 if (regnum != kNoRegister) {
116 *value = GetRegisterValue(regnum);
117 return true;
118 }
119 if (strncmp(desc, "0x", 2) == 0)
120 return SScanF(desc + 2, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
121 return SScanF(desc, "%u", reinterpret_cast<uint32_t*>(value)) == 1;
122}
123
124bool ArmDebugger::GetVFPSingleValue(const char* desc, float* value) {
125 bool is_double;
126 int regnum = VFPRegisters::Number(desc, &is_double);
127 if (regnum != kNoRegister && !is_double) {
128 *value = sim_->get_float_from_s_register(regnum).get_scalar();
129 return true;
130 }
131 return false;
132}
133
134bool ArmDebugger::GetVFPDoubleValue(const char* desc, double* value) {
135 bool is_double;
136 int regnum = VFPRegisters::Number(desc, &is_double);
137 if (regnum != kNoRegister && is_double) {
138 *value = sim_->get_double_from_d_register(regnum).get_scalar();
139 return true;
140 }
141 return false;
142}
143
144bool ArmDebugger::SetBreakpoint(Instruction* breakpc) {
145 // Check if a breakpoint can be set. If not return without any side-effects.
146 if (sim_->break_pc_ != nullptr) {
147 return false;
148 }
149
150 // Set the breakpoint.
151 sim_->break_pc_ = breakpc;
152 sim_->break_instr_ = breakpc->InstructionBits();
153 // Not setting the breakpoint instruction in the code itself. It will be set
154 // when the debugger shell continues.
155 return true;
156}
157
158namespace {
159// This function is dangerous, but it's only available in non-production
160// (simulator) builds.
161void SetInstructionBitsInCodeSpace(Instruction* instr, Instr value,
162 Heap* heap) {
163 CodePageMemoryModificationScopeForDebugging scope(
166}
167} // namespace
168
169void ArmDebugger::DeleteBreakpoint() {
170 UndoBreakpoint();
171 sim_->break_pc_ = nullptr;
172 sim_->break_instr_ = 0;
173}
174
175void ArmDebugger::UndoBreakpoint() {
176 if (sim_->break_pc_ != nullptr) {
177 SetInstructionBitsInCodeSpace(sim_->break_pc_, sim_->break_instr_,
178 sim_->isolate_->heap());
179 }
180}
181
182void ArmDebugger::RedoBreakpoint() {
183 if (sim_->break_pc_ != nullptr) {
184 SetInstructionBitsInCodeSpace(sim_->break_pc_, kBreakpointInstr,
185 sim_->isolate_->heap());
186 }
187}
188
189void ArmDebugger::Debug() {
190 if (v8_flags.correctness_fuzzer_suppressions) {
191 PrintF("Debugger disabled for differential fuzzing.\n");
192 return;
193 }
194 intptr_t last_pc = -1;
195 bool done = false;
196
197 // Unset breakpoint while running in the debugger shell, making it invisible
198 // to all commands.
199 UndoBreakpoint();
200
201 while (!done && !sim_->has_bad_pc()) {
202 if (last_pc != sim_->get_pc()) {
203 disasm::NameConverter converter;
204 disasm::Disassembler dasm(converter);
205 // use a reasonably large buffer
207 dasm.InstructionDecode(buffer,
208 reinterpret_cast<uint8_t*>(sim_->get_pc()));
209 PrintF(" 0x%08x %s\n", sim_->get_pc(), buffer.begin());
210 last_pc = sim_->get_pc();
211 }
212 ArrayUniquePtr<char> line(ReadLine("sim> "));
213
214 done = ExecDebugCommand(std::move(line));
215 }
216
217 // Reinstall breakpoint to stop execution and enter the debugger shell when
218 // hit.
219 RedoBreakpoint();
220}
221
222bool ArmDebugger::ExecDebugCommand(ArrayUniquePtr<char> line_ptr) {
223#define COMMAND_SIZE 63
224#define ARG_SIZE 255
225
226#define STR(a) #a
227#define XSTR(a) STR(a)
228
229 char cmd[COMMAND_SIZE + 1];
230 char arg1[ARG_SIZE + 1];
231 char arg2[ARG_SIZE + 1];
232 char* argv[3] = {cmd, arg1, arg2};
233
234 // make sure to have a proper terminating character if reaching the limit
235 cmd[COMMAND_SIZE] = 0;
236 arg1[ARG_SIZE] = 0;
237 arg2[ARG_SIZE] = 0;
238
239 if (line_ptr == nullptr) return true;
240
241 // Repeat last command by default.
242 const char* line = line_ptr.get();
243 const char* last_input = sim_->last_debugger_input();
244 if (strcmp(line, "\n") == 0 && (last_input != nullptr)) {
245 line_ptr.reset();
246 line = last_input;
247 } else {
248 // Update the latest command ran
249 sim_->set_last_debugger_input(std::move(line_ptr));
250 }
251
252 // Use sscanf to parse the individual parts of the command line. At the
253 // moment no command expects more than two parameters.
254 int argc = SScanF(line,
255 "%" XSTR(COMMAND_SIZE) "s "
256 "%" XSTR(ARG_SIZE) "s "
257 "%" XSTR(ARG_SIZE) "s",
258 cmd, arg1, arg2);
259 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
260 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
261 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
262 // Execute the one instruction we broke at with breakpoints disabled.
263 sim_->InstructionDecode(reinterpret_cast<Instruction*>(sim_->get_pc()));
264 // Leave the debugger shell.
265 return true;
266 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
267 if (argc == 2 || (argc == 3 && strcmp(arg2, "fp") == 0)) {
269 float svalue;
270 double dvalue;
271 if (strcmp(arg1, "all") == 0) {
272 for (int i = 0; i < kNumRegisters; i++) {
273 value = GetRegisterValue(i);
274 PrintF("%3s: 0x%08x %10d", RegisterName(Register::from_code(i)),
275 value, value);
276 if ((argc == 3 && strcmp(arg2, "fp") == 0) && i < 8 && (i % 2) == 0) {
277 dvalue = GetRegisterPairDoubleValue(i);
278 PrintF(" (%f)\n", dvalue);
279 } else {
280 PrintF("\n");
281 }
282 }
283 for (int i = 0; i < DwVfpRegister::SupportedRegisterCount(); i++) {
284 dvalue = GetVFPDoubleRegisterValue(i);
285 uint64_t as_words = base::bit_cast<uint64_t>(dvalue);
286 PrintF("%3s: %f 0x%08x %08x\n", VFPRegisters::Name(i, true), dvalue,
287 static_cast<uint32_t>(as_words >> 32),
288 static_cast<uint32_t>(as_words & 0xFFFFFFFF));
289 }
290 } else {
291 if (GetValue(arg1, &value)) {
292 PrintF("%s: 0x%08x %d \n", arg1, value, value);
293 } else if (GetVFPSingleValue(arg1, &svalue)) {
294 uint32_t as_word = base::bit_cast<uint32_t>(svalue);
295 PrintF("%s: %f 0x%08x\n", arg1, svalue, as_word);
296 } else if (GetVFPDoubleValue(arg1, &dvalue)) {
297 uint64_t as_words = base::bit_cast<uint64_t>(dvalue);
298 PrintF("%s: %f 0x%08x %08x\n", arg1, dvalue,
299 static_cast<uint32_t>(as_words >> 32),
300 static_cast<uint32_t>(as_words & 0xFFFFFFFF));
301 } else {
302 PrintF("%s unrecognized\n", arg1);
303 }
304 }
305 } else {
306 PrintF("print <register>\n");
307 }
308 } else if ((strcmp(cmd, "po") == 0) || (strcmp(cmd, "printobject") == 0)) {
309 if (argc == 2) {
311 StdoutStream os;
312 if (GetValue(arg1, &value)) {
313 Tagged<Object> obj(value);
314 os << arg1 << ": \n";
315#ifdef DEBUG
316 Print(obj, os);
317 os << "\n";
318#else
319 os << Brief(obj) << "\n";
320#endif
321 } else {
322 os << arg1 << " unrecognized\n";
323 }
324 } else {
325 PrintF("printobject <value>\n");
326 }
327 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0 ||
328 strcmp(cmd, "dump") == 0) {
329 int32_t* cur = nullptr;
330 int32_t* end = nullptr;
331 int next_arg = 1;
332
333 if (strcmp(cmd, "stack") == 0) {
334 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
335 } else { // "mem"
337 if (!GetValue(arg1, &value)) {
338 PrintF("%s unrecognized\n", arg1);
339 return false;
340 }
341 cur = reinterpret_cast<int32_t*>(value);
342 next_arg++;
343 }
344
345 int32_t words;
346 if (argc == next_arg) {
347 words = 10;
348 } else {
349 if (!GetValue(argv[next_arg], &words)) {
350 words = 10;
351 }
352 }
353 end = cur + words;
354
355 bool skip_obj_print = (strcmp(cmd, "dump") == 0);
356 while (cur < end) {
357 PrintF(" 0x%08" V8PRIxPTR ": 0x%08x %10d",
358 reinterpret_cast<intptr_t>(cur), *cur, *cur);
359 Tagged<Object> obj(*cur);
360 Heap* current_heap = sim_->isolate_->heap();
361 if (!skip_obj_print) {
362 if (IsSmi(obj) ||
363 IsValidHeapObject(current_heap, Cast<HeapObject>(obj))) {
364 PrintF(" (");
365 if (IsSmi(obj)) {
366 PrintF("smi %d", Smi::ToInt(obj));
367 } else {
368 ShortPrint(obj);
369 }
370 PrintF(")");
371 }
372 }
373 PrintF("\n");
374 cur++;
375 }
376 } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) {
377 disasm::NameConverter converter;
378 disasm::Disassembler dasm(converter);
379 // use a reasonably large buffer
381
382 uint8_t* prev = nullptr;
383 uint8_t* cur = nullptr;
384 uint8_t* end = nullptr;
385
386 if (argc == 1) {
387 cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
388 end = cur + (10 * kInstrSize);
389 } else if (argc == 2) {
390 int regnum = Registers::Number(arg1);
391 if (regnum != kNoRegister || strncmp(arg1, "0x", 2) == 0) {
392 // The argument is an address or a register name.
394 if (GetValue(arg1, &value)) {
395 cur = reinterpret_cast<uint8_t*>(value);
396 // Disassemble 10 instructions at <arg1>.
397 end = cur + (10 * kInstrSize);
398 }
399 } else {
400 // The argument is the number of instructions.
402 if (GetValue(arg1, &value)) {
403 cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
404 // Disassemble <arg1> instructions.
405 end = cur + (value * kInstrSize);
406 }
407 }
408 } else {
409 int32_t value1;
410 int32_t value2;
411 if (GetValue(arg1, &value1) && GetValue(arg2, &value2)) {
412 cur = reinterpret_cast<uint8_t*>(value1);
413 end = cur + (value2 * kInstrSize);
414 }
415 }
416
417 while (cur < end) {
418 prev = cur;
419 cur += dasm.InstructionDecode(buffer, cur);
420 PrintF(" 0x%08" V8PRIxPTR " %s\n", reinterpret_cast<intptr_t>(prev),
421 buffer.begin());
422 }
423 } else if (strcmp(cmd, "gdb") == 0) {
424 PrintF("relinquishing control to gdb\n");
426 PrintF("regaining control from gdb\n");
427 } else if (strcmp(cmd, "break") == 0) {
428 if (argc == 2) {
430 if (GetValue(arg1, &value)) {
431 if (!SetBreakpoint(reinterpret_cast<Instruction*>(value))) {
432 PrintF("setting breakpoint failed\n");
433 }
434 } else {
435 PrintF("%s unrecognized\n", arg1);
436 }
437 } else {
438 PrintF("break <address>\n");
439 }
440 } else if (strcmp(cmd, "backtrace") == 0 || strcmp(cmd, "bt") == 0) {
441 int32_t pc = sim_->get_pc();
442 int32_t lr = sim_->get_register(Simulator::lr);
443 int32_t sp = sim_->get_register(Simulator::sp);
444 int32_t fp = sim_->get_register(Simulator::fp);
445
446 int i = 0;
447 while (true) {
448 PrintF("#%d: 0x%08x (sp=0x%08x, fp=0x%08x)\n", i, pc, sp, fp);
449 pc = lr;
450 sp = fp;
451 if (pc == Simulator::end_sim_pc) {
452 break;
453 }
454 lr = *(reinterpret_cast<int32_t*>(fp) + 1);
455 fp = *reinterpret_cast<int32_t*>(fp);
456 i++;
457 if (i > 100) {
458 PrintF("Too many frames\n");
459 break;
460 }
461 }
462 } else if (strcmp(cmd, "del") == 0) {
463 DeleteBreakpoint();
464 } else if (strcmp(cmd, "flags") == 0) {
465 PrintF("N flag: %d; ", sim_->n_flag_);
466 PrintF("Z flag: %d; ", sim_->z_flag_);
467 PrintF("C flag: %d; ", sim_->c_flag_);
468 PrintF("V flag: %d\n", sim_->v_flag_);
469 PrintF("INVALID OP flag: %d; ", sim_->inv_op_vfp_flag_);
470 PrintF("DIV BY ZERO flag: %d; ", sim_->div_zero_vfp_flag_);
471 PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
472 PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
473 PrintF("INEXACT flag: %d;\n", sim_->inexact_vfp_flag_);
474 } else if (strcmp(cmd, "stop") == 0) {
476 intptr_t stop_pc = sim_->get_pc() - kInstrSize;
477 Instruction* stop_instr = reinterpret_cast<Instruction*>(stop_pc);
478 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
479 // Remove the current stop.
480 if (stop_instr->IsStop()) {
481 SetInstructionBitsInCodeSpace(stop_instr, kNopInstr,
482 sim_->isolate_->heap());
483 } else {
484 PrintF("Not at debugger stop.\n");
485 }
486 } else if (argc == 3) {
487 // Print information about all/the specified breakpoint(s).
488 if (strcmp(arg1, "info") == 0) {
489 if (strcmp(arg2, "all") == 0) {
490 PrintF("Stop information:\n");
491 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
492 sim_->PrintStopInfo(i);
493 }
494 } else if (GetValue(arg2, &value)) {
495 sim_->PrintStopInfo(value);
496 } else {
497 PrintF("Unrecognized argument.\n");
498 }
499 } else if (strcmp(arg1, "enable") == 0) {
500 // Enable all/the specified breakpoint(s).
501 if (strcmp(arg2, "all") == 0) {
502 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
503 sim_->EnableStop(i);
504 }
505 } else if (GetValue(arg2, &value)) {
506 sim_->EnableStop(value);
507 } else {
508 PrintF("Unrecognized argument.\n");
509 }
510 } else if (strcmp(arg1, "disable") == 0) {
511 // Disable all/the specified breakpoint(s).
512 if (strcmp(arg2, "all") == 0) {
513 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
514 sim_->DisableStop(i);
515 }
516 } else if (GetValue(arg2, &value)) {
517 sim_->DisableStop(value);
518 } else {
519 PrintF("Unrecognized argument.\n");
520 }
521 }
522 } else {
523 PrintF("Wrong usage. Use help command for more information.\n");
524 }
525 } else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) {
526 sim_->ToggleInstructionTracing();
527 PrintF("Trace of executed instructions is %s\n",
528 sim_->InstructionTracingEnabled() ? "on" : "off");
529 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
530 PrintF("cont\n");
531 PrintF(" continue execution (alias 'c')\n");
532 PrintF("stepi\n");
533 PrintF(" step one instruction (alias 'si')\n");
534 PrintF("print <register>\n");
535 PrintF(" print register content (alias 'p')\n");
536 PrintF(" use register name 'all' to print all registers\n");
537 PrintF(" add argument 'fp' to print register pair double values\n");
538 PrintF("printobject <register>\n");
539 PrintF(" print an object from a register (alias 'po')\n");
540 PrintF("flags\n");
541 PrintF(" print flags\n");
542 PrintF("stack [<words>]\n");
543 PrintF(" dump stack content, default dump 10 words)\n");
544 PrintF("mem <address> [<words>]\n");
545 PrintF(" dump memory content, default dump 10 words)\n");
546 PrintF("dump [<words>]\n");
547 PrintF(
548 " dump memory content without pretty printing JS objects, default "
549 "dump 10 words)\n");
550 PrintF("disasm [<instructions>]\n");
551 PrintF("disasm [<address/register>]\n");
552 PrintF("disasm [[<address/register>] <instructions>]\n");
553 PrintF(" disassemble code, default is 10 instructions\n");
554 PrintF(" from pc (alias 'di')\n");
555 PrintF("gdb\n");
556 PrintF(" enter gdb\n");
557 PrintF("break <address>\n");
558 PrintF(" set a break point on the address\n");
559 PrintF("backtrace / bt\n");
560 PrintF(" Walk the frame pointers, dumping the pc/sp/fp for each frame.\n");
561 PrintF("del\n");
562 PrintF(" delete the breakpoint\n");
563 PrintF("trace (alias 't')\n");
564 PrintF(" toogle the tracing of all executed statements\n");
565 PrintF("stop feature:\n");
566 PrintF(" Description:\n");
567 PrintF(" Stops are debug instructions inserted by\n");
568 PrintF(" the Assembler::stop() function.\n");
569 PrintF(" When hitting a stop, the Simulator will\n");
570 PrintF(" stop and give control to the ArmDebugger.\n");
571 PrintF(" The first %d stop codes are watched:\n",
572 Simulator::kNumOfWatchedStops);
573 PrintF(" - They can be enabled / disabled: the Simulator\n");
574 PrintF(" will / won't stop when hitting them.\n");
575 PrintF(" - The Simulator keeps track of how many times they \n");
576 PrintF(" are met. (See the info command.) Going over a\n");
577 PrintF(" disabled stop still increases its counter. \n");
578 PrintF(" Commands:\n");
579 PrintF(" stop info all/<code> : print infos about number <code>\n");
580 PrintF(" or all stop(s).\n");
581 PrintF(" stop enable/disable all/<code> : enables / disables\n");
582 PrintF(" all or number <code> stop(s)\n");
583 PrintF(" stop unstop\n");
584 PrintF(" ignore the stop instruction at the current location\n");
585 PrintF(" from now on\n");
586 } else {
587 PrintF("Unknown command: %s\n", cmd);
588 }
589 return false;
590
591#undef COMMAND_SIZE
592#undef ARG_SIZE
593
594#undef STR
595#undef XSTR
596}
597
598bool Simulator::InstructionTracingEnabled() { return instruction_tracing_; }
599
600void Simulator::ToggleInstructionTracing() {
601 instruction_tracing_ = !instruction_tracing_;
602}
603
604bool Simulator::ICacheMatch(void* one, void* two) {
605 DCHECK_EQ(reinterpret_cast<intptr_t>(one) & CachePage::kPageMask, 0);
606 DCHECK_EQ(reinterpret_cast<intptr_t>(two) & CachePage::kPageMask, 0);
607 return one == two;
608}
609
610static uint32_t ICacheHash(void* key) {
611 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)) >> 2;
612}
613
614static bool AllOnOnePage(uintptr_t start, int size) {
615 intptr_t start_page = (start & ~CachePage::kPageMask);
616 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
617 return start_page == end_page;
618}
619
620void Simulator::SetRedirectInstruction(Instruction* instruction) {
621 instruction->SetInstructionBits(al | (0xF * B24) | kCallRtRedirected);
622}
623
624void Simulator::FlushICache(base::CustomMatcherHashMap* i_cache,
625 void* start_addr, size_t size) {
626 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
627 int intra_line = (start & CachePage::kLineMask);
628 start -= intra_line;
629 size += intra_line;
630 size = ((size - 1) | CachePage::kLineMask) + 1;
631 int offset = (start & CachePage::kPageMask);
632 while (!AllOnOnePage(start, size - 1)) {
633 int bytes_to_flush = CachePage::kPageSize - offset;
634 FlushOnePage(i_cache, start, bytes_to_flush);
635 start += bytes_to_flush;
636 size -= bytes_to_flush;
637 DCHECK_EQ(0, start & CachePage::kPageMask);
638 offset = 0;
639 }
640 if (size != 0) {
641 FlushOnePage(i_cache, start, size);
642 }
643}
644
645CachePage* Simulator::GetCachePage(base::CustomMatcherHashMap* i_cache,
646 void* page) {
647 base::HashMap::Entry* entry = i_cache->LookupOrInsert(page, ICacheHash(page));
648 if (entry->value == nullptr) {
649 CachePage* new_page = new CachePage();
650 entry->value = new_page;
651 }
652 return reinterpret_cast<CachePage*>(entry->value);
653}
654
655// Flush from start up to and not including start + size.
656void Simulator::FlushOnePage(base::CustomMatcherHashMap* i_cache,
657 intptr_t start, int size) {
658 DCHECK_LE(size, CachePage::kPageSize);
659 DCHECK(AllOnOnePage(start, size - 1));
660 DCHECK_EQ(start & CachePage::kLineMask, 0);
661 DCHECK_EQ(size & CachePage::kLineMask, 0);
662 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
663 int offset = (start & CachePage::kPageMask);
664 CachePage* cache_page = GetCachePage(i_cache, page);
665 char* valid_bytemap = cache_page->ValidityByte(offset);
666 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
667}
668
669void Simulator::CheckICache(base::CustomMatcherHashMap* i_cache,
670 Instruction* instr) {
671 intptr_t address = reinterpret_cast<intptr_t>(instr);
672 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
673 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
674 int offset = (address & CachePage::kPageMask);
675 CachePage* cache_page = GetCachePage(i_cache, page);
676 char* cache_valid_byte = cache_page->ValidityByte(offset);
677 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
678 char* cached_line = cache_page->CachedData(offset & ~CachePage::kLineMask);
679 if (cache_hit) {
680 // Check that the data in memory matches the contents of the I-cache.
681 CHECK_EQ(0, memcmp(reinterpret_cast<void*>(instr),
682 cache_page->CachedData(offset), kInstrSize));
683 } else {
684 // Cache miss. Load memory into the cache.
685 memcpy(cached_line, line, CachePage::kLineLength);
686 *cache_valid_byte = CachePage::LINE_VALID;
687 }
688}
689
690Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
691 // Set up simulator support first. Some of this information is needed to
692 // setup the architecture state.
693 stack_ = reinterpret_cast<uint8_t*>(base::Malloc(kAllocatedStackSize));
694 pc_modified_ = false;
695 icount_ = 0;
696 break_pc_ = nullptr;
697 break_instr_ = 0;
698
699 // Set up architecture state.
700 // All registers are initialized to zero to start with.
701 for (int i = 0; i < num_registers; i++) {
702 registers_[i] = 0;
703 }
704 n_flag_ = false;
705 z_flag_ = false;
706 c_flag_ = false;
707 v_flag_ = false;
708
709 // Initializing VFP registers.
710 // All registers are initialized to zero to start with
711 // even though s_registers_ & d_registers_ share the same
712 // physical registers in the target.
713 for (int i = 0; i < num_d_registers * 2; i++) {
714 vfp_registers_[i] = 0;
715 }
716 n_flag_FPSCR_ = false;
717 z_flag_FPSCR_ = false;
718 c_flag_FPSCR_ = false;
719 v_flag_FPSCR_ = false;
720 FPSCR_rounding_mode_ = RN;
721 FPSCR_default_NaN_mode_ = false;
722
723 inv_op_vfp_flag_ = false;
724 div_zero_vfp_flag_ = false;
725 overflow_vfp_flag_ = false;
726 underflow_vfp_flag_ = false;
727 inexact_vfp_flag_ = false;
728
729 // The sp is initialized to point to the bottom (high address) of the
730 // usable stack area.
731 registers_[sp] = StackBase();
732 // The lr and pc are initialized to a known bad value that will cause an
733 // access violation if the simulator ever tries to execute it.
734 registers_[pc] = bad_lr;
735 registers_[lr] = bad_lr;
736
737 last_debugger_input_ = nullptr;
738
739 global_monitor_ = GlobalMonitor::Get();
740 global_monitor_->PrependProcessor(&global_monitor_processor_);
741
742 // Enabling deadlock detection while simulating is too slow.
743 SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kIgnore);
744}
745
746Simulator::~Simulator() {
747 global_monitor_->RemoveProcessor(&global_monitor_processor_);
748 base::Free(stack_);
749}
750
751// Get the active Simulator for the current thread.
752Simulator* Simulator::current(Isolate* isolate) {
754 isolate->FindOrAllocatePerThreadDataForThisThread();
755 DCHECK_NOT_NULL(isolate_data);
756
757 Simulator* sim = isolate_data->simulator();
758 if (sim == nullptr) {
759 // TODO(146): delete the simulator object when a thread/isolate goes away.
760 sim = new Simulator(isolate);
761 isolate_data->set_simulator(sim);
762 }
763 return sim;
764}
765
766// Sets the register in the architecture state. It will also deal with updating
767// Simulator internal state for special registers such as PC.
768void Simulator::set_register(int reg, int32_t value) {
769 DCHECK((reg >= 0) && (reg < num_registers));
770 if (reg == pc) {
771 pc_modified_ = true;
772 }
774}
775
776// Get the register from the architecture state. This function does handle
777// the special case of accessing the PC register.
778int32_t Simulator::get_register(int reg) const {
779 DCHECK((reg >= 0) && (reg < num_registers));
780 // Stupid code added to avoid bug in GCC.
781 // See: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
782 if (reg >= num_registers) return 0;
783 // End stupid code.
784 return registers_[reg] + ((reg == pc) ? Instruction::kPcLoadDelta : 0);
785}
786
787double Simulator::get_double_from_register_pair(int reg) {
788 DCHECK((reg >= 0) && (reg < num_registers) && ((reg % 2) == 0));
789
790 double dm_val = 0.0;
791 // Read the bits from the unsigned integer register_[] array
792 // into the double precision floating point value and return it.
793 char buffer[2 * sizeof(vfp_registers_[0])];
794 memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
795 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
796 return (dm_val);
797}
798
799void Simulator::set_register_pair_from_double(int reg, double* value) {
800 DCHECK((reg >= 0) && (reg < num_registers) && ((reg % 2) == 0));
801 memcpy(registers_ + reg, value, sizeof(*value));
802}
803
804void Simulator::set_dw_register(int dreg, const int* dbl) {
805 DCHECK((dreg >= 0) && (dreg < num_d_registers));
806 registers_[dreg] = dbl[0];
807 registers_[dreg + 1] = dbl[1];
808}
809
810void Simulator::get_d_register(int dreg, uint64_t* value) {
811 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::SupportedRegisterCount()));
812 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value));
813}
814
815void Simulator::set_d_register(int dreg, const uint64_t* value) {
816 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::SupportedRegisterCount()));
817 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value));
818}
819
820void Simulator::get_d_register(int dreg, uint32_t* value) {
821 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::SupportedRegisterCount()));
822 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value) * 2);
823}
824
825void Simulator::set_d_register(int dreg, const uint32_t* value) {
826 DCHECK((dreg >= 0) && (dreg < DwVfpRegister::SupportedRegisterCount()));
827 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value) * 2);
828}
829
830template <typename T, int SIZE>
831void Simulator::get_neon_register(int reg, T (&value)[SIZE / sizeof(T)]) {
832 DCHECK(SIZE == kSimd128Size || SIZE == kDoubleSize);
833 DCHECK_LE(0, reg);
834 DCHECK_GT(SIZE == kSimd128Size ? num_q_registers : num_d_registers, reg);
835 memcpy(value, vfp_registers_ + reg * (SIZE / 4), SIZE);
836}
837
838template <typename T, int SIZE>
839void Simulator::set_neon_register(int reg, const T (&value)[SIZE / sizeof(T)]) {
840 DCHECK(SIZE == kSimd128Size || SIZE == kDoubleSize);
841 DCHECK_LE(0, reg);
842 DCHECK_GT(SIZE == kSimd128Size ? num_q_registers : num_d_registers, reg);
843 memcpy(vfp_registers_ + reg * (SIZE / 4), value, SIZE);
844}
845
846// Raw access to the PC register.
847void Simulator::set_pc(int32_t value) {
848 pc_modified_ = true;
850}
851
852bool Simulator::has_bad_pc() const {
853 return ((registers_[pc] == bad_lr) || (registers_[pc] == end_sim_pc));
854}
855
856// Raw access to the PC register without the special adjustment when reading.
857int32_t Simulator::get_pc() const { return registers_[pc]; }
858
859// Getting from and setting into VFP registers.
860void Simulator::set_s_register(int sreg, unsigned int value) {
861 DCHECK((sreg >= 0) && (sreg < num_s_registers));
862 vfp_registers_[sreg] = value;
863}
864
865unsigned int Simulator::get_s_register(int sreg) const {
866 DCHECK((sreg >= 0) && (sreg < num_s_registers));
867 return vfp_registers_[sreg];
868}
869
870template <class InputType, int register_size>
871void Simulator::SetVFPRegister(int reg_index, const InputType& value) {
872 unsigned bytes = register_size * sizeof(vfp_registers_[0]);
873 DCHECK_EQ(sizeof(InputType), bytes);
874 DCHECK_GE(reg_index, 0);
875 if (register_size == 1) DCHECK(reg_index < num_s_registers);
876 if (register_size == 2)
877 DCHECK(reg_index < DwVfpRegister::SupportedRegisterCount());
878
879 memcpy(&vfp_registers_[reg_index * register_size], &value, bytes);
880}
881
882template <class ReturnType, int register_size>
883ReturnType Simulator::GetFromVFPRegister(int reg_index) {
884 unsigned bytes = register_size * sizeof(vfp_registers_[0]);
885 DCHECK_EQ(sizeof(ReturnType), bytes);
886 DCHECK_GE(reg_index, 0);
887 if (register_size == 1) DCHECK(reg_index < num_s_registers);
888 if (register_size == 2)
889 DCHECK(reg_index < DwVfpRegister::SupportedRegisterCount());
890
891 ReturnType value;
892 memcpy(&value, &vfp_registers_[register_size * reg_index], bytes);
893 return value;
894}
895
896void Simulator::SetSpecialRegister(SRegisterFieldMask reg_and_mask,
897 uint32_t value) {
898 // Only CPSR_f is implemented. Of that, only N, Z, C and V are implemented.
899 if ((reg_and_mask == CPSR_f) && ((value & ~kSpecialCondition) == 0)) {
900 n_flag_ = ((value & (1 << 31)) != 0);
901 z_flag_ = ((value & (1 << 30)) != 0);
902 c_flag_ = ((value & (1 << 29)) != 0);
903 v_flag_ = ((value & (1 << 28)) != 0);
904 } else {
906 }
907}
908
909uint32_t Simulator::GetFromSpecialRegister(SRegister reg) {
910 uint32_t result = 0;
911 // Only CPSR_f is implemented.
912 if (reg == CPSR) {
913 if (n_flag_) result |= (1 << 31);
914 if (z_flag_) result |= (1 << 30);
915 if (c_flag_) result |= (1 << 29);
916 if (v_flag_) result |= (1 << 28);
917 } else {
919 }
920 return result;
921}
922
923// Runtime FP routines take:
924// - two double arguments
925// - one double argument and zero or one integer arguments.
926// All are consructed here from r0-r3 or d0, d1 and r0.
927void Simulator::GetFpArgs(double* x, double* y, int32_t* z) {
928 if (use_eabi_hardfloat()) {
929 *x = get_double_from_d_register(0).get_scalar();
930 *y = get_double_from_d_register(1).get_scalar();
931 *z = get_register(0);
932 } else {
933 // Registers 0 and 1 -> x.
934 *x = get_double_from_register_pair(0);
935 // Register 2 and 3 -> y.
936 *y = get_double_from_register_pair(2);
937 // Register 2 -> z
938 *z = get_register(2);
939 }
940}
941
942// The return value is either in r0/r1 or d0.
943void Simulator::SetFpResult(const double& result) {
944 if (use_eabi_hardfloat()) {
945 char buffer[2 * sizeof(vfp_registers_[0])];
946 memcpy(buffer, &result, sizeof(buffer));
947 // Copy result to d0.
948 memcpy(vfp_registers_, buffer, sizeof(buffer));
949 } else {
950 char buffer[2 * sizeof(registers_[0])];
951 memcpy(buffer, &result, sizeof(buffer));
952 // Copy result to r0 and r1.
953 memcpy(registers_, buffer, sizeof(buffer));
954 }
955}
956
957void Simulator::TrashCallerSaveRegisters() {
958 // Return registers.
959 registers_[0] = 0x50BAD4U;
960 registers_[1] = 0x50BAD4U;
961 // Caller-saved registers.
962 registers_[2] = 0x50BAD4U;
963 registers_[3] = 0x50BAD4U;
964 registers_[12] = 0x50BAD4U;
965 // This value is a NaN in both 32-bit and 64-bit FP.
966 static const uint64_t v = 0x7ff000007f801000UL;
967 // d0 - d7 are caller-saved.
968 for (int i = 0; i < 8; i++) {
969 set_d_register(i, &v);
970 }
971 if (DoubleRegister::SupportedRegisterCount() > 16) {
972 // d16 - d31 (if supported) are caller-saved.
973 for (int i = 16; i < 32; i++) {
974 set_d_register(i, &v);
975 }
976 }
977}
978
979int Simulator::ReadW(int32_t addr) {
980 // All supported ARM targets allow unaligned accesses, so we don't need to
981 // check the alignment here.
982 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
983 local_monitor_.NotifyLoad(addr);
984 return base::ReadUnalignedValue<intptr_t>(addr);
985}
986
987int Simulator::ReadExW(int32_t addr) {
988 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
989 local_monitor_.NotifyLoadExcl(addr, TransactionSize::Word);
990 global_monitor_->NotifyLoadExcl_Locked(addr, &global_monitor_processor_);
991 return base::ReadUnalignedValue<intptr_t>(addr);
992}
993
994void Simulator::WriteW(int32_t addr, int value) {
995 // All supported ARM targets allow unaligned accesses, so we don't need to
996 // check the alignment here.
997 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
998 local_monitor_.NotifyStore(addr);
999 global_monitor_->NotifyStore_Locked(addr, &global_monitor_processor_);
1000 base::WriteUnalignedValue<intptr_t>(addr, value);
1001}
1002
1003int Simulator::WriteExW(int32_t addr, int value) {
1004 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1005 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Word) &&
1006 global_monitor_->NotifyStoreExcl_Locked(addr,
1007 &global_monitor_processor_)) {
1008 base::WriteUnalignedValue<intptr_t>(addr, value);
1009 return 0;
1010 } else {
1011 return 1;
1012 }
1013}
1014
1015uint16_t Simulator::ReadHU(int32_t addr) {
1016 // All supported ARM targets allow unaligned accesses, so we don't need to
1017 // check the alignment here.
1018 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1019 local_monitor_.NotifyLoad(addr);
1020 return base::ReadUnalignedValue<uint16_t>(addr);
1021}
1022
1023int16_t Simulator::ReadH(int32_t addr) {
1024 // All supported ARM targets allow unaligned accesses, so we don't need to
1025 // check the alignment here.
1026 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1027 local_monitor_.NotifyLoad(addr);
1028 return base::ReadUnalignedValue<int16_t>(addr);
1029}
1030
1031uint16_t Simulator::ReadExHU(int32_t addr) {
1032 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1033 local_monitor_.NotifyLoadExcl(addr, TransactionSize::HalfWord);
1034 global_monitor_->NotifyLoadExcl_Locked(addr, &global_monitor_processor_);
1035 return base::ReadUnalignedValue<uint16_t>(addr);
1036}
1037
1038void Simulator::WriteH(int32_t addr, uint16_t value) {
1039 // All supported ARM targets allow unaligned accesses, so we don't need to
1040 // check the alignment here.
1041 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1042 local_monitor_.NotifyStore(addr);
1043 global_monitor_->NotifyStore_Locked(addr, &global_monitor_processor_);
1044 base::WriteUnalignedValue(addr, value);
1045}
1046
1047void Simulator::WriteH(int32_t addr, int16_t value) {
1048 // All supported ARM targets allow unaligned accesses, so we don't need to
1049 // check the alignment here.
1050 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1051 local_monitor_.NotifyStore(addr);
1052 global_monitor_->NotifyStore_Locked(addr, &global_monitor_processor_);
1053 base::WriteUnalignedValue(addr, value);
1054}
1055
1056int Simulator::WriteExH(int32_t addr, uint16_t value) {
1057 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1058 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::HalfWord) &&
1059 global_monitor_->NotifyStoreExcl_Locked(addr,
1060 &global_monitor_processor_)) {
1061 base::WriteUnalignedValue(addr, value);
1062 return 0;
1063 } else {
1064 return 1;
1065 }
1066}
1067
1068uint8_t Simulator::ReadBU(int32_t addr) {
1069 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1070 local_monitor_.NotifyLoad(addr);
1071 return base::ReadUnalignedValue<uint8_t>(addr);
1072}
1073
1074int8_t Simulator::ReadB(int32_t addr) {
1075 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1076 local_monitor_.NotifyLoad(addr);
1077 return base::ReadUnalignedValue<int8_t>(addr);
1078}
1079
1080uint8_t Simulator::ReadExBU(int32_t addr) {
1081 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1082 local_monitor_.NotifyLoadExcl(addr, TransactionSize::Byte);
1083 global_monitor_->NotifyLoadExcl_Locked(addr, &global_monitor_processor_);
1084 return base::ReadUnalignedValue<uint8_t>(addr);
1085}
1086
1087void Simulator::WriteB(int32_t addr, uint8_t value) {
1088 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1089 local_monitor_.NotifyStore(addr);
1090 global_monitor_->NotifyStore_Locked(addr, &global_monitor_processor_);
1091 base::WriteUnalignedValue(addr, value);
1092}
1093
1094void Simulator::WriteB(int32_t addr, int8_t value) {
1095 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1096 local_monitor_.NotifyStore(addr);
1097 global_monitor_->NotifyStore_Locked(addr, &global_monitor_processor_);
1098 base::WriteUnalignedValue(addr, value);
1099}
1100
1101int Simulator::WriteExB(int32_t addr, uint8_t value) {
1102 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1103 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Byte) &&
1104 global_monitor_->NotifyStoreExcl_Locked(addr,
1105 &global_monitor_processor_)) {
1106 base::WriteUnalignedValue(addr, value);
1107 return 0;
1108 } else {
1109 return 1;
1110 }
1111}
1112
1113int32_t* Simulator::ReadDW(int32_t addr) {
1114 // All supported ARM targets allow unaligned accesses, so we don't need to
1115 // check the alignment here.
1116 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1117 local_monitor_.NotifyLoad(addr);
1118 return reinterpret_cast<int32_t*>(addr);
1119}
1120
1121int32_t* Simulator::ReadExDW(int32_t addr) {
1122 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1123 local_monitor_.NotifyLoadExcl(addr, TransactionSize::DoubleWord);
1124 global_monitor_->NotifyLoadExcl_Locked(addr, &global_monitor_processor_);
1125 return reinterpret_cast<int32_t*>(addr);
1126}
1127
1128void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) {
1129 // All supported ARM targets allow unaligned accesses, so we don't need to
1130 // check the alignment here.
1131 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1132 local_monitor_.NotifyStore(addr);
1133 global_monitor_->NotifyStore_Locked(addr, &global_monitor_processor_);
1134 base::WriteUnalignedValue(addr, value1);
1135 base::WriteUnalignedValue(addr + sizeof(value1), value2);
1136}
1137
1138int Simulator::WriteExDW(int32_t addr, int32_t value1, int32_t value2) {
1139 GlobalMonitor::SimulatorMutex lock_guard(global_monitor_);
1140 if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::DoubleWord) &&
1141 global_monitor_->NotifyStoreExcl_Locked(addr,
1142 &global_monitor_processor_)) {
1143 base::WriteUnalignedValue(addr, value1);
1144 base::WriteUnalignedValue(addr + sizeof(value1), value2);
1145 return 0;
1146 } else {
1147 return 1;
1148 }
1149}
1150
1151// Returns the limit of the stack area to enable checking for stack overflows.
1152uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
1153 // The simulator uses a separate JS stack. If we have exhausted the C stack,
1154 // we also drop down the JS limit to reflect the exhaustion on the JS stack.
1155 if (base::Stack::GetCurrentStackPosition() < c_limit) {
1156 return reinterpret_cast<uintptr_t>(get_sp());
1157 }
1158
1159 // Otherwise the limit is the JS stack. Leave a safety margin to prevent
1160 // overrunning the stack when pushing values.
1161 return reinterpret_cast<uintptr_t>(stack_) + kAdditionalStackMargin;
1162}
1163
1164uintptr_t Simulator::StackBase() const {
1165 return reinterpret_cast<uintptr_t>(stack_) + kUsableStackSize;
1166}
1167
1168base::Vector<uint8_t> Simulator::GetCentralStackView() const {
1169 // We do not add an additional safety margin as above in
1170 // Simulator::StackLimit, as this is currently only used in wasm::StackMemory,
1171 // which adds its own margin.
1172 return base::VectorOf(stack_, kUsableStackSize);
1173}
1174
1175void Simulator::IterateRegistersAndStack(::heap::base::StackVisitor* visitor) {
1176 for (int i = 0; i < num_registers; ++i) {
1177 visitor->VisitPointer(reinterpret_cast<const void*>(get_register(i)));
1178 }
1179
1180 for (const void* const* current =
1181 reinterpret_cast<const void* const*>(get_sp());
1183 const void* address = *current;
1184 if (address == nullptr) {
1185 continue;
1186 }
1187 visitor->VisitPointer(address);
1188 }
1189}
1190
1191// Unsupported instructions use Format to print an error and stop execution.
1192void Simulator::Format(Instruction* instr, const char* format) {
1193 PrintF("Simulator found unsupported instruction:\n 0x%08" V8PRIxPTR ": %s\n",
1194 reinterpret_cast<intptr_t>(instr), format);
1195 UNIMPLEMENTED();
1196}
1197
1198// Checks if the current instruction should be executed based on its
1199// condition bits.
1200bool Simulator::ConditionallyExecute(Instruction* instr) {
1201 switch (instr->ConditionField()) {
1202 case eq:
1203 return z_flag_;
1204 case ne:
1205 return !z_flag_;
1206 case cs:
1207 return c_flag_;
1208 case cc:
1209 return !c_flag_;
1210 case mi:
1211 return n_flag_;
1212 case pl:
1213 return !n_flag_;
1214 case vs:
1215 return v_flag_;
1216 case vc:
1217 return !v_flag_;
1218 case hi:
1219 return c_flag_ && !z_flag_;
1220 case ls:
1221 return !c_flag_ || z_flag_;
1222 case ge:
1223 return n_flag_ == v_flag_;
1224 case lt:
1225 return n_flag_ != v_flag_;
1226 case gt:
1227 return !z_flag_ && (n_flag_ == v_flag_);
1228 case le:
1229 return z_flag_ || (n_flag_ != v_flag_);
1230 case al:
1231 return true;
1232 default:
1233 UNREACHABLE();
1234 }
1235}
1236
1237// Calculate and set the Negative and Zero flags.
1238void Simulator::SetNZFlags(int32_t val) {
1239 n_flag_ = (val < 0);
1240 z_flag_ = (val == 0);
1241}
1242
1243// Set the Carry flag.
1244void Simulator::SetCFlag(bool val) { c_flag_ = val; }
1245
1246// Set the oVerflow flag.
1247void Simulator::SetVFlag(bool val) { v_flag_ = val; }
1248
1249// Calculate C flag value for additions.
1250bool Simulator::CarryFrom(int32_t left, int32_t right, int32_t carry) {
1251 uint32_t uleft = static_cast<uint32_t>(left);
1252 uint32_t uright = static_cast<uint32_t>(right);
1253 uint32_t urest = 0xFFFFFFFFU - uleft;
1254
1255 return (uright > urest) ||
1256 (carry && (((uright + 1) > urest) || (uright > (urest - 1))));
1257}
1258
1259// Calculate C flag value for subtractions.
1260bool Simulator::BorrowFrom(int32_t left, int32_t right, int32_t carry) {
1261 uint32_t uleft = static_cast<uint32_t>(left);
1262 uint32_t uright = static_cast<uint32_t>(right);
1263
1264 return (uright > uleft) ||
1265 (!carry && (((uright + 1) > uleft) || (uright > (uleft - 1))));
1266}
1267
1268// Calculate V flag value for additions and subtractions.
1269bool Simulator::OverflowFrom(int32_t alu_out, int32_t left, int32_t right,
1270 bool addition) {
1271 bool overflow;
1272 if (addition) {
1273 // operands have the same sign
1274 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
1275 // and operands and result have different sign
1276 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1277 } else {
1278 // operands have different signs
1279 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
1280 // and first operand and result have different signs
1281 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1282 }
1283 return overflow;
1284}
1285
1286// Support for VFP comparisons.
1287void Simulator::Compute_FPSCR_Flags(float val1, float val2) {
1288 if (std::isnan(val1) || std::isnan(val2)) {
1289 n_flag_FPSCR_ = false;
1290 z_flag_FPSCR_ = false;
1291 c_flag_FPSCR_ = true;
1292 v_flag_FPSCR_ = true;
1293 // All non-NaN cases.
1294 } else if (val1 == val2) {
1295 n_flag_FPSCR_ = false;
1296 z_flag_FPSCR_ = true;
1297 c_flag_FPSCR_ = true;
1298 v_flag_FPSCR_ = false;
1299 } else if (val1 < val2) {
1300 n_flag_FPSCR_ = true;
1301 z_flag_FPSCR_ = false;
1302 c_flag_FPSCR_ = false;
1303 v_flag_FPSCR_ = false;
1304 } else {
1305 // Case when (val1 > val2).
1306 n_flag_FPSCR_ = false;
1307 z_flag_FPSCR_ = false;
1308 c_flag_FPSCR_ = true;
1309 v_flag_FPSCR_ = false;
1310 }
1311}
1312
1313void Simulator::Compute_FPSCR_Flags(double val1, double val2) {
1314 if (std::isnan(val1) || std::isnan(val2)) {
1315 n_flag_FPSCR_ = false;
1316 z_flag_FPSCR_ = false;
1317 c_flag_FPSCR_ = true;
1318 v_flag_FPSCR_ = true;
1319 // All non-NaN cases.
1320 } else if (val1 == val2) {
1321 n_flag_FPSCR_ = false;
1322 z_flag_FPSCR_ = true;
1323 c_flag_FPSCR_ = true;
1324 v_flag_FPSCR_ = false;
1325 } else if (val1 < val2) {
1326 n_flag_FPSCR_ = true;
1327 z_flag_FPSCR_ = false;
1328 c_flag_FPSCR_ = false;
1329 v_flag_FPSCR_ = false;
1330 } else {
1331 // Case when (val1 > val2).
1332 n_flag_FPSCR_ = false;
1333 z_flag_FPSCR_ = false;
1334 c_flag_FPSCR_ = true;
1335 v_flag_FPSCR_ = false;
1336 }
1337}
1338
1339void Simulator::Copy_FPSCR_to_APSR() {
1340 n_flag_ = n_flag_FPSCR_;
1341 z_flag_ = z_flag_FPSCR_;
1342 c_flag_ = c_flag_FPSCR_;
1343 v_flag_ = v_flag_FPSCR_;
1344}
1345
1346// Addressing Mode 1 - Data-processing operands:
1347// Get the value based on the shifter_operand with register.
1348int32_t Simulator::GetShiftRm(Instruction* instr, bool* carry_out) {
1349 ShiftOp shift = instr->ShiftField();
1350 int shift_amount = instr->ShiftAmountValue();
1351 int32_t result = get_register(instr->RmValue());
1352 if (instr->Bit(4) == 0) {
1353 // by immediate
1354 if ((shift == ROR) && (shift_amount == 0)) {
1355 UNIMPLEMENTED();
1356 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
1357 shift_amount = 32;
1358 }
1359 switch (shift) {
1360 case ASR: {
1361 if (shift_amount == 0) {
1362 if (result < 0) {
1363 result = 0xFFFFFFFF;
1364 *carry_out = true;
1365 } else {
1366 result = 0;
1367 *carry_out = false;
1368 }
1369 } else {
1370 result >>= (shift_amount - 1);
1371 *carry_out = (result & 1) == 1;
1372 result >>= 1;
1373 }
1374 break;
1375 }
1376
1377 case LSL: {
1378 if (shift_amount == 0) {
1379 *carry_out = c_flag_;
1380 } else {
1381 result = static_cast<uint32_t>(result) << (shift_amount - 1);
1382 *carry_out = (result < 0);
1383 result = static_cast<uint32_t>(result) << 1;
1384 }
1385 break;
1386 }
1387
1388 case LSR: {
1389 if (shift_amount == 0) {
1390 result = 0;
1391 *carry_out = c_flag_;
1392 } else {
1393 uint32_t uresult = static_cast<uint32_t>(result);
1394 uresult >>= (shift_amount - 1);
1395 *carry_out = (uresult & 1) == 1;
1396 uresult >>= 1;
1397 result = static_cast<int32_t>(uresult);
1398 }
1399 break;
1400 }
1401
1402 case ROR: {
1403 if (shift_amount == 0) {
1404 *carry_out = c_flag_;
1405 } else {
1406 result = base::bits::RotateRight32(result, shift_amount);
1407 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
1408 }
1409 break;
1410 }
1411
1412 default: {
1413 UNREACHABLE();
1414 }
1415 }
1416 } else {
1417 // by register
1418 int rs = instr->RsValue();
1419 shift_amount = get_register(rs) & 0xFF;
1420 switch (shift) {
1421 case ASR: {
1422 if (shift_amount == 0) {
1423 *carry_out = c_flag_;
1424 } else if (shift_amount < 32) {
1425 result >>= (shift_amount - 1);
1426 *carry_out = (result & 1) == 1;
1427 result >>= 1;
1428 } else {
1429 DCHECK_GE(shift_amount, 32);
1430 if (result < 0) {
1431 *carry_out = true;
1432 result = 0xFFFFFFFF;
1433 } else {
1434 *carry_out = false;
1435 result = 0;
1436 }
1437 }
1438 break;
1439 }
1440
1441 case LSL: {
1442 if (shift_amount == 0) {
1443 *carry_out = c_flag_;
1444 } else if (shift_amount < 32) {
1445 result = static_cast<uint32_t>(result) << (shift_amount - 1);
1446 *carry_out = (result < 0);
1447 result = static_cast<uint32_t>(result) << 1;
1448 } else if (shift_amount == 32) {
1449 *carry_out = (result & 1) == 1;
1450 result = 0;
1451 } else {
1452 DCHECK_GT(shift_amount, 32);
1453 *carry_out = false;
1454 result = 0;
1455 }
1456 break;
1457 }
1458
1459 case LSR: {
1460 if (shift_amount == 0) {
1461 *carry_out = c_flag_;
1462 } else if (shift_amount < 32) {
1463 uint32_t uresult = static_cast<uint32_t>(result);
1464 uresult >>= (shift_amount - 1);
1465 *carry_out = (uresult & 1) == 1;
1466 uresult >>= 1;
1467 result = static_cast<int32_t>(uresult);
1468 } else if (shift_amount == 32) {
1469 *carry_out = (result < 0);
1470 result = 0;
1471 } else {
1472 *carry_out = false;
1473 result = 0;
1474 }
1475 break;
1476 }
1477
1478 case ROR: {
1479 if (shift_amount == 0) {
1480 *carry_out = c_flag_;
1481 } else {
1482 // Avoid undefined behavior. Rotating by multiples of 32 is no-op.
1483 result = base::bits::RotateRight32(result, shift_amount & 31);
1484 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
1485 }
1486 break;
1487 }
1488
1489 default: {
1490 UNREACHABLE();
1491 }
1492 }
1493 }
1494 return result;
1495}
1496
1497// Addressing Mode 1 - Data-processing operands:
1498// Get the value based on the shifter_operand with immediate.
1499int32_t Simulator::GetImm(Instruction* instr, bool* carry_out) {
1500 int rotate = instr->RotateValue() * 2;
1501 int immed8 = instr->Immed8Value();
1502 int imm = base::bits::RotateRight32(immed8, rotate);
1503 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1504 return imm;
1505}
1506
1507static int count_bits(int bit_vector) {
1508 int count = 0;
1509 while (bit_vector != 0) {
1510 if ((bit_vector & 1) != 0) {
1511 count++;
1512 }
1513 bit_vector >>= 1;
1514 }
1515 return count;
1516}
1517
1518int32_t Simulator::ProcessPU(Instruction* instr, int num_regs, int reg_size,
1519 intptr_t* start_address, intptr_t* end_address) {
1520 int rn = instr->RnValue();
1521 int32_t rn_val = get_register(rn);
1522 switch (instr->PUField()) {
1523 case da_x: {
1524 UNIMPLEMENTED();
1525 }
1526 case ia_x: {
1527 *start_address = rn_val;
1528 *end_address = rn_val + (num_regs * reg_size) - reg_size;
1529 rn_val = rn_val + (num_regs * reg_size);
1530 break;
1531 }
1532 case db_x: {
1533 *start_address = rn_val - (num_regs * reg_size);
1534 *end_address = rn_val - reg_size;
1535 rn_val = *start_address;
1536 break;
1537 }
1538 case ib_x: {
1539 *start_address = rn_val + reg_size;
1540 *end_address = rn_val + (num_regs * reg_size);
1541 rn_val = *end_address;
1542 break;
1543 }
1544 default: {
1545 UNREACHABLE();
1546 }
1547 }
1548 return rn_val;
1549}
1550
1551// Addressing Mode 4 - Load and Store Multiple
1552void Simulator::HandleRList(Instruction* instr, bool load) {
1553 int rlist = instr->RlistValue();
1554 int num_regs = count_bits(rlist);
1555
1556 intptr_t start_address = 0;
1557 intptr_t end_address = 0;
1558 int32_t rn_val =
1559 ProcessPU(instr, num_regs, kPointerSize, &start_address, &end_address);
1560
1561 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1562 // Catch null pointers a little earlier.
1563 DCHECK(start_address > 8191 || start_address < 0);
1564 int reg = 0;
1565 while (rlist != 0) {
1566 if ((rlist & 1) != 0) {
1567 if (load) {
1568 set_register(reg, *address);
1569 } else {
1570 *address = get_register(reg);
1571 }
1572 address += 1;
1573 }
1574 reg++;
1575 rlist >>= 1;
1576 }
1577 DCHECK(end_address == ((intptr_t)address) - 4);
1578 if (instr->HasW()) {
1579 set_register(instr->RnValue(), rn_val);
1580 }
1581}
1582
1583// Addressing Mode 6 - Load and Store Multiple Coprocessor registers.
1584void Simulator::HandleVList(Instruction* instr) {
1586 (instr->SzValue() == 0) ? kSinglePrecision : kDoublePrecision;
1587 int operand_size = (precision == kSinglePrecision) ? 4 : 8;
1588
1589 bool load = (instr->VLValue() == 0x1);
1590
1591 int vd;
1592 int num_regs;
1593 vd = instr->VFPDRegValue(precision);
1594 if (precision == kSinglePrecision) {
1595 num_regs = instr->Immed8Value();
1596 } else {
1597 num_regs = instr->Immed8Value() / 2;
1598 }
1599
1600 intptr_t start_address = 0;
1601 intptr_t end_address = 0;
1602 int32_t rn_val =
1603 ProcessPU(instr, num_regs, operand_size, &start_address, &end_address);
1604
1605 intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
1606 for (int reg = vd; reg < vd + num_regs; reg++) {
1607 if (precision == kSinglePrecision) {
1608 if (load) {
1609 set_s_register_from_sinteger(reg,
1610 ReadW(reinterpret_cast<int32_t>(address)));
1611 } else {
1612 WriteW(reinterpret_cast<int32_t>(address),
1613 get_sinteger_from_s_register(reg));
1614 }
1615 address += 1;
1616 } else {
1617 if (load) {
1618 int32_t data[] = {ReadW(reinterpret_cast<int32_t>(address)),
1619 ReadW(reinterpret_cast<int32_t>(address + 1))};
1620 set_d_register(reg, reinterpret_cast<uint32_t*>(data));
1621 } else {
1622 uint32_t data[2];
1623 get_d_register(reg, data);
1624 WriteW(reinterpret_cast<int32_t>(address), data[0]);
1625 WriteW(reinterpret_cast<int32_t>(address + 1), data[1]);
1626 }
1627 address += 2;
1628 }
1629 }
1630 DCHECK(reinterpret_cast<intptr_t>(address) - operand_size == end_address);
1631 if (instr->HasW()) {
1632 set_register(instr->RnValue(), rn_val);
1633 }
1634}
1635
1636// Calls into the V8 runtime are based on this very simple interface.
1637// Note: To be able to return two values from some calls the code in runtime.cc
1638// uses the ObjectPair which is essentially two 32-bit values stuffed into a
1639// 64-bit value. With the code below we assume that all runtime calls return
1640// 64 bits of result. If they don't, the r1 result register contains a bogus
1641// value, which is fine because it is caller-saved.
1642using SimulatorRuntimeCall = int64_t (*)(
1643 int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4,
1644 int32_t arg5, int32_t arg6, int32_t arg7, int32_t arg8, int32_t arg9,
1645 int32_t arg10, int32_t arg11, int32_t arg12, int32_t arg13, int32_t arg14,
1646 int32_t arg15, int32_t arg16, int32_t arg17, int32_t arg18, int32_t arg19);
1647
1648// These prototypes handle the four types of FP calls.
1649using SimulatorRuntimeCompareCall = int64_t (*)(double darg0, double darg1);
1650using SimulatorRuntimeFPFPCall = double (*)(double darg0, double darg1);
1651using SimulatorRuntimeFPCall = double (*)(double darg0);
1652using SimulatorRuntimeFPIntCall = double (*)(double darg0, int32_t arg0);
1653using SimulatorRuntimeIntFPCall = int32_t (*)(double darg0);
1654// Define four args for future flexibility; at the time of this writing only
1655// one is ever used.
1656using SimulatorRuntimeFPTaggedCall = double (*)(int32_t arg0, int32_t arg1,
1657 int32_t arg2, int32_t arg3);
1658
1659// This signature supports direct call in to API function native callback
1660// (refer to InvocationCallback in v8.h).
1661using SimulatorRuntimeDirectApiCall = void (*)(int32_t arg0);
1662
1663// This signature supports direct call to accessor getter callback.
1664using SimulatorRuntimeDirectGetterCall = void (*)(int32_t arg0, int32_t arg1);
1665
1666// Separate for fine-grained UBSan blocklisting. Casting any given C++
1667// function to {SimulatorRuntimeCall} is undefined behavior; but since
1668// the target function can indeed be any function that's exposed via
1669// the "fast C call" mechanism, we can't reconstruct its signature here.
1670int64_t UnsafeGenericFunctionCall(intptr_t function, int32_t arg0, int32_t arg1,
1671 int32_t arg2, int32_t arg3, int32_t arg4,
1672 int32_t arg5, int32_t arg6, int32_t arg7,
1673 int32_t arg8, int32_t arg9, int32_t arg10,
1674 int32_t arg11, int32_t arg12, int32_t arg13,
1675 int32_t arg14, int32_t arg15, int32_t arg16,
1676 int32_t arg17, int32_t arg18, int32_t arg19) {
1677 SimulatorRuntimeCall target =
1678 reinterpret_cast<SimulatorRuntimeCall>(function);
1679 return target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,
1680 arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18,
1681 arg19);
1682}
1683
1684// Software interrupt instructions are used by the simulator to call into the
1685// C-based V8 runtime.
1686void Simulator::SoftwareInterrupt(Instruction* instr) {
1687 int svc = instr->SvcValue();
1688 switch (svc) {
1689 case kCallRtRedirected: {
1690 // Check if stack is aligned. Error if not aligned is reported below to
1691 // include information on the function called.
1692 bool stack_aligned =
1693 (get_register(sp) & (v8_flags.sim_stack_alignment - 1)) == 0;
1694 Redirection* redirection = Redirection::FromInstruction(instr);
1695 int32_t arg0 = get_register(r0);
1696 int32_t arg1 = get_register(r1);
1697 int32_t arg2 = get_register(r2);
1698 int32_t arg3 = get_register(r3);
1699 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
1700 int32_t arg4 = stack_pointer[0];
1701 int32_t arg5 = stack_pointer[1];
1702 int32_t arg6 = stack_pointer[2];
1703 int32_t arg7 = stack_pointer[3];
1704 int32_t arg8 = stack_pointer[4];
1705 int32_t arg9 = stack_pointer[5];
1706 int32_t arg10 = stack_pointer[6];
1707 int32_t arg11 = stack_pointer[7];
1708 int32_t arg12 = stack_pointer[8];
1709 int32_t arg13 = stack_pointer[9];
1710 int32_t arg14 = stack_pointer[10];
1711 int32_t arg15 = stack_pointer[11];
1712 int32_t arg16 = stack_pointer[12];
1713 int32_t arg17 = stack_pointer[13];
1714 int32_t arg18 = stack_pointer[14];
1715 int32_t arg19 = stack_pointer[15];
1716 static_assert(kMaxCParameters == 20);
1717
1718 bool fp_call =
1719 (redirection->type() == ExternalReference::BUILTIN_FP_FP_CALL) ||
1720 (redirection->type() == ExternalReference::BUILTIN_COMPARE_CALL) ||
1721 (redirection->type() == ExternalReference::BUILTIN_FP_CALL) ||
1722 (redirection->type() == ExternalReference::BUILTIN_FP_INT_CALL) ||
1723 (redirection->type() == ExternalReference::BUILTIN_INT_FP_CALL);
1724 // This is dodgy but it works because the C entry stubs are never moved.
1725 // See comment in codegen-arm.cc and bug 1242173.
1726 int32_t saved_lr = get_register(lr);
1727 intptr_t external =
1728 reinterpret_cast<intptr_t>(redirection->external_function());
1729 if (fp_call) {
1730 double dval0, dval1; // one or two double parameters
1731 int32_t ival; // zero or one integer parameters
1732 int64_t iresult = 0; // integer return value
1733 double dresult = 0; // double return value
1734 GetFpArgs(&dval0, &dval1, &ival);
1735 if (InstructionTracingEnabled() || !stack_aligned) {
1736 SimulatorRuntimeCall generic_target =
1737 reinterpret_cast<SimulatorRuntimeCall>(external);
1738 switch (redirection->type()) {
1739 case ExternalReference::BUILTIN_FP_FP_CALL:
1740 case ExternalReference::BUILTIN_COMPARE_CALL:
1741 PrintF("Call to host function at %p with args %f, %f",
1742 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
1743 dval0, dval1);
1744 break;
1745 case ExternalReference::BUILTIN_FP_CALL:
1746 PrintF("Call to host function at %p with arg %f",
1747 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
1748 dval0);
1749 break;
1750 case ExternalReference::BUILTIN_FP_INT_CALL:
1751 PrintF("Call to host function at %p with args %f, %d",
1752 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
1753 dval0, ival);
1754 break;
1755 case ExternalReference::BUILTIN_INT_FP_CALL:
1756 PrintF("Call to host function at %p with args %f",
1757 reinterpret_cast<void*>(FUNCTION_ADDR(generic_target)),
1758 dval0);
1759 break;
1760 default:
1761 UNREACHABLE();
1762 }
1763 if (!stack_aligned) {
1764 PrintF(" with unaligned stack %08x\n", get_register(sp));
1765 }
1766 PrintF("\n");
1767 }
1768 CHECK(stack_aligned);
1769 switch (redirection->type()) {
1770 case ExternalReference::BUILTIN_COMPARE_CALL: {
1771 SimulatorRuntimeCompareCall target =
1772 reinterpret_cast<SimulatorRuntimeCompareCall>(external);
1773 iresult = target(dval0, dval1);
1774#ifdef DEBUG
1775 TrashCallerSaveRegisters();
1776#endif
1777 set_register(r0, static_cast<int32_t>(iresult));
1778 set_register(r1, static_cast<int32_t>(iresult >> 32));
1779 break;
1780 }
1781 case ExternalReference::BUILTIN_FP_FP_CALL: {
1782 SimulatorRuntimeFPFPCall target =
1783 reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
1784 dresult = target(dval0, dval1);
1785#ifdef DEBUG
1786 TrashCallerSaveRegisters();
1787#endif
1788 SetFpResult(dresult);
1789 break;
1790 }
1791 case ExternalReference::BUILTIN_FP_CALL: {
1792 SimulatorRuntimeFPCall target =
1793 reinterpret_cast<SimulatorRuntimeFPCall>(external);
1794 dresult = target(dval0);
1795#ifdef DEBUG
1796 TrashCallerSaveRegisters();
1797#endif
1798 SetFpResult(dresult);
1799 break;
1800 }
1801 case ExternalReference::BUILTIN_FP_INT_CALL: {
1802 SimulatorRuntimeFPIntCall target =
1803 reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
1804 dresult = target(dval0, ival);
1805#ifdef DEBUG
1806 TrashCallerSaveRegisters();
1807#endif
1808 SetFpResult(dresult);
1809 break;
1810 }
1811 case ExternalReference::BUILTIN_INT_FP_CALL: {
1812 SimulatorRuntimeIntFPCall target =
1813 reinterpret_cast<SimulatorRuntimeIntFPCall>(external);
1814 iresult = target(dval0);
1815#ifdef DEBUG
1816 TrashCallerSaveRegisters();
1817#endif
1818 set_register(r0, static_cast<int32_t>(iresult));
1819 break;
1820 }
1821 default:
1822 UNREACHABLE();
1823 }
1824 if (InstructionTracingEnabled()) {
1825 switch (redirection->type()) {
1826 case ExternalReference::BUILTIN_COMPARE_CALL:
1827 case ExternalReference::BUILTIN_INT_FP_CALL:
1828 PrintF("Returned %08x\n", static_cast<int32_t>(iresult));
1829 break;
1830 case ExternalReference::BUILTIN_FP_FP_CALL:
1831 case ExternalReference::BUILTIN_FP_CALL:
1832 case ExternalReference::BUILTIN_FP_INT_CALL:
1833 PrintF("Returned %f\n", dresult);
1834 break;
1835 default:
1836 UNREACHABLE();
1837 }
1838 }
1839 } else if (redirection->type() ==
1840 ExternalReference::BUILTIN_FP_POINTER_CALL) {
1841 if (InstructionTracingEnabled() || !stack_aligned) {
1842 PrintF("Call to host function at %p args %08x",
1843 reinterpret_cast<void*>(external), arg0);
1844 if (!stack_aligned) {
1845 PrintF(" with unaligned stack %08x\n", get_register(sp));
1846 }
1847 PrintF("\n");
1848 }
1849 CHECK(stack_aligned);
1850 SimulatorRuntimeFPTaggedCall target =
1851 reinterpret_cast<SimulatorRuntimeFPTaggedCall>(external);
1852 double dresult = target(arg0, arg1, arg2, arg3);
1853#ifdef DEBUG
1854 TrashCallerSaveRegisters();
1855#endif
1856 SetFpResult(dresult);
1857 if (InstructionTracingEnabled()) {
1858 PrintF("Returned %f\n", dresult);
1859 }
1860 } else if (redirection->type() == ExternalReference::DIRECT_API_CALL) {
1861 // void f(v8::FunctionCallbackInfo&)
1862 if (InstructionTracingEnabled() || !stack_aligned) {
1863 PrintF("Call to host function at %p args %08x",
1864 reinterpret_cast<void*>(external), arg0);
1865 if (!stack_aligned) {
1866 PrintF(" with unaligned stack %08x\n", get_register(sp));
1867 }
1868 PrintF("\n");
1869 }
1870 CHECK(stack_aligned);
1871 SimulatorRuntimeDirectApiCall target =
1872 reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
1873 target(arg0);
1874#ifdef DEBUG
1875 TrashCallerSaveRegisters();
1876#endif
1877 } else if (redirection->type() == ExternalReference::DIRECT_GETTER_CALL) {
1878 // void f(v8::Local<String> property, v8::PropertyCallbackInfo& info)
1879 if (InstructionTracingEnabled() || !stack_aligned) {
1880 PrintF("Call to host function at %p args %08x %08x",
1881 reinterpret_cast<void*>(external), arg0, arg1);
1882 if (!stack_aligned) {
1883 PrintF(" with unaligned stack %08x\n", get_register(sp));
1884 }
1885 PrintF("\n");
1886 }
1887 CHECK(stack_aligned);
1888 SimulatorRuntimeDirectGetterCall target =
1889 reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
1890 target(arg0, arg1);
1891#ifdef DEBUG
1892 TrashCallerSaveRegisters();
1893#endif
1894 } else {
1895 // builtin call.
1896 // FAST_C_CALL is temporarily handled here as well, because we lack
1897 // proper support for direct C calls with FP params in the simulator.
1898 // The generic BUILTIN_CALL path assumes all parameters are passed in
1899 // the GP registers, thus supporting calling the slow callback without
1900 // crashing. The reason for that is that in the mjsunit tests we check
1901 // the `fast_c_api.supports_fp_params` (which is false on non-simulator
1902 // builds for arm/arm64), thus we expect that the slow path will be
1903 // called. And since the slow path passes the arguments as a `const
1904 // FunctionCallbackInfo<Value>&` (which is a GP argument), the call is
1905 // made correctly.
1906 DCHECK(redirection->type() == ExternalReference::BUILTIN_CALL ||
1907 redirection->type() == ExternalReference::BUILTIN_CALL_PAIR ||
1908 redirection->type() == ExternalReference::FAST_C_CALL);
1909 if (InstructionTracingEnabled() || !stack_aligned) {
1910 PrintF(
1911 "Call to host function at %p "
1912 "args %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, "
1913 "%08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x, "
1914 "%08x",
1915 reinterpret_cast<void*>(external), arg0, arg1, arg2, arg3, arg4,
1916 arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14,
1917 arg15, arg16, arg17, arg18, arg19);
1918 if (!stack_aligned) {
1919 PrintF(" with unaligned stack %08x\n", get_register(sp));
1920 }
1921 PrintF("\n");
1922 }
1923 CHECK(stack_aligned);
1924 int64_t result = UnsafeGenericFunctionCall(
1925 external, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
1926 arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18,
1927 arg19);
1928#ifdef DEBUG
1929 TrashCallerSaveRegisters();
1930#endif
1931 int32_t lo_res = static_cast<int32_t>(result);
1932 int32_t hi_res = static_cast<int32_t>(result >> 32);
1933 if (InstructionTracingEnabled()) {
1934 PrintF("Returned %08x\n", lo_res);
1935 }
1936 set_register(r0, lo_res);
1937 set_register(r1, hi_res);
1938 }
1939 set_register(lr, saved_lr);
1940 set_pc(get_register(lr));
1941 break;
1942 }
1943 case kBreakpoint:
1944 ArmDebugger(this).Debug();
1945 break;
1946 // stop uses all codes greater than 1 << 23.
1947 default:
1948 if (svc >= (1 << 23)) {
1949 uint32_t code = svc & kStopCodeMask;
1950 if (isWatchedStop(code)) {
1951 IncreaseStopCounter(code);
1952 }
1953 // Stop if it is enabled, otherwise go on jumping over the stop
1954 // and the message address.
1955 if (isEnabledStop(code)) {
1956 if (code != kMaxStopCode) {
1957 PrintF("Simulator hit stop %u. ", code);
1958 } else {
1959 PrintF("Simulator hit stop. ");
1960 }
1961 DebugAtNextPC();
1962 }
1963 } else {
1964 // This is not a valid svc code.
1965 UNREACHABLE();
1966 }
1967 }
1968}
1969
1970float Simulator::canonicalizeNaN(float value) {
1971 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
1972 // choices" of the ARM Reference Manual.
1973 constexpr uint32_t kDefaultNaN = 0x7FC00000u;
1974 if (FPSCR_default_NaN_mode_ && std::isnan(value)) {
1975 value = base::bit_cast<float>(kDefaultNaN);
1976 }
1977 return value;
1978}
1979
1980Float32 Simulator::canonicalizeNaN(Float32 value) {
1981 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
1982 // choices" of the ARM Reference Manual.
1983 constexpr Float32 kDefaultNaN = Float32::FromBits(0x7FC00000u);
1984 return FPSCR_default_NaN_mode_ && value.is_nan() ? kDefaultNaN : value;
1985}
1986
1987double Simulator::canonicalizeNaN(double value) {
1988 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
1989 // choices" of the ARM Reference Manual.
1990 constexpr uint64_t kDefaultNaN = uint64_t{0x7FF8000000000000};
1991 if (FPSCR_default_NaN_mode_ && std::isnan(value)) {
1992 value = base::bit_cast<double>(kDefaultNaN);
1993 }
1994 return value;
1995}
1996
1997Float64 Simulator::canonicalizeNaN(Float64 value) {
1998 // Default NaN value, see "NaN handling" in "IEEE 754 standard implementation
1999 // choices" of the ARM Reference Manual.
2000 constexpr Float64 kDefaultNaN =
2001 Float64::FromBits(uint64_t{0x7FF8000000000000});
2002 return FPSCR_default_NaN_mode_ && value.is_nan() ? kDefaultNaN : value;
2003}
2004
2005// Stop helper functions.
2006bool Simulator::isWatchedStop(uint32_t code) {
2007 DCHECK_LE(code, kMaxStopCode);
2008 return code < kNumOfWatchedStops;
2009}
2010
2011bool Simulator::isEnabledStop(uint32_t code) {
2012 DCHECK_LE(code, kMaxStopCode);
2013 // Unwatched stops are always enabled.
2014 return !isWatchedStop(code) ||
2015 !(watched_stops_[code].count & kStopDisabledBit);
2016}
2017
2018void Simulator::EnableStop(uint32_t code) {
2019 DCHECK(isWatchedStop(code));
2020 if (!isEnabledStop(code)) {
2021 watched_stops_[code].count &= ~kStopDisabledBit;
2022 }
2023}
2024
2025void Simulator::DisableStop(uint32_t code) {
2026 DCHECK(isWatchedStop(code));
2027 if (isEnabledStop(code)) {
2028 watched_stops_[code].count |= kStopDisabledBit;
2029 }
2030}
2031
2032void Simulator::IncreaseStopCounter(uint32_t code) {
2033 DCHECK_LE(code, kMaxStopCode);
2034 DCHECK(isWatchedStop(code));
2035 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7FFFFFFF) {
2036 PrintF(
2037 "Stop counter for code %i has overflowed.\n"
2038 "Enabling this code and reseting the counter to 0.\n",
2039 code);
2040 watched_stops_[code].count = 0;
2041 EnableStop(code);
2042 } else {
2043 watched_stops_[code].count++;
2044 }
2045}
2046
2047// Print a stop status.
2048void Simulator::PrintStopInfo(uint32_t code) {
2049 DCHECK_LE(code, kMaxStopCode);
2050 if (!isWatchedStop(code)) {
2051 PrintF("Stop not watched.");
2052 } else {
2053 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
2054 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
2055 // Don't print the state of unused breakpoints.
2056 if (count != 0) {
2057 if (watched_stops_[code].desc) {
2058 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", code, code,
2059 state, count, watched_stops_[code].desc);
2060 } else {
2061 PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state,
2062 count);
2063 }
2064 }
2065 }
2066}
2067
2068// Handle execution based on instruction types.
2069
2070// Instruction types 0 and 1 are both rolled into one function because they
2071// only differ in the handling of the shifter_operand.
2072void Simulator::DecodeType01(Instruction* instr) {
2073 int type = instr->TypeValue();
2074 if ((type == 0) && instr->IsSpecialType0()) {
2075 // multiply instruction or extra loads and stores
2076 if (instr->Bits(7, 4) == 9) {
2077 if (instr->Bit(24) == 0) {
2078 // Raw field decoding here. Multiply instructions have their Rd in
2079 // funny places.
2080 int rn = instr->RnValue();
2081 int rm = instr->RmValue();
2082 int rs = instr->RsValue();
2083 int32_t rs_val = get_register(rs);
2084 int32_t rm_val = get_register(rm);
2085 if (instr->Bit(23) == 0) {
2086 if (instr->Bit(21) == 0) {
2087 // The MUL instruction description (A 4.1.33) refers to Rd as being
2088 // the destination for the operation, but it confusingly uses the
2089 // Rn field to encode it.
2090 // Format(instr, "mul'cond's 'rn, 'rm, 'rs");
2091 int rd = rn; // Remap the rn field to the Rd register.
2092 int32_t alu_out = base::MulWithWraparound(rm_val, rs_val);
2093 set_register(rd, alu_out);
2094 if (instr->HasS()) {
2095 SetNZFlags(alu_out);
2096 }
2097 } else {
2098 int rd = instr->RdValue();
2099 int32_t acc_value = get_register(rd);
2100 if (instr->Bit(22) == 0) {
2101 // The MLA instruction description (A 4.1.28) refers to the order
2102 // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
2103 // Rn field to encode the Rd register and the Rd field to encode
2104 // the Rn register.
2105 // Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
2106 int32_t mul_out = base::MulWithWraparound(rm_val, rs_val);
2107 int32_t result = base::AddWithWraparound(acc_value, mul_out);
2108 set_register(rn, result);
2109 } else {
2110 // Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd");
2111 int32_t mul_out = base::MulWithWraparound(rm_val, rs_val);
2112 int32_t result = base::SubWithWraparound(acc_value, mul_out);
2113 set_register(rn, result);
2114 }
2115 }
2116 } else {
2117 // The signed/long multiply instructions use the terms RdHi and RdLo
2118 // when referring to the target registers. They are mapped to the Rn
2119 // and Rd fields as follows:
2120 // RdLo == Rd
2121 // RdHi == Rn (This is confusingly stored in variable rd here
2122 // because the mul instruction from above uses the
2123 // Rn field to encode the Rd register. Good luck figuring
2124 // this out without reading the ARM instruction manual
2125 // at a very detailed level.)
2126 // Format(instr, "'um'al'cond's 'rd, 'rn, 'rs, 'rm");
2127 int rd_hi = rn; // Remap the rn field to the RdHi register.
2128 int rd_lo = instr->RdValue();
2129 int32_t hi_res = 0;
2130 int32_t lo_res = 0;
2131 if (instr->Bit(22) == 1) {
2132 int64_t left_op = static_cast<int32_t>(rm_val);
2133 int64_t right_op = static_cast<int32_t>(rs_val);
2134 uint64_t result = left_op * right_op;
2135 hi_res = static_cast<int32_t>(result >> 32);
2136 lo_res = static_cast<int32_t>(result & 0xFFFFFFFF);
2137 } else {
2138 // unsigned multiply
2139 uint64_t left_op = static_cast<uint32_t>(rm_val);
2140 uint64_t right_op = static_cast<uint32_t>(rs_val);
2141 uint64_t result = left_op * right_op;
2142 hi_res = static_cast<int32_t>(result >> 32);
2143 lo_res = static_cast<int32_t>(result & 0xFFFFFFFF);
2144 }
2145 set_register(rd_lo, lo_res);
2146 set_register(rd_hi, hi_res);
2147 if (instr->HasS()) {
2148 UNIMPLEMENTED();
2149 }
2150 }
2151 } else {
2152 if (instr->Bits(24, 23) == 3) {
2153 if (instr->Bit(20) == 1) {
2154 // ldrex
2155 int rt = instr->RtValue();
2156 int rn = instr->RnValue();
2157 int32_t addr = get_register(rn);
2158 switch (instr->Bits(22, 21)) {
2159 case 0: {
2160 // Format(instr, "ldrex'cond 'rt, ['rn]");
2161 int value = ReadExW(addr);
2162 set_register(rt, value);
2163 break;
2164 }
2165 case 1: {
2166 // Format(instr, "ldrexd'cond 'rt, ['rn]");
2167 int* rn_data = ReadExDW(addr);
2168 set_dw_register(rt, rn_data);
2169 break;
2170 }
2171 case 2: {
2172 // Format(instr, "ldrexb'cond 'rt, ['rn]");
2173 uint8_t value = ReadExBU(addr);
2174 set_register(rt, value);
2175 break;
2176 }
2177 case 3: {
2178 // Format(instr, "ldrexh'cond 'rt, ['rn]");
2179 uint16_t value = ReadExHU(addr);
2180 set_register(rt, value);
2181 break;
2182 }
2183 default:
2184 UNREACHABLE();
2185 }
2186 } else {
2187 // The instruction is documented as strex rd, rt, [rn], but the
2188 // "rt" register is using the rm bits.
2189 int rd = instr->RdValue();
2190 int rt = instr->RmValue();
2191 int rn = instr->RnValue();
2192 DCHECK_NE(rd, rn);
2193 DCHECK_NE(rd, rt);
2194 int32_t addr = get_register(rn);
2195 switch (instr->Bits(22, 21)) {
2196 case 0: {
2197 // Format(instr, "strex'cond 'rd, 'rm, ['rn]");
2198 int value = get_register(rt);
2199 int status = WriteExW(addr, value);
2200 set_register(rd, status);
2201 break;
2202 }
2203 case 1: {
2204 // Format(instr, "strexd'cond 'rd, 'rm, ['rn]");
2205 DCHECK_EQ(rt % 2, 0);
2206 int32_t value1 = get_register(rt);
2207 int32_t value2 = get_register(rt + 1);
2208 int status = WriteExDW(addr, value1, value2);
2209 set_register(rd, status);
2210 break;
2211 }
2212 case 2: {
2213 // Format(instr, "strexb'cond 'rd, 'rm, ['rn]");
2214 uint8_t value = get_register(rt);
2215 int status = WriteExB(addr, value);
2216 set_register(rd, status);
2217 break;
2218 }
2219 case 3: {
2220 // Format(instr, "strexh'cond 'rd, 'rm, ['rn]");
2221 uint16_t value = get_register(rt);
2222 int status = WriteExH(addr, value);
2223 set_register(rd, status);
2224 break;
2225 }
2226 default:
2227 UNREACHABLE();
2228 }
2229 }
2230 } else {
2231 UNIMPLEMENTED(); // Not used by V8.
2232 }
2233 }
2234 } else {
2235 // extra load/store instructions
2236 int rd = instr->RdValue();
2237 int rn = instr->RnValue();
2238 int32_t rn_val = get_register(rn);
2239 int32_t addr = 0;
2240 if (instr->Bit(22) == 0) {
2241 int rm = instr->RmValue();
2242 int32_t rm_val = get_register(rm);
2243 switch (instr->PUField()) {
2244 case da_x: {
2245 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], -'rm");
2246 DCHECK(!instr->HasW());
2247 addr = rn_val;
2248 rn_val = base::SubWithWraparound(rn_val, rm_val);
2249 set_register(rn, rn_val);
2250 break;
2251 }
2252 case ia_x: {
2253 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], +'rm");
2254 DCHECK(!instr->HasW());
2255 addr = rn_val;
2256 rn_val = base::AddWithWraparound(rn_val, rm_val);
2257 set_register(rn, rn_val);
2258 break;
2259 }
2260 case db_x: {
2261 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, -'rm]'w");
2262 rn_val = base::SubWithWraparound(rn_val, rm_val);
2263 addr = rn_val;
2264 if (instr->HasW()) {
2265 set_register(rn, rn_val);
2266 }
2267 break;
2268 }
2269 case ib_x: {
2270 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, +'rm]'w");
2271 rn_val = base::AddWithWraparound(rn_val, rm_val);
2272 addr = rn_val;
2273 if (instr->HasW()) {
2274 set_register(rn, rn_val);
2275 }
2276 break;
2277 }
2278 default: {
2279 // The PU field is a 2-bit field.
2280 UNREACHABLE();
2281 }
2282 }
2283 } else {
2284 int32_t imm_val = (instr->ImmedHValue() << 4) | instr->ImmedLValue();
2285 switch (instr->PUField()) {
2286 case da_x: {
2287 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #-'off8");
2288 DCHECK(!instr->HasW());
2289 addr = rn_val;
2290 rn_val = base::SubWithWraparound(rn_val, imm_val);
2291 set_register(rn, rn_val);
2292 break;
2293 }
2294 case ia_x: {
2295 // Format(instr, "'memop'cond'sign'h 'rd, ['rn], #+'off8");
2296 DCHECK(!instr->HasW());
2297 addr = rn_val;
2298 rn_val = base::AddWithWraparound(rn_val, imm_val);
2299 set_register(rn, rn_val);
2300 break;
2301 }
2302 case db_x: {
2303 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #-'off8]'w");
2304 rn_val = base::SubWithWraparound(rn_val, imm_val);
2305 addr = rn_val;
2306 if (instr->HasW()) {
2307 set_register(rn, rn_val);
2308 }
2309 break;
2310 }
2311 case ib_x: {
2312 // Format(instr, "'memop'cond'sign'h 'rd, ['rn, #+'off8]'w");
2313 rn_val = base::AddWithWraparound(rn_val, imm_val);
2314 addr = rn_val;
2315 if (instr->HasW()) {
2316 set_register(rn, rn_val);
2317 }
2318 break;
2319 }
2320 default: {
2321 // The PU field is a 2-bit field.
2322 UNREACHABLE();
2323 }
2324 }
2325 }
2326 if (((instr->Bits(7, 4) & 0xD) == 0xD) && (instr->Bit(20) == 0)) {
2327 DCHECK_EQ(rd % 2, 0);
2328 if (instr->HasH()) {
2329 // The strd instruction.
2330 int32_t value1 = get_register(rd);
2331 int32_t value2 = get_register(rd + 1);
2332 WriteDW(addr, value1, value2);
2333 } else {
2334 // The ldrd instruction.
2335 int* rn_data = ReadDW(addr);
2336 set_dw_register(rd, rn_data);
2337 }
2338 } else if (instr->HasH()) {
2339 if (instr->HasSign()) {
2340 if (instr->HasL()) {
2341 int16_t val = ReadH(addr);
2342 set_register(rd, val);
2343 } else {
2344 int16_t val = get_register(rd);
2345 WriteH(addr, val);
2346 }
2347 } else {
2348 if (instr->HasL()) {
2349 uint16_t val = ReadHU(addr);
2350 set_register(rd, val);
2351 } else {
2352 uint16_t val = get_register(rd);
2353 WriteH(addr, val);
2354 }
2355 }
2356 } else {
2357 // signed byte loads
2358 DCHECK(instr->HasSign());
2359 DCHECK(instr->HasL());
2360 int8_t val = ReadB(addr);
2361 set_register(rd, val);
2362 }
2363 return;
2364 }
2365 } else if ((type == 0) && instr->IsMiscType0()) {
2366 if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 2) &&
2367 (instr->Bits(15, 4) == 0xF00)) {
2368 // MSR
2369 int rm = instr->RmValue();
2370 DCHECK_NE(pc, rm); // UNPREDICTABLE
2371 SRegisterFieldMask sreg_and_mask =
2372 instr->BitField(22, 22) | instr->BitField(19, 16);
2373 SetSpecialRegister(sreg_and_mask, get_register(rm));
2374 } else if ((instr->Bits(27, 23) == 2) && (instr->Bits(21, 20) == 0) &&
2375 (instr->Bits(11, 0) == 0)) {
2376 // MRS
2377 int rd = instr->RdValue();
2378 DCHECK_NE(pc, rd); // UNPREDICTABLE
2379 SRegister sreg = static_cast<SRegister>(instr->BitField(22, 22));
2380 set_register(rd, GetFromSpecialRegister(sreg));
2381 } else if (instr->Bits(22, 21) == 1) {
2382 int rm = instr->RmValue();
2383 switch (instr->BitField(7, 4)) {
2384 case BX:
2385 set_pc(get_register(rm));
2386 break;
2387 case BLX: {
2388 uint32_t old_pc = get_pc();
2389 set_pc(get_register(rm));
2390 set_register(lr, old_pc + kInstrSize);
2391 break;
2392 }
2393 case BKPT:
2394 PrintF("Simulator hit BKPT. ");
2395 DebugAtNextPC();
2396 break;
2397 default:
2398 UNIMPLEMENTED();
2399 }
2400 } else if (instr->Bits(22, 21) == 3) {
2401 int rm = instr->RmValue();
2402 int rd = instr->RdValue();
2403 switch (instr->BitField(7, 4)) {
2404 case CLZ: {
2405 uint32_t bits = get_register(rm);
2406 int leading_zeros = 0;
2407 if (bits == 0) {
2408 leading_zeros = 32;
2409 } else {
2410 while ((bits & 0x80000000u) == 0) {
2411 bits <<= 1;
2412 leading_zeros++;
2413 }
2414 }
2415 set_register(rd, leading_zeros);
2416 break;
2417 }
2418 default:
2419 UNIMPLEMENTED();
2420 }
2421 } else {
2422 PrintF("%08x\n", instr->InstructionBits());
2423 UNIMPLEMENTED();
2424 }
2425 } else if ((type == 1) && instr->IsNopLikeType1()) {
2426 if (instr->BitField(7, 0) == 0) {
2427 // NOP.
2428 } else if (instr->BitField(7, 0) == 20) {
2429 // CSDB.
2430 } else {
2431 PrintF("%08x\n", instr->InstructionBits());
2432 UNIMPLEMENTED();
2433 }
2434 } else {
2435 int rd = instr->RdValue();
2436 int rn = instr->RnValue();
2437 int32_t rn_val = get_register(rn);
2438 int32_t shifter_operand = 0;
2439 bool shifter_carry_out = false;
2440 if (type == 0) {
2441 shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2442 } else {
2443 DCHECK_EQ(instr->TypeValue(), 1);
2444 shifter_operand = GetImm(instr, &shifter_carry_out);
2445 }
2446 int32_t alu_out;
2447
2448 switch (instr->OpcodeField()) {
2449 case AND: {
2450 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
2451 // Format(instr, "and'cond's 'rd, 'rn, 'imm");
2452 alu_out = rn_val & shifter_operand;
2453 set_register(rd, alu_out);
2454 if (instr->HasS()) {
2455 SetNZFlags(alu_out);
2456 SetCFlag(shifter_carry_out);
2457 }
2458 break;
2459 }
2460
2461 case EOR: {
2462 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
2463 // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
2464 alu_out = rn_val ^ shifter_operand;
2465 set_register(rd, alu_out);
2466 if (instr->HasS()) {
2467 SetNZFlags(alu_out);
2468 SetCFlag(shifter_carry_out);
2469 }
2470 break;
2471 }
2472
2473 case SUB: {
2474 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
2475 // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
2476 alu_out = base::SubWithWraparound(rn_val, shifter_operand);
2477 set_register(rd, alu_out);
2478 if (instr->HasS()) {
2479 SetNZFlags(alu_out);
2480 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2481 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2482 }
2483 break;
2484 }
2485
2486 case RSB: {
2487 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
2488 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
2489 alu_out = base::SubWithWraparound(shifter_operand, rn_val);
2490 set_register(rd, alu_out);
2491 if (instr->HasS()) {
2492 SetNZFlags(alu_out);
2493 SetCFlag(!BorrowFrom(shifter_operand, rn_val));
2494 SetVFlag(OverflowFrom(alu_out, shifter_operand, rn_val, false));
2495 }
2496 break;
2497 }
2498
2499 case ADD: {
2500 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
2501 // Format(instr, "add'cond's 'rd, 'rn, 'imm");
2502 alu_out = base::AddWithWraparound(rn_val, shifter_operand);
2503 set_register(rd, alu_out);
2504 if (instr->HasS()) {
2505 SetNZFlags(alu_out);
2506 SetCFlag(CarryFrom(rn_val, shifter_operand));
2507 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2508 }
2509 break;
2510 }
2511
2512 case ADC: {
2513 // Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
2514 // Format(instr, "adc'cond's 'rd, 'rn, 'imm");
2515 alu_out = base::AddWithWraparound(
2516 base::AddWithWraparound(rn_val, shifter_operand), GetCarry());
2517 set_register(rd, alu_out);
2518 if (instr->HasS()) {
2519 SetNZFlags(alu_out);
2520 SetCFlag(CarryFrom(rn_val, shifter_operand, GetCarry()));
2521 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2522 }
2523 break;
2524 }
2525
2526 case SBC: {
2527 // Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
2528 // Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
2529 alu_out = base::SubWithWraparound(
2530 base::SubWithWraparound(rn_val, shifter_operand),
2531 (GetCarry() ? 0 : 1));
2532 set_register(rd, alu_out);
2533 if (instr->HasS()) {
2534 SetNZFlags(alu_out);
2535 SetCFlag(!BorrowFrom(rn_val, shifter_operand, GetCarry()));
2536 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2537 }
2538 break;
2539 }
2540
2541 case RSC: {
2542 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
2543 Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
2544 break;
2545 }
2546
2547 case TST: {
2548 if (instr->HasS()) {
2549 // Format(instr, "tst'cond 'rn, 'shift_rm");
2550 // Format(instr, "tst'cond 'rn, 'imm");
2551 alu_out = rn_val & shifter_operand;
2552 SetNZFlags(alu_out);
2553 SetCFlag(shifter_carry_out);
2554 } else {
2555 // Format(instr, "movw'cond 'rd, 'imm").
2556 alu_out = instr->ImmedMovwMovtValue();
2557 set_register(rd, alu_out);
2558 }
2559 break;
2560 }
2561
2562 case TEQ: {
2563 if (instr->HasS()) {
2564 // Format(instr, "teq'cond 'rn, 'shift_rm");
2565 // Format(instr, "teq'cond 'rn, 'imm");
2566 alu_out = rn_val ^ shifter_operand;
2567 SetNZFlags(alu_out);
2568 SetCFlag(shifter_carry_out);
2569 } else {
2570 // Other instructions matching this pattern are handled in the
2571 // miscellaneous instructions part above.
2572 UNREACHABLE();
2573 }
2574 break;
2575 }
2576
2577 case CMP: {
2578 if (instr->HasS()) {
2579 // Format(instr, "cmp'cond 'rn, 'shift_rm");
2580 // Format(instr, "cmp'cond 'rn, 'imm");
2581 alu_out = base::SubWithWraparound(rn_val, shifter_operand);
2582 SetNZFlags(alu_out);
2583 SetCFlag(!BorrowFrom(rn_val, shifter_operand));
2584 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, false));
2585 } else {
2586 // Format(instr, "movt'cond 'rd, 'imm").
2587 alu_out =
2588 (get_register(rd) & 0xFFFF) | (instr->ImmedMovwMovtValue() << 16);
2589 set_register(rd, alu_out);
2590 }
2591 break;
2592 }
2593
2594 case CMN: {
2595 if (instr->HasS()) {
2596 // Format(instr, "cmn'cond 'rn, 'shift_rm");
2597 // Format(instr, "cmn'cond 'rn, 'imm");
2598 alu_out = base::AddWithWraparound(rn_val, shifter_operand);
2599 SetNZFlags(alu_out);
2600 SetCFlag(CarryFrom(rn_val, shifter_operand));
2601 SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
2602 } else {
2603 // Other instructions matching this pattern are handled in the
2604 // miscellaneous instructions part above.
2605 UNREACHABLE();
2606 }
2607 break;
2608 }
2609
2610 case ORR: {
2611 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
2612 // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
2613 alu_out = rn_val | shifter_operand;
2614 set_register(rd, alu_out);
2615 if (instr->HasS()) {
2616 SetNZFlags(alu_out);
2617 SetCFlag(shifter_carry_out);
2618 }
2619 break;
2620 }
2621
2622 case MOV: {
2623 // Format(instr, "mov'cond's 'rd, 'shift_rm");
2624 // Format(instr, "mov'cond's 'rd, 'imm");
2625 alu_out = shifter_operand;
2626 set_register(rd, alu_out);
2627 if (instr->HasS()) {
2628 SetNZFlags(alu_out);
2629 SetCFlag(shifter_carry_out);
2630 }
2631 break;
2632 }
2633
2634 case BIC: {
2635 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
2636 // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
2637 alu_out = rn_val & ~shifter_operand;
2638 set_register(rd, alu_out);
2639 if (instr->HasS()) {
2640 SetNZFlags(alu_out);
2641 SetCFlag(shifter_carry_out);
2642 }
2643 break;
2644 }
2645
2646 case MVN: {
2647 // Format(instr, "mvn'cond's 'rd, 'shift_rm");
2648 // Format(instr, "mvn'cond's 'rd, 'imm");
2649 alu_out = ~shifter_operand;
2650 set_register(rd, alu_out);
2651 if (instr->HasS()) {
2652 SetNZFlags(alu_out);
2653 SetCFlag(shifter_carry_out);
2654 }
2655 break;
2656 }
2657
2658 default: {
2659 UNREACHABLE();
2660 }
2661 }
2662 }
2663}
2664
2665void Simulator::DecodeType2(Instruction* instr) {
2666 int rd = instr->RdValue();
2667 int rn = instr->RnValue();
2668 int32_t rn_val = get_register(rn);
2669 int32_t im_val = instr->Offset12Value();
2670 int32_t addr = 0;
2671 switch (instr->PUField()) {
2672 case da_x: {
2673 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
2674 DCHECK(!instr->HasW());
2675 addr = rn_val;
2676 rn_val -= im_val;
2677 set_register(rn, rn_val);
2678 break;
2679 }
2680 case ia_x: {
2681 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
2682 DCHECK(!instr->HasW());
2683 addr = rn_val;
2684 rn_val += im_val;
2685 set_register(rn, rn_val);
2686 break;
2687 }
2688 case db_x: {
2689 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
2690 rn_val -= im_val;
2691 addr = rn_val;
2692 if (instr->HasW()) {
2693 set_register(rn, rn_val);
2694 }
2695 break;
2696 }
2697 case ib_x: {
2698 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
2699 rn_val += im_val;
2700 addr = rn_val;
2701 if (instr->HasW()) {
2702 set_register(rn, rn_val);
2703 }
2704 break;
2705 }
2706 default: {
2707 UNREACHABLE();
2708 }
2709 }
2710 if (instr->HasB()) {
2711 if (instr->HasL()) {
2712 uint8_t val = ReadBU(addr);
2713 set_register(rd, val);
2714 } else {
2715 uint8_t val = get_register(rd);
2716 WriteB(addr, val);
2717 }
2718 } else {
2719 if (instr->HasL()) {
2720 set_register(rd, ReadW(addr));
2721 } else {
2722 WriteW(addr, get_register(rd));
2723 }
2724 }
2725}
2726
2727void Simulator::DecodeType3(Instruction* instr) {
2728 int rd = instr->RdValue();
2729 int rn = instr->RnValue();
2730 int32_t rn_val = get_register(rn);
2731 bool shifter_carry_out = false;
2732 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2733 int32_t addr = 0;
2734 switch (instr->PUField()) {
2735 case da_x: {
2736 DCHECK(!instr->HasW());
2737 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
2738 UNIMPLEMENTED();
2739 }
2740 case ia_x: {
2741 if (instr->Bit(4) == 0) {
2742 // Memop.
2743 } else {
2744 if (instr->Bit(5) == 0) {
2745 switch (instr->Bits(22, 21)) {
2746 case 0:
2747 if (instr->Bit(20) == 0) {
2748 if (instr->Bit(6) == 0) {
2749 // Pkhbt.
2750 uint32_t rn_val = get_register(rn);
2751 uint32_t rm_val = get_register(instr->RmValue());
2752 int32_t shift = instr->Bits(11, 7);
2753 rm_val <<= shift;
2754 set_register(rd, (rn_val & 0xFFFF) | (rm_val & 0xFFFF0000U));
2755 } else {
2756 // Pkhtb.
2757 uint32_t rn_val = get_register(rn);
2758 int32_t rm_val = get_register(instr->RmValue());
2759 int32_t shift = instr->Bits(11, 7);
2760 if (shift == 0) {
2761 shift = 32;
2762 }
2763 rm_val >>= shift;
2764 set_register(rd, (rn_val & 0xFFFF0000U) | (rm_val & 0xFFFF));
2765 }
2766 } else {
2767 UNIMPLEMENTED();
2768 }
2769 break;
2770 case 1:
2771 UNIMPLEMENTED();
2772 case 2:
2773 UNIMPLEMENTED();
2774 case 3: {
2775 // Usat.
2776 int32_t sat_pos = instr->Bits(20, 16);
2777 int32_t sat_val = (1 << sat_pos) - 1;
2778 int32_t shift = instr->Bits(11, 7);
2779 int32_t shift_type = instr->Bit(6);
2780 int32_t rm_val = get_register(instr->RmValue());
2781 if (shift_type == 0) { // LSL
2782 rm_val <<= shift;
2783 } else { // ASR
2784 rm_val >>= shift;
2785 }
2786 // If saturation occurs, the Q flag should be set in the CPSR.
2787 // There is no Q flag yet, and no instruction (MRS) to read the
2788 // CPSR directly.
2789 if (rm_val > sat_val) {
2790 rm_val = sat_val;
2791 } else if (rm_val < 0) {
2792 rm_val = 0;
2793 }
2794 set_register(rd, rm_val);
2795 break;
2796 }
2797 }
2798 } else {
2799 switch (instr->Bits(22, 21)) {
2800 case 0:
2801 UNIMPLEMENTED();
2802 case 1:
2803 if (instr->Bits(9, 6) == 1) {
2804 if (instr->Bit(20) == 0) {
2805 if (instr->Bits(19, 16) == 0xF) {
2806 // Sxtb.
2807 int32_t rm_val = get_register(instr->RmValue());
2808 int32_t rotate = instr->Bits(11, 10);
2809 switch (rotate) {
2810 case 0:
2811 break;
2812 case 1:
2813 rm_val = (rm_val >> 8) | (rm_val << 24);
2814 break;
2815 case 2:
2816 rm_val = (rm_val >> 16) | (rm_val << 16);
2817 break;
2818 case 3:
2819 rm_val = (rm_val >> 24) | (rm_val << 8);
2820 break;
2821 }
2822 set_register(rd, static_cast<int8_t>(rm_val));
2823 } else {
2824 // Sxtab.
2825 int32_t rn_val = get_register(rn);
2826 int32_t rm_val = get_register(instr->RmValue());
2827 int32_t rotate = instr->Bits(11, 10);
2828 switch (rotate) {
2829 case 0:
2830 break;
2831 case 1:
2832 rm_val = (rm_val >> 8) | (rm_val << 24);
2833 break;
2834 case 2:
2835 rm_val = (rm_val >> 16) | (rm_val << 16);
2836 break;
2837 case 3:
2838 rm_val = (rm_val >> 24) | (rm_val << 8);
2839 break;
2840 }
2841 set_register(rd, rn_val + static_cast<int8_t>(rm_val));
2842 }
2843 } else {
2844 if (instr->Bits(19, 16) == 0xF) {
2845 // Sxth.
2846 int32_t rm_val = get_register(instr->RmValue());
2847 int32_t rotate = instr->Bits(11, 10);
2848 switch (rotate) {
2849 case 0:
2850 break;
2851 case 1:
2852 rm_val = (rm_val >> 8) | (rm_val << 24);
2853 break;
2854 case 2:
2855 rm_val = (rm_val >> 16) | (rm_val << 16);
2856 break;
2857 case 3:
2858 rm_val = (rm_val >> 24) | (rm_val << 8);
2859 break;
2860 }
2861 set_register(rd, static_cast<int16_t>(rm_val));
2862 } else {
2863 // Sxtah.
2864 int32_t rn_val = get_register(rn);
2865 int32_t rm_val = get_register(instr->RmValue());
2866 int32_t rotate = instr->Bits(11, 10);
2867 switch (rotate) {
2868 case 0:
2869 break;
2870 case 1:
2871 rm_val = (rm_val >> 8) | (rm_val << 24);
2872 break;
2873 case 2:
2874 rm_val = (rm_val >> 16) | (rm_val << 16);
2875 break;
2876 case 3:
2877 rm_val = (rm_val >> 24) | (rm_val << 8);
2878 break;
2879 }
2880 set_register(rd, rn_val + static_cast<int16_t>(rm_val));
2881 }
2882 }
2883 } else if (instr->Bits(27, 16) == 0x6BF &&
2884 instr->Bits(11, 4) == 0xF3) {
2885 // Rev.
2886 uint32_t rm_val = get_register(instr->RmValue());
2887 set_register(rd, ByteReverse(rm_val));
2888 } else {
2889 UNREACHABLE();
2890 }
2891 break;
2892 case 2:
2893 if ((instr->Bit(20) == 0) && (instr->Bits(9, 6) == 1)) {
2894 if (instr->Bits(19, 16) == 0xF) {
2895 // Uxtb16.
2896 uint32_t rm_val = get_register(instr->RmValue());
2897 int32_t rotate = instr->Bits(11, 10);
2898 switch (rotate) {
2899 case 0:
2900 break;
2901 case 1:
2902 rm_val = (rm_val >> 8) | (rm_val << 24);
2903 break;
2904 case 2:
2905 rm_val = (rm_val >> 16) | (rm_val << 16);
2906 break;
2907 case 3:
2908 rm_val = (rm_val >> 24) | (rm_val << 8);
2909 break;
2910 }
2911 set_register(rd, (rm_val & 0xFF) | (rm_val & 0xFF0000));
2912 } else {
2913 UNIMPLEMENTED();
2914 }
2915 } else {
2916 UNIMPLEMENTED();
2917 }
2918 break;
2919 case 3:
2920 if ((instr->Bits(9, 6) == 1)) {
2921 if (instr->Bit(20) == 0) {
2922 if (instr->Bits(19, 16) == 0xF) {
2923 // Uxtb.
2924 uint32_t rm_val = get_register(instr->RmValue());
2925 int32_t rotate = instr->Bits(11, 10);
2926 switch (rotate) {
2927 case 0:
2928 break;
2929 case 1:
2930 rm_val = (rm_val >> 8) | (rm_val << 24);
2931 break;
2932 case 2:
2933 rm_val = (rm_val >> 16) | (rm_val << 16);
2934 break;
2935 case 3:
2936 rm_val = (rm_val >> 24) | (rm_val << 8);
2937 break;
2938 }
2939 set_register(rd, (rm_val & 0xFF));
2940 } else {
2941 // Uxtab.
2942 uint32_t rn_val = get_register(rn);
2943 uint32_t rm_val = get_register(instr->RmValue());
2944 int32_t rotate = instr->Bits(11, 10);
2945 switch (rotate) {
2946 case 0:
2947 break;
2948 case 1:
2949 rm_val = (rm_val >> 8) | (rm_val << 24);
2950 break;
2951 case 2:
2952 rm_val = (rm_val >> 16) | (rm_val << 16);
2953 break;
2954 case 3:
2955 rm_val = (rm_val >> 24) | (rm_val << 8);
2956 break;
2957 }
2958 set_register(rd, rn_val + (rm_val & 0xFF));
2959 }
2960 } else {
2961 if (instr->Bits(19, 16) == 0xF) {
2962 // Uxth.
2963 uint32_t rm_val = get_register(instr->RmValue());
2964 int32_t rotate = instr->Bits(11, 10);
2965 switch (rotate) {
2966 case 0:
2967 break;
2968 case 1:
2969 rm_val = (rm_val >> 8) | (rm_val << 24);
2970 break;
2971 case 2:
2972 rm_val = (rm_val >> 16) | (rm_val << 16);
2973 break;
2974 case 3:
2975 rm_val = (rm_val >> 24) | (rm_val << 8);
2976 break;
2977 }
2978 set_register(rd, (rm_val & 0xFFFF));
2979 } else {
2980 // Uxtah.
2981 uint32_t rn_val = get_register(rn);
2982 uint32_t rm_val = get_register(instr->RmValue());
2983 int32_t rotate = instr->Bits(11, 10);
2984 switch (rotate) {
2985 case 0:
2986 break;
2987 case 1:
2988 rm_val = (rm_val >> 8) | (rm_val << 24);
2989 break;
2990 case 2:
2991 rm_val = (rm_val >> 16) | (rm_val << 16);
2992 break;
2993 case 3:
2994 rm_val = (rm_val >> 24) | (rm_val << 8);
2995 break;
2996 }
2997 set_register(rd, rn_val + (rm_val & 0xFFFF));
2998 }
2999 }
3000 } else {
3001 // PU == 0b01, BW == 0b11, Bits(9, 6) != 0b0001
3002 if ((instr->Bits(20, 16) == 0x1F) &&
3003 (instr->Bits(11, 4) == 0xF3)) {
3004 // Rbit.
3005 uint32_t rm_val = get_register(instr->RmValue());
3006 set_register(rd, base::bits::ReverseBits(rm_val));
3007 } else {
3008 UNIMPLEMENTED();
3009 }
3010 }
3011 break;
3012 }
3013 }
3014 return;
3015 }
3016 break;
3017 }
3018 case db_x: {
3019 if (instr->Bits(22, 20) == 0x5) {
3020 if (instr->Bits(7, 4) == 0x1) {
3021 int rm = instr->RmValue();
3022 int32_t rm_val = get_register(rm);
3023 int rs = instr->RsValue();
3024 int32_t rs_val = get_register(rs);
3025 if (instr->Bits(15, 12) == 0xF) {
3026 // SMMUL (in V8 notation matching ARM ISA format)
3027 // Format(instr, "smmul'cond 'rn, 'rm, 'rs");
3028 rn_val = base::bits::SignedMulHigh32(rm_val, rs_val);
3029 } else {
3030 // SMMLA (in V8 notation matching ARM ISA format)
3031 // Format(instr, "smmla'cond 'rn, 'rm, 'rs, 'rd");
3032 int rd = instr->RdValue();
3033 int32_t rd_val = get_register(rd);
3034 rn_val = base::bits::SignedMulHighAndAdd32(rm_val, rs_val, rd_val);
3035 }
3036 set_register(rn, rn_val);
3037 return;
3038 }
3039 }
3040 if (instr->Bits(5, 4) == 0x1) {
3041 if ((instr->Bit(22) == 0x0) && (instr->Bit(20) == 0x1)) {
3042 // (s/u)div (in V8 notation matching ARM ISA format) rn = rm/rs
3043 // Format(instr, "'(s/u)div'cond'b 'rn, 'rm, 'rs);
3044 int rm = instr->RmValue();
3045 int32_t rm_val = get_register(rm);
3046 int rs = instr->RsValue();
3047 int32_t rs_val = get_register(rs);
3048 int32_t ret_val = 0;
3049 // udiv
3050 if (instr->Bit(21) == 0x1) {
3051 ret_val = base::bit_cast<int32_t>(
3052 base::bits::UnsignedDiv32(base::bit_cast<uint32_t>(rm_val),
3053 base::bit_cast<uint32_t>(rs_val)));
3054 } else {
3055 ret_val = base::bits::SignedDiv32(rm_val, rs_val);
3056 }
3057 set_register(rn, ret_val);
3058 return;
3059 }
3060 }
3061 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
3062 addr = rn_val - shifter_operand;
3063 if (instr->HasW()) {
3064 set_register(rn, addr);
3065 }
3066 break;
3067 }
3068 case ib_x: {
3069 if (instr->HasW() && (instr->Bits(6, 4) == 0x5)) {
3070 uint32_t widthminus1 = static_cast<uint32_t>(instr->Bits(20, 16));
3071 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
3072 uint32_t msbit = widthminus1 + lsbit;
3073 if (msbit <= 31) {
3074 if (instr->Bit(22)) {
3075 // ubfx - unsigned bitfield extract.
3076 uint32_t rm_val =
3077 static_cast<uint32_t>(get_register(instr->RmValue()));
3078 uint32_t extr_val = rm_val << (31 - msbit);
3079 extr_val = extr_val >> (31 - widthminus1);
3080 set_register(instr->RdValue(), extr_val);
3081 } else {
3082 // sbfx - signed bitfield extract.
3083 int32_t rm_val = get_register(instr->RmValue());
3084 int32_t extr_val = static_cast<uint32_t>(rm_val) << (31 - msbit);
3085 extr_val = extr_val >> (31 - widthminus1);
3086 set_register(instr->RdValue(), extr_val);
3087 }
3088 } else {
3089 UNREACHABLE();
3090 }
3091 return;
3092 } else if (!instr->HasW() && (instr->Bits(6, 4) == 0x1)) {
3093 uint32_t lsbit = static_cast<uint32_t>(instr->Bits(11, 7));
3094 uint32_t msbit = static_cast<uint32_t>(instr->Bits(20, 16));
3095 if (msbit >= lsbit) {
3096 // bfc or bfi - bitfield clear/insert.
3097 uint32_t rd_val =
3098 static_cast<uint32_t>(get_register(instr->RdValue()));
3099 uint32_t bitcount = msbit - lsbit + 1;
3100 uint32_t mask = 0xFFFFFFFFu >> (32 - bitcount);
3101 rd_val &= ~(mask << lsbit);
3102 if (instr->RmValue() != 15) {
3103 // bfi - bitfield insert.
3104 uint32_t rm_val =
3105 static_cast<uint32_t>(get_register(instr->RmValue()));
3106 rm_val &= mask;
3107 rd_val |= rm_val << lsbit;
3108 }
3109 set_register(instr->RdValue(), rd_val);
3110 } else {
3111 UNREACHABLE();
3112 }
3113 return;
3114 } else {
3115 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
3116 addr = base::AddWithWraparound(rn_val, shifter_operand);
3117 if (instr->HasW()) {
3118 set_register(rn, addr);
3119 }
3120 }
3121 break;
3122 }
3123 default: {
3124 UNREACHABLE();
3125 }
3126 }
3127 if (instr->HasB()) {
3128 if (instr->HasL()) {
3129 uint8_t byte = ReadB(addr);
3130 set_register(rd, byte);
3131 } else {
3132 uint8_t byte = get_register(rd);
3133 WriteB(addr, byte);
3134 }
3135 } else {
3136 if (instr->HasL()) {
3137 set_register(rd, ReadW(addr));
3138 } else {
3139 WriteW(addr, get_register(rd));
3140 }
3141 }
3142}
3143
3144void Simulator::DecodeType4(Instruction* instr) {
3145 DCHECK_EQ(instr->Bit(22), 0); // only allowed to be set in privileged mode
3146 if (instr->HasL()) {
3147 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
3148 HandleRList(instr, true);
3149 } else {
3150 // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
3151 HandleRList(instr, false);
3152 }
3153}
3154
3155void Simulator::DecodeType5(Instruction* instr) {
3156 // Format(instr, "b'l'cond 'target");
3157 int off =
3158 static_cast<int>(static_cast<uint32_t>(instr->SImmed24Value()) << 2);
3159 intptr_t pc_address = get_pc();
3160 if (instr->HasLink()) {
3161 set_register(lr, pc_address + kInstrSize);
3162 }
3163 int pc_reg = get_register(pc);
3164 set_pc(pc_reg + off);
3165}
3166
3167void Simulator::DecodeType6(Instruction* instr) {
3168 DecodeType6CoprocessorIns(instr);
3169}
3170
3171void Simulator::DecodeType7(Instruction* instr) {
3172 if (instr->Bit(24) == 1) {
3173 SoftwareInterrupt(instr);
3174 } else {
3175 switch (instr->CoprocessorValue()) {
3176 case 10: // Fall through.
3177 case 11:
3178 DecodeTypeVFP(instr);
3179 break;
3180 case 15:
3181 DecodeTypeCP15(instr);
3182 break;
3183 default:
3184 UNIMPLEMENTED();
3185 }
3186 }
3187}
3188
3189// void Simulator::DecodeTypeVFP(Instruction* instr)
3190// The Following ARMv7 VFPv instructions are currently supported.
3191// vmov :Sn = Rt
3192// vmov :Rt = Sn
3193// vcvt: Dd = Sm
3194// vcvt: Sd = Dm
3195// vcvt.f64.s32 Dd, Dd, #<fbits>
3196// Dd = vabs(Dm)
3197// Sd = vabs(Sm)
3198// Dd = vneg(Dm)
3199// Sd = vneg(Sm)
3200// Dd = vadd(Dn, Dm)
3201// Sd = vadd(Sn, Sm)
3202// Dd = vsub(Dn, Dm)
3203// Sd = vsub(Sn, Sm)
3204// Dd = vmul(Dn, Dm)
3205// Sd = vmul(Sn, Sm)
3206// Dd = vdiv(Dn, Dm)
3207// Sd = vdiv(Sn, Sm)
3208// vcmp(Dd, Dm)
3209// vcmp(Sd, Sm)
3210// Dd = vsqrt(Dm)
3211// Sd = vsqrt(Sm)
3212// vmrs
3213// vdup.size Qd, Rt.
3214void Simulator::DecodeTypeVFP(Instruction* instr) {
3215 DCHECK((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0));
3216 DCHECK_EQ(instr->Bits(11, 9), 0x5);
3217 // Obtain single precision register codes.
3218 int m = instr->VFPMRegValue(kSinglePrecision);
3219 int d = instr->VFPDRegValue(kSinglePrecision);
3220 int n = instr->VFPNRegValue(kSinglePrecision);
3221 // Obtain double precision register codes.
3222 int vm = instr->VFPMRegValue(kDoublePrecision);
3223 int vd = instr->VFPDRegValue(kDoublePrecision);
3224 int vn = instr->VFPNRegValue(kDoublePrecision);
3225
3226 if (instr->Bit(4) == 0) {
3227 if (instr->Opc1Value() == 0x7) {
3228 // Other data processing instructions
3229 if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x1)) {
3230 // vmov register to register.
3231 if (instr->SzValue() == 0x1) {
3232 uint32_t data[2];
3233 get_d_register(vm, data);
3234 set_d_register(vd, data);
3235 } else {
3236 set_s_register(d, get_s_register(m));
3237 }
3238 } else if ((instr->Opc2Value() == 0x0) && (instr->Opc3Value() == 0x3)) {
3239 // vabs
3240 if (instr->SzValue() == 0x1) {
3241 Float64 dm = get_double_from_d_register(vm);
3242 constexpr uint64_t kSignBit64 = uint64_t{1} << 63;
3243 Float64 dd = Float64::FromBits(dm.get_bits() & ~kSignBit64);
3244 dd = canonicalizeNaN(dd);
3245 set_d_register_from_double(vd, dd);
3246 } else {
3247 Float32 sm = get_float_from_s_register(m);
3248 constexpr uint32_t kSignBit32 = uint32_t{1} << 31;
3249 Float32 sd = Float32::FromBits(sm.get_bits() & ~kSignBit32);
3250 sd = canonicalizeNaN(sd);
3251 set_s_register_from_float(d, sd);
3252 }
3253 } else if ((instr->Opc2Value() == 0x1) && (instr->Opc3Value() == 0x1)) {
3254 // vneg
3255 if (instr->SzValue() == 0x1) {
3256 Float64 dm = get_double_from_d_register(vm);
3257 constexpr uint64_t kSignBit64 = uint64_t{1} << 63;
3258 Float64 dd = Float64::FromBits(dm.get_bits() ^ kSignBit64);
3259 dd = canonicalizeNaN(dd);
3260 set_d_register_from_double(vd, dd);
3261 } else {
3262 Float32 sm = get_float_from_s_register(m);
3263 constexpr uint32_t kSignBit32 = uint32_t{1} << 31;
3264 Float32 sd = Float32::FromBits(sm.get_bits() ^ kSignBit32);
3265 sd = canonicalizeNaN(sd);
3266 set_s_register_from_float(d, sd);
3267 }
3268 } else if ((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3)) {
3269 DecodeVCVTBetweenDoubleAndSingle(instr);
3270 } else if ((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) {
3271 DecodeVCVTBetweenFloatingPointAndInteger(instr);
3272 } else if ((instr->Opc2Value() == 0xA) && (instr->Opc3Value() == 0x3) &&
3273 (instr->Bit(8) == 1)) {
3274 // vcvt.f64.s32 Dd, Dd, #<fbits>
3275 int fraction_bits = 32 - ((instr->Bits(3, 0) << 1) | instr->Bit(5));
3276 int fixed_value = get_sinteger_from_s_register(vd * 2);
3277 double divide = 1 << fraction_bits;
3278 set_d_register_from_double(vd, fixed_value / divide);
3279 } else if (((instr->Opc2Value() >> 1) == 0x6) &&
3280 (instr->Opc3Value() & 0x1)) {
3281 DecodeVCVTBetweenFloatingPointAndInteger(instr);
3282 } else if (((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
3283 (instr->Opc3Value() & 0x1)) {
3284 DecodeVCMP(instr);
3285 } else if (((instr->Opc2Value() == 0x1)) && (instr->Opc3Value() == 0x3)) {
3286 // vsqrt
3287 if (instr->SzValue() == 0x1) {
3288 double dm_value = get_double_from_d_register(vm).get_scalar();
3289 double dd_value = std::sqrt(dm_value);
3290 dd_value = canonicalizeNaN(dd_value);
3291 set_d_register_from_double(vd, dd_value);
3292 } else {
3293 float sm_value = get_float_from_s_register(m).get_scalar();
3294 float sd_value = std::sqrt(sm_value);
3295 sd_value = canonicalizeNaN(sd_value);
3296 set_s_register_from_float(d, sd_value);
3297 }
3298 } else if (instr->Opc3Value() == 0x0) {
3299 // vmov immediate.
3300 if (instr->SzValue() == 0x1) {
3301 set_d_register_from_double(vd, instr->DoubleImmedVmov());
3302 } else {
3303 // Cast double to float.
3304 float value = instr->DoubleImmedVmov().get_scalar();
3305 set_s_register_from_float(d, value);
3306 }
3307 } else if (((instr->Opc2Value() == 0x6)) && (instr->Opc3Value() == 0x3)) {
3308 // vrintz - truncate
3309 if (instr->SzValue() == 0x1) {
3310 double dm_value = get_double_from_d_register(vm).get_scalar();
3311 double dd_value = trunc(dm_value);
3312 dd_value = canonicalizeNaN(dd_value);
3313 set_d_register_from_double(vd, dd_value);
3314 } else {
3315 float sm_value = get_float_from_s_register(m).get_scalar();
3316 float sd_value = truncf(sm_value);
3317 sd_value = canonicalizeNaN(sd_value);
3318 set_s_register_from_float(d, sd_value);
3319 }
3320 } else {
3321 UNREACHABLE(); // Not used by V8.
3322 }
3323 } else if (instr->Opc1Value() == 0x3) {
3324 if (instr->Opc3Value() & 0x1) {
3325 // vsub
3326 if (instr->SzValue() == 0x1) {
3327 double dn_value = get_double_from_d_register(vn).get_scalar();
3328 double dm_value = get_double_from_d_register(vm).get_scalar();
3329 double dd_value = dn_value - dm_value;
3330 dd_value = canonicalizeNaN(dd_value);
3331 set_d_register_from_double(vd, dd_value);
3332 } else {
3333 float sn_value = get_float_from_s_register(n).get_scalar();
3334 float sm_value = get_float_from_s_register(m).get_scalar();
3335 float sd_value = sn_value - sm_value;
3336 sd_value = canonicalizeNaN(sd_value);
3337 set_s_register_from_float(d, sd_value);
3338 }
3339 } else {
3340 // vadd
3341 if (instr->SzValue() == 0x1) {
3342 double dn_value = get_double_from_d_register(vn).get_scalar();
3343 double dm_value = get_double_from_d_register(vm).get_scalar();
3344 double dd_value = dn_value + dm_value;
3345 dd_value = canonicalizeNaN(dd_value);
3346 set_d_register_from_double(vd, dd_value);
3347 } else {
3348 float sn_value = get_float_from_s_register(n).get_scalar();
3349 float sm_value = get_float_from_s_register(m).get_scalar();
3350 float sd_value = sn_value + sm_value;
3351 sd_value = canonicalizeNaN(sd_value);
3352 set_s_register_from_float(d, sd_value);
3353 }
3354 }
3355 } else if ((instr->Opc1Value() == 0x2) && !(instr->Opc3Value() & 0x1)) {
3356 // vmul
3357 if (instr->SzValue() == 0x1) {
3358 double dn_value = get_double_from_d_register(vn).get_scalar();
3359 double dm_value = get_double_from_d_register(vm).get_scalar();
3360 double dd_value = dn_value * dm_value;
3361 dd_value = canonicalizeNaN(dd_value);
3362 set_d_register_from_double(vd, dd_value);
3363 } else {
3364 float sn_value = get_float_from_s_register(n).get_scalar();
3365 float sm_value = get_float_from_s_register(m).get_scalar();
3366 float sd_value = sn_value * sm_value;
3367 sd_value = canonicalizeNaN(sd_value);
3368 set_s_register_from_float(d, sd_value);
3369 }
3370 } else if ((instr->Opc1Value() == 0x0)) {
3371 // vmla, vmls
3372 const bool is_vmls = (instr->Opc3Value() & 0x1);
3373 if (instr->SzValue() == 0x1) {
3374 const double dd_val = get_double_from_d_register(vd).get_scalar();
3375 const double dn_val = get_double_from_d_register(vn).get_scalar();
3376 const double dm_val = get_double_from_d_register(vm).get_scalar();
3377
3378 // Note: we do the mul and add/sub in separate steps to avoid getting a
3379 // result with too high precision.
3380 const double res = dn_val * dm_val;
3381 set_d_register_from_double(vd, res);
3382 if (is_vmls) {
3383 set_d_register_from_double(vd, canonicalizeNaN(dd_val - res));
3384 } else {
3385 set_d_register_from_double(vd, canonicalizeNaN(dd_val + res));
3386 }
3387 } else {
3388 const float sd_val = get_float_from_s_register(d).get_scalar();
3389 const float sn_val = get_float_from_s_register(n).get_scalar();
3390 const float sm_val = get_float_from_s_register(m).get_scalar();
3391
3392 // Note: we do the mul and add/sub in separate steps to avoid getting a
3393 // result with too high precision.
3394 const float res = sn_val * sm_val;
3395 set_s_register_from_float(d, res);
3396 if (is_vmls) {
3397 set_s_register_from_float(d, canonicalizeNaN(sd_val - res));
3398 } else {
3399 set_s_register_from_float(d, canonicalizeNaN(sd_val + res));
3400 }
3401 }
3402 } else if ((instr->Opc1Value() == 0x4) && !(instr->Opc3Value() & 0x1)) {
3403 // vdiv
3404 if (instr->SzValue() == 0x1) {
3405 double dn_value = get_double_from_d_register(vn).get_scalar();
3406 double dm_value = get_double_from_d_register(vm).get_scalar();
3407 double dd_value = base::Divide(dn_value, dm_value);
3408 div_zero_vfp_flag_ = (dm_value == 0);
3409 dd_value = canonicalizeNaN(dd_value);
3410 set_d_register_from_double(vd, dd_value);
3411 } else {
3412 float sn_value = get_float_from_s_register(n).get_scalar();
3413 float sm_value = get_float_from_s_register(m).get_scalar();
3414 float sd_value = base::Divide(sn_value, sm_value);
3415 div_zero_vfp_flag_ = (sm_value == 0);
3416 sd_value = canonicalizeNaN(sd_value);
3417 set_s_register_from_float(d, sd_value);
3418 }
3419 } else {
3420 UNIMPLEMENTED(); // Not used by V8.
3421 }
3422 } else {
3423 if ((instr->VCValue() == 0x0) && (instr->VAValue() == 0x0)) {
3424 DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
3425 } else if ((instr->VLValue() == 0x0) && (instr->VCValue() == 0x1)) {
3426 if (instr->Bit(23) == 0) {
3427 // vmov (ARM core register to scalar)
3428 int vd = instr->VFPNRegValue(kDoublePrecision);
3429 int rt = instr->RtValue();
3430 int opc1_opc2 = (instr->Bits(22, 21) << 2) | instr->Bits(6, 5);
3431 if ((opc1_opc2 & 0xB) == 0) {
3432 // NeonS32/NeonU32
3433 uint32_t data[2];
3434 get_d_register(vd, data);
3435 data[instr->Bit(21)] = get_register(rt);
3436 set_d_register(vd, data);
3437 } else {
3438 uint64_t data;
3439 get_d_register(vd, &data);
3440 uint64_t rt_value = get_register(rt);
3441 if ((opc1_opc2 & 0x8) != 0) {
3442 // NeonS8 / NeonU8
3443 int i = opc1_opc2 & 0x7;
3444 int shift = i * kBitsPerByte;
3445 const uint64_t mask = 0xFF;
3446 data &= ~(mask << shift);
3447 data |= (rt_value & mask) << shift;
3448 set_d_register(vd, &data);
3449 } else if ((opc1_opc2 & 0x1) != 0) {
3450 // NeonS16 / NeonU16
3451 int i = (opc1_opc2 >> 1) & 0x3;
3452 int shift = i * kBitsPerByte * kShortSize;
3453 const uint64_t mask = 0xFFFF;
3454 data &= ~(mask << shift);
3455 data |= (rt_value & mask) << shift;
3456 set_d_register(vd, &data);
3457 } else {
3458 UNREACHABLE(); // Not used by V8.
3459 }
3460 }
3461 } else {
3462 // vdup.size Qd, Rt.
3463 NeonSize size = Neon32;
3464 if (instr->Bit(5) != 0)
3465 size = Neon16;
3466 else if (instr->Bit(22) != 0)
3467 size = Neon8;
3468 int vd = instr->VFPNRegValue(kSimd128Precision);
3469 int rt = instr->RtValue();
3470 uint32_t rt_value = get_register(rt);
3471 uint32_t q_data[4];
3472 switch (size) {
3473 case Neon8: {
3474 rt_value &= 0xFF;
3475 uint8_t* dst = reinterpret_cast<uint8_t*>(q_data);
3476 for (int i = 0; i < 16; i++) {
3477 dst[i] = rt_value;
3478 }
3479 break;
3480 }
3481 case Neon16: {
3482 // Perform pairwise op.
3483 rt_value &= 0xFFFFu;
3484 uint32_t rt_rt = (rt_value << 16) | (rt_value & 0xFFFFu);
3485 for (int i = 0; i < 4; i++) {
3486 q_data[i] = rt_rt;
3487 }
3488 break;
3489 }
3490 case Neon32: {
3491 for (int i = 0; i < 4; i++) {
3492 q_data[i] = rt_value;
3493 }
3494 break;
3495 }
3496 default:
3497 UNREACHABLE();
3498 }
3499 set_neon_register(vd, q_data);
3500 }
3501 } else if ((instr->VLValue() == 0x1) && (instr->VCValue() == 0x1)) {
3502 // vmov (scalar to ARM core register)
3503 int vn = instr->VFPNRegValue(kDoublePrecision);
3504 int rt = instr->RtValue();
3505 int opc1_opc2 = (instr->Bits(22, 21) << 2) | instr->Bits(6, 5);
3506 uint64_t data;
3507 get_d_register(vn, &data);
3508 if ((opc1_opc2 & 0xB) == 0) {
3509 // NeonS32 / NeonU32
3510 DCHECK_EQ(0, instr->Bit(23));
3511 int32_t int_data[2];
3512 memcpy(int_data, &data, sizeof(int_data));
3513 set_register(rt, int_data[instr->Bit(21)]);
3514 } else {
3515 uint64_t data;
3516 get_d_register(vn, &data);
3517 bool u = instr->Bit(23) != 0;
3518 if ((opc1_opc2 & 0x8) != 0) {
3519 // NeonS8 / NeonU8
3520 int i = opc1_opc2 & 0x7;
3521 int shift = i * kBitsPerByte;
3522 uint32_t scalar = (data >> shift) & 0xFFu;
3523 if (!u && (scalar & 0x80) != 0) scalar |= 0xFFFFFF00;
3524 set_register(rt, scalar);
3525 } else if ((opc1_opc2 & 0x1) != 0) {
3526 // NeonS16 / NeonU16
3527 int i = (opc1_opc2 >> 1) & 0x3;
3528 int shift = i * kBitsPerByte * kShortSize;
3529 uint32_t scalar = (data >> shift) & 0xFFFFu;
3530 if (!u && (scalar & 0x8000) != 0) scalar |= 0xFFFF0000;
3531 set_register(rt, scalar);
3532 } else {
3533 UNREACHABLE(); // Not used by V8.
3534 }
3535 }
3536 } else if ((instr->VLValue() == 0x1) && (instr->VCValue() == 0x0) &&
3537 (instr->VAValue() == 0x7) && (instr->Bits(19, 16) == 0x1)) {
3538 // vmrs
3539 uint32_t rt = instr->RtValue();
3540 if (rt == 0xF) {
3541 Copy_FPSCR_to_APSR();
3542 } else {
3543 // Emulate FPSCR from the Simulator flags.
3544 uint32_t fpscr = (n_flag_FPSCR_ << 31) | (z_flag_FPSCR_ << 30) |
3545 (c_flag_FPSCR_ << 29) | (v_flag_FPSCR_ << 28) |
3546 (FPSCR_default_NaN_mode_ << 25) |
3547 (inexact_vfp_flag_ << 4) | (underflow_vfp_flag_ << 3) |
3548 (overflow_vfp_flag_ << 2) | (div_zero_vfp_flag_ << 1) |
3549 (inv_op_vfp_flag_ << 0) | (FPSCR_rounding_mode_);
3550 set_register(rt, fpscr);
3551 }
3552 } else if ((instr->VLValue() == 0x0) && (instr->VCValue() == 0x0) &&
3553 (instr->VAValue() == 0x7) && (instr->Bits(19, 16) == 0x1)) {
3554 // vmsr
3555 uint32_t rt = instr->RtValue();
3556 if (rt == pc) {
3557 UNREACHABLE();
3558 } else {
3559 uint32_t rt_value = get_register(rt);
3560 n_flag_FPSCR_ = (rt_value >> 31) & 1;
3561 z_flag_FPSCR_ = (rt_value >> 30) & 1;
3562 c_flag_FPSCR_ = (rt_value >> 29) & 1;
3563 v_flag_FPSCR_ = (rt_value >> 28) & 1;
3564 FPSCR_default_NaN_mode_ = (rt_value >> 25) & 1;
3565 inexact_vfp_flag_ = (rt_value >> 4) & 1;
3566 underflow_vfp_flag_ = (rt_value >> 3) & 1;
3567 overflow_vfp_flag_ = (rt_value >> 2) & 1;
3568 div_zero_vfp_flag_ = (rt_value >> 1) & 1;
3569 inv_op_vfp_flag_ = (rt_value >> 0) & 1;
3570 FPSCR_rounding_mode_ =
3571 static_cast<VFPRoundingMode>((rt_value)&kVFPRoundingModeMask);
3572 }
3573 } else {
3574 UNIMPLEMENTED(); // Not used by V8.
3575 }
3576 }
3577}
3578
3579void Simulator::DecodeTypeCP15(Instruction* instr) {
3580 DCHECK((instr->TypeValue() == 7) && (instr->Bit(24) == 0x0));
3581 DCHECK_EQ(instr->CoprocessorValue(), 15);
3582
3583 if (instr->Bit(4) == 1) {
3584 // mcr
3585 int crn = instr->Bits(19, 16);
3586 int crm = instr->Bits(3, 0);
3587 int opc1 = instr->Bits(23, 21);
3588 int opc2 = instr->Bits(7, 5);
3589 if ((opc1 == 0) && (crn == 7)) {
3590 // ARMv6 memory barrier operations.
3591 // Details available in ARM DDI 0406C.b, B3-1750.
3592 if (((crm == 10) && (opc2 == 5)) || // CP15DMB
3593 ((crm == 10) && (opc2 == 4)) || // CP15DSB
3594 ((crm == 5) && (opc2 == 4))) { // CP15ISB
3595 // These are ignored by the simulator for now.
3596 } else {
3597 UNIMPLEMENTED();
3598 }
3599 }
3600 } else {
3601 UNIMPLEMENTED();
3602 }
3603}
3604
3605void Simulator::DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(
3606 Instruction* instr) {
3607 DCHECK((instr->Bit(4) == 1) && (instr->VCValue() == 0x0) &&
3608 (instr->VAValue() == 0x0));
3609
3610 int t = instr->RtValue();
3611 int n = instr->VFPNRegValue(kSinglePrecision);
3612 bool to_arm_register = (instr->VLValue() == 0x1);
3613
3614 if (to_arm_register) {
3615 int32_t int_value = get_sinteger_from_s_register(n);
3616 set_register(t, int_value);
3617 } else {
3618 int32_t rs_val = get_register(t);
3619 set_s_register_from_sinteger(n, rs_val);
3620 }
3621}
3622
3623void Simulator::DecodeVCMP(Instruction* instr) {
3624 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
3625 DCHECK(((instr->Opc2Value() == 0x4) || (instr->Opc2Value() == 0x5)) &&
3626 (instr->Opc3Value() & 0x1));
3627 // Comparison.
3628
3630 if (instr->SzValue() == 0x1) {
3632 }
3633
3634 int d = instr->VFPDRegValue(precision);
3635 int m = 0;
3636 if (instr->Opc2Value() == 0x4) {
3637 m = instr->VFPMRegValue(precision);
3638 }
3639
3640 if (precision == kDoublePrecision) {
3641 double dd_value = get_double_from_d_register(d).get_scalar();
3642 double dm_value = 0.0;
3643 if (instr->Opc2Value() == 0x4) {
3644 dm_value = get_double_from_d_register(m).get_scalar();
3645 }
3646
3647 // Raise exceptions for quiet NaNs if necessary.
3648 if (instr->Bit(7) == 1) {
3649 if (std::isnan(dd_value)) {
3650 inv_op_vfp_flag_ = true;
3651 }
3652 }
3653
3654 Compute_FPSCR_Flags(dd_value, dm_value);
3655 } else {
3656 float sd_value = get_float_from_s_register(d).get_scalar();
3657 float sm_value = 0.0;
3658 if (instr->Opc2Value() == 0x4) {
3659 sm_value = get_float_from_s_register(m).get_scalar();
3660 }
3661
3662 // Raise exceptions for quiet NaNs if necessary.
3663 if (instr->Bit(7) == 1) {
3664 if (std::isnan(sd_value)) {
3665 inv_op_vfp_flag_ = true;
3666 }
3667 }
3668
3669 Compute_FPSCR_Flags(sd_value, sm_value);
3670 }
3671}
3672
3673void Simulator::DecodeVCVTBetweenDoubleAndSingle(Instruction* instr) {
3674 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7));
3675 DCHECK((instr->Opc2Value() == 0x7) && (instr->Opc3Value() == 0x3));
3676
3677 VFPRegPrecision dst_precision = kDoublePrecision;
3678 VFPRegPrecision src_precision = kSinglePrecision;
3679 if (instr->SzValue() == 1) {
3680 dst_precision = kSinglePrecision;
3681 src_precision = kDoublePrecision;
3682 }
3683
3684 int dst = instr->VFPDRegValue(dst_precision);
3685 int src = instr->VFPMRegValue(src_precision);
3686
3687 if (dst_precision == kSinglePrecision) {
3688 double val = get_double_from_d_register(src).get_scalar();
3689 set_s_register_from_float(dst, static_cast<float>(val));
3690 } else {
3691 float val = get_float_from_s_register(src).get_scalar();
3692 set_d_register_from_double(dst, static_cast<double>(val));
3693 }
3694}
3695
3696bool get_inv_op_vfp_flag(VFPRoundingMode mode, double val, bool unsigned_) {
3697 DCHECK((mode == RN) || (mode == RM) || (mode == RZ));
3698 double max_uint = static_cast<double>(0xFFFFFFFFu);
3699 double max_int = static_cast<double>(kMaxInt);
3700 double min_int = static_cast<double>(kMinInt);
3701
3702 // Check for NaN.
3703 if (val != val) {
3704 return true;
3705 }
3706
3707 // Check for overflow. This code works because 32bit integers can be
3708 // exactly represented by ieee-754 64bit floating-point values.
3709 switch (mode) {
3710 case RN:
3711 return unsigned_ ? (val >= (max_uint + 0.5)) || (val < -0.5)
3712 : (val >= (max_int + 0.5)) || (val < (min_int - 0.5));
3713
3714 case RM:
3715 return unsigned_ ? (val >= (max_uint + 1.0)) || (val < 0)
3716 : (val >= (max_int + 1.0)) || (val < min_int);
3717
3718 case RZ:
3719 return unsigned_ ? (val >= (max_uint + 1.0)) || (val <= -1)
3720 : (val >= (max_int + 1.0)) || (val <= (min_int - 1.0));
3721 default:
3722 UNREACHABLE();
3723 }
3724}
3725
3726// We call this function only if we had a vfp invalid exception.
3727// It returns the correct saturated value.
3728int VFPConversionSaturate(double val, bool unsigned_res) {
3729 if (val != val) {
3730 return 0;
3731 } else {
3732 if (unsigned_res) {
3733 return (val < 0) ? 0 : 0xFFFFFFFFu;
3734 } else {
3735 return (val < 0) ? kMinInt : kMaxInt;
3736 }
3737 }
3738}
3739
3740int32_t Simulator::ConvertDoubleToInt(double val, bool unsigned_integer,
3741 VFPRoundingMode mode) {
3743 if (unsigned_integer) {
3744 // The FastD2UI helper does not have the rounding behavior we want here
3745 // (it doesn't guarantee any particular rounding, and it doesn't check
3746 // for or handle overflow), so do the conversion by hand.
3747 using limits = std::numeric_limits<uint32_t>;
3748 if (val > limits::max()) {
3749 result = limits::max();
3750 } else if (!(val >= 0)) { // Negation to catch NaNs.
3751 result = 0;
3752 } else {
3753 result = static_cast<uint32_t>(val);
3754 }
3755 } else {
3756 result = FastD2IChecked(val);
3757 }
3758
3759 inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer);
3760
3761 double abs_diff = unsigned_integer
3762 ? std::fabs(val - static_cast<uint32_t>(result))
3763 : std::fabs(val - result);
3764
3765 inexact_vfp_flag_ = (abs_diff != 0);
3766
3767 if (inv_op_vfp_flag_) {
3768 result = VFPConversionSaturate(val, unsigned_integer);
3769 } else {
3770 switch (mode) {
3771 case RN: {
3772 int val_sign = (val > 0) ? 1 : -1;
3773 if (abs_diff > 0.5) {
3774 result += val_sign;
3775 } else if (abs_diff == 0.5) {
3776 // Round to even if exactly halfway.
3777 result = ((result % 2) == 0)
3778 ? result
3779 : base::AddWithWraparound(result, val_sign);
3780 }
3781 break;
3782 }
3783
3784 case RM:
3785 result = result > val ? result - 1 : result;
3786 break;
3787
3788 case RZ:
3789 // Nothing to do.
3790 break;
3791
3792 default:
3793 UNREACHABLE();
3794 }
3795 }
3796 return result;
3797}
3798
3799void Simulator::DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr) {
3800 DCHECK((instr->Bit(4) == 0) && (instr->Opc1Value() == 0x7) &&
3801 (instr->Bits(27, 23) == 0x1D));
3802 DCHECK(((instr->Opc2Value() == 0x8) && (instr->Opc3Value() & 0x1)) ||
3803 (((instr->Opc2Value() >> 1) == 0x6) && (instr->Opc3Value() & 0x1)));
3804
3805 // Conversion between floating-point and integer.
3806 bool to_integer = (instr->Bit(18) == 1);
3807
3808 VFPRegPrecision src_precision =
3809 (instr->SzValue() == 1) ? kDoublePrecision : kSinglePrecision;
3810
3811 if (to_integer) {
3812 // We are playing with code close to the C++ standard's limits below,
3813 // hence the very simple code and heavy checks.
3814 //
3815 // Note:
3816 // C++ defines default type casting from floating point to integer as
3817 // (close to) rounding toward zero ("fractional part discarded").
3818
3819 int dst = instr->VFPDRegValue(kSinglePrecision);
3820 int src = instr->VFPMRegValue(src_precision);
3821
3822 // Bit 7 in vcvt instructions indicates if we should use the FPSCR rounding
3823 // mode or the default Round to Zero mode.
3824 VFPRoundingMode mode = (instr->Bit(7) != 1) ? FPSCR_rounding_mode_ : RZ;
3825 DCHECK((mode == RM) || (mode == RZ) || (mode == RN));
3826
3827 bool unsigned_integer = (instr->Bit(16) == 0);
3828 bool double_precision = (src_precision == kDoublePrecision);
3829
3830 double val = double_precision ? get_double_from_d_register(src).get_scalar()
3831 : get_float_from_s_register(src).get_scalar();
3832
3833 int32_t temp = ConvertDoubleToInt(val, unsigned_integer, mode);
3834
3835 // Update the destination register.
3836 set_s_register_from_sinteger(dst, temp);
3837
3838 } else {
3839 bool unsigned_integer = (instr->Bit(7) == 0);
3840
3841 int dst = instr->VFPDRegValue(src_precision);
3842 int src = instr->VFPMRegValue(kSinglePrecision);
3843
3844 int val = get_sinteger_from_s_register(src);
3845
3846 if (src_precision == kDoublePrecision) {
3847 if (unsigned_integer) {
3848 set_d_register_from_double(
3849 dst, static_cast<double>(static_cast<uint32_t>(val)));
3850 } else {
3851 set_d_register_from_double(dst, static_cast<double>(val));
3852 }
3853 } else {
3854 if (unsigned_integer) {
3855 set_s_register_from_float(
3856 dst, static_cast<float>(static_cast<uint32_t>(val)));
3857 } else {
3858 set_s_register_from_float(dst, static_cast<float>(val));
3859 }
3860 }
3861 }
3862}
3863
3864// void Simulator::DecodeType6CoprocessorIns(Instruction* instr)
3865// Decode Type 6 coprocessor instructions.
3866// Dm = vmov(Rt, Rt2)
3867// <Rt, Rt2> = vmov(Dm)
3868// Ddst = MEM(Rbase + 4*offset).
3869// MEM(Rbase + 4*offset) = Dsrc.
3870void Simulator::DecodeType6CoprocessorIns(Instruction* instr) {
3871 DCHECK_EQ(instr->TypeValue(), 6);
3872
3873 if (instr->CoprocessorValue() == 0xA) {
3874 switch (instr->OpcodeValue()) {
3875 case 0x8:
3876 case 0xA:
3877 case 0xC:
3878 case 0xE: { // Load and store single precision float to memory.
3879 int rn = instr->RnValue();
3880 int vd = instr->VFPDRegValue(kSinglePrecision);
3881 int offset = instr->Immed8Value();
3882 if (!instr->HasU()) {
3883 offset = -offset;
3884 }
3885
3886 int32_t address = get_register(rn) + 4 * offset;
3887 // Load and store address for singles must be at least four-byte
3888 // aligned.
3889 DCHECK_EQ(address % 4, 0);
3890 if (instr->HasL()) {
3891 // Load single from memory: vldr.
3892 set_s_register_from_sinteger(vd, ReadW(address));
3893 } else {
3894 // Store single to memory: vstr.
3895 WriteW(address, get_sinteger_from_s_register(vd));
3896 }
3897 break;
3898 }
3899 case 0x4:
3900 case 0x5:
3901 case 0x6:
3902 case 0x7:
3903 case 0x9:
3904 case 0xB:
3905 // Load/store multiple single from memory: vldm/vstm.
3906 HandleVList(instr);
3907 break;
3908 default:
3909 UNIMPLEMENTED(); // Not used by V8.
3910 }
3911 } else if (instr->CoprocessorValue() == 0xB) {
3912 switch (instr->OpcodeValue()) {
3913 case 0x2:
3914 // Load and store double to two GP registers
3915 if (instr->Bits(7, 6) != 0 || instr->Bit(4) != 1) {
3916 UNIMPLEMENTED(); // Not used by V8.
3917 } else {
3918 int rt = instr->RtValue();
3919 int rn = instr->RnValue();
3920 int vm = instr->VFPMRegValue(kDoublePrecision);
3921 if (instr->HasL()) {
3922 uint32_t data[2];
3923 get_d_register(vm, data);
3924 set_register(rt, data[0]);
3925 set_register(rn, data[1]);
3926 } else {
3927 int32_t data[] = {get_register(rt), get_register(rn)};
3928 set_d_register(vm, reinterpret_cast<uint32_t*>(data));
3929 }
3930 }
3931 break;
3932 case 0x8:
3933 case 0xA:
3934 case 0xC:
3935 case 0xE: { // Load and store double to memory.
3936 int rn = instr->RnValue();
3937 int vd = instr->VFPDRegValue(kDoublePrecision);
3938 int offset = instr->Immed8Value();
3939 if (!instr->HasU()) {
3940 offset = -offset;
3941 }
3942 int32_t address = get_register(rn) + 4 * offset;
3943 // Load and store address for doubles must be at least four-byte
3944 // aligned.
3945 DCHECK_EQ(address % 4, 0);
3946 if (instr->HasL()) {
3947 // Load double from memory: vldr.
3948 int32_t data[] = {ReadW(address), ReadW(address + 4)};
3949 set_d_register(vd, reinterpret_cast<uint32_t*>(data));
3950 } else {
3951 // Store double to memory: vstr.
3952 uint32_t data[2];
3953 get_d_register(vd, data);
3954 WriteW(address, data[0]);
3955 WriteW(address + 4, data[1]);
3956 }
3957 break;
3958 }
3959 case 0x4:
3960 case 0x5:
3961 case 0x6:
3962 case 0x7:
3963 case 0x9:
3964 case 0xB:
3965 // Load/store multiple double from memory: vldm/vstm.
3966 HandleVList(instr);
3967 break;
3968 default:
3969 UNIMPLEMENTED(); // Not used by V8.
3970 }
3971 } else {
3972 UNIMPLEMENTED(); // Not used by V8.
3973 }
3974}
3975
3976// Helper functions for implementing NEON ops. Unop applies a unary op to each
3977// lane. Binop applies a binary operation to matching input lanes.
3978template <typename T, int SIZE = kSimd128Size>
3979void Unop(Simulator* simulator, int Vd, int Vm, std::function<T(T)> unop) {
3980 static const int kLanes = SIZE / sizeof(T);
3981 T src[kLanes];
3982 simulator->get_neon_register<T, SIZE>(Vm, src);
3983 for (int i = 0; i < kLanes; i++) {
3984 src[i] = unop(src[i]);
3985 }
3986 simulator->set_neon_register<T, SIZE>(Vd, src);
3987}
3988
3989template <typename T, int SIZE = kSimd128Size>
3990void Binop(Simulator* simulator, int Vd, int Vm, int Vn,
3991 std::function<T(T, T)> binop) {
3992 static const int kLanes = SIZE / sizeof(T);
3993 T src1[kLanes], src2[kLanes];
3994 simulator->get_neon_register<T, SIZE>(Vn, src1);
3995 simulator->get_neon_register<T, SIZE>(Vm, src2);
3996 for (int i = 0; i < kLanes; i++) {
3997 src1[i] = binop(src1[i], src2[i]);
3998 }
3999 simulator->set_neon_register<T, SIZE>(Vd, src1);
4000}
4001
4002// Templated operations for NEON instructions.
4003template <typename T, typename U>
4004U Widen(T value) {
4005 static_assert(sizeof(int64_t) > sizeof(T), "T must be int32_t or smaller");
4006 static_assert(sizeof(U) > sizeof(T), "T must smaller than U");
4007 return static_cast<U>(value);
4008}
4009
4010template <typename T, typename U>
4011void Widen(Simulator* simulator, int Vd, int Vm) {
4012 static const int kLanes = 8 / sizeof(T);
4013 T src[kLanes];
4014 U dst[kLanes];
4015 simulator->get_neon_register<T, kDoubleSize>(Vm, src);
4016 for (int i = 0; i < kLanes; i++) {
4017 dst[i] = Widen<T, U>(src[i]);
4018 }
4019 simulator->set_neon_register(Vd, dst);
4020}
4021
4022template <typename T, int SIZE>
4023void Abs(Simulator* simulator, int Vd, int Vm) {
4024 Unop<T>(simulator, Vd, Vm, [](T x) { return std::abs(x); });
4025}
4026
4027template <typename T, int SIZE>
4028void Neg(Simulator* simulator, int Vd, int Vm) {
4029 Unop<T>(simulator, Vd, Vm, [](T x) {
4030 // The respective minimum (negative) value maps to itself.
4031 return x == std::numeric_limits<T>::min() ? x : -x;
4032 });
4033}
4034
4035template <typename T, typename U>
4036void SaturatingNarrow(Simulator* simulator, int Vd, int Vm) {
4037 static const int kLanes = 16 / sizeof(T);
4038 T src[kLanes];
4039 U dst[kLanes];
4040 simulator->get_neon_register(Vm, src);
4041 for (int i = 0; i < kLanes; i++) {
4042 dst[i] = base::saturated_cast<U>(src[i]);
4043 }
4044 simulator->set_neon_register<U, kDoubleSize>(Vd, dst);
4045}
4046
4047template <typename T>
4048void AddSat(Simulator* simulator, int Vd, int Vm, int Vn) {
4049 Binop<T>(simulator, Vd, Vm, Vn, SaturateAdd<T>);
4050}
4051
4052template <typename T>
4053void SubSat(Simulator* simulator, int Vd, int Vm, int Vn) {
4054 Binop<T>(simulator, Vd, Vm, Vn, SaturateSub<T>);
4055}
4056
4057template <typename T, int SIZE>
4058void Zip(Simulator* simulator, int Vd, int Vm) {
4059 static const int kElems = SIZE / sizeof(T);
4060 static const int kPairs = kElems / 2;
4061 T src1[kElems], src2[kElems], dst1[kElems], dst2[kElems];
4062 simulator->get_neon_register<T, SIZE>(Vd, src1);
4063 simulator->get_neon_register<T, SIZE>(Vm, src2);
4064 for (int i = 0; i < kPairs; i++) {
4065 dst1[i * 2] = src1[i];
4066 dst1[i * 2 + 1] = src2[i];
4067 dst2[i * 2] = src1[i + kPairs];
4068 dst2[i * 2 + 1] = src2[i + kPairs];
4069 }
4070 simulator->set_neon_register<T, SIZE>(Vd, dst1);
4071 simulator->set_neon_register<T, SIZE>(Vm, dst2);
4072}
4073
4074template <typename T, int SIZE>
4075void Unzip(Simulator* simulator, int Vd, int Vm) {
4076 static const int kElems = SIZE / sizeof(T);
4077 static const int kPairs = kElems / 2;
4078 T src1[kElems], src2[kElems], dst1[kElems], dst2[kElems];
4079 simulator->get_neon_register<T, SIZE>(Vd, src1);
4080 simulator->get_neon_register<T, SIZE>(Vm, src2);
4081 for (int i = 0; i < kPairs; i++) {
4082 dst1[i] = src1[i * 2];
4083 dst1[i + kPairs] = src2[i * 2];
4084 dst2[i] = src1[i * 2 + 1];
4085 dst2[i + kPairs] = src2[i * 2 + 1];
4086 }
4087 simulator->set_neon_register<T, SIZE>(Vd, dst1);
4088 simulator->set_neon_register<T, SIZE>(Vm, dst2);
4089}
4090
4091template <typename T, int SIZE>
4092void Transpose(Simulator* simulator, int Vd, int Vm) {
4093 static const int kElems = SIZE / sizeof(T);
4094 static const int kPairs = kElems / 2;
4095 T src1[kElems], src2[kElems];
4096 simulator->get_neon_register<T, SIZE>(Vd, src1);
4097 simulator->get_neon_register<T, SIZE>(Vm, src2);
4098 for (int i = 0; i < kPairs; i++) {
4099 std::swap(src1[2 * i + 1], src2[2 * i]);
4100 }
4101 simulator->set_neon_register<T, SIZE>(Vd, src1);
4102 simulator->set_neon_register<T, SIZE>(Vm, src2);
4103}
4104
4105template <typename T, int SIZE>
4106void Test(Simulator* simulator, int Vd, int Vm, int Vn) {
4107 auto test = [](T x, T y) { return (x & y) ? -1 : 0; };
4108 Binop<T>(simulator, Vd, Vm, Vn, test);
4109}
4110
4111template <typename T, int SIZE>
4112void Add(Simulator* simulator, int Vd, int Vm, int Vn) {
4113 Binop<T>(simulator, Vd, Vm, Vn, std::plus<T>());
4114}
4115
4116template <typename T, int SIZE>
4117void Sub(Simulator* simulator, int Vd, int Vm, int Vn) {
4118 Binop<T>(simulator, Vd, Vm, Vn, std::minus<T>());
4119}
4120
4121namespace {
4122uint32_t Multiply(uint32_t a, uint32_t b) { return a * b; }
4123uint8_t Multiply(uint8_t a, uint8_t b) { return a * b; }
4124// 16-bit integers are special due to C++'s implicit conversion rules.
4125// See https://bugs.llvm.org/show_bug.cgi?id=25580.
4126uint16_t Multiply(uint16_t a, uint16_t b) {
4127 uint32_t result = static_cast<uint32_t>(a) * static_cast<uint32_t>(b);
4128 return static_cast<uint16_t>(result);
4129}
4130
4131void VmovImmediate(Simulator* simulator, Instruction* instr) {
4132 uint8_t cmode = instr->Bits(11, 8);
4133 int vd = instr->VFPDRegValue(kDoublePrecision);
4134 int q = instr->Bit(6);
4135 int regs = q ? 2 : 1;
4136 uint8_t imm = instr->Bit(24) << 7; // i
4137 imm |= instr->Bits(18, 16) << 4; // imm3
4138 imm |= instr->Bits(3, 0); // imm4
4139 switch (cmode) {
4140 case 0: {
4141 // Set the LSB of each 64-bit halves.
4142 uint64_t imm64 = imm;
4143 for (int r = 0; r < regs; r++) {
4144 simulator->set_d_register(vd + r, &imm64);
4145 }
4146 break;
4147 }
4148 case 0xe: {
4149 uint8_t imms[kSimd128Size];
4150 // Set all bytes of register.
4151 std::fill_n(imms, kSimd128Size, imm);
4152 uint64_t imm64;
4153 memcpy(&imm64, imms, 8);
4154 for (int r = 0; r < regs; r++) {
4155 simulator->set_d_register(vd + r, &imm64);
4156 }
4157 break;
4158 }
4159 default: {
4160 UNIMPLEMENTED();
4161 }
4162 }
4163}
4164} // namespace
4165
4166template <typename T, int SIZE>
4167void Mul(Simulator* simulator, int Vd, int Vm, int Vn) {
4168 static const int kElems = SIZE / sizeof(T);
4169 T src1[kElems], src2[kElems];
4170 simulator->get_neon_register<T, SIZE>(Vn, src1);
4171 simulator->get_neon_register<T, SIZE>(Vm, src2);
4172 for (int i = 0; i < kElems; i++) {
4173 src1[i] = Multiply(src1[i], src2[i]);
4174 }
4175 simulator->set_neon_register<T, SIZE>(Vd, src1);
4176}
4177
4178template <typename T, int SIZE>
4179void ShiftLeft(Simulator* simulator, int Vd, int Vm, int shift) {
4180 Unop<T>(simulator, Vd, Vm, [shift](T x) { return x << shift; });
4181}
4182
4183template <typename T, int SIZE>
4184void LogicalShiftRight(Simulator* simulator, int Vd, int Vm, int shift) {
4185 Unop<T, SIZE>(simulator, Vd, Vm, [shift](T x) { return x >> shift; });
4186}
4187
4188template <typename T, int SIZE>
4189void ArithmeticShiftRight(Simulator* simulator, int Vd, int Vm, int shift) {
4190 auto shift_fn =
4191 std::bind(ArithmeticShiftRight<T>, std::placeholders::_1, shift);
4192 Unop<T, SIZE>(simulator, Vd, Vm, shift_fn);
4193}
4194
4195template <typename T, int SIZE>
4196void ShiftRight(Simulator* simulator, int Vd, int Vm, int shift,
4197 bool is_unsigned) {
4198 if (is_unsigned) {
4199 using unsigned_T = std::make_unsigned_t<T>;
4200 LogicalShiftRight<unsigned_T, SIZE>(simulator, Vd, Vm, shift);
4201 } else {
4202 ArithmeticShiftRight<T, SIZE>(simulator, Vd, Vm, shift);
4203 }
4204}
4205
4206template <typename T, int SIZE>
4207void ShiftRightAccumulate(Simulator* simulator, int Vd, int Vm, int shift) {
4208 Binop<T, SIZE>(simulator, Vd, Vm, Vd,
4209 [shift](T a, T x) { return a + (x >> shift); });
4210}
4211
4212template <typename T, int SIZE>
4213void ArithmeticShiftRightAccumulate(Simulator* simulator, int Vd, int Vm,
4214 int shift) {
4215 Binop<T, SIZE>(simulator, Vd, Vm, Vd, [shift](T a, T x) {
4216 T result = ArithmeticShiftRight<T>(x, shift);
4217 return a + result;
4218 });
4219}
4220
4221template <typename T, int SIZE>
4222void ShiftLeftAndInsert(Simulator* simulator, int Vd, int Vm, int shift) {
4223 static const int kElems = SIZE / sizeof(T);
4224 T src[kElems];
4225 T dst[kElems];
4226 simulator->get_neon_register<T, SIZE>(Vm, src);
4227 simulator->get_neon_register<T, SIZE>(Vd, dst);
4228 uint64_t mask = (1llu << shift) - 1llu;
4229 for (int i = 0; i < kElems; i++) {
4230 dst[i] = (src[i] << shift) | (dst[i] & mask);
4231 }
4232 simulator->set_neon_register<T, SIZE>(Vd, dst);
4233}
4234
4235template <typename T, int SIZE>
4236void ShiftRightAndInsert(Simulator* simulator, int Vd, int Vm, int shift) {
4237 static const int kElems = SIZE / sizeof(T);
4238 T src[kElems];
4239 T dst[kElems];
4240 simulator->get_neon_register<T, SIZE>(Vm, src);
4241 simulator->get_neon_register<T, SIZE>(Vd, dst);
4242 uint64_t mask = ~((1llu << (kBitsPerByte * SIZE - shift)) - 1llu);
4243 for (int i = 0; i < kElems; i++) {
4244 dst[i] = (src[i] >> shift) | (dst[i] & mask);
4245 }
4246 simulator->set_neon_register<T, SIZE>(Vd, dst);
4247}
4248
4249template <typename T, typename S_T, int SIZE>
4250void ShiftByRegister(Simulator* simulator, int Vd, int Vm, int Vn) {
4251 static const int kElems = SIZE / sizeof(T);
4252 T src[kElems];
4253 S_T shift[kElems];
4254 simulator->get_neon_register<T, SIZE>(Vm, src);
4255 simulator->get_neon_register<S_T, SIZE>(Vn, shift);
4256 for (int i = 0; i < kElems; i++) {
4257 // Take lowest 8 bits of shift value (see F6.1.217 of ARM Architecture
4258 // Reference Manual ARMv8), as signed 8-bit value.
4259 int8_t shift_value = static_cast<int8_t>(shift[i]);
4260 int size = static_cast<int>(sizeof(T) * 8);
4261 // When shift value is greater/equal than size, we end up relying on
4262 // undefined behavior, handle that and emulate what the hardware does.
4263 if ((shift_value) >= 0) {
4264 // If the shift value is greater/equal than size, zero out the result.
4265 if (shift_value >= size) {
4266 src[i] = 0;
4267 } else {
4268 using unsignedT = std::make_unsigned_t<T>;
4269 src[i] = static_cast<unsignedT>(src[i]) << shift_value;
4270 }
4271 } else {
4272 // If the shift value is greater/equal than size, always end up with -1.
4273 if (-shift_value >= size) {
4274 src[i] = -1;
4275 } else {
4276 src[i] = ArithmeticShiftRight(src[i], -shift_value);
4277 }
4278 }
4279 }
4280 simulator->set_neon_register<T, SIZE>(Vd, src);
4281}
4282
4283template <typename T, int SIZE>
4284void CompareEqual(Simulator* simulator, int Vd, int Vm, int Vn) {
4285 Binop<T>(simulator, Vd, Vm, Vn, [](T x, T y) { return x == y ? -1 : 0; });
4286}
4287
4288template <typename T, int SIZE>
4289void CompareGreater(Simulator* simulator, int Vd, int Vm, int Vn, bool ge) {
4290 if (ge) {
4291 Binop<T>(simulator, Vd, Vm, Vn, [](T x, T y) { return x >= y ? -1 : 0; });
4292 } else {
4293 Binop<T>(simulator, Vd, Vm, Vn, [](T x, T y) { return x > y ? -1 : 0; });
4294 }
4295}
4296
4297float MinMax(float a, float b, bool is_min) {
4298 return is_min ? JSMin(a, b) : JSMax(a, b);
4299}
4300template <typename T>
4301T MinMax(T a, T b, bool is_min) {
4302 return is_min ? std::min(a, b) : std::max(a, b);
4303}
4304
4305template <typename T, int SIZE>
4306void MinMax(Simulator* simulator, int Vd, int Vm, int Vn, bool min) {
4307 if (min) {
4308 Binop<T>(simulator, Vd, Vm, Vn,
4309 [](auto x, auto y) { return std::min<T>(x, y); });
4310 } else {
4311 Binop<T>(simulator, Vd, Vm, Vn,
4312 [](auto x, auto y) { return std::max<T>(x, y); });
4313 }
4314}
4315
4316template <typename T>
4317void PairwiseMinMax(Simulator* simulator, int Vd, int Vm, int Vn, bool min) {
4318 static const int kElems = kDoubleSize / sizeof(T);
4319 static const int kPairs = kElems / 2;
4320 T dst[kElems], src1[kElems], src2[kElems];
4321 simulator->get_neon_register<T, kDoubleSize>(Vn, src1);
4322 simulator->get_neon_register<T, kDoubleSize>(Vm, src2);
4323 for (int i = 0; i < kPairs; i++) {
4324 dst[i] = MinMax(src1[i * 2], src1[i * 2 + 1], min);
4325 dst[i + kPairs] = MinMax(src2[i * 2], src2[i * 2 + 1], min);
4326 }
4327 simulator->set_neon_register<T, kDoubleSize>(Vd, dst);
4328}
4329
4330template <typename T>
4331void PairwiseAdd(Simulator* simulator, int Vd, int Vm, int Vn) {
4332 static const int kElems = kDoubleSize / sizeof(T);
4333 static const int kPairs = kElems / 2;
4334 T dst[kElems], src1[kElems], src2[kElems];
4335 simulator->get_neon_register<T, kDoubleSize>(Vn, src1);
4336 simulator->get_neon_register<T, kDoubleSize>(Vm, src2);
4337 for (int i = 0; i < kPairs; i++) {
4338 dst[i] = src1[i * 2] + src1[i * 2 + 1];
4339 dst[i + kPairs] = src2[i * 2] + src2[i * 2 + 1];
4340 }
4341 simulator->set_neon_register<T, kDoubleSize>(Vd, dst);
4342}
4343
4344template <typename NarrowType, typename WideType, int SIZE = kSimd128Size>
4345void PairwiseAddLong(Simulator* simulator, int Vd, int Vm) {
4346 DCHECK_EQ(sizeof(WideType), 2 * sizeof(NarrowType));
4347 static constexpr int kSElems = SIZE / sizeof(NarrowType);
4348 static constexpr int kTElems = SIZE / sizeof(WideType);
4349 NarrowType src[kSElems];
4350 WideType dst[kTElems];
4351 simulator->get_neon_register<NarrowType, SIZE>(Vm, src);
4352 for (int i = 0; i < kTElems; i++) {
4353 dst[i] = WideType{src[i * 2]} + WideType{src[i * 2 + 1]};
4354 }
4355 simulator->set_neon_register<WideType, SIZE>(Vd, dst);
4356}
4357
4358template <typename NarrowType, typename WideType, int SIZE = kSimd128Size>
4359void PairwiseAddAccumulateLong(Simulator* simulator, int Vd, int Vm) {
4360 DCHECK_EQ(sizeof(WideType), 2 * sizeof(NarrowType));
4361 static constexpr int kSElems = SIZE / sizeof(NarrowType);
4362 static constexpr int kTElems = SIZE / sizeof(WideType);
4363 NarrowType src[kSElems];
4364 WideType dst[kTElems];
4365 simulator->get_neon_register<NarrowType, SIZE>(Vm, src);
4366 simulator->get_neon_register<WideType, SIZE>(Vd, dst);
4367 for (int i = 0; i < kTElems; i++) {
4368 dst[i] += WideType{src[i * 2]} + WideType{src[i * 2 + 1]};
4369 }
4370 simulator->set_neon_register<WideType, SIZE>(Vd, dst);
4371}
4372
4373template <typename NarrowType, typename WideType>
4374void MultiplyLong(Simulator* simulator, int Vd, int Vn, int Vm) {
4375 DCHECK_EQ(sizeof(WideType), 2 * sizeof(NarrowType));
4376 static const int kElems = kSimd128Size / sizeof(WideType);
4377 NarrowType src1[kElems], src2[kElems];
4378 WideType dst[kElems];
4379
4380 // Get the entire d reg, then memcpy it to an array so we can address the
4381 // underlying datatype easily.
4382 uint64_t tmp;
4383 simulator->get_d_register(Vn, &tmp);
4384 memcpy(src1, &tmp, sizeof(tmp));
4385 simulator->get_d_register(Vm, &tmp);
4386 memcpy(src2, &tmp, sizeof(tmp));
4387
4388 for (int i = 0; i < kElems; i++) {
4389 dst[i] = WideType{src1[i]} * WideType{src2[i]};
4390 }
4391
4392 simulator->set_neon_register<WideType>(Vd, dst);
4393}
4394
4395void Simulator::DecodeUnconditional(Instruction* instr) {
4396 // This follows the decoding in F4.1.18 Unconditional instructions.
4397 int op0 = instr->Bits(26, 25);
4398 int op1 = instr->Bit(20);
4399
4400 // Four classes of decoding:
4401 // - Miscellaneous (omitted, no instructions used in V8).
4402 // - Advanced SIMD data-processing.
4403 // - Memory hints and barriers.
4404 // - Advanced SIMD element or structure load/store.
4405 if (op0 == 0b01) {
4406 DecodeAdvancedSIMDDataProcessing(instr);
4407 } else if ((op0 & 0b10) == 0b10 && op1) {
4408 DecodeMemoryHintsAndBarriers(instr);
4409 } else if (op0 == 0b10 && !op1) {
4410 DecodeAdvancedSIMDElementOrStructureLoadStore(instr);
4411 } else {
4412 UNIMPLEMENTED();
4413 }
4414}
4415
4416void Simulator::DecodeAdvancedSIMDTwoOrThreeRegisters(Instruction* instr) {
4417 // Advanced SIMD two registers, or three registers of different lengths.
4418 int op0 = instr->Bit(24);
4419 int op1 = instr->Bits(21, 20);
4420 int op2 = instr->Bits(11, 10);
4421 int op3 = instr->Bit(6);
4422 if (!op0 && op1 == 0b11) {
4423 // vext.8 Qd, Qm, Qn, imm4
4424 int imm4 = instr->Bits(11, 8);
4425 int Vd = instr->VFPDRegValue(kSimd128Precision);
4426 int Vm = instr->VFPMRegValue(kSimd128Precision);
4427 int Vn = instr->VFPNRegValue(kSimd128Precision);
4428 uint8_t src1[16], src2[16], dst[16];
4429 get_neon_register(Vn, src1);
4430 get_neon_register(Vm, src2);
4431 int boundary = kSimd128Size - imm4;
4432 int i = 0;
4433 for (; i < boundary; i++) {
4434 dst[i] = src1[i + imm4];
4435 }
4436 for (; i < 16; i++) {
4437 dst[i] = src2[i - boundary];
4438 }
4439 set_neon_register(Vd, dst);
4440 } else if (op0 && op1 == 0b11 && ((op2 >> 1) == 0)) {
4441 // Advanced SIMD two registers misc
4442 int size = instr->Bits(19, 18);
4443 int opc1 = instr->Bits(17, 16);
4444 int opc2 = instr->Bits(10, 7);
4445 int q = instr->Bit(6);
4446
4447 if (opc1 == 0 && (opc2 >> 2) == 0) {
4448 // vrev<op>.size Qd, Qm
4449 int Vd = instr->VFPDRegValue(kSimd128Precision);
4450 int Vm = instr->VFPMRegValue(kSimd128Precision);
4451 NeonSize size = static_cast<NeonSize>(instr->Bits(19, 18));
4452 NeonSize op =
4453 static_cast<NeonSize>(static_cast<int>(Neon64) - instr->Bits(8, 7));
4454 switch (op) {
4455 case Neon16: {
4456 DCHECK_EQ(Neon8, size);
4457 uint8_t src[16];
4458 get_neon_register(Vm, src);
4459 for (int i = 0; i < 16; i += 2) {
4460 std::swap(src[i], src[i + 1]);
4461 }
4462 set_neon_register(Vd, src);
4463 break;
4464 }
4465 case Neon32: {
4466 switch (size) {
4467 case Neon16: {
4468 uint16_t src[8];
4469 get_neon_register(Vm, src);
4470 for (int i = 0; i < 8; i += 2) {
4471 std::swap(src[i], src[i + 1]);
4472 }
4473 set_neon_register(Vd, src);
4474 break;
4475 }
4476 case Neon8: {
4477 uint8_t src[16];
4478 get_neon_register(Vm, src);
4479 for (int i = 0; i < 4; i++) {
4480 std::swap(src[i * 4], src[i * 4 + 3]);
4481 std::swap(src[i * 4 + 1], src[i * 4 + 2]);
4482 }
4483 set_neon_register(Vd, src);
4484 break;
4485 }
4486 default:
4487 UNREACHABLE();
4488 }
4489 break;
4490 }
4491 case Neon64: {
4492 switch (size) {
4493 case Neon32: {
4494 uint32_t src[4];
4495 get_neon_register(Vm, src);
4496 std::swap(src[0], src[1]);
4497 std::swap(src[2], src[3]);
4498 set_neon_register(Vd, src);
4499 break;
4500 }
4501 case Neon16: {
4502 uint16_t src[8];
4503 get_neon_register(Vm, src);
4504 for (int i = 0; i < 2; i++) {
4505 std::swap(src[i * 4], src[i * 4 + 3]);
4506 std::swap(src[i * 4 + 1], src[i * 4 + 2]);
4507 }
4508 set_neon_register(Vd, src);
4509 break;
4510 }
4511 case Neon8: {
4512 uint8_t src[16];
4513 get_neon_register(Vm, src);
4514 for (int i = 0; i < 4; i++) {
4515 std::swap(src[i], src[7 - i]);
4516 std::swap(src[i + 8], src[15 - i]);
4517 }
4518 set_neon_register(Vd, src);
4519 break;
4520 }
4521 default:
4522 UNREACHABLE();
4523 }
4524 break;
4525 }
4526 default:
4527 UNREACHABLE();
4528 }
4529 } else if (opc1 == 0 && (opc2 == 0b0100 || opc2 == 0b0101)) {
4530 DCHECK_EQ(1, instr->Bit(6)); // Only support Q regs.
4531 int Vd = instr->VFPDRegValue(kSimd128Precision);
4532 int Vm = instr->VFPMRegValue(kSimd128Precision);
4533 int is_signed = instr->Bit(7) == 0;
4534 // vpaddl Qd, Qm.
4535 switch (size) {
4536 case Neon8:
4537 is_signed ? PairwiseAddLong<int8_t, int16_t>(this, Vd, Vm)
4538 : PairwiseAddLong<uint8_t, uint16_t>(this, Vd, Vm);
4539 break;
4540 case Neon16:
4541 is_signed ? PairwiseAddLong<int16_t, int32_t>(this, Vd, Vm)
4542 : PairwiseAddLong<uint16_t, uint32_t>(this, Vd, Vm);
4543 break;
4544 case Neon32:
4545 is_signed ? PairwiseAddLong<int32_t, int64_t>(this, Vd, Vm)
4546 : PairwiseAddLong<uint32_t, uint64_t>(this, Vd, Vm);
4547 break;
4548 case Neon64:
4549 UNREACHABLE();
4550 }
4551 } else if (opc1 == 0 && (opc2 == 0b1100 || opc2 == 0b1101)) {
4552 DCHECK_EQ(1, instr->Bit(6)); // Only support Q regs.
4553 int Vd = instr->VFPDRegValue(kSimd128Precision);
4554 int Vm = instr->VFPMRegValue(kSimd128Precision);
4555 int is_signed = instr->Bit(7) == 0;
4556 // vpadal Qd, Qm
4557 switch (size) {
4558 case Neon8:
4559 is_signed
4560 ? PairwiseAddAccumulateLong<int8_t, int16_t>(this, Vd, Vm)
4561 : PairwiseAddAccumulateLong<uint8_t, uint16_t>(this, Vd, Vm);
4562 break;
4563 case Neon16:
4564 is_signed
4565 ? PairwiseAddAccumulateLong<int16_t, int32_t>(this, Vd, Vm)
4566 : PairwiseAddAccumulateLong<uint16_t, uint32_t>(this, Vd, Vm);
4567 break;
4568 case Neon32:
4569 is_signed
4570 ? PairwiseAddAccumulateLong<int32_t, int64_t>(this, Vd, Vm)
4571 : PairwiseAddAccumulateLong<uint32_t, uint64_t>(this, Vd, Vm);
4572 break;
4573 case Neon64:
4574 UNREACHABLE();
4575 }
4576 } else if (size == 0 && opc1 == 0b10 && opc2 == 0) {
4577 if (instr->Bit(6) == 0) {
4578 // vswp Dd, Dm.
4579 uint64_t dval, mval;
4580 int vd = instr->VFPDRegValue(kDoublePrecision);
4581 int vm = instr->VFPMRegValue(kDoublePrecision);
4582 get_d_register(vd, &dval);
4583 get_d_register(vm, &mval);
4584 set_d_register(vm, &dval);
4585 set_d_register(vd, &mval);
4586 } else {
4587 // vswp Qd, Qm.
4588 uint32_t dval[4], mval[4];
4589 int vd = instr->VFPDRegValue(kSimd128Precision);
4590 int vm = instr->VFPMRegValue(kSimd128Precision);
4591 get_neon_register(vd, dval);
4592 get_neon_register(vm, mval);
4593 set_neon_register(vm, dval);
4594 set_neon_register(vd, mval);
4595 }
4596 } else if (opc1 == 0 && opc2 == 0b1010) {
4597 // vcnt Qd, Qm.
4598 DCHECK_EQ(0, size);
4599 int vd = instr->VFPDRegValue(q ? kSimd128Precision : kDoublePrecision);
4600 int vm = instr->VFPMRegValue(q ? kSimd128Precision : kDoublePrecision);
4601 uint8_t q_data[16];
4602 get_neon_register(vm, q_data);
4603 for (int i = 0; i < 16; i++) {
4604 q_data[i] = base::bits::CountPopulation(q_data[i]);
4605 }
4606 set_neon_register(vd, q_data);
4607 } else if (opc1 == 0 && opc2 == 0b1011) {
4608 // vmvn Qd, Qm.
4609 int vd = instr->VFPDRegValue(kSimd128Precision);
4610 int vm = instr->VFPMRegValue(kSimd128Precision);
4611 uint32_t q_data[4];
4612 get_neon_register(vm, q_data);
4613 for (int i = 0; i < 4; i++) q_data[i] = ~q_data[i];
4614 set_neon_register(vd, q_data);
4615 } else if (opc1 == 0b01 && opc2 == 0b0010) {
4616 // vceq.<dt> Qd, Qm, #0 (signed integers).
4617 int Vd = instr->VFPDRegValue(kSimd128Precision);
4618 int Vm = instr->VFPMRegValue(kSimd128Precision);
4619 switch (size) {
4620 case Neon8:
4621 Unop<int8_t>(this, Vd, Vm, [](int8_t x) { return x == 0 ? -1 : 0; });
4622 break;
4623 case Neon16:
4624 Unop<int16_t>(this, Vd, Vm,
4625 [](int16_t x) { return x == 0 ? -1 : 0; });
4626 break;
4627 case Neon32:
4628 Unop<int32_t>(this, Vd, Vm,
4629 [](int32_t x) { return x == 0 ? -1 : 0; });
4630 break;
4631 case Neon64:
4632 UNREACHABLE();
4633 }
4634 } else if (opc1 == 0b01 && opc2 == 0b0100) {
4635 // vclt.<dt> Qd, Qm, #0 (signed integers).
4636 int Vd = instr->VFPDRegValue(kSimd128Precision);
4637 int Vm = instr->VFPMRegValue(kSimd128Precision);
4638 switch (size) {
4639 case Neon8:
4640 Unop<int8_t>(this, Vd, Vm, [](int8_t x) { return x < 0 ? -1 : 0; });
4641 break;
4642 case Neon16:
4643 Unop<int16_t>(this, Vd, Vm, [](int16_t x) { return x < 0 ? -1 : 0; });
4644 break;
4645 case Neon32:
4646 Unop<int32_t>(this, Vd, Vm, [](int32_t x) { return x < 0 ? -1 : 0; });
4647 break;
4648 case Neon64:
4649 UNREACHABLE();
4650 }
4651 } else if (opc1 == 0b01 && (opc2 & 0b0111) == 0b110) {
4652 // vabs<type>.<size> Qd, Qm
4653 int Vd = instr->VFPDRegValue(kSimd128Precision);
4654 int Vm = instr->VFPMRegValue(kSimd128Precision);
4655 if (instr->Bit(10) != 0) {
4656 // floating point (clear sign bits)
4657 uint32_t src[4];
4658 get_neon_register(Vm, src);
4659 for (int i = 0; i < 4; i++) {
4660 src[i] &= ~0x80000000;
4661 }
4662 set_neon_register(Vd, src);
4663 } else {
4664 // signed integer
4665 switch (size) {
4666 case Neon8:
4667 Abs<int8_t, kSimd128Size>(this, Vd, Vm);
4668 break;
4669 case Neon16:
4670 Abs<int16_t, kSimd128Size>(this, Vd, Vm);
4671 break;
4672 case Neon32:
4673 Abs<int32_t, kSimd128Size>(this, Vd, Vm);
4674 break;
4675 default:
4676 UNIMPLEMENTED();
4677 }
4678 }
4679 } else if (opc1 == 0b01 && (opc2 & 0b0111) == 0b111) {
4680 int Vd = instr->VFPDRegValue(kSimd128Precision);
4681 int Vm = instr->VFPMRegValue(kSimd128Precision);
4682 // vneg<type>.<size> Qd, Qm (signed integer)
4683 if (instr->Bit(10) != 0) {
4684 // floating point (toggle sign bits)
4685 uint32_t src[4];
4686 get_neon_register(Vm, src);
4687 for (int i = 0; i < 4; i++) {
4688 src[i] ^= 0x80000000;
4689 }
4690 set_neon_register(Vd, src);
4691 } else {
4692 // signed integer
4693 switch (size) {
4694 case Neon8:
4695 Neg<int8_t, kSimd128Size>(this, Vd, Vm);
4696 break;
4697 case Neon16:
4698 Neg<int16_t, kSimd128Size>(this, Vd, Vm);
4699 break;
4700 case Neon32:
4701 Neg<int32_t, kSimd128Size>(this, Vd, Vm);
4702 break;
4703 default:
4704 UNIMPLEMENTED();
4705 }
4706 }
4707 } else if (opc1 == 0b10 && opc2 == 0b0001) {
4708 if (q) {
4709 int Vd = instr->VFPDRegValue(kSimd128Precision);
4710 int Vm = instr->VFPMRegValue(kSimd128Precision);
4711 // vtrn.<size> Qd, Qm.
4712 switch (size) {
4713 case Neon8:
4714 Transpose<uint8_t, kSimd128Size>(this, Vd, Vm);
4715 break;
4716 case Neon16:
4717 Transpose<uint16_t, kSimd128Size>(this, Vd, Vm);
4718 break;
4719 case Neon32:
4720 Transpose<uint32_t, kSimd128Size>(this, Vd, Vm);
4721 break;
4722 default:
4723 UNREACHABLE();
4724 }
4725 } else {
4726 int Vd = instr->VFPDRegValue(kDoublePrecision);
4727 int Vm = instr->VFPMRegValue(kDoublePrecision);
4728 // vtrn.<size> Dd, Dm.
4729 switch (size) {
4730 case Neon8:
4731 Transpose<uint8_t, kDoubleSize>(this, Vd, Vm);
4732 break;
4733 case Neon16:
4734 Transpose<uint16_t, kDoubleSize>(this, Vd, Vm);
4735 break;
4736 case Neon32:
4737 Transpose<uint32_t, kDoubleSize>(this, Vd, Vm);
4738 break;
4739 default:
4740 UNREACHABLE();
4741 }
4742 }
4743 } else if (opc1 == 0b10 && (opc2 & 0b1110) == 0b0010) {
4744 NeonSize size = static_cast<NeonSize>(instr->Bits(19, 18));
4745 if (q) {
4746 int Vd = instr->VFPDRegValue(kSimd128Precision);
4747 int Vm = instr->VFPMRegValue(kSimd128Precision);
4748 if (instr->Bit(7) == 1) {
4749 // vzip.<size> Qd, Qm.
4750 switch (size) {
4751 case Neon8:
4752 Zip<uint8_t, kSimd128Size>(this, Vd, Vm);
4753 break;
4754 case Neon16:
4755 Zip<uint16_t, kSimd128Size>(this, Vd, Vm);
4756 break;
4757 case Neon32:
4758 Zip<uint32_t, kSimd128Size>(this, Vd, Vm);
4759 break;
4760 default:
4761 UNREACHABLE();
4762 }
4763 } else {
4764 // vuzp.<size> Qd, Qm.
4765 switch (size) {
4766 case Neon8:
4767 Unzip<uint8_t, kSimd128Size>(this, Vd, Vm);
4768 break;
4769 case Neon16:
4770 Unzip<uint16_t, kSimd128Size>(this, Vd, Vm);
4771 break;
4772 case Neon32:
4773 Unzip<uint32_t, kSimd128Size>(this, Vd, Vm);
4774 break;
4775 default:
4776 UNREACHABLE();
4777 }
4778 }
4779 } else {
4780 int Vd = instr->VFPDRegValue(kDoublePrecision);
4781 int Vm = instr->VFPMRegValue(kDoublePrecision);
4782 if (instr->Bit(7) == 1) {
4783 // vzip.<size> Dd, Dm.
4784 switch (size) {
4785 case Neon8:
4786 Zip<uint8_t, kDoubleSize>(this, Vd, Vm);
4787 break;
4788 case Neon16:
4789 Zip<uint16_t, kDoubleSize>(this, Vd, Vm);
4790 break;
4791 case Neon32:
4792 UNIMPLEMENTED();
4793 default:
4794 UNREACHABLE();
4795 }
4796 } else {
4797 // vuzp.<size> Dd, Dm.
4798 switch (size) {
4799 case Neon8:
4800 Unzip<uint8_t, kDoubleSize>(this, Vd, Vm);
4801 break;
4802 case Neon16:
4803 Unzip<uint16_t, kDoubleSize>(this, Vd, Vm);
4804 break;
4805 case Neon32:
4806 UNIMPLEMENTED();
4807 default:
4808 UNREACHABLE();
4809 }
4810 }
4811 }
4812 } else if (opc1 == 0b10 && (opc2 & 0b1110) == 0b0100) {
4813 // vqmovn.<type><size> Dd, Qm.
4814 int Vd = instr->VFPDRegValue(kDoublePrecision);
4815 int Vm = instr->VFPMRegValue(kSimd128Precision);
4816 NeonSize size = static_cast<NeonSize>(instr->Bits(19, 18));
4817 bool dst_unsigned = instr->Bit(6) != 0;
4818 bool src_unsigned = instr->Bits(7, 6) == 0b11;
4819 DCHECK_IMPLIES(src_unsigned, dst_unsigned);
4820 switch (size) {
4821 case Neon8: {
4822 if (src_unsigned) {
4823 SaturatingNarrow<uint16_t, uint8_t>(this, Vd, Vm);
4824 } else if (dst_unsigned) {
4825 SaturatingNarrow<int16_t, uint8_t>(this, Vd, Vm);
4826 } else {
4827 SaturatingNarrow<int16_t, int8_t>(this, Vd, Vm);
4828 }
4829 break;
4830 }
4831 case Neon16: {
4832 if (src_unsigned) {
4833 SaturatingNarrow<uint32_t, uint16_t>(this, Vd, Vm);
4834 } else if (dst_unsigned) {
4835 SaturatingNarrow<int32_t, uint16_t>(this, Vd, Vm);
4836 } else {
4837 SaturatingNarrow<int32_t, int16_t>(this, Vd, Vm);
4838 }
4839 break;
4840 }
4841 case Neon32: {
4842 if (src_unsigned) {
4843 SaturatingNarrow<uint64_t, uint32_t>(this, Vd, Vm);
4844 } else if (dst_unsigned) {
4845 SaturatingNarrow<int64_t, uint32_t>(this, Vd, Vm);
4846 } else {
4847 SaturatingNarrow<int64_t, int32_t>(this, Vd, Vm);
4848 }
4849 break;
4850 }
4851 case Neon64:
4852 UNREACHABLE();
4853 }
4854 } else if (opc1 == 0b10 && instr->Bit(10) == 1) {
4855 // vrint<q>.<dt> <Dd>, <Dm>
4856 // vrint<q>.<dt> <Qd>, <Qm>
4857 // See F6.1.205
4858 int regs = instr->Bit(6) + 1;
4859 int rounding_mode = instr->Bits(9, 7);
4860 float (*fproundint)(float) = nullptr;
4861 switch (rounding_mode) {
4862 case 0:
4863 fproundint = &nearbyintf;
4864 break;
4865 case 3:
4866 fproundint = &truncf;
4867 break;
4868 case 5:
4869 fproundint = &floorf;
4870 break;
4871 case 7:
4872 fproundint = &ceilf;
4873 break;
4874 default:
4875 UNIMPLEMENTED();
4876 }
4877 int vm = instr->VFPMRegValue(kDoublePrecision);
4878 int vd = instr->VFPDRegValue(kDoublePrecision);
4879
4880 float floats[2];
4881 for (int r = 0; r < regs; r++) {
4882 // We cannot simply use GetVFPSingleValue since our Q registers
4883 // might not map to any S registers at all.
4884 get_neon_register<float, kDoubleSize>(vm + r, floats);
4885 for (int e = 0; e < 2; e++) {
4886 floats[e] = canonicalizeNaN(fproundint(floats[e]));
4887 }
4888 set_neon_register<float, kDoubleSize>(vd + r, floats);
4889 }
4890 } else if (opc1 == 0b11 && (opc2 & 0b1100) == 0b1000) {
4891 // vrecpe/vrsqrte.f32 Qd, Qm.
4892 int Vd = instr->VFPDRegValue(kSimd128Precision);
4893 int Vm = instr->VFPMRegValue(kSimd128Precision);
4894 uint32_t src[4];
4895 get_neon_register(Vm, src);
4896 if (instr->Bit(7) == 0) {
4897 for (int i = 0; i < 4; i++) {
4898 float denom = base::bit_cast<float>(src[i]);
4899 div_zero_vfp_flag_ = (denom == 0);
4900 float result = 1.0f / denom;
4901 result = canonicalizeNaN(result);
4902 src[i] = base::bit_cast<uint32_t>(result);
4903 }
4904 } else {
4905 for (int i = 0; i < 4; i++) {
4906 float radicand = base::bit_cast<float>(src[i]);
4907 float result = 1.0f / std::sqrt(radicand);
4908 result = canonicalizeNaN(result);
4909 src[i] = base::bit_cast<uint32_t>(result);
4910 }
4911 }
4912 set_neon_register(Vd, src);
4913 } else if (opc1 == 0b11 && (opc2 & 0b1100) == 0b1100) {
4914 // vcvt.<Td>.<Tm> Qd, Qm.
4915 int Vd = instr->VFPDRegValue(kSimd128Precision);
4916 int Vm = instr->VFPMRegValue(kSimd128Precision);
4917 uint32_t q_data[4];
4918 get_neon_register(Vm, q_data);
4919 int op = instr->Bits(8, 7);
4920 for (int i = 0; i < 4; i++) {
4921 switch (op) {
4922 case 0:
4923 // f32 <- s32, round towards nearest.
4924 q_data[i] = base::bit_cast<uint32_t>(std::round(
4925 static_cast<float>(base::bit_cast<int32_t>(q_data[i]))));
4926 break;
4927 case 1:
4928 // f32 <- u32, round towards nearest.
4929 q_data[i] = base::bit_cast<uint32_t>(
4930 std::round(static_cast<float>(q_data[i])));
4931 break;
4932 case 2:
4933 // s32 <- f32, round to zero.
4934 q_data[i] = static_cast<uint32_t>(ConvertDoubleToInt(
4935 base::bit_cast<float>(q_data[i]), false, RZ));
4936 break;
4937 case 3:
4938 // u32 <- f32, round to zero.
4939 q_data[i] = static_cast<uint32_t>(
4940 ConvertDoubleToInt(base::bit_cast<float>(q_data[i]), true, RZ));
4941 break;
4942 }
4943 }
4944 set_neon_register(Vd, q_data);
4945 } else {
4946 UNIMPLEMENTED();
4947 }
4948 } else if (op0 && op1 == 0b11 && op2 == 0b10) {
4949 // vtb[l,x] Dd, <list>, Dm.
4950 int vd = instr->VFPDRegValue(kDoublePrecision);
4951 int vn = instr->VFPNRegValue(kDoublePrecision);
4952 int vm = instr->VFPMRegValue(kDoublePrecision);
4953 int table_len = (instr->Bits(9, 8) + 1) * kDoubleSize;
4954 bool vtbx = instr->Bit(6) != 0; // vtbl / vtbx
4955 uint64_t destination = 0, indices = 0, result = 0;
4956 get_d_register(vd, &destination);
4957 get_d_register(vm, &indices);
4958 for (int i = 0; i < kDoubleSize; i++) {
4959 int shift = i * kBitsPerByte;
4960 int index = (indices >> shift) & 0xFF;
4961 if (index < table_len) {
4962 uint64_t table;
4963 get_d_register(vn + index / kDoubleSize, &table);
4964 result |= ((table >> ((index % kDoubleSize) * kBitsPerByte)) & 0xFF)
4965 << shift;
4966 } else if (vtbx) {
4967 result |= destination & (0xFFull << shift);
4968 }
4969 }
4970 set_d_register(vd, &result);
4971 } else if (op0 && op1 == 0b11 && op2 == 0b11) {
4972 // Advanced SIMD duplicate (scalar)
4973 if (instr->Bits(9, 7) == 0) {
4974 // vdup.<size> Dd, Dm[index].
4975 // vdup.<size> Qd, Dm[index].
4976 int vm = instr->VFPMRegValue(kDoublePrecision);
4977 int imm4 = instr->Bits(19, 16);
4978 int size = 0, index = 0, mask = 0;
4979 if ((imm4 & 0x1) != 0) {
4980 size = 8;
4981 index = imm4 >> 1;
4982 mask = 0xFFu;
4983 } else if ((imm4 & 0x2) != 0) {
4984 size = 16;
4985 index = imm4 >> 2;
4986 mask = 0xFFFFu;
4987 } else {
4988 size = 32;
4989 index = imm4 >> 3;
4990 mask = 0xFFFFFFFFu;
4991 }
4992 uint64_t d_data;
4993 get_d_register(vm, &d_data);
4994 uint32_t scalar = (d_data >> (size * index)) & mask;
4995 uint32_t duped = scalar;
4996 for (int i = 1; i < 32 / size; i++) {
4997 scalar <<= size;
4998 duped |= scalar;
4999 }
5000 uint32_t result[4] = {duped, duped, duped, duped};
5001 if (instr->Bit(6) == 0) {
5002 int vd = instr->VFPDRegValue(kDoublePrecision);
5003 set_d_register(vd, result);
5004 } else {
5005 int vd = instr->VFPDRegValue(kSimd128Precision);
5006 set_neon_register(vd, result);
5007 }
5008 } else {
5009 UNIMPLEMENTED();
5010 }
5011 } else if (op1 != 0b11 && !op3) {
5012 // Advanced SIMD three registers of different lengths.
5013 int u = instr->Bit(24);
5014 int opc = instr->Bits(11, 8);
5015 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5016 if (opc == 0b1000) {
5017 // vmlal.u<size> Qd, Dn, Dm
5018 if (size != Neon32) UNIMPLEMENTED();
5019
5020 int Vd = instr->VFPDRegValue(kSimd128Precision);
5021 int Vn = instr->VFPNRegValue(kDoublePrecision);
5022 int Vm = instr->VFPMRegValue(kDoublePrecision);
5023 uint64_t src1, src2, dst[2];
5024
5025 get_neon_register<uint64_t>(Vd, dst);
5026 get_d_register(Vn, &src1);
5027 get_d_register(Vm, &src2);
5028 dst[0] += (src1 & 0xFFFFFFFFULL) * (src2 & 0xFFFFFFFFULL);
5029 dst[1] += (src1 >> 32) * (src2 >> 32);
5030 set_neon_register<uint64_t>(Vd, dst);
5031 } else if (opc == 0b1100) {
5032 int Vd = instr->VFPDRegValue(kSimd128Precision);
5033 int Vn = instr->VFPNRegValue(kDoublePrecision);
5034 int Vm = instr->VFPMRegValue(kDoublePrecision);
5035 if (u) {
5036 // vmull.u<size> Qd, Dn, Dm
5037 switch (size) {
5038 case Neon8: {
5039 MultiplyLong<uint8_t, uint16_t>(this, Vd, Vn, Vm);
5040 break;
5041 }
5042 case Neon16: {
5043 MultiplyLong<uint16_t, uint32_t>(this, Vd, Vn, Vm);
5044 break;
5045 }
5046 case Neon32: {
5047 MultiplyLong<uint32_t, uint64_t>(this, Vd, Vn, Vm);
5048 break;
5049 }
5050 case Neon64: {
5051 UNIMPLEMENTED();
5052 }
5053 }
5054 } else {
5055 // vmull.s<size> Qd, Dn, Dm
5056 switch (size) {
5057 case Neon8: {
5058 MultiplyLong<int8_t, int16_t>(this, Vd, Vn, Vm);
5059 break;
5060 }
5061 case Neon16: {
5062 MultiplyLong<int16_t, int32_t>(this, Vd, Vn, Vm);
5063 break;
5064 }
5065 case Neon32: {
5066 MultiplyLong<int32_t, int64_t>(this, Vd, Vn, Vm);
5067 break;
5068 }
5069 case Neon64: {
5070 UNIMPLEMENTED();
5071 }
5072 }
5073 }
5074 }
5075 } else if (op1 != 0b11 && op3) {
5076 // The instructions specified by this encoding are not used in V8.
5077 UNIMPLEMENTED();
5078 } else {
5079 UNIMPLEMENTED();
5080 }
5081}
5082
5083void Simulator::DecodeAdvancedSIMDDataProcessing(Instruction* instr) {
5084 int op0 = instr->Bit(23);
5085 int op1 = instr->Bit(4);
5086
5087 if (op0 == 0) {
5088 // Advanced SIMD three registers of same length.
5089 int u = instr->Bit(24);
5090 int opc = instr->Bits(11, 8);
5091 int q = instr->Bit(6);
5092 int sz = instr->Bits(21, 20);
5093 int Vd, Vm, Vn;
5094 if (q) {
5095 Vd = instr->VFPDRegValue(kSimd128Precision);
5096 Vm = instr->VFPMRegValue(kSimd128Precision);
5097 Vn = instr->VFPNRegValue(kSimd128Precision);
5098 } else {
5099 Vd = instr->VFPDRegValue(kDoublePrecision);
5100 Vm = instr->VFPMRegValue(kDoublePrecision);
5101 Vn = instr->VFPNRegValue(kDoublePrecision);
5102 }
5103
5104 if (!u && opc == 0 && op1) {
5105 // vqadd.s<size> Qd, Qm, Qn.
5106 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5107 switch (size) {
5108 case Neon8:
5109 AddSat<int8_t>(this, Vd, Vm, Vn);
5110 break;
5111 case Neon16:
5112 AddSat<int16_t>(this, Vd, Vm, Vn);
5113 break;
5114 case Neon32:
5115 AddSat<int32_t>(this, Vd, Vm, Vn);
5116 break;
5117 default:
5118 UNREACHABLE();
5119 }
5120 } else if (!u && opc == 1 && sz == 2 && q && op1) {
5121 // vmov Qd, Qm.
5122 // vorr, Qd, Qm, Qn.
5123 uint32_t src1[4];
5124 get_neon_register(Vm, src1);
5125 if (Vm != Vn) {
5126 uint32_t src2[4];
5127 get_neon_register(Vn, src2);
5128 for (int i = 0; i < 4; i++) {
5129 src1[i] = src1[i] | src2[i];
5130 }
5131 }
5132 set_neon_register(Vd, src1);
5133 } else if (!u && opc == 1 && sz == 3 && q && op1) {
5134 // vorn, Qd, Qm, Qn.
5135 // NeonSize does not matter.
5136 Binop<uint32_t>(this, Vd, Vm, Vn,
5137 [](uint32_t x, uint32_t y) { return x | (~y); });
5138 } else if (!u && opc == 1 && sz == 0 && q && op1) {
5139 // vand Qd, Qm, Qn.
5140 uint32_t src1[4], src2[4];
5141 get_neon_register(Vn, src1);
5142 get_neon_register(Vm, src2);
5143 for (int i = 0; i < 4; i++) {
5144 src1[i] = src1[i] & src2[i];
5145 }
5146 set_neon_register(Vd, src1);
5147 } else if (!u && opc == 1 && sz == 1 && q && op1) {
5148 // vbic Qd, Qm, Qn.
5149 uint32_t src1[4], src2[4];
5150 get_neon_register(Vn, src1);
5151 get_neon_register(Vm, src2);
5152 for (int i = 0; i < 4; i++) {
5153 src1[i] = src1[i] & ~src2[i];
5154 }
5155 set_neon_register(Vd, src1);
5156 } else if (!u && opc == 2 && op1) {
5157 // vqsub.s<size> Qd, Qm, Qn.
5158 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5159 switch (size) {
5160 case Neon8:
5161 SubSat<int8_t>(this, Vd, Vm, Vn);
5162 break;
5163 case Neon16:
5164 SubSat<int16_t>(this, Vd, Vm, Vn);
5165 break;
5166 case Neon32:
5167 SubSat<int32_t>(this, Vd, Vm, Vn);
5168 break;
5169 case Neon64:
5170 SubSat<int64_t>(this, Vd, Vm, Vn);
5171 break;
5172 default:
5173 UNREACHABLE();
5174 }
5175 } else if (!u && opc == 3) {
5176 // vcge/vcgt.s<size> Qd, Qm, Qn.
5177 bool ge = instr->Bit(4) == 1;
5178 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5179 switch (size) {
5180 case Neon8:
5181 CompareGreater<int8_t, kSimd128Size>(this, Vd, Vm, Vn, ge);
5182 break;
5183 case Neon16:
5184 CompareGreater<int16_t, kSimd128Size>(this, Vd, Vm, Vn, ge);
5185 break;
5186 case Neon32:
5187 CompareGreater<int32_t, kSimd128Size>(this, Vd, Vm, Vn, ge);
5188 break;
5189 default:
5190 UNREACHABLE();
5191 }
5192 } else if (!u && opc == 4 && !op1) {
5193 // vshl s<size> Qd, Qm, Qn.
5194 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5195 switch (size) {
5196 case Neon8:
5197 ShiftByRegister<int8_t, int8_t, kSimd128Size>(this, Vd, Vm, Vn);
5198 break;
5199 case Neon16:
5200 ShiftByRegister<int16_t, int16_t, kSimd128Size>(this, Vd, Vm, Vn);
5201 break;
5202 case Neon32:
5203 ShiftByRegister<int32_t, int32_t, kSimd128Size>(this, Vd, Vm, Vn);
5204 break;
5205 case Neon64:
5206 ShiftByRegister<int64_t, int64_t, kSimd128Size>(this, Vd, Vm, Vn);
5207 break;
5208 default:
5209 UNREACHABLE();
5210 }
5211 } else if (!u && opc == 6) {
5212 // vmin/vmax.s<size> Qd, Qm, Qn.
5213 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5214 bool min = instr->Bit(4) != 0;
5215 switch (size) {
5216 case Neon8:
5217 MinMax<int8_t, kSimd128Size>(this, Vd, Vm, Vn, min);
5218 break;
5219 case Neon16:
5220 MinMax<int16_t, kSimd128Size>(this, Vd, Vm, Vn, min);
5221 break;
5222 case Neon32:
5223 MinMax<int32_t, kSimd128Size>(this, Vd, Vm, Vn, min);
5224 break;
5225 default:
5226 UNREACHABLE();
5227 }
5228 } else if (!u && opc == 8 && op1) {
5229 // vtst.i<size> Qd, Qm, Qn.
5230 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5231 switch (size) {
5232 case Neon8:
5233 Test<uint8_t, kSimd128Size>(this, Vd, Vm, Vn);
5234 break;
5235 case Neon16:
5236 Test<uint16_t, kSimd128Size>(this, Vd, Vm, Vn);
5237 break;
5238 case Neon32:
5239 Test<uint32_t, kSimd128Size>(this, Vd, Vm, Vn);
5240 break;
5241 default:
5242 UNREACHABLE();
5243 }
5244 } else if (!u && opc == 8 && !op1) {
5245 // vadd.i<size> Qd, Qm, Qn.
5246 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5247 switch (size) {
5248 case Neon8:
5249 Add<uint8_t, kSimd128Size>(this, Vd, Vm, Vn);
5250 break;
5251 case Neon16:
5252 Add<uint16_t, kSimd128Size>(this, Vd, Vm, Vn);
5253 break;
5254 case Neon32:
5255 Add<uint32_t, kSimd128Size>(this, Vd, Vm, Vn);
5256 break;
5257 case Neon64:
5258 Add<uint64_t, kSimd128Size>(this, Vd, Vm, Vn);
5259 break;
5260 }
5261 } else if (opc == 9 && op1) {
5262 // vmul.i<size> Qd, Qm, Qn.
5263 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5264 switch (size) {
5265 case Neon8:
5266 Mul<uint8_t, kSimd128Size>(this, Vd, Vm, Vn);
5267 break;
5268 case Neon16:
5269 Mul<uint16_t, kSimd128Size>(this, Vd, Vm, Vn);
5270 break;
5271 case Neon32:
5272 Mul<uint32_t, kSimd128Size>(this, Vd, Vm, Vn);
5273 break;
5274 default:
5275 UNREACHABLE();
5276 }
5277 } else if (!u && opc == 0xA) {
5278 // vpmin/vpmax.s<size> Dd, Dm, Dn.
5279 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5280 bool min = instr->Bit(4) != 0;
5281 switch (size) {
5282 case Neon8:
5283 PairwiseMinMax<int8_t>(this, Vd, Vm, Vn, min);
5284 break;
5285 case Neon16:
5286 PairwiseMinMax<int16_t>(this, Vd, Vm, Vn, min);
5287 break;
5288 case Neon32:
5289 PairwiseMinMax<int32_t>(this, Vd, Vm, Vn, min);
5290 break;
5291 default:
5292 UNREACHABLE();
5293 }
5294 } else if (!u && opc == 0xB) {
5295 // vpadd.i<size> Dd, Dm, Dn.
5296 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5297 switch (size) {
5298 case Neon8:
5299 PairwiseAdd<int8_t>(this, Vd, Vm, Vn);
5300 break;
5301 case Neon16:
5302 PairwiseAdd<int16_t>(this, Vd, Vm, Vn);
5303 break;
5304 case Neon32:
5305 PairwiseAdd<int32_t>(this, Vd, Vm, Vn);
5306 break;
5307 default:
5308 UNREACHABLE();
5309 }
5310 } else if (!u && opc == 0xD && !op1) {
5311 float src1[4], src2[4];
5312 get_neon_register(Vn, src1);
5313 get_neon_register(Vm, src2);
5314 for (int i = 0; i < 4; i++) {
5315 if (instr->Bit(21) == 0) {
5316 // vadd.f32 Qd, Qm, Qn.
5317 src1[i] = src1[i] + src2[i];
5318 } else {
5319 // vsub.f32 Qd, Qm, Qn.
5320 src1[i] = src1[i] - src2[i];
5321 }
5322 }
5323 set_neon_register(Vd, src1);
5324 } else if (!u && opc == 0xE && !sz && !op1) {
5325 // vceq.f32.
5326 float src1[4], src2[4];
5327 get_neon_register(Vn, src1);
5328 get_neon_register(Vm, src2);
5329 uint32_t dst[4];
5330 for (int i = 0; i < 4; i++) {
5331 dst[i] = (src1[i] == src2[i]) ? 0xFFFFFFFF : 0;
5332 }
5333 set_neon_register(Vd, dst);
5334 } else if (!u && opc == 0xF && op1) {
5335 float src1[4], src2[4];
5336 get_neon_register(Vn, src1);
5337 get_neon_register(Vm, src2);
5338 if (instr->Bit(21) == 0) {
5339 // vrecps.f32 Qd, Qm, Qn.
5340 for (int i = 0; i < 4; i++) {
5341 src1[i] = 2.0f - src1[i] * src2[i];
5342 }
5343 } else {
5344 // vrsqrts.f32 Qd, Qm, Qn.
5345 for (int i = 0; i < 4; i++) {
5346 src1[i] = (3.0f - src1[i] * src2[i]) * 0.5f;
5347 }
5348 }
5349 set_neon_register(Vd, src1);
5350 } else if (!u && opc == 0xF && !op1) {
5351 float src1[4], src2[4];
5352 get_neon_register(Vn, src1);
5353 get_neon_register(Vm, src2);
5354 // vmin/vmax.f32 Qd, Qm, Qn.
5355 bool min = instr->Bit(21) == 1;
5356 bool saved = FPSCR_default_NaN_mode_;
5357 FPSCR_default_NaN_mode_ = true;
5358 for (int i = 0; i < 4; i++) {
5359 // vmin returns default NaN if any input is NaN.
5360 src1[i] = canonicalizeNaN(MinMax(src1[i], src2[i], min));
5361 }
5362 FPSCR_default_NaN_mode_ = saved;
5363 set_neon_register(Vd, src1);
5364 } else if (u && opc == 0 && op1) {
5365 // vqadd.u<size> Qd, Qm, Qn.
5366 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5367 switch (size) {
5368 case Neon8:
5369 AddSat<uint8_t>(this, Vd, Vm, Vn);
5370 break;
5371 case Neon16:
5372 AddSat<uint16_t>(this, Vd, Vm, Vn);
5373 break;
5374 case Neon32:
5375 AddSat<uint32_t>(this, Vd, Vm, Vn);
5376 break;
5377 default:
5378 UNREACHABLE();
5379 }
5380 } else if (u && opc == 1 && sz == 1 && op1) {
5381 // vbsl.size Qd, Qm, Qn.
5382 uint32_t dst[4], src1[4], src2[4];
5383 get_neon_register(Vd, dst);
5384 get_neon_register(Vn, src1);
5385 get_neon_register(Vm, src2);
5386 for (int i = 0; i < 4; i++) {
5387 dst[i] = (dst[i] & src1[i]) | (~dst[i] & src2[i]);
5388 }
5389 set_neon_register(Vd, dst);
5390 } else if (u && opc == 1 && sz == 0 && !q && op1) {
5391 // veor Dd, Dn, Dm
5392 uint64_t src1, src2;
5393 get_d_register(Vn, &src1);
5394 get_d_register(Vm, &src2);
5395 src1 ^= src2;
5396 set_d_register(Vd, &src1);
5397 } else if (u && opc == 1 && sz == 0 && q && op1) {
5398 // veor Qd, Qn, Qm
5399 uint32_t src1[4], src2[4];
5400 get_neon_register(Vn, src1);
5401 get_neon_register(Vm, src2);
5402 for (int i = 0; i < 4; i++) src1[i] ^= src2[i];
5403 set_neon_register(Vd, src1);
5404 } else if (u && opc == 1 && !op1) {
5405 // vrhadd.u<size> Qd, Qm, Qn.
5406 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5407 switch (size) {
5408 case Neon8:
5409 Binop<uint8_t>(this, Vd, Vm, Vn, RoundingAverageUnsigned<uint8_t>);
5410 break;
5411 case Neon16:
5412 Binop<uint16_t>(this, Vd, Vm, Vn, RoundingAverageUnsigned<uint16_t>);
5413 break;
5414 case Neon32:
5415 Binop<uint32_t>(this, Vd, Vm, Vn, RoundingAverageUnsigned<uint32_t>);
5416 break;
5417 default:
5418 UNREACHABLE();
5419 }
5420 } else if (u && opc == 2 && op1) {
5421 // vqsub.u<size> Qd, Qm, Qn.
5422 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5423 switch (size) {
5424 case Neon8:
5425 SubSat<uint8_t>(this, Vd, Vm, Vn);
5426 break;
5427 case Neon16:
5428 SubSat<uint16_t>(this, Vd, Vm, Vn);
5429 break;
5430 case Neon32:
5431 SubSat<uint32_t>(this, Vd, Vm, Vn);
5432 break;
5433 default:
5434 UNREACHABLE();
5435 }
5436 } else if (u && opc == 3) {
5437 // vcge/vcgt.u<size> Qd, Qm, Qn.
5438 bool ge = instr->Bit(4) == 1;
5439 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5440 switch (size) {
5441 case Neon8:
5442 CompareGreater<uint8_t, kSimd128Size>(this, Vd, Vm, Vn, ge);
5443 break;
5444 case Neon16:
5445 CompareGreater<uint16_t, kSimd128Size>(this, Vd, Vm, Vn, ge);
5446 break;
5447 case Neon32:
5448 CompareGreater<uint32_t, kSimd128Size>(this, Vd, Vm, Vn, ge);
5449 break;
5450 default:
5451 UNREACHABLE();
5452 }
5453 } else if (u && opc == 4 && !op1) {
5454 // vshl u<size> Qd, Qm, Qn.
5455 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5456 switch (size) {
5457 case Neon8:
5458 ShiftByRegister<uint8_t, int8_t, kSimd128Size>(this, Vd, Vm, Vn);
5459 break;
5460 case Neon16:
5461 ShiftByRegister<uint16_t, int16_t, kSimd128Size>(this, Vd, Vm, Vn);
5462 break;
5463 case Neon32:
5464 ShiftByRegister<uint32_t, int32_t, kSimd128Size>(this, Vd, Vm, Vn);
5465 break;
5466 case Neon64:
5467 ShiftByRegister<uint64_t, int64_t, kSimd128Size>(this, Vd, Vm, Vn);
5468 break;
5469 default:
5470 UNREACHABLE();
5471 }
5472 } else if (u && opc == 6) {
5473 // vmin/vmax.u<size> Qd, Qm, Qn.
5474 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5475 bool min = instr->Bit(4) != 0;
5476 switch (size) {
5477 case Neon8:
5478 MinMax<uint8_t, kSimd128Size>(this, Vd, Vm, Vn, min);
5479 break;
5480 case Neon16:
5481 MinMax<uint16_t, kSimd128Size>(this, Vd, Vm, Vn, min);
5482 break;
5483 case Neon32:
5484 MinMax<uint32_t, kSimd128Size>(this, Vd, Vm, Vn, min);
5485 break;
5486 default:
5487 UNREACHABLE();
5488 }
5489 } else if (u && opc == 8 && !op1) {
5490 // vsub.size Qd, Qm, Qn.
5491 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5492 switch (size) {
5493 case Neon8:
5494 Sub<uint8_t, kSimd128Size>(this, Vd, Vm, Vn);
5495 break;
5496 case Neon16:
5497 Sub<uint16_t, kSimd128Size>(this, Vd, Vm, Vn);
5498 break;
5499 case Neon32:
5500 Sub<uint32_t, kSimd128Size>(this, Vd, Vm, Vn);
5501 break;
5502 case Neon64:
5503 Sub<uint64_t, kSimd128Size>(this, Vd, Vm, Vn);
5504 break;
5505 }
5506 } else if (u && opc == 8 && op1) {
5507 // vceq.size Qd, Qm, Qn.
5508 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5509 switch (size) {
5510 case Neon8:
5511 CompareEqual<uint8_t, kSimd128Size>(this, Vd, Vm, Vn);
5512 break;
5513 case Neon16:
5514 CompareEqual<uint16_t, kSimd128Size>(this, Vd, Vm, Vn);
5515 break;
5516 case Neon32:
5517 CompareEqual<uint32_t, kSimd128Size>(this, Vd, Vm, Vn);
5518 break;
5519 default:
5520 UNREACHABLE();
5521 }
5522 } else if (u && opc == 0xA) {
5523 // vpmin/vpmax.u<size> Dd, Dm, Dn.
5524 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5525 bool min = instr->Bit(4) != 0;
5526 switch (size) {
5527 case Neon8:
5528 PairwiseMinMax<uint8_t>(this, Vd, Vm, Vn, min);
5529 break;
5530 case Neon16:
5531 PairwiseMinMax<uint16_t>(this, Vd, Vm, Vn, min);
5532 break;
5533 case Neon32:
5534 PairwiseMinMax<uint32_t>(this, Vd, Vm, Vn, min);
5535 break;
5536 default:
5537 UNREACHABLE();
5538 }
5539 } else if (u && opc == 0xD && sz == 0 && q && op1) {
5540 // vmul.f32 Qd, Qn, Qm
5541 float src1[4], src2[4];
5542 get_neon_register(Vn, src1);
5543 get_neon_register(Vm, src2);
5544 for (int i = 0; i < 4; i++) {
5545 src1[i] = src1[i] * src2[i];
5546 }
5547 set_neon_register(Vd, src1);
5548 } else if (u && opc == 0xD && sz == 0 && !q && !op1) {
5549 // vpadd.f32 Dd, Dn, Dm
5550 PairwiseAdd<float>(this, Vd, Vm, Vn);
5551 } else if (u && opc == 0xE && !op1) {
5552 // vcge/vcgt.f32 Qd, Qm, Qn
5553 bool ge = instr->Bit(21) == 0;
5554 float src1[4], src2[4];
5555 get_neon_register(Vn, src1);
5556 get_neon_register(Vm, src2);
5557 uint32_t dst[4];
5558 for (int i = 0; i < 4; i++) {
5559 if (ge) {
5560 dst[i] = src1[i] >= src2[i] ? 0xFFFFFFFFu : 0;
5561 } else {
5562 dst[i] = src1[i] > src2[i] ? 0xFFFFFFFFu : 0;
5563 }
5564 }
5565 set_neon_register(Vd, dst);
5566 } else if (u && opc == 0xB) {
5567 // vqrdmulh.<dt> Qd, Qm, Qn
5568 NeonSize size = static_cast<NeonSize>(instr->Bits(21, 20));
5569 if (size == Neon16) {
5570 Binop<int16_t>(this, Vd, Vm, Vn, SaturateRoundingQMul<int16_t>);
5571 } else {
5572 DCHECK_EQ(Neon32, size);
5573 Binop<int32_t>(this, Vd, Vm, Vn, SaturateRoundingQMul<int32_t>);
5574 }
5575 } else {
5576 UNIMPLEMENTED();
5577 }
5578 return;
5579 } else if (op0 == 1 && op1 == 0) {
5580 DecodeAdvancedSIMDTwoOrThreeRegisters(instr);
5581 } else if (op0 == 1 && op1 == 1) {
5582 // Advanced SIMD shifts and immediate generation.
5583 if (instr->Bits(21, 19) == 0 && instr->Bit(7) == 0) {
5584 VmovImmediate(this, instr);
5585 } else {
5586 // Advanced SIMD two registers and shift amount.
5587 int u = instr->Bit(24);
5588 int imm3H = instr->Bits(21, 19);
5589 int imm3L = instr->Bits(18, 16);
5590 int opc = instr->Bits(11, 8);
5591 int l = instr->Bit(7);
5592 int q = instr->Bit(6);
5593 int imm3H_L = imm3H << 1 | l;
5594 int imm7 = instr->Bits(21, 16);
5595 imm7 += (l << 6);
5596 int size = base::bits::RoundDownToPowerOfTwo32(imm7);
5597 NeonSize ns =
5598 static_cast<NeonSize>(base::bits::WhichPowerOfTwo(size >> 3));
5599
5600 if (imm3H_L != 0 && opc == 0) {
5601 // vshr.s/u<size> Qd, Qm, shift
5602 int shift = 2 * size - imm7;
5603 int Vd = instr->VFPDRegValue(q ? kSimd128Precision : kDoublePrecision);
5604 int Vm = instr->VFPMRegValue(q ? kSimd128Precision : kDoublePrecision);
5605 switch (ns) {
5606 case Neon8:
5607 q ? ShiftRight<int8_t, kSimd128Size>(this, Vd, Vm, shift, u)
5608 : ShiftRight<int8_t, kDoubleSize>(this, Vd, Vm, shift, u);
5609 break;
5610 case Neon16:
5611 q ? ShiftRight<int16_t, kSimd128Size>(this, Vd, Vm, shift, u)
5612 : ShiftRight<int16_t, kDoubleSize>(this, Vd, Vm, shift, u);
5613 break;
5614 case Neon32:
5615 q ? ShiftRight<int32_t, kSimd128Size>(this, Vd, Vm, shift, u)
5616 : ShiftRight<int32_t, kDoubleSize>(this, Vd, Vm, shift, u);
5617 break;
5618 case Neon64:
5619 q ? ShiftRight<int64_t, kSimd128Size>(this, Vd, Vm, shift, u)
5620 : ShiftRight<int64_t, kDoubleSize>(this, Vd, Vm, shift, u);
5621 break;
5622 }
5623 } else if (imm3H_L != 0 && opc == 1) {
5624 // vsra Dd, Dm, #imm
5625 DCHECK(!q); // Unimplemented for now.
5626 int shift = 2 * size - imm7;
5627 int Vd = instr->VFPDRegValue(kDoublePrecision);
5628 int Vm = instr->VFPMRegValue(kDoublePrecision);
5629 if (u) {
5630 switch (ns) {
5631 case Neon8:
5632 ShiftRightAccumulate<uint8_t, kDoubleSize>(this, Vd, Vm, shift);
5633 break;
5634 case Neon16:
5635 ShiftRightAccumulate<uint16_t, kDoubleSize>(this, Vd, Vm, shift);
5636 break;
5637 case Neon32:
5638 ShiftRightAccumulate<uint32_t, kDoubleSize>(this, Vd, Vm, shift);
5639 break;
5640 case Neon64:
5641 ShiftRightAccumulate<uint64_t, kDoubleSize>(this, Vd, Vm, shift);
5642 break;
5643 }
5644 } else {
5645 switch (ns) {
5646 case Neon8:
5647 ArithmeticShiftRightAccumulate<int8_t, kDoubleSize>(this, Vd, Vm,
5648 shift);
5649 break;
5650 case Neon16:
5651 ArithmeticShiftRightAccumulate<int16_t, kDoubleSize>(this, Vd, Vm,
5652 shift);
5653 break;
5654 case Neon32:
5655 ArithmeticShiftRightAccumulate<int32_t, kDoubleSize>(this, Vd, Vm,
5656 shift);
5657 break;
5658 case Neon64:
5659 ArithmeticShiftRightAccumulate<int64_t, kDoubleSize>(this, Vd, Vm,
5660 shift);
5661 break;
5662 }
5663 }
5664 } else if (imm3H_L != 0 && imm3L == 0 && opc == 0b1010 && !q) {
5665 if (u) {
5666 // vmovl unsigned
5667 if ((instr->VdValue() & 1) != 0) UNIMPLEMENTED();
5668 int Vd = instr->VFPDRegValue(kSimd128Precision);
5669 int Vm = instr->VFPMRegValue(kDoublePrecision);
5670 switch (imm3H) {
5671 case 1:
5672 Widen<uint8_t, uint16_t>(this, Vd, Vm);
5673 break;
5674 case 2:
5675 Widen<uint16_t, uint32_t>(this, Vd, Vm);
5676 break;
5677 case 4:
5678 Widen<uint32_t, uint64_t>(this, Vd, Vm);
5679 break;
5680 default:
5681 UNIMPLEMENTED();
5682 }
5683 } else {
5684 // vmovl signed
5685 if ((instr->VdValue() & 1) != 0) UNIMPLEMENTED();
5686 int Vd = instr->VFPDRegValue(kSimd128Precision);
5687 int Vm = instr->VFPMRegValue(kDoublePrecision);
5688 switch (imm3H) {
5689 case 1:
5690 Widen<int8_t, int16_t>(this, Vd, Vm);
5691 break;
5692 case 2:
5693 Widen<int16_t, int32_t>(this, Vd, Vm);
5694 break;
5695 case 4:
5696 Widen<int32_t, int64_t>(this, Vd, Vm);
5697 break;
5698 default:
5699 UNIMPLEMENTED();
5700 }
5701 }
5702 } else if (!u && imm3H_L != 0 && opc == 0b0101) {
5703 // vshl.i<size> Qd, Qm, shift
5704 int shift = imm7 - size;
5705 int Vd = instr->VFPDRegValue(kSimd128Precision);
5706 int Vm = instr->VFPMRegValue(kSimd128Precision);
5707 NeonSize ns =
5708 static_cast<NeonSize>(base::bits::WhichPowerOfTwo(size >> 3));
5709 switch (ns) {
5710 case Neon8:
5711 ShiftLeft<uint8_t, kSimd128Size>(this, Vd, Vm, shift);
5712 break;
5713 case Neon16:
5714 ShiftLeft<uint16_t, kSimd128Size>(this, Vd, Vm, shift);
5715 break;
5716 case Neon32:
5717 ShiftLeft<uint32_t, kSimd128Size>(this, Vd, Vm, shift);
5718 break;
5719 case Neon64:
5720 ShiftLeft<uint64_t, kSimd128Size>(this, Vd, Vm, shift);
5721 break;
5722 }
5723 } else if (u && imm3H_L != 0 && opc == 0b0100) {
5724 // vsri.<size> Dd, Dm, shift
5725 int shift = 2 * size - imm7;
5726 int Vd = instr->VFPDRegValue(kDoublePrecision);
5727 int Vm = instr->VFPMRegValue(kDoublePrecision);
5728 switch (size) {
5729 case 8:
5730 ShiftRightAndInsert<uint8_t, kDoubleSize>(this, Vd, Vm, shift);
5731 break;
5732 case 16:
5733 ShiftRightAndInsert<uint16_t, kDoubleSize>(this, Vd, Vm, shift);
5734 break;
5735 case 32:
5736 ShiftRightAndInsert<uint32_t, kDoubleSize>(this, Vd, Vm, shift);
5737 break;
5738 case 64:
5739 ShiftRightAndInsert<uint64_t, kDoubleSize>(this, Vd, Vm, shift);
5740 break;
5741 default:
5742 UNREACHABLE();
5743 }
5744 } else if (u && imm3H_L != 0 && opc == 0b0101) {
5745 // vsli.<size> Dd, Dm, shift
5746 int shift = imm7 - size;
5747 int Vd = instr->VFPDRegValue(kDoublePrecision);
5748 int Vm = instr->VFPMRegValue(kDoublePrecision);
5749 switch (size) {
5750 case 8:
5751 ShiftLeftAndInsert<uint8_t, kDoubleSize>(this, Vd, Vm, shift);
5752 break;
5753 case 16:
5754 ShiftLeftAndInsert<uint16_t, kDoubleSize>(this, Vd, Vm, shift);
5755 break;
5756 case 32:
5757 ShiftLeftAndInsert<uint32_t, kDoubleSize>(this, Vd, Vm, shift);
5758 break;
5759 case 64:
5760 ShiftLeftAndInsert<uint64_t, kDoubleSize>(this, Vd, Vm, shift);
5761 break;
5762 default:
5763 UNREACHABLE();
5764 }
5765 }
5766 }
5767 return;
5768 }
5769}
5770
5771void Simulator::DecodeMemoryHintsAndBarriers(Instruction* instr) {
5772 switch (instr->SpecialValue()) {
5773 case 0xA:
5774 case 0xB:
5775 if ((instr->Bits(22, 20) == 5) && (instr->Bits(15, 12) == 0xF)) {
5776 // pld: ignore instruction.
5777 } else if (instr->SpecialValue() == 0xA && instr->Bits(22, 20) == 7) {
5778 // dsb, dmb, isb: ignore instruction for now.
5779 // TODO(binji): implement
5780 // Also refer to the ARMv6 CP15 equivalents in DecodeTypeCP15.
5781 } else {
5782 UNIMPLEMENTED();
5783 }
5784 break;
5785 default:
5786 UNIMPLEMENTED();
5787 }
5788}
5789
5790void Simulator::DecodeAdvancedSIMDElementOrStructureLoadStore(
5791 Instruction* instr) {
5792 int op0 = instr->Bit(23);
5793 int op1 = instr->Bits(11, 10);
5794
5795 if (!op0) {
5796 DecodeAdvancedSIMDLoadStoreMultipleStructures(instr);
5797 } else if (op1 == 0b11) {
5798 DecodeAdvancedSIMDLoadSingleStructureToAllLanes(instr);
5799 } else {
5800 DecodeAdvancedSIMDLoadStoreSingleStructureToOneLane(instr);
5801 }
5802}
5803
5804void Simulator::DecodeAdvancedSIMDLoadStoreMultipleStructures(
5805 Instruction* instr) {
5806 int Vd = instr->VFPDRegValue(kDoublePrecision);
5807 int Rn = instr->VnValue();
5808 int Rm = instr->VmValue();
5809 int type = instr->Bits(11, 8);
5810 int32_t address = get_register(Rn);
5811 int regs = 0;
5812 switch (type) {
5813 case nlt_1:
5814 regs = 1;
5815 break;
5816 case nlt_2:
5817 regs = 2;
5818 break;
5819 case nlt_3:
5820 regs = 3;
5821 break;
5822 case nlt_4:
5823 regs = 4;
5824 break;
5825 default:
5826 UNIMPLEMENTED();
5827 }
5828 if (instr->Bit(21)) {
5829 // vld1
5830 int r = 0;
5831 while (r < regs) {
5832 uint32_t data[2];
5833 data[0] = ReadW(address);
5834 data[1] = ReadW(address + 4);
5835 set_d_register(Vd + r, data);
5836 address += 8;
5837 r++;
5838 }
5839 } else {
5840 // vst1
5841 int r = 0;
5842 while (r < regs) {
5843 uint32_t data[2];
5844 get_d_register(Vd + r, data);
5845 WriteW(address, data[0]);
5846 WriteW(address + 4, data[1]);
5847 address += 8;
5848 r++;
5849 }
5850 }
5851 AdvancedSIMDElementOrStructureLoadStoreWriteback(Rn, Rm, 8 * regs);
5852}
5853
5854void Simulator::DecodeAdvancedSIMDLoadSingleStructureToAllLanes(
5855 Instruction* instr) {
5856 DCHECK_NE(0, instr->Bit(21));
5857 int N = instr->Bits(9, 8);
5858
5859 int Vd = instr->VFPDRegValue(kDoublePrecision);
5860 int Rn = instr->VnValue();
5861 int Rm = instr->VmValue();
5862 int32_t address = get_register(Rn);
5863
5864 if (!N) {
5865 // vld1 (single element to all lanes).
5866 int regs = instr->Bit(5) + 1;
5867 int size = instr->Bits(7, 6);
5868 uint32_t q_data[2];
5869 switch (size) {
5870 case Neon8: {
5871 uint8_t data = ReadBU(address);
5872 uint8_t* dst = reinterpret_cast<uint8_t*>(q_data);
5873 for (int i = 0; i < 8; i++) {
5874 dst[i] = data;
5875 }
5876 break;
5877 }
5878 case Neon16: {
5879 uint16_t data = ReadHU(address);
5880 uint16_t* dst = reinterpret_cast<uint16_t*>(q_data);
5881 for (int i = 0; i < 4; i++) {
5882 dst[i] = data;
5883 }
5884 break;
5885 }
5886 case Neon32: {
5887 uint32_t data = ReadW(address);
5888 for (int i = 0; i < 2; i++) {
5889 q_data[i] = data;
5890 }
5891 break;
5892 }
5893 }
5894 for (int r = 0; r < regs; r++) {
5895 set_neon_register<uint32_t, kDoubleSize>(Vd + r, q_data);
5896 }
5897 AdvancedSIMDElementOrStructureLoadStoreWriteback(Rn, Rm, 1 << size);
5898 } else {
5899 UNIMPLEMENTED();
5900 }
5901}
5902
5903void Simulator::DecodeAdvancedSIMDLoadStoreSingleStructureToOneLane(
5904 Instruction* instr) {
5905 int L = instr->Bit(21);
5906 int size = instr->Bits(11, 10);
5907 int N = instr->Bits(9, 8);
5908 int Vd = instr->VFPDRegValue(kDoublePrecision);
5909 int Rn = instr->VnValue();
5910 int Rm = instr->VmValue();
5911 int32_t address = get_register(Rn);
5912
5913 if (L && N == 0) {
5914 // vld1 (single element to one lane)
5915 DCHECK_NE(3, size);
5916 uint64_t dreg;
5917 get_d_register(Vd, &dreg);
5918 switch (size) {
5919 case Neon8: {
5920 uint64_t data = ReadBU(address);
5921 DCHECK_EQ(0, instr->Bit(4));
5922 int i = instr->Bits(7, 5) * 8;
5923 dreg = (dreg & ~(uint64_t{0xff} << i)) | (data << i);
5924 break;
5925 }
5926 case Neon16: {
5927 DCHECK_EQ(0, instr->Bits(5, 4)); // Alignment not supported.
5928 uint64_t data = ReadHU(address);
5929 int i = instr->Bits(7, 6) * 16;
5930 dreg = (dreg & ~(uint64_t{0xffff} << i)) | (data << i);
5931 break;
5932 }
5933 case Neon32: {
5934 DCHECK_EQ(0, instr->Bits(6, 4)); // Alignment not supported.
5935 uint64_t data = static_cast<unsigned>(ReadW(address));
5936 int i = instr->Bit(7) * 32;
5937 dreg = (dreg & ~(uint64_t{0xffffffff} << i)) | (data << i);
5938 break;
5939 }
5940 case Neon64: {
5941 // Should have been handled by vld1 (single element to all lanes).
5942 UNREACHABLE();
5943 }
5944 }
5945 set_d_register(Vd, &dreg);
5946 AdvancedSIMDElementOrStructureLoadStoreWriteback(Rn, Rm, 1 << size);
5947 } else if (!L && N == 0) {
5948 // vst1s (single element from one lane).
5949 DCHECK_NE(3, size);
5950 uint64_t dreg;
5951 get_d_register(Vd, &dreg);
5952 switch (size) {
5953 case Neon8: {
5954 DCHECK_EQ(0, instr->Bit(4));
5955 int i = instr->Bits(7, 5) * 8;
5956 dreg = (dreg >> i) & 0xff;
5957 WriteB(address, static_cast<uint8_t>(dreg));
5958 break;
5959 }
5960 case Neon16: {
5961 DCHECK_EQ(0, instr->Bits(5, 4)); // Alignment not supported.
5962 int i = instr->Bits(7, 6) * 16;
5963 dreg = (dreg >> i) & 0xffff;
5964 WriteH(address, static_cast<uint16_t>(dreg));
5965 break;
5966 }
5967 case Neon32: {
5968 DCHECK_EQ(0, instr->Bits(6, 4)); // Alignment not supported.
5969 int i = instr->Bit(7) * 32;
5970 dreg = (dreg >> i) & 0xffffffff;
5971 WriteW(address, base::bit_cast<int>(static_cast<uint32_t>(dreg)));
5972 break;
5973 }
5974 case Neon64: {
5975 // Should have been handled by vst1 (single element to all lanes).
5976 UNREACHABLE();
5977 }
5978 }
5979 AdvancedSIMDElementOrStructureLoadStoreWriteback(Rn, Rm, 1 << size);
5980 } else {
5981 UNIMPLEMENTED();
5982 }
5983}
5984
5985void Simulator::DecodeFloatingPointDataProcessing(Instruction* instr) {
5986 switch (instr->SpecialValue()) {
5987 case 0x1D:
5988 if (instr->Opc1Value() == 0x7 && instr->Opc3Value() == 0x1 &&
5989 instr->Bits(11, 9) == 0x5 && instr->Bits(19, 18) == 0x2) {
5990 if (instr->SzValue() == 0x1) {
5991 int vm = instr->VFPMRegValue(kDoublePrecision);
5992 int vd = instr->VFPDRegValue(kDoublePrecision);
5993 double dm_value = get_double_from_d_register(vm).get_scalar();
5994 double dd_value = 0.0;
5995 int rounding_mode = instr->Bits(17, 16);
5996 switch (rounding_mode) {
5997 case 0x0: // vrinta - round with ties to away from zero
5998 dd_value = round(dm_value);
5999 break;
6000 case 0x1: { // vrintn - round with ties to even
6001 dd_value = nearbyint(dm_value);
6002 break;
6003 }
6004 case 0x2: // vrintp - ceil
6005 dd_value = ceil(dm_value);
6006 break;
6007 case 0x3: // vrintm - floor
6008 dd_value = floor(dm_value);
6009 break;
6010 default:
6011 UNREACHABLE(); // Case analysis is exhaustive.
6012 }
6013 dd_value = canonicalizeNaN(dd_value);
6014 set_d_register_from_double(vd, dd_value);
6015 } else {
6016 int m = instr->VFPMRegValue(kSinglePrecision);
6017 int d = instr->VFPDRegValue(kSinglePrecision);
6018 float sm_value = get_float_from_s_register(m).get_scalar();
6019 float sd_value = 0.0;
6020 int rounding_mode = instr->Bits(17, 16);
6021 switch (rounding_mode) {
6022 case 0x0: // vrinta - round with ties to away from zero
6023 sd_value = roundf(sm_value);
6024 break;
6025 case 0x1: { // vrintn - round with ties to even
6026 sd_value = nearbyintf(sm_value);
6027 break;
6028 }
6029 case 0x2: // vrintp - ceil
6030 sd_value = ceilf(sm_value);
6031 break;
6032 case 0x3: // vrintm - floor
6033 sd_value = floorf(sm_value);
6034 break;
6035 default:
6036 UNREACHABLE(); // Case analysis is exhaustive.
6037 }
6038 sd_value = canonicalizeNaN(sd_value);
6039 set_s_register_from_float(d, sd_value);
6040 }
6041 } else if ((instr->Opc1Value() == 0x4) && (instr->Bits(11, 9) == 0x5) &&
6042 (instr->Bit(4) == 0x0)) {
6043 if (instr->SzValue() == 0x1) {
6044 int m = instr->VFPMRegValue(kDoublePrecision);
6045 int n = instr->VFPNRegValue(kDoublePrecision);
6046 int d = instr->VFPDRegValue(kDoublePrecision);
6047 double dn_value = get_double_from_d_register(n).get_scalar();
6048 double dm_value = get_double_from_d_register(m).get_scalar();
6049 double dd_value;
6050 if (instr->Bit(6) == 0x1) { // vminnm
6051 if ((dn_value < dm_value) || std::isnan(dm_value)) {
6052 dd_value = dn_value;
6053 } else if ((dm_value < dn_value) || std::isnan(dn_value)) {
6054 dd_value = dm_value;
6055 } else {
6056 DCHECK_EQ(dn_value, dm_value);
6057 // Make sure that we pick the most negative sign for +/-0.
6058 dd_value = std::signbit(dn_value) ? dn_value : dm_value;
6059 }
6060 } else { // vmaxnm
6061 if ((dn_value > dm_value) || std::isnan(dm_value)) {
6062 dd_value = dn_value;
6063 } else if ((dm_value > dn_value) || std::isnan(dn_value)) {
6064 dd_value = dm_value;
6065 } else {
6066 DCHECK_EQ(dn_value, dm_value);
6067 // Make sure that we pick the most positive sign for +/-0.
6068 dd_value = std::signbit(dn_value) ? dm_value : dn_value;
6069 }
6070 }
6071 dd_value = canonicalizeNaN(dd_value);
6072 set_d_register_from_double(d, dd_value);
6073 } else {
6074 int m = instr->VFPMRegValue(kSinglePrecision);
6075 int n = instr->VFPNRegValue(kSinglePrecision);
6076 int d = instr->VFPDRegValue(kSinglePrecision);
6077 float sn_value = get_float_from_s_register(n).get_scalar();
6078 float sm_value = get_float_from_s_register(m).get_scalar();
6079 float sd_value;
6080 if (instr->Bit(6) == 0x1) { // vminnm
6081 if ((sn_value < sm_value) || std::isnan(sm_value)) {
6082 sd_value = sn_value;
6083 } else if ((sm_value < sn_value) || std::isnan(sn_value)) {
6084 sd_value = sm_value;
6085 } else {
6086 DCHECK_EQ(sn_value, sm_value);
6087 // Make sure that we pick the most negative sign for +/-0.
6088 sd_value = std::signbit(sn_value) ? sn_value : sm_value;
6089 }
6090 } else { // vmaxnm
6091 if ((sn_value > sm_value) || std::isnan(sm_value)) {
6092 sd_value = sn_value;
6093 } else if ((sm_value > sn_value) || std::isnan(sn_value)) {
6094 sd_value = sm_value;
6095 } else {
6096 DCHECK_EQ(sn_value, sm_value);
6097 // Make sure that we pick the most positive sign for +/-0.
6098 sd_value = std::signbit(sn_value) ? sm_value : sn_value;
6099 }
6100 }
6101 sd_value = canonicalizeNaN(sd_value);
6102 set_s_register_from_float(d, sd_value);
6103 }
6104 } else {
6105 UNIMPLEMENTED();
6106 }
6107 break;
6108 case 0x1C:
6109 if ((instr->Bits(11, 9) == 0x5) && (instr->Bit(6) == 0) &&
6110 (instr->Bit(4) == 0)) {
6111 // VSEL* (floating-point)
6112 bool condition_holds;
6113 switch (instr->Bits(21, 20)) {
6114 case 0x0: // VSELEQ
6115 condition_holds = (z_flag_ == 1);
6116 break;
6117 case 0x1: // VSELVS
6118 condition_holds = (v_flag_ == 1);
6119 break;
6120 case 0x2: // VSELGE
6121 condition_holds = (n_flag_ == v_flag_);
6122 break;
6123 case 0x3: // VSELGT
6124 condition_holds = ((z_flag_ == 0) && (n_flag_ == v_flag_));
6125 break;
6126 default:
6127 UNREACHABLE(); // Case analysis is exhaustive.
6128 }
6129 if (instr->SzValue() == 0x1) {
6130 int n = instr->VFPNRegValue(kDoublePrecision);
6131 int m = instr->VFPMRegValue(kDoublePrecision);
6132 int d = instr->VFPDRegValue(kDoublePrecision);
6133 Float64 result = get_double_from_d_register(condition_holds ? n : m);
6134 set_d_register_from_double(d, result);
6135 } else {
6136 int n = instr->VFPNRegValue(kSinglePrecision);
6137 int m = instr->VFPMRegValue(kSinglePrecision);
6138 int d = instr->VFPDRegValue(kSinglePrecision);
6139 Float32 result = get_float_from_s_register(condition_holds ? n : m);
6140 set_s_register_from_float(d, result);
6141 }
6142 } else {
6143 UNIMPLEMENTED();
6144 }
6145 break;
6146 default:
6147 UNIMPLEMENTED();
6148 }
6149}
6150
6151void Simulator::DecodeSpecialCondition(Instruction* instr) {
6152 int op0 = instr->Bits(25, 24);
6153 int op1 = instr->Bits(11, 9);
6154 int op2 = instr->Bit(4);
6155
6156 if (instr->Bit(27) == 0) {
6157 DecodeUnconditional(instr);
6158 } else if ((instr->Bits(27, 26) == 0b11) && (op0 == 0b10) &&
6159 ((op1 >> 1) == 0b10) && !op2) {
6160 DecodeFloatingPointDataProcessing(instr);
6161 } else {
6162 UNIMPLEMENTED();
6163 }
6164}
6165
6166// Executes the current instruction.
6167void Simulator::InstructionDecode(Instruction* instr) {
6168 if (v8_flags.check_icache) {
6169 CheckICache(i_cache(), instr);
6170 }
6171 pc_modified_ = false;
6172 if (InstructionTracingEnabled()) {
6173 disasm::NameConverter converter;
6174 disasm::Disassembler dasm(converter);
6175 // use a reasonably large buffer
6177 dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(instr));
6178 PrintF(" 0x%08" V8PRIxPTR " %s\n", reinterpret_cast<intptr_t>(instr),
6179 buffer.begin());
6180 }
6181 if (instr->ConditionField() == kSpecialCondition) {
6182 DecodeSpecialCondition(instr);
6183 } else if (ConditionallyExecute(instr)) {
6184 switch (instr->TypeValue()) {
6185 case 0:
6186 case 1: {
6187 DecodeType01(instr);
6188 break;
6189 }
6190 case 2: {
6191 DecodeType2(instr);
6192 break;
6193 }
6194 case 3: {
6195 DecodeType3(instr);
6196 break;
6197 }
6198 case 4: {
6199 DecodeType4(instr);
6200 break;
6201 }
6202 case 5: {
6203 DecodeType5(instr);
6204 break;
6205 }
6206 case 6: {
6207 DecodeType6(instr);
6208 break;
6209 }
6210 case 7: {
6211 DecodeType7(instr);
6212 break;
6213 }
6214 default: {
6215 UNIMPLEMENTED();
6216 }
6217 }
6218 }
6219 if (!pc_modified_) {
6220 set_register(pc, reinterpret_cast<int32_t>(instr) + kInstrSize);
6221 }
6222}
6223
6224void Simulator::Execute() {
6225 // Get the PC to simulate. Cannot use the accessor here as we need the
6226 // raw PC value and not the one used as input to arithmetic instructions.
6227 int program_counter = get_pc();
6228
6229 if (v8_flags.stop_sim_at == 0) {
6230 // Fast version of the dispatch loop without checking whether the simulator
6231 // should be stopping at a particular executed instruction.
6232 while (program_counter != end_sim_pc) {
6233 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
6234 icount_ = base::AddWithWraparound(icount_, 1);
6235 InstructionDecode(instr);
6236 program_counter = get_pc();
6237 }
6238 } else {
6239 // v8_flags.stop_sim_at is at the non-default value. Stop in the debugger
6240 // when we reach the particular instruction count.
6241 while (program_counter != end_sim_pc) {
6242 Instruction* instr = reinterpret_cast<Instruction*>(program_counter);
6243 icount_ = base::AddWithWraparound(icount_, 1);
6244 if (icount_ == v8_flags.stop_sim_at) {
6245 ArmDebugger dbg(this);
6246 dbg.Debug();
6247 } else {
6248 InstructionDecode(instr);
6249 }
6250 program_counter = get_pc();
6251 }
6252 }
6253}
6254
6255void Simulator::CallInternal(Address entry) {
6256 // Adjust JS-based stack limit to C-based stack limit.
6257 isolate_->stack_guard()->AdjustStackLimitForSimulator();
6258
6259 // Prepare to execute the code at entry
6260 set_register(pc, static_cast<int32_t>(entry));
6261 // Put down marker for end of simulation. The simulator will stop simulation
6262 // when the PC reaches this value. By saving the "end simulation" value into
6263 // the LR the simulation stops when returning to this call point.
6264 set_register(lr, end_sim_pc);
6265
6266 // Remember the values of callee-saved registers.
6267 // The code below assumes that r9 is not used as sb (static base) in
6268 // simulator code and therefore is regarded as a callee-saved register.
6269 int32_t r4_val = get_register(r4);
6270 int32_t r5_val = get_register(r5);
6271 int32_t r6_val = get_register(r6);
6272 int32_t r7_val = get_register(r7);
6273 int32_t r8_val = get_register(r8);
6274 int32_t r9_val = get_register(r9);
6275 int32_t r10_val = get_register(r10);
6276 int32_t r11_val = get_register(r11);
6277
6278 // Set up the callee-saved registers with a known value. To be able to check
6279 // that they are preserved properly across JS execution.
6280 int32_t callee_saved_value = icount_;
6281 set_register(r4, callee_saved_value);
6282 set_register(r5, callee_saved_value);
6283 set_register(r6, callee_saved_value);
6284 set_register(r7, callee_saved_value);
6285 set_register(r8, callee_saved_value);
6286 set_register(r9, callee_saved_value);
6287 set_register(r10, callee_saved_value);
6288 set_register(r11, callee_saved_value);
6289
6290 // Start the simulation
6291 Execute();
6292
6293 // Check that the callee-saved registers have been preserved.
6294 CHECK_EQ(callee_saved_value, get_register(r4));
6295 CHECK_EQ(callee_saved_value, get_register(r5));
6296 CHECK_EQ(callee_saved_value, get_register(r6));
6297 CHECK_EQ(callee_saved_value, get_register(r7));
6298 CHECK_EQ(callee_saved_value, get_register(r8));
6299 CHECK_EQ(callee_saved_value, get_register(r9));
6300 CHECK_EQ(callee_saved_value, get_register(r10));
6301 CHECK_EQ(callee_saved_value, get_register(r11));
6302
6303 // Restore callee-saved registers with the original value.
6304 set_register(r4, r4_val);
6305 set_register(r5, r5_val);
6306 set_register(r6, r6_val);
6307 set_register(r7, r7_val);
6308 set_register(r8, r8_val);
6309 set_register(r9, r9_val);
6310 set_register(r10, r10_val);
6311 set_register(r11, r11_val);
6312}
6313
6314intptr_t Simulator::CallImpl(Address entry, int argument_count,
6315 const intptr_t* arguments) {
6316 // Set up arguments
6317
6318 // First four arguments passed in registers.
6319 int reg_arg_count = std::min(4, argument_count);
6320 if (reg_arg_count > 0) set_register(r0, arguments[0]);
6321 if (reg_arg_count > 1) set_register(r1, arguments[1]);
6322 if (reg_arg_count > 2) set_register(r2, arguments[2]);
6323 if (reg_arg_count > 3) set_register(r3, arguments[3]);
6324
6325 // Remaining arguments passed on stack.
6326 int original_stack = get_register(sp);
6327 // Compute position of stack on entry to generated code.
6328 int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t));
6329 if (base::OS::ActivationFrameAlignment() != 0) {
6330 entry_stack &= -base::OS::ActivationFrameAlignment();
6331 }
6332 // Store remaining arguments on stack, from low to high memory.
6333 memcpy(reinterpret_cast<intptr_t*>(entry_stack), arguments + reg_arg_count,
6334 (argument_count - reg_arg_count) * sizeof(*arguments));
6335 set_register(sp, entry_stack);
6336
6337 CallInternal(entry);
6338
6339 // Pop stack passed arguments.
6340 CHECK_EQ(entry_stack, get_register(sp));
6341 set_register(sp, original_stack);
6342
6343 return get_register(r0);
6344}
6345
6346intptr_t Simulator::CallFPImpl(Address entry, double d0, double d1) {
6347 if (use_eabi_hardfloat()) {
6348 set_d_register_from_double(0, d0);
6349 set_d_register_from_double(1, d1);
6350 } else {
6351 set_register_pair_from_double(0, &d0);
6352 set_register_pair_from_double(2, &d1);
6353 }
6354 CallInternal(entry);
6355 return get_register(r0);
6356}
6357
6358uintptr_t Simulator::PushAddress(uintptr_t address) {
6359 int new_sp = get_register(sp) - sizeof(uintptr_t);
6360 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
6361 *stack_slot = address;
6362 set_register(sp, new_sp);
6363 return new_sp;
6364}
6365
6366uintptr_t Simulator::PopAddress() {
6367 int current_sp = get_register(sp);
6368 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
6369 uintptr_t address = *stack_slot;
6370 set_register(sp, current_sp + sizeof(uintptr_t));
6371 return address;
6372}
6373
6374Simulator::LocalMonitor::LocalMonitor()
6375 : access_state_(MonitorAccess::Open),
6376 tagged_addr_(0),
6377 size_(TransactionSize::None) {}
6378
6379void Simulator::LocalMonitor::Clear() {
6380 access_state_ = MonitorAccess::Open;
6381 tagged_addr_ = 0;
6382 size_ = TransactionSize::None;
6383}
6384
6385void Simulator::LocalMonitor::NotifyLoad(int32_t addr) {
6386 if (access_state_ == MonitorAccess::Exclusive) {
6387 // A load could cause a cache eviction which will affect the monitor. As a
6388 // result, it's most strict to unconditionally clear the local monitor on
6389 // load.
6390 Clear();
6391 }
6392}
6393
6394void Simulator::LocalMonitor::NotifyLoadExcl(int32_t addr,
6395 TransactionSize size) {
6396 access_state_ = MonitorAccess::Exclusive;
6397 tagged_addr_ = addr;
6398 size_ = size;
6399}
6400
6401void Simulator::LocalMonitor::NotifyStore(int32_t addr) {
6402 if (access_state_ == MonitorAccess::Exclusive) {
6403 // It is implementation-defined whether a non-exclusive store to an address
6404 // covered by the local monitor during exclusive access transitions to open
6405 // or exclusive access. See ARM DDI 0406C.b, A3.4.1.
6406 //
6407 // However, a store could cause a cache eviction which will affect the
6408 // monitor. As a result, it's most strict to unconditionally clear the
6409 // local monitor on store.
6410 Clear();
6411 }
6412}
6413
6414bool Simulator::LocalMonitor::NotifyStoreExcl(int32_t addr,
6415 TransactionSize size) {
6416 if (access_state_ == MonitorAccess::Exclusive) {
6417 // It is allowed for a processor to require that the address matches
6418 // exactly (A3.4.5), so this comparison does not mask addr.
6419 if (addr == tagged_addr_ && size_ == size) {
6420 Clear();
6421 return true;
6422 } else {
6423 // It is implementation-defined whether an exclusive store to a
6424 // non-tagged address will update memory. Behavior is unpredictable if
6425 // the transaction size of the exclusive store differs from that of the
6426 // exclusive load. See ARM DDI 0406C.b, A3.4.5.
6427 Clear();
6428 return false;
6429 }
6430 } else {
6431 DCHECK(access_state_ == MonitorAccess::Open);
6432 return false;
6433 }
6434}
6435
6436Simulator::GlobalMonitor::Processor::Processor()
6437 : access_state_(MonitorAccess::Open),
6438 tagged_addr_(0),
6439 next_(nullptr),
6440 prev_(nullptr),
6441 failure_counter_(0) {}
6442
6443void Simulator::GlobalMonitor::Processor::Clear_Locked() {
6444 access_state_ = MonitorAccess::Open;
6445 tagged_addr_ = 0;
6446}
6447
6448void Simulator::GlobalMonitor::Processor::NotifyLoadExcl_Locked(int32_t addr) {
6449 access_state_ = MonitorAccess::Exclusive;
6450 tagged_addr_ = addr;
6451}
6452
6453void Simulator::GlobalMonitor::Processor::NotifyStore_Locked(
6454 int32_t addr, bool is_requesting_processor) {
6455 if (access_state_ == MonitorAccess::Exclusive) {
6456 // It is implementation-defined whether a non-exclusive store by the
6457 // requesting processor to an address covered by the global monitor
6458 // during exclusive access transitions to open or exclusive access.
6459 //
6460 // For any other processor, the access state always transitions to open
6461 // access.
6462 //
6463 // See ARM DDI 0406C.b, A3.4.2.
6464 //
6465 // However, similar to the local monitor, it is possible that a store
6466 // caused a cache eviction, which can affect the montior, so
6467 // conservatively, we always clear the monitor.
6468 Clear_Locked();
6469 }
6470}
6471
6472bool Simulator::GlobalMonitor::Processor::NotifyStoreExcl_Locked(
6473 int32_t addr, bool is_requesting_processor) {
6474 if (access_state_ == MonitorAccess::Exclusive) {
6475 if (is_requesting_processor) {
6476 // It is allowed for a processor to require that the address matches
6477 // exactly (A3.4.5), so this comparison does not mask addr.
6478 if (addr == tagged_addr_) {
6479 // The access state for the requesting processor after a successful
6480 // exclusive store is implementation-defined, but according to the ARM
6481 // DDI, this has no effect on the subsequent operation of the global
6482 // monitor.
6483 Clear_Locked();
6484 // Introduce occasional strex failures. This is to simulate the
6485 // behavior of hardware, which can randomly fail due to background
6486 // cache evictions.
6487 if (failure_counter_++ >= kMaxFailureCounter) {
6488 failure_counter_ = 0;
6489 return false;
6490 } else {
6491 return true;
6492 }
6493 }
6494 } else if ((addr & kExclusiveTaggedAddrMask) ==
6495 (tagged_addr_ & kExclusiveTaggedAddrMask)) {
6496 // Check the masked addresses when responding to a successful lock by
6497 // another processor so the implementation is more conservative (i.e. the
6498 // granularity of locking is as large as possible.)
6499 Clear_Locked();
6500 return false;
6501 }
6502 }
6503 return false;
6504}
6505
6506void Simulator::GlobalMonitor::NotifyLoadExcl_Locked(int32_t addr,
6507 Processor* processor) {
6508 processor->NotifyLoadExcl_Locked(addr);
6509}
6510
6511void Simulator::GlobalMonitor::NotifyStore_Locked(int32_t addr,
6512 Processor* processor) {
6513 // Notify each processor of the store operation.
6514 for (Processor* iter = head_; iter; iter = iter->next_) {
6515 bool is_requesting_processor = iter == processor;
6516 iter->NotifyStore_Locked(addr, is_requesting_processor);
6517 }
6518}
6519
6520bool Simulator::GlobalMonitor::NotifyStoreExcl_Locked(int32_t addr,
6521 Processor* processor) {
6522 if (processor->NotifyStoreExcl_Locked(addr, true)) {
6523 // Notify the other processors that this StoreExcl succeeded.
6524 for (Processor* iter = head_; iter; iter = iter->next_) {
6525 if (iter != processor) {
6526 iter->NotifyStoreExcl_Locked(addr, false);
6527 }
6528 }
6529 return true;
6530 } else {
6531 return false;
6532 }
6533}
6534
6535void Simulator::GlobalMonitor::PrependProcessor(Processor* processor) {
6536 base::MutexGuard lock_guard(&mutex_);
6537 if (head_) {
6538 head_->prev_ = processor;
6539 }
6540 processor->prev_ = nullptr;
6541 processor->next_ = head_;
6542 head_ = processor;
6543 num_processors_++;
6544}
6545
6546void Simulator::GlobalMonitor::RemoveProcessor(Processor* processor) {
6547 base::MutexGuard lock_guard(&mutex_);
6548 if (processor->prev_) {
6549 processor->prev_->next_ = processor->next_;
6550 } else {
6551 head_ = processor->next_;
6552 }
6553 if (processor->next_) {
6554 processor->next_->prev_ = processor->prev_;
6555 }
6556 processor->prev_ = nullptr;
6557 processor->next_ = nullptr;
6558 num_processors_--;
6559}
6560
6561#undef SScanF
6562
6563} // namespace internal
6564} // namespace v8
6565
6566//
6567// The following functions are used by our gdb macros.
6568//
6569V8_DEBUGGING_EXPORT extern bool _v8_internal_Simulator_ExecDebugCommand(
6570 const char* command) {
6571 i::Isolate* isolate = i::Isolate::Current();
6572 if (!isolate) {
6573 fprintf(stderr, "No V8 Isolate found\n");
6574 return false;
6575 }
6576 i::Simulator* simulator = i::Simulator::current(isolate);
6577 if (!simulator) {
6578 fprintf(stderr, "No Arm simulator found\n");
6579 return false;
6580 }
6581 // Copy the command so that the simulator can take ownership of it.
6582 size_t len = strlen(command);
6583 i::ArrayUniquePtr<char> command_copy(i::NewArray<char>(len + 1));
6584 i::MemCopy(command_copy.get(), command, len + 1);
6585 return i::ArmDebugger(simulator).ExecDebugCommand(std::move(command_copy));
6586}
6587
6588#endif // USE_SIMULATOR
Isolate * isolate_
#define T
#define one
union v8::internal::@341::BuiltinMetadata::KindSpecificData data
virtual void VisitPointer(const void *address)=0
static void DebugBreak()
constexpr T * begin() const
Definition vector.h:96
static int SupportedRegisterCount()
V8_EXPORT_PRIVATE void SetInstructionBits(Instr value, WritableJitAllocation *jit_allocation=nullptr)
static V8_INLINE MemoryChunkMetadata * FromAddress(Address a)
static constexpr Register from_code(int code)
static int Number(const char *name)
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
static const char * Name(int reg, bool is_double)
static int Number(const char *name, bool *is_double)
base::Mutex & mutex_
Handle< Code > code
const int size_
Definition assembler.cc:132
#define FUNCTION_ADDR(f)
Definition globals.h:712
int start
uint32_t count
int end
LineAndColumn current
#define SIZE(Type, type, TYPE, ctype)
OptionalOpIndex index
int32_t offset
#define XSTR(s)
TNode< Object > target
std::optional< TNode< JSArray > > a
BalanceOverflow overflow
Precision precision
RoundingMode rounding_mode
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
InstructionOperand destination
int m
Definition mul-fft.cc:294
int r
Definition mul-fft.cc:298
STL namespace.
int int32_t
Definition unicode.cc:40
unsigned short uint16_t
Definition unicode.cc:39
signed short int16_t
Definition unicode.cc:38
V8_INLINE Dest bit_cast(Source const &source)
Definition macros.h:95
template unsigned leading_zeros
CustomMatcherTemplateHashMapImpl< DefaultAllocationPolicy > CustomMatcherHashMap
Definition hashmap.h:480
void Add(RWDigits Z, Digits X, Digits Y)
Zip(Iterables... iterables) -> Zip< Iterables... >
FloatWithBits< 32 > Float32
Definition index.h:233
FloatWithBits< 64 > Float64
Definition index.h:234
void Sub(LiftoffAssembler *lasm, Register dst, Register lhs, Register rhs)
constexpr int kMinInt
Definition globals.h:375
constexpr Opcode ADD
constexpr MiscInstructionsBits74 CLZ
constexpr Opcode ORR
constexpr BlockAddrMode ia_x
Wide MultiplyLong(Narrow a, Narrow b)
Definition utils.h:193
constexpr Opcode AND
constexpr int B21
std::make_unsigned< T >::type Abs(T a)
Definition utils.h:93
constexpr int kSimd128Size
Definition globals.h:706
constexpr Opcode BIC
constexpr int kBitsPerByte
Definition globals.h:682
constexpr int kPCRegister
constexpr int B25
constexpr NeonSize Neon32
constexpr BlockAddrMode db_x
constexpr NeonSize Neon8
constexpr Opcode RSC
void PrintF(const char *format,...)
Definition utils.cc:39
char * ReadLine(const char *prompt)
Definition utils.cc:69
constexpr Opcode MOV
T JSMax(T x, T y)
Definition utils.h:75
constexpr ShiftOp LSR
constexpr NeonSize Neon64
constexpr ShiftOp ASR
constexpr NeonListType nlt_3
constexpr ShiftOp LSL
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
uint32_t SRegisterFieldMask
constexpr NeonListType nlt_2
constexpr int N
constexpr MiscInstructionsBits74 BKPT
constexpr SoftwareInterruptCodes kBreakpoint
std::unique_ptr< T, ArrayDeleter< T > > ArrayUniquePtr
Definition allocation.h:73
constexpr int L
constexpr VFPRoundingMode RM
void Print(Tagged< Object > obj)
Definition objects.h:774
constexpr NeonSize Neon16
constexpr int B24
constexpr int U
constexpr VFPRegPrecision kDoublePrecision
constexpr SoftwareInterruptCodes kCallRtRedirected
constexpr Opcode SBC
constexpr BlockAddrMode da_x
constexpr Opcode MVN
void ShortPrint(Tagged< Object > obj, FILE *out)
Definition objects.cc:1865
constexpr int kNoRegister
constexpr VFPRoundingMode RZ
constexpr Opcode TEQ
constexpr MiscInstructionsBits74 BLX
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr Opcode SUB
constexpr Opcode CMN
constexpr ShiftOp ROR
return value
Definition map-inl.h:893
constexpr VFPRoundingMode RN
constexpr Opcode TST
constexpr uint8_t kInstrSize
constexpr Opcode ADC
constexpr int kMaxInt
Definition globals.h:374
constexpr Opcode EOR
constexpr Opcode CMP
const uint32_t kVFPRoundingModeMask
constexpr NeonListType nlt_1
constexpr int kDoubleSize
Definition globals.h:407
constexpr Opcode RSB
constexpr MiscInstructionsBits74 BX
constexpr NeonListType nlt_4
void MemCopy(void *dest, const void *src, size_t size)
Definition memcopy.h:124
constexpr VFPRegPrecision kSinglePrecision
constexpr int kShortSize
Definition globals.h:397
int FastD2IChecked(double x)
Definition conversions.h:91
T * NewArray(size_t size)
Definition allocation.h:43
constexpr BlockAddrMode ib_x
bool is_signed(Condition cond)
T JSMin(T x, T y)
Definition utils.h:84
V8_WARN_UNUSED_RESULT bool IsValidHeapObject(Heap *heap, Tagged< HeapObject > object)
constexpr uint32_t kStopCodeMask
constexpr int kNumRegisters
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_
Node * prev_
#define V8_DEBUGGING_EXPORT
#define UNREACHABLE()
Definition logging.h:67
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define CHECK_EQ(lhs, rhs)
#define UNIMPLEMENTED()
Definition logging.h:66
#define DCHECK(condition)
Definition logging.h:482
#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