Flutter Engine
The Flutter Engine
simulator_arm.cc
Go to the documentation of this file.
1// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include <setjmp.h> // NOLINT
6#include <stdlib.h>
7
8#include "vm/globals.h"
9#if defined(TARGET_ARCH_ARM)
10
11// Only build the simulator if not compiling for real ARM hardware.
12#if defined(USING_SIMULATOR)
13
14#include "vm/simulator.h"
15
17#include "vm/constants.h"
18#include "vm/cpu.h"
19#include "vm/image_snapshot.h"
20#include "vm/native_arguments.h"
21#include "vm/os_thread.h"
22#include "vm/stack_frame.h"
23
24namespace dart {
25
26// constants_arm.h does not define LR constant to prevent accidental direct use
27// of it during code generation. However using LR directly is okay in this
28// file because it is a simulator.
29constexpr Register LR = LR_DO_NOT_USE_DIRECTLY;
30
31DEFINE_FLAG(uint64_t,
32 trace_sim_after,
33 ULLONG_MAX,
34 "Trace simulator execution after instruction count reached.");
35DEFINE_FLAG(uint64_t,
36 stop_sim_at,
37 ULLONG_MAX,
38 "Instruction address or instruction count to stop simulator at.");
39
40// This macro provides a platform independent use of sscanf. The reason for
41// SScanF not being implemented in a platform independent way through
42// OS in the same way as SNPrint is that the Windows C Run-Time
43// Library does not provide vsscanf.
44#define SScanF sscanf // NOLINT
45
46// SimulatorSetjmpBuffer are linked together, and the last created one
47// is referenced by the Simulator. When an exception is thrown, the exception
48// runtime looks at where to jump and finds the corresponding
49// SimulatorSetjmpBuffer based on the stack pointer of the exception handler.
50// The runtime then does a Longjmp on that buffer to return to the simulator.
51class SimulatorSetjmpBuffer {
52 public:
53 void Longjmp() {
54 // "This" is now the last setjmp buffer.
55 simulator_->set_last_setjmp_buffer(this);
56 longjmp(buffer_, 1);
57 }
58
59 explicit SimulatorSetjmpBuffer(Simulator* sim) {
60 simulator_ = sim;
61 link_ = sim->last_setjmp_buffer();
62 sim->set_last_setjmp_buffer(this);
63 sp_ = static_cast<uword>(sim->get_register(SP));
64 }
65
66 ~SimulatorSetjmpBuffer() {
67 ASSERT(simulator_->last_setjmp_buffer() == this);
68 simulator_->set_last_setjmp_buffer(link_);
69 }
70
71 SimulatorSetjmpBuffer* link() { return link_; }
72
73 uword sp() { return sp_; }
74
75 private:
76 uword sp_;
77 Simulator* simulator_;
78 SimulatorSetjmpBuffer* link_;
79 jmp_buf buffer_;
80
81 friend class Simulator;
82};
83
84// The SimulatorDebugger class is used by the simulator while debugging
85// simulated ARM code.
86class SimulatorDebugger {
87 public:
88 explicit SimulatorDebugger(Simulator* sim);
89 ~SimulatorDebugger();
90
91 void Stop(Instr* instr, const char* message);
92 void Debug();
93 char* ReadLine(const char* prompt);
94
95 private:
96 Simulator* sim_;
97
98 bool GetValue(char* desc, uint32_t* value);
99 bool GetFValue(char* desc, float* value);
100 bool GetDValue(char* desc, double* value);
101
102 static TokenPosition GetApproximateTokenIndex(const Code& code, uword pc);
103
104 static void PrintDartFrame(uword vm_instructions,
105 uword isolate_instructions,
106 uword pc,
107 uword fp,
108 uword sp,
109 const Function& function,
110 TokenPosition token_pos,
111 bool is_optimized,
112 bool is_inlined);
113 void PrintBacktrace();
114
115 // Set or delete a breakpoint. Returns true if successful.
116 bool SetBreakpoint(Instr* breakpc);
117 bool DeleteBreakpoint(Instr* breakpc);
118
119 // Undo and redo all breakpoints. This is needed to bracket disassembly and
120 // execution to skip past breakpoints when run from the debugger.
121 void UndoBreakpoints();
122 void RedoBreakpoints();
123};
124
125SimulatorDebugger::SimulatorDebugger(Simulator* sim) {
126 sim_ = sim;
127}
128
129SimulatorDebugger::~SimulatorDebugger() {}
130
131void SimulatorDebugger::Stop(Instr* instr, const char* message) {
132 OS::PrintErr("Simulator hit %s\n", message);
133 Debug();
134}
135
136static Register LookupCpuRegisterByName(const char* name) {
137 static const char* const kNames[] = {
138 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",
139 "r11", "r12", "r13", "r14", "r15", "pc", "lr", "sp", "ip", "fp", "pp"};
140 static const Register kRegisters[] = {R0, R1, R2, R3, R4, R5, R6, R7,
141 R8, R9, R10, R11, R12, R13, R14, R15,
142 PC, LR, SP, IP, FP, PP};
143 ASSERT(ARRAY_SIZE(kNames) == ARRAY_SIZE(kRegisters));
144 for (unsigned i = 0; i < ARRAY_SIZE(kNames); i++) {
145 if (strcmp(kNames[i], name) == 0) {
146 return kRegisters[i];
147 }
148 }
149 return kNoRegister;
150}
151
152static SRegister LookupSRegisterByName(const char* name) {
153 int reg_nr = -1;
154 bool ok = SScanF(name, "s%d", &reg_nr);
155 if (ok && (0 <= reg_nr) && (reg_nr < kNumberOfSRegisters)) {
156 return static_cast<SRegister>(reg_nr);
157 }
158 return kNoSRegister;
159}
160
161static DRegister LookupDRegisterByName(const char* name) {
162 int reg_nr = -1;
163 bool ok = SScanF(name, "d%d", &reg_nr);
164 if (ok && (0 <= reg_nr) && (reg_nr < kNumberOfDRegisters)) {
165 return static_cast<DRegister>(reg_nr);
166 }
167 return kNoDRegister;
168}
169
170bool SimulatorDebugger::GetValue(char* desc, uint32_t* value) {
171 Register reg = LookupCpuRegisterByName(desc);
172 if (reg != kNoRegister) {
173 if (reg == PC) {
174 *value = sim_->get_pc();
175 } else {
176 *value = sim_->get_register(reg);
177 }
178 return true;
179 }
180 if (desc[0] == '*') {
181 uint32_t addr;
182 if (GetValue(desc + 1, &addr)) {
183 if (Simulator::IsIllegalAddress(addr)) {
184 return false;
185 }
186 *value = *(reinterpret_cast<uint32_t*>(addr));
187 return true;
188 }
189 }
190 bool retval = SScanF(desc, "0x%x", value) == 1;
191 if (!retval) {
192 retval = SScanF(desc, "%x", value) == 1;
193 }
194 return retval;
195}
196
197bool SimulatorDebugger::GetFValue(char* desc, float* value) {
198 SRegister sreg = LookupSRegisterByName(desc);
199 if (sreg != kNoSRegister) {
200 *value = sim_->get_sregister(sreg);
201 return true;
202 }
203 if (desc[0] == '*') {
204 uint32_t addr;
205 if (GetValue(desc + 1, &addr)) {
206 if (Simulator::IsIllegalAddress(addr)) {
207 return false;
208 }
209 *value = *(reinterpret_cast<float*>(addr));
210 return true;
211 }
212 }
213 return false;
214}
215
216bool SimulatorDebugger::GetDValue(char* desc, double* value) {
217 DRegister dreg = LookupDRegisterByName(desc);
218 if (dreg != kNoDRegister) {
219 *value = sim_->get_dregister(dreg);
220 return true;
221 }
222 if (desc[0] == '*') {
223 uint32_t addr;
224 if (GetValue(desc + 1, &addr)) {
225 if (Simulator::IsIllegalAddress(addr)) {
226 return false;
227 }
228 *value = *(reinterpret_cast<double*>(addr));
229 return true;
230 }
231 }
232 return false;
233}
234
235TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
236 uword pc) {
237 TokenPosition token_pos = TokenPosition::kNoSource;
238 uword pc_offset = pc - code.PayloadStart();
239 const PcDescriptors& descriptors =
240 PcDescriptors::Handle(code.pc_descriptors());
241 PcDescriptors::Iterator iter(descriptors, UntaggedPcDescriptors::kAnyKind);
242 while (iter.MoveNext()) {
243 if (iter.PcOffset() == pc_offset) {
244 return iter.TokenPos();
245 } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) {
246 token_pos = iter.TokenPos();
247 }
248 }
249 return token_pos;
250}
251
252#if defined(DART_PRECOMPILED_RUNTIME)
253static const char* ImageName(uword vm_instructions,
254 uword isolate_instructions,
255 uword pc,
256 intptr_t* offset) {
257 const Image vm_image(vm_instructions);
258 const Image isolate_image(isolate_instructions);
259 if (vm_image.contains(pc)) {
260 *offset = pc - vm_instructions;
262 } else if (isolate_image.contains(pc)) {
263 *offset = pc - isolate_instructions;
265 } else {
266 *offset = 0;
267 return "<unknown>";
268 }
269}
270#endif
271
272void SimulatorDebugger::PrintDartFrame(uword vm_instructions,
273 uword isolate_instructions,
274 uword pc,
275 uword fp,
276 uword sp,
277 const Function& function,
278 TokenPosition token_pos,
279 bool is_optimized,
280 bool is_inlined) {
281 const Script& script = Script::Handle(function.script());
282 const String& func_name = String::Handle(function.QualifiedScrubbedName());
283 const String& url = String::Handle(script.url());
284 intptr_t line, column;
285 if (script.GetTokenLocation(token_pos, &line, &column)) {
287 "pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd ":%" Pd ")", pc,
288 fp, sp, is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
289 func_name.ToCString(), url.ToCString(), line, column);
290
291 } else {
292 OS::PrintErr("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s)", pc, fp, sp,
293 is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
294 func_name.ToCString(), url.ToCString());
295 }
296#if defined(DART_PRECOMPILED_RUNTIME)
297 intptr_t offset;
298 auto const symbol_name =
299 ImageName(vm_instructions, isolate_instructions, pc, &offset);
300 OS::PrintErr(" %s+0x%" Px "", symbol_name, offset);
301#endif
302 OS::PrintErr("\n");
303}
304
305void SimulatorDebugger::PrintBacktrace() {
306 auto const T = Thread::Current();
307 auto const Z = T->zone();
308#if defined(DART_PRECOMPILED_RUNTIME)
309 auto const vm_instructions = reinterpret_cast<uword>(
311 auto const isolate_instructions = reinterpret_cast<uword>(
312 T->isolate_group()->source()->snapshot_instructions);
313 OS::PrintErr("vm_instructions=0x%" Px ", isolate_instructions=0x%" Px "\n",
314 vm_instructions, isolate_instructions);
315#else
316 const uword vm_instructions = 0;
317 const uword isolate_instructions = 0;
318#endif
319 StackFrameIterator frames(sim_->get_register(FP), sim_->get_register(SP),
320 sim_->get_pc(),
323 StackFrame* frame = frames.NextFrame();
324 ASSERT(frame != nullptr);
325 Function& function = Function::Handle(Z);
326 Function& inlined_function = Function::Handle(Z);
327 Code& code = Code::Handle(Z);
328 Code& unoptimized_code = Code::Handle(Z);
329 while (frame != nullptr) {
330 if (frame->IsDartFrame()) {
331 code = frame->LookupDartCode();
332 function = code.function();
333 if (code.is_optimized()) {
334 // For optimized frames, extract all the inlined functions if any
335 // into the stack trace.
336 InlinedFunctionsIterator it(code, frame->pc());
337 while (!it.Done()) {
338 // Print each inlined frame with its pc in the corresponding
339 // unoptimized frame.
340 inlined_function = it.function();
341 unoptimized_code = it.code();
342 uword unoptimized_pc = it.pc();
343 it.Advance();
344 if (!it.Done()) {
345 PrintDartFrame(
346 vm_instructions, isolate_instructions, unoptimized_pc,
347 frame->fp(), frame->sp(), inlined_function,
348 GetApproximateTokenIndex(unoptimized_code, unoptimized_pc),
349 true, true);
350 }
351 }
352 // Print the optimized inlining frame below.
353 }
354 PrintDartFrame(vm_instructions, isolate_instructions, frame->pc(),
355 frame->fp(), frame->sp(), function,
356 GetApproximateTokenIndex(code, frame->pc()),
357 code.is_optimized(), false);
358 } else {
359 OS::PrintErr("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s frame",
360 frame->pc(), frame->fp(), frame->sp(),
361 frame->IsEntryFrame() ? "entry"
362 : frame->IsExitFrame() ? "exit"
363 : frame->IsStubFrame() ? "stub"
364 : "invalid");
365#if defined(DART_PRECOMPILED_RUNTIME)
366 intptr_t offset;
367 auto const symbol_name = ImageName(vm_instructions, isolate_instructions,
368 frame->pc(), &offset);
369 OS::PrintErr(" %s+0x%" Px "", symbol_name, offset);
370#endif
371 OS::PrintErr("\n");
372 }
373 frame = frames.NextFrame();
374 }
375}
376
377bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) {
378 // Check if a breakpoint can be set. If not return without any side-effects.
379 if (sim_->break_pc_ != nullptr) {
380 return false;
381 }
382
383 // Set the breakpoint.
384 sim_->break_pc_ = breakpc;
385 sim_->break_instr_ = breakpc->InstructionBits();
386 // Not setting the breakpoint instruction in the code itself. It will be set
387 // when the debugger shell continues.
388 return true;
389}
390
391bool SimulatorDebugger::DeleteBreakpoint(Instr* breakpc) {
392 if (sim_->break_pc_ != nullptr) {
393 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
394 }
395
396 sim_->break_pc_ = nullptr;
397 sim_->break_instr_ = 0;
398 return true;
399}
400
401void SimulatorDebugger::UndoBreakpoints() {
402 if (sim_->break_pc_ != nullptr) {
403 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
404 }
405}
406
407void SimulatorDebugger::RedoBreakpoints() {
408 if (sim_->break_pc_ != nullptr) {
409 sim_->break_pc_->SetInstructionBits(Instr::kSimulatorBreakpointInstruction);
410 }
411}
412
413void SimulatorDebugger::Debug() {
414 intptr_t last_pc = -1;
415 bool done = false;
416
417#define COMMAND_SIZE 63
418#define ARG_SIZE 255
419
420#define STR(a) #a
421#define XSTR(a) STR(a)
422
423 char cmd[COMMAND_SIZE + 1];
424 char arg1[ARG_SIZE + 1];
425 char arg2[ARG_SIZE + 1];
426
427 // make sure to have a proper terminating character if reaching the limit
428 cmd[COMMAND_SIZE] = 0;
429 arg1[ARG_SIZE] = 0;
430 arg2[ARG_SIZE] = 0;
431
432 // Undo all set breakpoints while running in the debugger shell. This will
433 // make them invisible to all commands.
434 UndoBreakpoints();
435
436 while (!done) {
437 if (last_pc != sim_->get_pc()) {
438 last_pc = sim_->get_pc();
439 if (Simulator::IsIllegalAddress(last_pc)) {
440 OS::PrintErr("pc is out of bounds: 0x%" Px "\n", last_pc);
441 } else {
442 if (FLAG_support_disassembler) {
444 } else {
445 OS::PrintErr("Disassembler not supported in this mode.\n");
446 }
447 }
448 }
449 char* line = ReadLine("sim> ");
450 if (line == nullptr) {
451 FATAL("ReadLine failed");
452 } else {
453 // Use sscanf to parse the individual parts of the command line. At the
454 // moment no command expects more than two parameters.
455 int args = SScanF(line,
456 "%" XSTR(COMMAND_SIZE) "s "
457 "%" XSTR(ARG_SIZE) "s "
458 "%" XSTR(ARG_SIZE) "s",
459 cmd, arg1, arg2);
460 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
462 "c/cont -- continue execution\n"
463 "disasm -- disassemble instrs at current pc location\n"
464 " other variants are:\n"
465 " disasm <address>\n"
466 " disasm <address> <number_of_instructions>\n"
467 " by default 10 instrs are disassembled\n"
468 "del -- delete breakpoints\n"
469 "flags -- print flag values\n"
470 "gdb -- transfer control to gdb\n"
471 "h/help -- print this help string\n"
472 "break <address> -- set break point at specified address\n"
473 "p/print <reg or icount or value or *addr> -- print integer\n"
474 "ps/printsingle <sreg or *addr> -- print float value\n"
475 "pd/printdouble <dreg or *addr> -- print double value\n"
476 "po/printobject <*reg or *addr> -- print object\n"
477 "si/stepi -- single step an instruction\n"
478 "trace -- toggle execution tracing mode\n"
479 "bt -- print backtrace\n"
480 "unstop -- if current pc is a stop instr make it a nop\n"
481 "q/quit -- Quit the debugger and exit the program\n");
482 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) {
483 OS::PrintErr("Quitting\n");
484 OS::Exit(0);
485 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
486 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
487 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
488 // Execute the one instruction we broke at with breakpoints disabled.
489 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
490 // Leave the debugger shell.
491 done = true;
492 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
493 if (args == 2) {
494 uint32_t value;
495 if (strcmp(arg1, "icount") == 0) {
496 const uint64_t icount = sim_->get_icount();
497 OS::PrintErr("icount: %" Pu64 " 0x%" Px64 "\n", icount, icount);
498 } else if (GetValue(arg1, &value)) {
499 OS::PrintErr("%s: %u 0x%x\n", arg1, value, value);
500 } else {
501 OS::PrintErr("%s unrecognized\n", arg1);
502 }
503 } else {
504 OS::PrintErr("print <reg or icount or value or *addr>\n");
505 }
506 } else if ((strcmp(cmd, "ps") == 0) ||
507 (strcmp(cmd, "printsingle") == 0)) {
508 if (args == 2) {
509 float fvalue;
510 if (GetFValue(arg1, &fvalue)) {
511 uint32_t value = bit_cast<uint32_t, float>(fvalue);
512 OS::PrintErr("%s: 0%u 0x%x %.8g\n", arg1, value, value, fvalue);
513 } else {
514 OS::PrintErr("%s unrecognized\n", arg1);
515 }
516 } else {
517 OS::PrintErr("printfloat <sreg or *addr>\n");
518 }
519 } else if ((strcmp(cmd, "pd") == 0) ||
520 (strcmp(cmd, "printdouble") == 0)) {
521 if (args == 2) {
522 double dvalue;
523 if (GetDValue(arg1, &dvalue)) {
524 uint64_t long_value = bit_cast<uint64_t, double>(dvalue);
525 OS::PrintErr("%s: %llu 0x%llx %.8g\n", arg1, long_value, long_value,
526 dvalue);
527 } else {
528 OS::PrintErr("%s unrecognized\n", arg1);
529 }
530 } else {
531 OS::PrintErr("printdouble <dreg or *addr>\n");
532 }
533 } else if ((strcmp(cmd, "po") == 0) ||
534 (strcmp(cmd, "printobject") == 0)) {
535 if (args == 2) {
536 uint32_t value;
537 // Make the dereferencing '*' optional.
538 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) ||
539 GetValue(arg1, &value)) {
540 if (IsolateGroup::Current()->heap()->Contains(value)) {
541 OS::PrintErr("%s: \n", arg1);
542#if defined(DEBUG)
543 const Object& obj = Object::Handle(static_cast<ObjectPtr>(value));
544 obj.Print();
545#endif // defined(DEBUG)
546 } else {
547 OS::PrintErr("0x%x is not an object reference\n", value);
548 }
549 } else {
550 OS::PrintErr("%s unrecognized\n", arg1);
551 }
552 } else {
553 OS::PrintErr("printobject <*reg or *addr>\n");
554 }
555 } else if (strcmp(cmd, "disasm") == 0) {
556 uint32_t start = 0;
557 uint32_t end = 0;
558 if (args == 1) {
559 start = sim_->get_pc();
560 end = start + (10 * Instr::kInstrSize);
561 } else if (args == 2) {
562 if (GetValue(arg1, &start)) {
563 // No length parameter passed, assume 10 instructions.
564 if (Simulator::IsIllegalAddress(start)) {
565 // If start isn't a valid address, warn and use PC instead.
566 OS::PrintErr("First argument yields invalid address: 0x%x\n",
567 start);
568 OS::PrintErr("Using PC instead\n");
569 start = sim_->get_pc();
570 }
571 end = start + (10 * Instr::kInstrSize);
572 }
573 } else {
574 uint32_t length;
575 if (GetValue(arg1, &start) && GetValue(arg2, &length)) {
576 if (Simulator::IsIllegalAddress(start)) {
577 // If start isn't a valid address, warn and use PC instead.
578 OS::PrintErr("First argument yields invalid address: 0x%x\n",
579 start);
580 OS::PrintErr("Using PC instead\n");
581 start = sim_->get_pc();
582 }
584 }
585 }
586 if ((start > 0) && (end > start)) {
587 if (FLAG_support_disassembler) {
588 Disassembler::Disassemble(start, end);
589 } else {
590 OS::PrintErr("Disassembler not supported in this mode.\n");
591 }
592 } else {
593 OS::PrintErr("disasm [<address> [<number_of_instructions>]]\n");
594 }
595 } else if (strcmp(cmd, "gdb") == 0) {
596 OS::PrintErr("relinquishing control to gdb\n");
598 OS::PrintErr("regaining control from gdb\n");
599 } else if (strcmp(cmd, "break") == 0) {
600 if (args == 2) {
601 uint32_t addr;
602 if (GetValue(arg1, &addr)) {
603 if (!SetBreakpoint(reinterpret_cast<Instr*>(addr))) {
604 OS::PrintErr("setting breakpoint failed\n");
605 }
606 } else {
607 OS::PrintErr("%s unrecognized\n", arg1);
608 }
609 } else {
610 OS::PrintErr("break <addr>\n");
611 }
612 } else if (strcmp(cmd, "del") == 0) {
613 if (!DeleteBreakpoint(nullptr)) {
614 OS::PrintErr("deleting breakpoint failed\n");
615 }
616 } else if (strcmp(cmd, "flags") == 0) {
617 OS::PrintErr("APSR: ");
618 OS::PrintErr("N flag: %d; ", sim_->n_flag_);
619 OS::PrintErr("Z flag: %d; ", sim_->z_flag_);
620 OS::PrintErr("C flag: %d; ", sim_->c_flag_);
621 OS::PrintErr("V flag: %d\n", sim_->v_flag_);
622 OS::PrintErr("FPSCR: ");
623 OS::PrintErr("N flag: %d; ", sim_->fp_n_flag_);
624 OS::PrintErr("Z flag: %d; ", sim_->fp_z_flag_);
625 OS::PrintErr("C flag: %d; ", sim_->fp_c_flag_);
626 OS::PrintErr("V flag: %d\n", sim_->fp_v_flag_);
627 } else if (strcmp(cmd, "unstop") == 0) {
628 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize;
629 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc);
630 if (stop_instr->IsSvc() || stop_instr->IsBkpt()) {
631 stop_instr->SetInstructionBits(Instr::kNopInstruction);
632 } else {
633 OS::PrintErr("Not at debugger stop.\n");
634 }
635 } else if (strcmp(cmd, "trace") == 0) {
636 if (FLAG_trace_sim_after == ULLONG_MAX) {
637 FLAG_trace_sim_after = sim_->get_icount();
638 OS::PrintErr("execution tracing on\n");
639 } else {
640 FLAG_trace_sim_after = ULLONG_MAX;
641 OS::PrintErr("execution tracing off\n");
642 }
643 } else if (strcmp(cmd, "bt") == 0) {
644 Thread* thread = reinterpret_cast<Thread*>(sim_->get_register(THR));
645 thread->set_execution_state(Thread::kThreadInVM);
646 PrintBacktrace();
647 thread->set_execution_state(Thread::kThreadInGenerated);
648 } else {
649 OS::PrintErr("Unknown command: %s\n", cmd);
650 }
651 }
652 delete[] line;
653 }
654
655 // Add all the breakpoints back to stop execution and enter the debugger
656 // shell when hit.
657 RedoBreakpoints();
658
659#undef COMMAND_SIZE
660#undef ARG_SIZE
661
662#undef STR
663#undef XSTR
664}
665
666char* SimulatorDebugger::ReadLine(const char* prompt) {
667 char* result = nullptr;
668 char line_buf[256];
669 intptr_t offset = 0;
670 bool keep_going = true;
671 OS::PrintErr("%s", prompt);
672 while (keep_going) {
673 if (fgets(line_buf, sizeof(line_buf), stdin) == nullptr) {
674 // fgets got an error. Just give up.
675 if (result != nullptr) {
676 delete[] result;
677 }
678 return nullptr;
679 }
680 intptr_t len = strlen(line_buf);
681 if (len > 1 && line_buf[len - 2] == '\\' && line_buf[len - 1] == '\n') {
682 // When we read a line that ends with a "\" we remove the escape and
683 // append the remainder.
684 line_buf[len - 2] = '\n';
685 line_buf[len - 1] = 0;
686 len -= 1;
687 } else if ((len > 0) && (line_buf[len - 1] == '\n')) {
688 // Since we read a new line we are done reading the line. This
689 // will exit the loop after copying this buffer into the result.
690 keep_going = false;
691 }
692 if (result == nullptr) {
693 // Allocate the initial result and make room for the terminating '\0'
694 result = new char[len + 1];
695 if (result == nullptr) {
696 // OOM, so cannot readline anymore.
697 return nullptr;
698 }
699 } else {
700 // Allocate a new result with enough room for the new addition.
701 intptr_t new_len = offset + len + 1;
702 char* new_result = new char[new_len];
703 if (new_result == nullptr) {
704 // OOM, free the buffer allocated so far and return nullptr.
705 delete[] result;
706 return nullptr;
707 } else {
708 // Copy the existing input into the new array and set the new
709 // array as the result.
710 memmove(new_result, result, offset);
711 delete[] result;
712 result = new_result;
713 }
714 }
715 // Copy the newly read line into the result.
716 memmove(result + offset, line_buf, len);
717 offset += len;
718 }
719 ASSERT(result != nullptr);
720 result[offset] = '\0';
721 return result;
722}
723
724void Simulator::Init() {}
725
726Simulator::Simulator() : exclusive_access_addr_(0), exclusive_access_value_(0) {
727 // Setup simulator support first. Some of this information is needed to
728 // setup the architecture state.
729 // We allocate the stack here, the size is computed as the sum of
730 // the size specified by the user and the buffer space needed for
731 // handling stack overflow exceptions. To be safe in potential
732 // stack underflows we also add some underflow buffer space.
733 stack_ =
734 new char[(OSThread::GetSpecifiedStackSize() +
735 OSThread::kStackSizeBufferMax + kSimulatorStackUnderflowSize)];
736 // Low address.
737 stack_limit_ = reinterpret_cast<uword>(stack_);
738 // Limit for StackOverflowError.
739 overflow_stack_limit_ = stack_limit_ + OSThread::kStackSizeBufferMax;
740 // High address.
741 stack_base_ = overflow_stack_limit_ + OSThread::GetSpecifiedStackSize();
742
743 pc_modified_ = false;
744 icount_ = 0;
745 break_pc_ = nullptr;
746 break_instr_ = 0;
747 last_setjmp_buffer_ = nullptr;
748
749 // Setup architecture state.
750 // All registers are initialized to zero to start with.
751 for (int i = 0; i < kNumberOfCpuRegisters; i++) {
752 registers_[i] = 0;
753 }
754 n_flag_ = false;
755 z_flag_ = false;
756 c_flag_ = false;
757 v_flag_ = false;
758
759 // The sp is initialized to point to the bottom (high address) of the
760 // allocated stack area.
761 registers_[SP] = stack_base();
762 // The lr and pc are initialized to a known bad value that will cause an
763 // access violation if the simulator ever tries to execute it.
764 registers_[PC] = kBadLR;
765 registers_[LR] = kBadLR;
766
767 // All double-precision registers are initialized to zero.
768 for (int i = 0; i < kNumberOfDRegisters; i++) {
769 dregisters_[i] = 0;
770 }
771 // Since VFP registers are overlapping, single-precision registers should
772 // already be initialized.
774 for (int i = 0; i < kNumberOfSRegisters; i++) {
775 ASSERT(sregisters_[i] == 0.0);
776 }
777 fp_n_flag_ = false;
778 fp_z_flag_ = false;
779 fp_c_flag_ = false;
780 fp_v_flag_ = false;
781}
782
783Simulator::~Simulator() {
784 delete[] stack_;
785 Isolate* isolate = Isolate::Current();
786 if (isolate != nullptr) {
787 isolate->set_simulator(nullptr);
788 }
789}
790
791// When the generated code calls an external reference we need to catch that in
792// the simulator. The external reference will be a function compiled for the
793// host architecture. We need to call that function instead of trying to
794// execute it with the simulator. We do that by redirecting the external
795// reference to a svc (supervisor call) instruction that is handled by
796// the simulator. We write the original destination of the jump just at a known
797// offset from the svc instruction so the simulator knows what to call.
798class Redirection {
799 public:
800 uword address_of_svc_instruction() {
801 return reinterpret_cast<uword>(&svc_instruction_);
802 }
803
804 uword external_function() const { return external_function_; }
805
806 Simulator::CallKind call_kind() const { return call_kind_; }
807
808 int argument_count() const { return argument_count_; }
809
810 static Redirection* Get(uword external_function,
811 Simulator::CallKind call_kind,
812 int argument_count) {
813 MutexLocker ml(mutex_);
814
815 Redirection* old_head = list_.load(std::memory_order_relaxed);
816 for (Redirection* current = old_head; current != nullptr;
817 current = current->next_) {
818 if (current->external_function_ == external_function) return current;
819 }
820
821 Redirection* redirection =
822 new Redirection(external_function, call_kind, argument_count);
823 redirection->next_ = old_head;
824
825 // Use a memory fence to ensure all pending writes are written at the time
826 // of updating the list head, so the profiling thread always has a valid
827 // list to look at.
828 list_.store(redirection, std::memory_order_release);
829
830 return redirection;
831 }
832
833 static Redirection* FromSvcInstruction(Instr* svc_instruction) {
834 char* addr_of_svc = reinterpret_cast<char*>(svc_instruction);
835 char* addr_of_redirection =
836 addr_of_svc - OFFSET_OF(Redirection, svc_instruction_);
837 return reinterpret_cast<Redirection*>(addr_of_redirection);
838 }
839
840 // Please note that this function is called by the signal handler of the
841 // profiling thread. It can therefore run at any point in time and is not
842 // allowed to hold any locks - which is precisely the reason why the list is
843 // prepend-only and a memory fence is used when writing the list head [list_]!
844 static uword FunctionForRedirect(uword address_of_svc) {
845 for (Redirection* current = list_.load(std::memory_order_acquire);
846 current != nullptr; current = current->next_) {
847 if (current->address_of_svc_instruction() == address_of_svc) {
848 return current->external_function_;
849 }
850 }
851 return 0;
852 }
853
854 private:
855 Redirection(uword external_function,
856 Simulator::CallKind call_kind,
857 int argument_count)
858 : external_function_(external_function),
859 call_kind_(call_kind),
860 argument_count_(argument_count),
861 svc_instruction_(Instr::kSimulatorRedirectInstruction),
862 next_(nullptr) {}
863
864 uword external_function_;
865 Simulator::CallKind call_kind_;
866 int argument_count_;
867 uint32_t svc_instruction_;
868 Redirection* next_;
869 static std::atomic<Redirection*> list_;
870 static Mutex* mutex_;
871};
872
873std::atomic<Redirection*> Redirection::list_ = {nullptr};
874Mutex* Redirection::mutex_ = new Mutex();
875
876uword Simulator::RedirectExternalReference(uword function,
877 CallKind call_kind,
878 int argument_count) {
879 Redirection* redirection =
881 return redirection->address_of_svc_instruction();
882}
883
884uword Simulator::FunctionForRedirect(uword redirect) {
885 return Redirection::FunctionForRedirect(redirect);
886}
887
888// Get the active Simulator for the current isolate.
889Simulator* Simulator::Current() {
890 Isolate* isolate = Isolate::Current();
891 Simulator* simulator = isolate->simulator();
892 if (simulator == nullptr) {
893 NoSafepointScope no_safepoint;
894 simulator = new Simulator();
895 isolate->set_simulator(simulator);
896 }
897 return simulator;
898}
899
900// Sets the register in the architecture state. It will also deal with updating
901// Simulator internal state for special registers such as PC.
902DART_FORCE_INLINE void Simulator::set_register(Register reg, int32_t value) {
903 ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters));
904 if (reg == PC) {
905 pc_modified_ = true;
906 }
907 registers_[reg] = value;
908}
909
910// Raw access to the PC register.
911DART_FORCE_INLINE void Simulator::set_pc(int32_t value) {
912 pc_modified_ = true;
913 registers_[PC] = value;
914}
915
916// Accessors for VFP register state.
917DART_FORCE_INLINE void Simulator::set_sregister(SRegister reg, float value) {
918 ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
919 sregisters_[reg] = bit_cast<int32_t, float>(value);
920}
921
922DART_FORCE_INLINE float Simulator::get_sregister(SRegister reg) const {
923 ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
924 return bit_cast<float, int32_t>(sregisters_[reg]);
925}
926
927DART_FORCE_INLINE void Simulator::set_dregister(DRegister reg, double value) {
928 ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
929 dregisters_[reg] = bit_cast<int64_t, double>(value);
930}
931
932DART_FORCE_INLINE double Simulator::get_dregister(DRegister reg) const {
933 ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
934 return bit_cast<double, int64_t>(dregisters_[reg]);
935}
936
937void Simulator::set_qregister(QRegister reg, const simd_value_t& value) {
938 ASSERT(TargetCPUFeatures::neon_supported());
939 ASSERT((reg >= 0) && (reg < kNumberOfQRegisters));
940 memcpy(&qregisters_[reg], &value, sizeof(value)); // NOLINT
941}
942
943void Simulator::get_qregister(QRegister reg, simd_value_t* value) const {
944 ASSERT(TargetCPUFeatures::neon_supported());
945 // TODO(zra): Replace this test with an assert after we support
946 // 16 Q registers.
947 if ((reg >= 0) && (reg < kNumberOfQRegisters)) {
948 *value = qregisters_[reg];
949 }
950}
951
952void Simulator::set_sregister_bits(SRegister reg, int32_t value) {
953 ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
954 sregisters_[reg] = value;
955}
956
957int32_t Simulator::get_sregister_bits(SRegister reg) const {
958 ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
959 return sregisters_[reg];
960}
961
962void Simulator::set_dregister_bits(DRegister reg, int64_t value) {
963 ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
964 dregisters_[reg] = value;
965}
966
967int64_t Simulator::get_dregister_bits(DRegister reg) const {
968 ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
969 return dregisters_[reg];
970}
971
972void Simulator::HandleIllegalAccess(uword addr, Instr* instr) {
973 uword fault_pc = get_pc();
974 // The debugger will not be able to single step past this instruction, but
975 // it will be possible to disassemble the code and inspect registers.
976 char buffer[128];
977 snprintf(buffer, sizeof(buffer),
978 "illegal memory access at 0x%" Px ", pc=0x%" Px "\n", addr,
979 fault_pc);
980 SimulatorDebugger dbg(this);
981 dbg.Stop(instr, buffer);
982 // The debugger will return control in non-interactive mode.
983 FATAL("Cannot continue execution after illegal memory access.");
984}
985
986void Simulator::UnimplementedInstruction(Instr* instr) {
987 char buffer[64];
988 snprintf(buffer, sizeof(buffer), "Unimplemented instruction: pc=%p\n", instr);
989 SimulatorDebugger dbg(this);
990 dbg.Stop(instr, buffer);
991 FATAL("Cannot continue execution after unimplemented instruction.");
992}
993
994DART_FORCE_INLINE intptr_t Simulator::ReadW(uword addr, Instr* instr) {
995 return *reinterpret_cast<intptr_t*>(addr);
996}
997
998DART_FORCE_INLINE void Simulator::WriteW(uword addr,
999 intptr_t value,
1000 Instr* instr) {
1001 *reinterpret_cast<intptr_t*>(addr) = value;
1002}
1003
1004DART_FORCE_INLINE uint16_t Simulator::ReadHU(uword addr, Instr* instr) {
1005 return *reinterpret_cast<uint16_t*>(addr);
1006}
1007
1008DART_FORCE_INLINE int16_t Simulator::ReadH(uword addr, Instr* instr) {
1009 return *reinterpret_cast<int16_t*>(addr);
1010}
1011
1012DART_FORCE_INLINE void Simulator::WriteH(uword addr,
1013 uint16_t value,
1014 Instr* instr) {
1015 *reinterpret_cast<uint16_t*>(addr) = value;
1016}
1017
1018DART_FORCE_INLINE uint8_t Simulator::ReadBU(uword addr) {
1019 return *reinterpret_cast<uint8_t*>(addr);
1020}
1021
1022DART_FORCE_INLINE int8_t Simulator::ReadB(uword addr) {
1023 return *reinterpret_cast<int8_t*>(addr);
1024}
1025
1026DART_FORCE_INLINE void Simulator::WriteB(uword addr, uint8_t value) {
1027 *reinterpret_cast<uint8_t*>(addr) = value;
1028}
1029
1030void Simulator::ClearExclusive() {
1031 exclusive_access_addr_ = 0;
1032 exclusive_access_value_ = 0;
1033}
1034
1035intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) {
1036 exclusive_access_addr_ = addr;
1037 exclusive_access_value_ = ReadW(addr, instr);
1038 return exclusive_access_value_;
1039}
1040
1041intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) {
1042 // In a well-formed code store-exclusive instruction should always follow
1043 // a corresponding load-exclusive instruction with the same address.
1044 ASSERT((exclusive_access_addr_ == 0) || (exclusive_access_addr_ == addr));
1045 if (exclusive_access_addr_ != addr) {
1046 return 1; // Failure.
1047 }
1048
1049 int32_t old_value = static_cast<uint32_t>(exclusive_access_value_);
1050 ClearExclusive();
1051
1052 if ((random_.NextUInt32() % 16) == 0) {
1053 return 1; // Spurious failure.
1054 }
1055
1056 auto atomic_addr = reinterpret_cast<RelaxedAtomic<int32_t>*>(addr);
1057 if (atomic_addr->compare_exchange_weak(old_value, value)) {
1058 return 0; // Success.
1059 }
1060 return 1; // Failure.
1061}
1062
1063bool Simulator::IsTracingExecution() const {
1064 return icount_ > FLAG_trace_sim_after;
1065}
1066
1067// Unsupported instructions use Format to print an error and stop execution.
1068void Simulator::Format(Instr* instr, const char* format) {
1069 OS::PrintErr("Simulator found unsupported instruction:\n 0x%p: %s\n", instr,
1070 format);
1071 UNIMPLEMENTED();
1072}
1073
1074// Checks if the current instruction should be executed based on its
1075// condition bits.
1076DART_FORCE_INLINE bool Simulator::ConditionallyExecute(Instr* instr) {
1077 switch (instr->ConditionField()) {
1078 case EQ:
1079 return z_flag_;
1080 case NE:
1081 return !z_flag_;
1082 case CS:
1083 return c_flag_;
1084 case CC:
1085 return !c_flag_;
1086 case MI:
1087 return n_flag_;
1088 case PL:
1089 return !n_flag_;
1090 case VS:
1091 return v_flag_;
1092 case VC:
1093 return !v_flag_;
1094 case HI:
1095 return c_flag_ && !z_flag_;
1096 case LS:
1097 return !c_flag_ || z_flag_;
1098 case GE:
1099 return n_flag_ == v_flag_;
1100 case LT:
1101 return n_flag_ != v_flag_;
1102 case GT:
1103 return !z_flag_ && (n_flag_ == v_flag_);
1104 case LE:
1105 return z_flag_ || (n_flag_ != v_flag_);
1106 case AL:
1107 return true;
1108 default:
1109 UNREACHABLE();
1110 }
1111 return false;
1112}
1113
1114// Calculate and set the Negative and Zero flags.
1115DART_FORCE_INLINE void Simulator::SetNZFlags(int32_t val) {
1116 n_flag_ = (val < 0);
1117 z_flag_ = (val == 0);
1118}
1119
1120// Set the Carry flag.
1121DART_FORCE_INLINE void Simulator::SetCFlag(bool val) {
1122 c_flag_ = val;
1123}
1124
1125// Set the oVerflow flag.
1126DART_FORCE_INLINE void Simulator::SetVFlag(bool val) {
1127 v_flag_ = val;
1128}
1129
1130// Calculate C flag value for additions (and subtractions with adjusted args).
1131DART_FORCE_INLINE bool Simulator::CarryFrom(int32_t left,
1132 int32_t right,
1133 int32_t carry) {
1134 uint64_t uleft = static_cast<uint32_t>(left);
1135 uint64_t uright = static_cast<uint32_t>(right);
1136 uint64_t ucarry = static_cast<uint32_t>(carry);
1137 return ((uleft + uright + ucarry) >> 32) != 0;
1138}
1139
1140// Calculate V flag value for additions (and subtractions with adjusted args).
1141DART_FORCE_INLINE bool Simulator::OverflowFrom(int32_t left,
1142 int32_t right,
1143 int32_t carry) {
1144 int64_t result = static_cast<int64_t>(left) + right + carry;
1145 return (result >> 31) != (result >> 32);
1146}
1147
1148// Addressing Mode 1 - Data-processing operands:
1149// Get the value based on the shifter_operand with register.
1150int32_t Simulator::GetShiftRm(Instr* instr, bool* carry_out) {
1151 Shift shift = instr->ShiftField();
1152 int shift_amount = instr->ShiftAmountField();
1153 int32_t result = get_register(instr->RmField());
1154 if (instr->Bit(4) == 0) {
1155 // by immediate
1156 if ((shift == ROR) && (shift_amount == 0)) {
1157 UnimplementedInstruction(instr);
1158 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
1159 shift_amount = 32;
1160 }
1161 switch (shift) {
1162 case ASR: {
1163 if (shift_amount == 0) {
1164 if (result < 0) {
1165 result = 0xffffffff;
1166 *carry_out = true;
1167 } else {
1168 result = 0;
1169 *carry_out = false;
1170 }
1171 } else {
1172 result >>= (shift_amount - 1);
1173 *carry_out = (result & 1) == 1;
1174 result >>= 1;
1175 }
1176 break;
1177 }
1178
1179 case LSL: {
1180 if (shift_amount == 0) {
1181 *carry_out = c_flag_;
1182 } else {
1183 result = static_cast<uint32_t>(result) << (shift_amount - 1);
1184 *carry_out = (result < 0);
1185 result = static_cast<uint32_t>(result) << 1;
1186 }
1187 break;
1188 }
1189
1190 case LSR: {
1191 if (shift_amount == 0) {
1192 result = 0;
1193 *carry_out = c_flag_;
1194 } else {
1195 uint32_t uresult = static_cast<uint32_t>(result);
1196 uresult >>= (shift_amount - 1);
1197 *carry_out = (uresult & 1) == 1;
1198 uresult >>= 1;
1199 result = static_cast<int32_t>(uresult);
1200 }
1201 break;
1202 }
1203
1204 case ROR: {
1205 UnimplementedInstruction(instr);
1206 break;
1207 }
1208
1209 default: {
1210 UNREACHABLE();
1211 break;
1212 }
1213 }
1214 } else {
1215 // by register
1216 Register rs = instr->RsField();
1217 shift_amount = get_register(rs) & 0xff;
1218 switch (shift) {
1219 case ASR: {
1220 if (shift_amount == 0) {
1221 *carry_out = c_flag_;
1222 } else if (shift_amount < 32) {
1223 result >>= (shift_amount - 1);
1224 *carry_out = (result & 1) == 1;
1225 result >>= 1;
1226 } else {
1227 ASSERT(shift_amount >= 32);
1228 if (result < 0) {
1229 *carry_out = true;
1230 result = 0xffffffff;
1231 } else {
1232 *carry_out = false;
1233 result = 0;
1234 }
1235 }
1236 break;
1237 }
1238
1239 case LSL: {
1240 if (shift_amount == 0) {
1241 *carry_out = c_flag_;
1242 } else if (shift_amount < 32) {
1243 result = static_cast<uint32_t>(result) << (shift_amount - 1);
1244 *carry_out = (result < 0);
1245 result = static_cast<uint32_t>(result) << 1;
1246 } else if (shift_amount == 32) {
1247 *carry_out = (result & 1) == 1;
1248 result = 0;
1249 } else {
1250 ASSERT(shift_amount > 32);
1251 *carry_out = false;
1252 result = 0;
1253 }
1254 break;
1255 }
1256
1257 case LSR: {
1258 if (shift_amount == 0) {
1259 *carry_out = c_flag_;
1260 } else if (shift_amount < 32) {
1261 uint32_t uresult = static_cast<uint32_t>(result);
1262 uresult >>= (shift_amount - 1);
1263 *carry_out = (uresult & 1) == 1;
1264 uresult >>= 1;
1265 result = static_cast<int32_t>(uresult);
1266 } else if (shift_amount == 32) {
1267 *carry_out = (result < 0);
1268 result = 0;
1269 } else {
1270 *carry_out = false;
1271 result = 0;
1272 }
1273 break;
1274 }
1275
1276 case ROR: {
1277 UnimplementedInstruction(instr);
1278 break;
1279 }
1280
1281 default: {
1282 UNREACHABLE();
1283 break;
1284 }
1285 }
1286 }
1287 return result;
1288}
1289
1290// Addressing Mode 1 - Data-processing operands:
1291// Get the value based on the shifter_operand with immediate.
1292DART_FORCE_INLINE int32_t Simulator::GetImm(Instr* instr, bool* carry_out) {
1293 uint8_t rotate = instr->RotateField() * 2;
1294 int32_t immed8 = instr->Immed8Field();
1295 int32_t imm = Utils::RotateRight(immed8, rotate);
1296 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1297 return imm;
1298}
1299
1300// Addressing Mode 4 - Load and Store Multiple
1301void Simulator::HandleRList(Instr* instr, bool load) {
1302 Register rn = instr->RnField();
1303 int32_t rn_val = get_register(rn);
1304 int rlist = instr->RlistField();
1305 int num_regs = Utils::CountOneBits32(static_cast<uint32_t>(rlist));
1306
1307 uword address = 0;
1308 uword end_address = 0;
1309 switch (instr->PUField()) {
1310 case 0: {
1311 // Print("da");
1312 address = rn_val - (num_regs * 4) + 4;
1313 end_address = rn_val + 4;
1314 rn_val = rn_val - (num_regs * 4);
1315 break;
1316 }
1317 case 1: {
1318 // Print("ia");
1319 address = rn_val;
1320 end_address = rn_val + (num_regs * 4);
1321 rn_val = rn_val + (num_regs * 4);
1322 break;
1323 }
1324 case 2: {
1325 // Print("db");
1326 address = rn_val - (num_regs * 4);
1327 end_address = rn_val;
1328 rn_val = address;
1329 break;
1330 }
1331 case 3: {
1332 // Print("ib");
1333 address = rn_val + 4;
1334 end_address = rn_val + (num_regs * 4) + 4;
1335 rn_val = rn_val + (num_regs * 4);
1336 break;
1337 }
1338 default: {
1339 UNREACHABLE();
1340 break;
1341 }
1342 }
1343 if (IsIllegalAddress(address)) {
1344 HandleIllegalAccess(address, instr);
1345 } else {
1346 if (instr->HasW()) {
1347 set_register(rn, rn_val);
1348 }
1349 int reg = 0;
1350 while (rlist != 0) {
1351 if ((rlist & 1) != 0) {
1352 if (load) {
1353 set_register(static_cast<Register>(reg), ReadW(address, instr));
1354 } else {
1355 WriteW(address, get_register(static_cast<Register>(reg)), instr);
1356 }
1357 address += 4;
1358 }
1359 reg++;
1360 rlist >>= 1;
1361 }
1362 ASSERT(end_address == address);
1363 }
1364}
1365
1366// Calls into the Dart runtime are based on this interface.
1367typedef void (*SimulatorRuntimeCall)(NativeArguments arguments);
1368
1369// Calls to leaf Dart runtime functions are based on this interface.
1370typedef int32_t (*SimulatorLeafRuntimeCall)(int32_t r0,
1371 int32_t r1,
1372 int32_t r2,
1373 int32_t r3,
1374 int32_t r4);
1375
1376// [target] has several different signatures that differ from
1377// SimulatorLeafRuntimeCall. We can call them all from here only because in
1378// IA32's calling convention a function can be called with extra arguments
1379// and the callee will see the first arguments and won't unbalance the stack.
1380NO_SANITIZE_UNDEFINED("function")
1381static int32_t InvokeLeafRuntime(SimulatorLeafRuntimeCall target,
1382 int32_t r0,
1383 int32_t r1,
1384 int32_t r2,
1385 int32_t r3,
1386 int32_t r4) {
1387 return target(r0, r1, r2, r3, r4);
1388}
1389
1390// Calls to leaf float Dart runtime functions are based on this interface.
1391typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, double d1);
1392
1393// [target] has several different signatures that differ from
1394// SimulatorFloatLeafRuntimeCall. We can call them all from here only because
1395// IA32's calling convention a function can be called with extra arguments
1396// and the callee will see the first arguments and won't unbalance the stack.
1397NO_SANITIZE_UNDEFINED("function")
1398static double InvokeFloatLeafRuntime(SimulatorLeafFloatRuntimeCall target,
1399 double d0,
1400 double d1) {
1401 return target(d0, d1);
1402}
1403
1404// Calls to native Dart functions are based on this interface.
1405typedef void (*SimulatorNativeCallWrapper)(Dart_NativeArguments arguments,
1407
1408void Simulator::SupervisorCall(Instr* instr) {
1409 int svc = instr->SvcField();
1410 switch (svc) {
1411 case Instr::kSimulatorRedirectCode: {
1412 SimulatorSetjmpBuffer buffer(this);
1413
1414 if (!setjmp(buffer.buffer_)) {
1415 int32_t saved_lr = get_register(LR);
1416 Redirection* redirection = Redirection::FromSvcInstruction(instr);
1417 uword external = redirection->external_function();
1418 if (IsTracingExecution()) {
1419 THR_Print("Call to host function at 0x%" Pd "\n", external);
1420 }
1421 if (redirection->call_kind() == kRuntimeCall) {
1422 NativeArguments arguments;
1423 ASSERT(sizeof(NativeArguments) == 4 * kWordSize);
1424 arguments.thread_ = reinterpret_cast<Thread*>(get_register(R0));
1425 arguments.argc_tag_ = get_register(R1);
1426 arguments.argv_ = reinterpret_cast<ObjectPtr*>(get_register(R2));
1427 arguments.retval_ = reinterpret_cast<ObjectPtr*>(get_register(R3));
1428 SimulatorRuntimeCall target =
1429 reinterpret_cast<SimulatorRuntimeCall>(external);
1430 target(arguments);
1431 ClobberVolatileRegisters();
1432 } else if (redirection->call_kind() == kLeafRuntimeCall) {
1433 ASSERT((0 <= redirection->argument_count()) &&
1434 (redirection->argument_count() <= 5));
1435 int32_t r0 = get_register(R0);
1436 int32_t r1 = get_register(R1);
1437 int32_t r2 = get_register(R2);
1438 int32_t r3 = get_register(R3);
1439 int32_t r4 = *reinterpret_cast<int32_t*>(get_register(SP));
1440 SimulatorLeafRuntimeCall target =
1441 reinterpret_cast<SimulatorLeafRuntimeCall>(external);
1442 r0 = InvokeLeafRuntime(target, r0, r1, r2, r3, r4);
1443 ClobberVolatileRegisters();
1444 set_register(R0, r0); // Set returned result from function.
1445 } else if (redirection->call_kind() == kLeafFloatRuntimeCall) {
1446 ASSERT((0 <= redirection->argument_count()) &&
1447 (redirection->argument_count() <= 2));
1448 SimulatorLeafFloatRuntimeCall target =
1449 reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external);
1450 if (TargetCPUFeatures::hardfp_supported()) {
1451 // If we're doing "hardfp", the double arguments are already in the
1452 // floating point registers.
1453 double d0 = get_dregister(D0);
1454 double d1 = get_dregister(D1);
1455 d0 = InvokeFloatLeafRuntime(target, d0, d1);
1456 ClobberVolatileRegisters();
1457 set_dregister(D0, d0);
1458 } else {
1459 // If we're not doing "hardfp", we must be doing "soft" or "softfp",
1460 // So take the double arguments from the integer registers.
1461 uint32_t r0 = get_register(R0);
1462 int32_t r1 = get_register(R1);
1463 uint32_t r2 = get_register(R2);
1464 int32_t r3 = get_register(R3);
1465 int64_t a0 = Utils::LowHighTo64Bits(r0, r1);
1466 int64_t a1 = Utils::LowHighTo64Bits(r2, r3);
1467 double d0 = bit_cast<double, int64_t>(a0);
1468 double d1 = bit_cast<double, int64_t>(a1);
1469 d0 = InvokeFloatLeafRuntime(target, d0, d1);
1470 ClobberVolatileRegisters();
1471 a0 = bit_cast<int64_t, double>(d0);
1472 r0 = Utils::Low32Bits(a0);
1473 r1 = Utils::High32Bits(a0);
1474 set_register(R0, r0);
1475 set_register(R1, r1);
1476 }
1477 } else {
1478 ASSERT(redirection->call_kind() == kNativeCallWrapper);
1479 SimulatorNativeCallWrapper wrapper =
1480 reinterpret_cast<SimulatorNativeCallWrapper>(external);
1481 Dart_NativeArguments arguments =
1482 reinterpret_cast<Dart_NativeArguments>(get_register(R0));
1483 Dart_NativeFunction target_func =
1484 reinterpret_cast<Dart_NativeFunction>(get_register(R1));
1485 wrapper(arguments, target_func);
1486 ClobberVolatileRegisters();
1487 }
1488
1489 // Return.
1490 set_pc(saved_lr);
1491 } else {
1492 // Coming via long jump from a throw. Continue to exception handler.
1493 }
1494
1495 break;
1496 }
1497 case Instr::kSimulatorBreakCode: {
1498 SimulatorDebugger dbg(this);
1499 dbg.Stop(instr, "breakpoint");
1500 break;
1501 }
1502 default: {
1503 UNREACHABLE();
1504 break;
1505 }
1506 }
1507}
1508
1509void Simulator::ClobberVolatileRegisters() {
1510 // Clear atomic reservation.
1511 exclusive_access_addr_ = exclusive_access_value_ = 0;
1512
1513 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
1514 if ((kAbiVolatileCpuRegs & (1 << i)) != 0) {
1515 registers_[i] = random_.NextUInt32();
1516 }
1517 }
1518
1519 double zap_dvalue = static_cast<double>(icount_);
1520 for (int i = D0; i <= D7; i++) {
1521 set_dregister(static_cast<DRegister>(i), zap_dvalue);
1522 }
1523 // The above loop also zaps overlapping registers S2-S15.
1524 // Registers D8-D15 (overlapping with S16-S31) are preserved.
1525#if defined(VFPv3_D32)
1526 for (int i = D16; i <= D31; i++) {
1527 set_dregister(static_cast<DRegister>(i), zap_dvalue);
1528 }
1529#endif
1530}
1531
1532// Handle execution based on instruction types.
1533
1534// Instruction types 0 and 1 are both rolled into one function because they
1535// only differ in the handling of the shifter_operand.
1536DART_FORCE_INLINE void Simulator::DecodeType01(Instr* instr) {
1537 if (!instr->IsDataProcessing()) {
1538 // miscellaneous, multiply, sync primitives, extra loads and stores.
1539 if (instr->IsMiscellaneous()) {
1540 switch (instr->Bits(4, 3)) {
1541 case 1: {
1542 if (instr->Bits(21, 2) == 0x3) {
1543 // Format(instr, "clz'cond 'rd, 'rm");
1544 Register rm = instr->RmField();
1545 Register rd = instr->RdField();
1546 int32_t rm_val = get_register(rm);
1547 int32_t rd_val = 0;
1548 if (rm_val != 0) {
1549 while (rm_val > 0) {
1550 rd_val++;
1551 rm_val <<= 1;
1552 }
1553 } else {
1554 rd_val = 32;
1555 }
1556 set_register(rd, rd_val);
1557 } else {
1558 ASSERT(instr->Bits(21, 2) == 0x1);
1559 // Format(instr, "bx'cond 'rm");
1560 Register rm = instr->RmField();
1561 int32_t rm_val = get_register(rm);
1562 set_pc(rm_val);
1563 }
1564 break;
1565 }
1566 case 3: {
1567 ASSERT(instr->Bits(21, 2) == 0x1);
1568 // Format(instr, "blx'cond 'rm");
1569 Register rm = instr->RmField();
1570 int32_t rm_val = get_register(rm);
1571 intptr_t pc = get_pc();
1572 set_register(LR, pc + Instr::kInstrSize);
1573 set_pc(rm_val);
1574 break;
1575 }
1576 case 7: {
1577 if ((instr->Bits(21, 2) == 0x1) && (instr->ConditionField() == AL)) {
1578 // Format(instr, "bkpt #'imm12_4");
1579 SimulatorDebugger dbg(this);
1580 int32_t imm = instr->BkptField();
1581 char buffer[32];
1582 snprintf(buffer, sizeof(buffer), "bkpt #0x%x", imm);
1583 set_pc(get_pc() + Instr::kInstrSize);
1584 dbg.Stop(instr, buffer);
1585 } else {
1586 // Format(instr, "smc'cond");
1587 UnimplementedInstruction(instr);
1588 }
1589 break;
1590 }
1591 default: {
1592 UnimplementedInstruction(instr);
1593 break;
1594 }
1595 }
1596 } else if (instr->IsMultiplyOrSyncPrimitive()) {
1597 if (instr->Bit(24) == 0) {
1598 // multiply instructions.
1599 Register rn = instr->RnField();
1600 Register rd = instr->RdField();
1601 Register rs = instr->RsField();
1602 Register rm = instr->RmField();
1603 uint32_t rm_val = get_register(rm);
1604 uint32_t rs_val = get_register(rs);
1605 uint32_t rd_val = 0;
1606 switch (instr->Bits(21, 3)) {
1607 case 1:
1608 // Registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
1609 // Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
1610 case 3: {
1611 // Registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
1612 // Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd");
1613 rd_val = get_register(rd);
1615 }
1616 case 0: {
1617 // Registers rd, rn, rm are encoded as rn, rm, rs.
1618 // Format(instr, "mul'cond's 'rn, 'rm, 'rs");
1619 uint32_t alu_out = rm_val * rs_val;
1620 if (instr->Bits(21, 3) == 3) { // mls
1621 alu_out = -alu_out;
1622 }
1623 alu_out += rd_val;
1624 set_register(rn, alu_out);
1625 if (instr->HasS()) {
1626 SetNZFlags(alu_out);
1627 }
1628 break;
1629 }
1630 case 4:
1631 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1632 // Format(instr, "umull'cond's 'rd, 'rn, 'rm, 'rs");
1633 case 6: {
1634 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1635 // Format(instr, "smull'cond's 'rd, 'rn, 'rm, 'rs");
1636 int64_t result;
1637 if (instr->Bits(21, 3) == 4) { // umull
1638 uint64_t left_op = static_cast<uint32_t>(rm_val);
1639 uint64_t right_op = static_cast<uint32_t>(rs_val);
1640 result = left_op * right_op; // Unsigned multiplication.
1641 } else { // smull
1642 int64_t left_op = static_cast<int32_t>(rm_val);
1643 int64_t right_op = static_cast<int32_t>(rs_val);
1644 result = left_op * right_op; // Signed multiplication.
1645 }
1646 int32_t hi_res = Utils::High32Bits(result);
1647 int32_t lo_res = Utils::Low32Bits(result);
1648 set_register(rd, lo_res);
1649 set_register(rn, hi_res);
1650 if (instr->HasS()) {
1651 if (lo_res != 0) {
1652 // Collapse bits 0..31 into bit 32 so that 32-bit Z check works.
1653 hi_res |= 1;
1654 }
1655 ASSERT((result == 0) == (hi_res == 0)); // Z bit
1656 ASSERT(((result & (1LL << 63)) != 0) == (hi_res < 0)); // N bit
1657 SetNZFlags(hi_res);
1658 }
1659 break;
1660 }
1661 case 2:
1662 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1663 // Format(instr, "umaal'cond's 'rd, 'rn, 'rm, 'rs");
1665 case 5:
1666 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1667 // Format(instr, "umlal'cond's 'rd, 'rn, 'rm, 'rs");
1669 case 7: {
1670 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1671 // Format(instr, "smlal'cond's 'rd, 'rn, 'rm, 'rs");
1672 int32_t rd_lo_val = get_register(rd);
1673 int32_t rd_hi_val = get_register(rn);
1674 uint32_t accum_lo = static_cast<uint32_t>(rd_lo_val);
1675 int32_t accum_hi = static_cast<int32_t>(rd_hi_val);
1676 int64_t accum = Utils::LowHighTo64Bits(accum_lo, accum_hi);
1677 int64_t result;
1678 if (instr->Bits(21, 3) == 5) { // umlal
1679 uint64_t left_op = static_cast<uint32_t>(rm_val);
1680 uint64_t right_op = static_cast<uint32_t>(rs_val);
1681 result = accum + left_op * right_op; // Unsigned multiplication.
1682 } else if (instr->Bits(21, 3) == 7) { // smlal
1683 int64_t left_op = static_cast<int32_t>(rm_val);
1684 int64_t right_op = static_cast<int32_t>(rs_val);
1685 result = accum + left_op * right_op; // Signed multiplication.
1686 } else {
1687 ASSERT(instr->Bits(21, 3) == 2); // umaal
1688 ASSERT(!instr->HasS());
1689 uint64_t left_op = static_cast<uint32_t>(rm_val);
1690 uint64_t right_op = static_cast<uint32_t>(rs_val);
1691 result = left_op * right_op + // Unsigned multiplication.
1692 static_cast<uint32_t>(rd_lo_val) +
1693 static_cast<uint32_t>(rd_hi_val);
1694 }
1695 int32_t hi_res = Utils::High32Bits(result);
1696 int32_t lo_res = Utils::Low32Bits(result);
1697 set_register(rd, lo_res);
1698 set_register(rn, hi_res);
1699 if (instr->HasS()) {
1700 if (lo_res != 0) {
1701 // Collapse bits 0..31 into bit 32 so that 32-bit Z check works.
1702 hi_res |= 1;
1703 }
1704 ASSERT((result == 0) == (hi_res == 0)); // Z bit
1705 ASSERT(((result & (1LL << 63)) != 0) == (hi_res < 0)); // N bit
1706 SetNZFlags(hi_res);
1707 }
1708 break;
1709 }
1710 default: {
1711 UnimplementedInstruction(instr);
1712 break;
1713 }
1714 }
1715 } else {
1716 // synchronization primitives
1717 Register rd = instr->RdField();
1718 Register rn = instr->RnField();
1719 uword addr = get_register(rn);
1720 switch (instr->Bits(20, 4)) {
1721 case 8: {
1722 // Format(instr, "strex'cond 'rd, 'rm, ['rn]");
1723 if (IsIllegalAddress(addr)) {
1724 HandleIllegalAccess(addr, instr);
1725 } else {
1726 Register rm = instr->RmField();
1727 set_register(rd, WriteExclusiveW(addr, get_register(rm), instr));
1728 }
1729 break;
1730 }
1731 case 9: {
1732 // Format(instr, "ldrex'cond 'rd, ['rn]");
1733 if (IsIllegalAddress(addr)) {
1734 HandleIllegalAccess(addr, instr);
1735 } else {
1736 set_register(rd, ReadExclusiveW(addr, instr));
1737 }
1738 break;
1739 }
1740 default: {
1741 UnimplementedInstruction(instr);
1742 break;
1743 }
1744 }
1745 }
1746 } else if (instr->Bit(25) == 1) {
1747 // 16-bit immediate loads, msr (immediate), and hints
1748 switch (instr->Bits(20, 5)) {
1749 case 16:
1750 case 20: {
1751 uint16_t imm16 = instr->MovwField();
1752 Register rd = instr->RdField();
1753 if (instr->Bit(22) == 0) {
1754 // Format(instr, "movw'cond 'rd, #'imm4_12");
1755 set_register(rd, imm16);
1756 } else {
1757 // Format(instr, "movt'cond 'rd, #'imm4_12");
1758 set_register(rd, (get_register(rd) & 0xffff) | (imm16 << 16));
1759 }
1760 break;
1761 }
1762 case 18: {
1763 if ((instr->Bits(16, 4) == 0) && (instr->Bits(0, 8) == 0)) {
1764 // Format(instr, "nop'cond");
1765 } else {
1766 UnimplementedInstruction(instr);
1767 }
1768 break;
1769 }
1770 default: {
1771 UnimplementedInstruction(instr);
1772 break;
1773 }
1774 }
1775 } else {
1776 // extra load/store instructions
1777 Register rd = instr->RdField();
1778 Register rn = instr->RnField();
1779 int32_t rn_val = get_register(rn);
1780 uword addr = 0;
1781 bool write_back = false;
1782 if (instr->Bit(22) == 0) {
1783 Register rm = instr->RmField();
1784 int32_t rm_val = get_register(rm);
1785 switch (instr->PUField()) {
1786 case 0: {
1787 // Format(instr, "'memop'cond'x 'rd2, ['rn], -'rm");
1788 ASSERT(!instr->HasW());
1789 addr = rn_val;
1790 rn_val -= rm_val;
1791 write_back = true;
1792 break;
1793 }
1794 case 1: {
1795 // Format(instr, "'memop'cond'x 'rd2, ['rn], +'rm");
1796 ASSERT(!instr->HasW());
1797 addr = rn_val;
1798 rn_val += rm_val;
1799 write_back = true;
1800 break;
1801 }
1802 case 2: {
1803 // Format(instr, "'memop'cond'x 'rd2, ['rn, -'rm]'w");
1804 rn_val -= rm_val;
1805 addr = rn_val;
1806 write_back = instr->HasW();
1807 break;
1808 }
1809 case 3: {
1810 // Format(instr, "'memop'cond'x 'rd2, ['rn, +'rm]'w");
1811 rn_val += rm_val;
1812 addr = rn_val;
1813 write_back = instr->HasW();
1814 break;
1815 }
1816 default: {
1817 // The PU field is a 2-bit field.
1818 UNREACHABLE();
1819 break;
1820 }
1821 }
1822 } else {
1823 int32_t imm_val = (instr->ImmedHField() << 4) | instr->ImmedLField();
1824 switch (instr->PUField()) {
1825 case 0: {
1826 // Format(instr, "'memop'cond'x 'rd2, ['rn], #-'off8");
1827 ASSERT(!instr->HasW());
1828 addr = rn_val;
1829 rn_val -= imm_val;
1830 write_back = true;
1831 break;
1832 }
1833 case 1: {
1834 // Format(instr, "'memop'cond'x 'rd2, ['rn], #+'off8");
1835 ASSERT(!instr->HasW());
1836 addr = rn_val;
1837 rn_val += imm_val;
1838 write_back = true;
1839 break;
1840 }
1841 case 2: {
1842 // Format(instr, "'memop'cond'x 'rd2, ['rn, #-'off8]'w");
1843 rn_val -= imm_val;
1844 addr = rn_val;
1845 write_back = instr->HasW();
1846 break;
1847 }
1848 case 3: {
1849 // Format(instr, "'memop'cond'x 'rd2, ['rn, #+'off8]'w");
1850 rn_val += imm_val;
1851 addr = rn_val;
1852 write_back = instr->HasW();
1853 break;
1854 }
1855 default: {
1856 // The PU field is a 2-bit field.
1857 UNREACHABLE();
1858 break;
1859 }
1860 }
1861 }
1862 if (IsIllegalAddress(addr)) {
1863 HandleIllegalAccess(addr, instr);
1864 } else {
1865 if (write_back) {
1866 ASSERT(rd != rn); // Unpredictable.
1867 set_register(rn, rn_val);
1868 }
1869 if (!instr->HasSign()) {
1870 if (instr->HasL()) {
1871 uint16_t val = ReadHU(addr, instr);
1872 set_register(rd, val);
1873 } else {
1874 uint16_t val = get_register(rd);
1875 WriteH(addr, val, instr);
1876 }
1877 } else if (instr->HasL()) {
1878 if (instr->HasH()) {
1879 int16_t val = ReadH(addr, instr);
1880 set_register(rd, val);
1881 } else {
1882 int8_t val = ReadB(addr);
1883 set_register(rd, val);
1884 }
1885 } else if ((rd & 1) == 0) {
1886 Register rd1 = static_cast<Register>(rd | 1);
1888 if (instr->HasH()) {
1889 int32_t val_low = get_register(rd);
1890 int32_t val_high = get_register(rd1);
1891 WriteW(addr, val_low, instr);
1892 WriteW(addr + 4, val_high, instr);
1893 } else {
1894 int32_t val_low = ReadW(addr, instr);
1895 int32_t val_high = ReadW(addr + 4, instr);
1896 set_register(rd, val_low);
1897 set_register(rd1, val_high);
1898 }
1899 } else {
1900 UnimplementedInstruction(instr);
1901 }
1902 }
1903 }
1904 } else {
1905 Register rd = instr->RdField();
1906 Register rn = instr->RnField();
1907 uint32_t rn_val = get_register(rn);
1908 uint32_t shifter_operand = 0;
1909 bool shifter_carry_out = 0;
1910 if (instr->TypeField() == 0) {
1911 shifter_operand = GetShiftRm(instr, &shifter_carry_out);
1912 } else {
1913 ASSERT(instr->TypeField() == 1);
1914 shifter_operand = GetImm(instr, &shifter_carry_out);
1915 }
1916 uint32_t carry_in;
1917 uint32_t alu_out;
1918
1919 switch (instr->OpcodeField()) {
1920 case AND: {
1921 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
1922 // Format(instr, "and'cond's 'rd, 'rn, 'imm");
1923 alu_out = rn_val & shifter_operand;
1924 set_register(rd, alu_out);
1925 if (instr->HasS()) {
1926 SetNZFlags(alu_out);
1927 SetCFlag(shifter_carry_out);
1928 }
1929 break;
1930 }
1931
1932 case EOR: {
1933 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
1934 // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
1935 alu_out = rn_val ^ shifter_operand;
1936 set_register(rd, alu_out);
1937 if (instr->HasS()) {
1938 SetNZFlags(alu_out);
1939 SetCFlag(shifter_carry_out);
1940 }
1941 break;
1942 }
1943
1944 case SUB: {
1945 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
1946 // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
1947 alu_out = rn_val - shifter_operand;
1948 set_register(rd, alu_out);
1949 if (instr->HasS()) {
1950 SetNZFlags(alu_out);
1951 SetCFlag(CarryFrom(rn_val, ~shifter_operand, 1));
1952 SetVFlag(OverflowFrom(rn_val, ~shifter_operand, 1));
1953 }
1954 break;
1955 }
1956
1957 case RSB: {
1958 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
1959 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
1960 alu_out = shifter_operand - rn_val;
1961 set_register(rd, alu_out);
1962 if (instr->HasS()) {
1963 SetNZFlags(alu_out);
1964 SetCFlag(CarryFrom(shifter_operand, ~rn_val, 1));
1965 SetVFlag(OverflowFrom(shifter_operand, ~rn_val, 1));
1966 }
1967 break;
1968 }
1969
1970 case ADD: {
1971 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
1972 // Format(instr, "add'cond's 'rd, 'rn, 'imm");
1973 alu_out = rn_val + shifter_operand;
1974 set_register(rd, alu_out);
1975 if (instr->HasS()) {
1976 SetNZFlags(alu_out);
1977 SetCFlag(CarryFrom(rn_val, shifter_operand, 0));
1978 SetVFlag(OverflowFrom(rn_val, shifter_operand, 0));
1979 }
1980 break;
1981 }
1982
1983 case ADC: {
1984 // Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
1985 // Format(instr, "adc'cond's 'rd, 'rn, 'imm");
1986 carry_in = c_flag_ ? 1 : 0;
1987 alu_out = rn_val + shifter_operand + carry_in;
1988 set_register(rd, alu_out);
1989 if (instr->HasS()) {
1990 SetNZFlags(alu_out);
1991 SetCFlag(CarryFrom(rn_val, shifter_operand, carry_in));
1992 SetVFlag(OverflowFrom(rn_val, shifter_operand, carry_in));
1993 }
1994 break;
1995 }
1996
1997 case SBC: {
1998 // Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
1999 // Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
2000 carry_in = c_flag_ ? 1 : 0;
2001 alu_out = rn_val + ~shifter_operand + carry_in;
2002 set_register(rd, alu_out);
2003 if (instr->HasS()) {
2004 SetNZFlags(alu_out);
2005 SetCFlag(CarryFrom(rn_val, ~shifter_operand, carry_in));
2006 SetVFlag(OverflowFrom(rn_val, ~shifter_operand, carry_in));
2007 }
2008 break;
2009 }
2010
2011 case RSC: {
2012 // Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
2013 // Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
2014 carry_in = c_flag_ ? 1 : 0;
2015 alu_out = shifter_operand + ~rn_val + carry_in;
2016 set_register(rd, alu_out);
2017 if (instr->HasS()) {
2018 SetNZFlags(alu_out);
2019 SetCFlag(CarryFrom(shifter_operand, ~rn_val, carry_in));
2020 SetVFlag(OverflowFrom(shifter_operand, ~rn_val, carry_in));
2021 }
2022 break;
2023 }
2024
2025 case TST: {
2026 if (instr->HasS()) {
2027 // Format(instr, "tst'cond 'rn, 'shift_rm");
2028 // Format(instr, "tst'cond 'rn, 'imm");
2029 alu_out = rn_val & shifter_operand;
2030 SetNZFlags(alu_out);
2031 SetCFlag(shifter_carry_out);
2032 } else {
2033 UnimplementedInstruction(instr);
2034 }
2035 break;
2036 }
2037
2038 case TEQ: {
2039 if (instr->HasS()) {
2040 // Format(instr, "teq'cond 'rn, 'shift_rm");
2041 // Format(instr, "teq'cond 'rn, 'imm");
2042 alu_out = rn_val ^ shifter_operand;
2043 SetNZFlags(alu_out);
2044 SetCFlag(shifter_carry_out);
2045 } else {
2046 UnimplementedInstruction(instr);
2047 }
2048 break;
2049 }
2050
2051 case CMP: {
2052 if (instr->HasS()) {
2053 // Format(instr, "cmp'cond 'rn, 'shift_rm");
2054 // Format(instr, "cmp'cond 'rn, 'imm");
2055 alu_out = rn_val - shifter_operand;
2056 SetNZFlags(alu_out);
2057 SetCFlag(CarryFrom(rn_val, ~shifter_operand, 1));
2058 SetVFlag(OverflowFrom(rn_val, ~shifter_operand, 1));
2059 } else {
2060 UnimplementedInstruction(instr);
2061 }
2062 break;
2063 }
2064
2065 case CMN: {
2066 if (instr->HasS()) {
2067 // Format(instr, "cmn'cond 'rn, 'shift_rm");
2068 // Format(instr, "cmn'cond 'rn, 'imm");
2069 alu_out = rn_val + shifter_operand;
2070 SetNZFlags(alu_out);
2071 SetCFlag(CarryFrom(rn_val, shifter_operand, 0));
2072 SetVFlag(OverflowFrom(rn_val, shifter_operand, 0));
2073 } else {
2074 UnimplementedInstruction(instr);
2075 }
2076 break;
2077 }
2078
2079 case ORR: {
2080 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
2081 // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
2082 alu_out = rn_val | shifter_operand;
2083 set_register(rd, alu_out);
2084 if (instr->HasS()) {
2085 SetNZFlags(alu_out);
2086 SetCFlag(shifter_carry_out);
2087 }
2088 break;
2089 }
2090
2091 case MOV: {
2092 // Format(instr, "mov'cond's 'rd, 'shift_rm");
2093 // Format(instr, "mov'cond's 'rd, 'imm");
2094 alu_out = shifter_operand;
2095 set_register(rd, alu_out);
2096 if (instr->HasS()) {
2097 SetNZFlags(alu_out);
2098 SetCFlag(shifter_carry_out);
2099 }
2100 break;
2101 }
2102
2103 case BIC: {
2104 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
2105 // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
2106 alu_out = rn_val & ~shifter_operand;
2107 set_register(rd, alu_out);
2108 if (instr->HasS()) {
2109 SetNZFlags(alu_out);
2110 SetCFlag(shifter_carry_out);
2111 }
2112 break;
2113 }
2114
2115 case MVN: {
2116 // Format(instr, "mvn'cond's 'rd, 'shift_rm");
2117 // Format(instr, "mvn'cond's 'rd, 'imm");
2118 alu_out = ~shifter_operand;
2119 set_register(rd, alu_out);
2120 if (instr->HasS()) {
2121 SetNZFlags(alu_out);
2122 SetCFlag(shifter_carry_out);
2123 }
2124 break;
2125 }
2126
2127 default: {
2128 UNREACHABLE();
2129 break;
2130 }
2131 }
2132 }
2133}
2134
2135DART_FORCE_INLINE void Simulator::DecodeType2(Instr* instr) {
2136 Register rd = instr->RdField();
2137 Register rn = instr->RnField();
2138 int32_t rn_val = get_register(rn);
2139 int32_t im_val = instr->Offset12Field();
2140 uword addr = 0;
2141 bool write_back = false;
2142 switch (instr->PUField()) {
2143 case 0: {
2144 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
2145 ASSERT(!instr->HasW());
2146 addr = rn_val;
2147 rn_val -= im_val;
2148 write_back = true;
2149 break;
2150 }
2151 case 1: {
2152 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
2153 ASSERT(!instr->HasW());
2154 addr = rn_val;
2155 rn_val += im_val;
2156 write_back = true;
2157 break;
2158 }
2159 case 2: {
2160 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
2161 rn_val -= im_val;
2162 addr = rn_val;
2163 write_back = instr->HasW();
2164 break;
2165 }
2166 case 3: {
2167 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
2168 rn_val += im_val;
2169 addr = rn_val;
2170 write_back = instr->HasW();
2171 break;
2172 }
2173 default: {
2174 UNREACHABLE();
2175 break;
2176 }
2177 }
2178 if (IsIllegalAddress(addr)) {
2179 HandleIllegalAccess(addr, instr);
2180 } else {
2181 if (write_back) {
2182 ASSERT(rd != rn); // Unpredictable.
2183 set_register(rn, rn_val);
2184 }
2185 if (instr->HasB()) {
2186 if (instr->HasL()) {
2187 unsigned char val = ReadBU(addr);
2188 set_register(rd, val);
2189 } else {
2190 unsigned char val = get_register(rd);
2191 WriteB(addr, val);
2192 }
2193 } else {
2194 if (instr->HasL()) {
2195 set_register(rd, ReadW(addr, instr));
2196 } else {
2197 WriteW(addr, get_register(rd), instr);
2198 }
2199 }
2200 }
2201}
2202
2203void Simulator::DoDivision(Instr* instr) {
2204 const Register rd = instr->DivRdField();
2205 const Register rn = instr->DivRnField();
2206 const Register rm = instr->DivRmField();
2207
2208 if (!TargetCPUFeatures::integer_division_supported()) {
2209 UnimplementedInstruction(instr);
2210 return;
2211 }
2212
2213 // ARMv7-a does not trap on divide-by-zero. The destination register is just
2214 // set to 0.
2215 if (get_register(rm) == 0) {
2216 set_register(rd, 0);
2217 return;
2218 }
2219
2220 if (instr->IsDivUnsigned()) {
2221 // unsigned division.
2222 uint32_t rn_val = static_cast<uint32_t>(get_register(rn));
2223 uint32_t rm_val = static_cast<uint32_t>(get_register(rm));
2224 uint32_t result = rn_val / rm_val;
2225 set_register(rd, static_cast<int32_t>(result));
2226 } else {
2227 // signed division.
2228 int32_t rn_val = get_register(rn);
2229 int32_t rm_val = get_register(rm);
2230 int32_t result;
2231 if ((rn_val == static_cast<int32_t>(0x80000000)) &&
2232 (rm_val == static_cast<int32_t>(0xffffffff))) {
2233 result = 0x80000000;
2234 } else {
2235 result = rn_val / rm_val;
2236 }
2237 set_register(rd, result);
2238 }
2239}
2240
2241void Simulator::DecodeType3(Instr* instr) {
2242 if (instr->IsMedia()) {
2243 if (instr->IsDivision()) {
2244 DoDivision(instr);
2245 return;
2246 } else if (instr->IsRbit()) {
2247 // Format(instr, "rbit'cond 'rd, 'rm");
2248 Register rm = instr->RmField();
2249 Register rd = instr->RdField();
2250 set_register(rd, Utils::ReverseBits32(get_register(rm)));
2251 return;
2252 } else if (instr->IsBitFieldExtract()) {
2253 // Format(instr, "sbfx'cond 'rd, 'rn, 'lsb, 'width")
2254 const Register rd = instr->RdField();
2255 const Register rn = instr->BitFieldExtractRnField();
2256 const uint8_t width = instr->BitFieldExtractWidthField() + 1;
2257 const uint8_t lsb = instr->BitFieldExtractLSBField();
2258 const int32_t rn_val = get_register(rn);
2259 const uint32_t extracted_bitfield =
2260 ((rn_val >> lsb) & Utils::NBitMask(width));
2261 const uint32_t sign_extension =
2262 (instr->IsBitFieldExtractSignExtended() &&
2263 Utils::TestBit(extracted_bitfield, width - 1))
2264 ? ~Utils::NBitMask(width)
2265 : 0;
2266 set_register(rd, sign_extension | extracted_bitfield);
2267 } else {
2268 UNREACHABLE();
2269 }
2270 return;
2271 }
2272 Register rd = instr->RdField();
2273 Register rn = instr->RnField();
2274 int32_t rn_val = get_register(rn);
2275 bool shifter_carry_out = 0;
2276 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2277 uword addr = 0;
2278 bool write_back = false;
2279 switch (instr->PUField()) {
2280 case 0: {
2281 // Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
2282 ASSERT(!instr->HasW());
2283 addr = rn_val;
2284 rn_val -= shifter_operand;
2285 write_back = true;
2286 break;
2287 }
2288 case 1: {
2289 // Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
2290 ASSERT(!instr->HasW());
2291 addr = rn_val;
2292 rn_val += shifter_operand;
2293 write_back = true;
2294 break;
2295 }
2296 case 2: {
2297 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
2298 rn_val -= shifter_operand;
2299 addr = rn_val;
2300 write_back = instr->HasW();
2301 break;
2302 }
2303 case 3: {
2304 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
2305 rn_val += shifter_operand;
2306 addr = rn_val;
2307 write_back = instr->HasW();
2308 break;
2309 }
2310 default: {
2311 UNREACHABLE();
2312 break;
2313 }
2314 }
2315 if (IsIllegalAddress(addr)) {
2316 HandleIllegalAccess(addr, instr);
2317 } else {
2318 if (write_back) {
2319 ASSERT(rd != rn); // Unpredictable.
2320 set_register(rn, rn_val);
2321 }
2322 if (instr->HasB()) {
2323 if (instr->HasL()) {
2324 unsigned char val = ReadBU(addr);
2325 set_register(rd, val);
2326 } else {
2327 unsigned char val = get_register(rd);
2328 WriteB(addr, val);
2329 }
2330 } else {
2331 if (instr->HasL()) {
2332 set_register(rd, ReadW(addr, instr));
2333 } else {
2334 WriteW(addr, get_register(rd), instr);
2335 }
2336 }
2337 }
2338}
2339
2340void Simulator::DecodeType4(Instr* instr) {
2341 ASSERT(instr->Bit(22) == 0); // only allowed to be set in privileged mode
2342 if (instr->HasL()) {
2343 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
2344 HandleRList(instr, true);
2345 } else {
2346 // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
2347 HandleRList(instr, false);
2348 }
2349}
2350
2351void Simulator::DecodeType5(Instr* instr) {
2352 // Format(instr, "b'l'cond 'target");
2353 uint32_t off = (static_cast<uint32_t>(instr->SImmed24Field()) << 2) + 8;
2354 uint32_t pc = get_pc();
2355 if (instr->HasLink()) {
2356 set_register(LR, pc + Instr::kInstrSize);
2357 }
2358 set_pc(pc + off);
2359}
2360
2361void Simulator::DecodeType6(Instr* instr) {
2362 if (instr->IsVFPDoubleTransfer()) {
2363 Register rd = instr->RdField();
2364 Register rn = instr->RnField();
2365 if (instr->Bit(8) == 0) {
2366 SRegister sm = instr->SmField();
2367 SRegister sm1 = static_cast<SRegister>(sm + 1);
2369 if (instr->Bit(20) == 1) {
2370 // Format(instr, "vmovrrs'cond 'rd, 'rn, {'sm', 'sm1}");
2371 set_register(rd, get_sregister_bits(sm));
2372 set_register(rn, get_sregister_bits(sm1));
2373 } else {
2374 // Format(instr, "vmovsrr'cond {'sm, 'sm1}, 'rd', 'rn");
2375 set_sregister_bits(sm, get_register(rd));
2376 set_sregister_bits(sm1, get_register(rn));
2377 }
2378 } else {
2379 DRegister dm = instr->DmField();
2380 if (instr->Bit(20) == 1) {
2381 // Format(instr, "vmovrrd'cond 'rd, 'rn, 'dm");
2382 int64_t dm_val = get_dregister_bits(dm);
2383 set_register(rd, Utils::Low32Bits(dm_val));
2384 set_register(rn, Utils::High32Bits(dm_val));
2385 } else {
2386 // Format(instr, "vmovdrr'cond 'dm, 'rd, 'rn");
2387 int64_t dm_val =
2388 Utils::LowHighTo64Bits(get_register(rd), get_register(rn));
2389 set_dregister_bits(dm, dm_val);
2390 }
2391 }
2392 } else if (instr->IsVFPLoadStore()) {
2393 Register rn = instr->RnField();
2394 int32_t addr = get_register(rn);
2395 int32_t imm_val = instr->Bits(0, 8) << 2;
2396 if (instr->Bit(23) == 1) {
2397 addr += imm_val;
2398 } else {
2399 addr -= imm_val;
2400 }
2401 if (IsIllegalAddress(addr)) {
2402 HandleIllegalAccess(addr, instr);
2403 } else {
2404 if (instr->Bit(8) == 0) {
2405 SRegister sd = instr->SdField();
2406 if (instr->Bit(20) == 1) { // vldrs
2407 // Format(instr, "vldrs'cond 'sd, ['rn, #+'off10]");
2408 // Format(instr, "vldrs'cond 'sd, ['rn, #-'off10]");
2409 set_sregister_bits(sd, ReadW(addr, instr));
2410 } else { // vstrs
2411 // Format(instr, "vstrs'cond 'sd, ['rn, #+'off10]");
2412 // Format(instr, "vstrs'cond 'sd, ['rn, #-'off10]");
2413 WriteW(addr, get_sregister_bits(sd), instr);
2414 }
2415 } else {
2416 DRegister dd = instr->DdField();
2417 if (instr->Bit(20) == 1) { // vldrd
2418 // Format(instr, "vldrd'cond 'dd, ['rn, #+'off10]");
2419 // Format(instr, "vldrd'cond 'dd, ['rn, #-'off10]");
2420 int64_t dd_val = Utils::LowHighTo64Bits(ReadW(addr, instr),
2421 ReadW(addr + 4, instr));
2422 set_dregister_bits(dd, dd_val);
2423 } else { // vstrd
2424 // Format(instr, "vstrd'cond 'dd, ['rn, #+'off10]");
2425 // Format(instr, "vstrd'cond 'dd, ['rn, #-'off10]");
2426 int64_t dd_val = get_dregister_bits(dd);
2427 WriteW(addr, Utils::Low32Bits(dd_val), instr);
2428 WriteW(addr + 4, Utils::High32Bits(dd_val), instr);
2429 }
2430 }
2431 }
2432 } else if (instr->IsVFPMultipleLoadStore()) {
2433 Register rn = instr->RnField();
2434 int32_t addr = get_register(rn);
2435 int32_t imm_val = instr->Bits(0, 8);
2436 if (instr->Bit(23) == 0) {
2437 addr -= (imm_val << 2);
2438 }
2439 if (instr->HasW()) {
2440 if (instr->Bit(23) == 1) {
2441 set_register(rn, addr + (imm_val << 2));
2442 } else {
2443 set_register(rn, addr); // already subtracted from addr
2444 }
2445 }
2446 if (IsIllegalAddress(addr)) {
2447 HandleIllegalAccess(addr, instr);
2448 } else {
2449 if (instr->Bit(8) == 0) {
2450 int32_t regs_cnt = imm_val;
2451 int32_t start = instr->Bit(22) | (instr->Bits(12, 4) << 1);
2452 for (int i = start; i < start + regs_cnt; i++) {
2453 SRegister sd = static_cast<SRegister>(i);
2454 if (instr->Bit(20) == 1) {
2455 // Format(instr, "vldms'cond'pu 'rn'w, 'slist");
2456 set_sregister_bits(sd, ReadW(addr, instr));
2457 } else {
2458 // Format(instr, "vstms'cond'pu 'rn'w, 'slist");
2459 WriteW(addr, get_sregister_bits(sd), instr);
2460 }
2461 addr += 4;
2462 }
2463 } else {
2464 int32_t regs_cnt = imm_val >> 1;
2465 int32_t start = (instr->Bit(22) << 4) | instr->Bits(12, 4);
2466 if ((regs_cnt <= 16) && (start + regs_cnt <= kNumberOfDRegisters)) {
2467 for (int i = start; i < start + regs_cnt; i++) {
2468 DRegister dd = static_cast<DRegister>(i);
2469 if (instr->Bit(20) == 1) {
2470 // Format(instr, "vldmd'cond'pu 'rn'w, 'dlist");
2471 int64_t dd_val = Utils::LowHighTo64Bits(ReadW(addr, instr),
2472 ReadW(addr + 4, instr));
2473 set_dregister_bits(dd, dd_val);
2474 } else {
2475 // Format(instr, "vstmd'cond'pu 'rn'w, 'dlist");
2476 int64_t dd_val = get_dregister_bits(dd);
2477 WriteW(addr, Utils::Low32Bits(dd_val), instr);
2478 WriteW(addr + 4, Utils::High32Bits(dd_val), instr);
2479 }
2480 addr += 8;
2481 }
2482 } else {
2483 UnimplementedInstruction(instr);
2484 }
2485 }
2486 }
2487 } else {
2488 UnimplementedInstruction(instr);
2489 }
2490}
2491
2492void Simulator::DecodeType7(Instr* instr) {
2493 if (instr->Bit(24) == 1) {
2494 // Format(instr, "svc #'svc");
2495 SupervisorCall(instr);
2496 } else if (instr->IsVFPDataProcessingOrSingleTransfer()) {
2497 if (instr->Bit(4) == 0) {
2498 // VFP Data Processing
2499 SRegister sd;
2500 SRegister sn;
2501 SRegister sm;
2502 DRegister dd;
2503 DRegister dn;
2504 DRegister dm;
2505 if (instr->Bit(8) == 0) {
2506 sd = instr->SdField();
2507 sn = instr->SnField();
2508 sm = instr->SmField();
2509 dd = kNoDRegister;
2510 dn = kNoDRegister;
2511 dm = kNoDRegister;
2512 } else {
2513 sd = kNoSRegister;
2514 sn = kNoSRegister;
2515 sm = kNoSRegister;
2516 dd = instr->DdField();
2517 dn = instr->DnField();
2518 dm = instr->DmField();
2519 }
2520 switch (instr->Bits(20, 4) & 0xb) {
2521 case 1: // vnmla, vnmls, vnmul
2522 default: {
2523 UnimplementedInstruction(instr);
2524 break;
2525 }
2526 case 0: { // vmla, vmls floating-point
2527 if (instr->Bit(8) == 0) {
2528 float addend = get_sregister(sn) * get_sregister(sm);
2529 float sd_val = get_sregister(sd);
2530 if (instr->Bit(6) == 0) {
2531 // Format(instr, "vmlas'cond 'sd, 'sn, 'sm");
2532 } else {
2533 // Format(instr, "vmlss'cond 'sd, 'sn, 'sm");
2534 addend = -addend;
2535 }
2536 set_sregister(sd, sd_val + addend);
2537 } else {
2538 double addend = get_dregister(dn) * get_dregister(dm);
2539 double dd_val = get_dregister(dd);
2540 if (instr->Bit(6) == 0) {
2541 // Format(instr, "vmlad'cond 'dd, 'dn, 'dm");
2542 } else {
2543 // Format(instr, "vmlsd'cond 'dd, 'dn, 'dm");
2544 addend = -addend;
2545 }
2546 set_dregister(dd, dd_val + addend);
2547 }
2548 break;
2549 }
2550 case 2: { // vmul
2551 if (instr->Bit(8) == 0) {
2552 // Format(instr, "vmuls'cond 'sd, 'sn, 'sm");
2553 set_sregister(sd, get_sregister(sn) * get_sregister(sm));
2554 } else {
2555 // Format(instr, "vmuld'cond 'dd, 'dn, 'dm");
2556 set_dregister(dd, get_dregister(dn) * get_dregister(dm));
2557 }
2558 break;
2559 }
2560 case 8: { // vdiv
2561 if (instr->Bit(8) == 0) {
2562 // Format(instr, "vdivs'cond 'sd, 'sn, 'sm");
2563 set_sregister(sd, get_sregister(sn) / get_sregister(sm));
2564 } else {
2565 // Format(instr, "vdivd'cond 'dd, 'dn, 'dm");
2566 set_dregister(dd, get_dregister(dn) / get_dregister(dm));
2567 }
2568 break;
2569 }
2570 case 3: { // vadd, vsub floating-point
2571 if (instr->Bit(8) == 0) {
2572 if (instr->Bit(6) == 0) {
2573 // Format(instr, "vadds'cond 'sd, 'sn, 'sm");
2574 set_sregister(sd, get_sregister(sn) + get_sregister(sm));
2575 } else {
2576 // Format(instr, "vsubs'cond 'sd, 'sn, 'sm");
2577 set_sregister(sd, get_sregister(sn) - get_sregister(sm));
2578 }
2579 } else {
2580 if (instr->Bit(6) == 0) {
2581 // Format(instr, "vaddd'cond 'dd, 'dn, 'dm");
2582 set_dregister(dd, get_dregister(dn) + get_dregister(dm));
2583 } else {
2584 // Format(instr, "vsubd'cond 'dd, 'dn, 'dm");
2585 set_dregister(dd, get_dregister(dn) - get_dregister(dm));
2586 }
2587 }
2588 break;
2589 }
2590 case 0xb: { // Other VFP data-processing instructions
2591 if (instr->Bit(6) == 0) { // vmov immediate
2592 if (instr->Bit(8) == 0) {
2593 // Format(instr, "vmovs'cond 'sd, #'immf");
2594 set_sregister(sd, instr->ImmFloatField());
2595 } else {
2596 // Format(instr, "vmovd'cond 'dd, #'immd");
2597 set_dregister(dd, instr->ImmDoubleField());
2598 }
2599 break;
2600 }
2601 switch (instr->Bits(16, 4)) {
2602 case 0: { // vmov immediate, vmov register, vabs
2603 switch (instr->Bits(6, 2)) {
2604 case 1: { // vmov register
2605 if (instr->Bit(8) == 0) {
2606 // Format(instr, "vmovs'cond 'sd, 'sm");
2607 set_sregister(sd, get_sregister(sm));
2608 } else {
2609 // Format(instr, "vmovd'cond 'dd, 'dm");
2610 set_dregister(dd, get_dregister(dm));
2611 }
2612 break;
2613 }
2614 case 3: { // vabs
2615 if (instr->Bit(8) == 0) {
2616 // Format(instr, "vabss'cond 'sd, 'sm");
2617 set_sregister(sd, fabsf(get_sregister(sm)));
2618 } else {
2619 // Format(instr, "vabsd'cond 'dd, 'dm");
2620 set_dregister(dd, fabs(get_dregister(dm)));
2621 }
2622 break;
2623 }
2624 default: {
2625 UnimplementedInstruction(instr);
2626 break;
2627 }
2628 }
2629 break;
2630 }
2631 case 1: { // vneg, vsqrt
2632 switch (instr->Bits(6, 2)) {
2633 case 1: { // vneg
2634 if (instr->Bit(8) == 0) {
2635 // Format(instr, "vnegs'cond 'sd, 'sm");
2636 set_sregister(sd, -get_sregister(sm));
2637 } else {
2638 // Format(instr, "vnegd'cond 'dd, 'dm");
2639 set_dregister(dd, -get_dregister(dm));
2640 }
2641 break;
2642 }
2643 case 3: { // vsqrt
2644 if (instr->Bit(8) == 0) {
2645 // Format(instr, "vsqrts'cond 'sd, 'sm");
2646 set_sregister(sd, sqrtf(get_sregister(sm)));
2647 } else {
2648 // Format(instr, "vsqrtd'cond 'dd, 'dm");
2649 set_dregister(dd, sqrt(get_dregister(dm)));
2650 }
2651 break;
2652 }
2653 default: {
2654 UnimplementedInstruction(instr);
2655 break;
2656 }
2657 }
2658 break;
2659 }
2660 case 4: // vcmp, vcmpe
2661 case 5: { // vcmp #0.0, vcmpe #0.0
2662 if (instr->Bit(7) == 1) { // vcmpe
2663 UnimplementedInstruction(instr);
2664 } else {
2665 fp_n_flag_ = false;
2666 fp_z_flag_ = false;
2667 fp_c_flag_ = false;
2668 fp_v_flag_ = false;
2669 if (instr->Bit(8) == 0) { // vcmps
2670 float sd_val = get_sregister(sd);
2671 float sm_val;
2672 if (instr->Bit(16) == 0) {
2673 // Format(instr, "vcmps'cond 'sd, 'sm");
2674 sm_val = get_sregister(sm);
2675 } else {
2676 // Format(instr, "vcmps'cond 'sd, #0.0");
2677 sm_val = 0.0f;
2678 }
2679 if (isnan(sd_val) || isnan(sm_val)) {
2680 fp_c_flag_ = true;
2681 fp_v_flag_ = true;
2682 } else if (sd_val == sm_val) {
2683 fp_z_flag_ = true;
2684 fp_c_flag_ = true;
2685 } else if (sd_val < sm_val) {
2686 fp_n_flag_ = true;
2687 } else {
2688 fp_c_flag_ = true;
2689 }
2690 } else { // vcmpd
2691 double dd_val = get_dregister(dd);
2692 double dm_val;
2693 if (instr->Bit(16) == 0) {
2694 // Format(instr, "vcmpd'cond 'dd, 'dm");
2695 dm_val = get_dregister(dm);
2696 } else {
2697 // Format(instr, "vcmpd'cond 'dd, #0.0");
2698 dm_val = 0.0;
2699 }
2700 if (isnan(dd_val) || isnan(dm_val)) {
2701 fp_c_flag_ = true;
2702 fp_v_flag_ = true;
2703 } else if (dd_val == dm_val) {
2704 fp_z_flag_ = true;
2705 fp_c_flag_ = true;
2706 } else if (dd_val < dm_val) {
2707 fp_n_flag_ = true;
2708 } else {
2709 fp_c_flag_ = true;
2710 }
2711 }
2712 }
2713 break;
2714 }
2715 case 7: { // vcvt between double-precision and single-precision
2716 if (instr->Bit(8) == 0) {
2717 // Format(instr, "vcvtds'cond 'dd, 'sm");
2718 dd = instr->DdField();
2719 set_dregister(dd, static_cast<double>(get_sregister(sm)));
2720 } else {
2721 // Format(instr, "vcvtsd'cond 'sd, 'dm");
2722 sd = instr->SdField();
2723 set_sregister(sd, static_cast<float>(get_dregister(dm)));
2724 }
2725 break;
2726 }
2727 case 8: { // vcvt, vcvtr between floating-point and integer
2728 sm = instr->SmField();
2729 int32_t sm_int = get_sregister_bits(sm);
2730 uint32_t ud_val = 0;
2731 int32_t id_val = 0;
2732 if (instr->Bit(7) == 0) { // vcvtsu, vcvtdu
2733 ud_val = static_cast<uint32_t>(sm_int);
2734 } else { // vcvtsi, vcvtdi
2735 id_val = sm_int;
2736 }
2737 if (instr->Bit(8) == 0) {
2738 float sd_val;
2739 if (instr->Bit(7) == 0) {
2740 // Format(instr, "vcvtsu'cond 'sd, 'sm");
2741 sd_val = static_cast<float>(ud_val);
2742 } else {
2743 // Format(instr, "vcvtsi'cond 'sd, 'sm");
2744 sd_val = static_cast<float>(id_val);
2745 }
2746 set_sregister(sd, sd_val);
2747 } else {
2748 double dd_val;
2749 if (instr->Bit(7) == 0) {
2750 // Format(instr, "vcvtdu'cond 'dd, 'sm");
2751 dd_val = static_cast<double>(ud_val);
2752 } else {
2753 // Format(instr, "vcvtdi'cond 'dd, 'sm");
2754 dd_val = static_cast<double>(id_val);
2755 }
2756 set_dregister(dd, dd_val);
2757 }
2758 break;
2759 }
2760 case 12:
2761 case 13: { // vcvt, vcvtr between floating-point and integer
2762 // We do not need to record exceptions in the FPSCR cumulative
2763 // flags, because we do not use them.
2764 if (instr->Bit(7) == 0) {
2765 // We only support round-to-zero mode
2766 UnimplementedInstruction(instr);
2767 break;
2768 }
2769 int32_t id_val = 0;
2770 uint32_t ud_val = 0;
2771 if (instr->Bit(8) == 0) {
2772 float sm_val = get_sregister(sm);
2773 if (instr->Bit(16) == 0) {
2774 // Format(instr, "vcvtus'cond 'sd, 'sm");
2775 if (sm_val >= static_cast<float>(INT32_MAX)) {
2776 ud_val = INT32_MAX;
2777 } else if (sm_val > 0.0) {
2778 ud_val = static_cast<uint32_t>(sm_val);
2779 }
2780 } else {
2781 // Format(instr, "vcvtis'cond 'sd, 'sm");
2782 if (sm_val <= static_cast<float>(INT32_MIN)) {
2783 id_val = INT32_MIN;
2784 } else if (sm_val >= static_cast<float>(INT32_MAX)) {
2785 id_val = INT32_MAX;
2786 } else {
2787 id_val = static_cast<int32_t>(sm_val);
2788 }
2789 ASSERT((id_val >= 0) || !(sm_val >= 0.0));
2790 }
2791 } else {
2792 sd = instr->SdField();
2793 double dm_val = get_dregister(dm);
2794 if (instr->Bit(16) == 0) {
2795 // Format(instr, "vcvtud'cond 'sd, 'dm");
2796 if (dm_val >= static_cast<double>(INT32_MAX)) {
2797 ud_val = INT32_MAX;
2798 } else if (dm_val > 0.0) {
2799 ud_val = static_cast<uint32_t>(dm_val);
2800 }
2801 } else {
2802 // Format(instr, "vcvtid'cond 'sd, 'dm");
2803 if (dm_val <= static_cast<double>(INT32_MIN)) {
2804 id_val = INT32_MIN;
2805 } else if (dm_val >= static_cast<double>(INT32_MAX)) {
2806 id_val = INT32_MAX;
2807 } else if (isnan(dm_val)) {
2808 id_val = 0;
2809 } else {
2810 id_val = static_cast<int32_t>(dm_val);
2811 }
2812 ASSERT((id_val >= 0) || !(dm_val >= 0.0));
2813 }
2814 }
2815 int32_t sd_val;
2816 if (instr->Bit(16) == 0) {
2817 sd_val = static_cast<int32_t>(ud_val);
2818 } else {
2819 sd_val = id_val;
2820 }
2821 set_sregister_bits(sd, sd_val);
2822 break;
2823 }
2824 case 2: // vcvtb, vcvtt
2825 case 3: // vcvtb, vcvtt
2826 case 9: // undefined
2827 case 10: // vcvt between floating-point and fixed-point
2828 case 11: // vcvt between floating-point and fixed-point
2829 case 14: // vcvt between floating-point and fixed-point
2830 case 15: // vcvt between floating-point and fixed-point
2831 default: {
2832 UnimplementedInstruction(instr);
2833 break;
2834 }
2835 }
2836 } break;
2837 }
2838 } else {
2839 // 8, 16, or 32-bit Transfer between ARM Core and VFP
2840 if ((instr->Bits(21, 3) == 0) && (instr->Bit(8) == 0)) {
2841 Register rd = instr->RdField();
2842 SRegister sn = instr->SnField();
2843 if (instr->Bit(20) == 0) {
2844 // Format(instr, "vmovs'cond 'sn, 'rd");
2845 set_sregister_bits(sn, get_register(rd));
2846 } else {
2847 // Format(instr, "vmovr'cond 'rd, 'sn");
2848 set_register(rd, get_sregister_bits(sn));
2849 }
2850 } else if ((instr->Bits(22, 3) == 0) && (instr->Bit(20) == 0) &&
2851 (instr->Bit(8) == 1) && (instr->Bits(5, 2) == 0)) {
2852 DRegister dn = instr->DnField();
2853 Register rd = instr->RdField();
2854 const int32_t src_value = get_register(rd);
2855 const int64_t dst_value = get_dregister_bits(dn);
2856 int32_t dst_lo = Utils::Low32Bits(dst_value);
2857 int32_t dst_hi = Utils::High32Bits(dst_value);
2858 if (instr->Bit(21) == 0) {
2859 // Format(instr, "vmovd'cond 'dn[0], 'rd");
2860 dst_lo = src_value;
2861 } else {
2862 // Format(instr, "vmovd'cond 'dn[1], 'rd");
2863 dst_hi = src_value;
2864 }
2865 set_dregister_bits(dn, Utils::LowHighTo64Bits(dst_lo, dst_hi));
2866 } else if ((instr->Bits(20, 4) == 0xf) && (instr->Bit(8) == 0)) {
2867 if (instr->Bits(12, 4) == 0xf) {
2868 // Format(instr, "vmrs'cond APSR, FPSCR");
2869 n_flag_ = fp_n_flag_;
2870 z_flag_ = fp_z_flag_;
2871 c_flag_ = fp_c_flag_;
2872 v_flag_ = fp_v_flag_;
2873 } else {
2874 // Format(instr, "vmrs'cond 'rd, FPSCR");
2875 const int32_t n_flag = fp_n_flag_ ? (1 << 31) : 0;
2876 const int32_t z_flag = fp_z_flag_ ? (1 << 30) : 0;
2877 const int32_t c_flag = fp_c_flag_ ? (1 << 29) : 0;
2878 const int32_t v_flag = fp_v_flag_ ? (1 << 28) : 0;
2879 set_register(instr->RdField(), n_flag | z_flag | c_flag | v_flag);
2880 }
2881 } else {
2882 UnimplementedInstruction(instr);
2883 }
2884 }
2885 } else {
2886 UnimplementedInstruction(instr);
2887 }
2888}
2889
2890static void simd_value_swap(simd_value_t* s1,
2891 int i1,
2892 simd_value_t* s2,
2893 int i2) {
2894 uint32_t tmp;
2895 tmp = s1->u32[i1];
2896 s1->u32[i1] = s2->u32[i2];
2897 s2->u32[i2] = tmp;
2898}
2899
2900static float vminf(float f1, float f2) {
2901 if (f1 == f2) {
2902 // take care of (-0.0) < 0.0, (they are equal according to minss)
2903 return signbit(f1) ? f1 : f2;
2904 }
2905 return f1 > f2 ? f2 : f1;
2906}
2907
2908static float vmaxf(float f1, float f2) {
2909 if (f1 == f2) {
2910 // take care of (-0.0) < 0.0, (they are equal according to minss)
2911 return signbit(f1) ? f2 : f1;
2912 }
2913 return f1 < f2 ? f2 : f1;
2914}
2915
2916void Simulator::DecodeSIMDDataProcessing(Instr* instr) {
2917 ASSERT(instr->ConditionField() == kSpecialCondition);
2918
2919 if (instr->Bit(6) == 1) {
2920 // Q = 1, Using 128-bit Q registers.
2921 const QRegister qd = instr->QdField();
2922 const QRegister qn = instr->QnField();
2923 const QRegister qm = instr->QmField();
2924 simd_value_t s8d;
2925 simd_value_t s8n;
2926 simd_value_t s8m;
2927
2928 get_qregister(qn, &s8n);
2929 get_qregister(qm, &s8m);
2930
2931 if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) &&
2932 (instr->Bits(23, 2) == 0)) {
2933 // Uses q registers.
2934 // Format(instr, "vadd.'sz 'qd, 'qn, 'qm");
2935 const int size = instr->Bits(20, 2);
2936 if (size == 0) {
2937 for (int i = 0; i < 16; i++) {
2938 s8d.u8[i] = s8n.u8[i] + s8m.u8[i];
2939 }
2940 } else if (size == 1) {
2941 for (int i = 0; i < 8; i++) {
2942 s8d.u16[i] = s8n.u16[i] + s8m.u16[i];
2943 }
2944 } else if (size == 2) {
2945 for (int i = 0; i < 4; i++) {
2946 s8d.u32[i] = s8n.u32[i] + s8m.u32[i];
2947 }
2948 } else if (size == 3) {
2949 for (int i = 0; i < 2; i++) {
2950 s8d.u64[i] = s8n.u64[i] + s8m.u64[i];
2951 }
2952 } else {
2953 UNREACHABLE();
2954 }
2955 } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) &&
2956 (instr->Bits(23, 2) == 0) && (instr->Bit(21) == 0)) {
2957 // Format(instr, "vadd.F32 'qd, 'qn, 'qm");
2958 for (int i = 0; i < 4; i++) {
2959 s8d.f32[i] = s8n.f32[i] + s8m.f32[i];
2960 }
2961 } else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) &&
2962 (instr->Bits(23, 2) == 2)) {
2963 // Format(instr, "vsub.'sz 'qd, 'qn, 'qm");
2964 const int size = instr->Bits(20, 2);
2965 if (size == 0) {
2966 for (int i = 0; i < 16; i++) {
2967 s8d.u8[i] = s8n.u8[i] - s8m.u8[i];
2968 }
2969 } else if (size == 1) {
2970 for (int i = 0; i < 8; i++) {
2971 s8d.u16[i] = s8n.u16[i] - s8m.u16[i];
2972 }
2973 } else if (size == 2) {
2974 for (int i = 0; i < 4; i++) {
2975 s8d.u32[i] = s8n.u32[i] - s8m.u32[i];
2976 }
2977 } else if (size == 3) {
2978 for (int i = 0; i < 2; i++) {
2979 s8d.u64[i] = s8n.u64[i] - s8m.u64[i];
2980 }
2981 } else {
2982 UNREACHABLE();
2983 }
2984 } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) &&
2985 (instr->Bits(23, 2) == 0) && (instr->Bit(21) == 1)) {
2986 // Format(instr, "vsub.F32 'qd, 'qn, 'qm");
2987 for (int i = 0; i < 4; i++) {
2988 s8d.f32[i] = s8n.f32[i] - s8m.f32[i];
2989 }
2990 } else if ((instr->Bits(8, 4) == 9) && (instr->Bit(4) == 1) &&
2991 (instr->Bits(23, 2) == 0)) {
2992 // Format(instr, "vmul.'sz 'qd, 'qn, 'qm");
2993 const int size = instr->Bits(20, 2);
2994 if (size == 0) {
2995 for (int i = 0; i < 16; i++) {
2996 s8d.i8[i] = s8n.i8[i] * s8m.i8[i];
2997 }
2998 } else if (size == 1) {
2999 for (int i = 0; i < 8; i++) {
3000 s8d.i16[i] = s8n.i16[i] * s8m.i16[i];
3001 }
3002 } else if (size == 2) {
3003 for (int i = 0; i < 4; i++) {
3004 s8d.u32[i] = s8n.u32[i] * s8m.u32[i];
3005 }
3006 } else if (size == 3) {
3007 UnimplementedInstruction(instr);
3008 } else {
3009 UNREACHABLE();
3010 }
3011 } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 1) &&
3012 (instr->Bits(23, 2) == 2) && (instr->Bit(21) == 0)) {
3013 // Format(instr, "vmul.F32 'qd, 'qn, 'qm");
3014 for (int i = 0; i < 4; i++) {
3015 s8d.f32[i] = s8n.f32[i] * s8m.f32[i];
3016 }
3017 } else if ((instr->Bits(8, 4) == 4) && (instr->Bit(4) == 0) &&
3018 (instr->Bit(23) == 0) && (instr->Bits(25, 3) == 1)) {
3019 // Format(instr, "vshlqu'sz 'qd, 'qm, 'qn");
3020 // Format(instr, "vshlqi'sz 'qd, 'qm, 'qn");
3021 const bool is_signed = instr->Bit(24) == 0;
3022 const int size = instr->Bits(20, 2);
3023 if (size == 0) {
3024 for (int i = 0; i < 16; i++) {
3025 int8_t shift = s8n.i8[i];
3026 if (shift > 0) {
3027 s8d.u8[i] = s8m.u8[i] << shift;
3028 } else if (shift < 0) {
3029 if (is_signed) {
3030 s8d.i8[i] = s8m.i8[i] >> (-shift);
3031 } else {
3032 s8d.u8[i] = s8m.u8[i] >> (-shift);
3033 }
3034 }
3035 }
3036 } else if (size == 1) {
3037 for (int i = 0; i < 8; i++) {
3038 int8_t shift = s8n.i8[i * 2];
3039 if (shift > 0) {
3040 s8d.u16[i] = s8m.u16[i] << shift;
3041 } else if (shift < 0) {
3042 if (is_signed) {
3043 s8d.i16[i] = s8m.i16[i] >> (-shift);
3044 } else {
3045 s8d.u16[i] = s8m.u16[i] >> (-shift);
3046 }
3047 }
3048 }
3049 } else if (size == 2) {
3050 for (int i = 0; i < 4; i++) {
3051 int8_t shift = s8n.i8[i * 4];
3052 if (shift > 0) {
3053 s8d.u32[i] = s8m.u32[i] << shift;
3054 } else if (shift < 0) {
3055 if (is_signed) {
3056 s8d.i32[i] = s8m.i32[i] >> (-shift);
3057 } else {
3058 s8d.u32[i] = s8m.u32[i] >> (-shift);
3059 }
3060 }
3061 }
3062 } else {
3063 ASSERT(size == 3);
3064 for (int i = 0; i < 2; i++) {
3065 int8_t shift = s8n.i8[i * 8];
3066 if (shift > 0) {
3067 s8d.u64[i] = s8m.u64[i] << shift;
3068 } else if (shift < 0) {
3069 if (is_signed) {
3070 s8d.i64[i] = s8m.i64[i] >> (-shift);
3071 } else {
3072 s8d.u64[i] = s8m.u64[i] >> (-shift);
3073 }
3074 }
3075 }
3076 }
3077 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
3078 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 2)) {
3079 // Format(instr, "veorq 'qd, 'qn, 'qm");
3080 for (int i = 0; i < 4; i++) {
3081 s8d.u32[i] = s8n.u32[i] ^ s8m.u32[i];
3082 }
3083 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
3084 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 0)) {
3085 // Format(instr, "vornq 'qd, 'qn, 'qm");
3086 for (int i = 0; i < 4; i++) {
3087 s8d.u32[i] = s8n.u32[i] | ~s8m.u32[i];
3088 }
3089 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
3090 (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
3091 if (qm == qn) {
3092 // Format(instr, "vmovq 'qd, 'qm");
3093 for (int i = 0; i < 4; i++) {
3094 s8d.u32[i] = s8m.u32[i];
3095 }
3096 } else {
3097 // Format(instr, "vorrq 'qd, 'qm");
3098 for (int i = 0; i < 4; i++) {
3099 s8d.u32[i] = s8n.u32[i] | s8m.u32[i];
3100 }
3101 }
3102 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
3103 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
3104 // Format(instr, "vandq 'qd, 'qn, 'qm");
3105 for (int i = 0; i < 4; i++) {
3106 s8d.u32[i] = s8n.u32[i] & s8m.u32[i];
3107 }
3108 } else if ((instr->Bits(7, 5) == 11) && (instr->Bit(4) == 0) &&
3109 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 5) == 7) &&
3110 (instr->Bits(16, 4) == 0)) {
3111 // Format(instr, "vmvnq 'qd, 'qm");
3112 for (int i = 0; i < 4; i++) {
3113 s8d.u32[i] = ~s8m.u32[i];
3114 }
3115 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) &&
3116 (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
3117 // Format(instr, "vminqs 'qd, 'qn, 'qm");
3118 for (int i = 0; i < 4; i++) {
3119 s8d.f32[i] = vminf(s8n.f32[i], s8m.f32[i]);
3120 }
3121 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) &&
3122 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
3123 // Format(instr, "vmaxqs 'qd, 'qn, 'qm");
3124 for (int i = 0; i < 4; i++) {
3125 s8d.f32[i] = vmaxf(s8n.f32[i], s8m.f32[i]);
3126 }
3127 } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) &&
3128 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3129 (instr->Bit(7) == 0) && (instr->Bits(16, 4) == 9)) {
3130 // Format(instr, "vabsqs 'qd, 'qm");
3131 for (int i = 0; i < 4; i++) {
3132 s8d.f32[i] = fabsf(s8m.f32[i]);
3133 }
3134 } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) &&
3135 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3136 (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 9)) {
3137 // Format(instr, "vnegqs 'qd, 'qm");
3138 for (int i = 0; i < 4; i++) {
3139 s8d.f32[i] = -s8m.f32[i];
3140 }
3141 } else if ((instr->Bits(7, 5) == 10) && (instr->Bit(4) == 0) &&
3142 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3143 (instr->Bits(16, 4) == 11)) {
3144 // Format(instr, "vrecpeq 'qd, 'qm");
3145 for (int i = 0; i < 4; i++) {
3146 s8d.f32[i] = ReciprocalEstimate(s8m.f32[i]);
3147 }
3148 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 1) &&
3149 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
3150 // Format(instr, "vrecpsq 'qd, 'qn, 'qm");
3151 for (int i = 0; i < 4; i++) {
3152 s8d.f32[i] = ReciprocalStep(s8n.f32[i], s8m.f32[i]);
3153 }
3154 } else if ((instr->Bits(8, 4) == 5) && (instr->Bit(4) == 0) &&
3155 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3156 (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 11)) {
3157 // Format(instr, "vrsqrteqs 'qd, 'qm");
3158 for (int i = 0; i < 4; i++) {
3159 s8d.f32[i] = ReciprocalSqrtEstimate(s8m.f32[i]);
3160 }
3161 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 1) &&
3162 (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
3163 // Format(instr, "vrsqrtsqs 'qd, 'qn, 'qm");
3164 for (int i = 0; i < 4; i++) {
3165 s8d.f32[i] = ReciprocalSqrtStep(s8n.f32[i], s8m.f32[i]);
3166 }
3167 } else if ((instr->Bits(8, 4) == 12) && (instr->Bit(4) == 0) &&
3168 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3169 (instr->Bit(7) == 0)) {
3170 DRegister dm = instr->DmField();
3171 int64_t dm_value = get_dregister_bits(dm);
3172 int32_t imm4 = instr->Bits(16, 4);
3173 int32_t idx;
3174 if ((imm4 & 1) != 0) {
3175 // Format(instr, "vdupb 'qd, 'dm['imm4_vdup]");
3176 int8_t dm_b[8];
3177 memcpy(dm_b, &dm_value, sizeof(dm_b)); // NOLINT
3178 idx = imm4 >> 1;
3179 int8_t val = dm_b[idx];
3180 for (int i = 0; i < 16; i++) {
3181 s8d.i8[i] = val;
3182 }
3183 } else if ((imm4 & 2) != 0) {
3184 // Format(instr, "vduph 'qd, 'dm['imm4_vdup]");
3185 int16_t dm_h[4];
3186 memcpy(dm_h, &dm_value, sizeof(dm_h)); // NOLINT
3187 idx = imm4 >> 2;
3188 int16_t val = dm_h[idx];
3189 for (int i = 0; i < 8; i++) {
3190 s8d.i16[i] = val;
3191 }
3192 } else if ((imm4 & 4) != 0) {
3193 // Format(instr, "vdupw 'qd, 'dm['imm4_vdup]");
3194 int32_t dm_w[2];
3195 memcpy(dm_w, &dm_value, sizeof(dm_w)); // NOLINT
3196 idx = imm4 >> 3;
3197 int32_t val = dm_w[idx];
3198 for (int i = 0; i < 4; i++) {
3199 s8d.u32[i] = val;
3200 }
3201 } else {
3202 UnimplementedInstruction(instr);
3203 }
3204 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 0) &&
3205 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3206 (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 10)) {
3207 // Format(instr, "vzipqw 'qd, 'qm");
3208 get_qregister(qd, &s8d);
3209
3210 // Interleave the elements with the low words in qd, and the high words
3211 // in qm.
3212 simd_value_swap(&s8d, 3, &s8m, 2);
3213 simd_value_swap(&s8d, 3, &s8m, 1);
3214 simd_value_swap(&s8d, 2, &s8m, 0);
3215 simd_value_swap(&s8d, 2, &s8d, 1);
3216
3217 set_qregister(qm, s8m); // Writes both qd and qm.
3218 } else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 1) &&
3219 (instr->Bits(23, 2) == 2)) {
3220 // Format(instr, "vceqq'sz 'qd, 'qn, 'qm");
3221 const int size = instr->Bits(20, 2);
3222 if (size == 0) {
3223 for (int i = 0; i < 16; i++) {
3224 s8d.i8[i] = s8n.i8[i] == s8m.i8[i] ? 0xff : 0;
3225 }
3226 } else if (size == 1) {
3227 for (int i = 0; i < 8; i++) {
3228 s8d.i16[i] = s8n.i16[i] == s8m.i16[i] ? 0xffff : 0;
3229 }
3230 } else if (size == 2) {
3231 for (int i = 0; i < 4; i++) {
3232 s8d.u32[i] = s8n.u32[i] == s8m.u32[i] ? 0xffffffff : 0;
3233 }
3234 } else if (size == 3) {
3235 UnimplementedInstruction(instr);
3236 } else {
3237 UNREACHABLE();
3238 }
3239 } else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) &&
3240 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
3241 // Format(instr, "vceqqs 'qd, 'qn, 'qm");
3242 for (int i = 0; i < 4; i++) {
3243 s8d.u32[i] = s8n.f32[i] == s8m.f32[i] ? 0xffffffff : 0;
3244 }
3245 } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 1) &&
3246 (instr->Bits(23, 2) == 0)) {
3247 // Format(instr, "vcgeq'sz 'qd, 'qn, 'qm");
3248 const int size = instr->Bits(20, 2);
3249 if (size == 0) {
3250 for (int i = 0; i < 16; i++) {
3251 s8d.i8[i] = s8n.i8[i] >= s8m.i8[i] ? 0xff : 0;
3252 }
3253 } else if (size == 1) {
3254 for (int i = 0; i < 8; i++) {
3255 s8d.i16[i] = s8n.i16[i] >= s8m.i16[i] ? 0xffff : 0;
3256 }
3257 } else if (size == 2) {
3258 for (int i = 0; i < 4; i++) {
3259 s8d.u32[i] = s8n.i32[i] >= s8m.i32[i] ? 0xffffffff : 0;
3260 }
3261 } else if (size == 3) {
3262 UnimplementedInstruction(instr);
3263 } else {
3264 UNREACHABLE();
3265 }
3266 } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 1) &&
3267 (instr->Bits(23, 2) == 2)) {
3268 // Format(instr, "vcugeq'sz 'qd, 'qn, 'qm");
3269 const int size = instr->Bits(20, 2);
3270 if (size == 0) {
3271 for (int i = 0; i < 16; i++) {
3272 s8d.i8[i] = s8n.u8[i] >= s8m.u8[i] ? 0xff : 0;
3273 }
3274 } else if (size == 1) {
3275 for (int i = 0; i < 8; i++) {
3276 s8d.i16[i] = s8n.u16[i] >= s8m.u16[i] ? 0xffff : 0;
3277 }
3278 } else if (size == 2) {
3279 for (int i = 0; i < 4; i++) {
3280 s8d.u32[i] = s8n.u32[i] >= s8m.u32[i] ? 0xffffffff : 0;
3281 }
3282 } else if (size == 3) {
3283 UnimplementedInstruction(instr);
3284 } else {
3285 UNREACHABLE();
3286 }
3287 } else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) &&
3288 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 2)) {
3289 // Format(instr, "vcgeqs 'qd, 'qn, 'qm");
3290 for (int i = 0; i < 4; i++) {
3291 s8d.u32[i] = s8n.f32[i] >= s8m.f32[i] ? 0xffffffff : 0;
3292 }
3293 } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 0) &&
3294 (instr->Bits(23, 2) == 0)) {
3295 // Format(instr, "vcgtq'sz 'qd, 'qn, 'qm");
3296 const int size = instr->Bits(20, 2);
3297 if (size == 0) {
3298 for (int i = 0; i < 16; i++) {
3299 s8d.i8[i] = s8n.i8[i] > s8m.i8[i] ? 0xff : 0;
3300 }
3301 } else if (size == 1) {
3302 for (int i = 0; i < 8; i++) {
3303 s8d.i16[i] = s8n.i16[i] > s8m.i16[i] ? 0xffff : 0;
3304 }
3305 } else if (size == 2) {
3306 for (int i = 0; i < 4; i++) {
3307 s8d.u32[i] = s8n.i32[i] > s8m.i32[i] ? 0xffffffff : 0;
3308 }
3309 } else if (size == 3) {
3310 UnimplementedInstruction(instr);
3311 } else {
3312 UNREACHABLE();
3313 }
3314 } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 0) &&
3315 (instr->Bits(23, 2) == 2)) {
3316 // Format(instr, "vcugtq'sz 'qd, 'qn, 'qm");
3317 const int size = instr->Bits(20, 2);
3318 if (size == 0) {
3319 for (int i = 0; i < 16; i++) {
3320 s8d.i8[i] = s8n.u8[i] > s8m.u8[i] ? 0xff : 0;
3321 }
3322 } else if (size == 1) {
3323 for (int i = 0; i < 8; i++) {
3324 s8d.i16[i] = s8n.u16[i] > s8m.u16[i] ? 0xffff : 0;
3325 }
3326 } else if (size == 2) {
3327 for (int i = 0; i < 4; i++) {
3328 s8d.u32[i] = s8n.u32[i] > s8m.u32[i] ? 0xffffffff : 0;
3329 }
3330 } else if (size == 3) {
3331 UnimplementedInstruction(instr);
3332 } else {
3333 UNREACHABLE();
3334 }
3335 } else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) &&
3336 (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 2)) {
3337 // Format(instr, "vcgtqs 'qd, 'qn, 'qm");
3338 for (int i = 0; i < 4; i++) {
3339 s8d.u32[i] = s8n.f32[i] > s8m.f32[i] ? 0xffffffff : 0;
3340 }
3341 } else {
3342 UnimplementedInstruction(instr);
3343 }
3344
3345 set_qregister(qd, s8d);
3346 } else {
3347 // Q == 0, Uses 64-bit D registers.
3348 if ((instr->Bits(23, 2) == 3) && (instr->Bits(20, 2) == 3) &&
3349 (instr->Bits(10, 2) == 2) && (instr->Bit(4) == 0)) {
3350 // Format(instr, "vtbl 'dd, 'dtbllist, 'dm");
3351 DRegister dd = instr->DdField();
3352 DRegister dm = instr->DmField();
3353 int reg_count = instr->Bits(8, 2) + 1;
3354 int start = (instr->Bit(7) << 4) | instr->Bits(16, 4);
3355 int64_t table[4];
3356
3357 for (int i = 0; i < reg_count; i++) {
3358 DRegister d = static_cast<DRegister>(start + i);
3359 table[i] = get_dregister_bits(d);
3360 }
3361 for (int i = reg_count; i < 4; i++) {
3362 table[i] = 0;
3363 }
3364
3365 int64_t dm_value = get_dregister_bits(dm);
3366 int64_t result;
3367 int8_t* dm_bytes = reinterpret_cast<int8_t*>(&dm_value);
3368 int8_t* result_bytes = reinterpret_cast<int8_t*>(&result);
3369 int8_t* table_bytes = reinterpret_cast<int8_t*>(&table[0]);
3370 for (int i = 0; i < 8; i++) {
3371 int idx = dm_bytes[i];
3372 if ((idx >= 0) && (idx < 256)) {
3373 result_bytes[i] = table_bytes[idx];
3374 } else {
3375 result_bytes[i] = 0;
3376 }
3377 }
3378
3379 set_dregister_bits(dd, result);
3380 } else {
3381 UnimplementedInstruction(instr);
3382 }
3383 }
3384}
3385
3386// Executes the current instruction.
3387DART_FORCE_INLINE void Simulator::InstructionDecodeImpl(Instr* instr) {
3388 pc_modified_ = false;
3389 if (instr->ConditionField() == kSpecialCondition) {
3390 if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) {
3391 // Format(instr, "clrex");
3392 ClearExclusive();
3393 } else if (instr->InstructionBits() ==
3394 static_cast<int32_t>(kDataMemoryBarrier)) {
3395 // Format(instr, "dmb ish");
3396 std::atomic_thread_fence(std::memory_order_seq_cst);
3397 } else {
3398 if (instr->IsSIMDDataProcessing()) {
3399 DecodeSIMDDataProcessing(instr);
3400 } else {
3401 UnimplementedInstruction(instr);
3402 }
3403 }
3404 } else if (ConditionallyExecute(instr)) {
3405 switch (instr->TypeField()) {
3406 case 0:
3407 case 1: {
3408 DecodeType01(instr);
3409 break;
3410 }
3411 case 2: {
3412 DecodeType2(instr);
3413 break;
3414 }
3415 case 3: {
3416 DecodeType3(instr);
3417 break;
3418 }
3419 case 4: {
3420 DecodeType4(instr);
3421 break;
3422 }
3423 case 5: {
3424 DecodeType5(instr);
3425 break;
3426 }
3427 case 6: {
3428 DecodeType6(instr);
3429 break;
3430 }
3431 case 7: {
3432 DecodeType7(instr);
3433 break;
3434 }
3435 default: {
3436 // Type field is three bits.
3437 UNREACHABLE();
3438 break;
3439 }
3440 }
3441 }
3442 if (!pc_modified_) {
3443 set_register(PC, reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
3444 }
3445}
3446
3447void Simulator::InstructionDecode(Instr* instr) {
3448 if (IsTracingExecution()) {
3449 THR_Print("%" Pu64 " ", icount_);
3450 const uword start = reinterpret_cast<uword>(instr);
3451 const uword end = start + Instr::kInstrSize;
3452 if (FLAG_support_disassembler) {
3453 Disassembler::Disassemble(start, end);
3454 } else {
3455 THR_Print("Disassembler not supported in this mode.\n");
3456 }
3457 }
3458 InstructionDecodeImpl(instr);
3459}
3460
3461void Simulator::Execute() {
3462 if (LIKELY(FLAG_stop_sim_at == ULLONG_MAX &&
3463 FLAG_trace_sim_after == ULLONG_MAX)) {
3464 ExecuteNoTrace();
3465 } else {
3466 ExecuteTrace();
3467 }
3468}
3469
3470void Simulator::ExecuteNoTrace() {
3471 // Get the PC to simulate. Cannot use the accessor here as we need the
3472 // raw PC value and not the one used as input to arithmetic instructions.
3473 uword program_counter = get_pc();
3474
3475 // Fast version of the dispatch loop without checking whether the simulator
3476 // should be stopping at a particular executed instruction.
3477 while (program_counter != kEndSimulatingPC) {
3478 Instr* instr = reinterpret_cast<Instr*>(program_counter);
3479 icount_++;
3480 InstructionDecodeImpl(instr);
3481 program_counter = get_pc();
3482 }
3483}
3484
3485void Simulator::ExecuteTrace() {
3486 // Get the PC to simulate. Cannot use the accessor here as we need the
3487 // raw PC value and not the one used as input to arithmetic instructions.
3488 uword program_counter = get_pc();
3489
3490 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
3491 // we reach the particular instruction count or address.
3492 while (program_counter != kEndSimulatingPC) {
3493 Instr* instr = reinterpret_cast<Instr*>(program_counter);
3494 icount_++;
3495 if (icount_ == FLAG_stop_sim_at) {
3496 SimulatorDebugger dbg(this);
3497 dbg.Stop(instr, "Instruction count reached");
3498 } else if (reinterpret_cast<uint64_t>(instr) == FLAG_stop_sim_at) {
3499 SimulatorDebugger dbg(this);
3500 dbg.Stop(instr, "Instruction address reached");
3501 } else if (IsIllegalAddress(program_counter)) {
3502 HandleIllegalAccess(program_counter, instr);
3503 } else {
3504 InstructionDecode(instr);
3505 }
3506 program_counter = get_pc();
3507 }
3508}
3509
3510int64_t Simulator::Call(int32_t entry,
3511 int32_t parameter0,
3512 int32_t parameter1,
3513 int32_t parameter2,
3514 int32_t parameter3,
3515 bool fp_return,
3516 bool fp_args) {
3517 // Save the SP register before the call so we can restore it.
3518 int32_t sp_before_call = get_register(SP);
3519
3520 // Setup parameters.
3521 if (fp_args) {
3522 set_sregister(S0, bit_cast<float, int32_t>(parameter0));
3523 set_sregister(S1, bit_cast<float, int32_t>(parameter1));
3524 set_sregister(S2, bit_cast<float, int32_t>(parameter2));
3525 set_sregister(S3, bit_cast<float, int32_t>(parameter3));
3526 } else {
3527 set_register(R0, parameter0);
3528 set_register(R1, parameter1);
3529 set_register(R2, parameter2);
3530 set_register(R3, parameter3);
3531 }
3532
3533 // Make sure the activation frames are properly aligned.
3534 int32_t stack_pointer = sp_before_call;
3535 if (OS::ActivationFrameAlignment() > 1) {
3536 stack_pointer =
3537 Utils::RoundDown(stack_pointer, OS::ActivationFrameAlignment());
3538 }
3539 set_register(SP, stack_pointer);
3540
3541 // Prepare to execute the code at entry.
3542 set_register(PC, entry);
3543 // Put down marker for end of simulation. The simulator will stop simulation
3544 // when the PC reaches this value. By saving the "end simulation" value into
3545 // the LR the simulation stops when returning to this call point.
3546 set_register(LR, kEndSimulatingPC);
3547
3548 // Remember the values of callee-saved registers.
3549 // The code below assumes that r9 is not used as sb (static base) in
3550 // simulator code and therefore is regarded as a callee-saved register.
3551 int32_t r4_val = get_register(R4);
3552 int32_t r5_val = get_register(R5);
3553 int32_t r6_val = get_register(R6);
3554 int32_t r7_val = get_register(R7);
3555 int32_t r8_val = get_register(R8);
3556#if !defined(DART_TARGET_OS_MACOS) && !defined(DART_TARGET_OS_MACOS_IOS)
3557 int32_t r9_val = get_register(R9);
3558#endif
3559 int32_t r10_val = get_register(R10);
3560 int32_t r11_val = get_register(R11);
3561
3562 double d8_val = 0.0;
3563 double d9_val = 0.0;
3564 double d10_val = 0.0;
3565 double d11_val = 0.0;
3566 double d12_val = 0.0;
3567 double d13_val = 0.0;
3568 double d14_val = 0.0;
3569 double d15_val = 0.0;
3570
3571 d8_val = get_dregister(D8);
3572 d9_val = get_dregister(D9);
3573 d10_val = get_dregister(D10);
3574 d11_val = get_dregister(D11);
3575 d12_val = get_dregister(D12);
3576 d13_val = get_dregister(D13);
3577 d14_val = get_dregister(D14);
3578 d15_val = get_dregister(D15);
3579
3580 // Setup the callee-saved registers with a known value. To be able to check
3581 // that they are preserved properly across dart execution.
3582 int32_t callee_saved_value = icount_;
3583 set_register(R4, callee_saved_value);
3584 set_register(R5, callee_saved_value);
3585 set_register(R6, callee_saved_value);
3586 set_register(R7, callee_saved_value);
3587 set_register(R8, callee_saved_value);
3588#if !defined(DART_TARGET_OS_MACOS) && !defined(DART_TARGET_OS_MACOS_IOS)
3589 set_register(R9, callee_saved_value);
3590#endif
3591 set_register(R10, callee_saved_value);
3592 set_register(R11, callee_saved_value);
3593
3594 double callee_saved_dvalue = 0.0;
3595 callee_saved_dvalue = static_cast<double>(icount_);
3596 set_dregister(D8, callee_saved_dvalue);
3597 set_dregister(D9, callee_saved_dvalue);
3598 set_dregister(D10, callee_saved_dvalue);
3599 set_dregister(D11, callee_saved_dvalue);
3600 set_dregister(D12, callee_saved_dvalue);
3601 set_dregister(D13, callee_saved_dvalue);
3602 set_dregister(D14, callee_saved_dvalue);
3603 set_dregister(D15, callee_saved_dvalue);
3604
3605 // Start the simulation
3606 Execute();
3607
3608 // Check that the callee-saved registers have been preserved.
3609 ASSERT(callee_saved_value == get_register(R4));
3610 ASSERT(callee_saved_value == get_register(R5));
3611 ASSERT(callee_saved_value == get_register(R6));
3612 ASSERT(callee_saved_value == get_register(R7));
3613 ASSERT(callee_saved_value == get_register(R8));
3614#if !defined(DART_TARGET_OS_MACOS) && !defined(DART_TARGET_OS_MACOS_IOS)
3615 ASSERT(callee_saved_value == get_register(R9));
3616#endif
3617 ASSERT(callee_saved_value == get_register(R10));
3618 ASSERT(callee_saved_value == get_register(R11));
3619
3620 ASSERT(callee_saved_dvalue == get_dregister(D8));
3621 ASSERT(callee_saved_dvalue == get_dregister(D9));
3622 ASSERT(callee_saved_dvalue == get_dregister(D10));
3623 ASSERT(callee_saved_dvalue == get_dregister(D11));
3624 ASSERT(callee_saved_dvalue == get_dregister(D12));
3625 ASSERT(callee_saved_dvalue == get_dregister(D13));
3626 ASSERT(callee_saved_dvalue == get_dregister(D14));
3627 ASSERT(callee_saved_dvalue == get_dregister(D15));
3628
3629 // Restore callee-saved registers with the original value.
3630 set_register(R4, r4_val);
3631 set_register(R5, r5_val);
3632 set_register(R6, r6_val);
3633 set_register(R7, r7_val);
3634 set_register(R8, r8_val);
3635#if !defined(DART_TARGET_OS_MACOS) && !defined(DART_TARGET_OS_MACOS_IOS)
3636 set_register(R9, r9_val);
3637#endif
3638 set_register(R10, r10_val);
3639 set_register(R11, r11_val);
3640
3641 set_dregister(D8, d8_val);
3642 set_dregister(D9, d9_val);
3643 set_dregister(D10, d10_val);
3644 set_dregister(D11, d11_val);
3645 set_dregister(D12, d12_val);
3646 set_dregister(D13, d13_val);
3647 set_dregister(D14, d14_val);
3648 set_dregister(D15, d15_val);
3649
3650 // Restore the SP register and return R1:R0.
3651 set_register(SP, sp_before_call);
3652 int64_t return_value;
3653 if (fp_return) {
3654 return_value = bit_cast<int64_t, double>(get_dregister(D0));
3655 } else {
3656 return_value = Utils::LowHighTo64Bits(get_register(R0), get_register(R1));
3657 }
3658 return return_value;
3659}
3660
3661void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
3662 // Walk over all setjmp buffers (simulated --> C++ transitions)
3663 // and try to find the setjmp associated with the simulated stack pointer.
3664 SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
3665 while (buf->link() != nullptr && buf->link()->sp() <= sp) {
3666 buf = buf->link();
3667 }
3668 ASSERT(buf != nullptr);
3669
3670 // The C++ caller has not cleaned up the stack memory of C++ frames.
3671 // Prepare for unwinding frames by destroying all the stack resources
3672 // in the previous C++ frames.
3673 StackResource::Unwind(thread);
3674
3675 // Keep the following code in sync with `StubCode::JumpToFrameStub()`.
3676
3677 // Unwind the C++ stack and continue simulation in the target frame.
3678 set_register(PC, static_cast<int32_t>(pc));
3679 set_register(SP, static_cast<int32_t>(sp));
3680 set_register(FP, static_cast<int32_t>(fp));
3681 set_register(THR, reinterpret_cast<uword>(thread));
3682 // Set the tag.
3683 thread->set_vm_tag(VMTag::kDartTagId);
3684 // Clear top exit frame.
3685 thread->set_top_exit_frame_info(0);
3686 // Restore pool pointer.
3687 int32_t code =
3688 *reinterpret_cast<int32_t*>(fp + kPcMarkerSlotFromFp * kWordSize);
3689 int32_t pp = FLAG_precompiled_mode
3690 ? static_cast<int32_t>(thread->global_object_pool())
3691 : *reinterpret_cast<int32_t*>(
3692 (code + Code::object_pool_offset() - kHeapObjectTag));
3693
3694 set_register(CODE_REG, code);
3695 set_register(PP, pp);
3696 if (FLAG_precompiled_mode) {
3697 set_register(DISPATCH_TABLE_REG,
3698 reinterpret_cast<int32_t>(thread->dispatch_table_array()));
3699 }
3700 buf->Longjmp();
3701}
3702
3703} // namespace dart
3704
3705#endif // defined(USING_SIMULATOR)
3706
3707#endif // defined TARGET_ARCH_ARM
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
Definition: DM.cpp:263
static bool ok(int result)
static bool rotate(const SkDCubic &cubic, int zero, int index, SkDCubic &rotPath)
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
SI T load(const P *ptr)
Definition: Transform_inl.h:98
SI F table(const skcms_Curve *curve, F v)
#define UNREACHABLE()
Definition: assert.h:248
#define Z
static IsolateGroup * vm_isolate_group()
Definition: dart.h:69
static void Disassemble(uword start, uword end, DisassemblyFormatter *formatter, const Code &code, const CodeComments *comments=nullptr)
static constexpr int32_t kSimulatorBreakpointInstruction
static constexpr int32_t kNopInstruction
const uint8_t * snapshot_instructions
Definition: isolate.h:194
static IsolateGroup * Current()
Definition: isolate.h:539
IsolateGroupSource * source() const
Definition: isolate.h:286
static DART_NORETURN void Exit(int code)
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static void DebugBreak()
static Object & Handle()
Definition: object.h:407
static void Init()
static Thread * Current()
Definition: thread.h:362
@ kThreadInGenerated
Definition: thread.h:1035
#define LR
Definition: constants_arm.h:32
#define THR_Print(format,...)
Definition: log.h:20
#define kIsolateSnapshotInstructionsAsmSymbol
Definition: dart_api.h:3968
#define kVmSnapshotInstructionsAsmSymbol
Definition: dart_api.h:3965
struct _Dart_NativeArguments * Dart_NativeArguments
Definition: dart_api.h:3019
void(* Dart_NativeFunction)(Dart_NativeArguments arguments)
Definition: dart_api.h:3207
#define UNIMPLEMENTED
#define ASSERT(E)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
double frame
Definition: examples.cpp:31
#define FATAL(error)
glong glong end
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint8_t value
GAsyncResult * result
uint32_t uint32_t * format
uint32_t * target
Dart_NativeFunction function
Definition: fuchsia.cc:51
int argument_count
Definition: fuchsia.cc:52
size_t length
Win32Message message
const GrXPFactory * Get(SkBlendMode mode)
static bool is_signed(const Type &type)
bool Contains(const Container &container, const Value &value)
def link(from_root, to_root)
Definition: dart_pkg.py:44
Definition: dart_vm.cc:33
static int64_t GetValue(Dart_Handle arg)
float ReciprocalSqrtEstimate(float op)
void SetBreakpoint(Dart_NativeArguments args)
const Register THR
const char *const name
const RegList kAbiVolatileCpuRegs
static uint64_t RotateRight(uint64_t value, uint8_t rotate, uint8_t width)
float ReciprocalStep(float op1, float op2)
uintptr_t uword
Definition: globals.h:501
const Register CODE_REG
@ kSpecialCondition
const uint32_t fp
const Register DISPATCH_TABLE_REG
@ kNumberOfCpuRegisters
Definition: constants_arm.h:98
@ kNoRegister
Definition: constants_arm.h:99
constexpr uword kDataMemoryBarrier
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
static constexpr int kPcMarkerSlotFromFp
@ kNoSRegister
@ kNumberOfSRegisters
float ReciprocalSqrtStep(float op1, float op2)
constexpr intptr_t kWordSize
Definition: globals.h:509
const Register PP
@ kNumberOfQRegisters
@ kNumberOfDRegisters
@ kNoDRegister
@ kHeapObjectTag
float ReciprocalEstimate(float op)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
CanvasImage Image
Definition: dart_ui.cc:55
SolidFillVertexShader VS
def Format(template, **parameters)
Definition: emitter.py:13
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition: SkVx.h:706
#define LIKELY(cond)
Definition: globals.h:260
#define FALL_THROUGH
Definition: globals.h:15
#define Px
Definition: globals.h:410
#define Px64
Definition: globals.h:418
#define Pd
Definition: globals.h:408
#define Pu64
Definition: globals.h:417
#define T
Definition: precompiler.cc:65
int32_t width
SeparatedVector2 offset
#define NO_SANITIZE_UNDEFINED(check)
#define ARRAY_SIZE(array)
Definition: globals.h:72
#define OFFSET_OF(type, field)
Definition: globals.h:138