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