V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
macro-assembler-s390.cc
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/callable.h"
14 #include "src/code-factory.h"
15 #include "src/code-stubs.h"
16 #include "src/counters.h"
17 #include "src/debug/debug.h"
18 #include "src/external-reference-table.h"
19 #include "src/frames-inl.h"
20 #include "src/macro-assembler.h"
21 #include "src/objects/smi.h"
22 #include "src/register-configuration.h"
23 #include "src/runtime/runtime.h"
24 #include "src/snapshot/embedded-data.h"
25 #include "src/snapshot/snapshot.h"
26 #include "src/wasm/wasm-code-manager.h"
27 
28 // Satisfy cpplint check, but don't include platform-specific header. It is
29 // included recursively via macro-assembler.h.
30 #if 0
31 #include "src/s390/macro-assembler-s390.h"
32 #endif
33 
34 namespace v8 {
35 namespace internal {
36 
37 MacroAssembler::MacroAssembler(Isolate* isolate,
38  const AssemblerOptions& options, void* buffer,
39  int size, CodeObjectRequired create_code_object)
40  : TurboAssembler(isolate, options, buffer, size, create_code_object) {
41  if (create_code_object == CodeObjectRequired::kYes) {
42  // Unlike TurboAssembler, which can be used off the main thread and may not
43  // allocate, macro assembler creates its own copy of the self-reference
44  // marker in order to disambiguate between self-references during nested
45  // code generation (e.g.: codegen of the current object triggers stub
46  // compilation through CodeStub::GetCode()).
47  code_object_ = Handle<HeapObject>::New(
48  *isolate->factory()->NewSelfReferenceMarker(), isolate);
49  }
50 }
51 
52 int TurboAssembler::RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
53  Register exclusion1,
54  Register exclusion2,
55  Register exclusion3) const {
56  int bytes = 0;
57  RegList exclusions = 0;
58  if (exclusion1 != no_reg) {
59  exclusions |= exclusion1.bit();
60  if (exclusion2 != no_reg) {
61  exclusions |= exclusion2.bit();
62  if (exclusion3 != no_reg) {
63  exclusions |= exclusion3.bit();
64  }
65  }
66  }
67 
68  RegList list = kJSCallerSaved & ~exclusions;
69  bytes += NumRegs(list) * kPointerSize;
70 
71  if (fp_mode == kSaveFPRegs) {
72  bytes += NumRegs(kCallerSavedDoubles) * kDoubleSize;
73  }
74 
75  return bytes;
76 }
77 
78 int TurboAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1,
79  Register exclusion2, Register exclusion3) {
80  int bytes = 0;
81  RegList exclusions = 0;
82  if (exclusion1 != no_reg) {
83  exclusions |= exclusion1.bit();
84  if (exclusion2 != no_reg) {
85  exclusions |= exclusion2.bit();
86  if (exclusion3 != no_reg) {
87  exclusions |= exclusion3.bit();
88  }
89  }
90  }
91 
92  RegList list = kJSCallerSaved & ~exclusions;
93  MultiPush(list);
94  bytes += NumRegs(list) * kPointerSize;
95 
96  if (fp_mode == kSaveFPRegs) {
97  MultiPushDoubles(kCallerSavedDoubles);
98  bytes += NumRegs(kCallerSavedDoubles) * kDoubleSize;
99  }
100 
101  return bytes;
102 }
103 
104 int TurboAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1,
105  Register exclusion2, Register exclusion3) {
106  int bytes = 0;
107  if (fp_mode == kSaveFPRegs) {
108  MultiPopDoubles(kCallerSavedDoubles);
109  bytes += NumRegs(kCallerSavedDoubles) * kDoubleSize;
110  }
111 
112  RegList exclusions = 0;
113  if (exclusion1 != no_reg) {
114  exclusions |= exclusion1.bit();
115  if (exclusion2 != no_reg) {
116  exclusions |= exclusion2.bit();
117  if (exclusion3 != no_reg) {
118  exclusions |= exclusion3.bit();
119  }
120  }
121  }
122 
123  RegList list = kJSCallerSaved & ~exclusions;
124  MultiPop(list);
125  bytes += NumRegs(list) * kPointerSize;
126 
127  return bytes;
128 }
129 
130 void TurboAssembler::LoadFromConstantsTable(Register destination,
131  int constant_index) {
132  DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kBuiltinsConstantsTable));
133 
134  const uint32_t offset =
135  FixedArray::kHeaderSize + constant_index * kPointerSize - kHeapObjectTag;
136 
137  CHECK(is_uint19(offset));
138  DCHECK_NE(destination, r0);
139  LoadRoot(destination, RootIndex::kBuiltinsConstantsTable);
140  LoadP(destination, MemOperand(destination, offset), r1);
141 }
142 
143 void TurboAssembler::LoadRootRelative(Register destination, int32_t offset) {
144  LoadP(destination, MemOperand(kRootRegister, offset));
145 }
146 
147 void TurboAssembler::LoadRootRegisterOffset(Register destination,
148  intptr_t offset) {
149  if (offset == 0) {
150  LoadRR(destination, kRootRegister);
151  } else if (is_uint12(offset)) {
152  la(destination, MemOperand(kRootRegister, offset));
153  } else {
154  DCHECK(is_int20(offset));
155  lay(destination, MemOperand(kRootRegister, offset));
156  }
157 }
158 
159 void TurboAssembler::Jump(Register target, Condition cond) { b(cond, target); }
160 
161 void MacroAssembler::JumpToJSEntry(Register target) {
162  Move(ip, target);
163  Jump(ip);
164 }
165 
166 void TurboAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
167  Condition cond) {
168  Label skip;
169 
170  if (cond != al) b(NegateCondition(cond), &skip);
171 
172  DCHECK(rmode == RelocInfo::CODE_TARGET || rmode == RelocInfo::RUNTIME_ENTRY);
173 
174  mov(ip, Operand(target, rmode));
175  b(ip);
176 
177  bind(&skip);
178 }
179 
180 void TurboAssembler::Jump(Address target, RelocInfo::Mode rmode,
181  Condition cond) {
182  DCHECK(!RelocInfo::IsCodeTarget(rmode));
183  Jump(static_cast<intptr_t>(target), rmode, cond);
184 }
185 
186 void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
187  Condition cond) {
188  DCHECK(RelocInfo::IsCodeTarget(rmode));
189  if (FLAG_embedded_builtins) {
190  if (root_array_available_ && options().isolate_independent_code) {
191  Register scratch = r1;
192  IndirectLoadConstant(scratch, code);
193  la(scratch, MemOperand(scratch, Code::kHeaderSize - kHeapObjectTag));
194  b(cond, scratch);
195  return;
196  } else if (options().inline_offheap_trampolines) {
197  int builtin_index = Builtins::kNoBuiltinId;
198  if (isolate()->builtins()->IsBuiltinHandle(code, &builtin_index) &&
199  Builtins::IsIsolateIndependent(builtin_index)) {
200  // Inline the trampoline.
201  RecordCommentForOffHeapTrampoline(builtin_index);
202  EmbeddedData d = EmbeddedData::FromBlob();
203  Address entry = d.InstructionStartOfBuiltin(builtin_index);
204  // Use ip directly instead of using UseScratchRegisterScope, as we do
205  // not preserve scratch registers across calls.
206  mov(ip, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
207  Jump(ip, cond);
208  return;
209  }
210  }
211  }
212  jump(code, rmode, cond);
213 }
214 
215 void TurboAssembler::Call(Register target) {
216  // Branch to target via indirect branch
217  basr(r14, target);
218 }
219 
220 void MacroAssembler::CallJSEntry(Register target) {
221  DCHECK(target == r4);
222  Call(target);
223 }
224 
225 int MacroAssembler::CallSizeNotPredictableCodeSize(Address target,
226  RelocInfo::Mode rmode,
227  Condition cond) {
228  // S390 Assembler::move sequence is IILF / IIHF
229  int size;
230 #if V8_TARGET_ARCH_S390X
231  size = 14; // IILF + IIHF + BASR
232 #else
233  size = 8; // IILF + BASR
234 #endif
235  return size;
236 }
237 
238 void TurboAssembler::Call(Address target, RelocInfo::Mode rmode,
239  Condition cond) {
240  DCHECK(cond == al);
241 
242  mov(ip, Operand(target, rmode));
243  basr(r14, ip);
244 }
245 
246 void TurboAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
247  Condition cond) {
248  DCHECK(RelocInfo::IsCodeTarget(rmode) && cond == al);
249 
250  if (FLAG_embedded_builtins) {
251  if (root_array_available_ && options().isolate_independent_code) {
252  // Use ip directly instead of using UseScratchRegisterScope, as we do not
253  // preserve scratch registers across calls.
254  IndirectLoadConstant(ip, code);
255  la(ip, MemOperand(ip, Code::kHeaderSize - kHeapObjectTag));
256  Call(ip);
257  return;
258  } else if (options().inline_offheap_trampolines) {
259  int builtin_index = Builtins::kNoBuiltinId;
260  if (isolate()->builtins()->IsBuiltinHandle(code, &builtin_index) &&
261  Builtins::IsIsolateIndependent(builtin_index)) {
262  // Inline the trampoline.
263  RecordCommentForOffHeapTrampoline(builtin_index);
264  DCHECK(Builtins::IsBuiltinId(builtin_index));
265  EmbeddedData d = EmbeddedData::FromBlob();
266  Address entry = d.InstructionStartOfBuiltin(builtin_index);
267  // Use ip directly instead of using UseScratchRegisterScope, as we do
268  // not preserve scratch registers across calls.
269  mov(ip, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
270  Call(ip);
271  return;
272  }
273  }
274  }
275  call(code, rmode);
276 }
277 
278 void TurboAssembler::Drop(int count) {
279  if (count > 0) {
280  int total = count * kPointerSize;
281  if (is_uint12(total)) {
282  la(sp, MemOperand(sp, total));
283  } else if (is_int20(total)) {
284  lay(sp, MemOperand(sp, total));
285  } else {
286  AddP(sp, Operand(total));
287  }
288  }
289 }
290 
291 void TurboAssembler::Drop(Register count, Register scratch) {
292  ShiftLeftP(scratch, count, Operand(kPointerSizeLog2));
293  AddP(sp, sp, scratch);
294 }
295 
296 void TurboAssembler::Call(Label* target) { b(r14, target); }
297 
298 void TurboAssembler::Push(Handle<HeapObject> handle) {
299  mov(r0, Operand(handle));
300  push(r0);
301 }
302 
303 void TurboAssembler::Push(Smi smi) {
304  mov(r0, Operand(smi));
305  push(r0);
306 }
307 
308 void TurboAssembler::Move(Register dst, Handle<HeapObject> value) {
309  if (FLAG_embedded_builtins) {
310  if (root_array_available_ && options().isolate_independent_code) {
311  IndirectLoadConstant(dst, value);
312  return;
313  }
314  }
315  mov(dst, Operand(value));
316 }
317 
318 void TurboAssembler::Move(Register dst, ExternalReference reference) {
319  if (FLAG_embedded_builtins) {
320  if (root_array_available_ && options().isolate_independent_code) {
321  IndirectLoadExternalReference(dst, reference);
322  return;
323  }
324  }
325  mov(dst, Operand(reference));
326 }
327 
328 void TurboAssembler::Move(Register dst, Register src, Condition cond) {
329  if (dst != src) {
330  if (cond == al) {
331  LoadRR(dst, src);
332  } else {
333  LoadOnConditionP(cond, dst, src);
334  }
335  }
336 }
337 
338 void TurboAssembler::Move(DoubleRegister dst, DoubleRegister src) {
339  if (dst != src) {
340  ldr(dst, src);
341  }
342 }
343 
344 // Wrapper around Assembler::mvc (SS-a format)
345 void TurboAssembler::MoveChar(const MemOperand& opnd1,
346  const MemOperand& opnd2,
347  const Operand& length) {
348  mvc(opnd1, opnd2, Operand(static_cast<intptr_t>(length.immediate() - 1)));
349 }
350 
351 // Wrapper around Assembler::clc (SS-a format)
352 void TurboAssembler::CompareLogicalChar(const MemOperand& opnd1,
353  const MemOperand& opnd2,
354  const Operand& length) {
355  clc(opnd1, opnd2, Operand(static_cast<intptr_t>(length.immediate() - 1)));
356 }
357 
358 // Wrapper around Assembler::xc (SS-a format)
359 void TurboAssembler::ExclusiveOrChar(const MemOperand& opnd1,
360  const MemOperand& opnd2,
361  const Operand& length) {
362  xc(opnd1, opnd2, Operand(static_cast<intptr_t>(length.immediate() - 1)));
363 }
364 
365 // Wrapper around Assembler::risbg(n) (RIE-f)
366 void TurboAssembler::RotateInsertSelectBits(Register dst, Register src,
367  const Operand& startBit, const Operand& endBit,
368  const Operand& shiftAmt, bool zeroBits) {
369  if (zeroBits)
370  // High tag the top bit of I4/EndBit to zero out any unselected bits
371  risbg(dst, src, startBit,
372  Operand(static_cast<intptr_t>(endBit.immediate() | 0x80)), shiftAmt);
373  else
374  risbg(dst, src, startBit, endBit, shiftAmt);
375 }
376 
377 void TurboAssembler::BranchRelativeOnIdxHighP(Register dst, Register inc,
378  Label* L) {
379 #if V8_TARGET_ARCH_S390X
380  brxhg(dst, inc, L);
381 #else
382  brxh(dst, inc, L);
383 #endif // V8_TARGET_ARCH_S390X
384 }
385 
386 void TurboAssembler::MultiPush(RegList regs, Register location) {
387  int16_t num_to_push = base::bits::CountPopulation(regs);
388  int16_t stack_offset = num_to_push * kPointerSize;
389 
390  SubP(location, location, Operand(stack_offset));
391  for (int16_t i = Register::kNumRegisters - 1; i >= 0; i--) {
392  if ((regs & (1 << i)) != 0) {
393  stack_offset -= kPointerSize;
394  StoreP(ToRegister(i), MemOperand(location, stack_offset));
395  }
396  }
397 }
398 
399 void TurboAssembler::MultiPop(RegList regs, Register location) {
400  int16_t stack_offset = 0;
401 
402  for (int16_t i = 0; i < Register::kNumRegisters; i++) {
403  if ((regs & (1 << i)) != 0) {
404  LoadP(ToRegister(i), MemOperand(location, stack_offset));
405  stack_offset += kPointerSize;
406  }
407  }
408  AddP(location, location, Operand(stack_offset));
409 }
410 
411 void TurboAssembler::MultiPushDoubles(RegList dregs, Register location) {
412  int16_t num_to_push = base::bits::CountPopulation(dregs);
413  int16_t stack_offset = num_to_push * kDoubleSize;
414 
415  SubP(location, location, Operand(stack_offset));
416  for (int16_t i = DoubleRegister::kNumRegisters - 1; i >= 0; i--) {
417  if ((dregs & (1 << i)) != 0) {
418  DoubleRegister dreg = DoubleRegister::from_code(i);
419  stack_offset -= kDoubleSize;
420  StoreDouble(dreg, MemOperand(location, stack_offset));
421  }
422  }
423 }
424 
425 void TurboAssembler::MultiPopDoubles(RegList dregs, Register location) {
426  int16_t stack_offset = 0;
427 
428  for (int16_t i = 0; i < DoubleRegister::kNumRegisters; i++) {
429  if ((dregs & (1 << i)) != 0) {
430  DoubleRegister dreg = DoubleRegister::from_code(i);
431  LoadDouble(dreg, MemOperand(location, stack_offset));
432  stack_offset += kDoubleSize;
433  }
434  }
435  AddP(location, location, Operand(stack_offset));
436 }
437 
438 void TurboAssembler::LoadRoot(Register destination, RootIndex index,
439  Condition) {
440  LoadP(destination,
441  MemOperand(kRootRegister, RootRegisterOffsetForRootIndex(index)), r0);
442 }
443 
444 void MacroAssembler::RecordWriteField(Register object, int offset,
445  Register value, Register dst,
446  LinkRegisterStatus lr_status,
447  SaveFPRegsMode save_fp,
448  RememberedSetAction remembered_set_action,
449  SmiCheck smi_check) {
450  // First, check if a write barrier is even needed. The tests below
451  // catch stores of Smis.
452  Label done;
453 
454  // Skip barrier if writing a smi.
455  if (smi_check == INLINE_SMI_CHECK) {
456  JumpIfSmi(value, &done);
457  }
458 
459  // Although the object register is tagged, the offset is relative to the start
460  // of the object, so so offset must be a multiple of kPointerSize.
461  DCHECK(IsAligned(offset, kPointerSize));
462 
463  lay(dst, MemOperand(object, offset - kHeapObjectTag));
464  if (emit_debug_code()) {
465  Label ok;
466  AndP(r0, dst, Operand(kPointerSize - 1));
467  beq(&ok, Label::kNear);
468  stop("Unaligned cell in write barrier");
469  bind(&ok);
470  }
471 
472  RecordWrite(object, dst, value, lr_status, save_fp, remembered_set_action,
473  OMIT_SMI_CHECK);
474 
475  bind(&done);
476 
477  // Clobber clobbered input registers when running with the debug-code flag
478  // turned on to provoke errors.
479  if (emit_debug_code()) {
480  mov(value, Operand(bit_cast<intptr_t>(kZapValue + 4)));
481  mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 8)));
482  }
483 }
484 
485 void TurboAssembler::SaveRegisters(RegList registers) {
486  DCHECK_GT(NumRegs(registers), 0);
487  RegList regs = 0;
488  for (int i = 0; i < Register::kNumRegisters; ++i) {
489  if ((registers >> i) & 1u) {
490  regs |= Register::from_code(i).bit();
491  }
492  }
493  MultiPush(regs);
494 }
495 
496 void TurboAssembler::RestoreRegisters(RegList registers) {
497  DCHECK_GT(NumRegs(registers), 0);
498  RegList regs = 0;
499  for (int i = 0; i < Register::kNumRegisters; ++i) {
500  if ((registers >> i) & 1u) {
501  regs |= Register::from_code(i).bit();
502  }
503  }
504  MultiPop(regs);
505 }
506 
507 void TurboAssembler::CallRecordWriteStub(
508  Register object, Register address,
509  RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode) {
510  CallRecordWriteStub(
511  object, address, remembered_set_action, fp_mode,
512  isolate()->builtins()->builtin_handle(Builtins::kRecordWrite),
513  kNullAddress);
514 }
515 
516 void TurboAssembler::CallRecordWriteStub(
517  Register object, Register address,
518  RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode,
519  Address wasm_target) {
520  CallRecordWriteStub(object, address, remembered_set_action, fp_mode,
521  Handle<Code>::null(), wasm_target);
522 }
523 
524 void TurboAssembler::CallRecordWriteStub(
525  Register object, Register address,
526  RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode,
527  Handle<Code> code_target, Address wasm_target) {
528  DCHECK_NE(code_target.is_null(), wasm_target == kNullAddress);
529  // TODO(albertnetymk): For now we ignore remembered_set_action and fp_mode,
530  // i.e. always emit remember set and save FP registers in RecordWriteStub. If
531  // large performance regression is observed, we should use these values to
532  // avoid unnecessary work.
533 
534  RecordWriteDescriptor descriptor;
535  RegList registers = descriptor.allocatable_registers();
536 
537  SaveRegisters(registers);
538  Register object_parameter(
539  descriptor.GetRegisterParameter(RecordWriteDescriptor::kObject));
540  Register slot_parameter(
541  descriptor.GetRegisterParameter(RecordWriteDescriptor::kSlot));
542  Register remembered_set_parameter(
543  descriptor.GetRegisterParameter(RecordWriteDescriptor::kRememberedSet));
544  Register fp_mode_parameter(
545  descriptor.GetRegisterParameter(RecordWriteDescriptor::kFPMode));
546 
547  Push(object);
548  Push(address);
549 
550  Pop(slot_parameter);
551  Pop(object_parameter);
552 
553  Move(remembered_set_parameter, Smi::FromEnum(remembered_set_action));
554  Move(fp_mode_parameter, Smi::FromEnum(fp_mode));
555  if (code_target.is_null()) {
556  Call(wasm_target, RelocInfo::WASM_STUB_CALL);
557  } else {
558  Call(code_target, RelocInfo::CODE_TARGET);
559  }
560 
561  RestoreRegisters(registers);
562 }
563 
564 // Will clobber 4 registers: object, address, scratch, ip. The
565 // register 'object' contains a heap object pointer. The heap object
566 // tag is shifted away.
567 void MacroAssembler::RecordWrite(Register object, Register address,
568  Register value, LinkRegisterStatus lr_status,
569  SaveFPRegsMode fp_mode,
570  RememberedSetAction remembered_set_action,
571  SmiCheck smi_check) {
572  DCHECK(object != value);
573  if (emit_debug_code()) {
574  CmpP(value, MemOperand(address));
575  Check(eq, AbortReason::kWrongAddressOrValuePassedToRecordWrite);
576  }
577 
578  if (remembered_set_action == OMIT_REMEMBERED_SET &&
579  !FLAG_incremental_marking) {
580  return;
581  }
582  // First, check if a write barrier is even needed. The tests below
583  // catch stores of smis and stores into the young generation.
584  Label done;
585 
586  if (smi_check == INLINE_SMI_CHECK) {
587  JumpIfSmi(value, &done);
588  }
589 
590  CheckPageFlag(value,
591  value, // Used as scratch.
592  MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
593  CheckPageFlag(object,
594  value, // Used as scratch.
595  MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done);
596 
597  // Record the actual write.
598  if (lr_status == kLRHasNotBeenSaved) {
599  push(r14);
600  }
601  CallRecordWriteStub(object, address, remembered_set_action, fp_mode);
602  if (lr_status == kLRHasNotBeenSaved) {
603  pop(r14);
604  }
605 
606  bind(&done);
607 
608  // Count number of write barriers in generated code.
609  isolate()->counters()->write_barriers_static()->Increment();
610  IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip,
611  value);
612 
613  // Clobber clobbered registers when running with the debug-code flag
614  // turned on to provoke errors.
615  if (emit_debug_code()) {
616  mov(address, Operand(bit_cast<intptr_t>(kZapValue + 12)));
617  mov(value, Operand(bit_cast<intptr_t>(kZapValue + 16)));
618  }
619 }
620 
621 void TurboAssembler::PushCommonFrame(Register marker_reg) {
622  int fp_delta = 0;
623  CleanseP(r14);
624  if (marker_reg.is_valid()) {
625  Push(r14, fp, marker_reg);
626  fp_delta = 1;
627  } else {
628  Push(r14, fp);
629  fp_delta = 0;
630  }
631  la(fp, MemOperand(sp, fp_delta * kPointerSize));
632 }
633 
634 void TurboAssembler::PopCommonFrame(Register marker_reg) {
635  if (marker_reg.is_valid()) {
636  Pop(r14, fp, marker_reg);
637  } else {
638  Pop(r14, fp);
639  }
640 }
641 
642 void TurboAssembler::PushStandardFrame(Register function_reg) {
643  int fp_delta = 0;
644  CleanseP(r14);
645  if (function_reg.is_valid()) {
646  Push(r14, fp, cp, function_reg);
647  fp_delta = 2;
648  } else {
649  Push(r14, fp, cp);
650  fp_delta = 1;
651  }
652  la(fp, MemOperand(sp, fp_delta * kPointerSize));
653 }
654 
655 void TurboAssembler::RestoreFrameStateForTailCall() {
656  // if (FLAG_enable_embedded_constant_pool) {
657  // LoadP(kConstantPoolRegister,
658  // MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
659  // set_constant_pool_available(false);
660  // }
661  DCHECK(!FLAG_enable_embedded_constant_pool);
662  LoadP(r14, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
663  LoadP(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
664 }
665 
666 // Push and pop all registers that can hold pointers.
667 void MacroAssembler::PushSafepointRegisters() {
668  // Safepoints expect a block of kNumSafepointRegisters values on the
669  // stack, so adjust the stack for unsaved registers.
670  const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
671  DCHECK_GE(num_unsaved, 0);
672  if (num_unsaved > 0) {
673  lay(sp, MemOperand(sp, -(num_unsaved * kPointerSize)));
674  }
675  MultiPush(kSafepointSavedRegisters);
676 }
677 
678 void MacroAssembler::PopSafepointRegisters() {
679  const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
680  MultiPop(kSafepointSavedRegisters);
681  if (num_unsaved > 0) {
682  la(sp, MemOperand(sp, num_unsaved * kPointerSize));
683  }
684 }
685 
686 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
687  // The registers are pushed starting with the highest encoding,
688  // which means that lowest encodings are closest to the stack pointer.
689  RegList regs = kSafepointSavedRegisters;
690  int index = 0;
691 
692  DCHECK(reg_code >= 0 && reg_code < kNumRegisters);
693 
694  for (int16_t i = 0; i < reg_code; i++) {
695  if ((regs & (1 << i)) != 0) {
696  index++;
697  }
698  }
699 
700  return index;
701 }
702 
703 void TurboAssembler::CanonicalizeNaN(const DoubleRegister dst,
704  const DoubleRegister src) {
705  // Turn potential sNaN into qNaN
706  if (dst != src) ldr(dst, src);
707  lzdr(kDoubleRegZero);
708  sdbr(dst, kDoubleRegZero);
709 }
710 
711 void TurboAssembler::ConvertIntToDouble(DoubleRegister dst, Register src) {
712  cdfbr(dst, src);
713 }
714 
715 void TurboAssembler::ConvertUnsignedIntToDouble(DoubleRegister dst,
716  Register src) {
717  if (CpuFeatures::IsSupported(FLOATING_POINT_EXT)) {
718  cdlfbr(Condition(5), Condition(0), dst, src);
719  } else {
720  // zero-extend src
721  llgfr(src, src);
722  // convert to double
723  cdgbr(dst, src);
724  }
725 }
726 
727 void TurboAssembler::ConvertIntToFloat(DoubleRegister dst, Register src) {
728  cefbra(Condition(4), dst, src);
729 }
730 
731 void TurboAssembler::ConvertUnsignedIntToFloat(DoubleRegister dst,
732  Register src) {
733  celfbr(Condition(4), Condition(0), dst, src);
734 }
735 
736 void TurboAssembler::ConvertInt64ToFloat(DoubleRegister double_dst,
737  Register src) {
738  cegbr(double_dst, src);
739 }
740 
741 void TurboAssembler::ConvertInt64ToDouble(DoubleRegister double_dst,
742  Register src) {
743  cdgbr(double_dst, src);
744 }
745 
746 void TurboAssembler::ConvertUnsignedInt64ToFloat(DoubleRegister double_dst,
747  Register src) {
748  celgbr(Condition(0), Condition(0), double_dst, src);
749 }
750 
751 void TurboAssembler::ConvertUnsignedInt64ToDouble(DoubleRegister double_dst,
752  Register src) {
753  cdlgbr(Condition(0), Condition(0), double_dst, src);
754 }
755 
756 void TurboAssembler::ConvertFloat32ToInt64(const Register dst,
757  const DoubleRegister double_input,
758  FPRoundingMode rounding_mode) {
759  Condition m = Condition(0);
760  switch (rounding_mode) {
761  case kRoundToZero:
762  m = Condition(5);
763  break;
764  case kRoundToNearest:
765  UNIMPLEMENTED();
766  break;
767  case kRoundToPlusInf:
768  m = Condition(6);
769  break;
770  case kRoundToMinusInf:
771  m = Condition(7);
772  break;
773  default:
774  UNIMPLEMENTED();
775  break;
776  }
777  cgebr(m, dst, double_input);
778 }
779 
780 void TurboAssembler::ConvertDoubleToInt64(const Register dst,
781  const DoubleRegister double_input,
782  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  cgdbr(m, dst, double_input);
802 }
803 
804 void TurboAssembler::ConvertDoubleToInt32(const Register dst,
805  const DoubleRegister double_input,
806  FPRoundingMode rounding_mode) {
807  Condition m = Condition(0);
808  switch (rounding_mode) {
809  case kRoundToZero:
810  m = Condition(5);
811  break;
812  case kRoundToNearest:
813  m = Condition(4);
814  break;
815  case kRoundToPlusInf:
816  m = Condition(6);
817  break;
818  case kRoundToMinusInf:
819  m = Condition(7);
820  break;
821  default:
822  UNIMPLEMENTED();
823  break;
824  }
825 #ifdef V8_TARGET_ARCH_S390X
826  lghi(dst, Operand::Zero());
827 #endif
828  cfdbr(m, dst, double_input);
829 }
830 
831 void TurboAssembler::ConvertFloat32ToInt32(const Register result,
832  const DoubleRegister double_input,
833  FPRoundingMode rounding_mode) {
834  Condition m = Condition(0);
835  switch (rounding_mode) {
836  case kRoundToZero:
837  m = Condition(5);
838  break;
839  case kRoundToNearest:
840  m = Condition(4);
841  break;
842  case kRoundToPlusInf:
843  m = Condition(6);
844  break;
845  case kRoundToMinusInf:
846  m = Condition(7);
847  break;
848  default:
849  UNIMPLEMENTED();
850  break;
851  }
852 #ifdef V8_TARGET_ARCH_S390X
853  lghi(result, Operand::Zero());
854 #endif
855  cfebr(m, result, double_input);
856 }
857 
858 void TurboAssembler::ConvertFloat32ToUnsignedInt32(
859  const Register result, const DoubleRegister double_input,
860  FPRoundingMode rounding_mode) {
861  Condition m = Condition(0);
862  switch (rounding_mode) {
863  case kRoundToZero:
864  m = Condition(5);
865  break;
866  case kRoundToNearest:
867  UNIMPLEMENTED();
868  break;
869  case kRoundToPlusInf:
870  m = Condition(6);
871  break;
872  case kRoundToMinusInf:
873  m = Condition(7);
874  break;
875  default:
876  UNIMPLEMENTED();
877  break;
878  }
879 #ifdef V8_TARGET_ARCH_S390X
880  lghi(result, Operand::Zero());
881 #endif
882  clfebr(m, Condition(0), result, double_input);
883 }
884 
885 void TurboAssembler::ConvertFloat32ToUnsignedInt64(
886  const Register result, const DoubleRegister double_input,
887  FPRoundingMode rounding_mode) {
888  Condition m = Condition(0);
889  switch (rounding_mode) {
890  case kRoundToZero:
891  m = Condition(5);
892  break;
893  case kRoundToNearest:
894  UNIMPLEMENTED();
895  break;
896  case kRoundToPlusInf:
897  m = Condition(6);
898  break;
899  case kRoundToMinusInf:
900  m = Condition(7);
901  break;
902  default:
903  UNIMPLEMENTED();
904  break;
905  }
906  clgebr(m, Condition(0), result, double_input);
907 }
908 
909 void TurboAssembler::ConvertDoubleToUnsignedInt64(
910  const Register dst, const DoubleRegister double_input,
911  FPRoundingMode rounding_mode) {
912  Condition m = Condition(0);
913  switch (rounding_mode) {
914  case kRoundToZero:
915  m = Condition(5);
916  break;
917  case kRoundToNearest:
918  UNIMPLEMENTED();
919  break;
920  case kRoundToPlusInf:
921  m = Condition(6);
922  break;
923  case kRoundToMinusInf:
924  m = Condition(7);
925  break;
926  default:
927  UNIMPLEMENTED();
928  break;
929  }
930  clgdbr(m, Condition(0), dst, double_input);
931 }
932 
933 void TurboAssembler::ConvertDoubleToUnsignedInt32(
934  const Register dst, const DoubleRegister double_input,
935  FPRoundingMode rounding_mode) {
936  Condition m = Condition(0);
937  switch (rounding_mode) {
938  case kRoundToZero:
939  m = Condition(5);
940  break;
941  case kRoundToNearest:
942  UNIMPLEMENTED();
943  break;
944  case kRoundToPlusInf:
945  m = Condition(6);
946  break;
947  case kRoundToMinusInf:
948  m = Condition(7);
949  break;
950  default:
951  UNIMPLEMENTED();
952  break;
953  }
954 #ifdef V8_TARGET_ARCH_S390X
955  lghi(dst, Operand::Zero());
956 #endif
957  clfdbr(m, Condition(0), dst, double_input);
958 }
959 
960 #if !V8_TARGET_ARCH_S390X
961 void TurboAssembler::ShiftLeftPair(Register dst_low, Register dst_high,
962  Register src_low, Register src_high,
963  Register scratch, Register shift) {
964  LoadRR(r0, src_high);
965  LoadRR(r1, src_low);
966  sldl(r0, shift, Operand::Zero());
967  LoadRR(dst_high, r0);
968  LoadRR(dst_low, r1);
969 }
970 
971 void TurboAssembler::ShiftLeftPair(Register dst_low, Register dst_high,
972  Register src_low, Register src_high,
973  uint32_t shift) {
974  LoadRR(r0, src_high);
975  LoadRR(r1, src_low);
976  sldl(r0, r0, Operand(shift));
977  LoadRR(dst_high, r0);
978  LoadRR(dst_low, r1);
979 }
980 
981 void TurboAssembler::ShiftRightPair(Register dst_low, Register dst_high,
982  Register src_low, Register src_high,
983  Register scratch, Register shift) {
984  LoadRR(r0, src_high);
985  LoadRR(r1, src_low);
986  srdl(r0, shift, Operand::Zero());
987  LoadRR(dst_high, r0);
988  LoadRR(dst_low, r1);
989 }
990 
991 void TurboAssembler::ShiftRightPair(Register dst_low, Register dst_high,
992  Register src_low, Register src_high,
993  uint32_t shift) {
994  LoadRR(r0, src_high);
995  LoadRR(r1, src_low);
996  srdl(r0, Operand(shift));
997  LoadRR(dst_high, r0);
998  LoadRR(dst_low, r1);
999 }
1000 
1001 void TurboAssembler::ShiftRightArithPair(Register dst_low, Register dst_high,
1002  Register src_low, Register src_high,
1003  Register scratch, Register shift) {
1004  LoadRR(r0, src_high);
1005  LoadRR(r1, src_low);
1006  srda(r0, shift, Operand::Zero());
1007  LoadRR(dst_high, r0);
1008  LoadRR(dst_low, r1);
1009 }
1010 
1011 void TurboAssembler::ShiftRightArithPair(Register dst_low, Register dst_high,
1012  Register src_low, Register src_high,
1013  uint32_t shift) {
1014  LoadRR(r0, src_high);
1015  LoadRR(r1, src_low);
1016  srda(r0, r0, Operand(shift));
1017  LoadRR(dst_high, r0);
1018  LoadRR(dst_low, r1);
1019 }
1020 #endif
1021 
1022 void TurboAssembler::MovDoubleToInt64(Register dst, DoubleRegister src) {
1023  lgdr(dst, src);
1024 }
1025 
1026 void TurboAssembler::MovInt64ToDouble(DoubleRegister dst, Register src) {
1027  ldgr(dst, src);
1028 }
1029 
1030 void TurboAssembler::StubPrologue(StackFrame::Type type, Register base,
1031  int prologue_offset) {
1032  {
1033  ConstantPoolUnavailableScope constant_pool_unavailable(this);
1034  Load(r1, Operand(StackFrame::TypeToMarker(type)));
1035  PushCommonFrame(r1);
1036  }
1037 }
1038 
1039 void TurboAssembler::Prologue(Register base, int prologue_offset) {
1040  DCHECK(base != no_reg);
1041  PushStandardFrame(r3);
1042 }
1043 
1044 void TurboAssembler::EnterFrame(StackFrame::Type type,
1045  bool load_constant_pool_pointer_reg) {
1046  // We create a stack frame with:
1047  // Return Addr <-- old sp
1048  // Old FP <-- new fp
1049  // CP
1050  // type
1051  // CodeObject <-- new sp
1052 
1053  Load(ip, Operand(StackFrame::TypeToMarker(type)));
1054  PushCommonFrame(ip);
1055 }
1056 
1057 int TurboAssembler::LeaveFrame(StackFrame::Type type, int stack_adjustment) {
1058  // Drop the execution stack down to the frame pointer and restore
1059  // the caller frame pointer, return address and constant pool pointer.
1060  LoadP(r14, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
1061  if (is_int20(StandardFrameConstants::kCallerSPOffset + stack_adjustment)) {
1062  lay(r1, MemOperand(fp, StandardFrameConstants::kCallerSPOffset +
1063  stack_adjustment));
1064  } else {
1065  AddP(r1, fp,
1066  Operand(StandardFrameConstants::kCallerSPOffset + stack_adjustment));
1067  }
1068  LoadP(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
1069  LoadRR(sp, r1);
1070  int frame_ends = pc_offset();
1071  return frame_ends;
1072 }
1073 
1074 // ExitFrame layout (probably wrongish.. needs updating)
1075 //
1076 // SP -> previousSP
1077 // LK reserved
1078 // code
1079 // sp_on_exit (for debug?)
1080 // oldSP->prev SP
1081 // LK
1082 // <parameters on stack>
1083 
1084 // Prior to calling EnterExitFrame, we've got a bunch of parameters
1085 // on the stack that we need to wrap a real frame around.. so first
1086 // we reserve a slot for LK and push the previous SP which is captured
1087 // in the fp register (r11)
1088 // Then - we buy a new frame
1089 
1090 // r14
1091 // oldFP <- newFP
1092 // SP
1093 // Code
1094 // Floats
1095 // gaps
1096 // Args
1097 // ABIRes <- newSP
1098 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
1099  StackFrame::Type frame_type) {
1100  DCHECK(frame_type == StackFrame::EXIT ||
1101  frame_type == StackFrame::BUILTIN_EXIT);
1102  // Set up the frame structure on the stack.
1103  DCHECK_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
1104  DCHECK_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
1105  DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
1106  DCHECK_GT(stack_space, 0);
1107 
1108  // This is an opportunity to build a frame to wrap
1109  // all of the pushes that have happened inside of V8
1110  // since we were called from C code
1111  CleanseP(r14);
1112  Load(r1, Operand(StackFrame::TypeToMarker(frame_type)));
1113  PushCommonFrame(r1);
1114  // Reserve room for saved entry sp and code object.
1115  lay(sp, MemOperand(fp, -ExitFrameConstants::kFixedFrameSizeFromFp));
1116 
1117  if (emit_debug_code()) {
1118  StoreP(MemOperand(fp, ExitFrameConstants::kSPOffset), Operand::Zero(), r1);
1119  }
1120  Move(r1, CodeObject());
1121  StoreP(r1, MemOperand(fp, ExitFrameConstants::kCodeOffset));
1122 
1123  // Save the frame pointer and the context in top.
1124  Move(r1, ExternalReference::Create(IsolateAddressId::kCEntryFPAddress,
1125  isolate()));
1126  StoreP(fp, MemOperand(r1));
1127  Move(r1,
1128  ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()));
1129  StoreP(cp, MemOperand(r1));
1130 
1131  // Optionally save all volatile double registers.
1132  if (save_doubles) {
1133  MultiPushDoubles(kCallerSavedDoubles);
1134  // Note that d0 will be accessible at
1135  // fp - ExitFrameConstants::kFrameSize -
1136  // kNumCallerSavedDoubles * kDoubleSize,
1137  // since the sp slot and code slot were pushed after the fp.
1138  }
1139 
1140  lay(sp, MemOperand(sp, -stack_space * kPointerSize));
1141 
1142  // Allocate and align the frame preparing for calling the runtime
1143  // function.
1144  const int frame_alignment = TurboAssembler::ActivationFrameAlignment();
1145  if (frame_alignment > 0) {
1146  DCHECK_EQ(frame_alignment, 8);
1147  ClearRightImm(sp, sp, Operand(3)); // equivalent to &= -8
1148  }
1149 
1150  lay(sp, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize));
1151  StoreP(MemOperand(sp), Operand::Zero(), r0);
1152  // Set the exit frame sp value to point just before the return address
1153  // location.
1154  lay(r1, MemOperand(sp, kStackFrameSPSlot * kPointerSize));
1155  StoreP(r1, MemOperand(fp, ExitFrameConstants::kSPOffset));
1156 }
1157 
1158 int TurboAssembler::ActivationFrameAlignment() {
1159 #if !defined(USE_SIMULATOR)
1160  // Running on the real platform. Use the alignment as mandated by the local
1161  // environment.
1162  // Note: This will break if we ever start generating snapshots on one S390
1163  // platform for another S390 platform with a different alignment.
1164  return base::OS::ActivationFrameAlignment();
1165 #else // Simulated
1166  // If we are using the simulator then we should always align to the expected
1167  // alignment. As the simulator is used to generate snapshots we do not know
1168  // if the target platform will need alignment, so this is controlled from a
1169  // flag.
1170  return FLAG_sim_stack_alignment;
1171 #endif
1172 }
1173 
1174 void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
1175  bool argument_count_is_length) {
1176  // Optionally restore all double registers.
1177  if (save_doubles) {
1178  // Calculate the stack location of the saved doubles and restore them.
1179  const int kNumRegs = kNumCallerSavedDoubles;
1180  lay(r5, MemOperand(fp, -(ExitFrameConstants::kFixedFrameSizeFromFp +
1181  kNumRegs * kDoubleSize)));
1182  MultiPopDoubles(kCallerSavedDoubles, r5);
1183  }
1184 
1185  // Clear top frame.
1186  Move(ip, ExternalReference::Create(IsolateAddressId::kCEntryFPAddress,
1187  isolate()));
1188  StoreP(MemOperand(ip), Operand(0, RelocInfo::NONE), r0);
1189 
1190  // Restore current context from top and clear it in debug mode.
1191  Move(ip,
1192  ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()));
1193  LoadP(cp, MemOperand(ip));
1194 
1195 #ifdef DEBUG
1196  mov(r1, Operand(Context::kInvalidContext));
1197  Move(ip,
1198  ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()));
1199  StoreP(r1, MemOperand(ip));
1200 #endif
1201 
1202  // Tear down the exit frame, pop the arguments, and return.
1203  LeaveFrame(StackFrame::EXIT);
1204 
1205  if (argument_count.is_valid()) {
1206  if (!argument_count_is_length) {
1207  ShiftLeftP(argument_count, argument_count, Operand(kPointerSizeLog2));
1208  }
1209  la(sp, MemOperand(sp, argument_count));
1210  }
1211 }
1212 
1213 void TurboAssembler::MovFromFloatResult(const DoubleRegister dst) {
1214  Move(dst, d0);
1215 }
1216 
1217 void TurboAssembler::MovFromFloatParameter(const DoubleRegister dst) {
1218  Move(dst, d0);
1219 }
1220 
1221 void TurboAssembler::PrepareForTailCall(const ParameterCount& callee_args_count,
1222  Register caller_args_count_reg,
1223  Register scratch0, Register scratch1) {
1224 #if DEBUG
1225  if (callee_args_count.is_reg()) {
1226  DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0,
1227  scratch1));
1228  } else {
1229  DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1));
1230  }
1231 #endif
1232 
1233  // Calculate the end of destination area where we will put the arguments
1234  // after we drop current frame. We AddP kPointerSize to count the receiver
1235  // argument which is not included into formal parameters count.
1236  Register dst_reg = scratch0;
1237  ShiftLeftP(dst_reg, caller_args_count_reg, Operand(kPointerSizeLog2));
1238  AddP(dst_reg, fp, dst_reg);
1239  AddP(dst_reg, dst_reg,
1240  Operand(StandardFrameConstants::kCallerSPOffset + kPointerSize));
1241 
1242  Register src_reg = caller_args_count_reg;
1243  // Calculate the end of source area. +kPointerSize is for the receiver.
1244  if (callee_args_count.is_reg()) {
1245  ShiftLeftP(src_reg, callee_args_count.reg(), Operand(kPointerSizeLog2));
1246  AddP(src_reg, sp, src_reg);
1247  AddP(src_reg, src_reg, Operand(kPointerSize));
1248  } else {
1249  mov(src_reg, Operand((callee_args_count.immediate() + 1) * kPointerSize));
1250  AddP(src_reg, src_reg, sp);
1251  }
1252 
1253  if (FLAG_debug_code) {
1254  CmpLogicalP(src_reg, dst_reg);
1255  Check(lt, AbortReason::kStackAccessBelowStackPointer);
1256  }
1257 
1258  // Restore caller's frame pointer and return address now as they will be
1259  // overwritten by the copying loop.
1260  RestoreFrameStateForTailCall();
1261 
1262  // Now copy callee arguments to the caller frame going backwards to avoid
1263  // callee arguments corruption (source and destination areas could overlap).
1264 
1265  // Both src_reg and dst_reg are pointing to the word after the one to copy,
1266  // so they must be pre-decremented in the loop.
1267  Register tmp_reg = scratch1;
1268  Label loop;
1269  if (callee_args_count.is_reg()) {
1270  AddP(tmp_reg, callee_args_count.reg(), Operand(1)); // +1 for receiver
1271  } else {
1272  mov(tmp_reg, Operand(callee_args_count.immediate() + 1));
1273  }
1274  LoadRR(r1, tmp_reg);
1275  bind(&loop);
1276  LoadP(tmp_reg, MemOperand(src_reg, -kPointerSize));
1277  StoreP(tmp_reg, MemOperand(dst_reg, -kPointerSize));
1278  lay(src_reg, MemOperand(src_reg, -kPointerSize));
1279  lay(dst_reg, MemOperand(dst_reg, -kPointerSize));
1280  BranchOnCount(r1, &loop);
1281 
1282  // Leave current frame.
1283  LoadRR(sp, dst_reg);
1284 }
1285 
1286 void MacroAssembler::InvokePrologue(const ParameterCount& expected,
1287  const ParameterCount& actual, Label* done,
1288  bool* definitely_mismatches,
1289  InvokeFlag flag) {
1290  bool definitely_matches = false;
1291  *definitely_mismatches = false;
1292  Label regular_invoke;
1293 
1294  // Check whether the expected and actual arguments count match. If not,
1295  // setup registers according to contract with ArgumentsAdaptorTrampoline:
1296  // r2: actual arguments count
1297  // r3: function (passed through to callee)
1298  // r4: expected arguments count
1299 
1300  // The code below is made a lot easier because the calling code already sets
1301  // up actual and expected registers according to the contract if values are
1302  // passed in registers.
1303 
1304  // ARM has some sanity checks as per below, considering add them for S390
1305  DCHECK(actual.is_immediate() || actual.reg() == r2);
1306  DCHECK(expected.is_immediate() || expected.reg() == r4);
1307 
1308  if (expected.is_immediate()) {
1309  DCHECK(actual.is_immediate());
1310  mov(r2, Operand(actual.immediate()));
1311  if (expected.immediate() == actual.immediate()) {
1312  definitely_matches = true;
1313  } else {
1314  const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
1315  if (expected.immediate() == sentinel) {
1316  // Don't worry about adapting arguments for builtins that
1317  // don't want that done. Skip adaption code by making it look
1318  // like we have a match between expected and actual number of
1319  // arguments.
1320  definitely_matches = true;
1321  } else {
1322  *definitely_mismatches = true;
1323  mov(r4, Operand(expected.immediate()));
1324  }
1325  }
1326  } else {
1327  if (actual.is_immediate()) {
1328  mov(r2, Operand(actual.immediate()));
1329  CmpPH(expected.reg(), Operand(actual.immediate()));
1330  beq(&regular_invoke);
1331  } else {
1332  CmpP(expected.reg(), actual.reg());
1333  beq(&regular_invoke);
1334  }
1335  }
1336 
1337  if (!definitely_matches) {
1338  Handle<Code> adaptor = BUILTIN_CODE(isolate(), ArgumentsAdaptorTrampoline);
1339  if (flag == CALL_FUNCTION) {
1340  Call(adaptor);
1341  if (!*definitely_mismatches) {
1342  b(done);
1343  }
1344  } else {
1345  Jump(adaptor, RelocInfo::CODE_TARGET);
1346  }
1347  bind(&regular_invoke);
1348  }
1349 }
1350 
1351 void MacroAssembler::CheckDebugHook(Register fun, Register new_target,
1352  const ParameterCount& expected,
1353  const ParameterCount& actual) {
1354  Label skip_hook;
1355 
1356  ExternalReference debug_hook_active =
1357  ExternalReference::debug_hook_on_function_call_address(isolate());
1358  Move(r6, debug_hook_active);
1359  tm(MemOperand(r6), Operand::Zero());
1360  bne(&skip_hook);
1361 
1362  {
1363  // Load receiver to pass it later to DebugOnFunctionCall hook.
1364  if (actual.is_reg()) {
1365  LoadRR(r6, actual.reg());
1366  } else {
1367  mov(r6, Operand(actual.immediate()));
1368  }
1369  ShiftLeftP(r6, r6, Operand(kPointerSizeLog2));
1370  LoadP(r6, MemOperand(sp, r6));
1371  FrameScope frame(this,
1372  has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
1373  if (expected.is_reg()) {
1374  SmiTag(expected.reg());
1375  Push(expected.reg());
1376  }
1377  if (actual.is_reg()) {
1378  SmiTag(actual.reg());
1379  Push(actual.reg());
1380  }
1381  if (new_target.is_valid()) {
1382  Push(new_target);
1383  }
1384  Push(fun, fun, r6);
1385  CallRuntime(Runtime::kDebugOnFunctionCall);
1386  Pop(fun);
1387  if (new_target.is_valid()) {
1388  Pop(new_target);
1389  }
1390  if (actual.is_reg()) {
1391  Pop(actual.reg());
1392  SmiUntag(actual.reg());
1393  }
1394  if (expected.is_reg()) {
1395  Pop(expected.reg());
1396  SmiUntag(expected.reg());
1397  }
1398  }
1399  bind(&skip_hook);
1400 }
1401 
1402 void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
1403  const ParameterCount& expected,
1404  const ParameterCount& actual,
1405  InvokeFlag flag) {
1406  // You can't call a function without a valid frame.
1407  DCHECK(flag == JUMP_FUNCTION || has_frame());
1408 
1409  DCHECK(function == r3);
1410  DCHECK_IMPLIES(new_target.is_valid(), new_target == r5);
1411 
1412  // On function call, call into the debugger if necessary.
1413  CheckDebugHook(function, new_target, expected, actual);
1414 
1415  // Clear the new.target register if not given.
1416  if (!new_target.is_valid()) {
1417  LoadRoot(r5, RootIndex::kUndefinedValue);
1418  }
1419 
1420  Label done;
1421  bool definitely_mismatches = false;
1422  InvokePrologue(expected, actual, &done, &definitely_mismatches, flag);
1423  if (!definitely_mismatches) {
1424  // We call indirectly through the code field in the function to
1425  // allow recompilation to take effect without changing any of the
1426  // call sites.
1427  Register code = kJavaScriptCallCodeStartRegister;
1428  LoadP(code, FieldMemOperand(function, JSFunction::kCodeOffset));
1429  AddP(code, code, Operand(Code::kHeaderSize - kHeapObjectTag));
1430  if (flag == CALL_FUNCTION) {
1431  CallJSEntry(code);
1432  } else {
1433  DCHECK(flag == JUMP_FUNCTION);
1434  JumpToJSEntry(code);
1435  }
1436 
1437  // Continue here if InvokePrologue does handle the invocation due to
1438  // mismatched parameter counts.
1439  bind(&done);
1440  }
1441 }
1442 
1443 void MacroAssembler::InvokeFunction(Register fun, Register new_target,
1444  const ParameterCount& actual,
1445  InvokeFlag flag) {
1446  // You can't call a function without a valid frame.
1447  DCHECK(flag == JUMP_FUNCTION || has_frame());
1448 
1449  // Contract with called JS functions requires that function is passed in r3.
1450  DCHECK(fun == r3);
1451 
1452  Register expected_reg = r4;
1453  Register temp_reg = r6;
1454  LoadP(temp_reg, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset));
1455  LoadP(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
1456  LoadLogicalHalfWordP(
1457  expected_reg,
1458  FieldMemOperand(temp_reg,
1459  SharedFunctionInfo::kFormalParameterCountOffset));
1460 
1461  ParameterCount expected(expected_reg);
1462  InvokeFunctionCode(fun, new_target, expected, actual, flag);
1463 }
1464 
1465 void MacroAssembler::InvokeFunction(Register function,
1466  const ParameterCount& expected,
1467  const ParameterCount& actual,
1468  InvokeFlag flag) {
1469  // You can't call a function without a valid frame.
1470  DCHECK(flag == JUMP_FUNCTION || has_frame());
1471 
1472  // Contract with called JS functions requires that function is passed in r3.
1473  DCHECK(function == r3);
1474 
1475  // Get the function and setup the context.
1476  LoadP(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
1477 
1478  InvokeFunctionCode(r3, no_reg, expected, actual, flag);
1479 }
1480 
1481 void MacroAssembler::MaybeDropFrames() {
1482  // Check whether we need to drop frames to restart a function on the stack.
1483  ExternalReference restart_fp =
1484  ExternalReference::debug_restart_fp_address(isolate());
1485  Move(r3, restart_fp);
1486  LoadP(r3, MemOperand(r3));
1487  CmpP(r3, Operand::Zero());
1488  Jump(BUILTIN_CODE(isolate(), FrameDropperTrampoline), RelocInfo::CODE_TARGET,
1489  ne);
1490 }
1491 
1492 void MacroAssembler::PushStackHandler() {
1493  // Adjust this code if not the case.
1494  STATIC_ASSERT(StackHandlerConstants::kSize == 2 * kPointerSize);
1495  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
1496 
1497  // Link the current handler as the next handler.
1498  mov(r7, Operand(ExternalReference::Create(IsolateAddressId::kHandlerAddress,
1499  isolate())));
1500 
1501  // Buy the full stack frame for 5 slots.
1502  lay(sp, MemOperand(sp, -StackHandlerConstants::kSize));
1503 
1504  // Store padding.
1505  lghi(r0, Operand::Zero());
1506  StoreP(r0, MemOperand(sp)); // Padding.
1507 
1508  // Copy the old handler into the next handler slot.
1509  MoveChar(MemOperand(sp, StackHandlerConstants::kNextOffset), MemOperand(r7),
1510  Operand(kPointerSize));
1511  // Set this new handler as the current one.
1512  StoreP(sp, MemOperand(r7));
1513 }
1514 
1515 void MacroAssembler::PopStackHandler() {
1516  STATIC_ASSERT(StackHandlerConstants::kSize == 2 * kPointerSize);
1517  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
1518 
1519  // Pop the Next Handler into r3 and store it into Handler Address reference.
1520  Pop(r3);
1521  mov(ip, Operand(ExternalReference::Create(IsolateAddressId::kHandlerAddress,
1522  isolate())));
1523  StoreP(r3, MemOperand(ip));
1524 
1525  Drop(1); // Drop padding.
1526 }
1527 
1528 void MacroAssembler::CompareObjectType(Register object, Register map,
1529  Register type_reg, InstanceType type) {
1530  const Register temp = type_reg == no_reg ? r0 : type_reg;
1531 
1532  LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset));
1533  CompareInstanceType(map, temp, type);
1534 }
1535 
1536 void MacroAssembler::CompareInstanceType(Register map, Register type_reg,
1537  InstanceType type) {
1538  STATIC_ASSERT(Map::kInstanceTypeOffset < 4096);
1539  STATIC_ASSERT(LAST_TYPE <= 0xFFFF);
1540  LoadHalfWordP(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
1541  CmpP(type_reg, Operand(type));
1542 }
1543 
1544 void MacroAssembler::CompareRoot(Register obj, RootIndex index) {
1545  CmpP(obj, MemOperand(kRootRegister, RootRegisterOffsetForRootIndex(index)));
1546 }
1547 
1548 void MacroAssembler::CallStub(CodeStub* stub, Condition cond) {
1549  DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs.
1550  Call(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
1551 }
1552 
1553 void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) {
1554  Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
1555 }
1556 
1557 bool TurboAssembler::AllowThisStubCall(CodeStub* stub) {
1558  return has_frame_ || !stub->SometimesSetsUpAFrame();
1559 }
1560 
1561 void MacroAssembler::TryDoubleToInt32Exact(Register result,
1562  DoubleRegister double_input,
1563  Register scratch,
1564  DoubleRegister double_scratch) {
1565  Label done;
1566  DCHECK(double_input != double_scratch);
1567 
1568  ConvertDoubleToInt64(result, double_input);
1569 
1570  TestIfInt32(result);
1571  bne(&done);
1572 
1573  // convert back and compare
1574  cdfbr(double_scratch, result);
1575  cdbr(double_scratch, double_input);
1576  bind(&done);
1577 }
1578 
1579 void TurboAssembler::TruncateDoubleToI(Isolate* isolate, Zone* zone,
1580  Register result,
1581  DoubleRegister double_input,
1582  StubCallMode stub_mode) {
1583  Label done;
1584 
1585  TryInlineTruncateDoubleToI(result, double_input, &done);
1586 
1587  // If we fell through then inline version didn't succeed - call stub instead.
1588  push(r14);
1589  // Put input on stack.
1590  lay(sp, MemOperand(sp, -kDoubleSize));
1591  StoreDouble(double_input, MemOperand(sp));
1592 
1593  if (stub_mode == StubCallMode::kCallWasmRuntimeStub) {
1594  Call(wasm::WasmCode::kDoubleToI, RelocInfo::WASM_STUB_CALL);
1595  } else {
1596  Call(BUILTIN_CODE(isolate, DoubleToI), RelocInfo::CODE_TARGET);
1597  }
1598 
1599  LoadP(result, MemOperand(sp, 0));
1600  la(sp, MemOperand(sp, kDoubleSize));
1601  pop(r14);
1602 
1603  bind(&done);
1604 }
1605 
1606 void TurboAssembler::TryInlineTruncateDoubleToI(Register result,
1607  DoubleRegister double_input,
1608  Label* done) {
1609  ConvertDoubleToInt64(result, double_input);
1610 
1611  // Test for overflow
1612  TestIfInt32(result);
1613  beq(done);
1614 }
1615 
1616 void TurboAssembler::CallRuntimeWithCEntry(Runtime::FunctionId fid,
1617  Register centry) {
1618  const Runtime::Function* f = Runtime::FunctionForId(fid);
1619  mov(r2, Operand(f->nargs));
1620  Move(r3, ExternalReference::Create(f));
1621  DCHECK(!AreAliased(centry, r2, r3));
1622  la(centry, MemOperand(centry, Code::kHeaderSize - kHeapObjectTag));
1623  Call(centry);
1624 }
1625 
1626 void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
1627  SaveFPRegsMode save_doubles) {
1628  // All parameters are on the stack. r2 has the return value after call.
1629 
1630  // If the expected number of arguments of the runtime function is
1631  // constant, we check that the actual number of arguments match the
1632  // expectation.
1633  CHECK(f->nargs < 0 || f->nargs == num_arguments);
1634 
1635  // TODO(1236192): Most runtime routines don't need the number of
1636  // arguments passed in because it is constant. At some point we
1637  // should remove this need and make the runtime routine entry code
1638  // smarter.
1639  mov(r2, Operand(num_arguments));
1640  Move(r3, ExternalReference::Create(f));
1641 #if V8_TARGET_ARCH_S390X
1642  Handle<Code> code =
1643  CodeFactory::CEntry(isolate(), f->result_size, save_doubles);
1644 #else
1645  Handle<Code> code = CodeFactory::CEntry(isolate(), 1, save_doubles);
1646 #endif
1647 
1648  Call(code, RelocInfo::CODE_TARGET);
1649 }
1650 
1651 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
1652  const Runtime::Function* function = Runtime::FunctionForId(fid);
1653  DCHECK_EQ(1, function->result_size);
1654  if (function->nargs >= 0) {
1655  mov(r2, Operand(function->nargs));
1656  }
1657  JumpToExternalReference(ExternalReference::Create(fid));
1658 }
1659 
1660 void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
1661  bool builtin_exit_frame) {
1662  Move(r3, builtin);
1663  Handle<Code> code = CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs,
1664  kArgvOnStack, builtin_exit_frame);
1665  Jump(code, RelocInfo::CODE_TARGET);
1666 }
1667 
1668 void MacroAssembler::JumpToInstructionStream(Address entry) {
1669  mov(kOffHeapTrampolineRegister, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
1670  Jump(kOffHeapTrampolineRegister);
1671 }
1672 
1673 void MacroAssembler::LoadWeakValue(Register out, Register in,
1674  Label* target_if_cleared) {
1675  Cmp32(in, Operand(kClearedWeakHeapObjectLower32));
1676  beq(target_if_cleared);
1677 
1678  AndP(out, in, Operand(~kWeakHeapObjectMask));
1679 }
1680 
1681 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
1682  Register scratch1, Register scratch2) {
1683  DCHECK(value > 0 && is_int8(value));
1684  if (FLAG_native_code_counters && counter->Enabled()) {
1685  Move(scratch2, ExternalReference::Create(counter));
1686  // @TODO(john.yan): can be optimized by asi()
1687  LoadW(scratch1, MemOperand(scratch2));
1688  AddP(scratch1, Operand(value));
1689  StoreW(scratch1, MemOperand(scratch2));
1690  }
1691 }
1692 
1693 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
1694  Register scratch1, Register scratch2) {
1695  DCHECK(value > 0 && is_int8(value));
1696  if (FLAG_native_code_counters && counter->Enabled()) {
1697  Move(scratch2, ExternalReference::Create(counter));
1698  // @TODO(john.yan): can be optimized by asi()
1699  LoadW(scratch1, MemOperand(scratch2));
1700  AddP(scratch1, Operand(-value));
1701  StoreW(scratch1, MemOperand(scratch2));
1702  }
1703 }
1704 
1705 void TurboAssembler::Assert(Condition cond, AbortReason reason, CRegister cr) {
1706  if (emit_debug_code()) Check(cond, reason, cr);
1707 }
1708 
1709 void TurboAssembler::Check(Condition cond, AbortReason reason, CRegister cr) {
1710  Label L;
1711  b(cond, &L);
1712  Abort(reason);
1713  // will not return here
1714  bind(&L);
1715 }
1716 
1717 void TurboAssembler::Abort(AbortReason reason) {
1718  Label abort_start;
1719  bind(&abort_start);
1720  const char* msg = GetAbortReason(reason);
1721 #ifdef DEBUG
1722  RecordComment("Abort message: ");
1723  RecordComment(msg);
1724 #endif
1725 
1726  // Avoid emitting call to builtin if requested.
1727  if (trap_on_abort()) {
1728  stop(msg);
1729  return;
1730  }
1731 
1732  if (should_abort_hard()) {
1733  // We don't care if we constructed a frame. Just pretend we did.
1734  FrameScope assume_frame(this, StackFrame::NONE);
1735  lgfi(r2, Operand(static_cast<int>(reason)));
1736  PrepareCallCFunction(1, 0, r3);
1737  Move(r3, ExternalReference::abort_with_reason());
1738  // Use Call directly to avoid any unneeded overhead. The function won't
1739  // return anyway.
1740  Call(r3);
1741  return;
1742  }
1743 
1744  LoadSmiLiteral(r3, Smi::FromInt(static_cast<int>(reason)));
1745 
1746  // Disable stub call restrictions to always allow calls to abort.
1747  if (!has_frame_) {
1748  // We don't actually want to generate a pile of code for this, so just
1749  // claim there is a stack frame, without generating one.
1750  FrameScope scope(this, StackFrame::NONE);
1751  Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
1752  } else {
1753  Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
1754  }
1755  // will not return here
1756 }
1757 
1758 void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
1759  LoadP(dst, NativeContextMemOperand());
1760  LoadP(dst, ContextMemOperand(dst, index));
1761 }
1762 
1763 void MacroAssembler::UntagAndJumpIfSmi(Register dst, Register src,
1764  Label* smi_case) {
1765  STATIC_ASSERT(kSmiTag == 0);
1766  STATIC_ASSERT(kSmiTagSize == 1);
1767  // this won't work if src == dst
1768  DCHECK(src.code() != dst.code());
1769  SmiUntag(dst, src);
1770  TestIfSmi(src);
1771  beq(smi_case);
1772 }
1773 
1774 void MacroAssembler::JumpIfEitherSmi(Register reg1, Register reg2,
1775  Label* on_either_smi) {
1776  STATIC_ASSERT(kSmiTag == 0);
1777  JumpIfSmi(reg1, on_either_smi);
1778  JumpIfSmi(reg2, on_either_smi);
1779 }
1780 
1781 void MacroAssembler::AssertNotSmi(Register object) {
1782  if (emit_debug_code()) {
1783  STATIC_ASSERT(kSmiTag == 0);
1784  TestIfSmi(object);
1785  Check(ne, AbortReason::kOperandIsASmi, cr0);
1786  }
1787 }
1788 
1789 void MacroAssembler::AssertSmi(Register object) {
1790  if (emit_debug_code()) {
1791  STATIC_ASSERT(kSmiTag == 0);
1792  TestIfSmi(object);
1793  Check(eq, AbortReason::kOperandIsNotASmi, cr0);
1794  }
1795 }
1796 
1797 void MacroAssembler::AssertConstructor(Register object, Register scratch) {
1798  if (emit_debug_code()) {
1799  STATIC_ASSERT(kSmiTag == 0);
1800  TestIfSmi(object);
1801  Check(ne, AbortReason::kOperandIsASmiAndNotAConstructor);
1802  LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
1803  tm(FieldMemOperand(scratch, Map::kBitFieldOffset),
1804  Operand(Map::IsConstructorBit::kMask));
1805  Check(ne, AbortReason::kOperandIsNotAConstructor);
1806  }
1807 }
1808 
1809 void MacroAssembler::AssertFunction(Register object) {
1810  if (emit_debug_code()) {
1811  STATIC_ASSERT(kSmiTag == 0);
1812  TestIfSmi(object);
1813  Check(ne, AbortReason::kOperandIsASmiAndNotAFunction, cr0);
1814  push(object);
1815  CompareObjectType(object, object, object, JS_FUNCTION_TYPE);
1816  pop(object);
1817  Check(eq, AbortReason::kOperandIsNotAFunction);
1818  }
1819 }
1820 
1821 void MacroAssembler::AssertBoundFunction(Register object) {
1822  if (emit_debug_code()) {
1823  STATIC_ASSERT(kSmiTag == 0);
1824  TestIfSmi(object);
1825  Check(ne, AbortReason::kOperandIsASmiAndNotABoundFunction, cr0);
1826  push(object);
1827  CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE);
1828  pop(object);
1829  Check(eq, AbortReason::kOperandIsNotABoundFunction);
1830  }
1831 }
1832 
1833 void MacroAssembler::AssertGeneratorObject(Register object) {
1834  if (!emit_debug_code()) return;
1835  TestIfSmi(object);
1836  Check(ne, AbortReason::kOperandIsASmiAndNotAGeneratorObject, cr0);
1837 
1838  // Load map
1839  Register map = object;
1840  push(object);
1841  LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset));
1842 
1843  // Check if JSGeneratorObject
1844  Label do_check;
1845  Register instance_type = object;
1846  CompareInstanceType(map, instance_type, JS_GENERATOR_OBJECT_TYPE);
1847  beq(&do_check);
1848 
1849  // Check if JSAsyncFunctionObject (See MacroAssembler::CompareInstanceType)
1850  CmpP(instance_type, Operand(JS_ASYNC_FUNCTION_OBJECT_TYPE));
1851  beq(&do_check);
1852 
1853  // Check if JSAsyncGeneratorObject (See MacroAssembler::CompareInstanceType)
1854  CmpP(instance_type, Operand(JS_ASYNC_GENERATOR_OBJECT_TYPE));
1855 
1856  bind(&do_check);
1857  // Restore generator object to register and perform assertion
1858  pop(object);
1859  Check(eq, AbortReason::kOperandIsNotAGeneratorObject);
1860 }
1861 
1862 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
1863  Register scratch) {
1864  if (emit_debug_code()) {
1865  Label done_checking;
1866  AssertNotSmi(object);
1867  CompareRoot(object, RootIndex::kUndefinedValue);
1868  beq(&done_checking, Label::kNear);
1869  LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
1870  CompareInstanceType(scratch, scratch, ALLOCATION_SITE_TYPE);
1871  Assert(eq, AbortReason::kExpectedUndefinedOrCell);
1872  bind(&done_checking);
1873  }
1874 }
1875 
1876 static const int kRegisterPassedArguments = 5;
1877 
1878 int TurboAssembler::CalculateStackPassedWords(int num_reg_arguments,
1879  int num_double_arguments) {
1880  int stack_passed_words = 0;
1881  if (num_double_arguments > DoubleRegister::kNumRegisters) {
1882  stack_passed_words +=
1883  2 * (num_double_arguments - DoubleRegister::kNumRegisters);
1884  }
1885  // Up to five simple arguments are passed in registers r2..r6
1886  if (num_reg_arguments > kRegisterPassedArguments) {
1887  stack_passed_words += num_reg_arguments - kRegisterPassedArguments;
1888  }
1889  return stack_passed_words;
1890 }
1891 
1892 void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
1893  int num_double_arguments,
1894  Register scratch) {
1895  int frame_alignment = ActivationFrameAlignment();
1896  int stack_passed_arguments =
1897  CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
1898  int stack_space = kNumRequiredStackFrameSlots;
1899  if (frame_alignment > kPointerSize) {
1900  // Make stack end at alignment and make room for stack arguments
1901  // -- preserving original value of sp.
1902  LoadRR(scratch, sp);
1903  lay(sp, MemOperand(sp, -(stack_passed_arguments + 1) * kPointerSize));
1904  DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
1905  ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
1906  StoreP(scratch, MemOperand(sp, (stack_passed_arguments)*kPointerSize));
1907  } else {
1908  stack_space += stack_passed_arguments;
1909  }
1910  lay(sp, MemOperand(sp, (-stack_space) * kPointerSize));
1911 }
1912 
1913 void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
1914  Register scratch) {
1915  PrepareCallCFunction(num_reg_arguments, 0, scratch);
1916 }
1917 
1918 void TurboAssembler::MovToFloatParameter(DoubleRegister src) { Move(d0, src); }
1919 
1920 void TurboAssembler::MovToFloatResult(DoubleRegister src) { Move(d0, src); }
1921 
1922 void TurboAssembler::MovToFloatParameters(DoubleRegister src1,
1923  DoubleRegister src2) {
1924  if (src2 == d0) {
1925  DCHECK(src1 != d2);
1926  Move(d2, src2);
1927  Move(d0, src1);
1928  } else {
1929  Move(d0, src1);
1930  Move(d2, src2);
1931  }
1932 }
1933 
1934 void TurboAssembler::CallCFunction(ExternalReference function,
1935  int num_reg_arguments,
1936  int num_double_arguments) {
1937  Move(ip, function);
1938  CallCFunctionHelper(ip, num_reg_arguments, num_double_arguments);
1939 }
1940 
1941 void TurboAssembler::CallCFunction(Register function, int num_reg_arguments,
1942  int num_double_arguments) {
1943  CallCFunctionHelper(function, num_reg_arguments, num_double_arguments);
1944 }
1945 
1946 void TurboAssembler::CallCFunction(ExternalReference function,
1947  int num_arguments) {
1948  CallCFunction(function, num_arguments, 0);
1949 }
1950 
1951 void TurboAssembler::CallCFunction(Register function, int num_arguments) {
1952  CallCFunction(function, num_arguments, 0);
1953 }
1954 
1955 void TurboAssembler::CallCFunctionHelper(Register function,
1956  int num_reg_arguments,
1957  int num_double_arguments) {
1958  DCHECK_LE(num_reg_arguments + num_double_arguments, kMaxCParameters);
1959  DCHECK(has_frame());
1960 
1961  // Just call directly. The function called cannot cause a GC, or
1962  // allow preemption, so the return address in the link register
1963  // stays correct.
1964  Register dest = function;
1965  if (ABI_CALL_VIA_IP) {
1966  Move(ip, function);
1967  dest = ip;
1968  }
1969 
1970  Call(dest);
1971 
1972  int stack_passed_arguments =
1973  CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
1974  int stack_space = kNumRequiredStackFrameSlots + stack_passed_arguments;
1975  if (ActivationFrameAlignment() > kPointerSize) {
1976  // Load the original stack pointer (pre-alignment) from the stack
1977  LoadP(sp, MemOperand(sp, stack_space * kPointerSize));
1978  } else {
1979  la(sp, MemOperand(sp, stack_space * kPointerSize));
1980  }
1981 }
1982 
1983 void TurboAssembler::CheckPageFlag(
1984  Register object,
1985  Register scratch, // scratch may be same register as object
1986  int mask, Condition cc, Label* condition_met) {
1987  DCHECK(cc == ne || cc == eq);
1988  ClearRightImm(scratch, object, Operand(kPageSizeBits));
1989 
1990  if (base::bits::IsPowerOfTwo(mask)) {
1991  // If it's a power of two, we can use Test-Under-Mask Memory-Imm form
1992  // which allows testing of a single byte in memory.
1993  int32_t byte_offset = 4;
1994  uint32_t shifted_mask = mask;
1995  // Determine the byte offset to be tested
1996  if (mask <= 0x80) {
1997  byte_offset = kPointerSize - 1;
1998  } else if (mask < 0x8000) {
1999  byte_offset = kPointerSize - 2;
2000  shifted_mask = mask >> 8;
2001  } else if (mask < 0x800000) {
2002  byte_offset = kPointerSize - 3;
2003  shifted_mask = mask >> 16;
2004  } else {
2005  byte_offset = kPointerSize - 4;
2006  shifted_mask = mask >> 24;
2007  }
2008 #if V8_TARGET_LITTLE_ENDIAN
2009  // Reverse the byte_offset if emulating on little endian platform
2010  byte_offset = kPointerSize - byte_offset - 1;
2011 #endif
2012  tm(MemOperand(scratch, MemoryChunk::kFlagsOffset + byte_offset),
2013  Operand(shifted_mask));
2014  } else {
2015  LoadP(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
2016  AndP(r0, scratch, Operand(mask));
2017  }
2018  // Should be okay to remove rc
2019 
2020  if (cc == ne) {
2021  bne(condition_met);
2022  }
2023  if (cc == eq) {
2024  beq(condition_met);
2025  }
2026 }
2027 
2029 //
2030 // New MacroAssembler Interfaces added for S390
2031 //
2033 // Primarily used for loading constants
2034 // This should really move to be in macro-assembler as it
2035 // is really a pseudo instruction
2036 // Some usages of this intend for a FIXED_SEQUENCE to be used
2037 // @TODO - break this dependency so we can optimize mov() in general
2038 // and only use the generic version when we require a fixed sequence
2039 void MacroAssembler::LoadRepresentation(Register dst, const MemOperand& mem,
2040  Representation r, Register scratch) {
2041  DCHECK(!r.IsDouble());
2042  if (r.IsInteger8()) {
2043  LoadB(dst, mem);
2044  } else if (r.IsUInteger8()) {
2045  LoadlB(dst, mem);
2046  } else if (r.IsInteger16()) {
2047  LoadHalfWordP(dst, mem, scratch);
2048  } else if (r.IsUInteger16()) {
2049  LoadHalfWordP(dst, mem, scratch);
2050 #if V8_TARGET_ARCH_S390X
2051  } else if (r.IsInteger32()) {
2052  LoadW(dst, mem, scratch);
2053 #endif
2054  } else {
2055  LoadP(dst, mem, scratch);
2056  }
2057 }
2058 
2059 void MacroAssembler::StoreRepresentation(Register src, const MemOperand& mem,
2060  Representation r, Register scratch) {
2061  DCHECK(!r.IsDouble());
2062  if (r.IsInteger8() || r.IsUInteger8()) {
2063  StoreByte(src, mem, scratch);
2064  } else if (r.IsInteger16() || r.IsUInteger16()) {
2065  StoreHalfWord(src, mem, scratch);
2066 #if V8_TARGET_ARCH_S390X
2067  } else if (r.IsInteger32()) {
2068  StoreW(src, mem, scratch);
2069 #endif
2070  } else {
2071  if (r.IsHeapObject()) {
2072  AssertNotSmi(src);
2073  } else if (r.IsSmi()) {
2074  AssertSmi(src);
2075  }
2076  StoreP(src, mem, scratch);
2077  }
2078 }
2079 
2080 Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2, Register reg3,
2081  Register reg4, Register reg5,
2082  Register reg6) {
2083  RegList regs = 0;
2084  if (reg1.is_valid()) regs |= reg1.bit();
2085  if (reg2.is_valid()) regs |= reg2.bit();
2086  if (reg3.is_valid()) regs |= reg3.bit();
2087  if (reg4.is_valid()) regs |= reg4.bit();
2088  if (reg5.is_valid()) regs |= reg5.bit();
2089  if (reg6.is_valid()) regs |= reg6.bit();
2090 
2091  const RegisterConfiguration* config = RegisterConfiguration::Default();
2092  for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
2093  int code = config->GetAllocatableGeneralCode(i);
2094  Register candidate = Register::from_code(code);
2095  if (regs & candidate.bit()) continue;
2096  return candidate;
2097  }
2098  UNREACHABLE();
2099 }
2100 
2101 void TurboAssembler::mov(Register dst, const Operand& src) {
2102 #if V8_TARGET_ARCH_S390X
2103  int64_t value;
2104 #else
2105  int value;
2106 #endif
2107  if (src.is_heap_object_request()) {
2108  RequestHeapObject(src.heap_object_request());
2109  value = 0;
2110  } else {
2111  value = src.immediate();
2112  }
2113 
2114  if (src.rmode() != RelocInfo::NONE) {
2115  // some form of relocation needed
2116  RecordRelocInfo(src.rmode(), value);
2117  }
2118 
2119 #if V8_TARGET_ARCH_S390X
2120  int32_t hi_32 = static_cast<int64_t>(value) >> 32;
2121  int32_t lo_32 = static_cast<int32_t>(value);
2122 
2123  iihf(dst, Operand(hi_32));
2124  iilf(dst, Operand(lo_32));
2125 #else
2126  iilf(dst, Operand(value));
2127 #endif
2128 }
2129 
2130 void TurboAssembler::Mul32(Register dst, const MemOperand& src1) {
2131  if (is_uint12(src1.offset())) {
2132  ms(dst, src1);
2133  } else if (is_int20(src1.offset())) {
2134  msy(dst, src1);
2135  } else {
2136  UNIMPLEMENTED();
2137  }
2138 }
2139 
2140 void TurboAssembler::Mul32(Register dst, Register src1) { msr(dst, src1); }
2141 
2142 void TurboAssembler::Mul32(Register dst, const Operand& src1) {
2143  msfi(dst, src1);
2144 }
2145 
2146 #define Generate_MulHigh32(instr) \
2147  { \
2148  lgfr(dst, src1); \
2149  instr(dst, src2); \
2150  srlg(dst, dst, Operand(32)); \
2151  }
2152 
2153 void TurboAssembler::MulHigh32(Register dst, Register src1,
2154  const MemOperand& src2) {
2155  Generate_MulHigh32(msgf);
2156 }
2157 
2158 void TurboAssembler::MulHigh32(Register dst, Register src1, Register src2) {
2159  if (dst == src2) {
2160  std::swap(src1, src2);
2161  }
2162  Generate_MulHigh32(msgfr);
2163 }
2164 
2165 void TurboAssembler::MulHigh32(Register dst, Register src1,
2166  const Operand& src2) {
2167  Generate_MulHigh32(msgfi);
2168 }
2169 
2170 #undef Generate_MulHigh32
2171 
2172 #define Generate_MulHighU32(instr) \
2173  { \
2174  lr(r1, src1); \
2175  instr(r0, src2); \
2176  LoadlW(dst, r0); \
2177  }
2178 
2179 void TurboAssembler::MulHighU32(Register dst, Register src1,
2180  const MemOperand& src2) {
2181  Generate_MulHighU32(ml);
2182 }
2183 
2184 void TurboAssembler::MulHighU32(Register dst, Register src1, Register src2) {
2185  Generate_MulHighU32(mlr);
2186 }
2187 
2188 void TurboAssembler::MulHighU32(Register dst, Register src1,
2189  const Operand& src2) {
2190  USE(dst);
2191  USE(src1);
2192  USE(src2);
2193  UNREACHABLE();
2194 }
2195 
2196 #undef Generate_MulHighU32
2197 
2198 #define Generate_Mul32WithOverflowIfCCUnequal(instr) \
2199  { \
2200  lgfr(dst, src1); \
2201  instr(dst, src2); \
2202  cgfr(dst, dst); \
2203  }
2204 
2205 void TurboAssembler::Mul32WithOverflowIfCCUnequal(Register dst, Register src1,
2206  const MemOperand& src2) {
2207  Register result = dst;
2208  if (src2.rx() == dst || src2.rb() == dst) dst = r0;
2209  Generate_Mul32WithOverflowIfCCUnequal(msgf);
2210  if (result != dst) llgfr(result, dst);
2211 }
2212 
2213 void TurboAssembler::Mul32WithOverflowIfCCUnequal(Register dst, Register src1,
2214  Register src2) {
2215  if (dst == src2) {
2216  std::swap(src1, src2);
2217  }
2218  Generate_Mul32WithOverflowIfCCUnequal(msgfr);
2219 }
2220 
2221 void TurboAssembler::Mul32WithOverflowIfCCUnequal(Register dst, Register src1,
2222  const Operand& src2) {
2223  Generate_Mul32WithOverflowIfCCUnequal(msgfi);
2224 }
2225 
2226 #undef Generate_Mul32WithOverflowIfCCUnequal
2227 
2228 void TurboAssembler::Mul64(Register dst, const MemOperand& src1) {
2229  if (is_int20(src1.offset())) {
2230  msg(dst, src1);
2231  } else {
2232  UNIMPLEMENTED();
2233  }
2234 }
2235 
2236 void TurboAssembler::Mul64(Register dst, Register src1) { msgr(dst, src1); }
2237 
2238 void TurboAssembler::Mul64(Register dst, const Operand& src1) {
2239  msgfi(dst, src1);
2240 }
2241 
2242 void TurboAssembler::Mul(Register dst, Register src1, Register src2) {
2243  if (CpuFeatures::IsSupported(MISC_INSTR_EXT2)) {
2244  MulPWithCondition(dst, src1, src2);
2245  } else {
2246  if (dst == src2) {
2247  MulP(dst, src1);
2248  } else if (dst == src1) {
2249  MulP(dst, src2);
2250  } else {
2251  Move(dst, src1);
2252  MulP(dst, src2);
2253  }
2254  }
2255 }
2256 
2257 void TurboAssembler::DivP(Register dividend, Register divider) {
2258  // have to make sure the src and dst are reg pairs
2259  DCHECK_EQ(dividend.code() % 2, 0);
2260 #if V8_TARGET_ARCH_S390X
2261  dsgr(dividend, divider);
2262 #else
2263  dr(dividend, divider);
2264 #endif
2265 }
2266 
2267 #define Generate_Div32(instr) \
2268  { \
2269  lgfr(r1, src1); \
2270  instr(r0, src2); \
2271  LoadlW(dst, r1); \
2272  }
2273 
2274 void TurboAssembler::Div32(Register dst, Register src1,
2275  const MemOperand& src2) {
2276  Generate_Div32(dsgf);
2277 }
2278 
2279 void TurboAssembler::Div32(Register dst, Register src1, Register src2) {
2280  Generate_Div32(dsgfr);
2281 }
2282 
2283 #undef Generate_Div32
2284 
2285 #define Generate_DivU32(instr) \
2286  { \
2287  lr(r0, src1); \
2288  srdl(r0, Operand(32)); \
2289  instr(r0, src2); \
2290  LoadlW(dst, r1); \
2291  }
2292 
2293 void TurboAssembler::DivU32(Register dst, Register src1,
2294  const MemOperand& src2) {
2295  Generate_DivU32(dl);
2296 }
2297 
2298 void TurboAssembler::DivU32(Register dst, Register src1, Register src2) {
2299  Generate_DivU32(dlr);
2300 }
2301 
2302 #undef Generate_DivU32
2303 
2304 #define Generate_Div64(instr) \
2305  { \
2306  lgr(r1, src1); \
2307  instr(r0, src2); \
2308  lgr(dst, r1); \
2309  }
2310 
2311 void TurboAssembler::Div64(Register dst, Register src1,
2312  const MemOperand& src2) {
2313  Generate_Div64(dsg);
2314 }
2315 
2316 void TurboAssembler::Div64(Register dst, Register src1, Register src2) {
2317  Generate_Div64(dsgr);
2318 }
2319 
2320 #undef Generate_Div64
2321 
2322 #define Generate_DivU64(instr) \
2323  { \
2324  lgr(r1, src1); \
2325  lghi(r0, Operand::Zero()); \
2326  instr(r0, src2); \
2327  lgr(dst, r1); \
2328  }
2329 
2330 void TurboAssembler::DivU64(Register dst, Register src1,
2331  const MemOperand& src2) {
2332  Generate_DivU64(dlg);
2333 }
2334 
2335 void TurboAssembler::DivU64(Register dst, Register src1, Register src2) {
2336  Generate_DivU64(dlgr);
2337 }
2338 
2339 #undef Generate_DivU64
2340 
2341 #define Generate_Mod32(instr) \
2342  { \
2343  lgfr(r1, src1); \
2344  instr(r0, src2); \
2345  LoadlW(dst, r0); \
2346  }
2347 
2348 void TurboAssembler::Mod32(Register dst, Register src1,
2349  const MemOperand& src2) {
2350  Generate_Mod32(dsgf);
2351 }
2352 
2353 void TurboAssembler::Mod32(Register dst, Register src1, Register src2) {
2354  Generate_Mod32(dsgfr);
2355 }
2356 
2357 #undef Generate_Mod32
2358 
2359 #define Generate_ModU32(instr) \
2360  { \
2361  lr(r0, src1); \
2362  srdl(r0, Operand(32)); \
2363  instr(r0, src2); \
2364  LoadlW(dst, r0); \
2365  }
2366 
2367 void TurboAssembler::ModU32(Register dst, Register src1,
2368  const MemOperand& src2) {
2369  Generate_ModU32(dl);
2370 }
2371 
2372 void TurboAssembler::ModU32(Register dst, Register src1, Register src2) {
2373  Generate_ModU32(dlr);
2374 }
2375 
2376 #undef Generate_ModU32
2377 
2378 #define Generate_Mod64(instr) \
2379  { \
2380  lgr(r1, src1); \
2381  instr(r0, src2); \
2382  lgr(dst, r0); \
2383  }
2384 
2385 void TurboAssembler::Mod64(Register dst, Register src1,
2386  const MemOperand& src2) {
2387  Generate_Mod64(dsg);
2388 }
2389 
2390 void TurboAssembler::Mod64(Register dst, Register src1, Register src2) {
2391  Generate_Mod64(dsgr);
2392 }
2393 
2394 #undef Generate_Mod64
2395 
2396 #define Generate_ModU64(instr) \
2397  { \
2398  lgr(r1, src1); \
2399  lghi(r0, Operand::Zero()); \
2400  instr(r0, src2); \
2401  lgr(dst, r0); \
2402  }
2403 
2404 void TurboAssembler::ModU64(Register dst, Register src1,
2405  const MemOperand& src2) {
2406  Generate_ModU64(dlg);
2407 }
2408 
2409 void TurboAssembler::ModU64(Register dst, Register src1, Register src2) {
2410  Generate_ModU64(dlgr);
2411 }
2412 
2413 #undef Generate_ModU64
2414 
2415 void TurboAssembler::MulP(Register dst, const Operand& opnd) {
2416 #if V8_TARGET_ARCH_S390X
2417  msgfi(dst, opnd);
2418 #else
2419  msfi(dst, opnd);
2420 #endif
2421 }
2422 
2423 void TurboAssembler::MulP(Register dst, Register src) {
2424 #if V8_TARGET_ARCH_S390X
2425  msgr(dst, src);
2426 #else
2427  msr(dst, src);
2428 #endif
2429 }
2430 
2431 void TurboAssembler::MulPWithCondition(Register dst, Register src1,
2432  Register src2) {
2433  CHECK(CpuFeatures::IsSupported(MISC_INSTR_EXT2));
2434 #if V8_TARGET_ARCH_S390X
2435  msgrkc(dst, src1, src2);
2436 #else
2437  msrkc(dst, src1, src2);
2438 #endif
2439 }
2440 
2441 void TurboAssembler::MulP(Register dst, const MemOperand& opnd) {
2442 #if V8_TARGET_ARCH_S390X
2443  if (is_uint16(opnd.offset())) {
2444  ms(dst, opnd);
2445  } else if (is_int20(opnd.offset())) {
2446  msy(dst, opnd);
2447  } else {
2448  UNIMPLEMENTED();
2449  }
2450 #else
2451  if (is_int20(opnd.offset())) {
2452  msg(dst, opnd);
2453  } else {
2454  UNIMPLEMENTED();
2455  }
2456 #endif
2457 }
2458 
2459 void TurboAssembler::Sqrt(DoubleRegister result, DoubleRegister input) {
2460  sqdbr(result, input);
2461 }
2462 void TurboAssembler::Sqrt(DoubleRegister result, const MemOperand& input) {
2463  if (is_uint12(input.offset())) {
2464  sqdb(result, input);
2465  } else {
2466  ldy(result, input);
2467  sqdbr(result, result);
2468  }
2469 }
2470 //----------------------------------------------------------------------------
2471 // Add Instructions
2472 //----------------------------------------------------------------------------
2473 
2474 // Add 32-bit (Register dst = Register dst + Immediate opnd)
2475 void TurboAssembler::Add32(Register dst, const Operand& opnd) {
2476  if (is_int16(opnd.immediate()))
2477  ahi(dst, opnd);
2478  else
2479  afi(dst, opnd);
2480 }
2481 
2482 // Add 32-bit (Register dst = Register dst + Immediate opnd)
2483 void TurboAssembler::Add32_RI(Register dst, const Operand& opnd) {
2484  // Just a wrapper for above
2485  Add32(dst, opnd);
2486 }
2487 
2488 // Add Pointer Size (Register dst = Register dst + Immediate opnd)
2489 void TurboAssembler::AddP(Register dst, const Operand& opnd) {
2490 #if V8_TARGET_ARCH_S390X
2491  if (is_int16(opnd.immediate()))
2492  aghi(dst, opnd);
2493  else
2494  agfi(dst, opnd);
2495 #else
2496  Add32(dst, opnd);
2497 #endif
2498 }
2499 
2500 // Add 32-bit (Register dst = Register src + Immediate opnd)
2501 void TurboAssembler::Add32(Register dst, Register src, const Operand& opnd) {
2502  if (dst != src) {
2503  if (CpuFeatures::IsSupported(DISTINCT_OPS) && is_int16(opnd.immediate())) {
2504  ahik(dst, src, opnd);
2505  return;
2506  }
2507  lr(dst, src);
2508  }
2509  Add32(dst, opnd);
2510 }
2511 
2512 // Add 32-bit (Register dst = Register src + Immediate opnd)
2513 void TurboAssembler::Add32_RRI(Register dst, Register src,
2514  const Operand& opnd) {
2515  // Just a wrapper for above
2516  Add32(dst, src, opnd);
2517 }
2518 
2519 // Add Pointer Size (Register dst = Register src + Immediate opnd)
2520 void TurboAssembler::AddP(Register dst, Register src, const Operand& opnd) {
2521  if (dst != src) {
2522  if (CpuFeatures::IsSupported(DISTINCT_OPS) && is_int16(opnd.immediate())) {
2523  AddPImm_RRI(dst, src, opnd);
2524  return;
2525  }
2526  LoadRR(dst, src);
2527  }
2528  AddP(dst, opnd);
2529 }
2530 
2531 // Add 32-bit (Register dst = Register dst + Register src)
2532 void TurboAssembler::Add32(Register dst, Register src) { ar(dst, src); }
2533 
2534 // Add Pointer Size (Register dst = Register dst + Register src)
2535 void TurboAssembler::AddP(Register dst, Register src) { AddRR(dst, src); }
2536 
2537 // Add Pointer Size with src extension
2538 // (Register dst(ptr) = Register dst (ptr) + Register src (32 | 32->64))
2539 // src is treated as a 32-bit signed integer, which is sign extended to
2540 // 64-bit if necessary.
2541 void TurboAssembler::AddP_ExtendSrc(Register dst, Register src) {
2542 #if V8_TARGET_ARCH_S390X
2543  agfr(dst, src);
2544 #else
2545  ar(dst, src);
2546 #endif
2547 }
2548 
2549 // Add 32-bit (Register dst = Register src1 + Register src2)
2550 void TurboAssembler::Add32(Register dst, Register src1, Register src2) {
2551  if (dst != src1 && dst != src2) {
2552  // We prefer to generate AR/AGR, over the non clobbering ARK/AGRK
2553  // as AR is a smaller instruction
2554  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
2555  ark(dst, src1, src2);
2556  return;
2557  } else {
2558  lr(dst, src1);
2559  }
2560  } else if (dst == src2) {
2561  src2 = src1;
2562  }
2563  ar(dst, src2);
2564 }
2565 
2566 // Add Pointer Size (Register dst = Register src1 + Register src2)
2567 void TurboAssembler::AddP(Register dst, Register src1, Register src2) {
2568  if (dst != src1 && dst != src2) {
2569  // We prefer to generate AR/AGR, over the non clobbering ARK/AGRK
2570  // as AR is a smaller instruction
2571  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
2572  AddP_RRR(dst, src1, src2);
2573  return;
2574  } else {
2575  LoadRR(dst, src1);
2576  }
2577  } else if (dst == src2) {
2578  src2 = src1;
2579  }
2580  AddRR(dst, src2);
2581 }
2582 
2583 // Add Pointer Size with src extension
2584 // (Register dst (ptr) = Register dst (ptr) + Register src1 (ptr) +
2585 // Register src2 (32 | 32->64))
2586 // src is treated as a 32-bit signed integer, which is sign extended to
2587 // 64-bit if necessary.
2588 void TurboAssembler::AddP_ExtendSrc(Register dst, Register src1,
2589  Register src2) {
2590 #if V8_TARGET_ARCH_S390X
2591  if (dst == src2) {
2592  // The source we need to sign extend is the same as result.
2593  lgfr(dst, src2);
2594  agr(dst, src1);
2595  } else {
2596  if (dst != src1) LoadRR(dst, src1);
2597  agfr(dst, src2);
2598  }
2599 #else
2600  AddP(dst, src1, src2);
2601 #endif
2602 }
2603 
2604 // Add 32-bit (Register-Memory)
2605 void TurboAssembler::Add32(Register dst, const MemOperand& opnd) {
2606  DCHECK(is_int20(opnd.offset()));
2607  if (is_uint12(opnd.offset()))
2608  a(dst, opnd);
2609  else
2610  ay(dst, opnd);
2611 }
2612 
2613 // Add Pointer Size (Register-Memory)
2614 void TurboAssembler::AddP(Register dst, const MemOperand& opnd) {
2615 #if V8_TARGET_ARCH_S390X
2616  DCHECK(is_int20(opnd.offset()));
2617  ag(dst, opnd);
2618 #else
2619  Add32(dst, opnd);
2620 #endif
2621 }
2622 
2623 // Add Pointer Size with src extension
2624 // (Register dst (ptr) = Register dst (ptr) + Mem opnd (32 | 32->64))
2625 // src is treated as a 32-bit signed integer, which is sign extended to
2626 // 64-bit if necessary.
2627 void TurboAssembler::AddP_ExtendSrc(Register dst, const MemOperand& opnd) {
2628 #if V8_TARGET_ARCH_S390X
2629  DCHECK(is_int20(opnd.offset()));
2630  agf(dst, opnd);
2631 #else
2632  Add32(dst, opnd);
2633 #endif
2634 }
2635 
2636 // Add 32-bit (Memory - Immediate)
2637 void TurboAssembler::Add32(const MemOperand& opnd, const Operand& imm) {
2638  DCHECK(is_int8(imm.immediate()));
2639  DCHECK(is_int20(opnd.offset()));
2640  DCHECK(CpuFeatures::IsSupported(GENERAL_INSTR_EXT));
2641  asi(opnd, imm);
2642 }
2643 
2644 // Add Pointer-sized (Memory - Immediate)
2645 void TurboAssembler::AddP(const MemOperand& opnd, const Operand& imm) {
2646  DCHECK(is_int8(imm.immediate()));
2647  DCHECK(is_int20(opnd.offset()));
2648  DCHECK(CpuFeatures::IsSupported(GENERAL_INSTR_EXT));
2649 #if V8_TARGET_ARCH_S390X
2650  agsi(opnd, imm);
2651 #else
2652  asi(opnd, imm);
2653 #endif
2654 }
2655 
2656 //----------------------------------------------------------------------------
2657 // Add Logical Instructions
2658 //----------------------------------------------------------------------------
2659 
2660 // Add Logical With Carry 32-bit (Register dst = Register src1 + Register src2)
2661 void TurboAssembler::AddLogicalWithCarry32(Register dst, Register src1,
2662  Register src2) {
2663  if (dst != src2 && dst != src1) {
2664  lr(dst, src1);
2665  alcr(dst, src2);
2666  } else if (dst != src2) {
2667  // dst == src1
2668  DCHECK(dst == src1);
2669  alcr(dst, src2);
2670  } else {
2671  // dst == src2
2672  DCHECK(dst == src2);
2673  alcr(dst, src1);
2674  }
2675 }
2676 
2677 // Add Logical 32-bit (Register dst = Register src1 + Register src2)
2678 void TurboAssembler::AddLogical32(Register dst, Register src1, Register src2) {
2679  if (dst != src2 && dst != src1) {
2680  lr(dst, src1);
2681  alr(dst, src2);
2682  } else if (dst != src2) {
2683  // dst == src1
2684  DCHECK(dst == src1);
2685  alr(dst, src2);
2686  } else {
2687  // dst == src2
2688  DCHECK(dst == src2);
2689  alr(dst, src1);
2690  }
2691 }
2692 
2693 // Add Logical 32-bit (Register dst = Register dst + Immediate opnd)
2694 void TurboAssembler::AddLogical(Register dst, const Operand& imm) {
2695  alfi(dst, imm);
2696 }
2697 
2698 // Add Logical Pointer Size (Register dst = Register dst + Immediate opnd)
2699 void TurboAssembler::AddLogicalP(Register dst, const Operand& imm) {
2700 #ifdef V8_TARGET_ARCH_S390X
2701  algfi(dst, imm);
2702 #else
2703  AddLogical(dst, imm);
2704 #endif
2705 }
2706 
2707 // Add Logical 32-bit (Register-Memory)
2708 void TurboAssembler::AddLogical(Register dst, const MemOperand& opnd) {
2709  DCHECK(is_int20(opnd.offset()));
2710  if (is_uint12(opnd.offset()))
2711  al_z(dst, opnd);
2712  else
2713  aly(dst, opnd);
2714 }
2715 
2716 // Add Logical Pointer Size (Register-Memory)
2717 void TurboAssembler::AddLogicalP(Register dst, const MemOperand& opnd) {
2718 #if V8_TARGET_ARCH_S390X
2719  DCHECK(is_int20(opnd.offset()));
2720  alg(dst, opnd);
2721 #else
2722  AddLogical(dst, opnd);
2723 #endif
2724 }
2725 
2726 //----------------------------------------------------------------------------
2727 // Subtract Instructions
2728 //----------------------------------------------------------------------------
2729 
2730 // Subtract Logical With Carry 32-bit (Register dst = Register src1 - Register
2731 // src2)
2732 void TurboAssembler::SubLogicalWithBorrow32(Register dst, Register src1,
2733  Register src2) {
2734  if (dst != src2 && dst != src1) {
2735  lr(dst, src1);
2736  slbr(dst, src2);
2737  } else if (dst != src2) {
2738  // dst == src1
2739  DCHECK(dst == src1);
2740  slbr(dst, src2);
2741  } else {
2742  // dst == src2
2743  DCHECK(dst == src2);
2744  lr(r0, dst);
2745  SubLogicalWithBorrow32(dst, src1, r0);
2746  }
2747 }
2748 
2749 // Subtract Logical 32-bit (Register dst = Register src1 - Register src2)
2750 void TurboAssembler::SubLogical32(Register dst, Register src1, Register src2) {
2751  if (dst != src2 && dst != src1) {
2752  lr(dst, src1);
2753  slr(dst, src2);
2754  } else if (dst != src2) {
2755  // dst == src1
2756  DCHECK(dst == src1);
2757  slr(dst, src2);
2758  } else {
2759  // dst == src2
2760  DCHECK(dst == src2);
2761  lr(r0, dst);
2762  SubLogical32(dst, src1, r0);
2763  }
2764 }
2765 
2766 // Subtract 32-bit (Register dst = Register dst - Immediate opnd)
2767 void TurboAssembler::Sub32(Register dst, const Operand& imm) {
2768  Add32(dst, Operand(-(imm.immediate())));
2769 }
2770 
2771 // Subtract Pointer Size (Register dst = Register dst - Immediate opnd)
2772 void TurboAssembler::SubP(Register dst, const Operand& imm) {
2773  AddP(dst, Operand(-(imm.immediate())));
2774 }
2775 
2776 // Subtract 32-bit (Register dst = Register src - Immediate opnd)
2777 void TurboAssembler::Sub32(Register dst, Register src, const Operand& imm) {
2778  Add32(dst, src, Operand(-(imm.immediate())));
2779 }
2780 
2781 // Subtract Pointer Sized (Register dst = Register src - Immediate opnd)
2782 void TurboAssembler::SubP(Register dst, Register src, const Operand& imm) {
2783  AddP(dst, src, Operand(-(imm.immediate())));
2784 }
2785 
2786 // Subtract 32-bit (Register dst = Register dst - Register src)
2787 void TurboAssembler::Sub32(Register dst, Register src) { sr(dst, src); }
2788 
2789 // Subtract Pointer Size (Register dst = Register dst - Register src)
2790 void TurboAssembler::SubP(Register dst, Register src) { SubRR(dst, src); }
2791 
2792 // Subtract Pointer Size with src extension
2793 // (Register dst(ptr) = Register dst (ptr) - Register src (32 | 32->64))
2794 // src is treated as a 32-bit signed integer, which is sign extended to
2795 // 64-bit if necessary.
2796 void TurboAssembler::SubP_ExtendSrc(Register dst, Register src) {
2797 #if V8_TARGET_ARCH_S390X
2798  sgfr(dst, src);
2799 #else
2800  sr(dst, src);
2801 #endif
2802 }
2803 
2804 // Subtract 32-bit (Register = Register - Register)
2805 void TurboAssembler::Sub32(Register dst, Register src1, Register src2) {
2806  // Use non-clobbering version if possible
2807  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
2808  srk(dst, src1, src2);
2809  return;
2810  }
2811  if (dst != src1 && dst != src2) lr(dst, src1);
2812  // In scenario where we have dst = src - dst, we need to swap and negate
2813  if (dst != src1 && dst == src2) {
2814  Label done;
2815  lcr(dst, dst); // dst = -dst
2816  b(overflow, &done);
2817  ar(dst, src1); // dst = dst + src
2818  bind(&done);
2819  } else {
2820  sr(dst, src2);
2821  }
2822 }
2823 
2824 // Subtract Pointer Sized (Register = Register - Register)
2825 void TurboAssembler::SubP(Register dst, Register src1, Register src2) {
2826  // Use non-clobbering version if possible
2827  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
2828  SubP_RRR(dst, src1, src2);
2829  return;
2830  }
2831  if (dst != src1 && dst != src2) LoadRR(dst, src1);
2832  // In scenario where we have dst = src - dst, we need to swap and negate
2833  if (dst != src1 && dst == src2) {
2834  Label done;
2835  LoadComplementRR(dst, dst); // dst = -dst
2836  b(overflow, &done);
2837  AddP(dst, src1); // dst = dst + src
2838  bind(&done);
2839  } else {
2840  SubP(dst, src2);
2841  }
2842 }
2843 
2844 // Subtract Pointer Size with src extension
2845 // (Register dst(ptr) = Register dst (ptr) - Register src (32 | 32->64))
2846 // src is treated as a 32-bit signed integer, which is sign extended to
2847 // 64-bit if necessary.
2848 void TurboAssembler::SubP_ExtendSrc(Register dst, Register src1,
2849  Register src2) {
2850 #if V8_TARGET_ARCH_S390X
2851  if (dst != src1 && dst != src2) LoadRR(dst, src1);
2852 
2853  // In scenario where we have dst = src - dst, we need to swap and negate
2854  if (dst != src1 && dst == src2) {
2855  lgfr(dst, dst); // Sign extend this operand first.
2856  LoadComplementRR(dst, dst); // dst = -dst
2857  AddP(dst, src1); // dst = -dst + src
2858  } else {
2859  sgfr(dst, src2);
2860  }
2861 #else
2862  SubP(dst, src1, src2);
2863 #endif
2864 }
2865 
2866 // Subtract 32-bit (Register-Memory)
2867 void TurboAssembler::Sub32(Register dst, const MemOperand& opnd) {
2868  DCHECK(is_int20(opnd.offset()));
2869  if (is_uint12(opnd.offset()))
2870  s(dst, opnd);
2871  else
2872  sy(dst, opnd);
2873 }
2874 
2875 // Subtract Pointer Sized (Register - Memory)
2876 void TurboAssembler::SubP(Register dst, const MemOperand& opnd) {
2877 #if V8_TARGET_ARCH_S390X
2878  sg(dst, opnd);
2879 #else
2880  Sub32(dst, opnd);
2881 #endif
2882 }
2883 
2884 void TurboAssembler::MovIntToFloat(DoubleRegister dst, Register src) {
2885  sllg(r0, src, Operand(32));
2886  ldgr(dst, r0);
2887 }
2888 
2889 void TurboAssembler::MovFloatToInt(Register dst, DoubleRegister src) {
2890  lgdr(dst, src);
2891  srlg(dst, dst, Operand(32));
2892 }
2893 
2894 void TurboAssembler::SubP_ExtendSrc(Register dst, const MemOperand& opnd) {
2895 #if V8_TARGET_ARCH_S390X
2896  DCHECK(is_int20(opnd.offset()));
2897  sgf(dst, opnd);
2898 #else
2899  Sub32(dst, opnd);
2900 #endif
2901 }
2902 
2903 // Load And Subtract 32-bit (similar to laa/lan/lao/lax)
2904 void TurboAssembler::LoadAndSub32(Register dst, Register src,
2905  const MemOperand& opnd) {
2906  lcr(dst, src);
2907  laa(dst, dst, opnd);
2908 }
2909 
2910 void TurboAssembler::LoadAndSub64(Register dst, Register src,
2911  const MemOperand& opnd) {
2912  lcgr(dst, src);
2913  laag(dst, dst, opnd);
2914 }
2915 
2916 //----------------------------------------------------------------------------
2917 // Subtract Logical Instructions
2918 //----------------------------------------------------------------------------
2919 
2920 // Subtract Logical 32-bit (Register - Memory)
2921 void TurboAssembler::SubLogical(Register dst, const MemOperand& opnd) {
2922  DCHECK(is_int20(opnd.offset()));
2923  if (is_uint12(opnd.offset()))
2924  sl(dst, opnd);
2925  else
2926  sly(dst, opnd);
2927 }
2928 
2929 // Subtract Logical Pointer Sized (Register - Memory)
2930 void TurboAssembler::SubLogicalP(Register dst, const MemOperand& opnd) {
2931  DCHECK(is_int20(opnd.offset()));
2932 #if V8_TARGET_ARCH_S390X
2933  slgf(dst, opnd);
2934 #else
2935  SubLogical(dst, opnd);
2936 #endif
2937 }
2938 
2939 // Subtract Logical Pointer Size with src extension
2940 // (Register dst (ptr) = Register dst (ptr) - Mem opnd (32 | 32->64))
2941 // src is treated as a 32-bit signed integer, which is sign extended to
2942 // 64-bit if necessary.
2943 void TurboAssembler::SubLogicalP_ExtendSrc(Register dst,
2944  const MemOperand& opnd) {
2945 #if V8_TARGET_ARCH_S390X
2946  DCHECK(is_int20(opnd.offset()));
2947  slgf(dst, opnd);
2948 #else
2949  SubLogical(dst, opnd);
2950 #endif
2951 }
2952 
2953 //----------------------------------------------------------------------------
2954 // Bitwise Operations
2955 //----------------------------------------------------------------------------
2956 
2957 // AND 32-bit - dst = dst & src
2958 void TurboAssembler::And(Register dst, Register src) { nr(dst, src); }
2959 
2960 // AND Pointer Size - dst = dst & src
2961 void TurboAssembler::AndP(Register dst, Register src) { AndRR(dst, src); }
2962 
2963 // Non-clobbering AND 32-bit - dst = src1 & src1
2964 void TurboAssembler::And(Register dst, Register src1, Register src2) {
2965  if (dst != src1 && dst != src2) {
2966  // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
2967  // as XR is a smaller instruction
2968  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
2969  nrk(dst, src1, src2);
2970  return;
2971  } else {
2972  lr(dst, src1);
2973  }
2974  } else if (dst == src2) {
2975  src2 = src1;
2976  }
2977  And(dst, src2);
2978 }
2979 
2980 // Non-clobbering AND pointer size - dst = src1 & src1
2981 void TurboAssembler::AndP(Register dst, Register src1, Register src2) {
2982  if (dst != src1 && dst != src2) {
2983  // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
2984  // as XR is a smaller instruction
2985  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
2986  AndP_RRR(dst, src1, src2);
2987  return;
2988  } else {
2989  LoadRR(dst, src1);
2990  }
2991  } else if (dst == src2) {
2992  src2 = src1;
2993  }
2994  AndP(dst, src2);
2995 }
2996 
2997 // AND 32-bit (Reg - Mem)
2998 void TurboAssembler::And(Register dst, const MemOperand& opnd) {
2999  DCHECK(is_int20(opnd.offset()));
3000  if (is_uint12(opnd.offset()))
3001  n(dst, opnd);
3002  else
3003  ny(dst, opnd);
3004 }
3005 
3006 // AND Pointer Size (Reg - Mem)
3007 void TurboAssembler::AndP(Register dst, const MemOperand& opnd) {
3008  DCHECK(is_int20(opnd.offset()));
3009 #if V8_TARGET_ARCH_S390X
3010  ng(dst, opnd);
3011 #else
3012  And(dst, opnd);
3013 #endif
3014 }
3015 
3016 // AND 32-bit - dst = dst & imm
3017 void TurboAssembler::And(Register dst, const Operand& opnd) { nilf(dst, opnd); }
3018 
3019 // AND Pointer Size - dst = dst & imm
3020 void TurboAssembler::AndP(Register dst, const Operand& opnd) {
3021 #if V8_TARGET_ARCH_S390X
3022  intptr_t value = opnd.immediate();
3023  if (value >> 32 != -1) {
3024  // this may not work b/c condition code won't be set correctly
3025  nihf(dst, Operand(value >> 32));
3026  }
3027  nilf(dst, Operand(value & 0xFFFFFFFF));
3028 #else
3029  And(dst, opnd);
3030 #endif
3031 }
3032 
3033 // AND 32-bit - dst = src & imm
3034 void TurboAssembler::And(Register dst, Register src, const Operand& opnd) {
3035  if (dst != src) lr(dst, src);
3036  nilf(dst, opnd);
3037 }
3038 
3039 // AND Pointer Size - dst = src & imm
3040 void TurboAssembler::AndP(Register dst, Register src, const Operand& opnd) {
3041  // Try to exploit RISBG first
3042  intptr_t value = opnd.immediate();
3043  if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
3044  intptr_t shifted_value = value;
3045  int trailing_zeros = 0;
3046 
3047  // We start checking how many trailing zeros are left at the end.
3048  while ((0 != shifted_value) && (0 == (shifted_value & 1))) {
3049  trailing_zeros++;
3050  shifted_value >>= 1;
3051  }
3052 
3053  // If temp (value with right-most set of zeros shifted out) is 1 less
3054  // than power of 2, we have consecutive bits of 1.
3055  // Special case: If shift_value is zero, we cannot use RISBG, as it requires
3056  // selection of at least 1 bit.
3057  if ((0 != shifted_value) && base::bits::IsPowerOfTwo(shifted_value + 1)) {
3058  int startBit =
3059  base::bits::CountLeadingZeros64(shifted_value) - trailing_zeros;
3060  int endBit = 63 - trailing_zeros;
3061  // Start: startBit, End: endBit, Shift = 0, true = zero unselected bits.
3062  RotateInsertSelectBits(dst, src, Operand(startBit), Operand(endBit),
3063  Operand::Zero(), true);
3064  return;
3065  } else if (-1 == shifted_value) {
3066  // A Special case in which all top bits up to MSB are 1's. In this case,
3067  // we can set startBit to be 0.
3068  int endBit = 63 - trailing_zeros;
3069  RotateInsertSelectBits(dst, src, Operand::Zero(), Operand(endBit),
3070  Operand::Zero(), true);
3071  return;
3072  }
3073  }
3074 
3075  // If we are &'ing zero, we can just whack the dst register and skip copy
3076  if (dst != src && (0 != value)) LoadRR(dst, src);
3077  AndP(dst, opnd);
3078 }
3079 
3080 // OR 32-bit - dst = dst & src
3081 void TurboAssembler::Or(Register dst, Register src) { or_z(dst, src); }
3082 
3083 // OR Pointer Size - dst = dst & src
3084 void TurboAssembler::OrP(Register dst, Register src) { OrRR(dst, src); }
3085 
3086 // Non-clobbering OR 32-bit - dst = src1 & src1
3087 void TurboAssembler::Or(Register dst, Register src1, Register src2) {
3088  if (dst != src1 && dst != src2) {
3089  // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
3090  // as XR is a smaller instruction
3091  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
3092  ork(dst, src1, src2);
3093  return;
3094  } else {
3095  lr(dst, src1);
3096  }
3097  } else if (dst == src2) {
3098  src2 = src1;
3099  }
3100  Or(dst, src2);
3101 }
3102 
3103 // Non-clobbering OR pointer size - dst = src1 & src1
3104 void TurboAssembler::OrP(Register dst, Register src1, Register src2) {
3105  if (dst != src1 && dst != src2) {
3106  // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
3107  // as XR is a smaller instruction
3108  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
3109  OrP_RRR(dst, src1, src2);
3110  return;
3111  } else {
3112  LoadRR(dst, src1);
3113  }
3114  } else if (dst == src2) {
3115  src2 = src1;
3116  }
3117  OrP(dst, src2);
3118 }
3119 
3120 // OR 32-bit (Reg - Mem)
3121 void TurboAssembler::Or(Register dst, const MemOperand& opnd) {
3122  DCHECK(is_int20(opnd.offset()));
3123  if (is_uint12(opnd.offset()))
3124  o(dst, opnd);
3125  else
3126  oy(dst, opnd);
3127 }
3128 
3129 // OR Pointer Size (Reg - Mem)
3130 void TurboAssembler::OrP(Register dst, const MemOperand& opnd) {
3131  DCHECK(is_int20(opnd.offset()));
3132 #if V8_TARGET_ARCH_S390X
3133  og(dst, opnd);
3134 #else
3135  Or(dst, opnd);
3136 #endif
3137 }
3138 
3139 // OR 32-bit - dst = dst & imm
3140 void TurboAssembler::Or(Register dst, const Operand& opnd) { oilf(dst, opnd); }
3141 
3142 // OR Pointer Size - dst = dst & imm
3143 void TurboAssembler::OrP(Register dst, const Operand& opnd) {
3144 #if V8_TARGET_ARCH_S390X
3145  intptr_t value = opnd.immediate();
3146  if (value >> 32 != 0) {
3147  // this may not work b/c condition code won't be set correctly
3148  oihf(dst, Operand(value >> 32));
3149  }
3150  oilf(dst, Operand(value & 0xFFFFFFFF));
3151 #else
3152  Or(dst, opnd);
3153 #endif
3154 }
3155 
3156 // OR 32-bit - dst = src & imm
3157 void TurboAssembler::Or(Register dst, Register src, const Operand& opnd) {
3158  if (dst != src) lr(dst, src);
3159  oilf(dst, opnd);
3160 }
3161 
3162 // OR Pointer Size - dst = src & imm
3163 void TurboAssembler::OrP(Register dst, Register src, const Operand& opnd) {
3164  if (dst != src) LoadRR(dst, src);
3165  OrP(dst, opnd);
3166 }
3167 
3168 // XOR 32-bit - dst = dst & src
3169 void TurboAssembler::Xor(Register dst, Register src) { xr(dst, src); }
3170 
3171 // XOR Pointer Size - dst = dst & src
3172 void TurboAssembler::XorP(Register dst, Register src) { XorRR(dst, src); }
3173 
3174 // Non-clobbering XOR 32-bit - dst = src1 & src1
3175 void TurboAssembler::Xor(Register dst, Register src1, Register src2) {
3176  if (dst != src1 && dst != src2) {
3177  // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
3178  // as XR is a smaller instruction
3179  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
3180  xrk(dst, src1, src2);
3181  return;
3182  } else {
3183  lr(dst, src1);
3184  }
3185  } else if (dst == src2) {
3186  src2 = src1;
3187  }
3188  Xor(dst, src2);
3189 }
3190 
3191 // Non-clobbering XOR pointer size - dst = src1 & src1
3192 void TurboAssembler::XorP(Register dst, Register src1, Register src2) {
3193  if (dst != src1 && dst != src2) {
3194  // We prefer to generate XR/XGR, over the non clobbering XRK/XRK
3195  // as XR is a smaller instruction
3196  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
3197  XorP_RRR(dst, src1, src2);
3198  return;
3199  } else {
3200  LoadRR(dst, src1);
3201  }
3202  } else if (dst == src2) {
3203  src2 = src1;
3204  }
3205  XorP(dst, src2);
3206 }
3207 
3208 // XOR 32-bit (Reg - Mem)
3209 void TurboAssembler::Xor(Register dst, const MemOperand& opnd) {
3210  DCHECK(is_int20(opnd.offset()));
3211  if (is_uint12(opnd.offset()))
3212  x(dst, opnd);
3213  else
3214  xy(dst, opnd);
3215 }
3216 
3217 // XOR Pointer Size (Reg - Mem)
3218 void TurboAssembler::XorP(Register dst, const MemOperand& opnd) {
3219  DCHECK(is_int20(opnd.offset()));
3220 #if V8_TARGET_ARCH_S390X
3221  xg(dst, opnd);
3222 #else
3223  Xor(dst, opnd);
3224 #endif
3225 }
3226 
3227 // XOR 32-bit - dst = dst & imm
3228 void TurboAssembler::Xor(Register dst, const Operand& opnd) { xilf(dst, opnd); }
3229 
3230 // XOR Pointer Size - dst = dst & imm
3231 void TurboAssembler::XorP(Register dst, const Operand& opnd) {
3232 #if V8_TARGET_ARCH_S390X
3233  intptr_t value = opnd.immediate();
3234  xihf(dst, Operand(value >> 32));
3235  xilf(dst, Operand(value & 0xFFFFFFFF));
3236 #else
3237  Xor(dst, opnd);
3238 #endif
3239 }
3240 
3241 // XOR 32-bit - dst = src & imm
3242 void TurboAssembler::Xor(Register dst, Register src, const Operand& opnd) {
3243  if (dst != src) lr(dst, src);
3244  xilf(dst, opnd);
3245 }
3246 
3247 // XOR Pointer Size - dst = src & imm
3248 void TurboAssembler::XorP(Register dst, Register src, const Operand& opnd) {
3249  if (dst != src) LoadRR(dst, src);
3250  XorP(dst, opnd);
3251 }
3252 
3253 void TurboAssembler::Not32(Register dst, Register src) {
3254  if (src != no_reg && src != dst) lr(dst, src);
3255  xilf(dst, Operand(0xFFFFFFFF));
3256 }
3257 
3258 void TurboAssembler::Not64(Register dst, Register src) {
3259  if (src != no_reg && src != dst) lgr(dst, src);
3260  xihf(dst, Operand(0xFFFFFFFF));
3261  xilf(dst, Operand(0xFFFFFFFF));
3262 }
3263 
3264 void TurboAssembler::NotP(Register dst, Register src) {
3265 #if V8_TARGET_ARCH_S390X
3266  Not64(dst, src);
3267 #else
3268  Not32(dst, src);
3269 #endif
3270 }
3271 
3272 // works the same as mov
3273 void TurboAssembler::Load(Register dst, const Operand& opnd) {
3274  intptr_t value = opnd.immediate();
3275  if (is_int16(value)) {
3276 #if V8_TARGET_ARCH_S390X
3277  lghi(dst, opnd);
3278 #else
3279  lhi(dst, opnd);
3280 #endif
3281  } else if (is_int32(value)) {
3282 #if V8_TARGET_ARCH_S390X
3283  lgfi(dst, opnd);
3284 #else
3285  iilf(dst, opnd);
3286 #endif
3287  } else if (is_uint32(value)) {
3288 #if V8_TARGET_ARCH_S390X
3289  llilf(dst, opnd);
3290 #else
3291  iilf(dst, opnd);
3292 #endif
3293  } else {
3294  int32_t hi_32 = static_cast<int64_t>(value) >> 32;
3295  int32_t lo_32 = static_cast<int32_t>(value);
3296 
3297  iihf(dst, Operand(hi_32));
3298  iilf(dst, Operand(lo_32));
3299  }
3300 }
3301 
3302 void TurboAssembler::Load(Register dst, const MemOperand& opnd) {
3303  DCHECK(is_int20(opnd.offset()));
3304 #if V8_TARGET_ARCH_S390X
3305  lgf(dst, opnd); // 64<-32
3306 #else
3307  if (is_uint12(opnd.offset())) {
3308  l(dst, opnd);
3309  } else {
3310  ly(dst, opnd);
3311  }
3312 #endif
3313 }
3314 
3315 void TurboAssembler::LoadPositiveP(Register result, Register input) {
3316 #if V8_TARGET_ARCH_S390X
3317  lpgr(result, input);
3318 #else
3319  lpr(result, input);
3320 #endif
3321 }
3322 
3323 void TurboAssembler::LoadPositive32(Register result, Register input) {
3324  lpr(result, input);
3325  lgfr(result, result);
3326 }
3327 
3328 //-----------------------------------------------------------------------------
3329 // Compare Helpers
3330 //-----------------------------------------------------------------------------
3331 
3332 // Compare 32-bit Register vs Register
3333 void TurboAssembler::Cmp32(Register src1, Register src2) { cr_z(src1, src2); }
3334 
3335 // Compare Pointer Sized Register vs Register
3336 void TurboAssembler::CmpP(Register src1, Register src2) {
3337 #if V8_TARGET_ARCH_S390X
3338  cgr(src1, src2);
3339 #else
3340  Cmp32(src1, src2);
3341 #endif
3342 }
3343 
3344 // Compare 32-bit Register vs Immediate
3345 // This helper will set up proper relocation entries if required.
3346 void TurboAssembler::Cmp32(Register dst, const Operand& opnd) {
3347  if (opnd.rmode() == RelocInfo::NONE) {
3348  intptr_t value = opnd.immediate();
3349  if (is_int16(value))
3350  chi(dst, opnd);
3351  else
3352  cfi(dst, opnd);
3353  } else {
3354  // Need to generate relocation record here
3355  RecordRelocInfo(opnd.rmode(), opnd.immediate());
3356  cfi(dst, opnd);
3357  }
3358 }
3359 
3360 // Compare Pointer Sized Register vs Immediate
3361 // This helper will set up proper relocation entries if required.
3362 void TurboAssembler::CmpP(Register dst, const Operand& opnd) {
3363 #if V8_TARGET_ARCH_S390X
3364  if (opnd.rmode() == RelocInfo::NONE) {
3365  cgfi(dst, opnd);
3366  } else {
3367  mov(r0, opnd); // Need to generate 64-bit relocation
3368  cgr(dst, r0);
3369  }
3370 #else
3371  Cmp32(dst, opnd);
3372 #endif
3373 }
3374 
3375 // Compare 32-bit Register vs Memory
3376 void TurboAssembler::Cmp32(Register dst, const MemOperand& opnd) {
3377  // make sure offset is within 20 bit range
3378  DCHECK(is_int20(opnd.offset()));
3379  if (is_uint12(opnd.offset()))
3380  c(dst, opnd);
3381  else
3382  cy(dst, opnd);
3383 }
3384 
3385 // Compare Pointer Size Register vs Memory
3386 void TurboAssembler::CmpP(Register dst, const MemOperand& opnd) {
3387  // make sure offset is within 20 bit range
3388  DCHECK(is_int20(opnd.offset()));
3389 #if V8_TARGET_ARCH_S390X
3390  cg(dst, opnd);
3391 #else
3392  Cmp32(dst, opnd);
3393 #endif
3394 }
3395 
3396 // Using cs or scy based on the offset
3397 void TurboAssembler::CmpAndSwap(Register old_val, Register new_val,
3398  const MemOperand& opnd) {
3399  if (is_uint12(opnd.offset())) {
3400  cs(old_val, new_val, opnd);
3401  } else {
3402  csy(old_val, new_val, opnd);
3403  }
3404 }
3405 
3406 void TurboAssembler::CmpAndSwap64(Register old_val, Register new_val,
3407  const MemOperand& opnd) {
3408  DCHECK(is_int20(opnd.offset()));
3409  csg(old_val, new_val, opnd);
3410 }
3411 
3412 //-----------------------------------------------------------------------------
3413 // Compare Logical Helpers
3414 //-----------------------------------------------------------------------------
3415 
3416 // Compare Logical 32-bit Register vs Register
3417 void TurboAssembler::CmpLogical32(Register dst, Register src) { clr(dst, src); }
3418 
3419 // Compare Logical Pointer Sized Register vs Register
3420 void TurboAssembler::CmpLogicalP(Register dst, Register src) {
3421 #ifdef V8_TARGET_ARCH_S390X
3422  clgr(dst, src);
3423 #else
3424  CmpLogical32(dst, src);
3425 #endif
3426 }
3427 
3428 // Compare Logical 32-bit Register vs Immediate
3429 void TurboAssembler::CmpLogical32(Register dst, const Operand& opnd) {
3430  clfi(dst, opnd);
3431 }
3432 
3433 // Compare Logical Pointer Sized Register vs Immediate
3434 void TurboAssembler::CmpLogicalP(Register dst, const Operand& opnd) {
3435 #if V8_TARGET_ARCH_S390X
3436  DCHECK_EQ(static_cast<uint32_t>(opnd.immediate() >> 32), 0);
3437  clgfi(dst, opnd);
3438 #else
3439  CmpLogical32(dst, opnd);
3440 #endif
3441 }
3442 
3443 // Compare Logical 32-bit Register vs Memory
3444 void TurboAssembler::CmpLogical32(Register dst, const MemOperand& opnd) {
3445  // make sure offset is within 20 bit range
3446  DCHECK(is_int20(opnd.offset()));
3447  if (is_uint12(opnd.offset()))
3448  cl(dst, opnd);
3449  else
3450  cly(dst, opnd);
3451 }
3452 
3453 // Compare Logical Pointer Sized Register vs Memory
3454 void TurboAssembler::CmpLogicalP(Register dst, const MemOperand& opnd) {
3455  // make sure offset is within 20 bit range
3456  DCHECK(is_int20(opnd.offset()));
3457 #if V8_TARGET_ARCH_S390X
3458  clg(dst, opnd);
3459 #else
3460  CmpLogical32(dst, opnd);
3461 #endif
3462 }
3463 
3464 // Compare Logical Byte (Mem - Imm)
3465 void TurboAssembler::CmpLogicalByte(const MemOperand& mem, const Operand& imm) {
3466  DCHECK(is_uint8(imm.immediate()));
3467  if (is_uint12(mem.offset()))
3468  cli(mem, imm);
3469  else
3470  cliy(mem, imm);
3471 }
3472 
3473 void TurboAssembler::Branch(Condition c, const Operand& opnd) {
3474  intptr_t value = opnd.immediate();
3475  if (is_int16(value))
3476  brc(c, opnd);
3477  else
3478  brcl(c, opnd);
3479 }
3480 
3481 // Branch On Count. Decrement R1, and branch if R1 != 0.
3482 void TurboAssembler::BranchOnCount(Register r1, Label* l) {
3483  int32_t offset = branch_offset(l);
3484  if (is_int16(offset)) {
3485 #if V8_TARGET_ARCH_S390X
3486  brctg(r1, Operand(offset));
3487 #else
3488  brct(r1, Operand(offset));
3489 #endif
3490  } else {
3491  AddP(r1, Operand(-1));
3492  Branch(ne, Operand(offset));
3493  }
3494 }
3495 
3496 void TurboAssembler::LoadIntLiteral(Register dst, int value) {
3497  Load(dst, Operand(value));
3498 }
3499 
3500 void TurboAssembler::LoadSmiLiteral(Register dst, Smi smi) {
3501  intptr_t value = static_cast<intptr_t>(smi.ptr());
3502 #if V8_TARGET_ARCH_S390X
3503  DCHECK_EQ(value & 0xFFFFFFFF, 0);
3504  // The smi value is loaded in upper 32-bits. Lower 32-bit are zeros.
3505  llihf(dst, Operand(value >> 32));
3506 #else
3507  llilf(dst, Operand(value));
3508 #endif
3509 }
3510 
3511 void TurboAssembler::LoadDoubleLiteral(DoubleRegister result, uint64_t value,
3512  Register scratch) {
3513  uint32_t hi_32 = value >> 32;
3514  uint32_t lo_32 = static_cast<uint32_t>(value);
3515 
3516  // Load the 64-bit value into a GPR, then transfer it to FPR via LDGR
3517  if (value == 0) {
3518  lzdr(result);
3519  } else if (lo_32 == 0) {
3520  llihf(scratch, Operand(hi_32));
3521  ldgr(result, scratch);
3522  } else {
3523  iihf(scratch, Operand(hi_32));
3524  iilf(scratch, Operand(lo_32));
3525  ldgr(result, scratch);
3526  }
3527 }
3528 
3529 void TurboAssembler::LoadDoubleLiteral(DoubleRegister result, double value,
3530  Register scratch) {
3531  uint64_t int_val = bit_cast<uint64_t, double>(value);
3532  LoadDoubleLiteral(result, int_val, scratch);
3533 }
3534 
3535 void TurboAssembler::LoadFloat32Literal(DoubleRegister result, float value,
3536  Register scratch) {
3537  uint64_t int_val = static_cast<uint64_t>(bit_cast<uint32_t, float>(value))
3538  << 32;
3539  LoadDoubleLiteral(result, int_val, scratch);
3540 }
3541 
3542 void TurboAssembler::CmpSmiLiteral(Register src1, Smi smi, Register scratch) {
3543 #if V8_TARGET_ARCH_S390X
3544  if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
3545  cih(src1, Operand(static_cast<intptr_t>(smi.ptr()) >> 32));
3546  } else {
3547  LoadSmiLiteral(scratch, smi);
3548  cgr(src1, scratch);
3549  }
3550 #else
3551  // CFI takes 32-bit immediate.
3552  cfi(src1, Operand(smi));
3553 #endif
3554 }
3555 
3556 // Load a "pointer" sized value from the memory location
3557 void TurboAssembler::LoadP(Register dst, const MemOperand& mem,
3558  Register scratch) {
3559  int offset = mem.offset();
3560 
3561 #if V8_TARGET_ARCH_S390X
3562  MemOperand src = mem;
3563  if (!is_int20(offset)) {
3564  DCHECK(scratch != no_reg && scratch != r0 && mem.rx() == r0);
3565  DCHECK(scratch != mem.rb());
3566  LoadIntLiteral(scratch, offset);
3567  src = MemOperand(mem.rb(), scratch);
3568  }
3569  lg(dst, src);
3570 #else
3571  if (is_uint12(offset)) {
3572  l(dst, mem);
3573  } else if (is_int20(offset)) {
3574  ly(dst, mem);
3575  } else {
3576  DCHECK(scratch != no_reg && scratch != r0 && mem.rx() == r0);
3577  DCHECK(scratch != mem.rb());
3578  LoadIntLiteral(scratch, offset);
3579  l(dst, MemOperand(mem.rb(), scratch));
3580  }
3581 #endif
3582 }
3583 
3584 // Store a "pointer" sized value to the memory location
3585 void TurboAssembler::StoreP(Register src, const MemOperand& mem,
3586  Register scratch) {
3587  if (!is_int20(mem.offset())) {
3588  DCHECK(scratch != no_reg);
3589  DCHECK(scratch != r0);
3590  LoadIntLiteral(scratch, mem.offset());
3591 #if V8_TARGET_ARCH_S390X
3592  stg(src, MemOperand(mem.rb(), scratch));
3593 #else
3594  st(src, MemOperand(mem.rb(), scratch));
3595 #endif
3596  } else {
3597 #if V8_TARGET_ARCH_S390X
3598  stg(src, mem);
3599 #else
3600  // StoreW will try to generate ST if offset fits, otherwise
3601  // it'll generate STY.
3602  StoreW(src, mem);
3603 #endif
3604  }
3605 }
3606 
3607 // Store a "pointer" sized constant to the memory location
3608 void TurboAssembler::StoreP(const MemOperand& mem, const Operand& opnd,
3609  Register scratch) {
3610  // Relocations not supported
3611  DCHECK_EQ(opnd.rmode(), RelocInfo::NONE);
3612 
3613  // Try to use MVGHI/MVHI
3614  if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT) && is_uint12(mem.offset()) &&
3615  mem.getIndexRegister() == r0 && is_int16(opnd.immediate())) {
3616 #if V8_TARGET_ARCH_S390X
3617  mvghi(mem, opnd);
3618 #else
3619  mvhi(mem, opnd);
3620 #endif
3621  } else {
3622  LoadImmP(scratch, opnd);
3623  StoreP(scratch, mem);
3624  }
3625 }
3626 
3627 void TurboAssembler::LoadMultipleP(Register dst1, Register dst2,
3628  const MemOperand& mem) {
3629 #if V8_TARGET_ARCH_S390X
3630  DCHECK(is_int20(mem.offset()));
3631  lmg(dst1, dst2, mem);
3632 #else
3633  if (is_uint12(mem.offset())) {
3634  lm(dst1, dst2, mem);
3635  } else {
3636  DCHECK(is_int20(mem.offset()));
3637  lmy(dst1, dst2, mem);
3638  }
3639 #endif
3640 }
3641 
3642 void TurboAssembler::StoreMultipleP(Register src1, Register src2,
3643  const MemOperand& mem) {
3644 #if V8_TARGET_ARCH_S390X
3645  DCHECK(is_int20(mem.offset()));
3646  stmg(src1, src2, mem);
3647 #else
3648  if (is_uint12(mem.offset())) {
3649  stm(src1, src2, mem);
3650  } else {
3651  DCHECK(is_int20(mem.offset()));
3652  stmy(src1, src2, mem);
3653  }
3654 #endif
3655 }
3656 
3657 void TurboAssembler::LoadMultipleW(Register dst1, Register dst2,
3658  const MemOperand& mem) {
3659  if (is_uint12(mem.offset())) {
3660  lm(dst1, dst2, mem);
3661  } else {
3662  DCHECK(is_int20(mem.offset()));
3663  lmy(dst1, dst2, mem);
3664  }
3665 }
3666 
3667 void TurboAssembler::StoreMultipleW(Register src1, Register src2,
3668  const MemOperand& mem) {
3669  if (is_uint12(mem.offset())) {
3670  stm(src1, src2, mem);
3671  } else {
3672  DCHECK(is_int20(mem.offset()));
3673  stmy(src1, src2, mem);
3674  }
3675 }
3676 
3677 // Load 32-bits and sign extend if necessary.
3678 void TurboAssembler::LoadW(Register dst, Register src) {
3679 #if V8_TARGET_ARCH_S390X
3680  lgfr(dst, src);
3681 #else
3682  if (dst != src) lr(dst, src);
3683 #endif
3684 }
3685 
3686 // Load 32-bits and sign extend if necessary.
3687 void TurboAssembler::LoadW(Register dst, const MemOperand& mem,
3688  Register scratch) {
3689  int offset = mem.offset();
3690 
3691  if (!is_int20(offset)) {
3692  DCHECK(scratch != no_reg);
3693  LoadIntLiteral(scratch, offset);
3694 #if V8_TARGET_ARCH_S390X
3695  lgf(dst, MemOperand(mem.rb(), scratch));
3696 #else
3697  l(dst, MemOperand(mem.rb(), scratch));
3698 #endif
3699  } else {
3700 #if V8_TARGET_ARCH_S390X
3701  lgf(dst, mem);
3702 #else
3703  if (is_uint12(offset)) {
3704  l(dst, mem);
3705  } else {
3706  ly(dst, mem);
3707  }
3708 #endif
3709  }
3710 }
3711 
3712 // Load 32-bits and zero extend if necessary.
3713 void TurboAssembler::LoadlW(Register dst, Register src) {
3714 #if V8_TARGET_ARCH_S390X
3715  llgfr(dst, src);
3716 #else
3717  if (dst != src) lr(dst, src);
3718 #endif
3719 }
3720 
3721 // Variable length depending on whether offset fits into immediate field
3722 // MemOperand of RX or RXY format
3723 void TurboAssembler::LoadlW(Register dst, const MemOperand& mem,
3724  Register scratch) {
3725  Register base = mem.rb();
3726  int offset = mem.offset();
3727 
3728 #if V8_TARGET_ARCH_S390X
3729  if (is_int20(offset)) {
3730  llgf(dst, mem);
3731  } else if (scratch != no_reg) {
3732  // Materialize offset into scratch register.
3733  LoadIntLiteral(scratch, offset);
3734  llgf(dst, MemOperand(base, scratch));
3735  } else {
3736  DCHECK(false);
3737  }
3738 #else
3739  bool use_RXform = false;
3740  bool use_RXYform = false;
3741  if (is_uint12(offset)) {
3742  // RX-format supports unsigned 12-bits offset.
3743  use_RXform = true;
3744  } else if (is_int20(offset)) {
3745  // RXY-format supports signed 20-bits offset.
3746  use_RXYform = true;
3747  } else if (scratch != no_reg) {
3748  // Materialize offset into scratch register.
3749  LoadIntLiteral(scratch, offset);
3750  } else {
3751  DCHECK(false);
3752  }
3753 
3754  if (use_RXform) {
3755  l(dst, mem);
3756  } else if (use_RXYform) {
3757  ly(dst, mem);
3758  } else {
3759  ly(dst, MemOperand(base, scratch));
3760  }
3761 #endif
3762 }
3763 
3764 void TurboAssembler::LoadLogicalHalfWordP(Register dst, const MemOperand& mem) {
3765 #if V8_TARGET_ARCH_S390X
3766  llgh(dst, mem);
3767 #else
3768  llh(dst, mem);
3769 #endif
3770 }
3771 
3772 void TurboAssembler::LoadLogicalHalfWordP(Register dst, Register src) {
3773 #if V8_TARGET_ARCH_S390X
3774  llghr(dst, src);
3775 #else
3776  llhr(dst, src);
3777 #endif
3778 }
3779 
3780 void TurboAssembler::LoadB(Register dst, const MemOperand& mem) {
3781 #if V8_TARGET_ARCH_S390X
3782  lgb(dst, mem);
3783 #else
3784  lb(dst, mem);
3785 #endif
3786 }
3787 
3788 void TurboAssembler::LoadB(Register dst, Register src) {
3789 #if V8_TARGET_ARCH_S390X
3790  lgbr(dst, src);
3791 #else
3792  lbr(dst, src);
3793 #endif
3794 }
3795 
3796 void TurboAssembler::LoadlB(Register dst, const MemOperand& mem) {
3797 #if V8_TARGET_ARCH_S390X
3798  llgc(dst, mem);
3799 #else
3800  llc(dst, mem);
3801 #endif
3802 }
3803 
3804 void TurboAssembler::LoadlB(Register dst, Register src) {
3805 #if V8_TARGET_ARCH_S390X
3806  llgcr(dst, src);
3807 #else
3808  llcr(dst, src);
3809 #endif
3810 }
3811 
3812 void TurboAssembler::LoadLogicalReversedWordP(Register dst,
3813  const MemOperand& mem) {
3814  lrv(dst, mem);
3815  LoadlW(dst, dst);
3816 }
3817 
3818 void TurboAssembler::LoadLogicalReversedHalfWordP(Register dst,
3819  const MemOperand& mem) {
3820  lrvh(dst, mem);
3821  LoadLogicalHalfWordP(dst, dst);
3822 }
3823 
3824 
3825 // Load And Test (Reg <- Reg)
3826 void TurboAssembler::LoadAndTest32(Register dst, Register src) {
3827  ltr(dst, src);
3828 }
3829 
3830 // Load And Test
3831 // (Register dst(ptr) = Register src (32 | 32->64))
3832 // src is treated as a 32-bit signed integer, which is sign extended to
3833 // 64-bit if necessary.
3834 void TurboAssembler::LoadAndTestP_ExtendSrc(Register dst, Register src) {
3835 #if V8_TARGET_ARCH_S390X
3836  ltgfr(dst, src);
3837 #else
3838  ltr(dst, src);
3839 #endif
3840 }
3841 
3842 // Load And Test Pointer Sized (Reg <- Reg)
3843 void TurboAssembler::LoadAndTestP(Register dst, Register src) {
3844 #if V8_TARGET_ARCH_S390X
3845  ltgr(dst, src);
3846 #else
3847  ltr(dst, src);
3848 #endif
3849 }
3850 
3851 // Load And Test 32-bit (Reg <- Mem)
3852 void TurboAssembler::LoadAndTest32(Register dst, const MemOperand& mem) {
3853  lt_z(dst, mem);
3854 }
3855 
3856 // Load And Test Pointer Sized (Reg <- Mem)
3857 void TurboAssembler::LoadAndTestP(Register dst, const MemOperand& mem) {
3858 #if V8_TARGET_ARCH_S390X
3859  ltg(dst, mem);
3860 #else
3861  lt_z(dst, mem);
3862 #endif
3863 }
3864 
3865 // Load On Condition Pointer Sized (Reg <- Reg)
3866 void TurboAssembler::LoadOnConditionP(Condition cond, Register dst,
3867  Register src) {
3868 #if V8_TARGET_ARCH_S390X
3869  locgr(cond, dst, src);
3870 #else
3871  locr(cond, dst, src);
3872 #endif
3873 }
3874 
3875 // Load Double Precision (64-bit) Floating Point number from memory
3876 void TurboAssembler::LoadDouble(DoubleRegister dst, const MemOperand& mem) {
3877  // for 32bit and 64bit we all use 64bit floating point regs
3878  if (is_uint12(mem.offset())) {
3879  ld(dst, mem);
3880  } else {
3881  ldy(dst, mem);
3882  }
3883 }
3884 
3885 // Load Single Precision (32-bit) Floating Point number from memory
3886 void TurboAssembler::LoadFloat32(DoubleRegister dst, const MemOperand& mem) {
3887  if (is_uint12(mem.offset())) {
3888  le_z(dst, mem);
3889  } else {
3890  DCHECK(is_int20(mem.offset()));
3891  ley(dst, mem);
3892  }
3893 }
3894 
3895 // Load Single Precision (32-bit) Floating Point number from memory,
3896 // and convert to Double Precision (64-bit)
3897 void TurboAssembler::LoadFloat32ConvertToDouble(DoubleRegister dst,
3898  const MemOperand& mem) {
3899  LoadFloat32(dst, mem);
3900  ldebr(dst, dst);
3901 }
3902 
3903 // Store Double Precision (64-bit) Floating Point number to memory
3904 void TurboAssembler::StoreDouble(DoubleRegister dst, const MemOperand& mem) {
3905  if (is_uint12(mem.offset())) {
3906  std(dst, mem);
3907  } else {
3908  stdy(dst, mem);
3909  }
3910 }
3911 
3912 // Store Single Precision (32-bit) Floating Point number to memory
3913 void TurboAssembler::StoreFloat32(DoubleRegister src, const MemOperand& mem) {
3914  if (is_uint12(mem.offset())) {
3915  ste(src, mem);
3916  } else {
3917  stey(src, mem);
3918  }
3919 }
3920 
3921 // Convert Double precision (64-bit) to Single Precision (32-bit)
3922 // and store resulting Float32 to memory
3923 void TurboAssembler::StoreDoubleAsFloat32(DoubleRegister src,
3924  const MemOperand& mem,
3925  DoubleRegister scratch) {
3926  ledbr(scratch, src);
3927  StoreFloat32(scratch, mem);
3928 }
3929 
3930 void TurboAssembler::AddFloat32(DoubleRegister dst, const MemOperand& opnd,
3931  DoubleRegister scratch) {
3932  if (is_uint12(opnd.offset())) {
3933  aeb(dst, opnd);
3934  } else {
3935  ley(scratch, opnd);
3936  aebr(dst, scratch);
3937  }
3938 }
3939 
3940 void TurboAssembler::AddFloat64(DoubleRegister dst, const MemOperand& opnd,
3941  DoubleRegister scratch) {
3942  if (is_uint12(opnd.offset())) {
3943  adb(dst, opnd);
3944  } else {
3945  ldy(scratch, opnd);
3946  adbr(dst, scratch);
3947  }
3948 }
3949 
3950 void TurboAssembler::SubFloat32(DoubleRegister dst, const MemOperand& opnd,
3951  DoubleRegister scratch) {
3952  if (is_uint12(opnd.offset())) {
3953  seb(dst, opnd);
3954  } else {
3955  ley(scratch, opnd);
3956  sebr(dst, scratch);
3957  }
3958 }
3959 
3960 void TurboAssembler::SubFloat64(DoubleRegister dst, const MemOperand& opnd,
3961  DoubleRegister scratch) {
3962  if (is_uint12(opnd.offset())) {
3963  sdb(dst, opnd);
3964  } else {
3965  ldy(scratch, opnd);
3966  sdbr(dst, scratch);
3967  }
3968 }
3969 
3970 void TurboAssembler::MulFloat32(DoubleRegister dst, const MemOperand& opnd,
3971  DoubleRegister scratch) {
3972  if (is_uint12(opnd.offset())) {
3973  meeb(dst, opnd);
3974  } else {
3975  ley(scratch, opnd);
3976  meebr(dst, scratch);
3977  }
3978 }
3979 
3980 void TurboAssembler::MulFloat64(DoubleRegister dst, const MemOperand& opnd,
3981  DoubleRegister scratch) {
3982  if (is_uint12(opnd.offset())) {
3983  mdb(dst, opnd);
3984  } else {
3985  ldy(scratch, opnd);
3986  mdbr(dst, scratch);
3987  }
3988 }
3989 
3990 void TurboAssembler::DivFloat32(DoubleRegister dst, const MemOperand& opnd,
3991  DoubleRegister scratch) {
3992  if (is_uint12(opnd.offset())) {
3993  deb(dst, opnd);
3994  } else {
3995  ley(scratch, opnd);
3996  debr(dst, scratch);
3997  }
3998 }
3999 
4000 void TurboAssembler::DivFloat64(DoubleRegister dst, const MemOperand& opnd,
4001  DoubleRegister scratch) {
4002  if (is_uint12(opnd.offset())) {
4003  ddb(dst, opnd);
4004  } else {
4005  ldy(scratch, opnd);
4006  ddbr(dst, scratch);
4007  }
4008 }
4009 
4010 void TurboAssembler::LoadFloat32ToDouble(DoubleRegister dst,
4011  const MemOperand& opnd,
4012  DoubleRegister scratch) {
4013  if (is_uint12(opnd.offset())) {
4014  ldeb(dst, opnd);
4015  } else {
4016  ley(scratch, opnd);
4017  ldebr(dst, scratch);
4018  }
4019 }
4020 
4021 // Variable length depending on whether offset fits into immediate field
4022 // MemOperand of RX or RXY format
4023 void TurboAssembler::StoreW(Register src, const MemOperand& mem,
4024  Register scratch) {
4025  Register base = mem.rb();
4026  int offset = mem.offset();
4027 
4028  bool use_RXform = false;
4029  bool use_RXYform = false;
4030 
4031  if (is_uint12(offset)) {
4032  // RX-format supports unsigned 12-bits offset.
4033  use_RXform = true;
4034  } else if (is_int20(offset)) {
4035  // RXY-format supports signed 20-bits offset.
4036  use_RXYform = true;
4037  } else if (scratch != no_reg) {
4038  // Materialize offset into scratch register.
4039  LoadIntLiteral(scratch, offset);
4040  } else {
4041  // scratch is no_reg
4042  DCHECK(false);
4043  }
4044 
4045  if (use_RXform) {
4046  st(src, mem);
4047  } else if (use_RXYform) {
4048  sty(src, mem);
4049  } else {
4050  StoreW(src, MemOperand(base, scratch));
4051  }
4052 }
4053 
4054 void TurboAssembler::LoadHalfWordP(Register dst, Register src) {
4055 #if V8_TARGET_ARCH_S390X
4056  lghr(dst, src);
4057 #else
4058  lhr(dst, src);
4059 #endif
4060 }
4061 
4062 // Loads 16-bits half-word value from memory and sign extends to pointer
4063 // sized register
4064 void TurboAssembler::LoadHalfWordP(Register dst, const MemOperand& mem,
4065  Register scratch) {
4066  Register base = mem.rb();
4067  int offset = mem.offset();
4068 
4069  if (!is_int20(offset)) {
4070  DCHECK(scratch != no_reg);
4071  LoadIntLiteral(scratch, offset);
4072 #if V8_TARGET_ARCH_S390X
4073  lgh(dst, MemOperand(base, scratch));
4074 #else
4075  lh(dst, MemOperand(base, scratch));
4076 #endif
4077  } else {
4078 #if V8_TARGET_ARCH_S390X
4079  lgh(dst, mem);
4080 #else
4081  if (is_uint12(offset)) {
4082  lh(dst, mem);
4083  } else {
4084  lhy(dst, mem);
4085  }
4086 #endif
4087  }
4088 }
4089 
4090 // Variable length depending on whether offset fits into immediate field
4091 // MemOperand current only supports d-form
4092 void TurboAssembler::StoreHalfWord(Register src, const MemOperand& mem,
4093  Register scratch) {
4094  Register base = mem.rb();
4095  int offset = mem.offset();
4096 
4097  if (is_uint12(offset)) {
4098  sth(src, mem);
4099  } else if (is_int20(offset)) {
4100  sthy(src, mem);
4101  } else {
4102  DCHECK(scratch != no_reg);
4103  LoadIntLiteral(scratch, offset);
4104  sth(src, MemOperand(base, scratch));
4105  }
4106 }
4107 
4108 // Variable length depending on whether offset fits into immediate field
4109 // MemOperand current only supports d-form
4110 void TurboAssembler::StoreByte(Register src, const MemOperand& mem,
4111  Register scratch) {
4112  Register base = mem.rb();
4113  int offset = mem.offset();
4114 
4115  if (is_uint12(offset)) {
4116  stc(src, mem);
4117  } else if (is_int20(offset)) {
4118  stcy(src, mem);
4119  } else {
4120  DCHECK(scratch != no_reg);
4121  LoadIntLiteral(scratch, offset);
4122  stc(src, MemOperand(base, scratch));
4123  }
4124 }
4125 
4126 // Shift left logical for 32-bit integer types.
4127 void TurboAssembler::ShiftLeft(Register dst, Register src, const Operand& val) {
4128  if (dst == src) {
4129  sll(dst, val);
4130  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4131  sllk(dst, src, val);
4132  } else {
4133  lr(dst, src);
4134  sll(dst, val);
4135  }
4136 }
4137 
4138 // Shift left logical for 32-bit integer types.
4139 void TurboAssembler::ShiftLeft(Register dst, Register src, Register val) {
4140  if (dst == src) {
4141  sll(dst, val);
4142  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4143  sllk(dst, src, val);
4144  } else {
4145  DCHECK(dst != val); // The lr/sll path clobbers val.
4146  lr(dst, src);
4147  sll(dst, val);
4148  }
4149 }
4150 
4151 // Shift right logical for 32-bit integer types.
4152 void TurboAssembler::ShiftRight(Register dst, Register src,
4153  const Operand& val) {
4154  if (dst == src) {
4155  srl(dst, val);
4156  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4157  srlk(dst, src, val);
4158  } else {
4159  lr(dst, src);
4160  srl(dst, val);
4161  }
4162 }
4163 
4164 // Shift right logical for 32-bit integer types.
4165 void TurboAssembler::ShiftRight(Register dst, Register src, Register val) {
4166  if (dst == src) {
4167  srl(dst, val);
4168  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4169  srlk(dst, src, val);
4170  } else {
4171  DCHECK(dst != val); // The lr/srl path clobbers val.
4172  lr(dst, src);
4173  srl(dst, val);
4174  }
4175 }
4176 
4177 // Shift left arithmetic for 32-bit integer types.
4178 void TurboAssembler::ShiftLeftArith(Register dst, Register src,
4179  const Operand& val) {
4180  if (dst == src) {
4181  sla(dst, val);
4182  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4183  slak(dst, src, val);
4184  } else {
4185  lr(dst, src);
4186  sla(dst, val);
4187  }
4188 }
4189 
4190 // Shift left arithmetic for 32-bit integer types.
4191 void TurboAssembler::ShiftLeftArith(Register dst, Register src, Register val) {
4192  if (dst == src) {
4193  sla(dst, val);
4194  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4195  slak(dst, src, val);
4196  } else {
4197  DCHECK(dst != val); // The lr/sla path clobbers val.
4198  lr(dst, src);
4199  sla(dst, val);
4200  }
4201 }
4202 
4203 // Shift right arithmetic for 32-bit integer types.
4204 void TurboAssembler::ShiftRightArith(Register dst, Register src,
4205  const Operand& val) {
4206  if (dst == src) {
4207  sra(dst, val);
4208  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4209  srak(dst, src, val);
4210  } else {
4211  lr(dst, src);
4212  sra(dst, val);
4213  }
4214 }
4215 
4216 // Shift right arithmetic for 32-bit integer types.
4217 void TurboAssembler::ShiftRightArith(Register dst, Register src, Register val) {
4218  if (dst == src) {
4219  sra(dst, val);
4220  } else if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
4221  srak(dst, src, val);
4222  } else {
4223  DCHECK(dst != val); // The lr/sra path clobbers val.
4224  lr(dst, src);
4225  sra(dst, val);
4226  }
4227 }
4228 
4229 // Clear right most # of bits
4230 void TurboAssembler::ClearRightImm(Register dst, Register src,
4231  const Operand& val) {
4232  int numBitsToClear = val.immediate() % (kPointerSize * 8);
4233 
4234  // Try to use RISBG if possible
4235  if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
4236  int endBit = 63 - numBitsToClear;
4237  RotateInsertSelectBits(dst, src, Operand::Zero(), Operand(endBit),
4238  Operand::Zero(), true);
4239  return;
4240  }
4241 
4242  uint64_t hexMask = ~((1L << numBitsToClear) - 1);
4243 
4244  // S390 AND instr clobbers source. Make a copy if necessary
4245  if (dst != src) LoadRR(dst, src);
4246 
4247  if (numBitsToClear <= 16) {
4248  nill(dst, Operand(static_cast<uint16_t>(hexMask)));
4249  } else if (numBitsToClear <= 32) {
4250  nilf(dst, Operand(static_cast<uint32_t>(hexMask)));
4251  } else if (numBitsToClear <= 64) {
4252  nilf(dst, Operand(static_cast<intptr_t>(0)));
4253  nihf(dst, Operand(hexMask >> 32));
4254  }
4255 }
4256 
4257 void TurboAssembler::Popcnt32(Register dst, Register src) {
4258  DCHECK(src != r0);
4259  DCHECK(dst != r0);
4260 
4261  popcnt(dst, src);
4262  ShiftRight(r0, dst, Operand(16));
4263  ar(dst, r0);
4264  ShiftRight(r0, dst, Operand(8));
4265  ar(dst, r0);
4266  llgcr(dst, dst);
4267 }
4268 
4269 #ifdef V8_TARGET_ARCH_S390X
4270 void TurboAssembler::Popcnt64(Register dst, Register src) {
4271  DCHECK(src != r0);
4272  DCHECK(dst != r0);
4273 
4274  popcnt(dst, src);
4275  ShiftRightP(r0, dst, Operand(32));
4276  AddP(dst, r0);
4277  ShiftRightP(r0, dst, Operand(16));
4278  AddP(dst, r0);
4279  ShiftRightP(r0, dst, Operand(8));
4280  AddP(dst, r0);
4281  LoadlB(dst, dst);
4282 }
4283 #endif
4284 
4285 void TurboAssembler::SwapP(Register src, Register dst, Register scratch) {
4286  if (src == dst) return;
4287  DCHECK(!AreAliased(src, dst, scratch));
4288  LoadRR(scratch, src);
4289  LoadRR(src, dst);
4290  LoadRR(dst, scratch);
4291 }
4292 
4293 void TurboAssembler::SwapP(Register src, MemOperand dst, Register scratch) {
4294  if (dst.rx() != r0) DCHECK(!AreAliased(src, dst.rx(), scratch));
4295  if (dst.rb() != r0) DCHECK(!AreAliased(src, dst.rb(), scratch));
4296  DCHECK(!AreAliased(src, scratch));
4297  LoadRR(scratch, src);
4298  LoadP(src, dst);
4299  StoreP(scratch, dst);
4300 }
4301 
4302 void TurboAssembler::SwapP(MemOperand src, MemOperand dst, Register scratch_0,
4303  Register scratch_1) {
4304  if (src.rx() != r0) DCHECK(!AreAliased(src.rx(), scratch_0, scratch_1));
4305  if (src.rb() != r0) DCHECK(!AreAliased(src.rb(), scratch_0, scratch_1));
4306  if (dst.rx() != r0) DCHECK(!AreAliased(dst.rx(), scratch_0, scratch_1));
4307  if (dst.rb() != r0) DCHECK(!AreAliased(dst.rb(), scratch_0, scratch_1));
4308  DCHECK(!AreAliased(scratch_0, scratch_1));
4309  LoadP(scratch_0, src);
4310  LoadP(scratch_1, dst);
4311  StoreP(scratch_0, dst);
4312  StoreP(scratch_1, src);
4313 }
4314 
4315 void TurboAssembler::SwapFloat32(DoubleRegister src, DoubleRegister dst,
4316  DoubleRegister scratch) {
4317  if (src == dst) return;
4318  DCHECK(!AreAliased(src, dst, scratch));
4319  ldr(scratch, src);
4320  ldr(src, dst);
4321  ldr(dst, scratch);
4322 }
4323 
4324 void TurboAssembler::SwapFloat32(DoubleRegister src, MemOperand dst,
4325  DoubleRegister scratch) {
4326  DCHECK(!AreAliased(src, scratch));
4327  ldr(scratch, src);
4328  LoadFloat32(src, dst);
4329  StoreFloat32(scratch, dst);
4330 }
4331 
4332 void TurboAssembler::SwapFloat32(MemOperand src, MemOperand dst,
4333  DoubleRegister scratch_0,
4334  DoubleRegister scratch_1) {
4335  DCHECK(!AreAliased(scratch_0, scratch_1));
4336  LoadFloat32(scratch_0, src);
4337  LoadFloat32(scratch_1, dst);
4338  StoreFloat32(scratch_0, dst);
4339  StoreFloat32(scratch_1, src);
4340 }
4341 
4342 void TurboAssembler::SwapDouble(DoubleRegister src, DoubleRegister dst,
4343  DoubleRegister scratch) {
4344  if (src == dst) return;
4345  DCHECK(!AreAliased(src, dst, scratch));
4346  ldr(scratch, src);
4347  ldr(src, dst);
4348  ldr(dst, scratch);
4349 }
4350 
4351 void TurboAssembler::SwapDouble(DoubleRegister src, MemOperand dst,
4352  DoubleRegister scratch) {
4353  DCHECK(!AreAliased(src, scratch));
4354  ldr(scratch, src);
4355  LoadDouble(src, dst);
4356  StoreDouble(scratch, dst);
4357 }
4358 
4359 void TurboAssembler::SwapDouble(MemOperand src, MemOperand dst,
4360  DoubleRegister scratch_0,
4361  DoubleRegister scratch_1) {
4362  DCHECK(!AreAliased(scratch_0, scratch_1));
4363  LoadDouble(scratch_0, src);
4364  LoadDouble(scratch_1, dst);
4365  StoreDouble(scratch_0, dst);
4366  StoreDouble(scratch_1, src);
4367 }
4368 
4369 void TurboAssembler::ResetSpeculationPoisonRegister() {
4370  mov(kSpeculationPoisonRegister, Operand(-1));
4371 }
4372 
4373 void TurboAssembler::ComputeCodeStartAddress(Register dst) {
4374  larl(dst, Operand(-pc_offset() / 2));
4375 }
4376 
4377 void TurboAssembler::JumpIfEqual(Register x, int32_t y, Label* dest) {
4378  Cmp32(x, Operand(y));
4379  beq(dest);
4380 }
4381 
4382 void TurboAssembler::JumpIfLessThan(Register x, int32_t y, Label* dest) {
4383  Cmp32(x, Operand(y));
4384  blt(dest);
4385 }
4386 
4387 } // namespace internal
4388 } // namespace v8
4389 
4390 #endif // V8_TARGET_ARCH_S390
STL namespace.
Definition: libplatform.h:13