1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80: */
3 // Copyright 2020 the V8 project authors. All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following
12 // disclaimer in the documentation and/or other materials provided
13 // with the distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived
16 // from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "jit/loong64/Simulator-loong64.h"
31
32 #include <float.h>
33 #include <limits>
34
35 #include "jit/AtomicOperations.h"
36 #include "jit/loong64/Assembler-loong64.h"
37 #include "threading/LockGuard.h"
38 #include "vm/Runtime.h"
39 #include "wasm/WasmInstance.h"
40 #include "wasm/WasmSignalHandlers.h"
41
42 #define I8(v) static_cast<int8_t>(v)
43 #define I16(v) static_cast<int16_t>(v)
44 #define U16(v) static_cast<uint16_t>(v)
45 #define I32(v) static_cast<int32_t>(v)
46 #define U32(v) static_cast<uint32_t>(v)
47 #define I64(v) static_cast<int64_t>(v)
48 #define U64(v) static_cast<uint64_t>(v)
49 #define I128(v) static_cast<__int128_t>(v)
50 #define U128(v) static_cast<__uint128_t>(v)
51
52 #define I32_CHECK(v) \
53 ({ \
54 MOZ_ASSERT(I64(I32(v)) == I64(v)); \
55 I32((v)); \
56 })
57
58 namespace js {
59 namespace jit {
60
MultiplyHighSigned(int64_t u,int64_t v)61 static int64_t MultiplyHighSigned(int64_t u, int64_t v) {
62 uint64_t u0, v0, w0;
63 int64_t u1, v1, w1, w2, t;
64
65 u0 = u & 0xFFFFFFFFL;
66 u1 = u >> 32;
67 v0 = v & 0xFFFFFFFFL;
68 v1 = v >> 32;
69
70 w0 = u0 * v0;
71 t = u1 * v0 + (w0 >> 32);
72 w1 = t & 0xFFFFFFFFL;
73 w2 = t >> 32;
74 w1 = u0 * v1 + w1;
75
76 return u1 * v1 + w2 + (w1 >> 32);
77 }
78
MultiplyHighUnsigned(uint64_t u,uint64_t v)79 static uint64_t MultiplyHighUnsigned(uint64_t u, uint64_t v) {
80 uint64_t u0, v0, w0;
81 uint64_t u1, v1, w1, w2, t;
82
83 u0 = u & 0xFFFFFFFFL;
84 u1 = u >> 32;
85 v0 = v & 0xFFFFFFFFL;
86 v1 = v >> 32;
87
88 w0 = u0 * v0;
89 t = u1 * v0 + (w0 >> 32);
90 w1 = t & 0xFFFFFFFFL;
91 w2 = t >> 32;
92 w1 = u0 * v1 + w1;
93
94 return u1 * v1 + w2 + (w1 >> 32);
95 }
96
97 // Precondition: 0 <= shift < 32
RotateRight32(uint32_t value,uint32_t shift)98 inline constexpr uint32_t RotateRight32(uint32_t value, uint32_t shift) {
99 return (value >> shift) | (value << ((32 - shift) & 31));
100 }
101
102 // Precondition: 0 <= shift < 32
RotateLeft32(uint32_t value,uint32_t shift)103 inline constexpr uint32_t RotateLeft32(uint32_t value, uint32_t shift) {
104 return (value << shift) | (value >> ((32 - shift) & 31));
105 }
106
107 // Precondition: 0 <= shift < 64
RotateRight64(uint64_t value,uint64_t shift)108 inline constexpr uint64_t RotateRight64(uint64_t value, uint64_t shift) {
109 return (value >> shift) | (value << ((64 - shift) & 63));
110 }
111
112 // Precondition: 0 <= shift < 64
RotateLeft64(uint64_t value,uint64_t shift)113 inline constexpr uint64_t RotateLeft64(uint64_t value, uint64_t shift) {
114 return (value << shift) | (value >> ((64 - shift) & 63));
115 }
116
117 // break instr with MAX_BREAK_CODE.
118 static const Instr kCallRedirInstr = op_break | CODEMask;
119
120 // -----------------------------------------------------------------------------
121 // LoongArch64 assembly various constants.
122
123 class SimInstruction {
124 public:
125 enum {
126 kInstrSize = 4,
127 // On LoongArch, PC cannot actually be directly accessed. We behave as if PC
128 // was always the value of the current instruction being executed.
129 kPCReadOffset = 0
130 };
131
132 // Get the raw instruction bits.
instructionBits() const133 inline Instr instructionBits() const {
134 return *reinterpret_cast<const Instr*>(this);
135 }
136
137 // Set the raw instruction bits to value.
setInstructionBits(Instr value)138 inline void setInstructionBits(Instr value) {
139 *reinterpret_cast<Instr*>(this) = value;
140 }
141
142 // Read one particular bit out of the instruction bits.
bit(int nr) const143 inline int bit(int nr) const { return (instructionBits() >> nr) & 1; }
144
145 // Read a bit field out of the instruction bits.
bits(int hi,int lo) const146 inline int bits(int hi, int lo) const {
147 return (instructionBits() >> lo) & ((2 << (hi - lo)) - 1);
148 }
149
150 // Instruction type.
151 enum Type {
152 kUnsupported = -1,
153 kOp6Type,
154 kOp7Type,
155 kOp8Type,
156 kOp10Type,
157 kOp11Type,
158 kOp12Type,
159 kOp14Type,
160 kOp15Type,
161 kOp16Type,
162 kOp17Type,
163 kOp22Type,
164 kOp24Type
165 };
166
167 // Get the encoding type of the instruction.
168 Type instructionType() const;
169
rjValue() const170 inline int rjValue() const { return bits(RJShift + RJBits - 1, RJShift); }
171
rkValue() const172 inline int rkValue() const { return bits(RKShift + RKBits - 1, RKShift); }
173
rdValue() const174 inline int rdValue() const { return bits(RDShift + RDBits - 1, RDShift); }
175
sa2Value() const176 inline int sa2Value() const { return bits(SAShift + SA2Bits - 1, SAShift); }
177
sa3Value() const178 inline int sa3Value() const { return bits(SAShift + SA3Bits - 1, SAShift); }
179
lsbwValue() const180 inline int lsbwValue() const {
181 return bits(LSBWShift + LSBWBits - 1, LSBWShift);
182 }
183
msbwValue() const184 inline int msbwValue() const {
185 return bits(MSBWShift + MSBWBits - 1, MSBWShift);
186 }
187
lsbdValue() const188 inline int lsbdValue() const {
189 return bits(LSBDShift + LSBDBits - 1, LSBDShift);
190 }
191
msbdValue() const192 inline int msbdValue() const {
193 return bits(MSBDShift + MSBDBits - 1, MSBDShift);
194 }
195
fdValue() const196 inline int fdValue() const { return bits(FDShift + FDBits - 1, FDShift); }
197
fjValue() const198 inline int fjValue() const { return bits(FJShift + FJBits - 1, FJShift); }
199
fkValue() const200 inline int fkValue() const { return bits(FKShift + FKBits - 1, FKShift); }
201
faValue() const202 inline int faValue() const { return bits(FAShift + FABits - 1, FAShift); }
203
cdValue() const204 inline int cdValue() const { return bits(CDShift + CDBits - 1, CDShift); }
205
cjValue() const206 inline int cjValue() const { return bits(CJShift + CJBits - 1, CJShift); }
207
caValue() const208 inline int caValue() const { return bits(CAShift + CABits - 1, CAShift); }
209
condValue() const210 inline int condValue() const {
211 return bits(CONDShift + CONDBits - 1, CONDShift);
212 }
213
imm5Value() const214 inline int imm5Value() const {
215 return bits(Imm5Shift + Imm5Bits - 1, Imm5Shift);
216 }
217
imm6Value() const218 inline int imm6Value() const {
219 return bits(Imm6Shift + Imm6Bits - 1, Imm6Shift);
220 }
221
imm12Value() const222 inline int imm12Value() const {
223 return bits(Imm12Shift + Imm12Bits - 1, Imm12Shift);
224 }
225
imm14Value() const226 inline int imm14Value() const {
227 return bits(Imm14Shift + Imm14Bits - 1, Imm14Shift);
228 }
229
imm16Value() const230 inline int imm16Value() const {
231 return bits(Imm16Shift + Imm16Bits - 1, Imm16Shift);
232 }
233
imm20Value() const234 inline int imm20Value() const {
235 return bits(Imm20Shift + Imm20Bits - 1, Imm20Shift);
236 }
237
imm26Value() const238 inline int32_t imm26Value() const {
239 return bits(Imm26Shift + Imm26Bits - 1, Imm26Shift);
240 }
241
242 // Say if the instruction is a debugger break/trap.
243 bool isTrap() const;
244
245 private:
246 SimInstruction() = delete;
247 SimInstruction(const SimInstruction& other) = delete;
248 void operator=(const SimInstruction& other) = delete;
249 };
250
isTrap() const251 bool SimInstruction::isTrap() const {
252 // is break??
253 switch (bits(31, 15) << 15) {
254 case op_break:
255 return (instructionBits() != kCallRedirInstr) && (bits(15, 0) != 6);
256 default:
257 return false;
258 };
259 }
260
instructionType() const261 SimInstruction::Type SimInstruction::instructionType() const {
262 SimInstruction::Type kType = kUnsupported;
263
264 // Check for kOp6Type
265 switch (bits(31, 26) << 26) {
266 case op_beqz:
267 case op_bnez:
268 case op_bcz:
269 case op_jirl:
270 case op_b:
271 case op_bl:
272 case op_beq:
273 case op_bne:
274 case op_blt:
275 case op_bge:
276 case op_bltu:
277 case op_bgeu:
278 case op_addu16i_d:
279 kType = kOp6Type;
280 break;
281 default:
282 kType = kUnsupported;
283 }
284
285 if (kType == kUnsupported) {
286 // Check for kOp7Type
287 switch (bits(31, 25) << 25) {
288 case op_lu12i_w:
289 case op_lu32i_d:
290 case op_pcaddi:
291 case op_pcalau12i:
292 case op_pcaddu12i:
293 case op_pcaddu18i:
294 kType = kOp7Type;
295 break;
296 default:
297 kType = kUnsupported;
298 }
299 }
300
301 if (kType == kUnsupported) {
302 // Check for kOp8Type
303 switch (bits(31, 24) << 24) {
304 case op_ll_w:
305 case op_sc_w:
306 case op_ll_d:
307 case op_sc_d:
308 case op_ldptr_w:
309 case op_stptr_w:
310 case op_ldptr_d:
311 case op_stptr_d:
312 kType = kOp8Type;
313 break;
314 default:
315 kType = kUnsupported;
316 }
317 }
318
319 if (kType == kUnsupported) {
320 // Check for kOp10Type
321 switch (bits(31, 22) << 22) {
322 case op_bstrins_d:
323 case op_bstrpick_d:
324 case op_slti:
325 case op_sltui:
326 case op_addi_w:
327 case op_addi_d:
328 case op_lu52i_d:
329 case op_andi:
330 case op_ori:
331 case op_xori:
332 case op_ld_b:
333 case op_ld_h:
334 case op_ld_w:
335 case op_ld_d:
336 case op_st_b:
337 case op_st_h:
338 case op_st_w:
339 case op_st_d:
340 case op_ld_bu:
341 case op_ld_hu:
342 case op_ld_wu:
343 case op_preld:
344 case op_fld_s:
345 case op_fst_s:
346 case op_fld_d:
347 case op_fst_d:
348 case op_bstr_w: // BSTRINS_W & BSTRPICK_W
349 kType = kOp10Type;
350 break;
351 default:
352 kType = kUnsupported;
353 }
354 }
355
356 if (kType == kUnsupported) {
357 // Check for kOp11Type
358 switch (bits(31, 21) << 21) {
359 case op_bstr_w:
360 kType = kOp11Type;
361 break;
362 default:
363 kType = kUnsupported;
364 }
365 }
366
367 if (kType == kUnsupported) {
368 // Check for kOp12Type
369 switch (bits(31, 20) << 20) {
370 case op_fmadd_s:
371 case op_fmadd_d:
372 case op_fmsub_s:
373 case op_fmsub_d:
374 case op_fnmadd_s:
375 case op_fnmadd_d:
376 case op_fnmsub_s:
377 case op_fnmsub_d:
378 case op_fcmp_cond_s:
379 case op_fcmp_cond_d:
380 kType = kOp12Type;
381 break;
382 default:
383 kType = kUnsupported;
384 }
385 }
386
387 if (kType == kUnsupported) {
388 // Check for kOp14Type
389 switch (bits(31, 18) << 18) {
390 case op_bytepick_d:
391 case op_fsel:
392 kType = kOp14Type;
393 break;
394 default:
395 kType = kUnsupported;
396 }
397 }
398
399 if (kType == kUnsupported) {
400 // Check for kOp15Type
401 switch (bits(31, 17) << 17) {
402 case op_bytepick_w:
403 case op_alsl_w:
404 case op_alsl_wu:
405 case op_alsl_d:
406 kType = kOp15Type;
407 break;
408 default:
409 kType = kUnsupported;
410 }
411 }
412
413 if (kType == kUnsupported) {
414 // Check for kOp16Type
415 switch (bits(31, 16) << 16) {
416 case op_slli_d:
417 case op_srli_d:
418 case op_srai_d:
419 case op_rotri_d:
420 kType = kOp16Type;
421 break;
422 default:
423 kType = kUnsupported;
424 }
425 }
426
427 if (kType == kUnsupported) {
428 // Check for kOp17Type
429 switch (bits(31, 15) << 15) {
430 case op_slli_w:
431 case op_srli_w:
432 case op_srai_w:
433 case op_rotri_w:
434 case op_add_w:
435 case op_add_d:
436 case op_sub_w:
437 case op_sub_d:
438 case op_slt:
439 case op_sltu:
440 case op_maskeqz:
441 case op_masknez:
442 case op_nor:
443 case op_and:
444 case op_or:
445 case op_xor:
446 case op_orn:
447 case op_andn:
448 case op_sll_w:
449 case op_srl_w:
450 case op_sra_w:
451 case op_sll_d:
452 case op_srl_d:
453 case op_sra_d:
454 case op_rotr_w:
455 case op_rotr_d:
456 case op_mul_w:
457 case op_mul_d:
458 case op_mulh_d:
459 case op_mulh_du:
460 case op_mulh_w:
461 case op_mulh_wu:
462 case op_mulw_d_w:
463 case op_mulw_d_wu:
464 case op_div_w:
465 case op_mod_w:
466 case op_div_wu:
467 case op_mod_wu:
468 case op_div_d:
469 case op_mod_d:
470 case op_div_du:
471 case op_mod_du:
472 case op_break:
473 case op_fadd_s:
474 case op_fadd_d:
475 case op_fsub_s:
476 case op_fsub_d:
477 case op_fmul_s:
478 case op_fmul_d:
479 case op_fdiv_s:
480 case op_fdiv_d:
481 case op_fmax_s:
482 case op_fmax_d:
483 case op_fmin_s:
484 case op_fmin_d:
485 case op_fmaxa_s:
486 case op_fmaxa_d:
487 case op_fmina_s:
488 case op_fmina_d:
489 case op_fcopysign_s:
490 case op_fcopysign_d:
491 case op_ldx_b:
492 case op_ldx_h:
493 case op_ldx_w:
494 case op_ldx_d:
495 case op_stx_b:
496 case op_stx_h:
497 case op_stx_w:
498 case op_stx_d:
499 case op_ldx_bu:
500 case op_ldx_hu:
501 case op_ldx_wu:
502 case op_fldx_s:
503 case op_fldx_d:
504 case op_fstx_s:
505 case op_fstx_d:
506 case op_amswap_w:
507 case op_amswap_d:
508 case op_amadd_w:
509 case op_amadd_d:
510 case op_amand_w:
511 case op_amand_d:
512 case op_amor_w:
513 case op_amor_d:
514 case op_amxor_w:
515 case op_amxor_d:
516 case op_ammax_w:
517 case op_ammax_d:
518 case op_ammin_w:
519 case op_ammin_d:
520 case op_ammax_wu:
521 case op_ammax_du:
522 case op_ammin_wu:
523 case op_ammin_du:
524 case op_amswap_db_w:
525 case op_amswap_db_d:
526 case op_amadd_db_w:
527 case op_amadd_db_d:
528 case op_amand_db_w:
529 case op_amand_db_d:
530 case op_amor_db_w:
531 case op_amor_db_d:
532 case op_amxor_db_w:
533 case op_amxor_db_d:
534 case op_ammax_db_w:
535 case op_ammax_db_d:
536 case op_ammin_db_w:
537 case op_ammin_db_d:
538 case op_ammax_db_wu:
539 case op_ammax_db_du:
540 case op_ammin_db_wu:
541 case op_ammin_db_du:
542 case op_dbar:
543 case op_ibar:
544 kType = kOp17Type;
545 break;
546 default:
547 kType = kUnsupported;
548 }
549 }
550
551 if (kType == kUnsupported) {
552 // Check for kOp22Type
553 switch (bits(31, 10) << 10) {
554 case op_clo_w:
555 case op_clz_w:
556 case op_cto_w:
557 case op_ctz_w:
558 case op_clo_d:
559 case op_clz_d:
560 case op_cto_d:
561 case op_ctz_d:
562 case op_revb_2h:
563 case op_revb_4h:
564 case op_revb_2w:
565 case op_revb_d:
566 case op_revh_2w:
567 case op_revh_d:
568 case op_bitrev_4b:
569 case op_bitrev_8b:
570 case op_bitrev_w:
571 case op_bitrev_d:
572 case op_ext_w_h:
573 case op_ext_w_b:
574 case op_fabs_s:
575 case op_fabs_d:
576 case op_fneg_s:
577 case op_fneg_d:
578 case op_fsqrt_s:
579 case op_fsqrt_d:
580 case op_fmov_s:
581 case op_fmov_d:
582 case op_movgr2fr_w:
583 case op_movgr2fr_d:
584 case op_movgr2frh_w:
585 case op_movfr2gr_s:
586 case op_movfr2gr_d:
587 case op_movfrh2gr_s:
588 case op_movfcsr2gr:
589 case op_movfr2cf:
590 case op_movgr2cf:
591 case op_fcvt_s_d:
592 case op_fcvt_d_s:
593 case op_ftintrm_w_s:
594 case op_ftintrm_w_d:
595 case op_ftintrm_l_s:
596 case op_ftintrm_l_d:
597 case op_ftintrp_w_s:
598 case op_ftintrp_w_d:
599 case op_ftintrp_l_s:
600 case op_ftintrp_l_d:
601 case op_ftintrz_w_s:
602 case op_ftintrz_w_d:
603 case op_ftintrz_l_s:
604 case op_ftintrz_l_d:
605 case op_ftintrne_w_s:
606 case op_ftintrne_w_d:
607 case op_ftintrne_l_s:
608 case op_ftintrne_l_d:
609 case op_ftint_w_s:
610 case op_ftint_w_d:
611 case op_ftint_l_s:
612 case op_ftint_l_d:
613 case op_ffint_s_w:
614 case op_ffint_s_l:
615 case op_ffint_d_w:
616 case op_ffint_d_l:
617 case op_frint_s:
618 case op_frint_d:
619 kType = kOp22Type;
620 break;
621 default:
622 kType = kUnsupported;
623 }
624 }
625
626 if (kType == kUnsupported) {
627 // Check for kOp24Type
628 switch (bits(31, 8) << 8) {
629 case op_movcf2fr:
630 case op_movcf2gr:
631 kType = kOp24Type;
632 break;
633 default:
634 kType = kUnsupported;
635 }
636 }
637
638 return kType;
639 }
640
641 // C/C++ argument slots size.
642 const int kCArgSlotCount = 0;
643 const int kCArgsSlotsSize = kCArgSlotCount * sizeof(uintptr_t);
644
645 class CachePage {
646 public:
647 static const int LINE_VALID = 0;
648 static const int LINE_INVALID = 1;
649
650 static const int kPageShift = 12;
651 static const int kPageSize = 1 << kPageShift;
652 static const int kPageMask = kPageSize - 1;
653 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
654 static const int kLineLength = 1 << kLineShift;
655 static const int kLineMask = kLineLength - 1;
656
CachePage()657 CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
658
validityByte(int offset)659 char* validityByte(int offset) {
660 return &validity_map_[offset >> kLineShift];
661 }
662
cachedData(int offset)663 char* cachedData(int offset) { return &data_[offset]; }
664
665 private:
666 char data_[kPageSize]; // The cached data.
667 static const int kValidityMapSize = kPageSize >> kLineShift;
668 char validity_map_[kValidityMapSize]; // One byte per line.
669 };
670
671 // Protects the icache() and redirection() properties of the
672 // Simulator.
673 class AutoLockSimulatorCache : public LockGuard<Mutex> {
674 using Base = LockGuard<Mutex>;
675
676 public:
AutoLockSimulatorCache()677 explicit AutoLockSimulatorCache()
678 : Base(SimulatorProcess::singleton_->cacheLock_) {}
679 };
680
681 mozilla::Atomic<size_t, mozilla::ReleaseAcquire>
682 SimulatorProcess::ICacheCheckingDisableCount(
683 1); // Checking is disabled by default.
684 SimulatorProcess* SimulatorProcess::singleton_ = nullptr;
685
686 int64_t Simulator::StopSimAt = -1;
687
Create()688 Simulator* Simulator::Create() {
689 auto sim = MakeUnique<Simulator>();
690 if (!sim) {
691 return nullptr;
692 }
693
694 if (!sim->init()) {
695 return nullptr;
696 }
697
698 int64_t stopAt;
699 char* stopAtStr = getenv("LOONG64_SIM_STOP_AT");
700 if (stopAtStr && sscanf(stopAtStr, "%" PRIi64, &stopAt) == 1) {
701 fprintf(stderr, "\nStopping simulation at icount %" PRIi64 "\n", stopAt);
702 Simulator::StopSimAt = stopAt;
703 }
704
705 return sim.release();
706 }
707
Destroy(Simulator * sim)708 void Simulator::Destroy(Simulator* sim) { js_delete(sim); }
709
710 // The loong64Debugger class is used by the simulator while debugging simulated
711 // code.
712 class loong64Debugger {
713 public:
loong64Debugger(Simulator * sim)714 explicit loong64Debugger(Simulator* sim) : sim_(sim) {}
715
716 void stop(SimInstruction* instr);
717 void debug();
718 // Print all registers with a nice formatting.
719 void printAllRegs();
720 void printAllRegsIncludingFPU();
721
722 private:
723 // We set the breakpoint code to 0x7fff to easily recognize it.
724 static const Instr kBreakpointInstr = op_break | (0x7fff & CODEMask);
725 static const Instr kNopInstr = 0x0;
726
727 Simulator* sim_;
728
729 int64_t getRegisterValue(int regnum);
730 int64_t getFPURegisterValueLong(int regnum);
731 float getFPURegisterValueFloat(int regnum);
732 double getFPURegisterValueDouble(int regnum);
733 bool getValue(const char* desc, int64_t* value);
734
735 // Set or delete a breakpoint. Returns true if successful.
736 bool setBreakpoint(SimInstruction* breakpc);
737 bool deleteBreakpoint(SimInstruction* breakpc);
738
739 // Undo and redo all breakpoints. This is needed to bracket disassembly and
740 // execution to skip past breakpoints when run from the debugger.
741 void undoBreakpoints();
742 void redoBreakpoints();
743 };
744
UNIMPLEMENTED()745 static void UNIMPLEMENTED() {
746 printf("UNIMPLEMENTED instruction.\n");
747 MOZ_CRASH();
748 }
UNREACHABLE()749 static void UNREACHABLE() {
750 printf("UNREACHABLE instruction.\n");
751 MOZ_CRASH();
752 }
UNSUPPORTED()753 static void UNSUPPORTED() {
754 printf("Unsupported instruction.\n");
755 MOZ_CRASH();
756 }
757
stop(SimInstruction * instr)758 void loong64Debugger::stop(SimInstruction* instr) {
759 // Get the stop code.
760 uint32_t code = instr->bits(25, 6);
761 // Retrieve the encoded address, which comes just after this stop.
762 char* msg =
763 *reinterpret_cast<char**>(sim_->get_pc() + SimInstruction::kInstrSize);
764 // Update this stop description.
765 if (!sim_->watchedStops_[code].desc_) {
766 sim_->watchedStops_[code].desc_ = msg;
767 }
768 // Print the stop message and code if it is not the default code.
769 if (code != kMaxStopCode) {
770 printf("Simulator hit stop %u: %s\n", code, msg);
771 } else {
772 printf("Simulator hit %s\n", msg);
773 }
774 sim_->set_pc(sim_->get_pc() + 2 * SimInstruction::kInstrSize);
775 debug();
776 }
777
getRegisterValue(int regnum)778 int64_t loong64Debugger::getRegisterValue(int regnum) {
779 if (regnum == kPCRegister) {
780 return sim_->get_pc();
781 }
782 return sim_->getRegister(regnum);
783 }
784
getFPURegisterValueLong(int regnum)785 int64_t loong64Debugger::getFPURegisterValueLong(int regnum) {
786 return sim_->getFpuRegister(regnum);
787 }
788
getFPURegisterValueFloat(int regnum)789 float loong64Debugger::getFPURegisterValueFloat(int regnum) {
790 return sim_->getFpuRegisterFloat(regnum);
791 }
792
getFPURegisterValueDouble(int regnum)793 double loong64Debugger::getFPURegisterValueDouble(int regnum) {
794 return sim_->getFpuRegisterDouble(regnum);
795 }
796
getValue(const char * desc,int64_t * value)797 bool loong64Debugger::getValue(const char* desc, int64_t* value) {
798 Register reg = Register::FromName(desc);
799 if (reg != InvalidReg) {
800 *value = getRegisterValue(reg.code());
801 return true;
802 }
803
804 if (strncmp(desc, "0x", 2) == 0) {
805 return sscanf(desc + 2, "%lx", reinterpret_cast<uint64_t*>(value)) == 1;
806 }
807 return sscanf(desc, "%lu", reinterpret_cast<uint64_t*>(value)) == 1;
808 }
809
setBreakpoint(SimInstruction * breakpc)810 bool loong64Debugger::setBreakpoint(SimInstruction* breakpc) {
811 // Check if a breakpoint can be set. If not return without any side-effects.
812 if (sim_->break_pc_ != nullptr) {
813 return false;
814 }
815
816 // Set the breakpoint.
817 sim_->break_pc_ = breakpc;
818 sim_->break_instr_ = breakpc->instructionBits();
819 // Not setting the breakpoint instruction in the code itself. It will be set
820 // when the debugger shell continues.
821 return true;
822 }
823
deleteBreakpoint(SimInstruction * breakpc)824 bool loong64Debugger::deleteBreakpoint(SimInstruction* breakpc) {
825 if (sim_->break_pc_ != nullptr) {
826 sim_->break_pc_->setInstructionBits(sim_->break_instr_);
827 }
828
829 sim_->break_pc_ = nullptr;
830 sim_->break_instr_ = 0;
831 return true;
832 }
833
undoBreakpoints()834 void loong64Debugger::undoBreakpoints() {
835 if (sim_->break_pc_) {
836 sim_->break_pc_->setInstructionBits(sim_->break_instr_);
837 }
838 }
839
redoBreakpoints()840 void loong64Debugger::redoBreakpoints() {
841 if (sim_->break_pc_) {
842 sim_->break_pc_->setInstructionBits(kBreakpointInstr);
843 }
844 }
845
printAllRegs()846 void loong64Debugger::printAllRegs() {
847 int64_t value;
848 for (uint32_t i = 0; i < Registers::Total; i++) {
849 value = getRegisterValue(i);
850 printf("%3s: 0x%016" PRIx64 " %20" PRIi64 " ", Registers::GetName(i),
851 value, value);
852
853 if (i % 2) {
854 printf("\n");
855 }
856 }
857 printf("\n");
858
859 value = getRegisterValue(Simulator::pc);
860 printf(" pc: 0x%016" PRIx64 "\n", value);
861 }
862
printAllRegsIncludingFPU()863 void loong64Debugger::printAllRegsIncludingFPU() {
864 printAllRegs();
865
866 printf("\n\n");
867 // f0, f1, f2, ... f31.
868 for (uint32_t i = 0; i < FloatRegisters::TotalPhys; i++) {
869 printf("%3s: 0x%016" PRIi64 "\tflt: %-8.4g\tdbl: %-16.4g\n",
870 FloatRegisters::GetName(i), getFPURegisterValueLong(i),
871 getFPURegisterValueFloat(i), getFPURegisterValueDouble(i));
872 }
873 }
874
ReadLine(const char * prompt)875 static char* ReadLine(const char* prompt) {
876 UniqueChars result;
877 char lineBuf[256];
878 int offset = 0;
879 bool keepGoing = true;
880 fprintf(stdout, "%s", prompt);
881 fflush(stdout);
882 while (keepGoing) {
883 if (fgets(lineBuf, sizeof(lineBuf), stdin) == nullptr) {
884 // fgets got an error. Just give up.
885 return nullptr;
886 }
887 int len = strlen(lineBuf);
888 if (len > 0 && lineBuf[len - 1] == '\n') {
889 // Since we read a new line we are done reading the line. This
890 // will exit the loop after copying this buffer into the result.
891 keepGoing = false;
892 }
893 if (!result) {
894 // Allocate the initial result and make room for the terminating '\0'
895 result.reset(js_pod_malloc<char>(len + 1));
896 if (!result) {
897 return nullptr;
898 }
899 } else {
900 // Allocate a new result with enough room for the new addition.
901 int new_len = offset + len + 1;
902 char* new_result = js_pod_malloc<char>(new_len);
903 if (!new_result) {
904 return nullptr;
905 }
906 // Copy the existing input into the new array and set the new
907 // array as the result.
908 memcpy(new_result, result.get(), offset * sizeof(char));
909 result.reset(new_result);
910 }
911 // Copy the newly read line into the result.
912 memcpy(result.get() + offset, lineBuf, len * sizeof(char));
913 offset += len;
914 }
915
916 MOZ_ASSERT(result);
917 result[offset] = '\0';
918 return result.release();
919 }
920
DisassembleInstruction(uint64_t pc)921 static void DisassembleInstruction(uint64_t pc) {
922 printf("Not supported on loongarch64 yet\n");
923 }
924
debug()925 void loong64Debugger::debug() {
926 intptr_t lastPC = -1;
927 bool done = false;
928
929 #define COMMAND_SIZE 63
930 #define ARG_SIZE 255
931
932 #define STR(a) #a
933 #define XSTR(a) STR(a)
934
935 char cmd[COMMAND_SIZE + 1];
936 char arg1[ARG_SIZE + 1];
937 char arg2[ARG_SIZE + 1];
938 char* argv[3] = {cmd, arg1, arg2};
939
940 // Make sure to have a proper terminating character if reaching the limit.
941 cmd[COMMAND_SIZE] = 0;
942 arg1[ARG_SIZE] = 0;
943 arg2[ARG_SIZE] = 0;
944
945 // Undo all set breakpoints while running in the debugger shell. This will
946 // make them invisible to all commands.
947 undoBreakpoints();
948
949 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
950 if (lastPC != sim_->get_pc()) {
951 DisassembleInstruction(sim_->get_pc());
952 printf(" 0x%016" PRIi64 " \n", sim_->get_pc());
953 lastPC = sim_->get_pc();
954 }
955 char* line = ReadLine("sim> ");
956 if (line == nullptr) {
957 break;
958 } else {
959 char* last_input = sim_->lastDebuggerInput();
960 if (strcmp(line, "\n") == 0 && last_input != nullptr) {
961 line = last_input;
962 } else {
963 // Ownership is transferred to sim_;
964 sim_->setLastDebuggerInput(line);
965 }
966 // Use sscanf to parse the individual parts of the command line. At the
967 // moment no command expects more than two parameters.
968 int argc = sscanf(line,
969 "%" XSTR(COMMAND_SIZE) "s "
970 "%" XSTR(ARG_SIZE) "s "
971 "%" XSTR(ARG_SIZE) "s",
972 cmd, arg1, arg2);
973 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
974 SimInstruction* instr =
975 reinterpret_cast<SimInstruction*>(sim_->get_pc());
976 if (!instr->isTrap()) {
977 sim_->instructionDecode(
978 reinterpret_cast<SimInstruction*>(sim_->get_pc()));
979 } else {
980 // Allow si to jump over generated breakpoints.
981 printf("/!\\ Jumping over generated breakpoint.\n");
982 sim_->set_pc(sim_->get_pc() + SimInstruction::kInstrSize);
983 }
984 sim_->icount_++;
985 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
986 // Execute the one instruction we broke at with breakpoints disabled.
987 sim_->instructionDecode(
988 reinterpret_cast<SimInstruction*>(sim_->get_pc()));
989 sim_->icount_++;
990 // Leave the debugger shell.
991 done = true;
992 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
993 if (argc == 2) {
994 int64_t value;
995 if (strcmp(arg1, "all") == 0) {
996 printAllRegs();
997 } else if (strcmp(arg1, "allf") == 0) {
998 printAllRegsIncludingFPU();
999 } else {
1000 Register reg = Register::FromName(arg1);
1001 FloatRegisters::Code fReg = FloatRegisters::FromName(arg1);
1002 if (reg != InvalidReg) {
1003 value = getRegisterValue(reg.code());
1004 printf("%s: 0x%016" PRIi64 " %20" PRIi64 " \n", arg1, value,
1005 value);
1006 } else if (fReg != FloatRegisters::Invalid) {
1007 printf("%3s: 0x%016" PRIi64 "\tflt: %-8.4g\tdbl: %-16.4g\n",
1008 FloatRegisters::GetName(fReg),
1009 getFPURegisterValueLong(fReg),
1010 getFPURegisterValueFloat(fReg),
1011 getFPURegisterValueDouble(fReg));
1012 } else {
1013 printf("%s unrecognized\n", arg1);
1014 }
1015 }
1016 } else {
1017 printf("print <register> or print <fpu register> single\n");
1018 }
1019 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
1020 int64_t* cur = nullptr;
1021 int64_t* end = nullptr;
1022 int next_arg = 1;
1023
1024 if (strcmp(cmd, "stack") == 0) {
1025 cur = reinterpret_cast<int64_t*>(sim_->getRegister(Simulator::sp));
1026 } else { // Command "mem".
1027 int64_t value;
1028 if (!getValue(arg1, &value)) {
1029 printf("%s unrecognized\n", arg1);
1030 continue;
1031 }
1032 cur = reinterpret_cast<int64_t*>(value);
1033 next_arg++;
1034 }
1035
1036 int64_t words;
1037 if (argc == next_arg) {
1038 words = 10;
1039 } else {
1040 if (!getValue(argv[next_arg], &words)) {
1041 words = 10;
1042 }
1043 }
1044 end = cur + words;
1045
1046 while (cur < end) {
1047 printf(" %p: 0x%016" PRIx64 " %20" PRIi64, cur, *cur, *cur);
1048 printf("\n");
1049 cur++;
1050 }
1051
1052 } else if ((strcmp(cmd, "disasm") == 0) || (strcmp(cmd, "dpc") == 0) ||
1053 (strcmp(cmd, "di") == 0)) {
1054 uint8_t* cur = nullptr;
1055 uint8_t* end = nullptr;
1056
1057 if (argc == 1) {
1058 cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
1059 end = cur + (10 * SimInstruction::kInstrSize);
1060 } else if (argc == 2) {
1061 Register reg = Register::FromName(arg1);
1062 if (reg != InvalidReg || strncmp(arg1, "0x", 2) == 0) {
1063 // The argument is an address or a register name.
1064 int64_t value;
1065 if (getValue(arg1, &value)) {
1066 cur = reinterpret_cast<uint8_t*>(value);
1067 // Disassemble 10 instructions at <arg1>.
1068 end = cur + (10 * SimInstruction::kInstrSize);
1069 }
1070 } else {
1071 // The argument is the number of instructions.
1072 int64_t value;
1073 if (getValue(arg1, &value)) {
1074 cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
1075 // Disassemble <arg1> instructions.
1076 end = cur + (value * SimInstruction::kInstrSize);
1077 }
1078 }
1079 } else {
1080 int64_t value1;
1081 int64_t value2;
1082 if (getValue(arg1, &value1) && getValue(arg2, &value2)) {
1083 cur = reinterpret_cast<uint8_t*>(value1);
1084 end = cur + (value2 * SimInstruction::kInstrSize);
1085 }
1086 }
1087
1088 while (cur < end) {
1089 DisassembleInstruction(uint64_t(cur));
1090 cur += SimInstruction::kInstrSize;
1091 }
1092 } else if (strcmp(cmd, "gdb") == 0) {
1093 printf("relinquishing control to gdb\n");
1094 asm("int $3");
1095 printf("regaining control from gdb\n");
1096 } else if (strcmp(cmd, "break") == 0) {
1097 if (argc == 2) {
1098 int64_t value;
1099 if (getValue(arg1, &value)) {
1100 if (!setBreakpoint(reinterpret_cast<SimInstruction*>(value))) {
1101 printf("setting breakpoint failed\n");
1102 }
1103 } else {
1104 printf("%s unrecognized\n", arg1);
1105 }
1106 } else {
1107 printf("break <address>\n");
1108 }
1109 } else if (strcmp(cmd, "del") == 0) {
1110 if (!deleteBreakpoint(nullptr)) {
1111 printf("deleting breakpoint failed\n");
1112 }
1113 } else if (strcmp(cmd, "flags") == 0) {
1114 printf("No flags on LOONG64 !\n");
1115 } else if (strcmp(cmd, "stop") == 0) {
1116 int64_t value;
1117 intptr_t stop_pc = sim_->get_pc() - 2 * SimInstruction::kInstrSize;
1118 SimInstruction* stop_instr = reinterpret_cast<SimInstruction*>(stop_pc);
1119 SimInstruction* msg_address = reinterpret_cast<SimInstruction*>(
1120 stop_pc + SimInstruction::kInstrSize);
1121 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
1122 // Remove the current stop.
1123 if (sim_->isStopInstruction(stop_instr)) {
1124 stop_instr->setInstructionBits(kNopInstr);
1125 msg_address->setInstructionBits(kNopInstr);
1126 } else {
1127 printf("Not at debugger stop.\n");
1128 }
1129 } else if (argc == 3) {
1130 // Print information about all/the specified breakpoint(s).
1131 if (strcmp(arg1, "info") == 0) {
1132 if (strcmp(arg2, "all") == 0) {
1133 printf("Stop information:\n");
1134 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
1135 i++) {
1136 sim_->printStopInfo(i);
1137 }
1138 } else if (getValue(arg2, &value)) {
1139 sim_->printStopInfo(value);
1140 } else {
1141 printf("Unrecognized argument.\n");
1142 }
1143 } else if (strcmp(arg1, "enable") == 0) {
1144 // Enable all/the specified breakpoint(s).
1145 if (strcmp(arg2, "all") == 0) {
1146 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
1147 i++) {
1148 sim_->enableStop(i);
1149 }
1150 } else if (getValue(arg2, &value)) {
1151 sim_->enableStop(value);
1152 } else {
1153 printf("Unrecognized argument.\n");
1154 }
1155 } else if (strcmp(arg1, "disable") == 0) {
1156 // Disable all/the specified breakpoint(s).
1157 if (strcmp(arg2, "all") == 0) {
1158 for (uint32_t i = kMaxWatchpointCode + 1; i <= kMaxStopCode;
1159 i++) {
1160 sim_->disableStop(i);
1161 }
1162 } else if (getValue(arg2, &value)) {
1163 sim_->disableStop(value);
1164 } else {
1165 printf("Unrecognized argument.\n");
1166 }
1167 }
1168 } else {
1169 printf("Wrong usage. Use help command for more information.\n");
1170 }
1171 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
1172 printf("cont\n");
1173 printf(" continue execution (alias 'c')\n");
1174 printf("stepi\n");
1175 printf(" step one instruction (alias 'si')\n");
1176 printf("print <register>\n");
1177 printf(" print register content (alias 'p')\n");
1178 printf(" use register name 'all' to print all registers\n");
1179 printf("printobject <register>\n");
1180 printf(" print an object from a register (alias 'po')\n");
1181 printf("stack [<words>]\n");
1182 printf(" dump stack content, default dump 10 words)\n");
1183 printf("mem <address> [<words>]\n");
1184 printf(" dump memory content, default dump 10 words)\n");
1185 printf("flags\n");
1186 printf(" print flags\n");
1187 printf("disasm [<instructions>]\n");
1188 printf("disasm [<address/register>]\n");
1189 printf("disasm [[<address/register>] <instructions>]\n");
1190 printf(" disassemble code, default is 10 instructions\n");
1191 printf(" from pc (alias 'di')\n");
1192 printf("gdb\n");
1193 printf(" enter gdb\n");
1194 printf("break <address>\n");
1195 printf(" set a break point on the address\n");
1196 printf("del\n");
1197 printf(" delete the breakpoint\n");
1198 printf("stop feature:\n");
1199 printf(" Description:\n");
1200 printf(" Stops are debug instructions inserted by\n");
1201 printf(" the Assembler::stop() function.\n");
1202 printf(" When hitting a stop, the Simulator will\n");
1203 printf(" stop and and give control to the Debugger.\n");
1204 printf(" All stop codes are watched:\n");
1205 printf(" - They can be enabled / disabled: the Simulator\n");
1206 printf(" will / won't stop when hitting them.\n");
1207 printf(" - The Simulator keeps track of how many times they \n");
1208 printf(" are met. (See the info command.) Going over a\n");
1209 printf(" disabled stop still increases its counter. \n");
1210 printf(" Commands:\n");
1211 printf(" stop info all/<code> : print infos about number <code>\n");
1212 printf(" or all stop(s).\n");
1213 printf(" stop enable/disable all/<code> : enables / disables\n");
1214 printf(" all or number <code> stop(s)\n");
1215 printf(" stop unstop\n");
1216 printf(" ignore the stop instruction at the current location\n");
1217 printf(" from now on\n");
1218 } else {
1219 printf("Unknown command: %s\n", cmd);
1220 }
1221 }
1222 }
1223
1224 // Add all the breakpoints back to stop execution and enter the debugger
1225 // shell when hit.
1226 redoBreakpoints();
1227
1228 #undef COMMAND_SIZE
1229 #undef ARG_SIZE
1230
1231 #undef STR
1232 #undef XSTR
1233 }
1234
AllOnOnePage(uintptr_t start,int size)1235 static bool AllOnOnePage(uintptr_t start, int size) {
1236 intptr_t start_page = (start & ~CachePage::kPageMask);
1237 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
1238 return start_page == end_page;
1239 }
1240
setLastDebuggerInput(char * input)1241 void Simulator::setLastDebuggerInput(char* input) {
1242 js_free(lastDebuggerInput_);
1243 lastDebuggerInput_ = input;
1244 }
1245
GetCachePageLocked(SimulatorProcess::ICacheMap & i_cache,void * page)1246 static CachePage* GetCachePageLocked(SimulatorProcess::ICacheMap& i_cache,
1247 void* page) {
1248 SimulatorProcess::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
1249 if (p) {
1250 return p->value();
1251 }
1252 AutoEnterOOMUnsafeRegion oomUnsafe;
1253 CachePage* new_page = js_new<CachePage>();
1254 if (!new_page || !i_cache.add(p, page, new_page)) {
1255 oomUnsafe.crash("Simulator CachePage");
1256 }
1257 return new_page;
1258 }
1259
1260 // Flush from start up to and not including start + size.
FlushOnePageLocked(SimulatorProcess::ICacheMap & i_cache,intptr_t start,int size)1261 static void FlushOnePageLocked(SimulatorProcess::ICacheMap& i_cache,
1262 intptr_t start, int size) {
1263 MOZ_ASSERT(size <= CachePage::kPageSize);
1264 MOZ_ASSERT(AllOnOnePage(start, size - 1));
1265 MOZ_ASSERT((start & CachePage::kLineMask) == 0);
1266 MOZ_ASSERT((size & CachePage::kLineMask) == 0);
1267 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
1268 int offset = (start & CachePage::kPageMask);
1269 CachePage* cache_page = GetCachePageLocked(i_cache, page);
1270 char* valid_bytemap = cache_page->validityByte(offset);
1271 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
1272 }
1273
FlushICacheLocked(SimulatorProcess::ICacheMap & i_cache,void * start_addr,size_t size)1274 static void FlushICacheLocked(SimulatorProcess::ICacheMap& i_cache,
1275 void* start_addr, size_t size) {
1276 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
1277 int intra_line = (start & CachePage::kLineMask);
1278 start -= intra_line;
1279 size += intra_line;
1280 size = ((size - 1) | CachePage::kLineMask) + 1;
1281 int offset = (start & CachePage::kPageMask);
1282 while (!AllOnOnePage(start, size - 1)) {
1283 int bytes_to_flush = CachePage::kPageSize - offset;
1284 FlushOnePageLocked(i_cache, start, bytes_to_flush);
1285 start += bytes_to_flush;
1286 size -= bytes_to_flush;
1287 MOZ_ASSERT((start & CachePage::kPageMask) == 0);
1288 offset = 0;
1289 }
1290 if (size != 0) {
1291 FlushOnePageLocked(i_cache, start, size);
1292 }
1293 }
1294
1295 /* static */
checkICacheLocked(SimInstruction * instr)1296 void SimulatorProcess::checkICacheLocked(SimInstruction* instr) {
1297 intptr_t address = reinterpret_cast<intptr_t>(instr);
1298 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
1299 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
1300 int offset = (address & CachePage::kPageMask);
1301 CachePage* cache_page = GetCachePageLocked(icache(), page);
1302 char* cache_valid_byte = cache_page->validityByte(offset);
1303 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
1304 char* cached_line = cache_page->cachedData(offset & ~CachePage::kLineMask);
1305
1306 if (cache_hit) {
1307 // Check that the data in memory matches the contents of the I-cache.
1308 mozilla::DebugOnly<int> cmpret =
1309 memcmp(reinterpret_cast<void*>(instr), cache_page->cachedData(offset),
1310 SimInstruction::kInstrSize);
1311 MOZ_ASSERT(cmpret == 0);
1312 } else {
1313 // Cache miss. Load memory into the cache.
1314 memcpy(cached_line, line, CachePage::kLineLength);
1315 *cache_valid_byte = CachePage::LINE_VALID;
1316 }
1317 }
1318
hash(const Lookup & l)1319 HashNumber SimulatorProcess::ICacheHasher::hash(const Lookup& l) {
1320 return U32(reinterpret_cast<uintptr_t>(l)) >> 2;
1321 }
1322
match(const Key & k,const Lookup & l)1323 bool SimulatorProcess::ICacheHasher::match(const Key& k, const Lookup& l) {
1324 MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0);
1325 MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0);
1326 return k == l;
1327 }
1328
1329 /* static */
FlushICache(void * start_addr,size_t size)1330 void SimulatorProcess::FlushICache(void* start_addr, size_t size) {
1331 if (!ICacheCheckingDisableCount) {
1332 AutoLockSimulatorCache als;
1333 js::jit::FlushICacheLocked(icache(), start_addr, size);
1334 }
1335 }
1336
Simulator()1337 Simulator::Simulator() {
1338 // Set up simulator support first. Some of this information is needed to
1339 // setup the architecture state.
1340
1341 // Note, allocation and anything that depends on allocated memory is
1342 // deferred until init(), in order to handle OOM properly.
1343
1344 stack_ = nullptr;
1345 stackLimit_ = 0;
1346 pc_modified_ = false;
1347 icount_ = 0;
1348 break_count_ = 0;
1349 break_pc_ = nullptr;
1350 break_instr_ = 0;
1351 single_stepping_ = false;
1352 single_step_callback_ = nullptr;
1353 single_step_callback_arg_ = nullptr;
1354
1355 // Set up architecture state.
1356 // All registers are initialized to zero to start with.
1357 for (int i = 0; i < Register::kNumSimuRegisters; i++) {
1358 registers_[i] = 0;
1359 }
1360 for (int i = 0; i < Simulator::FPURegister::kNumFPURegisters; i++) {
1361 FPUregisters_[i] = 0;
1362 }
1363
1364 for (int i = 0; i < kNumCFRegisters; i++) {
1365 CFregisters_[i] = 0;
1366 }
1367
1368 FCSR_ = 0;
1369 LLBit_ = false;
1370 LLAddr_ = 0;
1371 lastLLValue_ = 0;
1372
1373 // The ra and pc are initialized to a known bad value that will cause an
1374 // access violation if the simulator ever tries to execute it.
1375 registers_[pc] = bad_ra;
1376 registers_[ra] = bad_ra;
1377
1378 for (int i = 0; i < kNumExceptions; i++) {
1379 exceptions[i] = 0;
1380 }
1381
1382 lastDebuggerInput_ = nullptr;
1383 }
1384
init()1385 bool Simulator::init() {
1386 // Allocate 2MB for the stack. Note that we will only use 1MB, see below.
1387 static const size_t stackSize = 2 * 1024 * 1024;
1388 stack_ = js_pod_malloc<char>(stackSize);
1389 if (!stack_) {
1390 return false;
1391 }
1392
1393 // Leave a safety margin of 1MB to prevent overrunning the stack when
1394 // pushing values (total stack size is 2MB).
1395 stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
1396
1397 // The sp is initialized to point to the bottom (high address) of the
1398 // allocated stack area. To be safe in potential stack underflows we leave
1399 // some buffer below.
1400 registers_[sp] = reinterpret_cast<int64_t>(stack_) + stackSize - 64;
1401
1402 return true;
1403 }
1404
1405 // When the generated code calls an external reference we need to catch that in
1406 // the simulator. The external reference will be a function compiled for the
1407 // host architecture. We need to call that function instead of trying to
1408 // execute it with the simulator. We do that by redirecting the external
1409 // reference to a swi (software-interrupt) instruction that is handled by
1410 // the simulator. We write the original destination of the jump just at a known
1411 // offset from the swi instruction so the simulator knows what to call.
1412 class Redirection {
1413 friend class SimulatorProcess;
1414
1415 // sim's lock must already be held.
Redirection(void * nativeFunction,ABIFunctionType type)1416 Redirection(void* nativeFunction, ABIFunctionType type)
1417 : nativeFunction_(nativeFunction),
1418 swiInstruction_(kCallRedirInstr),
1419 type_(type),
1420 next_(nullptr) {
1421 next_ = SimulatorProcess::redirection();
1422 if (!SimulatorProcess::ICacheCheckingDisableCount) {
1423 FlushICacheLocked(SimulatorProcess::icache(), addressOfSwiInstruction(),
1424 SimInstruction::kInstrSize);
1425 }
1426 SimulatorProcess::setRedirection(this);
1427 }
1428
1429 public:
addressOfSwiInstruction()1430 void* addressOfSwiInstruction() { return &swiInstruction_; }
nativeFunction() const1431 void* nativeFunction() const { return nativeFunction_; }
type() const1432 ABIFunctionType type() const { return type_; }
1433
Get(void * nativeFunction,ABIFunctionType type)1434 static Redirection* Get(void* nativeFunction, ABIFunctionType type) {
1435 AutoLockSimulatorCache als;
1436
1437 Redirection* current = SimulatorProcess::redirection();
1438 for (; current != nullptr; current = current->next_) {
1439 if (current->nativeFunction_ == nativeFunction) {
1440 MOZ_ASSERT(current->type() == type);
1441 return current;
1442 }
1443 }
1444
1445 // Note: we can't use js_new here because the constructor is private.
1446 AutoEnterOOMUnsafeRegion oomUnsafe;
1447 Redirection* redir = js_pod_malloc<Redirection>(1);
1448 if (!redir) {
1449 oomUnsafe.crash("Simulator redirection");
1450 }
1451 new (redir) Redirection(nativeFunction, type);
1452 return redir;
1453 }
1454
FromSwiInstruction(SimInstruction * swiInstruction)1455 static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) {
1456 uint8_t* addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction);
1457 uint8_t* addrOfRedirection =
1458 addrOfSwi - offsetof(Redirection, swiInstruction_);
1459 return reinterpret_cast<Redirection*>(addrOfRedirection);
1460 }
1461
1462 private:
1463 void* nativeFunction_;
1464 uint32_t swiInstruction_;
1465 ABIFunctionType type_;
1466 Redirection* next_;
1467 };
1468
~Simulator()1469 Simulator::~Simulator() { js_free(stack_); }
1470
SimulatorProcess()1471 SimulatorProcess::SimulatorProcess()
1472 : cacheLock_(mutexid::SimulatorCacheLock), redirection_(nullptr) {
1473 if (getenv("LOONG64_SIM_ICACHE_CHECKS")) {
1474 ICacheCheckingDisableCount = 0;
1475 }
1476 }
1477
~SimulatorProcess()1478 SimulatorProcess::~SimulatorProcess() {
1479 Redirection* r = redirection_;
1480 while (r) {
1481 Redirection* next = r->next_;
1482 js_delete(r);
1483 r = next;
1484 }
1485 }
1486
1487 /* static */
RedirectNativeFunction(void * nativeFunction,ABIFunctionType type)1488 void* Simulator::RedirectNativeFunction(void* nativeFunction,
1489 ABIFunctionType type) {
1490 Redirection* redirection = Redirection::Get(nativeFunction, type);
1491 return redirection->addressOfSwiInstruction();
1492 }
1493
1494 // Get the active Simulator for the current thread.
Current()1495 Simulator* Simulator::Current() {
1496 JSContext* cx = TlsContext.get();
1497 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
1498 return cx->simulator();
1499 }
1500
1501 // Sets the register in the architecture state. It will also deal with updating
1502 // Simulator internal state for special registers such as PC.
setRegister(int reg,int64_t value)1503 void Simulator::setRegister(int reg, int64_t value) {
1504 MOZ_ASSERT((reg >= 0) && (reg < Register::kNumSimuRegisters));
1505 if (reg == pc) {
1506 pc_modified_ = true;
1507 }
1508
1509 // Zero register always holds 0.
1510 registers_[reg] = (reg == 0) ? 0 : value;
1511 }
1512
setFpuRegister(int fpureg,int64_t value)1513 void Simulator::setFpuRegister(int fpureg, int64_t value) {
1514 MOZ_ASSERT((fpureg >= 0) &&
1515 (fpureg < Simulator::FPURegister::kNumFPURegisters));
1516 FPUregisters_[fpureg] = value;
1517 }
1518
setFpuRegisterHiWord(int fpureg,int32_t value)1519 void Simulator::setFpuRegisterHiWord(int fpureg, int32_t value) {
1520 // Set ONLY upper 32-bits, leaving lower bits untouched.
1521 MOZ_ASSERT((fpureg >= 0) &&
1522 (fpureg < Simulator::FPURegister::kNumFPURegisters));
1523 int32_t* phiword;
1524 phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
1525
1526 *phiword = value;
1527 }
1528
setFpuRegisterWord(int fpureg,int32_t value)1529 void Simulator::setFpuRegisterWord(int fpureg, int32_t value) {
1530 // Set ONLY lower 32-bits, leaving upper bits untouched.
1531 MOZ_ASSERT((fpureg >= 0) &&
1532 (fpureg < Simulator::FPURegister::kNumFPURegisters));
1533 int32_t* pword;
1534 pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
1535
1536 *pword = value;
1537 }
1538
setFpuRegisterWordInvalidResult(float original,float rounded,int fpureg)1539 void Simulator::setFpuRegisterWordInvalidResult(float original, float rounded,
1540 int fpureg) {
1541 double max_int32 = static_cast<double>(INT32_MAX);
1542 double min_int32 = static_cast<double>(INT32_MIN);
1543
1544 if (std::isnan(original)) {
1545 setFpuRegisterWord(fpureg, 0);
1546 } else if (rounded > max_int32) {
1547 setFpuRegister(fpureg, kFPUInvalidResult);
1548 } else if (rounded < min_int32) {
1549 setFpuRegister(fpureg, kFPUInvalidResultNegative);
1550 } else {
1551 UNREACHABLE();
1552 }
1553 }
1554
setFpuRegisterWordInvalidResult(double original,double rounded,int fpureg)1555 void Simulator::setFpuRegisterWordInvalidResult(double original, double rounded,
1556 int fpureg) {
1557 double max_int32 = static_cast<double>(INT32_MAX);
1558 double min_int32 = static_cast<double>(INT32_MIN);
1559
1560 if (std::isnan(original)) {
1561 setFpuRegisterWord(fpureg, 0);
1562 } else if (rounded > max_int32) {
1563 setFpuRegisterWord(fpureg, kFPUInvalidResult);
1564 } else if (rounded < min_int32) {
1565 setFpuRegisterWord(fpureg, kFPUInvalidResultNegative);
1566 } else {
1567 UNREACHABLE();
1568 }
1569 }
1570
setFpuRegisterInvalidResult(float original,float rounded,int fpureg)1571 void Simulator::setFpuRegisterInvalidResult(float original, float rounded,
1572 int fpureg) {
1573 double max_int32 = static_cast<double>(INT32_MAX);
1574 double min_int32 = static_cast<double>(INT32_MIN);
1575
1576 if (std::isnan(original)) {
1577 setFpuRegister(fpureg, 0);
1578 } else if (rounded > max_int32) {
1579 setFpuRegister(fpureg, kFPUInvalidResult);
1580 } else if (rounded < min_int32) {
1581 setFpuRegister(fpureg, kFPUInvalidResultNegative);
1582 } else {
1583 UNREACHABLE();
1584 }
1585 }
1586
setFpuRegisterInvalidResult(double original,double rounded,int fpureg)1587 void Simulator::setFpuRegisterInvalidResult(double original, double rounded,
1588 int fpureg) {
1589 double max_int32 = static_cast<double>(INT32_MAX);
1590 double min_int32 = static_cast<double>(INT32_MIN);
1591
1592 if (std::isnan(original)) {
1593 setFpuRegister(fpureg, 0);
1594 } else if (rounded > max_int32) {
1595 setFpuRegister(fpureg, kFPUInvalidResult);
1596 } else if (rounded < min_int32) {
1597 setFpuRegister(fpureg, kFPUInvalidResultNegative);
1598 } else {
1599 UNREACHABLE();
1600 }
1601 }
1602
setFpuRegisterInvalidResult64(float original,float rounded,int fpureg)1603 void Simulator::setFpuRegisterInvalidResult64(float original, float rounded,
1604 int fpureg) {
1605 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1606 // loading the most accurate representation into max_int64, which is 2^63.
1607 double max_int64 = static_cast<double>(INT64_MAX);
1608 double min_int64 = static_cast<double>(INT64_MIN);
1609
1610 if (std::isnan(original)) {
1611 setFpuRegister(fpureg, 0);
1612 } else if (rounded >= max_int64) {
1613 setFpuRegister(fpureg, kFPU64InvalidResult);
1614 } else if (rounded < min_int64) {
1615 setFpuRegister(fpureg, kFPU64InvalidResultNegative);
1616 } else {
1617 UNREACHABLE();
1618 }
1619 }
1620
setFpuRegisterInvalidResult64(double original,double rounded,int fpureg)1621 void Simulator::setFpuRegisterInvalidResult64(double original, double rounded,
1622 int fpureg) {
1623 // The value of INT64_MAX (2^63-1) can't be represented as double exactly,
1624 // loading the most accurate representation into max_int64, which is 2^63.
1625 double max_int64 = static_cast<double>(INT64_MAX);
1626 double min_int64 = static_cast<double>(INT64_MIN);
1627
1628 if (std::isnan(original)) {
1629 setFpuRegister(fpureg, 0);
1630 } else if (rounded >= max_int64) {
1631 setFpuRegister(fpureg, kFPU64InvalidResult);
1632 } else if (rounded < min_int64) {
1633 setFpuRegister(fpureg, kFPU64InvalidResultNegative);
1634 } else {
1635 UNREACHABLE();
1636 }
1637 }
1638
setFpuRegisterFloat(int fpureg,float value)1639 void Simulator::setFpuRegisterFloat(int fpureg, float value) {
1640 MOZ_ASSERT((fpureg >= 0) &&
1641 (fpureg < Simulator::FPURegister::kNumFPURegisters));
1642 *mozilla::BitwiseCast<float*>(&FPUregisters_[fpureg]) = value;
1643 }
1644
setFpuRegisterDouble(int fpureg,double value)1645 void Simulator::setFpuRegisterDouble(int fpureg, double value) {
1646 MOZ_ASSERT((fpureg >= 0) &&
1647 (fpureg < Simulator::FPURegister::kNumFPURegisters));
1648 *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]) = value;
1649 }
1650
setCFRegister(int cfreg,bool value)1651 void Simulator::setCFRegister(int cfreg, bool value) {
1652 MOZ_ASSERT((cfreg >= 0) && (cfreg < kNumCFRegisters));
1653 CFregisters_[cfreg] = value;
1654 }
1655
getCFRegister(int cfreg) const1656 bool Simulator::getCFRegister(int cfreg) const {
1657 MOZ_ASSERT((cfreg >= 0) && (cfreg < kNumCFRegisters));
1658 return CFregisters_[cfreg];
1659 }
1660
1661 // Get the register from the architecture state. This function does handle
1662 // the special case of accessing the PC register.
getRegister(int reg) const1663 int64_t Simulator::getRegister(int reg) const {
1664 MOZ_ASSERT((reg >= 0) && (reg < Register::kNumSimuRegisters));
1665 if (reg == 0) {
1666 return 0;
1667 }
1668 return registers_[reg] + ((reg == pc) ? SimInstruction::kPCReadOffset : 0);
1669 }
1670
getFpuRegister(int fpureg) const1671 int64_t Simulator::getFpuRegister(int fpureg) const {
1672 MOZ_ASSERT((fpureg >= 0) &&
1673 (fpureg < Simulator::FPURegister::kNumFPURegisters));
1674 return FPUregisters_[fpureg];
1675 }
1676
getFpuRegisterWord(int fpureg) const1677 int32_t Simulator::getFpuRegisterWord(int fpureg) const {
1678 MOZ_ASSERT((fpureg >= 0) &&
1679 (fpureg < Simulator::FPURegister::kNumFPURegisters));
1680 return *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]);
1681 }
1682
getFpuRegisterSignedWord(int fpureg) const1683 int32_t Simulator::getFpuRegisterSignedWord(int fpureg) const {
1684 MOZ_ASSERT((fpureg >= 0) &&
1685 (fpureg < Simulator::FPURegister::kNumFPURegisters));
1686 return *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]);
1687 }
1688
getFpuRegisterHiWord(int fpureg) const1689 int32_t Simulator::getFpuRegisterHiWord(int fpureg) const {
1690 MOZ_ASSERT((fpureg >= 0) &&
1691 (fpureg < Simulator::FPURegister::kNumFPURegisters));
1692 return *((mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg])) + 1);
1693 }
1694
getFpuRegisterFloat(int fpureg) const1695 float Simulator::getFpuRegisterFloat(int fpureg) const {
1696 MOZ_ASSERT((fpureg >= 0) &&
1697 (fpureg < Simulator::FPURegister::kNumFPURegisters));
1698 return *mozilla::BitwiseCast<float*>(&FPUregisters_[fpureg]);
1699 }
1700
getFpuRegisterDouble(int fpureg) const1701 double Simulator::getFpuRegisterDouble(int fpureg) const {
1702 MOZ_ASSERT((fpureg >= 0) &&
1703 (fpureg < Simulator::FPURegister::kNumFPURegisters));
1704 return *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]);
1705 }
1706
setCallResultDouble(double result)1707 void Simulator::setCallResultDouble(double result) {
1708 setFpuRegisterDouble(f0, result);
1709 }
1710
setCallResultFloat(float result)1711 void Simulator::setCallResultFloat(float result) {
1712 setFpuRegisterFloat(f0, result);
1713 }
1714
setCallResult(int64_t res)1715 void Simulator::setCallResult(int64_t res) { setRegister(a0, res); }
1716
setCallResult(__int128_t res)1717 void Simulator::setCallResult(__int128_t res) {
1718 setRegister(a0, I64(res));
1719 setRegister(a1, I64(res >> 64));
1720 }
1721
1722 // Helper functions for setting and testing the FCSR register's bits.
setFCSRBit(uint32_t cc,bool value)1723 void Simulator::setFCSRBit(uint32_t cc, bool value) {
1724 if (value) {
1725 FCSR_ |= (1 << cc);
1726 } else {
1727 FCSR_ &= ~(1 << cc);
1728 }
1729 }
1730
testFCSRBit(uint32_t cc)1731 bool Simulator::testFCSRBit(uint32_t cc) { return FCSR_ & (1 << cc); }
1732
getFCSRRoundingMode()1733 unsigned int Simulator::getFCSRRoundingMode() {
1734 return FCSR_ & kFPURoundingModeMask;
1735 }
1736
1737 // Sets the rounding error codes in FCSR based on the result of the rounding.
1738 // Returns true if the operation was invalid.
1739 template <typename T>
setFCSRRoundError(double original,double rounded)1740 bool Simulator::setFCSRRoundError(double original, double rounded) {
1741 bool ret = false;
1742
1743 setFCSRBit(kFCSRInexactCauseBit, false);
1744 setFCSRBit(kFCSRUnderflowCauseBit, false);
1745 setFCSRBit(kFCSROverflowCauseBit, false);
1746 setFCSRBit(kFCSRInvalidOpCauseBit, false);
1747
1748 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1749 setFCSRBit(kFCSRInvalidOpFlagBit, true);
1750 setFCSRBit(kFCSRInvalidOpCauseBit, true);
1751 ret = true;
1752 }
1753
1754 if (original != rounded) {
1755 setFCSRBit(kFCSRInexactFlagBit, true);
1756 setFCSRBit(kFCSRInexactCauseBit, true);
1757 }
1758
1759 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1760 setFCSRBit(kFCSRUnderflowFlagBit, true);
1761 setFCSRBit(kFCSRUnderflowCauseBit, true);
1762 ret = true;
1763 }
1764
1765 if ((long double)rounded > (long double)std::numeric_limits<T>::max() ||
1766 (long double)rounded < (long double)std::numeric_limits<T>::min()) {
1767 setFCSRBit(kFCSROverflowFlagBit, true);
1768 setFCSRBit(kFCSROverflowCauseBit, true);
1769 // The reference is not really clear but it seems this is required:
1770 setFCSRBit(kFCSRInvalidOpFlagBit, true);
1771 setFCSRBit(kFCSRInvalidOpCauseBit, true);
1772 ret = true;
1773 }
1774
1775 return ret;
1776 }
1777
1778 // For cvt instructions only
1779 template <typename T>
roundAccordingToFCSR(T toRound,T * rounded,int32_t * rounded_int)1780 void Simulator::roundAccordingToFCSR(T toRound, T* rounded,
1781 int32_t* rounded_int) {
1782 switch ((FCSR_ >> 8) & 3) {
1783 case kRoundToNearest:
1784 *rounded = std::floor(toRound + 0.5);
1785 *rounded_int = static_cast<int32_t>(*rounded);
1786 if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
1787 // If the number is halfway between two integers,
1788 // round to the even one.
1789 *rounded_int -= 1;
1790 *rounded -= 1.;
1791 }
1792 break;
1793 case kRoundToZero:
1794 *rounded = trunc(toRound);
1795 *rounded_int = static_cast<int32_t>(*rounded);
1796 break;
1797 case kRoundToPlusInf:
1798 *rounded = std::ceil(toRound);
1799 *rounded_int = static_cast<int32_t>(*rounded);
1800 break;
1801 case kRoundToMinusInf:
1802 *rounded = std::floor(toRound);
1803 *rounded_int = static_cast<int32_t>(*rounded);
1804 break;
1805 }
1806 }
1807
1808 template <typename T>
round64AccordingToFCSR(T toRound,T * rounded,int64_t * rounded_int)1809 void Simulator::round64AccordingToFCSR(T toRound, T* rounded,
1810 int64_t* rounded_int) {
1811 switch ((FCSR_ >> 8) & 3) {
1812 case kRoundToNearest:
1813 *rounded = std::floor(toRound + 0.5);
1814 *rounded_int = static_cast<int64_t>(*rounded);
1815 if ((*rounded_int & 1) != 0 && *rounded_int - toRound == 0.5) {
1816 // If the number is halfway between two integers,
1817 // round to the even one.
1818 *rounded_int -= 1;
1819 *rounded -= 1.;
1820 }
1821 break;
1822 case kRoundToZero:
1823 *rounded = trunc(toRound);
1824 *rounded_int = static_cast<int64_t>(*rounded);
1825 break;
1826 case kRoundToPlusInf:
1827 *rounded = std::ceil(toRound);
1828 *rounded_int = static_cast<int64_t>(*rounded);
1829 break;
1830 case kRoundToMinusInf:
1831 *rounded = std::floor(toRound);
1832 *rounded_int = static_cast<int64_t>(*rounded);
1833 break;
1834 }
1835 }
1836
1837 // Raw access to the PC register.
set_pc(int64_t value)1838 void Simulator::set_pc(int64_t value) {
1839 pc_modified_ = true;
1840 registers_[pc] = value;
1841 }
1842
has_bad_pc() const1843 bool Simulator::has_bad_pc() const {
1844 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1845 }
1846
1847 // Raw access to the PC register without the special adjustment when reading.
get_pc() const1848 int64_t Simulator::get_pc() const { return registers_[pc]; }
1849
registerState()1850 JS::ProfilingFrameIterator::RegisterState Simulator::registerState() {
1851 wasm::RegisterState state;
1852 state.pc = (void*)get_pc();
1853 state.fp = (void*)getRegister(fp);
1854 state.sp = (void*)getRegister(sp);
1855 state.lr = (void*)getRegister(ra);
1856 return state;
1857 }
1858
readBU(uint64_t addr)1859 uint8_t Simulator::readBU(uint64_t addr) {
1860 if (handleWasmSegFault(addr, 1)) {
1861 return 0xff;
1862 }
1863
1864 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1865 return *ptr;
1866 }
1867
readB(uint64_t addr)1868 int8_t Simulator::readB(uint64_t addr) {
1869 if (handleWasmSegFault(addr, 1)) {
1870 return -1;
1871 }
1872
1873 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1874 return *ptr;
1875 }
1876
writeB(uint64_t addr,uint8_t value)1877 void Simulator::writeB(uint64_t addr, uint8_t value) {
1878 if (handleWasmSegFault(addr, 1)) {
1879 return;
1880 }
1881
1882 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1883 *ptr = value;
1884 }
1885
writeB(uint64_t addr,int8_t value)1886 void Simulator::writeB(uint64_t addr, int8_t value) {
1887 if (handleWasmSegFault(addr, 1)) {
1888 return;
1889 }
1890
1891 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1892 *ptr = value;
1893 }
1894
readHU(uint64_t addr,SimInstruction * instr)1895 uint16_t Simulator::readHU(uint64_t addr, SimInstruction* instr) {
1896 if (handleWasmSegFault(addr, 2)) {
1897 return 0xffff;
1898 }
1899
1900 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1901 return *ptr;
1902 }
1903
readH(uint64_t addr,SimInstruction * instr)1904 int16_t Simulator::readH(uint64_t addr, SimInstruction* instr) {
1905 if (handleWasmSegFault(addr, 2)) {
1906 return -1;
1907 }
1908
1909 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1910 return *ptr;
1911 }
1912
writeH(uint64_t addr,uint16_t value,SimInstruction * instr)1913 void Simulator::writeH(uint64_t addr, uint16_t value, SimInstruction* instr) {
1914 if (handleWasmSegFault(addr, 2)) {
1915 return;
1916 }
1917
1918 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1919 LLBit_ = false;
1920 *ptr = value;
1921 return;
1922 }
1923
writeH(uint64_t addr,int16_t value,SimInstruction * instr)1924 void Simulator::writeH(uint64_t addr, int16_t value, SimInstruction* instr) {
1925 if (handleWasmSegFault(addr, 2)) {
1926 return;
1927 }
1928
1929 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1930 LLBit_ = false;
1931 *ptr = value;
1932 return;
1933 }
1934
readWU(uint64_t addr,SimInstruction * instr)1935 uint32_t Simulator::readWU(uint64_t addr, SimInstruction* instr) {
1936 if (handleWasmSegFault(addr, 4)) {
1937 return -1;
1938 }
1939
1940 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
1941 return *ptr;
1942 }
1943
readW(uint64_t addr,SimInstruction * instr)1944 int32_t Simulator::readW(uint64_t addr, SimInstruction* instr) {
1945 if (handleWasmSegFault(addr, 4)) {
1946 return -1;
1947 }
1948
1949 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1950 return *ptr;
1951 }
1952
writeW(uint64_t addr,uint32_t value,SimInstruction * instr)1953 void Simulator::writeW(uint64_t addr, uint32_t value, SimInstruction* instr) {
1954 if (handleWasmSegFault(addr, 4)) {
1955 return;
1956 }
1957
1958 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
1959 LLBit_ = false;
1960 *ptr = value;
1961 return;
1962 }
1963
writeW(uint64_t addr,int32_t value,SimInstruction * instr)1964 void Simulator::writeW(uint64_t addr, int32_t value, SimInstruction* instr) {
1965 if (handleWasmSegFault(addr, 4)) {
1966 return;
1967 }
1968
1969 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1970 LLBit_ = false;
1971 *ptr = value;
1972 return;
1973 }
1974
readDW(uint64_t addr,SimInstruction * instr)1975 int64_t Simulator::readDW(uint64_t addr, SimInstruction* instr) {
1976 if (handleWasmSegFault(addr, 8)) {
1977 return -1;
1978 }
1979
1980 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
1981 return *ptr;
1982 }
1983
writeDW(uint64_t addr,int64_t value,SimInstruction * instr)1984 void Simulator::writeDW(uint64_t addr, int64_t value, SimInstruction* instr) {
1985 if (handleWasmSegFault(addr, 8)) {
1986 return;
1987 }
1988
1989 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1990 LLBit_ = false;
1991 *ptr = value;
1992 return;
1993 }
1994
readD(uint64_t addr,SimInstruction * instr)1995 double Simulator::readD(uint64_t addr, SimInstruction* instr) {
1996 if (handleWasmSegFault(addr, 8)) {
1997 return NAN;
1998 }
1999
2000 double* ptr = reinterpret_cast<double*>(addr);
2001 return *ptr;
2002 }
2003
writeD(uint64_t addr,double value,SimInstruction * instr)2004 void Simulator::writeD(uint64_t addr, double value, SimInstruction* instr) {
2005 if (handleWasmSegFault(addr, 8)) {
2006 return;
2007 }
2008
2009 double* ptr = reinterpret_cast<double*>(addr);
2010 LLBit_ = false;
2011 *ptr = value;
2012 return;
2013 }
2014
loadLinkedW(uint64_t addr,SimInstruction * instr)2015 int Simulator::loadLinkedW(uint64_t addr, SimInstruction* instr) {
2016 if ((addr & 3) == 0) {
2017 if (handleWasmSegFault(addr, 4)) {
2018 return -1;
2019 }
2020
2021 volatile int32_t* ptr = reinterpret_cast<volatile int32_t*>(addr);
2022 int32_t value = *ptr;
2023 lastLLValue_ = value;
2024 LLAddr_ = addr;
2025 // Note that any memory write or "external" interrupt should reset this
2026 // value to false.
2027 LLBit_ = true;
2028 return value;
2029 }
2030 printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
2031 reinterpret_cast<intptr_t>(instr));
2032 MOZ_CRASH();
2033 return 0;
2034 }
2035
storeConditionalW(uint64_t addr,int value,SimInstruction * instr)2036 int Simulator::storeConditionalW(uint64_t addr, int value,
2037 SimInstruction* instr) {
2038 // Correct behavior in this case, as defined by architecture, is to just
2039 // return 0, but there is no point at allowing that. It is certainly an
2040 // indicator of a bug.
2041 if (addr != LLAddr_) {
2042 printf("SC to bad address: 0x%016" PRIx64 ", pc=0x%016" PRIx64
2043 ", expected: 0x%016" PRIx64 "\n",
2044 addr, reinterpret_cast<intptr_t>(instr), LLAddr_);
2045 MOZ_CRASH();
2046 }
2047
2048 if ((addr & 3) == 0) {
2049 SharedMem<int32_t*> ptr =
2050 SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr));
2051
2052 if (!LLBit_) {
2053 return 0;
2054 }
2055
2056 LLBit_ = false;
2057 LLAddr_ = 0;
2058 int32_t expected = int32_t(lastLLValue_);
2059 int32_t old =
2060 AtomicOperations::compareExchangeSeqCst(ptr, expected, int32_t(value));
2061 return (old == expected) ? 1 : 0;
2062 }
2063 printf("Unaligned SC at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
2064 reinterpret_cast<intptr_t>(instr));
2065 MOZ_CRASH();
2066 return 0;
2067 }
2068
loadLinkedD(uint64_t addr,SimInstruction * instr)2069 int64_t Simulator::loadLinkedD(uint64_t addr, SimInstruction* instr) {
2070 if ((addr & kPointerAlignmentMask) == 0) {
2071 if (handleWasmSegFault(addr, 8)) {
2072 return -1;
2073 }
2074
2075 volatile int64_t* ptr = reinterpret_cast<volatile int64_t*>(addr);
2076 int64_t value = *ptr;
2077 lastLLValue_ = value;
2078 LLAddr_ = addr;
2079 // Note that any memory write or "external" interrupt should reset this
2080 // value to false.
2081 LLBit_ = true;
2082 return value;
2083 }
2084 printf("Unaligned write at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
2085 reinterpret_cast<intptr_t>(instr));
2086 MOZ_CRASH();
2087 return 0;
2088 }
2089
storeConditionalD(uint64_t addr,int64_t value,SimInstruction * instr)2090 int Simulator::storeConditionalD(uint64_t addr, int64_t value,
2091 SimInstruction* instr) {
2092 // Correct behavior in this case, as defined by architecture, is to just
2093 // return 0, but there is no point at allowing that. It is certainly an
2094 // indicator of a bug.
2095 if (addr != LLAddr_) {
2096 printf("SC to bad address: 0x%016" PRIx64 ", pc=0x%016" PRIx64
2097 ", expected: 0x%016" PRIx64 "\n",
2098 addr, reinterpret_cast<intptr_t>(instr), LLAddr_);
2099 MOZ_CRASH();
2100 }
2101
2102 if ((addr & kPointerAlignmentMask) == 0) {
2103 SharedMem<int64_t*> ptr =
2104 SharedMem<int64_t*>::shared(reinterpret_cast<int64_t*>(addr));
2105
2106 if (!LLBit_) {
2107 return 0;
2108 }
2109
2110 LLBit_ = false;
2111 LLAddr_ = 0;
2112 int64_t expected = lastLLValue_;
2113 int64_t old =
2114 AtomicOperations::compareExchangeSeqCst(ptr, expected, int64_t(value));
2115 return (old == expected) ? 1 : 0;
2116 }
2117 printf("Unaligned SC at 0x%016" PRIx64 ", pc=0x%016" PRIxPTR "\n", addr,
2118 reinterpret_cast<intptr_t>(instr));
2119 MOZ_CRASH();
2120 return 0;
2121 }
2122
stackLimit() const2123 uintptr_t Simulator::stackLimit() const { return stackLimit_; }
2124
addressOfStackLimit()2125 uintptr_t* Simulator::addressOfStackLimit() { return &stackLimit_; }
2126
overRecursed(uintptr_t newsp) const2127 bool Simulator::overRecursed(uintptr_t newsp) const {
2128 if (newsp == 0) {
2129 newsp = getRegister(sp);
2130 }
2131 return newsp <= stackLimit();
2132 }
2133
overRecursedWithExtra(uint32_t extra) const2134 bool Simulator::overRecursedWithExtra(uint32_t extra) const {
2135 uintptr_t newsp = getRegister(sp) - extra;
2136 return newsp <= stackLimit();
2137 }
2138
2139 // Unsupported instructions use format to print an error and stop execution.
format(SimInstruction * instr,const char * format)2140 void Simulator::format(SimInstruction* instr, const char* format) {
2141 printf("Simulator found unsupported instruction:\n 0x%016lx: %s\n",
2142 reinterpret_cast<intptr_t>(instr), format);
2143 MOZ_CRASH();
2144 }
2145
2146 // Note: With the code below we assume that all runtime calls return a 64 bits
2147 // result. If they don't, the a1 result register contains a bogus value, which
2148 // is fine because it is caller-saved.
2149 typedef int64_t (*Prototype_General0)();
2150 typedef int64_t (*Prototype_General1)(int64_t arg0);
2151 typedef int64_t (*Prototype_General2)(int64_t arg0, int64_t arg1);
2152 typedef int64_t (*Prototype_General3)(int64_t arg0, int64_t arg1, int64_t arg2);
2153 typedef int64_t (*Prototype_General4)(int64_t arg0, int64_t arg1, int64_t arg2,
2154 int64_t arg3);
2155 typedef int64_t (*Prototype_General5)(int64_t arg0, int64_t arg1, int64_t arg2,
2156 int64_t arg3, int64_t arg4);
2157 typedef int64_t (*Prototype_General6)(int64_t arg0, int64_t arg1, int64_t arg2,
2158 int64_t arg3, int64_t arg4, int64_t arg5);
2159 typedef int64_t (*Prototype_General7)(int64_t arg0, int64_t arg1, int64_t arg2,
2160 int64_t arg3, int64_t arg4, int64_t arg5,
2161 int64_t arg6);
2162 typedef int64_t (*Prototype_General8)(int64_t arg0, int64_t arg1, int64_t arg2,
2163 int64_t arg3, int64_t arg4, int64_t arg5,
2164 int64_t arg6, int64_t arg7);
2165 typedef int64_t (*Prototype_GeneralGeneralGeneralInt64)(int64_t arg0,
2166 int64_t arg1,
2167 int64_t arg2,
2168 int64_t arg3);
2169 typedef int64_t (*Prototype_GeneralGeneralInt64Int64)(int64_t arg0,
2170 int64_t arg1,
2171 int64_t arg2,
2172 int64_t arg3);
2173 typedef int64_t (*Prototype_Int_Float32)(float arg0);
2174 typedef int64_t (*Prototype_Int_Double)(double arg0);
2175 typedef int64_t (*Prototype_Int_IntDouble)(int64_t arg0, double arg1);
2176 typedef int64_t (*Prototype_Int_DoubleInt)(double arg0, int64_t arg1);
2177 typedef int64_t (*Prototype_Int_DoubleIntInt)(double arg0, int64_t arg1,
2178 int64_t arg2);
2179 typedef int64_t (*Prototype_Int_IntDoubleIntInt)(int64_t arg0, double arg1,
2180 int64_t arg2, int64_t arg3);
2181
2182 typedef float (*Prototype_Float32_Float32)(float arg0);
2183 typedef float (*Prototype_Float32_Float32Float32)(float arg0, float arg1);
2184
2185 typedef double (*Prototype_Double_None)();
2186 typedef double (*Prototype_Double_Double)(double arg0);
2187 typedef double (*Prototype_Double_Int)(int64_t arg0);
2188 typedef double (*Prototype_Double_DoubleInt)(double arg0, int64_t arg1);
2189 typedef double (*Prototype_Double_IntDouble)(int64_t arg0, double arg1);
2190 typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
2191 typedef double (*Prototype_Double_DoubleDoubleDouble)(double arg0, double arg1,
2192 double arg2);
2193 typedef double (*Prototype_Double_DoubleDoubleDoubleDouble)(double arg0,
2194 double arg1,
2195 double arg2,
2196 double arg3);
2197
2198 typedef int32_t (*Prototype_Int32_General)(int64_t);
2199 typedef int32_t (*Prototype_Int32_GeneralInt32)(int64_t, int32_t);
2200 typedef int32_t (*Prototype_Int32_GeneralInt32Int32)(int64_t, int32_t, int32_t);
2201 typedef int32_t (*Prototype_Int32_GeneralInt32Int32Int32Int32)(int64_t, int32_t,
2202 int32_t, int32_t,
2203 int32_t);
2204 typedef int32_t (*Prototype_Int32_GeneralInt32Int32Int32Int32Int32)(
2205 int64_t, int32_t, int32_t, int32_t, int32_t, int32_t);
2206 typedef int32_t (*Prototype_Int32_GeneralInt32Int32Int32Int32General)(
2207 int64_t, int32_t, int32_t, int32_t, int32_t, int64_t);
2208 typedef int32_t (*Prototype_Int32_GeneralInt32Int32Int32General)(
2209 int64_t, int32_t, int32_t, int32_t, int64_t);
2210 typedef int32_t (*Prototype_Int32_GeneralInt32Int32Int64)(int64_t, int32_t,
2211 int32_t, int64_t);
2212 typedef int32_t (*Prototype_Int32_GeneralInt32Int32General)(int64_t, int32_t,
2213 int32_t, int64_t);
2214 typedef int32_t (*Prototype_Int32_GeneralInt32Int64Int64)(int64_t, int32_t,
2215 int64_t, int64_t);
2216 typedef int32_t (*Prototype_Int32_GeneralInt32GeneralInt32)(int64_t, int32_t,
2217 int64_t, int32_t);
2218 typedef int32_t (*Prototype_Int32_GeneralInt32GeneralInt32Int32)(
2219 int64_t, int32_t, int64_t, int32_t, int32_t);
2220 typedef int32_t (*Prototype_Int32_GeneralGeneral)(int64_t, int64_t);
2221 typedef int32_t (*Prototype_Int32_GeneralGeneralGeneral)(int64_t, int64_t,
2222 int64_t);
2223 typedef int32_t (*Prototype_Int32_GeneralGeneralInt32Int32)(int64_t, int64_t,
2224 int32_t, int32_t);
2225 typedef int32_t (*Prototype_Int32_GeneralInt64Int32Int32Int32)(int64_t, int64_t,
2226 int32_t, int32_t,
2227 int32_t);
2228 typedef int32_t (*Prototype_Int32_GeneralInt64Int32)(int64_t, int64_t, int32_t);
2229 typedef int32_t (*Prototype_Int32_GeneralInt64Int32Int64)(int64_t, int64_t,
2230 int32_t, int64_t);
2231 typedef int32_t (*Prototype_Int32_GeneralInt64Int32Int64General)(
2232 int64_t, int64_t, int32_t, int64_t, int64_t);
2233 typedef int32_t (*Prototype_Int32_GeneralInt64Int64Int64)(int64_t, int64_t,
2234 int64_t, int64_t);
2235 typedef int32_t (*Prototype_Int32_GeneralInt64Int64Int64General)(
2236 int64_t, int64_t, int64_t, int64_t, int64_t);
2237 typedef int64_t (*Prototype_General_GeneralInt32)(int64_t, int32_t);
2238 typedef int64_t (*Prototype_General_GeneralInt32Int32)(int64_t, int32_t,
2239 int32_t);
2240 typedef int64_t (*Prototype_General_GeneralInt32General)(int64_t, int32_t,
2241 int64_t);
2242 typedef int64_t (*Prototype_Int64_General)(int64_t);
2243 typedef int64_t (*Prototype_Int64_GeneralInt64)(int64_t, int64_t);
2244
rj_reg(SimInstruction * instr) const2245 inline int32_t Simulator::rj_reg(SimInstruction* instr) const {
2246 return instr->rjValue();
2247 }
2248
rj(SimInstruction * instr) const2249 inline int64_t Simulator::rj(SimInstruction* instr) const {
2250 return getRegister(rj_reg(instr));
2251 }
2252
rj_u(SimInstruction * instr) const2253 inline uint64_t Simulator::rj_u(SimInstruction* instr) const {
2254 return static_cast<uint64_t>(getRegister(rj_reg(instr)));
2255 }
2256
rk_reg(SimInstruction * instr) const2257 inline int32_t Simulator::rk_reg(SimInstruction* instr) const {
2258 return instr->rkValue();
2259 }
2260
rk(SimInstruction * instr) const2261 inline int64_t Simulator::rk(SimInstruction* instr) const {
2262 return getRegister(rk_reg(instr));
2263 }
2264
rk_u(SimInstruction * instr) const2265 inline uint64_t Simulator::rk_u(SimInstruction* instr) const {
2266 return static_cast<uint64_t>(getRegister(rk_reg(instr)));
2267 }
2268
rd_reg(SimInstruction * instr) const2269 inline int32_t Simulator::rd_reg(SimInstruction* instr) const {
2270 return instr->rdValue();
2271 }
2272
rd(SimInstruction * instr) const2273 inline int64_t Simulator::rd(SimInstruction* instr) const {
2274 return getRegister(rd_reg(instr));
2275 }
2276
rd_u(SimInstruction * instr) const2277 inline uint64_t Simulator::rd_u(SimInstruction* instr) const {
2278 return static_cast<uint64_t>(getRegister(rd_reg(instr)));
2279 }
2280
fa_reg(SimInstruction * instr) const2281 inline int32_t Simulator::fa_reg(SimInstruction* instr) const {
2282 return instr->faValue();
2283 }
2284
fa_float(SimInstruction * instr) const2285 inline float Simulator::fa_float(SimInstruction* instr) const {
2286 return getFpuRegisterFloat(fa_reg(instr));
2287 }
2288
fa_double(SimInstruction * instr) const2289 inline double Simulator::fa_double(SimInstruction* instr) const {
2290 return getFpuRegisterDouble(fa_reg(instr));
2291 }
2292
fj_reg(SimInstruction * instr) const2293 inline int32_t Simulator::fj_reg(SimInstruction* instr) const {
2294 return instr->fjValue();
2295 }
2296
fj_float(SimInstruction * instr) const2297 inline float Simulator::fj_float(SimInstruction* instr) const {
2298 return getFpuRegisterFloat(fj_reg(instr));
2299 }
2300
fj_double(SimInstruction * instr) const2301 inline double Simulator::fj_double(SimInstruction* instr) const {
2302 return getFpuRegisterDouble(fj_reg(instr));
2303 }
2304
fk_reg(SimInstruction * instr) const2305 inline int32_t Simulator::fk_reg(SimInstruction* instr) const {
2306 return instr->fkValue();
2307 }
2308
fk_float(SimInstruction * instr) const2309 inline float Simulator::fk_float(SimInstruction* instr) const {
2310 return getFpuRegisterFloat(fk_reg(instr));
2311 }
2312
fk_double(SimInstruction * instr) const2313 inline double Simulator::fk_double(SimInstruction* instr) const {
2314 return getFpuRegisterDouble(fk_reg(instr));
2315 }
2316
fd_reg(SimInstruction * instr) const2317 inline int32_t Simulator::fd_reg(SimInstruction* instr) const {
2318 return instr->fdValue();
2319 }
2320
fd_float(SimInstruction * instr) const2321 inline float Simulator::fd_float(SimInstruction* instr) const {
2322 return getFpuRegisterFloat(fd_reg(instr));
2323 }
2324
fd_double(SimInstruction * instr) const2325 inline double Simulator::fd_double(SimInstruction* instr) const {
2326 return getFpuRegisterDouble(fd_reg(instr));
2327 }
2328
cj_reg(SimInstruction * instr) const2329 inline int32_t Simulator::cj_reg(SimInstruction* instr) const {
2330 return instr->cjValue();
2331 }
2332
cj(SimInstruction * instr) const2333 inline bool Simulator::cj(SimInstruction* instr) const {
2334 return getCFRegister(cj_reg(instr));
2335 }
2336
cd_reg(SimInstruction * instr) const2337 inline int32_t Simulator::cd_reg(SimInstruction* instr) const {
2338 return instr->cdValue();
2339 }
2340
cd(SimInstruction * instr) const2341 inline bool Simulator::cd(SimInstruction* instr) const {
2342 return getCFRegister(cd_reg(instr));
2343 }
2344
ca_reg(SimInstruction * instr) const2345 inline int32_t Simulator::ca_reg(SimInstruction* instr) const {
2346 return instr->caValue();
2347 }
2348
ca(SimInstruction * instr) const2349 inline bool Simulator::ca(SimInstruction* instr) const {
2350 return getCFRegister(ca_reg(instr));
2351 }
2352
sa2(SimInstruction * instr) const2353 inline uint32_t Simulator::sa2(SimInstruction* instr) const {
2354 return instr->sa2Value();
2355 }
2356
sa3(SimInstruction * instr) const2357 inline uint32_t Simulator::sa3(SimInstruction* instr) const {
2358 return instr->sa3Value();
2359 }
2360
ui5(SimInstruction * instr) const2361 inline uint32_t Simulator::ui5(SimInstruction* instr) const {
2362 return instr->imm5Value();
2363 }
2364
ui6(SimInstruction * instr) const2365 inline uint32_t Simulator::ui6(SimInstruction* instr) const {
2366 return instr->imm6Value();
2367 }
2368
lsbw(SimInstruction * instr) const2369 inline uint32_t Simulator::lsbw(SimInstruction* instr) const {
2370 return instr->lsbwValue();
2371 }
2372
msbw(SimInstruction * instr) const2373 inline uint32_t Simulator::msbw(SimInstruction* instr) const {
2374 return instr->msbwValue();
2375 }
2376
lsbd(SimInstruction * instr) const2377 inline uint32_t Simulator::lsbd(SimInstruction* instr) const {
2378 return instr->lsbdValue();
2379 }
2380
msbd(SimInstruction * instr) const2381 inline uint32_t Simulator::msbd(SimInstruction* instr) const {
2382 return instr->msbdValue();
2383 }
2384
cond(SimInstruction * instr) const2385 inline uint32_t Simulator::cond(SimInstruction* instr) const {
2386 return instr->condValue();
2387 }
2388
si12(SimInstruction * instr) const2389 inline int32_t Simulator::si12(SimInstruction* instr) const {
2390 return (instr->imm12Value() << 20) >> 20;
2391 }
2392
ui12(SimInstruction * instr) const2393 inline uint32_t Simulator::ui12(SimInstruction* instr) const {
2394 return instr->imm12Value();
2395 }
2396
si14(SimInstruction * instr) const2397 inline int32_t Simulator::si14(SimInstruction* instr) const {
2398 return (instr->imm14Value() << 18) >> 18;
2399 }
2400
si16(SimInstruction * instr) const2401 inline int32_t Simulator::si16(SimInstruction* instr) const {
2402 return (instr->imm16Value() << 16) >> 16;
2403 }
2404
si20(SimInstruction * instr) const2405 inline int32_t Simulator::si20(SimInstruction* instr) const {
2406 return (instr->imm20Value() << 12) >> 12;
2407 }
2408
2409 // Software interrupt instructions are used by the simulator to call into C++.
softwareInterrupt(SimInstruction * instr)2410 void Simulator::softwareInterrupt(SimInstruction* instr) {
2411 // the break_ instruction could get us here.
2412 mozilla::DebugOnly<int32_t> opcode_hi15 = instr->bits(31, 17);
2413 MOZ_ASSERT(opcode_hi15 == 0x15);
2414 uint32_t code = instr->bits(14, 0);
2415
2416 if (instr->instructionBits() == kCallRedirInstr) {
2417 Redirection* redirection = Redirection::FromSwiInstruction(instr);
2418 uintptr_t nativeFn =
2419 reinterpret_cast<uintptr_t>(redirection->nativeFunction());
2420
2421 int64_t arg0 = getRegister(a0);
2422 int64_t arg1 = getRegister(a1);
2423 int64_t arg2 = getRegister(a2);
2424 int64_t arg3 = getRegister(a3);
2425 int64_t arg4 = getRegister(a4);
2426 int64_t arg5 = getRegister(a5);
2427
2428 // This is dodgy but it works because the C entry stubs are never moved.
2429 // See comment in codegen-arm.cc and bug 1242173.
2430 int64_t saved_ra = getRegister(ra);
2431
2432 intptr_t external =
2433 reinterpret_cast<intptr_t>(redirection->nativeFunction());
2434
2435 bool stack_aligned = (getRegister(sp) & (ABIStackAlignment - 1)) == 0;
2436 if (!stack_aligned) {
2437 fprintf(stderr, "Runtime call with unaligned stack!\n");
2438 MOZ_CRASH();
2439 }
2440
2441 if (single_stepping_) {
2442 single_step_callback_(single_step_callback_arg_, this, nullptr);
2443 }
2444
2445 switch (redirection->type()) {
2446 case Args_General0: {
2447 Prototype_General0 target =
2448 reinterpret_cast<Prototype_General0>(external);
2449 int64_t result = target();
2450 setCallResult(result);
2451 break;
2452 }
2453 case Args_General1: {
2454 Prototype_General1 target =
2455 reinterpret_cast<Prototype_General1>(external);
2456 int64_t result = target(arg0);
2457 setCallResult(result);
2458 break;
2459 }
2460 case Args_General2: {
2461 Prototype_General2 target =
2462 reinterpret_cast<Prototype_General2>(external);
2463 int64_t result = target(arg0, arg1);
2464 setCallResult(result);
2465 break;
2466 }
2467 case Args_General3: {
2468 Prototype_General3 target =
2469 reinterpret_cast<Prototype_General3>(external);
2470 int64_t result = target(arg0, arg1, arg2);
2471 if (external == intptr_t(&js::wasm::Instance::wake_m32)) {
2472 result = int32_t(result);
2473 }
2474 setCallResult(result);
2475 break;
2476 }
2477 case Args_General4: {
2478 Prototype_General4 target =
2479 reinterpret_cast<Prototype_General4>(external);
2480 int64_t result = target(arg0, arg1, arg2, arg3);
2481 setCallResult(result);
2482 break;
2483 }
2484 case Args_General5: {
2485 Prototype_General5 target =
2486 reinterpret_cast<Prototype_General5>(external);
2487 int64_t result = target(arg0, arg1, arg2, arg3, arg4);
2488 setCallResult(result);
2489 break;
2490 }
2491 case Args_General6: {
2492 Prototype_General6 target =
2493 reinterpret_cast<Prototype_General6>(external);
2494 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
2495 setCallResult(result);
2496 break;
2497 }
2498 case Args_General7: {
2499 Prototype_General7 target =
2500 reinterpret_cast<Prototype_General7>(external);
2501 int64_t arg6 = getRegister(a6);
2502 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
2503 setCallResult(result);
2504 break;
2505 }
2506 case Args_General8: {
2507 Prototype_General8 target =
2508 reinterpret_cast<Prototype_General8>(external);
2509 int64_t arg6 = getRegister(a6);
2510 int64_t arg7 = getRegister(a7);
2511 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
2512 setCallResult(result);
2513 break;
2514 }
2515 case Args_Double_None: {
2516 Prototype_Double_None target =
2517 reinterpret_cast<Prototype_Double_None>(external);
2518 double dresult = target();
2519 setCallResultDouble(dresult);
2520 break;
2521 }
2522 case Args_Int_Float32: {
2523 float fval0;
2524 fval0 = getFpuRegisterFloat(0);
2525 Prototype_Int_Float32 target =
2526 reinterpret_cast<Prototype_Int_Float32>(external);
2527 int64_t result = target(fval0);
2528 setRegister(a0, result);
2529 break;
2530 }
2531 case Args_Int_Double: {
2532 double dval0 = getFpuRegisterDouble(0);
2533 Prototype_Int_Double target =
2534 reinterpret_cast<Prototype_Int_Double>(external);
2535 int64_t result = target(dval0);
2536 if (external == intptr_t((int32_t(*)(double))JS::ToInt32)) {
2537 result = int32_t(result);
2538 }
2539 setRegister(a0, result);
2540 break;
2541 }
2542 case Args_Int_GeneralGeneralGeneralInt64: {
2543 Prototype_GeneralGeneralGeneralInt64 target =
2544 reinterpret_cast<Prototype_GeneralGeneralGeneralInt64>(external);
2545 int64_t result = target(arg0, arg1, arg2, arg3);
2546 if (external == intptr_t(&js::wasm::Instance::wait_i32_m32)) {
2547 result = int32_t(result);
2548 }
2549 setRegister(a0, result);
2550 break;
2551 }
2552 case Args_Int_GeneralGeneralInt64Int64: {
2553 Prototype_GeneralGeneralInt64Int64 target =
2554 reinterpret_cast<Prototype_GeneralGeneralInt64Int64>(external);
2555 int64_t result = target(arg0, arg1, arg2, arg3);
2556 if (external == intptr_t(&js::wasm::Instance::wait_i64_m32)) {
2557 result = int32_t(result);
2558 }
2559 setRegister(a0, result);
2560 break;
2561 }
2562 case Args_Int_DoubleInt: {
2563 double dval = getFpuRegisterDouble(0);
2564 Prototype_Int_DoubleInt target =
2565 reinterpret_cast<Prototype_Int_DoubleInt>(external);
2566 int64_t result = target(dval, arg0);
2567 setRegister(a0, result);
2568 break;
2569 }
2570 case Args_Int_DoubleIntInt: {
2571 double dval = getFpuRegisterDouble(0);
2572 Prototype_Int_DoubleIntInt target =
2573 reinterpret_cast<Prototype_Int_DoubleIntInt>(external);
2574 int64_t result = target(dval, arg0, arg1);
2575 setRegister(a0, result);
2576 break;
2577 }
2578 case Args_Int_IntDoubleIntInt: {
2579 double dval = getFpuRegisterDouble(0);
2580 Prototype_Int_IntDoubleIntInt target =
2581 reinterpret_cast<Prototype_Int_IntDoubleIntInt>(external);
2582 int64_t result = target(arg0, dval, arg1, arg2);
2583 setRegister(a0, result);
2584 break;
2585 }
2586 case Args_Double_Double: {
2587 double dval0 = getFpuRegisterDouble(0);
2588 Prototype_Double_Double target =
2589 reinterpret_cast<Prototype_Double_Double>(external);
2590 double dresult = target(dval0);
2591 setCallResultDouble(dresult);
2592 break;
2593 }
2594 case Args_Float32_Float32: {
2595 float fval0;
2596 fval0 = getFpuRegisterFloat(0);
2597 Prototype_Float32_Float32 target =
2598 reinterpret_cast<Prototype_Float32_Float32>(external);
2599 float fresult = target(fval0);
2600 setCallResultFloat(fresult);
2601 break;
2602 }
2603 case Args_Float32_Float32Float32: {
2604 float fval0;
2605 float fval1;
2606 fval0 = getFpuRegisterFloat(0);
2607 fval1 = getFpuRegisterFloat(1);
2608 Prototype_Float32_Float32Float32 target =
2609 reinterpret_cast<Prototype_Float32_Float32Float32>(external);
2610 float fresult = target(fval0, fval1);
2611 setCallResultFloat(fresult);
2612 break;
2613 }
2614 case Args_Double_Int: {
2615 Prototype_Double_Int target =
2616 reinterpret_cast<Prototype_Double_Int>(external);
2617 double dresult = target(arg0);
2618 setCallResultDouble(dresult);
2619 break;
2620 }
2621 case Args_Double_DoubleInt: {
2622 double dval0 = getFpuRegisterDouble(0);
2623 Prototype_Double_DoubleInt target =
2624 reinterpret_cast<Prototype_Double_DoubleInt>(external);
2625 double dresult = target(dval0, arg0);
2626 setCallResultDouble(dresult);
2627 break;
2628 }
2629 case Args_Double_DoubleDouble: {
2630 double dval0 = getFpuRegisterDouble(0);
2631 double dval1 = getFpuRegisterDouble(1);
2632 Prototype_Double_DoubleDouble target =
2633 reinterpret_cast<Prototype_Double_DoubleDouble>(external);
2634 double dresult = target(dval0, dval1);
2635 setCallResultDouble(dresult);
2636 break;
2637 }
2638 case Args_Double_IntDouble: {
2639 double dval0 = getFpuRegisterDouble(0);
2640 Prototype_Double_IntDouble target =
2641 reinterpret_cast<Prototype_Double_IntDouble>(external);
2642 double dresult = target(arg0, dval0);
2643 setCallResultDouble(dresult);
2644 break;
2645 }
2646 case Args_Int_IntDouble: {
2647 double dval0 = getFpuRegisterDouble(0);
2648 Prototype_Int_IntDouble target =
2649 reinterpret_cast<Prototype_Int_IntDouble>(external);
2650 int64_t result = target(arg0, dval0);
2651 setRegister(a0, result);
2652 break;
2653 }
2654 case Args_Double_DoubleDoubleDouble: {
2655 double dval0 = getFpuRegisterDouble(0);
2656 double dval1 = getFpuRegisterDouble(1);
2657 double dval2 = getFpuRegisterDouble(2);
2658 Prototype_Double_DoubleDoubleDouble target =
2659 reinterpret_cast<Prototype_Double_DoubleDoubleDouble>(external);
2660 double dresult = target(dval0, dval1, dval2);
2661 setCallResultDouble(dresult);
2662 break;
2663 }
2664 case Args_Double_DoubleDoubleDoubleDouble: {
2665 double dval0 = getFpuRegisterDouble(0);
2666 double dval1 = getFpuRegisterDouble(1);
2667 double dval2 = getFpuRegisterDouble(2);
2668 double dval3 = getFpuRegisterDouble(3);
2669 Prototype_Double_DoubleDoubleDoubleDouble target =
2670 reinterpret_cast<Prototype_Double_DoubleDoubleDoubleDouble>(
2671 external);
2672 double dresult = target(dval0, dval1, dval2, dval3);
2673 setCallResultDouble(dresult);
2674 break;
2675 }
2676 case Args_Int32_General: {
2677 int32_t ret = reinterpret_cast<Prototype_Int32_General>(nativeFn)(arg0);
2678 setRegister(a0, I64(ret));
2679 break;
2680 }
2681 case Args_Int32_GeneralInt32: {
2682 int32_t ret = reinterpret_cast<Prototype_Int32_GeneralInt32>(nativeFn)(
2683 arg0, I32(arg1));
2684 setRegister(a0, I64(ret));
2685 break;
2686 }
2687 case Args_Int32_GeneralInt32Int32: {
2688 int32_t ret = reinterpret_cast<Prototype_Int32_GeneralInt32Int32>(
2689 nativeFn)(arg0, I32(arg1), I32(arg2));
2690 setRegister(a0, I64(ret));
2691 break;
2692 }
2693 case Args_Int32_GeneralInt32Int32Int32Int32: {
2694 int32_t ret =
2695 reinterpret_cast<Prototype_Int32_GeneralInt32Int32Int32Int32>(
2696 nativeFn)(arg0, I32(arg1), I32(arg2), I32(arg3), I32(arg4));
2697 setRegister(a0, I64(ret));
2698 break;
2699 }
2700 case Args_Int32_GeneralInt32Int32Int32Int32Int32: {
2701 int32_t ret =
2702 reinterpret_cast<Prototype_Int32_GeneralInt32Int32Int32Int32Int32>(
2703 nativeFn)(arg0, I32(arg1), I32(arg2), I32(arg3), I32(arg4),
2704 I32(arg5));
2705 setRegister(a0, I64(ret));
2706 break;
2707 }
2708 case Args_Int32_GeneralInt32Int32Int32Int32General: {
2709 int32_t ret = reinterpret_cast<
2710 Prototype_Int32_GeneralInt32Int32Int32Int32General>(nativeFn)(
2711 arg0, I32(arg1), I32(arg2), I32(arg3), I32(arg4), arg5);
2712 setRegister(a0, I64(ret));
2713 break;
2714 }
2715 case Args_Int32_GeneralInt32Int32Int32General: {
2716 int32_t ret =
2717 reinterpret_cast<Prototype_Int32_GeneralInt32Int32Int32General>(
2718 nativeFn)(arg0, I32(arg1), I32(arg2), I32(arg3), arg4);
2719 setRegister(a0, I64(ret));
2720 break;
2721 }
2722 case Args_Int32_GeneralInt32Int32Int64: {
2723 int32_t ret = reinterpret_cast<Prototype_Int32_GeneralInt32Int32Int64>(
2724 nativeFn)(arg0, I32(arg1), I32(arg2), arg3);
2725 setRegister(a0, I64(ret));
2726 break;
2727 }
2728 case Args_Int32_GeneralInt32Int32General: {
2729 int32_t ret =
2730 reinterpret_cast<Prototype_Int32_GeneralInt32Int32General>(
2731 nativeFn)(arg0, I32(arg1), I32(arg2), arg3);
2732 setRegister(a0, I64(ret));
2733 break;
2734 }
2735 case Args_Int32_GeneralInt32Int64Int64: {
2736 int32_t ret = reinterpret_cast<Prototype_Int32_GeneralInt32Int64Int64>(
2737 nativeFn)(arg0, I32(arg1), arg2, arg3);
2738 setRegister(a0, I64(ret));
2739 break;
2740 }
2741 case Args_Int32_GeneralInt32GeneralInt32: {
2742 int32_t ret =
2743 reinterpret_cast<Prototype_Int32_GeneralInt32GeneralInt32>(
2744 nativeFn)(arg0, I32(arg1), arg2, I32(arg3));
2745 setRegister(a0, I64(ret));
2746 break;
2747 }
2748 case Args_Int32_GeneralInt32GeneralInt32Int32: {
2749 int32_t ret =
2750 reinterpret_cast<Prototype_Int32_GeneralInt32GeneralInt32Int32>(
2751 nativeFn)(arg0, I32(arg1), arg2, I32(arg3), I32(arg4));
2752 setRegister(a0, I64(ret));
2753 break;
2754 }
2755 case Args_Int32_GeneralGeneral: {
2756 int32_t ret = reinterpret_cast<Prototype_Int32_GeneralGeneral>(
2757 nativeFn)(arg0, arg1);
2758 setRegister(a0, I64(ret));
2759 break;
2760 }
2761 case Args_Int32_GeneralGeneralGeneral: {
2762 int32_t ret = reinterpret_cast<Prototype_Int32_GeneralGeneralGeneral>(
2763 nativeFn)(arg0, arg1, arg2);
2764 setRegister(a0, I64(ret));
2765 break;
2766 }
2767 case Args_Int32_GeneralGeneralInt32Int32: {
2768 int32_t ret =
2769 reinterpret_cast<Prototype_Int32_GeneralGeneralInt32Int32>(
2770 nativeFn)(arg0, arg1, I32(arg2), I32(arg3));
2771 setRegister(a0, I64(ret));
2772 break;
2773 }
2774 case js::jit::Args_Int32_GeneralInt64Int32Int32Int32: {
2775 int32_t ret =
2776 reinterpret_cast<Prototype_Int32_GeneralInt64Int32Int32Int32>(
2777 nativeFn)(arg0, arg1, I32(arg2), I32(arg3), I32(arg4));
2778 setRegister(a0, I64(ret));
2779 break;
2780 }
2781 case js::jit::Args_Int32_GeneralInt64Int32: {
2782 int32_t ret = reinterpret_cast<Prototype_Int32_GeneralInt64Int32>(
2783 nativeFn)(arg0, arg1, I32(arg2));
2784 setRegister(a0, I64(ret));
2785 break;
2786 }
2787 case js::jit::Args_Int32_GeneralInt64Int32Int64: {
2788 int32_t ret = reinterpret_cast<Prototype_Int32_GeneralInt64Int32Int64>(
2789 nativeFn)(arg0, arg1, I32(arg2), arg3);
2790 setRegister(a0, I64(ret));
2791 break;
2792 }
2793 case js::jit::Args_Int32_GeneralInt64Int32Int64General: {
2794 int32_t ret =
2795 reinterpret_cast<Prototype_Int32_GeneralInt64Int32Int64General>(
2796 nativeFn)(arg0, arg1, I32(arg2), arg3, arg4);
2797 setRegister(a0, I64(ret));
2798 break;
2799 }
2800 case js::jit::Args_Int32_GeneralInt64Int64Int64: {
2801 int32_t ret = reinterpret_cast<Prototype_Int32_GeneralInt64Int64Int64>(
2802 nativeFn)(arg0, arg1, arg2, arg3);
2803 setRegister(a0, I64(ret));
2804 break;
2805 }
2806 case js::jit::Args_Int32_GeneralInt64Int64Int64General: {
2807 int32_t ret =
2808 reinterpret_cast<Prototype_Int32_GeneralInt64Int64Int64General>(
2809 nativeFn)(arg0, arg1, arg2, arg3, arg4);
2810 setRegister(a0, I64(ret));
2811 break;
2812 }
2813 case Args_General_GeneralInt32: {
2814 int64_t ret = reinterpret_cast<Prototype_General_GeneralInt32>(
2815 nativeFn)(arg0, I32(arg1));
2816 setRegister(a0, ret);
2817 break;
2818 }
2819 case Args_General_GeneralInt32Int32: {
2820 int64_t ret = reinterpret_cast<Prototype_General_GeneralInt32Int32>(
2821 nativeFn)(arg0, I32(arg1), I32(arg2));
2822 setRegister(a0, ret);
2823 break;
2824 }
2825 case Args_General_GeneralInt32General: {
2826 int64_t ret = reinterpret_cast<Prototype_General_GeneralInt32General>(
2827 nativeFn)(arg0, I32(arg1), arg2);
2828 setRegister(a0, ret);
2829 break;
2830 }
2831 case js::jit::Args_Int64_General: {
2832 int64_t ret = reinterpret_cast<Prototype_Int64_General>(nativeFn)(arg0);
2833 setRegister(a0, ret);
2834 break;
2835 }
2836 case js::jit::Args_Int64_GeneralInt64: {
2837 int64_t ret = reinterpret_cast<Prototype_Int64_GeneralInt64>(nativeFn)(
2838 arg0, arg1);
2839 setRegister(a0, ret);
2840 break;
2841 }
2842 default:
2843 MOZ_CRASH("Unknown function type.");
2844 }
2845
2846 if (single_stepping_) {
2847 single_step_callback_(single_step_callback_arg_, this, nullptr);
2848 }
2849
2850 setRegister(ra, saved_ra);
2851 set_pc(getRegister(ra));
2852 } else if ((instr->bits(31, 15) << 15 == op_break) && code == kWasmTrapCode) {
2853 uint8_t* newPC;
2854 if (wasm::HandleIllegalInstruction(registerState(), &newPC)) {
2855 set_pc(int64_t(newPC));
2856 return;
2857 }
2858 } else if ((instr->bits(31, 15) << 15 == op_break) && code <= kMaxStopCode &&
2859 code != 6) {
2860 if (isWatchpoint(code)) {
2861 // printWatchpoint(code);
2862 } else {
2863 increaseStopCounter(code);
2864 handleStop(code, instr);
2865 }
2866 } else {
2867 // All remaining break_ codes, and all traps are handled here.
2868 loong64Debugger dbg(this);
2869 dbg.debug();
2870 }
2871 }
2872
2873 // Stop helper functions.
isWatchpoint(uint32_t code)2874 bool Simulator::isWatchpoint(uint32_t code) {
2875 return (code <= kMaxWatchpointCode);
2876 }
2877
printWatchpoint(uint32_t code)2878 void Simulator::printWatchpoint(uint32_t code) {
2879 loong64Debugger dbg(this);
2880 ++break_count_;
2881 printf("\n---- break %d marker: %20" PRIi64 " (instr count: %20" PRIi64
2882 ") ----\n",
2883 code, break_count_, icount_);
2884 dbg.printAllRegs(); // Print registers and continue running.
2885 }
2886
handleStop(uint32_t code,SimInstruction * instr)2887 void Simulator::handleStop(uint32_t code, SimInstruction* instr) {
2888 // Stop if it is enabled, otherwise go on jumping over the stop
2889 // and the message address.
2890 if (isEnabledStop(code)) {
2891 loong64Debugger dbg(this);
2892 dbg.stop(instr);
2893 } else {
2894 set_pc(get_pc() + 1 * SimInstruction::kInstrSize);
2895 }
2896 }
2897
isStopInstruction(SimInstruction * instr)2898 bool Simulator::isStopInstruction(SimInstruction* instr) {
2899 int32_t opcode_hi15 = instr->bits(31, 17);
2900 uint32_t code = static_cast<uint32_t>(instr->bits(14, 0));
2901 return (opcode_hi15 == 0x15) && code > kMaxWatchpointCode &&
2902 code <= kMaxStopCode;
2903 }
2904
isEnabledStop(uint32_t code)2905 bool Simulator::isEnabledStop(uint32_t code) {
2906 MOZ_ASSERT(code <= kMaxStopCode);
2907 MOZ_ASSERT(code > kMaxWatchpointCode);
2908 return !(watchedStops_[code].count_ & kStopDisabledBit);
2909 }
2910
enableStop(uint32_t code)2911 void Simulator::enableStop(uint32_t code) {
2912 if (!isEnabledStop(code)) {
2913 watchedStops_[code].count_ &= ~kStopDisabledBit;
2914 }
2915 }
2916
disableStop(uint32_t code)2917 void Simulator::disableStop(uint32_t code) {
2918 if (isEnabledStop(code)) {
2919 watchedStops_[code].count_ |= kStopDisabledBit;
2920 }
2921 }
2922
increaseStopCounter(uint32_t code)2923 void Simulator::increaseStopCounter(uint32_t code) {
2924 MOZ_ASSERT(code <= kMaxStopCode);
2925 if ((watchedStops_[code].count_ & ~(1 << 31)) == 0x7fffffff) {
2926 printf(
2927 "Stop counter for code %i has overflowed.\n"
2928 "Enabling this code and reseting the counter to 0.\n",
2929 code);
2930 watchedStops_[code].count_ = 0;
2931 enableStop(code);
2932 } else {
2933 watchedStops_[code].count_++;
2934 }
2935 }
2936
2937 // Print a stop status.
printStopInfo(uint32_t code)2938 void Simulator::printStopInfo(uint32_t code) {
2939 if (code <= kMaxWatchpointCode) {
2940 printf("That is a watchpoint, not a stop.\n");
2941 return;
2942 } else if (code > kMaxStopCode) {
2943 printf("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
2944 return;
2945 }
2946 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
2947 int32_t count = watchedStops_[code].count_ & ~kStopDisabledBit;
2948 // Don't print the state of unused breakpoints.
2949 if (count != 0) {
2950 if (watchedStops_[code].desc_) {
2951 printf("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", code, code, state,
2952 count, watchedStops_[code].desc_);
2953 } else {
2954 printf("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state,
2955 count);
2956 }
2957 }
2958 }
2959
signalExceptions()2960 void Simulator::signalExceptions() {
2961 for (int i = 1; i < kNumExceptions; i++) {
2962 if (exceptions[i] != 0) {
2963 MOZ_CRASH("Error: Exception raised.");
2964 }
2965 }
2966 }
2967
2968 // ReverseBits(value) returns |value| in reverse bit order.
2969 template <typename T>
ReverseBits(T value)2970 T ReverseBits(T value) {
2971 MOZ_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
2972 (sizeof(value) == 4) || (sizeof(value) == 8));
2973 T result = 0;
2974 for (unsigned i = 0; i < (sizeof(value) * 8); i++) {
2975 result = (result << 1) | (value & 1);
2976 value >>= 1;
2977 }
2978 return result;
2979 }
2980
2981 // Min/Max template functions for Double and Single arguments.
2982
2983 template <typename T>
2984 static T FPAbs(T a);
2985
2986 template <>
FPAbs(double a)2987 double FPAbs<double>(double a) {
2988 return fabs(a);
2989 }
2990
2991 template <>
FPAbs(float a)2992 float FPAbs<float>(float a) {
2993 return fabsf(a);
2994 }
2995
2996 enum class MaxMinKind : int { kMin = 0, kMax = 1 };
2997
2998 template <typename T>
FPUProcessNaNsAndZeros(T a,T b,MaxMinKind kind,T * result)2999 static bool FPUProcessNaNsAndZeros(T a, T b, MaxMinKind kind, T* result) {
3000 if (std::isnan(a) && std::isnan(b)) {
3001 *result = a;
3002 } else if (std::isnan(a)) {
3003 *result = b;
3004 } else if (std::isnan(b)) {
3005 *result = a;
3006 } else if (b == a) {
3007 // Handle -0.0 == 0.0 case.
3008 // std::signbit() returns int 0 or 1 so subtracting MaxMinKind::kMax
3009 // negates the result.
3010 *result = std::signbit(b) - static_cast<int>(kind) ? b : a;
3011 } else {
3012 return false;
3013 }
3014 return true;
3015 }
3016
3017 template <typename T>
FPUMin(T a,T b)3018 static T FPUMin(T a, T b) {
3019 T result;
3020 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
3021 return result;
3022 } else {
3023 return b < a ? b : a;
3024 }
3025 }
3026
3027 template <typename T>
FPUMax(T a,T b)3028 static T FPUMax(T a, T b) {
3029 T result;
3030 if (FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMax, &result)) {
3031 return result;
3032 } else {
3033 return b > a ? b : a;
3034 }
3035 }
3036
3037 template <typename T>
FPUMinA(T a,T b)3038 static T FPUMinA(T a, T b) {
3039 T result;
3040 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
3041 if (FPAbs(a) < FPAbs(b)) {
3042 result = a;
3043 } else if (FPAbs(b) < FPAbs(a)) {
3044 result = b;
3045 } else {
3046 result = a < b ? a : b;
3047 }
3048 }
3049 return result;
3050 }
3051
3052 template <typename T>
FPUMaxA(T a,T b)3053 static T FPUMaxA(T a, T b) {
3054 T result;
3055 if (!FPUProcessNaNsAndZeros(a, b, MaxMinKind::kMin, &result)) {
3056 if (FPAbs(a) > FPAbs(b)) {
3057 result = a;
3058 } else if (FPAbs(b) > FPAbs(a)) {
3059 result = b;
3060 } else {
3061 result = a > b ? a : b;
3062 }
3063 }
3064 return result;
3065 }
3066
3067 enum class KeepSign : bool { no = false, yes };
3068
3069 // Handle execution based on instruction types.
3070 // decodeTypeImmediate
decodeTypeOp6(SimInstruction * instr)3071 void Simulator::decodeTypeOp6(SimInstruction* instr) {
3072 // Next pc.
3073 int64_t next_pc = bad_ra;
3074
3075 // Used for memory instructions.
3076 int64_t alu_out = 0;
3077
3078 // Branch instructions common part.
3079 auto BranchAndLinkHelper = [this, &next_pc](SimInstruction* instr) {
3080 int64_t current_pc = get_pc();
3081 setRegister(ra, current_pc + SimInstruction::kInstrSize);
3082 int32_t offs26_low16 =
3083 static_cast<uint32_t>(instr->bits(25, 10) << 16) >> 16;
3084 int32_t offs26_high10 = static_cast<int32_t>(instr->bits(9, 0) << 22) >> 6;
3085 int32_t offs26 = offs26_low16 | offs26_high10;
3086 next_pc = current_pc + (offs26 << 2);
3087 set_pc(next_pc);
3088 };
3089
3090 auto BranchOff16Helper = [this, &next_pc](SimInstruction* instr,
3091 bool do_branch) {
3092 int64_t current_pc = get_pc();
3093 int32_t offs16 = static_cast<int32_t>(instr->bits(25, 10) << 16) >> 16;
3094 int32_t offs = do_branch ? (offs16 << 2) : SimInstruction::kInstrSize;
3095 next_pc = current_pc + offs;
3096 set_pc(next_pc);
3097 };
3098
3099 auto BranchOff21Helper = [this, &next_pc](SimInstruction* instr,
3100 bool do_branch) {
3101 int64_t current_pc = get_pc();
3102 int32_t offs21_low16 =
3103 static_cast<uint32_t>(instr->bits(25, 10) << 16) >> 16;
3104 int32_t offs21_high5 = static_cast<int32_t>(instr->bits(4, 0) << 27) >> 11;
3105 int32_t offs = offs21_low16 | offs21_high5;
3106 offs = do_branch ? (offs << 2) : SimInstruction::kInstrSize;
3107 next_pc = current_pc + offs;
3108 set_pc(next_pc);
3109 };
3110
3111 auto BranchOff26Helper = [this, &next_pc](SimInstruction* instr) {
3112 int64_t current_pc = get_pc();
3113 int32_t offs26_low16 =
3114 static_cast<uint32_t>(instr->bits(25, 10) << 16) >> 16;
3115 int32_t offs26_high10 = static_cast<int32_t>(instr->bits(9, 0) << 22) >> 6;
3116 int32_t offs26 = offs26_low16 | offs26_high10;
3117 next_pc = current_pc + (offs26 << 2);
3118 set_pc(next_pc);
3119 };
3120
3121 auto JumpOff16Helper = [this, &next_pc](SimInstruction* instr) {
3122 int32_t offs16 = static_cast<int32_t>(instr->bits(25, 10) << 16) >> 16;
3123 setRegister(rd_reg(instr), get_pc() + SimInstruction::kInstrSize);
3124 next_pc = rj(instr) + (offs16 << 2);
3125 set_pc(next_pc);
3126 };
3127
3128 switch (instr->bits(31, 26) << 26) {
3129 case op_addu16i_d: {
3130 int32_t si16_upper = static_cast<int32_t>(si16(instr)) << 16;
3131 alu_out = static_cast<int64_t>(si16_upper) + rj(instr);
3132 setRegister(rd_reg(instr), alu_out);
3133 break;
3134 }
3135 case op_beqz: {
3136 BranchOff21Helper(instr, rj(instr) == 0);
3137 break;
3138 }
3139 case op_bnez: {
3140 BranchOff21Helper(instr, rj(instr) != 0);
3141 break;
3142 }
3143 case op_bcz: {
3144 if (instr->bits(9, 8) == 0b00) {
3145 // BCEQZ
3146 BranchOff21Helper(instr, cj(instr) == false);
3147 } else if (instr->bits(9, 8) == 0b01) {
3148 // BCNEZ
3149 BranchOff21Helper(instr, cj(instr) == true);
3150 } else {
3151 UNREACHABLE();
3152 }
3153 break;
3154 }
3155 case op_jirl: {
3156 JumpOff16Helper(instr);
3157 break;
3158 }
3159 case op_b: {
3160 BranchOff26Helper(instr);
3161 break;
3162 }
3163 case op_bl: {
3164 BranchAndLinkHelper(instr);
3165 break;
3166 }
3167 case op_beq: {
3168 BranchOff16Helper(instr, rj(instr) == rd(instr));
3169 break;
3170 }
3171 case op_bne: {
3172 BranchOff16Helper(instr, rj(instr) != rd(instr));
3173 break;
3174 }
3175 case op_blt: {
3176 BranchOff16Helper(instr, rj(instr) < rd(instr));
3177 break;
3178 }
3179 case op_bge: {
3180 BranchOff16Helper(instr, rj(instr) >= rd(instr));
3181 break;
3182 }
3183 case op_bltu: {
3184 BranchOff16Helper(instr, rj_u(instr) < rd_u(instr));
3185 break;
3186 }
3187 case op_bgeu: {
3188 BranchOff16Helper(instr, rj_u(instr) >= rd_u(instr));
3189 break;
3190 }
3191 default:
3192 UNREACHABLE();
3193 }
3194 }
3195
decodeTypeOp7(SimInstruction * instr)3196 void Simulator::decodeTypeOp7(SimInstruction* instr) {
3197 int64_t alu_out;
3198
3199 switch (instr->bits(31, 25) << 25) {
3200 case op_lu12i_w: {
3201 int32_t si20_upper = static_cast<int32_t>(si20(instr) << 12);
3202 setRegister(rd_reg(instr), static_cast<int64_t>(si20_upper));
3203 break;
3204 }
3205 case op_lu32i_d: {
3206 int32_t si20_signExtend = static_cast<int32_t>(si20(instr) << 12) >> 12;
3207 int64_t lower_32bit_mask = 0xFFFFFFFF;
3208 alu_out = (static_cast<int64_t>(si20_signExtend) << 32) |
3209 (rd(instr) & lower_32bit_mask);
3210 setRegister(rd_reg(instr), alu_out);
3211 break;
3212 }
3213 case op_pcaddi: {
3214 int32_t si20_signExtend = static_cast<int32_t>(si20(instr) << 12) >> 10;
3215 int64_t current_pc = get_pc();
3216 alu_out = static_cast<int64_t>(si20_signExtend) + current_pc;
3217 setRegister(rd_reg(instr), alu_out);
3218 break;
3219 }
3220 case op_pcalau12i: {
3221 int32_t si20_signExtend = static_cast<int32_t>(si20(instr) << 12);
3222 int64_t current_pc = get_pc();
3223 int64_t clear_lower12bit_mask = 0xFFFFFFFFFFFFF000;
3224 alu_out = static_cast<int64_t>(si20_signExtend) + current_pc;
3225 setRegister(rd_reg(instr), alu_out & clear_lower12bit_mask);
3226 break;
3227 }
3228 case op_pcaddu12i: {
3229 int32_t si20_signExtend = static_cast<int32_t>(si20(instr) << 12);
3230 int64_t current_pc = get_pc();
3231 alu_out = static_cast<int64_t>(si20_signExtend) + current_pc;
3232 setRegister(rd_reg(instr), alu_out);
3233 break;
3234 }
3235 case op_pcaddu18i: {
3236 int64_t si20_signExtend = (static_cast<int64_t>(si20(instr)) << 44) >> 26;
3237 int64_t current_pc = get_pc();
3238 alu_out = si20_signExtend + current_pc;
3239 setRegister(rd_reg(instr), alu_out);
3240 break;
3241 }
3242 default:
3243 UNREACHABLE();
3244 }
3245 }
3246
decodeTypeOp8(SimInstruction * instr)3247 void Simulator::decodeTypeOp8(SimInstruction* instr) {
3248 int64_t addr = 0x0;
3249 int64_t si14_se = (static_cast<int64_t>(si14(instr)) << 50) >> 48;
3250
3251 switch (instr->bits(31, 24) << 24) {
3252 case op_ldptr_w: {
3253 setRegister(rd_reg(instr), readW(rj(instr) + si14_se, instr));
3254 break;
3255 }
3256 case op_stptr_w: {
3257 writeW(rj(instr) + si14_se, static_cast<int32_t>(rd(instr)), instr);
3258 break;
3259 }
3260 case op_ldptr_d: {
3261 setRegister(rd_reg(instr), readDW(rj(instr) + si14_se, instr));
3262 break;
3263 }
3264 case op_stptr_d: {
3265 writeDW(rj(instr) + si14_se, rd(instr), instr);
3266 break;
3267 }
3268 case op_ll_w: {
3269 addr = si14_se + rj(instr);
3270 setRegister(rd_reg(instr), loadLinkedW(addr, instr));
3271 break;
3272 }
3273 case op_sc_w: {
3274 addr = si14_se + rj(instr);
3275 setRegister(
3276 rd_reg(instr),
3277 storeConditionalW(addr, static_cast<int32_t>(rd(instr)), instr));
3278 break;
3279 }
3280 case op_ll_d: {
3281 addr = si14_se + rj(instr);
3282 setRegister(rd_reg(instr), loadLinkedD(addr, instr));
3283 break;
3284 }
3285 case op_sc_d: {
3286 addr = si14_se + rj(instr);
3287 setRegister(rd_reg(instr), storeConditionalD(addr, rd(instr), instr));
3288 break;
3289 }
3290 default:
3291 UNREACHABLE();
3292 }
3293 }
3294
decodeTypeOp10(SimInstruction * instr)3295 void Simulator::decodeTypeOp10(SimInstruction* instr) {
3296 int64_t alu_out = 0x0;
3297 int64_t si12_se = (static_cast<int64_t>(si12(instr)) << 52) >> 52;
3298 uint64_t si12_ze = (static_cast<uint64_t>(ui12(instr)) << 52) >> 52;
3299
3300 switch (instr->bits(31, 22) << 22) {
3301 case op_bstrins_d: {
3302 uint8_t lsbd_ = lsbd(instr);
3303 uint8_t msbd_ = msbd(instr);
3304 MOZ_ASSERT(lsbd_ <= msbd_);
3305 uint8_t size = msbd_ - lsbd_ + 1;
3306 if (size < 64) {
3307 uint64_t mask = (1ULL << size) - 1;
3308 alu_out =
3309 (rd_u(instr) & ~(mask << lsbd_)) | ((rj_u(instr) & mask) << lsbd_);
3310 setRegister(rd_reg(instr), alu_out);
3311 } else if (size == 64) {
3312 setRegister(rd_reg(instr), rj(instr));
3313 }
3314 break;
3315 }
3316 case op_bstrpick_d: {
3317 uint8_t lsbd_ = lsbd(instr);
3318 uint8_t msbd_ = msbd(instr);
3319 MOZ_ASSERT(lsbd_ <= msbd_);
3320 uint8_t size = msbd_ - lsbd_ + 1;
3321 if (size < 64) {
3322 uint64_t mask = (1ULL << size) - 1;
3323 alu_out = (rj_u(instr) & (mask << lsbd_)) >> lsbd_;
3324 setRegister(rd_reg(instr), alu_out);
3325 } else if (size == 64) {
3326 setRegister(rd_reg(instr), rj(instr));
3327 }
3328 break;
3329 }
3330 case op_slti: {
3331 setRegister(rd_reg(instr), rj(instr) < si12_se ? 1 : 0);
3332 break;
3333 }
3334 case op_sltui: {
3335 setRegister(rd_reg(instr),
3336 rj_u(instr) < static_cast<uint64_t>(si12_se) ? 1 : 0);
3337 break;
3338 }
3339 case op_addi_w: {
3340 int32_t alu32_out =
3341 static_cast<int32_t>(rj(instr)) + static_cast<int32_t>(si12_se);
3342 setRegister(rd_reg(instr), alu32_out);
3343 break;
3344 }
3345 case op_addi_d: {
3346 setRegister(rd_reg(instr), rj(instr) + si12_se);
3347 break;
3348 }
3349 case op_lu52i_d: {
3350 int64_t si12_se = static_cast<int64_t>(si12(instr)) << 52;
3351 uint64_t mask = (1ULL << 52) - 1;
3352 alu_out = si12_se + (rj(instr) & mask);
3353 setRegister(rd_reg(instr), alu_out);
3354 break;
3355 }
3356 case op_andi: {
3357 setRegister(rd_reg(instr), rj(instr) & si12_ze);
3358 break;
3359 }
3360 case op_ori: {
3361 setRegister(rd_reg(instr), rj_u(instr) | si12_ze);
3362 break;
3363 }
3364 case op_xori: {
3365 setRegister(rd_reg(instr), rj_u(instr) ^ si12_ze);
3366 break;
3367 }
3368 case op_ld_b: {
3369 setRegister(rd_reg(instr), readB(rj(instr) + si12_se));
3370 break;
3371 }
3372 case op_ld_h: {
3373 setRegister(rd_reg(instr), readH(rj(instr) + si12_se, instr));
3374 break;
3375 }
3376 case op_ld_w: {
3377 setRegister(rd_reg(instr), readW(rj(instr) + si12_se, instr));
3378 break;
3379 }
3380 case op_ld_d: {
3381 setRegister(rd_reg(instr), readDW(rj(instr) + si12_se, instr));
3382 break;
3383 }
3384 case op_st_b: {
3385 writeB(rj(instr) + si12_se, static_cast<int8_t>(rd(instr)));
3386 break;
3387 }
3388 case op_st_h: {
3389 writeH(rj(instr) + si12_se, static_cast<int16_t>(rd(instr)), instr);
3390 break;
3391 }
3392 case op_st_w: {
3393 writeW(rj(instr) + si12_se, static_cast<int32_t>(rd(instr)), instr);
3394 break;
3395 }
3396 case op_st_d: {
3397 writeDW(rj(instr) + si12_se, rd(instr), instr);
3398 break;
3399 }
3400 case op_ld_bu: {
3401 setRegister(rd_reg(instr), readBU(rj(instr) + si12_se));
3402 break;
3403 }
3404 case op_ld_hu: {
3405 setRegister(rd_reg(instr), readHU(rj(instr) + si12_se, instr));
3406 break;
3407 }
3408 case op_ld_wu: {
3409 setRegister(rd_reg(instr), readWU(rj(instr) + si12_se, instr));
3410 break;
3411 }
3412 case op_fld_s: {
3413 setFpuRegister(fd_reg(instr), kFPUInvalidResult); // Trash upper 32 bits.
3414 setFpuRegisterWord(fd_reg(instr), readW(rj(instr) + si12_se, instr));
3415 break;
3416 }
3417 case op_fst_s: {
3418 int32_t alu_out_32 = static_cast<int32_t>(getFpuRegister(fd_reg(instr)));
3419 writeW(rj(instr) + si12_se, alu_out_32, instr);
3420 break;
3421 }
3422 case op_fld_d: {
3423 setFpuRegisterDouble(fd_reg(instr), readD(rj(instr) + si12_se, instr));
3424 break;
3425 }
3426 case op_fst_d: {
3427 writeD(rj(instr) + si12_se, getFpuRegisterDouble(fd_reg(instr)), instr);
3428 break;
3429 }
3430 case op_preld:
3431 UNIMPLEMENTED();
3432 break;
3433 default:
3434 UNREACHABLE();
3435 }
3436 }
3437
decodeTypeOp11(SimInstruction * instr)3438 void Simulator::decodeTypeOp11(SimInstruction* instr) {
3439 int64_t alu_out = 0x0;
3440
3441 switch (instr->bits(31, 21) << 21) {
3442 case op_bstr_w: {
3443 MOZ_ASSERT(instr->bit(21) == 1);
3444 uint8_t lsbw_ = lsbw(instr);
3445 uint8_t msbw_ = msbw(instr);
3446 MOZ_ASSERT(lsbw_ <= msbw_);
3447 uint8_t size = msbw_ - lsbw_ + 1;
3448 uint64_t mask = (1ULL << size) - 1;
3449 if (instr->bit(15) == 0) {
3450 // BSTRINS_W
3451 alu_out = static_cast<int32_t>((rd_u(instr) & ~(mask << lsbw_)) |
3452 ((rj_u(instr) & mask) << lsbw_));
3453 } else {
3454 // BSTRPICK_W
3455 alu_out =
3456 static_cast<int32_t>((rj_u(instr) & (mask << lsbw_)) >> lsbw_);
3457 }
3458 setRegister(rd_reg(instr), alu_out);
3459 break;
3460 }
3461 default:
3462 UNREACHABLE();
3463 }
3464 }
3465
decodeTypeOp12(SimInstruction * instr)3466 void Simulator::decodeTypeOp12(SimInstruction* instr) {
3467 switch (instr->bits(31, 20) << 20) {
3468 case op_fmadd_s: {
3469 setFpuRegisterFloat(
3470 fd_reg(instr),
3471 std::fma(fj_float(instr), fk_float(instr), fa_float(instr)));
3472 break;
3473 }
3474 case op_fmadd_d: {
3475 setFpuRegisterDouble(
3476 fd_reg(instr),
3477 std::fma(fj_double(instr), fk_double(instr), fa_double(instr)));
3478 break;
3479 }
3480 case op_fmsub_s: {
3481 setFpuRegisterFloat(
3482 fd_reg(instr),
3483 std::fma(-fj_float(instr), fk_float(instr), fa_float(instr)));
3484 break;
3485 }
3486 case op_fmsub_d: {
3487 setFpuRegisterDouble(
3488 fd_reg(instr),
3489 std::fma(-fj_double(instr), fk_double(instr), fa_double(instr)));
3490 break;
3491 }
3492 case op_fnmadd_s: {
3493 setFpuRegisterFloat(
3494 fd_reg(instr),
3495 std::fma(-fj_float(instr), fk_float(instr), -fa_float(instr)));
3496 break;
3497 }
3498 case op_fnmadd_d: {
3499 setFpuRegisterDouble(
3500 fd_reg(instr),
3501 std::fma(-fj_double(instr), fk_double(instr), -fa_double(instr)));
3502 break;
3503 }
3504 case op_fnmsub_s: {
3505 setFpuRegisterFloat(
3506 fd_reg(instr),
3507 std::fma(fj_float(instr), fk_float(instr), -fa_float(instr)));
3508 break;
3509 }
3510 case op_fnmsub_d: {
3511 setFpuRegisterDouble(
3512 fd_reg(instr),
3513 std::fma(fj_double(instr), fk_double(instr), -fa_double(instr)));
3514 break;
3515 }
3516 case op_fcmp_cond_s: {
3517 MOZ_ASSERT(instr->bits(4, 3) == 0);
3518 float fj = fj_float(instr);
3519 float fk = fk_float(instr);
3520 switch (cond(instr)) {
3521 case AssemblerLOONG64::CAF: {
3522 setCFRegister(cd_reg(instr), false);
3523 break;
3524 }
3525 case AssemblerLOONG64::CUN: {
3526 setCFRegister(cd_reg(instr), std::isnan(fj) || std::isnan(fk));
3527 break;
3528 }
3529 case AssemblerLOONG64::CEQ: {
3530 setCFRegister(cd_reg(instr), fj == fk);
3531 break;
3532 }
3533 case AssemblerLOONG64::CUEQ: {
3534 setCFRegister(cd_reg(instr),
3535 (fj == fk) || std::isnan(fj) || std::isnan(fk));
3536 break;
3537 }
3538 case AssemblerLOONG64::CLT: {
3539 setCFRegister(cd_reg(instr), fj < fk);
3540 break;
3541 }
3542 case AssemblerLOONG64::CULT: {
3543 setCFRegister(cd_reg(instr),
3544 (fj < fk) || std::isnan(fj) || std::isnan(fk));
3545 break;
3546 }
3547 case AssemblerLOONG64::CLE: {
3548 setCFRegister(cd_reg(instr), fj <= fk);
3549 break;
3550 }
3551 case AssemblerLOONG64::CULE: {
3552 setCFRegister(cd_reg(instr),
3553 (fj <= fk) || std::isnan(fj) || std::isnan(fk));
3554 break;
3555 }
3556 case AssemblerLOONG64::CNE: {
3557 setCFRegister(cd_reg(instr), (fj < fk) || (fj > fk));
3558 break;
3559 }
3560 case AssemblerLOONG64::COR: {
3561 setCFRegister(cd_reg(instr), !std::isnan(fj) && !std::isnan(fk));
3562 break;
3563 }
3564 case AssemblerLOONG64::CUNE: {
3565 setCFRegister(cd_reg(instr), (fj < fk) || (fj > fk) ||
3566 std::isnan(fj) || std::isnan(fk));
3567 break;
3568 }
3569 case AssemblerLOONG64::SAF:
3570 UNIMPLEMENTED();
3571 break;
3572 case AssemblerLOONG64::SUN:
3573 UNIMPLEMENTED();
3574 break;
3575 case AssemblerLOONG64::SEQ:
3576 UNIMPLEMENTED();
3577 break;
3578 case AssemblerLOONG64::SUEQ:
3579 UNIMPLEMENTED();
3580 break;
3581 case AssemblerLOONG64::SLT:
3582 UNIMPLEMENTED();
3583 break;
3584 case AssemblerLOONG64::SULT:
3585 UNIMPLEMENTED();
3586 break;
3587 case AssemblerLOONG64::SLE:
3588 UNIMPLEMENTED();
3589 break;
3590 case AssemblerLOONG64::SULE:
3591 UNIMPLEMENTED();
3592 break;
3593 case AssemblerLOONG64::SNE:
3594 UNIMPLEMENTED();
3595 break;
3596 case AssemblerLOONG64::SOR:
3597 UNIMPLEMENTED();
3598 break;
3599 case AssemblerLOONG64::SUNE:
3600 UNIMPLEMENTED();
3601 break;
3602 default:
3603 UNREACHABLE();
3604 }
3605 break;
3606 }
3607 case op_fcmp_cond_d: {
3608 MOZ_ASSERT(instr->bits(4, 3) == 0);
3609 double fj = fj_double(instr);
3610 double fk = fk_double(instr);
3611 switch (cond(instr)) {
3612 case AssemblerLOONG64::CAF: {
3613 setCFRegister(cd_reg(instr), false);
3614 break;
3615 }
3616 case AssemblerLOONG64::CUN: {
3617 setCFRegister(cd_reg(instr), std::isnan(fj) || std::isnan(fk));
3618 break;
3619 }
3620 case AssemblerLOONG64::CEQ: {
3621 setCFRegister(cd_reg(instr), fj == fk);
3622 break;
3623 }
3624 case AssemblerLOONG64::CUEQ: {
3625 setCFRegister(cd_reg(instr),
3626 (fj == fk) || std::isnan(fj) || std::isnan(fk));
3627 break;
3628 }
3629 case AssemblerLOONG64::CLT: {
3630 setCFRegister(cd_reg(instr), fj < fk);
3631 break;
3632 }
3633 case AssemblerLOONG64::CULT: {
3634 setCFRegister(cd_reg(instr),
3635 (fj < fk) || std::isnan(fj) || std::isnan(fk));
3636 break;
3637 }
3638 case AssemblerLOONG64::CLE: {
3639 setCFRegister(cd_reg(instr), fj <= fk);
3640 break;
3641 }
3642 case AssemblerLOONG64::CULE: {
3643 setCFRegister(cd_reg(instr),
3644 (fj <= fk) || std::isnan(fj) || std::isnan(fk));
3645 break;
3646 }
3647 case AssemblerLOONG64::CNE: {
3648 setCFRegister(cd_reg(instr), (fj < fk) || (fj > fk));
3649 break;
3650 }
3651 case AssemblerLOONG64::COR: {
3652 setCFRegister(cd_reg(instr), !std::isnan(fj) && !std::isnan(fk));
3653 break;
3654 }
3655 case AssemblerLOONG64::CUNE: {
3656 setCFRegister(cd_reg(instr),
3657 (fj != fk) || std::isnan(fj) || std::isnan(fk));
3658 break;
3659 }
3660 case AssemblerLOONG64::SAF:
3661 UNIMPLEMENTED();
3662 break;
3663 case AssemblerLOONG64::SUN:
3664 UNIMPLEMENTED();
3665 break;
3666 case AssemblerLOONG64::SEQ:
3667 UNIMPLEMENTED();
3668 break;
3669 case AssemblerLOONG64::SUEQ:
3670 UNIMPLEMENTED();
3671 break;
3672 case AssemblerLOONG64::SLT:
3673 UNIMPLEMENTED();
3674 break;
3675 case AssemblerLOONG64::SULT:
3676 UNIMPLEMENTED();
3677 break;
3678 case AssemblerLOONG64::SLE:
3679 UNIMPLEMENTED();
3680 break;
3681 case AssemblerLOONG64::SULE:
3682 UNIMPLEMENTED();
3683 break;
3684 case AssemblerLOONG64::SNE:
3685 UNIMPLEMENTED();
3686 break;
3687 case AssemblerLOONG64::SOR:
3688 UNIMPLEMENTED();
3689 break;
3690 case AssemblerLOONG64::SUNE:
3691 UNIMPLEMENTED();
3692 break;
3693 default:
3694 UNREACHABLE();
3695 }
3696 break;
3697 }
3698 default:
3699 UNREACHABLE();
3700 }
3701 }
3702
decodeTypeOp14(SimInstruction * instr)3703 void Simulator::decodeTypeOp14(SimInstruction* instr) {
3704 int64_t alu_out = 0x0;
3705
3706 switch (instr->bits(31, 18) << 18) {
3707 case op_bytepick_d: {
3708 uint8_t sa = sa3(instr) * 8;
3709 if (sa == 0) {
3710 alu_out = rk(instr);
3711 } else {
3712 int64_t mask = (1ULL << 63) >> (sa - 1);
3713 int64_t rk_hi = (rk(instr) & (~mask)) << sa;
3714 int64_t rj_lo = (rj(instr) & mask) >> (64 - sa);
3715 alu_out = rk_hi | rj_lo;
3716 }
3717 setRegister(rd_reg(instr), alu_out);
3718 break;
3719 }
3720 case op_fsel: {
3721 MOZ_ASSERT(instr->bits(19, 18) == 0);
3722 if (ca(instr) == 0) {
3723 setFpuRegisterDouble(fd_reg(instr), fj_double(instr));
3724 } else {
3725 setFpuRegisterDouble(fd_reg(instr), fk_double(instr));
3726 }
3727 break;
3728 }
3729 default:
3730 UNREACHABLE();
3731 }
3732 }
3733
decodeTypeOp15(SimInstruction * instr)3734 void Simulator::decodeTypeOp15(SimInstruction* instr) {
3735 int64_t alu_out = 0x0;
3736 int32_t alu32_out = 0x0;
3737
3738 switch (instr->bits(31, 17) << 17) {
3739 case op_bytepick_w: {
3740 MOZ_ASSERT(instr->bit(17) == 0);
3741 uint8_t sa = sa2(instr) * 8;
3742 if (sa == 0) {
3743 alu32_out = static_cast<int32_t>(rk(instr));
3744 } else {
3745 int32_t mask = (1 << 31) >> (sa - 1);
3746 int32_t rk_hi = (static_cast<int32_t>(rk(instr)) & (~mask)) << sa;
3747 int32_t rj_lo = (static_cast<uint32_t>(rj(instr)) & mask) >> (32 - sa);
3748 alu32_out = rk_hi | rj_lo;
3749 }
3750 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
3751 break;
3752 }
3753 case op_alsl_w: {
3754 uint8_t sa = sa2(instr) + 1;
3755 alu32_out = (static_cast<int32_t>(rj(instr)) << sa) +
3756 static_cast<int32_t>(rk(instr));
3757 setRegister(rd_reg(instr), alu32_out);
3758 break;
3759 }
3760 case op_alsl_wu: {
3761 uint8_t sa = sa2(instr) + 1;
3762 alu32_out = (static_cast<int32_t>(rj(instr)) << sa) +
3763 static_cast<int32_t>(rk(instr));
3764 setRegister(rd_reg(instr), static_cast<uint32_t>(alu32_out));
3765 break;
3766 }
3767 case op_alsl_d: {
3768 MOZ_ASSERT(instr->bit(17) == 0);
3769 uint8_t sa = sa2(instr) + 1;
3770 alu_out = (rj(instr) << sa) + rk(instr);
3771 setRegister(rd_reg(instr), alu_out);
3772 break;
3773 }
3774 default:
3775 UNREACHABLE();
3776 }
3777 }
3778
decodeTypeOp16(SimInstruction * instr)3779 void Simulator::decodeTypeOp16(SimInstruction* instr) {
3780 int64_t alu_out;
3781 switch (instr->bits(31, 16) << 16) {
3782 case op_slli_d: {
3783 MOZ_ASSERT(instr->bit(17) == 0);
3784 MOZ_ASSERT(instr->bits(17, 16) == 0b01);
3785 setRegister(rd_reg(instr), rj(instr) << ui6(instr));
3786 break;
3787 }
3788 case op_srli_d: {
3789 MOZ_ASSERT(instr->bit(17) == 0);
3790 setRegister(rd_reg(instr), rj_u(instr) >> ui6(instr));
3791 break;
3792 }
3793 case op_srai_d: {
3794 MOZ_ASSERT(instr->bit(17) == 0);
3795 setRegister(rd_reg(instr), rj(instr) >> ui6(instr));
3796 break;
3797 }
3798 case op_rotri_d: {
3799 MOZ_ASSERT(instr->bit(17) == 0);
3800 MOZ_ASSERT(instr->bits(17, 16) == 0b01);
3801 alu_out = static_cast<int64_t>(RotateRight64(rj_u(instr), ui6(instr)));
3802 setRegister(rd_reg(instr), alu_out);
3803 break;
3804 }
3805 default:
3806 UNREACHABLE();
3807 }
3808 }
3809
decodeTypeOp17(SimInstruction * instr)3810 void Simulator::decodeTypeOp17(SimInstruction* instr) {
3811 int64_t alu_out;
3812 int32_t alu32_out;
3813
3814 switch (instr->bits(31, 15) << 15) {
3815 case op_slli_w: {
3816 MOZ_ASSERT(instr->bit(17) == 0);
3817 MOZ_ASSERT(instr->bits(17, 15) == 0b001);
3818 alu32_out = static_cast<int32_t>(rj(instr)) << ui5(instr);
3819 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
3820 break;
3821 }
3822 case op_srai_w: {
3823 MOZ_ASSERT(instr->bit(17) == 0);
3824 MOZ_ASSERT(instr->bits(17, 15) == 0b001);
3825 alu32_out = static_cast<int32_t>(rj(instr)) >> ui5(instr);
3826 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
3827 break;
3828 }
3829 case op_rotri_w: {
3830 MOZ_ASSERT(instr->bit(17) == 0);
3831 MOZ_ASSERT(instr->bits(17, 15) == 0b001);
3832 alu32_out = static_cast<int32_t>(
3833 RotateRight32(static_cast<const uint32_t>(rj_u(instr)),
3834 static_cast<const uint32_t>(ui5(instr))));
3835 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
3836 break;
3837 }
3838 case op_srli_w: {
3839 MOZ_ASSERT(instr->bit(17) == 0);
3840 MOZ_ASSERT(instr->bits(17, 15) == 0b001);
3841 alu32_out = static_cast<uint32_t>(rj(instr)) >> ui5(instr);
3842 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
3843 break;
3844 }
3845 case op_add_w: {
3846 int32_t alu32_out = static_cast<int32_t>(rj(instr) + rk(instr));
3847 // Sign-extend result of 32bit operation into 64bit register.
3848 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
3849 break;
3850 }
3851 case op_add_d:
3852 setRegister(rd_reg(instr), rj(instr) + rk(instr));
3853 break;
3854 case op_sub_w: {
3855 int32_t alu32_out = static_cast<int32_t>(rj(instr) - rk(instr));
3856 // Sign-extend result of 32bit operation into 64bit register.
3857 setRegister(rd_reg(instr), static_cast<int64_t>(alu32_out));
3858 break;
3859 }
3860 case op_sub_d:
3861 setRegister(rd_reg(instr), rj(instr) - rk(instr));
3862 break;
3863 case op_slt:
3864 setRegister(rd_reg(instr), rj(instr) < rk(instr) ? 1 : 0);
3865 break;
3866 case op_sltu:
3867 setRegister(rd_reg(instr), rj_u(instr) < rk_u(instr) ? 1 : 0);
3868 break;
3869 case op_maskeqz:
3870 setRegister(rd_reg(instr), rk(instr) == 0 ? 0 : rj(instr));
3871 break;
3872 case op_masknez:
3873 setRegister(rd_reg(instr), rk(instr) != 0 ? 0 : rj(instr));
3874 break;
3875 case op_nor:
3876 setRegister(rd_reg(instr), ~(rj(instr) | rk(instr)));
3877 break;
3878 case op_and:
3879 setRegister(rd_reg(instr), rj(instr) & rk(instr));
3880 break;
3881 case op_or:
3882 setRegister(rd_reg(instr), rj(instr) | rk(instr));
3883 break;
3884 case op_xor:
3885 setRegister(rd_reg(instr), rj(instr) ^ rk(instr));
3886 break;
3887 case op_orn:
3888 setRegister(rd_reg(instr), rj(instr) | (~rk(instr)));
3889 break;
3890 case op_andn:
3891 setRegister(rd_reg(instr), rj(instr) & (~rk(instr)));
3892 break;
3893 case op_sll_w:
3894 setRegister(rd_reg(instr), (int32_t)rj(instr) << (rk_u(instr) % 32));
3895 break;
3896 case op_srl_w: {
3897 alu_out =
3898 static_cast<int32_t>((uint32_t)rj_u(instr) >> (rk_u(instr) % 32));
3899 setRegister(rd_reg(instr), alu_out);
3900 break;
3901 }
3902 case op_sra_w:
3903 setRegister(rd_reg(instr), (int32_t)rj(instr) >> (rk_u(instr) % 32));
3904 break;
3905 case op_sll_d:
3906 setRegister(rd_reg(instr), rj(instr) << (rk_u(instr) % 64));
3907 break;
3908 case op_srl_d: {
3909 alu_out = static_cast<int64_t>(rj_u(instr) >> (rk_u(instr) % 64));
3910 setRegister(rd_reg(instr), alu_out);
3911 break;
3912 }
3913 case op_sra_d:
3914 setRegister(rd_reg(instr), rj(instr) >> (rk_u(instr) % 64));
3915 break;
3916 case op_rotr_w: {
3917 alu_out = static_cast<int32_t>(
3918 RotateRight32(static_cast<const uint32_t>(rj_u(instr)),
3919 static_cast<const uint32_t>(rk_u(instr) % 32)));
3920 setRegister(rd_reg(instr), alu_out);
3921 break;
3922 }
3923 case op_rotr_d: {
3924 alu_out = static_cast<int64_t>(
3925 RotateRight64((rj_u(instr)), (rk_u(instr) % 64)));
3926 setRegister(rd_reg(instr), alu_out);
3927 break;
3928 }
3929 case op_mul_w: {
3930 alu_out =
3931 static_cast<int32_t>(rj(instr)) * static_cast<int32_t>(rk(instr));
3932 setRegister(rd_reg(instr), alu_out);
3933 break;
3934 }
3935 case op_mulh_w: {
3936 int32_t rj_lo = static_cast<int32_t>(rj(instr));
3937 int32_t rk_lo = static_cast<int32_t>(rk(instr));
3938 alu_out = static_cast<int64_t>(rj_lo) * static_cast<int64_t>(rk_lo);
3939 setRegister(rd_reg(instr), alu_out >> 32);
3940 break;
3941 }
3942 case op_mulh_wu: {
3943 uint32_t rj_lo = static_cast<uint32_t>(rj_u(instr));
3944 uint32_t rk_lo = static_cast<uint32_t>(rk_u(instr));
3945 alu_out = static_cast<uint64_t>(rj_lo) * static_cast<uint64_t>(rk_lo);
3946 setRegister(rd_reg(instr), alu_out >> 32);
3947 break;
3948 }
3949 case op_mul_d:
3950 setRegister(rd_reg(instr), rj(instr) * rk(instr));
3951 break;
3952 case op_mulh_d:
3953 setRegister(rd_reg(instr), MultiplyHighSigned(rj(instr), rk(instr)));
3954 break;
3955 case op_mulh_du:
3956 setRegister(rd_reg(instr),
3957 MultiplyHighUnsigned(rj_u(instr), rk_u(instr)));
3958 break;
3959 case op_mulw_d_w: {
3960 int64_t rj_i32 = static_cast<int32_t>(rj(instr));
3961 int64_t rk_i32 = static_cast<int32_t>(rk(instr));
3962 setRegister(rd_reg(instr), rj_i32 * rk_i32);
3963 break;
3964 }
3965 case op_mulw_d_wu: {
3966 uint64_t rj_u32 = static_cast<uint32_t>(rj_u(instr));
3967 uint64_t rk_u32 = static_cast<uint32_t>(rk_u(instr));
3968 setRegister(rd_reg(instr), rj_u32 * rk_u32);
3969 break;
3970 }
3971 case op_div_w: {
3972 int32_t rj_i32 = static_cast<int32_t>(rj(instr));
3973 int32_t rk_i32 = static_cast<int32_t>(rk(instr));
3974 if (rj_i32 == INT_MIN && rk_i32 == -1) {
3975 setRegister(rd_reg(instr), INT_MIN);
3976 } else if (rk_i32 != 0) {
3977 setRegister(rd_reg(instr), rj_i32 / rk_i32);
3978 }
3979 break;
3980 }
3981 case op_mod_w: {
3982 int32_t rj_i32 = static_cast<int32_t>(rj(instr));
3983 int32_t rk_i32 = static_cast<int32_t>(rk(instr));
3984 if (rj_i32 == INT_MIN && rk_i32 == -1) {
3985 setRegister(rd_reg(instr), 0);
3986 } else if (rk_i32 != 0) {
3987 setRegister(rd_reg(instr), rj_i32 % rk_i32);
3988 }
3989 break;
3990 }
3991 case op_div_wu: {
3992 uint32_t rj_u32 = static_cast<uint32_t>(rj(instr));
3993 uint32_t rk_u32 = static_cast<uint32_t>(rk(instr));
3994 if (rk_u32 != 0) {
3995 setRegister(rd_reg(instr), static_cast<int32_t>(rj_u32 / rk_u32));
3996 }
3997 break;
3998 }
3999 case op_mod_wu: {
4000 uint32_t rj_u32 = static_cast<uint32_t>(rj(instr));
4001 uint32_t rk_u32 = static_cast<uint32_t>(rk(instr));
4002 if (rk_u32 != 0) {
4003 setRegister(rd_reg(instr), static_cast<int32_t>(rj_u32 % rk_u32));
4004 }
4005 break;
4006 }
4007 case op_div_d: {
4008 if (rj(instr) == INT64_MIN && rk(instr) == -1) {
4009 setRegister(rd_reg(instr), INT64_MIN);
4010 } else if (rk(instr) != 0) {
4011 setRegister(rd_reg(instr), rj(instr) / rk(instr));
4012 }
4013 break;
4014 }
4015 case op_mod_d: {
4016 if (rj(instr) == LONG_MIN && rk(instr) == -1) {
4017 setRegister(rd_reg(instr), 0);
4018 } else if (rk(instr) != 0) {
4019 setRegister(rd_reg(instr), rj(instr) % rk(instr));
4020 }
4021 break;
4022 }
4023 case op_div_du: {
4024 if (rk_u(instr) != 0) {
4025 setRegister(rd_reg(instr),
4026 static_cast<int64_t>(rj_u(instr) / rk_u(instr)));
4027 }
4028 break;
4029 }
4030 case op_mod_du: {
4031 if (rk_u(instr) != 0) {
4032 setRegister(rd_reg(instr),
4033 static_cast<int64_t>(rj_u(instr) % rk_u(instr)));
4034 }
4035 break;
4036 }
4037 case op_break:
4038 softwareInterrupt(instr);
4039 break;
4040 case op_fadd_s: {
4041 setFpuRegisterFloat(fd_reg(instr), fj_float(instr) + fk_float(instr));
4042 break;
4043 }
4044 case op_fadd_d: {
4045 setFpuRegisterDouble(fd_reg(instr), fj_double(instr) + fk_double(instr));
4046 break;
4047 }
4048 case op_fsub_s: {
4049 setFpuRegisterFloat(fd_reg(instr), fj_float(instr) - fk_float(instr));
4050 break;
4051 }
4052 case op_fsub_d: {
4053 setFpuRegisterDouble(fd_reg(instr), fj_double(instr) - fk_double(instr));
4054 break;
4055 }
4056 case op_fmul_s: {
4057 setFpuRegisterFloat(fd_reg(instr), fj_float(instr) * fk_float(instr));
4058 break;
4059 }
4060 case op_fmul_d: {
4061 setFpuRegisterDouble(fd_reg(instr), fj_double(instr) * fk_double(instr));
4062 break;
4063 }
4064 case op_fdiv_s: {
4065 setFpuRegisterFloat(fd_reg(instr), fj_float(instr) / fk_float(instr));
4066 break;
4067 }
4068
4069 case op_fdiv_d: {
4070 setFpuRegisterDouble(fd_reg(instr), fj_double(instr) / fk_double(instr));
4071 break;
4072 }
4073 case op_fmax_s: {
4074 setFpuRegisterFloat(fd_reg(instr),
4075 FPUMax(fk_float(instr), fj_float(instr)));
4076 break;
4077 }
4078 case op_fmax_d: {
4079 setFpuRegisterDouble(fd_reg(instr),
4080 FPUMax(fk_double(instr), fj_double(instr)));
4081 break;
4082 }
4083 case op_fmin_s: {
4084 setFpuRegisterFloat(fd_reg(instr),
4085 FPUMin(fk_float(instr), fj_float(instr)));
4086 break;
4087 }
4088 case op_fmin_d: {
4089 setFpuRegisterDouble(fd_reg(instr),
4090 FPUMin(fk_double(instr), fj_double(instr)));
4091 break;
4092 }
4093 case op_fmaxa_s: {
4094 setFpuRegisterFloat(fd_reg(instr),
4095 FPUMaxA(fk_float(instr), fj_float(instr)));
4096 break;
4097 }
4098 case op_fmaxa_d: {
4099 setFpuRegisterDouble(fd_reg(instr),
4100 FPUMaxA(fk_double(instr), fj_double(instr)));
4101 break;
4102 }
4103 case op_fmina_s: {
4104 setFpuRegisterFloat(fd_reg(instr),
4105 FPUMinA(fk_float(instr), fj_float(instr)));
4106 break;
4107 }
4108 case op_fmina_d: {
4109 setFpuRegisterDouble(fd_reg(instr),
4110 FPUMinA(fk_double(instr), fj_double(instr)));
4111 break;
4112 }
4113 case op_ldx_b:
4114 setRegister(rd_reg(instr), readB(rj(instr) + rk(instr)));
4115 break;
4116 case op_ldx_h:
4117 setRegister(rd_reg(instr), readH(rj(instr) + rk(instr), instr));
4118 break;
4119 case op_ldx_w:
4120 setRegister(rd_reg(instr), readW(rj(instr) + rk(instr), instr));
4121 break;
4122 case op_ldx_d:
4123 setRegister(rd_reg(instr), readDW(rj(instr) + rk(instr), instr));
4124 break;
4125 case op_stx_b:
4126 writeB(rj(instr) + rk(instr), static_cast<int8_t>(rd(instr)));
4127 break;
4128 case op_stx_h:
4129 writeH(rj(instr) + rk(instr), static_cast<int16_t>(rd(instr)), instr);
4130 break;
4131 case op_stx_w:
4132 writeW(rj(instr) + rk(instr), static_cast<int32_t>(rd(instr)), instr);
4133 break;
4134 case op_stx_d:
4135 writeDW(rj(instr) + rk(instr), rd(instr), instr);
4136 break;
4137 case op_ldx_bu:
4138 setRegister(rd_reg(instr), readBU(rj(instr) + rk(instr)));
4139 break;
4140 case op_ldx_hu:
4141 setRegister(rd_reg(instr), readHU(rj(instr) + rk(instr), instr));
4142 break;
4143 case op_ldx_wu:
4144 setRegister(rd_reg(instr), readWU(rj(instr) + rk(instr), instr));
4145 break;
4146 case op_fldx_s:
4147 setFpuRegister(fd_reg(instr), kFPUInvalidResult); // Trash upper 32 bits.
4148 setFpuRegisterWord(fd_reg(instr), readW(rj(instr) + rk(instr), instr));
4149 break;
4150 case op_fldx_d:
4151 setFpuRegister(fd_reg(instr), kFPUInvalidResult); // Trash upper 32 bits.
4152 setFpuRegisterDouble(fd_reg(instr), readD(rj(instr) + rk(instr), instr));
4153 break;
4154 case op_fstx_s: {
4155 int32_t alu_out_32 = static_cast<int32_t>(getFpuRegister(fd_reg(instr)));
4156 writeW(rj(instr) + rk(instr), alu_out_32, instr);
4157 break;
4158 }
4159 case op_fstx_d: {
4160 writeD(rj(instr) + rk(instr), getFpuRegisterDouble(fd_reg(instr)), instr);
4161 break;
4162 }
4163 case op_amswap_w:
4164 UNIMPLEMENTED();
4165 break;
4166 case op_amswap_d:
4167 UNIMPLEMENTED();
4168 break;
4169 case op_amadd_w:
4170 UNIMPLEMENTED();
4171 break;
4172 case op_amadd_d:
4173 UNIMPLEMENTED();
4174 break;
4175 case op_amand_w:
4176 UNIMPLEMENTED();
4177 break;
4178 case op_amand_d:
4179 UNIMPLEMENTED();
4180 break;
4181 case op_amor_w:
4182 UNIMPLEMENTED();
4183 break;
4184 case op_amor_d:
4185 UNIMPLEMENTED();
4186 break;
4187 case op_amxor_w:
4188 UNIMPLEMENTED();
4189 break;
4190 case op_amxor_d:
4191 UNIMPLEMENTED();
4192 break;
4193 case op_ammax_w:
4194 UNIMPLEMENTED();
4195 break;
4196 case op_ammax_d:
4197 UNIMPLEMENTED();
4198 break;
4199 case op_ammin_w:
4200 UNIMPLEMENTED();
4201 break;
4202 case op_ammin_d:
4203 UNIMPLEMENTED();
4204 break;
4205 case op_ammax_wu:
4206 UNIMPLEMENTED();
4207 break;
4208 case op_ammax_du:
4209 UNIMPLEMENTED();
4210 break;
4211 case op_ammin_wu:
4212 UNIMPLEMENTED();
4213 break;
4214 case op_ammin_du:
4215 UNIMPLEMENTED();
4216 break;
4217 case op_amswap_db_w:
4218 UNIMPLEMENTED();
4219 break;
4220 case op_amswap_db_d:
4221 UNIMPLEMENTED();
4222 break;
4223 case op_amadd_db_w:
4224 UNIMPLEMENTED();
4225 break;
4226 case op_amadd_db_d:
4227 UNIMPLEMENTED();
4228 break;
4229 case op_amand_db_w:
4230 UNIMPLEMENTED();
4231 break;
4232 case op_amand_db_d:
4233 UNIMPLEMENTED();
4234 break;
4235 case op_amor_db_w:
4236 UNIMPLEMENTED();
4237 break;
4238 case op_amor_db_d:
4239 UNIMPLEMENTED();
4240 break;
4241 case op_amxor_db_w:
4242 UNIMPLEMENTED();
4243 break;
4244 case op_amxor_db_d:
4245 UNIMPLEMENTED();
4246 break;
4247 case op_ammax_db_w:
4248 UNIMPLEMENTED();
4249 break;
4250 case op_ammax_db_d:
4251 UNIMPLEMENTED();
4252 break;
4253 case op_ammin_db_w:
4254 UNIMPLEMENTED();
4255 break;
4256 case op_ammin_db_d:
4257 UNIMPLEMENTED();
4258 break;
4259 case op_ammax_db_wu:
4260 UNIMPLEMENTED();
4261 break;
4262 case op_ammax_db_du:
4263 UNIMPLEMENTED();
4264 break;
4265 case op_ammin_db_wu:
4266 UNIMPLEMENTED();
4267 break;
4268 case op_ammin_db_du:
4269 UNIMPLEMENTED();
4270 break;
4271 case op_dbar:
4272 // TODO(loong64): dbar simulation
4273 break;
4274 case op_ibar:
4275 UNIMPLEMENTED();
4276 break;
4277 case op_fcopysign_s:
4278 UNIMPLEMENTED();
4279 break;
4280 case op_fcopysign_d:
4281 UNIMPLEMENTED();
4282 break;
4283 default:
4284 UNREACHABLE();
4285 }
4286 }
4287
decodeTypeOp22(SimInstruction * instr)4288 void Simulator::decodeTypeOp22(SimInstruction* instr) {
4289 int64_t alu_out;
4290
4291 switch (instr->bits(31, 10) << 10) {
4292 case op_clz_w: {
4293 alu_out = U32(rj_u(instr)) ? __builtin_clz(U32(rj_u(instr))) : 32;
4294 setRegister(rd_reg(instr), alu_out);
4295 break;
4296 }
4297 case op_ctz_w: {
4298 alu_out = U32(rj_u(instr)) ? __builtin_ctz(U32(rj_u(instr))) : 32;
4299 setRegister(rd_reg(instr), alu_out);
4300 break;
4301 }
4302 case op_clz_d: {
4303 alu_out = U64(rj_u(instr)) ? __builtin_clzll(U64(rj_u(instr))) : 64;
4304 setRegister(rd_reg(instr), alu_out);
4305 break;
4306 }
4307 case op_ctz_d: {
4308 alu_out = U64(rj_u(instr)) ? __builtin_ctzll(U64(rj_u(instr))) : 64;
4309 setRegister(rd_reg(instr), alu_out);
4310 break;
4311 }
4312 case op_revb_2h: {
4313 uint32_t input = static_cast<uint32_t>(rj(instr));
4314 uint64_t output = 0;
4315
4316 uint32_t mask = 0xFF000000;
4317 for (int i = 0; i < 4; i++) {
4318 uint32_t tmp = mask & input;
4319 if (i % 2 == 0) {
4320 tmp = tmp >> 8;
4321 } else {
4322 tmp = tmp << 8;
4323 }
4324 output = output | tmp;
4325 mask = mask >> 8;
4326 }
4327
4328 alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
4329 setRegister(rd_reg(instr), alu_out);
4330 break;
4331 }
4332 case op_revb_4h: {
4333 uint64_t input = rj_u(instr);
4334 uint64_t output = 0;
4335
4336 uint64_t mask = 0xFF00000000000000;
4337 for (int i = 0; i < 8; i++) {
4338 uint64_t tmp = mask & input;
4339 if (i % 2 == 0) {
4340 tmp = tmp >> 8;
4341 } else {
4342 tmp = tmp << 8;
4343 }
4344 output = output | tmp;
4345 mask = mask >> 8;
4346 }
4347
4348 alu_out = static_cast<int64_t>(output);
4349 setRegister(rd_reg(instr), alu_out);
4350 break;
4351 }
4352 case op_revb_2w: {
4353 uint64_t input = rj_u(instr);
4354 uint64_t output = 0;
4355
4356 uint64_t mask = 0xFF000000FF000000;
4357 for (int i = 0; i < 4; i++) {
4358 uint64_t tmp = mask & input;
4359 if (i <= 1) {
4360 tmp = tmp >> (24 - i * 16);
4361 } else {
4362 tmp = tmp << (i * 16 - 24);
4363 }
4364 output = output | tmp;
4365 mask = mask >> 8;
4366 }
4367
4368 alu_out = static_cast<int64_t>(output);
4369 setRegister(rd_reg(instr), alu_out);
4370 break;
4371 }
4372 case op_revb_d: {
4373 uint64_t input = rj_u(instr);
4374 uint64_t output = 0;
4375
4376 uint64_t mask = 0xFF00000000000000;
4377 for (int i = 0; i < 8; i++) {
4378 uint64_t tmp = mask & input;
4379 if (i <= 3) {
4380 tmp = tmp >> (56 - i * 16);
4381 } else {
4382 tmp = tmp << (i * 16 - 56);
4383 }
4384 output = output | tmp;
4385 mask = mask >> 8;
4386 }
4387
4388 alu_out = static_cast<int64_t>(output);
4389 setRegister(rd_reg(instr), alu_out);
4390 break;
4391 }
4392 case op_revh_2w: {
4393 uint64_t input = rj_u(instr);
4394 uint64_t output = 0;
4395
4396 uint64_t mask = 0xFFFF000000000000;
4397 for (int i = 0; i < 4; i++) {
4398 uint64_t tmp = mask & input;
4399 if (i % 2 == 0) {
4400 tmp = tmp >> 16;
4401 } else {
4402 tmp = tmp << 16;
4403 }
4404 output = output | tmp;
4405 mask = mask >> 16;
4406 }
4407
4408 alu_out = static_cast<int64_t>(output);
4409 setRegister(rd_reg(instr), alu_out);
4410 break;
4411 }
4412 case op_revh_d: {
4413 uint64_t input = rj_u(instr);
4414 uint64_t output = 0;
4415
4416 uint64_t mask = 0xFFFF000000000000;
4417 for (int i = 0; i < 4; i++) {
4418 uint64_t tmp = mask & input;
4419 if (i <= 1) {
4420 tmp = tmp >> (48 - i * 32);
4421 } else {
4422 tmp = tmp << (i * 32 - 48);
4423 }
4424 output = output | tmp;
4425 mask = mask >> 16;
4426 }
4427
4428 alu_out = static_cast<int64_t>(output);
4429 setRegister(rd_reg(instr), alu_out);
4430 break;
4431 }
4432 case op_bitrev_4b: {
4433 uint32_t input = static_cast<uint32_t>(rj(instr));
4434 uint32_t output = 0;
4435 uint8_t i_byte, o_byte;
4436
4437 // Reverse the bit in byte for each individual byte
4438 for (int i = 0; i < 4; i++) {
4439 output = output >> 8;
4440 i_byte = input & 0xFF;
4441
4442 // Fast way to reverse bits in byte
4443 // Devised by Sean Anderson, July 13, 2001
4444 o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
4445 (i_byte * 0x8020LU & 0x88440LU)) *
4446 0x10101LU >>
4447 16);
4448
4449 output = output | (static_cast<uint32_t>(o_byte << 24));
4450 input = input >> 8;
4451 }
4452
4453 alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
4454 setRegister(rd_reg(instr), alu_out);
4455 break;
4456 }
4457 case op_bitrev_8b: {
4458 uint64_t input = rj_u(instr);
4459 uint64_t output = 0;
4460 uint8_t i_byte, o_byte;
4461
4462 // Reverse the bit in byte for each individual byte
4463 for (int i = 0; i < 8; i++) {
4464 output = output >> 8;
4465 i_byte = input & 0xFF;
4466
4467 // Fast way to reverse bits in byte
4468 // Devised by Sean Anderson, July 13, 2001
4469 o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
4470 (i_byte * 0x8020LU & 0x88440LU)) *
4471 0x10101LU >>
4472 16);
4473
4474 output = output | (static_cast<uint64_t>(o_byte) << 56);
4475 input = input >> 8;
4476 }
4477
4478 alu_out = static_cast<int64_t>(output);
4479 setRegister(rd_reg(instr), alu_out);
4480 break;
4481 }
4482 case op_bitrev_w: {
4483 uint32_t input = static_cast<uint32_t>(rj(instr));
4484 uint32_t output = 0;
4485 output = ReverseBits(input);
4486 alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
4487 setRegister(rd_reg(instr), alu_out);
4488 break;
4489 }
4490 case op_bitrev_d: {
4491 alu_out = static_cast<int64_t>(ReverseBits(rj_u(instr)));
4492 setRegister(rd_reg(instr), alu_out);
4493 break;
4494 }
4495 case op_ext_w_b: {
4496 uint8_t input = static_cast<uint8_t>(rj(instr));
4497 alu_out = static_cast<int64_t>(static_cast<int8_t>(input));
4498 setRegister(rd_reg(instr), alu_out);
4499 break;
4500 }
4501 case op_ext_w_h: {
4502 uint16_t input = static_cast<uint16_t>(rj(instr));
4503 alu_out = static_cast<int64_t>(static_cast<int16_t>(input));
4504 setRegister(rd_reg(instr), alu_out);
4505 break;
4506 }
4507 case op_fabs_s: {
4508 setFpuRegisterFloat(fd_reg(instr), std::abs(fj_float(instr)));
4509 break;
4510 }
4511 case op_fabs_d: {
4512 setFpuRegisterDouble(fd_reg(instr), std::abs(fj_double(instr)));
4513 break;
4514 }
4515 case op_fneg_s: {
4516 setFpuRegisterFloat(fd_reg(instr), -fj_float(instr));
4517 break;
4518 }
4519 case op_fneg_d: {
4520 setFpuRegisterDouble(fd_reg(instr), -fj_double(instr));
4521 break;
4522 }
4523 case op_fsqrt_s: {
4524 if (fj_float(instr) >= 0) {
4525 setFpuRegisterFloat(fd_reg(instr), std::sqrt(fj_float(instr)));
4526 } else {
4527 setFpuRegisterFloat(fd_reg(instr), std::sqrt(-1)); // qnan
4528 setFCSRBit(kFCSRInvalidOpFlagBit, true);
4529 }
4530 break;
4531 }
4532 case op_fsqrt_d: {
4533 if (fj_double(instr) >= 0) {
4534 setFpuRegisterDouble(fd_reg(instr), std::sqrt(fj_double(instr)));
4535 } else {
4536 setFpuRegisterDouble(fd_reg(instr), std::sqrt(-1)); // qnan
4537 setFCSRBit(kFCSRInvalidOpFlagBit, true);
4538 }
4539 break;
4540 }
4541 case op_fmov_s: {
4542 setFpuRegisterFloat(fd_reg(instr), fj_float(instr));
4543 break;
4544 }
4545 case op_fmov_d: {
4546 setFpuRegisterDouble(fd_reg(instr), fj_double(instr));
4547 break;
4548 }
4549 case op_movgr2fr_w: {
4550 setFpuRegisterWord(fd_reg(instr), static_cast<int32_t>(rj(instr)));
4551 break;
4552 }
4553 case op_movgr2fr_d: {
4554 setFpuRegister(fd_reg(instr), rj(instr));
4555 break;
4556 }
4557 case op_movgr2frh_w: {
4558 setFpuRegisterHiWord(fd_reg(instr), static_cast<int32_t>(rj(instr)));
4559 break;
4560 }
4561 case op_movfr2gr_s: {
4562 setRegister(rd_reg(instr),
4563 static_cast<int64_t>(getFpuRegisterWord(fj_reg(instr))));
4564 break;
4565 }
4566 case op_movfr2gr_d: {
4567 setRegister(rd_reg(instr), getFpuRegister(fj_reg(instr)));
4568 break;
4569 }
4570 case op_movfrh2gr_s: {
4571 setRegister(rd_reg(instr), getFpuRegisterHiWord(fj_reg(instr)));
4572 break;
4573 }
4574 case op_movgr2fcsr: {
4575 // fcsr could be 0-3
4576 MOZ_ASSERT(rd_reg(instr) < 4);
4577 FCSR_ = static_cast<uint32_t>(rj(instr));
4578 break;
4579 }
4580 case op_movfcsr2gr: {
4581 setRegister(rd_reg(instr), FCSR_);
4582 break;
4583 }
4584 case op_fcvt_s_d: {
4585 setFpuRegisterFloat(fd_reg(instr), static_cast<float>(fj_double(instr)));
4586 break;
4587 }
4588 case op_fcvt_d_s: {
4589 setFpuRegisterDouble(fd_reg(instr), static_cast<double>(fj_float(instr)));
4590 break;
4591 }
4592 case op_ftintrm_w_s: {
4593 float fj = fj_float(instr);
4594 float rounded = std::floor(fj);
4595 int32_t result = static_cast<int32_t>(rounded);
4596 setFpuRegisterWord(fd_reg(instr), result);
4597 if (setFCSRRoundError<int32_t>(fj, rounded)) {
4598 setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr));
4599 }
4600 break;
4601 }
4602 case op_ftintrm_w_d: {
4603 double fj = fj_double(instr);
4604 double rounded = std::floor(fj);
4605 int32_t result = static_cast<int32_t>(rounded);
4606 setFpuRegisterWord(fd_reg(instr), result);
4607 if (setFCSRRoundError<int32_t>(fj, rounded)) {
4608 setFpuRegisterInvalidResult(fj, rounded, fd_reg(instr));
4609 }
4610 break;
4611 }
4612 case op_ftintrm_l_s: {
4613 float fj = fj_float(instr);
4614 float rounded = std::floor(fj);
4615 int64_t result = static_cast<int64_t>(rounded);
4616 setFpuRegister(fd_reg(instr), result);
4617 if (setFCSRRoundError<int64_t>(fj, rounded)) {
4618 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
4619 }
4620 break;
4621 }
4622 case op_ftintrm_l_d: {
4623 double fj = fj_double(instr);
4624 double rounded = std::floor(fj);
4625 int64_t result = static_cast<int64_t>(rounded);
4626 setFpuRegister(fd_reg(instr), result);
4627 if (setFCSRRoundError<int64_t>(fj, rounded)) {
4628 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
4629 }
4630 break;
4631 }
4632 case op_ftintrp_w_s: {
4633 float fj = fj_float(instr);
4634 float rounded = std::ceil(fj);
4635 int32_t result = static_cast<int32_t>(rounded);
4636 setFpuRegisterWord(fd_reg(instr), result);
4637 if (setFCSRRoundError<int32_t>(fj, rounded)) {
4638 setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr));
4639 }
4640 break;
4641 }
4642 case op_ftintrp_w_d: {
4643 double fj = fj_double(instr);
4644 double rounded = std::ceil(fj);
4645 int32_t result = static_cast<int32_t>(rounded);
4646 setFpuRegisterWord(fd_reg(instr), result);
4647 if (setFCSRRoundError<int32_t>(fj, rounded)) {
4648 setFpuRegisterInvalidResult(fj, rounded, fd_reg(instr));
4649 }
4650 break;
4651 }
4652 case op_ftintrp_l_s: {
4653 float fj = fj_float(instr);
4654 float rounded = std::ceil(fj);
4655 int64_t result = static_cast<int64_t>(rounded);
4656 setFpuRegister(fd_reg(instr), result);
4657 if (setFCSRRoundError<int64_t>(fj, rounded)) {
4658 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
4659 }
4660 break;
4661 }
4662 case op_ftintrp_l_d: {
4663 double fj = fj_double(instr);
4664 double rounded = std::ceil(fj);
4665 int64_t result = static_cast<int64_t>(rounded);
4666 setFpuRegister(fd_reg(instr), result);
4667 if (setFCSRRoundError<int64_t>(fj, rounded)) {
4668 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
4669 }
4670 break;
4671 }
4672 case op_ftintrz_w_s: {
4673 float fj = fj_float(instr);
4674 float rounded = std::trunc(fj);
4675 int32_t result = static_cast<int32_t>(rounded);
4676 setFpuRegisterWord(fd_reg(instr), result);
4677 if (setFCSRRoundError<int32_t>(fj, rounded)) {
4678 setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr));
4679 }
4680 break;
4681 }
4682 case op_ftintrz_w_d: {
4683 double fj = fj_double(instr);
4684 double rounded = std::trunc(fj);
4685 int32_t result = static_cast<int32_t>(rounded);
4686 setFpuRegisterWord(fd_reg(instr), result);
4687 if (setFCSRRoundError<int32_t>(fj, rounded)) {
4688 setFpuRegisterInvalidResult(fj, rounded, fd_reg(instr));
4689 }
4690 break;
4691 }
4692 case op_ftintrz_l_s: {
4693 float fj = fj_float(instr);
4694 float rounded = std::trunc(fj);
4695 int64_t result = static_cast<int64_t>(rounded);
4696 setFpuRegister(fd_reg(instr), result);
4697 if (setFCSRRoundError<int64_t>(fj, rounded)) {
4698 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
4699 }
4700 break;
4701 }
4702 case op_ftintrz_l_d: {
4703 double fj = fj_double(instr);
4704 double rounded = std::trunc(fj);
4705 int64_t result = static_cast<int64_t>(rounded);
4706 setFpuRegister(fd_reg(instr), result);
4707 if (setFCSRRoundError<int64_t>(fj, rounded)) {
4708 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
4709 }
4710 break;
4711 }
4712 case op_ftintrne_w_s: {
4713 float fj = fj_float(instr);
4714 float rounded = std::floor(fj + 0.5);
4715 int32_t result = static_cast<int32_t>(rounded);
4716 if ((result & 1) != 0 && result - fj == 0.5) {
4717 // If the number is halfway between two integers,
4718 // round to the even one.
4719 result--;
4720 }
4721 setFpuRegisterWord(fd_reg(instr), result);
4722 if (setFCSRRoundError<int32_t>(fj, rounded)) {
4723 setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr));
4724 }
4725 break;
4726 }
4727 case op_ftintrne_w_d: {
4728 double fj = fj_double(instr);
4729 double rounded = std::floor(fj + 0.5);
4730 int32_t result = static_cast<int32_t>(rounded);
4731 if ((result & 1) != 0 && result - fj == 0.5) {
4732 // If the number is halfway between two integers,
4733 // round to the even one.
4734 result--;
4735 }
4736 setFpuRegisterWord(fd_reg(instr), result);
4737 if (setFCSRRoundError<int32_t>(fj, rounded)) {
4738 setFpuRegisterInvalidResult(fj, rounded, fd_reg(instr));
4739 }
4740 break;
4741 }
4742 case op_ftintrne_l_s: {
4743 float fj = fj_float(instr);
4744 float rounded = std::floor(fj + 0.5);
4745 int64_t result = static_cast<int64_t>(rounded);
4746 if ((result & 1) != 0 && result - fj == 0.5) {
4747 // If the number is halfway between two integers,
4748 // round to the even one.
4749 result--;
4750 }
4751 setFpuRegister(fd_reg(instr), result);
4752 if (setFCSRRoundError<int64_t>(fj, rounded)) {
4753 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
4754 }
4755 break;
4756 }
4757 case op_ftintrne_l_d: {
4758 double fj = fj_double(instr);
4759 double rounded = std::floor(fj + 0.5);
4760 int64_t result = static_cast<int64_t>(rounded);
4761 if ((result & 1) != 0 && result - fj == 0.5) {
4762 // If the number is halfway between two integers,
4763 // round to the even one.
4764 result--;
4765 }
4766 setFpuRegister(fd_reg(instr), result);
4767 if (setFCSRRoundError<int64_t>(fj, rounded)) {
4768 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
4769 }
4770 break;
4771 }
4772 case op_ftint_w_s: {
4773 float fj = fj_float(instr);
4774 float rounded;
4775 int32_t result;
4776 roundAccordingToFCSR<float>(fj, &rounded, &result);
4777 setFpuRegisterWord(fd_reg(instr), result);
4778 if (setFCSRRoundError<int32_t>(fj, rounded)) {
4779 setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr));
4780 }
4781 break;
4782 }
4783 case op_ftint_w_d: {
4784 double fj = fj_double(instr);
4785 double rounded;
4786 int32_t result;
4787 roundAccordingToFCSR<double>(fj, &rounded, &result);
4788 setFpuRegisterWord(fd_reg(instr), result);
4789 if (setFCSRRoundError<int32_t>(fj, rounded)) {
4790 setFpuRegisterWordInvalidResult(fj, rounded, fd_reg(instr));
4791 }
4792 break;
4793 }
4794 case op_ftint_l_s: {
4795 float fj = fj_float(instr);
4796 float rounded;
4797 int64_t result;
4798 round64AccordingToFCSR<float>(fj, &rounded, &result);
4799 setFpuRegister(fd_reg(instr), result);
4800 if (setFCSRRoundError<int64_t>(fj, rounded)) {
4801 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
4802 }
4803 break;
4804 }
4805 case op_ftint_l_d: {
4806 double fj = fj_double(instr);
4807 double rounded;
4808 int64_t result;
4809 round64AccordingToFCSR<double>(fj, &rounded, &result);
4810 setFpuRegister(fd_reg(instr), result);
4811 if (setFCSRRoundError<int64_t>(fj, rounded)) {
4812 setFpuRegisterInvalidResult64(fj, rounded, fd_reg(instr));
4813 }
4814 break;
4815 }
4816 case op_ffint_s_w: {
4817 alu_out = getFpuRegisterSignedWord(fj_reg(instr));
4818 setFpuRegisterFloat(fd_reg(instr), static_cast<float>(alu_out));
4819 break;
4820 }
4821 case op_ffint_s_l: {
4822 alu_out = getFpuRegister(fj_reg(instr));
4823 setFpuRegisterFloat(fd_reg(instr), static_cast<float>(alu_out));
4824 break;
4825 }
4826 case op_ffint_d_w: {
4827 alu_out = getFpuRegisterSignedWord(fj_reg(instr));
4828 setFpuRegisterDouble(fd_reg(instr), static_cast<double>(alu_out));
4829 break;
4830 }
4831 case op_ffint_d_l: {
4832 alu_out = getFpuRegister(fj_reg(instr));
4833 setFpuRegisterDouble(fd_reg(instr), static_cast<double>(alu_out));
4834 break;
4835 }
4836 case op_frint_s: {
4837 float fj = fj_float(instr);
4838 float result, temp_result;
4839 double temp;
4840 float upper = std::ceil(fj);
4841 float lower = std::floor(fj);
4842 switch (getFCSRRoundingMode()) {
4843 case kRoundToNearest:
4844 if (upper - fj < fj - lower) {
4845 result = upper;
4846 } else if (upper - fj > fj - lower) {
4847 result = lower;
4848 } else {
4849 temp_result = upper / 2;
4850 float reminder = std::modf(temp_result, &temp);
4851 if (reminder == 0) {
4852 result = upper;
4853 } else {
4854 result = lower;
4855 }
4856 }
4857 break;
4858 case kRoundToZero:
4859 result = (fj > 0 ? lower : upper);
4860 break;
4861 case kRoundToPlusInf:
4862 result = upper;
4863 break;
4864 case kRoundToMinusInf:
4865 result = lower;
4866 break;
4867 }
4868 setFpuRegisterFloat(fd_reg(instr), result);
4869 if (result != fj) {
4870 setFCSRBit(kFCSRInexactFlagBit, true);
4871 }
4872 break;
4873 }
4874 case op_frint_d: {
4875 double fj = fj_double(instr);
4876 double result, temp, temp_result;
4877 double upper = std::ceil(fj);
4878 double lower = std::floor(fj);
4879 switch (getFCSRRoundingMode()) {
4880 case kRoundToNearest:
4881 if (upper - fj < fj - lower) {
4882 result = upper;
4883 } else if (upper - fj > fj - lower) {
4884 result = lower;
4885 } else {
4886 temp_result = upper / 2;
4887 double reminder = std::modf(temp_result, &temp);
4888 if (reminder == 0) {
4889 result = upper;
4890 } else {
4891 result = lower;
4892 }
4893 }
4894 break;
4895 case kRoundToZero:
4896 result = (fj > 0 ? lower : upper);
4897 break;
4898 case kRoundToPlusInf:
4899 result = upper;
4900 break;
4901 case kRoundToMinusInf:
4902 result = lower;
4903 break;
4904 }
4905 setFpuRegisterDouble(fd_reg(instr), result);
4906 if (result != fj) {
4907 setFCSRBit(kFCSRInexactFlagBit, true);
4908 }
4909 break;
4910 }
4911 case op_movfr2cf:
4912 printf("Sim UNIMPLEMENTED: MOVFR2CF\n");
4913 UNIMPLEMENTED();
4914 break;
4915 case op_movgr2cf:
4916 printf("Sim UNIMPLEMENTED: MOVGR2CF\n");
4917 UNIMPLEMENTED();
4918 break;
4919 case op_clo_w:
4920 printf("Sim UNIMPLEMENTED: FCO_W\n");
4921 UNIMPLEMENTED();
4922 break;
4923 case op_cto_w:
4924 printf("Sim UNIMPLEMENTED: FTO_W\n");
4925 UNIMPLEMENTED();
4926 break;
4927 case op_clo_d:
4928 printf("Sim UNIMPLEMENTED: FLO_D\n");
4929 UNIMPLEMENTED();
4930 break;
4931 case op_cto_d:
4932 printf("Sim UNIMPLEMENTED: FTO_D\n");
4933 UNIMPLEMENTED();
4934 break;
4935 // Unimplemented opcodes raised an error in the configuration step before,
4936 // so we can use the default here to set the destination register in common
4937 // cases.
4938 default:
4939 UNREACHABLE();
4940 }
4941 }
4942
decodeTypeOp24(SimInstruction * instr)4943 void Simulator::decodeTypeOp24(SimInstruction* instr) {
4944 switch (instr->bits(31, 8) << 8) {
4945 case op_movcf2fr:
4946 UNIMPLEMENTED();
4947 break;
4948 case op_movcf2gr:
4949 setRegister(rd_reg(instr), getCFRegister(cj_reg(instr)));
4950 break;
4951 UNIMPLEMENTED();
4952 break;
4953 default:
4954 UNREACHABLE();
4955 }
4956 }
4957
4958 // Executes the current instruction.
instructionDecode(SimInstruction * instr)4959 void Simulator::instructionDecode(SimInstruction* instr) {
4960 if (!SimulatorProcess::ICacheCheckingDisableCount) {
4961 AutoLockSimulatorCache als;
4962 SimulatorProcess::checkICacheLocked(instr);
4963 }
4964 pc_modified_ = false;
4965
4966 switch (instr->instructionType()) {
4967 case SimInstruction::kOp6Type:
4968 decodeTypeOp6(instr);
4969 break;
4970 case SimInstruction::kOp7Type:
4971 decodeTypeOp7(instr);
4972 break;
4973 case SimInstruction::kOp8Type:
4974 decodeTypeOp8(instr);
4975 break;
4976 case SimInstruction::kOp10Type:
4977 decodeTypeOp10(instr);
4978 break;
4979 case SimInstruction::kOp11Type:
4980 decodeTypeOp11(instr);
4981 break;
4982 case SimInstruction::kOp12Type:
4983 decodeTypeOp12(instr);
4984 break;
4985 case SimInstruction::kOp14Type:
4986 decodeTypeOp14(instr);
4987 break;
4988 case SimInstruction::kOp15Type:
4989 decodeTypeOp15(instr);
4990 break;
4991 case SimInstruction::kOp16Type:
4992 decodeTypeOp16(instr);
4993 break;
4994 case SimInstruction::kOp17Type:
4995 decodeTypeOp17(instr);
4996 break;
4997 case SimInstruction::kOp22Type:
4998 decodeTypeOp22(instr);
4999 break;
5000 case SimInstruction::kOp24Type:
5001 decodeTypeOp24(instr);
5002 break;
5003 default:
5004 UNSUPPORTED();
5005 }
5006 if (!pc_modified_) {
5007 setRegister(pc,
5008 reinterpret_cast<int64_t>(instr) + SimInstruction::kInstrSize);
5009 }
5010 }
5011
enable_single_stepping(SingleStepCallback cb,void * arg)5012 void Simulator::enable_single_stepping(SingleStepCallback cb, void* arg) {
5013 single_stepping_ = true;
5014 single_step_callback_ = cb;
5015 single_step_callback_arg_ = arg;
5016 single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
5017 }
5018
disable_single_stepping()5019 void Simulator::disable_single_stepping() {
5020 if (!single_stepping_) {
5021 return;
5022 }
5023 single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
5024 single_stepping_ = false;
5025 single_step_callback_ = nullptr;
5026 single_step_callback_arg_ = nullptr;
5027 }
5028
5029 template <bool enableStopSimAt>
execute()5030 void Simulator::execute() {
5031 if (single_stepping_) {
5032 single_step_callback_(single_step_callback_arg_, this, nullptr);
5033 }
5034
5035 // Get the PC to simulate. Cannot use the accessor here as we need the
5036 // raw PC value and not the one used as input to arithmetic instructions.
5037 int64_t program_counter = get_pc();
5038
5039 while (program_counter != end_sim_pc) {
5040 if (enableStopSimAt && (icount_ == Simulator::StopSimAt)) {
5041 loong64Debugger dbg(this);
5042 dbg.debug();
5043 } else {
5044 if (single_stepping_) {
5045 single_step_callback_(single_step_callback_arg_, this,
5046 (void*)program_counter);
5047 }
5048 SimInstruction* instr =
5049 reinterpret_cast<SimInstruction*>(program_counter);
5050 instructionDecode(instr);
5051 icount_++;
5052 }
5053 program_counter = get_pc();
5054 }
5055
5056 if (single_stepping_) {
5057 single_step_callback_(single_step_callback_arg_, this, nullptr);
5058 }
5059 }
5060
callInternal(uint8_t * entry)5061 void Simulator::callInternal(uint8_t* entry) {
5062 // Prepare to execute the code at entry.
5063 setRegister(pc, reinterpret_cast<int64_t>(entry));
5064 // Put down marker for end of simulation. The simulator will stop simulation
5065 // when the PC reaches this value. By saving the "end simulation" value into
5066 // the LR the simulation stops when returning to this call point.
5067 setRegister(ra, end_sim_pc);
5068
5069 // Remember the values of callee-saved registers.
5070 // The code below assumes that r9 is not used as sb (static base) in
5071 // simulator code and therefore is regarded as a callee-saved register.
5072 int64_t s0_val = getRegister(s0);
5073 int64_t s1_val = getRegister(s1);
5074 int64_t s2_val = getRegister(s2);
5075 int64_t s3_val = getRegister(s3);
5076 int64_t s4_val = getRegister(s4);
5077 int64_t s5_val = getRegister(s5);
5078 int64_t s6_val = getRegister(s6);
5079 int64_t s7_val = getRegister(s7);
5080 int64_t s8_val = getRegister(s8);
5081 int64_t gp_val = getRegister(gp);
5082 int64_t sp_val = getRegister(sp);
5083 int64_t tp_val = getRegister(tp);
5084 int64_t fp_val = getRegister(fp);
5085
5086 // Set up the callee-saved registers with a known value. To be able to check
5087 // that they are preserved properly across JS execution.
5088 int64_t callee_saved_value = icount_;
5089 setRegister(s0, callee_saved_value);
5090 setRegister(s1, callee_saved_value);
5091 setRegister(s2, callee_saved_value);
5092 setRegister(s3, callee_saved_value);
5093 setRegister(s4, callee_saved_value);
5094 setRegister(s5, callee_saved_value);
5095 setRegister(s6, callee_saved_value);
5096 setRegister(s7, callee_saved_value);
5097 setRegister(s8, callee_saved_value);
5098 setRegister(gp, callee_saved_value);
5099 setRegister(tp, callee_saved_value);
5100 setRegister(fp, callee_saved_value);
5101
5102 // Start the simulation.
5103 if (Simulator::StopSimAt != -1) {
5104 execute<true>();
5105 } else {
5106 execute<false>();
5107 }
5108
5109 // Check that the callee-saved registers have been preserved.
5110 MOZ_ASSERT(callee_saved_value == getRegister(s0));
5111 MOZ_ASSERT(callee_saved_value == getRegister(s1));
5112 MOZ_ASSERT(callee_saved_value == getRegister(s2));
5113 MOZ_ASSERT(callee_saved_value == getRegister(s3));
5114 MOZ_ASSERT(callee_saved_value == getRegister(s4));
5115 MOZ_ASSERT(callee_saved_value == getRegister(s5));
5116 MOZ_ASSERT(callee_saved_value == getRegister(s6));
5117 MOZ_ASSERT(callee_saved_value == getRegister(s7));
5118 MOZ_ASSERT(callee_saved_value == getRegister(s8));
5119 MOZ_ASSERT(callee_saved_value == getRegister(gp));
5120 MOZ_ASSERT(callee_saved_value == getRegister(tp));
5121 MOZ_ASSERT(callee_saved_value == getRegister(fp));
5122
5123 // Restore callee-saved registers with the original value.
5124 setRegister(s0, s0_val);
5125 setRegister(s1, s1_val);
5126 setRegister(s2, s2_val);
5127 setRegister(s3, s3_val);
5128 setRegister(s4, s4_val);
5129 setRegister(s5, s5_val);
5130 setRegister(s6, s6_val);
5131 setRegister(s7, s7_val);
5132 setRegister(s8, s8_val);
5133 setRegister(gp, gp_val);
5134 setRegister(sp, sp_val);
5135 setRegister(tp, tp_val);
5136 setRegister(fp, fp_val);
5137 }
5138
call(uint8_t * entry,int argument_count,...)5139 int64_t Simulator::call(uint8_t* entry, int argument_count, ...) {
5140 va_list parameters;
5141 va_start(parameters, argument_count);
5142
5143 int64_t original_stack = getRegister(sp);
5144 // Compute position of stack on entry to generated code.
5145 int64_t entry_stack = original_stack;
5146 if (argument_count > kCArgSlotCount) {
5147 entry_stack = entry_stack - argument_count * sizeof(int64_t);
5148 } else {
5149 entry_stack = entry_stack - kCArgsSlotsSize;
5150 }
5151
5152 entry_stack &= ~U64(ABIStackAlignment - 1);
5153
5154 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
5155
5156 // Setup the arguments.
5157 for (int i = 0; i < argument_count; i++) {
5158 js::jit::Register argReg;
5159 if (GetIntArgReg(i, &argReg)) {
5160 setRegister(argReg.code(), va_arg(parameters, int64_t));
5161 } else {
5162 stack_argument[i] = va_arg(parameters, int64_t);
5163 }
5164 }
5165
5166 va_end(parameters);
5167 setRegister(sp, entry_stack);
5168
5169 callInternal(entry);
5170
5171 // Pop stack passed arguments.
5172 MOZ_ASSERT(entry_stack == getRegister(sp));
5173 setRegister(sp, original_stack);
5174
5175 int64_t result = getRegister(a0);
5176 return result;
5177 }
5178
pushAddress(uintptr_t address)5179 uintptr_t Simulator::pushAddress(uintptr_t address) {
5180 int new_sp = getRegister(sp) - sizeof(uintptr_t);
5181 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
5182 *stack_slot = address;
5183 setRegister(sp, new_sp);
5184 return new_sp;
5185 }
5186
popAddress()5187 uintptr_t Simulator::popAddress() {
5188 int current_sp = getRegister(sp);
5189 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
5190 uintptr_t address = *stack_slot;
5191 setRegister(sp, current_sp + sizeof(uintptr_t));
5192 return address;
5193 }
5194
5195 } // namespace jit
5196 } // namespace js
5197
simulator() const5198 js::jit::Simulator* JSContext::simulator() const { return simulator_; }
5199