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