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