Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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) {
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.
773 ASSERT(2 * kNumberOfDRegisters >= kNumberOfSRegisters);
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 =
880 Redirection::Get(function, call_kind, argument_count);
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 qregisters_[reg].data_[0] = value.data_[0];
941 qregisters_[reg].data_[1] = value.data_[1];
942 qregisters_[reg].data_[2] = value.data_[2];
943 qregisters_[reg].data_[3] = value.data_[3];
944}
945
946void Simulator::get_qregister(QRegister reg, simd_value_t* value) const {
947 ASSERT(TargetCPUFeatures::neon_supported());
948 // TODO(zra): Replace this test with an assert after we support
949 // 16 Q registers.
950 if ((reg >= 0) && (reg < kNumberOfQRegisters)) {
951 *value = qregisters_[reg];
952 }
953}
954
955void Simulator::set_sregister_bits(SRegister reg, int32_t value) {
956 ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
957 sregisters_[reg] = value;
958}
959
960int32_t Simulator::get_sregister_bits(SRegister reg) const {
961 ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
962 return sregisters_[reg];
963}
964
965void Simulator::set_dregister_bits(DRegister reg, int64_t value) {
966 ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
967 dregisters_[reg] = value;
968}
969
970int64_t Simulator::get_dregister_bits(DRegister reg) const {
971 ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
972 return dregisters_[reg];
973}
974
975void Simulator::HandleIllegalAccess(uword addr, Instr* instr) {
976 uword fault_pc = get_pc();
977 // The debugger will not be able to single step past this instruction, but
978 // it will be possible to disassemble the code and inspect registers.
979 char buffer[128];
980 snprintf(buffer, sizeof(buffer),
981 "illegal memory access at 0x%" Px ", pc=0x%" Px "\n", addr,
982 fault_pc);
983 SimulatorDebugger dbg(this);
984 dbg.Stop(instr, buffer);
985 // The debugger will return control in non-interactive mode.
986 FATAL("Cannot continue execution after illegal memory access.");
987}
988
989void Simulator::UnimplementedInstruction(Instr* instr) {
990 char buffer[64];
991 snprintf(buffer, sizeof(buffer), "Unimplemented instruction: pc=%p\n", instr);
992 SimulatorDebugger dbg(this);
993 dbg.Stop(instr, buffer);
994 FATAL("Cannot continue execution after unimplemented instruction.");
995}
996
997DART_FORCE_INLINE intptr_t Simulator::ReadW(uword addr, Instr* instr) {
998 return *reinterpret_cast<intptr_t*>(addr);
999}
1000
1001DART_FORCE_INLINE void Simulator::WriteW(uword addr,
1002 intptr_t value,
1003 Instr* instr) {
1004 *reinterpret_cast<intptr_t*>(addr) = value;
1005}
1006
1007DART_FORCE_INLINE uint16_t Simulator::ReadHU(uword addr, Instr* instr) {
1008 return *reinterpret_cast<uint16_t*>(addr);
1009}
1010
1011DART_FORCE_INLINE int16_t Simulator::ReadH(uword addr, Instr* instr) {
1012 return *reinterpret_cast<int16_t*>(addr);
1013}
1014
1015DART_FORCE_INLINE void Simulator::WriteH(uword addr,
1016 uint16_t value,
1017 Instr* instr) {
1018 *reinterpret_cast<uint16_t*>(addr) = value;
1019}
1020
1021DART_FORCE_INLINE uint8_t Simulator::ReadBU(uword addr) {
1022 return *reinterpret_cast<uint8_t*>(addr);
1023}
1024
1025DART_FORCE_INLINE int8_t Simulator::ReadB(uword addr) {
1026 return *reinterpret_cast<int8_t*>(addr);
1027}
1028
1029DART_FORCE_INLINE void Simulator::WriteB(uword addr, uint8_t value) {
1030 *reinterpret_cast<uint8_t*>(addr) = value;
1031}
1032
1033void Simulator::ClearExclusive() {
1034 exclusive_access_addr_ = 0;
1035 exclusive_access_value_ = 0;
1036}
1037
1038intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) {
1039 exclusive_access_addr_ = addr;
1040 exclusive_access_value_ = ReadW(addr, instr);
1041 return exclusive_access_value_;
1042}
1043
1044intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) {
1045 // In a well-formed code store-exclusive instruction should always follow
1046 // a corresponding load-exclusive instruction with the same address.
1047 ASSERT((exclusive_access_addr_ == 0) || (exclusive_access_addr_ == addr));
1048 if (exclusive_access_addr_ != addr) {
1049 return 1; // Failure.
1050 }
1051
1052 int32_t old_value = static_cast<uint32_t>(exclusive_access_value_);
1053 ClearExclusive();
1054
1055 auto atomic_addr = reinterpret_cast<RelaxedAtomic<int32_t>*>(addr);
1056 if (atomic_addr->compare_exchange_weak(old_value, value)) {
1057 return 0; // Success.
1058 }
1059 return 1; // Failure.
1060}
1061
1062bool Simulator::IsTracingExecution() const {
1063 return icount_ > FLAG_trace_sim_after;
1064}
1065
1066// Unsupported instructions use Format to print an error and stop execution.
1067void Simulator::Format(Instr* instr, const char* format) {
1068 OS::PrintErr("Simulator found unsupported instruction:\n 0x%p: %s\n", instr,
1069 format);
1070 UNIMPLEMENTED();
1071}
1072
1073// Checks if the current instruction should be executed based on its
1074// condition bits.
1075DART_FORCE_INLINE bool Simulator::ConditionallyExecute(Instr* instr) {
1076 switch (instr->ConditionField()) {
1077 case EQ:
1078 return z_flag_;
1079 case NE:
1080 return !z_flag_;
1081 case CS:
1082 return c_flag_;
1083 case CC:
1084 return !c_flag_;
1085 case MI:
1086 return n_flag_;
1087 case PL:
1088 return !n_flag_;
1089 case VS:
1090 return v_flag_;
1091 case VC:
1092 return !v_flag_;
1093 case HI:
1094 return c_flag_ && !z_flag_;
1095 case LS:
1096 return !c_flag_ || z_flag_;
1097 case GE:
1098 return n_flag_ == v_flag_;
1099 case LT:
1100 return n_flag_ != v_flag_;
1101 case GT:
1102 return !z_flag_ && (n_flag_ == v_flag_);
1103 case LE:
1104 return z_flag_ || (n_flag_ != v_flag_);
1105 case AL:
1106 return true;
1107 default:
1108 UNREACHABLE();
1109 }
1110 return false;
1111}
1112
1113// Calculate and set the Negative and Zero flags.
1114DART_FORCE_INLINE void Simulator::SetNZFlags(int32_t val) {
1115 n_flag_ = (val < 0);
1116 z_flag_ = (val == 0);
1117}
1118
1119// Set the Carry flag.
1120DART_FORCE_INLINE void Simulator::SetCFlag(bool val) {
1121 c_flag_ = val;
1122}
1123
1124// Set the oVerflow flag.
1125DART_FORCE_INLINE void Simulator::SetVFlag(bool val) {
1126 v_flag_ = val;
1127}
1128
1129// Calculate C flag value for additions (and subtractions with adjusted args).
1130DART_FORCE_INLINE bool Simulator::CarryFrom(int32_t left,
1131 int32_t right,
1132 int32_t carry) {
1133 uint64_t uleft = static_cast<uint32_t>(left);
1134 uint64_t uright = static_cast<uint32_t>(right);
1135 uint64_t ucarry = static_cast<uint32_t>(carry);
1136 return ((uleft + uright + ucarry) >> 32) != 0;
1137}
1138
1139// Calculate V flag value for additions (and subtractions with adjusted args).
1140DART_FORCE_INLINE bool Simulator::OverflowFrom(int32_t left,
1141 int32_t right,
1142 int32_t carry) {
1143 int64_t result = static_cast<int64_t>(left) + right + carry;
1144 return (result >> 31) != (result >> 32);
1145}
1146
1147// Addressing Mode 1 - Data-processing operands:
1148// Get the value based on the shifter_operand with register.
1149int32_t Simulator::GetShiftRm(Instr* instr, bool* carry_out) {
1150 Shift shift = instr->ShiftField();
1151 int shift_amount = instr->ShiftAmountField();
1152 int32_t result = get_register(instr->RmField());
1153 if (instr->Bit(4) == 0) {
1154 // by immediate
1155 if ((shift == ROR) && (shift_amount == 0)) {
1156 UnimplementedInstruction(instr);
1157 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) {
1158 shift_amount = 32;
1159 }
1160 switch (shift) {
1161 case ASR: {
1162 if (shift_amount == 0) {
1163 if (result < 0) {
1164 result = 0xffffffff;
1165 *carry_out = true;
1166 } else {
1167 result = 0;
1168 *carry_out = false;
1169 }
1170 } else {
1171 result >>= (shift_amount - 1);
1172 *carry_out = (result & 1) == 1;
1173 result >>= 1;
1174 }
1175 break;
1176 }
1177
1178 case LSL: {
1179 if (shift_amount == 0) {
1180 *carry_out = c_flag_;
1181 } else {
1182 result = static_cast<uint32_t>(result) << (shift_amount - 1);
1183 *carry_out = (result < 0);
1184 result = static_cast<uint32_t>(result) << 1;
1185 }
1186 break;
1187 }
1188
1189 case LSR: {
1190 if (shift_amount == 0) {
1191 result = 0;
1192 *carry_out = c_flag_;
1193 } else {
1194 uint32_t uresult = static_cast<uint32_t>(result);
1195 uresult >>= (shift_amount - 1);
1196 *carry_out = (uresult & 1) == 1;
1197 uresult >>= 1;
1198 result = static_cast<int32_t>(uresult);
1199 }
1200 break;
1201 }
1202
1203 case ROR: {
1204 UnimplementedInstruction(instr);
1205 break;
1206 }
1207
1208 default: {
1209 UNREACHABLE();
1210 break;
1211 }
1212 }
1213 } else {
1214 // by register
1215 Register rs = instr->RsField();
1216 shift_amount = get_register(rs) & 0xff;
1217 switch (shift) {
1218 case ASR: {
1219 if (shift_amount == 0) {
1220 *carry_out = c_flag_;
1221 } else if (shift_amount < 32) {
1222 result >>= (shift_amount - 1);
1223 *carry_out = (result & 1) == 1;
1224 result >>= 1;
1225 } else {
1226 ASSERT(shift_amount >= 32);
1227 if (result < 0) {
1228 *carry_out = true;
1229 result = 0xffffffff;
1230 } else {
1231 *carry_out = false;
1232 result = 0;
1233 }
1234 }
1235 break;
1236 }
1237
1238 case LSL: {
1239 if (shift_amount == 0) {
1240 *carry_out = c_flag_;
1241 } else if (shift_amount < 32) {
1242 result = static_cast<uint32_t>(result) << (shift_amount - 1);
1243 *carry_out = (result < 0);
1244 result = static_cast<uint32_t>(result) << 1;
1245 } else if (shift_amount == 32) {
1246 *carry_out = (result & 1) == 1;
1247 result = 0;
1248 } else {
1249 ASSERT(shift_amount > 32);
1250 *carry_out = false;
1251 result = 0;
1252 }
1253 break;
1254 }
1255
1256 case LSR: {
1257 if (shift_amount == 0) {
1258 *carry_out = c_flag_;
1259 } else if (shift_amount < 32) {
1260 uint32_t uresult = static_cast<uint32_t>(result);
1261 uresult >>= (shift_amount - 1);
1262 *carry_out = (uresult & 1) == 1;
1263 uresult >>= 1;
1264 result = static_cast<int32_t>(uresult);
1265 } else if (shift_amount == 32) {
1266 *carry_out = (result < 0);
1267 result = 0;
1268 } else {
1269 *carry_out = false;
1270 result = 0;
1271 }
1272 break;
1273 }
1274
1275 case ROR: {
1276 UnimplementedInstruction(instr);
1277 break;
1278 }
1279
1280 default: {
1281 UNREACHABLE();
1282 break;
1283 }
1284 }
1285 }
1286 return result;
1287}
1288
1289// Addressing Mode 1 - Data-processing operands:
1290// Get the value based on the shifter_operand with immediate.
1291DART_FORCE_INLINE int32_t Simulator::GetImm(Instr* instr, bool* carry_out) {
1292 uint8_t rotate = instr->RotateField() * 2;
1293 int32_t immed8 = instr->Immed8Field();
1294 int32_t imm = Utils::RotateRight(immed8, rotate);
1295 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1296 return imm;
1297}
1298
1299// Addressing Mode 4 - Load and Store Multiple
1300void Simulator::HandleRList(Instr* instr, bool load) {
1301 Register rn = instr->RnField();
1302 int32_t rn_val = get_register(rn);
1303 int rlist = instr->RlistField();
1304 int num_regs = Utils::CountOneBits32(static_cast<uint32_t>(rlist));
1305
1306 uword address = 0;
1307 uword end_address = 0;
1308 switch (instr->PUField()) {
1309 case 0: {
1310 // Print("da");
1311 address = rn_val - (num_regs * 4) + 4;
1312 end_address = rn_val + 4;
1313 rn_val = rn_val - (num_regs * 4);
1314 break;
1315 }
1316 case 1: {
1317 // Print("ia");
1318 address = rn_val;
1319 end_address = rn_val + (num_regs * 4);
1320 rn_val = rn_val + (num_regs * 4);
1321 break;
1322 }
1323 case 2: {
1324 // Print("db");
1325 address = rn_val - (num_regs * 4);
1326 end_address = rn_val;
1327 rn_val = address;
1328 break;
1329 }
1330 case 3: {
1331 // Print("ib");
1332 address = rn_val + 4;
1333 end_address = rn_val + (num_regs * 4) + 4;
1334 rn_val = rn_val + (num_regs * 4);
1335 break;
1336 }
1337 default: {
1338 UNREACHABLE();
1339 break;
1340 }
1341 }
1342 if (IsIllegalAddress(address)) {
1343 HandleIllegalAccess(address, instr);
1344 } else {
1345 if (instr->HasW()) {
1346 set_register(rn, rn_val);
1347 }
1348 int reg = 0;
1349 while (rlist != 0) {
1350 if ((rlist & 1) != 0) {
1351 if (load) {
1352 set_register(static_cast<Register>(reg), ReadW(address, instr));
1353 } else {
1354 WriteW(address, get_register(static_cast<Register>(reg)), instr);
1355 }
1356 address += 4;
1357 }
1358 reg++;
1359 rlist >>= 1;
1360 }
1361 ASSERT(end_address == address);
1362 }
1363}
1364
1365// Calls into the Dart runtime are based on this interface.
1366typedef void (*SimulatorRuntimeCall)(NativeArguments arguments);
1367
1368// Calls to leaf Dart runtime functions are based on this interface.
1369typedef int32_t (*SimulatorLeafRuntimeCall)(int32_t r0,
1370 int32_t r1,
1371 int32_t r2,
1372 int32_t r3,
1373 int32_t r4);
1374
1375// [target] has several different signatures that differ from
1376// SimulatorLeafRuntimeCall. We can call them all from here only because in
1377// IA32's calling convention a function can be called with extra arguments
1378// and the callee will see the first arguments and won't unbalance the stack.
1379NO_SANITIZE_UNDEFINED("function")
1380static int32_t InvokeLeafRuntime(SimulatorLeafRuntimeCall target,
1381 int32_t r0,
1382 int32_t r1,
1383 int32_t r2,
1384 int32_t r3,
1385 int32_t r4) {
1386 return target(r0, r1, r2, r3, r4);
1387}
1388
1389// Calls to leaf float Dart runtime functions are based on this interface.
1390typedef double (*SimulatorLeafFloatRuntimeCall)(double d0, double d1);
1391
1392// [target] has several different signatures that differ from
1393// SimulatorFloatLeafRuntimeCall. We can call them all from here only because
1394// IA32's calling convention a function can be called with extra arguments
1395// and the callee will see the first arguments and won't unbalance the stack.
1396NO_SANITIZE_UNDEFINED("function")
1397static double InvokeFloatLeafRuntime(SimulatorLeafFloatRuntimeCall target,
1398 double d0,
1399 double d1) {
1400 return target(d0, d1);
1401}
1402
1403// Calls to native Dart functions are based on this interface.
1404typedef void (*SimulatorNativeCallWrapper)(Dart_NativeArguments arguments,
1406
1407void Simulator::SupervisorCall(Instr* instr) {
1408 int svc = instr->SvcField();
1409 switch (svc) {
1410 case Instr::kSimulatorRedirectCode: {
1411 SimulatorSetjmpBuffer buffer(this);
1412
1413 if (!setjmp(buffer.buffer_)) {
1414 int32_t saved_lr = get_register(LR);
1415 Redirection* redirection = Redirection::FromSvcInstruction(instr);
1416 uword external = redirection->external_function();
1417 if (IsTracingExecution()) {
1418 THR_Print("Call to host function at 0x%" Pd "\n", external);
1419 }
1420 if (redirection->call_kind() == kRuntimeCall) {
1421 NativeArguments arguments;
1422 ASSERT(sizeof(NativeArguments) == 4 * kWordSize);
1423 arguments.thread_ = reinterpret_cast<Thread*>(get_register(R0));
1424 arguments.argc_tag_ = get_register(R1);
1425 arguments.argv_ = reinterpret_cast<ObjectPtr*>(get_register(R2));
1426 arguments.retval_ = reinterpret_cast<ObjectPtr*>(get_register(R3));
1427 SimulatorRuntimeCall target =
1428 reinterpret_cast<SimulatorRuntimeCall>(external);
1429 target(arguments);
1430 ClobberVolatileRegisters();
1431 } else if (redirection->call_kind() == kLeafRuntimeCall) {
1432 ASSERT((0 <= redirection->argument_count()) &&
1433 (redirection->argument_count() <= 5));
1434 int32_t r0 = get_register(R0);
1435 int32_t r1 = get_register(R1);
1436 int32_t r2 = get_register(R2);
1437 int32_t r3 = get_register(R3);
1438 int32_t r4 = *reinterpret_cast<int32_t*>(get_register(SP));
1439 SimulatorLeafRuntimeCall target =
1440 reinterpret_cast<SimulatorLeafRuntimeCall>(external);
1441 r0 = InvokeLeafRuntime(target, r0, r1, r2, r3, r4);
1442 ClobberVolatileRegisters();
1443 set_register(R0, r0); // Set returned result from function.
1444 } else if (redirection->call_kind() == kLeafFloatRuntimeCall) {
1445 ASSERT((0 <= redirection->argument_count()) &&
1446 (redirection->argument_count() <= 2));
1447 SimulatorLeafFloatRuntimeCall target =
1448 reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external);
1449 if (TargetCPUFeatures::hardfp_supported()) {
1450 // If we're doing "hardfp", the double arguments are already in the
1451 // floating point registers.
1452 double d0 = get_dregister(D0);
1453 double d1 = get_dregister(D1);
1454 d0 = InvokeFloatLeafRuntime(target, d0, d1);
1455 ClobberVolatileRegisters();
1456 set_dregister(D0, d0);
1457 } else {
1458 // If we're not doing "hardfp", we must be doing "soft" or "softfp",
1459 // So take the double arguments from the integer registers.
1460 uint32_t r0 = get_register(R0);
1461 int32_t r1 = get_register(R1);
1462 uint32_t r2 = get_register(R2);
1463 int32_t r3 = get_register(R3);
1464 int64_t a0 = Utils::LowHighTo64Bits(r0, r1);
1465 int64_t a1 = Utils::LowHighTo64Bits(r2, r3);
1466 double d0 = bit_cast<double, int64_t>(a0);
1467 double d1 = bit_cast<double, int64_t>(a1);
1468 d0 = InvokeFloatLeafRuntime(target, d0, d1);
1469 ClobberVolatileRegisters();
1470 a0 = bit_cast<int64_t, double>(d0);
1471 r0 = Utils::Low32Bits(a0);
1472 r1 = Utils::High32Bits(a0);
1473 set_register(R0, r0);
1474 set_register(R1, r1);
1475 }
1476 } else {
1477 ASSERT(redirection->call_kind() == kNativeCallWrapper);
1478 SimulatorNativeCallWrapper wrapper =
1479 reinterpret_cast<SimulatorNativeCallWrapper>(external);
1480 Dart_NativeArguments arguments =
1481 reinterpret_cast<Dart_NativeArguments>(get_register(R0));
1482 Dart_NativeFunction target_func =
1483 reinterpret_cast<Dart_NativeFunction>(get_register(R1));
1484 wrapper(arguments, target_func);
1485 ClobberVolatileRegisters();
1486 }
1487
1488 // Return.
1489 set_pc(saved_lr);
1490 } else {
1491 // Coming via long jump from a throw. Continue to exception handler.
1492 }
1493
1494 break;
1495 }
1496 case Instr::kSimulatorBreakCode: {
1497 SimulatorDebugger dbg(this);
1498 dbg.Stop(instr, "breakpoint");
1499 break;
1500 }
1501 default: {
1502 UNREACHABLE();
1503 break;
1504 }
1505 }
1506}
1507
1508void Simulator::ClobberVolatileRegisters() {
1509 // Clear atomic reservation.
1510 exclusive_access_addr_ = exclusive_access_value_ = 0;
1511
1512 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
1513 if ((kAbiVolatileCpuRegs & (1 << i)) != 0) {
1514 registers_[i] = icount_;
1515 }
1516 }
1517
1518 double zap_dvalue = static_cast<double>(icount_);
1519 for (int i = D0; i <= D7; i++) {
1520 set_dregister(static_cast<DRegister>(i), zap_dvalue);
1521 }
1522 // The above loop also zaps overlapping registers S2-S15.
1523 // Registers D8-D15 (overlapping with S16-S31) are preserved.
1524#if defined(VFPv3_D32)
1525 for (int i = D16; i <= D31; i++) {
1526 set_dregister(static_cast<DRegister>(i), zap_dvalue);
1527 }
1528#endif
1529}
1530
1531// Handle execution based on instruction types.
1532
1533// Instruction types 0 and 1 are both rolled into one function because they
1534// only differ in the handling of the shifter_operand.
1535DART_FORCE_INLINE void Simulator::DecodeType01(Instr* instr) {
1536 if (!instr->IsDataProcessing()) {
1537 // miscellaneous, multiply, sync primitives, extra loads and stores.
1538 if (instr->IsMiscellaneous()) {
1539 switch (instr->Bits(4, 3)) {
1540 case 1: {
1541 if (instr->Bits(21, 2) == 0x3) {
1542 // Format(instr, "clz'cond 'rd, 'rm");
1543 Register rm = instr->RmField();
1544 Register rd = instr->RdField();
1545 int32_t rm_val = get_register(rm);
1546 int32_t rd_val = 0;
1547 if (rm_val != 0) {
1548 while (rm_val > 0) {
1549 rd_val++;
1550 rm_val <<= 1;
1551 }
1552 } else {
1553 rd_val = 32;
1554 }
1555 set_register(rd, rd_val);
1556 } else {
1557 ASSERT(instr->Bits(21, 2) == 0x1);
1558 // Format(instr, "bx'cond 'rm");
1559 Register rm = instr->RmField();
1560 int32_t rm_val = get_register(rm);
1561 set_pc(rm_val);
1562 }
1563 break;
1564 }
1565 case 3: {
1566 ASSERT(instr->Bits(21, 2) == 0x1);
1567 // Format(instr, "blx'cond 'rm");
1568 Register rm = instr->RmField();
1569 int32_t rm_val = get_register(rm);
1570 intptr_t pc = get_pc();
1571 set_register(LR, pc + Instr::kInstrSize);
1572 set_pc(rm_val);
1573 break;
1574 }
1575 case 7: {
1576 if ((instr->Bits(21, 2) == 0x1) && (instr->ConditionField() == AL)) {
1577 // Format(instr, "bkpt #'imm12_4");
1578 SimulatorDebugger dbg(this);
1579 int32_t imm = instr->BkptField();
1580 char buffer[32];
1581 snprintf(buffer, sizeof(buffer), "bkpt #0x%x", imm);
1582 set_pc(get_pc() + Instr::kInstrSize);
1583 dbg.Stop(instr, buffer);
1584 } else {
1585 // Format(instr, "smc'cond");
1586 UnimplementedInstruction(instr);
1587 }
1588 break;
1589 }
1590 default: {
1591 UnimplementedInstruction(instr);
1592 break;
1593 }
1594 }
1595 } else if (instr->IsMultiplyOrSyncPrimitive()) {
1596 if (instr->Bit(24) == 0) {
1597 // multiply instructions.
1598 Register rn = instr->RnField();
1599 Register rd = instr->RdField();
1600 Register rs = instr->RsField();
1601 Register rm = instr->RmField();
1602 uint32_t rm_val = get_register(rm);
1603 uint32_t rs_val = get_register(rs);
1604 uint32_t rd_val = 0;
1605 switch (instr->Bits(21, 3)) {
1606 case 1:
1607 // Registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
1608 // Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd");
1609 case 3: {
1610 // Registers rd, rn, rm, ra are encoded as rn, rm, rs, rd.
1611 // Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd");
1612 rd_val = get_register(rd);
1614 }
1615 case 0: {
1616 // Registers rd, rn, rm are encoded as rn, rm, rs.
1617 // Format(instr, "mul'cond's 'rn, 'rm, 'rs");
1618 uint32_t alu_out = rm_val * rs_val;
1619 if (instr->Bits(21, 3) == 3) { // mls
1620 alu_out = -alu_out;
1621 }
1622 alu_out += rd_val;
1623 set_register(rn, alu_out);
1624 if (instr->HasS()) {
1625 SetNZFlags(alu_out);
1626 }
1627 break;
1628 }
1629 case 4:
1630 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1631 // Format(instr, "umull'cond's 'rd, 'rn, 'rm, 'rs");
1632 case 6: {
1633 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1634 // Format(instr, "smull'cond's 'rd, 'rn, 'rm, 'rs");
1635 int64_t result;
1636 if (instr->Bits(21, 3) == 4) { // umull
1637 uint64_t left_op = static_cast<uint32_t>(rm_val);
1638 uint64_t right_op = static_cast<uint32_t>(rs_val);
1639 result = left_op * right_op; // Unsigned multiplication.
1640 } else { // smull
1641 int64_t left_op = static_cast<int32_t>(rm_val);
1642 int64_t right_op = static_cast<int32_t>(rs_val);
1643 result = left_op * right_op; // Signed multiplication.
1644 }
1645 int32_t hi_res = Utils::High32Bits(result);
1646 int32_t lo_res = Utils::Low32Bits(result);
1647 set_register(rd, lo_res);
1648 set_register(rn, hi_res);
1649 if (instr->HasS()) {
1650 if (lo_res != 0) {
1651 // Collapse bits 0..31 into bit 32 so that 32-bit Z check works.
1652 hi_res |= 1;
1653 }
1654 ASSERT((result == 0) == (hi_res == 0)); // Z bit
1655 ASSERT(((result & (1LL << 63)) != 0) == (hi_res < 0)); // N bit
1656 SetNZFlags(hi_res);
1657 }
1658 break;
1659 }
1660 case 2:
1661 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1662 // Format(instr, "umaal'cond's 'rd, 'rn, 'rm, 'rs");
1664 case 5:
1665 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1666 // Format(instr, "umlal'cond's 'rd, 'rn, 'rm, 'rs");
1668 case 7: {
1669 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs.
1670 // Format(instr, "smlal'cond's 'rd, 'rn, 'rm, 'rs");
1671 int32_t rd_lo_val = get_register(rd);
1672 int32_t rd_hi_val = get_register(rn);
1673 uint32_t accum_lo = static_cast<uint32_t>(rd_lo_val);
1674 int32_t accum_hi = static_cast<int32_t>(rd_hi_val);
1675 int64_t accum = Utils::LowHighTo64Bits(accum_lo, accum_hi);
1676 int64_t result;
1677 if (instr->Bits(21, 3) == 5) { // umlal
1678 uint64_t left_op = static_cast<uint32_t>(rm_val);
1679 uint64_t right_op = static_cast<uint32_t>(rs_val);
1680 result = accum + left_op * right_op; // Unsigned multiplication.
1681 } else if (instr->Bits(21, 3) == 7) { // smlal
1682 int64_t left_op = static_cast<int32_t>(rm_val);
1683 int64_t right_op = static_cast<int32_t>(rs_val);
1684 result = accum + left_op * right_op; // Signed multiplication.
1685 } else {
1686 ASSERT(instr->Bits(21, 3) == 2); // umaal
1687 ASSERT(!instr->HasS());
1688 uint64_t left_op = static_cast<uint32_t>(rm_val);
1689 uint64_t right_op = static_cast<uint32_t>(rs_val);
1690 result = left_op * right_op + // Unsigned multiplication.
1691 static_cast<uint32_t>(rd_lo_val) +
1692 static_cast<uint32_t>(rd_hi_val);
1693 }
1694 int32_t hi_res = Utils::High32Bits(result);
1695 int32_t lo_res = Utils::Low32Bits(result);
1696 set_register(rd, lo_res);
1697 set_register(rn, hi_res);
1698 if (instr->HasS()) {
1699 if (lo_res != 0) {
1700 // Collapse bits 0..31 into bit 32 so that 32-bit Z check works.
1701 hi_res |= 1;
1702 }
1703 ASSERT((result == 0) == (hi_res == 0)); // Z bit
1704 ASSERT(((result & (1LL << 63)) != 0) == (hi_res < 0)); // N bit
1705 SetNZFlags(hi_res);
1706 }
1707 break;
1708 }
1709 default: {
1710 UnimplementedInstruction(instr);
1711 break;
1712 }
1713 }
1714 } else {
1715 // synchronization primitives
1716 Register rd = instr->RdField();
1717 Register rn = instr->RnField();
1718 uword addr = get_register(rn);
1719 switch (instr->Bits(20, 4)) {
1720 case 8: {
1721 // Format(instr, "strex'cond 'rd, 'rm, ['rn]");
1722 if (IsIllegalAddress(addr)) {
1723 HandleIllegalAccess(addr, instr);
1724 } else {
1725 Register rm = instr->RmField();
1726 set_register(rd, WriteExclusiveW(addr, get_register(rm), instr));
1727 }
1728 break;
1729 }
1730 case 9: {
1731 // Format(instr, "ldrex'cond 'rd, ['rn]");
1732 if (IsIllegalAddress(addr)) {
1733 HandleIllegalAccess(addr, instr);
1734 } else {
1735 set_register(rd, ReadExclusiveW(addr, instr));
1736 }
1737 break;
1738 }
1739 default: {
1740 UnimplementedInstruction(instr);
1741 break;
1742 }
1743 }
1744 }
1745 } else if (instr->Bit(25) == 1) {
1746 // 16-bit immediate loads, msr (immediate), and hints
1747 switch (instr->Bits(20, 5)) {
1748 case 16:
1749 case 20: {
1750 uint16_t imm16 = instr->MovwField();
1751 Register rd = instr->RdField();
1752 if (instr->Bit(22) == 0) {
1753 // Format(instr, "movw'cond 'rd, #'imm4_12");
1754 set_register(rd, imm16);
1755 } else {
1756 // Format(instr, "movt'cond 'rd, #'imm4_12");
1757 set_register(rd, (get_register(rd) & 0xffff) | (imm16 << 16));
1758 }
1759 break;
1760 }
1761 case 18: {
1762 if ((instr->Bits(16, 4) == 0) && (instr->Bits(0, 8) == 0)) {
1763 // Format(instr, "nop'cond");
1764 } else {
1765 UnimplementedInstruction(instr);
1766 }
1767 break;
1768 }
1769 default: {
1770 UnimplementedInstruction(instr);
1771 break;
1772 }
1773 }
1774 } else {
1775 // extra load/store instructions
1776 Register rd = instr->RdField();
1777 Register rn = instr->RnField();
1778 int32_t rn_val = get_register(rn);
1779 uword addr = 0;
1780 bool write_back = false;
1781 if (instr->Bit(22) == 0) {
1782 Register rm = instr->RmField();
1783 int32_t rm_val = get_register(rm);
1784 switch (instr->PUField()) {
1785 case 0: {
1786 // Format(instr, "'memop'cond'x 'rd2, ['rn], -'rm");
1787 ASSERT(!instr->HasW());
1788 addr = rn_val;
1789 rn_val -= rm_val;
1790 write_back = true;
1791 break;
1792 }
1793 case 1: {
1794 // Format(instr, "'memop'cond'x 'rd2, ['rn], +'rm");
1795 ASSERT(!instr->HasW());
1796 addr = rn_val;
1797 rn_val += rm_val;
1798 write_back = true;
1799 break;
1800 }
1801 case 2: {
1802 // Format(instr, "'memop'cond'x 'rd2, ['rn, -'rm]'w");
1803 rn_val -= rm_val;
1804 addr = rn_val;
1805 write_back = instr->HasW();
1806 break;
1807 }
1808 case 3: {
1809 // Format(instr, "'memop'cond'x 'rd2, ['rn, +'rm]'w");
1810 rn_val += rm_val;
1811 addr = rn_val;
1812 write_back = instr->HasW();
1813 break;
1814 }
1815 default: {
1816 // The PU field is a 2-bit field.
1817 UNREACHABLE();
1818 break;
1819 }
1820 }
1821 } else {
1822 int32_t imm_val = (instr->ImmedHField() << 4) | instr->ImmedLField();
1823 switch (instr->PUField()) {
1824 case 0: {
1825 // Format(instr, "'memop'cond'x 'rd2, ['rn], #-'off8");
1826 ASSERT(!instr->HasW());
1827 addr = rn_val;
1828 rn_val -= imm_val;
1829 write_back = true;
1830 break;
1831 }
1832 case 1: {
1833 // Format(instr, "'memop'cond'x 'rd2, ['rn], #+'off8");
1834 ASSERT(!instr->HasW());
1835 addr = rn_val;
1836 rn_val += imm_val;
1837 write_back = true;
1838 break;
1839 }
1840 case 2: {
1841 // Format(instr, "'memop'cond'x 'rd2, ['rn, #-'off8]'w");
1842 rn_val -= imm_val;
1843 addr = rn_val;
1844 write_back = instr->HasW();
1845 break;
1846 }
1847 case 3: {
1848 // Format(instr, "'memop'cond'x 'rd2, ['rn, #+'off8]'w");
1849 rn_val += imm_val;
1850 addr = rn_val;
1851 write_back = instr->HasW();
1852 break;
1853 }
1854 default: {
1855 // The PU field is a 2-bit field.
1856 UNREACHABLE();
1857 break;
1858 }
1859 }
1860 }
1861 if (IsIllegalAddress(addr)) {
1862 HandleIllegalAccess(addr, instr);
1863 } else {
1864 if (write_back) {
1865 ASSERT(rd != rn); // Unpredictable.
1866 set_register(rn, rn_val);
1867 }
1868 if (!instr->HasSign()) {
1869 if (instr->HasL()) {
1870 uint16_t val = ReadHU(addr, instr);
1871 set_register(rd, val);
1872 } else {
1873 uint16_t val = get_register(rd);
1874 WriteH(addr, val, instr);
1875 }
1876 } else if (instr->HasL()) {
1877 if (instr->HasH()) {
1878 int16_t val = ReadH(addr, instr);
1879 set_register(rd, val);
1880 } else {
1881 int8_t val = ReadB(addr);
1882 set_register(rd, val);
1883 }
1884 } else if ((rd & 1) == 0) {
1885 Register rd1 = static_cast<Register>(rd | 1);
1886 ASSERT(rd1 < kNumberOfCpuRegisters);
1887 if (instr->HasH()) {
1888 int32_t val_low = get_register(rd);
1889 int32_t val_high = get_register(rd1);
1890 WriteW(addr, val_low, instr);
1891 WriteW(addr + 4, val_high, instr);
1892 } else {
1893 int32_t val_low = ReadW(addr, instr);
1894 int32_t val_high = ReadW(addr + 4, instr);
1895 set_register(rd, val_low);
1896 set_register(rd1, val_high);
1897 }
1898 } else {
1899 UnimplementedInstruction(instr);
1900 }
1901 }
1902 }
1903 } else {
1904 Register rd = instr->RdField();
1905 Register rn = instr->RnField();
1906 uint32_t rn_val = get_register(rn);
1907 uint32_t shifter_operand = 0;
1908 bool shifter_carry_out = 0;
1909 if (instr->TypeField() == 0) {
1910 shifter_operand = GetShiftRm(instr, &shifter_carry_out);
1911 } else {
1912 ASSERT(instr->TypeField() == 1);
1913 shifter_operand = GetImm(instr, &shifter_carry_out);
1914 }
1915 uint32_t carry_in;
1916 uint32_t alu_out;
1917
1918 switch (instr->OpcodeField()) {
1919 case AND: {
1920 // Format(instr, "and'cond's 'rd, 'rn, 'shift_rm");
1921 // Format(instr, "and'cond's 'rd, 'rn, 'imm");
1922 alu_out = rn_val & shifter_operand;
1923 set_register(rd, alu_out);
1924 if (instr->HasS()) {
1925 SetNZFlags(alu_out);
1926 SetCFlag(shifter_carry_out);
1927 }
1928 break;
1929 }
1930
1931 case EOR: {
1932 // Format(instr, "eor'cond's 'rd, 'rn, 'shift_rm");
1933 // Format(instr, "eor'cond's 'rd, 'rn, 'imm");
1934 alu_out = rn_val ^ shifter_operand;
1935 set_register(rd, alu_out);
1936 if (instr->HasS()) {
1937 SetNZFlags(alu_out);
1938 SetCFlag(shifter_carry_out);
1939 }
1940 break;
1941 }
1942
1943 case SUB: {
1944 // Format(instr, "sub'cond's 'rd, 'rn, 'shift_rm");
1945 // Format(instr, "sub'cond's 'rd, 'rn, 'imm");
1946 alu_out = rn_val - shifter_operand;
1947 set_register(rd, alu_out);
1948 if (instr->HasS()) {
1949 SetNZFlags(alu_out);
1950 SetCFlag(CarryFrom(rn_val, ~shifter_operand, 1));
1951 SetVFlag(OverflowFrom(rn_val, ~shifter_operand, 1));
1952 }
1953 break;
1954 }
1955
1956 case RSB: {
1957 // Format(instr, "rsb'cond's 'rd, 'rn, 'shift_rm");
1958 // Format(instr, "rsb'cond's 'rd, 'rn, 'imm");
1959 alu_out = shifter_operand - rn_val;
1960 set_register(rd, alu_out);
1961 if (instr->HasS()) {
1962 SetNZFlags(alu_out);
1963 SetCFlag(CarryFrom(shifter_operand, ~rn_val, 1));
1964 SetVFlag(OverflowFrom(shifter_operand, ~rn_val, 1));
1965 }
1966 break;
1967 }
1968
1969 case ADD: {
1970 // Format(instr, "add'cond's 'rd, 'rn, 'shift_rm");
1971 // Format(instr, "add'cond's 'rd, 'rn, 'imm");
1972 alu_out = rn_val + shifter_operand;
1973 set_register(rd, alu_out);
1974 if (instr->HasS()) {
1975 SetNZFlags(alu_out);
1976 SetCFlag(CarryFrom(rn_val, shifter_operand, 0));
1977 SetVFlag(OverflowFrom(rn_val, shifter_operand, 0));
1978 }
1979 break;
1980 }
1981
1982 case ADC: {
1983 // Format(instr, "adc'cond's 'rd, 'rn, 'shift_rm");
1984 // Format(instr, "adc'cond's 'rd, 'rn, 'imm");
1985 carry_in = c_flag_ ? 1 : 0;
1986 alu_out = rn_val + shifter_operand + carry_in;
1987 set_register(rd, alu_out);
1988 if (instr->HasS()) {
1989 SetNZFlags(alu_out);
1990 SetCFlag(CarryFrom(rn_val, shifter_operand, carry_in));
1991 SetVFlag(OverflowFrom(rn_val, shifter_operand, carry_in));
1992 }
1993 break;
1994 }
1995
1996 case SBC: {
1997 // Format(instr, "sbc'cond's 'rd, 'rn, 'shift_rm");
1998 // Format(instr, "sbc'cond's 'rd, 'rn, 'imm");
1999 carry_in = c_flag_ ? 1 : 0;
2000 alu_out = rn_val + ~shifter_operand + carry_in;
2001 set_register(rd, alu_out);
2002 if (instr->HasS()) {
2003 SetNZFlags(alu_out);
2004 SetCFlag(CarryFrom(rn_val, ~shifter_operand, carry_in));
2005 SetVFlag(OverflowFrom(rn_val, ~shifter_operand, carry_in));
2006 }
2007 break;
2008 }
2009
2010 case RSC: {
2011 // Format(instr, "rsc'cond's 'rd, 'rn, 'shift_rm");
2012 // Format(instr, "rsc'cond's 'rd, 'rn, 'imm");
2013 carry_in = c_flag_ ? 1 : 0;
2014 alu_out = shifter_operand + ~rn_val + carry_in;
2015 set_register(rd, alu_out);
2016 if (instr->HasS()) {
2017 SetNZFlags(alu_out);
2018 SetCFlag(CarryFrom(shifter_operand, ~rn_val, carry_in));
2019 SetVFlag(OverflowFrom(shifter_operand, ~rn_val, carry_in));
2020 }
2021 break;
2022 }
2023
2024 case TST: {
2025 if (instr->HasS()) {
2026 // Format(instr, "tst'cond 'rn, 'shift_rm");
2027 // Format(instr, "tst'cond 'rn, 'imm");
2028 alu_out = rn_val & shifter_operand;
2029 SetNZFlags(alu_out);
2030 SetCFlag(shifter_carry_out);
2031 } else {
2032 UnimplementedInstruction(instr);
2033 }
2034 break;
2035 }
2036
2037 case TEQ: {
2038 if (instr->HasS()) {
2039 // Format(instr, "teq'cond 'rn, 'shift_rm");
2040 // Format(instr, "teq'cond 'rn, 'imm");
2041 alu_out = rn_val ^ shifter_operand;
2042 SetNZFlags(alu_out);
2043 SetCFlag(shifter_carry_out);
2044 } else {
2045 UnimplementedInstruction(instr);
2046 }
2047 break;
2048 }
2049
2050 case CMP: {
2051 if (instr->HasS()) {
2052 // Format(instr, "cmp'cond 'rn, 'shift_rm");
2053 // Format(instr, "cmp'cond 'rn, 'imm");
2054 alu_out = rn_val - shifter_operand;
2055 SetNZFlags(alu_out);
2056 SetCFlag(CarryFrom(rn_val, ~shifter_operand, 1));
2057 SetVFlag(OverflowFrom(rn_val, ~shifter_operand, 1));
2058 } else {
2059 UnimplementedInstruction(instr);
2060 }
2061 break;
2062 }
2063
2064 case CMN: {
2065 if (instr->HasS()) {
2066 // Format(instr, "cmn'cond 'rn, 'shift_rm");
2067 // Format(instr, "cmn'cond 'rn, 'imm");
2068 alu_out = rn_val + shifter_operand;
2069 SetNZFlags(alu_out);
2070 SetCFlag(CarryFrom(rn_val, shifter_operand, 0));
2071 SetVFlag(OverflowFrom(rn_val, shifter_operand, 0));
2072 } else {
2073 UnimplementedInstruction(instr);
2074 }
2075 break;
2076 }
2077
2078 case ORR: {
2079 // Format(instr, "orr'cond's 'rd, 'rn, 'shift_rm");
2080 // Format(instr, "orr'cond's 'rd, 'rn, 'imm");
2081 alu_out = rn_val | shifter_operand;
2082 set_register(rd, alu_out);
2083 if (instr->HasS()) {
2084 SetNZFlags(alu_out);
2085 SetCFlag(shifter_carry_out);
2086 }
2087 break;
2088 }
2089
2090 case MOV: {
2091 // Format(instr, "mov'cond's 'rd, 'shift_rm");
2092 // Format(instr, "mov'cond's 'rd, 'imm");
2093 alu_out = shifter_operand;
2094 set_register(rd, alu_out);
2095 if (instr->HasS()) {
2096 SetNZFlags(alu_out);
2097 SetCFlag(shifter_carry_out);
2098 }
2099 break;
2100 }
2101
2102 case BIC: {
2103 // Format(instr, "bic'cond's 'rd, 'rn, 'shift_rm");
2104 // Format(instr, "bic'cond's 'rd, 'rn, 'imm");
2105 alu_out = rn_val & ~shifter_operand;
2106 set_register(rd, alu_out);
2107 if (instr->HasS()) {
2108 SetNZFlags(alu_out);
2109 SetCFlag(shifter_carry_out);
2110 }
2111 break;
2112 }
2113
2114 case MVN: {
2115 // Format(instr, "mvn'cond's 'rd, 'shift_rm");
2116 // Format(instr, "mvn'cond's 'rd, 'imm");
2117 alu_out = ~shifter_operand;
2118 set_register(rd, alu_out);
2119 if (instr->HasS()) {
2120 SetNZFlags(alu_out);
2121 SetCFlag(shifter_carry_out);
2122 }
2123 break;
2124 }
2125
2126 default: {
2127 UNREACHABLE();
2128 break;
2129 }
2130 }
2131 }
2132}
2133
2134DART_FORCE_INLINE void Simulator::DecodeType2(Instr* instr) {
2135 Register rd = instr->RdField();
2136 Register rn = instr->RnField();
2137 int32_t rn_val = get_register(rn);
2138 int32_t im_val = instr->Offset12Field();
2139 uword addr = 0;
2140 bool write_back = false;
2141 switch (instr->PUField()) {
2142 case 0: {
2143 // Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12");
2144 ASSERT(!instr->HasW());
2145 addr = rn_val;
2146 rn_val -= im_val;
2147 write_back = true;
2148 break;
2149 }
2150 case 1: {
2151 // Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12");
2152 ASSERT(!instr->HasW());
2153 addr = rn_val;
2154 rn_val += im_val;
2155 write_back = true;
2156 break;
2157 }
2158 case 2: {
2159 // Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w");
2160 rn_val -= im_val;
2161 addr = rn_val;
2162 write_back = instr->HasW();
2163 break;
2164 }
2165 case 3: {
2166 // Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w");
2167 rn_val += im_val;
2168 addr = rn_val;
2169 write_back = instr->HasW();
2170 break;
2171 }
2172 default: {
2173 UNREACHABLE();
2174 break;
2175 }
2176 }
2177 if (IsIllegalAddress(addr)) {
2178 HandleIllegalAccess(addr, instr);
2179 } else {
2180 if (write_back) {
2181 ASSERT(rd != rn); // Unpredictable.
2182 set_register(rn, rn_val);
2183 }
2184 if (instr->HasB()) {
2185 if (instr->HasL()) {
2186 unsigned char val = ReadBU(addr);
2187 set_register(rd, val);
2188 } else {
2189 unsigned char val = get_register(rd);
2190 WriteB(addr, val);
2191 }
2192 } else {
2193 if (instr->HasL()) {
2194 set_register(rd, ReadW(addr, instr));
2195 } else {
2196 WriteW(addr, get_register(rd), instr);
2197 }
2198 }
2199 }
2200}
2201
2202void Simulator::DoDivision(Instr* instr) {
2203 const Register rd = instr->DivRdField();
2204 const Register rn = instr->DivRnField();
2205 const Register rm = instr->DivRmField();
2206
2207 if (!TargetCPUFeatures::integer_division_supported()) {
2208 UnimplementedInstruction(instr);
2209 return;
2210 }
2211
2212 // ARMv7-a does not trap on divide-by-zero. The destination register is just
2213 // set to 0.
2214 if (get_register(rm) == 0) {
2215 set_register(rd, 0);
2216 return;
2217 }
2218
2219 if (instr->IsDivUnsigned()) {
2220 // unsigned division.
2221 uint32_t rn_val = static_cast<uint32_t>(get_register(rn));
2222 uint32_t rm_val = static_cast<uint32_t>(get_register(rm));
2223 uint32_t result = rn_val / rm_val;
2224 set_register(rd, static_cast<int32_t>(result));
2225 } else {
2226 // signed division.
2227 int32_t rn_val = get_register(rn);
2228 int32_t rm_val = get_register(rm);
2229 int32_t result;
2230 if ((rn_val == static_cast<int32_t>(0x80000000)) &&
2231 (rm_val == static_cast<int32_t>(0xffffffff))) {
2232 result = 0x80000000;
2233 } else {
2234 result = rn_val / rm_val;
2235 }
2236 set_register(rd, result);
2237 }
2238}
2239
2240void Simulator::DecodeType3(Instr* instr) {
2241 if (instr->IsMedia()) {
2242 if (instr->IsDivision()) {
2243 DoDivision(instr);
2244 return;
2245 } else if (instr->IsRbit()) {
2246 // Format(instr, "rbit'cond 'rd, 'rm");
2247 Register rm = instr->RmField();
2248 Register rd = instr->RdField();
2249 set_register(rd, Utils::ReverseBits32(get_register(rm)));
2250 return;
2251 } else if (instr->IsBitFieldExtract()) {
2252 // Format(instr, "sbfx'cond 'rd, 'rn, 'lsb, 'width")
2253 const Register rd = instr->RdField();
2254 const Register rn = instr->BitFieldExtractRnField();
2255 const uint8_t width = instr->BitFieldExtractWidthField() + 1;
2256 const uint8_t lsb = instr->BitFieldExtractLSBField();
2257 const int32_t rn_val = get_register(rn);
2258 const uint32_t extracted_bitfield =
2259 ((rn_val >> lsb) & Utils::NBitMask(width));
2260 const uint32_t sign_extension =
2261 (instr->IsBitFieldExtractSignExtended() &&
2262 Utils::TestBit(extracted_bitfield, width - 1))
2263 ? ~Utils::NBitMask(width)
2264 : 0;
2265 set_register(rd, sign_extension | extracted_bitfield);
2266 } else {
2267 UNREACHABLE();
2268 }
2269 return;
2270 }
2271 Register rd = instr->RdField();
2272 Register rn = instr->RnField();
2273 int32_t rn_val = get_register(rn);
2274 bool shifter_carry_out = 0;
2275 int32_t shifter_operand = GetShiftRm(instr, &shifter_carry_out);
2276 uword addr = 0;
2277 bool write_back = false;
2278 switch (instr->PUField()) {
2279 case 0: {
2280 // Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm");
2281 ASSERT(!instr->HasW());
2282 addr = rn_val;
2283 rn_val -= shifter_operand;
2284 write_back = true;
2285 break;
2286 }
2287 case 1: {
2288 // Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm");
2289 ASSERT(!instr->HasW());
2290 addr = rn_val;
2291 rn_val += shifter_operand;
2292 write_back = true;
2293 break;
2294 }
2295 case 2: {
2296 // Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w");
2297 rn_val -= shifter_operand;
2298 addr = rn_val;
2299 write_back = instr->HasW();
2300 break;
2301 }
2302 case 3: {
2303 // Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w");
2304 rn_val += shifter_operand;
2305 addr = rn_val;
2306 write_back = instr->HasW();
2307 break;
2308 }
2309 default: {
2310 UNREACHABLE();
2311 break;
2312 }
2313 }
2314 if (IsIllegalAddress(addr)) {
2315 HandleIllegalAccess(addr, instr);
2316 } else {
2317 if (write_back) {
2318 ASSERT(rd != rn); // Unpredictable.
2319 set_register(rn, rn_val);
2320 }
2321 if (instr->HasB()) {
2322 if (instr->HasL()) {
2323 unsigned char val = ReadBU(addr);
2324 set_register(rd, val);
2325 } else {
2326 unsigned char val = get_register(rd);
2327 WriteB(addr, val);
2328 }
2329 } else {
2330 if (instr->HasL()) {
2331 set_register(rd, ReadW(addr, instr));
2332 } else {
2333 WriteW(addr, get_register(rd), instr);
2334 }
2335 }
2336 }
2337}
2338
2339void Simulator::DecodeType4(Instr* instr) {
2340 ASSERT(instr->Bit(22) == 0); // only allowed to be set in privileged mode
2341 if (instr->HasL()) {
2342 // Format(instr, "ldm'cond'pu 'rn'w, 'rlist");
2343 HandleRList(instr, true);
2344 } else {
2345 // Format(instr, "stm'cond'pu 'rn'w, 'rlist");
2346 HandleRList(instr, false);
2347 }
2348}
2349
2350void Simulator::DecodeType5(Instr* instr) {
2351 // Format(instr, "b'l'cond 'target");
2352 uint32_t off = (static_cast<uint32_t>(instr->SImmed24Field()) << 2) + 8;
2353 uint32_t pc = get_pc();
2354 if (instr->HasLink()) {
2355 set_register(LR, pc + Instr::kInstrSize);
2356 }
2357 set_pc(pc + off);
2358}
2359
2360void Simulator::DecodeType6(Instr* instr) {
2361 if (instr->IsVFPDoubleTransfer()) {
2362 Register rd = instr->RdField();
2363 Register rn = instr->RnField();
2364 if (instr->Bit(8) == 0) {
2365 SRegister sm = instr->SmField();
2366 SRegister sm1 = static_cast<SRegister>(sm + 1);
2367 ASSERT(sm1 < kNumberOfSRegisters);
2368 if (instr->Bit(20) == 1) {
2369 // Format(instr, "vmovrrs'cond 'rd, 'rn, {'sm', 'sm1}");
2370 set_register(rd, get_sregister_bits(sm));
2371 set_register(rn, get_sregister_bits(sm1));
2372 } else {
2373 // Format(instr, "vmovsrr'cond {'sm, 'sm1}, 'rd', 'rn");
2374 set_sregister_bits(sm, get_register(rd));
2375 set_sregister_bits(sm1, get_register(rn));
2376 }
2377 } else {
2378 DRegister dm = instr->DmField();
2379 if (instr->Bit(20) == 1) {
2380 // Format(instr, "vmovrrd'cond 'rd, 'rn, 'dm");
2381 int64_t dm_val = get_dregister_bits(dm);
2382 set_register(rd, Utils::Low32Bits(dm_val));
2383 set_register(rn, Utils::High32Bits(dm_val));
2384 } else {
2385 // Format(instr, "vmovdrr'cond 'dm, 'rd, 'rn");
2386 int64_t dm_val =
2387 Utils::LowHighTo64Bits(get_register(rd), get_register(rn));
2388 set_dregister_bits(dm, dm_val);
2389 }
2390 }
2391 } else if (instr->IsVFPLoadStore()) {
2392 Register rn = instr->RnField();
2393 int32_t addr = get_register(rn);
2394 int32_t imm_val = instr->Bits(0, 8) << 2;
2395 if (instr->Bit(23) == 1) {
2396 addr += imm_val;
2397 } else {
2398 addr -= imm_val;
2399 }
2400 if (IsIllegalAddress(addr)) {
2401 HandleIllegalAccess(addr, instr);
2402 } else {
2403 if (instr->Bit(8) == 0) {
2404 SRegister sd = instr->SdField();
2405 if (instr->Bit(20) == 1) { // vldrs
2406 // Format(instr, "vldrs'cond 'sd, ['rn, #+'off10]");
2407 // Format(instr, "vldrs'cond 'sd, ['rn, #-'off10]");
2408 set_sregister_bits(sd, ReadW(addr, instr));
2409 } else { // vstrs
2410 // Format(instr, "vstrs'cond 'sd, ['rn, #+'off10]");
2411 // Format(instr, "vstrs'cond 'sd, ['rn, #-'off10]");
2412 WriteW(addr, get_sregister_bits(sd), instr);
2413 }
2414 } else {
2415 DRegister dd = instr->DdField();
2416 if (instr->Bit(20) == 1) { // vldrd
2417 // Format(instr, "vldrd'cond 'dd, ['rn, #+'off10]");
2418 // Format(instr, "vldrd'cond 'dd, ['rn, #-'off10]");
2419 int64_t dd_val = Utils::LowHighTo64Bits(ReadW(addr, instr),
2420 ReadW(addr + 4, instr));
2421 set_dregister_bits(dd, dd_val);
2422 } else { // vstrd
2423 // Format(instr, "vstrd'cond 'dd, ['rn, #+'off10]");
2424 // Format(instr, "vstrd'cond 'dd, ['rn, #-'off10]");
2425 int64_t dd_val = get_dregister_bits(dd);
2426 WriteW(addr, Utils::Low32Bits(dd_val), instr);
2427 WriteW(addr + 4, Utils::High32Bits(dd_val), instr);
2428 }
2429 }
2430 }
2431 } else if (instr->IsVFPMultipleLoadStore()) {
2432 Register rn = instr->RnField();
2433 int32_t addr = get_register(rn);
2434 int32_t imm_val = instr->Bits(0, 8);
2435 if (instr->Bit(23) == 0) {
2436 addr -= (imm_val << 2);
2437 }
2438 if (instr->HasW()) {
2439 if (instr->Bit(23) == 1) {
2440 set_register(rn, addr + (imm_val << 2));
2441 } else {
2442 set_register(rn, addr); // already subtracted from addr
2443 }
2444 }
2445 if (IsIllegalAddress(addr)) {
2446 HandleIllegalAccess(addr, instr);
2447 } else {
2448 if (instr->Bit(8) == 0) {
2449 int32_t regs_cnt = imm_val;
2450 int32_t start = instr->Bit(22) | (instr->Bits(12, 4) << 1);
2451 for (int i = start; i < start + regs_cnt; i++) {
2452 SRegister sd = static_cast<SRegister>(i);
2453 if (instr->Bit(20) == 1) {
2454 // Format(instr, "vldms'cond'pu 'rn'w, 'slist");
2455 set_sregister_bits(sd, ReadW(addr, instr));
2456 } else {
2457 // Format(instr, "vstms'cond'pu 'rn'w, 'slist");
2458 WriteW(addr, get_sregister_bits(sd), instr);
2459 }
2460 addr += 4;
2461 }
2462 } else {
2463 int32_t regs_cnt = imm_val >> 1;
2464 int32_t start = (instr->Bit(22) << 4) | instr->Bits(12, 4);
2465 if ((regs_cnt <= 16) && (start + regs_cnt <= kNumberOfDRegisters)) {
2466 for (int i = start; i < start + regs_cnt; i++) {
2467 DRegister dd = static_cast<DRegister>(i);
2468 if (instr->Bit(20) == 1) {
2469 // Format(instr, "vldmd'cond'pu 'rn'w, 'dlist");
2470 int64_t dd_val = Utils::LowHighTo64Bits(ReadW(addr, instr),
2471 ReadW(addr + 4, instr));
2472 set_dregister_bits(dd, dd_val);
2473 } else {
2474 // Format(instr, "vstmd'cond'pu 'rn'w, 'dlist");
2475 int64_t dd_val = get_dregister_bits(dd);
2476 WriteW(addr, Utils::Low32Bits(dd_val), instr);
2477 WriteW(addr + 4, Utils::High32Bits(dd_val), instr);
2478 }
2479 addr += 8;
2480 }
2481 } else {
2482 UnimplementedInstruction(instr);
2483 }
2484 }
2485 }
2486 } else {
2487 UnimplementedInstruction(instr);
2488 }
2489}
2490
2491void Simulator::DecodeType7(Instr* instr) {
2492 if (instr->Bit(24) == 1) {
2493 // Format(instr, "svc #'svc");
2494 SupervisorCall(instr);
2495 } else if (instr->IsVFPDataProcessingOrSingleTransfer()) {
2496 if (instr->Bit(4) == 0) {
2497 // VFP Data Processing
2498 SRegister sd;
2499 SRegister sn;
2500 SRegister sm;
2501 DRegister dd;
2502 DRegister dn;
2503 DRegister dm;
2504 if (instr->Bit(8) == 0) {
2505 sd = instr->SdField();
2506 sn = instr->SnField();
2507 sm = instr->SmField();
2508 dd = kNoDRegister;
2509 dn = kNoDRegister;
2510 dm = kNoDRegister;
2511 } else {
2512 sd = kNoSRegister;
2513 sn = kNoSRegister;
2514 sm = kNoSRegister;
2515 dd = instr->DdField();
2516 dn = instr->DnField();
2517 dm = instr->DmField();
2518 }
2519 switch (instr->Bits(20, 4) & 0xb) {
2520 case 1: // vnmla, vnmls, vnmul
2521 default: {
2522 UnimplementedInstruction(instr);
2523 break;
2524 }
2525 case 0: { // vmla, vmls floating-point
2526 if (instr->Bit(8) == 0) {
2527 float addend = get_sregister(sn) * get_sregister(sm);
2528 float sd_val = get_sregister(sd);
2529 if (instr->Bit(6) == 0) {
2530 // Format(instr, "vmlas'cond 'sd, 'sn, 'sm");
2531 } else {
2532 // Format(instr, "vmlss'cond 'sd, 'sn, 'sm");
2533 addend = -addend;
2534 }
2535 set_sregister(sd, sd_val + addend);
2536 } else {
2537 double addend = get_dregister(dn) * get_dregister(dm);
2538 double dd_val = get_dregister(dd);
2539 if (instr->Bit(6) == 0) {
2540 // Format(instr, "vmlad'cond 'dd, 'dn, 'dm");
2541 } else {
2542 // Format(instr, "vmlsd'cond 'dd, 'dn, 'dm");
2543 addend = -addend;
2544 }
2545 set_dregister(dd, dd_val + addend);
2546 }
2547 break;
2548 }
2549 case 2: { // vmul
2550 if (instr->Bit(8) == 0) {
2551 // Format(instr, "vmuls'cond 'sd, 'sn, 'sm");
2552 set_sregister(sd, get_sregister(sn) * get_sregister(sm));
2553 } else {
2554 // Format(instr, "vmuld'cond 'dd, 'dn, 'dm");
2555 set_dregister(dd, get_dregister(dn) * get_dregister(dm));
2556 }
2557 break;
2558 }
2559 case 8: { // vdiv
2560 if (instr->Bit(8) == 0) {
2561 // Format(instr, "vdivs'cond 'sd, 'sn, 'sm");
2562 set_sregister(sd, get_sregister(sn) / get_sregister(sm));
2563 } else {
2564 // Format(instr, "vdivd'cond 'dd, 'dn, 'dm");
2565 set_dregister(dd, get_dregister(dn) / get_dregister(dm));
2566 }
2567 break;
2568 }
2569 case 3: { // vadd, vsub floating-point
2570 if (instr->Bit(8) == 0) {
2571 if (instr->Bit(6) == 0) {
2572 // Format(instr, "vadds'cond 'sd, 'sn, 'sm");
2573 set_sregister(sd, get_sregister(sn) + get_sregister(sm));
2574 } else {
2575 // Format(instr, "vsubs'cond 'sd, 'sn, 'sm");
2576 set_sregister(sd, get_sregister(sn) - get_sregister(sm));
2577 }
2578 } else {
2579 if (instr->Bit(6) == 0) {
2580 // Format(instr, "vaddd'cond 'dd, 'dn, 'dm");
2581 set_dregister(dd, get_dregister(dn) + get_dregister(dm));
2582 } else {
2583 // Format(instr, "vsubd'cond 'dd, 'dn, 'dm");
2584 set_dregister(dd, get_dregister(dn) - get_dregister(dm));
2585 }
2586 }
2587 break;
2588 }
2589 case 0xb: { // Other VFP data-processing instructions
2590 if (instr->Bit(6) == 0) { // vmov immediate
2591 if (instr->Bit(8) == 0) {
2592 // Format(instr, "vmovs'cond 'sd, #'immf");
2593 set_sregister(sd, instr->ImmFloatField());
2594 } else {
2595 // Format(instr, "vmovd'cond 'dd, #'immd");
2596 set_dregister(dd, instr->ImmDoubleField());
2597 }
2598 break;
2599 }
2600 switch (instr->Bits(16, 4)) {
2601 case 0: { // vmov immediate, vmov register, vabs
2602 switch (instr->Bits(6, 2)) {
2603 case 1: { // vmov register
2604 if (instr->Bit(8) == 0) {
2605 // Format(instr, "vmovs'cond 'sd, 'sm");
2606 set_sregister(sd, get_sregister(sm));
2607 } else {
2608 // Format(instr, "vmovd'cond 'dd, 'dm");
2609 set_dregister(dd, get_dregister(dm));
2610 }
2611 break;
2612 }
2613 case 3: { // vabs
2614 if (instr->Bit(8) == 0) {
2615 // Format(instr, "vabss'cond 'sd, 'sm");
2616 set_sregister(sd, fabsf(get_sregister(sm)));
2617 } else {
2618 // Format(instr, "vabsd'cond 'dd, 'dm");
2619 set_dregister(dd, fabs(get_dregister(dm)));
2620 }
2621 break;
2622 }
2623 default: {
2624 UnimplementedInstruction(instr);
2625 break;
2626 }
2627 }
2628 break;
2629 }
2630 case 1: { // vneg, vsqrt
2631 switch (instr->Bits(6, 2)) {
2632 case 1: { // vneg
2633 if (instr->Bit(8) == 0) {
2634 // Format(instr, "vnegs'cond 'sd, 'sm");
2635 set_sregister(sd, -get_sregister(sm));
2636 } else {
2637 // Format(instr, "vnegd'cond 'dd, 'dm");
2638 set_dregister(dd, -get_dregister(dm));
2639 }
2640 break;
2641 }
2642 case 3: { // vsqrt
2643 if (instr->Bit(8) == 0) {
2644 // Format(instr, "vsqrts'cond 'sd, 'sm");
2645 set_sregister(sd, sqrtf(get_sregister(sm)));
2646 } else {
2647 // Format(instr, "vsqrtd'cond 'dd, 'dm");
2648 set_dregister(dd, sqrt(get_dregister(dm)));
2649 }
2650 break;
2651 }
2652 default: {
2653 UnimplementedInstruction(instr);
2654 break;
2655 }
2656 }
2657 break;
2658 }
2659 case 4: // vcmp, vcmpe
2660 case 5: { // vcmp #0.0, vcmpe #0.0
2661 if (instr->Bit(7) == 1) { // vcmpe
2662 UnimplementedInstruction(instr);
2663 } else {
2664 fp_n_flag_ = false;
2665 fp_z_flag_ = false;
2666 fp_c_flag_ = false;
2667 fp_v_flag_ = false;
2668 if (instr->Bit(8) == 0) { // vcmps
2669 float sd_val = get_sregister(sd);
2670 float sm_val;
2671 if (instr->Bit(16) == 0) {
2672 // Format(instr, "vcmps'cond 'sd, 'sm");
2673 sm_val = get_sregister(sm);
2674 } else {
2675 // Format(instr, "vcmps'cond 'sd, #0.0");
2676 sm_val = 0.0f;
2677 }
2678 if (isnan(sd_val) || isnan(sm_val)) {
2679 fp_c_flag_ = true;
2680 fp_v_flag_ = true;
2681 } else if (sd_val == sm_val) {
2682 fp_z_flag_ = true;
2683 fp_c_flag_ = true;
2684 } else if (sd_val < sm_val) {
2685 fp_n_flag_ = true;
2686 } else {
2687 fp_c_flag_ = true;
2688 }
2689 } else { // vcmpd
2690 double dd_val = get_dregister(dd);
2691 double dm_val;
2692 if (instr->Bit(16) == 0) {
2693 // Format(instr, "vcmpd'cond 'dd, 'dm");
2694 dm_val = get_dregister(dm);
2695 } else {
2696 // Format(instr, "vcmpd'cond 'dd, #0.0");
2697 dm_val = 0.0;
2698 }
2699 if (isnan(dd_val) || isnan(dm_val)) {
2700 fp_c_flag_ = true;
2701 fp_v_flag_ = true;
2702 } else if (dd_val == dm_val) {
2703 fp_z_flag_ = true;
2704 fp_c_flag_ = true;
2705 } else if (dd_val < dm_val) {
2706 fp_n_flag_ = true;
2707 } else {
2708 fp_c_flag_ = true;
2709 }
2710 }
2711 }
2712 break;
2713 }
2714 case 7: { // vcvt between double-precision and single-precision
2715 if (instr->Bit(8) == 0) {
2716 // Format(instr, "vcvtds'cond 'dd, 'sm");
2717 dd = instr->DdField();
2718 set_dregister(dd, static_cast<double>(get_sregister(sm)));
2719 } else {
2720 // Format(instr, "vcvtsd'cond 'sd, 'dm");
2721 sd = instr->SdField();
2722 set_sregister(sd, static_cast<float>(get_dregister(dm)));
2723 }
2724 break;
2725 }
2726 case 8: { // vcvt, vcvtr between floating-point and integer
2727 sm = instr->SmField();
2728 int32_t sm_int = get_sregister_bits(sm);
2729 uint32_t ud_val = 0;
2730 int32_t id_val = 0;
2731 if (instr->Bit(7) == 0) { // vcvtsu, vcvtdu
2732 ud_val = static_cast<uint32_t>(sm_int);
2733 } else { // vcvtsi, vcvtdi
2734 id_val = sm_int;
2735 }
2736 if (instr->Bit(8) == 0) {
2737 float sd_val;
2738 if (instr->Bit(7) == 0) {
2739 // Format(instr, "vcvtsu'cond 'sd, 'sm");
2740 sd_val = static_cast<float>(ud_val);
2741 } else {
2742 // Format(instr, "vcvtsi'cond 'sd, 'sm");
2743 sd_val = static_cast<float>(id_val);
2744 }
2745 set_sregister(sd, sd_val);
2746 } else {
2747 double dd_val;
2748 if (instr->Bit(7) == 0) {
2749 // Format(instr, "vcvtdu'cond 'dd, 'sm");
2750 dd_val = static_cast<double>(ud_val);
2751 } else {
2752 // Format(instr, "vcvtdi'cond 'dd, 'sm");
2753 dd_val = static_cast<double>(id_val);
2754 }
2755 set_dregister(dd, dd_val);
2756 }
2757 break;
2758 }
2759 case 12:
2760 case 13: { // vcvt, vcvtr between floating-point and integer
2761 // We do not need to record exceptions in the FPSCR cumulative
2762 // flags, because we do not use them.
2763 if (instr->Bit(7) == 0) {
2764 // We only support round-to-zero mode
2765 UnimplementedInstruction(instr);
2766 break;
2767 }
2768 int32_t id_val = 0;
2769 uint32_t ud_val = 0;
2770 if (instr->Bit(8) == 0) {
2771 float sm_val = get_sregister(sm);
2772 if (instr->Bit(16) == 0) {
2773 // Format(instr, "vcvtus'cond 'sd, 'sm");
2774 if (sm_val >= static_cast<float>(INT32_MAX)) {
2775 ud_val = INT32_MAX;
2776 } else if (sm_val > 0.0) {
2777 ud_val = static_cast<uint32_t>(sm_val);
2778 }
2779 } else {
2780 // Format(instr, "vcvtis'cond 'sd, 'sm");
2781 if (sm_val <= static_cast<float>(INT32_MIN)) {
2782 id_val = INT32_MIN;
2783 } else if (sm_val >= static_cast<float>(INT32_MAX)) {
2784 id_val = INT32_MAX;
2785 } else {
2786 id_val = static_cast<int32_t>(sm_val);
2787 }
2788 ASSERT((id_val >= 0) || !(sm_val >= 0.0));
2789 }
2790 } else {
2791 sd = instr->SdField();
2792 double dm_val = get_dregister(dm);
2793 if (instr->Bit(16) == 0) {
2794 // Format(instr, "vcvtud'cond 'sd, 'dm");
2795 if (dm_val >= static_cast<double>(INT32_MAX)) {
2796 ud_val = INT32_MAX;
2797 } else if (dm_val > 0.0) {
2798 ud_val = static_cast<uint32_t>(dm_val);
2799 }
2800 } else {
2801 // Format(instr, "vcvtid'cond 'sd, 'dm");
2802 if (dm_val <= static_cast<double>(INT32_MIN)) {
2803 id_val = INT32_MIN;
2804 } else if (dm_val >= static_cast<double>(INT32_MAX)) {
2805 id_val = INT32_MAX;
2806 } else if (isnan(dm_val)) {
2807 id_val = 0;
2808 } else {
2809 id_val = static_cast<int32_t>(dm_val);
2810 }
2811 ASSERT((id_val >= 0) || !(dm_val >= 0.0));
2812 }
2813 }
2814 int32_t sd_val;
2815 if (instr->Bit(16) == 0) {
2816 sd_val = static_cast<int32_t>(ud_val);
2817 } else {
2818 sd_val = id_val;
2819 }
2820 set_sregister_bits(sd, sd_val);
2821 break;
2822 }
2823 case 2: // vcvtb, vcvtt
2824 case 3: // vcvtb, vcvtt
2825 case 9: // undefined
2826 case 10: // vcvt between floating-point and fixed-point
2827 case 11: // vcvt between floating-point and fixed-point
2828 case 14: // vcvt between floating-point and fixed-point
2829 case 15: // vcvt between floating-point and fixed-point
2830 default: {
2831 UnimplementedInstruction(instr);
2832 break;
2833 }
2834 }
2835 } break;
2836 }
2837 } else {
2838 // 8, 16, or 32-bit Transfer between ARM Core and VFP
2839 if ((instr->Bits(21, 3) == 0) && (instr->Bit(8) == 0)) {
2840 Register rd = instr->RdField();
2841 SRegister sn = instr->SnField();
2842 if (instr->Bit(20) == 0) {
2843 // Format(instr, "vmovs'cond 'sn, 'rd");
2844 set_sregister_bits(sn, get_register(rd));
2845 } else {
2846 // Format(instr, "vmovr'cond 'rd, 'sn");
2847 set_register(rd, get_sregister_bits(sn));
2848 }
2849 } else if ((instr->Bits(22, 3) == 0) && (instr->Bit(20) == 0) &&
2850 (instr->Bit(8) == 1) && (instr->Bits(5, 2) == 0)) {
2851 DRegister dn = instr->DnField();
2852 Register rd = instr->RdField();
2853 const int32_t src_value = get_register(rd);
2854 const int64_t dst_value = get_dregister_bits(dn);
2855 int32_t dst_lo = Utils::Low32Bits(dst_value);
2856 int32_t dst_hi = Utils::High32Bits(dst_value);
2857 if (instr->Bit(21) == 0) {
2858 // Format(instr, "vmovd'cond 'dn[0], 'rd");
2859 dst_lo = src_value;
2860 } else {
2861 // Format(instr, "vmovd'cond 'dn[1], 'rd");
2862 dst_hi = src_value;
2863 }
2864 set_dregister_bits(dn, Utils::LowHighTo64Bits(dst_lo, dst_hi));
2865 } else if ((instr->Bits(20, 4) == 0xf) && (instr->Bit(8) == 0)) {
2866 if (instr->Bits(12, 4) == 0xf) {
2867 // Format(instr, "vmrs'cond APSR, FPSCR");
2868 n_flag_ = fp_n_flag_;
2869 z_flag_ = fp_z_flag_;
2870 c_flag_ = fp_c_flag_;
2871 v_flag_ = fp_v_flag_;
2872 } else {
2873 // Format(instr, "vmrs'cond 'rd, FPSCR");
2874 const int32_t n_flag = fp_n_flag_ ? (1 << 31) : 0;
2875 const int32_t z_flag = fp_z_flag_ ? (1 << 30) : 0;
2876 const int32_t c_flag = fp_c_flag_ ? (1 << 29) : 0;
2877 const int32_t v_flag = fp_v_flag_ ? (1 << 28) : 0;
2878 set_register(instr->RdField(), n_flag | z_flag | c_flag | v_flag);
2879 }
2880 } else {
2881 UnimplementedInstruction(instr);
2882 }
2883 }
2884 } else {
2885 UnimplementedInstruction(instr);
2886 }
2887}
2888
2889static void simd_value_swap(simd_value_t* s1,
2890 int i1,
2891 simd_value_t* s2,
2892 int i2) {
2893 uint32_t tmp;
2894 tmp = s1->data_[i1].u;
2895 s1->data_[i1].u = s2->data_[i2].u;
2896 s2->data_[i2].u = tmp;
2897}
2898
2899static float vminf(float f1, float f2) {
2900 if (f1 == f2) {
2901 // take care of (-0.0) < 0.0, (they are equal according to minss)
2902 return signbit(f1) ? f1 : f2;
2903 }
2904 return f1 > f2 ? f2 : f1;
2905}
2906
2907static float vmaxf(float f1, float f2) {
2908 if (f1 == f2) {
2909 // take care of (-0.0) < 0.0, (they are equal according to minss)
2910 return signbit(f1) ? f2 : f1;
2911 }
2912 return f1 < f2 ? f2 : f1;
2913}
2914
2915void Simulator::DecodeSIMDDataProcessing(Instr* instr) {
2916 ASSERT(instr->ConditionField() == kSpecialCondition);
2917
2918 if (instr->Bit(6) == 1) {
2919 // Q = 1, Using 128-bit Q registers.
2920 const QRegister qd = instr->QdField();
2921 const QRegister qn = instr->QnField();
2922 const QRegister qm = instr->QmField();
2923 simd_value_t s8d;
2924 simd_value_t s8n;
2925 simd_value_t s8m;
2926
2927 get_qregister(qn, &s8n);
2928 get_qregister(qm, &s8m);
2929 int8_t* s8d_8 = reinterpret_cast<int8_t*>(&s8d);
2930 int8_t* s8n_8 = reinterpret_cast<int8_t*>(&s8n);
2931 int8_t* s8m_8 = reinterpret_cast<int8_t*>(&s8m);
2932 uint8_t* s8d_u8 = reinterpret_cast<uint8_t*>(&s8d);
2933 uint8_t* s8n_u8 = reinterpret_cast<uint8_t*>(&s8n);
2934 uint8_t* s8m_u8 = reinterpret_cast<uint8_t*>(&s8m);
2935 int16_t* s8d_16 = reinterpret_cast<int16_t*>(&s8d);
2936 int16_t* s8n_16 = reinterpret_cast<int16_t*>(&s8n);
2937 int16_t* s8m_16 = reinterpret_cast<int16_t*>(&s8m);
2938 uint16_t* s8d_u16 = reinterpret_cast<uint16_t*>(&s8d);
2939 uint16_t* s8n_u16 = reinterpret_cast<uint16_t*>(&s8n);
2940 uint16_t* s8m_u16 = reinterpret_cast<uint16_t*>(&s8m);
2941 int32_t* s8d_32 = reinterpret_cast<int32_t*>(&s8d);
2942 int32_t* s8n_32 = reinterpret_cast<int32_t*>(&s8n);
2943 int32_t* s8m_32 = reinterpret_cast<int32_t*>(&s8m);
2944 uint32_t* s8d_u32 = reinterpret_cast<uint32_t*>(&s8d);
2945 uint32_t* s8m_u32 = reinterpret_cast<uint32_t*>(&s8m);
2946 int64_t* s8d_64 = reinterpret_cast<int64_t*>(&s8d);
2947 int64_t* s8n_64 = reinterpret_cast<int64_t*>(&s8n);
2948 int64_t* s8m_64 = reinterpret_cast<int64_t*>(&s8m);
2949 uint64_t* s8d_u64 = reinterpret_cast<uint64_t*>(&s8d);
2950 uint64_t* s8m_u64 = reinterpret_cast<uint64_t*>(&s8m);
2951
2952 if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) &&
2953 (instr->Bits(23, 2) == 0)) {
2954 // Uses q registers.
2955 // Format(instr, "vadd.'sz 'qd, 'qn, 'qm");
2956 const int size = instr->Bits(20, 2);
2957 if (size == 0) {
2958 for (int i = 0; i < 16; i++) {
2959 s8d_8[i] = s8n_8[i] + s8m_8[i];
2960 }
2961 } else if (size == 1) {
2962 for (int i = 0; i < 8; i++) {
2963 s8d_16[i] = s8n_16[i] + s8m_16[i];
2964 }
2965 } else if (size == 2) {
2966 for (int i = 0; i < 4; i++) {
2967 s8d.data_[i].u = s8n.data_[i].u + s8m.data_[i].u;
2968 }
2969 } else if (size == 3) {
2970 for (int i = 0; i < 2; i++) {
2971 s8d_64[i] = s8n_64[i] + s8m_64[i];
2972 }
2973 } else {
2974 UNREACHABLE();
2975 }
2976 } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) &&
2977 (instr->Bits(23, 2) == 0) && (instr->Bit(21) == 0)) {
2978 // Format(instr, "vadd.F32 'qd, 'qn, 'qm");
2979 for (int i = 0; i < 4; i++) {
2980 s8d.data_[i].f = s8n.data_[i].f + s8m.data_[i].f;
2981 }
2982 } else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) &&
2983 (instr->Bits(23, 2) == 2)) {
2984 // Format(instr, "vsub.'sz 'qd, 'qn, 'qm");
2985 const int size = instr->Bits(20, 2);
2986 if (size == 0) {
2987 for (int i = 0; i < 16; i++) {
2988 s8d_8[i] = s8n_8[i] - s8m_8[i];
2989 }
2990 } else if (size == 1) {
2991 for (int i = 0; i < 8; i++) {
2992 s8d_16[i] = s8n_16[i] - s8m_16[i];
2993 }
2994 } else if (size == 2) {
2995 for (int i = 0; i < 4; i++) {
2996 s8d.data_[i].u = s8n.data_[i].u - s8m.data_[i].u;
2997 }
2998 } else if (size == 3) {
2999 for (int i = 0; i < 2; i++) {
3000 s8d_64[i] = s8n_64[i] - s8m_64[i];
3001 }
3002 } else {
3003 UNREACHABLE();
3004 }
3005 } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) &&
3006 (instr->Bits(23, 2) == 0) && (instr->Bit(21) == 1)) {
3007 // Format(instr, "vsub.F32 'qd, 'qn, 'qm");
3008 for (int i = 0; i < 4; i++) {
3009 s8d.data_[i].f = s8n.data_[i].f - s8m.data_[i].f;
3010 }
3011 } else if ((instr->Bits(8, 4) == 9) && (instr->Bit(4) == 1) &&
3012 (instr->Bits(23, 2) == 0)) {
3013 // Format(instr, "vmul.'sz 'qd, 'qn, 'qm");
3014 const int size = instr->Bits(20, 2);
3015 if (size == 0) {
3016 for (int i = 0; i < 16; i++) {
3017 s8d_8[i] = s8n_8[i] * s8m_8[i];
3018 }
3019 } else if (size == 1) {
3020 for (int i = 0; i < 8; i++) {
3021 s8d_16[i] = s8n_16[i] * s8m_16[i];
3022 }
3023 } else if (size == 2) {
3024 for (int i = 0; i < 4; i++) {
3025 s8d.data_[i].u = s8n.data_[i].u * s8m.data_[i].u;
3026 }
3027 } else if (size == 3) {
3028 UnimplementedInstruction(instr);
3029 } else {
3030 UNREACHABLE();
3031 }
3032 } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 1) &&
3033 (instr->Bits(23, 2) == 2) && (instr->Bit(21) == 0)) {
3034 // Format(instr, "vmul.F32 'qd, 'qn, 'qm");
3035 for (int i = 0; i < 4; i++) {
3036 s8d.data_[i].f = s8n.data_[i].f * s8m.data_[i].f;
3037 }
3038 } else if ((instr->Bits(8, 4) == 4) && (instr->Bit(4) == 0) &&
3039 (instr->Bit(23) == 0) && (instr->Bits(25, 3) == 1)) {
3040 // Format(instr, "vshlqu'sz 'qd, 'qm, 'qn");
3041 // Format(instr, "vshlqi'sz 'qd, 'qm, 'qn");
3042 const bool is_signed = instr->Bit(24) == 0;
3043 const int size = instr->Bits(20, 2);
3044 if (size == 0) {
3045 for (int i = 0; i < 16; i++) {
3046 int8_t shift = s8n_8[i];
3047 if (shift > 0) {
3048 s8d_u8[i] = s8m_u8[i] << shift;
3049 } else if (shift < 0) {
3050 if (is_signed) {
3051 s8d_8[i] = s8m_8[i] >> (-shift);
3052 } else {
3053 s8d_u8[i] = s8m_u8[i] >> (-shift);
3054 }
3055 }
3056 }
3057 } else if (size == 1) {
3058 for (int i = 0; i < 8; i++) {
3059 int8_t shift = s8n_8[i * 2];
3060 if (shift > 0) {
3061 s8d_u16[i] = s8m_u16[i] << shift;
3062 } else if (shift < 0) {
3063 if (is_signed) {
3064 s8d_16[i] = s8m_16[i] >> (-shift);
3065 } else {
3066 s8d_u16[i] = s8m_u16[i] >> (-shift);
3067 }
3068 }
3069 }
3070 } else if (size == 2) {
3071 for (int i = 0; i < 4; i++) {
3072 int8_t shift = s8n_8[i * 4];
3073 if (shift > 0) {
3074 s8d_u32[i] = s8m_u32[i] << shift;
3075 } else if (shift < 0) {
3076 if (is_signed) {
3077 s8d_32[i] = s8m_32[i] >> (-shift);
3078 } else {
3079 s8d_u32[i] = s8m_u32[i] >> (-shift);
3080 }
3081 }
3082 }
3083 } else {
3084 ASSERT(size == 3);
3085 for (int i = 0; i < 2; i++) {
3086 int8_t shift = s8n_8[i * 8];
3087 if (shift > 0) {
3088 s8d_u64[i] = s8m_u64[i] << shift;
3089 } else if (shift < 0) {
3090 if (is_signed) {
3091 s8d_64[i] = s8m_64[i] >> (-shift);
3092 } else {
3093 s8d_u64[i] = s8m_u64[i] >> (-shift);
3094 }
3095 }
3096 }
3097 }
3098 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
3099 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 2)) {
3100 // Format(instr, "veorq 'qd, 'qn, 'qm");
3101 for (int i = 0; i < 4; i++) {
3102 s8d.data_[i].u = s8n.data_[i].u ^ s8m.data_[i].u;
3103 }
3104 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
3105 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 0)) {
3106 // Format(instr, "vornq 'qd, 'qn, 'qm");
3107 for (int i = 0; i < 4; i++) {
3108 s8d.data_[i].u = s8n.data_[i].u | ~s8m.data_[i].u;
3109 }
3110 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
3111 (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
3112 if (qm == qn) {
3113 // Format(instr, "vmovq 'qd, 'qm");
3114 for (int i = 0; i < 4; i++) {
3115 s8d.data_[i].u = s8m.data_[i].u;
3116 }
3117 } else {
3118 // Format(instr, "vorrq 'qd, 'qm");
3119 for (int i = 0; i < 4; i++) {
3120 s8d.data_[i].u = s8n.data_[i].u | s8m.data_[i].u;
3121 }
3122 }
3123 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 1) &&
3124 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
3125 // Format(instr, "vandq 'qd, 'qn, 'qm");
3126 for (int i = 0; i < 4; i++) {
3127 s8d.data_[i].u = s8n.data_[i].u & s8m.data_[i].u;
3128 }
3129 } else if ((instr->Bits(7, 5) == 11) && (instr->Bit(4) == 0) &&
3130 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 5) == 7) &&
3131 (instr->Bits(16, 4) == 0)) {
3132 // Format(instr, "vmvnq 'qd, 'qm");
3133 for (int i = 0; i < 4; i++) {
3134 s8d.data_[i].u = ~s8m.data_[i].u;
3135 }
3136 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) &&
3137 (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
3138 // Format(instr, "vminqs 'qd, 'qn, 'qm");
3139 for (int i = 0; i < 4; i++) {
3140 s8d.data_[i].f = vminf(s8n.data_[i].f, s8m.data_[i].f);
3141 }
3142 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 0) &&
3143 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
3144 // Format(instr, "vmaxqs 'qd, 'qn, 'qm");
3145 for (int i = 0; i < 4; i++) {
3146 s8d.data_[i].f = vmaxf(s8n.data_[i].f, s8m.data_[i].f);
3147 }
3148 } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) &&
3149 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3150 (instr->Bit(7) == 0) && (instr->Bits(16, 4) == 9)) {
3151 // Format(instr, "vabsqs 'qd, 'qm");
3152 for (int i = 0; i < 4; i++) {
3153 s8d.data_[i].f = fabsf(s8m.data_[i].f);
3154 }
3155 } else if ((instr->Bits(8, 4) == 7) && (instr->Bit(4) == 0) &&
3156 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3157 (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 9)) {
3158 // Format(instr, "vnegqs 'qd, 'qm");
3159 for (int i = 0; i < 4; i++) {
3160 s8d.data_[i].f = -s8m.data_[i].f;
3161 }
3162 } else if ((instr->Bits(7, 5) == 10) && (instr->Bit(4) == 0) &&
3163 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3164 (instr->Bits(16, 4) == 11)) {
3165 // Format(instr, "vrecpeq 'qd, 'qm");
3166 for (int i = 0; i < 4; i++) {
3167 s8d.data_[i].f = ReciprocalEstimate(s8m.data_[i].f);
3168 }
3169 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 1) &&
3170 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
3171 // Format(instr, "vrecpsq 'qd, 'qn, 'qm");
3172 for (int i = 0; i < 4; i++) {
3173 s8d.data_[i].f = ReciprocalStep(s8n.data_[i].f, s8m.data_[i].f);
3174 }
3175 } else if ((instr->Bits(8, 4) == 5) && (instr->Bit(4) == 0) &&
3176 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3177 (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 11)) {
3178 // Format(instr, "vrsqrteqs 'qd, 'qm");
3179 for (int i = 0; i < 4; i++) {
3180 s8d.data_[i].f = ReciprocalSqrtEstimate(s8m.data_[i].f);
3181 }
3182 } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 1) &&
3183 (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
3184 // Format(instr, "vrsqrtsqs 'qd, 'qn, 'qm");
3185 for (int i = 0; i < 4; i++) {
3186 s8d.data_[i].f = ReciprocalSqrtStep(s8n.data_[i].f, s8m.data_[i].f);
3187 }
3188 } else if ((instr->Bits(8, 4) == 12) && (instr->Bit(4) == 0) &&
3189 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3190 (instr->Bit(7) == 0)) {
3191 DRegister dm = instr->DmField();
3192 int64_t dm_value = get_dregister_bits(dm);
3193 int32_t imm4 = instr->Bits(16, 4);
3194 int32_t idx;
3195 if ((imm4 & 1) != 0) {
3196 // Format(instr, "vdupb 'qd, 'dm['imm4_vdup]");
3197 int8_t* dm_b = reinterpret_cast<int8_t*>(&dm_value);
3198 idx = imm4 >> 1;
3199 int8_t val = dm_b[idx];
3200 for (int i = 0; i < 16; i++) {
3201 s8d_8[i] = val;
3202 }
3203 } else if ((imm4 & 2) != 0) {
3204 // Format(instr, "vduph 'qd, 'dm['imm4_vdup]");
3205 int16_t* dm_h = reinterpret_cast<int16_t*>(&dm_value);
3206 idx = imm4 >> 2;
3207 int16_t val = dm_h[idx];
3208 for (int i = 0; i < 8; i++) {
3209 s8d_16[i] = val;
3210 }
3211 } else if ((imm4 & 4) != 0) {
3212 // Format(instr, "vdupw 'qd, 'dm['imm4_vdup]");
3213 int32_t* dm_w = reinterpret_cast<int32_t*>(&dm_value);
3214 idx = imm4 >> 3;
3215 int32_t val = dm_w[idx];
3216 for (int i = 0; i < 4; i++) {
3217 s8d.data_[i].u = val;
3218 }
3219 } else {
3220 UnimplementedInstruction(instr);
3221 }
3222 } else if ((instr->Bits(8, 4) == 1) && (instr->Bit(4) == 0) &&
3223 (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
3224 (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 10)) {
3225 // Format(instr, "vzipqw 'qd, 'qm");
3226 get_qregister(qd, &s8d);
3227
3228 // Interleave the elements with the low words in qd, and the high words
3229 // in qm.
3230 simd_value_swap(&s8d, 3, &s8m, 2);
3231 simd_value_swap(&s8d, 3, &s8m, 1);
3232 simd_value_swap(&s8d, 2, &s8m, 0);
3233 simd_value_swap(&s8d, 2, &s8d, 1);
3234
3235 set_qregister(qm, s8m); // Writes both qd and qm.
3236 } else if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 1) &&
3237 (instr->Bits(23, 2) == 2)) {
3238 // Format(instr, "vceqq'sz 'qd, 'qn, 'qm");
3239 const int size = instr->Bits(20, 2);
3240 if (size == 0) {
3241 for (int i = 0; i < 16; i++) {
3242 s8d_8[i] = s8n_8[i] == s8m_8[i] ? 0xff : 0;
3243 }
3244 } else if (size == 1) {
3245 for (int i = 0; i < 8; i++) {
3246 s8d_16[i] = s8n_16[i] == s8m_16[i] ? 0xffff : 0;
3247 }
3248 } else if (size == 2) {
3249 for (int i = 0; i < 4; i++) {
3250 s8d.data_[i].u = s8n.data_[i].u == s8m.data_[i].u ? 0xffffffff : 0;
3251 }
3252 } else if (size == 3) {
3253 UnimplementedInstruction(instr);
3254 } else {
3255 UNREACHABLE();
3256 }
3257 } else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) &&
3258 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
3259 // Format(instr, "vceqqs 'qd, 'qn, 'qm");
3260 for (int i = 0; i < 4; i++) {
3261 s8d.data_[i].u = s8n.data_[i].f == s8m.data_[i].f ? 0xffffffff : 0;
3262 }
3263 } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 1) &&
3264 (instr->Bits(23, 2) == 0)) {
3265 // Format(instr, "vcgeq'sz 'qd, 'qn, 'qm");
3266 const int size = instr->Bits(20, 2);
3267 if (size == 0) {
3268 for (int i = 0; i < 16; i++) {
3269 s8d_8[i] = s8n_8[i] >= s8m_8[i] ? 0xff : 0;
3270 }
3271 } else if (size == 1) {
3272 for (int i = 0; i < 8; i++) {
3273 s8d_16[i] = s8n_16[i] >= s8m_16[i] ? 0xffff : 0;
3274 }
3275 } else if (size == 2) {
3276 for (int i = 0; i < 4; i++) {
3277 s8d.data_[i].u = s8n_32[i] >= s8m_32[i] ? 0xffffffff : 0;
3278 }
3279 } else if (size == 3) {
3280 UnimplementedInstruction(instr);
3281 } else {
3282 UNREACHABLE();
3283 }
3284 } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 1) &&
3285 (instr->Bits(23, 2) == 2)) {
3286 // Format(instr, "vcugeq'sz 'qd, 'qn, 'qm");
3287 const int size = instr->Bits(20, 2);
3288 if (size == 0) {
3289 for (int i = 0; i < 16; i++) {
3290 s8d_8[i] = s8n_u8[i] >= s8m_u8[i] ? 0xff : 0;
3291 }
3292 } else if (size == 1) {
3293 for (int i = 0; i < 8; i++) {
3294 s8d_16[i] = s8n_u16[i] >= s8m_u16[i] ? 0xffff : 0;
3295 }
3296 } else if (size == 2) {
3297 for (int i = 0; i < 4; i++) {
3298 s8d.data_[i].u = s8n.data_[i].u >= s8m.data_[i].u ? 0xffffffff : 0;
3299 }
3300 } else if (size == 3) {
3301 UnimplementedInstruction(instr);
3302 } else {
3303 UNREACHABLE();
3304 }
3305 } else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) &&
3306 (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 2)) {
3307 // Format(instr, "vcgeqs 'qd, 'qn, 'qm");
3308 for (int i = 0; i < 4; i++) {
3309 s8d.data_[i].u = s8n.data_[i].f >= s8m.data_[i].f ? 0xffffffff : 0;
3310 }
3311 } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 0) &&
3312 (instr->Bits(23, 2) == 0)) {
3313 // Format(instr, "vcgtq'sz 'qd, 'qn, 'qm");
3314 const int size = instr->Bits(20, 2);
3315 if (size == 0) {
3316 for (int i = 0; i < 16; i++) {
3317 s8d_8[i] = s8n_8[i] > s8m_8[i] ? 0xff : 0;
3318 }
3319 } else if (size == 1) {
3320 for (int i = 0; i < 8; i++) {
3321 s8d_16[i] = s8n_16[i] > s8m_16[i] ? 0xffff : 0;
3322 }
3323 } else if (size == 2) {
3324 for (int i = 0; i < 4; i++) {
3325 s8d.data_[i].u = s8n_32[i] > s8m_32[i] ? 0xffffffff : 0;
3326 }
3327 } else if (size == 3) {
3328 UnimplementedInstruction(instr);
3329 } else {
3330 UNREACHABLE();
3331 }
3332 } else if ((instr->Bits(8, 4) == 3) && (instr->Bit(4) == 0) &&
3333 (instr->Bits(23, 2) == 2)) {
3334 // Format(instr, "vcugtq'sz 'qd, 'qn, 'qm");
3335 const int size = instr->Bits(20, 2);
3336 if (size == 0) {
3337 for (int i = 0; i < 16; i++) {
3338 s8d_8[i] = s8n_u8[i] > s8m_u8[i] ? 0xff : 0;
3339 }
3340 } else if (size == 1) {
3341 for (int i = 0; i < 8; i++) {
3342 s8d_16[i] = s8n_u16[i] > s8m_u16[i] ? 0xffff : 0;
3343 }
3344 } else if (size == 2) {
3345 for (int i = 0; i < 4; i++) {
3346 s8d.data_[i].u = s8n.data_[i].u > s8m.data_[i].u ? 0xffffffff : 0;
3347 }
3348 } else if (size == 3) {
3349 UnimplementedInstruction(instr);
3350 } else {
3351 UNREACHABLE();
3352 }
3353 } else if ((instr->Bits(8, 4) == 14) && (instr->Bit(4) == 0) &&
3354 (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 2)) {
3355 // Format(instr, "vcgtqs 'qd, 'qn, 'qm");
3356 for (int i = 0; i < 4; i++) {
3357 s8d.data_[i].u = s8n.data_[i].f > s8m.data_[i].f ? 0xffffffff : 0;
3358 }
3359 } else {
3360 UnimplementedInstruction(instr);
3361 }
3362
3363 set_qregister(qd, s8d);
3364 } else {
3365 // Q == 0, Uses 64-bit D registers.
3366 if ((instr->Bits(23, 2) == 3) && (instr->Bits(20, 2) == 3) &&
3367 (instr->Bits(10, 2) == 2) && (instr->Bit(4) == 0)) {
3368 // Format(instr, "vtbl 'dd, 'dtbllist, 'dm");
3369 DRegister dd = instr->DdField();
3370 DRegister dm = instr->DmField();
3371 int reg_count = instr->Bits(8, 2) + 1;
3372 int start = (instr->Bit(7) << 4) | instr->Bits(16, 4);
3373 int64_t table[4];
3374
3375 for (int i = 0; i < reg_count; i++) {
3376 DRegister d = static_cast<DRegister>(start + i);
3377 table[i] = get_dregister_bits(d);
3378 }
3379 for (int i = reg_count; i < 4; i++) {
3380 table[i] = 0;
3381 }
3382
3383 int64_t dm_value = get_dregister_bits(dm);
3384 int64_t result;
3385 int8_t* dm_bytes = reinterpret_cast<int8_t*>(&dm_value);
3386 int8_t* result_bytes = reinterpret_cast<int8_t*>(&result);
3387 int8_t* table_bytes = reinterpret_cast<int8_t*>(&table[0]);
3388 for (int i = 0; i < 8; i++) {
3389 int idx = dm_bytes[i];
3390 if ((idx >= 0) && (idx < 256)) {
3391 result_bytes[i] = table_bytes[idx];
3392 } else {
3393 result_bytes[i] = 0;
3394 }
3395 }
3396
3397 set_dregister_bits(dd, result);
3398 } else {
3399 UnimplementedInstruction(instr);
3400 }
3401 }
3402}
3403
3404// Executes the current instruction.
3405DART_FORCE_INLINE void Simulator::InstructionDecodeImpl(Instr* instr) {
3406 pc_modified_ = false;
3407 if (instr->ConditionField() == kSpecialCondition) {
3408 if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) {
3409 // Format(instr, "clrex");
3410 ClearExclusive();
3411 } else if (instr->InstructionBits() ==
3412 static_cast<int32_t>(kDataMemoryBarrier)) {
3413 // Format(instr, "dmb ish");
3414 std::atomic_thread_fence(std::memory_order_seq_cst);
3415 } else {
3416 if (instr->IsSIMDDataProcessing()) {
3417 DecodeSIMDDataProcessing(instr);
3418 } else {
3419 UnimplementedInstruction(instr);
3420 }
3421 }
3422 } else if (ConditionallyExecute(instr)) {
3423 switch (instr->TypeField()) {
3424 case 0:
3425 case 1: {
3426 DecodeType01(instr);
3427 break;
3428 }
3429 case 2: {
3430 DecodeType2(instr);
3431 break;
3432 }
3433 case 3: {
3434 DecodeType3(instr);
3435 break;
3436 }
3437 case 4: {
3438 DecodeType4(instr);
3439 break;
3440 }
3441 case 5: {
3442 DecodeType5(instr);
3443 break;
3444 }
3445 case 6: {
3446 DecodeType6(instr);
3447 break;
3448 }
3449 case 7: {
3450 DecodeType7(instr);
3451 break;
3452 }
3453 default: {
3454 // Type field is three bits.
3455 UNREACHABLE();
3456 break;
3457 }
3458 }
3459 }
3460 if (!pc_modified_) {
3461 set_register(PC, reinterpret_cast<int32_t>(instr) + Instr::kInstrSize);
3462 }
3463}
3464
3465void Simulator::InstructionDecode(Instr* instr) {
3466 if (IsTracingExecution()) {
3467 THR_Print("%" Pu64 " ", icount_);
3468 const uword start = reinterpret_cast<uword>(instr);
3469 const uword end = start + Instr::kInstrSize;
3470 if (FLAG_support_disassembler) {
3471 Disassembler::Disassemble(start, end);
3472 } else {
3473 THR_Print("Disassembler not supported in this mode.\n");
3474 }
3475 }
3476 InstructionDecodeImpl(instr);
3477}
3478
3479void Simulator::Execute() {
3480 if (LIKELY(FLAG_stop_sim_at == ULLONG_MAX &&
3481 FLAG_trace_sim_after == ULLONG_MAX)) {
3482 ExecuteNoTrace();
3483 } else {
3484 ExecuteTrace();
3485 }
3486}
3487
3488void Simulator::ExecuteNoTrace() {
3489 // Get the PC to simulate. Cannot use the accessor here as we need the
3490 // raw PC value and not the one used as input to arithmetic instructions.
3491 uword program_counter = get_pc();
3492
3493 // Fast version of the dispatch loop without checking whether the simulator
3494 // should be stopping at a particular executed instruction.
3495 while (program_counter != kEndSimulatingPC) {
3496 Instr* instr = reinterpret_cast<Instr*>(program_counter);
3497 icount_++;
3498 InstructionDecodeImpl(instr);
3499 program_counter = get_pc();
3500 }
3501}
3502
3503void Simulator::ExecuteTrace() {
3504 // Get the PC to simulate. Cannot use the accessor here as we need the
3505 // raw PC value and not the one used as input to arithmetic instructions.
3506 uword program_counter = get_pc();
3507
3508 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
3509 // we reach the particular instruction count or address.
3510 while (program_counter != kEndSimulatingPC) {
3511 Instr* instr = reinterpret_cast<Instr*>(program_counter);
3512 icount_++;
3513 if (icount_ == FLAG_stop_sim_at) {
3514 SimulatorDebugger dbg(this);
3515 dbg.Stop(instr, "Instruction count reached");
3516 } else if (reinterpret_cast<uint64_t>(instr) == FLAG_stop_sim_at) {
3517 SimulatorDebugger dbg(this);
3518 dbg.Stop(instr, "Instruction address reached");
3519 } else if (IsIllegalAddress(program_counter)) {
3520 HandleIllegalAccess(program_counter, instr);
3521 } else {
3522 InstructionDecode(instr);
3523 }
3524 program_counter = get_pc();
3525 }
3526}
3527
3528int64_t Simulator::Call(int32_t entry,
3529 int32_t parameter0,
3530 int32_t parameter1,
3531 int32_t parameter2,
3532 int32_t parameter3,
3533 bool fp_return,
3534 bool fp_args) {
3535 // Save the SP register before the call so we can restore it.
3536 int32_t sp_before_call = get_register(SP);
3537
3538 // Setup parameters.
3539 if (fp_args) {
3540 set_sregister(S0, bit_cast<float, int32_t>(parameter0));
3541 set_sregister(S1, bit_cast<float, int32_t>(parameter1));
3542 set_sregister(S2, bit_cast<float, int32_t>(parameter2));
3543 set_sregister(S3, bit_cast<float, int32_t>(parameter3));
3544 } else {
3545 set_register(R0, parameter0);
3546 set_register(R1, parameter1);
3547 set_register(R2, parameter2);
3548 set_register(R3, parameter3);
3549 }
3550
3551 // Make sure the activation frames are properly aligned.
3552 int32_t stack_pointer = sp_before_call;
3553 if (OS::ActivationFrameAlignment() > 1) {
3554 stack_pointer =
3555 Utils::RoundDown(stack_pointer, OS::ActivationFrameAlignment());
3556 }
3557 set_register(SP, stack_pointer);
3558
3559 // Prepare to execute the code at entry.
3560 set_register(PC, entry);
3561 // Put down marker for end of simulation. The simulator will stop simulation
3562 // when the PC reaches this value. By saving the "end simulation" value into
3563 // the LR the simulation stops when returning to this call point.
3564 set_register(LR, kEndSimulatingPC);
3565
3566 // Remember the values of callee-saved registers.
3567 // The code below assumes that r9 is not used as sb (static base) in
3568 // simulator code and therefore is regarded as a callee-saved register.
3569 int32_t r4_val = get_register(R4);
3570 int32_t r5_val = get_register(R5);
3571 int32_t r6_val = get_register(R6);
3572 int32_t r7_val = get_register(R7);
3573 int32_t r8_val = get_register(R8);
3574#if !defined(DART_TARGET_OS_MACOS) && !defined(DART_TARGET_OS_MACOS_IOS)
3575 int32_t r9_val = get_register(R9);
3576#endif
3577 int32_t r10_val = get_register(R10);
3578 int32_t r11_val = get_register(R11);
3579
3580 double d8_val = 0.0;
3581 double d9_val = 0.0;
3582 double d10_val = 0.0;
3583 double d11_val = 0.0;
3584 double d12_val = 0.0;
3585 double d13_val = 0.0;
3586 double d14_val = 0.0;
3587 double d15_val = 0.0;
3588
3589 d8_val = get_dregister(D8);
3590 d9_val = get_dregister(D9);
3591 d10_val = get_dregister(D10);
3592 d11_val = get_dregister(D11);
3593 d12_val = get_dregister(D12);
3594 d13_val = get_dregister(D13);
3595 d14_val = get_dregister(D14);
3596 d15_val = get_dregister(D15);
3597
3598 // Setup the callee-saved registers with a known value. To be able to check
3599 // that they are preserved properly across dart execution.
3600 int32_t callee_saved_value = icount_;
3601 set_register(R4, callee_saved_value);
3602 set_register(R5, callee_saved_value);
3603 set_register(R6, callee_saved_value);
3604 set_register(R7, callee_saved_value);
3605 set_register(R8, callee_saved_value);
3606#if !defined(DART_TARGET_OS_MACOS) && !defined(DART_TARGET_OS_MACOS_IOS)
3607 set_register(R9, callee_saved_value);
3608#endif
3609 set_register(R10, callee_saved_value);
3610 set_register(R11, callee_saved_value);
3611
3612 double callee_saved_dvalue = 0.0;
3613 callee_saved_dvalue = static_cast<double>(icount_);
3614 set_dregister(D8, callee_saved_dvalue);
3615 set_dregister(D9, callee_saved_dvalue);
3616 set_dregister(D10, callee_saved_dvalue);
3617 set_dregister(D11, callee_saved_dvalue);
3618 set_dregister(D12, callee_saved_dvalue);
3619 set_dregister(D13, callee_saved_dvalue);
3620 set_dregister(D14, callee_saved_dvalue);
3621 set_dregister(D15, callee_saved_dvalue);
3622
3623 // Start the simulation
3624 Execute();
3625
3626 // Check that the callee-saved registers have been preserved.
3627 ASSERT(callee_saved_value == get_register(R4));
3628 ASSERT(callee_saved_value == get_register(R5));
3629 ASSERT(callee_saved_value == get_register(R6));
3630 ASSERT(callee_saved_value == get_register(R7));
3631 ASSERT(callee_saved_value == get_register(R8));
3632#if !defined(DART_TARGET_OS_MACOS) && !defined(DART_TARGET_OS_MACOS_IOS)
3633 ASSERT(callee_saved_value == get_register(R9));
3634#endif
3635 ASSERT(callee_saved_value == get_register(R10));
3636 ASSERT(callee_saved_value == get_register(R11));
3637
3638 ASSERT(callee_saved_dvalue == get_dregister(D8));
3639 ASSERT(callee_saved_dvalue == get_dregister(D9));
3640 ASSERT(callee_saved_dvalue == get_dregister(D10));
3641 ASSERT(callee_saved_dvalue == get_dregister(D11));
3642 ASSERT(callee_saved_dvalue == get_dregister(D12));
3643 ASSERT(callee_saved_dvalue == get_dregister(D13));
3644 ASSERT(callee_saved_dvalue == get_dregister(D14));
3645 ASSERT(callee_saved_dvalue == get_dregister(D15));
3646
3647 // Restore callee-saved registers with the original value.
3648 set_register(R4, r4_val);
3649 set_register(R5, r5_val);
3650 set_register(R6, r6_val);
3651 set_register(R7, r7_val);
3652 set_register(R8, r8_val);
3653#if !defined(DART_TARGET_OS_MACOS) && !defined(DART_TARGET_OS_MACOS_IOS)
3654 set_register(R9, r9_val);
3655#endif
3656 set_register(R10, r10_val);
3657 set_register(R11, r11_val);
3658
3659 set_dregister(D8, d8_val);
3660 set_dregister(D9, d9_val);
3661 set_dregister(D10, d10_val);
3662 set_dregister(D11, d11_val);
3663 set_dregister(D12, d12_val);
3664 set_dregister(D13, d13_val);
3665 set_dregister(D14, d14_val);
3666 set_dregister(D15, d15_val);
3667
3668 // Restore the SP register and return R1:R0.
3669 set_register(SP, sp_before_call);
3670 int64_t return_value;
3671 if (fp_return) {
3672 return_value = bit_cast<int64_t, double>(get_dregister(D0));
3673 } else {
3674 return_value = Utils::LowHighTo64Bits(get_register(R0), get_register(R1));
3675 }
3676 return return_value;
3677}
3678
3679void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
3680 // Walk over all setjmp buffers (simulated --> C++ transitions)
3681 // and try to find the setjmp associated with the simulated stack pointer.
3682 SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
3683 while (buf->link() != nullptr && buf->link()->sp() <= sp) {
3684 buf = buf->link();
3685 }
3686 ASSERT(buf != nullptr);
3687
3688 // The C++ caller has not cleaned up the stack memory of C++ frames.
3689 // Prepare for unwinding frames by destroying all the stack resources
3690 // in the previous C++ frames.
3691 StackResource::Unwind(thread);
3692
3693 // Keep the following code in sync with `StubCode::JumpToFrameStub()`.
3694
3695 // Unwind the C++ stack and continue simulation in the target frame.
3696 set_register(PC, static_cast<int32_t>(pc));
3697 set_register(SP, static_cast<int32_t>(sp));
3698 set_register(FP, static_cast<int32_t>(fp));
3699 set_register(THR, reinterpret_cast<uword>(thread));
3700 // Set the tag.
3701 thread->set_vm_tag(VMTag::kDartTagId);
3702 // Clear top exit frame.
3703 thread->set_top_exit_frame_info(0);
3704 // Restore pool pointer.
3705 int32_t code =
3706 *reinterpret_cast<int32_t*>(fp + kPcMarkerSlotFromFp * kWordSize);
3707 int32_t pp = FLAG_precompiled_mode
3708 ? static_cast<int32_t>(thread->global_object_pool())
3709 : *reinterpret_cast<int32_t*>(
3710 (code + Code::object_pool_offset() - kHeapObjectTag));
3711
3712 set_register(CODE_REG, code);
3713 set_register(PP, pp);
3714 if (FLAG_precompiled_mode) {
3715 set_register(DISPATCH_TABLE_REG,
3716 reinterpret_cast<int32_t>(thread->dispatch_table_array()));
3717 }
3718 buf->Longjmp();
3719}
3720
3721} // namespace dart
3722
3723#endif // defined(USING_SIMULATOR)
3724
3725#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)
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:193
static IsolateGroup * Current()
Definition isolate.h:534
IsolateGroupSource * source() const
Definition isolate.h:285
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:361
@ kThreadInGenerated
Definition thread.h:1022
#define LR
#define THR_Print(format,...)
Definition log.h:20
#define kIsolateSnapshotInstructionsAsmSymbol
Definition dart_api.h:3911
#define kVmSnapshotInstructionsAsmSymbol
Definition dart_api.h:3908
struct _Dart_NativeArguments * Dart_NativeArguments
Definition dart_api.h:3010
void(* Dart_NativeFunction)(Dart_NativeArguments arguments)
Definition dart_api.h:3198
#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
static const uint8_t buffer[]
uint8_t value
GAsyncResult * result
uint32_t uint32_t * format
uint32_t * target
#define DEFINE_FLAG(type, name, default_value, comment)
Definition flags.h:16
Dart_NativeFunction function
Definition fuchsia.cc:51
int argument_count
Definition fuchsia.cc:52
size_t length
Win32Message message
const GrXPFactory * Get(SkBlendMode mode)
bool Contains(const Container &container, const Value &value)
link(from_root, to_root)
Definition dart_pkg.py:44
static int64_t GetValue(Dart_Handle arg)
float ReciprocalSqrtEstimate(float op)
void SetBreakpoint(Dart_NativeArguments args)
const Register THR
const char *const name
float ReciprocalStep(float op1, float op2)
@ kHeapObjectTag
uintptr_t uword
Definition globals.h:501
const uint32_t fp
@ kNumberOfCpuRegisters
@ kNoRegister
@ kNoSRegister
@ kNumberOfSRegisters
float ReciprocalSqrtStep(float op1, float op2)
constexpr intptr_t kWordSize
Definition globals.h:509
const Register PP
@ kNumberOfDRegisters
@ kNoDRegister
float ReciprocalEstimate(float op)
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
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
int32_t width
Point offset
#define NO_SANITIZE_UNDEFINED(check)
#define ARRAY_SIZE(array)
Definition globals.h:72
#define OFFSET_OF(type, field)
Definition globals.h:138