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