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