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