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