• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <limits.h>  // For LONG_MIN, LONG_MAX.
6 
7 #if V8_TARGET_ARCH_MIPS64
8 
9 #include "src/base/bits.h"
10 #include "src/base/division-by-constant.h"
11 #include "src/codegen/assembler-inl.h"
12 #include "src/codegen/callable.h"
13 #include "src/codegen/code-factory.h"
14 #include "src/codegen/external-reference-table.h"
15 #include "src/codegen/interface-descriptors-inl.h"
16 #include "src/codegen/macro-assembler.h"
17 #include "src/codegen/register-configuration.h"
18 #include "src/debug/debug.h"
19 #include "src/deoptimizer/deoptimizer.h"
20 #include "src/execution/frames-inl.h"
21 #include "src/heap/memory-chunk.h"
22 #include "src/init/bootstrapper.h"
23 #include "src/logging/counters.h"
24 #include "src/objects/heap-number.h"
25 #include "src/runtime/runtime.h"
26 #include "src/snapshot/snapshot.h"
27 
28 #if V8_ENABLE_WEBASSEMBLY
29 #include "src/wasm/wasm-code-manager.h"
30 #endif  // V8_ENABLE_WEBASSEMBLY
31 
32 // Satisfy cpplint check, but don't include platform-specific header. It is
33 // included recursively via macro-assembler.h.
34 #if 0
35 #include "src/codegen/mips64/macro-assembler-mips64.h"
36 #endif
37 
38 namespace v8 {
39 namespace internal {
40 
IsZero(const Operand & rt)41 static inline bool IsZero(const Operand& rt) {
42   if (rt.is_reg()) {
43     return rt.rm() == zero_reg;
44   } else {
45     return rt.immediate() == 0;
46   }
47 }
48 
RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,Register exclusion1,Register exclusion2,Register exclusion3) const49 int TurboAssembler::RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
50                                                     Register exclusion1,
51                                                     Register exclusion2,
52                                                     Register exclusion3) const {
53   int bytes = 0;
54   RegList exclusions = {exclusion1, exclusion2, exclusion3};
55   RegList list = kJSCallerSaved - exclusions;
56   bytes += list.Count() * kPointerSize;
57 
58   if (fp_mode == SaveFPRegsMode::kSave) {
59     bytes += kCallerSavedFPU.Count() * kDoubleSize;
60   }
61 
62   return bytes;
63 }
64 
PushCallerSaved(SaveFPRegsMode fp_mode,Register exclusion1,Register exclusion2,Register exclusion3)65 int TurboAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1,
66                                     Register exclusion2, Register exclusion3) {
67   ASM_CODE_COMMENT(this);
68   int bytes = 0;
69   RegList exclusions = {exclusion1, exclusion2, exclusion3};
70   RegList list = kJSCallerSaved - exclusions;
71   MultiPush(list);
72   bytes += list.Count() * kPointerSize;
73 
74   if (fp_mode == SaveFPRegsMode::kSave) {
75     MultiPushFPU(kCallerSavedFPU);
76     bytes += kCallerSavedFPU.Count() * kDoubleSize;
77   }
78 
79   return bytes;
80 }
81 
PopCallerSaved(SaveFPRegsMode fp_mode,Register exclusion1,Register exclusion2,Register exclusion3)82 int TurboAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1,
83                                    Register exclusion2, Register exclusion3) {
84   ASM_CODE_COMMENT(this);
85   int bytes = 0;
86   if (fp_mode == SaveFPRegsMode::kSave) {
87     MultiPopFPU(kCallerSavedFPU);
88     bytes += kCallerSavedFPU.Count() * kDoubleSize;
89   }
90 
91   RegList exclusions = {exclusion1, exclusion2, exclusion3};
92   RegList list = kJSCallerSaved - exclusions;
93   MultiPop(list);
94   bytes += list.Count() * kPointerSize;
95 
96   return bytes;
97 }
98 
LoadRoot(Register destination,RootIndex index)99 void TurboAssembler::LoadRoot(Register destination, RootIndex index) {
100   Ld(destination, MemOperand(s6, RootRegisterOffsetForRootIndex(index)));
101 }
102 
LoadRoot(Register destination,RootIndex index,Condition cond,Register src1,const Operand & src2)103 void TurboAssembler::LoadRoot(Register destination, RootIndex index,
104                               Condition cond, Register src1,
105                               const Operand& src2) {
106   Branch(2, NegateCondition(cond), src1, src2);
107   Ld(destination, MemOperand(s6, RootRegisterOffsetForRootIndex(index)));
108 }
109 
PushCommonFrame(Register marker_reg)110 void TurboAssembler::PushCommonFrame(Register marker_reg) {
111   if (marker_reg.is_valid()) {
112     Push(ra, fp, marker_reg);
113     Daddu(fp, sp, Operand(kPointerSize));
114   } else {
115     Push(ra, fp);
116     mov(fp, sp);
117   }
118 }
119 
PushStandardFrame(Register function_reg)120 void TurboAssembler::PushStandardFrame(Register function_reg) {
121   int offset = -StandardFrameConstants::kContextOffset;
122   if (function_reg.is_valid()) {
123     Push(ra, fp, cp, function_reg, kJavaScriptCallArgCountRegister);
124     offset += 2 * kPointerSize;
125   } else {
126     Push(ra, fp, cp, kJavaScriptCallArgCountRegister);
127     offset += kPointerSize;
128   }
129   Daddu(fp, sp, Operand(offset));
130 }
131 
132 // Clobbers object, dst, value, and ra, if (ra_status == kRAHasBeenSaved)
133 // The register 'object' contains a heap object pointer.  The heap object
134 // tag is shifted away.
RecordWriteField(Register object,int offset,Register value,Register dst,RAStatus ra_status,SaveFPRegsMode save_fp,RememberedSetAction remembered_set_action,SmiCheck smi_check)135 void MacroAssembler::RecordWriteField(Register object, int offset,
136                                       Register value, Register dst,
137                                       RAStatus ra_status,
138                                       SaveFPRegsMode save_fp,
139                                       RememberedSetAction remembered_set_action,
140                                       SmiCheck smi_check) {
141   ASM_CODE_COMMENT(this);
142   DCHECK(!AreAliased(value, dst, t8, object));
143   // First, check if a write barrier is even needed. The tests below
144   // catch stores of Smis.
145   Label done;
146 
147   // Skip barrier if writing a smi.
148   if (smi_check == SmiCheck::kInline) {
149     JumpIfSmi(value, &done);
150   }
151 
152   // Although the object register is tagged, the offset is relative to the start
153   // of the object, so offset must be a multiple of kPointerSize.
154   DCHECK(IsAligned(offset, kPointerSize));
155 
156   Daddu(dst, object, Operand(offset - kHeapObjectTag));
157   if (FLAG_debug_code) {
158     BlockTrampolinePoolScope block_trampoline_pool(this);
159     Label ok;
160     And(t8, dst, Operand(kPointerSize - 1));
161     Branch(&ok, eq, t8, Operand(zero_reg));
162     stop();
163     bind(&ok);
164   }
165 
166   RecordWrite(object, dst, value, ra_status, save_fp, remembered_set_action,
167               SmiCheck::kOmit);
168 
169   bind(&done);
170 
171   // Clobber clobbered input registers when running with the debug-code flag
172   // turned on to provoke errors.
173   if (FLAG_debug_code) {
174     li(value, Operand(bit_cast<int64_t>(kZapValue + 4)));
175     li(dst, Operand(bit_cast<int64_t>(kZapValue + 8)));
176   }
177 }
178 
MaybeSaveRegisters(RegList registers)179 void TurboAssembler::MaybeSaveRegisters(RegList registers) {
180   if (registers.is_empty()) return;
181   MultiPush(registers);
182 }
183 
MaybeRestoreRegisters(RegList registers)184 void TurboAssembler::MaybeRestoreRegisters(RegList registers) {
185   if (registers.is_empty()) return;
186   MultiPop(registers);
187 }
188 
CallEphemeronKeyBarrier(Register object,Register slot_address,SaveFPRegsMode fp_mode)189 void TurboAssembler::CallEphemeronKeyBarrier(Register object,
190                                              Register slot_address,
191                                              SaveFPRegsMode fp_mode) {
192   ASM_CODE_COMMENT(this);
193   DCHECK(!AreAliased(object, slot_address));
194   RegList registers =
195       WriteBarrierDescriptor::ComputeSavedRegisters(object, slot_address);
196   MaybeSaveRegisters(registers);
197 
198   Register object_parameter = WriteBarrierDescriptor::ObjectRegister();
199   Register slot_address_parameter =
200       WriteBarrierDescriptor::SlotAddressRegister();
201 
202   Push(object);
203   Push(slot_address);
204   Pop(slot_address_parameter);
205   Pop(object_parameter);
206 
207   Call(isolate()->builtins()->code_handle(
208            Builtins::GetEphemeronKeyBarrierStub(fp_mode)),
209        RelocInfo::CODE_TARGET);
210   MaybeRestoreRegisters(registers);
211 }
212 
CallRecordWriteStubSaveRegisters(Register object,Register slot_address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode,StubCallMode mode)213 void TurboAssembler::CallRecordWriteStubSaveRegisters(
214     Register object, Register slot_address,
215     RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode,
216     StubCallMode mode) {
217   DCHECK(!AreAliased(object, slot_address));
218   RegList registers =
219       WriteBarrierDescriptor::ComputeSavedRegisters(object, slot_address);
220   MaybeSaveRegisters(registers);
221 
222   Register object_parameter = WriteBarrierDescriptor::ObjectRegister();
223   Register slot_address_parameter =
224       WriteBarrierDescriptor::SlotAddressRegister();
225 
226   Push(object);
227   Push(slot_address);
228   Pop(slot_address_parameter);
229   Pop(object_parameter);
230 
231   CallRecordWriteStub(object_parameter, slot_address_parameter,
232                       remembered_set_action, fp_mode, mode);
233 
234   MaybeRestoreRegisters(registers);
235 }
236 
CallRecordWriteStub(Register object,Register slot_address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode,StubCallMode mode)237 void TurboAssembler::CallRecordWriteStub(
238     Register object, Register slot_address,
239     RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode,
240     StubCallMode mode) {
241   // Use CallRecordWriteStubSaveRegisters if the object and slot registers
242   // need to be caller saved.
243   DCHECK_EQ(WriteBarrierDescriptor::ObjectRegister(), object);
244   DCHECK_EQ(WriteBarrierDescriptor::SlotAddressRegister(), slot_address);
245 #if V8_ENABLE_WEBASSEMBLY
246   if (mode == StubCallMode::kCallWasmRuntimeStub) {
247     auto wasm_target =
248         wasm::WasmCode::GetRecordWriteStub(remembered_set_action, fp_mode);
249     Call(wasm_target, RelocInfo::WASM_STUB_CALL);
250 #else
251   if (false) {
252 #endif
253   } else {
254     auto builtin = Builtins::GetRecordWriteStub(remembered_set_action, fp_mode);
255     if (options().inline_offheap_trampolines) {
256       // Inline the trampoline.
257       RecordCommentForOffHeapTrampoline(builtin);
258       li(t9, Operand(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET));
259       Call(t9);
260       RecordComment("]");
261     } else {
262       Handle<Code> code_target = isolate()->builtins()->code_handle(builtin);
263       Call(code_target, RelocInfo::CODE_TARGET);
264     }
265   }
266 }
267 
268 // Clobbers object, address, value, and ra, if (ra_status == kRAHasBeenSaved)
269 // The register 'object' contains a heap object pointer.  The heap object
270 // tag is shifted away.
271 void MacroAssembler::RecordWrite(Register object, Register address,
272                                  Register value, RAStatus ra_status,
273                                  SaveFPRegsMode fp_mode,
274                                  RememberedSetAction remembered_set_action,
275                                  SmiCheck smi_check) {
276   DCHECK(!AreAliased(object, address, value, t8));
277   DCHECK(!AreAliased(object, address, value, t9));
278 
279   if (FLAG_debug_code) {
280     UseScratchRegisterScope temps(this);
281     Register scratch = temps.Acquire();
282     DCHECK(!AreAliased(object, value, scratch));
283     Ld(scratch, MemOperand(address));
284     Assert(eq, AbortReason::kWrongAddressOrValuePassedToRecordWrite, scratch,
285            Operand(value));
286   }
287 
288   if ((remembered_set_action == RememberedSetAction::kOmit &&
289        !FLAG_incremental_marking) ||
290       FLAG_disable_write_barriers) {
291     return;
292   }
293 
294   // First, check if a write barrier is even needed. The tests below
295   // catch stores of smis and stores into the young generation.
296   Label done;
297 
298   if (smi_check == SmiCheck::kInline) {
299     DCHECK_EQ(0, kSmiTag);
300     JumpIfSmi(value, &done);
301   }
302 
303   CheckPageFlag(value,
304                 value,  // Used as scratch.
305                 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
306   CheckPageFlag(object,
307                 value,  // Used as scratch.
308                 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done);
309 
310   // Record the actual write.
311   if (ra_status == kRAHasNotBeenSaved) {
312     push(ra);
313   }
314 
315   Register slot_address = WriteBarrierDescriptor::SlotAddressRegister();
316   DCHECK(!AreAliased(object, slot_address, value));
317   mov(slot_address, address);
318   CallRecordWriteStub(object, slot_address, remembered_set_action, fp_mode);
319 
320   if (ra_status == kRAHasNotBeenSaved) {
321     pop(ra);
322   }
323 
324   bind(&done);
325 
326   // Clobber clobbered registers when running with the debug-code flag
327   // turned on to provoke errors.
328   if (FLAG_debug_code) {
329     li(address, Operand(bit_cast<int64_t>(kZapValue + 12)));
330     li(value, Operand(bit_cast<int64_t>(kZapValue + 16)));
331     li(slot_address, Operand(bit_cast<int64_t>(kZapValue + 20)));
332   }
333 }
334 
335 // ---------------------------------------------------------------------------
336 // Instruction macros.
337 
338 void TurboAssembler::Addu(Register rd, Register rs, const Operand& rt) {
339   if (rt.is_reg()) {
340     addu(rd, rs, rt.rm());
341   } else {
342     if (is_int16(rt.immediate()) && !MustUseReg(rt.rmode())) {
343       addiu(rd, rs, static_cast<int32_t>(rt.immediate()));
344     } else {
345       // li handles the relocation.
346       UseScratchRegisterScope temps(this);
347       Register scratch = temps.Acquire();
348       DCHECK(rs != scratch);
349       li(scratch, rt);
350       addu(rd, rs, scratch);
351     }
352   }
353 }
354 
355 void TurboAssembler::Daddu(Register rd, Register rs, const Operand& rt) {
356   if (rt.is_reg()) {
357     daddu(rd, rs, rt.rm());
358   } else {
359     if (is_int16(rt.immediate()) && !MustUseReg(rt.rmode())) {
360       daddiu(rd, rs, static_cast<int32_t>(rt.immediate()));
361     } else {
362       // li handles the relocation.
363       UseScratchRegisterScope temps(this);
364       Register scratch = temps.Acquire();
365       DCHECK(rs != scratch);
366       li(scratch, rt);
367       daddu(rd, rs, scratch);
368     }
369   }
370 }
371 
372 void TurboAssembler::Subu(Register rd, Register rs, const Operand& rt) {
373   if (rt.is_reg()) {
374     subu(rd, rs, rt.rm());
375   } else {
376     DCHECK(is_int32(rt.immediate()));
377     if (is_int16(-rt.immediate()) && !MustUseReg(rt.rmode())) {
378       addiu(rd, rs,
379             static_cast<int32_t>(
380                 -rt.immediate()));  // No subiu instr, use addiu(x, y, -imm).
381     } else {
382       UseScratchRegisterScope temps(this);
383       Register scratch = temps.Acquire();
384       DCHECK(rs != scratch);
385       if (-rt.immediate() >> 16 == 0 && !MustUseReg(rt.rmode())) {
386         // Use load -imm and addu when loading -imm generates one instruction.
387         li(scratch, -rt.immediate());
388         addu(rd, rs, scratch);
389       } else {
390         // li handles the relocation.
391         li(scratch, rt);
392         subu(rd, rs, scratch);
393       }
394     }
395   }
396 }
397 
398 void TurboAssembler::Dsubu(Register rd, Register rs, const Operand& rt) {
399   if (rt.is_reg()) {
400     dsubu(rd, rs, rt.rm());
401   } else if (is_int16(-rt.immediate()) && !MustUseReg(rt.rmode())) {
402     daddiu(rd, rs,
403            static_cast<int32_t>(
404                -rt.immediate()));  // No dsubiu instr, use daddiu(x, y, -imm).
405   } else {
406     DCHECK(rs != at);
407     int li_count = InstrCountForLi64Bit(rt.immediate());
408     int li_neg_count = InstrCountForLi64Bit(-rt.immediate());
409     if (li_neg_count < li_count && !MustUseReg(rt.rmode())) {
410       // Use load -imm and daddu when loading -imm generates one instruction.
411       DCHECK(rt.immediate() != std::numeric_limits<int32_t>::min());
412       UseScratchRegisterScope temps(this);
413       Register scratch = temps.Acquire();
414       li(scratch, Operand(-rt.immediate()));
415       Daddu(rd, rs, scratch);
416     } else {
417       // li handles the relocation.
418       UseScratchRegisterScope temps(this);
419       Register scratch = temps.Acquire();
420       li(scratch, rt);
421       dsubu(rd, rs, scratch);
422     }
423   }
424 }
425 
426 void TurboAssembler::Mul(Register rd, Register rs, const Operand& rt) {
427   if (rt.is_reg()) {
428     mul(rd, rs, rt.rm());
429   } else {
430     // li handles the relocation.
431     UseScratchRegisterScope temps(this);
432     Register scratch = temps.Acquire();
433     DCHECK(rs != scratch);
434     li(scratch, rt);
435     mul(rd, rs, scratch);
436   }
437 }
438 
439 void TurboAssembler::Mulh(Register rd, Register rs, const Operand& rt) {
440   if (rt.is_reg()) {
441     if (kArchVariant != kMips64r6) {
442       mult(rs, rt.rm());
443       mfhi(rd);
444     } else {
445       muh(rd, rs, rt.rm());
446     }
447   } else {
448     // li handles the relocation.
449     UseScratchRegisterScope temps(this);
450     Register scratch = temps.Acquire();
451     DCHECK(rs != scratch);
452     li(scratch, rt);
453     if (kArchVariant != kMips64r6) {
454       mult(rs, scratch);
455       mfhi(rd);
456     } else {
457       muh(rd, rs, scratch);
458     }
459   }
460 }
461 
462 void TurboAssembler::Mulhu(Register rd, Register rs, const Operand& rt) {
463   if (rt.is_reg()) {
464     if (kArchVariant != kMips64r6) {
465       multu(rs, rt.rm());
466       mfhi(rd);
467     } else {
468       muhu(rd, rs, rt.rm());
469     }
470   } else {
471     // li handles the relocation.
472     UseScratchRegisterScope temps(this);
473     Register scratch = temps.Acquire();
474     DCHECK(rs != scratch);
475     li(scratch, rt);
476     if (kArchVariant != kMips64r6) {
477       multu(rs, scratch);
478       mfhi(rd);
479     } else {
480       muhu(rd, rs, scratch);
481     }
482   }
483 }
484 
485 void TurboAssembler::Dmul(Register rd, Register rs, const Operand& rt) {
486   if (rt.is_reg()) {
487     if (kArchVariant == kMips64r6) {
488       dmul(rd, rs, rt.rm());
489     } else {
490       dmult(rs, rt.rm());
491       mflo(rd);
492     }
493   } else {
494     // li handles the relocation.
495     UseScratchRegisterScope temps(this);
496     Register scratch = temps.Acquire();
497     DCHECK(rs != scratch);
498     li(scratch, rt);
499     if (kArchVariant == kMips64r6) {
500       dmul(rd, rs, scratch);
501     } else {
502       dmult(rs, scratch);
503       mflo(rd);
504     }
505   }
506 }
507 
508 void TurboAssembler::Dmulh(Register rd, Register rs, const Operand& rt) {
509   if (rt.is_reg()) {
510     if (kArchVariant == kMips64r6) {
511       dmuh(rd, rs, rt.rm());
512     } else {
513       dmult(rs, rt.rm());
514       mfhi(rd);
515     }
516   } else {
517     // li handles the relocation.
518     UseScratchRegisterScope temps(this);
519     Register scratch = temps.Acquire();
520     DCHECK(rs != scratch);
521     li(scratch, rt);
522     if (kArchVariant == kMips64r6) {
523       dmuh(rd, rs, scratch);
524     } else {
525       dmult(rs, scratch);
526       mfhi(rd);
527     }
528   }
529 }
530 
531 void TurboAssembler::Mult(Register rs, const Operand& rt) {
532   if (rt.is_reg()) {
533     mult(rs, rt.rm());
534   } else {
535     // li handles the relocation.
536     UseScratchRegisterScope temps(this);
537     Register scratch = temps.Acquire();
538     DCHECK(rs != scratch);
539     li(scratch, rt);
540     mult(rs, scratch);
541   }
542 }
543 
544 void TurboAssembler::Dmult(Register rs, const Operand& rt) {
545   if (rt.is_reg()) {
546     dmult(rs, rt.rm());
547   } else {
548     // li handles the relocation.
549     UseScratchRegisterScope temps(this);
550     Register scratch = temps.Acquire();
551     DCHECK(rs != scratch);
552     li(scratch, rt);
553     dmult(rs, scratch);
554   }
555 }
556 
557 void TurboAssembler::Multu(Register rs, const Operand& rt) {
558   if (rt.is_reg()) {
559     multu(rs, rt.rm());
560   } else {
561     // li handles the relocation.
562     UseScratchRegisterScope temps(this);
563     Register scratch = temps.Acquire();
564     DCHECK(rs != scratch);
565     li(scratch, rt);
566     multu(rs, scratch);
567   }
568 }
569 
570 void TurboAssembler::Dmultu(Register rs, const Operand& rt) {
571   if (rt.is_reg()) {
572     dmultu(rs, rt.rm());
573   } else {
574     // li handles the relocation.
575     UseScratchRegisterScope temps(this);
576     Register scratch = temps.Acquire();
577     DCHECK(rs != scratch);
578     li(scratch, rt);
579     dmultu(rs, scratch);
580   }
581 }
582 
583 void TurboAssembler::Div(Register rs, const Operand& rt) {
584   if (rt.is_reg()) {
585     div(rs, rt.rm());
586   } else {
587     // li handles the relocation.
588     UseScratchRegisterScope temps(this);
589     Register scratch = temps.Acquire();
590     DCHECK(rs != scratch);
591     li(scratch, rt);
592     div(rs, scratch);
593   }
594 }
595 
596 void TurboAssembler::Div(Register res, Register rs, const Operand& rt) {
597   if (rt.is_reg()) {
598     if (kArchVariant != kMips64r6) {
599       div(rs, rt.rm());
600       mflo(res);
601     } else {
602       div(res, rs, rt.rm());
603     }
604   } else {
605     // li handles the relocation.
606     UseScratchRegisterScope temps(this);
607     Register scratch = temps.Acquire();
608     DCHECK(rs != scratch);
609     li(scratch, rt);
610     if (kArchVariant != kMips64r6) {
611       div(rs, scratch);
612       mflo(res);
613     } else {
614       div(res, rs, scratch);
615     }
616   }
617 }
618 
619 void TurboAssembler::Mod(Register rd, Register rs, const Operand& rt) {
620   if (rt.is_reg()) {
621     if (kArchVariant != kMips64r6) {
622       div(rs, rt.rm());
623       mfhi(rd);
624     } else {
625       mod(rd, rs, rt.rm());
626     }
627   } else {
628     // li handles the relocation.
629     UseScratchRegisterScope temps(this);
630     Register scratch = temps.Acquire();
631     DCHECK(rs != scratch);
632     li(scratch, rt);
633     if (kArchVariant != kMips64r6) {
634       div(rs, scratch);
635       mfhi(rd);
636     } else {
637       mod(rd, rs, scratch);
638     }
639   }
640 }
641 
642 void TurboAssembler::Modu(Register rd, Register rs, const Operand& rt) {
643   if (rt.is_reg()) {
644     if (kArchVariant != kMips64r6) {
645       divu(rs, rt.rm());
646       mfhi(rd);
647     } else {
648       modu(rd, rs, rt.rm());
649     }
650   } else {
651     // li handles the relocation.
652     UseScratchRegisterScope temps(this);
653     Register scratch = temps.Acquire();
654     DCHECK(rs != scratch);
655     li(scratch, rt);
656     if (kArchVariant != kMips64r6) {
657       divu(rs, scratch);
658       mfhi(rd);
659     } else {
660       modu(rd, rs, scratch);
661     }
662   }
663 }
664 
665 void TurboAssembler::Ddiv(Register rs, const Operand& rt) {
666   if (rt.is_reg()) {
667     ddiv(rs, rt.rm());
668   } else {
669     // li handles the relocation.
670     UseScratchRegisterScope temps(this);
671     Register scratch = temps.Acquire();
672     DCHECK(rs != scratch);
673     li(scratch, rt);
674     ddiv(rs, scratch);
675   }
676 }
677 
678 void TurboAssembler::Ddiv(Register rd, Register rs, const Operand& rt) {
679   if (kArchVariant != kMips64r6) {
680     if (rt.is_reg()) {
681       ddiv(rs, rt.rm());
682       mflo(rd);
683     } else {
684       // li handles the relocation.
685       UseScratchRegisterScope temps(this);
686       Register scratch = temps.Acquire();
687       DCHECK(rs != scratch);
688       li(scratch, rt);
689       ddiv(rs, scratch);
690       mflo(rd);
691     }
692   } else {
693     if (rt.is_reg()) {
694       ddiv(rd, rs, rt.rm());
695     } else {
696       // li handles the relocation.
697       UseScratchRegisterScope temps(this);
698       Register scratch = temps.Acquire();
699       DCHECK(rs != scratch);
700       li(scratch, rt);
701       ddiv(rd, rs, scratch);
702     }
703   }
704 }
705 
706 void TurboAssembler::Divu(Register rs, const Operand& rt) {
707   if (rt.is_reg()) {
708     divu(rs, rt.rm());
709   } else {
710     // li handles the relocation.
711     UseScratchRegisterScope temps(this);
712     Register scratch = temps.Acquire();
713     DCHECK(rs != scratch);
714     li(scratch, rt);
715     divu(rs, scratch);
716   }
717 }
718 
719 void TurboAssembler::Divu(Register res, Register rs, const Operand& rt) {
720   if (rt.is_reg()) {
721     if (kArchVariant != kMips64r6) {
722       divu(rs, rt.rm());
723       mflo(res);
724     } else {
725       divu(res, rs, rt.rm());
726     }
727   } else {
728     // li handles the relocation.
729     UseScratchRegisterScope temps(this);
730     Register scratch = temps.Acquire();
731     DCHECK(rs != scratch);
732     li(scratch, rt);
733     if (kArchVariant != kMips64r6) {
734       divu(rs, scratch);
735       mflo(res);
736     } else {
737       divu(res, rs, scratch);
738     }
739   }
740 }
741 
742 void TurboAssembler::Ddivu(Register rs, const Operand& rt) {
743   if (rt.is_reg()) {
744     ddivu(rs, rt.rm());
745   } else {
746     // li handles the relocation.
747     UseScratchRegisterScope temps(this);
748     Register scratch = temps.Acquire();
749     DCHECK(rs != scratch);
750     li(scratch, rt);
751     ddivu(rs, scratch);
752   }
753 }
754 
755 void TurboAssembler::Ddivu(Register res, Register rs, const Operand& rt) {
756   if (rt.is_reg()) {
757     if (kArchVariant != kMips64r6) {
758       ddivu(rs, rt.rm());
759       mflo(res);
760     } else {
761       ddivu(res, rs, rt.rm());
762     }
763   } else {
764     // li handles the relocation.
765     UseScratchRegisterScope temps(this);
766     Register scratch = temps.Acquire();
767     DCHECK(rs != scratch);
768     li(scratch, rt);
769     if (kArchVariant != kMips64r6) {
770       ddivu(rs, scratch);
771       mflo(res);
772     } else {
773       ddivu(res, rs, scratch);
774     }
775   }
776 }
777 
778 void TurboAssembler::Dmod(Register rd, Register rs, const Operand& rt) {
779   if (kArchVariant != kMips64r6) {
780     if (rt.is_reg()) {
781       ddiv(rs, rt.rm());
782       mfhi(rd);
783     } else {
784       // li handles the relocation.
785       UseScratchRegisterScope temps(this);
786       Register scratch = temps.Acquire();
787       DCHECK(rs != scratch);
788       li(scratch, rt);
789       ddiv(rs, scratch);
790       mfhi(rd);
791     }
792   } else {
793     if (rt.is_reg()) {
794       dmod(rd, rs, rt.rm());
795     } else {
796       // li handles the relocation.
797       UseScratchRegisterScope temps(this);
798       Register scratch = temps.Acquire();
799       DCHECK(rs != scratch);
800       li(scratch, rt);
801       dmod(rd, rs, scratch);
802     }
803   }
804 }
805 
806 void TurboAssembler::Dmodu(Register rd, Register rs, const Operand& rt) {
807   if (kArchVariant != kMips64r6) {
808     if (rt.is_reg()) {
809       ddivu(rs, rt.rm());
810       mfhi(rd);
811     } else {
812       // li handles the relocation.
813       UseScratchRegisterScope temps(this);
814       Register scratch = temps.Acquire();
815       DCHECK(rs != scratch);
816       li(scratch, rt);
817       ddivu(rs, scratch);
818       mfhi(rd);
819     }
820   } else {
821     if (rt.is_reg()) {
822       dmodu(rd, rs, rt.rm());
823     } else {
824       // li handles the relocation.
825       UseScratchRegisterScope temps(this);
826       Register scratch = temps.Acquire();
827       DCHECK(rs != scratch);
828       li(scratch, rt);
829       dmodu(rd, rs, scratch);
830     }
831   }
832 }
833 
834 void TurboAssembler::And(Register rd, Register rs, const Operand& rt) {
835   if (rt.is_reg()) {
836     and_(rd, rs, rt.rm());
837   } else {
838     if (is_uint16(rt.immediate()) && !MustUseReg(rt.rmode())) {
839       andi(rd, rs, static_cast<int32_t>(rt.immediate()));
840     } else {
841       // li handles the relocation.
842       UseScratchRegisterScope temps(this);
843       Register scratch = temps.Acquire();
844       DCHECK(rs != scratch);
845       li(scratch, rt);
846       and_(rd, rs, scratch);
847     }
848   }
849 }
850 
851 void TurboAssembler::Or(Register rd, Register rs, const Operand& rt) {
852   if (rt.is_reg()) {
853     or_(rd, rs, rt.rm());
854   } else {
855     if (is_uint16(rt.immediate()) && !MustUseReg(rt.rmode())) {
856       ori(rd, rs, static_cast<int32_t>(rt.immediate()));
857     } else {
858       // li handles the relocation.
859       UseScratchRegisterScope temps(this);
860       Register scratch = temps.Acquire();
861       DCHECK(rs != scratch);
862       li(scratch, rt);
863       or_(rd, rs, scratch);
864     }
865   }
866 }
867 
868 void TurboAssembler::Xor(Register rd, Register rs, const Operand& rt) {
869   if (rt.is_reg()) {
870     xor_(rd, rs, rt.rm());
871   } else {
872     if (is_uint16(rt.immediate()) && !MustUseReg(rt.rmode())) {
873       xori(rd, rs, static_cast<int32_t>(rt.immediate()));
874     } else {
875       // li handles the relocation.
876       UseScratchRegisterScope temps(this);
877       Register scratch = temps.Acquire();
878       DCHECK(rs != scratch);
879       li(scratch, rt);
880       xor_(rd, rs, scratch);
881     }
882   }
883 }
884 
885 void TurboAssembler::Nor(Register rd, Register rs, const Operand& rt) {
886   if (rt.is_reg()) {
887     nor(rd, rs, rt.rm());
888   } else {
889     // li handles the relocation.
890     UseScratchRegisterScope temps(this);
891     Register scratch = temps.Acquire();
892     DCHECK(rs != scratch);
893     li(scratch, rt);
894     nor(rd, rs, scratch);
895   }
896 }
897 
898 void TurboAssembler::Neg(Register rs, const Operand& rt) {
899   dsubu(rs, zero_reg, rt.rm());
900 }
901 
902 void TurboAssembler::Slt(Register rd, Register rs, const Operand& rt) {
903   if (rt.is_reg()) {
904     slt(rd, rs, rt.rm());
905   } else {
906     if (is_int16(rt.immediate()) && !MustUseReg(rt.rmode())) {
907       slti(rd, rs, static_cast<int32_t>(rt.immediate()));
908     } else {
909       // li handles the relocation.
910       UseScratchRegisterScope temps(this);
911       BlockTrampolinePoolScope block_trampoline_pool(this);
912       Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
913       DCHECK(rs != scratch);
914       li(scratch, rt);
915       slt(rd, rs, scratch);
916     }
917   }
918 }
919 
920 void TurboAssembler::Sltu(Register rd, Register rs, const Operand& rt) {
921   if (rt.is_reg()) {
922     sltu(rd, rs, rt.rm());
923   } else {
924     const uint64_t int16_min = std::numeric_limits<int16_t>::min();
925     if (is_uint15(rt.immediate()) && !MustUseReg(rt.rmode())) {
926       // Imm range is: [0, 32767].
927       sltiu(rd, rs, static_cast<int32_t>(rt.immediate()));
928     } else if (is_uint15(rt.immediate() - int16_min) &&
929                !MustUseReg(rt.rmode())) {
930       // Imm range is: [max_unsigned-32767,max_unsigned].
931       sltiu(rd, rs, static_cast<uint16_t>(rt.immediate()));
932     } else {
933       // li handles the relocation.
934       UseScratchRegisterScope temps(this);
935       BlockTrampolinePoolScope block_trampoline_pool(this);
936       Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
937       DCHECK(rs != scratch);
938       li(scratch, rt);
939       sltu(rd, rs, scratch);
940     }
941   }
942 }
943 
944 void TurboAssembler::Sle(Register rd, Register rs, const Operand& rt) {
945   if (rt.is_reg()) {
946     slt(rd, rt.rm(), rs);
947   } else {
948     // li handles the relocation.
949     UseScratchRegisterScope temps(this);
950     Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
951     BlockTrampolinePoolScope block_trampoline_pool(this);
952     DCHECK(rs != scratch);
953     li(scratch, rt);
954     slt(rd, scratch, rs);
955   }
956   xori(rd, rd, 1);
957 }
958 
959 void TurboAssembler::Sleu(Register rd, Register rs, const Operand& rt) {
960   if (rt.is_reg()) {
961     sltu(rd, rt.rm(), rs);
962   } else {
963     // li handles the relocation.
964     UseScratchRegisterScope temps(this);
965     Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
966     BlockTrampolinePoolScope block_trampoline_pool(this);
967     DCHECK(rs != scratch);
968     li(scratch, rt);
969     sltu(rd, scratch, rs);
970   }
971   xori(rd, rd, 1);
972 }
973 
974 void TurboAssembler::Sge(Register rd, Register rs, const Operand& rt) {
975   Slt(rd, rs, rt);
976   xori(rd, rd, 1);
977 }
978 
979 void TurboAssembler::Sgeu(Register rd, Register rs, const Operand& rt) {
980   Sltu(rd, rs, rt);
981   xori(rd, rd, 1);
982 }
983 
984 void TurboAssembler::Sgt(Register rd, Register rs, const Operand& rt) {
985   if (rt.is_reg()) {
986     slt(rd, rt.rm(), rs);
987   } else {
988     // li handles the relocation.
989     UseScratchRegisterScope temps(this);
990     Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
991     BlockTrampolinePoolScope block_trampoline_pool(this);
992     DCHECK(rs != scratch);
993     li(scratch, rt);
994     slt(rd, scratch, rs);
995   }
996 }
997 
998 void TurboAssembler::Sgtu(Register rd, Register rs, const Operand& rt) {
999   if (rt.is_reg()) {
1000     sltu(rd, rt.rm(), rs);
1001   } else {
1002     // li handles the relocation.
1003     UseScratchRegisterScope temps(this);
1004     Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
1005     BlockTrampolinePoolScope block_trampoline_pool(this);
1006     DCHECK(rs != scratch);
1007     li(scratch, rt);
1008     sltu(rd, scratch, rs);
1009   }
1010 }
1011 
1012 void TurboAssembler::Ror(Register rd, Register rs, const Operand& rt) {
1013   if (rt.is_reg()) {
1014     rotrv(rd, rs, rt.rm());
1015   } else {
1016     int64_t ror_value = rt.immediate() % 32;
1017     if (ror_value < 0) {
1018       ror_value += 32;
1019     }
1020     rotr(rd, rs, ror_value);
1021   }
1022 }
1023 
1024 void TurboAssembler::Dror(Register rd, Register rs, const Operand& rt) {
1025   if (rt.is_reg()) {
1026     drotrv(rd, rs, rt.rm());
1027   } else {
1028     int64_t dror_value = rt.immediate() % 64;
1029     if (dror_value < 0) dror_value += 64;
1030     if (dror_value <= 31) {
1031       drotr(rd, rs, dror_value);
1032     } else {
1033       drotr32(rd, rs, dror_value - 32);
1034     }
1035   }
1036 }
1037 
1038 void MacroAssembler::Pref(int32_t hint, const MemOperand& rs) {
1039   pref(hint, rs);
1040 }
1041 
1042 void TurboAssembler::Lsa(Register rd, Register rt, Register rs, uint8_t sa,
1043                          Register scratch) {
1044   DCHECK(sa >= 1 && sa <= 31);
1045   if (kArchVariant == kMips64r6 && sa <= 4) {
1046     lsa(rd, rt, rs, sa - 1);
1047   } else {
1048     Register tmp = rd == rt ? scratch : rd;
1049     DCHECK(tmp != rt);
1050     sll(tmp, rs, sa);
1051     Addu(rd, rt, tmp);
1052   }
1053 }
1054 
1055 void TurboAssembler::Dlsa(Register rd, Register rt, Register rs, uint8_t sa,
1056                           Register scratch) {
1057   DCHECK(sa >= 1 && sa <= 63);
1058   if (kArchVariant == kMips64r6 && sa <= 4) {
1059     dlsa(rd, rt, rs, sa - 1);
1060   } else {
1061     Register tmp = rd == rt ? scratch : rd;
1062     DCHECK(tmp != rt);
1063     if (sa <= 31)
1064       dsll(tmp, rs, sa);
1065     else
1066       dsll32(tmp, rs, sa - 32);
1067     Daddu(rd, rt, tmp);
1068   }
1069 }
1070 
1071 void TurboAssembler::Bovc(Register rs, Register rt, Label* L) {
1072   if (is_trampoline_emitted()) {
1073     Label skip;
1074     bnvc(rs, rt, &skip);
1075     BranchLong(L, PROTECT);
1076     bind(&skip);
1077   } else {
1078     bovc(rs, rt, L);
1079   }
1080 }
1081 
1082 void TurboAssembler::Bnvc(Register rs, Register rt, Label* L) {
1083   if (is_trampoline_emitted()) {
1084     Label skip;
1085     bovc(rs, rt, &skip);
1086     BranchLong(L, PROTECT);
1087     bind(&skip);
1088   } else {
1089     bnvc(rs, rt, L);
1090   }
1091 }
1092 
1093 // ------------Pseudo-instructions-------------
1094 
1095 // Change endianness
1096 void TurboAssembler::ByteSwapSigned(Register dest, Register src,
1097                                     int operand_size) {
1098   DCHECK(operand_size == 2 || operand_size == 4 || operand_size == 8);
1099   DCHECK(kArchVariant == kMips64r6 || kArchVariant == kMips64r2);
1100   if (operand_size == 2) {
1101     wsbh(dest, src);
1102     seh(dest, dest);
1103   } else if (operand_size == 4) {
1104     wsbh(dest, src);
1105     rotr(dest, dest, 16);
1106   } else {
1107     dsbh(dest, src);
1108     dshd(dest, dest);
1109   }
1110 }
1111 
1112 void TurboAssembler::ByteSwapUnsigned(Register dest, Register src,
1113                                       int operand_size) {
1114   DCHECK(operand_size == 2 || operand_size == 4);
1115   if (operand_size == 2) {
1116     wsbh(dest, src);
1117     andi(dest, dest, 0xFFFF);
1118   } else {
1119     wsbh(dest, src);
1120     rotr(dest, dest, 16);
1121     dinsu_(dest, zero_reg, 32, 32);
1122   }
1123 }
1124 
1125 void TurboAssembler::Ulw(Register rd, const MemOperand& rs) {
1126   DCHECK(rd != at);
1127   DCHECK(rs.rm() != at);
1128   if (kArchVariant == kMips64r6) {
1129     Lw(rd, rs);
1130   } else {
1131     DCHECK_EQ(kArchVariant, kMips64r2);
1132     DCHECK(kMipsLwrOffset <= 3 && kMipsLwlOffset <= 3);
1133     MemOperand source = rs;
1134     // Adjust offset for two accesses and check if offset + 3 fits into int16_t.
1135     AdjustBaseAndOffset(&source, OffsetAccessType::TWO_ACCESSES, 3);
1136     if (rd != source.rm()) {
1137       lwr(rd, MemOperand(source.rm(), source.offset() + kMipsLwrOffset));
1138       lwl(rd, MemOperand(source.rm(), source.offset() + kMipsLwlOffset));
1139     } else {
1140       UseScratchRegisterScope temps(this);
1141       Register scratch = temps.Acquire();
1142       lwr(scratch, MemOperand(rs.rm(), rs.offset() + kMipsLwrOffset));
1143       lwl(scratch, MemOperand(rs.rm(), rs.offset() + kMipsLwlOffset));
1144       mov(rd, scratch);
1145     }
1146   }
1147 }
1148 
1149 void TurboAssembler::Ulwu(Register rd, const MemOperand& rs) {
1150   if (kArchVariant == kMips64r6) {
1151     Lwu(rd, rs);
1152   } else {
1153     DCHECK_EQ(kArchVariant, kMips64r2);
1154     Ulw(rd, rs);
1155     Dext(rd, rd, 0, 32);
1156   }
1157 }
1158 
1159 void TurboAssembler::Usw(Register rd, const MemOperand& rs) {
1160   DCHECK(rd != at);
1161   DCHECK(rs.rm() != at);
1162   DCHECK(rd != rs.rm());
1163   if (kArchVariant == kMips64r6) {
1164     Sw(rd, rs);
1165   } else {
1166     DCHECK_EQ(kArchVariant, kMips64r2);
1167     DCHECK(kMipsSwrOffset <= 3 && kMipsSwlOffset <= 3);
1168     MemOperand source = rs;
1169     // Adjust offset for two accesses and check if offset + 3 fits into int16_t.
1170     AdjustBaseAndOffset(&source, OffsetAccessType::TWO_ACCESSES, 3);
1171     swr(rd, MemOperand(source.rm(), source.offset() + kMipsSwrOffset));
1172     swl(rd, MemOperand(source.rm(), source.offset() + kMipsSwlOffset));
1173   }
1174 }
1175 
1176 void TurboAssembler::Ulh(Register rd, const MemOperand& rs) {
1177   DCHECK(rd != at);
1178   DCHECK(rs.rm() != at);
1179   if (kArchVariant == kMips64r6) {
1180     Lh(rd, rs);
1181   } else {
1182     DCHECK_EQ(kArchVariant, kMips64r2);
1183     MemOperand source = rs;
1184     // Adjust offset for two accesses and check if offset + 1 fits into int16_t.
1185     AdjustBaseAndOffset(&source, OffsetAccessType::TWO_ACCESSES, 1);
1186     UseScratchRegisterScope temps(this);
1187     Register scratch = temps.Acquire();
1188     if (source.rm() == scratch) {
1189 #if defined(V8_TARGET_LITTLE_ENDIAN)
1190       Lb(rd, MemOperand(source.rm(), source.offset() + 1));
1191       Lbu(scratch, source);
1192 #elif defined(V8_TARGET_BIG_ENDIAN)
1193       Lb(rd, source);
1194       Lbu(scratch, MemOperand(source.rm(), source.offset() + 1));
1195 #endif
1196     } else {
1197 #if defined(V8_TARGET_LITTLE_ENDIAN)
1198       Lbu(scratch, source);
1199       Lb(rd, MemOperand(source.rm(), source.offset() + 1));
1200 #elif defined(V8_TARGET_BIG_ENDIAN)
1201       Lbu(scratch, MemOperand(source.rm(), source.offset() + 1));
1202       Lb(rd, source);
1203 #endif
1204     }
1205     dsll(rd, rd, 8);
1206     or_(rd, rd, scratch);
1207   }
1208 }
1209 
1210 void TurboAssembler::Ulhu(Register rd, const MemOperand& rs) {
1211   DCHECK(rd != at);
1212   DCHECK(rs.rm() != at);
1213   if (kArchVariant == kMips64r6) {
1214     Lhu(rd, rs);
1215   } else {
1216     DCHECK_EQ(kArchVariant, kMips64r2);
1217     MemOperand source = rs;
1218     // Adjust offset for two accesses and check if offset + 1 fits into int16_t.
1219     AdjustBaseAndOffset(&source, OffsetAccessType::TWO_ACCESSES, 1);
1220     UseScratchRegisterScope temps(this);
1221     Register scratch = temps.Acquire();
1222     if (source.rm() == scratch) {
1223 #if defined(V8_TARGET_LITTLE_ENDIAN)
1224       Lbu(rd, MemOperand(source.rm(), source.offset() + 1));
1225       Lbu(scratch, source);
1226 #elif defined(V8_TARGET_BIG_ENDIAN)
1227       Lbu(rd, source);
1228       Lbu(scratch, MemOperand(source.rm(), source.offset() + 1));
1229 #endif
1230     } else {
1231 #if defined(V8_TARGET_LITTLE_ENDIAN)
1232       Lbu(scratch, source);
1233       Lbu(rd, MemOperand(source.rm(), source.offset() + 1));
1234 #elif defined(V8_TARGET_BIG_ENDIAN)
1235       Lbu(scratch, MemOperand(source.rm(), source.offset() + 1));
1236       Lbu(rd, source);
1237 #endif
1238     }
1239     dsll(rd, rd, 8);
1240     or_(rd, rd, scratch);
1241   }
1242 }
1243 
1244 void TurboAssembler::Ush(Register rd, const MemOperand& rs, Register scratch) {
1245   DCHECK(rd != at);
1246   DCHECK(rs.rm() != at);
1247   DCHECK(rs.rm() != scratch);
1248   DCHECK(scratch != at);
1249   if (kArchVariant == kMips64r6) {
1250     Sh(rd, rs);
1251   } else {
1252     DCHECK_EQ(kArchVariant, kMips64r2);
1253     MemOperand source = rs;
1254     // Adjust offset for two accesses and check if offset + 1 fits into int16_t.
1255     AdjustBaseAndOffset(&source, OffsetAccessType::TWO_ACCESSES, 1);
1256 
1257     if (scratch != rd) {
1258       mov(scratch, rd);
1259     }
1260 
1261 #if defined(V8_TARGET_LITTLE_ENDIAN)
1262     Sb(scratch, source);
1263     srl(scratch, scratch, 8);
1264     Sb(scratch, MemOperand(source.rm(), source.offset() + 1));
1265 #elif defined(V8_TARGET_BIG_ENDIAN)
1266     Sb(scratch, MemOperand(source.rm(), source.offset() + 1));
1267     srl(scratch, scratch, 8);
1268     Sb(scratch, source);
1269 #endif
1270   }
1271 }
1272 
1273 void TurboAssembler::Uld(Register rd, const MemOperand& rs) {
1274   DCHECK(rd != at);
1275   DCHECK(rs.rm() != at);
1276   if (kArchVariant == kMips64r6) {
1277     Ld(rd, rs);
1278   } else {
1279     DCHECK_EQ(kArchVariant, kMips64r2);
1280     DCHECK(kMipsLdrOffset <= 7 && kMipsLdlOffset <= 7);
1281     MemOperand source = rs;
1282     // Adjust offset for two accesses and check if offset + 7 fits into int16_t.
1283     AdjustBaseAndOffset(&source, OffsetAccessType::TWO_ACCESSES, 7);
1284     if (rd != source.rm()) {
1285       ldr(rd, MemOperand(source.rm(), source.offset() + kMipsLdrOffset));
1286       ldl(rd, MemOperand(source.rm(), source.offset() + kMipsLdlOffset));
1287     } else {
1288       UseScratchRegisterScope temps(this);
1289       Register scratch = temps.Acquire();
1290       ldr(scratch, MemOperand(rs.rm(), rs.offset() + kMipsLdrOffset));
1291       ldl(scratch, MemOperand(rs.rm(), rs.offset() + kMipsLdlOffset));
1292       mov(rd, scratch);
1293     }
1294   }
1295 }
1296 
1297 // Load consequent 32-bit word pair in 64-bit reg. and put first word in low
1298 // bits,
1299 // second word in high bits.
1300 void MacroAssembler::LoadWordPair(Register rd, const MemOperand& rs,
1301                                   Register scratch) {
1302   Lwu(rd, rs);
1303   Lw(scratch, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2));
1304   dsll32(scratch, scratch, 0);
1305   Daddu(rd, rd, scratch);
1306 }
1307 
1308 void TurboAssembler::Usd(Register rd, const MemOperand& rs) {
1309   DCHECK(rd != at);
1310   DCHECK(rs.rm() != at);
1311   if (kArchVariant == kMips64r6) {
1312     Sd(rd, rs);
1313   } else {
1314     DCHECK_EQ(kArchVariant, kMips64r2);
1315     DCHECK(kMipsSdrOffset <= 7 && kMipsSdlOffset <= 7);
1316     MemOperand source = rs;
1317     // Adjust offset for two accesses and check if offset + 7 fits into int16_t.
1318     AdjustBaseAndOffset(&source, OffsetAccessType::TWO_ACCESSES, 7);
1319     sdr(rd, MemOperand(source.rm(), source.offset() + kMipsSdrOffset));
1320     sdl(rd, MemOperand(source.rm(), source.offset() + kMipsSdlOffset));
1321   }
1322 }
1323 
1324 // Do 64-bit store as two consequent 32-bit stores to unaligned address.
1325 void MacroAssembler::StoreWordPair(Register rd, const MemOperand& rs,
1326                                    Register scratch) {
1327   Sw(rd, rs);
1328   dsrl32(scratch, rd, 0);
1329   Sw(scratch, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2));
1330 }
1331 
1332 void TurboAssembler::Ulwc1(FPURegister fd, const MemOperand& rs,
1333                            Register scratch) {
1334   if (kArchVariant == kMips64r6) {
1335     Lwc1(fd, rs);
1336   } else {
1337     DCHECK_EQ(kArchVariant, kMips64r2);
1338     Ulw(scratch, rs);
1339     mtc1(scratch, fd);
1340   }
1341 }
1342 
1343 void TurboAssembler::Uswc1(FPURegister fd, const MemOperand& rs,
1344                            Register scratch) {
1345   if (kArchVariant == kMips64r6) {
1346     Swc1(fd, rs);
1347   } else {
1348     DCHECK_EQ(kArchVariant, kMips64r2);
1349     mfc1(scratch, fd);
1350     Usw(scratch, rs);
1351   }
1352 }
1353 
1354 void TurboAssembler::Uldc1(FPURegister fd, const MemOperand& rs,
1355                            Register scratch) {
1356   DCHECK(scratch != at);
1357   if (kArchVariant == kMips64r6) {
1358     Ldc1(fd, rs);
1359   } else {
1360     DCHECK_EQ(kArchVariant, kMips64r2);
1361     Uld(scratch, rs);
1362     dmtc1(scratch, fd);
1363   }
1364 }
1365 
1366 void TurboAssembler::Usdc1(FPURegister fd, const MemOperand& rs,
1367                            Register scratch) {
1368   DCHECK(scratch != at);
1369   if (kArchVariant == kMips64r6) {
1370     Sdc1(fd, rs);
1371   } else {
1372     DCHECK_EQ(kArchVariant, kMips64r2);
1373     dmfc1(scratch, fd);
1374     Usd(scratch, rs);
1375   }
1376 }
1377 
1378 void TurboAssembler::Lb(Register rd, const MemOperand& rs) {
1379   MemOperand source = rs;
1380   AdjustBaseAndOffset(&source);
1381   lb(rd, source);
1382 }
1383 
1384 void TurboAssembler::Lbu(Register rd, const MemOperand& rs) {
1385   MemOperand source = rs;
1386   AdjustBaseAndOffset(&source);
1387   lbu(rd, source);
1388 }
1389 
1390 void TurboAssembler::Sb(Register rd, const MemOperand& rs) {
1391   MemOperand source = rs;
1392   AdjustBaseAndOffset(&source);
1393   sb(rd, source);
1394 }
1395 
1396 void TurboAssembler::Lh(Register rd, const MemOperand& rs) {
1397   MemOperand source = rs;
1398   AdjustBaseAndOffset(&source);
1399   lh(rd, source);
1400 }
1401 
1402 void TurboAssembler::Lhu(Register rd, const MemOperand& rs) {
1403   MemOperand source = rs;
1404   AdjustBaseAndOffset(&source);
1405   lhu(rd, source);
1406 }
1407 
1408 void TurboAssembler::Sh(Register rd, const MemOperand& rs) {
1409   MemOperand source = rs;
1410   AdjustBaseAndOffset(&source);
1411   sh(rd, source);
1412 }
1413 
1414 void TurboAssembler::Lw(Register rd, const MemOperand& rs) {
1415   MemOperand source = rs;
1416   AdjustBaseAndOffset(&source);
1417   lw(rd, source);
1418 }
1419 
1420 void TurboAssembler::Lwu(Register rd, const MemOperand& rs) {
1421   MemOperand source = rs;
1422   AdjustBaseAndOffset(&source);
1423   lwu(rd, source);
1424 }
1425 
1426 void TurboAssembler::Sw(Register rd, const MemOperand& rs) {
1427   MemOperand source = rs;
1428   AdjustBaseAndOffset(&source);
1429   sw(rd, source);
1430 }
1431 
1432 void TurboAssembler::Ld(Register rd, const MemOperand& rs) {
1433   MemOperand source = rs;
1434   AdjustBaseAndOffset(&source);
1435   ld(rd, source);
1436 }
1437 
1438 void TurboAssembler::Sd(Register rd, const MemOperand& rs) {
1439   MemOperand source = rs;
1440   AdjustBaseAndOffset(&source);
1441   sd(rd, source);
1442 }
1443 
1444 void TurboAssembler::Lwc1(FPURegister fd, const MemOperand& src) {
1445   MemOperand tmp = src;
1446   AdjustBaseAndOffset(&tmp);
1447   lwc1(fd, tmp);
1448 }
1449 
1450 void TurboAssembler::Swc1(FPURegister fs, const MemOperand& src) {
1451   MemOperand tmp = src;
1452   AdjustBaseAndOffset(&tmp);
1453   swc1(fs, tmp);
1454 }
1455 
1456 void TurboAssembler::Ldc1(FPURegister fd, const MemOperand& src) {
1457   MemOperand tmp = src;
1458   AdjustBaseAndOffset(&tmp);
1459   ldc1(fd, tmp);
1460 }
1461 
1462 void TurboAssembler::Sdc1(FPURegister fs, const MemOperand& src) {
1463   MemOperand tmp = src;
1464   AdjustBaseAndOffset(&tmp);
1465   sdc1(fs, tmp);
1466 }
1467 
1468 void TurboAssembler::Ll(Register rd, const MemOperand& rs) {
1469   bool is_one_instruction = (kArchVariant == kMips64r6) ? is_int9(rs.offset())
1470                                                         : is_int16(rs.offset());
1471   if (is_one_instruction) {
1472     ll(rd, rs);
1473   } else {
1474     UseScratchRegisterScope temps(this);
1475     Register scratch = temps.Acquire();
1476     li(scratch, rs.offset());
1477     daddu(scratch, scratch, rs.rm());
1478     ll(rd, MemOperand(scratch, 0));
1479   }
1480 }
1481 
1482 void TurboAssembler::Lld(Register rd, const MemOperand& rs) {
1483   bool is_one_instruction = (kArchVariant == kMips64r6) ? is_int9(rs.offset())
1484                                                         : is_int16(rs.offset());
1485   if (is_one_instruction) {
1486     lld(rd, rs);
1487   } else {
1488     UseScratchRegisterScope temps(this);
1489     Register scratch = temps.Acquire();
1490     li(scratch, rs.offset());
1491     daddu(scratch, scratch, rs.rm());
1492     lld(rd, MemOperand(scratch, 0));
1493   }
1494 }
1495 
1496 void TurboAssembler::Sc(Register rd, const MemOperand& rs) {
1497   bool is_one_instruction = (kArchVariant == kMips64r6) ? is_int9(rs.offset())
1498                                                         : is_int16(rs.offset());
1499   if (is_one_instruction) {
1500     sc(rd, rs);
1501   } else {
1502     UseScratchRegisterScope temps(this);
1503     Register scratch = temps.Acquire();
1504     li(scratch, rs.offset());
1505     daddu(scratch, scratch, rs.rm());
1506     sc(rd, MemOperand(scratch, 0));
1507   }
1508 }
1509 
1510 void TurboAssembler::Scd(Register rd, const MemOperand& rs) {
1511   bool is_one_instruction = (kArchVariant == kMips64r6) ? is_int9(rs.offset())
1512                                                         : is_int16(rs.offset());
1513   if (is_one_instruction) {
1514     scd(rd, rs);
1515   } else {
1516     UseScratchRegisterScope temps(this);
1517     Register scratch = temps.Acquire();
1518     li(scratch, rs.offset());
1519     daddu(scratch, scratch, rs.rm());
1520     scd(rd, MemOperand(scratch, 0));
1521   }
1522 }
1523 
1524 void TurboAssembler::li(Register dst, Handle<HeapObject> value, LiFlags mode) {
1525   // TODO(jgruber,v8:8887): Also consider a root-relative load when generating
1526   // non-isolate-independent code. In many cases it might be cheaper than
1527   // embedding the relocatable value.
1528   if (root_array_available_ && options().isolate_independent_code) {
1529     IndirectLoadConstant(dst, value);
1530     return;
1531   }
1532   li(dst, Operand(value), mode);
1533 }
1534 
1535 void TurboAssembler::li(Register dst, ExternalReference value, LiFlags mode) {
1536   // TODO(jgruber,v8:8887): Also consider a root-relative load when generating
1537   // non-isolate-independent code. In many cases it might be cheaper than
1538   // embedding the relocatable value.
1539   if (root_array_available_ && options().isolate_independent_code) {
1540     IndirectLoadExternalReference(dst, value);
1541     return;
1542   }
1543   li(dst, Operand(value), mode);
1544 }
1545 
1546 void TurboAssembler::li(Register dst, const StringConstantBase* string,
1547                         LiFlags mode) {
1548   li(dst, Operand::EmbeddedStringConstant(string), mode);
1549 }
1550 
1551 static inline int InstrCountForLiLower32Bit(int64_t value) {
1552   if (!is_int16(static_cast<int32_t>(value)) && (value & kUpper16MaskOf64) &&
1553       (value & kImm16Mask)) {
1554     return 2;
1555   } else {
1556     return 1;
1557   }
1558 }
1559 
1560 void TurboAssembler::LiLower32BitHelper(Register rd, Operand j) {
1561   if (is_int16(static_cast<int32_t>(j.immediate()))) {
1562     daddiu(rd, zero_reg, (j.immediate() & kImm16Mask));
1563   } else if (!(j.immediate() & kUpper16MaskOf64)) {
1564     ori(rd, zero_reg, j.immediate() & kImm16Mask);
1565   } else {
1566     lui(rd, j.immediate() >> kLuiShift & kImm16Mask);
1567     if (j.immediate() & kImm16Mask) {
1568       ori(rd, rd, j.immediate() & kImm16Mask);
1569     }
1570   }
1571 }
1572 
1573 static inline int InstrCountForLoadReplicatedConst32(int64_t value) {
1574   uint32_t x = static_cast<uint32_t>(value);
1575   uint32_t y = static_cast<uint32_t>(value >> 32);
1576 
1577   if (x == y) {
1578     return (is_uint16(x) || is_int16(x) || (x & kImm16Mask) == 0) ? 2 : 3;
1579   }
1580 
1581   return INT_MAX;
1582 }
1583 
1584 int TurboAssembler::InstrCountForLi64Bit(int64_t value) {
1585   if (is_int32(value)) {
1586     return InstrCountForLiLower32Bit(value);
1587   } else {
1588     int bit31 = value >> 31 & 0x1;
1589     if ((value & kUpper16MaskOf64) == 0 && is_int16(value >> 32) &&
1590         kArchVariant == kMips64r6) {
1591       return 2;
1592     } else if ((value & (kHigher16MaskOf64 | kUpper16MaskOf64)) == 0 &&
1593                kArchVariant == kMips64r6) {
1594       return 2;
1595     } else if ((value & kImm16Mask) == 0 && is_int16((value >> 32) + bit31) &&
1596                kArchVariant == kMips64r6) {
1597       return 2;
1598     } else if ((value & kImm16Mask) == 0 &&
1599                ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF) &&
1600                kArchVariant == kMips64r6) {
1601       return 2;
1602     } else if (is_int16(static_cast<int32_t>(value)) &&
1603                is_int16((value >> 32) + bit31) && kArchVariant == kMips64r6) {
1604       return 2;
1605     } else if (is_int16(static_cast<int32_t>(value)) &&
1606                ((value >> 31) & 0x1FFFF) == ((0x20000 - bit31) & 0x1FFFF) &&
1607                kArchVariant == kMips64r6) {
1608       return 2;
1609     } else if (base::bits::IsPowerOfTwo(value + 1) ||
1610                value == std::numeric_limits<int64_t>::max()) {
1611       return 2;
1612     } else {
1613       int shift_cnt = base::bits::CountTrailingZeros64(value);
1614       int rep32_count = InstrCountForLoadReplicatedConst32(value);
1615       int64_t tmp = value >> shift_cnt;
1616       if (is_uint16(tmp)) {
1617         return 2;
1618       } else if (is_int16(tmp)) {
1619         return 2;
1620       } else if (rep32_count < 3) {
1621         return 2;
1622       } else if (is_int32(tmp)) {
1623         return 3;
1624       } else {
1625         shift_cnt = 16 + base::bits::CountTrailingZeros64(value >> 16);
1626         tmp = value >> shift_cnt;
1627         if (is_uint16(tmp)) {
1628           return 3;
1629         } else if (is_int16(tmp)) {
1630           return 3;
1631         } else if (rep32_count < 4) {
1632           return 3;
1633         } else if (kArchVariant == kMips64r6) {
1634           int64_t imm = value;
1635           int count = InstrCountForLiLower32Bit(imm);
1636           imm = (imm >> 32) + bit31;
1637           if (imm & kImm16Mask) {
1638             count++;
1639           }
1640           imm = (imm >> 16) + (imm >> 15 & 0x1);
1641           if (imm & kImm16Mask) {
1642             count++;
1643           }
1644           return count;
1645         } else {
1646           if (is_int48(value)) {
1647             int64_t k = value >> 16;
1648             int count = InstrCountForLiLower32Bit(k) + 1;
1649             if (value & kImm16Mask) {
1650               count++;
1651             }
1652             return count;
1653           } else {
1654             int64_t k = value >> 32;
1655             int count = InstrCountForLiLower32Bit(k);
1656             if ((value >> 16) & kImm16Mask) {
1657               count += 3;
1658               if (value & kImm16Mask) {
1659                 count++;
1660               }
1661             } else {
1662               count++;
1663               if (value & kImm16Mask) {
1664                 count++;
1665               }
1666             }
1667             return count;
1668           }
1669         }
1670       }
1671     }
1672   }
1673   UNREACHABLE();
1674   return INT_MAX;
1675 }
1676 
1677 // All changes to if...else conditions here must be added to
1678 // InstrCountForLi64Bit as well.
1679 void TurboAssembler::li_optimized(Register rd, Operand j, LiFlags mode) {
1680   DCHECK(!j.is_reg());
1681   DCHECK(!MustUseReg(j.rmode()));
1682   DCHECK(mode == OPTIMIZE_SIZE);
1683   BlockTrampolinePoolScope block_trampoline_pool(this);
1684   // Normal load of an immediate value which does not need Relocation Info.
1685   if (is_int32(j.immediate())) {
1686     LiLower32BitHelper(rd, j);
1687   } else {
1688     int bit31 = j.immediate() >> 31 & 0x1;
1689     if ((j.immediate() & kUpper16MaskOf64) == 0 &&
1690         is_int16(j.immediate() >> 32) && kArchVariant == kMips64r6) {
1691       // 64-bit value which consists of an unsigned 16-bit value in its
1692       // least significant 32-bits, and a signed 16-bit value in its
1693       // most significant 32-bits.
1694       ori(rd, zero_reg, j.immediate() & kImm16Mask);
1695       dahi(rd, j.immediate() >> 32 & kImm16Mask);
1696     } else if ((j.immediate() & (kHigher16MaskOf64 | kUpper16MaskOf64)) == 0 &&
1697                kArchVariant == kMips64r6) {
1698       // 64-bit value which consists of an unsigned 16-bit value in its
1699       // least significant 48-bits, and a signed 16-bit value in its
1700       // most significant 16-bits.
1701       ori(rd, zero_reg, j.immediate() & kImm16Mask);
1702       dati(rd, j.immediate() >> 48 & kImm16Mask);
1703     } else if ((j.immediate() & kImm16Mask) == 0 &&
1704                is_int16((j.immediate() >> 32) + bit31) &&
1705                kArchVariant == kMips64r6) {
1706       // 16 LSBs (Least Significant Bits) all set to zero.
1707       // 48 MSBs (Most Significant Bits) hold a signed 32-bit value.
1708       lui(rd, j.immediate() >> kLuiShift & kImm16Mask);
1709       dahi(rd, ((j.immediate() >> 32) + bit31) & kImm16Mask);
1710     } else if ((j.immediate() & kImm16Mask) == 0 &&
1711                ((j.immediate() >> 31) & 0x1FFFF) ==
1712                    ((0x20000 - bit31) & 0x1FFFF) &&
1713                kArchVariant == kMips64r6) {
1714       // 16 LSBs all set to zero.
1715       // 48 MSBs hold a signed value which can't be represented by signed
1716       // 32-bit number, and the middle 16 bits are all zero, or all one.
1717       lui(rd, j.immediate() >> kLuiShift & kImm16Mask);
1718       dati(rd, ((j.immediate() >> 48) + bit31) & kImm16Mask);
1719     } else if (is_int16(static_cast<int32_t>(j.immediate())) &&
1720                is_int16((j.immediate() >> 32) + bit31) &&
1721                kArchVariant == kMips64r6) {
1722       // 32 LSBs contain a signed 16-bit number.
1723       // 32 MSBs contain a signed 16-bit number.
1724       daddiu(rd, zero_reg, j.immediate() & kImm16Mask);
1725       dahi(rd, ((j.immediate() >> 32) + bit31) & kImm16Mask);
1726     } else if (is_int16(static_cast<int32_t>(j.immediate())) &&
1727                ((j.immediate() >> 31) & 0x1FFFF) ==
1728                    ((0x20000 - bit31) & 0x1FFFF) &&
1729                kArchVariant == kMips64r6) {
1730       // 48 LSBs contain an unsigned 16-bit number.
1731       // 16 MSBs contain a signed 16-bit number.
1732       daddiu(rd, zero_reg, j.immediate() & kImm16Mask);
1733       dati(rd, ((j.immediate() >> 48) + bit31) & kImm16Mask);
1734     } else if (base::bits::IsPowerOfTwo(j.immediate() + 1) ||
1735                j.immediate() == std::numeric_limits<int64_t>::max()) {
1736       // 64-bit values which have their "n" LSBs set to one, and their
1737       // "64-n" MSBs set to zero. "n" must meet the restrictions 0 < n < 64.
1738       int shift_cnt = 64 - base::bits::CountTrailingZeros64(j.immediate() + 1);
1739       daddiu(rd, zero_reg, -1);
1740       if (shift_cnt < 32) {
1741         dsrl(rd, rd, shift_cnt);
1742       } else {
1743         dsrl32(rd, rd, shift_cnt & 31);
1744       }
1745     } else {
1746       int shift_cnt = base::bits::CountTrailingZeros64(j.immediate());
1747       int rep32_count = InstrCountForLoadReplicatedConst32(j.immediate());
1748       int64_t tmp = j.immediate() >> shift_cnt;
1749       if (is_uint16(tmp)) {
1750         // Value can be computed by loading a 16-bit unsigned value, and
1751         // then shifting left.
1752         ori(rd, zero_reg, tmp & kImm16Mask);
1753         if (shift_cnt < 32) {
1754           dsll(rd, rd, shift_cnt);
1755         } else {
1756           dsll32(rd, rd, shift_cnt & 31);
1757         }
1758       } else if (is_int16(tmp)) {
1759         // Value can be computed by loading a 16-bit signed value, and
1760         // then shifting left.
1761         daddiu(rd, zero_reg, static_cast<int32_t>(tmp));
1762         if (shift_cnt < 32) {
1763           dsll(rd, rd, shift_cnt);
1764         } else {
1765           dsll32(rd, rd, shift_cnt & 31);
1766         }
1767       } else if (rep32_count < 3) {
1768         // Value being loaded has 32 LSBs equal to the 32 MSBs, and the
1769         // value loaded into the 32 LSBs can be loaded with a single
1770         // MIPS instruction.
1771         LiLower32BitHelper(rd, j);
1772         Dins(rd, rd, 32, 32);
1773       } else if (is_int32(tmp)) {
1774         // Loads with 3 instructions.
1775         // Value can be computed by loading a 32-bit signed value, and
1776         // then shifting left.
1777         lui(rd, tmp >> kLuiShift & kImm16Mask);
1778         ori(rd, rd, tmp & kImm16Mask);
1779         if (shift_cnt < 32) {
1780           dsll(rd, rd, shift_cnt);
1781         } else {
1782           dsll32(rd, rd, shift_cnt & 31);
1783         }
1784       } else {
1785         shift_cnt = 16 + base::bits::CountTrailingZeros64(j.immediate() >> 16);
1786         tmp = j.immediate() >> shift_cnt;
1787         if (is_uint16(tmp)) {
1788           // Value can be computed by loading a 16-bit unsigned value,
1789           // shifting left, and "or"ing in another 16-bit unsigned value.
1790           ori(rd, zero_reg, tmp & kImm16Mask);
1791           if (shift_cnt < 32) {
1792             dsll(rd, rd, shift_cnt);
1793           } else {
1794             dsll32(rd, rd, shift_cnt & 31);
1795           }
1796           ori(rd, rd, j.immediate() & kImm16Mask);
1797         } else if (is_int16(tmp)) {
1798           // Value can be computed by loading a 16-bit signed value,
1799           // shifting left, and "or"ing in a 16-bit unsigned value.
1800           daddiu(rd, zero_reg, static_cast<int32_t>(tmp));
1801           if (shift_cnt < 32) {
1802             dsll(rd, rd, shift_cnt);
1803           } else {
1804             dsll32(rd, rd, shift_cnt & 31);
1805           }
1806           ori(rd, rd, j.immediate() & kImm16Mask);
1807         } else if (rep32_count < 4) {
1808           // Value being loaded has 32 LSBs equal to the 32 MSBs, and the
1809           // value in the 32 LSBs requires 2 MIPS instructions to load.
1810           LiLower32BitHelper(rd, j);
1811           Dins(rd, rd, 32, 32);
1812         } else if (kArchVariant == kMips64r6) {
1813           // Loads with 3-4 instructions.
1814           // Catch-all case to get any other 64-bit values which aren't
1815           // handled by special cases above.
1816           int64_t imm = j.immediate();
1817           LiLower32BitHelper(rd, j);
1818           imm = (imm >> 32) + bit31;
1819           if (imm & kImm16Mask) {
1820             dahi(rd, imm & kImm16Mask);
1821           }
1822           imm = (imm >> 16) + (imm >> 15 & 0x1);
1823           if (imm & kImm16Mask) {
1824             dati(rd, imm & kImm16Mask);
1825           }
1826         } else {
1827           if (is_int48(j.immediate())) {
1828             Operand k = Operand(j.immediate() >> 16);
1829             LiLower32BitHelper(rd, k);
1830             dsll(rd, rd, 16);
1831             if (j.immediate() & kImm16Mask) {
1832               ori(rd, rd, j.immediate() & kImm16Mask);
1833             }
1834           } else {
1835             Operand k = Operand(j.immediate() >> 32);
1836             LiLower32BitHelper(rd, k);
1837             if ((j.immediate() >> 16) & kImm16Mask) {
1838               dsll(rd, rd, 16);
1839               ori(rd, rd, (j.immediate() >> 16) & kImm16Mask);
1840               dsll(rd, rd, 16);
1841               if (j.immediate() & kImm16Mask) {
1842                 ori(rd, rd, j.immediate() & kImm16Mask);
1843               }
1844             } else {
1845               dsll32(rd, rd, 0);
1846               if (j.immediate() & kImm16Mask) {
1847                 ori(rd, rd, j.immediate() & kImm16Mask);
1848               }
1849             }
1850           }
1851         }
1852       }
1853     }
1854   }
1855 }
1856 
1857 void TurboAssembler::li(Register rd, Operand j, LiFlags mode) {
1858   DCHECK(!j.is_reg());
1859   BlockTrampolinePoolScope block_trampoline_pool(this);
1860   if (!MustUseReg(j.rmode()) && mode == OPTIMIZE_SIZE) {
1861     int li_count = InstrCountForLi64Bit(j.immediate());
1862     int li_neg_count = InstrCountForLi64Bit(-j.immediate());
1863     int li_not_count = InstrCountForLi64Bit(~j.immediate());
1864     // Loading -MIN_INT64 could cause problems, but loading MIN_INT64 takes only
1865     // two instructions so no need to check for this.
1866     if (li_neg_count <= li_not_count && li_neg_count < li_count - 1) {
1867       DCHECK(j.immediate() != std::numeric_limits<int64_t>::min());
1868       li_optimized(rd, Operand(-j.immediate()), mode);
1869       Dsubu(rd, zero_reg, rd);
1870     } else if (li_neg_count > li_not_count && li_not_count < li_count - 1) {
1871       DCHECK(j.immediate() != std::numeric_limits<int64_t>::min());
1872       li_optimized(rd, Operand(~j.immediate()), mode);
1873       nor(rd, rd, rd);
1874     } else {
1875       li_optimized(rd, j, mode);
1876     }
1877   } else if (MustUseReg(j.rmode())) {
1878     int64_t immediate;
1879     if (j.IsHeapObjectRequest()) {
1880       RequestHeapObject(j.heap_object_request());
1881       immediate = 0;
1882     } else {
1883       immediate = j.immediate();
1884     }
1885 
1886     RecordRelocInfo(j.rmode(), immediate);
1887     lui(rd, (immediate >> 32) & kImm16Mask);
1888     ori(rd, rd, (immediate >> 16) & kImm16Mask);
1889     dsll(rd, rd, 16);
1890     ori(rd, rd, immediate & kImm16Mask);
1891   } else if (mode == ADDRESS_LOAD) {
1892     // We always need the same number of instructions as we may need to patch
1893     // this code to load another value which may need all 4 instructions.
1894     lui(rd, (j.immediate() >> 32) & kImm16Mask);
1895     ori(rd, rd, (j.immediate() >> 16) & kImm16Mask);
1896     dsll(rd, rd, 16);
1897     ori(rd, rd, j.immediate() & kImm16Mask);
1898   } else {  // mode == CONSTANT_SIZE - always emit the same instruction
1899             // sequence.
1900     if (kArchVariant == kMips64r6) {
1901       int64_t imm = j.immediate();
1902       lui(rd, imm >> kLuiShift & kImm16Mask);
1903       ori(rd, rd, (imm & kImm16Mask));
1904       imm = (imm >> 32) + ((imm >> 31) & 0x1);
1905       dahi(rd, imm & kImm16Mask & kImm16Mask);
1906       imm = (imm >> 16) + ((imm >> 15) & 0x1);
1907       dati(rd, imm & kImm16Mask & kImm16Mask);
1908     } else {
1909       lui(rd, (j.immediate() >> 48) & kImm16Mask);
1910       ori(rd, rd, (j.immediate() >> 32) & kImm16Mask);
1911       dsll(rd, rd, 16);
1912       ori(rd, rd, (j.immediate() >> 16) & kImm16Mask);
1913       dsll(rd, rd, 16);
1914       ori(rd, rd, j.immediate() & kImm16Mask);
1915     }
1916   }
1917 }
1918 
1919 void TurboAssembler::MultiPush(RegList regs) {
1920   int16_t num_to_push = regs.Count();
1921   int16_t stack_offset = num_to_push * kPointerSize;
1922 
1923   Dsubu(sp, sp, Operand(stack_offset));
1924   for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
1925     if ((regs.bits() & (1 << i)) != 0) {
1926       stack_offset -= kPointerSize;
1927       Sd(ToRegister(i), MemOperand(sp, stack_offset));
1928     }
1929   }
1930 }
1931 
1932 void TurboAssembler::MultiPop(RegList regs) {
1933   int16_t stack_offset = 0;
1934 
1935   for (int16_t i = 0; i < kNumRegisters; i++) {
1936     if ((regs.bits() & (1 << i)) != 0) {
1937       Ld(ToRegister(i), MemOperand(sp, stack_offset));
1938       stack_offset += kPointerSize;
1939     }
1940   }
1941   daddiu(sp, sp, stack_offset);
1942 }
1943 
1944 void TurboAssembler::MultiPushFPU(DoubleRegList regs) {
1945   int16_t num_to_push = regs.Count();
1946   int16_t stack_offset = num_to_push * kDoubleSize;
1947 
1948   Dsubu(sp, sp, Operand(stack_offset));
1949   for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
1950     if ((regs.bits() & (1 << i)) != 0) {
1951       stack_offset -= kDoubleSize;
1952       Sdc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
1953     }
1954   }
1955 }
1956 
1957 void TurboAssembler::MultiPopFPU(DoubleRegList regs) {
1958   int16_t stack_offset = 0;
1959 
1960   for (int16_t i = 0; i < kNumRegisters; i++) {
1961     if ((regs.bits() & (1 << i)) != 0) {
1962       Ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
1963       stack_offset += kDoubleSize;
1964     }
1965   }
1966   daddiu(sp, sp, stack_offset);
1967 }
1968 
1969 void TurboAssembler::MultiPushMSA(DoubleRegList regs) {
1970   int16_t num_to_push = regs.Count();
1971   int16_t stack_offset = num_to_push * kSimd128Size;
1972 
1973   Dsubu(sp, sp, Operand(stack_offset));
1974   for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
1975     if ((regs.bits() & (1 << i)) != 0) {
1976       stack_offset -= kSimd128Size;
1977       st_d(MSARegister::from_code(i), MemOperand(sp, stack_offset));
1978     }
1979   }
1980 }
1981 
1982 void TurboAssembler::MultiPopMSA(DoubleRegList regs) {
1983   int16_t stack_offset = 0;
1984 
1985   for (int16_t i = 0; i < kNumRegisters; i++) {
1986     if ((regs.bits() & (1 << i)) != 0) {
1987       ld_d(MSARegister::from_code(i), MemOperand(sp, stack_offset));
1988       stack_offset += kSimd128Size;
1989     }
1990   }
1991   daddiu(sp, sp, stack_offset);
1992 }
1993 
1994 void TurboAssembler::Ext(Register rt, Register rs, uint16_t pos,
1995                          uint16_t size) {
1996   DCHECK_LT(pos, 32);
1997   DCHECK_LT(pos + size, 33);
1998   ext_(rt, rs, pos, size);
1999 }
2000 
2001 void TurboAssembler::Dext(Register rt, Register rs, uint16_t pos,
2002                           uint16_t size) {
2003   DCHECK(pos < 64 && 0 < size && size <= 64 && 0 < pos + size &&
2004          pos + size <= 64);
2005   if (size > 32) {
2006     dextm_(rt, rs, pos, size);
2007   } else if (pos >= 32) {
2008     dextu_(rt, rs, pos, size);
2009   } else {
2010     dext_(rt, rs, pos, size);
2011   }
2012 }
2013 
2014 void TurboAssembler::Ins(Register rt, Register rs, uint16_t pos,
2015                          uint16_t size) {
2016   DCHECK_LT(pos, 32);
2017   DCHECK_LE(pos + size, 32);
2018   DCHECK_NE(size, 0);
2019   ins_(rt, rs, pos, size);
2020 }
2021 
2022 void TurboAssembler::Dins(Register rt, Register rs, uint16_t pos,
2023                           uint16_t size) {
2024   DCHECK(pos < 64 && 0 < size && size <= 64 && 0 < pos + size &&
2025          pos + size <= 64);
2026   if (pos + size <= 32) {
2027     dins_(rt, rs, pos, size);
2028   } else if (pos < 32) {
2029     dinsm_(rt, rs, pos, size);
2030   } else {
2031     dinsu_(rt, rs, pos, size);
2032   }
2033 }
2034 
2035 void TurboAssembler::ExtractBits(Register dest, Register source, Register pos,
2036                                  int size, bool sign_extend) {
2037   dsrav(dest, source, pos);
2038   Dext(dest, dest, 0, size);
2039   if (sign_extend) {
2040     switch (size) {
2041       case 8:
2042         seb(dest, dest);
2043         break;
2044       case 16:
2045         seh(dest, dest);
2046         break;
2047       case 32:
2048         // sign-extend word
2049         sll(dest, dest, 0);
2050         break;
2051       default:
2052         UNREACHABLE();
2053     }
2054   }
2055 }
2056 
2057 void TurboAssembler::InsertBits(Register dest, Register source, Register pos,
2058                                 int size) {
2059   Dror(dest, dest, pos);
2060   Dins(dest, source, 0, size);
2061   {
2062     UseScratchRegisterScope temps(this);
2063     Register scratch = temps.Acquire();
2064     Dsubu(scratch, zero_reg, pos);
2065     Dror(dest, dest, scratch);
2066   }
2067 }
2068 
2069 void TurboAssembler::Neg_s(FPURegister fd, FPURegister fs) {
2070   if (kArchVariant == kMips64r6) {
2071     // r6 neg_s changes the sign for NaN-like operands as well.
2072     neg_s(fd, fs);
2073   } else {
2074     DCHECK_EQ(kArchVariant, kMips64r2);
2075     BlockTrampolinePoolScope block_trampoline_pool(this);
2076     Label is_nan, done;
2077     Register scratch1 = t8;
2078     Register scratch2 = t9;
2079     CompareIsNanF32(fs, fs);
2080     BranchTrueShortF(&is_nan);
2081     Branch(USE_DELAY_SLOT, &done);
2082     // For NaN input, neg_s will return the same NaN value,
2083     // while the sign has to be changed separately.
2084     neg_s(fd, fs);  // In delay slot.
2085     bind(&is_nan);
2086     mfc1(scratch1, fs);
2087     li(scratch2, kBinary32SignMask);
2088     Xor(scratch1, scratch1, scratch2);
2089     mtc1(scratch1, fd);
2090     bind(&done);
2091   }
2092 }
2093 
2094 void TurboAssembler::Neg_d(FPURegister fd, FPURegister fs) {
2095   if (kArchVariant == kMips64r6) {
2096     // r6 neg_d changes the sign for NaN-like operands as well.
2097     neg_d(fd, fs);
2098   } else {
2099     DCHECK_EQ(kArchVariant, kMips64r2);
2100     BlockTrampolinePoolScope block_trampoline_pool(this);
2101     Label is_nan, done;
2102     Register scratch1 = t8;
2103     Register scratch2 = t9;
2104     CompareIsNanF64(fs, fs);
2105     BranchTrueShortF(&is_nan);
2106     Branch(USE_DELAY_SLOT, &done);
2107     // For NaN input, neg_d will return the same NaN value,
2108     // while the sign has to be changed separately.
2109     neg_d(fd, fs);  // In delay slot.
2110     bind(&is_nan);
2111     dmfc1(scratch1, fs);
2112     li(scratch2, base::Double::kSignMask);
2113     Xor(scratch1, scratch1, scratch2);
2114     dmtc1(scratch1, fd);
2115     bind(&done);
2116   }
2117 }
2118 
2119 void TurboAssembler::Cvt_d_uw(FPURegister fd, FPURegister fs) {
2120   // Move the data from fs to t8.
2121   BlockTrampolinePoolScope block_trampoline_pool(this);
2122   mfc1(t8, fs);
2123   Cvt_d_uw(fd, t8);
2124 }
2125 
2126 void TurboAssembler::Cvt_d_uw(FPURegister fd, Register rs) {
2127   BlockTrampolinePoolScope block_trampoline_pool(this);
2128 
2129   // Convert rs to a FP value in fd.
2130   DCHECK(rs != t9);
2131   DCHECK(rs != at);
2132 
2133   // Zero extend int32 in rs.
2134   Dext(t9, rs, 0, 32);
2135   dmtc1(t9, fd);
2136   cvt_d_l(fd, fd);
2137 }
2138 
2139 void TurboAssembler::Cvt_d_ul(FPURegister fd, FPURegister fs) {
2140   BlockTrampolinePoolScope block_trampoline_pool(this);
2141   // Move the data from fs to t8.
2142   dmfc1(t8, fs);
2143   Cvt_d_ul(fd, t8);
2144 }
2145 
2146 void TurboAssembler::Cvt_d_ul(FPURegister fd, Register rs) {
2147   BlockTrampolinePoolScope block_trampoline_pool(this);
2148   // Convert rs to a FP value in fd.
2149 
2150   DCHECK(rs != t9);
2151   DCHECK(rs != at);
2152 
2153   Label msb_clear, conversion_done;
2154 
2155   Branch(&msb_clear, ge, rs, Operand(zero_reg));
2156 
2157   // Rs >= 2^63
2158   andi(t9, rs, 1);
2159   dsrl(rs, rs, 1);
2160   or_(t9, t9, rs);
2161   dmtc1(t9, fd);
2162   cvt_d_l(fd, fd);
2163   Branch(USE_DELAY_SLOT, &conversion_done);
2164   add_d(fd, fd, fd);  // In delay slot.
2165 
2166   bind(&msb_clear);
2167   // Rs < 2^63, we can do simple conversion.
2168   dmtc1(rs, fd);
2169   cvt_d_l(fd, fd);
2170 
2171   bind(&conversion_done);
2172 }
2173 
2174 void TurboAssembler::Cvt_s_uw(FPURegister fd, FPURegister fs) {
2175   BlockTrampolinePoolScope block_trampoline_pool(this);
2176   // Move the data from fs to t8.
2177   mfc1(t8, fs);
2178   Cvt_s_uw(fd, t8);
2179 }
2180 
2181 void TurboAssembler::Cvt_s_uw(FPURegister fd, Register rs) {
2182   BlockTrampolinePoolScope block_trampoline_pool(this);
2183   // Convert rs to a FP value in fd.
2184   DCHECK(rs != t9);
2185   DCHECK(rs != at);
2186 
2187   // Zero extend int32 in rs.
2188   Dext(t9, rs, 0, 32);
2189   dmtc1(t9, fd);
2190   cvt_s_l(fd, fd);
2191 }
2192 
2193 void TurboAssembler::Cvt_s_ul(FPURegister fd, FPURegister fs) {
2194   BlockTrampolinePoolScope block_trampoline_pool(this);
2195   // Move the data from fs to t8.
2196   dmfc1(t8, fs);
2197   Cvt_s_ul(fd, t8);
2198 }
2199 
2200 void TurboAssembler::Cvt_s_ul(FPURegister fd, Register rs) {
2201   BlockTrampolinePoolScope block_trampoline_pool(this);
2202   // Convert rs to a FP value in fd.
2203 
2204   DCHECK(rs != t9);
2205   DCHECK(rs != at);
2206 
2207   Label positive, conversion_done;
2208 
2209   Branch(&positive, ge, rs, Operand(zero_reg));
2210 
2211   // Rs >= 2^31.
2212   andi(t9, rs, 1);
2213   dsrl(rs, rs, 1);
2214   or_(t9, t9, rs);
2215   dmtc1(t9, fd);
2216   cvt_s_l(fd, fd);
2217   Branch(USE_DELAY_SLOT, &conversion_done);
2218   add_s(fd, fd, fd);  // In delay slot.
2219 
2220   bind(&positive);
2221   // Rs < 2^31, we can do simple conversion.
2222   dmtc1(rs, fd);
2223   cvt_s_l(fd, fd);
2224 
2225   bind(&conversion_done);
2226 }
2227 
2228 void MacroAssembler::Round_l_d(FPURegister fd, FPURegister fs) {
2229   round_l_d(fd, fs);
2230 }
2231 
2232 void MacroAssembler::Floor_l_d(FPURegister fd, FPURegister fs) {
2233   floor_l_d(fd, fs);
2234 }
2235 
2236 void MacroAssembler::Ceil_l_d(FPURegister fd, FPURegister fs) {
2237   ceil_l_d(fd, fs);
2238 }
2239 
2240 void MacroAssembler::Trunc_l_d(FPURegister fd, FPURegister fs) {
2241   trunc_l_d(fd, fs);
2242 }
2243 
2244 void MacroAssembler::Trunc_l_ud(FPURegister fd, FPURegister fs,
2245                                 FPURegister scratch) {
2246   BlockTrampolinePoolScope block_trampoline_pool(this);
2247   // Load to GPR.
2248   dmfc1(t8, fs);
2249   // Reset sign bit.
2250   {
2251     UseScratchRegisterScope temps(this);
2252     Register scratch1 = temps.Acquire();
2253     li(scratch1, 0x7FFFFFFFFFFFFFFF);
2254     and_(t8, t8, scratch1);
2255   }
2256   dmtc1(t8, fs);
2257   trunc_l_d(fd, fs);
2258 }
2259 
2260 void TurboAssembler::Trunc_uw_d(FPURegister fd, FPURegister fs,
2261                                 FPURegister scratch) {
2262   BlockTrampolinePoolScope block_trampoline_pool(this);
2263   Trunc_uw_d(t8, fs, scratch);
2264   mtc1(t8, fd);
2265 }
2266 
2267 void TurboAssembler::Trunc_uw_s(FPURegister fd, FPURegister fs,
2268                                 FPURegister scratch) {
2269   BlockTrampolinePoolScope block_trampoline_pool(this);
2270   Trunc_uw_s(t8, fs, scratch);
2271   mtc1(t8, fd);
2272 }
2273 
2274 void TurboAssembler::Trunc_ul_d(FPURegister fd, FPURegister fs,
2275                                 FPURegister scratch, Register result) {
2276   BlockTrampolinePoolScope block_trampoline_pool(this);
2277   Trunc_ul_d(t8, fs, scratch, result);
2278   dmtc1(t8, fd);
2279 }
2280 
2281 void TurboAssembler::Trunc_ul_s(FPURegister fd, FPURegister fs,
2282                                 FPURegister scratch, Register result) {
2283   BlockTrampolinePoolScope block_trampoline_pool(this);
2284   Trunc_ul_s(t8, fs, scratch, result);
2285   dmtc1(t8, fd);
2286 }
2287 
2288 void MacroAssembler::Trunc_w_d(FPURegister fd, FPURegister fs) {
2289   trunc_w_d(fd, fs);
2290 }
2291 
2292 void MacroAssembler::Round_w_d(FPURegister fd, FPURegister fs) {
2293   round_w_d(fd, fs);
2294 }
2295 
2296 void MacroAssembler::Floor_w_d(FPURegister fd, FPURegister fs) {
2297   floor_w_d(fd, fs);
2298 }
2299 
2300 void MacroAssembler::Ceil_w_d(FPURegister fd, FPURegister fs) {
2301   ceil_w_d(fd, fs);
2302 }
2303 
2304 void TurboAssembler::Trunc_uw_d(Register rd, FPURegister fs,
2305                                 FPURegister scratch) {
2306   DCHECK(fs != scratch);
2307   DCHECK(rd != at);
2308 
2309   {
2310     // Load 2^31 into scratch as its float representation.
2311     UseScratchRegisterScope temps(this);
2312     Register scratch1 = temps.Acquire();
2313     li(scratch1, 0x41E00000);
2314     mtc1(zero_reg, scratch);
2315     mthc1(scratch1, scratch);
2316   }
2317   // Test if scratch > fd.
2318   // If fd < 2^31 we can convert it normally.
2319   Label simple_convert;
2320   CompareF64(OLT, fs, scratch);
2321   BranchTrueShortF(&simple_convert);
2322 
2323   // First we subtract 2^31 from fd, then trunc it to rs
2324   // and add 2^31 to rs.
2325   sub_d(scratch, fs, scratch);
2326   trunc_w_d(scratch, scratch);
2327   mfc1(rd, scratch);
2328   Or(rd, rd, 1 << 31);
2329 
2330   Label done;
2331   Branch(&done);
2332   // Simple conversion.
2333   bind(&simple_convert);
2334   trunc_w_d(scratch, fs);
2335   mfc1(rd, scratch);
2336 
2337   bind(&done);
2338 }
2339 
2340 void TurboAssembler::Trunc_uw_s(Register rd, FPURegister fs,
2341                                 FPURegister scratch) {
2342   DCHECK(fs != scratch);
2343   DCHECK(rd != at);
2344 
2345   {
2346     // Load 2^31 into scratch as its float representation.
2347     UseScratchRegisterScope temps(this);
2348     Register scratch1 = temps.Acquire();
2349     li(scratch1, 0x4F000000);
2350     mtc1(scratch1, scratch);
2351   }
2352   // Test if scratch > fs.
2353   // If fs < 2^31 we can convert it normally.
2354   Label simple_convert;
2355   CompareF32(OLT, fs, scratch);
2356   BranchTrueShortF(&simple_convert);
2357 
2358   // First we subtract 2^31 from fs, then trunc it to rd
2359   // and add 2^31 to rd.
2360   sub_s(scratch, fs, scratch);
2361   trunc_w_s(scratch, scratch);
2362   mfc1(rd, scratch);
2363   Or(rd, rd, 1 << 31);
2364 
2365   Label done;
2366   Branch(&done);
2367   // Simple conversion.
2368   bind(&simple_convert);
2369   trunc_w_s(scratch, fs);
2370   mfc1(rd, scratch);
2371 
2372   bind(&done);
2373 }
2374 
2375 void TurboAssembler::Trunc_ul_d(Register rd, FPURegister fs,
2376                                 FPURegister scratch, Register result) {
2377   DCHECK(fs != scratch);
2378   DCHECK(result.is_valid() ? !AreAliased(rd, result, at) : !AreAliased(rd, at));
2379 
2380   Label simple_convert, done, fail;
2381   if (result.is_valid()) {
2382     mov(result, zero_reg);
2383     Move(scratch, -1.0);
2384     // If fd =< -1 or unordered, then the conversion fails.
2385     CompareF64(OLE, fs, scratch);
2386     BranchTrueShortF(&fail);
2387     CompareIsNanF64(fs, scratch);
2388     BranchTrueShortF(&fail);
2389   }
2390 
2391   // Load 2^63 into scratch as its double representation.
2392   li(at, 0x43E0000000000000);
2393   dmtc1(at, scratch);
2394 
2395   // Test if scratch > fs.
2396   // If fs < 2^63 we can convert it normally.
2397   CompareF64(OLT, fs, scratch);
2398   BranchTrueShortF(&simple_convert);
2399 
2400   // First we subtract 2^63 from fs, then trunc it to rd
2401   // and add 2^63 to rd.
2402   sub_d(scratch, fs, scratch);
2403   trunc_l_d(scratch, scratch);
2404   dmfc1(rd, scratch);
2405   Or(rd, rd, Operand(1UL << 63));
2406   Branch(&done);
2407 
2408   // Simple conversion.
2409   bind(&simple_convert);
2410   trunc_l_d(scratch, fs);
2411   dmfc1(rd, scratch);
2412 
2413   bind(&done);
2414   if (result.is_valid()) {
2415     // Conversion is failed if the result is negative.
2416     {
2417       UseScratchRegisterScope temps(this);
2418       Register scratch1 = temps.Acquire();
2419       addiu(scratch1, zero_reg, -1);
2420       dsrl(scratch1, scratch1, 1);  // Load 2^62.
2421       dmfc1(result, scratch);
2422       xor_(result, result, scratch1);
2423     }
2424     Slt(result, zero_reg, result);
2425   }
2426 
2427   bind(&fail);
2428 }
2429 
2430 void TurboAssembler::Trunc_ul_s(Register rd, FPURegister fs,
2431                                 FPURegister scratch, Register result) {
2432   DCHECK(fs != scratch);
2433   DCHECK(result.is_valid() ? !AreAliased(rd, result, at) : !AreAliased(rd, at));
2434 
2435   Label simple_convert, done, fail;
2436   if (result.is_valid()) {
2437     mov(result, zero_reg);
2438     Move(scratch, -1.0f);
2439     // If fd =< -1 or unordered, then the conversion fails.
2440     CompareF32(OLE, fs, scratch);
2441     BranchTrueShortF(&fail);
2442     CompareIsNanF32(fs, scratch);
2443     BranchTrueShortF(&fail);
2444   }
2445 
2446   {
2447     // Load 2^63 into scratch as its float representation.
2448     UseScratchRegisterScope temps(this);
2449     Register scratch1 = temps.Acquire();
2450     li(scratch1, 0x5F000000);
2451     mtc1(scratch1, scratch);
2452   }
2453 
2454   // Test if scratch > fs.
2455   // If fs < 2^63 we can convert it normally.
2456   CompareF32(OLT, fs, scratch);
2457   BranchTrueShortF(&simple_convert);
2458 
2459   // First we subtract 2^63 from fs, then trunc it to rd
2460   // and add 2^63 to rd.
2461   sub_s(scratch, fs, scratch);
2462   trunc_l_s(scratch, scratch);
2463   dmfc1(rd, scratch);
2464   Or(rd, rd, Operand(1UL << 63));
2465   Branch(&done);
2466 
2467   // Simple conversion.
2468   bind(&simple_convert);
2469   trunc_l_s(scratch, fs);
2470   dmfc1(rd, scratch);
2471 
2472   bind(&done);
2473   if (result.is_valid()) {
2474     // Conversion is failed if the result is negative or unordered.
2475     {
2476       UseScratchRegisterScope temps(this);
2477       Register scratch1 = temps.Acquire();
2478       addiu(scratch1, zero_reg, -1);
2479       dsrl(scratch1, scratch1, 1);  // Load 2^62.
2480       dmfc1(result, scratch);
2481       xor_(result, result, scratch1);
2482     }
2483     Slt(result, zero_reg, result);
2484   }
2485 
2486   bind(&fail);
2487 }
2488 
2489 template <typename RoundFunc>
2490 void TurboAssembler::RoundDouble(FPURegister dst, FPURegister src,
2491                                  FPURoundingMode mode, RoundFunc round) {
2492   BlockTrampolinePoolScope block_trampoline_pool(this);
2493   Register scratch = t8;
2494   if (kArchVariant == kMips64r6) {
2495     cfc1(scratch, FCSR);
2496     li(at, Operand(mode));
2497     ctc1(at, FCSR);
2498     rint_d(dst, src);
2499     ctc1(scratch, FCSR);
2500   } else {
2501     Label done;
2502     if (!IsDoubleZeroRegSet()) {
2503       Move(kDoubleRegZero, 0.0);
2504     }
2505     mfhc1(scratch, src);
2506     Ext(at, scratch, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
2507     Branch(USE_DELAY_SLOT, &done, hs, at,
2508            Operand(HeapNumber::kExponentBias + HeapNumber::kMantissaBits));
2509     // Canonicalize the result.
2510     sub_d(dst, src, kDoubleRegZero);
2511     round(this, dst, src);
2512     dmfc1(at, dst);
2513     Branch(USE_DELAY_SLOT, &done, ne, at, Operand(zero_reg));
2514     cvt_d_l(dst, dst);
2515     srl(at, scratch, 31);
2516     sll(at, at, 31);
2517     mthc1(at, dst);
2518     bind(&done);
2519   }
2520 }
2521 
2522 void TurboAssembler::Floor_d_d(FPURegister dst, FPURegister src) {
2523   RoundDouble(dst, src, mode_floor,
2524               [](TurboAssembler* tasm, FPURegister dst, FPURegister src) {
2525                 tasm->floor_l_d(dst, src);
2526               });
2527 }
2528 
2529 void TurboAssembler::Ceil_d_d(FPURegister dst, FPURegister src) {
2530   RoundDouble(dst, src, mode_ceil,
2531               [](TurboAssembler* tasm, FPURegister dst, FPURegister src) {
2532                 tasm->ceil_l_d(dst, src);
2533               });
2534 }
2535 
2536 void TurboAssembler::Trunc_d_d(FPURegister dst, FPURegister src) {
2537   RoundDouble(dst, src, mode_trunc,
2538               [](TurboAssembler* tasm, FPURegister dst, FPURegister src) {
2539                 tasm->trunc_l_d(dst, src);
2540               });
2541 }
2542 
2543 void TurboAssembler::Round_d_d(FPURegister dst, FPURegister src) {
2544   RoundDouble(dst, src, mode_round,
2545               [](TurboAssembler* tasm, FPURegister dst, FPURegister src) {
2546                 tasm->round_l_d(dst, src);
2547               });
2548 }
2549 
2550 template <typename RoundFunc>
2551 void TurboAssembler::RoundFloat(FPURegister dst, FPURegister src,
2552                                 FPURoundingMode mode, RoundFunc round) {
2553   BlockTrampolinePoolScope block_trampoline_pool(this);
2554   Register scratch = t8;
2555   if (kArchVariant == kMips64r6) {
2556     cfc1(scratch, FCSR);
2557     li(at, Operand(mode));
2558     ctc1(at, FCSR);
2559     rint_s(dst, src);
2560     ctc1(scratch, FCSR);
2561   } else {
2562     int32_t kFloat32ExponentBias = 127;
2563     int32_t kFloat32MantissaBits = 23;
2564     int32_t kFloat32ExponentBits = 8;
2565     Label done;
2566     if (!IsDoubleZeroRegSet()) {
2567       Move(kDoubleRegZero, 0.0);
2568     }
2569     mfc1(scratch, src);
2570     Ext(at, scratch, kFloat32MantissaBits, kFloat32ExponentBits);
2571     Branch(USE_DELAY_SLOT, &done, hs, at,
2572            Operand(kFloat32ExponentBias + kFloat32MantissaBits));
2573     // Canonicalize the result.
2574     sub_s(dst, src, kDoubleRegZero);
2575     round(this, dst, src);
2576     mfc1(at, dst);
2577     Branch(USE_DELAY_SLOT, &done, ne, at, Operand(zero_reg));
2578     cvt_s_w(dst, dst);
2579     srl(at, scratch, 31);
2580     sll(at, at, 31);
2581     mtc1(at, dst);
2582     bind(&done);
2583   }
2584 }
2585 
2586 void TurboAssembler::Floor_s_s(FPURegister dst, FPURegister src) {
2587   RoundFloat(dst, src, mode_floor,
2588              [](TurboAssembler* tasm, FPURegister dst, FPURegister src) {
2589                tasm->floor_w_s(dst, src);
2590              });
2591 }
2592 
2593 void TurboAssembler::Ceil_s_s(FPURegister dst, FPURegister src) {
2594   RoundFloat(dst, src, mode_ceil,
2595              [](TurboAssembler* tasm, FPURegister dst, FPURegister src) {
2596                tasm->ceil_w_s(dst, src);
2597              });
2598 }
2599 
2600 void TurboAssembler::Trunc_s_s(FPURegister dst, FPURegister src) {
2601   RoundFloat(dst, src, mode_trunc,
2602              [](TurboAssembler* tasm, FPURegister dst, FPURegister src) {
2603                tasm->trunc_w_s(dst, src);
2604              });
2605 }
2606 
2607 void TurboAssembler::Round_s_s(FPURegister dst, FPURegister src) {
2608   RoundFloat(dst, src, mode_round,
2609              [](TurboAssembler* tasm, FPURegister dst, FPURegister src) {
2610                tasm->round_w_s(dst, src);
2611              });
2612 }
2613 
2614 void TurboAssembler::LoadLane(MSASize sz, MSARegister dst, uint8_t laneidx,
2615                               MemOperand src) {
2616   UseScratchRegisterScope temps(this);
2617   Register scratch = temps.Acquire();
2618   switch (sz) {
2619     case MSA_B:
2620       Lbu(scratch, src);
2621       insert_b(dst, laneidx, scratch);
2622       break;
2623     case MSA_H:
2624       Lhu(scratch, src);
2625       insert_h(dst, laneidx, scratch);
2626       break;
2627     case MSA_W:
2628       Lwu(scratch, src);
2629       insert_w(dst, laneidx, scratch);
2630       break;
2631     case MSA_D:
2632       Ld(scratch, src);
2633       insert_d(dst, laneidx, scratch);
2634       break;
2635     default:
2636       UNREACHABLE();
2637   }
2638 }
2639 
2640 void TurboAssembler::StoreLane(MSASize sz, MSARegister src, uint8_t laneidx,
2641                                MemOperand dst) {
2642   UseScratchRegisterScope temps(this);
2643   Register scratch = temps.Acquire();
2644   switch (sz) {
2645     case MSA_B:
2646       copy_u_b(scratch, src, laneidx);
2647       Sb(scratch, dst);
2648       break;
2649     case MSA_H:
2650       copy_u_h(scratch, src, laneidx);
2651       Sh(scratch, dst);
2652       break;
2653     case MSA_W:
2654       if (laneidx == 0) {
2655         FPURegister src_reg = FPURegister::from_code(src.code());
2656         Swc1(src_reg, dst);
2657       } else {
2658         copy_u_w(scratch, src, laneidx);
2659         Sw(scratch, dst);
2660       }
2661       break;
2662     case MSA_D:
2663       if (laneidx == 0) {
2664         FPURegister src_reg = FPURegister::from_code(src.code());
2665         Sdc1(src_reg, dst);
2666       } else {
2667         copy_s_d(scratch, src, laneidx);
2668         Sd(scratch, dst);
2669       }
2670       break;
2671     default:
2672       UNREACHABLE();
2673   }
2674 }
2675 
2676 #define EXT_MUL_BINOP(type, ilv_instr, dotp_instr)            \
2677   case type:                                                  \
2678     xor_v(kSimd128RegZero, kSimd128RegZero, kSimd128RegZero); \
2679     ilv_instr(kSimd128ScratchReg, kSimd128RegZero, src1);     \
2680     ilv_instr(kSimd128RegZero, kSimd128RegZero, src2);        \
2681     dotp_instr(dst, kSimd128ScratchReg, kSimd128RegZero);     \
2682     break;
2683 
2684 void TurboAssembler::ExtMulLow(MSADataType type, MSARegister dst,
2685                                MSARegister src1, MSARegister src2) {
2686   switch (type) {
2687     EXT_MUL_BINOP(MSAS8, ilvr_b, dotp_s_h)
2688     EXT_MUL_BINOP(MSAS16, ilvr_h, dotp_s_w)
2689     EXT_MUL_BINOP(MSAS32, ilvr_w, dotp_s_d)
2690     EXT_MUL_BINOP(MSAU8, ilvr_b, dotp_u_h)
2691     EXT_MUL_BINOP(MSAU16, ilvr_h, dotp_u_w)
2692     EXT_MUL_BINOP(MSAU32, ilvr_w, dotp_u_d)
2693     default:
2694       UNREACHABLE();
2695   }
2696 }
2697 
2698 void TurboAssembler::ExtMulHigh(MSADataType type, MSARegister dst,
2699                                 MSARegister src1, MSARegister src2) {
2700   switch (type) {
2701     EXT_MUL_BINOP(MSAS8, ilvl_b, dotp_s_h)
2702     EXT_MUL_BINOP(MSAS16, ilvl_h, dotp_s_w)
2703     EXT_MUL_BINOP(MSAS32, ilvl_w, dotp_s_d)
2704     EXT_MUL_BINOP(MSAU8, ilvl_b, dotp_u_h)
2705     EXT_MUL_BINOP(MSAU16, ilvl_h, dotp_u_w)
2706     EXT_MUL_BINOP(MSAU32, ilvl_w, dotp_u_d)
2707     default:
2708       UNREACHABLE();
2709   }
2710 }
2711 #undef EXT_MUL_BINOP
2712 
2713 void TurboAssembler::LoadSplat(MSASize sz, MSARegister dst, MemOperand src) {
2714   UseScratchRegisterScope temps(this);
2715   Register scratch = temps.Acquire();
2716   switch (sz) {
2717     case MSA_B:
2718       Lb(scratch, src);
2719       fill_b(dst, scratch);
2720       break;
2721     case MSA_H:
2722       Lh(scratch, src);
2723       fill_h(dst, scratch);
2724       break;
2725     case MSA_W:
2726       Lw(scratch, src);
2727       fill_w(dst, scratch);
2728       break;
2729     case MSA_D:
2730       Ld(scratch, src);
2731       fill_d(dst, scratch);
2732       break;
2733     default:
2734       UNREACHABLE();
2735   }
2736 }
2737 
2738 void TurboAssembler::ExtAddPairwise(MSADataType type, MSARegister dst,
2739                                     MSARegister src) {
2740   switch (type) {
2741     case MSAS8:
2742       hadd_s_h(dst, src, src);
2743       break;
2744     case MSAU8:
2745       hadd_u_h(dst, src, src);
2746       break;
2747     case MSAS16:
2748       hadd_s_w(dst, src, src);
2749       break;
2750     case MSAU16:
2751       hadd_u_w(dst, src, src);
2752       break;
2753     default:
2754       UNREACHABLE();
2755   }
2756 }
2757 
2758 void TurboAssembler::MSARoundW(MSARegister dst, MSARegister src,
2759                                FPURoundingMode mode) {
2760   BlockTrampolinePoolScope block_trampoline_pool(this);
2761   Register scratch = t8;
2762   Register scratch2 = at;
2763   cfcmsa(scratch, MSACSR);
2764   if (mode == kRoundToNearest) {
2765     scratch2 = zero_reg;
2766   } else {
2767     li(scratch2, Operand(mode));
2768   }
2769   ctcmsa(MSACSR, scratch2);
2770   frint_w(dst, src);
2771   ctcmsa(MSACSR, scratch);
2772 }
2773 
2774 void TurboAssembler::MSARoundD(MSARegister dst, MSARegister src,
2775                                FPURoundingMode mode) {
2776   BlockTrampolinePoolScope block_trampoline_pool(this);
2777   Register scratch = t8;
2778   Register scratch2 = at;
2779   cfcmsa(scratch, MSACSR);
2780   if (mode == kRoundToNearest) {
2781     scratch2 = zero_reg;
2782   } else {
2783     li(scratch2, Operand(mode));
2784   }
2785   ctcmsa(MSACSR, scratch2);
2786   frint_d(dst, src);
2787   ctcmsa(MSACSR, scratch);
2788 }
2789 
2790 void MacroAssembler::Madd_s(FPURegister fd, FPURegister fr, FPURegister fs,
2791                             FPURegister ft, FPURegister scratch) {
2792   DCHECK(fr != scratch && fs != scratch && ft != scratch);
2793   mul_s(scratch, fs, ft);
2794   add_s(fd, fr, scratch);
2795 }
2796 
2797 void MacroAssembler::Madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
2798                             FPURegister ft, FPURegister scratch) {
2799   DCHECK(fr != scratch && fs != scratch && ft != scratch);
2800   mul_d(scratch, fs, ft);
2801   add_d(fd, fr, scratch);
2802 }
2803 
2804 void MacroAssembler::Msub_s(FPURegister fd, FPURegister fr, FPURegister fs,
2805                             FPURegister ft, FPURegister scratch) {
2806   DCHECK(fr != scratch && fs != scratch && ft != scratch);
2807   mul_s(scratch, fs, ft);
2808   sub_s(fd, scratch, fr);
2809 }
2810 
2811 void MacroAssembler::Msub_d(FPURegister fd, FPURegister fr, FPURegister fs,
2812                             FPURegister ft, FPURegister scratch) {
2813   DCHECK(fr != scratch && fs != scratch && ft != scratch);
2814   mul_d(scratch, fs, ft);
2815   sub_d(fd, scratch, fr);
2816 }
2817 
2818 void TurboAssembler::CompareF(SecondaryField sizeField, FPUCondition cc,
2819                               FPURegister cmp1, FPURegister cmp2) {
2820   if (kArchVariant == kMips64r6) {
2821     sizeField = sizeField == D ? L : W;
2822     DCHECK(cmp1 != kDoubleCompareReg && cmp2 != kDoubleCompareReg);
2823     cmp(cc, sizeField, kDoubleCompareReg, cmp1, cmp2);
2824   } else {
2825     c(cc, sizeField, cmp1, cmp2);
2826   }
2827 }
2828 
2829 void TurboAssembler::CompareIsNanF(SecondaryField sizeField, FPURegister cmp1,
2830                                    FPURegister cmp2) {
2831   CompareF(sizeField, UN, cmp1, cmp2);
2832 }
2833 
2834 void TurboAssembler::BranchTrueShortF(Label* target, BranchDelaySlot bd) {
2835   if (kArchVariant == kMips64r6) {
2836     bc1nez(target, kDoubleCompareReg);
2837   } else {
2838     bc1t(target);
2839   }
2840   if (bd == PROTECT) {
2841     nop();
2842   }
2843 }
2844 
2845 void TurboAssembler::BranchFalseShortF(Label* target, BranchDelaySlot bd) {
2846   if (kArchVariant == kMips64r6) {
2847     bc1eqz(target, kDoubleCompareReg);
2848   } else {
2849     bc1f(target);
2850   }
2851   if (bd == PROTECT) {
2852     nop();
2853   }
2854 }
2855 
2856 void TurboAssembler::BranchTrueF(Label* target, BranchDelaySlot bd) {
2857   bool long_branch =
2858       target->is_bound() ? !is_near(target) : is_trampoline_emitted();
2859   if (long_branch) {
2860     Label skip;
2861     BranchFalseShortF(&skip);
2862     BranchLong(target, bd);
2863     bind(&skip);
2864   } else {
2865     BranchTrueShortF(target, bd);
2866   }
2867 }
2868 
2869 void TurboAssembler::BranchFalseF(Label* target, BranchDelaySlot bd) {
2870   bool long_branch =
2871       target->is_bound() ? !is_near(target) : is_trampoline_emitted();
2872   if (long_branch) {
2873     Label skip;
2874     BranchTrueShortF(&skip);
2875     BranchLong(target, bd);
2876     bind(&skip);
2877   } else {
2878     BranchFalseShortF(target, bd);
2879   }
2880 }
2881 
2882 void TurboAssembler::BranchMSA(Label* target, MSABranchDF df,
2883                                MSABranchCondition cond, MSARegister wt,
2884                                BranchDelaySlot bd) {
2885   {
2886     BlockTrampolinePoolScope block_trampoline_pool(this);
2887 
2888     if (target) {
2889       bool long_branch =
2890           target->is_bound() ? !is_near(target) : is_trampoline_emitted();
2891       if (long_branch) {
2892         Label skip;
2893         MSABranchCondition neg_cond = NegateMSABranchCondition(cond);
2894         BranchShortMSA(df, &skip, neg_cond, wt, bd);
2895         BranchLong(target, bd);
2896         bind(&skip);
2897       } else {
2898         BranchShortMSA(df, target, cond, wt, bd);
2899       }
2900     }
2901   }
2902 }
2903 
2904 void TurboAssembler::BranchShortMSA(MSABranchDF df, Label* target,
2905                                     MSABranchCondition cond, MSARegister wt,
2906                                     BranchDelaySlot bd) {
2907   if (IsEnabled(MIPS_SIMD)) {
2908     BlockTrampolinePoolScope block_trampoline_pool(this);
2909     if (target) {
2910       switch (cond) {
2911         case all_not_zero:
2912           switch (df) {
2913             case MSA_BRANCH_D:
2914               bnz_d(wt, target);
2915               break;
2916             case MSA_BRANCH_W:
2917               bnz_w(wt, target);
2918               break;
2919             case MSA_BRANCH_H:
2920               bnz_h(wt, target);
2921               break;
2922             case MSA_BRANCH_B:
2923             default:
2924               bnz_b(wt, target);
2925           }
2926           break;
2927         case one_elem_not_zero:
2928           bnz_v(wt, target);
2929           break;
2930         case one_elem_zero:
2931           switch (df) {
2932             case MSA_BRANCH_D:
2933               bz_d(wt, target);
2934               break;
2935             case MSA_BRANCH_W:
2936               bz_w(wt, target);
2937               break;
2938             case MSA_BRANCH_H:
2939               bz_h(wt, target);
2940               break;
2941             case MSA_BRANCH_B:
2942             default:
2943               bz_b(wt, target);
2944           }
2945           break;
2946         case all_zero:
2947           bz_v(wt, target);
2948           break;
2949         default:
2950           UNREACHABLE();
2951       }
2952     }
2953   } else {
2954     UNREACHABLE();
2955   }
2956   if (bd == PROTECT) {
2957     nop();
2958   }
2959 }
2960 
2961 void TurboAssembler::FmoveLow(FPURegister dst, Register src_low) {
2962   UseScratchRegisterScope temps(this);
2963   Register scratch = temps.Acquire();
2964   DCHECK(src_low != scratch);
2965   mfhc1(scratch, dst);
2966   mtc1(src_low, dst);
2967   mthc1(scratch, dst);
2968 }
2969 
2970 void TurboAssembler::Move(FPURegister dst, uint32_t src) {
2971   UseScratchRegisterScope temps(this);
2972   Register scratch = temps.Acquire();
2973   li(scratch, Operand(static_cast<int32_t>(src)));
2974   mtc1(scratch, dst);
2975 }
2976 
2977 void TurboAssembler::Move(FPURegister dst, uint64_t src) {
2978   // Handle special values first.
2979   if (src == bit_cast<uint64_t>(0.0) && has_double_zero_reg_set_) {
2980     mov_d(dst, kDoubleRegZero);
2981   } else if (src == bit_cast<uint64_t>(-0.0) && has_double_zero_reg_set_) {
2982     Neg_d(dst, kDoubleRegZero);
2983   } else {
2984     uint32_t lo = src & 0xFFFFFFFF;
2985     uint32_t hi = src >> 32;
2986     // Move the low part of the double into the lower of the corresponding FPU
2987     // register of FPU register pair.
2988     if (lo != 0) {
2989       UseScratchRegisterScope temps(this);
2990       Register scratch = temps.Acquire();
2991       li(scratch, Operand(lo));
2992       mtc1(scratch, dst);
2993     } else {
2994       mtc1(zero_reg, dst);
2995     }
2996     // Move the high part of the double into the higher of the corresponding FPU
2997     // register of FPU register pair.
2998     if (hi != 0) {
2999       UseScratchRegisterScope temps(this);
3000       Register scratch = temps.Acquire();
3001       li(scratch, Operand(hi));
3002       mthc1(scratch, dst);
3003     } else {
3004       mthc1(zero_reg, dst);
3005     }
3006     if (dst == kDoubleRegZero) has_double_zero_reg_set_ = true;
3007   }
3008 }
3009 
3010 void TurboAssembler::Movz(Register rd, Register rs, Register rt) {
3011   if (kArchVariant == kMips64r6) {
3012     Label done;
3013     Branch(&done, ne, rt, Operand(zero_reg));
3014     mov(rd, rs);
3015     bind(&done);
3016   } else {
3017     movz(rd, rs, rt);
3018   }
3019 }
3020 
3021 void TurboAssembler::Movn(Register rd, Register rs, Register rt) {
3022   if (kArchVariant == kMips64r6) {
3023     Label done;
3024     Branch(&done, eq, rt, Operand(zero_reg));
3025     mov(rd, rs);
3026     bind(&done);
3027   } else {
3028     movn(rd, rs, rt);
3029   }
3030 }
3031 
3032 void TurboAssembler::LoadZeroOnCondition(Register rd, Register rs,
3033                                          const Operand& rt, Condition cond) {
3034   BlockTrampolinePoolScope block_trampoline_pool(this);
3035   switch (cond) {
3036     case cc_always:
3037       mov(rd, zero_reg);
3038       break;
3039     case eq:
3040       if (rs == zero_reg) {
3041         if (rt.is_reg()) {
3042           LoadZeroIfConditionZero(rd, rt.rm());
3043         } else {
3044           if (rt.immediate() == 0) {
3045             mov(rd, zero_reg);
3046           } else {
3047             nop();
3048           }
3049         }
3050       } else if (IsZero(rt)) {
3051         LoadZeroIfConditionZero(rd, rs);
3052       } else {
3053         Dsubu(t9, rs, rt);
3054         LoadZeroIfConditionZero(rd, t9);
3055       }
3056       break;
3057     case ne:
3058       if (rs == zero_reg) {
3059         if (rt.is_reg()) {
3060           LoadZeroIfConditionNotZero(rd, rt.rm());
3061         } else {
3062           if (rt.immediate() != 0) {
3063             mov(rd, zero_reg);
3064           } else {
3065             nop();
3066           }
3067         }
3068       } else if (IsZero(rt)) {
3069         LoadZeroIfConditionNotZero(rd, rs);
3070       } else {
3071         Dsubu(t9, rs, rt);
3072         LoadZeroIfConditionNotZero(rd, t9);
3073       }
3074       break;
3075 
3076     // Signed comparison.
3077     case greater:
3078       Sgt(t9, rs, rt);
3079       LoadZeroIfConditionNotZero(rd, t9);
3080       break;
3081     case greater_equal:
3082       Sge(t9, rs, rt);
3083       LoadZeroIfConditionNotZero(rd, t9);
3084       // rs >= rt
3085       break;
3086     case less:
3087       Slt(t9, rs, rt);
3088       LoadZeroIfConditionNotZero(rd, t9);
3089       // rs < rt
3090       break;
3091     case less_equal:
3092       Sle(t9, rs, rt);
3093       LoadZeroIfConditionNotZero(rd, t9);
3094       // rs <= rt
3095       break;
3096 
3097     // Unsigned comparison.
3098     case Ugreater:
3099       Sgtu(t9, rs, rt);
3100       LoadZeroIfConditionNotZero(rd, t9);
3101       // rs > rt
3102       break;
3103 
3104     case Ugreater_equal:
3105       Sgeu(t9, rs, rt);
3106       LoadZeroIfConditionNotZero(rd, t9);
3107       // rs >= rt
3108       break;
3109     case Uless:
3110       Sltu(t9, rs, rt);
3111       LoadZeroIfConditionNotZero(rd, t9);
3112       // rs < rt
3113       break;
3114     case Uless_equal:
3115       Sleu(t9, rs, rt);
3116       LoadZeroIfConditionNotZero(rd, t9);
3117       // rs <= rt
3118       break;
3119     default:
3120       UNREACHABLE();
3121   }
3122 }
3123 
3124 void TurboAssembler::LoadZeroIfConditionNotZero(Register dest,
3125                                                 Register condition) {
3126   if (kArchVariant == kMips64r6) {
3127     seleqz(dest, dest, condition);
3128   } else {
3129     Movn(dest, zero_reg, condition);
3130   }
3131 }
3132 
3133 void TurboAssembler::LoadZeroIfConditionZero(Register dest,
3134                                              Register condition) {
3135   if (kArchVariant == kMips64r6) {
3136     selnez(dest, dest, condition);
3137   } else {
3138     Movz(dest, zero_reg, condition);
3139   }
3140 }
3141 
3142 void TurboAssembler::LoadZeroIfFPUCondition(Register dest) {
3143   if (kArchVariant == kMips64r6) {
3144     dmfc1(kScratchReg, kDoubleCompareReg);
3145     LoadZeroIfConditionNotZero(dest, kScratchReg);
3146   } else {
3147     Movt(dest, zero_reg);
3148   }
3149 }
3150 
3151 void TurboAssembler::LoadZeroIfNotFPUCondition(Register dest) {
3152   if (kArchVariant == kMips64r6) {
3153     dmfc1(kScratchReg, kDoubleCompareReg);
3154     LoadZeroIfConditionZero(dest, kScratchReg);
3155   } else {
3156     Movf(dest, zero_reg);
3157   }
3158 }
3159 
3160 void TurboAssembler::Movt(Register rd, Register rs, uint16_t cc) {
3161   movt(rd, rs, cc);
3162 }
3163 
3164 void TurboAssembler::Movf(Register rd, Register rs, uint16_t cc) {
3165   movf(rd, rs, cc);
3166 }
3167 
3168 void TurboAssembler::Clz(Register rd, Register rs) { clz(rd, rs); }
3169 
3170 void TurboAssembler::Dclz(Register rd, Register rs) { dclz(rd, rs); }
3171 
3172 void TurboAssembler::Ctz(Register rd, Register rs) {
3173   if (kArchVariant == kMips64r6) {
3174     // We don't have an instruction to count the number of trailing zeroes.
3175     // Start by flipping the bits end-for-end so we can count the number of
3176     // leading zeroes instead.
3177     rotr(rd, rs, 16);
3178     wsbh(rd, rd);
3179     bitswap(rd, rd);
3180     Clz(rd, rd);
3181   } else {
3182     // Convert trailing zeroes to trailing ones, and bits to their left
3183     // to zeroes.
3184     UseScratchRegisterScope temps(this);
3185     Register scratch = temps.Acquire();
3186     Daddu(scratch, rs, -1);
3187     Xor(rd, scratch, rs);
3188     And(rd, rd, scratch);
3189     // Count number of leading zeroes.
3190     Clz(rd, rd);
3191     // Subtract number of leading zeroes from 32 to get number of trailing
3192     // ones. Remember that the trailing ones were formerly trailing zeroes.
3193     li(scratch, 32);
3194     Subu(rd, scratch, rd);
3195   }
3196 }
3197 
3198 void TurboAssembler::Dctz(Register rd, Register rs) {
3199   if (kArchVariant == kMips64r6) {
3200     // We don't have an instruction to count the number of trailing zeroes.
3201     // Start by flipping the bits end-for-end so we can count the number of
3202     // leading zeroes instead.
3203     dsbh(rd, rs);
3204     dshd(rd, rd);
3205     dbitswap(rd, rd);
3206     dclz(rd, rd);
3207   } else {
3208     // Convert trailing zeroes to trailing ones, and bits to their left
3209     // to zeroes.
3210     UseScratchRegisterScope temps(this);
3211     Register scratch = temps.Acquire();
3212     Daddu(scratch, rs, -1);
3213     Xor(rd, scratch, rs);
3214     And(rd, rd, scratch);
3215     // Count number of leading zeroes.
3216     dclz(rd, rd);
3217     // Subtract number of leading zeroes from 64 to get number of trailing
3218     // ones. Remember that the trailing ones were formerly trailing zeroes.
3219     li(scratch, 64);
3220     Dsubu(rd, scratch, rd);
3221   }
3222 }
3223 
3224 void TurboAssembler::Popcnt(Register rd, Register rs) {
3225   ASM_CODE_COMMENT(this);
3226   // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
3227   //
3228   // A generalization of the best bit counting method to integers of
3229   // bit-widths up to 128 (parameterized by type T) is this:
3230   //
3231   // v = v - ((v >> 1) & (T)~(T)0/3);                           // temp
3232   // v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);      // temp
3233   // v = (v + (v >> 4)) & (T)~(T)0/255*15;                      // temp
3234   // c = (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * BITS_PER_BYTE; //count
3235   //
3236   // For comparison, for 32-bit quantities, this algorithm can be executed
3237   // using 20 MIPS instructions (the calls to LoadConst32() generate two
3238   // machine instructions each for the values being used in this algorithm).
3239   // A(n unrolled) loop-based algorithm requires 25 instructions.
3240   //
3241   // For a 64-bit operand this can be performed in 24 instructions compared
3242   // to a(n unrolled) loop based algorithm which requires 38 instructions.
3243   //
3244   // There are algorithms which are faster in the cases where very few
3245   // bits are set but the algorithm here attempts to minimize the total
3246   // number of instructions executed even when a large number of bits
3247   // are set.
3248   uint32_t B0 = 0x55555555;     // (T)~(T)0/3
3249   uint32_t B1 = 0x33333333;     // (T)~(T)0/15*3
3250   uint32_t B2 = 0x0F0F0F0F;     // (T)~(T)0/255*15
3251   uint32_t value = 0x01010101;  // (T)~(T)0/255
3252   uint32_t shift = 24;          // (sizeof(T) - 1) * BITS_PER_BYTE
3253 
3254   UseScratchRegisterScope temps(this);
3255   BlockTrampolinePoolScope block_trampoline_pool(this);
3256   Register scratch = temps.Acquire();
3257   Register scratch2 = t8;
3258   srl(scratch, rs, 1);
3259   li(scratch2, B0);
3260   And(scratch, scratch, scratch2);
3261   Subu(scratch, rs, scratch);
3262   li(scratch2, B1);
3263   And(rd, scratch, scratch2);
3264   srl(scratch, scratch, 2);
3265   And(scratch, scratch, scratch2);
3266   Addu(scratch, rd, scratch);
3267   srl(rd, scratch, 4);
3268   Addu(rd, rd, scratch);
3269   li(scratch2, B2);
3270   And(rd, rd, scratch2);
3271   li(scratch, value);
3272   Mul(rd, rd, scratch);
3273   srl(rd, rd, shift);
3274 }
3275 
3276 void TurboAssembler::Dpopcnt(Register rd, Register rs) {
3277   ASM_CODE_COMMENT(this);
3278   uint64_t B0 = 0x5555555555555555l;     // (T)~(T)0/3
3279   uint64_t B1 = 0x3333333333333333l;     // (T)~(T)0/15*3
3280   uint64_t B2 = 0x0F0F0F0F0F0F0F0Fl;     // (T)~(T)0/255*15
3281   uint64_t value = 0x0101010101010101l;  // (T)~(T)0/255
3282   uint64_t shift = 24;                   // (sizeof(T) - 1) * BITS_PER_BYTE
3283 
3284   UseScratchRegisterScope temps(this);
3285   BlockTrampolinePoolScope block_trampoline_pool(this);
3286   Register scratch = temps.Acquire();
3287   Register scratch2 = t8;
3288   dsrl(scratch, rs, 1);
3289   li(scratch2, B0);
3290   And(scratch, scratch, scratch2);
3291   Dsubu(scratch, rs, scratch);
3292   li(scratch2, B1);
3293   And(rd, scratch, scratch2);
3294   dsrl(scratch, scratch, 2);
3295   And(scratch, scratch, scratch2);
3296   Daddu(scratch, rd, scratch);
3297   dsrl(rd, scratch, 4);
3298   Daddu(rd, rd, scratch);
3299   li(scratch2, B2);
3300   And(rd, rd, scratch2);
3301   li(scratch, value);
3302   Dmul(rd, rd, scratch);
3303   dsrl32(rd, rd, shift);
3304 }
3305 
3306 void TurboAssembler::TryInlineTruncateDoubleToI(Register result,
3307                                                 DoubleRegister double_input,
3308                                                 Label* done) {
3309   DoubleRegister single_scratch = kScratchDoubleReg.low();
3310   BlockTrampolinePoolScope block_trampoline_pool(this);
3311   Register scratch = t9;
3312 
3313   // Try a conversion to a signed integer.
3314   trunc_w_d(single_scratch, double_input);
3315   mfc1(result, single_scratch);
3316   // Retrieve the FCSR.
3317   cfc1(scratch, FCSR);
3318   // Check for overflow and NaNs.
3319   And(scratch, scratch,
3320       kFCSROverflowCauseMask | kFCSRUnderflowCauseMask |
3321           kFCSRInvalidOpCauseMask);
3322   // If we had no exceptions we are done.
3323   Branch(done, eq, scratch, Operand(zero_reg));
3324 }
3325 
3326 void TurboAssembler::TruncateDoubleToI(Isolate* isolate, Zone* zone,
3327                                        Register result,
3328                                        DoubleRegister double_input,
3329                                        StubCallMode stub_mode) {
3330   Label done;
3331 
3332   TryInlineTruncateDoubleToI(result, double_input, &done);
3333 
3334   // If we fell through then inline version didn't succeed - call stub instead.
3335   push(ra);
3336   Dsubu(sp, sp, Operand(kDoubleSize));  // Put input on stack.
3337   Sdc1(double_input, MemOperand(sp, 0));
3338 
3339 #if V8_ENABLE_WEBASSEMBLY
3340   if (stub_mode == StubCallMode::kCallWasmRuntimeStub) {
3341     Call(wasm::WasmCode::kDoubleToI, RelocInfo::WASM_STUB_CALL);
3342 #else
3343   // For balance.
3344   if (false) {
3345 #endif  // V8_ENABLE_WEBASSEMBLY
3346   } else {
3347     Call(BUILTIN_CODE(isolate, DoubleToI), RelocInfo::CODE_TARGET);
3348   }
3349   Ld(result, MemOperand(sp, 0));
3350 
3351   Daddu(sp, sp, Operand(kDoubleSize));
3352   pop(ra);
3353 
3354   bind(&done);
3355 }
3356 
3357 // Emulated condtional branches do not emit a nop in the branch delay slot.
3358 //
3359 // BRANCH_ARGS_CHECK checks that conditional jump arguments are correct.
3360 #define BRANCH_ARGS_CHECK(cond, rs, rt)                                  \
3361   DCHECK((cond == cc_always && rs == zero_reg && rt.rm() == zero_reg) || \
3362          (cond != cc_always && (rs != zero_reg || rt.rm() != zero_reg)))
3363 
3364 void TurboAssembler::Branch(int32_t offset, BranchDelaySlot bdslot) {
3365   DCHECK_EQ(kArchVariant, kMips64r6 ? is_int26(offset) : is_int16(offset));
3366   BranchShort(offset, bdslot);
3367 }
3368 
3369 void TurboAssembler::Branch(int32_t offset, Condition cond, Register rs,
3370                             const Operand& rt, BranchDelaySlot bdslot) {
3371   bool is_near = BranchShortCheck(offset, nullptr, cond, rs, rt, bdslot);
3372   DCHECK(is_near);
3373   USE(is_near);
3374 }
3375 
3376 void TurboAssembler::Branch(Label* L, BranchDelaySlot bdslot) {
3377   if (L->is_bound()) {
3378     if (is_near_branch(L)) {
3379       BranchShort(L, bdslot);
3380     } else {
3381       BranchLong(L, bdslot);
3382     }
3383   } else {
3384     if (is_trampoline_emitted()) {
3385       BranchLong(L, bdslot);
3386     } else {
3387       BranchShort(L, bdslot);
3388     }
3389   }
3390 }
3391 
3392 void TurboAssembler::Branch(Label* L, Condition cond, Register rs,
3393                             const Operand& rt, BranchDelaySlot bdslot) {
3394   if (L->is_bound()) {
3395     if (!BranchShortCheck(0, L, cond, rs, rt, bdslot)) {
3396       if (cond != cc_always) {
3397         Label skip;
3398         Condition neg_cond = NegateCondition(cond);
3399         BranchShort(&skip, neg_cond, rs, rt);
3400         BranchLong(L, bdslot);
3401         bind(&skip);
3402       } else {
3403         BranchLong(L, bdslot);
3404       }
3405     }
3406   } else {
3407     if (is_trampoline_emitted()) {
3408       if (cond != cc_always) {
3409         Label skip;
3410         Condition neg_cond = NegateCondition(cond);
3411         BranchShort(&skip, neg_cond, rs, rt);
3412         BranchLong(L, bdslot);
3413         bind(&skip);
3414       } else {
3415         BranchLong(L, bdslot);
3416       }
3417     } else {
3418       BranchShort(L, cond, rs, rt, bdslot);
3419     }
3420   }
3421 }
3422 
3423 void TurboAssembler::Branch(Label* L, Condition cond, Register rs,
3424                             RootIndex index, BranchDelaySlot bdslot) {
3425   UseScratchRegisterScope temps(this);
3426   Register scratch = temps.Acquire();
3427   LoadRoot(scratch, index);
3428   Branch(L, cond, rs, Operand(scratch), bdslot);
3429 }
3430 
3431 void TurboAssembler::BranchShortHelper(int16_t offset, Label* L,
3432                                        BranchDelaySlot bdslot) {
3433   DCHECK(L == nullptr || offset == 0);
3434   offset = GetOffset(offset, L, OffsetSize::kOffset16);
3435   b(offset);
3436 
3437   // Emit a nop in the branch delay slot if required.
3438   if (bdslot == PROTECT) nop();
3439 }
3440 
3441 void TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L) {
3442   DCHECK(L == nullptr || offset == 0);
3443   offset = GetOffset(offset, L, OffsetSize::kOffset26);
3444   bc(offset);
3445 }
3446 
3447 void TurboAssembler::BranchShort(int32_t offset, BranchDelaySlot bdslot) {
3448   if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3449     DCHECK(is_int26(offset));
3450     BranchShortHelperR6(offset, nullptr);
3451   } else {
3452     DCHECK(is_int16(offset));
3453     BranchShortHelper(offset, nullptr, bdslot);
3454   }
3455 }
3456 
3457 void TurboAssembler::BranchShort(Label* L, BranchDelaySlot bdslot) {
3458   if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3459     BranchShortHelperR6(0, L);
3460   } else {
3461     BranchShortHelper(0, L, bdslot);
3462   }
3463 }
3464 
3465 int32_t TurboAssembler::GetOffset(int32_t offset, Label* L, OffsetSize bits) {
3466   if (L) {
3467     offset = branch_offset_helper(L, bits) >> 2;
3468   } else {
3469     DCHECK(is_intn(offset, bits));
3470   }
3471   return offset;
3472 }
3473 
3474 Register TurboAssembler::GetRtAsRegisterHelper(const Operand& rt,
3475                                                Register scratch) {
3476   Register r2 = no_reg;
3477   if (rt.is_reg()) {
3478     r2 = rt.rm();
3479   } else {
3480     r2 = scratch;
3481     li(r2, rt);
3482   }
3483 
3484   return r2;
3485 }
3486 
3487 bool TurboAssembler::CalculateOffset(Label* L, int32_t* offset,
3488                                      OffsetSize bits) {
3489   if (!is_near(L, bits)) return false;
3490   *offset = GetOffset(*offset, L, bits);
3491   return true;
3492 }
3493 
3494 bool TurboAssembler::CalculateOffset(Label* L, int32_t* offset, OffsetSize bits,
3495                                      Register* scratch, const Operand& rt) {
3496   if (!is_near(L, bits)) return false;
3497   *scratch = GetRtAsRegisterHelper(rt, *scratch);
3498   *offset = GetOffset(*offset, L, bits);
3499   return true;
3500 }
3501 
3502 bool TurboAssembler::BranchShortHelperR6(int32_t offset, Label* L,
3503                                          Condition cond, Register rs,
3504                                          const Operand& rt) {
3505   DCHECK(L == nullptr || offset == 0);
3506   UseScratchRegisterScope temps(this);
3507   BlockTrampolinePoolScope block_trampoline_pool(this);
3508   Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
3509 
3510   // Be careful to always use shifted_branch_offset only just before the
3511   // branch instruction, as the location will be remember for patching the
3512   // target.
3513   {
3514     BlockTrampolinePoolScope block_trampoline_pool(this);
3515     switch (cond) {
3516       case cc_always:
3517         if (!CalculateOffset(L, &offset, OffsetSize::kOffset26)) return false;
3518         bc(offset);
3519         break;
3520       case eq:
3521         if (rt.is_reg() && rs.code() == rt.rm().code()) {
3522           // Pre R6 beq is used here to make the code patchable. Otherwise bc
3523           // should be used which has no condition field so is not patchable.
3524           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3525             return false;
3526           beq(rs, scratch, offset);
3527           nop();
3528         } else if (IsZero(rt)) {
3529           if (!CalculateOffset(L, &offset, OffsetSize::kOffset21)) return false;
3530           beqzc(rs, offset);
3531         } else {
3532           // We don't want any other register but scratch clobbered.
3533           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3534             return false;
3535           beqc(rs, scratch, offset);
3536         }
3537         break;
3538       case ne:
3539         if (rt.is_reg() && rs.code() == rt.rm().code()) {
3540           // Pre R6 bne is used here to make the code patchable. Otherwise we
3541           // should not generate any instruction.
3542           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3543             return false;
3544           bne(rs, scratch, offset);
3545           nop();
3546         } else if (IsZero(rt)) {
3547           if (!CalculateOffset(L, &offset, OffsetSize::kOffset21)) return false;
3548           bnezc(rs, offset);
3549         } else {
3550           // We don't want any other register but scratch clobbered.
3551           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3552             return false;
3553           bnec(rs, scratch, offset);
3554         }
3555         break;
3556 
3557       // Signed comparison.
3558       case greater:
3559         // rs > rt
3560         if (rt.is_reg() && rs.code() == rt.rm().code()) {
3561           break;  // No code needs to be emitted.
3562         } else if (rs == zero_reg) {
3563           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3564             return false;
3565           bltzc(scratch, offset);
3566         } else if (IsZero(rt)) {
3567           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16)) return false;
3568           bgtzc(rs, offset);
3569         } else {
3570           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3571             return false;
3572           DCHECK(rs != scratch);
3573           bltc(scratch, rs, offset);
3574         }
3575         break;
3576       case greater_equal:
3577         // rs >= rt
3578         if (rt.is_reg() && rs.code() == rt.rm().code()) {
3579           if (!CalculateOffset(L, &offset, OffsetSize::kOffset26)) return false;
3580           bc(offset);
3581         } else if (rs == zero_reg) {
3582           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3583             return false;
3584           blezc(scratch, offset);
3585         } else if (IsZero(rt)) {
3586           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16)) return false;
3587           bgezc(rs, offset);
3588         } else {
3589           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3590             return false;
3591           DCHECK(rs != scratch);
3592           bgec(rs, scratch, offset);
3593         }
3594         break;
3595       case less:
3596         // rs < rt
3597         if (rt.is_reg() && rs.code() == rt.rm().code()) {
3598           break;  // No code needs to be emitted.
3599         } else if (rs == zero_reg) {
3600           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3601             return false;
3602           bgtzc(scratch, offset);
3603         } else if (IsZero(rt)) {
3604           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16)) return false;
3605           bltzc(rs, offset);
3606         } else {
3607           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3608             return false;
3609           DCHECK(rs != scratch);
3610           bltc(rs, scratch, offset);
3611         }
3612         break;
3613       case less_equal:
3614         // rs <= rt
3615         if (rt.is_reg() && rs.code() == rt.rm().code()) {
3616           if (!CalculateOffset(L, &offset, OffsetSize::kOffset26)) return false;
3617           bc(offset);
3618         } else if (rs == zero_reg) {
3619           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3620             return false;
3621           bgezc(scratch, offset);
3622         } else if (IsZero(rt)) {
3623           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16)) return false;
3624           blezc(rs, offset);
3625         } else {
3626           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3627             return false;
3628           DCHECK(rs != scratch);
3629           bgec(scratch, rs, offset);
3630         }
3631         break;
3632 
3633       // Unsigned comparison.
3634       case Ugreater:
3635         // rs > rt
3636         if (rt.is_reg() && rs.code() == rt.rm().code()) {
3637           break;  // No code needs to be emitted.
3638         } else if (rs == zero_reg) {
3639           if (!CalculateOffset(L, &offset, OffsetSize::kOffset21, &scratch, rt))
3640             return false;
3641           bnezc(scratch, offset);
3642         } else if (IsZero(rt)) {
3643           if (!CalculateOffset(L, &offset, OffsetSize::kOffset21)) return false;
3644           bnezc(rs, offset);
3645         } else {
3646           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3647             return false;
3648           DCHECK(rs != scratch);
3649           bltuc(scratch, rs, offset);
3650         }
3651         break;
3652       case Ugreater_equal:
3653         // rs >= rt
3654         if (rt.is_reg() && rs.code() == rt.rm().code()) {
3655           if (!CalculateOffset(L, &offset, OffsetSize::kOffset26)) return false;
3656           bc(offset);
3657         } else if (rs == zero_reg) {
3658           if (!CalculateOffset(L, &offset, OffsetSize::kOffset21, &scratch, rt))
3659             return false;
3660           beqzc(scratch, offset);
3661         } else if (IsZero(rt)) {
3662           if (!CalculateOffset(L, &offset, OffsetSize::kOffset26)) return false;
3663           bc(offset);
3664         } else {
3665           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3666             return false;
3667           DCHECK(rs != scratch);
3668           bgeuc(rs, scratch, offset);
3669         }
3670         break;
3671       case Uless:
3672         // rs < rt
3673         if (rt.is_reg() && rs.code() == rt.rm().code()) {
3674           break;  // No code needs to be emitted.
3675         } else if (rs == zero_reg) {
3676           if (!CalculateOffset(L, &offset, OffsetSize::kOffset21, &scratch, rt))
3677             return false;
3678           bnezc(scratch, offset);
3679         } else if (IsZero(rt)) {
3680           break;  // No code needs to be emitted.
3681         } else {
3682           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3683             return false;
3684           DCHECK(rs != scratch);
3685           bltuc(rs, scratch, offset);
3686         }
3687         break;
3688       case Uless_equal:
3689         // rs <= rt
3690         if (rt.is_reg() && rs.code() == rt.rm().code()) {
3691           if (!CalculateOffset(L, &offset, OffsetSize::kOffset26)) return false;
3692           bc(offset);
3693         } else if (rs == zero_reg) {
3694           if (!CalculateOffset(L, &offset, OffsetSize::kOffset26, &scratch, rt))
3695             return false;
3696           bc(offset);
3697         } else if (IsZero(rt)) {
3698           if (!CalculateOffset(L, &offset, OffsetSize::kOffset21)) return false;
3699           beqzc(rs, offset);
3700         } else {
3701           if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
3702             return false;
3703           DCHECK(rs != scratch);
3704           bgeuc(scratch, rs, offset);
3705         }
3706         break;
3707       default:
3708         UNREACHABLE();
3709     }
3710   }
3711   CheckTrampolinePoolQuick(1);
3712   return true;
3713 }
3714 
3715 bool TurboAssembler::BranchShortHelper(int16_t offset, Label* L, Condition cond,
3716                                        Register rs, const Operand& rt,
3717                                        BranchDelaySlot bdslot) {
3718   DCHECK(L == nullptr || offset == 0);
3719   if (!is_near(L, OffsetSize::kOffset16)) return false;
3720 
3721   UseScratchRegisterScope temps(this);
3722   BlockTrampolinePoolScope block_trampoline_pool(this);
3723   Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
3724   int32_t offset32;
3725 
3726   // Be careful to always use shifted_branch_offset only just before the
3727   // branch instruction, as the location will be remember for patching the
3728   // target.
3729   {
3730     BlockTrampolinePoolScope block_trampoline_pool(this);
3731     switch (cond) {
3732       case cc_always:
3733         offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3734         b(offset32);
3735         break;
3736       case eq:
3737         if (IsZero(rt)) {
3738           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3739           beq(rs, zero_reg, offset32);
3740         } else {
3741           // We don't want any other register but scratch clobbered.
3742           scratch = GetRtAsRegisterHelper(rt, scratch);
3743           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3744           beq(rs, scratch, offset32);
3745         }
3746         break;
3747       case ne:
3748         if (IsZero(rt)) {
3749           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3750           bne(rs, zero_reg, offset32);
3751         } else {
3752           // We don't want any other register but scratch clobbered.
3753           scratch = GetRtAsRegisterHelper(rt, scratch);
3754           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3755           bne(rs, scratch, offset32);
3756         }
3757         break;
3758 
3759       // Signed comparison.
3760       case greater:
3761         if (IsZero(rt)) {
3762           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3763           bgtz(rs, offset32);
3764         } else {
3765           Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3766           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3767           bne(scratch, zero_reg, offset32);
3768         }
3769         break;
3770       case greater_equal:
3771         if (IsZero(rt)) {
3772           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3773           bgez(rs, offset32);
3774         } else {
3775           Slt(scratch, rs, rt);
3776           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3777           beq(scratch, zero_reg, offset32);
3778         }
3779         break;
3780       case less:
3781         if (IsZero(rt)) {
3782           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3783           bltz(rs, offset32);
3784         } else {
3785           Slt(scratch, rs, rt);
3786           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3787           bne(scratch, zero_reg, offset32);
3788         }
3789         break;
3790       case less_equal:
3791         if (IsZero(rt)) {
3792           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3793           blez(rs, offset32);
3794         } else {
3795           Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3796           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3797           beq(scratch, zero_reg, offset32);
3798         }
3799         break;
3800 
3801       // Unsigned comparison.
3802       case Ugreater:
3803         if (IsZero(rt)) {
3804           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3805           bne(rs, zero_reg, offset32);
3806         } else {
3807           Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3808           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3809           bne(scratch, zero_reg, offset32);
3810         }
3811         break;
3812       case Ugreater_equal:
3813         if (IsZero(rt)) {
3814           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3815           b(offset32);
3816         } else {
3817           Sltu(scratch, rs, rt);
3818           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3819           beq(scratch, zero_reg, offset32);
3820         }
3821         break;
3822       case Uless:
3823         if (IsZero(rt)) {
3824           return true;  // No code needs to be emitted.
3825         } else {
3826           Sltu(scratch, rs, rt);
3827           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3828           bne(scratch, zero_reg, offset32);
3829         }
3830         break;
3831       case Uless_equal:
3832         if (IsZero(rt)) {
3833           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3834           beq(rs, zero_reg, offset32);
3835         } else {
3836           Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3837           offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3838           beq(scratch, zero_reg, offset32);
3839         }
3840         break;
3841       default:
3842         UNREACHABLE();
3843     }
3844   }
3845 
3846   // Emit a nop in the branch delay slot if required.
3847   if (bdslot == PROTECT) nop();
3848 
3849   return true;
3850 }
3851 
3852 bool TurboAssembler::BranchShortCheck(int32_t offset, Label* L, Condition cond,
3853                                       Register rs, const Operand& rt,
3854                                       BranchDelaySlot bdslot) {
3855   BRANCH_ARGS_CHECK(cond, rs, rt);
3856 
3857   if (!L) {
3858     if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3859       DCHECK(is_int26(offset));
3860       return BranchShortHelperR6(offset, nullptr, cond, rs, rt);
3861     } else {
3862       DCHECK(is_int16(offset));
3863       return BranchShortHelper(offset, nullptr, cond, rs, rt, bdslot);
3864     }
3865   } else {
3866     DCHECK_EQ(offset, 0);
3867     if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3868       return BranchShortHelperR6(0, L, cond, rs, rt);
3869     } else {
3870       return BranchShortHelper(0, L, cond, rs, rt, bdslot);
3871     }
3872   }
3873 }
3874 
3875 void TurboAssembler::BranchShort(int32_t offset, Condition cond, Register rs,
3876                                  const Operand& rt, BranchDelaySlot bdslot) {
3877   BranchShortCheck(offset, nullptr, cond, rs, rt, bdslot);
3878 }
3879 
3880 void TurboAssembler::BranchShort(Label* L, Condition cond, Register rs,
3881                                  const Operand& rt, BranchDelaySlot bdslot) {
3882   BranchShortCheck(0, L, cond, rs, rt, bdslot);
3883 }
3884 
3885 void TurboAssembler::BranchAndLink(int32_t offset, BranchDelaySlot bdslot) {
3886   BranchAndLinkShort(offset, bdslot);
3887 }
3888 
3889 void TurboAssembler::BranchAndLink(int32_t offset, Condition cond, Register rs,
3890                                    const Operand& rt, BranchDelaySlot bdslot) {
3891   bool is_near = BranchAndLinkShortCheck(offset, nullptr, cond, rs, rt, bdslot);
3892   DCHECK(is_near);
3893   USE(is_near);
3894 }
3895 
3896 void TurboAssembler::BranchAndLink(Label* L, BranchDelaySlot bdslot) {
3897   if (L->is_bound()) {
3898     if (is_near_branch(L)) {
3899       BranchAndLinkShort(L, bdslot);
3900     } else {
3901       BranchAndLinkLong(L, bdslot);
3902     }
3903   } else {
3904     if (is_trampoline_emitted()) {
3905       BranchAndLinkLong(L, bdslot);
3906     } else {
3907       BranchAndLinkShort(L, bdslot);
3908     }
3909   }
3910 }
3911 
3912 void TurboAssembler::BranchAndLink(Label* L, Condition cond, Register rs,
3913                                    const Operand& rt, BranchDelaySlot bdslot) {
3914   if (L->is_bound()) {
3915     if (!BranchAndLinkShortCheck(0, L, cond, rs, rt, bdslot)) {
3916       Label skip;
3917       Condition neg_cond = NegateCondition(cond);
3918       BranchShort(&skip, neg_cond, rs, rt);
3919       BranchAndLinkLong(L, bdslot);
3920       bind(&skip);
3921     }
3922   } else {
3923     if (is_trampoline_emitted()) {
3924       Label skip;
3925       Condition neg_cond = NegateCondition(cond);
3926       BranchShort(&skip, neg_cond, rs, rt);
3927       BranchAndLinkLong(L, bdslot);
3928       bind(&skip);
3929     } else {
3930       BranchAndLinkShortCheck(0, L, cond, rs, rt, bdslot);
3931     }
3932   }
3933 }
3934 
3935 void TurboAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L,
3936                                               BranchDelaySlot bdslot) {
3937   DCHECK(L == nullptr || offset == 0);
3938   offset = GetOffset(offset, L, OffsetSize::kOffset16);
3939   bal(offset);
3940 
3941   // Emit a nop in the branch delay slot if required.
3942   if (bdslot == PROTECT) nop();
3943 }
3944 
3945 void TurboAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L) {
3946   DCHECK(L == nullptr || offset == 0);
3947   offset = GetOffset(offset, L, OffsetSize::kOffset26);
3948   balc(offset);
3949 }
3950 
3951 void TurboAssembler::BranchAndLinkShort(int32_t offset,
3952                                         BranchDelaySlot bdslot) {
3953   if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3954     DCHECK(is_int26(offset));
3955     BranchAndLinkShortHelperR6(offset, nullptr);
3956   } else {
3957     DCHECK(is_int16(offset));
3958     BranchAndLinkShortHelper(offset, nullptr, bdslot);
3959   }
3960 }
3961 
3962 void TurboAssembler::BranchAndLinkShort(Label* L, BranchDelaySlot bdslot) {
3963   if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3964     BranchAndLinkShortHelperR6(0, L);
3965   } else {
3966     BranchAndLinkShortHelper(0, L, bdslot);
3967   }
3968 }
3969 
3970 bool TurboAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L,
3971                                                 Condition cond, Register rs,
3972                                                 const Operand& rt) {
3973   DCHECK(L == nullptr || offset == 0);
3974   UseScratchRegisterScope temps(this);
3975   Register scratch = temps.hasAvailable() ? temps.Acquire() : t8;
3976   OffsetSize bits = OffsetSize::kOffset16;
3977 
3978   BlockTrampolinePoolScope block_trampoline_pool(this);
3979   DCHECK((cond == cc_always && is_int26(offset)) || is_int16(offset));
3980   switch (cond) {
3981     case cc_always:
3982       if (!CalculateOffset(L, &offset, OffsetSize::kOffset26)) return false;
3983       balc(offset);
3984       break;
3985     case eq:
3986       if (!is_near(L, bits)) return false;
3987       Subu(scratch, rs, rt);
3988       offset = GetOffset(offset, L, bits);
3989       beqzalc(scratch, offset);
3990       break;
3991     case ne:
3992       if (!is_near(L, bits)) return false;
3993       Subu(scratch, rs, rt);
3994       offset = GetOffset(offset, L, bits);
3995       bnezalc(scratch, offset);
3996       break;
3997 
3998     // Signed comparison.
3999     case greater:
4000       // rs > rt
4001       if (rs.code() == rt.rm().code()) {
4002         break;  // No code needs to be emitted.
4003       } else if (rs == zero_reg) {
4004         if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
4005           return false;
4006         bltzalc(scratch, offset);
4007       } else if (IsZero(rt)) {
4008         if (!CalculateOffset(L, &offset, OffsetSize::kOffset16)) return false;
4009         bgtzalc(rs, offset);
4010       } else {
4011         if (!is_near(L, bits)) return false;
4012         Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
4013         offset = GetOffset(offset, L, bits);
4014         bnezalc(scratch, offset);
4015       }
4016       break;
4017     case greater_equal:
4018       // rs >= rt
4019       if (rs.code() == rt.rm().code()) {
4020         if (!CalculateOffset(L, &offset, OffsetSize::kOffset26)) return false;
4021         balc(offset);
4022       } else if (rs == zero_reg) {
4023         if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
4024           return false;
4025         blezalc(scratch, offset);
4026       } else if (IsZero(rt)) {
4027         if (!CalculateOffset(L, &offset, OffsetSize::kOffset16)) return false;
4028         bgezalc(rs, offset);
4029       } else {
4030         if (!is_near(L, bits)) return false;
4031         Slt(scratch, rs, rt);
4032         offset = GetOffset(offset, L, bits);
4033         beqzalc(scratch, offset);
4034       }
4035       break;
4036     case less:
4037       // rs < rt
4038       if (rs.code() == rt.rm().code()) {
4039         break;  // No code needs to be emitted.
4040       } else if (rs == zero_reg) {
4041         if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
4042           return false;
4043         bgtzalc(scratch, offset);
4044       } else if (IsZero(rt)) {
4045         if (!CalculateOffset(L, &offset, OffsetSize::kOffset16)) return false;
4046         bltzalc(rs, offset);
4047       } else {
4048         if (!is_near(L, bits)) return false;
4049         Slt(scratch, rs, rt);
4050         offset = GetOffset(offset, L, bits);
4051         bnezalc(scratch, offset);
4052       }
4053       break;
4054     case less_equal:
4055       // rs <= r2
4056       if (rs.code() == rt.rm().code()) {
4057         if (!CalculateOffset(L, &offset, OffsetSize::kOffset26)) return false;
4058         balc(offset);
4059       } else if (rs == zero_reg) {
4060         if (!CalculateOffset(L, &offset, OffsetSize::kOffset16, &scratch, rt))
4061           return false;
4062         bgezalc(scratch, offset);
4063       } else if (IsZero(rt)) {
4064         if (!CalculateOffset(L, &offset, OffsetSize::kOffset16)) return false;
4065         blezalc(rs, offset);
4066       } else {
4067         if (!is_near(L, bits)) return false;
4068         Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
4069         offset = GetOffset(offset, L, bits);
4070         beqzalc(scratch, offset);
4071       }
4072       break;
4073 
4074     // Unsigned comparison.
4075     case Ugreater:
4076       // rs > r2
4077       if (!is_near(L, bits)) return false;
4078       Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
4079       offset = GetOffset(offset, L, bits);
4080       bnezalc(scratch, offset);
4081       break;
4082     case Ugreater_equal:
4083       // rs >= r2
4084       if (!is_near(L, bits)) return false;
4085       Sltu(scratch, rs, rt);
4086       offset = GetOffset(offset, L, bits);
4087       beqzalc(scratch, offset);
4088       break;
4089     case Uless:
4090       // rs < r2
4091       if (!is_near(L, bits)) return false;
4092       Sltu(scratch, rs, rt);
4093       offset = GetOffset(offset, L, bits);
4094       bnezalc(scratch, offset);
4095       break;
4096     case Uless_equal:
4097       // rs <= r2
4098       if (!is_near(L, bits)) return false;
4099       Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
4100       offset = GetOffset(offset, L, bits);
4101       beqzalc(scratch, offset);
4102       break;
4103     default:
4104       UNREACHABLE();
4105   }
4106   return true;
4107 }
4108 
4109 // Pre r6 we need to use a bgezal or bltzal, but they can't be used directly
4110 // with the slt instructions. We could use sub or add instead but we would miss
4111 // overflow cases, so we keep slt and add an intermediate third instruction.
4112 bool TurboAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L,
4113                                               Condition cond, Register rs,
4114                                               const Operand& rt,
4115                                               BranchDelaySlot bdslot) {
4116   DCHECK(L == nullptr || offset == 0);
4117   if (!is_near(L, OffsetSize::kOffset16)) return false;
4118 
4119   Register scratch = t8;
4120   BlockTrampolinePoolScope block_trampoline_pool(this);
4121 
4122   switch (cond) {
4123     case cc_always:
4124       offset = GetOffset(offset, L, OffsetSize::kOffset16);
4125       bal(offset);
4126       break;
4127     case eq:
4128       bne(rs, GetRtAsRegisterHelper(rt, scratch), 2);
4129       nop();
4130       offset = GetOffset(offset, L, OffsetSize::kOffset16);
4131       bal(offset);
4132       break;
4133     case ne:
4134       beq(rs, GetRtAsRegisterHelper(rt, scratch), 2);
4135       nop();
4136       offset = GetOffset(offset, L, OffsetSize::kOffset16);
4137       bal(offset);
4138       break;
4139 
4140     // Signed comparison.
4141     case greater:
4142       Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
4143       addiu(scratch, scratch, -1);
4144       offset = GetOffset(offset, L, OffsetSize::kOffset16);
4145       bgezal(scratch, offset);
4146       break;
4147     case greater_equal:
4148       Slt(scratch, rs, rt);
4149       addiu(scratch, scratch, -1);
4150       offset = GetOffset(offset, L, OffsetSize::kOffset16);
4151       bltzal(scratch, offset);
4152       break;
4153     case less:
4154       Slt(scratch, rs, rt);
4155       addiu(scratch, scratch, -1);
4156       offset = GetOffset(offset, L, OffsetSize::kOffset16);
4157       bgezal(scratch, offset);
4158       break;
4159     case less_equal:
4160       Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
4161       addiu(scratch, scratch, -1);
4162       offset = GetOffset(offset, L, OffsetSize::kOffset16);
4163       bltzal(scratch, offset);
4164       break;
4165 
4166     // Unsigned comparison.
4167     case Ugreater:
4168       Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
4169       addiu(scratch, scratch, -1);
4170       offset = GetOffset(offset, L, OffsetSize::kOffset16);
4171       bgezal(scratch, offset);
4172       break;
4173     case Ugreater_equal:
4174       Sltu(scratch, rs, rt);
4175       addiu(scratch, scratch, -1);
4176       offset = GetOffset(offset, L, OffsetSize::kOffset16);
4177       bltzal(scratch, offset);
4178       break;
4179     case Uless:
4180       Sltu(scratch, rs, rt);
4181       addiu(scratch, scratch, -1);
4182       offset = GetOffset(offset, L, OffsetSize::kOffset16);
4183       bgezal(scratch, offset);
4184       break;
4185     case Uless_equal:
4186       Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
4187       addiu(scratch, scratch, -1);
4188       offset = GetOffset(offset, L, OffsetSize::kOffset16);
4189       bltzal(scratch, offset);
4190       break;
4191 
4192     default:
4193       UNREACHABLE();
4194   }
4195 
4196   // Emit a nop in the branch delay slot if required.
4197   if (bdslot == PROTECT) nop();
4198 
4199   return true;
4200 }
4201 
4202 bool TurboAssembler::BranchAndLinkShortCheck(int32_t offset, Label* L,
4203                                              Condition cond, Register rs,
4204                                              const Operand& rt,
4205                                              BranchDelaySlot bdslot) {
4206   BRANCH_ARGS_CHECK(cond, rs, rt);
4207 
4208   if (!L) {
4209     if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
4210       DCHECK(is_int26(offset));
4211       return BranchAndLinkShortHelperR6(offset, nullptr, cond, rs, rt);
4212     } else {
4213       DCHECK(is_int16(offset));
4214       return BranchAndLinkShortHelper(offset, nullptr, cond, rs, rt, bdslot);
4215     }
4216   } else {
4217     DCHECK_EQ(offset, 0);
4218     if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
4219       return BranchAndLinkShortHelperR6(0, L, cond, rs, rt);
4220     } else {
4221       return BranchAndLinkShortHelper(0, L, cond, rs, rt, bdslot);
4222     }
4223   }
4224 }
4225 
4226 void TurboAssembler::LoadFromConstantsTable(Register destination,
4227                                             int constant_index) {
4228   ASM_CODE_COMMENT(this);
4229   DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kBuiltinsConstantsTable));
4230   LoadRoot(destination, RootIndex::kBuiltinsConstantsTable);
4231   Ld(destination,
4232      FieldMemOperand(destination,
4233                      FixedArray::kHeaderSize + constant_index * kPointerSize));
4234 }
4235 
4236 void TurboAssembler::LoadRootRelative(Register destination, int32_t offset) {
4237   Ld(destination, MemOperand(kRootRegister, offset));
4238 }
4239 
4240 void TurboAssembler::LoadRootRegisterOffset(Register destination,
4241                                             intptr_t offset) {
4242   if (offset == 0) {
4243     Move(destination, kRootRegister);
4244   } else {
4245     Daddu(destination, kRootRegister, Operand(offset));
4246   }
4247 }
4248 
4249 void TurboAssembler::Jump(Register target, Condition cond, Register rs,
4250                           const Operand& rt, BranchDelaySlot bd) {
4251   BlockTrampolinePoolScope block_trampoline_pool(this);
4252   if (kArchVariant == kMips64r6 && bd == PROTECT) {
4253     if (cond == cc_always) {
4254       jic(target, 0);
4255     } else {
4256       BRANCH_ARGS_CHECK(cond, rs, rt);
4257       Branch(2, NegateCondition(cond), rs, rt);
4258       jic(target, 0);
4259     }
4260   } else {
4261     if (cond == cc_always) {
4262       jr(target);
4263     } else {
4264       BRANCH_ARGS_CHECK(cond, rs, rt);
4265       Branch(2, NegateCondition(cond), rs, rt);
4266       jr(target);
4267     }
4268     // Emit a nop in the branch delay slot if required.
4269     if (bd == PROTECT) nop();
4270   }
4271 }
4272 
4273 void TurboAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
4274                           Condition cond, Register rs, const Operand& rt,
4275                           BranchDelaySlot bd) {
4276   Label skip;
4277   if (cond != cc_always) {
4278     Branch(USE_DELAY_SLOT, &skip, NegateCondition(cond), rs, rt);
4279   }
4280   // The first instruction of 'li' may be placed in the delay slot.
4281   // This is not an issue, t9 is expected to be clobbered anyway.
4282   {
4283     BlockTrampolinePoolScope block_trampoline_pool(this);
4284     li(t9, Operand(target, rmode));
4285     Jump(t9, al, zero_reg, Operand(zero_reg), bd);
4286     bind(&skip);
4287   }
4288 }
4289 
4290 void TurboAssembler::Jump(Address target, RelocInfo::Mode rmode, Condition cond,
4291                           Register rs, const Operand& rt, BranchDelaySlot bd) {
4292   DCHECK(!RelocInfo::IsCodeTarget(rmode));
4293   Jump(static_cast<intptr_t>(target), rmode, cond, rs, rt, bd);
4294 }
4295 
4296 void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
4297                           Condition cond, Register rs, const Operand& rt,
4298                           BranchDelaySlot bd) {
4299   DCHECK(RelocInfo::IsCodeTarget(rmode));
4300 
4301   BlockTrampolinePoolScope block_trampoline_pool(this);
4302   if (root_array_available_ && options().isolate_independent_code) {
4303     IndirectLoadConstant(t9, code);
4304     Daddu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag));
4305     Jump(t9, cond, rs, rt, bd);
4306     return;
4307   } else if (options().inline_offheap_trampolines) {
4308     Builtin builtin = Builtin::kNoBuiltinId;
4309     if (isolate()->builtins()->IsBuiltinHandle(code, &builtin) &&
4310         Builtins::IsIsolateIndependent(builtin)) {
4311       // Inline the trampoline.
4312       RecordCommentForOffHeapTrampoline(builtin);
4313       li(t9, Operand(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET));
4314       Jump(t9, cond, rs, rt, bd);
4315       RecordComment("]");
4316       return;
4317     }
4318   }
4319 
4320   Jump(static_cast<intptr_t>(code.address()), rmode, cond, rs, rt, bd);
4321 }
4322 
4323 void TurboAssembler::Jump(const ExternalReference& reference) {
4324   li(t9, reference);
4325   Jump(t9);
4326 }
4327 
4328 // Note: To call gcc-compiled C code on mips, you must call through t9.
4329 void TurboAssembler::Call(Register target, Condition cond, Register rs,
4330                           const Operand& rt, BranchDelaySlot bd) {
4331   BlockTrampolinePoolScope block_trampoline_pool(this);
4332   if (kArchVariant == kMips64r6 && bd == PROTECT) {
4333     if (cond == cc_always) {
4334       jialc(target, 0);
4335     } else {
4336       BRANCH_ARGS_CHECK(cond, rs, rt);
4337       Branch(2, NegateCondition(cond), rs, rt);
4338       jialc(target, 0);
4339     }
4340   } else {
4341     if (cond == cc_always) {
4342       jalr(target);
4343     } else {
4344       BRANCH_ARGS_CHECK(cond, rs, rt);
4345       Branch(2, NegateCondition(cond), rs, rt);
4346       jalr(target);
4347     }
4348     // Emit a nop in the branch delay slot if required.
4349     if (bd == PROTECT) nop();
4350   }
4351   set_pc_for_safepoint();
4352 }
4353 
4354 void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit,
4355                                      unsigned higher_limit,
4356                                      Label* on_in_range) {
4357   ASM_CODE_COMMENT(this);
4358   if (lower_limit != 0) {
4359     UseScratchRegisterScope temps(this);
4360     Register scratch = temps.Acquire();
4361     Dsubu(scratch, value, Operand(lower_limit));
4362     Branch(on_in_range, ls, scratch, Operand(higher_limit - lower_limit));
4363   } else {
4364     Branch(on_in_range, ls, value, Operand(higher_limit - lower_limit));
4365   }
4366 }
4367 
4368 void TurboAssembler::Call(Address target, RelocInfo::Mode rmode, Condition cond,
4369                           Register rs, const Operand& rt, BranchDelaySlot bd) {
4370   BlockTrampolinePoolScope block_trampoline_pool(this);
4371   li(t9, Operand(static_cast<int64_t>(target), rmode), ADDRESS_LOAD);
4372   Call(t9, cond, rs, rt, bd);
4373 }
4374 
4375 void TurboAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
4376                           Condition cond, Register rs, const Operand& rt,
4377                           BranchDelaySlot bd) {
4378   BlockTrampolinePoolScope block_trampoline_pool(this);
4379 
4380   if (root_array_available_ && options().isolate_independent_code) {
4381     IndirectLoadConstant(t9, code);
4382     Daddu(t9, t9, Operand(Code::kHeaderSize - kHeapObjectTag));
4383     Call(t9, cond, rs, rt, bd);
4384     return;
4385   } else if (options().inline_offheap_trampolines) {
4386     Builtin builtin = Builtin::kNoBuiltinId;
4387     if (isolate()->builtins()->IsBuiltinHandle(code, &builtin) &&
4388         Builtins::IsIsolateIndependent(builtin)) {
4389       // Inline the trampoline.
4390       RecordCommentForOffHeapTrampoline(builtin);
4391       li(t9, Operand(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET));
4392       Call(t9, cond, rs, rt, bd);
4393       RecordComment("]");
4394       return;
4395     }
4396   }
4397 
4398   DCHECK(RelocInfo::IsCodeTarget(rmode));
4399   DCHECK(code->IsExecutable());
4400   Call(code.address(), rmode, cond, rs, rt, bd);
4401 }
4402 
4403 void TurboAssembler::LoadEntryFromBuiltinIndex(Register builtin_index) {
4404   ASM_CODE_COMMENT(this);
4405   STATIC_ASSERT(kSystemPointerSize == 8);
4406   STATIC_ASSERT(kSmiTagSize == 1);
4407   STATIC_ASSERT(kSmiTag == 0);
4408 
4409   // The builtin_index register contains the builtin index as a Smi.
4410   SmiUntag(builtin_index, builtin_index);
4411   Dlsa(builtin_index, kRootRegister, builtin_index, kSystemPointerSizeLog2);
4412   Ld(builtin_index,
4413      MemOperand(builtin_index, IsolateData::builtin_entry_table_offset()));
4414 }
4415 void TurboAssembler::LoadEntryFromBuiltin(Builtin builtin,
4416                                           Register destination) {
4417   Ld(destination, EntryFromBuiltinAsOperand(builtin));
4418 }
4419 MemOperand TurboAssembler::EntryFromBuiltinAsOperand(Builtin builtin) {
4420   DCHECK(root_array_available());
4421   return MemOperand(kRootRegister,
4422                     IsolateData::BuiltinEntrySlotOffset(builtin));
4423 }
4424 
4425 void TurboAssembler::CallBuiltinByIndex(Register builtin_index) {
4426   ASM_CODE_COMMENT(this);
4427   LoadEntryFromBuiltinIndex(builtin_index);
4428   Call(builtin_index);
4429 }
4430 void TurboAssembler::CallBuiltin(Builtin builtin) {
4431   RecordCommentForOffHeapTrampoline(builtin);
4432   Call(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET);
4433   RecordComment("]");
4434 }
4435 
4436 void TurboAssembler::PatchAndJump(Address target) {
4437   if (kArchVariant != kMips64r6) {
4438     ASM_CODE_COMMENT(this);
4439     UseScratchRegisterScope temps(this);
4440     Register scratch = temps.Acquire();
4441     mov(scratch, ra);
4442     bal(1);                                  // jump to ld
4443     nop();                                   // in the delay slot
4444     ld(t9, MemOperand(ra, kInstrSize * 3));  // ra == pc_
4445     jr(t9);
4446     mov(ra, scratch);  // in delay slot
4447     DCHECK_EQ(reinterpret_cast<uint64_t>(pc_) % 8, 0);
4448     *reinterpret_cast<uint64_t*>(pc_) = target;  // pc_ should be align.
4449     pc_ += sizeof(uint64_t);
4450   } else {
4451     // TODO(mips r6): Implement.
4452     UNIMPLEMENTED();
4453   }
4454 }
4455 
4456 void TurboAssembler::StoreReturnAddressAndCall(Register target) {
4457   ASM_CODE_COMMENT(this);
4458   // This generates the final instruction sequence for calls to C functions
4459   // once an exit frame has been constructed.
4460   //
4461   // Note that this assumes the caller code (i.e. the Code object currently
4462   // being generated) is immovable or that the callee function cannot trigger
4463   // GC, since the callee function will return to it.
4464 
4465   // Compute the return address in lr to return to after the jump below. The pc
4466   // is already at '+ 8' from the current instruction; but return is after three
4467   // instructions, so add another 4 to pc to get the return address.
4468 
4469   Assembler::BlockTrampolinePoolScope block_trampoline_pool(this);
4470   static constexpr int kNumInstructionsToJump = 4;
4471   Label find_ra;
4472   // Adjust the value in ra to point to the correct return location, 2nd
4473   // instruction past the real call into C code (the jalr(t9)), and push it.
4474   // This is the return address of the exit frame.
4475   if (kArchVariant >= kMips64r6) {
4476     addiupc(ra, kNumInstructionsToJump + 1);
4477   } else {
4478     // This no-op-and-link sequence saves PC + 8 in ra register on pre-r6 MIPS
4479     nal();  // nal has branch delay slot.
4480     Daddu(ra, ra, kNumInstructionsToJump * kInstrSize);
4481   }
4482   bind(&find_ra);
4483 
4484   // This spot was reserved in EnterExitFrame.
4485   Sd(ra, MemOperand(sp));
4486   // Stack space reservation moved to the branch delay slot below.
4487   // Stack is still aligned.
4488 
4489   // Call the C routine.
4490   mov(t9, target);  // Function pointer to t9 to conform to ABI for PIC.
4491   jalr(t9);
4492   // Set up sp in the delay slot.
4493   daddiu(sp, sp, -kCArgsSlotsSize);
4494   // Make sure the stored 'ra' points to this position.
4495   DCHECK_EQ(kNumInstructionsToJump, InstructionsGeneratedSince(&find_ra));
4496 }
4497 
4498 void TurboAssembler::Ret(Condition cond, Register rs, const Operand& rt,
4499                          BranchDelaySlot bd) {
4500   Jump(ra, cond, rs, rt, bd);
4501 }
4502 
4503 void TurboAssembler::BranchLong(Label* L, BranchDelaySlot bdslot) {
4504   if (kArchVariant == kMips64r6 && bdslot == PROTECT &&
4505       (!L->is_bound() || is_near_r6(L))) {
4506     BranchShortHelperR6(0, L);
4507   } else {
4508     // Generate position independent long branch.
4509     BlockTrampolinePoolScope block_trampoline_pool(this);
4510     int64_t imm64 = branch_long_offset(L);
4511     DCHECK(is_int32(imm64));
4512     int32_t imm32 = static_cast<int32_t>(imm64);
4513     or_(t8, ra, zero_reg);
4514     nal();                                        // Read PC into ra register.
4515     lui(t9, (imm32 & kHiMaskOf32) >> kLuiShift);  // Branch delay slot.
4516     ori(t9, t9, (imm32 & kImm16Mask));
4517     daddu(t9, ra, t9);
4518     if (bdslot == USE_DELAY_SLOT) {
4519       or_(ra, t8, zero_reg);
4520     }
4521     jr(t9);
4522     // Emit a or_ in the branch delay slot if it's protected.
4523     if (bdslot == PROTECT) or_(ra, t8, zero_reg);
4524   }
4525 }
4526 
4527 void TurboAssembler::BranchLong(int32_t offset, BranchDelaySlot bdslot) {
4528   if (kArchVariant == kMips64r6 && bdslot == PROTECT && (is_int26(offset))) {
4529     BranchShortHelperR6(offset, nullptr);
4530   } else {
4531     BlockTrampolinePoolScope block_trampoline_pool(this);
4532     or_(t8, ra, zero_reg);
4533     nal();                                         // Read PC into ra register.
4534     lui(t9, (offset & kHiMaskOf32) >> kLuiShift);  // Branch delay slot.
4535     ori(t9, t9, (offset & kImm16Mask));
4536     daddu(t9, ra, t9);
4537     if (bdslot == USE_DELAY_SLOT) {
4538       or_(ra, t8, zero_reg);
4539     }
4540     jr(t9);
4541     // Emit a or_ in the branch delay slot if it's protected.
4542     if (bdslot == PROTECT) or_(ra, t8, zero_reg);
4543   }
4544 }
4545 
4546 void TurboAssembler::BranchAndLinkLong(Label* L, BranchDelaySlot bdslot) {
4547   if (kArchVariant == kMips64r6 && bdslot == PROTECT &&
4548       (!L->is_bound() || is_near_r6(L))) {
4549     BranchAndLinkShortHelperR6(0, L);
4550   } else {
4551     // Generate position independent long branch and link.
4552     BlockTrampolinePoolScope block_trampoline_pool(this);
4553     int64_t imm64 = branch_long_offset(L);
4554     DCHECK(is_int32(imm64));
4555     int32_t imm32 = static_cast<int32_t>(imm64);
4556     lui(t8, (imm32 & kHiMaskOf32) >> kLuiShift);
4557     nal();                              // Read PC into ra register.
4558     ori(t8, t8, (imm32 & kImm16Mask));  // Branch delay slot.
4559     daddu(t8, ra, t8);
4560     jalr(t8);
4561     // Emit a nop in the branch delay slot if required.
4562     if (bdslot == PROTECT) nop();
4563   }
4564 }
4565 
4566 void TurboAssembler::DropArguments(Register count, ArgumentsCountType type,
4567                                    ArgumentsCountMode mode, Register scratch) {
4568   switch (type) {
4569     case kCountIsInteger: {
4570       Dlsa(sp, sp, count, kPointerSizeLog2);
4571       break;
4572     }
4573     case kCountIsSmi: {
4574       STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
4575       DCHECK_NE(scratch, no_reg);
4576       SmiScale(scratch, count, kPointerSizeLog2);
4577       Daddu(sp, sp, scratch);
4578       break;
4579     }
4580     case kCountIsBytes: {
4581       Daddu(sp, sp, count);
4582       break;
4583     }
4584   }
4585   if (mode == kCountExcludesReceiver) {
4586     Daddu(sp, sp, kSystemPointerSize);
4587   }
4588 }
4589 
4590 void TurboAssembler::DropArgumentsAndPushNewReceiver(Register argc,
4591                                                      Register receiver,
4592                                                      ArgumentsCountType type,
4593                                                      ArgumentsCountMode mode,
4594                                                      Register scratch) {
4595   DCHECK(!AreAliased(argc, receiver));
4596   if (mode == kCountExcludesReceiver) {
4597     // Drop arguments without receiver and override old receiver.
4598     DropArguments(argc, type, kCountIncludesReceiver, scratch);
4599     Sd(receiver, MemOperand(sp));
4600   } else {
4601     DropArguments(argc, type, mode, scratch);
4602     push(receiver);
4603   }
4604 }
4605 
4606 void TurboAssembler::DropAndRet(int drop) {
4607   int32_t drop_size = drop * kSystemPointerSize;
4608   DCHECK(is_int31(drop_size));
4609 
4610   if (is_int16(drop_size)) {
4611     Ret(USE_DELAY_SLOT);
4612     daddiu(sp, sp, drop_size);
4613   } else {
4614     UseScratchRegisterScope temps(this);
4615     Register scratch = temps.Acquire();
4616     li(scratch, drop_size);
4617     Ret(USE_DELAY_SLOT);
4618     daddu(sp, sp, scratch);
4619   }
4620 }
4621 
4622 void TurboAssembler::DropAndRet(int drop, Condition cond, Register r1,
4623                                 const Operand& r2) {
4624   // Both Drop and Ret need to be conditional.
4625   Label skip;
4626   if (cond != cc_always) {
4627     Branch(&skip, NegateCondition(cond), r1, r2);
4628   }
4629 
4630   Drop(drop);
4631   Ret();
4632 
4633   if (cond != cc_always) {
4634     bind(&skip);
4635   }
4636 }
4637 
4638 void TurboAssembler::Drop(int count, Condition cond, Register reg,
4639                           const Operand& op) {
4640   if (count <= 0) {
4641     return;
4642   }
4643 
4644   Label skip;
4645 
4646   if (cond != al) {
4647     Branch(&skip, NegateCondition(cond), reg, op);
4648   }
4649 
4650   Daddu(sp, sp, Operand(count * kPointerSize));
4651 
4652   if (cond != al) {
4653     bind(&skip);
4654   }
4655 }
4656 
4657 void MacroAssembler::Swap(Register reg1, Register reg2, Register scratch) {
4658   if (scratch == no_reg) {
4659     Xor(reg1, reg1, Operand(reg2));
4660     Xor(reg2, reg2, Operand(reg1));
4661     Xor(reg1, reg1, Operand(reg2));
4662   } else {
4663     mov(scratch, reg1);
4664     mov(reg1, reg2);
4665     mov(reg2, scratch);
4666   }
4667 }
4668 
4669 void TurboAssembler::Call(Label* target) { BranchAndLink(target); }
4670 
4671 void TurboAssembler::LoadAddress(Register dst, Label* target) {
4672   uint64_t address = jump_address(target);
4673   li(dst, address);
4674 }
4675 
4676 void TurboAssembler::Push(Smi smi) {
4677   UseScratchRegisterScope temps(this);
4678   Register scratch = temps.Acquire();
4679   li(scratch, Operand(smi));
4680   push(scratch);
4681 }
4682 
4683 void TurboAssembler::Push(Handle<HeapObject> handle) {
4684   UseScratchRegisterScope temps(this);
4685   Register scratch = temps.Acquire();
4686   li(scratch, Operand(handle));
4687   push(scratch);
4688 }
4689 
4690 void TurboAssembler::PushArray(Register array, Register size, Register scratch,
4691                                Register scratch2, PushArrayOrder order) {
4692   DCHECK(!AreAliased(array, size, scratch, scratch2));
4693   Label loop, entry;
4694   if (order == PushArrayOrder::kReverse) {
4695     mov(scratch, zero_reg);
4696     jmp(&entry);
4697     bind(&loop);
4698     Dlsa(scratch2, array, scratch, kPointerSizeLog2);
4699     Ld(scratch2, MemOperand(scratch2));
4700     push(scratch2);
4701     Daddu(scratch, scratch, Operand(1));
4702     bind(&entry);
4703     Branch(&loop, less, scratch, Operand(size));
4704   } else {
4705     mov(scratch, size);
4706     jmp(&entry);
4707     bind(&loop);
4708     Dlsa(scratch2, array, scratch, kPointerSizeLog2);
4709     Ld(scratch2, MemOperand(scratch2));
4710     push(scratch2);
4711     bind(&entry);
4712     Daddu(scratch, scratch, Operand(-1));
4713     Branch(&loop, greater_equal, scratch, Operand(zero_reg));
4714   }
4715 }
4716 
4717 // ---------------------------------------------------------------------------
4718 // Exception handling.
4719 
4720 void MacroAssembler::PushStackHandler() {
4721   // Adjust this code if not the case.
4722   STATIC_ASSERT(StackHandlerConstants::kSize == 2 * kPointerSize);
4723   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
4724 
4725   Push(Smi::zero());  // Padding.
4726 
4727   // Link the current handler as the next handler.
4728   li(t2,
4729      ExternalReference::Create(IsolateAddressId::kHandlerAddress, isolate()));
4730   Ld(t1, MemOperand(t2));
4731   push(t1);
4732 
4733   // Set this new handler as the current one.
4734   Sd(sp, MemOperand(t2));
4735 }
4736 
4737 void MacroAssembler::PopStackHandler() {
4738   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
4739   pop(a1);
4740   Daddu(sp, sp,
4741         Operand(
4742             static_cast<int64_t>(StackHandlerConstants::kSize - kPointerSize)));
4743   UseScratchRegisterScope temps(this);
4744   Register scratch = temps.Acquire();
4745   li(scratch,
4746      ExternalReference::Create(IsolateAddressId::kHandlerAddress, isolate()));
4747   Sd(a1, MemOperand(scratch));
4748 }
4749 
4750 void TurboAssembler::FPUCanonicalizeNaN(const DoubleRegister dst,
4751                                         const DoubleRegister src) {
4752   sub_d(dst, src, kDoubleRegZero);
4753 }
4754 
4755 void TurboAssembler::MovFromFloatResult(const DoubleRegister dst) {
4756   if (IsMipsSoftFloatABI) {
4757     if (kArchEndian == kLittle) {
4758       Move(dst, v0, v1);
4759     } else {
4760       Move(dst, v1, v0);
4761     }
4762   } else {
4763     Move(dst, f0);  // Reg f0 is o32 ABI FP return value.
4764   }
4765 }
4766 
4767 void TurboAssembler::MovFromFloatParameter(const DoubleRegister dst) {
4768   if (IsMipsSoftFloatABI) {
4769     if (kArchEndian == kLittle) {
4770       Move(dst, a0, a1);
4771     } else {
4772       Move(dst, a1, a0);
4773     }
4774   } else {
4775     Move(dst, f12);  // Reg f12 is n64 ABI FP first argument value.
4776   }
4777 }
4778 
4779 void TurboAssembler::MovToFloatParameter(DoubleRegister src) {
4780   if (!IsMipsSoftFloatABI) {
4781     Move(f12, src);
4782   } else {
4783     if (kArchEndian == kLittle) {
4784       Move(a0, a1, src);
4785     } else {
4786       Move(a1, a0, src);
4787     }
4788   }
4789 }
4790 
4791 void TurboAssembler::MovToFloatResult(DoubleRegister src) {
4792   if (!IsMipsSoftFloatABI) {
4793     Move(f0, src);
4794   } else {
4795     if (kArchEndian == kLittle) {
4796       Move(v0, v1, src);
4797     } else {
4798       Move(v1, v0, src);
4799     }
4800   }
4801 }
4802 
4803 void TurboAssembler::MovToFloatParameters(DoubleRegister src1,
4804                                           DoubleRegister src2) {
4805   if (!IsMipsSoftFloatABI) {
4806     const DoubleRegister fparg2 = f13;
4807     if (src2 == f12) {
4808       DCHECK(src1 != fparg2);
4809       Move(fparg2, src2);
4810       Move(f12, src1);
4811     } else {
4812       Move(f12, src1);
4813       Move(fparg2, src2);
4814     }
4815   } else {
4816     if (kArchEndian == kLittle) {
4817       Move(a0, a1, src1);
4818       Move(a2, a3, src2);
4819     } else {
4820       Move(a1, a0, src1);
4821       Move(a3, a2, src2);
4822     }
4823   }
4824 }
4825 
4826 // -----------------------------------------------------------------------------
4827 // JavaScript invokes.
4828 
4829 void MacroAssembler::LoadStackLimit(Register destination, StackLimitKind kind) {
4830   ASM_CODE_COMMENT(this);
4831   DCHECK(root_array_available());
4832   Isolate* isolate = this->isolate();
4833   ExternalReference limit =
4834       kind == StackLimitKind::kRealStackLimit
4835           ? ExternalReference::address_of_real_jslimit(isolate)
4836           : ExternalReference::address_of_jslimit(isolate);
4837   DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit));
4838 
4839   intptr_t offset =
4840       TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit);
4841   CHECK(is_int32(offset));
4842   Ld(destination, MemOperand(kRootRegister, static_cast<int32_t>(offset)));
4843 }
4844 
4845 void MacroAssembler::StackOverflowCheck(Register num_args, Register scratch1,
4846                                         Register scratch2,
4847                                         Label* stack_overflow) {
4848   ASM_CODE_COMMENT(this);
4849   // Check the stack for overflow. We are not trying to catch
4850   // interruptions (e.g. debug break and preemption) here, so the "real stack
4851   // limit" is checked.
4852 
4853   LoadStackLimit(scratch1, StackLimitKind::kRealStackLimit);
4854   // Make scratch1 the space we have left. The stack might already be overflowed
4855   // here which will cause scratch1 to become negative.
4856   dsubu(scratch1, sp, scratch1);
4857   // Check if the arguments will overflow the stack.
4858   dsll(scratch2, num_args, kPointerSizeLog2);
4859   // Signed comparison.
4860   Branch(stack_overflow, le, scratch1, Operand(scratch2));
4861 }
4862 
4863 void MacroAssembler::InvokePrologue(Register expected_parameter_count,
4864                                     Register actual_parameter_count,
4865                                     Label* done, InvokeType type) {
4866   ASM_CODE_COMMENT(this);
4867   Label regular_invoke;
4868 
4869   //  a0: actual arguments count
4870   //  a1: function (passed through to callee)
4871   //  a2: expected arguments count
4872 
4873   DCHECK_EQ(actual_parameter_count, a0);
4874   DCHECK_EQ(expected_parameter_count, a2);
4875 
4876   // If the expected parameter count is equal to the adaptor sentinel, no need
4877   // to push undefined value as arguments.
4878   if (kDontAdaptArgumentsSentinel != 0) {
4879     Branch(&regular_invoke, eq, expected_parameter_count,
4880            Operand(kDontAdaptArgumentsSentinel));
4881   }
4882 
4883   // If overapplication or if the actual argument count is equal to the
4884   // formal parameter count, no need to push extra undefined values.
4885   Dsubu(expected_parameter_count, expected_parameter_count,
4886         actual_parameter_count);
4887   Branch(&regular_invoke, le, expected_parameter_count, Operand(zero_reg));
4888 
4889   Label stack_overflow;
4890   StackOverflowCheck(expected_parameter_count, t0, t1, &stack_overflow);
4891   // Underapplication. Move the arguments already in the stack, including the
4892   // receiver and the return address.
4893   {
4894     Label copy;
4895     Register src = a6, dest = a7;
4896     mov(src, sp);
4897     dsll(t0, expected_parameter_count, kSystemPointerSizeLog2);
4898     Dsubu(sp, sp, Operand(t0));
4899     // Update stack pointer.
4900     mov(dest, sp);
4901     mov(t0, actual_parameter_count);
4902     bind(&copy);
4903     Ld(t1, MemOperand(src, 0));
4904     Sd(t1, MemOperand(dest, 0));
4905     Dsubu(t0, t0, Operand(1));
4906     Daddu(src, src, Operand(kSystemPointerSize));
4907     Daddu(dest, dest, Operand(kSystemPointerSize));
4908     Branch(&copy, gt, t0, Operand(zero_reg));
4909   }
4910 
4911   // Fill remaining expected arguments with undefined values.
4912   LoadRoot(t0, RootIndex::kUndefinedValue);
4913   {
4914     Label loop;
4915     bind(&loop);
4916     Sd(t0, MemOperand(a7, 0));
4917     Dsubu(expected_parameter_count, expected_parameter_count, Operand(1));
4918     Daddu(a7, a7, Operand(kSystemPointerSize));
4919     Branch(&loop, gt, expected_parameter_count, Operand(zero_reg));
4920   }
4921   b(&regular_invoke);
4922   nop();
4923 
4924   bind(&stack_overflow);
4925   {
4926     FrameScope frame(
4927         this, has_frame() ? StackFrame::NO_FRAME_TYPE : StackFrame::INTERNAL);
4928     CallRuntime(Runtime::kThrowStackOverflow);
4929     break_(0xCC);
4930   }
4931 
4932   bind(&regular_invoke);
4933 }
4934 
4935 void MacroAssembler::CheckDebugHook(Register fun, Register new_target,
4936                                     Register expected_parameter_count,
4937                                     Register actual_parameter_count) {
4938   Label skip_hook;
4939 
4940   li(t0, ExternalReference::debug_hook_on_function_call_address(isolate()));
4941   Lb(t0, MemOperand(t0));
4942   Branch(&skip_hook, eq, t0, Operand(zero_reg));
4943 
4944   {
4945     // Load receiver to pass it later to DebugOnFunctionCall hook.
4946     LoadReceiver(t0, actual_parameter_count);
4947 
4948     FrameScope frame(
4949         this, has_frame() ? StackFrame::NO_FRAME_TYPE : StackFrame::INTERNAL);
4950     SmiTag(expected_parameter_count);
4951     Push(expected_parameter_count);
4952 
4953     SmiTag(actual_parameter_count);
4954     Push(actual_parameter_count);
4955 
4956     if (new_target.is_valid()) {
4957       Push(new_target);
4958     }
4959     Push(fun);
4960     Push(fun);
4961     Push(t0);
4962     CallRuntime(Runtime::kDebugOnFunctionCall);
4963     Pop(fun);
4964     if (new_target.is_valid()) {
4965       Pop(new_target);
4966     }
4967 
4968     Pop(actual_parameter_count);
4969     SmiUntag(actual_parameter_count);
4970 
4971     Pop(expected_parameter_count);
4972     SmiUntag(expected_parameter_count);
4973   }
4974   bind(&skip_hook);
4975 }
4976 
4977 void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
4978                                         Register expected_parameter_count,
4979                                         Register actual_parameter_count,
4980                                         InvokeType type) {
4981   // You can't call a function without a valid frame.
4982   DCHECK_IMPLIES(type == InvokeType::kCall, has_frame());
4983   DCHECK_EQ(function, a1);
4984   DCHECK_IMPLIES(new_target.is_valid(), new_target == a3);
4985 
4986   // On function call, call into the debugger if necessary.
4987   CheckDebugHook(function, new_target, expected_parameter_count,
4988                  actual_parameter_count);
4989 
4990   // Clear the new.target register if not given.
4991   if (!new_target.is_valid()) {
4992     LoadRoot(a3, RootIndex::kUndefinedValue);
4993   }
4994 
4995   Label done;
4996   InvokePrologue(expected_parameter_count, actual_parameter_count, &done, type);
4997   // We call indirectly through the code field in the function to
4998   // allow recompilation to take effect without changing any of the
4999   // call sites.
5000   Register code = kJavaScriptCallCodeStartRegister;
5001   Ld(code, FieldMemOperand(function, JSFunction::kCodeOffset));
5002   switch (type) {
5003     case InvokeType::kCall:
5004       Daddu(code, code, Operand(Code::kHeaderSize - kHeapObjectTag));
5005       Call(code);
5006       break;
5007     case InvokeType::kJump:
5008       Daddu(code, code, Operand(Code::kHeaderSize - kHeapObjectTag));
5009       Jump(code);
5010       break;
5011   }
5012 
5013   // Continue here if InvokePrologue does handle the invocation due to
5014   // mismatched parameter counts.
5015   bind(&done);
5016 }
5017 
5018 void MacroAssembler::InvokeFunctionWithNewTarget(
5019     Register function, Register new_target, Register actual_parameter_count,
5020     InvokeType type) {
5021   ASM_CODE_COMMENT(this);
5022   // You can't call a function without a valid frame.
5023   DCHECK_IMPLIES(type == InvokeType::kCall, has_frame());
5024 
5025   // Contract with called JS functions requires that function is passed in a1.
5026   DCHECK_EQ(function, a1);
5027   Register expected_parameter_count = a2;
5028   Register temp_reg = t0;
5029   Ld(temp_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
5030   Ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
5031   // The argument count is stored as uint16_t
5032   Lhu(expected_parameter_count,
5033       FieldMemOperand(temp_reg,
5034                       SharedFunctionInfo::kFormalParameterCountOffset));
5035 
5036   InvokeFunctionCode(a1, new_target, expected_parameter_count,
5037                      actual_parameter_count, type);
5038 }
5039 
5040 void MacroAssembler::InvokeFunction(Register function,
5041                                     Register expected_parameter_count,
5042                                     Register actual_parameter_count,
5043                                     InvokeType type) {
5044   ASM_CODE_COMMENT(this);
5045   // You can't call a function without a valid frame.
5046   DCHECK_IMPLIES(type == InvokeType::kCall, has_frame());
5047 
5048   // Contract with called JS functions requires that function is passed in a1.
5049   DCHECK_EQ(function, a1);
5050 
5051   // Get the function and setup the context.
5052   Ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
5053 
5054   InvokeFunctionCode(a1, no_reg, expected_parameter_count,
5055                      actual_parameter_count, type);
5056 }
5057 
5058 // ---------------------------------------------------------------------------
5059 // Support functions.
5060 
5061 void MacroAssembler::GetObjectType(Register object, Register map,
5062                                    Register type_reg) {
5063   LoadMap(map, object);
5064   Lhu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
5065 }
5066 
5067 void MacroAssembler::GetInstanceTypeRange(Register map, Register type_reg,
5068                                           InstanceType lower_limit,
5069                                           Register range) {
5070   Lhu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
5071   Dsubu(range, type_reg, Operand(lower_limit));
5072 }
5073 
5074 // -----------------------------------------------------------------------------
5075 // Runtime calls.
5076 
5077 void TurboAssembler::DaddOverflow(Register dst, Register left,
5078                                   const Operand& right, Register overflow) {
5079   ASM_CODE_COMMENT(this);
5080   BlockTrampolinePoolScope block_trampoline_pool(this);
5081   Register right_reg = no_reg;
5082   Register scratch = t8;
5083   if (!right.is_reg()) {
5084     li(at, Operand(right));
5085     right_reg = at;
5086   } else {
5087     right_reg = right.rm();
5088   }
5089 
5090   DCHECK(left != scratch && right_reg != scratch && dst != scratch &&
5091          overflow != scratch);
5092   DCHECK(overflow != left && overflow != right_reg);
5093 
5094   if (dst == left || dst == right_reg) {
5095     daddu(scratch, left, right_reg);
5096     xor_(overflow, scratch, left);
5097     xor_(at, scratch, right_reg);
5098     and_(overflow, overflow, at);
5099     mov(dst, scratch);
5100   } else {
5101     daddu(dst, left, right_reg);
5102     xor_(overflow, dst, left);
5103     xor_(at, dst, right_reg);
5104     and_(overflow, overflow, at);
5105   }
5106 }
5107 
5108 void TurboAssembler::DsubOverflow(Register dst, Register left,
5109                                   const Operand& right, Register overflow) {
5110   ASM_CODE_COMMENT(this);
5111   BlockTrampolinePoolScope block_trampoline_pool(this);
5112   Register right_reg = no_reg;
5113   Register scratch = t8;
5114   if (!right.is_reg()) {
5115     li(at, Operand(right));
5116     right_reg = at;
5117   } else {
5118     right_reg = right.rm();
5119   }
5120 
5121   DCHECK(left != scratch && right_reg != scratch && dst != scratch &&
5122          overflow != scratch);
5123   DCHECK(overflow != left && overflow != right_reg);
5124 
5125   if (dst == left || dst == right_reg) {
5126     dsubu(scratch, left, right_reg);
5127     xor_(overflow, left, scratch);
5128     xor_(at, left, right_reg);
5129     and_(overflow, overflow, at);
5130     mov(dst, scratch);
5131   } else {
5132     dsubu(dst, left, right_reg);
5133     xor_(overflow, left, dst);
5134     xor_(at, left, right_reg);
5135     and_(overflow, overflow, at);
5136   }
5137 }
5138 
5139 void TurboAssembler::MulOverflow(Register dst, Register left,
5140                                  const Operand& right, Register overflow) {
5141   ASM_CODE_COMMENT(this);
5142   BlockTrampolinePoolScope block_trampoline_pool(this);
5143   Register right_reg = no_reg;
5144   Register scratch = t8;
5145   if (!right.is_reg()) {
5146     li(at, Operand(right));
5147     right_reg = at;
5148   } else {
5149     right_reg = right.rm();
5150   }
5151 
5152   DCHECK(left != scratch && right_reg != scratch && dst != scratch &&
5153          overflow != scratch);
5154   DCHECK(overflow != left && overflow != right_reg);
5155 
5156   if (dst == left || dst == right_reg) {
5157     Mul(scratch, left, right_reg);
5158     Mulh(overflow, left, right_reg);
5159     mov(dst, scratch);
5160   } else {
5161     Mul(dst, left, right_reg);
5162     Mulh(overflow, left, right_reg);
5163   }
5164 
5165   dsra32(scratch, dst, 0);
5166   xor_(overflow, overflow, scratch);
5167 }
5168 
5169 void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
5170                                  SaveFPRegsMode save_doubles) {
5171   ASM_CODE_COMMENT(this);
5172   // All parameters are on the stack. v0 has the return value after call.
5173 
5174   // If the expected number of arguments of the runtime function is
5175   // constant, we check that the actual number of arguments match the
5176   // expectation.
5177   CHECK(f->nargs < 0 || f->nargs == num_arguments);
5178 
5179   // TODO(1236192): Most runtime routines don't need the number of
5180   // arguments passed in because it is constant. At some point we
5181   // should remove this need and make the runtime routine entry code
5182   // smarter.
5183   PrepareCEntryArgs(num_arguments);
5184   PrepareCEntryFunction(ExternalReference::Create(f));
5185   Handle<Code> code =
5186       CodeFactory::CEntry(isolate(), f->result_size, save_doubles);
5187   Call(code, RelocInfo::CODE_TARGET);
5188 }
5189 
5190 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
5191   ASM_CODE_COMMENT(this);
5192   const Runtime::Function* function = Runtime::FunctionForId(fid);
5193   DCHECK_EQ(1, function->result_size);
5194   if (function->nargs >= 0) {
5195     PrepareCEntryArgs(function->nargs);
5196   }
5197   JumpToExternalReference(ExternalReference::Create(fid));
5198 }
5199 
5200 void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
5201                                              BranchDelaySlot bd,
5202                                              bool builtin_exit_frame) {
5203   PrepareCEntryFunction(builtin);
5204   Handle<Code> code = CodeFactory::CEntry(isolate(), 1, SaveFPRegsMode::kIgnore,
5205                                           ArgvMode::kStack, builtin_exit_frame);
5206   Jump(code, RelocInfo::CODE_TARGET, al, zero_reg, Operand(zero_reg), bd);
5207 }
5208 
5209 void MacroAssembler::JumpToOffHeapInstructionStream(Address entry) {
5210   li(kOffHeapTrampolineRegister, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
5211   Jump(kOffHeapTrampolineRegister);
5212 }
5213 
5214 void MacroAssembler::LoadWeakValue(Register out, Register in,
5215                                    Label* target_if_cleared) {
5216   Branch(target_if_cleared, eq, in, Operand(kClearedWeakHeapObjectLower32));
5217 
5218   And(out, in, Operand(~kWeakHeapObjectMask));
5219 }
5220 
5221 void MacroAssembler::EmitIncrementCounter(StatsCounter* counter, int value,
5222                                           Register scratch1,
5223                                           Register scratch2) {
5224   DCHECK_GT(value, 0);
5225   if (FLAG_native_code_counters && counter->Enabled()) {
5226     ASM_CODE_COMMENT(this);
5227     // This operation has to be exactly 32-bit wide in case the external
5228     // reference table redirects the counter to a uint32_t dummy_stats_counter_
5229     // field.
5230     li(scratch2, ExternalReference::Create(counter));
5231     Lw(scratch1, MemOperand(scratch2));
5232     Addu(scratch1, scratch1, Operand(value));
5233     Sw(scratch1, MemOperand(scratch2));
5234   }
5235 }
5236 
5237 void MacroAssembler::EmitDecrementCounter(StatsCounter* counter, int value,
5238                                           Register scratch1,
5239                                           Register scratch2) {
5240   DCHECK_GT(value, 0);
5241   if (FLAG_native_code_counters && counter->Enabled()) {
5242     ASM_CODE_COMMENT(this);
5243     // This operation has to be exactly 32-bit wide in case the external
5244     // reference table redirects the counter to a uint32_t dummy_stats_counter_
5245     // field.
5246     li(scratch2, ExternalReference::Create(counter));
5247     Lw(scratch1, MemOperand(scratch2));
5248     Subu(scratch1, scratch1, Operand(value));
5249     Sw(scratch1, MemOperand(scratch2));
5250   }
5251 }
5252 
5253 // -----------------------------------------------------------------------------
5254 // Debugging.
5255 
5256 void TurboAssembler::Trap() { stop(); }
5257 void TurboAssembler::DebugBreak() { stop(); }
5258 
5259 void TurboAssembler::Assert(Condition cc, AbortReason reason, Register rs,
5260                             Operand rt) {
5261   if (FLAG_debug_code) Check(cc, reason, rs, rt);
5262 }
5263 
5264 void TurboAssembler::Check(Condition cc, AbortReason reason, Register rs,
5265                            Operand rt) {
5266   Label L;
5267   Branch(&L, cc, rs, rt);
5268   Abort(reason);
5269   // Will not return here.
5270   bind(&L);
5271 }
5272 
5273 void TurboAssembler::Abort(AbortReason reason) {
5274   Label abort_start;
5275   bind(&abort_start);
5276   if (FLAG_code_comments) {
5277     const char* msg = GetAbortReason(reason);
5278     RecordComment("Abort message: ");
5279     RecordComment(msg);
5280   }
5281 
5282   // Avoid emitting call to builtin if requested.
5283   if (trap_on_abort()) {
5284     stop();
5285     return;
5286   }
5287 
5288   if (should_abort_hard()) {
5289     // We don't care if we constructed a frame. Just pretend we did.
5290     FrameScope assume_frame(this, StackFrame::NO_FRAME_TYPE);
5291     PrepareCallCFunction(0, a0);
5292     li(a0, Operand(static_cast<int>(reason)));
5293     CallCFunction(ExternalReference::abort_with_reason(), 1);
5294     return;
5295   }
5296 
5297   Move(a0, Smi::FromInt(static_cast<int>(reason)));
5298 
5299   // Disable stub call restrictions to always allow calls to abort.
5300   if (!has_frame()) {
5301     // We don't actually want to generate a pile of code for this, so just
5302     // claim there is a stack frame, without generating one.
5303     FrameScope scope(this, StackFrame::NO_FRAME_TYPE);
5304     Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
5305   } else {
5306     Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
5307   }
5308   // Will not return here.
5309   if (is_trampoline_pool_blocked()) {
5310     // If the calling code cares about the exact number of
5311     // instructions generated, we insert padding here to keep the size
5312     // of the Abort macro constant.
5313     // Currently in debug mode with debug_code enabled the number of
5314     // generated instructions is 10, so we use this as a maximum value.
5315     static const int kExpectedAbortInstructions = 10;
5316     int abort_instructions = InstructionsGeneratedSince(&abort_start);
5317     DCHECK_LE(abort_instructions, kExpectedAbortInstructions);
5318     while (abort_instructions++ < kExpectedAbortInstructions) {
5319       nop();
5320     }
5321   }
5322 }
5323 
5324 void TurboAssembler::LoadMap(Register destination, Register object) {
5325   Ld(destination, FieldMemOperand(object, HeapObject::kMapOffset));
5326 }
5327 
5328 void MacroAssembler::LoadNativeContextSlot(Register dst, int index) {
5329   LoadMap(dst, cp);
5330   Ld(dst,
5331      FieldMemOperand(dst, Map::kConstructorOrBackPointerOrNativeContextOffset));
5332   Ld(dst, MemOperand(dst, Context::SlotOffset(index)));
5333 }
5334 
5335 void TurboAssembler::StubPrologue(StackFrame::Type type) {
5336   UseScratchRegisterScope temps(this);
5337   Register scratch = temps.Acquire();
5338   li(scratch, Operand(StackFrame::TypeToMarker(type)));
5339   PushCommonFrame(scratch);
5340 }
5341 
5342 void TurboAssembler::Prologue() { PushStandardFrame(a1); }
5343 
5344 void TurboAssembler::EnterFrame(StackFrame::Type type) {
5345   ASM_CODE_COMMENT(this);
5346   BlockTrampolinePoolScope block_trampoline_pool(this);
5347   Push(ra, fp);
5348   Move(fp, sp);
5349   if (!StackFrame::IsJavaScript(type)) {
5350     li(kScratchReg, Operand(StackFrame::TypeToMarker(type)));
5351     Push(kScratchReg);
5352   }
5353 #if V8_ENABLE_WEBASSEMBLY
5354   if (type == StackFrame::WASM) Push(kWasmInstanceRegister);
5355 #endif  // V8_ENABLE_WEBASSEMBLY
5356 }
5357 
5358 void TurboAssembler::LeaveFrame(StackFrame::Type type) {
5359   ASM_CODE_COMMENT(this);
5360   daddiu(sp, fp, 2 * kPointerSize);
5361   Ld(ra, MemOperand(fp, 1 * kPointerSize));
5362   Ld(fp, MemOperand(fp, 0 * kPointerSize));
5363 }
5364 
5365 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
5366                                     StackFrame::Type frame_type) {
5367   ASM_CODE_COMMENT(this);
5368   DCHECK(frame_type == StackFrame::EXIT ||
5369          frame_type == StackFrame::BUILTIN_EXIT);
5370 
5371   // Set up the frame structure on the stack.
5372   STATIC_ASSERT(2 * kPointerSize == ExitFrameConstants::kCallerSPDisplacement);
5373   STATIC_ASSERT(1 * kPointerSize == ExitFrameConstants::kCallerPCOffset);
5374   STATIC_ASSERT(0 * kPointerSize == ExitFrameConstants::kCallerFPOffset);
5375 
5376   // This is how the stack will look:
5377   // fp + 2 (==kCallerSPDisplacement) - old stack's end
5378   // [fp + 1 (==kCallerPCOffset)] - saved old ra
5379   // [fp + 0 (==kCallerFPOffset)] - saved old fp
5380   // [fp - 1 StackFrame::EXIT Smi
5381   // [fp - 2 (==kSPOffset)] - sp of the called function
5382   // fp - (2 + stack_space + alignment) == sp == [fp - kSPOffset] - top of the
5383   //   new stack (will contain saved ra)
5384 
5385   // Save registers and reserve room for saved entry sp.
5386   daddiu(sp, sp, -2 * kPointerSize - ExitFrameConstants::kFixedFrameSizeFromFp);
5387   Sd(ra, MemOperand(sp, 3 * kPointerSize));
5388   Sd(fp, MemOperand(sp, 2 * kPointerSize));
5389   {
5390     UseScratchRegisterScope temps(this);
5391     Register scratch = temps.Acquire();
5392     li(scratch, Operand(StackFrame::TypeToMarker(frame_type)));
5393     Sd(scratch, MemOperand(sp, 1 * kPointerSize));
5394   }
5395   // Set up new frame pointer.
5396   daddiu(fp, sp, ExitFrameConstants::kFixedFrameSizeFromFp);
5397 
5398   if (FLAG_debug_code) {
5399     Sd(zero_reg, MemOperand(fp, ExitFrameConstants::kSPOffset));
5400   }
5401 
5402   {
5403     BlockTrampolinePoolScope block_trampoline_pool(this);
5404     // Save the frame pointer and the context in top.
5405     li(t8, ExternalReference::Create(IsolateAddressId::kCEntryFPAddress,
5406                                      isolate()));
5407     Sd(fp, MemOperand(t8));
5408     li(t8,
5409        ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()));
5410     Sd(cp, MemOperand(t8));
5411   }
5412 
5413   const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
5414   if (save_doubles) {
5415     // The stack is already aligned to 0 modulo 8 for stores with sdc1.
5416     int kNumOfSavedRegisters = FPURegister::kNumRegisters / 2;
5417     int space = kNumOfSavedRegisters * kDoubleSize;
5418     Dsubu(sp, sp, Operand(space));
5419     // Remember: we only need to save every 2nd double FPU value.
5420     for (int i = 0; i < kNumOfSavedRegisters; i++) {
5421       FPURegister reg = FPURegister::from_code(2 * i);
5422       Sdc1(reg, MemOperand(sp, i * kDoubleSize));
5423     }
5424   }
5425 
5426   // Reserve place for the return address, stack space and an optional slot
5427   // (used by DirectCEntry to hold the return value if a struct is
5428   // returned) and align the frame preparing for calling the runtime function.
5429   DCHECK_GE(stack_space, 0);
5430   Dsubu(sp, sp, Operand((stack_space + 2) * kPointerSize));
5431   if (frame_alignment > 0) {
5432     DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
5433     And(sp, sp, Operand(-frame_alignment));  // Align stack.
5434   }
5435 
5436   // Set the exit frame sp value to point just before the return address
5437   // location.
5438   UseScratchRegisterScope temps(this);
5439   Register scratch = temps.Acquire();
5440   daddiu(scratch, sp, kPointerSize);
5441   Sd(scratch, MemOperand(fp, ExitFrameConstants::kSPOffset));
5442 }
5443 
5444 void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
5445                                     bool do_return,
5446                                     bool argument_count_is_length) {
5447   ASM_CODE_COMMENT(this);
5448   BlockTrampolinePoolScope block_trampoline_pool(this);
5449   // Optionally restore all double registers.
5450   if (save_doubles) {
5451     // Remember: we only need to restore every 2nd double FPU value.
5452     int kNumOfSavedRegisters = FPURegister::kNumRegisters / 2;
5453     Dsubu(t8, fp,
5454           Operand(ExitFrameConstants::kFixedFrameSizeFromFp +
5455                   kNumOfSavedRegisters * kDoubleSize));
5456     for (int i = 0; i < kNumOfSavedRegisters; i++) {
5457       FPURegister reg = FPURegister::from_code(2 * i);
5458       Ldc1(reg, MemOperand(t8, i * kDoubleSize));
5459     }
5460   }
5461 
5462   // Clear top frame.
5463   li(t8,
5464      ExternalReference::Create(IsolateAddressId::kCEntryFPAddress, isolate()));
5465   Sd(zero_reg, MemOperand(t8));
5466 
5467   // Restore current context from top and clear it in debug mode.
5468   li(t8,
5469      ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()));
5470   Ld(cp, MemOperand(t8));
5471 
5472   if (FLAG_debug_code) {
5473     UseScratchRegisterScope temp(this);
5474     Register scratch = temp.Acquire();
5475     li(scratch, Operand(Context::kInvalidContext));
5476     Sd(scratch, MemOperand(t8));
5477   }
5478 
5479   // Pop the arguments, restore registers, and return.
5480   mov(sp, fp);  // Respect ABI stack constraint.
5481   Ld(fp, MemOperand(sp, ExitFrameConstants::kCallerFPOffset));
5482   Ld(ra, MemOperand(sp, ExitFrameConstants::kCallerPCOffset));
5483 
5484   if (argument_count.is_valid()) {
5485     if (argument_count_is_length) {
5486       daddu(sp, sp, argument_count);
5487     } else {
5488       Dlsa(sp, sp, argument_count, kPointerSizeLog2, t8);
5489     }
5490   }
5491 
5492   if (do_return) {
5493     Ret(USE_DELAY_SLOT);
5494     // If returning, the instruction in the delay slot will be the addiu below.
5495   }
5496   daddiu(sp, sp, 2 * kPointerSize);
5497 }
5498 
5499 int TurboAssembler::ActivationFrameAlignment() {
5500 #if V8_HOST_ARCH_MIPS || V8_HOST_ARCH_MIPS64
5501   // Running on the real platform. Use the alignment as mandated by the local
5502   // environment.
5503   // Note: This will break if we ever start generating snapshots on one Mips
5504   // platform for another Mips platform with a different alignment.
5505   return base::OS::ActivationFrameAlignment();
5506 #else   // V8_HOST_ARCH_MIPS
5507   // If we are using the simulator then we should always align to the expected
5508   // alignment. As the simulator is used to generate snapshots we do not know
5509   // if the target platform will need alignment, so this is controlled from a
5510   // flag.
5511   return FLAG_sim_stack_alignment;
5512 #endif  // V8_HOST_ARCH_MIPS
5513 }
5514 
5515 void MacroAssembler::AssertStackIsAligned() {
5516   if (FLAG_debug_code) {
5517     ASM_CODE_COMMENT(this);
5518     const int frame_alignment = ActivationFrameAlignment();
5519     const int frame_alignment_mask = frame_alignment - 1;
5520 
5521     if (frame_alignment > kPointerSize) {
5522       Label alignment_as_expected;
5523       DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
5524       {
5525         UseScratchRegisterScope temps(this);
5526         Register scratch = temps.Acquire();
5527         andi(scratch, sp, frame_alignment_mask);
5528         Branch(&alignment_as_expected, eq, scratch, Operand(zero_reg));
5529       }
5530       // Don't use Check here, as it will call Runtime_Abort re-entering here.
5531       stop();
5532       bind(&alignment_as_expected);
5533     }
5534   }
5535 }
5536 
5537 void TurboAssembler::SmiUntag(Register dst, const MemOperand& src) {
5538   if (SmiValuesAre32Bits()) {
5539     Lw(dst, MemOperand(src.rm(), SmiWordOffset(src.offset())));
5540   } else {
5541     DCHECK(SmiValuesAre31Bits());
5542     Lw(dst, src);
5543     SmiUntag(dst);
5544   }
5545 }
5546 
5547 void TurboAssembler::JumpIfSmi(Register value, Label* smi_label,
5548                                BranchDelaySlot bd) {
5549   DCHECK_EQ(0, kSmiTag);
5550   UseScratchRegisterScope temps(this);
5551   Register scratch = temps.Acquire();
5552   andi(scratch, value, kSmiTagMask);
5553   Branch(bd, smi_label, eq, scratch, Operand(zero_reg));
5554 }
5555 
5556 void MacroAssembler::JumpIfNotSmi(Register value, Label* not_smi_label,
5557                                   BranchDelaySlot bd) {
5558   DCHECK_EQ(0, kSmiTag);
5559   UseScratchRegisterScope temps(this);
5560   Register scratch = temps.Acquire();
5561   andi(scratch, value, kSmiTagMask);
5562   Branch(bd, not_smi_label, ne, scratch, Operand(zero_reg));
5563 }
5564 
5565 void TurboAssembler::AssertNotSmi(Register object) {
5566   if (FLAG_debug_code) {
5567     ASM_CODE_COMMENT(this);
5568     STATIC_ASSERT(kSmiTag == 0);
5569     UseScratchRegisterScope temps(this);
5570     Register scratch = temps.Acquire();
5571     andi(scratch, object, kSmiTagMask);
5572     Check(ne, AbortReason::kOperandIsASmi, scratch, Operand(zero_reg));
5573   }
5574 }
5575 
5576 void TurboAssembler::AssertSmi(Register object) {
5577   if (FLAG_debug_code) {
5578     ASM_CODE_COMMENT(this);
5579     STATIC_ASSERT(kSmiTag == 0);
5580     UseScratchRegisterScope temps(this);
5581     Register scratch = temps.Acquire();
5582     andi(scratch, object, kSmiTagMask);
5583     Check(eq, AbortReason::kOperandIsASmi, scratch, Operand(zero_reg));
5584   }
5585 }
5586 
5587 void MacroAssembler::AssertConstructor(Register object) {
5588   if (FLAG_debug_code) {
5589     ASM_CODE_COMMENT(this);
5590     BlockTrampolinePoolScope block_trampoline_pool(this);
5591     STATIC_ASSERT(kSmiTag == 0);
5592     SmiTst(object, t8);
5593     Check(ne, AbortReason::kOperandIsASmiAndNotAConstructor, t8,
5594           Operand(zero_reg));
5595 
5596     LoadMap(t8, object);
5597     Lbu(t8, FieldMemOperand(t8, Map::kBitFieldOffset));
5598     And(t8, t8, Operand(Map::Bits1::IsConstructorBit::kMask));
5599     Check(ne, AbortReason::kOperandIsNotAConstructor, t8, Operand(zero_reg));
5600   }
5601 }
5602 
5603 void MacroAssembler::AssertFunction(Register object) {
5604   if (FLAG_debug_code) {
5605     ASM_CODE_COMMENT(this);
5606     BlockTrampolinePoolScope block_trampoline_pool(this);
5607     STATIC_ASSERT(kSmiTag == 0);
5608     SmiTst(object, t8);
5609     Check(ne, AbortReason::kOperandIsASmiAndNotAFunction, t8,
5610           Operand(zero_reg));
5611     push(object);
5612     LoadMap(object, object);
5613     GetInstanceTypeRange(object, object, FIRST_JS_FUNCTION_TYPE, t8);
5614     Check(ls, AbortReason::kOperandIsNotAFunction, t8,
5615           Operand(LAST_JS_FUNCTION_TYPE - FIRST_JS_FUNCTION_TYPE));
5616     pop(object);
5617   }
5618 }
5619 
5620 void MacroAssembler::AssertCallableFunction(Register object) {
5621   if (FLAG_debug_code) {
5622     ASM_CODE_COMMENT(this);
5623     BlockTrampolinePoolScope block_trampoline_pool(this);
5624     STATIC_ASSERT(kSmiTag == 0);
5625     SmiTst(object, t8);
5626     Check(ne, AbortReason::kOperandIsASmiAndNotAFunction, t8,
5627           Operand(zero_reg));
5628     push(object);
5629     LoadMap(object, object);
5630     GetInstanceTypeRange(object, object, FIRST_CALLABLE_JS_FUNCTION_TYPE, t8);
5631     Check(ls, AbortReason::kOperandIsNotACallableFunction, t8,
5632           Operand(LAST_CALLABLE_JS_FUNCTION_TYPE -
5633                   FIRST_CALLABLE_JS_FUNCTION_TYPE));
5634     pop(object);
5635   }
5636 }
5637 
5638 void MacroAssembler::AssertBoundFunction(Register object) {
5639   if (FLAG_debug_code) {
5640     ASM_CODE_COMMENT(this);
5641     BlockTrampolinePoolScope block_trampoline_pool(this);
5642     STATIC_ASSERT(kSmiTag == 0);
5643     SmiTst(object, t8);
5644     Check(ne, AbortReason::kOperandIsASmiAndNotABoundFunction, t8,
5645           Operand(zero_reg));
5646     GetObjectType(object, t8, t8);
5647     Check(eq, AbortReason::kOperandIsNotABoundFunction, t8,
5648           Operand(JS_BOUND_FUNCTION_TYPE));
5649   }
5650 }
5651 
5652 void MacroAssembler::AssertGeneratorObject(Register object) {
5653   if (!FLAG_debug_code) return;
5654   ASM_CODE_COMMENT(this);
5655   BlockTrampolinePoolScope block_trampoline_pool(this);
5656   STATIC_ASSERT(kSmiTag == 0);
5657   SmiTst(object, t8);
5658   Check(ne, AbortReason::kOperandIsASmiAndNotAGeneratorObject, t8,
5659         Operand(zero_reg));
5660 
5661   GetObjectType(object, t8, t8);
5662 
5663   Label done;
5664 
5665   // Check if JSGeneratorObject
5666   Branch(&done, eq, t8, Operand(JS_GENERATOR_OBJECT_TYPE));
5667 
5668   // Check if JSAsyncFunctionObject (See MacroAssembler::CompareInstanceType)
5669   Branch(&done, eq, t8, Operand(JS_ASYNC_FUNCTION_OBJECT_TYPE));
5670 
5671   // Check if JSAsyncGeneratorObject
5672   Branch(&done, eq, t8, Operand(JS_ASYNC_GENERATOR_OBJECT_TYPE));
5673 
5674   Abort(AbortReason::kOperandIsNotAGeneratorObject);
5675 
5676   bind(&done);
5677 }
5678 
5679 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
5680                                                      Register scratch) {
5681   if (FLAG_debug_code) {
5682     ASM_CODE_COMMENT(this);
5683     Label done_checking;
5684     AssertNotSmi(object);
5685     LoadRoot(scratch, RootIndex::kUndefinedValue);
5686     Branch(&done_checking, eq, object, Operand(scratch));
5687     GetObjectType(object, scratch, scratch);
5688     Assert(eq, AbortReason::kExpectedUndefinedOrCell, scratch,
5689            Operand(ALLOCATION_SITE_TYPE));
5690     bind(&done_checking);
5691   }
5692 }
5693 
5694 void TurboAssembler::Float32Max(FPURegister dst, FPURegister src1,
5695                                 FPURegister src2, Label* out_of_line) {
5696   ASM_CODE_COMMENT(this);
5697   if (src1 == src2) {
5698     Move_s(dst, src1);
5699     return;
5700   }
5701 
5702   // Check if one of operands is NaN.
5703   CompareIsNanF32(src1, src2);
5704   BranchTrueF(out_of_line);
5705 
5706   if (kArchVariant >= kMips64r6) {
5707     max_s(dst, src1, src2);
5708   } else {
5709     Label return_left, return_right, done;
5710 
5711     CompareF32(OLT, src1, src2);
5712     BranchTrueShortF(&return_right);
5713     CompareF32(OLT, src2, src1);
5714     BranchTrueShortF(&return_left);
5715 
5716     // Operands are equal, but check for +/-0.
5717     {
5718       BlockTrampolinePoolScope block_trampoline_pool(this);
5719       mfc1(t8, src1);
5720       dsll32(t8, t8, 0);
5721       Branch(&return_left, eq, t8, Operand(zero_reg));
5722       Branch(&return_right);
5723     }
5724 
5725     bind(&return_right);
5726     if (src2 != dst) {
5727       Move_s(dst, src2);
5728     }
5729     Branch(&done);
5730 
5731     bind(&return_left);
5732     if (src1 != dst) {
5733       Move_s(dst, src1);
5734     }
5735 
5736     bind(&done);
5737   }
5738 }
5739 
5740 void TurboAssembler::Float32MaxOutOfLine(FPURegister dst, FPURegister src1,
5741                                          FPURegister src2) {
5742   add_s(dst, src1, src2);
5743 }
5744 
5745 void TurboAssembler::Float32Min(FPURegister dst, FPURegister src1,
5746                                 FPURegister src2, Label* out_of_line) {
5747   ASM_CODE_COMMENT(this);
5748   if (src1 == src2) {
5749     Move_s(dst, src1);
5750     return;
5751   }
5752 
5753   // Check if one of operands is NaN.
5754   CompareIsNanF32(src1, src2);
5755   BranchTrueF(out_of_line);
5756 
5757   if (kArchVariant >= kMips64r6) {
5758     min_s(dst, src1, src2);
5759   } else {
5760     Label return_left, return_right, done;
5761 
5762     CompareF32(OLT, src1, src2);
5763     BranchTrueShortF(&return_left);
5764     CompareF32(OLT, src2, src1);
5765     BranchTrueShortF(&return_right);
5766 
5767     // Left equals right => check for -0.
5768     {
5769       BlockTrampolinePoolScope block_trampoline_pool(this);
5770       mfc1(t8, src1);
5771       dsll32(t8, t8, 0);
5772       Branch(&return_right, eq, t8, Operand(zero_reg));
5773       Branch(&return_left);
5774     }
5775 
5776     bind(&return_right);
5777     if (src2 != dst) {
5778       Move_s(dst, src2);
5779     }
5780     Branch(&done);
5781 
5782     bind(&return_left);
5783     if (src1 != dst) {
5784       Move_s(dst, src1);
5785     }
5786 
5787     bind(&done);
5788   }
5789 }
5790 
5791 void TurboAssembler::Float32MinOutOfLine(FPURegister dst, FPURegister src1,
5792                                          FPURegister src2) {
5793   add_s(dst, src1, src2);
5794 }
5795 
5796 void TurboAssembler::Float64Max(FPURegister dst, FPURegister src1,
5797                                 FPURegister src2, Label* out_of_line) {
5798   ASM_CODE_COMMENT(this);
5799   if (src1 == src2) {
5800     Move_d(dst, src1);
5801     return;
5802   }
5803 
5804   // Check if one of operands is NaN.
5805   CompareIsNanF64(src1, src2);
5806   BranchTrueF(out_of_line);
5807 
5808   if (kArchVariant >= kMips64r6) {
5809     max_d(dst, src1, src2);
5810   } else {
5811     Label return_left, return_right, done;
5812 
5813     CompareF64(OLT, src1, src2);
5814     BranchTrueShortF(&return_right);
5815     CompareF64(OLT, src2, src1);
5816     BranchTrueShortF(&return_left);
5817 
5818     // Left equals right => check for -0.
5819     {
5820       BlockTrampolinePoolScope block_trampoline_pool(this);
5821       dmfc1(t8, src1);
5822       Branch(&return_left, eq, t8, Operand(zero_reg));
5823       Branch(&return_right);
5824     }
5825 
5826     bind(&return_right);
5827     if (src2 != dst) {
5828       Move_d(dst, src2);
5829     }
5830     Branch(&done);
5831 
5832     bind(&return_left);
5833     if (src1 != dst) {
5834       Move_d(dst, src1);
5835     }
5836 
5837     bind(&done);
5838   }
5839 }
5840 
5841 void TurboAssembler::Float64MaxOutOfLine(FPURegister dst, FPURegister src1,
5842                                          FPURegister src2) {
5843   add_d(dst, src1, src2);
5844 }
5845 
5846 void TurboAssembler::Float64Min(FPURegister dst, FPURegister src1,
5847                                 FPURegister src2, Label* out_of_line) {
5848   ASM_CODE_COMMENT(this);
5849   if (src1 == src2) {
5850     Move_d(dst, src1);
5851     return;
5852   }
5853 
5854   // Check if one of operands is NaN.
5855   CompareIsNanF64(src1, src2);
5856   BranchTrueF(out_of_line);
5857 
5858   if (kArchVariant >= kMips64r6) {
5859     min_d(dst, src1, src2);
5860   } else {
5861     Label return_left, return_right, done;
5862 
5863     CompareF64(OLT, src1, src2);
5864     BranchTrueShortF(&return_left);
5865     CompareF64(OLT, src2, src1);
5866     BranchTrueShortF(&return_right);
5867 
5868     // Left equals right => check for -0.
5869     {
5870       BlockTrampolinePoolScope block_trampoline_pool(this);
5871       dmfc1(t8, src1);
5872       Branch(&return_right, eq, t8, Operand(zero_reg));
5873       Branch(&return_left);
5874     }
5875 
5876     bind(&return_right);
5877     if (src2 != dst) {
5878       Move_d(dst, src2);
5879     }
5880     Branch(&done);
5881 
5882     bind(&return_left);
5883     if (src1 != dst) {
5884       Move_d(dst, src1);
5885     }
5886 
5887     bind(&done);
5888   }
5889 }
5890 
5891 void TurboAssembler::Float64MinOutOfLine(FPURegister dst, FPURegister src1,
5892                                          FPURegister src2) {
5893   add_d(dst, src1, src2);
5894 }
5895 
5896 static const int kRegisterPassedArguments = 8;
5897 
5898 int TurboAssembler::CalculateStackPassedWords(int num_reg_arguments,
5899                                               int num_double_arguments) {
5900   int stack_passed_words = 0;
5901   num_reg_arguments += 2 * num_double_arguments;
5902 
5903   // O32: Up to four simple arguments are passed in registers a0..a3.
5904   // N64: Up to eight simple arguments are passed in registers a0..a7.
5905   if (num_reg_arguments > kRegisterPassedArguments) {
5906     stack_passed_words += num_reg_arguments - kRegisterPassedArguments;
5907   }
5908   stack_passed_words += kCArgSlotCount;
5909   return stack_passed_words;
5910 }
5911 
5912 void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
5913                                           int num_double_arguments,
5914                                           Register scratch) {
5915   ASM_CODE_COMMENT(this);
5916   int frame_alignment = ActivationFrameAlignment();
5917 
5918   // n64: Up to eight simple arguments in a0..a3, a4..a7, No argument slots.
5919   // O32: Up to four simple arguments are passed in registers a0..a3.
5920   // Those four arguments must have reserved argument slots on the stack for
5921   // mips, even though those argument slots are not normally used.
5922   // Both ABIs: Remaining arguments are pushed on the stack, above (higher
5923   // address than) the (O32) argument slots. (arg slot calculation handled by
5924   // CalculateStackPassedWords()).
5925   int stack_passed_arguments =
5926       CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
5927   if (frame_alignment > kPointerSize) {
5928     // Make stack end at alignment and make room for num_arguments - 4 words
5929     // and the original value of sp.
5930     mov(scratch, sp);
5931     Dsubu(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize));
5932     DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
5933     And(sp, sp, Operand(-frame_alignment));
5934     Sd(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
5935   } else {
5936     Dsubu(sp, sp, Operand(stack_passed_arguments * kPointerSize));
5937   }
5938 }
5939 
5940 void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
5941                                           Register scratch) {
5942   PrepareCallCFunction(num_reg_arguments, 0, scratch);
5943 }
5944 
5945 void TurboAssembler::CallCFunction(ExternalReference function,
5946                                    int num_reg_arguments,
5947                                    int num_double_arguments) {
5948   ASM_CODE_COMMENT(this);
5949   BlockTrampolinePoolScope block_trampoline_pool(this);
5950   li(t9, function);
5951   CallCFunctionHelper(t9, num_reg_arguments, num_double_arguments);
5952 }
5953 
5954 void TurboAssembler::CallCFunction(Register function, int num_reg_arguments,
5955                                    int num_double_arguments) {
5956   ASM_CODE_COMMENT(this);
5957   CallCFunctionHelper(function, num_reg_arguments, num_double_arguments);
5958 }
5959 
5960 void TurboAssembler::CallCFunction(ExternalReference function,
5961                                    int num_arguments) {
5962   CallCFunction(function, num_arguments, 0);
5963 }
5964 
5965 void TurboAssembler::CallCFunction(Register function, int num_arguments) {
5966   CallCFunction(function, num_arguments, 0);
5967 }
5968 
5969 void TurboAssembler::CallCFunctionHelper(Register function,
5970                                          int num_reg_arguments,
5971                                          int num_double_arguments) {
5972   DCHECK_LE(num_reg_arguments + num_double_arguments, kMaxCParameters);
5973   DCHECK(has_frame());
5974   // Make sure that the stack is aligned before calling a C function unless
5975   // running in the simulator. The simulator has its own alignment check which
5976   // provides more information.
5977   // The argument stots are presumed to have been set up by
5978   // PrepareCallCFunction. The C function must be called via t9, for mips ABI.
5979 
5980 #if V8_HOST_ARCH_MIPS || V8_HOST_ARCH_MIPS64
5981   if (FLAG_debug_code) {
5982     int frame_alignment = base::OS::ActivationFrameAlignment();
5983     int frame_alignment_mask = frame_alignment - 1;
5984     if (frame_alignment > kPointerSize) {
5985       DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
5986       Label alignment_as_expected;
5987       {
5988         UseScratchRegisterScope temps(this);
5989         Register scratch = temps.Acquire();
5990         And(scratch, sp, Operand(frame_alignment_mask));
5991         Branch(&alignment_as_expected, eq, scratch, Operand(zero_reg));
5992       }
5993       // Don't use Check here, as it will call Runtime_Abort possibly
5994       // re-entering here.
5995       stop();
5996       bind(&alignment_as_expected);
5997     }
5998   }
5999 #endif  // V8_HOST_ARCH_MIPS
6000 
6001   // Just call directly. The function called cannot cause a GC, or
6002   // allow preemption, so the return address in the link register
6003   // stays correct.
6004   {
6005     BlockTrampolinePoolScope block_trampoline_pool(this);
6006     if (function != t9) {
6007       mov(t9, function);
6008       function = t9;
6009     }
6010 
6011     // Save the frame pointer and PC so that the stack layout remains iterable,
6012     // even without an ExitFrame which normally exists between JS and C frames.
6013     // 't' registers are caller-saved so this is safe as a scratch register.
6014     Register pc_scratch = t1;
6015     Register scratch = t2;
6016     DCHECK(!AreAliased(pc_scratch, scratch, function));
6017 
6018     mov(scratch, ra);
6019     nal();
6020     mov(pc_scratch, ra);
6021     mov(ra, scratch);
6022 
6023     // See x64 code for reasoning about how to address the isolate data fields.
6024     if (root_array_available()) {
6025       Sd(pc_scratch, MemOperand(kRootRegister,
6026                                 IsolateData::fast_c_call_caller_pc_offset()));
6027       Sd(fp, MemOperand(kRootRegister,
6028                         IsolateData::fast_c_call_caller_fp_offset()));
6029     } else {
6030       DCHECK_NOT_NULL(isolate());
6031       li(scratch, ExternalReference::fast_c_call_caller_pc_address(isolate()));
6032       Sd(pc_scratch, MemOperand(scratch));
6033       li(scratch, ExternalReference::fast_c_call_caller_fp_address(isolate()));
6034       Sd(fp, MemOperand(scratch));
6035     }
6036 
6037     Call(function);
6038 
6039     // We don't unset the PC; the FP is the source of truth.
6040     if (root_array_available()) {
6041       Sd(zero_reg, MemOperand(kRootRegister,
6042                               IsolateData::fast_c_call_caller_fp_offset()));
6043     } else {
6044       DCHECK_NOT_NULL(isolate());
6045       li(scratch, ExternalReference::fast_c_call_caller_fp_address(isolate()));
6046       Sd(zero_reg, MemOperand(scratch));
6047     }
6048 
6049     int stack_passed_arguments =
6050         CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
6051 
6052     if (base::OS::ActivationFrameAlignment() > kPointerSize) {
6053       Ld(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
6054     } else {
6055       Daddu(sp, sp, Operand(stack_passed_arguments * kPointerSize));
6056     }
6057 
6058     set_pc_for_safepoint();
6059   }
6060 }
6061 
6062 #undef BRANCH_ARGS_CHECK
6063 
6064 void TurboAssembler::CheckPageFlag(Register object, Register scratch, int mask,
6065                                    Condition cc, Label* condition_met) {
6066   ASM_CODE_COMMENT(this);
6067   And(scratch, object, Operand(~kPageAlignmentMask));
6068   Ld(scratch, MemOperand(scratch, BasicMemoryChunk::kFlagsOffset));
6069   And(scratch, scratch, Operand(mask));
6070   Branch(condition_met, cc, scratch, Operand(zero_reg));
6071 }
6072 
6073 Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2, Register reg3,
6074                                    Register reg4, Register reg5,
6075                                    Register reg6) {
6076   RegList regs = {reg1, reg2, reg3, reg4, reg5, reg6};
6077 
6078   const RegisterConfiguration* config = RegisterConfiguration::Default();
6079   for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
6080     int code = config->GetAllocatableGeneralCode(i);
6081     Register candidate = Register::from_code(code);
6082     if (regs.has(candidate)) continue;
6083     return candidate;
6084   }
6085   UNREACHABLE();
6086 }
6087 
6088 void TurboAssembler::ComputeCodeStartAddress(Register dst) {
6089   // This push on ra and the pop below together ensure that we restore the
6090   // register ra, which is needed while computing the code start address.
6091   push(ra);
6092 
6093   // The nal instruction puts the address of the current instruction into
6094   // the return address (ra) register, which we can use later on.
6095   if (kArchVariant == kMips64r6) {
6096     addiupc(ra, 1);
6097   } else {
6098     nal();
6099     nop();
6100   }
6101   int pc = pc_offset();
6102   li(dst, Operand(pc));
6103   Dsubu(dst, ra, dst);
6104 
6105   pop(ra);  // Restore ra
6106 }
6107 
6108 void TurboAssembler::CallForDeoptimization(Builtin target, int, Label* exit,
6109                                            DeoptimizeKind kind, Label* ret,
6110                                            Label*) {
6111   ASM_CODE_COMMENT(this);
6112   BlockTrampolinePoolScope block_trampoline_pool(this);
6113   Ld(t9,
6114      MemOperand(kRootRegister, IsolateData::BuiltinEntrySlotOffset(target)));
6115   Call(t9);
6116   DCHECK_EQ(SizeOfCodeGeneratedSince(exit),
6117             (kind == DeoptimizeKind::kLazy) ? Deoptimizer::kLazyDeoptExitSize
6118                                             : Deoptimizer::kEagerDeoptExitSize);
6119 }
6120 
6121 void TurboAssembler::LoadCodeObjectEntry(Register destination,
6122                                          Register code_object) {
6123   ASM_CODE_COMMENT(this);
6124   // Code objects are called differently depending on whether we are generating
6125   // builtin code (which will later be embedded into the binary) or compiling
6126   // user JS code at runtime.
6127   // * Builtin code runs in --jitless mode and thus must not call into on-heap
6128   //   Code targets. Instead, we dispatch through the builtins entry table.
6129   // * Codegen at runtime does not have this restriction and we can use the
6130   //   shorter, branchless instruction sequence. The assumption here is that
6131   //   targets are usually generated code and not builtin Code objects.
6132   if (options().isolate_independent_code) {
6133     DCHECK(root_array_available());
6134     Label if_code_is_off_heap, out;
6135 
6136     Register scratch = kScratchReg;
6137     DCHECK(!AreAliased(destination, scratch));
6138     DCHECK(!AreAliased(code_object, scratch));
6139 
6140     // Check whether the Code object is an off-heap trampoline. If so, call its
6141     // (off-heap) entry point directly without going through the (on-heap)
6142     // trampoline.  Otherwise, just call the Code object as always.
6143     Lw(scratch, FieldMemOperand(code_object, Code::kFlagsOffset));
6144     And(scratch, scratch, Operand(Code::IsOffHeapTrampoline::kMask));
6145     Branch(&if_code_is_off_heap, ne, scratch, Operand(zero_reg));
6146 
6147     // Not an off-heap trampoline object, the entry point is at
6148     // Code::raw_instruction_start().
6149     Daddu(destination, code_object, Code::kHeaderSize - kHeapObjectTag);
6150     Branch(&out);
6151 
6152     // An off-heap trampoline, the entry point is loaded from the builtin entry
6153     // table.
6154     bind(&if_code_is_off_heap);
6155     Lw(scratch, FieldMemOperand(code_object, Code::kBuiltinIndexOffset));
6156     Dlsa(destination, kRootRegister, scratch, kSystemPointerSizeLog2);
6157     Ld(destination,
6158        MemOperand(destination, IsolateData::builtin_entry_table_offset()));
6159 
6160     bind(&out);
6161   } else {
6162     Daddu(destination, code_object, Code::kHeaderSize - kHeapObjectTag);
6163   }
6164 }
6165 
6166 void TurboAssembler::CallCodeObject(Register code_object) {
6167   ASM_CODE_COMMENT(this);
6168   LoadCodeObjectEntry(code_object, code_object);
6169   Call(code_object);
6170 }
6171 
6172 void TurboAssembler::JumpCodeObject(Register code_object, JumpMode jump_mode) {
6173   ASM_CODE_COMMENT(this);
6174   DCHECK_EQ(JumpMode::kJump, jump_mode);
6175   LoadCodeObjectEntry(code_object, code_object);
6176   Jump(code_object);
6177 }
6178 
6179 }  // namespace internal
6180 }  // namespace v8
6181 
6182 #endif  // V8_TARGET_ARCH_MIPS64
6183