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 
36 #include "src/v8.h"
37 
38 #if V8_TARGET_ARCH_MIPS64
39 
40 #include "src/base/cpu.h"
41 #include "src/mips64/assembler-mips64-inl.h"
42 #include "src/serialize.h"
43 
44 namespace v8 {
45 namespace internal {
46 
47 
48 // Get the CPU features enabled by the build. For cross compilation the
49 // preprocessor symbols CAN_USE_FPU_INSTRUCTIONS
50 // can be defined to enable FPU instructions when building the
51 // snapshot.
CpuFeaturesImpliedByCompiler()52 static unsigned CpuFeaturesImpliedByCompiler() {
53   unsigned answer = 0;
54 #ifdef CAN_USE_FPU_INSTRUCTIONS
55   answer |= 1u << FPU;
56 #endif  // def CAN_USE_FPU_INSTRUCTIONS
57 
58   // If the compiler is allowed to use FPU then we can use FPU too in our code
59   // generation even when generating snapshots.  This won't work for cross
60   // compilation.
61 #if defined(__mips__) && defined(__mips_hard_float) && __mips_hard_float != 0
62   answer |= 1u << FPU;
63 #endif
64 
65   return answer;
66 }
67 
68 
AllocationIndexToString(int index)69 const char* DoubleRegister::AllocationIndexToString(int index) {
70   DCHECK(index >= 0 && index < kMaxNumAllocatableRegisters);
71   const char* const names[] = {
72     "f0",
73     "f2",
74     "f4",
75     "f6",
76     "f8",
77     "f10",
78     "f12",
79     "f14",
80     "f16",
81     "f18",
82     "f20",
83     "f22",
84     "f24",
85     "f26"
86   };
87   return names[index];
88 }
89 
90 
ProbeImpl(bool cross_compile)91 void CpuFeatures::ProbeImpl(bool cross_compile) {
92   supported_ |= CpuFeaturesImpliedByCompiler();
93 
94   // Only use statically determined features for cross compile (snapshot).
95   if (cross_compile) return;
96 
97   // If the compiler is allowed to use fpu then we can use fpu too in our
98   // code generation.
99 #ifndef __mips__
100   // For the simulator build, use FPU.
101   supported_ |= 1u << FPU;
102 #else
103   // Probe for additional features at runtime.
104   base::CPU cpu;
105   if (cpu.has_fpu()) supported_ |= 1u << FPU;
106 #endif
107 }
108 
109 
PrintTarget()110 void CpuFeatures::PrintTarget() { }
PrintFeatures()111 void CpuFeatures::PrintFeatures() { }
112 
113 
ToNumber(Register reg)114 int ToNumber(Register reg) {
115   DCHECK(reg.is_valid());
116   const int kNumbers[] = {
117     0,    // zero_reg
118     1,    // at
119     2,    // v0
120     3,    // v1
121     4,    // a0
122     5,    // a1
123     6,    // a2
124     7,    // a3
125     8,    // a4
126     9,    // a5
127     10,   // a6
128     11,   // a7
129     12,   // t0
130     13,   // t1
131     14,   // t2
132     15,   // t3
133     16,   // s0
134     17,   // s1
135     18,   // s2
136     19,   // s3
137     20,   // s4
138     21,   // s5
139     22,   // s6
140     23,   // s7
141     24,   // t8
142     25,   // t9
143     26,   // k0
144     27,   // k1
145     28,   // gp
146     29,   // sp
147     30,   // fp
148     31,   // ra
149   };
150   return kNumbers[reg.code()];
151 }
152 
153 
ToRegister(int num)154 Register ToRegister(int num) {
155   DCHECK(num >= 0 && num < kNumRegisters);
156   const Register kRegisters[] = {
157     zero_reg,
158     at,
159     v0, v1,
160     a0, a1, a2, a3, a4, a5, a6, a7,
161     t0, t1, t2, t3,
162     s0, s1, s2, s3, s4, s5, s6, s7,
163     t8, t9,
164     k0, k1,
165     gp,
166     sp,
167     fp,
168     ra
169   };
170   return kRegisters[num];
171 }
172 
173 
174 // -----------------------------------------------------------------------------
175 // Implementation of RelocInfo.
176 
177 const int RelocInfo::kApplyMask = RelocInfo::kCodeTargetMask |
178                                   1 << RelocInfo::INTERNAL_REFERENCE;
179 
180 
IsCodedSpecially()181 bool RelocInfo::IsCodedSpecially() {
182   // The deserializer needs to know whether a pointer is specially coded.  Being
183   // specially coded on MIPS means that it is a lui/ori instruction, and that is
184   // always the case inside code objects.
185   return true;
186 }
187 
188 
IsInConstantPool()189 bool RelocInfo::IsInConstantPool() {
190   return false;
191 }
192 
193 
194 // Patch the code at the current address with the supplied instructions.
PatchCode(byte * instructions,int instruction_count)195 void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
196   Instr* pc = reinterpret_cast<Instr*>(pc_);
197   Instr* instr = reinterpret_cast<Instr*>(instructions);
198   for (int i = 0; i < instruction_count; i++) {
199     *(pc + i) = *(instr + i);
200   }
201 
202   // Indicate that code has changed.
203   CpuFeatures::FlushICache(pc_, instruction_count * Assembler::kInstrSize);
204 }
205 
206 
207 // Patch the code at the current PC with a call to the target address.
208 // Additional guard instructions can be added if required.
PatchCodeWithCall(Address target,int guard_bytes)209 void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
210   // Patch the code at the current address with a call to the target.
211   UNIMPLEMENTED_MIPS();
212 }
213 
214 
215 // -----------------------------------------------------------------------------
216 // Implementation of Operand and MemOperand.
217 // See assembler-mips-inl.h for inlined constructors.
218 
Operand(Handle<Object> handle)219 Operand::Operand(Handle<Object> handle) {
220   AllowDeferredHandleDereference using_raw_address;
221   rm_ = no_reg;
222   // Verify all Objects referred by code are NOT in new space.
223   Object* obj = *handle;
224   if (obj->IsHeapObject()) {
225     DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj));
226     imm64_ = reinterpret_cast<intptr_t>(handle.location());
227     rmode_ = RelocInfo::EMBEDDED_OBJECT;
228   } else {
229     // No relocation needed.
230     imm64_ = reinterpret_cast<intptr_t>(obj);
231     rmode_ = RelocInfo::NONE64;
232   }
233 }
234 
235 
MemOperand(Register rm,int64_t offset)236 MemOperand::MemOperand(Register rm, int64_t offset) : Operand(rm) {
237   offset_ = offset;
238 }
239 
240 
MemOperand(Register rm,int64_t unit,int64_t multiplier,OffsetAddend offset_addend)241 MemOperand::MemOperand(Register rm, int64_t unit, int64_t multiplier,
242                        OffsetAddend offset_addend) : Operand(rm) {
243   offset_ = unit * multiplier + offset_addend;
244 }
245 
246 
247 // -----------------------------------------------------------------------------
248 // Specific instructions, constants, and masks.
249 
250 static const int kNegOffset = 0x00008000;
251 // daddiu(sp, sp, 8) aka Pop() operation or part of Pop(r)
252 // operations as post-increment of sp.
253 const Instr kPopInstruction = DADDIU | (kRegister_sp_Code << kRsShift)
254       | (kRegister_sp_Code << kRtShift)
255       | (kPointerSize & kImm16Mask);  // NOLINT
256 // daddiu(sp, sp, -8) part of Push(r) operation as pre-decrement of sp.
257 const Instr kPushInstruction = DADDIU | (kRegister_sp_Code << kRsShift)
258       | (kRegister_sp_Code << kRtShift)
259       | (-kPointerSize & kImm16Mask);  // NOLINT
260 // sd(r, MemOperand(sp, 0))
261 const Instr kPushRegPattern = SD | (kRegister_sp_Code << kRsShift)
262       |  (0 & kImm16Mask);  // NOLINT
263 //  ld(r, MemOperand(sp, 0))
264 const Instr kPopRegPattern = LD | (kRegister_sp_Code << kRsShift)
265       |  (0 & kImm16Mask);  // NOLINT
266 
267 const Instr kLwRegFpOffsetPattern = LW | (kRegister_fp_Code << kRsShift)
268       |  (0 & kImm16Mask);  // NOLINT
269 
270 const Instr kSwRegFpOffsetPattern = SW | (kRegister_fp_Code << kRsShift)
271       |  (0 & kImm16Mask);  // NOLINT
272 
273 const Instr kLwRegFpNegOffsetPattern = LW | (kRegister_fp_Code << kRsShift)
274       |  (kNegOffset & kImm16Mask);  // NOLINT
275 
276 const Instr kSwRegFpNegOffsetPattern = SW | (kRegister_fp_Code << kRsShift)
277       |  (kNegOffset & kImm16Mask);  // NOLINT
278 // A mask for the Rt register for push, pop, lw, sw instructions.
279 const Instr kRtMask = kRtFieldMask;
280 const Instr kLwSwInstrTypeMask = 0xffe00000;
281 const Instr kLwSwInstrArgumentMask  = ~kLwSwInstrTypeMask;
282 const Instr kLwSwOffsetMask = kImm16Mask;
283 
284 
Assembler(Isolate * isolate,void * buffer,int buffer_size)285 Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
286     : AssemblerBase(isolate, buffer, buffer_size),
287       recorded_ast_id_(TypeFeedbackId::None()),
288       positions_recorder_(this) {
289   reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
290 
291   last_trampoline_pool_end_ = 0;
292   no_trampoline_pool_before_ = 0;
293   trampoline_pool_blocked_nesting_ = 0;
294   // We leave space (16 * kTrampolineSlotsSize)
295   // for BlockTrampolinePoolScope buffer.
296   next_buffer_check_ = FLAG_force_long_branches
297       ? kMaxInt : kMaxBranchOffset - kTrampolineSlotsSize * 16;
298   internal_trampoline_exception_ = false;
299   last_bound_pos_ = 0;
300 
301   trampoline_emitted_ = FLAG_force_long_branches;
302   unbound_labels_count_ = 0;
303   block_buffer_growth_ = false;
304 
305   ClearRecordedAstId();
306 }
307 
308 
GetCode(CodeDesc * desc)309 void Assembler::GetCode(CodeDesc* desc) {
310   DCHECK(pc_ <= reloc_info_writer.pos());  // No overlap.
311   // Set up code descriptor.
312   desc->buffer = buffer_;
313   desc->buffer_size = buffer_size_;
314   desc->instr_size = pc_offset();
315   desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
316   desc->origin = this;
317 }
318 
319 
Align(int m)320 void Assembler::Align(int m) {
321   DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
322   while ((pc_offset() & (m - 1)) != 0) {
323     nop();
324   }
325 }
326 
327 
CodeTargetAlign()328 void Assembler::CodeTargetAlign() {
329   // No advantage to aligning branch/call targets to more than
330   // single instruction, that I am aware of.
331   Align(4);
332 }
333 
334 
GetRtReg(Instr instr)335 Register Assembler::GetRtReg(Instr instr) {
336   Register rt;
337   rt.code_ = (instr & kRtFieldMask) >> kRtShift;
338   return rt;
339 }
340 
341 
GetRsReg(Instr instr)342 Register Assembler::GetRsReg(Instr instr) {
343   Register rs;
344   rs.code_ = (instr & kRsFieldMask) >> kRsShift;
345   return rs;
346 }
347 
348 
GetRdReg(Instr instr)349 Register Assembler::GetRdReg(Instr instr) {
350   Register rd;
351   rd.code_ = (instr & kRdFieldMask) >> kRdShift;
352   return rd;
353 }
354 
355 
GetRt(Instr instr)356 uint32_t Assembler::GetRt(Instr instr) {
357   return (instr & kRtFieldMask) >> kRtShift;
358 }
359 
360 
GetRtField(Instr instr)361 uint32_t Assembler::GetRtField(Instr instr) {
362   return instr & kRtFieldMask;
363 }
364 
365 
GetRs(Instr instr)366 uint32_t Assembler::GetRs(Instr instr) {
367   return (instr & kRsFieldMask) >> kRsShift;
368 }
369 
370 
GetRsField(Instr instr)371 uint32_t Assembler::GetRsField(Instr instr) {
372   return instr & kRsFieldMask;
373 }
374 
375 
GetRd(Instr instr)376 uint32_t Assembler::GetRd(Instr instr) {
377   return  (instr & kRdFieldMask) >> kRdShift;
378 }
379 
380 
GetRdField(Instr instr)381 uint32_t Assembler::GetRdField(Instr instr) {
382   return  instr & kRdFieldMask;
383 }
384 
385 
GetSa(Instr instr)386 uint32_t Assembler::GetSa(Instr instr) {
387   return (instr & kSaFieldMask) >> kSaShift;
388 }
389 
390 
GetSaField(Instr instr)391 uint32_t Assembler::GetSaField(Instr instr) {
392   return instr & kSaFieldMask;
393 }
394 
395 
GetOpcodeField(Instr instr)396 uint32_t Assembler::GetOpcodeField(Instr instr) {
397   return instr & kOpcodeMask;
398 }
399 
400 
GetFunction(Instr instr)401 uint32_t Assembler::GetFunction(Instr instr) {
402   return (instr & kFunctionFieldMask) >> kFunctionShift;
403 }
404 
405 
GetFunctionField(Instr instr)406 uint32_t Assembler::GetFunctionField(Instr instr) {
407   return instr & kFunctionFieldMask;
408 }
409 
410 
GetImmediate16(Instr instr)411 uint32_t Assembler::GetImmediate16(Instr instr) {
412   return instr & kImm16Mask;
413 }
414 
415 
GetLabelConst(Instr instr)416 uint32_t Assembler::GetLabelConst(Instr instr) {
417   return instr & ~kImm16Mask;
418 }
419 
420 
IsPop(Instr instr)421 bool Assembler::IsPop(Instr instr) {
422   return (instr & ~kRtMask) == kPopRegPattern;
423 }
424 
425 
IsPush(Instr instr)426 bool Assembler::IsPush(Instr instr) {
427   return (instr & ~kRtMask) == kPushRegPattern;
428 }
429 
430 
IsSwRegFpOffset(Instr instr)431 bool Assembler::IsSwRegFpOffset(Instr instr) {
432   return ((instr & kLwSwInstrTypeMask) == kSwRegFpOffsetPattern);
433 }
434 
435 
IsLwRegFpOffset(Instr instr)436 bool Assembler::IsLwRegFpOffset(Instr instr) {
437   return ((instr & kLwSwInstrTypeMask) == kLwRegFpOffsetPattern);
438 }
439 
440 
IsSwRegFpNegOffset(Instr instr)441 bool Assembler::IsSwRegFpNegOffset(Instr instr) {
442   return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
443           kSwRegFpNegOffsetPattern);
444 }
445 
446 
IsLwRegFpNegOffset(Instr instr)447 bool Assembler::IsLwRegFpNegOffset(Instr instr) {
448   return ((instr & (kLwSwInstrTypeMask | kNegOffset)) ==
449           kLwRegFpNegOffsetPattern);
450 }
451 
452 
453 // Labels refer to positions in the (to be) generated code.
454 // There are bound, linked, and unused labels.
455 //
456 // Bound labels refer to known positions in the already
457 // generated code. pos() is the position the label refers to.
458 //
459 // Linked labels refer to unknown positions in the code
460 // to be generated; pos() is the position of the last
461 // instruction using the label.
462 
463 // The link chain is terminated by a value in the instruction of -1,
464 // which is an otherwise illegal value (branch -1 is inf loop).
465 // The instruction 16-bit offset field addresses 32-bit words, but in
466 // code is conv to an 18-bit value addressing bytes, hence the -4 value.
467 
468 const int kEndOfChain = -4;
469 // Determines the end of the Jump chain (a subset of the label link chain).
470 const int kEndOfJumpChain = 0;
471 
472 
IsBranch(Instr instr)473 bool Assembler::IsBranch(Instr instr) {
474   uint32_t opcode   = GetOpcodeField(instr);
475   uint32_t rt_field = GetRtField(instr);
476   uint32_t rs_field = GetRsField(instr);
477   // Checks if the instruction is a branch.
478   return opcode == BEQ ||
479       opcode == BNE ||
480       opcode == BLEZ ||
481       opcode == BGTZ ||
482       opcode == BEQL ||
483       opcode == BNEL ||
484       opcode == BLEZL ||
485       opcode == BGTZL ||
486       (opcode == REGIMM && (rt_field == BLTZ || rt_field == BGEZ ||
487                             rt_field == BLTZAL || rt_field == BGEZAL)) ||
488       (opcode == COP1 && rs_field == BC1) ||  // Coprocessor branch.
489       (opcode == COP1 && rs_field == BC1EQZ) ||
490       (opcode == COP1 && rs_field == BC1NEZ);
491 }
492 
493 
IsEmittedConstant(Instr instr)494 bool Assembler::IsEmittedConstant(Instr instr) {
495   uint32_t label_constant = GetLabelConst(instr);
496   return label_constant == 0;  // Emitted label const in reg-exp engine.
497 }
498 
499 
IsBeq(Instr instr)500 bool Assembler::IsBeq(Instr instr) {
501   return GetOpcodeField(instr) == BEQ;
502 }
503 
504 
IsBne(Instr instr)505 bool Assembler::IsBne(Instr instr) {
506   return GetOpcodeField(instr) == BNE;
507 }
508 
509 
IsJump(Instr instr)510 bool Assembler::IsJump(Instr instr) {
511   uint32_t opcode   = GetOpcodeField(instr);
512   uint32_t rt_field = GetRtField(instr);
513   uint32_t rd_field = GetRdField(instr);
514   uint32_t function_field = GetFunctionField(instr);
515   // Checks if the instruction is a jump.
516   return opcode == J || opcode == JAL ||
517       (opcode == SPECIAL && rt_field == 0 &&
518       ((function_field == JALR) || (rd_field == 0 && (function_field == JR))));
519 }
520 
521 
IsJ(Instr instr)522 bool Assembler::IsJ(Instr instr) {
523   uint32_t opcode = GetOpcodeField(instr);
524   // Checks if the instruction is a jump.
525   return opcode == J;
526 }
527 
528 
IsJal(Instr instr)529 bool Assembler::IsJal(Instr instr) {
530   return GetOpcodeField(instr) == JAL;
531 }
532 
533 
IsJr(Instr instr)534 bool Assembler::IsJr(Instr instr) {
535   return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JR;
536 }
537 
538 
IsJalr(Instr instr)539 bool Assembler::IsJalr(Instr instr) {
540   return GetOpcodeField(instr) == SPECIAL && GetFunctionField(instr) == JALR;
541 }
542 
543 
IsLui(Instr instr)544 bool Assembler::IsLui(Instr instr) {
545   uint32_t opcode = GetOpcodeField(instr);
546   // Checks if the instruction is a load upper immediate.
547   return opcode == LUI;
548 }
549 
550 
IsOri(Instr instr)551 bool Assembler::IsOri(Instr instr) {
552   uint32_t opcode = GetOpcodeField(instr);
553   // Checks if the instruction is a load upper immediate.
554   return opcode == ORI;
555 }
556 
557 
IsNop(Instr instr,unsigned int type)558 bool Assembler::IsNop(Instr instr, unsigned int type) {
559   // See Assembler::nop(type).
560   DCHECK(type < 32);
561   uint32_t opcode = GetOpcodeField(instr);
562   uint32_t function = GetFunctionField(instr);
563   uint32_t rt = GetRt(instr);
564   uint32_t rd = GetRd(instr);
565   uint32_t sa = GetSa(instr);
566 
567   // Traditional mips nop == sll(zero_reg, zero_reg, 0)
568   // When marking non-zero type, use sll(zero_reg, at, type)
569   // to avoid use of mips ssnop and ehb special encodings
570   // of the sll instruction.
571 
572   Register nop_rt_reg = (type == 0) ? zero_reg : at;
573   bool ret = (opcode == SPECIAL && function == SLL &&
574               rd == static_cast<uint32_t>(ToNumber(zero_reg)) &&
575               rt == static_cast<uint32_t>(ToNumber(nop_rt_reg)) &&
576               sa == type);
577 
578   return ret;
579 }
580 
581 
GetBranchOffset(Instr instr)582 int32_t Assembler::GetBranchOffset(Instr instr) {
583   DCHECK(IsBranch(instr));
584   return (static_cast<int16_t>(instr & kImm16Mask)) << 2;
585 }
586 
587 
IsLw(Instr instr)588 bool Assembler::IsLw(Instr instr) {
589   return ((instr & kOpcodeMask) == LW);
590 }
591 
592 
GetLwOffset(Instr instr)593 int16_t Assembler::GetLwOffset(Instr instr) {
594   DCHECK(IsLw(instr));
595   return ((instr & kImm16Mask));
596 }
597 
598 
SetLwOffset(Instr instr,int16_t offset)599 Instr Assembler::SetLwOffset(Instr instr, int16_t offset) {
600   DCHECK(IsLw(instr));
601 
602   // We actually create a new lw instruction based on the original one.
603   Instr temp_instr = LW | (instr & kRsFieldMask) | (instr & kRtFieldMask)
604       | (offset & kImm16Mask);
605 
606   return temp_instr;
607 }
608 
609 
IsSw(Instr instr)610 bool Assembler::IsSw(Instr instr) {
611   return ((instr & kOpcodeMask) == SW);
612 }
613 
614 
SetSwOffset(Instr instr,int16_t offset)615 Instr Assembler::SetSwOffset(Instr instr, int16_t offset) {
616   DCHECK(IsSw(instr));
617   return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
618 }
619 
620 
IsAddImmediate(Instr instr)621 bool Assembler::IsAddImmediate(Instr instr) {
622   return ((instr & kOpcodeMask) == ADDIU || (instr & kOpcodeMask) == DADDIU);
623 }
624 
625 
SetAddImmediateOffset(Instr instr,int16_t offset)626 Instr Assembler::SetAddImmediateOffset(Instr instr, int16_t offset) {
627   DCHECK(IsAddImmediate(instr));
628   return ((instr & ~kImm16Mask) | (offset & kImm16Mask));
629 }
630 
631 
IsAndImmediate(Instr instr)632 bool Assembler::IsAndImmediate(Instr instr) {
633   return GetOpcodeField(instr) == ANDI;
634 }
635 
636 
target_at(int64_t pos)637 int64_t Assembler::target_at(int64_t pos) {
638   Instr instr = instr_at(pos);
639   if ((instr & ~kImm16Mask) == 0) {
640     // Emitted label constant, not part of a branch.
641     if (instr == 0) {
642        return kEndOfChain;
643      } else {
644        int32_t imm18 =((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
645        return (imm18 + pos);
646      }
647   }
648   // Check we have a branch or jump instruction.
649   DCHECK(IsBranch(instr) || IsJ(instr) || IsLui(instr));
650   // Do NOT change this to <<2. We rely on arithmetic shifts here, assuming
651   // the compiler uses arithmetic shifts for signed integers.
652   if (IsBranch(instr)) {
653     int32_t imm18 = ((instr & static_cast<int32_t>(kImm16Mask)) << 16) >> 14;
654     if (imm18 == kEndOfChain) {
655       // EndOfChain sentinel is returned directly, not relative to pc or pos.
656       return kEndOfChain;
657     } else {
658       return pos + kBranchPCOffset + imm18;
659     }
660   } else if (IsLui(instr)) {
661     Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
662     Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
663     Instr instr_ori2 = instr_at(pos + 3 * Assembler::kInstrSize);
664     DCHECK(IsOri(instr_ori));
665     DCHECK(IsOri(instr_ori2));
666 
667     // TODO(plind) create named constants for shift values.
668     int64_t imm = static_cast<int64_t>(instr_lui & kImm16Mask) << 48;
669     imm |= static_cast<int64_t>(instr_ori & kImm16Mask) << 32;
670     imm |= static_cast<int64_t>(instr_ori2 & kImm16Mask) << 16;
671     // Sign extend address;
672     imm >>= 16;
673 
674     if (imm == kEndOfJumpChain) {
675       // EndOfChain sentinel is returned directly, not relative to pc or pos.
676       return kEndOfChain;
677     } else {
678       uint64_t instr_address = reinterpret_cast<int64_t>(buffer_ + pos);
679       int64_t delta = instr_address - imm;
680       DCHECK(pos > delta);
681       return pos - delta;
682     }
683   } else {
684     int32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
685     if (imm28 == kEndOfJumpChain) {
686       // EndOfChain sentinel is returned directly, not relative to pc or pos.
687       return kEndOfChain;
688     } else {
689       uint64_t instr_address = reinterpret_cast<int64_t>(buffer_ + pos);
690       instr_address &= kImm28Mask;
691       int64_t delta = instr_address - imm28;
692       DCHECK(pos > delta);
693       return pos - delta;
694     }
695   }
696 }
697 
698 
target_at_put(int64_t pos,int64_t target_pos)699 void Assembler::target_at_put(int64_t pos, int64_t target_pos) {
700   Instr instr = instr_at(pos);
701   if ((instr & ~kImm16Mask) == 0) {
702     DCHECK(target_pos == kEndOfChain || target_pos >= 0);
703     // Emitted label constant, not part of a branch.
704     // Make label relative to Code* of generated Code object.
705     instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
706     return;
707   }
708 
709   DCHECK(IsBranch(instr) || IsJ(instr) || IsLui(instr));
710   if (IsBranch(instr)) {
711     int32_t imm18 = target_pos - (pos + kBranchPCOffset);
712     DCHECK((imm18 & 3) == 0);
713 
714     instr &= ~kImm16Mask;
715     int32_t imm16 = imm18 >> 2;
716     DCHECK(is_int16(imm16));
717 
718     instr_at_put(pos, instr | (imm16 & kImm16Mask));
719   } else if (IsLui(instr)) {
720     Instr instr_lui = instr_at(pos + 0 * Assembler::kInstrSize);
721     Instr instr_ori = instr_at(pos + 1 * Assembler::kInstrSize);
722     Instr instr_ori2 = instr_at(pos + 3 * Assembler::kInstrSize);
723     DCHECK(IsOri(instr_ori));
724     DCHECK(IsOri(instr_ori2));
725 
726     uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos;
727     DCHECK((imm & 3) == 0);
728 
729     instr_lui &= ~kImm16Mask;
730     instr_ori &= ~kImm16Mask;
731     instr_ori2 &= ~kImm16Mask;
732 
733     instr_at_put(pos + 0 * Assembler::kInstrSize,
734                  instr_lui | ((imm >> 32) & kImm16Mask));
735     instr_at_put(pos + 1 * Assembler::kInstrSize,
736                  instr_ori | ((imm >> 16) & kImm16Mask));
737     instr_at_put(pos + 3 * Assembler::kInstrSize,
738                  instr_ori2 | (imm & kImm16Mask));
739   } else {
740     uint64_t imm28 = reinterpret_cast<uint64_t>(buffer_) + target_pos;
741     imm28 &= kImm28Mask;
742     DCHECK((imm28 & 3) == 0);
743 
744     instr &= ~kImm26Mask;
745     uint32_t imm26 = imm28 >> 2;
746     DCHECK(is_uint26(imm26));
747 
748     instr_at_put(pos, instr | (imm26 & kImm26Mask));
749   }
750 }
751 
752 
print(Label * L)753 void Assembler::print(Label* L) {
754   if (L->is_unused()) {
755     PrintF("unused label\n");
756   } else if (L->is_bound()) {
757     PrintF("bound label to %d\n", L->pos());
758   } else if (L->is_linked()) {
759     Label l = *L;
760     PrintF("unbound label");
761     while (l.is_linked()) {
762       PrintF("@ %d ", l.pos());
763       Instr instr = instr_at(l.pos());
764       if ((instr & ~kImm16Mask) == 0) {
765         PrintF("value\n");
766       } else {
767         PrintF("%d\n", instr);
768       }
769       next(&l);
770     }
771   } else {
772     PrintF("label in inconsistent state (pos = %d)\n", L->pos_);
773   }
774 }
775 
776 
bind_to(Label * L,int pos)777 void Assembler::bind_to(Label* L, int pos) {
778   DCHECK(0 <= pos && pos <= pc_offset());  // Must have valid binding position.
779   int32_t trampoline_pos = kInvalidSlotPos;
780   if (L->is_linked() && !trampoline_emitted_) {
781     unbound_labels_count_--;
782     next_buffer_check_ += kTrampolineSlotsSize;
783   }
784 
785   while (L->is_linked()) {
786     int32_t fixup_pos = L->pos();
787     int32_t dist = pos - fixup_pos;
788     next(L);  // Call next before overwriting link with target at fixup_pos.
789     Instr instr = instr_at(fixup_pos);
790     if (IsBranch(instr)) {
791       if (dist > kMaxBranchOffset) {
792         if (trampoline_pos == kInvalidSlotPos) {
793           trampoline_pos = get_trampoline_entry(fixup_pos);
794           CHECK(trampoline_pos != kInvalidSlotPos);
795         }
796         DCHECK((trampoline_pos - fixup_pos) <= kMaxBranchOffset);
797         target_at_put(fixup_pos, trampoline_pos);
798         fixup_pos = trampoline_pos;
799         dist = pos - fixup_pos;
800       }
801       target_at_put(fixup_pos, pos);
802     } else {
803       DCHECK(IsJ(instr) || IsLui(instr) || IsEmittedConstant(instr));
804       target_at_put(fixup_pos, pos);
805     }
806   }
807   L->bind_to(pos);
808 
809   // Keep track of the last bound label so we don't eliminate any instructions
810   // before a bound label.
811   if (pos > last_bound_pos_)
812     last_bound_pos_ = pos;
813 }
814 
815 
bind(Label * L)816 void Assembler::bind(Label* L) {
817   DCHECK(!L->is_bound());  // Label can only be bound once.
818   bind_to(L, pc_offset());
819 }
820 
821 
next(Label * L)822 void Assembler::next(Label* L) {
823   DCHECK(L->is_linked());
824   int link = target_at(L->pos());
825   if (link == kEndOfChain) {
826     L->Unuse();
827   } else {
828     DCHECK(link >= 0);
829     L->link_to(link);
830   }
831 }
832 
833 
is_near(Label * L)834 bool Assembler::is_near(Label* L) {
835   if (L->is_bound()) {
836     return ((pc_offset() - L->pos()) < kMaxBranchOffset - 4 * kInstrSize);
837   }
838   return false;
839 }
840 
841 
842 // We have to use a temporary register for things that can be relocated even
843 // if they can be encoded in the MIPS's 16 bits of immediate-offset instruction
844 // space.  There is no guarantee that the relocated location can be similarly
845 // encoded.
MustUseReg(RelocInfo::Mode rmode)846 bool Assembler::MustUseReg(RelocInfo::Mode rmode) {
847   return !RelocInfo::IsNone(rmode);
848 }
849 
GenInstrRegister(Opcode opcode,Register rs,Register rt,Register rd,uint16_t sa,SecondaryField func)850 void Assembler::GenInstrRegister(Opcode opcode,
851                                  Register rs,
852                                  Register rt,
853                                  Register rd,
854                                  uint16_t sa,
855                                  SecondaryField func) {
856   DCHECK(rd.is_valid() && rs.is_valid() && rt.is_valid() && is_uint5(sa));
857   Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
858       | (rd.code() << kRdShift) | (sa << kSaShift) | func;
859   emit(instr);
860 }
861 
862 
GenInstrRegister(Opcode opcode,Register rs,Register rt,uint16_t msb,uint16_t lsb,SecondaryField func)863 void Assembler::GenInstrRegister(Opcode opcode,
864                                  Register rs,
865                                  Register rt,
866                                  uint16_t msb,
867                                  uint16_t lsb,
868                                  SecondaryField func) {
869   DCHECK(rs.is_valid() && rt.is_valid() && is_uint5(msb) && is_uint5(lsb));
870   Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
871       | (msb << kRdShift) | (lsb << kSaShift) | func;
872   emit(instr);
873 }
874 
875 
GenInstrRegister(Opcode opcode,SecondaryField fmt,FPURegister ft,FPURegister fs,FPURegister fd,SecondaryField func)876 void Assembler::GenInstrRegister(Opcode opcode,
877                                  SecondaryField fmt,
878                                  FPURegister ft,
879                                  FPURegister fs,
880                                  FPURegister fd,
881                                  SecondaryField func) {
882   DCHECK(fd.is_valid() && fs.is_valid() && ft.is_valid());
883   Instr instr = opcode | fmt | (ft.code() << kFtShift) | (fs.code() << kFsShift)
884       | (fd.code() << kFdShift) | func;
885   emit(instr);
886 }
887 
888 
GenInstrRegister(Opcode opcode,FPURegister fr,FPURegister ft,FPURegister fs,FPURegister fd,SecondaryField func)889 void Assembler::GenInstrRegister(Opcode opcode,
890                                  FPURegister fr,
891                                  FPURegister ft,
892                                  FPURegister fs,
893                                  FPURegister fd,
894                                  SecondaryField func) {
895   DCHECK(fd.is_valid() && fr.is_valid() && fs.is_valid() && ft.is_valid());
896   Instr instr = opcode | (fr.code() << kFrShift) | (ft.code() << kFtShift)
897       | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
898   emit(instr);
899 }
900 
901 
GenInstrRegister(Opcode opcode,SecondaryField fmt,Register rt,FPURegister fs,FPURegister fd,SecondaryField func)902 void Assembler::GenInstrRegister(Opcode opcode,
903                                  SecondaryField fmt,
904                                  Register rt,
905                                  FPURegister fs,
906                                  FPURegister fd,
907                                  SecondaryField func) {
908   DCHECK(fd.is_valid() && fs.is_valid() && rt.is_valid());
909   Instr instr = opcode | fmt | (rt.code() << kRtShift)
910       | (fs.code() << kFsShift) | (fd.code() << kFdShift) | func;
911   emit(instr);
912 }
913 
914 
GenInstrRegister(Opcode opcode,SecondaryField fmt,Register rt,FPUControlRegister fs,SecondaryField func)915 void Assembler::GenInstrRegister(Opcode opcode,
916                                  SecondaryField fmt,
917                                  Register rt,
918                                  FPUControlRegister fs,
919                                  SecondaryField func) {
920   DCHECK(fs.is_valid() && rt.is_valid());
921   Instr instr =
922       opcode | fmt | (rt.code() << kRtShift) | (fs.code() << kFsShift) | func;
923   emit(instr);
924 }
925 
926 
927 // Instructions with immediate value.
928 // Registers are in the order of the instruction encoding, from left to right.
GenInstrImmediate(Opcode opcode,Register rs,Register rt,int32_t j)929 void Assembler::GenInstrImmediate(Opcode opcode,
930                                   Register rs,
931                                   Register rt,
932                                   int32_t j) {
933   DCHECK(rs.is_valid() && rt.is_valid() && (is_int16(j) || is_uint16(j)));
934   Instr instr = opcode | (rs.code() << kRsShift) | (rt.code() << kRtShift)
935       | (j & kImm16Mask);
936   emit(instr);
937 }
938 
939 
GenInstrImmediate(Opcode opcode,Register rs,SecondaryField SF,int32_t j)940 void Assembler::GenInstrImmediate(Opcode opcode,
941                                   Register rs,
942                                   SecondaryField SF,
943                                   int32_t j) {
944   DCHECK(rs.is_valid() && (is_int16(j) || is_uint16(j)));
945   Instr instr = opcode | (rs.code() << kRsShift) | SF | (j & kImm16Mask);
946   emit(instr);
947 }
948 
949 
GenInstrImmediate(Opcode opcode,Register rs,FPURegister ft,int32_t j)950 void Assembler::GenInstrImmediate(Opcode opcode,
951                                   Register rs,
952                                   FPURegister ft,
953                                   int32_t j) {
954   DCHECK(rs.is_valid() && ft.is_valid() && (is_int16(j) || is_uint16(j)));
955   Instr instr = opcode | (rs.code() << kRsShift) | (ft.code() << kFtShift)
956       | (j & kImm16Mask);
957   emit(instr);
958 }
959 
960 
GenInstrJump(Opcode opcode,uint32_t address)961 void Assembler::GenInstrJump(Opcode opcode,
962                              uint32_t address) {
963   BlockTrampolinePoolScope block_trampoline_pool(this);
964   DCHECK(is_uint26(address));
965   Instr instr = opcode | address;
966   emit(instr);
967   BlockTrampolinePoolFor(1);  // For associated delay slot.
968 }
969 
970 
971 // Returns the next free trampoline entry.
get_trampoline_entry(int32_t pos)972 int32_t Assembler::get_trampoline_entry(int32_t pos) {
973   int32_t trampoline_entry = kInvalidSlotPos;
974   if (!internal_trampoline_exception_) {
975     if (trampoline_.start() > pos) {
976      trampoline_entry = trampoline_.take_slot();
977     }
978 
979     if (kInvalidSlotPos == trampoline_entry) {
980       internal_trampoline_exception_ = true;
981     }
982   }
983   return trampoline_entry;
984 }
985 
986 
jump_address(Label * L)987 uint64_t Assembler::jump_address(Label* L) {
988   int64_t target_pos;
989   if (L->is_bound()) {
990     target_pos = L->pos();
991   } else {
992     if (L->is_linked()) {
993       target_pos = L->pos();  // L's link.
994       L->link_to(pc_offset());
995     } else {
996       L->link_to(pc_offset());
997       return kEndOfJumpChain;
998     }
999   }
1000 
1001   uint64_t imm = reinterpret_cast<uint64_t>(buffer_) + target_pos;
1002   DCHECK((imm & 3) == 0);
1003 
1004   return imm;
1005 }
1006 
1007 
branch_offset(Label * L,bool jump_elimination_allowed)1008 int32_t Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
1009   int32_t target_pos;
1010   if (L->is_bound()) {
1011     target_pos = L->pos();
1012   } else {
1013     if (L->is_linked()) {
1014       target_pos = L->pos();
1015       L->link_to(pc_offset());
1016     } else {
1017       L->link_to(pc_offset());
1018       if (!trampoline_emitted_) {
1019         unbound_labels_count_++;
1020         next_buffer_check_ -= kTrampolineSlotsSize;
1021       }
1022       return kEndOfChain;
1023     }
1024   }
1025 
1026   int32_t offset = target_pos - (pc_offset() + kBranchPCOffset);
1027   DCHECK((offset & 3) == 0);
1028   DCHECK(is_int16(offset >> 2));
1029 
1030   return offset;
1031 }
1032 
1033 
branch_offset_compact(Label * L,bool jump_elimination_allowed)1034 int32_t Assembler::branch_offset_compact(Label* L,
1035     bool jump_elimination_allowed) {
1036   int32_t target_pos;
1037   if (L->is_bound()) {
1038     target_pos = L->pos();
1039   } else {
1040     if (L->is_linked()) {
1041       target_pos = L->pos();
1042       L->link_to(pc_offset());
1043     } else {
1044       L->link_to(pc_offset());
1045       if (!trampoline_emitted_) {
1046         unbound_labels_count_++;
1047         next_buffer_check_ -= kTrampolineSlotsSize;
1048       }
1049       return kEndOfChain;
1050     }
1051   }
1052 
1053   int32_t offset = target_pos - pc_offset();
1054   DCHECK((offset & 3) == 0);
1055   DCHECK(is_int16(offset >> 2));
1056 
1057   return offset;
1058 }
1059 
1060 
branch_offset21(Label * L,bool jump_elimination_allowed)1061 int32_t Assembler::branch_offset21(Label* L, bool jump_elimination_allowed) {
1062   int32_t target_pos;
1063   if (L->is_bound()) {
1064     target_pos = L->pos();
1065   } else {
1066     if (L->is_linked()) {
1067       target_pos = L->pos();
1068       L->link_to(pc_offset());
1069     } else {
1070       L->link_to(pc_offset());
1071       if (!trampoline_emitted_) {
1072         unbound_labels_count_++;
1073         next_buffer_check_ -= kTrampolineSlotsSize;
1074       }
1075       return kEndOfChain;
1076     }
1077   }
1078 
1079   int32_t offset = target_pos - (pc_offset() + kBranchPCOffset);
1080   DCHECK((offset & 3) == 0);
1081   DCHECK(((offset >> 2) & 0xFFE00000) == 0);  // Offset is 21bit width.
1082 
1083   return offset;
1084 }
1085 
1086 
branch_offset21_compact(Label * L,bool jump_elimination_allowed)1087 int32_t Assembler::branch_offset21_compact(Label* L,
1088     bool jump_elimination_allowed) {
1089   int32_t target_pos;
1090   if (L->is_bound()) {
1091     target_pos = L->pos();
1092   } else {
1093     if (L->is_linked()) {
1094       target_pos = L->pos();
1095       L->link_to(pc_offset());
1096     } else {
1097       L->link_to(pc_offset());
1098       if (!trampoline_emitted_) {
1099         unbound_labels_count_++;
1100         next_buffer_check_ -= kTrampolineSlotsSize;
1101       }
1102       return kEndOfChain;
1103     }
1104   }
1105 
1106   int32_t offset = target_pos - pc_offset();
1107   DCHECK((offset & 3) == 0);
1108   DCHECK(((offset >> 2) & 0xFFE00000) == 0);  // Offset is 21bit width.
1109 
1110   return offset;
1111 }
1112 
1113 
label_at_put(Label * L,int at_offset)1114 void Assembler::label_at_put(Label* L, int at_offset) {
1115   int target_pos;
1116   if (L->is_bound()) {
1117     target_pos = L->pos();
1118     instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
1119   } else {
1120     if (L->is_linked()) {
1121       target_pos = L->pos();  // L's link.
1122       int32_t imm18 = target_pos - at_offset;
1123       DCHECK((imm18 & 3) == 0);
1124       int32_t imm16 = imm18 >> 2;
1125       DCHECK(is_int16(imm16));
1126       instr_at_put(at_offset, (imm16 & kImm16Mask));
1127     } else {
1128       target_pos = kEndOfChain;
1129       instr_at_put(at_offset, 0);
1130       if (!trampoline_emitted_) {
1131         unbound_labels_count_++;
1132         next_buffer_check_ -= kTrampolineSlotsSize;
1133       }
1134     }
1135     L->link_to(at_offset);
1136   }
1137 }
1138 
1139 
1140 //------- Branch and jump instructions --------
1141 
b(int16_t offset)1142 void Assembler::b(int16_t offset) {
1143   beq(zero_reg, zero_reg, offset);
1144 }
1145 
1146 
bal(int16_t offset)1147 void Assembler::bal(int16_t offset) {
1148   positions_recorder()->WriteRecordedPositions();
1149   bgezal(zero_reg, offset);
1150 }
1151 
1152 
beq(Register rs,Register rt,int16_t offset)1153 void Assembler::beq(Register rs, Register rt, int16_t offset) {
1154   BlockTrampolinePoolScope block_trampoline_pool(this);
1155   GenInstrImmediate(BEQ, rs, rt, offset);
1156   BlockTrampolinePoolFor(1);  // For associated delay slot.
1157 }
1158 
1159 
bgez(Register rs,int16_t offset)1160 void Assembler::bgez(Register rs, int16_t offset) {
1161   BlockTrampolinePoolScope block_trampoline_pool(this);
1162   GenInstrImmediate(REGIMM, rs, BGEZ, offset);
1163   BlockTrampolinePoolFor(1);  // For associated delay slot.
1164 }
1165 
1166 
bgezc(Register rt,int16_t offset)1167 void Assembler::bgezc(Register rt, int16_t offset) {
1168   DCHECK(kArchVariant == kMips64r6);
1169   DCHECK(!(rt.is(zero_reg)));
1170   GenInstrImmediate(BLEZL, rt, rt, offset);
1171 }
1172 
1173 
bgeuc(Register rs,Register rt,int16_t offset)1174 void Assembler::bgeuc(Register rs, Register rt, int16_t offset) {
1175   DCHECK(kArchVariant == kMips64r6);
1176   DCHECK(!(rs.is(zero_reg)));
1177   DCHECK(!(rt.is(zero_reg)));
1178   DCHECK(rs.code() != rt.code());
1179   GenInstrImmediate(BLEZ, rs, rt, offset);
1180 }
1181 
1182 
bgec(Register rs,Register rt,int16_t offset)1183 void Assembler::bgec(Register rs, Register rt, int16_t offset) {
1184   DCHECK(kArchVariant == kMips64r6);
1185   DCHECK(!(rs.is(zero_reg)));
1186   DCHECK(!(rt.is(zero_reg)));
1187   DCHECK(rs.code() != rt.code());
1188   GenInstrImmediate(BLEZL, rs, rt, offset);
1189 }
1190 
1191 
bgezal(Register rs,int16_t offset)1192 void Assembler::bgezal(Register rs, int16_t offset) {
1193   DCHECK(kArchVariant != kMips64r6 || rs.is(zero_reg));
1194   BlockTrampolinePoolScope block_trampoline_pool(this);
1195   positions_recorder()->WriteRecordedPositions();
1196   GenInstrImmediate(REGIMM, rs, BGEZAL, offset);
1197   BlockTrampolinePoolFor(1);  // For associated delay slot.
1198 }
1199 
1200 
bgtz(Register rs,int16_t offset)1201 void Assembler::bgtz(Register rs, int16_t offset) {
1202   BlockTrampolinePoolScope block_trampoline_pool(this);
1203   GenInstrImmediate(BGTZ, rs, zero_reg, offset);
1204   BlockTrampolinePoolFor(1);  // For associated delay slot.
1205 }
1206 
1207 
bgtzc(Register rt,int16_t offset)1208 void Assembler::bgtzc(Register rt, int16_t offset) {
1209   DCHECK(kArchVariant == kMips64r6);
1210   DCHECK(!(rt.is(zero_reg)));
1211   GenInstrImmediate(BGTZL, zero_reg, rt, offset);
1212 }
1213 
1214 
blez(Register rs,int16_t offset)1215 void Assembler::blez(Register rs, int16_t offset) {
1216   BlockTrampolinePoolScope block_trampoline_pool(this);
1217   GenInstrImmediate(BLEZ, rs, zero_reg, offset);
1218   BlockTrampolinePoolFor(1);  // For associated delay slot.
1219 }
1220 
1221 
blezc(Register rt,int16_t offset)1222 void Assembler::blezc(Register rt, int16_t offset) {
1223   DCHECK(kArchVariant == kMips64r6);
1224   DCHECK(!(rt.is(zero_reg)));
1225   GenInstrImmediate(BLEZL, zero_reg, rt, offset);
1226 }
1227 
1228 
bltzc(Register rt,int16_t offset)1229 void Assembler::bltzc(Register rt, int16_t offset) {
1230   DCHECK(kArchVariant == kMips64r6);
1231   DCHECK(!(rt.is(zero_reg)));
1232   GenInstrImmediate(BGTZL, rt, rt, offset);
1233 }
1234 
1235 
bltuc(Register rs,Register rt,int16_t offset)1236 void Assembler::bltuc(Register rs, Register rt, int16_t offset) {
1237   DCHECK(kArchVariant == kMips64r6);
1238   DCHECK(!(rs.is(zero_reg)));
1239   DCHECK(!(rt.is(zero_reg)));
1240   DCHECK(rs.code() != rt.code());
1241   GenInstrImmediate(BGTZ, rs, rt, offset);
1242 }
1243 
1244 
bltc(Register rs,Register rt,int16_t offset)1245 void Assembler::bltc(Register rs, Register rt, int16_t offset) {
1246   DCHECK(kArchVariant == kMips64r6);
1247   DCHECK(!(rs.is(zero_reg)));
1248   DCHECK(!(rt.is(zero_reg)));
1249   DCHECK(rs.code() != rt.code());
1250   GenInstrImmediate(BGTZL, rs, rt, offset);
1251 }
1252 
1253 
bltz(Register rs,int16_t offset)1254 void Assembler::bltz(Register rs, int16_t offset) {
1255   BlockTrampolinePoolScope block_trampoline_pool(this);
1256   GenInstrImmediate(REGIMM, rs, BLTZ, offset);
1257   BlockTrampolinePoolFor(1);  // For associated delay slot.
1258 }
1259 
1260 
bltzal(Register rs,int16_t offset)1261 void Assembler::bltzal(Register rs, int16_t offset) {
1262   DCHECK(kArchVariant != kMips64r6 || rs.is(zero_reg));
1263   BlockTrampolinePoolScope block_trampoline_pool(this);
1264   positions_recorder()->WriteRecordedPositions();
1265   GenInstrImmediate(REGIMM, rs, BLTZAL, offset);
1266   BlockTrampolinePoolFor(1);  // For associated delay slot.
1267 }
1268 
1269 
bne(Register rs,Register rt,int16_t offset)1270 void Assembler::bne(Register rs, Register rt, int16_t offset) {
1271   BlockTrampolinePoolScope block_trampoline_pool(this);
1272   GenInstrImmediate(BNE, rs, rt, offset);
1273   BlockTrampolinePoolFor(1);  // For associated delay slot.
1274 }
1275 
1276 
bovc(Register rs,Register rt,int16_t offset)1277 void Assembler::bovc(Register rs, Register rt, int16_t offset) {
1278   DCHECK(kArchVariant == kMips64r6);
1279   DCHECK(!(rs.is(zero_reg)));
1280   DCHECK(rs.code() >= rt.code());
1281   GenInstrImmediate(ADDI, rs, rt, offset);
1282 }
1283 
1284 
bnvc(Register rs,Register rt,int16_t offset)1285 void Assembler::bnvc(Register rs, Register rt, int16_t offset) {
1286   DCHECK(kArchVariant == kMips64r6);
1287   DCHECK(!(rs.is(zero_reg)));
1288   DCHECK(rs.code() >= rt.code());
1289   GenInstrImmediate(DADDI, rs, rt, offset);
1290 }
1291 
1292 
blezalc(Register rt,int16_t offset)1293 void Assembler::blezalc(Register rt, int16_t offset) {
1294   DCHECK(kArchVariant == kMips64r6);
1295   DCHECK(!(rt.is(zero_reg)));
1296   GenInstrImmediate(BLEZ, zero_reg, rt, offset);
1297 }
1298 
1299 
bgezalc(Register rt,int16_t offset)1300 void Assembler::bgezalc(Register rt, int16_t offset) {
1301   DCHECK(kArchVariant == kMips64r6);
1302   DCHECK(!(rt.is(zero_reg)));
1303   GenInstrImmediate(BLEZ, rt, rt, offset);
1304 }
1305 
1306 
bgezall(Register rs,int16_t offset)1307 void Assembler::bgezall(Register rs, int16_t offset) {
1308   DCHECK(kArchVariant == kMips64r6);
1309   DCHECK(!(rs.is(zero_reg)));
1310   GenInstrImmediate(REGIMM, rs, BGEZALL, offset);
1311 }
1312 
1313 
bltzalc(Register rt,int16_t offset)1314 void Assembler::bltzalc(Register rt, int16_t offset) {
1315   DCHECK(kArchVariant == kMips64r6);
1316   DCHECK(!(rt.is(zero_reg)));
1317   GenInstrImmediate(BGTZ, rt, rt, offset);
1318 }
1319 
1320 
bgtzalc(Register rt,int16_t offset)1321 void Assembler::bgtzalc(Register rt, int16_t offset) {
1322   DCHECK(kArchVariant == kMips64r6);
1323   DCHECK(!(rt.is(zero_reg)));
1324   GenInstrImmediate(BGTZ, zero_reg, rt, offset);
1325 }
1326 
1327 
beqzalc(Register rt,int16_t offset)1328 void Assembler::beqzalc(Register rt, int16_t offset) {
1329   DCHECK(kArchVariant == kMips64r6);
1330   DCHECK(!(rt.is(zero_reg)));
1331   GenInstrImmediate(ADDI, zero_reg, rt, offset);
1332 }
1333 
1334 
bnezalc(Register rt,int16_t offset)1335 void Assembler::bnezalc(Register rt, int16_t offset) {
1336   DCHECK(kArchVariant == kMips64r6);
1337   DCHECK(!(rt.is(zero_reg)));
1338   GenInstrImmediate(DADDI, zero_reg, rt, offset);
1339 }
1340 
1341 
beqc(Register rs,Register rt,int16_t offset)1342 void Assembler::beqc(Register rs, Register rt, int16_t offset) {
1343   DCHECK(kArchVariant == kMips64r6);
1344   DCHECK(rs.code() < rt.code());
1345   GenInstrImmediate(ADDI, rs, rt, offset);
1346 }
1347 
1348 
beqzc(Register rs,int32_t offset)1349 void Assembler::beqzc(Register rs, int32_t offset) {
1350   DCHECK(kArchVariant == kMips64r6);
1351   DCHECK(!(rs.is(zero_reg)));
1352   Instr instr = BEQZC | (rs.code() << kRsShift) | offset;
1353   emit(instr);
1354 }
1355 
1356 
bnec(Register rs,Register rt,int16_t offset)1357 void Assembler::bnec(Register rs, Register rt, int16_t offset) {
1358   DCHECK(kArchVariant == kMips64r6);
1359   DCHECK(rs.code() < rt.code());
1360   GenInstrImmediate(DADDI, rs, rt, offset);
1361 }
1362 
1363 
bnezc(Register rs,int32_t offset)1364 void Assembler::bnezc(Register rs, int32_t offset) {
1365   DCHECK(kArchVariant == kMips64r6);
1366   DCHECK(!(rs.is(zero_reg)));
1367   Instr instr = BNEZC | (rs.code() << kRsShift) | offset;
1368   emit(instr);
1369 }
1370 
1371 
j(int64_t target)1372 void Assembler::j(int64_t target) {
1373 #if DEBUG
1374   // Get pc of delay slot.
1375   uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize);
1376   bool in_range = (ipc ^ static_cast<uint64_t>(target) >>
1377                   (kImm26Bits + kImmFieldShift)) == 0;
1378   DCHECK(in_range && ((target & 3) == 0));
1379 #endif
1380   GenInstrJump(J, target >> 2);
1381 }
1382 
1383 
jr(Register rs)1384 void Assembler::jr(Register rs) {
1385   if (kArchVariant != kMips64r6) {
1386     BlockTrampolinePoolScope block_trampoline_pool(this);
1387     if (rs.is(ra)) {
1388       positions_recorder()->WriteRecordedPositions();
1389     }
1390     GenInstrRegister(SPECIAL, rs, zero_reg, zero_reg, 0, JR);
1391     BlockTrampolinePoolFor(1);  // For associated delay slot.
1392   } else {
1393     jalr(rs, zero_reg);
1394   }
1395 }
1396 
1397 
jal(int64_t target)1398 void Assembler::jal(int64_t target) {
1399 #ifdef DEBUG
1400   // Get pc of delay slot.
1401   uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize);
1402   bool in_range = (ipc ^ static_cast<uint64_t>(target) >>
1403                   (kImm26Bits + kImmFieldShift)) == 0;
1404   DCHECK(in_range && ((target & 3) == 0));
1405 #endif
1406   positions_recorder()->WriteRecordedPositions();
1407   GenInstrJump(JAL, target >> 2);
1408 }
1409 
1410 
jalr(Register rs,Register rd)1411 void Assembler::jalr(Register rs, Register rd) {
1412   BlockTrampolinePoolScope block_trampoline_pool(this);
1413   positions_recorder()->WriteRecordedPositions();
1414   GenInstrRegister(SPECIAL, rs, zero_reg, rd, 0, JALR);
1415   BlockTrampolinePoolFor(1);  // For associated delay slot.
1416 }
1417 
1418 
j_or_jr(int64_t target,Register rs)1419 void Assembler::j_or_jr(int64_t target, Register rs) {
1420   // Get pc of delay slot.
1421   uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize);
1422   bool in_range = (ipc ^ static_cast<uint64_t>(target) >>
1423                   (kImm26Bits + kImmFieldShift)) == 0;
1424   if (in_range) {
1425       j(target);
1426   } else {
1427       jr(t9);
1428   }
1429 }
1430 
1431 
jal_or_jalr(int64_t target,Register rs)1432 void Assembler::jal_or_jalr(int64_t target, Register rs) {
1433   // Get pc of delay slot.
1434   uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize);
1435   bool in_range = (ipc ^ static_cast<uint64_t>(target) >>
1436                   (kImm26Bits+kImmFieldShift)) == 0;
1437   if (in_range) {
1438       jal(target);
1439   } else {
1440       jalr(t9);
1441   }
1442 }
1443 
1444 
1445 // -------Data-processing-instructions---------
1446 
1447 // Arithmetic.
1448 
addu(Register rd,Register rs,Register rt)1449 void Assembler::addu(Register rd, Register rs, Register rt) {
1450   GenInstrRegister(SPECIAL, rs, rt, rd, 0, ADDU);
1451 }
1452 
1453 
addiu(Register rd,Register rs,int32_t j)1454 void Assembler::addiu(Register rd, Register rs, int32_t j) {
1455   GenInstrImmediate(ADDIU, rs, rd, j);
1456 }
1457 
1458 
subu(Register rd,Register rs,Register rt)1459 void Assembler::subu(Register rd, Register rs, Register rt) {
1460   GenInstrRegister(SPECIAL, rs, rt, rd, 0, SUBU);
1461 }
1462 
1463 
mul(Register rd,Register rs,Register rt)1464 void Assembler::mul(Register rd, Register rs, Register rt) {
1465   if (kArchVariant == kMips64r6) {
1466       GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH);
1467   } else {
1468       GenInstrRegister(SPECIAL2, rs, rt, rd, 0, MUL);
1469   }
1470 }
1471 
1472 
muh(Register rd,Register rs,Register rt)1473 void Assembler::muh(Register rd, Register rs, Register rt) {
1474   DCHECK(kArchVariant == kMips64r6);
1475   GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH);
1476 }
1477 
1478 
mulu(Register rd,Register rs,Register rt)1479 void Assembler::mulu(Register rd, Register rs, Register rt) {
1480   DCHECK(kArchVariant == kMips64r6);
1481   GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, MUL_MUH_U);
1482 }
1483 
1484 
muhu(Register rd,Register rs,Register rt)1485 void Assembler::muhu(Register rd, Register rs, Register rt) {
1486   DCHECK(kArchVariant == kMips64r6);
1487   GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, MUL_MUH_U);
1488 }
1489 
1490 
dmul(Register rd,Register rs,Register rt)1491 void Assembler::dmul(Register rd, Register rs, Register rt) {
1492   DCHECK(kArchVariant == kMips64r6);
1493   GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, D_MUL_MUH);
1494 }
1495 
1496 
dmuh(Register rd,Register rs,Register rt)1497 void Assembler::dmuh(Register rd, Register rs, Register rt) {
1498   DCHECK(kArchVariant == kMips64r6);
1499   GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, D_MUL_MUH);
1500 }
1501 
1502 
dmulu(Register rd,Register rs,Register rt)1503 void Assembler::dmulu(Register rd, Register rs, Register rt) {
1504   DCHECK(kArchVariant == kMips64r6);
1505   GenInstrRegister(SPECIAL, rs, rt, rd, MUL_OP, D_MUL_MUH_U);
1506 }
1507 
1508 
dmuhu(Register rd,Register rs,Register rt)1509 void Assembler::dmuhu(Register rd, Register rs, Register rt) {
1510   DCHECK(kArchVariant == kMips64r6);
1511   GenInstrRegister(SPECIAL, rs, rt, rd, MUH_OP, D_MUL_MUH_U);
1512 }
1513 
1514 
mult(Register rs,Register rt)1515 void Assembler::mult(Register rs, Register rt) {
1516   DCHECK(kArchVariant != kMips64r6);
1517   GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULT);
1518 }
1519 
1520 
multu(Register rs,Register rt)1521 void Assembler::multu(Register rs, Register rt) {
1522   DCHECK(kArchVariant != kMips64r6);
1523   GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, MULTU);
1524 }
1525 
1526 
daddiu(Register rd,Register rs,int32_t j)1527 void Assembler::daddiu(Register rd, Register rs, int32_t j) {
1528   GenInstrImmediate(DADDIU, rs, rd, j);
1529 }
1530 
1531 
div(Register rs,Register rt)1532 void Assembler::div(Register rs, Register rt) {
1533   GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIV);
1534 }
1535 
1536 
div(Register rd,Register rs,Register rt)1537 void Assembler::div(Register rd, Register rs, Register rt) {
1538   DCHECK(kArchVariant == kMips64r6);
1539   GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD);
1540 }
1541 
1542 
mod(Register rd,Register rs,Register rt)1543 void Assembler::mod(Register rd, Register rs, Register rt) {
1544   DCHECK(kArchVariant == kMips64r6);
1545   GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD);
1546 }
1547 
1548 
divu(Register rs,Register rt)1549 void Assembler::divu(Register rs, Register rt) {
1550   GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DIVU);
1551 }
1552 
1553 
divu(Register rd,Register rs,Register rt)1554 void Assembler::divu(Register rd, Register rs, Register rt) {
1555   DCHECK(kArchVariant == kMips64r6);
1556   GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, DIV_MOD_U);
1557 }
1558 
1559 
modu(Register rd,Register rs,Register rt)1560 void Assembler::modu(Register rd, Register rs, Register rt) {
1561   DCHECK(kArchVariant == kMips64r6);
1562   GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, DIV_MOD_U);
1563 }
1564 
1565 
daddu(Register rd,Register rs,Register rt)1566 void Assembler::daddu(Register rd, Register rs, Register rt) {
1567   GenInstrRegister(SPECIAL, rs, rt, rd, 0, DADDU);
1568 }
1569 
1570 
dsubu(Register rd,Register rs,Register rt)1571 void Assembler::dsubu(Register rd, Register rs, Register rt) {
1572   GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSUBU);
1573 }
1574 
1575 
dmult(Register rs,Register rt)1576 void Assembler::dmult(Register rs, Register rt) {
1577   GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DMULT);
1578 }
1579 
1580 
dmultu(Register rs,Register rt)1581 void Assembler::dmultu(Register rs, Register rt) {
1582   GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DMULTU);
1583 }
1584 
1585 
ddiv(Register rs,Register rt)1586 void Assembler::ddiv(Register rs, Register rt) {
1587   GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DDIV);
1588 }
1589 
1590 
ddiv(Register rd,Register rs,Register rt)1591 void Assembler::ddiv(Register rd, Register rs, Register rt) {
1592   DCHECK(kArchVariant == kMips64r6);
1593   GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, D_DIV_MOD);
1594 }
1595 
1596 
dmod(Register rd,Register rs,Register rt)1597 void Assembler::dmod(Register rd, Register rs, Register rt) {
1598   DCHECK(kArchVariant == kMips64r6);
1599   GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, D_DIV_MOD);
1600 }
1601 
1602 
ddivu(Register rs,Register rt)1603 void Assembler::ddivu(Register rs, Register rt) {
1604   GenInstrRegister(SPECIAL, rs, rt, zero_reg, 0, DDIVU);
1605 }
1606 
1607 
ddivu(Register rd,Register rs,Register rt)1608 void Assembler::ddivu(Register rd, Register rs, Register rt) {
1609   DCHECK(kArchVariant == kMips64r6);
1610   GenInstrRegister(SPECIAL, rs, rt, rd, DIV_OP, D_DIV_MOD_U);
1611 }
1612 
1613 
dmodu(Register rd,Register rs,Register rt)1614 void Assembler::dmodu(Register rd, Register rs, Register rt) {
1615   DCHECK(kArchVariant == kMips64r6);
1616   GenInstrRegister(SPECIAL, rs, rt, rd, MOD_OP, D_DIV_MOD_U);
1617 }
1618 
1619 
1620 // Logical.
1621 
and_(Register rd,Register rs,Register rt)1622 void Assembler::and_(Register rd, Register rs, Register rt) {
1623   GenInstrRegister(SPECIAL, rs, rt, rd, 0, AND);
1624 }
1625 
1626 
andi(Register rt,Register rs,int32_t j)1627 void Assembler::andi(Register rt, Register rs, int32_t j) {
1628   DCHECK(is_uint16(j));
1629   GenInstrImmediate(ANDI, rs, rt, j);
1630 }
1631 
1632 
or_(Register rd,Register rs,Register rt)1633 void Assembler::or_(Register rd, Register rs, Register rt) {
1634   GenInstrRegister(SPECIAL, rs, rt, rd, 0, OR);
1635 }
1636 
1637 
ori(Register rt,Register rs,int32_t j)1638 void Assembler::ori(Register rt, Register rs, int32_t j) {
1639   DCHECK(is_uint16(j));
1640   GenInstrImmediate(ORI, rs, rt, j);
1641 }
1642 
1643 
xor_(Register rd,Register rs,Register rt)1644 void Assembler::xor_(Register rd, Register rs, Register rt) {
1645   GenInstrRegister(SPECIAL, rs, rt, rd, 0, XOR);
1646 }
1647 
1648 
xori(Register rt,Register rs,int32_t j)1649 void Assembler::xori(Register rt, Register rs, int32_t j) {
1650   DCHECK(is_uint16(j));
1651   GenInstrImmediate(XORI, rs, rt, j);
1652 }
1653 
1654 
nor(Register rd,Register rs,Register rt)1655 void Assembler::nor(Register rd, Register rs, Register rt) {
1656   GenInstrRegister(SPECIAL, rs, rt, rd, 0, NOR);
1657 }
1658 
1659 
1660 // Shifts.
sll(Register rd,Register rt,uint16_t sa,bool coming_from_nop)1661 void Assembler::sll(Register rd,
1662                     Register rt,
1663                     uint16_t sa,
1664                     bool coming_from_nop) {
1665   // Don't allow nop instructions in the form sll zero_reg, zero_reg to be
1666   // generated using the sll instruction. They must be generated using
1667   // nop(int/NopMarkerTypes) or MarkCode(int/NopMarkerTypes) pseudo
1668   // instructions.
1669   DCHECK(coming_from_nop || !(rd.is(zero_reg) && rt.is(zero_reg)));
1670   GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SLL);
1671 }
1672 
1673 
sllv(Register rd,Register rt,Register rs)1674 void Assembler::sllv(Register rd, Register rt, Register rs) {
1675   GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLLV);
1676 }
1677 
1678 
srl(Register rd,Register rt,uint16_t sa)1679 void Assembler::srl(Register rd, Register rt, uint16_t sa) {
1680   GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SRL);
1681 }
1682 
1683 
srlv(Register rd,Register rt,Register rs)1684 void Assembler::srlv(Register rd, Register rt, Register rs) {
1685   GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRLV);
1686 }
1687 
1688 
sra(Register rd,Register rt,uint16_t sa)1689 void Assembler::sra(Register rd, Register rt, uint16_t sa) {
1690   GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, SRA);
1691 }
1692 
1693 
srav(Register rd,Register rt,Register rs)1694 void Assembler::srav(Register rd, Register rt, Register rs) {
1695   GenInstrRegister(SPECIAL, rs, rt, rd, 0, SRAV);
1696 }
1697 
1698 
rotr(Register rd,Register rt,uint16_t sa)1699 void Assembler::rotr(Register rd, Register rt, uint16_t sa) {
1700   // Should be called via MacroAssembler::Ror.
1701   DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
1702   DCHECK(kArchVariant == kMips64r2);
1703   Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1704       | (rd.code() << kRdShift) | (sa << kSaShift) | SRL;
1705   emit(instr);
1706 }
1707 
1708 
rotrv(Register rd,Register rt,Register rs)1709 void Assembler::rotrv(Register rd, Register rt, Register rs) {
1710   // Should be called via MacroAssembler::Ror.
1711   DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid() );
1712   DCHECK(kArchVariant == kMips64r2);
1713   Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1714      | (rd.code() << kRdShift) | (1 << kSaShift) | SRLV;
1715   emit(instr);
1716 }
1717 
1718 
dsll(Register rd,Register rt,uint16_t sa)1719 void Assembler::dsll(Register rd, Register rt, uint16_t sa) {
1720   GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, DSLL);
1721 }
1722 
1723 
dsllv(Register rd,Register rt,Register rs)1724 void Assembler::dsllv(Register rd, Register rt, Register rs) {
1725   GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSLLV);
1726 }
1727 
1728 
dsrl(Register rd,Register rt,uint16_t sa)1729 void Assembler::dsrl(Register rd, Register rt, uint16_t sa) {
1730   GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, DSRL);
1731 }
1732 
1733 
dsrlv(Register rd,Register rt,Register rs)1734 void Assembler::dsrlv(Register rd, Register rt, Register rs) {
1735   GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSRLV);
1736 }
1737 
1738 
drotr(Register rd,Register rt,uint16_t sa)1739 void Assembler::drotr(Register rd, Register rt, uint16_t sa) {
1740   DCHECK(rd.is_valid() && rt.is_valid() && is_uint5(sa));
1741   Instr instr = SPECIAL | (1 << kRsShift) | (rt.code() << kRtShift)
1742       | (rd.code() << kRdShift) | (sa << kSaShift) | DSRL;
1743   emit(instr);
1744 }
1745 
1746 
drotrv(Register rd,Register rt,Register rs)1747 void Assembler::drotrv(Register rd, Register rt, Register rs) {
1748   DCHECK(rd.is_valid() && rt.is_valid() && rs.is_valid() );
1749   Instr instr = SPECIAL | (rs.code() << kRsShift) | (rt.code() << kRtShift)
1750       | (rd.code() << kRdShift) | (1 << kSaShift) | DSRLV;
1751   emit(instr);
1752 }
1753 
1754 
dsra(Register rd,Register rt,uint16_t sa)1755 void Assembler::dsra(Register rd, Register rt, uint16_t sa) {
1756   GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, DSRA);
1757 }
1758 
1759 
dsrav(Register rd,Register rt,Register rs)1760 void Assembler::dsrav(Register rd, Register rt, Register rs) {
1761   GenInstrRegister(SPECIAL, rs, rt, rd, 0, DSRAV);
1762 }
1763 
1764 
dsll32(Register rd,Register rt,uint16_t sa)1765 void Assembler::dsll32(Register rd, Register rt, uint16_t sa) {
1766   GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, DSLL32);
1767 }
1768 
1769 
dsrl32(Register rd,Register rt,uint16_t sa)1770 void Assembler::dsrl32(Register rd, Register rt, uint16_t sa) {
1771   GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, DSRL32);
1772 }
1773 
1774 
dsra32(Register rd,Register rt,uint16_t sa)1775 void Assembler::dsra32(Register rd, Register rt, uint16_t sa) {
1776   GenInstrRegister(SPECIAL, zero_reg, rt, rd, sa, DSRA32);
1777 }
1778 
1779 
1780 // ------------Memory-instructions-------------
1781 
1782 // Helper for base-reg + offset, when offset is larger than int16.
LoadRegPlusOffsetToAt(const MemOperand & src)1783 void Assembler::LoadRegPlusOffsetToAt(const MemOperand& src) {
1784   DCHECK(!src.rm().is(at));
1785   DCHECK(is_int32(src.offset_));
1786   daddiu(at, zero_reg, (src.offset_ >> kLuiShift) & kImm16Mask);
1787   dsll(at, at, kLuiShift);
1788   ori(at, at, src.offset_ & kImm16Mask);  // Load 32-bit offset.
1789   daddu(at, at, src.rm());  // Add base register.
1790 }
1791 
1792 
lb(Register rd,const MemOperand & rs)1793 void Assembler::lb(Register rd, const MemOperand& rs) {
1794   if (is_int16(rs.offset_)) {
1795     GenInstrImmediate(LB, rs.rm(), rd, rs.offset_);
1796   } else {  // Offset > 16 bits, use multiple instructions to load.
1797     LoadRegPlusOffsetToAt(rs);
1798     GenInstrImmediate(LB, at, rd, 0);  // Equiv to lb(rd, MemOperand(at, 0));
1799   }
1800 }
1801 
1802 
lbu(Register rd,const MemOperand & rs)1803 void Assembler::lbu(Register rd, const MemOperand& rs) {
1804   if (is_int16(rs.offset_)) {
1805     GenInstrImmediate(LBU, rs.rm(), rd, rs.offset_);
1806   } else {  // Offset > 16 bits, use multiple instructions to load.
1807     LoadRegPlusOffsetToAt(rs);
1808     GenInstrImmediate(LBU, at, rd, 0);  // Equiv to lbu(rd, MemOperand(at, 0));
1809   }
1810 }
1811 
1812 
lh(Register rd,const MemOperand & rs)1813 void Assembler::lh(Register rd, const MemOperand& rs) {
1814   if (is_int16(rs.offset_)) {
1815     GenInstrImmediate(LH, rs.rm(), rd, rs.offset_);
1816   } else {  // Offset > 16 bits, use multiple instructions to load.
1817     LoadRegPlusOffsetToAt(rs);
1818     GenInstrImmediate(LH, at, rd, 0);  // Equiv to lh(rd, MemOperand(at, 0));
1819   }
1820 }
1821 
1822 
lhu(Register rd,const MemOperand & rs)1823 void Assembler::lhu(Register rd, const MemOperand& rs) {
1824   if (is_int16(rs.offset_)) {
1825     GenInstrImmediate(LHU, rs.rm(), rd, rs.offset_);
1826   } else {  // Offset > 16 bits, use multiple instructions to load.
1827     LoadRegPlusOffsetToAt(rs);
1828     GenInstrImmediate(LHU, at, rd, 0);  // Equiv to lhu(rd, MemOperand(at, 0));
1829   }
1830 }
1831 
1832 
lw(Register rd,const MemOperand & rs)1833 void Assembler::lw(Register rd, const MemOperand& rs) {
1834   if (is_int16(rs.offset_)) {
1835     GenInstrImmediate(LW, rs.rm(), rd, rs.offset_);
1836   } else {  // Offset > 16 bits, use multiple instructions to load.
1837     LoadRegPlusOffsetToAt(rs);
1838     GenInstrImmediate(LW, at, rd, 0);  // Equiv to lw(rd, MemOperand(at, 0));
1839   }
1840 }
1841 
1842 
lwu(Register rd,const MemOperand & rs)1843 void Assembler::lwu(Register rd, const MemOperand& rs) {
1844   if (is_int16(rs.offset_)) {
1845     GenInstrImmediate(LWU, rs.rm(), rd, rs.offset_);
1846   } else {  // Offset > 16 bits, use multiple instructions to load.
1847     LoadRegPlusOffsetToAt(rs);
1848     GenInstrImmediate(LWU, at, rd, 0);  // Equiv to lwu(rd, MemOperand(at, 0));
1849   }
1850 }
1851 
1852 
lwl(Register rd,const MemOperand & rs)1853 void Assembler::lwl(Register rd, const MemOperand& rs) {
1854   GenInstrImmediate(LWL, rs.rm(), rd, rs.offset_);
1855 }
1856 
1857 
lwr(Register rd,const MemOperand & rs)1858 void Assembler::lwr(Register rd, const MemOperand& rs) {
1859   GenInstrImmediate(LWR, rs.rm(), rd, rs.offset_);
1860 }
1861 
1862 
sb(Register rd,const MemOperand & rs)1863 void Assembler::sb(Register rd, const MemOperand& rs) {
1864   if (is_int16(rs.offset_)) {
1865     GenInstrImmediate(SB, rs.rm(), rd, rs.offset_);
1866   } else {  // Offset > 16 bits, use multiple instructions to store.
1867     LoadRegPlusOffsetToAt(rs);
1868     GenInstrImmediate(SB, at, rd, 0);  // Equiv to sb(rd, MemOperand(at, 0));
1869   }
1870 }
1871 
1872 
sh(Register rd,const MemOperand & rs)1873 void Assembler::sh(Register rd, const MemOperand& rs) {
1874   if (is_int16(rs.offset_)) {
1875     GenInstrImmediate(SH, rs.rm(), rd, rs.offset_);
1876   } else {  // Offset > 16 bits, use multiple instructions to store.
1877     LoadRegPlusOffsetToAt(rs);
1878     GenInstrImmediate(SH, at, rd, 0);  // Equiv to sh(rd, MemOperand(at, 0));
1879   }
1880 }
1881 
1882 
sw(Register rd,const MemOperand & rs)1883 void Assembler::sw(Register rd, const MemOperand& rs) {
1884   if (is_int16(rs.offset_)) {
1885     GenInstrImmediate(SW, rs.rm(), rd, rs.offset_);
1886   } else {  // Offset > 16 bits, use multiple instructions to store.
1887     LoadRegPlusOffsetToAt(rs);
1888     GenInstrImmediate(SW, at, rd, 0);  // Equiv to sw(rd, MemOperand(at, 0));
1889   }
1890 }
1891 
1892 
swl(Register rd,const MemOperand & rs)1893 void Assembler::swl(Register rd, const MemOperand& rs) {
1894   GenInstrImmediate(SWL, rs.rm(), rd, rs.offset_);
1895 }
1896 
1897 
swr(Register rd,const MemOperand & rs)1898 void Assembler::swr(Register rd, const MemOperand& rs) {
1899   GenInstrImmediate(SWR, rs.rm(), rd, rs.offset_);
1900 }
1901 
1902 
lui(Register rd,int32_t j)1903 void Assembler::lui(Register rd, int32_t j) {
1904   DCHECK(is_uint16(j));
1905   GenInstrImmediate(LUI, zero_reg, rd, j);
1906 }
1907 
1908 
aui(Register rs,Register rt,int32_t j)1909 void Assembler::aui(Register rs, Register rt, int32_t j) {
1910   // This instruction uses same opcode as 'lui'. The difference in encoding is
1911   // 'lui' has zero reg. for rs field.
1912   DCHECK(is_uint16(j));
1913   GenInstrImmediate(LUI, rs, rt, j);
1914 }
1915 
1916 
daui(Register rs,Register rt,int32_t j)1917 void Assembler::daui(Register rs, Register rt, int32_t j) {
1918   DCHECK(is_uint16(j));
1919   GenInstrImmediate(DAUI, rs, rt, j);
1920 }
1921 
1922 
dahi(Register rs,int32_t j)1923 void Assembler::dahi(Register rs, int32_t j) {
1924   DCHECK(is_uint16(j));
1925   GenInstrImmediate(REGIMM, rs, DAHI, j);
1926 }
1927 
1928 
dati(Register rs,int32_t j)1929 void Assembler::dati(Register rs, int32_t j) {
1930   DCHECK(is_uint16(j));
1931   GenInstrImmediate(REGIMM, rs, DATI, j);
1932 }
1933 
1934 
ldl(Register rd,const MemOperand & rs)1935 void Assembler::ldl(Register rd, const MemOperand& rs) {
1936   GenInstrImmediate(LDL, rs.rm(), rd, rs.offset_);
1937 }
1938 
1939 
ldr(Register rd,const MemOperand & rs)1940 void Assembler::ldr(Register rd, const MemOperand& rs) {
1941   GenInstrImmediate(LDR, rs.rm(), rd, rs.offset_);
1942 }
1943 
1944 
sdl(Register rd,const MemOperand & rs)1945 void Assembler::sdl(Register rd, const MemOperand& rs) {
1946   GenInstrImmediate(SDL, rs.rm(), rd, rs.offset_);
1947 }
1948 
1949 
sdr(Register rd,const MemOperand & rs)1950 void Assembler::sdr(Register rd, const MemOperand& rs) {
1951   GenInstrImmediate(SDR, rs.rm(), rd, rs.offset_);
1952 }
1953 
1954 
ld(Register rd,const MemOperand & rs)1955 void Assembler::ld(Register rd, const MemOperand& rs) {
1956   if (is_int16(rs.offset_)) {
1957     GenInstrImmediate(LD, rs.rm(), rd, rs.offset_);
1958   } else {  // Offset > 16 bits, use multiple instructions to load.
1959     LoadRegPlusOffsetToAt(rs);
1960     GenInstrImmediate(LD, at, rd, 0);  // Equiv to lw(rd, MemOperand(at, 0));
1961   }
1962 }
1963 
1964 
sd(Register rd,const MemOperand & rs)1965 void Assembler::sd(Register rd, const MemOperand& rs) {
1966   if (is_int16(rs.offset_)) {
1967     GenInstrImmediate(SD, rs.rm(), rd, rs.offset_);
1968   } else {  // Offset > 16 bits, use multiple instructions to store.
1969     LoadRegPlusOffsetToAt(rs);
1970     GenInstrImmediate(SD, at, rd, 0);  // Equiv to sw(rd, MemOperand(at, 0));
1971   }
1972 }
1973 
1974 
1975 // -------------Misc-instructions--------------
1976 
1977 // Break / Trap instructions.
break_(uint32_t code,bool break_as_stop)1978 void Assembler::break_(uint32_t code, bool break_as_stop) {
1979   DCHECK((code & ~0xfffff) == 0);
1980   // We need to invalidate breaks that could be stops as well because the
1981   // simulator expects a char pointer after the stop instruction.
1982   // See constants-mips.h for explanation.
1983   DCHECK((break_as_stop &&
1984           code <= kMaxStopCode &&
1985           code > kMaxWatchpointCode) ||
1986          (!break_as_stop &&
1987           (code > kMaxStopCode ||
1988            code <= kMaxWatchpointCode)));
1989   Instr break_instr = SPECIAL | BREAK | (code << 6);
1990   emit(break_instr);
1991 }
1992 
1993 
stop(const char * msg,uint32_t code)1994 void Assembler::stop(const char* msg, uint32_t code) {
1995   DCHECK(code > kMaxWatchpointCode);
1996   DCHECK(code <= kMaxStopCode);
1997 #if defined(V8_HOST_ARCH_MIPS) || defined(V8_HOST_ARCH_MIPS64)
1998   break_(0x54321);
1999 #else  // V8_HOST_ARCH_MIPS
2000   BlockTrampolinePoolFor(3);
2001   // The Simulator will handle the stop instruction and get the message address.
2002   // On MIPS stop() is just a special kind of break_().
2003   break_(code, true);
2004   emit(reinterpret_cast<uint64_t>(msg));
2005 #endif
2006 }
2007 
2008 
tge(Register rs,Register rt,uint16_t code)2009 void Assembler::tge(Register rs, Register rt, uint16_t code) {
2010   DCHECK(is_uint10(code));
2011   Instr instr = SPECIAL | TGE | rs.code() << kRsShift
2012       | rt.code() << kRtShift | code << 6;
2013   emit(instr);
2014 }
2015 
2016 
tgeu(Register rs,Register rt,uint16_t code)2017 void Assembler::tgeu(Register rs, Register rt, uint16_t code) {
2018   DCHECK(is_uint10(code));
2019   Instr instr = SPECIAL | TGEU | rs.code() << kRsShift
2020       | rt.code() << kRtShift | code << 6;
2021   emit(instr);
2022 }
2023 
2024 
tlt(Register rs,Register rt,uint16_t code)2025 void Assembler::tlt(Register rs, Register rt, uint16_t code) {
2026   DCHECK(is_uint10(code));
2027   Instr instr =
2028       SPECIAL | TLT | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2029   emit(instr);
2030 }
2031 
2032 
tltu(Register rs,Register rt,uint16_t code)2033 void Assembler::tltu(Register rs, Register rt, uint16_t code) {
2034   DCHECK(is_uint10(code));
2035   Instr instr =
2036       SPECIAL | TLTU | rs.code() << kRsShift
2037       | rt.code() << kRtShift | code << 6;
2038   emit(instr);
2039 }
2040 
2041 
teq(Register rs,Register rt,uint16_t code)2042 void Assembler::teq(Register rs, Register rt, uint16_t code) {
2043   DCHECK(is_uint10(code));
2044   Instr instr =
2045       SPECIAL | TEQ | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2046   emit(instr);
2047 }
2048 
2049 
tne(Register rs,Register rt,uint16_t code)2050 void Assembler::tne(Register rs, Register rt, uint16_t code) {
2051   DCHECK(is_uint10(code));
2052   Instr instr =
2053       SPECIAL | TNE | rs.code() << kRsShift | rt.code() << kRtShift | code << 6;
2054   emit(instr);
2055 }
2056 
2057 
2058 // Move from HI/LO register.
2059 
mfhi(Register rd)2060 void Assembler::mfhi(Register rd) {
2061   GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFHI);
2062 }
2063 
2064 
mflo(Register rd)2065 void Assembler::mflo(Register rd) {
2066   GenInstrRegister(SPECIAL, zero_reg, zero_reg, rd, 0, MFLO);
2067 }
2068 
2069 
2070 // Set on less than instructions.
slt(Register rd,Register rs,Register rt)2071 void Assembler::slt(Register rd, Register rs, Register rt) {
2072   GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLT);
2073 }
2074 
2075 
sltu(Register rd,Register rs,Register rt)2076 void Assembler::sltu(Register rd, Register rs, Register rt) {
2077   GenInstrRegister(SPECIAL, rs, rt, rd, 0, SLTU);
2078 }
2079 
2080 
slti(Register rt,Register rs,int32_t j)2081 void Assembler::slti(Register rt, Register rs, int32_t j) {
2082   GenInstrImmediate(SLTI, rs, rt, j);
2083 }
2084 
2085 
sltiu(Register rt,Register rs,int32_t j)2086 void Assembler::sltiu(Register rt, Register rs, int32_t j) {
2087   GenInstrImmediate(SLTIU, rs, rt, j);
2088 }
2089 
2090 
2091 // Conditional move.
movz(Register rd,Register rs,Register rt)2092 void Assembler::movz(Register rd, Register rs, Register rt) {
2093   GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVZ);
2094 }
2095 
2096 
movn(Register rd,Register rs,Register rt)2097 void Assembler::movn(Register rd, Register rs, Register rt) {
2098   GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVN);
2099 }
2100 
2101 
movt(Register rd,Register rs,uint16_t cc)2102 void Assembler::movt(Register rd, Register rs, uint16_t cc) {
2103   Register rt;
2104   rt.code_ = (cc & 0x0007) << 2 | 1;
2105   GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2106 }
2107 
2108 
movf(Register rd,Register rs,uint16_t cc)2109 void Assembler::movf(Register rd, Register rs, uint16_t cc) {
2110   Register rt;
2111   rt.code_ = (cc & 0x0007) << 2 | 0;
2112   GenInstrRegister(SPECIAL, rs, rt, rd, 0, MOVCI);
2113 }
2114 
2115 
sel(SecondaryField fmt,FPURegister fd,FPURegister ft,FPURegister fs,uint8_t sel)2116 void Assembler::sel(SecondaryField fmt, FPURegister fd,
2117     FPURegister ft, FPURegister fs, uint8_t sel) {
2118   DCHECK(kArchVariant == kMips64r6);
2119   DCHECK(fmt == D);
2120   DCHECK(fmt == S);
2121 
2122   Instr instr = COP1 | fmt << kRsShift | ft.code() << kFtShift |
2123       fs.code() << kFsShift | fd.code() << kFdShift | SEL;
2124   emit(instr);
2125 }
2126 
2127 
2128 // GPR.
seleqz(Register rs,Register rt,Register rd)2129 void Assembler::seleqz(Register rs, Register rt, Register rd) {
2130   DCHECK(kArchVariant == kMips64r6);
2131   GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELEQZ_S);
2132 }
2133 
2134 
2135 // FPR.
seleqz(SecondaryField fmt,FPURegister fd,FPURegister ft,FPURegister fs)2136 void Assembler::seleqz(SecondaryField fmt, FPURegister fd,
2137     FPURegister ft, FPURegister fs) {
2138   DCHECK(kArchVariant == kMips64r6);
2139   DCHECK(fmt == D);
2140   DCHECK(fmt == S);
2141 
2142   Instr instr = COP1 | fmt << kRsShift | ft.code() << kFtShift |
2143       fs.code() << kFsShift | fd.code() << kFdShift | SELEQZ_C;
2144   emit(instr);
2145 }
2146 
2147 
2148 // GPR.
selnez(Register rs,Register rt,Register rd)2149 void Assembler::selnez(Register rs, Register rt, Register rd) {
2150   DCHECK(kArchVariant == kMips64r6);
2151   GenInstrRegister(SPECIAL, rs, rt, rd, 0, SELNEZ_S);
2152 }
2153 
2154 
2155 // FPR.
selnez(SecondaryField fmt,FPURegister fd,FPURegister ft,FPURegister fs)2156 void Assembler::selnez(SecondaryField fmt, FPURegister fd,
2157     FPURegister ft, FPURegister fs) {
2158   DCHECK(kArchVariant == kMips64r6);
2159   DCHECK(fmt == D);
2160   DCHECK(fmt == S);
2161 
2162   Instr instr = COP1 | fmt << kRsShift | ft.code() << kFtShift |
2163       fs.code() << kFsShift | fd.code() << kFdShift | SELNEZ_C;
2164   emit(instr);
2165 }
2166 
2167 
2168 // Bit twiddling.
clz(Register rd,Register rs)2169 void Assembler::clz(Register rd, Register rs) {
2170   if (kArchVariant != kMips64r6) {
2171     // Clz instr requires same GPR number in 'rd' and 'rt' fields.
2172     GenInstrRegister(SPECIAL2, rs, rd, rd, 0, CLZ);
2173   } else {
2174     GenInstrRegister(SPECIAL, rs, zero_reg, rd, 1, CLZ_R6);
2175   }
2176 }
2177 
2178 
ins_(Register rt,Register rs,uint16_t pos,uint16_t size)2179 void Assembler::ins_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2180   // Should be called via MacroAssembler::Ins.
2181   // Ins instr has 'rt' field as dest, and two uint5: msb, lsb.
2182   DCHECK((kArchVariant == kMips64r2) || (kArchVariant == kMips64r6));
2183   GenInstrRegister(SPECIAL3, rs, rt, pos + size - 1, pos, INS);
2184 }
2185 
2186 
ext_(Register rt,Register rs,uint16_t pos,uint16_t size)2187 void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
2188   // Should be called via MacroAssembler::Ext.
2189   // Ext instr has 'rt' field as dest, and two uint5: msb, lsb.
2190   DCHECK(kArchVariant == kMips64r2 || kArchVariant == kMips64r6);
2191   GenInstrRegister(SPECIAL3, rs, rt, size - 1, pos, EXT);
2192 }
2193 
2194 
pref(int32_t hint,const MemOperand & rs)2195 void Assembler::pref(int32_t hint, const MemOperand& rs) {
2196   DCHECK(is_uint5(hint) && is_uint16(rs.offset_));
2197   Instr instr = PREF | (rs.rm().code() << kRsShift) | (hint << kRtShift)
2198       | (rs.offset_);
2199   emit(instr);
2200 }
2201 
2202 
2203 // --------Coprocessor-instructions----------------
2204 
2205 // Load, store, move.
lwc1(FPURegister fd,const MemOperand & src)2206 void Assembler::lwc1(FPURegister fd, const MemOperand& src) {
2207   GenInstrImmediate(LWC1, src.rm(), fd, src.offset_);
2208 }
2209 
2210 
ldc1(FPURegister fd,const MemOperand & src)2211 void Assembler::ldc1(FPURegister fd, const MemOperand& src) {
2212   GenInstrImmediate(LDC1, src.rm(), fd, src.offset_);
2213 }
2214 
2215 
swc1(FPURegister fd,const MemOperand & src)2216 void Assembler::swc1(FPURegister fd, const MemOperand& src) {
2217   GenInstrImmediate(SWC1, src.rm(), fd, src.offset_);
2218 }
2219 
2220 
sdc1(FPURegister fd,const MemOperand & src)2221 void Assembler::sdc1(FPURegister fd, const MemOperand& src) {
2222   GenInstrImmediate(SDC1, src.rm(), fd, src.offset_);
2223 }
2224 
2225 
mtc1(Register rt,FPURegister fs)2226 void Assembler::mtc1(Register rt, FPURegister fs) {
2227   GenInstrRegister(COP1, MTC1, rt, fs, f0);
2228 }
2229 
2230 
mthc1(Register rt,FPURegister fs)2231 void Assembler::mthc1(Register rt, FPURegister fs) {
2232   GenInstrRegister(COP1, MTHC1, rt, fs, f0);
2233 }
2234 
2235 
dmtc1(Register rt,FPURegister fs)2236 void Assembler::dmtc1(Register rt, FPURegister fs) {
2237   GenInstrRegister(COP1, DMTC1, rt, fs, f0);
2238 }
2239 
2240 
mfc1(Register rt,FPURegister fs)2241 void Assembler::mfc1(Register rt, FPURegister fs) {
2242   GenInstrRegister(COP1, MFC1, rt, fs, f0);
2243 }
2244 
2245 
mfhc1(Register rt,FPURegister fs)2246 void Assembler::mfhc1(Register rt, FPURegister fs) {
2247   GenInstrRegister(COP1, MFHC1, rt, fs, f0);
2248 }
2249 
2250 
dmfc1(Register rt,FPURegister fs)2251 void Assembler::dmfc1(Register rt, FPURegister fs) {
2252   GenInstrRegister(COP1, DMFC1, rt, fs, f0);
2253 }
2254 
2255 
ctc1(Register rt,FPUControlRegister fs)2256 void Assembler::ctc1(Register rt, FPUControlRegister fs) {
2257   GenInstrRegister(COP1, CTC1, rt, fs);
2258 }
2259 
2260 
cfc1(Register rt,FPUControlRegister fs)2261 void Assembler::cfc1(Register rt, FPUControlRegister fs) {
2262   GenInstrRegister(COP1, CFC1, rt, fs);
2263 }
2264 
2265 
DoubleAsTwoUInt32(double d,uint32_t * lo,uint32_t * hi)2266 void Assembler::DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
2267   uint64_t i;
2268   memcpy(&i, &d, 8);
2269 
2270   *lo = i & 0xffffffff;
2271   *hi = i >> 32;
2272 }
2273 
2274 
2275 // Arithmetic.
2276 
add_d(FPURegister fd,FPURegister fs,FPURegister ft)2277 void Assembler::add_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2278   GenInstrRegister(COP1, D, ft, fs, fd, ADD_D);
2279 }
2280 
2281 
sub_d(FPURegister fd,FPURegister fs,FPURegister ft)2282 void Assembler::sub_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2283   GenInstrRegister(COP1, D, ft, fs, fd, SUB_D);
2284 }
2285 
2286 
mul_d(FPURegister fd,FPURegister fs,FPURegister ft)2287 void Assembler::mul_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2288   GenInstrRegister(COP1, D, ft, fs, fd, MUL_D);
2289 }
2290 
2291 
madd_d(FPURegister fd,FPURegister fr,FPURegister fs,FPURegister ft)2292 void Assembler::madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
2293     FPURegister ft) {
2294   GenInstrRegister(COP1X, fr, ft, fs, fd, MADD_D);
2295 }
2296 
2297 
div_d(FPURegister fd,FPURegister fs,FPURegister ft)2298 void Assembler::div_d(FPURegister fd, FPURegister fs, FPURegister ft) {
2299   GenInstrRegister(COP1, D, ft, fs, fd, DIV_D);
2300 }
2301 
2302 
abs_d(FPURegister fd,FPURegister fs)2303 void Assembler::abs_d(FPURegister fd, FPURegister fs) {
2304   GenInstrRegister(COP1, D, f0, fs, fd, ABS_D);
2305 }
2306 
2307 
mov_d(FPURegister fd,FPURegister fs)2308 void Assembler::mov_d(FPURegister fd, FPURegister fs) {
2309   GenInstrRegister(COP1, D, f0, fs, fd, MOV_D);
2310 }
2311 
2312 
neg_d(FPURegister fd,FPURegister fs)2313 void Assembler::neg_d(FPURegister fd, FPURegister fs) {
2314   GenInstrRegister(COP1, D, f0, fs, fd, NEG_D);
2315 }
2316 
2317 
sqrt_d(FPURegister fd,FPURegister fs)2318 void Assembler::sqrt_d(FPURegister fd, FPURegister fs) {
2319   GenInstrRegister(COP1, D, f0, fs, fd, SQRT_D);
2320 }
2321 
2322 
2323 // Conversions.
2324 
cvt_w_s(FPURegister fd,FPURegister fs)2325 void Assembler::cvt_w_s(FPURegister fd, FPURegister fs) {
2326   GenInstrRegister(COP1, S, f0, fs, fd, CVT_W_S);
2327 }
2328 
2329 
cvt_w_d(FPURegister fd,FPURegister fs)2330 void Assembler::cvt_w_d(FPURegister fd, FPURegister fs) {
2331   GenInstrRegister(COP1, D, f0, fs, fd, CVT_W_D);
2332 }
2333 
2334 
trunc_w_s(FPURegister fd,FPURegister fs)2335 void Assembler::trunc_w_s(FPURegister fd, FPURegister fs) {
2336   GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_W_S);
2337 }
2338 
2339 
trunc_w_d(FPURegister fd,FPURegister fs)2340 void Assembler::trunc_w_d(FPURegister fd, FPURegister fs) {
2341   GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_W_D);
2342 }
2343 
2344 
round_w_s(FPURegister fd,FPURegister fs)2345 void Assembler::round_w_s(FPURegister fd, FPURegister fs) {
2346   GenInstrRegister(COP1, S, f0, fs, fd, ROUND_W_S);
2347 }
2348 
2349 
round_w_d(FPURegister fd,FPURegister fs)2350 void Assembler::round_w_d(FPURegister fd, FPURegister fs) {
2351   GenInstrRegister(COP1, D, f0, fs, fd, ROUND_W_D);
2352 }
2353 
2354 
floor_w_s(FPURegister fd,FPURegister fs)2355 void Assembler::floor_w_s(FPURegister fd, FPURegister fs) {
2356   GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_W_S);
2357 }
2358 
2359 
floor_w_d(FPURegister fd,FPURegister fs)2360 void Assembler::floor_w_d(FPURegister fd, FPURegister fs) {
2361   GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_W_D);
2362 }
2363 
2364 
ceil_w_s(FPURegister fd,FPURegister fs)2365 void Assembler::ceil_w_s(FPURegister fd, FPURegister fs) {
2366   GenInstrRegister(COP1, S, f0, fs, fd, CEIL_W_S);
2367 }
2368 
2369 
ceil_w_d(FPURegister fd,FPURegister fs)2370 void Assembler::ceil_w_d(FPURegister fd, FPURegister fs) {
2371   GenInstrRegister(COP1, D, f0, fs, fd, CEIL_W_D);
2372 }
2373 
2374 
cvt_l_s(FPURegister fd,FPURegister fs)2375 void Assembler::cvt_l_s(FPURegister fd, FPURegister fs) {
2376   DCHECK(kArchVariant == kMips64r2);
2377   GenInstrRegister(COP1, S, f0, fs, fd, CVT_L_S);
2378 }
2379 
2380 
cvt_l_d(FPURegister fd,FPURegister fs)2381 void Assembler::cvt_l_d(FPURegister fd, FPURegister fs) {
2382   DCHECK(kArchVariant == kMips64r2);
2383   GenInstrRegister(COP1, D, f0, fs, fd, CVT_L_D);
2384 }
2385 
2386 
trunc_l_s(FPURegister fd,FPURegister fs)2387 void Assembler::trunc_l_s(FPURegister fd, FPURegister fs) {
2388   DCHECK(kArchVariant == kMips64r2);
2389   GenInstrRegister(COP1, S, f0, fs, fd, TRUNC_L_S);
2390 }
2391 
2392 
trunc_l_d(FPURegister fd,FPURegister fs)2393 void Assembler::trunc_l_d(FPURegister fd, FPURegister fs) {
2394   DCHECK(kArchVariant == kMips64r2);
2395   GenInstrRegister(COP1, D, f0, fs, fd, TRUNC_L_D);
2396 }
2397 
2398 
round_l_s(FPURegister fd,FPURegister fs)2399 void Assembler::round_l_s(FPURegister fd, FPURegister fs) {
2400   GenInstrRegister(COP1, S, f0, fs, fd, ROUND_L_S);
2401 }
2402 
2403 
round_l_d(FPURegister fd,FPURegister fs)2404 void Assembler::round_l_d(FPURegister fd, FPURegister fs) {
2405   GenInstrRegister(COP1, D, f0, fs, fd, ROUND_L_D);
2406 }
2407 
2408 
floor_l_s(FPURegister fd,FPURegister fs)2409 void Assembler::floor_l_s(FPURegister fd, FPURegister fs) {
2410   GenInstrRegister(COP1, S, f0, fs, fd, FLOOR_L_S);
2411 }
2412 
2413 
floor_l_d(FPURegister fd,FPURegister fs)2414 void Assembler::floor_l_d(FPURegister fd, FPURegister fs) {
2415   GenInstrRegister(COP1, D, f0, fs, fd, FLOOR_L_D);
2416 }
2417 
2418 
ceil_l_s(FPURegister fd,FPURegister fs)2419 void Assembler::ceil_l_s(FPURegister fd, FPURegister fs) {
2420   GenInstrRegister(COP1, S, f0, fs, fd, CEIL_L_S);
2421 }
2422 
2423 
ceil_l_d(FPURegister fd,FPURegister fs)2424 void Assembler::ceil_l_d(FPURegister fd, FPURegister fs) {
2425   GenInstrRegister(COP1, D, f0, fs, fd, CEIL_L_D);
2426 }
2427 
2428 
min(SecondaryField fmt,FPURegister fd,FPURegister ft,FPURegister fs)2429 void Assembler::min(SecondaryField fmt, FPURegister fd, FPURegister ft,
2430     FPURegister fs) {
2431   DCHECK(kArchVariant == kMips64r6);
2432   DCHECK((fmt == D) || (fmt == S));
2433   GenInstrRegister(COP1, fmt, ft, fs, fd, MIN);
2434 }
2435 
2436 
mina(SecondaryField fmt,FPURegister fd,FPURegister ft,FPURegister fs)2437 void Assembler::mina(SecondaryField fmt, FPURegister fd, FPURegister ft,
2438     FPURegister fs) {
2439   DCHECK(kArchVariant == kMips64r6);
2440   DCHECK((fmt == D) || (fmt == S));
2441   GenInstrRegister(COP1, fmt, ft, fs, fd, MINA);
2442 }
2443 
2444 
max(SecondaryField fmt,FPURegister fd,FPURegister ft,FPURegister fs)2445 void Assembler::max(SecondaryField fmt, FPURegister fd, FPURegister ft,
2446     FPURegister fs) {
2447   DCHECK(kArchVariant == kMips64r6);
2448   DCHECK((fmt == D) || (fmt == S));
2449   GenInstrRegister(COP1, fmt, ft, fs, fd, MAX);
2450 }
2451 
2452 
maxa(SecondaryField fmt,FPURegister fd,FPURegister ft,FPURegister fs)2453 void Assembler::maxa(SecondaryField fmt, FPURegister fd, FPURegister ft,
2454     FPURegister fs) {
2455   DCHECK(kArchVariant == kMips64r6);
2456   DCHECK((fmt == D) || (fmt == S));
2457   GenInstrRegister(COP1, fmt, ft, fs, fd, MAXA);
2458 }
2459 
2460 
cvt_s_w(FPURegister fd,FPURegister fs)2461 void Assembler::cvt_s_w(FPURegister fd, FPURegister fs) {
2462   GenInstrRegister(COP1, W, f0, fs, fd, CVT_S_W);
2463 }
2464 
2465 
cvt_s_l(FPURegister fd,FPURegister fs)2466 void Assembler::cvt_s_l(FPURegister fd, FPURegister fs) {
2467   DCHECK(kArchVariant == kMips64r2);
2468   GenInstrRegister(COP1, L, f0, fs, fd, CVT_S_L);
2469 }
2470 
2471 
cvt_s_d(FPURegister fd,FPURegister fs)2472 void Assembler::cvt_s_d(FPURegister fd, FPURegister fs) {
2473   GenInstrRegister(COP1, D, f0, fs, fd, CVT_S_D);
2474 }
2475 
2476 
cvt_d_w(FPURegister fd,FPURegister fs)2477 void Assembler::cvt_d_w(FPURegister fd, FPURegister fs) {
2478   GenInstrRegister(COP1, W, f0, fs, fd, CVT_D_W);
2479 }
2480 
2481 
cvt_d_l(FPURegister fd,FPURegister fs)2482 void Assembler::cvt_d_l(FPURegister fd, FPURegister fs) {
2483   DCHECK(kArchVariant == kMips64r2);
2484   GenInstrRegister(COP1, L, f0, fs, fd, CVT_D_L);
2485 }
2486 
2487 
cvt_d_s(FPURegister fd,FPURegister fs)2488 void Assembler::cvt_d_s(FPURegister fd, FPURegister fs) {
2489   GenInstrRegister(COP1, S, f0, fs, fd, CVT_D_S);
2490 }
2491 
2492 
2493 // Conditions for >= MIPSr6.
cmp(FPUCondition cond,SecondaryField fmt,FPURegister fd,FPURegister fs,FPURegister ft)2494 void Assembler::cmp(FPUCondition cond, SecondaryField fmt,
2495     FPURegister fd, FPURegister fs, FPURegister ft) {
2496   DCHECK(kArchVariant == kMips64r6);
2497   DCHECK((fmt & ~(31 << kRsShift)) == 0);
2498   Instr instr = COP1 | fmt | ft.code() << kFtShift |
2499       fs.code() << kFsShift | fd.code() << kFdShift | (0 << 5) | cond;
2500   emit(instr);
2501 }
2502 
2503 
bc1eqz(int16_t offset,FPURegister ft)2504 void Assembler::bc1eqz(int16_t offset, FPURegister ft) {
2505   DCHECK(kArchVariant == kMips64r6);
2506   Instr instr = COP1 | BC1EQZ | ft.code() << kFtShift | (offset & kImm16Mask);
2507   emit(instr);
2508 }
2509 
2510 
bc1nez(int16_t offset,FPURegister ft)2511 void Assembler::bc1nez(int16_t offset, FPURegister ft) {
2512   DCHECK(kArchVariant == kMips64r6);
2513   Instr instr = COP1 | BC1NEZ | ft.code() << kFtShift | (offset & kImm16Mask);
2514   emit(instr);
2515 }
2516 
2517 
2518 // Conditions for < MIPSr6.
c(FPUCondition cond,SecondaryField fmt,FPURegister fs,FPURegister ft,uint16_t cc)2519 void Assembler::c(FPUCondition cond, SecondaryField fmt,
2520     FPURegister fs, FPURegister ft, uint16_t cc) {
2521   DCHECK(kArchVariant != kMips64r6);
2522   DCHECK(is_uint3(cc));
2523   DCHECK((fmt & ~(31 << kRsShift)) == 0);
2524   Instr instr = COP1 | fmt | ft.code() << kFtShift | fs.code() << kFsShift
2525       | cc << 8 | 3 << 4 | cond;
2526   emit(instr);
2527 }
2528 
2529 
fcmp(FPURegister src1,const double src2,FPUCondition cond)2530 void Assembler::fcmp(FPURegister src1, const double src2,
2531       FPUCondition cond) {
2532   DCHECK(src2 == 0.0);
2533   mtc1(zero_reg, f14);
2534   cvt_d_w(f14, f14);
2535   c(cond, D, src1, f14, 0);
2536 }
2537 
2538 
bc1f(int16_t offset,uint16_t cc)2539 void Assembler::bc1f(int16_t offset, uint16_t cc) {
2540   DCHECK(is_uint3(cc));
2541   Instr instr = COP1 | BC1 | cc << 18 | 0 << 16 | (offset & kImm16Mask);
2542   emit(instr);
2543 }
2544 
2545 
bc1t(int16_t offset,uint16_t cc)2546 void Assembler::bc1t(int16_t offset, uint16_t cc) {
2547   DCHECK(is_uint3(cc));
2548   Instr instr = COP1 | BC1 | cc << 18 | 1 << 16 | (offset & kImm16Mask);
2549   emit(instr);
2550 }
2551 
2552 
2553 // Debugging.
RecordJSReturn()2554 void Assembler::RecordJSReturn() {
2555   positions_recorder()->WriteRecordedPositions();
2556   CheckBuffer();
2557   RecordRelocInfo(RelocInfo::JS_RETURN);
2558 }
2559 
2560 
RecordDebugBreakSlot()2561 void Assembler::RecordDebugBreakSlot() {
2562   positions_recorder()->WriteRecordedPositions();
2563   CheckBuffer();
2564   RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
2565 }
2566 
2567 
RecordComment(const char * msg)2568 void Assembler::RecordComment(const char* msg) {
2569   if (FLAG_code_comments) {
2570     CheckBuffer();
2571     RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
2572   }
2573 }
2574 
2575 
RelocateInternalReference(byte * pc,intptr_t pc_delta)2576 int Assembler::RelocateInternalReference(byte* pc, intptr_t pc_delta) {
2577   Instr instr = instr_at(pc);
2578   DCHECK(IsJ(instr) || IsLui(instr));
2579   if (IsLui(instr)) {
2580     Instr instr_lui = instr_at(pc + 0 * Assembler::kInstrSize);
2581     Instr instr_ori = instr_at(pc + 1 * Assembler::kInstrSize);
2582     Instr instr_ori2 = instr_at(pc + 3 * Assembler::kInstrSize);
2583     DCHECK(IsOri(instr_ori));
2584     DCHECK(IsOri(instr_ori2));
2585     // TODO(plind): symbolic names for the shifts.
2586     int64_t imm = (instr_lui & static_cast<int64_t>(kImm16Mask)) << 48;
2587     imm |= (instr_ori & static_cast<int64_t>(kImm16Mask)) << 32;
2588     imm |= (instr_ori2 & static_cast<int64_t>(kImm16Mask)) << 16;
2589     // Sign extend address.
2590     imm >>= 16;
2591 
2592     if (imm == kEndOfJumpChain) {
2593       return 0;  // Number of instructions patched.
2594     }
2595     imm += pc_delta;
2596     DCHECK((imm & 3) == 0);
2597 
2598     instr_lui &= ~kImm16Mask;
2599     instr_ori &= ~kImm16Mask;
2600     instr_ori2 &= ~kImm16Mask;
2601 
2602     instr_at_put(pc + 0 * Assembler::kInstrSize,
2603                  instr_lui | ((imm >> 32) & kImm16Mask));
2604     instr_at_put(pc + 1 * Assembler::kInstrSize,
2605                  instr_ori | (imm >> 16 & kImm16Mask));
2606     instr_at_put(pc + 3 * Assembler::kInstrSize,
2607                  instr_ori2 | (imm & kImm16Mask));
2608     return 4;  // Number of instructions patched.
2609   } else {
2610     uint32_t imm28 = (instr & static_cast<int32_t>(kImm26Mask)) << 2;
2611     if (static_cast<int32_t>(imm28) == kEndOfJumpChain) {
2612       return 0;  // Number of instructions patched.
2613     }
2614 
2615     imm28 += pc_delta;
2616     imm28 &= kImm28Mask;
2617     DCHECK((imm28 & 3) == 0);
2618 
2619     instr &= ~kImm26Mask;
2620     uint32_t imm26 = imm28 >> 2;
2621     DCHECK(is_uint26(imm26));
2622 
2623     instr_at_put(pc, instr | (imm26 & kImm26Mask));
2624     return 1;  // Number of instructions patched.
2625   }
2626 }
2627 
2628 
GrowBuffer()2629 void Assembler::GrowBuffer() {
2630   if (!own_buffer_) FATAL("external code buffer is too small");
2631 
2632   // Compute new buffer size.
2633   CodeDesc desc;  // The new buffer.
2634   if (buffer_size_ < 1 * MB) {
2635     desc.buffer_size = 2*buffer_size_;
2636   } else {
2637     desc.buffer_size = buffer_size_ + 1*MB;
2638   }
2639   CHECK_GT(desc.buffer_size, 0);  // No overflow.
2640 
2641   // Set up new buffer.
2642   desc.buffer = NewArray<byte>(desc.buffer_size);
2643 
2644   desc.instr_size = pc_offset();
2645   desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
2646 
2647   // Copy the data.
2648   intptr_t pc_delta = desc.buffer - buffer_;
2649   intptr_t rc_delta = (desc.buffer + desc.buffer_size) -
2650       (buffer_ + buffer_size_);
2651   MemMove(desc.buffer, buffer_, desc.instr_size);
2652   MemMove(reloc_info_writer.pos() + rc_delta,
2653               reloc_info_writer.pos(), desc.reloc_size);
2654 
2655   // Switch buffers.
2656   DeleteArray(buffer_);
2657   buffer_ = desc.buffer;
2658   buffer_size_ = desc.buffer_size;
2659   pc_ += pc_delta;
2660   reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
2661                                reloc_info_writer.last_pc() + pc_delta);
2662 
2663   // Relocate runtime entries.
2664   for (RelocIterator it(desc); !it.done(); it.next()) {
2665     RelocInfo::Mode rmode = it.rinfo()->rmode();
2666     if (rmode == RelocInfo::INTERNAL_REFERENCE) {
2667       byte* p = reinterpret_cast<byte*>(it.rinfo()->pc());
2668       RelocateInternalReference(p, pc_delta);
2669     }
2670   }
2671 
2672   DCHECK(!overflow());
2673 }
2674 
2675 
db(uint8_t data)2676 void Assembler::db(uint8_t data) {
2677   CheckBuffer();
2678   *reinterpret_cast<uint8_t*>(pc_) = data;
2679   pc_ += sizeof(uint8_t);
2680 }
2681 
2682 
dd(uint32_t data)2683 void Assembler::dd(uint32_t data) {
2684   CheckBuffer();
2685   *reinterpret_cast<uint32_t*>(pc_) = data;
2686   pc_ += sizeof(uint32_t);
2687 }
2688 
2689 
emit_code_stub_address(Code * stub)2690 void Assembler::emit_code_stub_address(Code* stub) {
2691   CheckBuffer();
2692   *reinterpret_cast<uint64_t*>(pc_) =
2693       reinterpret_cast<uint64_t>(stub->instruction_start());
2694   pc_ += sizeof(uint64_t);
2695 }
2696 
2697 
RecordRelocInfo(RelocInfo::Mode rmode,intptr_t data)2698 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
2699   // We do not try to reuse pool constants.
2700   RelocInfo rinfo(pc_, rmode, data, NULL);
2701   if (rmode >= RelocInfo::JS_RETURN && rmode <= RelocInfo::DEBUG_BREAK_SLOT) {
2702     // Adjust code for new modes.
2703     DCHECK(RelocInfo::IsDebugBreakSlot(rmode)
2704            || RelocInfo::IsJSReturn(rmode)
2705            || RelocInfo::IsComment(rmode)
2706            || RelocInfo::IsPosition(rmode));
2707     // These modes do not need an entry in the constant pool.
2708   }
2709   if (!RelocInfo::IsNone(rinfo.rmode())) {
2710     // Don't record external references unless the heap will be serialized.
2711     if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
2712         !serializer_enabled() && !emit_debug_code()) {
2713       return;
2714     }
2715     DCHECK(buffer_space() >= kMaxRelocSize);  // Too late to grow buffer here.
2716     if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
2717       RelocInfo reloc_info_with_ast_id(pc_,
2718                                        rmode,
2719                                        RecordedAstId().ToInt(),
2720                                        NULL);
2721       ClearRecordedAstId();
2722       reloc_info_writer.Write(&reloc_info_with_ast_id);
2723     } else {
2724       reloc_info_writer.Write(&rinfo);
2725     }
2726   }
2727 }
2728 
2729 
BlockTrampolinePoolFor(int instructions)2730 void Assembler::BlockTrampolinePoolFor(int instructions) {
2731   BlockTrampolinePoolBefore(pc_offset() + instructions * kInstrSize);
2732 }
2733 
2734 
CheckTrampolinePool()2735 void Assembler::CheckTrampolinePool() {
2736   // Some small sequences of instructions must not be broken up by the
2737   // insertion of a trampoline pool; such sequences are protected by setting
2738   // either trampoline_pool_blocked_nesting_ or no_trampoline_pool_before_,
2739   // which are both checked here. Also, recursive calls to CheckTrampolinePool
2740   // are blocked by trampoline_pool_blocked_nesting_.
2741   if ((trampoline_pool_blocked_nesting_ > 0) ||
2742       (pc_offset() < no_trampoline_pool_before_)) {
2743     // Emission is currently blocked; make sure we try again as soon as
2744     // possible.
2745     if (trampoline_pool_blocked_nesting_ > 0) {
2746       next_buffer_check_ = pc_offset() + kInstrSize;
2747     } else {
2748       next_buffer_check_ = no_trampoline_pool_before_;
2749     }
2750     return;
2751   }
2752 
2753   DCHECK(!trampoline_emitted_);
2754   DCHECK(unbound_labels_count_ >= 0);
2755   if (unbound_labels_count_ > 0) {
2756     // First we emit jump (2 instructions), then we emit trampoline pool.
2757     { BlockTrampolinePoolScope block_trampoline_pool(this);
2758       Label after_pool;
2759       b(&after_pool);
2760       nop();
2761 
2762       int pool_start = pc_offset();
2763       for (int i = 0; i < unbound_labels_count_; i++) {
2764         uint64_t imm64;
2765         imm64 = jump_address(&after_pool);
2766         { BlockGrowBufferScope block_buf_growth(this);
2767           // Buffer growth (and relocation) must be blocked for internal
2768           // references until associated instructions are emitted and available
2769           // to be patched.
2770           RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
2771           // TODO(plind): Verify this, presume I cannot use macro-assembler
2772           // here.
2773           lui(at, (imm64 >> 32) & kImm16Mask);
2774           ori(at, at, (imm64 >> 16) & kImm16Mask);
2775           dsll(at, at, 16);
2776           ori(at, at, imm64 & kImm16Mask);
2777         }
2778         jr(at);
2779         nop();
2780       }
2781       bind(&after_pool);
2782       trampoline_ = Trampoline(pool_start, unbound_labels_count_);
2783 
2784       trampoline_emitted_ = true;
2785       // As we are only going to emit trampoline once, we need to prevent any
2786       // further emission.
2787       next_buffer_check_ = kMaxInt;
2788     }
2789   } else {
2790     // Number of branches to unbound label at this point is zero, so we can
2791     // move next buffer check to maximum.
2792     next_buffer_check_ = pc_offset() +
2793         kMaxBranchOffset - kTrampolineSlotsSize * 16;
2794   }
2795   return;
2796 }
2797 
2798 
target_address_at(Address pc)2799 Address Assembler::target_address_at(Address pc) {
2800   Instr instr0 = instr_at(pc);
2801   Instr instr1 = instr_at(pc + 1 * kInstrSize);
2802   Instr instr3 = instr_at(pc + 3 * kInstrSize);
2803 
2804   // Interpret 4 instructions for address generated by li: See listing in
2805   // Assembler::set_target_address_at() just below.
2806   if ((GetOpcodeField(instr0) == LUI) && (GetOpcodeField(instr1) == ORI) &&
2807       (GetOpcodeField(instr3) == ORI)) {
2808     // Assemble the 48 bit value.
2809      int64_t addr  = static_cast<int64_t>(
2810           ((uint64_t)(GetImmediate16(instr0)) << 32) |
2811           ((uint64_t)(GetImmediate16(instr1)) << 16) |
2812           ((uint64_t)(GetImmediate16(instr3))));
2813 
2814     // Sign extend to get canonical address.
2815     addr = (addr << 16) >> 16;
2816     return reinterpret_cast<Address>(addr);
2817   }
2818   // We should never get here, force a bad address if we do.
2819   UNREACHABLE();
2820   return (Address)0x0;
2821 }
2822 
2823 
2824 // MIPS and ia32 use opposite encoding for qNaN and sNaN, such that ia32
2825 // qNaN is a MIPS sNaN, and ia32 sNaN is MIPS qNaN. If running from a heap
2826 // snapshot generated on ia32, the resulting MIPS sNaN must be quieted.
2827 // OS::nan_value() returns a qNaN.
QuietNaN(HeapObject * object)2828 void Assembler::QuietNaN(HeapObject* object) {
2829   HeapNumber::cast(object)->set_value(base::OS::nan_value());
2830 }
2831 
2832 
2833 // On Mips64, a target address is stored in a 4-instruction sequence:
2834 //    0: lui(rd, (j.imm64_ >> 32) & kImm16Mask);
2835 //    1: ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
2836 //    2: dsll(rd, rd, 16);
2837 //    3: ori(rd, rd, j.imm32_ & kImm16Mask);
2838 //
2839 // Patching the address must replace all the lui & ori instructions,
2840 // and flush the i-cache.
2841 //
2842 // There is an optimization below, which emits a nop when the address
2843 // fits in just 16 bits. This is unlikely to help, and should be benchmarked,
2844 // and possibly removed.
set_target_address_at(Address pc,Address target,ICacheFlushMode icache_flush_mode)2845 void Assembler::set_target_address_at(Address pc,
2846                                       Address target,
2847                                       ICacheFlushMode icache_flush_mode) {
2848 // There is an optimization where only 4 instructions are used to load address
2849 // in code on MIP64 because only 48-bits of address is effectively used.
2850 // It relies on fact the upper [63:48] bits are not used for virtual address
2851 // translation and they have to be set according to value of bit 47 in order
2852 // get canonical address.
2853   Instr instr1 = instr_at(pc + kInstrSize);
2854   uint32_t rt_code = GetRt(instr1);
2855   uint32_t* p = reinterpret_cast<uint32_t*>(pc);
2856   uint64_t itarget = reinterpret_cast<uint64_t>(target);
2857 
2858 #ifdef DEBUG
2859   // Check we have the result from a li macro-instruction.
2860   Instr instr0 = instr_at(pc);
2861   Instr instr3 = instr_at(pc + kInstrSize * 3);
2862   CHECK((GetOpcodeField(instr0) == LUI && GetOpcodeField(instr1) == ORI &&
2863          GetOpcodeField(instr3) == ORI));
2864 #endif
2865 
2866   // Must use 4 instructions to insure patchable code.
2867   // lui rt, upper-16.
2868   // ori rt, rt, lower-16.
2869   // dsll rt, rt, 16.
2870   // ori rt rt, lower-16.
2871   *p = LUI | (rt_code << kRtShift) | ((itarget >> 32) & kImm16Mask);
2872   *(p + 1) = ORI | (rt_code << kRtShift) | (rt_code << kRsShift)
2873       | ((itarget >> 16) & kImm16Mask);
2874   *(p + 3) = ORI | (rt_code << kRsShift) | (rt_code << kRtShift)
2875       | (itarget & kImm16Mask);
2876 
2877   if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
2878     CpuFeatures::FlushICache(pc, 4 * Assembler::kInstrSize);
2879   }
2880 }
2881 
2882 
JumpLabelToJumpRegister(Address pc)2883 void Assembler::JumpLabelToJumpRegister(Address pc) {
2884   // Address pc points to lui/ori instructions.
2885   // Jump to label may follow at pc + 2 * kInstrSize.
2886   uint32_t* p = reinterpret_cast<uint32_t*>(pc);
2887 #ifdef DEBUG
2888   Instr instr1 = instr_at(pc);
2889 #endif
2890   Instr instr2 = instr_at(pc + 1 * kInstrSize);
2891   Instr instr3 = instr_at(pc + 6 * kInstrSize);
2892   bool patched = false;
2893 
2894   if (IsJal(instr3)) {
2895     DCHECK(GetOpcodeField(instr1) == LUI);
2896     DCHECK(GetOpcodeField(instr2) == ORI);
2897 
2898     uint32_t rs_field = GetRt(instr2) << kRsShift;
2899     uint32_t rd_field = ra.code() << kRdShift;  // Return-address (ra) reg.
2900     *(p+6) = SPECIAL | rs_field | rd_field | JALR;
2901     patched = true;
2902   } else if (IsJ(instr3)) {
2903     DCHECK(GetOpcodeField(instr1) == LUI);
2904     DCHECK(GetOpcodeField(instr2) == ORI);
2905 
2906     uint32_t rs_field = GetRt(instr2) << kRsShift;
2907     *(p+6) = SPECIAL | rs_field | JR;
2908     patched = true;
2909   }
2910 
2911   if (patched) {
2912       CpuFeatures::FlushICache(pc+6, sizeof(int32_t));
2913   }
2914 }
2915 
2916 
NewConstantPool(Isolate * isolate)2917 Handle<ConstantPoolArray> Assembler::NewConstantPool(Isolate* isolate) {
2918   // No out-of-line constant pool support.
2919   DCHECK(!FLAG_enable_ool_constant_pool);
2920   return isolate->factory()->empty_constant_pool_array();
2921 }
2922 
2923 
PopulateConstantPool(ConstantPoolArray * constant_pool)2924 void Assembler::PopulateConstantPool(ConstantPoolArray* constant_pool) {
2925   // No out-of-line constant pool support.
2926   DCHECK(!FLAG_enable_ool_constant_pool);
2927   return;
2928 }
2929 
2930 
2931 } }  // namespace v8::internal
2932 
2933 #endif  // V8_TARGET_ARCH_MIPS64
2934