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