1 // Copyright (c) 1994-2006 Sun Microsystems Inc.
2 // All Rights Reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // - Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // - Redistribution in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 //
15 // - Neither the name of Sun Microsystems or the names of contributors may
16 // be used to endorse or promote products derived from this software without
17 // specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31 // The original source code covered by the above license above has been
32 // modified significantly by Google Inc.
33 // Copyright 2012 the V8 project authors. All rights reserved.
34
35 #include "src/mips64/assembler-mips64.h"
36
37 #if V8_TARGET_ARCH_MIPS64
38
39 #include "src/base/cpu.h"
40 #include "src/mips64/assembler-mips64-inl.h"
41
42 namespace v8 {
43 namespace internal {
44
45
46 // Get the CPU features enabled by the build. For cross compilation the
47 // preprocessor symbols CAN_USE_FPU_INSTRUCTIONS
48 // can be defined to enable FPU instructions when building the
49 // snapshot.
CpuFeaturesImpliedByCompiler()50 static unsigned CpuFeaturesImpliedByCompiler() {
51 unsigned answer = 0;
52 #ifdef CAN_USE_FPU_INSTRUCTIONS
53 answer |= 1u << FPU;
54 #endif // def CAN_USE_FPU_INSTRUCTIONS
55
56 // If the compiler is allowed to use FPU then we can use FPU too in our code
57 // generation even when generating snapshots. This won't work for cross
58 // compilation.
59 #if defined(__mips__) && defined(__mips_hard_float) && __mips_hard_float != 0
60 answer |= 1u << FPU;
61 #endif
62
63 return answer;
64 }
65
66
ProbeImpl(bool cross_compile)67 void CpuFeatures::ProbeImpl(bool cross_compile) {
68 supported_ |= CpuFeaturesImpliedByCompiler();
69
70 // Only use statically determined features for cross compile (snapshot).
71 if (cross_compile) return;
72
73 // If the compiler is allowed to use fpu then we can use fpu too in our
74 // code generation.
75 #ifndef __mips__
76 // For the simulator build, use FPU.
77 supported_ |= 1u << FPU;
78 #else
79 // Probe for additional features at runtime.
80 base::CPU cpu;
81 if (cpu.has_fpu()) supported_ |= 1u << FPU;
82 #endif
83 }
84
85
PrintTarget()86 void CpuFeatures::PrintTarget() { }
PrintFeatures()87 void CpuFeatures::PrintFeatures() { }
88
89
ToNumber(Register reg)90 int ToNumber(Register reg) {
91 DCHECK(reg.is_valid());
92 const int kNumbers[] = {
93 0, // zero_reg
94 1, // at
95 2, // v0
96 3, // v1
97 4, // a0
98 5, // a1
99 6, // a2
100 7, // a3
101 8, // a4
102 9, // a5
103 10, // a6
104 11, // a7
105 12, // t0
106 13, // t1
107 14, // t2
108 15, // t3
109 16, // s0
110 17, // s1
111 18, // s2
112 19, // s3
113 20, // s4
114 21, // s5
115 22, // s6
116 23, // s7
117 24, // t8
118 25, // t9
119 26, // k0
120 27, // k1
121 28, // gp
122 29, // sp
123 30, // fp
124 31, // ra
125 };
126 return kNumbers[reg.code()];
127 }
128
129
ToRegister(int num)130 Register ToRegister(int num) {
131 DCHECK(num >= 0 && num < kNumRegisters);
132 const Register kRegisters[] = {
133 zero_reg,
134 at,
135 v0, v1,
136 a0, a1, a2, a3, a4, a5, a6, a7,
137 t0, t1, t2, t3,
138 s0, s1, s2, s3, s4, s5, s6, s7,
139 t8, t9,
140 k0, k1,
141 gp,
142 sp,
143 fp,
144 ra
145 };
146 return kRegisters[num];
147 }
148
149
150 // -----------------------------------------------------------------------------
151 // Implementation of RelocInfo.
152
153 const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
154 1 << RelocInfo::INTERNAL_REFERENCE |
155 1 << RelocInfo::INTERNAL_REFERENCE_ENCODED;
156
157
IsCodedSpecially()158 bool RelocInfo::IsCodedSpecially() {
159 // The deserializer needs to know whether a pointer is specially coded. Being
160 // specially coded on MIPS means that it is a lui/ori instruction, and that is
161 // always the case inside code objects.
162 return true;
163 }
164
165
IsInConstantPool()166 bool RelocInfo::IsInConstantPool() {
167 return false;
168 }
169
wasm_memory_reference()170 Address RelocInfo::wasm_memory_reference() {
171 DCHECK(IsWasmMemoryReference(rmode_));
172 return Assembler::target_address_at(pc_, host_);
173 }
174
wasm_global_reference()175 Address RelocInfo::wasm_global_reference() {
176 DCHECK(IsWasmGlobalReference(rmode_));
177 return Assembler::target_address_at(pc_, host_);
178 }
179
wasm_memory_size_reference()180 uint32_t RelocInfo::wasm_memory_size_reference() {
181 DCHECK(IsWasmMemorySizeReference(rmode_));
182 return static_cast<uint32_t>(
183 reinterpret_cast<intptr_t>((Assembler::target_address_at(pc_, host_))));
184 }
185
wasm_function_table_size_reference()186 uint32_t RelocInfo::wasm_function_table_size_reference() {
187 DCHECK(IsWasmFunctionTableSizeReference(rmode_));
188 return static_cast<uint32_t>(
189 reinterpret_cast<intptr_t>((Assembler::target_address_at(pc_, host_))));
190 }
191
unchecked_update_wasm_memory_reference(Address address,ICacheFlushMode flush_mode)192 void RelocInfo::unchecked_update_wasm_memory_reference(
193 Address address, ICacheFlushMode flush_mode) {
194 Assembler::set_target_address_at(isolate_, pc_, host_, address, flush_mode);
195 }
196
unchecked_update_wasm_size(uint32_t size,ICacheFlushMode flush_mode)197 void RelocInfo::unchecked_update_wasm_size(uint32_t size,
198 ICacheFlushMode flush_mode) {
199 Assembler::set_target_address_at(isolate_, pc_, host_,
200 reinterpret_cast<Address>(size), flush_mode);
201 }
202
203 // -----------------------------------------------------------------------------
204 // Implementation of Operand and MemOperand.
205 // See assembler-mips-inl.h for inlined constructors.
206
Operand(Handle<Object> handle)207 Operand::Operand(Handle<Object> handle) {
208 AllowDeferredHandleDereference using_raw_address;
209 rm_ = no_reg;
210 // Verify all Objects referred by code are NOT in new space.
211 Object* obj = *handle;
212 if (obj->IsHeapObject()) {
213 imm64_ = reinterpret_cast<intptr_t>(handle.location());
214 rmode_ = RelocInfo::EMBEDDED_OBJECT;
215 } else {
216 // No relocation needed.
217 imm64_ = reinterpret_cast<intptr_t>(obj);
218 rmode_ = RelocInfo::NONE64;
219 }
220 }
221
222
MemOperand(Register rm,int32_t offset)223 MemOperand::MemOperand(Register rm, int32_t offset) : Operand(rm) {
224 offset_ = offset;
225 }
226
227
MemOperand(Register rm,int32_t unit,int32_t multiplier,OffsetAddend offset_addend)228 MemOperand::MemOperand(Register rm, int32_t unit, int32_t multiplier,
229 OffsetAddend offset_addend)
230 : Operand(rm) {
231 offset_ = unit * multiplier + offset_addend;
232 }
233
234
235 // -----------------------------------------------------------------------------
236 // Specific instructions, constants, and masks.
237
238 static const int kNegOffset = 0x00008000;
239 // daddiu(sp, sp, 8) aka Pop() operation or part of Pop(r)
240 // operations as post-increment of sp.
241 const Instr kPopInstruction = DADDIU | (Register::kCode_sp << kRsShift) |
242 (Register::kCode_sp << kRtShift) |
243 (kPointerSize & kImm16Mask); // NOLINT
244 // daddiu(sp, sp, -8) part of Push(r) operation as pre-decrement of sp.
245 const Instr kPushInstruction = DADDIU | (Register::kCode_sp << kRsShift) |
246 (Register::kCode_sp << kRtShift) |
247 (-kPointerSize & kImm16Mask); // NOLINT
248 // sd(r, MemOperand(sp, 0))
249 const Instr kPushRegPattern =
250 SD | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
251 // ld(r, MemOperand(sp, 0))
252 const Instr kPopRegPattern =
253 LD | (Register::kCode_sp << kRsShift) | (0 & kImm16Mask); // NOLINT
254
255 const Instr kLwRegFpOffsetPattern =
256 LW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
257
258 const Instr kSwRegFpOffsetPattern =
259 SW | (Register::kCode_fp << kRsShift) | (0 & kImm16Mask); // NOLINT
260
261 const Instr kLwRegFpNegOffsetPattern = LW | (Register::kCode_fp << kRsShift) |
262 (kNegOffset & kImm16Mask); // NOLINT
263
264 const Instr kSwRegFpNegOffsetPattern = SW | (Register::kCode_fp << kRsShift) |
265 (kNegOffset & kImm16Mask); // NOLINT
266 // A mask for the Rt register for push, pop, lw, sw instructions.
267 const Instr kRtMask = kRtFieldMask;
268 const Instr kLwSwInstrTypeMask = 0xffe00000;
269 const Instr kLwSwInstrArgumentMask = ~kLwSwInstrTypeMask;
270 const Instr kLwSwOffsetMask = kImm16Mask;
271
Assembler(Isolate * isolate,void * buffer,int buffer_size)272 Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
273 : AssemblerBase(isolate, buffer, buffer_size),
274 recorded_ast_id_(TypeFeedbackId::None()) {
275 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
276
277 last_trampoline_pool_end_ = 0;
278 no_trampoline_pool_before_ = 0;
279 trampoline_pool_blocked_nesting_ = 0;
280 // We leave space (16 * kTrampolineSlotsSize)
281 // for BlockTrampolinePoolScope buffer.
282 next_buffer_check_ = FLAG_force_long_branches
283 ? kMaxInt : kMaxBranchOffset - kTrampolineSlotsSize * 16;
284 internal_trampoline_exception_ = false;
285 last_bound_pos_ = 0;
286
287 trampoline_emitted_ = FLAG_force_long_branches;
288 unbound_labels_count_ = 0;
289 block_buffer_growth_ = false;
290
291 ClearRecordedAstId();
292 }
293
294
GetCode(CodeDesc * desc)295 void Assembler::GetCode(CodeDesc* desc) {
296 EmitForbiddenSlotInstruction();
297 DCHECK(pc_ <= reloc_info_writer.pos()); // No overlap.
298 // Set up code descriptor.
299 desc->buffer = buffer_;
300 desc->buffer_size = buffer_size_;
301 desc->instr_size = pc_offset();
302 desc->reloc_size =
303 static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer.pos());
304 desc->origin = this;
305 desc->constant_pool_size = 0;
306 desc->unwinding_info_size = 0;
307 desc->unwinding_info = nullptr;
308 }
309
310
Align(int m)311 void Assembler::Align(int m) {
312 DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
313 EmitForbiddenSlotInstruction();
314 while ((pc_offset() & (m - 1)) != 0) {
315 nop();
316 }
317 }
318
319
CodeTargetAlign()320 void Assembler::CodeTargetAlign() {
321 // No advantage to aligning branch/call targets to more than
322 // single instruction, that I am aware of.
323 Align(4);
324 }
325
326
GetRtReg(Instr instr)327 Register Assembler::GetRtReg(Instr instr) {
328 Register rt;
329 rt.reg_code = (instr & kRtFieldMask) >> kRtShift;
330 return rt;
331 }
332
333
GetRsReg(Instr instr)334 Register Assembler::GetRsReg(Instr instr) {
335 Register rs;
336 rs.reg_code = (instr & kRsFieldMask) >> kRsShift;
337 return rs;
338 }
339
340
GetRdReg(Instr instr)341 Register Assembler::GetRdReg(Instr instr) {
342 Register rd;
343 rd.reg_code = (instr & kRdFieldMask) >> kRdShift;
344 return rd;
345 }
346
347
GetRt(Instr instr)348 uint32_t Assembler::GetRt(Instr instr) {
349 return (instr & kRtFieldMask) >> kRtShift;
350 }
351
352
GetRtField(Instr instr)353 uint32_t Assembler::GetRtField(Instr instr) {
354 return instr & kRtFieldMask;
355 }
356
357
GetRs(Instr instr)358 uint32_t Assembler::GetRs(Instr instr) {
359 return (instr & kRsFieldMask) >> kRsShift;
360 }
361
362
GetRsField(Instr instr)363 uint32_t Assembler::GetRsField(Instr instr) {
364 return instr & kRsFieldMask;
365 }
366
367
GetRd(Instr instr)368 uint32_t Assembler::GetRd(Instr instr) {
369 return (instr & kRdFieldMask) >> kRdShift;
370 }
371
372
GetRdField(Instr instr)373 uint32_t Assembler::GetRdField(Instr instr) {
374 return instr & kRdFieldMask;
375 }
376
377
GetSa(Instr instr)378 uint32_t Assembler::GetSa(Instr instr) {
379 return (instr & kSaFieldMask) >> kSaShift;
380 }
381
382
GetSaField(Instr instr)383 uint32_t Assembler::GetSaField(Instr instr) {
384 return instr & kSaFieldMask;
385 }
386
387
GetOpcodeField(Instr instr)388 uint32_t Assembler::GetOpcodeField(Instr instr) {
389 return instr & kOpcodeMask;
390 }
391
392
GetFunction(Instr instr)393 uint32_t Assembler::GetFunction(Instr instr) {
394 return (instr & kFunctionFieldMask) >> kFunctionShift;
395 }
396
397
GetFunctionField(Instr instr)398 uint32_t Assembler::GetFunctionField(Instr instr) {
399 return instr & kFunctionFieldMask;
400 }
401
402
GetImmediate16(Instr instr)403 uint32_t Assembler::GetImmediate16(Instr instr) {
404 return instr & kImm16Mask;
405 }
406
407
GetLabelConst(Instr instr)408 uint32_t Assembler::GetLabelConst(Instr instr) {
409 return instr & ~kImm16Mask;
410 }
411
412
IsPop(Instr instr)413 bool Assembler::IsPop(Instr instr) {
414 return (instr & ~kRtMask) == kPopRegPattern;
415 }
416
417
IsPush(Instr instr)418 bool Assembler::IsPush(Instr instr) {
419 return (instr & ~kRtMask) == kPushRegPattern;
420 }
421
422
IsSwRegFpOffset(Instr instr)423 bool Assembler::IsSwRegFpOffset(Instr instr) {
424 return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
425 }
426
427
IsLwRegFpOffset(Instr instr)428 bool Assembler::IsLwRegFpOffset(Instr instr) {
429 return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
430 }
431
432
IsSwRegFpNegOffset(Instr instr)433 bool Assembler::IsSwRegFpNegOffset(Instr instr) {
434 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
435 kSwRegFpNegOffsetPattern);
436 }
437
438
IsLwRegFpNegOffset(Instr instr)439 bool Assembler::IsLwRegFpNegOffset(Instr instr) {
440 return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
441 kLwRegFpNegOffsetPattern);
442 }
443
444
445 // Labels refer to positions in the (to be) generated code.
446 // There are bound, linked, and unused labels.
447 //
448 // Bound labels refer to known positions in the already
449 // generated code. pos() is the position the label refers to.
450 //
451 // Linked labels refer to unknown positions in the code
452 // to be generated; pos() is the position of the last
453 // instruction using the label.
454
455 // The link chain is terminated by a value in the instruction of -1,
456 // which is an otherwise illegal value (branch -1 is inf loop).
457 // The instruction 16-bit offset field addresses 32-bit words, but in
458 // code is conv to an 18-bit value addressing bytes, hence the -4 value.
459
460 const int kEndOfChain = -4;
461 // Determines the end of the Jump chain (a subset of the label link chain).
462 const int kEndOfJumpChain = 0;
463
464
IsBranch(Instr instr)465 bool Assembler::IsBranch(Instr instr) {
466 uint32_t opcode = GetOpcodeField(instr);
467 uint32_t rt_field = GetRtField(instr);
468 uint32_t rs_field = GetRsField(instr);
469 // Checks if the instruction is a branch.
470 bool isBranch =
471 opcode == BEQ || opcode == BNE || opcode == BLEZ || opcode == BGTZ ||
472 opcode == BEQL || opcode == BNEL || opcode == BLEZL || opcode == BGTZL ||
473 (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
474 rt_field == BLTZAL || rt_field == BGEZAL)) ||
475 (opcode == COP1 && rs_field == BC1) || // Coprocessor branch.
476 (opcode == COP1 && rs_field == BC1EQZ) ||
477 (opcode == COP1 && rs_field == BC1NEZ);
478 if (!isBranch && kArchVariant == kMips64r6) {
479 // All the 3 variants of POP10 (BOVC, BEQC, BEQZALC) and
480 // POP30 (BNVC, BNEC, BNEZALC) are branch ops.
481 isBranch |= opcode == POP10 || opcode == POP30 || opcode == BC ||
482 opcode == BALC ||
483 (opcode == POP66 && rs_field != 0) || // BEQZC
484 (opcode == POP76 && rs_field != 0); // BNEZC
485 }
486 return isBranch;
487 }
488
489
IsBc(Instr instr)490 bool Assembler::IsBc(Instr instr) {
491 uint32_t opcode = GetOpcodeField(instr);
492 // Checks if the instruction is a BC or BALC.
493 return opcode == BC || opcode == BALC;
494 }
495
496
IsBzc(Instr instr)497 bool Assembler::IsBzc(Instr instr) {
498 uint32_t opcode = GetOpcodeField(instr);
499 // Checks if the instruction is BEQZC or BNEZC.
500 return (opcode == POP66 && GetRsField(instr) != 0) ||
501 (opcode == POP76 && GetRsField(instr) != 0);
502 }
503
504
IsEmittedConstant(Instr instr)505 bool Assembler::IsEmittedConstant(Instr instr) {
506 uint32_t label_constant = GetLabelConst(instr);
507 return label_constant == 0; // Emitted label const in reg-exp engine.
508 }
509
510
IsBeq(Instr instr)511 bool Assembler::IsBeq(Instr instr) {
512 return GetOpcodeField(instr) == BEQ;
513 }
514
515
IsBne(Instr instr)516 bool Assembler::IsBne(Instr instr) {
517 return GetOpcodeField(instr) == BNE;
518 }
519
520
IsBeqzc(Instr instr)521 bool Assembler::IsBeqzc(Instr instr) {
522 uint32_t opcode = GetOpcodeField(instr);
523 return opcode == POP66 && GetRsField(instr) != 0;
524 }
525
526
IsBnezc(Instr instr)527 bool Assembler::IsBnezc(Instr instr) {
528 uint32_t opcode = GetOpcodeField(instr);
529 return opcode == POP76 && GetRsField(instr) != 0;
530 }
531
532
IsBeqc(Instr instr)533 bool Assembler::IsBeqc(Instr instr) {
534 uint32_t opcode = GetOpcodeField(instr);
535 uint32_t rs = GetRsField(instr);
536 uint32_t rt = GetRtField(instr);
537 return opcode == POP10 && rs != 0 && rs < rt; // && rt != 0
538 }
539
540
IsBnec(Instr instr)541 bool Assembler::IsBnec(Instr instr) {
542 uint32_t opcode = GetOpcodeField(instr);
543 uint32_t rs = GetRsField(instr);
544 uint32_t rt = GetRtField(instr);
545 return opcode == POP30 && rs != 0 && rs < rt; // && rt != 0
546 }
547
548
IsJump(Instr instr)549 bool Assembler::IsJump(Instr instr) {
550 uint32_t opcode = GetOpcodeField(instr);
551 uint32_t rt_field = GetRtField(instr);
552 uint32_t rd_field = GetRdField(instr);
553 uint32_t function_field = GetFunctionField(instr);
554 // Checks if the instruction is a jump.
555 return opcode == J || opcode == JAL ||
556 (opcode == SPECIAL && rt_field == 0 &&
557 ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
558 }
559
560
IsJ(Instr instr)561 bool Assembler::IsJ(Instr instr) {
562 uint32_t opcode = GetOpcodeField(instr);
563 // Checks if the instruction is a jump.
564 return opcode == J;
565 }
566
567
IsJal(Instr instr)568 bool Assembler::IsJal(Instr instr) {
569 return GetOpcodeField(instr) == JAL;
570 }
571
572
IsJr(Instr instr)573 bool Assembler::IsJr(Instr instr) {
574 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
575 }
576
577
IsJalr(Instr instr)578 bool Assembler::IsJalr(Instr instr) {
579 return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JALR;
580 }
581
582
IsLui(Instr instr)583 bool Assembler::IsLui(Instr instr) {
584 uint32_t opcode = GetOpcodeField(instr);
585 // Checks if the instruction is a load upper immediate.
586 return opcode == LUI;
587 }
588
589
IsOri(Instr instr)590 bool Assembler::IsOri(Instr instr) {
591 uint32_t opcode = GetOpcodeField(instr);
592 // Checks if the instruction is a load upper immediate.
593 return opcode == ORI;
594 }
595
596
IsNop(Instr instr,unsigned int type)597 bool Assembler::IsNop(Instr instr, unsigned int type) {
598 // See Assembler::nop(type).
599 DCHECK(type < 32);
600 uint32_t opcode = GetOpcodeField(instr);
601 uint32_t function = GetFunctionField(instr);
602 uint32_t rt = GetRt(instr);
603 uint32_t rd = GetRd(instr);
604 uint32_t sa = GetSa(instr);
605
606 // Traditional mips nop == sll(zero_reg, zero_reg, 0)
607 // When marking non-zero type, use sll(zero_reg, at, type)
608 // to avoid use of mips ssnop and ehb special encodings
609 // of the sll instruction.
610
611 Register nop_rt_reg = (type == 0) ? zero_reg : at;
612 bool ret = (opcode == SPECIAL && function == SLL &&
613 rd == static_cast<uint32_t>(ToNumber(zero_reg)) &&
614 rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) &&
615 sa == type);
616
617 return ret;
618 }
619
620
GetBranchOffset(Instr instr)621 int32_t Assembler::GetBranchOffset(Instr instr) {
622 DCHECK(IsBranch(instr));
623 return (static_cast<int16_t>(instr & kImm16Mask)) << 2;
624 }
625
626
IsLw(Instr instr)627 bool Assembler::IsLw(Instr instr) {
628 return (static_cast<uint32_t>(instr & kOpcodeMask) == LW);
629 }
630
631
GetLwOffset(Instr instr)632 int16_t Assembler::GetLwOffset(Instr instr) {
633 DCHECK(IsLw(instr));
634 return ((instr & kImm16Mask));
635 }
636
637
SetLwOffset(Instr instr,int16_t offset)638 Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
639 DCHECK(IsLw(instr));
640
641 // We actually create a new lw instruction based on the original one.
642 Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
643 | (offset & kImm16Mask);
644
645 return temp_instr;
646 }
647
648
IsSw(Instr instr)649 bool Assembler::IsSw(Instr instr) {
650 return (static_cast<uint32_t>(instr & kOpcodeMask) == SW);
651 }
652
653
SetSwOffset(Instr instr,int16_t offset)654 Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
655 DCHECK(IsSw(instr));
656 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
657 }
658
659
IsAddImmediate(Instr instr)660 bool Assembler::IsAddImmediate(Instr instr) {
661 return ((instr & kOpcodeMask) == ADDIU || (instr & kOpcodeMask) == DADDIU);
662 }
663
664
SetAddImmediateOffset(Instr instr,int16_t offset)665 Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
666 DCHECK(IsAddImmediate(instr));
667 return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
668 }
669
670
IsAndImmediate(Instr instr)671 bool Assembler::IsAndImmediate(Instr instr) {
672 return GetOpcodeField(instr) == ANDI;
673 }
674
675
OffsetSizeInBits(Instr instr)676 static Assembler::OffsetSize OffsetSizeInBits(Instr instr) {
677 if (kArchVariant == kMips64r6) {
678 if (Assembler::IsBc(instr)) {
679 return Assembler::OffsetSize::kOffset26;
680 } else if (Assembler::IsBzc(instr)) {
681 return Assembler::OffsetSize::kOffset21;
682 }
683 }
684 return Assembler::OffsetSize::kOffset16;
685 }
686
687
AddBranchOffset(int pos,Instr instr)688 static inline int32_t AddBranchOffset(int pos, Instr instr) {
689 int bits = OffsetSizeInBits(instr);
690 const int32_t mask = (1 << bits) - 1;
691 bits = 32 - bits;
692
693 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
694 // the compiler uses arithmetic shifts for signed integers.
695 int32_t imm = ((instr & mask) << bits) >> (bits - 2);
696
697 if (imm == kEndOfChain) {
698 // EndOfChain sentinel is returned directly, not relative to pc or pos.
699 return kEndOfChain;
700 } else {
701 return pos + Assembler::kBranchPCOffset + imm;
702 }
703 }
704
705
target_at(int pos,bool is_internal)706 int Assembler::target_at(int pos, bool is_internal) {
707 if (is_internal) {
708 int64_t* p = reinterpret_cast<int64_t*>(buffer_ + pos);
709 int64_t address = *p;
710 if (address == kEndOfJumpChain) {
711 return kEndOfChain;
712 } else {
713 int64_t instr_address = reinterpret_cast<int64_t>(p);
714 DCHECK(instr_address - address < INT_MAX);
715 int delta = static_cast<int>(instr_address - address);
716 DCHECK(pos > delta);
717 return pos - delta;
718 }
719 }
720 Instr instr = instr_at(pos);
721 if ((instr & ~kImm16Mask) == 0) {
722 // Emitted label constant, not part of a branch.
723 if (instr == 0) {
724 return kEndOfChain;
725 } else {
726 int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
727 return (imm18 + pos);
728 }
729 }
730 // Check we have a branch or jump instruction.
731 DCHECK(IsBranch(instr) || IsJ(instr) || IsJal(instr) || IsLui(instr));
732 // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
733 // the compiler uses arithmetic shifts for signed integers.
734 if (IsBranch(instr)) {
735 return AddBranchOffset(pos, instr);
736 } else if (IsLui(instr)) {
737 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
738 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
739 Instr instr_ori2 = instr_at(pos + 3 * Assembler::kInstrSize);
740 DCHECK(IsOri(instr_ori));
741 DCHECK(IsOri(instr_ori2));
742
743 // TODO(plind) create named constants for shift values.
744 int64_t imm = static_cast<int64_t>(instr_lui & kImm16Mask) << 48;
745 imm |= static_cast<int64_t>(instr_ori & kImm16Mask) << 32;
746 imm |= static_cast<int64_t>(instr_ori2 & kImm16Mask) << 16;
747 // Sign extend address;
748 imm >>= 16;
749
750 if (imm == kEndOfJumpChain) {
751 // EndOfChain sentinel is returned directly, not relative to pc or pos.
752 return kEndOfChain;
753 } else {
754 uint64_t instr_address = reinterpret_cast<int64_t>(buffer_ + pos);
755 DCHECK(instr_address - imm < INT_MAX);
756 int delta = static_cast<int>(instr_address - imm);
757 DCHECK(pos > delta);
758 return pos - delta;
759 }
760 } else {
761 DCHECK(IsJ(instr) || IsJal(instr));
762 int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
763 if (imm28 == kEndOfJumpChain) {
764 // EndOfChain sentinel is returned directly, not relative to pc or pos.
765 return kEndOfChain;
766 } else {
767 // Sign extend 28-bit offset.
768 int32_t delta = static_cast<int32_t>((imm28 << 4) >> 4);
769 return pos + delta;
770 }
771 }
772 }
773
774
SetBranchOffset(int32_t pos,int32_t target_pos,Instr instr)775 static inline Instr SetBranchOffset(int32_t pos, int32_t target_pos,
776 Instr instr) {
777 int32_t bits = OffsetSizeInBits(instr);
778 int32_t imm = target_pos - (pos + Assembler::kBranchPCOffset);
779 DCHECK((imm & 3) == 0);
780 imm >>= 2;
781
782 const int32_t mask = (1 << bits) - 1;
783 instr &= ~mask;
784 DCHECK(is_intn(imm, bits));
785
786 return instr | (imm & mask);
787 }
788
789
target_at_put(int pos,int target_pos,bool is_internal)790 void Assembler::target_at_put(int pos, int target_pos, bool is_internal) {
791 if (is_internal) {
792 uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos;
793 *reinterpret_cast<uint64_t*>(buffer_ + pos) = imm;
794 return;
795 }
796 Instr instr = instr_at(pos);
797 if ((instr & ~kImm16Mask) == 0) {
798 DCHECK(target_pos == kEndOfChain || target_pos >= 0);
799 // Emitted label constant, not part of a branch.
800 // Make label relative to Code* of generated Code object.
801 instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
802 return;
803 }
804
805 if (IsBranch(instr)) {
806 instr = SetBranchOffset(pos, target_pos, instr);
807 instr_at_put(pos, instr);
808 } else if (IsLui(instr)) {
809 Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
810 Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
811 Instr instr_ori2 = instr_at(pos + 3 * Assembler::kInstrSize);
812 DCHECK(IsOri(instr_ori));
813 DCHECK(IsOri(instr_ori2));
814
815 uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos;
816 DCHECK((imm & 3) == 0);
817
818 instr_lui &= ~kImm16Mask;
819 instr_ori &= ~kImm16Mask;
820 instr_ori2 &= ~kImm16Mask;
821
822 instr_at_put(pos + 0 * Assembler::kInstrSize,
823 instr_lui | ((imm >> 32) & kImm16Mask));
824 instr_at_put(pos + 1 * Assembler::kInstrSize,
825 instr_ori | ((imm >> 16) & kImm16Mask));
826 instr_at_put(pos + 3 * Assembler::kInstrSize,
827 instr_ori2 | (imm & kImm16Mask));
828 } else if (IsJ(instr) || IsJal(instr)) {
829 int32_t imm28 = target_pos - pos;
830 DCHECK((imm28 & 3) == 0);
831
832 uint32_t imm26 = static_cast<uint32_t>(imm28 >> 2);
833 DCHECK(is_uint26(imm26));
834 // Place 26-bit signed offset with markings.
835 // When code is committed it will be resolved to j/jal.
836 int32_t mark = IsJ(instr) ? kJRawMark : kJalRawMark;
837 instr_at_put(pos, mark | (imm26 & kImm26Mask));
838 } else {
839 int32_t imm28 = target_pos - pos;
840 DCHECK((imm28 & 3) == 0);
841
842 uint32_t imm26 = static_cast<uint32_t>(imm28 >> 2);
843 DCHECK(is_uint26(imm26));
844 // Place raw 26-bit signed offset.
845 // When code is committed it will be resolved to j/jal.
846 instr &= ~kImm26Mask;
847 instr_at_put(pos, instr | (imm26 & kImm26Mask));
848 }
849 }
850
851
print(Label * L)852 void Assembler::print(Label* L) {
853 if (L->is_unused()) {
854 PrintF("unused label\n");
855 } else if (L->is_bound()) {
856 PrintF("bound label to %d\n", L->pos());
857 } else if (L->is_linked()) {
858 Label l = *L;
859 PrintF("unbound label");
860 while (l.is_linked()) {
861 PrintF("@ %d ", l.pos());
862 Instr instr = instr_at(l.pos());
863 if ((instr & ~kImm16Mask) == 0) {
864 PrintF("value\n");
865 } else {
866 PrintF("%d\n", instr);
867 }
868 next(&l, is_internal_reference(&l));
869 }
870 } else {
871 PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
872 }
873 }
874
875
bind_to(Label * L,int pos)876 void Assembler::bind_to(Label* L, int pos) {
877 DCHECK(0 <= pos && pos <= pc_offset()); // Must have valid binding position.
878 int trampoline_pos = kInvalidSlotPos;
879 bool is_internal = false;
880 if (L->is_linked() && !trampoline_emitted_) {
881 unbound_labels_count_--;
882 if (!is_internal_reference(L)) {
883 next_buffer_check_ += kTrampolineSlotsSize;
884 }
885 }
886
887 while (L->is_linked()) {
888 int fixup_pos = L->pos();
889 int dist = pos - fixup_pos;
890 is_internal = is_internal_reference(L);
891 next(L, is_internal); // Call next before overwriting link with target at
892 // fixup_pos.
893 Instr instr = instr_at(fixup_pos);
894 if (is_internal) {
895 target_at_put(fixup_pos, pos, is_internal);
896 } else {
897 if (IsBranch(instr)) {
898 int branch_offset = BranchOffset(instr);
899 if (dist > branch_offset) {
900 if (trampoline_pos == kInvalidSlotPos) {
901 trampoline_pos = get_trampoline_entry(fixup_pos);
902 CHECK(trampoline_pos != kInvalidSlotPos);
903 }
904 CHECK((trampoline_pos - fixup_pos) <= branch_offset);
905 target_at_put(fixup_pos, trampoline_pos, false);
906 fixup_pos = trampoline_pos;
907 }
908 target_at_put(fixup_pos, pos, false);
909 } else {
910 DCHECK(IsJ(instr) || IsJal(instr) || IsLui(instr) ||
911 IsEmittedConstant(instr));
912 target_at_put(fixup_pos, pos, false);
913 }
914 }
915 }
916 L->bind_to(pos);
917
918 // Keep track of the last bound label so we don't eliminate any instructions
919 // before a bound label.
920 if (pos > last_bound_pos_)
921 last_bound_pos_ = pos;
922 }
923
924
bind(Label * L)925 void Assembler::bind(Label* L) {
926 DCHECK(!L->is_bound()); // Label can only be bound once.
927 bind_to(L, pc_offset());
928 }
929
930
next(Label * L,bool is_internal)931 void Assembler::next(Label* L, bool is_internal) {
932 DCHECK(L->is_linked());
933 int link = target_at(L->pos(), is_internal);
934 if (link == kEndOfChain) {
935 L->Unuse();
936 } else {
937 DCHECK(link >= 0);
938 L->link_to(link);
939 }
940 }
941
942
is_near(Label * L)943 bool Assembler::is_near(Label* L) {
944 DCHECK(L->is_bound());
945 return pc_offset() - L->pos() < kMaxBranchOffset - 4 * kInstrSize;
946 }
947
948
is_near(Label * L,OffsetSize bits)949 bool Assembler::is_near(Label* L, OffsetSize bits) {
950 if (L == nullptr || !L->is_bound()) return true;
951 return ((pc_offset() - L->pos()) <
952 (1 << (bits + 2 - 1)) - 1 - 5 * kInstrSize);
953 }
954
955
is_near_branch(Label * L)956 bool Assembler::is_near_branch(Label* L) {
957 DCHECK(L->is_bound());
958 return kArchVariant == kMips64r6 ? is_near_r6(L) : is_near_pre_r6(L);
959 }
960
961
BranchOffset(Instr instr)962 int Assembler::BranchOffset(Instr instr) {
963 // At pre-R6 and for other R6 branches the offset is 16 bits.
964 int bits = OffsetSize::kOffset16;
965
966 if (kArchVariant == kMips64r6) {
967 uint32_t opcode = GetOpcodeField(instr);
968 switch (opcode) {
969 // Checks BC or BALC.
970 case BC:
971 case BALC:
972 bits = OffsetSize::kOffset26;
973 break;
974
975 // Checks BEQZC or BNEZC.
976 case POP66:
977 case POP76:
978 if (GetRsField(instr) != 0) bits = OffsetSize::kOffset21;
979 break;
980 default:
981 break;
982 }
983 }
984
985 return (1 << (bits + 2 - 1)) - 1;
986 }
987
988
989 // We have to use a temporary register for things that can be relocated even
990 // if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
991 // space. There is no guarantee that the relocated location can be similarly
992 // encoded.
MustUseReg(RelocInfo::Mode rmode)993 bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
994 return !RelocInfo::IsNone(rmode);
995 }
996
GenInstrRegister(Opcode opcode,Register rs,Register rt,Register rd,uint16_t sa,SecondaryField func)997 void Assembler::GenInstrRegister(Opcode opcode,
998 Register rs,
999 Register rt,
1000 Register rd,
1001 uint16_t sa,
1002 SecondaryField func) {
1003 DCHECK(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa));
1004 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1005 | (rd.code() << kRdShift) | (sa << kSaShift) | func;
1006 emit(instr);
1007 }
1008
1009
GenInstrRegister(Opcode opcode,Register rs,Register rt,uint16_t msb,uint16_t lsb,SecondaryField func)1010 void Assembler::GenInstrRegister(Opcode opcode,
1011 Register rs,
1012 Register rt,
1013 uint16_t msb,
1014 uint16_t lsb,
1015 SecondaryField func) {
1016 DCHECK(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
1017 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1018 | (msb << kRdShift) | (lsb << kSaShift) | func;
1019 emit(instr);
1020 }
1021
1022
GenInstrRegister(Opcode opcode,SecondaryField fmt,FPURegister ft,FPURegister fs,FPURegister fd,SecondaryField func)1023 void Assembler::GenInstrRegister(Opcode opcode,
1024 SecondaryField fmt,
1025 FPURegister ft,
1026 FPURegister fs,
1027 FPURegister fd,
1028 SecondaryField func) {
1029 DCHECK(fd.is_valid() && fs.is_valid() && ft.is_valid());
1030 Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
1031 | (fd.code() << kFdShift) | func;
1032 emit(instr);
1033 }
1034
1035
GenInstrRegister(Opcode opcode,FPURegister fr,FPURegister ft,FPURegister fs,FPURegister fd,SecondaryField func)1036 void Assembler::GenInstrRegister(Opcode opcode,
1037 FPURegister fr,
1038 FPURegister ft,
1039 FPURegister fs,
1040 FPURegister fd,
1041 SecondaryField func) {
1042 DCHECK(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
1043 Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
1044 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1045 emit(instr);
1046 }
1047
1048
GenInstrRegister(Opcode opcode,SecondaryField fmt,Register rt,FPURegister fs,FPURegister fd,SecondaryField func)1049 void Assembler::GenInstrRegister(Opcode opcode,
1050 SecondaryField fmt,
1051 Register rt,
1052 FPURegister fs,
1053 FPURegister fd,
1054 SecondaryField func) {
1055 DCHECK(fd.is_valid() && fs.is_valid() && rt.is_valid());
1056 Instr instr = opcode | fmt | (rt.code() << kRtShift)
1057 | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
1058 emit(instr);
1059 }
1060
1061
GenInstrRegister(Opcode opcode,SecondaryField fmt,Register rt,FPUControlRegister fs,SecondaryField func)1062 void Assembler::GenInstrRegister(Opcode opcode,
1063 SecondaryField fmt,
1064 Register rt,
1065 FPUControlRegister fs,
1066 SecondaryField func) {
1067 DCHECK(fs.is_valid() && rt.is_valid());
1068 Instr instr =
1069 opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
1070 emit(instr);
1071 }
1072
1073
1074 // Instructions with immediate value.
1075 // Registers are in the order of the instruction encoding, from left to right.
GenInstrImmediate(Opcode opcode,Register rs,Register rt,int32_t j,CompactBranchType is_compact_branch)1076 void Assembler::GenInstrImmediate(Opcode opcode, Register rs, Register rt,
1077 int32_t j,
1078 CompactBranchType is_compact_branch) {
1079 DCHECK(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j)));
1080 Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1081 | (j & kImm16Mask);
1082 emit(instr, is_compact_branch);
1083 }
1084
1085
GenInstrImmediate(Opcode opcode,Register rs,SecondaryField SF,int32_t j,CompactBranchType is_compact_branch)1086 void Assembler::GenInstrImmediate(Opcode opcode, Register rs, SecondaryField SF,
1087 int32_t j,
1088 CompactBranchType is_compact_branch) {
1089 DCHECK(rs.is_valid() && (is_int16(j) || is_uint16(j)));
1090 Instr instr = opcode | (rs.code() << kRsShift) | SF | (j & kImm16Mask);
1091 emit(instr, is_compact_branch);
1092 }
1093
1094
GenInstrImmediate(Opcode opcode,Register rs,FPURegister ft,int32_t j,CompactBranchType is_compact_branch)1095 void Assembler::GenInstrImmediate(Opcode opcode, Register rs, FPURegister ft,
1096 int32_t j,
1097 CompactBranchType is_compact_branch) {
1098 DCHECK(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
1099 Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
1100 | (j & kImm16Mask);
1101 emit(instr, is_compact_branch);
1102 }
1103
1104
GenInstrImmediate(Opcode opcode,Register rs,int32_t offset21,CompactBranchType is_compact_branch)1105 void Assembler::GenInstrImmediate(Opcode opcode, Register rs, int32_t offset21,
1106 CompactBranchType is_compact_branch) {
1107 DCHECK(rs.is_valid() && (is_int21(offset21)));
1108 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
1109 emit(instr, is_compact_branch);
1110 }
1111
1112
GenInstrImmediate(Opcode opcode,Register rs,uint32_t offset21)1113 void Assembler::GenInstrImmediate(Opcode opcode, Register rs,
1114 uint32_t offset21) {
1115 DCHECK(rs.is_valid() && (is_uint21(offset21)));
1116 Instr instr = opcode | (rs.code() << kRsShift) | (offset21 & kImm21Mask);
1117 emit(instr);
1118 }
1119
1120
GenInstrImmediate(Opcode opcode,int32_t offset26,CompactBranchType is_compact_branch)1121 void Assembler::GenInstrImmediate(Opcode opcode, int32_t offset26,
1122 CompactBranchType is_compact_branch) {
1123 DCHECK(is_int26(offset26));
1124 Instr instr = opcode | (offset26 & kImm26Mask);
1125 emit(instr, is_compact_branch);
1126 }
1127
1128
GenInstrJump(Opcode opcode,uint32_t address)1129 void Assembler::GenInstrJump(Opcode opcode,
1130 uint32_t address) {
1131 BlockTrampolinePoolScope block_trampoline_pool(this);
1132 DCHECK(is_uint26(address));
1133 Instr instr = opcode | address;
1134 emit(instr);
1135 BlockTrampolinePoolFor(1); // For associated delay slot.
1136 }
1137
1138
1139 // Returns the next free trampoline entry.
get_trampoline_entry(int32_t pos)1140 int32_t Assembler::get_trampoline_entry(int32_t pos) {
1141 int32_t trampoline_entry = kInvalidSlotPos;
1142 if (!internal_trampoline_exception_) {
1143 if (trampoline_.start() > pos) {
1144 trampoline_entry = trampoline_.take_slot();
1145 }
1146
1147 if (kInvalidSlotPos == trampoline_entry) {
1148 internal_trampoline_exception_ = true;
1149 }
1150 }
1151 return trampoline_entry;
1152 }
1153
1154
jump_address(Label * L)1155 uint64_t Assembler::jump_address(Label* L) {
1156 int64_t target_pos;
1157 if (L->is_bound()) {
1158 target_pos = L->pos();
1159 } else {
1160 if (L->is_linked()) {
1161 target_pos = L->pos(); // L's link.
1162 L->link_to(pc_offset());
1163 } else {
1164 L->link_to(pc_offset());
1165 return kEndOfJumpChain;
1166 }
1167 }
1168 uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos;
1169 DCHECK((imm & 3) == 0);
1170
1171 return imm;
1172 }
1173
1174
jump_offset(Label * L)1175 uint64_t Assembler::jump_offset(Label* L) {
1176 int64_t target_pos;
1177 int32_t pad = IsPrevInstrCompactBranch() ? kInstrSize : 0;
1178
1179 if (L->is_bound()) {
1180 target_pos = L->pos();
1181 } else {
1182 if (L->is_linked()) {
1183 target_pos = L->pos(); // L's link.
1184 L->link_to(pc_offset() + pad);
1185 } else {
1186 L->link_to(pc_offset() + pad);
1187 return kEndOfJumpChain;
1188 }
1189 }
1190 int64_t imm = target_pos - (pc_offset() + pad);
1191 DCHECK((imm & 3) == 0);
1192
1193 return static_cast<uint64_t>(imm);
1194 }
1195
1196
branch_offset_helper(Label * L,OffsetSize bits)1197 int32_t Assembler::branch_offset_helper(Label* L, OffsetSize bits) {
1198 int32_t target_pos;
1199 int32_t pad = IsPrevInstrCompactBranch() ? kInstrSize : 0;
1200
1201 if (L->is_bound()) {
1202 target_pos = L->pos();
1203 } else {
1204 if (L->is_linked()) {
1205 target_pos = L->pos();
1206 L->link_to(pc_offset() + pad);
1207 } else {
1208 L->link_to(pc_offset() + pad);
1209 if (!trampoline_emitted_) {
1210 unbound_labels_count_++;
1211 next_buffer_check_ -= kTrampolineSlotsSize;
1212 }
1213 return kEndOfChain;
1214 }
1215 }
1216
1217 int32_t offset = target_pos - (pc_offset() + kBranchPCOffset + pad);
1218 DCHECK(is_intn(offset, bits + 2));
1219 DCHECK((offset & 3) == 0);
1220
1221 return offset;
1222 }
1223
1224
label_at_put(Label * L,int at_offset)1225 void Assembler::label_at_put(Label* L, int at_offset) {
1226 int target_pos;
1227 if (L->is_bound()) {
1228 target_pos = L->pos();
1229 instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
1230 } else {
1231 if (L->is_linked()) {
1232 target_pos = L->pos(); // L's link.
1233 int32_t imm18 = target_pos - at_offset;
1234 DCHECK((imm18 & 3) == 0);
1235 int32_t imm16 = imm18 >> 2;
1236 DCHECK(is_int16(imm16));
1237 instr_at_put(at_offset, (imm16 & kImm16Mask));
1238 } else {
1239 target_pos = kEndOfChain;
1240 instr_at_put(at_offset, 0);
1241 if (!trampoline_emitted_) {
1242 unbound_labels_count_++;
1243 next_buffer_check_ -= kTrampolineSlotsSize;
1244 }
1245 }
1246 L->link_to(at_offset);
1247 }
1248 }
1249
1250
1251 //------- Branch and jump instructions --------
1252
b(int16_t offset)1253 void Assembler::b(int16_t offset) {
1254 beq(zero_reg, zero_reg, offset);
1255 }
1256
1257
bal(int16_t offset)1258 void Assembler::bal(int16_t offset) {
1259 bgezal(zero_reg, offset);
1260 }
1261
1262
bc(int32_t offset)1263 void Assembler::bc(int32_t offset) {
1264 DCHECK(kArchVariant == kMips64r6);
1265 GenInstrImmediate(BC, offset, CompactBranchType::COMPACT_BRANCH);
1266 }
1267
1268
balc(int32_t offset)1269 void Assembler::balc(int32_t offset) {
1270 DCHECK(kArchVariant == kMips64r6);
1271 GenInstrImmediate(BALC, offset, CompactBranchType::COMPACT_BRANCH);
1272 }
1273
1274
beq(Register rs,Register rt,int16_t offset)1275 void Assembler::beq(Register rs, Register rt, int16_t offset) {
1276 BlockTrampolinePoolScope block_trampoline_pool(this);
1277 GenInstrImmediate(BEQ, rs, rt, offset);
1278 BlockTrampolinePoolFor(1); // For associated delay slot.
1279 }
1280
1281
bgez(Register rs,int16_t offset)1282 void Assembler::bgez(Register rs, int16_t offset) {
1283 BlockTrampolinePoolScope block_trampoline_pool(this);
1284 GenInstrImmediate(REGIMM, rs, BGEZ, offset);
1285 BlockTrampolinePoolFor(1); // For associated delay slot.
1286 }
1287
1288
bgezc(Register rt,int16_t offset)1289 void Assembler::bgezc(Register rt, int16_t offset) {
1290 DCHECK(kArchVariant == kMips64r6);
1291 DCHECK(!(rt.is(zero_reg)));
1292 GenInstrImmediate(BLEZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
1293 }
1294
1295
bgeuc(Register rs,Register rt,int16_t offset)1296 void Assembler::bgeuc(Register rs, Register rt, int16_t offset) {
1297 DCHECK(kArchVariant == kMips64r6);
1298 DCHECK(!(rs.is(zero_reg)));
1299 DCHECK(!(rt.is(zero_reg)));
1300 DCHECK(rs.code() != rt.code());
1301 GenInstrImmediate(BLEZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1302 }
1303
1304
bgec(Register rs,Register rt,int16_t offset)1305 void Assembler::bgec(Register rs, Register rt, int16_t offset) {
1306 DCHECK(kArchVariant == kMips64r6);
1307 DCHECK(!(rs.is(zero_reg)));
1308 DCHECK(!(rt.is(zero_reg)));
1309 DCHECK(rs.code() != rt.code());
1310 GenInstrImmediate(BLEZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1311 }
1312
1313
bgezal(Register rs,int16_t offset)1314 void Assembler::bgezal(Register rs, int16_t offset) {
1315 DCHECK(kArchVariant != kMips64r6 || rs.is(zero_reg));
1316 BlockTrampolinePoolScope block_trampoline_pool(this);
1317 GenInstrImmediate(REGIMM, rs, BGEZAL, offset);
1318 BlockTrampolinePoolFor(1); // For associated delay slot.
1319 }
1320
1321
bgtz(Register rs,int16_t offset)1322 void Assembler::bgtz(Register rs, int16_t offset) {
1323 BlockTrampolinePoolScope block_trampoline_pool(this);
1324 GenInstrImmediate(BGTZ, rs, zero_reg, offset);
1325 BlockTrampolinePoolFor(1); // For associated delay slot.
1326 }
1327
1328
bgtzc(Register rt,int16_t offset)1329 void Assembler::bgtzc(Register rt, int16_t offset) {
1330 DCHECK(kArchVariant == kMips64r6);
1331 DCHECK(!(rt.is(zero_reg)));
1332 GenInstrImmediate(BGTZL, zero_reg, rt, offset,
1333 CompactBranchType::COMPACT_BRANCH);
1334 }
1335
1336
blez(Register rs,int16_t offset)1337 void Assembler::blez(Register rs, int16_t offset) {
1338 BlockTrampolinePoolScope block_trampoline_pool(this);
1339 GenInstrImmediate(BLEZ, rs, zero_reg, offset);
1340 BlockTrampolinePoolFor(1); // For associated delay slot.
1341 }
1342
1343
blezc(Register rt,int16_t offset)1344 void Assembler::blezc(Register rt, int16_t offset) {
1345 DCHECK(kArchVariant == kMips64r6);
1346 DCHECK(!(rt.is(zero_reg)));
1347 GenInstrImmediate(BLEZL, zero_reg, rt, offset,
1348 CompactBranchType::COMPACT_BRANCH);
1349 }
1350
1351
bltzc(Register rt,int16_t offset)1352 void Assembler::bltzc(Register rt, int16_t offset) {
1353 DCHECK(kArchVariant == kMips64r6);
1354 DCHECK(!rt.is(zero_reg));
1355 GenInstrImmediate(BGTZL, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
1356 }
1357
1358
bltuc(Register rs,Register rt,int16_t offset)1359 void Assembler::bltuc(Register rs, Register rt, int16_t offset) {
1360 DCHECK(kArchVariant == kMips64r6);
1361 DCHECK(!(rs.is(zero_reg)));
1362 DCHECK(!(rt.is(zero_reg)));
1363 DCHECK(rs.code() != rt.code());
1364 GenInstrImmediate(BGTZ, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1365 }
1366
1367
bltc(Register rs,Register rt,int16_t offset)1368 void Assembler::bltc(Register rs, Register rt, int16_t offset) {
1369 DCHECK(kArchVariant == kMips64r6);
1370 DCHECK(!rs.is(zero_reg));
1371 DCHECK(!rt.is(zero_reg));
1372 DCHECK(rs.code() != rt.code());
1373 GenInstrImmediate(BGTZL, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1374 }
1375
1376
bltz(Register rs,int16_t offset)1377 void Assembler::bltz(Register rs, int16_t offset) {
1378 BlockTrampolinePoolScope block_trampoline_pool(this);
1379 GenInstrImmediate(REGIMM, rs, BLTZ, offset);
1380 BlockTrampolinePoolFor(1); // For associated delay slot.
1381 }
1382
1383
bltzal(Register rs,int16_t offset)1384 void Assembler::bltzal(Register rs, int16_t offset) {
1385 DCHECK(kArchVariant != kMips64r6 || rs.is(zero_reg));
1386 BlockTrampolinePoolScope block_trampoline_pool(this);
1387 GenInstrImmediate(REGIMM, rs, BLTZAL, offset);
1388 BlockTrampolinePoolFor(1); // For associated delay slot.
1389 }
1390
1391
bne(Register rs,Register rt,int16_t offset)1392 void Assembler::bne(Register rs, Register rt, int16_t offset) {
1393 BlockTrampolinePoolScope block_trampoline_pool(this);
1394 GenInstrImmediate(BNE, rs, rt, offset);
1395 BlockTrampolinePoolFor(1); // For associated delay slot.
1396 }
1397
1398
bovc(Register rs,Register rt,int16_t offset)1399 void Assembler::bovc(Register rs, Register rt, int16_t offset) {
1400 DCHECK(kArchVariant == kMips64r6);
1401 if (rs.code() >= rt.code()) {
1402 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1403 } else {
1404 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1405 }
1406 }
1407
1408
bnvc(Register rs,Register rt,int16_t offset)1409 void Assembler::bnvc(Register rs, Register rt, int16_t offset) {
1410 DCHECK(kArchVariant == kMips64r6);
1411 if (rs.code() >= rt.code()) {
1412 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1413 } else {
1414 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1415 }
1416 }
1417
1418
blezalc(Register rt,int16_t offset)1419 void Assembler::blezalc(Register rt, int16_t offset) {
1420 DCHECK(kArchVariant == kMips64r6);
1421 DCHECK(!(rt.is(zero_reg)));
1422 GenInstrImmediate(BLEZ, zero_reg, rt, offset,
1423 CompactBranchType::COMPACT_BRANCH);
1424 }
1425
1426
bgezalc(Register rt,int16_t offset)1427 void Assembler::bgezalc(Register rt, int16_t offset) {
1428 DCHECK(kArchVariant == kMips64r6);
1429 DCHECK(!(rt.is(zero_reg)));
1430 GenInstrImmediate(BLEZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
1431 }
1432
1433
bgezall(Register rs,int16_t offset)1434 void Assembler::bgezall(Register rs, int16_t offset) {
1435 DCHECK(kArchVariant != kMips64r6);
1436 DCHECK(!(rs.is(zero_reg)));
1437 BlockTrampolinePoolScope block_trampoline_pool(this);
1438 GenInstrImmediate(REGIMM, rs, BGEZALL, offset);
1439 BlockTrampolinePoolFor(1); // For associated delay slot.
1440 }
1441
1442
bltzalc(Register rt,int16_t offset)1443 void Assembler::bltzalc(Register rt, int16_t offset) {
1444 DCHECK(kArchVariant == kMips64r6);
1445 DCHECK(!(rt.is(zero_reg)));
1446 GenInstrImmediate(BGTZ, rt, rt, offset, CompactBranchType::COMPACT_BRANCH);
1447 }
1448
1449
bgtzalc(Register rt,int16_t offset)1450 void Assembler::bgtzalc(Register rt, int16_t offset) {
1451 DCHECK(kArchVariant == kMips64r6);
1452 DCHECK(!(rt.is(zero_reg)));
1453 GenInstrImmediate(BGTZ, zero_reg, rt, offset,
1454 CompactBranchType::COMPACT_BRANCH);
1455 }
1456
1457
beqzalc(Register rt,int16_t offset)1458 void Assembler::beqzalc(Register rt, int16_t offset) {
1459 DCHECK(kArchVariant == kMips64r6);
1460 DCHECK(!(rt.is(zero_reg)));
1461 GenInstrImmediate(ADDI, zero_reg, rt, offset,
1462 CompactBranchType::COMPACT_BRANCH);
1463 }
1464
1465
bnezalc(Register rt,int16_t offset)1466 void Assembler::bnezalc(Register rt, int16_t offset) {
1467 DCHECK(kArchVariant == kMips64r6);
1468 DCHECK(!(rt.is(zero_reg)));
1469 GenInstrImmediate(DADDI, zero_reg, rt, offset,
1470 CompactBranchType::COMPACT_BRANCH);
1471 }
1472
1473
beqc(Register rs,Register rt,int16_t offset)1474 void Assembler::beqc(Register rs, Register rt, int16_t offset) {
1475 DCHECK(kArchVariant == kMips64r6);
1476 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1477 if (rs.code() < rt.code()) {
1478 GenInstrImmediate(ADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1479 } else {
1480 GenInstrImmediate(ADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1481 }
1482 }
1483
1484
beqzc(Register rs,int32_t offset)1485 void Assembler::beqzc(Register rs, int32_t offset) {
1486 DCHECK(kArchVariant == kMips64r6);
1487 DCHECK(!(rs.is(zero_reg)));
1488 GenInstrImmediate(POP66, rs, offset, CompactBranchType::COMPACT_BRANCH);
1489 }
1490
1491
bnec(Register rs,Register rt,int16_t offset)1492 void Assembler::bnec(Register rs, Register rt, int16_t offset) {
1493 DCHECK(kArchVariant == kMips64r6);
1494 DCHECK(rs.code() != rt.code() && rs.code() != 0 && rt.code() != 0);
1495 if (rs.code() < rt.code()) {
1496 GenInstrImmediate(DADDI, rs, rt, offset, CompactBranchType::COMPACT_BRANCH);
1497 } else {
1498 GenInstrImmediate(DADDI, rt, rs, offset, CompactBranchType::COMPACT_BRANCH);
1499 }
1500 }
1501
1502
bnezc(Register rs,int32_t offset)1503 void Assembler::bnezc(Register rs, int32_t offset) {
1504 DCHECK(kArchVariant == kMips64r6);
1505 DCHECK(!(rs.is(zero_reg)));
1506 GenInstrImmediate(POP76, rs, offset, CompactBranchType::COMPACT_BRANCH);
1507 }
1508
1509
j(int64_t target)1510 void Assembler::j(int64_t target) {
1511 BlockTrampolinePoolScope block_trampoline_pool(this);
1512 GenInstrJump(J, static_cast<uint32_t>(target >> 2) & kImm26Mask);
1513 BlockTrampolinePoolFor(1); // For associated delay slot.
1514 }
1515
1516
j(Label * target)1517 void Assembler::j(Label* target) {
1518 uint64_t imm = jump_offset(target);
1519 if (target->is_bound()) {
1520 BlockTrampolinePoolScope block_trampoline_pool(this);
1521 GenInstrJump(static_cast<Opcode>(kJRawMark),
1522 static_cast<uint32_t>(imm >> 2) & kImm26Mask);
1523 BlockTrampolinePoolFor(1); // For associated delay slot.
1524 } else {
1525 j(imm);
1526 }
1527 }
1528
1529
jal(Label * target)1530 void Assembler::jal(Label* target) {
1531 uint64_t imm = jump_offset(target);
1532 if (target->is_bound()) {
1533 BlockTrampolinePoolScope block_trampoline_pool(this);
1534 GenInstrJump(static_cast<Opcode>(kJalRawMark),
1535 static_cast<uint32_t>(imm >> 2) & kImm26Mask);
1536 BlockTrampolinePoolFor(1); // For associated delay slot.
1537 } else {
1538 jal(imm);
1539 }
1540 }
1541
1542
jr(Register rs)1543 void Assembler::jr(Register rs) {
1544 if (kArchVariant != kMips64r6) {
1545 BlockTrampolinePoolScope block_trampoline_pool(this);
1546 GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR);
1547 BlockTrampolinePoolFor(1); // For associated delay slot.
1548 } else {
1549 jalr(rs, zero_reg);
1550 }
1551 }
1552
1553
jal(int64_t target)1554 void Assembler::jal(int64_t target) {
1555 BlockTrampolinePoolScope block_trampoline_pool(this);
1556 GenInstrJump(JAL, static_cast<uint32_t>(target >> 2) & kImm26Mask);
1557 BlockTrampolinePoolFor(1); // For associated delay slot.
1558 }
1559
1560
jalr(Register rs,Register rd)1561 void Assembler::jalr(Register rs, Register rd) {
1562 DCHECK(rs.code() != rd.code());
1563 BlockTrampolinePoolScope block_trampoline_pool(this);
1564 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
1565 BlockTrampolinePoolFor(1); // For associated delay slot.
1566 }
1567
1568
jic(Register rt,int16_t offset)1569 void Assembler::jic(Register rt, int16_t offset) {
1570 DCHECK(kArchVariant == kMips64r6);
1571 GenInstrImmediate(POP66, zero_reg, rt, offset);
1572 }
1573
1574
jialc(Register rt,int16_t offset)1575 void Assembler::jialc(Register rt, int16_t offset) {
1576 DCHECK(kArchVariant == kMips64r6);
1577 GenInstrImmediate(POP76, zero_reg, rt, offset);
1578 }
1579
1580
1581 // -------Data-processing-instructions---------
1582
1583 // Arithmetic.
1584
addu(Register rd,Register rs,Register rt)1585 void Assembler::addu(Register rd, Register rs, Register rt) {
1586 GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU);
1587 }
1588
1589
addiu(Register rd,Register rs,int32_t j)1590 void Assembler::addiu(Register rd, Register rs, int32_t j) {
1591 GenInstrImmediate(ADDIU, rs, rd, j);
1592 }
1593
1594
subu(Register rd,Register rs,Register rt)1595 void Assembler::subu(Register rd, Register rs, Register rt) {
1596 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU);
1597 }
1598
1599
mul(Register rd,Register rs,Register rt)1600 void Assembler::mul(Register rd, Register rs, Register rt) {
1601 if (kArchVariant == kMips64r6) {
1602 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH);
1603 } else {
1604 GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL);
1605 }
1606 }
1607
1608
muh(Register rd,Register rs,Register rt)1609 void Assembler::muh(Register rd, Register rs, Register rt) {
1610 DCHECK(kArchVariant == kMips64r6);
1611 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH);
1612 }
1613
1614
mulu(Register rd,Register rs,Register rt)1615 void Assembler::mulu(Register rd, Register rs, Register rt) {
1616 DCHECK(kArchVariant == kMips64r6);
1617 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH_U);
1618 }
1619
1620
muhu(Register rd,Register rs,Register rt)1621 void Assembler::muhu(Register rd, Register rs, Register rt) {
1622 DCHECK(kArchVariant == kMips64r6);
1623 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH_U);
1624 }
1625
1626
dmul(Register rd,Register rs,Register rt)1627 void Assembler::dmul(Register rd, Register rs, Register rt) {
1628 DCHECK(kArchVariant == kMips64r6);
1629 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, D_MUL_MUH);
1630 }
1631
1632
dmuh(Register rd,Register rs,Register rt)1633 void Assembler::dmuh(Register rd, Register rs, Register rt) {
1634 DCHECK(kArchVariant == kMips64r6);
1635 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, D_MUL_MUH);
1636 }
1637
1638
dmulu(Register rd,Register rs,Register rt)1639 void Assembler::dmulu(Register rd, Register rs, Register rt) {
1640 DCHECK(kArchVariant == kMips64r6);
1641 GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, D_MUL_MUH_U);
1642 }
1643
1644
dmuhu(Register rd,Register rs,Register rt)1645 void Assembler::dmuhu(Register rd, Register rs, Register rt) {
1646 DCHECK(kArchVariant == kMips64r6);
1647 GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, D_MUL_MUH_U);
1648 }
1649
1650
mult(Register rs,Register rt)1651 void Assembler::mult(Register rs, Register rt) {
1652 DCHECK(kArchVariant != kMips64r6);
1653 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULT);
1654 }
1655
1656
multu(Register rs,Register rt)1657 void Assembler::multu(Register rs, Register rt) {
1658 DCHECK(kArchVariant != kMips64r6);
1659 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULTU);
1660 }
1661
1662
daddiu(Register rd,Register rs,int32_t j)1663 void Assembler::daddiu(Register rd, Register rs, int32_t j) {
1664 GenInstrImmediate(DADDIU, rs, rd, j);
1665 }
1666
1667
div(Register rs,Register rt)1668 void Assembler::div(Register rs, Register rt) {
1669 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIV);
1670 }
1671
1672
div(Register rd,Register rs,Register rt)1673 void Assembler::div(Register rd, Register rs, Register rt) {
1674 DCHECK(kArchVariant == kMips64r6);
1675 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD);
1676 }
1677
1678
mod(Register rd,Register rs,Register rt)1679 void Assembler::mod(Register rd, Register rs, Register rt) {
1680 DCHECK(kArchVariant == kMips64r6);
1681 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD);
1682 }
1683
1684
divu(Register rs,Register rt)1685 void Assembler::divu(Register rs, Register rt) {
1686 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIVU);
1687 }
1688
1689
divu(Register rd,Register rs,Register rt)1690 void Assembler::divu(Register rd, Register rs, Register rt) {
1691 DCHECK(kArchVariant == kMips64r6);
1692 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD_U);
1693 }
1694
1695
modu(Register rd,Register rs,Register rt)1696 void Assembler::modu(Register rd, Register rs, Register rt) {
1697 DCHECK(kArchVariant == kMips64r6);
1698 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD_U);
1699 }
1700
1701
daddu(Register rd,Register rs,Register rt)1702 void Assembler::daddu(Register rd, Register rs, Register rt) {
1703 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DADDU);
1704 }
1705
1706
dsubu(Register rd,Register rs,Register rt)1707 void Assembler::dsubu(Register rd, Register rs, Register rt) {
1708 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSUBU);
1709 }
1710
1711
dmult(Register rs,Register rt)1712 void Assembler::dmult(Register rs, Register rt) {
1713 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DMULT);
1714 }
1715
1716
dmultu(Register rs,Register rt)1717 void Assembler::dmultu(Register rs, Register rt) {
1718 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DMULTU);
1719 }
1720
1721
ddiv(Register rs,Register rt)1722 void Assembler::ddiv(Register rs, Register rt) {
1723 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DDIV);
1724 }
1725
1726
ddiv(Register rd,Register rs,Register rt)1727 void Assembler::ddiv(Register rd, Register rs, Register rt) {
1728 DCHECK(kArchVariant == kMips64r6);
1729 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, D_DIV_MOD);
1730 }
1731
1732
dmod(Register rd,Register rs,Register rt)1733 void Assembler::dmod(Register rd, Register rs, Register rt) {
1734 DCHECK(kArchVariant == kMips64r6);
1735 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, D_DIV_MOD);
1736 }
1737
1738
ddivu(Register rs,Register rt)1739 void Assembler::ddivu(Register rs, Register rt) {
1740 GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DDIVU);
1741 }
1742
1743
ddivu(Register rd,Register rs,Register rt)1744 void Assembler::ddivu(Register rd, Register rs, Register rt) {
1745 DCHECK(kArchVariant == kMips64r6);
1746 GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, D_DIV_MOD_U);
1747 }
1748
1749
dmodu(Register rd,Register rs,Register rt)1750 void Assembler::dmodu(Register rd, Register rs, Register rt) {
1751 DCHECK(kArchVariant == kMips64r6);
1752 GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, D_DIV_MOD_U);
1753 }
1754
1755
1756 // Logical.
1757
and_(Register rd,Register rs,Register rt)1758 void Assembler::and_(Register rd, Register rs, Register rt) {
1759 GenInstrRegister(SPECIAL, rs, rt, rd, 0, AND);
1760 }
1761
1762
andi(Register rt,Register rs,int32_t j)1763 void Assembler::andi(Register rt, Register rs, int32_t j) {
1764 DCHECK(is_uint16(j));
1765 GenInstrImmediate(ANDI, rs, rt, j);
1766 }
1767
1768
or_(Register rd,Register rs,Register rt)1769 void Assembler::or_(Register rd, Register rs, Register rt) {
1770 GenInstrRegister(SPECIAL, rs, rt, rd, 0, OR);
1771 }
1772
1773
ori(Register rt,Register rs,int32_t j)1774 void Assembler::ori(Register rt, Register rs, int32_t j) {
1775 DCHECK(is_uint16(j));
1776 GenInstrImmediate(ORI, rs, rt, j);
1777 }
1778
1779
xor_(Register rd,Register rs,Register rt)1780 void Assembler::xor_(Register rd, Register rs, Register rt) {
1781 GenInstrRegister(SPECIAL, rs, rt, rd, 0, XOR);
1782 }
1783
1784
xori(Register rt,Register rs,int32_t j)1785 void Assembler::xori(Register rt, Register rs, int32_t j) {
1786 DCHECK(is_uint16(j));
1787 GenInstrImmediate(XORI, rs, rt, j);
1788 }
1789
1790
nor(Register rd,Register rs,Register rt)1791 void Assembler::nor(Register rd, Register rs, Register rt) {
1792 GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR);
1793 }
1794
1795
1796 // Shifts.
sll(Register rd,Register rt,uint16_t sa,bool coming_from_nop)1797 void Assembler::sll(Register rd,
1798 Register rt,
1799 uint16_t sa,
1800 bool coming_from_nop) {
1801 // Don't allow nop instructions in the form sll zero_reg, zero_reg to be
1802 // generated using the sll instruction. They must be generated using
1803 // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo
1804 // instructions.
1805 DCHECK(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg)));
1806 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SLL);
1807 }
1808
1809
sllv(Register rd,Register rt,Register rs)1810 void Assembler::sllv(Register rd, Register rt, Register rs) {
1811 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV);
1812 }
1813
1814
srl(Register rd,Register rt,uint16_t sa)1815 void Assembler::srl(Register rd, Register rt, uint16_t sa) {
1816 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRL);
1817 }
1818
1819
srlv(Register rd,Register rt,Register rs)1820 void Assembler::srlv(Register rd, Register rt, Register rs) {
1821 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV);
1822 }
1823
1824
sra(Register rd,Register rt,uint16_t sa)1825 void Assembler::sra(Register rd, Register rt, uint16_t sa) {
1826 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, SRA);
1827 }
1828
1829
srav(Register rd,Register rt,Register rs)1830 void Assembler::srav(Register rd, Register rt, Register rs) {
1831 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV);
1832 }
1833
1834
rotr(Register rd,Register rt,uint16_t sa)1835 void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
1836 // Should be called via MacroAssembler::Ror.
1837 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
1838 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
1839 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1840 | (rd.code() << kRdShift) | (sa << kSaShift) | SRL;
1841 emit(instr);
1842 }
1843
1844
rotrv(Register rd,Register rt,Register rs)1845 void Assembler::rotrv(Register rd, Register rt, Register rs) {
1846 // Should be called via MacroAssembler::Ror.
1847 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1848 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
1849 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1850 | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
1851 emit(instr);
1852 }
1853
1854
dsll(Register rd,Register rt,uint16_t sa)1855 void Assembler::dsll(Register rd, Register rt, uint16_t sa) {
1856 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSLL);
1857 }
1858
1859
dsllv(Register rd,Register rt,Register rs)1860 void Assembler::dsllv(Register rd, Register rt, Register rs) {
1861 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSLLV);
1862 }
1863
1864
dsrl(Register rd,Register rt,uint16_t sa)1865 void Assembler::dsrl(Register rd, Register rt, uint16_t sa) {
1866 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSRL);
1867 }
1868
1869
dsrlv(Register rd,Register rt,Register rs)1870 void Assembler::dsrlv(Register rd, Register rt, Register rs) {
1871 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSRLV);
1872 }
1873
1874
drotr(Register rd,Register rt,uint16_t sa)1875 void Assembler::drotr(Register rd, Register rt, uint16_t sa) {
1876 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
1877 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1878 | (rd.code() << kRdShift) | (sa << kSaShift) | DSRL;
1879 emit(instr);
1880 }
1881
drotr32(Register rd,Register rt,uint16_t sa)1882 void Assembler::drotr32(Register rd, Register rt, uint16_t sa) {
1883 DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
1884 Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift) |
1885 (rd.code() << kRdShift) | (sa << kSaShift) | DSRL32;
1886 emit(instr);
1887 }
1888
drotrv(Register rd,Register rt,Register rs)1889 void Assembler::drotrv(Register rd, Register rt, Register rs) {
1890 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid() );
1891 Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1892 | (rd.code() << kRdShift) | (1 << kSaShift) | DSRLV;
1893 emit(instr);
1894 }
1895
1896
dsra(Register rd,Register rt,uint16_t sa)1897 void Assembler::dsra(Register rd, Register rt, uint16_t sa) {
1898 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSRA);
1899 }
1900
1901
dsrav(Register rd,Register rt,Register rs)1902 void Assembler::dsrav(Register rd, Register rt, Register rs) {
1903 GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSRAV);
1904 }
1905
1906
dsll32(Register rd,Register rt,uint16_t sa)1907 void Assembler::dsll32(Register rd, Register rt, uint16_t sa) {
1908 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSLL32);
1909 }
1910
1911
dsrl32(Register rd,Register rt,uint16_t sa)1912 void Assembler::dsrl32(Register rd, Register rt, uint16_t sa) {
1913 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSRL32);
1914 }
1915
1916
dsra32(Register rd,Register rt,uint16_t sa)1917 void Assembler::dsra32(Register rd, Register rt, uint16_t sa) {
1918 GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa & 0x1F, DSRA32);
1919 }
1920
1921
lsa(Register rd,Register rt,Register rs,uint8_t sa)1922 void Assembler::lsa(Register rd, Register rt, Register rs, uint8_t sa) {
1923 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1924 DCHECK(sa <= 3);
1925 DCHECK(kArchVariant == kMips64r6);
1926 Instr instr = SPECIAL | rs.code() << kRsShift | rt.code() << kRtShift |
1927 rd.code() << kRdShift | sa << kSaShift | LSA;
1928 emit(instr);
1929 }
1930
1931
dlsa(Register rd,Register rt,Register rs,uint8_t sa)1932 void Assembler::dlsa(Register rd, Register rt, Register rs, uint8_t sa) {
1933 DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid());
1934 DCHECK(sa <= 3);
1935 DCHECK(kArchVariant == kMips64r6);
1936 Instr instr = SPECIAL | rs.code() << kRsShift | rt.code() << kRtShift |
1937 rd.code() << kRdShift | sa << kSaShift | DLSA;
1938 emit(instr);
1939 }
1940
1941
1942 // ------------Memory-instructions-------------
1943
1944 // Helper for base-reg + offset, when offset is larger than int16.
LoadRegPlusOffsetToAt(const MemOperand & src)1945 void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
1946 DCHECK(!src.rm().is(at));
1947 DCHECK(is_int32(src.offset_));
1948
1949 if (kArchVariant == kMips64r6) {
1950 int32_t hi = (src.offset_ >> kLuiShift) & kImm16Mask;
1951 if (src.offset_ & kNegOffset) {
1952 if ((hi & kNegOffset) != ((hi + 1) & kNegOffset)) {
1953 lui(at, (src.offset_ >> kLuiShift) & kImm16Mask);
1954 ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
1955 daddu(at, at, src.rm()); // Add base register.
1956 return;
1957 }
1958
1959 hi += 1;
1960 }
1961
1962 daui(at, src.rm(), hi);
1963 daddiu(at, at, src.offset_ & kImm16Mask);
1964 } else {
1965 lui(at, (src.offset_ >> kLuiShift) & kImm16Mask);
1966 ori(at, at, src.offset_ & kImm16Mask); // Load 32-bit offset.
1967 daddu(at, at, src.rm()); // Add base register.
1968 }
1969 }
1970
1971 // Helper for base-reg + upper part of offset, when offset is larger than int16.
1972 // Loads higher part of the offset to AT register.
1973 // Returns lower part of the offset to be used as offset
1974 // in Load/Store instructions
LoadRegPlusUpperOffsetPartToAt(const MemOperand & src)1975 int32_t Assembler::LoadRegPlusUpperOffsetPartToAt(const MemOperand& src) {
1976 DCHECK(!src.rm().is(at));
1977 DCHECK(is_int32(src.offset_));
1978 int32_t hi = (src.offset_ >> kLuiShift) & kImm16Mask;
1979 // If the highest bit of the lower part of the offset is 1, this would make
1980 // the offset in the load/store instruction negative. We need to compensate
1981 // for this by adding 1 to the upper part of the offset.
1982 if (src.offset_ & kNegOffset) {
1983 if ((hi & kNegOffset) != ((hi + 1) & kNegOffset)) {
1984 LoadRegPlusOffsetToAt(src);
1985 return 0;
1986 }
1987
1988 hi += 1;
1989 }
1990
1991 if (kArchVariant == kMips64r6) {
1992 daui(at, src.rm(), hi);
1993 } else {
1994 lui(at, hi);
1995 daddu(at, at, src.rm());
1996 }
1997 return (src.offset_ & kImm16Mask);
1998 }
1999
lb(Register rd,const MemOperand & rs)2000 void Assembler::lb(Register rd, const MemOperand& rs) {
2001 if (is_int16(rs.offset_)) {
2002 GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
2003 } else { // Offset > 16 bits, use multiple instructions to load.
2004 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
2005 GenInstrImmediate(LB, at, rd, off16);
2006 }
2007 }
2008
2009
lbu(Register rd,const MemOperand & rs)2010 void Assembler::lbu(Register rd, const MemOperand& rs) {
2011 if (is_int16(rs.offset_)) {
2012 GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
2013 } else { // Offset > 16 bits, use multiple instructions to load.
2014 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
2015 GenInstrImmediate(LBU, at, rd, off16);
2016 }
2017 }
2018
2019
lh(Register rd,const MemOperand & rs)2020 void Assembler::lh(Register rd, const MemOperand& rs) {
2021 if (is_int16(rs.offset_)) {
2022 GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
2023 } else { // Offset > 16 bits, use multiple instructions to load.
2024 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
2025 GenInstrImmediate(LH, at, rd, off16);
2026 }
2027 }
2028
2029
lhu(Register rd,const MemOperand & rs)2030 void Assembler::lhu(Register rd, const MemOperand& rs) {
2031 if (is_int16(rs.offset_)) {
2032 GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
2033 } else { // Offset > 16 bits, use multiple instructions to load.
2034 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
2035 GenInstrImmediate(LHU, at, rd, off16);
2036 }
2037 }
2038
2039
lw(Register rd,const MemOperand & rs)2040 void Assembler::lw(Register rd, const MemOperand& rs) {
2041 if (is_int16(rs.offset_)) {
2042 GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
2043 } else { // Offset > 16 bits, use multiple instructions to load.
2044 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
2045 GenInstrImmediate(LW, at, rd, off16);
2046 }
2047 }
2048
2049
lwu(Register rd,const MemOperand & rs)2050 void Assembler::lwu(Register rd, const MemOperand& rs) {
2051 if (is_int16(rs.offset_)) {
2052 GenInstrImmediate(LWU, rs.rm(), rd, rs.offset_);
2053 } else { // Offset > 16 bits, use multiple instructions to load.
2054 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
2055 GenInstrImmediate(LWU, at, rd, off16);
2056 }
2057 }
2058
2059
lwl(Register rd,const MemOperand & rs)2060 void Assembler::lwl(Register rd, const MemOperand& rs) {
2061 DCHECK(is_int16(rs.offset_));
2062 DCHECK(kArchVariant == kMips64r2);
2063 GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
2064 }
2065
2066
lwr(Register rd,const MemOperand & rs)2067 void Assembler::lwr(Register rd, const MemOperand& rs) {
2068 DCHECK(is_int16(rs.offset_));
2069 DCHECK(kArchVariant == kMips64r2);
2070 GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
2071 }
2072
2073
sb(Register rd,const MemOperand & rs)2074 void Assembler::sb(Register rd, const MemOperand& rs) {
2075 if (is_int16(rs.offset_)) {
2076 GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
2077 } else { // Offset > 16 bits, use multiple instructions to store.
2078 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
2079 GenInstrImmediate(SB, at, rd, off16);
2080 }
2081 }
2082
2083
sh(Register rd,const MemOperand & rs)2084 void Assembler::sh(Register rd, const MemOperand& rs) {
2085 if (is_int16(rs.offset_)) {
2086 GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
2087 } else { // Offset > 16 bits, use multiple instructions to store.
2088 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
2089 GenInstrImmediate(SH, at, rd, off16);
2090 }
2091 }
2092
2093
sw(Register rd,const MemOperand & rs)2094 void Assembler::sw(Register rd, const MemOperand& rs) {
2095 if (is_int16(rs.offset_)) {
2096 GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
2097 } else { // Offset > 16 bits, use multiple instructions to store.
2098 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
2099 GenInstrImmediate(SW, at, rd, off16);
2100 }
2101 }
2102
2103
swl(Register rd,const MemOperand & rs)2104 void Assembler::swl(Register rd, const MemOperand& rs) {
2105 DCHECK(is_int16(rs.offset_));
2106 DCHECK(kArchVariant == kMips64r2);
2107 GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
2108 }
2109
2110
swr(Register rd,const MemOperand & rs)2111 void Assembler::swr(Register rd, const MemOperand& rs) {
2112 DCHECK(is_int16(rs.offset_));
2113 DCHECK(kArchVariant == kMips64r2);
2114 GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
2115 }
2116
2117
lui(Register rd,int32_t j)2118 void Assembler::lui(Register rd, int32_t j) {
2119 DCHECK(is_uint16(j));
2120 GenInstrImmediate(LUI, zero_reg, rd, j);
2121 }
2122
2123
aui(Register rt,Register rs,int32_t j)2124 void Assembler::aui(Register rt, Register rs, int32_t j) {
2125 // This instruction uses same opcode as 'lui'. The difference in encoding is
2126 // 'lui' has zero reg. for rs field.
2127 DCHECK(is_uint16(j));
2128 GenInstrImmediate(LUI, rs, rt, j);
2129 }
2130
2131
daui(Register rt,Register rs,int32_t j)2132 void Assembler::daui(Register rt, Register rs, int32_t j) {
2133 DCHECK(is_uint16(j));
2134 DCHECK(!rs.is(zero_reg));
2135 GenInstrImmediate(DAUI, rs, rt, j);
2136 }
2137
2138
dahi(Register rs,int32_t j)2139 void Assembler::dahi(Register rs, int32_t j) {
2140 DCHECK(is_uint16(j));
2141 GenInstrImmediate(REGIMM, rs, DAHI, j);
2142 }
2143
2144
dati(Register rs,int32_t j)2145 void Assembler::dati(Register rs, int32_t j) {
2146 DCHECK(is_uint16(j));
2147 GenInstrImmediate(REGIMM, rs, DATI, j);
2148 }
2149
2150
ldl(Register rd,const MemOperand & rs)2151 void Assembler::ldl(Register rd, const MemOperand& rs) {
2152 DCHECK(is_int16(rs.offset_));
2153 DCHECK(kArchVariant == kMips64r2);
2154 GenInstrImmediate(LDL, rs.rm(), rd, rs.offset_);
2155 }
2156
2157
ldr(Register rd,const MemOperand & rs)2158 void Assembler::ldr(Register rd, const MemOperand& rs) {
2159 DCHECK(is_int16(rs.offset_));
2160 DCHECK(kArchVariant == kMips64r2);
2161 GenInstrImmediate(LDR, rs.rm(), rd, rs.offset_);
2162 }
2163
2164
sdl(Register rd,const MemOperand & rs)2165 void Assembler::sdl(Register rd, const MemOperand& rs) {
2166 DCHECK(is_int16(rs.offset_));
2167 DCHECK(kArchVariant == kMips64r2);
2168 GenInstrImmediate(SDL, rs.rm(), rd, rs.offset_);
2169 }
2170
2171
sdr(Register rd,const MemOperand & rs)2172 void Assembler::sdr(Register rd, const MemOperand& rs) {
2173 DCHECK(is_int16(rs.offset_));
2174 DCHECK(kArchVariant == kMips64r2);
2175 GenInstrImmediate(SDR, rs.rm(), rd, rs.offset_);
2176 }
2177
2178
ld(Register rd,const MemOperand & rs)2179 void Assembler::ld(Register rd, const MemOperand& rs) {
2180 if (is_int16(rs.offset_)) {
2181 GenInstrImmediate(LD, rs.rm(), rd, rs.offset_);
2182 } else { // Offset > 16 bits, use multiple instructions to load.
2183 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
2184 GenInstrImmediate(LD, at, rd, off16);
2185 }
2186 }
2187
2188
sd(Register rd,const MemOperand & rs)2189 void Assembler::sd(Register rd, const MemOperand& rs) {
2190 if (is_int16(rs.offset_)) {
2191 GenInstrImmediate(SD, rs.rm(), rd, rs.offset_);
2192 } else { // Offset > 16 bits, use multiple instructions to store.
2193 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(rs);
2194 GenInstrImmediate(SD, at, rd, off16);
2195 }
2196 }
2197
2198
2199 // ---------PC-Relative instructions-----------
2200
addiupc(Register rs,int32_t imm19)2201 void Assembler::addiupc(Register rs, int32_t imm19) {
2202 DCHECK(kArchVariant == kMips64r6);
2203 DCHECK(rs.is_valid() && is_int19(imm19));
2204 uint32_t imm21 = ADDIUPC << kImm19Bits | (imm19 & kImm19Mask);
2205 GenInstrImmediate(PCREL, rs, imm21);
2206 }
2207
2208
lwpc(Register rs,int32_t offset19)2209 void Assembler::lwpc(Register rs, int32_t offset19) {
2210 DCHECK(kArchVariant == kMips64r6);
2211 DCHECK(rs.is_valid() && is_int19(offset19));
2212 uint32_t imm21 = LWPC << kImm19Bits | (offset19 & kImm19Mask);
2213 GenInstrImmediate(PCREL, rs, imm21);
2214 }
2215
2216
lwupc(Register rs,int32_t offset19)2217 void Assembler::lwupc(Register rs, int32_t offset19) {
2218 DCHECK(kArchVariant == kMips64r6);
2219 DCHECK(rs.is_valid() && is_int19(offset19));
2220 uint32_t imm21 = LWUPC << kImm19Bits | (offset19 & kImm19Mask);
2221 GenInstrImmediate(PCREL, rs, imm21);
2222 }
2223
2224
ldpc(Register rs,int32_t offset18)2225 void Assembler::ldpc(Register rs, int32_t offset18) {
2226 DCHECK(kArchVariant == kMips64r6);
2227 DCHECK(rs.is_valid() && is_int18(offset18));
2228 uint32_t imm21 = LDPC << kImm18Bits | (offset18 & kImm18Mask);
2229 GenInstrImmediate(PCREL, rs, imm21);
2230 }
2231
2232
auipc(Register rs,int16_t imm16)2233 void Assembler::auipc(Register rs, int16_t imm16) {
2234 DCHECK(kArchVariant == kMips64r6);
2235 DCHECK(rs.is_valid());
2236 uint32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
2237 GenInstrImmediate(PCREL, rs, imm21);
2238 }
2239
2240
aluipc(Register rs,int16_t imm16)2241 void Assembler::aluipc(Register rs, int16_t imm16) {
2242 DCHECK(kArchVariant == kMips64r6);
2243 DCHECK(rs.is_valid());
2244 uint32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
2245 GenInstrImmediate(PCREL, rs, imm21);
2246 }
2247
2248
2249 // -------------Misc-instructions--------------
2250
2251 // Break / Trap instructions.
break_(uint32_t code,bool break_as_stop)2252 void Assembler::break_(uint32_t code, bool break_as_stop) {
2253 DCHECK((code & ~0xfffff) == 0);
2254 // We need to invalidate breaks that could be stops as well because the
2255 // simulator expects a char pointer after the stop instruction.
2256 // See constants-mips.h for explanation.
2257 DCHECK((break_as_stop &&
2258 code <= kMaxStopCode &&
2259 code > kMaxWatchpointCode) ||
2260 (!break_as_stop &&
2261 (code > kMaxStopCode ||
2262 code <= kMaxWatchpointCode)));
2263 Instr break_instr = SPECIAL | BREAK | (code << 6);
2264 emit(break_instr);
2265 }
2266
2267
stop(const char * msg,uint32_t code)2268 void Assembler::stop(const char* msg, uint32_t code) {
2269 DCHECK(code > kMaxWatchpointCode);
2270 DCHECK(code <= kMaxStopCode);
2271 #if defined(V8_HOST_ARCH_MIPS) || defined(V8_HOST_ARCH_MIPS64)
2272 break_(0x54321);
2273 #else // V8_HOST_ARCH_MIPS
2274 BlockTrampolinePoolFor(3);
2275 // The Simulator will handle the stop instruction and get the message address.
2276 // On MIPS stop() is just a special kind of break_().
2277 break_(code, true);
2278 // Do not embed the message string address! We used to do this, but that
2279 // made snapshots created from position-independent executable builds
2280 // non-deterministic.
2281 // TODO(yangguo): remove this field entirely.
2282 nop();
2283 #endif
2284 }
2285
2286
tge(Register rs,Register rt,uint16_t code)2287 void Assembler::tge(Register rs, Register rt, uint16_t code) {
2288 DCHECK(is_uint10(code));
2289 Instr instr = SPECIAL | TGE | rs.code() << kRsShift
2290 | rt.code() << kRtShift | code << 6;
2291 emit(instr);
2292 }
2293
2294
tgeu(Register rs,Register rt,uint16_t code)2295 void Assembler::tgeu(Register rs, Register rt, uint16_t code) {
2296 DCHECK(is_uint10(code));
2297 Instr instr = SPECIAL | TGEU | rs.code() << kRsShift
2298 | rt.code() << kRtShift | code << 6;
2299 emit(instr);
2300 }
2301
2302
tlt(Register rs,Register rt,uint16_t code)2303 void Assembler::tlt(Register rs, Register rt, uint16_t code) {
2304 DCHECK(is_uint10(code));
2305 Instr instr =
2306 SPECIAL | TLT | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2307 emit(instr);
2308 }
2309
2310
tltu(Register rs,Register rt,uint16_t code)2311 void Assembler::tltu(Register rs, Register rt, uint16_t code) {
2312 DCHECK(is_uint10(code));
2313 Instr instr =
2314 SPECIAL | TLTU | rs.code() << kRsShift
2315 | rt.code() << kRtShift | code << 6;
2316 emit(instr);
2317 }
2318
2319
teq(Register rs,Register rt,uint16_t code)2320 void Assembler::teq(Register rs, Register rt, uint16_t code) {
2321 DCHECK(is_uint10(code));
2322 Instr instr =
2323 SPECIAL | TEQ | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2324 emit(instr);
2325 }
2326
2327
tne(Register rs,Register rt,uint16_t code)2328 void Assembler::tne(Register rs, Register rt, uint16_t code) {
2329 DCHECK(is_uint10(code));
2330 Instr instr =
2331 SPECIAL | TNE | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2332 emit(instr);
2333 }
2334
sync()2335 void Assembler::sync() {
2336 Instr sync_instr = SPECIAL | SYNC;
2337 emit(sync_instr);
2338 }
2339
2340 // Move from HI/LO register.
2341
mfhi(Register rd)2342 void Assembler::mfhi(Register rd) {
2343 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFHI);
2344 }
2345
2346
mflo(Register rd)2347 void Assembler::mflo(Register rd) {
2348 GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFLO);
2349 }
2350
2351
2352 // Set on less than instructions.
slt(Register rd,Register rs,Register rt)2353 void Assembler::slt(Register rd, Register rs, Register rt) {
2354 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLT);
2355 }
2356
2357
sltu(Register rd,Register rs,Register rt)2358 void Assembler::sltu(Register rd, Register rs, Register rt) {
2359 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLTU);
2360 }
2361
2362
slti(Register rt,Register rs,int32_t j)2363 void Assembler::slti(Register rt, Register rs, int32_t j) {
2364 GenInstrImmediate(SLTI, rs, rt, j);
2365 }
2366
2367
sltiu(Register rt,Register rs,int32_t j)2368 void Assembler::sltiu(Register rt, Register rs, int32_t j) {
2369 GenInstrImmediate(SLTIU, rs, rt, j);
2370 }
2371
2372
2373 // Conditional move.
movz(Register rd,Register rs,Register rt)2374 void Assembler::movz(Register rd, Register rs, Register rt) {
2375 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ);
2376 }
2377
2378
movn(Register rd,Register rs,Register rt)2379 void Assembler::movn(Register rd, Register rs, Register rt) {
2380 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN);
2381 }
2382
2383
movt(Register rd,Register rs,uint16_t cc)2384 void Assembler::movt(Register rd, Register rs, uint16_t cc) {
2385 Register rt;
2386 rt.reg_code = (cc & 0x0007) << 2 | 1;
2387 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2388 }
2389
2390
movf(Register rd,Register rs,uint16_t cc)2391 void Assembler::movf(Register rd, Register rs, uint16_t cc) {
2392 Register rt;
2393 rt.reg_code = (cc & 0x0007) << 2 | 0;
2394 GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2395 }
2396
2397
min_s(FPURegister fd,FPURegister fs,FPURegister ft)2398 void Assembler::min_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2399 min(S, fd, fs, ft);
2400 }
2401
2402
min_d(FPURegister fd,FPURegister fs,FPURegister ft)2403 void Assembler::min_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2404 min(D, fd, fs, ft);
2405 }
2406
2407
max_s(FPURegister fd,FPURegister fs,FPURegister ft)2408 void Assembler::max_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2409 max(S, fd, fs, ft);
2410 }
2411
2412
max_d(FPURegister fd,FPURegister fs,FPURegister ft)2413 void Assembler::max_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2414 max(D, fd, fs, ft);
2415 }
2416
2417
mina_s(FPURegister fd,FPURegister fs,FPURegister ft)2418 void Assembler::mina_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2419 mina(S, fd, fs, ft);
2420 }
2421
2422
mina_d(FPURegister fd,FPURegister fs,FPURegister ft)2423 void Assembler::mina_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2424 mina(D, fd, fs, ft);
2425 }
2426
2427
maxa_s(FPURegister fd,FPURegister fs,FPURegister ft)2428 void Assembler::maxa_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2429 maxa(S, fd, fs, ft);
2430 }
2431
2432
maxa_d(FPURegister fd,FPURegister fs,FPURegister ft)2433 void Assembler::maxa_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2434 maxa(D, fd, fs, ft);
2435 }
2436
2437
max(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)2438 void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister fs,
2439 FPURegister ft) {
2440 DCHECK(kArchVariant == kMips64r6);
2441 DCHECK((fmt == D) || (fmt == S));
2442 GenInstrRegister(COP1, fmt, ft, fs, fd, MAX);
2443 }
2444
2445
min(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)2446 void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister fs,
2447 FPURegister ft) {
2448 DCHECK(kArchVariant == kMips64r6);
2449 DCHECK((fmt == D) || (fmt == S));
2450 GenInstrRegister(COP1, fmt, ft, fs, fd, MIN);
2451 }
2452
2453
2454 // GPR.
seleqz(Register rd,Register rs,Register rt)2455 void Assembler::seleqz(Register rd, Register rs, Register rt) {
2456 DCHECK(kArchVariant == kMips64r6);
2457 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S);
2458 }
2459
2460
2461 // GPR.
selnez(Register rd,Register rs,Register rt)2462 void Assembler::selnez(Register rd, Register rs, Register rt) {
2463 DCHECK(kArchVariant == kMips64r6);
2464 GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S);
2465 }
2466
2467
2468 // Bit twiddling.
clz(Register rd,Register rs)2469 void Assembler::clz(Register rd, Register rs) {
2470 if (kArchVariant != kMips64r6) {
2471 // Clz instr requires same GPR number in 'rd' and 'rt' fields.
2472 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ);
2473 } else {
2474 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, CLZ_R6);
2475 }
2476 }
2477
2478
dclz(Register rd,Register rs)2479 void Assembler::dclz(Register rd, Register rs) {
2480 if (kArchVariant != kMips64r6) {
2481 // dclz instr requires same GPR number in 'rd' and 'rt' fields.
2482 GenInstrRegister(SPECIAL2, rs, rd, rd, 0, DCLZ);
2483 } else {
2484 GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, DCLZ_R6);
2485 }
2486 }
2487
2488
ins_(Register rt,Register rs,uint16_t pos,uint16_t size)2489 void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2490 // Should be called via MacroAssembler::Ins.
2491 // Ins instr has 'rt' field as dest, and two uint5: msb, lsb.
2492 DCHECK((kArchVariant == kMips64r2) || (kArchVariant == kMips64r6));
2493 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS);
2494 }
2495
2496
dins_(Register rt,Register rs,uint16_t pos,uint16_t size)2497 void Assembler::dins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2498 // Should be called via MacroAssembler::Dins.
2499 // Dext instr has 'rt' field as dest, and two uint5: msb, lsb.
2500 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2501 GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, DINS);
2502 }
2503
2504
ext_(Register rt,Register rs,uint16_t pos,uint16_t size)2505 void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2506 // Should be called via MacroAssembler::Ext.
2507 // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
2508 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2509 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT);
2510 }
2511
2512
dext_(Register rt,Register rs,uint16_t pos,uint16_t size)2513 void Assembler::dext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2514 // Should be called via MacroAssembler::Dext.
2515 // Dext instr has 'rt' field as dest, and two uint5: msb, lsb.
2516 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2517 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, DEXT);
2518 }
2519
2520
dextm(Register rt,Register rs,uint16_t pos,uint16_t size)2521 void Assembler::dextm(Register rt, Register rs, uint16_t pos, uint16_t size) {
2522 // Should be called via MacroAssembler::Dextm.
2523 // Dextm instr has 'rt' field as dest, and two uint5: msb, lsb.
2524 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2525 GenInstrRegister(SPECIAL3, rs, rt, size - 1 - 32, pos, DEXTM);
2526 }
2527
2528
dextu(Register rt,Register rs,uint16_t pos,uint16_t size)2529 void Assembler::dextu(Register rt, Register rs, uint16_t pos, uint16_t size) {
2530 // Should be called via MacroAssembler::Dextu.
2531 // Dext instr has 'rt' field as dest, and two uint5: msb, lsb.
2532 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2533 GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos - 32, DEXTU);
2534 }
2535
2536
bitswap(Register rd,Register rt)2537 void Assembler::bitswap(Register rd, Register rt) {
2538 DCHECK(kArchVariant == kMips64r6);
2539 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BSHFL);
2540 }
2541
2542
dbitswap(Register rd,Register rt)2543 void Assembler::dbitswap(Register rd, Register rt) {
2544 DCHECK(kArchVariant == kMips64r6);
2545 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, DBSHFL);
2546 }
2547
2548
pref(int32_t hint,const MemOperand & rs)2549 void Assembler::pref(int32_t hint, const MemOperand& rs) {
2550 DCHECK(is_uint5(hint) && is_uint16(rs.offset_));
2551 Instr instr = PREF | (rs.rm().code() << kRsShift) | (hint << kRtShift)
2552 | (rs.offset_);
2553 emit(instr);
2554 }
2555
2556
align(Register rd,Register rs,Register rt,uint8_t bp)2557 void Assembler::align(Register rd, Register rs, Register rt, uint8_t bp) {
2558 DCHECK(kArchVariant == kMips64r6);
2559 DCHECK(is_uint3(bp));
2560 uint16_t sa = (ALIGN << kBp2Bits) | bp;
2561 GenInstrRegister(SPECIAL3, rs, rt, rd, sa, BSHFL);
2562 }
2563
2564
dalign(Register rd,Register rs,Register rt,uint8_t bp)2565 void Assembler::dalign(Register rd, Register rs, Register rt, uint8_t bp) {
2566 DCHECK(kArchVariant == kMips64r6);
2567 DCHECK(is_uint3(bp));
2568 uint16_t sa = (DALIGN << kBp3Bits) | bp;
2569 GenInstrRegister(SPECIAL3, rs, rt, rd, sa, DBSHFL);
2570 }
2571
wsbh(Register rd,Register rt)2572 void Assembler::wsbh(Register rd, Register rt) {
2573 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2574 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, WSBH, BSHFL);
2575 }
2576
dsbh(Register rd,Register rt)2577 void Assembler::dsbh(Register rd, Register rt) {
2578 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2579 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, DSBH, DBSHFL);
2580 }
2581
dshd(Register rd,Register rt)2582 void Assembler::dshd(Register rd, Register rt) {
2583 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2584 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, DSHD, DBSHFL);
2585 }
2586
seh(Register rd,Register rt)2587 void Assembler::seh(Register rd, Register rt) {
2588 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2589 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, SEH, BSHFL);
2590 }
2591
seb(Register rd,Register rt)2592 void Assembler::seb(Register rd, Register rt) {
2593 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2594 GenInstrRegister(SPECIAL3, zero_reg, rt, rd, SEB, BSHFL);
2595 }
2596
2597 // --------Coprocessor-instructions----------------
2598
2599 // Load, store, move.
lwc1(FPURegister fd,const MemOperand & src)2600 void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
2601 if (is_int16(src.offset_)) {
2602 GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
2603 } else { // Offset > 16 bits, use multiple instructions to load.
2604 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(src);
2605 GenInstrImmediate(LWC1, at, fd, off16);
2606 }
2607 }
2608
2609
ldc1(FPURegister fd,const MemOperand & src)2610 void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
2611 if (is_int16(src.offset_)) {
2612 GenInstrImmediate(LDC1, src.rm(), fd, src.offset_);
2613 } else { // Offset > 16 bits, use multiple instructions to load.
2614 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(src);
2615 GenInstrImmediate(LDC1, at, fd, off16);
2616 }
2617 }
2618
2619
swc1(FPURegister fd,const MemOperand & src)2620 void Assembler::swc1(FPURegister fd, const MemOperand& src) {
2621 if (is_int16(src.offset_)) {
2622 GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
2623 } else { // Offset > 16 bits, use multiple instructions to load.
2624 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(src);
2625 GenInstrImmediate(SWC1, at, fd, off16);
2626 }
2627 }
2628
2629
sdc1(FPURegister fd,const MemOperand & src)2630 void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
2631 DCHECK(!src.rm().is(at));
2632 if (is_int16(src.offset_)) {
2633 GenInstrImmediate(SDC1, src.rm(), fd, src.offset_);
2634 } else { // Offset > 16 bits, use multiple instructions to load.
2635 int32_t off16 = LoadRegPlusUpperOffsetPartToAt(src);
2636 GenInstrImmediate(SDC1, at, fd, off16);
2637 }
2638 }
2639
2640
mtc1(Register rt,FPURegister fs)2641 void Assembler::mtc1(Register rt, FPURegister fs) {
2642 GenInstrRegister(COP1, MTC1, rt, fs, f0);
2643 }
2644
2645
mthc1(Register rt,FPURegister fs)2646 void Assembler::mthc1(Register rt, FPURegister fs) {
2647 GenInstrRegister(COP1, MTHC1, rt, fs, f0);
2648 }
2649
2650
dmtc1(Register rt,FPURegister fs)2651 void Assembler::dmtc1(Register rt, FPURegister fs) {
2652 GenInstrRegister(COP1, DMTC1, rt, fs, f0);
2653 }
2654
2655
mfc1(Register rt,FPURegister fs)2656 void Assembler::mfc1(Register rt, FPURegister fs) {
2657 GenInstrRegister(COP1, MFC1, rt, fs, f0);
2658 }
2659
2660
mfhc1(Register rt,FPURegister fs)2661 void Assembler::mfhc1(Register rt, FPURegister fs) {
2662 GenInstrRegister(COP1, MFHC1, rt, fs, f0);
2663 }
2664
2665
dmfc1(Register rt,FPURegister fs)2666 void Assembler::dmfc1(Register rt, FPURegister fs) {
2667 GenInstrRegister(COP1, DMFC1, rt, fs, f0);
2668 }
2669
2670
ctc1(Register rt,FPUControlRegister fs)2671 void Assembler::ctc1(Register rt, FPUControlRegister fs) {
2672 GenInstrRegister(COP1, CTC1, rt, fs);
2673 }
2674
2675
cfc1(Register rt,FPUControlRegister fs)2676 void Assembler::cfc1(Register rt, FPUControlRegister fs) {
2677 GenInstrRegister(COP1, CFC1, rt, fs);
2678 }
2679
2680
DoubleAsTwoUInt32(double d,uint32_t * lo,uint32_t * hi)2681 void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2682 uint64_t i;
2683 memcpy(&i, &d, 8);
2684
2685 *lo = i & 0xffffffff;
2686 *hi = i >> 32;
2687 }
2688
2689
sel(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)2690 void Assembler::sel(SecondaryField fmt, FPURegister fd, FPURegister fs,
2691 FPURegister ft) {
2692 DCHECK(kArchVariant == kMips64r6);
2693 DCHECK((fmt == D) || (fmt == S));
2694
2695 GenInstrRegister(COP1, fmt, ft, fs, fd, SEL);
2696 }
2697
2698
sel_s(FPURegister fd,FPURegister fs,FPURegister ft)2699 void Assembler::sel_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2700 sel(S, fd, fs, ft);
2701 }
2702
2703
sel_d(FPURegister fd,FPURegister fs,FPURegister ft)2704 void Assembler::sel_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2705 sel(D, fd, fs, ft);
2706 }
2707
2708
2709 // FPR.
seleqz(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)2710 void Assembler::seleqz(SecondaryField fmt, FPURegister fd, FPURegister fs,
2711 FPURegister ft) {
2712 DCHECK((fmt == D) || (fmt == S));
2713 GenInstrRegister(COP1, fmt, ft, fs, fd, SELEQZ_C);
2714 }
2715
2716
seleqz_d(FPURegister fd,FPURegister fs,FPURegister ft)2717 void Assembler::seleqz_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2718 seleqz(D, fd, fs, ft);
2719 }
2720
2721
seleqz_s(FPURegister fd,FPURegister fs,FPURegister ft)2722 void Assembler::seleqz_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2723 seleqz(S, fd, fs, ft);
2724 }
2725
2726
selnez_d(FPURegister fd,FPURegister fs,FPURegister ft)2727 void Assembler::selnez_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2728 selnez(D, fd, fs, ft);
2729 }
2730
2731
selnez_s(FPURegister fd,FPURegister fs,FPURegister ft)2732 void Assembler::selnez_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2733 selnez(S, fd, fs, ft);
2734 }
2735
2736
movz_s(FPURegister fd,FPURegister fs,Register rt)2737 void Assembler::movz_s(FPURegister fd, FPURegister fs, Register rt) {
2738 DCHECK(kArchVariant == kMips64r2);
2739 GenInstrRegister(COP1, S, rt, fs, fd, MOVZ_C);
2740 }
2741
2742
movz_d(FPURegister fd,FPURegister fs,Register rt)2743 void Assembler::movz_d(FPURegister fd, FPURegister fs, Register rt) {
2744 DCHECK(kArchVariant == kMips64r2);
2745 GenInstrRegister(COP1, D, rt, fs, fd, MOVZ_C);
2746 }
2747
2748
movt_s(FPURegister fd,FPURegister fs,uint16_t cc)2749 void Assembler::movt_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2750 DCHECK(kArchVariant == kMips64r2);
2751 FPURegister ft;
2752 ft.reg_code = (cc & 0x0007) << 2 | 1;
2753 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2754 }
2755
2756
movt_d(FPURegister fd,FPURegister fs,uint16_t cc)2757 void Assembler::movt_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2758 DCHECK(kArchVariant == kMips64r2);
2759 FPURegister ft;
2760 ft.reg_code = (cc & 0x0007) << 2 | 1;
2761 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2762 }
2763
2764
movf_s(FPURegister fd,FPURegister fs,uint16_t cc)2765 void Assembler::movf_s(FPURegister fd, FPURegister fs, uint16_t cc) {
2766 DCHECK(kArchVariant == kMips64r2);
2767 FPURegister ft;
2768 ft.reg_code = (cc & 0x0007) << 2 | 0;
2769 GenInstrRegister(COP1, S, ft, fs, fd, MOVF);
2770 }
2771
2772
movf_d(FPURegister fd,FPURegister fs,uint16_t cc)2773 void Assembler::movf_d(FPURegister fd, FPURegister fs, uint16_t cc) {
2774 DCHECK(kArchVariant == kMips64r2);
2775 FPURegister ft;
2776 ft.reg_code = (cc & 0x0007) << 2 | 0;
2777 GenInstrRegister(COP1, D, ft, fs, fd, MOVF);
2778 }
2779
2780
movn_s(FPURegister fd,FPURegister fs,Register rt)2781 void Assembler::movn_s(FPURegister fd, FPURegister fs, Register rt) {
2782 DCHECK(kArchVariant == kMips64r2);
2783 GenInstrRegister(COP1, S, rt, fs, fd, MOVN_C);
2784 }
2785
2786
movn_d(FPURegister fd,FPURegister fs,Register rt)2787 void Assembler::movn_d(FPURegister fd, FPURegister fs, Register rt) {
2788 DCHECK(kArchVariant == kMips64r2);
2789 GenInstrRegister(COP1, D, rt, fs, fd, MOVN_C);
2790 }
2791
2792
2793 // FPR.
selnez(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)2794 void Assembler::selnez(SecondaryField fmt, FPURegister fd, FPURegister fs,
2795 FPURegister ft) {
2796 DCHECK(kArchVariant == kMips64r6);
2797 DCHECK((fmt == D) || (fmt == S));
2798 GenInstrRegister(COP1, fmt, ft, fs, fd, SELNEZ_C);
2799 }
2800
2801
2802 // Arithmetic.
2803
add_s(FPURegister fd,FPURegister fs,FPURegister ft)2804 void Assembler::add_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2805 GenInstrRegister(COP1, S, ft, fs, fd, ADD_D);
2806 }
2807
2808
add_d(FPURegister fd,FPURegister fs,FPURegister ft)2809 void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2810 GenInstrRegister(COP1, D, ft, fs, fd, ADD_D);
2811 }
2812
2813
sub_s(FPURegister fd,FPURegister fs,FPURegister ft)2814 void Assembler::sub_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2815 GenInstrRegister(COP1, S, ft, fs, fd, SUB_D);
2816 }
2817
2818
sub_d(FPURegister fd,FPURegister fs,FPURegister ft)2819 void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2820 GenInstrRegister(COP1, D, ft, fs, fd, SUB_D);
2821 }
2822
2823
mul_s(FPURegister fd,FPURegister fs,FPURegister ft)2824 void Assembler::mul_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2825 GenInstrRegister(COP1, S, ft, fs, fd, MUL_D);
2826 }
2827
2828
mul_d(FPURegister fd,FPURegister fs,FPURegister ft)2829 void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2830 GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
2831 }
2832
madd_s(FPURegister fd,FPURegister fr,FPURegister fs,FPURegister ft)2833 void Assembler::madd_s(FPURegister fd, FPURegister fr, FPURegister fs,
2834 FPURegister ft) {
2835 DCHECK(kArchVariant == kMips64r2);
2836 GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_S);
2837 }
2838
madd_d(FPURegister fd,FPURegister fr,FPURegister fs,FPURegister ft)2839 void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
2840 FPURegister ft) {
2841 DCHECK(kArchVariant == kMips64r2);
2842 GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
2843 }
2844
msub_s(FPURegister fd,FPURegister fr,FPURegister fs,FPURegister ft)2845 void Assembler::msub_s(FPURegister fd, FPURegister fr, FPURegister fs,
2846 FPURegister ft) {
2847 DCHECK(kArchVariant == kMips64r2);
2848 GenInstrRegister(COP1X, fr, ft, fs, fd, MSUB_S);
2849 }
2850
msub_d(FPURegister fd,FPURegister fr,FPURegister fs,FPURegister ft)2851 void Assembler::msub_d(FPURegister fd, FPURegister fr, FPURegister fs,
2852 FPURegister ft) {
2853 DCHECK(kArchVariant == kMips64r2);
2854 GenInstrRegister(COP1X, fr, ft, fs, fd, MSUB_D);
2855 }
2856
maddf_s(FPURegister fd,FPURegister fs,FPURegister ft)2857 void Assembler::maddf_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2858 DCHECK(kArchVariant == kMips64r6);
2859 GenInstrRegister(COP1, S, ft, fs, fd, MADDF_S);
2860 }
2861
maddf_d(FPURegister fd,FPURegister fs,FPURegister ft)2862 void Assembler::maddf_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2863 DCHECK(kArchVariant == kMips64r6);
2864 GenInstrRegister(COP1, D, ft, fs, fd, MADDF_D);
2865 }
2866
msubf_s(FPURegister fd,FPURegister fs,FPURegister ft)2867 void Assembler::msubf_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2868 DCHECK(kArchVariant == kMips64r6);
2869 GenInstrRegister(COP1, S, ft, fs, fd, MSUBF_S);
2870 }
2871
msubf_d(FPURegister fd,FPURegister fs,FPURegister ft)2872 void Assembler::msubf_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2873 DCHECK(kArchVariant == kMips64r6);
2874 GenInstrRegister(COP1, D, ft, fs, fd, MSUBF_D);
2875 }
2876
div_s(FPURegister fd,FPURegister fs,FPURegister ft)2877 void Assembler::div_s(FPURegister fd, FPURegister fs, FPURegister ft) {
2878 GenInstrRegister(COP1, S, ft, fs, fd, DIV_D);
2879 }
2880
2881
div_d(FPURegister fd,FPURegister fs,FPURegister ft)2882 void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2883 GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
2884 }
2885
2886
abs_s(FPURegister fd,FPURegister fs)2887 void Assembler::abs_s(FPURegister fd, FPURegister fs) {
2888 GenInstrRegister(COP1, S, f0, fs, fd, ABS_D);
2889 }
2890
2891
abs_d(FPURegister fd,FPURegister fs)2892 void Assembler::abs_d(FPURegister fd, FPURegister fs) {
2893 GenInstrRegister(COP1, D, f0, fs, fd, ABS_D);
2894 }
2895
2896
mov_d(FPURegister fd,FPURegister fs)2897 void Assembler::mov_d(FPURegister fd, FPURegister fs) {
2898 GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
2899 }
2900
2901
mov_s(FPURegister fd,FPURegister fs)2902 void Assembler::mov_s(FPURegister fd, FPURegister fs) {
2903 GenInstrRegister(COP1, S, f0, fs, fd, MOV_S);
2904 }
2905
2906
neg_s(FPURegister fd,FPURegister fs)2907 void Assembler::neg_s(FPURegister fd, FPURegister fs) {
2908 GenInstrRegister(COP1, S, f0, fs, fd, NEG_D);
2909 }
2910
2911
neg_d(FPURegister fd,FPURegister fs)2912 void Assembler::neg_d(FPURegister fd, FPURegister fs) {
2913 GenInstrRegister(COP1, D, f0, fs, fd, NEG_D);
2914 }
2915
2916
sqrt_s(FPURegister fd,FPURegister fs)2917 void Assembler::sqrt_s(FPURegister fd, FPURegister fs) {
2918 GenInstrRegister(COP1, S, f0, fs, fd, SQRT_D);
2919 }
2920
2921
sqrt_d(FPURegister fd,FPURegister fs)2922 void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
2923 GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D);
2924 }
2925
2926
rsqrt_s(FPURegister fd,FPURegister fs)2927 void Assembler::rsqrt_s(FPURegister fd, FPURegister fs) {
2928 GenInstrRegister(COP1, S, f0, fs, fd, RSQRT_S);
2929 }
2930
2931
rsqrt_d(FPURegister fd,FPURegister fs)2932 void Assembler::rsqrt_d(FPURegister fd, FPURegister fs) {
2933 GenInstrRegister(COP1, D, f0, fs, fd, RSQRT_D);
2934 }
2935
2936
recip_d(FPURegister fd,FPURegister fs)2937 void Assembler::recip_d(FPURegister fd, FPURegister fs) {
2938 GenInstrRegister(COP1, D, f0, fs, fd, RECIP_D);
2939 }
2940
2941
recip_s(FPURegister fd,FPURegister fs)2942 void Assembler::recip_s(FPURegister fd, FPURegister fs) {
2943 GenInstrRegister(COP1, S, f0, fs, fd, RECIP_S);
2944 }
2945
2946
2947 // Conversions.
cvt_w_s(FPURegister fd,FPURegister fs)2948 void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
2949 GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S);
2950 }
2951
2952
cvt_w_d(FPURegister fd,FPURegister fs)2953 void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) {
2954 GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D);
2955 }
2956
2957
trunc_w_s(FPURegister fd,FPURegister fs)2958 void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) {
2959 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S);
2960 }
2961
2962
trunc_w_d(FPURegister fd,FPURegister fs)2963 void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) {
2964 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D);
2965 }
2966
2967
round_w_s(FPURegister fd,FPURegister fs)2968 void Assembler::round_w_s(FPURegister fd, FPURegister fs) {
2969 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S);
2970 }
2971
2972
round_w_d(FPURegister fd,FPURegister fs)2973 void Assembler::round_w_d(FPURegister fd, FPURegister fs) {
2974 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D);
2975 }
2976
2977
floor_w_s(FPURegister fd,FPURegister fs)2978 void Assembler::floor_w_s(FPURegister fd, FPURegister fs) {
2979 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S);
2980 }
2981
2982
floor_w_d(FPURegister fd,FPURegister fs)2983 void Assembler::floor_w_d(FPURegister fd, FPURegister fs) {
2984 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D);
2985 }
2986
2987
ceil_w_s(FPURegister fd,FPURegister fs)2988 void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) {
2989 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S);
2990 }
2991
2992
ceil_w_d(FPURegister fd,FPURegister fs)2993 void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) {
2994 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D);
2995 }
2996
2997
rint_s(FPURegister fd,FPURegister fs)2998 void Assembler::rint_s(FPURegister fd, FPURegister fs) { rint(S, fd, fs); }
2999
3000
rint_d(FPURegister fd,FPURegister fs)3001 void Assembler::rint_d(FPURegister fd, FPURegister fs) { rint(D, fd, fs); }
3002
3003
rint(SecondaryField fmt,FPURegister fd,FPURegister fs)3004 void Assembler::rint(SecondaryField fmt, FPURegister fd, FPURegister fs) {
3005 DCHECK(kArchVariant == kMips64r6);
3006 GenInstrRegister(COP1, fmt, f0, fs, fd, RINT);
3007 }
3008
3009
cvt_l_s(FPURegister fd,FPURegister fs)3010 void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
3011 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
3012 GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
3013 }
3014
3015
cvt_l_d(FPURegister fd,FPURegister fs)3016 void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
3017 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
3018 GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
3019 }
3020
3021
trunc_l_s(FPURegister fd,FPURegister fs)3022 void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) {
3023 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
3024 GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S);
3025 }
3026
3027
trunc_l_d(FPURegister fd,FPURegister fs)3028 void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) {
3029 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
3030 GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D);
3031 }
3032
3033
round_l_s(FPURegister fd,FPURegister fs)3034 void Assembler::round_l_s(FPURegister fd, FPURegister fs) {
3035 GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S);
3036 }
3037
3038
round_l_d(FPURegister fd,FPURegister fs)3039 void Assembler::round_l_d(FPURegister fd, FPURegister fs) {
3040 GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D);
3041 }
3042
3043
floor_l_s(FPURegister fd,FPURegister fs)3044 void Assembler::floor_l_s(FPURegister fd, FPURegister fs) {
3045 GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S);
3046 }
3047
3048
floor_l_d(FPURegister fd,FPURegister fs)3049 void Assembler::floor_l_d(FPURegister fd, FPURegister fs) {
3050 GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D);
3051 }
3052
3053
ceil_l_s(FPURegister fd,FPURegister fs)3054 void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) {
3055 GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S);
3056 }
3057
3058
ceil_l_d(FPURegister fd,FPURegister fs)3059 void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
3060 GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D);
3061 }
3062
3063
class_s(FPURegister fd,FPURegister fs)3064 void Assembler::class_s(FPURegister fd, FPURegister fs) {
3065 DCHECK(kArchVariant == kMips64r6);
3066 GenInstrRegister(COP1, S, f0, fs, fd, CLASS_S);
3067 }
3068
3069
class_d(FPURegister fd,FPURegister fs)3070 void Assembler::class_d(FPURegister fd, FPURegister fs) {
3071 DCHECK(kArchVariant == kMips64r6);
3072 GenInstrRegister(COP1, D, f0, fs, fd, CLASS_D);
3073 }
3074
3075
mina(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)3076 void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister fs,
3077 FPURegister ft) {
3078 DCHECK(kArchVariant == kMips64r6);
3079 DCHECK((fmt == D) || (fmt == S));
3080 GenInstrRegister(COP1, fmt, ft, fs, fd, MINA);
3081 }
3082
3083
maxa(SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)3084 void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister fs,
3085 FPURegister ft) {
3086 DCHECK(kArchVariant == kMips64r6);
3087 DCHECK((fmt == D) || (fmt == S));
3088 GenInstrRegister(COP1, fmt, ft, fs, fd, MAXA);
3089 }
3090
3091
cvt_s_w(FPURegister fd,FPURegister fs)3092 void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
3093 GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W);
3094 }
3095
3096
cvt_s_l(FPURegister fd,FPURegister fs)3097 void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
3098 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
3099 GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
3100 }
3101
3102
cvt_s_d(FPURegister fd,FPURegister fs)3103 void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) {
3104 GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D);
3105 }
3106
3107
cvt_d_w(FPURegister fd,FPURegister fs)3108 void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
3109 GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W);
3110 }
3111
3112
cvt_d_l(FPURegister fd,FPURegister fs)3113 void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
3114 DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
3115 GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
3116 }
3117
3118
cvt_d_s(FPURegister fd,FPURegister fs)3119 void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
3120 GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S);
3121 }
3122
3123
3124 // Conditions for >= MIPSr6.
cmp(FPUCondition cond,SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)3125 void Assembler::cmp(FPUCondition cond, SecondaryField fmt,
3126 FPURegister fd, FPURegister fs, FPURegister ft) {
3127 DCHECK(kArchVariant == kMips64r6);
3128 DCHECK((fmt & ~(31 << kRsShift)) == 0);
3129 Instr instr = COP1 | fmt | ft.code() << kFtShift |
3130 fs.code() << kFsShift | fd.code() << kFdShift | (0 << 5) | cond;
3131 emit(instr);
3132 }
3133
3134
cmp_s(FPUCondition cond,FPURegister fd,FPURegister fs,FPURegister ft)3135 void Assembler::cmp_s(FPUCondition cond, FPURegister fd, FPURegister fs,
3136 FPURegister ft) {
3137 cmp(cond, W, fd, fs, ft);
3138 }
3139
cmp_d(FPUCondition cond,FPURegister fd,FPURegister fs,FPURegister ft)3140 void Assembler::cmp_d(FPUCondition cond, FPURegister fd, FPURegister fs,
3141 FPURegister ft) {
3142 cmp(cond, L, fd, fs, ft);
3143 }
3144
3145
bc1eqz(int16_t offset,FPURegister ft)3146 void Assembler::bc1eqz(int16_t offset, FPURegister ft) {
3147 DCHECK(kArchVariant == kMips64r6);
3148 Instr instr = COP1 | BC1EQZ | ft.code() << kFtShift | (offset & kImm16Mask);
3149 emit(instr);
3150 }
3151
3152
bc1nez(int16_t offset,FPURegister ft)3153 void Assembler::bc1nez(int16_t offset, FPURegister ft) {
3154 DCHECK(kArchVariant == kMips64r6);
3155 Instr instr = COP1 | BC1NEZ | ft.code() << kFtShift | (offset & kImm16Mask);
3156 emit(instr);
3157 }
3158
3159
3160 // Conditions for < MIPSr6.
c(FPUCondition cond,SecondaryField fmt,FPURegister fs,FPURegister ft,uint16_t cc)3161 void Assembler::c(FPUCondition cond, SecondaryField fmt,
3162 FPURegister fs, FPURegister ft, uint16_t cc) {
3163 DCHECK(kArchVariant != kMips64r6);
3164 DCHECK(is_uint3(cc));
3165 DCHECK(fmt == S || fmt == D);
3166 DCHECK((fmt & ~(31 << kRsShift)) == 0);
3167 Instr instr = COP1 | fmt | ft.code() << kFtShift | fs.code() << kFsShift
3168 | cc << 8 | 3 << 4 | cond;
3169 emit(instr);
3170 }
3171
3172
c_s(FPUCondition cond,FPURegister fs,FPURegister ft,uint16_t cc)3173 void Assembler::c_s(FPUCondition cond, FPURegister fs, FPURegister ft,
3174 uint16_t cc) {
3175 c(cond, S, fs, ft, cc);
3176 }
3177
3178
c_d(FPUCondition cond,FPURegister fs,FPURegister ft,uint16_t cc)3179 void Assembler::c_d(FPUCondition cond, FPURegister fs, FPURegister ft,
3180 uint16_t cc) {
3181 c(cond, D, fs, ft, cc);
3182 }
3183
3184
fcmp(FPURegister src1,const double src2,FPUCondition cond)3185 void Assembler::fcmp(FPURegister src1, const double src2,
3186 FPUCondition cond) {
3187 DCHECK(src2 == 0.0);
3188 mtc1(zero_reg, f14);
3189 cvt_d_w(f14, f14);
3190 c(cond, D, src1, f14, 0);
3191 }
3192
3193
bc1f(int16_t offset,uint16_t cc)3194 void Assembler::bc1f(int16_t offset, uint16_t cc) {
3195 DCHECK(is_uint3(cc));
3196 Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
3197 emit(instr);
3198 }
3199
3200
bc1t(int16_t offset,uint16_t cc)3201 void Assembler::bc1t(int16_t offset, uint16_t cc) {
3202 DCHECK(is_uint3(cc));
3203 Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
3204 emit(instr);
3205 }
3206
3207
RelocateInternalReference(RelocInfo::Mode rmode,byte * pc,intptr_t pc_delta)3208 int Assembler::RelocateInternalReference(RelocInfo::Mode rmode, byte* pc,
3209 intptr_t pc_delta) {
3210 if (RelocInfo::IsInternalReference(rmode)) {
3211 int64_t* p = reinterpret_cast<int64_t*>(pc);
3212 if (*p == kEndOfJumpChain) {
3213 return 0; // Number of instructions patched.
3214 }
3215 *p += pc_delta;
3216 return 2; // Number of instructions patched.
3217 }
3218 Instr instr = instr_at(pc);
3219 DCHECK(RelocInfo::IsInternalReferenceEncoded(rmode));
3220 if (IsLui(instr)) {
3221 Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize);
3222 Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize);
3223 Instr instr_ori2 = instr_at(pc + 3 * Assembler::kInstrSize);
3224 DCHECK(IsOri(instr_ori));
3225 DCHECK(IsOri(instr_ori2));
3226 // TODO(plind): symbolic names for the shifts.
3227 int64_t imm = (instr_lui & static_cast<int64_t>(kImm16Mask)) << 48;
3228 imm |= (instr_ori & static_cast<int64_t>(kImm16Mask)) << 32;
3229 imm |= (instr_ori2 & static_cast<int64_t>(kImm16Mask)) << 16;
3230 // Sign extend address.
3231 imm >>= 16;
3232
3233 if (imm == kEndOfJumpChain) {
3234 return 0; // Number of instructions patched.
3235 }
3236 imm += pc_delta;
3237 DCHECK((imm & 3) == 0);
3238
3239 instr_lui &= ~kImm16Mask;
3240 instr_ori &= ~kImm16Mask;
3241 instr_ori2 &= ~kImm16Mask;
3242
3243 instr_at_put(pc + 0 * Assembler::kInstrSize,
3244 instr_lui | ((imm >> 32) & kImm16Mask));
3245 instr_at_put(pc + 1 * Assembler::kInstrSize,
3246 instr_ori | (imm >> 16 & kImm16Mask));
3247 instr_at_put(pc + 3 * Assembler::kInstrSize,
3248 instr_ori2 | (imm & kImm16Mask));
3249 return 4; // Number of instructions patched.
3250 } else if (IsJ(instr) || IsJal(instr)) {
3251 // Regular j/jal relocation.
3252 uint32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
3253 imm28 += pc_delta;
3254 imm28 &= kImm28Mask;
3255 instr &= ~kImm26Mask;
3256 DCHECK((imm28 & 3) == 0);
3257 uint32_t imm26 = static_cast<uint32_t>(imm28 >> 2);
3258 instr_at_put(pc, instr | (imm26 & kImm26Mask));
3259 return 1; // Number of instructions patched.
3260 } else {
3261 DCHECK(((instr & kJumpRawMask) == kJRawMark) ||
3262 ((instr & kJumpRawMask) == kJalRawMark));
3263 // Unbox raw offset and emit j/jal.
3264 int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
3265 // Sign extend 28-bit offset to 32-bit.
3266 imm28 = (imm28 << 4) >> 4;
3267 uint64_t target =
3268 static_cast<int64_t>(imm28) + reinterpret_cast<uint64_t>(pc);
3269 target &= kImm28Mask;
3270 DCHECK((imm28 & 3) == 0);
3271 uint32_t imm26 = static_cast<uint32_t>(target >> 2);
3272 // Check markings whether to emit j or jal.
3273 uint32_t unbox = (instr & kJRawMark) ? J : JAL;
3274 instr_at_put(pc, unbox | (imm26 & kImm26Mask));
3275 return 1; // Number of instructions patched.
3276 }
3277 }
3278
3279
GrowBuffer()3280 void Assembler::GrowBuffer() {
3281 if (!own_buffer_) FATAL("external code buffer is too small");
3282
3283 // Compute new buffer size.
3284 CodeDesc desc; // The new buffer.
3285 if (buffer_size_ < 1 * MB) {
3286 desc.buffer_size = 2*buffer_size_;
3287 } else {
3288 desc.buffer_size = buffer_size_ + 1*MB;
3289 }
3290 CHECK_GT(desc.buffer_size, 0); // No overflow.
3291
3292 // Set up new buffer.
3293 desc.buffer = NewArray<byte>(desc.buffer_size);
3294 desc.origin = this;
3295
3296 desc.instr_size = pc_offset();
3297 desc.reloc_size =
3298 static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer.pos());
3299
3300 // Copy the data.
3301 intptr_t pc_delta = desc.buffer - buffer_;
3302 intptr_t rc_delta = (desc.buffer + desc.buffer_size) -
3303 (buffer_ + buffer_size_);
3304 MemMove(desc.buffer, buffer_, desc.instr_size);
3305 MemMove(reloc_info_writer.pos() + rc_delta,
3306 reloc_info_writer.pos(), desc.reloc_size);
3307
3308 // Switch buffers.
3309 DeleteArray(buffer_);
3310 buffer_ = desc.buffer;
3311 buffer_size_ = desc.buffer_size;
3312 pc_ += pc_delta;
3313 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
3314 reloc_info_writer.last_pc() + pc_delta);
3315
3316 // Relocate runtime entries.
3317 for (RelocIterator it(desc); !it.done(); it.next()) {
3318 RelocInfo::Mode rmode = it.rinfo()->rmode();
3319 if (rmode == RelocInfo::INTERNAL_REFERENCE) {
3320 byte* p = reinterpret_cast<byte*>(it.rinfo()->pc());
3321 RelocateInternalReference(rmode, p, pc_delta);
3322 }
3323 }
3324 DCHECK(!overflow());
3325 }
3326
3327
db(uint8_t data)3328 void Assembler::db(uint8_t data) {
3329 CheckForEmitInForbiddenSlot();
3330 EmitHelper(data);
3331 }
3332
3333
dd(uint32_t data)3334 void Assembler::dd(uint32_t data) {
3335 CheckForEmitInForbiddenSlot();
3336 EmitHelper(data);
3337 }
3338
3339
dq(uint64_t data)3340 void Assembler::dq(uint64_t data) {
3341 CheckForEmitInForbiddenSlot();
3342 EmitHelper(data);
3343 }
3344
3345
dd(Label * label)3346 void Assembler::dd(Label* label) {
3347 uint64_t data;
3348 CheckForEmitInForbiddenSlot();
3349 if (label->is_bound()) {
3350 data = reinterpret_cast<uint64_t>(buffer_ + label->pos());
3351 } else {
3352 data = jump_address(label);
3353 unbound_labels_count_++;
3354 internal_reference_positions_.insert(label->pos());
3355 }
3356 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
3357 EmitHelper(data);
3358 }
3359
3360
RecordRelocInfo(RelocInfo::Mode rmode,intptr_t data)3361 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
3362 // We do not try to reuse pool constants.
3363 RelocInfo rinfo(isolate(), pc_, rmode, data, NULL);
3364 if (rmode >= RelocInfo::COMMENT &&
3365 rmode <= RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL) {
3366 // Adjust code for new modes.
3367 DCHECK(RelocInfo::IsDebugBreakSlot(rmode) || RelocInfo::IsComment(rmode));
3368 // These modes do not need an entry in the constant pool.
3369 }
3370 if (!RelocInfo::IsNone(rinfo.rmode())) {
3371 // Don't record external references unless the heap will be serialized.
3372 if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
3373 !serializer_enabled() && !emit_debug_code()) {
3374 return;
3375 }
3376 DCHECK(buffer_space() >= kMaxRelocSize); // Too late to grow buffer here.
3377 if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
3378 RelocInfo reloc_info_with_ast_id(isolate(), pc_, rmode,
3379 RecordedAstId().ToInt(), NULL);
3380 ClearRecordedAstId();
3381 reloc_info_writer.Write(&reloc_info_with_ast_id);
3382 } else {
3383 reloc_info_writer.Write(&rinfo);
3384 }
3385 }
3386 }
3387
3388
BlockTrampolinePoolFor(int instructions)3389 void Assembler::BlockTrampolinePoolFor(int instructions) {
3390 CheckTrampolinePoolQuick(instructions);
3391 BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
3392 }
3393
3394
CheckTrampolinePool()3395 void Assembler::CheckTrampolinePool() {
3396 // Some small sequences of instructions must not be broken up by the
3397 // insertion of a trampoline pool; such sequences are protected by setting
3398 // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
3399 // which are both checked here. Also, recursive calls to CheckTrampolinePool
3400 // are blocked by trampoline_pool_blocked_nesting_.
3401 if ((trampoline_pool_blocked_nesting_ > 0) ||
3402 (pc_offset() < no_trampoline_pool_before_)) {
3403 // Emission is currently blocked; make sure we try again as soon as
3404 // possible.
3405 if (trampoline_pool_blocked_nesting_ > 0) {
3406 next_buffer_check_ = pc_offset() + kInstrSize;
3407 } else {
3408 next_buffer_check_ = no_trampoline_pool_before_;
3409 }
3410 return;
3411 }
3412
3413 DCHECK(!trampoline_emitted_);
3414 DCHECK(unbound_labels_count_ >= 0);
3415 if (unbound_labels_count_ > 0) {
3416 // First we emit jump (2 instructions), then we emit trampoline pool.
3417 { BlockTrampolinePoolScope block_trampoline_pool(this);
3418 Label after_pool;
3419 if (kArchVariant == kMips64r6) {
3420 bc(&after_pool);
3421 } else {
3422 b(&after_pool);
3423 }
3424 nop();
3425
3426 int pool_start = pc_offset();
3427 for (int i = 0; i < unbound_labels_count_; i++) {
3428 { BlockGrowBufferScope block_buf_growth(this);
3429 // Buffer growth (and relocation) must be blocked for internal
3430 // references until associated instructions are emitted and available
3431 // to be patched.
3432 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
3433 j(&after_pool);
3434 }
3435 nop();
3436 }
3437 bind(&after_pool);
3438 trampoline_ = Trampoline(pool_start, unbound_labels_count_);
3439
3440 trampoline_emitted_ = true;
3441 // As we are only going to emit trampoline once, we need to prevent any
3442 // further emission.
3443 next_buffer_check_ = kMaxInt;
3444 }
3445 } else {
3446 // Number of branches to unbound label at this point is zero, so we can
3447 // move next buffer check to maximum.
3448 next_buffer_check_ = pc_offset() +
3449 kMaxBranchOffset - kTrampolineSlotsSize * 16;
3450 }
3451 return;
3452 }
3453
3454
target_address_at(Address pc)3455 Address Assembler::target_address_at(Address pc) {
3456 Instr instr0 = instr_at(pc);
3457 Instr instr1 = instr_at(pc + 1 * kInstrSize);
3458 Instr instr3 = instr_at(pc + 3 * kInstrSize);
3459
3460 // Interpret 4 instructions for address generated by li: See listing in
3461 // Assembler::set_target_address_at() just below.
3462 if ((GetOpcodeField(instr0) == LUI) && (GetOpcodeField(instr1) == ORI) &&
3463 (GetOpcodeField(instr3) == ORI)) {
3464 // Assemble the 48 bit value.
3465 int64_t addr = static_cast<int64_t>(
3466 ((uint64_t)(GetImmediate16(instr0)) << 32) |
3467 ((uint64_t)(GetImmediate16(instr1)) << 16) |
3468 ((uint64_t)(GetImmediate16(instr3))));
3469
3470 // Sign extend to get canonical address.
3471 addr = (addr << 16) >> 16;
3472 return reinterpret_cast<Address>(addr);
3473 }
3474 // We should never get here, force a bad address if we do.
3475 UNREACHABLE();
3476 return (Address)0x0;
3477 }
3478
3479
3480 // MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32
3481 // qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap
3482 // snapshot generated on ia32, the resulting MIPS sNaN must be quieted.
3483 // OS::nan_value() returns a qNaN.
QuietNaN(HeapObject * object)3484 void Assembler::QuietNaN(HeapObject* object) {
3485 HeapNumber::cast(object)->set_value(std::numeric_limits<double>::quiet_NaN());
3486 }
3487
3488
3489 // On Mips64, a target address is stored in a 4-instruction sequence:
3490 // 0: lui(rd, (j.imm64_ >> 32) & kImm16Mask);
3491 // 1: ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
3492 // 2: dsll(rd, rd, 16);
3493 // 3: ori(rd, rd, j.imm32_ & kImm16Mask);
3494 //
3495 // Patching the address must replace all the lui & ori instructions,
3496 // and flush the i-cache.
3497 //
3498 // There is an optimization below, which emits a nop when the address
3499 // fits in just 16 bits. This is unlikely to help, and should be benchmarked,
3500 // and possibly removed.
set_target_address_at(Isolate * isolate,Address pc,Address target,ICacheFlushMode icache_flush_mode)3501 void Assembler::set_target_address_at(Isolate* isolate, Address pc,
3502 Address target,
3503 ICacheFlushMode icache_flush_mode) {
3504 // There is an optimization where only 4 instructions are used to load address
3505 // in code on MIP64 because only 48-bits of address is effectively used.
3506 // It relies on fact the upper [63:48] bits are not used for virtual address
3507 // translation and they have to be set according to value of bit 47 in order
3508 // get canonical address.
3509 Instr instr1 = instr_at(pc + kInstrSize);
3510 uint32_t rt_code = GetRt(instr1);
3511 uint32_t* p = reinterpret_cast<uint32_t*>(pc);
3512 uint64_t itarget = reinterpret_cast<uint64_t>(target);
3513
3514 #ifdef DEBUG
3515 // Check we have the result from a li macro-instruction.
3516 Instr instr0 = instr_at(pc);
3517 Instr instr3 = instr_at(pc + kInstrSize * 3);
3518 CHECK((GetOpcodeField(instr0) == LUI && GetOpcodeField(instr1) == ORI &&
3519 GetOpcodeField(instr3) == ORI));
3520 #endif
3521
3522 // Must use 4 instructions to insure patchable code.
3523 // lui rt, upper-16.
3524 // ori rt, rt, lower-16.
3525 // dsll rt, rt, 16.
3526 // ori rt rt, lower-16.
3527 *p = LUI | (rt_code << kRtShift) | ((itarget >> 32) & kImm16Mask);
3528 *(p + 1) = ORI | (rt_code << kRtShift) | (rt_code << kRsShift)
3529 | ((itarget >> 16) & kImm16Mask);
3530 *(p + 3) = ORI | (rt_code << kRsShift) | (rt_code << kRtShift)
3531 | (itarget & kImm16Mask);
3532
3533 if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
3534 Assembler::FlushICache(isolate, pc, 4 * Assembler::kInstrSize);
3535 }
3536 }
3537
3538 } // namespace internal
3539 } // namespace v8
3540
3541 #endif // V8_TARGET_ARCH_MIPS64
3542