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