1// Copyright (c) 2014, 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_ARM64)
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
16#include "vm/compiler/assembler/disassembler.h"
17#include "vm/constants.h"
18#include "vm/image_snapshot.h"
19#include "vm/native_arguments.h"
20#include "vm/os_thread.h"
21#include "vm/stack_frame.h"
22
23namespace dart {
24
25// constants_arm64.h does not define LR constant to prevent accidental direct
26// use of it during code generation. However using LR directly is okay in this
27// file because it is a simulator.
28constexpr Register LR = LR_DO_NOT_USE_DIRECTLY;
29
30DEFINE_FLAG(uint64_t,
31 trace_sim_after,
32 ULLONG_MAX,
33 "Trace simulator execution after instruction count reached.");
34DEFINE_FLAG(uint64_t,
35 stop_sim_at,
36 ULLONG_MAX,
37 "Instruction address or instruction count to stop simulator at.");
38
39DEFINE_FLAG(bool,
40 sim_allow_unaligned_accesses,
41 true,
42 "Allow unaligned accesses to Normal memory.");
43
44// This macro provides a platform independent use of sscanf. The reason for
45// SScanF not being implemented in a platform independent way through
46// OS in the same way as SNPrint is that the Windows C Run-Time
47// Library does not provide vsscanf.
48#define SScanF sscanf // NOLINT
49
50// SimulatorSetjmpBuffer are linked together, and the last created one
51// is referenced by the Simulator. When an exception is thrown, the exception
52// runtime looks at where to jump and finds the corresponding
53// SimulatorSetjmpBuffer based on the stack pointer of the exception handler.
54// The runtime then does a Longjmp on that buffer to return to the simulator.
55class SimulatorSetjmpBuffer {
56 public:
57 void Longjmp() {
58 // "This" is now the last setjmp buffer.
59 simulator_->set_last_setjmp_buffer(this);
60 longjmp(buffer_, 1);
61 }
62
63 explicit SimulatorSetjmpBuffer(Simulator* sim) {
64 simulator_ = sim;
65 link_ = sim->last_setjmp_buffer();
66 sim->set_last_setjmp_buffer(this);
67 sp_ = static_cast<uword>(sim->get_register(R31, R31IsSP));
68 }
69
70 ~SimulatorSetjmpBuffer() {
71 ASSERT(simulator_->last_setjmp_buffer() == this);
72 simulator_->set_last_setjmp_buffer(link_);
73 }
74
75 SimulatorSetjmpBuffer* link() { return link_; }
76
77 uword sp() { return sp_; }
78
79 private:
80 uword sp_;
81 Simulator* simulator_;
82 SimulatorSetjmpBuffer* link_;
83 jmp_buf buffer_;
84
85 friend class Simulator;
86};
87
88// The SimulatorDebugger class is used by the simulator while debugging
89// simulated ARM64 code.
90class SimulatorDebugger {
91 public:
92 explicit SimulatorDebugger(Simulator* sim);
93 ~SimulatorDebugger();
94
95 void Stop(Instr* instr, const char* message);
96 void Debug();
97 char* ReadLine(const char* prompt);
98
99 private:
100 Simulator* sim_;
101
102 bool GetValue(char* desc, uint64_t* value);
103 bool GetSValue(char* desc, uint32_t* value);
104 bool GetDValue(char* desc, uint64_t* value);
105 bool GetQValue(char* desc, simd_value_t* value);
106
107 static TokenPosition GetApproximateTokenIndex(const Code& code, uword pc);
108
109 static void PrintDartFrame(uword vm_instructions,
110 uword isolate_instructions,
111 uword pc,
112 uword fp,
113 uword sp,
114 const Function& function,
115 TokenPosition token_pos,
116 bool is_optimized,
117 bool is_inlined);
118 void PrintBacktrace();
119
120 // Set or delete a breakpoint. Returns true if successful.
121 bool SetBreakpoint(Instr* breakpc);
122 bool DeleteBreakpoint(Instr* breakpc);
123
124 // Undo and redo all breakpoints. This is needed to bracket disassembly and
125 // execution to skip past breakpoints when run from the debugger.
126 void UndoBreakpoints();
127 void RedoBreakpoints();
128};
129
130SimulatorDebugger::SimulatorDebugger(Simulator* sim) {
131 sim_ = sim;
132}
133
134SimulatorDebugger::~SimulatorDebugger() {}
135
136void SimulatorDebugger::Stop(Instr* instr, const char* message) {
137 OS::PrintErr("Simulator hit %s\n", message);
138 Debug();
139}
140
141static Register LookupCpuRegisterByName(const char* name) {
142 static const char* const kNames[] = {
143 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
144 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
145 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
146 "r24", "r25", "r26", "r27", "r28", "r29", "r30",
147
148 "ip0", "ip1", "pp", "fp", "lr", "sp", "zr",
149 };
150 static const Register kRegisters[] = {
151 R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10,
152 R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21,
153 R22, R23, R24, R25, R26, R27, R28, R29, R30,
154
155 IP0, IP1, PP, FP, LR, R31, ZR,
156 };
157 ASSERT(ARRAY_SIZE(kNames) == ARRAY_SIZE(kRegisters));
158 for (unsigned i = 0; i < ARRAY_SIZE(kNames); i++) {
159 if (strcmp(kNames[i], name) == 0) {
160 return kRegisters[i];
161 }
162 }
163 return kNoRegister;
164}
165
166static VRegister LookupVRegisterByName(const char* name) {
167 int reg_nr = -1;
168 bool ok = SScanF(name, "v%d", &reg_nr);
169 if (ok && (0 <= reg_nr) && (reg_nr < kNumberOfVRegisters)) {
170 return static_cast<VRegister>(reg_nr);
171 }
172 return kNoVRegister;
173}
174
175bool SimulatorDebugger::GetValue(char* desc, uint64_t* value) {
176 Register reg = LookupCpuRegisterByName(desc);
177 if (reg != kNoRegister) {
178 if (reg == ZR) {
179 *value = 0;
180 return true;
181 }
182 *value = sim_->get_register(reg);
183 return true;
184 }
185 if (desc[0] == '*') {
186 uint64_t addr;
187 if (GetValue(desc + 1, &addr)) {
188 if (Simulator::IsIllegalAddress(addr)) {
189 return false;
190 }
191 *value = *(reinterpret_cast<int64_t*>(addr));
192 return true;
193 }
194 }
195 if (strcmp("pc", desc) == 0) {
196 *value = sim_->get_pc();
197 return true;
198 }
199 bool retval = SScanF(desc, "0x%" Px64, value) == 1;
200 if (!retval) {
201 retval = SScanF(desc, "%" Px64, value) == 1;
202 }
203 return retval;
204}
205
206bool SimulatorDebugger::GetSValue(char* desc, uint32_t* value) {
207 VRegister vreg = LookupVRegisterByName(desc);
208 if (vreg != kNoVRegister) {
209 *value = sim_->get_vregisters(vreg, 0);
210 return true;
211 }
212 if (desc[0] == '*') {
213 uint64_t addr;
214 if (GetValue(desc + 1, &addr)) {
215 if (Simulator::IsIllegalAddress(addr)) {
216 return false;
217 }
218 *value = *(reinterpret_cast<uint32_t*>(addr));
219 return true;
220 }
221 }
222 return false;
223}
224
225bool SimulatorDebugger::GetDValue(char* desc, uint64_t* value) {
226 VRegister vreg = LookupVRegisterByName(desc);
227 if (vreg != kNoVRegister) {
228 *value = sim_->get_vregisterd(vreg, 0);
229 return true;
230 }
231 if (desc[0] == '*') {
232 uint64_t addr;
233 if (GetValue(desc + 1, &addr)) {
234 if (Simulator::IsIllegalAddress(addr)) {
235 return false;
236 }
237 *value = *(reinterpret_cast<uint64_t*>(addr));
238 return true;
239 }
240 }
241 return false;
242}
243
244bool SimulatorDebugger::GetQValue(char* desc, simd_value_t* value) {
245 VRegister vreg = LookupVRegisterByName(desc);
246 if (vreg != kNoVRegister) {
247 sim_->get_vregister(vreg, value);
248 return true;
249 }
250 if (desc[0] == '*') {
251 uint64_t addr;
252 if (GetValue(desc + 1, &addr)) {
253 if (Simulator::IsIllegalAddress(addr)) {
254 return false;
255 }
256 *value = *(reinterpret_cast<simd_value_t*>(addr));
257 return true;
258 }
259 }
260 return false;
261}
262
263TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
264 uword pc) {
265 TokenPosition token_pos = TokenPosition::kNoSource;
266 uword pc_offset = pc - code.PayloadStart();
267 const PcDescriptors& descriptors =
268 PcDescriptors::Handle(code.pc_descriptors());
269 PcDescriptors::Iterator iter(descriptors, UntaggedPcDescriptors::kAnyKind);
270 while (iter.MoveNext()) {
271 if (iter.PcOffset() == pc_offset) {
272 return iter.TokenPos();
273 } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) {
274 token_pos = iter.TokenPos();
275 }
276 }
277 return token_pos;
278}
279
280#if defined(DART_PRECOMPILED_RUNTIME)
281static const char* ImageName(uword vm_instructions,
282 uword isolate_instructions,
283 uword pc,
284 intptr_t* offset) {
285 const Image vm_image(vm_instructions);
286 const Image isolate_image(isolate_instructions);
287 if (vm_image.contains(pc)) {
288 *offset = pc - vm_instructions;
289 return kVmSnapshotInstructionsAsmSymbol;
290 } else if (isolate_image.contains(pc)) {
291 *offset = pc - isolate_instructions;
292 return kIsolateSnapshotInstructionsAsmSymbol;
293 } else {
294 *offset = 0;
295 return "<unknown>";
296 }
297}
298#endif
299
300void SimulatorDebugger::PrintDartFrame(uword vm_instructions,
301 uword isolate_instructions,
302 uword pc,
303 uword fp,
304 uword sp,
305 const Function& function,
306 TokenPosition token_pos,
307 bool is_optimized,
308 bool is_inlined) {
309 const Script& script = Script::Handle(function.script());
310 const String& func_name = String::Handle(function.QualifiedScrubbedName());
311 const String& url = String::Handle(script.url());
312 intptr_t line, column;
313 if (script.GetTokenLocation(token_pos, &line, &column)) {
314 OS::PrintErr(
315 "pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd ":%" Pd ")", pc,
316 fp, sp, is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
317 func_name.ToCString(), url.ToCString(), line, column);
318 } else {
319 OS::PrintErr("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s)", pc, fp, sp,
320 is_optimized ? (is_inlined ? "inlined " : "optimized ") : "",
321 func_name.ToCString(), url.ToCString());
322 }
323#if defined(DART_PRECOMPILED_RUNTIME)
324 intptr_t offset;
325 auto const symbol_name =
326 ImageName(vm_instructions, isolate_instructions, pc, &offset);
327 OS::PrintErr(" %s+0x%" Px "", symbol_name, offset);
328#endif
329 OS::PrintErr("\n");
330}
331
332void SimulatorDebugger::PrintBacktrace() {
333 auto const T = Thread::Current();
334 auto const Z = T->zone();
335#if defined(DART_PRECOMPILED_RUNTIME)
336 auto const vm_instructions = reinterpret_cast<uword>(
337 Dart::vm_isolate_group()->source()->snapshot_instructions);
338 auto const isolate_instructions = reinterpret_cast<uword>(
339 T->isolate_group()->source()->snapshot_instructions);
340 OS::PrintErr("vm_instructions=0x%" Px ", isolate_instructions=0x%" Px "\n",
341 vm_instructions, isolate_instructions);
342#else
343 const uword vm_instructions = 0;
344 const uword isolate_instructions = 0;
345#endif
346 StackFrameIterator frames(sim_->get_register(FP), sim_->get_register(SP),
347 sim_->get_pc(),
348 ValidationPolicy::kDontValidateFrames, T,
349 StackFrameIterator::kNoCrossThreadIteration);
350 StackFrame* frame = frames.NextFrame();
351 ASSERT(frame != nullptr);
352 Function& function = Function::Handle(Z);
353 Function& inlined_function = Function::Handle(Z);
354 Code& code = Code::Handle(Z);
355 Code& unoptimized_code = Code::Handle(Z);
356 while (frame != nullptr) {
357 if (frame->IsDartFrame()) {
358 code = frame->LookupDartCode();
359 function = code.function();
360 if (code.is_optimized()) {
361 // For optimized frames, extract all the inlined functions if any
362 // into the stack trace.
363 InlinedFunctionsIterator it(code, frame->pc());
364 while (!it.Done()) {
365 // Print each inlined frame with its pc in the corresponding
366 // unoptimized frame.
367 inlined_function = it.function();
368 unoptimized_code = it.code();
369 uword unoptimized_pc = it.pc();
370 it.Advance();
371 if (!it.Done()) {
372 PrintDartFrame(
373 vm_instructions, isolate_instructions, unoptimized_pc,
374 frame->fp(), frame->sp(), inlined_function,
375 GetApproximateTokenIndex(unoptimized_code, unoptimized_pc),
376 true, true);
377 }
378 }
379 // Print the optimized inlining frame below.
380 }
381 PrintDartFrame(vm_instructions, isolate_instructions, frame->pc(),
382 frame->fp(), frame->sp(), function,
383 GetApproximateTokenIndex(code, frame->pc()),
384 code.is_optimized(), false);
385 } else {
386 OS::PrintErr("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s frame",
387 frame->pc(), frame->fp(), frame->sp(),
388 frame->IsEntryFrame()
389 ? "entry"
390 : frame->IsExitFrame()
391 ? "exit"
392 : frame->IsStubFrame() ? "stub" : "invalid");
393#if defined(DART_PRECOMPILED_RUNTIME)
394 intptr_t offset;
395 auto const symbol_name = ImageName(vm_instructions, isolate_instructions,
396 frame->pc(), &offset);
397 OS::PrintErr(" %s+0x%" Px "", symbol_name, offset);
398#endif
399 OS::PrintErr("\n");
400 }
401 frame = frames.NextFrame();
402 }
403}
404
405bool SimulatorDebugger::SetBreakpoint(Instr* breakpc) {
406 // Check if a breakpoint can be set. If not return without any side-effects.
407 if (sim_->break_pc_ != nullptr) {
408 return false;
409 }
410
411 // Set the breakpoint.
412 sim_->break_pc_ = breakpc;
413 sim_->break_instr_ = breakpc->InstructionBits();
414 // Not setting the breakpoint instruction in the code itself. It will be set
415 // when the debugger shell continues.
416 return true;
417}
418
419bool SimulatorDebugger::DeleteBreakpoint(Instr* breakpc) {
420 if (sim_->break_pc_ != nullptr) {
421 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
422 }
423
424 sim_->break_pc_ = nullptr;
425 sim_->break_instr_ = 0;
426 return true;
427}
428
429void SimulatorDebugger::UndoBreakpoints() {
430 if (sim_->break_pc_ != nullptr) {
431 sim_->break_pc_->SetInstructionBits(sim_->break_instr_);
432 }
433}
434
435void SimulatorDebugger::RedoBreakpoints() {
436 if (sim_->break_pc_ != nullptr) {
437 sim_->break_pc_->SetInstructionBits(Instr::kSimulatorBreakpointInstruction);
438 }
439}
440
441void SimulatorDebugger::Debug() {
442 uintptr_t last_pc = -1;
443 bool done = false;
444
445#define COMMAND_SIZE 63
446#define ARG_SIZE 255
447
448#define STR(a) #a
449#define XSTR(a) STR(a)
450
451 char cmd[COMMAND_SIZE + 1];
452 char arg1[ARG_SIZE + 1];
453 char arg2[ARG_SIZE + 1];
454
455 // make sure to have a proper terminating character if reaching the limit
456 cmd[COMMAND_SIZE] = 0;
457 arg1[ARG_SIZE] = 0;
458 arg2[ARG_SIZE] = 0;
459
460 // Undo all set breakpoints while running in the debugger shell. This will
461 // make them invisible to all commands.
462 UndoBreakpoints();
463
464 while (!done) {
465 if (last_pc != sim_->get_pc()) {
466 last_pc = sim_->get_pc();
467 if (Simulator::IsIllegalAddress(last_pc)) {
468 OS::PrintErr("pc is out of bounds: 0x%" Px "\n", last_pc);
469 } else {
470 if (FLAG_support_disassembler) {
471 Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize);
472 } else {
473 OS::PrintErr("Disassembler not supported in this mode.\n");
474 }
475 }
476 }
477 char* line = ReadLine("sim> ");
478 if (line == nullptr) {
479 FATAL("ReadLine failed");
480 } else {
481 // Use sscanf to parse the individual parts of the command line. At the
482 // moment no command expects more than two parameters.
483 int args = SScanF(line,
484 "%" XSTR(COMMAND_SIZE) "s "
485 "%" XSTR(ARG_SIZE) "s "
486 "%" XSTR(ARG_SIZE) "s",
487 cmd, arg1, arg2);
488 if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
489 OS::PrintErr(
490 "c/cont -- continue execution\n"
491 "disasm -- disassemble instrs at current pc location\n"
492 " other variants are:\n"
493 " disasm <address>\n"
494 " disasm <address> <number_of_instructions>\n"
495 " by default 10 instrs are disassembled\n"
496 "del -- delete breakpoints\n"
497 "flags -- print flag values\n"
498 "gdb -- transfer control to gdb\n"
499 "h/help -- print this help string\n"
500 "break <address> -- set break point at specified address\n"
501 "p/print <reg or icount or value or *addr> -- print integer\n"
502 "pf/printfloat <vreg or *addr> --print float value\n"
503 "pd/printdouble <vreg or *addr> -- print double value\n"
504 "pq/printquad <vreg or *addr> -- print vector register\n"
505 "po/printobject <*reg or *addr> -- print object\n"
506 "si/stepi -- single step an instruction\n"
507 "trace -- toggle execution tracing mode\n"
508 "bt -- print backtrace\n"
509 "unstop -- if current pc is a stop instr make it a nop\n"
510 "q/quit -- Quit the debugger and exit the program\n");
511 } else if ((strcmp(cmd, "quit") == 0) || (strcmp(cmd, "q") == 0)) {
512 OS::PrintErr("Quitting\n");
513 OS::Exit(0);
514 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
515 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
516 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
517 // Execute the one instruction we broke at with breakpoints disabled.
518 sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
519 // Leave the debugger shell.
520 done = true;
521 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
522 if (args == 2) {
523 uint64_t value;
524 if (strcmp(arg1, "icount") == 0) {
525 value = sim_->get_icount();
526 OS::PrintErr("icount: %" Pu64 " 0x%" Px64 "\n", value, value);
527 } else if (GetValue(arg1, &value)) {
528 OS::PrintErr("%s: %" Pu64 " 0x%" Px64 "\n", arg1, value, value);
529 } else {
530 OS::PrintErr("%s unrecognized\n", arg1);
531 }
532 } else {
533 OS::PrintErr("print <reg or icount or value or *addr>\n");
534 }
535 } else if ((strcmp(cmd, "pf") == 0) || (strcmp(cmd, "printfloat") == 0)) {
536 if (args == 2) {
537 uint32_t value;
538 if (GetSValue(arg1, &value)) {
539 float svalue = bit_cast<float, uint32_t>(value);
540 OS::PrintErr("%s: %d 0x%x %.8g\n", arg1, value, value, svalue);
541 } else {
542 OS::PrintErr("%s unrecognized\n", arg1);
543 }
544 } else {
545 OS::PrintErr("printfloat <vreg or *addr>\n");
546 }
547 } else if ((strcmp(cmd, "pd") == 0) ||
548 (strcmp(cmd, "printdouble") == 0)) {
549 if (args == 2) {
550 uint64_t long_value;
551 if (GetDValue(arg1, &long_value)) {
552 double dvalue = bit_cast<double, uint64_t>(long_value);
553 OS::PrintErr("%s: %" Pu64 " 0x%" Px64 " %.8g\n", arg1, long_value,
554 long_value, dvalue);
555 } else {
556 OS::PrintErr("%s unrecognized\n", arg1);
557 }
558 } else {
559 OS::PrintErr("printdouble <vreg or *addr>\n");
560 }
561 } else if ((strcmp(cmd, "pq") == 0) || (strcmp(cmd, "printquad") == 0)) {
562 if (args == 2) {
563 simd_value_t quad_value;
564 if (GetQValue(arg1, &quad_value)) {
565 const int64_t d0 = quad_value.bits.i64[0];
566 const int64_t d1 = quad_value.bits.i64[1];
567 const double dval0 = bit_cast<double, int64_t>(d0);
568 const double dval1 = bit_cast<double, int64_t>(d1);
569 const int32_t s0 = quad_value.bits.i32[0];
570 const int32_t s1 = quad_value.bits.i32[1];
571 const int32_t s2 = quad_value.bits.i32[2];
572 const int32_t s3 = quad_value.bits.i32[3];
573 const float sval0 = bit_cast<float, int32_t>(s0);
574 const float sval1 = bit_cast<float, int32_t>(s1);
575 const float sval2 = bit_cast<float, int32_t>(s2);
576 const float sval3 = bit_cast<float, int32_t>(s3);
577 OS::PrintErr("%s: %" Pu64 " 0x%" Px64 " %.8g\n", arg1, d0, d0,
578 dval0);
579 OS::PrintErr("%s: %" Pu64 " 0x%" Px64 " %.8g\n", arg1, d1, d1,
580 dval1);
581 OS::PrintErr("%s: %d 0x%x %.8g\n", arg1, s0, s0, sval0);
582 OS::PrintErr("%s: %d 0x%x %.8g\n", arg1, s1, s1, sval1);
583 OS::PrintErr("%s: %d 0x%x %.8g\n", arg1, s2, s2, sval2);
584 OS::PrintErr("%s: %d 0x%x %.8g\n", arg1, s3, s3, sval3);
585 } else {
586 OS::PrintErr("%s unrecognized\n", arg1);
587 }
588 } else {
589 OS::PrintErr("printquad <vreg or *addr>\n");
590 }
591 } else if ((strcmp(cmd, "po") == 0) ||
592 (strcmp(cmd, "printobject") == 0)) {
593 if (args == 2) {
594 uint64_t value;
595 // Make the dereferencing '*' optional.
596 if (((arg1[0] == '*') && GetValue(arg1 + 1, &value)) ||
597 GetValue(arg1, &value)) {
598 if (IsolateGroup::Current()->heap()->Contains(value)) {
599 OS::PrintErr("%s: \n", arg1);
600#if defined(DEBUG)
601 const Object& obj = Object::Handle(
602 static_cast<ObjectPtr>(static_cast<uword>(value)));
603 obj.Print();
604#endif // defined(DEBUG)
605 } else {
606 OS::PrintErr("0x%" Px64 " is not an object reference\n", value);
607 }
608 } else {
609 OS::PrintErr("%s unrecognized\n", arg1);
610 }
611 } else {
612 OS::PrintErr("printobject <*reg or *addr>\n");
613 }
614 } else if (strcmp(cmd, "disasm") == 0) {
615 uint64_t start = 0;
616 uint64_t end = 0;
617 if (args == 1) {
618 start = sim_->get_pc();
619 end = start + (10 * Instr::kInstrSize);
620 } else if (args == 2) {
621 if (GetValue(arg1, &start)) {
622 // No length parameter passed, assume 10 instructions.
623 if (Simulator::IsIllegalAddress(start)) {
624 // If start isn't a valid address, warn and use PC instead.
625 OS::PrintErr("First argument yields invalid address: 0x%" Px64
626 "\n",
627 start);
628 OS::PrintErr("Using PC instead\n");
629 start = sim_->get_pc();
630 }
631 end = start + (10 * Instr::kInstrSize);
632 }
633 } else {
634 uint64_t length;
635 if (GetValue(arg1, &start) && GetValue(arg2, &length)) {
636 if (Simulator::IsIllegalAddress(start)) {
637 // If start isn't a valid address, warn and use PC instead.
638 OS::PrintErr("First argument yields invalid address: 0x%" Px64
639 "\n",
640 start);
641 OS::PrintErr("Using PC instead\n");
642 start = sim_->get_pc();
643 }
644 end = start + (length * Instr::kInstrSize);
645 }
646 }
647 if ((start > 0) && (end > start)) {
648 if (FLAG_support_disassembler) {
649 Disassembler::Disassemble(start, end);
650 } else {
651 OS::PrintErr("Disassembler not supported in this mode.\n");
652 }
653 } else {
654 OS::PrintErr("disasm [<address> [<number_of_instructions>]]\n");
655 }
656 } else if (strcmp(cmd, "gdb") == 0) {
657 OS::PrintErr("relinquishing control to gdb\n");
658 OS::DebugBreak();
659 OS::PrintErr("regaining control from gdb\n");
660 } else if (strcmp(cmd, "break") == 0) {
661 if (args == 2) {
662 uint64_t addr;
663 if (GetValue(arg1, &addr)) {
664 if (!SetBreakpoint(reinterpret_cast<Instr*>(addr))) {
665 OS::PrintErr("setting breakpoint failed\n");
666 }
667 } else {
668 OS::PrintErr("%s unrecognized\n", arg1);
669 }
670 } else {
671 OS::PrintErr("break <addr>\n");
672 }
673 } else if (strcmp(cmd, "del") == 0) {
674 if (!DeleteBreakpoint(nullptr)) {
675 OS::PrintErr("deleting breakpoint failed\n");
676 }
677 } else if (strcmp(cmd, "flags") == 0) {
678 OS::PrintErr("APSR: ");
679 OS::PrintErr("N flag: %d; ", static_cast<int>(sim_->n_flag_));
680 OS::PrintErr("Z flag: %d; ", static_cast<int>(sim_->z_flag_));
681 OS::PrintErr("C flag: %d; ", static_cast<int>(sim_->c_flag_));
682 OS::PrintErr("V flag: %d\n", static_cast<int>(sim_->v_flag_));
683 } else if (strcmp(cmd, "unstop") == 0) {
684 intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize;
685 Instr* stop_instr = reinterpret_cast<Instr*>(stop_pc);
686 if (stop_instr->IsExceptionGenOp()) {
687 stop_instr->SetInstructionBits(Instr::kNopInstruction);
688 } else {
689 OS::PrintErr("Not at debugger stop.\n");
690 }
691 } else if (strcmp(cmd, "trace") == 0) {
692 if (FLAG_trace_sim_after == ULLONG_MAX) {
693 FLAG_trace_sim_after = sim_->get_icount();
694 OS::PrintErr("execution tracing on\n");
695 } else {
696 FLAG_trace_sim_after = ULLONG_MAX;
697 OS::PrintErr("execution tracing off\n");
698 }
699 } else if (strcmp(cmd, "bt") == 0) {
700 Thread* thread = reinterpret_cast<Thread*>(sim_->get_register(THR));
701 thread->set_execution_state(Thread::kThreadInVM);
702 PrintBacktrace();
703 thread->set_execution_state(Thread::kThreadInGenerated);
704 } else {
705 OS::PrintErr("Unknown command: %s\n", cmd);
706 }
707 }
708 delete[] line;
709 }
710
711 // Add all the breakpoints back to stop execution and enter the debugger
712 // shell when hit.
713 RedoBreakpoints();
714
715#undef COMMAND_SIZE
716#undef ARG_SIZE
717
718#undef STR
719#undef XSTR
720}
721
722char* SimulatorDebugger::ReadLine(const char* prompt) {
723 char* result = nullptr;
724 char line_buf[256];
725 intptr_t offset = 0;
726 bool keep_going = true;
727 OS::PrintErr("%s", prompt);
728 while (keep_going) {
729 if (fgets(line_buf, sizeof(line_buf), stdin) == nullptr) {
730 // fgets got an error. Just give up.
731 if (result != nullptr) {
732 delete[] result;
733 }
734 return nullptr;
735 }
736 intptr_t len = strlen(line_buf);
737 if (len > 1 && line_buf[len - 2] == '\\' && line_buf[len - 1] == '\n') {
738 // When we read a line that ends with a "\" we remove the escape and
739 // append the remainder.
740 line_buf[len - 2] = '\n';
741 line_buf[len - 1] = 0;
742 len -= 1;
743 } else if ((len > 0) && (line_buf[len - 1] == '\n')) {
744 // Since we read a new line we are done reading the line. This
745 // will exit the loop after copying this buffer into the result.
746 keep_going = false;
747 }
748 if (result == nullptr) {
749 // Allocate the initial result and make room for the terminating '\0'
750 result = new char[len + 1];
751 if (result == nullptr) {
752 // OOM, so cannot readline anymore.
753 return nullptr;
754 }
755 } else {
756 // Allocate a new result with enough room for the new addition.
757 intptr_t new_len = offset + len + 1;
758 char* new_result = new char[new_len];
759 if (new_result == nullptr) {
760 // OOM, free the buffer allocated so far and return nullptr.
761 delete[] result;
762 return nullptr;
763 } else {
764 // Copy the existing input into the new array and set the new
765 // array as the result.
766 memmove(new_result, result, offset);
767 delete[] result;
768 result = new_result;
769 }
770 }
771 // Copy the newly read line into the result.
772 memmove(result + offset, line_buf, len);
773 offset += len;
774 }
775 ASSERT(result != nullptr);
776 result[offset] = '\0';
777 return result;
778}
779
780void Simulator::Init() {}
781
782Simulator::Simulator() : exclusive_access_addr_(0), exclusive_access_value_(0) {
783 // Setup simulator support first. Some of this information is needed to
784 // setup the architecture state.
785 // We allocate the stack here, the size is computed as the sum of
786 // the size specified by the user and the buffer space needed for
787 // handling stack overflow exceptions. To be safe in potential
788 // stack underflows we also add some underflow buffer space.
789 stack_ =
790 new char[(OSThread::GetSpecifiedStackSize() +
791 OSThread::kStackSizeBufferMax + kSimulatorStackUnderflowSize)];
792 // Low address.
793 stack_limit_ = reinterpret_cast<uword>(stack_);
794 // Limit for StackOverflowError.
795 overflow_stack_limit_ = stack_limit_ + OSThread::kStackSizeBufferMax;
796 // High address.
797 stack_base_ = overflow_stack_limit_ + OSThread::GetSpecifiedStackSize();
798
799 pc_modified_ = false;
800 icount_ = 0;
801 break_pc_ = nullptr;
802 break_instr_ = 0;
803 last_setjmp_buffer_ = nullptr;
804
805 // Setup architecture state.
806 // All registers are initialized to zero to start with.
807 for (int i = 0; i < kNumberOfCpuRegisters; i++) {
808 registers_[i] = 0;
809 }
810 n_flag_ = false;
811 z_flag_ = false;
812 c_flag_ = false;
813 v_flag_ = false;
814
815 for (int i = 0; i < kNumberOfVRegisters; i++) {
816 vregisters_[i].bits.i64[0] = 0;
817 vregisters_[i].bits.i64[1] = 0;
818 }
819
820 // The sp is initialized to point to the bottom (high address) of the
821 // allocated stack area.
822 registers_[R31] = stack_base();
823 // The lr and pc are initialized to a known bad value that will cause an
824 // access violation if the simulator ever tries to execute it.
825 registers_[LR] = kBadLR;
826 pc_ = kBadLR;
827}
828
829Simulator::~Simulator() {
830 delete[] stack_;
831 Isolate* isolate = Isolate::Current();
832 if (isolate != nullptr) {
833 isolate->set_simulator(nullptr);
834 }
835}
836
837// When the generated code calls an external reference we need to catch that in
838// the simulator. The external reference will be a function compiled for the
839// host architecture. We need to call that function instead of trying to
840// execute it with the simulator. We do that by redirecting the external
841// reference to a svc (supervisor call) instruction that is handled by
842// the simulator. We write the original destination of the jump just at a known
843// offset from the svc instruction so the simulator knows what to call.
844class Redirection {
845 public:
846 uword address_of_hlt_instruction() {
847 return reinterpret_cast<uword>(&hlt_instruction_);
848 }
849
850 uword external_function() const { return external_function_; }
851
852 Simulator::CallKind call_kind() const { return call_kind_; }
853
854 int argument_count() const { return argument_count_; }
855
856 static Redirection* Get(uword external_function,
857 Simulator::CallKind call_kind,
858 int argument_count) {
859 MutexLocker ml(mutex_);
860
861 Redirection* old_head = list_.load(std::memory_order_relaxed);
862 for (Redirection* current = old_head; current != nullptr;
863 current = current->next_) {
864 if (current->external_function_ == external_function) return current;
865 }
866
867 Redirection* redirection =
868 new Redirection(external_function, call_kind, argument_count);
869 redirection->next_ = old_head;
870
871 // Use a memory fence to ensure all pending writes are written at the time
872 // of updating the list head, so the profiling thread always has a valid
873 // list to look at.
874 list_.store(redirection, std::memory_order_release);
875
876 return redirection;
877 }
878
879 static Redirection* FromHltInstruction(Instr* hlt_instruction) {
880 char* addr_of_hlt = reinterpret_cast<char*>(hlt_instruction);
881 char* addr_of_redirection =
882 addr_of_hlt - OFFSET_OF(Redirection, hlt_instruction_);
883 return reinterpret_cast<Redirection*>(addr_of_redirection);
884 }
885
886 // Please note that this function is called by the signal handler of the
887 // profiling thread. It can therefore run at any point in time and is not
888 // allowed to hold any locks - which is precisely the reason why the list is
889 // prepend-only and a memory fence is used when writing the list head [list_]!
890 static uword FunctionForRedirect(uword address_of_hlt) {
891 for (Redirection* current = list_.load(std::memory_order_acquire);
892 current != nullptr; current = current->next_) {
893 if (current->address_of_hlt_instruction() == address_of_hlt) {
894 return current->external_function_;
895 }
896 }
897 return 0;
898 }
899
900 private:
901 Redirection(uword external_function,
902 Simulator::CallKind call_kind,
903 int argument_count)
904 : external_function_(external_function),
905 call_kind_(call_kind),
906 argument_count_(argument_count),
907 hlt_instruction_(Instr::kSimulatorRedirectInstruction),
908 next_(nullptr) {}
909
910 uword external_function_;
911 Simulator::CallKind call_kind_;
912 int argument_count_;
913 uint32_t hlt_instruction_;
914 Redirection* next_;
915 static std::atomic<Redirection*> list_;
916 static Mutex* mutex_;
917};
918
919std::atomic<Redirection*> Redirection::list_ = {nullptr};
920Mutex* Redirection::mutex_ = new Mutex();
921
922uword Simulator::RedirectExternalReference(uword function,
923 CallKind call_kind,
924 int argument_count) {
925 Redirection* redirection =
926 Redirection::Get(function, call_kind, argument_count);
927 return redirection->address_of_hlt_instruction();
928}
929
930uword Simulator::FunctionForRedirect(uword redirect) {
931 return Redirection::FunctionForRedirect(redirect);
932}
933
934// Get the active Simulator for the current isolate.
935Simulator* Simulator::Current() {
936 Isolate* isolate = Isolate::Current();
937 Simulator* simulator = isolate->simulator();
938 if (simulator == nullptr) {
939 NoSafepointScope no_safepoint;
940 simulator = new Simulator();
941 isolate->set_simulator(simulator);
942 }
943 return simulator;
944}
945
946// Sets the register in the architecture state.
947void Simulator::set_register(Instr* instr,
948 Register reg,
949 int64_t value,
950 R31Type r31t) {
951 // Register is in range.
952 ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters));
953#if !defined(DART_TARGET_OS_FUCHSIA)
954 ASSERT(instr == nullptr || reg != R18); // R18 is globally reserved on iOS.
955#endif
956
957 if ((reg != R31) || (r31t != R31IsZR)) {
958 registers_[reg] = value;
959 // If we're setting CSP, make sure it is 16-byte aligned. In truth, CSP
960 // can store addresses that are not 16-byte aligned, but loads and stores
961 // are not allowed through CSP when it is not aligned. Thus, this check is
962 // more conservative that necessary. However, it will likely be more
963 // useful to find the program locations where CSP is set to a bad value,
964 // than to find only the resulting loads/stores that would cause a fault on
965 // hardware.
966 if ((instr != nullptr) && (reg == R31) && !Utils::IsAligned(value, 16)) {
967 UnalignedAccess("CSP set", value, instr);
968 }
969
970#if defined(DEBUG)
971 if (reg == SP) {
972 // Memory below CSP can be written to at any instruction boundary by a
973 // signal handler. Simulate this to ensure we're keeping CSP far enough
974 // ahead of SP to prevent Dart frames from being trashed.
975 uword csp = registers_[R31];
976 WriteX(csp - 1 * kWordSize, icount_, nullptr);
977 WriteX(csp - 2 * kWordSize, icount_, nullptr);
978 WriteX(csp - 3 * kWordSize, icount_, nullptr);
979 WriteX(csp - 4 * kWordSize, icount_, nullptr);
980 }
981#endif
982 }
983}
984
985// Get the register from the architecture state.
986int64_t Simulator::get_register(Register reg, R31Type r31t) const {
987 ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters));
988 if ((reg == R31) && (r31t == R31IsZR)) {
989 return 0;
990 } else {
991 return registers_[reg];
992 }
993}
994
995void Simulator::set_wregister(Register reg, int32_t value, R31Type r31t) {
996 ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters));
997 // When setting in W mode, clear the high bits.
998 if ((reg != R31) || (r31t != R31IsZR)) {
999 registers_[reg] = Utils::LowHighTo64Bits(static_cast<uint32_t>(value), 0);
1000 }
1001}
1002
1003// Get the register from the architecture state.
1004int32_t Simulator::get_wregister(Register reg, R31Type r31t) const {
1005 ASSERT((reg >= 0) && (reg < kNumberOfCpuRegisters));
1006 if ((reg == R31) && (r31t == R31IsZR)) {
1007 return 0;
1008 } else {
1009 return static_cast<int32_t>(registers_[reg]);
1010 }
1011}
1012
1013int32_t Simulator::get_vregisters(VRegister reg, int idx) const {
1014 ASSERT((reg >= 0) && (reg < kNumberOfVRegisters));
1015 ASSERT((idx >= 0) && (idx <= 3));
1016 return vregisters_[reg].bits.i32[idx];
1017}
1018
1019void Simulator::set_vregisters(VRegister reg, int idx, int32_t value) {
1020 ASSERT((reg >= 0) && (reg < kNumberOfVRegisters));
1021 ASSERT((idx >= 0) && (idx <= 3));
1022 vregisters_[reg].bits.i32[idx] = value;
1023}
1024
1025int64_t Simulator::get_vregisterd(VRegister reg, int idx) const {
1026 ASSERT((reg >= 0) && (reg < kNumberOfVRegisters));
1027 ASSERT((idx == 0) || (idx == 1));
1028 return vregisters_[reg].bits.i64[idx];
1029}
1030
1031void Simulator::set_vregisterd(VRegister reg, int idx, int64_t value) {
1032 ASSERT((reg >= 0) && (reg < kNumberOfVRegisters));
1033 ASSERT((idx == 0) || (idx == 1));
1034 vregisters_[reg].bits.i64[idx] = value;
1035}
1036
1037void Simulator::get_vregister(VRegister reg, simd_value_t* value) const {
1038 ASSERT((reg >= 0) && (reg < kNumberOfVRegisters));
1039 value->bits.i64[0] = vregisters_[reg].bits.i64[0];
1040 value->bits.i64[1] = vregisters_[reg].bits.i64[1];
1041}
1042
1043void Simulator::set_vregister(VRegister reg, const simd_value_t& value) {
1044 ASSERT((reg >= 0) && (reg < kNumberOfVRegisters));
1045 vregisters_[reg].bits.i64[0] = value.bits.i64[0];
1046 vregisters_[reg].bits.i64[1] = value.bits.i64[1];
1047}
1048
1049// Raw access to the PC register.
1050void Simulator::set_pc(uint64_t value) {
1051 pc_modified_ = true;
1052 last_pc_ = pc_;
1053 pc_ = value;
1054}
1055
1056// Raw access to the pc.
1057uint64_t Simulator::get_pc() const {
1058 return pc_;
1059}
1060
1061uint64_t Simulator::get_last_pc() const {
1062 return last_pc_;
1063}
1064
1065void Simulator::HandleIllegalAccess(uword addr, Instr* instr) {
1066 uword fault_pc = get_pc();
1067 uword last_pc = get_last_pc();
1068 char buffer[128];
1069 snprintf(buffer, sizeof(buffer),
1070 "illegal memory access at 0x%" Px ", pc=0x%" Px ", last_pc=0x%" Px
1071 "\n",
1072 addr, fault_pc, last_pc);
1073 SimulatorDebugger dbg(this);
1074 dbg.Stop(instr, buffer);
1075 // The debugger will return control in non-interactive mode.
1076 FATAL("Cannot continue execution after illegal memory access.");
1077}
1078
1079// ARMv8 supports unaligned memory accesses to normal memory without trapping
1080// for all instructions except Load-Exclusive/Store-Exclusive and
1081// Load-Acquire/Store-Release.
1082// See B2.4.2 "Alignment of data accesses" for more information.
1083void Simulator::UnalignedAccess(const char* msg, uword addr, Instr* instr) {
1084 char buffer[128];
1085 snprintf(buffer, sizeof(buffer), "unaligned %s at 0x%" Px ", pc=%p\n", msg,
1086 addr, instr);
1087 SimulatorDebugger dbg(this);
1088 dbg.Stop(instr, buffer);
1089 // The debugger will not be able to single step past this instruction, but
1090 // it will be possible to disassemble the code and inspect registers.
1091 FATAL("Cannot continue execution after unaligned access.");
1092}
1093
1094void Simulator::UnimplementedInstruction(Instr* instr) {
1095 char buffer[128];
1096 snprintf(buffer, sizeof(buffer),
1097 "Unimplemented instruction: at %p, last_pc=0x%" Px64 "\n", instr,
1098 get_last_pc());
1099 SimulatorDebugger dbg(this);
1100 dbg.Stop(instr, buffer);
1101 FATAL("Cannot continue execution after unimplemented instruction.");
1102}
1103
1104bool Simulator::IsTracingExecution() const {
1105 return icount_ > FLAG_trace_sim_after;
1106}
1107
1108intptr_t Simulator::ReadX(uword addr,
1109 Instr* instr,
1110 bool must_be_aligned /* = false */) {
1111 const bool allow_unaligned_access =
1112 FLAG_sim_allow_unaligned_accesses && !must_be_aligned;
1113 if (allow_unaligned_access || (addr & 7) == 0) {
1114 return LoadUnaligned(reinterpret_cast<intptr_t*>(addr));
1115 }
1116 UnalignedAccess("read", addr, instr);
1117 return 0;
1118}
1119
1120void Simulator::WriteX(uword addr, intptr_t value, Instr* instr) {
1121 if (FLAG_sim_allow_unaligned_accesses || (addr & 7) == 0) {
1122 StoreUnaligned(reinterpret_cast<intptr_t*>(addr), value);
1123 return;
1124 }
1125 UnalignedAccess("write", addr, instr);
1126}
1127
1128uint32_t Simulator::ReadWU(uword addr,
1129 Instr* instr,
1130 bool must_be_aligned /* = false */) {
1131 const bool allow_unaligned_access =
1132 FLAG_sim_allow_unaligned_accesses && !must_be_aligned;
1133 if (allow_unaligned_access || (addr & 3) == 0) {
1134 return LoadUnaligned(reinterpret_cast<uint32_t*>(addr));
1135 }
1136 UnalignedAccess("read unsigned single word", addr, instr);
1137 return 0;
1138}
1139
1140int32_t Simulator::ReadW(uword addr, Instr* instr) {
1141 if (FLAG_sim_allow_unaligned_accesses || (addr & 3) == 0) {
1142 return LoadUnaligned(reinterpret_cast<int32_t*>(addr));
1143 }
1144 UnalignedAccess("read single word", addr, instr);
1145 return 0;
1146}
1147
1148void Simulator::WriteW(uword addr, uint32_t value, Instr* instr) {
1149 if (FLAG_sim_allow_unaligned_accesses || (addr & 3) == 0) {
1150 StoreUnaligned(reinterpret_cast<uint32_t*>(addr), value);
1151 return;
1152 }
1153 UnalignedAccess("write single word", addr, instr);
1154}
1155
1156uint16_t Simulator::ReadHU(uword addr, Instr* instr) {
1157 if (FLAG_sim_allow_unaligned_accesses || (addr & 1) == 0) {
1158 return LoadUnaligned(reinterpret_cast<uint16_t*>(addr));
1159 }
1160 UnalignedAccess("unsigned halfword read", addr, instr);
1161 return 0;
1162}
1163
1164int16_t Simulator::ReadH(uword addr, Instr* instr) {
1165 if (FLAG_sim_allow_unaligned_accesses || (addr & 1) == 0) {
1166 return LoadUnaligned(reinterpret_cast<int16_t*>(addr));
1167 }
1168 UnalignedAccess("signed halfword read", addr, instr);
1169 return 0;
1170}
1171
1172void Simulator::WriteH(uword addr, uint16_t value, Instr* instr) {
1173 if (FLAG_sim_allow_unaligned_accesses || (addr & 1) == 0) {
1174 StoreUnaligned(reinterpret_cast<uint16_t*>(addr), value);
1175 return;
1176 }
1177 UnalignedAccess("halfword write", addr, instr);
1178}
1179
1180uint8_t Simulator::ReadBU(uword addr) {
1181 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1182 return *ptr;
1183}
1184
1185int8_t Simulator::ReadB(uword addr) {
1186 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1187 return *ptr;
1188}
1189
1190void Simulator::WriteB(uword addr, uint8_t value) {
1191 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1192 *ptr = value;
1193}
1194
1195void Simulator::ClearExclusive() {
1196 exclusive_access_addr_ = 0;
1197 exclusive_access_value_ = 0;
1198}
1199
1200intptr_t Simulator::ReadExclusiveX(uword addr, Instr* instr) {
1201 exclusive_access_addr_ = addr;
1202 exclusive_access_value_ = ReadX(addr, instr, /*must_be_aligned=*/true);
1203 return exclusive_access_value_;
1204}
1205
1206intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) {
1207 exclusive_access_addr_ = addr;
1208 exclusive_access_value_ = ReadWU(addr, instr, /*must_be_aligned=*/true);
1209 return exclusive_access_value_;
1210}
1211
1212intptr_t Simulator::WriteExclusiveX(uword addr, intptr_t value, Instr* instr) {
1213 // In a well-formed code store-exclusive instruction should always follow
1214 // a corresponding load-exclusive instruction with the same address.
1215 ASSERT((exclusive_access_addr_ == 0) || (exclusive_access_addr_ == addr));
1216 if (exclusive_access_addr_ != addr) {
1217 return 1; // Failure.
1218 }
1219
1220 int64_t old_value = exclusive_access_value_;
1221 ClearExclusive();
1222
1223 auto atomic_addr = reinterpret_cast<RelaxedAtomic<int64_t>*>(addr);
1224 if (atomic_addr->compare_exchange_weak(old_value, value)) {
1225 return 0; // Success.
1226 }
1227 return 1; // Failure.
1228}
1229
1230intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) {
1231 // In a well-formed code store-exclusive instruction should always follow
1232 // a corresponding load-exclusive instruction with the same address.
1233 ASSERT((exclusive_access_addr_ == 0) || (exclusive_access_addr_ == addr));
1234 if (exclusive_access_addr_ != addr) {
1235 return 1; // Failure.
1236 }
1237
1238 int32_t old_value = static_cast<uint32_t>(exclusive_access_value_);
1239 ClearExclusive();
1240
1241 auto atomic_addr = reinterpret_cast<RelaxedAtomic<int32_t>*>(addr);
1242 if (atomic_addr->compare_exchange_weak(old_value, value)) {
1243 return 0; // Success.
1244 }
1245 return 1; // Failure.
1246}
1247
1248intptr_t Simulator::ReadAcquire(uword addr, Instr* instr) {
1249 // TODO(42074): Once we switch to C++20 we should change this to use use
1250 // `std::atomic_ref<T>` which supports performing atomic operations on
1251 // non-atomic data.
1252 COMPILE_ASSERT(sizeof(std::atomic<intptr_t>) == sizeof(intptr_t));
1253 return reinterpret_cast<std::atomic<intptr_t>*>(addr)->load(
1254 std::memory_order_acquire);
1255}
1256
1257uint32_t Simulator::ReadAcquireW(uword addr, Instr* instr) {
1258 // TODO(42074): Once we switch to C++20 we should change this to use use
1259 // `std::atomic_ref<T>` which supports performing atomic operations on
1260 // non-atomic data.
1261 COMPILE_ASSERT(sizeof(std::atomic<intptr_t>) == sizeof(intptr_t));
1262 return reinterpret_cast<std::atomic<uint32_t>*>(addr)->load(
1263 std::memory_order_acquire);
1264}
1265
1266void Simulator::WriteRelease(uword addr, intptr_t value, Instr* instr) {
1267 // TODO(42074): Once we switch to C++20 we should change this to use use
1268 // `std::atomic_ref<T>` which supports performing atomic operations on
1269 // non-atomic data.
1270 COMPILE_ASSERT(sizeof(std::atomic<intptr_t>) == sizeof(intptr_t));
1271 reinterpret_cast<std::atomic<intptr_t>*>(addr)->store(
1272 value, std::memory_order_release);
1273}
1274
1275void Simulator::WriteReleaseW(uword addr, uint32_t value, Instr* instr) {
1276 // TODO(42074): Once we switch to C++20 we should change this to use use
1277 // `std::atomic_ref<T>` which supports performing atomic operations on
1278 // non-atomic data.
1279 COMPILE_ASSERT(sizeof(std::atomic<intptr_t>) == sizeof(intptr_t));
1280 reinterpret_cast<std::atomic<uint32_t>*>(addr)->store(
1281 value, std::memory_order_release);
1282}
1283
1284// Unsupported instructions use Format to print an error and stop execution.
1285void Simulator::Format(Instr* instr, const char* format) {
1286 OS::PrintErr("Simulator found unsupported instruction:\n 0x%p: %s\n", instr,
1287 format);
1288 UNIMPLEMENTED();
1289}
1290
1291// Calculate and set the Negative and Zero flags.
1292void Simulator::SetNZFlagsW(int32_t val) {
1293 n_flag_ = (val < 0);
1294 z_flag_ = (val == 0);
1295}
1296
1297// Calculate C flag value for additions (and subtractions with adjusted args).
1298bool Simulator::CarryFromW(int32_t left, int32_t right, int32_t carry) {
1299 uint64_t uleft = static_cast<uint32_t>(left);
1300 uint64_t uright = static_cast<uint32_t>(right);
1301 uint64_t ucarry = static_cast<uint32_t>(carry);
1302 return ((uleft + uright + ucarry) >> 32) != 0;
1303}
1304
1305// Calculate V flag value for additions (and subtractions with adjusted args).
1306bool Simulator::OverflowFromW(int32_t left, int32_t right, int32_t carry) {
1307 int64_t result = static_cast<int64_t>(left) + right + carry;
1308 return (result >> 31) != (result >> 32);
1309}
1310
1311// Calculate and set the Negative and Zero flags.
1312void Simulator::SetNZFlagsX(int64_t val) {
1313 n_flag_ = (val < 0);
1314 z_flag_ = (val == 0);
1315}
1316
1317// Calculate C flag value for additions and subtractions.
1318bool Simulator::CarryFromX(int64_t alu_out,
1319 int64_t left,
1320 int64_t right,
1321 bool addition) {
1322 if (addition) {
1323 return (((left & right) | ((left | right) & ~alu_out)) >> 63) != 0;
1324 } else {
1325 return (((~left & right) | ((~left | right) & alu_out)) >> 63) == 0;
1326 }
1327}
1328
1329// Calculate V flag value for additions and subtractions.
1330bool Simulator::OverflowFromX(int64_t alu_out,
1331 int64_t left,
1332 int64_t right,
1333 bool addition) {
1334 if (addition) {
1335 return (((alu_out ^ left) & (alu_out ^ right)) >> 63) != 0;
1336 } else {
1337 return (((left ^ right) & (alu_out ^ left)) >> 63) != 0;
1338 }
1339}
1340
1341// Set the Carry flag.
1342void Simulator::SetCFlag(bool val) {
1343 c_flag_ = val;
1344}
1345
1346// Set the oVerflow flag.
1347void Simulator::SetVFlag(bool val) {
1348 v_flag_ = val;
1349}
1350
1351void Simulator::DecodeMoveWide(Instr* instr) {
1352 const Register rd = instr->RdField();
1353 const int hw = instr->HWField();
1354 const int64_t shift = hw << 4;
1355 const int64_t shifted_imm = static_cast<int64_t>(instr->Imm16Field())
1356 << shift;
1357
1358 if (instr->SFField() != 0) {
1359 if (instr->Bits(29, 2) == 0) {
1360 // Format(instr, "movn'sf 'rd, 'imm16 'hw");
1361 set_register(instr, rd, ~shifted_imm, instr->RdMode());
1362 } else if (instr->Bits(29, 2) == 2) {
1363 // Format(instr, "movz'sf 'rd, 'imm16 'hw");
1364 set_register(instr, rd, shifted_imm, instr->RdMode());
1365 } else if (instr->Bits(29, 2) == 3) {
1366 // Format(instr, "movk'sf 'rd, 'imm16 'hw");
1367 const int64_t rd_val = get_register(rd, instr->RdMode());
1368 const int64_t result = (rd_val & ~(0xffffL << shift)) | shifted_imm;
1369 set_register(instr, rd, result, instr->RdMode());
1370 } else {
1371 UnimplementedInstruction(instr);
1372 }
1373 } else if ((hw & 0x2) == 0) {
1374 if (instr->Bits(29, 2) == 0) {
1375 // Format(instr, "movn'sf 'rd, 'imm16 'hw");
1376 set_wregister(rd, ~shifted_imm & kWRegMask, instr->RdMode());
1377 } else if (instr->Bits(29, 2) == 2) {
1378 // Format(instr, "movz'sf 'rd, 'imm16 'hw");
1379 set_wregister(rd, shifted_imm & kWRegMask, instr->RdMode());
1380 } else if (instr->Bits(29, 2) == 3) {
1381 // Format(instr, "movk'sf 'rd, 'imm16 'hw");
1382 const int32_t rd_val = get_wregister(rd, instr->RdMode());
1383 const int32_t result = (rd_val & ~(0xffffL << shift)) | shifted_imm;
1384 set_wregister(rd, result, instr->RdMode());
1385 } else {
1386 UnimplementedInstruction(instr);
1387 }
1388 } else {
1389 // Dest is 32 bits, but shift is more than 32.
1390 UnimplementedInstruction(instr);
1391 }
1392}
1393
1394void Simulator::DecodeAddSubImm(Instr* instr) {
1395 const bool addition = (instr->Bit(30) == 0);
1396 // Format(instr, "addi'sf's 'rd, 'rn, 'imm12s");
1397 // Format(instr, "subi'sf's 'rd, 'rn, 'imm12s");
1398 const Register rd = instr->RdField();
1399 const Register rn = instr->RnField();
1400 uint32_t imm = (instr->Bit(22) == 1) ? (instr->Imm12Field() << 12)
1401 : (instr->Imm12Field());
1402 if (instr->SFField() != 0) {
1403 // 64-bit add.
1404 const uint64_t rn_val = get_register(rn, instr->RnMode());
1405 const uint64_t alu_out = addition ? (rn_val + imm) : (rn_val - imm);
1406 set_register(instr, rd, alu_out, instr->RdMode());
1407 if (instr->HasS()) {
1408 SetNZFlagsX(alu_out);
1409 SetCFlag(CarryFromX(alu_out, rn_val, imm, addition));
1410 SetVFlag(OverflowFromX(alu_out, rn_val, imm, addition));
1411 }
1412 } else {
1413 // 32-bit add.
1414 const uint32_t rn_val = get_wregister(rn, instr->RnMode());
1415 uint32_t carry_in = 0;
1416 if (!addition) {
1417 carry_in = 1;
1418 imm = ~imm;
1419 }
1420 const uint32_t alu_out = rn_val + imm + carry_in;
1421 set_wregister(rd, alu_out, instr->RdMode());
1422 if (instr->HasS()) {
1423 SetNZFlagsW(alu_out);
1424 SetCFlag(CarryFromW(rn_val, imm, carry_in));
1425 SetVFlag(OverflowFromW(rn_val, imm, carry_in));
1426 }
1427 }
1428}
1429
1430void Simulator::DecodeBitfield(Instr* instr) {
1431 int bitwidth = instr->SFField() == 0 ? 32 : 64;
1432 unsigned op = instr->Bits(29, 2);
1433 ASSERT(op <= 2);
1434 bool sign_extend = op == 0;
1435 bool zero_extend = op == 2;
1436 ASSERT(instr->NField() == instr->SFField());
1437 const Register rn = instr->RnField();
1438 const Register rd = instr->RdField();
1439 int64_t result = get_register(rn, instr->RnMode());
1440 int r_bit = instr->ImmRField();
1441 int s_bit = instr->ImmSField();
1442 result &= Utils::NBitMask(bitwidth);
1443 ASSERT(s_bit < bitwidth && r_bit < bitwidth);
1444 // See ARM v8 Instruction set overview 5.4.5.
1445 // If s >= r then Rd[s-r:0] := Rn[s:r], else Rd[bitwidth+s-r:bitwidth-r] :=
1446 // Rn[s:0].
1447 uword mask = Utils::NBitMask(s_bit + 1);
1448 if (s_bit >= r_bit) {
1449 mask >>= r_bit;
1450 result >>= r_bit;
1451 } else {
1452 result = static_cast<uint64_t>(result) << (bitwidth - r_bit);
1453 mask <<= bitwidth - r_bit;
1454 }
1455 result &= mask;
1456 if (sign_extend) {
1457 int highest_bit = (s_bit - r_bit) & (bitwidth - 1);
1458 int shift = 64 - highest_bit - 1;
1459 result <<= shift;
1460 result = static_cast<word>(result) >> shift;
1461 } else if (!zero_extend) {
1462 const int64_t rd_val = get_register(rd, instr->RnMode());
1463 result |= rd_val & ~mask;
1464 }
1465 if (bitwidth == 64) {
1466 set_register(instr, rd, result, instr->RdMode());
1467 } else {
1468 set_wregister(rd, result, instr->RdMode());
1469 }
1470}
1471
1472void Simulator::DecodeLogicalImm(Instr* instr) {
1473 const int op = instr->Bits(29, 2);
1474 const bool set_flags = op == 3;
1475 const int out_size = ((instr->SFField() == 0) && (instr->NField() == 0))
1476 ? kWRegSizeInBits
1477 : kXRegSizeInBits;
1478 const Register rn = instr->RnField();
1479 const Register rd = instr->RdField();
1480 const int64_t rn_val = get_register(rn, instr->RnMode());
1481 const uint64_t imm = instr->ImmLogical();
1482 if (imm == 0) {
1483 UnimplementedInstruction(instr);
1484 }
1485
1486 int64_t alu_out = 0;
1487 switch (op) {
1488 case 0:
1489 alu_out = rn_val & imm;
1490 break;
1491 case 1:
1492 alu_out = rn_val | imm;
1493 break;
1494 case 2:
1495 alu_out = rn_val ^ imm;
1496 break;
1497 case 3:
1498 alu_out = rn_val & imm;
1499 break;
1500 default:
1501 UNREACHABLE();
1502 break;
1503 }
1504
1505 if (set_flags) {
1506 if (out_size == kXRegSizeInBits) {
1507 SetNZFlagsX(alu_out);
1508 } else {
1509 SetNZFlagsW(alu_out);
1510 }
1511 SetCFlag(false);
1512 SetVFlag(false);
1513 }
1514
1515 if (out_size == kXRegSizeInBits) {
1516 set_register(instr, rd, alu_out, instr->RdMode());
1517 } else {
1518 set_wregister(rd, alu_out, instr->RdMode());
1519 }
1520}
1521
1522void Simulator::DecodePCRel(Instr* instr) {
1523 const int op = instr->Bit(31);
1524 if (op == 0) {
1525 // Format(instr, "adr 'rd, 'pcrel")
1526 const Register rd = instr->RdField();
1527 const uint64_t immhi = instr->SImm19Field();
1528 const uint64_t immlo = instr->Bits(29, 2);
1529 const uint64_t off = (immhi << 2) | immlo;
1530 const uint64_t dest = get_pc() + off;
1531 set_register(instr, rd, dest, instr->RdMode());
1532 } else {
1533 UnimplementedInstruction(instr);
1534 }
1535}
1536
1537void Simulator::DecodeDPImmediate(Instr* instr) {
1538 if (instr->IsMoveWideOp()) {
1539 DecodeMoveWide(instr);
1540 } else if (instr->IsAddSubImmOp()) {
1541 DecodeAddSubImm(instr);
1542 } else if (instr->IsBitfieldOp()) {
1543 DecodeBitfield(instr);
1544 } else if (instr->IsLogicalImmOp()) {
1545 DecodeLogicalImm(instr);
1546 } else if (instr->IsPCRelOp()) {
1547 DecodePCRel(instr);
1548 } else {
1549 UnimplementedInstruction(instr);
1550 }
1551}
1552
1553void Simulator::DecodeCompareAndBranch(Instr* instr) {
1554 const int op = instr->Bit(24);
1555 const Register rt = instr->RtField();
1556 const uint64_t imm19 = instr->SImm19Field();
1557 const uint64_t dest = get_pc() + (imm19 << 2);
1558 const uint64_t mask = instr->SFField() == 1 ? kXRegMask : kWRegMask;
1559 const uint64_t rt_val = get_register(rt, R31IsZR) & mask;
1560 if (op == 0) {
1561 // Format(instr, "cbz'sf 'rt, 'dest19");
1562 if (rt_val == 0) {
1563 set_pc(dest);
1564 }
1565 } else {
1566 // Format(instr, "cbnz'sf 'rt, 'dest19");
1567 if (rt_val != 0) {
1568 set_pc(dest);
1569 }
1570 }
1571}
1572
1573bool Simulator::ConditionallyExecute(Instr* instr) {
1574 Condition cond;
1575 if (instr->IsConditionalSelectOp()) {
1576 cond = instr->SelectConditionField();
1577 } else {
1578 cond = instr->ConditionField();
1579 }
1580 switch (cond) {
1581 case EQ:
1582 return z_flag_;
1583 case NE:
1584 return !z_flag_;
1585 case CS:
1586 return c_flag_;
1587 case CC:
1588 return !c_flag_;
1589 case MI:
1590 return n_flag_;
1591 case PL:
1592 return !n_flag_;
1593 case VS:
1594 return v_flag_;
1595 case VC:
1596 return !v_flag_;
1597 case HI:
1598 return c_flag_ && !z_flag_;
1599 case LS:
1600 return !c_flag_ || z_flag_;
1601 case GE:
1602 return n_flag_ == v_flag_;
1603 case LT:
1604 return n_flag_ != v_flag_;
1605 case GT:
1606 return !z_flag_ && (n_flag_ == v_flag_);
1607 case LE:
1608 return z_flag_ || (n_flag_ != v_flag_);
1609 case AL:
1610 return true;
1611 default:
1612 UNREACHABLE();
1613 }
1614 return false;
1615}
1616
1617void Simulator::DecodeConditionalBranch(Instr* instr) {
1618 // Format(instr, "b'cond 'dest19");
1619 if ((instr->Bit(24) != 0) || (instr->Bit(4) != 0)) {
1620 UnimplementedInstruction(instr);
1621 }
1622 const uint64_t imm19 = instr->SImm19Field();
1623 const uint64_t dest = get_pc() + (imm19 << 2);
1624 if (ConditionallyExecute(instr)) {
1625 set_pc(dest);
1626 }
1627}
1628
1629// Calls into the Dart runtime are based on this interface.
1630typedef void (*SimulatorRuntimeCall)(NativeArguments arguments);
1631
1632// Calls to leaf Dart runtime functions are based on this interface.
1633typedef int64_t (*SimulatorLeafRuntimeCall)(int64_t r0,
1634 int64_t r1,
1635 int64_t r2,
1636 int64_t r3,
1637 int64_t r4,
1638 int64_t r5,
1639 int64_t r6,
1640 int64_t r7);
1641
1642// [target] has several different signatures that differ from
1643// SimulatorLeafRuntimeCall. We can call them all from here only because in
1644// X64's calling conventions a function can be called with extra arguments
1645// and the callee will see the first arguments and won't unbalance the stack.
1646NO_SANITIZE_UNDEFINED("function")
1647static int64_t InvokeLeafRuntime(SimulatorLeafRuntimeCall target,
1648 int64_t r0,
1649 int64_t r1,
1650 int64_t r2,
1651 int64_t r3,
1652 int64_t r4,
1653 int64_t r5,
1654 int64_t r6,
1655 int64_t r7) {
1656 return target(r0, r1, r2, r3, r4, r5, r6, r7);
1657}
1658
1659// Calls to leaf float Dart runtime functions are based on this interface.
1660typedef double (*SimulatorLeafFloatRuntimeCall)(double d0,
1661 double d1,
1662 double d2,
1663 double d3,
1664 double d4,
1665 double d5,
1666 double d6,
1667 double d7);
1668
1669// [target] has several different signatures that differ from
1670// SimulatorFloatLeafRuntimeCall. We can call them all from here only because in
1671// X64's calling conventions a function can be called with extra arguments
1672// and the callee will see the first arguments and won't unbalance the stack.
1673NO_SANITIZE_UNDEFINED("function")
1674static double InvokeFloatLeafRuntime(SimulatorLeafFloatRuntimeCall target,
1675 double d0,
1676 double d1,
1677 double d2,
1678 double d3,
1679 double d4,
1680 double d5,
1681 double d6,
1682 double d7) {
1683 return target(d0, d1, d2, d3, d4, d5, d6, d7);
1684}
1685
1686// Calls to native Dart functions are based on this interface.
1687typedef void (*SimulatorNativeCallWrapper)(Dart_NativeArguments arguments,
1688 Dart_NativeFunction target);
1689
1690void Simulator::DoRedirectedCall(Instr* instr) {
1691 SimulatorSetjmpBuffer buffer(this);
1692 if (!setjmp(buffer.buffer_)) {
1693 int64_t saved_lr = get_register(LR);
1694 Redirection* redirection = Redirection::FromHltInstruction(instr);
1695 uword external = redirection->external_function();
1696 if (IsTracingExecution()) {
1697 THR_Print("Call to host function at 0x%" Pd "\n", external);
1698 }
1699
1700 if (redirection->call_kind() == kRuntimeCall) {
1701 NativeArguments* arguments =
1702 reinterpret_cast<NativeArguments*>(get_register(R0));
1703 SimulatorRuntimeCall target =
1704 reinterpret_cast<SimulatorRuntimeCall>(external);
1705 target(*arguments);
1706 ClobberVolatileRegisters();
1707 } else if (redirection->call_kind() == kLeafRuntimeCall) {
1708 ASSERT((0 <= redirection->argument_count()) &&
1709 (redirection->argument_count() <= 8));
1710 SimulatorLeafRuntimeCall target =
1711 reinterpret_cast<SimulatorLeafRuntimeCall>(external);
1712 const int64_t r0 = get_register(R0);
1713 const int64_t r1 = get_register(R1);
1714 const int64_t r2 = get_register(R2);
1715 const int64_t r3 = get_register(R3);
1716 const int64_t r4 = get_register(R4);
1717 const int64_t r5 = get_register(R5);
1718 const int64_t r6 = get_register(R6);
1719 const int64_t r7 = get_register(R7);
1720 const int64_t res =
1721 InvokeLeafRuntime(target, r0, r1, r2, r3, r4, r5, r6, r7);
1722 ClobberVolatileRegisters();
1723 set_register(instr, R0, res); // Set returned result from function.
1724 } else if (redirection->call_kind() == kLeafFloatRuntimeCall) {
1725 ASSERT((0 <= redirection->argument_count()) &&
1726 (redirection->argument_count() <= 8));
1727 SimulatorLeafFloatRuntimeCall target =
1728 reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external);
1729 const double d0 = bit_cast<double, int64_t>(get_vregisterd(V0, 0));
1730 const double d1 = bit_cast<double, int64_t>(get_vregisterd(V1, 0));
1731 const double d2 = bit_cast<double, int64_t>(get_vregisterd(V2, 0));
1732 const double d3 = bit_cast<double, int64_t>(get_vregisterd(V3, 0));
1733 const double d4 = bit_cast<double, int64_t>(get_vregisterd(V4, 0));
1734 const double d5 = bit_cast<double, int64_t>(get_vregisterd(V5, 0));
1735 const double d6 = bit_cast<double, int64_t>(get_vregisterd(V6, 0));
1736 const double d7 = bit_cast<double, int64_t>(get_vregisterd(V7, 0));
1737 const double res =
1738 InvokeFloatLeafRuntime(target, d0, d1, d2, d3, d4, d5, d6, d7);
1739 ClobberVolatileRegisters();
1740 set_vregisterd(V0, 0, bit_cast<int64_t, double>(res));
1741 set_vregisterd(V0, 1, 0);
1742 } else {
1743 ASSERT(redirection->call_kind() == kNativeCallWrapper);
1744 SimulatorNativeCallWrapper wrapper =
1745 reinterpret_cast<SimulatorNativeCallWrapper>(external);
1746 Dart_NativeArguments arguments =
1747 reinterpret_cast<Dart_NativeArguments>(get_register(R0));
1748 Dart_NativeFunction target =
1749 reinterpret_cast<Dart_NativeFunction>(get_register(R1));
1750 wrapper(arguments, target);
1751 ClobberVolatileRegisters();
1752 }
1753
1754 // Return.
1755 set_pc(saved_lr);
1756 } else {
1757 // Coming via long jump from a throw. Continue to exception handler.
1758 }
1759}
1760
1761void Simulator::ClobberVolatileRegisters() {
1762 // Clear atomic reservation.
1763 exclusive_access_addr_ = exclusive_access_value_ = 0;
1764
1765 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
1766 if ((kAbiVolatileCpuRegs & (1 << i)) != 0) {
1767 registers_[i] = icount_;
1768 }
1769 }
1770
1771 for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
1772 if ((kAbiVolatileFpuRegs & (1 << i)) != 0) {
1773 vregisters_[i].bits.i64[0] = icount_;
1774 vregisters_[i].bits.i64[1] = icount_;
1775 }
1776 }
1777}
1778
1779void Simulator::DecodeExceptionGen(Instr* instr) {
1780 if ((instr->Bits(0, 2) == 1) && (instr->Bits(2, 3) == 0) &&
1781 (instr->Bits(21, 3) == 0)) {
1782 // Format(instr, "svc 'imm16");
1783 UnimplementedInstruction(instr);
1784 } else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) &&
1785 (instr->Bits(21, 3) == 1)) {
1786 // Format(instr, "brk 'imm16");
1787 SimulatorDebugger dbg(this);
1788 int32_t imm = instr->Imm16Field();
1789 char buffer[32];
1790 snprintf(buffer, sizeof(buffer), "brk #0x%x", imm);
1791 set_pc(get_pc() + Instr::kInstrSize);
1792 dbg.Stop(instr, buffer);
1793 } else if ((instr->Bits(0, 2) == 0) && (instr->Bits(2, 3) == 0) &&
1794 (instr->Bits(21, 3) == 2)) {
1795 // Format(instr, "hlt 'imm16");
1796 uint16_t imm = static_cast<uint16_t>(instr->Imm16Field());
1797 if (imm == Instr::kSimulatorBreakCode) {
1798 SimulatorDebugger dbg(this);
1799 dbg.Stop(instr, "breakpoint");
1800 } else if (imm == Instr::kSimulatorRedirectCode) {
1801 DoRedirectedCall(instr);
1802 } else {
1803 UnimplementedInstruction(instr);
1804 }
1805 } else {
1806 UnimplementedInstruction(instr);
1807 }
1808}
1809
1810void Simulator::DecodeSystem(Instr* instr) {
1811 if (instr->InstructionBits() == CLREX) {
1812 // Format(instr, "clrex");
1813 ClearExclusive();
1814 return;
1815 }
1816
1817 if ((instr->Bits(0, 8) == 0x1f) && (instr->Bits(12, 4) == 2) &&
1818 (instr->Bits(16, 3) == 3) && (instr->Bits(19, 2) == 0) &&
1819 (instr->Bit(21) == 0)) {
1820 if (instr->Bits(8, 4) == 0) {
1821 // Format(instr, "nop");
1822 } else {
1823 UnimplementedInstruction(instr);
1824 }
1825 } else {
1826 UnimplementedInstruction(instr);
1827 }
1828}
1829
1830void Simulator::DecodeTestAndBranch(Instr* instr) {
1831 const int op = instr->Bit(24);
1832 const int bitpos = instr->Bits(19, 5) | (instr->Bit(31) << 5);
1833 const uint64_t imm14 = instr->SImm14Field();
1834 const uint64_t dest = get_pc() + (imm14 << 2);
1835 const Register rt = instr->RtField();
1836 const uint64_t rt_val = get_register(rt, R31IsZR);
1837 if (op == 0) {
1838 // Format(instr, "tbz'sf 'rt, 'bitpos, 'dest14");
1839 if ((rt_val & (1ull << bitpos)) == 0) {
1840 set_pc(dest);
1841 }
1842 } else {
1843 // Format(instr, "tbnz'sf 'rt, 'bitpos, 'dest14");
1844 if ((rt_val & (1ull << bitpos)) != 0) {
1845 set_pc(dest);
1846 }
1847 }
1848}
1849
1850void Simulator::DecodeUnconditionalBranch(Instr* instr) {
1851 const bool link = instr->Bit(31) == 1;
1852 const uint64_t imm26 = instr->SImm26Field();
1853 const uint64_t dest = get_pc() + (imm26 << 2);
1854 const uint64_t ret = get_pc() + Instr::kInstrSize;
1855 set_pc(dest);
1856 if (link) {
1857 set_register(instr, LR, ret);
1858 }
1859}
1860
1861void Simulator::DecodeUnconditionalBranchReg(Instr* instr) {
1862 if ((instr->Bits(0, 5) == 0) && (instr->Bits(10, 6) == 0) &&
1863 (instr->Bits(16, 5) == 0x1f)) {
1864 switch (instr->Bits(21, 4)) {
1865 case 0: {
1866 // Format(instr, "br 'rn");
1867 const Register rn = instr->RnField();
1868 const int64_t dest = get_register(rn, instr->RnMode());
1869 set_pc(dest);
1870 break;
1871 }
1872 case 1: {
1873 // Format(instr, "blr 'rn");
1874 const Register rn = instr->RnField();
1875 const int64_t dest = get_register(rn, instr->RnMode());
1876 const int64_t ret = get_pc() + Instr::kInstrSize;
1877 set_pc(dest);
1878 set_register(instr, LR, ret);
1879 break;
1880 }
1881 case 2: {
1882 // Format(instr, "ret 'rn");
1883 const Register rn = instr->RnField();
1884 const int64_t rn_val = get_register(rn, instr->RnMode());
1885 set_pc(rn_val);
1886 break;
1887 }
1888 default:
1889 UnimplementedInstruction(instr);
1890 break;
1891 }
1892 } else {
1893 UnimplementedInstruction(instr);
1894 }
1895}
1896
1897DART_FORCE_INLINE
1898void Simulator::DecodeCompareBranch(Instr* instr) {
1899 if (instr->IsCompareAndBranchOp()) {
1900 DecodeCompareAndBranch(instr);
1901 } else if (instr->IsConditionalBranchOp()) {
1902 DecodeConditionalBranch(instr);
1903 } else if (instr->IsExceptionGenOp()) {
1904 DecodeExceptionGen(instr);
1905 } else if (instr->IsSystemOp()) {
1906 DecodeSystem(instr);
1907 } else if (instr->IsTestAndBranchOp()) {
1908 DecodeTestAndBranch(instr);
1909 } else if (instr->IsUnconditionalBranchOp()) {
1910 DecodeUnconditionalBranch(instr);
1911 } else if (instr->IsUnconditionalBranchRegOp()) {
1912 DecodeUnconditionalBranchReg(instr);
1913 } else {
1914 UnimplementedInstruction(instr);
1915 }
1916}
1917
1918void Simulator::DecodeLoadStoreReg(Instr* instr) {
1919 // Calculate the address.
1920 const Register rn = instr->RnField();
1921 const Register rt = instr->RtField();
1922 const VRegister vt = instr->VtField();
1923 const int64_t rn_val = get_register(rn, R31IsSP);
1924 const uint32_t size = (instr->Bit(26) == 1)
1925 ? ((instr->Bit(23) << 2) | instr->SzField())
1926 : instr->SzField();
1927 uword address = 0;
1928 uword wb_address = 0;
1929 bool wb = false;
1930 if (instr->Bit(24) == 1) {
1931 // addr = rn + scaled unsigned 12-bit immediate offset.
1932 const uint32_t imm12 = static_cast<uint32_t>(instr->Imm12Field());
1933 const uint32_t offset = imm12 << size;
1934 address = rn_val + offset;
1935 } else if (instr->Bits(10, 2) == 0) {
1936 // addr = rn + signed 9-bit immediate offset.
1937 wb = false;
1938 const int64_t offset = static_cast<int64_t>(instr->SImm9Field());
1939 address = rn_val + offset;
1940 wb_address = rn_val;
1941 } else if (instr->Bit(10) == 1) {
1942 // addr = rn + signed 9-bit immediate offset.
1943 wb = true;
1944 const int64_t offset = static_cast<int64_t>(instr->SImm9Field());
1945 if (instr->Bit(11) == 1) {
1946 // Pre-index.
1947 address = rn_val + offset;
1948 wb_address = address;
1949 } else {
1950 // Post-index.
1951 address = rn_val;
1952 wb_address = rn_val + offset;
1953 }
1954 } else if (instr->Bits(10, 2) == 2) {
1955 // addr = rn + (rm EXT optionally scaled by operand instruction size).
1956 const Register rm = instr->RmField();
1957 const Extend ext = instr->ExtendTypeField();
1958 const uint8_t scale = (ext == UXTX) && (instr->Bit(12) == 1) ? size : 0;
1959 const int64_t rm_val = get_register(rm, R31IsZR);
1960 const int64_t offset = ExtendOperand(kXRegSizeInBits, rm_val, ext, scale);
1961 address = rn_val + offset;
1962 } else {
1963 UnimplementedInstruction(instr);
1964 return;
1965 }
1966
1967 // Check the address.
1968 if (IsIllegalAddress(address)) {
1969 HandleIllegalAccess(address, instr);
1970 return;
1971 }
1972
1973 // Do access.
1974 if (instr->Bit(26) == 1) {
1975 if (instr->Bit(22) == 0) {
1976 // Format(instr, "fstr'fsz 'vt, 'memop");
1977 const int64_t vt_val = get_vregisterd(vt, 0);
1978 switch (size) {
1979 case 2:
1980 WriteW(address, vt_val & kWRegMask, instr);
1981 break;
1982 case 3:
1983 WriteX(address, vt_val, instr);
1984 break;
1985 case 4: {
1986 simd_value_t val;
1987 get_vregister(vt, &val);
1988 WriteX(address, val.bits.i64[0], instr);
1989 WriteX(address + kWordSize, val.bits.i64[1], instr);
1990 break;
1991 }
1992 default:
1993 UnimplementedInstruction(instr);
1994 return;
1995 }
1996 } else {
1997 // Format(instr, "fldr'fsz 'vt, 'memop");
1998 switch (size) {
1999 case 2:
2000 set_vregisterd(vt, 0, static_cast<int64_t>(ReadWU(address, instr)));
2001 set_vregisterd(vt, 1, 0);
2002 break;
2003 case 3:
2004 set_vregisterd(vt, 0, ReadX(address, instr));
2005 set_vregisterd(vt, 1, 0);
2006 break;
2007 case 4: {
2008 simd_value_t val;
2009 val.bits.i64[0] = ReadX(address, instr);
2010 val.bits.i64[1] = ReadX(address + kWordSize, instr);
2011 set_vregister(vt, val);
2012 break;
2013 }
2014 default:
2015 UnimplementedInstruction(instr);
2016 return;
2017 }
2018 }
2019 } else {
2020 if (instr->Bits(22, 2) == 0) {
2021 // Format(instr, "str'sz 'rt, 'memop");
2022 const int32_t rt_val32 = get_wregister(rt, R31IsZR);
2023 switch (size) {
2024 case 0: {
2025 const uint8_t val = static_cast<uint8_t>(rt_val32);
2026 WriteB(address, val);
2027 break;
2028 }
2029 case 1: {
2030 const uint16_t val = static_cast<uint16_t>(rt_val32);
2031 WriteH(address, val, instr);
2032 break;
2033 }
2034 case 2: {
2035 const uint32_t val = static_cast<uint32_t>(rt_val32);
2036 WriteW(address, val, instr);
2037 break;
2038 }
2039 case 3: {
2040 const int64_t val = get_register(rt, R31IsZR);
2041 WriteX(address, val, instr);
2042 break;
2043 }
2044 default:
2045 UNREACHABLE();
2046 break;
2047 }
2048 } else {
2049 // Format(instr, "ldr'sz 'rt, 'memop");
2050 // Undefined case.
2051 if ((size == 3) && (instr->Bits(22, 2) == 3)) {
2052 UnimplementedInstruction(instr);
2053 return;
2054 }
2055
2056 // Read the value.
2057 const bool is_signed = instr->Bit(23) == 1;
2058 // Write the W register for signed values when size < 2.
2059 // Write the W register for unsigned values when size == 2.
2060 const bool use_w =
2061 (is_signed && (instr->Bit(22) == 1)) || (!is_signed && (size == 2));
2062 int64_t val = 0; // Sign extend into an int64_t.
2063 switch (size) {
2064 case 0: {
2065 if (is_signed) {
2066 val = static_cast<int64_t>(ReadB(address));
2067 } else {
2068 val = static_cast<int64_t>(ReadBU(address));
2069 }
2070 break;
2071 }
2072 case 1: {
2073 if (is_signed) {
2074 val = static_cast<int64_t>(ReadH(address, instr));
2075 } else {
2076 val = static_cast<int64_t>(ReadHU(address, instr));
2077 }
2078 break;
2079 }
2080 case 2: {
2081 if (is_signed) {
2082 val = static_cast<int64_t>(ReadW(address, instr));
2083 } else {
2084 val = static_cast<int64_t>(ReadWU(address, instr));
2085 }
2086 break;
2087 }
2088 case 3:
2089 val = ReadX(address, instr);
2090 break;
2091 default:
2092 UNREACHABLE();
2093 break;
2094 }
2095
2096 // Write to register.
2097 if (use_w) {
2098 set_wregister(rt, static_cast<int32_t>(val), R31IsZR);
2099 } else {
2100 set_register(instr, rt, val, R31IsZR);
2101 }
2102 }
2103 }
2104
2105 // Do writeback.
2106 if (wb) {
2107 set_register(instr, rn, wb_address, R31IsSP);
2108 }
2109}
2110
2111void Simulator::DecodeLoadStoreRegPair(Instr* instr) {
2112 const int32_t opc = instr->Bits(23, 3);
2113 const Register rn = instr->RnField();
2114 const int64_t rn_val = get_register(rn, R31IsSP);
2115 const intptr_t shift =
2116 (instr->Bit(26) == 1) ? 2 + instr->SzField() : 2 + instr->SFField();
2117 const intptr_t size = 1 << shift;
2118 const int32_t offset = (static_cast<uint32_t>(instr->SImm7Field()) << shift);
2119 uword address = 0;
2120 uword wb_address = 0;
2121 bool wb = false;
2122
2123 if ((instr->Bits(30, 2) == 3)) {
2124 UnimplementedInstruction(instr);
2125 return;
2126 }
2127
2128 // Calculate address.
2129 switch (opc) {
2130 case 1:
2131 address = rn_val;
2132 wb_address = rn_val + offset;
2133 wb = true;
2134 break;
2135 case 2:
2136 address = rn_val + offset;
2137 break;
2138 case 3:
2139 address = rn_val + offset;
2140 wb_address = address;
2141 wb = true;
2142 break;
2143 default:
2144 UnimplementedInstruction(instr);
2145 return;
2146 }
2147
2148 // Check the address.
2149 if (IsIllegalAddress(address)) {
2150 HandleIllegalAccess(address, instr);
2151 return;
2152 }
2153
2154 // Do access.
2155 if (instr->Bit(26) == 1) {
2156 // SIMD/FP.
2157 const VRegister vt = instr->VtField();
2158 const VRegister vt2 = instr->Vt2Field();
2159 if (instr->Bit(22) != 0) {
2160 // Format(instr, "ldp 'vt, 'vt2, 'memop");
2161 switch (size) {
2162 case 4:
2163 set_vregisterd(vt, 0, static_cast<int64_t>(ReadWU(address, instr)));
2164 set_vregisterd(vt, 1, 0);
2165 set_vregisterd(vt2, 0,
2166 static_cast<int64_t>(ReadWU(address + 4, instr)));
2167 set_vregisterd(vt2, 1, 0);
2168 break;
2169 case 8:
2170 set_vregisterd(vt, 0, ReadX(address, instr));
2171 set_vregisterd(vt, 1, 0);
2172 set_vregisterd(vt2, 0, ReadX(address + 8, instr));
2173 set_vregisterd(vt2, 1, 0);
2174 break;
2175 case 16: {
2176 simd_value_t val;
2177 val.bits.i64[0] = ReadX(address, instr);
2178 val.bits.i64[1] = ReadX(address + 8, instr);
2179 set_vregister(vt, val);
2180 val.bits.i64[0] = ReadX(address + 16, instr);
2181 val.bits.i64[1] = ReadX(address + 24, instr);
2182 set_vregister(vt2, val);
2183 break;
2184 }
2185 default:
2186 UnimplementedInstruction(instr);
2187 return;
2188 }
2189 } else {
2190 // Format(instr, "stp 'vt, 'vt2, 'memop");
2191 switch (size) {
2192 case 4:
2193 WriteW(address, get_vregisterd(vt, 0) & kWRegMask, instr);
2194 WriteW(address + 4, get_vregisterd(vt2, 0) & kWRegMask, instr);
2195 break;
2196 case 8:
2197 WriteX(address, get_vregisterd(vt, 0), instr);
2198 WriteX(address + 8, get_vregisterd(vt2, 0), instr);
2199 break;
2200 case 16: {
2201 simd_value_t val;
2202 get_vregister(vt, &val);
2203 WriteX(address, val.bits.i64[0], instr);
2204 WriteX(address + 8, val.bits.i64[1], instr);
2205 get_vregister(vt2, &val);
2206 WriteX(address + 16, val.bits.i64[0], instr);
2207 WriteX(address + 24, val.bits.i64[1], instr);
2208 break;
2209 }
2210 default:
2211 UnimplementedInstruction(instr);
2212 return;
2213 }
2214 }
2215 } else {
2216 // Integer.
2217 const Register rt = instr->RtField();
2218 const Register rt2 = instr->Rt2Field();
2219 if (instr->Bit(22) != 0) {
2220 // Format(instr, "ldp'sf 'rt, 'rt2, 'memop");
2221 const bool is_signed = instr->Bit(30) == 1;
2222 int64_t val1 = 0; // Sign extend into an int64_t.
2223 int64_t val2 = 0;
2224 if (instr->Bit(31) == 1) {
2225 // 64-bit read.
2226 val1 = ReadX(address, instr);
2227 val2 = ReadX(address + size, instr);
2228 } else {
2229 if (is_signed) {
2230 val1 = static_cast<int64_t>(ReadW(address, instr));
2231 val2 = static_cast<int64_t>(ReadW(address + size, instr));
2232 } else {
2233 val1 = static_cast<int64_t>(ReadWU(address, instr));
2234 val2 = static_cast<int64_t>(ReadWU(address + size, instr));
2235 }
2236 }
2237 // Write to register.
2238 if (instr->Bit(31) == 1) {
2239 set_register(instr, rt, val1, R31IsZR);
2240 set_register(instr, rt2, val2, R31IsZR);
2241 } else {
2242 set_wregister(rt, static_cast<int32_t>(val1), R31IsZR);
2243 set_wregister(rt2, static_cast<int32_t>(val2), R31IsZR);
2244 }
2245 } else {
2246 // Format(instr, "stp'sf 'rt, 'rt2, 'memop");
2247 if (instr->Bit(31) == 1) {
2248 const int64_t val1 = get_register(rt, R31IsZR);
2249 const int64_t val2 = get_register(rt2, R31IsZR);
2250 WriteX(address, val1, instr);
2251 WriteX(address + size, val2, instr);
2252 } else {
2253 const int32_t val1 = get_wregister(rt, R31IsZR);
2254 const int32_t val2 = get_wregister(rt2, R31IsZR);
2255 WriteW(address, val1, instr);
2256 WriteW(address + size, val2, instr);
2257 }
2258 }
2259 }
2260
2261 // Do writeback.
2262 if (wb) {
2263 set_register(instr, rn, wb_address, R31IsSP);
2264 }
2265}
2266
2267void Simulator::DecodeLoadRegLiteral(Instr* instr) {
2268 if ((instr->Bit(31) != 0) || (instr->Bit(29) != 0) ||
2269 (instr->Bits(24, 3) != 0)) {
2270 UnimplementedInstruction(instr);
2271 }
2272
2273 const Register rt = instr->RtField();
2274 const int64_t off = instr->SImm19Field() << 2;
2275 const int64_t pc = reinterpret_cast<int64_t>(instr);
2276 const int64_t address = pc + off;
2277 const int64_t val = ReadX(address, instr);
2278 if (instr->Bit(30) != 0) {
2279 // Format(instr, "ldrx 'rt, 'pcldr");
2280 set_register(instr, rt, val, R31IsZR);
2281 } else {
2282 // Format(instr, "ldrw 'rt, 'pcldr");
2283 set_wregister(rt, static_cast<int32_t>(val), R31IsZR);
2284 }
2285}
2286
2287void Simulator::DecodeLoadStoreExclusive(Instr* instr) {
2288 if (instr->Bit(21) != 0 || instr->Bit(23) != instr->Bit(15)) {
2289 UNIMPLEMENTED();
2290 }
2291 const int32_t size = instr->Bits(30, 2);
2292 if (size != 3 && size != 2) {
2293 UNIMPLEMENTED();
2294 }
2295 const Register rs = instr->RsField();
2296 const Register rn = instr->RnField();
2297 const Register rt = instr->RtField();
2298 ASSERT(instr->Rt2Field() == R31); // Should-Be-One
2299 const bool is_load = instr->Bit(22) == 1;
2300 const bool is_exclusive = instr->Bit(23) == 0;
2301 const bool is_ordered = instr->Bit(15) == 1;
2302 if (is_load) {
2303 const bool is_load_acquire = !is_exclusive && is_ordered;
2304 if (is_load_acquire) {
2305 ASSERT(rs == R31); // Should-Be-One
2306 // Format(instr, "ldar 'rt, 'rn");
2307 const int64_t addr = get_register(rn, R31IsSP);
2308 const intptr_t value =
2309 (size == 3) ? ReadAcquire(addr, instr) : ReadAcquireW(addr, instr);
2310 set_register(instr, rt, value, R31IsSP);
2311 } else {
2312 ASSERT(rs == R31); // Should-Be-One
2313 // Format(instr, "ldxr 'rt, 'rn");
2314 const int64_t addr = get_register(rn, R31IsSP);
2315 const intptr_t value = (size == 3) ? ReadExclusiveX(addr, instr)
2316 : ReadExclusiveW(addr, instr);
2317 set_register(instr, rt, value, R31IsSP);
2318 }
2319 } else {
2320 const bool is_store_release = !is_exclusive && is_ordered;
2321 if (is_store_release) {
2322 ASSERT(rs == R31); // Should-Be-One
2323 // Format(instr, "stlr 'rt, 'rn");
2324 const uword value = get_register(rt, R31IsSP);
2325 const uword addr = get_register(rn, R31IsSP);
2326 if (size == 3) {
2327 WriteRelease(addr, value, instr);
2328 } else {
2329 WriteReleaseW(addr, static_cast<uint32_t>(value), instr);
2330 }
2331 } else {
2332 // Format(instr, "stxr 'rs, 'rt, 'rn");
2333 const uword value = get_register(rt, R31IsSP);
2334 const uword addr = get_register(rn, R31IsSP);
2335 const intptr_t status =
2336 (size == 3)
2337 ? WriteExclusiveX(addr, value, instr)
2338 : WriteExclusiveW(addr, static_cast<uint32_t>(value), instr);
2339 set_register(instr, rs, status, R31IsSP);
2340 }
2341 }
2342}
2343
2344void Simulator::DecodeAtomicMemory(Instr* instr) {
2345 const int32_t size = instr->Bits(30, 2);
2346 std::memory_order order;
2347 switch (instr->Bits(22, 2)) {
2348 case 3:
2349 order = std::memory_order_acq_rel;
2350 break;
2351 case 2:
2352 order = std::memory_order_acquire;
2353 break;
2354 case 1:
2355 order = std::memory_order_release;
2356 break;
2357 case 0:
2358 order = std::memory_order_relaxed;
2359 break;
2360 }
2361 const Register rs = instr->RsField();
2362 const Register rn = instr->RnField();
2363 const Register rt = instr->RtField();
2364 const int32_t opc = instr->Bits(12, 3);
2365
2366 if (size == 3) {
2367 uint64_t in = get_register(rs, R31IsZR);
2368 auto addr =
2369 reinterpret_cast<std::atomic<uint64_t>*>(get_register(rn, R31IsSP));
2370 uint64_t out;
2371 switch (opc) {
2372 case 1:
2373 out = addr->fetch_and(~in, order);
2374 break;
2375 case 3:
2376 out = addr->fetch_or(in, order);
2377 break;
2378 default:
2379 UNIMPLEMENTED();
2380 }
2381 set_register(instr, rt, out, R31IsZR);
2382 } else if (size == 2) {
2383 ASSERT(size == 2);
2384 uint32_t in = get_wregister(rs, R31IsZR);
2385 auto addr =
2386 reinterpret_cast<std::atomic<uint32_t>*>(get_register(rn, R31IsSP));
2387 uint32_t out;
2388 switch (opc) {
2389 case 1:
2390 out = addr->fetch_and(~in, order);
2391 break;
2392 case 3:
2393 out = addr->fetch_or(in, order);
2394 break;
2395 default:
2396 UNIMPLEMENTED();
2397 }
2398 set_wregister(rt, out, R31IsZR);
2399 } else {
2400 UNIMPLEMENTED();
2401 }
2402}
2403
2404DART_FORCE_INLINE
2405void Simulator::DecodeLoadStore(Instr* instr) {
2406 if (instr->IsAtomicMemoryOp()) {
2407 DecodeAtomicMemory(instr);
2408 } else if (instr->IsLoadStoreRegOp()) {
2409 DecodeLoadStoreReg(instr);
2410 } else if (instr->IsLoadStoreRegPairOp()) {
2411 DecodeLoadStoreRegPair(instr);
2412 } else if (instr->IsLoadRegLiteralOp()) {
2413 DecodeLoadRegLiteral(instr);
2414 } else if (instr->IsLoadStoreExclusiveOp()) {
2415 DecodeLoadStoreExclusive(instr);
2416 } else {
2417 UnimplementedInstruction(instr);
2418 }
2419}
2420
2421int64_t Simulator::ShiftOperand(uint8_t reg_size,
2422 int64_t value,
2423 Shift shift_type,
2424 uint8_t amount) {
2425 if (amount == 0) {
2426 return value;
2427 }
2428 int64_t mask = reg_size == kXRegSizeInBits ? kXRegMask : kWRegMask;
2429 switch (shift_type) {
2430 case LSL:
2431 return (static_cast<uint64_t>(value) << amount) & mask;
2432 case LSR:
2433 return static_cast<uint64_t>(value) >> amount;
2434 case ASR: {
2435 // Shift used to restore the sign.
2436 uint8_t s_shift = kXRegSizeInBits - reg_size;
2437 // Value with its sign restored.
2438 int64_t s_value = (value << s_shift) >> s_shift;
2439 return (s_value >> amount) & mask;
2440 }
2441 case ROR: {
2442 if (reg_size == kWRegSizeInBits) {
2443 value &= kWRegMask;
2444 }
2445 return (static_cast<uint64_t>(value) >> amount) |
2446 ((static_cast<uint64_t>(value) & ((1ULL << amount) - 1ULL))
2447 << (reg_size - amount));
2448 }
2449 default:
2450 UNIMPLEMENTED();
2451 return 0;
2452 }
2453}
2454
2455int64_t Simulator::ExtendOperand(uint8_t reg_size,
2456 int64_t value,
2457 Extend extend_type,
2458 uint8_t amount) {
2459 switch (extend_type) {
2460 case UXTB:
2461 value &= 0xff;
2462 break;
2463 case UXTH:
2464 value &= 0xffff;
2465 break;
2466 case UXTW:
2467 value &= 0xffffffff;
2468 break;
2469 case SXTB:
2470 value = static_cast<int64_t>(static_cast<uint64_t>(value) << 56) >> 56;
2471 break;
2472 case SXTH:
2473 value = static_cast<int64_t>(static_cast<uint64_t>(value) << 48) >> 48;
2474 break;
2475 case SXTW:
2476 value = static_cast<int64_t>(static_cast<uint64_t>(value) << 32) >> 32;
2477 break;
2478 case UXTX:
2479 case SXTX:
2480 break;
2481 default:
2482 UNREACHABLE();
2483 break;
2484 }
2485 int64_t mask = (reg_size == kXRegSizeInBits) ? kXRegMask : kWRegMask;
2486 return (static_cast<uint64_t>(value) << amount) & mask;
2487}
2488
2489int64_t Simulator::DecodeShiftExtendOperand(Instr* instr) {
2490 const Register rm = instr->RmField();
2491 const int64_t rm_val = get_register(rm, R31IsZR);
2492 const uint8_t size =
2493 instr->SFField() != 0 ? kXRegSizeInBits : kWRegSizeInBits;
2494 if (instr->IsShift()) {
2495 const Shift shift_type = instr->ShiftTypeField();
2496 const uint8_t shift_amount = instr->Imm6Field();
2497 return ShiftOperand(size, rm_val, shift_type, shift_amount);
2498 } else {
2499 ASSERT(instr->IsExtend());
2500 const Extend extend_type = instr->ExtendTypeField();
2501 const uint8_t shift_amount = instr->Imm3Field();
2502 return ExtendOperand(size, rm_val, extend_type, shift_amount);
2503 }
2504 UNREACHABLE();
2505 return -1;
2506}
2507
2508void Simulator::DecodeAddSubShiftExt(Instr* instr) {
2509 // Format(instr, "add'sf's 'rd, 'rn, 'shift_op");
2510 // also, sub, cmp, etc.
2511 const bool addition = (instr->Bit(30) == 0);
2512 const Register rd = instr->RdField();
2513 const Register rn = instr->RnField();
2514 const uint64_t rm_val = DecodeShiftExtendOperand(instr);
2515 if (instr->SFField() != 0) {
2516 // 64-bit add.
2517 const uint64_t rn_val = get_register(rn, instr->RnMode());
2518 const uint64_t alu_out = rn_val + (addition ? rm_val : -rm_val);
2519 set_register(instr, rd, alu_out, instr->RdMode());
2520 if (instr->HasS()) {
2521 SetNZFlagsX(alu_out);
2522 SetCFlag(CarryFromX(alu_out, rn_val, rm_val, addition));
2523 SetVFlag(OverflowFromX(alu_out, rn_val, rm_val, addition));
2524 }
2525 } else {
2526 // 32-bit add.
2527 const uint32_t rn_val = get_wregister(rn, instr->RnMode());
2528 uint32_t rm_val32 = static_cast<uint32_t>(rm_val & kWRegMask);
2529 uint32_t carry_in = 0;
2530 if (!addition) {
2531 carry_in = 1;
2532 rm_val32 = ~rm_val32;
2533 }
2534 const uint32_t alu_out = rn_val + rm_val32 + carry_in;
2535 set_wregister(rd, alu_out, instr->RdMode());
2536 if (instr->HasS()) {
2537 SetNZFlagsW(alu_out);
2538 SetCFlag(CarryFromW(rn_val, rm_val32, carry_in));
2539 SetVFlag(OverflowFromW(rn_val, rm_val32, carry_in));
2540 }
2541 }
2542}
2543
2544void Simulator::DecodeAddSubWithCarry(Instr* instr) {
2545 // Format(instr, "adc'sf's 'rd, 'rn, 'rm");
2546 // Format(instr, "sbc'sf's 'rd, 'rn, 'rm");
2547 const bool addition = (instr->Bit(30) == 0);
2548 const Register rd = instr->RdField();
2549 const Register rn = instr->RnField();
2550 const Register rm = instr->RmField();
2551 const uint64_t rn_val64 = get_register(rn, R31IsZR);
2552 const uint32_t rn_val32 = get_wregister(rn, R31IsZR);
2553 const uint64_t rm_val64 = get_register(rm, R31IsZR);
2554 uint32_t rm_val32 = get_wregister(rm, R31IsZR);
2555 const uint32_t carry_in = c_flag_ ? 1 : 0;
2556 if (instr->SFField() != 0) {
2557 // 64-bit add.
2558 const uint64_t alu_out =
2559 rn_val64 + (addition ? rm_val64 : ~rm_val64) + carry_in;
2560 set_register(instr, rd, alu_out, R31IsZR);
2561 if (instr->HasS()) {
2562 SetNZFlagsX(alu_out);
2563 SetCFlag(CarryFromX(alu_out, rn_val64, rm_val64, addition));
2564 SetVFlag(OverflowFromX(alu_out, rn_val64, rm_val64, addition));
2565 }
2566 } else {
2567 // 32-bit add.
2568 if (!addition) {
2569 rm_val32 = ~rm_val32;
2570 }
2571 const uint32_t alu_out = rn_val32 + rm_val32 + carry_in;
2572 set_wregister(rd, alu_out, R31IsZR);
2573 if (instr->HasS()) {
2574 SetNZFlagsW(alu_out);
2575 SetCFlag(CarryFromW(rn_val32, rm_val32, carry_in));
2576 SetVFlag(OverflowFromW(rn_val32, rm_val32, carry_in));
2577 }
2578 }
2579}
2580
2581void Simulator::DecodeLogicalShift(Instr* instr) {
2582 const int op = (instr->Bits(29, 2) << 1) | instr->Bit(21);
2583 const Register rd = instr->RdField();
2584 const Register rn = instr->RnField();
2585 const int64_t rn_val = get_register(rn, instr->RnMode());
2586 const int64_t rm_val = DecodeShiftExtendOperand(instr);
2587 int64_t alu_out = 0;
2588 switch (op) {
2589 case 0:
2590 // Format(instr, "and'sf 'rd, 'rn, 'shift_op");
2591 alu_out = rn_val & rm_val;
2592 break;
2593 case 1:
2594 // Format(instr, "bic'sf 'rd, 'rn, 'shift_op");
2595 alu_out = rn_val & (~rm_val);
2596 break;
2597 case 2:
2598 // Format(instr, "orr'sf 'rd, 'rn, 'shift_op");
2599 alu_out = rn_val | rm_val;
2600 break;
2601 case 3:
2602 // Format(instr, "orn'sf 'rd, 'rn, 'shift_op");
2603 alu_out = rn_val | (~rm_val);
2604 break;
2605 case 4:
2606 // Format(instr, "eor'sf 'rd, 'rn, 'shift_op");
2607 alu_out = rn_val ^ rm_val;
2608 break;
2609 case 5:
2610 // Format(instr, "eon'sf 'rd, 'rn, 'shift_op");
2611 alu_out = rn_val ^ (~rm_val);
2612 break;
2613 case 6:
2614 // Format(instr, "and'sfs 'rd, 'rn, 'shift_op");
2615 alu_out = rn_val & rm_val;
2616 break;
2617 case 7:
2618 // Format(instr, "bic'sfs 'rd, 'rn, 'shift_op");
2619 alu_out = rn_val & (~rm_val);
2620 break;
2621 default:
2622 UNREACHABLE();
2623 break;
2624 }
2625
2626 // Set flags if ands or bics.
2627 if ((op == 6) || (op == 7)) {
2628 if (instr->SFField() == 1) {
2629 SetNZFlagsX(alu_out);
2630 } else {
2631 SetNZFlagsW(alu_out);
2632 }
2633 SetCFlag(false);
2634 SetVFlag(false);
2635 }
2636
2637 if (instr->SFField() == 1) {
2638 set_register(instr, rd, alu_out, instr->RdMode());
2639 } else {
2640 set_wregister(rd, alu_out & kWRegMask, instr->RdMode());
2641 }
2642}
2643
2644static int64_t divide64(int64_t top, int64_t bottom, bool is_signed) {
2645 // ARM64 does not trap on integer division by zero. The destination register
2646 // is instead set to 0.
2647 if (bottom == 0) {
2648 return 0;
2649 }
2650
2651 if (is_signed) {
2652 // INT_MIN / -1 = INT_MIN.
2653 if ((top == static_cast<int64_t>(0x8000000000000000LL)) &&
2654 (bottom == static_cast<int64_t>(0xffffffffffffffffLL))) {
2655 return static_cast<int64_t>(0x8000000000000000LL);
2656 } else {
2657 return top / bottom;
2658 }
2659 } else {
2660 const uint64_t utop = static_cast<uint64_t>(top);
2661 const uint64_t ubottom = static_cast<uint64_t>(bottom);
2662 return static_cast<int64_t>(utop / ubottom);
2663 }
2664}
2665
2666static int32_t divide32(int32_t top, int32_t bottom, bool is_signed) {
2667 // ARM64 does not trap on integer division by zero. The destination register
2668 // is instead set to 0.
2669 if (bottom == 0) {
2670 return 0;
2671 }
2672
2673 if (is_signed) {
2674 // INT_MIN / -1 = INT_MIN.
2675 if ((top == static_cast<int32_t>(0x80000000)) &&
2676 (bottom == static_cast<int32_t>(0xffffffff))) {
2677 return static_cast<int32_t>(0x80000000);
2678 } else {
2679 return top / bottom;
2680 }
2681 } else {
2682 const uint32_t utop = static_cast<uint32_t>(top);
2683 const uint32_t ubottom = static_cast<uint32_t>(bottom);
2684 return static_cast<int32_t>(utop / ubottom);
2685 }
2686}
2687
2688void Simulator::DecodeMiscDP1Source(Instr* instr) {
2689 if (instr->Bit(29) != 0) {
2690 UnimplementedInstruction(instr);
2691 }
2692
2693 const Register rd = instr->RdField();
2694 const Register rn = instr->RnField();
2695 const int op = instr->Bits(10, 10);
2696 const int64_t rn_val64 = get_register(rn, R31IsZR);
2697 const int32_t rn_val32 = get_wregister(rn, R31IsZR);
2698 switch (op) {
2699 case 4: {
2700 // Format(instr, "clz'sf 'rd, 'rn");
2701 if (instr->SFField() == 1) {
2702 const uint64_t rd_val = Utils::CountLeadingZeros64(rn_val64);
2703 set_register(instr, rd, rd_val, R31IsZR);
2704 } else {
2705 const uint32_t rd_val = Utils::CountLeadingZeros32(rn_val32);
2706 set_wregister(rd, rd_val, R31IsZR);
2707 }
2708 break;
2709 }
2710 case 0: {
2711 // Format(instr, "rbit'sf 'rd, 'rn");
2712 if (instr->SFField() == 1) {
2713 const uint64_t rd_val = Utils::ReverseBits64(rn_val64);
2714 set_register(instr, rd, rd_val, R31IsZR);
2715 } else {
2716 const uint32_t rd_val = Utils::ReverseBits32(rn_val32);
2717 set_wregister(rd, rd_val, R31IsZR);
2718 }
2719 break;
2720 }
2721 default:
2722 UnimplementedInstruction(instr);
2723 break;
2724 }
2725}
2726
2727void Simulator::DecodeMiscDP2Source(Instr* instr) {
2728 if (instr->Bit(29) != 0) {
2729 UnimplementedInstruction(instr);
2730 }
2731
2732 const Register rd = instr->RdField();
2733 const Register rn = instr->RnField();
2734 const Register rm = instr->RmField();
2735 const int op = instr->Bits(10, 5);
2736 const int64_t rn_val64 = get_register(rn, R31IsZR);
2737 const int64_t rm_val64 = get_register(rm, R31IsZR);
2738 const int32_t rn_val32 = get_wregister(rn, R31IsZR);
2739 const int32_t rm_val32 = get_wregister(rm, R31IsZR);
2740 switch (op) {
2741 case 2:
2742 case 3: {
2743 // Format(instr, "udiv'sf 'rd, 'rn, 'rm");
2744 // Format(instr, "sdiv'sf 'rd, 'rn, 'rm");
2745 const bool is_signed = instr->Bit(10) == 1;
2746 if (instr->SFField() == 1) {
2747 set_register(instr, rd, divide64(rn_val64, rm_val64, is_signed),
2748 R31IsZR);
2749 } else {
2750 set_wregister(rd, divide32(rn_val32, rm_val32, is_signed), R31IsZR);
2751 }
2752 break;
2753 }
2754 case 8: {
2755 // Format(instr, "lsl'sf 'rd, 'rn, 'rm");
2756 if (instr->SFField() == 1) {
2757 const uint64_t rn_u64 = static_cast<uint64_t>(rn_val64);
2758 const int64_t alu_out = rn_u64 << (rm_val64 & (kXRegSizeInBits - 1));
2759 set_register(instr, rd, alu_out, R31IsZR);
2760 } else {
2761 const uint32_t rn_u32 = static_cast<uint32_t>(rn_val32);
2762 const int32_t alu_out = rn_u32 << (rm_val32 & (kXRegSizeInBits - 1));
2763 set_wregister(rd, alu_out, R31IsZR);
2764 }
2765 break;
2766 }
2767 case 9: {
2768 // Format(instr, "lsr'sf 'rd, 'rn, 'rm");
2769 if (instr->SFField() == 1) {
2770 const uint64_t rn_u64 = static_cast<uint64_t>(rn_val64);
2771 const int64_t alu_out = rn_u64 >> (rm_val64 & (kXRegSizeInBits - 1));
2772 set_register(instr, rd, alu_out, R31IsZR);
2773 } else {
2774 const uint32_t rn_u32 = static_cast<uint32_t>(rn_val32);
2775 const int32_t alu_out = rn_u32 >> (rm_val32 & (kXRegSizeInBits - 1));
2776 set_wregister(rd, alu_out, R31IsZR);
2777 }
2778 break;
2779 }
2780 case 10: {
2781 // Format(instr, "asr'sf 'rd, 'rn, 'rm");
2782 if (instr->SFField() == 1) {
2783 const int64_t alu_out = rn_val64 >> (rm_val64 & (kXRegSizeInBits - 1));
2784 set_register(instr, rd, alu_out, R31IsZR);
2785 } else {
2786 const int32_t alu_out = rn_val32 >> (rm_val32 & (kXRegSizeInBits - 1));
2787 set_wregister(rd, alu_out, R31IsZR);
2788 }
2789 break;
2790 }
2791 default:
2792 UnimplementedInstruction(instr);
2793 break;
2794 }
2795}
2796
2797void Simulator::DecodeMiscDP3Source(Instr* instr) {
2798 const Register rd = instr->RdField();
2799 const Register rn = instr->RnField();
2800 const Register rm = instr->RmField();
2801 const Register ra = instr->RaField();
2802 if ((instr->Bits(29, 2) == 0) && (instr->Bits(21, 3) == 0) &&
2803 (instr->Bit(15) == 0)) {
2804 // Format(instr, "madd'sf 'rd, 'rn, 'rm, 'ra");
2805 if (instr->SFField() == 1) {
2806 const uint64_t rn_val = get_register(rn, R31IsZR);
2807 const uint64_t rm_val = get_register(rm, R31IsZR);
2808 const uint64_t ra_val = get_register(ra, R31IsZR);
2809 const uint64_t alu_out = ra_val + (rn_val * rm_val);
2810 set_register(instr, rd, alu_out, R31IsZR);
2811 } else {
2812 const uint32_t rn_val = get_wregister(rn, R31IsZR);
2813 const uint32_t rm_val = get_wregister(rm, R31IsZR);
2814 const uint32_t ra_val = get_wregister(ra, R31IsZR);
2815 const uint32_t alu_out = ra_val + (rn_val * rm_val);
2816 set_wregister(rd, alu_out, R31IsZR);
2817 }
2818 } else if ((instr->Bits(29, 2) == 0) && (instr->Bits(21, 3) == 0) &&
2819 (instr->Bit(15) == 1)) {
2820 // Format(instr, "msub'sf 'rd, 'rn, 'rm, 'ra");
2821 if (instr->SFField() == 1) {
2822 const uint64_t rn_val = get_register(rn, R31IsZR);
2823 const uint64_t rm_val = get_register(rm, R31IsZR);
2824 const uint64_t ra_val = get_register(ra, R31IsZR);
2825 const uint64_t alu_out = ra_val - (rn_val * rm_val);
2826 set_register(instr, rd, alu_out, R31IsZR);
2827 } else {
2828 const uint32_t rn_val = get_wregister(rn, R31IsZR);
2829 const uint32_t rm_val = get_wregister(rm, R31IsZR);
2830 const uint32_t ra_val = get_wregister(ra, R31IsZR);
2831 const uint32_t alu_out = ra_val - (rn_val * rm_val);
2832 set_wregister(rd, alu_out, R31IsZR);
2833 }
2834 } else if ((instr->Bits(29, 3) == 4) && (instr->Bits(21, 3) == 2) &&
2835 (instr->Bit(15) == 0)) {
2836 ASSERT(ra == R31); // Should-Be-One
2837 // Format(instr, "smulh 'rd, 'rn, 'rm");
2838 const int64_t rn_val = get_register(rn, R31IsZR);
2839 const int64_t rm_val = get_register(rm, R31IsZR);
2840#if defined(DART_HOST_OS_WINDOWS)
2841 // Visual Studio does not support __int128.
2842 int64_t alu_out;
2843 Multiply128(rn_val, rm_val, &alu_out);
2844#else
2845 const __int128 res =
2846 static_cast<__int128>(rn_val) * static_cast<__int128>(rm_val);
2847 const int64_t alu_out = static_cast<int64_t>(res >> 64);
2848#endif // DART_HOST_OS_WINDOWS
2849 set_register(instr, rd, alu_out, R31IsZR);
2850 } else if ((instr->Bits(29, 3) == 4) && (instr->Bits(21, 3) == 6) &&
2851 (instr->Bit(15) == 0)) {
2852 ASSERT(ra == R31); // Should-Be-One
2853 // Format(instr, "umulh 'rd, 'rn, 'rm");
2854 const uint64_t rn_val = get_register(rn, R31IsZR);
2855 const uint64_t rm_val = get_register(rm, R31IsZR);
2856#if defined(DART_HOST_OS_WINDOWS)
2857 // Visual Studio does not support __int128.
2858 uint64_t alu_out;
2859 UnsignedMultiply128(rn_val, rm_val, &alu_out);
2860#else
2861 const unsigned __int128 res = static_cast<unsigned __int128>(rn_val) *
2862 static_cast<unsigned __int128>(rm_val);
2863 const uint64_t alu_out = static_cast<uint64_t>(res >> 64);
2864#endif // DART_HOST_OS_WINDOWS
2865 set_register(instr, rd, alu_out, R31IsZR);
2866 } else if ((instr->Bits(29, 3) == 4) && (instr->Bit(15) == 0)) {
2867 if (instr->Bits(21, 3) == 5) {
2868 // Format(instr, "umaddl 'rd, 'rn, 'rm, 'ra");
2869 const uint64_t rn_val = static_cast<uint32_t>(get_wregister(rn, R31IsZR));
2870 const uint64_t rm_val = static_cast<uint32_t>(get_wregister(rm, R31IsZR));
2871 const uint64_t ra_val = get_register(ra, R31IsZR);
2872 const uint64_t alu_out = ra_val + (rn_val * rm_val);
2873 set_register(instr, rd, alu_out, R31IsZR);
2874 } else {
2875 // Format(instr, "smaddl 'rd, 'rn, 'rm, 'ra");
2876 const int64_t rn_val = static_cast<int32_t>(get_wregister(rn, R31IsZR));
2877 const int64_t rm_val = static_cast<int32_t>(get_wregister(rm, R31IsZR));
2878 const int64_t ra_val = get_register(ra, R31IsZR);
2879 const int64_t alu_out = ra_val + (rn_val * rm_val);
2880 set_register(instr, rd, alu_out, R31IsZR);
2881 }
2882 } else {
2883 UnimplementedInstruction(instr);
2884 }
2885}
2886
2887void Simulator::DecodeConditionalSelect(Instr* instr) {
2888 const Register rd = instr->RdField();
2889 const Register rn = instr->RnField();
2890 const Register rm = instr->RmField();
2891 const int64_t rm_val64 = get_register(rm, R31IsZR);
2892 const int32_t rm_val32 = get_wregister(rm, R31IsZR);
2893 const int64_t rn_val64 = get_register(rn, instr->RnMode());
2894 const int32_t rn_val32 = get_wregister(rn, instr->RnMode());
2895 int64_t result64 = 0;
2896 int32_t result32 = 0;
2897
2898 if ((instr->Bits(29, 2) == 0) && (instr->Bits(10, 2) == 0)) {
2899 // Format(instr, "mov'sf'cond 'rd, 'rn, 'rm");
2900 result64 = rm_val64;
2901 result32 = rm_val32;
2902 if (ConditionallyExecute(instr)) {
2903 result64 = rn_val64;
2904 result32 = rn_val32;
2905 }
2906 } else if ((instr->Bits(29, 2) == 0) && (instr->Bits(10, 2) == 1)) {
2907 // Format(instr, "csinc'sf'cond 'rd, 'rn, 'rm");
2908 result64 = rm_val64 + 1;
2909 result32 = rm_val32 + 1;
2910 if (ConditionallyExecute(instr)) {
2911 result64 = rn_val64;
2912 result32 = rn_val32;
2913 }
2914 } else if ((instr->Bits(29, 2) == 2) && (instr->Bits(10, 2) == 0)) {
2915 // Format(instr, "csinv'sf'cond 'rd, 'rn, 'rm");
2916 result64 = ~rm_val64;
2917 result32 = ~rm_val32;
2918 if (ConditionallyExecute(instr)) {
2919 result64 = rn_val64;
2920 result32 = rn_val32;
2921 }
2922 } else if ((instr->Bits(29, 2) == 2) && (instr->Bits(10, 2) == 1)) {
2923 // Format(instr, "csneg'sf'cond 'rd, 'rn, 'rm");
2924 result64 = -rm_val64;
2925 result32 = -rm_val32;
2926 if (ConditionallyExecute(instr)) {
2927 result64 = rn_val64;
2928 result32 = rn_val32;
2929 }
2930 } else {
2931 UnimplementedInstruction(instr);
2932 return;
2933 }
2934
2935 if (instr->SFField() == 1) {
2936 set_register(instr, rd, result64, instr->RdMode());
2937 } else {
2938 set_wregister(rd, result32, instr->RdMode());
2939 }
2940}
2941
2942void Simulator::DecodeDPRegister(Instr* instr) {
2943 if (instr->IsAddSubShiftExtOp()) {
2944 DecodeAddSubShiftExt(instr);
2945 } else if (instr->IsAddSubWithCarryOp()) {
2946 DecodeAddSubWithCarry(instr);
2947 } else if (instr->IsLogicalShiftOp()) {
2948 DecodeLogicalShift(instr);
2949 } else if (instr->IsMiscDP1SourceOp()) {
2950 DecodeMiscDP1Source(instr);
2951 } else if (instr->IsMiscDP2SourceOp()) {
2952 DecodeMiscDP2Source(instr);
2953 } else if (instr->IsMiscDP3SourceOp()) {
2954 DecodeMiscDP3Source(instr);
2955 } else if (instr->IsConditionalSelectOp()) {
2956 DecodeConditionalSelect(instr);
2957 } else {
2958 UnimplementedInstruction(instr);
2959 }
2960}
2961
2962void Simulator::DecodeSIMDCopy(Instr* instr) {
2963 const int32_t Q = instr->Bit(30);
2964 const int32_t op = instr->Bit(29);
2965 const int32_t imm4 = instr->Bits(11, 4);
2966 const int32_t imm5 = instr->Bits(16, 5);
2967
2968 int32_t idx4 = -1;
2969 int32_t idx5 = -1;
2970 int32_t element_bytes;
2971 if ((imm5 & 0x1) != 0) {
2972 idx4 = imm4;
2973 idx5 = imm5 >> 1;
2974 element_bytes = 1;
2975 } else if ((imm5 & 0x2) != 0) {
2976 idx4 = imm4 >> 1;
2977 idx5 = imm5 >> 2;
2978 element_bytes = 2;
2979 } else if ((imm5 & 0x4) != 0) {
2980 idx4 = imm4 >> 2;
2981 idx5 = imm5 >> 3;
2982 element_bytes = 4;
2983 } else if ((imm5 & 0x8) != 0) {
2984 idx4 = imm4 >> 3;
2985 idx5 = imm5 >> 4;
2986 element_bytes = 8;
2987 } else {
2988 UnimplementedInstruction(instr);
2989 return;
2990 }
2991 ASSERT((idx4 != -1) && (idx5 != -1));
2992
2993 const VRegister vd = instr->VdField();
2994 const VRegister vn = instr->VnField();
2995 const Register rn = instr->RnField();
2996 const Register rd = instr->RdField();
2997 if ((op == 0) && (imm4 == 7)) {
2998 if (Q == 0) {
2999 // Format(instr, "vmovrs 'rd, 'vn'idx5");
3000 set_wregister(rd, get_vregisters(vn, idx5), R31IsZR);
3001 } else {
3002 // Format(instr, "vmovrd 'rd, 'vn'idx5");
3003 set_register(instr, rd, get_vregisterd(vn, idx5), R31IsZR);
3004 }
3005 } else if ((Q == 1) && (op == 0) && (imm4 == 0)) {
3006 // Format(instr, "vdup'csz 'vd, 'vn'idx5");
3007 if (element_bytes == 4) {
3008 for (int i = 0; i < 4; i++) {
3009 set_vregisters(vd, i, get_vregisters(vn, idx5));
3010 }
3011 } else if (element_bytes == 8) {
3012 for (int i = 0; i < 2; i++) {
3013 set_vregisterd(vd, i, get_vregisterd(vn, idx5));
3014 }
3015 } else {
3016 UnimplementedInstruction(instr);
3017 return;
3018 }
3019 } else if ((Q == 1) && (op == 0) && (imm4 == 3)) {
3020 // Format(instr, "vins'csz 'vd'idx5, 'rn");
3021 if (element_bytes == 4) {
3022 set_vregisters(vd, idx5, get_wregister(rn, R31IsZR));
3023 } else if (element_bytes == 8) {
3024 set_vregisterd(vd, idx5, get_register(rn, R31IsZR));
3025 } else {
3026 UnimplementedInstruction(instr);
3027 }
3028 } else if ((Q == 1) && (op == 0) && (imm4 == 1)) {
3029 // Format(instr, "vdup'csz 'vd, 'rn");
3030 if (element_bytes == 4) {
3031 for (int i = 0; i < 4; i++) {
3032 set_vregisters(vd, i, get_wregister(rn, R31IsZR));
3033 }
3034 } else if (element_bytes == 8) {
3035 for (int i = 0; i < 2; i++) {
3036 set_vregisterd(vd, i, get_register(rn, R31IsZR));
3037 }
3038 } else {
3039 UnimplementedInstruction(instr);
3040 return;
3041 }
3042 } else if ((Q == 1) && (op == 1)) {
3043 // Format(instr, "vins'csz 'vd'idx5, 'vn'idx4");
3044 if (element_bytes == 4) {
3045 set_vregisters(vd, idx5, get_vregisters(vn, idx4));
3046 } else if (element_bytes == 8) {
3047 set_vregisterd(vd, idx5, get_vregisterd(vn, idx4));
3048 } else {
3049 UnimplementedInstruction(instr);
3050 }
3051 } else {
3052 UnimplementedInstruction(instr);
3053 }
3054}
3055
3056static float vminf(float f1, float f2) {
3057 if (f1 == f2) {
3058 // take care of (-0.0) < 0.0, (they are equal according to minss)
3059 return signbit(f1) ? f1 : f2;
3060 }
3061 return f1 > f2 ? f2 : f1;
3062}
3063
3064static float vmaxf(float f1, float f2) {
3065 if (f1 == f2) {
3066 // take care of (-0.0) < 0.0, (they are equal according to minss)
3067 return signbit(f1) ? f2 : f1;
3068 }
3069 return f1 < f2 ? f2 : f1;
3070}
3071
3072static double vmind(double f1, double f2) {
3073 if (f1 == f2) {
3074 // take care of (-0.0) < 0.0, (they are equal according to minss)
3075 return signbit(f1) ? f1 : f2;
3076 }
3077 return f1 > f2 ? f2 : f1;
3078}
3079
3080static double vmaxd(double f1, double f2) {
3081 if (f1 == f2) {
3082 // take care of (-0.0) < 0.0, (they are equal according to minss)
3083 return signbit(f1) ? f2 : f1;
3084 }
3085 return f1 < f2 ? f2 : f1;
3086}
3087
3088void Simulator::DecodeSIMDThreeSame(Instr* instr) {
3089 const int Q = instr->Bit(30);
3090 const int U = instr->Bit(29);
3091 const int opcode = instr->Bits(11, 5);
3092
3093 if (Q == 0) {
3094 UnimplementedInstruction(instr);
3095 return;
3096 }
3097
3098 const VRegister vd = instr->VdField();
3099 const VRegister vn = instr->VnField();
3100 const VRegister vm = instr->VmField();
3101 if (instr->Bit(22) == 0) {
3102 // f32 case.
3103 for (int idx = 0; idx < 4; idx++) {
3104 const int32_t vn_val = get_vregisters(vn, idx);
3105 const int32_t vm_val = get_vregisters(vm, idx);
3106 const float vn_flt = bit_cast<float, int32_t>(vn_val);
3107 const float vm_flt = bit_cast<float, int32_t>(vm_val);
3108 int32_t res = 0.0;
3109 if ((U == 0) && (opcode == 0x3)) {
3110 if (instr->Bit(23) == 0) {
3111 // Format(instr, "vand 'vd, 'vn, 'vm");
3112 res = vn_val & vm_val;
3113 } else {
3114 // Format(instr, "vorr 'vd, 'vn, 'vm");
3115 res = vn_val | vm_val;
3116 }
3117 } else if ((U == 1) && (opcode == 0x3)) {
3118 // Format(instr, "veor 'vd, 'vn, 'vm");
3119 res = vn_val ^ vm_val;
3120 } else if ((U == 0) && (opcode == 0x10)) {
3121 // Format(instr, "vadd'vsz 'vd, 'vn, 'vm");
3122 res = vn_val + vm_val;
3123 } else if ((U == 1) && (opcode == 0x10)) {
3124 // Format(instr, "vsub'vsz 'vd, 'vn, 'vm");
3125 res = vn_val - vm_val;
3126 } else if ((U == 0) && (opcode == 0x1a)) {
3127 if (instr->Bit(23) == 0) {
3128 // Format(instr, "vadd'vsz 'vd, 'vn, 'vm");
3129 res = bit_cast<int32_t, float>(vn_flt + vm_flt);
3130 } else {
3131 // Format(instr, "vsub'vsz 'vd, 'vn, 'vm");
3132 res = bit_cast<int32_t, float>(vn_flt - vm_flt);
3133 }
3134 } else if ((U == 1) && (opcode == 0x1b)) {
3135 // Format(instr, "vmul'vsz 'vd, 'vn, 'vm");
3136 res = bit_cast<int32_t, float>(vn_flt * vm_flt);
3137 } else if ((U == 1) && (opcode == 0x1f)) {
3138 // Format(instr, "vdiv'vsz 'vd, 'vn, 'vm");
3139 res = bit_cast<int32_t, float>(vn_flt / vm_flt);
3140 } else if ((U == 0) && (opcode == 0x1c)) {
3141 // Format(instr, "vceq'vsz 'vd, 'vn, 'vm");
3142 res = (vn_flt == vm_flt) ? 0xffffffff : 0;
3143 } else if ((U == 1) && (opcode == 0x1c)) {
3144 if (instr->Bit(23) == 1) {
3145 // Format(instr, "vcgt'vsz 'vd, 'vn, 'vm");
3146 res = (vn_flt > vm_flt) ? 0xffffffff : 0;
3147 } else {
3148 // Format(instr, "vcge'vsz 'vd, 'vn, 'vm");
3149 res = (vn_flt >= vm_flt) ? 0xffffffff : 0;
3150 }
3151 } else if ((U == 0) && (opcode == 0x1e)) {
3152 if (instr->Bit(23) == 1) {
3153 // Format(instr, "vmin'vsz 'vd, 'vn, 'vm");
3154 const float m = vminf(vn_flt, vm_flt);
3155 res = bit_cast<int32_t, float>(m);
3156 } else {
3157 // Format(instr, "vmax'vsz 'vd, 'vn, 'vm");
3158 const float m = vmaxf(vn_flt, vm_flt);
3159 res = bit_cast<int32_t, float>(m);
3160 }
3161 } else if ((U == 0) && (opcode == 0x1f)) {
3162 if (instr->Bit(23) == 0) {
3163 // Format(instr, "vrecps'vsz 'vd, 'vn, 'vm");
3164 res = bit_cast<int32_t, float>(2.0 - (vn_flt * vm_flt));
3165 } else {
3166 // Format(instr, "vrsqrt'vsz 'vd, 'vn, 'vm");
3167 res = bit_cast<int32_t, float>((3.0 - vn_flt * vm_flt) / 2.0);
3168 }
3169 } else {
3170 UnimplementedInstruction(instr);
3171 return;
3172 }
3173 set_vregisters(vd, idx, res);
3174 }
3175 } else {
3176 // f64 case.
3177 for (int idx = 0; idx < 2; idx++) {
3178 const int64_t vn_val = get_vregisterd(vn, idx);
3179 const int64_t vm_val = get_vregisterd(vm, idx);
3180 const double vn_dbl = bit_cast<double, int64_t>(vn_val);
3181 const double vm_dbl = bit_cast<double, int64_t>(vm_val);
3182 int64_t res = 0.0;
3183 if ((U == 0) && (opcode == 0x3)) {
3184 if (instr->Bit(23) == 0) {
3185 // Format(instr, "vand 'vd, 'vn, 'vm");
3186 res = vn_val & vm_val;
3187 } else {
3188 // Format(instr, "vorr 'vd, 'vn, 'vm");
3189 res = vn_val | vm_val;
3190 }
3191 } else if ((U == 1) && (opcode == 0x3)) {
3192 // Format(instr, "veor 'vd, 'vn, 'vm");
3193 res = vn_val ^ vm_val;
3194 } else if ((U == 0) && (opcode == 0x10)) {
3195 // Format(instr, "vadd'vsz 'vd, 'vn, 'vm");
3196 res = vn_val + vm_val;
3197 } else if ((U == 1) && (opcode == 0x10)) {
3198 // Format(instr, "vsub'vsz 'vd, 'vn, 'vm");
3199 res = vn_val - vm_val;
3200 } else if ((U == 0) && (opcode == 0x1a)) {
3201 if (instr->Bit(23) == 0) {
3202 // Format(instr, "vadd'vsz 'vd, 'vn, 'vm");
3203 res = bit_cast<int64_t, double>(vn_dbl + vm_dbl);
3204 } else {
3205 // Format(instr, "vsub'vsz 'vd, 'vn, 'vm");
3206 res = bit_cast<int64_t, double>(vn_dbl - vm_dbl);
3207 }
3208 } else if ((U == 1) && (opcode == 0x1b)) {
3209 // Format(instr, "vmul'vsz 'vd, 'vn, 'vm");
3210 res = bit_cast<int64_t, double>(vn_dbl * vm_dbl);
3211 } else if ((U == 1) && (opcode == 0x1f)) {
3212 // Format(instr, "vdiv'vsz 'vd, 'vn, 'vm");
3213 res = bit_cast<int64_t, double>(vn_dbl / vm_dbl);
3214 } else if ((U == 0) && (opcode == 0x1c)) {
3215 // Format(instr, "vceq'vsz 'vd, 'vn, 'vm");
3216 res = (vn_dbl == vm_dbl) ? 0xffffffffffffffffLL : 0;
3217 } else if ((U == 1) && (opcode == 0x1c)) {
3218 if (instr->Bit(23) == 1) {
3219 // Format(instr, "vcgt'vsz 'vd, 'vn, 'vm");
3220 res = (vn_dbl > vm_dbl) ? 0xffffffffffffffffLL : 0;
3221 } else {
3222 // Format(instr, "vcge'vsz 'vd, 'vn, 'vm");
3223 res = (vn_dbl >= vm_dbl) ? 0xffffffffffffffffLL : 0;
3224 }
3225 } else if ((U == 0) && (opcode == 0x1e)) {
3226 if (instr->Bit(23) == 1) {
3227 // Format(instr, "vmin'vsz 'vd, 'vn, 'vm");
3228 const double m = vmind(vn_dbl, vm_dbl);
3229 res = bit_cast<int64_t, double>(m);
3230 } else {
3231 // Format(instr, "vmax'vsz 'vd, 'vn, 'vm");
3232 const double m = vmaxd(vn_dbl, vm_dbl);
3233 res = bit_cast<int64_t, double>(m);
3234 }
3235 } else {
3236 UnimplementedInstruction(instr);
3237 return;
3238 }
3239 set_vregisterd(vd, idx, res);
3240 }
3241 }
3242}
3243
3244static float arm_reciprocal_sqrt_estimate(float a) {
3245 // From the ARM Architecture Reference Manual A2-87.
3246 if (isinf(a) || (fabs(a) >= exp2f(126)))
3247 return 0.0;
3248 else if (a == 0.0)
3249 return kPosInfinity;
3250 else if (isnan(a))
3251 return a;
3252
3253 uint32_t a_bits = bit_cast<uint32_t, float>(a);
3254 uint64_t scaled;
3255 if (((a_bits >> 23) & 1) != 0) {
3256 // scaled = '0 01111111101' : operand<22:0> : Zeros(29)
3257 scaled = (static_cast<uint64_t>(0x3fd) << 52) |
3258 ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
3259 } else {
3260 // scaled = '0 01111111110' : operand<22:0> : Zeros(29)
3261 scaled = (static_cast<uint64_t>(0x3fe) << 52) |
3262 ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
3263 }
3264 // result_exp = (380 - UInt(operand<30:23>) DIV 2;
3265 int32_t result_exp = (380 - ((a_bits >> 23) & 0xff)) / 2;
3266
3267 double scaled_d = bit_cast<double, uint64_t>(scaled);
3268 ASSERT((scaled_d >= 0.25) && (scaled_d < 1.0));
3269
3270 double r;
3271 if (scaled_d < 0.5) {
3272 // range 0.25 <= a < 0.5
3273
3274 // a in units of 1/512 rounded down.
3275 int32_t q0 = static_cast<int32_t>(scaled_d * 512.0);
3276 // reciprocal root r.
3277 r = 1.0 / sqrt((static_cast<double>(q0) + 0.5) / 512.0);
3278 } else {
3279 // range 0.5 <= a < 1.0
3280
3281 // a in units of 1/256 rounded down.
3282 int32_t q1 = static_cast<int32_t>(scaled_d * 256.0);
3283 // reciprocal root r.
3284 r = 1.0 / sqrt((static_cast<double>(q1) + 0.5) / 256.0);
3285 }
3286 // r in units of 1/256 rounded to nearest.
3287 int32_t s = static_cast<int>(256.0 * r + 0.5);
3288 double estimate = static_cast<double>(s) / 256.0;
3289 ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0)));
3290
3291 // result = 0 : result_exp<7:0> : estimate<51:29>
3292 int32_t result_bits =
3293 ((result_exp & 0xff) << 23) |
3294 ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
3295 return bit_cast<float, int32_t>(result_bits);
3296}
3297
3298static float arm_recip_estimate(float a) {
3299 // From the ARM Architecture Reference Manual A2-85.
3300 if (isinf(a) || (fabs(a) >= exp2f(126)))
3301 return 0.0;
3302 else if (a == 0.0)
3303 return kPosInfinity;
3304 else if (isnan(a))
3305 return a;
3306
3307 uint32_t a_bits = bit_cast<uint32_t, float>(a);
3308 // scaled = '0011 1111 1110' : a<22:0> : Zeros(29)
3309 uint64_t scaled = (static_cast<uint64_t>(0x3fe) << 52) |
3310 ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
3311 // result_exp = 253 - UInt(a<30:23>)
3312 int32_t result_exp = 253 - ((a_bits >> 23) & 0xff);
3313 ASSERT((result_exp >= 1) && (result_exp <= 252));
3314
3315 double scaled_d = bit_cast<double, uint64_t>(scaled);
3316 ASSERT((scaled_d >= 0.5) && (scaled_d < 1.0));
3317
3318 // a in units of 1/512 rounded down.
3319 int32_t q = static_cast<int32_t>(scaled_d * 512.0);
3320 // reciprocal r.
3321 double r = 1.0 / ((static_cast<double>(q) + 0.5) / 512.0);
3322 // r in units of 1/256 rounded to nearest.
3323 int32_t s = static_cast<int32_t>(256.0 * r + 0.5);
3324 double estimate = static_cast<double>(s) / 256.0;
3325 ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0)));
3326
3327 // result = sign : result_exp<7:0> : estimate<51:29>
3328 int32_t result_bits =
3329 (a_bits & 0x80000000) | ((result_exp & 0xff) << 23) |
3330 ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
3331 return bit_cast<float, int32_t>(result_bits);
3332}
3333
3334void Simulator::DecodeSIMDTwoReg(Instr* instr) {
3335 const int32_t Q = instr->Bit(30);
3336 const int32_t U = instr->Bit(29);
3337 const int32_t op = instr->Bits(12, 5);
3338 const int32_t sz = instr->Bits(22, 2);
3339 const VRegister vd = instr->VdField();
3340 const VRegister vn = instr->VnField();
3341
3342 if (Q != 1) {
3343 UnimplementedInstruction(instr);
3344 return;
3345 }
3346
3347 if ((U == 1) && (op == 5)) {
3348 // Format(instr, "vnot 'vd, 'vn");
3349 for (int i = 0; i < 2; i++) {
3350 set_vregisterd(vd, i, ~get_vregisterd(vn, i));
3351 }
3352 } else if ((U == 0) && (op == 0xf)) {
3353 if (sz == 2) {
3354 // Format(instr, "vabss 'vd, 'vn");
3355 for (int i = 0; i < 4; i++) {
3356 const int32_t vn_val = get_vregisters(vn, i);
3357 const float vn_flt = bit_cast<float, int32_t>(vn_val);
3358 set_vregisters(vd, i, bit_cast<int32_t, float>(fabsf(vn_flt)));
3359 }
3360 } else if (sz == 3) {
3361 // Format(instr, "vabsd 'vd, 'vn");
3362 for (int i = 0; i < 2; i++) {
3363 const int64_t vn_val = get_vregisterd(vn, i);
3364 const double vn_dbl = bit_cast<double, int64_t>(vn_val);
3365 set_vregisterd(vd, i, bit_cast<int64_t, double>(fabs(vn_dbl)));
3366 }
3367 } else {
3368 UnimplementedInstruction(instr);
3369 }
3370 } else if ((U == 1) && (op == 0xf)) {
3371 if (sz == 2) {
3372 // Format(instr, "vnegs 'vd, 'vn");
3373 for (int i = 0; i < 4; i++) {
3374 const int32_t vn_val = get_vregisters(vn, i);
3375 const float vn_flt = bit_cast<float, int32_t>(vn_val);
3376 set_vregisters(vd, i, bit_cast<int32_t, float>(-vn_flt));
3377 }
3378 } else if (sz == 3) {
3379 // Format(instr, "vnegd 'vd, 'vn");
3380 for (int i = 0; i < 2; i++) {
3381 const int64_t vn_val = get_vregisterd(vn, i);
3382 const double vn_dbl = bit_cast<double, int64_t>(vn_val);
3383 set_vregisterd(vd, i, bit_cast<int64_t, double>(-vn_dbl));
3384 }
3385 } else {
3386 UnimplementedInstruction(instr);
3387 }
3388 } else if ((U == 1) && (op == 0x1f)) {
3389 if (sz == 2) {
3390 // Format(instr, "vsqrts 'vd, 'vn");
3391 for (int i = 0; i < 4; i++) {
3392 const int32_t vn_val = get_vregisters(vn, i);
3393 const float vn_flt = bit_cast<float, int32_t>(vn_val);
3394 set_vregisters(vd, i, bit_cast<int32_t, float>(sqrtf(vn_flt)));
3395 }
3396 } else if (sz == 3) {
3397 // Format(instr, "vsqrtd 'vd, 'vn");
3398 for (int i = 0; i < 2; i++) {
3399 const int64_t vn_val = get_vregisterd(vn, i);
3400 const double vn_dbl = bit_cast<double, int64_t>(vn_val);
3401 set_vregisterd(vd, i, bit_cast<int64_t, double>(sqrt(vn_dbl)));
3402 }
3403 } else {
3404 UnimplementedInstruction(instr);
3405 }
3406 } else if ((U == 0) && (op == 0x1d)) {
3407 if (sz != 2) {
3408 UnimplementedInstruction(instr);
3409 return;
3410 }
3411 // Format(instr, "vrecpes 'vd, 'vn");
3412 for (int i = 0; i < 4; i++) {
3413 const int32_t vn_val = get_vregisters(vn, i);
3414 const float vn_flt = bit_cast<float, int32_t>(vn_val);
3415 const float re = arm_recip_estimate(vn_flt);
3416 set_vregisters(vd, i, bit_cast<int32_t, float>(re));
3417 }
3418 } else if ((U == 1) && (op == 0x1d)) {
3419 if (sz != 2) {
3420 UnimplementedInstruction(instr);
3421 return;
3422 }
3423 // Format(instr, "vrsqrtes 'vd, 'vn");
3424 for (int i = 0; i < 4; i++) {
3425 const int32_t vn_val = get_vregisters(vn, i);
3426 const float vn_flt = bit_cast<float, int32_t>(vn_val);
3427 const float re = arm_reciprocal_sqrt_estimate(vn_flt);
3428 set_vregisters(vd, i, bit_cast<int32_t, float>(re));
3429 }
3430 } else {
3431 UnimplementedInstruction(instr);
3432 }
3433}
3434
3435void Simulator::DecodeDPSimd1(Instr* instr) {
3436 if (instr->IsSIMDCopyOp()) {
3437 DecodeSIMDCopy(instr);
3438 } else if (instr->IsSIMDThreeSameOp()) {
3439 DecodeSIMDThreeSame(instr);
3440 } else if (instr->IsSIMDTwoRegOp()) {
3441 DecodeSIMDTwoReg(instr);
3442 } else {
3443 UnimplementedInstruction(instr);
3444 }
3445}
3446
3447void Simulator::DecodeFPImm(Instr* instr) {
3448 if ((instr->Bit(31) != 0) || (instr->Bit(29) != 0) || (instr->Bit(23) != 0) ||
3449 (instr->Bits(5, 5) != 0)) {
3450 UnimplementedInstruction(instr);
3451 return;
3452 }
3453 if (instr->Bit(22) == 1) {
3454 // Double.
3455 // Format(instr, "fmovd 'vd, #'immd");
3456 const VRegister vd = instr->VdField();
3457 const int64_t immd = Instr::VFPExpandImm(instr->Imm8Field());
3458 set_vregisterd(vd, 0, immd);
3459 set_vregisterd(vd, 1, 0);
3460 } else {
3461 // Single.
3462 UnimplementedInstruction(instr);
3463 }
3464}
3465
3466void Simulator::DecodeFPIntCvt(Instr* instr) {
3467 const VRegister vd = instr->VdField();
3468 const VRegister vn = instr->VnField();
3469 const Register rd = instr->RdField();
3470 const Register rn = instr->RnField();
3471
3472 if (instr->Bit(29) != 0) {
3473 UnimplementedInstruction(instr);
3474 return;
3475 }
3476
3477 if ((instr->SFField() == 0) && (instr->Bits(22, 2) == 0)) {
3478 if (instr->Bits(16, 5) == 6) {
3479 // Format(instr, "fmovrs'sf 'rd, 'vn");
3480 const int32_t vn_val = get_vregisters(vn, 0);
3481 set_wregister(rd, vn_val, R31IsZR);
3482 } else if (instr->Bits(16, 5) == 7) {
3483 // Format(instr, "fmovsr'sf 'vd, 'rn");
3484 const int32_t rn_val = get_wregister(rn, R31IsZR);
3485 set_vregisters(vd, 0, rn_val);
3486 set_vregisters(vd, 1, 0);
3487 set_vregisters(vd, 2, 0);
3488 set_vregisters(vd, 3, 0);
3489 } else {
3490 UnimplementedInstruction(instr);
3491 }
3492 } else if (instr->Bits(22, 2) == 1) {
3493 if (instr->Bits(16, 5) == 2) {
3494 // Format(instr, "scvtfd'sf 'vd, 'rn");
3495 const int64_t rn_val64 = get_register(rn, instr->RnMode());
3496 const int32_t rn_val32 = get_wregister(rn, instr->RnMode());
3497 const double vn_dbl = (instr->SFField() == 1)
3498 ? static_cast<double>(rn_val64)
3499 : static_cast<double>(rn_val32);
3500 set_vregisterd(vd, 0, bit_cast<int64_t, double>(vn_dbl));
3501 set_vregisterd(vd, 1, 0);
3502 } else if (instr->Bits(16, 5) == 6) {
3503 // Format(instr, "fmovrd'sf 'rd, 'vn");
3504 const int64_t vn_val = get_vregisterd(vn, 0);
3505 set_register(instr, rd, vn_val, R31IsZR);
3506 } else if (instr->Bits(16, 5) == 7) {
3507 // Format(instr, "fmovdr'sf 'vd, 'rn");
3508 const int64_t rn_val = get_register(rn, R31IsZR);
3509 set_vregisterd(vd, 0, rn_val);
3510 set_vregisterd(vd, 1, 0);
3511 } else if ((instr->Bits(16, 5) == 8) || (instr->Bits(16, 5) == 16) ||
3512 (instr->Bits(16, 5) == 24)) {
3513 const intptr_t max = instr->Bit(31) == 1 ? INT64_MAX : INT32_MAX;
3514 const intptr_t min = instr->Bit(31) == 1 ? INT64_MIN : INT32_MIN;
3515 double vn_val = bit_cast<double, int64_t>(get_vregisterd(vn, 0));
3516 switch (instr->Bits(16, 5)) {
3517 case 8:
3518 // Format(instr, "fcvtps'sf 'rd, 'vn");
3519 vn_val = ceil(vn_val);
3520 break;
3521 case 16:
3522 // Format(instr, "fcvtms'sf 'rd, 'vn");
3523 vn_val = floor(vn_val);
3524 break;
3525 case 24:
3526 // Format(instr, "fcvtzs'sf 'rd, 'vn");
3527 break;
3528 }
3529 int64_t result;
3530 if (vn_val >= static_cast<double>(max)) {
3531 result = max;
3532 } else if (vn_val <= static_cast<double>(min)) {
3533 result = min;
3534 } else {
3535 result = static_cast<int64_t>(vn_val);
3536 }
3537 if (instr->Bit(31) == 1) {
3538 set_register(instr, rd, result, instr->RdMode());
3539 } else {
3540 set_register(instr, rd, result & 0xffffffffll, instr->RdMode());
3541 }
3542 } else {
3543 UnimplementedInstruction(instr);
3544 }
3545 } else {
3546 UnimplementedInstruction(instr);
3547 }
3548}
3549
3550void Simulator::DecodeFPOneSource(Instr* instr) {
3551 const int opc = instr->Bits(15, 6);
3552 const VRegister vd = instr->VdField();
3553 const VRegister vn = instr->VnField();
3554 const int64_t vn_val = get_vregisterd(vn, 0);
3555 const int32_t vn_val32 = vn_val & kWRegMask;
3556 const double vn_dbl = bit_cast<double, int64_t>(vn_val);
3557 const float vn_flt = bit_cast<float, int32_t>(vn_val32);
3558
3559 if ((opc != 5) && (instr->Bit(22) != 1)) {
3560 // Source is interpreted as single-precision only if we're doing a
3561 // conversion from single -> double.
3562 UnimplementedInstruction(instr);
3563 return;
3564 }
3565
3566 int64_t res_val = 0;
3567 switch (opc) {
3568 case 0:
3569 // Format("fmovdd 'vd, 'vn");
3570 res_val = get_vregisterd(vn, 0);
3571 break;
3572 case 1:
3573 // Format("fabsd 'vd, 'vn");
3574 res_val = bit_cast<int64_t, double>(fabs(vn_dbl));
3575 break;
3576 case 2:
3577 // Format("fnegd 'vd, 'vn");
3578 res_val = bit_cast<int64_t, double>(-vn_dbl);
3579 break;
3580 case 3:
3581 // Format("fsqrtd 'vd, 'vn");
3582 res_val = bit_cast<int64_t, double>(sqrt(vn_dbl));
3583 break;
3584 case 4: {
3585 // Format(instr, "fcvtsd 'vd, 'vn");
3586 const uint32_t val =
3587 bit_cast<uint32_t, float>(static_cast<float>(vn_dbl));
3588 res_val = static_cast<int64_t>(val);
3589 break;
3590 }
3591 case 5:
3592 // Format(instr, "fcvtds 'vd, 'vn");
3593 res_val = bit_cast<int64_t, double>(static_cast<double>(vn_flt));
3594 break;
3595 default:
3596 UnimplementedInstruction(instr);
3597 break;
3598 }
3599
3600 set_vregisterd(vd, 0, res_val);
3601 set_vregisterd(vd, 1, 0);
3602}
3603
3604void Simulator::DecodeFPTwoSource(Instr* instr) {
3605 if (instr->Bits(22, 2) != 1) {
3606 UnimplementedInstruction(instr);
3607 return;
3608 }
3609 const VRegister vd = instr->VdField();
3610 const VRegister vn = instr->VnField();
3611 const VRegister vm = instr->VmField();
3612 const double vn_val = bit_cast<double, int64_t>(get_vregisterd(vn, 0));
3613 const double vm_val = bit_cast<double, int64_t>(get_vregisterd(vm, 0));
3614 const int opc = instr->Bits(12, 4);
3615 double result;
3616
3617 switch (opc) {
3618 case 0:
3619 // Format(instr, "fmuld 'vd, 'vn, 'vm");
3620 result = vn_val * vm_val;
3621 break;
3622 case 1:
3623 // Format(instr, "fdivd 'vd, 'vn, 'vm");
3624 result = vn_val / vm_val;
3625 break;
3626 case 2:
3627 // Format(instr, "faddd 'vd, 'vn, 'vm");
3628 result = vn_val + vm_val;
3629 break;
3630 case 3:
3631 // Format(instr, "fsubd 'vd, 'vn, 'vm");
3632 result = vn_val - vm_val;
3633 break;
3634 default:
3635 UnimplementedInstruction(instr);
3636 return;
3637 }
3638
3639 set_vregisterd(vd, 0, bit_cast<int64_t, double>(result));
3640 set_vregisterd(vd, 1, 0);
3641}
3642
3643void Simulator::DecodeFPCompare(Instr* instr) {
3644 const VRegister vn = instr->VnField();
3645 const VRegister vm = instr->VmField();
3646 const double vn_val = bit_cast<double, int64_t>(get_vregisterd(vn, 0));
3647 double vm_val;
3648
3649 if ((instr->Bit(22) == 1) && (instr->Bits(3, 2) == 0)) {
3650 // Format(instr, "fcmpd 'vn, 'vm");
3651 vm_val = bit_cast<double, int64_t>(get_vregisterd(vm, 0));
3652 } else if ((instr->Bit(22) == 1) && (instr->Bits(3, 2) == 1)) {
3653 if (instr->VmField() == V0) {
3654 // Format(instr, "fcmpd 'vn, #0.0");
3655 vm_val = 0.0;
3656 } else {
3657 UnimplementedInstruction(instr);
3658 return;
3659 }
3660 } else {
3661 UnimplementedInstruction(instr);
3662 return;
3663 }
3664
3665 n_flag_ = false;
3666 z_flag_ = false;
3667 c_flag_ = false;
3668 v_flag_ = false;
3669
3670 if (isnan(vn_val) || isnan(vm_val)) {
3671 c_flag_ = true;
3672 v_flag_ = true;
3673 } else if (vn_val == vm_val) {
3674 z_flag_ = true;
3675 c_flag_ = true;
3676 } else if (vn_val < vm_val) {
3677 n_flag_ = true;
3678 } else {
3679 c_flag_ = true;
3680 }
3681}
3682
3683void Simulator::DecodeFP(Instr* instr) {
3684 if (instr->IsFPImmOp()) {
3685 DecodeFPImm(instr);
3686 } else if (instr->IsFPIntCvtOp()) {
3687 DecodeFPIntCvt(instr);
3688 } else if (instr->IsFPOneSourceOp()) {
3689 DecodeFPOneSource(instr);
3690 } else if (instr->IsFPTwoSourceOp()) {
3691 DecodeFPTwoSource(instr);
3692 } else if (instr->IsFPCompareOp()) {
3693 DecodeFPCompare(instr);
3694 } else {
3695 UnimplementedInstruction(instr);
3696 }
3697}
3698
3699void Simulator::DecodeDPSimd2(Instr* instr) {
3700 if (instr->IsFPOp()) {
3701 DecodeFP(instr);
3702 } else {
3703 UnimplementedInstruction(instr);
3704 }
3705}
3706
3707// Executes the current instruction.
3708DART_FORCE_INLINE
3709void Simulator::InstructionDecodeImpl(Instr* instr) {
3710 pc_modified_ = false;
3711
3712 if (instr->IsLoadStoreOp()) {
3713 DecodeLoadStore(instr);
3714 } else if (instr->IsDPImmediateOp()) {
3715 DecodeDPImmediate(instr);
3716 } else if (instr->IsCompareBranchOp()) {
3717 DecodeCompareBranch(instr);
3718 } else if (instr->IsDPRegisterOp()) {
3719 DecodeDPRegister(instr);
3720 } else if (instr->IsDPSimd1Op()) {
3721 DecodeDPSimd1(instr);
3722 } else if (instr->IsDPSimd2Op()) {
3723 DecodeDPSimd2(instr);
3724 } else {
3725 UnimplementedInstruction(instr);
3726 }
3727
3728 if (!pc_modified_) {
3729 set_pc(reinterpret_cast<int64_t>(instr) + Instr::kInstrSize);
3730 }
3731}
3732
3733void Simulator::InstructionDecode(Instr* instr) {
3734 if (IsTracingExecution()) {
3735 THR_Print("%" Pu64 " ", icount_);
3736 const uword start = reinterpret_cast<uword>(instr);
3737 const uword end = start + Instr::kInstrSize;
3738 if (FLAG_support_disassembler) {
3739 Disassembler::Disassemble(start, end);
3740 } else {
3741 THR_Print("Disassembler not supported in this mode.\n");
3742 }
3743 }
3744 InstructionDecodeImpl(instr);
3745}
3746
3747void Simulator::Execute() {
3748 if (LIKELY(FLAG_stop_sim_at == ULLONG_MAX &&
3749 FLAG_trace_sim_after == ULLONG_MAX)) {
3750 ExecuteNoTrace();
3751 } else {
3752 ExecuteTrace();
3753 }
3754}
3755
3756void Simulator::ExecuteNoTrace() {
3757 // Get the PC to simulate. Cannot use the accessor here as we need the
3758 // raw PC value and not the one used as input to arithmetic instructions.
3759 uword program_counter = get_pc();
3760
3761 // Fast version of the dispatch loop without checking whether the simulator
3762 // should be stopping at a particular executed instruction.
3763 while (program_counter != kEndSimulatingPC) {
3764 Instr* instr = reinterpret_cast<Instr*>(program_counter);
3765 icount_++;
3766 InstructionDecodeImpl(instr);
3767 program_counter = get_pc();
3768 }
3769}
3770
3771void Simulator::ExecuteTrace() {
3772 // Get the PC to simulate. Cannot use the accessor here as we need the
3773 // raw PC value and not the one used as input to arithmetic instructions.
3774 uword program_counter = get_pc();
3775
3776 // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
3777 // we reach the particular instruction count or address.
3778 while (program_counter != kEndSimulatingPC) {
3779 Instr* instr = reinterpret_cast<Instr*>(program_counter);
3780 icount_++;
3781 if (icount_ == FLAG_stop_sim_at) {
3782 SimulatorDebugger dbg(this);
3783 dbg.Stop(instr, "Instruction count reached");
3784 } else if (reinterpret_cast<uint64_t>(instr) == FLAG_stop_sim_at) {
3785 SimulatorDebugger dbg(this);
3786 dbg.Stop(instr, "Instruction address reached");
3787 } else if (IsIllegalAddress(program_counter)) {
3788 HandleIllegalAccess(program_counter, instr);
3789 } else {
3790 InstructionDecode(instr);
3791 }
3792 program_counter = get_pc();
3793 }
3794}
3795
3796int64_t Simulator::Call(int64_t entry,
3797 int64_t parameter0,
3798 int64_t parameter1,
3799 int64_t parameter2,
3800 int64_t parameter3,
3801 bool fp_return,
3802 bool fp_args) {
3803 // Save the SP register before the call so we can restore it.
3804 const intptr_t sp_before_call = get_register(R31, R31IsSP);
3805
3806 // Setup parameters.
3807 if (fp_args) {
3808 set_vregisterd(V0, 0, parameter0);
3809 set_vregisterd(V0, 1, 0);
3810 set_vregisterd(V1, 0, parameter1);
3811 set_vregisterd(V1, 1, 0);
3812 set_vregisterd(V2, 0, parameter2);
3813 set_vregisterd(V2, 1, 0);
3814 set_vregisterd(V3, 0, parameter3);
3815 set_vregisterd(V3, 1, 0);
3816 } else {
3817 set_register(nullptr, R0, parameter0);
3818 set_register(nullptr, R1, parameter1);
3819 set_register(nullptr, R2, parameter2);
3820 set_register(nullptr, R3, parameter3);
3821 }
3822
3823 // Make sure the activation frames are properly aligned.
3824 intptr_t stack_pointer = sp_before_call;
3825 if (OS::ActivationFrameAlignment() > 1) {
3826 stack_pointer =
3827 Utils::RoundDown(stack_pointer, OS::ActivationFrameAlignment());
3828 }
3829 set_register(nullptr, R31, stack_pointer, R31IsSP);
3830
3831 // Prepare to execute the code at entry.
3832 set_pc(entry);
3833 // Put down marker for end of simulation. The simulator will stop simulation
3834 // when the PC reaches this value. By saving the "end simulation" value into
3835 // the LR the simulation stops when returning to this call point.
3836 set_register(nullptr, LR, kEndSimulatingPC);
3837
3838 // Remember the values of callee-saved registers, and set them up with a
3839 // known value so that we are able to check that they are preserved
3840 // properly across Dart execution.
3841 int64_t preserved_vals[kAbiPreservedCpuRegCount];
3842 const double dicount = static_cast<double>(icount_);
3843 const int64_t callee_saved_value = bit_cast<int64_t, double>(dicount);
3844 for (int i = kAbiFirstPreservedCpuReg; i <= kAbiLastPreservedCpuReg; i++) {
3845 const Register r = static_cast<Register>(i);
3846 preserved_vals[i - kAbiFirstPreservedCpuReg] = get_register(r);
3847 set_register(nullptr, r, callee_saved_value);
3848 }
3849
3850 // Only the bottom half of the V registers must be preserved.
3851 int64_t preserved_dvals[kAbiPreservedFpuRegCount];
3852 for (int i = kAbiFirstPreservedFpuReg; i <= kAbiLastPreservedFpuReg; i++) {
3853 const VRegister r = static_cast<VRegister>(i);
3854 preserved_dvals[i - kAbiFirstPreservedFpuReg] = get_vregisterd(r, 0);
3855 set_vregisterd(r, 0, callee_saved_value);
3856 set_vregisterd(r, 1, 0);
3857 }
3858
3859 // Start the simulation.
3860 Execute();
3861
3862 // Check that the callee-saved registers have been preserved,
3863 // and restore them with the original value.
3864 for (int i = kAbiFirstPreservedCpuReg; i <= kAbiLastPreservedCpuReg; i++) {
3865 const Register r = static_cast<Register>(i);
3866 ASSERT(callee_saved_value == get_register(r));
3867 set_register(nullptr, r, preserved_vals[i - kAbiFirstPreservedCpuReg]);
3868 }
3869
3870 for (int i = kAbiFirstPreservedFpuReg; i <= kAbiLastPreservedFpuReg; i++) {
3871 const VRegister r = static_cast<VRegister>(i);
3872 ASSERT(callee_saved_value == get_vregisterd(r, 0));
3873 set_vregisterd(r, 0, preserved_dvals[i - kAbiFirstPreservedFpuReg]);
3874 set_vregisterd(r, 1, 0);
3875 }
3876
3877 // Restore the SP register and return R0.
3878 set_register(nullptr, R31, sp_before_call, R31IsSP);
3879 int64_t return_value;
3880 if (fp_return) {
3881 return_value = get_vregisterd(V0, 0);
3882 } else {
3883 return_value = get_register(R0);
3884 }
3885 return return_value;
3886}
3887
3888void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
3889 // Walk over all setjmp buffers (simulated --> C++ transitions)
3890 // and try to find the setjmp associated with the simulated stack pointer.
3891 SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
3892 while (buf->link() != nullptr && buf->link()->sp() <= sp) {
3893 buf = buf->link();
3894 }
3895 ASSERT(buf != nullptr);
3896
3897 // The C++ caller has not cleaned up the stack memory of C++ frames.
3898 // Prepare for unwinding frames by destroying all the stack resources
3899 // in the previous C++ frames.
3900 StackResource::Unwind(thread);
3901
3902 // Keep the following code in sync with `StubCode::JumpToFrameStub()`.
3903
3904 // Unwind the C++ stack and continue simulation in the target frame.
3905 set_pc(static_cast<int64_t>(pc));
3906 set_register(nullptr, SP, static_cast<int64_t>(sp));
3907 set_register(nullptr, FP, static_cast<int64_t>(fp));
3908 set_register(nullptr, THR, reinterpret_cast<int64_t>(thread));
3909 set_register(nullptr, R31, thread->saved_stack_limit() - 4096);
3910#if defined(DART_TARGET_OS_FUCHSIA)
3911 set_register(nullptr, R18, thread->saved_shadow_call_stack());
3912#endif
3913 // Set the tag.
3914 thread->set_vm_tag(VMTag::kDartTagId);
3915 // Clear top exit frame.
3916 thread->set_top_exit_frame_info(0);
3917 // Restore pool pointer.
3918 int64_t code =
3919 *reinterpret_cast<int64_t*>(fp + kPcMarkerSlotFromFp * kWordSize);
3920 int64_t pp = FLAG_precompiled_mode
3921 ? static_cast<int64_t>(thread->global_object_pool())
3922 : *reinterpret_cast<int64_t*>(
3923 code + Code::object_pool_offset() - kHeapObjectTag);
3924 pp -= kHeapObjectTag; // In the PP register, the pool pointer is untagged.
3925 set_register(nullptr, CODE_REG, code);
3926 set_register(nullptr, PP, pp);
3927 set_register(
3928 nullptr, HEAP_BITS,
3929 (thread->write_barrier_mask() << 32) | (thread->heap_base() >> 32));
3930 set_register(nullptr, NULL_REG, static_cast<int64_t>(Object::null()));
3931 if (FLAG_precompiled_mode) {
3932 set_register(nullptr, DISPATCH_TABLE_REG,
3933 reinterpret_cast<int64_t>(thread->dispatch_table_array()));
3934 }
3935
3936 buf->Longjmp();
3937}
3938
3939} // namespace dart
3940
3941#endif // !defined(USING_SIMULATOR)
3942
3943#endif // defined TARGET_ARCH_ARM64
3944

source code of dart_sdk/runtime/vm/simulator_arm64.cc