1 // Copyright 2015, ARM Limited
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright notice,
8 // this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright notice,
10 // this list of conditions and the following disclaimer in the documentation
11 // and/or other materials provided with the distribution.
12 // * Neither the name of ARM Limited nor the names of its contributors may be
13 // used to endorse or promote products derived from this software without
14 // specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 #include "jstypes.h"
28
29 #ifdef JS_SIMULATOR_ARM64
30
31 #include "jit/arm64/vixl/Simulator-vixl.h"
32
33 #include <cmath>
34 #include <string.h>
35
36 #include "jit/AtomicOperations.h"
37
38 namespace vixl {
39
40 const Instruction* Simulator::kEndOfSimAddress = NULL;
41
SetBits(int msb,int lsb,uint32_t bits)42 void SimSystemRegister::SetBits(int msb, int lsb, uint32_t bits) {
43 int width = msb - lsb + 1;
44 VIXL_ASSERT(IsUintN(width, bits) || IsIntN(width, bits));
45
46 bits <<= lsb;
47 uint32_t mask = ((1 << width) - 1) << lsb;
48 VIXL_ASSERT((mask & write_ignore_mask_) == 0);
49
50 value_ = (value_ & ~mask) | (bits & mask);
51 }
52
53
DefaultValueFor(SystemRegister id)54 SimSystemRegister SimSystemRegister::DefaultValueFor(SystemRegister id) {
55 switch (id) {
56 case NZCV:
57 return SimSystemRegister(0x00000000, NZCVWriteIgnoreMask);
58 case FPCR:
59 return SimSystemRegister(0x00000000, FPCRWriteIgnoreMask);
60 default:
61 VIXL_UNREACHABLE();
62 return SimSystemRegister();
63 }
64 }
65
66
Run()67 void Simulator::Run() {
68 pc_modified_ = false;
69 while (pc_ != kEndOfSimAddress) {
70 ExecuteInstruction();
71 LogAllWrittenRegisters();
72 }
73 }
74
75
RunFrom(const Instruction * first)76 void Simulator::RunFrom(const Instruction* first) {
77 set_pc(first);
78 Run();
79 }
80
81
82 const char* Simulator::xreg_names[] = {
83 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
84 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
85 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
86 "x24", "x25", "x26", "x27", "x28", "x29", "lr", "xzr", "sp"};
87
88 const char* Simulator::wreg_names[] = {
89 "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
90 "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
91 "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
92 "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wzr", "wsp"};
93
94 const char* Simulator::sreg_names[] = {
95 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
96 "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
97 "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
98 "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"};
99
100 const char* Simulator::dreg_names[] = {
101 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
102 "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
103 "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
104 "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"};
105
106 const char* Simulator::vreg_names[] = {
107 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
108 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
109 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
110 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"};
111
112
113
WRegNameForCode(unsigned code,Reg31Mode mode)114 const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) {
115 VIXL_ASSERT(code < kNumberOfRegisters);
116 // If the code represents the stack pointer, index the name after zr.
117 if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
118 code = kZeroRegCode + 1;
119 }
120 return wreg_names[code];
121 }
122
123
XRegNameForCode(unsigned code,Reg31Mode mode)124 const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) {
125 VIXL_ASSERT(code < kNumberOfRegisters);
126 // If the code represents the stack pointer, index the name after zr.
127 if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
128 code = kZeroRegCode + 1;
129 }
130 return xreg_names[code];
131 }
132
133
SRegNameForCode(unsigned code)134 const char* Simulator::SRegNameForCode(unsigned code) {
135 VIXL_ASSERT(code < kNumberOfFPRegisters);
136 return sreg_names[code];
137 }
138
139
DRegNameForCode(unsigned code)140 const char* Simulator::DRegNameForCode(unsigned code) {
141 VIXL_ASSERT(code < kNumberOfFPRegisters);
142 return dreg_names[code];
143 }
144
145
VRegNameForCode(unsigned code)146 const char* Simulator::VRegNameForCode(unsigned code) {
147 VIXL_ASSERT(code < kNumberOfVRegisters);
148 return vreg_names[code];
149 }
150
151
152 #define COLOUR(colour_code) "\033[0;" colour_code "m"
153 #define COLOUR_BOLD(colour_code) "\033[1;" colour_code "m"
154 #define NORMAL ""
155 #define GREY "30"
156 #define RED "31"
157 #define GREEN "32"
158 #define YELLOW "33"
159 #define BLUE "34"
160 #define MAGENTA "35"
161 #define CYAN "36"
162 #define WHITE "37"
set_coloured_trace(bool value)163 void Simulator::set_coloured_trace(bool value) {
164 coloured_trace_ = value;
165
166 clr_normal = value ? COLOUR(NORMAL) : "";
167 clr_flag_name = value ? COLOUR_BOLD(WHITE) : "";
168 clr_flag_value = value ? COLOUR(NORMAL) : "";
169 clr_reg_name = value ? COLOUR_BOLD(CYAN) : "";
170 clr_reg_value = value ? COLOUR(CYAN) : "";
171 clr_vreg_name = value ? COLOUR_BOLD(MAGENTA) : "";
172 clr_vreg_value = value ? COLOUR(MAGENTA) : "";
173 clr_memory_address = value ? COLOUR_BOLD(BLUE) : "";
174 clr_warning = value ? COLOUR_BOLD(YELLOW) : "";
175 clr_warning_message = value ? COLOUR(YELLOW) : "";
176 clr_printf = value ? COLOUR(GREEN) : "";
177 }
178 #undef COLOUR
179 #undef COLOUR_BOLD
180 #undef NORMAL
181 #undef GREY
182 #undef RED
183 #undef GREEN
184 #undef YELLOW
185 #undef BLUE
186 #undef MAGENTA
187 #undef CYAN
188 #undef WHITE
189
190
set_trace_parameters(int parameters)191 void Simulator::set_trace_parameters(int parameters) {
192 bool disasm_before = trace_parameters_ & LOG_DISASM;
193 trace_parameters_ = parameters;
194 bool disasm_after = trace_parameters_ & LOG_DISASM;
195
196 if (disasm_before != disasm_after) {
197 if (disasm_after) {
198 decoder_->InsertVisitorBefore(print_disasm_, this);
199 } else {
200 decoder_->RemoveVisitor(print_disasm_);
201 }
202 }
203 }
204
205
set_instruction_stats(bool value)206 void Simulator::set_instruction_stats(bool value) {
207 if (instrumentation_ == nullptr) {
208 return;
209 }
210
211 if (value != instruction_stats_) {
212 if (value) {
213 decoder_->AppendVisitor(instrumentation_);
214 } else {
215 decoder_->RemoveVisitor(instrumentation_);
216 }
217 instruction_stats_ = value;
218 }
219 }
220
221 // Helpers ---------------------------------------------------------------------
AddWithCarry(unsigned reg_size,bool set_flags,uint64_t left,uint64_t right,int carry_in)222 uint64_t Simulator::AddWithCarry(unsigned reg_size,
223 bool set_flags,
224 uint64_t left,
225 uint64_t right,
226 int carry_in) {
227 VIXL_ASSERT((carry_in == 0) || (carry_in == 1));
228 VIXL_ASSERT((reg_size == kXRegSize) || (reg_size == kWRegSize));
229
230 uint64_t max_uint = (reg_size == kWRegSize) ? kWMaxUInt : kXMaxUInt;
231 uint64_t reg_mask = (reg_size == kWRegSize) ? kWRegMask : kXRegMask;
232 uint64_t sign_mask = (reg_size == kWRegSize) ? kWSignMask : kXSignMask;
233
234 left &= reg_mask;
235 right &= reg_mask;
236 uint64_t result = (left + right + carry_in) & reg_mask;
237
238 if (set_flags) {
239 nzcv().SetN(CalcNFlag(result, reg_size));
240 nzcv().SetZ(CalcZFlag(result));
241
242 // Compute the C flag by comparing the result to the max unsigned integer.
243 uint64_t max_uint_2op = max_uint - carry_in;
244 bool C = (left > max_uint_2op) || ((max_uint_2op - left) < right);
245 nzcv().SetC(C ? 1 : 0);
246
247 // Overflow iff the sign bit is the same for the two inputs and different
248 // for the result.
249 uint64_t left_sign = left & sign_mask;
250 uint64_t right_sign = right & sign_mask;
251 uint64_t result_sign = result & sign_mask;
252 bool V = (left_sign == right_sign) && (left_sign != result_sign);
253 nzcv().SetV(V ? 1 : 0);
254
255 LogSystemRegister(NZCV);
256 }
257 return result;
258 }
259
260
ShiftOperand(unsigned reg_size,int64_t value,Shift shift_type,unsigned amount)261 int64_t Simulator::ShiftOperand(unsigned reg_size,
262 int64_t value,
263 Shift shift_type,
264 unsigned amount) {
265 if (amount == 0) {
266 return value;
267 }
268 int64_t mask = reg_size == kXRegSize ? kXRegMask : kWRegMask;
269 switch (shift_type) {
270 case LSL:
271 return (value << amount) & mask;
272 case LSR:
273 return static_cast<uint64_t>(value) >> amount;
274 case ASR: {
275 // Shift used to restore the sign.
276 unsigned s_shift = kXRegSize - reg_size;
277 // Value with its sign restored.
278 int64_t s_value = (value << s_shift) >> s_shift;
279 return (s_value >> amount) & mask;
280 }
281 case ROR: {
282 if (reg_size == kWRegSize) {
283 value &= kWRegMask;
284 }
285 return (static_cast<uint64_t>(value) >> amount) |
286 ((value & ((INT64_C(1) << amount) - 1)) <<
287 (reg_size - amount));
288 }
289 default:
290 VIXL_UNIMPLEMENTED();
291 return 0;
292 }
293 }
294
295
ExtendValue(unsigned reg_size,int64_t value,Extend extend_type,unsigned left_shift)296 int64_t Simulator::ExtendValue(unsigned reg_size,
297 int64_t value,
298 Extend extend_type,
299 unsigned left_shift) {
300 switch (extend_type) {
301 case UXTB:
302 value &= kByteMask;
303 break;
304 case UXTH:
305 value &= kHalfWordMask;
306 break;
307 case UXTW:
308 value &= kWordMask;
309 break;
310 case SXTB:
311 value = (value << 56) >> 56;
312 break;
313 case SXTH:
314 value = (value << 48) >> 48;
315 break;
316 case SXTW:
317 value = (value << 32) >> 32;
318 break;
319 case UXTX:
320 case SXTX:
321 break;
322 default:
323 VIXL_UNREACHABLE();
324 }
325 int64_t mask = (reg_size == kXRegSize) ? kXRegMask : kWRegMask;
326 return (value << left_shift) & mask;
327 }
328
329
FPCompare(double val0,double val1,FPTrapFlags trap)330 void Simulator::FPCompare(double val0, double val1, FPTrapFlags trap) {
331 AssertSupportedFPCR();
332
333 // TODO: This assumes that the C++ implementation handles comparisons in the
334 // way that we expect (as per AssertSupportedFPCR()).
335 bool process_exception = false;
336 if ((std::isnan(val0) != 0) || (std::isnan(val1) != 0)) {
337 nzcv().SetRawValue(FPUnorderedFlag);
338 if (IsSignallingNaN(val0) || IsSignallingNaN(val1) ||
339 (trap == EnableTrap)) {
340 process_exception = true;
341 }
342 } else if (val0 < val1) {
343 nzcv().SetRawValue(FPLessThanFlag);
344 } else if (val0 > val1) {
345 nzcv().SetRawValue(FPGreaterThanFlag);
346 } else if (val0 == val1) {
347 nzcv().SetRawValue(FPEqualFlag);
348 } else {
349 VIXL_UNREACHABLE();
350 }
351 LogSystemRegister(NZCV);
352 if (process_exception) FPProcessException();
353 }
354
355
GetPrintRegisterFormatForSize(unsigned reg_size,unsigned lane_size)356 Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormatForSize(
357 unsigned reg_size, unsigned lane_size) {
358 VIXL_ASSERT(reg_size >= lane_size);
359
360 uint32_t format = 0;
361 if (reg_size != lane_size) {
362 switch (reg_size) {
363 default: VIXL_UNREACHABLE(); break;
364 case kQRegSizeInBytes: format = kPrintRegAsQVector; break;
365 case kDRegSizeInBytes: format = kPrintRegAsDVector; break;
366 }
367 }
368
369 switch (lane_size) {
370 default: VIXL_UNREACHABLE(); break;
371 case kQRegSizeInBytes: format |= kPrintReg1Q; break;
372 case kDRegSizeInBytes: format |= kPrintReg1D; break;
373 case kSRegSizeInBytes: format |= kPrintReg1S; break;
374 case kHRegSizeInBytes: format |= kPrintReg1H; break;
375 case kBRegSizeInBytes: format |= kPrintReg1B; break;
376 }
377 // These sizes would be duplicate case labels.
378 VIXL_STATIC_ASSERT(kXRegSizeInBytes == kDRegSizeInBytes);
379 VIXL_STATIC_ASSERT(kWRegSizeInBytes == kSRegSizeInBytes);
380 VIXL_STATIC_ASSERT(kPrintXReg == kPrintReg1D);
381 VIXL_STATIC_ASSERT(kPrintWReg == kPrintReg1S);
382
383 return static_cast<PrintRegisterFormat>(format);
384 }
385
386
GetPrintRegisterFormat(VectorFormat vform)387 Simulator::PrintRegisterFormat Simulator::GetPrintRegisterFormat(
388 VectorFormat vform) {
389 switch (vform) {
390 default: VIXL_UNREACHABLE(); return kPrintReg16B;
391 case kFormat16B: return kPrintReg16B;
392 case kFormat8B: return kPrintReg8B;
393 case kFormat8H: return kPrintReg8H;
394 case kFormat4H: return kPrintReg4H;
395 case kFormat4S: return kPrintReg4S;
396 case kFormat2S: return kPrintReg2S;
397 case kFormat2D: return kPrintReg2D;
398 case kFormat1D: return kPrintReg1D;
399 }
400 }
401
402
PrintWrittenRegisters()403 void Simulator::PrintWrittenRegisters() {
404 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
405 if (registers_[i].WrittenSinceLastLog()) PrintRegister(i);
406 }
407 }
408
409
PrintWrittenVRegisters()410 void Simulator::PrintWrittenVRegisters() {
411 for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
412 // At this point there is no type information, so print as a raw 1Q.
413 if (vregisters_[i].WrittenSinceLastLog()) PrintVRegister(i, kPrintReg1Q);
414 }
415 }
416
417
PrintSystemRegisters()418 void Simulator::PrintSystemRegisters() {
419 PrintSystemRegister(NZCV);
420 PrintSystemRegister(FPCR);
421 }
422
423
PrintRegisters()424 void Simulator::PrintRegisters() {
425 for (unsigned i = 0; i < kNumberOfRegisters; i++) {
426 PrintRegister(i);
427 }
428 }
429
430
PrintVRegisters()431 void Simulator::PrintVRegisters() {
432 for (unsigned i = 0; i < kNumberOfVRegisters; i++) {
433 // At this point there is no type information, so print as a raw 1Q.
434 PrintVRegister(i, kPrintReg1Q);
435 }
436 }
437
438
439 // Print a register's name and raw value.
440 //
441 // Only the least-significant `size_in_bytes` bytes of the register are printed,
442 // but the value is aligned as if the whole register had been printed.
443 //
444 // For typical register updates, size_in_bytes should be set to kXRegSizeInBytes
445 // -- the default -- so that the whole register is printed. Other values of
446 // size_in_bytes are intended for use when the register hasn't actually been
447 // updated (such as in PrintWrite).
448 //
449 // No newline is printed. This allows the caller to print more details (such as
450 // a memory access annotation).
PrintRegisterRawHelper(unsigned code,Reg31Mode r31mode,int size_in_bytes)451 void Simulator::PrintRegisterRawHelper(unsigned code, Reg31Mode r31mode,
452 int size_in_bytes) {
453 // The template for all supported sizes.
454 // "# x{code}: 0xffeeddccbbaa9988"
455 // "# w{code}: 0xbbaa9988"
456 // "# w{code}<15:0>: 0x9988"
457 // "# w{code}<7:0>: 0x88"
458 unsigned padding_chars = (kXRegSizeInBytes - size_in_bytes) * 2;
459
460 const char * name = "";
461 const char * suffix = "";
462 switch (size_in_bytes) {
463 case kXRegSizeInBytes: name = XRegNameForCode(code, r31mode); break;
464 case kWRegSizeInBytes: name = WRegNameForCode(code, r31mode); break;
465 case 2:
466 name = WRegNameForCode(code, r31mode);
467 suffix = "<15:0>";
468 padding_chars -= strlen(suffix);
469 break;
470 case 1:
471 name = WRegNameForCode(code, r31mode);
472 suffix = "<7:0>";
473 padding_chars -= strlen(suffix);
474 break;
475 default:
476 VIXL_UNREACHABLE();
477 }
478 fprintf(stream_, "# %s%5s%s: ", clr_reg_name, name, suffix);
479
480 // Print leading padding spaces.
481 VIXL_ASSERT(padding_chars < (kXRegSizeInBytes * 2));
482 for (unsigned i = 0; i < padding_chars; i++) {
483 putc(' ', stream_);
484 }
485
486 // Print the specified bits in hexadecimal format.
487 uint64_t bits = reg<uint64_t>(code, r31mode);
488 bits &= kXRegMask >> ((kXRegSizeInBytes - size_in_bytes) * 8);
489 VIXL_STATIC_ASSERT(sizeof(bits) == kXRegSizeInBytes);
490
491 int chars = size_in_bytes * 2;
492 fprintf(stream_, "%s0x%0*" PRIx64 "%s",
493 clr_reg_value, chars, bits, clr_normal);
494 }
495
496
PrintRegister(unsigned code,Reg31Mode r31mode)497 void Simulator::PrintRegister(unsigned code, Reg31Mode r31mode) {
498 registers_[code].NotifyRegisterLogged();
499
500 // Don't print writes into xzr.
501 if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
502 return;
503 }
504
505 // The template for all x and w registers:
506 // "# x{code}: 0x{value}"
507 // "# w{code}: 0x{value}"
508
509 PrintRegisterRawHelper(code, r31mode);
510 fprintf(stream_, "\n");
511 }
512
513
514 // Print a register's name and raw value.
515 //
516 // The `bytes` and `lsb` arguments can be used to limit the bytes that are
517 // printed. These arguments are intended for use in cases where register hasn't
518 // actually been updated (such as in PrintVWrite).
519 //
520 // No newline is printed. This allows the caller to print more details (such as
521 // a floating-point interpretation or a memory access annotation).
PrintVRegisterRawHelper(unsigned code,int bytes,int lsb)522 void Simulator::PrintVRegisterRawHelper(unsigned code, int bytes, int lsb) {
523 // The template for vector types:
524 // "# v{code}: 0xffeeddccbbaa99887766554433221100".
525 // An example with bytes=4 and lsb=8:
526 // "# v{code}: 0xbbaa9988 ".
527 fprintf(stream_, "# %s%5s: %s",
528 clr_vreg_name, VRegNameForCode(code), clr_vreg_value);
529
530 int msb = lsb + bytes - 1;
531 int byte = kQRegSizeInBytes - 1;
532
533 // Print leading padding spaces. (Two spaces per byte.)
534 while (byte > msb) {
535 fprintf(stream_, " ");
536 byte--;
537 }
538
539 // Print the specified part of the value, byte by byte.
540 qreg_t rawbits = qreg(code);
541 fprintf(stream_, "0x");
542 while (byte >= lsb) {
543 fprintf(stream_, "%02x", rawbits.val[byte]);
544 byte--;
545 }
546
547 // Print trailing padding spaces.
548 while (byte >= 0) {
549 fprintf(stream_, " ");
550 byte--;
551 }
552 fprintf(stream_, "%s", clr_normal);
553 }
554
555
556 // Print each of the specified lanes of a register as a float or double value.
557 //
558 // The `lane_count` and `lslane` arguments can be used to limit the lanes that
559 // are printed. These arguments are intended for use in cases where register
560 // hasn't actually been updated (such as in PrintVWrite).
561 //
562 // No newline is printed. This allows the caller to print more details (such as
563 // a memory access annotation).
PrintVRegisterFPHelper(unsigned code,unsigned lane_size_in_bytes,int lane_count,int rightmost_lane)564 void Simulator::PrintVRegisterFPHelper(unsigned code,
565 unsigned lane_size_in_bytes,
566 int lane_count,
567 int rightmost_lane) {
568 VIXL_ASSERT((lane_size_in_bytes == kSRegSizeInBytes) ||
569 (lane_size_in_bytes == kDRegSizeInBytes));
570
571 unsigned msb = ((lane_count + rightmost_lane) * lane_size_in_bytes);
572 VIXL_ASSERT(msb <= kQRegSizeInBytes);
573
574 // For scalar types ((lane_count == 1) && (rightmost_lane == 0)), a register
575 // name is used:
576 // " (s{code}: {value})"
577 // " (d{code}: {value})"
578 // For vector types, "..." is used to represent one or more omitted lanes.
579 // " (..., {value}, {value}, ...)"
580 if ((lane_count == 1) && (rightmost_lane == 0)) {
581 const char * name =
582 (lane_size_in_bytes == kSRegSizeInBytes) ? SRegNameForCode(code)
583 : DRegNameForCode(code);
584 fprintf(stream_, " (%s%s: ", clr_vreg_name, name);
585 } else {
586 if (msb < (kQRegSizeInBytes - 1)) {
587 fprintf(stream_, " (..., ");
588 } else {
589 fprintf(stream_, " (");
590 }
591 }
592
593 // Print the list of values.
594 const char * separator = "";
595 int leftmost_lane = rightmost_lane + lane_count - 1;
596 for (int lane = leftmost_lane; lane >= rightmost_lane; lane--) {
597 double value =
598 (lane_size_in_bytes == kSRegSizeInBytes) ? vreg(code).Get<float>(lane)
599 : vreg(code).Get<double>(lane);
600 fprintf(stream_, "%s%s%#g%s", separator, clr_vreg_value, value, clr_normal);
601 separator = ", ";
602 }
603
604 if (rightmost_lane > 0) {
605 fprintf(stream_, ", ...");
606 }
607 fprintf(stream_, ")");
608 }
609
610
PrintVRegister(unsigned code,PrintRegisterFormat format)611 void Simulator::PrintVRegister(unsigned code, PrintRegisterFormat format) {
612 vregisters_[code].NotifyRegisterLogged();
613
614 int lane_size_log2 = format & kPrintRegLaneSizeMask;
615
616 int reg_size_log2;
617 if (format & kPrintRegAsQVector) {
618 reg_size_log2 = kQRegSizeInBytesLog2;
619 } else if (format & kPrintRegAsDVector) {
620 reg_size_log2 = kDRegSizeInBytesLog2;
621 } else {
622 // Scalar types.
623 reg_size_log2 = lane_size_log2;
624 }
625
626 int lane_count = 1 << (reg_size_log2 - lane_size_log2);
627 int lane_size = 1 << lane_size_log2;
628
629 // The template for vector types:
630 // "# v{code}: 0x{rawbits} (..., {value}, ...)".
631 // The template for scalar types:
632 // "# v{code}: 0x{rawbits} ({reg}:{value})".
633 // The values in parentheses after the bit representations are floating-point
634 // interpretations. They are displayed only if the kPrintVRegAsFP bit is set.
635
636 PrintVRegisterRawHelper(code);
637 if (format & kPrintRegAsFP) {
638 PrintVRegisterFPHelper(code, lane_size, lane_count);
639 }
640
641 fprintf(stream_, "\n");
642 }
643
644
PrintSystemRegister(SystemRegister id)645 void Simulator::PrintSystemRegister(SystemRegister id) {
646 switch (id) {
647 case NZCV:
648 fprintf(stream_, "# %sNZCV: %sN:%d Z:%d C:%d V:%d%s\n",
649 clr_flag_name, clr_flag_value,
650 nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(),
651 clr_normal);
652 break;
653 case FPCR: {
654 static const char * rmode[] = {
655 "0b00 (Round to Nearest)",
656 "0b01 (Round towards Plus Infinity)",
657 "0b10 (Round towards Minus Infinity)",
658 "0b11 (Round towards Zero)"
659 };
660 VIXL_ASSERT(fpcr().RMode() < (sizeof(rmode) / sizeof(rmode[0])));
661 fprintf(stream_,
662 "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n",
663 clr_flag_name, clr_flag_value,
664 fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()],
665 clr_normal);
666 break;
667 }
668 default:
669 VIXL_UNREACHABLE();
670 }
671 }
672
673
PrintRead(uintptr_t address,unsigned reg_code,PrintRegisterFormat format)674 void Simulator::PrintRead(uintptr_t address,
675 unsigned reg_code,
676 PrintRegisterFormat format) {
677 registers_[reg_code].NotifyRegisterLogged();
678
679 USE(format);
680
681 // The template is "# {reg}: 0x{value} <- {address}".
682 PrintRegisterRawHelper(reg_code, Reg31IsZeroRegister);
683 fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n",
684 clr_memory_address, address, clr_normal);
685 }
686
687
PrintVRead(uintptr_t address,unsigned reg_code,PrintRegisterFormat format,unsigned lane)688 void Simulator::PrintVRead(uintptr_t address,
689 unsigned reg_code,
690 PrintRegisterFormat format,
691 unsigned lane) {
692 vregisters_[reg_code].NotifyRegisterLogged();
693
694 // The template is "# v{code}: 0x{rawbits} <- address".
695 PrintVRegisterRawHelper(reg_code);
696 if (format & kPrintRegAsFP) {
697 PrintVRegisterFPHelper(reg_code, GetPrintRegLaneSizeInBytes(format),
698 GetPrintRegLaneCount(format), lane);
699 }
700 fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n",
701 clr_memory_address, address, clr_normal);
702 }
703
704
PrintWrite(uintptr_t address,unsigned reg_code,PrintRegisterFormat format)705 void Simulator::PrintWrite(uintptr_t address,
706 unsigned reg_code,
707 PrintRegisterFormat format) {
708 VIXL_ASSERT(GetPrintRegLaneCount(format) == 1);
709
710 // The template is "# v{code}: 0x{value} -> {address}". To keep the trace tidy
711 // and readable, the value is aligned with the values in the register trace.
712 PrintRegisterRawHelper(reg_code, Reg31IsZeroRegister,
713 GetPrintRegSizeInBytes(format));
714 fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n",
715 clr_memory_address, address, clr_normal);
716 }
717
718
PrintVWrite(uintptr_t address,unsigned reg_code,PrintRegisterFormat format,unsigned lane)719 void Simulator::PrintVWrite(uintptr_t address,
720 unsigned reg_code,
721 PrintRegisterFormat format,
722 unsigned lane) {
723 // The templates:
724 // "# v{code}: 0x{rawbits} -> {address}"
725 // "# v{code}: 0x{rawbits} (..., {value}, ...) -> {address}".
726 // "# v{code}: 0x{rawbits} ({reg}:{value}) -> {address}"
727 // Because this trace doesn't represent a change to the source register's
728 // value, only the relevant part of the value is printed. To keep the trace
729 // tidy and readable, the raw value is aligned with the other values in the
730 // register trace.
731 int lane_count = GetPrintRegLaneCount(format);
732 int lane_size = GetPrintRegLaneSizeInBytes(format);
733 int reg_size = GetPrintRegSizeInBytes(format);
734 PrintVRegisterRawHelper(reg_code, reg_size, lane_size * lane);
735 if (format & kPrintRegAsFP) {
736 PrintVRegisterFPHelper(reg_code, lane_size, lane_count, lane);
737 }
738 fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n",
739 clr_memory_address, address, clr_normal);
740 }
741
742
743 // Visitors---------------------------------------------------------------------
744
VisitUnimplemented(const Instruction * instr)745 void Simulator::VisitUnimplemented(const Instruction* instr) {
746 printf("Unimplemented instruction at %p: 0x%08" PRIx32 "\n",
747 reinterpret_cast<const void*>(instr), instr->InstructionBits());
748 VIXL_UNIMPLEMENTED();
749 }
750
751
VisitUnallocated(const Instruction * instr)752 void Simulator::VisitUnallocated(const Instruction* instr) {
753 printf("Unallocated instruction at %p: 0x%08" PRIx32 "\n",
754 reinterpret_cast<const void*>(instr), instr->InstructionBits());
755 VIXL_UNIMPLEMENTED();
756 }
757
758
VisitPCRelAddressing(const Instruction * instr)759 void Simulator::VisitPCRelAddressing(const Instruction* instr) {
760 VIXL_ASSERT((instr->Mask(PCRelAddressingMask) == ADR) ||
761 (instr->Mask(PCRelAddressingMask) == ADRP));
762
763 set_reg(instr->Rd(), instr->ImmPCOffsetTarget());
764 }
765
766
VisitUnconditionalBranch(const Instruction * instr)767 void Simulator::VisitUnconditionalBranch(const Instruction* instr) {
768 switch (instr->Mask(UnconditionalBranchMask)) {
769 case BL:
770 set_lr(instr->NextInstruction());
771 VIXL_FALLTHROUGH();
772 case B:
773 set_pc(instr->ImmPCOffsetTarget());
774 break;
775 default: VIXL_UNREACHABLE();
776 }
777 }
778
779
VisitConditionalBranch(const Instruction * instr)780 void Simulator::VisitConditionalBranch(const Instruction* instr) {
781 VIXL_ASSERT(instr->Mask(ConditionalBranchMask) == B_cond);
782 if (ConditionPassed(instr->ConditionBranch())) {
783 set_pc(instr->ImmPCOffsetTarget());
784 }
785 }
786
787
VisitUnconditionalBranchToRegister(const Instruction * instr)788 void Simulator::VisitUnconditionalBranchToRegister(const Instruction* instr) {
789 const Instruction* target = Instruction::Cast(xreg(instr->Rn()));
790
791 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
792 case BLR:
793 set_lr(instr->NextInstruction());
794 VIXL_FALLTHROUGH();
795 case BR:
796 case RET: set_pc(target); break;
797 default: VIXL_UNREACHABLE();
798 }
799 }
800
801
VisitTestBranch(const Instruction * instr)802 void Simulator::VisitTestBranch(const Instruction* instr) {
803 unsigned bit_pos = (instr->ImmTestBranchBit5() << 5) |
804 instr->ImmTestBranchBit40();
805 bool bit_zero = ((xreg(instr->Rt()) >> bit_pos) & 1) == 0;
806 bool take_branch = false;
807 switch (instr->Mask(TestBranchMask)) {
808 case TBZ: take_branch = bit_zero; break;
809 case TBNZ: take_branch = !bit_zero; break;
810 default: VIXL_UNIMPLEMENTED();
811 }
812 if (take_branch) {
813 set_pc(instr->ImmPCOffsetTarget());
814 }
815 }
816
817
VisitCompareBranch(const Instruction * instr)818 void Simulator::VisitCompareBranch(const Instruction* instr) {
819 unsigned rt = instr->Rt();
820 bool take_branch = false;
821 switch (instr->Mask(CompareBranchMask)) {
822 case CBZ_w: take_branch = (wreg(rt) == 0); break;
823 case CBZ_x: take_branch = (xreg(rt) == 0); break;
824 case CBNZ_w: take_branch = (wreg(rt) != 0); break;
825 case CBNZ_x: take_branch = (xreg(rt) != 0); break;
826 default: VIXL_UNIMPLEMENTED();
827 }
828 if (take_branch) {
829 set_pc(instr->ImmPCOffsetTarget());
830 }
831 }
832
833
AddSubHelper(const Instruction * instr,int64_t op2)834 void Simulator::AddSubHelper(const Instruction* instr, int64_t op2) {
835 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
836 bool set_flags = instr->FlagsUpdate();
837 int64_t new_val = 0;
838 Instr operation = instr->Mask(AddSubOpMask);
839
840 switch (operation) {
841 case ADD:
842 case ADDS: {
843 new_val = AddWithCarry(reg_size,
844 set_flags,
845 reg(reg_size, instr->Rn(), instr->RnMode()),
846 op2);
847 break;
848 }
849 case SUB:
850 case SUBS: {
851 new_val = AddWithCarry(reg_size,
852 set_flags,
853 reg(reg_size, instr->Rn(), instr->RnMode()),
854 ~op2,
855 1);
856 break;
857 }
858 default: VIXL_UNREACHABLE();
859 }
860
861 set_reg(reg_size, instr->Rd(), new_val, LogRegWrites, instr->RdMode());
862 }
863
864
VisitAddSubShifted(const Instruction * instr)865 void Simulator::VisitAddSubShifted(const Instruction* instr) {
866 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
867 int64_t op2 = ShiftOperand(reg_size,
868 reg(reg_size, instr->Rm()),
869 static_cast<Shift>(instr->ShiftDP()),
870 instr->ImmDPShift());
871 AddSubHelper(instr, op2);
872 }
873
874
VisitAddSubImmediate(const Instruction * instr)875 void Simulator::VisitAddSubImmediate(const Instruction* instr) {
876 int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0);
877 AddSubHelper(instr, op2);
878 }
879
880
VisitAddSubExtended(const Instruction * instr)881 void Simulator::VisitAddSubExtended(const Instruction* instr) {
882 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
883 int64_t op2 = ExtendValue(reg_size,
884 reg(reg_size, instr->Rm()),
885 static_cast<Extend>(instr->ExtendMode()),
886 instr->ImmExtendShift());
887 AddSubHelper(instr, op2);
888 }
889
890
VisitAddSubWithCarry(const Instruction * instr)891 void Simulator::VisitAddSubWithCarry(const Instruction* instr) {
892 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
893 int64_t op2 = reg(reg_size, instr->Rm());
894 int64_t new_val;
895
896 if ((instr->Mask(AddSubOpMask) == SUB) || instr->Mask(AddSubOpMask) == SUBS) {
897 op2 = ~op2;
898 }
899
900 new_val = AddWithCarry(reg_size,
901 instr->FlagsUpdate(),
902 reg(reg_size, instr->Rn()),
903 op2,
904 C());
905
906 set_reg(reg_size, instr->Rd(), new_val);
907 }
908
909
VisitLogicalShifted(const Instruction * instr)910 void Simulator::VisitLogicalShifted(const Instruction* instr) {
911 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
912 Shift shift_type = static_cast<Shift>(instr->ShiftDP());
913 unsigned shift_amount = instr->ImmDPShift();
914 int64_t op2 = ShiftOperand(reg_size, reg(reg_size, instr->Rm()), shift_type,
915 shift_amount);
916 if (instr->Mask(NOT) == NOT) {
917 op2 = ~op2;
918 }
919 LogicalHelper(instr, op2);
920 }
921
922
VisitLogicalImmediate(const Instruction * instr)923 void Simulator::VisitLogicalImmediate(const Instruction* instr) {
924 LogicalHelper(instr, instr->ImmLogical());
925 }
926
927
LogicalHelper(const Instruction * instr,int64_t op2)928 void Simulator::LogicalHelper(const Instruction* instr, int64_t op2) {
929 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
930 int64_t op1 = reg(reg_size, instr->Rn());
931 int64_t result = 0;
932 bool update_flags = false;
933
934 // Switch on the logical operation, stripping out the NOT bit, as it has a
935 // different meaning for logical immediate instructions.
936 switch (instr->Mask(LogicalOpMask & ~NOT)) {
937 case ANDS: update_flags = true; VIXL_FALLTHROUGH();
938 case AND: result = op1 & op2; break;
939 case ORR: result = op1 | op2; break;
940 case EOR: result = op1 ^ op2; break;
941 default:
942 VIXL_UNIMPLEMENTED();
943 }
944
945 if (update_flags) {
946 nzcv().SetN(CalcNFlag(result, reg_size));
947 nzcv().SetZ(CalcZFlag(result));
948 nzcv().SetC(0);
949 nzcv().SetV(0);
950 LogSystemRegister(NZCV);
951 }
952
953 set_reg(reg_size, instr->Rd(), result, LogRegWrites, instr->RdMode());
954 }
955
956
VisitConditionalCompareRegister(const Instruction * instr)957 void Simulator::VisitConditionalCompareRegister(const Instruction* instr) {
958 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
959 ConditionalCompareHelper(instr, reg(reg_size, instr->Rm()));
960 }
961
962
VisitConditionalCompareImmediate(const Instruction * instr)963 void Simulator::VisitConditionalCompareImmediate(const Instruction* instr) {
964 ConditionalCompareHelper(instr, instr->ImmCondCmp());
965 }
966
967
ConditionalCompareHelper(const Instruction * instr,int64_t op2)968 void Simulator::ConditionalCompareHelper(const Instruction* instr,
969 int64_t op2) {
970 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
971 int64_t op1 = reg(reg_size, instr->Rn());
972
973 if (ConditionPassed(instr->Condition())) {
974 // If the condition passes, set the status flags to the result of comparing
975 // the operands.
976 if (instr->Mask(ConditionalCompareMask) == CCMP) {
977 AddWithCarry(reg_size, true, op1, ~op2, 1);
978 } else {
979 VIXL_ASSERT(instr->Mask(ConditionalCompareMask) == CCMN);
980 AddWithCarry(reg_size, true, op1, op2, 0);
981 }
982 } else {
983 // If the condition fails, set the status flags to the nzcv immediate.
984 nzcv().SetFlags(instr->Nzcv());
985 LogSystemRegister(NZCV);
986 }
987 }
988
989
VisitLoadStoreUnsignedOffset(const Instruction * instr)990 void Simulator::VisitLoadStoreUnsignedOffset(const Instruction* instr) {
991 int offset = instr->ImmLSUnsigned() << instr->SizeLS();
992 LoadStoreHelper(instr, offset, Offset);
993 }
994
995
VisitLoadStoreUnscaledOffset(const Instruction * instr)996 void Simulator::VisitLoadStoreUnscaledOffset(const Instruction* instr) {
997 LoadStoreHelper(instr, instr->ImmLS(), Offset);
998 }
999
1000
VisitLoadStorePreIndex(const Instruction * instr)1001 void Simulator::VisitLoadStorePreIndex(const Instruction* instr) {
1002 LoadStoreHelper(instr, instr->ImmLS(), PreIndex);
1003 }
1004
1005
VisitLoadStorePostIndex(const Instruction * instr)1006 void Simulator::VisitLoadStorePostIndex(const Instruction* instr) {
1007 LoadStoreHelper(instr, instr->ImmLS(), PostIndex);
1008 }
1009
1010
VisitLoadStoreRegisterOffset(const Instruction * instr)1011 void Simulator::VisitLoadStoreRegisterOffset(const Instruction* instr) {
1012 Extend ext = static_cast<Extend>(instr->ExtendMode());
1013 VIXL_ASSERT((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX));
1014 unsigned shift_amount = instr->ImmShiftLS() * instr->SizeLS();
1015
1016 int64_t offset = ExtendValue(kXRegSize, xreg(instr->Rm()), ext,
1017 shift_amount);
1018 LoadStoreHelper(instr, offset, Offset);
1019 }
1020
1021 template<typename T>
Faulted()1022 static T Faulted() {
1023 return ~0;
1024 }
1025
1026 template<>
Faulted()1027 Simulator::qreg_t Faulted() {
1028 static_assert(kQRegSizeInBytes == 16, "Known constraint");
1029 static Simulator::qreg_t dummy = { {
1030 255, 255, 255, 255, 255, 255, 255, 255,
1031 255, 255, 255, 255, 255, 255, 255, 255
1032 } };
1033 return dummy;
1034 }
1035
1036 template<typename T> T
Read(uintptr_t address)1037 Simulator::Read(uintptr_t address)
1038 {
1039 address = Memory::AddressUntag(address);
1040 if (handle_wasm_seg_fault(address, sizeof(T)))
1041 return Faulted<T>();
1042 return Memory::Read<T>(address);
1043 }
1044
1045 template <typename T> void
Write(uintptr_t address,T value)1046 Simulator::Write(uintptr_t address, T value)
1047 {
1048 address = Memory::AddressUntag(address);
1049 if (handle_wasm_seg_fault(address, sizeof(T)))
1050 return;
1051 Memory::Write<T>(address, value);
1052 }
1053
LoadStoreHelper(const Instruction * instr,int64_t offset,AddrMode addrmode)1054 void Simulator::LoadStoreHelper(const Instruction* instr,
1055 int64_t offset,
1056 AddrMode addrmode) {
1057 unsigned srcdst = instr->Rt();
1058 uintptr_t address = AddressModeHelper(instr->Rn(), offset, addrmode);
1059
1060 LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreMask));
1061 switch (op) {
1062 case LDRB_w:
1063 set_wreg(srcdst, Read<uint8_t>(address), NoRegLog); break;
1064 case LDRH_w:
1065 set_wreg(srcdst, Read<uint16_t>(address), NoRegLog); break;
1066 case LDR_w:
1067 set_wreg(srcdst, Read<uint32_t>(address), NoRegLog); break;
1068 case LDR_x:
1069 set_xreg(srcdst, Read<uint64_t>(address), NoRegLog); break;
1070 case LDRSB_w:
1071 set_wreg(srcdst, Read<int8_t>(address), NoRegLog); break;
1072 case LDRSH_w:
1073 set_wreg(srcdst, Read<int16_t>(address), NoRegLog); break;
1074 case LDRSB_x:
1075 set_xreg(srcdst, Read<int8_t>(address), NoRegLog); break;
1076 case LDRSH_x:
1077 set_xreg(srcdst, Read<int16_t>(address), NoRegLog); break;
1078 case LDRSW_x:
1079 set_xreg(srcdst, Read<int32_t>(address), NoRegLog); break;
1080 case LDR_b:
1081 set_breg(srcdst, Read<uint8_t>(address), NoRegLog); break;
1082 case LDR_h:
1083 set_hreg(srcdst, Read<uint16_t>(address), NoRegLog); break;
1084 case LDR_s:
1085 set_sreg(srcdst, Read<float>(address), NoRegLog); break;
1086 case LDR_d:
1087 set_dreg(srcdst, Read<double>(address), NoRegLog); break;
1088 case LDR_q:
1089 set_qreg(srcdst, Read<qreg_t>(address), NoRegLog); break;
1090
1091 case STRB_w: Write<uint8_t>(address, wreg(srcdst)); break;
1092 case STRH_w: Write<uint16_t>(address, wreg(srcdst)); break;
1093 case STR_w: Write<uint32_t>(address, wreg(srcdst)); break;
1094 case STR_x: Write<uint64_t>(address, xreg(srcdst)); break;
1095 case STR_b: Write<uint8_t>(address, breg(srcdst)); break;
1096 case STR_h: Write<uint16_t>(address, hreg(srcdst)); break;
1097 case STR_s: Write<float>(address, sreg(srcdst)); break;
1098 case STR_d: Write<double>(address, dreg(srcdst)); break;
1099 case STR_q: Write<qreg_t>(address, qreg(srcdst)); break;
1100
1101 // Ignore prfm hint instructions.
1102 case PRFM: break;
1103
1104 default: VIXL_UNIMPLEMENTED();
1105 }
1106
1107 unsigned access_size = 1 << instr->SizeLS();
1108 if (instr->IsLoad()) {
1109 if ((op == LDR_s) || (op == LDR_d)) {
1110 LogVRead(address, srcdst, GetPrintRegisterFormatForSizeFP(access_size));
1111 } else if ((op == LDR_b) || (op == LDR_h) || (op == LDR_q)) {
1112 LogVRead(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1113 } else {
1114 LogRead(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1115 }
1116 } else {
1117 if ((op == STR_s) || (op == STR_d)) {
1118 LogVWrite(address, srcdst, GetPrintRegisterFormatForSizeFP(access_size));
1119 } else if ((op == STR_b) || (op == STR_h) || (op == STR_q)) {
1120 LogVWrite(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1121 } else {
1122 LogWrite(address, srcdst, GetPrintRegisterFormatForSize(access_size));
1123 }
1124 }
1125
1126 local_monitor_.MaybeClear();
1127 }
1128
1129
VisitLoadStorePairOffset(const Instruction * instr)1130 void Simulator::VisitLoadStorePairOffset(const Instruction* instr) {
1131 LoadStorePairHelper(instr, Offset);
1132 }
1133
1134
VisitLoadStorePairPreIndex(const Instruction * instr)1135 void Simulator::VisitLoadStorePairPreIndex(const Instruction* instr) {
1136 LoadStorePairHelper(instr, PreIndex);
1137 }
1138
1139
VisitLoadStorePairPostIndex(const Instruction * instr)1140 void Simulator::VisitLoadStorePairPostIndex(const Instruction* instr) {
1141 LoadStorePairHelper(instr, PostIndex);
1142 }
1143
1144
VisitLoadStorePairNonTemporal(const Instruction * instr)1145 void Simulator::VisitLoadStorePairNonTemporal(const Instruction* instr) {
1146 LoadStorePairHelper(instr, Offset);
1147 }
1148
1149
LoadStorePairHelper(const Instruction * instr,AddrMode addrmode)1150 void Simulator::LoadStorePairHelper(const Instruction* instr,
1151 AddrMode addrmode) {
1152 unsigned rt = instr->Rt();
1153 unsigned rt2 = instr->Rt2();
1154 int element_size = 1 << instr->SizeLSPair();
1155 int64_t offset = instr->ImmLSPair() * element_size;
1156 uintptr_t address = AddressModeHelper(instr->Rn(), offset, addrmode);
1157 uintptr_t address2 = address + element_size;
1158
1159 LoadStorePairOp op =
1160 static_cast<LoadStorePairOp>(instr->Mask(LoadStorePairMask));
1161
1162 // 'rt' and 'rt2' can only be aliased for stores.
1163 VIXL_ASSERT(((op & LoadStorePairLBit) == 0) || (rt != rt2));
1164
1165 switch (op) {
1166 // Use NoRegLog to suppress the register trace (LOG_REGS, LOG_FP_REGS). We
1167 // will print a more detailed log.
1168 case LDP_w: {
1169 set_wreg(rt, Read<uint32_t>(address), NoRegLog);
1170 set_wreg(rt2, Read<uint32_t>(address2), NoRegLog);
1171 break;
1172 }
1173 case LDP_s: {
1174 set_sreg(rt, Read<float>(address), NoRegLog);
1175 set_sreg(rt2, Read<float>(address2), NoRegLog);
1176 break;
1177 }
1178 case LDP_x: {
1179 set_xreg(rt, Read<uint64_t>(address), NoRegLog);
1180 set_xreg(rt2, Read<uint64_t>(address2), NoRegLog);
1181 break;
1182 }
1183 case LDP_d: {
1184 set_dreg(rt, Read<double>(address), NoRegLog);
1185 set_dreg(rt2, Read<double>(address2), NoRegLog);
1186 break;
1187 }
1188 case LDP_q: {
1189 set_qreg(rt, Read<qreg_t>(address), NoRegLog);
1190 set_qreg(rt2, Read<qreg_t>(address2), NoRegLog);
1191 break;
1192 }
1193 case LDPSW_x: {
1194 set_xreg(rt, Read<int32_t>(address), NoRegLog);
1195 set_xreg(rt2, Read<int32_t>(address2), NoRegLog);
1196 break;
1197 }
1198 case STP_w: {
1199 Write<uint32_t>(address, wreg(rt));
1200 Write<uint32_t>(address2, wreg(rt2));
1201 break;
1202 }
1203 case STP_s: {
1204 Write<float>(address, sreg(rt));
1205 Write<float>(address2, sreg(rt2));
1206 break;
1207 }
1208 case STP_x: {
1209 Write<uint64_t>(address, xreg(rt));
1210 Write<uint64_t>(address2, xreg(rt2));
1211 break;
1212 }
1213 case STP_d: {
1214 Write<double>(address, dreg(rt));
1215 Write<double>(address2, dreg(rt2));
1216 break;
1217 }
1218 case STP_q: {
1219 Write<qreg_t>(address, qreg(rt));
1220 Write<qreg_t>(address2, qreg(rt2));
1221 break;
1222 }
1223 default: VIXL_UNREACHABLE();
1224 }
1225
1226 // Print a detailed trace (including the memory address) instead of the basic
1227 // register:value trace generated by set_*reg().
1228 if (instr->IsLoad()) {
1229 if ((op == LDP_s) || (op == LDP_d)) {
1230 LogVRead(address, rt, GetPrintRegisterFormatForSizeFP(element_size));
1231 LogVRead(address2, rt2, GetPrintRegisterFormatForSizeFP(element_size));
1232 } else if (op == LDP_q) {
1233 LogVRead(address, rt, GetPrintRegisterFormatForSize(element_size));
1234 LogVRead(address2, rt2, GetPrintRegisterFormatForSize(element_size));
1235 } else {
1236 LogRead(address, rt, GetPrintRegisterFormatForSize(element_size));
1237 LogRead(address2, rt2, GetPrintRegisterFormatForSize(element_size));
1238 }
1239 } else {
1240 if ((op == STP_s) || (op == STP_d)) {
1241 LogVWrite(address, rt, GetPrintRegisterFormatForSizeFP(element_size));
1242 LogVWrite(address2, rt2, GetPrintRegisterFormatForSizeFP(element_size));
1243 } else if (op == STP_q) {
1244 LogVWrite(address, rt, GetPrintRegisterFormatForSize(element_size));
1245 LogVWrite(address2, rt2, GetPrintRegisterFormatForSize(element_size));
1246 } else {
1247 LogWrite(address, rt, GetPrintRegisterFormatForSize(element_size));
1248 LogWrite(address2, rt2, GetPrintRegisterFormatForSize(element_size));
1249 }
1250 }
1251
1252 local_monitor_.MaybeClear();
1253 }
1254
1255
PrintExclusiveAccessWarning()1256 void Simulator::PrintExclusiveAccessWarning() {
1257 if (print_exclusive_access_warning_) {
1258 fprintf(
1259 stderr,
1260 "%sWARNING:%s VIXL simulator support for load-/store-/clear-exclusive "
1261 "instructions is limited. Refer to the README for details.%s\n",
1262 clr_warning, clr_warning_message, clr_normal);
1263 print_exclusive_access_warning_ = false;
1264 }
1265 }
1266
1267
VisitLoadStoreExclusive(const Instruction * instr)1268 void Simulator::VisitLoadStoreExclusive(const Instruction* instr) {
1269 PrintExclusiveAccessWarning();
1270
1271 unsigned rs = instr->Rs();
1272 unsigned rt = instr->Rt();
1273 unsigned rt2 = instr->Rt2();
1274 unsigned rn = instr->Rn();
1275
1276 LoadStoreExclusive op =
1277 static_cast<LoadStoreExclusive>(instr->Mask(LoadStoreExclusiveMask));
1278
1279 bool is_acquire_release = instr->LdStXAcquireRelease();
1280 bool is_exclusive = !instr->LdStXNotExclusive();
1281 bool is_load = instr->LdStXLoad();
1282 bool is_pair = instr->LdStXPair();
1283
1284 unsigned element_size = 1 << instr->LdStXSizeLog2();
1285 unsigned access_size = is_pair ? element_size * 2 : element_size;
1286 uint64_t address = reg<uint64_t>(rn, Reg31IsStackPointer);
1287
1288 // Verify that the address is available to the host.
1289 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
1290
1291 // Check the alignment of `address`.
1292 if (AlignDown(address, access_size) != address) {
1293 VIXL_ALIGNMENT_EXCEPTION();
1294 }
1295
1296 // The sp must be aligned to 16 bytes when it is accessed.
1297 if ((rn == 31) && (AlignDown(address, 16) != address)) {
1298 VIXL_ALIGNMENT_EXCEPTION();
1299 }
1300
1301 if (is_load) {
1302 if (is_exclusive) {
1303 local_monitor_.MarkExclusive(address, access_size);
1304 } else {
1305 // Any non-exclusive load can clear the local monitor as a side effect. We
1306 // don't need to do this, but it is useful to stress the simulated code.
1307 local_monitor_.Clear();
1308 }
1309
1310 // Use NoRegLog to suppress the register trace (LOG_REGS, LOG_FP_REGS). We
1311 // will print a more detailed log.
1312 switch (op) {
1313 case LDXRB_w:
1314 case LDAXRB_w:
1315 case LDARB_w:
1316 set_wreg(rt, Read<uint8_t>(address), NoRegLog);
1317 break;
1318 case LDXRH_w:
1319 case LDAXRH_w:
1320 case LDARH_w:
1321 set_wreg(rt, Read<uint16_t>(address), NoRegLog);
1322 break;
1323 case LDXR_w:
1324 case LDAXR_w:
1325 case LDAR_w:
1326 set_wreg(rt, Read<uint32_t>(address), NoRegLog);
1327 break;
1328 case LDXR_x:
1329 case LDAXR_x:
1330 case LDAR_x:
1331 set_xreg(rt, Read<uint64_t>(address), NoRegLog);
1332 break;
1333 case LDXP_w:
1334 case LDAXP_w:
1335 set_wreg(rt, Read<uint32_t>(address), NoRegLog);
1336 set_wreg(rt2, Read<uint32_t>(address + element_size), NoRegLog);
1337 break;
1338 case LDXP_x:
1339 case LDAXP_x:
1340 set_xreg(rt, Read<uint64_t>(address), NoRegLog);
1341 set_xreg(rt2, Read<uint64_t>(address + element_size), NoRegLog);
1342 break;
1343 default:
1344 VIXL_UNREACHABLE();
1345 }
1346
1347 if (is_acquire_release) {
1348 // Approximate load-acquire by issuing a full barrier after the load.
1349 js::jit::AtomicOperations::fenceSeqCst();
1350 }
1351
1352 LogRead(address, rt, GetPrintRegisterFormatForSize(element_size));
1353 if (is_pair) {
1354 LogRead(address + element_size, rt2,
1355 GetPrintRegisterFormatForSize(element_size));
1356 }
1357 } else {
1358 if (is_acquire_release) {
1359 // Approximate store-release by issuing a full barrier before the store.
1360 js::jit::AtomicOperations::fenceSeqCst();
1361 }
1362
1363 bool do_store = true;
1364 if (is_exclusive) {
1365 do_store = local_monitor_.IsExclusive(address, access_size) &&
1366 global_monitor_.IsExclusive(address, access_size);
1367 set_wreg(rs, do_store ? 0 : 1);
1368
1369 // - All exclusive stores explicitly clear the local monitor.
1370 local_monitor_.Clear();
1371 } else {
1372 // - Any other store can clear the local monitor as a side effect.
1373 local_monitor_.MaybeClear();
1374 }
1375
1376 if (do_store) {
1377 switch (op) {
1378 case STXRB_w:
1379 case STLXRB_w:
1380 case STLRB_w:
1381 Write<uint8_t>(address, wreg(rt));
1382 break;
1383 case STXRH_w:
1384 case STLXRH_w:
1385 case STLRH_w:
1386 Write<uint16_t>(address, wreg(rt));
1387 break;
1388 case STXR_w:
1389 case STLXR_w:
1390 case STLR_w:
1391 Write<uint32_t>(address, wreg(rt));
1392 break;
1393 case STXR_x:
1394 case STLXR_x:
1395 case STLR_x:
1396 Write<uint64_t>(address, xreg(rt));
1397 break;
1398 case STXP_w:
1399 case STLXP_w:
1400 Write<uint32_t>(address, wreg(rt));
1401 Write<uint32_t>(address + element_size, wreg(rt2));
1402 break;
1403 case STXP_x:
1404 case STLXP_x:
1405 Write<uint64_t>(address, xreg(rt));
1406 Write<uint64_t>(address + element_size, xreg(rt2));
1407 break;
1408 default:
1409 VIXL_UNREACHABLE();
1410 }
1411
1412 LogWrite(address, rt, GetPrintRegisterFormatForSize(element_size));
1413 if (is_pair) {
1414 LogWrite(address + element_size, rt2,
1415 GetPrintRegisterFormatForSize(element_size));
1416 }
1417 }
1418 }
1419 }
1420
1421
VisitLoadLiteral(const Instruction * instr)1422 void Simulator::VisitLoadLiteral(const Instruction* instr) {
1423 unsigned rt = instr->Rt();
1424 uint64_t address = instr->LiteralAddress<uint64_t>();
1425
1426 // Verify that the calculated address is available to the host.
1427 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
1428
1429 switch (instr->Mask(LoadLiteralMask)) {
1430 // Use NoRegLog to suppress the register trace (LOG_REGS, LOG_VREGS), then
1431 // print a more detailed log.
1432 case LDR_w_lit:
1433 set_wreg(rt, Read<uint32_t>(address), NoRegLog);
1434 LogRead(address, rt, kPrintWReg);
1435 break;
1436 case LDR_x_lit:
1437 set_xreg(rt, Read<uint64_t>(address), NoRegLog);
1438 LogRead(address, rt, kPrintXReg);
1439 break;
1440 case LDR_s_lit:
1441 set_sreg(rt, Read<float>(address), NoRegLog);
1442 LogVRead(address, rt, kPrintSReg);
1443 break;
1444 case LDR_d_lit:
1445 set_dreg(rt, Read<double>(address), NoRegLog);
1446 LogVRead(address, rt, kPrintDReg);
1447 break;
1448 case LDR_q_lit:
1449 set_qreg(rt, Read<qreg_t>(address), NoRegLog);
1450 LogVRead(address, rt, kPrintReg1Q);
1451 break;
1452 case LDRSW_x_lit:
1453 set_xreg(rt, Read<int32_t>(address), NoRegLog);
1454 LogRead(address, rt, kPrintWReg);
1455 break;
1456
1457 // Ignore prfm hint instructions.
1458 case PRFM_lit: break;
1459
1460 default: VIXL_UNREACHABLE();
1461 }
1462
1463 local_monitor_.MaybeClear();
1464 }
1465
1466
AddressModeHelper(unsigned addr_reg,int64_t offset,AddrMode addrmode)1467 uintptr_t Simulator::AddressModeHelper(unsigned addr_reg,
1468 int64_t offset,
1469 AddrMode addrmode) {
1470 uint64_t address = xreg(addr_reg, Reg31IsStackPointer);
1471
1472 if ((addr_reg == 31) && ((address % 16) != 0)) {
1473 // When the base register is SP the stack pointer is required to be
1474 // quadword aligned prior to the address calculation and write-backs.
1475 // Misalignment will cause a stack alignment fault.
1476 VIXL_ALIGNMENT_EXCEPTION();
1477 }
1478
1479 if ((addrmode == PreIndex) || (addrmode == PostIndex)) {
1480 VIXL_ASSERT(offset != 0);
1481 // Only preindex should log the register update here. For Postindex, the
1482 // update will be printed automatically by LogWrittenRegisters _after_ the
1483 // memory access itself is logged.
1484 RegLogMode log_mode = (addrmode == PreIndex) ? LogRegWrites : NoRegLog;
1485 set_xreg(addr_reg, address + offset, log_mode, Reg31IsStackPointer);
1486 }
1487
1488 if ((addrmode == Offset) || (addrmode == PreIndex)) {
1489 address += offset;
1490 }
1491
1492 // Verify that the calculated address is available to the host.
1493 VIXL_ASSERT(address == static_cast<uintptr_t>(address));
1494
1495 return static_cast<uintptr_t>(address);
1496 }
1497
1498
VisitMoveWideImmediate(const Instruction * instr)1499 void Simulator::VisitMoveWideImmediate(const Instruction* instr) {
1500 MoveWideImmediateOp mov_op =
1501 static_cast<MoveWideImmediateOp>(instr->Mask(MoveWideImmediateMask));
1502 int64_t new_xn_val = 0;
1503
1504 bool is_64_bits = instr->SixtyFourBits() == 1;
1505 // Shift is limited for W operations.
1506 VIXL_ASSERT(is_64_bits || (instr->ShiftMoveWide() < 2));
1507
1508 // Get the shifted immediate.
1509 int64_t shift = instr->ShiftMoveWide() * 16;
1510 int64_t shifted_imm16 = static_cast<int64_t>(instr->ImmMoveWide()) << shift;
1511
1512 // Compute the new value.
1513 switch (mov_op) {
1514 case MOVN_w:
1515 case MOVN_x: {
1516 new_xn_val = ~shifted_imm16;
1517 if (!is_64_bits) new_xn_val &= kWRegMask;
1518 break;
1519 }
1520 case MOVK_w:
1521 case MOVK_x: {
1522 unsigned reg_code = instr->Rd();
1523 int64_t prev_xn_val = is_64_bits ? xreg(reg_code)
1524 : wreg(reg_code);
1525 new_xn_val =
1526 (prev_xn_val & ~(INT64_C(0xffff) << shift)) | shifted_imm16;
1527 break;
1528 }
1529 case MOVZ_w:
1530 case MOVZ_x: {
1531 new_xn_val = shifted_imm16;
1532 break;
1533 }
1534 default:
1535 VIXL_UNREACHABLE();
1536 }
1537
1538 // Update the destination register.
1539 set_xreg(instr->Rd(), new_xn_val);
1540 }
1541
1542
VisitConditionalSelect(const Instruction * instr)1543 void Simulator::VisitConditionalSelect(const Instruction* instr) {
1544 uint64_t new_val = xreg(instr->Rn());
1545
1546 if (ConditionFailed(static_cast<Condition>(instr->Condition()))) {
1547 new_val = xreg(instr->Rm());
1548 switch (instr->Mask(ConditionalSelectMask)) {
1549 case CSEL_w:
1550 case CSEL_x: break;
1551 case CSINC_w:
1552 case CSINC_x: new_val++; break;
1553 case CSINV_w:
1554 case CSINV_x: new_val = ~new_val; break;
1555 case CSNEG_w:
1556 case CSNEG_x: new_val = -new_val; break;
1557 default: VIXL_UNIMPLEMENTED();
1558 }
1559 }
1560 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
1561 set_reg(reg_size, instr->Rd(), new_val);
1562 }
1563
1564
VisitDataProcessing1Source(const Instruction * instr)1565 void Simulator::VisitDataProcessing1Source(const Instruction* instr) {
1566 unsigned dst = instr->Rd();
1567 unsigned src = instr->Rn();
1568
1569 switch (instr->Mask(DataProcessing1SourceMask)) {
1570 case RBIT_w: set_wreg(dst, ReverseBits(wreg(src))); break;
1571 case RBIT_x: set_xreg(dst, ReverseBits(xreg(src))); break;
1572 case REV16_w: set_wreg(dst, ReverseBytes(wreg(src), 1)); break;
1573 case REV16_x: set_xreg(dst, ReverseBytes(xreg(src), 1)); break;
1574 case REV_w: set_wreg(dst, ReverseBytes(wreg(src), 2)); break;
1575 case REV32_x: set_xreg(dst, ReverseBytes(xreg(src), 2)); break;
1576 case REV_x: set_xreg(dst, ReverseBytes(xreg(src), 3)); break;
1577 case CLZ_w: set_wreg(dst, CountLeadingZeros(wreg(src))); break;
1578 case CLZ_x: set_xreg(dst, CountLeadingZeros(xreg(src))); break;
1579 case CLS_w: {
1580 set_wreg(dst, CountLeadingSignBits(wreg(src)));
1581 break;
1582 }
1583 case CLS_x: {
1584 set_xreg(dst, CountLeadingSignBits(xreg(src)));
1585 break;
1586 }
1587 default: VIXL_UNIMPLEMENTED();
1588 }
1589 }
1590
1591
Poly32Mod2(unsigned n,uint64_t data,uint32_t poly)1592 uint32_t Simulator::Poly32Mod2(unsigned n, uint64_t data, uint32_t poly) {
1593 VIXL_ASSERT((n > 32) && (n <= 64));
1594 for (unsigned i = (n - 1); i >= 32; i--) {
1595 if (((data >> i) & 1) != 0) {
1596 uint64_t polysh32 = (uint64_t)poly << (i - 32);
1597 uint64_t mask = (UINT64_C(1) << i) - 1;
1598 data = ((data & mask) ^ polysh32);
1599 }
1600 }
1601 return data & 0xffffffff;
1602 }
1603
1604
1605 template <typename T>
Crc32Checksum(uint32_t acc,T val,uint32_t poly)1606 uint32_t Simulator::Crc32Checksum(uint32_t acc, T val, uint32_t poly) {
1607 unsigned size = sizeof(val) * 8; // Number of bits in type T.
1608 VIXL_ASSERT((size == 8) || (size == 16) || (size == 32));
1609 uint64_t tempacc = static_cast<uint64_t>(ReverseBits(acc)) << size;
1610 uint64_t tempval = static_cast<uint64_t>(ReverseBits(val)) << 32;
1611 return ReverseBits(Poly32Mod2(32 + size, tempacc ^ tempval, poly));
1612 }
1613
1614
Crc32Checksum(uint32_t acc,uint64_t val,uint32_t poly)1615 uint32_t Simulator::Crc32Checksum(uint32_t acc, uint64_t val, uint32_t poly) {
1616 // Poly32Mod2 cannot handle inputs with more than 32 bits, so compute
1617 // the CRC of each 32-bit word sequentially.
1618 acc = Crc32Checksum(acc, (uint32_t)(val & 0xffffffff), poly);
1619 return Crc32Checksum(acc, (uint32_t)(val >> 32), poly);
1620 }
1621
1622
VisitDataProcessing2Source(const Instruction * instr)1623 void Simulator::VisitDataProcessing2Source(const Instruction* instr) {
1624 Shift shift_op = NO_SHIFT;
1625 int64_t result = 0;
1626 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
1627
1628 switch (instr->Mask(DataProcessing2SourceMask)) {
1629 case SDIV_w: {
1630 int32_t rn = wreg(instr->Rn());
1631 int32_t rm = wreg(instr->Rm());
1632 if ((rn == kWMinInt) && (rm == -1)) {
1633 result = kWMinInt;
1634 } else if (rm == 0) {
1635 // Division by zero can be trapped, but not on A-class processors.
1636 result = 0;
1637 } else {
1638 result = rn / rm;
1639 }
1640 break;
1641 }
1642 case SDIV_x: {
1643 int64_t rn = xreg(instr->Rn());
1644 int64_t rm = xreg(instr->Rm());
1645 if ((rn == kXMinInt) && (rm == -1)) {
1646 result = kXMinInt;
1647 } else if (rm == 0) {
1648 // Division by zero can be trapped, but not on A-class processors.
1649 result = 0;
1650 } else {
1651 result = rn / rm;
1652 }
1653 break;
1654 }
1655 case UDIV_w: {
1656 uint32_t rn = static_cast<uint32_t>(wreg(instr->Rn()));
1657 uint32_t rm = static_cast<uint32_t>(wreg(instr->Rm()));
1658 if (rm == 0) {
1659 // Division by zero can be trapped, but not on A-class processors.
1660 result = 0;
1661 } else {
1662 result = rn / rm;
1663 }
1664 break;
1665 }
1666 case UDIV_x: {
1667 uint64_t rn = static_cast<uint64_t>(xreg(instr->Rn()));
1668 uint64_t rm = static_cast<uint64_t>(xreg(instr->Rm()));
1669 if (rm == 0) {
1670 // Division by zero can be trapped, but not on A-class processors.
1671 result = 0;
1672 } else {
1673 result = rn / rm;
1674 }
1675 break;
1676 }
1677 case LSLV_w:
1678 case LSLV_x: shift_op = LSL; break;
1679 case LSRV_w:
1680 case LSRV_x: shift_op = LSR; break;
1681 case ASRV_w:
1682 case ASRV_x: shift_op = ASR; break;
1683 case RORV_w:
1684 case RORV_x: shift_op = ROR; break;
1685 case CRC32B: {
1686 uint32_t acc = reg<uint32_t>(instr->Rn());
1687 uint8_t val = reg<uint8_t>(instr->Rm());
1688 result = Crc32Checksum(acc, val, CRC32_POLY);
1689 break;
1690 }
1691 case CRC32H: {
1692 uint32_t acc = reg<uint32_t>(instr->Rn());
1693 uint16_t val = reg<uint16_t>(instr->Rm());
1694 result = Crc32Checksum(acc, val, CRC32_POLY);
1695 break;
1696 }
1697 case CRC32W: {
1698 uint32_t acc = reg<uint32_t>(instr->Rn());
1699 uint32_t val = reg<uint32_t>(instr->Rm());
1700 result = Crc32Checksum(acc, val, CRC32_POLY);
1701 break;
1702 }
1703 case CRC32X: {
1704 uint32_t acc = reg<uint32_t>(instr->Rn());
1705 uint64_t val = reg<uint64_t>(instr->Rm());
1706 result = Crc32Checksum(acc, val, CRC32_POLY);
1707 reg_size = kWRegSize;
1708 break;
1709 }
1710 case CRC32CB: {
1711 uint32_t acc = reg<uint32_t>(instr->Rn());
1712 uint8_t val = reg<uint8_t>(instr->Rm());
1713 result = Crc32Checksum(acc, val, CRC32C_POLY);
1714 break;
1715 }
1716 case CRC32CH: {
1717 uint32_t acc = reg<uint32_t>(instr->Rn());
1718 uint16_t val = reg<uint16_t>(instr->Rm());
1719 result = Crc32Checksum(acc, val, CRC32C_POLY);
1720 break;
1721 }
1722 case CRC32CW: {
1723 uint32_t acc = reg<uint32_t>(instr->Rn());
1724 uint32_t val = reg<uint32_t>(instr->Rm());
1725 result = Crc32Checksum(acc, val, CRC32C_POLY);
1726 break;
1727 }
1728 case CRC32CX: {
1729 uint32_t acc = reg<uint32_t>(instr->Rn());
1730 uint64_t val = reg<uint64_t>(instr->Rm());
1731 result = Crc32Checksum(acc, val, CRC32C_POLY);
1732 reg_size = kWRegSize;
1733 break;
1734 }
1735 default: VIXL_UNIMPLEMENTED();
1736 }
1737
1738 if (shift_op != NO_SHIFT) {
1739 // Shift distance encoded in the least-significant five/six bits of the
1740 // register.
1741 int mask = (instr->SixtyFourBits() == 1) ? 0x3f : 0x1f;
1742 unsigned shift = wreg(instr->Rm()) & mask;
1743 result = ShiftOperand(reg_size, reg(reg_size, instr->Rn()), shift_op,
1744 shift);
1745 }
1746 set_reg(reg_size, instr->Rd(), result);
1747 }
1748
1749
1750 // The algorithm used is adapted from the one described in section 8.2 of
1751 // Hacker's Delight, by Henry S. Warren, Jr.
1752 // It assumes that a right shift on a signed integer is an arithmetic shift.
1753 // Type T must be either uint64_t or int64_t.
1754 template <typename T>
MultiplyHigh(T u,T v)1755 static T MultiplyHigh(T u, T v) {
1756 uint64_t u0, v0, w0;
1757 T u1, v1, w1, w2, t;
1758
1759 VIXL_ASSERT(sizeof(u) == sizeof(u0));
1760
1761 u0 = u & 0xffffffff;
1762 u1 = u >> 32;
1763 v0 = v & 0xffffffff;
1764 v1 = v >> 32;
1765
1766 w0 = u0 * v0;
1767 t = u1 * v0 + (w0 >> 32);
1768 w1 = t & 0xffffffff;
1769 w2 = t >> 32;
1770 w1 = u0 * v1 + w1;
1771
1772 return u1 * v1 + w2 + (w1 >> 32);
1773 }
1774
1775
VisitDataProcessing3Source(const Instruction * instr)1776 void Simulator::VisitDataProcessing3Source(const Instruction* instr) {
1777 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
1778
1779 int64_t result = 0;
1780 // Extract and sign- or zero-extend 32-bit arguments for widening operations.
1781 uint64_t rn_u32 = reg<uint32_t>(instr->Rn());
1782 uint64_t rm_u32 = reg<uint32_t>(instr->Rm());
1783 int64_t rn_s32 = reg<int32_t>(instr->Rn());
1784 int64_t rm_s32 = reg<int32_t>(instr->Rm());
1785 switch (instr->Mask(DataProcessing3SourceMask)) {
1786 case MADD_w:
1787 case MADD_x:
1788 result = xreg(instr->Ra()) + (xreg(instr->Rn()) * xreg(instr->Rm()));
1789 break;
1790 case MSUB_w:
1791 case MSUB_x:
1792 result = xreg(instr->Ra()) - (xreg(instr->Rn()) * xreg(instr->Rm()));
1793 break;
1794 case SMADDL_x: result = xreg(instr->Ra()) + (rn_s32 * rm_s32); break;
1795 case SMSUBL_x: result = xreg(instr->Ra()) - (rn_s32 * rm_s32); break;
1796 case UMADDL_x: result = xreg(instr->Ra()) + (rn_u32 * rm_u32); break;
1797 case UMSUBL_x: result = xreg(instr->Ra()) - (rn_u32 * rm_u32); break;
1798 case UMULH_x:
1799 result = MultiplyHigh(reg<uint64_t>(instr->Rn()),
1800 reg<uint64_t>(instr->Rm()));
1801 break;
1802 case SMULH_x:
1803 result = MultiplyHigh(xreg(instr->Rn()), xreg(instr->Rm()));
1804 break;
1805 default: VIXL_UNIMPLEMENTED();
1806 }
1807 set_reg(reg_size, instr->Rd(), result);
1808 }
1809
1810
VisitBitfield(const Instruction * instr)1811 void Simulator::VisitBitfield(const Instruction* instr) {
1812 unsigned reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
1813 int64_t reg_mask = instr->SixtyFourBits() ? kXRegMask : kWRegMask;
1814 int64_t R = instr->ImmR();
1815 int64_t S = instr->ImmS();
1816 int64_t diff = S - R;
1817 int64_t mask;
1818 if (diff >= 0) {
1819 mask = (diff < (reg_size - 1)) ? (INT64_C(1) << (diff + 1)) - 1
1820 : reg_mask;
1821 } else {
1822 mask = (INT64_C(1) << (S + 1)) - 1;
1823 mask = (static_cast<uint64_t>(mask) >> R) | (mask << (reg_size - R));
1824 diff += reg_size;
1825 }
1826
1827 // inzero indicates if the extracted bitfield is inserted into the
1828 // destination register value or in zero.
1829 // If extend is true, extend the sign of the extracted bitfield.
1830 bool inzero = false;
1831 bool extend = false;
1832 switch (instr->Mask(BitfieldMask)) {
1833 case BFM_x:
1834 case BFM_w:
1835 break;
1836 case SBFM_x:
1837 case SBFM_w:
1838 inzero = true;
1839 extend = true;
1840 break;
1841 case UBFM_x:
1842 case UBFM_w:
1843 inzero = true;
1844 break;
1845 default:
1846 VIXL_UNIMPLEMENTED();
1847 }
1848
1849 int64_t dst = inzero ? 0 : reg(reg_size, instr->Rd());
1850 int64_t src = reg(reg_size, instr->Rn());
1851 // Rotate source bitfield into place.
1852 int64_t result = (static_cast<uint64_t>(src) >> R) | (src << (reg_size - R));
1853 // Determine the sign extension.
1854 int64_t topbits = ((INT64_C(1) << (reg_size - diff - 1)) - 1) << (diff + 1);
1855 int64_t signbits = extend && ((src >> S) & 1) ? topbits : 0;
1856
1857 // Merge sign extension, dest/zero and bitfield.
1858 result = signbits | (result & mask) | (dst & ~mask);
1859
1860 set_reg(reg_size, instr->Rd(), result);
1861 }
1862
1863
VisitExtract(const Instruction * instr)1864 void Simulator::VisitExtract(const Instruction* instr) {
1865 unsigned lsb = instr->ImmS();
1866 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize
1867 : kWRegSize;
1868 uint64_t low_res = static_cast<uint64_t>(reg(reg_size, instr->Rm())) >> lsb;
1869 uint64_t high_res =
1870 (lsb == 0) ? 0 : reg(reg_size, instr->Rn()) << (reg_size - lsb);
1871 set_reg(reg_size, instr->Rd(), low_res | high_res);
1872 }
1873
1874
VisitFPImmediate(const Instruction * instr)1875 void Simulator::VisitFPImmediate(const Instruction* instr) {
1876 AssertSupportedFPCR();
1877
1878 unsigned dest = instr->Rd();
1879 switch (instr->Mask(FPImmediateMask)) {
1880 case FMOV_s_imm: set_sreg(dest, instr->ImmFP32()); break;
1881 case FMOV_d_imm: set_dreg(dest, instr->ImmFP64()); break;
1882 default: VIXL_UNREACHABLE();
1883 }
1884 }
1885
1886
VisitFPIntegerConvert(const Instruction * instr)1887 void Simulator::VisitFPIntegerConvert(const Instruction* instr) {
1888 AssertSupportedFPCR();
1889
1890 unsigned dst = instr->Rd();
1891 unsigned src = instr->Rn();
1892
1893 FPRounding round = RMode();
1894
1895 switch (instr->Mask(FPIntegerConvertMask)) {
1896 case FCVTAS_ws: set_wreg(dst, FPToInt32(sreg(src), FPTieAway)); break;
1897 case FCVTAS_xs: set_xreg(dst, FPToInt64(sreg(src), FPTieAway)); break;
1898 case FCVTAS_wd: set_wreg(dst, FPToInt32(dreg(src), FPTieAway)); break;
1899 case FCVTAS_xd: set_xreg(dst, FPToInt64(dreg(src), FPTieAway)); break;
1900 case FCVTAU_ws: set_wreg(dst, FPToUInt32(sreg(src), FPTieAway)); break;
1901 case FCVTAU_xs: set_xreg(dst, FPToUInt64(sreg(src), FPTieAway)); break;
1902 case FCVTAU_wd: set_wreg(dst, FPToUInt32(dreg(src), FPTieAway)); break;
1903 case FCVTAU_xd: set_xreg(dst, FPToUInt64(dreg(src), FPTieAway)); break;
1904 case FCVTMS_ws:
1905 set_wreg(dst, FPToInt32(sreg(src), FPNegativeInfinity));
1906 break;
1907 case FCVTMS_xs:
1908 set_xreg(dst, FPToInt64(sreg(src), FPNegativeInfinity));
1909 break;
1910 case FCVTMS_wd:
1911 set_wreg(dst, FPToInt32(dreg(src), FPNegativeInfinity));
1912 break;
1913 case FCVTMS_xd:
1914 set_xreg(dst, FPToInt64(dreg(src), FPNegativeInfinity));
1915 break;
1916 case FCVTMU_ws:
1917 set_wreg(dst, FPToUInt32(sreg(src), FPNegativeInfinity));
1918 break;
1919 case FCVTMU_xs:
1920 set_xreg(dst, FPToUInt64(sreg(src), FPNegativeInfinity));
1921 break;
1922 case FCVTMU_wd:
1923 set_wreg(dst, FPToUInt32(dreg(src), FPNegativeInfinity));
1924 break;
1925 case FCVTMU_xd:
1926 set_xreg(dst, FPToUInt64(dreg(src), FPNegativeInfinity));
1927 break;
1928 case FCVTPS_ws:
1929 set_wreg(dst, FPToInt32(sreg(src), FPPositiveInfinity));
1930 break;
1931 case FCVTPS_xs:
1932 set_xreg(dst, FPToInt64(sreg(src), FPPositiveInfinity));
1933 break;
1934 case FCVTPS_wd:
1935 set_wreg(dst, FPToInt32(dreg(src), FPPositiveInfinity));
1936 break;
1937 case FCVTPS_xd:
1938 set_xreg(dst, FPToInt64(dreg(src), FPPositiveInfinity));
1939 break;
1940 case FCVTPU_ws:
1941 set_wreg(dst, FPToUInt32(sreg(src), FPPositiveInfinity));
1942 break;
1943 case FCVTPU_xs:
1944 set_xreg(dst, FPToUInt64(sreg(src), FPPositiveInfinity));
1945 break;
1946 case FCVTPU_wd:
1947 set_wreg(dst, FPToUInt32(dreg(src), FPPositiveInfinity));
1948 break;
1949 case FCVTPU_xd:
1950 set_xreg(dst, FPToUInt64(dreg(src), FPPositiveInfinity));
1951 break;
1952 case FCVTNS_ws: set_wreg(dst, FPToInt32(sreg(src), FPTieEven)); break;
1953 case FCVTNS_xs: set_xreg(dst, FPToInt64(sreg(src), FPTieEven)); break;
1954 case FCVTNS_wd: set_wreg(dst, FPToInt32(dreg(src), FPTieEven)); break;
1955 case FCVTNS_xd: set_xreg(dst, FPToInt64(dreg(src), FPTieEven)); break;
1956 case FCVTNU_ws: set_wreg(dst, FPToUInt32(sreg(src), FPTieEven)); break;
1957 case FCVTNU_xs: set_xreg(dst, FPToUInt64(sreg(src), FPTieEven)); break;
1958 case FCVTNU_wd: set_wreg(dst, FPToUInt32(dreg(src), FPTieEven)); break;
1959 case FCVTNU_xd: set_xreg(dst, FPToUInt64(dreg(src), FPTieEven)); break;
1960 case FCVTZS_ws: set_wreg(dst, FPToInt32(sreg(src), FPZero)); break;
1961 case FCVTZS_xs: set_xreg(dst, FPToInt64(sreg(src), FPZero)); break;
1962 case FCVTZS_wd: set_wreg(dst, FPToInt32(dreg(src), FPZero)); break;
1963 case FCVTZS_xd: set_xreg(dst, FPToInt64(dreg(src), FPZero)); break;
1964 case FCVTZU_ws: set_wreg(dst, FPToUInt32(sreg(src), FPZero)); break;
1965 case FCVTZU_xs: set_xreg(dst, FPToUInt64(sreg(src), FPZero)); break;
1966 case FCVTZU_wd: set_wreg(dst, FPToUInt32(dreg(src), FPZero)); break;
1967 case FCVTZU_xd: set_xreg(dst, FPToUInt64(dreg(src), FPZero)); break;
1968 case FJCVTZS: set_wreg(dst, FPToFixedJS(dreg(src))); break;
1969 case FMOV_ws: set_wreg(dst, sreg_bits(src)); break;
1970 case FMOV_xd: set_xreg(dst, dreg_bits(src)); break;
1971 case FMOV_sw: set_sreg_bits(dst, wreg(src)); break;
1972 case FMOV_dx: set_dreg_bits(dst, xreg(src)); break;
1973 case FMOV_d1_x:
1974 LogicVRegister(vreg(dst)).SetUint(kFormatD, 1, xreg(src));
1975 break;
1976 case FMOV_x_d1:
1977 set_xreg(dst, LogicVRegister(vreg(src)).Uint(kFormatD, 1));
1978 break;
1979
1980 // A 32-bit input can be handled in the same way as a 64-bit input, since
1981 // the sign- or zero-extension will not affect the conversion.
1982 case SCVTF_dx: set_dreg(dst, FixedToDouble(xreg(src), 0, round)); break;
1983 case SCVTF_dw: set_dreg(dst, FixedToDouble(wreg(src), 0, round)); break;
1984 case UCVTF_dx: set_dreg(dst, UFixedToDouble(xreg(src), 0, round)); break;
1985 case UCVTF_dw: {
1986 set_dreg(dst, UFixedToDouble(static_cast<uint32_t>(wreg(src)), 0, round));
1987 break;
1988 }
1989 case SCVTF_sx: set_sreg(dst, FixedToFloat(xreg(src), 0, round)); break;
1990 case SCVTF_sw: set_sreg(dst, FixedToFloat(wreg(src), 0, round)); break;
1991 case UCVTF_sx: set_sreg(dst, UFixedToFloat(xreg(src), 0, round)); break;
1992 case UCVTF_sw: {
1993 set_sreg(dst, UFixedToFloat(static_cast<uint32_t>(wreg(src)), 0, round));
1994 break;
1995 }
1996
1997 default: VIXL_UNREACHABLE();
1998 }
1999 }
2000
2001
VisitFPFixedPointConvert(const Instruction * instr)2002 void Simulator::VisitFPFixedPointConvert(const Instruction* instr) {
2003 AssertSupportedFPCR();
2004
2005 unsigned dst = instr->Rd();
2006 unsigned src = instr->Rn();
2007 int fbits = 64 - instr->FPScale();
2008
2009 FPRounding round = RMode();
2010
2011 switch (instr->Mask(FPFixedPointConvertMask)) {
2012 // A 32-bit input can be handled in the same way as a 64-bit input, since
2013 // the sign- or zero-extension will not affect the conversion.
2014 case SCVTF_dx_fixed:
2015 set_dreg(dst, FixedToDouble(xreg(src), fbits, round));
2016 break;
2017 case SCVTF_dw_fixed:
2018 set_dreg(dst, FixedToDouble(wreg(src), fbits, round));
2019 break;
2020 case UCVTF_dx_fixed:
2021 set_dreg(dst, UFixedToDouble(xreg(src), fbits, round));
2022 break;
2023 case UCVTF_dw_fixed: {
2024 set_dreg(dst,
2025 UFixedToDouble(static_cast<uint32_t>(wreg(src)), fbits, round));
2026 break;
2027 }
2028 case SCVTF_sx_fixed:
2029 set_sreg(dst, FixedToFloat(xreg(src), fbits, round));
2030 break;
2031 case SCVTF_sw_fixed:
2032 set_sreg(dst, FixedToFloat(wreg(src), fbits, round));
2033 break;
2034 case UCVTF_sx_fixed:
2035 set_sreg(dst, UFixedToFloat(xreg(src), fbits, round));
2036 break;
2037 case UCVTF_sw_fixed: {
2038 set_sreg(dst,
2039 UFixedToFloat(static_cast<uint32_t>(wreg(src)), fbits, round));
2040 break;
2041 }
2042 case FCVTZS_xd_fixed:
2043 set_xreg(dst, FPToInt64(dreg(src) * std::pow(2.0, fbits), FPZero));
2044 break;
2045 case FCVTZS_wd_fixed:
2046 set_wreg(dst, FPToInt32(dreg(src) * std::pow(2.0, fbits), FPZero));
2047 break;
2048 case FCVTZU_xd_fixed:
2049 set_xreg(dst, FPToUInt64(dreg(src) * std::pow(2.0, fbits), FPZero));
2050 break;
2051 case FCVTZU_wd_fixed:
2052 set_wreg(dst, FPToUInt32(dreg(src) * std::pow(2.0, fbits), FPZero));
2053 break;
2054 case FCVTZS_xs_fixed:
2055 set_xreg(dst, FPToInt64(sreg(src) * std::pow(2.0f, fbits), FPZero));
2056 break;
2057 case FCVTZS_ws_fixed:
2058 set_wreg(dst, FPToInt32(sreg(src) * std::pow(2.0f, fbits), FPZero));
2059 break;
2060 case FCVTZU_xs_fixed:
2061 set_xreg(dst, FPToUInt64(sreg(src) * std::pow(2.0f, fbits), FPZero));
2062 break;
2063 case FCVTZU_ws_fixed:
2064 set_wreg(dst, FPToUInt32(sreg(src) * std::pow(2.0f, fbits), FPZero));
2065 break;
2066 default: VIXL_UNREACHABLE();
2067 }
2068 }
2069
2070
VisitFPCompare(const Instruction * instr)2071 void Simulator::VisitFPCompare(const Instruction* instr) {
2072 AssertSupportedFPCR();
2073
2074 FPTrapFlags trap = DisableTrap;
2075 switch (instr->Mask(FPCompareMask)) {
2076 case FCMPE_s: trap = EnableTrap; VIXL_FALLTHROUGH();
2077 case FCMP_s: FPCompare(sreg(instr->Rn()), sreg(instr->Rm()), trap); break;
2078 case FCMPE_d: trap = EnableTrap; VIXL_FALLTHROUGH();
2079 case FCMP_d: FPCompare(dreg(instr->Rn()), dreg(instr->Rm()), trap); break;
2080 case FCMPE_s_zero: trap = EnableTrap; VIXL_FALLTHROUGH();
2081 case FCMP_s_zero: FPCompare(sreg(instr->Rn()), 0.0f, trap); break;
2082 case FCMPE_d_zero: trap = EnableTrap; VIXL_FALLTHROUGH();
2083 case FCMP_d_zero: FPCompare(dreg(instr->Rn()), 0.0, trap); break;
2084 default: VIXL_UNIMPLEMENTED();
2085 }
2086 }
2087
2088
VisitFPConditionalCompare(const Instruction * instr)2089 void Simulator::VisitFPConditionalCompare(const Instruction* instr) {
2090 AssertSupportedFPCR();
2091
2092 FPTrapFlags trap = DisableTrap;
2093 switch (instr->Mask(FPConditionalCompareMask)) {
2094 case FCCMPE_s: trap = EnableTrap;
2095 VIXL_FALLTHROUGH();
2096 case FCCMP_s:
2097 if (ConditionPassed(instr->Condition())) {
2098 FPCompare(sreg(instr->Rn()), sreg(instr->Rm()), trap);
2099 } else {
2100 nzcv().SetFlags(instr->Nzcv());
2101 LogSystemRegister(NZCV);
2102 }
2103 break;
2104 case FCCMPE_d: trap = EnableTrap;
2105 VIXL_FALLTHROUGH();
2106 case FCCMP_d:
2107 if (ConditionPassed(instr->Condition())) {
2108 FPCompare(dreg(instr->Rn()), dreg(instr->Rm()), trap);
2109 } else {
2110 nzcv().SetFlags(instr->Nzcv());
2111 LogSystemRegister(NZCV);
2112 }
2113 break;
2114 default: VIXL_UNIMPLEMENTED();
2115 }
2116 }
2117
2118
VisitFPConditionalSelect(const Instruction * instr)2119 void Simulator::VisitFPConditionalSelect(const Instruction* instr) {
2120 AssertSupportedFPCR();
2121
2122 Instr selected;
2123 if (ConditionPassed(instr->Condition())) {
2124 selected = instr->Rn();
2125 } else {
2126 selected = instr->Rm();
2127 }
2128
2129 switch (instr->Mask(FPConditionalSelectMask)) {
2130 case FCSEL_s: set_sreg(instr->Rd(), sreg(selected)); break;
2131 case FCSEL_d: set_dreg(instr->Rd(), dreg(selected)); break;
2132 default: VIXL_UNIMPLEMENTED();
2133 }
2134 }
2135
2136
VisitFPDataProcessing1Source(const Instruction * instr)2137 void Simulator::VisitFPDataProcessing1Source(const Instruction* instr) {
2138 AssertSupportedFPCR();
2139
2140 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
2141 VectorFormat vform = (instr->Mask(FP64) == FP64) ? kFormatD : kFormatS;
2142 SimVRegister& rd = vreg(instr->Rd());
2143 SimVRegister& rn = vreg(instr->Rn());
2144 bool inexact_exception = false;
2145
2146 unsigned fd = instr->Rd();
2147 unsigned fn = instr->Rn();
2148
2149 switch (instr->Mask(FPDataProcessing1SourceMask)) {
2150 case FMOV_s: set_sreg(fd, sreg(fn)); return;
2151 case FMOV_d: set_dreg(fd, dreg(fn)); return;
2152 case FABS_s: fabs_(kFormatS, vreg(fd), vreg(fn)); return;
2153 case FABS_d: fabs_(kFormatD, vreg(fd), vreg(fn)); return;
2154 case FNEG_s: fneg(kFormatS, vreg(fd), vreg(fn)); return;
2155 case FNEG_d: fneg(kFormatD, vreg(fd), vreg(fn)); return;
2156 case FCVT_ds:
2157 set_dreg(fd, FPToDouble(sreg(fn), ReadDN()));
2158 return;
2159 case FCVT_sd:
2160 set_sreg(fd, FPToFloat(dreg(fn), FPTieEven, ReadDN()));
2161 return;
2162 case FCVT_hs:
2163 set_hreg(fd, Float16ToRawbits(FPToFloat16(sreg(fn), FPTieEven, ReadDN())));
2164 return;
2165 case FCVT_sh:
2166 set_sreg(fd, FPToFloat(RawbitsToFloat16(hreg(fn)), ReadDN()));
2167 return;
2168 case FCVT_dh:
2169 set_dreg(fd, FPToDouble(hreg(fn), ReadDN()));
2170 return;
2171 case FCVT_hd:
2172 set_hreg(fd, Float16ToRawbits(FPToFloat16(dreg(fn), FPTieEven, ReadDN())));
2173 return;
2174 case FSQRT_s:
2175 case FSQRT_d: fsqrt(vform, rd, rn); return;
2176 case FRINTI_s:
2177 case FRINTI_d: break; // Use FPCR rounding mode.
2178 case FRINTX_s:
2179 case FRINTX_d: inexact_exception = true; break;
2180 case FRINTA_s:
2181 case FRINTA_d: fpcr_rounding = FPTieAway; break;
2182 case FRINTM_s:
2183 case FRINTM_d: fpcr_rounding = FPNegativeInfinity; break;
2184 case FRINTN_s:
2185 case FRINTN_d: fpcr_rounding = FPTieEven; break;
2186 case FRINTP_s:
2187 case FRINTP_d: fpcr_rounding = FPPositiveInfinity; break;
2188 case FRINTZ_s:
2189 case FRINTZ_d: fpcr_rounding = FPZero; break;
2190 default: VIXL_UNIMPLEMENTED();
2191 }
2192
2193 // Only FRINT* instructions fall through the switch above.
2194 frint(vform, rd, rn, fpcr_rounding, inexact_exception);
2195 }
2196
2197
VisitFPDataProcessing2Source(const Instruction * instr)2198 void Simulator::VisitFPDataProcessing2Source(const Instruction* instr) {
2199 AssertSupportedFPCR();
2200
2201 VectorFormat vform = (instr->Mask(FP64) == FP64) ? kFormatD : kFormatS;
2202 SimVRegister& rd = vreg(instr->Rd());
2203 SimVRegister& rn = vreg(instr->Rn());
2204 SimVRegister& rm = vreg(instr->Rm());
2205
2206 switch (instr->Mask(FPDataProcessing2SourceMask)) {
2207 case FADD_s:
2208 case FADD_d: fadd(vform, rd, rn, rm); break;
2209 case FSUB_s:
2210 case FSUB_d: fsub(vform, rd, rn, rm); break;
2211 case FMUL_s:
2212 case FMUL_d: fmul(vform, rd, rn, rm); break;
2213 case FNMUL_s:
2214 case FNMUL_d: fnmul(vform, rd, rn, rm); break;
2215 case FDIV_s:
2216 case FDIV_d: fdiv(vform, rd, rn, rm); break;
2217 case FMAX_s:
2218 case FMAX_d: fmax(vform, rd, rn, rm); break;
2219 case FMIN_s:
2220 case FMIN_d: fmin(vform, rd, rn, rm); break;
2221 case FMAXNM_s:
2222 case FMAXNM_d: fmaxnm(vform, rd, rn, rm); break;
2223 case FMINNM_s:
2224 case FMINNM_d: fminnm(vform, rd, rn, rm); break;
2225 default:
2226 VIXL_UNREACHABLE();
2227 }
2228 }
2229
2230
VisitFPDataProcessing3Source(const Instruction * instr)2231 void Simulator::VisitFPDataProcessing3Source(const Instruction* instr) {
2232 AssertSupportedFPCR();
2233
2234 unsigned fd = instr->Rd();
2235 unsigned fn = instr->Rn();
2236 unsigned fm = instr->Rm();
2237 unsigned fa = instr->Ra();
2238
2239 switch (instr->Mask(FPDataProcessing3SourceMask)) {
2240 // fd = fa +/- (fn * fm)
2241 case FMADD_s: set_sreg(fd, FPMulAdd(sreg(fa), sreg(fn), sreg(fm))); break;
2242 case FMSUB_s: set_sreg(fd, FPMulAdd(sreg(fa), -sreg(fn), sreg(fm))); break;
2243 case FMADD_d: set_dreg(fd, FPMulAdd(dreg(fa), dreg(fn), dreg(fm))); break;
2244 case FMSUB_d: set_dreg(fd, FPMulAdd(dreg(fa), -dreg(fn), dreg(fm))); break;
2245 // Negated variants of the above.
2246 case FNMADD_s:
2247 set_sreg(fd, FPMulAdd(-sreg(fa), -sreg(fn), sreg(fm)));
2248 break;
2249 case FNMSUB_s:
2250 set_sreg(fd, FPMulAdd(-sreg(fa), sreg(fn), sreg(fm)));
2251 break;
2252 case FNMADD_d:
2253 set_dreg(fd, FPMulAdd(-dreg(fa), -dreg(fn), dreg(fm)));
2254 break;
2255 case FNMSUB_d:
2256 set_dreg(fd, FPMulAdd(-dreg(fa), dreg(fn), dreg(fm)));
2257 break;
2258 default: VIXL_UNIMPLEMENTED();
2259 }
2260 }
2261
2262
FPProcessNaNs(const Instruction * instr)2263 bool Simulator::FPProcessNaNs(const Instruction* instr) {
2264 unsigned fd = instr->Rd();
2265 unsigned fn = instr->Rn();
2266 unsigned fm = instr->Rm();
2267 bool done = false;
2268
2269 if (instr->Mask(FP64) == FP64) {
2270 double result = FPProcessNaNs(dreg(fn), dreg(fm));
2271 if (std::isnan(result)) {
2272 set_dreg(fd, result);
2273 done = true;
2274 }
2275 } else {
2276 float result = FPProcessNaNs(sreg(fn), sreg(fm));
2277 if (std::isnan(result)) {
2278 set_sreg(fd, result);
2279 done = true;
2280 }
2281 }
2282
2283 return done;
2284 }
2285
2286
SysOp_W(int op,int64_t val)2287 void Simulator::SysOp_W(int op, int64_t val) {
2288 switch (op) {
2289 case IVAU:
2290 case CVAC:
2291 case CVAU:
2292 case CIVAC: {
2293 // Perform a dummy memory access to ensure that we have read access
2294 // to the specified address.
2295 volatile uint8_t y = Read<uint8_t>(val);
2296 USE(y);
2297 // TODO: Implement "case ZVA:".
2298 break;
2299 }
2300 default:
2301 VIXL_UNIMPLEMENTED();
2302 }
2303 }
2304
2305
VisitSystem(const Instruction * instr)2306 void Simulator::VisitSystem(const Instruction* instr) {
2307 // Some system instructions hijack their Op and Cp fields to represent a
2308 // range of immediates instead of indicating a different instruction. This
2309 // makes the decoding tricky.
2310 if (instr->Mask(SystemExclusiveMonitorFMask) == SystemExclusiveMonitorFixed) {
2311 VIXL_ASSERT(instr->Mask(SystemExclusiveMonitorMask) == CLREX);
2312 switch (instr->Mask(SystemExclusiveMonitorMask)) {
2313 case CLREX: {
2314 PrintExclusiveAccessWarning();
2315 ClearLocalMonitor();
2316 break;
2317 }
2318 }
2319 } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
2320 switch (instr->Mask(SystemSysRegMask)) {
2321 case MRS: {
2322 switch (instr->ImmSystemRegister()) {
2323 case NZCV: set_xreg(instr->Rt(), nzcv().RawValue()); break;
2324 case FPCR: set_xreg(instr->Rt(), fpcr().RawValue()); break;
2325 default: VIXL_UNIMPLEMENTED();
2326 }
2327 break;
2328 }
2329 case MSR: {
2330 switch (instr->ImmSystemRegister()) {
2331 case NZCV:
2332 nzcv().SetRawValue(wreg(instr->Rt()));
2333 LogSystemRegister(NZCV);
2334 break;
2335 case FPCR:
2336 fpcr().SetRawValue(wreg(instr->Rt()));
2337 LogSystemRegister(FPCR);
2338 break;
2339 default: VIXL_UNIMPLEMENTED();
2340 }
2341 break;
2342 }
2343 }
2344 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
2345 VIXL_ASSERT(instr->Mask(SystemHintMask) == HINT);
2346 switch (instr->ImmHint()) {
2347 case NOP: break;
2348 case CSDB: break;
2349 default: VIXL_UNIMPLEMENTED();
2350 }
2351 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
2352 js::jit::AtomicOperations::fenceSeqCst();
2353 } else if ((instr->Mask(SystemSysFMask) == SystemSysFixed)) {
2354 switch (instr->Mask(SystemSysMask)) {
2355 case SYS: SysOp_W(instr->SysOp(), xreg(instr->Rt())); break;
2356 default: VIXL_UNIMPLEMENTED();
2357 }
2358 } else {
2359 VIXL_UNIMPLEMENTED();
2360 }
2361 }
2362
2363
VisitCrypto2RegSHA(const Instruction * instr)2364 void Simulator::VisitCrypto2RegSHA(const Instruction* instr) {
2365 VisitUnimplemented(instr);
2366 }
2367
2368
VisitCrypto3RegSHA(const Instruction * instr)2369 void Simulator::VisitCrypto3RegSHA(const Instruction* instr) {
2370 VisitUnimplemented(instr);
2371 }
2372
2373
VisitCryptoAES(const Instruction * instr)2374 void Simulator::VisitCryptoAES(const Instruction* instr) {
2375 VisitUnimplemented(instr);
2376 }
2377
2378
VisitNEON2RegMisc(const Instruction * instr)2379 void Simulator::VisitNEON2RegMisc(const Instruction* instr) {
2380 NEONFormatDecoder nfd(instr);
2381 VectorFormat vf = nfd.GetVectorFormat();
2382
2383 static const NEONFormatMap map_lp = {
2384 {23, 22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S, NF_1D, NF_2D}
2385 };
2386 VectorFormat vf_lp = nfd.GetVectorFormat(&map_lp);
2387
2388 static const NEONFormatMap map_fcvtl = {
2389 {22}, {NF_4S, NF_2D}
2390 };
2391 VectorFormat vf_fcvtl = nfd.GetVectorFormat(&map_fcvtl);
2392
2393 static const NEONFormatMap map_fcvtn = {
2394 {22, 30}, {NF_4H, NF_8H, NF_2S, NF_4S}
2395 };
2396 VectorFormat vf_fcvtn = nfd.GetVectorFormat(&map_fcvtn);
2397
2398 SimVRegister& rd = vreg(instr->Rd());
2399 SimVRegister& rn = vreg(instr->Rn());
2400
2401 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_opcode) {
2402 // These instructions all use a two bit size field, except NOT and RBIT,
2403 // which use the field to encode the operation.
2404 switch (instr->Mask(NEON2RegMiscMask)) {
2405 case NEON_REV64: rev64(vf, rd, rn); break;
2406 case NEON_REV32: rev32(vf, rd, rn); break;
2407 case NEON_REV16: rev16(vf, rd, rn); break;
2408 case NEON_SUQADD: suqadd(vf, rd, rn); break;
2409 case NEON_USQADD: usqadd(vf, rd, rn); break;
2410 case NEON_CLS: cls(vf, rd, rn); break;
2411 case NEON_CLZ: clz(vf, rd, rn); break;
2412 case NEON_CNT: cnt(vf, rd, rn); break;
2413 case NEON_SQABS: abs(vf, rd, rn).SignedSaturate(vf); break;
2414 case NEON_SQNEG: neg(vf, rd, rn).SignedSaturate(vf); break;
2415 case NEON_CMGT_zero: cmp(vf, rd, rn, 0, gt); break;
2416 case NEON_CMGE_zero: cmp(vf, rd, rn, 0, ge); break;
2417 case NEON_CMEQ_zero: cmp(vf, rd, rn, 0, eq); break;
2418 case NEON_CMLE_zero: cmp(vf, rd, rn, 0, le); break;
2419 case NEON_CMLT_zero: cmp(vf, rd, rn, 0, lt); break;
2420 case NEON_ABS: abs(vf, rd, rn); break;
2421 case NEON_NEG: neg(vf, rd, rn); break;
2422 case NEON_SADDLP: saddlp(vf_lp, rd, rn); break;
2423 case NEON_UADDLP: uaddlp(vf_lp, rd, rn); break;
2424 case NEON_SADALP: sadalp(vf_lp, rd, rn); break;
2425 case NEON_UADALP: uadalp(vf_lp, rd, rn); break;
2426 case NEON_RBIT_NOT:
2427 vf = nfd.GetVectorFormat(nfd.LogicalFormatMap());
2428 switch (instr->FPType()) {
2429 case 0: not_(vf, rd, rn); break;
2430 case 1: rbit(vf, rd, rn);; break;
2431 default:
2432 VIXL_UNIMPLEMENTED();
2433 }
2434 break;
2435 }
2436 } else {
2437 VectorFormat fpf = nfd.GetVectorFormat(nfd.FPFormatMap());
2438 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
2439 bool inexact_exception = false;
2440
2441 // These instructions all use a one bit size field, except XTN, SQXTUN,
2442 // SHLL, SQXTN and UQXTN, which use a two bit size field.
2443 switch (instr->Mask(NEON2RegMiscFPMask)) {
2444 case NEON_FABS: fabs_(fpf, rd, rn); return;
2445 case NEON_FNEG: fneg(fpf, rd, rn); return;
2446 case NEON_FSQRT: fsqrt(fpf, rd, rn); return;
2447 case NEON_FCVTL:
2448 if (instr->Mask(NEON_Q)) {
2449 fcvtl2(vf_fcvtl, rd, rn);
2450 } else {
2451 fcvtl(vf_fcvtl, rd, rn);
2452 }
2453 return;
2454 case NEON_FCVTN:
2455 if (instr->Mask(NEON_Q)) {
2456 fcvtn2(vf_fcvtn, rd, rn);
2457 } else {
2458 fcvtn(vf_fcvtn, rd, rn);
2459 }
2460 return;
2461 case NEON_FCVTXN:
2462 if (instr->Mask(NEON_Q)) {
2463 fcvtxn2(vf_fcvtn, rd, rn);
2464 } else {
2465 fcvtxn(vf_fcvtn, rd, rn);
2466 }
2467 return;
2468
2469 // The following instructions break from the switch statement, rather
2470 // than return.
2471 case NEON_FRINTI: break; // Use FPCR rounding mode.
2472 case NEON_FRINTX: inexact_exception = true; break;
2473 case NEON_FRINTA: fpcr_rounding = FPTieAway; break;
2474 case NEON_FRINTM: fpcr_rounding = FPNegativeInfinity; break;
2475 case NEON_FRINTN: fpcr_rounding = FPTieEven; break;
2476 case NEON_FRINTP: fpcr_rounding = FPPositiveInfinity; break;
2477 case NEON_FRINTZ: fpcr_rounding = FPZero; break;
2478
2479 case NEON_FCVTNS: fcvts(fpf, rd, rn, FPTieEven); return;
2480 case NEON_FCVTNU: fcvtu(fpf, rd, rn, FPTieEven); return;
2481 case NEON_FCVTPS: fcvts(fpf, rd, rn, FPPositiveInfinity); return;
2482 case NEON_FCVTPU: fcvtu(fpf, rd, rn, FPPositiveInfinity); return;
2483 case NEON_FCVTMS: fcvts(fpf, rd, rn, FPNegativeInfinity); return;
2484 case NEON_FCVTMU: fcvtu(fpf, rd, rn, FPNegativeInfinity); return;
2485 case NEON_FCVTZS: fcvts(fpf, rd, rn, FPZero); return;
2486 case NEON_FCVTZU: fcvtu(fpf, rd, rn, FPZero); return;
2487 case NEON_FCVTAS: fcvts(fpf, rd, rn, FPTieAway); return;
2488 case NEON_FCVTAU: fcvtu(fpf, rd, rn, FPTieAway); return;
2489 case NEON_SCVTF: scvtf(fpf, rd, rn, 0, fpcr_rounding); return;
2490 case NEON_UCVTF: ucvtf(fpf, rd, rn, 0, fpcr_rounding); return;
2491 case NEON_URSQRTE: ursqrte(fpf, rd, rn); return;
2492 case NEON_URECPE: urecpe(fpf, rd, rn); return;
2493 case NEON_FRSQRTE: frsqrte(fpf, rd, rn); return;
2494 case NEON_FRECPE: frecpe(fpf, rd, rn, fpcr_rounding); return;
2495 case NEON_FCMGT_zero: fcmp_zero(fpf, rd, rn, gt); return;
2496 case NEON_FCMGE_zero: fcmp_zero(fpf, rd, rn, ge); return;
2497 case NEON_FCMEQ_zero: fcmp_zero(fpf, rd, rn, eq); return;
2498 case NEON_FCMLE_zero: fcmp_zero(fpf, rd, rn, le); return;
2499 case NEON_FCMLT_zero: fcmp_zero(fpf, rd, rn, lt); return;
2500 default:
2501 if ((NEON_XTN_opcode <= instr->Mask(NEON2RegMiscOpcode)) &&
2502 (instr->Mask(NEON2RegMiscOpcode) <= NEON_UQXTN_opcode)) {
2503 switch (instr->Mask(NEON2RegMiscMask)) {
2504 case NEON_XTN: xtn(vf, rd, rn); return;
2505 case NEON_SQXTN: sqxtn(vf, rd, rn); return;
2506 case NEON_UQXTN: uqxtn(vf, rd, rn); return;
2507 case NEON_SQXTUN: sqxtun(vf, rd, rn); return;
2508 case NEON_SHLL:
2509 vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
2510 if (instr->Mask(NEON_Q)) {
2511 shll2(vf, rd, rn);
2512 } else {
2513 shll(vf, rd, rn);
2514 }
2515 return;
2516 default:
2517 VIXL_UNIMPLEMENTED();
2518 }
2519 } else {
2520 VIXL_UNIMPLEMENTED();
2521 }
2522 }
2523
2524 // Only FRINT* instructions fall through the switch above.
2525 frint(fpf, rd, rn, fpcr_rounding, inexact_exception);
2526 }
2527 }
2528
2529
VisitNEON3Same(const Instruction * instr)2530 void Simulator::VisitNEON3Same(const Instruction* instr) {
2531 NEONFormatDecoder nfd(instr);
2532 SimVRegister& rd = vreg(instr->Rd());
2533 SimVRegister& rn = vreg(instr->Rn());
2534 SimVRegister& rm = vreg(instr->Rm());
2535
2536 if (instr->Mask(NEON3SameLogicalFMask) == NEON3SameLogicalFixed) {
2537 VectorFormat vf = nfd.GetVectorFormat(nfd.LogicalFormatMap());
2538 switch (instr->Mask(NEON3SameLogicalMask)) {
2539 case NEON_AND: and_(vf, rd, rn, rm); break;
2540 case NEON_ORR: orr(vf, rd, rn, rm); break;
2541 case NEON_ORN: orn(vf, rd, rn, rm); break;
2542 case NEON_EOR: eor(vf, rd, rn, rm); break;
2543 case NEON_BIC: bic(vf, rd, rn, rm); break;
2544 case NEON_BIF: bif(vf, rd, rn, rm); break;
2545 case NEON_BIT: bit(vf, rd, rn, rm); break;
2546 case NEON_BSL: bsl(vf, rd, rn, rm); break;
2547 default:
2548 VIXL_UNIMPLEMENTED();
2549 }
2550 } else if (instr->Mask(NEON3SameFPFMask) == NEON3SameFPFixed) {
2551 VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap());
2552 switch (instr->Mask(NEON3SameFPMask)) {
2553 case NEON_FADD: fadd(vf, rd, rn, rm); break;
2554 case NEON_FSUB: fsub(vf, rd, rn, rm); break;
2555 case NEON_FMUL: fmul(vf, rd, rn, rm); break;
2556 case NEON_FDIV: fdiv(vf, rd, rn, rm); break;
2557 case NEON_FMAX: fmax(vf, rd, rn, rm); break;
2558 case NEON_FMIN: fmin(vf, rd, rn, rm); break;
2559 case NEON_FMAXNM: fmaxnm(vf, rd, rn, rm); break;
2560 case NEON_FMINNM: fminnm(vf, rd, rn, rm); break;
2561 case NEON_FMLA: fmla(vf, rd, rn, rm); break;
2562 case NEON_FMLS: fmls(vf, rd, rn, rm); break;
2563 case NEON_FMULX: fmulx(vf, rd, rn, rm); break;
2564 case NEON_FACGE: fabscmp(vf, rd, rn, rm, ge); break;
2565 case NEON_FACGT: fabscmp(vf, rd, rn, rm, gt); break;
2566 case NEON_FCMEQ: fcmp(vf, rd, rn, rm, eq); break;
2567 case NEON_FCMGE: fcmp(vf, rd, rn, rm, ge); break;
2568 case NEON_FCMGT: fcmp(vf, rd, rn, rm, gt); break;
2569 case NEON_FRECPS: frecps(vf, rd, rn, rm); break;
2570 case NEON_FRSQRTS: frsqrts(vf, rd, rn, rm); break;
2571 case NEON_FABD: fabd(vf, rd, rn, rm); break;
2572 case NEON_FADDP: faddp(vf, rd, rn, rm); break;
2573 case NEON_FMAXP: fmaxp(vf, rd, rn, rm); break;
2574 case NEON_FMAXNMP: fmaxnmp(vf, rd, rn, rm); break;
2575 case NEON_FMINP: fminp(vf, rd, rn, rm); break;
2576 case NEON_FMINNMP: fminnmp(vf, rd, rn, rm); break;
2577 default:
2578 VIXL_UNIMPLEMENTED();
2579 }
2580 } else {
2581 VectorFormat vf = nfd.GetVectorFormat();
2582 switch (instr->Mask(NEON3SameMask)) {
2583 case NEON_ADD: add(vf, rd, rn, rm); break;
2584 case NEON_ADDP: addp(vf, rd, rn, rm); break;
2585 case NEON_CMEQ: cmp(vf, rd, rn, rm, eq); break;
2586 case NEON_CMGE: cmp(vf, rd, rn, rm, ge); break;
2587 case NEON_CMGT: cmp(vf, rd, rn, rm, gt); break;
2588 case NEON_CMHI: cmp(vf, rd, rn, rm, hi); break;
2589 case NEON_CMHS: cmp(vf, rd, rn, rm, hs); break;
2590 case NEON_CMTST: cmptst(vf, rd, rn, rm); break;
2591 case NEON_MLS: mls(vf, rd, rn, rm); break;
2592 case NEON_MLA: mla(vf, rd, rn, rm); break;
2593 case NEON_MUL: mul(vf, rd, rn, rm); break;
2594 case NEON_PMUL: pmul(vf, rd, rn, rm); break;
2595 case NEON_SMAX: smax(vf, rd, rn, rm); break;
2596 case NEON_SMAXP: smaxp(vf, rd, rn, rm); break;
2597 case NEON_SMIN: smin(vf, rd, rn, rm); break;
2598 case NEON_SMINP: sminp(vf, rd, rn, rm); break;
2599 case NEON_SUB: sub(vf, rd, rn, rm); break;
2600 case NEON_UMAX: umax(vf, rd, rn, rm); break;
2601 case NEON_UMAXP: umaxp(vf, rd, rn, rm); break;
2602 case NEON_UMIN: umin(vf, rd, rn, rm); break;
2603 case NEON_UMINP: uminp(vf, rd, rn, rm); break;
2604 case NEON_SSHL: sshl(vf, rd, rn, rm); break;
2605 case NEON_USHL: ushl(vf, rd, rn, rm); break;
2606 case NEON_SABD: absdiff(vf, rd, rn, rm, true); break;
2607 case NEON_UABD: absdiff(vf, rd, rn, rm, false); break;
2608 case NEON_SABA: saba(vf, rd, rn, rm); break;
2609 case NEON_UABA: uaba(vf, rd, rn, rm); break;
2610 case NEON_UQADD: add(vf, rd, rn, rm).UnsignedSaturate(vf); break;
2611 case NEON_SQADD: add(vf, rd, rn, rm).SignedSaturate(vf); break;
2612 case NEON_UQSUB: sub(vf, rd, rn, rm).UnsignedSaturate(vf); break;
2613 case NEON_SQSUB: sub(vf, rd, rn, rm).SignedSaturate(vf); break;
2614 case NEON_SQDMULH: sqdmulh(vf, rd, rn, rm); break;
2615 case NEON_SQRDMULH: sqrdmulh(vf, rd, rn, rm); break;
2616 case NEON_UQSHL: ushl(vf, rd, rn, rm).UnsignedSaturate(vf); break;
2617 case NEON_SQSHL: sshl(vf, rd, rn, rm).SignedSaturate(vf); break;
2618 case NEON_URSHL: ushl(vf, rd, rn, rm).Round(vf); break;
2619 case NEON_SRSHL: sshl(vf, rd, rn, rm).Round(vf); break;
2620 case NEON_UQRSHL:
2621 ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf);
2622 break;
2623 case NEON_SQRSHL:
2624 sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf);
2625 break;
2626 case NEON_UHADD:
2627 add(vf, rd, rn, rm).Uhalve(vf);
2628 break;
2629 case NEON_URHADD:
2630 add(vf, rd, rn, rm).Uhalve(vf).Round(vf);
2631 break;
2632 case NEON_SHADD:
2633 add(vf, rd, rn, rm).Halve(vf);
2634 break;
2635 case NEON_SRHADD:
2636 add(vf, rd, rn, rm).Halve(vf).Round(vf);
2637 break;
2638 case NEON_UHSUB:
2639 sub(vf, rd, rn, rm).Uhalve(vf);
2640 break;
2641 case NEON_SHSUB:
2642 sub(vf, rd, rn, rm).Halve(vf);
2643 break;
2644 default:
2645 VIXL_UNIMPLEMENTED();
2646 }
2647 }
2648 }
2649
2650
VisitNEON3Different(const Instruction * instr)2651 void Simulator::VisitNEON3Different(const Instruction* instr) {
2652 NEONFormatDecoder nfd(instr);
2653 VectorFormat vf = nfd.GetVectorFormat();
2654 VectorFormat vf_l = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
2655
2656 SimVRegister& rd = vreg(instr->Rd());
2657 SimVRegister& rn = vreg(instr->Rn());
2658 SimVRegister& rm = vreg(instr->Rm());
2659
2660 switch (instr->Mask(NEON3DifferentMask)) {
2661 case NEON_PMULL: pmull(vf_l, rd, rn, rm); break;
2662 case NEON_PMULL2: pmull2(vf_l, rd, rn, rm); break;
2663 case NEON_UADDL: uaddl(vf_l, rd, rn, rm); break;
2664 case NEON_UADDL2: uaddl2(vf_l, rd, rn, rm); break;
2665 case NEON_SADDL: saddl(vf_l, rd, rn, rm); break;
2666 case NEON_SADDL2: saddl2(vf_l, rd, rn, rm); break;
2667 case NEON_USUBL: usubl(vf_l, rd, rn, rm); break;
2668 case NEON_USUBL2: usubl2(vf_l, rd, rn, rm); break;
2669 case NEON_SSUBL: ssubl(vf_l, rd, rn, rm); break;
2670 case NEON_SSUBL2: ssubl2(vf_l, rd, rn, rm); break;
2671 case NEON_SABAL: sabal(vf_l, rd, rn, rm); break;
2672 case NEON_SABAL2: sabal2(vf_l, rd, rn, rm); break;
2673 case NEON_UABAL: uabal(vf_l, rd, rn, rm); break;
2674 case NEON_UABAL2: uabal2(vf_l, rd, rn, rm); break;
2675 case NEON_SABDL: sabdl(vf_l, rd, rn, rm); break;
2676 case NEON_SABDL2: sabdl2(vf_l, rd, rn, rm); break;
2677 case NEON_UABDL: uabdl(vf_l, rd, rn, rm); break;
2678 case NEON_UABDL2: uabdl2(vf_l, rd, rn, rm); break;
2679 case NEON_SMLAL: smlal(vf_l, rd, rn, rm); break;
2680 case NEON_SMLAL2: smlal2(vf_l, rd, rn, rm); break;
2681 case NEON_UMLAL: umlal(vf_l, rd, rn, rm); break;
2682 case NEON_UMLAL2: umlal2(vf_l, rd, rn, rm); break;
2683 case NEON_SMLSL: smlsl(vf_l, rd, rn, rm); break;
2684 case NEON_SMLSL2: smlsl2(vf_l, rd, rn, rm); break;
2685 case NEON_UMLSL: umlsl(vf_l, rd, rn, rm); break;
2686 case NEON_UMLSL2: umlsl2(vf_l, rd, rn, rm); break;
2687 case NEON_SMULL: smull(vf_l, rd, rn, rm); break;
2688 case NEON_SMULL2: smull2(vf_l, rd, rn, rm); break;
2689 case NEON_UMULL: umull(vf_l, rd, rn, rm); break;
2690 case NEON_UMULL2: umull2(vf_l, rd, rn, rm); break;
2691 case NEON_SQDMLAL: sqdmlal(vf_l, rd, rn, rm); break;
2692 case NEON_SQDMLAL2: sqdmlal2(vf_l, rd, rn, rm); break;
2693 case NEON_SQDMLSL: sqdmlsl(vf_l, rd, rn, rm); break;
2694 case NEON_SQDMLSL2: sqdmlsl2(vf_l, rd, rn, rm); break;
2695 case NEON_SQDMULL: sqdmull(vf_l, rd, rn, rm); break;
2696 case NEON_SQDMULL2: sqdmull2(vf_l, rd, rn, rm); break;
2697 case NEON_UADDW: uaddw(vf_l, rd, rn, rm); break;
2698 case NEON_UADDW2: uaddw2(vf_l, rd, rn, rm); break;
2699 case NEON_SADDW: saddw(vf_l, rd, rn, rm); break;
2700 case NEON_SADDW2: saddw2(vf_l, rd, rn, rm); break;
2701 case NEON_USUBW: usubw(vf_l, rd, rn, rm); break;
2702 case NEON_USUBW2: usubw2(vf_l, rd, rn, rm); break;
2703 case NEON_SSUBW: ssubw(vf_l, rd, rn, rm); break;
2704 case NEON_SSUBW2: ssubw2(vf_l, rd, rn, rm); break;
2705 case NEON_ADDHN: addhn(vf, rd, rn, rm); break;
2706 case NEON_ADDHN2: addhn2(vf, rd, rn, rm); break;
2707 case NEON_RADDHN: raddhn(vf, rd, rn, rm); break;
2708 case NEON_RADDHN2: raddhn2(vf, rd, rn, rm); break;
2709 case NEON_SUBHN: subhn(vf, rd, rn, rm); break;
2710 case NEON_SUBHN2: subhn2(vf, rd, rn, rm); break;
2711 case NEON_RSUBHN: rsubhn(vf, rd, rn, rm); break;
2712 case NEON_RSUBHN2: rsubhn2(vf, rd, rn, rm); break;
2713 default:
2714 VIXL_UNIMPLEMENTED();
2715 }
2716 }
2717
2718
VisitNEONAcrossLanes(const Instruction * instr)2719 void Simulator::VisitNEONAcrossLanes(const Instruction* instr) {
2720 NEONFormatDecoder nfd(instr);
2721
2722 SimVRegister& rd = vreg(instr->Rd());
2723 SimVRegister& rn = vreg(instr->Rn());
2724
2725 // The input operand's VectorFormat is passed for these instructions.
2726 if (instr->Mask(NEONAcrossLanesFPFMask) == NEONAcrossLanesFPFixed) {
2727 VectorFormat vf = nfd.GetVectorFormat(nfd.FPFormatMap());
2728
2729 switch (instr->Mask(NEONAcrossLanesFPMask)) {
2730 case NEON_FMAXV: fmaxv(vf, rd, rn); break;
2731 case NEON_FMINV: fminv(vf, rd, rn); break;
2732 case NEON_FMAXNMV: fmaxnmv(vf, rd, rn); break;
2733 case NEON_FMINNMV: fminnmv(vf, rd, rn); break;
2734 default:
2735 VIXL_UNIMPLEMENTED();
2736 }
2737 } else {
2738 VectorFormat vf = nfd.GetVectorFormat();
2739
2740 switch (instr->Mask(NEONAcrossLanesMask)) {
2741 case NEON_ADDV: addv(vf, rd, rn); break;
2742 case NEON_SMAXV: smaxv(vf, rd, rn); break;
2743 case NEON_SMINV: sminv(vf, rd, rn); break;
2744 case NEON_UMAXV: umaxv(vf, rd, rn); break;
2745 case NEON_UMINV: uminv(vf, rd, rn); break;
2746 case NEON_SADDLV: saddlv(vf, rd, rn); break;
2747 case NEON_UADDLV: uaddlv(vf, rd, rn); break;
2748 default:
2749 VIXL_UNIMPLEMENTED();
2750 }
2751 }
2752 }
2753
2754
VisitNEONByIndexedElement(const Instruction * instr)2755 void Simulator::VisitNEONByIndexedElement(const Instruction* instr) {
2756 NEONFormatDecoder nfd(instr);
2757 VectorFormat vf_r = nfd.GetVectorFormat();
2758 VectorFormat vf = nfd.GetVectorFormat(nfd.LongIntegerFormatMap());
2759
2760 SimVRegister& rd = vreg(instr->Rd());
2761 SimVRegister& rn = vreg(instr->Rn());
2762
2763 ByElementOp Op = NULL;
2764
2765 int rm_reg = instr->Rm();
2766 int index = (instr->NEONH() << 1) | instr->NEONL();
2767 if (instr->NEONSize() == 1) {
2768 rm_reg &= 0xf;
2769 index = (index << 1) | instr->NEONM();
2770 }
2771
2772 switch (instr->Mask(NEONByIndexedElementMask)) {
2773 case NEON_MUL_byelement: Op = &Simulator::mul; vf = vf_r; break;
2774 case NEON_MLA_byelement: Op = &Simulator::mla; vf = vf_r; break;
2775 case NEON_MLS_byelement: Op = &Simulator::mls; vf = vf_r; break;
2776 case NEON_SQDMULH_byelement: Op = &Simulator::sqdmulh; vf = vf_r; break;
2777 case NEON_SQRDMULH_byelement: Op = &Simulator::sqrdmulh; vf = vf_r; break;
2778 case NEON_SMULL_byelement:
2779 if (instr->Mask(NEON_Q)) {
2780 Op = &Simulator::smull2;
2781 } else {
2782 Op = &Simulator::smull;
2783 }
2784 break;
2785 case NEON_UMULL_byelement:
2786 if (instr->Mask(NEON_Q)) {
2787 Op = &Simulator::umull2;
2788 } else {
2789 Op = &Simulator::umull;
2790 }
2791 break;
2792 case NEON_SMLAL_byelement:
2793 if (instr->Mask(NEON_Q)) {
2794 Op = &Simulator::smlal2;
2795 } else {
2796 Op = &Simulator::smlal;
2797 }
2798 break;
2799 case NEON_UMLAL_byelement:
2800 if (instr->Mask(NEON_Q)) {
2801 Op = &Simulator::umlal2;
2802 } else {
2803 Op = &Simulator::umlal;
2804 }
2805 break;
2806 case NEON_SMLSL_byelement:
2807 if (instr->Mask(NEON_Q)) {
2808 Op = &Simulator::smlsl2;
2809 } else {
2810 Op = &Simulator::smlsl;
2811 }
2812 break;
2813 case NEON_UMLSL_byelement:
2814 if (instr->Mask(NEON_Q)) {
2815 Op = &Simulator::umlsl2;
2816 } else {
2817 Op = &Simulator::umlsl;
2818 }
2819 break;
2820 case NEON_SQDMULL_byelement:
2821 if (instr->Mask(NEON_Q)) {
2822 Op = &Simulator::sqdmull2;
2823 } else {
2824 Op = &Simulator::sqdmull;
2825 }
2826 break;
2827 case NEON_SQDMLAL_byelement:
2828 if (instr->Mask(NEON_Q)) {
2829 Op = &Simulator::sqdmlal2;
2830 } else {
2831 Op = &Simulator::sqdmlal;
2832 }
2833 break;
2834 case NEON_SQDMLSL_byelement:
2835 if (instr->Mask(NEON_Q)) {
2836 Op = &Simulator::sqdmlsl2;
2837 } else {
2838 Op = &Simulator::sqdmlsl;
2839 }
2840 break;
2841 default:
2842 index = instr->NEONH();
2843 if ((instr->FPType() & 1) == 0) {
2844 index = (index << 1) | instr->NEONL();
2845 }
2846
2847 vf = nfd.GetVectorFormat(nfd.FPFormatMap());
2848
2849 switch (instr->Mask(NEONByIndexedElementFPMask)) {
2850 case NEON_FMUL_byelement: Op = &Simulator::fmul; break;
2851 case NEON_FMLA_byelement: Op = &Simulator::fmla; break;
2852 case NEON_FMLS_byelement: Op = &Simulator::fmls; break;
2853 case NEON_FMULX_byelement: Op = &Simulator::fmulx; break;
2854 default: VIXL_UNIMPLEMENTED();
2855 }
2856 }
2857
2858 (this->*Op)(vf, rd, rn, vreg(rm_reg), index);
2859 }
2860
2861
VisitNEONCopy(const Instruction * instr)2862 void Simulator::VisitNEONCopy(const Instruction* instr) {
2863 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularFormatMap());
2864 VectorFormat vf = nfd.GetVectorFormat();
2865
2866 SimVRegister& rd = vreg(instr->Rd());
2867 SimVRegister& rn = vreg(instr->Rn());
2868 int imm5 = instr->ImmNEON5();
2869 int tz = CountTrailingZeros(imm5, 32);
2870 int reg_index = imm5 >> (tz + 1);
2871
2872 if (instr->Mask(NEONCopyInsElementMask) == NEON_INS_ELEMENT) {
2873 int imm4 = instr->ImmNEON4();
2874 int rn_index = imm4 >> tz;
2875 ins_element(vf, rd, reg_index, rn, rn_index);
2876 } else if (instr->Mask(NEONCopyInsGeneralMask) == NEON_INS_GENERAL) {
2877 ins_immediate(vf, rd, reg_index, xreg(instr->Rn()));
2878 } else if (instr->Mask(NEONCopyUmovMask) == NEON_UMOV) {
2879 uint64_t value = LogicVRegister(rn).Uint(vf, reg_index);
2880 value &= MaxUintFromFormat(vf);
2881 set_xreg(instr->Rd(), value);
2882 } else if (instr->Mask(NEONCopyUmovMask) == NEON_SMOV) {
2883 int64_t value = LogicVRegister(rn).Int(vf, reg_index);
2884 if (instr->NEONQ()) {
2885 set_xreg(instr->Rd(), value);
2886 } else {
2887 set_wreg(instr->Rd(), (int32_t)value);
2888 }
2889 } else if (instr->Mask(NEONCopyDupElementMask) == NEON_DUP_ELEMENT) {
2890 dup_element(vf, rd, rn, reg_index);
2891 } else if (instr->Mask(NEONCopyDupGeneralMask) == NEON_DUP_GENERAL) {
2892 dup_immediate(vf, rd, xreg(instr->Rn()));
2893 } else {
2894 VIXL_UNIMPLEMENTED();
2895 }
2896 }
2897
2898
VisitNEONExtract(const Instruction * instr)2899 void Simulator::VisitNEONExtract(const Instruction* instr) {
2900 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
2901 VectorFormat vf = nfd.GetVectorFormat();
2902 SimVRegister& rd = vreg(instr->Rd());
2903 SimVRegister& rn = vreg(instr->Rn());
2904 SimVRegister& rm = vreg(instr->Rm());
2905 if (instr->Mask(NEONExtractMask) == NEON_EXT) {
2906 int index = instr->ImmNEONExt();
2907 ext(vf, rd, rn, rm, index);
2908 } else {
2909 VIXL_UNIMPLEMENTED();
2910 }
2911 }
2912
2913
NEONLoadStoreMultiStructHelper(const Instruction * instr,AddrMode addr_mode)2914 void Simulator::NEONLoadStoreMultiStructHelper(const Instruction* instr,
2915 AddrMode addr_mode) {
2916 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
2917 VectorFormat vf = nfd.GetVectorFormat();
2918
2919 uint64_t addr_base = xreg(instr->Rn(), Reg31IsStackPointer);
2920 int reg_size = RegisterSizeInBytesFromFormat(vf);
2921
2922 int reg[4];
2923 uint64_t addr[4];
2924 for (int i = 0; i < 4; i++) {
2925 reg[i] = (instr->Rt() + i) % kNumberOfVRegisters;
2926 addr[i] = addr_base + (i * reg_size);
2927 }
2928 int count = 1;
2929 bool log_read = true;
2930
2931 Instr itype = instr->Mask(NEONLoadStoreMultiStructMask);
2932 if (((itype == NEON_LD1_1v) || (itype == NEON_LD1_2v) ||
2933 (itype == NEON_LD1_3v) || (itype == NEON_LD1_4v) ||
2934 (itype == NEON_ST1_1v) || (itype == NEON_ST1_2v) ||
2935 (itype == NEON_ST1_3v) || (itype == NEON_ST1_4v)) &&
2936 (instr->Bits(20, 16) != 0)) {
2937 VIXL_UNREACHABLE();
2938 }
2939
2940 // We use the PostIndex mask here, as it works in this case for both Offset
2941 // and PostIndex addressing.
2942 switch (instr->Mask(NEONLoadStoreMultiStructPostIndexMask)) {
2943 case NEON_LD1_4v:
2944 case NEON_LD1_4v_post: ld1(vf, vreg(reg[3]), addr[3]); count++;
2945 VIXL_FALLTHROUGH();
2946 case NEON_LD1_3v:
2947 case NEON_LD1_3v_post: ld1(vf, vreg(reg[2]), addr[2]); count++;
2948 VIXL_FALLTHROUGH();
2949 case NEON_LD1_2v:
2950 case NEON_LD1_2v_post: ld1(vf, vreg(reg[1]), addr[1]); count++;
2951 VIXL_FALLTHROUGH();
2952 case NEON_LD1_1v:
2953 case NEON_LD1_1v_post:
2954 ld1(vf, vreg(reg[0]), addr[0]);
2955 log_read = true;
2956 break;
2957 case NEON_ST1_4v:
2958 case NEON_ST1_4v_post: st1(vf, vreg(reg[3]), addr[3]); count++;
2959 VIXL_FALLTHROUGH();
2960 case NEON_ST1_3v:
2961 case NEON_ST1_3v_post: st1(vf, vreg(reg[2]), addr[2]); count++;
2962 VIXL_FALLTHROUGH();
2963 case NEON_ST1_2v:
2964 case NEON_ST1_2v_post: st1(vf, vreg(reg[1]), addr[1]); count++;
2965 VIXL_FALLTHROUGH();
2966 case NEON_ST1_1v:
2967 case NEON_ST1_1v_post:
2968 st1(vf, vreg(reg[0]), addr[0]);
2969 log_read = false;
2970 break;
2971 case NEON_LD2_post:
2972 case NEON_LD2:
2973 ld2(vf, vreg(reg[0]), vreg(reg[1]), addr[0]);
2974 count = 2;
2975 break;
2976 case NEON_ST2:
2977 case NEON_ST2_post:
2978 st2(vf, vreg(reg[0]), vreg(reg[1]), addr[0]);
2979 count = 2;
2980 break;
2981 case NEON_LD3_post:
2982 case NEON_LD3:
2983 ld3(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), addr[0]);
2984 count = 3;
2985 break;
2986 case NEON_ST3:
2987 case NEON_ST3_post:
2988 st3(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), addr[0]);
2989 count = 3;
2990 break;
2991 case NEON_ST4:
2992 case NEON_ST4_post:
2993 st4(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), vreg(reg[3]),
2994 addr[0]);
2995 count = 4;
2996 break;
2997 case NEON_LD4_post:
2998 case NEON_LD4:
2999 ld4(vf, vreg(reg[0]), vreg(reg[1]), vreg(reg[2]), vreg(reg[3]),
3000 addr[0]);
3001 count = 4;
3002 break;
3003 default: VIXL_UNIMPLEMENTED();
3004 }
3005
3006 // Explicitly log the register update whilst we have type information.
3007 for (int i = 0; i < count; i++) {
3008 // For de-interleaving loads, only print the base address.
3009 int lane_size = LaneSizeInBytesFromFormat(vf);
3010 PrintRegisterFormat format = GetPrintRegisterFormatTryFP(
3011 GetPrintRegisterFormatForSize(reg_size, lane_size));
3012 if (log_read) {
3013 LogVRead(addr_base, reg[i], format);
3014 } else {
3015 LogVWrite(addr_base, reg[i], format);
3016 }
3017 }
3018
3019 if (addr_mode == PostIndex) {
3020 int rm = instr->Rm();
3021 // The immediate post index addressing mode is indicated by rm = 31.
3022 // The immediate is implied by the number of vector registers used.
3023 addr_base += (rm == 31) ? RegisterSizeInBytesFromFormat(vf) * count
3024 : xreg(rm);
3025 set_xreg(instr->Rn(), addr_base);
3026 } else {
3027 VIXL_ASSERT(addr_mode == Offset);
3028 }
3029 }
3030
3031
VisitNEONLoadStoreMultiStruct(const Instruction * instr)3032 void Simulator::VisitNEONLoadStoreMultiStruct(const Instruction* instr) {
3033 NEONLoadStoreMultiStructHelper(instr, Offset);
3034 }
3035
3036
VisitNEONLoadStoreMultiStructPostIndex(const Instruction * instr)3037 void Simulator::VisitNEONLoadStoreMultiStructPostIndex(
3038 const Instruction* instr) {
3039 NEONLoadStoreMultiStructHelper(instr, PostIndex);
3040 }
3041
3042
NEONLoadStoreSingleStructHelper(const Instruction * instr,AddrMode addr_mode)3043 void Simulator::NEONLoadStoreSingleStructHelper(const Instruction* instr,
3044 AddrMode addr_mode) {
3045 uint64_t addr = xreg(instr->Rn(), Reg31IsStackPointer);
3046 int rt = instr->Rt();
3047
3048 Instr itype = instr->Mask(NEONLoadStoreSingleStructMask);
3049 if (((itype == NEON_LD1_b) || (itype == NEON_LD1_h) ||
3050 (itype == NEON_LD1_s) || (itype == NEON_LD1_d)) &&
3051 (instr->Bits(20, 16) != 0)) {
3052 VIXL_UNREACHABLE();
3053 }
3054
3055 // We use the PostIndex mask here, as it works in this case for both Offset
3056 // and PostIndex addressing.
3057 bool do_load = false;
3058
3059 bool replicating = false;
3060
3061 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LoadStoreFormatMap());
3062 VectorFormat vf_t = nfd.GetVectorFormat();
3063
3064 VectorFormat vf = kFormat16B;
3065 switch (instr->Mask(NEONLoadStoreSingleStructPostIndexMask)) {
3066 case NEON_LD1_b:
3067 case NEON_LD1_b_post:
3068 case NEON_LD2_b:
3069 case NEON_LD2_b_post:
3070 case NEON_LD3_b:
3071 case NEON_LD3_b_post:
3072 case NEON_LD4_b:
3073 case NEON_LD4_b_post: do_load = true;
3074 VIXL_FALLTHROUGH();
3075 case NEON_ST1_b:
3076 case NEON_ST1_b_post:
3077 case NEON_ST2_b:
3078 case NEON_ST2_b_post:
3079 case NEON_ST3_b:
3080 case NEON_ST3_b_post:
3081 case NEON_ST4_b:
3082 case NEON_ST4_b_post: break;
3083
3084 case NEON_LD1_h:
3085 case NEON_LD1_h_post:
3086 case NEON_LD2_h:
3087 case NEON_LD2_h_post:
3088 case NEON_LD3_h:
3089 case NEON_LD3_h_post:
3090 case NEON_LD4_h:
3091 case NEON_LD4_h_post: do_load = true;
3092 VIXL_FALLTHROUGH();
3093 case NEON_ST1_h:
3094 case NEON_ST1_h_post:
3095 case NEON_ST2_h:
3096 case NEON_ST2_h_post:
3097 case NEON_ST3_h:
3098 case NEON_ST3_h_post:
3099 case NEON_ST4_h:
3100 case NEON_ST4_h_post: vf = kFormat8H; break;
3101 case NEON_LD1_s:
3102 case NEON_LD1_s_post:
3103 case NEON_LD2_s:
3104 case NEON_LD2_s_post:
3105 case NEON_LD3_s:
3106 case NEON_LD3_s_post:
3107 case NEON_LD4_s:
3108 case NEON_LD4_s_post: do_load = true;
3109 VIXL_FALLTHROUGH();
3110 case NEON_ST1_s:
3111 case NEON_ST1_s_post:
3112 case NEON_ST2_s:
3113 case NEON_ST2_s_post:
3114 case NEON_ST3_s:
3115 case NEON_ST3_s_post:
3116 case NEON_ST4_s:
3117 case NEON_ST4_s_post: {
3118 VIXL_STATIC_ASSERT((NEON_LD1_s | (1 << NEONLSSize_offset)) == NEON_LD1_d);
3119 VIXL_STATIC_ASSERT(
3120 (NEON_LD1_s_post | (1 << NEONLSSize_offset)) == NEON_LD1_d_post);
3121 VIXL_STATIC_ASSERT((NEON_ST1_s | (1 << NEONLSSize_offset)) == NEON_ST1_d);
3122 VIXL_STATIC_ASSERT(
3123 (NEON_ST1_s_post | (1 << NEONLSSize_offset)) == NEON_ST1_d_post);
3124 vf = ((instr->NEONLSSize() & 1) == 0) ? kFormat4S : kFormat2D;
3125 break;
3126 }
3127
3128 case NEON_LD1R:
3129 case NEON_LD1R_post:
3130 case NEON_LD2R:
3131 case NEON_LD2R_post:
3132 case NEON_LD3R:
3133 case NEON_LD3R_post:
3134 case NEON_LD4R:
3135 case NEON_LD4R_post: {
3136 vf = vf_t;
3137 do_load = true;
3138 replicating = true;
3139 break;
3140 }
3141 default: VIXL_UNIMPLEMENTED();
3142 }
3143
3144 PrintRegisterFormat print_format =
3145 GetPrintRegisterFormatTryFP(GetPrintRegisterFormat(vf));
3146 // Make sure that the print_format only includes a single lane.
3147 print_format =
3148 static_cast<PrintRegisterFormat>(print_format & ~kPrintRegAsVectorMask);
3149
3150 int esize = LaneSizeInBytesFromFormat(vf);
3151 int index_shift = LaneSizeInBytesLog2FromFormat(vf);
3152 int lane = instr->NEONLSIndex(index_shift);
3153 int scale = 0;
3154 int rt2 = (rt + 1) % kNumberOfVRegisters;
3155 int rt3 = (rt2 + 1) % kNumberOfVRegisters;
3156 int rt4 = (rt3 + 1) % kNumberOfVRegisters;
3157 switch (instr->Mask(NEONLoadStoreSingleLenMask)) {
3158 case NEONLoadStoreSingle1:
3159 scale = 1;
3160 if (do_load) {
3161 if (replicating) {
3162 ld1r(vf, vreg(rt), addr);
3163 } else {
3164 ld1(vf, vreg(rt), lane, addr);
3165 }
3166 LogVRead(addr, rt, print_format, lane);
3167 } else {
3168 st1(vf, vreg(rt), lane, addr);
3169 LogVWrite(addr, rt, print_format, lane);
3170 }
3171 break;
3172 case NEONLoadStoreSingle2:
3173 scale = 2;
3174 if (do_load) {
3175 if (replicating) {
3176 ld2r(vf, vreg(rt), vreg(rt2), addr);
3177 } else {
3178 ld2(vf, vreg(rt), vreg(rt2), lane, addr);
3179 }
3180 LogVRead(addr, rt, print_format, lane);
3181 LogVRead(addr + esize, rt2, print_format, lane);
3182 } else {
3183 st2(vf, vreg(rt), vreg(rt2), lane, addr);
3184 LogVWrite(addr, rt, print_format, lane);
3185 LogVWrite(addr + esize, rt2, print_format, lane);
3186 }
3187 break;
3188 case NEONLoadStoreSingle3:
3189 scale = 3;
3190 if (do_load) {
3191 if (replicating) {
3192 ld3r(vf, vreg(rt), vreg(rt2), vreg(rt3), addr);
3193 } else {
3194 ld3(vf, vreg(rt), vreg(rt2), vreg(rt3), lane, addr);
3195 }
3196 LogVRead(addr, rt, print_format, lane);
3197 LogVRead(addr + esize, rt2, print_format, lane);
3198 LogVRead(addr + (2 * esize), rt3, print_format, lane);
3199 } else {
3200 st3(vf, vreg(rt), vreg(rt2), vreg(rt3), lane, addr);
3201 LogVWrite(addr, rt, print_format, lane);
3202 LogVWrite(addr + esize, rt2, print_format, lane);
3203 LogVWrite(addr + (2 * esize), rt3, print_format, lane);
3204 }
3205 break;
3206 case NEONLoadStoreSingle4:
3207 scale = 4;
3208 if (do_load) {
3209 if (replicating) {
3210 ld4r(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), addr);
3211 } else {
3212 ld4(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), lane, addr);
3213 }
3214 LogVRead(addr, rt, print_format, lane);
3215 LogVRead(addr + esize, rt2, print_format, lane);
3216 LogVRead(addr + (2 * esize), rt3, print_format, lane);
3217 LogVRead(addr + (3 * esize), rt4, print_format, lane);
3218 } else {
3219 st4(vf, vreg(rt), vreg(rt2), vreg(rt3), vreg(rt4), lane, addr);
3220 LogVWrite(addr, rt, print_format, lane);
3221 LogVWrite(addr + esize, rt2, print_format, lane);
3222 LogVWrite(addr + (2 * esize), rt3, print_format, lane);
3223 LogVWrite(addr + (3 * esize), rt4, print_format, lane);
3224 }
3225 break;
3226 default: VIXL_UNIMPLEMENTED();
3227 }
3228
3229 if (addr_mode == PostIndex) {
3230 int rm = instr->Rm();
3231 int lane_size = LaneSizeInBytesFromFormat(vf);
3232 set_xreg(instr->Rn(), addr + ((rm == 31) ? (scale * lane_size) : xreg(rm)));
3233 }
3234 }
3235
3236
VisitNEONLoadStoreSingleStruct(const Instruction * instr)3237 void Simulator::VisitNEONLoadStoreSingleStruct(const Instruction* instr) {
3238 NEONLoadStoreSingleStructHelper(instr, Offset);
3239 }
3240
3241
VisitNEONLoadStoreSingleStructPostIndex(const Instruction * instr)3242 void Simulator::VisitNEONLoadStoreSingleStructPostIndex(
3243 const Instruction* instr) {
3244 NEONLoadStoreSingleStructHelper(instr, PostIndex);
3245 }
3246
3247
VisitNEONModifiedImmediate(const Instruction * instr)3248 void Simulator::VisitNEONModifiedImmediate(const Instruction* instr) {
3249 SimVRegister& rd = vreg(instr->Rd());
3250 int cmode = instr->NEONCmode();
3251 int cmode_3_1 = (cmode >> 1) & 7;
3252 int cmode_3 = (cmode >> 3) & 1;
3253 int cmode_2 = (cmode >> 2) & 1;
3254 int cmode_1 = (cmode >> 1) & 1;
3255 int cmode_0 = cmode & 1;
3256 int q = instr->NEONQ();
3257 int op_bit = instr->NEONModImmOp();
3258 uint64_t imm8 = instr->ImmNEONabcdefgh();
3259
3260 // Find the format and immediate value
3261 uint64_t imm = 0;
3262 VectorFormat vform = kFormatUndefined;
3263 switch (cmode_3_1) {
3264 case 0x0:
3265 case 0x1:
3266 case 0x2:
3267 case 0x3:
3268 vform = (q == 1) ? kFormat4S : kFormat2S;
3269 imm = imm8 << (8 * cmode_3_1);
3270 break;
3271 case 0x4:
3272 case 0x5:
3273 vform = (q == 1) ? kFormat8H : kFormat4H;
3274 imm = imm8 << (8 * cmode_1);
3275 break;
3276 case 0x6:
3277 vform = (q == 1) ? kFormat4S : kFormat2S;
3278 if (cmode_0 == 0) {
3279 imm = imm8 << 8 | 0x000000ff;
3280 } else {
3281 imm = imm8 << 16 | 0x0000ffff;
3282 }
3283 break;
3284 case 0x7:
3285 if (cmode_0 == 0 && op_bit == 0) {
3286 vform = q ? kFormat16B : kFormat8B;
3287 imm = imm8;
3288 } else if (cmode_0 == 0 && op_bit == 1) {
3289 vform = q ? kFormat2D : kFormat1D;
3290 imm = 0;
3291 for (int i = 0; i < 8; ++i) {
3292 if (imm8 & (1ULL << i)) {
3293 imm |= (UINT64_C(0xff) << (8 * i));
3294 }
3295 }
3296 } else { // cmode_0 == 1, cmode == 0xf.
3297 if (op_bit == 0) {
3298 vform = q ? kFormat4S : kFormat2S;
3299 imm = FloatToRawbits(instr->ImmNEONFP32());
3300 } else if (q == 1) {
3301 vform = kFormat2D;
3302 imm = DoubleToRawbits(instr->ImmNEONFP64());
3303 } else {
3304 VIXL_ASSERT((q == 0) && (op_bit == 1) && (cmode == 0xf));
3305 VisitUnallocated(instr);
3306 }
3307 }
3308 break;
3309 default: VIXL_UNREACHABLE(); break;
3310 }
3311
3312 // Find the operation
3313 NEONModifiedImmediateOp op;
3314 if (cmode_3 == 0) {
3315 if (cmode_0 == 0) {
3316 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
3317 } else { // cmode<0> == '1'
3318 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR;
3319 }
3320 } else { // cmode<3> == '1'
3321 if (cmode_2 == 0) {
3322 if (cmode_0 == 0) {
3323 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
3324 } else { // cmode<0> == '1'
3325 op = op_bit ? NEONModifiedImmediate_BIC : NEONModifiedImmediate_ORR;
3326 }
3327 } else { // cmode<2> == '1'
3328 if (cmode_1 == 0) {
3329 op = op_bit ? NEONModifiedImmediate_MVNI : NEONModifiedImmediate_MOVI;
3330 } else { // cmode<1> == '1'
3331 if (cmode_0 == 0) {
3332 op = NEONModifiedImmediate_MOVI;
3333 } else { // cmode<0> == '1'
3334 op = NEONModifiedImmediate_MOVI;
3335 }
3336 }
3337 }
3338 }
3339
3340 // Call the logic function
3341 if (op == NEONModifiedImmediate_ORR) {
3342 orr(vform, rd, rd, imm);
3343 } else if (op == NEONModifiedImmediate_BIC) {
3344 bic(vform, rd, rd, imm);
3345 } else if (op == NEONModifiedImmediate_MOVI) {
3346 movi(vform, rd, imm);
3347 } else if (op == NEONModifiedImmediate_MVNI) {
3348 mvni(vform, rd, imm);
3349 } else {
3350 VisitUnimplemented(instr);
3351 }
3352 }
3353
3354
VisitNEONScalar2RegMisc(const Instruction * instr)3355 void Simulator::VisitNEONScalar2RegMisc(const Instruction* instr) {
3356 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
3357 VectorFormat vf = nfd.GetVectorFormat();
3358
3359 SimVRegister& rd = vreg(instr->Rd());
3360 SimVRegister& rn = vreg(instr->Rn());
3361
3362 if (instr->Mask(NEON2RegMiscOpcode) <= NEON_NEG_scalar_opcode) {
3363 // These instructions all use a two bit size field, except NOT and RBIT,
3364 // which use the field to encode the operation.
3365 switch (instr->Mask(NEONScalar2RegMiscMask)) {
3366 case NEON_CMEQ_zero_scalar: cmp(vf, rd, rn, 0, eq); break;
3367 case NEON_CMGE_zero_scalar: cmp(vf, rd, rn, 0, ge); break;
3368 case NEON_CMGT_zero_scalar: cmp(vf, rd, rn, 0, gt); break;
3369 case NEON_CMLT_zero_scalar: cmp(vf, rd, rn, 0, lt); break;
3370 case NEON_CMLE_zero_scalar: cmp(vf, rd, rn, 0, le); break;
3371 case NEON_ABS_scalar: abs(vf, rd, rn); break;
3372 case NEON_SQABS_scalar: abs(vf, rd, rn).SignedSaturate(vf); break;
3373 case NEON_NEG_scalar: neg(vf, rd, rn); break;
3374 case NEON_SQNEG_scalar: neg(vf, rd, rn).SignedSaturate(vf); break;
3375 case NEON_SUQADD_scalar: suqadd(vf, rd, rn); break;
3376 case NEON_USQADD_scalar: usqadd(vf, rd, rn); break;
3377 default: VIXL_UNIMPLEMENTED(); break;
3378 }
3379 } else {
3380 VectorFormat fpf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
3381 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
3382
3383 // These instructions all use a one bit size field, except SQXTUN, SQXTN
3384 // and UQXTN, which use a two bit size field.
3385 switch (instr->Mask(NEONScalar2RegMiscFPMask)) {
3386 case NEON_FRECPE_scalar: frecpe(fpf, rd, rn, fpcr_rounding); break;
3387 case NEON_FRECPX_scalar: frecpx(fpf, rd, rn); break;
3388 case NEON_FRSQRTE_scalar: frsqrte(fpf, rd, rn); break;
3389 case NEON_FCMGT_zero_scalar: fcmp_zero(fpf, rd, rn, gt); break;
3390 case NEON_FCMGE_zero_scalar: fcmp_zero(fpf, rd, rn, ge); break;
3391 case NEON_FCMEQ_zero_scalar: fcmp_zero(fpf, rd, rn, eq); break;
3392 case NEON_FCMLE_zero_scalar: fcmp_zero(fpf, rd, rn, le); break;
3393 case NEON_FCMLT_zero_scalar: fcmp_zero(fpf, rd, rn, lt); break;
3394 case NEON_SCVTF_scalar: scvtf(fpf, rd, rn, 0, fpcr_rounding); break;
3395 case NEON_UCVTF_scalar: ucvtf(fpf, rd, rn, 0, fpcr_rounding); break;
3396 case NEON_FCVTNS_scalar: fcvts(fpf, rd, rn, FPTieEven); break;
3397 case NEON_FCVTNU_scalar: fcvtu(fpf, rd, rn, FPTieEven); break;
3398 case NEON_FCVTPS_scalar: fcvts(fpf, rd, rn, FPPositiveInfinity); break;
3399 case NEON_FCVTPU_scalar: fcvtu(fpf, rd, rn, FPPositiveInfinity); break;
3400 case NEON_FCVTMS_scalar: fcvts(fpf, rd, rn, FPNegativeInfinity); break;
3401 case NEON_FCVTMU_scalar: fcvtu(fpf, rd, rn, FPNegativeInfinity); break;
3402 case NEON_FCVTZS_scalar: fcvts(fpf, rd, rn, FPZero); break;
3403 case NEON_FCVTZU_scalar: fcvtu(fpf, rd, rn, FPZero); break;
3404 case NEON_FCVTAS_scalar: fcvts(fpf, rd, rn, FPTieAway); break;
3405 case NEON_FCVTAU_scalar: fcvtu(fpf, rd, rn, FPTieAway); break;
3406 case NEON_FCVTXN_scalar:
3407 // Unlike all of the other FP instructions above, fcvtxn encodes dest
3408 // size S as size<0>=1. There's only one case, so we ignore the form.
3409 VIXL_ASSERT(instr->Bit(22) == 1);
3410 fcvtxn(kFormatS, rd, rn);
3411 break;
3412 default:
3413 switch (instr->Mask(NEONScalar2RegMiscMask)) {
3414 case NEON_SQXTN_scalar: sqxtn(vf, rd, rn); break;
3415 case NEON_UQXTN_scalar: uqxtn(vf, rd, rn); break;
3416 case NEON_SQXTUN_scalar: sqxtun(vf, rd, rn); break;
3417 default:
3418 VIXL_UNIMPLEMENTED();
3419 }
3420 }
3421 }
3422 }
3423
3424
VisitNEONScalar3Diff(const Instruction * instr)3425 void Simulator::VisitNEONScalar3Diff(const Instruction* instr) {
3426 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap());
3427 VectorFormat vf = nfd.GetVectorFormat();
3428
3429 SimVRegister& rd = vreg(instr->Rd());
3430 SimVRegister& rn = vreg(instr->Rn());
3431 SimVRegister& rm = vreg(instr->Rm());
3432 switch (instr->Mask(NEONScalar3DiffMask)) {
3433 case NEON_SQDMLAL_scalar: sqdmlal(vf, rd, rn, rm); break;
3434 case NEON_SQDMLSL_scalar: sqdmlsl(vf, rd, rn, rm); break;
3435 case NEON_SQDMULL_scalar: sqdmull(vf, rd, rn, rm); break;
3436 default:
3437 VIXL_UNIMPLEMENTED();
3438 }
3439 }
3440
3441
VisitNEONScalar3Same(const Instruction * instr)3442 void Simulator::VisitNEONScalar3Same(const Instruction* instr) {
3443 NEONFormatDecoder nfd(instr, NEONFormatDecoder::ScalarFormatMap());
3444 VectorFormat vf = nfd.GetVectorFormat();
3445
3446 SimVRegister& rd = vreg(instr->Rd());
3447 SimVRegister& rn = vreg(instr->Rn());
3448 SimVRegister& rm = vreg(instr->Rm());
3449
3450 if (instr->Mask(NEONScalar3SameFPFMask) == NEONScalar3SameFPFixed) {
3451 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
3452 switch (instr->Mask(NEONScalar3SameFPMask)) {
3453 case NEON_FMULX_scalar: fmulx(vf, rd, rn, rm); break;
3454 case NEON_FACGE_scalar: fabscmp(vf, rd, rn, rm, ge); break;
3455 case NEON_FACGT_scalar: fabscmp(vf, rd, rn, rm, gt); break;
3456 case NEON_FCMEQ_scalar: fcmp(vf, rd, rn, rm, eq); break;
3457 case NEON_FCMGE_scalar: fcmp(vf, rd, rn, rm, ge); break;
3458 case NEON_FCMGT_scalar: fcmp(vf, rd, rn, rm, gt); break;
3459 case NEON_FRECPS_scalar: frecps(vf, rd, rn, rm); break;
3460 case NEON_FRSQRTS_scalar: frsqrts(vf, rd, rn, rm); break;
3461 case NEON_FABD_scalar: fabd(vf, rd, rn, rm); break;
3462 default:
3463 VIXL_UNIMPLEMENTED();
3464 }
3465 } else {
3466 switch (instr->Mask(NEONScalar3SameMask)) {
3467 case NEON_ADD_scalar: add(vf, rd, rn, rm); break;
3468 case NEON_SUB_scalar: sub(vf, rd, rn, rm); break;
3469 case NEON_CMEQ_scalar: cmp(vf, rd, rn, rm, eq); break;
3470 case NEON_CMGE_scalar: cmp(vf, rd, rn, rm, ge); break;
3471 case NEON_CMGT_scalar: cmp(vf, rd, rn, rm, gt); break;
3472 case NEON_CMHI_scalar: cmp(vf, rd, rn, rm, hi); break;
3473 case NEON_CMHS_scalar: cmp(vf, rd, rn, rm, hs); break;
3474 case NEON_CMTST_scalar: cmptst(vf, rd, rn, rm); break;
3475 case NEON_USHL_scalar: ushl(vf, rd, rn, rm); break;
3476 case NEON_SSHL_scalar: sshl(vf, rd, rn, rm); break;
3477 case NEON_SQDMULH_scalar: sqdmulh(vf, rd, rn, rm); break;
3478 case NEON_SQRDMULH_scalar: sqrdmulh(vf, rd, rn, rm); break;
3479 case NEON_UQADD_scalar:
3480 add(vf, rd, rn, rm).UnsignedSaturate(vf);
3481 break;
3482 case NEON_SQADD_scalar:
3483 add(vf, rd, rn, rm).SignedSaturate(vf);
3484 break;
3485 case NEON_UQSUB_scalar:
3486 sub(vf, rd, rn, rm).UnsignedSaturate(vf);
3487 break;
3488 case NEON_SQSUB_scalar:
3489 sub(vf, rd, rn, rm).SignedSaturate(vf);
3490 break;
3491 case NEON_UQSHL_scalar:
3492 ushl(vf, rd, rn, rm).UnsignedSaturate(vf);
3493 break;
3494 case NEON_SQSHL_scalar:
3495 sshl(vf, rd, rn, rm).SignedSaturate(vf);
3496 break;
3497 case NEON_URSHL_scalar:
3498 ushl(vf, rd, rn, rm).Round(vf);
3499 break;
3500 case NEON_SRSHL_scalar:
3501 sshl(vf, rd, rn, rm).Round(vf);
3502 break;
3503 case NEON_UQRSHL_scalar:
3504 ushl(vf, rd, rn, rm).Round(vf).UnsignedSaturate(vf);
3505 break;
3506 case NEON_SQRSHL_scalar:
3507 sshl(vf, rd, rn, rm).Round(vf).SignedSaturate(vf);
3508 break;
3509 default:
3510 VIXL_UNIMPLEMENTED();
3511 }
3512 }
3513 }
3514
3515
VisitNEONScalarByIndexedElement(const Instruction * instr)3516 void Simulator::VisitNEONScalarByIndexedElement(const Instruction* instr) {
3517 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LongScalarFormatMap());
3518 VectorFormat vf = nfd.GetVectorFormat();
3519 VectorFormat vf_r = nfd.GetVectorFormat(nfd.ScalarFormatMap());
3520
3521 SimVRegister& rd = vreg(instr->Rd());
3522 SimVRegister& rn = vreg(instr->Rn());
3523 ByElementOp Op = NULL;
3524
3525 int rm_reg = instr->Rm();
3526 int index = (instr->NEONH() << 1) | instr->NEONL();
3527 if (instr->NEONSize() == 1) {
3528 rm_reg &= 0xf;
3529 index = (index << 1) | instr->NEONM();
3530 }
3531
3532 switch (instr->Mask(NEONScalarByIndexedElementMask)) {
3533 case NEON_SQDMULL_byelement_scalar: Op = &Simulator::sqdmull; break;
3534 case NEON_SQDMLAL_byelement_scalar: Op = &Simulator::sqdmlal; break;
3535 case NEON_SQDMLSL_byelement_scalar: Op = &Simulator::sqdmlsl; break;
3536 case NEON_SQDMULH_byelement_scalar:
3537 Op = &Simulator::sqdmulh;
3538 vf = vf_r;
3539 break;
3540 case NEON_SQRDMULH_byelement_scalar:
3541 Op = &Simulator::sqrdmulh;
3542 vf = vf_r;
3543 break;
3544 default:
3545 vf = nfd.GetVectorFormat(nfd.FPScalarFormatMap());
3546 index = instr->NEONH();
3547 if ((instr->FPType() & 1) == 0) {
3548 index = (index << 1) | instr->NEONL();
3549 }
3550 switch (instr->Mask(NEONScalarByIndexedElementFPMask)) {
3551 case NEON_FMUL_byelement_scalar: Op = &Simulator::fmul; break;
3552 case NEON_FMLA_byelement_scalar: Op = &Simulator::fmla; break;
3553 case NEON_FMLS_byelement_scalar: Op = &Simulator::fmls; break;
3554 case NEON_FMULX_byelement_scalar: Op = &Simulator::fmulx; break;
3555 default: VIXL_UNIMPLEMENTED();
3556 }
3557 }
3558
3559 (this->*Op)(vf, rd, rn, vreg(rm_reg), index);
3560 }
3561
3562
VisitNEONScalarCopy(const Instruction * instr)3563 void Simulator::VisitNEONScalarCopy(const Instruction* instr) {
3564 NEONFormatDecoder nfd(instr, NEONFormatDecoder::TriangularScalarFormatMap());
3565 VectorFormat vf = nfd.GetVectorFormat();
3566
3567 SimVRegister& rd = vreg(instr->Rd());
3568 SimVRegister& rn = vreg(instr->Rn());
3569
3570 if (instr->Mask(NEONScalarCopyMask) == NEON_DUP_ELEMENT_scalar) {
3571 int imm5 = instr->ImmNEON5();
3572 int tz = CountTrailingZeros(imm5, 32);
3573 int rn_index = imm5 >> (tz + 1);
3574 dup_element(vf, rd, rn, rn_index);
3575 } else {
3576 VIXL_UNIMPLEMENTED();
3577 }
3578 }
3579
3580
VisitNEONScalarPairwise(const Instruction * instr)3581 void Simulator::VisitNEONScalarPairwise(const Instruction* instr) {
3582 NEONFormatDecoder nfd(instr, NEONFormatDecoder::FPScalarFormatMap());
3583 VectorFormat vf = nfd.GetVectorFormat();
3584
3585 SimVRegister& rd = vreg(instr->Rd());
3586 SimVRegister& rn = vreg(instr->Rn());
3587 switch (instr->Mask(NEONScalarPairwiseMask)) {
3588 case NEON_ADDP_scalar: addp(vf, rd, rn); break;
3589 case NEON_FADDP_scalar: faddp(vf, rd, rn); break;
3590 case NEON_FMAXP_scalar: fmaxp(vf, rd, rn); break;
3591 case NEON_FMAXNMP_scalar: fmaxnmp(vf, rd, rn); break;
3592 case NEON_FMINP_scalar: fminp(vf, rd, rn); break;
3593 case NEON_FMINNMP_scalar: fminnmp(vf, rd, rn); break;
3594 default:
3595 VIXL_UNIMPLEMENTED();
3596 }
3597 }
3598
3599
VisitNEONScalarShiftImmediate(const Instruction * instr)3600 void Simulator::VisitNEONScalarShiftImmediate(const Instruction* instr) {
3601 SimVRegister& rd = vreg(instr->Rd());
3602 SimVRegister& rn = vreg(instr->Rn());
3603 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
3604
3605 static const NEONFormatMap map = {
3606 {22, 21, 20, 19},
3607 {NF_UNDEF, NF_B, NF_H, NF_H, NF_S, NF_S, NF_S, NF_S,
3608 NF_D, NF_D, NF_D, NF_D, NF_D, NF_D, NF_D, NF_D}
3609 };
3610 NEONFormatDecoder nfd(instr, &map);
3611 VectorFormat vf = nfd.GetVectorFormat();
3612
3613 int highestSetBit = HighestSetBitPosition(instr->ImmNEONImmh());
3614 int immhimmb = instr->ImmNEONImmhImmb();
3615 int right_shift = (16 << highestSetBit) - immhimmb;
3616 int left_shift = immhimmb - (8 << highestSetBit);
3617 switch (instr->Mask(NEONScalarShiftImmediateMask)) {
3618 case NEON_SHL_scalar: shl(vf, rd, rn, left_shift); break;
3619 case NEON_SLI_scalar: sli(vf, rd, rn, left_shift); break;
3620 case NEON_SQSHL_imm_scalar: sqshl(vf, rd, rn, left_shift); break;
3621 case NEON_UQSHL_imm_scalar: uqshl(vf, rd, rn, left_shift); break;
3622 case NEON_SQSHLU_scalar: sqshlu(vf, rd, rn, left_shift); break;
3623 case NEON_SRI_scalar: sri(vf, rd, rn, right_shift); break;
3624 case NEON_SSHR_scalar: sshr(vf, rd, rn, right_shift); break;
3625 case NEON_USHR_scalar: ushr(vf, rd, rn, right_shift); break;
3626 case NEON_SRSHR_scalar: sshr(vf, rd, rn, right_shift).Round(vf); break;
3627 case NEON_URSHR_scalar: ushr(vf, rd, rn, right_shift).Round(vf); break;
3628 case NEON_SSRA_scalar: ssra(vf, rd, rn, right_shift); break;
3629 case NEON_USRA_scalar: usra(vf, rd, rn, right_shift); break;
3630 case NEON_SRSRA_scalar: srsra(vf, rd, rn, right_shift); break;
3631 case NEON_URSRA_scalar: ursra(vf, rd, rn, right_shift); break;
3632 case NEON_UQSHRN_scalar: uqshrn(vf, rd, rn, right_shift); break;
3633 case NEON_UQRSHRN_scalar: uqrshrn(vf, rd, rn, right_shift); break;
3634 case NEON_SQSHRN_scalar: sqshrn(vf, rd, rn, right_shift); break;
3635 case NEON_SQRSHRN_scalar: sqrshrn(vf, rd, rn, right_shift); break;
3636 case NEON_SQSHRUN_scalar: sqshrun(vf, rd, rn, right_shift); break;
3637 case NEON_SQRSHRUN_scalar: sqrshrun(vf, rd, rn, right_shift); break;
3638 case NEON_FCVTZS_imm_scalar: fcvts(vf, rd, rn, FPZero, right_shift); break;
3639 case NEON_FCVTZU_imm_scalar: fcvtu(vf, rd, rn, FPZero, right_shift); break;
3640 case NEON_SCVTF_imm_scalar:
3641 scvtf(vf, rd, rn, right_shift, fpcr_rounding);
3642 break;
3643 case NEON_UCVTF_imm_scalar:
3644 ucvtf(vf, rd, rn, right_shift, fpcr_rounding);
3645 break;
3646 default:
3647 VIXL_UNIMPLEMENTED();
3648 }
3649 }
3650
3651
VisitNEONShiftImmediate(const Instruction * instr)3652 void Simulator::VisitNEONShiftImmediate(const Instruction* instr) {
3653 SimVRegister& rd = vreg(instr->Rd());
3654 SimVRegister& rn = vreg(instr->Rn());
3655 FPRounding fpcr_rounding = static_cast<FPRounding>(fpcr().RMode());
3656
3657 // 00010->8B, 00011->16B, 001x0->4H, 001x1->8H,
3658 // 01xx0->2S, 01xx1->4S, 1xxx1->2D, all others undefined.
3659 static const NEONFormatMap map = {
3660 {22, 21, 20, 19, 30},
3661 {NF_UNDEF, NF_UNDEF, NF_8B, NF_16B, NF_4H, NF_8H, NF_4H, NF_8H,
3662 NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S, NF_2S, NF_4S,
3663 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D,
3664 NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D, NF_UNDEF, NF_2D}
3665 };
3666 NEONFormatDecoder nfd(instr, &map);
3667 VectorFormat vf = nfd.GetVectorFormat();
3668
3669 // 0001->8H, 001x->4S, 01xx->2D, all others undefined.
3670 static const NEONFormatMap map_l = {
3671 {22, 21, 20, 19},
3672 {NF_UNDEF, NF_8H, NF_4S, NF_4S, NF_2D, NF_2D, NF_2D, NF_2D}
3673 };
3674 VectorFormat vf_l = nfd.GetVectorFormat(&map_l);
3675
3676 int highestSetBit = HighestSetBitPosition(instr->ImmNEONImmh());
3677 int immhimmb = instr->ImmNEONImmhImmb();
3678 int right_shift = (16 << highestSetBit) - immhimmb;
3679 int left_shift = immhimmb - (8 << highestSetBit);
3680
3681 switch (instr->Mask(NEONShiftImmediateMask)) {
3682 case NEON_SHL: shl(vf, rd, rn, left_shift); break;
3683 case NEON_SLI: sli(vf, rd, rn, left_shift); break;
3684 case NEON_SQSHLU: sqshlu(vf, rd, rn, left_shift); break;
3685 case NEON_SRI: sri(vf, rd, rn, right_shift); break;
3686 case NEON_SSHR: sshr(vf, rd, rn, right_shift); break;
3687 case NEON_USHR: ushr(vf, rd, rn, right_shift); break;
3688 case NEON_SRSHR: sshr(vf, rd, rn, right_shift).Round(vf); break;
3689 case NEON_URSHR: ushr(vf, rd, rn, right_shift).Round(vf); break;
3690 case NEON_SSRA: ssra(vf, rd, rn, right_shift); break;
3691 case NEON_USRA: usra(vf, rd, rn, right_shift); break;
3692 case NEON_SRSRA: srsra(vf, rd, rn, right_shift); break;
3693 case NEON_URSRA: ursra(vf, rd, rn, right_shift); break;
3694 case NEON_SQSHL_imm: sqshl(vf, rd, rn, left_shift); break;
3695 case NEON_UQSHL_imm: uqshl(vf, rd, rn, left_shift); break;
3696 case NEON_SCVTF_imm: scvtf(vf, rd, rn, right_shift, fpcr_rounding); break;
3697 case NEON_UCVTF_imm: ucvtf(vf, rd, rn, right_shift, fpcr_rounding); break;
3698 case NEON_FCVTZS_imm: fcvts(vf, rd, rn, FPZero, right_shift); break;
3699 case NEON_FCVTZU_imm: fcvtu(vf, rd, rn, FPZero, right_shift); break;
3700 case NEON_SSHLL:
3701 vf = vf_l;
3702 if (instr->Mask(NEON_Q)) {
3703 sshll2(vf, rd, rn, left_shift);
3704 } else {
3705 sshll(vf, rd, rn, left_shift);
3706 }
3707 break;
3708 case NEON_USHLL:
3709 vf = vf_l;
3710 if (instr->Mask(NEON_Q)) {
3711 ushll2(vf, rd, rn, left_shift);
3712 } else {
3713 ushll(vf, rd, rn, left_shift);
3714 }
3715 break;
3716 case NEON_SHRN:
3717 if (instr->Mask(NEON_Q)) {
3718 shrn2(vf, rd, rn, right_shift);
3719 } else {
3720 shrn(vf, rd, rn, right_shift);
3721 }
3722 break;
3723 case NEON_RSHRN:
3724 if (instr->Mask(NEON_Q)) {
3725 rshrn2(vf, rd, rn, right_shift);
3726 } else {
3727 rshrn(vf, rd, rn, right_shift);
3728 }
3729 break;
3730 case NEON_UQSHRN:
3731 if (instr->Mask(NEON_Q)) {
3732 uqshrn2(vf, rd, rn, right_shift);
3733 } else {
3734 uqshrn(vf, rd, rn, right_shift);
3735 }
3736 break;
3737 case NEON_UQRSHRN:
3738 if (instr->Mask(NEON_Q)) {
3739 uqrshrn2(vf, rd, rn, right_shift);
3740 } else {
3741 uqrshrn(vf, rd, rn, right_shift);
3742 }
3743 break;
3744 case NEON_SQSHRN:
3745 if (instr->Mask(NEON_Q)) {
3746 sqshrn2(vf, rd, rn, right_shift);
3747 } else {
3748 sqshrn(vf, rd, rn, right_shift);
3749 }
3750 break;
3751 case NEON_SQRSHRN:
3752 if (instr->Mask(NEON_Q)) {
3753 sqrshrn2(vf, rd, rn, right_shift);
3754 } else {
3755 sqrshrn(vf, rd, rn, right_shift);
3756 }
3757 break;
3758 case NEON_SQSHRUN:
3759 if (instr->Mask(NEON_Q)) {
3760 sqshrun2(vf, rd, rn, right_shift);
3761 } else {
3762 sqshrun(vf, rd, rn, right_shift);
3763 }
3764 break;
3765 case NEON_SQRSHRUN:
3766 if (instr->Mask(NEON_Q)) {
3767 sqrshrun2(vf, rd, rn, right_shift);
3768 } else {
3769 sqrshrun(vf, rd, rn, right_shift);
3770 }
3771 break;
3772 default:
3773 VIXL_UNIMPLEMENTED();
3774 }
3775 }
3776
3777
VisitNEONTable(const Instruction * instr)3778 void Simulator::VisitNEONTable(const Instruction* instr) {
3779 NEONFormatDecoder nfd(instr, NEONFormatDecoder::LogicalFormatMap());
3780 VectorFormat vf = nfd.GetVectorFormat();
3781
3782 SimVRegister& rd = vreg(instr->Rd());
3783 SimVRegister& rn = vreg(instr->Rn());
3784 SimVRegister& rn2 = vreg((instr->Rn() + 1) % kNumberOfVRegisters);
3785 SimVRegister& rn3 = vreg((instr->Rn() + 2) % kNumberOfVRegisters);
3786 SimVRegister& rn4 = vreg((instr->Rn() + 3) % kNumberOfVRegisters);
3787 SimVRegister& rm = vreg(instr->Rm());
3788
3789 switch (instr->Mask(NEONTableMask)) {
3790 case NEON_TBL_1v: tbl(vf, rd, rn, rm); break;
3791 case NEON_TBL_2v: tbl(vf, rd, rn, rn2, rm); break;
3792 case NEON_TBL_3v: tbl(vf, rd, rn, rn2, rn3, rm); break;
3793 case NEON_TBL_4v: tbl(vf, rd, rn, rn2, rn3, rn4, rm); break;
3794 case NEON_TBX_1v: tbx(vf, rd, rn, rm); break;
3795 case NEON_TBX_2v: tbx(vf, rd, rn, rn2, rm); break;
3796 case NEON_TBX_3v: tbx(vf, rd, rn, rn2, rn3, rm); break;
3797 case NEON_TBX_4v: tbx(vf, rd, rn, rn2, rn3, rn4, rm); break;
3798 default:
3799 VIXL_UNIMPLEMENTED();
3800 }
3801 }
3802
3803
VisitNEONPerm(const Instruction * instr)3804 void Simulator::VisitNEONPerm(const Instruction* instr) {
3805 NEONFormatDecoder nfd(instr);
3806 VectorFormat vf = nfd.GetVectorFormat();
3807
3808 SimVRegister& rd = vreg(instr->Rd());
3809 SimVRegister& rn = vreg(instr->Rn());
3810 SimVRegister& rm = vreg(instr->Rm());
3811
3812 switch (instr->Mask(NEONPermMask)) {
3813 case NEON_TRN1: trn1(vf, rd, rn, rm); break;
3814 case NEON_TRN2: trn2(vf, rd, rn, rm); break;
3815 case NEON_UZP1: uzp1(vf, rd, rn, rm); break;
3816 case NEON_UZP2: uzp2(vf, rd, rn, rm); break;
3817 case NEON_ZIP1: zip1(vf, rd, rn, rm); break;
3818 case NEON_ZIP2: zip2(vf, rd, rn, rm); break;
3819 default:
3820 VIXL_UNIMPLEMENTED();
3821 }
3822 }
3823
3824
DoUnreachable(const Instruction * instr)3825 void Simulator::DoUnreachable(const Instruction* instr) {
3826 VIXL_ASSERT(instr->InstructionBits() == UNDEFINED_INST_PATTERN);
3827
3828 fprintf(stream_, "Hit UNREACHABLE marker at pc=%p.\n",
3829 reinterpret_cast<const void*>(instr));
3830 abort();
3831 }
3832
3833
DoTrace(const Instruction * instr)3834 void Simulator::DoTrace(const Instruction* instr) {
3835 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
3836 (instr->ImmException() == kTraceOpcode));
3837
3838 // Read the arguments encoded inline in the instruction stream.
3839 uint32_t parameters;
3840 uint32_t command;
3841
3842 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
3843 memcpy(¶meters, instr + kTraceParamsOffset, sizeof(parameters));
3844 memcpy(&command, instr + kTraceCommandOffset, sizeof(command));
3845
3846 switch (command) {
3847 case TRACE_ENABLE:
3848 set_trace_parameters(trace_parameters() | parameters);
3849 break;
3850 case TRACE_DISABLE:
3851 set_trace_parameters(trace_parameters() & ~parameters);
3852 break;
3853 default:
3854 VIXL_UNREACHABLE();
3855 }
3856
3857 set_pc(instr->InstructionAtOffset(kTraceLength));
3858 }
3859
3860
DoLog(const Instruction * instr)3861 void Simulator::DoLog(const Instruction* instr) {
3862 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
3863 (instr->ImmException() == kLogOpcode));
3864
3865 // Read the arguments encoded inline in the instruction stream.
3866 uint32_t parameters;
3867
3868 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
3869 memcpy(¶meters, instr + kTraceParamsOffset, sizeof(parameters));
3870
3871 // We don't support a one-shot LOG_DISASM.
3872 VIXL_ASSERT((parameters & LOG_DISASM) == 0);
3873 // Print the requested information.
3874 if (parameters & LOG_SYSREGS) PrintSystemRegisters();
3875 if (parameters & LOG_REGS) PrintRegisters();
3876 if (parameters & LOG_VREGS) PrintVRegisters();
3877
3878 set_pc(instr->InstructionAtOffset(kLogLength));
3879 }
3880
3881
DoPrintf(const Instruction * instr)3882 void Simulator::DoPrintf(const Instruction* instr) {
3883 VIXL_ASSERT((instr->Mask(ExceptionMask) == HLT) &&
3884 (instr->ImmException() == kPrintfOpcode));
3885
3886 // Read the arguments encoded inline in the instruction stream.
3887 uint32_t arg_count;
3888 uint32_t arg_pattern_list;
3889 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
3890 memcpy(&arg_count,
3891 instr + kPrintfArgCountOffset,
3892 sizeof(arg_count));
3893 memcpy(&arg_pattern_list,
3894 instr + kPrintfArgPatternListOffset,
3895 sizeof(arg_pattern_list));
3896
3897 VIXL_ASSERT(arg_count <= kPrintfMaxArgCount);
3898 VIXL_ASSERT((arg_pattern_list >> (kPrintfArgPatternBits * arg_count)) == 0);
3899
3900 // We need to call the host printf function with a set of arguments defined by
3901 // arg_pattern_list. Because we don't know the types and sizes of the
3902 // arguments, this is very difficult to do in a robust and portable way. To
3903 // work around the problem, we pick apart the format string, and print one
3904 // format placeholder at a time.
3905
3906 // Allocate space for the format string. We take a copy, so we can modify it.
3907 // Leave enough space for one extra character per expected argument (plus the
3908 // '\0' termination).
3909 const char * format_base = reg<const char *>(0);
3910 VIXL_ASSERT(format_base != NULL);
3911 size_t length = strlen(format_base) + 1;
3912 char * const format = (char *)js_calloc(length + arg_count);
3913
3914 // A list of chunks, each with exactly one format placeholder.
3915 const char * chunks[kPrintfMaxArgCount];
3916
3917 // Copy the format string and search for format placeholders.
3918 uint32_t placeholder_count = 0;
3919 char * format_scratch = format;
3920 for (size_t i = 0; i < length; i++) {
3921 if (format_base[i] != '%') {
3922 *format_scratch++ = format_base[i];
3923 } else {
3924 if (format_base[i + 1] == '%') {
3925 // Ignore explicit "%%" sequences.
3926 *format_scratch++ = format_base[i];
3927 i++;
3928 // Chunks after the first are passed as format strings to printf, so we
3929 // need to escape '%' characters in those chunks.
3930 if (placeholder_count > 0) *format_scratch++ = format_base[i];
3931 } else {
3932 VIXL_CHECK(placeholder_count < arg_count);
3933 // Insert '\0' before placeholders, and store their locations.
3934 *format_scratch++ = '\0';
3935 chunks[placeholder_count++] = format_scratch;
3936 *format_scratch++ = format_base[i];
3937 }
3938 }
3939 }
3940 VIXL_CHECK(placeholder_count == arg_count);
3941
3942 // Finally, call printf with each chunk, passing the appropriate register
3943 // argument. Normally, printf returns the number of bytes transmitted, so we
3944 // can emulate a single printf call by adding the result from each chunk. If
3945 // any call returns a negative (error) value, though, just return that value.
3946
3947 printf("%s", clr_printf);
3948
3949 // Because '\0' is inserted before each placeholder, the first string in
3950 // 'format' contains no format placeholders and should be printed literally.
3951 int result = printf("%s", format);
3952 int pcs_r = 1; // Start at x1. x0 holds the format string.
3953 int pcs_f = 0; // Start at d0.
3954 if (result >= 0) {
3955 for (uint32_t i = 0; i < placeholder_count; i++) {
3956 int part_result = -1;
3957
3958 uint32_t arg_pattern = arg_pattern_list >> (i * kPrintfArgPatternBits);
3959 arg_pattern &= (1 << kPrintfArgPatternBits) - 1;
3960 switch (arg_pattern) {
3961 case kPrintfArgW: part_result = printf(chunks[i], wreg(pcs_r++)); break;
3962 case kPrintfArgX: part_result = printf(chunks[i], xreg(pcs_r++)); break;
3963 case kPrintfArgD: part_result = printf(chunks[i], dreg(pcs_f++)); break;
3964 default: VIXL_UNREACHABLE();
3965 }
3966
3967 if (part_result < 0) {
3968 // Handle error values.
3969 result = part_result;
3970 break;
3971 }
3972
3973 result += part_result;
3974 }
3975 }
3976
3977 printf("%s", clr_normal);
3978
3979 // Printf returns its result in x0 (just like the C library's printf).
3980 set_xreg(0, result);
3981
3982 // The printf parameters are inlined in the code, so skip them.
3983 set_pc(instr->InstructionAtOffset(kPrintfLength));
3984
3985 // Set LR as if we'd just called a native printf function.
3986 set_lr(pc());
3987
3988 js_free(format);
3989 }
3990
3991 } // namespace vixl
3992
3993 #endif // JS_SIMULATOR_ARM64
3994