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