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