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
38namespace v8 {
39namespace internal {
40
41static 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
49int 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
65int 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
82int 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
99void TurboAssembler::LoadRoot(Register destination, RootIndex index) {
100  Ld(destination, MemOperand(s6, RootRegisterOffsetForRootIndex(index)));
101}
102
103void 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
110void 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
120void 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.
135void 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
179void TurboAssembler::MaybeSaveRegisters(RegList registers) {
180  if (registers.is_empty()) return;
181  MultiPush(registers);
182}
183
184void TurboAssembler::MaybeRestoreRegisters(RegList registers) {
185  if (registers.is_empty()) return;
186  MultiPop(registers);
187}
188
189void 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
213void 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
237void 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.
271void 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
338void 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
355void 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
372void 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
398void 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
426void 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
439void 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
462void 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
485void 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
508void 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
531void 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
544void 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
557void 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
570void 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
583void 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
596void 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
619void 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
642void 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
665void 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
678void 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
706void 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
719void 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
742void 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
755void 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
778void 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
806void 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
834void 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
851void 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
868void 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
885void 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
898void TurboAssembler::Neg(Register rs, const Operand& rt) {
899  dsubu(rs, zero_reg, rt.rm());
900}
901
902void 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
920void 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
944void 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
959void 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
974void TurboAssembler::Sge(Register rd, Register rs, const Operand& rt) {
975  Slt(rd, rs, rt);
976  xori(rd, rd, 1);
977}
978
979void TurboAssembler::Sgeu(Register rd, Register rs, const Operand& rt) {
980  Sltu(rd, rs, rt);
981  xori(rd, rd, 1);
982}
983
984void 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
998void 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
1012void 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
1024void 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
1038void MacroAssembler::Pref(int32_t hint, const MemOperand& rs) {
1039  pref(hint, rs);
1040}
1041
1042void 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
1055void 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
1071void 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
1082void 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
1096void 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
1112void 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
1125void 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
1149void 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
1159void 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
1176void 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
1210void 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
1244void 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
1273void 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.
1300void 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
1308void 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.
1325void 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
1332void 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
1343void 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
1354void 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
1366void 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
1378void TurboAssembler::Lb(Register rd, const MemOperand& rs) {
1379  MemOperand source = rs;
1380  AdjustBaseAndOffset(&source);
1381  lb(rd, source);
1382}
1383
1384void TurboAssembler::Lbu(Register rd, const MemOperand& rs) {
1385  MemOperand source = rs;
1386  AdjustBaseAndOffset(&source);
1387  lbu(rd, source);
1388}
1389
1390void TurboAssembler::Sb(Register rd, const MemOperand& rs) {
1391  MemOperand source = rs;
1392  AdjustBaseAndOffset(&source);
1393  sb(rd, source);
1394}
1395
1396void TurboAssembler::Lh(Register rd, const MemOperand& rs) {
1397  MemOperand source = rs;
1398  AdjustBaseAndOffset(&source);
1399  lh(rd, source);
1400}
1401
1402void TurboAssembler::Lhu(Register rd, const MemOperand& rs) {
1403  MemOperand source = rs;
1404  AdjustBaseAndOffset(&source);
1405  lhu(rd, source);
1406}
1407
1408void TurboAssembler::Sh(Register rd, const MemOperand& rs) {
1409  MemOperand source = rs;
1410  AdjustBaseAndOffset(&source);
1411  sh(rd, source);
1412}
1413
1414void TurboAssembler::Lw(Register rd, const MemOperand& rs) {
1415  MemOperand source = rs;
1416  AdjustBaseAndOffset(&source);
1417  lw(rd, source);
1418}
1419
1420void TurboAssembler::Lwu(Register rd, const MemOperand& rs) {
1421  MemOperand source = rs;
1422  AdjustBaseAndOffset(&source);
1423  lwu(rd, source);
1424}
1425
1426void TurboAssembler::Sw(Register rd, const MemOperand& rs) {
1427  MemOperand source = rs;
1428  AdjustBaseAndOffset(&source);
1429  sw(rd, source);
1430}
1431
1432void TurboAssembler::Ld(Register rd, const MemOperand& rs) {
1433  MemOperand source = rs;
1434  AdjustBaseAndOffset(&source);
1435  ld(rd, source);
1436}
1437
1438void TurboAssembler::Sd(Register rd, const MemOperand& rs) {
1439  MemOperand source = rs;
1440  AdjustBaseAndOffset(&source);
1441  sd(rd, source);
1442}
1443
1444void TurboAssembler::Lwc1(FPURegister fd, const MemOperand& src) {
1445  MemOperand tmp = src;
1446  AdjustBaseAndOffset(&tmp);
1447  lwc1(fd, tmp);
1448}
1449
1450void TurboAssembler::Swc1(FPURegister fs, const MemOperand& src) {
1451  MemOperand tmp = src;
1452  AdjustBaseAndOffset(&tmp);
1453  swc1(fs, tmp);
1454}
1455
1456void TurboAssembler::Ldc1(FPURegister fd, const MemOperand& src) {
1457  MemOperand tmp = src;
1458  AdjustBaseAndOffset(&tmp);
1459  ldc1(fd, tmp);
1460}
1461
1462void TurboAssembler::Sdc1(FPURegister fs, const MemOperand& src) {
1463  MemOperand tmp = src;
1464  AdjustBaseAndOffset(&tmp);
1465  sdc1(fs, tmp);
1466}
1467
1468void 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
1482void 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
1496void 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
1510void 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
1524void 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
1535void 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
1546void TurboAssembler::li(Register dst, const StringConstantBase* string,
1547                        LiFlags mode) {
1548  li(dst, Operand::EmbeddedStringConstant(string), mode);
1549}
1550
1551static 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
1560void 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
1573static 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
1584int 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.
1679void 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
1857void 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
1919void 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
1932void 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
1944void 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
1957void 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
1969void 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
1982void 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
1994void 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
2001void 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
2014void 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
2022void 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
2035void 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
2057void 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
2069void 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
2094void 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
2119void 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
2126void 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
2139void 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
2146void 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
2174void 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
2181void 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
2193void 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
2200void 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
2228void MacroAssembler::Round_l_d(FPURegister fd, FPURegister fs) {
2229  round_l_d(fd, fs);
2230}
2231
2232void MacroAssembler::Floor_l_d(FPURegister fd, FPURegister fs) {
2233  floor_l_d(fd, fs);
2234}
2235
2236void MacroAssembler::Ceil_l_d(FPURegister fd, FPURegister fs) {
2237  ceil_l_d(fd, fs);
2238}
2239
2240void MacroAssembler::Trunc_l_d(FPURegister fd, FPURegister fs) {
2241  trunc_l_d(fd, fs);
2242}
2243
2244void 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
2260void 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
2267void 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
2274void 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
2281void 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
2288void MacroAssembler::Trunc_w_d(FPURegister fd, FPURegister fs) {
2289  trunc_w_d(fd, fs);
2290}
2291
2292void MacroAssembler::Round_w_d(FPURegister fd, FPURegister fs) {
2293  round_w_d(fd, fs);
2294}
2295
2296void MacroAssembler::Floor_w_d(FPURegister fd, FPURegister fs) {
2297  floor_w_d(fd, fs);
2298}
2299
2300void MacroAssembler::Ceil_w_d(FPURegister fd, FPURegister fs) {
2301  ceil_w_d(fd, fs);
2302}
2303
2304void 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
2340void 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
2375void 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
2430void 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
2489template <typename RoundFunc>
2490void 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
2522void 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
2529void 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
2536void 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
2543void 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
2550template <typename RoundFunc>
2551void 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
2586void 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
2593void 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
2600void 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
2607void 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
2614void 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
2640void 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
2684void 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
2698void 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
2713void 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
2738void 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
2758void 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
2774void 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
2790void 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
2797void 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
2804void 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
2811void 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
2818void 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
2829void TurboAssembler::CompareIsNanF(SecondaryField sizeField, FPURegister cmp1,
2830                                   FPURegister cmp2) {
2831  CompareF(sizeField, UN, cmp1, cmp2);
2832}
2833
2834void 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
2845void 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
2856void 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
2869void 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
2882void 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
2904void 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
2961void 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
2970void 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
2977void 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
3010void 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
3021void 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
3032void 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
3124void 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
3133void 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
3142void 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
3151void 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
3160void TurboAssembler::Movt(Register rd, Register rs, uint16_t cc) {
3161  movt(rd, rs, cc);
3162}
3163
3164void TurboAssembler::Movf(Register rd, Register rs, uint16_t cc) {
3165  movf(rd, rs, cc);
3166}
3167
3168void TurboAssembler::Clz(Register rd, Register rs) { clz(rd, rs); }
3169
3170void TurboAssembler::Dclz(Register rd, Register rs) { dclz(rd, rs); }
3171
3172void 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
3198void 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
3224void 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
3276void 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
3306void 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
3326void 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
3364void TurboAssembler::Branch(int32_t offset, BranchDelaySlot bdslot) {
3365  DCHECK_EQ(kArchVariant, kMips64r6 ? is_int26(offset) : is_int16(offset));
3366  BranchShort(offset, bdslot);
3367}
3368
3369void 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
3376void 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
3392void 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
3423void 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
3431void 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
3441void 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
3447void 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
3457void 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
3465int32_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
3474Register 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
3487bool 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
3494bool 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
3502bool 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
3715bool 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
3852bool 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
3875void 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
3880void TurboAssembler::BranchShort(Label* L, Condition cond, Register rs,
3881                                 const Operand& rt, BranchDelaySlot bdslot) {
3882  BranchShortCheck(0, L, cond, rs, rt, bdslot);
3883}
3884
3885void TurboAssembler::BranchAndLink(int32_t offset, BranchDelaySlot bdslot) {
3886  BranchAndLinkShort(offset, bdslot);
3887}
3888
3889void 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
3896void 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
3912void 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
3935void 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
3945void 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
3951void 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
3962void 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
3970bool 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.
4112bool 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
4202bool 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
4226void 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
4236void TurboAssembler::LoadRootRelative(Register destination, int32_t offset) {
4237  Ld(destination, MemOperand(kRootRegister, offset));
4238}
4239
4240void 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
4249void 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
4273void 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
4290void 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
4296void 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
4323void 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.
4329void 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
4354void 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
4368void 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
4375void 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
4403void 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}
4415void TurboAssembler::LoadEntryFromBuiltin(Builtin builtin,
4416                                          Register destination) {
4417  Ld(destination, EntryFromBuiltinAsOperand(builtin));
4418}
4419MemOperand TurboAssembler::EntryFromBuiltinAsOperand(Builtin builtin) {
4420  DCHECK(root_array_available());
4421  return MemOperand(kRootRegister,
4422                    IsolateData::BuiltinEntrySlotOffset(builtin));
4423}
4424
4425void TurboAssembler::CallBuiltinByIndex(Register builtin_index) {
4426  ASM_CODE_COMMENT(this);
4427  LoadEntryFromBuiltinIndex(builtin_index);
4428  Call(builtin_index);
4429}
4430void TurboAssembler::CallBuiltin(Builtin builtin) {
4431  RecordCommentForOffHeapTrampoline(builtin);
4432  Call(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET);
4433  RecordComment("]");
4434}
4435
4436void 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
4456void 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
4498void TurboAssembler::Ret(Condition cond, Register rs, const Operand& rt,
4499                         BranchDelaySlot bd) {
4500  Jump(ra, cond, rs, rt, bd);
4501}
4502
4503void 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
4527void 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
4546void 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
4566void 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
4590void 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
4606void 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
4622void 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
4638void 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
4657void 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
4669void TurboAssembler::Call(Label* target) { BranchAndLink(target); }
4670
4671void TurboAssembler::LoadAddress(Register dst, Label* target) {
4672  uint64_t address = jump_address(target);
4673  li(dst, address);
4674}
4675
4676void TurboAssembler::Push(Smi smi) {
4677  UseScratchRegisterScope temps(this);
4678  Register scratch = temps.Acquire();
4679  li(scratch, Operand(smi));
4680  push(scratch);
4681}
4682
4683void TurboAssembler::Push(Handle<HeapObject> handle) {
4684  UseScratchRegisterScope temps(this);
4685  Register scratch = temps.Acquire();
4686  li(scratch, Operand(handle));
4687  push(scratch);
4688}
4689
4690void 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
4720void 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
4737void 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
4750void TurboAssembler::FPUCanonicalizeNaN(const DoubleRegister dst,
4751                                        const DoubleRegister src) {
4752  sub_d(dst, src, kDoubleRegZero);
4753}
4754
4755void 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
4767void 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
4779void 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
4791void 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
4803void 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
4829void 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
4845void 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
4863void 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
4935void 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
4977void 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
5018void 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
5040void 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
5061void MacroAssembler::GetObjectType(Register object, Register map,
5062                                   Register type_reg) {
5063  LoadMap(map, object);
5064  Lhu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
5065}
5066
5067void 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
5077void 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
5108void 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
5139void 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
5169void 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
5190void 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
5200void 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
5209void MacroAssembler::JumpToOffHeapInstructionStream(Address entry) {
5210  li(kOffHeapTrampolineRegister, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
5211  Jump(kOffHeapTrampolineRegister);
5212}
5213
5214void 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
5221void 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
5237void 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
5256void TurboAssembler::Trap() { stop(); }
5257void TurboAssembler::DebugBreak() { stop(); }
5258
5259void TurboAssembler::Assert(Condition cc, AbortReason reason, Register rs,
5260                            Operand rt) {
5261  if (FLAG_debug_code) Check(cc, reason, rs, rt);
5262}
5263
5264void 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
5273void 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
5324void TurboAssembler::LoadMap(Register destination, Register object) {
5325  Ld(destination, FieldMemOperand(object, HeapObject::kMapOffset));
5326}
5327
5328void 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
5335void 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
5342void TurboAssembler::Prologue() { PushStandardFrame(a1); }
5343
5344void 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
5358void 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
5365void 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
5444void 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
5499int 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
5515void 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
5537void 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
5547void 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
5556void 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
5565void 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
5576void 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
5587void 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
5603void 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
5620void 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
5638void 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
5652void 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
5679void 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
5694void 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
5740void TurboAssembler::Float32MaxOutOfLine(FPURegister dst, FPURegister src1,
5741                                         FPURegister src2) {
5742  add_s(dst, src1, src2);
5743}
5744
5745void 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
5791void TurboAssembler::Float32MinOutOfLine(FPURegister dst, FPURegister src1,
5792                                         FPURegister src2) {
5793  add_s(dst, src1, src2);
5794}
5795
5796void 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
5841void TurboAssembler::Float64MaxOutOfLine(FPURegister dst, FPURegister src1,
5842                                         FPURegister src2) {
5843  add_d(dst, src1, src2);
5844}
5845
5846void 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
5891void TurboAssembler::Float64MinOutOfLine(FPURegister dst, FPURegister src1,
5892                                         FPURegister src2) {
5893  add_d(dst, src1, src2);
5894}
5895
5896static const int kRegisterPassedArguments = 8;
5897
5898int 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
5912void 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
5940void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
5941                                          Register scratch) {
5942  PrepareCallCFunction(num_reg_arguments, 0, scratch);
5943}
5944
5945void 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
5954void 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
5960void TurboAssembler::CallCFunction(ExternalReference function,
5961                                   int num_arguments) {
5962  CallCFunction(function, num_arguments, 0);
5963}
5964
5965void TurboAssembler::CallCFunction(Register function, int num_arguments) {
5966  CallCFunction(function, num_arguments, 0);
5967}
5968
5969void 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
6064void 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
6073Register 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
6088void 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
6108void 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
6121void 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
6166void TurboAssembler::CallCodeObject(Register code_object) {
6167  ASM_CODE_COMMENT(this);
6168  LoadCodeObjectEntry(code_object, code_object);
6169  Call(code_object);
6170}
6171
6172void 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