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 "src/compiler/code-generator.h"
      6 
      7 #include "src/ast/scopes.h"
      8 #include "src/compiler/code-generator-impl.h"
      9 #include "src/compiler/gap-resolver.h"
     10 #include "src/compiler/node-matchers.h"
     11 #include "src/compiler/osr.h"
     12 #include "src/ppc/macro-assembler-ppc.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 namespace compiler {
     17 
     18 #define __ masm()->
     19 
     20 
     21 #define kScratchReg r11
     22 
     23 
     24 // Adds PPC-specific methods to convert InstructionOperands.
     25 class PPCOperandConverter final : public InstructionOperandConverter {
     26  public:
     27   PPCOperandConverter(CodeGenerator* gen, Instruction* instr)
     28       : InstructionOperandConverter(gen, instr) {}
     29 
     30   size_t OutputCount() { return instr_->OutputCount(); }
     31 
     32   RCBit OutputRCBit() const {
     33     switch (instr_->flags_mode()) {
     34       case kFlags_branch:
     35       case kFlags_set:
     36         return SetRC;
     37       case kFlags_none:
     38         return LeaveRC;
     39     }
     40     UNREACHABLE();
     41     return LeaveRC;
     42   }
     43 
     44   bool CompareLogical() const {
     45     switch (instr_->flags_condition()) {
     46       case kUnsignedLessThan:
     47       case kUnsignedGreaterThanOrEqual:
     48       case kUnsignedLessThanOrEqual:
     49       case kUnsignedGreaterThan:
     50         return true;
     51       default:
     52         return false;
     53     }
     54     UNREACHABLE();
     55     return false;
     56   }
     57 
     58   Operand InputImmediate(size_t index) {
     59     Constant constant = ToConstant(instr_->InputAt(index));
     60     switch (constant.type()) {
     61       case Constant::kInt32:
     62         return Operand(constant.ToInt32());
     63       case Constant::kFloat32:
     64         return Operand(
     65             isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
     66       case Constant::kFloat64:
     67         return Operand(
     68             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
     69       case Constant::kInt64:
     70 #if V8_TARGET_ARCH_PPC64
     71         return Operand(constant.ToInt64());
     72 #endif
     73       case Constant::kExternalReference:
     74       case Constant::kHeapObject:
     75       case Constant::kRpoNumber:
     76         break;
     77     }
     78     UNREACHABLE();
     79     return Operand::Zero();
     80   }
     81 
     82   MemOperand MemoryOperand(AddressingMode* mode, size_t* first_index) {
     83     const size_t index = *first_index;
     84     *mode = AddressingModeField::decode(instr_->opcode());
     85     switch (*mode) {
     86       case kMode_None:
     87         break;
     88       case kMode_MRI:
     89         *first_index += 2;
     90         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
     91       case kMode_MRR:
     92         *first_index += 2;
     93         return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
     94     }
     95     UNREACHABLE();
     96     return MemOperand(r0);
     97   }
     98 
     99   MemOperand MemoryOperand(AddressingMode* mode, size_t first_index = 0) {
    100     return MemoryOperand(mode, &first_index);
    101   }
    102 
    103   MemOperand ToMemOperand(InstructionOperand* op) const {
    104     DCHECK_NOT_NULL(op);
    105     DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
    106     FrameOffset offset = frame_access_state()->GetFrameOffset(
    107         AllocatedOperand::cast(op)->index());
    108     return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
    109   }
    110 };
    111 
    112 
    113 static inline bool HasRegisterInput(Instruction* instr, size_t index) {
    114   return instr->InputAt(index)->IsRegister();
    115 }
    116 
    117 
    118 namespace {
    119 
    120 class OutOfLineLoadNAN32 final : public OutOfLineCode {
    121  public:
    122   OutOfLineLoadNAN32(CodeGenerator* gen, DoubleRegister result)
    123       : OutOfLineCode(gen), result_(result) {}
    124 
    125   void Generate() final {
    126     __ LoadDoubleLiteral(result_, std::numeric_limits<float>::quiet_NaN(),
    127                          kScratchReg);
    128   }
    129 
    130  private:
    131   DoubleRegister const result_;
    132 };
    133 
    134 
    135 class OutOfLineLoadNAN64 final : public OutOfLineCode {
    136  public:
    137   OutOfLineLoadNAN64(CodeGenerator* gen, DoubleRegister result)
    138       : OutOfLineCode(gen), result_(result) {}
    139 
    140   void Generate() final {
    141     __ LoadDoubleLiteral(result_, std::numeric_limits<double>::quiet_NaN(),
    142                          kScratchReg);
    143   }
    144 
    145  private:
    146   DoubleRegister const result_;
    147 };
    148 
    149 
    150 class OutOfLineLoadZero final : public OutOfLineCode {
    151  public:
    152   OutOfLineLoadZero(CodeGenerator* gen, Register result)
    153       : OutOfLineCode(gen), result_(result) {}
    154 
    155   void Generate() final { __ li(result_, Operand::Zero()); }
    156 
    157  private:
    158   Register const result_;
    159 };
    160 
    161 
    162 class OutOfLineRecordWrite final : public OutOfLineCode {
    163  public:
    164   OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register offset,
    165                        Register value, Register scratch0, Register scratch1,
    166                        RecordWriteMode mode)
    167       : OutOfLineCode(gen),
    168         object_(object),
    169         offset_(offset),
    170         value_(value),
    171         scratch0_(scratch0),
    172         scratch1_(scratch1),
    173         mode_(mode) {}
    174 
    175   void Generate() final {
    176     if (mode_ > RecordWriteMode::kValueIsPointer) {
    177       __ JumpIfSmi(value_, exit());
    178     }
    179     if (mode_ > RecordWriteMode::kValueIsMap) {
    180       __ CheckPageFlag(value_, scratch0_,
    181                        MemoryChunk::kPointersToHereAreInterestingMask, eq,
    182                        exit());
    183     }
    184     SaveFPRegsMode const save_fp_mode =
    185         frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
    186     // TODO(turbofan): Once we get frame elision working, we need to save
    187     // and restore lr properly here if the frame was elided.
    188     RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
    189                          EMIT_REMEMBERED_SET, save_fp_mode);
    190     __ add(scratch1_, object_, offset_);
    191     __ CallStub(&stub);
    192   }
    193 
    194  private:
    195   Register const object_;
    196   Register const offset_;
    197   Register const value_;
    198   Register const scratch0_;
    199   Register const scratch1_;
    200   RecordWriteMode const mode_;
    201 };
    202 
    203 
    204 Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) {
    205   switch (condition) {
    206     case kEqual:
    207       return eq;
    208     case kNotEqual:
    209       return ne;
    210     case kSignedLessThan:
    211     case kUnsignedLessThan:
    212       return lt;
    213     case kSignedGreaterThanOrEqual:
    214     case kUnsignedGreaterThanOrEqual:
    215       return ge;
    216     case kSignedLessThanOrEqual:
    217     case kUnsignedLessThanOrEqual:
    218       return le;
    219     case kSignedGreaterThan:
    220     case kUnsignedGreaterThan:
    221       return gt;
    222     case kOverflow:
    223       // Overflow checked for add/sub only.
    224       switch (op) {
    225 #if V8_TARGET_ARCH_PPC64
    226         case kPPC_Add:
    227         case kPPC_Sub:
    228           return lt;
    229 #endif
    230         case kPPC_AddWithOverflow32:
    231         case kPPC_SubWithOverflow32:
    232 #if V8_TARGET_ARCH_PPC64
    233           return ne;
    234 #else
    235           return lt;
    236 #endif
    237         default:
    238           break;
    239       }
    240       break;
    241     case kNotOverflow:
    242       switch (op) {
    243 #if V8_TARGET_ARCH_PPC64
    244         case kPPC_Add:
    245         case kPPC_Sub:
    246           return ge;
    247 #endif
    248         case kPPC_AddWithOverflow32:
    249         case kPPC_SubWithOverflow32:
    250 #if V8_TARGET_ARCH_PPC64
    251           return eq;
    252 #else
    253           return ge;
    254 #endif
    255         default:
    256           break;
    257       }
    258       break;
    259     default:
    260       break;
    261   }
    262   UNREACHABLE();
    263   return kNoCondition;
    264 }
    265 
    266 }  // namespace
    267 
    268 #define ASSEMBLE_FLOAT_UNOP_RC(asm_instr)                            \
    269   do {                                                               \
    270     __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
    271                  i.OutputRCBit());                                   \
    272   } while (0)
    273 
    274 
    275 #define ASSEMBLE_FLOAT_BINOP_RC(asm_instr)                           \
    276   do {                                                               \
    277     __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
    278                  i.InputDoubleRegister(1), i.OutputRCBit());         \
    279   } while (0)
    280 
    281 
    282 #define ASSEMBLE_BINOP(asm_instr_reg, asm_instr_imm)           \
    283   do {                                                         \
    284     if (HasRegisterInput(instr, 1)) {                          \
    285       __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \
    286                        i.InputRegister(1));                    \
    287     } else {                                                   \
    288       __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \
    289                        i.InputImmediate(1));                   \
    290     }                                                          \
    291   } while (0)
    292 
    293 
    294 #define ASSEMBLE_BINOP_RC(asm_instr_reg, asm_instr_imm)        \
    295   do {                                                         \
    296     if (HasRegisterInput(instr, 1)) {                          \
    297       __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \
    298                        i.InputRegister(1), i.OutputRCBit());   \
    299     } else {                                                   \
    300       __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \
    301                        i.InputImmediate(1), i.OutputRCBit());  \
    302     }                                                          \
    303   } while (0)
    304 
    305 
    306 #define ASSEMBLE_BINOP_INT_RC(asm_instr_reg, asm_instr_imm)    \
    307   do {                                                         \
    308     if (HasRegisterInput(instr, 1)) {                          \
    309       __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \
    310                        i.InputRegister(1), i.OutputRCBit());   \
    311     } else {                                                   \
    312       __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \
    313                        i.InputInt32(1), i.OutputRCBit());      \
    314     }                                                          \
    315   } while (0)
    316 
    317 
    318 #define ASSEMBLE_ADD_WITH_OVERFLOW()                                    \
    319   do {                                                                  \
    320     if (HasRegisterInput(instr, 1)) {                                   \
    321       __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
    322                                 i.InputRegister(1), kScratchReg, r0);   \
    323     } else {                                                            \
    324       __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
    325                                 i.InputInt32(1), kScratchReg, r0);      \
    326     }                                                                   \
    327   } while (0)
    328 
    329 
    330 #define ASSEMBLE_SUB_WITH_OVERFLOW()                                    \
    331   do {                                                                  \
    332     if (HasRegisterInput(instr, 1)) {                                   \
    333       __ SubAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
    334                                 i.InputRegister(1), kScratchReg, r0);   \
    335     } else {                                                            \
    336       __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
    337                                 -i.InputInt32(1), kScratchReg, r0);     \
    338     }                                                                   \
    339   } while (0)
    340 
    341 
    342 #if V8_TARGET_ARCH_PPC64
    343 #define ASSEMBLE_ADD_WITH_OVERFLOW32()           \
    344   do {                                           \
    345     ASSEMBLE_BINOP(add, addi);                   \
    346     __ TestIfInt32(i.OutputRegister(), r0, cr0); \
    347   } while (0)
    348 
    349 
    350 #define ASSEMBLE_SUB_WITH_OVERFLOW32()           \
    351   do {                                           \
    352     ASSEMBLE_BINOP(sub, subi);                   \
    353     __ TestIfInt32(i.OutputRegister(), r0, cr0); \
    354   } while (0)
    355 #else
    356 #define ASSEMBLE_ADD_WITH_OVERFLOW32 ASSEMBLE_ADD_WITH_OVERFLOW
    357 #define ASSEMBLE_SUB_WITH_OVERFLOW32 ASSEMBLE_SUB_WITH_OVERFLOW
    358 #endif
    359 
    360 
    361 #define ASSEMBLE_COMPARE(cmp_instr, cmpl_instr)                        \
    362   do {                                                                 \
    363     const CRegister cr = cr0;                                          \
    364     if (HasRegisterInput(instr, 1)) {                                  \
    365       if (i.CompareLogical()) {                                        \
    366         __ cmpl_instr(i.InputRegister(0), i.InputRegister(1), cr);     \
    367       } else {                                                         \
    368         __ cmp_instr(i.InputRegister(0), i.InputRegister(1), cr);      \
    369       }                                                                \
    370     } else {                                                           \
    371       if (i.CompareLogical()) {                                        \
    372         __ cmpl_instr##i(i.InputRegister(0), i.InputImmediate(1), cr); \
    373       } else {                                                         \
    374         __ cmp_instr##i(i.InputRegister(0), i.InputImmediate(1), cr);  \
    375       }                                                                \
    376     }                                                                  \
    377     DCHECK_EQ(SetRC, i.OutputRCBit());                                 \
    378   } while (0)
    379 
    380 
    381 #define ASSEMBLE_FLOAT_COMPARE(cmp_instr)                                 \
    382   do {                                                                    \
    383     const CRegister cr = cr0;                                             \
    384     __ cmp_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1), cr); \
    385     DCHECK_EQ(SetRC, i.OutputRCBit());                                    \
    386   } while (0)
    387 
    388 
    389 #define ASSEMBLE_MODULO(div_instr, mul_instr)                        \
    390   do {                                                               \
    391     const Register scratch = kScratchReg;                            \
    392     __ div_instr(scratch, i.InputRegister(0), i.InputRegister(1));   \
    393     __ mul_instr(scratch, scratch, i.InputRegister(1));              \
    394     __ sub(i.OutputRegister(), i.InputRegister(0), scratch, LeaveOE, \
    395            i.OutputRCBit());                                         \
    396   } while (0)
    397 
    398 
    399 #define ASSEMBLE_FLOAT_MODULO()                                               \
    400   do {                                                                        \
    401     FrameScope scope(masm(), StackFrame::MANUAL);                             \
    402     __ PrepareCallCFunction(0, 2, kScratchReg);                               \
    403     __ MovToFloatParameters(i.InputDoubleRegister(0),                         \
    404                             i.InputDoubleRegister(1));                        \
    405     __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()), \
    406                      0, 2);                                                   \
    407     __ MovFromFloatResult(i.OutputDoubleRegister());                          \
    408     DCHECK_EQ(LeaveRC, i.OutputRCBit());                                      \
    409   } while (0)
    410 
    411 
    412 #define ASSEMBLE_FLOAT_MAX(scratch_reg)                                       \
    413   do {                                                                        \
    414     __ fsub(scratch_reg, i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \
    415     __ fsel(i.OutputDoubleRegister(), scratch_reg, i.InputDoubleRegister(0),  \
    416             i.InputDoubleRegister(1));                                        \
    417   } while (0)
    418 
    419 
    420 #define ASSEMBLE_FLOAT_MIN(scratch_reg)                                       \
    421   do {                                                                        \
    422     __ fsub(scratch_reg, i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \
    423     __ fsel(i.OutputDoubleRegister(), scratch_reg, i.InputDoubleRegister(1),  \
    424             i.InputDoubleRegister(0));                                        \
    425   } while (0)
    426 
    427 
    428 #define ASSEMBLE_LOAD_FLOAT(asm_instr, asm_instrx)    \
    429   do {                                                \
    430     DoubleRegister result = i.OutputDoubleRegister(); \
    431     AddressingMode mode = kMode_None;                 \
    432     MemOperand operand = i.MemoryOperand(&mode);      \
    433     if (mode == kMode_MRI) {                          \
    434       __ asm_instr(result, operand);                  \
    435     } else {                                          \
    436       __ asm_instrx(result, operand);                 \
    437     }                                                 \
    438     DCHECK_EQ(LeaveRC, i.OutputRCBit());              \
    439   } while (0)
    440 
    441 
    442 #define ASSEMBLE_LOAD_INTEGER(asm_instr, asm_instrx) \
    443   do {                                               \
    444     Register result = i.OutputRegister();            \
    445     AddressingMode mode = kMode_None;                \
    446     MemOperand operand = i.MemoryOperand(&mode);     \
    447     if (mode == kMode_MRI) {                         \
    448       __ asm_instr(result, operand);                 \
    449     } else {                                         \
    450       __ asm_instrx(result, operand);                \
    451     }                                                \
    452     DCHECK_EQ(LeaveRC, i.OutputRCBit());             \
    453   } while (0)
    454 
    455 
    456 #define ASSEMBLE_STORE_FLOAT32()                         \
    457   do {                                                   \
    458     size_t index = 0;                                    \
    459     AddressingMode mode = kMode_None;                    \
    460     MemOperand operand = i.MemoryOperand(&mode, &index); \
    461     DoubleRegister value = i.InputDoubleRegister(index); \
    462     __ frsp(kScratchDoubleReg, value);                   \
    463     if (mode == kMode_MRI) {                             \
    464       __ stfs(kScratchDoubleReg, operand);               \
    465     } else {                                             \
    466       __ stfsx(kScratchDoubleReg, operand);              \
    467     }                                                    \
    468     DCHECK_EQ(LeaveRC, i.OutputRCBit());                 \
    469   } while (0)
    470 
    471 
    472 #define ASSEMBLE_STORE_DOUBLE()                          \
    473   do {                                                   \
    474     size_t index = 0;                                    \
    475     AddressingMode mode = kMode_None;                    \
    476     MemOperand operand = i.MemoryOperand(&mode, &index); \
    477     DoubleRegister value = i.InputDoubleRegister(index); \
    478     if (mode == kMode_MRI) {                             \
    479       __ stfd(value, operand);                           \
    480     } else {                                             \
    481       __ stfdx(value, operand);                          \
    482     }                                                    \
    483     DCHECK_EQ(LeaveRC, i.OutputRCBit());                 \
    484   } while (0)
    485 
    486 
    487 #define ASSEMBLE_STORE_INTEGER(asm_instr, asm_instrx)    \
    488   do {                                                   \
    489     size_t index = 0;                                    \
    490     AddressingMode mode = kMode_None;                    \
    491     MemOperand operand = i.MemoryOperand(&mode, &index); \
    492     Register value = i.InputRegister(index);             \
    493     if (mode == kMode_MRI) {                             \
    494       __ asm_instr(value, operand);                      \
    495     } else {                                             \
    496       __ asm_instrx(value, operand);                     \
    497     }                                                    \
    498     DCHECK_EQ(LeaveRC, i.OutputRCBit());                 \
    499   } while (0)
    500 
    501 
    502 // TODO(mbrandy): fix paths that produce garbage in offset's upper 32-bits.
    503 #define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr, asm_instrx, width)  \
    504   do {                                                             \
    505     DoubleRegister result = i.OutputDoubleRegister();              \
    506     size_t index = 0;                                              \
    507     AddressingMode mode = kMode_None;                              \
    508     MemOperand operand = i.MemoryOperand(&mode, index);            \
    509     DCHECK_EQ(kMode_MRR, mode);                                    \
    510     Register offset = operand.rb();                                \
    511     __ extsw(offset, offset);                                      \
    512     if (HasRegisterInput(instr, 2)) {                              \
    513       __ cmplw(offset, i.InputRegister(2));                        \
    514     } else {                                                       \
    515       __ cmplwi(offset, i.InputImmediate(2));                      \
    516     }                                                              \
    517     auto ool = new (zone()) OutOfLineLoadNAN##width(this, result); \
    518     __ bge(ool->entry());                                          \
    519     if (mode == kMode_MRI) {                                       \
    520       __ asm_instr(result, operand);                               \
    521     } else {                                                       \
    522       __ asm_instrx(result, operand);                              \
    523     }                                                              \
    524     __ bind(ool->exit());                                          \
    525     DCHECK_EQ(LeaveRC, i.OutputRCBit());                           \
    526   } while (0)
    527 
    528 
    529 // TODO(mbrandy): fix paths that produce garbage in offset's upper 32-bits.
    530 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr, asm_instrx) \
    531   do {                                                       \
    532     Register result = i.OutputRegister();                    \
    533     size_t index = 0;                                        \
    534     AddressingMode mode = kMode_None;                        \
    535     MemOperand operand = i.MemoryOperand(&mode, index);      \
    536     DCHECK_EQ(kMode_MRR, mode);                              \
    537     Register offset = operand.rb();                          \
    538     __ extsw(offset, offset);                                \
    539     if (HasRegisterInput(instr, 2)) {                        \
    540       __ cmplw(offset, i.InputRegister(2));                  \
    541     } else {                                                 \
    542       __ cmplwi(offset, i.InputImmediate(2));                \
    543     }                                                        \
    544     auto ool = new (zone()) OutOfLineLoadZero(this, result); \
    545     __ bge(ool->entry());                                    \
    546     if (mode == kMode_MRI) {                                 \
    547       __ asm_instr(result, operand);                         \
    548     } else {                                                 \
    549       __ asm_instrx(result, operand);                        \
    550     }                                                        \
    551     __ bind(ool->exit());                                    \
    552     DCHECK_EQ(LeaveRC, i.OutputRCBit());                     \
    553   } while (0)
    554 
    555 
    556 // TODO(mbrandy): fix paths that produce garbage in offset's upper 32-bits.
    557 #define ASSEMBLE_CHECKED_STORE_FLOAT32()                \
    558   do {                                                  \
    559     Label done;                                         \
    560     size_t index = 0;                                   \
    561     AddressingMode mode = kMode_None;                   \
    562     MemOperand operand = i.MemoryOperand(&mode, index); \
    563     DCHECK_EQ(kMode_MRR, mode);                         \
    564     Register offset = operand.rb();                     \
    565     __ extsw(offset, offset);                           \
    566     if (HasRegisterInput(instr, 2)) {                   \
    567       __ cmplw(offset, i.InputRegister(2));             \
    568     } else {                                            \
    569       __ cmplwi(offset, i.InputImmediate(2));           \
    570     }                                                   \
    571     __ bge(&done);                                      \
    572     DoubleRegister value = i.InputDoubleRegister(3);    \
    573     __ frsp(kScratchDoubleReg, value);                  \
    574     if (mode == kMode_MRI) {                            \
    575       __ stfs(kScratchDoubleReg, operand);              \
    576     } else {                                            \
    577       __ stfsx(kScratchDoubleReg, operand);             \
    578     }                                                   \
    579     __ bind(&done);                                     \
    580     DCHECK_EQ(LeaveRC, i.OutputRCBit());                \
    581   } while (0)
    582 
    583 
    584 // TODO(mbrandy): fix paths that produce garbage in offset's upper 32-bits.
    585 #define ASSEMBLE_CHECKED_STORE_DOUBLE()                 \
    586   do {                                                  \
    587     Label done;                                         \
    588     size_t index = 0;                                   \
    589     AddressingMode mode = kMode_None;                   \
    590     MemOperand operand = i.MemoryOperand(&mode, index); \
    591     DCHECK_EQ(kMode_MRR, mode);                         \
    592     Register offset = operand.rb();                     \
    593     __ extsw(offset, offset);                           \
    594     if (HasRegisterInput(instr, 2)) {                   \
    595       __ cmplw(offset, i.InputRegister(2));             \
    596     } else {                                            \
    597       __ cmplwi(offset, i.InputImmediate(2));           \
    598     }                                                   \
    599     __ bge(&done);                                      \
    600     DoubleRegister value = i.InputDoubleRegister(3);    \
    601     if (mode == kMode_MRI) {                            \
    602       __ stfd(value, operand);                          \
    603     } else {                                            \
    604       __ stfdx(value, operand);                         \
    605     }                                                   \
    606     __ bind(&done);                                     \
    607     DCHECK_EQ(LeaveRC, i.OutputRCBit());                \
    608   } while (0)
    609 
    610 
    611 // TODO(mbrandy): fix paths that produce garbage in offset's upper 32-bits.
    612 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr, asm_instrx) \
    613   do {                                                        \
    614     Label done;                                               \
    615     size_t index = 0;                                         \
    616     AddressingMode mode = kMode_None;                         \
    617     MemOperand operand = i.MemoryOperand(&mode, index);       \
    618     DCHECK_EQ(kMode_MRR, mode);                               \
    619     Register offset = operand.rb();                           \
    620     __ extsw(offset, offset);                                 \
    621     if (HasRegisterInput(instr, 2)) {                         \
    622       __ cmplw(offset, i.InputRegister(2));                   \
    623     } else {                                                  \
    624       __ cmplwi(offset, i.InputImmediate(2));                 \
    625     }                                                         \
    626     __ bge(&done);                                            \
    627     Register value = i.InputRegister(3);                      \
    628     if (mode == kMode_MRI) {                                  \
    629       __ asm_instr(value, operand);                           \
    630     } else {                                                  \
    631       __ asm_instrx(value, operand);                          \
    632     }                                                         \
    633     __ bind(&done);                                           \
    634     DCHECK_EQ(LeaveRC, i.OutputRCBit());                      \
    635   } while (0)
    636 
    637 
    638 void CodeGenerator::AssembleDeconstructActivationRecord(int stack_param_delta) {
    639   int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
    640   if (sp_slot_delta > 0) {
    641     __ Add(sp, sp, sp_slot_delta * kPointerSize, r0);
    642   }
    643   frame_access_state()->SetFrameAccessToDefault();
    644 }
    645 
    646 
    647 void CodeGenerator::AssemblePrepareTailCall(int stack_param_delta) {
    648   int sp_slot_delta = TailCallFrameStackSlotDelta(stack_param_delta);
    649   if (sp_slot_delta < 0) {
    650     __ Add(sp, sp, sp_slot_delta * kPointerSize, r0);
    651     frame_access_state()->IncreaseSPDelta(-sp_slot_delta);
    652   }
    653   if (frame()->needs_frame()) {
    654     if (FLAG_enable_embedded_constant_pool) {
    655       __ LoadP(kConstantPoolRegister,
    656                MemOperand(fp, StandardFrameConstants::kConstantPoolOffset));
    657     }
    658     __ LoadP(r0, MemOperand(fp, StandardFrameConstants::kCallerPCOffset));
    659     __ LoadP(fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
    660     __ mtlr(r0);
    661   }
    662   frame_access_state()->SetFrameAccessToSP();
    663 }
    664 
    665 
    666 // Assembles an instruction after register allocation, producing machine code.
    667 void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
    668   PPCOperandConverter i(this, instr);
    669   ArchOpcode opcode = ArchOpcodeField::decode(instr->opcode());
    670 
    671   switch (opcode) {
    672     case kArchCallCodeObject: {
    673       v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
    674           masm());
    675       EnsureSpaceForLazyDeopt();
    676       if (HasRegisterInput(instr, 0)) {
    677         __ addi(ip, i.InputRegister(0),
    678                 Operand(Code::kHeaderSize - kHeapObjectTag));
    679         __ Call(ip);
    680       } else {
    681         __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
    682                 RelocInfo::CODE_TARGET);
    683       }
    684       RecordCallPosition(instr);
    685       DCHECK_EQ(LeaveRC, i.OutputRCBit());
    686       frame_access_state()->ClearSPDelta();
    687       break;
    688     }
    689     case kArchTailCallCodeObject: {
    690       int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
    691       AssembleDeconstructActivationRecord(stack_param_delta);
    692       if (HasRegisterInput(instr, 0)) {
    693         __ addi(ip, i.InputRegister(0),
    694                 Operand(Code::kHeaderSize - kHeapObjectTag));
    695         __ Jump(ip);
    696       } else {
    697         // We cannot use the constant pool to load the target since
    698         // we've already restored the caller's frame.
    699         ConstantPoolUnavailableScope constant_pool_unavailable(masm());
    700         __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
    701                 RelocInfo::CODE_TARGET);
    702       }
    703       DCHECK_EQ(LeaveRC, i.OutputRCBit());
    704       frame_access_state()->ClearSPDelta();
    705       break;
    706     }
    707     case kArchCallJSFunction: {
    708       v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
    709           masm());
    710       EnsureSpaceForLazyDeopt();
    711       Register func = i.InputRegister(0);
    712       if (FLAG_debug_code) {
    713         // Check the function's context matches the context argument.
    714         __ LoadP(kScratchReg,
    715                  FieldMemOperand(func, JSFunction::kContextOffset));
    716         __ cmp(cp, kScratchReg);
    717         __ Assert(eq, kWrongFunctionContext);
    718       }
    719       __ LoadP(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
    720       __ Call(ip);
    721       RecordCallPosition(instr);
    722       DCHECK_EQ(LeaveRC, i.OutputRCBit());
    723       frame_access_state()->ClearSPDelta();
    724       break;
    725     }
    726     case kArchTailCallJSFunction: {
    727       Register func = i.InputRegister(0);
    728       if (FLAG_debug_code) {
    729         // Check the function's context matches the context argument.
    730         __ LoadP(kScratchReg,
    731                  FieldMemOperand(func, JSFunction::kContextOffset));
    732         __ cmp(cp, kScratchReg);
    733         __ Assert(eq, kWrongFunctionContext);
    734       }
    735       int stack_param_delta = i.InputInt32(instr->InputCount() - 1);
    736       AssembleDeconstructActivationRecord(stack_param_delta);
    737       __ LoadP(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
    738       __ Jump(ip);
    739       DCHECK_EQ(LeaveRC, i.OutputRCBit());
    740       frame_access_state()->ClearSPDelta();
    741       break;
    742     }
    743     case kArchLazyBailout: {
    744       v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
    745           masm());
    746       EnsureSpaceForLazyDeopt();
    747       RecordCallPosition(instr);
    748       break;
    749     }
    750     case kArchPrepareCallCFunction: {
    751       int const num_parameters = MiscField::decode(instr->opcode());
    752       __ PrepareCallCFunction(num_parameters, kScratchReg);
    753       // Frame alignment requires using FP-relative frame addressing.
    754       frame_access_state()->SetFrameAccessToFP();
    755       break;
    756     }
    757     case kArchPrepareTailCall:
    758       AssemblePrepareTailCall(i.InputInt32(instr->InputCount() - 1));
    759       break;
    760     case kArchCallCFunction: {
    761       int const num_parameters = MiscField::decode(instr->opcode());
    762       if (instr->InputAt(0)->IsImmediate()) {
    763         ExternalReference ref = i.InputExternalReference(0);
    764         __ CallCFunction(ref, num_parameters);
    765       } else {
    766         Register func = i.InputRegister(0);
    767         __ CallCFunction(func, num_parameters);
    768       }
    769       frame_access_state()->SetFrameAccessToDefault();
    770       frame_access_state()->ClearSPDelta();
    771       break;
    772     }
    773     case kArchJmp:
    774       AssembleArchJump(i.InputRpo(0));
    775       DCHECK_EQ(LeaveRC, i.OutputRCBit());
    776       break;
    777     case kArchLookupSwitch:
    778       AssembleArchLookupSwitch(instr);
    779       DCHECK_EQ(LeaveRC, i.OutputRCBit());
    780       break;
    781     case kArchTableSwitch:
    782       AssembleArchTableSwitch(instr);
    783       DCHECK_EQ(LeaveRC, i.OutputRCBit());
    784       break;
    785     case kArchNop:
    786     case kArchThrowTerminator:
    787       // don't emit code for nops.
    788       DCHECK_EQ(LeaveRC, i.OutputRCBit());
    789       break;
    790     case kArchDeoptimize: {
    791       int deopt_state_id =
    792           BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
    793       Deoptimizer::BailoutType bailout_type =
    794           Deoptimizer::BailoutType(MiscField::decode(instr->opcode()));
    795       AssembleDeoptimizerCall(deopt_state_id, bailout_type);
    796       break;
    797     }
    798     case kArchRet:
    799       AssembleReturn();
    800       DCHECK_EQ(LeaveRC, i.OutputRCBit());
    801       break;
    802     case kArchStackPointer:
    803       __ mr(i.OutputRegister(), sp);
    804       DCHECK_EQ(LeaveRC, i.OutputRCBit());
    805       break;
    806     case kArchFramePointer:
    807       __ mr(i.OutputRegister(), fp);
    808       DCHECK_EQ(LeaveRC, i.OutputRCBit());
    809       break;
    810     case kArchTruncateDoubleToI:
    811       // TODO(mbrandy): move slow call to stub out of line.
    812       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
    813       DCHECK_EQ(LeaveRC, i.OutputRCBit());
    814       break;
    815     case kArchStoreWithWriteBarrier: {
    816       RecordWriteMode mode =
    817           static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
    818       Register object = i.InputRegister(0);
    819       Register offset = i.InputRegister(1);
    820       Register value = i.InputRegister(2);
    821       Register scratch0 = i.TempRegister(0);
    822       Register scratch1 = i.TempRegister(1);
    823       auto ool = new (zone()) OutOfLineRecordWrite(this, object, offset, value,
    824                                                    scratch0, scratch1, mode);
    825       __ StorePX(value, MemOperand(object, offset));
    826       __ CheckPageFlag(object, scratch0,
    827                        MemoryChunk::kPointersFromHereAreInterestingMask, ne,
    828                        ool->entry());
    829       __ bind(ool->exit());
    830       break;
    831     }
    832     case kPPC_And:
    833       if (HasRegisterInput(instr, 1)) {
    834         __ and_(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    835                 i.OutputRCBit());
    836       } else {
    837         __ andi(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
    838       }
    839       break;
    840     case kPPC_AndComplement:
    841       __ andc(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    842               i.OutputRCBit());
    843       break;
    844     case kPPC_Or:
    845       if (HasRegisterInput(instr, 1)) {
    846         __ orx(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    847                i.OutputRCBit());
    848       } else {
    849         __ ori(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
    850         DCHECK_EQ(LeaveRC, i.OutputRCBit());
    851       }
    852       break;
    853     case kPPC_OrComplement:
    854       __ orc(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    855              i.OutputRCBit());
    856       break;
    857     case kPPC_Xor:
    858       if (HasRegisterInput(instr, 1)) {
    859         __ xor_(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    860                 i.OutputRCBit());
    861       } else {
    862         __ xori(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
    863         DCHECK_EQ(LeaveRC, i.OutputRCBit());
    864       }
    865       break;
    866     case kPPC_ShiftLeft32:
    867       ASSEMBLE_BINOP_RC(slw, slwi);
    868       break;
    869 #if V8_TARGET_ARCH_PPC64
    870     case kPPC_ShiftLeft64:
    871       ASSEMBLE_BINOP_RC(sld, sldi);
    872       break;
    873 #endif
    874     case kPPC_ShiftRight32:
    875       ASSEMBLE_BINOP_RC(srw, srwi);
    876       break;
    877 #if V8_TARGET_ARCH_PPC64
    878     case kPPC_ShiftRight64:
    879       ASSEMBLE_BINOP_RC(srd, srdi);
    880       break;
    881 #endif
    882     case kPPC_ShiftRightAlg32:
    883       ASSEMBLE_BINOP_INT_RC(sraw, srawi);
    884       break;
    885 #if V8_TARGET_ARCH_PPC64
    886     case kPPC_ShiftRightAlg64:
    887       ASSEMBLE_BINOP_INT_RC(srad, sradi);
    888       break;
    889 #endif
    890     case kPPC_RotRight32:
    891       if (HasRegisterInput(instr, 1)) {
    892         __ subfic(kScratchReg, i.InputRegister(1), Operand(32));
    893         __ rotlw(i.OutputRegister(), i.InputRegister(0), kScratchReg,
    894                  i.OutputRCBit());
    895       } else {
    896         int sh = i.InputInt32(1);
    897         __ rotrwi(i.OutputRegister(), i.InputRegister(0), sh, i.OutputRCBit());
    898       }
    899       break;
    900 #if V8_TARGET_ARCH_PPC64
    901     case kPPC_RotRight64:
    902       if (HasRegisterInput(instr, 1)) {
    903         __ subfic(kScratchReg, i.InputRegister(1), Operand(64));
    904         __ rotld(i.OutputRegister(), i.InputRegister(0), kScratchReg,
    905                  i.OutputRCBit());
    906       } else {
    907         int sh = i.InputInt32(1);
    908         __ rotrdi(i.OutputRegister(), i.InputRegister(0), sh, i.OutputRCBit());
    909       }
    910       break;
    911 #endif
    912     case kPPC_Not:
    913       __ notx(i.OutputRegister(), i.InputRegister(0), i.OutputRCBit());
    914       break;
    915     case kPPC_RotLeftAndMask32:
    916       __ rlwinm(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
    917                 31 - i.InputInt32(2), 31 - i.InputInt32(3), i.OutputRCBit());
    918       break;
    919 #if V8_TARGET_ARCH_PPC64
    920     case kPPC_RotLeftAndClear64:
    921       __ rldic(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
    922                63 - i.InputInt32(2), i.OutputRCBit());
    923       break;
    924     case kPPC_RotLeftAndClearLeft64:
    925       __ rldicl(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
    926                 63 - i.InputInt32(2), i.OutputRCBit());
    927       break;
    928     case kPPC_RotLeftAndClearRight64:
    929       __ rldicr(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
    930                 63 - i.InputInt32(2), i.OutputRCBit());
    931       break;
    932 #endif
    933     case kPPC_Add:
    934 #if V8_TARGET_ARCH_PPC64
    935       if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
    936         ASSEMBLE_ADD_WITH_OVERFLOW();
    937       } else {
    938 #endif
    939         if (HasRegisterInput(instr, 1)) {
    940           __ add(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    941                  LeaveOE, i.OutputRCBit());
    942         } else {
    943           __ addi(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
    944           DCHECK_EQ(LeaveRC, i.OutputRCBit());
    945         }
    946 #if V8_TARGET_ARCH_PPC64
    947       }
    948 #endif
    949       break;
    950     case kPPC_AddWithOverflow32:
    951       ASSEMBLE_ADD_WITH_OVERFLOW32();
    952       break;
    953     case kPPC_AddDouble:
    954       ASSEMBLE_FLOAT_BINOP_RC(fadd);
    955       break;
    956     case kPPC_Sub:
    957 #if V8_TARGET_ARCH_PPC64
    958       if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
    959         ASSEMBLE_SUB_WITH_OVERFLOW();
    960       } else {
    961 #endif
    962         if (HasRegisterInput(instr, 1)) {
    963           __ sub(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    964                  LeaveOE, i.OutputRCBit());
    965         } else {
    966           __ subi(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
    967           DCHECK_EQ(LeaveRC, i.OutputRCBit());
    968         }
    969 #if V8_TARGET_ARCH_PPC64
    970       }
    971 #endif
    972       break;
    973     case kPPC_SubWithOverflow32:
    974       ASSEMBLE_SUB_WITH_OVERFLOW32();
    975       break;
    976     case kPPC_SubDouble:
    977       ASSEMBLE_FLOAT_BINOP_RC(fsub);
    978       break;
    979     case kPPC_Mul32:
    980       __ mullw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    981                LeaveOE, i.OutputRCBit());
    982       break;
    983 #if V8_TARGET_ARCH_PPC64
    984     case kPPC_Mul64:
    985       __ mulld(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    986                LeaveOE, i.OutputRCBit());
    987       break;
    988 #endif
    989     case kPPC_MulHigh32:
    990       __ mulhw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    991                i.OutputRCBit());
    992       break;
    993     case kPPC_MulHighU32:
    994       __ mulhwu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
    995                 i.OutputRCBit());
    996       break;
    997     case kPPC_MulDouble:
    998       ASSEMBLE_FLOAT_BINOP_RC(fmul);
    999       break;
   1000     case kPPC_Div32:
   1001       __ divw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
   1002       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1003       break;
   1004 #if V8_TARGET_ARCH_PPC64
   1005     case kPPC_Div64:
   1006       __ divd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
   1007       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1008       break;
   1009 #endif
   1010     case kPPC_DivU32:
   1011       __ divwu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
   1012       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1013       break;
   1014 #if V8_TARGET_ARCH_PPC64
   1015     case kPPC_DivU64:
   1016       __ divdu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
   1017       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1018       break;
   1019 #endif
   1020     case kPPC_DivDouble:
   1021       ASSEMBLE_FLOAT_BINOP_RC(fdiv);
   1022       break;
   1023     case kPPC_Mod32:
   1024       ASSEMBLE_MODULO(divw, mullw);
   1025       break;
   1026 #if V8_TARGET_ARCH_PPC64
   1027     case kPPC_Mod64:
   1028       ASSEMBLE_MODULO(divd, mulld);
   1029       break;
   1030 #endif
   1031     case kPPC_ModU32:
   1032       ASSEMBLE_MODULO(divwu, mullw);
   1033       break;
   1034 #if V8_TARGET_ARCH_PPC64
   1035     case kPPC_ModU64:
   1036       ASSEMBLE_MODULO(divdu, mulld);
   1037       break;
   1038 #endif
   1039     case kPPC_ModDouble:
   1040       // TODO(bmeurer): We should really get rid of this special instruction,
   1041       // and generate a CallAddress instruction instead.
   1042       ASSEMBLE_FLOAT_MODULO();
   1043       break;
   1044     case kPPC_Neg:
   1045       __ neg(i.OutputRegister(), i.InputRegister(0), LeaveOE, i.OutputRCBit());
   1046       break;
   1047     case kPPC_MaxDouble:
   1048       ASSEMBLE_FLOAT_MAX(kScratchDoubleReg);
   1049       break;
   1050     case kPPC_MinDouble:
   1051       ASSEMBLE_FLOAT_MIN(kScratchDoubleReg);
   1052       break;
   1053     case kPPC_AbsDouble:
   1054       ASSEMBLE_FLOAT_UNOP_RC(fabs);
   1055       break;
   1056     case kPPC_SqrtDouble:
   1057       ASSEMBLE_FLOAT_UNOP_RC(fsqrt);
   1058       break;
   1059     case kPPC_FloorDouble:
   1060       ASSEMBLE_FLOAT_UNOP_RC(frim);
   1061       break;
   1062     case kPPC_CeilDouble:
   1063       ASSEMBLE_FLOAT_UNOP_RC(frip);
   1064       break;
   1065     case kPPC_TruncateDouble:
   1066       ASSEMBLE_FLOAT_UNOP_RC(friz);
   1067       break;
   1068     case kPPC_RoundDouble:
   1069       ASSEMBLE_FLOAT_UNOP_RC(frin);
   1070       break;
   1071     case kPPC_NegDouble:
   1072       ASSEMBLE_FLOAT_UNOP_RC(fneg);
   1073       break;
   1074     case kPPC_Cntlz32:
   1075       __ cntlzw_(i.OutputRegister(), i.InputRegister(0));
   1076       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1077       break;
   1078 #if V8_TARGET_ARCH_PPC64
   1079     case kPPC_Cntlz64:
   1080       __ cntlzd_(i.OutputRegister(), i.InputRegister(0));
   1081       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1082       break;
   1083 #endif
   1084     case kPPC_Popcnt32:
   1085       __ popcntw(i.OutputRegister(), i.InputRegister(0));
   1086       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1087       break;
   1088 #if V8_TARGET_ARCH_PPC64
   1089     case kPPC_Popcnt64:
   1090       __ popcntd(i.OutputRegister(), i.InputRegister(0));
   1091       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1092       break;
   1093 #endif
   1094     case kPPC_Cmp32:
   1095       ASSEMBLE_COMPARE(cmpw, cmplw);
   1096       break;
   1097 #if V8_TARGET_ARCH_PPC64
   1098     case kPPC_Cmp64:
   1099       ASSEMBLE_COMPARE(cmp, cmpl);
   1100       break;
   1101 #endif
   1102     case kPPC_CmpDouble:
   1103       ASSEMBLE_FLOAT_COMPARE(fcmpu);
   1104       break;
   1105     case kPPC_Tst32:
   1106       if (HasRegisterInput(instr, 1)) {
   1107         __ and_(r0, i.InputRegister(0), i.InputRegister(1), i.OutputRCBit());
   1108       } else {
   1109         __ andi(r0, i.InputRegister(0), i.InputImmediate(1));
   1110       }
   1111 #if V8_TARGET_ARCH_PPC64
   1112       __ extsw(r0, r0, i.OutputRCBit());
   1113 #endif
   1114       DCHECK_EQ(SetRC, i.OutputRCBit());
   1115       break;
   1116 #if V8_TARGET_ARCH_PPC64
   1117     case kPPC_Tst64:
   1118       if (HasRegisterInput(instr, 1)) {
   1119         __ and_(r0, i.InputRegister(0), i.InputRegister(1), i.OutputRCBit());
   1120       } else {
   1121         __ andi(r0, i.InputRegister(0), i.InputImmediate(1));
   1122       }
   1123       DCHECK_EQ(SetRC, i.OutputRCBit());
   1124       break;
   1125 #endif
   1126     case kPPC_Push:
   1127       if (instr->InputAt(0)->IsDoubleRegister()) {
   1128         __ stfdu(i.InputDoubleRegister(0), MemOperand(sp, -kDoubleSize));
   1129         frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
   1130       } else {
   1131         __ Push(i.InputRegister(0));
   1132         frame_access_state()->IncreaseSPDelta(1);
   1133       }
   1134       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1135       break;
   1136     case kPPC_PushFrame: {
   1137       int num_slots = i.InputInt32(1);
   1138       if (instr->InputAt(0)->IsDoubleRegister()) {
   1139         __ stfdu(i.InputDoubleRegister(0),
   1140                  MemOperand(sp, -num_slots * kPointerSize));
   1141       } else {
   1142         __ StorePU(i.InputRegister(0),
   1143                    MemOperand(sp, -num_slots * kPointerSize));
   1144       }
   1145       break;
   1146     }
   1147     case kPPC_StoreToStackSlot: {
   1148       int slot = i.InputInt32(1);
   1149       if (instr->InputAt(0)->IsDoubleRegister()) {
   1150         __ stfd(i.InputDoubleRegister(0), MemOperand(sp, slot * kPointerSize));
   1151       } else {
   1152         __ StoreP(i.InputRegister(0), MemOperand(sp, slot * kPointerSize));
   1153       }
   1154       break;
   1155     }
   1156     case kPPC_ExtendSignWord8:
   1157       __ extsb(i.OutputRegister(), i.InputRegister(0));
   1158       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1159       break;
   1160     case kPPC_ExtendSignWord16:
   1161       __ extsh(i.OutputRegister(), i.InputRegister(0));
   1162       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1163       break;
   1164 #if V8_TARGET_ARCH_PPC64
   1165     case kPPC_ExtendSignWord32:
   1166       __ extsw(i.OutputRegister(), i.InputRegister(0));
   1167       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1168       break;
   1169     case kPPC_Uint32ToUint64:
   1170       // Zero extend
   1171       __ clrldi(i.OutputRegister(), i.InputRegister(0), Operand(32));
   1172       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1173       break;
   1174     case kPPC_Int64ToInt32:
   1175       __ extsw(i.OutputRegister(), i.InputRegister(0));
   1176       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1177       break;
   1178     case kPPC_Int64ToFloat32:
   1179       __ ConvertInt64ToFloat(i.InputRegister(0), i.OutputDoubleRegister());
   1180       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1181       break;
   1182     case kPPC_Int64ToDouble:
   1183       __ ConvertInt64ToDouble(i.InputRegister(0), i.OutputDoubleRegister());
   1184       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1185       break;
   1186     case kPPC_Uint64ToFloat32:
   1187       __ ConvertUnsignedInt64ToFloat(i.InputRegister(0),
   1188                                      i.OutputDoubleRegister());
   1189       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1190       break;
   1191     case kPPC_Uint64ToDouble:
   1192       __ ConvertUnsignedInt64ToDouble(i.InputRegister(0),
   1193                                       i.OutputDoubleRegister());
   1194       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1195       break;
   1196 #endif
   1197     case kPPC_Int32ToDouble:
   1198       __ ConvertIntToDouble(i.InputRegister(0), i.OutputDoubleRegister());
   1199       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1200       break;
   1201     case kPPC_Uint32ToDouble:
   1202       __ ConvertUnsignedIntToDouble(i.InputRegister(0),
   1203                                     i.OutputDoubleRegister());
   1204       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1205       break;
   1206     case kPPC_DoubleToInt32:
   1207     case kPPC_DoubleToUint32:
   1208     case kPPC_DoubleToInt64: {
   1209 #if V8_TARGET_ARCH_PPC64
   1210       bool check_conversion =
   1211           (opcode == kPPC_DoubleToInt64 && i.OutputCount() > 1);
   1212       if (check_conversion) {
   1213         __ mtfsb0(VXCVI);  // clear FPSCR:VXCVI bit
   1214       }
   1215 #endif
   1216       __ ConvertDoubleToInt64(i.InputDoubleRegister(0),
   1217 #if !V8_TARGET_ARCH_PPC64
   1218                               kScratchReg,
   1219 #endif
   1220                               i.OutputRegister(0), kScratchDoubleReg);
   1221 #if V8_TARGET_ARCH_PPC64
   1222       if (check_conversion) {
   1223         // Set 2nd output to zero if conversion fails.
   1224         CRegister cr = cr7;
   1225         int crbit = v8::internal::Assembler::encode_crbit(
   1226             cr, static_cast<CRBit>(VXCVI % CRWIDTH));
   1227         __ mcrfs(cr, VXCVI);  // extract FPSCR field containing VXCVI into cr7
   1228         if (CpuFeatures::IsSupported(ISELECT)) {
   1229           __ li(i.OutputRegister(1), Operand(1));
   1230           __ isel(i.OutputRegister(1), r0, i.OutputRegister(1), crbit);
   1231         } else {
   1232           __ li(i.OutputRegister(1), Operand::Zero());
   1233           __ bc(v8::internal::Assembler::kInstrSize * 2, BT, crbit);
   1234           __ li(i.OutputRegister(1), Operand(1));
   1235         }
   1236       }
   1237 #endif
   1238       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1239       break;
   1240     }
   1241 #if V8_TARGET_ARCH_PPC64
   1242     case kPPC_DoubleToUint64: {
   1243       bool check_conversion = (i.OutputCount() > 1);
   1244       if (check_conversion) {
   1245         __ mtfsb0(VXCVI);  // clear FPSCR:VXCVI bit
   1246       }
   1247       __ ConvertDoubleToUnsignedInt64(i.InputDoubleRegister(0),
   1248                                       i.OutputRegister(0), kScratchDoubleReg);
   1249       if (check_conversion) {
   1250         // Set 2nd output to zero if conversion fails.
   1251         CRegister cr = cr7;
   1252         int crbit = v8::internal::Assembler::encode_crbit(
   1253             cr, static_cast<CRBit>(VXCVI % CRWIDTH));
   1254         __ mcrfs(cr, VXCVI);  // extract FPSCR field containing VXCVI into cr7
   1255         if (CpuFeatures::IsSupported(ISELECT)) {
   1256           __ li(i.OutputRegister(1), Operand(1));
   1257           __ isel(i.OutputRegister(1), r0, i.OutputRegister(1), crbit);
   1258         } else {
   1259           __ li(i.OutputRegister(1), Operand::Zero());
   1260           __ bc(v8::internal::Assembler::kInstrSize * 2, BT, crbit);
   1261           __ li(i.OutputRegister(1), Operand(1));
   1262         }
   1263       }
   1264       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1265       break;
   1266     }
   1267 #endif
   1268     case kPPC_DoubleToFloat32:
   1269       ASSEMBLE_FLOAT_UNOP_RC(frsp);
   1270       break;
   1271     case kPPC_Float32ToDouble:
   1272       // Nothing to do.
   1273       __ Move(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
   1274       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1275       break;
   1276     case kPPC_DoubleExtractLowWord32:
   1277       __ MovDoubleLowToInt(i.OutputRegister(), i.InputDoubleRegister(0));
   1278       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1279       break;
   1280     case kPPC_DoubleExtractHighWord32:
   1281       __ MovDoubleHighToInt(i.OutputRegister(), i.InputDoubleRegister(0));
   1282       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1283       break;
   1284     case kPPC_DoubleInsertLowWord32:
   1285       __ InsertDoubleLow(i.OutputDoubleRegister(), i.InputRegister(1), r0);
   1286       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1287       break;
   1288     case kPPC_DoubleInsertHighWord32:
   1289       __ InsertDoubleHigh(i.OutputDoubleRegister(), i.InputRegister(1), r0);
   1290       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1291       break;
   1292     case kPPC_DoubleConstruct:
   1293 #if V8_TARGET_ARCH_PPC64
   1294       __ MovInt64ComponentsToDouble(i.OutputDoubleRegister(),
   1295                                     i.InputRegister(0), i.InputRegister(1), r0);
   1296 #else
   1297       __ MovInt64ToDouble(i.OutputDoubleRegister(), i.InputRegister(0),
   1298                           i.InputRegister(1));
   1299 #endif
   1300       DCHECK_EQ(LeaveRC, i.OutputRCBit());
   1301       break;
   1302     case kPPC_BitcastFloat32ToInt32:
   1303       __ MovFloatToInt(i.OutputRegister(), i.InputDoubleRegister(0));
   1304       break;
   1305     case kPPC_BitcastInt32ToFloat32:
   1306       __ MovIntToFloat(i.OutputDoubleRegister(), i.InputRegister(0));
   1307       break;
   1308 #if V8_TARGET_ARCH_PPC64
   1309     case kPPC_BitcastDoubleToInt64:
   1310       __ MovDoubleToInt64(i.OutputRegister(), i.InputDoubleRegister(0));
   1311       break;
   1312     case kPPC_BitcastInt64ToDouble:
   1313       __ MovInt64ToDouble(i.OutputDoubleRegister(), i.InputRegister(0));
   1314       break;
   1315 #endif
   1316     case kPPC_LoadWordU8:
   1317       ASSEMBLE_LOAD_INTEGER(lbz, lbzx);
   1318       break;
   1319     case kPPC_LoadWordS8:
   1320       ASSEMBLE_LOAD_INTEGER(lbz, lbzx);
   1321       __ extsb(i.OutputRegister(), i.OutputRegister());
   1322       break;
   1323     case kPPC_LoadWordU16:
   1324       ASSEMBLE_LOAD_INTEGER(lhz, lhzx);
   1325       break;
   1326     case kPPC_LoadWordS16:
   1327       ASSEMBLE_LOAD_INTEGER(lha, lhax);
   1328       break;
   1329     case kPPC_LoadWordS32:
   1330       ASSEMBLE_LOAD_INTEGER(lwa, lwax);
   1331       break;
   1332 #if V8_TARGET_ARCH_PPC64
   1333     case kPPC_LoadWord64:
   1334       ASSEMBLE_LOAD_INTEGER(ld, ldx);
   1335       break;
   1336 #endif
   1337     case kPPC_LoadFloat32:
   1338       ASSEMBLE_LOAD_FLOAT(lfs, lfsx);
   1339       break;
   1340     case kPPC_LoadDouble:
   1341       ASSEMBLE_LOAD_FLOAT(lfd, lfdx);
   1342       break;
   1343     case kPPC_StoreWord8:
   1344       ASSEMBLE_STORE_INTEGER(stb, stbx);
   1345       break;
   1346     case kPPC_StoreWord16:
   1347       ASSEMBLE_STORE_INTEGER(sth, sthx);
   1348       break;
   1349     case kPPC_StoreWord32:
   1350       ASSEMBLE_STORE_INTEGER(stw, stwx);
   1351       break;
   1352 #if V8_TARGET_ARCH_PPC64
   1353     case kPPC_StoreWord64:
   1354       ASSEMBLE_STORE_INTEGER(std, stdx);
   1355       break;
   1356 #endif
   1357     case kPPC_StoreFloat32:
   1358       ASSEMBLE_STORE_FLOAT32();
   1359       break;
   1360     case kPPC_StoreDouble:
   1361       ASSEMBLE_STORE_DOUBLE();
   1362       break;
   1363     case kCheckedLoadInt8:
   1364       ASSEMBLE_CHECKED_LOAD_INTEGER(lbz, lbzx);
   1365       __ extsb(i.OutputRegister(), i.OutputRegister());
   1366       break;
   1367     case kCheckedLoadUint8:
   1368       ASSEMBLE_CHECKED_LOAD_INTEGER(lbz, lbzx);
   1369       break;
   1370     case kCheckedLoadInt16:
   1371       ASSEMBLE_CHECKED_LOAD_INTEGER(lha, lhax);
   1372       break;
   1373     case kCheckedLoadUint16:
   1374       ASSEMBLE_CHECKED_LOAD_INTEGER(lhz, lhzx);
   1375       break;
   1376     case kCheckedLoadWord32:
   1377       ASSEMBLE_CHECKED_LOAD_INTEGER(lwa, lwax);
   1378       break;
   1379     case kCheckedLoadWord64:
   1380 #if V8_TARGET_ARCH_PPC64
   1381       ASSEMBLE_CHECKED_LOAD_INTEGER(ld, ldx);
   1382 #else
   1383       UNREACHABLE();
   1384 #endif
   1385       break;
   1386     case kCheckedLoadFloat32:
   1387       ASSEMBLE_CHECKED_LOAD_FLOAT(lfs, lfsx, 32);
   1388       break;
   1389     case kCheckedLoadFloat64:
   1390       ASSEMBLE_CHECKED_LOAD_FLOAT(lfd, lfdx, 64);
   1391       break;
   1392     case kCheckedStoreWord8:
   1393       ASSEMBLE_CHECKED_STORE_INTEGER(stb, stbx);
   1394       break;
   1395     case kCheckedStoreWord16:
   1396       ASSEMBLE_CHECKED_STORE_INTEGER(sth, sthx);
   1397       break;
   1398     case kCheckedStoreWord32:
   1399       ASSEMBLE_CHECKED_STORE_INTEGER(stw, stwx);
   1400       break;
   1401     case kCheckedStoreWord64:
   1402 #if V8_TARGET_ARCH_PPC64
   1403       ASSEMBLE_CHECKED_STORE_INTEGER(std, stdx);
   1404 #else
   1405       UNREACHABLE();
   1406 #endif
   1407       break;
   1408     case kCheckedStoreFloat32:
   1409       ASSEMBLE_CHECKED_STORE_FLOAT32();
   1410       break;
   1411     case kCheckedStoreFloat64:
   1412       ASSEMBLE_CHECKED_STORE_DOUBLE();
   1413       break;
   1414     default:
   1415       UNREACHABLE();
   1416       break;
   1417   }
   1418 }  // NOLINT(readability/fn_size)
   1419 
   1420 
   1421 // Assembles branches after an instruction.
   1422 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
   1423   PPCOperandConverter i(this, instr);
   1424   Label* tlabel = branch->true_label;
   1425   Label* flabel = branch->false_label;
   1426   ArchOpcode op = instr->arch_opcode();
   1427   FlagsCondition condition = branch->condition;
   1428   CRegister cr = cr0;
   1429 
   1430   Condition cond = FlagsConditionToCondition(condition, op);
   1431   if (op == kPPC_CmpDouble) {
   1432     // check for unordered if necessary
   1433     if (cond == le) {
   1434       __ bunordered(flabel, cr);
   1435       // Unnecessary for eq/lt since only FU bit will be set.
   1436     } else if (cond == gt) {
   1437       __ bunordered(tlabel, cr);
   1438       // Unnecessary for ne/ge since only FU bit will be set.
   1439     }
   1440   }
   1441   __ b(cond, tlabel, cr);
   1442   if (!branch->fallthru) __ b(flabel);  // no fallthru to flabel.
   1443 }
   1444 
   1445 
   1446 void CodeGenerator::AssembleArchJump(RpoNumber target) {
   1447   if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
   1448 }
   1449 
   1450 
   1451 // Assembles boolean materializations after an instruction.
   1452 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
   1453                                         FlagsCondition condition) {
   1454   PPCOperandConverter i(this, instr);
   1455   Label done;
   1456   ArchOpcode op = instr->arch_opcode();
   1457   CRegister cr = cr0;
   1458   int reg_value = -1;
   1459 
   1460   // Materialize a full 32-bit 1 or 0 value. The result register is always the
   1461   // last output of the instruction.
   1462   DCHECK_NE(0u, instr->OutputCount());
   1463   Register reg = i.OutputRegister(instr->OutputCount() - 1);
   1464 
   1465   Condition cond = FlagsConditionToCondition(condition, op);
   1466   if (op == kPPC_CmpDouble) {
   1467     // check for unordered if necessary
   1468     if (cond == le) {
   1469       reg_value = 0;
   1470       __ li(reg, Operand::Zero());
   1471       __ bunordered(&done, cr);
   1472     } else if (cond == gt) {
   1473       reg_value = 1;
   1474       __ li(reg, Operand(1));
   1475       __ bunordered(&done, cr);
   1476     }
   1477     // Unnecessary for eq/lt & ne/ge since only FU bit will be set.
   1478   }
   1479 
   1480   if (CpuFeatures::IsSupported(ISELECT)) {
   1481     switch (cond) {
   1482       case eq:
   1483       case lt:
   1484       case gt:
   1485         if (reg_value != 1) __ li(reg, Operand(1));
   1486         __ li(kScratchReg, Operand::Zero());
   1487         __ isel(cond, reg, reg, kScratchReg, cr);
   1488         break;
   1489       case ne:
   1490       case ge:
   1491       case le:
   1492         if (reg_value != 1) __ li(reg, Operand(1));
   1493         // r0 implies logical zero in this form
   1494         __ isel(NegateCondition(cond), reg, r0, reg, cr);
   1495         break;
   1496     default:
   1497       UNREACHABLE();
   1498       break;
   1499     }
   1500   } else {
   1501     if (reg_value != 0) __ li(reg, Operand::Zero());
   1502     __ b(NegateCondition(cond), &done, cr);
   1503     __ li(reg, Operand(1));
   1504   }
   1505   __ bind(&done);
   1506 }
   1507 
   1508 
   1509 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
   1510   PPCOperandConverter i(this, instr);
   1511   Register input = i.InputRegister(0);
   1512   for (size_t index = 2; index < instr->InputCount(); index += 2) {
   1513     __ Cmpi(input, Operand(i.InputInt32(index + 0)), r0);
   1514     __ beq(GetLabel(i.InputRpo(index + 1)));
   1515   }
   1516   AssembleArchJump(i.InputRpo(1));
   1517 }
   1518 
   1519 
   1520 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
   1521   PPCOperandConverter i(this, instr);
   1522   Register input = i.InputRegister(0);
   1523   int32_t const case_count = static_cast<int32_t>(instr->InputCount() - 2);
   1524   Label** cases = zone()->NewArray<Label*>(case_count);
   1525   for (int32_t index = 0; index < case_count; ++index) {
   1526     cases[index] = GetLabel(i.InputRpo(index + 2));
   1527   }
   1528   Label* const table = AddJumpTable(cases, case_count);
   1529   __ Cmpli(input, Operand(case_count), r0);
   1530   __ bge(GetLabel(i.InputRpo(1)));
   1531   __ mov_label_addr(kScratchReg, table);
   1532   __ ShiftLeftImm(r0, input, Operand(kPointerSizeLog2));
   1533   __ LoadPX(kScratchReg, MemOperand(kScratchReg, r0));
   1534   __ Jump(kScratchReg);
   1535 }
   1536 
   1537 
   1538 void CodeGenerator::AssembleDeoptimizerCall(
   1539     int deoptimization_id, Deoptimizer::BailoutType bailout_type) {
   1540   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
   1541       isolate(), deoptimization_id, bailout_type);
   1542   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
   1543 }
   1544 
   1545 
   1546 void CodeGenerator::AssemblePrologue() {
   1547   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   1548   if (descriptor->IsCFunctionCall()) {
   1549     __ function_descriptor();
   1550     __ mflr(r0);
   1551     if (FLAG_enable_embedded_constant_pool) {
   1552       __ Push(r0, fp, kConstantPoolRegister);
   1553       // Adjust FP to point to saved FP.
   1554       __ subi(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset));
   1555     } else {
   1556       __ Push(r0, fp);
   1557       __ mr(fp, sp);
   1558     }
   1559   } else if (descriptor->IsJSFunctionCall()) {
   1560     __ Prologue(this->info()->GeneratePreagedPrologue(), ip);
   1561   } else if (frame()->needs_frame()) {
   1562     if (!ABI_CALL_VIA_IP && info()->output_code_kind() == Code::WASM_FUNCTION) {
   1563       // TODO(mbrandy): Restrict only to the wasm wrapper case.
   1564       __ StubPrologue();
   1565     } else {
   1566       __ StubPrologue(ip);
   1567     }
   1568   } else {
   1569     frame()->SetElidedFrameSizeInSlots(0);
   1570   }
   1571   frame_access_state()->SetFrameAccessToDefault();
   1572 
   1573   int stack_shrink_slots = frame()->GetSpillSlotCount();
   1574   if (info()->is_osr()) {
   1575     // TurboFan OSR-compiled functions cannot be entered directly.
   1576     __ Abort(kShouldNotDirectlyEnterOsrFunction);
   1577 
   1578     // Unoptimized code jumps directly to this entrypoint while the unoptimized
   1579     // frame is still on the stack. Optimized code uses OSR values directly from
   1580     // the unoptimized frame. Thus, all that needs to be done is to allocate the
   1581     // remaining stack slots.
   1582     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
   1583     osr_pc_offset_ = __ pc_offset();
   1584     // TODO(titzer): cannot address target function == local #-1
   1585     __ LoadP(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
   1586     stack_shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
   1587   }
   1588 
   1589   const RegList double_saves = descriptor->CalleeSavedFPRegisters();
   1590   if (double_saves != 0) {
   1591     stack_shrink_slots += frame()->AlignSavedCalleeRegisterSlots();
   1592   }
   1593   if (stack_shrink_slots > 0) {
   1594     __ Add(sp, sp, -stack_shrink_slots * kPointerSize, r0);
   1595   }
   1596 
   1597   // Save callee-saved Double registers.
   1598   if (double_saves != 0) {
   1599     __ MultiPushDoubles(double_saves);
   1600     DCHECK(kNumCalleeSavedDoubles ==
   1601            base::bits::CountPopulation32(double_saves));
   1602     frame()->AllocateSavedCalleeRegisterSlots(kNumCalleeSavedDoubles *
   1603                                               (kDoubleSize / kPointerSize));
   1604   }
   1605 
   1606   // Save callee-saved registers.
   1607   const RegList saves =
   1608       FLAG_enable_embedded_constant_pool
   1609           ? descriptor->CalleeSavedRegisters() & ~kConstantPoolRegister.bit()
   1610           : descriptor->CalleeSavedRegisters();
   1611   if (saves != 0) {
   1612     __ MultiPush(saves);
   1613     // register save area does not include the fp or constant pool pointer.
   1614     const int num_saves =
   1615         kNumCalleeSaved - 1 - (FLAG_enable_embedded_constant_pool ? 1 : 0);
   1616     DCHECK(num_saves == base::bits::CountPopulation32(saves));
   1617     frame()->AllocateSavedCalleeRegisterSlots(num_saves);
   1618   }
   1619 }
   1620 
   1621 
   1622 void CodeGenerator::AssembleReturn() {
   1623   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
   1624   int pop_count = static_cast<int>(descriptor->StackParameterCount());
   1625 
   1626   // Restore registers.
   1627   const RegList saves =
   1628       FLAG_enable_embedded_constant_pool
   1629           ? descriptor->CalleeSavedRegisters() & ~kConstantPoolRegister.bit()
   1630           : descriptor->CalleeSavedRegisters();
   1631   if (saves != 0) {
   1632     __ MultiPop(saves);
   1633   }
   1634 
   1635   // Restore double registers.
   1636   const RegList double_saves = descriptor->CalleeSavedFPRegisters();
   1637   if (double_saves != 0) {
   1638     __ MultiPopDoubles(double_saves);
   1639   }
   1640 
   1641   if (descriptor->IsCFunctionCall()) {
   1642     __ LeaveFrame(StackFrame::MANUAL, pop_count * kPointerSize);
   1643   } else if (frame()->needs_frame()) {
   1644     // Canonicalize JSFunction return sites for now.
   1645     if (return_label_.is_bound()) {
   1646       __ b(&return_label_);
   1647       return;
   1648     } else {
   1649       __ bind(&return_label_);
   1650       __ LeaveFrame(StackFrame::MANUAL, pop_count * kPointerSize);
   1651     }
   1652   } else {
   1653     __ Drop(pop_count);
   1654   }
   1655   __ Ret();
   1656 }
   1657 
   1658 
   1659 void CodeGenerator::AssembleMove(InstructionOperand* source,
   1660                                  InstructionOperand* destination) {
   1661   PPCOperandConverter g(this, nullptr);
   1662   // Dispatch on the source and destination operand kinds.  Not all
   1663   // combinations are possible.
   1664   if (source->IsRegister()) {
   1665     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   1666     Register src = g.ToRegister(source);
   1667     if (destination->IsRegister()) {
   1668       __ Move(g.ToRegister(destination), src);
   1669     } else {
   1670       __ StoreP(src, g.ToMemOperand(destination), r0);
   1671     }
   1672   } else if (source->IsStackSlot()) {
   1673     DCHECK(destination->IsRegister() || destination->IsStackSlot());
   1674     MemOperand src = g.ToMemOperand(source);
   1675     if (destination->IsRegister()) {
   1676       __ LoadP(g.ToRegister(destination), src, r0);
   1677     } else {
   1678       Register temp = kScratchReg;
   1679       __ LoadP(temp, src, r0);
   1680       __ StoreP(temp, g.ToMemOperand(destination), r0);
   1681     }
   1682   } else if (source->IsConstant()) {
   1683     Constant src = g.ToConstant(source);
   1684     if (destination->IsRegister() || destination->IsStackSlot()) {
   1685       Register dst =
   1686           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
   1687       switch (src.type()) {
   1688         case Constant::kInt32:
   1689           __ mov(dst, Operand(src.ToInt32()));
   1690           break;
   1691         case Constant::kInt64:
   1692           __ mov(dst, Operand(src.ToInt64()));
   1693           break;
   1694         case Constant::kFloat32:
   1695           __ Move(dst,
   1696                   isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
   1697           break;
   1698         case Constant::kFloat64:
   1699           __ Move(dst,
   1700                   isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
   1701           break;
   1702         case Constant::kExternalReference:
   1703           __ mov(dst, Operand(src.ToExternalReference()));
   1704           break;
   1705         case Constant::kHeapObject: {
   1706           Handle<HeapObject> src_object = src.ToHeapObject();
   1707           Heap::RootListIndex index;
   1708           int offset;
   1709           if (IsMaterializableFromFrame(src_object, &offset)) {
   1710             __ LoadP(dst, MemOperand(fp, offset));
   1711           } else if (IsMaterializableFromRoot(src_object, &index)) {
   1712             __ LoadRoot(dst, index);
   1713           } else {
   1714             __ Move(dst, src_object);
   1715           }
   1716           break;
   1717         }
   1718         case Constant::kRpoNumber:
   1719           UNREACHABLE();  // TODO(dcarney): loading RPO constants on PPC.
   1720           break;
   1721       }
   1722       if (destination->IsStackSlot()) {
   1723         __ StoreP(dst, g.ToMemOperand(destination), r0);
   1724       }
   1725     } else {
   1726       DoubleRegister dst = destination->IsDoubleRegister()
   1727                                ? g.ToDoubleRegister(destination)
   1728                                : kScratchDoubleReg;
   1729       double value = (src.type() == Constant::kFloat32) ? src.ToFloat32()
   1730                                                         : src.ToFloat64();
   1731       __ LoadDoubleLiteral(dst, value, kScratchReg);
   1732       if (destination->IsDoubleStackSlot()) {
   1733         __ StoreDouble(dst, g.ToMemOperand(destination), r0);
   1734       }
   1735     }
   1736   } else if (source->IsDoubleRegister()) {
   1737     DoubleRegister src = g.ToDoubleRegister(source);
   1738     if (destination->IsDoubleRegister()) {
   1739       DoubleRegister dst = g.ToDoubleRegister(destination);
   1740       __ Move(dst, src);
   1741     } else {
   1742       DCHECK(destination->IsDoubleStackSlot());
   1743       __ StoreDouble(src, g.ToMemOperand(destination), r0);
   1744     }
   1745   } else if (source->IsDoubleStackSlot()) {
   1746     DCHECK(destination->IsDoubleRegister() || destination->IsDoubleStackSlot());
   1747     MemOperand src = g.ToMemOperand(source);
   1748     if (destination->IsDoubleRegister()) {
   1749       __ LoadDouble(g.ToDoubleRegister(destination), src, r0);
   1750     } else {
   1751       DoubleRegister temp = kScratchDoubleReg;
   1752       __ LoadDouble(temp, src, r0);
   1753       __ StoreDouble(temp, g.ToMemOperand(destination), r0);
   1754     }
   1755   } else {
   1756     UNREACHABLE();
   1757   }
   1758 }
   1759 
   1760 
   1761 void CodeGenerator::AssembleSwap(InstructionOperand* source,
   1762                                  InstructionOperand* destination) {
   1763   PPCOperandConverter g(this, nullptr);
   1764   // Dispatch on the source and destination operand kinds.  Not all
   1765   // combinations are possible.
   1766   if (source->IsRegister()) {
   1767     // Register-register.
   1768     Register temp = kScratchReg;
   1769     Register src = g.ToRegister(source);
   1770     if (destination->IsRegister()) {
   1771       Register dst = g.ToRegister(destination);
   1772       __ mr(temp, src);
   1773       __ mr(src, dst);
   1774       __ mr(dst, temp);
   1775     } else {
   1776       DCHECK(destination->IsStackSlot());
   1777       MemOperand dst = g.ToMemOperand(destination);
   1778       __ mr(temp, src);
   1779       __ LoadP(src, dst);
   1780       __ StoreP(temp, dst);
   1781     }
   1782 #if V8_TARGET_ARCH_PPC64
   1783   } else if (source->IsStackSlot() || source->IsDoubleStackSlot()) {
   1784 #else
   1785   } else if (source->IsStackSlot()) {
   1786     DCHECK(destination->IsStackSlot());
   1787 #endif
   1788     Register temp_0 = kScratchReg;
   1789     Register temp_1 = r0;
   1790     MemOperand src = g.ToMemOperand(source);
   1791     MemOperand dst = g.ToMemOperand(destination);
   1792     __ LoadP(temp_0, src);
   1793     __ LoadP(temp_1, dst);
   1794     __ StoreP(temp_0, dst);
   1795     __ StoreP(temp_1, src);
   1796   } else if (source->IsDoubleRegister()) {
   1797     DoubleRegister temp = kScratchDoubleReg;
   1798     DoubleRegister src = g.ToDoubleRegister(source);
   1799     if (destination->IsDoubleRegister()) {
   1800       DoubleRegister dst = g.ToDoubleRegister(destination);
   1801       __ fmr(temp, src);
   1802       __ fmr(src, dst);
   1803       __ fmr(dst, temp);
   1804     } else {
   1805       DCHECK(destination->IsDoubleStackSlot());
   1806       MemOperand dst = g.ToMemOperand(destination);
   1807       __ fmr(temp, src);
   1808       __ lfd(src, dst);
   1809       __ stfd(temp, dst);
   1810     }
   1811 #if !V8_TARGET_ARCH_PPC64
   1812   } else if (source->IsDoubleStackSlot()) {
   1813     DCHECK(destination->IsDoubleStackSlot());
   1814     DoubleRegister temp_0 = kScratchDoubleReg;
   1815     DoubleRegister temp_1 = d0;
   1816     MemOperand src = g.ToMemOperand(source);
   1817     MemOperand dst = g.ToMemOperand(destination);
   1818     __ lfd(temp_0, src);
   1819     __ lfd(temp_1, dst);
   1820     __ stfd(temp_0, dst);
   1821     __ stfd(temp_1, src);
   1822 #endif
   1823   } else {
   1824     // No other combinations are possible.
   1825     UNREACHABLE();
   1826   }
   1827 }
   1828 
   1829 
   1830 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
   1831   for (size_t index = 0; index < target_count; ++index) {
   1832     __ emit_label_addr(targets[index]);
   1833   }
   1834 }
   1835 
   1836 
   1837 void CodeGenerator::AddNopForSmiCodeInlining() {
   1838   // We do not insert nops for inlined Smi code.
   1839 }
   1840 
   1841 
   1842 void CodeGenerator::EnsureSpaceForLazyDeopt() {
   1843   if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
   1844     return;
   1845   }
   1846 
   1847   int space_needed = Deoptimizer::patch_size();
   1848   // Ensure that we have enough space after the previous lazy-bailout
   1849   // instruction for patching the code here.
   1850   int current_pc = masm()->pc_offset();
   1851   if (current_pc < last_lazy_deopt_pc_ + space_needed) {
   1852     // Block tramoline pool emission for duration of padding.
   1853     v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
   1854         masm());
   1855     int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
   1856     DCHECK_EQ(0, padding_size % v8::internal::Assembler::kInstrSize);
   1857     while (padding_size > 0) {
   1858       __ nop();
   1859       padding_size -= v8::internal::Assembler::kInstrSize;
   1860     }
   1861   }
   1862 }
   1863 
   1864 #undef __
   1865 
   1866 }  // namespace compiler
   1867 }  // namespace internal
   1868 }  // namespace v8
   1869