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