blob: f8e7e1f92f69c6358ea2472a80765e941d209bbc [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#if V8_TARGET_ARCH_MIPS64
8
9#include "src/base/division-by-constant.h"
10#include "src/bootstrapper.h"
11#include "src/codegen.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012#include "src/debug/debug.h"
13#include "src/mips64/macro-assembler-mips64.h"
14#include "src/register-configuration.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015#include "src/runtime/runtime.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016
17namespace v8 {
18namespace internal {
19
Ben Murdoch61f157c2016-09-16 13:49:30 +010020// Floating point constants.
21const uint64_t kDoubleSignMask = Double::kSignMask;
22const uint32_t kDoubleExponentShift = HeapNumber::kMantissaBits;
23const uint32_t kDoubleNaNShift = kDoubleExponentShift - 1;
24const uint64_t kDoubleNaNMask = Double::kExponentMask | (1L << kDoubleNaNShift);
25
26const uint32_t kSingleSignMask = kBinary32SignMask;
27const uint32_t kSingleExponentMask = kBinary32ExponentMask;
28const uint32_t kSingleExponentShift = kBinary32ExponentShift;
29const uint32_t kSingleNaNShift = kSingleExponentShift - 1;
30const uint32_t kSingleNaNMask = kSingleExponentMask | (1 << kSingleNaNShift);
31
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000032MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size,
33 CodeObjectRequired create_code_object)
Ben Murdochb8a8cc12014-11-26 15:28:44 +000034 : Assembler(arg_isolate, buffer, size),
35 generating_stub_(false),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040036 has_frame_(false),
37 has_double_zero_reg_set_(false) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000038 if (create_code_object == CodeObjectRequired::kYes) {
39 code_object_ =
40 Handle<Object>::New(isolate()->heap()->undefined_value(), isolate());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000041 }
42}
43
Ben Murdochb8a8cc12014-11-26 15:28:44 +000044void MacroAssembler::Load(Register dst,
45 const MemOperand& src,
46 Representation r) {
47 DCHECK(!r.IsDouble());
48 if (r.IsInteger8()) {
49 lb(dst, src);
50 } else if (r.IsUInteger8()) {
51 lbu(dst, src);
52 } else if (r.IsInteger16()) {
53 lh(dst, src);
54 } else if (r.IsUInteger16()) {
55 lhu(dst, src);
56 } else if (r.IsInteger32()) {
57 lw(dst, src);
58 } else {
59 ld(dst, src);
60 }
61}
62
63
64void MacroAssembler::Store(Register src,
65 const MemOperand& dst,
66 Representation r) {
67 DCHECK(!r.IsDouble());
68 if (r.IsInteger8() || r.IsUInteger8()) {
69 sb(src, dst);
70 } else if (r.IsInteger16() || r.IsUInteger16()) {
71 sh(src, dst);
72 } else if (r.IsInteger32()) {
73 sw(src, dst);
74 } else {
75 if (r.IsHeapObject()) {
76 AssertNotSmi(src);
77 } else if (r.IsSmi()) {
78 AssertSmi(src);
79 }
80 sd(src, dst);
81 }
82}
83
84
85void MacroAssembler::LoadRoot(Register destination,
86 Heap::RootListIndex index) {
87 ld(destination, MemOperand(s6, index << kPointerSizeLog2));
88}
89
90
91void MacroAssembler::LoadRoot(Register destination,
92 Heap::RootListIndex index,
93 Condition cond,
94 Register src1, const Operand& src2) {
95 Branch(2, NegateCondition(cond), src1, src2);
96 ld(destination, MemOperand(s6, index << kPointerSizeLog2));
97}
98
99
100void MacroAssembler::StoreRoot(Register source,
101 Heap::RootListIndex index) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000102 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 sd(source, MemOperand(s6, index << kPointerSizeLog2));
104}
105
106
107void MacroAssembler::StoreRoot(Register source,
108 Heap::RootListIndex index,
109 Condition cond,
110 Register src1, const Operand& src2) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111 DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000112 Branch(2, NegateCondition(cond), src1, src2);
113 sd(source, MemOperand(s6, index << kPointerSizeLog2));
114}
115
Ben Murdochda12d292016-06-02 14:46:10 +0100116void MacroAssembler::PushCommonFrame(Register marker_reg) {
117 if (marker_reg.is_valid()) {
118 Push(ra, fp, marker_reg);
119 Daddu(fp, sp, Operand(kPointerSize));
120 } else {
121 Push(ra, fp);
122 mov(fp, sp);
123 }
124}
125
126void MacroAssembler::PopCommonFrame(Register marker_reg) {
127 if (marker_reg.is_valid()) {
128 Pop(ra, fp, marker_reg);
129 } else {
130 Pop(ra, fp);
131 }
132}
133
134void MacroAssembler::PushStandardFrame(Register function_reg) {
135 int offset = -StandardFrameConstants::kContextOffset;
136 if (function_reg.is_valid()) {
137 Push(ra, fp, cp, function_reg);
138 offset += kPointerSize;
139 } else {
140 Push(ra, fp, cp);
141 }
142 Daddu(fp, sp, Operand(offset));
143}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144
145// Push and pop all registers that can hold pointers.
146void MacroAssembler::PushSafepointRegisters() {
147 // Safepoints expect a block of kNumSafepointRegisters values on the
148 // stack, so adjust the stack for unsaved registers.
149 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
150 DCHECK(num_unsaved >= 0);
151 if (num_unsaved > 0) {
152 Dsubu(sp, sp, Operand(num_unsaved * kPointerSize));
153 }
154 MultiPush(kSafepointSavedRegisters);
155}
156
157
158void MacroAssembler::PopSafepointRegisters() {
159 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
160 MultiPop(kSafepointSavedRegisters);
161 if (num_unsaved > 0) {
162 Daddu(sp, sp, Operand(num_unsaved * kPointerSize));
163 }
164}
165
166
167void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) {
168 sd(src, SafepointRegisterSlot(dst));
169}
170
171
172void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
173 ld(dst, SafepointRegisterSlot(src));
174}
175
176
177int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
178 // The registers are pushed starting with the highest encoding,
179 // which means that lowest encodings are closest to the stack pointer.
180 return kSafepointRegisterStackIndexMap[reg_code];
181}
182
183
184MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
185 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
186}
187
188
189MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
190 UNIMPLEMENTED_MIPS();
191 // General purpose registers are pushed last on the stack.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000192 int doubles_size = DoubleRegister::kMaxNumRegisters * kDoubleSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000193 int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
194 return MemOperand(sp, doubles_size + register_offset);
195}
196
197
198void MacroAssembler::InNewSpace(Register object,
199 Register scratch,
200 Condition cc,
201 Label* branch) {
202 DCHECK(cc == eq || cc == ne);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100203 const int mask =
204 1 << MemoryChunk::IN_FROM_SPACE | 1 << MemoryChunk::IN_TO_SPACE;
205 CheckPageFlag(object, scratch, mask, cc, branch);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000206}
207
208
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000209// Clobbers object, dst, value, and ra, if (ra_status == kRAHasBeenSaved)
210// The register 'object' contains a heap object pointer. The heap object
211// tag is shifted away.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000212void MacroAssembler::RecordWriteField(
213 Register object,
214 int offset,
215 Register value,
216 Register dst,
217 RAStatus ra_status,
218 SaveFPRegsMode save_fp,
219 RememberedSetAction remembered_set_action,
220 SmiCheck smi_check,
221 PointersToHereCheck pointers_to_here_check_for_value) {
222 DCHECK(!AreAliased(value, dst, t8, object));
223 // First, check if a write barrier is even needed. The tests below
224 // catch stores of Smis.
225 Label done;
226
227 // Skip barrier if writing a smi.
228 if (smi_check == INLINE_SMI_CHECK) {
229 JumpIfSmi(value, &done);
230 }
231
232 // Although the object register is tagged, the offset is relative to the start
233 // of the object, so so offset must be a multiple of kPointerSize.
234 DCHECK(IsAligned(offset, kPointerSize));
235
236 Daddu(dst, object, Operand(offset - kHeapObjectTag));
237 if (emit_debug_code()) {
238 Label ok;
239 And(t8, dst, Operand((1 << kPointerSizeLog2) - 1));
240 Branch(&ok, eq, t8, Operand(zero_reg));
241 stop("Unaligned cell in write barrier");
242 bind(&ok);
243 }
244
245 RecordWrite(object,
246 dst,
247 value,
248 ra_status,
249 save_fp,
250 remembered_set_action,
251 OMIT_SMI_CHECK,
252 pointers_to_here_check_for_value);
253
254 bind(&done);
255
256 // Clobber clobbered input registers when running with the debug-code flag
257 // turned on to provoke errors.
258 if (emit_debug_code()) {
259 li(value, Operand(bit_cast<int64_t>(kZapValue + 4)));
260 li(dst, Operand(bit_cast<int64_t>(kZapValue + 8)));
261 }
262}
263
264
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000265// Clobbers object, dst, map, and ra, if (ra_status == kRAHasBeenSaved)
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000266void MacroAssembler::RecordWriteForMap(Register object,
267 Register map,
268 Register dst,
269 RAStatus ra_status,
270 SaveFPRegsMode fp_mode) {
271 if (emit_debug_code()) {
272 DCHECK(!dst.is(at));
273 ld(dst, FieldMemOperand(map, HeapObject::kMapOffset));
274 Check(eq,
275 kWrongAddressOrValuePassedToRecordWrite,
276 dst,
277 Operand(isolate()->factory()->meta_map()));
278 }
279
280 if (!FLAG_incremental_marking) {
281 return;
282 }
283
284 if (emit_debug_code()) {
285 ld(at, FieldMemOperand(object, HeapObject::kMapOffset));
286 Check(eq,
287 kWrongAddressOrValuePassedToRecordWrite,
288 map,
289 Operand(at));
290 }
291
292 Label done;
293
294 // A single check of the map's pages interesting flag suffices, since it is
295 // only set during incremental collection, and then it's also guaranteed that
296 // the from object's page's interesting flag is also set. This optimization
297 // relies on the fact that maps can never be in new space.
298 CheckPageFlag(map,
299 map, // Used as scratch.
300 MemoryChunk::kPointersToHereAreInterestingMask,
301 eq,
302 &done);
303
304 Daddu(dst, object, Operand(HeapObject::kMapOffset - kHeapObjectTag));
305 if (emit_debug_code()) {
306 Label ok;
307 And(at, dst, Operand((1 << kPointerSizeLog2) - 1));
308 Branch(&ok, eq, at, Operand(zero_reg));
309 stop("Unaligned cell in write barrier");
310 bind(&ok);
311 }
312
313 // Record the actual write.
314 if (ra_status == kRAHasNotBeenSaved) {
315 push(ra);
316 }
317 RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET,
318 fp_mode);
319 CallStub(&stub);
320 if (ra_status == kRAHasNotBeenSaved) {
321 pop(ra);
322 }
323
324 bind(&done);
325
326 // Count number of write barriers in generated code.
327 isolate()->counters()->write_barriers_static()->Increment();
328 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, at, dst);
329
330 // Clobber clobbered registers when running with the debug-code flag
331 // turned on to provoke errors.
332 if (emit_debug_code()) {
333 li(dst, Operand(bit_cast<int64_t>(kZapValue + 12)));
334 li(map, Operand(bit_cast<int64_t>(kZapValue + 16)));
335 }
336}
337
338
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000339// Clobbers object, address, value, and ra, if (ra_status == kRAHasBeenSaved)
340// The register 'object' contains a heap object pointer. The heap object
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000341// tag is shifted away.
342void MacroAssembler::RecordWrite(
343 Register object,
344 Register address,
345 Register value,
346 RAStatus ra_status,
347 SaveFPRegsMode fp_mode,
348 RememberedSetAction remembered_set_action,
349 SmiCheck smi_check,
350 PointersToHereCheck pointers_to_here_check_for_value) {
351 DCHECK(!AreAliased(object, address, value, t8));
352 DCHECK(!AreAliased(object, address, value, t9));
353
354 if (emit_debug_code()) {
355 ld(at, MemOperand(address));
356 Assert(
357 eq, kWrongAddressOrValuePassedToRecordWrite, at, Operand(value));
358 }
359
360 if (remembered_set_action == OMIT_REMEMBERED_SET &&
361 !FLAG_incremental_marking) {
362 return;
363 }
364
365 // First, check if a write barrier is even needed. The tests below
366 // catch stores of smis and stores into the young generation.
367 Label done;
368
369 if (smi_check == INLINE_SMI_CHECK) {
370 DCHECK_EQ(0, kSmiTag);
371 JumpIfSmi(value, &done);
372 }
373
374 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) {
375 CheckPageFlag(value,
376 value, // Used as scratch.
377 MemoryChunk::kPointersToHereAreInterestingMask,
378 eq,
379 &done);
380 }
381 CheckPageFlag(object,
382 value, // Used as scratch.
383 MemoryChunk::kPointersFromHereAreInterestingMask,
384 eq,
385 &done);
386
387 // Record the actual write.
388 if (ra_status == kRAHasNotBeenSaved) {
389 push(ra);
390 }
391 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
392 fp_mode);
393 CallStub(&stub);
394 if (ra_status == kRAHasNotBeenSaved) {
395 pop(ra);
396 }
397
398 bind(&done);
399
400 // Count number of write barriers in generated code.
401 isolate()->counters()->write_barriers_static()->Increment();
402 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, at,
403 value);
404
405 // Clobber clobbered registers when running with the debug-code flag
406 // turned on to provoke errors.
407 if (emit_debug_code()) {
408 li(address, Operand(bit_cast<int64_t>(kZapValue + 12)));
409 li(value, Operand(bit_cast<int64_t>(kZapValue + 16)));
410 }
411}
412
Ben Murdoch097c5b22016-05-18 11:27:45 +0100413void MacroAssembler::RecordWriteCodeEntryField(Register js_function,
414 Register code_entry,
415 Register scratch) {
416 const int offset = JSFunction::kCodeEntryOffset;
417
418 // Since a code entry (value) is always in old space, we don't need to update
419 // remembered set. If incremental marking is off, there is nothing for us to
420 // do.
421 if (!FLAG_incremental_marking) return;
422
423 DCHECK(js_function.is(a1));
424 DCHECK(code_entry.is(a4));
425 DCHECK(scratch.is(a5));
426 AssertNotSmi(js_function);
427
428 if (emit_debug_code()) {
429 Daddu(scratch, js_function, Operand(offset - kHeapObjectTag));
430 ld(at, MemOperand(scratch));
431 Assert(eq, kWrongAddressOrValuePassedToRecordWrite, at,
432 Operand(code_entry));
433 }
434
435 // First, check if a write barrier is even needed. The tests below
436 // catch stores of Smis and stores into young gen.
437 Label done;
438
439 CheckPageFlag(code_entry, scratch,
440 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
441 CheckPageFlag(js_function, scratch,
442 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done);
443
444 const Register dst = scratch;
445 Daddu(dst, js_function, Operand(offset - kHeapObjectTag));
446
447 // Save caller-saved registers. js_function and code_entry are in the
448 // caller-saved register list.
449 DCHECK(kJSCallerSaved & js_function.bit());
450 DCHECK(kJSCallerSaved & code_entry.bit());
451 MultiPush(kJSCallerSaved | ra.bit());
452
453 int argument_count = 3;
454
455 PrepareCallCFunction(argument_count, code_entry);
456
457 Move(a0, js_function);
458 Move(a1, dst);
459 li(a2, Operand(ExternalReference::isolate_address(isolate())));
460
461 {
462 AllowExternalCallThatCantCauseGC scope(this);
463 CallCFunction(
464 ExternalReference::incremental_marking_record_write_code_entry_function(
465 isolate()),
466 argument_count);
467 }
468
469 // Restore caller-saved registers.
470 MultiPop(kJSCallerSaved | ra.bit());
471
472 bind(&done);
473}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000474
475void MacroAssembler::RememberedSetHelper(Register object, // For debug tests.
476 Register address,
477 Register scratch,
478 SaveFPRegsMode fp_mode,
479 RememberedSetFinalAction and_then) {
480 Label done;
481 if (emit_debug_code()) {
482 Label ok;
483 JumpIfNotInNewSpace(object, scratch, &ok);
484 stop("Remembered set pointer is in new space");
485 bind(&ok);
486 }
487 // Load store buffer top.
488 ExternalReference store_buffer =
489 ExternalReference::store_buffer_top(isolate());
490 li(t8, Operand(store_buffer));
491 ld(scratch, MemOperand(t8));
492 // Store pointer to buffer and increment buffer top.
493 sd(address, MemOperand(scratch));
494 Daddu(scratch, scratch, kPointerSize);
495 // Write back new top of buffer.
496 sd(scratch, MemOperand(t8));
497 // Call stub on end of buffer.
498 // Check for end of buffer.
Ben Murdochda12d292016-06-02 14:46:10 +0100499 And(t8, scratch, Operand(StoreBuffer::kStoreBufferMask));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500 DCHECK(!scratch.is(t8));
501 if (and_then == kFallThroughAtEnd) {
Ben Murdochda12d292016-06-02 14:46:10 +0100502 Branch(&done, ne, t8, Operand(zero_reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000503 } else {
504 DCHECK(and_then == kReturnAtEnd);
Ben Murdochda12d292016-06-02 14:46:10 +0100505 Ret(ne, t8, Operand(zero_reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000506 }
507 push(ra);
508 StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode);
509 CallStub(&store_buffer_overflow);
510 pop(ra);
511 bind(&done);
512 if (and_then == kReturnAtEnd) {
513 Ret();
514 }
515}
516
517
518// -----------------------------------------------------------------------------
519// Allocation support.
520
521
522void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
523 Register scratch,
524 Label* miss) {
525 Label same_contexts;
Ben Murdochda12d292016-06-02 14:46:10 +0100526 Register temporary = t8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000527
528 DCHECK(!holder_reg.is(scratch));
529 DCHECK(!holder_reg.is(at));
530 DCHECK(!scratch.is(at));
531
Ben Murdochda12d292016-06-02 14:46:10 +0100532 // Load current lexical context from the active StandardFrame, which
533 // may require crawling past STUB frames.
534 Label load_context;
535 Label has_context;
536 mov(at, fp);
537 bind(&load_context);
538 ld(scratch, MemOperand(at, CommonFrameConstants::kContextOrFrameTypeOffset));
539 // Passing temporary register, otherwise JumpIfNotSmi modifies register at.
540 JumpIfNotSmi(scratch, &has_context, temporary);
541 ld(at, MemOperand(at, CommonFrameConstants::kCallerFPOffset));
542 Branch(&load_context);
543 bind(&has_context);
544
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000545 // In debug mode, make sure the lexical context is set.
546#ifdef DEBUG
547 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext,
548 scratch, Operand(zero_reg));
549#endif
550
551 // Load the native context of the current context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000552 ld(scratch, ContextMemOperand(scratch, Context::NATIVE_CONTEXT_INDEX));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000553
554 // Check the context is a native context.
555 if (emit_debug_code()) {
556 push(holder_reg); // Temporarily save holder on the stack.
557 // Read the first word and compare to the native_context_map.
558 ld(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset));
559 LoadRoot(at, Heap::kNativeContextMapRootIndex);
560 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext,
561 holder_reg, Operand(at));
562 pop(holder_reg); // Restore holder.
563 }
564
565 // Check if both contexts are the same.
566 ld(at, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
567 Branch(&same_contexts, eq, scratch, Operand(at));
568
569 // Check the context is a native context.
570 if (emit_debug_code()) {
571 push(holder_reg); // Temporarily save holder on the stack.
572 mov(holder_reg, at); // Move at to its holding place.
573 LoadRoot(at, Heap::kNullValueRootIndex);
574 Check(ne, kJSGlobalProxyContextShouldNotBeNull,
575 holder_reg, Operand(at));
576
577 ld(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset));
578 LoadRoot(at, Heap::kNativeContextMapRootIndex);
579 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext,
580 holder_reg, Operand(at));
581 // Restore at is not needed. at is reloaded below.
582 pop(holder_reg); // Restore holder.
583 // Restore at to holder's context.
584 ld(at, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
585 }
586
587 // Check that the security token in the calling global object is
588 // compatible with the security token in the receiving global
589 // object.
590 int token_offset = Context::kHeaderSize +
591 Context::SECURITY_TOKEN_INDEX * kPointerSize;
592
593 ld(scratch, FieldMemOperand(scratch, token_offset));
594 ld(at, FieldMemOperand(at, token_offset));
595 Branch(miss, ne, scratch, Operand(at));
596
597 bind(&same_contexts);
598}
599
600
601// Compute the hash code from the untagged key. This must be kept in sync with
602// ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
603// code-stub-hydrogen.cc
604void MacroAssembler::GetNumberHash(Register reg0, Register scratch) {
605 // First of all we assign the hash seed to scratch.
606 LoadRoot(scratch, Heap::kHashSeedRootIndex);
607 SmiUntag(scratch);
608
609 // Xor original key with a seed.
610 xor_(reg0, reg0, scratch);
611
612 // Compute the hash code from the untagged key. This must be kept in sync
613 // with ComputeIntegerHash in utils.h.
614 //
615 // hash = ~hash + (hash << 15);
616 // The algorithm uses 32-bit integer values.
617 nor(scratch, reg0, zero_reg);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100618 Lsa(reg0, scratch, reg0, 15);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000619
620 // hash = hash ^ (hash >> 12);
621 srl(at, reg0, 12);
622 xor_(reg0, reg0, at);
623
624 // hash = hash + (hash << 2);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100625 Lsa(reg0, reg0, reg0, 2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000626
627 // hash = hash ^ (hash >> 4);
628 srl(at, reg0, 4);
629 xor_(reg0, reg0, at);
630
631 // hash = hash * 2057;
632 sll(scratch, reg0, 11);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100633 Lsa(reg0, reg0, reg0, 3);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634 addu(reg0, reg0, scratch);
635
636 // hash = hash ^ (hash >> 16);
637 srl(at, reg0, 16);
638 xor_(reg0, reg0, at);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000639 And(reg0, reg0, Operand(0x3fffffff));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000640}
641
642
643void MacroAssembler::LoadFromNumberDictionary(Label* miss,
644 Register elements,
645 Register key,
646 Register result,
647 Register reg0,
648 Register reg1,
649 Register reg2) {
650 // Register use:
651 //
652 // elements - holds the slow-case elements of the receiver on entry.
653 // Unchanged unless 'result' is the same register.
654 //
655 // key - holds the smi key on entry.
656 // Unchanged unless 'result' is the same register.
657 //
658 //
659 // result - holds the result on exit if the load succeeded.
660 // Allowed to be the same as 'key' or 'result'.
661 // Unchanged on bailout so 'key' or 'result' can be used
662 // in further computation.
663 //
664 // Scratch registers:
665 //
666 // reg0 - holds the untagged key on entry and holds the hash once computed.
667 //
668 // reg1 - Used to hold the capacity mask of the dictionary.
669 //
670 // reg2 - Used for the index into the dictionary.
671 // at - Temporary (avoid MacroAssembler instructions also using 'at').
672 Label done;
673
674 GetNumberHash(reg0, reg1);
675
676 // Compute the capacity mask.
677 ld(reg1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset));
678 SmiUntag(reg1, reg1);
679 Dsubu(reg1, reg1, Operand(1));
680
681 // Generate an unrolled loop that performs a few probes before giving up.
682 for (int i = 0; i < kNumberDictionaryProbes; i++) {
683 // Use reg2 for index calculations and keep the hash intact in reg0.
684 mov(reg2, reg0);
685 // Compute the masked index: (hash + i + i * i) & mask.
686 if (i > 0) {
687 Daddu(reg2, reg2, Operand(SeededNumberDictionary::GetProbeOffset(i)));
688 }
689 and_(reg2, reg2, reg1);
690
691 // Scale the index by multiplying by the element size.
692 DCHECK(SeededNumberDictionary::kEntrySize == 3);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100693 Dlsa(reg2, reg2, reg2, 1); // reg2 = reg2 * 3.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000694
695 // Check if the key is identical to the name.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100696 Dlsa(reg2, elements, reg2, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000697
698 ld(at, FieldMemOperand(reg2, SeededNumberDictionary::kElementsStartOffset));
699 if (i != kNumberDictionaryProbes - 1) {
700 Branch(&done, eq, key, Operand(at));
701 } else {
702 Branch(miss, ne, key, Operand(at));
703 }
704 }
705
706 bind(&done);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400707 // Check that the value is a field property.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000708 // reg2: elements + (index * kPointerSize).
709 const int kDetailsOffset =
710 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
711 ld(reg1, FieldMemOperand(reg2, kDetailsOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000712 DCHECK_EQ(DATA, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000713 And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
714 Branch(miss, ne, at, Operand(zero_reg));
715
716 // Get the value at the masked, scaled index and return.
717 const int kValueOffset =
718 SeededNumberDictionary::kElementsStartOffset + kPointerSize;
719 ld(result, FieldMemOperand(reg2, kValueOffset));
720}
721
722
723// ---------------------------------------------------------------------------
724// Instruction macros.
725
726void MacroAssembler::Addu(Register rd, Register rs, const Operand& rt) {
727 if (rt.is_reg()) {
728 addu(rd, rs, rt.rm());
729 } else {
730 if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000731 addiu(rd, rs, static_cast<int32_t>(rt.imm64_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000732 } else {
733 // li handles the relocation.
734 DCHECK(!rs.is(at));
735 li(at, rt);
736 addu(rd, rs, at);
737 }
738 }
739}
740
741
742void MacroAssembler::Daddu(Register rd, Register rs, const Operand& rt) {
743 if (rt.is_reg()) {
744 daddu(rd, rs, rt.rm());
745 } else {
746 if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000747 daddiu(rd, rs, static_cast<int32_t>(rt.imm64_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000748 } else {
749 // li handles the relocation.
750 DCHECK(!rs.is(at));
751 li(at, rt);
752 daddu(rd, rs, at);
753 }
754 }
755}
756
757
758void MacroAssembler::Subu(Register rd, Register rs, const Operand& rt) {
759 if (rt.is_reg()) {
760 subu(rd, rs, rt.rm());
761 } else {
762 if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000763 addiu(rd, rs, static_cast<int32_t>(
764 -rt.imm64_)); // No subiu instr, use addiu(x, y, -imm).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000765 } else {
766 // li handles the relocation.
767 DCHECK(!rs.is(at));
768 li(at, rt);
769 subu(rd, rs, at);
770 }
771 }
772}
773
774
775void MacroAssembler::Dsubu(Register rd, Register rs, const Operand& rt) {
776 if (rt.is_reg()) {
777 dsubu(rd, rs, rt.rm());
778 } else {
779 if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000780 daddiu(rd, rs,
781 static_cast<int32_t>(
782 -rt.imm64_)); // No subiu instr, use addiu(x, y, -imm).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000783 } else {
784 // li handles the relocation.
785 DCHECK(!rs.is(at));
786 li(at, rt);
787 dsubu(rd, rs, at);
788 }
789 }
790}
791
792
793void MacroAssembler::Mul(Register rd, Register rs, const Operand& rt) {
794 if (rt.is_reg()) {
795 mul(rd, rs, rt.rm());
796 } else {
797 // li handles the relocation.
798 DCHECK(!rs.is(at));
799 li(at, rt);
800 mul(rd, rs, at);
801 }
802}
803
804
805void MacroAssembler::Mulh(Register rd, Register rs, const Operand& rt) {
806 if (rt.is_reg()) {
807 if (kArchVariant != kMips64r6) {
808 mult(rs, rt.rm());
809 mfhi(rd);
810 } else {
811 muh(rd, rs, rt.rm());
812 }
813 } else {
814 // li handles the relocation.
815 DCHECK(!rs.is(at));
816 li(at, rt);
817 if (kArchVariant != kMips64r6) {
818 mult(rs, at);
819 mfhi(rd);
820 } else {
821 muh(rd, rs, at);
822 }
823 }
824}
825
826
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400827void MacroAssembler::Mulhu(Register rd, Register rs, const Operand& rt) {
828 if (rt.is_reg()) {
829 if (kArchVariant != kMips64r6) {
830 multu(rs, rt.rm());
831 mfhi(rd);
832 } else {
833 muhu(rd, rs, rt.rm());
834 }
835 } else {
836 // li handles the relocation.
837 DCHECK(!rs.is(at));
838 li(at, rt);
839 if (kArchVariant != kMips64r6) {
840 multu(rs, at);
841 mfhi(rd);
842 } else {
843 muhu(rd, rs, at);
844 }
845 }
846}
847
848
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000849void MacroAssembler::Dmul(Register rd, Register rs, const Operand& rt) {
850 if (rt.is_reg()) {
851 if (kArchVariant == kMips64r6) {
852 dmul(rd, rs, rt.rm());
853 } else {
854 dmult(rs, rt.rm());
855 mflo(rd);
856 }
857 } else {
858 // li handles the relocation.
859 DCHECK(!rs.is(at));
860 li(at, rt);
861 if (kArchVariant == kMips64r6) {
862 dmul(rd, rs, at);
863 } else {
864 dmult(rs, at);
865 mflo(rd);
866 }
867 }
868}
869
870
871void MacroAssembler::Dmulh(Register rd, Register rs, const Operand& rt) {
872 if (rt.is_reg()) {
873 if (kArchVariant == kMips64r6) {
874 dmuh(rd, rs, rt.rm());
875 } else {
876 dmult(rs, rt.rm());
877 mfhi(rd);
878 }
879 } else {
880 // li handles the relocation.
881 DCHECK(!rs.is(at));
882 li(at, rt);
883 if (kArchVariant == kMips64r6) {
884 dmuh(rd, rs, at);
885 } else {
886 dmult(rs, at);
887 mfhi(rd);
888 }
889 }
890}
891
892
893void MacroAssembler::Mult(Register rs, const Operand& rt) {
894 if (rt.is_reg()) {
895 mult(rs, rt.rm());
896 } else {
897 // li handles the relocation.
898 DCHECK(!rs.is(at));
899 li(at, rt);
900 mult(rs, at);
901 }
902}
903
904
905void MacroAssembler::Dmult(Register rs, const Operand& rt) {
906 if (rt.is_reg()) {
907 dmult(rs, rt.rm());
908 } else {
909 // li handles the relocation.
910 DCHECK(!rs.is(at));
911 li(at, rt);
912 dmult(rs, at);
913 }
914}
915
916
917void MacroAssembler::Multu(Register rs, const Operand& rt) {
918 if (rt.is_reg()) {
919 multu(rs, rt.rm());
920 } else {
921 // li handles the relocation.
922 DCHECK(!rs.is(at));
923 li(at, rt);
924 multu(rs, at);
925 }
926}
927
928
929void MacroAssembler::Dmultu(Register rs, const Operand& rt) {
930 if (rt.is_reg()) {
931 dmultu(rs, rt.rm());
932 } else {
933 // li handles the relocation.
934 DCHECK(!rs.is(at));
935 li(at, rt);
936 dmultu(rs, at);
937 }
938}
939
940
941void MacroAssembler::Div(Register rs, const Operand& rt) {
942 if (rt.is_reg()) {
943 div(rs, rt.rm());
944 } else {
945 // li handles the relocation.
946 DCHECK(!rs.is(at));
947 li(at, rt);
948 div(rs, at);
949 }
950}
951
952
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400953void MacroAssembler::Div(Register res, Register rs, const Operand& rt) {
954 if (rt.is_reg()) {
955 if (kArchVariant != kMips64r6) {
956 div(rs, rt.rm());
957 mflo(res);
958 } else {
959 div(res, rs, rt.rm());
960 }
961 } else {
962 // li handles the relocation.
963 DCHECK(!rs.is(at));
964 li(at, rt);
965 if (kArchVariant != kMips64r6) {
966 div(rs, at);
967 mflo(res);
968 } else {
969 div(res, rs, at);
970 }
971 }
972}
973
974
975void MacroAssembler::Mod(Register rd, Register rs, const Operand& rt) {
976 if (rt.is_reg()) {
977 if (kArchVariant != kMips64r6) {
978 div(rs, rt.rm());
979 mfhi(rd);
980 } else {
981 mod(rd, rs, rt.rm());
982 }
983 } else {
984 // li handles the relocation.
985 DCHECK(!rs.is(at));
986 li(at, rt);
987 if (kArchVariant != kMips64r6) {
988 div(rs, at);
989 mfhi(rd);
990 } else {
991 mod(rd, rs, at);
992 }
993 }
994}
995
996
997void MacroAssembler::Modu(Register rd, Register rs, const Operand& rt) {
998 if (rt.is_reg()) {
999 if (kArchVariant != kMips64r6) {
1000 divu(rs, rt.rm());
1001 mfhi(rd);
1002 } else {
1003 modu(rd, rs, rt.rm());
1004 }
1005 } else {
1006 // li handles the relocation.
1007 DCHECK(!rs.is(at));
1008 li(at, rt);
1009 if (kArchVariant != kMips64r6) {
1010 divu(rs, at);
1011 mfhi(rd);
1012 } else {
1013 modu(rd, rs, at);
1014 }
1015 }
1016}
1017
1018
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001019void MacroAssembler::Ddiv(Register rs, const Operand& rt) {
1020 if (rt.is_reg()) {
1021 ddiv(rs, rt.rm());
1022 } else {
1023 // li handles the relocation.
1024 DCHECK(!rs.is(at));
1025 li(at, rt);
1026 ddiv(rs, at);
1027 }
1028}
1029
1030
1031void MacroAssembler::Ddiv(Register rd, Register rs, const Operand& rt) {
1032 if (kArchVariant != kMips64r6) {
1033 if (rt.is_reg()) {
1034 ddiv(rs, rt.rm());
1035 mflo(rd);
1036 } else {
1037 // li handles the relocation.
1038 DCHECK(!rs.is(at));
1039 li(at, rt);
1040 ddiv(rs, at);
1041 mflo(rd);
1042 }
1043 } else {
1044 if (rt.is_reg()) {
1045 ddiv(rd, rs, rt.rm());
1046 } else {
1047 // li handles the relocation.
1048 DCHECK(!rs.is(at));
1049 li(at, rt);
1050 ddiv(rd, rs, at);
1051 }
1052 }
1053}
1054
1055
1056void MacroAssembler::Divu(Register rs, const Operand& rt) {
1057 if (rt.is_reg()) {
1058 divu(rs, rt.rm());
1059 } else {
1060 // li handles the relocation.
1061 DCHECK(!rs.is(at));
1062 li(at, rt);
1063 divu(rs, at);
1064 }
1065}
1066
1067
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001068void MacroAssembler::Divu(Register res, Register rs, const Operand& rt) {
1069 if (rt.is_reg()) {
1070 if (kArchVariant != kMips64r6) {
1071 divu(rs, rt.rm());
1072 mflo(res);
1073 } else {
1074 divu(res, rs, rt.rm());
1075 }
1076 } else {
1077 // li handles the relocation.
1078 DCHECK(!rs.is(at));
1079 li(at, rt);
1080 if (kArchVariant != kMips64r6) {
1081 divu(rs, at);
1082 mflo(res);
1083 } else {
1084 divu(res, rs, at);
1085 }
1086 }
1087}
1088
1089
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001090void MacroAssembler::Ddivu(Register rs, const Operand& rt) {
1091 if (rt.is_reg()) {
1092 ddivu(rs, rt.rm());
1093 } else {
1094 // li handles the relocation.
1095 DCHECK(!rs.is(at));
1096 li(at, rt);
1097 ddivu(rs, at);
1098 }
1099}
1100
1101
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001102void MacroAssembler::Ddivu(Register res, Register rs, const Operand& rt) {
1103 if (rt.is_reg()) {
1104 if (kArchVariant != kMips64r6) {
1105 ddivu(rs, rt.rm());
1106 mflo(res);
1107 } else {
1108 ddivu(res, rs, rt.rm());
1109 }
1110 } else {
1111 // li handles the relocation.
1112 DCHECK(!rs.is(at));
1113 li(at, rt);
1114 if (kArchVariant != kMips64r6) {
1115 ddivu(rs, at);
1116 mflo(res);
1117 } else {
1118 ddivu(res, rs, at);
1119 }
1120 }
1121}
1122
1123
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001124void MacroAssembler::Dmod(Register rd, Register rs, const Operand& rt) {
1125 if (kArchVariant != kMips64r6) {
1126 if (rt.is_reg()) {
1127 ddiv(rs, rt.rm());
1128 mfhi(rd);
1129 } else {
1130 // li handles the relocation.
1131 DCHECK(!rs.is(at));
1132 li(at, rt);
1133 ddiv(rs, at);
1134 mfhi(rd);
1135 }
1136 } else {
1137 if (rt.is_reg()) {
1138 dmod(rd, rs, rt.rm());
1139 } else {
1140 // li handles the relocation.
1141 DCHECK(!rs.is(at));
1142 li(at, rt);
1143 dmod(rd, rs, at);
1144 }
1145 }
1146}
1147
1148
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001149void MacroAssembler::Dmodu(Register rd, Register rs, const Operand& rt) {
1150 if (kArchVariant != kMips64r6) {
1151 if (rt.is_reg()) {
1152 ddivu(rs, rt.rm());
1153 mfhi(rd);
1154 } else {
1155 // li handles the relocation.
1156 DCHECK(!rs.is(at));
1157 li(at, rt);
1158 ddivu(rs, at);
1159 mfhi(rd);
1160 }
1161 } else {
1162 if (rt.is_reg()) {
1163 dmodu(rd, rs, rt.rm());
1164 } else {
1165 // li handles the relocation.
1166 DCHECK(!rs.is(at));
1167 li(at, rt);
1168 dmodu(rd, rs, at);
1169 }
1170 }
1171}
1172
1173
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001174void MacroAssembler::And(Register rd, Register rs, const Operand& rt) {
1175 if (rt.is_reg()) {
1176 and_(rd, rs, rt.rm());
1177 } else {
1178 if (is_uint16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001179 andi(rd, rs, static_cast<int32_t>(rt.imm64_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001180 } else {
1181 // li handles the relocation.
1182 DCHECK(!rs.is(at));
1183 li(at, rt);
1184 and_(rd, rs, at);
1185 }
1186 }
1187}
1188
1189
1190void MacroAssembler::Or(Register rd, Register rs, const Operand& rt) {
1191 if (rt.is_reg()) {
1192 or_(rd, rs, rt.rm());
1193 } else {
1194 if (is_uint16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001195 ori(rd, rs, static_cast<int32_t>(rt.imm64_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001196 } else {
1197 // li handles the relocation.
1198 DCHECK(!rs.is(at));
1199 li(at, rt);
1200 or_(rd, rs, at);
1201 }
1202 }
1203}
1204
1205
1206void MacroAssembler::Xor(Register rd, Register rs, const Operand& rt) {
1207 if (rt.is_reg()) {
1208 xor_(rd, rs, rt.rm());
1209 } else {
1210 if (is_uint16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001211 xori(rd, rs, static_cast<int32_t>(rt.imm64_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001212 } else {
1213 // li handles the relocation.
1214 DCHECK(!rs.is(at));
1215 li(at, rt);
1216 xor_(rd, rs, at);
1217 }
1218 }
1219}
1220
1221
1222void MacroAssembler::Nor(Register rd, Register rs, const Operand& rt) {
1223 if (rt.is_reg()) {
1224 nor(rd, rs, rt.rm());
1225 } else {
1226 // li handles the relocation.
1227 DCHECK(!rs.is(at));
1228 li(at, rt);
1229 nor(rd, rs, at);
1230 }
1231}
1232
1233
1234void MacroAssembler::Neg(Register rs, const Operand& rt) {
1235 DCHECK(rt.is_reg());
1236 DCHECK(!at.is(rs));
1237 DCHECK(!at.is(rt.rm()));
1238 li(at, -1);
1239 xor_(rs, rt.rm(), at);
1240}
1241
1242
1243void MacroAssembler::Slt(Register rd, Register rs, const Operand& rt) {
1244 if (rt.is_reg()) {
1245 slt(rd, rs, rt.rm());
1246 } else {
1247 if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001248 slti(rd, rs, static_cast<int32_t>(rt.imm64_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001249 } else {
1250 // li handles the relocation.
1251 DCHECK(!rs.is(at));
1252 li(at, rt);
1253 slt(rd, rs, at);
1254 }
1255 }
1256}
1257
1258
1259void MacroAssembler::Sltu(Register rd, Register rs, const Operand& rt) {
1260 if (rt.is_reg()) {
1261 sltu(rd, rs, rt.rm());
1262 } else {
1263 if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001264 sltiu(rd, rs, static_cast<int32_t>(rt.imm64_));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001265 } else {
1266 // li handles the relocation.
1267 DCHECK(!rs.is(at));
1268 li(at, rt);
1269 sltu(rd, rs, at);
1270 }
1271 }
1272}
1273
1274
1275void MacroAssembler::Ror(Register rd, Register rs, const Operand& rt) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001276 if (rt.is_reg()) {
1277 rotrv(rd, rs, rt.rm());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001278 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01001279 int64_t ror_value = rt.imm64_ % 32;
1280 if (ror_value < 0) {
1281 ror_value += 32;
1282 }
1283 rotr(rd, rs, ror_value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001284 }
1285}
1286
1287
1288void MacroAssembler::Dror(Register rd, Register rs, const Operand& rt) {
1289 if (rt.is_reg()) {
1290 drotrv(rd, rs, rt.rm());
1291 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01001292 int64_t dror_value = rt.imm64_ % 64;
1293 if (dror_value < 0) dror_value += 64;
1294 if (dror_value <= 31) {
1295 drotr(rd, rs, dror_value);
1296 } else {
1297 drotr32(rd, rs, dror_value - 32);
1298 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001299 }
1300}
1301
1302
1303void MacroAssembler::Pref(int32_t hint, const MemOperand& rs) {
1304 pref(hint, rs);
1305}
1306
1307
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001308void MacroAssembler::Lsa(Register rd, Register rt, Register rs, uint8_t sa,
1309 Register scratch) {
Ben Murdochda12d292016-06-02 14:46:10 +01001310 DCHECK(sa >= 1 && sa <= 31);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001311 if (kArchVariant == kMips64r6 && sa <= 4) {
Ben Murdochda12d292016-06-02 14:46:10 +01001312 lsa(rd, rt, rs, sa - 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001313 } else {
1314 Register tmp = rd.is(rt) ? scratch : rd;
1315 DCHECK(!tmp.is(rt));
1316 sll(tmp, rs, sa);
1317 Addu(rd, rt, tmp);
1318 }
1319}
1320
1321
1322void MacroAssembler::Dlsa(Register rd, Register rt, Register rs, uint8_t sa,
1323 Register scratch) {
Ben Murdochda12d292016-06-02 14:46:10 +01001324 DCHECK(sa >= 1 && sa <= 31);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001325 if (kArchVariant == kMips64r6 && sa <= 4) {
Ben Murdochda12d292016-06-02 14:46:10 +01001326 dlsa(rd, rt, rs, sa - 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001327 } else {
1328 Register tmp = rd.is(rt) ? scratch : rd;
1329 DCHECK(!tmp.is(rt));
1330 dsll(tmp, rs, sa);
1331 Daddu(rd, rt, tmp);
1332 }
1333}
1334
1335
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001336// ------------Pseudo-instructions-------------
1337
Ben Murdoch61f157c2016-09-16 13:49:30 +01001338// Change endianness
1339void MacroAssembler::ByteSwapSigned(Register reg, int operand_size) {
1340 DCHECK(operand_size == 1 || operand_size == 2 || operand_size == 4 ||
1341 operand_size == 8);
1342 DCHECK(kArchVariant == kMips64r6 || kArchVariant == kMips64r2);
1343 if (operand_size == 1) {
1344 seb(reg, reg);
1345 sll(reg, reg, 0);
1346 dsbh(reg, reg);
1347 dshd(reg, reg);
1348 } else if (operand_size == 2) {
1349 seh(reg, reg);
1350 sll(reg, reg, 0);
1351 dsbh(reg, reg);
1352 dshd(reg, reg);
1353 } else if (operand_size == 4) {
1354 sll(reg, reg, 0);
1355 dsbh(reg, reg);
1356 dshd(reg, reg);
1357 } else {
1358 dsbh(reg, reg);
1359 dshd(reg, reg);
1360 }
1361}
1362
1363void MacroAssembler::ByteSwapUnsigned(Register reg, int operand_size) {
1364 DCHECK(operand_size == 1 || operand_size == 2 || operand_size == 4);
1365 if (operand_size == 1) {
1366 andi(reg, reg, 0xFF);
1367 dsbh(reg, reg);
1368 dshd(reg, reg);
1369 } else if (operand_size == 2) {
1370 andi(reg, reg, 0xFFFF);
1371 dsbh(reg, reg);
1372 dshd(reg, reg);
1373 } else {
1374 dsll32(reg, reg, 0);
1375 dsrl32(reg, reg, 0);
1376 dsbh(reg, reg);
1377 dshd(reg, reg);
1378 }
1379}
1380
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001381void MacroAssembler::Ulw(Register rd, const MemOperand& rs) {
Ben Murdochc5610432016-08-08 18:44:38 +01001382 DCHECK(!rd.is(at));
1383 DCHECK(!rs.rm().is(at));
1384 if (kArchVariant == kMips64r6) {
1385 lw(rd, rs);
1386 } else {
1387 DCHECK(kArchVariant == kMips64r2);
1388 if (is_int16(rs.offset() + kMipsLwrOffset) &&
1389 is_int16(rs.offset() + kMipsLwlOffset)) {
1390 if (!rd.is(rs.rm())) {
1391 lwr(rd, MemOperand(rs.rm(), rs.offset() + kMipsLwrOffset));
1392 lwl(rd, MemOperand(rs.rm(), rs.offset() + kMipsLwlOffset));
1393 } else {
1394 lwr(at, MemOperand(rs.rm(), rs.offset() + kMipsLwrOffset));
1395 lwl(at, MemOperand(rs.rm(), rs.offset() + kMipsLwlOffset));
1396 mov(rd, at);
1397 }
1398 } else { // Offset > 16 bits, use multiple instructions to load.
1399 LoadRegPlusOffsetToAt(rs);
1400 lwr(rd, MemOperand(at, kMipsLwrOffset));
1401 lwl(rd, MemOperand(at, kMipsLwlOffset));
1402 }
1403 }
1404}
1405
1406void MacroAssembler::Ulwu(Register rd, const MemOperand& rs) {
1407 if (kArchVariant == kMips64r6) {
1408 lwu(rd, rs);
1409 } else {
1410 DCHECK(kArchVariant == kMips64r2);
1411 Ulw(rd, rs);
1412 Dext(rd, rd, 0, 32);
1413 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001414}
1415
1416
1417void MacroAssembler::Usw(Register rd, const MemOperand& rs) {
Ben Murdochc5610432016-08-08 18:44:38 +01001418 DCHECK(!rd.is(at));
1419 DCHECK(!rs.rm().is(at));
1420 if (kArchVariant == kMips64r6) {
1421 sw(rd, rs);
1422 } else {
1423 DCHECK(kArchVariant == kMips64r2);
1424 if (is_int16(rs.offset() + kMipsSwrOffset) &&
1425 is_int16(rs.offset() + kMipsSwlOffset)) {
1426 swr(rd, MemOperand(rs.rm(), rs.offset() + kMipsSwrOffset));
1427 swl(rd, MemOperand(rs.rm(), rs.offset() + kMipsSwlOffset));
1428 } else {
1429 LoadRegPlusOffsetToAt(rs);
1430 swr(rd, MemOperand(at, kMipsSwrOffset));
1431 swl(rd, MemOperand(at, kMipsSwlOffset));
1432 }
1433 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001434}
1435
Ben Murdochc5610432016-08-08 18:44:38 +01001436void MacroAssembler::Ulh(Register rd, const MemOperand& rs) {
1437 DCHECK(!rd.is(at));
1438 DCHECK(!rs.rm().is(at));
1439 if (kArchVariant == kMips64r6) {
1440 lh(rd, rs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001441 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001442 DCHECK(kArchVariant == kMips64r2);
1443 if (is_int16(rs.offset()) && is_int16(rs.offset() + 1)) {
1444#if defined(V8_TARGET_LITTLE_ENDIAN)
1445 lbu(at, rs);
1446 lb(rd, MemOperand(rs.rm(), rs.offset() + 1));
1447#elif defined(V8_TARGET_BIG_ENDIAN)
1448 lbu(at, MemOperand(rs.rm(), rs.offset() + 1));
1449 lb(rd, rs);
1450#endif
1451 } else { // Offset > 16 bits, use multiple instructions to load.
1452 LoadRegPlusOffsetToAt(rs);
1453#if defined(V8_TARGET_LITTLE_ENDIAN)
1454 lb(rd, MemOperand(at, 1));
1455 lbu(at, MemOperand(at, 0));
1456#elif defined(V8_TARGET_BIG_ENDIAN)
1457 lb(rd, MemOperand(at, 0));
1458 lbu(at, MemOperand(at, 1));
1459#endif
1460 }
1461 dsll(rd, rd, 8);
1462 or_(rd, rd, at);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001463 }
Ben Murdochc5610432016-08-08 18:44:38 +01001464}
1465
1466void MacroAssembler::Ulhu(Register rd, const MemOperand& rs) {
1467 DCHECK(!rd.is(at));
1468 DCHECK(!rs.rm().is(at));
1469 if (kArchVariant == kMips64r6) {
1470 lhu(rd, rs);
1471 } else {
1472 DCHECK(kArchVariant == kMips64r2);
1473 if (is_int16(rs.offset()) && is_int16(rs.offset() + 1)) {
1474#if defined(V8_TARGET_LITTLE_ENDIAN)
1475 lbu(at, rs);
1476 lbu(rd, MemOperand(rs.rm(), rs.offset() + 1));
1477#elif defined(V8_TARGET_BIG_ENDIAN)
1478 lbu(at, MemOperand(rs.rm(), rs.offset() + 1));
1479 lbu(rd, rs);
1480#endif
1481 } else { // Offset > 16 bits, use multiple instructions to load.
1482 LoadRegPlusOffsetToAt(rs);
1483#if defined(V8_TARGET_LITTLE_ENDIAN)
1484 lbu(rd, MemOperand(at, 1));
1485 lbu(at, MemOperand(at, 0));
1486#elif defined(V8_TARGET_BIG_ENDIAN)
1487 lbu(rd, MemOperand(at, 0));
1488 lbu(at, MemOperand(at, 1));
1489#endif
1490 }
1491 dsll(rd, rd, 8);
1492 or_(rd, rd, at);
1493 }
1494}
1495
1496void MacroAssembler::Ush(Register rd, const MemOperand& rs, Register scratch) {
1497 DCHECK(!rd.is(at));
1498 DCHECK(!rs.rm().is(at));
1499 DCHECK(!rs.rm().is(scratch));
1500 DCHECK(!scratch.is(at));
1501 if (kArchVariant == kMips64r6) {
1502 sh(rd, rs);
1503 } else {
1504 DCHECK(kArchVariant == kMips64r2);
1505 MemOperand source = rs;
1506 // If offset > 16 bits, load address to at with offset 0.
1507 if (!is_int16(rs.offset()) || !is_int16(rs.offset() + 1)) {
1508 LoadRegPlusOffsetToAt(rs);
1509 source = MemOperand(at, 0);
1510 }
1511
1512 if (!scratch.is(rd)) {
1513 mov(scratch, rd);
1514 }
1515
1516#if defined(V8_TARGET_LITTLE_ENDIAN)
1517 sb(scratch, source);
1518 srl(scratch, scratch, 8);
1519 sb(scratch, MemOperand(source.rm(), source.offset() + 1));
1520#elif defined(V8_TARGET_BIG_ENDIAN)
1521 sb(scratch, MemOperand(source.rm(), source.offset() + 1));
1522 srl(scratch, scratch, 8);
1523 sb(scratch, source);
1524#endif
1525 }
1526}
1527
1528void MacroAssembler::Uld(Register rd, const MemOperand& rs) {
1529 DCHECK(!rd.is(at));
1530 DCHECK(!rs.rm().is(at));
1531 if (kArchVariant == kMips64r6) {
1532 ld(rd, rs);
1533 } else {
1534 DCHECK(kArchVariant == kMips64r2);
1535 if (is_int16(rs.offset() + kMipsLdrOffset) &&
1536 is_int16(rs.offset() + kMipsLdlOffset)) {
1537 if (!rd.is(rs.rm())) {
1538 ldr(rd, MemOperand(rs.rm(), rs.offset() + kMipsLdrOffset));
1539 ldl(rd, MemOperand(rs.rm(), rs.offset() + kMipsLdlOffset));
1540 } else {
1541 ldr(at, MemOperand(rs.rm(), rs.offset() + kMipsLdrOffset));
1542 ldl(at, MemOperand(rs.rm(), rs.offset() + kMipsLdlOffset));
1543 mov(rd, at);
1544 }
1545 } else { // Offset > 16 bits, use multiple instructions to load.
1546 LoadRegPlusOffsetToAt(rs);
1547 ldr(rd, MemOperand(at, kMipsLdrOffset));
1548 ldl(rd, MemOperand(at, kMipsLdlOffset));
1549 }
1550 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001551}
1552
1553
1554// Load consequent 32-bit word pair in 64-bit reg. and put first word in low
1555// bits,
1556// second word in high bits.
1557void MacroAssembler::LoadWordPair(Register rd, const MemOperand& rs,
1558 Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001559 lwu(rd, rs);
1560 lw(scratch, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2));
1561 dsll32(scratch, scratch, 0);
1562 Daddu(rd, rd, scratch);
1563}
1564
Ben Murdochc5610432016-08-08 18:44:38 +01001565void MacroAssembler::Usd(Register rd, const MemOperand& rs) {
1566 DCHECK(!rd.is(at));
1567 DCHECK(!rs.rm().is(at));
1568 if (kArchVariant == kMips64r6) {
1569 sd(rd, rs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001570 } else {
Ben Murdochc5610432016-08-08 18:44:38 +01001571 DCHECK(kArchVariant == kMips64r2);
1572 if (is_int16(rs.offset() + kMipsSdrOffset) &&
1573 is_int16(rs.offset() + kMipsSdlOffset)) {
1574 sdr(rd, MemOperand(rs.rm(), rs.offset() + kMipsSdrOffset));
1575 sdl(rd, MemOperand(rs.rm(), rs.offset() + kMipsSdlOffset));
1576 } else {
1577 LoadRegPlusOffsetToAt(rs);
1578 sdr(rd, MemOperand(at, kMipsSdrOffset));
1579 sdl(rd, MemOperand(at, kMipsSdlOffset));
1580 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001581 }
1582}
1583
1584
1585// Do 64-bit store as two consequent 32-bit stores to unaligned address.
1586void MacroAssembler::StoreWordPair(Register rd, const MemOperand& rs,
1587 Register scratch) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001588 sw(rd, rs);
1589 dsrl32(scratch, rd, 0);
1590 sw(scratch, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2));
1591}
1592
Ben Murdochc5610432016-08-08 18:44:38 +01001593void MacroAssembler::Ulwc1(FPURegister fd, const MemOperand& rs,
1594 Register scratch) {
1595 if (kArchVariant == kMips64r6) {
1596 lwc1(fd, rs);
1597 } else {
1598 DCHECK(kArchVariant == kMips64r2);
1599 Ulw(scratch, rs);
1600 mtc1(scratch, fd);
1601 }
1602}
1603
1604void MacroAssembler::Uswc1(FPURegister fd, const MemOperand& rs,
1605 Register scratch) {
1606 if (kArchVariant == kMips64r6) {
1607 swc1(fd, rs);
1608 } else {
1609 DCHECK(kArchVariant == kMips64r2);
1610 mfc1(scratch, fd);
1611 Usw(scratch, rs);
1612 }
1613}
1614
1615void MacroAssembler::Uldc1(FPURegister fd, const MemOperand& rs,
1616 Register scratch) {
1617 DCHECK(!scratch.is(at));
1618 if (kArchVariant == kMips64r6) {
1619 ldc1(fd, rs);
1620 } else {
1621 DCHECK(kArchVariant == kMips64r2);
1622 Uld(scratch, rs);
1623 dmtc1(scratch, fd);
1624 }
1625}
1626
1627void MacroAssembler::Usdc1(FPURegister fd, const MemOperand& rs,
1628 Register scratch) {
1629 DCHECK(!scratch.is(at));
1630 if (kArchVariant == kMips64r6) {
1631 sdc1(fd, rs);
1632 } else {
1633 DCHECK(kArchVariant == kMips64r2);
1634 dmfc1(scratch, fd);
1635 Usd(scratch, rs);
1636 }
1637}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001638
1639void MacroAssembler::li(Register dst, Handle<Object> value, LiFlags mode) {
1640 AllowDeferredHandleDereference smi_check;
1641 if (value->IsSmi()) {
1642 li(dst, Operand(value), mode);
1643 } else {
1644 DCHECK(value->IsHeapObject());
1645 if (isolate()->heap()->InNewSpace(*value)) {
1646 Handle<Cell> cell = isolate()->factory()->NewCell(value);
1647 li(dst, Operand(cell));
1648 ld(dst, FieldMemOperand(dst, Cell::kValueOffset));
1649 } else {
1650 li(dst, Operand(value));
1651 }
1652 }
1653}
1654
Ben Murdoch097c5b22016-05-18 11:27:45 +01001655static inline int64_t ShiftAndFixSignExtension(int64_t imm, int bitnum) {
1656 if ((imm >> (bitnum - 1)) & 0x1) {
1657 imm = (imm >> bitnum) + 1;
1658 } else {
1659 imm = imm >> bitnum;
1660 }
1661 return imm;
1662}
1663
1664bool MacroAssembler::LiLower32BitHelper(Register rd, Operand j) {
1665 bool higher_bits_sign_extended = false;
1666 if (is_int16(j.imm64_)) {
1667 daddiu(rd, zero_reg, (j.imm64_ & kImm16Mask));
1668 } else if (!(j.imm64_ & kHiMask)) {
1669 ori(rd, zero_reg, (j.imm64_ & kImm16Mask));
1670 } else if (!(j.imm64_ & kImm16Mask)) {
1671 lui(rd, (j.imm64_ >> kLuiShift) & kImm16Mask);
1672 if ((j.imm64_ >> (kLuiShift + 15)) & 0x1) {
1673 higher_bits_sign_extended = true;
1674 }
1675 } else {
1676 lui(rd, (j.imm64_ >> kLuiShift) & kImm16Mask);
1677 ori(rd, rd, (j.imm64_ & kImm16Mask));
1678 if ((j.imm64_ >> (kLuiShift + 15)) & 0x1) {
1679 higher_bits_sign_extended = true;
1680 }
1681 }
1682 return higher_bits_sign_extended;
1683}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001684
1685void MacroAssembler::li(Register rd, Operand j, LiFlags mode) {
1686 DCHECK(!j.is_reg());
1687 BlockTrampolinePoolScope block_trampoline_pool(this);
1688 if (!MustUseReg(j.rmode_) && mode == OPTIMIZE_SIZE) {
1689 // Normal load of an immediate value which does not need Relocation Info.
1690 if (is_int32(j.imm64_)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001691 LiLower32BitHelper(rd, j);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001692 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001693 if (kArchVariant == kMips64r6) {
1694 int64_t imm = j.imm64_;
1695 bool higher_bits_sign_extended = LiLower32BitHelper(rd, j);
1696 imm = ShiftAndFixSignExtension(imm, 32);
1697 // If LUI writes 1s to higher bits, we need both DAHI/DATI.
1698 if ((imm & kImm16Mask) ||
1699 (higher_bits_sign_extended && (j.imm64_ > 0))) {
1700 dahi(rd, imm & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001701 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001702 imm = ShiftAndFixSignExtension(imm, 16);
1703 if ((!is_int48(j.imm64_) && (imm & kImm16Mask)) ||
1704 (higher_bits_sign_extended && (j.imm64_ > 0))) {
1705 dati(rd, imm & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001706 }
1707 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001708 if (is_int48(j.imm64_)) {
1709 if ((j.imm64_ >> 32) & kImm16Mask) {
1710 lui(rd, (j.imm64_ >> 32) & kImm16Mask);
1711 if ((j.imm64_ >> 16) & kImm16Mask) {
1712 ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
1713 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001714 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001715 ori(rd, zero_reg, (j.imm64_ >> 16) & kImm16Mask);
1716 }
1717 dsll(rd, rd, 16);
1718 if (j.imm64_ & kImm16Mask) {
1719 ori(rd, rd, j.imm64_ & kImm16Mask);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001720 }
1721 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001722 lui(rd, (j.imm64_ >> 48) & kImm16Mask);
1723 if ((j.imm64_ >> 32) & kImm16Mask) {
1724 ori(rd, rd, (j.imm64_ >> 32) & kImm16Mask);
1725 }
1726 if ((j.imm64_ >> 16) & kImm16Mask) {
1727 dsll(rd, rd, 16);
1728 ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
1729 if (j.imm64_ & kImm16Mask) {
1730 dsll(rd, rd, 16);
1731 ori(rd, rd, j.imm64_ & kImm16Mask);
1732 } else {
1733 dsll(rd, rd, 16);
1734 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001735 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001736 if (j.imm64_ & kImm16Mask) {
1737 dsll32(rd, rd, 0);
1738 ori(rd, rd, j.imm64_ & kImm16Mask);
1739 } else {
1740 dsll32(rd, rd, 0);
1741 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001742 }
1743 }
1744 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001745 }
1746 } else if (MustUseReg(j.rmode_)) {
1747 RecordRelocInfo(j.rmode_, j.imm64_);
1748 lui(rd, (j.imm64_ >> 32) & kImm16Mask);
1749 ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
1750 dsll(rd, rd, 16);
1751 ori(rd, rd, j.imm64_ & kImm16Mask);
1752 } else if (mode == ADDRESS_LOAD) {
1753 // We always need the same number of instructions as we may need to patch
1754 // this code to load another value which may need all 4 instructions.
1755 lui(rd, (j.imm64_ >> 32) & kImm16Mask);
1756 ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
1757 dsll(rd, rd, 16);
1758 ori(rd, rd, j.imm64_ & kImm16Mask);
1759 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001760 if (kArchVariant == kMips64r6) {
1761 int64_t imm = j.imm64_;
1762 lui(rd, (imm >> kLuiShift) & kImm16Mask);
1763 if (imm & kImm16Mask) {
1764 ori(rd, rd, (imm & kImm16Mask));
1765 }
1766 if ((imm >> 31) & 0x1) {
1767 imm = (imm >> 32) + 1;
1768 } else {
1769 imm = imm >> 32;
1770 }
1771 dahi(rd, imm & kImm16Mask);
1772 if ((imm >> 15) & 0x1) {
1773 imm = (imm >> 16) + 1;
1774 } else {
1775 imm = imm >> 16;
1776 }
1777 dati(rd, imm & kImm16Mask);
1778 } else {
1779 lui(rd, (j.imm64_ >> 48) & kImm16Mask);
1780 ori(rd, rd, (j.imm64_ >> 32) & kImm16Mask);
1781 dsll(rd, rd, 16);
1782 ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
1783 dsll(rd, rd, 16);
1784 ori(rd, rd, j.imm64_ & kImm16Mask);
1785 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001786 }
1787}
1788
1789
1790void MacroAssembler::MultiPush(RegList regs) {
1791 int16_t num_to_push = NumberOfBitsSet(regs);
1792 int16_t stack_offset = num_to_push * kPointerSize;
1793
1794 Dsubu(sp, sp, Operand(stack_offset));
1795 for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
1796 if ((regs & (1 << i)) != 0) {
1797 stack_offset -= kPointerSize;
1798 sd(ToRegister(i), MemOperand(sp, stack_offset));
1799 }
1800 }
1801}
1802
1803
1804void MacroAssembler::MultiPushReversed(RegList regs) {
1805 int16_t num_to_push = NumberOfBitsSet(regs);
1806 int16_t stack_offset = num_to_push * kPointerSize;
1807
1808 Dsubu(sp, sp, Operand(stack_offset));
1809 for (int16_t i = 0; i < kNumRegisters; i++) {
1810 if ((regs & (1 << i)) != 0) {
1811 stack_offset -= kPointerSize;
1812 sd(ToRegister(i), MemOperand(sp, stack_offset));
1813 }
1814 }
1815}
1816
1817
1818void MacroAssembler::MultiPop(RegList regs) {
1819 int16_t stack_offset = 0;
1820
1821 for (int16_t i = 0; i < kNumRegisters; i++) {
1822 if ((regs & (1 << i)) != 0) {
1823 ld(ToRegister(i), MemOperand(sp, stack_offset));
1824 stack_offset += kPointerSize;
1825 }
1826 }
1827 daddiu(sp, sp, stack_offset);
1828}
1829
1830
1831void MacroAssembler::MultiPopReversed(RegList regs) {
1832 int16_t stack_offset = 0;
1833
1834 for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
1835 if ((regs & (1 << i)) != 0) {
1836 ld(ToRegister(i), MemOperand(sp, stack_offset));
1837 stack_offset += kPointerSize;
1838 }
1839 }
1840 daddiu(sp, sp, stack_offset);
1841}
1842
1843
1844void MacroAssembler::MultiPushFPU(RegList regs) {
1845 int16_t num_to_push = NumberOfBitsSet(regs);
1846 int16_t stack_offset = num_to_push * kDoubleSize;
1847
1848 Dsubu(sp, sp, Operand(stack_offset));
1849 for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
1850 if ((regs & (1 << i)) != 0) {
1851 stack_offset -= kDoubleSize;
1852 sdc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
1853 }
1854 }
1855}
1856
1857
1858void MacroAssembler::MultiPushReversedFPU(RegList regs) {
1859 int16_t num_to_push = NumberOfBitsSet(regs);
1860 int16_t stack_offset = num_to_push * kDoubleSize;
1861
1862 Dsubu(sp, sp, Operand(stack_offset));
1863 for (int16_t i = 0; i < kNumRegisters; i++) {
1864 if ((regs & (1 << i)) != 0) {
1865 stack_offset -= kDoubleSize;
1866 sdc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
1867 }
1868 }
1869}
1870
1871
1872void MacroAssembler::MultiPopFPU(RegList regs) {
1873 int16_t stack_offset = 0;
1874
1875 for (int16_t i = 0; i < kNumRegisters; i++) {
1876 if ((regs & (1 << i)) != 0) {
1877 ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
1878 stack_offset += kDoubleSize;
1879 }
1880 }
1881 daddiu(sp, sp, stack_offset);
1882}
1883
1884
1885void MacroAssembler::MultiPopReversedFPU(RegList regs) {
1886 int16_t stack_offset = 0;
1887
1888 for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
1889 if ((regs & (1 << i)) != 0) {
1890 ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
1891 stack_offset += kDoubleSize;
1892 }
1893 }
1894 daddiu(sp, sp, stack_offset);
1895}
1896
1897
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001898void MacroAssembler::Ext(Register rt,
1899 Register rs,
1900 uint16_t pos,
1901 uint16_t size) {
1902 DCHECK(pos < 32);
1903 DCHECK(pos + size < 33);
1904 ext_(rt, rs, pos, size);
1905}
1906
1907
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001908void MacroAssembler::Dext(Register rt, Register rs, uint16_t pos,
1909 uint16_t size) {
1910 DCHECK(pos < 32);
1911 DCHECK(pos + size < 33);
1912 dext_(rt, rs, pos, size);
1913}
1914
1915
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001916void MacroAssembler::Dextm(Register rt, Register rs, uint16_t pos,
1917 uint16_t size) {
1918 DCHECK(pos < 32);
1919 DCHECK(size <= 64);
1920 dextm(rt, rs, pos, size);
1921}
1922
1923
1924void MacroAssembler::Dextu(Register rt, Register rs, uint16_t pos,
1925 uint16_t size) {
1926 DCHECK(pos >= 32 && pos < 64);
1927 DCHECK(size < 33);
1928 dextu(rt, rs, pos, size);
1929}
1930
1931
1932void MacroAssembler::Dins(Register rt, Register rs, uint16_t pos,
1933 uint16_t size) {
1934 DCHECK(pos < 32);
1935 DCHECK(pos + size <= 32);
1936 DCHECK(size != 0);
1937 dins_(rt, rs, pos, size);
1938}
1939
1940
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001941void MacroAssembler::Ins(Register rt,
1942 Register rs,
1943 uint16_t pos,
1944 uint16_t size) {
1945 DCHECK(pos < 32);
1946 DCHECK(pos + size <= 32);
1947 DCHECK(size != 0);
1948 ins_(rt, rs, pos, size);
1949}
1950
1951
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001952void MacroAssembler::Cvt_d_uw(FPURegister fd, FPURegister fs) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001953 // Move the data from fs to t8.
1954 mfc1(t8, fs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001955 Cvt_d_uw(fd, t8);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001956}
1957
1958
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001959void MacroAssembler::Cvt_d_uw(FPURegister fd, Register rs) {
1960 // Convert rs to a FP value in fd.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001961 DCHECK(!rs.is(t9));
1962 DCHECK(!rs.is(at));
1963
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001964 // Zero extend int32 in rs.
1965 Dext(t9, rs, 0, 32);
1966 dmtc1(t9, fd);
1967 cvt_d_l(fd, fd);
1968}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001969
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001970
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001971void MacroAssembler::Cvt_d_ul(FPURegister fd, FPURegister fs) {
1972 // Move the data from fs to t8.
1973 dmfc1(t8, fs);
1974 Cvt_d_ul(fd, t8);
1975}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001976
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001977
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001978void MacroAssembler::Cvt_d_ul(FPURegister fd, Register rs) {
1979 // Convert rs to a FP value in fd.
1980
1981 DCHECK(!rs.is(t9));
1982 DCHECK(!rs.is(at));
1983
1984 Label msb_clear, conversion_done;
1985
1986 Branch(&msb_clear, ge, rs, Operand(zero_reg));
1987
1988 // Rs >= 2^63
1989 andi(t9, rs, 1);
1990 dsrl(rs, rs, 1);
1991 or_(t9, t9, rs);
1992 dmtc1(t9, fd);
1993 cvt_d_l(fd, fd);
1994 Branch(USE_DELAY_SLOT, &conversion_done);
1995 add_d(fd, fd, fd); // In delay slot.
1996
1997 bind(&msb_clear);
1998 // Rs < 2^63, we can do simple conversion.
1999 dmtc1(rs, fd);
2000 cvt_d_l(fd, fd);
2001
2002 bind(&conversion_done);
2003}
2004
Ben Murdoch097c5b22016-05-18 11:27:45 +01002005void MacroAssembler::Cvt_s_uw(FPURegister fd, FPURegister fs) {
2006 // Move the data from fs to t8.
2007 mfc1(t8, fs);
2008 Cvt_s_uw(fd, t8);
2009}
2010
2011void MacroAssembler::Cvt_s_uw(FPURegister fd, Register rs) {
2012 // Convert rs to a FP value in fd.
2013 DCHECK(!rs.is(t9));
2014 DCHECK(!rs.is(at));
2015
2016 // Zero extend int32 in rs.
2017 Dext(t9, rs, 0, 32);
2018 dmtc1(t9, fd);
2019 cvt_s_l(fd, fd);
2020}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002021
2022void MacroAssembler::Cvt_s_ul(FPURegister fd, FPURegister fs) {
2023 // Move the data from fs to t8.
2024 dmfc1(t8, fs);
2025 Cvt_s_ul(fd, t8);
2026}
2027
2028
2029void MacroAssembler::Cvt_s_ul(FPURegister fd, Register rs) {
2030 // Convert rs to a FP value in fd.
2031
2032 DCHECK(!rs.is(t9));
2033 DCHECK(!rs.is(at));
2034
2035 Label positive, conversion_done;
2036
2037 Branch(&positive, ge, rs, Operand(zero_reg));
2038
2039 // Rs >= 2^31.
2040 andi(t9, rs, 1);
2041 dsrl(rs, rs, 1);
2042 or_(t9, t9, rs);
2043 dmtc1(t9, fd);
2044 cvt_s_l(fd, fd);
2045 Branch(USE_DELAY_SLOT, &conversion_done);
2046 add_s(fd, fd, fd); // In delay slot.
2047
2048 bind(&positive);
2049 // Rs < 2^31, we can do simple conversion.
2050 dmtc1(rs, fd);
2051 cvt_s_l(fd, fd);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002052
2053 bind(&conversion_done);
2054}
2055
2056
2057void MacroAssembler::Round_l_d(FPURegister fd, FPURegister fs) {
2058 round_l_d(fd, fs);
2059}
2060
2061
2062void MacroAssembler::Floor_l_d(FPURegister fd, FPURegister fs) {
2063 floor_l_d(fd, fs);
2064}
2065
2066
2067void MacroAssembler::Ceil_l_d(FPURegister fd, FPURegister fs) {
2068 ceil_l_d(fd, fs);
2069}
2070
2071
2072void MacroAssembler::Trunc_l_d(FPURegister fd, FPURegister fs) {
2073 trunc_l_d(fd, fs);
2074}
2075
2076
2077void MacroAssembler::Trunc_l_ud(FPURegister fd,
2078 FPURegister fs,
2079 FPURegister scratch) {
2080 // Load to GPR.
2081 dmfc1(t8, fs);
2082 // Reset sign bit.
2083 li(at, 0x7fffffffffffffff);
2084 and_(t8, t8, at);
2085 dmtc1(t8, fs);
2086 trunc_l_d(fd, fs);
2087}
2088
2089
2090void MacroAssembler::Trunc_uw_d(FPURegister fd,
2091 FPURegister fs,
2092 FPURegister scratch) {
2093 Trunc_uw_d(fs, t8, scratch);
2094 mtc1(t8, fd);
2095}
2096
Ben Murdoch097c5b22016-05-18 11:27:45 +01002097void MacroAssembler::Trunc_uw_s(FPURegister fd, FPURegister fs,
2098 FPURegister scratch) {
2099 Trunc_uw_s(fs, t8, scratch);
2100 mtc1(t8, fd);
2101}
2102
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002103void MacroAssembler::Trunc_ul_d(FPURegister fd, FPURegister fs,
2104 FPURegister scratch, Register result) {
2105 Trunc_ul_d(fs, t8, scratch, result);
2106 dmtc1(t8, fd);
2107}
2108
2109
2110void MacroAssembler::Trunc_ul_s(FPURegister fd, FPURegister fs,
2111 FPURegister scratch, Register result) {
2112 Trunc_ul_s(fs, t8, scratch, result);
2113 dmtc1(t8, fd);
2114}
2115
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002116
2117void MacroAssembler::Trunc_w_d(FPURegister fd, FPURegister fs) {
2118 trunc_w_d(fd, fs);
2119}
2120
2121
2122void MacroAssembler::Round_w_d(FPURegister fd, FPURegister fs) {
2123 round_w_d(fd, fs);
2124}
2125
2126
2127void MacroAssembler::Floor_w_d(FPURegister fd, FPURegister fs) {
2128 floor_w_d(fd, fs);
2129}
2130
2131
2132void MacroAssembler::Ceil_w_d(FPURegister fd, FPURegister fs) {
2133 ceil_w_d(fd, fs);
2134}
2135
2136
2137void MacroAssembler::Trunc_uw_d(FPURegister fd,
2138 Register rs,
2139 FPURegister scratch) {
2140 DCHECK(!fd.is(scratch));
2141 DCHECK(!rs.is(at));
2142
2143 // Load 2^31 into scratch as its float representation.
2144 li(at, 0x41E00000);
2145 mtc1(zero_reg, scratch);
2146 mthc1(at, scratch);
2147 // Test if scratch > fd.
2148 // If fd < 2^31 we can convert it normally.
2149 Label simple_convert;
2150 BranchF(&simple_convert, NULL, lt, fd, scratch);
2151
2152 // First we subtract 2^31 from fd, then trunc it to rs
2153 // and add 2^31 to rs.
2154 sub_d(scratch, fd, scratch);
2155 trunc_w_d(scratch, scratch);
2156 mfc1(rs, scratch);
2157 Or(rs, rs, 1 << 31);
2158
2159 Label done;
2160 Branch(&done);
2161 // Simple conversion.
2162 bind(&simple_convert);
2163 trunc_w_d(scratch, fd);
2164 mfc1(rs, scratch);
2165
2166 bind(&done);
2167}
2168
Ben Murdoch097c5b22016-05-18 11:27:45 +01002169void MacroAssembler::Trunc_uw_s(FPURegister fd, Register rs,
2170 FPURegister scratch) {
2171 DCHECK(!fd.is(scratch));
2172 DCHECK(!rs.is(at));
2173
2174 // Load 2^31 into scratch as its float representation.
2175 li(at, 0x4F000000);
2176 mtc1(at, scratch);
2177 // Test if scratch > fd.
2178 // If fd < 2^31 we can convert it normally.
2179 Label simple_convert;
2180 BranchF32(&simple_convert, NULL, lt, fd, scratch);
2181
2182 // First we subtract 2^31 from fd, then trunc it to rs
2183 // and add 2^31 to rs.
2184 sub_s(scratch, fd, scratch);
2185 trunc_w_s(scratch, scratch);
2186 mfc1(rs, scratch);
2187 Or(rs, rs, 1 << 31);
2188
2189 Label done;
2190 Branch(&done);
2191 // Simple conversion.
2192 bind(&simple_convert);
2193 trunc_w_s(scratch, fd);
2194 mfc1(rs, scratch);
2195
2196 bind(&done);
2197}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002198
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002199void MacroAssembler::Trunc_ul_d(FPURegister fd, Register rs,
2200 FPURegister scratch, Register result) {
2201 DCHECK(!fd.is(scratch));
2202 DCHECK(!AreAliased(rs, result, at));
2203
2204 Label simple_convert, done, fail;
2205 if (result.is_valid()) {
2206 mov(result, zero_reg);
2207 Move(scratch, -1.0);
2208 // If fd =< -1 or unordered, then the conversion fails.
2209 BranchF(&fail, &fail, le, fd, scratch);
2210 }
2211
2212 // Load 2^63 into scratch as its double representation.
2213 li(at, 0x43e0000000000000);
2214 dmtc1(at, scratch);
2215
2216 // Test if scratch > fd.
2217 // If fd < 2^63 we can convert it normally.
2218 BranchF(&simple_convert, nullptr, lt, fd, scratch);
2219
2220 // First we subtract 2^63 from fd, then trunc it to rs
2221 // and add 2^63 to rs.
2222 sub_d(scratch, fd, scratch);
2223 trunc_l_d(scratch, scratch);
2224 dmfc1(rs, scratch);
2225 Or(rs, rs, Operand(1UL << 63));
2226 Branch(&done);
2227
2228 // Simple conversion.
2229 bind(&simple_convert);
2230 trunc_l_d(scratch, fd);
2231 dmfc1(rs, scratch);
2232
2233 bind(&done);
2234 if (result.is_valid()) {
2235 // Conversion is failed if the result is negative.
2236 addiu(at, zero_reg, -1);
2237 dsrl(at, at, 1); // Load 2^62.
2238 dmfc1(result, scratch);
2239 xor_(result, result, at);
2240 Slt(result, zero_reg, result);
2241 }
2242
2243 bind(&fail);
2244}
2245
2246
2247void MacroAssembler::Trunc_ul_s(FPURegister fd, Register rs,
2248 FPURegister scratch, Register result) {
2249 DCHECK(!fd.is(scratch));
2250 DCHECK(!AreAliased(rs, result, at));
2251
2252 Label simple_convert, done, fail;
2253 if (result.is_valid()) {
2254 mov(result, zero_reg);
2255 Move(scratch, -1.0f);
2256 // If fd =< -1 or unordered, then the conversion fails.
2257 BranchF32(&fail, &fail, le, fd, scratch);
2258 }
2259
2260 // Load 2^63 into scratch as its float representation.
2261 li(at, 0x5f000000);
2262 mtc1(at, scratch);
2263
2264 // Test if scratch > fd.
2265 // If fd < 2^63 we can convert it normally.
2266 BranchF32(&simple_convert, nullptr, lt, fd, scratch);
2267
2268 // First we subtract 2^63 from fd, then trunc it to rs
2269 // and add 2^63 to rs.
2270 sub_s(scratch, fd, scratch);
2271 trunc_l_s(scratch, scratch);
2272 dmfc1(rs, scratch);
2273 Or(rs, rs, Operand(1UL << 63));
2274 Branch(&done);
2275
2276 // Simple conversion.
2277 bind(&simple_convert);
2278 trunc_l_s(scratch, fd);
2279 dmfc1(rs, scratch);
2280
2281 bind(&done);
2282 if (result.is_valid()) {
2283 // Conversion is failed if the result is negative or unordered.
2284 addiu(at, zero_reg, -1);
2285 dsrl(at, at, 1); // Load 2^62.
2286 dmfc1(result, scratch);
2287 xor_(result, result, at);
2288 Slt(result, zero_reg, result);
2289 }
2290
2291 bind(&fail);
2292}
2293
2294
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002295void MacroAssembler::Madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
2296 FPURegister ft, FPURegister scratch) {
2297 if (0) { // TODO(plind): find reasonable arch-variant symbol names.
2298 madd_d(fd, fr, fs, ft);
2299 } else {
2300 // Can not change source regs's value.
2301 DCHECK(!fr.is(scratch) && !fs.is(scratch) && !ft.is(scratch));
2302 mul_d(scratch, fs, ft);
2303 add_d(fd, fr, scratch);
2304 }
2305}
2306
2307
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002308void MacroAssembler::BranchFCommon(SecondaryField sizeField, Label* target,
2309 Label* nan, Condition cond, FPURegister cmp1,
2310 FPURegister cmp2, BranchDelaySlot bd) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002311 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002312 if (cond == al) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002313 Branch(bd, target);
2314 return;
2315 }
2316
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002317 if (kArchVariant == kMips64r6) {
2318 sizeField = sizeField == D ? L : W;
2319 }
2320
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002321 DCHECK(nan || target);
2322 // Check for unordered (NaN) cases.
2323 if (nan) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002324 bool long_branch = nan->is_bound() ? is_near(nan) : is_trampoline_emitted();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002325 if (kArchVariant != kMips64r6) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002326 if (long_branch) {
2327 Label skip;
2328 c(UN, sizeField, cmp1, cmp2);
2329 bc1f(&skip);
2330 nop();
2331 BranchLong(nan, bd);
2332 bind(&skip);
2333 } else {
2334 c(UN, sizeField, cmp1, cmp2);
2335 bc1t(nan);
2336 if (bd == PROTECT) {
2337 nop();
2338 }
2339 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002340 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002341 // Use kDoubleCompareReg for comparison result. It has to be unavailable
2342 // to lithium
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002343 // register allocator.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002344 DCHECK(!cmp1.is(kDoubleCompareReg) && !cmp2.is(kDoubleCompareReg));
2345 if (long_branch) {
2346 Label skip;
2347 cmp(UN, sizeField, kDoubleCompareReg, cmp1, cmp2);
2348 bc1eqz(&skip, kDoubleCompareReg);
2349 nop();
2350 BranchLong(nan, bd);
2351 bind(&skip);
2352 } else {
2353 cmp(UN, sizeField, kDoubleCompareReg, cmp1, cmp2);
2354 bc1nez(nan, kDoubleCompareReg);
2355 if (bd == PROTECT) {
2356 nop();
2357 }
2358 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002359 }
2360 }
2361
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002362 if (target) {
2363 bool long_branch =
2364 target->is_bound() ? is_near(target) : is_trampoline_emitted();
2365 if (long_branch) {
2366 Label skip;
2367 Condition neg_cond = NegateFpuCondition(cond);
2368 BranchShortF(sizeField, &skip, neg_cond, cmp1, cmp2, bd);
2369 BranchLong(target, bd);
2370 bind(&skip);
2371 } else {
2372 BranchShortF(sizeField, target, cond, cmp1, cmp2, bd);
2373 }
2374 }
2375}
2376
2377
2378void MacroAssembler::BranchShortF(SecondaryField sizeField, Label* target,
2379 Condition cc, FPURegister cmp1,
2380 FPURegister cmp2, BranchDelaySlot bd) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002381 if (kArchVariant != kMips64r6) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002382 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002383 if (target) {
2384 // Here NaN cases were either handled by this function or are assumed to
2385 // have been handled by the caller.
2386 switch (cc) {
2387 case lt:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002388 c(OLT, sizeField, cmp1, cmp2);
2389 bc1t(target);
2390 break;
2391 case ult:
2392 c(ULT, sizeField, cmp1, cmp2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002393 bc1t(target);
2394 break;
2395 case gt:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002396 c(ULE, sizeField, cmp1, cmp2);
2397 bc1f(target);
2398 break;
2399 case ugt:
2400 c(OLE, sizeField, cmp1, cmp2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002401 bc1f(target);
2402 break;
2403 case ge:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002404 c(ULT, sizeField, cmp1, cmp2);
2405 bc1f(target);
2406 break;
2407 case uge:
2408 c(OLT, sizeField, cmp1, cmp2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002409 bc1f(target);
2410 break;
2411 case le:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002412 c(OLE, sizeField, cmp1, cmp2);
2413 bc1t(target);
2414 break;
2415 case ule:
2416 c(ULE, sizeField, cmp1, cmp2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002417 bc1t(target);
2418 break;
2419 case eq:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002420 c(EQ, sizeField, cmp1, cmp2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002421 bc1t(target);
2422 break;
2423 case ueq:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002424 c(UEQ, sizeField, cmp1, cmp2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002425 bc1t(target);
2426 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002427 case ne: // Unordered or not equal.
2428 c(EQ, sizeField, cmp1, cmp2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002429 bc1f(target);
2430 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002431 case ogl:
2432 c(UEQ, sizeField, cmp1, cmp2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002433 bc1f(target);
2434 break;
2435 default:
2436 CHECK(0);
2437 }
2438 }
2439 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002440 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002441 if (target) {
2442 // Here NaN cases were either handled by this function or are assumed to
2443 // have been handled by the caller.
2444 // Unsigned conditions are treated as their signed counterpart.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002445 // Use kDoubleCompareReg for comparison result, it is valid in fp64 (FR =
2446 // 1) mode.
2447 DCHECK(!cmp1.is(kDoubleCompareReg) && !cmp2.is(kDoubleCompareReg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002448 switch (cc) {
2449 case lt:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002450 cmp(OLT, sizeField, kDoubleCompareReg, cmp1, cmp2);
2451 bc1nez(target, kDoubleCompareReg);
2452 break;
2453 case ult:
2454 cmp(ULT, sizeField, kDoubleCompareReg, cmp1, cmp2);
2455 bc1nez(target, kDoubleCompareReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002456 break;
2457 case gt:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002458 cmp(ULE, sizeField, kDoubleCompareReg, cmp1, cmp2);
2459 bc1eqz(target, kDoubleCompareReg);
2460 break;
2461 case ugt:
2462 cmp(OLE, sizeField, kDoubleCompareReg, cmp1, cmp2);
2463 bc1eqz(target, kDoubleCompareReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002464 break;
2465 case ge:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002466 cmp(ULT, sizeField, kDoubleCompareReg, cmp1, cmp2);
2467 bc1eqz(target, kDoubleCompareReg);
2468 break;
2469 case uge:
2470 cmp(OLT, sizeField, kDoubleCompareReg, cmp1, cmp2);
2471 bc1eqz(target, kDoubleCompareReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002472 break;
2473 case le:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002474 cmp(OLE, sizeField, kDoubleCompareReg, cmp1, cmp2);
2475 bc1nez(target, kDoubleCompareReg);
2476 break;
2477 case ule:
2478 cmp(ULE, sizeField, kDoubleCompareReg, cmp1, cmp2);
2479 bc1nez(target, kDoubleCompareReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002480 break;
2481 case eq:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002482 cmp(EQ, sizeField, kDoubleCompareReg, cmp1, cmp2);
2483 bc1nez(target, kDoubleCompareReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002484 break;
2485 case ueq:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002486 cmp(UEQ, sizeField, kDoubleCompareReg, cmp1, cmp2);
2487 bc1nez(target, kDoubleCompareReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002488 break;
2489 case ne:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002490 cmp(EQ, sizeField, kDoubleCompareReg, cmp1, cmp2);
2491 bc1eqz(target, kDoubleCompareReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002492 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002493 case ogl:
2494 cmp(UEQ, sizeField, kDoubleCompareReg, cmp1, cmp2);
2495 bc1eqz(target, kDoubleCompareReg);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002496 break;
2497 default:
2498 CHECK(0);
2499 }
2500 }
2501 }
2502
2503 if (bd == PROTECT) {
2504 nop();
2505 }
2506}
2507
2508
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002509void MacroAssembler::FmoveLow(FPURegister dst, Register src_low) {
2510 DCHECK(!src_low.is(at));
2511 mfhc1(at, dst);
2512 mtc1(src_low, dst);
2513 mthc1(at, dst);
2514}
2515
2516
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002517void MacroAssembler::Move(FPURegister dst, float imm) {
2518 li(at, Operand(bit_cast<int32_t>(imm)));
2519 mtc1(at, dst);
2520}
2521
2522
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002523void MacroAssembler::Move(FPURegister dst, double imm) {
2524 static const DoubleRepresentation minus_zero(-0.0);
2525 static const DoubleRepresentation zero(0.0);
2526 DoubleRepresentation value_rep(imm);
2527 // Handle special values first.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002528 if (value_rep == zero && has_double_zero_reg_set_) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002529 mov_d(dst, kDoubleRegZero);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002530 } else if (value_rep == minus_zero && has_double_zero_reg_set_) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002531 neg_d(dst, kDoubleRegZero);
2532 } else {
2533 uint32_t lo, hi;
2534 DoubleAsTwoUInt32(imm, &lo, &hi);
2535 // Move the low part of the double into the lower bits of the corresponding
2536 // FPU register.
2537 if (lo != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002538 if (!(lo & kImm16Mask)) {
2539 lui(at, (lo >> kLuiShift) & kImm16Mask);
2540 mtc1(at, dst);
2541 } else if (!(lo & kHiMask)) {
2542 ori(at, zero_reg, lo & kImm16Mask);
2543 mtc1(at, dst);
2544 } else {
2545 lui(at, (lo >> kLuiShift) & kImm16Mask);
2546 ori(at, at, lo & kImm16Mask);
2547 mtc1(at, dst);
2548 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002549 } else {
2550 mtc1(zero_reg, dst);
2551 }
2552 // Move the high part of the double into the high bits of the corresponding
2553 // FPU register.
2554 if (hi != 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002555 if (!(hi & kImm16Mask)) {
2556 lui(at, (hi >> kLuiShift) & kImm16Mask);
2557 mthc1(at, dst);
2558 } else if (!(hi & kHiMask)) {
2559 ori(at, zero_reg, hi & kImm16Mask);
2560 mthc1(at, dst);
2561 } else {
2562 lui(at, (hi >> kLuiShift) & kImm16Mask);
2563 ori(at, at, hi & kImm16Mask);
2564 mthc1(at, dst);
2565 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002566 } else {
2567 mthc1(zero_reg, dst);
2568 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002569 if (dst.is(kDoubleRegZero)) has_double_zero_reg_set_ = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002570 }
2571}
2572
2573
2574void MacroAssembler::Movz(Register rd, Register rs, Register rt) {
2575 if (kArchVariant == kMips64r6) {
2576 Label done;
2577 Branch(&done, ne, rt, Operand(zero_reg));
2578 mov(rd, rs);
2579 bind(&done);
2580 } else {
2581 movz(rd, rs, rt);
2582 }
2583}
2584
2585
2586void MacroAssembler::Movn(Register rd, Register rs, Register rt) {
2587 if (kArchVariant == kMips64r6) {
2588 Label done;
2589 Branch(&done, eq, rt, Operand(zero_reg));
2590 mov(rd, rs);
2591 bind(&done);
2592 } else {
2593 movn(rd, rs, rt);
2594 }
2595}
2596
2597
2598void MacroAssembler::Movt(Register rd, Register rs, uint16_t cc) {
2599 movt(rd, rs, cc);
2600}
2601
2602
2603void MacroAssembler::Movf(Register rd, Register rs, uint16_t cc) {
2604 movf(rd, rs, cc);
2605}
2606
Ben Murdochda12d292016-06-02 14:46:10 +01002607#define __ masm->
2608
2609static bool ZeroHelper_d(MacroAssembler* masm, MaxMinKind kind, FPURegister dst,
2610 FPURegister src1, FPURegister src2, Label* equal) {
2611 if (src1.is(src2)) {
2612 __ Move(dst, src1);
2613 return true;
2614 }
2615
2616 Label other, compare_not_equal;
2617 FPURegister left, right;
2618 if (kind == MaxMinKind::kMin) {
2619 left = src1;
2620 right = src2;
2621 } else {
2622 left = src2;
2623 right = src1;
2624 }
2625
2626 __ BranchF64(&compare_not_equal, nullptr, ne, src1, src2);
2627 // Left and right hand side are equal, check for -0 vs. +0.
2628 __ dmfc1(t8, src1);
2629 __ Branch(&other, eq, t8, Operand(0x8000000000000000));
2630 __ Move_d(dst, right);
2631 __ Branch(equal);
2632 __ bind(&other);
2633 __ Move_d(dst, left);
2634 __ Branch(equal);
2635 __ bind(&compare_not_equal);
2636 return false;
2637}
2638
2639static bool ZeroHelper_s(MacroAssembler* masm, MaxMinKind kind, FPURegister dst,
2640 FPURegister src1, FPURegister src2, Label* equal) {
2641 if (src1.is(src2)) {
2642 __ Move(dst, src1);
2643 return true;
2644 }
2645
2646 Label other, compare_not_equal;
2647 FPURegister left, right;
2648 if (kind == MaxMinKind::kMin) {
2649 left = src1;
2650 right = src2;
2651 } else {
2652 left = src2;
2653 right = src1;
2654 }
2655
2656 __ BranchF32(&compare_not_equal, nullptr, ne, src1, src2);
2657 // Left and right hand side are equal, check for -0 vs. +0.
2658 __ FmoveLow(t8, src1);
2659 __ dsll32(t8, t8, 0);
2660 __ Branch(&other, eq, t8, Operand(0x8000000000000000));
2661 __ Move_s(dst, right);
2662 __ Branch(equal);
2663 __ bind(&other);
2664 __ Move_s(dst, left);
2665 __ Branch(equal);
2666 __ bind(&compare_not_equal);
2667 return false;
2668}
2669
2670#undef __
2671
2672void MacroAssembler::MinNaNCheck_d(FPURegister dst, FPURegister src1,
2673 FPURegister src2, Label* nan) {
2674 if (nan) {
2675 BranchF64(nullptr, nan, eq, src1, src2);
2676 }
2677 if (kArchVariant >= kMips64r6) {
2678 min_d(dst, src1, src2);
2679 } else {
2680 Label skip;
2681 if (!ZeroHelper_d(this, MaxMinKind::kMin, dst, src1, src2, &skip)) {
2682 if (dst.is(src1)) {
2683 BranchF64(&skip, nullptr, le, src1, src2);
2684 Move_d(dst, src2);
2685 } else if (dst.is(src2)) {
2686 BranchF64(&skip, nullptr, ge, src1, src2);
2687 Move_d(dst, src1);
2688 } else {
2689 Label right;
2690 BranchF64(&right, nullptr, gt, src1, src2);
2691 Move_d(dst, src1);
2692 Branch(&skip);
2693 bind(&right);
2694 Move_d(dst, src2);
2695 }
2696 }
2697 bind(&skip);
2698 }
2699}
2700
2701void MacroAssembler::MaxNaNCheck_d(FPURegister dst, FPURegister src1,
2702 FPURegister src2, Label* nan) {
2703 if (nan) {
2704 BranchF64(nullptr, nan, eq, src1, src2);
2705 }
2706 if (kArchVariant >= kMips64r6) {
2707 max_d(dst, src1, src2);
2708 } else {
2709 Label skip;
2710 if (!ZeroHelper_d(this, MaxMinKind::kMax, dst, src1, src2, &skip)) {
2711 if (dst.is(src1)) {
2712 BranchF64(&skip, nullptr, ge, src1, src2);
2713 Move_d(dst, src2);
2714 } else if (dst.is(src2)) {
2715 BranchF64(&skip, nullptr, le, src1, src2);
2716 Move_d(dst, src1);
2717 } else {
2718 Label right;
2719 BranchF64(&right, nullptr, lt, src1, src2);
2720 Move_d(dst, src1);
2721 Branch(&skip);
2722 bind(&right);
2723 Move_d(dst, src2);
2724 }
2725 }
2726 bind(&skip);
2727 }
2728}
2729
2730void MacroAssembler::MinNaNCheck_s(FPURegister dst, FPURegister src1,
2731 FPURegister src2, Label* nan) {
2732 if (nan) {
2733 BranchF32(nullptr, nan, eq, src1, src2);
2734 }
2735 if (kArchVariant >= kMips64r6) {
2736 min_s(dst, src1, src2);
2737 } else {
2738 Label skip;
2739 if (!ZeroHelper_s(this, MaxMinKind::kMin, dst, src1, src2, &skip)) {
2740 if (dst.is(src1)) {
2741 BranchF32(&skip, nullptr, le, src1, src2);
2742 Move_s(dst, src2);
2743 } else if (dst.is(src2)) {
2744 BranchF32(&skip, nullptr, ge, src1, src2);
2745 Move_s(dst, src1);
2746 } else {
2747 Label right;
2748 BranchF32(&right, nullptr, gt, src1, src2);
2749 Move_s(dst, src1);
2750 Branch(&skip);
2751 bind(&right);
2752 Move_s(dst, src2);
2753 }
2754 }
2755 bind(&skip);
2756 }
2757}
2758
2759void MacroAssembler::MaxNaNCheck_s(FPURegister dst, FPURegister src1,
2760 FPURegister src2, Label* nan) {
2761 if (nan) {
2762 BranchF32(nullptr, nan, eq, src1, src2);
2763 }
2764 if (kArchVariant >= kMips64r6) {
2765 max_s(dst, src1, src2);
2766 } else {
2767 Label skip;
2768 if (!ZeroHelper_s(this, MaxMinKind::kMax, dst, src1, src2, &skip)) {
2769 if (dst.is(src1)) {
2770 BranchF32(&skip, nullptr, ge, src1, src2);
2771 Move_s(dst, src2);
2772 } else if (dst.is(src2)) {
2773 BranchF32(&skip, nullptr, le, src1, src2);
2774 Move_s(dst, src1);
2775 } else {
2776 Label right;
2777 BranchF32(&right, nullptr, lt, src1, src2);
2778 Move_s(dst, src1);
2779 Branch(&skip);
2780 bind(&right);
2781 Move_s(dst, src2);
2782 }
2783 }
2784 bind(&skip);
2785 }
2786}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002787
2788void MacroAssembler::Clz(Register rd, Register rs) {
2789 clz(rd, rs);
2790}
2791
2792
2793void MacroAssembler::EmitFPUTruncate(FPURoundingMode rounding_mode,
2794 Register result,
2795 DoubleRegister double_input,
2796 Register scratch,
2797 DoubleRegister double_scratch,
2798 Register except_flag,
2799 CheckForInexactConversion check_inexact) {
2800 DCHECK(!result.is(scratch));
2801 DCHECK(!double_input.is(double_scratch));
2802 DCHECK(!except_flag.is(scratch));
2803
2804 Label done;
2805
2806 // Clear the except flag (0 = no exception)
2807 mov(except_flag, zero_reg);
2808
2809 // Test for values that can be exactly represented as a signed 32-bit integer.
2810 cvt_w_d(double_scratch, double_input);
2811 mfc1(result, double_scratch);
2812 cvt_d_w(double_scratch, double_scratch);
2813 BranchF(&done, NULL, eq, double_input, double_scratch);
2814
2815 int32_t except_mask = kFCSRFlagMask; // Assume interested in all exceptions.
2816
2817 if (check_inexact == kDontCheckForInexactConversion) {
2818 // Ignore inexact exceptions.
2819 except_mask &= ~kFCSRInexactFlagMask;
2820 }
2821
2822 // Save FCSR.
2823 cfc1(scratch, FCSR);
2824 // Disable FPU exceptions.
2825 ctc1(zero_reg, FCSR);
2826
2827 // Do operation based on rounding mode.
2828 switch (rounding_mode) {
2829 case kRoundToNearest:
2830 Round_w_d(double_scratch, double_input);
2831 break;
2832 case kRoundToZero:
2833 Trunc_w_d(double_scratch, double_input);
2834 break;
2835 case kRoundToPlusInf:
2836 Ceil_w_d(double_scratch, double_input);
2837 break;
2838 case kRoundToMinusInf:
2839 Floor_w_d(double_scratch, double_input);
2840 break;
2841 } // End of switch-statement.
2842
2843 // Retrieve FCSR.
2844 cfc1(except_flag, FCSR);
2845 // Restore FCSR.
2846 ctc1(scratch, FCSR);
2847 // Move the converted value into the result register.
2848 mfc1(result, double_scratch);
2849
2850 // Check for fpu exceptions.
2851 And(except_flag, except_flag, Operand(except_mask));
2852
2853 bind(&done);
2854}
2855
2856
2857void MacroAssembler::TryInlineTruncateDoubleToI(Register result,
2858 DoubleRegister double_input,
2859 Label* done) {
2860 DoubleRegister single_scratch = kLithiumScratchDouble.low();
2861 Register scratch = at;
2862 Register scratch2 = t9;
2863
2864 // Clear cumulative exception flags and save the FCSR.
2865 cfc1(scratch2, FCSR);
2866 ctc1(zero_reg, FCSR);
2867 // Try a conversion to a signed integer.
2868 trunc_w_d(single_scratch, double_input);
2869 mfc1(result, single_scratch);
2870 // Retrieve and restore the FCSR.
2871 cfc1(scratch, FCSR);
2872 ctc1(scratch2, FCSR);
2873 // Check for overflow and NaNs.
2874 And(scratch,
2875 scratch,
2876 kFCSROverflowFlagMask | kFCSRUnderflowFlagMask | kFCSRInvalidOpFlagMask);
2877 // If we had no exceptions we are done.
2878 Branch(done, eq, scratch, Operand(zero_reg));
2879}
2880
2881
2882void MacroAssembler::TruncateDoubleToI(Register result,
2883 DoubleRegister double_input) {
2884 Label done;
2885
2886 TryInlineTruncateDoubleToI(result, double_input, &done);
2887
2888 // If we fell through then inline version didn't succeed - call stub instead.
2889 push(ra);
2890 Dsubu(sp, sp, Operand(kDoubleSize)); // Put input on stack.
2891 sdc1(double_input, MemOperand(sp, 0));
2892
2893 DoubleToIStub stub(isolate(), sp, result, 0, true, true);
2894 CallStub(&stub);
2895
2896 Daddu(sp, sp, Operand(kDoubleSize));
2897 pop(ra);
2898
2899 bind(&done);
2900}
2901
2902
2903void MacroAssembler::TruncateHeapNumberToI(Register result, Register object) {
2904 Label done;
2905 DoubleRegister double_scratch = f12;
2906 DCHECK(!result.is(object));
2907
2908 ldc1(double_scratch,
2909 MemOperand(object, HeapNumber::kValueOffset - kHeapObjectTag));
2910 TryInlineTruncateDoubleToI(result, double_scratch, &done);
2911
2912 // If we fell through then inline version didn't succeed - call stub instead.
2913 push(ra);
2914 DoubleToIStub stub(isolate(),
2915 object,
2916 result,
2917 HeapNumber::kValueOffset - kHeapObjectTag,
2918 true,
2919 true);
2920 CallStub(&stub);
2921 pop(ra);
2922
2923 bind(&done);
2924}
2925
2926
2927void MacroAssembler::TruncateNumberToI(Register object,
2928 Register result,
2929 Register heap_number_map,
2930 Register scratch,
2931 Label* not_number) {
2932 Label done;
2933 DCHECK(!result.is(object));
2934
2935 UntagAndJumpIfSmi(result, object, &done);
2936 JumpIfNotHeapNumber(object, heap_number_map, scratch, not_number);
2937 TruncateHeapNumberToI(result, object);
2938
2939 bind(&done);
2940}
2941
2942
2943void MacroAssembler::GetLeastBitsFromSmi(Register dst,
2944 Register src,
2945 int num_least_bits) {
2946 // Ext(dst, src, kSmiTagSize, num_least_bits);
2947 SmiUntag(dst, src);
2948 And(dst, dst, Operand((1 << num_least_bits) - 1));
2949}
2950
2951
2952void MacroAssembler::GetLeastBitsFromInt32(Register dst,
2953 Register src,
2954 int num_least_bits) {
2955 DCHECK(!src.is(dst));
2956 And(dst, src, Operand((1 << num_least_bits) - 1));
2957}
2958
2959
2960// Emulated condtional branches do not emit a nop in the branch delay slot.
2961//
2962// BRANCH_ARGS_CHECK checks that conditional jump arguments are correct.
2963#define BRANCH_ARGS_CHECK(cond, rs, rt) DCHECK( \
2964 (cond == cc_always && rs.is(zero_reg) && rt.rm().is(zero_reg)) || \
2965 (cond != cc_always && (!rs.is(zero_reg) || !rt.rm().is(zero_reg))))
2966
2967
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002968void MacroAssembler::Branch(int32_t offset, BranchDelaySlot bdslot) {
2969 DCHECK(kArchVariant == kMips64r6 ? is_int26(offset) : is_int16(offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002970 BranchShort(offset, bdslot);
2971}
2972
2973
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002974void MacroAssembler::Branch(int32_t offset, Condition cond, Register rs,
2975 const Operand& rt, BranchDelaySlot bdslot) {
2976 bool is_near = BranchShortCheck(offset, nullptr, cond, rs, rt, bdslot);
2977 DCHECK(is_near);
2978 USE(is_near);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002979}
2980
2981
2982void MacroAssembler::Branch(Label* L, BranchDelaySlot bdslot) {
2983 if (L->is_bound()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002984 if (is_near_branch(L)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002985 BranchShort(L, bdslot);
2986 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002987 BranchLong(L, bdslot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002988 }
2989 } else {
2990 if (is_trampoline_emitted()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002991 BranchLong(L, bdslot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002992 } else {
2993 BranchShort(L, bdslot);
2994 }
2995 }
2996}
2997
2998
2999void MacroAssembler::Branch(Label* L, Condition cond, Register rs,
3000 const Operand& rt,
3001 BranchDelaySlot bdslot) {
3002 if (L->is_bound()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003003 if (!BranchShortCheck(0, L, cond, rs, rt, bdslot)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003004 if (cond != cc_always) {
3005 Label skip;
3006 Condition neg_cond = NegateCondition(cond);
3007 BranchShort(&skip, neg_cond, rs, rt);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003008 BranchLong(L, bdslot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003009 bind(&skip);
3010 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003011 BranchLong(L, bdslot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003012 }
3013 }
3014 } else {
3015 if (is_trampoline_emitted()) {
3016 if (cond != cc_always) {
3017 Label skip;
3018 Condition neg_cond = NegateCondition(cond);
3019 BranchShort(&skip, neg_cond, rs, rt);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003020 BranchLong(L, bdslot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003021 bind(&skip);
3022 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003023 BranchLong(L, bdslot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003024 }
3025 } else {
3026 BranchShort(L, cond, rs, rt, bdslot);
3027 }
3028 }
3029}
3030
3031
3032void MacroAssembler::Branch(Label* L,
3033 Condition cond,
3034 Register rs,
3035 Heap::RootListIndex index,
3036 BranchDelaySlot bdslot) {
3037 LoadRoot(at, index);
3038 Branch(L, cond, rs, Operand(at), bdslot);
3039}
3040
3041
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003042void MacroAssembler::BranchShortHelper(int16_t offset, Label* L,
3043 BranchDelaySlot bdslot) {
3044 DCHECK(L == nullptr || offset == 0);
3045 offset = GetOffset(offset, L, OffsetSize::kOffset16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003046 b(offset);
3047
3048 // Emit a nop in the branch delay slot if required.
3049 if (bdslot == PROTECT)
3050 nop();
3051}
3052
3053
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003054void MacroAssembler::BranchShortHelperR6(int32_t offset, Label* L) {
3055 DCHECK(L == nullptr || offset == 0);
3056 offset = GetOffset(offset, L, OffsetSize::kOffset26);
3057 bc(offset);
3058}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003059
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003060
3061void MacroAssembler::BranchShort(int32_t offset, BranchDelaySlot bdslot) {
3062 if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3063 DCHECK(is_int26(offset));
3064 BranchShortHelperR6(offset, nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003065 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003066 DCHECK(is_int16(offset));
3067 BranchShortHelper(offset, nullptr, bdslot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003068 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003069}
3070
3071
3072void MacroAssembler::BranchShort(Label* L, BranchDelaySlot bdslot) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003073 if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3074 BranchShortHelperR6(0, L);
3075 } else {
3076 BranchShortHelper(0, L, bdslot);
3077 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003078}
3079
3080
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003081static inline bool IsZero(const Operand& rt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003082 if (rt.is_reg()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003083 return rt.rm().is(zero_reg);
3084 } else {
3085 return rt.immediate() == 0;
3086 }
3087}
3088
3089
3090int32_t MacroAssembler::GetOffset(int32_t offset, Label* L, OffsetSize bits) {
3091 if (L) {
3092 offset = branch_offset_helper(L, bits) >> 2;
3093 } else {
3094 DCHECK(is_intn(offset, bits));
3095 }
3096 return offset;
3097}
3098
3099
3100Register MacroAssembler::GetRtAsRegisterHelper(const Operand& rt,
3101 Register scratch) {
3102 Register r2 = no_reg;
3103 if (rt.is_reg()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003104 r2 = rt.rm_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003105 } else {
3106 r2 = scratch;
3107 li(r2, rt);
3108 }
3109
3110 return r2;
3111}
3112
3113
3114bool MacroAssembler::BranchShortHelperR6(int32_t offset, Label* L,
3115 Condition cond, Register rs,
3116 const Operand& rt) {
3117 DCHECK(L == nullptr || offset == 0);
3118 Register scratch = rs.is(at) ? t8 : at;
3119 OffsetSize bits = OffsetSize::kOffset16;
3120
3121 // Be careful to always use shifted_branch_offset only just before the
3122 // branch instruction, as the location will be remember for patching the
3123 // target.
3124 {
3125 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003126 switch (cond) {
3127 case cc_always:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003128 bits = OffsetSize::kOffset26;
3129 if (!is_near(L, bits)) return false;
3130 offset = GetOffset(offset, L, bits);
3131 bc(offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003132 break;
3133 case eq:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003134 if (rs.code() == rt.rm_.reg_code) {
3135 // Pre R6 beq is used here to make the code patchable. Otherwise bc
3136 // should be used which has no condition field so is not patchable.
3137 bits = OffsetSize::kOffset16;
3138 if (!is_near(L, bits)) return false;
3139 scratch = GetRtAsRegisterHelper(rt, scratch);
3140 offset = GetOffset(offset, L, bits);
3141 beq(rs, scratch, offset);
3142 nop();
3143 } else if (IsZero(rt)) {
3144 bits = OffsetSize::kOffset21;
3145 if (!is_near(L, bits)) return false;
3146 offset = GetOffset(offset, L, bits);
3147 beqzc(rs, offset);
3148 } else {
3149 // We don't want any other register but scratch clobbered.
3150 bits = OffsetSize::kOffset16;
3151 if (!is_near(L, bits)) return false;
3152 scratch = GetRtAsRegisterHelper(rt, scratch);
3153 offset = GetOffset(offset, L, bits);
3154 beqc(rs, scratch, offset);
3155 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003156 break;
3157 case ne:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003158 if (rs.code() == rt.rm_.reg_code) {
3159 // Pre R6 bne is used here to make the code patchable. Otherwise we
3160 // should not generate any instruction.
3161 bits = OffsetSize::kOffset16;
3162 if (!is_near(L, bits)) return false;
3163 scratch = GetRtAsRegisterHelper(rt, scratch);
3164 offset = GetOffset(offset, L, bits);
3165 bne(rs, scratch, offset);
3166 nop();
3167 } else if (IsZero(rt)) {
3168 bits = OffsetSize::kOffset21;
3169 if (!is_near(L, bits)) return false;
3170 offset = GetOffset(offset, L, bits);
3171 bnezc(rs, offset);
3172 } else {
3173 // We don't want any other register but scratch clobbered.
3174 bits = OffsetSize::kOffset16;
3175 if (!is_near(L, bits)) return false;
3176 scratch = GetRtAsRegisterHelper(rt, scratch);
3177 offset = GetOffset(offset, L, bits);
3178 bnec(rs, scratch, offset);
3179 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003180 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003181
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003182 // Signed comparison.
3183 case greater:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003184 // rs > rt
3185 if (rs.code() == rt.rm_.reg_code) {
3186 break; // No code needs to be emitted.
3187 } else if (rs.is(zero_reg)) {
3188 bits = OffsetSize::kOffset16;
3189 if (!is_near(L, bits)) return false;
3190 scratch = GetRtAsRegisterHelper(rt, scratch);
3191 offset = GetOffset(offset, L, bits);
3192 bltzc(scratch, offset);
3193 } else if (IsZero(rt)) {
3194 bits = OffsetSize::kOffset16;
3195 if (!is_near(L, bits)) return false;
3196 offset = GetOffset(offset, L, bits);
3197 bgtzc(rs, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003198 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003199 bits = OffsetSize::kOffset16;
3200 if (!is_near(L, bits)) return false;
3201 scratch = GetRtAsRegisterHelper(rt, scratch);
3202 DCHECK(!rs.is(scratch));
3203 offset = GetOffset(offset, L, bits);
3204 bltc(scratch, rs, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003205 }
3206 break;
3207 case greater_equal:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003208 // rs >= rt
3209 if (rs.code() == rt.rm_.reg_code) {
3210 bits = OffsetSize::kOffset26;
3211 if (!is_near(L, bits)) return false;
3212 offset = GetOffset(offset, L, bits);
3213 bc(offset);
3214 } else if (rs.is(zero_reg)) {
3215 bits = OffsetSize::kOffset16;
3216 if (!is_near(L, bits)) return false;
3217 scratch = GetRtAsRegisterHelper(rt, scratch);
3218 offset = GetOffset(offset, L, bits);
3219 blezc(scratch, offset);
3220 } else if (IsZero(rt)) {
3221 bits = OffsetSize::kOffset16;
3222 if (!is_near(L, bits)) return false;
3223 offset = GetOffset(offset, L, bits);
3224 bgezc(rs, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003225 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003226 bits = OffsetSize::kOffset16;
3227 if (!is_near(L, bits)) return false;
3228 scratch = GetRtAsRegisterHelper(rt, scratch);
3229 DCHECK(!rs.is(scratch));
3230 offset = GetOffset(offset, L, bits);
3231 bgec(rs, scratch, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003232 }
3233 break;
3234 case less:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003235 // rs < rt
3236 if (rs.code() == rt.rm_.reg_code) {
3237 break; // No code needs to be emitted.
3238 } else if (rs.is(zero_reg)) {
3239 bits = OffsetSize::kOffset16;
3240 if (!is_near(L, bits)) return false;
3241 scratch = GetRtAsRegisterHelper(rt, scratch);
3242 offset = GetOffset(offset, L, bits);
3243 bgtzc(scratch, offset);
3244 } else if (IsZero(rt)) {
3245 bits = OffsetSize::kOffset16;
3246 if (!is_near(L, bits)) return false;
3247 offset = GetOffset(offset, L, bits);
3248 bltzc(rs, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003249 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003250 bits = OffsetSize::kOffset16;
3251 if (!is_near(L, bits)) return false;
3252 scratch = GetRtAsRegisterHelper(rt, scratch);
3253 DCHECK(!rs.is(scratch));
3254 offset = GetOffset(offset, L, bits);
3255 bltc(rs, scratch, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003256 }
3257 break;
3258 case less_equal:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003259 // rs <= rt
3260 if (rs.code() == rt.rm_.reg_code) {
3261 bits = OffsetSize::kOffset26;
3262 if (!is_near(L, bits)) return false;
3263 offset = GetOffset(offset, L, bits);
3264 bc(offset);
3265 } else if (rs.is(zero_reg)) {
3266 bits = OffsetSize::kOffset16;
3267 if (!is_near(L, bits)) return false;
3268 scratch = GetRtAsRegisterHelper(rt, scratch);
3269 offset = GetOffset(offset, L, bits);
3270 bgezc(scratch, offset);
3271 } else if (IsZero(rt)) {
3272 bits = OffsetSize::kOffset16;
3273 if (!is_near(L, bits)) return false;
3274 offset = GetOffset(offset, L, bits);
3275 blezc(rs, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003276 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003277 bits = OffsetSize::kOffset16;
3278 if (!is_near(L, bits)) return false;
3279 scratch = GetRtAsRegisterHelper(rt, scratch);
3280 DCHECK(!rs.is(scratch));
3281 offset = GetOffset(offset, L, bits);
3282 bgec(scratch, rs, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003283 }
3284 break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003285
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003286 // Unsigned comparison.
3287 case Ugreater:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003288 // rs > rt
3289 if (rs.code() == rt.rm_.reg_code) {
3290 break; // No code needs to be emitted.
3291 } else if (rs.is(zero_reg)) {
3292 bits = OffsetSize::kOffset21;
3293 if (!is_near(L, bits)) return false;
3294 scratch = GetRtAsRegisterHelper(rt, scratch);
3295 offset = GetOffset(offset, L, bits);
3296 bnezc(scratch, offset);
3297 } else if (IsZero(rt)) {
3298 bits = OffsetSize::kOffset21;
3299 if (!is_near(L, bits)) return false;
3300 offset = GetOffset(offset, L, bits);
3301 bnezc(rs, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003302 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003303 bits = OffsetSize::kOffset16;
3304 if (!is_near(L, bits)) return false;
3305 scratch = GetRtAsRegisterHelper(rt, scratch);
3306 DCHECK(!rs.is(scratch));
3307 offset = GetOffset(offset, L, bits);
3308 bltuc(scratch, rs, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003309 }
3310 break;
3311 case Ugreater_equal:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003312 // rs >= rt
3313 if (rs.code() == rt.rm_.reg_code) {
3314 bits = OffsetSize::kOffset26;
3315 if (!is_near(L, bits)) return false;
3316 offset = GetOffset(offset, L, bits);
3317 bc(offset);
3318 } else if (rs.is(zero_reg)) {
3319 bits = OffsetSize::kOffset21;
3320 if (!is_near(L, bits)) return false;
3321 scratch = GetRtAsRegisterHelper(rt, scratch);
3322 offset = GetOffset(offset, L, bits);
3323 beqzc(scratch, offset);
3324 } else if (IsZero(rt)) {
3325 bits = OffsetSize::kOffset26;
3326 if (!is_near(L, bits)) return false;
3327 offset = GetOffset(offset, L, bits);
3328 bc(offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003329 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003330 bits = OffsetSize::kOffset16;
3331 if (!is_near(L, bits)) return false;
3332 scratch = GetRtAsRegisterHelper(rt, scratch);
3333 DCHECK(!rs.is(scratch));
3334 offset = GetOffset(offset, L, bits);
3335 bgeuc(rs, scratch, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003336 }
3337 break;
3338 case Uless:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003339 // rs < rt
3340 if (rs.code() == rt.rm_.reg_code) {
3341 break; // No code needs to be emitted.
3342 } else if (rs.is(zero_reg)) {
3343 bits = OffsetSize::kOffset21;
3344 if (!is_near(L, bits)) return false;
3345 scratch = GetRtAsRegisterHelper(rt, scratch);
3346 offset = GetOffset(offset, L, bits);
3347 bnezc(scratch, offset);
3348 } else if (IsZero(rt)) {
3349 break; // No code needs to be emitted.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003350 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003351 bits = OffsetSize::kOffset16;
3352 if (!is_near(L, bits)) return false;
3353 scratch = GetRtAsRegisterHelper(rt, scratch);
3354 DCHECK(!rs.is(scratch));
3355 offset = GetOffset(offset, L, bits);
3356 bltuc(rs, scratch, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003357 }
3358 break;
3359 case Uless_equal:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003360 // rs <= rt
3361 if (rs.code() == rt.rm_.reg_code) {
3362 bits = OffsetSize::kOffset26;
3363 if (!is_near(L, bits)) return false;
3364 offset = GetOffset(offset, L, bits);
3365 bc(offset);
3366 } else if (rs.is(zero_reg)) {
3367 bits = OffsetSize::kOffset26;
3368 if (!is_near(L, bits)) return false;
3369 scratch = GetRtAsRegisterHelper(rt, scratch);
3370 offset = GetOffset(offset, L, bits);
3371 bc(offset);
3372 } else if (IsZero(rt)) {
3373 bits = OffsetSize::kOffset21;
3374 if (!is_near(L, bits)) return false;
3375 offset = GetOffset(offset, L, bits);
3376 beqzc(rs, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003377 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003378 bits = OffsetSize::kOffset16;
3379 if (!is_near(L, bits)) return false;
3380 scratch = GetRtAsRegisterHelper(rt, scratch);
3381 DCHECK(!rs.is(scratch));
3382 offset = GetOffset(offset, L, bits);
3383 bgeuc(scratch, rs, offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003384 }
3385 break;
3386 default:
3387 UNREACHABLE();
3388 }
3389 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003390 CheckTrampolinePoolQuick(1);
3391 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003392}
3393
3394
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003395bool MacroAssembler::BranchShortHelper(int16_t offset, Label* L, Condition cond,
3396 Register rs, const Operand& rt,
3397 BranchDelaySlot bdslot) {
3398 DCHECK(L == nullptr || offset == 0);
3399 if (!is_near(L, OffsetSize::kOffset16)) return false;
3400
3401 Register scratch = at;
3402 int32_t offset32;
3403
3404 // Be careful to always use shifted_branch_offset only just before the
3405 // branch instruction, as the location will be remember for patching the
3406 // target.
3407 {
3408 BlockTrampolinePoolScope block_trampoline_pool(this);
3409 switch (cond) {
3410 case cc_always:
3411 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3412 b(offset32);
3413 break;
3414 case eq:
3415 if (IsZero(rt)) {
3416 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3417 beq(rs, zero_reg, offset32);
3418 } else {
3419 // We don't want any other register but scratch clobbered.
3420 scratch = GetRtAsRegisterHelper(rt, scratch);
3421 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3422 beq(rs, scratch, offset32);
3423 }
3424 break;
3425 case ne:
3426 if (IsZero(rt)) {
3427 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3428 bne(rs, zero_reg, offset32);
3429 } else {
3430 // We don't want any other register but scratch clobbered.
3431 scratch = GetRtAsRegisterHelper(rt, scratch);
3432 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3433 bne(rs, scratch, offset32);
3434 }
3435 break;
3436
3437 // Signed comparison.
3438 case greater:
3439 if (IsZero(rt)) {
3440 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3441 bgtz(rs, offset32);
3442 } else {
3443 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3444 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3445 bne(scratch, zero_reg, offset32);
3446 }
3447 break;
3448 case greater_equal:
3449 if (IsZero(rt)) {
3450 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3451 bgez(rs, offset32);
3452 } else {
3453 Slt(scratch, rs, rt);
3454 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3455 beq(scratch, zero_reg, offset32);
3456 }
3457 break;
3458 case less:
3459 if (IsZero(rt)) {
3460 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3461 bltz(rs, offset32);
3462 } else {
3463 Slt(scratch, rs, rt);
3464 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3465 bne(scratch, zero_reg, offset32);
3466 }
3467 break;
3468 case less_equal:
3469 if (IsZero(rt)) {
3470 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3471 blez(rs, offset32);
3472 } else {
3473 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3474 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3475 beq(scratch, zero_reg, offset32);
3476 }
3477 break;
3478
3479 // Unsigned comparison.
3480 case Ugreater:
3481 if (IsZero(rt)) {
3482 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3483 bne(rs, zero_reg, offset32);
3484 } else {
3485 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3486 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3487 bne(scratch, zero_reg, offset32);
3488 }
3489 break;
3490 case Ugreater_equal:
3491 if (IsZero(rt)) {
3492 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3493 b(offset32);
3494 } else {
3495 Sltu(scratch, rs, rt);
3496 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3497 beq(scratch, zero_reg, offset32);
3498 }
3499 break;
3500 case Uless:
3501 if (IsZero(rt)) {
3502 return true; // No code needs to be emitted.
3503 } else {
3504 Sltu(scratch, rs, rt);
3505 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3506 bne(scratch, zero_reg, offset32);
3507 }
3508 break;
3509 case Uless_equal:
3510 if (IsZero(rt)) {
3511 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3512 beq(rs, zero_reg, offset32);
3513 } else {
3514 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3515 offset32 = GetOffset(offset, L, OffsetSize::kOffset16);
3516 beq(scratch, zero_reg, offset32);
3517 }
3518 break;
3519 default:
3520 UNREACHABLE();
3521 }
3522 }
3523
3524 // Emit a nop in the branch delay slot if required.
3525 if (bdslot == PROTECT)
3526 nop();
3527
3528 return true;
3529}
3530
3531
3532bool MacroAssembler::BranchShortCheck(int32_t offset, Label* L, Condition cond,
3533 Register rs, const Operand& rt,
3534 BranchDelaySlot bdslot) {
3535 BRANCH_ARGS_CHECK(cond, rs, rt);
3536
3537 if (!L) {
3538 if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3539 DCHECK(is_int26(offset));
3540 return BranchShortHelperR6(offset, nullptr, cond, rs, rt);
3541 } else {
3542 DCHECK(is_int16(offset));
3543 return BranchShortHelper(offset, nullptr, cond, rs, rt, bdslot);
3544 }
3545 } else {
3546 DCHECK(offset == 0);
3547 if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3548 return BranchShortHelperR6(0, L, cond, rs, rt);
3549 } else {
3550 return BranchShortHelper(0, L, cond, rs, rt, bdslot);
3551 }
3552 }
3553 return false;
3554}
3555
3556
3557void MacroAssembler::BranchShort(int32_t offset, Condition cond, Register rs,
3558 const Operand& rt, BranchDelaySlot bdslot) {
3559 BranchShortCheck(offset, nullptr, cond, rs, rt, bdslot);
3560}
3561
3562
3563void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
3564 const Operand& rt, BranchDelaySlot bdslot) {
3565 BranchShortCheck(0, L, cond, rs, rt, bdslot);
3566}
3567
3568
3569void MacroAssembler::BranchAndLink(int32_t offset, BranchDelaySlot bdslot) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003570 BranchAndLinkShort(offset, bdslot);
3571}
3572
3573
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003574void MacroAssembler::BranchAndLink(int32_t offset, Condition cond, Register rs,
3575 const Operand& rt, BranchDelaySlot bdslot) {
3576 bool is_near = BranchAndLinkShortCheck(offset, nullptr, cond, rs, rt, bdslot);
3577 DCHECK(is_near);
3578 USE(is_near);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003579}
3580
3581
3582void MacroAssembler::BranchAndLink(Label* L, BranchDelaySlot bdslot) {
3583 if (L->is_bound()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003584 if (is_near_branch(L)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003585 BranchAndLinkShort(L, bdslot);
3586 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003587 BranchAndLinkLong(L, bdslot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003588 }
3589 } else {
3590 if (is_trampoline_emitted()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003591 BranchAndLinkLong(L, bdslot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003592 } else {
3593 BranchAndLinkShort(L, bdslot);
3594 }
3595 }
3596}
3597
3598
3599void MacroAssembler::BranchAndLink(Label* L, Condition cond, Register rs,
3600 const Operand& rt,
3601 BranchDelaySlot bdslot) {
3602 if (L->is_bound()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003603 if (!BranchAndLinkShortCheck(0, L, cond, rs, rt, bdslot)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003604 Label skip;
3605 Condition neg_cond = NegateCondition(cond);
3606 BranchShort(&skip, neg_cond, rs, rt);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003607 BranchAndLinkLong(L, bdslot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003608 bind(&skip);
3609 }
3610 } else {
3611 if (is_trampoline_emitted()) {
3612 Label skip;
3613 Condition neg_cond = NegateCondition(cond);
3614 BranchShort(&skip, neg_cond, rs, rt);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003615 BranchAndLinkLong(L, bdslot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003616 bind(&skip);
3617 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003618 BranchAndLinkShortCheck(0, L, cond, rs, rt, bdslot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003619 }
3620 }
3621}
3622
3623
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003624void MacroAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L,
3625 BranchDelaySlot bdslot) {
3626 DCHECK(L == nullptr || offset == 0);
3627 offset = GetOffset(offset, L, OffsetSize::kOffset16);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003628 bal(offset);
3629
3630 // Emit a nop in the branch delay slot if required.
3631 if (bdslot == PROTECT)
3632 nop();
3633}
3634
3635
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003636void MacroAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L) {
3637 DCHECK(L == nullptr || offset == 0);
3638 offset = GetOffset(offset, L, OffsetSize::kOffset26);
3639 balc(offset);
3640}
3641
3642
3643void MacroAssembler::BranchAndLinkShort(int32_t offset,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003644 BranchDelaySlot bdslot) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003645 if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3646 DCHECK(is_int26(offset));
3647 BranchAndLinkShortHelperR6(offset, nullptr);
3648 } else {
3649 DCHECK(is_int16(offset));
3650 BranchAndLinkShortHelper(offset, nullptr, bdslot);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003651 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003652}
3653
3654
3655void MacroAssembler::BranchAndLinkShort(Label* L, BranchDelaySlot bdslot) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003656 if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3657 BranchAndLinkShortHelperR6(0, L);
3658 } else {
3659 BranchAndLinkShortHelper(0, L, bdslot);
3660 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003661}
3662
3663
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003664bool MacroAssembler::BranchAndLinkShortHelperR6(int32_t offset, Label* L,
3665 Condition cond, Register rs,
3666 const Operand& rt) {
3667 DCHECK(L == nullptr || offset == 0);
3668 Register scratch = rs.is(at) ? t8 : at;
3669 OffsetSize bits = OffsetSize::kOffset16;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003670
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003671 BlockTrampolinePoolScope block_trampoline_pool(this);
3672 DCHECK((cond == cc_always && is_int26(offset)) || is_int16(offset));
3673 switch (cond) {
3674 case cc_always:
3675 bits = OffsetSize::kOffset26;
3676 if (!is_near(L, bits)) return false;
3677 offset = GetOffset(offset, L, bits);
3678 balc(offset);
3679 break;
3680 case eq:
3681 if (!is_near(L, bits)) return false;
3682 Subu(scratch, rs, rt);
3683 offset = GetOffset(offset, L, bits);
3684 beqzalc(scratch, offset);
3685 break;
3686 case ne:
3687 if (!is_near(L, bits)) return false;
3688 Subu(scratch, rs, rt);
3689 offset = GetOffset(offset, L, bits);
3690 bnezalc(scratch, offset);
3691 break;
3692
3693 // Signed comparison.
3694 case greater:
3695 // rs > rt
3696 if (rs.code() == rt.rm_.reg_code) {
3697 break; // No code needs to be emitted.
3698 } else if (rs.is(zero_reg)) {
3699 if (!is_near(L, bits)) return false;
3700 scratch = GetRtAsRegisterHelper(rt, scratch);
3701 offset = GetOffset(offset, L, bits);
3702 bltzalc(scratch, offset);
3703 } else if (IsZero(rt)) {
3704 if (!is_near(L, bits)) return false;
3705 offset = GetOffset(offset, L, bits);
3706 bgtzalc(rs, offset);
3707 } else {
3708 if (!is_near(L, bits)) return false;
3709 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3710 offset = GetOffset(offset, L, bits);
3711 bnezalc(scratch, offset);
3712 }
3713 break;
3714 case greater_equal:
3715 // rs >= rt
3716 if (rs.code() == rt.rm_.reg_code) {
3717 bits = OffsetSize::kOffset26;
3718 if (!is_near(L, bits)) return false;
3719 offset = GetOffset(offset, L, bits);
3720 balc(offset);
3721 } else if (rs.is(zero_reg)) {
3722 if (!is_near(L, bits)) return false;
3723 scratch = GetRtAsRegisterHelper(rt, scratch);
3724 offset = GetOffset(offset, L, bits);
3725 blezalc(scratch, offset);
3726 } else if (IsZero(rt)) {
3727 if (!is_near(L, bits)) return false;
3728 offset = GetOffset(offset, L, bits);
3729 bgezalc(rs, offset);
3730 } else {
3731 if (!is_near(L, bits)) return false;
3732 Slt(scratch, rs, rt);
3733 offset = GetOffset(offset, L, bits);
3734 beqzalc(scratch, offset);
3735 }
3736 break;
3737 case less:
3738 // rs < rt
3739 if (rs.code() == rt.rm_.reg_code) {
3740 break; // No code needs to be emitted.
3741 } else if (rs.is(zero_reg)) {
3742 if (!is_near(L, bits)) return false;
3743 scratch = GetRtAsRegisterHelper(rt, scratch);
3744 offset = GetOffset(offset, L, bits);
3745 bgtzalc(scratch, offset);
3746 } else if (IsZero(rt)) {
3747 if (!is_near(L, bits)) return false;
3748 offset = GetOffset(offset, L, bits);
3749 bltzalc(rs, offset);
3750 } else {
3751 if (!is_near(L, bits)) return false;
3752 Slt(scratch, rs, rt);
3753 offset = GetOffset(offset, L, bits);
3754 bnezalc(scratch, offset);
3755 }
3756 break;
3757 case less_equal:
3758 // rs <= r2
3759 if (rs.code() == rt.rm_.reg_code) {
3760 bits = OffsetSize::kOffset26;
3761 if (!is_near(L, bits)) return false;
3762 offset = GetOffset(offset, L, bits);
3763 balc(offset);
3764 } else if (rs.is(zero_reg)) {
3765 if (!is_near(L, bits)) return false;
3766 scratch = GetRtAsRegisterHelper(rt, scratch);
3767 offset = GetOffset(offset, L, bits);
3768 bgezalc(scratch, offset);
3769 } else if (IsZero(rt)) {
3770 if (!is_near(L, bits)) return false;
3771 offset = GetOffset(offset, L, bits);
3772 blezalc(rs, offset);
3773 } else {
3774 if (!is_near(L, bits)) return false;
3775 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3776 offset = GetOffset(offset, L, bits);
3777 beqzalc(scratch, offset);
3778 }
3779 break;
3780
3781
3782 // Unsigned comparison.
3783 case Ugreater:
3784 // rs > r2
3785 if (!is_near(L, bits)) return false;
3786 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3787 offset = GetOffset(offset, L, bits);
3788 bnezalc(scratch, offset);
3789 break;
3790 case Ugreater_equal:
3791 // rs >= r2
3792 if (!is_near(L, bits)) return false;
3793 Sltu(scratch, rs, rt);
3794 offset = GetOffset(offset, L, bits);
3795 beqzalc(scratch, offset);
3796 break;
3797 case Uless:
3798 // rs < r2
3799 if (!is_near(L, bits)) return false;
3800 Sltu(scratch, rs, rt);
3801 offset = GetOffset(offset, L, bits);
3802 bnezalc(scratch, offset);
3803 break;
3804 case Uless_equal:
3805 // rs <= r2
3806 if (!is_near(L, bits)) return false;
3807 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3808 offset = GetOffset(offset, L, bits);
3809 beqzalc(scratch, offset);
3810 break;
3811 default:
3812 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003813 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003814 return true;
3815}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003816
3817
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003818// Pre r6 we need to use a bgezal or bltzal, but they can't be used directly
3819// with the slt instructions. We could use sub or add instead but we would miss
3820// overflow cases, so we keep slt and add an intermediate third instruction.
3821bool MacroAssembler::BranchAndLinkShortHelper(int16_t offset, Label* L,
3822 Condition cond, Register rs,
3823 const Operand& rt,
3824 BranchDelaySlot bdslot) {
3825 DCHECK(L == nullptr || offset == 0);
3826 if (!is_near(L, OffsetSize::kOffset16)) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003827
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003828 Register scratch = t8;
3829 BlockTrampolinePoolScope block_trampoline_pool(this);
3830
3831 switch (cond) {
3832 case cc_always:
3833 offset = GetOffset(offset, L, OffsetSize::kOffset16);
3834 bal(offset);
3835 break;
3836 case eq:
3837 bne(rs, GetRtAsRegisterHelper(rt, scratch), 2);
3838 nop();
3839 offset = GetOffset(offset, L, OffsetSize::kOffset16);
3840 bal(offset);
3841 break;
3842 case ne:
3843 beq(rs, GetRtAsRegisterHelper(rt, scratch), 2);
3844 nop();
3845 offset = GetOffset(offset, L, OffsetSize::kOffset16);
3846 bal(offset);
3847 break;
3848
3849 // Signed comparison.
3850 case greater:
3851 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3852 addiu(scratch, scratch, -1);
3853 offset = GetOffset(offset, L, OffsetSize::kOffset16);
3854 bgezal(scratch, offset);
3855 break;
3856 case greater_equal:
3857 Slt(scratch, rs, rt);
3858 addiu(scratch, scratch, -1);
3859 offset = GetOffset(offset, L, OffsetSize::kOffset16);
3860 bltzal(scratch, offset);
3861 break;
3862 case less:
3863 Slt(scratch, rs, rt);
3864 addiu(scratch, scratch, -1);
3865 offset = GetOffset(offset, L, OffsetSize::kOffset16);
3866 bgezal(scratch, offset);
3867 break;
3868 case less_equal:
3869 Slt(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3870 addiu(scratch, scratch, -1);
3871 offset = GetOffset(offset, L, OffsetSize::kOffset16);
3872 bltzal(scratch, offset);
3873 break;
3874
3875 // Unsigned comparison.
3876 case Ugreater:
3877 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3878 addiu(scratch, scratch, -1);
3879 offset = GetOffset(offset, L, OffsetSize::kOffset16);
3880 bgezal(scratch, offset);
3881 break;
3882 case Ugreater_equal:
3883 Sltu(scratch, rs, rt);
3884 addiu(scratch, scratch, -1);
3885 offset = GetOffset(offset, L, OffsetSize::kOffset16);
3886 bltzal(scratch, offset);
3887 break;
3888 case Uless:
3889 Sltu(scratch, rs, rt);
3890 addiu(scratch, scratch, -1);
3891 offset = GetOffset(offset, L, OffsetSize::kOffset16);
3892 bgezal(scratch, offset);
3893 break;
3894 case Uless_equal:
3895 Sltu(scratch, GetRtAsRegisterHelper(rt, scratch), rs);
3896 addiu(scratch, scratch, -1);
3897 offset = GetOffset(offset, L, OffsetSize::kOffset16);
3898 bltzal(scratch, offset);
3899 break;
3900
3901 default:
3902 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003903 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003904
3905 // Emit a nop in the branch delay slot if required.
3906 if (bdslot == PROTECT)
3907 nop();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003908
3909 return true;
3910}
3911
3912
3913bool MacroAssembler::BranchAndLinkShortCheck(int32_t offset, Label* L,
3914 Condition cond, Register rs,
3915 const Operand& rt,
3916 BranchDelaySlot bdslot) {
3917 BRANCH_ARGS_CHECK(cond, rs, rt);
3918
3919 if (!L) {
3920 if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3921 DCHECK(is_int26(offset));
3922 return BranchAndLinkShortHelperR6(offset, nullptr, cond, rs, rt);
3923 } else {
3924 DCHECK(is_int16(offset));
3925 return BranchAndLinkShortHelper(offset, nullptr, cond, rs, rt, bdslot);
3926 }
3927 } else {
3928 DCHECK(offset == 0);
3929 if (kArchVariant == kMips64r6 && bdslot == PROTECT) {
3930 return BranchAndLinkShortHelperR6(0, L, cond, rs, rt);
3931 } else {
3932 return BranchAndLinkShortHelper(0, L, cond, rs, rt, bdslot);
3933 }
3934 }
3935 return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003936}
3937
3938
3939void MacroAssembler::Jump(Register target,
3940 Condition cond,
3941 Register rs,
3942 const Operand& rt,
3943 BranchDelaySlot bd) {
3944 BlockTrampolinePoolScope block_trampoline_pool(this);
Ben Murdochda12d292016-06-02 14:46:10 +01003945 if (kArchVariant == kMips64r6 && bd == PROTECT) {
3946 if (cond == cc_always) {
3947 jic(target, 0);
3948 } else {
3949 BRANCH_ARGS_CHECK(cond, rs, rt);
3950 Branch(2, NegateCondition(cond), rs, rt);
3951 jic(target, 0);
3952 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003953 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01003954 if (cond == cc_always) {
3955 jr(target);
3956 } else {
3957 BRANCH_ARGS_CHECK(cond, rs, rt);
3958 Branch(2, NegateCondition(cond), rs, rt);
3959 jr(target);
3960 }
3961 // Emit a nop in the branch delay slot if required.
3962 if (bd == PROTECT) nop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003963 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003964}
3965
3966
3967void MacroAssembler::Jump(intptr_t target,
3968 RelocInfo::Mode rmode,
3969 Condition cond,
3970 Register rs,
3971 const Operand& rt,
3972 BranchDelaySlot bd) {
3973 Label skip;
3974 if (cond != cc_always) {
3975 Branch(USE_DELAY_SLOT, &skip, NegateCondition(cond), rs, rt);
3976 }
3977 // The first instruction of 'li' may be placed in the delay slot.
3978 // This is not an issue, t9 is expected to be clobbered anyway.
3979 li(t9, Operand(target, rmode));
3980 Jump(t9, al, zero_reg, Operand(zero_reg), bd);
3981 bind(&skip);
3982}
3983
3984
3985void MacroAssembler::Jump(Address target,
3986 RelocInfo::Mode rmode,
3987 Condition cond,
3988 Register rs,
3989 const Operand& rt,
3990 BranchDelaySlot bd) {
3991 DCHECK(!RelocInfo::IsCodeTarget(rmode));
3992 Jump(reinterpret_cast<intptr_t>(target), rmode, cond, rs, rt, bd);
3993}
3994
3995
3996void MacroAssembler::Jump(Handle<Code> code,
3997 RelocInfo::Mode rmode,
3998 Condition cond,
3999 Register rs,
4000 const Operand& rt,
4001 BranchDelaySlot bd) {
4002 DCHECK(RelocInfo::IsCodeTarget(rmode));
4003 AllowDeferredHandleDereference embedding_raw_address;
4004 Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond, rs, rt, bd);
4005}
4006
4007
4008int MacroAssembler::CallSize(Register target,
4009 Condition cond,
4010 Register rs,
4011 const Operand& rt,
4012 BranchDelaySlot bd) {
4013 int size = 0;
4014
4015 if (cond == cc_always) {
4016 size += 1;
4017 } else {
4018 size += 3;
4019 }
4020
Ben Murdochda12d292016-06-02 14:46:10 +01004021 if (bd == PROTECT && kArchVariant != kMips64r6) size += 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004022
4023 return size * kInstrSize;
4024}
4025
4026
4027// Note: To call gcc-compiled C code on mips, you must call thru t9.
4028void MacroAssembler::Call(Register target,
4029 Condition cond,
4030 Register rs,
4031 const Operand& rt,
4032 BranchDelaySlot bd) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004033#ifdef DEBUG
4034 int size = IsPrevInstrCompactBranch() ? kInstrSize : 0;
4035#endif
4036
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004037 BlockTrampolinePoolScope block_trampoline_pool(this);
4038 Label start;
4039 bind(&start);
Ben Murdochda12d292016-06-02 14:46:10 +01004040 if (kArchVariant == kMips64r6 && bd == PROTECT) {
4041 if (cond == cc_always) {
4042 jialc(target, 0);
4043 } else {
4044 BRANCH_ARGS_CHECK(cond, rs, rt);
4045 Branch(2, NegateCondition(cond), rs, rt);
4046 jialc(target, 0);
4047 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004048 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01004049 if (cond == cc_always) {
4050 jalr(target);
4051 } else {
4052 BRANCH_ARGS_CHECK(cond, rs, rt);
4053 Branch(2, NegateCondition(cond), rs, rt);
4054 jalr(target);
4055 }
4056 // Emit a nop in the branch delay slot if required.
4057 if (bd == PROTECT) nop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004058 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004059
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004060#ifdef DEBUG
4061 CHECK_EQ(size + CallSize(target, cond, rs, rt, bd),
4062 SizeOfCodeGeneratedSince(&start));
4063#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004064}
4065
4066
4067int MacroAssembler::CallSize(Address target,
4068 RelocInfo::Mode rmode,
4069 Condition cond,
4070 Register rs,
4071 const Operand& rt,
4072 BranchDelaySlot bd) {
4073 int size = CallSize(t9, cond, rs, rt, bd);
4074 return size + 4 * kInstrSize;
4075}
4076
4077
4078void MacroAssembler::Call(Address target,
4079 RelocInfo::Mode rmode,
4080 Condition cond,
4081 Register rs,
4082 const Operand& rt,
4083 BranchDelaySlot bd) {
4084 BlockTrampolinePoolScope block_trampoline_pool(this);
4085 Label start;
4086 bind(&start);
4087 int64_t target_int = reinterpret_cast<int64_t>(target);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004088 li(t9, Operand(target_int, rmode), ADDRESS_LOAD);
4089 Call(t9, cond, rs, rt, bd);
4090 DCHECK_EQ(CallSize(target, rmode, cond, rs, rt, bd),
4091 SizeOfCodeGeneratedSince(&start));
4092}
4093
4094
4095int MacroAssembler::CallSize(Handle<Code> code,
4096 RelocInfo::Mode rmode,
4097 TypeFeedbackId ast_id,
4098 Condition cond,
4099 Register rs,
4100 const Operand& rt,
4101 BranchDelaySlot bd) {
4102 AllowDeferredHandleDereference using_raw_address;
4103 return CallSize(reinterpret_cast<Address>(code.location()),
4104 rmode, cond, rs, rt, bd);
4105}
4106
4107
4108void MacroAssembler::Call(Handle<Code> code,
4109 RelocInfo::Mode rmode,
4110 TypeFeedbackId ast_id,
4111 Condition cond,
4112 Register rs,
4113 const Operand& rt,
4114 BranchDelaySlot bd) {
4115 BlockTrampolinePoolScope block_trampoline_pool(this);
4116 Label start;
4117 bind(&start);
4118 DCHECK(RelocInfo::IsCodeTarget(rmode));
4119 if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) {
4120 SetRecordedAstId(ast_id);
4121 rmode = RelocInfo::CODE_TARGET_WITH_ID;
4122 }
4123 AllowDeferredHandleDereference embedding_raw_address;
4124 Call(reinterpret_cast<Address>(code.location()), rmode, cond, rs, rt, bd);
4125 DCHECK_EQ(CallSize(code, rmode, ast_id, cond, rs, rt, bd),
4126 SizeOfCodeGeneratedSince(&start));
4127}
4128
4129
4130void MacroAssembler::Ret(Condition cond,
4131 Register rs,
4132 const Operand& rt,
4133 BranchDelaySlot bd) {
4134 Jump(ra, cond, rs, rt, bd);
4135}
4136
4137
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004138void MacroAssembler::BranchLong(Label* L, BranchDelaySlot bdslot) {
4139 if (kArchVariant == kMips64r6 && bdslot == PROTECT &&
4140 (!L->is_bound() || is_near_r6(L))) {
4141 BranchShortHelperR6(0, L);
4142 } else {
4143 EmitForbiddenSlotInstruction();
4144 BlockTrampolinePoolScope block_trampoline_pool(this);
4145 {
4146 BlockGrowBufferScope block_buf_growth(this);
4147 // Buffer growth (and relocation) must be blocked for internal references
4148 // until associated instructions are emitted and available to be patched.
4149 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
4150 j(L);
4151 }
4152 // Emit a nop in the branch delay slot if required.
4153 if (bdslot == PROTECT) nop();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004154 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004155}
4156
4157
4158void MacroAssembler::BranchAndLinkLong(Label* L, BranchDelaySlot bdslot) {
4159 if (kArchVariant == kMips64r6 && bdslot == PROTECT &&
4160 (!L->is_bound() || is_near_r6(L))) {
4161 BranchAndLinkShortHelperR6(0, L);
4162 } else {
4163 EmitForbiddenSlotInstruction();
4164 BlockTrampolinePoolScope block_trampoline_pool(this);
4165 {
4166 BlockGrowBufferScope block_buf_growth(this);
4167 // Buffer growth (and relocation) must be blocked for internal references
4168 // until associated instructions are emitted and available to be patched.
4169 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE_ENCODED);
4170 jal(L);
4171 }
4172 // Emit a nop in the branch delay slot if required.
4173 if (bdslot == PROTECT) nop();
4174 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004175}
4176
4177
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004178void MacroAssembler::DropAndRet(int drop) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004179 DCHECK(is_int16(drop * kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004180 Ret(USE_DELAY_SLOT);
4181 daddiu(sp, sp, drop * kPointerSize);
4182}
4183
4184void MacroAssembler::DropAndRet(int drop,
4185 Condition cond,
4186 Register r1,
4187 const Operand& r2) {
4188 // Both Drop and Ret need to be conditional.
4189 Label skip;
4190 if (cond != cc_always) {
4191 Branch(&skip, NegateCondition(cond), r1, r2);
4192 }
4193
4194 Drop(drop);
4195 Ret();
4196
4197 if (cond != cc_always) {
4198 bind(&skip);
4199 }
4200}
4201
4202
4203void MacroAssembler::Drop(int count,
4204 Condition cond,
4205 Register reg,
4206 const Operand& op) {
4207 if (count <= 0) {
4208 return;
4209 }
4210
4211 Label skip;
4212
4213 if (cond != al) {
4214 Branch(&skip, NegateCondition(cond), reg, op);
4215 }
4216
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004217 Daddu(sp, sp, Operand(count * kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004218
4219 if (cond != al) {
4220 bind(&skip);
4221 }
4222}
4223
4224
4225
4226void MacroAssembler::Swap(Register reg1,
4227 Register reg2,
4228 Register scratch) {
4229 if (scratch.is(no_reg)) {
4230 Xor(reg1, reg1, Operand(reg2));
4231 Xor(reg2, reg2, Operand(reg1));
4232 Xor(reg1, reg1, Operand(reg2));
4233 } else {
4234 mov(scratch, reg1);
4235 mov(reg1, reg2);
4236 mov(reg2, scratch);
4237 }
4238}
4239
4240
4241void MacroAssembler::Call(Label* target) {
4242 BranchAndLink(target);
4243}
4244
4245
4246void MacroAssembler::Push(Handle<Object> handle) {
4247 li(at, Operand(handle));
4248 push(at);
4249}
4250
4251
4252void MacroAssembler::PushRegisterAsTwoSmis(Register src, Register scratch) {
4253 DCHECK(!src.is(scratch));
4254 mov(scratch, src);
4255 dsrl32(src, src, 0);
4256 dsll32(src, src, 0);
4257 push(src);
4258 dsll32(scratch, scratch, 0);
4259 push(scratch);
4260}
4261
4262
4263void MacroAssembler::PopRegisterAsTwoSmis(Register dst, Register scratch) {
4264 DCHECK(!dst.is(scratch));
4265 pop(scratch);
4266 dsrl32(scratch, scratch, 0);
4267 pop(dst);
4268 dsrl32(dst, dst, 0);
4269 dsll32(dst, dst, 0);
4270 or_(dst, dst, scratch);
4271}
4272
4273
4274void MacroAssembler::DebugBreak() {
4275 PrepareCEntryArgs(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004276 PrepareCEntryFunction(
4277 ExternalReference(Runtime::kHandleDebuggerStatement, isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004278 CEntryStub ces(isolate(), 1);
4279 DCHECK(AllowThisStubCall(&ces));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004280 Call(ces.GetCode(), RelocInfo::DEBUGGER_STATEMENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004281}
4282
4283
4284// ---------------------------------------------------------------------------
4285// Exception handling.
4286
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004287void MacroAssembler::PushStackHandler() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004288 // Adjust this code if not the case.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004289 STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004290 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004291
4292 // Link the current handler as the next handler.
4293 li(a6, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
4294 ld(a5, MemOperand(a6));
4295 push(a5);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004296
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004297 // Set this new handler as the current one.
4298 sd(sp, MemOperand(a6));
4299}
4300
4301
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004302void MacroAssembler::PopStackHandler() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004303 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
4304 pop(a1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004305 Daddu(sp, sp, Operand(static_cast<int64_t>(StackHandlerConstants::kSize -
4306 kPointerSize)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004307 li(at, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
4308 sd(a1, MemOperand(at));
4309}
4310
4311
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004312void MacroAssembler::Allocate(int object_size,
4313 Register result,
4314 Register scratch1,
4315 Register scratch2,
4316 Label* gc_required,
4317 AllocationFlags flags) {
4318 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
4319 if (!FLAG_inline_new) {
4320 if (emit_debug_code()) {
4321 // Trash the registers to simulate an allocation failure.
4322 li(result, 0x7091);
4323 li(scratch1, 0x7191);
4324 li(scratch2, 0x7291);
4325 }
4326 jmp(gc_required);
4327 return;
4328 }
4329
Ben Murdoch097c5b22016-05-18 11:27:45 +01004330 DCHECK(!AreAliased(result, scratch1, scratch2, t9, at));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004331
4332 // Make object size into bytes.
4333 if ((flags & SIZE_IN_WORDS) != 0) {
4334 object_size *= kPointerSize;
4335 }
4336 DCHECK(0 == (object_size & kObjectAlignmentMask));
4337
4338 // Check relative positions of allocation top and limit addresses.
4339 // ARM adds additional checks to make sure the ldm instruction can be
4340 // used. On MIPS we don't have ldm so we don't need additional checks either.
4341 ExternalReference allocation_top =
4342 AllocationUtils::GetAllocationTopReference(isolate(), flags);
4343 ExternalReference allocation_limit =
4344 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
4345
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004346 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
4347 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004348 DCHECK((limit - top) == kPointerSize);
4349
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004350 // Set up allocation top address and allocation limit registers.
4351 Register top_address = scratch1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004352 // This code stores a temporary value in t9.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004353 Register alloc_limit = t9;
4354 Register result_end = scratch2;
4355 li(top_address, Operand(allocation_top));
4356
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004357 if ((flags & RESULT_CONTAINS_TOP) == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004358 // Load allocation top into result and allocation limit into alloc_limit.
4359 ld(result, MemOperand(top_address));
4360 ld(alloc_limit, MemOperand(top_address, kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004361 } else {
4362 if (emit_debug_code()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004363 // Assert that result actually contains top on entry.
4364 ld(alloc_limit, MemOperand(top_address));
4365 Check(eq, kUnexpectedAllocationTop, result, Operand(alloc_limit));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004366 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004367 // Load allocation limit. Result already contains allocation top.
4368 ld(alloc_limit, MemOperand(top_address, static_cast<int32_t>(limit - top)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004369 }
4370
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004371 // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have
4372 // the same alignment on ARM64.
4373 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
4374
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004375 if (emit_debug_code()) {
4376 And(at, result, Operand(kDoubleAlignmentMask));
4377 Check(eq, kAllocationIsNotDoubleAligned, at, Operand(zero_reg));
4378 }
4379
4380 // Calculate new top and bail out if new space is exhausted. Use result
4381 // to calculate the new top.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004382 Daddu(result_end, result, Operand(object_size));
4383 Branch(gc_required, Ugreater, result_end, Operand(alloc_limit));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004384
Ben Murdochc5610432016-08-08 18:44:38 +01004385 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
4386 // The top pointer is not updated for allocation folding dominators.
4387 sd(result_end, MemOperand(top_address));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004388 }
Ben Murdochc5610432016-08-08 18:44:38 +01004389
4390 // Tag object.
4391 Daddu(result, result, Operand(kHeapObjectTag));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004392}
4393
4394
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004395void MacroAssembler::Allocate(Register object_size, Register result,
4396 Register result_end, Register scratch,
4397 Label* gc_required, AllocationFlags flags) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004398 if (!FLAG_inline_new) {
4399 if (emit_debug_code()) {
4400 // Trash the registers to simulate an allocation failure.
4401 li(result, 0x7091);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004402 li(scratch, 0x7191);
4403 li(result_end, 0x7291);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004404 }
4405 jmp(gc_required);
4406 return;
4407 }
4408
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004409 // |object_size| and |result_end| may overlap, other registers must not.
Ben Murdoch097c5b22016-05-18 11:27:45 +01004410 DCHECK(!AreAliased(object_size, result, scratch, t9, at));
4411 DCHECK(!AreAliased(result_end, result, scratch, t9, at));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004412
4413 // Check relative positions of allocation top and limit addresses.
4414 // ARM adds additional checks to make sure the ldm instruction can be
4415 // used. On MIPS we don't have ldm so we don't need additional checks either.
4416 ExternalReference allocation_top =
4417 AllocationUtils::GetAllocationTopReference(isolate(), flags);
4418 ExternalReference allocation_limit =
4419 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004420 intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
4421 intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004422 DCHECK((limit - top) == kPointerSize);
4423
4424 // Set up allocation top address and object size registers.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004425 Register top_address = scratch;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004426 // This code stores a temporary value in t9.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004427 Register alloc_limit = t9;
4428 li(top_address, Operand(allocation_top));
4429
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004430 if ((flags & RESULT_CONTAINS_TOP) == 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004431 // Load allocation top into result and allocation limit into alloc_limit.
4432 ld(result, MemOperand(top_address));
4433 ld(alloc_limit, MemOperand(top_address, kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004434 } else {
4435 if (emit_debug_code()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004436 // Assert that result actually contains top on entry.
4437 ld(alloc_limit, MemOperand(top_address));
4438 Check(eq, kUnexpectedAllocationTop, result, Operand(alloc_limit));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004439 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004440 // Load allocation limit. Result already contains allocation top.
4441 ld(alloc_limit, MemOperand(top_address, static_cast<int32_t>(limit - top)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004442 }
4443
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004444 // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have
4445 // the same alignment on ARM64.
4446 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
4447
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004448 if (emit_debug_code()) {
4449 And(at, result, Operand(kDoubleAlignmentMask));
4450 Check(eq, kAllocationIsNotDoubleAligned, at, Operand(zero_reg));
4451 }
4452
4453 // Calculate new top and bail out if new space is exhausted. Use result
4454 // to calculate the new top. Object size may be in words so a shift is
4455 // required to get the number of bytes.
4456 if ((flags & SIZE_IN_WORDS) != 0) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01004457 Dlsa(result_end, result, object_size, kPointerSizeLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004458 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004459 Daddu(result_end, result, Operand(object_size));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004460 }
Ben Murdochc5610432016-08-08 18:44:38 +01004461
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004462 Branch(gc_required, Ugreater, result_end, Operand(alloc_limit));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004463
4464 // Update allocation top. result temporarily holds the new top.
4465 if (emit_debug_code()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004466 And(at, result_end, Operand(kObjectAlignmentMask));
4467 Check(eq, kUnalignedAllocationInNewSpace, at, Operand(zero_reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004468 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004469
Ben Murdochc5610432016-08-08 18:44:38 +01004470 if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
4471 // The top pointer is not updated for allocation folding dominators.
4472 sd(result_end, MemOperand(top_address));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004473 }
Ben Murdochc5610432016-08-08 18:44:38 +01004474
4475 // Tag object if.
4476 Daddu(result, result, Operand(kHeapObjectTag));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004477}
4478
Ben Murdochc5610432016-08-08 18:44:38 +01004479void MacroAssembler::FastAllocate(int object_size, Register result,
4480 Register scratch1, Register scratch2,
4481 AllocationFlags flags) {
4482 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
4483 DCHECK(!AreAliased(result, scratch1, scratch2, at));
4484
4485 // Make object size into bytes.
4486 if ((flags & SIZE_IN_WORDS) != 0) {
4487 object_size *= kPointerSize;
4488 }
4489 DCHECK(0 == (object_size & kObjectAlignmentMask));
4490
4491 ExternalReference allocation_top =
4492 AllocationUtils::GetAllocationTopReference(isolate(), flags);
4493
4494 Register top_address = scratch1;
4495 Register result_end = scratch2;
4496 li(top_address, Operand(allocation_top));
4497 ld(result, MemOperand(top_address));
4498
4499 // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have
4500 // the same alignment on MIPS64.
4501 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
4502
4503 if (emit_debug_code()) {
4504 And(at, result, Operand(kDoubleAlignmentMask));
4505 Check(eq, kAllocationIsNotDoubleAligned, at, Operand(zero_reg));
4506 }
4507
4508 // Calculate new top and write it back.
4509 Daddu(result_end, result, Operand(object_size));
4510 sd(result_end, MemOperand(top_address));
4511
4512 Daddu(result, result, Operand(kHeapObjectTag));
4513}
4514
4515void MacroAssembler::FastAllocate(Register object_size, Register result,
4516 Register result_end, Register scratch,
4517 AllocationFlags flags) {
4518 // |object_size| and |result_end| may overlap, other registers must not.
4519 DCHECK(!AreAliased(object_size, result, scratch, at));
4520 DCHECK(!AreAliased(result_end, result, scratch, at));
4521
4522 ExternalReference allocation_top =
4523 AllocationUtils::GetAllocationTopReference(isolate(), flags);
4524
4525 // Set up allocation top address and object size registers.
4526 Register top_address = scratch;
4527 li(top_address, Operand(allocation_top));
4528 ld(result, MemOperand(top_address));
4529
4530 // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have
4531 // the same alignment on MIPS64.
4532 STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
4533
4534 if (emit_debug_code()) {
4535 And(at, result, Operand(kDoubleAlignmentMask));
4536 Check(eq, kAllocationIsNotDoubleAligned, at, Operand(zero_reg));
4537 }
4538
4539 // Calculate new top and write it back
4540 if ((flags & SIZE_IN_WORDS) != 0) {
4541 Dlsa(result_end, result, object_size, kPointerSizeLog2);
4542 } else {
4543 Daddu(result_end, result, Operand(object_size));
4544 }
4545
4546 // Update allocation top. result temporarily holds the new top.
4547 if (emit_debug_code()) {
4548 And(at, result_end, Operand(kObjectAlignmentMask));
4549 Check(eq, kUnalignedAllocationInNewSpace, at, Operand(zero_reg));
4550 }
4551
4552 Daddu(result, result, Operand(kHeapObjectTag));
4553}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004554
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004555void MacroAssembler::AllocateTwoByteString(Register result,
4556 Register length,
4557 Register scratch1,
4558 Register scratch2,
4559 Register scratch3,
4560 Label* gc_required) {
4561 // Calculate the number of bytes needed for the characters in the string while
4562 // observing object alignment.
4563 DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
4564 dsll(scratch1, length, 1); // Length in bytes, not chars.
4565 daddiu(scratch1, scratch1,
4566 kObjectAlignmentMask + SeqTwoByteString::kHeaderSize);
4567 And(scratch1, scratch1, Operand(~kObjectAlignmentMask));
4568
4569 // Allocate two-byte string in new space.
Ben Murdochc5610432016-08-08 18:44:38 +01004570 Allocate(scratch1, result, scratch2, scratch3, gc_required,
4571 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004572
4573 // Set the map, length and hash field.
4574 InitializeNewString(result,
4575 length,
4576 Heap::kStringMapRootIndex,
4577 scratch1,
4578 scratch2);
4579}
4580
4581
4582void MacroAssembler::AllocateOneByteString(Register result, Register length,
4583 Register scratch1, Register scratch2,
4584 Register scratch3,
4585 Label* gc_required) {
4586 // Calculate the number of bytes needed for the characters in the string
4587 // while observing object alignment.
4588 DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
4589 DCHECK(kCharSize == 1);
4590 daddiu(scratch1, length,
4591 kObjectAlignmentMask + SeqOneByteString::kHeaderSize);
4592 And(scratch1, scratch1, Operand(~kObjectAlignmentMask));
4593
4594 // Allocate one-byte string in new space.
Ben Murdochc5610432016-08-08 18:44:38 +01004595 Allocate(scratch1, result, scratch2, scratch3, gc_required,
4596 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004597
4598 // Set the map, length and hash field.
4599 InitializeNewString(result, length, Heap::kOneByteStringMapRootIndex,
4600 scratch1, scratch2);
4601}
4602
4603
4604void MacroAssembler::AllocateTwoByteConsString(Register result,
4605 Register length,
4606 Register scratch1,
4607 Register scratch2,
4608 Label* gc_required) {
4609 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01004610 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004611 InitializeNewString(result,
4612 length,
4613 Heap::kConsStringMapRootIndex,
4614 scratch1,
4615 scratch2);
4616}
4617
4618
4619void MacroAssembler::AllocateOneByteConsString(Register result, Register length,
4620 Register scratch1,
4621 Register scratch2,
4622 Label* gc_required) {
Ben Murdochc5610432016-08-08 18:44:38 +01004623 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
4624 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004625
4626 InitializeNewString(result, length, Heap::kConsOneByteStringMapRootIndex,
4627 scratch1, scratch2);
4628}
4629
4630
4631void MacroAssembler::AllocateTwoByteSlicedString(Register result,
4632 Register length,
4633 Register scratch1,
4634 Register scratch2,
4635 Label* gc_required) {
4636 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01004637 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004638
4639 InitializeNewString(result,
4640 length,
4641 Heap::kSlicedStringMapRootIndex,
4642 scratch1,
4643 scratch2);
4644}
4645
4646
4647void MacroAssembler::AllocateOneByteSlicedString(Register result,
4648 Register length,
4649 Register scratch1,
4650 Register scratch2,
4651 Label* gc_required) {
4652 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
Ben Murdochc5610432016-08-08 18:44:38 +01004653 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004654
4655 InitializeNewString(result, length, Heap::kSlicedOneByteStringMapRootIndex,
4656 scratch1, scratch2);
4657}
4658
4659
4660void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg,
4661 Label* not_unique_name) {
4662 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
4663 Label succeed;
4664 And(at, reg, Operand(kIsNotStringMask | kIsNotInternalizedMask));
4665 Branch(&succeed, eq, at, Operand(zero_reg));
4666 Branch(not_unique_name, ne, reg, Operand(SYMBOL_TYPE));
4667
4668 bind(&succeed);
4669}
4670
4671
4672// Allocates a heap number or jumps to the label if the young space is full and
4673// a scavenge is needed.
4674void MacroAssembler::AllocateHeapNumber(Register result,
4675 Register scratch1,
4676 Register scratch2,
4677 Register heap_number_map,
4678 Label* need_gc,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004679 MutableMode mode) {
4680 // Allocate an object in the heap for the heap number and tag it as a heap
4681 // object.
4682 Allocate(HeapNumber::kSize, result, scratch1, scratch2, need_gc,
Ben Murdochc5610432016-08-08 18:44:38 +01004683 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004684
4685 Heap::RootListIndex map_index = mode == MUTABLE
4686 ? Heap::kMutableHeapNumberMapRootIndex
4687 : Heap::kHeapNumberMapRootIndex;
4688 AssertIsRoot(heap_number_map, map_index);
4689
4690 // Store heap number map in the allocated object.
Ben Murdochc5610432016-08-08 18:44:38 +01004691 sd(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004692}
4693
4694
4695void MacroAssembler::AllocateHeapNumberWithValue(Register result,
4696 FPURegister value,
4697 Register scratch1,
4698 Register scratch2,
4699 Label* gc_required) {
4700 LoadRoot(t8, Heap::kHeapNumberMapRootIndex);
4701 AllocateHeapNumber(result, scratch1, scratch2, t8, gc_required);
4702 sdc1(value, FieldMemOperand(result, HeapNumber::kValueOffset));
4703}
4704
4705
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004706void MacroAssembler::AllocateJSValue(Register result, Register constructor,
4707 Register value, Register scratch1,
4708 Register scratch2, Label* gc_required) {
4709 DCHECK(!result.is(constructor));
4710 DCHECK(!result.is(scratch1));
4711 DCHECK(!result.is(scratch2));
4712 DCHECK(!result.is(value));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004713
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004714 // Allocate JSValue in new space.
Ben Murdochc5610432016-08-08 18:44:38 +01004715 Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required,
4716 NO_ALLOCATION_FLAGS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004717
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004718 // Initialize the JSValue.
4719 LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
4720 sd(scratch1, FieldMemOperand(result, HeapObject::kMapOffset));
4721 LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
4722 sd(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset));
4723 sd(scratch1, FieldMemOperand(result, JSObject::kElementsOffset));
4724 sd(value, FieldMemOperand(result, JSValue::kValueOffset));
4725 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004726}
4727
4728
4729void MacroAssembler::CopyBytes(Register src,
4730 Register dst,
4731 Register length,
4732 Register scratch) {
4733 Label align_loop_1, word_loop, byte_loop, byte_loop_1, done;
4734
4735 // Align src before copying in word size chunks.
4736 Branch(&byte_loop, le, length, Operand(kPointerSize));
4737 bind(&align_loop_1);
4738 And(scratch, src, kPointerSize - 1);
4739 Branch(&word_loop, eq, scratch, Operand(zero_reg));
4740 lbu(scratch, MemOperand(src));
4741 Daddu(src, src, 1);
4742 sb(scratch, MemOperand(dst));
4743 Daddu(dst, dst, 1);
4744 Dsubu(length, length, Operand(1));
4745 Branch(&align_loop_1, ne, length, Operand(zero_reg));
4746
4747 // Copy bytes in word size chunks.
4748 bind(&word_loop);
4749 if (emit_debug_code()) {
4750 And(scratch, src, kPointerSize - 1);
4751 Assert(eq, kExpectingAlignmentForCopyBytes,
4752 scratch, Operand(zero_reg));
4753 }
4754 Branch(&byte_loop, lt, length, Operand(kPointerSize));
4755 ld(scratch, MemOperand(src));
4756 Daddu(src, src, kPointerSize);
4757
4758 // TODO(kalmard) check if this can be optimized to use sw in most cases.
4759 // Can't use unaligned access - copy byte by byte.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004760 if (kArchEndian == kLittle) {
4761 sb(scratch, MemOperand(dst, 0));
4762 dsrl(scratch, scratch, 8);
4763 sb(scratch, MemOperand(dst, 1));
4764 dsrl(scratch, scratch, 8);
4765 sb(scratch, MemOperand(dst, 2));
4766 dsrl(scratch, scratch, 8);
4767 sb(scratch, MemOperand(dst, 3));
4768 dsrl(scratch, scratch, 8);
4769 sb(scratch, MemOperand(dst, 4));
4770 dsrl(scratch, scratch, 8);
4771 sb(scratch, MemOperand(dst, 5));
4772 dsrl(scratch, scratch, 8);
4773 sb(scratch, MemOperand(dst, 6));
4774 dsrl(scratch, scratch, 8);
4775 sb(scratch, MemOperand(dst, 7));
4776 } else {
4777 sb(scratch, MemOperand(dst, 7));
4778 dsrl(scratch, scratch, 8);
4779 sb(scratch, MemOperand(dst, 6));
4780 dsrl(scratch, scratch, 8);
4781 sb(scratch, MemOperand(dst, 5));
4782 dsrl(scratch, scratch, 8);
4783 sb(scratch, MemOperand(dst, 4));
4784 dsrl(scratch, scratch, 8);
4785 sb(scratch, MemOperand(dst, 3));
4786 dsrl(scratch, scratch, 8);
4787 sb(scratch, MemOperand(dst, 2));
4788 dsrl(scratch, scratch, 8);
4789 sb(scratch, MemOperand(dst, 1));
4790 dsrl(scratch, scratch, 8);
4791 sb(scratch, MemOperand(dst, 0));
4792 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004793 Daddu(dst, dst, 8);
4794
4795 Dsubu(length, length, Operand(kPointerSize));
4796 Branch(&word_loop);
4797
4798 // Copy the last bytes if any left.
4799 bind(&byte_loop);
4800 Branch(&done, eq, length, Operand(zero_reg));
4801 bind(&byte_loop_1);
4802 lbu(scratch, MemOperand(src));
4803 Daddu(src, src, 1);
4804 sb(scratch, MemOperand(dst));
4805 Daddu(dst, dst, 1);
4806 Dsubu(length, length, Operand(1));
4807 Branch(&byte_loop_1, ne, length, Operand(zero_reg));
4808 bind(&done);
4809}
4810
4811
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004812void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
4813 Register end_address,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004814 Register filler) {
4815 Label loop, entry;
4816 Branch(&entry);
4817 bind(&loop);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004818 sd(filler, MemOperand(current_address));
4819 Daddu(current_address, current_address, kPointerSize);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004820 bind(&entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004821 Branch(&loop, ult, current_address, Operand(end_address));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004822}
4823
4824
4825void MacroAssembler::CheckFastElements(Register map,
4826 Register scratch,
4827 Label* fail) {
4828 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
4829 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
4830 STATIC_ASSERT(FAST_ELEMENTS == 2);
4831 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
4832 lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset));
4833 Branch(fail, hi, scratch,
4834 Operand(Map::kMaximumBitField2FastHoleyElementValue));
4835}
4836
4837
4838void MacroAssembler::CheckFastObjectElements(Register map,
4839 Register scratch,
4840 Label* fail) {
4841 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
4842 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
4843 STATIC_ASSERT(FAST_ELEMENTS == 2);
4844 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
4845 lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset));
4846 Branch(fail, ls, scratch,
4847 Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
4848 Branch(fail, hi, scratch,
4849 Operand(Map::kMaximumBitField2FastHoleyElementValue));
4850}
4851
4852
4853void MacroAssembler::CheckFastSmiElements(Register map,
4854 Register scratch,
4855 Label* fail) {
4856 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
4857 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
4858 lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset));
4859 Branch(fail, hi, scratch,
4860 Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
4861}
4862
4863
4864void MacroAssembler::StoreNumberToDoubleElements(Register value_reg,
4865 Register key_reg,
4866 Register elements_reg,
4867 Register scratch1,
4868 Register scratch2,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004869 Label* fail,
4870 int elements_offset) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004871 DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1, scratch2));
4872 Label smi_value, done;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004873
4874 // Handle smi values specially.
4875 JumpIfSmi(value_reg, &smi_value);
4876
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004877 // Ensure that the object is a heap number.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004878 CheckMap(value_reg,
4879 scratch1,
4880 Heap::kHeapNumberMapRootIndex,
4881 fail,
4882 DONT_DO_SMI_CHECK);
4883
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004884 // Double value, turn potential sNaN into qNan.
4885 DoubleRegister double_result = f0;
4886 DoubleRegister double_scratch = f2;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004887
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004888 ldc1(double_result, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
4889 Branch(USE_DELAY_SLOT, &done); // Canonicalization is one instruction.
4890 FPUCanonicalizeNaN(double_result, double_result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004891
4892 bind(&smi_value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004893 // Untag and transfer.
4894 dsrl32(scratch1, value_reg, 0);
4895 mtc1(scratch1, double_scratch);
4896 cvt_d_w(double_result, double_scratch);
4897
4898 bind(&done);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004899 Daddu(scratch1, elements_reg,
4900 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag -
4901 elements_offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004902 dsra(scratch2, key_reg, 32 - kDoubleSizeLog2);
4903 Daddu(scratch1, scratch1, scratch2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004904 // scratch1 is now effective address of the double element.
4905 sdc1(double_result, MemOperand(scratch1, 0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004906}
4907
Ben Murdoch61f157c2016-09-16 13:49:30 +01004908void MacroAssembler::SubNanPreservePayloadAndSign_s(FPURegister fd,
4909 FPURegister fs,
4910 FPURegister ft) {
4911 FloatRegister dest = fd.is(fs) || fd.is(ft) ? kLithiumScratchDouble : fd;
4912 Label check_nan, save_payload, done;
4913 Register scratch1 = t8;
4914 Register scratch2 = t9;
4915
4916 sub_s(dest, fs, ft);
4917 // Check if the result of subtraction is NaN.
4918 BranchF32(nullptr, &check_nan, eq, fs, ft);
4919 Branch(USE_DELAY_SLOT, &done);
4920 dest.is(fd) ? nop() : mov_s(fd, dest);
4921
4922 bind(&check_nan);
4923 // Check if first operand is a NaN.
4924 mfc1(scratch1, fs);
4925 BranchF32(nullptr, &save_payload, eq, fs, fs);
4926 // Second operand must be a NaN.
4927 mfc1(scratch1, ft);
4928
4929 bind(&save_payload);
4930 // Reserve payload.
4931 And(scratch1, scratch1,
4932 Operand(kSingleSignMask | ((1 << kSingleNaNShift) - 1)));
4933 mfc1(scratch2, dest);
4934 And(scratch2, scratch2, Operand(kSingleNaNMask));
4935 Or(scratch2, scratch2, scratch1);
4936 mtc1(scratch2, fd);
4937
4938 bind(&done);
4939}
4940
4941void MacroAssembler::SubNanPreservePayloadAndSign_d(FPURegister fd,
4942 FPURegister fs,
4943 FPURegister ft) {
4944 FloatRegister dest = fd.is(fs) || fd.is(ft) ? kLithiumScratchDouble : fd;
4945 Label check_nan, save_payload, done;
4946 Register scratch1 = t8;
4947 Register scratch2 = t9;
4948
4949 sub_d(dest, fs, ft);
4950 // Check if the result of subtraction is NaN.
4951 BranchF64(nullptr, &check_nan, eq, fs, ft);
4952 Branch(USE_DELAY_SLOT, &done);
4953 dest.is(fd) ? nop() : mov_d(fd, dest);
4954
4955 bind(&check_nan);
4956 // Check if first operand is a NaN.
4957 dmfc1(scratch1, fs);
4958 BranchF64(nullptr, &save_payload, eq, fs, fs);
4959 // Second operand must be a NaN.
4960 dmfc1(scratch1, ft);
4961
4962 bind(&save_payload);
4963 // Reserve payload.
4964 li(at, Operand(kDoubleSignMask | (1L << kDoubleNaNShift)));
4965 Dsubu(at, at, Operand(1));
4966 And(scratch1, scratch1, at);
4967 dmfc1(scratch2, dest);
4968 And(scratch2, scratch2, Operand(kDoubleNaNMask));
4969 Or(scratch2, scratch2, scratch1);
4970 dmtc1(scratch2, fd);
4971
4972 bind(&done);
4973}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004974
4975void MacroAssembler::CompareMapAndBranch(Register obj,
4976 Register scratch,
4977 Handle<Map> map,
4978 Label* early_success,
4979 Condition cond,
4980 Label* branch_to) {
4981 ld(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
4982 CompareMapAndBranch(scratch, map, early_success, cond, branch_to);
4983}
4984
4985
4986void MacroAssembler::CompareMapAndBranch(Register obj_map,
4987 Handle<Map> map,
4988 Label* early_success,
4989 Condition cond,
4990 Label* branch_to) {
4991 Branch(branch_to, cond, obj_map, Operand(map));
4992}
4993
4994
4995void MacroAssembler::CheckMap(Register obj,
4996 Register scratch,
4997 Handle<Map> map,
4998 Label* fail,
4999 SmiCheckType smi_check_type) {
5000 if (smi_check_type == DO_SMI_CHECK) {
5001 JumpIfSmi(obj, fail);
5002 }
5003 Label success;
5004 CompareMapAndBranch(obj, scratch, map, &success, ne, fail);
5005 bind(&success);
5006}
5007
5008
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005009void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
5010 Register scratch2, Handle<WeakCell> cell,
5011 Handle<Code> success,
5012 SmiCheckType smi_check_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005013 Label fail;
5014 if (smi_check_type == DO_SMI_CHECK) {
5015 JumpIfSmi(obj, &fail);
5016 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005017 ld(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset));
5018 GetWeakValue(scratch2, cell);
5019 Jump(success, RelocInfo::CODE_TARGET, eq, scratch1, Operand(scratch2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005020 bind(&fail);
5021}
5022
5023
5024void MacroAssembler::CheckMap(Register obj,
5025 Register scratch,
5026 Heap::RootListIndex index,
5027 Label* fail,
5028 SmiCheckType smi_check_type) {
5029 if (smi_check_type == DO_SMI_CHECK) {
5030 JumpIfSmi(obj, fail);
5031 }
5032 ld(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
5033 LoadRoot(at, index);
5034 Branch(fail, ne, scratch, Operand(at));
5035}
5036
5037
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005038void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
5039 li(value, Operand(cell));
5040 ld(value, FieldMemOperand(value, WeakCell::kValueOffset));
5041}
5042
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005043void MacroAssembler::FPUCanonicalizeNaN(const DoubleRegister dst,
5044 const DoubleRegister src) {
5045 sub_d(dst, src, kDoubleRegZero);
5046}
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005047
5048void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
5049 Label* miss) {
5050 GetWeakValue(value, cell);
5051 JumpIfSmi(value, miss);
5052}
5053
5054
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005055void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) {
5056 if (IsMipsSoftFloatABI) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005057 if (kArchEndian == kLittle) {
5058 Move(dst, v0, v1);
5059 } else {
5060 Move(dst, v1, v0);
5061 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005062 } else {
5063 Move(dst, f0); // Reg f0 is o32 ABI FP return value.
5064 }
5065}
5066
5067
5068void MacroAssembler::MovFromFloatParameter(const DoubleRegister dst) {
5069 if (IsMipsSoftFloatABI) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005070 if (kArchEndian == kLittle) {
5071 Move(dst, a0, a1);
5072 } else {
5073 Move(dst, a1, a0);
5074 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005075 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005076 Move(dst, f12); // Reg f12 is n64 ABI FP first argument value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005077 }
5078}
5079
5080
5081void MacroAssembler::MovToFloatParameter(DoubleRegister src) {
5082 if (!IsMipsSoftFloatABI) {
5083 Move(f12, src);
5084 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005085 if (kArchEndian == kLittle) {
5086 Move(a0, a1, src);
5087 } else {
5088 Move(a1, a0, src);
5089 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005090 }
5091}
5092
5093
5094void MacroAssembler::MovToFloatResult(DoubleRegister src) {
5095 if (!IsMipsSoftFloatABI) {
5096 Move(f0, src);
5097 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005098 if (kArchEndian == kLittle) {
5099 Move(v0, v1, src);
5100 } else {
5101 Move(v1, v0, src);
5102 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005103 }
5104}
5105
5106
5107void MacroAssembler::MovToFloatParameters(DoubleRegister src1,
5108 DoubleRegister src2) {
5109 if (!IsMipsSoftFloatABI) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01005110 const DoubleRegister fparg2 = f13;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005111 if (src2.is(f12)) {
5112 DCHECK(!src1.is(fparg2));
5113 Move(fparg2, src2);
5114 Move(f12, src1);
5115 } else {
5116 Move(f12, src1);
5117 Move(fparg2, src2);
5118 }
5119 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005120 if (kArchEndian == kLittle) {
5121 Move(a0, a1, src1);
5122 Move(a2, a3, src2);
5123 } else {
5124 Move(a1, a0, src1);
5125 Move(a3, a2, src2);
5126 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005127 }
5128}
5129
5130
5131// -----------------------------------------------------------------------------
5132// JavaScript invokes.
5133
Ben Murdochda12d292016-06-02 14:46:10 +01005134void MacroAssembler::PrepareForTailCall(const ParameterCount& callee_args_count,
5135 Register caller_args_count_reg,
5136 Register scratch0, Register scratch1) {
5137#if DEBUG
5138 if (callee_args_count.is_reg()) {
5139 DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0,
5140 scratch1));
5141 } else {
5142 DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1));
5143 }
5144#endif
5145
5146 // Calculate the end of destination area where we will put the arguments
5147 // after we drop current frame. We add kPointerSize to count the receiver
5148 // argument which is not included into formal parameters count.
5149 Register dst_reg = scratch0;
5150 Dlsa(dst_reg, fp, caller_args_count_reg, kPointerSizeLog2);
5151 Daddu(dst_reg, dst_reg,
5152 Operand(StandardFrameConstants::kCallerSPOffset + kPointerSize));
5153
5154 Register src_reg = caller_args_count_reg;
5155 // Calculate the end of source area. +kPointerSize is for the receiver.
5156 if (callee_args_count.is_reg()) {
5157 Dlsa(src_reg, sp, callee_args_count.reg(), kPointerSizeLog2);
5158 Daddu(src_reg, src_reg, Operand(kPointerSize));
5159 } else {
5160 Daddu(src_reg, sp,
5161 Operand((callee_args_count.immediate() + 1) * kPointerSize));
5162 }
5163
5164 if (FLAG_debug_code) {
5165 Check(lo, kStackAccessBelowStackPointer, src_reg, Operand(dst_reg));
5166 }
5167
5168 // Restore caller's frame pointer and return address now as they will be
5169 // overwritten by the copying loop.
5170 ld(ra, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
5171 ld(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
5172
5173 // Now copy callee arguments to the caller frame going backwards to avoid
5174 // callee arguments corruption (source and destination areas could overlap).
5175
5176 // Both src_reg and dst_reg are pointing to the word after the one to copy,
5177 // so they must be pre-decremented in the loop.
5178 Register tmp_reg = scratch1;
5179 Label loop, entry;
5180 Branch(&entry);
5181 bind(&loop);
5182 Dsubu(src_reg, src_reg, Operand(kPointerSize));
5183 Dsubu(dst_reg, dst_reg, Operand(kPointerSize));
5184 ld(tmp_reg, MemOperand(src_reg));
5185 sd(tmp_reg, MemOperand(dst_reg));
5186 bind(&entry);
5187 Branch(&loop, ne, sp, Operand(src_reg));
5188
5189 // Leave current frame.
5190 mov(sp, dst_reg);
5191}
5192
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005193void MacroAssembler::InvokePrologue(const ParameterCount& expected,
5194 const ParameterCount& actual,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005195 Label* done,
5196 bool* definitely_mismatches,
5197 InvokeFlag flag,
5198 const CallWrapper& call_wrapper) {
5199 bool definitely_matches = false;
5200 *definitely_mismatches = false;
5201 Label regular_invoke;
5202
5203 // Check whether the expected and actual arguments count match. If not,
5204 // setup registers according to contract with ArgumentsAdaptorTrampoline:
5205 // a0: actual arguments count
5206 // a1: function (passed through to callee)
5207 // a2: expected arguments count
5208
5209 // The code below is made a lot easier because the calling code already sets
5210 // up actual and expected registers according to the contract if values are
5211 // passed in registers.
5212 DCHECK(actual.is_immediate() || actual.reg().is(a0));
5213 DCHECK(expected.is_immediate() || expected.reg().is(a2));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005214
5215 if (expected.is_immediate()) {
5216 DCHECK(actual.is_immediate());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005217 li(a0, Operand(actual.immediate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005218 if (expected.immediate() == actual.immediate()) {
5219 definitely_matches = true;
5220 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005221 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
5222 if (expected.immediate() == sentinel) {
5223 // Don't worry about adapting arguments for builtins that
5224 // don't want that done. Skip adaption code by making it look
5225 // like we have a match between expected and actual number of
5226 // arguments.
5227 definitely_matches = true;
5228 } else {
5229 *definitely_mismatches = true;
5230 li(a2, Operand(expected.immediate()));
5231 }
5232 }
5233 } else if (actual.is_immediate()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005234 li(a0, Operand(actual.immediate()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005235 Branch(&regular_invoke, eq, expected.reg(), Operand(a0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005236 } else {
5237 Branch(&regular_invoke, eq, expected.reg(), Operand(actual.reg()));
5238 }
5239
5240 if (!definitely_matches) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005241 Handle<Code> adaptor =
5242 isolate()->builtins()->ArgumentsAdaptorTrampoline();
5243 if (flag == CALL_FUNCTION) {
5244 call_wrapper.BeforeCall(CallSize(adaptor));
5245 Call(adaptor);
5246 call_wrapper.AfterCall();
5247 if (!*definitely_mismatches) {
5248 Branch(done);
5249 }
5250 } else {
5251 Jump(adaptor, RelocInfo::CODE_TARGET);
5252 }
5253 bind(&regular_invoke);
5254 }
5255}
5256
5257
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005258void MacroAssembler::FloodFunctionIfStepping(Register fun, Register new_target,
5259 const ParameterCount& expected,
5260 const ParameterCount& actual) {
5261 Label skip_flooding;
Ben Murdoch61f157c2016-09-16 13:49:30 +01005262 ExternalReference last_step_action =
5263 ExternalReference::debug_last_step_action_address(isolate());
5264 STATIC_ASSERT(StepFrame > StepIn);
5265 li(t0, Operand(last_step_action));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005266 lb(t0, MemOperand(t0));
Ben Murdoch61f157c2016-09-16 13:49:30 +01005267 Branch(&skip_flooding, lt, t0, Operand(StepIn));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005268 {
5269 FrameScope frame(this,
5270 has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
5271 if (expected.is_reg()) {
5272 SmiTag(expected.reg());
5273 Push(expected.reg());
5274 }
5275 if (actual.is_reg()) {
5276 SmiTag(actual.reg());
5277 Push(actual.reg());
5278 }
5279 if (new_target.is_valid()) {
5280 Push(new_target);
5281 }
5282 Push(fun);
5283 Push(fun);
Ben Murdoch097c5b22016-05-18 11:27:45 +01005284 CallRuntime(Runtime::kDebugPrepareStepInIfStepping);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005285 Pop(fun);
5286 if (new_target.is_valid()) {
5287 Pop(new_target);
5288 }
5289 if (actual.is_reg()) {
5290 Pop(actual.reg());
5291 SmiUntag(actual.reg());
5292 }
5293 if (expected.is_reg()) {
5294 Pop(expected.reg());
5295 SmiUntag(expected.reg());
5296 }
5297 }
5298 bind(&skip_flooding);
5299}
5300
5301
5302void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
5303 const ParameterCount& expected,
5304 const ParameterCount& actual,
5305 InvokeFlag flag,
5306 const CallWrapper& call_wrapper) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005307 // You can't call a function without a valid frame.
5308 DCHECK(flag == JUMP_FUNCTION || has_frame());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005309 DCHECK(function.is(a1));
5310 DCHECK_IMPLIES(new_target.is_valid(), new_target.is(a3));
5311
5312 if (call_wrapper.NeedsDebugStepCheck()) {
5313 FloodFunctionIfStepping(function, new_target, expected, actual);
5314 }
5315
5316 // Clear the new.target register if not given.
5317 if (!new_target.is_valid()) {
5318 LoadRoot(a3, Heap::kUndefinedValueRootIndex);
5319 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005320
5321 Label done;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005322 bool definitely_mismatches = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005323 InvokePrologue(expected, actual, &done, &definitely_mismatches, flag,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005324 call_wrapper);
5325 if (!definitely_mismatches) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005326 // We call indirectly through the code field in the function to
5327 // allow recompilation to take effect without changing any of the
5328 // call sites.
5329 Register code = t0;
5330 ld(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005331 if (flag == CALL_FUNCTION) {
5332 call_wrapper.BeforeCall(CallSize(code));
5333 Call(code);
5334 call_wrapper.AfterCall();
5335 } else {
5336 DCHECK(flag == JUMP_FUNCTION);
5337 Jump(code);
5338 }
5339 // Continue here if InvokePrologue does handle the invocation due to
5340 // mismatched parameter counts.
5341 bind(&done);
5342 }
5343}
5344
5345
5346void MacroAssembler::InvokeFunction(Register function,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005347 Register new_target,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005348 const ParameterCount& actual,
5349 InvokeFlag flag,
5350 const CallWrapper& call_wrapper) {
5351 // You can't call a function without a valid frame.
5352 DCHECK(flag == JUMP_FUNCTION || has_frame());
5353
5354 // Contract with called JS functions requires that function is passed in a1.
5355 DCHECK(function.is(a1));
5356 Register expected_reg = a2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005357 Register temp_reg = t0;
5358 ld(temp_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005359 ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
5360 // The argument count is stored as int32_t on 64-bit platforms.
5361 // TODO(plind): Smi on 32-bit platforms.
5362 lw(expected_reg,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005363 FieldMemOperand(temp_reg,
5364 SharedFunctionInfo::kFormalParameterCountOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005365 ParameterCount expected(expected_reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005366 InvokeFunctionCode(a1, new_target, expected, actual, flag, call_wrapper);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005367}
5368
5369
5370void MacroAssembler::InvokeFunction(Register function,
5371 const ParameterCount& expected,
5372 const ParameterCount& actual,
5373 InvokeFlag flag,
5374 const CallWrapper& call_wrapper) {
5375 // You can't call a function without a valid frame.
5376 DCHECK(flag == JUMP_FUNCTION || has_frame());
5377
5378 // Contract with called JS functions requires that function is passed in a1.
5379 DCHECK(function.is(a1));
5380
5381 // Get the function and setup the context.
5382 ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
5383
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005384 InvokeFunctionCode(a1, no_reg, expected, actual, flag, call_wrapper);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005385}
5386
5387
5388void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
5389 const ParameterCount& expected,
5390 const ParameterCount& actual,
5391 InvokeFlag flag,
5392 const CallWrapper& call_wrapper) {
5393 li(a1, function);
5394 InvokeFunction(a1, expected, actual, flag, call_wrapper);
5395}
5396
5397
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005398void MacroAssembler::IsObjectJSStringType(Register object,
5399 Register scratch,
5400 Label* fail) {
5401 DCHECK(kNotStringTag != 0);
5402
5403 ld(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
5404 lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
5405 And(scratch, scratch, Operand(kIsNotStringMask));
5406 Branch(fail, ne, scratch, Operand(zero_reg));
5407}
5408
5409
5410void MacroAssembler::IsObjectNameType(Register object,
5411 Register scratch,
5412 Label* fail) {
5413 ld(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
5414 lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
5415 Branch(fail, hi, scratch, Operand(LAST_NAME_TYPE));
5416}
5417
5418
5419// ---------------------------------------------------------------------------
5420// Support functions.
5421
5422
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005423void MacroAssembler::GetMapConstructor(Register result, Register map,
5424 Register temp, Register temp2) {
5425 Label done, loop;
5426 ld(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
5427 bind(&loop);
5428 JumpIfSmi(result, &done);
5429 GetObjectType(result, temp, temp2);
5430 Branch(&done, ne, temp2, Operand(MAP_TYPE));
5431 ld(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
5432 Branch(&loop);
5433 bind(&done);
5434}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005435
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005436
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005437void MacroAssembler::TryGetFunctionPrototype(Register function, Register result,
5438 Register scratch, Label* miss) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005439 // Get the prototype or initial map from the function.
5440 ld(result,
5441 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
5442
5443 // If the prototype or initial map is the hole, don't return it and
5444 // simply miss the cache instead. This will allow us to allocate a
5445 // prototype object on-demand in the runtime system.
5446 LoadRoot(t8, Heap::kTheHoleValueRootIndex);
5447 Branch(miss, eq, result, Operand(t8));
5448
5449 // If the function does not have an initial map, we're done.
5450 Label done;
5451 GetObjectType(result, scratch, scratch);
5452 Branch(&done, ne, scratch, Operand(MAP_TYPE));
5453
5454 // Get the prototype from the initial map.
5455 ld(result, FieldMemOperand(result, Map::kPrototypeOffset));
5456
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005457 // All done.
5458 bind(&done);
5459}
5460
5461
5462void MacroAssembler::GetObjectType(Register object,
5463 Register map,
5464 Register type_reg) {
5465 ld(map, FieldMemOperand(object, HeapObject::kMapOffset));
5466 lbu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
5467}
5468
5469
5470// -----------------------------------------------------------------------------
5471// Runtime calls.
5472
5473void MacroAssembler::CallStub(CodeStub* stub,
5474 TypeFeedbackId ast_id,
5475 Condition cond,
5476 Register r1,
5477 const Operand& r2,
5478 BranchDelaySlot bd) {
5479 DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs.
5480 Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id,
5481 cond, r1, r2, bd);
5482}
5483
5484
5485void MacroAssembler::TailCallStub(CodeStub* stub,
5486 Condition cond,
5487 Register r1,
5488 const Operand& r2,
5489 BranchDelaySlot bd) {
5490 Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond, r1, r2, bd);
5491}
5492
5493
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005494bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
5495 return has_frame_ || !stub->SometimesSetsUpAFrame();
5496}
5497
5498
5499void MacroAssembler::IndexFromHash(Register hash, Register index) {
5500 // If the hash field contains an array index pick it out. The assert checks
5501 // that the constants for the maximum number of digits for an array index
5502 // cached in the hash field and the number of bits reserved for it does not
5503 // conflict.
5504 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
5505 (1 << String::kArrayIndexValueBits));
5506 DecodeFieldToSmi<String::ArrayIndexValueBits>(index, hash);
5507}
5508
5509
5510void MacroAssembler::ObjectToDoubleFPURegister(Register object,
5511 FPURegister result,
5512 Register scratch1,
5513 Register scratch2,
5514 Register heap_number_map,
5515 Label* not_number,
5516 ObjectToDoubleFlags flags) {
5517 Label done;
5518 if ((flags & OBJECT_NOT_SMI) == 0) {
5519 Label not_smi;
5520 JumpIfNotSmi(object, &not_smi);
5521 // Remove smi tag and convert to double.
5522 // dsra(scratch1, object, kSmiTagSize);
5523 dsra32(scratch1, object, 0);
5524 mtc1(scratch1, result);
5525 cvt_d_w(result, result);
5526 Branch(&done);
5527 bind(&not_smi);
5528 }
5529 // Check for heap number and load double value from it.
5530 ld(scratch1, FieldMemOperand(object, HeapObject::kMapOffset));
5531 Branch(not_number, ne, scratch1, Operand(heap_number_map));
5532
5533 if ((flags & AVOID_NANS_AND_INFINITIES) != 0) {
5534 // If exponent is all ones the number is either a NaN or +/-Infinity.
5535 Register exponent = scratch1;
5536 Register mask_reg = scratch2;
5537 lwu(exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
5538 li(mask_reg, HeapNumber::kExponentMask);
5539
5540 And(exponent, exponent, mask_reg);
5541 Branch(not_number, eq, exponent, Operand(mask_reg));
5542 }
5543 ldc1(result, FieldMemOperand(object, HeapNumber::kValueOffset));
5544 bind(&done);
5545}
5546
5547
5548void MacroAssembler::SmiToDoubleFPURegister(Register smi,
5549 FPURegister value,
5550 Register scratch1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005551 dsra32(scratch1, smi, 0);
5552 mtc1(scratch1, value);
5553 cvt_d_w(value, value);
5554}
5555
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005556static inline void BranchOvfHelper(MacroAssembler* masm, Register overflow_dst,
5557 Label* overflow_label,
5558 Label* no_overflow_label) {
5559 DCHECK(overflow_label || no_overflow_label);
5560 if (!overflow_label) {
5561 DCHECK(no_overflow_label);
5562 masm->Branch(no_overflow_label, ge, overflow_dst, Operand(zero_reg));
5563 } else {
5564 masm->Branch(overflow_label, lt, overflow_dst, Operand(zero_reg));
5565 if (no_overflow_label) masm->Branch(no_overflow_label);
5566 }
5567}
5568
Ben Murdochda12d292016-06-02 14:46:10 +01005569void MacroAssembler::AddBranchOvf(Register dst, Register left,
5570 const Operand& right, Label* overflow_label,
5571 Label* no_overflow_label, Register scratch) {
5572 if (right.is_reg()) {
5573 AddBranchOvf(dst, left, right.rm(), overflow_label, no_overflow_label,
5574 scratch);
5575 } else {
5576 if (kArchVariant == kMips64r6) {
5577 Register right_reg = t9;
5578 DCHECK(!left.is(right_reg));
5579 li(right_reg, Operand(right));
5580 AddBranchOvf(dst, left, right_reg, overflow_label, no_overflow_label);
5581 } else {
5582 Register overflow_dst = t9;
5583 DCHECK(!dst.is(scratch));
5584 DCHECK(!dst.is(overflow_dst));
5585 DCHECK(!scratch.is(overflow_dst));
5586 DCHECK(!left.is(overflow_dst));
5587 if (dst.is(left)) {
5588 mov(scratch, left); // Preserve left.
5589 // Left is overwritten.
5590 Addu(dst, left, static_cast<int32_t>(right.immediate()));
5591 xor_(scratch, dst, scratch); // Original left.
5592 // Load right since xori takes uint16 as immediate.
5593 Addu(overflow_dst, zero_reg, right);
5594 xor_(overflow_dst, dst, overflow_dst);
5595 and_(overflow_dst, overflow_dst, scratch);
5596 } else {
5597 Addu(dst, left, static_cast<int32_t>(right.immediate()));
5598 xor_(overflow_dst, dst, left);
5599 // Load right since xori takes uint16 as immediate.
5600 Addu(scratch, zero_reg, right);
5601 xor_(scratch, dst, scratch);
5602 and_(overflow_dst, scratch, overflow_dst);
5603 }
5604 BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
5605 }
5606 }
5607}
5608
5609void MacroAssembler::AddBranchOvf(Register dst, Register left, Register right,
5610 Label* overflow_label,
5611 Label* no_overflow_label, Register scratch) {
5612 if (kArchVariant == kMips64r6) {
5613 if (!overflow_label) {
5614 DCHECK(no_overflow_label);
5615 DCHECK(!dst.is(scratch));
5616 Register left_reg = left.is(dst) ? scratch : left;
5617 Register right_reg = right.is(dst) ? t9 : right;
5618 DCHECK(!dst.is(left_reg));
5619 DCHECK(!dst.is(right_reg));
5620 Move(left_reg, left);
5621 Move(right_reg, right);
5622 addu(dst, left, right);
5623 bnvc(left_reg, right_reg, no_overflow_label);
5624 } else {
5625 bovc(left, right, overflow_label);
5626 addu(dst, left, right);
5627 if (no_overflow_label) bc(no_overflow_label);
5628 }
5629 } else {
5630 Register overflow_dst = t9;
5631 DCHECK(!dst.is(scratch));
5632 DCHECK(!dst.is(overflow_dst));
5633 DCHECK(!scratch.is(overflow_dst));
5634 DCHECK(!left.is(overflow_dst));
5635 DCHECK(!right.is(overflow_dst));
5636 DCHECK(!left.is(scratch));
5637 DCHECK(!right.is(scratch));
5638
5639 if (left.is(right) && dst.is(left)) {
5640 mov(overflow_dst, right);
5641 right = overflow_dst;
5642 }
5643
5644 if (dst.is(left)) {
5645 mov(scratch, left); // Preserve left.
5646 addu(dst, left, right); // Left is overwritten.
5647 xor_(scratch, dst, scratch); // Original left.
5648 xor_(overflow_dst, dst, right);
5649 and_(overflow_dst, overflow_dst, scratch);
5650 } else if (dst.is(right)) {
5651 mov(scratch, right); // Preserve right.
5652 addu(dst, left, right); // Right is overwritten.
5653 xor_(scratch, dst, scratch); // Original right.
5654 xor_(overflow_dst, dst, left);
5655 and_(overflow_dst, overflow_dst, scratch);
5656 } else {
5657 addu(dst, left, right);
5658 xor_(overflow_dst, dst, left);
5659 xor_(scratch, dst, right);
5660 and_(overflow_dst, scratch, overflow_dst);
5661 }
5662 BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
5663 }
5664}
5665
5666void MacroAssembler::SubBranchOvf(Register dst, Register left,
5667 const Operand& right, Label* overflow_label,
5668 Label* no_overflow_label, Register scratch) {
5669 DCHECK(overflow_label || no_overflow_label);
5670 if (right.is_reg()) {
5671 SubBranchOvf(dst, left, right.rm(), overflow_label, no_overflow_label,
5672 scratch);
5673 } else {
5674 Register overflow_dst = t9;
5675 DCHECK(!dst.is(scratch));
5676 DCHECK(!dst.is(overflow_dst));
5677 DCHECK(!scratch.is(overflow_dst));
5678 DCHECK(!left.is(overflow_dst));
5679 DCHECK(!left.is(scratch));
5680 if (dst.is(left)) {
5681 mov(scratch, left); // Preserve left.
5682 // Left is overwritten.
5683 Subu(dst, left, static_cast<int32_t>(right.immediate()));
5684 // Load right since xori takes uint16 as immediate.
5685 Addu(overflow_dst, zero_reg, right);
5686 xor_(overflow_dst, scratch, overflow_dst); // scratch is original left.
5687 xor_(scratch, dst, scratch); // scratch is original left.
5688 and_(overflow_dst, scratch, overflow_dst);
5689 } else {
5690 Subu(dst, left, right);
5691 xor_(overflow_dst, dst, left);
5692 // Load right since xori takes uint16 as immediate.
5693 Addu(scratch, zero_reg, right);
5694 xor_(scratch, left, scratch);
5695 and_(overflow_dst, scratch, overflow_dst);
5696 }
5697 BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
5698 }
5699}
5700
5701void MacroAssembler::SubBranchOvf(Register dst, Register left, Register right,
5702 Label* overflow_label,
5703 Label* no_overflow_label, Register scratch) {
5704 DCHECK(overflow_label || no_overflow_label);
5705 Register overflow_dst = t9;
5706 DCHECK(!dst.is(scratch));
5707 DCHECK(!dst.is(overflow_dst));
5708 DCHECK(!scratch.is(overflow_dst));
5709 DCHECK(!overflow_dst.is(left));
5710 DCHECK(!overflow_dst.is(right));
5711 DCHECK(!scratch.is(left));
5712 DCHECK(!scratch.is(right));
5713
5714 // This happens with some crankshaft code. Since Subu works fine if
5715 // left == right, let's not make that restriction here.
5716 if (left.is(right)) {
5717 mov(dst, zero_reg);
5718 if (no_overflow_label) {
5719 Branch(no_overflow_label);
5720 }
5721 }
5722
5723 if (dst.is(left)) {
5724 mov(scratch, left); // Preserve left.
5725 subu(dst, left, right); // Left is overwritten.
5726 xor_(overflow_dst, dst, scratch); // scratch is original left.
5727 xor_(scratch, scratch, right); // scratch is original left.
5728 and_(overflow_dst, scratch, overflow_dst);
5729 } else if (dst.is(right)) {
5730 mov(scratch, right); // Preserve right.
5731 subu(dst, left, right); // Right is overwritten.
5732 xor_(overflow_dst, dst, left);
5733 xor_(scratch, left, scratch); // Original right.
5734 and_(overflow_dst, scratch, overflow_dst);
5735 } else {
5736 subu(dst, left, right);
5737 xor_(overflow_dst, dst, left);
5738 xor_(scratch, left, right);
5739 and_(overflow_dst, scratch, overflow_dst);
5740 }
5741 BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
5742}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005743
5744void MacroAssembler::DaddBranchOvf(Register dst, Register left,
5745 const Operand& right, Label* overflow_label,
5746 Label* no_overflow_label, Register scratch) {
5747 if (right.is_reg()) {
5748 DaddBranchOvf(dst, left, right.rm(), overflow_label, no_overflow_label,
5749 scratch);
5750 } else {
5751 Register overflow_dst = t9;
5752 DCHECK(!dst.is(scratch));
5753 DCHECK(!dst.is(overflow_dst));
5754 DCHECK(!scratch.is(overflow_dst));
5755 DCHECK(!left.is(overflow_dst));
5756 li(overflow_dst, right); // Load right.
5757 if (dst.is(left)) {
5758 mov(scratch, left); // Preserve left.
5759 Daddu(dst, left, overflow_dst); // Left is overwritten.
5760 xor_(scratch, dst, scratch); // Original left.
5761 xor_(overflow_dst, dst, overflow_dst);
5762 and_(overflow_dst, overflow_dst, scratch);
5763 } else {
5764 Daddu(dst, left, overflow_dst);
5765 xor_(scratch, dst, overflow_dst);
5766 xor_(overflow_dst, dst, left);
5767 and_(overflow_dst, scratch, overflow_dst);
5768 }
5769 BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
5770 }
5771}
5772
5773
5774void MacroAssembler::DaddBranchOvf(Register dst, Register left, Register right,
5775 Label* overflow_label,
5776 Label* no_overflow_label, Register scratch) {
5777 Register overflow_dst = t9;
5778 DCHECK(!dst.is(scratch));
5779 DCHECK(!dst.is(overflow_dst));
5780 DCHECK(!scratch.is(overflow_dst));
5781 DCHECK(!left.is(overflow_dst));
5782 DCHECK(!right.is(overflow_dst));
5783 DCHECK(!left.is(scratch));
5784 DCHECK(!right.is(scratch));
5785
5786 if (left.is(right) && dst.is(left)) {
5787 mov(overflow_dst, right);
5788 right = overflow_dst;
5789 }
5790
5791 if (dst.is(left)) {
5792 mov(scratch, left); // Preserve left.
5793 daddu(dst, left, right); // Left is overwritten.
5794 xor_(scratch, dst, scratch); // Original left.
5795 xor_(overflow_dst, dst, right);
5796 and_(overflow_dst, overflow_dst, scratch);
5797 } else if (dst.is(right)) {
5798 mov(scratch, right); // Preserve right.
5799 daddu(dst, left, right); // Right is overwritten.
5800 xor_(scratch, dst, scratch); // Original right.
5801 xor_(overflow_dst, dst, left);
5802 and_(overflow_dst, overflow_dst, scratch);
5803 } else {
5804 daddu(dst, left, right);
5805 xor_(overflow_dst, dst, left);
5806 xor_(scratch, dst, right);
5807 and_(overflow_dst, scratch, overflow_dst);
5808 }
5809 BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
5810}
5811
5812
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005813void MacroAssembler::DsubBranchOvf(Register dst, Register left,
5814 const Operand& right, Label* overflow_label,
5815 Label* no_overflow_label, Register scratch) {
5816 DCHECK(overflow_label || no_overflow_label);
5817 if (right.is_reg()) {
5818 DsubBranchOvf(dst, left, right.rm(), overflow_label, no_overflow_label,
5819 scratch);
5820 } else {
5821 Register overflow_dst = t9;
5822 DCHECK(!dst.is(scratch));
5823 DCHECK(!dst.is(overflow_dst));
5824 DCHECK(!scratch.is(overflow_dst));
5825 DCHECK(!left.is(overflow_dst));
5826 DCHECK(!left.is(scratch));
5827 li(overflow_dst, right); // Load right.
5828 if (dst.is(left)) {
5829 mov(scratch, left); // Preserve left.
5830 Dsubu(dst, left, overflow_dst); // Left is overwritten.
5831 xor_(overflow_dst, scratch, overflow_dst); // scratch is original left.
5832 xor_(scratch, dst, scratch); // scratch is original left.
5833 and_(overflow_dst, scratch, overflow_dst);
5834 } else {
5835 Dsubu(dst, left, overflow_dst);
5836 xor_(scratch, left, overflow_dst);
5837 xor_(overflow_dst, dst, left);
5838 and_(overflow_dst, scratch, overflow_dst);
5839 }
5840 BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
5841 }
5842}
5843
5844
5845void MacroAssembler::DsubBranchOvf(Register dst, Register left, Register right,
5846 Label* overflow_label,
5847 Label* no_overflow_label, Register scratch) {
5848 DCHECK(overflow_label || no_overflow_label);
5849 Register overflow_dst = t9;
5850 DCHECK(!dst.is(scratch));
5851 DCHECK(!dst.is(overflow_dst));
5852 DCHECK(!scratch.is(overflow_dst));
5853 DCHECK(!overflow_dst.is(left));
5854 DCHECK(!overflow_dst.is(right));
5855 DCHECK(!scratch.is(left));
5856 DCHECK(!scratch.is(right));
5857
5858 // This happens with some crankshaft code. Since Subu works fine if
5859 // left == right, let's not make that restriction here.
5860 if (left.is(right)) {
5861 mov(dst, zero_reg);
5862 if (no_overflow_label) {
5863 Branch(no_overflow_label);
5864 }
5865 }
5866
5867 if (dst.is(left)) {
5868 mov(scratch, left); // Preserve left.
5869 dsubu(dst, left, right); // Left is overwritten.
5870 xor_(overflow_dst, dst, scratch); // scratch is original left.
5871 xor_(scratch, scratch, right); // scratch is original left.
5872 and_(overflow_dst, scratch, overflow_dst);
5873 } else if (dst.is(right)) {
5874 mov(scratch, right); // Preserve right.
5875 dsubu(dst, left, right); // Right is overwritten.
5876 xor_(overflow_dst, dst, left);
5877 xor_(scratch, left, scratch); // Original right.
5878 and_(overflow_dst, scratch, overflow_dst);
5879 } else {
5880 dsubu(dst, left, right);
5881 xor_(overflow_dst, dst, left);
5882 xor_(scratch, left, right);
5883 and_(overflow_dst, scratch, overflow_dst);
5884 }
5885 BranchOvfHelper(this, overflow_dst, overflow_label, no_overflow_label);
5886}
5887
5888
5889void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
5890 SaveFPRegsMode save_doubles,
5891 BranchDelaySlot bd) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005892 // All parameters are on the stack. v0 has the return value after call.
5893
5894 // If the expected number of arguments of the runtime function is
5895 // constant, we check that the actual number of arguments match the
5896 // expectation.
5897 CHECK(f->nargs < 0 || f->nargs == num_arguments);
5898
5899 // TODO(1236192): Most runtime routines don't need the number of
5900 // arguments passed in because it is constant. At some point we
5901 // should remove this need and make the runtime routine entry code
5902 // smarter.
5903 PrepareCEntryArgs(num_arguments);
5904 PrepareCEntryFunction(ExternalReference(f, isolate()));
5905 CEntryStub stub(isolate(), 1, save_doubles);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005906 CallStub(&stub, TypeFeedbackId::None(), al, zero_reg, Operand(zero_reg), bd);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005907}
5908
5909
5910void MacroAssembler::CallExternalReference(const ExternalReference& ext,
5911 int num_arguments,
5912 BranchDelaySlot bd) {
5913 PrepareCEntryArgs(num_arguments);
5914 PrepareCEntryFunction(ext);
5915
5916 CEntryStub stub(isolate(), 1);
5917 CallStub(&stub, TypeFeedbackId::None(), al, zero_reg, Operand(zero_reg), bd);
5918}
5919
5920
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005921void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
5922 const Runtime::Function* function = Runtime::FunctionForId(fid);
5923 DCHECK_EQ(1, function->result_size);
5924 if (function->nargs >= 0) {
5925 PrepareCEntryArgs(function->nargs);
5926 }
5927 JumpToExternalReference(ExternalReference(fid, isolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005928}
5929
5930
5931void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
5932 BranchDelaySlot bd) {
5933 PrepareCEntryFunction(builtin);
5934 CEntryStub stub(isolate(), 1);
5935 Jump(stub.GetCode(),
5936 RelocInfo::CODE_TARGET,
5937 al,
5938 zero_reg,
5939 Operand(zero_reg),
5940 bd);
5941}
5942
5943
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005944void MacroAssembler::SetCounter(StatsCounter* counter, int value,
5945 Register scratch1, Register scratch2) {
5946 if (FLAG_native_code_counters && counter->Enabled()) {
5947 li(scratch1, Operand(value));
5948 li(scratch2, Operand(ExternalReference(counter)));
5949 sd(scratch1, MemOperand(scratch2));
5950 }
5951}
5952
5953
5954void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
5955 Register scratch1, Register scratch2) {
5956 DCHECK(value > 0);
5957 if (FLAG_native_code_counters && counter->Enabled()) {
5958 li(scratch2, Operand(ExternalReference(counter)));
5959 ld(scratch1, MemOperand(scratch2));
5960 Daddu(scratch1, scratch1, Operand(value));
5961 sd(scratch1, MemOperand(scratch2));
5962 }
5963}
5964
5965
5966void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
5967 Register scratch1, Register scratch2) {
5968 DCHECK(value > 0);
5969 if (FLAG_native_code_counters && counter->Enabled()) {
5970 li(scratch2, Operand(ExternalReference(counter)));
5971 ld(scratch1, MemOperand(scratch2));
5972 Dsubu(scratch1, scratch1, Operand(value));
5973 sd(scratch1, MemOperand(scratch2));
5974 }
5975}
5976
5977
5978// -----------------------------------------------------------------------------
5979// Debugging.
5980
5981void MacroAssembler::Assert(Condition cc, BailoutReason reason,
5982 Register rs, Operand rt) {
5983 if (emit_debug_code())
5984 Check(cc, reason, rs, rt);
5985}
5986
5987
5988void MacroAssembler::AssertFastElements(Register elements) {
5989 if (emit_debug_code()) {
5990 DCHECK(!elements.is(at));
5991 Label ok;
5992 push(elements);
5993 ld(elements, FieldMemOperand(elements, HeapObject::kMapOffset));
5994 LoadRoot(at, Heap::kFixedArrayMapRootIndex);
5995 Branch(&ok, eq, elements, Operand(at));
5996 LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex);
5997 Branch(&ok, eq, elements, Operand(at));
5998 LoadRoot(at, Heap::kFixedCOWArrayMapRootIndex);
5999 Branch(&ok, eq, elements, Operand(at));
6000 Abort(kJSObjectWithFastElementsMapHasSlowElements);
6001 bind(&ok);
6002 pop(elements);
6003 }
6004}
6005
6006
6007void MacroAssembler::Check(Condition cc, BailoutReason reason,
6008 Register rs, Operand rt) {
6009 Label L;
6010 Branch(&L, cc, rs, rt);
6011 Abort(reason);
6012 // Will not return here.
6013 bind(&L);
6014}
6015
6016
6017void MacroAssembler::Abort(BailoutReason reason) {
6018 Label abort_start;
6019 bind(&abort_start);
6020#ifdef DEBUG
6021 const char* msg = GetBailoutReason(reason);
6022 if (msg != NULL) {
6023 RecordComment("Abort message: ");
6024 RecordComment(msg);
6025 }
6026
6027 if (FLAG_trap_on_abort) {
6028 stop(msg);
6029 return;
6030 }
6031#endif
6032
6033 li(a0, Operand(Smi::FromInt(reason)));
6034 push(a0);
6035 // Disable stub call restrictions to always allow calls to abort.
6036 if (!has_frame_) {
6037 // We don't actually want to generate a pile of code for this, so just
6038 // claim there is a stack frame, without generating one.
6039 FrameScope scope(this, StackFrame::NONE);
Ben Murdoch097c5b22016-05-18 11:27:45 +01006040 CallRuntime(Runtime::kAbort);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006041 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01006042 CallRuntime(Runtime::kAbort);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006043 }
6044 // Will not return here.
6045 if (is_trampoline_pool_blocked()) {
6046 // If the calling code cares about the exact number of
6047 // instructions generated, we insert padding here to keep the size
6048 // of the Abort macro constant.
6049 // Currently in debug mode with debug_code enabled the number of
6050 // generated instructions is 10, so we use this as a maximum value.
6051 static const int kExpectedAbortInstructions = 10;
6052 int abort_instructions = InstructionsGeneratedSince(&abort_start);
6053 DCHECK(abort_instructions <= kExpectedAbortInstructions);
6054 while (abort_instructions++ < kExpectedAbortInstructions) {
6055 nop();
6056 }
6057 }
6058}
6059
6060
6061void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
6062 if (context_chain_length > 0) {
6063 // Move up the chain of contexts to the context containing the slot.
6064 ld(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX)));
6065 for (int i = 1; i < context_chain_length; i++) {
6066 ld(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
6067 }
6068 } else {
6069 // Slot is in the current function context. Move it into the
6070 // destination register in case we store into it (the write barrier
6071 // cannot be allowed to destroy the context in esi).
6072 Move(dst, cp);
6073 }
6074}
6075
6076
6077void MacroAssembler::LoadTransitionedArrayMapConditional(
6078 ElementsKind expected_kind,
6079 ElementsKind transitioned_kind,
6080 Register map_in_out,
6081 Register scratch,
6082 Label* no_map_match) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006083 DCHECK(IsFastElementsKind(expected_kind));
6084 DCHECK(IsFastElementsKind(transitioned_kind));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006085
6086 // Check that the function's map is the same as the expected cached map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006087 ld(scratch, NativeContextMemOperand());
6088 ld(at, ContextMemOperand(scratch, Context::ArrayMapIndex(expected_kind)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006089 Branch(no_map_match, ne, map_in_out, Operand(at));
6090
6091 // Use the transitioned cached map.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006092 ld(map_in_out,
6093 ContextMemOperand(scratch, Context::ArrayMapIndex(transitioned_kind)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006094}
6095
6096
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006097void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
6098 ld(dst, NativeContextMemOperand());
6099 ld(dst, ContextMemOperand(dst, index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006100}
6101
6102
6103void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
6104 Register map,
6105 Register scratch) {
6106 // Load the initial map. The global functions all have initial maps.
6107 ld(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
6108 if (emit_debug_code()) {
6109 Label ok, fail;
6110 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK);
6111 Branch(&ok);
6112 bind(&fail);
6113 Abort(kGlobalFunctionsMustHaveInitialMap);
6114 bind(&ok);
6115 }
6116}
6117
Ben Murdochda12d292016-06-02 14:46:10 +01006118void MacroAssembler::StubPrologue(StackFrame::Type type) {
6119 li(at, Operand(Smi::FromInt(type)));
6120 PushCommonFrame(at);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006121}
6122
6123
6124void MacroAssembler::Prologue(bool code_pre_aging) {
6125 PredictableCodeSizeScope predictible_code_size_scope(
6126 this, kNoCodeAgeSequenceLength);
6127 // The following three instructions must remain together and unmodified
6128 // for code aging to work properly.
6129 if (code_pre_aging) {
6130 // Pre-age the code.
6131 Code* stub = Code::GetPreAgedCodeAgeStub(isolate());
6132 nop(Assembler::CODE_AGE_MARKER_NOP);
6133 // Load the stub address to t9 and call it,
6134 // GetCodeAgeAndParity() extracts the stub address from this instruction.
6135 li(t9,
6136 Operand(reinterpret_cast<uint64_t>(stub->instruction_start())),
6137 ADDRESS_LOAD);
6138 nop(); // Prevent jalr to jal optimization.
6139 jalr(t9, a0);
6140 nop(); // Branch delay slot nop.
6141 nop(); // Pad the empty space.
6142 } else {
Ben Murdochda12d292016-06-02 14:46:10 +01006143 PushStandardFrame(a1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006144 nop(Assembler::CODE_AGE_SEQUENCE_NOP);
6145 nop(Assembler::CODE_AGE_SEQUENCE_NOP);
6146 nop(Assembler::CODE_AGE_SEQUENCE_NOP);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006147 }
6148}
6149
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006150void MacroAssembler::EmitLoadTypeFeedbackVector(Register vector) {
6151 ld(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
Ben Murdoch61f157c2016-09-16 13:49:30 +01006152 ld(vector, FieldMemOperand(vector, JSFunction::kLiteralsOffset));
6153 ld(vector, FieldMemOperand(vector, LiteralsArray::kFeedbackVectorOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006154}
6155
6156
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006157void MacroAssembler::EnterFrame(StackFrame::Type type,
6158 bool load_constant_pool_pointer_reg) {
6159 // Out-of-line constant pool not implemented on mips64.
6160 UNREACHABLE();
6161}
6162
6163
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006164void MacroAssembler::EnterFrame(StackFrame::Type type) {
Ben Murdochda12d292016-06-02 14:46:10 +01006165 int stack_offset, fp_offset;
6166 if (type == StackFrame::INTERNAL) {
6167 stack_offset = -4 * kPointerSize;
6168 fp_offset = 2 * kPointerSize;
6169 } else {
6170 stack_offset = -3 * kPointerSize;
6171 fp_offset = 1 * kPointerSize;
6172 }
6173 daddiu(sp, sp, stack_offset);
6174 stack_offset = -stack_offset - kPointerSize;
6175 sd(ra, MemOperand(sp, stack_offset));
6176 stack_offset -= kPointerSize;
6177 sd(fp, MemOperand(sp, stack_offset));
6178 stack_offset -= kPointerSize;
6179 li(t9, Operand(Smi::FromInt(type)));
6180 sd(t9, MemOperand(sp, stack_offset));
6181 if (type == StackFrame::INTERNAL) {
6182 DCHECK_EQ(stack_offset, kPointerSize);
6183 li(t9, Operand(CodeObject()));
6184 sd(t9, MemOperand(sp, 0));
6185 } else {
6186 DCHECK_EQ(stack_offset, 0);
6187 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006188 // Adjust FP to point to saved FP.
Ben Murdochda12d292016-06-02 14:46:10 +01006189 Daddu(fp, sp, Operand(fp_offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006190}
6191
6192
6193void MacroAssembler::LeaveFrame(StackFrame::Type type) {
Ben Murdochda12d292016-06-02 14:46:10 +01006194 daddiu(sp, fp, 2 * kPointerSize);
6195 ld(ra, MemOperand(fp, 1 * kPointerSize));
6196 ld(fp, MemOperand(fp, 0 * kPointerSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006197}
6198
Ben Murdochda12d292016-06-02 14:46:10 +01006199void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006200 // Set up the frame structure on the stack.
6201 STATIC_ASSERT(2 * kPointerSize == ExitFrameConstants::kCallerSPDisplacement);
6202 STATIC_ASSERT(1 * kPointerSize == ExitFrameConstants::kCallerPCOffset);
6203 STATIC_ASSERT(0 * kPointerSize == ExitFrameConstants::kCallerFPOffset);
6204
6205 // This is how the stack will look:
6206 // fp + 2 (==kCallerSPDisplacement) - old stack's end
6207 // [fp + 1 (==kCallerPCOffset)] - saved old ra
6208 // [fp + 0 (==kCallerFPOffset)] - saved old fp
Ben Murdochda12d292016-06-02 14:46:10 +01006209 // [fp - 1 StackFrame::EXIT Smi
6210 // [fp - 2 (==kSPOffset)] - sp of the called function
6211 // [fp - 3 (==kCodeOffset)] - CodeObject
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006212 // fp - (2 + stack_space + alignment) == sp == [fp - kSPOffset] - top of the
6213 // new stack (will contain saved ra)
6214
Ben Murdochda12d292016-06-02 14:46:10 +01006215 // Save registers and reserve room for saved entry sp and code object.
6216 daddiu(sp, sp, -2 * kPointerSize - ExitFrameConstants::kFixedFrameSizeFromFp);
6217 sd(ra, MemOperand(sp, 4 * kPointerSize));
6218 sd(fp, MemOperand(sp, 3 * kPointerSize));
6219 li(at, Operand(Smi::FromInt(StackFrame::EXIT)));
6220 sd(at, MemOperand(sp, 2 * kPointerSize));
6221 // Set up new frame pointer.
6222 daddiu(fp, sp, ExitFrameConstants::kFixedFrameSizeFromFp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006223
6224 if (emit_debug_code()) {
6225 sd(zero_reg, MemOperand(fp, ExitFrameConstants::kSPOffset));
6226 }
6227
6228 // Accessed from ExitFrame::code_slot.
6229 li(t8, Operand(CodeObject()), CONSTANT_SIZE);
6230 sd(t8, MemOperand(fp, ExitFrameConstants::kCodeOffset));
6231
6232 // Save the frame pointer and the context in top.
6233 li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
6234 sd(fp, MemOperand(t8));
6235 li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
6236 sd(cp, MemOperand(t8));
6237
6238 const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
6239 if (save_doubles) {
6240 // The stack is already aligned to 0 modulo 8 for stores with sdc1.
6241 int kNumOfSavedRegisters = FPURegister::kMaxNumRegisters / 2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006242 int space = kNumOfSavedRegisters * kDoubleSize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006243 Dsubu(sp, sp, Operand(space));
6244 // Remember: we only need to save every 2nd double FPU value.
6245 for (int i = 0; i < kNumOfSavedRegisters; i++) {
6246 FPURegister reg = FPURegister::from_code(2 * i);
6247 sdc1(reg, MemOperand(sp, i * kDoubleSize));
6248 }
6249 }
6250
6251 // Reserve place for the return address, stack space and an optional slot
6252 // (used by the DirectCEntryStub to hold the return value if a struct is
6253 // returned) and align the frame preparing for calling the runtime function.
6254 DCHECK(stack_space >= 0);
6255 Dsubu(sp, sp, Operand((stack_space + 2) * kPointerSize));
6256 if (frame_alignment > 0) {
6257 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
6258 And(sp, sp, Operand(-frame_alignment)); // Align stack.
6259 }
6260
6261 // Set the exit frame sp value to point just before the return address
6262 // location.
6263 daddiu(at, sp, kPointerSize);
6264 sd(at, MemOperand(fp, ExitFrameConstants::kSPOffset));
6265}
6266
6267
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006268void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
6269 bool restore_context, bool do_return,
6270 bool argument_count_is_length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006271 // Optionally restore all double registers.
6272 if (save_doubles) {
6273 // Remember: we only need to restore every 2nd double FPU value.
6274 int kNumOfSavedRegisters = FPURegister::kMaxNumRegisters / 2;
Ben Murdochda12d292016-06-02 14:46:10 +01006275 Dsubu(t8, fp, Operand(ExitFrameConstants::kFixedFrameSizeFromFp +
6276 kNumOfSavedRegisters * kDoubleSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006277 for (int i = 0; i < kNumOfSavedRegisters; i++) {
6278 FPURegister reg = FPURegister::from_code(2 * i);
6279 ldc1(reg, MemOperand(t8, i * kDoubleSize));
6280 }
6281 }
6282
6283 // Clear top frame.
6284 li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
6285 sd(zero_reg, MemOperand(t8));
6286
6287 // Restore current context from top and clear it in debug mode.
6288 if (restore_context) {
6289 li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
6290 ld(cp, MemOperand(t8));
6291 }
6292#ifdef DEBUG
6293 li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
6294 sd(a3, MemOperand(t8));
6295#endif
6296
6297 // Pop the arguments, restore registers, and return.
6298 mov(sp, fp); // Respect ABI stack constraint.
6299 ld(fp, MemOperand(sp, ExitFrameConstants::kCallerFPOffset));
6300 ld(ra, MemOperand(sp, ExitFrameConstants::kCallerPCOffset));
6301
6302 if (argument_count.is_valid()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006303 if (argument_count_is_length) {
6304 daddu(sp, sp, argument_count);
6305 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01006306 Dlsa(sp, sp, argument_count, kPointerSizeLog2, t8);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006307 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006308 }
6309
6310 if (do_return) {
6311 Ret(USE_DELAY_SLOT);
6312 // If returning, the instruction in the delay slot will be the addiu below.
6313 }
6314 daddiu(sp, sp, 2 * kPointerSize);
6315}
6316
6317
6318void MacroAssembler::InitializeNewString(Register string,
6319 Register length,
6320 Heap::RootListIndex map_index,
6321 Register scratch1,
6322 Register scratch2) {
6323 // dsll(scratch1, length, kSmiTagSize);
6324 dsll32(scratch1, length, 0);
6325 LoadRoot(scratch2, map_index);
6326 sd(scratch1, FieldMemOperand(string, String::kLengthOffset));
6327 li(scratch1, Operand(String::kEmptyHashField));
6328 sd(scratch2, FieldMemOperand(string, HeapObject::kMapOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006329 sw(scratch1, FieldMemOperand(string, String::kHashFieldOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006330}
6331
6332
6333int MacroAssembler::ActivationFrameAlignment() {
6334#if V8_HOST_ARCH_MIPS || V8_HOST_ARCH_MIPS64
6335 // Running on the real platform. Use the alignment as mandated by the local
6336 // environment.
6337 // Note: This will break if we ever start generating snapshots on one Mips
6338 // platform for another Mips platform with a different alignment.
6339 return base::OS::ActivationFrameAlignment();
6340#else // V8_HOST_ARCH_MIPS
6341 // If we are using the simulator then we should always align to the expected
6342 // alignment. As the simulator is used to generate snapshots we do not know
6343 // if the target platform will need alignment, so this is controlled from a
6344 // flag.
6345 return FLAG_sim_stack_alignment;
6346#endif // V8_HOST_ARCH_MIPS
6347}
6348
6349
6350void MacroAssembler::AssertStackIsAligned() {
6351 if (emit_debug_code()) {
6352 const int frame_alignment = ActivationFrameAlignment();
6353 const int frame_alignment_mask = frame_alignment - 1;
6354
6355 if (frame_alignment > kPointerSize) {
6356 Label alignment_as_expected;
6357 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
6358 andi(at, sp, frame_alignment_mask);
6359 Branch(&alignment_as_expected, eq, at, Operand(zero_reg));
6360 // Don't use Check here, as it will call Runtime_Abort re-entering here.
6361 stop("Unexpected stack alignment");
6362 bind(&alignment_as_expected);
6363 }
6364 }
6365}
6366
6367
6368void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
6369 Register reg,
6370 Register scratch,
6371 Label* not_power_of_two_or_zero) {
6372 Dsubu(scratch, reg, Operand(1));
6373 Branch(USE_DELAY_SLOT, not_power_of_two_or_zero, lt,
6374 scratch, Operand(zero_reg));
6375 and_(at, scratch, reg); // In the delay slot.
6376 Branch(not_power_of_two_or_zero, ne, at, Operand(zero_reg));
6377}
6378
6379
6380void MacroAssembler::SmiTagCheckOverflow(Register reg, Register overflow) {
6381 DCHECK(!reg.is(overflow));
6382 mov(overflow, reg); // Save original value.
6383 SmiTag(reg);
6384 xor_(overflow, overflow, reg); // Overflow if (value ^ 2 * value) < 0.
6385}
6386
6387
6388void MacroAssembler::SmiTagCheckOverflow(Register dst,
6389 Register src,
6390 Register overflow) {
6391 if (dst.is(src)) {
6392 // Fall back to slower case.
6393 SmiTagCheckOverflow(dst, overflow);
6394 } else {
6395 DCHECK(!dst.is(src));
6396 DCHECK(!dst.is(overflow));
6397 DCHECK(!src.is(overflow));
6398 SmiTag(dst, src);
6399 xor_(overflow, dst, src); // Overflow if (value ^ 2 * value) < 0.
6400 }
6401}
6402
6403
6404void MacroAssembler::SmiLoadUntag(Register dst, MemOperand src) {
6405 if (SmiValuesAre32Bits()) {
6406 lw(dst, UntagSmiMemOperand(src.rm(), src.offset()));
6407 } else {
6408 lw(dst, src);
6409 SmiUntag(dst);
6410 }
6411}
6412
6413
6414void MacroAssembler::SmiLoadScale(Register dst, MemOperand src, int scale) {
6415 if (SmiValuesAre32Bits()) {
6416 // TODO(plind): not clear if lw or ld faster here, need micro-benchmark.
6417 lw(dst, UntagSmiMemOperand(src.rm(), src.offset()));
6418 dsll(dst, dst, scale);
6419 } else {
6420 lw(dst, src);
6421 DCHECK(scale >= kSmiTagSize);
6422 sll(dst, dst, scale - kSmiTagSize);
6423 }
6424}
6425
6426
6427// Returns 2 values: the Smi and a scaled version of the int within the Smi.
6428void MacroAssembler::SmiLoadWithScale(Register d_smi,
6429 Register d_scaled,
6430 MemOperand src,
6431 int scale) {
6432 if (SmiValuesAre32Bits()) {
6433 ld(d_smi, src);
6434 dsra(d_scaled, d_smi, kSmiShift - scale);
6435 } else {
6436 lw(d_smi, src);
6437 DCHECK(scale >= kSmiTagSize);
6438 sll(d_scaled, d_smi, scale - kSmiTagSize);
6439 }
6440}
6441
6442
6443// Returns 2 values: the untagged Smi (int32) and scaled version of that int.
6444void MacroAssembler::SmiLoadUntagWithScale(Register d_int,
6445 Register d_scaled,
6446 MemOperand src,
6447 int scale) {
6448 if (SmiValuesAre32Bits()) {
6449 lw(d_int, UntagSmiMemOperand(src.rm(), src.offset()));
6450 dsll(d_scaled, d_int, scale);
6451 } else {
6452 lw(d_int, src);
6453 // Need both the int and the scaled in, so use two instructions.
6454 SmiUntag(d_int);
6455 sll(d_scaled, d_int, scale);
6456 }
6457}
6458
6459
6460void MacroAssembler::UntagAndJumpIfSmi(Register dst,
6461 Register src,
6462 Label* smi_case) {
6463 // DCHECK(!dst.is(src));
6464 JumpIfSmi(src, smi_case, at, USE_DELAY_SLOT);
6465 SmiUntag(dst, src);
6466}
6467
6468
6469void MacroAssembler::UntagAndJumpIfNotSmi(Register dst,
6470 Register src,
6471 Label* non_smi_case) {
6472 // DCHECK(!dst.is(src));
6473 JumpIfNotSmi(src, non_smi_case, at, USE_DELAY_SLOT);
6474 SmiUntag(dst, src);
6475}
6476
6477void MacroAssembler::JumpIfSmi(Register value,
6478 Label* smi_label,
6479 Register scratch,
6480 BranchDelaySlot bd) {
6481 DCHECK_EQ(0, kSmiTag);
6482 andi(scratch, value, kSmiTagMask);
6483 Branch(bd, smi_label, eq, scratch, Operand(zero_reg));
6484}
6485
6486void MacroAssembler::JumpIfNotSmi(Register value,
6487 Label* not_smi_label,
6488 Register scratch,
6489 BranchDelaySlot bd) {
6490 DCHECK_EQ(0, kSmiTag);
6491 andi(scratch, value, kSmiTagMask);
6492 Branch(bd, not_smi_label, ne, scratch, Operand(zero_reg));
6493}
6494
6495
6496void MacroAssembler::JumpIfNotBothSmi(Register reg1,
6497 Register reg2,
6498 Label* on_not_both_smi) {
6499 STATIC_ASSERT(kSmiTag == 0);
6500 // TODO(plind): Find some better to fix this assert issue.
6501#if defined(__APPLE__)
6502 DCHECK_EQ(1, kSmiTagMask);
6503#else
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006504 DCHECK_EQ((int64_t)1, kSmiTagMask);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006505#endif
6506 or_(at, reg1, reg2);
6507 JumpIfNotSmi(at, on_not_both_smi);
6508}
6509
6510
6511void MacroAssembler::JumpIfEitherSmi(Register reg1,
6512 Register reg2,
6513 Label* on_either_smi) {
6514 STATIC_ASSERT(kSmiTag == 0);
6515 // TODO(plind): Find some better to fix this assert issue.
6516#if defined(__APPLE__)
6517 DCHECK_EQ(1, kSmiTagMask);
6518#else
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006519 DCHECK_EQ((int64_t)1, kSmiTagMask);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006520#endif
6521 // Both Smi tags must be 1 (not Smi).
6522 and_(at, reg1, reg2);
6523 JumpIfSmi(at, on_either_smi);
6524}
6525
Ben Murdochda12d292016-06-02 14:46:10 +01006526void MacroAssembler::AssertNotNumber(Register object) {
6527 if (emit_debug_code()) {
6528 STATIC_ASSERT(kSmiTag == 0);
6529 andi(at, object, kSmiTagMask);
6530 Check(ne, kOperandIsANumber, at, Operand(zero_reg));
6531 GetObjectType(object, t8, t8);
6532 Check(ne, kOperandIsNotANumber, t8, Operand(HEAP_NUMBER_TYPE));
6533 }
6534}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006535
6536void MacroAssembler::AssertNotSmi(Register object) {
6537 if (emit_debug_code()) {
6538 STATIC_ASSERT(kSmiTag == 0);
6539 andi(at, object, kSmiTagMask);
6540 Check(ne, kOperandIsASmi, at, Operand(zero_reg));
6541 }
6542}
6543
6544
6545void MacroAssembler::AssertSmi(Register object) {
6546 if (emit_debug_code()) {
6547 STATIC_ASSERT(kSmiTag == 0);
6548 andi(at, object, kSmiTagMask);
6549 Check(eq, kOperandIsASmi, at, Operand(zero_reg));
6550 }
6551}
6552
6553
6554void MacroAssembler::AssertString(Register object) {
6555 if (emit_debug_code()) {
6556 STATIC_ASSERT(kSmiTag == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006557 SmiTst(object, t8);
6558 Check(ne, kOperandIsASmiAndNotAString, t8, Operand(zero_reg));
6559 GetObjectType(object, t8, t8);
6560 Check(lo, kOperandIsNotAString, t8, Operand(FIRST_NONSTRING_TYPE));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006561 }
6562}
6563
6564
6565void MacroAssembler::AssertName(Register object) {
6566 if (emit_debug_code()) {
6567 STATIC_ASSERT(kSmiTag == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006568 SmiTst(object, t8);
6569 Check(ne, kOperandIsASmiAndNotAName, t8, Operand(zero_reg));
6570 GetObjectType(object, t8, t8);
6571 Check(le, kOperandIsNotAName, t8, Operand(LAST_NAME_TYPE));
6572 }
6573}
6574
6575
6576void MacroAssembler::AssertFunction(Register object) {
6577 if (emit_debug_code()) {
6578 STATIC_ASSERT(kSmiTag == 0);
6579 SmiTst(object, t8);
6580 Check(ne, kOperandIsASmiAndNotAFunction, t8, Operand(zero_reg));
6581 GetObjectType(object, t8, t8);
6582 Check(eq, kOperandIsNotAFunction, t8, Operand(JS_FUNCTION_TYPE));
6583 }
6584}
6585
6586
6587void MacroAssembler::AssertBoundFunction(Register object) {
6588 if (emit_debug_code()) {
6589 STATIC_ASSERT(kSmiTag == 0);
6590 SmiTst(object, t8);
6591 Check(ne, kOperandIsASmiAndNotABoundFunction, t8, Operand(zero_reg));
6592 GetObjectType(object, t8, t8);
6593 Check(eq, kOperandIsNotABoundFunction, t8, Operand(JS_BOUND_FUNCTION_TYPE));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006594 }
6595}
6596
Ben Murdochc5610432016-08-08 18:44:38 +01006597void MacroAssembler::AssertGeneratorObject(Register object) {
6598 if (emit_debug_code()) {
6599 STATIC_ASSERT(kSmiTag == 0);
6600 SmiTst(object, t8);
6601 Check(ne, kOperandIsASmiAndNotAGeneratorObject, t8, Operand(zero_reg));
6602 GetObjectType(object, t8, t8);
6603 Check(eq, kOperandIsNotAGeneratorObject, t8,
6604 Operand(JS_GENERATOR_OBJECT_TYPE));
6605 }
6606}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006607
Ben Murdoch097c5b22016-05-18 11:27:45 +01006608void MacroAssembler::AssertReceiver(Register object) {
6609 if (emit_debug_code()) {
6610 STATIC_ASSERT(kSmiTag == 0);
6611 SmiTst(object, t8);
6612 Check(ne, kOperandIsASmiAndNotAReceiver, t8, Operand(zero_reg));
6613 GetObjectType(object, t8, t8);
6614 Check(ge, kOperandIsNotAReceiver, t8, Operand(FIRST_JS_RECEIVER_TYPE));
6615 }
6616}
6617
6618
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006619void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
6620 Register scratch) {
6621 if (emit_debug_code()) {
6622 Label done_checking;
6623 AssertNotSmi(object);
6624 LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
6625 Branch(&done_checking, eq, object, Operand(scratch));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006626 ld(t8, FieldMemOperand(object, HeapObject::kMapOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006627 LoadRoot(scratch, Heap::kAllocationSiteMapRootIndex);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006628 Assert(eq, kExpectedUndefinedOrCell, t8, Operand(scratch));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006629 bind(&done_checking);
6630 }
6631}
6632
6633
6634void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) {
6635 if (emit_debug_code()) {
6636 DCHECK(!reg.is(at));
6637 LoadRoot(at, index);
6638 Check(eq, kHeapNumberMapRegisterClobbered, reg, Operand(at));
6639 }
6640}
6641
6642
6643void MacroAssembler::JumpIfNotHeapNumber(Register object,
6644 Register heap_number_map,
6645 Register scratch,
6646 Label* on_not_heap_number) {
6647 ld(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
6648 AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
6649 Branch(on_not_heap_number, ne, scratch, Operand(heap_number_map));
6650}
6651
6652
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006653void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings(
6654 Register first, Register second, Register scratch1, Register scratch2,
6655 Label* failure) {
6656 // Test that both first and second are sequential one-byte strings.
6657 // Assume that they are non-smis.
6658 ld(scratch1, FieldMemOperand(first, HeapObject::kMapOffset));
6659 ld(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
6660 lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
6661 lbu(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
6662
6663 JumpIfBothInstanceTypesAreNotSequentialOneByte(scratch1, scratch2, scratch1,
6664 scratch2, failure);
6665}
6666
6667
6668void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register first,
6669 Register second,
6670 Register scratch1,
6671 Register scratch2,
6672 Label* failure) {
6673 // Check that neither is a smi.
6674 STATIC_ASSERT(kSmiTag == 0);
6675 And(scratch1, first, Operand(second));
6676 JumpIfSmi(scratch1, failure);
6677 JumpIfNonSmisNotBothSequentialOneByteStrings(first, second, scratch1,
6678 scratch2, failure);
6679}
6680
6681
6682void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte(
6683 Register first, Register second, Register scratch1, Register scratch2,
6684 Label* failure) {
6685 const int kFlatOneByteStringMask =
6686 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
6687 const int kFlatOneByteStringTag =
6688 kStringTag | kOneByteStringTag | kSeqStringTag;
6689 DCHECK(kFlatOneByteStringTag <= 0xffff); // Ensure this fits 16-bit immed.
6690 andi(scratch1, first, kFlatOneByteStringMask);
6691 Branch(failure, ne, scratch1, Operand(kFlatOneByteStringTag));
6692 andi(scratch2, second, kFlatOneByteStringMask);
6693 Branch(failure, ne, scratch2, Operand(kFlatOneByteStringTag));
6694}
6695
6696
6697void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(Register type,
6698 Register scratch,
6699 Label* failure) {
6700 const int kFlatOneByteStringMask =
6701 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
6702 const int kFlatOneByteStringTag =
6703 kStringTag | kOneByteStringTag | kSeqStringTag;
6704 And(scratch, type, Operand(kFlatOneByteStringMask));
6705 Branch(failure, ne, scratch, Operand(kFlatOneByteStringTag));
6706}
6707
Ben Murdoch097c5b22016-05-18 11:27:45 +01006708static const int kRegisterPassedArguments = 8;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006709
6710int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments,
6711 int num_double_arguments) {
6712 int stack_passed_words = 0;
6713 num_reg_arguments += 2 * num_double_arguments;
6714
6715 // O32: Up to four simple arguments are passed in registers a0..a3.
6716 // N64: Up to eight simple arguments are passed in registers a0..a7.
6717 if (num_reg_arguments > kRegisterPassedArguments) {
6718 stack_passed_words += num_reg_arguments - kRegisterPassedArguments;
6719 }
6720 stack_passed_words += kCArgSlotCount;
6721 return stack_passed_words;
6722}
6723
6724
6725void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
6726 Register index,
6727 Register value,
6728 Register scratch,
6729 uint32_t encoding_mask) {
6730 Label is_object;
6731 SmiTst(string, at);
6732 Check(ne, kNonObject, at, Operand(zero_reg));
6733
6734 ld(at, FieldMemOperand(string, HeapObject::kMapOffset));
6735 lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset));
6736
6737 andi(at, at, kStringRepresentationMask | kStringEncodingMask);
6738 li(scratch, Operand(encoding_mask));
6739 Check(eq, kUnexpectedStringType, at, Operand(scratch));
6740
6741 // TODO(plind): requires Smi size check code for mips32.
6742
6743 ld(at, FieldMemOperand(string, String::kLengthOffset));
6744 Check(lt, kIndexIsTooLarge, index, Operand(at));
6745
6746 DCHECK(Smi::FromInt(0) == 0);
6747 Check(ge, kIndexIsNegative, index, Operand(zero_reg));
6748}
6749
6750
6751void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
6752 int num_double_arguments,
6753 Register scratch) {
6754 int frame_alignment = ActivationFrameAlignment();
6755
6756 // n64: Up to eight simple arguments in a0..a3, a4..a7, No argument slots.
6757 // O32: Up to four simple arguments are passed in registers a0..a3.
6758 // Those four arguments must have reserved argument slots on the stack for
6759 // mips, even though those argument slots are not normally used.
6760 // Both ABIs: Remaining arguments are pushed on the stack, above (higher
6761 // address than) the (O32) argument slots. (arg slot calculation handled by
6762 // CalculateStackPassedWords()).
6763 int stack_passed_arguments = CalculateStackPassedWords(
6764 num_reg_arguments, num_double_arguments);
6765 if (frame_alignment > kPointerSize) {
6766 // Make stack end at alignment and make room for num_arguments - 4 words
6767 // and the original value of sp.
6768 mov(scratch, sp);
6769 Dsubu(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize));
6770 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
6771 And(sp, sp, Operand(-frame_alignment));
6772 sd(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
6773 } else {
6774 Dsubu(sp, sp, Operand(stack_passed_arguments * kPointerSize));
6775 }
6776}
6777
6778
6779void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
6780 Register scratch) {
6781 PrepareCallCFunction(num_reg_arguments, 0, scratch);
6782}
6783
6784
6785void MacroAssembler::CallCFunction(ExternalReference function,
6786 int num_reg_arguments,
6787 int num_double_arguments) {
6788 li(t8, Operand(function));
6789 CallCFunctionHelper(t8, num_reg_arguments, num_double_arguments);
6790}
6791
6792
6793void MacroAssembler::CallCFunction(Register function,
6794 int num_reg_arguments,
6795 int num_double_arguments) {
6796 CallCFunctionHelper(function, num_reg_arguments, num_double_arguments);
6797}
6798
6799
6800void MacroAssembler::CallCFunction(ExternalReference function,
6801 int num_arguments) {
6802 CallCFunction(function, num_arguments, 0);
6803}
6804
6805
6806void MacroAssembler::CallCFunction(Register function,
6807 int num_arguments) {
6808 CallCFunction(function, num_arguments, 0);
6809}
6810
6811
6812void MacroAssembler::CallCFunctionHelper(Register function,
6813 int num_reg_arguments,
6814 int num_double_arguments) {
6815 DCHECK(has_frame());
6816 // Make sure that the stack is aligned before calling a C function unless
6817 // running in the simulator. The simulator has its own alignment check which
6818 // provides more information.
6819 // The argument stots are presumed to have been set up by
6820 // PrepareCallCFunction. The C function must be called via t9, for mips ABI.
6821
6822#if V8_HOST_ARCH_MIPS || V8_HOST_ARCH_MIPS64
6823 if (emit_debug_code()) {
6824 int frame_alignment = base::OS::ActivationFrameAlignment();
6825 int frame_alignment_mask = frame_alignment - 1;
6826 if (frame_alignment > kPointerSize) {
6827 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
6828 Label alignment_as_expected;
6829 And(at, sp, Operand(frame_alignment_mask));
6830 Branch(&alignment_as_expected, eq, at, Operand(zero_reg));
6831 // Don't use Check here, as it will call Runtime_Abort possibly
6832 // re-entering here.
6833 stop("Unexpected alignment in CallCFunction");
6834 bind(&alignment_as_expected);
6835 }
6836 }
6837#endif // V8_HOST_ARCH_MIPS
6838
6839 // Just call directly. The function called cannot cause a GC, or
6840 // allow preemption, so the return address in the link register
6841 // stays correct.
6842
6843 if (!function.is(t9)) {
6844 mov(t9, function);
6845 function = t9;
6846 }
6847
6848 Call(function);
6849
6850 int stack_passed_arguments = CalculateStackPassedWords(
6851 num_reg_arguments, num_double_arguments);
6852
6853 if (base::OS::ActivationFrameAlignment() > kPointerSize) {
6854 ld(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
6855 } else {
6856 Daddu(sp, sp, Operand(stack_passed_arguments * kPointerSize));
6857 }
6858}
6859
6860
6861#undef BRANCH_ARGS_CHECK
6862
6863
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006864void MacroAssembler::CheckPageFlag(
6865 Register object,
6866 Register scratch,
6867 int mask,
6868 Condition cc,
6869 Label* condition_met) {
6870 And(scratch, object, Operand(~Page::kPageAlignmentMask));
6871 ld(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
6872 And(scratch, scratch, Operand(mask));
6873 Branch(condition_met, cc, scratch, Operand(zero_reg));
6874}
6875
6876
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006877void MacroAssembler::JumpIfBlack(Register object,
6878 Register scratch0,
6879 Register scratch1,
6880 Label* on_black) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006881 HasColor(object, scratch0, scratch1, on_black, 1, 1); // kBlackBitPattern.
6882 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006883}
6884
6885
6886void MacroAssembler::HasColor(Register object,
6887 Register bitmap_scratch,
6888 Register mask_scratch,
6889 Label* has_color,
6890 int first_bit,
6891 int second_bit) {
6892 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, t8));
6893 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, t9));
6894
6895 GetMarkBits(object, bitmap_scratch, mask_scratch);
6896
6897 Label other_color;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006898 // Note that we are using two 4-byte aligned loads.
6899 LoadWordPair(t9, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006900 And(t8, t9, Operand(mask_scratch));
6901 Branch(&other_color, first_bit == 1 ? eq : ne, t8, Operand(zero_reg));
6902 // Shift left 1 by adding.
6903 Daddu(mask_scratch, mask_scratch, Operand(mask_scratch));
6904 And(t8, t9, Operand(mask_scratch));
6905 Branch(has_color, second_bit == 1 ? ne : eq, t8, Operand(zero_reg));
6906
6907 bind(&other_color);
6908}
6909
6910
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006911void MacroAssembler::GetMarkBits(Register addr_reg,
6912 Register bitmap_reg,
6913 Register mask_reg) {
6914 DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg));
6915 // addr_reg is divided into fields:
6916 // |63 page base 20|19 high 8|7 shift 3|2 0|
6917 // 'high' gives the index of the cell holding color bits for the object.
6918 // 'shift' gives the offset in the cell for this object's color.
6919 And(bitmap_reg, addr_reg, Operand(~Page::kPageAlignmentMask));
6920 Ext(mask_reg, addr_reg, kPointerSizeLog2, Bitmap::kBitsPerCellLog2);
6921 const int kLowBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2;
6922 Ext(t8, addr_reg, kLowBits, kPageSizeBits - kLowBits);
Ben Murdoch097c5b22016-05-18 11:27:45 +01006923 Dlsa(bitmap_reg, bitmap_reg, t8, Bitmap::kBytesPerCellLog2);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006924 li(t8, Operand(1));
6925 dsllv(mask_reg, t8, mask_reg);
6926}
6927
6928
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006929void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
6930 Register mask_scratch, Register load_scratch,
6931 Label* value_is_white) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006932 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, t8));
6933 GetMarkBits(value, bitmap_scratch, mask_scratch);
6934
6935 // If the value is black or grey we don't need to do anything.
6936 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006937 DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
6938 DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006939 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
6940
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006941 // Since both black and grey have a 1 in the first position and white does
6942 // not have a 1 there we only need to check one bit.
6943 // Note that we are using a 4-byte aligned 8-byte load.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006944 if (emit_debug_code()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006945 LoadWordPair(load_scratch,
6946 MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
6947 } else {
6948 lwu(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006949 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006950 And(t8, mask_scratch, load_scratch);
6951 Branch(value_is_white, eq, t8, Operand(zero_reg));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006952}
6953
6954
6955void MacroAssembler::LoadInstanceDescriptors(Register map,
6956 Register descriptors) {
6957 ld(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
6958}
6959
6960
6961void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006962 lwu(dst, FieldMemOperand(map, Map::kBitField3Offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006963 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
6964}
6965
6966
6967void MacroAssembler::EnumLength(Register dst, Register map) {
6968 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006969 lwu(dst, FieldMemOperand(map, Map::kBitField3Offset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006970 And(dst, dst, Operand(Map::EnumLengthBits::kMask));
6971 SmiTag(dst);
6972}
6973
6974
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00006975void MacroAssembler::LoadAccessor(Register dst, Register holder,
6976 int accessor_index,
6977 AccessorComponent accessor) {
6978 ld(dst, FieldMemOperand(holder, HeapObject::kMapOffset));
6979 LoadInstanceDescriptors(dst, dst);
6980 ld(dst,
6981 FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
6982 int offset = accessor == ACCESSOR_GETTER ? AccessorPair::kGetterOffset
6983 : AccessorPair::kSetterOffset;
6984 ld(dst, FieldMemOperand(dst, offset));
6985}
6986
6987
Ben Murdoch097c5b22016-05-18 11:27:45 +01006988void MacroAssembler::CheckEnumCache(Label* call_runtime) {
6989 Register null_value = a5;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006990 Register empty_fixed_array_value = a6;
6991 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
6992 Label next, start;
6993 mov(a2, a0);
6994
6995 // Check if the enum length field is properly initialized, indicating that
6996 // there is an enum cache.
6997 ld(a1, FieldMemOperand(a2, HeapObject::kMapOffset));
6998
6999 EnumLength(a3, a1);
7000 Branch(
7001 call_runtime, eq, a3, Operand(Smi::FromInt(kInvalidEnumCacheSentinel)));
7002
Ben Murdoch097c5b22016-05-18 11:27:45 +01007003 LoadRoot(null_value, Heap::kNullValueRootIndex);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007004 jmp(&start);
7005
7006 bind(&next);
7007 ld(a1, FieldMemOperand(a2, HeapObject::kMapOffset));
7008
7009 // For all objects but the receiver, check that the cache is empty.
7010 EnumLength(a3, a1);
7011 Branch(call_runtime, ne, a3, Operand(Smi::FromInt(0)));
7012
7013 bind(&start);
7014
7015 // Check that there are no elements. Register a2 contains the current JS
7016 // object we've reached through the prototype chain.
7017 Label no_elements;
7018 ld(a2, FieldMemOperand(a2, JSObject::kElementsOffset));
7019 Branch(&no_elements, eq, a2, Operand(empty_fixed_array_value));
7020
7021 // Second chance, the object may be using the empty slow element dictionary.
7022 LoadRoot(at, Heap::kEmptySlowElementDictionaryRootIndex);
7023 Branch(call_runtime, ne, a2, Operand(at));
7024
7025 bind(&no_elements);
7026 ld(a2, FieldMemOperand(a1, Map::kPrototypeOffset));
7027 Branch(&next, ne, a2, Operand(null_value));
7028}
7029
7030
7031void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) {
7032 DCHECK(!output_reg.is(input_reg));
7033 Label done;
7034 li(output_reg, Operand(255));
7035 // Normal branch: nop in delay slot.
7036 Branch(&done, gt, input_reg, Operand(output_reg));
7037 // Use delay slot in this branch.
7038 Branch(USE_DELAY_SLOT, &done, lt, input_reg, Operand(zero_reg));
7039 mov(output_reg, zero_reg); // In delay slot.
7040 mov(output_reg, input_reg); // Value is in range 0..255.
7041 bind(&done);
7042}
7043
7044
7045void MacroAssembler::ClampDoubleToUint8(Register result_reg,
7046 DoubleRegister input_reg,
7047 DoubleRegister temp_double_reg) {
7048 Label above_zero;
7049 Label done;
7050 Label in_bounds;
7051
7052 Move(temp_double_reg, 0.0);
7053 BranchF(&above_zero, NULL, gt, input_reg, temp_double_reg);
7054
7055 // Double value is less than zero, NaN or Inf, return 0.
7056 mov(result_reg, zero_reg);
7057 Branch(&done);
7058
7059 // Double value is >= 255, return 255.
7060 bind(&above_zero);
7061 Move(temp_double_reg, 255.0);
7062 BranchF(&in_bounds, NULL, le, input_reg, temp_double_reg);
7063 li(result_reg, Operand(255));
7064 Branch(&done);
7065
7066 // In 0-255 range, round and truncate.
7067 bind(&in_bounds);
7068 cvt_w_d(temp_double_reg, input_reg);
7069 mfc1(result_reg, temp_double_reg);
7070 bind(&done);
7071}
7072
Ben Murdochda12d292016-06-02 14:46:10 +01007073void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver_reg,
7074 Register scratch_reg,
7075 Label* no_memento_found) {
7076 Label map_check;
7077 Label top_check;
Ben Murdochc5610432016-08-08 18:44:38 +01007078 ExternalReference new_space_allocation_top_adr =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007079 ExternalReference::new_space_allocation_top_address(isolate());
Ben Murdochda12d292016-06-02 14:46:10 +01007080 const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag;
7081 const int kMementoEndOffset = kMementoMapOffset + AllocationMemento::kSize;
7082
7083 // Bail out if the object is not in new space.
7084 JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found);
7085 // If the object is in new space, we need to check whether it is on the same
7086 // page as the current top.
Ben Murdochc5610432016-08-08 18:44:38 +01007087 Daddu(scratch_reg, receiver_reg, Operand(kMementoEndOffset));
7088 li(at, Operand(new_space_allocation_top_adr));
7089 ld(at, MemOperand(at));
7090 Xor(scratch_reg, scratch_reg, Operand(at));
Ben Murdochda12d292016-06-02 14:46:10 +01007091 And(scratch_reg, scratch_reg, Operand(~Page::kPageAlignmentMask));
7092 Branch(&top_check, eq, scratch_reg, Operand(zero_reg));
7093 // The object is on a different page than allocation top. Bail out if the
7094 // object sits on the page boundary as no memento can follow and we cannot
7095 // touch the memory following it.
Ben Murdochc5610432016-08-08 18:44:38 +01007096 Daddu(scratch_reg, receiver_reg, Operand(kMementoEndOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01007097 Xor(scratch_reg, scratch_reg, Operand(receiver_reg));
7098 And(scratch_reg, scratch_reg, Operand(~Page::kPageAlignmentMask));
7099 Branch(no_memento_found, ne, scratch_reg, Operand(zero_reg));
7100 // Continue with the actual map check.
7101 jmp(&map_check);
7102 // If top is on the same page as the current object, we need to check whether
7103 // we are below top.
7104 bind(&top_check);
Ben Murdochc5610432016-08-08 18:44:38 +01007105 Daddu(scratch_reg, receiver_reg, Operand(kMementoEndOffset));
7106 li(at, Operand(new_space_allocation_top_adr));
7107 ld(at, MemOperand(at));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007108 Branch(no_memento_found, gt, scratch_reg, Operand(at));
Ben Murdochda12d292016-06-02 14:46:10 +01007109 // Memento map check.
7110 bind(&map_check);
Ben Murdochc5610432016-08-08 18:44:38 +01007111 ld(scratch_reg, MemOperand(receiver_reg, kMementoMapOffset));
Ben Murdochda12d292016-06-02 14:46:10 +01007112 Branch(no_memento_found, ne, scratch_reg,
7113 Operand(isolate()->factory()->allocation_memento_map()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007114}
7115
7116
7117Register GetRegisterThatIsNotOneOf(Register reg1,
7118 Register reg2,
7119 Register reg3,
7120 Register reg4,
7121 Register reg5,
7122 Register reg6) {
7123 RegList regs = 0;
7124 if (reg1.is_valid()) regs |= reg1.bit();
7125 if (reg2.is_valid()) regs |= reg2.bit();
7126 if (reg3.is_valid()) regs |= reg3.bit();
7127 if (reg4.is_valid()) regs |= reg4.bit();
7128 if (reg5.is_valid()) regs |= reg5.bit();
7129 if (reg6.is_valid()) regs |= reg6.bit();
7130
Ben Murdoch61f157c2016-09-16 13:49:30 +01007131 const RegisterConfiguration* config = RegisterConfiguration::Crankshaft();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007132 for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
7133 int code = config->GetAllocatableGeneralCode(i);
7134 Register candidate = Register::from_code(code);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007135 if (regs & candidate.bit()) continue;
7136 return candidate;
7137 }
7138 UNREACHABLE();
7139 return no_reg;
7140}
7141
7142
7143void MacroAssembler::JumpIfDictionaryInPrototypeChain(
7144 Register object,
7145 Register scratch0,
7146 Register scratch1,
7147 Label* found) {
7148 DCHECK(!scratch1.is(scratch0));
7149 Factory* factory = isolate()->factory();
7150 Register current = scratch0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007151 Label loop_again, end;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007152
7153 // Scratch contained elements pointer.
7154 Move(current, object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007155 ld(current, FieldMemOperand(current, HeapObject::kMapOffset));
7156 ld(current, FieldMemOperand(current, Map::kPrototypeOffset));
7157 Branch(&end, eq, current, Operand(factory->null_value()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007158
7159 // Loop based on the map going up the prototype chain.
7160 bind(&loop_again);
7161 ld(current, FieldMemOperand(current, HeapObject::kMapOffset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007162 lbu(scratch1, FieldMemOperand(current, Map::kInstanceTypeOffset));
7163 STATIC_ASSERT(JS_VALUE_TYPE < JS_OBJECT_TYPE);
7164 STATIC_ASSERT(JS_PROXY_TYPE < JS_OBJECT_TYPE);
7165 Branch(found, lo, scratch1, Operand(JS_OBJECT_TYPE));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007166 lb(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
7167 DecodeField<Map::ElementsKindBits>(scratch1);
7168 Branch(found, eq, scratch1, Operand(DICTIONARY_ELEMENTS));
7169 ld(current, FieldMemOperand(current, Map::kPrototypeOffset));
7170 Branch(&loop_again, ne, current, Operand(factory->null_value()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007171
7172 bind(&end);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007173}
7174
7175
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007176bool AreAliased(Register reg1, Register reg2, Register reg3, Register reg4,
7177 Register reg5, Register reg6, Register reg7, Register reg8,
7178 Register reg9, Register reg10) {
7179 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + reg3.is_valid() +
7180 reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
7181 reg7.is_valid() + reg8.is_valid() + reg9.is_valid() +
7182 reg10.is_valid();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007183
7184 RegList regs = 0;
7185 if (reg1.is_valid()) regs |= reg1.bit();
7186 if (reg2.is_valid()) regs |= reg2.bit();
7187 if (reg3.is_valid()) regs |= reg3.bit();
7188 if (reg4.is_valid()) regs |= reg4.bit();
7189 if (reg5.is_valid()) regs |= reg5.bit();
7190 if (reg6.is_valid()) regs |= reg6.bit();
7191 if (reg7.is_valid()) regs |= reg7.bit();
7192 if (reg8.is_valid()) regs |= reg8.bit();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007193 if (reg9.is_valid()) regs |= reg9.bit();
7194 if (reg10.is_valid()) regs |= reg10.bit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007195 int n_of_non_aliasing_regs = NumRegs(regs);
7196
7197 return n_of_valid_regs != n_of_non_aliasing_regs;
7198}
7199
7200
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007201CodePatcher::CodePatcher(Isolate* isolate, byte* address, int instructions,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007202 FlushICache flush_cache)
7203 : address_(address),
7204 size_(instructions * Assembler::kInstrSize),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007205 masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007206 flush_cache_(flush_cache) {
7207 // Create a new macro assembler pointing to the address of the code to patch.
7208 // The size is adjusted with kGap on order for the assembler to generate size
7209 // bytes of instructions without failing with buffer size constraints.
7210 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
7211}
7212
7213
7214CodePatcher::~CodePatcher() {
7215 // Indicate that code has changed.
7216 if (flush_cache_ == FLUSH) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007217 Assembler::FlushICache(masm_.isolate(), address_, size_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007218 }
7219 // Check that the code was patched as expected.
7220 DCHECK(masm_.pc_ == address_ + size_);
7221 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
7222}
7223
7224
7225void CodePatcher::Emit(Instr instr) {
7226 masm()->emit(instr);
7227}
7228
7229
7230void CodePatcher::Emit(Address addr) {
7231 // masm()->emit(reinterpret_cast<Instr>(addr));
7232}
7233
7234
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007235void CodePatcher::ChangeBranchCondition(Instr current_instr,
7236 uint32_t new_opcode) {
7237 current_instr = (current_instr & ~kOpcodeMask) | new_opcode;
7238 masm_.emit(current_instr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007239}
7240
7241
7242void MacroAssembler::TruncatingDiv(Register result,
7243 Register dividend,
7244 int32_t divisor) {
7245 DCHECK(!dividend.is(result));
7246 DCHECK(!dividend.is(at));
7247 DCHECK(!result.is(at));
7248 base::MagicNumbersForDivision<uint32_t> mag =
7249 base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007250 li(at, Operand(static_cast<int32_t>(mag.multiplier)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007251 Mulh(result, dividend, Operand(at));
7252 bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
7253 if (divisor > 0 && neg) {
7254 Addu(result, result, Operand(dividend));
7255 }
7256 if (divisor < 0 && !neg && mag.multiplier > 0) {
7257 Subu(result, result, Operand(dividend));
7258 }
7259 if (mag.shift > 0) sra(result, result, mag.shift);
7260 srl(at, dividend, 31);
7261 Addu(result, result, Operand(at));
7262}
7263
7264
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007265} // namespace internal
7266} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007267
7268#endif // V8_TARGET_ARCH_MIPS64