1// Copyright 2014 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 <assert.h>  // For assert
6#include <limits.h>  // For LONG_MIN, LONG_MAX.
7
8#if V8_TARGET_ARCH_S390
9
10#include "src/base/bits.h"
11#include "src/base/division-by-constant.h"
12#include "src/bootstrapper.h"
13#include "src/codegen.h"
14#include "src/debug/debug.h"
15#include "src/register-configuration.h"
16#include "src/runtime/runtime.h"
17
18#include "src/s390/macro-assembler-s390.h"
19
20namespace v8 {
21namespace internal {
22
23MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size,
24                               CodeObjectRequired create_code_object)
25    : Assembler(arg_isolate, buffer, size),
26      generating_stub_(false),
27      has_frame_(false) {
28  if (create_code_object == CodeObjectRequired::kYes) {
29    code_object_ =
30        Handle<Object>::New(isolate()->heap()->undefined_value(), isolate());
31  }
32}
33
34void MacroAssembler::Jump(Register target) { b(target); }
35
36void MacroAssembler::JumpToJSEntry(Register target) {
37  Move(ip, target);
38  Jump(ip);
39}
40
41void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
42                          Condition cond, CRegister) {
43  Label skip;
44
45  if (cond != al) b(NegateCondition(cond), &skip);
46
47  DCHECK(rmode == RelocInfo::CODE_TARGET || rmode == RelocInfo::RUNTIME_ENTRY);
48
49  mov(ip, Operand(target, rmode));
50  b(ip);
51
52  bind(&skip);
53}
54
55void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode, Condition cond,
56                          CRegister cr) {
57  DCHECK(!RelocInfo::IsCodeTarget(rmode));
58  Jump(reinterpret_cast<intptr_t>(target), rmode, cond, cr);
59}
60
61void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
62                          Condition cond) {
63  DCHECK(RelocInfo::IsCodeTarget(rmode));
64  jump(code, rmode, cond);
65}
66
67int MacroAssembler::CallSize(Register target) { return 2; }  // BASR
68
69void MacroAssembler::Call(Register target) {
70  Label start;
71  bind(&start);
72
73  // Branch to target via indirect branch
74  basr(r14, target);
75
76  DCHECK_EQ(CallSize(target), SizeOfCodeGeneratedSince(&start));
77}
78
79void MacroAssembler::CallJSEntry(Register target) {
80  DCHECK(target.is(ip));
81  Call(target);
82}
83
84int MacroAssembler::CallSize(Address target, RelocInfo::Mode rmode,
85                             Condition cond) {
86  // S390 Assembler::move sequence is IILF / IIHF
87  int size;
88#if V8_TARGET_ARCH_S390X
89  size = 14;  // IILF + IIHF + BASR
90#else
91  size = 8;  // IILF + BASR
92#endif
93  return size;
94}
95
96int MacroAssembler::CallSizeNotPredictableCodeSize(Address target,
97                                                   RelocInfo::Mode rmode,
98                                                   Condition cond) {
99  // S390 Assembler::move sequence is IILF / IIHF
100  int size;
101#if V8_TARGET_ARCH_S390X
102  size = 14;  // IILF + IIHF + BASR
103#else
104  size = 8;  // IILF + BASR
105#endif
106  return size;
107}
108
109void MacroAssembler::Call(Address target, RelocInfo::Mode rmode,
110                          Condition cond) {
111  DCHECK(cond == al);
112
113#ifdef DEBUG
114  // Check the expected size before generating code to ensure we assume the same
115  // constant pool availability (e.g., whether constant pool is full or not).
116  int expected_size = CallSize(target, rmode, cond);
117  Label start;
118  bind(&start);
119#endif
120
121  mov(ip, Operand(reinterpret_cast<intptr_t>(target), rmode));
122  basr(r14, ip);
123
124  DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start));
125}
126
127int MacroAssembler::CallSize(Handle<Code> code, RelocInfo::Mode rmode,
128                             TypeFeedbackId ast_id, Condition cond) {
129  return 6;  // BRASL
130}
131
132void MacroAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
133                          TypeFeedbackId ast_id, Condition cond) {
134  DCHECK(RelocInfo::IsCodeTarget(rmode) && cond == al);
135
136#ifdef DEBUG
137  // Check the expected size before generating code to ensure we assume the same
138  // constant pool availability (e.g., whether constant pool is full or not).
139  int expected_size = CallSize(code, rmode, ast_id, cond);
140  Label start;
141  bind(&start);
142#endif
143  call(code, rmode, ast_id);
144  DCHECK_EQ(expected_size, SizeOfCodeGeneratedSince(&start));
145}
146
147void MacroAssembler::Drop(int count) {
148  if (count > 0) {
149    int total = count * kPointerSize;
150    if (is_uint12(total)) {
151      la(sp, MemOperand(sp, total));
152    } else if (is_int20(total)) {
153      lay(sp, MemOperand(sp, total));
154    } else {
155      AddP(sp, Operand(total));
156    }
157  }
158}
159
160void MacroAssembler::Drop(Register count, Register scratch) {
161  ShiftLeftP(scratch, count, Operand(kPointerSizeLog2));
162  AddP(sp, sp, scratch);
163}
164
165void MacroAssembler::Call(Label* target) { b(r14, target); }
166
167void MacroAssembler::Push(Handle<Object> handle) {
168  mov(r0, Operand(handle));
169  push(r0);
170}
171
172void MacroAssembler::Move(Register dst, Handle<Object> value) {
173  mov(dst, Operand(value));
174}
175
176void MacroAssembler::Move(Register dst, Register src, Condition cond) {
177  if (!dst.is(src)) {
178    LoadRR(dst, src);
179  }
180}
181
182void MacroAssembler::Move(DoubleRegister dst, DoubleRegister src) {
183  if (!dst.is(src)) {
184    ldr(dst, src);
185  }
186}
187
188void MacroAssembler::MultiPush(RegList regs, Register location) {
189  int16_t num_to_push = NumberOfBitsSet(regs);
190  int16_t stack_offset = num_to_push * kPointerSize;
191
192  SubP(location, location, Operand(stack_offset));
193  for (int16_t i = Register::kNumRegisters - 1; i >= 0; i--) {
194    if ((regs & (1 << i)) != 0) {
195      stack_offset -= kPointerSize;
196      StoreP(ToRegister(i), MemOperand(location, stack_offset));
197    }
198  }
199}
200
201void MacroAssembler::MultiPop(RegList regs, Register location) {
202  int16_t stack_offset = 0;
203
204  for (int16_t i = 0; i < Register::kNumRegisters; i++) {
205    if ((regs & (1 << i)) != 0) {
206      LoadP(ToRegister(i), MemOperand(location, stack_offset));
207      stack_offset += kPointerSize;
208    }
209  }
210  AddP(location, location, Operand(stack_offset));
211}
212
213void MacroAssembler::MultiPushDoubles(RegList dregs, Register location) {
214  int16_t num_to_push = NumberOfBitsSet(dregs);
215  int16_t stack_offset = num_to_push * kDoubleSize;
216
217  SubP(location, location, Operand(stack_offset));
218  for (int16_t i = DoubleRegister::kNumRegisters - 1; i >= 0; i--) {
219    if ((dregs & (1 << i)) != 0) {
220      DoubleRegister dreg = DoubleRegister::from_code(i);
221      stack_offset -= kDoubleSize;
222      StoreDouble(dreg, MemOperand(location, stack_offset));
223    }
224  }
225}
226
227void MacroAssembler::MultiPopDoubles(RegList dregs, Register location) {
228  int16_t stack_offset = 0;
229
230  for (int16_t i = 0; i < DoubleRegister::kNumRegisters; i++) {
231    if ((dregs & (1 << i)) != 0) {
232      DoubleRegister dreg = DoubleRegister::from_code(i);
233      LoadDouble(dreg, MemOperand(location, stack_offset));
234      stack_offset += kDoubleSize;
235    }
236  }
237  AddP(location, location, Operand(stack_offset));
238}
239
240void MacroAssembler::LoadRoot(Register destination, Heap::RootListIndex index,
241                              Condition) {
242  LoadP(destination, MemOperand(kRootRegister, index << kPointerSizeLog2), r0);
243}
244
245void MacroAssembler::StoreRoot(Register source, Heap::RootListIndex index,
246                               Condition) {
247  DCHECK(Heap::RootCanBeWrittenAfterInitialization(index));
248  StoreP(source, MemOperand(kRootRegister, index << kPointerSizeLog2));
249}
250
251void MacroAssembler::InNewSpace(Register object, Register scratch,
252                                Condition cond, Label* branch) {
253  DCHECK(cond == eq || cond == ne);
254  CheckPageFlag(object, scratch, MemoryChunk::kIsInNewSpaceMask, cond, branch);
255}
256
257void MacroAssembler::RecordWriteField(
258    Register object, int offset, Register value, Register dst,
259    LinkRegisterStatus lr_status, SaveFPRegsMode save_fp,
260    RememberedSetAction remembered_set_action, SmiCheck smi_check,
261    PointersToHereCheck pointers_to_here_check_for_value) {
262  // First, check if a write barrier is even needed. The tests below
263  // catch stores of Smis.
264  Label done;
265
266  // Skip barrier if writing a smi.
267  if (smi_check == INLINE_SMI_CHECK) {
268    JumpIfSmi(value, &done);
269  }
270
271  // Although the object register is tagged, the offset is relative to the start
272  // of the object, so so offset must be a multiple of kPointerSize.
273  DCHECK(IsAligned(offset, kPointerSize));
274
275  lay(dst, MemOperand(object, offset - kHeapObjectTag));
276  if (emit_debug_code()) {
277    Label ok;
278    AndP(r0, dst, Operand((1 << kPointerSizeLog2) - 1));
279    beq(&ok, Label::kNear);
280    stop("Unaligned cell in write barrier");
281    bind(&ok);
282  }
283
284  RecordWrite(object, dst, value, lr_status, save_fp, remembered_set_action,
285              OMIT_SMI_CHECK, pointers_to_here_check_for_value);
286
287  bind(&done);
288
289  // Clobber clobbered input registers when running with the debug-code flag
290  // turned on to provoke errors.
291  if (emit_debug_code()) {
292    mov(value, Operand(bit_cast<intptr_t>(kZapValue + 4)));
293    mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 8)));
294  }
295}
296
297// Will clobber 4 registers: object, map, dst, ip.  The
298// register 'object' contains a heap object pointer.
299void MacroAssembler::RecordWriteForMap(Register object, Register map,
300                                       Register dst,
301                                       LinkRegisterStatus lr_status,
302                                       SaveFPRegsMode fp_mode) {
303  if (emit_debug_code()) {
304    LoadP(dst, FieldMemOperand(map, HeapObject::kMapOffset));
305    CmpP(dst, Operand(isolate()->factory()->meta_map()));
306    Check(eq, kWrongAddressOrValuePassedToRecordWrite);
307  }
308
309  if (!FLAG_incremental_marking) {
310    return;
311  }
312
313  if (emit_debug_code()) {
314    CmpP(map, FieldMemOperand(object, HeapObject::kMapOffset));
315    Check(eq, kWrongAddressOrValuePassedToRecordWrite);
316  }
317
318  Label done;
319
320  // A single check of the map's pages interesting flag suffices, since it is
321  // only set during incremental collection, and then it's also guaranteed that
322  // the from object's page's interesting flag is also set.  This optimization
323  // relies on the fact that maps can never be in new space.
324  CheckPageFlag(map,
325                map,  // Used as scratch.
326                MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
327
328  lay(dst, MemOperand(object, HeapObject::kMapOffset - kHeapObjectTag));
329  if (emit_debug_code()) {
330    Label ok;
331    AndP(r0, dst, Operand((1 << kPointerSizeLog2) - 1));
332    beq(&ok, Label::kNear);
333    stop("Unaligned cell in write barrier");
334    bind(&ok);
335  }
336
337  // Record the actual write.
338  if (lr_status == kLRHasNotBeenSaved) {
339    push(r14);
340  }
341  RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET,
342                       fp_mode);
343  CallStub(&stub);
344  if (lr_status == kLRHasNotBeenSaved) {
345    pop(r14);
346  }
347
348  bind(&done);
349
350  // Count number of write barriers in generated code.
351  isolate()->counters()->write_barriers_static()->Increment();
352  IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip, dst);
353
354  // Clobber clobbered registers when running with the debug-code flag
355  // turned on to provoke errors.
356  if (emit_debug_code()) {
357    mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 12)));
358    mov(map, Operand(bit_cast<intptr_t>(kZapValue + 16)));
359  }
360}
361
362// Will clobber 4 registers: object, address, scratch, ip.  The
363// register 'object' contains a heap object pointer.  The heap object
364// tag is shifted away.
365void MacroAssembler::RecordWrite(
366    Register object, Register address, Register value,
367    LinkRegisterStatus lr_status, SaveFPRegsMode fp_mode,
368    RememberedSetAction remembered_set_action, SmiCheck smi_check,
369    PointersToHereCheck pointers_to_here_check_for_value) {
370  DCHECK(!object.is(value));
371  if (emit_debug_code()) {
372    CmpP(value, MemOperand(address));
373    Check(eq, kWrongAddressOrValuePassedToRecordWrite);
374  }
375
376  if (remembered_set_action == OMIT_REMEMBERED_SET &&
377      !FLAG_incremental_marking) {
378    return;
379  }
380  // First, check if a write barrier is even needed. The tests below
381  // catch stores of smis and stores into the young generation.
382  Label done;
383
384  if (smi_check == INLINE_SMI_CHECK) {
385    JumpIfSmi(value, &done);
386  }
387
388  if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) {
389    CheckPageFlag(value,
390                  value,  // Used as scratch.
391                  MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
392  }
393  CheckPageFlag(object,
394                value,  // Used as scratch.
395                MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done);
396
397  // Record the actual write.
398  if (lr_status == kLRHasNotBeenSaved) {
399    push(r14);
400  }
401  RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
402                       fp_mode);
403  CallStub(&stub);
404  if (lr_status == kLRHasNotBeenSaved) {
405    pop(r14);
406  }
407
408  bind(&done);
409
410  // Count number of write barriers in generated code.
411  isolate()->counters()->write_barriers_static()->Increment();
412  IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip,
413                   value);
414
415  // Clobber clobbered registers when running with the debug-code flag
416  // turned on to provoke errors.
417  if (emit_debug_code()) {
418    mov(address, Operand(bit_cast<intptr_t>(kZapValue + 12)));
419    mov(value, Operand(bit_cast<intptr_t>(kZapValue + 16)));
420  }
421}
422
423void MacroAssembler::RecordWriteCodeEntryField(Register js_function,
424                                               Register code_entry,
425                                               Register scratch) {
426  const int offset = JSFunction::kCodeEntryOffset;
427
428  // Since a code entry (value) is always in old space, we don't need to update
429  // remembered set. If incremental marking is off, there is nothing for us to
430  // do.
431  if (!FLAG_incremental_marking) return;
432
433  DCHECK(js_function.is(r3));
434  DCHECK(code_entry.is(r6));
435  DCHECK(scratch.is(r7));
436  AssertNotSmi(js_function);
437
438  if (emit_debug_code()) {
439    AddP(scratch, js_function, Operand(offset - kHeapObjectTag));
440    LoadP(ip, MemOperand(scratch));
441    CmpP(ip, code_entry);
442    Check(eq, kWrongAddressOrValuePassedToRecordWrite);
443  }
444
445  // First, check if a write barrier is even needed. The tests below
446  // catch stores of Smis and stores into young gen.
447  Label done;
448
449  CheckPageFlag(code_entry, scratch,
450                MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
451  CheckPageFlag(js_function, scratch,
452                MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done);
453
454  const Register dst = scratch;
455  AddP(dst, js_function, Operand(offset - kHeapObjectTag));
456
457  // Save caller-saved registers.  js_function and code_entry are in the
458  // caller-saved register list.
459  DCHECK(kJSCallerSaved & js_function.bit());
460  // DCHECK(kJSCallerSaved & code_entry.bit());
461  MultiPush(kJSCallerSaved | code_entry.bit() | r14.bit());
462
463  int argument_count = 3;
464  PrepareCallCFunction(argument_count, code_entry);
465
466  LoadRR(r2, js_function);
467  LoadRR(r3, dst);
468  mov(r4, Operand(ExternalReference::isolate_address(isolate())));
469
470  {
471    AllowExternalCallThatCantCauseGC scope(this);
472    CallCFunction(
473        ExternalReference::incremental_marking_record_write_code_entry_function(
474            isolate()),
475        argument_count);
476  }
477
478  // Restore caller-saved registers (including js_function and code_entry).
479  MultiPop(kJSCallerSaved | code_entry.bit() | r14.bit());
480
481  bind(&done);
482}
483
484void MacroAssembler::RememberedSetHelper(Register object,  // For debug tests.
485                                         Register address, Register scratch,
486                                         SaveFPRegsMode fp_mode,
487                                         RememberedSetFinalAction and_then) {
488  Label done;
489  if (emit_debug_code()) {
490    Label ok;
491    JumpIfNotInNewSpace(object, scratch, &ok);
492    stop("Remembered set pointer is in new space");
493    bind(&ok);
494  }
495  // Load store buffer top.
496  ExternalReference store_buffer =
497      ExternalReference::store_buffer_top(isolate());
498  mov(ip, Operand(store_buffer));
499  LoadP(scratch, MemOperand(ip));
500  // Store pointer to buffer and increment buffer top.
501  StoreP(address, MemOperand(scratch));
502  AddP(scratch, Operand(kPointerSize));
503  // Write back new top of buffer.
504  StoreP(scratch, MemOperand(ip));
505  // Call stub on end of buffer.
506  // Check for end of buffer.
507  AndP(scratch, Operand(StoreBuffer::kStoreBufferMask));
508
509  if (and_then == kFallThroughAtEnd) {
510    bne(&done, Label::kNear);
511  } else {
512    DCHECK(and_then == kReturnAtEnd);
513    bne(&done, Label::kNear);
514  }
515  push(r14);
516  StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode);
517  CallStub(&store_buffer_overflow);
518  pop(r14);
519  bind(&done);
520  if (and_then == kReturnAtEnd) {
521    Ret();
522  }
523}
524
525void MacroAssembler::PushCommonFrame(Register marker_reg) {
526  int fp_delta = 0;
527  CleanseP(r14);
528  if (marker_reg.is_valid()) {
529    Push(r14, fp, marker_reg);
530    fp_delta = 1;
531  } else {
532    Push(r14, fp);
533    fp_delta = 0;
534  }
535  la(fp, MemOperand(sp, fp_delta * kPointerSize));
536}
537
538void MacroAssembler::PopCommonFrame(Register marker_reg) {
539  if (marker_reg.is_valid()) {
540    Pop(r14, fp, marker_reg);
541  } else {
542    Pop(r14, fp);
543  }
544}
545
546void MacroAssembler::PushStandardFrame(Register function_reg) {
547  int fp_delta = 0;
548  CleanseP(r14);
549  if (function_reg.is_valid()) {
550    Push(r14, fp, cp, function_reg);
551    fp_delta = 2;
552  } else {
553    Push(r14, fp, cp);
554    fp_delta = 1;
555  }
556  la(fp, MemOperand(sp, fp_delta * kPointerSize));
557}
558
559void MacroAssembler::RestoreFrameStateForTailCall() {
560  // if (FLAG_enable_embedded_constant_pool) {
561  //   LoadP(kConstantPoolRegister,
562  //         MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
563  //   set_constant_pool_available(false);
564  // }
565  DCHECK(!FLAG_enable_embedded_constant_pool);
566  LoadP(r14, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
567  LoadP(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
568}
569
570const RegList MacroAssembler::kSafepointSavedRegisters = Register::kAllocatable;
571const int MacroAssembler::kNumSafepointSavedRegisters =
572    Register::kNumAllocatable;
573
574// Push and pop all registers that can hold pointers.
575void MacroAssembler::PushSafepointRegisters() {
576  // Safepoints expect a block of kNumSafepointRegisters values on the
577  // stack, so adjust the stack for unsaved registers.
578  const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
579  DCHECK(num_unsaved >= 0);
580  if (num_unsaved > 0) {
581    lay(sp, MemOperand(sp, -(num_unsaved * kPointerSize)));
582  }
583  MultiPush(kSafepointSavedRegisters);
584}
585
586void MacroAssembler::PopSafepointRegisters() {
587  const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
588  MultiPop(kSafepointSavedRegisters);
589  if (num_unsaved > 0) {
590    la(sp, MemOperand(sp, num_unsaved * kPointerSize));
591  }
592}
593
594void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) {
595  StoreP(src, SafepointRegisterSlot(dst));
596}
597
598void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
599  LoadP(dst, SafepointRegisterSlot(src));
600}
601
602int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
603  // The registers are pushed starting with the highest encoding,
604  // which means that lowest encodings are closest to the stack pointer.
605  RegList regs = kSafepointSavedRegisters;
606  int index = 0;
607
608  DCHECK(reg_code >= 0 && reg_code < kNumRegisters);
609
610  for (int16_t i = 0; i < reg_code; i++) {
611    if ((regs & (1 << i)) != 0) {
612      index++;
613    }
614  }
615
616  return index;
617}
618
619MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
620  return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
621}
622
623MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
624  // General purpose registers are pushed last on the stack.
625  const RegisterConfiguration* config = RegisterConfiguration::Crankshaft();
626  int doubles_size = config->num_allocatable_double_registers() * kDoubleSize;
627  int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
628  return MemOperand(sp, doubles_size + register_offset);
629}
630
631void MacroAssembler::CanonicalizeNaN(const DoubleRegister dst,
632                                     const DoubleRegister src) {
633  // Turn potential sNaN into qNaN
634  if (!dst.is(src)) ldr(dst, src);
635  lzdr(kDoubleRegZero);
636  sdbr(dst, kDoubleRegZero);
637}
638
639void MacroAssembler::ConvertIntToDouble(Register src, DoubleRegister dst) {
640  cdfbr(dst, src);
641}
642
643void MacroAssembler::ConvertUnsignedIntToDouble(Register src,
644                                                DoubleRegister dst) {
645  if (CpuFeatures::IsSupported(FLOATING_POINT_EXT)) {
646    cdlfbr(Condition(5), Condition(0), dst, src);
647  } else {
648    // zero-extend src
649    llgfr(src, src);
650    // convert to double
651    cdgbr(dst, src);
652  }
653}
654
655void MacroAssembler::ConvertIntToFloat(Register src, DoubleRegister dst) {
656  cefbr(Condition(4), dst, src);
657}
658
659void MacroAssembler::ConvertUnsignedIntToFloat(Register src,
660                                               DoubleRegister dst) {
661  celfbr(Condition(4), Condition(0), dst, src);
662}
663
664#if V8_TARGET_ARCH_S390X
665void MacroAssembler::ConvertInt64ToDouble(Register src,
666                                          DoubleRegister double_dst) {
667  cdgbr(double_dst, src);
668}
669
670void MacroAssembler::ConvertUnsignedInt64ToFloat(Register src,
671                                                 DoubleRegister double_dst) {
672  celgbr(Condition(0), Condition(0), double_dst, src);
673}
674
675void MacroAssembler::ConvertUnsignedInt64ToDouble(Register src,
676                                                  DoubleRegister double_dst) {
677  cdlgbr(Condition(0), Condition(0), double_dst, src);
678}
679
680void MacroAssembler::ConvertInt64ToFloat(Register src,
681                                         DoubleRegister double_dst) {
682  cegbr(double_dst, src);
683}
684#endif
685
686void MacroAssembler::ConvertFloat32ToInt64(const DoubleRegister double_input,
687#if !V8_TARGET_ARCH_S390X
688                                           const Register dst_hi,
689#endif
690                                           const Register dst,
691                                           const DoubleRegister double_dst,
692                                           FPRoundingMode rounding_mode) {
693  Condition m = Condition(0);
694  switch (rounding_mode) {
695    case kRoundToZero:
696      m = Condition(5);
697      break;
698    case kRoundToNearest:
699      UNIMPLEMENTED();
700      break;
701    case kRoundToPlusInf:
702      m = Condition(6);
703      break;
704    case kRoundToMinusInf:
705      m = Condition(7);
706      break;
707    default:
708      UNIMPLEMENTED();
709      break;
710  }
711  cgebr(m, dst, double_input);
712  ldgr(double_dst, dst);
713#if !V8_TARGET_ARCH_S390X
714  srlg(dst_hi, dst, Operand(32));
715#endif
716}
717
718void MacroAssembler::ConvertDoubleToInt64(const DoubleRegister double_input,
719#if !V8_TARGET_ARCH_S390X
720                                          const Register dst_hi,
721#endif
722                                          const Register dst,
723                                          const DoubleRegister double_dst,
724                                          FPRoundingMode rounding_mode) {
725  Condition m = Condition(0);
726  switch (rounding_mode) {
727    case kRoundToZero:
728      m = Condition(5);
729      break;
730    case kRoundToNearest:
731      UNIMPLEMENTED();
732      break;
733    case kRoundToPlusInf:
734      m = Condition(6);
735      break;
736    case kRoundToMinusInf:
737      m = Condition(7);
738      break;
739    default:
740      UNIMPLEMENTED();
741      break;
742  }
743  cgdbr(m, dst, double_input);
744  ldgr(double_dst, dst);
745#if !V8_TARGET_ARCH_S390X
746  srlg(dst_hi, dst, Operand(32));
747#endif
748}
749
750void MacroAssembler::ConvertFloat32ToInt32(const DoubleRegister double_input,
751                                           const Register dst,
752                                           const DoubleRegister double_dst,
753                                           FPRoundingMode rounding_mode) {
754  Condition m = Condition(0);
755  switch (rounding_mode) {
756    case kRoundToZero:
757      m = Condition(5);
758      break;
759    case kRoundToNearest:
760      m = Condition(4);
761      break;
762    case kRoundToPlusInf:
763      m = Condition(6);
764      break;
765    case kRoundToMinusInf:
766      m = Condition(7);
767      break;
768    default:
769      UNIMPLEMENTED();
770      break;
771  }
772  cfebr(m, dst, double_input);
773  Label done;
774  b(Condition(0xe), &done, Label::kNear);  // special case
775  LoadImmP(dst, Operand::Zero());
776  bind(&done);
777  ldgr(double_dst, dst);
778}
779
780void MacroAssembler::ConvertFloat32ToUnsignedInt32(
781    const DoubleRegister double_input, const Register dst,
782    const DoubleRegister double_dst, FPRoundingMode rounding_mode) {
783  Condition m = Condition(0);
784  switch (rounding_mode) {
785    case kRoundToZero:
786      m = Condition(5);
787      break;
788    case kRoundToNearest:
789      UNIMPLEMENTED();
790      break;
791    case kRoundToPlusInf:
792      m = Condition(6);
793      break;
794    case kRoundToMinusInf:
795      m = Condition(7);
796      break;
797    default:
798      UNIMPLEMENTED();
799      break;
800  }
801  clfebr(m, Condition(0), dst, double_input);
802  Label done;
803  b(Condition(0xe), &done, Label::kNear);  // special case
804  LoadImmP(dst, Operand::Zero());
805  bind(&done);
806  ldgr(double_dst, dst);
807}
808
809#if V8_TARGET_ARCH_S390X
810void MacroAssembler::ConvertFloat32ToUnsignedInt64(
811    const DoubleRegister double_input, const Register dst,
812    const DoubleRegister double_dst, FPRoundingMode rounding_mode) {
813  Condition m = Condition(0);
814  switch (rounding_mode) {
815    case kRoundToZero:
816      m = Condition(5);
817      break;
818    case kRoundToNearest:
819      UNIMPLEMENTED();
820      break;
821    case kRoundToPlusInf:
822      m = Condition(6);
823      break;
824    case kRoundToMinusInf:
825      m = Condition(7);
826      break;
827    default:
828      UNIMPLEMENTED();
829      break;
830  }
831  clgebr(m, Condition(0), dst, double_input);
832  ldgr(double_dst, dst);
833}
834
835void MacroAssembler::ConvertDoubleToUnsignedInt64(
836    const DoubleRegister double_input, const Register dst,
837    const DoubleRegister double_dst, FPRoundingMode rounding_mode) {
838  Condition m = Condition(0);
839  switch (rounding_mode) {
840    case kRoundToZero:
841      m = Condition(5);
842      break;
843    case kRoundToNearest:
844      UNIMPLEMENTED();
845      break;
846    case kRoundToPlusInf:
847      m = Condition(6);
848      break;
849    case kRoundToMinusInf:
850      m = Condition(7);
851      break;
852    default:
853      UNIMPLEMENTED();
854      break;
855  }
856  clgdbr(m, Condition(0), dst, double_input);
857  ldgr(double_dst, dst);
858}
859
860#endif
861
862#if !V8_TARGET_ARCH_S390X
863void MacroAssembler::ShiftLeftPair(Register dst_low, Register dst_high,
864                                   Register src_low, Register src_high,
865                                   Register scratch, Register shift) {
866  LoadRR(r0, src_high);
867  LoadRR(r1, src_low);
868  sldl(r0, shift, Operand::Zero());
869  LoadRR(dst_high, r0);
870  LoadRR(dst_low, r1);
871}
872
873void MacroAssembler::ShiftLeftPair(Register dst_low, Register dst_high,
874                                   Register src_low, Register src_high,
875                                   uint32_t shift) {
876  LoadRR(r0, src_high);
877  LoadRR(r1, src_low);
878  sldl(r0, r0, Operand(shift));
879  LoadRR(dst_high, r0);
880  LoadRR(dst_low, r1);
881}
882
883void MacroAssembler::ShiftRightPair(Register dst_low, Register dst_high,
884                                    Register src_low, Register src_high,
885                                    Register scratch, Register shift) {
886  LoadRR(r0, src_high);
887  LoadRR(r1, src_low);
888  srdl(r0, shift, Operand::Zero());
889  LoadRR(dst_high, r0);
890  LoadRR(dst_low, r1);
891}
892
893void MacroAssembler::ShiftRightPair(Register dst_low, Register dst_high,
894                                    Register src_low, Register src_high,
895                                    uint32_t shift) {
896  LoadRR(r0, src_high);
897  LoadRR(r1, src_low);
898  srdl(r0, r0, Operand(shift));
899  LoadRR(dst_high, r0);
900  LoadRR(dst_low, r1);
901}
902
903void MacroAssembler::ShiftRightArithPair(Register dst_low, Register dst_high,
904                                         Register src_low, Register src_high,
905                                         Register scratch, Register shift) {
906  LoadRR(r0, src_high);
907  LoadRR(r1, src_low);
908  srda(r0, shift, Operand::Zero());
909  LoadRR(dst_high, r0);
910  LoadRR(dst_low, r1);
911}
912
913void MacroAssembler::ShiftRightArithPair(Register dst_low, Register dst_high,
914                                         Register src_low, Register src_high,
915                                         uint32_t shift) {
916  LoadRR(r0, src_high);
917  LoadRR(r1, src_low);
918  srda(r0, r0, Operand(shift));
919  LoadRR(dst_high, r0);
920  LoadRR(dst_low, r1);
921}
922#endif
923
924void MacroAssembler::MovDoubleToInt64(Register dst, DoubleRegister src) {
925  lgdr(dst, src);
926}
927
928void MacroAssembler::MovInt64ToDouble(DoubleRegister dst, Register src) {
929  ldgr(dst, src);
930}
931
932void MacroAssembler::StubPrologue(StackFrame::Type type, Register base,
933                                  int prologue_offset) {
934  {
935    ConstantPoolUnavailableScope constant_pool_unavailable(this);
936    Load(r1, Operand(StackFrame::TypeToMarker(type)));
937    PushCommonFrame(r1);
938  }
939}
940
941void MacroAssembler::Prologue(bool code_pre_aging, Register base,
942                              int prologue_offset) {
943  DCHECK(!base.is(no_reg));
944  {
945    PredictableCodeSizeScope predictible_code_size_scope(
946        this, kNoCodeAgeSequenceLength);
947    // The following instructions must remain together and unmodified
948    // for code aging to work properly.
949    if (code_pre_aging) {
950      // Pre-age the code.
951      // This matches the code found in PatchPlatformCodeAge()
952      Code* stub = Code::GetPreAgedCodeAgeStub(isolate());
953      intptr_t target = reinterpret_cast<intptr_t>(stub->instruction_start());
954      nop();
955      CleanseP(r14);
956      Push(r14);
957      mov(r2, Operand(target));
958      Call(r2);
959      for (int i = 0; i < kNoCodeAgeSequenceLength - kCodeAgingSequenceLength;
960           i += 2) {
961        // TODO(joransiu): Create nop function to pad
962        //         (kNoCodeAgeSequenceLength - kCodeAgingSequenceLength) bytes.
963        nop();  // 2-byte nops().
964      }
965    } else {
966      // This matches the code found in GetNoCodeAgeSequence()
967      PushStandardFrame(r3);
968    }
969  }
970}
971
972void MacroAssembler::EmitLoadFeedbackVector(Register vector) {
973  LoadP(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
974  LoadP(vector, FieldMemOperand(vector, JSFunction::kFeedbackVectorOffset));
975  LoadP(vector, FieldMemOperand(vector, Cell::kValueOffset));
976}
977
978void MacroAssembler::EnterFrame(StackFrame::Type type,
979                                bool load_constant_pool_pointer_reg) {
980  // We create a stack frame with:
981  //    Return Addr <-- old sp
982  //    Old FP      <-- new fp
983  //    CP
984  //    type
985  //    CodeObject  <-- new sp
986
987  Load(ip, Operand(StackFrame::TypeToMarker(type)));
988  PushCommonFrame(ip);
989
990  if (type == StackFrame::INTERNAL) {
991    mov(r0, Operand(CodeObject()));
992    push(r0);
993  }
994}
995
996int MacroAssembler::LeaveFrame(StackFrame::Type type, int stack_adjustment) {
997  // Drop the execution stack down to the frame pointer and restore
998  // the caller frame pointer, return address and constant pool pointer.
999  LoadP(r14, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
1000  lay(r1, MemOperand(
1001              fp, StandardFrameConstants::kCallerSPOffset + stack_adjustment));
1002  LoadP(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
1003  LoadRR(sp, r1);
1004  int frame_ends = pc_offset();
1005  return frame_ends;
1006}
1007
1008void MacroAssembler::EnterBuiltinFrame(Register context, Register target,
1009                                       Register argc) {
1010  CleanseP(r14);
1011  Push(r14, fp, context, target);
1012  la(fp, MemOperand(sp, 2 * kPointerSize));
1013  Push(argc);
1014}
1015
1016void MacroAssembler::LeaveBuiltinFrame(Register context, Register target,
1017                                       Register argc) {
1018  Pop(argc);
1019  Pop(r14, fp, context, target);
1020}
1021
1022// ExitFrame layout (probably wrongish.. needs updating)
1023//
1024//  SP -> previousSP
1025//        LK reserved
1026//        code
1027//        sp_on_exit (for debug?)
1028// oldSP->prev SP
1029//        LK
1030//        <parameters on stack>
1031
1032// Prior to calling EnterExitFrame, we've got a bunch of parameters
1033// on the stack that we need to wrap a real frame around.. so first
1034// we reserve a slot for LK and push the previous SP which is captured
1035// in the fp register (r11)
1036// Then - we buy a new frame
1037
1038// r14
1039// oldFP <- newFP
1040// SP
1041// Code
1042// Floats
1043// gaps
1044// Args
1045// ABIRes <- newSP
1046void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
1047                                    StackFrame::Type frame_type) {
1048  DCHECK(frame_type == StackFrame::EXIT ||
1049         frame_type == StackFrame::BUILTIN_EXIT);
1050  // Set up the frame structure on the stack.
1051  DCHECK_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
1052  DCHECK_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
1053  DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
1054  DCHECK(stack_space > 0);
1055
1056  // This is an opportunity to build a frame to wrap
1057  // all of the pushes that have happened inside of V8
1058  // since we were called from C code
1059  CleanseP(r14);
1060  Load(r1, Operand(StackFrame::TypeToMarker(frame_type)));
1061  PushCommonFrame(r1);
1062  // Reserve room for saved entry sp and code object.
1063  lay(sp, MemOperand(fp, -ExitFrameConstants::kFixedFrameSizeFromFp));
1064
1065  if (emit_debug_code()) {
1066    StoreP(MemOperand(fp, ExitFrameConstants::kSPOffset), Operand::Zero(), r1);
1067  }
1068  mov(r1, Operand(CodeObject()));
1069  StoreP(r1, MemOperand(fp, ExitFrameConstants::kCodeOffset));
1070
1071  // Save the frame pointer and the context in top.
1072  mov(r1, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
1073  StoreP(fp, MemOperand(r1));
1074  mov(r1, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
1075  StoreP(cp, MemOperand(r1));
1076
1077  // Optionally save all volatile double registers.
1078  if (save_doubles) {
1079    MultiPushDoubles(kCallerSavedDoubles);
1080    // Note that d0 will be accessible at
1081    //   fp - ExitFrameConstants::kFrameSize -
1082    //   kNumCallerSavedDoubles * kDoubleSize,
1083    // since the sp slot and code slot were pushed after the fp.
1084  }
1085
1086  lay(sp, MemOperand(sp, -stack_space * kPointerSize));
1087
1088  // Allocate and align the frame preparing for calling the runtime
1089  // function.
1090  const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
1091  if (frame_alignment > 0) {
1092    DCHECK(frame_alignment == 8);
1093    ClearRightImm(sp, sp, Operand(3));  // equivalent to &= -8
1094  }
1095
1096  lay(sp, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize));
1097  StoreP(MemOperand(sp), Operand::Zero(), r0);
1098  // Set the exit frame sp value to point just before the return address
1099  // location.
1100  lay(r1, MemOperand(sp, kStackFrameSPSlot * kPointerSize));
1101  StoreP(r1, MemOperand(fp, ExitFrameConstants::kSPOffset));
1102}
1103
1104int MacroAssembler::ActivationFrameAlignment() {
1105#if !defined(USE_SIMULATOR)
1106  // Running on the real platform. Use the alignment as mandated by the local
1107  // environment.
1108  // Note: This will break if we ever start generating snapshots on one S390
1109  // platform for another S390 platform with a different alignment.
1110  return base::OS::ActivationFrameAlignment();
1111#else  // Simulated
1112  // If we are using the simulator then we should always align to the expected
1113  // alignment. As the simulator is used to generate snapshots we do not know
1114  // if the target platform will need alignment, so this is controlled from a
1115  // flag.
1116  return FLAG_sim_stack_alignment;
1117#endif
1118}
1119
1120void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
1121                                    bool restore_context,
1122                                    bool argument_count_is_length) {
1123  // Optionally restore all double registers.
1124  if (save_doubles) {
1125    // Calculate the stack location of the saved doubles and restore them.
1126    const int kNumRegs = kNumCallerSavedDoubles;
1127    lay(r5, MemOperand(fp, -(ExitFrameConstants::kFixedFrameSizeFromFp +
1128                             kNumRegs * kDoubleSize)));
1129    MultiPopDoubles(kCallerSavedDoubles, r5);
1130  }
1131
1132  // Clear top frame.
1133  mov(ip, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
1134  StoreP(MemOperand(ip), Operand(0, kRelocInfo_NONEPTR), r0);
1135
1136  // Restore current context from top and clear it in debug mode.
1137  if (restore_context) {
1138    mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
1139    LoadP(cp, MemOperand(ip));
1140  }
1141#ifdef DEBUG
1142  mov(ip, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
1143  StoreP(MemOperand(ip), Operand(0, kRelocInfo_NONEPTR), r0);
1144#endif
1145
1146  // Tear down the exit frame, pop the arguments, and return.
1147  LeaveFrame(StackFrame::EXIT);
1148
1149  if (argument_count.is_valid()) {
1150    if (!argument_count_is_length) {
1151      ShiftLeftP(argument_count, argument_count, Operand(kPointerSizeLog2));
1152    }
1153    la(sp, MemOperand(sp, argument_count));
1154  }
1155}
1156
1157void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) {
1158  Move(dst, d0);
1159}
1160
1161void MacroAssembler::MovFromFloatParameter(const DoubleRegister dst) {
1162  Move(dst, d0);
1163}
1164
1165void MacroAssembler::PrepareForTailCall(const ParameterCount& callee_args_count,
1166                                        Register caller_args_count_reg,
1167                                        Register scratch0, Register scratch1) {
1168#if DEBUG
1169  if (callee_args_count.is_reg()) {
1170    DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0,
1171                       scratch1));
1172  } else {
1173    DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1));
1174  }
1175#endif
1176
1177  // Calculate the end of destination area where we will put the arguments
1178  // after we drop current frame. We AddP kPointerSize to count the receiver
1179  // argument which is not included into formal parameters count.
1180  Register dst_reg = scratch0;
1181  ShiftLeftP(dst_reg, caller_args_count_reg, Operand(kPointerSizeLog2));
1182  AddP(dst_reg, fp, dst_reg);
1183  AddP(dst_reg, dst_reg,
1184       Operand(StandardFrameConstants::kCallerSPOffset + kPointerSize));
1185
1186  Register src_reg = caller_args_count_reg;
1187  // Calculate the end of source area. +kPointerSize is for the receiver.
1188  if (callee_args_count.is_reg()) {
1189    ShiftLeftP(src_reg, callee_args_count.reg(), Operand(kPointerSizeLog2));
1190    AddP(src_reg, sp, src_reg);
1191    AddP(src_reg, src_reg, Operand(kPointerSize));
1192  } else {
1193    mov(src_reg, Operand((callee_args_count.immediate() + 1) * kPointerSize));
1194    AddP(src_reg, src_reg, sp);
1195  }
1196
1197  if (FLAG_debug_code) {
1198    CmpLogicalP(src_reg, dst_reg);
1199    Check(lt, kStackAccessBelowStackPointer);
1200  }
1201
1202  // Restore caller's frame pointer and return address now as they will be
1203  // overwritten by the copying loop.
1204  RestoreFrameStateForTailCall();
1205
1206  // Now copy callee arguments to the caller frame going backwards to avoid
1207  // callee arguments corruption (source and destination areas could overlap).
1208
1209  // Both src_reg and dst_reg are pointing to the word after the one to copy,
1210  // so they must be pre-decremented in the loop.
1211  Register tmp_reg = scratch1;
1212  Label loop;
1213  if (callee_args_count.is_reg()) {
1214    AddP(tmp_reg, callee_args_count.reg(), Operand(1));  // +1 for receiver
1215  } else {
1216    mov(tmp_reg, Operand(callee_args_count.immediate() + 1));
1217  }
1218  LoadRR(r1, tmp_reg);
1219  bind(&loop);
1220  LoadP(tmp_reg, MemOperand(src_reg, -kPointerSize));
1221  StoreP(tmp_reg, MemOperand(dst_reg, -kPointerSize));
1222  lay(src_reg, MemOperand(src_reg, -kPointerSize));
1223  lay(dst_reg, MemOperand(dst_reg, -kPointerSize));
1224  BranchOnCount(r1, &loop);
1225
1226  // Leave current frame.
1227  LoadRR(sp, dst_reg);
1228}
1229
1230void MacroAssembler::InvokePrologue(const ParameterCount& expected,
1231                                    const ParameterCount& actual, Label* done,
1232                                    bool* definitely_mismatches,
1233                                    InvokeFlag flag,
1234                                    const CallWrapper& call_wrapper) {
1235  bool definitely_matches = false;
1236  *definitely_mismatches = false;
1237  Label regular_invoke;
1238
1239  // Check whether the expected and actual arguments count match. If not,
1240  // setup registers according to contract with ArgumentsAdaptorTrampoline:
1241  //  r2: actual arguments count
1242  //  r3: function (passed through to callee)
1243  //  r4: expected arguments count
1244
1245  // The code below is made a lot easier because the calling code already sets
1246  // up actual and expected registers according to the contract if values are
1247  // passed in registers.
1248
1249  // ARM has some sanity checks as per below, considering add them for S390
1250  //  DCHECK(actual.is_immediate() || actual.reg().is(r2));
1251  //  DCHECK(expected.is_immediate() || expected.reg().is(r4));
1252
1253  if (expected.is_immediate()) {
1254    DCHECK(actual.is_immediate());
1255    mov(r2, Operand(actual.immediate()));
1256    if (expected.immediate() == actual.immediate()) {
1257      definitely_matches = true;
1258    } else {
1259      const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1260      if (expected.immediate() == sentinel) {
1261        // Don't worry about adapting arguments for builtins that
1262        // don't want that done. Skip adaption code by making it look
1263        // like we have a match between expected and actual number of
1264        // arguments.
1265        definitely_matches = true;
1266      } else {
1267        *definitely_mismatches = true;
1268        mov(r4, Operand(expected.immediate()));
1269      }
1270    }
1271  } else {
1272    if (actual.is_immediate()) {
1273      mov(r2, Operand(actual.immediate()));
1274      CmpPH(expected.reg(), Operand(actual.immediate()));
1275      beq(&regular_invoke);
1276    } else {
1277      CmpP(expected.reg(), actual.reg());
1278      beq(&regular_invoke);
1279    }
1280  }
1281
1282  if (!definitely_matches) {
1283    Handle<Code> adaptor = isolate()->builtins()->ArgumentsAdaptorTrampoline();
1284    if (flag == CALL_FUNCTION) {
1285      call_wrapper.BeforeCall(CallSize(adaptor));
1286      Call(adaptor);
1287      call_wrapper.AfterCall();
1288      if (!*definitely_mismatches) {
1289        b(done);
1290      }
1291    } else {
1292      Jump(adaptor, RelocInfo::CODE_TARGET);
1293    }
1294    bind(&regular_invoke);
1295  }
1296}
1297
1298void MacroAssembler::CheckDebugHook(Register fun, Register new_target,
1299                                    const ParameterCount& expected,
1300                                    const ParameterCount& actual) {
1301  Label skip_hook;
1302  ExternalReference debug_hook_avtive =
1303      ExternalReference::debug_hook_on_function_call_address(isolate());
1304  mov(r6, Operand(debug_hook_avtive));
1305  LoadB(r6, MemOperand(r6));
1306  CmpP(r6, Operand::Zero());
1307  beq(&skip_hook);
1308  {
1309    FrameScope frame(this,
1310                     has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
1311    if (expected.is_reg()) {
1312      SmiTag(expected.reg());
1313      Push(expected.reg());
1314    }
1315    if (actual.is_reg()) {
1316      SmiTag(actual.reg());
1317      Push(actual.reg());
1318    }
1319    if (new_target.is_valid()) {
1320      Push(new_target);
1321    }
1322    Push(fun, fun);
1323    CallRuntime(Runtime::kDebugOnFunctionCall);
1324    Pop(fun);
1325    if (new_target.is_valid()) {
1326      Pop(new_target);
1327    }
1328    if (actual.is_reg()) {
1329      Pop(actual.reg());
1330      SmiUntag(actual.reg());
1331    }
1332    if (expected.is_reg()) {
1333      Pop(expected.reg());
1334      SmiUntag(expected.reg());
1335    }
1336  }
1337  bind(&skip_hook);
1338}
1339
1340void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
1341                                        const ParameterCount& expected,
1342                                        const ParameterCount& actual,
1343                                        InvokeFlag flag,
1344                                        const CallWrapper& call_wrapper) {
1345  // You can't call a function without a valid frame.
1346  DCHECK(flag == JUMP_FUNCTION || has_frame());
1347
1348  DCHECK(function.is(r3));
1349  DCHECK_IMPLIES(new_target.is_valid(), new_target.is(r5));
1350
1351  if (call_wrapper.NeedsDebugHookCheck()) {
1352    CheckDebugHook(function, new_target, expected, actual);
1353  }
1354
1355  // Clear the new.target register if not given.
1356  if (!new_target.is_valid()) {
1357    LoadRoot(r5, Heap::kUndefinedValueRootIndex);
1358  }
1359
1360  Label done;
1361  bool definitely_mismatches = false;
1362  InvokePrologue(expected, actual, &done, &definitely_mismatches, flag,
1363                 call_wrapper);
1364  if (!definitely_mismatches) {
1365    // We call indirectly through the code field in the function to
1366    // allow recompilation to take effect without changing any of the
1367    // call sites.
1368    Register code = ip;
1369    LoadP(code, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
1370    if (flag == CALL_FUNCTION) {
1371      call_wrapper.BeforeCall(CallSize(code));
1372      CallJSEntry(code);
1373      call_wrapper.AfterCall();
1374    } else {
1375      DCHECK(flag == JUMP_FUNCTION);
1376      JumpToJSEntry(code);
1377    }
1378
1379    // Continue here if InvokePrologue does handle the invocation due to
1380    // mismatched parameter counts.
1381    bind(&done);
1382  }
1383}
1384
1385void MacroAssembler::InvokeFunction(Register fun, Register new_target,
1386                                    const ParameterCount& actual,
1387                                    InvokeFlag flag,
1388                                    const CallWrapper& call_wrapper) {
1389  // You can't call a function without a valid frame.
1390  DCHECK(flag == JUMP_FUNCTION || has_frame());
1391
1392  // Contract with called JS functions requires that function is passed in r3.
1393  DCHECK(fun.is(r3));
1394
1395  Register expected_reg = r4;
1396  Register temp_reg = r6;
1397  LoadP(temp_reg, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset));
1398  LoadP(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
1399  LoadW(expected_reg,
1400        FieldMemOperand(temp_reg,
1401                        SharedFunctionInfo::kFormalParameterCountOffset));
1402#if !defined(V8_TARGET_ARCH_S390X)
1403  SmiUntag(expected_reg);
1404#endif
1405
1406  ParameterCount expected(expected_reg);
1407  InvokeFunctionCode(fun, new_target, expected, actual, flag, call_wrapper);
1408}
1409
1410void MacroAssembler::InvokeFunction(Register function,
1411                                    const ParameterCount& expected,
1412                                    const ParameterCount& actual,
1413                                    InvokeFlag flag,
1414                                    const CallWrapper& call_wrapper) {
1415  // You can't call a function without a valid frame.
1416  DCHECK(flag == JUMP_FUNCTION || has_frame());
1417
1418  // Contract with called JS functions requires that function is passed in r3.
1419  DCHECK(function.is(r3));
1420
1421  // Get the function and setup the context.
1422  LoadP(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
1423
1424  InvokeFunctionCode(r3, no_reg, expected, actual, flag, call_wrapper);
1425}
1426
1427void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
1428                                    const ParameterCount& expected,
1429                                    const ParameterCount& actual,
1430                                    InvokeFlag flag,
1431                                    const CallWrapper& call_wrapper) {
1432  Move(r3, function);
1433  InvokeFunction(r3, expected, actual, flag, call_wrapper);
1434}
1435
1436void MacroAssembler::IsObjectJSStringType(Register object, Register scratch,
1437                                          Label* fail) {
1438  DCHECK(kNotStringTag != 0);
1439
1440  LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
1441  LoadlB(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
1442  mov(r0, Operand(kIsNotStringMask));
1443  AndP(r0, scratch);
1444  bne(fail);
1445}
1446
1447void MacroAssembler::IsObjectNameType(Register object, Register scratch,
1448                                      Label* fail) {
1449  LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
1450  LoadlB(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
1451  CmpP(scratch, Operand(LAST_NAME_TYPE));
1452  bgt(fail);
1453}
1454
1455void MacroAssembler::MaybeDropFrames() {
1456  // Check whether we need to drop frames to restart a function on the stack.
1457  ExternalReference restart_fp =
1458      ExternalReference::debug_restart_fp_address(isolate());
1459  mov(r3, Operand(restart_fp));
1460  LoadP(r3, MemOperand(r3));
1461  CmpP(r3, Operand::Zero());
1462  Jump(isolate()->builtins()->FrameDropperTrampoline(), RelocInfo::CODE_TARGET,
1463       ne);
1464}
1465
1466void MacroAssembler::PushStackHandler() {
1467  // Adjust this code if not the case.
1468  STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
1469  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
1470
1471  // Link the current handler as the next handler.
1472  mov(r7, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
1473
1474  // Buy the full stack frame for 5 slots.
1475  lay(sp, MemOperand(sp, -StackHandlerConstants::kSize));
1476
1477  // Copy the old handler into the next handler slot.
1478  mvc(MemOperand(sp, StackHandlerConstants::kNextOffset), MemOperand(r7),
1479      kPointerSize);
1480  // Set this new handler as the current one.
1481  StoreP(sp, MemOperand(r7));
1482}
1483
1484void MacroAssembler::PopStackHandler() {
1485  STATIC_ASSERT(StackHandlerConstants::kSize == 1 * kPointerSize);
1486  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1487
1488  // Pop the Next Handler into r3 and store it into Handler Address reference.
1489  Pop(r3);
1490  mov(ip, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
1491
1492  StoreP(r3, MemOperand(ip));
1493}
1494
1495// Compute the hash code from the untagged key.  This must be kept in sync with
1496// ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
1497// code-stub-hydrogen.cc
1498void MacroAssembler::GetNumberHash(Register t0, Register scratch) {
1499  // First of all we assign the hash seed to scratch.
1500  LoadRoot(scratch, Heap::kHashSeedRootIndex);
1501  SmiUntag(scratch);
1502
1503  // Xor original key with a seed.
1504  XorP(t0, scratch);
1505
1506  // Compute the hash code from the untagged key.  This must be kept in sync
1507  // with ComputeIntegerHash in utils.h.
1508  //
1509  // hash = ~hash + (hash << 15);
1510  LoadRR(scratch, t0);
1511  NotP(scratch);
1512  sll(t0, Operand(15));
1513  AddP(t0, scratch, t0);
1514  // hash = hash ^ (hash >> 12);
1515  ShiftRight(scratch, t0, Operand(12));
1516  XorP(t0, scratch);
1517  // hash = hash + (hash << 2);
1518  ShiftLeft(scratch, t0, Operand(2));
1519  AddP(t0, t0, scratch);
1520  // hash = hash ^ (hash >> 4);
1521  ShiftRight(scratch, t0, Operand(4));
1522  XorP(t0, scratch);
1523  // hash = hash * 2057;
1524  LoadRR(r0, t0);
1525  ShiftLeft(scratch, t0, Operand(3));
1526  AddP(t0, t0, scratch);
1527  ShiftLeft(scratch, r0, Operand(11));
1528  AddP(t0, t0, scratch);
1529  // hash = hash ^ (hash >> 16);
1530  ShiftRight(scratch, t0, Operand(16));
1531  XorP(t0, scratch);
1532  // hash & 0x3fffffff
1533  ExtractBitRange(t0, t0, 29, 0);
1534}
1535
1536void MacroAssembler::Allocate(int object_size, Register result,
1537                              Register scratch1, Register scratch2,
1538                              Label* gc_required, AllocationFlags flags) {
1539  DCHECK(object_size <= kMaxRegularHeapObjectSize);
1540  DCHECK((flags & ALLOCATION_FOLDED) == 0);
1541  if (!FLAG_inline_new) {
1542    if (emit_debug_code()) {
1543      // Trash the registers to simulate an allocation failure.
1544      LoadImmP(result, Operand(0x7091));
1545      LoadImmP(scratch1, Operand(0x7191));
1546      LoadImmP(scratch2, Operand(0x7291));
1547    }
1548    b(gc_required);
1549    return;
1550  }
1551
1552  DCHECK(!AreAliased(result, scratch1, scratch2, ip));
1553
1554  // Make object size into bytes.
1555  if ((flags & SIZE_IN_WORDS) != 0) {
1556    object_size *= kPointerSize;
1557  }
1558  DCHECK_EQ(0, static_cast<int>(object_size & kObjectAlignmentMask));
1559
1560  // Check relative positions of allocation top and limit addresses.
1561  ExternalReference allocation_top =
1562      AllocationUtils::GetAllocationTopReference(isolate(), flags);
1563  ExternalReference allocation_limit =
1564      AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1565
1566  intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
1567  intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
1568  DCHECK((limit - top) == kPointerSize);
1569
1570  // Set up allocation top address register.
1571  Register top_address = scratch1;
1572  Register result_end = scratch2;
1573  mov(top_address, Operand(allocation_top));
1574
1575  if ((flags & RESULT_CONTAINS_TOP) == 0) {
1576    // Load allocation top into result and allocation limit into ip.
1577    LoadP(result, MemOperand(top_address));
1578  } else {
1579    if (emit_debug_code()) {
1580      // Assert that result actually contains top on entry.
1581      CmpP(result, MemOperand(top_address));
1582      Check(eq, kUnexpectedAllocationTop);
1583    }
1584  }
1585
1586  if ((flags & DOUBLE_ALIGNMENT) != 0) {
1587// Align the next allocation. Storing the filler map without checking top is
1588// safe in new-space because the limit of the heap is aligned there.
1589#if V8_TARGET_ARCH_S390X
1590    STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
1591#else
1592    STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
1593    AndP(result_end, result, Operand(kDoubleAlignmentMask));
1594    Label aligned;
1595    beq(&aligned, Label::kNear);
1596    if ((flags & PRETENURE) != 0) {
1597      CmpLogicalP(result, MemOperand(top_address, limit - top));
1598      bge(gc_required);
1599    }
1600    mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
1601    StoreW(result_end, MemOperand(result));
1602    AddP(result, result, Operand(kDoubleSize / 2));
1603    bind(&aligned);
1604#endif
1605  }
1606
1607  AddP(result_end, result, Operand(object_size));
1608
1609  // Compare with allocation limit.
1610  CmpLogicalP(result_end, MemOperand(top_address, limit - top));
1611  bge(gc_required);
1612
1613  if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
1614    // The top pointer is not updated for allocation folding dominators.
1615    StoreP(result_end, MemOperand(top_address));
1616  }
1617
1618  if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
1619    // Prefetch the allocation_top's next cache line in advance to
1620    // help alleviate potential cache misses.
1621    // Mode 2 - Prefetch the data into a cache line for store access.
1622    pfd(static_cast<Condition>(2), MemOperand(result, 256));
1623  }
1624
1625  // Tag object.
1626  la(result, MemOperand(result, kHeapObjectTag));
1627}
1628
1629void MacroAssembler::Allocate(Register object_size, Register result,
1630                              Register result_end, Register scratch,
1631                              Label* gc_required, AllocationFlags flags) {
1632  DCHECK((flags & ALLOCATION_FOLDED) == 0);
1633  if (!FLAG_inline_new) {
1634    if (emit_debug_code()) {
1635      // Trash the registers to simulate an allocation failure.
1636      LoadImmP(result, Operand(0x7091));
1637      LoadImmP(scratch, Operand(0x7191));
1638      LoadImmP(result_end, Operand(0x7291));
1639    }
1640    b(gc_required);
1641    return;
1642  }
1643
1644  // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag
1645  // is not specified. Other registers must not overlap.
1646  DCHECK(!AreAliased(object_size, result, scratch, ip));
1647  DCHECK(!AreAliased(result_end, result, scratch, ip));
1648  DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end));
1649
1650  // Check relative positions of allocation top and limit addresses.
1651  ExternalReference allocation_top =
1652      AllocationUtils::GetAllocationTopReference(isolate(), flags);
1653  ExternalReference allocation_limit =
1654      AllocationUtils::GetAllocationLimitReference(isolate(), flags);
1655  intptr_t top = reinterpret_cast<intptr_t>(allocation_top.address());
1656  intptr_t limit = reinterpret_cast<intptr_t>(allocation_limit.address());
1657  DCHECK((limit - top) == kPointerSize);
1658
1659  // Set up allocation top address and allocation limit registers.
1660  Register top_address = scratch;
1661  mov(top_address, Operand(allocation_top));
1662
1663  if ((flags & RESULT_CONTAINS_TOP) == 0) {
1664    // Load allocation top into result
1665    LoadP(result, MemOperand(top_address));
1666  } else {
1667    if (emit_debug_code()) {
1668      // Assert that result actually contains top on entry.
1669      CmpP(result, MemOperand(top_address));
1670      Check(eq, kUnexpectedAllocationTop);
1671    }
1672  }
1673
1674  if ((flags & DOUBLE_ALIGNMENT) != 0) {
1675// Align the next allocation. Storing the filler map without checking top is
1676// safe in new-space because the limit of the heap is aligned there.
1677#if V8_TARGET_ARCH_S390X
1678    STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
1679#else
1680    STATIC_ASSERT(kPointerAlignment * 2 == kDoubleAlignment);
1681    AndP(result_end, result, Operand(kDoubleAlignmentMask));
1682    Label aligned;
1683    beq(&aligned, Label::kNear);
1684    if ((flags & PRETENURE) != 0) {
1685      CmpLogicalP(result, MemOperand(top_address, limit - top));
1686      bge(gc_required);
1687    }
1688    mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
1689    StoreW(result_end, MemOperand(result));
1690    AddP(result, result, Operand(kDoubleSize / 2));
1691    bind(&aligned);
1692#endif
1693  }
1694
1695  // Calculate new top and bail out if new space is exhausted. Use result
1696  // to calculate the new top. Object size may be in words so a shift is
1697  // required to get the number of bytes.
1698  if ((flags & SIZE_IN_WORDS) != 0) {
1699    ShiftLeftP(result_end, object_size, Operand(kPointerSizeLog2));
1700    AddP(result_end, result, result_end);
1701  } else {
1702    AddP(result_end, result, object_size);
1703  }
1704  CmpLogicalP(result_end, MemOperand(top_address, limit - top));
1705  bge(gc_required);
1706
1707  // Update allocation top. result temporarily holds the new top.
1708  if (emit_debug_code()) {
1709    AndP(r0, result_end, Operand(kObjectAlignmentMask));
1710    Check(eq, kUnalignedAllocationInNewSpace, cr0);
1711  }
1712  if ((flags & ALLOCATION_FOLDING_DOMINATOR) == 0) {
1713    // The top pointer is not updated for allocation folding dominators.
1714    StoreP(result_end, MemOperand(top_address));
1715  }
1716
1717  if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
1718    // Prefetch the allocation_top's next cache line in advance to
1719    // help alleviate potential cache misses.
1720    // Mode 2 - Prefetch the data into a cache line for store access.
1721    pfd(static_cast<Condition>(2), MemOperand(result, 256));
1722  }
1723
1724  // Tag object.
1725  la(result, MemOperand(result, kHeapObjectTag));
1726}
1727
1728void MacroAssembler::FastAllocate(Register object_size, Register result,
1729                                  Register result_end, Register scratch,
1730                                  AllocationFlags flags) {
1731  // |object_size| and |result_end| may overlap if the DOUBLE_ALIGNMENT flag
1732  // is not specified. Other registers must not overlap.
1733  DCHECK(!AreAliased(object_size, result, scratch, ip));
1734  DCHECK(!AreAliased(result_end, result, scratch, ip));
1735  DCHECK((flags & DOUBLE_ALIGNMENT) == 0 || !object_size.is(result_end));
1736
1737  ExternalReference allocation_top =
1738      AllocationUtils::GetAllocationTopReference(isolate(), flags);
1739
1740  Register top_address = scratch;
1741  mov(top_address, Operand(allocation_top));
1742  LoadP(result, MemOperand(top_address));
1743
1744  if ((flags & DOUBLE_ALIGNMENT) != 0) {
1745// Align the next allocation. Storing the filler map without checking top is
1746// safe in new-space because the limit of the heap is aligned there.
1747#if V8_TARGET_ARCH_S390X
1748    STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
1749#else
1750    DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1751    AndP(result_end, result, Operand(kDoubleAlignmentMask));
1752    Label aligned;
1753    beq(&aligned, Label::kNear);
1754    mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
1755    StoreW(result_end, MemOperand(result));
1756    AddP(result, result, Operand(kDoubleSize / 2));
1757    bind(&aligned);
1758#endif
1759  }
1760
1761  // Calculate new top using result. Object size may be in words so a shift is
1762  // required to get the number of bytes.
1763  if ((flags & SIZE_IN_WORDS) != 0) {
1764    ShiftLeftP(result_end, object_size, Operand(kPointerSizeLog2));
1765    AddP(result_end, result, result_end);
1766  } else {
1767    AddP(result_end, result, object_size);
1768  }
1769
1770  // Update allocation top. result temporarily holds the new top.
1771  if (emit_debug_code()) {
1772    AndP(r0, result_end, Operand(kObjectAlignmentMask));
1773    Check(eq, kUnalignedAllocationInNewSpace, cr0);
1774  }
1775  StoreP(result_end, MemOperand(top_address));
1776
1777  if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
1778    // Prefetch the allocation_top's next cache line in advance to
1779    // help alleviate potential cache misses.
1780    // Mode 2 - Prefetch the data into a cache line for store access.
1781    pfd(static_cast<Condition>(2), MemOperand(result, 256));
1782  }
1783
1784  // Tag object.
1785  la(result, MemOperand(result, kHeapObjectTag));
1786}
1787
1788void MacroAssembler::FastAllocate(int object_size, Register result,
1789                                  Register scratch1, Register scratch2,
1790                                  AllocationFlags flags) {
1791  DCHECK(object_size <= kMaxRegularHeapObjectSize);
1792  DCHECK(!AreAliased(result, scratch1, scratch2, ip));
1793
1794  // Make object size into bytes.
1795  if ((flags & SIZE_IN_WORDS) != 0) {
1796    object_size *= kPointerSize;
1797  }
1798  DCHECK_EQ(0, object_size & kObjectAlignmentMask);
1799
1800  ExternalReference allocation_top =
1801      AllocationUtils::GetAllocationTopReference(isolate(), flags);
1802
1803  // Set up allocation top address register.
1804  Register top_address = scratch1;
1805  Register result_end = scratch2;
1806  mov(top_address, Operand(allocation_top));
1807  LoadP(result, MemOperand(top_address));
1808
1809  if ((flags & DOUBLE_ALIGNMENT) != 0) {
1810// Align the next allocation. Storing the filler map without checking top is
1811// safe in new-space because the limit of the heap is aligned there.
1812#if V8_TARGET_ARCH_S390X
1813    STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
1814#else
1815    DCHECK(kPointerAlignment * 2 == kDoubleAlignment);
1816    AndP(result_end, result, Operand(kDoubleAlignmentMask));
1817    Label aligned;
1818    beq(&aligned, Label::kNear);
1819    mov(result_end, Operand(isolate()->factory()->one_pointer_filler_map()));
1820    StoreW(result_end, MemOperand(result));
1821    AddP(result, result, Operand(kDoubleSize / 2));
1822    bind(&aligned);
1823#endif
1824  }
1825
1826#if V8_TARGET_ARCH_S390X
1827  // Limit to 64-bit only, as double alignment check above may adjust
1828  // allocation top by an extra kDoubleSize/2.
1829  if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT) && is_int8(object_size)) {
1830    // Update allocation top.
1831    AddP(MemOperand(top_address), Operand(object_size));
1832  } else {
1833    // Calculate new top using result.
1834    AddP(result_end, result, Operand(object_size));
1835    // Update allocation top.
1836    StoreP(result_end, MemOperand(top_address));
1837  }
1838#else
1839  // Calculate new top using result.
1840  AddP(result_end, result, Operand(object_size));
1841  // Update allocation top.
1842  StoreP(result_end, MemOperand(top_address));
1843#endif
1844
1845  if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
1846    // Prefetch the allocation_top's next cache line in advance to
1847    // help alleviate potential cache misses.
1848    // Mode 2 - Prefetch the data into a cache line for store access.
1849    pfd(static_cast<Condition>(2), MemOperand(result, 256));
1850  }
1851
1852  // Tag object.
1853  la(result, MemOperand(result, kHeapObjectTag));
1854}
1855
1856void MacroAssembler::CompareObjectType(Register object, Register map,
1857                                       Register type_reg, InstanceType type) {
1858  const Register temp = type_reg.is(no_reg) ? r0 : type_reg;
1859
1860  LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset));
1861  CompareInstanceType(map, temp, type);
1862}
1863
1864void MacroAssembler::CompareInstanceType(Register map, Register type_reg,
1865                                         InstanceType type) {
1866  STATIC_ASSERT(Map::kInstanceTypeOffset < 4096);
1867  STATIC_ASSERT(LAST_TYPE < 256);
1868  LoadlB(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
1869  CmpP(type_reg, Operand(type));
1870}
1871
1872void MacroAssembler::CompareRoot(Register obj, Heap::RootListIndex index) {
1873  CmpP(obj, MemOperand(kRootRegister, index << kPointerSizeLog2));
1874}
1875
1876void MacroAssembler::SmiToDouble(DoubleRegister value, Register smi) {
1877  SmiUntag(ip, smi);
1878  ConvertIntToDouble(ip, value);
1879}
1880
1881void MacroAssembler::CompareMap(Register obj, Register scratch, Handle<Map> map,
1882                                Label* early_success) {
1883  LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
1884  CompareMap(obj, map, early_success);
1885}
1886
1887void MacroAssembler::CompareMap(Register obj_map, Handle<Map> map,
1888                                Label* early_success) {
1889  mov(r0, Operand(map));
1890  CmpP(r0, FieldMemOperand(obj_map, HeapObject::kMapOffset));
1891}
1892
1893void MacroAssembler::CheckMap(Register obj, Register scratch, Handle<Map> map,
1894                              Label* fail, SmiCheckType smi_check_type) {
1895  if (smi_check_type == DO_SMI_CHECK) {
1896    JumpIfSmi(obj, fail);
1897  }
1898
1899  Label success;
1900  CompareMap(obj, scratch, map, &success);
1901  bne(fail);
1902  bind(&success);
1903}
1904
1905void MacroAssembler::CheckMap(Register obj, Register scratch,
1906                              Heap::RootListIndex index, Label* fail,
1907                              SmiCheckType smi_check_type) {
1908  if (smi_check_type == DO_SMI_CHECK) {
1909    JumpIfSmi(obj, fail);
1910  }
1911  LoadP(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
1912  CompareRoot(scratch, index);
1913  bne(fail);
1914}
1915
1916void MacroAssembler::DispatchWeakMap(Register obj, Register scratch1,
1917                                     Register scratch2, Handle<WeakCell> cell,
1918                                     Handle<Code> success,
1919                                     SmiCheckType smi_check_type) {
1920  Label fail;
1921  if (smi_check_type == DO_SMI_CHECK) {
1922    JumpIfSmi(obj, &fail);
1923  }
1924  LoadP(scratch1, FieldMemOperand(obj, HeapObject::kMapOffset));
1925  CmpWeakValue(scratch1, cell, scratch2);
1926  Jump(success, RelocInfo::CODE_TARGET, eq);
1927  bind(&fail);
1928}
1929
1930void MacroAssembler::CmpWeakValue(Register value, Handle<WeakCell> cell,
1931                                  Register scratch, CRegister) {
1932  mov(scratch, Operand(cell));
1933  CmpP(value, FieldMemOperand(scratch, WeakCell::kValueOffset));
1934}
1935
1936void MacroAssembler::GetWeakValue(Register value, Handle<WeakCell> cell) {
1937  mov(value, Operand(cell));
1938  LoadP(value, FieldMemOperand(value, WeakCell::kValueOffset));
1939}
1940
1941void MacroAssembler::LoadWeakValue(Register value, Handle<WeakCell> cell,
1942                                   Label* miss) {
1943  GetWeakValue(value, cell);
1944  JumpIfSmi(value, miss);
1945}
1946
1947void MacroAssembler::GetMapConstructor(Register result, Register map,
1948                                       Register temp, Register temp2) {
1949  Label done, loop;
1950  LoadP(result, FieldMemOperand(map, Map::kConstructorOrBackPointerOffset));
1951  bind(&loop);
1952  JumpIfSmi(result, &done);
1953  CompareObjectType(result, temp, temp2, MAP_TYPE);
1954  bne(&done);
1955  LoadP(result, FieldMemOperand(result, Map::kConstructorOrBackPointerOffset));
1956  b(&loop);
1957  bind(&done);
1958}
1959
1960void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id,
1961                              Condition cond) {
1962  DCHECK(AllowThisStubCall(stub));  // Stub calls are not allowed in some stubs.
1963  Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id, cond);
1964}
1965
1966void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) {
1967  Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
1968}
1969
1970bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
1971  return has_frame_ || !stub->SometimesSetsUpAFrame();
1972}
1973
1974void MacroAssembler::TestDoubleIsInt32(DoubleRegister double_input,
1975                                       Register scratch1, Register scratch2,
1976                                       DoubleRegister double_scratch) {
1977  TryDoubleToInt32Exact(scratch1, double_input, scratch2, double_scratch);
1978}
1979
1980void MacroAssembler::TestDoubleIsMinusZero(DoubleRegister input,
1981                                           Register scratch1,
1982                                           Register scratch2) {
1983  lgdr(scratch1, input);
1984#if V8_TARGET_ARCH_S390X
1985  llihf(scratch2, Operand(0x80000000));  // scratch2 = 0x80000000_00000000
1986  CmpP(scratch1, scratch2);
1987#else
1988  Label done;
1989  CmpP(scratch1, Operand::Zero());
1990  bne(&done, Label::kNear);
1991
1992  srlg(scratch1, scratch1, Operand(32));
1993  CmpP(scratch1, Operand(HeapNumber::kSignMask));
1994  bind(&done);
1995#endif
1996}
1997
1998void MacroAssembler::TestDoubleSign(DoubleRegister input, Register scratch) {
1999  lgdr(scratch, input);
2000  cgfi(scratch, Operand::Zero());
2001}
2002
2003void MacroAssembler::TestHeapNumberSign(Register input, Register scratch) {
2004  LoadlW(scratch, FieldMemOperand(input, HeapNumber::kValueOffset +
2005                                             Register::kExponentOffset));
2006  Cmp32(scratch, Operand::Zero());
2007}
2008
2009void MacroAssembler::TryDoubleToInt32Exact(Register result,
2010                                           DoubleRegister double_input,
2011                                           Register scratch,
2012                                           DoubleRegister double_scratch) {
2013  Label done;
2014  DCHECK(!double_input.is(double_scratch));
2015
2016  ConvertDoubleToInt64(double_input,
2017#if !V8_TARGET_ARCH_S390X
2018                       scratch,
2019#endif
2020                       result, double_scratch);
2021
2022#if V8_TARGET_ARCH_S390X
2023  TestIfInt32(result, r0);
2024#else
2025  TestIfInt32(scratch, result, r0);
2026#endif
2027  bne(&done);
2028
2029  // convert back and compare
2030  lgdr(scratch, double_scratch);
2031  cdfbr(double_scratch, scratch);
2032  cdbr(double_scratch, double_input);
2033  bind(&done);
2034}
2035
2036void MacroAssembler::TryInt32Floor(Register result, DoubleRegister double_input,
2037                                   Register input_high, Register scratch,
2038                                   DoubleRegister double_scratch, Label* done,
2039                                   Label* exact) {
2040  DCHECK(!result.is(input_high));
2041  DCHECK(!double_input.is(double_scratch));
2042  Label exception;
2043
2044  // Move high word into input_high
2045  lay(sp, MemOperand(sp, -kDoubleSize));
2046  StoreDouble(double_input, MemOperand(sp));
2047  LoadlW(input_high, MemOperand(sp, Register::kExponentOffset));
2048  la(sp, MemOperand(sp, kDoubleSize));
2049
2050  // Test for NaN/Inf
2051  ExtractBitMask(result, input_high, HeapNumber::kExponentMask);
2052  CmpLogicalP(result, Operand(0x7ff));
2053  beq(&exception);
2054
2055  // Convert (rounding to -Inf)
2056  ConvertDoubleToInt64(double_input,
2057#if !V8_TARGET_ARCH_S390X
2058                       scratch,
2059#endif
2060                       result, double_scratch, kRoundToMinusInf);
2061
2062// Test for overflow
2063#if V8_TARGET_ARCH_S390X
2064  TestIfInt32(result, r0);
2065#else
2066  TestIfInt32(scratch, result, r0);
2067#endif
2068  bne(&exception);
2069
2070  // Test for exactness
2071  lgdr(scratch, double_scratch);
2072  cdfbr(double_scratch, scratch);
2073  cdbr(double_scratch, double_input);
2074  beq(exact);
2075  b(done);
2076
2077  bind(&exception);
2078}
2079
2080void MacroAssembler::TryInlineTruncateDoubleToI(Register result,
2081                                                DoubleRegister double_input,
2082                                                Label* done) {
2083  DoubleRegister double_scratch = kScratchDoubleReg;
2084#if !V8_TARGET_ARCH_S390X
2085  Register scratch = ip;
2086#endif
2087
2088  ConvertDoubleToInt64(double_input,
2089#if !V8_TARGET_ARCH_S390X
2090                       scratch,
2091#endif
2092                       result, double_scratch);
2093
2094// Test for overflow
2095#if V8_TARGET_ARCH_S390X
2096  TestIfInt32(result, r0);
2097#else
2098  TestIfInt32(scratch, result, r0);
2099#endif
2100  beq(done);
2101}
2102
2103void MacroAssembler::TruncateDoubleToI(Register result,
2104                                       DoubleRegister double_input) {
2105  Label done;
2106
2107  TryInlineTruncateDoubleToI(result, double_input, &done);
2108
2109  // If we fell through then inline version didn't succeed - call stub instead.
2110  push(r14);
2111  // Put input on stack.
2112  lay(sp, MemOperand(sp, -kDoubleSize));
2113  StoreDouble(double_input, MemOperand(sp));
2114
2115  DoubleToIStub stub(isolate(), sp, result, 0, true, true);
2116  CallStub(&stub);
2117
2118  la(sp, MemOperand(sp, kDoubleSize));
2119  pop(r14);
2120
2121  bind(&done);
2122}
2123
2124void MacroAssembler::TruncateHeapNumberToI(Register result, Register object) {
2125  Label done;
2126  DoubleRegister double_scratch = kScratchDoubleReg;
2127  DCHECK(!result.is(object));
2128
2129  LoadDouble(double_scratch, FieldMemOperand(object, HeapNumber::kValueOffset));
2130  TryInlineTruncateDoubleToI(result, double_scratch, &done);
2131
2132  // If we fell through then inline version didn't succeed - call stub instead.
2133  push(r14);
2134  DoubleToIStub stub(isolate(), object, result,
2135                     HeapNumber::kValueOffset - kHeapObjectTag, true, true);
2136  CallStub(&stub);
2137  pop(r14);
2138
2139  bind(&done);
2140}
2141
2142void MacroAssembler::TruncateNumberToI(Register object, Register result,
2143                                       Register heap_number_map,
2144                                       Register scratch1, Label* not_number) {
2145  Label done;
2146  DCHECK(!result.is(object));
2147
2148  UntagAndJumpIfSmi(result, object, &done);
2149  JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
2150  TruncateHeapNumberToI(result, object);
2151
2152  bind(&done);
2153}
2154
2155void MacroAssembler::GetLeastBitsFromSmi(Register dst, Register src,
2156                                         int num_least_bits) {
2157  if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
2158    // We rotate by kSmiShift amount, and extract the num_least_bits
2159    risbg(dst, src, Operand(64 - num_least_bits), Operand(63),
2160          Operand(64 - kSmiShift), true);
2161  } else {
2162    SmiUntag(dst, src);
2163    AndP(dst, Operand((1 << num_least_bits) - 1));
2164  }
2165}
2166
2167void MacroAssembler::GetLeastBitsFromInt32(Register dst, Register src,
2168                                           int num_least_bits) {
2169  AndP(dst, src, Operand((1 << num_least_bits) - 1));
2170}
2171
2172void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
2173                                 SaveFPRegsMode save_doubles) {
2174  // All parameters are on the stack.  r2 has the return value after call.
2175
2176  // If the expected number of arguments of the runtime function is
2177  // constant, we check that the actual number of arguments match the
2178  // expectation.
2179  CHECK(f->nargs < 0 || f->nargs == num_arguments);
2180
2181  // TODO(1236192): Most runtime routines don't need the number of
2182  // arguments passed in because it is constant. At some point we
2183  // should remove this need and make the runtime routine entry code
2184  // smarter.
2185  mov(r2, Operand(num_arguments));
2186  mov(r3, Operand(ExternalReference(f, isolate())));
2187  CEntryStub stub(isolate(),
2188#if V8_TARGET_ARCH_S390X
2189                  f->result_size,
2190#else
2191                  1,
2192#endif
2193                  save_doubles);
2194  CallStub(&stub);
2195}
2196
2197void MacroAssembler::CallExternalReference(const ExternalReference& ext,
2198                                           int num_arguments) {
2199  mov(r2, Operand(num_arguments));
2200  mov(r3, Operand(ext));
2201
2202  CEntryStub stub(isolate(), 1);
2203  CallStub(&stub);
2204}
2205
2206void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
2207  const Runtime::Function* function = Runtime::FunctionForId(fid);
2208  DCHECK_EQ(1, function->result_size);
2209  if (function->nargs >= 0) {
2210    mov(r2, Operand(function->nargs));
2211  }
2212  JumpToExternalReference(ExternalReference(fid, isolate()));
2213}
2214
2215void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
2216                                             bool builtin_exit_frame) {
2217  mov(r3, Operand(builtin));
2218  CEntryStub stub(isolate(), 1, kDontSaveFPRegs, kArgvOnStack,
2219                  builtin_exit_frame);
2220  Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
2221}
2222
2223void MacroAssembler::SetCounter(StatsCounter* counter, int value,
2224                                Register scratch1, Register scratch2) {
2225  if (FLAG_native_code_counters && counter->Enabled()) {
2226    mov(scratch1, Operand(value));
2227    mov(scratch2, Operand(ExternalReference(counter)));
2228    StoreW(scratch1, MemOperand(scratch2));
2229  }
2230}
2231
2232void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
2233                                      Register scratch1, Register scratch2) {
2234  DCHECK(value > 0 && is_int8(value));
2235  if (FLAG_native_code_counters && counter->Enabled()) {
2236    mov(scratch1, Operand(ExternalReference(counter)));
2237    // @TODO(john.yan): can be optimized by asi()
2238    LoadW(scratch2, MemOperand(scratch1));
2239    AddP(scratch2, Operand(value));
2240    StoreW(scratch2, MemOperand(scratch1));
2241  }
2242}
2243
2244void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
2245                                      Register scratch1, Register scratch2) {
2246  DCHECK(value > 0 && is_int8(value));
2247  if (FLAG_native_code_counters && counter->Enabled()) {
2248    mov(scratch1, Operand(ExternalReference(counter)));
2249    // @TODO(john.yan): can be optimized by asi()
2250    LoadW(scratch2, MemOperand(scratch1));
2251    AddP(scratch2, Operand(-value));
2252    StoreW(scratch2, MemOperand(scratch1));
2253  }
2254}
2255
2256void MacroAssembler::Assert(Condition cond, BailoutReason reason,
2257                            CRegister cr) {
2258  if (emit_debug_code()) Check(cond, reason, cr);
2259}
2260
2261void MacroAssembler::AssertFastElements(Register elements) {
2262  if (emit_debug_code()) {
2263    DCHECK(!elements.is(r0));
2264    Label ok;
2265    push(elements);
2266    LoadP(elements, FieldMemOperand(elements, HeapObject::kMapOffset));
2267    CompareRoot(elements, Heap::kFixedArrayMapRootIndex);
2268    beq(&ok, Label::kNear);
2269    CompareRoot(elements, Heap::kFixedDoubleArrayMapRootIndex);
2270    beq(&ok, Label::kNear);
2271    CompareRoot(elements, Heap::kFixedCOWArrayMapRootIndex);
2272    beq(&ok, Label::kNear);
2273    Abort(kJSObjectWithFastElementsMapHasSlowElements);
2274    bind(&ok);
2275    pop(elements);
2276  }
2277}
2278
2279void MacroAssembler::Check(Condition cond, BailoutReason reason, CRegister cr) {
2280  Label L;
2281  b(cond, &L);
2282  Abort(reason);
2283  // will not return here
2284  bind(&L);
2285}
2286
2287void MacroAssembler::Abort(BailoutReason reason) {
2288  Label abort_start;
2289  bind(&abort_start);
2290#ifdef DEBUG
2291  const char* msg = GetBailoutReason(reason);
2292  if (msg != NULL) {
2293    RecordComment("Abort message: ");
2294    RecordComment(msg);
2295  }
2296
2297  if (FLAG_trap_on_abort) {
2298    stop(msg);
2299    return;
2300  }
2301#endif
2302
2303  // Check if Abort() has already been initialized.
2304  DCHECK(isolate()->builtins()->Abort()->IsHeapObject());
2305
2306  LoadSmiLiteral(r3, Smi::FromInt(static_cast<int>(reason)));
2307
2308  // Disable stub call restrictions to always allow calls to abort.
2309  if (!has_frame_) {
2310    // We don't actually want to generate a pile of code for this, so just
2311    // claim there is a stack frame, without generating one.
2312    FrameScope scope(this, StackFrame::NONE);
2313    Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET);
2314  } else {
2315    Call(isolate()->builtins()->Abort(), RelocInfo::CODE_TARGET);
2316  }
2317  // will not return here
2318}
2319
2320void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
2321  if (context_chain_length > 0) {
2322    // Move up the chain of contexts to the context containing the slot.
2323    LoadP(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2324    for (int i = 1; i < context_chain_length; i++) {
2325      LoadP(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2326    }
2327  } else {
2328    // Slot is in the current function context.  Move it into the
2329    // destination register in case we store into it (the write barrier
2330    // cannot be allowed to destroy the context in esi).
2331    LoadRR(dst, cp);
2332  }
2333}
2334
2335void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
2336  LoadP(dst, NativeContextMemOperand());
2337  LoadP(dst, ContextMemOperand(dst, index));
2338}
2339
2340void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
2341                                                  Register map,
2342                                                  Register scratch) {
2343  // Load the initial map. The global functions all have initial maps.
2344  LoadP(map,
2345        FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
2346  if (emit_debug_code()) {
2347    Label ok, fail;
2348    CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK);
2349    b(&ok);
2350    bind(&fail);
2351    Abort(kGlobalFunctionsMustHaveInitialMap);
2352    bind(&ok);
2353  }
2354}
2355
2356void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
2357    Register reg, Register scratch, Label* not_power_of_two_or_zero) {
2358  SubP(scratch, reg, Operand(1));
2359  CmpP(scratch, Operand::Zero());
2360  blt(not_power_of_two_or_zero);
2361  AndP(r0, reg, scratch /*, SetRC*/);  // Should be okay to remove rc
2362  bne(not_power_of_two_or_zero /*, cr0*/);
2363}
2364
2365void MacroAssembler::JumpIfNotPowerOfTwoOrZeroAndNeg(Register reg,
2366                                                     Register scratch,
2367                                                     Label* zero_and_neg,
2368                                                     Label* not_power_of_two) {
2369  SubP(scratch, reg, Operand(1));
2370  CmpP(scratch, Operand::Zero());
2371  blt(zero_and_neg);
2372  AndP(r0, reg, scratch /*, SetRC*/);  // Should be okay to remove rc
2373  bne(not_power_of_two /*, cr0*/);
2374}
2375
2376#if !V8_TARGET_ARCH_S390X
2377void MacroAssembler::SmiTagCheckOverflow(Register reg, Register overflow) {
2378  DCHECK(!reg.is(overflow));
2379  LoadRR(overflow, reg);  // Save original value.
2380  SmiTag(reg);
2381  XorP(overflow, overflow, reg);  // Overflow if (value ^ 2 * value) < 0.
2382  LoadAndTestRR(overflow, overflow);
2383}
2384
2385void MacroAssembler::SmiTagCheckOverflow(Register dst, Register src,
2386                                         Register overflow) {
2387  if (dst.is(src)) {
2388    // Fall back to slower case.
2389    SmiTagCheckOverflow(dst, overflow);
2390  } else {
2391    DCHECK(!dst.is(src));
2392    DCHECK(!dst.is(overflow));
2393    DCHECK(!src.is(overflow));
2394    SmiTag(dst, src);
2395    XorP(overflow, dst, src);  // Overflow if (value ^ 2 * value) < 0.
2396    LoadAndTestRR(overflow, overflow);
2397  }
2398}
2399#endif
2400
2401void MacroAssembler::JumpIfNotBothSmi(Register reg1, Register reg2,
2402                                      Label* on_not_both_smi) {
2403  STATIC_ASSERT(kSmiTag == 0);
2404  OrP(r0, reg1, reg2 /*, LeaveRC*/);  // should be okay to remove LeaveRC
2405  JumpIfNotSmi(r0, on_not_both_smi);
2406}
2407
2408void MacroAssembler::UntagAndJumpIfSmi(Register dst, Register src,
2409                                       Label* smi_case) {
2410  STATIC_ASSERT(kSmiTag == 0);
2411  STATIC_ASSERT(kSmiTagSize == 1);
2412  // this won't work if src == dst
2413  DCHECK(src.code() != dst.code());
2414  SmiUntag(dst, src);
2415  TestIfSmi(src);
2416  beq(smi_case);
2417}
2418
2419void MacroAssembler::JumpIfEitherSmi(Register reg1, Register reg2,
2420                                     Label* on_either_smi) {
2421  STATIC_ASSERT(kSmiTag == 0);
2422  JumpIfSmi(reg1, on_either_smi);
2423  JumpIfSmi(reg2, on_either_smi);
2424}
2425
2426void MacroAssembler::AssertNotNumber(Register object) {
2427  if (emit_debug_code()) {
2428    STATIC_ASSERT(kSmiTag == 0);
2429    TestIfSmi(object);
2430    Check(ne, kOperandIsANumber, cr0);
2431    push(object);
2432    CompareObjectType(object, object, object, HEAP_NUMBER_TYPE);
2433    pop(object);
2434    Check(ne, kOperandIsANumber);
2435  }
2436}
2437
2438void MacroAssembler::AssertNotSmi(Register object) {
2439  if (emit_debug_code()) {
2440    STATIC_ASSERT(kSmiTag == 0);
2441    TestIfSmi(object);
2442    Check(ne, kOperandIsASmi, cr0);
2443  }
2444}
2445
2446void MacroAssembler::AssertSmi(Register object) {
2447  if (emit_debug_code()) {
2448    STATIC_ASSERT(kSmiTag == 0);
2449    TestIfSmi(object);
2450    Check(eq, kOperandIsNotSmi, cr0);
2451  }
2452}
2453
2454void MacroAssembler::AssertString(Register object) {
2455  if (emit_debug_code()) {
2456    STATIC_ASSERT(kSmiTag == 0);
2457    TestIfSmi(object);
2458    Check(ne, kOperandIsASmiAndNotAString, cr0);
2459    push(object);
2460    LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset));
2461    CompareInstanceType(object, object, FIRST_NONSTRING_TYPE);
2462    pop(object);
2463    Check(lt, kOperandIsNotAString);
2464  }
2465}
2466
2467void MacroAssembler::AssertName(Register object) {
2468  if (emit_debug_code()) {
2469    STATIC_ASSERT(kSmiTag == 0);
2470    TestIfSmi(object);
2471    Check(ne, kOperandIsASmiAndNotAName, cr0);
2472    push(object);
2473    LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset));
2474    CompareInstanceType(object, object, LAST_NAME_TYPE);
2475    pop(object);
2476    Check(le, kOperandIsNotAName);
2477  }
2478}
2479
2480void MacroAssembler::AssertFunction(Register object) {
2481  if (emit_debug_code()) {
2482    STATIC_ASSERT(kSmiTag == 0);
2483    TestIfSmi(object);
2484    Check(ne, kOperandIsASmiAndNotAFunction, cr0);
2485    push(object);
2486    CompareObjectType(object, object, object, JS_FUNCTION_TYPE);
2487    pop(object);
2488    Check(eq, kOperandIsNotAFunction);
2489  }
2490}
2491
2492void MacroAssembler::AssertBoundFunction(Register object) {
2493  if (emit_debug_code()) {
2494    STATIC_ASSERT(kSmiTag == 0);
2495    TestIfSmi(object);
2496    Check(ne, kOperandIsASmiAndNotABoundFunction, cr0);
2497    push(object);
2498    CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE);
2499    pop(object);
2500    Check(eq, kOperandIsNotABoundFunction);
2501  }
2502}
2503
2504void MacroAssembler::AssertGeneratorObject(Register object) {
2505  if (emit_debug_code()) {
2506    STATIC_ASSERT(kSmiTag == 0);
2507    TestIfSmi(object);
2508    Check(ne, kOperandIsASmiAndNotAGeneratorObject, cr0);
2509    push(object);
2510    CompareObjectType(object, object, object, JS_GENERATOR_OBJECT_TYPE);
2511    pop(object);
2512    Check(eq, kOperandIsNotAGeneratorObject);
2513  }
2514}
2515
2516void MacroAssembler::AssertReceiver(Register object) {
2517  if (emit_debug_code()) {
2518    STATIC_ASSERT(kSmiTag == 0);
2519    TestIfSmi(object);
2520    Check(ne, kOperandIsASmiAndNotAReceiver, cr0);
2521    push(object);
2522    STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
2523    CompareObjectType(object, object, object, FIRST_JS_RECEIVER_TYPE);
2524    pop(object);
2525    Check(ge, kOperandIsNotAReceiver);
2526  }
2527}
2528
2529void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
2530                                                     Register scratch) {
2531  if (emit_debug_code()) {
2532    Label done_checking;
2533    AssertNotSmi(object);
2534    CompareRoot(object, Heap::kUndefinedValueRootIndex);
2535    beq(&done_checking, Label::kNear);
2536    LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
2537    CompareRoot(scratch, Heap::kAllocationSiteMapRootIndex);
2538    Assert(eq, kExpectedUndefinedOrCell);
2539    bind(&done_checking);
2540  }
2541}
2542
2543void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) {
2544  if (emit_debug_code()) {
2545    CompareRoot(reg, index);
2546    Check(eq, kHeapNumberMapRegisterClobbered);
2547  }
2548}
2549
2550void MacroAssembler::JumpIfNotHeapNumber(Register object,
2551                                         Register heap_number_map,
2552                                         Register scratch,
2553                                         Label* on_not_heap_number) {
2554  LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
2555  AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
2556  CmpP(scratch, heap_number_map);
2557  bne(on_not_heap_number);
2558}
2559
2560void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings(
2561    Register first, Register second, Register scratch1, Register scratch2,
2562    Label* failure) {
2563  // Test that both first and second are sequential one-byte strings.
2564  // Assume that they are non-smis.
2565  LoadP(scratch1, FieldMemOperand(first, HeapObject::kMapOffset));
2566  LoadP(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
2567  LoadlB(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
2568  LoadlB(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
2569
2570  JumpIfBothInstanceTypesAreNotSequentialOneByte(scratch1, scratch2, scratch1,
2571                                                 scratch2, failure);
2572}
2573
2574void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register first,
2575                                                           Register second,
2576                                                           Register scratch1,
2577                                                           Register scratch2,
2578                                                           Label* failure) {
2579  // Check that neither is a smi.
2580  AndP(scratch1, first, second);
2581  JumpIfSmi(scratch1, failure);
2582  JumpIfNonSmisNotBothSequentialOneByteStrings(first, second, scratch1,
2583                                               scratch2, failure);
2584}
2585
2586void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg,
2587                                                     Label* not_unique_name) {
2588  STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
2589  Label succeed;
2590  AndP(r0, reg, Operand(kIsNotStringMask | kIsNotInternalizedMask));
2591  beq(&succeed, Label::kNear);
2592  CmpP(reg, Operand(SYMBOL_TYPE));
2593  bne(not_unique_name);
2594
2595  bind(&succeed);
2596}
2597
2598// Allocates a heap number or jumps to the need_gc label if the young space
2599// is full and a scavenge is needed.
2600void MacroAssembler::AllocateHeapNumber(Register result, Register scratch1,
2601                                        Register scratch2,
2602                                        Register heap_number_map,
2603                                        Label* gc_required,
2604                                        MutableMode mode) {
2605  // Allocate an object in the heap for the heap number and tag it as a heap
2606  // object.
2607  Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
2608           NO_ALLOCATION_FLAGS);
2609
2610  Heap::RootListIndex map_index = mode == MUTABLE
2611                                      ? Heap::kMutableHeapNumberMapRootIndex
2612                                      : Heap::kHeapNumberMapRootIndex;
2613  AssertIsRoot(heap_number_map, map_index);
2614
2615  // Store heap number map in the allocated object.
2616    StoreP(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
2617}
2618
2619void MacroAssembler::AllocateHeapNumberWithValue(
2620    Register result, DoubleRegister value, Register scratch1, Register scratch2,
2621    Register heap_number_map, Label* gc_required) {
2622  AllocateHeapNumber(result, scratch1, scratch2, heap_number_map, gc_required);
2623  StoreDouble(value, FieldMemOperand(result, HeapNumber::kValueOffset));
2624}
2625
2626void MacroAssembler::AllocateJSValue(Register result, Register constructor,
2627                                     Register value, Register scratch1,
2628                                     Register scratch2, Label* gc_required) {
2629  DCHECK(!result.is(constructor));
2630  DCHECK(!result.is(scratch1));
2631  DCHECK(!result.is(scratch2));
2632  DCHECK(!result.is(value));
2633
2634  // Allocate JSValue in new space.
2635  Allocate(JSValue::kSize, result, scratch1, scratch2, gc_required,
2636           NO_ALLOCATION_FLAGS);
2637
2638  // Initialize the JSValue.
2639  LoadGlobalFunctionInitialMap(constructor, scratch1, scratch2);
2640  StoreP(scratch1, FieldMemOperand(result, HeapObject::kMapOffset), r0);
2641  LoadRoot(scratch1, Heap::kEmptyFixedArrayRootIndex);
2642  StoreP(scratch1, FieldMemOperand(result, JSObject::kPropertiesOffset), r0);
2643  StoreP(scratch1, FieldMemOperand(result, JSObject::kElementsOffset), r0);
2644  StoreP(value, FieldMemOperand(result, JSValue::kValueOffset), r0);
2645  STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize);
2646}
2647
2648void MacroAssembler::InitializeNFieldsWithFiller(Register current_address,
2649                                                 Register count,
2650                                                 Register filler) {
2651  Label loop;
2652  bind(&loop);
2653  StoreP(filler, MemOperand(current_address));
2654  AddP(current_address, current_address, Operand(kPointerSize));
2655  BranchOnCount(r1, &loop);
2656}
2657
2658void MacroAssembler::InitializeFieldsWithFiller(Register current_address,
2659                                                Register end_address,
2660                                                Register filler) {
2661  Label done;
2662  DCHECK(!filler.is(r1));
2663  DCHECK(!current_address.is(r1));
2664  DCHECK(!end_address.is(r1));
2665  SubP(r1, end_address, current_address /*, LeaveOE, SetRC*/);
2666  beq(&done, Label::kNear);
2667  ShiftRightP(r1, r1, Operand(kPointerSizeLog2));
2668  InitializeNFieldsWithFiller(current_address, r1, filler);
2669  bind(&done);
2670}
2671
2672void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte(
2673    Register first, Register second, Register scratch1, Register scratch2,
2674    Label* failure) {
2675  const int kFlatOneByteStringMask =
2676      kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
2677  const int kFlatOneByteStringTag =
2678      kStringTag | kOneByteStringTag | kSeqStringTag;
2679  if (!scratch1.is(first)) LoadRR(scratch1, first);
2680  if (!scratch2.is(second)) LoadRR(scratch2, second);
2681  nilf(scratch1, Operand(kFlatOneByteStringMask));
2682  CmpP(scratch1, Operand(kFlatOneByteStringTag));
2683  bne(failure);
2684  nilf(scratch2, Operand(kFlatOneByteStringMask));
2685  CmpP(scratch2, Operand(kFlatOneByteStringTag));
2686  bne(failure);
2687}
2688
2689static const int kRegisterPassedArguments = 5;
2690
2691int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments,
2692                                              int num_double_arguments) {
2693  int stack_passed_words = 0;
2694  if (num_double_arguments > DoubleRegister::kNumRegisters) {
2695    stack_passed_words +=
2696        2 * (num_double_arguments - DoubleRegister::kNumRegisters);
2697  }
2698  // Up to five simple arguments are passed in registers r2..r6
2699  if (num_reg_arguments > kRegisterPassedArguments) {
2700    stack_passed_words += num_reg_arguments - kRegisterPassedArguments;
2701  }
2702  return stack_passed_words;
2703}
2704
2705void MacroAssembler::EmitSeqStringSetCharCheck(Register string, Register index,
2706                                               Register value,
2707                                               uint32_t encoding_mask) {
2708  Label is_object;
2709  TestIfSmi(string);
2710  Check(ne, kNonObject, cr0);
2711
2712  LoadP(ip, FieldMemOperand(string, HeapObject::kMapOffset));
2713  LoadlB(ip, FieldMemOperand(ip, Map::kInstanceTypeOffset));
2714
2715  AndP(ip, Operand(kStringRepresentationMask | kStringEncodingMask));
2716  CmpP(ip, Operand(encoding_mask));
2717  Check(eq, kUnexpectedStringType);
2718
2719// The index is assumed to be untagged coming in, tag it to compare with the
2720// string length without using a temp register, it is restored at the end of
2721// this function.
2722#if !V8_TARGET_ARCH_S390X
2723  Label index_tag_ok, index_tag_bad;
2724  JumpIfNotSmiCandidate(index, r0, &index_tag_bad);
2725#endif
2726  SmiTag(index, index);
2727#if !V8_TARGET_ARCH_S390X
2728  b(&index_tag_ok);
2729  bind(&index_tag_bad);
2730  Abort(kIndexIsTooLarge);
2731  bind(&index_tag_ok);
2732#endif
2733
2734  LoadP(ip, FieldMemOperand(string, String::kLengthOffset));
2735  CmpP(index, ip);
2736  Check(lt, kIndexIsTooLarge);
2737
2738  DCHECK(Smi::kZero == 0);
2739  CmpP(index, Operand::Zero());
2740  Check(ge, kIndexIsNegative);
2741
2742  SmiUntag(index, index);
2743}
2744
2745void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
2746                                          int num_double_arguments,
2747                                          Register scratch) {
2748  int frame_alignment = ActivationFrameAlignment();
2749  int stack_passed_arguments =
2750      CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
2751  int stack_space = kNumRequiredStackFrameSlots;
2752  if (frame_alignment > kPointerSize) {
2753    // Make stack end at alignment and make room for stack arguments
2754    // -- preserving original value of sp.
2755    LoadRR(scratch, sp);
2756    lay(sp, MemOperand(sp, -(stack_passed_arguments + 1) * kPointerSize));
2757    DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
2758    ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
2759    StoreP(scratch, MemOperand(sp, (stack_passed_arguments)*kPointerSize));
2760  } else {
2761    stack_space += stack_passed_arguments;
2762  }
2763  lay(sp, MemOperand(sp, -(stack_space)*kPointerSize));
2764}
2765
2766void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
2767                                          Register scratch) {
2768  PrepareCallCFunction(num_reg_arguments, 0, scratch);
2769}
2770
2771void MacroAssembler::MovToFloatParameter(DoubleRegister src) { Move(d0, src); }
2772
2773void MacroAssembler::MovToFloatResult(DoubleRegister src) { Move(d0, src); }
2774
2775void MacroAssembler::MovToFloatParameters(DoubleRegister src1,
2776                                          DoubleRegister src2) {
2777  if (src2.is(d0)) {
2778    DCHECK(!src1.is(d2));
2779    Move(d2, src2);
2780    Move(d0, src1);
2781  } else {
2782    Move(d0, src1);
2783    Move(d2, src2);
2784  }
2785}
2786
2787void MacroAssembler::CallCFunction(ExternalReference function,
2788                                   int num_reg_arguments,
2789                                   int num_double_arguments) {
2790  mov(ip, Operand(function));
2791  CallCFunctionHelper(ip, num_reg_arguments, num_double_arguments);
2792}
2793
2794void MacroAssembler::CallCFunction(Register function, int num_reg_arguments,
2795                                   int num_double_arguments) {
2796  CallCFunctionHelper(function, num_reg_arguments, num_double_arguments);
2797}
2798
2799void MacroAssembler::CallCFunction(ExternalReference function,
2800                                   int num_arguments) {
2801  CallCFunction(function, num_arguments, 0);
2802}
2803
2804void MacroAssembler::CallCFunction(Register function, int num_arguments) {
2805  CallCFunction(function, num_arguments, 0);
2806}
2807
2808void MacroAssembler::CallCFunctionHelper(Register function,
2809                                         int num_reg_arguments,
2810                                         int num_double_arguments) {
2811  DCHECK(has_frame());
2812
2813  // Just call directly. The function called cannot cause a GC, or
2814  // allow preemption, so the return address in the link register
2815  // stays correct.
2816  Register dest = function;
2817  if (ABI_CALL_VIA_IP) {
2818    Move(ip, function);
2819    dest = ip;
2820  }
2821
2822  Call(dest);
2823
2824  int stack_passed_arguments =
2825      CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
2826  int stack_space = kNumRequiredStackFrameSlots + stack_passed_arguments;
2827  if (ActivationFrameAlignment() > kPointerSize) {
2828    // Load the original stack pointer (pre-alignment) from the stack
2829    LoadP(sp, MemOperand(sp, stack_space * kPointerSize));
2830  } else {
2831    la(sp, MemOperand(sp, stack_space * kPointerSize));
2832  }
2833}
2834
2835void MacroAssembler::CheckPageFlag(
2836    Register object,
2837    Register scratch,  // scratch may be same register as object
2838    int mask, Condition cc, Label* condition_met) {
2839  DCHECK(cc == ne || cc == eq);
2840  ClearRightImm(scratch, object, Operand(kPageSizeBits));
2841
2842  if (base::bits::IsPowerOfTwo32(mask)) {
2843    // If it's a power of two, we can use Test-Under-Mask Memory-Imm form
2844    // which allows testing of a single byte in memory.
2845    int32_t byte_offset = 4;
2846    uint32_t shifted_mask = mask;
2847    // Determine the byte offset to be tested
2848    if (mask <= 0x80) {
2849      byte_offset = kPointerSize - 1;
2850    } else if (mask < 0x8000) {
2851      byte_offset = kPointerSize - 2;
2852      shifted_mask = mask >> 8;
2853    } else if (mask < 0x800000) {
2854      byte_offset = kPointerSize - 3;
2855      shifted_mask = mask >> 16;
2856    } else {
2857      byte_offset = kPointerSize - 4;
2858      shifted_mask = mask >> 24;
2859    }
2860#if V8_TARGET_LITTLE_ENDIAN
2861    // Reverse the byte_offset if emulating on little endian platform
2862    byte_offset = kPointerSize - byte_offset - 1;
2863#endif
2864    tm(MemOperand(scratch, MemoryChunk::kFlagsOffset + byte_offset),
2865       Operand(shifted_mask));
2866  } else {
2867    LoadP(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
2868    AndP(r0, scratch, Operand(mask));
2869  }
2870  // Should be okay to remove rc
2871
2872  if (cc == ne) {
2873    bne(condition_met);
2874  }
2875  if (cc == eq) {
2876    beq(condition_met);
2877  }
2878}
2879
2880void MacroAssembler::JumpIfBlack(Register object, Register scratch0,
2881                                 Register scratch1, Label* on_black) {
2882  HasColor(object, scratch0, scratch1, on_black, 1, 1);  // kBlackBitPattern.
2883  DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
2884}
2885
2886void MacroAssembler::HasColor(Register object, Register bitmap_scratch,
2887                              Register mask_scratch, Label* has_color,
2888                              int first_bit, int second_bit) {
2889  DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, no_reg));
2890
2891  GetMarkBits(object, bitmap_scratch, mask_scratch);
2892
2893  Label other_color, word_boundary;
2894  LoadlW(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
2895  // Test the first bit
2896  AndP(r0, ip, mask_scratch /*, SetRC*/);  // Should be okay to remove rc
2897  b(first_bit == 1 ? eq : ne, &other_color, Label::kNear);
2898  // Shift left 1
2899  // May need to load the next cell
2900  sll(mask_scratch, Operand(1) /*, SetRC*/);
2901  LoadAndTest32(mask_scratch, mask_scratch);
2902  beq(&word_boundary, Label::kNear);
2903  // Test the second bit
2904  AndP(r0, ip, mask_scratch /*, SetRC*/);  // Should be okay to remove rc
2905  b(second_bit == 1 ? ne : eq, has_color);
2906  b(&other_color, Label::kNear);
2907
2908  bind(&word_boundary);
2909  LoadlW(ip, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize + kIntSize));
2910  AndP(r0, ip, Operand(1));
2911  b(second_bit == 1 ? ne : eq, has_color);
2912  bind(&other_color);
2913}
2914
2915void MacroAssembler::GetMarkBits(Register addr_reg, Register bitmap_reg,
2916                                 Register mask_reg) {
2917  DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg));
2918  LoadRR(bitmap_reg, addr_reg);
2919  nilf(bitmap_reg, Operand(~Page::kPageAlignmentMask));
2920  const int kLowBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2;
2921  ExtractBitRange(mask_reg, addr_reg, kLowBits - 1, kPointerSizeLog2);
2922  ExtractBitRange(ip, addr_reg, kPageSizeBits - 1, kLowBits);
2923  ShiftLeftP(ip, ip, Operand(Bitmap::kBytesPerCellLog2));
2924  AddP(bitmap_reg, ip);
2925  LoadRR(ip, mask_reg);  // Have to do some funky reg shuffling as
2926                         // 31-bit shift left clobbers on s390.
2927  LoadImmP(mask_reg, Operand(1));
2928  ShiftLeftP(mask_reg, mask_reg, ip);
2929}
2930
2931void MacroAssembler::JumpIfWhite(Register value, Register bitmap_scratch,
2932                                 Register mask_scratch, Register load_scratch,
2933                                 Label* value_is_white) {
2934  DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, ip));
2935  GetMarkBits(value, bitmap_scratch, mask_scratch);
2936
2937  // If the value is black or grey we don't need to do anything.
2938  DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
2939  DCHECK(strcmp(Marking::kBlackBitPattern, "11") == 0);
2940  DCHECK(strcmp(Marking::kGreyBitPattern, "10") == 0);
2941  DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
2942
2943  // Since both black and grey have a 1 in the first position and white does
2944  // not have a 1 there we only need to check one bit.
2945  LoadlW(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
2946  LoadRR(r0, load_scratch);
2947  AndP(r0, mask_scratch);
2948  beq(value_is_white);
2949}
2950
2951// Saturate a value into 8-bit unsigned integer
2952//   if input_value < 0, output_value is 0
2953//   if input_value > 255, output_value is 255
2954//   otherwise output_value is the input_value
2955void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) {
2956  int satval = (1 << 8) - 1;
2957
2958  Label done, negative_label, overflow_label;
2959  CmpP(input_reg, Operand::Zero());
2960  blt(&negative_label);
2961
2962  CmpP(input_reg, Operand(satval));
2963  bgt(&overflow_label);
2964  if (!output_reg.is(input_reg)) {
2965    LoadRR(output_reg, input_reg);
2966  }
2967  b(&done);
2968
2969  bind(&negative_label);
2970  LoadImmP(output_reg, Operand::Zero());  // set to 0 if negative
2971  b(&done);
2972
2973  bind(&overflow_label);  // set to satval if > satval
2974  LoadImmP(output_reg, Operand(satval));
2975
2976  bind(&done);
2977}
2978
2979void MacroAssembler::ClampDoubleToUint8(Register result_reg,
2980                                        DoubleRegister input_reg,
2981                                        DoubleRegister double_scratch) {
2982  Label above_zero;
2983  Label done;
2984  Label in_bounds;
2985
2986  LoadDoubleLiteral(double_scratch, 0.0, result_reg);
2987  cdbr(input_reg, double_scratch);
2988  bgt(&above_zero, Label::kNear);
2989
2990  // Double value is less than zero, NaN or Inf, return 0.
2991  LoadIntLiteral(result_reg, 0);
2992  b(&done, Label::kNear);
2993
2994  // Double value is >= 255, return 255.
2995  bind(&above_zero);
2996  LoadDoubleLiteral(double_scratch, 255.0, result_reg);
2997  cdbr(input_reg, double_scratch);
2998  ble(&in_bounds, Label::kNear);
2999  LoadIntLiteral(result_reg, 255);
3000  b(&done, Label::kNear);
3001
3002  // In 0-255 range, round and truncate.
3003  bind(&in_bounds);
3004
3005  // round to nearest (default rounding mode)
3006  cfdbr(ROUND_TO_NEAREST_WITH_TIES_TO_EVEN, result_reg, input_reg);
3007  bind(&done);
3008}
3009
3010void MacroAssembler::LoadInstanceDescriptors(Register map,
3011                                             Register descriptors) {
3012  LoadP(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
3013}
3014
3015void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
3016  LoadlW(dst, FieldMemOperand(map, Map::kBitField3Offset));
3017  DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
3018}
3019
3020void MacroAssembler::EnumLength(Register dst, Register map) {
3021  STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
3022  LoadW(dst, FieldMemOperand(map, Map::kBitField3Offset));
3023  And(dst, Operand(Map::EnumLengthBits::kMask));
3024  SmiTag(dst);
3025}
3026
3027void MacroAssembler::LoadAccessor(Register dst, Register holder,
3028                                  int accessor_index,
3029                                  AccessorComponent accessor) {
3030  LoadP(dst, FieldMemOperand(holder, HeapObject::kMapOffset));
3031  LoadInstanceDescriptors(dst, dst);
3032  LoadP(dst,
3033        FieldMemOperand(dst, DescriptorArray::GetValueOffset(accessor_index)));
3034  const int getterOffset = AccessorPair::kGetterOffset;
3035  const int setterOffset = AccessorPair::kSetterOffset;
3036  int offset = ((accessor == ACCESSOR_GETTER) ? getterOffset : setterOffset);
3037  LoadP(dst, FieldMemOperand(dst, offset));
3038}
3039
3040void MacroAssembler::CheckEnumCache(Label* call_runtime) {
3041  Register null_value = r7;
3042  Register empty_fixed_array_value = r8;
3043  LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
3044  Label next, start;
3045  LoadRR(r4, r2);
3046
3047  // Check if the enum length field is properly initialized, indicating that
3048  // there is an enum cache.
3049  LoadP(r3, FieldMemOperand(r4, HeapObject::kMapOffset));
3050
3051  EnumLength(r5, r3);
3052  CmpSmiLiteral(r5, Smi::FromInt(kInvalidEnumCacheSentinel), r0);
3053  beq(call_runtime);
3054
3055  LoadRoot(null_value, Heap::kNullValueRootIndex);
3056  b(&start, Label::kNear);
3057
3058  bind(&next);
3059  LoadP(r3, FieldMemOperand(r4, HeapObject::kMapOffset));
3060
3061  // For all objects but the receiver, check that the cache is empty.
3062  EnumLength(r5, r3);
3063  CmpSmiLiteral(r5, Smi::kZero, r0);
3064  bne(call_runtime);
3065
3066  bind(&start);
3067
3068  // Check that there are no elements. Register r4 contains the current JS
3069  // object we've reached through the prototype chain.
3070  Label no_elements;
3071  LoadP(r4, FieldMemOperand(r4, JSObject::kElementsOffset));
3072  CmpP(r4, empty_fixed_array_value);
3073  beq(&no_elements, Label::kNear);
3074
3075  // Second chance, the object may be using the empty slow element dictionary.
3076  CompareRoot(r5, Heap::kEmptySlowElementDictionaryRootIndex);
3077  bne(call_runtime);
3078
3079  bind(&no_elements);
3080  LoadP(r4, FieldMemOperand(r3, Map::kPrototypeOffset));
3081  CmpP(r4, null_value);
3082  bne(&next);
3083}
3084
3085////////////////////////////////////////////////////////////////////////////////
3086//
3087// New MacroAssembler Interfaces added for S390
3088//
3089////////////////////////////////////////////////////////////////////////////////
3090// Primarily used for loading constants
3091// This should really move to be in macro-assembler as it
3092// is really a pseudo instruction
3093// Some usages of this intend for a FIXED_SEQUENCE to be used
3094// @TODO - break this dependency so we can optimize mov() in general
3095// and only use the generic version when we require a fixed sequence
3096void MacroAssembler::LoadRepresentation(Register dst, const MemOperand& mem,
3097                                        Representation r, Register scratch) {
3098  DCHECK(!r.IsDouble());
3099  if (r.IsInteger8()) {
3100    LoadB(dst, mem);
3101  } else if (r.IsUInteger8()) {
3102    LoadlB(dst, mem);
3103  } else if (r.IsInteger16()) {
3104    LoadHalfWordP(dst, mem, scratch);
3105  } else if (r.IsUInteger16()) {
3106    LoadHalfWordP(dst, mem, scratch);
3107#if V8_TARGET_ARCH_S390X
3108  } else if (r.IsInteger32()) {
3109    LoadW(dst, mem, scratch);
3110#endif
3111  } else {
3112    LoadP(dst, mem, scratch);
3113  }
3114}
3115
3116void MacroAssembler::StoreRepresentation(Register src, const MemOperand& mem,
3117                                         Representation r, Register scratch) {
3118  DCHECK(!r.IsDouble());
3119  if (r.IsInteger8() || r.IsUInteger8()) {
3120    StoreByte(src, mem, scratch);
3121  } else if (r.IsInteger16() || r.IsUInteger16()) {
3122    StoreHalfWord(src, mem, scratch);
3123#if V8_TARGET_ARCH_S390X
3124  } else if (r.IsInteger32()) {
3125    StoreW(src, mem, scratch);
3126#endif
3127  } else {
3128    if (r.IsHeapObject()) {
3129      AssertNotSmi(src);
3130    } else if (r.IsSmi()) {
3131      AssertSmi(src);
3132    }
3133    StoreP(src, mem, scratch);
3134  }
3135}
3136
3137void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver_reg,
3138                                                     Register scratch_reg,
3139                                                     Register scratch2_reg,
3140                                                     Label* no_memento_found) {
3141  Label map_check;
3142  Label top_check;
3143  ExternalReference new_space_allocation_top_adr =
3144      ExternalReference::new_space_allocation_top_address(isolate());
3145  const int kMementoMapOffset = JSArray::kSize - kHeapObjectTag;
3146  const int kMementoLastWordOffset =
3147      kMementoMapOffset + AllocationMemento::kSize - kPointerSize;
3148
3149  DCHECK(!AreAliased(receiver_reg, scratch_reg));
3150
3151  // Bail out if the object is not in new space.
3152  JumpIfNotInNewSpace(receiver_reg, scratch_reg, no_memento_found);
3153
3154  DCHECK((~Page::kPageAlignmentMask & 0xffff) == 0);
3155
3156  // If the object is in new space, we need to check whether it is on the same
3157  // page as the current top.
3158  AddP(scratch_reg, receiver_reg, Operand(kMementoLastWordOffset));
3159  mov(ip, Operand(new_space_allocation_top_adr));
3160  LoadP(ip, MemOperand(ip));
3161  XorP(r0, scratch_reg, ip);
3162  AndP(r0, r0, Operand(~Page::kPageAlignmentMask));
3163  beq(&top_check, Label::kNear);
3164  // The object is on a different page than allocation top. Bail out if the
3165  // object sits on the page boundary as no memento can follow and we cannot
3166  // touch the memory following it.
3167  XorP(r0, scratch_reg, receiver_reg);
3168  AndP(r0, r0, Operand(~Page::kPageAlignmentMask));
3169  bne(no_memento_found);
3170  // Continue with the actual map check.
3171  b(&map_check, Label::kNear);
3172  // If top is on the same page as the current object, we need to check whether
3173  // we are below top.
3174  bind(&top_check);
3175  CmpP(scratch_reg, ip);
3176  bge(no_memento_found);
3177  // Memento map check.
3178  bind(&map_check);
3179  LoadP(scratch_reg, MemOperand(receiver_reg, kMementoMapOffset));
3180  CmpP(scratch_reg, Operand(isolate()->factory()->allocation_memento_map()));
3181}
3182
3183Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2, Register reg3,
3184                                   Register reg4, Register reg5,
3185                                   Register reg6) {
3186  RegList regs = 0;
3187  if (reg1.is_valid()) regs |= reg1.bit();
3188  if (reg2.is_valid()) regs |= reg2.bit();
3189  if (reg3.is_valid()) regs |= reg3.bit();
3190  if (reg4.is_valid()) regs |= reg4.bit();
3191  if (reg5.is_valid()) regs |= reg5.bit();
3192  if (reg6.is_valid()) regs |= reg6.bit();
3193
3194  const RegisterConfiguration* config = RegisterConfiguration::Crankshaft();
3195  for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
3196    int code = config->GetAllocatableGeneralCode(i);
3197    Register candidate = Register::from_code(code);
3198    if (regs & candidate.bit()) continue;
3199    return candidate;
3200  }
3201  UNREACHABLE();
3202  return no_reg;
3203}
3204
3205void MacroAssembler::mov(Register dst, const Operand& src) {
3206  if (src.rmode_ != kRelocInfo_NONEPTR) {
3207    // some form of relocation needed
3208    RecordRelocInfo(src.rmode_, src.imm_);
3209  }
3210
3211#if V8_TARGET_ARCH_S390X
3212  int64_t value = src.immediate();
3213  int32_t hi_32 = static_cast<int64_t>(value) >> 32;
3214  int32_t lo_32 = static_cast<int32_t>(value);
3215
3216  iihf(dst, Operand(hi_32));
3217  iilf(dst, Operand(lo_32));
3218#else
3219  int value = src.immediate();
3220  iilf(dst, Operand(value));
3221#endif
3222}
3223
3224void MacroAssembler::Mul32(Register dst, const MemOperand& src1) {
3225  if (is_uint12(src1.offset())) {
3226    ms(dst, src1);
3227  } else if (is_int20(src1.offset())) {
3228    msy(dst, src1);
3229  } else {
3230    UNIMPLEMENTED();
3231  }
3232}
3233
3234void MacroAssembler::Mul32(Register dst, Register src1) { msr(dst, src1); }
3235
3236void MacroAssembler::Mul32(Register dst, const Operand& src1) {
3237  msfi(dst, src1);
3238}
3239
3240#define Generate_MulHigh32(instr) \
3241  {                               \
3242    lgfr(dst, src1);              \
3243    instr(dst, src2);             \
3244    srlg(dst, dst, Operand(32));  \
3245  }
3246
3247void MacroAssembler::MulHigh32(Register dst, Register src1,
3248                               const MemOperand& src2) {
3249  Generate_MulHigh32(msgf);
3250}
3251
3252void MacroAssembler::MulHigh32(Register dst, Register src1, Register src2) {
3253  if (dst.is(src2)) {
3254    std::swap(src1, src2);
3255  }
3256  Generate_MulHigh32(msgfr);
3257}
3258
3259void MacroAssembler::MulHigh32(Register dst, Register src1,
3260                               const Operand& src2) {
3261  Generate_MulHigh32(msgfi);
3262}
3263
3264#undef Generate_MulHigh32
3265
3266#define Generate_MulHighU32(instr) \
3267  {                                \
3268    lr(r1, src1);                  \
3269    instr(r0, src2);               \
3270    LoadlW(dst, r0);               \
3271  }
3272
3273void MacroAssembler::MulHighU32(Register dst, Register src1,
3274                                const MemOperand& src2) {
3275  Generate_MulHighU32(ml);
3276}
3277
3278void MacroAssembler::MulHighU32(Register dst, Register src1, Register src2) {
3279  Generate_MulHighU32(mlr);
3280}
3281
3282void MacroAssembler::MulHighU32(Register dst, Register src1,
3283                                const Operand& src2) {
3284  USE(dst);
3285  USE(src1);
3286  USE(src2);
3287  UNREACHABLE();
3288}
3289
3290#undef Generate_MulHighU32
3291
3292#define Generate_Mul32WithOverflowIfCCUnequal(instr) \
3293  {                                                  \
3294    lgfr(dst, src1);                                 \
3295    instr(dst, src2);                                \
3296    cgfr(dst, dst);                                  \
3297  }
3298
3299void MacroAssembler::Mul32WithOverflowIfCCUnequal(Register dst, Register src1,
3300                                                  const MemOperand& src2) {
3301  Register result = dst;
3302  if (src2.rx().is(dst) || src2.rb().is(dst)) dst = r0;
3303  Generate_Mul32WithOverflowIfCCUnequal(msgf);
3304  if (!result.is(dst)) llgfr(result, dst);
3305}
3306
3307void MacroAssembler::Mul32WithOverflowIfCCUnequal(Register dst, Register src1,
3308                                                  Register src2) {
3309  if (dst.is(src2)) {
3310    std::swap(src1, src2);
3311  }
3312  Generate_Mul32WithOverflowIfCCUnequal(msgfr);
3313}
3314
3315void MacroAssembler::Mul32WithOverflowIfCCUnequal(Register dst, Register src1,
3316                                                  const Operand& src2) {
3317  Generate_Mul32WithOverflowIfCCUnequal(msgfi);
3318}
3319
3320#undef Generate_Mul32WithOverflowIfCCUnequal
3321
3322void MacroAssembler::Mul64(Register dst, const MemOperand& src1) {
3323  if (is_int20(src1.offset())) {
3324    msg(dst, src1);
3325  } else {
3326    UNIMPLEMENTED();
3327  }
3328}
3329
3330void MacroAssembler::Mul64(Register dst, Register src1) { msgr(dst, src1); }
3331
3332void MacroAssembler::Mul64(Register dst, const Operand& src1) {
3333  msgfi(dst, src1);
3334}
3335
3336void MacroAssembler::Mul(Register dst, Register src1, Register src2) {
3337  if (CpuFeatures::IsSupported(MISC_INSTR_EXT2)) {
3338    MulPWithCondition(dst, src1, src2);
3339  } else {
3340    if (dst.is(src2)) {
3341      MulP(dst, src1);
3342    } else if (dst.is(src1)) {
3343      MulP(dst, src2);
3344    } else {
3345      Move(dst, src1);
3346      MulP(dst, src2);
3347    }
3348  }
3349}
3350
3351void MacroAssembler::DivP(Register dividend, Register divider) {
3352  // have to make sure the src and dst are reg pairs
3353  DCHECK(dividend.code() % 2 == 0);
3354#if V8_TARGET_ARCH_S390X
3355  dsgr(dividend, divider);
3356#else
3357  dr(dividend, divider);
3358#endif
3359}
3360
3361#define Generate_Div32(instr) \
3362  {                           \
3363    lgfr(r1, src1);           \
3364    instr(r0, src2);          \
3365    LoadlW(dst, r1);          \
3366  }
3367
3368void MacroAssembler::Div32(Register dst, Register src1,
3369                           const MemOperand& src2) {
3370  Generate_Div32(dsgf);
3371}
3372
3373void MacroAssembler::Div32(Register dst, Register src1, Register src2) {
3374  Generate_Div32(dsgfr);
3375}
3376
3377void MacroAssembler::Div32(Register dst, Register src1, const Operand& src2) {
3378  USE(dst);
3379  USE(src1);
3380  USE(src2);
3381  UNREACHABLE();
3382}
3383
3384#undef Generate_Div32
3385
3386#define Generate_DivU32(instr) \
3387  {                            \
3388    lr(r0, src1);              \
3389    srdl(r0, Operand(32));     \
3390    instr(r0, src2);           \
3391    LoadlW(dst, r1);           \
3392  }
3393
3394void MacroAssembler::DivU32(Register dst, Register src1,
3395                            const MemOperand& src2) {
3396  Generate_DivU32(dl);
3397}
3398
3399void MacroAssembler::DivU32(Register dst, Register src1, Register src2) {
3400  Generate_DivU32(dlr);
3401}
3402
3403void MacroAssembler::DivU32(Register dst, Register src1, const Operand& src2) {
3404  USE(dst);
3405  USE(src1);
3406  USE(src2);
3407  UNREACHABLE();
3408}
3409
3410#undef Generate_DivU32
3411
3412#define Generate_Mod32(instr) \
3413  {                           \
3414    lgfr(r1, src1);           \
3415    instr(r0, src2);          \
3416    LoadlW(dst, r0);          \
3417  }
3418
3419void MacroAssembler::Mod32(Register dst, Register src1,
3420                           const MemOperand& src2) {
3421  Generate_Mod32(dsgf);
3422}
3423
3424void MacroAssembler::Mod32(Register dst, Register src1, Register src2) {
3425  Generate_Mod32(dsgfr);
3426}
3427
3428void MacroAssembler::Mod32(Register dst, Register src1, const Operand& src2) {
3429  USE(dst);
3430  USE(src1);
3431  USE(src2);
3432  UNREACHABLE();
3433}
3434
3435#undef Generate_Mod32
3436
3437#define Generate_ModU32(instr) \
3438  {                            \
3439    lr(r0, src1);              \
3440    srdl(r0, Operand(32));     \
3441    instr(r0, src2);           \
3442    LoadlW(dst, r0);           \
3443  }
3444
3445void MacroAssembler::ModU32(Register dst, Register src1,
3446                            const MemOperand& src2) {
3447  Generate_ModU32(dl);
3448}
3449
3450void MacroAssembler::ModU32(Register dst, Register src1, Register src2) {
3451  Generate_ModU32(dlr);
3452}
3453
3454void MacroAssembler::ModU32(Register dst, Register src1, const Operand& src2) {
3455  USE(dst);
3456  USE(src1);
3457  USE(src2);
3458  UNREACHABLE();
3459}
3460
3461#undef Generate_ModU32
3462
3463void MacroAssembler::MulP(Register dst, const Operand& opnd) {
3464#if V8_TARGET_ARCH_S390X
3465  msgfi(dst, opnd);
3466#else
3467  msfi(dst, opnd);
3468#endif
3469}
3470
3471void MacroAssembler::MulP(Register dst, Register src) {
3472#if V8_TARGET_ARCH_S390X
3473  msgr(dst, src);
3474#else
3475  msr(dst, src);
3476#endif
3477}
3478
3479void MacroAssembler::MulPWithCondition(Register dst, Register src1,
3480                                       Register src2) {
3481  CHECK(CpuFeatures::IsSupported(MISC_INSTR_EXT2));
3482#if V8_TARGET_ARCH_S390X
3483  msgrkc(dst, src1, src2);
3484#else
3485  msrkc(dst, src1, src2);
3486#endif
3487}
3488
3489void MacroAssembler::MulP(Register dst, const MemOperand& opnd) {
3490#if V8_TARGET_ARCH_S390X
3491  if (is_uint16(opnd.offset())) {
3492    ms(dst, opnd);
3493  } else if (is_int20(opnd.offset())) {
3494    msy(dst, opnd);
3495  } else {
3496    UNIMPLEMENTED();
3497  }
3498#else
3499  if (is_int20(opnd.offset())) {
3500    msg(dst, opnd);
3501  } else {
3502    UNIMPLEMENTED();
3503  }
3504#endif
3505}
3506
3507void MacroAssembler::Sqrt(DoubleRegister result, DoubleRegister input) {
3508  sqdbr(result, input);
3509}
3510void MacroAssembler::Sqrt(DoubleRegister result, const MemOperand& input) {
3511  if (is_uint12(input.offset())) {
3512    sqdb(result, input);
3513  } else {
3514    ldy(result, input);
3515    sqdbr(result, result);
3516  }
3517}
3518//----------------------------------------------------------------------------
3519//  Add Instructions
3520//----------------------------------------------------------------------------
3521
3522// Add 32-bit (Register dst = Register dst + Immediate opnd)
3523void MacroAssembler::Add32(Register dst, const Operand& opnd) {
3524  if (is_int16(opnd.immediate()))
3525    ahi(dst, opnd);
3526  else
3527    afi(dst, opnd);
3528}
3529
3530// Add 32-bit (Register dst = Register dst + Immediate opnd)
3531void MacroAssembler::Add32_RI(Register dst, const Operand& opnd) {
3532  // Just a wrapper for above
3533  Add32(dst, opnd);
3534}
3535
3536// Add Pointer Size (Register dst = Register dst + Immediate opnd)
3537void MacroAssembler::AddP(Register dst, const Operand& opnd) {
3538#if V8_TARGET_ARCH_S390X
3539  if (is_int16(opnd.immediate()))
3540    aghi(dst, opnd);
3541  else
3542    agfi(dst, opnd);
3543#else
3544  Add32(dst, opnd);
3545#endif
3546}
3547
3548// Add 32-bit (Register dst = Register src + Immediate opnd)
3549void MacroAssembler::Add32(Register dst, Register src, const Operand& opnd) {
3550  if (!dst.is(src)) {
3551    if (CpuFeatures::IsSupported(DISTINCT_OPS) && is_int16(opnd.immediate())) {
3552      ahik(dst, src, opnd);
3553      return;
3554    }
3555    lr(dst, src);
3556  }
3557  Add32(dst, opnd);
3558}
3559
3560// Add 32-bit (Register dst = Register src + Immediate opnd)
3561void MacroAssembler::Add32_RRI(Register dst, Register src,
3562                               const Operand& opnd) {
3563  // Just a wrapper for above
3564  Add32(dst, src, opnd);
3565}
3566
3567// Add Pointer Size (Register dst = Register src + Immediate opnd)
3568void MacroAssembler::AddP(Register dst, Register src, const Operand& opnd) {
3569  if (!dst.is(src)) {
3570    if (CpuFeatures::IsSupported(DISTINCT_OPS) && is_int16(opnd.immediate())) {
3571      AddPImm_RRI(dst, src, opnd);
3572      return;
3573    }
3574    LoadRR(dst, src);
3575  }
3576  AddP(dst, opnd);
3577}
3578
3579// Add 32-bit (Register dst = Register dst + Register src)
3580void MacroAssembler::Add32(Register dst, Register src) { ar(dst, src); }
3581
3582// Add Pointer Size (Register dst = Register dst + Register src)
3583void MacroAssembler::AddP(Register dst, Register src) { AddRR(dst, src); }
3584
3585// Add Pointer Size with src extension
3586//     (Register dst(ptr) = Register dst (ptr) + Register src (32 | 32->64))
3587// src is treated as a 32-bit signed integer, which is sign extended to
3588// 64-bit if necessary.
3589void MacroAssembler::AddP_ExtendSrc(Register dst, Register src) {
3590#if V8_TARGET_ARCH_S390X
3591  agfr(dst, src);
3592#else
3593  ar(dst, src);
3594#endif
3595}
3596
3597// Add 32-bit (Register dst = Register src1 + Register src2)
3598void MacroAssembler::Add32(Register dst, Register src1, Register src2) {
3599  if (!dst.is(src1) && !dst.is(src2)) {
3600    // We prefer to generate AR/AGR, over the non clobbering ARK/AGRK
3601    // as AR is a smaller instruction
3602    if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
3603      ark(dst, src1, src2);
3604      return;
3605    } else {
3606      lr(dst, src1);
3607    }
3608  } else if (dst.is(src2)) {
3609    src2 = src1;
3610  }
3611  ar(dst, src2);
3612}
3613
3614// Add Pointer Size (Register dst = Register src1 + Register src2)
3615void MacroAssembler::AddP(Register dst, Register src1, Register src2) {
3616  if (!dst.is(src1) && !dst.is(src2)) {
3617    // We prefer to generate AR/AGR, over the non clobbering ARK/AGRK
3618    // as AR is a smaller instruction
3619    if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
3620      AddP_RRR(dst, src1, src2);
3621      return;
3622    } else {
3623      LoadRR(dst, src1);
3624    }
3625  } else if (dst.is(src2)) {
3626    src2 = src1;
3627  }
3628  AddRR(dst, src2);
3629}
3630
3631// Add Pointer Size with src extension
3632//      (Register dst (ptr) = Register dst (ptr) + Register src1 (ptr) +
3633//                            Register src2 (32 | 32->64))
3634// src is treated as a 32-bit signed integer, which is sign extended to
3635// 64-bit if necessary.
3636void MacroAssembler::AddP_ExtendSrc(Register dst, Register src1,
3637                                    Register src2) {
3638#if V8_TARGET_ARCH_S390X
3639  if (dst.is(src2)) {
3640    // The source we need to sign extend is the same as result.
3641    lgfr(dst, src2);
3642    agr(dst, src1);
3643  } else {
3644    if (!dst.is(src1)) LoadRR(dst, src1);
3645    agfr(dst, src2);
3646  }
3647#else
3648  AddP(dst, src1, src2);
3649#endif
3650}
3651
3652// Add 32-bit (Register-Memory)
3653void MacroAssembler::Add32(Register dst, const MemOperand& opnd) {
3654  DCHECK(is_int20(opnd.offset()));
3655  if (is_uint12(opnd.offset()))
3656    a(dst, opnd);
3657  else
3658    ay(dst, opnd);
3659}
3660
3661// Add Pointer Size (Register-Memory)
3662void MacroAssembler::AddP(Register dst, const MemOperand& opnd) {
3663#if V8_TARGET_ARCH_S390X
3664  DCHECK(is_int20(opnd.offset()));
3665  ag(dst, opnd);
3666#else
3667  Add32(dst, opnd);
3668#endif
3669}
3670
3671// Add Pointer Size with src extension
3672//      (Register dst (ptr) = Register dst (ptr) + Mem opnd (32 | 32->64))
3673// src is treated as a 32-bit signed integer, which is sign extended to
3674// 64-bit if necessary.
3675void MacroAssembler::AddP_ExtendSrc(Register dst, const MemOperand& opnd) {
3676#if V8_TARGET_ARCH_S390X
3677  DCHECK(is_int20(opnd.offset()));
3678  agf(dst, opnd);
3679#else
3680  Add32(dst, opnd);
3681#endif
3682}
3683
3684// Add 32-bit (Memory - Immediate)
3685void MacroAssembler::Add32(const MemOperand& opnd, const Operand& imm) {
3686  DCHECK(is_int8(imm.immediate()));
3687  DCHECK(is_int20(opnd.offset()));
3688  DCHECK(CpuFeatures::IsSupported(GENERAL_INSTR_EXT));
3689  asi(opnd, imm);
3690}
3691
3692// Add Pointer-sized (Memory - Immediate)
3693void MacroAssembler::AddP(const MemOperand& opnd, const Operand& imm) {
3694  DCHECK(is_int8(imm.immediate()));
3695  DCHECK(is_int20(opnd.offset()));
3696  DCHECK(CpuFeatures::IsSupported(GENERAL_INSTR_EXT));
3697#if V8_TARGET_ARCH_S390X
3698  agsi(opnd, imm);
3699#else
3700  asi(opnd, imm);
3701#endif
3702}
3703
3704//----------------------------------------------------------------------------
3705//  Add Logical Instructions
3706//----------------------------------------------------------------------------
3707
3708// Add Logical With Carry 32-bit (Register dst = Register src1 + Register src2)
3709void MacroAssembler::AddLogicalWithCarry32(Register dst, Register src1,
3710                                           Register src2) {
3711  if (!dst.is(src2) && !dst.is(src1)) {
3712    lr(dst, src1);
3713    alcr(dst, src2);
3714  } else if (!dst.is(src2)) {
3715    // dst == src1
3716    DCHECK(dst.is(src1));
3717    alcr(dst, src2);
3718  } else {
3719    // dst == src2
3720    DCHECK(dst.is(src2));
3721    alcr(dst, src1);
3722  }
3723}
3724
3725// Add Logical 32-bit (Register dst = Register src1 + Register src2)
3726void MacroAssembler::AddLogical32(Register dst, Register src1, Register src2) {
3727  if (!dst.is(src2) && !dst.is(src1)) {
3728    lr(dst, src1);
3729    alr(dst, src2);
3730  } else if (!dst.is(src2)) {
3731    // dst == src1
3732    DCHECK(dst.is(src1));
3733    alr(dst, src2);
3734  } else {
3735    // dst == src2
3736    DCHECK(dst.is(src2));
3737    alr(dst, src1);
3738  }
3739}
3740
3741// Add Logical 32-bit (Register dst = Register dst + Immediate opnd)
3742void MacroAssembler::AddLogical(Register dst, const Operand& imm) {
3743  alfi(dst, imm);
3744}
3745
3746// Add Logical Pointer Size (Register dst = Register dst + Immediate opnd)
3747void MacroAssembler::AddLogicalP(Register dst, const Operand& imm) {
3748#ifdef V8_TARGET_ARCH_S390X
3749  algfi(dst, imm);
3750#else
3751  AddLogical(dst, imm);
3752#endif
3753}
3754
3755// Add Logical 32-bit (Register-Memory)
3756void MacroAssembler::AddLogical(Register dst, const MemOperand& opnd) {
3757  DCHECK(is_int20(opnd.offset()));
3758  if (is_uint12(opnd.offset()))
3759    al_z(dst, opnd);
3760  else
3761    aly(dst, opnd);
3762}
3763
3764// Add Logical Pointer Size (Register-Memory)
3765void MacroAssembler::AddLogicalP(Register dst, const MemOperand& opnd) {
3766#if V8_TARGET_ARCH_S390X
3767  DCHECK(is_int20(opnd.offset()));
3768  alg(dst, opnd);
3769#else
3770  AddLogical(dst, opnd);
3771#endif
3772}
3773
3774//----------------------------------------------------------------------------
3775//  Subtract Instructions
3776//----------------------------------------------------------------------------
3777
3778// Subtract Logical With Carry 32-bit (Register dst = Register src1 - Register
3779// src2)
3780void MacroAssembler::SubLogicalWithBorrow32(Register dst, Register src1,
3781                                            Register src2) {
3782  if (!dst.is(src2) && !dst.is(src1)) {
3783    lr(dst, src1);
3784    slbr(dst, src2);
3785  } else if (!dst.is(src2)) {
3786    // dst == src1
3787    DCHECK(dst.is(src1));
3788    slbr(dst, src2);
3789  } else {
3790    // dst == src2
3791    DCHECK(dst.is(src2));
3792    lr(r0, dst);
3793    SubLogicalWithBorrow32(dst, src1, r0);
3794  }
3795}
3796
3797// Subtract Logical 32-bit (Register dst = Register src1 - Register src2)
3798void MacroAssembler::SubLogical32(Register dst, Register src1, Register src2) {
3799  if (!dst.is(src2) && !dst.is(src1)) {
3800    lr(dst, src1);
3801    slr(dst, src2);
3802  } else if (!dst.is(src2)) {
3803    // dst == src1
3804    DCHECK(dst.is(src1));
3805    slr(dst, src2);
3806  } else {
3807    // dst == src2
3808    DCHECK(dst.is(src2));
3809    lr(r0, dst);
3810    SubLogical32(dst, src1, r0);
3811  }
3812}
3813
3814// Subtract 32-bit (Register dst = Register dst - Immediate opnd)
3815void MacroAssembler::Sub32(Register dst, const Operand& imm) {
3816  Add32(dst, Operand(-(imm.imm_)));
3817}
3818
3819// Subtract Pointer Size (Register dst = Register dst - Immediate opnd)
3820void MacroAssembler::SubP(Register dst, const Operand& imm) {
3821  AddP(dst, Operand(-(imm.imm_)));
3822}
3823
3824// Subtract 32-bit (Register dst = Register src - Immediate opnd)
3825void MacroAssembler::Sub32(Register dst, Register src, const Operand& imm) {
3826  Add32(dst, src, Operand(-(imm.imm_)));
3827}
3828
3829// Subtract Pointer Sized (Register dst = Register src - Immediate opnd)
3830void MacroAssembler::SubP(Register dst, Register src, const Operand& imm) {
3831  AddP(dst, src, Operand(-(imm.imm_)));
3832}
3833
3834// Subtract 32-bit (Register dst = Register dst - Register src)
3835void MacroAssembler::Sub32(Register dst, Register src) { sr(dst, src); }
3836
3837// Subtract Pointer Size (Register dst = Register dst - Register src)
3838void MacroAssembler::SubP(Register dst, Register src) { SubRR(dst, src); }
3839
3840// Subtract Pointer Size with src extension
3841//     (Register dst(ptr) = Register dst (ptr) - Register src (32 | 32->64))
3842// src is treated as a 32-bit signed integer, which is sign extended to
3843// 64-bit if necessary.
3844void MacroAssembler::SubP_ExtendSrc(Register dst, Register src) {
3845#if V8_TARGET_ARCH_S390X
3846  sgfr(dst, src);
3847#else
3848  sr(dst, src);
3849#endif
3850}
3851
3852// Subtract 32-bit (Register = Register - Register)
3853void MacroAssembler::Sub32(Register dst, Register src1, Register src2) {
3854  // Use non-clobbering version if possible
3855  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
3856    srk(dst, src1, src2);
3857    return;
3858  }
3859  if (!dst.is(src1) && !dst.is(src2)) lr(dst, src1);
3860  // In scenario where we have dst = src - dst, we need to swap and negate
3861  if (!dst.is(src1) && dst.is(src2)) {
3862    Label done;
3863    lcr(dst, dst);  // dst = -dst
3864    b(overflow, &done);
3865    ar(dst, src1);  // dst = dst + src
3866    bind(&done);
3867  } else {
3868    sr(dst, src2);
3869  }
3870}
3871
3872// Subtract Pointer Sized (Register = Register - Register)
3873void MacroAssembler::SubP(Register dst, Register src1, Register src2) {
3874  // Use non-clobbering version if possible
3875  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
3876    SubP_RRR(dst, src1, src2);
3877    return;
3878  }
3879  if (!dst.is(src1) && !dst.is(src2)) LoadRR(dst, src1);
3880  // In scenario where we have dst = src - dst, we need to swap and negate
3881  if (!dst.is(src1) && dst.is(src2)) {
3882    Label done;
3883    LoadComplementRR(dst, dst);  // dst = -dst
3884    b(overflow, &done);
3885    AddP(dst, src1);  // dst = dst + src
3886    bind(&done);
3887  } else {
3888    SubP(dst, src2);
3889  }
3890}
3891
3892// Subtract Pointer Size with src extension
3893//     (Register dst(ptr) = Register dst (ptr) - Register src (32 | 32->64))
3894// src is treated as a 32-bit signed integer, which is sign extended to
3895// 64-bit if necessary.
3896void MacroAssembler::SubP_ExtendSrc(Register dst, Register src1,
3897                                    Register src2) {
3898#if V8_TARGET_ARCH_S390X
3899  if (!dst.is(src1) && !dst.is(src2)) LoadRR(dst, src1);
3900
3901  // In scenario where we have dst = src - dst, we need to swap and negate
3902  if (!dst.is(src1) && dst.is(src2)) {
3903    lgfr(dst, dst);              // Sign extend this operand first.
3904    LoadComplementRR(dst, dst);  // dst = -dst
3905    AddP(dst, src1);             // dst = -dst + src
3906  } else {
3907    sgfr(dst, src2);
3908  }
3909#else
3910  SubP(dst, src1, src2);
3911#endif
3912}
3913
3914// Subtract 32-bit (Register-Memory)
3915void MacroAssembler::Sub32(Register dst, const MemOperand& opnd) {
3916  DCHECK(is_int20(opnd.offset()));
3917  if (is_uint12(opnd.offset()))
3918    s(dst, opnd);
3919  else
3920    sy(dst, opnd);
3921}
3922
3923// Subtract Pointer Sized (Register - Memory)
3924void MacroAssembler::SubP(Register dst, const MemOperand& opnd) {
3925#if V8_TARGET_ARCH_S390X
3926  sg(dst, opnd);
3927#else
3928  Sub32(dst, opnd);
3929#endif
3930}
3931
3932void MacroAssembler::MovIntToFloat(DoubleRegister dst, Register src) {
3933  sllg(r0, src, Operand(32));
3934  ldgr(dst, r0);
3935}
3936
3937void MacroAssembler::MovFloatToInt(Register dst, DoubleRegister src) {
3938  lgdr(dst, src);
3939  srlg(dst, dst, Operand(32));
3940}
3941
3942void MacroAssembler::SubP_ExtendSrc(Register dst, const MemOperand& opnd) {
3943#if V8_TARGET_ARCH_S390X
3944  DCHECK(is_int20(opnd.offset()));
3945  sgf(dst, opnd);
3946#else
3947  Sub32(dst, opnd);
3948#endif
3949}
3950
3951//----------------------------------------------------------------------------
3952//  Subtract Logical Instructions
3953//----------------------------------------------------------------------------
3954
3955// Subtract Logical 32-bit (Register - Memory)
3956void MacroAssembler::SubLogical(Register dst, const MemOperand& opnd) {
3957  DCHECK(is_int20(opnd.offset()));
3958  if (is_uint12(opnd.offset()))
3959    sl(dst, opnd);
3960  else
3961    sly(dst, opnd);
3962}
3963
3964// Subtract Logical Pointer Sized (Register - Memory)
3965void MacroAssembler::SubLogicalP(Register dst, const MemOperand& opnd) {
3966  DCHECK(is_int20(opnd.offset()));
3967#if V8_TARGET_ARCH_S390X
3968  slgf(dst, opnd);
3969#else
3970  SubLogical(dst, opnd);
3971#endif
3972}
3973
3974// Subtract Logical Pointer Size with src extension
3975//      (Register dst (ptr) = Register dst (ptr) - Mem opnd (32 | 32->64))
3976// src is treated as a 32-bit signed integer, which is sign extended to
3977// 64-bit if necessary.
3978void MacroAssembler::SubLogicalP_ExtendSrc(Register dst,
3979                                           const MemOperand& opnd) {
3980#if V8_TARGET_ARCH_S390X
3981  DCHECK(is_int20(opnd.offset()));
3982  slgf(dst, opnd);
3983#else
3984  SubLogical(dst, opnd);
3985#endif
3986}
3987
3988//----------------------------------------------------------------------------
3989//  Bitwise Operations
3990//----------------------------------------------------------------------------
3991
3992// AND 32-bit - dst = dst & src
3993void MacroAssembler::And(Register dst, Register src) { nr(dst, src); }
3994
3995// AND Pointer Size - dst = dst & src
3996void MacroAssembler::AndP(Register dst, Register src) { AndRR(dst, src); }
3997
3998// Non-clobbering AND 32-bit - dst = src1 & src1
3999void MacroAssembler::And(Register dst, Register src1, Register src2) {
4000  if (!dst.is(src1) && !dst.is(src2)) {
4001    // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
4002    // as XR is a smaller instruction
4003    if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4004      nrk(dst, src1, src2);
4005      return;
4006    } else {
4007      lr(dst, src1);
4008    }
4009  } else if (dst.is(src2)) {
4010    src2 = src1;
4011  }
4012  And(dst, src2);
4013}
4014
4015// Non-clobbering AND pointer size - dst = src1 & src1
4016void MacroAssembler::AndP(Register dst, Register src1, Register src2) {
4017  if (!dst.is(src1) && !dst.is(src2)) {
4018    // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
4019    // as XR is a smaller instruction
4020    if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4021      AndP_RRR(dst, src1, src2);
4022      return;
4023    } else {
4024      LoadRR(dst, src1);
4025    }
4026  } else if (dst.is(src2)) {
4027    src2 = src1;
4028  }
4029  AndP(dst, src2);
4030}
4031
4032// AND 32-bit (Reg - Mem)
4033void MacroAssembler::And(Register dst, const MemOperand& opnd) {
4034  DCHECK(is_int20(opnd.offset()));
4035  if (is_uint12(opnd.offset()))
4036    n(dst, opnd);
4037  else
4038    ny(dst, opnd);
4039}
4040
4041// AND Pointer Size (Reg - Mem)
4042void MacroAssembler::AndP(Register dst, const MemOperand& opnd) {
4043  DCHECK(is_int20(opnd.offset()));
4044#if V8_TARGET_ARCH_S390X
4045  ng(dst, opnd);
4046#else
4047  And(dst, opnd);
4048#endif
4049}
4050
4051// AND 32-bit - dst = dst & imm
4052void MacroAssembler::And(Register dst, const Operand& opnd) { nilf(dst, opnd); }
4053
4054// AND Pointer Size - dst = dst & imm
4055void MacroAssembler::AndP(Register dst, const Operand& opnd) {
4056#if V8_TARGET_ARCH_S390X
4057  intptr_t value = opnd.imm_;
4058  if (value >> 32 != -1) {
4059    // this may not work b/c condition code won't be set correctly
4060    nihf(dst, Operand(value >> 32));
4061  }
4062  nilf(dst, Operand(value & 0xFFFFFFFF));
4063#else
4064  And(dst, opnd);
4065#endif
4066}
4067
4068// AND 32-bit - dst = src & imm
4069void MacroAssembler::And(Register dst, Register src, const Operand& opnd) {
4070  if (!dst.is(src)) lr(dst, src);
4071  nilf(dst, opnd);
4072}
4073
4074// AND Pointer Size - dst = src & imm
4075void MacroAssembler::AndP(Register dst, Register src, const Operand& opnd) {
4076  // Try to exploit RISBG first
4077  intptr_t value = opnd.imm_;
4078  if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
4079    intptr_t shifted_value = value;
4080    int trailing_zeros = 0;
4081
4082    // We start checking how many trailing zeros are left at the end.
4083    while ((0 != shifted_value) && (0 == (shifted_value & 1))) {
4084      trailing_zeros++;
4085      shifted_value >>= 1;
4086    }
4087
4088    // If temp (value with right-most set of zeros shifted out) is 1 less
4089    // than power of 2, we have consecutive bits of 1.
4090    // Special case: If shift_value is zero, we cannot use RISBG, as it requires
4091    //               selection of at least 1 bit.
4092    if ((0 != shifted_value) && base::bits::IsPowerOfTwo64(shifted_value + 1)) {
4093      int startBit =
4094          base::bits::CountLeadingZeros64(shifted_value) - trailing_zeros;
4095      int endBit = 63 - trailing_zeros;
4096      // Start: startBit, End: endBit, Shift = 0, true = zero unselected bits.
4097      risbg(dst, src, Operand(startBit), Operand(endBit), Operand::Zero(),
4098            true);
4099      return;
4100    } else if (-1 == shifted_value) {
4101      // A Special case in which all top bits up to MSB are 1's.  In this case,
4102      // we can set startBit to be 0.
4103      int endBit = 63 - trailing_zeros;
4104      risbg(dst, src, Operand::Zero(), Operand(endBit), Operand::Zero(), true);
4105      return;
4106    }
4107  }
4108
4109  // If we are &'ing zero, we can just whack the dst register and skip copy
4110  if (!dst.is(src) && (0 != value)) LoadRR(dst, src);
4111  AndP(dst, opnd);
4112}
4113
4114// OR 32-bit - dst = dst & src
4115void MacroAssembler::Or(Register dst, Register src) { or_z(dst, src); }
4116
4117// OR Pointer Size - dst = dst & src
4118void MacroAssembler::OrP(Register dst, Register src) { OrRR(dst, src); }
4119
4120// Non-clobbering OR 32-bit - dst = src1 & src1
4121void MacroAssembler::Or(Register dst, Register src1, Register src2) {
4122  if (!dst.is(src1) && !dst.is(src2)) {
4123    // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
4124    // as XR is a smaller instruction
4125    if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4126      ork(dst, src1, src2);
4127      return;
4128    } else {
4129      lr(dst, src1);
4130    }
4131  } else if (dst.is(src2)) {
4132    src2 = src1;
4133  }
4134  Or(dst, src2);
4135}
4136
4137// Non-clobbering OR pointer size - dst = src1 & src1
4138void MacroAssembler::OrP(Register dst, Register src1, Register src2) {
4139  if (!dst.is(src1) && !dst.is(src2)) {
4140    // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
4141    // as XR is a smaller instruction
4142    if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4143      OrP_RRR(dst, src1, src2);
4144      return;
4145    } else {
4146      LoadRR(dst, src1);
4147    }
4148  } else if (dst.is(src2)) {
4149    src2 = src1;
4150  }
4151  OrP(dst, src2);
4152}
4153
4154// OR 32-bit (Reg - Mem)
4155void MacroAssembler::Or(Register dst, const MemOperand& opnd) {
4156  DCHECK(is_int20(opnd.offset()));
4157  if (is_uint12(opnd.offset()))
4158    o(dst, opnd);
4159  else
4160    oy(dst, opnd);
4161}
4162
4163// OR Pointer Size (Reg - Mem)
4164void MacroAssembler::OrP(Register dst, const MemOperand& opnd) {
4165  DCHECK(is_int20(opnd.offset()));
4166#if V8_TARGET_ARCH_S390X
4167  og(dst, opnd);
4168#else
4169  Or(dst, opnd);
4170#endif
4171}
4172
4173// OR 32-bit - dst = dst & imm
4174void MacroAssembler::Or(Register dst, const Operand& opnd) { oilf(dst, opnd); }
4175
4176// OR Pointer Size - dst = dst & imm
4177void MacroAssembler::OrP(Register dst, const Operand& opnd) {
4178#if V8_TARGET_ARCH_S390X
4179  intptr_t value = opnd.imm_;
4180  if (value >> 32 != 0) {
4181    // this may not work b/c condition code won't be set correctly
4182    oihf(dst, Operand(value >> 32));
4183  }
4184  oilf(dst, Operand(value & 0xFFFFFFFF));
4185#else
4186  Or(dst, opnd);
4187#endif
4188}
4189
4190// OR 32-bit - dst = src & imm
4191void MacroAssembler::Or(Register dst, Register src, const Operand& opnd) {
4192  if (!dst.is(src)) lr(dst, src);
4193  oilf(dst, opnd);
4194}
4195
4196// OR Pointer Size - dst = src & imm
4197void MacroAssembler::OrP(Register dst, Register src, const Operand& opnd) {
4198  if (!dst.is(src)) LoadRR(dst, src);
4199  OrP(dst, opnd);
4200}
4201
4202// XOR 32-bit - dst = dst & src
4203void MacroAssembler::Xor(Register dst, Register src) { xr(dst, src); }
4204
4205// XOR Pointer Size - dst = dst & src
4206void MacroAssembler::XorP(Register dst, Register src) { XorRR(dst, src); }
4207
4208// Non-clobbering XOR 32-bit - dst = src1 & src1
4209void MacroAssembler::Xor(Register dst, Register src1, Register src2) {
4210  if (!dst.is(src1) && !dst.is(src2)) {
4211    // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
4212    // as XR is a smaller instruction
4213    if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4214      xrk(dst, src1, src2);
4215      return;
4216    } else {
4217      lr(dst, src1);
4218    }
4219  } else if (dst.is(src2)) {
4220    src2 = src1;
4221  }
4222  Xor(dst, src2);
4223}
4224
4225// Non-clobbering XOR pointer size - dst = src1 & src1
4226void MacroAssembler::XorP(Register dst, Register src1, Register src2) {
4227  if (!dst.is(src1) && !dst.is(src2)) {
4228    // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
4229    // as XR is a smaller instruction
4230    if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4231      XorP_RRR(dst, src1, src2);
4232      return;
4233    } else {
4234      LoadRR(dst, src1);
4235    }
4236  } else if (dst.is(src2)) {
4237    src2 = src1;
4238  }
4239  XorP(dst, src2);
4240}
4241
4242// XOR 32-bit (Reg - Mem)
4243void MacroAssembler::Xor(Register dst, const MemOperand& opnd) {
4244  DCHECK(is_int20(opnd.offset()));
4245  if (is_uint12(opnd.offset()))
4246    x(dst, opnd);
4247  else
4248    xy(dst, opnd);
4249}
4250
4251// XOR Pointer Size (Reg - Mem)
4252void MacroAssembler::XorP(Register dst, const MemOperand& opnd) {
4253  DCHECK(is_int20(opnd.offset()));
4254#if V8_TARGET_ARCH_S390X
4255  xg(dst, opnd);
4256#else
4257  Xor(dst, opnd);
4258#endif
4259}
4260
4261// XOR 32-bit - dst = dst & imm
4262void MacroAssembler::Xor(Register dst, const Operand& opnd) { xilf(dst, opnd); }
4263
4264// XOR Pointer Size - dst = dst & imm
4265void MacroAssembler::XorP(Register dst, const Operand& opnd) {
4266#if V8_TARGET_ARCH_S390X
4267  intptr_t value = opnd.imm_;
4268  xihf(dst, Operand(value >> 32));
4269  xilf(dst, Operand(value & 0xFFFFFFFF));
4270#else
4271  Xor(dst, opnd);
4272#endif
4273}
4274
4275// XOR 32-bit - dst = src & imm
4276void MacroAssembler::Xor(Register dst, Register src, const Operand& opnd) {
4277  if (!dst.is(src)) lr(dst, src);
4278  xilf(dst, opnd);
4279}
4280
4281// XOR Pointer Size - dst = src & imm
4282void MacroAssembler::XorP(Register dst, Register src, const Operand& opnd) {
4283  if (!dst.is(src)) LoadRR(dst, src);
4284  XorP(dst, opnd);
4285}
4286
4287void MacroAssembler::Not32(Register dst, Register src) {
4288  if (!src.is(no_reg) && !src.is(dst)) lr(dst, src);
4289  xilf(dst, Operand(0xFFFFFFFF));
4290}
4291
4292void MacroAssembler::Not64(Register dst, Register src) {
4293  if (!src.is(no_reg) && !src.is(dst)) lgr(dst, src);
4294  xihf(dst, Operand(0xFFFFFFFF));
4295  xilf(dst, Operand(0xFFFFFFFF));
4296}
4297
4298void MacroAssembler::NotP(Register dst, Register src) {
4299#if V8_TARGET_ARCH_S390X
4300  Not64(dst, src);
4301#else
4302  Not32(dst, src);
4303#endif
4304}
4305
4306// works the same as mov
4307void MacroAssembler::Load(Register dst, const Operand& opnd) {
4308  intptr_t value = opnd.immediate();
4309  if (is_int16(value)) {
4310#if V8_TARGET_ARCH_S390X
4311    lghi(dst, opnd);
4312#else
4313    lhi(dst, opnd);
4314#endif
4315  } else if (is_int32(value)) {
4316#if V8_TARGET_ARCH_S390X
4317    lgfi(dst, opnd);
4318#else
4319    iilf(dst, opnd);
4320#endif
4321  } else if (is_uint32(value)) {
4322#if V8_TARGET_ARCH_S390X
4323    llilf(dst, opnd);
4324#else
4325    iilf(dst, opnd);
4326#endif
4327  } else {
4328    int32_t hi_32 = static_cast<int64_t>(value) >> 32;
4329    int32_t lo_32 = static_cast<int32_t>(value);
4330
4331    iihf(dst, Operand(hi_32));
4332    iilf(dst, Operand(lo_32));
4333  }
4334}
4335
4336void MacroAssembler::Load(Register dst, const MemOperand& opnd) {
4337  DCHECK(is_int20(opnd.offset()));
4338#if V8_TARGET_ARCH_S390X
4339  lgf(dst, opnd);  // 64<-32
4340#else
4341  if (is_uint12(opnd.offset())) {
4342    l(dst, opnd);
4343  } else {
4344    ly(dst, opnd);
4345  }
4346#endif
4347}
4348
4349void MacroAssembler::LoadPositiveP(Register result, Register input) {
4350#if V8_TARGET_ARCH_S390X
4351  lpgr(result, input);
4352#else
4353  lpr(result, input);
4354#endif
4355}
4356
4357void MacroAssembler::LoadPositive32(Register result, Register input) {
4358  lpr(result, input);
4359  lgfr(result, result);
4360}
4361
4362//-----------------------------------------------------------------------------
4363//  Compare Helpers
4364//-----------------------------------------------------------------------------
4365
4366// Compare 32-bit Register vs Register
4367void MacroAssembler::Cmp32(Register src1, Register src2) { cr_z(src1, src2); }
4368
4369// Compare Pointer Sized Register vs Register
4370void MacroAssembler::CmpP(Register src1, Register src2) {
4371#if V8_TARGET_ARCH_S390X
4372  cgr(src1, src2);
4373#else
4374  Cmp32(src1, src2);
4375#endif
4376}
4377
4378// Compare 32-bit Register vs Immediate
4379// This helper will set up proper relocation entries if required.
4380void MacroAssembler::Cmp32(Register dst, const Operand& opnd) {
4381  if (opnd.rmode_ == kRelocInfo_NONEPTR) {
4382    intptr_t value = opnd.immediate();
4383    if (is_int16(value))
4384      chi(dst, opnd);
4385    else
4386      cfi(dst, opnd);
4387  } else {
4388    // Need to generate relocation record here
4389    RecordRelocInfo(opnd.rmode_, opnd.imm_);
4390    cfi(dst, opnd);
4391  }
4392}
4393
4394// Compare Pointer Sized  Register vs Immediate
4395// This helper will set up proper relocation entries if required.
4396void MacroAssembler::CmpP(Register dst, const Operand& opnd) {
4397#if V8_TARGET_ARCH_S390X
4398  if (opnd.rmode_ == kRelocInfo_NONEPTR) {
4399    cgfi(dst, opnd);
4400  } else {
4401    mov(r0, opnd);  // Need to generate 64-bit relocation
4402    cgr(dst, r0);
4403  }
4404#else
4405  Cmp32(dst, opnd);
4406#endif
4407}
4408
4409// Compare 32-bit Register vs Memory
4410void MacroAssembler::Cmp32(Register dst, const MemOperand& opnd) {
4411  // make sure offset is within 20 bit range
4412  DCHECK(is_int20(opnd.offset()));
4413  if (is_uint12(opnd.offset()))
4414    c(dst, opnd);
4415  else
4416    cy(dst, opnd);
4417}
4418
4419// Compare Pointer Size Register vs Memory
4420void MacroAssembler::CmpP(Register dst, const MemOperand& opnd) {
4421  // make sure offset is within 20 bit range
4422  DCHECK(is_int20(opnd.offset()));
4423#if V8_TARGET_ARCH_S390X
4424  cg(dst, opnd);
4425#else
4426  Cmp32(dst, opnd);
4427#endif
4428}
4429
4430//-----------------------------------------------------------------------------
4431// Compare Logical Helpers
4432//-----------------------------------------------------------------------------
4433
4434// Compare Logical 32-bit Register vs Register
4435void MacroAssembler::CmpLogical32(Register dst, Register src) { clr(dst, src); }
4436
4437// Compare Logical Pointer Sized Register vs Register
4438void MacroAssembler::CmpLogicalP(Register dst, Register src) {
4439#ifdef V8_TARGET_ARCH_S390X
4440  clgr(dst, src);
4441#else
4442  CmpLogical32(dst, src);
4443#endif
4444}
4445
4446// Compare Logical 32-bit Register vs Immediate
4447void MacroAssembler::CmpLogical32(Register dst, const Operand& opnd) {
4448  clfi(dst, opnd);
4449}
4450
4451// Compare Logical Pointer Sized Register vs Immediate
4452void MacroAssembler::CmpLogicalP(Register dst, const Operand& opnd) {
4453#if V8_TARGET_ARCH_S390X
4454  DCHECK(static_cast<uint32_t>(opnd.immediate() >> 32) == 0);
4455  clgfi(dst, opnd);
4456#else
4457  CmpLogical32(dst, opnd);
4458#endif
4459}
4460
4461// Compare Logical 32-bit Register vs Memory
4462void MacroAssembler::CmpLogical32(Register dst, const MemOperand& opnd) {
4463  // make sure offset is within 20 bit range
4464  DCHECK(is_int20(opnd.offset()));
4465  if (is_uint12(opnd.offset()))
4466    cl(dst, opnd);
4467  else
4468    cly(dst, opnd);
4469}
4470
4471// Compare Logical Pointer Sized Register vs Memory
4472void MacroAssembler::CmpLogicalP(Register dst, const MemOperand& opnd) {
4473  // make sure offset is within 20 bit range
4474  DCHECK(is_int20(opnd.offset()));
4475#if V8_TARGET_ARCH_S390X
4476  clg(dst, opnd);
4477#else
4478  CmpLogical32(dst, opnd);
4479#endif
4480}
4481
4482// Compare Logical Byte (Mem - Imm)
4483void MacroAssembler::CmpLogicalByte(const MemOperand& mem, const Operand& imm) {
4484  DCHECK(is_uint8(imm.immediate()));
4485  if (is_uint12(mem.offset()))
4486    cli(mem, imm);
4487  else
4488    cliy(mem, imm);
4489}
4490
4491void MacroAssembler::Branch(Condition c, const Operand& opnd) {
4492  intptr_t value = opnd.immediate();
4493  if (is_int16(value))
4494    brc(c, opnd);
4495  else
4496    brcl(c, opnd);
4497}
4498
4499// Branch On Count.  Decrement R1, and branch if R1 != 0.
4500void MacroAssembler::BranchOnCount(Register r1, Label* l) {
4501  int32_t offset = branch_offset(l);
4502  if (is_int16(offset)) {
4503#if V8_TARGET_ARCH_S390X
4504    brctg(r1, Operand(offset));
4505#else
4506    brct(r1, Operand(offset));
4507#endif
4508  } else {
4509    AddP(r1, Operand(-1));
4510    Branch(ne, Operand(offset));
4511  }
4512}
4513
4514void MacroAssembler::LoadIntLiteral(Register dst, int value) {
4515  Load(dst, Operand(value));
4516}
4517
4518void MacroAssembler::LoadSmiLiteral(Register dst, Smi* smi) {
4519  intptr_t value = reinterpret_cast<intptr_t>(smi);
4520#if V8_TARGET_ARCH_S390X
4521  DCHECK((value & 0xffffffff) == 0);
4522  // The smi value is loaded in upper 32-bits.  Lower 32-bit are zeros.
4523  llihf(dst, Operand(value >> 32));
4524#else
4525  llilf(dst, Operand(value));
4526#endif
4527}
4528
4529void MacroAssembler::LoadDoubleLiteral(DoubleRegister result, uint64_t value,
4530                                       Register scratch) {
4531  uint32_t hi_32 = value >> 32;
4532  uint32_t lo_32 = static_cast<uint32_t>(value);
4533
4534  // Load the 64-bit value into a GPR, then transfer it to FPR via LDGR
4535  if (value == 0) {
4536    lzdr(result);
4537  } else if (lo_32 == 0) {
4538    llihf(scratch, Operand(hi_32));
4539    ldgr(result, scratch);
4540  } else {
4541    iihf(scratch, Operand(hi_32));
4542    iilf(scratch, Operand(lo_32));
4543    ldgr(result, scratch);
4544  }
4545}
4546
4547void MacroAssembler::LoadDoubleLiteral(DoubleRegister result, double value,
4548                                       Register scratch) {
4549  uint64_t int_val = bit_cast<uint64_t, double>(value);
4550  LoadDoubleLiteral(result, int_val, scratch);
4551}
4552
4553void MacroAssembler::LoadFloat32Literal(DoubleRegister result, float value,
4554                                        Register scratch) {
4555  uint64_t int_val = static_cast<uint64_t>(bit_cast<uint32_t, float>(value))
4556                     << 32;
4557  LoadDoubleLiteral(result, int_val, scratch);
4558}
4559
4560void MacroAssembler::CmpSmiLiteral(Register src1, Smi* smi, Register scratch) {
4561#if V8_TARGET_ARCH_S390X
4562  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4563    cih(src1, Operand(reinterpret_cast<intptr_t>(smi) >> 32));
4564  } else {
4565    LoadSmiLiteral(scratch, smi);
4566    cgr(src1, scratch);
4567  }
4568#else
4569  // CFI takes 32-bit immediate.
4570  cfi(src1, Operand(smi));
4571#endif
4572}
4573
4574void MacroAssembler::CmpLogicalSmiLiteral(Register src1, Smi* smi,
4575                                          Register scratch) {
4576#if V8_TARGET_ARCH_S390X
4577  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4578    clih(src1, Operand(reinterpret_cast<intptr_t>(smi) >> 32));
4579  } else {
4580    LoadSmiLiteral(scratch, smi);
4581    clgr(src1, scratch);
4582  }
4583#else
4584  // CLFI takes 32-bit immediate
4585  clfi(src1, Operand(smi));
4586#endif
4587}
4588
4589void MacroAssembler::AddSmiLiteral(Register dst, Register src, Smi* smi,
4590                                   Register scratch) {
4591#if V8_TARGET_ARCH_S390X
4592  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4593    if (!dst.is(src)) LoadRR(dst, src);
4594    aih(dst, Operand(reinterpret_cast<intptr_t>(smi) >> 32));
4595  } else {
4596    LoadSmiLiteral(scratch, smi);
4597    AddP(dst, src, scratch);
4598  }
4599#else
4600  AddP(dst, src, Operand(reinterpret_cast<intptr_t>(smi)));
4601#endif
4602}
4603
4604void MacroAssembler::SubSmiLiteral(Register dst, Register src, Smi* smi,
4605                                   Register scratch) {
4606#if V8_TARGET_ARCH_S390X
4607  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4608    if (!dst.is(src)) LoadRR(dst, src);
4609    aih(dst, Operand((-reinterpret_cast<intptr_t>(smi)) >> 32));
4610  } else {
4611    LoadSmiLiteral(scratch, smi);
4612    SubP(dst, src, scratch);
4613  }
4614#else
4615  AddP(dst, src, Operand(-(reinterpret_cast<intptr_t>(smi))));
4616#endif
4617}
4618
4619void MacroAssembler::AndSmiLiteral(Register dst, Register src, Smi* smi) {
4620  if (!dst.is(src)) LoadRR(dst, src);
4621#if V8_TARGET_ARCH_S390X
4622  DCHECK((reinterpret_cast<intptr_t>(smi) & 0xffffffff) == 0);
4623  int value = static_cast<int>(reinterpret_cast<intptr_t>(smi) >> 32);
4624  nihf(dst, Operand(value));
4625#else
4626  nilf(dst, Operand(reinterpret_cast<int>(smi)));
4627#endif
4628}
4629
4630// Load a "pointer" sized value from the memory location
4631void MacroAssembler::LoadP(Register dst, const MemOperand& mem,
4632                           Register scratch) {
4633  int offset = mem.offset();
4634
4635  if (!scratch.is(no_reg) && !is_int20(offset)) {
4636    /* cannot use d-form */
4637    LoadIntLiteral(scratch, offset);
4638#if V8_TARGET_ARCH_S390X
4639    lg(dst, MemOperand(mem.rb(), scratch));
4640#else
4641    l(dst, MemOperand(mem.rb(), scratch));
4642#endif
4643  } else {
4644#if V8_TARGET_ARCH_S390X
4645    lg(dst, mem);
4646#else
4647    if (is_uint12(offset)) {
4648      l(dst, mem);
4649    } else {
4650      ly(dst, mem);
4651    }
4652#endif
4653  }
4654}
4655
4656// Store a "pointer" sized value to the memory location
4657void MacroAssembler::StoreP(Register src, const MemOperand& mem,
4658                            Register scratch) {
4659  if (!is_int20(mem.offset())) {
4660    DCHECK(!scratch.is(no_reg));
4661    DCHECK(!scratch.is(r0));
4662    LoadIntLiteral(scratch, mem.offset());
4663#if V8_TARGET_ARCH_S390X
4664    stg(src, MemOperand(mem.rb(), scratch));
4665#else
4666    st(src, MemOperand(mem.rb(), scratch));
4667#endif
4668  } else {
4669#if V8_TARGET_ARCH_S390X
4670    stg(src, mem);
4671#else
4672    // StoreW will try to generate ST if offset fits, otherwise
4673    // it'll generate STY.
4674    StoreW(src, mem);
4675#endif
4676  }
4677}
4678
4679// Store a "pointer" sized constant to the memory location
4680void MacroAssembler::StoreP(const MemOperand& mem, const Operand& opnd,
4681                            Register scratch) {
4682  // Relocations not supported
4683  DCHECK(opnd.rmode_ == kRelocInfo_NONEPTR);
4684
4685  // Try to use MVGHI/MVHI
4686  if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT) && is_uint12(mem.offset()) &&
4687      mem.getIndexRegister().is(r0) && is_int16(opnd.imm_)) {
4688#if V8_TARGET_ARCH_S390X
4689    mvghi(mem, opnd);
4690#else
4691    mvhi(mem, opnd);
4692#endif
4693  } else {
4694    LoadImmP(scratch, opnd);
4695    StoreP(scratch, mem);
4696  }
4697}
4698
4699void MacroAssembler::LoadMultipleP(Register dst1, Register dst2,
4700                                   const MemOperand& mem) {
4701#if V8_TARGET_ARCH_S390X
4702  DCHECK(is_int20(mem.offset()));
4703  lmg(dst1, dst2, mem);
4704#else
4705  if (is_uint12(mem.offset())) {
4706    lm(dst1, dst2, mem);
4707  } else {
4708    DCHECK(is_int20(mem.offset()));
4709    lmy(dst1, dst2, mem);
4710  }
4711#endif
4712}
4713
4714void MacroAssembler::StoreMultipleP(Register src1, Register src2,
4715                                    const MemOperand& mem) {
4716#if V8_TARGET_ARCH_S390X
4717  DCHECK(is_int20(mem.offset()));
4718  stmg(src1, src2, mem);
4719#else
4720  if (is_uint12(mem.offset())) {
4721    stm(src1, src2, mem);
4722  } else {
4723    DCHECK(is_int20(mem.offset()));
4724    stmy(src1, src2, mem);
4725  }
4726#endif
4727}
4728
4729void MacroAssembler::LoadMultipleW(Register dst1, Register dst2,
4730                                   const MemOperand& mem) {
4731  if (is_uint12(mem.offset())) {
4732    lm(dst1, dst2, mem);
4733  } else {
4734    DCHECK(is_int20(mem.offset()));
4735    lmy(dst1, dst2, mem);
4736  }
4737}
4738
4739void MacroAssembler::StoreMultipleW(Register src1, Register src2,
4740                                    const MemOperand& mem) {
4741  if (is_uint12(mem.offset())) {
4742    stm(src1, src2, mem);
4743  } else {
4744    DCHECK(is_int20(mem.offset()));
4745    stmy(src1, src2, mem);
4746  }
4747}
4748
4749// Load 32-bits and sign extend if necessary.
4750void MacroAssembler::LoadW(Register dst, Register src) {
4751#if V8_TARGET_ARCH_S390X
4752  lgfr(dst, src);
4753#else
4754  if (!dst.is(src)) lr(dst, src);
4755#endif
4756}
4757
4758// Load 32-bits and sign extend if necessary.
4759void MacroAssembler::LoadW(Register dst, const MemOperand& mem,
4760                           Register scratch) {
4761  int offset = mem.offset();
4762
4763  if (!is_int20(offset)) {
4764    DCHECK(!scratch.is(no_reg));
4765    LoadIntLiteral(scratch, offset);
4766#if V8_TARGET_ARCH_S390X
4767    lgf(dst, MemOperand(mem.rb(), scratch));
4768#else
4769    l(dst, MemOperand(mem.rb(), scratch));
4770#endif
4771  } else {
4772#if V8_TARGET_ARCH_S390X
4773    lgf(dst, mem);
4774#else
4775    if (is_uint12(offset)) {
4776      l(dst, mem);
4777    } else {
4778      ly(dst, mem);
4779    }
4780#endif
4781  }
4782}
4783
4784// Load 32-bits and zero extend if necessary.
4785void MacroAssembler::LoadlW(Register dst, Register src) {
4786#if V8_TARGET_ARCH_S390X
4787  llgfr(dst, src);
4788#else
4789  if (!dst.is(src)) lr(dst, src);
4790#endif
4791}
4792
4793// Variable length depending on whether offset fits into immediate field
4794// MemOperand of RX or RXY format
4795void MacroAssembler::LoadlW(Register dst, const MemOperand& mem,
4796                            Register scratch) {
4797  Register base = mem.rb();
4798  int offset = mem.offset();
4799
4800#if V8_TARGET_ARCH_S390X
4801  if (is_int20(offset)) {
4802    llgf(dst, mem);
4803  } else if (!scratch.is(no_reg)) {
4804    // Materialize offset into scratch register.
4805    LoadIntLiteral(scratch, offset);
4806    llgf(dst, MemOperand(base, scratch));
4807  } else {
4808    DCHECK(false);
4809  }
4810#else
4811  bool use_RXform = false;
4812  bool use_RXYform = false;
4813  if (is_uint12(offset)) {
4814    // RX-format supports unsigned 12-bits offset.
4815    use_RXform = true;
4816  } else if (is_int20(offset)) {
4817    // RXY-format supports signed 20-bits offset.
4818    use_RXYform = true;
4819  } else if (!scratch.is(no_reg)) {
4820    // Materialize offset into scratch register.
4821    LoadIntLiteral(scratch, offset);
4822  } else {
4823    DCHECK(false);
4824  }
4825
4826  if (use_RXform) {
4827    l(dst, mem);
4828  } else if (use_RXYform) {
4829    ly(dst, mem);
4830  } else {
4831    ly(dst, MemOperand(base, scratch));
4832  }
4833#endif
4834}
4835
4836void MacroAssembler::LoadLogicalHalfWordP(Register dst, const MemOperand& mem) {
4837#if V8_TARGET_ARCH_S390X
4838  llgh(dst, mem);
4839#else
4840  llh(dst, mem);
4841#endif
4842}
4843
4844void MacroAssembler::LoadLogicalHalfWordP(Register dst, Register src) {
4845#if V8_TARGET_ARCH_S390X
4846  llghr(dst, src);
4847#else
4848  llhr(dst, src);
4849#endif
4850}
4851
4852void MacroAssembler::LoadB(Register dst, const MemOperand& mem) {
4853#if V8_TARGET_ARCH_S390X
4854  lgb(dst, mem);
4855#else
4856  lb(dst, mem);
4857#endif
4858}
4859
4860void MacroAssembler::LoadB(Register dst, Register src) {
4861#if V8_TARGET_ARCH_S390X
4862  lgbr(dst, src);
4863#else
4864  lbr(dst, src);
4865#endif
4866}
4867
4868void MacroAssembler::LoadlB(Register dst, const MemOperand& mem) {
4869#if V8_TARGET_ARCH_S390X
4870  llgc(dst, mem);
4871#else
4872  llc(dst, mem);
4873#endif
4874}
4875
4876void MacroAssembler::LoadlB(Register dst, Register src) {
4877#if V8_TARGET_ARCH_S390X
4878  llgcr(dst, src);
4879#else
4880  llcr(dst, src);
4881#endif
4882}
4883
4884void MacroAssembler::LoadLogicalReversedWordP(Register dst,
4885                                              const MemOperand& mem) {
4886  lrv(dst, mem);
4887  LoadlW(dst, dst);
4888}
4889
4890
4891void MacroAssembler::LoadLogicalReversedHalfWordP(Register dst,
4892                                              const MemOperand& mem) {
4893  lrvh(dst, mem);
4894  LoadLogicalHalfWordP(dst, dst);
4895}
4896
4897
4898// Load And Test (Reg <- Reg)
4899void MacroAssembler::LoadAndTest32(Register dst, Register src) {
4900  ltr(dst, src);
4901}
4902
4903// Load And Test
4904//     (Register dst(ptr) = Register src (32 | 32->64))
4905// src is treated as a 32-bit signed integer, which is sign extended to
4906// 64-bit if necessary.
4907void MacroAssembler::LoadAndTestP_ExtendSrc(Register dst, Register src) {
4908#if V8_TARGET_ARCH_S390X
4909  ltgfr(dst, src);
4910#else
4911  ltr(dst, src);
4912#endif
4913}
4914
4915// Load And Test Pointer Sized (Reg <- Reg)
4916void MacroAssembler::LoadAndTestP(Register dst, Register src) {
4917#if V8_TARGET_ARCH_S390X
4918  ltgr(dst, src);
4919#else
4920  ltr(dst, src);
4921#endif
4922}
4923
4924// Load And Test 32-bit (Reg <- Mem)
4925void MacroAssembler::LoadAndTest32(Register dst, const MemOperand& mem) {
4926  lt_z(dst, mem);
4927}
4928
4929// Load And Test Pointer Sized (Reg <- Mem)
4930void MacroAssembler::LoadAndTestP(Register dst, const MemOperand& mem) {
4931#if V8_TARGET_ARCH_S390X
4932  ltg(dst, mem);
4933#else
4934  lt_z(dst, mem);
4935#endif
4936}
4937
4938// Load On Condition Pointer Sized (Reg <- Reg)
4939void MacroAssembler::LoadOnConditionP(Condition cond, Register dst,
4940                                      Register src) {
4941#if V8_TARGET_ARCH_S390X
4942  locgr(cond, dst, src);
4943#else
4944  locr(cond, dst, src);
4945#endif
4946}
4947
4948// Load Double Precision (64-bit) Floating Point number from memory
4949void MacroAssembler::LoadDouble(DoubleRegister dst, const MemOperand& mem) {
4950  // for 32bit and 64bit we all use 64bit floating point regs
4951  if (is_uint12(mem.offset())) {
4952    ld(dst, mem);
4953  } else {
4954    ldy(dst, mem);
4955  }
4956}
4957
4958// Load Single Precision (32-bit) Floating Point number from memory
4959void MacroAssembler::LoadFloat32(DoubleRegister dst, const MemOperand& mem) {
4960  if (is_uint12(mem.offset())) {
4961    le_z(dst, mem);
4962  } else {
4963    DCHECK(is_int20(mem.offset()));
4964    ley(dst, mem);
4965  }
4966}
4967
4968// Load Single Precision (32-bit) Floating Point number from memory,
4969// and convert to Double Precision (64-bit)
4970void MacroAssembler::LoadFloat32ConvertToDouble(DoubleRegister dst,
4971                                                const MemOperand& mem) {
4972  LoadFloat32(dst, mem);
4973  ldebr(dst, dst);
4974}
4975
4976// Store Double Precision (64-bit) Floating Point number to memory
4977void MacroAssembler::StoreDouble(DoubleRegister dst, const MemOperand& mem) {
4978  if (is_uint12(mem.offset())) {
4979    std(dst, mem);
4980  } else {
4981    stdy(dst, mem);
4982  }
4983}
4984
4985// Store Single Precision (32-bit) Floating Point number to memory
4986void MacroAssembler::StoreFloat32(DoubleRegister src, const MemOperand& mem) {
4987  if (is_uint12(mem.offset())) {
4988    ste(src, mem);
4989  } else {
4990    stey(src, mem);
4991  }
4992}
4993
4994// Convert Double precision (64-bit) to Single Precision (32-bit)
4995// and store resulting Float32 to memory
4996void MacroAssembler::StoreDoubleAsFloat32(DoubleRegister src,
4997                                          const MemOperand& mem,
4998                                          DoubleRegister scratch) {
4999  ledbr(scratch, src);
5000  StoreFloat32(scratch, mem);
5001}
5002
5003// Variable length depending on whether offset fits into immediate field
5004// MemOperand of RX or RXY format
5005void MacroAssembler::StoreW(Register src, const MemOperand& mem,
5006                            Register scratch) {
5007  Register base = mem.rb();
5008  int offset = mem.offset();
5009
5010  bool use_RXform = false;
5011  bool use_RXYform = false;
5012
5013  if (is_uint12(offset)) {
5014    // RX-format supports unsigned 12-bits offset.
5015    use_RXform = true;
5016  } else if (is_int20(offset)) {
5017    // RXY-format supports signed 20-bits offset.
5018    use_RXYform = true;
5019  } else if (!scratch.is(no_reg)) {
5020    // Materialize offset into scratch register.
5021    LoadIntLiteral(scratch, offset);
5022  } else {
5023    // scratch is no_reg
5024    DCHECK(false);
5025  }
5026
5027  if (use_RXform) {
5028    st(src, mem);
5029  } else if (use_RXYform) {
5030    sty(src, mem);
5031  } else {
5032    StoreW(src, MemOperand(base, scratch));
5033  }
5034}
5035
5036// Loads 16-bits half-word value from memory and sign extends to pointer
5037// sized register
5038void MacroAssembler::LoadHalfWordP(Register dst, const MemOperand& mem,
5039                                   Register scratch) {
5040  Register base = mem.rb();
5041  int offset = mem.offset();
5042
5043  if (!is_int20(offset)) {
5044    DCHECK(!scratch.is(no_reg));
5045    LoadIntLiteral(scratch, offset);
5046#if V8_TARGET_ARCH_S390X
5047    lgh(dst, MemOperand(base, scratch));
5048#else
5049    lh(dst, MemOperand(base, scratch));
5050#endif
5051  } else {
5052#if V8_TARGET_ARCH_S390X
5053    lgh(dst, mem);
5054#else
5055    if (is_uint12(offset)) {
5056      lh(dst, mem);
5057    } else {
5058      lhy(dst, mem);
5059    }
5060#endif
5061  }
5062}
5063
5064// Variable length depending on whether offset fits into immediate field
5065// MemOperand current only supports d-form
5066void MacroAssembler::StoreHalfWord(Register src, const MemOperand& mem,
5067                                   Register scratch) {
5068  Register base = mem.rb();
5069  int offset = mem.offset();
5070
5071  if (is_uint12(offset)) {
5072    sth(src, mem);
5073  } else if (is_int20(offset)) {
5074    sthy(src, mem);
5075  } else {
5076    DCHECK(!scratch.is(no_reg));
5077    LoadIntLiteral(scratch, offset);
5078    sth(src, MemOperand(base, scratch));
5079  }
5080}
5081
5082// Variable length depending on whether offset fits into immediate field
5083// MemOperand current only supports d-form
5084void MacroAssembler::StoreByte(Register src, const MemOperand& mem,
5085                               Register scratch) {
5086  Register base = mem.rb();
5087  int offset = mem.offset();
5088
5089  if (is_uint12(offset)) {
5090    stc(src, mem);
5091  } else if (is_int20(offset)) {
5092    stcy(src, mem);
5093  } else {
5094    DCHECK(!scratch.is(no_reg));
5095    LoadIntLiteral(scratch, offset);
5096    stc(src, MemOperand(base, scratch));
5097  }
5098}
5099
5100// Shift left logical for 32-bit integer types.
5101void MacroAssembler::ShiftLeft(Register dst, Register src, const Operand& val) {
5102  if (dst.is(src)) {
5103    sll(dst, val);
5104  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5105    sllk(dst, src, val);
5106  } else {
5107    lr(dst, src);
5108    sll(dst, val);
5109  }
5110}
5111
5112// Shift left logical for 32-bit integer types.
5113void MacroAssembler::ShiftLeft(Register dst, Register src, Register val) {
5114  if (dst.is(src)) {
5115    sll(dst, val);
5116  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5117    sllk(dst, src, val);
5118  } else {
5119    DCHECK(!dst.is(val));  // The lr/sll path clobbers val.
5120    lr(dst, src);
5121    sll(dst, val);
5122  }
5123}
5124
5125// Shift right logical for 32-bit integer types.
5126void MacroAssembler::ShiftRight(Register dst, Register src,
5127                                const Operand& val) {
5128  if (dst.is(src)) {
5129    srl(dst, val);
5130  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5131    srlk(dst, src, val);
5132  } else {
5133    lr(dst, src);
5134    srl(dst, val);
5135  }
5136}
5137
5138// Shift right logical for 32-bit integer types.
5139void MacroAssembler::ShiftRight(Register dst, Register src, Register val) {
5140  if (dst.is(src)) {
5141    srl(dst, val);
5142  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5143    srlk(dst, src, val);
5144  } else {
5145    DCHECK(!dst.is(val));  // The lr/srl path clobbers val.
5146    lr(dst, src);
5147    srl(dst, val);
5148  }
5149}
5150
5151// Shift left arithmetic for 32-bit integer types.
5152void MacroAssembler::ShiftLeftArith(Register dst, Register src,
5153                                    const Operand& val) {
5154  if (dst.is(src)) {
5155    sla(dst, val);
5156  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5157    slak(dst, src, val);
5158  } else {
5159    lr(dst, src);
5160    sla(dst, val);
5161  }
5162}
5163
5164// Shift left arithmetic for 32-bit integer types.
5165void MacroAssembler::ShiftLeftArith(Register dst, Register src, Register val) {
5166  if (dst.is(src)) {
5167    sla(dst, val);
5168  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5169    slak(dst, src, val);
5170  } else {
5171    DCHECK(!dst.is(val));  // The lr/sla path clobbers val.
5172    lr(dst, src);
5173    sla(dst, val);
5174  }
5175}
5176
5177// Shift right arithmetic for 32-bit integer types.
5178void MacroAssembler::ShiftRightArith(Register dst, Register src,
5179                                     const Operand& val) {
5180  if (dst.is(src)) {
5181    sra(dst, val);
5182  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5183    srak(dst, src, val);
5184  } else {
5185    lr(dst, src);
5186    sra(dst, val);
5187  }
5188}
5189
5190// Shift right arithmetic for 32-bit integer types.
5191void MacroAssembler::ShiftRightArith(Register dst, Register src, Register val) {
5192  if (dst.is(src)) {
5193    sra(dst, val);
5194  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
5195    srak(dst, src, val);
5196  } else {
5197    DCHECK(!dst.is(val));  // The lr/sra path clobbers val.
5198    lr(dst, src);
5199    sra(dst, val);
5200  }
5201}
5202
5203// Clear right most # of bits
5204void MacroAssembler::ClearRightImm(Register dst, Register src,
5205                                   const Operand& val) {
5206  int numBitsToClear = val.imm_ % (kPointerSize * 8);
5207
5208  // Try to use RISBG if possible
5209  if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
5210    int endBit = 63 - numBitsToClear;
5211    risbg(dst, src, Operand::Zero(), Operand(endBit), Operand::Zero(), true);
5212    return;
5213  }
5214
5215  uint64_t hexMask = ~((1L << numBitsToClear) - 1);
5216
5217  // S390 AND instr clobbers source.  Make a copy if necessary
5218  if (!dst.is(src)) LoadRR(dst, src);
5219
5220  if (numBitsToClear <= 16) {
5221    nill(dst, Operand(static_cast<uint16_t>(hexMask)));
5222  } else if (numBitsToClear <= 32) {
5223    nilf(dst, Operand(static_cast<uint32_t>(hexMask)));
5224  } else if (numBitsToClear <= 64) {
5225    nilf(dst, Operand(static_cast<intptr_t>(0)));
5226    nihf(dst, Operand(hexMask >> 32));
5227  }
5228}
5229
5230void MacroAssembler::Popcnt32(Register dst, Register src) {
5231  DCHECK(!src.is(r0));
5232  DCHECK(!dst.is(r0));
5233
5234  popcnt(dst, src);
5235  ShiftRight(r0, dst, Operand(16));
5236  ar(dst, r0);
5237  ShiftRight(r0, dst, Operand(8));
5238  ar(dst, r0);
5239  LoadlB(dst, dst);
5240}
5241
5242#ifdef V8_TARGET_ARCH_S390X
5243void MacroAssembler::Popcnt64(Register dst, Register src) {
5244  DCHECK(!src.is(r0));
5245  DCHECK(!dst.is(r0));
5246
5247  popcnt(dst, src);
5248  ShiftRightP(r0, dst, Operand(32));
5249  AddP(dst, r0);
5250  ShiftRightP(r0, dst, Operand(16));
5251  AddP(dst, r0);
5252  ShiftRightP(r0, dst, Operand(8));
5253  AddP(dst, r0);
5254  LoadlB(dst, dst);
5255}
5256#endif
5257
5258#ifdef DEBUG
5259bool AreAliased(Register reg1, Register reg2, Register reg3, Register reg4,
5260                Register reg5, Register reg6, Register reg7, Register reg8,
5261                Register reg9, Register reg10) {
5262  int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() + reg3.is_valid() +
5263                        reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
5264                        reg7.is_valid() + reg8.is_valid() + reg9.is_valid() +
5265                        reg10.is_valid();
5266
5267  RegList regs = 0;
5268  if (reg1.is_valid()) regs |= reg1.bit();
5269  if (reg2.is_valid()) regs |= reg2.bit();
5270  if (reg3.is_valid()) regs |= reg3.bit();
5271  if (reg4.is_valid()) regs |= reg4.bit();
5272  if (reg5.is_valid()) regs |= reg5.bit();
5273  if (reg6.is_valid()) regs |= reg6.bit();
5274  if (reg7.is_valid()) regs |= reg7.bit();
5275  if (reg8.is_valid()) regs |= reg8.bit();
5276  if (reg9.is_valid()) regs |= reg9.bit();
5277  if (reg10.is_valid()) regs |= reg10.bit();
5278  int n_of_non_aliasing_regs = NumRegs(regs);
5279
5280  return n_of_valid_regs != n_of_non_aliasing_regs;
5281}
5282#endif
5283
5284CodePatcher::CodePatcher(Isolate* isolate, byte* address, int size,
5285                         FlushICache flush_cache)
5286    : address_(address),
5287      size_(size),
5288      masm_(isolate, address, size_ + Assembler::kGap, CodeObjectRequired::kNo),
5289      flush_cache_(flush_cache) {
5290  // Create a new macro assembler pointing to the address of the code to patch.
5291  // The size is adjusted with kGap on order for the assembler to generate size
5292  // bytes of instructions without failing with buffer size constraints.
5293  DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
5294}
5295
5296CodePatcher::~CodePatcher() {
5297  // Indicate that code has changed.
5298  if (flush_cache_ == FLUSH) {
5299    Assembler::FlushICache(masm_.isolate(), address_, size_);
5300  }
5301
5302  // Check that the code was patched as expected.
5303  DCHECK(masm_.pc_ == address_ + size_);
5304  DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
5305}
5306
5307void MacroAssembler::TruncatingDiv(Register result, Register dividend,
5308                                   int32_t divisor) {
5309  DCHECK(!dividend.is(result));
5310  DCHECK(!dividend.is(r0));
5311  DCHECK(!result.is(r0));
5312  base::MagicNumbersForDivision<uint32_t> mag =
5313      base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
5314#ifdef V8_TARGET_ARCH_S390X
5315  LoadRR(result, dividend);
5316  MulP(result, Operand(mag.multiplier));
5317  ShiftRightArithP(result, result, Operand(32));
5318
5319#else
5320  lay(sp, MemOperand(sp, -kPointerSize));
5321  StoreP(r1, MemOperand(sp));
5322
5323  mov(r1, Operand(mag.multiplier));
5324  mr_z(r0, dividend);  // r0:r1 = r1 * dividend
5325
5326  LoadRR(result, r0);
5327  LoadP(r1, MemOperand(sp));
5328  la(sp, MemOperand(sp, kPointerSize));
5329#endif
5330  bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
5331  if (divisor > 0 && neg) {
5332    AddP(result, dividend);
5333  }
5334  if (divisor < 0 && !neg && mag.multiplier > 0) {
5335    SubP(result, dividend);
5336  }
5337  if (mag.shift > 0) ShiftRightArith(result, result, Operand(mag.shift));
5338  ExtractBit(r0, dividend, 31);
5339  AddP(result, r0);
5340}
5341
5342}  // namespace internal
5343}  // namespace v8
5344
5345#endif  // V8_TARGET_ARCH_S390
5346