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 #include "jit/mips-shared/Assembler-mips-shared.h"
8 
9 #include "mozilla/DebugOnly.h"
10 #include "mozilla/MathAlgorithms.h"
11 
12 #include "gc/Marking.h"
13 #include "jit/ExecutableAllocator.h"
14 #include "vm/Realm.h"
15 
16 using mozilla::DebugOnly;
17 
18 using namespace js;
19 using namespace js::jit;
20 
21 // Encode a standard register when it is being used as rd, the rs, and
22 // an extra register(rt). These should never be called with an InvalidReg.
RS(Register r)23 uint32_t js::jit::RS(Register r) {
24   MOZ_ASSERT((r.code() & ~RegMask) == 0);
25   return r.code() << RSShift;
26 }
27 
RT(Register r)28 uint32_t js::jit::RT(Register r) {
29   MOZ_ASSERT((r.code() & ~RegMask) == 0);
30   return r.code() << RTShift;
31 }
32 
RD(Register r)33 uint32_t js::jit::RD(Register r) {
34   MOZ_ASSERT((r.code() & ~RegMask) == 0);
35   return r.code() << RDShift;
36 }
37 
RZ(Register r)38 uint32_t js::jit::RZ(Register r) {
39   MOZ_ASSERT((r.code() & ~RegMask) == 0);
40   return r.code() << RZShift;
41 }
42 
SA(uint32_t value)43 uint32_t js::jit::SA(uint32_t value) {
44   MOZ_ASSERT(value < 32);
45   return value << SAShift;
46 }
47 
FS(uint32_t value)48 uint32_t js::jit::FS(uint32_t value) {
49   MOZ_ASSERT(value < 32);
50   return value << FSShift;
51 }
52 
toRS(Instruction & i)53 Register js::jit::toRS(Instruction& i) {
54   return Register::FromCode((i.encode() & RSMask) >> RSShift);
55 }
56 
toRT(Instruction & i)57 Register js::jit::toRT(Instruction& i) {
58   return Register::FromCode((i.encode() & RTMask) >> RTShift);
59 }
60 
toRD(Instruction & i)61 Register js::jit::toRD(Instruction& i) {
62   return Register::FromCode((i.encode() & RDMask) >> RDShift);
63 }
64 
toR(Instruction & i)65 Register js::jit::toR(Instruction& i) {
66   return Register::FromCode(i.encode() & RegMask);
67 }
68 
extractImm16(BOffImm16 * dest)69 void InstImm::extractImm16(BOffImm16* dest) { *dest = BOffImm16(*this); }
70 
finish()71 void AssemblerMIPSShared::finish() {
72   MOZ_ASSERT(!isFinished);
73   isFinished = true;
74 }
75 
appendRawCode(const uint8_t * code,size_t numBytes)76 bool AssemblerMIPSShared::appendRawCode(const uint8_t* code, size_t numBytes) {
77   return m_buffer.appendRawCode(code, numBytes);
78 }
79 
reserve(size_t size)80 bool AssemblerMIPSShared::reserve(size_t size) {
81   // This buffer uses fixed-size chunks so there's no point in reserving
82   // now vs. on-demand.
83   return !oom();
84 }
85 
swapBuffer(wasm::Bytes & bytes)86 bool AssemblerMIPSShared::swapBuffer(wasm::Bytes& bytes) {
87   // For now, specialize to the one use case. As long as wasm::Bytes is a
88   // Vector, not a linked-list of chunks, there's not much we can do other
89   // than copy.
90   MOZ_ASSERT(bytes.empty());
91   if (!bytes.resize(bytesNeeded())) {
92     return false;
93   }
94   m_buffer.executableCopy(bytes.begin());
95   return true;
96 }
97 
copyJumpRelocationTable(uint8_t * dest)98 void AssemblerMIPSShared::copyJumpRelocationTable(uint8_t* dest) {
99   if (jumpRelocations_.length()) {
100     memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length());
101   }
102 }
103 
copyDataRelocationTable(uint8_t * dest)104 void AssemblerMIPSShared::copyDataRelocationTable(uint8_t* dest) {
105   if (dataRelocations_.length()) {
106     memcpy(dest, dataRelocations_.buffer(), dataRelocations_.length());
107   }
108 }
109 
InvertCondition(Condition cond)110 AssemblerMIPSShared::Condition AssemblerMIPSShared::InvertCondition(
111     Condition cond) {
112   switch (cond) {
113     case Equal:
114       return NotEqual;
115     case NotEqual:
116       return Equal;
117     case Zero:
118       return NonZero;
119     case NonZero:
120       return Zero;
121     case LessThan:
122       return GreaterThanOrEqual;
123     case LessThanOrEqual:
124       return GreaterThan;
125     case GreaterThan:
126       return LessThanOrEqual;
127     case GreaterThanOrEqual:
128       return LessThan;
129     case Above:
130       return BelowOrEqual;
131     case AboveOrEqual:
132       return Below;
133     case Below:
134       return AboveOrEqual;
135     case BelowOrEqual:
136       return Above;
137     case Signed:
138       return NotSigned;
139     case NotSigned:
140       return Signed;
141     default:
142       MOZ_CRASH("unexpected condition");
143   }
144 }
145 
InvertCondition(DoubleCondition cond)146 AssemblerMIPSShared::DoubleCondition AssemblerMIPSShared::InvertCondition(
147     DoubleCondition cond) {
148   switch (cond) {
149     case DoubleOrdered:
150       return DoubleUnordered;
151     case DoubleEqual:
152       return DoubleNotEqualOrUnordered;
153     case DoubleNotEqual:
154       return DoubleEqualOrUnordered;
155     case DoubleGreaterThan:
156       return DoubleLessThanOrEqualOrUnordered;
157     case DoubleGreaterThanOrEqual:
158       return DoubleLessThanOrUnordered;
159     case DoubleLessThan:
160       return DoubleGreaterThanOrEqualOrUnordered;
161     case DoubleLessThanOrEqual:
162       return DoubleGreaterThanOrUnordered;
163     case DoubleUnordered:
164       return DoubleOrdered;
165     case DoubleEqualOrUnordered:
166       return DoubleNotEqual;
167     case DoubleNotEqualOrUnordered:
168       return DoubleEqual;
169     case DoubleGreaterThanOrUnordered:
170       return DoubleLessThanOrEqual;
171     case DoubleGreaterThanOrEqualOrUnordered:
172       return DoubleLessThan;
173     case DoubleLessThanOrUnordered:
174       return DoubleGreaterThanOrEqual;
175     case DoubleLessThanOrEqualOrUnordered:
176       return DoubleGreaterThan;
177     default:
178       MOZ_CRASH("unexpected condition");
179   }
180 }
181 
BOffImm16(InstImm inst)182 BOffImm16::BOffImm16(InstImm inst) : data(inst.encode() & Imm16Mask) {}
183 
getDest(Instruction * src) const184 Instruction* BOffImm16::getDest(Instruction* src) const {
185   return &src[(((int32_t)data << 16) >> 16) + 1];
186 }
187 
oom() const188 bool AssemblerMIPSShared::oom() const {
189   return AssemblerShared::oom() || m_buffer.oom() || jumpRelocations_.oom() ||
190          dataRelocations_.oom();
191 }
192 
193 // Size of the instruction stream, in bytes.
size() const194 size_t AssemblerMIPSShared::size() const { return m_buffer.size(); }
195 
196 // Size of the relocation table, in bytes.
jumpRelocationTableBytes() const197 size_t AssemblerMIPSShared::jumpRelocationTableBytes() const {
198   return jumpRelocations_.length();
199 }
200 
dataRelocationTableBytes() const201 size_t AssemblerMIPSShared::dataRelocationTableBytes() const {
202   return dataRelocations_.length();
203 }
204 
205 // Size of the data table, in bytes.
bytesNeeded() const206 size_t AssemblerMIPSShared::bytesNeeded() const {
207   return size() + jumpRelocationTableBytes() + dataRelocationTableBytes();
208 }
209 
210 // write a blob of binary into the instruction stream
writeInst(uint32_t x,uint32_t * dest)211 BufferOffset AssemblerMIPSShared::writeInst(uint32_t x, uint32_t* dest) {
212   if (dest == nullptr) {
213     return m_buffer.putInt(x);
214   }
215 
216   WriteInstStatic(x, dest);
217   return BufferOffset();
218 }
219 
WriteInstStatic(uint32_t x,uint32_t * dest)220 void AssemblerMIPSShared::WriteInstStatic(uint32_t x, uint32_t* dest) {
221   MOZ_ASSERT(dest != nullptr);
222   *dest = x;
223 }
224 
haltingAlign(int alignment)225 BufferOffset AssemblerMIPSShared::haltingAlign(int alignment) {
226   // TODO: Implement a proper halting align.
227   return nopAlign(alignment);
228 }
229 
nopAlign(int alignment)230 BufferOffset AssemblerMIPSShared::nopAlign(int alignment) {
231   BufferOffset ret;
232   MOZ_ASSERT(m_buffer.isAligned(4));
233   if (alignment == 8) {
234     if (!m_buffer.isAligned(alignment)) {
235       BufferOffset tmp = as_nop();
236       if (!ret.assigned()) {
237         ret = tmp;
238       }
239     }
240   } else {
241     MOZ_ASSERT((alignment & (alignment - 1)) == 0);
242     while (size() & (alignment - 1)) {
243       BufferOffset tmp = as_nop();
244       if (!ret.assigned()) {
245         ret = tmp;
246       }
247     }
248   }
249   return ret;
250 }
251 
as_nop()252 BufferOffset AssemblerMIPSShared::as_nop() {
253   spew("nop");
254   return writeInst(op_special | ff_sll);
255 }
256 
257 // Logical operations.
as_and(Register rd,Register rs,Register rt)258 BufferOffset AssemblerMIPSShared::as_and(Register rd, Register rs,
259                                          Register rt) {
260   spew("and    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
261   return writeInst(InstReg(op_special, rs, rt, rd, ff_and).encode());
262 }
263 
as_or(Register rd,Register rs,Register rt)264 BufferOffset AssemblerMIPSShared::as_or(Register rd, Register rs, Register rt) {
265   spew("or     %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
266   return writeInst(InstReg(op_special, rs, rt, rd, ff_or).encode());
267 }
268 
as_xor(Register rd,Register rs,Register rt)269 BufferOffset AssemblerMIPSShared::as_xor(Register rd, Register rs,
270                                          Register rt) {
271   spew("xor    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
272   return writeInst(InstReg(op_special, rs, rt, rd, ff_xor).encode());
273 }
274 
as_nor(Register rd,Register rs,Register rt)275 BufferOffset AssemblerMIPSShared::as_nor(Register rd, Register rs,
276                                          Register rt) {
277   spew("nor    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
278   return writeInst(InstReg(op_special, rs, rt, rd, ff_nor).encode());
279 }
280 
as_andi(Register rd,Register rs,int32_t j)281 BufferOffset AssemblerMIPSShared::as_andi(Register rd, Register rs, int32_t j) {
282   MOZ_ASSERT(Imm16::IsInUnsignedRange(j));
283   spew("andi   %3s,%3s,0x%x", rd.name(), rs.name(), j);
284   return writeInst(InstImm(op_andi, rs, rd, Imm16(j)).encode());
285 }
286 
as_ori(Register rd,Register rs,int32_t j)287 BufferOffset AssemblerMIPSShared::as_ori(Register rd, Register rs, int32_t j) {
288   MOZ_ASSERT(Imm16::IsInUnsignedRange(j));
289   spew("ori    %3s,%3s,0x%x", rd.name(), rs.name(), j);
290   return writeInst(InstImm(op_ori, rs, rd, Imm16(j)).encode());
291 }
292 
as_xori(Register rd,Register rs,int32_t j)293 BufferOffset AssemblerMIPSShared::as_xori(Register rd, Register rs, int32_t j) {
294   MOZ_ASSERT(Imm16::IsInUnsignedRange(j));
295   spew("xori   %3s,%3s,0x%x", rd.name(), rs.name(), j);
296   return writeInst(InstImm(op_xori, rs, rd, Imm16(j)).encode());
297 }
298 
as_lui(Register rd,int32_t j)299 BufferOffset AssemblerMIPSShared::as_lui(Register rd, int32_t j) {
300   MOZ_ASSERT(Imm16::IsInUnsignedRange(j));
301   spew("lui    %3s,0x%x", rd.name(), j);
302   return writeInst(InstImm(op_lui, zero, rd, Imm16(j)).encode());
303 }
304 
305 // Branch and jump instructions
as_bal(BOffImm16 off)306 BufferOffset AssemblerMIPSShared::as_bal(BOffImm16 off) {
307   spew("bal    %d", off.decode());
308   BufferOffset bo =
309       writeInst(InstImm(op_regimm, zero, rt_bgezal, off).encode());
310   return bo;
311 }
312 
as_b(BOffImm16 off)313 BufferOffset AssemblerMIPSShared::as_b(BOffImm16 off) {
314   spew("b      %d", off.decode());
315   BufferOffset bo = writeInst(InstImm(op_beq, zero, zero, off).encode());
316   return bo;
317 }
318 
getBranchCode(JumpOrCall jumpOrCall)319 InstImm AssemblerMIPSShared::getBranchCode(JumpOrCall jumpOrCall) {
320   if (jumpOrCall == BranchIsCall) {
321     return InstImm(op_regimm, zero, rt_bgezal, BOffImm16(0));
322   }
323 
324   return InstImm(op_beq, zero, zero, BOffImm16(0));
325 }
326 
getBranchCode(Register s,Register t,Condition c)327 InstImm AssemblerMIPSShared::getBranchCode(Register s, Register t,
328                                            Condition c) {
329   MOZ_ASSERT(c == AssemblerMIPSShared::Equal ||
330              c == AssemblerMIPSShared::NotEqual);
331   return InstImm(c == AssemblerMIPSShared::Equal ? op_beq : op_bne, s, t,
332                  BOffImm16(0));
333 }
334 
getBranchCode(Register s,Condition c)335 InstImm AssemblerMIPSShared::getBranchCode(Register s, Condition c) {
336   switch (c) {
337     case AssemblerMIPSShared::Equal:
338     case AssemblerMIPSShared::Zero:
339     case AssemblerMIPSShared::BelowOrEqual:
340       return InstImm(op_beq, s, zero, BOffImm16(0));
341     case AssemblerMIPSShared::NotEqual:
342     case AssemblerMIPSShared::NonZero:
343     case AssemblerMIPSShared::Above:
344       return InstImm(op_bne, s, zero, BOffImm16(0));
345     case AssemblerMIPSShared::GreaterThan:
346       return InstImm(op_bgtz, s, zero, BOffImm16(0));
347     case AssemblerMIPSShared::GreaterThanOrEqual:
348     case AssemblerMIPSShared::NotSigned:
349       return InstImm(op_regimm, s, rt_bgez, BOffImm16(0));
350     case AssemblerMIPSShared::LessThan:
351     case AssemblerMIPSShared::Signed:
352       return InstImm(op_regimm, s, rt_bltz, BOffImm16(0));
353     case AssemblerMIPSShared::LessThanOrEqual:
354       return InstImm(op_blez, s, zero, BOffImm16(0));
355     default:
356       MOZ_CRASH("Condition not supported.");
357   }
358 }
359 
getBranchCode(FloatTestKind testKind,FPConditionBit fcc)360 InstImm AssemblerMIPSShared::getBranchCode(FloatTestKind testKind,
361                                            FPConditionBit fcc) {
362   MOZ_ASSERT(!(fcc && FccMask));
363 #ifdef MIPSR6
364   RSField rsField = ((testKind == TestForTrue ? rs_t : rs_f));
365 
366   return InstImm(op_cop1, rsField, FloatRegisters::f24 << 16, BOffImm16(0));
367 #else
368   uint32_t rtField = ((testKind == TestForTrue ? 1 : 0) | (fcc << FccShift))
369                      << RTShift;
370 
371   return InstImm(op_cop1, rs_bc1, rtField, BOffImm16(0));
372 #endif
373 }
374 
as_j(JOffImm26 off)375 BufferOffset AssemblerMIPSShared::as_j(JOffImm26 off) {
376   spew("j      0x%x", off.decode());
377   BufferOffset bo = writeInst(InstJump(op_j, off).encode());
378   return bo;
379 }
as_jal(JOffImm26 off)380 BufferOffset AssemblerMIPSShared::as_jal(JOffImm26 off) {
381   spew("jal    0x%x", off.decode());
382   BufferOffset bo = writeInst(InstJump(op_jal, off).encode());
383   return bo;
384 }
385 
as_jr(Register rs)386 BufferOffset AssemblerMIPSShared::as_jr(Register rs) {
387   spew("jr     %3s", rs.name());
388 #ifdef MIPSR6
389   BufferOffset bo =
390       writeInst(InstReg(op_special, rs, zero, zero, ff_jalr).encode());
391 #else
392   BufferOffset bo =
393       writeInst(InstReg(op_special, rs, zero, zero, ff_jr).encode());
394 #endif
395   return bo;
396 }
as_jalr(Register rs)397 BufferOffset AssemblerMIPSShared::as_jalr(Register rs) {
398   spew("jalr   %3s", rs.name());
399   BufferOffset bo =
400       writeInst(InstReg(op_special, rs, zero, ra, ff_jalr).encode());
401   return bo;
402 }
403 
404 // Arithmetic instructions
as_addu(Register rd,Register rs,Register rt)405 BufferOffset AssemblerMIPSShared::as_addu(Register rd, Register rs,
406                                           Register rt) {
407   spew("addu   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
408   return writeInst(InstReg(op_special, rs, rt, rd, ff_addu).encode());
409 }
410 
as_addiu(Register rd,Register rs,int32_t j)411 BufferOffset AssemblerMIPSShared::as_addiu(Register rd, Register rs,
412                                            int32_t j) {
413   MOZ_ASSERT(Imm16::IsInSignedRange(j));
414   spew("addiu  %3s,%3s,0x%x", rd.name(), rs.name(), j);
415   return writeInst(InstImm(op_addiu, rs, rd, Imm16(j)).encode());
416 }
417 
as_daddu(Register rd,Register rs,Register rt)418 BufferOffset AssemblerMIPSShared::as_daddu(Register rd, Register rs,
419                                            Register rt) {
420   spew("daddu  %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
421   return writeInst(InstReg(op_special, rs, rt, rd, ff_daddu).encode());
422 }
423 
as_daddiu(Register rd,Register rs,int32_t j)424 BufferOffset AssemblerMIPSShared::as_daddiu(Register rd, Register rs,
425                                             int32_t j) {
426   MOZ_ASSERT(Imm16::IsInSignedRange(j));
427   spew("daddiu %3s,%3s,0x%x", rd.name(), rs.name(), j);
428   return writeInst(InstImm(op_daddiu, rs, rd, Imm16(j)).encode());
429 }
430 
as_subu(Register rd,Register rs,Register rt)431 BufferOffset AssemblerMIPSShared::as_subu(Register rd, Register rs,
432                                           Register rt) {
433   spew("subu   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
434   return writeInst(InstReg(op_special, rs, rt, rd, ff_subu).encode());
435 }
436 
as_dsubu(Register rd,Register rs,Register rt)437 BufferOffset AssemblerMIPSShared::as_dsubu(Register rd, Register rs,
438                                            Register rt) {
439   spew("dsubu  %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
440   return writeInst(InstReg(op_special, rs, rt, rd, ff_dsubu).encode());
441 }
442 
as_mult(Register rs,Register rt)443 BufferOffset AssemblerMIPSShared::as_mult(Register rs, Register rt) {
444   spew("mult   %3s,%3s", rs.name(), rt.name());
445   return writeInst(InstReg(op_special, rs, rt, ff_mult).encode());
446 }
447 
as_multu(Register rs,Register rt)448 BufferOffset AssemblerMIPSShared::as_multu(Register rs, Register rt) {
449   spew("multu  %3s,%3s", rs.name(), rt.name());
450   return writeInst(InstReg(op_special, rs, rt, ff_multu).encode());
451 }
452 
as_dmult(Register rs,Register rt)453 BufferOffset AssemblerMIPSShared::as_dmult(Register rs, Register rt) {
454   spew("dmult  %3s,%3s", rs.name(), rt.name());
455   return writeInst(InstReg(op_special, rs, rt, ff_dmult).encode());
456 }
457 
as_dmultu(Register rs,Register rt)458 BufferOffset AssemblerMIPSShared::as_dmultu(Register rs, Register rt) {
459   spew("dmultu %3s,%3s", rs.name(), rt.name());
460   return writeInst(InstReg(op_special, rs, rt, ff_dmultu).encode());
461 }
462 
as_div(Register rs,Register rt)463 BufferOffset AssemblerMIPSShared::as_div(Register rs, Register rt) {
464   spew("div    %3s,%3s", rs.name(), rt.name());
465   return writeInst(InstReg(op_special, rs, rt, ff_div).encode());
466 }
467 
as_div(Register rd,Register rs,Register rt)468 BufferOffset AssemblerMIPSShared::as_div(Register rd, Register rs,
469                                          Register rt) {
470   spew("div    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
471   return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_div).encode());
472 }
473 
as_divu(Register rs,Register rt)474 BufferOffset AssemblerMIPSShared::as_divu(Register rs, Register rt) {
475   spew("divu   %3s,%3s", rs.name(), rt.name());
476   return writeInst(InstReg(op_special, rs, rt, ff_divu).encode());
477 }
478 
as_divu(Register rd,Register rs,Register rt)479 BufferOffset AssemblerMIPSShared::as_divu(Register rd, Register rs,
480                                           Register rt) {
481   spew("divu    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
482   return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_divu).encode());
483 }
484 
as_mod(Register rd,Register rs,Register rt)485 BufferOffset AssemblerMIPSShared::as_mod(Register rd, Register rs,
486                                          Register rt) {
487   spew("mod    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
488   return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_mod).encode());
489 }
490 
as_modu(Register rd,Register rs,Register rt)491 BufferOffset AssemblerMIPSShared::as_modu(Register rd, Register rs,
492                                           Register rt) {
493   spew("modu   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
494   return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_modu).encode());
495 }
496 
as_ddiv(Register rs,Register rt)497 BufferOffset AssemblerMIPSShared::as_ddiv(Register rs, Register rt) {
498   spew("ddiv   %3s,%3s", rs.name(), rt.name());
499   return writeInst(InstReg(op_special, rs, rt, ff_ddiv).encode());
500 }
501 
as_ddiv(Register rd,Register rs,Register rt)502 BufferOffset AssemblerMIPSShared::as_ddiv(Register rd, Register rs,
503                                           Register rt) {
504   spew("ddiv   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
505   return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_ddiv).encode());
506 }
507 
as_ddivu(Register rs,Register rt)508 BufferOffset AssemblerMIPSShared::as_ddivu(Register rs, Register rt) {
509   spew("ddivu  %3s,%3s", rs.name(), rt.name());
510   return writeInst(InstReg(op_special, rs, rt, ff_ddivu).encode());
511 }
512 
as_ddivu(Register rd,Register rs,Register rt)513 BufferOffset AssemblerMIPSShared::as_ddivu(Register rd, Register rs,
514                                            Register rt) {
515   spew("ddivu  %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
516   return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_ddivu).encode());
517 }
518 
as_mul(Register rd,Register rs,Register rt)519 BufferOffset AssemblerMIPSShared::as_mul(Register rd, Register rs,
520                                          Register rt) {
521   spew("mul    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
522 #ifdef MIPSR6
523   return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_mul).encode());
524 #else
525   return writeInst(InstReg(op_special2, rs, rt, rd, ff_mul).encode());
526 #endif
527 }
528 
as_muh(Register rd,Register rs,Register rt)529 BufferOffset AssemblerMIPSShared::as_muh(Register rd, Register rs,
530                                          Register rt) {
531   spew("muh  %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
532   return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_muh).encode());
533 }
534 
as_mulu(Register rd,Register rs,Register rt)535 BufferOffset AssemblerMIPSShared::as_mulu(Register rd, Register rs,
536                                           Register rt) {
537   spew("mulu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
538   return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_mulu).encode());
539 }
540 
as_muhu(Register rd,Register rs,Register rt)541 BufferOffset AssemblerMIPSShared::as_muhu(Register rd, Register rs,
542                                           Register rt) {
543   spew("muhu %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
544   return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_muhu).encode());
545 }
546 
as_dmul(Register rd,Register rs,Register rt)547 BufferOffset AssemblerMIPSShared::as_dmul(Register rd, Register rs,
548                                           Register rt) {
549   spew("dmul   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
550   return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_dmul).encode());
551 }
552 
as_dmuh(Register rd,Register rs,Register rt)553 BufferOffset AssemblerMIPSShared::as_dmuh(Register rd, Register rs,
554                                           Register rt) {
555   spew("dmuh   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
556   return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_dmuh).encode());
557 }
558 
as_dmulu(Register rd,Register rt,Register rs)559 BufferOffset AssemblerMIPSShared::as_dmulu(Register rd, Register rt,
560                                            Register rs) {
561   spew("dmulu   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
562   return writeInst(InstReg(op_special, rs, rt, rd, 0x2, ff_dmulu).encode());
563 }
564 
as_dmuhu(Register rd,Register rt,Register rs)565 BufferOffset AssemblerMIPSShared::as_dmuhu(Register rd, Register rt,
566                                            Register rs) {
567   spew("dmuhu   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
568   return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_dmuhu).encode());
569 }
570 
as_dmod(Register rd,Register rs,Register rt)571 BufferOffset AssemblerMIPSShared::as_dmod(Register rd, Register rs,
572                                           Register rt) {
573   spew("dmod    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
574   return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_dmod).encode());
575 }
576 
as_dmodu(Register rd,Register rs,Register rt)577 BufferOffset AssemblerMIPSShared::as_dmodu(Register rd, Register rs,
578                                            Register rt) {
579   spew("dmodu    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
580   return writeInst(InstReg(op_special, rs, rt, rd, 0x3, ff_dmodu).encode());
581 }
582 
as_madd(Register rs,Register rt)583 BufferOffset AssemblerMIPSShared::as_madd(Register rs, Register rt) {
584   spew("madd %3s,%3s", rs.name(), rt.name());
585   return writeInst(InstReg(op_special2, rs, rt, ff_madd).encode());
586 }
587 
as_maddu(Register rs,Register rt)588 BufferOffset AssemblerMIPSShared::as_maddu(Register rs, Register rt) {
589   spew("maddu %3s,%3s", rs.name(), rt.name());
590   return writeInst(InstReg(op_special2, rs, rt, ff_maddu).encode());
591 }
592 
593 // Shift instructions
as_sll(Register rd,Register rt,uint16_t sa)594 BufferOffset AssemblerMIPSShared::as_sll(Register rd, Register rt,
595                                          uint16_t sa) {
596   MOZ_ASSERT(sa < 32);
597   spew("sll    %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
598   return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sll).encode());
599 }
600 
as_dsll(Register rd,Register rt,uint16_t sa)601 BufferOffset AssemblerMIPSShared::as_dsll(Register rd, Register rt,
602                                           uint16_t sa) {
603   MOZ_ASSERT(sa < 32);
604   spew("dsll   %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
605   return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsll).encode());
606 }
607 
as_dsll32(Register rd,Register rt,uint16_t sa)608 BufferOffset AssemblerMIPSShared::as_dsll32(Register rd, Register rt,
609                                             uint16_t sa) {
610   MOZ_ASSERT(31 < sa && sa < 64);
611   spew("dsll32 %3s,%3s, 0x%x", rd.name(), rt.name(), sa - 32);
612   return writeInst(
613       InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsll32).encode());
614 }
615 
as_sllv(Register rd,Register rt,Register rs)616 BufferOffset AssemblerMIPSShared::as_sllv(Register rd, Register rt,
617                                           Register rs) {
618   spew("sllv   %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
619   return writeInst(InstReg(op_special, rs, rt, rd, ff_sllv).encode());
620 }
621 
as_dsllv(Register rd,Register rt,Register rs)622 BufferOffset AssemblerMIPSShared::as_dsllv(Register rd, Register rt,
623                                            Register rs) {
624   spew("dsllv  %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
625   return writeInst(InstReg(op_special, rs, rt, rd, ff_dsllv).encode());
626 }
627 
as_srl(Register rd,Register rt,uint16_t sa)628 BufferOffset AssemblerMIPSShared::as_srl(Register rd, Register rt,
629                                          uint16_t sa) {
630   MOZ_ASSERT(sa < 32);
631   spew("srl    %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
632   return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_srl).encode());
633 }
634 
as_dsrl(Register rd,Register rt,uint16_t sa)635 BufferOffset AssemblerMIPSShared::as_dsrl(Register rd, Register rt,
636                                           uint16_t sa) {
637   MOZ_ASSERT(sa < 32);
638   spew("dsrl   %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
639   return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsrl).encode());
640 }
641 
as_dsrl32(Register rd,Register rt,uint16_t sa)642 BufferOffset AssemblerMIPSShared::as_dsrl32(Register rd, Register rt,
643                                             uint16_t sa) {
644   MOZ_ASSERT(31 < sa && sa < 64);
645   spew("dsrl32 %3s,%3s, 0x%x", rd.name(), rt.name(), sa - 32);
646   return writeInst(
647       InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsrl32).encode());
648 }
649 
as_srlv(Register rd,Register rt,Register rs)650 BufferOffset AssemblerMIPSShared::as_srlv(Register rd, Register rt,
651                                           Register rs) {
652   spew("srlv   %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
653   return writeInst(InstReg(op_special, rs, rt, rd, ff_srlv).encode());
654 }
655 
as_dsrlv(Register rd,Register rt,Register rs)656 BufferOffset AssemblerMIPSShared::as_dsrlv(Register rd, Register rt,
657                                            Register rs) {
658   spew("dsrlv  %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
659   return writeInst(InstReg(op_special, rs, rt, rd, ff_dsrlv).encode());
660 }
661 
as_sra(Register rd,Register rt,uint16_t sa)662 BufferOffset AssemblerMIPSShared::as_sra(Register rd, Register rt,
663                                          uint16_t sa) {
664   MOZ_ASSERT(sa < 32);
665   spew("sra    %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
666   return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_sra).encode());
667 }
668 
as_dsra(Register rd,Register rt,uint16_t sa)669 BufferOffset AssemblerMIPSShared::as_dsra(Register rd, Register rt,
670                                           uint16_t sa) {
671   MOZ_ASSERT(sa < 32);
672   spew("dsra   %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
673   return writeInst(InstReg(op_special, rs_zero, rt, rd, sa, ff_dsra).encode());
674 }
675 
as_dsra32(Register rd,Register rt,uint16_t sa)676 BufferOffset AssemblerMIPSShared::as_dsra32(Register rd, Register rt,
677                                             uint16_t sa) {
678   MOZ_ASSERT(31 < sa && sa < 64);
679   spew("dsra32 %3s,%3s, 0x%x", rd.name(), rt.name(), sa - 32);
680   return writeInst(
681       InstReg(op_special, rs_zero, rt, rd, sa - 32, ff_dsra32).encode());
682 }
683 
as_srav(Register rd,Register rt,Register rs)684 BufferOffset AssemblerMIPSShared::as_srav(Register rd, Register rt,
685                                           Register rs) {
686   spew("srav   %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
687   return writeInst(InstReg(op_special, rs, rt, rd, ff_srav).encode());
688 }
689 
as_dsrav(Register rd,Register rt,Register rs)690 BufferOffset AssemblerMIPSShared::as_dsrav(Register rd, Register rt,
691                                            Register rs) {
692   spew("dsrav  %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
693   return writeInst(InstReg(op_special, rs, rt, rd, ff_dsrav).encode());
694 }
695 
as_rotr(Register rd,Register rt,uint16_t sa)696 BufferOffset AssemblerMIPSShared::as_rotr(Register rd, Register rt,
697                                           uint16_t sa) {
698   MOZ_ASSERT(sa < 32);
699   spew("rotr   %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
700   MOZ_ASSERT(hasR2());
701   return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_srl).encode());
702 }
703 
as_drotr(Register rd,Register rt,uint16_t sa)704 BufferOffset AssemblerMIPSShared::as_drotr(Register rd, Register rt,
705                                            uint16_t sa) {
706   MOZ_ASSERT(sa < 32);
707   spew("drotr  %3s,%3s, 0x%x", rd.name(), rt.name(), sa);
708   MOZ_ASSERT(hasR2());
709   return writeInst(InstReg(op_special, rs_one, rt, rd, sa, ff_dsrl).encode());
710 }
711 
as_drotr32(Register rd,Register rt,uint16_t sa)712 BufferOffset AssemblerMIPSShared::as_drotr32(Register rd, Register rt,
713                                              uint16_t sa) {
714   MOZ_ASSERT(31 < sa && sa < 64);
715   spew("drotr32%3s,%3s, 0x%x", rd.name(), rt.name(), sa - 32);
716   MOZ_ASSERT(hasR2());
717   return writeInst(
718       InstReg(op_special, rs_one, rt, rd, sa - 32, ff_dsrl32).encode());
719 }
720 
as_rotrv(Register rd,Register rt,Register rs)721 BufferOffset AssemblerMIPSShared::as_rotrv(Register rd, Register rt,
722                                            Register rs) {
723   spew("rotrv  %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
724   MOZ_ASSERT(hasR2());
725   return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_srlv).encode());
726 }
727 
as_drotrv(Register rd,Register rt,Register rs)728 BufferOffset AssemblerMIPSShared::as_drotrv(Register rd, Register rt,
729                                             Register rs) {
730   spew("drotrv %3s,%3s,%3s", rd.name(), rt.name(), rs.name());
731   MOZ_ASSERT(hasR2());
732   return writeInst(InstReg(op_special, rs, rt, rd, 1, ff_dsrlv).encode());
733 }
734 
735 // Load and store instructions
as_lb(Register rd,Register rs,int16_t off)736 BufferOffset AssemblerMIPSShared::as_lb(Register rd, Register rs, int16_t off) {
737   spew("lb     %3s, (0x%x)%2s", rd.name(), off, rs.name());
738   return writeInst(InstImm(op_lb, rs, rd, Imm16(off)).encode());
739 }
740 
as_lbu(Register rd,Register rs,int16_t off)741 BufferOffset AssemblerMIPSShared::as_lbu(Register rd, Register rs,
742                                          int16_t off) {
743   spew("lbu    %3s, (0x%x)%2s", rd.name(), off, rs.name());
744   return writeInst(InstImm(op_lbu, rs, rd, Imm16(off)).encode());
745 }
746 
as_lh(Register rd,Register rs,int16_t off)747 BufferOffset AssemblerMIPSShared::as_lh(Register rd, Register rs, int16_t off) {
748   spew("lh     %3s, (0x%x)%2s", rd.name(), off, rs.name());
749   return writeInst(InstImm(op_lh, rs, rd, Imm16(off)).encode());
750 }
751 
as_lhu(Register rd,Register rs,int16_t off)752 BufferOffset AssemblerMIPSShared::as_lhu(Register rd, Register rs,
753                                          int16_t off) {
754   spew("lhu    %3s, (0x%x)%2s", rd.name(), off, rs.name());
755   return writeInst(InstImm(op_lhu, rs, rd, Imm16(off)).encode());
756 }
757 
as_lw(Register rd,Register rs,int16_t off)758 BufferOffset AssemblerMIPSShared::as_lw(Register rd, Register rs, int16_t off) {
759   spew("lw     %3s, (0x%x)%2s", rd.name(), off, rs.name());
760   return writeInst(InstImm(op_lw, rs, rd, Imm16(off)).encode());
761 }
762 
as_lwu(Register rd,Register rs,int16_t off)763 BufferOffset AssemblerMIPSShared::as_lwu(Register rd, Register rs,
764                                          int16_t off) {
765   spew("lwu    %3s, (0x%x)%2s", rd.name(), off, rs.name());
766   return writeInst(InstImm(op_lwu, rs, rd, Imm16(off)).encode());
767 }
768 
as_lwl(Register rd,Register rs,int16_t off)769 BufferOffset AssemblerMIPSShared::as_lwl(Register rd, Register rs,
770                                          int16_t off) {
771   spew("lwl    %3s, (0x%x)%2s", rd.name(), off, rs.name());
772   return writeInst(InstImm(op_lwl, rs, rd, Imm16(off)).encode());
773 }
774 
as_lwr(Register rd,Register rs,int16_t off)775 BufferOffset AssemblerMIPSShared::as_lwr(Register rd, Register rs,
776                                          int16_t off) {
777   spew("lwr    %3s, (0x%x)%2s", rd.name(), off, rs.name());
778   return writeInst(InstImm(op_lwr, rs, rd, Imm16(off)).encode());
779 }
780 
as_ll(Register rd,Register rs,int16_t off)781 BufferOffset AssemblerMIPSShared::as_ll(Register rd, Register rs, int16_t off) {
782   spew("ll     %3s, (0x%x)%2s", rd.name(), off, rs.name());
783 #ifdef MIPSR6
784   return writeInst(InstReg(op_special3, rs, rd, ff_ll).encode());
785 #else
786   return writeInst(InstImm(op_ll, rs, rd, Imm16(off)).encode());
787 #endif
788 }
789 
as_lld(Register rd,Register rs,int16_t off)790 BufferOffset AssemblerMIPSShared::as_lld(Register rd, Register rs,
791                                          int16_t off) {
792   spew("lld     %3s, (0x%x)%2s", rd.name(), off, rs.name());
793 #ifdef MIPSR6
794   return writeInst(InstReg(op_special3, rs, rd, ff_lld).encode());
795 #else
796   return writeInst(InstImm(op_lld, rs, rd, Imm16(off)).encode());
797 #endif
798 }
799 
as_ld(Register rd,Register rs,int16_t off)800 BufferOffset AssemblerMIPSShared::as_ld(Register rd, Register rs, int16_t off) {
801   spew("ld     %3s, (0x%x)%2s", rd.name(), off, rs.name());
802   return writeInst(InstImm(op_ld, rs, rd, Imm16(off)).encode());
803 }
804 
as_ldl(Register rd,Register rs,int16_t off)805 BufferOffset AssemblerMIPSShared::as_ldl(Register rd, Register rs,
806                                          int16_t off) {
807   spew("ldl    %3s, (0x%x)%2s", rd.name(), off, rs.name());
808   return writeInst(InstImm(op_ldl, rs, rd, Imm16(off)).encode());
809 }
810 
as_ldr(Register rd,Register rs,int16_t off)811 BufferOffset AssemblerMIPSShared::as_ldr(Register rd, Register rs,
812                                          int16_t off) {
813   spew("ldr    %3s, (0x%x)%2s", rd.name(), off, rs.name());
814   return writeInst(InstImm(op_ldr, rs, rd, Imm16(off)).encode());
815 }
816 
as_sb(Register rd,Register rs,int16_t off)817 BufferOffset AssemblerMIPSShared::as_sb(Register rd, Register rs, int16_t off) {
818   spew("sb     %3s, (0x%x)%2s", rd.name(), off, rs.name());
819   return writeInst(InstImm(op_sb, rs, rd, Imm16(off)).encode());
820 }
821 
as_sh(Register rd,Register rs,int16_t off)822 BufferOffset AssemblerMIPSShared::as_sh(Register rd, Register rs, int16_t off) {
823   spew("sh     %3s, (0x%x)%2s", rd.name(), off, rs.name());
824   return writeInst(InstImm(op_sh, rs, rd, Imm16(off)).encode());
825 }
826 
as_sw(Register rd,Register rs,int16_t off)827 BufferOffset AssemblerMIPSShared::as_sw(Register rd, Register rs, int16_t off) {
828   spew("sw     %3s, (0x%x)%2s", rd.name(), off, rs.name());
829   return writeInst(InstImm(op_sw, rs, rd, Imm16(off)).encode());
830 }
831 
as_swl(Register rd,Register rs,int16_t off)832 BufferOffset AssemblerMIPSShared::as_swl(Register rd, Register rs,
833                                          int16_t off) {
834   spew("swl    %3s, (0x%x)%2s", rd.name(), off, rs.name());
835   return writeInst(InstImm(op_swl, rs, rd, Imm16(off)).encode());
836 }
837 
as_swr(Register rd,Register rs,int16_t off)838 BufferOffset AssemblerMIPSShared::as_swr(Register rd, Register rs,
839                                          int16_t off) {
840   spew("swr    %3s, (0x%x)%2s", rd.name(), off, rs.name());
841   return writeInst(InstImm(op_swr, rs, rd, Imm16(off)).encode());
842 }
843 
as_sc(Register rd,Register rs,int16_t off)844 BufferOffset AssemblerMIPSShared::as_sc(Register rd, Register rs, int16_t off) {
845   spew("sc     %3s, (0x%x)%2s", rd.name(), off, rs.name());
846 #ifdef MIPSR6
847   return writeInst(InstReg(op_special3, rs, rd, ff_sc).encode());
848 #else
849   return writeInst(InstImm(op_sc, rs, rd, Imm16(off)).encode());
850 #endif
851 }
852 
as_scd(Register rd,Register rs,int16_t off)853 BufferOffset AssemblerMIPSShared::as_scd(Register rd, Register rs,
854                                          int16_t off) {
855 #ifdef MIPSR6
856   return writeInst(InstReg(op_special3, rs, rd, ff_scd).encode());
857 #else
858   spew("scd     %3s, (0x%x)%2s", rd.name(), off, rs.name());
859   return writeInst(InstImm(op_scd, rs, rd, Imm16(off)).encode());
860 #endif
861 }
862 
as_sd(Register rd,Register rs,int16_t off)863 BufferOffset AssemblerMIPSShared::as_sd(Register rd, Register rs, int16_t off) {
864   spew("sd     %3s, (0x%x)%2s", rd.name(), off, rs.name());
865   return writeInst(InstImm(op_sd, rs, rd, Imm16(off)).encode());
866 }
867 
as_sdl(Register rd,Register rs,int16_t off)868 BufferOffset AssemblerMIPSShared::as_sdl(Register rd, Register rs,
869                                          int16_t off) {
870   spew("sdl    %3s, (0x%x)%2s", rd.name(), off, rs.name());
871   return writeInst(InstImm(op_sdl, rs, rd, Imm16(off)).encode());
872 }
873 
as_sdr(Register rd,Register rs,int16_t off)874 BufferOffset AssemblerMIPSShared::as_sdr(Register rd, Register rs,
875                                          int16_t off) {
876   spew("sdr    %3s, (0x%x)%2s", rd.name(), off, rs.name());
877   return writeInst(InstImm(op_sdr, rs, rd, Imm16(off)).encode());
878 }
879 
as_seleqz(Register rd,Register rs,Register rt)880 BufferOffset AssemblerMIPSShared::as_seleqz(Register rd, Register rs,
881                                             Register rt) {
882   spew("seleqz    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
883   return writeInst(InstReg(op_special, rs, rt, rd, 0x0, ff_seleqz).encode());
884 }
885 
as_selnez(Register rd,Register rs,Register rt)886 BufferOffset AssemblerMIPSShared::as_selnez(Register rd, Register rs,
887                                             Register rt) {
888   spew("selnez    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
889   return writeInst(InstReg(op_special, rs, rt, rd, 0x0, ff_selnez).encode());
890 }
891 
as_gslbx(Register rd,Register rs,Register ri,int16_t off)892 BufferOffset AssemblerMIPSShared::as_gslbx(Register rd, Register rs,
893                                            Register ri, int16_t off) {
894   MOZ_ASSERT(Imm8::IsInSignedRange(off));
895   spew("gslbx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
896   return writeInst(InstGS(op_ldc2, rs, rd, ri, Imm8(off), ff_gsxbx).encode());
897 }
898 
as_gssbx(Register rd,Register rs,Register ri,int16_t off)899 BufferOffset AssemblerMIPSShared::as_gssbx(Register rd, Register rs,
900                                            Register ri, int16_t off) {
901   MOZ_ASSERT(Imm8::IsInSignedRange(off));
902   spew("gssbx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
903   return writeInst(InstGS(op_sdc2, rs, rd, ri, Imm8(off), ff_gsxbx).encode());
904 }
905 
as_gslhx(Register rd,Register rs,Register ri,int16_t off)906 BufferOffset AssemblerMIPSShared::as_gslhx(Register rd, Register rs,
907                                            Register ri, int16_t off) {
908   MOZ_ASSERT(Imm8::IsInSignedRange(off));
909   spew("gslhx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
910   return writeInst(InstGS(op_ldc2, rs, rd, ri, Imm8(off), ff_gsxhx).encode());
911 }
912 
as_gsshx(Register rd,Register rs,Register ri,int16_t off)913 BufferOffset AssemblerMIPSShared::as_gsshx(Register rd, Register rs,
914                                            Register ri, int16_t off) {
915   MOZ_ASSERT(Imm8::IsInSignedRange(off));
916   spew("gsshx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
917   return writeInst(InstGS(op_sdc2, rs, rd, ri, Imm8(off), ff_gsxhx).encode());
918 }
919 
as_gslwx(Register rd,Register rs,Register ri,int16_t off)920 BufferOffset AssemblerMIPSShared::as_gslwx(Register rd, Register rs,
921                                            Register ri, int16_t off) {
922   MOZ_ASSERT(Imm8::IsInSignedRange(off));
923   spew("gslwx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
924   return writeInst(InstGS(op_ldc2, rs, rd, ri, Imm8(off), ff_gsxwx).encode());
925 }
926 
as_gsswx(Register rd,Register rs,Register ri,int16_t off)927 BufferOffset AssemblerMIPSShared::as_gsswx(Register rd, Register rs,
928                                            Register ri, int16_t off) {
929   MOZ_ASSERT(Imm8::IsInSignedRange(off));
930   spew("gsswx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
931   return writeInst(InstGS(op_sdc2, rs, rd, ri, Imm8(off), ff_gsxwx).encode());
932 }
933 
as_gsldx(Register rd,Register rs,Register ri,int16_t off)934 BufferOffset AssemblerMIPSShared::as_gsldx(Register rd, Register rs,
935                                            Register ri, int16_t off) {
936   MOZ_ASSERT(Imm8::IsInSignedRange(off));
937   spew("gsldx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
938   return writeInst(InstGS(op_ldc2, rs, rd, ri, Imm8(off), ff_gsxdx).encode());
939 }
940 
as_gssdx(Register rd,Register rs,Register ri,int16_t off)941 BufferOffset AssemblerMIPSShared::as_gssdx(Register rd, Register rs,
942                                            Register ri, int16_t off) {
943   MOZ_ASSERT(Imm8::IsInSignedRange(off));
944   spew("gssdx  %3s,%3s, (0x%x)%2s", rd.name(), rs.name(), off, ri.name());
945   return writeInst(InstGS(op_sdc2, rs, rd, ri, Imm8(off), ff_gsxdx).encode());
946 }
947 
as_gslq(Register rh,Register rl,Register rs,int16_t off)948 BufferOffset AssemblerMIPSShared::as_gslq(Register rh, Register rl, Register rs,
949                                           int16_t off) {
950   MOZ_ASSERT(GSImm13::IsInRange(off));
951   spew("gslq   %3s,%3s, (0x%x)%2s", rh.name(), rl.name(), off, rs.name());
952   return writeInst(InstGS(op_lwc2, rs, rl, rh, GSImm13(off), ff_gsxq).encode());
953 }
954 
as_gssq(Register rh,Register rl,Register rs,int16_t off)955 BufferOffset AssemblerMIPSShared::as_gssq(Register rh, Register rl, Register rs,
956                                           int16_t off) {
957   MOZ_ASSERT(GSImm13::IsInRange(off));
958   spew("gssq   %3s,%3s, (0x%x)%2s", rh.name(), rl.name(), off, rs.name());
959   return writeInst(InstGS(op_swc2, rs, rl, rh, GSImm13(off), ff_gsxq).encode());
960 }
961 
962 // Move from HI/LO register.
as_mfhi(Register rd)963 BufferOffset AssemblerMIPSShared::as_mfhi(Register rd) {
964   spew("mfhi   %3s", rd.name());
965   return writeInst(InstReg(op_special, rd, ff_mfhi).encode());
966 }
967 
as_mflo(Register rd)968 BufferOffset AssemblerMIPSShared::as_mflo(Register rd) {
969   spew("mflo   %3s", rd.name());
970   return writeInst(InstReg(op_special, rd, ff_mflo).encode());
971 }
972 
973 // Set on less than.
as_slt(Register rd,Register rs,Register rt)974 BufferOffset AssemblerMIPSShared::as_slt(Register rd, Register rs,
975                                          Register rt) {
976   spew("slt    %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
977   return writeInst(InstReg(op_special, rs, rt, rd, ff_slt).encode());
978 }
979 
as_sltu(Register rd,Register rs,Register rt)980 BufferOffset AssemblerMIPSShared::as_sltu(Register rd, Register rs,
981                                           Register rt) {
982   spew("sltu   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
983   return writeInst(InstReg(op_special, rs, rt, rd, ff_sltu).encode());
984 }
985 
as_slti(Register rd,Register rs,int32_t j)986 BufferOffset AssemblerMIPSShared::as_slti(Register rd, Register rs, int32_t j) {
987   MOZ_ASSERT(Imm16::IsInSignedRange(j));
988   spew("slti   %3s,%3s, 0x%x", rd.name(), rs.name(), j);
989   return writeInst(InstImm(op_slti, rs, rd, Imm16(j)).encode());
990 }
991 
as_sltiu(Register rd,Register rs,uint32_t j)992 BufferOffset AssemblerMIPSShared::as_sltiu(Register rd, Register rs,
993                                            uint32_t j) {
994   MOZ_ASSERT(Imm16::IsInSignedRange(int32_t(j)));
995   spew("sltiu  %3s,%3s, 0x%x", rd.name(), rs.name(), j);
996   return writeInst(InstImm(op_sltiu, rs, rd, Imm16(j)).encode());
997 }
998 
999 // Conditional move.
as_movz(Register rd,Register rs,Register rt)1000 BufferOffset AssemblerMIPSShared::as_movz(Register rd, Register rs,
1001                                           Register rt) {
1002   spew("movz   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
1003   return writeInst(InstReg(op_special, rs, rt, rd, ff_movz).encode());
1004 }
1005 
as_movn(Register rd,Register rs,Register rt)1006 BufferOffset AssemblerMIPSShared::as_movn(Register rd, Register rs,
1007                                           Register rt) {
1008   spew("movn   %3s,%3s,%3s", rd.name(), rs.name(), rt.name());
1009   return writeInst(InstReg(op_special, rs, rt, rd, ff_movn).encode());
1010 }
1011 
as_movt(Register rd,Register rs,uint16_t cc)1012 BufferOffset AssemblerMIPSShared::as_movt(Register rd, Register rs,
1013                                           uint16_t cc) {
1014   Register rt;
1015   rt = Register::FromCode((cc & 0x7) << 2 | 1);
1016   spew("movt   %3s,%3s, FCC%d", rd.name(), rs.name(), cc);
1017   return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode());
1018 }
1019 
as_movf(Register rd,Register rs,uint16_t cc)1020 BufferOffset AssemblerMIPSShared::as_movf(Register rd, Register rs,
1021                                           uint16_t cc) {
1022   Register rt;
1023   rt = Register::FromCode((cc & 0x7) << 2 | 0);
1024   spew("movf   %3s,%3s, FCC%d", rd.name(), rs.name(), cc);
1025   return writeInst(InstReg(op_special, rs, rt, rd, ff_movci).encode());
1026 }
1027 
1028 // Bit twiddling.
as_clz(Register rd,Register rs)1029 BufferOffset AssemblerMIPSShared::as_clz(Register rd, Register rs) {
1030   spew("clz    %3s,%3s", rd.name(), rs.name());
1031 #ifdef MIPSR6
1032   return writeInst(InstReg(op_special, rs, 0x0, rd, 0x1, ff_clz).encode());
1033 #else
1034   return writeInst(InstReg(op_special2, rs, rd, rd, ff_clz).encode());
1035 #endif
1036 }
1037 
as_dclz(Register rd,Register rs)1038 BufferOffset AssemblerMIPSShared::as_dclz(Register rd, Register rs) {
1039   spew("dclz   %3s,%3s", rd.name(), rs.name());
1040 #ifdef MIPSR6
1041   return writeInst(InstReg(op_special, rs, 0x0, rd, 0x1, ff_dclz).encode());
1042 #else
1043   return writeInst(InstReg(op_special2, rs, rd, rd, ff_dclz).encode());
1044 #endif
1045 }
1046 
as_wsbh(Register rd,Register rt)1047 BufferOffset AssemblerMIPSShared::as_wsbh(Register rd, Register rt) {
1048   spew("wsbh   %3s,%3s", rd.name(), rt.name());
1049   return writeInst(InstReg(op_special3, zero, rt, rd, 0x2, ff_bshfl).encode());
1050 }
1051 
as_dsbh(Register rd,Register rt)1052 BufferOffset AssemblerMIPSShared::as_dsbh(Register rd, Register rt) {
1053   spew("dsbh   %3s,%3s", rd.name(), rt.name());
1054   return writeInst(InstReg(op_special3, zero, rt, rd, 0x2, ff_dbshfl).encode());
1055 }
1056 
as_dshd(Register rd,Register rt)1057 BufferOffset AssemblerMIPSShared::as_dshd(Register rd, Register rt) {
1058   spew("dshd   %3s,%3s", rd.name(), rt.name());
1059   return writeInst(InstReg(op_special3, zero, rt, rd, 0x5, ff_dbshfl).encode());
1060 }
1061 
as_ins(Register rt,Register rs,uint16_t pos,uint16_t size)1062 BufferOffset AssemblerMIPSShared::as_ins(Register rt, Register rs, uint16_t pos,
1063                                          uint16_t size) {
1064   MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 &&
1065              pos + size <= 32);
1066   Register rd;
1067   rd = Register::FromCode(pos + size - 1);
1068   spew("ins    %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
1069   MOZ_ASSERT(hasR2());
1070   return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ins).encode());
1071 }
1072 
as_dins(Register rt,Register rs,uint16_t pos,uint16_t size)1073 BufferOffset AssemblerMIPSShared::as_dins(Register rt, Register rs,
1074                                           uint16_t pos, uint16_t size) {
1075   MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 &&
1076              pos + size <= 32);
1077   Register rd;
1078   rd = Register::FromCode(pos + size - 1);
1079   spew("dins   %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
1080   MOZ_ASSERT(hasR2());
1081   return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dins).encode());
1082 }
1083 
as_dinsm(Register rt,Register rs,uint16_t pos,uint16_t size)1084 BufferOffset AssemblerMIPSShared::as_dinsm(Register rt, Register rs,
1085                                            uint16_t pos, uint16_t size) {
1086   MOZ_ASSERT(pos < 32 && size >= 2 && size <= 64 && pos + size > 32 &&
1087              pos + size <= 64);
1088   Register rd;
1089   rd = Register::FromCode(pos + size - 1 - 32);
1090   spew("dinsm  %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
1091   MOZ_ASSERT(hasR2());
1092   return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dinsm).encode());
1093 }
1094 
as_dinsu(Register rt,Register rs,uint16_t pos,uint16_t size)1095 BufferOffset AssemblerMIPSShared::as_dinsu(Register rt, Register rs,
1096                                            uint16_t pos, uint16_t size) {
1097   MOZ_ASSERT(pos >= 32 && pos < 64 && size >= 1 && size <= 32 &&
1098              pos + size > 32 && pos + size <= 64);
1099   Register rd;
1100   rd = Register::FromCode(pos + size - 1 - 32);
1101   spew("dinsu  %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
1102   MOZ_ASSERT(hasR2());
1103   return writeInst(
1104       InstReg(op_special3, rs, rt, rd, pos - 32, ff_dinsu).encode());
1105 }
1106 
as_ext(Register rt,Register rs,uint16_t pos,uint16_t size)1107 BufferOffset AssemblerMIPSShared::as_ext(Register rt, Register rs, uint16_t pos,
1108                                          uint16_t size) {
1109   MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 &&
1110              pos + size <= 32);
1111   Register rd;
1112   rd = Register::FromCode(size - 1);
1113   spew("ext    %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
1114   MOZ_ASSERT(hasR2());
1115   return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ext).encode());
1116 }
1117 
1118 // Sign extend
as_seb(Register rd,Register rt)1119 BufferOffset AssemblerMIPSShared::as_seb(Register rd, Register rt) {
1120   spew("seb    %3s,%3s", rd.name(), rt.name());
1121   MOZ_ASSERT(hasR2());
1122   return writeInst(InstReg(op_special3, zero, rt, rd, 16, ff_bshfl).encode());
1123 }
1124 
as_seh(Register rd,Register rt)1125 BufferOffset AssemblerMIPSShared::as_seh(Register rd, Register rt) {
1126   spew("seh    %3s,%3s", rd.name(), rt.name());
1127   MOZ_ASSERT(hasR2());
1128   return writeInst(InstReg(op_special3, zero, rt, rd, 24, ff_bshfl).encode());
1129 }
1130 
as_dext(Register rt,Register rs,uint16_t pos,uint16_t size)1131 BufferOffset AssemblerMIPSShared::as_dext(Register rt, Register rs,
1132                                           uint16_t pos, uint16_t size) {
1133   MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 &&
1134              pos + size <= 63);
1135   Register rd;
1136   rd = Register::FromCode(size - 1);
1137   spew("dext   %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
1138   MOZ_ASSERT(hasR2());
1139   return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dext).encode());
1140 }
1141 
as_dextm(Register rt,Register rs,uint16_t pos,uint16_t size)1142 BufferOffset AssemblerMIPSShared::as_dextm(Register rt, Register rs,
1143                                            uint16_t pos, uint16_t size) {
1144   MOZ_ASSERT(pos < 32 && size > 32 && size <= 64 && pos + size > 32 &&
1145              pos + size <= 64);
1146   Register rd;
1147   rd = Register::FromCode(size - 1 - 32);
1148   spew("dextm  %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
1149   MOZ_ASSERT(hasR2());
1150   return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_dextm).encode());
1151 }
1152 
as_dextu(Register rt,Register rs,uint16_t pos,uint16_t size)1153 BufferOffset AssemblerMIPSShared::as_dextu(Register rt, Register rs,
1154                                            uint16_t pos, uint16_t size) {
1155   MOZ_ASSERT(pos >= 32 && pos < 64 && size != 0 && size <= 32 &&
1156              pos + size > 32 && pos + size <= 64);
1157   Register rd;
1158   rd = Register::FromCode(size - 1);
1159   spew("dextu  %3s,%3s, %d, %d", rt.name(), rs.name(), pos, size);
1160   MOZ_ASSERT(hasR2());
1161   return writeInst(
1162       InstReg(op_special3, rs, rt, rd, pos - 32, ff_dextu).encode());
1163 }
1164 
1165 // FP instructions
as_ldc1(FloatRegister ft,Register base,int32_t off)1166 BufferOffset AssemblerMIPSShared::as_ldc1(FloatRegister ft, Register base,
1167                                           int32_t off) {
1168   MOZ_ASSERT(Imm16::IsInSignedRange(off));
1169   spew("ldc1   %3s, (0x%x)%2s", ft.name(), off, base.name());
1170   return writeInst(InstImm(op_ldc1, base, ft, Imm16(off)).encode());
1171 }
1172 
as_sdc1(FloatRegister ft,Register base,int32_t off)1173 BufferOffset AssemblerMIPSShared::as_sdc1(FloatRegister ft, Register base,
1174                                           int32_t off) {
1175   MOZ_ASSERT(Imm16::IsInSignedRange(off));
1176   spew("sdc1   %3s, (0x%x)%2s", ft.name(), off, base.name());
1177   return writeInst(InstImm(op_sdc1, base, ft, Imm16(off)).encode());
1178 }
1179 
as_lwc1(FloatRegister ft,Register base,int32_t off)1180 BufferOffset AssemblerMIPSShared::as_lwc1(FloatRegister ft, Register base,
1181                                           int32_t off) {
1182   MOZ_ASSERT(Imm16::IsInSignedRange(off));
1183   spew("lwc1   %3s, (0x%x)%2s", ft.name(), off, base.name());
1184   return writeInst(InstImm(op_lwc1, base, ft, Imm16(off)).encode());
1185 }
1186 
as_swc1(FloatRegister ft,Register base,int32_t off)1187 BufferOffset AssemblerMIPSShared::as_swc1(FloatRegister ft, Register base,
1188                                           int32_t off) {
1189   MOZ_ASSERT(Imm16::IsInSignedRange(off));
1190   spew("swc1   %3s, (0x%x)%2s", ft.name(), off, base.name());
1191   return writeInst(InstImm(op_swc1, base, ft, Imm16(off)).encode());
1192 }
1193 
as_gsldl(FloatRegister fd,Register base,int32_t off)1194 BufferOffset AssemblerMIPSShared::as_gsldl(FloatRegister fd, Register base,
1195                                            int32_t off) {
1196   MOZ_ASSERT(Imm8::IsInSignedRange(off));
1197   spew("gsldl  %3s, (0x%x)%2s", fd.name(), off, base.name());
1198   return writeInst(InstGS(op_lwc2, base, fd, Imm8(off), ff_gsxdlc1).encode());
1199 }
1200 
as_gsldr(FloatRegister fd,Register base,int32_t off)1201 BufferOffset AssemblerMIPSShared::as_gsldr(FloatRegister fd, Register base,
1202                                            int32_t off) {
1203   MOZ_ASSERT(Imm8::IsInSignedRange(off));
1204   spew("gsldr  %3s, (0x%x)%2s", fd.name(), off, base.name());
1205   return writeInst(InstGS(op_lwc2, base, fd, Imm8(off), ff_gsxdrc1).encode());
1206 }
1207 
as_gssdl(FloatRegister fd,Register base,int32_t off)1208 BufferOffset AssemblerMIPSShared::as_gssdl(FloatRegister fd, Register base,
1209                                            int32_t off) {
1210   MOZ_ASSERT(Imm8::IsInSignedRange(off));
1211   spew("gssdl  %3s, (0x%x)%2s", fd.name(), off, base.name());
1212   return writeInst(InstGS(op_swc2, base, fd, Imm8(off), ff_gsxdlc1).encode());
1213 }
1214 
as_gssdr(FloatRegister fd,Register base,int32_t off)1215 BufferOffset AssemblerMIPSShared::as_gssdr(FloatRegister fd, Register base,
1216                                            int32_t off) {
1217   MOZ_ASSERT(Imm8::IsInSignedRange(off));
1218   spew("gssdr  %3s, (0x%x)%2s", fd.name(), off, base.name());
1219   return writeInst(InstGS(op_swc2, base, fd, Imm8(off), ff_gsxdrc1).encode());
1220 }
1221 
as_gslsl(FloatRegister fd,Register base,int32_t off)1222 BufferOffset AssemblerMIPSShared::as_gslsl(FloatRegister fd, Register base,
1223                                            int32_t off) {
1224   MOZ_ASSERT(Imm8::IsInSignedRange(off));
1225   spew("gslsl  %3s, (0x%x)%2s", fd.name(), off, base.name());
1226   return writeInst(InstGS(op_lwc2, base, fd, Imm8(off), ff_gsxwlc1).encode());
1227 }
1228 
as_gslsr(FloatRegister fd,Register base,int32_t off)1229 BufferOffset AssemblerMIPSShared::as_gslsr(FloatRegister fd, Register base,
1230                                            int32_t off) {
1231   MOZ_ASSERT(Imm8::IsInSignedRange(off));
1232   spew("gslsr  %3s, (0x%x)%2s", fd.name(), off, base.name());
1233   return writeInst(InstGS(op_lwc2, base, fd, Imm8(off), ff_gsxwrc1).encode());
1234 }
1235 
as_gsssl(FloatRegister fd,Register base,int32_t off)1236 BufferOffset AssemblerMIPSShared::as_gsssl(FloatRegister fd, Register base,
1237                                            int32_t off) {
1238   MOZ_ASSERT(Imm8::IsInSignedRange(off));
1239   spew("gsssl  %3s, (0x%x)%2s", fd.name(), off, base.name());
1240   return writeInst(InstGS(op_swc2, base, fd, Imm8(off), ff_gsxwlc1).encode());
1241 }
1242 
as_gsssr(FloatRegister fd,Register base,int32_t off)1243 BufferOffset AssemblerMIPSShared::as_gsssr(FloatRegister fd, Register base,
1244                                            int32_t off) {
1245   MOZ_ASSERT(Imm8::IsInSignedRange(off));
1246   spew("gsssr  %3s, (0x%x)%2s", fd.name(), off, base.name());
1247   return writeInst(InstGS(op_swc2, base, fd, Imm8(off), ff_gsxwrc1).encode());
1248 }
1249 
as_gslsx(FloatRegister fd,Register rs,Register ri,int16_t off)1250 BufferOffset AssemblerMIPSShared::as_gslsx(FloatRegister fd, Register rs,
1251                                            Register ri, int16_t off) {
1252   MOZ_ASSERT(Imm8::IsInSignedRange(off));
1253   spew("gslsx  %3s, (%3s,%3s, 0x%x)", fd.name(), rs.name(), ri.name(), off);
1254   return writeInst(InstGS(op_ldc2, rs, fd, ri, Imm8(off), ff_gsxwxc1).encode());
1255 }
1256 
as_gsssx(FloatRegister fd,Register rs,Register ri,int16_t off)1257 BufferOffset AssemblerMIPSShared::as_gsssx(FloatRegister fd, Register rs,
1258                                            Register ri, int16_t off) {
1259   MOZ_ASSERT(Imm8::IsInSignedRange(off));
1260   spew("gsssx  %3s, (%3s,%3s, 0x%x)", fd.name(), rs.name(), ri.name(), off);
1261   return writeInst(InstGS(op_sdc2, rs, fd, ri, Imm8(off), ff_gsxwxc1).encode());
1262 }
1263 
as_gsldx(FloatRegister fd,Register rs,Register ri,int16_t off)1264 BufferOffset AssemblerMIPSShared::as_gsldx(FloatRegister fd, Register rs,
1265                                            Register ri, int16_t off) {
1266   MOZ_ASSERT(Imm8::IsInSignedRange(off));
1267   spew("gsldx  %3s, (%3s,%3s, 0x%x)", fd.name(), rs.name(), ri.name(), off);
1268   return writeInst(InstGS(op_ldc2, rs, fd, ri, Imm8(off), ff_gsxdxc1).encode());
1269 }
1270 
as_gssdx(FloatRegister fd,Register rs,Register ri,int16_t off)1271 BufferOffset AssemblerMIPSShared::as_gssdx(FloatRegister fd, Register rs,
1272                                            Register ri, int16_t off) {
1273   MOZ_ASSERT(Imm8::IsInSignedRange(off));
1274   spew("gssdx  %3s, (%3s,%3s, 0x%x)", fd.name(), rs.name(), ri.name(), off);
1275   return writeInst(InstGS(op_sdc2, rs, fd, ri, Imm8(off), ff_gsxdxc1).encode());
1276 }
1277 
as_gslq(FloatRegister rh,FloatRegister rl,Register rs,int16_t off)1278 BufferOffset AssemblerMIPSShared::as_gslq(FloatRegister rh, FloatRegister rl,
1279                                           Register rs, int16_t off) {
1280   MOZ_ASSERT(GSImm13::IsInRange(off));
1281   spew("gslq   %3s,%3s, (0x%x)%2s", rh.name(), rl.name(), off, rs.name());
1282   return writeInst(
1283       InstGS(op_lwc2, rs, rl, rh, GSImm13(off), ff_gsxqc1).encode());
1284 }
1285 
as_gssq(FloatRegister rh,FloatRegister rl,Register rs,int16_t off)1286 BufferOffset AssemblerMIPSShared::as_gssq(FloatRegister rh, FloatRegister rl,
1287                                           Register rs, int16_t off) {
1288   MOZ_ASSERT(GSImm13::IsInRange(off));
1289   spew("gssq   %3s,%3s, (0x%x)%2s", rh.name(), rl.name(), off, rs.name());
1290   return writeInst(
1291       InstGS(op_swc2, rs, rl, rh, GSImm13(off), ff_gsxqc1).encode());
1292 }
1293 
as_movs(FloatRegister fd,FloatRegister fs)1294 BufferOffset AssemblerMIPSShared::as_movs(FloatRegister fd, FloatRegister fs) {
1295   spew("mov.s  %3s,%3s", fd.name(), fs.name());
1296   return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_mov_fmt).encode());
1297 }
1298 
as_movd(FloatRegister fd,FloatRegister fs)1299 BufferOffset AssemblerMIPSShared::as_movd(FloatRegister fd, FloatRegister fs) {
1300   spew("mov.d  %3s,%3s", fd.name(), fs.name());
1301   return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_mov_fmt).encode());
1302 }
1303 
as_ctc1(Register rt,FPControl fc)1304 BufferOffset AssemblerMIPSShared::as_ctc1(Register rt, FPControl fc) {
1305   spew("ctc1   %3s,%d", rt.name(), fc);
1306   return writeInst(InstReg(op_cop1, rs_ctc1, rt, (uint32_t)fc).encode());
1307 }
1308 
as_cfc1(Register rt,FPControl fc)1309 BufferOffset AssemblerMIPSShared::as_cfc1(Register rt, FPControl fc) {
1310   spew("cfc1   %3s,%d", rt.name(), fc);
1311   return writeInst(InstReg(op_cop1, rs_cfc1, rt, (uint32_t)fc).encode());
1312 }
1313 
as_mtc1(Register rt,FloatRegister fs)1314 BufferOffset AssemblerMIPSShared::as_mtc1(Register rt, FloatRegister fs) {
1315   spew("mtc1   %3s,%3s", rt.name(), fs.name());
1316   return writeInst(InstReg(op_cop1, rs_mtc1, rt, fs).encode());
1317 }
1318 
as_mfc1(Register rt,FloatRegister fs)1319 BufferOffset AssemblerMIPSShared::as_mfc1(Register rt, FloatRegister fs) {
1320   spew("mfc1   %3s,%3s", rt.name(), fs.name());
1321   return writeInst(InstReg(op_cop1, rs_mfc1, rt, fs).encode());
1322 }
1323 
as_mthc1(Register rt,FloatRegister fs)1324 BufferOffset AssemblerMIPSShared::as_mthc1(Register rt, FloatRegister fs) {
1325   spew("mthc1  %3s,%3s", rt.name(), fs.name());
1326   return writeInst(InstReg(op_cop1, rs_mthc1, rt, fs).encode());
1327 }
1328 
as_mfhc1(Register rt,FloatRegister fs)1329 BufferOffset AssemblerMIPSShared::as_mfhc1(Register rt, FloatRegister fs) {
1330   spew("mfhc1  %3s,%3s", rt.name(), fs.name());
1331   return writeInst(InstReg(op_cop1, rs_mfhc1, rt, fs).encode());
1332 }
1333 
as_dmtc1(Register rt,FloatRegister fs)1334 BufferOffset AssemblerMIPSShared::as_dmtc1(Register rt, FloatRegister fs) {
1335   spew("dmtc1  %3s,%3s", rt.name(), fs.name());
1336   return writeInst(InstReg(op_cop1, rs_dmtc1, rt, fs).encode());
1337 }
1338 
as_dmfc1(Register rt,FloatRegister fs)1339 BufferOffset AssemblerMIPSShared::as_dmfc1(Register rt, FloatRegister fs) {
1340   spew("dmfc1  %3s,%3s", rt.name(), fs.name());
1341   return writeInst(InstReg(op_cop1, rs_dmfc1, rt, fs).encode());
1342 }
1343 
1344 // FP convert instructions
as_ceilws(FloatRegister fd,FloatRegister fs)1345 BufferOffset AssemblerMIPSShared::as_ceilws(FloatRegister fd,
1346                                             FloatRegister fs) {
1347   spew("ceil.w.s%3s,%3s", fd.name(), fs.name());
1348   return writeInst(
1349       InstReg(op_cop1, rs_s, zero, fs, fd, ff_ceil_w_fmt).encode());
1350 }
1351 
as_floorws(FloatRegister fd,FloatRegister fs)1352 BufferOffset AssemblerMIPSShared::as_floorws(FloatRegister fd,
1353                                              FloatRegister fs) {
1354   spew("floor.w.s%3s,%3s", fd.name(), fs.name());
1355   return writeInst(
1356       InstReg(op_cop1, rs_s, zero, fs, fd, ff_floor_w_fmt).encode());
1357 }
1358 
as_roundws(FloatRegister fd,FloatRegister fs)1359 BufferOffset AssemblerMIPSShared::as_roundws(FloatRegister fd,
1360                                              FloatRegister fs) {
1361   spew("round.w.s%3s,%3s", fd.name(), fs.name());
1362   return writeInst(
1363       InstReg(op_cop1, rs_s, zero, fs, fd, ff_round_w_fmt).encode());
1364 }
1365 
as_truncws(FloatRegister fd,FloatRegister fs)1366 BufferOffset AssemblerMIPSShared::as_truncws(FloatRegister fd,
1367                                              FloatRegister fs) {
1368   spew("trunc.w.s%3s,%3s", fd.name(), fs.name());
1369   return writeInst(
1370       InstReg(op_cop1, rs_s, zero, fs, fd, ff_trunc_w_fmt).encode());
1371 }
1372 
as_truncls(FloatRegister fd,FloatRegister fs)1373 BufferOffset AssemblerMIPSShared::as_truncls(FloatRegister fd,
1374                                              FloatRegister fs) {
1375   spew("trunc.l.s%3s,%3s", fd.name(), fs.name());
1376   MOZ_ASSERT(hasR2());
1377   return writeInst(
1378       InstReg(op_cop1, rs_s, zero, fs, fd, ff_trunc_l_fmt).encode());
1379 }
1380 
as_ceilwd(FloatRegister fd,FloatRegister fs)1381 BufferOffset AssemblerMIPSShared::as_ceilwd(FloatRegister fd,
1382                                             FloatRegister fs) {
1383   spew("ceil.w.d%3s,%3s", fd.name(), fs.name());
1384   return writeInst(
1385       InstReg(op_cop1, rs_d, zero, fs, fd, ff_ceil_w_fmt).encode());
1386 }
1387 
as_floorwd(FloatRegister fd,FloatRegister fs)1388 BufferOffset AssemblerMIPSShared::as_floorwd(FloatRegister fd,
1389                                              FloatRegister fs) {
1390   spew("floor.w.d%3s,%3s", fd.name(), fs.name());
1391   return writeInst(
1392       InstReg(op_cop1, rs_d, zero, fs, fd, ff_floor_w_fmt).encode());
1393 }
1394 
as_roundwd(FloatRegister fd,FloatRegister fs)1395 BufferOffset AssemblerMIPSShared::as_roundwd(FloatRegister fd,
1396                                              FloatRegister fs) {
1397   spew("round.w.d%3s,%3s", fd.name(), fs.name());
1398   return writeInst(
1399       InstReg(op_cop1, rs_d, zero, fs, fd, ff_round_w_fmt).encode());
1400 }
1401 
as_truncwd(FloatRegister fd,FloatRegister fs)1402 BufferOffset AssemblerMIPSShared::as_truncwd(FloatRegister fd,
1403                                              FloatRegister fs) {
1404   spew("trunc.w.d%3s,%3s", fd.name(), fs.name());
1405   return writeInst(
1406       InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_w_fmt).encode());
1407 }
1408 
as_truncld(FloatRegister fd,FloatRegister fs)1409 BufferOffset AssemblerMIPSShared::as_truncld(FloatRegister fd,
1410                                              FloatRegister fs) {
1411   spew("trunc.l.d%3s,%3s", fd.name(), fs.name());
1412   MOZ_ASSERT(hasR2());
1413   return writeInst(
1414       InstReg(op_cop1, rs_d, zero, fs, fd, ff_trunc_l_fmt).encode());
1415 }
1416 
as_cvtdl(FloatRegister fd,FloatRegister fs)1417 BufferOffset AssemblerMIPSShared::as_cvtdl(FloatRegister fd, FloatRegister fs) {
1418   spew("cvt.d.l%3s,%3s", fd.name(), fs.name());
1419   MOZ_ASSERT(hasR2());
1420   return writeInst(InstReg(op_cop1, rs_l, zero, fs, fd, ff_cvt_d_fmt).encode());
1421 }
1422 
as_cvtds(FloatRegister fd,FloatRegister fs)1423 BufferOffset AssemblerMIPSShared::as_cvtds(FloatRegister fd, FloatRegister fs) {
1424   spew("cvt.d.s%3s,%3s", fd.name(), fs.name());
1425   return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_d_fmt).encode());
1426 }
1427 
as_cvtdw(FloatRegister fd,FloatRegister fs)1428 BufferOffset AssemblerMIPSShared::as_cvtdw(FloatRegister fd, FloatRegister fs) {
1429   spew("cvt.d.w%3s,%3s", fd.name(), fs.name());
1430   return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_d_fmt).encode());
1431 }
1432 
as_cvtsd(FloatRegister fd,FloatRegister fs)1433 BufferOffset AssemblerMIPSShared::as_cvtsd(FloatRegister fd, FloatRegister fs) {
1434   spew("cvt.s.d%3s,%3s", fd.name(), fs.name());
1435   return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_s_fmt).encode());
1436 }
1437 
as_cvtsl(FloatRegister fd,FloatRegister fs)1438 BufferOffset AssemblerMIPSShared::as_cvtsl(FloatRegister fd, FloatRegister fs) {
1439   spew("cvt.s.l%3s,%3s", fd.name(), fs.name());
1440   MOZ_ASSERT(hasR2());
1441   return writeInst(InstReg(op_cop1, rs_l, zero, fs, fd, ff_cvt_s_fmt).encode());
1442 }
1443 
as_cvtsw(FloatRegister fd,FloatRegister fs)1444 BufferOffset AssemblerMIPSShared::as_cvtsw(FloatRegister fd, FloatRegister fs) {
1445   spew("cvt.s.w%3s,%3s", fd.name(), fs.name());
1446   return writeInst(InstReg(op_cop1, rs_w, zero, fs, fd, ff_cvt_s_fmt).encode());
1447 }
1448 
as_cvtwd(FloatRegister fd,FloatRegister fs)1449 BufferOffset AssemblerMIPSShared::as_cvtwd(FloatRegister fd, FloatRegister fs) {
1450   spew("cvt.w.d%3s,%3s", fd.name(), fs.name());
1451   return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_cvt_w_fmt).encode());
1452 }
1453 
as_cvtws(FloatRegister fd,FloatRegister fs)1454 BufferOffset AssemblerMIPSShared::as_cvtws(FloatRegister fd, FloatRegister fs) {
1455   spew("cvt.w.s%3s,%3s", fd.name(), fs.name());
1456   return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_cvt_w_fmt).encode());
1457 }
1458 
1459 // FP arithmetic instructions
as_adds(FloatRegister fd,FloatRegister fs,FloatRegister ft)1460 BufferOffset AssemblerMIPSShared::as_adds(FloatRegister fd, FloatRegister fs,
1461                                           FloatRegister ft) {
1462   spew("add.s  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
1463   return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_add_fmt).encode());
1464 }
1465 
as_addd(FloatRegister fd,FloatRegister fs,FloatRegister ft)1466 BufferOffset AssemblerMIPSShared::as_addd(FloatRegister fd, FloatRegister fs,
1467                                           FloatRegister ft) {
1468   spew("add.d  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
1469   return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_add_fmt).encode());
1470 }
1471 
as_subs(FloatRegister fd,FloatRegister fs,FloatRegister ft)1472 BufferOffset AssemblerMIPSShared::as_subs(FloatRegister fd, FloatRegister fs,
1473                                           FloatRegister ft) {
1474   spew("sub.s  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
1475   return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_sub_fmt).encode());
1476 }
1477 
as_subd(FloatRegister fd,FloatRegister fs,FloatRegister ft)1478 BufferOffset AssemblerMIPSShared::as_subd(FloatRegister fd, FloatRegister fs,
1479                                           FloatRegister ft) {
1480   spew("sub.d  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
1481   return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_sub_fmt).encode());
1482 }
1483 
as_abss(FloatRegister fd,FloatRegister fs)1484 BufferOffset AssemblerMIPSShared::as_abss(FloatRegister fd, FloatRegister fs) {
1485   spew("abs.s  %3s,%3s", fd.name(), fs.name());
1486   return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_abs_fmt).encode());
1487 }
1488 
as_absd(FloatRegister fd,FloatRegister fs)1489 BufferOffset AssemblerMIPSShared::as_absd(FloatRegister fd, FloatRegister fs) {
1490   spew("abs.d  %3s,%3s", fd.name(), fs.name());
1491   return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_abs_fmt).encode());
1492 }
1493 
as_negs(FloatRegister fd,FloatRegister fs)1494 BufferOffset AssemblerMIPSShared::as_negs(FloatRegister fd, FloatRegister fs) {
1495   spew("neg.s  %3s,%3s", fd.name(), fs.name());
1496   return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_neg_fmt).encode());
1497 }
1498 
as_negd(FloatRegister fd,FloatRegister fs)1499 BufferOffset AssemblerMIPSShared::as_negd(FloatRegister fd, FloatRegister fs) {
1500   spew("neg.d  %3s,%3s", fd.name(), fs.name());
1501   return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_neg_fmt).encode());
1502 }
1503 
as_muls(FloatRegister fd,FloatRegister fs,FloatRegister ft)1504 BufferOffset AssemblerMIPSShared::as_muls(FloatRegister fd, FloatRegister fs,
1505                                           FloatRegister ft) {
1506   spew("mul.s  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
1507   return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_mul_fmt).encode());
1508 }
1509 
as_muld(FloatRegister fd,FloatRegister fs,FloatRegister ft)1510 BufferOffset AssemblerMIPSShared::as_muld(FloatRegister fd, FloatRegister fs,
1511                                           FloatRegister ft) {
1512   spew("mul.d  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
1513   return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_mul_fmt).encode());
1514 }
1515 
as_divs(FloatRegister fd,FloatRegister fs,FloatRegister ft)1516 BufferOffset AssemblerMIPSShared::as_divs(FloatRegister fd, FloatRegister fs,
1517                                           FloatRegister ft) {
1518   spew("div.s  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
1519   return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_div_fmt).encode());
1520 }
1521 
as_divd(FloatRegister fd,FloatRegister fs,FloatRegister ft)1522 BufferOffset AssemblerMIPSShared::as_divd(FloatRegister fd, FloatRegister fs,
1523                                           FloatRegister ft) {
1524   spew("divd.d  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
1525   return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_div_fmt).encode());
1526 }
1527 
as_sqrts(FloatRegister fd,FloatRegister fs)1528 BufferOffset AssemblerMIPSShared::as_sqrts(FloatRegister fd, FloatRegister fs) {
1529   spew("sqrts  %3s,%3s", fd.name(), fs.name());
1530   return writeInst(InstReg(op_cop1, rs_s, zero, fs, fd, ff_sqrt_fmt).encode());
1531 }
1532 
as_sqrtd(FloatRegister fd,FloatRegister fs)1533 BufferOffset AssemblerMIPSShared::as_sqrtd(FloatRegister fd, FloatRegister fs) {
1534   spew("sqrtd  %3s,%3s", fd.name(), fs.name());
1535   return writeInst(InstReg(op_cop1, rs_d, zero, fs, fd, ff_sqrt_fmt).encode());
1536 }
1537 
1538 // FP compare instructions
as_cf(FloatFormat fmt,FloatRegister fs,FloatRegister ft,FPConditionBit fcc)1539 BufferOffset AssemblerMIPSShared::as_cf(FloatFormat fmt, FloatRegister fs,
1540                                         FloatRegister ft, FPConditionBit fcc) {
1541   if (fmt == DoubleFloat) {
1542     spew("c.f.d  FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1543 #ifdef MIPSR6
1544     return writeInst(
1545         InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_f_fmt)
1546             .encode());
1547 #else
1548     return writeInst(
1549         InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_f_fmt).encode());
1550 #endif
1551   } else {
1552     spew("c.f.s  FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1553 #ifdef MIPSR6
1554     return writeInst(
1555         InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_f_fmt)
1556             .encode());
1557 #else
1558     return writeInst(
1559         InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_f_fmt).encode());
1560 #endif
1561   }
1562 }
1563 
as_cun(FloatFormat fmt,FloatRegister fs,FloatRegister ft,FPConditionBit fcc)1564 BufferOffset AssemblerMIPSShared::as_cun(FloatFormat fmt, FloatRegister fs,
1565                                          FloatRegister ft, FPConditionBit fcc) {
1566   if (fmt == DoubleFloat) {
1567     spew("c.un.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1568 #ifdef MIPSR6
1569     return writeInst(
1570         InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_un_fmt)
1571             .encode());
1572 #else
1573     return writeInst(
1574         InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_un_fmt).encode());
1575 #endif
1576   } else {
1577     spew("c.un.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1578 #ifdef MIPSR6
1579     return writeInst(
1580         InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_un_fmt)
1581             .encode());
1582 #else
1583     return writeInst(
1584         InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_un_fmt).encode());
1585 #endif
1586   }
1587 }
1588 
as_ceq(FloatFormat fmt,FloatRegister fs,FloatRegister ft,FPConditionBit fcc)1589 BufferOffset AssemblerMIPSShared::as_ceq(FloatFormat fmt, FloatRegister fs,
1590                                          FloatRegister ft, FPConditionBit fcc) {
1591   if (fmt == DoubleFloat) {
1592     spew("c.eq.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1593 #ifdef MIPSR6
1594     return writeInst(
1595         InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_eq_fmt)
1596             .encode());
1597 #else
1598     return writeInst(
1599         InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_eq_fmt).encode());
1600 #endif
1601   } else {
1602     spew("c.eq.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1603 #ifdef MIPSR6
1604     return writeInst(
1605         InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_eq_fmt)
1606             .encode());
1607 #else
1608     return writeInst(
1609         InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_eq_fmt).encode());
1610 #endif
1611   }
1612 }
1613 
as_cueq(FloatFormat fmt,FloatRegister fs,FloatRegister ft,FPConditionBit fcc)1614 BufferOffset AssemblerMIPSShared::as_cueq(FloatFormat fmt, FloatRegister fs,
1615                                           FloatRegister ft,
1616                                           FPConditionBit fcc) {
1617   if (fmt == DoubleFloat) {
1618     spew("c.ueq.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1619 #ifdef MIPSR6
1620     return writeInst(
1621         InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_ueq_fmt)
1622             .encode());
1623 #else
1624     return writeInst(
1625         InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_ueq_fmt).encode());
1626 #endif
1627   } else {
1628     spew("c.ueq.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1629 #ifdef MIPSR6
1630     return writeInst(
1631         InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_ueq_fmt)
1632             .encode());
1633 #else
1634     return writeInst(
1635         InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_ueq_fmt).encode());
1636 #endif
1637   }
1638 }
1639 
as_colt(FloatFormat fmt,FloatRegister fs,FloatRegister ft,FPConditionBit fcc)1640 BufferOffset AssemblerMIPSShared::as_colt(FloatFormat fmt, FloatRegister fs,
1641                                           FloatRegister ft,
1642                                           FPConditionBit fcc) {
1643   if (fmt == DoubleFloat) {
1644     spew("c.olt.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1645 #ifdef MIPSR6
1646     return writeInst(
1647         InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_olt_fmt)
1648             .encode());
1649 #else
1650     return writeInst(
1651         InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_olt_fmt).encode());
1652 #endif
1653   } else {
1654     spew("c.olt.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1655 #ifdef MIPSR6
1656     return writeInst(
1657         InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_olt_fmt)
1658             .encode());
1659 #else
1660     return writeInst(
1661         InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_olt_fmt).encode());
1662 #endif
1663   }
1664 }
1665 
as_cult(FloatFormat fmt,FloatRegister fs,FloatRegister ft,FPConditionBit fcc)1666 BufferOffset AssemblerMIPSShared::as_cult(FloatFormat fmt, FloatRegister fs,
1667                                           FloatRegister ft,
1668                                           FPConditionBit fcc) {
1669   if (fmt == DoubleFloat) {
1670     spew("c.ult.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1671 #ifdef MIPSR6
1672     return writeInst(
1673         InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_ult_fmt)
1674             .encode());
1675 #else
1676     return writeInst(
1677         InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_ult_fmt).encode());
1678 #endif
1679   } else {
1680     spew("c.ult.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1681 #ifdef MIPSR6
1682     return writeInst(
1683         InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_ult_fmt)
1684             .encode());
1685 #else
1686     return writeInst(
1687         InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_ult_fmt).encode());
1688 #endif
1689   }
1690 }
1691 
as_cole(FloatFormat fmt,FloatRegister fs,FloatRegister ft,FPConditionBit fcc)1692 BufferOffset AssemblerMIPSShared::as_cole(FloatFormat fmt, FloatRegister fs,
1693                                           FloatRegister ft,
1694                                           FPConditionBit fcc) {
1695   if (fmt == DoubleFloat) {
1696     spew("c.ole.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1697 #ifdef MIPSR6
1698     return writeInst(
1699         InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_ole_fmt)
1700             .encode());
1701 #else
1702     return writeInst(
1703         InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_ole_fmt).encode());
1704 #endif
1705   } else {
1706     spew("c.ole.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1707 #ifdef MIPSR6
1708     return writeInst(
1709         InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_ole_fmt)
1710             .encode());
1711 #else
1712     return writeInst(
1713         InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_ole_fmt).encode());
1714 #endif
1715   }
1716 }
1717 
as_cule(FloatFormat fmt,FloatRegister fs,FloatRegister ft,FPConditionBit fcc)1718 BufferOffset AssemblerMIPSShared::as_cule(FloatFormat fmt, FloatRegister fs,
1719                                           FloatRegister ft,
1720                                           FPConditionBit fcc) {
1721   if (fmt == DoubleFloat) {
1722     spew("c.ule.d FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1723 #ifdef MIPSR6
1724     return writeInst(
1725         InstReg(op_cop1, rs_d_r6, ft, fs, FloatRegisters::f24, ff_c_ule_fmt)
1726             .encode());
1727 #else
1728     return writeInst(
1729         InstReg(op_cop1, rs_d, ft, fs, fcc << FccShift, ff_c_ule_fmt).encode());
1730 #endif
1731   } else {
1732     spew("c.ule.s FCC%d,%3s,%3s", fcc, fs.name(), ft.name());
1733 #ifdef MIPSR6
1734     return writeInst(
1735         InstReg(op_cop1, rs_s_r6, ft, fs, FloatRegisters::f24, ff_c_ule_fmt)
1736             .encode());
1737 #else
1738     return writeInst(
1739         InstReg(op_cop1, rs_s, ft, fs, fcc << FccShift, ff_c_ule_fmt).encode());
1740 #endif
1741   }
1742 }
1743 
1744 // FP conditional move.
as_movt(FloatFormat fmt,FloatRegister fd,FloatRegister fs,FPConditionBit fcc)1745 BufferOffset AssemblerMIPSShared::as_movt(FloatFormat fmt, FloatRegister fd,
1746                                           FloatRegister fs,
1747                                           FPConditionBit fcc) {
1748   Register rt = Register::FromCode(fcc << 2 | 1);
1749   if (fmt == DoubleFloat) {
1750     spew("movt.d FCC%d,%3s,%3s", fcc, fd.name(), fs.name());
1751     return writeInst(InstReg(op_cop1, rs_d, rt, fs, fd, ff_movf_fmt).encode());
1752   } else {
1753     spew("movt.s FCC%d,%3s,%3s", fcc, fd.name(), fs.name());
1754     return writeInst(InstReg(op_cop1, rs_s, rt, fs, fd, ff_movf_fmt).encode());
1755   }
1756 }
1757 
as_movf(FloatFormat fmt,FloatRegister fd,FloatRegister fs,FPConditionBit fcc)1758 BufferOffset AssemblerMIPSShared::as_movf(FloatFormat fmt, FloatRegister fd,
1759                                           FloatRegister fs,
1760                                           FPConditionBit fcc) {
1761   Register rt = Register::FromCode(fcc << 2 | 0);
1762   if (fmt == DoubleFloat) {
1763     spew("movf.d FCC%d,%3s,%3s", fcc, fd.name(), fs.name());
1764     return writeInst(InstReg(op_cop1, rs_d, rt, fs, fd, ff_movf_fmt).encode());
1765   } else {
1766     spew("movf.s FCC%d,%3s,%3s", fcc, fd.name(), fs.name());
1767     return writeInst(InstReg(op_cop1, rs_s, rt, fs, fd, ff_movf_fmt).encode());
1768   }
1769 }
1770 
as_movz(FloatFormat fmt,FloatRegister fd,FloatRegister fs,Register rt)1771 BufferOffset AssemblerMIPSShared::as_movz(FloatFormat fmt, FloatRegister fd,
1772                                           FloatRegister fs, Register rt) {
1773   if (fmt == DoubleFloat) {
1774     spew("movz.d %3s,%3s,%3s", fd.name(), fs.name(), rt.name());
1775     return writeInst(InstReg(op_cop1, rs_d, rt, fs, fd, ff_movz_fmt).encode());
1776   } else {
1777     spew("movz.s %3s,%3s,%3s", fd.name(), fs.name(), rt.name());
1778     return writeInst(InstReg(op_cop1, rs_s, rt, fs, fd, ff_movz_fmt).encode());
1779   }
1780 }
1781 
as_movn(FloatFormat fmt,FloatRegister fd,FloatRegister fs,Register rt)1782 BufferOffset AssemblerMIPSShared::as_movn(FloatFormat fmt, FloatRegister fd,
1783                                           FloatRegister fs, Register rt) {
1784   if (fmt == DoubleFloat) {
1785     spew("movn.d %3s,%3s,%3s", fd.name(), fs.name(), rt.name());
1786     return writeInst(InstReg(op_cop1, rs_d, rt, fs, fd, ff_movn_fmt).encode());
1787   } else {
1788     spew("movn.s %3s,%3s,%3s", fd.name(), fs.name(), rt.name());
1789     return writeInst(InstReg(op_cop1, rs_s, rt, fs, fd, ff_movn_fmt).encode());
1790   }
1791 }
1792 
as_max(FloatFormat fmt,FloatRegister fd,FloatRegister fs,FloatRegister ft)1793 BufferOffset AssemblerMIPSShared::as_max(FloatFormat fmt, FloatRegister fd,
1794                                          FloatRegister fs, FloatRegister ft) {
1795   if (fmt == DoubleFloat) {
1796     spew("max  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
1797     return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_max).encode());
1798   } else {
1799     spew("max  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
1800     return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_max).encode());
1801   }
1802 }
1803 
as_min(FloatFormat fmt,FloatRegister fd,FloatRegister fs,FloatRegister ft)1804 BufferOffset AssemblerMIPSShared::as_min(FloatFormat fmt, FloatRegister fd,
1805                                          FloatRegister fs, FloatRegister ft) {
1806   if (fmt == DoubleFloat) {
1807     spew("min  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
1808     return writeInst(InstReg(op_cop1, rs_d, ft, fs, fd, ff_min).encode());
1809   } else {
1810     spew("min  %3s,%3s,%3s", fd.name(), fs.name(), ft.name());
1811     return writeInst(InstReg(op_cop1, rs_s, ft, fs, fd, ff_min).encode());
1812   }
1813 }
1814 
as_tge(Register rs,Register rt,uint32_t code)1815 BufferOffset AssemblerMIPSShared::as_tge(Register rs, Register rt,
1816                                          uint32_t code) {
1817   MOZ_ASSERT(code <= MAX_BREAK_CODE);
1818   spew("tge %3s,%3s,%d", rs.name(), rt.name(), code);
1819   return writeInst(InstReg(op_special, rs, rt, zero, code, ff_tge).encode());
1820 }
1821 
as_tgeu(Register rs,Register rt,uint32_t code)1822 BufferOffset AssemblerMIPSShared::as_tgeu(Register rs, Register rt,
1823                                           uint32_t code) {
1824   MOZ_ASSERT(code <= MAX_BREAK_CODE);
1825   spew("tgeu %3s,%3s,%d", rs.name(), rt.name(), code);
1826   return writeInst(InstReg(op_special, rs, rt, zero, code, ff_tgeu).encode());
1827 }
1828 
as_tlt(Register rs,Register rt,uint32_t code)1829 BufferOffset AssemblerMIPSShared::as_tlt(Register rs, Register rt,
1830                                          uint32_t code) {
1831   MOZ_ASSERT(code <= MAX_BREAK_CODE);
1832   spew("tlt %3s,%3s,%d", rs.name(), rt.name(), code);
1833   return writeInst(InstReg(op_special, rs, rt, zero, code, ff_tlt).encode());
1834 }
1835 
as_tltu(Register rs,Register rt,uint32_t code)1836 BufferOffset AssemblerMIPSShared::as_tltu(Register rs, Register rt,
1837                                           uint32_t code) {
1838   MOZ_ASSERT(code <= MAX_BREAK_CODE);
1839   spew("tltu %3s,%3s,%d", rs.name(), rt.name(), code);
1840   return writeInst(InstReg(op_special, rs, rt, zero, code, ff_tltu).encode());
1841 }
1842 
as_teq(Register rs,Register rt,uint32_t code)1843 BufferOffset AssemblerMIPSShared::as_teq(Register rs, Register rt,
1844                                          uint32_t code) {
1845   MOZ_ASSERT(code <= MAX_BREAK_CODE);
1846   spew("teq %3s,%3s,%d", rs.name(), rt.name(), code);
1847   return writeInst(InstReg(op_special, rs, rt, zero, code, ff_teq).encode());
1848 }
1849 
as_tne(Register rs,Register rt,uint32_t code)1850 BufferOffset AssemblerMIPSShared::as_tne(Register rs, Register rt,
1851                                          uint32_t code) {
1852   MOZ_ASSERT(code <= MAX_BREAK_CODE);
1853   spew("tne %3s,%3s,%d", rs.name(), rt.name(), code);
1854   return writeInst(InstReg(op_special, rs, rt, zero, code, ff_tne).encode());
1855 }
1856 
bind(Label * label,BufferOffset boff)1857 void AssemblerMIPSShared::bind(Label* label, BufferOffset boff) {
1858   spew(".set Llabel %p", label);
1859   // If our caller didn't give us an explicit target to bind to
1860   // then we want to bind to the location of the next instruction
1861   BufferOffset dest = boff.assigned() ? boff : nextOffset();
1862   if (label->used()) {
1863     int32_t next;
1864 
1865     // A used label holds a link to branch that uses it.
1866     BufferOffset b(label);
1867     do {
1868       // Even a 0 offset may be invalid if we're out of memory.
1869       if (oom()) {
1870         return;
1871       }
1872 
1873       Instruction* inst = editSrc(b);
1874 
1875       // Second word holds a pointer to the next branch in label's chain.
1876       next = inst[1].encode();
1877       bind(reinterpret_cast<InstImm*>(inst), b.getOffset(), dest.getOffset());
1878 
1879       b = BufferOffset(next);
1880     } while (next != LabelBase::INVALID_OFFSET);
1881   }
1882   label->bind(dest.getOffset());
1883 }
1884 
retarget(Label * label,Label * target)1885 void AssemblerMIPSShared::retarget(Label* label, Label* target) {
1886   spew("retarget %p -> %p", label, target);
1887   if (label->used() && !oom()) {
1888     if (target->bound()) {
1889       bind(label, BufferOffset(target));
1890     } else if (target->used()) {
1891       // The target is not bound but used. Prepend label's branch list
1892       // onto target's.
1893       int32_t next;
1894       BufferOffset labelBranchOffset(label);
1895 
1896       // Find the head of the use chain for label.
1897       do {
1898         Instruction* inst = editSrc(labelBranchOffset);
1899 
1900         // Second word holds a pointer to the next branch in chain.
1901         next = inst[1].encode();
1902         labelBranchOffset = BufferOffset(next);
1903       } while (next != LabelBase::INVALID_OFFSET);
1904 
1905       // Then patch the head of label's use chain to the tail of
1906       // target's use chain, prepending the entire use chain of target.
1907       Instruction* inst = editSrc(labelBranchOffset);
1908       int32_t prev = target->offset();
1909       target->use(label->offset());
1910       inst[1].setData(prev);
1911     } else {
1912       // The target is unbound and unused.  We can just take the head of
1913       // the list hanging off of label, and dump that into target.
1914       target->use(label->offset());
1915     }
1916   }
1917   label->reset();
1918 }
1919 
dbg_break()1920 void dbg_break() {}
as_break(uint32_t code)1921 void AssemblerMIPSShared::as_break(uint32_t code) {
1922   MOZ_ASSERT(code <= MAX_BREAK_CODE);
1923   spew("break %d", code);
1924   writeInst(op_special | code << FunctionBits | ff_break);
1925 }
1926 
as_sync(uint32_t stype)1927 void AssemblerMIPSShared::as_sync(uint32_t stype) {
1928   MOZ_ASSERT(stype <= 31);
1929   spew("sync %d", stype);
1930   writeInst(InstReg(op_special, zero, zero, zero, stype, ff_sync).encode());
1931 }
1932 
1933 // This just stomps over memory with 32 bits of raw data. Its purpose is to
1934 // overwrite the call of JITed code with 32 bits worth of an offset. This will
1935 // is only meant to function on code that has been invalidated, so it should
1936 // be totally safe. Since that instruction will never be executed again, a
1937 // ICache flush should not be necessary
PatchWrite_Imm32(CodeLocationLabel label,Imm32 imm)1938 void AssemblerMIPSShared::PatchWrite_Imm32(CodeLocationLabel label, Imm32 imm) {
1939   // Raw is going to be the return address.
1940   uint32_t* raw = (uint32_t*)label.raw();
1941   // Overwrite the 4 bytes before the return address, which will
1942   // end up being the call instruction.
1943   *(raw - 1) = imm.value;
1944 }
1945 
NextInstruction(uint8_t * inst_,uint32_t * count)1946 uint8_t* AssemblerMIPSShared::NextInstruction(uint8_t* inst_, uint32_t* count) {
1947   Instruction* inst = reinterpret_cast<Instruction*>(inst_);
1948   if (count != nullptr) {
1949     *count += sizeof(Instruction);
1950   }
1951   return reinterpret_cast<uint8_t*>(inst->next());
1952 }
1953 
1954 // Since there are no pools in MIPS implementation, this should be simple.
next()1955 Instruction* Instruction::next() { return this + 1; }
1956 
invertBranch(InstImm branch,BOffImm16 skipOffset)1957 InstImm AssemblerMIPSShared::invertBranch(InstImm branch,
1958                                           BOffImm16 skipOffset) {
1959   uint32_t rt = 0;
1960   OpcodeField op = (OpcodeField)(branch.extractOpcode() << OpcodeShift);
1961   switch (op) {
1962     case op_beq:
1963       branch.setBOffImm16(skipOffset);
1964       branch.setOpcode(op_bne);
1965       return branch;
1966     case op_bne:
1967       branch.setBOffImm16(skipOffset);
1968       branch.setOpcode(op_beq);
1969       return branch;
1970     case op_bgtz:
1971       branch.setBOffImm16(skipOffset);
1972       branch.setOpcode(op_blez);
1973       return branch;
1974     case op_blez:
1975       branch.setBOffImm16(skipOffset);
1976       branch.setOpcode(op_bgtz);
1977       return branch;
1978     case op_regimm:
1979       branch.setBOffImm16(skipOffset);
1980       rt = branch.extractRT();
1981       if (rt == (rt_bltz >> RTShift)) {
1982         branch.setRT(rt_bgez);
1983         return branch;
1984       }
1985       if (rt == (rt_bgez >> RTShift)) {
1986         branch.setRT(rt_bltz);
1987         return branch;
1988       }
1989 
1990       MOZ_CRASH("Error creating long branch.");
1991 
1992     case op_cop1:
1993       MOZ_ASSERT(branch.extractRS() == rs_bc1 >> RSShift);
1994 
1995       branch.setBOffImm16(skipOffset);
1996       rt = branch.extractRT();
1997       if (rt & 0x1) {
1998         branch.setRT((RTField)((rt & ~0x1) << RTShift));
1999       } else {
2000         branch.setRT((RTField)((rt | 0x1) << RTShift));
2001       }
2002       return branch;
2003     default:
2004       MOZ_CRASH("Error creating long branch.");
2005   }
2006 }
2007 
ToggleToJmp(CodeLocationLabel inst_)2008 void AssemblerMIPSShared::ToggleToJmp(CodeLocationLabel inst_) {
2009   InstImm* inst = (InstImm*)inst_.raw();
2010 
2011   MOZ_ASSERT(inst->extractOpcode() == ((uint32_t)op_andi >> OpcodeShift));
2012   // We converted beq to andi, so now we restore it.
2013   inst->setOpcode(op_beq);
2014 }
2015 
ToggleToCmp(CodeLocationLabel inst_)2016 void AssemblerMIPSShared::ToggleToCmp(CodeLocationLabel inst_) {
2017   InstImm* inst = (InstImm*)inst_.raw();
2018 
2019   // toggledJump is allways used for short jumps.
2020   MOZ_ASSERT(inst->extractOpcode() == ((uint32_t)op_beq >> OpcodeShift));
2021   // Replace "beq $zero, $zero, offset" with "andi $zero, $zero, offset"
2022   inst->setOpcode(op_andi);
2023 }
2024 
UpdateLuiOriValue(Instruction * inst0,Instruction * inst1,uint32_t value)2025 void AssemblerMIPSShared::UpdateLuiOriValue(Instruction* inst0,
2026                                             Instruction* inst1,
2027                                             uint32_t value) {
2028   MOZ_ASSERT(inst0->extractOpcode() == ((uint32_t)op_lui >> OpcodeShift));
2029   MOZ_ASSERT(inst1->extractOpcode() == ((uint32_t)op_ori >> OpcodeShift));
2030 
2031   ((InstImm*)inst0)->setImm16(Imm16::Upper(Imm32(value)));
2032   ((InstImm*)inst1)->setImm16(Imm16::Lower(Imm32(value)));
2033 }
2034 
2035 #ifdef JS_JITSPEW
decodeBranchInstAndSpew(InstImm branch)2036 void AssemblerMIPSShared::decodeBranchInstAndSpew(InstImm branch) {
2037   OpcodeField op = (OpcodeField)(branch.extractOpcode() << OpcodeShift);
2038   uint32_t rt_id;
2039   uint32_t rs_id;
2040   uint32_t immi = branch.extractImm16Value();
2041   uint32_t fcc;
2042   switch (op) {
2043     case op_beq:
2044       rt_id = branch.extractRT();
2045       rs_id = branch.extractRS();
2046       spew("beq    %3s,%3s,0x%x", Registers::GetName(rs_id),
2047            Registers::GetName(rt_id), (int32_t(immi << 18) >> 16) + 4);
2048       break;
2049     case op_bne:
2050       rt_id = branch.extractRT();
2051       rs_id = branch.extractRS();
2052       spew("bne    %3s,%3s,0x%x", Registers::GetName(rs_id),
2053            Registers::GetName(rt_id), (int32_t(immi << 18) >> 16) + 4);
2054       break;
2055     case op_bgtz:
2056       rs_id = branch.extractRS();
2057       spew("bgt    %3s,  0,0x%x", Registers::GetName(rs_id),
2058            (int32_t(immi << 18) >> 16) + 4);
2059       break;
2060     case op_blez:
2061       rs_id = branch.extractRS();
2062       spew("ble    %3s,  0,0x%x", Registers::GetName(rs_id),
2063            (int32_t(immi << 18) >> 16) + 4);
2064       break;
2065     case op_regimm:
2066       rt_id = branch.extractRT();
2067       if (rt_id == (rt_bltz >> RTShift)) {
2068         rs_id = branch.extractRS();
2069         spew("blt   %3s,  0,0x%x", Registers::GetName(rs_id),
2070              (int32_t(immi << 18) >> 16) + 4);
2071       } else if (rt_id == (rt_bgez >> RTShift)) {
2072         rs_id = branch.extractRS();
2073         spew("bge   %3s,  0,0x%x", Registers::GetName(rs_id),
2074              (int32_t(immi << 18) >> 16) + 4);
2075       } else {
2076         MOZ_CRASH("Error disassemble branch.");
2077       }
2078       break;
2079     case op_cop1:
2080       MOZ_ASSERT(branch.extractRS() == rs_bc1 >> RSShift);
2081       rt_id = branch.extractRT();
2082       fcc = branch.extractBitField(FCccShift + FCccBits - 1, FCccShift);
2083       if (rt_id & 0x1) {
2084         spew("bc1t  FCC%d, 0x%x", fcc, (int32_t(immi << 18) >> 16) + 4);
2085       } else {
2086         spew("bc1f  FCC%d, 0x%x", fcc, (int32_t(immi << 18) >> 16) + 4);
2087       }
2088       break;
2089     default:
2090       MOZ_CRASH("Error disassemble branch.");
2091   }
2092 }
2093 #endif
2094