• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <limits.h>  // For LONG_MIN, LONG_MAX.
6 
7 #if V8_TARGET_ARCH_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 
MacroAssembler(Isolate * isolate,const AssemblerOptions & options,void * buffer,int size,CodeObjectRequired create_code_object)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 
IsZero(const Operand & rt)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 
RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,Register exclusion1,Register exclusion2,Register exclusion3) const52 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 
PushCallerSaved(SaveFPRegsMode fp_mode,Register exclusion1,Register exclusion2,Register exclusion3)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 
PopCallerSaved(SaveFPRegsMode fp_mode,Register exclusion1,Register exclusion2,Register exclusion3)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 
LoadRoot(Register destination,Heap::RootListIndex index)130 void TurboAssembler::LoadRoot(Register destination, Heap::RootListIndex index) {
131   lw(destination, MemOperand(kRootRegister, RootRegisterOffset(index)));
132 }
133 
LoadRoot(Register destination,Heap::RootListIndex index,Condition cond,Register src1,const Operand & src2)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 
PushCommonFrame(Register marker_reg)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 
PushStandardFrame(Register function_reg)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.
PushSafepointRegisters()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 
PopSafepointRegisters()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 
SafepointRegisterStackIndex(int reg_code)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.
RecordWriteField(Register object,int offset,Register value,Register dst,RAStatus ra_status,SaveFPRegsMode save_fp,RememberedSetAction remembered_set_action,SmiCheck smi_check)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 
SaveRegisters(RegList registers)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 
RestoreRegisters(RegList registers)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 
CallRecordWriteStub(Register object,Register address,RememberedSetAction remembered_set_action,SaveFPRegsMode fp_mode)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.
RecordWrite(Register object,Register address,Register value,RAStatus ra_status,SaveFPRegsMode fp_mode,RememberedSetAction remembered_set_action,SmiCheck smi_check)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 
Addu(Register rd,Register rs,const Operand & rt)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 
Subu(Register rd,Register rs,const Operand & rt)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 
Mul(Register rd,Register rs,const Operand & rt)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 
Mul(Register rd_hi,Register rd_lo,Register rs,const Operand & rt)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 
Mulu(Register rd_hi,Register rd_lo,Register rs,const Operand & rt)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 
Mulh(Register rd,Register rs,const Operand & rt)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 
Mult(Register rs,const Operand & rt)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 
Mulhu(Register rd,Register rs,const Operand & rt)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 
Multu(Register rs,const Operand & rt)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 
Div(Register rs,const Operand & rt)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 
Div(Register rem,Register res,Register rs,const Operand & rt)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 
Div(Register res,Register rs,const Operand & rt)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 
Mod(Register rd,Register rs,const Operand & rt)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 
Modu(Register rd,Register rs,const Operand & rt)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 
Divu(Register rs,const Operand & rt)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 
Divu(Register res,Register rs,const Operand & rt)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 
And(Register rd,Register rs,const Operand & rt)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 
Or(Register rd,Register rs,const Operand & rt)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 
Xor(Register rd,Register rs,const Operand & rt)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 
Nor(Register rd,Register rs,const Operand & rt)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 
Neg(Register rs,const Operand & rt)792 void TurboAssembler::Neg(Register rs, const Operand& rt) {
793   subu(rs, zero_reg, rt.rm());
794 }
795 
Slt(Register rd,Register rs,const Operand & rt)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 
Sltu(Register rd,Register rs,const Operand & rt)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 
Sle(Register rd,Register rs,const Operand & rt)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 
Sleu(Register rd,Register rs,const Operand & rt)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 
Sge(Register rd,Register rs,const Operand & rt)868 void TurboAssembler::Sge(Register rd, Register rs, const Operand& rt) {
869   Slt(rd, rs, rt);
870   xori(rd, rd, 1);
871 }
872 
Sgeu(Register rd,Register rs,const Operand & rt)873 void TurboAssembler::Sgeu(Register rd, Register rs, const Operand& rt) {
874   Sltu(rd, rs, rt);
875   xori(rd, rd, 1);
876 }
877 
Sgt(Register rd,Register rs,const Operand & rt)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 
Sgtu(Register rd,Register rs,const Operand & rt)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 
Ror(Register rd,Register rs,const Operand & rt)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 
Pref(int32_t hint,const MemOperand & rs)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 
Lsa(Register rd,Register rt,Register rs,uint8_t sa,Register scratch)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 
Bovc(Register rs,Register rt,Label * L)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 
Bnvc(Register rs,Register rt,Label * L)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
ByteSwapSigned(Register dest,Register src,int operand_size)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 
ByteSwapUnsigned(Register dest,Register src,int operand_size)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 
Ulw(Register rd,const MemOperand & rs)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 
Usw(Register rd,const MemOperand & rs)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 
Ulh(Register rd,const MemOperand & rs)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 
Ulhu(Register rd,const MemOperand & rs)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 
Ush(Register rd,const MemOperand & rs,Register scratch)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 
Ulwc1(FPURegister fd,const MemOperand & rs,Register scratch)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 
Uswc1(FPURegister fd,const MemOperand & rs,Register scratch)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 
Uldc1(FPURegister fd,const MemOperand & rs,Register scratch)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 
Usdc1(FPURegister fd,const MemOperand & rs,Register scratch)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 
Ldc1(FPURegister fd,const MemOperand & src)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 
Sdc1(FPURegister fd,const MemOperand & src)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 
Ll(Register rd,const MemOperand & rs)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 
Sc(Register rd,const MemOperand & rs)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 
li(Register dst,Handle<HeapObject> value,LiFlags mode)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 
li(Register dst,ExternalReference value,LiFlags mode)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 
li(Register rd,Operand j,LiFlags mode)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 
MultiPush(RegList regs)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 
MultiPop(RegList regs)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 
MultiPushFPU(RegList regs)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 
MultiPopFPU(RegList regs)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 
AddPair(Register dst_low,Register dst_high,Register left_low,Register left_high,Register right_low,Register right_high,Register scratch1,Register scratch2)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 
SubPair(Register dst_low,Register dst_high,Register left_low,Register left_high,Register right_low,Register right_high,Register scratch1,Register scratch2)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 
MulPair(Register dst_low,Register dst_high,Register left_low,Register left_high,Register right_low,Register right_high,Register scratch1,Register scratch2)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 
ShlPair(Register dst_low,Register dst_high,Register src_low,Register src_high,Register shift,Register scratch1,Register scratch2)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 
ShlPair(Register dst_low,Register dst_high,Register src_low,Register src_high,uint32_t shift,Register scratch)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 
ShrPair(Register dst_low,Register dst_high,Register src_low,Register src_high,Register shift,Register scratch1,Register scratch2)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 
ShrPair(Register dst_low,Register dst_high,Register src_low,Register src_high,uint32_t shift,Register scratch)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 
SarPair(Register dst_low,Register dst_high,Register src_low,Register src_high,Register shift,Register scratch1,Register scratch2)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 
SarPair(Register dst_low,Register dst_high,Register src_low,Register src_high,uint32_t shift,Register scratch)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 
Ext(Register rt,Register rs,uint16_t pos,uint16_t size)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 
Ins(Register rt,Register rs,uint16_t pos,uint16_t size)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 
ExtractBits(Register dest,Register source,Register pos,int size,bool sign_extend)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 
InsertBits(Register dest,Register source,Register pos,int size)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 
Seb(Register rd,Register rt)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 
Seh(Register rd,Register rt)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 
Neg_s(FPURegister fd,FPURegister fs)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 
Neg_d(FPURegister fd,FPURegister fs)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 
Cvt_d_uw(FPURegister fd,Register rs,FPURegister scratch)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 
Trunc_uw_d(FPURegister fd,FPURegister fs,FPURegister scratch)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 
Trunc_uw_s(FPURegister fd,FPURegister fs,FPURegister scratch)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 
Trunc_w_d(FPURegister fd,FPURegister fs)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 
Round_w_d(FPURegister fd,FPURegister fs)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 
Floor_w_d(FPURegister fd,FPURegister fs)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 
Ceil_w_d(FPURegister fd,FPURegister fs)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 
Trunc_uw_d(Register rd,FPURegister fs,FPURegister scratch)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 
Trunc_uw_s(Register rd,FPURegister fs,FPURegister scratch)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>
RoundDouble(FPURegister dst,FPURegister src,FPURoundingMode mode,RoundFunc round)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 
Floor_d_d(FPURegister dst,FPURegister src)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 
Ceil_d_d(FPURegister dst,FPURegister src)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 
Trunc_d_d(FPURegister dst,FPURegister src)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 
Round_d_d(FPURegister dst,FPURegister src)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>
RoundFloat(FPURegister dst,FPURegister src,FPURoundingMode mode,RoundFunc round)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 
Floor_s_s(FPURegister dst,FPURegister src)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 
Ceil_s_s(FPURegister dst,FPURegister src)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 
Trunc_s_s(FPURegister dst,FPURegister src)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 
Round_s_s(FPURegister dst,FPURegister src)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 
Mthc1(Register rt,FPURegister fs)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 
Mfhc1(Register rt,FPURegister fs)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 
Madd_s(FPURegister fd,FPURegister fr,FPURegister fs,FPURegister ft,FPURegister scratch)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 
Madd_d(FPURegister fd,FPURegister fr,FPURegister fs,FPURegister ft,FPURegister scratch)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 
Msub_s(FPURegister fd,FPURegister fr,FPURegister fs,FPURegister ft,FPURegister scratch)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 
Msub_d(FPURegister fd,FPURegister fr,FPURegister fs,FPURegister ft,FPURegister scratch)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 
CompareF(SecondaryField sizeField,FPUCondition cc,FPURegister cmp1,FPURegister cmp2)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 
CompareIsNanF(SecondaryField sizeField,FPURegister cmp1,FPURegister cmp2)2146 void TurboAssembler::CompareIsNanF(SecondaryField sizeField, FPURegister cmp1,
2147                                    FPURegister cmp2) {
2148   CompareF(sizeField, UN, cmp1, cmp2);
2149 }
2150 
BranchTrueShortF(Label * target,BranchDelaySlot bd)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 
BranchFalseShortF(Label * target,BranchDelaySlot bd)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 
BranchTrueF(Label * target,BranchDelaySlot bd)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 
BranchFalseF(Label * target,BranchDelaySlot bd)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 
BranchMSA(Label * target,MSABranchDF df,MSABranchCondition cond,MSARegister wt,BranchDelaySlot bd)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 
BranchShortMSA(MSABranchDF df,Label * target,MSABranchCondition cond,MSARegister wt,BranchDelaySlot bd)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 
FmoveLow(FPURegister dst,Register src_low)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 
Move(FPURegister dst,uint32_t src)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 
Move(FPURegister dst,uint64_t src)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 
LoadZeroOnCondition(Register rd,Register rs,const Operand & rt,Condition cond)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 
LoadZeroIfConditionNotZero(Register dest,Register condition)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 
LoadZeroIfConditionZero(Register dest,Register condition)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 
LoadZeroIfFPUCondition(Register dest)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 
LoadZeroIfNotFPUCondition(Register dest)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 
Movz(Register rd,Register rs,Register rt)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 
Movn(Register rd,Register rs,Register rt)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 
Movt(Register rd,Register rs,uint16_t cc)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 
Movf(Register rd,Register rs,uint16_t cc)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 
Clz(Register rd,Register rs)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 
Ctz(Register rd,Register rs)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 
Popcnt(Register rd,Register rs)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 
EmitFPUTruncate(FPURoundingMode rounding_mode,Register result,DoubleRegister double_input,Register scratch,DoubleRegister double_scratch,Register except_flag,CheckForInexactConversion check_inexact)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 
TryInlineTruncateDoubleToI(Register result,DoubleRegister double_input,Label * done)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 
TruncateDoubleToI(Isolate * isolate,Zone * zone,Register result,DoubleRegister double_input,StubCallMode stub_mode)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 
Branch(int32_t offset,BranchDelaySlot bdslot)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 
Branch(int32_t offset,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bdslot)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 
Branch(Label * L,BranchDelaySlot bdslot)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 
Branch(Label * L,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bdslot)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 
Branch(Label * L,Condition cond,Register rs,Heap::RootListIndex index,BranchDelaySlot bdslot)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 
BranchShortHelper(int16_t offset,Label * L,BranchDelaySlot bdslot)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 
BranchShortHelperR6(int32_t offset,Label * L)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 
BranchShort(int32_t offset,BranchDelaySlot bdslot)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 
BranchShort(Label * L,BranchDelaySlot bdslot)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 
GetOffset(int32_t offset,Label * L,OffsetSize bits)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 
GetRtAsRegisterHelper(const Operand & rt,Register scratch)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 
CalculateOffset(Label * L,int32_t & offset,OffsetSize bits)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 
CalculateOffset(Label * L,int32_t & offset,OffsetSize bits,Register & scratch,const Operand & rt)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 
BranchShortHelperR6(int32_t offset,Label * L,Condition cond,Register rs,const Operand & rt)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 
BranchShortHelper(int16_t offset,Label * L,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bdslot)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 
BranchShortCheck(int32_t offset,Label * L,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bdslot)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 
BranchShort(int32_t offset,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bdslot)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 
BranchShort(Label * L,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bdslot)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 
BranchAndLink(int32_t offset,BranchDelaySlot bdslot)3278 void TurboAssembler::BranchAndLink(int32_t offset, BranchDelaySlot bdslot) {
3279   BranchAndLinkShort(offset, bdslot);
3280 }
3281 
BranchAndLink(int32_t offset,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bdslot)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 
BranchAndLink(Label * L,BranchDelaySlot bdslot)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 
BranchAndLink(Label * L,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bdslot)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 
BranchAndLinkShortHelper(int16_t offset,Label * L,BranchDelaySlot bdslot)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 
BranchAndLinkShortHelperR6(int32_t offset,Label * L)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 
BranchAndLinkShort(int32_t offset,BranchDelaySlot bdslot)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 
BranchAndLinkShort(Label * L,BranchDelaySlot bdslot)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 
BranchAndLinkShortHelperR6(int32_t offset,Label * L,Condition cond,Register rs,const Operand & rt)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.
BranchAndLinkShortHelper(int16_t offset,Label * L,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bdslot)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 
BranchAndLinkShortCheck(int32_t offset,Label * L,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bdslot)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 
LoadFromConstantsTable(Register destination,int constant_index)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 
LoadRootRelative(Register destination,int32_t offset)3633 void TurboAssembler::LoadRootRelative(Register destination, int32_t offset) {
3634   lw(destination, MemOperand(kRootRegister, offset));
3635 }
3636 
LoadRootRegisterOffset(Register destination,intptr_t offset)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 
Jump(Register target,int16_t offset,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bd)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 
Jump(Register target,Register base,int16_t offset,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bd)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 
Jump(Register target,const Operand & offset,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bd)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 
Jump(intptr_t target,RelocInfo::Mode rmode,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bd)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 
Jump(Address target,RelocInfo::Mode rmode,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bd)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 
Jump(Handle<Code> code,RelocInfo::Mode rmode,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bd)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.
Call(Register target,int16_t offset,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bd)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.
Call(Register target,Register base,int16_t offset,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bd)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 
Call(Address target,RelocInfo::Mode rmode,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bd)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 
Call(Handle<Code> code,RelocInfo::Mode rmode,Condition cond,Register rs,const Operand & rt,BranchDelaySlot bd)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 
Ret(Condition cond,Register rs,const Operand & rt,BranchDelaySlot bd)3907 void TurboAssembler::Ret(Condition cond, Register rs, const Operand& rt,
3908                          BranchDelaySlot bd) {
3909   Jump(ra, 0, cond, rs, rt, bd);
3910 }
3911 
BranchLong(Label * L,BranchDelaySlot bdslot)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 
BranchAndLinkLong(Label * L,BranchDelaySlot bdslot)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 
DropAndRet(int drop)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 
DropAndRet(int drop,Condition cond,Register r1,const Operand & r2)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 
Drop(int count,Condition cond,Register reg,const Operand & op)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 
Swap(Register reg1,Register reg2,Register scratch)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 
Call(Label * target)4011 void TurboAssembler::Call(Label* target) { BranchAndLink(target); }
4012 
Push(Handle<HeapObject> handle)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 
Push(Smi * smi)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 
MaybeDropFrames()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 
PushStackHandler()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 
PopStackHandler()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 
FPUCanonicalizeNaN(const DoubleRegister dst,const DoubleRegister src)4067 void TurboAssembler::FPUCanonicalizeNaN(const DoubleRegister dst,
4068                                         const DoubleRegister src) {
4069   sub_d(dst, src, kDoubleRegZero);
4070 }
4071 
MovFromFloatResult(DoubleRegister dst)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 
MovFromFloatParameter(DoubleRegister dst)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 
MovToFloatParameter(DoubleRegister src)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 
MovToFloatResult(DoubleRegister src)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 
MovToFloatParameters(DoubleRegister src1,DoubleRegister src2)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 
PrepareForTailCall(const ParameterCount & callee_args_count,Register caller_args_count_reg,Register scratch0,Register scratch1)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 
InvokePrologue(const ParameterCount & expected,const ParameterCount & actual,Label * done,bool * definitely_mismatches,InvokeFlag flag)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 
CheckDebugHook(Register fun,Register new_target,const ParameterCount & expected,const ParameterCount & actual)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 
InvokeFunctionCode(Register function,Register new_target,const ParameterCount & expected,const ParameterCount & actual,InvokeFlag flag)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 
InvokeFunction(Register function,Register new_target,const ParameterCount & actual,InvokeFlag flag)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 
InvokeFunction(Register function,const ParameterCount & expected,const ParameterCount & actual,InvokeFlag flag)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 
GetObjectType(Register object,Register map,Register type_reg)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 
CallStub(CodeStub * stub,Condition cond,Register r1,const Operand & r2,BranchDelaySlot bd)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 
CallStubDelayed(CodeStub * stub,Condition cond,Register r1,const Operand & r2,BranchDelaySlot bd)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 
TailCallStub(CodeStub * stub,Condition cond,Register r1,const Operand & r2,BranchDelaySlot bd)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 
AllowThisStubCall(CodeStub * stub)4436 bool TurboAssembler::AllowThisStubCall(CodeStub* stub) {
4437   return has_frame() || !stub->SometimesSetsUpAFrame();
4438 }
4439 
AddOverflow(Register dst,Register left,const Operand & right,Register overflow)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 
SubOverflow(Register dst,Register left,const Operand & right,Register overflow)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 
MulOverflow(Register dst,Register left,const Operand & right,Register overflow)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 
CallRuntimeWithCEntry(Runtime::FunctionId fid,Register centry)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 
CallRuntime(const Runtime::Function * f,int num_arguments,SaveFPRegsMode save_doubles)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 
TailCallRuntime(Runtime::FunctionId fid)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 
JumpToExternalReference(const ExternalReference & builtin,BranchDelaySlot bd,bool builtin_exit_frame)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 
JumpToInstructionStream(Address entry)4580 void MacroAssembler::JumpToInstructionStream(Address entry) {
4581   li(kOffHeapTrampolineRegister, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
4582   Jump(kOffHeapTrampolineRegister);
4583 }
4584 
LoadWeakValue(Register out,Register in,Label * target_if_cleared)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 
IncrementCounter(StatsCounter * counter,int value,Register scratch1,Register scratch2)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 
DecrementCounter(StatsCounter * counter,int value,Register scratch1,Register scratch2)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 
Assert(Condition cc,AbortReason reason,Register rs,Operand rt)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 
Check(Condition cc,AbortReason reason,Register rs,Operand rt)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 
Abort(AbortReason reason)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 
LoadNativeContextSlot(int index,Register dst)4685 void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
4686   lw(dst, NativeContextMemOperand());
4687   lw(dst, ContextMemOperand(dst, index));
4688 }
4689 
StubPrologue(StackFrame::Type type)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 
Prologue()4697 void TurboAssembler::Prologue() { PushStandardFrame(a1); }
4698 
EnterFrame(StackFrame::Type type)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 
LeaveFrame(StackFrame::Type type)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 
EnterBuiltinFrame(Register context,Register target,Register argc)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 
LeaveBuiltinFrame(Register context,Register target,Register argc)4729 void MacroAssembler::LeaveBuiltinFrame(Register context, Register target,
4730                                        Register argc) {
4731   Pop(context, target, argc);
4732   Pop(ra, fp);
4733 }
4734 
EnterExitFrame(bool save_doubles,int stack_space,StackFrame::Type frame_type)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 
LeaveExitFrame(bool save_doubles,Register argument_count,bool do_return,bool argument_count_is_length)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 
ActivationFrameAlignment()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 
AssertStackIsAligned()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 
UntagAndJumpIfSmi(Register dst,Register src,Label * smi_case)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 
JumpIfSmi(Register value,Label * smi_label,Register scratch,BranchDelaySlot bd)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 
JumpIfNotSmi(Register value,Label * not_smi_label,Register scratch,BranchDelaySlot bd)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 
JumpIfEitherSmi(Register reg1,Register reg2,Label * on_either_smi)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 
AssertNotSmi(Register object)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 
AssertSmi(Register object)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 
AssertConstructor(Register object)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 
AssertFunction(Register object)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 
AssertBoundFunction(Register object)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 
AssertGeneratorObject(Register object)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 
AssertUndefinedOrAllocationSite(Register object,Register scratch)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 
Float32Max(FPURegister dst,FPURegister src1,FPURegister src2,Label * out_of_line)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 
Float32MaxOutOfLine(FPURegister dst,FPURegister src1,FPURegister src2)5089 void TurboAssembler::Float32MaxOutOfLine(FPURegister dst, FPURegister src1,
5090                                          FPURegister src2) {
5091   add_s(dst, src1, src2);
5092 }
5093 
Float32Min(FPURegister dst,FPURegister src1,FPURegister src2,Label * out_of_line)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 
Float32MinOutOfLine(FPURegister dst,FPURegister src1,FPURegister src2)5138 void TurboAssembler::Float32MinOutOfLine(FPURegister dst, FPURegister src1,
5139                                          FPURegister src2) {
5140   add_s(dst, src1, src2);
5141 }
5142 
Float64Max(DoubleRegister dst,DoubleRegister src1,DoubleRegister src2,Label * out_of_line)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 
Float64MaxOutOfLine(DoubleRegister dst,DoubleRegister src1,DoubleRegister src2)5187 void TurboAssembler::Float64MaxOutOfLine(DoubleRegister dst,
5188                                          DoubleRegister src1,
5189                                          DoubleRegister src2) {
5190   add_d(dst, src1, src2);
5191 }
5192 
Float64Min(DoubleRegister dst,DoubleRegister src1,DoubleRegister src2,Label * out_of_line)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 
Float64MinOutOfLine(DoubleRegister dst,DoubleRegister src1,DoubleRegister src2)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 
CalculateStackPassedWords(int num_reg_arguments,int num_double_arguments)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 
PrepareCallCFunction(int num_reg_arguments,int num_double_arguments,Register scratch)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 
PrepareCallCFunction(int num_reg_arguments,Register scratch)5283 void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
5284                                           Register scratch) {
5285   PrepareCallCFunction(num_reg_arguments, 0, scratch);
5286 }
5287 
CallCFunction(ExternalReference function,int num_reg_arguments,int num_double_arguments)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 
CallCFunction(Register function,int num_reg_arguments,int num_double_arguments)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 
CallCFunction(ExternalReference function,int num_arguments)5304 void TurboAssembler::CallCFunction(ExternalReference function,
5305                                    int num_arguments) {
5306   CallCFunction(function, num_arguments, 0);
5307 }
5308 
CallCFunction(Register function,int num_arguments)5309 void TurboAssembler::CallCFunction(Register function, int num_arguments) {
5310   CallCFunction(function, num_arguments, 0);
5311 }
5312 
CallCFunctionHelper(Register function_base,int16_t function_offset,int num_reg_arguments,int num_double_arguments)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 
CheckPageFlag(Register object,Register scratch,int mask,Condition cc,Label * condition_met)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 
GetRegisterThatIsNotOneOf(Register reg1,Register reg2,Register reg3,Register reg4,Register reg5,Register reg6)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 
ComputeCodeStartAddress(Register dst)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 
ResetSpeculationPoisonRegister()5428 void TurboAssembler::ResetSpeculationPoisonRegister() {
5429   li(kSpeculationPoisonRegister, -1);
5430 }
5431 
5432 }  // namespace internal
5433 }  // namespace v8
5434 
5435 #endif  // V8_TARGET_ARCH_MIPS
5436