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