Home | History | Annotate | Download | only in ppc
      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_PPC
      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/debug/debug.h"
     17 #include "src/external-reference-table.h"
     18 #include "src/frames-inl.h"
     19 #include "src/instruction-stream.h"
     20 #include "src/register-configuration.h"
     21 #include "src/runtime/runtime.h"
     22 #include "src/snapshot/snapshot.h"
     23 #include "src/wasm/wasm-code-manager.h"
     24 
     25 #include "src/ppc/macro-assembler-ppc.h"
     26 
     27 namespace v8 {
     28 namespace internal {
     29 
     30 MacroAssembler::MacroAssembler(Isolate* isolate,
     31                                const AssemblerOptions& options, void* buffer,
     32                                int size, CodeObjectRequired create_code_object)
     33     : TurboAssembler(isolate, options, buffer, size, create_code_object) {
     34   if (create_code_object == CodeObjectRequired::kYes) {
     35     // Unlike TurboAssembler, which can be used off the main thread and may not
     36     // allocate, macro assembler creates its own copy of the self-reference
     37     // marker in order to disambiguate between self-references during nested
     38     // code generation (e.g.: codegen of the current object triggers stub
     39     // compilation through CodeStub::GetCode()).
     40     code_object_ = Handle<HeapObject>::New(
     41         *isolate->factory()->NewSelfReferenceMarker(), isolate);
     42   }
     43 }
     44 
     45 int TurboAssembler::RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode,
     46                                                     Register exclusion1,
     47                                                     Register exclusion2,
     48                                                     Register exclusion3) const {
     49   int bytes = 0;
     50   RegList exclusions = 0;
     51   if (exclusion1 != no_reg) {
     52     exclusions |= exclusion1.bit();
     53     if (exclusion2 != no_reg) {
     54       exclusions |= exclusion2.bit();
     55       if (exclusion3 != no_reg) {
     56         exclusions |= exclusion3.bit();
     57       }
     58     }
     59   }
     60 
     61   RegList list = kJSCallerSaved & ~exclusions;
     62   bytes += NumRegs(list) * kPointerSize;
     63 
     64   if (fp_mode == kSaveFPRegs) {
     65     bytes += kNumCallerSavedDoubles * kDoubleSize;
     66   }
     67 
     68   return bytes;
     69 }
     70 
     71 int TurboAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1,
     72                                     Register exclusion2, Register exclusion3) {
     73   int bytes = 0;
     74   RegList exclusions = 0;
     75   if (exclusion1 != no_reg) {
     76     exclusions |= exclusion1.bit();
     77     if (exclusion2 != no_reg) {
     78       exclusions |= exclusion2.bit();
     79       if (exclusion3 != no_reg) {
     80         exclusions |= exclusion3.bit();
     81       }
     82     }
     83   }
     84 
     85   RegList list = kJSCallerSaved & ~exclusions;
     86   MultiPush(list);
     87   bytes += NumRegs(list) * kPointerSize;
     88 
     89   if (fp_mode == kSaveFPRegs) {
     90     MultiPushDoubles(kCallerSavedDoubles);
     91     bytes += kNumCallerSavedDoubles * kDoubleSize;
     92   }
     93 
     94   return bytes;
     95 }
     96 
     97 int TurboAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1,
     98                                    Register exclusion2, Register exclusion3) {
     99   int bytes = 0;
    100   if (fp_mode == kSaveFPRegs) {
    101     MultiPopDoubles(kCallerSavedDoubles);
    102     bytes += kNumCallerSavedDoubles * kDoubleSize;
    103   }
    104 
    105   RegList exclusions = 0;
    106   if (exclusion1 != no_reg) {
    107     exclusions |= exclusion1.bit();
    108     if (exclusion2 != no_reg) {
    109       exclusions |= exclusion2.bit();
    110       if (exclusion3 != no_reg) {
    111         exclusions |= exclusion3.bit();
    112       }
    113     }
    114   }
    115 
    116   RegList list = kJSCallerSaved & ~exclusions;
    117   MultiPop(list);
    118   bytes += NumRegs(list) * kPointerSize;
    119 
    120   return bytes;
    121 }
    122 
    123 void TurboAssembler::Jump(Register target) {
    124   mtctr(target);
    125   bctr();
    126 }
    127 
    128 void TurboAssembler::LoadFromConstantsTable(Register destination,
    129                                             int constant_index) {
    130   DCHECK(isolate()->heap()->RootCanBeTreatedAsConstant(
    131       Heap::kBuiltinsConstantsTableRootIndex));
    132 
    133   const uint32_t offset =
    134       FixedArray::kHeaderSize + constant_index * kPointerSize - kHeapObjectTag;
    135 
    136   CHECK(is_uint19(offset));
    137   DCHECK_NE(destination, r0);
    138   LoadRoot(destination, Heap::kBuiltinsConstantsTableRootIndex);
    139   LoadP(destination, MemOperand(destination, offset), r0);
    140 }
    141 
    142 void TurboAssembler::LoadRootRelative(Register destination, int32_t offset) {
    143   LoadP(destination, MemOperand(kRootRegister, offset), r0);
    144 }
    145 
    146 void TurboAssembler::LoadRootRegisterOffset(Register destination,
    147                                             intptr_t offset) {
    148   if (offset == 0) {
    149     mr(destination, kRootRegister);
    150   } else {
    151     addi(destination, kRootRegister, Operand(offset));
    152   }
    153 }
    154 
    155 void MacroAssembler::JumpToJSEntry(Register target) {
    156   Move(ip, target);
    157   Jump(ip);
    158 }
    159 
    160 void TurboAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
    161                           Condition cond, CRegister cr) {
    162   Label skip;
    163 
    164   if (cond != al) b(NegateCondition(cond), &skip, cr);
    165 
    166   DCHECK(rmode == RelocInfo::CODE_TARGET || rmode == RelocInfo::RUNTIME_ENTRY);
    167 
    168   mov(ip, Operand(target, rmode));
    169   mtctr(ip);
    170   bctr();
    171 
    172   bind(&skip);
    173 }
    174 
    175 void TurboAssembler::Jump(Address target, RelocInfo::Mode rmode, Condition cond,
    176                           CRegister cr) {
    177   DCHECK(!RelocInfo::IsCodeTarget(rmode));
    178   Jump(static_cast<intptr_t>(target), rmode, cond, cr);
    179 }
    180 
    181 void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
    182                           Condition cond, CRegister cr) {
    183   DCHECK(RelocInfo::IsCodeTarget(rmode));
    184   // 'code' is always generated ppc code, never THUMB code
    185   if (FLAG_embedded_builtins) {
    186     if (root_array_available_ && options().isolate_independent_code) {
    187       Register scratch = ip;
    188       IndirectLoadConstant(scratch, code);
    189       addi(scratch, scratch, Operand(Code::kHeaderSize - kHeapObjectTag));
    190       Label skip;
    191       if (cond != al) b(NegateCondition(cond), &skip, cr);
    192       Jump(scratch);
    193       bind(&skip);
    194       return;
    195     } else if (options().inline_offheap_trampolines) {
    196       int builtin_index = Builtins::kNoBuiltinId;
    197       if (isolate()->builtins()->IsBuiltinHandle(code, &builtin_index) &&
    198           Builtins::IsIsolateIndependent(builtin_index)) {
    199         // Inline the trampoline.
    200         RecordCommentForOffHeapTrampoline(builtin_index);
    201         EmbeddedData d = EmbeddedData::FromBlob();
    202         Address entry = d.InstructionStartOfBuiltin(builtin_index);
    203         // Use ip directly instead of using UseScratchRegisterScope, as we do
    204         // not preserve scratch registers across calls.
    205         mov(ip, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
    206         Label skip;
    207         if (cond != al) b(NegateCondition(cond), &skip, cr);
    208         Jump(ip);
    209         bind(&skip);
    210         return;
    211       }
    212     }
    213   }
    214   Jump(static_cast<intptr_t>(code.address()), rmode, cond, cr);
    215 }
    216 
    217 void TurboAssembler::Call(Register target) {
    218   BlockTrampolinePoolScope block_trampoline_pool(this);
    219   // branch via link register and set LK bit for return point
    220   mtctr(target);
    221   bctrl();
    222 }
    223 
    224 void MacroAssembler::CallJSEntry(Register target) {
    225   CHECK(target == r5);
    226   Call(target);
    227 }
    228 
    229 int MacroAssembler::CallSizeNotPredictableCodeSize(Address target,
    230                                                    RelocInfo::Mode rmode,
    231                                                    Condition cond) {
    232   return (2 + kMovInstructionsNoConstantPool) * kInstrSize;
    233 }
    234 
    235 void TurboAssembler::Call(Address target, RelocInfo::Mode rmode,
    236                           Condition cond) {
    237   BlockTrampolinePoolScope block_trampoline_pool(this);
    238   DCHECK(cond == al);
    239 
    240   // This can likely be optimized to make use of bc() with 24bit relative
    241   //
    242   // RecordRelocInfo(x.rmode_, x.immediate);
    243   // bc( BA, .... offset, LKset);
    244   //
    245 
    246   mov(ip, Operand(target, rmode));
    247   mtctr(ip);
    248   bctrl();
    249 }
    250 
    251 void TurboAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
    252                           Condition cond) {
    253   BlockTrampolinePoolScope block_trampoline_pool(this);
    254   DCHECK(RelocInfo::IsCodeTarget(rmode));
    255 
    256   if (FLAG_embedded_builtins) {
    257     if (root_array_available_ && options().isolate_independent_code) {
    258       // Use ip directly instead of using UseScratchRegisterScope, as we do not
    259       // preserve scratch registers across calls.
    260       IndirectLoadConstant(ip, code);
    261       addi(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
    262       Label skip;
    263       if (cond != al) b(NegateCondition(cond), &skip);
    264       Call(ip);
    265       bind(&skip);
    266       return;
    267     } else if (options().inline_offheap_trampolines) {
    268       int builtin_index = Builtins::kNoBuiltinId;
    269       if (isolate()->builtins()->IsBuiltinHandle(code, &builtin_index) &&
    270           Builtins::IsIsolateIndependent(builtin_index)) {
    271         // Inline the trampoline.
    272         RecordCommentForOffHeapTrampoline(builtin_index);
    273         DCHECK(Builtins::IsBuiltinId(builtin_index));
    274         EmbeddedData d = EmbeddedData::FromBlob();
    275         Address entry = d.InstructionStartOfBuiltin(builtin_index);
    276         // Use ip directly instead of using UseScratchRegisterScope, as we do
    277         // not preserve scratch registers across calls.
    278         mov(ip, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
    279         Label skip;
    280         if (cond != al) b(NegateCondition(cond), &skip);
    281         Call(ip);
    282         bind(&skip);
    283         return;
    284       }
    285     }
    286   }
    287   Call(code.address(), rmode, cond);
    288 }
    289 
    290 void TurboAssembler::Drop(int count) {
    291   if (count > 0) {
    292     Add(sp, sp, count * kPointerSize, r0);
    293   }
    294 }
    295 
    296 void TurboAssembler::Drop(Register count, Register scratch) {
    297   ShiftLeftImm(scratch, count, Operand(kPointerSizeLog2));
    298   add(sp, sp, scratch);
    299 }
    300 
    301 void TurboAssembler::Call(Label* target) { b(target, SetLK); }
    302 
    303 void TurboAssembler::Push(Handle<HeapObject> handle) {
    304   mov(r0, Operand(handle));
    305   push(r0);
    306 }
    307 
    308 void TurboAssembler::Push(Smi* smi) {
    309   mov(r0, Operand(smi));
    310   push(r0);
    311 }
    312 
    313 void TurboAssembler::Move(Register dst, Handle<HeapObject> value) {
    314   if (FLAG_embedded_builtins) {
    315     if (root_array_available_ && options().isolate_independent_code) {
    316       IndirectLoadConstant(dst, value);
    317       return;
    318     }
    319   }
    320   mov(dst, Operand(value));
    321 }
    322 
    323 void TurboAssembler::Move(Register dst, ExternalReference reference) {
    324   if (FLAG_embedded_builtins) {
    325     if (root_array_available_ && options().isolate_independent_code) {
    326       IndirectLoadExternalReference(dst, reference);
    327       return;
    328     }
    329   }
    330   mov(dst, Operand(reference));
    331 }
    332 
    333 void TurboAssembler::Move(Register dst, Register src, Condition cond) {
    334   DCHECK(cond == al);
    335   if (dst != src) {
    336     mr(dst, src);
    337   }
    338 }
    339 
    340 void TurboAssembler::Move(DoubleRegister dst, DoubleRegister src) {
    341   if (dst != src) {
    342     fmr(dst, src);
    343   }
    344 }
    345 
    346 void TurboAssembler::MultiPush(RegList regs, Register location) {
    347   int16_t num_to_push = base::bits::CountPopulation(regs);
    348   int16_t stack_offset = num_to_push * kPointerSize;
    349 
    350   subi(location, location, Operand(stack_offset));
    351   for (int16_t i = Register::kNumRegisters - 1; i >= 0; i--) {
    352     if ((regs & (1 << i)) != 0) {
    353       stack_offset -= kPointerSize;
    354       StoreP(ToRegister(i), MemOperand(location, stack_offset));
    355     }
    356   }
    357 }
    358 
    359 void TurboAssembler::MultiPop(RegList regs, Register location) {
    360   int16_t stack_offset = 0;
    361 
    362   for (int16_t i = 0; i < Register::kNumRegisters; i++) {
    363     if ((regs & (1 << i)) != 0) {
    364       LoadP(ToRegister(i), MemOperand(location, stack_offset));
    365       stack_offset += kPointerSize;
    366     }
    367   }
    368   addi(location, location, Operand(stack_offset));
    369 }
    370 
    371 void TurboAssembler::MultiPushDoubles(RegList dregs, Register location) {
    372   int16_t num_to_push = base::bits::CountPopulation(dregs);
    373   int16_t stack_offset = num_to_push * kDoubleSize;
    374 
    375   subi(location, location, Operand(stack_offset));
    376   for (int16_t i = DoubleRegister::kNumRegisters - 1; i >= 0; i--) {
    377     if ((dregs & (1 << i)) != 0) {
    378       DoubleRegister dreg = DoubleRegister::from_code(i);
    379       stack_offset -= kDoubleSize;
    380       stfd(dreg, MemOperand(location, stack_offset));
    381     }
    382   }
    383 }
    384 
    385 void TurboAssembler::MultiPopDoubles(RegList dregs, Register location) {
    386   int16_t stack_offset = 0;
    387 
    388   for (int16_t i = 0; i < DoubleRegister::kNumRegisters; i++) {
    389     if ((dregs & (1 << i)) != 0) {
    390       DoubleRegister dreg = DoubleRegister::from_code(i);
    391       lfd(dreg, MemOperand(location, stack_offset));
    392       stack_offset += kDoubleSize;
    393     }
    394   }
    395   addi(location, location, Operand(stack_offset));
    396 }
    397 
    398 void TurboAssembler::LoadRoot(Register destination, Heap::RootListIndex index,
    399                               Condition cond) {
    400   DCHECK(cond == al);
    401   LoadP(destination, MemOperand(kRootRegister, RootRegisterOffset(index)), r0);
    402 }
    403 
    404 void MacroAssembler::RecordWriteField(Register object, int offset,
    405                                       Register value, Register dst,
    406                                       LinkRegisterStatus lr_status,
    407                                       SaveFPRegsMode save_fp,
    408                                       RememberedSetAction remembered_set_action,
    409                                       SmiCheck smi_check) {
    410   // First, check if a write barrier is even needed. The tests below
    411   // catch stores of Smis.
    412   Label done;
    413 
    414   // Skip barrier if writing a smi.
    415   if (smi_check == INLINE_SMI_CHECK) {
    416     JumpIfSmi(value, &done);
    417   }
    418 
    419   // Although the object register is tagged, the offset is relative to the start
    420   // of the object, so so offset must be a multiple of kPointerSize.
    421   DCHECK(IsAligned(offset, kPointerSize));
    422 
    423   Add(dst, object, offset - kHeapObjectTag, r0);
    424   if (emit_debug_code()) {
    425     Label ok;
    426     andi(r0, dst, Operand(kPointerSize - 1));
    427     beq(&ok, cr0);
    428     stop("Unaligned cell in write barrier");
    429     bind(&ok);
    430   }
    431 
    432   RecordWrite(object, dst, value, lr_status, save_fp, remembered_set_action,
    433               OMIT_SMI_CHECK);
    434 
    435   bind(&done);
    436 
    437   // Clobber clobbered input registers when running with the debug-code flag
    438   // turned on to provoke errors.
    439   if (emit_debug_code()) {
    440     mov(value, Operand(bit_cast<intptr_t>(kZapValue + 4)));
    441     mov(dst, Operand(bit_cast<intptr_t>(kZapValue + 8)));
    442   }
    443 }
    444 
    445 void TurboAssembler::SaveRegisters(RegList registers) {
    446   DCHECK_GT(NumRegs(registers), 0);
    447   RegList regs = 0;
    448   for (int i = 0; i < Register::kNumRegisters; ++i) {
    449     if ((registers >> i) & 1u) {
    450       regs |= Register::from_code(i).bit();
    451     }
    452   }
    453 
    454   MultiPush(regs);
    455 }
    456 
    457 void TurboAssembler::RestoreRegisters(RegList registers) {
    458   DCHECK_GT(NumRegs(registers), 0);
    459   RegList regs = 0;
    460   for (int i = 0; i < Register::kNumRegisters; ++i) {
    461     if ((registers >> i) & 1u) {
    462       regs |= Register::from_code(i).bit();
    463     }
    464   }
    465   MultiPop(regs);
    466 }
    467 
    468 void TurboAssembler::CallRecordWriteStub(
    469     Register object, Register address,
    470     RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode) {
    471   // TODO(albertnetymk): For now we ignore remembered_set_action and fp_mode,
    472   // i.e. always emit remember set and save FP registers in RecordWriteStub. If
    473   // large performance regression is observed, we should use these values to
    474   // avoid unnecessary work.
    475 
    476   Callable const callable =
    477       Builtins::CallableFor(isolate(), Builtins::kRecordWrite);
    478   RegList registers = callable.descriptor().allocatable_registers();
    479 
    480   SaveRegisters(registers);
    481 
    482   Register object_parameter(callable.descriptor().GetRegisterParameter(
    483       RecordWriteDescriptor::kObject));
    484   Register slot_parameter(
    485       callable.descriptor().GetRegisterParameter(RecordWriteDescriptor::kSlot));
    486   Register isolate_parameter(callable.descriptor().GetRegisterParameter(
    487       RecordWriteDescriptor::kIsolate));
    488   Register remembered_set_parameter(callable.descriptor().GetRegisterParameter(
    489       RecordWriteDescriptor::kRememberedSet));
    490   Register fp_mode_parameter(callable.descriptor().GetRegisterParameter(
    491       RecordWriteDescriptor::kFPMode));
    492 
    493   push(object);
    494   push(address);
    495 
    496   pop(slot_parameter);
    497   pop(object_parameter);
    498 
    499   Move(isolate_parameter, ExternalReference::isolate_address(isolate()));
    500   Move(remembered_set_parameter, Smi::FromEnum(remembered_set_action));
    501   Move(fp_mode_parameter, Smi::FromEnum(fp_mode));
    502   Call(callable.code(), RelocInfo::CODE_TARGET);
    503 
    504   RestoreRegisters(registers);
    505 }
    506 
    507 // Will clobber 4 registers: object, address, scratch, ip.  The
    508 // register 'object' contains a heap object pointer.  The heap object
    509 // tag is shifted away.
    510 void MacroAssembler::RecordWrite(Register object, Register address,
    511                                  Register value, LinkRegisterStatus lr_status,
    512                                  SaveFPRegsMode fp_mode,
    513                                  RememberedSetAction remembered_set_action,
    514                                  SmiCheck smi_check) {
    515   DCHECK(object != value);
    516   if (emit_debug_code()) {
    517     LoadP(r0, MemOperand(address));
    518     cmp(r0, value);
    519     Check(eq, AbortReason::kWrongAddressOrValuePassedToRecordWrite);
    520   }
    521 
    522   if (remembered_set_action == OMIT_REMEMBERED_SET &&
    523       !FLAG_incremental_marking) {
    524     return;
    525   }
    526 
    527   // First, check if a write barrier is even needed. The tests below
    528   // catch stores of smis and stores into the young generation.
    529   Label done;
    530 
    531   if (smi_check == INLINE_SMI_CHECK) {
    532     JumpIfSmi(value, &done);
    533   }
    534 
    535   CheckPageFlag(value,
    536                 value,  // Used as scratch.
    537                 MemoryChunk::kPointersToHereAreInterestingMask, eq, &done);
    538   CheckPageFlag(object,
    539                 value,  // Used as scratch.
    540                 MemoryChunk::kPointersFromHereAreInterestingMask, eq, &done);
    541 
    542   // Record the actual write.
    543   if (lr_status == kLRHasNotBeenSaved) {
    544     mflr(r0);
    545     push(r0);
    546   }
    547   CallRecordWriteStub(object, address, remembered_set_action, fp_mode);
    548   if (lr_status == kLRHasNotBeenSaved) {
    549     pop(r0);
    550     mtlr(r0);
    551   }
    552 
    553   bind(&done);
    554 
    555   // Count number of write barriers in generated code.
    556   isolate()->counters()->write_barriers_static()->Increment();
    557   IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, ip,
    558                    value);
    559 
    560   // Clobber clobbered registers when running with the debug-code flag
    561   // turned on to provoke errors.
    562   if (emit_debug_code()) {
    563     mov(address, Operand(bit_cast<intptr_t>(kZapValue + 12)));
    564     mov(value, Operand(bit_cast<intptr_t>(kZapValue + 16)));
    565   }
    566 }
    567 
    568 void TurboAssembler::PushCommonFrame(Register marker_reg) {
    569   int fp_delta = 0;
    570   mflr(r0);
    571   if (FLAG_enable_embedded_constant_pool) {
    572     if (marker_reg.is_valid()) {
    573       Push(r0, fp, kConstantPoolRegister, marker_reg);
    574       fp_delta = 2;
    575     } else {
    576       Push(r0, fp, kConstantPoolRegister);
    577       fp_delta = 1;
    578     }
    579   } else {
    580     if (marker_reg.is_valid()) {
    581       Push(r0, fp, marker_reg);
    582       fp_delta = 1;
    583     } else {
    584       Push(r0, fp);
    585       fp_delta = 0;
    586     }
    587   }
    588   addi(fp, sp, Operand(fp_delta * kPointerSize));
    589 }
    590 
    591 void TurboAssembler::PushStandardFrame(Register function_reg) {
    592   int fp_delta = 0;
    593   mflr(r0);
    594   if (FLAG_enable_embedded_constant_pool) {
    595     if (function_reg.is_valid()) {
    596       Push(r0, fp, kConstantPoolRegister, cp, function_reg);
    597       fp_delta = 3;
    598     } else {
    599       Push(r0, fp, kConstantPoolRegister, cp);
    600       fp_delta = 2;
    601     }
    602   } else {
    603     if (function_reg.is_valid()) {
    604       Push(r0, fp, cp, function_reg);
    605       fp_delta = 2;
    606     } else {
    607       Push(r0, fp, cp);
    608       fp_delta = 1;
    609     }
    610   }
    611   addi(fp, sp, Operand(fp_delta * kPointerSize));
    612 }
    613 
    614 void TurboAssembler::RestoreFrameStateForTailCall() {
    615   if (FLAG_enable_embedded_constant_pool) {
    616     LoadP(kConstantPoolRegister,
    617           MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
    618     set_constant_pool_available(false);
    619   }
    620   LoadP(r0, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
    621   LoadP(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
    622   mtlr(r0);
    623 }
    624 
    625 // Push and pop all registers that can hold pointers.
    626 void MacroAssembler::PushSafepointRegisters() {
    627   // Safepoints expect a block of kNumSafepointRegisters values on the
    628   // stack, so adjust the stack for unsaved registers.
    629   const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
    630   DCHECK_GE(num_unsaved, 0);
    631   if (num_unsaved > 0) {
    632     subi(sp, sp, Operand(num_unsaved * kPointerSize));
    633   }
    634   MultiPush(kSafepointSavedRegisters);
    635 }
    636 
    637 
    638 void MacroAssembler::PopSafepointRegisters() {
    639   const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
    640   MultiPop(kSafepointSavedRegisters);
    641   if (num_unsaved > 0) {
    642     addi(sp, sp, Operand(num_unsaved * kPointerSize));
    643   }
    644 }
    645 
    646 int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
    647   // The registers are pushed starting with the highest encoding,
    648   // which means that lowest encodings are closest to the stack pointer.
    649   RegList regs = kSafepointSavedRegisters;
    650   int index = 0;
    651 
    652   DCHECK(reg_code >= 0 && reg_code < kNumRegisters);
    653 
    654   for (int16_t i = 0; i < reg_code; i++) {
    655     if ((regs & (1 << i)) != 0) {
    656       index++;
    657     }
    658   }
    659 
    660   return index;
    661 }
    662 
    663 
    664 void TurboAssembler::CanonicalizeNaN(const DoubleRegister dst,
    665                                      const DoubleRegister src) {
    666   // Turn potential sNaN into qNaN.
    667   fsub(dst, src, kDoubleRegZero);
    668 }
    669 
    670 void TurboAssembler::ConvertIntToDouble(Register src, DoubleRegister dst) {
    671   MovIntToDouble(dst, src, r0);
    672   fcfid(dst, dst);
    673 }
    674 
    675 void TurboAssembler::ConvertUnsignedIntToDouble(Register src,
    676                                                 DoubleRegister dst) {
    677   MovUnsignedIntToDouble(dst, src, r0);
    678   fcfid(dst, dst);
    679 }
    680 
    681 void TurboAssembler::ConvertIntToFloat(Register src, DoubleRegister dst) {
    682   MovIntToDouble(dst, src, r0);
    683   fcfids(dst, dst);
    684 }
    685 
    686 void TurboAssembler::ConvertUnsignedIntToFloat(Register src,
    687                                                DoubleRegister dst) {
    688   MovUnsignedIntToDouble(dst, src, r0);
    689   fcfids(dst, dst);
    690 }
    691 
    692 #if V8_TARGET_ARCH_PPC64
    693 void TurboAssembler::ConvertInt64ToDouble(Register src,
    694                                           DoubleRegister double_dst) {
    695   MovInt64ToDouble(double_dst, src);
    696   fcfid(double_dst, double_dst);
    697 }
    698 
    699 void TurboAssembler::ConvertUnsignedInt64ToFloat(Register src,
    700                                                  DoubleRegister double_dst) {
    701   MovInt64ToDouble(double_dst, src);
    702   fcfidus(double_dst, double_dst);
    703 }
    704 
    705 void TurboAssembler::ConvertUnsignedInt64ToDouble(Register src,
    706                                                   DoubleRegister double_dst) {
    707   MovInt64ToDouble(double_dst, src);
    708   fcfidu(double_dst, double_dst);
    709 }
    710 
    711 void TurboAssembler::ConvertInt64ToFloat(Register src,
    712                                          DoubleRegister double_dst) {
    713   MovInt64ToDouble(double_dst, src);
    714   fcfids(double_dst, double_dst);
    715 }
    716 #endif
    717 
    718 void TurboAssembler::ConvertDoubleToInt64(const DoubleRegister double_input,
    719 #if !V8_TARGET_ARCH_PPC64
    720                                           const Register dst_hi,
    721 #endif
    722                                           const Register dst,
    723                                           const DoubleRegister double_dst,
    724                                           FPRoundingMode rounding_mode) {
    725   if (rounding_mode == kRoundToZero) {
    726     fctidz(double_dst, double_input);
    727   } else {
    728     SetRoundingMode(rounding_mode);
    729     fctid(double_dst, double_input);
    730     ResetRoundingMode();
    731   }
    732 
    733   MovDoubleToInt64(
    734 #if !V8_TARGET_ARCH_PPC64
    735       dst_hi,
    736 #endif
    737       dst, double_dst);
    738 }
    739 
    740 #if V8_TARGET_ARCH_PPC64
    741 void TurboAssembler::ConvertDoubleToUnsignedInt64(
    742     const DoubleRegister double_input, const Register dst,
    743     const DoubleRegister double_dst, FPRoundingMode rounding_mode) {
    744   if (rounding_mode == kRoundToZero) {
    745     fctiduz(double_dst, double_input);
    746   } else {
    747     SetRoundingMode(rounding_mode);
    748     fctidu(double_dst, double_input);
    749     ResetRoundingMode();
    750   }
    751 
    752   MovDoubleToInt64(dst, double_dst);
    753 }
    754 #endif
    755 
    756 #if !V8_TARGET_ARCH_PPC64
    757 void TurboAssembler::ShiftLeftPair(Register dst_low, Register dst_high,
    758                                    Register src_low, Register src_high,
    759                                    Register scratch, Register shift) {
    760   DCHECK(!AreAliased(dst_low, src_high));
    761   DCHECK(!AreAliased(dst_high, src_low));
    762   DCHECK(!AreAliased(dst_low, dst_high, shift));
    763   Label less_than_32;
    764   Label done;
    765   cmpi(shift, Operand(32));
    766   blt(&less_than_32);
    767   // If shift >= 32
    768   andi(scratch, shift, Operand(0x1F));
    769   slw(dst_high, src_low, scratch);
    770   li(dst_low, Operand::Zero());
    771   b(&done);
    772   bind(&less_than_32);
    773   // If shift < 32
    774   subfic(scratch, shift, Operand(32));
    775   slw(dst_high, src_high, shift);
    776   srw(scratch, src_low, scratch);
    777   orx(dst_high, dst_high, scratch);
    778   slw(dst_low, src_low, shift);
    779   bind(&done);
    780 }
    781 
    782 void TurboAssembler::ShiftLeftPair(Register dst_low, Register dst_high,
    783                                    Register src_low, Register src_high,
    784                                    uint32_t shift) {
    785   DCHECK(!AreAliased(dst_low, src_high));
    786   DCHECK(!AreAliased(dst_high, src_low));
    787   if (shift == 32) {
    788     Move(dst_high, src_low);
    789     li(dst_low, Operand::Zero());
    790   } else if (shift > 32) {
    791     shift &= 0x1F;
    792     slwi(dst_high, src_low, Operand(shift));
    793     li(dst_low, Operand::Zero());
    794   } else if (shift == 0) {
    795     Move(dst_low, src_low);
    796     Move(dst_high, src_high);
    797   } else {
    798     slwi(dst_high, src_high, Operand(shift));
    799     rlwimi(dst_high, src_low, shift, 32 - shift, 31);
    800     slwi(dst_low, src_low, Operand(shift));
    801   }
    802 }
    803 
    804 void TurboAssembler::ShiftRightPair(Register dst_low, Register dst_high,
    805                                     Register src_low, Register src_high,
    806                                     Register scratch, Register shift) {
    807   DCHECK(!AreAliased(dst_low, src_high));
    808   DCHECK(!AreAliased(dst_high, src_low));
    809   DCHECK(!AreAliased(dst_low, dst_high, shift));
    810   Label less_than_32;
    811   Label done;
    812   cmpi(shift, Operand(32));
    813   blt(&less_than_32);
    814   // If shift >= 32
    815   andi(scratch, shift, Operand(0x1F));
    816   srw(dst_low, src_high, scratch);
    817   li(dst_high, Operand::Zero());
    818   b(&done);
    819   bind(&less_than_32);
    820   // If shift < 32
    821   subfic(scratch, shift, Operand(32));
    822   srw(dst_low, src_low, shift);
    823   slw(scratch, src_high, scratch);
    824   orx(dst_low, dst_low, scratch);
    825   srw(dst_high, src_high, shift);
    826   bind(&done);
    827 }
    828 
    829 void TurboAssembler::ShiftRightPair(Register dst_low, Register dst_high,
    830                                     Register src_low, Register src_high,
    831                                     uint32_t shift) {
    832   DCHECK(!AreAliased(dst_low, src_high));
    833   DCHECK(!AreAliased(dst_high, src_low));
    834   if (shift == 32) {
    835     Move(dst_low, src_high);
    836     li(dst_high, Operand::Zero());
    837   } else if (shift > 32) {
    838     shift &= 0x1F;
    839     srwi(dst_low, src_high, Operand(shift));
    840     li(dst_high, Operand::Zero());
    841   } else if (shift == 0) {
    842     Move(dst_low, src_low);
    843     Move(dst_high, src_high);
    844   } else {
    845     srwi(dst_low, src_low, Operand(shift));
    846     rlwimi(dst_low, src_high, 32 - shift, 0, shift - 1);
    847     srwi(dst_high, src_high, Operand(shift));
    848   }
    849 }
    850 
    851 void TurboAssembler::ShiftRightAlgPair(Register dst_low, Register dst_high,
    852                                        Register src_low, Register src_high,
    853                                        Register scratch, Register shift) {
    854   DCHECK(!AreAliased(dst_low, src_high, shift));
    855   DCHECK(!AreAliased(dst_high, src_low, shift));
    856   Label less_than_32;
    857   Label done;
    858   cmpi(shift, Operand(32));
    859   blt(&less_than_32);
    860   // If shift >= 32
    861   andi(scratch, shift, Operand(0x1F));
    862   sraw(dst_low, src_high, scratch);
    863   srawi(dst_high, src_high, 31);
    864   b(&done);
    865   bind(&less_than_32);
    866   // If shift < 32
    867   subfic(scratch, shift, Operand(32));
    868   srw(dst_low, src_low, shift);
    869   slw(scratch, src_high, scratch);
    870   orx(dst_low, dst_low, scratch);
    871   sraw(dst_high, src_high, shift);
    872   bind(&done);
    873 }
    874 
    875 void TurboAssembler::ShiftRightAlgPair(Register dst_low, Register dst_high,
    876                                        Register src_low, Register src_high,
    877                                        uint32_t shift) {
    878   DCHECK(!AreAliased(dst_low, src_high));
    879   DCHECK(!AreAliased(dst_high, src_low));
    880   if (shift == 32) {
    881     Move(dst_low, src_high);
    882     srawi(dst_high, src_high, 31);
    883   } else if (shift > 32) {
    884     shift &= 0x1F;
    885     srawi(dst_low, src_high, shift);
    886     srawi(dst_high, src_high, 31);
    887   } else if (shift == 0) {
    888     Move(dst_low, src_low);
    889     Move(dst_high, src_high);
    890   } else {
    891     srwi(dst_low, src_low, Operand(shift));
    892     rlwimi(dst_low, src_high, 32 - shift, 0, shift - 1);
    893     srawi(dst_high, src_high, shift);
    894   }
    895 }
    896 #endif
    897 
    898 void TurboAssembler::LoadConstantPoolPointerRegisterFromCodeTargetAddress(
    899     Register code_target_address) {
    900   lwz(kConstantPoolRegister,
    901       MemOperand(code_target_address,
    902                  Code::kConstantPoolOffset - Code::kHeaderSize));
    903   add(kConstantPoolRegister, kConstantPoolRegister, code_target_address);
    904 }
    905 
    906 void TurboAssembler::LoadPC(Register dst) {
    907   b(4, SetLK);
    908   mflr(dst);
    909 }
    910 
    911 void TurboAssembler::ComputeCodeStartAddress(Register dst) {
    912   mflr(r0);
    913   LoadPC(dst);
    914   subi(dst, dst, Operand(pc_offset() - kInstrSize));
    915   mtlr(r0);
    916 }
    917 
    918 void TurboAssembler::LoadConstantPoolPointerRegister() {
    919   LoadPC(kConstantPoolRegister);
    920   int32_t delta = -pc_offset() + 4;
    921   add_label_offset(kConstantPoolRegister, kConstantPoolRegister,
    922                    ConstantPoolPosition(), delta);
    923 }
    924 
    925 void TurboAssembler::StubPrologue(StackFrame::Type type) {
    926   {
    927     ConstantPoolUnavailableScope constant_pool_unavailable(this);
    928     mov(r11, Operand(StackFrame::TypeToMarker(type)));
    929     PushCommonFrame(r11);
    930   }
    931   if (FLAG_enable_embedded_constant_pool) {
    932     LoadConstantPoolPointerRegister();
    933     set_constant_pool_available(true);
    934   }
    935 }
    936 
    937 void TurboAssembler::Prologue() {
    938   PushStandardFrame(r4);
    939   if (FLAG_enable_embedded_constant_pool) {
    940     // base contains prologue address
    941     LoadConstantPoolPointerRegister();
    942     set_constant_pool_available(true);
    943   }
    944 }
    945 
    946 void TurboAssembler::EnterFrame(StackFrame::Type type,
    947                                 bool load_constant_pool_pointer_reg) {
    948   if (FLAG_enable_embedded_constant_pool && load_constant_pool_pointer_reg) {
    949     // Push type explicitly so we can leverage the constant pool.
    950     // This path cannot rely on ip containing code entry.
    951     PushCommonFrame();
    952     LoadConstantPoolPointerRegister();
    953     mov(ip, Operand(StackFrame::TypeToMarker(type)));
    954     push(ip);
    955   } else {
    956     mov(ip, Operand(StackFrame::TypeToMarker(type)));
    957     PushCommonFrame(ip);
    958   }
    959 }
    960 
    961 int TurboAssembler::LeaveFrame(StackFrame::Type type, int stack_adjustment) {
    962   ConstantPoolUnavailableScope constant_pool_unavailable(this);
    963   // r3: preserved
    964   // r4: preserved
    965   // r5: preserved
    966 
    967   // Drop the execution stack down to the frame pointer and restore
    968   // the caller's state.
    969   int frame_ends;
    970   LoadP(r0, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
    971   LoadP(ip, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
    972   if (FLAG_enable_embedded_constant_pool) {
    973     LoadP(kConstantPoolRegister,
    974           MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
    975   }
    976   mtlr(r0);
    977   frame_ends = pc_offset();
    978   Add(sp, fp, StandardFrameConstants::kCallerSPOffset + stack_adjustment, r0);
    979   mr(fp, ip);
    980   return frame_ends;
    981 }
    982 
    983 // ExitFrame layout (probably wrongish.. needs updating)
    984 //
    985 //  SP -> previousSP
    986 //        LK reserved
    987 //        code
    988 //        sp_on_exit (for debug?)
    989 // oldSP->prev SP
    990 //        LK
    991 //        <parameters on stack>
    992 
    993 // Prior to calling EnterExitFrame, we've got a bunch of parameters
    994 // on the stack that we need to wrap a real frame around.. so first
    995 // we reserve a slot for LK and push the previous SP which is captured
    996 // in the fp register (r31)
    997 // Then - we buy a new frame
    998 
    999 void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
   1000                                     StackFrame::Type frame_type) {
   1001   DCHECK(frame_type == StackFrame::EXIT ||
   1002          frame_type == StackFrame::BUILTIN_EXIT);
   1003   // Set up the frame structure on the stack.
   1004   DCHECK_EQ(2 * kPointerSize, ExitFrameConstants::kCallerSPDisplacement);
   1005   DCHECK_EQ(1 * kPointerSize, ExitFrameConstants::kCallerPCOffset);
   1006   DCHECK_EQ(0 * kPointerSize, ExitFrameConstants::kCallerFPOffset);
   1007   DCHECK_GT(stack_space, 0);
   1008 
   1009   // This is an opportunity to build a frame to wrap
   1010   // all of the pushes that have happened inside of V8
   1011   // since we were called from C code
   1012 
   1013   mov(ip, Operand(StackFrame::TypeToMarker(frame_type)));
   1014   PushCommonFrame(ip);
   1015   // Reserve room for saved entry sp and code object.
   1016   subi(sp, fp, Operand(ExitFrameConstants::kFixedFrameSizeFromFp));
   1017 
   1018   if (emit_debug_code()) {
   1019     li(r8, Operand::Zero());
   1020     StoreP(r8, MemOperand(fp, ExitFrameConstants::kSPOffset));
   1021   }
   1022   if (FLAG_enable_embedded_constant_pool) {
   1023     StoreP(kConstantPoolRegister,
   1024            MemOperand(fp, ExitFrameConstants::kConstantPoolOffset));
   1025   }
   1026   Move(r8, CodeObject());
   1027   StoreP(r8, MemOperand(fp, ExitFrameConstants::kCodeOffset));
   1028 
   1029   // Save the frame pointer and the context in top.
   1030   Move(r8, ExternalReference::Create(IsolateAddressId::kCEntryFPAddress,
   1031                                      isolate()));
   1032   StoreP(fp, MemOperand(r8));
   1033   Move(r8,
   1034        ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()));
   1035   StoreP(cp, MemOperand(r8));
   1036 
   1037   // Optionally save all volatile double registers.
   1038   if (save_doubles) {
   1039     MultiPushDoubles(kCallerSavedDoubles);
   1040     // Note that d0 will be accessible at
   1041     //   fp - ExitFrameConstants::kFrameSize -
   1042     //   kNumCallerSavedDoubles * kDoubleSize,
   1043     // since the sp slot and code slot were pushed after the fp.
   1044   }
   1045 
   1046   addi(sp, sp, Operand(-stack_space * kPointerSize));
   1047 
   1048   // Allocate and align the frame preparing for calling the runtime
   1049   // function.
   1050   const int frame_alignment = ActivationFrameAlignment();
   1051   if (frame_alignment > kPointerSize) {
   1052     DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
   1053     ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
   1054   }
   1055   li(r0, Operand::Zero());
   1056   StorePU(r0, MemOperand(sp, -kNumRequiredStackFrameSlots * kPointerSize));
   1057 
   1058   // Set the exit frame sp value to point just before the return address
   1059   // location.
   1060   addi(r8, sp, Operand((kStackFrameExtraParamSlot + 1) * kPointerSize));
   1061   StoreP(r8, MemOperand(fp, ExitFrameConstants::kSPOffset));
   1062 }
   1063 
   1064 int TurboAssembler::ActivationFrameAlignment() {
   1065 #if !defined(USE_SIMULATOR)
   1066   // Running on the real platform. Use the alignment as mandated by the local
   1067   // environment.
   1068   // Note: This will break if we ever start generating snapshots on one PPC
   1069   // platform for another PPC platform with a different alignment.
   1070   return base::OS::ActivationFrameAlignment();
   1071 #else  // Simulated
   1072   // If we are using the simulator then we should always align to the expected
   1073   // alignment. As the simulator is used to generate snapshots we do not know
   1074   // if the target platform will need alignment, so this is controlled from a
   1075   // flag.
   1076   return FLAG_sim_stack_alignment;
   1077 #endif
   1078 }
   1079 
   1080 
   1081 void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
   1082                                     bool argument_count_is_length) {
   1083   ConstantPoolUnavailableScope constant_pool_unavailable(this);
   1084   // Optionally restore all double registers.
   1085   if (save_doubles) {
   1086     // Calculate the stack location of the saved doubles and restore them.
   1087     const int kNumRegs = kNumCallerSavedDoubles;
   1088     const int offset =
   1089         (ExitFrameConstants::kFixedFrameSizeFromFp + kNumRegs * kDoubleSize);
   1090     addi(r6, fp, Operand(-offset));
   1091     MultiPopDoubles(kCallerSavedDoubles, r6);
   1092   }
   1093 
   1094   // Clear top frame.
   1095   li(r6, Operand::Zero());
   1096   Move(ip, ExternalReference::Create(IsolateAddressId::kCEntryFPAddress,
   1097                                      isolate()));
   1098   StoreP(r6, MemOperand(ip));
   1099 
   1100   // Restore current context from top and clear it in debug mode.
   1101   Move(ip,
   1102        ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()));
   1103   LoadP(cp, MemOperand(ip));
   1104 
   1105 #ifdef DEBUG
   1106   mov(r6, Operand(Context::kInvalidContext));
   1107   Move(ip,
   1108        ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()));
   1109   StoreP(r6, MemOperand(ip));
   1110 #endif
   1111 
   1112   // Tear down the exit frame, pop the arguments, and return.
   1113   LeaveFrame(StackFrame::EXIT);
   1114 
   1115   if (argument_count.is_valid()) {
   1116     if (!argument_count_is_length) {
   1117       ShiftLeftImm(argument_count, argument_count, Operand(kPointerSizeLog2));
   1118     }
   1119     add(sp, sp, argument_count);
   1120   }
   1121 }
   1122 
   1123 void TurboAssembler::MovFromFloatResult(const DoubleRegister dst) {
   1124   Move(dst, d1);
   1125 }
   1126 
   1127 void TurboAssembler::MovFromFloatParameter(const DoubleRegister dst) {
   1128   Move(dst, d1);
   1129 }
   1130 
   1131 void TurboAssembler::PrepareForTailCall(const ParameterCount& callee_args_count,
   1132                                         Register caller_args_count_reg,
   1133                                         Register scratch0, Register scratch1) {
   1134 #if DEBUG
   1135   if (callee_args_count.is_reg()) {
   1136     DCHECK(!AreAliased(callee_args_count.reg(), caller_args_count_reg, scratch0,
   1137                        scratch1));
   1138   } else {
   1139     DCHECK(!AreAliased(caller_args_count_reg, scratch0, scratch1));
   1140   }
   1141 #endif
   1142 
   1143   // Calculate the end of destination area where we will put the arguments
   1144   // after we drop current frame. We add kPointerSize to count the receiver
   1145   // argument which is not included into formal parameters count.
   1146   Register dst_reg = scratch0;
   1147   ShiftLeftImm(dst_reg, caller_args_count_reg, Operand(kPointerSizeLog2));
   1148   add(dst_reg, fp, dst_reg);
   1149   addi(dst_reg, dst_reg,
   1150        Operand(StandardFrameConstants::kCallerSPOffset + kPointerSize));
   1151 
   1152   Register src_reg = caller_args_count_reg;
   1153   // Calculate the end of source area. +kPointerSize is for the receiver.
   1154   if (callee_args_count.is_reg()) {
   1155     ShiftLeftImm(src_reg, callee_args_count.reg(), Operand(kPointerSizeLog2));
   1156     add(src_reg, sp, src_reg);
   1157     addi(src_reg, src_reg, Operand(kPointerSize));
   1158   } else {
   1159     Add(src_reg, sp, (callee_args_count.immediate() + 1) * kPointerSize, r0);
   1160   }
   1161 
   1162   if (FLAG_debug_code) {
   1163     cmpl(src_reg, dst_reg);
   1164     Check(lt, AbortReason::kStackAccessBelowStackPointer);
   1165   }
   1166 
   1167   // Restore caller's frame pointer and return address now as they will be
   1168   // overwritten by the copying loop.
   1169   RestoreFrameStateForTailCall();
   1170 
   1171   // Now copy callee arguments to the caller frame going backwards to avoid
   1172   // callee arguments corruption (source and destination areas could overlap).
   1173 
   1174   // Both src_reg and dst_reg are pointing to the word after the one to copy,
   1175   // so they must be pre-decremented in the loop.
   1176   Register tmp_reg = scratch1;
   1177   Label loop;
   1178   if (callee_args_count.is_reg()) {
   1179     addi(tmp_reg, callee_args_count.reg(), Operand(1));  // +1 for receiver
   1180   } else {
   1181     mov(tmp_reg, Operand(callee_args_count.immediate() + 1));
   1182   }
   1183   mtctr(tmp_reg);
   1184   bind(&loop);
   1185   LoadPU(tmp_reg, MemOperand(src_reg, -kPointerSize));
   1186   StorePU(tmp_reg, MemOperand(dst_reg, -kPointerSize));
   1187   bdnz(&loop);
   1188 
   1189   // Leave current frame.
   1190   mr(sp, dst_reg);
   1191 }
   1192 
   1193 void MacroAssembler::InvokePrologue(const ParameterCount& expected,
   1194                                     const ParameterCount& actual, Label* done,
   1195                                     bool* definitely_mismatches,
   1196                                     InvokeFlag flag) {
   1197   bool definitely_matches = false;
   1198   *definitely_mismatches = false;
   1199   Label regular_invoke;
   1200 
   1201   // Check whether the expected and actual arguments count match. If not,
   1202   // setup registers according to contract with ArgumentsAdaptorTrampoline:
   1203   //  r3: actual arguments count
   1204   //  r4: function (passed through to callee)
   1205   //  r5: expected arguments count
   1206 
   1207   // The code below is made a lot easier because the calling code already sets
   1208   // up actual and expected registers according to the contract if values are
   1209   // passed in registers.
   1210 
   1211   // ARM has some sanity checks as per below, considering add them for PPC
   1212   //  DCHECK(actual.is_immediate() || actual.reg() == r3);
   1213   //  DCHECK(expected.is_immediate() || expected.reg() == r5);
   1214 
   1215   if (expected.is_immediate()) {
   1216     DCHECK(actual.is_immediate());
   1217     mov(r3, Operand(actual.immediate()));
   1218     if (expected.immediate() == actual.immediate()) {
   1219       definitely_matches = true;
   1220     } else {
   1221       const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
   1222       if (expected.immediate() == sentinel) {
   1223         // Don't worry about adapting arguments for builtins that
   1224         // don't want that done. Skip adaption code by making it look
   1225         // like we have a match between expected and actual number of
   1226         // arguments.
   1227         definitely_matches = true;
   1228       } else {
   1229         *definitely_mismatches = true;
   1230         mov(r5, Operand(expected.immediate()));
   1231       }
   1232     }
   1233   } else {
   1234     if (actual.is_immediate()) {
   1235       mov(r3, Operand(actual.immediate()));
   1236       cmpi(expected.reg(), Operand(actual.immediate()));
   1237       beq(&regular_invoke);
   1238     } else {
   1239       cmp(expected.reg(), actual.reg());
   1240       beq(&regular_invoke);
   1241     }
   1242   }
   1243 
   1244   if (!definitely_matches) {
   1245     Handle<Code> adaptor = BUILTIN_CODE(isolate(), ArgumentsAdaptorTrampoline);
   1246     if (flag == CALL_FUNCTION) {
   1247       Call(adaptor);
   1248       if (!*definitely_mismatches) {
   1249         b(done);
   1250       }
   1251     } else {
   1252       Jump(adaptor, RelocInfo::CODE_TARGET);
   1253     }
   1254     bind(&regular_invoke);
   1255   }
   1256 }
   1257 
   1258 void MacroAssembler::CheckDebugHook(Register fun, Register new_target,
   1259                                     const ParameterCount& expected,
   1260                                     const ParameterCount& actual) {
   1261   Label skip_hook;
   1262 
   1263   ExternalReference debug_hook_active =
   1264       ExternalReference::debug_hook_on_function_call_address(isolate());
   1265   Move(r7, debug_hook_active);
   1266   LoadByte(r7, MemOperand(r7), r0);
   1267   extsb(r7, r7);
   1268   CmpSmiLiteral(r7, Smi::kZero, r0);
   1269   beq(&skip_hook);
   1270 
   1271   {
   1272     // Load receiver to pass it later to DebugOnFunctionCall hook.
   1273     if (actual.is_reg()) {
   1274       mr(r7, actual.reg());
   1275     } else {
   1276       mov(r7, Operand(actual.immediate()));
   1277     }
   1278     ShiftLeftImm(r7, r7, Operand(kPointerSizeLog2));
   1279     LoadPX(r7, MemOperand(sp, r7));
   1280     FrameScope frame(this,
   1281                      has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
   1282     if (expected.is_reg()) {
   1283       SmiTag(expected.reg());
   1284       Push(expected.reg());
   1285     }
   1286     if (actual.is_reg()) {
   1287       SmiTag(actual.reg());
   1288       Push(actual.reg());
   1289     }
   1290     if (new_target.is_valid()) {
   1291       Push(new_target);
   1292     }
   1293     Push(fun, fun, r7);
   1294     CallRuntime(Runtime::kDebugOnFunctionCall);
   1295     Pop(fun);
   1296     if (new_target.is_valid()) {
   1297       Pop(new_target);
   1298     }
   1299     if (actual.is_reg()) {
   1300       Pop(actual.reg());
   1301       SmiUntag(actual.reg());
   1302     }
   1303     if (expected.is_reg()) {
   1304       Pop(expected.reg());
   1305       SmiUntag(expected.reg());
   1306     }
   1307   }
   1308   bind(&skip_hook);
   1309 }
   1310 
   1311 void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
   1312                                         const ParameterCount& expected,
   1313                                         const ParameterCount& actual,
   1314                                         InvokeFlag flag) {
   1315   // You can't call a function without a valid frame.
   1316   DCHECK(flag == JUMP_FUNCTION || has_frame());
   1317   DCHECK(function == r4);
   1318   DCHECK_IMPLIES(new_target.is_valid(), new_target == r6);
   1319 
   1320   // On function call, call into the debugger if necessary.
   1321   CheckDebugHook(function, new_target, expected, actual);
   1322 
   1323   // Clear the new.target register if not given.
   1324   if (!new_target.is_valid()) {
   1325     LoadRoot(r6, Heap::kUndefinedValueRootIndex);
   1326   }
   1327 
   1328   Label done;
   1329   bool definitely_mismatches = false;
   1330   InvokePrologue(expected, actual, &done, &definitely_mismatches, flag);
   1331   if (!definitely_mismatches) {
   1332     // We call indirectly through the code field in the function to
   1333     // allow recompilation to take effect without changing any of the
   1334     // call sites.
   1335     Register code = kJavaScriptCallCodeStartRegister;
   1336     LoadP(code, FieldMemOperand(function, JSFunction::kCodeOffset));
   1337     addi(code, code, Operand(Code::kHeaderSize - kHeapObjectTag));
   1338     if (flag == CALL_FUNCTION) {
   1339       CallJSEntry(code);
   1340     } else {
   1341       DCHECK(flag == JUMP_FUNCTION);
   1342       JumpToJSEntry(code);
   1343     }
   1344 
   1345     // Continue here if InvokePrologue does handle the invocation due to
   1346     // mismatched parameter counts.
   1347     bind(&done);
   1348   }
   1349 }
   1350 
   1351 void MacroAssembler::InvokeFunction(Register fun, Register new_target,
   1352                                     const ParameterCount& actual,
   1353                                     InvokeFlag flag) {
   1354   // You can't call a function without a valid frame.
   1355   DCHECK(flag == JUMP_FUNCTION || has_frame());
   1356 
   1357   // Contract with called JS functions requires that function is passed in r4.
   1358   DCHECK(fun == r4);
   1359 
   1360   Register expected_reg = r5;
   1361   Register temp_reg = r7;
   1362 
   1363   LoadP(temp_reg, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
   1364   LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
   1365   LoadHalfWord(expected_reg,
   1366                FieldMemOperand(
   1367                    temp_reg, SharedFunctionInfo::kFormalParameterCountOffset));
   1368 
   1369   ParameterCount expected(expected_reg);
   1370   InvokeFunctionCode(fun, new_target, expected, actual, flag);
   1371 }
   1372 
   1373 void MacroAssembler::InvokeFunction(Register function,
   1374                                     const ParameterCount& expected,
   1375                                     const ParameterCount& actual,
   1376                                     InvokeFlag flag) {
   1377   // You can't call a function without a valid frame.
   1378   DCHECK(flag == JUMP_FUNCTION || has_frame());
   1379 
   1380   // Contract with called JS functions requires that function is passed in r4.
   1381   DCHECK(function == r4);
   1382 
   1383   // Get the function and setup the context.
   1384   LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
   1385 
   1386   InvokeFunctionCode(r4, no_reg, expected, actual, flag);
   1387 }
   1388 
   1389 void MacroAssembler::MaybeDropFrames() {
   1390   // Check whether we need to drop frames to restart a function on the stack.
   1391   ExternalReference restart_fp =
   1392       ExternalReference::debug_restart_fp_address(isolate());
   1393   Move(r4, restart_fp);
   1394   LoadP(r4, MemOperand(r4));
   1395   cmpi(r4, Operand::Zero());
   1396   Jump(BUILTIN_CODE(isolate(), FrameDropperTrampoline), RelocInfo::CODE_TARGET,
   1397        ne);
   1398 }
   1399 
   1400 void MacroAssembler::PushStackHandler() {
   1401   // Adjust this code if not the case.
   1402   STATIC_ASSERT(StackHandlerConstants::kSize == 2 * kPointerSize);
   1403   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
   1404 
   1405   Push(Smi::kZero);  // Padding.
   1406 
   1407   // Link the current handler as the next handler.
   1408   // Preserve r3-r7.
   1409   mov(r8, Operand(ExternalReference::Create(IsolateAddressId::kHandlerAddress,
   1410                                             isolate())));
   1411   LoadP(r0, MemOperand(r8));
   1412   push(r0);
   1413 
   1414   // Set this new handler as the current one.
   1415   StoreP(sp, MemOperand(r8));
   1416 }
   1417 
   1418 
   1419 void MacroAssembler::PopStackHandler() {
   1420   STATIC_ASSERT(StackHandlerConstants::kSize == 2 * kPointerSize);
   1421   STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
   1422 
   1423   pop(r4);
   1424   mov(ip, Operand(ExternalReference::Create(IsolateAddressId::kHandlerAddress,
   1425                                             isolate())));
   1426   StoreP(r4, MemOperand(ip));
   1427 
   1428   Drop(1);  // Drop padding.
   1429 }
   1430 
   1431 
   1432 void MacroAssembler::CompareObjectType(Register object, Register map,
   1433                                        Register type_reg, InstanceType type) {
   1434   const Register temp = type_reg == no_reg ? r0 : type_reg;
   1435 
   1436   LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset));
   1437   CompareInstanceType(map, temp, type);
   1438 }
   1439 
   1440 
   1441 void MacroAssembler::CompareInstanceType(Register map, Register type_reg,
   1442                                          InstanceType type) {
   1443   STATIC_ASSERT(Map::kInstanceTypeOffset < 4096);
   1444   STATIC_ASSERT(LAST_TYPE <= 0xFFFF);
   1445   lhz(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
   1446   cmpi(type_reg, Operand(type));
   1447 }
   1448 
   1449 
   1450 void MacroAssembler::CompareRoot(Register obj, Heap::RootListIndex index) {
   1451   DCHECK(obj != r0);
   1452   LoadRoot(r0, index);
   1453   cmp(obj, r0);
   1454 }
   1455 
   1456 void TurboAssembler::AddAndCheckForOverflow(Register dst, Register left,
   1457                                             Register right,
   1458                                             Register overflow_dst,
   1459                                             Register scratch) {
   1460   DCHECK(dst != overflow_dst);
   1461   DCHECK(dst != scratch);
   1462   DCHECK(overflow_dst != scratch);
   1463   DCHECK(overflow_dst != left);
   1464   DCHECK(overflow_dst != right);
   1465 
   1466   bool left_is_right = left == right;
   1467   RCBit xorRC = left_is_right ? SetRC : LeaveRC;
   1468 
   1469   // C = A+B; C overflows if A/B have same sign and C has diff sign than A
   1470   if (dst == left) {
   1471     mr(scratch, left);            // Preserve left.
   1472     add(dst, left, right);        // Left is overwritten.
   1473     xor_(overflow_dst, dst, scratch, xorRC);  // Original left.
   1474     if (!left_is_right) xor_(scratch, dst, right);
   1475   } else if (dst == right) {
   1476     mr(scratch, right);           // Preserve right.
   1477     add(dst, left, right);        // Right is overwritten.
   1478     xor_(overflow_dst, dst, left, xorRC);
   1479     if (!left_is_right) xor_(scratch, dst, scratch);  // Original right.
   1480   } else {
   1481     add(dst, left, right);
   1482     xor_(overflow_dst, dst, left, xorRC);
   1483     if (!left_is_right) xor_(scratch, dst, right);
   1484   }
   1485   if (!left_is_right) and_(overflow_dst, scratch, overflow_dst, SetRC);
   1486 }
   1487 
   1488 void TurboAssembler::AddAndCheckForOverflow(Register dst, Register left,
   1489                                             intptr_t right,
   1490                                             Register overflow_dst,
   1491                                             Register scratch) {
   1492   Register original_left = left;
   1493   DCHECK(dst != overflow_dst);
   1494   DCHECK(dst != scratch);
   1495   DCHECK(overflow_dst != scratch);
   1496   DCHECK(overflow_dst != left);
   1497 
   1498   // C = A+B; C overflows if A/B have same sign and C has diff sign than A
   1499   if (dst == left) {
   1500     // Preserve left.
   1501     original_left = overflow_dst;
   1502     mr(original_left, left);
   1503   }
   1504   Add(dst, left, right, scratch);
   1505   xor_(overflow_dst, dst, original_left);
   1506   if (right >= 0) {
   1507     and_(overflow_dst, overflow_dst, dst, SetRC);
   1508   } else {
   1509     andc(overflow_dst, overflow_dst, dst, SetRC);
   1510   }
   1511 }
   1512 
   1513 void TurboAssembler::SubAndCheckForOverflow(Register dst, Register left,
   1514                                             Register right,
   1515                                             Register overflow_dst,
   1516                                             Register scratch) {
   1517   DCHECK(dst != overflow_dst);
   1518   DCHECK(dst != scratch);
   1519   DCHECK(overflow_dst != scratch);
   1520   DCHECK(overflow_dst != left);
   1521   DCHECK(overflow_dst != right);
   1522 
   1523   // C = A-B; C overflows if A/B have diff signs and C has diff sign than A
   1524   if (dst == left) {
   1525     mr(scratch, left);      // Preserve left.
   1526     sub(dst, left, right);  // Left is overwritten.
   1527     xor_(overflow_dst, dst, scratch);
   1528     xor_(scratch, scratch, right);
   1529     and_(overflow_dst, overflow_dst, scratch, SetRC);
   1530   } else if (dst == right) {
   1531     mr(scratch, right);     // Preserve right.
   1532     sub(dst, left, right);  // Right is overwritten.
   1533     xor_(overflow_dst, dst, left);
   1534     xor_(scratch, left, scratch);
   1535     and_(overflow_dst, overflow_dst, scratch, SetRC);
   1536   } else {
   1537     sub(dst, left, right);
   1538     xor_(overflow_dst, dst, left);
   1539     xor_(scratch, left, right);
   1540     and_(overflow_dst, scratch, overflow_dst, SetRC);
   1541   }
   1542 }
   1543 
   1544 
   1545 void MacroAssembler::CallStub(CodeStub* stub, Condition cond) {
   1546   DCHECK(AllowThisStubCall(stub));  // Stub calls are not allowed in some stubs.
   1547   Call(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
   1548 }
   1549 
   1550 void TurboAssembler::CallStubDelayed(CodeStub* stub) {
   1551   DCHECK(AllowThisStubCall(stub));  // Stub calls are not allowed in some stubs.
   1552 
   1553   // Block constant pool for the call instruction sequence.
   1554   ConstantPoolUnavailableScope constant_pool_unavailable(this);
   1555 
   1556   mov(ip, Operand::EmbeddedCode(stub));
   1557   mtctr(ip);
   1558   bctrl();
   1559 }
   1560 
   1561 void MacroAssembler::TailCallStub(CodeStub* stub, Condition cond) {
   1562   Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond);
   1563 }
   1564 
   1565 bool TurboAssembler::AllowThisStubCall(CodeStub* stub) {
   1566   return has_frame_ || !stub->SometimesSetsUpAFrame();
   1567 }
   1568 
   1569 void MacroAssembler::TryDoubleToInt32Exact(Register result,
   1570                                            DoubleRegister double_input,
   1571                                            Register scratch,
   1572                                            DoubleRegister double_scratch) {
   1573   Label done;
   1574   DCHECK(double_input != double_scratch);
   1575 
   1576   ConvertDoubleToInt64(double_input,
   1577 #if !V8_TARGET_ARCH_PPC64
   1578                        scratch,
   1579 #endif
   1580                        result, double_scratch);
   1581 
   1582 #if V8_TARGET_ARCH_PPC64
   1583   TestIfInt32(result, r0);
   1584 #else
   1585   TestIfInt32(scratch, result, r0);
   1586 #endif
   1587   bne(&done);
   1588 
   1589   // convert back and compare
   1590   fcfid(double_scratch, double_scratch);
   1591   fcmpu(double_scratch, double_input);
   1592   bind(&done);
   1593 }
   1594 
   1595 void TurboAssembler::TruncateDoubleToI(Isolate* isolate, Zone* zone,
   1596                                        Register result,
   1597                                        DoubleRegister double_input,
   1598                                        StubCallMode stub_mode) {
   1599   Label done;
   1600 
   1601   TryInlineTruncateDoubleToI(result, double_input, &done);
   1602 
   1603   // If we fell through then inline version didn't succeed - call stub instead.
   1604   mflr(r0);
   1605   push(r0);
   1606   // Put input on stack.
   1607   stfdu(double_input, MemOperand(sp, -kDoubleSize));
   1608 
   1609   if (stub_mode == StubCallMode::kCallWasmRuntimeStub) {
   1610     Call(wasm::WasmCode::kDoubleToI, RelocInfo::WASM_STUB_CALL);
   1611   } else {
   1612     Call(BUILTIN_CODE(isolate, DoubleToI), RelocInfo::CODE_TARGET);
   1613   }
   1614 
   1615   LoadP(result, MemOperand(sp));
   1616   addi(sp, sp, Operand(kDoubleSize));
   1617   pop(r0);
   1618   mtlr(r0);
   1619 
   1620   bind(&done);
   1621 }
   1622 
   1623 void TurboAssembler::TryInlineTruncateDoubleToI(Register result,
   1624                                                 DoubleRegister double_input,
   1625                                                 Label* done) {
   1626   DoubleRegister double_scratch = kScratchDoubleReg;
   1627 #if !V8_TARGET_ARCH_PPC64
   1628   Register scratch = ip;
   1629 #endif
   1630 
   1631   ConvertDoubleToInt64(double_input,
   1632 #if !V8_TARGET_ARCH_PPC64
   1633                        scratch,
   1634 #endif
   1635                        result, double_scratch);
   1636 
   1637 // Test for overflow
   1638 #if V8_TARGET_ARCH_PPC64
   1639   TestIfInt32(result, r0);
   1640 #else
   1641   TestIfInt32(scratch, result, r0);
   1642 #endif
   1643   beq(done);
   1644 }
   1645 
   1646 void TurboAssembler::CallRuntimeWithCEntry(Runtime::FunctionId fid,
   1647                                            Register centry) {
   1648   const Runtime::Function* f = Runtime::FunctionForId(fid);
   1649   // TODO(1236192): Most runtime routines don't need the number of
   1650   // arguments passed in because it is constant. At some point we
   1651   // should remove this need and make the runtime routine entry code
   1652   // smarter.
   1653   mov(r3, Operand(f->nargs));
   1654   Move(r4, ExternalReference::Create(f));
   1655   DCHECK(!AreAliased(centry, r3, r4));
   1656   addi(centry, centry, Operand(Code::kHeaderSize - kHeapObjectTag));
   1657   Call(centry);
   1658 }
   1659 
   1660 void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
   1661                                  SaveFPRegsMode save_doubles) {
   1662   // All parameters are on the stack.  r3 has the return value after call.
   1663 
   1664   // If the expected number of arguments of the runtime function is
   1665   // constant, we check that the actual number of arguments match the
   1666   // expectation.
   1667   CHECK(f->nargs < 0 || f->nargs == num_arguments);
   1668 
   1669   // TODO(1236192): Most runtime routines don't need the number of
   1670   // arguments passed in because it is constant. At some point we
   1671   // should remove this need and make the runtime routine entry code
   1672   // smarter.
   1673   mov(r3, Operand(num_arguments));
   1674   Move(r4, ExternalReference::Create(f));
   1675 #if V8_TARGET_ARCH_PPC64
   1676   Handle<Code> code =
   1677       CodeFactory::CEntry(isolate(), f->result_size, save_doubles);
   1678 #else
   1679   Handle<Code> code = CodeFactory::CEntry(isolate(), 1, save_doubles);
   1680 #endif
   1681   Call(code, RelocInfo::CODE_TARGET);
   1682 }
   1683 
   1684 void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
   1685   const Runtime::Function* function = Runtime::FunctionForId(fid);
   1686   DCHECK_EQ(1, function->result_size);
   1687   if (function->nargs >= 0) {
   1688     mov(r3, Operand(function->nargs));
   1689   }
   1690   JumpToExternalReference(ExternalReference::Create(fid));
   1691 }
   1692 
   1693 
   1694 void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
   1695                                              bool builtin_exit_frame) {
   1696   Move(r4, builtin);
   1697   Handle<Code> code = CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs,
   1698                                           kArgvOnStack, builtin_exit_frame);
   1699   Jump(code, RelocInfo::CODE_TARGET);
   1700 }
   1701 
   1702 void MacroAssembler::JumpToInstructionStream(Address entry) {
   1703   mov(kOffHeapTrampolineRegister, Operand(entry, RelocInfo::OFF_HEAP_TARGET));
   1704   Jump(kOffHeapTrampolineRegister);
   1705 }
   1706 
   1707 void MacroAssembler::LoadWeakValue(Register out, Register in,
   1708                                    Label* target_if_cleared) {
   1709   cmpi(in, Operand(kClearedWeakHeapObject));
   1710   beq(target_if_cleared);
   1711 
   1712   mov(r0, Operand(~kWeakHeapObjectMask));
   1713   and_(out, in, r0);
   1714 }
   1715 
   1716 void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
   1717                                       Register scratch1, Register scratch2) {
   1718   DCHECK_GT(value, 0);
   1719   if (FLAG_native_code_counters && counter->Enabled()) {
   1720     Move(scratch2, ExternalReference::Create(counter));
   1721     lwz(scratch1, MemOperand(scratch2));
   1722     addi(scratch1, scratch1, Operand(value));
   1723     stw(scratch1, MemOperand(scratch2));
   1724   }
   1725 }
   1726 
   1727 
   1728 void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
   1729                                       Register scratch1, Register scratch2) {
   1730   DCHECK_GT(value, 0);
   1731   if (FLAG_native_code_counters && counter->Enabled()) {
   1732     Move(scratch2, ExternalReference::Create(counter));
   1733     lwz(scratch1, MemOperand(scratch2));
   1734     subi(scratch1, scratch1, Operand(value));
   1735     stw(scratch1, MemOperand(scratch2));
   1736   }
   1737 }
   1738 
   1739 void TurboAssembler::Assert(Condition cond, AbortReason reason,
   1740                             CRegister cr) {
   1741   if (emit_debug_code()) Check(cond, reason, cr);
   1742 }
   1743 
   1744 void TurboAssembler::Check(Condition cond, AbortReason reason, CRegister cr) {
   1745   Label L;
   1746   b(cond, &L, cr);
   1747   Abort(reason);
   1748   // will not return here
   1749   bind(&L);
   1750 }
   1751 
   1752 void TurboAssembler::Abort(AbortReason reason) {
   1753   Label abort_start;
   1754   bind(&abort_start);
   1755   const char* msg = GetAbortReason(reason);
   1756 #ifdef DEBUG
   1757   RecordComment("Abort message: ");
   1758   RecordComment(msg);
   1759 #endif
   1760 
   1761   // Avoid emitting call to builtin if requested.
   1762   if (trap_on_abort()) {
   1763     stop(msg);
   1764     return;
   1765   }
   1766 
   1767   if (should_abort_hard()) {
   1768     // We don't care if we constructed a frame. Just pretend we did.
   1769     FrameScope assume_frame(this, StackFrame::NONE);
   1770     mov(r3, Operand(static_cast<int>(reason)));
   1771     PrepareCallCFunction(1, r4);
   1772     CallCFunction(ExternalReference::abort_with_reason(), 1);
   1773     return;
   1774   }
   1775 
   1776   LoadSmiLiteral(r4, Smi::FromInt(static_cast<int>(reason)));
   1777 
   1778   // Disable stub call restrictions to always allow calls to abort.
   1779   if (!has_frame_) {
   1780     // We don't actually want to generate a pile of code for this, so just
   1781     // claim there is a stack frame, without generating one.
   1782     FrameScope scope(this, StackFrame::NONE);
   1783     Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
   1784   } else {
   1785     Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
   1786   }
   1787   // will not return here
   1788 }
   1789 
   1790 void MacroAssembler::LoadNativeContextSlot(int index, Register dst) {
   1791   LoadP(dst, NativeContextMemOperand());
   1792   LoadP(dst, ContextMemOperand(dst, index));
   1793 }
   1794 
   1795 
   1796 void MacroAssembler::UntagAndJumpIfSmi(Register dst, Register src,
   1797                                        Label* smi_case) {
   1798   STATIC_ASSERT(kSmiTag == 0);
   1799   TestBitRange(src, kSmiTagSize - 1, 0, r0);
   1800   SmiUntag(dst, src);
   1801   beq(smi_case, cr0);
   1802 }
   1803 
   1804 void MacroAssembler::JumpIfEitherSmi(Register reg1, Register reg2,
   1805                                      Label* on_either_smi) {
   1806   STATIC_ASSERT(kSmiTag == 0);
   1807   JumpIfSmi(reg1, on_either_smi);
   1808   JumpIfSmi(reg2, on_either_smi);
   1809 }
   1810 
   1811 void MacroAssembler::AssertNotSmi(Register object) {
   1812   if (emit_debug_code()) {
   1813     STATIC_ASSERT(kSmiTag == 0);
   1814     TestIfSmi(object, r0);
   1815     Check(ne, AbortReason::kOperandIsASmi, cr0);
   1816   }
   1817 }
   1818 
   1819 
   1820 void MacroAssembler::AssertSmi(Register object) {
   1821   if (emit_debug_code()) {
   1822     STATIC_ASSERT(kSmiTag == 0);
   1823     TestIfSmi(object, r0);
   1824     Check(eq, AbortReason::kOperandIsNotASmi, cr0);
   1825   }
   1826 }
   1827 
   1828 void MacroAssembler::AssertConstructor(Register object) {
   1829   if (emit_debug_code()) {
   1830     STATIC_ASSERT(kSmiTag == 0);
   1831     TestIfSmi(object, r0);
   1832     Check(ne, AbortReason::kOperandIsASmiAndNotAConstructor, cr0);
   1833     push(object);
   1834     LoadP(object, FieldMemOperand(object, HeapObject::kMapOffset));
   1835     lbz(object, FieldMemOperand(object, Map::kBitFieldOffset));
   1836     andi(object, object, Operand(Map::IsConstructorBit::kMask));
   1837     pop(object);
   1838     Check(ne, AbortReason::kOperandIsNotAConstructor, cr0);
   1839   }
   1840 }
   1841 
   1842 void MacroAssembler::AssertFunction(Register object) {
   1843   if (emit_debug_code()) {
   1844     STATIC_ASSERT(kSmiTag == 0);
   1845     TestIfSmi(object, r0);
   1846     Check(ne, AbortReason::kOperandIsASmiAndNotAFunction, cr0);
   1847     push(object);
   1848     CompareObjectType(object, object, object, JS_FUNCTION_TYPE);
   1849     pop(object);
   1850     Check(eq, AbortReason::kOperandIsNotAFunction);
   1851   }
   1852 }
   1853 
   1854 
   1855 void MacroAssembler::AssertBoundFunction(Register object) {
   1856   if (emit_debug_code()) {
   1857     STATIC_ASSERT(kSmiTag == 0);
   1858     TestIfSmi(object, r0);
   1859     Check(ne, AbortReason::kOperandIsASmiAndNotABoundFunction, cr0);
   1860     push(object);
   1861     CompareObjectType(object, object, object, JS_BOUND_FUNCTION_TYPE);
   1862     pop(object);
   1863     Check(eq, AbortReason::kOperandIsNotABoundFunction);
   1864   }
   1865 }
   1866 
   1867 void MacroAssembler::AssertGeneratorObject(Register object) {
   1868   if (!emit_debug_code()) return;
   1869   TestIfSmi(object, r0);
   1870   Check(ne, AbortReason::kOperandIsASmiAndNotAGeneratorObject, cr0);
   1871 
   1872   // Load map
   1873   Register map = object;
   1874   push(object);
   1875   LoadP(map, FieldMemOperand(object, HeapObject::kMapOffset));
   1876 
   1877   // Check if JSGeneratorObject
   1878   Label do_check;
   1879   Register instance_type = object;
   1880   CompareInstanceType(map, instance_type, JS_GENERATOR_OBJECT_TYPE);
   1881   beq(&do_check);
   1882 
   1883   // Check if JSAsyncGeneratorObject (See MacroAssembler::CompareInstanceType)
   1884   cmpi(instance_type, Operand(JS_ASYNC_GENERATOR_OBJECT_TYPE));
   1885 
   1886   bind(&do_check);
   1887   // Restore generator object to register and perform assertion
   1888   pop(object);
   1889   Check(eq, AbortReason::kOperandIsNotAGeneratorObject);
   1890 }
   1891 
   1892 void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
   1893                                                      Register scratch) {
   1894   if (emit_debug_code()) {
   1895     Label done_checking;
   1896     AssertNotSmi(object);
   1897     CompareRoot(object, Heap::kUndefinedValueRootIndex);
   1898     beq(&done_checking);
   1899     LoadP(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
   1900     CompareInstanceType(scratch, scratch, ALLOCATION_SITE_TYPE);
   1901     Assert(eq, AbortReason::kExpectedUndefinedOrCell);
   1902     bind(&done_checking);
   1903   }
   1904 }
   1905 
   1906 
   1907 static const int kRegisterPassedArguments = 8;
   1908 
   1909 int TurboAssembler::CalculateStackPassedWords(int num_reg_arguments,
   1910                                               int num_double_arguments) {
   1911   int stack_passed_words = 0;
   1912   if (num_double_arguments > DoubleRegister::kNumRegisters) {
   1913     stack_passed_words +=
   1914         2 * (num_double_arguments - DoubleRegister::kNumRegisters);
   1915   }
   1916   // Up to 8 simple arguments are passed in registers r3..r10.
   1917   if (num_reg_arguments > kRegisterPassedArguments) {
   1918     stack_passed_words += num_reg_arguments - kRegisterPassedArguments;
   1919   }
   1920   return stack_passed_words;
   1921 }
   1922 
   1923 void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
   1924                                           int num_double_arguments,
   1925                                           Register scratch) {
   1926   int frame_alignment = ActivationFrameAlignment();
   1927   int stack_passed_arguments =
   1928       CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
   1929   int stack_space = kNumRequiredStackFrameSlots;
   1930 
   1931   if (frame_alignment > kPointerSize) {
   1932     // Make stack end at alignment and make room for stack arguments
   1933     // -- preserving original value of sp.
   1934     mr(scratch, sp);
   1935     addi(sp, sp, Operand(-(stack_passed_arguments + 1) * kPointerSize));
   1936     DCHECK(base::bits::IsPowerOfTwo(frame_alignment));
   1937     ClearRightImm(sp, sp, Operand(WhichPowerOf2(frame_alignment)));
   1938     StoreP(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
   1939   } else {
   1940     // Make room for stack arguments
   1941     stack_space += stack_passed_arguments;
   1942   }
   1943 
   1944   // Allocate frame with required slots to make ABI work.
   1945   li(r0, Operand::Zero());
   1946   StorePU(r0, MemOperand(sp, -stack_space * kPointerSize));
   1947 }
   1948 
   1949 void TurboAssembler::PrepareCallCFunction(int num_reg_arguments,
   1950                                           Register scratch) {
   1951   PrepareCallCFunction(num_reg_arguments, 0, scratch);
   1952 }
   1953 
   1954 void TurboAssembler::MovToFloatParameter(DoubleRegister src) { Move(d1, src); }
   1955 
   1956 void TurboAssembler::MovToFloatResult(DoubleRegister src) { Move(d1, src); }
   1957 
   1958 void TurboAssembler::MovToFloatParameters(DoubleRegister src1,
   1959                                           DoubleRegister src2) {
   1960   if (src2 == d1) {
   1961     DCHECK(src1 != d2);
   1962     Move(d2, src2);
   1963     Move(d1, src1);
   1964   } else {
   1965     Move(d1, src1);
   1966     Move(d2, src2);
   1967   }
   1968 }
   1969 
   1970 void TurboAssembler::CallCFunction(ExternalReference function,
   1971                                    int num_reg_arguments,
   1972                                    int num_double_arguments) {
   1973   Move(ip, function);
   1974   CallCFunctionHelper(ip, num_reg_arguments, num_double_arguments);
   1975 }
   1976 
   1977 void TurboAssembler::CallCFunction(Register function, int num_reg_arguments,
   1978                                    int num_double_arguments) {
   1979   CallCFunctionHelper(function, num_reg_arguments, num_double_arguments);
   1980 }
   1981 
   1982 void TurboAssembler::CallCFunction(ExternalReference function,
   1983                                    int num_arguments) {
   1984   CallCFunction(function, num_arguments, 0);
   1985 }
   1986 
   1987 void TurboAssembler::CallCFunction(Register function, int num_arguments) {
   1988   CallCFunction(function, num_arguments, 0);
   1989 }
   1990 
   1991 void TurboAssembler::CallCFunctionHelper(Register function,
   1992                                          int num_reg_arguments,
   1993                                          int num_double_arguments) {
   1994   DCHECK_LE(num_reg_arguments + num_double_arguments, kMaxCParameters);
   1995   DCHECK(has_frame());
   1996 
   1997   // Just call directly. The function called cannot cause a GC, or
   1998   // allow preemption, so the return address in the link register
   1999   // stays correct.
   2000   Register dest = function;
   2001   if (ABI_USES_FUNCTION_DESCRIPTORS) {
   2002     // AIX/PPC64BE Linux uses a function descriptor. When calling C code be
   2003     // aware of this descriptor and pick up values from it
   2004     LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(function, kPointerSize));
   2005     LoadP(ip, MemOperand(function, 0));
   2006     dest = ip;
   2007   } else if (ABI_CALL_VIA_IP) {
   2008     Move(ip, function);
   2009     dest = ip;
   2010   }
   2011 
   2012   Call(dest);
   2013 
   2014   // Remove frame bought in PrepareCallCFunction
   2015   int stack_passed_arguments =
   2016       CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
   2017   int stack_space = kNumRequiredStackFrameSlots + stack_passed_arguments;
   2018   if (ActivationFrameAlignment() > kPointerSize) {
   2019     LoadP(sp, MemOperand(sp, stack_space * kPointerSize));
   2020   } else {
   2021     addi(sp, sp, Operand(stack_space * kPointerSize));
   2022   }
   2023 }
   2024 
   2025 
   2026 void TurboAssembler::CheckPageFlag(
   2027     Register object,
   2028     Register scratch,  // scratch may be same register as object
   2029     int mask, Condition cc, Label* condition_met) {
   2030   DCHECK(cc == ne || cc == eq);
   2031   ClearRightImm(scratch, object, Operand(kPageSizeBits));
   2032   LoadP(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
   2033 
   2034   mov(r0, Operand(mask));
   2035   and_(r0, scratch, r0, SetRC);
   2036 
   2037   if (cc == ne) {
   2038     bne(condition_met, cr0);
   2039   }
   2040   if (cc == eq) {
   2041     beq(condition_met, cr0);
   2042   }
   2043 }
   2044 
   2045 void TurboAssembler::SetRoundingMode(FPRoundingMode RN) { mtfsfi(7, RN); }
   2046 
   2047 void TurboAssembler::ResetRoundingMode() {
   2048   mtfsfi(7, kRoundToNearest);  // reset (default is kRoundToNearest)
   2049 }
   2050 
   2051 
   2052 ////////////////////////////////////////////////////////////////////////////////
   2053 //
   2054 // New MacroAssembler Interfaces added for PPC
   2055 //
   2056 ////////////////////////////////////////////////////////////////////////////////
   2057 void TurboAssembler::LoadIntLiteral(Register dst, int value) {
   2058   mov(dst, Operand(value));
   2059 }
   2060 
   2061 void TurboAssembler::LoadSmiLiteral(Register dst, Smi* smi) {
   2062   mov(dst, Operand(smi));
   2063 }
   2064 
   2065 void TurboAssembler::LoadDoubleLiteral(DoubleRegister result, Double value,
   2066                                        Register scratch) {
   2067   if (FLAG_enable_embedded_constant_pool && is_constant_pool_available() &&
   2068       !(scratch == r0 && ConstantPoolAccessIsInOverflow())) {
   2069     ConstantPoolEntry::Access access = ConstantPoolAddEntry(value);
   2070     if (access == ConstantPoolEntry::OVERFLOWED) {
   2071       addis(scratch, kConstantPoolRegister, Operand::Zero());
   2072       lfd(result, MemOperand(scratch, 0));
   2073     } else {
   2074       lfd(result, MemOperand(kConstantPoolRegister, 0));
   2075     }
   2076     return;
   2077   }
   2078 
   2079   // avoid gcc strict aliasing error using union cast
   2080   union {
   2081     uint64_t dval;
   2082 #if V8_TARGET_ARCH_PPC64
   2083     intptr_t ival;
   2084 #else
   2085     intptr_t ival[2];
   2086 #endif
   2087   } litVal;
   2088 
   2089   litVal.dval = value.AsUint64();
   2090 
   2091 #if V8_TARGET_ARCH_PPC64
   2092   if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
   2093     mov(scratch, Operand(litVal.ival));
   2094     mtfprd(result, scratch);
   2095     return;
   2096   }
   2097 #endif
   2098 
   2099   addi(sp, sp, Operand(-kDoubleSize));
   2100 #if V8_TARGET_ARCH_PPC64
   2101   mov(scratch, Operand(litVal.ival));
   2102   std(scratch, MemOperand(sp));
   2103 #else
   2104   LoadIntLiteral(scratch, litVal.ival[0]);
   2105   stw(scratch, MemOperand(sp, 0));
   2106   LoadIntLiteral(scratch, litVal.ival[1]);
   2107   stw(scratch, MemOperand(sp, 4));
   2108 #endif
   2109   nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
   2110   lfd(result, MemOperand(sp, 0));
   2111   addi(sp, sp, Operand(kDoubleSize));
   2112 }
   2113 
   2114 void TurboAssembler::MovIntToDouble(DoubleRegister dst, Register src,
   2115                                     Register scratch) {
   2116 // sign-extend src to 64-bit
   2117 #if V8_TARGET_ARCH_PPC64
   2118   if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
   2119     mtfprwa(dst, src);
   2120     return;
   2121   }
   2122 #endif
   2123 
   2124   DCHECK(src != scratch);
   2125   subi(sp, sp, Operand(kDoubleSize));
   2126 #if V8_TARGET_ARCH_PPC64
   2127   extsw(scratch, src);
   2128   std(scratch, MemOperand(sp, 0));
   2129 #else
   2130   srawi(scratch, src, 31);
   2131   stw(scratch, MemOperand(sp, Register::kExponentOffset));
   2132   stw(src, MemOperand(sp, Register::kMantissaOffset));
   2133 #endif
   2134   nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
   2135   lfd(dst, MemOperand(sp, 0));
   2136   addi(sp, sp, Operand(kDoubleSize));
   2137 }
   2138 
   2139 void TurboAssembler::MovUnsignedIntToDouble(DoubleRegister dst, Register src,
   2140                                             Register scratch) {
   2141 // zero-extend src to 64-bit
   2142 #if V8_TARGET_ARCH_PPC64
   2143   if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
   2144     mtfprwz(dst, src);
   2145     return;
   2146   }
   2147 #endif
   2148 
   2149   DCHECK(src != scratch);
   2150   subi(sp, sp, Operand(kDoubleSize));
   2151 #if V8_TARGET_ARCH_PPC64
   2152   clrldi(scratch, src, Operand(32));
   2153   std(scratch, MemOperand(sp, 0));
   2154 #else
   2155   li(scratch, Operand::Zero());
   2156   stw(scratch, MemOperand(sp, Register::kExponentOffset));
   2157   stw(src, MemOperand(sp, Register::kMantissaOffset));
   2158 #endif
   2159   nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
   2160   lfd(dst, MemOperand(sp, 0));
   2161   addi(sp, sp, Operand(kDoubleSize));
   2162 }
   2163 
   2164 void TurboAssembler::MovInt64ToDouble(DoubleRegister dst,
   2165 #if !V8_TARGET_ARCH_PPC64
   2166                                       Register src_hi,
   2167 #endif
   2168                                       Register src) {
   2169 #if V8_TARGET_ARCH_PPC64
   2170   if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
   2171     mtfprd(dst, src);
   2172     return;
   2173   }
   2174 #endif
   2175 
   2176   subi(sp, sp, Operand(kDoubleSize));
   2177 #if V8_TARGET_ARCH_PPC64
   2178   std(src, MemOperand(sp, 0));
   2179 #else
   2180   stw(src_hi, MemOperand(sp, Register::kExponentOffset));
   2181   stw(src, MemOperand(sp, Register::kMantissaOffset));
   2182 #endif
   2183   nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
   2184   lfd(dst, MemOperand(sp, 0));
   2185   addi(sp, sp, Operand(kDoubleSize));
   2186 }
   2187 
   2188 
   2189 #if V8_TARGET_ARCH_PPC64
   2190 void TurboAssembler::MovInt64ComponentsToDouble(DoubleRegister dst,
   2191                                                 Register src_hi,
   2192                                                 Register src_lo,
   2193                                                 Register scratch) {
   2194   if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
   2195     sldi(scratch, src_hi, Operand(32));
   2196     rldimi(scratch, src_lo, 0, 32);
   2197     mtfprd(dst, scratch);
   2198     return;
   2199   }
   2200 
   2201   subi(sp, sp, Operand(kDoubleSize));
   2202   stw(src_hi, MemOperand(sp, Register::kExponentOffset));
   2203   stw(src_lo, MemOperand(sp, Register::kMantissaOffset));
   2204   nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
   2205   lfd(dst, MemOperand(sp));
   2206   addi(sp, sp, Operand(kDoubleSize));
   2207 }
   2208 #endif
   2209 
   2210 void TurboAssembler::InsertDoubleLow(DoubleRegister dst, Register src,
   2211                                      Register scratch) {
   2212 #if V8_TARGET_ARCH_PPC64
   2213   if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
   2214     mffprd(scratch, dst);
   2215     rldimi(scratch, src, 0, 32);
   2216     mtfprd(dst, scratch);
   2217     return;
   2218   }
   2219 #endif
   2220 
   2221   subi(sp, sp, Operand(kDoubleSize));
   2222   stfd(dst, MemOperand(sp));
   2223   stw(src, MemOperand(sp, Register::kMantissaOffset));
   2224   nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
   2225   lfd(dst, MemOperand(sp));
   2226   addi(sp, sp, Operand(kDoubleSize));
   2227 }
   2228 
   2229 void TurboAssembler::InsertDoubleHigh(DoubleRegister dst, Register src,
   2230                                       Register scratch) {
   2231 #if V8_TARGET_ARCH_PPC64
   2232   if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
   2233     mffprd(scratch, dst);
   2234     rldimi(scratch, src, 32, 0);
   2235     mtfprd(dst, scratch);
   2236     return;
   2237   }
   2238 #endif
   2239 
   2240   subi(sp, sp, Operand(kDoubleSize));
   2241   stfd(dst, MemOperand(sp));
   2242   stw(src, MemOperand(sp, Register::kExponentOffset));
   2243   nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
   2244   lfd(dst, MemOperand(sp));
   2245   addi(sp, sp, Operand(kDoubleSize));
   2246 }
   2247 
   2248 void TurboAssembler::MovDoubleLowToInt(Register dst, DoubleRegister src) {
   2249 #if V8_TARGET_ARCH_PPC64
   2250   if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
   2251     mffprwz(dst, src);
   2252     return;
   2253   }
   2254 #endif
   2255 
   2256   subi(sp, sp, Operand(kDoubleSize));
   2257   stfd(src, MemOperand(sp));
   2258   nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
   2259   lwz(dst, MemOperand(sp, Register::kMantissaOffset));
   2260   addi(sp, sp, Operand(kDoubleSize));
   2261 }
   2262 
   2263 void TurboAssembler::MovDoubleHighToInt(Register dst, DoubleRegister src) {
   2264 #if V8_TARGET_ARCH_PPC64
   2265   if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
   2266     mffprd(dst, src);
   2267     srdi(dst, dst, Operand(32));
   2268     return;
   2269   }
   2270 #endif
   2271 
   2272   subi(sp, sp, Operand(kDoubleSize));
   2273   stfd(src, MemOperand(sp));
   2274   nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
   2275   lwz(dst, MemOperand(sp, Register::kExponentOffset));
   2276   addi(sp, sp, Operand(kDoubleSize));
   2277 }
   2278 
   2279 void TurboAssembler::MovDoubleToInt64(
   2280 #if !V8_TARGET_ARCH_PPC64
   2281     Register dst_hi,
   2282 #endif
   2283     Register dst, DoubleRegister src) {
   2284 #if V8_TARGET_ARCH_PPC64
   2285   if (CpuFeatures::IsSupported(FPR_GPR_MOV)) {
   2286     mffprd(dst, src);
   2287     return;
   2288   }
   2289 #endif
   2290 
   2291   subi(sp, sp, Operand(kDoubleSize));
   2292   stfd(src, MemOperand(sp));
   2293   nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
   2294 #if V8_TARGET_ARCH_PPC64
   2295   ld(dst, MemOperand(sp, 0));
   2296 #else
   2297   lwz(dst_hi, MemOperand(sp, Register::kExponentOffset));
   2298   lwz(dst, MemOperand(sp, Register::kMantissaOffset));
   2299 #endif
   2300   addi(sp, sp, Operand(kDoubleSize));
   2301 }
   2302 
   2303 void TurboAssembler::MovIntToFloat(DoubleRegister dst, Register src) {
   2304   subi(sp, sp, Operand(kFloatSize));
   2305   stw(src, MemOperand(sp, 0));
   2306   nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
   2307   lfs(dst, MemOperand(sp, 0));
   2308   addi(sp, sp, Operand(kFloatSize));
   2309 }
   2310 
   2311 void TurboAssembler::MovFloatToInt(Register dst, DoubleRegister src) {
   2312   subi(sp, sp, Operand(kFloatSize));
   2313   stfs(src, MemOperand(sp, 0));
   2314   nop(GROUP_ENDING_NOP);  // LHS/RAW optimization
   2315   lwz(dst, MemOperand(sp, 0));
   2316   addi(sp, sp, Operand(kFloatSize));
   2317 }
   2318 
   2319 void TurboAssembler::Add(Register dst, Register src, intptr_t value,
   2320                          Register scratch) {
   2321   if (is_int16(value)) {
   2322     addi(dst, src, Operand(value));
   2323   } else {
   2324     mov(scratch, Operand(value));
   2325     add(dst, src, scratch);
   2326   }
   2327 }
   2328 
   2329 
   2330 void TurboAssembler::Cmpi(Register src1, const Operand& src2, Register scratch,
   2331                           CRegister cr) {
   2332   intptr_t value = src2.immediate();
   2333   if (is_int16(value)) {
   2334     cmpi(src1, src2, cr);
   2335   } else {
   2336     mov(scratch, src2);
   2337     cmp(src1, scratch, cr);
   2338   }
   2339 }
   2340 
   2341 void TurboAssembler::Cmpli(Register src1, const Operand& src2, Register scratch,
   2342                            CRegister cr) {
   2343   intptr_t value = src2.immediate();
   2344   if (is_uint16(value)) {
   2345     cmpli(src1, src2, cr);
   2346   } else {
   2347     mov(scratch, src2);
   2348     cmpl(src1, scratch, cr);
   2349   }
   2350 }
   2351 
   2352 void TurboAssembler::Cmpwi(Register src1, const Operand& src2, Register scratch,
   2353                            CRegister cr) {
   2354   intptr_t value = src2.immediate();
   2355   if (is_int16(value)) {
   2356     cmpwi(src1, src2, cr);
   2357   } else {
   2358     mov(scratch, src2);
   2359     cmpw(src1, scratch, cr);
   2360   }
   2361 }
   2362 
   2363 
   2364 void MacroAssembler::Cmplwi(Register src1, const Operand& src2,
   2365                             Register scratch, CRegister cr) {
   2366   intptr_t value = src2.immediate();
   2367   if (is_uint16(value)) {
   2368     cmplwi(src1, src2, cr);
   2369   } else {
   2370     mov(scratch, src2);
   2371     cmplw(src1, scratch, cr);
   2372   }
   2373 }
   2374 
   2375 
   2376 void MacroAssembler::And(Register ra, Register rs, const Operand& rb,
   2377                          RCBit rc) {
   2378   if (rb.is_reg()) {
   2379     and_(ra, rs, rb.rm(), rc);
   2380   } else {
   2381     if (is_uint16(rb.immediate()) && RelocInfo::IsNone(rb.rmode_) &&
   2382         rc == SetRC) {
   2383       andi(ra, rs, rb);
   2384     } else {
   2385       // mov handles the relocation.
   2386       DCHECK(rs != r0);
   2387       mov(r0, rb);
   2388       and_(ra, rs, r0, rc);
   2389     }
   2390   }
   2391 }
   2392 
   2393 
   2394 void MacroAssembler::Or(Register ra, Register rs, const Operand& rb, RCBit rc) {
   2395   if (rb.is_reg()) {
   2396     orx(ra, rs, rb.rm(), rc);
   2397   } else {
   2398     if (is_uint16(rb.immediate()) && RelocInfo::IsNone(rb.rmode_) &&
   2399         rc == LeaveRC) {
   2400       ori(ra, rs, rb);
   2401     } else {
   2402       // mov handles the relocation.
   2403       DCHECK(rs != r0);
   2404       mov(r0, rb);
   2405       orx(ra, rs, r0, rc);
   2406     }
   2407   }
   2408 }
   2409 
   2410 
   2411 void MacroAssembler::Xor(Register ra, Register rs, const Operand& rb,
   2412                          RCBit rc) {
   2413   if (rb.is_reg()) {
   2414     xor_(ra, rs, rb.rm(), rc);
   2415   } else {
   2416     if (is_uint16(rb.immediate()) && RelocInfo::IsNone(rb.rmode_) &&
   2417         rc == LeaveRC) {
   2418       xori(ra, rs, rb);
   2419     } else {
   2420       // mov handles the relocation.
   2421       DCHECK(rs != r0);
   2422       mov(r0, rb);
   2423       xor_(ra, rs, r0, rc);
   2424     }
   2425   }
   2426 }
   2427 
   2428 
   2429 void MacroAssembler::CmpSmiLiteral(Register src1, Smi* smi, Register scratch,
   2430                                    CRegister cr) {
   2431 #if V8_TARGET_ARCH_PPC64
   2432   LoadSmiLiteral(scratch, smi);
   2433   cmp(src1, scratch, cr);
   2434 #else
   2435   Cmpi(src1, Operand(smi), scratch, cr);
   2436 #endif
   2437 }
   2438 
   2439 
   2440 void MacroAssembler::CmplSmiLiteral(Register src1, Smi* smi, Register scratch,
   2441                                     CRegister cr) {
   2442 #if V8_TARGET_ARCH_PPC64
   2443   LoadSmiLiteral(scratch, smi);
   2444   cmpl(src1, scratch, cr);
   2445 #else
   2446   Cmpli(src1, Operand(smi), scratch, cr);
   2447 #endif
   2448 }
   2449 
   2450 
   2451 void MacroAssembler::AddSmiLiteral(Register dst, Register src, Smi* smi,
   2452                                    Register scratch) {
   2453 #if V8_TARGET_ARCH_PPC64
   2454   LoadSmiLiteral(scratch, smi);
   2455   add(dst, src, scratch);
   2456 #else
   2457   Add(dst, src, reinterpret_cast<intptr_t>(smi), scratch);
   2458 #endif
   2459 }
   2460 
   2461 
   2462 void MacroAssembler::SubSmiLiteral(Register dst, Register src, Smi* smi,
   2463                                    Register scratch) {
   2464 #if V8_TARGET_ARCH_PPC64
   2465   LoadSmiLiteral(scratch, smi);
   2466   sub(dst, src, scratch);
   2467 #else
   2468   Add(dst, src, -(reinterpret_cast<intptr_t>(smi)), scratch);
   2469 #endif
   2470 }
   2471 
   2472 
   2473 void MacroAssembler::AndSmiLiteral(Register dst, Register src, Smi* smi,
   2474                                    Register scratch, RCBit rc) {
   2475 #if V8_TARGET_ARCH_PPC64
   2476   LoadSmiLiteral(scratch, smi);
   2477   and_(dst, src, scratch, rc);
   2478 #else
   2479   And(dst, src, Operand(smi), rc);
   2480 #endif
   2481 }
   2482 
   2483 
   2484 // Load a "pointer" sized value from the memory location
   2485 void TurboAssembler::LoadP(Register dst, const MemOperand& mem,
   2486                            Register scratch) {
   2487   DCHECK_EQ(mem.rb(), no_reg);
   2488   int offset = mem.offset();
   2489 
   2490   if (!is_int16(offset)) {
   2491     /* cannot use d-form */
   2492     DCHECK_NE(scratch, no_reg);
   2493     mov(scratch, Operand(offset));
   2494     LoadPX(dst, MemOperand(mem.ra(), scratch));
   2495   } else {
   2496 #if V8_TARGET_ARCH_PPC64
   2497     int misaligned = (offset & 3);
   2498     if (misaligned) {
   2499       // adjust base to conform to offset alignment requirements
   2500       // Todo: enhance to use scratch if dst is unsuitable
   2501       DCHECK(dst != r0);
   2502       addi(dst, mem.ra(), Operand((offset & 3) - 4));
   2503       ld(dst, MemOperand(dst, (offset & ~3) + 4));
   2504     } else {
   2505       ld(dst, mem);
   2506     }
   2507 #else
   2508     lwz(dst, mem);
   2509 #endif
   2510   }
   2511 }
   2512 
   2513 void TurboAssembler::LoadPU(Register dst, const MemOperand& mem,
   2514                             Register scratch) {
   2515   int offset = mem.offset();
   2516 
   2517   if (!is_int16(offset)) {
   2518     /* cannot use d-form */
   2519     DCHECK(scratch != no_reg);
   2520     mov(scratch, Operand(offset));
   2521     LoadPUX(dst, MemOperand(mem.ra(), scratch));
   2522   } else {
   2523 #if V8_TARGET_ARCH_PPC64
   2524     ldu(dst, mem);
   2525 #else
   2526     lwzu(dst, mem);
   2527 #endif
   2528   }
   2529 }
   2530 
   2531 // Store a "pointer" sized value to the memory location
   2532 void TurboAssembler::StoreP(Register src, const MemOperand& mem,
   2533                             Register scratch) {
   2534   int offset = mem.offset();
   2535 
   2536   if (!is_int16(offset)) {
   2537     /* cannot use d-form */
   2538     DCHECK(scratch != no_reg);
   2539     mov(scratch, Operand(offset));
   2540     StorePX(src, MemOperand(mem.ra(), scratch));
   2541   } else {
   2542 #if V8_TARGET_ARCH_PPC64
   2543     int misaligned = (offset & 3);
   2544     if (misaligned) {
   2545       // adjust base to conform to offset alignment requirements
   2546       // a suitable scratch is required here
   2547       DCHECK(scratch != no_reg);
   2548       if (scratch == r0) {
   2549         LoadIntLiteral(scratch, offset);
   2550         stdx(src, MemOperand(mem.ra(), scratch));
   2551       } else {
   2552         addi(scratch, mem.ra(), Operand((offset & 3) - 4));
   2553         std(src, MemOperand(scratch, (offset & ~3) + 4));
   2554       }
   2555     } else {
   2556       std(src, mem);
   2557     }
   2558 #else
   2559     stw(src, mem);
   2560 #endif
   2561   }
   2562 }
   2563 
   2564 void TurboAssembler::StorePU(Register src, const MemOperand& mem,
   2565                              Register scratch) {
   2566   int offset = mem.offset();
   2567 
   2568   if (!is_int16(offset)) {
   2569     /* cannot use d-form */
   2570     DCHECK(scratch != no_reg);
   2571     mov(scratch, Operand(offset));
   2572     StorePUX(src, MemOperand(mem.ra(), scratch));
   2573   } else {
   2574 #if V8_TARGET_ARCH_PPC64
   2575     stdu(src, mem);
   2576 #else
   2577     stwu(src, mem);
   2578 #endif
   2579   }
   2580 }
   2581 
   2582 void TurboAssembler::LoadWordArith(Register dst, const MemOperand& mem,
   2583                                    Register scratch) {
   2584   int offset = mem.offset();
   2585 
   2586   if (!is_int16(offset)) {
   2587     DCHECK(scratch != no_reg);
   2588     mov(scratch, Operand(offset));
   2589     lwax(dst, MemOperand(mem.ra(), scratch));
   2590   } else {
   2591 #if V8_TARGET_ARCH_PPC64
   2592     int misaligned = (offset & 3);
   2593     if (misaligned) {
   2594       // adjust base to conform to offset alignment requirements
   2595       // Todo: enhance to use scratch if dst is unsuitable
   2596       DCHECK(dst != r0);
   2597       addi(dst, mem.ra(), Operand((offset & 3) - 4));
   2598       lwa(dst, MemOperand(dst, (offset & ~3) + 4));
   2599     } else {
   2600       lwa(dst, mem);
   2601     }
   2602 #else
   2603     lwz(dst, mem);
   2604 #endif
   2605   }
   2606 }
   2607 
   2608 
   2609 // Variable length depending on whether offset fits into immediate field
   2610 // MemOperand currently only supports d-form
   2611 void MacroAssembler::LoadWord(Register dst, const MemOperand& mem,
   2612                               Register scratch) {
   2613   Register base = mem.ra();
   2614   int offset = mem.offset();
   2615 
   2616   if (!is_int16(offset)) {
   2617     LoadIntLiteral(scratch, offset);
   2618     lwzx(dst, MemOperand(base, scratch));
   2619   } else {
   2620     lwz(dst, mem);
   2621   }
   2622 }
   2623 
   2624 
   2625 // Variable length depending on whether offset fits into immediate field
   2626 // MemOperand current only supports d-form
   2627 void MacroAssembler::StoreWord(Register src, const MemOperand& mem,
   2628                                Register scratch) {
   2629   Register base = mem.ra();
   2630   int offset = mem.offset();
   2631 
   2632   if (!is_int16(offset)) {
   2633     LoadIntLiteral(scratch, offset);
   2634     stwx(src, MemOperand(base, scratch));
   2635   } else {
   2636     stw(src, mem);
   2637   }
   2638 }
   2639 
   2640 
   2641 void MacroAssembler::LoadHalfWordArith(Register dst, const MemOperand& mem,
   2642                                        Register scratch) {
   2643   int offset = mem.offset();
   2644 
   2645   if (!is_int16(offset)) {
   2646     DCHECK(scratch != no_reg);
   2647     mov(scratch, Operand(offset));
   2648     lhax(dst, MemOperand(mem.ra(), scratch));
   2649   } else {
   2650     lha(dst, mem);
   2651   }
   2652 }
   2653 
   2654 
   2655 // Variable length depending on whether offset fits into immediate field
   2656 // MemOperand currently only supports d-form
   2657 void MacroAssembler::LoadHalfWord(Register dst, const MemOperand& mem,
   2658                                   Register scratch) {
   2659   Register base = mem.ra();
   2660   int offset = mem.offset();
   2661 
   2662   if (!is_int16(offset)) {
   2663     DCHECK_NE(scratch, no_reg);
   2664     LoadIntLiteral(scratch, offset);
   2665     lhzx(dst, MemOperand(base, scratch));
   2666   } else {
   2667     lhz(dst, mem);
   2668   }
   2669 }
   2670 
   2671 
   2672 // Variable length depending on whether offset fits into immediate field
   2673 // MemOperand current only supports d-form
   2674 void MacroAssembler::StoreHalfWord(Register src, const MemOperand& mem,
   2675                                    Register scratch) {
   2676   Register base = mem.ra();
   2677   int offset = mem.offset();
   2678 
   2679   if (!is_int16(offset)) {
   2680     LoadIntLiteral(scratch, offset);
   2681     sthx(src, MemOperand(base, scratch));
   2682   } else {
   2683     sth(src, mem);
   2684   }
   2685 }
   2686 
   2687 
   2688 // Variable length depending on whether offset fits into immediate field
   2689 // MemOperand currently only supports d-form
   2690 void MacroAssembler::LoadByte(Register dst, const MemOperand& mem,
   2691                               Register scratch) {
   2692   Register base = mem.ra();
   2693   int offset = mem.offset();
   2694 
   2695   if (!is_int16(offset)) {
   2696     LoadIntLiteral(scratch, offset);
   2697     lbzx(dst, MemOperand(base, scratch));
   2698   } else {
   2699     lbz(dst, mem);
   2700   }
   2701 }
   2702 
   2703 
   2704 // Variable length depending on whether offset fits into immediate field
   2705 // MemOperand current only supports d-form
   2706 void MacroAssembler::StoreByte(Register src, const MemOperand& mem,
   2707                                Register scratch) {
   2708   Register base = mem.ra();
   2709   int offset = mem.offset();
   2710 
   2711   if (!is_int16(offset)) {
   2712     LoadIntLiteral(scratch, offset);
   2713     stbx(src, MemOperand(base, scratch));
   2714   } else {
   2715     stb(src, mem);
   2716   }
   2717 }
   2718 
   2719 
   2720 void MacroAssembler::LoadRepresentation(Register dst, const MemOperand& mem,
   2721                                         Representation r, Register scratch) {
   2722   DCHECK(!r.IsDouble());
   2723   if (r.IsInteger8()) {
   2724     LoadByte(dst, mem, scratch);
   2725     extsb(dst, dst);
   2726   } else if (r.IsUInteger8()) {
   2727     LoadByte(dst, mem, scratch);
   2728   } else if (r.IsInteger16()) {
   2729     LoadHalfWordArith(dst, mem, scratch);
   2730   } else if (r.IsUInteger16()) {
   2731     LoadHalfWord(dst, mem, scratch);
   2732 #if V8_TARGET_ARCH_PPC64
   2733   } else if (r.IsInteger32()) {
   2734     LoadWordArith(dst, mem, scratch);
   2735 #endif
   2736   } else {
   2737     LoadP(dst, mem, scratch);
   2738   }
   2739 }
   2740 
   2741 
   2742 void MacroAssembler::StoreRepresentation(Register src, const MemOperand& mem,
   2743                                          Representation r, Register scratch) {
   2744   DCHECK(!r.IsDouble());
   2745   if (r.IsInteger8() || r.IsUInteger8()) {
   2746     StoreByte(src, mem, scratch);
   2747   } else if (r.IsInteger16() || r.IsUInteger16()) {
   2748     StoreHalfWord(src, mem, scratch);
   2749 #if V8_TARGET_ARCH_PPC64
   2750   } else if (r.IsInteger32()) {
   2751     StoreWord(src, mem, scratch);
   2752 #endif
   2753   } else {
   2754     if (r.IsHeapObject()) {
   2755       AssertNotSmi(src);
   2756     } else if (r.IsSmi()) {
   2757       AssertSmi(src);
   2758     }
   2759     StoreP(src, mem, scratch);
   2760   }
   2761 }
   2762 
   2763 void TurboAssembler::LoadDouble(DoubleRegister dst, const MemOperand& mem,
   2764                                 Register scratch) {
   2765   Register base = mem.ra();
   2766   int offset = mem.offset();
   2767 
   2768   if (!is_int16(offset)) {
   2769     mov(scratch, Operand(offset));
   2770     lfdx(dst, MemOperand(base, scratch));
   2771   } else {
   2772     lfd(dst, mem);
   2773   }
   2774 }
   2775 
   2776 void MacroAssembler::LoadDoubleU(DoubleRegister dst, const MemOperand& mem,
   2777                                 Register scratch) {
   2778   Register base = mem.ra();
   2779   int offset = mem.offset();
   2780 
   2781   if (!is_int16(offset)) {
   2782     mov(scratch, Operand(offset));
   2783     lfdux(dst, MemOperand(base, scratch));
   2784   } else {
   2785     lfdu(dst, mem);
   2786   }
   2787 }
   2788 
   2789 void TurboAssembler::LoadSingle(DoubleRegister dst, const MemOperand& mem,
   2790                                 Register scratch) {
   2791   Register base = mem.ra();
   2792   int offset = mem.offset();
   2793 
   2794   if (!is_int16(offset)) {
   2795     mov(scratch, Operand(offset));
   2796     lfsx(dst, MemOperand(base, scratch));
   2797   } else {
   2798     lfs(dst, mem);
   2799   }
   2800 }
   2801 
   2802 void TurboAssembler::LoadSingleU(DoubleRegister dst, const MemOperand& mem,
   2803                                  Register scratch) {
   2804   Register base = mem.ra();
   2805   int offset = mem.offset();
   2806 
   2807   if (!is_int16(offset)) {
   2808     mov(scratch, Operand(offset));
   2809     lfsux(dst, MemOperand(base, scratch));
   2810   } else {
   2811     lfsu(dst, mem);
   2812   }
   2813 }
   2814 
   2815 void TurboAssembler::StoreDouble(DoubleRegister src, const MemOperand& mem,
   2816                                  Register scratch) {
   2817   Register base = mem.ra();
   2818   int offset = mem.offset();
   2819 
   2820   if (!is_int16(offset)) {
   2821     mov(scratch, Operand(offset));
   2822     stfdx(src, MemOperand(base, scratch));
   2823   } else {
   2824     stfd(src, mem);
   2825   }
   2826 }
   2827 
   2828 void TurboAssembler::StoreDoubleU(DoubleRegister src, const MemOperand& mem,
   2829                                   Register scratch) {
   2830   Register base = mem.ra();
   2831   int offset = mem.offset();
   2832 
   2833   if (!is_int16(offset)) {
   2834     mov(scratch, Operand(offset));
   2835     stfdux(src, MemOperand(base, scratch));
   2836   } else {
   2837     stfdu(src, mem);
   2838   }
   2839 }
   2840 
   2841 void TurboAssembler::StoreSingle(DoubleRegister src, const MemOperand& mem,
   2842                                  Register scratch) {
   2843   Register base = mem.ra();
   2844   int offset = mem.offset();
   2845 
   2846   if (!is_int16(offset)) {
   2847     mov(scratch, Operand(offset));
   2848     stfsx(src, MemOperand(base, scratch));
   2849   } else {
   2850     stfs(src, mem);
   2851   }
   2852 }
   2853 
   2854 void TurboAssembler::StoreSingleU(DoubleRegister src, const MemOperand& mem,
   2855                                   Register scratch) {
   2856   Register base = mem.ra();
   2857   int offset = mem.offset();
   2858 
   2859   if (!is_int16(offset)) {
   2860     mov(scratch, Operand(offset));
   2861     stfsux(src, MemOperand(base, scratch));
   2862   } else {
   2863     stfsu(src, mem);
   2864   }
   2865 }
   2866 
   2867 Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2, Register reg3,
   2868                                    Register reg4, Register reg5,
   2869                                    Register reg6) {
   2870   RegList regs = 0;
   2871   if (reg1.is_valid()) regs |= reg1.bit();
   2872   if (reg2.is_valid()) regs |= reg2.bit();
   2873   if (reg3.is_valid()) regs |= reg3.bit();
   2874   if (reg4.is_valid()) regs |= reg4.bit();
   2875   if (reg5.is_valid()) regs |= reg5.bit();
   2876   if (reg6.is_valid()) regs |= reg6.bit();
   2877 
   2878   const RegisterConfiguration* config = RegisterConfiguration::Default();
   2879   for (int i = 0; i < config->num_allocatable_general_registers(); ++i) {
   2880     int code = config->GetAllocatableGeneralCode(i);
   2881     Register candidate = Register::from_code(code);
   2882     if (regs & candidate.bit()) continue;
   2883     return candidate;
   2884   }
   2885   UNREACHABLE();
   2886 }
   2887 
   2888 void TurboAssembler::SwapP(Register src, Register dst, Register scratch) {
   2889   if (src == dst) return;
   2890   DCHECK(!AreAliased(src, dst, scratch));
   2891   mr(scratch, src);
   2892   mr(src, dst);
   2893   mr(dst, scratch);
   2894 }
   2895 
   2896 void TurboAssembler::SwapP(Register src, MemOperand dst, Register scratch) {
   2897   if (dst.ra() != r0 && dst.ra().is_valid())
   2898     DCHECK(!AreAliased(src, dst.ra(), scratch));
   2899   if (dst.rb() != r0 && dst.rb().is_valid())
   2900     DCHECK(!AreAliased(src, dst.rb(), scratch));
   2901   DCHECK(!AreAliased(src, scratch));
   2902   mr(scratch, src);
   2903   LoadP(src, dst, r0);
   2904   StoreP(scratch, dst, r0);
   2905 }
   2906 
   2907 void TurboAssembler::SwapP(MemOperand src, MemOperand dst, Register scratch_0,
   2908                            Register scratch_1) {
   2909   if (src.ra() != r0 && src.ra().is_valid())
   2910     DCHECK(!AreAliased(src.ra(), scratch_0, scratch_1));
   2911   if (src.rb() != r0 && src.rb().is_valid())
   2912     DCHECK(!AreAliased(src.rb(), scratch_0, scratch_1));
   2913   if (dst.ra() != r0 && dst.ra().is_valid())
   2914     DCHECK(!AreAliased(dst.ra(), scratch_0, scratch_1));
   2915   if (dst.rb() != r0 && dst.rb().is_valid())
   2916     DCHECK(!AreAliased(dst.rb(), scratch_0, scratch_1));
   2917   DCHECK(!AreAliased(scratch_0, scratch_1));
   2918   if (is_int16(src.offset()) || is_int16(dst.offset())) {
   2919     if (!is_int16(src.offset())) {
   2920       // swap operand
   2921       MemOperand temp = src;
   2922       src = dst;
   2923       dst = temp;
   2924     }
   2925     LoadP(scratch_1, dst, scratch_0);
   2926     LoadP(scratch_0, src);
   2927     StoreP(scratch_1, src);
   2928     StoreP(scratch_0, dst, scratch_1);
   2929   } else {
   2930     LoadP(scratch_1, dst, scratch_0);
   2931     push(scratch_1);
   2932     LoadP(scratch_0, src, scratch_1);
   2933     StoreP(scratch_0, dst, scratch_1);
   2934     pop(scratch_1);
   2935     StoreP(scratch_1, src, scratch_0);
   2936   }
   2937 }
   2938 
   2939 void TurboAssembler::SwapFloat32(DoubleRegister src, DoubleRegister dst,
   2940                                  DoubleRegister scratch) {
   2941   if (src == dst) return;
   2942   DCHECK(!AreAliased(src, dst, scratch));
   2943   fmr(scratch, src);
   2944   fmr(src, dst);
   2945   fmr(dst, scratch);
   2946 }
   2947 
   2948 void TurboAssembler::SwapFloat32(DoubleRegister src, MemOperand dst,
   2949                                  DoubleRegister scratch) {
   2950   DCHECK(!AreAliased(src, scratch));
   2951   fmr(scratch, src);
   2952   LoadSingle(src, dst, r0);
   2953   StoreSingle(scratch, dst, r0);
   2954 }
   2955 
   2956 void TurboAssembler::SwapFloat32(MemOperand src, MemOperand dst,
   2957                                  DoubleRegister scratch_0,
   2958                                  DoubleRegister scratch_1) {
   2959   DCHECK(!AreAliased(scratch_0, scratch_1));
   2960   LoadSingle(scratch_0, src, r0);
   2961   LoadSingle(scratch_1, dst, r0);
   2962   StoreSingle(scratch_0, dst, r0);
   2963   StoreSingle(scratch_1, src, r0);
   2964 }
   2965 
   2966 void TurboAssembler::SwapDouble(DoubleRegister src, DoubleRegister dst,
   2967                                 DoubleRegister scratch) {
   2968   if (src == dst) return;
   2969   DCHECK(!AreAliased(src, dst, scratch));
   2970   fmr(scratch, src);
   2971   fmr(src, dst);
   2972   fmr(dst, scratch);
   2973 }
   2974 
   2975 void TurboAssembler::SwapDouble(DoubleRegister src, MemOperand dst,
   2976                                 DoubleRegister scratch) {
   2977   DCHECK(!AreAliased(src, scratch));
   2978   fmr(scratch, src);
   2979   LoadDouble(src, dst, r0);
   2980   StoreDouble(scratch, dst, r0);
   2981 }
   2982 
   2983 void TurboAssembler::SwapDouble(MemOperand src, MemOperand dst,
   2984                                 DoubleRegister scratch_0,
   2985                                 DoubleRegister scratch_1) {
   2986   DCHECK(!AreAliased(scratch_0, scratch_1));
   2987   LoadDouble(scratch_0, src, r0);
   2988   LoadDouble(scratch_1, dst, r0);
   2989   StoreDouble(scratch_0, dst, r0);
   2990   StoreDouble(scratch_1, src, r0);
   2991 }
   2992 
   2993 void TurboAssembler::ResetSpeculationPoisonRegister() {
   2994   mov(kSpeculationPoisonRegister, Operand(-1));
   2995 }
   2996 
   2997 void TurboAssembler::JumpIfEqual(Register x, int32_t y, Label* dest) {
   2998   Cmpi(x, Operand(y), r0);
   2999   beq(dest);
   3000 }
   3001 
   3002 void TurboAssembler::JumpIfLessThan(Register x, int32_t y, Label* dest) {
   3003   Cmpi(x, Operand(y), r0);
   3004   blt(dest);
   3005 }
   3006 
   3007 }  // namespace internal
   3008 }  // namespace v8
   3009 
   3010 #endif  // V8_TARGET_ARCH_PPC
   3011