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