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_loong64_Assembler_loong64_h
8 #define jit_loong64_Assembler_loong64_h
9 
10 #include "mozilla/Sprintf.h"
11 #include <iterator>
12 
13 #include "jit/CompactBuffer.h"
14 #include "jit/JitCode.h"
15 #include "jit/JitSpewer.h"
16 #include "jit/loong64/Architecture-loong64.h"
17 #include "jit/shared/Assembler-shared.h"
18 #include "jit/shared/Disassembler-shared.h"
19 #include "jit/shared/IonAssemblerBuffer.h"
20 #include "wasm/WasmTypeDecls.h"
21 
22 namespace js {
23 namespace jit {
24 
25 static constexpr Register zero{Registers::zero};
26 static constexpr Register ra{Registers::ra};
27 static constexpr Register tp{Registers::tp};
28 static constexpr Register sp{Registers::sp};
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::a4};
34 static constexpr Register a5{Registers::a5};
35 static constexpr Register a6{Registers::a6};
36 static constexpr Register a7{Registers::a7};
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::t4};
42 static constexpr Register t5{Registers::t5};
43 static constexpr Register t6{Registers::t6};
44 static constexpr Register t7{Registers::t7};
45 static constexpr Register t8{Registers::t8};
46 static constexpr Register rx{Registers::rx};
47 static constexpr Register fp{Registers::fp};
48 static constexpr Register s0{Registers::s0};
49 static constexpr Register s1{Registers::s1};
50 static constexpr Register s2{Registers::s2};
51 static constexpr Register s3{Registers::s3};
52 static constexpr Register s4{Registers::s4};
53 static constexpr Register s5{Registers::s5};
54 static constexpr Register s6{Registers::s6};
55 static constexpr Register s7{Registers::s7};
56 static constexpr Register s8{Registers::s8};
57 
58 static constexpr FloatRegister f0{FloatRegisters::f0, FloatRegisters::Double};
59 static constexpr FloatRegister f1{FloatRegisters::f1, FloatRegisters::Double};
60 static constexpr FloatRegister f2{FloatRegisters::f2, FloatRegisters::Double};
61 static constexpr FloatRegister f3{FloatRegisters::f3, FloatRegisters::Double};
62 static constexpr FloatRegister f4{FloatRegisters::f4, FloatRegisters::Double};
63 static constexpr FloatRegister f5{FloatRegisters::f5, FloatRegisters::Double};
64 static constexpr FloatRegister f6{FloatRegisters::f6, FloatRegisters::Double};
65 static constexpr FloatRegister f7{FloatRegisters::f7, FloatRegisters::Double};
66 static constexpr FloatRegister f8{FloatRegisters::f8, FloatRegisters::Double};
67 static constexpr FloatRegister f9{FloatRegisters::f9, FloatRegisters::Double};
68 static constexpr FloatRegister f10{FloatRegisters::f10, FloatRegisters::Double};
69 static constexpr FloatRegister f11{FloatRegisters::f11, FloatRegisters::Double};
70 static constexpr FloatRegister f12{FloatRegisters::f12, FloatRegisters::Double};
71 static constexpr FloatRegister f13{FloatRegisters::f13, FloatRegisters::Double};
72 static constexpr FloatRegister f14{FloatRegisters::f14, FloatRegisters::Double};
73 static constexpr FloatRegister f15{FloatRegisters::f15, FloatRegisters::Double};
74 static constexpr FloatRegister f16{FloatRegisters::f16, FloatRegisters::Double};
75 static constexpr FloatRegister f17{FloatRegisters::f17, FloatRegisters::Double};
76 static constexpr FloatRegister f18{FloatRegisters::f18, FloatRegisters::Double};
77 static constexpr FloatRegister f19{FloatRegisters::f19, FloatRegisters::Double};
78 static constexpr FloatRegister f20{FloatRegisters::f20, FloatRegisters::Double};
79 static constexpr FloatRegister f21{FloatRegisters::f21, FloatRegisters::Double};
80 static constexpr FloatRegister f22{FloatRegisters::f22, FloatRegisters::Double};
81 static constexpr FloatRegister f23{FloatRegisters::f23, FloatRegisters::Double};
82 static constexpr FloatRegister f24{FloatRegisters::f24, FloatRegisters::Double};
83 static constexpr FloatRegister f25{FloatRegisters::f25, FloatRegisters::Double};
84 static constexpr FloatRegister f26{FloatRegisters::f26, FloatRegisters::Double};
85 static constexpr FloatRegister f27{FloatRegisters::f27, FloatRegisters::Double};
86 static constexpr FloatRegister f28{FloatRegisters::f28, FloatRegisters::Double};
87 static constexpr FloatRegister f29{FloatRegisters::f29, FloatRegisters::Double};
88 static constexpr FloatRegister f30{FloatRegisters::f30, FloatRegisters::Double};
89 static constexpr FloatRegister f31{FloatRegisters::f31, FloatRegisters::Double};
90 
91 static constexpr Register InvalidReg{Registers::Invalid};
92 static constexpr FloatRegister InvalidFloatReg;
93 
94 static constexpr Register StackPointer = sp;
95 static constexpr Register FramePointer = fp;
96 static constexpr Register ReturnReg = a0;
97 static constexpr Register64 ReturnReg64(ReturnReg);
98 static constexpr FloatRegister ReturnFloat32Reg{FloatRegisters::f0,
99                                                 FloatRegisters::Single};
100 static constexpr FloatRegister ReturnDoubleReg = f0;
101 static constexpr FloatRegister ReturnSimd128Reg = InvalidFloatReg;
102 
103 static constexpr Register ScratchRegister = t7;
104 static constexpr Register SecondScratchReg = t8;
105 
106 // Helper classes for ScratchRegister usage. Asserts that only one piece
107 // of code thinks it has exclusive ownership of each scratch register.
108 struct ScratchRegisterScope : public AutoRegisterScope {
ScratchRegisterScopeScratchRegisterScope109   explicit ScratchRegisterScope(MacroAssembler& masm)
110       : AutoRegisterScope(masm, ScratchRegister) {}
111 };
112 
113 struct SecondScratchRegisterScope : public AutoRegisterScope {
SecondScratchRegisterScopeSecondScratchRegisterScope114   explicit SecondScratchRegisterScope(MacroAssembler& masm)
115       : AutoRegisterScope(masm, SecondScratchReg) {}
116 };
117 
118 static constexpr FloatRegister ScratchFloat32Reg{FloatRegisters::f23,
119                                                  FloatRegisters::Single};
120 static constexpr FloatRegister ScratchDoubleReg = f23;
121 static constexpr FloatRegister ScratchSimd128Reg = InvalidFloatReg;
122 
123 struct ScratchFloat32Scope : public AutoFloatRegisterScope {
ScratchFloat32ScopeScratchFloat32Scope124   explicit ScratchFloat32Scope(MacroAssembler& masm)
125       : AutoFloatRegisterScope(masm, ScratchFloat32Reg) {}
126 };
127 
128 struct ScratchDoubleScope : public AutoFloatRegisterScope {
ScratchDoubleScopeScratchDoubleScope129   explicit ScratchDoubleScope(MacroAssembler& masm)
130       : AutoFloatRegisterScope(masm, ScratchDoubleReg) {}
131 };
132 
133 // Use arg reg from EnterJIT function as OsrFrameReg.
134 static constexpr Register OsrFrameReg = a3;
135 static constexpr Register PreBarrierReg = a1;
136 static constexpr Register InterpreterPCReg = t0;
137 static constexpr Register CallTempReg0 = t0;
138 static constexpr Register CallTempReg1 = t1;
139 static constexpr Register CallTempReg2 = t2;
140 static constexpr Register CallTempReg3 = t3;
141 static constexpr Register CallTempReg4 = t4;
142 static constexpr Register CallTempReg5 = t5;
143 static constexpr Register CallTempNonArgRegs[] = {t0, t1, t2, t3};
144 static const uint32_t NumCallTempNonArgRegs = std::size(CallTempNonArgRegs);
145 
146 static constexpr Register IntArgReg0 = a0;
147 static constexpr Register IntArgReg1 = a1;
148 static constexpr Register IntArgReg2 = a2;
149 static constexpr Register IntArgReg3 = a3;
150 static constexpr Register IntArgReg4 = a4;
151 static constexpr Register IntArgReg5 = a5;
152 static constexpr Register IntArgReg6 = a6;
153 static constexpr Register IntArgReg7 = a7;
154 static constexpr Register HeapReg = s7;
155 
156 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
157 static constexpr Register RegExpMatcherRegExpReg = CallTempReg0;
158 static constexpr Register RegExpMatcherStringReg = CallTempReg1;
159 static constexpr Register RegExpMatcherLastIndexReg = CallTempReg2;
160 
161 // Registerd used in RegExpTester instruction (do not use ReturnReg).
162 static constexpr Register RegExpTesterRegExpReg = CallTempReg0;
163 static constexpr Register RegExpTesterStringReg = CallTempReg1;
164 static constexpr Register RegExpTesterLastIndexReg = CallTempReg2;
165 
166 static constexpr Register JSReturnReg_Type = a3;
167 static constexpr Register JSReturnReg_Data = a2;
168 static constexpr Register JSReturnReg = a2;
169 static constexpr ValueOperand JSReturnOperand = ValueOperand(JSReturnReg);
170 
171 // These registers may be volatile or nonvolatile.
172 static constexpr Register ABINonArgReg0 = t0;
173 static constexpr Register ABINonArgReg1 = t1;
174 static constexpr Register ABINonArgReg2 = t2;
175 static constexpr Register ABINonArgReg3 = t3;
176 
177 // These registers may be volatile or nonvolatile.
178 // Note: these three registers are all guaranteed to be different
179 static constexpr Register ABINonArgReturnReg0 = t0;
180 static constexpr Register ABINonArgReturnReg1 = t1;
181 static constexpr Register ABINonVolatileReg = s0;
182 
183 // This register is guaranteed to be clobberable during the prologue and
184 // epilogue of an ABI call which must preserve both ABI argument, return
185 // and non-volatile registers.
186 static constexpr Register ABINonArgReturnVolatileReg = ra;
187 
188 // This register may be volatile or nonvolatile.
189 // Avoid f23 which is the scratch register.
190 static constexpr FloatRegister ABINonArgDoubleReg{FloatRegisters::f21,
191                                                   FloatRegisters::Double};
192 
193 // TLS pointer argument register for WebAssembly functions. This must not alias
194 // any other register used for passing function arguments or return values.
195 // Preserved by WebAssembly functions. Must be nonvolatile.
196 static constexpr Register WasmTlsReg = s4;
197 
198 // Registers used for wasm table calls. These registers must be disjoint
199 // from the ABI argument registers, WasmTlsReg and each other.
200 static constexpr Register WasmTableCallScratchReg0 = ABINonArgReg0;
201 static constexpr Register WasmTableCallScratchReg1 = ABINonArgReg1;
202 static constexpr Register WasmTableCallSigReg = ABINonArgReg2;
203 static constexpr Register WasmTableCallIndexReg = ABINonArgReg3;
204 
205 // Register used as a scratch along the return path in the fast js -> wasm stub
206 // code. This must not overlap ReturnReg, JSReturnOperand, or WasmTlsReg. It
207 // must be a volatile register.
208 static constexpr Register WasmJitEntryReturnScratch = t1;
209 
210 static constexpr uint32_t ABIStackAlignment = 16;
211 static constexpr uint32_t CodeAlignment = 16;
212 static constexpr uint32_t JitStackAlignment = 16;
213 
214 static constexpr uint32_t JitStackValueAlignment =
215     JitStackAlignment / sizeof(Value);
216 static_assert(JitStackAlignment % sizeof(Value) == 0 &&
217                   JitStackValueAlignment >= 1,
218               "Stack alignment should be a non-zero multiple of sizeof(Value)");
219 
220 // TODO(loong64): this is just a filler to prevent a build failure. The
221 // LoongArch SIMD alignment requirements still need to be explored.
222 static constexpr uint32_t SimdMemoryAlignment = 16;
223 
224 static_assert(CodeAlignment % SimdMemoryAlignment == 0,
225               "Code alignment should be larger than any of the alignments "
226               "which are used for "
227               "the constant sections of the code buffer.  Thus it should be "
228               "larger than the "
229               "alignment for SIMD constants.");
230 
231 static constexpr uint32_t WasmStackAlignment = SimdMemoryAlignment;
232 static const uint32_t WasmTrapInstructionLength = 4;
233 
234 // See comments in wasm::GenerateFunctionPrologue.  The difference between these
235 // is the size of the largest callable prologue on the platform.
236 static constexpr uint32_t WasmCheckedCallEntryOffset = 0u;
237 static constexpr uint32_t WasmCheckedTailEntryOffset = 16u;
238 
239 static constexpr Scale ScalePointer = TimesEight;
240 
241 // TODO(loong64): Add LoongArch instruction types description.
242 
243 // LoongArch instruction encoding constants.
244 static const uint32_t RJShift = 5;
245 static const uint32_t RJBits = 5;
246 static const uint32_t RKShift = 10;
247 static const uint32_t RKBits = 5;
248 static const uint32_t RDShift = 0;
249 static const uint32_t RDBits = 5;
250 static const uint32_t FJShift = 5;
251 static const uint32_t FJBits = 5;
252 static const uint32_t FKShift = 10;
253 static const uint32_t FKBits = 5;
254 static const uint32_t FDShift = 0;
255 static const uint32_t FDBits = 5;
256 static const uint32_t FAShift = 15;
257 static const uint32_t FABits = 5;
258 static const uint32_t CJShift = 5;
259 static const uint32_t CJBits = 3;
260 static const uint32_t CDShift = 0;
261 static const uint32_t CDBits = 3;
262 static const uint32_t CAShift = 15;
263 static const uint32_t CABits = 3;
264 static const uint32_t CONDShift = 15;
265 static const uint32_t CONDBits = 5;
266 
267 static const uint32_t SAShift = 15;
268 static const uint32_t SA2Bits = 2;
269 static const uint32_t SA3Bits = 3;
270 static const uint32_t LSBWShift = 10;
271 static const uint32_t LSBWBits = 5;
272 static const uint32_t LSBDShift = 10;
273 static const uint32_t LSBDBits = 6;
274 static const uint32_t MSBWShift = 16;
275 static const uint32_t MSBWBits = 5;
276 static const uint32_t MSBDShift = 16;
277 static const uint32_t MSBDBits = 6;
278 static const uint32_t Imm5Shift = 10;
279 static const uint32_t Imm5Bits = 5;
280 static const uint32_t Imm6Shift = 10;
281 static const uint32_t Imm6Bits = 6;
282 static const uint32_t Imm12Shift = 10;
283 static const uint32_t Imm12Bits = 12;
284 static const uint32_t Imm14Shift = 10;
285 static const uint32_t Imm14Bits = 14;
286 static const uint32_t Imm15Shift = 0;
287 static const uint32_t Imm15Bits = 15;
288 static const uint32_t Imm16Shift = 10;
289 static const uint32_t Imm16Bits = 16;
290 static const uint32_t Imm20Shift = 5;
291 static const uint32_t Imm20Bits = 20;
292 static const uint32_t Imm21Shift = 0;
293 static const uint32_t Imm21Bits = 21;
294 static const uint32_t Imm26Shift = 0;
295 static const uint32_t Imm26Bits = 26;
296 static const uint32_t CODEShift = 0;
297 static const uint32_t CODEBits = 15;
298 
299 // LoongArch instruction field bit masks.
300 static const uint32_t RJMask = (1 << RJBits) - 1;
301 static const uint32_t RKMask = (1 << RKBits) - 1;
302 static const uint32_t RDMask = (1 << RDBits) - 1;
303 static const uint32_t SA2Mask = (1 << SA2Bits) - 1;
304 static const uint32_t SA3Mask = (1 << SA3Bits) - 1;
305 static const uint32_t CONDMask = (1 << CONDBits) - 1;
306 static const uint32_t LSBWMask = (1 << LSBWBits) - 1;
307 static const uint32_t LSBDMask = (1 << LSBDBits) - 1;
308 static const uint32_t MSBWMask = (1 << MSBWBits) - 1;
309 static const uint32_t MSBDMask = (1 << MSBDBits) - 1;
310 static const uint32_t CODEMask = (1 << CODEBits) - 1;
311 static const uint32_t Imm5Mask = (1 << Imm5Bits) - 1;
312 static const uint32_t Imm6Mask = (1 << Imm6Bits) - 1;
313 static const uint32_t Imm12Mask = (1 << Imm12Bits) - 1;
314 static const uint32_t Imm14Mask = (1 << Imm14Bits) - 1;
315 static const uint32_t Imm15Mask = (1 << Imm15Bits) - 1;
316 static const uint32_t Imm16Mask = (1 << Imm16Bits) - 1;
317 static const uint32_t Imm20Mask = (1 << Imm20Bits) - 1;
318 static const uint32_t Imm21Mask = (1 << Imm21Bits) - 1;
319 static const uint32_t Imm26Mask = (1 << Imm26Bits) - 1;
320 static const uint32_t BOffImm16Mask = ((1 << Imm16Bits) - 1) << Imm16Shift;
321 static const uint32_t BOffImm21Mask = ((1 << Imm21Bits) - 1) << Imm21Shift;
322 static const uint32_t BOffImm26Mask = ((1 << Imm26Bits) - 1) << Imm26Shift;
323 static const uint32_t RegMask = Registers::Total - 1;
324 
325 // TODO(loong64) Change to syscall?
326 static const uint32_t MAX_BREAK_CODE = 1024 - 1;
327 static const uint32_t WASM_TRAP = 6;  // BRK_OVERFLOW
328 
329 // TODO(loong64) Change to LoongArch instruction type.
330 class Instruction;
331 class InstReg;
332 class InstImm;
333 class InstJump;
334 
335 uint32_t RJ(Register r);
336 uint32_t RK(Register r);
337 uint32_t RD(Register r);
338 uint32_t FJ(FloatRegister r);
339 uint32_t FK(FloatRegister r);
340 uint32_t FD(FloatRegister r);
341 uint32_t FA(FloatRegister r);
342 uint32_t SA2(uint32_t value);
343 uint32_t SA2(FloatRegister r);
344 uint32_t SA3(uint32_t value);
345 uint32_t SA3(FloatRegister r);
346 
347 Register toRK(Instruction& i);
348 Register toRJ(Instruction& i);
349 Register toRD(Instruction& i);
350 Register toR(Instruction& i);
351 
352 // LoongArch enums for instruction fields
353 enum OpcodeField {
354   op_beqz = 0x10U << 26,
355   op_bnez = 0x11U << 26,
356   op_bcz = 0x12U << 26,  // bceqz & bcnez
357   op_jirl = 0x13U << 26,
358   op_b = 0x14U << 26,
359   op_bl = 0x15U << 26,
360   op_beq = 0x16U << 26,
361   op_bne = 0x17U << 26,
362   op_blt = 0x18U << 26,
363   op_bge = 0x19U << 26,
364   op_bltu = 0x1aU << 26,
365   op_bgeu = 0x1bU << 26,
366 
367   op_addu16i_d = 0x4U << 26,
368 
369   op_lu12i_w = 0xaU << 25,
370   op_lu32i_d = 0xbU << 25,
371   op_pcaddi = 0xcU << 25,
372   op_pcalau12i = 0xdU << 25,
373   op_pcaddu12i = 0xeU << 25,
374   op_pcaddu18i = 0xfU << 25,
375   op_ll_w = 0x20U << 24,
376   op_sc_w = 0x21U << 24,
377   op_ll_d = 0x22U << 24,
378   op_sc_d = 0x23U << 24,
379   op_ldptr_w = 0x24U << 24,
380   op_stptr_w = 0x25U << 24,
381   op_ldptr_d = 0x26U << 24,
382   op_stptr_d = 0x27U << 24,
383   op_bstrins_d = 0x2U << 22,
384   op_bstrpick_d = 0x3U << 22,
385   op_slti = 0x8U << 22,
386   op_sltui = 0x9U << 22,
387   op_addi_w = 0xaU << 22,
388   op_addi_d = 0xbU << 22,
389   op_lu52i_d = 0xcU << 22,
390   op_andi = 0xdU << 22,
391   op_ori = 0xeU << 22,
392   op_xori = 0xfU << 22,
393   op_ld_b = 0xa0U << 22,
394   op_ld_h = 0xa1U << 22,
395   op_ld_w = 0xa2U << 22,
396   op_ld_d = 0xa3U << 22,
397   op_st_b = 0xa4U << 22,
398   op_st_h = 0xa5U << 22,
399   op_st_w = 0xa6U << 22,
400   op_st_d = 0xa7U << 22,
401   op_ld_bu = 0xa8U << 22,
402   op_ld_hu = 0xa9U << 22,
403   op_ld_wu = 0xaaU << 22,
404   op_preld = 0xabU << 22,
405   op_fld_s = 0xacU << 22,
406   op_fst_s = 0xadU << 22,
407   op_fld_d = 0xaeU << 22,
408   op_fst_d = 0xafU << 22,
409   op_bstr_w = 0x3U << 21,  // BSTRINS_W & BSTRPICK_W
410   op_fmadd_s = 0x81U << 20,
411   op_fmadd_d = 0x82U << 20,
412   op_fmsub_s = 0x85U << 20,
413   op_fmsub_d = 0x86U << 20,
414   op_fnmadd_s = 0x89U << 20,
415   op_fnmadd_d = 0x8aU << 20,
416   op_fnmsub_s = 0x8dU << 20,
417   op_fnmsub_d = 0x8eU << 20,
418   op_fcmp_cond_s = 0xc1U << 20,
419   op_fcmp_cond_d = 0xc2U << 20,
420 
421   op_bytepick_d = 0x3U << 18,
422   op_fsel = 0x340U << 18,
423 
424   op_bytepick_w = 0x4U << 17,
425   op_alsl_w = 0x2U << 17,
426   op_alsl_wu = 0x3U << 17,
427   op_alsl_d = 0x16U << 17,
428 
429   op_slli_d = 0x41U << 16,
430   op_srli_d = 0x45U << 16,
431   op_srai_d = 0x49U << 16,
432 
433   op_slli_w = 0x81U << 15,
434   op_srli_w = 0x89U << 15,
435   op_srai_w = 0x91U << 15,
436   op_add_w = 0x20U << 15,
437   op_add_d = 0x21U << 15,
438   op_sub_w = 0x22U << 15,
439   op_sub_d = 0x23U << 15,
440   op_slt = 0x24U << 15,
441   op_sltu = 0x25U << 15,
442   op_maskeqz = 0x26U << 15,
443   op_masknez = 0x27U << 15,
444   op_nor = 0x28U << 15,
445   op_and = 0x29U << 15,
446   op_or = 0x2aU << 15,
447   op_xor = 0x2bU << 15,
448   op_orn = 0x2cU << 15,
449   op_andn = 0x2dU << 15,
450   op_sll_w = 0x2eU << 15,
451   op_srl_w = 0x2fU << 15,
452   op_sra_w = 0x30U << 15,
453   op_sll_d = 0x31U << 15,
454   op_srl_d = 0x32U << 15,
455   op_sra_d = 0x33U << 15,
456   op_rotr_w = 0x36U << 15,
457   op_rotr_d = 0x37U << 15,
458   op_rotri_w = 0x99U << 15,
459   op_rotri_d = 0x4DU << 16,
460   op_mul_w = 0x38U << 15,
461   op_mulh_w = 0x39U << 15,
462   op_mulh_wu = 0x3aU << 15,
463   op_mul_d = 0x3bU << 15,
464   op_mulh_d = 0x3cU << 15,
465   op_mulh_du = 0x3dU << 15,
466   op_mulw_d_w = 0x3eU << 15,
467   op_mulw_d_wu = 0x3fU << 15,
468   op_div_w = 0x40U << 15,
469   op_mod_w = 0x41U << 15,
470   op_div_wu = 0x42U << 15,
471   op_mod_wu = 0x43U << 15,
472   op_div_d = 0x44U << 15,
473   op_mod_d = 0x45U << 15,
474   op_div_du = 0x46U << 15,
475   op_mod_du = 0x47U << 15,
476   op_break = 0x54U << 15,
477   op_syscall = 0x56U << 15,
478   op_fadd_s = 0x201U << 15,
479   op_fadd_d = 0x202U << 15,
480   op_fsub_s = 0x205U << 15,
481   op_fsub_d = 0x206U << 15,
482   op_fmul_s = 0x209U << 15,
483   op_fmul_d = 0x20aU << 15,
484   op_fdiv_s = 0x20dU << 15,
485   op_fdiv_d = 0x20eU << 15,
486   op_fmax_s = 0x211U << 15,
487   op_fmax_d = 0x212U << 15,
488   op_fmin_s = 0x215U << 15,
489   op_fmin_d = 0x216U << 15,
490   op_fmaxa_s = 0x219U << 15,
491   op_fmaxa_d = 0x21aU << 15,
492   op_fmina_s = 0x21dU << 15,
493   op_fmina_d = 0x21eU << 15,
494   op_fcopysign_s = 0x225U << 15,
495   op_fcopysign_d = 0x226U << 15,
496   op_ldx_b = 0x7000U << 15,
497   op_ldx_h = 0x7008U << 15,
498   op_ldx_w = 0x7010U << 15,
499   op_ldx_d = 0x7018U << 15,
500   op_stx_b = 0x7020U << 15,
501   op_stx_h = 0x7028U << 15,
502   op_stx_w = 0x7030U << 15,
503   op_stx_d = 0x7038U << 15,
504   op_ldx_bu = 0x7040U << 15,
505   op_ldx_hu = 0x7048U << 15,
506   op_ldx_wu = 0x7050U << 15,
507   op_fldx_s = 0x7060U << 15,
508   op_fldx_d = 0x7068U << 15,
509   op_fstx_s = 0x7070U << 15,
510   op_fstx_d = 0x7078U << 15,
511   op_amswap_w = 0x70c0U << 15,
512   op_amswap_d = 0x70c1U << 15,
513   op_amadd_w = 0x70c2U << 15,
514   op_amadd_d = 0x70c3U << 15,
515   op_amand_w = 0x70c4U << 15,
516   op_amand_d = 0x70c5U << 15,
517   op_amor_w = 0x70c6U << 15,
518   op_amor_d = 0x70c7U << 15,
519   op_amxor_w = 0x70c8U << 15,
520   op_amxor_d = 0x70c9U << 15,
521   op_ammax_w = 0x70caU << 15,
522   op_ammax_d = 0x70cbU << 15,
523   op_ammin_w = 0x70ccU << 15,
524   op_ammin_d = 0x70cdU << 15,
525   op_ammax_wu = 0x70ceU << 15,
526   op_ammax_du = 0x70cfU << 15,
527   op_ammin_wu = 0x70d0U << 15,
528   op_ammin_du = 0x70d1U << 15,
529   op_amswap_db_w = 0x70d2U << 15,
530   op_amswap_db_d = 0x70d3U << 15,
531   op_amadd_db_w = 0x70d4U << 15,
532   op_amadd_db_d = 0x70d5U << 15,
533   op_amand_db_w = 0x70d6U << 15,
534   op_amand_db_d = 0x70d7U << 15,
535   op_amor_db_w = 0x70d8U << 15,
536   op_amor_db_d = 0x70d9U << 15,
537   op_amxor_db_w = 0x70daU << 15,
538   op_amxor_db_d = 0x70dbU << 15,
539   op_ammax_db_w = 0x70dcU << 15,
540   op_ammax_db_d = 0x70ddU << 15,
541   op_ammin_db_w = 0x70deU << 15,
542   op_ammin_db_d = 0x70dfU << 15,
543   op_ammax_db_wu = 0x70e0U << 15,
544   op_ammax_db_du = 0x70e1U << 15,
545   op_ammin_db_wu = 0x70e2U << 15,
546   op_ammin_db_du = 0x70e3U << 15,
547   op_dbar = 0x70e4U << 15,
548   op_ibar = 0x70e5U << 15,
549   op_clo_w = 0x4U << 10,
550   op_clz_w = 0x5U << 10,
551   op_cto_w = 0x6U << 10,
552   op_ctz_w = 0x7U << 10,
553   op_clo_d = 0x8U << 10,
554   op_clz_d = 0x9U << 10,
555   op_cto_d = 0xaU << 10,
556   op_ctz_d = 0xbU << 10,
557   op_revb_2h = 0xcU << 10,
558   op_revb_4h = 0xdU << 10,
559   op_revb_2w = 0xeU << 10,
560   op_revb_d = 0xfU << 10,
561   op_revh_2w = 0x10U << 10,
562   op_revh_d = 0x11U << 10,
563   op_bitrev_4b = 0x12U << 10,
564   op_bitrev_8b = 0x13U << 10,
565   op_bitrev_w = 0x14U << 10,
566   op_bitrev_d = 0x15U << 10,
567   op_ext_w_h = 0x16U << 10,
568   op_ext_w_b = 0x17U << 10,
569   op_fabs_s = 0x4501U << 10,
570   op_fabs_d = 0x4502U << 10,
571   op_fneg_s = 0x4505U << 10,
572   op_fneg_d = 0x4506U << 10,
573   op_fsqrt_s = 0x4511U << 10,
574   op_fsqrt_d = 0x4512U << 10,
575   op_fmov_s = 0x4525U << 10,
576   op_fmov_d = 0x4526U << 10,
577   op_movgr2fr_w = 0x4529U << 10,
578   op_movgr2fr_d = 0x452aU << 10,
579   op_movgr2frh_w = 0x452bU << 10,
580   op_movfr2gr_s = 0x452dU << 10,
581   op_movfr2gr_d = 0x452eU << 10,
582   op_movfrh2gr_s = 0x452fU << 10,
583   op_movgr2fcsr = 0x4530U << 10,
584   op_movfcsr2gr = 0x4532U << 10,
585   op_movfr2cf = 0x4534U << 10,
586   op_movgr2cf = 0x4536U << 10,
587   op_fcvt_s_d = 0x4646U << 10,
588   op_fcvt_d_s = 0x4649U << 10,
589   op_ftintrm_w_s = 0x4681U << 10,
590   op_ftintrm_w_d = 0x4682U << 10,
591   op_ftintrm_l_s = 0x4689U << 10,
592   op_ftintrm_l_d = 0x468aU << 10,
593   op_ftintrp_w_s = 0x4691U << 10,
594   op_ftintrp_w_d = 0x4692U << 10,
595   op_ftintrp_l_s = 0x4699U << 10,
596   op_ftintrp_l_d = 0x469aU << 10,
597   op_ftintrz_w_s = 0x46a1U << 10,
598   op_ftintrz_w_d = 0x46a2U << 10,
599   op_ftintrz_l_s = 0x46a9U << 10,
600   op_ftintrz_l_d = 0x46aaU << 10,
601   op_ftintrne_w_s = 0x46b1U << 10,
602   op_ftintrne_w_d = 0x46b2U << 10,
603   op_ftintrne_l_s = 0x46b9U << 10,
604   op_ftintrne_l_d = 0x46baU << 10,
605   op_ftint_w_s = 0x46c1U << 10,
606   op_ftint_w_d = 0x46c2U << 10,
607   op_ftint_l_s = 0x46c9U << 10,
608   op_ftint_l_d = 0x46caU << 10,
609   op_ffint_s_w = 0x4744U << 10,
610   op_ffint_s_l = 0x4746U << 10,
611   op_ffint_d_w = 0x4748U << 10,
612   op_ffint_d_l = 0x474aU << 10,
613   op_frint_s = 0x4791U << 10,
614   op_frint_d = 0x4792U << 10,
615   op_movcf2fr = 0x114d4U << 8,
616   op_movcf2gr = 0x114dcU << 8,
617 };
618 
619 class Operand;
620 
621 // A BOffImm16 is a 16 bit immediate that is used for branches.
622 class BOffImm16 {
623   uint32_t data;
624 
625  public:
encode()626   uint32_t encode() {
627     MOZ_ASSERT(!isInvalid());
628     return data;
629   }
decode()630   int32_t decode() {
631     MOZ_ASSERT(!isInvalid());
632     return (int32_t(data << 18) >> 16);
633   }
634 
BOffImm16(int offset)635   explicit BOffImm16(int offset) : data((offset) >> 2 & Imm16Mask) {
636     MOZ_ASSERT((offset & 0x3) == 0);
637     MOZ_ASSERT(IsInRange(offset));
638   }
IsInRange(int offset)639   static bool IsInRange(int offset) {
640     if ((offset) < int(unsigned(INT16_MIN) << 2)) {
641       return false;
642     }
643     if ((offset) > (INT16_MAX << 2)) {
644       return false;
645     }
646     return true;
647   }
648   static const uint32_t INVALID = 0x00020000;
BOffImm16()649   BOffImm16() : data(INVALID) {}
650 
isInvalid()651   bool isInvalid() { return data == INVALID; }
652   Instruction* getDest(Instruction* src) const;
653 
654   BOffImm16(InstImm inst);
655 };
656 
657 // A JOffImm26 is a 26 bit immediate that is used for unconditional jumps.
658 class JOffImm26 {
659   uint32_t data;
660 
661  public:
encode()662   uint32_t encode() {
663     MOZ_ASSERT(!isInvalid());
664     return data;
665   }
decode()666   int32_t decode() {
667     MOZ_ASSERT(!isInvalid());
668     return (int32_t(data << 8) >> 6);
669   }
670 
JOffImm26(int offset)671   explicit JOffImm26(int offset) : data((offset) >> 2 & Imm26Mask) {
672     MOZ_ASSERT((offset & 0x3) == 0);
673     MOZ_ASSERT(IsInRange(offset));
674   }
IsInRange(int offset)675   static bool IsInRange(int offset) {
676     if ((offset) < -536870912) {
677       return false;
678     }
679     if ((offset) > 536870908) {
680       return false;
681     }
682     return true;
683   }
684   static const uint32_t INVALID = 0x20000000;
JOffImm26()685   JOffImm26() : data(INVALID) {}
686 
isInvalid()687   bool isInvalid() { return data == INVALID; }
688   Instruction* getDest(Instruction* src);
689 };
690 
691 class Imm16 {
692   uint16_t value;
693 
694  public:
695   Imm16();
Imm16(uint32_t imm)696   Imm16(uint32_t imm) : value(imm) {}
encode()697   uint32_t encode() { return value; }
decodeSigned()698   int32_t decodeSigned() { return value; }
decodeUnsigned()699   uint32_t decodeUnsigned() { return value; }
700 
IsInSignedRange(int32_t imm)701   static bool IsInSignedRange(int32_t imm) {
702     return imm >= INT16_MIN && imm <= INT16_MAX;
703   }
704 
IsInUnsignedRange(uint32_t imm)705   static bool IsInUnsignedRange(uint32_t imm) { return imm <= UINT16_MAX; }
706 };
707 
708 class Imm8 {
709   uint8_t value;
710 
711  public:
712   Imm8();
Imm8(uint32_t imm)713   Imm8(uint32_t imm) : value(imm) {}
encode(uint32_t shift)714   uint32_t encode(uint32_t shift) { return value << shift; }
decodeSigned()715   int32_t decodeSigned() { return value; }
decodeUnsigned()716   uint32_t decodeUnsigned() { return value; }
IsInSignedRange(int32_t imm)717   static bool IsInSignedRange(int32_t imm) {
718     return imm >= INT8_MIN && imm <= INT8_MAX;
719   }
IsInUnsignedRange(uint32_t imm)720   static bool IsInUnsignedRange(uint32_t imm) { return imm <= UINT8_MAX; }
Lower(Imm16 imm)721   static Imm8 Lower(Imm16 imm) { return Imm8(imm.decodeSigned() & 0xff); }
Upper(Imm16 imm)722   static Imm8 Upper(Imm16 imm) {
723     return Imm8((imm.decodeSigned() >> 8) & 0xff);
724   }
725 };
726 
727 class Operand {
728  public:
729   enum Tag { REG, FREG, MEM };
730 
731  private:
732   Tag tag : 3;
733   uint32_t reg : 5;
734   int32_t offset;
735 
736  public:
Operand(Register reg_)737   Operand(Register reg_) : tag(REG), reg(reg_.code()) {}
738 
Operand(FloatRegister freg)739   Operand(FloatRegister freg) : tag(FREG), reg(freg.code()) {}
740 
Operand(Register base,Imm32 off)741   Operand(Register base, Imm32 off)
742       : tag(MEM), reg(base.code()), offset(off.value) {}
743 
Operand(Register base,int32_t off)744   Operand(Register base, int32_t off)
745       : tag(MEM), reg(base.code()), offset(off) {}
746 
Operand(const Address & addr)747   Operand(const Address& addr)
748       : tag(MEM), reg(addr.base.code()), offset(addr.offset) {}
749 
getTag()750   Tag getTag() const { return tag; }
751 
toReg()752   Register toReg() const {
753     MOZ_ASSERT(tag == REG);
754     return Register::FromCode(reg);
755   }
756 
toFReg()757   FloatRegister toFReg() const {
758     MOZ_ASSERT(tag == FREG);
759     return FloatRegister::FromCode(reg);
760   }
761 
toAddr(Register * r,Imm32 * dest)762   void toAddr(Register* r, Imm32* dest) const {
763     MOZ_ASSERT(tag == MEM);
764     *r = Register::FromCode(reg);
765     *dest = Imm32(offset);
766   }
toAddress()767   Address toAddress() const {
768     MOZ_ASSERT(tag == MEM);
769     return Address(Register::FromCode(reg), offset);
770   }
disp()771   int32_t disp() const {
772     MOZ_ASSERT(tag == MEM);
773     return offset;
774   }
775 
base()776   int32_t base() const {
777     MOZ_ASSERT(tag == MEM);
778     return reg;
779   }
baseReg()780   Register baseReg() const {
781     MOZ_ASSERT(tag == MEM);
782     return Register::FromCode(reg);
783   }
784 };
785 
786 // int check.
is_intN(int32_t x,unsigned n)787 inline bool is_intN(int32_t x, unsigned n) {
788   MOZ_ASSERT((0 < n) && (n < 64));
789   int32_t limit = static_cast<int32_t>(1) << (n - 1);
790   return (-limit <= x) && (x < limit);
791 }
792 
is_uintN(int32_t x,unsigned n)793 inline bool is_uintN(int32_t x, unsigned n) {
794   MOZ_ASSERT((0 < n) && (n < (sizeof(x) * 8)));
795   return !(x >> n);
796 }
797 
firstHalf()798 inline Imm32 Imm64::firstHalf() const { return low(); }
799 
secondHalf()800 inline Imm32 Imm64::secondHalf() const { return hi(); }
801 
802 static constexpr int32_t SliceSize = 1024;
803 typedef js::jit::AssemblerBuffer<SliceSize, Instruction> LOONGBuffer;
804 
805 class LOONGBufferWithExecutableCopy : public LOONGBuffer {
806  public:
executableCopy(uint8_t * buffer)807   void executableCopy(uint8_t* buffer) {
808     if (this->oom()) {
809       return;
810     }
811 
812     for (Slice* cur = head; cur != nullptr; cur = cur->getNext()) {
813       memcpy(buffer, &cur->instructions, cur->length());
814       buffer += cur->length();
815     }
816   }
817 
appendRawCode(const uint8_t * code,size_t numBytes)818   bool appendRawCode(const uint8_t* code, size_t numBytes) {
819     if (this->oom()) {
820       return false;
821     }
822     while (numBytes > SliceSize) {
823       this->putBytes(SliceSize, code);
824       numBytes -= SliceSize;
825       code += SliceSize;
826     }
827     this->putBytes(numBytes, code);
828     return !this->oom();
829   }
830 };
831 
832 class AssemblerLOONG64 : public AssemblerShared {
833  public:
834   // TODO(loong64): Should we remove these conditions here?
835   enum Condition {
836     Equal,
837     NotEqual,
838     Above,
839     AboveOrEqual,
840     Below,
841     BelowOrEqual,
842     GreaterThan,
843     GreaterThanOrEqual,
844     GreaterThanOrEqual_Signed,
845     GreaterThanOrEqual_NotSigned,
846     LessThan,
847     LessThan_Signed,
848     LessThan_NotSigned,
849     LessThanOrEqual,
850     Overflow,
851     CarrySet,
852     CarryClear,
853     Signed,
854     NotSigned,
855     Zero,
856     NonZero,
857     Always,
858   };
859 
860   enum DoubleCondition {
861     DoubleOrdered,
862     DoubleEqual,
863     DoubleNotEqual,
864     DoubleGreaterThan,
865     DoubleGreaterThanOrEqual,
866     DoubleLessThan,
867     DoubleLessThanOrEqual,
868     DoubleUnordered,
869     DoubleEqualOrUnordered,
870     DoubleNotEqualOrUnordered,
871     DoubleGreaterThanOrUnordered,
872     DoubleGreaterThanOrEqualOrUnordered,
873     DoubleLessThanOrUnordered,
874     DoubleLessThanOrEqualOrUnordered
875   };
876 
877   enum FPUCondition {
878     kNoFPUCondition = -1,
879 
880     CAF = 0x00,
881     SAF = 0x01,
882     CLT = 0x02,
883     SLT = 0x03,
884     CEQ = 0x04,
885     SEQ = 0x05,
886     CLE = 0x06,
887     SLE = 0x07,
888     CUN = 0x08,
889     SUN = 0x09,
890     CULT = 0x0a,
891     SULT = 0x0b,
892     CUEQ = 0x0c,
893     SUEQ = 0x0d,
894     CULE = 0x0e,
895     SULE = 0x0f,
896     CNE = 0x10,
897     SNE = 0x11,
898     COR = 0x14,
899     SOR = 0x15,
900     CUNE = 0x18,
901     SUNE = 0x19,
902   };
903 
904   enum FPConditionBit { FCC0 = 0, FCC1, FFC2, FCC3, FCC4, FCC5, FCC6, FCC7 };
905 
906   enum FPControl { FCSR = 0 };
907 
908   enum FCSRBit { CauseI = 24, CauseU, CauseO, CauseZ, CauseV };
909 
910   enum FloatFormat { SingleFloat, DoubleFloat };
911 
912   enum JumpOrCall { BranchIsJump, BranchIsCall };
913 
914   enum FloatTestKind { TestForTrue, TestForFalse };
915 
916   // :( this should be protected, but since CodeGenerator
917   // wants to use it, It needs to go out here :(
918 
nextOffset()919   BufferOffset nextOffset() { return m_buffer.nextOffset(); }
920 
921  protected:
editSrc(BufferOffset bo)922   Instruction* editSrc(BufferOffset bo) { return m_buffer.getInst(bo); }
923 
924   // structure for fixing up pc-relative loads/jumps when a the machine code
925   // gets moved (executable copy, gc, etc.)
926   struct RelativePatch {
927     // the offset within the code buffer where the value is loaded that
928     // we want to fix-up
929     BufferOffset offset;
930     void* target;
931     RelocationKind kind;
932 
RelativePatchRelativePatch933     RelativePatch(BufferOffset offset, void* target, RelocationKind kind)
934         : offset(offset), target(target), kind(kind) {}
935   };
936 
937   js::Vector<RelativePatch, 8, SystemAllocPolicy> jumps_;
938 
939   CompactBufferWriter jumpRelocations_;
940   CompactBufferWriter dataRelocations_;
941 
942   LOONGBufferWithExecutableCopy m_buffer;
943 
944 #ifdef JS_JITSPEW
945   Sprinter* printer;
946 #endif
947 
948  public:
AssemblerLOONG64()949   AssemblerLOONG64()
950       : m_buffer(),
951 #ifdef JS_JITSPEW
952         printer(nullptr),
953 #endif
954         isFinished(false) {
955   }
956 
957   static Condition InvertCondition(Condition cond);
958   static DoubleCondition InvertCondition(DoubleCondition cond);
959   // This is changing the condition codes for cmp a, b to the same codes for cmp
960   // b, a.
961   static Condition InvertCmpCondition(Condition cond);
962 
963   // As opposed to x86/x64 version, the data relocation has to be executed
964   // before to recover the pointer, and not after.
writeDataRelocation(ImmGCPtr ptr)965   void writeDataRelocation(ImmGCPtr ptr) {
966     // Raw GC pointer relocations and Value relocations both end up in
967     // TraceOneDataRelocation.
968     if (ptr.value) {
969       if (gc::IsInsideNursery(ptr.value)) {
970         embedsNurseryPointers_ = true;
971       }
972       dataRelocations_.writeUnsigned(nextOffset().getOffset());
973     }
974   }
975 
assertNoGCThings()976   void assertNoGCThings() const {
977 #ifdef DEBUG
978     MOZ_ASSERT(dataRelocations_.length() == 0);
979     for (auto& j : jumps_) {
980       MOZ_ASSERT(j.kind == RelocationKind::HARDCODED);
981     }
982 #endif
983   }
984 
985  public:
setUnlimitedBuffer()986   void setUnlimitedBuffer() { m_buffer.setUnlimited(); }
987   bool oom() const;
988 
setPrinter(Sprinter * sp)989   void setPrinter(Sprinter* sp) {
990 #ifdef JS_JITSPEW
991     printer = sp;
992 #endif
993   }
994 
995 #ifdef JS_JITSPEW
spew(const char * fmt,...)996   inline void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) {
997     if (MOZ_UNLIKELY(printer || JitSpewEnabled(JitSpew_Codegen))) {
998       va_list va;
999       va_start(va, fmt);
1000       spew(fmt, va);
1001       va_end(va);
1002     }
1003   }
1004 
1005   void decodeBranchInstAndSpew(InstImm branch);
1006 #else
spew(const char * fmt,...)1007   MOZ_ALWAYS_INLINE void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) {}
1008 #endif
1009 
1010 #ifdef JS_JITSPEW
spew(const char * fmt,va_list va)1011   MOZ_COLD void spew(const char* fmt, va_list va) MOZ_FORMAT_PRINTF(2, 0) {
1012     // Buffer to hold the formatted string. Note that this may contain
1013     // '%' characters, so do not pass it directly to printf functions.
1014     char buf[200];
1015 
1016     int i = VsprintfLiteral(buf, fmt, va);
1017     if (i > -1) {
1018       if (printer) {
1019         printer->printf("%s\n", buf);
1020       }
1021       js::jit::JitSpew(js::jit::JitSpew_Codegen, "%s", buf);
1022     }
1023   }
1024 #endif
1025 
getStackPointer()1026   Register getStackPointer() const { return StackPointer; }
1027 
1028  protected:
1029   bool isFinished;
1030 
1031  public:
1032   void finish();
1033   bool appendRawCode(const uint8_t* code, size_t numBytes);
1034   bool reserve(size_t size);
1035   bool swapBuffer(wasm::Bytes& bytes);
1036   void executableCopy(void* buffer);
1037   void copyJumpRelocationTable(uint8_t* dest);
1038   void copyDataRelocationTable(uint8_t* dest);
1039 
1040   // Size of the instruction stream, in bytes.
1041   size_t size() const;
1042   // Size of the jump relocation table, in bytes.
1043   size_t jumpRelocationTableBytes() const;
1044   size_t dataRelocationTableBytes() const;
1045 
1046   // Size of the data table, in bytes.
1047   size_t bytesNeeded() const;
1048 
1049   // Write a blob of binary into the instruction stream *OR*
1050   // into a destination address. If dest is nullptr (the default), then the
1051   // instruction gets written into the instruction stream. If dest is not null
1052   // it is interpreted as a pointer to the location that we want the
1053   // instruction to be written.
1054   BufferOffset writeInst(uint32_t x, uint32_t* dest = nullptr);
1055   // A static variant for the cases where we don't want to have an assembler
1056   // object at all. Normally, you would use the dummy (nullptr) object.
1057   static void WriteInstStatic(uint32_t x, uint32_t* dest);
1058 
1059  public:
1060   BufferOffset haltingAlign(int alignment);
1061   BufferOffset nopAlign(int alignment);
as_nop()1062   BufferOffset as_nop() { return as_andi(zero, zero, 0); }
1063 
1064   // Branch and jump instructions
1065   BufferOffset as_b(JOffImm26 off);
1066   BufferOffset as_bl(JOffImm26 off);
1067   BufferOffset as_jirl(Register rd, Register rj, BOffImm16 off);
1068 
1069   InstImm getBranchCode(JumpOrCall jumpOrCall);  // b, bl
1070   InstImm getBranchCode(Register rd, Register rj,
1071                         Condition c);  // beq, bne, bge, bgeu, blt, bltu
1072   InstImm getBranchCode(Register rj, Condition c);  // beqz, bnez
1073   InstImm getBranchCode(FPConditionBit cj);         // bceqz, bcnez
1074 
1075   // Arithmetic instructions
1076   BufferOffset as_add_w(Register rd, Register rj, Register rk);
1077   BufferOffset as_add_d(Register rd, Register rj, Register rk);
1078   BufferOffset as_sub_w(Register rd, Register rj, Register rk);
1079   BufferOffset as_sub_d(Register rd, Register rj, Register rk);
1080 
1081   BufferOffset as_addi_w(Register rd, Register rj, int32_t si12);
1082   BufferOffset as_addi_d(Register rd, Register rj, int32_t si12);
1083   BufferOffset as_addu16i_d(Register rd, Register rj, int32_t si16);
1084 
1085   BufferOffset as_alsl_w(Register rd, Register rj, Register rk, uint32_t sa2);
1086   BufferOffset as_alsl_wu(Register rd, Register rj, Register rk, uint32_t sa2);
1087   BufferOffset as_alsl_d(Register rd, Register rj, Register rk, uint32_t sa2);
1088 
1089   BufferOffset as_lu12i_w(Register rd, int32_t si20);
1090   BufferOffset as_lu32i_d(Register rd, int32_t si20);
1091   BufferOffset as_lu52i_d(Register rd, Register rj, int32_t si12);
1092 
1093   BufferOffset as_slt(Register rd, Register rj, Register rk);
1094   BufferOffset as_sltu(Register rd, Register rj, Register rk);
1095   BufferOffset as_slti(Register rd, Register rj, int32_t si12);
1096   BufferOffset as_sltui(Register rd, Register rj, int32_t si12);
1097 
1098   BufferOffset as_pcaddi(Register rd, int32_t si20);
1099   BufferOffset as_pcaddu12i(Register rd, int32_t si20);
1100   BufferOffset as_pcaddu18i(Register rd, int32_t si20);
1101   BufferOffset as_pcalau12i(Register rd, int32_t si20);
1102 
1103   BufferOffset as_mul_w(Register rd, Register rj, Register rk);
1104   BufferOffset as_mulh_w(Register rd, Register rj, Register rk);
1105   BufferOffset as_mulh_wu(Register rd, Register rj, Register rk);
1106   BufferOffset as_mul_d(Register rd, Register rj, Register rk);
1107   BufferOffset as_mulh_d(Register rd, Register rj, Register rk);
1108   BufferOffset as_mulh_du(Register rd, Register rj, Register rk);
1109 
1110   BufferOffset as_mulw_d_w(Register rd, Register rj, Register rk);
1111   BufferOffset as_mulw_d_wu(Register rd, Register rj, Register rk);
1112 
1113   BufferOffset as_div_w(Register rd, Register rj, Register rk);
1114   BufferOffset as_mod_w(Register rd, Register rj, Register rk);
1115   BufferOffset as_div_wu(Register rd, Register rj, Register rk);
1116   BufferOffset as_mod_wu(Register rd, Register rj, Register rk);
1117   BufferOffset as_div_d(Register rd, Register rj, Register rk);
1118   BufferOffset as_mod_d(Register rd, Register rj, Register rk);
1119   BufferOffset as_div_du(Register rd, Register rj, Register rk);
1120   BufferOffset as_mod_du(Register rd, Register rj, Register rk);
1121 
1122   // Logical instructions
1123   BufferOffset as_and(Register rd, Register rj, Register rk);
1124   BufferOffset as_or(Register rd, Register rj, Register rk);
1125   BufferOffset as_xor(Register rd, Register rj, Register rk);
1126   BufferOffset as_nor(Register rd, Register rj, Register rk);
1127   BufferOffset as_andn(Register rd, Register rj, Register rk);
1128   BufferOffset as_orn(Register rd, Register rj, Register rk);
1129 
1130   BufferOffset as_andi(Register rd, Register rj, int32_t ui12);
1131   BufferOffset as_ori(Register rd, Register rj, int32_t ui12);
1132   BufferOffset as_xori(Register rd, Register rj, int32_t ui12);
1133 
1134   // Shift instructions
1135   BufferOffset as_sll_w(Register rd, Register rj, Register rk);
1136   BufferOffset as_srl_w(Register rd, Register rj, Register rk);
1137   BufferOffset as_sra_w(Register rd, Register rj, Register rk);
1138   BufferOffset as_rotr_w(Register rd, Register rj, Register rk);
1139 
1140   BufferOffset as_slli_w(Register rd, Register rj, int32_t ui5);
1141   BufferOffset as_srli_w(Register rd, Register rj, int32_t ui5);
1142   BufferOffset as_srai_w(Register rd, Register rj, int32_t ui5);
1143   BufferOffset as_rotri_w(Register rd, Register rj, int32_t ui5);
1144 
1145   BufferOffset as_sll_d(Register rd, Register rj, Register rk);
1146   BufferOffset as_srl_d(Register rd, Register rj, Register rk);
1147   BufferOffset as_sra_d(Register rd, Register rj, Register rk);
1148   BufferOffset as_rotr_d(Register rd, Register rj, Register rk);
1149 
1150   BufferOffset as_slli_d(Register rd, Register rj, int32_t ui6);
1151   BufferOffset as_srli_d(Register rd, Register rj, int32_t ui6);
1152   BufferOffset as_srai_d(Register rd, Register rj, int32_t ui6);
1153   BufferOffset as_rotri_d(Register rd, Register rj, int32_t ui6);
1154 
1155   // Bit operation instrucitons
1156   BufferOffset as_ext_w_b(Register rd, Register rj);
1157   BufferOffset as_ext_w_h(Register rd, Register rj);
1158 
1159   BufferOffset as_clo_w(Register rd, Register rj);
1160   BufferOffset as_clz_w(Register rd, Register rj);
1161   BufferOffset as_cto_w(Register rd, Register rj);
1162   BufferOffset as_ctz_w(Register rd, Register rj);
1163   BufferOffset as_clo_d(Register rd, Register rj);
1164   BufferOffset as_clz_d(Register rd, Register rj);
1165   BufferOffset as_cto_d(Register rd, Register rj);
1166   BufferOffset as_ctz_d(Register rd, Register rj);
1167 
1168   BufferOffset as_bytepick_w(Register rd, Register rj, Register rk,
1169                              int32_t sa2);
1170   BufferOffset as_bytepick_d(Register rd, Register rj, Register rk,
1171                              int32_t sa3);
1172 
1173   BufferOffset as_revb_2h(Register rd, Register rj);
1174   BufferOffset as_revb_4h(Register rd, Register rj);
1175   BufferOffset as_revb_2w(Register rd, Register rj);
1176   BufferOffset as_revb_d(Register rd, Register rj);
1177 
1178   BufferOffset as_revh_2w(Register rd, Register rj);
1179   BufferOffset as_revh_d(Register rd, Register rj);
1180 
1181   BufferOffset as_bitrev_4b(Register rd, Register rj);
1182   BufferOffset as_bitrev_8b(Register rd, Register rj);
1183 
1184   BufferOffset as_bitrev_w(Register rd, Register rj);
1185   BufferOffset as_bitrev_d(Register rd, Register rj);
1186 
1187   BufferOffset as_bstrins_w(Register rd, Register rj, int32_t msbw,
1188                             int32_t lsbw);
1189   BufferOffset as_bstrins_d(Register rd, Register rj, int32_t msbd,
1190                             int32_t lsbd);
1191   BufferOffset as_bstrpick_w(Register rd, Register rj, int32_t msbw,
1192                              int32_t lsbw);
1193   BufferOffset as_bstrpick_d(Register rd, Register rj, int32_t msbd,
1194                              int32_t lsbd);
1195 
1196   BufferOffset as_maskeqz(Register rd, Register rj, Register rk);
1197   BufferOffset as_masknez(Register rd, Register rj, Register rk);
1198 
1199   // Load and store instructions
1200   BufferOffset as_ld_b(Register rd, Register rj, int32_t si12);
1201   BufferOffset as_ld_h(Register rd, Register rj, int32_t si12);
1202   BufferOffset as_ld_w(Register rd, Register rj, int32_t si12);
1203   BufferOffset as_ld_d(Register rd, Register rj, int32_t si12);
1204   BufferOffset as_ld_bu(Register rd, Register rj, int32_t si12);
1205   BufferOffset as_ld_hu(Register rd, Register rj, int32_t si12);
1206   BufferOffset as_ld_wu(Register rd, Register rj, int32_t si12);
1207   BufferOffset as_st_b(Register rd, Register rj, int32_t si12);
1208   BufferOffset as_st_h(Register rd, Register rj, int32_t si12);
1209   BufferOffset as_st_w(Register rd, Register rj, int32_t si12);
1210   BufferOffset as_st_d(Register rd, Register rj, int32_t si12);
1211 
1212   BufferOffset as_ldx_b(Register rd, Register rj, Register rk);
1213   BufferOffset as_ldx_h(Register rd, Register rj, Register rk);
1214   BufferOffset as_ldx_w(Register rd, Register rj, Register rk);
1215   BufferOffset as_ldx_d(Register rd, Register rj, Register rk);
1216   BufferOffset as_ldx_bu(Register rd, Register rj, Register rk);
1217   BufferOffset as_ldx_hu(Register rd, Register rj, Register rk);
1218   BufferOffset as_ldx_wu(Register rd, Register rj, Register rk);
1219   BufferOffset as_stx_b(Register rd, Register rj, Register rk);
1220   BufferOffset as_stx_h(Register rd, Register rj, Register rk);
1221   BufferOffset as_stx_w(Register rd, Register rj, Register rk);
1222   BufferOffset as_stx_d(Register rd, Register rj, Register rk);
1223 
1224   BufferOffset as_ldptr_w(Register rd, Register rj, int32_t si14);
1225   BufferOffset as_ldptr_d(Register rd, Register rj, int32_t si14);
1226   BufferOffset as_stptr_w(Register rd, Register rj, int32_t si14);
1227   BufferOffset as_stptr_d(Register rd, Register rj, int32_t si14);
1228 
1229   BufferOffset as_preld(int32_t hint, Register rj, int32_t si12);
1230 
1231   // Atomic instructions
1232   BufferOffset as_amswap_w(Register rd, Register rj, Register rk);
1233   BufferOffset as_amswap_d(Register rd, Register rj, Register rk);
1234   BufferOffset as_amadd_w(Register rd, Register rj, Register rk);
1235   BufferOffset as_amadd_d(Register rd, Register rj, Register rk);
1236   BufferOffset as_amand_w(Register rd, Register rj, Register rk);
1237   BufferOffset as_amand_d(Register rd, Register rj, Register rk);
1238   BufferOffset as_amor_w(Register rd, Register rj, Register rk);
1239   BufferOffset as_amor_d(Register rd, Register rj, Register rk);
1240   BufferOffset as_amxor_w(Register rd, Register rj, Register rk);
1241   BufferOffset as_amxor_d(Register rd, Register rj, Register rk);
1242   BufferOffset as_ammax_w(Register rd, Register rj, Register rk);
1243   BufferOffset as_ammax_d(Register rd, Register rj, Register rk);
1244   BufferOffset as_ammin_w(Register rd, Register rj, Register rk);
1245   BufferOffset as_ammin_d(Register rd, Register rj, Register rk);
1246   BufferOffset as_ammax_wu(Register rd, Register rj, Register rk);
1247   BufferOffset as_ammax_du(Register rd, Register rj, Register rk);
1248   BufferOffset as_ammin_wu(Register rd, Register rj, Register rk);
1249   BufferOffset as_ammin_du(Register rd, Register rj, Register rk);
1250 
1251   BufferOffset as_amswap_db_w(Register rd, Register rj, Register rk);
1252   BufferOffset as_amswap_db_d(Register rd, Register rj, Register rk);
1253   BufferOffset as_amadd_db_w(Register rd, Register rj, Register rk);
1254   BufferOffset as_amadd_db_d(Register rd, Register rj, Register rk);
1255   BufferOffset as_amand_db_w(Register rd, Register rj, Register rk);
1256   BufferOffset as_amand_db_d(Register rd, Register rj, Register rk);
1257   BufferOffset as_amor_db_w(Register rd, Register rj, Register rk);
1258   BufferOffset as_amor_db_d(Register rd, Register rj, Register rk);
1259   BufferOffset as_amxor_db_w(Register rd, Register rj, Register rk);
1260   BufferOffset as_amxor_db_d(Register rd, Register rj, Register rk);
1261   BufferOffset as_ammax_db_w(Register rd, Register rj, Register rk);
1262   BufferOffset as_ammax_db_d(Register rd, Register rj, Register rk);
1263   BufferOffset as_ammin_db_w(Register rd, Register rj, Register rk);
1264   BufferOffset as_ammin_db_d(Register rd, Register rj, Register rk);
1265   BufferOffset as_ammax_db_wu(Register rd, Register rj, Register rk);
1266   BufferOffset as_ammax_db_du(Register rd, Register rj, Register rk);
1267   BufferOffset as_ammin_db_wu(Register rd, Register rj, Register rk);
1268   BufferOffset as_ammin_db_du(Register rd, Register rj, Register rk);
1269 
1270   BufferOffset as_ll_w(Register rd, Register rj, int32_t si14);
1271   BufferOffset as_ll_d(Register rd, Register rj, int32_t si14);
1272   BufferOffset as_sc_w(Register rd, Register rj, int32_t si14);
1273   BufferOffset as_sc_d(Register rd, Register rj, int32_t si14);
1274 
1275   // Barrier instructions
1276   BufferOffset as_dbar(int32_t hint);
1277   BufferOffset as_ibar(int32_t hint);
1278 
1279   // FP Arithmetic instructions
1280   BufferOffset as_fadd_s(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1281   BufferOffset as_fadd_d(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1282   BufferOffset as_fsub_s(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1283   BufferOffset as_fsub_d(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1284   BufferOffset as_fmul_s(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1285   BufferOffset as_fmul_d(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1286   BufferOffset as_fdiv_s(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1287   BufferOffset as_fdiv_d(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1288 
1289   BufferOffset as_fmadd_s(FloatRegister fd, FloatRegister fj, FloatRegister fk,
1290                           FloatRegister fa);
1291   BufferOffset as_fmadd_d(FloatRegister fd, FloatRegister fj, FloatRegister fk,
1292                           FloatRegister fa);
1293   BufferOffset as_fmsub_s(FloatRegister fd, FloatRegister fj, FloatRegister fk,
1294                           FloatRegister fa);
1295   BufferOffset as_fmsub_d(FloatRegister fd, FloatRegister fj, FloatRegister fk,
1296                           FloatRegister fa);
1297   BufferOffset as_fnmadd_s(FloatRegister fd, FloatRegister fj, FloatRegister fk,
1298                            FloatRegister fa);
1299   BufferOffset as_fnmadd_d(FloatRegister fd, FloatRegister fj, FloatRegister fk,
1300                            FloatRegister fa);
1301   BufferOffset as_fnmsub_s(FloatRegister fd, FloatRegister fj, FloatRegister fk,
1302                            FloatRegister fa);
1303   BufferOffset as_fnmsub_d(FloatRegister fd, FloatRegister fj, FloatRegister fk,
1304                            FloatRegister fa);
1305 
1306   BufferOffset as_fmax_s(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1307   BufferOffset as_fmax_d(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1308   BufferOffset as_fmin_s(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1309   BufferOffset as_fmin_d(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1310 
1311   BufferOffset as_fmaxa_s(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1312   BufferOffset as_fmaxa_d(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1313   BufferOffset as_fmina_s(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1314   BufferOffset as_fmina_d(FloatRegister fd, FloatRegister fj, FloatRegister fk);
1315 
1316   BufferOffset as_fabs_s(FloatRegister fd, FloatRegister fj);
1317   BufferOffset as_fabs_d(FloatRegister fd, FloatRegister fj);
1318   BufferOffset as_fneg_s(FloatRegister fd, FloatRegister fj);
1319   BufferOffset as_fneg_d(FloatRegister fd, FloatRegister fj);
1320 
1321   BufferOffset as_fsqrt_s(FloatRegister fd, FloatRegister fj);
1322   BufferOffset as_fsqrt_d(FloatRegister fd, FloatRegister fj);
1323   BufferOffset as_fcopysign_s(FloatRegister fd, FloatRegister fj,
1324                               FloatRegister fk);
1325   BufferOffset as_fcopysign_d(FloatRegister fd, FloatRegister fj,
1326                               FloatRegister fk);
1327 
1328   // FP compare instructions (fcmp.cond.s fcmp.cond.d)
1329   BufferOffset as_fcmp_cor(FloatFormat fmt, FloatRegister fj, FloatRegister fk,
1330                            FPConditionBit cd);
1331   BufferOffset as_fcmp_ceq(FloatFormat fmt, FloatRegister fj, FloatRegister fk,
1332                            FPConditionBit cd);
1333   BufferOffset as_fcmp_cne(FloatFormat fmt, FloatRegister fj, FloatRegister fk,
1334                            FPConditionBit cd);
1335   BufferOffset as_fcmp_cle(FloatFormat fmt, FloatRegister fj, FloatRegister fk,
1336                            FPConditionBit cd);
1337   BufferOffset as_fcmp_clt(FloatFormat fmt, FloatRegister fj, FloatRegister fk,
1338                            FPConditionBit cd);
1339   BufferOffset as_fcmp_cun(FloatFormat fmt, FloatRegister fj, FloatRegister fk,
1340                            FPConditionBit cd);
1341   BufferOffset as_fcmp_cueq(FloatFormat fmt, FloatRegister fj, FloatRegister fk,
1342                             FPConditionBit cd);
1343   BufferOffset as_fcmp_cune(FloatFormat fmt, FloatRegister fj, FloatRegister fk,
1344                             FPConditionBit cd);
1345   BufferOffset as_fcmp_cule(FloatFormat fmt, FloatRegister fj, FloatRegister fk,
1346                             FPConditionBit cd);
1347   BufferOffset as_fcmp_cult(FloatFormat fmt, FloatRegister fj, FloatRegister fk,
1348                             FPConditionBit cd);
1349 
1350   // FP conversion instructions
1351   BufferOffset as_fcvt_s_d(FloatRegister fd, FloatRegister fj);
1352   BufferOffset as_fcvt_d_s(FloatRegister fd, FloatRegister fj);
1353 
1354   BufferOffset as_ffint_s_w(FloatRegister fd, FloatRegister fj);
1355   BufferOffset as_ffint_s_l(FloatRegister fd, FloatRegister fj);
1356   BufferOffset as_ffint_d_w(FloatRegister fd, FloatRegister fj);
1357   BufferOffset as_ffint_d_l(FloatRegister fd, FloatRegister fj);
1358   BufferOffset as_ftint_w_s(FloatRegister fd, FloatRegister fj);
1359   BufferOffset as_ftint_w_d(FloatRegister fd, FloatRegister fj);
1360   BufferOffset as_ftint_l_s(FloatRegister fd, FloatRegister fj);
1361   BufferOffset as_ftint_l_d(FloatRegister fd, FloatRegister fj);
1362 
1363   BufferOffset as_ftintrm_w_s(FloatRegister fd, FloatRegister fj);
1364   BufferOffset as_ftintrm_w_d(FloatRegister fd, FloatRegister fj);
1365   BufferOffset as_ftintrm_l_s(FloatRegister fd, FloatRegister fj);
1366   BufferOffset as_ftintrm_l_d(FloatRegister fd, FloatRegister fj);
1367   BufferOffset as_ftintrp_w_s(FloatRegister fd, FloatRegister fj);
1368   BufferOffset as_ftintrp_w_d(FloatRegister fd, FloatRegister fj);
1369   BufferOffset as_ftintrp_l_s(FloatRegister fd, FloatRegister fj);
1370   BufferOffset as_ftintrp_l_d(FloatRegister fd, FloatRegister fj);
1371   BufferOffset as_ftintrz_w_s(FloatRegister fd, FloatRegister fj);
1372   BufferOffset as_ftintrz_w_d(FloatRegister fd, FloatRegister fj);
1373   BufferOffset as_ftintrz_l_s(FloatRegister fd, FloatRegister fj);
1374   BufferOffset as_ftintrz_l_d(FloatRegister fd, FloatRegister fj);
1375   BufferOffset as_ftintrne_w_s(FloatRegister fd, FloatRegister fj);
1376   BufferOffset as_ftintrne_w_d(FloatRegister fd, FloatRegister fj);
1377   BufferOffset as_ftintrne_l_s(FloatRegister fd, FloatRegister fj);
1378   BufferOffset as_ftintrne_l_d(FloatRegister fd, FloatRegister fj);
1379 
1380   BufferOffset as_frint_s(FloatRegister fd, FloatRegister fj);
1381   BufferOffset as_frint_d(FloatRegister fd, FloatRegister fj);
1382 
1383   // FP mov instructions
1384   BufferOffset as_fmov_s(FloatRegister fd, FloatRegister fj);
1385   BufferOffset as_fmov_d(FloatRegister fd, FloatRegister fj);
1386 
1387   BufferOffset as_fsel(FloatRegister fd, FloatRegister fj, FloatRegister fk,
1388                        FPConditionBit ca);
1389 
1390   BufferOffset as_movgr2fr_w(FloatRegister fd, Register rj);
1391   BufferOffset as_movgr2fr_d(FloatRegister fd, Register rj);
1392   BufferOffset as_movgr2frh_w(FloatRegister fd, Register rj);
1393 
1394   BufferOffset as_movfr2gr_s(Register rd, FloatRegister fj);
1395   BufferOffset as_movfr2gr_d(Register rd, FloatRegister fj);
1396   BufferOffset as_movfrh2gr_s(Register rd, FloatRegister fj);
1397 
1398   BufferOffset as_movgr2fcsr(Register rj);
1399   BufferOffset as_movfcsr2gr(Register rd);
1400 
1401   BufferOffset as_movfr2cf(FPConditionBit cd, FloatRegister fj);
1402   BufferOffset as_movcf2fr(FloatRegister fd, FPConditionBit cj);
1403 
1404   BufferOffset as_movgr2cf(FPConditionBit cd, Register rj);
1405   BufferOffset as_movcf2gr(Register rd, FPConditionBit cj);
1406 
1407   // FP load/store instructions
1408   BufferOffset as_fld_s(FloatRegister fd, Register rj, int32_t si12);
1409   BufferOffset as_fld_d(FloatRegister fd, Register rj, int32_t si12);
1410   BufferOffset as_fst_s(FloatRegister fd, Register rj, int32_t si12);
1411   BufferOffset as_fst_d(FloatRegister fd, Register rj, int32_t si12);
1412 
1413   BufferOffset as_fldx_s(FloatRegister fd, Register rj, Register rk);
1414   BufferOffset as_fldx_d(FloatRegister fd, Register rj, Register rk);
1415   BufferOffset as_fstx_s(FloatRegister fd, Register rj, Register rk);
1416   BufferOffset as_fstx_d(FloatRegister fd, Register rj, Register rk);
1417 
1418   // label operations
1419   void bind(Label* label, BufferOffset boff = BufferOffset());
1420   virtual void bind(InstImm* inst, uintptr_t branch, uintptr_t target) = 0;
bind(CodeLabel * label)1421   void bind(CodeLabel* label) { label->target()->bind(currentOffset()); }
currentOffset()1422   uint32_t currentOffset() { return nextOffset().getOffset(); }
1423   void retarget(Label* label, Label* target);
1424 
1425   void call(Label* label);
1426   void call(void* target);
1427 
1428   void as_break(uint32_t code);
1429 
1430  public:
SupportsFloatingPoint()1431   static bool SupportsFloatingPoint() {
1432 #if defined(__loongarch_hard_float) || defined(JS_SIMULATOR_LOONG64)
1433     return true;
1434 #else
1435     return false;
1436 #endif
1437   }
SupportsUnalignedAccesses()1438   static bool SupportsUnalignedAccesses() { return true; }
SupportsFastUnalignedFPAccesses()1439   static bool SupportsFastUnalignedFPAccesses() { return true; }
1440 
HasRoundInstruction(RoundingMode mode)1441   static bool HasRoundInstruction(RoundingMode mode) { return false; }
1442 
1443  protected:
1444   InstImm invertBranch(InstImm branch, BOffImm16 skipOffset);
addPendingJump(BufferOffset src,ImmPtr target,RelocationKind kind)1445   void addPendingJump(BufferOffset src, ImmPtr target, RelocationKind kind) {
1446     enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind));
1447     if (kind == RelocationKind::JITCODE) {
1448       jumpRelocations_.writeUnsigned(src.getOffset());
1449     }
1450   }
1451 
addLongJump(BufferOffset src,BufferOffset dst)1452   void addLongJump(BufferOffset src, BufferOffset dst) {
1453     CodeLabel cl;
1454     cl.patchAt()->bind(src.getOffset());
1455     cl.target()->bind(dst.getOffset());
1456     cl.setLinkMode(CodeLabel::JumpImmediate);
1457     addCodeLabel(std::move(cl));
1458   }
1459 
1460  public:
flushBuffer()1461   void flushBuffer() {}
1462 
comment(const char * msg)1463   void comment(const char* msg) { spew("; %s", msg); }
1464 
NopSize()1465   static uint32_t NopSize() { return 4; }
1466 
1467   static void PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm);
1468 
1469   static uint8_t* NextInstruction(uint8_t* instruction,
1470                                   uint32_t* count = nullptr);
1471 
1472   static void ToggleToJmp(CodeLocationLabel inst_);
1473   static void ToggleToCmp(CodeLocationLabel inst_);
1474 
verifyHeapAccessDisassembly(uint32_t begin,uint32_t end,const Disassembler::HeapAccess & heapAccess)1475   void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end,
1476                                    const Disassembler::HeapAccess& heapAccess) {
1477     // Implement this if we implement a disassembler.
1478   }
1479 };  // AssemblerLOONG64
1480 
1481 // andi r0, r0, 0
1482 const uint32_t NopInst = 0x03400000;
1483 
1484 // An Instruction is a structure for both encoding and decoding any and all
1485 // LoongArch instructions.
1486 class Instruction {
1487  public:
1488   uint32_t data;
1489 
1490  protected:
1491   // Standard constructor
Instruction(uint32_t data_)1492   Instruction(uint32_t data_) : data(data_) {}
1493   // You should never create an instruction directly.  You should create a
1494   // more specific instruction which will eventually call one of these
1495   // constructors for you.
1496 
1497  public:
encode()1498   uint32_t encode() const { return data; }
1499 
makeNop()1500   void makeNop() { data = NopInst; }
1501 
setData(uint32_t data)1502   void setData(uint32_t data) { this->data = data; }
1503 
1504   const Instruction& operator=(const Instruction& src) {
1505     data = src.data;
1506     return *this;
1507   }
1508 
1509   // Extract the one particular bit.
extractBit(uint32_t bit)1510   uint32_t extractBit(uint32_t bit) { return (encode() >> bit) & 1; }
1511   // Extract a bit field out of the instruction
extractBitField(uint32_t hi,uint32_t lo)1512   uint32_t extractBitField(uint32_t hi, uint32_t lo) {
1513     return (encode() >> lo) & ((2 << (hi - lo)) - 1);
1514   }
1515 
1516   // Get the next instruction in the instruction stream.
1517   // This does neat things like ignoreconstant pools and their guards.
1518   Instruction* next();
1519 
1520   // Sometimes, an api wants a uint32_t (or a pointer to it) rather than
1521   // an instruction.  raw() just coerces this into a pointer to a uint32_t
raw()1522   const uint32_t* raw() const { return &data; }
size()1523   uint32_t size() const { return 4; }
1524 };  // Instruction
1525 
1526 // make sure that it is the right size
1527 static_assert(sizeof(Instruction) == 4,
1528               "Size of Instruction class has to be 4 bytes.");
1529 
1530 class InstNOP : public Instruction {
1531  public:
InstNOP()1532   InstNOP() : Instruction(NopInst) {}
1533 };
1534 
1535 // Class for register type instructions.
1536 class InstReg : public Instruction {
1537  public:
InstReg(OpcodeField op,Register rj,Register rd)1538   InstReg(OpcodeField op, Register rj, Register rd)
1539       : Instruction(op | RJ(rj) | RD(rd)) {}
InstReg(OpcodeField op,Register rk,Register rj,Register rd)1540   InstReg(OpcodeField op, Register rk, Register rj, Register rd)
1541       : Instruction(op | RK(rk) | RJ(rj) | RD(rd)) {}
InstReg(OpcodeField op,uint32_t sa,Register rk,Register rj,Register rd,uint32_t sa_bit)1542   InstReg(OpcodeField op, uint32_t sa, Register rk, Register rj, Register rd,
1543           uint32_t sa_bit)
1544       : Instruction(sa_bit == 2 ? op | SA2(sa) | RK(rk) | RJ(rj) | RD(rd)
1545                                 : op | SA3(sa) | RK(rk) | RJ(rj) | RD(rd)) {
1546     MOZ_ASSERT(sa_bit == 2 || sa_bit == 3);
1547   }
InstReg(OpcodeField op,Register rj,Register rd,bool HasRd)1548   InstReg(OpcodeField op, Register rj, Register rd, bool HasRd)
1549       : Instruction(HasRd ? op | RJ(rj) | RD(rd) : op | RK(rj) | RJ(rd)) {}
1550 
1551   // For floating-point
InstReg(OpcodeField op,Register rj,FloatRegister fd)1552   InstReg(OpcodeField op, Register rj, FloatRegister fd)
1553       : Instruction(op | RJ(rj) | FD(fd)) {}
InstReg(OpcodeField op,FloatRegister fj,FloatRegister fd)1554   InstReg(OpcodeField op, FloatRegister fj, FloatRegister fd)
1555       : Instruction(op | FJ(fj) | FD(fd)) {}
InstReg(OpcodeField op,FloatRegister fk,FloatRegister fj,FloatRegister fd)1556   InstReg(OpcodeField op, FloatRegister fk, FloatRegister fj, FloatRegister fd)
1557       : Instruction(op | FK(fk) | FJ(fj) | FD(fd)) {}
InstReg(OpcodeField op,Register rk,Register rj,FloatRegister fd)1558   InstReg(OpcodeField op, Register rk, Register rj, FloatRegister fd)
1559       : Instruction(op | RK(rk) | RJ(rj) | FD(fd)) {}
InstReg(OpcodeField op,FloatRegister fa,FloatRegister fk,FloatRegister fj,FloatRegister fd)1560   InstReg(OpcodeField op, FloatRegister fa, FloatRegister fk, FloatRegister fj,
1561           FloatRegister fd)
1562       : Instruction(op | FA(fa) | FK(fk) | FJ(fj) | FD(fd)) {}
InstReg(OpcodeField op,AssemblerLOONG64::FPConditionBit ca,FloatRegister fk,FloatRegister fj,FloatRegister fd)1563   InstReg(OpcodeField op, AssemblerLOONG64::FPConditionBit ca, FloatRegister fk,
1564           FloatRegister fj, FloatRegister fd)
1565       : Instruction(op | ca << CAShift | FK(fk) | FJ(fj) | FD(fd)) {
1566     MOZ_ASSERT(op == op_fsel);
1567   }
InstReg(OpcodeField op,FloatRegister fj,Register rd)1568   InstReg(OpcodeField op, FloatRegister fj, Register rd)
1569       : Instruction(op | FJ(fj) | RD(rd)) {
1570     MOZ_ASSERT((op == op_movfr2gr_s) || (op == op_movfr2gr_d) ||
1571                (op == op_movfrh2gr_s));
1572   }
InstReg(OpcodeField op,Register rj,uint32_t fd)1573   InstReg(OpcodeField op, Register rj, uint32_t fd)
1574       : Instruction(op | RJ(rj) | fd) {
1575     MOZ_ASSERT(op == op_movgr2fcsr);
1576   }
InstReg(OpcodeField op,uint32_t fj,Register rd)1577   InstReg(OpcodeField op, uint32_t fj, Register rd)
1578       : Instruction(op | (fj << FJShift) | RD(rd)) {
1579     MOZ_ASSERT(op == op_movfcsr2gr);
1580   }
InstReg(OpcodeField op,FloatRegister fj,AssemblerLOONG64::FPConditionBit cd)1581   InstReg(OpcodeField op, FloatRegister fj, AssemblerLOONG64::FPConditionBit cd)
1582       : Instruction(op | FJ(fj) | cd) {
1583     MOZ_ASSERT(op == op_movfr2cf);
1584   }
InstReg(OpcodeField op,AssemblerLOONG64::FPConditionBit cj,FloatRegister fd)1585   InstReg(OpcodeField op, AssemblerLOONG64::FPConditionBit cj, FloatRegister fd)
1586       : Instruction(op | (cj << CJShift) | FD(fd)) {
1587     MOZ_ASSERT(op == op_movcf2fr);
1588   }
InstReg(OpcodeField op,Register rj,AssemblerLOONG64::FPConditionBit cd)1589   InstReg(OpcodeField op, Register rj, AssemblerLOONG64::FPConditionBit cd)
1590       : Instruction(op | RJ(rj) | cd) {
1591     MOZ_ASSERT(op == op_movgr2cf);
1592   }
InstReg(OpcodeField op,AssemblerLOONG64::FPConditionBit cj,Register rd)1593   InstReg(OpcodeField op, AssemblerLOONG64::FPConditionBit cj, Register rd)
1594       : Instruction(op | (cj << CJShift) | RD(rd)) {
1595     MOZ_ASSERT(op == op_movcf2gr);
1596   }
InstReg(OpcodeField op,int32_t cond,FloatRegister fk,FloatRegister fj,AssemblerLOONG64::FPConditionBit cd)1597   InstReg(OpcodeField op, int32_t cond, FloatRegister fk, FloatRegister fj,
1598           AssemblerLOONG64::FPConditionBit cd)
1599       : Instruction(op | (cond & CONDMask) << CONDShift | FK(fk) | FJ(fj) |
1600                     (cd & RDMask)) {
1601     MOZ_ASSERT(is_uintN(cond, 5));
1602   }
1603 
extractRK()1604   uint32_t extractRK() {
1605     return extractBitField(RKShift + RKBits - 1, RKShift);
1606   }
extractRJ()1607   uint32_t extractRJ() {
1608     return extractBitField(RJShift + RJBits - 1, RJShift);
1609   }
extractRD()1610   uint32_t extractRD() {
1611     return extractBitField(RDShift + RDBits - 1, RDShift);
1612   }
extractSA2()1613   uint32_t extractSA2() {
1614     return extractBitField(SAShift + SA2Bits - 1, SAShift);
1615   }
extractSA3()1616   uint32_t extractSA3() {
1617     return extractBitField(SAShift + SA3Bits - 1, SAShift);
1618   }
1619 };
1620 
1621 // Class for branch, load and store instructions with immediate offset.
1622 class InstImm : public Instruction {
1623  public:
1624   void extractImm16(BOffImm16* dest);
genImm(int32_t value,uint32_t value_bits)1625   uint32_t genImm(int32_t value, uint32_t value_bits) {
1626     uint32_t imm = value & Imm5Mask;
1627     if (value_bits == 6) {
1628       imm = value & Imm6Mask;
1629     } else if (value_bits == 12) {
1630       imm = value & Imm12Mask;
1631     } else if (value_bits == 14) {
1632       imm = value & Imm14Mask;
1633     }
1634 
1635     return imm;
1636   }
1637 
InstImm(OpcodeField op,int32_t value,Register rj,Register rd,uint32_t value_bits)1638   InstImm(OpcodeField op, int32_t value, Register rj, Register rd,
1639           uint32_t value_bits)
1640       : Instruction(op | genImm(value, value_bits) << RKShift | RJ(rj) |
1641                     RD(rd)) {
1642     MOZ_ASSERT(value_bits == 5 || value_bits == 6 || value_bits == 12 ||
1643                value_bits == 14);
1644   }
InstImm(OpcodeField op,BOffImm16 off,Register rj,Register rd)1645   InstImm(OpcodeField op, BOffImm16 off, Register rj, Register rd)
1646       : Instruction(op | (off.encode() & Imm16Mask) << Imm16Shift | RJ(rj) |
1647                     RD(rd)) {}
InstImm(OpcodeField op,int32_t si21,Register rj,bool NotHasRd)1648   InstImm(OpcodeField op, int32_t si21, Register rj, bool NotHasRd)
1649       : Instruction(NotHasRd ? op | (si21 & Imm16Mask) << RKShift | RJ(rj) |
1650                                    (si21 & Imm21Mask) >> 16
1651                              : op | (si21 & Imm20Mask) << Imm20Shift | RD(rj)) {
1652     if (NotHasRd) {
1653       MOZ_ASSERT(op == op_beqz || op == op_bnez);
1654       MOZ_ASSERT(is_intN(si21, 21));
1655     } else {
1656       MOZ_ASSERT(op == op_lu12i_w || op == op_lu32i_d || op == op_pcaddi ||
1657                  op == op_pcaddu12i || op == op_pcaddu18i ||
1658                  op == op_pcalau12i);
1659       // si20
1660       MOZ_ASSERT(is_intN(si21, 20) || is_uintN(si21, 20));
1661     }
1662   }
InstImm(OpcodeField op,int32_t si21,AssemblerLOONG64::FPConditionBit cj,bool isNotEqual)1663   InstImm(OpcodeField op, int32_t si21, AssemblerLOONG64::FPConditionBit cj,
1664           bool isNotEqual)
1665       : Instruction(isNotEqual
1666                         ? op | (si21 & Imm16Mask) << RKShift |
1667                               (cj + 8) << CJShift | (si21 & Imm21Mask) >> 16
1668                         : op | (si21 & Imm16Mask) << RKShift | cj << CJShift |
1669                               (si21 & Imm21Mask) >> 16) {
1670     MOZ_ASSERT(is_intN(si21, 21));
1671     MOZ_ASSERT(op == op_bcz);
1672     MOZ_ASSERT(cj >= 0 && cj <= 7);
1673   }
InstImm(OpcodeField op,Imm16 off,Register rj,Register rd)1674   InstImm(OpcodeField op, Imm16 off, Register rj, Register rd)
1675       : Instruction(op | (off.encode() & Imm16Mask) << Imm16Shift | RJ(rj) |
1676                     RD(rd)) {}
InstImm(OpcodeField op,int32_t bit15)1677   InstImm(OpcodeField op, int32_t bit15)
1678       : Instruction(op | (bit15 & Imm15Mask)) {
1679     MOZ_ASSERT(is_uintN(bit15, 15));
1680   }
1681 
InstImm(OpcodeField op,int32_t bit26,bool jump)1682   InstImm(OpcodeField op, int32_t bit26, bool jump)
1683       : Instruction(op | (bit26 & Imm16Mask) << Imm16Shift |
1684                     (bit26 & Imm26Mask) >> 16) {
1685     MOZ_ASSERT(is_intN(bit26, 26));
1686   }
InstImm(OpcodeField op,int32_t si12,Register rj,int32_t hint)1687   InstImm(OpcodeField op, int32_t si12, Register rj, int32_t hint)
1688       : Instruction(op | (si12 & Imm12Mask) << Imm12Shift | RJ(rj) |
1689                     (hint & RDMask)) {
1690     MOZ_ASSERT(op == op_preld);
1691   }
InstImm(OpcodeField op,int32_t msb,int32_t lsb,Register rj,Register rd,uint32_t sb_bits)1692   InstImm(OpcodeField op, int32_t msb, int32_t lsb, Register rj, Register rd,
1693           uint32_t sb_bits)
1694       : Instruction((sb_bits == 5)
1695                         ? op | (msb & MSBWMask) << MSBWShift |
1696                               (lsb & LSBWMask) << LSBWShift | RJ(rj) | RD(rd)
1697                         : op | (msb & MSBDMask) << MSBDShift |
1698                               (lsb & LSBDMask) << LSBDShift | RJ(rj) | RD(rd)) {
1699     MOZ_ASSERT(sb_bits == 5 || sb_bits == 6);
1700     MOZ_ASSERT(op == op_bstr_w || op == op_bstrins_d || op == op_bstrpick_d);
1701   }
InstImm(OpcodeField op,int32_t msb,int32_t lsb,Register rj,Register rd)1702   InstImm(OpcodeField op, int32_t msb, int32_t lsb, Register rj, Register rd)
1703       : Instruction(op | (msb & MSBWMask) << MSBWShift |
1704                     ((lsb + 0x20) & LSBDMask) << LSBWShift | RJ(rj) | RD(rd)) {
1705     MOZ_ASSERT(op == op_bstr_w);
1706   }
1707 
1708   // For floating-point loads and stores.
InstImm(OpcodeField op,int32_t si12,Register rj,FloatRegister fd)1709   InstImm(OpcodeField op, int32_t si12, Register rj, FloatRegister fd)
1710       : Instruction(op | (si12 & Imm12Mask) << Imm12Shift | RJ(rj) | FD(fd)) {
1711     MOZ_ASSERT(is_intN(si12, 12));
1712   }
1713 
setOpcode(OpcodeField op,uint32_t opBits)1714   void setOpcode(OpcodeField op, uint32_t opBits) {
1715     // opBits not greater than 24.
1716     MOZ_ASSERT(opBits < 25);
1717     uint32_t OpcodeShift = 32 - opBits;
1718     uint32_t OpcodeMask = ((1 << opBits) - 1) << OpcodeShift;
1719     data = (data & ~OpcodeMask) | op;
1720   }
extractRK()1721   uint32_t extractRK() {
1722     return extractBitField(RKShift + RKBits - 1, RKShift);
1723   }
extractRJ()1724   uint32_t extractRJ() {
1725     return extractBitField(RJShift + RJBits - 1, RJShift);
1726   }
setRJ(uint32_t rj)1727   void setRJ(uint32_t rj) { data = (data & ~RJMask) | (rj << RJShift); }
extractRD()1728   uint32_t extractRD() {
1729     return extractBitField(RDShift + RDBits - 1, RDShift);
1730   }
extractImm16Value()1731   uint32_t extractImm16Value() {
1732     return extractBitField(Imm16Shift + Imm16Bits - 1, Imm16Shift);
1733   }
setBOffImm16(BOffImm16 off)1734   void setBOffImm16(BOffImm16 off) {
1735     // Reset immediate field and replace it
1736     data = (data & ~BOffImm16Mask) | (off.encode() << Imm16Shift);
1737   }
setImm21(int32_t off)1738   void setImm21(int32_t off) {
1739     // Reset immediate field and replace it
1740     uint32_t low16 = (off >> 2) & Imm16Mask;
1741     int32_t high5 = (off >> 18) & Imm5Mask;
1742     uint32_t fcc_info = (data >> 5) & 0x1F;
1743     data = (data & ~BOffImm26Mask) | (low16 << Imm16Shift) | high5 |
1744            (fcc_info << 5);
1745   }
1746 };
1747 
1748 // Class for Jump type instructions.
1749 class InstJump : public Instruction {
1750  public:
InstJump(OpcodeField op,JOffImm26 off)1751   InstJump(OpcodeField op, JOffImm26 off)
1752       : Instruction(op | (off.encode() & Imm16Mask) << Imm16Shift |
1753                     (off.encode() & Imm26Mask) >> 16) {
1754     MOZ_ASSERT(op == op_b || op == op_bl);
1755   }
1756 
setJOffImm26(JOffImm26 off)1757   void setJOffImm26(JOffImm26 off) {
1758     // Reset immediate field and replace it
1759     data = (data & ~BOffImm26Mask) |
1760            ((off.encode() & Imm16Mask) << Imm16Shift) |
1761            ((off.encode() >> 16) & 0x3ff);
1762   }
extractImm26Value()1763   uint32_t extractImm26Value() {
1764     return extractBitField(Imm26Shift + Imm26Bits - 1, Imm26Shift);
1765   }
1766 };
1767 
1768 class ABIArgGenerator {
1769  public:
ABIArgGenerator()1770   ABIArgGenerator()
1771       : intRegIndex_(0), floatRegIndex_(0), stackOffset_(0), current_() {}
1772 
1773   ABIArg next(MIRType argType);
current()1774   ABIArg& current() { return current_; }
stackBytesConsumedSoFar()1775   uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
increaseStackOffset(uint32_t bytes)1776   void increaseStackOffset(uint32_t bytes) { stackOffset_ += bytes; }
1777 
1778  protected:
1779   unsigned intRegIndex_;
1780   unsigned floatRegIndex_;
1781   uint32_t stackOffset_;
1782   ABIArg current_;
1783 };
1784 
1785 class Assembler : public AssemblerLOONG64 {
1786  public:
Assembler()1787   Assembler() : AssemblerLOONG64() {}
1788 
1789   static uintptr_t GetPointer(uint8_t*);
1790 
1791   using AssemblerLOONG64::bind;
1792 
1793   static void Bind(uint8_t* rawCode, const CodeLabel& label);
1794 
1795   void processCodeLabels(uint8_t* rawCode);
1796 
1797   static void TraceJumpRelocations(JSTracer* trc, JitCode* code,
1798                                    CompactBufferReader& reader);
1799   static void TraceDataRelocations(JSTracer* trc, JitCode* code,
1800                                    CompactBufferReader& reader);
1801 
1802   void bind(InstImm* inst, uintptr_t branch, uintptr_t target);
1803 
1804   // Copy the assembly code to the given buffer, and perform any pending
1805   // relocations relying on the target address.
1806   void executableCopy(uint8_t* buffer);
1807 
1808   static uint32_t PatchWrite_NearCallSize();
1809 
1810   static uint64_t ExtractLoad64Value(Instruction* inst0);
1811   static void UpdateLoad64Value(Instruction* inst0, uint64_t value);
1812   static void WriteLoad64Instructions(Instruction* inst0, Register reg,
1813                                       uint64_t value);
1814 
1815   static void PatchWrite_NearCall(CodeLocationLabel start,
1816                                   CodeLocationLabel toCall);
1817   static void PatchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue,
1818                                       ImmPtr expectedValue);
1819   static void PatchDataWithValueCheck(CodeLocationLabel label,
1820                                       PatchedImmPtr newValue,
1821                                       PatchedImmPtr expectedValue);
1822 
1823   static uint64_t ExtractInstructionImmediate(uint8_t* code);
1824 
1825   static void ToggleCall(CodeLocationLabel inst_, bool enabled);
1826 };  // Assembler
1827 
1828 static const uint32_t NumIntArgRegs = 8;
1829 static const uint32_t NumFloatArgRegs = 8;
1830 
GetIntArgReg(uint32_t usedIntArgs,Register * out)1831 static inline bool GetIntArgReg(uint32_t usedIntArgs, Register* out) {
1832   if (usedIntArgs < NumIntArgRegs) {
1833     *out = Register::FromCode(a0.code() + usedIntArgs);
1834     return true;
1835   }
1836   return false;
1837 }
1838 
GetFloatArgReg(uint32_t usedFloatArgs,FloatRegister * out)1839 static inline bool GetFloatArgReg(uint32_t usedFloatArgs, FloatRegister* out) {
1840   if (usedFloatArgs < NumFloatArgRegs) {
1841     *out = FloatRegister::FromCode(f0.code() + usedFloatArgs);
1842     return true;
1843   }
1844   return false;
1845 }
1846 
1847 // Get a register in which we plan to put a quantity that will be used as an
1848 // integer argument. This differs from GetIntArgReg in that if we have no more
1849 // actual argument registers to use we will fall back on using whatever
1850 // CallTempReg* don't overlap the argument registers, and only fail once those
1851 // run out too.
GetTempRegForIntArg(uint32_t usedIntArgs,uint32_t usedFloatArgs,Register * out)1852 static inline bool GetTempRegForIntArg(uint32_t usedIntArgs,
1853                                        uint32_t usedFloatArgs, Register* out) {
1854   // NOTE: We can't properly determine which regs are used if there are
1855   // float arguments. If this is needed, we will have to guess.
1856   MOZ_ASSERT(usedFloatArgs == 0);
1857 
1858   if (GetIntArgReg(usedIntArgs, out)) {
1859     return true;
1860   }
1861   // Unfortunately, we have to assume things about the point at which
1862   // GetIntArgReg returns false, because we need to know how many registers it
1863   // can allocate.
1864   usedIntArgs -= NumIntArgRegs;
1865   if (usedIntArgs >= NumCallTempNonArgRegs) {
1866     return false;
1867   }
1868   *out = CallTempNonArgRegs[usedIntArgs];
1869   return true;
1870 }
1871 
1872 }  // namespace jit
1873 }  // namespace js
1874 
1875 #endif /* jit_loong64_Assembler_loong64_h */
1876