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  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef jit_mips_shared_Assembler_mips_shared_h
8 #define jit_mips_shared_Assembler_mips_shared_h
9 
10 #include "mozilla/Attributes.h"
11 #include "mozilla/MathAlgorithms.h"
12 #include "mozilla/Sprintf.h"
13 
14 #include "jit/CompactBuffer.h"
15 #include "jit/JitCode.h"
16 #include "jit/JitSpewer.h"
17 #include "jit/mips-shared/Architecture-mips-shared.h"
18 #include "jit/shared/Assembler-shared.h"
19 #include "jit/shared/IonAssemblerBuffer.h"
20 #include "wasm/WasmTypes.h"
21 
22 namespace js {
23 namespace jit {
24 
25 static constexpr Register zero{Registers::zero};
26 static constexpr Register at{Registers::at};
27 static constexpr Register v0{Registers::v0};
28 static constexpr Register v1{Registers::v1};
29 static constexpr Register a0{Registers::a0};
30 static constexpr Register a1{Registers::a1};
31 static constexpr Register a2{Registers::a2};
32 static constexpr Register a3{Registers::a3};
33 static constexpr Register a4{Registers::ta0};
34 static constexpr Register a5{Registers::ta1};
35 static constexpr Register a6{Registers::ta2};
36 static constexpr Register a7{Registers::ta3};
37 static constexpr Register t0{Registers::t0};
38 static constexpr Register t1{Registers::t1};
39 static constexpr Register t2{Registers::t2};
40 static constexpr Register t3{Registers::t3};
41 static constexpr Register t4{Registers::ta0};
42 static constexpr Register t5{Registers::ta1};
43 static constexpr Register t6{Registers::ta2};
44 static constexpr Register t7{Registers::ta3};
45 static constexpr Register s0{Registers::s0};
46 static constexpr Register s1{Registers::s1};
47 static constexpr Register s2{Registers::s2};
48 static constexpr Register s3{Registers::s3};
49 static constexpr Register s4{Registers::s4};
50 static constexpr Register s5{Registers::s5};
51 static constexpr Register s6{Registers::s6};
52 static constexpr Register s7{Registers::s7};
53 static constexpr Register t8{Registers::t8};
54 static constexpr Register t9{Registers::t9};
55 static constexpr Register k0{Registers::k0};
56 static constexpr Register k1{Registers::k1};
57 static constexpr Register gp{Registers::gp};
58 static constexpr Register sp{Registers::sp};
59 static constexpr Register fp{Registers::fp};
60 static constexpr Register ra{Registers::ra};
61 
62 static constexpr Register ScratchRegister = at;
63 static constexpr Register SecondScratchReg = t8;
64 
65 // Helper classes for ScratchRegister usage. Asserts that only one piece
66 // of code thinks it has exclusive ownership of each scratch register.
67 struct ScratchRegisterScope : public AutoRegisterScope {
ScratchRegisterScopeScratchRegisterScope68   explicit ScratchRegisterScope(MacroAssembler& masm)
69       : AutoRegisterScope(masm, ScratchRegister) {}
70 };
71 struct SecondScratchRegisterScope : public AutoRegisterScope {
SecondScratchRegisterScopeSecondScratchRegisterScope72   explicit SecondScratchRegisterScope(MacroAssembler& masm)
73       : AutoRegisterScope(masm, SecondScratchReg) {}
74 };
75 
76 // Use arg reg from EnterJIT function as OsrFrameReg.
77 static constexpr Register OsrFrameReg = a3;
78 static constexpr Register CallTempReg0 = t0;
79 static constexpr Register CallTempReg1 = t1;
80 static constexpr Register CallTempReg2 = t2;
81 static constexpr Register CallTempReg3 = t3;
82 
83 static constexpr Register IntArgReg0 = a0;
84 static constexpr Register IntArgReg1 = a1;
85 static constexpr Register IntArgReg2 = a2;
86 static constexpr Register IntArgReg3 = a3;
87 static constexpr Register IntArgReg4 = a4;
88 static constexpr Register IntArgReg5 = a5;
89 static constexpr Register IntArgReg6 = a6;
90 static constexpr Register IntArgReg7 = a7;
91 static constexpr Register GlobalReg = s6;  // used by Odin
92 static constexpr Register HeapReg = s7;    // used by Odin
93 
94 static constexpr Register PreBarrierReg = a1;
95 
96 static constexpr Register InvalidReg{Registers::invalid_reg};
97 static constexpr FloatRegister InvalidFloatReg;
98 
99 static constexpr Register StackPointer = sp;
100 static constexpr Register FramePointer = fp;
101 static constexpr Register ReturnReg = v0;
102 static constexpr FloatRegister ReturnSimd128Reg = InvalidFloatReg;
103 static constexpr FloatRegister ScratchSimd128Reg = InvalidFloatReg;
104 
105 // A bias applied to the GlobalReg to allow the use of instructions with small
106 // negative immediate offsets which doubles the range of global data that can be
107 // accessed with a single instruction.
108 static const int32_t WasmGlobalRegBias = 32768;
109 
110 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
111 static constexpr Register RegExpMatcherRegExpReg = CallTempReg0;
112 static constexpr Register RegExpMatcherStringReg = CallTempReg1;
113 static constexpr Register RegExpMatcherLastIndexReg = CallTempReg2;
114 
115 // Registerd used in RegExpTester instruction (do not use ReturnReg).
116 static constexpr Register RegExpTesterRegExpReg = CallTempReg0;
117 static constexpr Register RegExpTesterStringReg = CallTempReg1;
118 static constexpr Register RegExpTesterLastIndexReg = CallTempReg2;
119 
120 static constexpr uint32_t CodeAlignment = 8;
121 
122 /* clang-format off */
123 // MIPS instruction types
124 //                +---------------------------------------------------------------+
125 //                |    6      |    5    |    5    |    5    |    5    |    6      |
126 //                +---------------------------------------------------------------+
127 // Register type  |  Opcode   |    Rs   |    Rt   |    Rd   |    Sa   | Function  |
128 //                +---------------------------------------------------------------+
129 //                |    6      |    5    |    5    |               16              |
130 //                +---------------------------------------------------------------+
131 // Immediate type |  Opcode   |    Rs   |    Rt   |    2's complement constant    |
132 //                +---------------------------------------------------------------+
133 //                |    6      |                        26                         |
134 //                +---------------------------------------------------------------+
135 // Jump type      |  Opcode   |                    jump_target                    |
136 //                +---------------------------------------------------------------+
137 //                31 bit                                                      bit 0
138 /* clang-format on */
139 
140 // MIPS instruction encoding constants.
141 static const uint32_t OpcodeShift = 26;
142 static const uint32_t OpcodeBits = 6;
143 static const uint32_t RSShift = 21;
144 static const uint32_t RSBits = 5;
145 static const uint32_t RTShift = 16;
146 static const uint32_t RTBits = 5;
147 static const uint32_t RDShift = 11;
148 static const uint32_t RDBits = 5;
149 static const uint32_t RZShift = 0;
150 static const uint32_t RZBits = 5;
151 static const uint32_t SAShift = 6;
152 static const uint32_t SABits = 5;
153 static const uint32_t FunctionShift = 0;
154 static const uint32_t FunctionBits = 6;
155 static const uint32_t Imm16Shift = 0;
156 static const uint32_t Imm16Bits = 16;
157 static const uint32_t Imm26Shift = 0;
158 static const uint32_t Imm26Bits = 26;
159 static const uint32_t Imm28Shift = 0;
160 static const uint32_t Imm28Bits = 28;
161 static const uint32_t ImmFieldShift = 2;
162 static const uint32_t FRBits = 5;
163 static const uint32_t FRShift = 21;
164 static const uint32_t FSShift = 11;
165 static const uint32_t FSBits = 5;
166 static const uint32_t FTShift = 16;
167 static const uint32_t FTBits = 5;
168 static const uint32_t FDShift = 6;
169 static const uint32_t FDBits = 5;
170 static const uint32_t FCccShift = 8;
171 static const uint32_t FCccBits = 3;
172 static const uint32_t FBccShift = 18;
173 static const uint32_t FBccBits = 3;
174 static const uint32_t FBtrueShift = 16;
175 static const uint32_t FBtrueBits = 1;
176 static const uint32_t FccMask = 0x7;
177 static const uint32_t FccShift = 2;
178 
179 // MIPS instruction  field bit masks.
180 static const uint32_t OpcodeMask = ((1 << OpcodeBits) - 1) << OpcodeShift;
181 static const uint32_t Imm16Mask = ((1 << Imm16Bits) - 1) << Imm16Shift;
182 static const uint32_t Imm26Mask = ((1 << Imm26Bits) - 1) << Imm26Shift;
183 static const uint32_t Imm28Mask = ((1 << Imm28Bits) - 1) << Imm28Shift;
184 static const uint32_t RSMask = ((1 << RSBits) - 1) << RSShift;
185 static const uint32_t RTMask = ((1 << RTBits) - 1) << RTShift;
186 static const uint32_t RDMask = ((1 << RDBits) - 1) << RDShift;
187 static const uint32_t SAMask = ((1 << SABits) - 1) << SAShift;
188 static const uint32_t FunctionMask = ((1 << FunctionBits) - 1) << FunctionShift;
189 static const uint32_t RegMask = Registers::Total - 1;
190 
191 static const uint32_t BREAK_STACK_UNALIGNED = 1;
192 static const uint32_t MAX_BREAK_CODE = 1024 - 1;
193 static const uint32_t WASM_TRAP = 6;  // BRK_OVERFLOW
194 
195 class Instruction;
196 class InstReg;
197 class InstImm;
198 class InstJump;
199 
200 uint32_t RS(Register r);
201 uint32_t RT(Register r);
202 uint32_t RT(FloatRegister r);
203 uint32_t RD(Register r);
204 uint32_t RD(FloatRegister r);
205 uint32_t RZ(Register r);
206 uint32_t RZ(FloatRegister r);
207 uint32_t SA(uint32_t value);
208 uint32_t SA(FloatRegister r);
209 uint32_t FS(uint32_t value);
210 
211 Register toRS(Instruction& i);
212 Register toRT(Instruction& i);
213 Register toRD(Instruction& i);
214 Register toR(Instruction& i);
215 
216 // MIPS enums for instruction fields
217 enum OpcodeField {
218   op_special = 0 << OpcodeShift,
219   op_regimm = 1 << OpcodeShift,
220 
221   op_j = 2 << OpcodeShift,
222   op_jal = 3 << OpcodeShift,
223   op_beq = 4 << OpcodeShift,
224   op_bne = 5 << OpcodeShift,
225   op_blez = 6 << OpcodeShift,
226   op_bgtz = 7 << OpcodeShift,
227 
228   op_addi = 8 << OpcodeShift,
229   op_addiu = 9 << OpcodeShift,
230   op_slti = 10 << OpcodeShift,
231   op_sltiu = 11 << OpcodeShift,
232   op_andi = 12 << OpcodeShift,
233   op_ori = 13 << OpcodeShift,
234   op_xori = 14 << OpcodeShift,
235   op_lui = 15 << OpcodeShift,
236 
237   op_cop1 = 17 << OpcodeShift,
238   op_cop1x = 19 << OpcodeShift,
239 
240   op_beql = 20 << OpcodeShift,
241   op_bnel = 21 << OpcodeShift,
242   op_blezl = 22 << OpcodeShift,
243   op_bgtzl = 23 << OpcodeShift,
244 
245   op_daddi = 24 << OpcodeShift,
246   op_daddiu = 25 << OpcodeShift,
247 
248   op_ldl = 26 << OpcodeShift,
249   op_ldr = 27 << OpcodeShift,
250 
251   op_special2 = 28 << OpcodeShift,
252   op_special3 = 31 << OpcodeShift,
253 
254   op_lb = 32 << OpcodeShift,
255   op_lh = 33 << OpcodeShift,
256   op_lwl = 34 << OpcodeShift,
257   op_lw = 35 << OpcodeShift,
258   op_lbu = 36 << OpcodeShift,
259   op_lhu = 37 << OpcodeShift,
260   op_lwr = 38 << OpcodeShift,
261   op_lwu = 39 << OpcodeShift,
262   op_sb = 40 << OpcodeShift,
263   op_sh = 41 << OpcodeShift,
264   op_swl = 42 << OpcodeShift,
265   op_sw = 43 << OpcodeShift,
266   op_sdl = 44 << OpcodeShift,
267   op_sdr = 45 << OpcodeShift,
268   op_swr = 46 << OpcodeShift,
269 
270   op_ll = 48 << OpcodeShift,
271   op_lwc1 = 49 << OpcodeShift,
272   op_lwc2 = 50 << OpcodeShift,
273   op_lld = 52 << OpcodeShift,
274   op_ldc1 = 53 << OpcodeShift,
275   op_ldc2 = 54 << OpcodeShift,
276   op_ld = 55 << OpcodeShift,
277 
278   op_sc = 56 << OpcodeShift,
279   op_swc1 = 57 << OpcodeShift,
280   op_swc2 = 58 << OpcodeShift,
281   op_scd = 60 << OpcodeShift,
282   op_sdc1 = 61 << OpcodeShift,
283   op_sdc2 = 62 << OpcodeShift,
284   op_sd = 63 << OpcodeShift,
285 };
286 
287 enum RSField {
288   rs_zero = 0 << RSShift,
289   // cop1 encoding of RS field.
290   rs_mfc1 = 0 << RSShift,
291   rs_one = 1 << RSShift,
292   rs_dmfc1 = 1 << RSShift,
293   rs_cfc1 = 2 << RSShift,
294   rs_mfhc1 = 3 << RSShift,
295   rs_mtc1 = 4 << RSShift,
296   rs_dmtc1 = 5 << RSShift,
297   rs_ctc1 = 6 << RSShift,
298   rs_mthc1 = 7 << RSShift,
299   rs_bc1 = 8 << RSShift,
300   rs_f = 0x9 << RSShift,
301   rs_t = 0xd << RSShift,
302   rs_s_r6 = 20 << RSShift,
303   rs_d_r6 = 21 << RSShift,
304   rs_s = 16 << RSShift,
305   rs_d = 17 << RSShift,
306   rs_w = 20 << RSShift,
307   rs_l = 21 << RSShift,
308   rs_ps = 22 << RSShift
309 };
310 
311 enum RTField {
312   rt_zero = 0 << RTShift,
313   // regimm  encoding of RT field.
314   rt_bltz = 0 << RTShift,
315   rt_bgez = 1 << RTShift,
316   rt_bltzal = 16 << RTShift,
317   rt_bgezal = 17 << RTShift
318 };
319 
320 enum FunctionField {
321   // special encoding of function field.
322   ff_sll = 0,
323   ff_movci = 1,
324   ff_srl = 2,
325   ff_sra = 3,
326   ff_sllv = 4,
327   ff_srlv = 6,
328   ff_srav = 7,
329 
330   ff_jr = 8,
331   ff_jalr = 9,
332   ff_movz = 10,
333   ff_movn = 11,
334   ff_break = 13,
335   ff_sync = 15,
336 
337   ff_mfhi = 16,
338   ff_mflo = 18,
339 
340   ff_dsllv = 20,
341   ff_dsrlv = 22,
342   ff_dsrav = 23,
343 
344   ff_mult = 24,
345   ff_multu = 25,
346 
347   ff_mulu = 25,
348   ff_muh = 24,
349   ff_muhu = 25,
350   ff_dmul = 28,
351   ff_dmulu = 29,
352   ff_dmuh = 28,
353   ff_dmuhu = 29,
354 
355   ff_div = 26,
356   ff_mod = 26,
357   ff_divu = 27,
358   ff_modu = 27,
359   ff_dmult = 28,
360   ff_dmultu = 29,
361   ff_ddiv = 30,
362   ff_dmod = 30,
363   ff_ddivu = 31,
364   ff_dmodu = 31,
365 
366   ff_add = 32,
367   ff_addu = 33,
368   ff_sub = 34,
369   ff_subu = 35,
370   ff_and = 36,
371   ff_or = 37,
372   ff_xor = 38,
373   ff_nor = 39,
374 
375   ff_slt = 42,
376   ff_sltu = 43,
377   ff_dadd = 44,
378   ff_daddu = 45,
379   ff_dsub = 46,
380   ff_dsubu = 47,
381 
382   ff_tge = 48,
383   ff_tgeu = 49,
384   ff_tlt = 50,
385   ff_tltu = 51,
386   ff_teq = 52,
387   ff_seleqz = 53,
388   ff_tne = 54,
389   ff_selnez = 55,
390   ff_dsll = 56,
391   ff_dsrl = 58,
392   ff_dsra = 59,
393   ff_dsll32 = 60,
394   ff_dsrl32 = 62,
395   ff_dsra32 = 63,
396 
397   // special2 encoding of function field.
398   ff_madd = 0,
399   ff_maddu = 1,
400 #ifdef MIPSR6
401   ff_clz = 16,
402   ff_dclz = 18,
403   ff_mul = 24,
404 #else
405   ff_mul = 2,
406   ff_clz = 32,
407   ff_dclz = 36,
408 #endif
409   ff_clo = 33,
410 
411   // special3 encoding of function field.
412   ff_ext = 0,
413   ff_dextm = 1,
414   ff_dextu = 2,
415   ff_dext = 3,
416   ff_ins = 4,
417   ff_dinsm = 5,
418   ff_dinsu = 6,
419   ff_dins = 7,
420   ff_bshfl = 32,
421   ff_dbshfl = 36,
422   ff_sc = 38,
423   ff_scd = 39,
424   ff_ll = 54,
425   ff_lld = 55,
426 
427   // cop1 encoding of function field.
428   ff_add_fmt = 0,
429   ff_sub_fmt = 1,
430   ff_mul_fmt = 2,
431   ff_div_fmt = 3,
432   ff_sqrt_fmt = 4,
433   ff_abs_fmt = 5,
434   ff_mov_fmt = 6,
435   ff_neg_fmt = 7,
436 
437   ff_round_l_fmt = 8,
438   ff_trunc_l_fmt = 9,
439   ff_ceil_l_fmt = 10,
440   ff_floor_l_fmt = 11,
441 
442   ff_round_w_fmt = 12,
443   ff_trunc_w_fmt = 13,
444   ff_ceil_w_fmt = 14,
445   ff_floor_w_fmt = 15,
446 
447   ff_movf_fmt = 17,
448   ff_movz_fmt = 18,
449   ff_movn_fmt = 19,
450 
451   ff_min = 28,
452   ff_max = 30,
453 
454   ff_cvt_s_fmt = 32,
455   ff_cvt_d_fmt = 33,
456   ff_cvt_w_fmt = 36,
457   ff_cvt_l_fmt = 37,
458   ff_cvt_ps_s = 38,
459 
460 #ifdef MIPSR6
461   ff_c_f_fmt = 0,
462   ff_c_un_fmt = 1,
463   ff_c_eq_fmt = 2,
464   ff_c_ueq_fmt = 3,
465   ff_c_olt_fmt = 4,
466   ff_c_ult_fmt = 5,
467   ff_c_ole_fmt = 6,
468   ff_c_ule_fmt = 7,
469 #else
470   ff_c_f_fmt = 48,
471   ff_c_un_fmt = 49,
472   ff_c_eq_fmt = 50,
473   ff_c_ueq_fmt = 51,
474   ff_c_olt_fmt = 52,
475   ff_c_ult_fmt = 53,
476   ff_c_ole_fmt = 54,
477   ff_c_ule_fmt = 55,
478 #endif
479 
480   ff_madd_s = 32,
481   ff_madd_d = 33,
482 
483   // Loongson encoding of function field.
484   ff_gsxbx = 0,
485   ff_gsxhx = 1,
486   ff_gsxwx = 2,
487   ff_gsxdx = 3,
488   ff_gsxwlc1 = 4,
489   ff_gsxwrc1 = 5,
490   ff_gsxdlc1 = 6,
491   ff_gsxdrc1 = 7,
492   ff_gsxwxc1 = 6,
493   ff_gsxdxc1 = 7,
494   ff_gsxq = 0x20,
495   ff_gsxqc1 = 0x8020,
496 
497   ff_null = 0
498 };
499 
500 class Operand;
501 
502 // A BOffImm16 is a 16 bit immediate that is used for branches.
503 class BOffImm16 {
504   uint32_t data;
505 
506  public:
encode()507   uint32_t encode() {
508     MOZ_ASSERT(!isInvalid());
509     return data;
510   }
decode()511   int32_t decode() {
512     MOZ_ASSERT(!isInvalid());
513     return (int32_t(data << 18) >> 16) + 4;
514   }
515 
BOffImm16(int offset)516   explicit BOffImm16(int offset) : data((offset - 4) >> 2 & Imm16Mask) {
517     MOZ_ASSERT((offset & 0x3) == 0);
518     MOZ_ASSERT(IsInRange(offset));
519   }
IsInRange(int offset)520   static bool IsInRange(int offset) {
521     if ((offset - 4) < int(unsigned(INT16_MIN) << 2)) {
522       return false;
523     }
524     if ((offset - 4) > (INT16_MAX << 2)) {
525       return false;
526     }
527     return true;
528   }
529   static const uint32_t INVALID = 0x00020000;
BOffImm16()530   BOffImm16() : data(INVALID) {}
531 
isInvalid()532   bool isInvalid() { return data == INVALID; }
533   Instruction* getDest(Instruction* src) const;
534 
535   BOffImm16(InstImm inst);
536 };
537 
538 // A JOffImm26 is a 26 bit immediate that is used for unconditional jumps.
539 class JOffImm26 {
540   uint32_t data;
541 
542  public:
encode()543   uint32_t encode() {
544     MOZ_ASSERT(!isInvalid());
545     return data;
546   }
decode()547   int32_t decode() {
548     MOZ_ASSERT(!isInvalid());
549     return (int32_t(data << 8) >> 6) + 4;
550   }
551 
JOffImm26(int offset)552   explicit JOffImm26(int offset) : data((offset - 4) >> 2 & Imm26Mask) {
553     MOZ_ASSERT((offset & 0x3) == 0);
554     MOZ_ASSERT(IsInRange(offset));
555   }
IsInRange(int offset)556   static bool IsInRange(int offset) {
557     if ((offset - 4) < -536870912) {
558       return false;
559     }
560     if ((offset - 4) > 536870908) {
561       return false;
562     }
563     return true;
564   }
565   static const uint32_t INVALID = 0x20000000;
JOffImm26()566   JOffImm26() : data(INVALID) {}
567 
isInvalid()568   bool isInvalid() { return data == INVALID; }
569   Instruction* getDest(Instruction* src);
570 };
571 
572 class Imm16 {
573   uint16_t value;
574 
575  public:
576   Imm16();
Imm16(uint32_t imm)577   Imm16(uint32_t imm) : value(imm) {}
encode()578   uint32_t encode() { return value; }
decodeSigned()579   int32_t decodeSigned() { return value; }
decodeUnsigned()580   uint32_t decodeUnsigned() { return value; }
IsInSignedRange(int32_t imm)581   static bool IsInSignedRange(int32_t imm) {
582     return imm >= INT16_MIN && imm <= INT16_MAX;
583   }
IsInUnsignedRange(uint32_t imm)584   static bool IsInUnsignedRange(uint32_t imm) { return imm <= UINT16_MAX; }
Lower(Imm32 imm)585   static Imm16 Lower(Imm32 imm) { return Imm16(imm.value & 0xffff); }
Upper(Imm32 imm)586   static Imm16 Upper(Imm32 imm) { return Imm16((imm.value >> 16) & 0xffff); }
587 };
588 
589 class Imm8 {
590   uint8_t value;
591 
592  public:
593   Imm8();
Imm8(uint32_t imm)594   Imm8(uint32_t imm) : value(imm) {}
encode(uint32_t shift)595   uint32_t encode(uint32_t shift) { return value << shift; }
decodeSigned()596   int32_t decodeSigned() { return value; }
decodeUnsigned()597   uint32_t decodeUnsigned() { return value; }
IsInSignedRange(int32_t imm)598   static bool IsInSignedRange(int32_t imm) {
599     return imm >= INT8_MIN && imm <= INT8_MAX;
600   }
IsInUnsignedRange(uint32_t imm)601   static bool IsInUnsignedRange(uint32_t imm) { return imm <= UINT8_MAX; }
Lower(Imm16 imm)602   static Imm8 Lower(Imm16 imm) { return Imm8(imm.decodeSigned() & 0xff); }
Upper(Imm16 imm)603   static Imm8 Upper(Imm16 imm) {
604     return Imm8((imm.decodeSigned() >> 8) & 0xff);
605   }
606 };
607 
608 class GSImm13 {
609   uint16_t value;
610 
611  public:
612   GSImm13();
GSImm13(uint32_t imm)613   GSImm13(uint32_t imm) : value(imm & ~0xf) {}
encode(uint32_t shift)614   uint32_t encode(uint32_t shift) { return ((value >> 4) & 0x1ff) << shift; }
decodeSigned()615   int32_t decodeSigned() { return value; }
decodeUnsigned()616   uint32_t decodeUnsigned() { return value; }
IsInRange(int32_t imm)617   static bool IsInRange(int32_t imm) {
618     return imm >= int32_t(uint32_t(-256) << 4) && imm <= (255 << 4);
619   }
620 };
621 
622 class Operand {
623  public:
624   enum Tag { REG, FREG, MEM };
625 
626  private:
627   Tag tag : 3;
628   uint32_t reg : 5;
629   int32_t offset;
630 
631  public:
Operand(Register reg_)632   Operand(Register reg_) : tag(REG), reg(reg_.code()) {}
633 
Operand(FloatRegister freg)634   Operand(FloatRegister freg) : tag(FREG), reg(freg.code()) {}
635 
Operand(Register base,Imm32 off)636   Operand(Register base, Imm32 off)
637       : tag(MEM), reg(base.code()), offset(off.value) {}
638 
Operand(Register base,int32_t off)639   Operand(Register base, int32_t off)
640       : tag(MEM), reg(base.code()), offset(off) {}
641 
Operand(const Address & addr)642   Operand(const Address& addr)
643       : tag(MEM), reg(addr.base.code()), offset(addr.offset) {}
644 
getTag()645   Tag getTag() const { return tag; }
646 
toReg()647   Register toReg() const {
648     MOZ_ASSERT(tag == REG);
649     return Register::FromCode(reg);
650   }
651 
toFReg()652   FloatRegister toFReg() const {
653     MOZ_ASSERT(tag == FREG);
654     return FloatRegister::FromCode(reg);
655   }
656 
toAddr(Register * r,Imm32 * dest)657   void toAddr(Register* r, Imm32* dest) const {
658     MOZ_ASSERT(tag == MEM);
659     *r = Register::FromCode(reg);
660     *dest = Imm32(offset);
661   }
toAddress()662   Address toAddress() const {
663     MOZ_ASSERT(tag == MEM);
664     return Address(Register::FromCode(reg), offset);
665   }
disp()666   int32_t disp() const {
667     MOZ_ASSERT(tag == MEM);
668     return offset;
669   }
670 
base()671   int32_t base() const {
672     MOZ_ASSERT(tag == MEM);
673     return reg;
674   }
baseReg()675   Register baseReg() const {
676     MOZ_ASSERT(tag == MEM);
677     return Register::FromCode(reg);
678   }
679 };
680 
firstHalf()681 inline Imm32 Imm64::firstHalf() const { return low(); }
682 
secondHalf()683 inline Imm32 Imm64::secondHalf() const { return hi(); }
684 
685 static constexpr int32_t SliceSize = 1024;
686 typedef js::jit::AssemblerBuffer<SliceSize, Instruction> MIPSBuffer;
687 
688 class MIPSBufferWithExecutableCopy : public MIPSBuffer {
689  public:
executableCopy(uint8_t * buffer)690   void executableCopy(uint8_t* buffer) {
691     if (this->oom()) {
692       return;
693     }
694 
695     for (Slice* cur = head; cur != nullptr; cur = cur->getNext()) {
696       memcpy(buffer, &cur->instructions, cur->length());
697       buffer += cur->length();
698     }
699   }
700 
appendRawCode(const uint8_t * code,size_t numBytes)701   bool appendRawCode(const uint8_t* code, size_t numBytes) {
702     if (this->oom()) {
703       return false;
704     }
705     while (numBytes > SliceSize) {
706       this->putBytes(SliceSize, code);
707       numBytes -= SliceSize;
708       code += SliceSize;
709     }
710     this->putBytes(numBytes, code);
711     return !this->oom();
712   }
713 };
714 
715 class AssemblerMIPSShared : public AssemblerShared {
716  public:
717   enum Condition {
718     Equal,
719     NotEqual,
720     Above,
721     AboveOrEqual,
722     Below,
723     BelowOrEqual,
724     GreaterThan,
725     GreaterThanOrEqual,
726     LessThan,
727     LessThanOrEqual,
728     Overflow,
729     CarrySet,
730     CarryClear,
731     Signed,
732     NotSigned,
733     Zero,
734     NonZero,
735     Always,
736   };
737 
738   enum DoubleCondition {
739     // These conditions will only evaluate to true if the comparison is ordered
740     // - i.e. neither operand is NaN.
741     DoubleOrdered,
742     DoubleEqual,
743     DoubleNotEqual,
744     DoubleGreaterThan,
745     DoubleGreaterThanOrEqual,
746     DoubleLessThan,
747     DoubleLessThanOrEqual,
748     // If either operand is NaN, these conditions always evaluate to true.
749     DoubleUnordered,
750     DoubleEqualOrUnordered,
751     DoubleNotEqualOrUnordered,
752     DoubleGreaterThanOrUnordered,
753     DoubleGreaterThanOrEqualOrUnordered,
754     DoubleLessThanOrUnordered,
755     DoubleLessThanOrEqualOrUnordered
756   };
757 
758   enum FPConditionBit { FCC0 = 0, FCC1, FCC2, FCC3, FCC4, FCC5, FCC6, FCC7 };
759 
760   enum FPControl {
761     FIR = 0,
762     UFR,
763     UNFR = 4,
764     FCCR = 25,
765     FEXR,
766     FENR = 28,
767     FCSR = 31
768   };
769 
770   enum FCSRBit { CauseI = 12, CauseU, CauseO, CauseZ, CauseV };
771 
772   enum FloatFormat { SingleFloat, DoubleFloat };
773 
774   enum JumpOrCall { BranchIsJump, BranchIsCall };
775 
776   enum FloatTestKind { TestForTrue, TestForFalse };
777 
778   // :( this should be protected, but since CodeGenerator
779   // wants to use it, It needs to go out here :(
780 
nextOffset()781   BufferOffset nextOffset() { return m_buffer.nextOffset(); }
782 
783  protected:
editSrc(BufferOffset bo)784   Instruction* editSrc(BufferOffset bo) { return m_buffer.getInst(bo); }
785 
786   // structure for fixing up pc-relative loads/jumps when a the machine code
787   // gets moved (executable copy, gc, etc.)
788   struct RelativePatch {
789     // the offset within the code buffer where the value is loaded that
790     // we want to fix-up
791     BufferOffset offset;
792     void* target;
793     RelocationKind kind;
794 
RelativePatchRelativePatch795     RelativePatch(BufferOffset offset, void* target, RelocationKind kind)
796         : offset(offset), target(target), kind(kind) {}
797   };
798 
799   js::Vector<RelativePatch, 8, SystemAllocPolicy> jumps_;
800 
801   CompactBufferWriter jumpRelocations_;
802   CompactBufferWriter dataRelocations_;
803 
804   MIPSBufferWithExecutableCopy m_buffer;
805 
806 #ifdef JS_JITSPEW
807   Sprinter* printer;
808 #endif
809 
810  public:
AssemblerMIPSShared()811   AssemblerMIPSShared()
812       : m_buffer(),
813 #ifdef JS_JITSPEW
814         printer(nullptr),
815 #endif
816         isFinished(false) {
817   }
818 
819   static Condition InvertCondition(Condition cond);
820   static DoubleCondition InvertCondition(DoubleCondition cond);
821 
822   // As opposed to x86/x64 version, the data relocation has to be executed
823   // before to recover the pointer, and not after.
writeDataRelocation(ImmGCPtr ptr)824   void writeDataRelocation(ImmGCPtr ptr) {
825     // Raw GC pointer relocations and Value relocations both end up in
826     // TraceOneDataRelocation.
827     if (ptr.value) {
828       if (gc::IsInsideNursery(ptr.value)) {
829         embedsNurseryPointers_ = true;
830       }
831       dataRelocations_.writeUnsigned(nextOffset().getOffset());
832     }
833   }
834 
assertNoGCThings()835   void assertNoGCThings() const {
836 #ifdef DEBUG
837     MOZ_ASSERT(dataRelocations_.length() == 0);
838     for (auto& j : jumps_) {
839       MOZ_ASSERT(j.kind == RelocationKind::HARDCODED);
840     }
841 #endif
842   }
843 
844  public:
setUnlimitedBuffer()845   void setUnlimitedBuffer() { m_buffer.setUnlimited(); }
846   bool oom() const;
847 
setPrinter(Sprinter * sp)848   void setPrinter(Sprinter* sp) {
849 #ifdef JS_JITSPEW
850     printer = sp;
851 #endif
852   }
853 
854 #ifdef JS_JITSPEW
spew(const char * fmt,...)855   inline void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) {
856     if (MOZ_UNLIKELY(printer || JitSpewEnabled(JitSpew_Codegen))) {
857       va_list va;
858       va_start(va, fmt);
859       spew(fmt, va);
860       va_end(va);
861     }
862   }
863 
864   void decodeBranchInstAndSpew(InstImm branch);
865 #else
spew(const char * fmt,...)866   MOZ_ALWAYS_INLINE void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) {}
867 #endif
868 
869 #ifdef JS_JITSPEW
spew(const char * fmt,va_list va)870   MOZ_COLD void spew(const char* fmt, va_list va) MOZ_FORMAT_PRINTF(2, 0) {
871     // Buffer to hold the formatted string. Note that this may contain
872     // '%' characters, so do not pass it directly to printf functions.
873     char buf[200];
874 
875     int i = VsprintfLiteral(buf, fmt, va);
876     if (i > -1) {
877       if (printer) {
878         printer->printf("%s\n", buf);
879       }
880       js::jit::JitSpew(js::jit::JitSpew_Codegen, "%s", buf);
881     }
882   }
883 #endif
884 
getStackPointer()885   Register getStackPointer() const { return StackPointer; }
886 
887  protected:
888   bool isFinished;
889 
890  public:
891   void finish();
892   bool appendRawCode(const uint8_t* code, size_t numBytes);
893   bool reserve(size_t size);
894   bool swapBuffer(wasm::Bytes& bytes);
895   void executableCopy(void* buffer);
896   void copyJumpRelocationTable(uint8_t* dest);
897   void copyDataRelocationTable(uint8_t* dest);
898 
899   // Size of the instruction stream, in bytes.
900   size_t size() const;
901   // Size of the jump relocation table, in bytes.
902   size_t jumpRelocationTableBytes() const;
903   size_t dataRelocationTableBytes() const;
904 
905   // Size of the data table, in bytes.
906   size_t bytesNeeded() const;
907 
908   // Write a blob of binary into the instruction stream *OR*
909   // into a destination address. If dest is nullptr (the default), then the
910   // instruction gets written into the instruction stream. If dest is not null
911   // it is interpreted as a pointer to the location that we want the
912   // instruction to be written.
913   BufferOffset writeInst(uint32_t x, uint32_t* dest = nullptr);
914   // A static variant for the cases where we don't want to have an assembler
915   // object at all. Normally, you would use the dummy (nullptr) object.
916   static void WriteInstStatic(uint32_t x, uint32_t* dest);
917 
918  public:
919   BufferOffset haltingAlign(int alignment);
920   BufferOffset nopAlign(int alignment);
921   BufferOffset as_nop();
922 
923   // Branch and jump instructions
924   BufferOffset as_bal(BOffImm16 off);
925   BufferOffset as_b(BOffImm16 off);
926 
927   InstImm getBranchCode(JumpOrCall jumpOrCall);
928   InstImm getBranchCode(Register s, Register t, Condition c);
929   InstImm getBranchCode(Register s, Condition c);
930   InstImm getBranchCode(FloatTestKind testKind, FPConditionBit fcc);
931 
932   BufferOffset as_j(JOffImm26 off);
933   BufferOffset as_jal(JOffImm26 off);
934 
935   BufferOffset as_jr(Register rs);
936   BufferOffset as_jalr(Register rs);
937 
938   // Arithmetic instructions
939   BufferOffset as_addu(Register rd, Register rs, Register rt);
940   BufferOffset as_addiu(Register rd, Register rs, int32_t j);
941   BufferOffset as_daddu(Register rd, Register rs, Register rt);
942   BufferOffset as_daddiu(Register rd, Register rs, int32_t j);
943   BufferOffset as_subu(Register rd, Register rs, Register rt);
944   BufferOffset as_dsubu(Register rd, Register rs, Register rt);
945   BufferOffset as_mult(Register rs, Register rt);
946   BufferOffset as_multu(Register rs, Register rt);
947   BufferOffset as_dmult(Register rs, Register rt);
948   BufferOffset as_dmultu(Register rs, Register rt);
949   BufferOffset as_div(Register rs, Register rt);
950   BufferOffset as_divu(Register rs, Register rt);
951   BufferOffset as_mul(Register rd, Register rs, Register rt);
952   BufferOffset as_madd(Register rs, Register rt);
953   BufferOffset as_maddu(Register rs, Register rt);
954   BufferOffset as_ddiv(Register rs, Register rt);
955   BufferOffset as_ddivu(Register rs, Register rt);
956 
957   BufferOffset as_muh(Register rd, Register rs, Register rt);
958   BufferOffset as_muhu(Register rd, Register rs, Register rt);
959   BufferOffset as_mulu(Register rd, Register rs, Register rt);
960   BufferOffset as_dmuh(Register rd, Register rs, Register rt);
961   BufferOffset as_dmuhu(Register rd, Register rs, Register rt);
962   BufferOffset as_dmul(Register rd, Register rs, Register rt);
963   BufferOffset as_dmulu(Register rd, Register rs, Register rt);
964   BufferOffset as_div(Register rd, Register rs, Register rt);
965   BufferOffset as_divu(Register rd, Register rs, Register rt);
966   BufferOffset as_mod(Register rd, Register rs, Register rt);
967   BufferOffset as_modu(Register rd, Register rs, Register rt);
968   BufferOffset as_ddiv(Register rd, Register rs, Register rt);
969   BufferOffset as_ddivu(Register rd, Register rs, Register rt);
970   BufferOffset as_dmod(Register rd, Register rs, Register rt);
971   BufferOffset as_dmodu(Register rd, Register rs, Register rt);
972 
973   // Logical instructions
974   BufferOffset as_and(Register rd, Register rs, Register rt);
975   BufferOffset as_or(Register rd, Register rs, Register rt);
976   BufferOffset as_xor(Register rd, Register rs, Register rt);
977   BufferOffset as_nor(Register rd, Register rs, Register rt);
978 
979   BufferOffset as_andi(Register rd, Register rs, int32_t j);
980   BufferOffset as_ori(Register rd, Register rs, int32_t j);
981   BufferOffset as_xori(Register rd, Register rs, int32_t j);
982   BufferOffset as_lui(Register rd, int32_t j);
983 
984   // Shift instructions
985   // as_sll(zero, zero, x) instructions are reserved as nop
986   BufferOffset as_sll(Register rd, Register rt, uint16_t sa);
987   BufferOffset as_dsll(Register rd, Register rt, uint16_t sa);
988   BufferOffset as_dsll32(Register rd, Register rt, uint16_t sa);
989   BufferOffset as_sllv(Register rd, Register rt, Register rs);
990   BufferOffset as_dsllv(Register rd, Register rt, Register rs);
991   BufferOffset as_srl(Register rd, Register rt, uint16_t sa);
992   BufferOffset as_dsrl(Register rd, Register rt, uint16_t sa);
993   BufferOffset as_dsrl32(Register rd, Register rt, uint16_t sa);
994   BufferOffset as_srlv(Register rd, Register rt, Register rs);
995   BufferOffset as_dsrlv(Register rd, Register rt, Register rs);
996   BufferOffset as_sra(Register rd, Register rt, uint16_t sa);
997   BufferOffset as_dsra(Register rd, Register rt, uint16_t sa);
998   BufferOffset as_dsra32(Register rd, Register rt, uint16_t sa);
999   BufferOffset as_srav(Register rd, Register rt, Register rs);
1000   BufferOffset as_rotr(Register rd, Register rt, uint16_t sa);
1001   BufferOffset as_rotrv(Register rd, Register rt, Register rs);
1002   BufferOffset as_dsrav(Register rd, Register rt, Register rs);
1003   BufferOffset as_drotr(Register rd, Register rt, uint16_t sa);
1004   BufferOffset as_drotr32(Register rd, Register rt, uint16_t sa);
1005   BufferOffset as_drotrv(Register rd, Register rt, Register rs);
1006 
1007   // Load and store instructions
1008   BufferOffset as_lb(Register rd, Register rs, int16_t off);
1009   BufferOffset as_lbu(Register rd, Register rs, int16_t off);
1010   BufferOffset as_lh(Register rd, Register rs, int16_t off);
1011   BufferOffset as_lhu(Register rd, Register rs, int16_t off);
1012   BufferOffset as_lw(Register rd, Register rs, int16_t off);
1013   BufferOffset as_lwu(Register rd, Register rs, int16_t off);
1014   BufferOffset as_lwl(Register rd, Register rs, int16_t off);
1015   BufferOffset as_lwr(Register rd, Register rs, int16_t off);
1016   BufferOffset as_ll(Register rd, Register rs, int16_t off);
1017   BufferOffset as_lld(Register rd, Register rs, int16_t off);
1018   BufferOffset as_ld(Register rd, Register rs, int16_t off);
1019   BufferOffset as_ldl(Register rd, Register rs, int16_t off);
1020   BufferOffset as_ldr(Register rd, Register rs, int16_t off);
1021   BufferOffset as_sb(Register rd, Register rs, int16_t off);
1022   BufferOffset as_sh(Register rd, Register rs, int16_t off);
1023   BufferOffset as_sw(Register rd, Register rs, int16_t off);
1024   BufferOffset as_swl(Register rd, Register rs, int16_t off);
1025   BufferOffset as_swr(Register rd, Register rs, int16_t off);
1026   BufferOffset as_sc(Register rd, Register rs, int16_t off);
1027   BufferOffset as_scd(Register rd, Register rs, int16_t off);
1028   BufferOffset as_sd(Register rd, Register rs, int16_t off);
1029   BufferOffset as_sdl(Register rd, Register rs, int16_t off);
1030   BufferOffset as_sdr(Register rd, Register rs, int16_t off);
1031 
1032   // Loongson-specific load and store instructions
1033   BufferOffset as_gslbx(Register rd, Register rs, Register ri, int16_t off);
1034   BufferOffset as_gssbx(Register rd, Register rs, Register ri, int16_t off);
1035   BufferOffset as_gslhx(Register rd, Register rs, Register ri, int16_t off);
1036   BufferOffset as_gsshx(Register rd, Register rs, Register ri, int16_t off);
1037   BufferOffset as_gslwx(Register rd, Register rs, Register ri, int16_t off);
1038   BufferOffset as_gsswx(Register rd, Register rs, Register ri, int16_t off);
1039   BufferOffset as_gsldx(Register rd, Register rs, Register ri, int16_t off);
1040   BufferOffset as_gssdx(Register rd, Register rs, Register ri, int16_t off);
1041   BufferOffset as_gslq(Register rh, Register rl, Register rs, int16_t off);
1042   BufferOffset as_gssq(Register rh, Register rl, Register rs, int16_t off);
1043 
1044   // Move from HI/LO register.
1045   BufferOffset as_mfhi(Register rd);
1046   BufferOffset as_mflo(Register rd);
1047 
1048   // Set on less than.
1049   BufferOffset as_slt(Register rd, Register rs, Register rt);
1050   BufferOffset as_sltu(Register rd, Register rs, Register rt);
1051   BufferOffset as_slti(Register rd, Register rs, int32_t j);
1052   BufferOffset as_sltiu(Register rd, Register rs, uint32_t j);
1053 
1054   // Conditional move.
1055   BufferOffset as_movz(Register rd, Register rs, Register rt);
1056   BufferOffset as_movn(Register rd, Register rs, Register rt);
1057   BufferOffset as_movt(Register rd, Register rs, uint16_t cc = 0);
1058   BufferOffset as_movf(Register rd, Register rs, uint16_t cc = 0);
1059   BufferOffset as_seleqz(Register rd, Register rs, Register rt);
1060   BufferOffset as_selnez(Register rd, Register rs, Register rt);
1061 
1062   // Bit twiddling.
1063   BufferOffset as_clz(Register rd, Register rs);
1064   BufferOffset as_dclz(Register rd, Register rs);
1065   BufferOffset as_wsbh(Register rd, Register rt);
1066   BufferOffset as_dsbh(Register rd, Register rt);
1067   BufferOffset as_dshd(Register rd, Register rt);
1068   BufferOffset as_ins(Register rt, Register rs, uint16_t pos, uint16_t size);
1069   BufferOffset as_dins(Register rt, Register rs, uint16_t pos, uint16_t size);
1070   BufferOffset as_dinsm(Register rt, Register rs, uint16_t pos, uint16_t size);
1071   BufferOffset as_dinsu(Register rt, Register rs, uint16_t pos, uint16_t size);
1072   BufferOffset as_ext(Register rt, Register rs, uint16_t pos, uint16_t size);
1073   BufferOffset as_dext(Register rt, Register rs, uint16_t pos, uint16_t size);
1074   BufferOffset as_dextm(Register rt, Register rs, uint16_t pos, uint16_t size);
1075   BufferOffset as_dextu(Register rt, Register rs, uint16_t pos, uint16_t size);
1076 
1077   // Sign extend
1078   BufferOffset as_seb(Register rd, Register rt);
1079   BufferOffset as_seh(Register rd, Register rt);
1080 
1081   // FP instructions
1082 
1083   BufferOffset as_ldc1(FloatRegister ft, Register base, int32_t off);
1084   BufferOffset as_sdc1(FloatRegister ft, Register base, int32_t off);
1085 
1086   BufferOffset as_lwc1(FloatRegister ft, Register base, int32_t off);
1087   BufferOffset as_swc1(FloatRegister ft, Register base, int32_t off);
1088 
1089   // Loongson-specific FP load and store instructions
1090   BufferOffset as_gsldl(FloatRegister fd, Register base, int32_t off);
1091   BufferOffset as_gsldr(FloatRegister fd, Register base, int32_t off);
1092   BufferOffset as_gssdl(FloatRegister fd, Register base, int32_t off);
1093   BufferOffset as_gssdr(FloatRegister fd, Register base, int32_t off);
1094   BufferOffset as_gslsl(FloatRegister fd, Register base, int32_t off);
1095   BufferOffset as_gslsr(FloatRegister fd, Register base, int32_t off);
1096   BufferOffset as_gsssl(FloatRegister fd, Register base, int32_t off);
1097   BufferOffset as_gsssr(FloatRegister fd, Register base, int32_t off);
1098   BufferOffset as_gslsx(FloatRegister fd, Register rs, Register ri,
1099                         int16_t off);
1100   BufferOffset as_gsssx(FloatRegister fd, Register rs, Register ri,
1101                         int16_t off);
1102   BufferOffset as_gsldx(FloatRegister fd, Register rs, Register ri,
1103                         int16_t off);
1104   BufferOffset as_gssdx(FloatRegister fd, Register rs, Register ri,
1105                         int16_t off);
1106   BufferOffset as_gslq(FloatRegister rh, FloatRegister rl, Register rs,
1107                        int16_t off);
1108   BufferOffset as_gssq(FloatRegister rh, FloatRegister rl, Register rs,
1109                        int16_t off);
1110 
1111   BufferOffset as_movs(FloatRegister fd, FloatRegister fs);
1112   BufferOffset as_movd(FloatRegister fd, FloatRegister fs);
1113 
1114   BufferOffset as_ctc1(Register rt, FPControl fc);
1115   BufferOffset as_cfc1(Register rt, FPControl fc);
1116 
1117   BufferOffset as_mtc1(Register rt, FloatRegister fs);
1118   BufferOffset as_mfc1(Register rt, FloatRegister fs);
1119 
1120   BufferOffset as_mthc1(Register rt, FloatRegister fs);
1121   BufferOffset as_mfhc1(Register rt, FloatRegister fs);
1122   BufferOffset as_dmtc1(Register rt, FloatRegister fs);
1123   BufferOffset as_dmfc1(Register rt, FloatRegister fs);
1124 
1125  public:
1126   // FP convert instructions
1127   BufferOffset as_ceilws(FloatRegister fd, FloatRegister fs);
1128   BufferOffset as_floorws(FloatRegister fd, FloatRegister fs);
1129   BufferOffset as_roundws(FloatRegister fd, FloatRegister fs);
1130   BufferOffset as_truncws(FloatRegister fd, FloatRegister fs);
1131   BufferOffset as_truncls(FloatRegister fd, FloatRegister fs);
1132 
1133   BufferOffset as_ceilwd(FloatRegister fd, FloatRegister fs);
1134   BufferOffset as_floorwd(FloatRegister fd, FloatRegister fs);
1135   BufferOffset as_roundwd(FloatRegister fd, FloatRegister fs);
1136   BufferOffset as_truncwd(FloatRegister fd, FloatRegister fs);
1137   BufferOffset as_truncld(FloatRegister fd, FloatRegister fs);
1138 
1139   BufferOffset as_cvtdl(FloatRegister fd, FloatRegister fs);
1140   BufferOffset as_cvtds(FloatRegister fd, FloatRegister fs);
1141   BufferOffset as_cvtdw(FloatRegister fd, FloatRegister fs);
1142   BufferOffset as_cvtld(FloatRegister fd, FloatRegister fs);
1143   BufferOffset as_cvtls(FloatRegister fd, FloatRegister fs);
1144   BufferOffset as_cvtsd(FloatRegister fd, FloatRegister fs);
1145   BufferOffset as_cvtsl(FloatRegister fd, FloatRegister fs);
1146   BufferOffset as_cvtsw(FloatRegister fd, FloatRegister fs);
1147   BufferOffset as_cvtwd(FloatRegister fd, FloatRegister fs);
1148   BufferOffset as_cvtws(FloatRegister fd, FloatRegister fs);
1149 
1150   // FP arithmetic instructions
1151   BufferOffset as_adds(FloatRegister fd, FloatRegister fs, FloatRegister ft);
1152   BufferOffset as_addd(FloatRegister fd, FloatRegister fs, FloatRegister ft);
1153   BufferOffset as_subs(FloatRegister fd, FloatRegister fs, FloatRegister ft);
1154   BufferOffset as_subd(FloatRegister fd, FloatRegister fs, FloatRegister ft);
1155 
1156   BufferOffset as_abss(FloatRegister fd, FloatRegister fs);
1157   BufferOffset as_absd(FloatRegister fd, FloatRegister fs);
1158   BufferOffset as_negs(FloatRegister fd, FloatRegister fs);
1159   BufferOffset as_negd(FloatRegister fd, FloatRegister fs);
1160 
1161   BufferOffset as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft);
1162   BufferOffset as_muld(FloatRegister fd, FloatRegister fs, FloatRegister ft);
1163   BufferOffset as_divs(FloatRegister fd, FloatRegister fs, FloatRegister ft);
1164   BufferOffset as_divd(FloatRegister fd, FloatRegister fs, FloatRegister ft);
1165   BufferOffset as_sqrts(FloatRegister fd, FloatRegister fs);
1166   BufferOffset as_sqrtd(FloatRegister fd, FloatRegister fs);
1167 
1168   BufferOffset as_max(FloatFormat fmt, FloatRegister fd, FloatRegister fs,
1169                       FloatRegister ft);
1170   BufferOffset as_min(FloatFormat fmt, FloatRegister fd, FloatRegister fs,
1171                       FloatRegister ft);
1172 
1173   // FP compare instructions
1174   BufferOffset as_cf(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
1175                      FPConditionBit fcc = FCC0);
1176   BufferOffset as_cun(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
1177                       FPConditionBit fcc = FCC0);
1178   BufferOffset as_ceq(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
1179                       FPConditionBit fcc = FCC0);
1180   BufferOffset as_cueq(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
1181                        FPConditionBit fcc = FCC0);
1182   BufferOffset as_colt(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
1183                        FPConditionBit fcc = FCC0);
1184   BufferOffset as_cult(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
1185                        FPConditionBit fcc = FCC0);
1186   BufferOffset as_cole(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
1187                        FPConditionBit fcc = FCC0);
1188   BufferOffset as_cule(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
1189                        FPConditionBit fcc = FCC0);
1190 
1191   // FP conditional move.
1192   BufferOffset as_movt(FloatFormat fmt, FloatRegister fd, FloatRegister fs,
1193                        FPConditionBit fcc = FCC0);
1194   BufferOffset as_movf(FloatFormat fmt, FloatRegister fd, FloatRegister fs,
1195                        FPConditionBit fcc = FCC0);
1196   BufferOffset as_movz(FloatFormat fmt, FloatRegister fd, FloatRegister fs,
1197                        Register rt);
1198   BufferOffset as_movn(FloatFormat fmt, FloatRegister fd, FloatRegister fs,
1199                        Register rt);
1200 
1201   // Conditional trap operations
1202   BufferOffset as_tge(Register rs, Register rt, uint32_t code = 0);
1203   BufferOffset as_tgeu(Register rs, Register rt, uint32_t code = 0);
1204   BufferOffset as_tlt(Register rs, Register rt, uint32_t code = 0);
1205   BufferOffset as_tltu(Register rs, Register rt, uint32_t code = 0);
1206   BufferOffset as_teq(Register rs, Register rt, uint32_t code = 0);
1207   BufferOffset as_tne(Register rs, Register rt, uint32_t code = 0);
1208 
1209   // label operations
1210   void bind(Label* label, BufferOffset boff = BufferOffset());
1211   virtual void bind(InstImm* inst, uintptr_t branch, uintptr_t target) = 0;
bind(CodeLabel * label)1212   void bind(CodeLabel* label) { label->target()->bind(currentOffset()); }
currentOffset()1213   uint32_t currentOffset() { return nextOffset().getOffset(); }
1214   void retarget(Label* label, Label* target);
1215 
1216   void call(Label* label);
1217   void call(void* target);
1218 
1219   void as_break(uint32_t code);
1220   void as_sync(uint32_t stype = 0);
1221 
1222  public:
SupportsFloatingPoint()1223   static bool SupportsFloatingPoint() {
1224 #if (defined(__mips_hard_float) && !defined(__mips_single_float)) || \
1225     defined(JS_SIMULATOR_MIPS32) || defined(JS_SIMULATOR_MIPS64)
1226     return true;
1227 #else
1228     return false;
1229 #endif
1230   }
SupportsUnalignedAccesses()1231   static bool SupportsUnalignedAccesses() { return true; }
SupportsFastUnalignedAccesses()1232   static bool SupportsFastUnalignedAccesses() { return false; }
1233 
HasRoundInstruction(RoundingMode mode)1234   static bool HasRoundInstruction(RoundingMode mode) { return false; }
1235 
1236  protected:
1237   InstImm invertBranch(InstImm branch, BOffImm16 skipOffset);
addPendingJump(BufferOffset src,ImmPtr target,RelocationKind kind)1238   void addPendingJump(BufferOffset src, ImmPtr target, RelocationKind kind) {
1239     enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind));
1240     if (kind == RelocationKind::JITCODE) {
1241       jumpRelocations_.writeUnsigned(src.getOffset());
1242     }
1243   }
1244 
addLongJump(BufferOffset src,BufferOffset dst)1245   void addLongJump(BufferOffset src, BufferOffset dst) {
1246     CodeLabel cl;
1247     cl.patchAt()->bind(src.getOffset());
1248     cl.target()->bind(dst.getOffset());
1249     cl.setLinkMode(CodeLabel::JumpImmediate);
1250     addCodeLabel(std::move(cl));
1251   }
1252 
1253  public:
flushBuffer()1254   void flushBuffer() {}
1255 
comment(const char * msg)1256   void comment(const char* msg) { spew("; %s", msg); }
1257 
NopSize()1258   static uint32_t NopSize() { return 4; }
1259 
1260   static void PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm);
1261 
AlignDoubleArg(uint32_t offset)1262   static uint32_t AlignDoubleArg(uint32_t offset) {
1263     return (offset + 1U) & ~1U;
1264   }
1265 
1266   static uint8_t* NextInstruction(uint8_t* instruction,
1267                                   uint32_t* count = nullptr);
1268 
1269   static void ToggleToJmp(CodeLocationLabel inst_);
1270   static void ToggleToCmp(CodeLocationLabel inst_);
1271 
1272   static void UpdateLuiOriValue(Instruction* inst0, Instruction* inst1,
1273                                 uint32_t value);
1274 
verifyHeapAccessDisassembly(uint32_t begin,uint32_t end,const Disassembler::HeapAccess & heapAccess)1275   void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end,
1276                                    const Disassembler::HeapAccess& heapAccess) {
1277     // Implement this if we implement a disassembler.
1278   }
1279 };  // AssemblerMIPSShared
1280 
1281 // sll zero, zero, 0
1282 const uint32_t NopInst = 0x00000000;
1283 
1284 // An Instruction is a structure for both encoding and decoding any and all
1285 // MIPS instructions.
1286 class Instruction {
1287  protected:
1288   uint32_t data;
1289 
1290   // Standard constructor
Instruction(uint32_t data_)1291   Instruction(uint32_t data_) : data(data_) {}
1292 
1293   // You should never create an instruction directly.  You should create a
1294   // more specific instruction which will eventually call one of these
1295   // constructors for you.
1296  public:
encode()1297   uint32_t encode() const { return data; }
1298 
makeNop()1299   void makeNop() { data = NopInst; }
1300 
setData(uint32_t data)1301   void setData(uint32_t data) { this->data = data; }
1302 
1303   const Instruction& operator=(const Instruction& src) {
1304     data = src.data;
1305     return *this;
1306   }
1307 
1308   // Extract the one particular bit.
extractBit(uint32_t bit)1309   uint32_t extractBit(uint32_t bit) { return (encode() >> bit) & 1; }
1310   // Extract a bit field out of the instruction
extractBitField(uint32_t hi,uint32_t lo)1311   uint32_t extractBitField(uint32_t hi, uint32_t lo) {
1312     return (encode() >> lo) & ((2 << (hi - lo)) - 1);
1313   }
1314   // Since all MIPS instructions have opcode, the opcode
1315   // extractor resides in the base class.
extractOpcode()1316   uint32_t extractOpcode() {
1317     return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift);
1318   }
1319   // Return the fields at their original place in the instruction encoding.
OpcodeFieldRaw()1320   OpcodeField OpcodeFieldRaw() const {
1321     return static_cast<OpcodeField>(encode() & OpcodeMask);
1322   }
1323 
1324   // Get the next instruction in the instruction stream.
1325   // This does neat things like ignoreconstant pools and their guards.
1326   Instruction* next();
1327 
1328   // Sometimes, an api wants a uint32_t (or a pointer to it) rather than
1329   // an instruction.  raw() just coerces this into a pointer to a uint32_t
raw()1330   const uint32_t* raw() const { return &data; }
size()1331   uint32_t size() const { return 4; }
1332 };  // Instruction
1333 
1334 // make sure that it is the right size
1335 static_assert(sizeof(Instruction) == 4,
1336               "Size of Instruction class has to be 4 bytes.");
1337 
1338 class InstNOP : public Instruction {
1339  public:
InstNOP()1340   InstNOP() : Instruction(NopInst) {}
1341 };
1342 
1343 // Class for register type instructions.
1344 class InstReg : public Instruction {
1345  public:
InstReg(OpcodeField op,Register rd,FunctionField ff)1346   InstReg(OpcodeField op, Register rd, FunctionField ff)
1347       : Instruction(op | RD(rd) | ff) {}
InstReg(OpcodeField op,Register rs,Register rt,FunctionField ff)1348   InstReg(OpcodeField op, Register rs, Register rt, FunctionField ff)
1349       : Instruction(op | RS(rs) | RT(rt) | ff) {}
InstReg(OpcodeField op,Register rs,Register rt,Register rd,FunctionField ff)1350   InstReg(OpcodeField op, Register rs, Register rt, Register rd,
1351           FunctionField ff)
1352       : Instruction(op | RS(rs) | RT(rt) | RD(rd) | ff) {}
InstReg(OpcodeField op,Register rs,Register rt,Register rd,uint32_t sa,FunctionField ff)1353   InstReg(OpcodeField op, Register rs, Register rt, Register rd, uint32_t sa,
1354           FunctionField ff)
1355       : Instruction(op | RS(rs) | RT(rt) | RD(rd) | SA(sa) | ff) {}
InstReg(OpcodeField op,RSField rs,Register rt,Register rd,uint32_t sa,FunctionField ff)1356   InstReg(OpcodeField op, RSField rs, Register rt, Register rd, uint32_t sa,
1357           FunctionField ff)
1358       : Instruction(op | rs | RT(rt) | RD(rd) | SA(sa) | ff) {}
InstReg(OpcodeField op,Register rs,RTField rt,Register rd,uint32_t sa,FunctionField ff)1359   InstReg(OpcodeField op, Register rs, RTField rt, Register rd, uint32_t sa,
1360           FunctionField ff)
1361       : Instruction(op | RS(rs) | rt | RD(rd) | SA(sa) | ff) {}
InstReg(OpcodeField op,Register rs,uint32_t cc,Register rd,uint32_t sa,FunctionField ff)1362   InstReg(OpcodeField op, Register rs, uint32_t cc, Register rd, uint32_t sa,
1363           FunctionField ff)
1364       : Instruction(op | RS(rs) | cc | RD(rd) | SA(sa) | ff) {}
InstReg(OpcodeField op,uint32_t code,FunctionField ff)1365   InstReg(OpcodeField op, uint32_t code, FunctionField ff)
1366       : Instruction(op | code | ff) {}
1367   // for float point
InstReg(OpcodeField op,RSField rs,Register rt,uint32_t fs)1368   InstReg(OpcodeField op, RSField rs, Register rt, uint32_t fs)
1369       : Instruction(op | rs | RT(rt) | FS(fs)) {}
InstReg(OpcodeField op,RSField rs,Register rt,FloatRegister rd)1370   InstReg(OpcodeField op, RSField rs, Register rt, FloatRegister rd)
1371       : Instruction(op | rs | RT(rt) | RD(rd)) {}
InstReg(OpcodeField op,RSField rs,Register rt,FloatRegister rd,uint32_t sa,FunctionField ff)1372   InstReg(OpcodeField op, RSField rs, Register rt, FloatRegister rd,
1373           uint32_t sa, FunctionField ff)
1374       : Instruction(op | rs | RT(rt) | RD(rd) | SA(sa) | ff) {}
InstReg(OpcodeField op,RSField rs,Register rt,FloatRegister fs,FloatRegister fd,FunctionField ff)1375   InstReg(OpcodeField op, RSField rs, Register rt, FloatRegister fs,
1376           FloatRegister fd, FunctionField ff)
1377       : Instruction(op | rs | RT(rt) | RD(fs) | SA(fd) | ff) {}
InstReg(OpcodeField op,RSField rs,FloatRegister ft,FloatRegister fs,FloatRegister fd,FunctionField ff)1378   InstReg(OpcodeField op, RSField rs, FloatRegister ft, FloatRegister fs,
1379           FloatRegister fd, FunctionField ff)
1380       : Instruction(op | rs | RT(ft) | RD(fs) | SA(fd) | ff) {}
InstReg(OpcodeField op,RSField rs,FloatRegister ft,FloatRegister fd,uint32_t sa,FunctionField ff)1381   InstReg(OpcodeField op, RSField rs, FloatRegister ft, FloatRegister fd,
1382           uint32_t sa, FunctionField ff)
1383       : Instruction(op | rs | RT(ft) | RD(fd) | SA(sa) | ff) {}
1384 
extractRS()1385   uint32_t extractRS() {
1386     return extractBitField(RSShift + RSBits - 1, RSShift);
1387   }
extractRT()1388   uint32_t extractRT() {
1389     return extractBitField(RTShift + RTBits - 1, RTShift);
1390   }
extractRD()1391   uint32_t extractRD() {
1392     return extractBitField(RDShift + RDBits - 1, RDShift);
1393   }
extractSA()1394   uint32_t extractSA() {
1395     return extractBitField(SAShift + SABits - 1, SAShift);
1396   }
extractFunctionField()1397   uint32_t extractFunctionField() {
1398     return extractBitField(FunctionShift + FunctionBits - 1, FunctionShift);
1399   }
1400 };
1401 
1402 // Class for branch, load and store instructions with immediate offset.
1403 class InstImm : public Instruction {
1404  public:
1405   void extractImm16(BOffImm16* dest);
1406 
InstImm(OpcodeField op,Register rs,Register rt,BOffImm16 off)1407   InstImm(OpcodeField op, Register rs, Register rt, BOffImm16 off)
1408       : Instruction(op | RS(rs) | RT(rt) | off.encode()) {}
InstImm(OpcodeField op,Register rs,RTField rt,BOffImm16 off)1409   InstImm(OpcodeField op, Register rs, RTField rt, BOffImm16 off)
1410       : Instruction(op | RS(rs) | rt | off.encode()) {}
InstImm(OpcodeField op,RSField rs,uint32_t cc,BOffImm16 off)1411   InstImm(OpcodeField op, RSField rs, uint32_t cc, BOffImm16 off)
1412       : Instruction(op | rs | cc | off.encode()) {}
InstImm(OpcodeField op,Register rs,Register rt,Imm16 off)1413   InstImm(OpcodeField op, Register rs, Register rt, Imm16 off)
1414       : Instruction(op | RS(rs) | RT(rt) | off.encode()) {}
InstImm(uint32_t raw)1415   InstImm(uint32_t raw) : Instruction(raw) {}
1416   // For floating-point loads and stores.
InstImm(OpcodeField op,Register rs,FloatRegister rt,Imm16 off)1417   InstImm(OpcodeField op, Register rs, FloatRegister rt, Imm16 off)
1418       : Instruction(op | RS(rs) | RT(rt) | off.encode()) {}
1419 
extractOpcode()1420   uint32_t extractOpcode() {
1421     return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift);
1422   }
setOpcode(OpcodeField op)1423   void setOpcode(OpcodeField op) { data = (data & ~OpcodeMask) | op; }
extractRS()1424   uint32_t extractRS() {
1425     return extractBitField(RSShift + RSBits - 1, RSShift);
1426   }
extractRT()1427   uint32_t extractRT() {
1428     return extractBitField(RTShift + RTBits - 1, RTShift);
1429   }
setRT(RTField rt)1430   void setRT(RTField rt) { data = (data & ~RTMask) | rt; }
extractImm16Value()1431   uint32_t extractImm16Value() {
1432     return extractBitField(Imm16Shift + Imm16Bits - 1, Imm16Shift);
1433   }
setBOffImm16(BOffImm16 off)1434   void setBOffImm16(BOffImm16 off) {
1435     // Reset immediate field and replace it
1436     data = (data & ~Imm16Mask) | off.encode();
1437   }
setImm16(Imm16 off)1438   void setImm16(Imm16 off) {
1439     // Reset immediate field and replace it
1440     data = (data & ~Imm16Mask) | off.encode();
1441   }
1442 };
1443 
1444 // Class for Jump type instructions.
1445 class InstJump : public Instruction {
1446  public:
InstJump(OpcodeField op,JOffImm26 off)1447   InstJump(OpcodeField op, JOffImm26 off) : Instruction(op | off.encode()) {}
1448 
extractImm26Value()1449   uint32_t extractImm26Value() {
1450     return extractBitField(Imm26Shift + Imm26Bits - 1, Imm26Shift);
1451   }
1452 };
1453 
1454 // Class for Loongson-specific instructions
1455 class InstGS : public Instruction {
1456  public:
1457   // For indexed loads and stores.
InstGS(OpcodeField op,Register rs,Register rt,Register rd,Imm8 off,FunctionField ff)1458   InstGS(OpcodeField op, Register rs, Register rt, Register rd, Imm8 off,
1459          FunctionField ff)
1460       : Instruction(op | RS(rs) | RT(rt) | RD(rd) | off.encode(3) | ff) {}
InstGS(OpcodeField op,Register rs,FloatRegister rt,Register rd,Imm8 off,FunctionField ff)1461   InstGS(OpcodeField op, Register rs, FloatRegister rt, Register rd, Imm8 off,
1462          FunctionField ff)
1463       : Instruction(op | RS(rs) | RT(rt) | RD(rd) | off.encode(3) | ff) {}
1464   // For quad-word loads and stores.
InstGS(OpcodeField op,Register rs,Register rt,Register rz,GSImm13 off,FunctionField ff)1465   InstGS(OpcodeField op, Register rs, Register rt, Register rz, GSImm13 off,
1466          FunctionField ff)
1467       : Instruction(op | RS(rs) | RT(rt) | RZ(rz) | off.encode(6) | ff) {}
InstGS(OpcodeField op,Register rs,FloatRegister rt,FloatRegister rz,GSImm13 off,FunctionField ff)1468   InstGS(OpcodeField op, Register rs, FloatRegister rt, FloatRegister rz,
1469          GSImm13 off, FunctionField ff)
1470       : Instruction(op | RS(rs) | RT(rt) | RZ(rz) | off.encode(6) | ff) {}
InstGS(uint32_t raw)1471   InstGS(uint32_t raw) : Instruction(raw) {}
1472   // For floating-point unaligned loads and stores.
InstGS(OpcodeField op,Register rs,FloatRegister rt,Imm8 off,FunctionField ff)1473   InstGS(OpcodeField op, Register rs, FloatRegister rt, Imm8 off,
1474          FunctionField ff)
1475       : Instruction(op | RS(rs) | RT(rt) | off.encode(6) | ff) {}
1476 };
1477 
IsUnaligned(const wasm::MemoryAccessDesc & access)1478 inline bool IsUnaligned(const wasm::MemoryAccessDesc& access) {
1479   if (!access.align()) {
1480     return false;
1481   }
1482 
1483 #ifdef JS_CODEGEN_MIPS32
1484   if (access.type() == Scalar::Int64 && access.align() >= 4) {
1485     return false;
1486   }
1487 #endif
1488 
1489   return access.align() < access.byteSize();
1490 }
1491 
1492 }  // namespace jit
1493 }  // namespace js
1494 
1495 #endif /* jit_mips_shared_Assembler_mips_shared_h */
1496