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/base/numbers/double.h"
6 #include "src/codegen/assembler-inl.h"
7 #include "src/codegen/callable.h"
8 #include "src/codegen/macro-assembler.h"
9 #include "src/codegen/optimized-compilation-info.h"
10 #include "src/compiler/backend/code-generator-impl.h"
11 #include "src/compiler/backend/code-generator.h"
12 #include "src/compiler/backend/gap-resolver.h"
13 #include "src/compiler/node-matchers.h"
14 #include "src/compiler/osr.h"
15 #include "src/heap/memory-chunk.h"
16 
17 #if V8_ENABLE_WEBASSEMBLY
18 #include "src/wasm/wasm-code-manager.h"
19 #include "src/wasm/wasm-objects.h"
20 #endif  // V8_ENABLE_WEBASSEMBLY
21 
22 namespace v8 {
23 namespace internal {
24 namespace compiler {
25 
26 #define __ tasm()->
27 
28 #define kScratchReg r11
29 
30 // Adds PPC-specific methods to convert InstructionOperands.
31 class PPCOperandConverter final : public InstructionOperandConverter {
32  public:
PPCOperandConverter(CodeGenerator * gen,Instruction * instr)33   PPCOperandConverter(CodeGenerator* gen, Instruction* instr)
34       : InstructionOperandConverter(gen, instr) {}
35 
OutputCount()36   size_t OutputCount() { return instr_->OutputCount(); }
37 
OutputRCBit() const38   RCBit OutputRCBit() const {
39     switch (instr_->flags_mode()) {
40       case kFlags_branch:
41       case kFlags_deoptimize:
42       case kFlags_set:
43       case kFlags_trap:
44       case kFlags_select:
45         return SetRC;
46       case kFlags_none:
47         return LeaveRC;
48     }
49     UNREACHABLE();
50   }
51 
CompareLogical() const52   bool CompareLogical() const {
53     switch (instr_->flags_condition()) {
54       case kUnsignedLessThan:
55       case kUnsignedGreaterThanOrEqual:
56       case kUnsignedLessThanOrEqual:
57       case kUnsignedGreaterThan:
58         return true;
59       default:
60         return false;
61     }
62     UNREACHABLE();
63   }
64 
InputImmediate(size_t index)65   Operand InputImmediate(size_t index) {
66     Constant constant = ToConstant(instr_->InputAt(index));
67     switch (constant.type()) {
68       case Constant::kInt32:
69         return Operand(constant.ToInt32());
70       case Constant::kFloat32:
71         return Operand::EmbeddedNumber(constant.ToFloat32());
72       case Constant::kFloat64:
73         return Operand::EmbeddedNumber(constant.ToFloat64().value());
74       case Constant::kInt64:
75 #if V8_TARGET_ARCH_PPC64
76         return Operand(constant.ToInt64());
77 #endif
78       case Constant::kExternalReference:
79         return Operand(constant.ToExternalReference());
80       case Constant::kDelayedStringConstant:
81         return Operand::EmbeddedStringConstant(
82             constant.ToDelayedStringConstant());
83       case Constant::kCompressedHeapObject:
84       case Constant::kHeapObject:
85       case Constant::kRpoNumber:
86         break;
87     }
88     UNREACHABLE();
89   }
90 
MemoryOperand(AddressingMode * mode,size_t * first_index)91   MemOperand MemoryOperand(AddressingMode* mode, size_t* first_index) {
92     const size_t index = *first_index;
93     AddressingMode addr_mode = AddressingModeField::decode(instr_->opcode());
94     if (mode) *mode = addr_mode;
95     switch (addr_mode) {
96       case kMode_None:
97         break;
98       case kMode_MRI:
99         *first_index += 2;
100         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
101       case kMode_MRR:
102         *first_index += 2;
103         return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
104     }
105     UNREACHABLE();
106   }
107 
MemoryOperand(AddressingMode * mode=NULL,size_t first_index=0)108   MemOperand MemoryOperand(AddressingMode* mode = NULL,
109                            size_t first_index = 0) {
110     return MemoryOperand(mode, &first_index);
111   }
112 
ToMemOperand(InstructionOperand * op) const113   MemOperand ToMemOperand(InstructionOperand* op) const {
114     DCHECK_NOT_NULL(op);
115     DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
116     return SlotToMemOperand(AllocatedOperand::cast(op)->index());
117   }
118 
SlotToMemOperand(int slot) const119   MemOperand SlotToMemOperand(int slot) const {
120     FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
121     return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
122   }
123 };
124 
HasRegisterInput(Instruction * instr,size_t index)125 static inline bool HasRegisterInput(Instruction* instr, size_t index) {
126   return instr->InputAt(index)->IsRegister();
127 }
128 
129 namespace {
130 
131 class OutOfLineRecordWrite final : public OutOfLineCode {
132  public:
OutOfLineRecordWrite(CodeGenerator * gen,Register object,Register offset,Register value,Register scratch0,Register scratch1,RecordWriteMode mode,StubCallMode stub_mode,UnwindingInfoWriter * unwinding_info_writer)133   OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register offset,
134                        Register value, Register scratch0, Register scratch1,
135                        RecordWriteMode mode, StubCallMode stub_mode,
136                        UnwindingInfoWriter* unwinding_info_writer)
137       : OutOfLineCode(gen),
138         object_(object),
139         offset_(offset),
140         offset_immediate_(0),
141         value_(value),
142         scratch0_(scratch0),
143         scratch1_(scratch1),
144         mode_(mode),
145 #if V8_ENABLE_WEBASSEMBLY
146         stub_mode_(stub_mode),
147 #endif  // V8_ENABLE_WEBASSEMBLY
148         must_save_lr_(!gen->frame_access_state()->has_frame()),
149         unwinding_info_writer_(unwinding_info_writer),
150         zone_(gen->zone()) {
151     DCHECK(!AreAliased(object, offset, scratch0, scratch1));
152     DCHECK(!AreAliased(value, offset, scratch0, scratch1));
153   }
154 
OutOfLineRecordWrite(CodeGenerator * gen,Register object,int32_t offset,Register value,Register scratch0,Register scratch1,RecordWriteMode mode,StubCallMode stub_mode,UnwindingInfoWriter * unwinding_info_writer)155   OutOfLineRecordWrite(CodeGenerator* gen, Register object, int32_t offset,
156                        Register value, Register scratch0, Register scratch1,
157                        RecordWriteMode mode, StubCallMode stub_mode,
158                        UnwindingInfoWriter* unwinding_info_writer)
159       : OutOfLineCode(gen),
160         object_(object),
161         offset_(no_reg),
162         offset_immediate_(offset),
163         value_(value),
164         scratch0_(scratch0),
165         scratch1_(scratch1),
166         mode_(mode),
167 #if V8_ENABLE_WEBASSEMBLY
168         stub_mode_(stub_mode),
169 #endif  // V8_ENABLE_WEBASSEMBLY
170         must_save_lr_(!gen->frame_access_state()->has_frame()),
171         unwinding_info_writer_(unwinding_info_writer),
172         zone_(gen->zone()) {
173   }
174 
Generate()175   void Generate() final {
176     ConstantPoolUnavailableScope constant_pool_unavailable(tasm());
177     if (COMPRESS_POINTERS_BOOL) {
178       __ DecompressTaggedPointer(value_, value_);
179     }
180     __ CheckPageFlag(value_, scratch0_,
181                      MemoryChunk::kPointersToHereAreInterestingMask, eq,
182                      exit());
183     if (offset_ == no_reg) {
184       __ addi(scratch1_, object_, Operand(offset_immediate_));
185     } else {
186       DCHECK_EQ(0, offset_immediate_);
187       __ add(scratch1_, object_, offset_);
188     }
189     RememberedSetAction const remembered_set_action =
190         mode_ > RecordWriteMode::kValueIsMap ? RememberedSetAction::kEmit
191                                              : RememberedSetAction::kOmit;
192     SaveFPRegsMode const save_fp_mode = frame()->DidAllocateDoubleRegisters()
193                                             ? SaveFPRegsMode::kSave
194                                             : SaveFPRegsMode::kIgnore;
195     if (must_save_lr_) {
196       // We need to save and restore lr if the frame was elided.
197       __ mflr(scratch0_);
198       __ Push(scratch0_);
199       unwinding_info_writer_->MarkLinkRegisterOnTopOfStack(__ pc_offset());
200     }
201     if (mode_ == RecordWriteMode::kValueIsEphemeronKey) {
202       __ CallEphemeronKeyBarrier(object_, scratch1_, save_fp_mode);
203 #if V8_ENABLE_WEBASSEMBLY
204     } else if (stub_mode_ == StubCallMode::kCallWasmRuntimeStub) {
205       __ CallRecordWriteStubSaveRegisters(object_, scratch1_,
206                                           remembered_set_action, save_fp_mode,
207                                           StubCallMode::kCallWasmRuntimeStub);
208 #endif  // V8_ENABLE_WEBASSEMBLY
209     } else {
210       __ CallRecordWriteStubSaveRegisters(object_, scratch1_,
211                                           remembered_set_action, save_fp_mode);
212     }
213     if (must_save_lr_) {
214       // We need to save and restore lr if the frame was elided.
215       __ Pop(scratch0_);
216       __ mtlr(scratch0_);
217       unwinding_info_writer_->MarkPopLinkRegisterFromTopOfStack(__ pc_offset());
218     }
219   }
220 
221  private:
222   Register const object_;
223   Register const offset_;
224   int32_t const offset_immediate_;  // Valid if offset_ == no_reg.
225   Register const value_;
226   Register const scratch0_;
227   Register const scratch1_;
228   RecordWriteMode const mode_;
229 #if V8_ENABLE_WEBASSEMBLY
230   StubCallMode stub_mode_;
231 #endif  // V8_ENABLE_WEBASSEMBLY
232   bool must_save_lr_;
233   UnwindingInfoWriter* const unwinding_info_writer_;
234   Zone* zone_;
235 };
236 
FlagsConditionToCondition(FlagsCondition condition,ArchOpcode op)237 Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) {
238   switch (condition) {
239     case kEqual:
240       return eq;
241     case kNotEqual:
242       return ne;
243     case kSignedLessThan:
244     case kUnsignedLessThan:
245       return lt;
246     case kSignedGreaterThanOrEqual:
247     case kUnsignedGreaterThanOrEqual:
248       return ge;
249     case kSignedLessThanOrEqual:
250     case kUnsignedLessThanOrEqual:
251       return le;
252     case kSignedGreaterThan:
253     case kUnsignedGreaterThan:
254       return gt;
255     case kOverflow:
256       // Overflow checked for add/sub only.
257       switch (op) {
258 #if V8_TARGET_ARCH_PPC64
259         case kPPC_Add32:
260         case kPPC_Add64:
261         case kPPC_Sub:
262 #endif
263         case kPPC_AddWithOverflow32:
264         case kPPC_SubWithOverflow32:
265           return lt;
266         default:
267           break;
268       }
269       break;
270     case kNotOverflow:
271       switch (op) {
272 #if V8_TARGET_ARCH_PPC64
273         case kPPC_Add32:
274         case kPPC_Add64:
275         case kPPC_Sub:
276 #endif
277         case kPPC_AddWithOverflow32:
278         case kPPC_SubWithOverflow32:
279           return ge;
280         default:
281           break;
282       }
283       break;
284     default:
285       break;
286   }
287   UNREACHABLE();
288 }
289 
290 }  // namespace
291 
292 #define ASSEMBLE_FLOAT_UNOP_RC(asm_instr, round)                     \
293   do {                                                               \
294     __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
295                  i.OutputRCBit());                                   \
296     if (round) {                                                     \
297       __ frsp(i.OutputDoubleRegister(), i.OutputDoubleRegister());   \
298     }                                                                \
299   } while (0)
300 
301 #define ASSEMBLE_FLOAT_BINOP_RC(asm_instr, round)                    \
302   do {                                                               \
303     __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
304                  i.InputDoubleRegister(1), i.OutputRCBit());         \
305     if (round) {                                                     \
306       __ frsp(i.OutputDoubleRegister(), i.OutputDoubleRegister());   \
307     }                                                                \
308   } while (0)
309 
310 #define ASSEMBLE_BINOP(asm_instr_reg, asm_instr_imm)           \
311   do {                                                         \
312     if (HasRegisterInput(instr, 1)) {                          \
313       __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \
314                        i.InputRegister(1));                    \
315     } else {                                                   \
316       __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \
317                        i.InputImmediate(1));                   \
318     }                                                          \
319   } while (0)
320 
321 #define ASSEMBLE_BINOP_RC(asm_instr_reg, asm_instr_imm)        \
322   do {                                                         \
323     if (HasRegisterInput(instr, 1)) {                          \
324       __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \
325                        i.InputRegister(1), i.OutputRCBit());   \
326     } else {                                                   \
327       __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \
328                        i.InputImmediate(1), i.OutputRCBit());  \
329     }                                                          \
330   } while (0)
331 
332 #define ASSEMBLE_BINOP_INT_RC(asm_instr_reg, asm_instr_imm)    \
333   do {                                                         \
334     if (HasRegisterInput(instr, 1)) {                          \
335       __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \
336                        i.InputRegister(1), i.OutputRCBit());   \
337     } else {                                                   \
338       __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \
339                        i.InputImmediate(1), i.OutputRCBit());  \
340     }                                                          \
341   } while (0)
342 
343 #define ASSEMBLE_ADD_WITH_OVERFLOW()                                    \
344   do {                                                                  \
345     if (HasRegisterInput(instr, 1)) {                                   \
346       __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
347                                 i.InputRegister(1), kScratchReg, r0);   \
348     } else {                                                            \
349       __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
350                                 i.InputInt32(1), kScratchReg, r0);      \
351     }                                                                   \
352   } while (0)
353 
354 #define ASSEMBLE_SUB_WITH_OVERFLOW()                                    \
355   do {                                                                  \
356     if (HasRegisterInput(instr, 1)) {                                   \
357       __ SubAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
358                                 i.InputRegister(1), kScratchReg, r0);   \
359     } else {                                                            \
360       __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
361                                 -i.InputInt32(1), kScratchReg, r0);     \
362     }                                                                   \
363   } while (0)
364 
365 #if V8_TARGET_ARCH_PPC64
366 #define ASSEMBLE_ADD_WITH_OVERFLOW32()         \
367   do {                                         \
368     ASSEMBLE_ADD_WITH_OVERFLOW();              \
369     __ extsw(kScratchReg, kScratchReg, SetRC); \
370   } while (0)
371 
372 #define ASSEMBLE_SUB_WITH_OVERFLOW32()         \
373   do {                                         \
374     ASSEMBLE_SUB_WITH_OVERFLOW();              \
375     __ extsw(kScratchReg, kScratchReg, SetRC); \
376   } while (0)
377 #else
378 #define ASSEMBLE_ADD_WITH_OVERFLOW32 ASSEMBLE_ADD_WITH_OVERFLOW
379 #define ASSEMBLE_SUB_WITH_OVERFLOW32 ASSEMBLE_SUB_WITH_OVERFLOW
380 #endif
381 
382 #define ASSEMBLE_COMPARE(cmp_instr, cmpl_instr)                        \
383   do {                                                                 \
384     const CRegister cr = cr0;                                          \
385     if (HasRegisterInput(instr, 1)) {                                  \
386       if (i.CompareLogical()) {                                        \
387         __ cmpl_instr(i.InputRegister(0), i.InputRegister(1), cr);     \
388       } else {                                                         \
389         __ cmp_instr(i.InputRegister(0), i.InputRegister(1), cr);      \
390       }                                                                \
391     } else {                                                           \
392       if (i.CompareLogical()) {                                        \
393         __ cmpl_instr##i(i.InputRegister(0), i.InputImmediate(1), cr); \
394       } else {                                                         \
395         __ cmp_instr##i(i.InputRegister(0), i.InputImmediate(1), cr);  \
396       }                                                                \
397     }                                                                  \
398     DCHECK_EQ(SetRC, i.OutputRCBit());                                 \
399   } while (0)
400 
401 #define ASSEMBLE_FLOAT_COMPARE(cmp_instr)                                 \
402   do {                                                                    \
403     const CRegister cr = cr0;                                             \
404     __ cmp_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1), cr); \
405     DCHECK_EQ(SetRC, i.OutputRCBit());                                    \
406   } while (0)
407 
408 #define ASSEMBLE_MODULO(div_instr, mul_instr)                        \
409   do {                                                               \
410     const Register scratch = kScratchReg;                            \
411     __ div_instr(scratch, i.InputRegister(0), i.InputRegister(1));   \
412     __ mul_instr(scratch, scratch, i.InputRegister(1));              \
413     __ sub(i.OutputRegister(), i.InputRegister(0), scratch, LeaveOE, \
414            i.OutputRCBit());                                         \
415   } while (0)
416 
417 #define ASSEMBLE_FLOAT_MODULO()                                             \
418   do {                                                                      \
419     FrameScope scope(tasm(), StackFrame::MANUAL);                           \
420     __ PrepareCallCFunction(0, 2, kScratchReg);                             \
421     __ MovToFloatParameters(i.InputDoubleRegister(0),                       \
422                             i.InputDoubleRegister(1));                      \
423     __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2); \
424     __ MovFromFloatResult(i.OutputDoubleRegister());                        \
425     DCHECK_EQ(LeaveRC, i.OutputRCBit());                                    \
426   } while (0)
427 
428 #define ASSEMBLE_IEEE754_UNOP(name)                                            \
429   do {                                                                         \
430     /* TODO(bmeurer): We should really get rid of this special instruction, */ \
431     /* and generate a CallAddress instruction instead. */                      \
432     FrameScope scope(tasm(), StackFrame::MANUAL);                              \
433     __ PrepareCallCFunction(0, 1, kScratchReg);                                \
434     __ MovToFloatParameter(i.InputDoubleRegister(0));                          \
435     __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 1);    \
436     /* Move the result in the double result register. */                       \
437     __ MovFromFloatResult(i.OutputDoubleRegister());                           \
438     DCHECK_EQ(LeaveRC, i.OutputRCBit());                                       \
439   } while (0)
440 
441 #define ASSEMBLE_IEEE754_BINOP(name)                                           \
442   do {                                                                         \
443     /* TODO(bmeurer): We should really get rid of this special instruction, */ \
444     /* and generate a CallAddress instruction instead. */                      \
445     FrameScope scope(tasm(), StackFrame::MANUAL);                              \
446     __ PrepareCallCFunction(0, 2, kScratchReg);                                \
447     __ MovToFloatParameters(i.InputDoubleRegister(0),                          \
448                             i.InputDoubleRegister(1));                         \
449     __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 2);    \
450     /* Move the result in the double result register. */                       \
451     __ MovFromFloatResult(i.OutputDoubleRegister());                           \
452     DCHECK_EQ(LeaveRC, i.OutputRCBit());                                       \
453   } while (0)
454 
455 #define ASSEMBLE_LOAD_FLOAT(asm_instr, asm_instrx)    \
456   do {                                                \
457     DoubleRegister result = i.OutputDoubleRegister(); \
458     AddressingMode mode = kMode_None;                 \
459     MemOperand operand = i.MemoryOperand(&mode);      \
460     bool is_atomic = i.InputInt32(2);                 \
461     if (mode == kMode_MRI) {                          \
462       __ asm_instr(result, operand);                  \
463     } else {                                          \
464       __ asm_instrx(result, operand);                 \
465     }                                                 \
466     if (is_atomic) __ lwsync();                       \
467     DCHECK_EQ(LeaveRC, i.OutputRCBit());              \
468   } while (0)
469 
470 #define ASSEMBLE_LOAD_INTEGER(asm_instr, asm_instrx) \
471   do {                                               \
472     Register result = i.OutputRegister();            \
473     AddressingMode mode = kMode_None;                \
474     MemOperand operand = i.MemoryOperand(&mode);     \
475     bool is_atomic = i.InputInt32(2);                \
476     if (mode == kMode_MRI) {                         \
477       __ asm_instr(result, operand);                 \
478     } else {                                         \
479       __ asm_instrx(result, operand);                \
480     }                                                \
481     if (is_atomic) __ lwsync();                      \
482     DCHECK_EQ(LeaveRC, i.OutputRCBit());             \
483   } while (0)
484 
485 #define ASSEMBLE_LOAD_INTEGER_RR(asm_instr)      \
486   do {                                           \
487     Register result = i.OutputRegister();        \
488     AddressingMode mode = kMode_None;            \
489     MemOperand operand = i.MemoryOperand(&mode); \
490     DCHECK_EQ(mode, kMode_MRR);                  \
491     bool is_atomic = i.InputInt32(2);            \
492     __ asm_instr(result, operand);               \
493     if (is_atomic) __ lwsync();                  \
494     DCHECK_EQ(LeaveRC, i.OutputRCBit());         \
495   } while (0)
496 
497 #define ASSEMBLE_STORE_FLOAT(asm_instr, asm_instrx)      \
498   do {                                                   \
499     size_t index = 0;                                    \
500     AddressingMode mode = kMode_None;                    \
501     MemOperand operand = i.MemoryOperand(&mode, &index); \
502     DoubleRegister value = i.InputDoubleRegister(index); \
503     bool is_atomic = i.InputInt32(3);                    \
504     if (is_atomic) __ lwsync();                          \
505     /* removed frsp as instruction-selector checked */   \
506     /* value to be kFloat32 */                           \
507     if (mode == kMode_MRI) {                             \
508       __ asm_instr(value, operand);                      \
509     } else {                                             \
510       __ asm_instrx(value, operand);                     \
511     }                                                    \
512     if (is_atomic) __ sync();                            \
513     DCHECK_EQ(LeaveRC, i.OutputRCBit());                 \
514   } while (0)
515 
516 #define ASSEMBLE_STORE_INTEGER(asm_instr, asm_instrx)    \
517   do {                                                   \
518     size_t index = 0;                                    \
519     AddressingMode mode = kMode_None;                    \
520     MemOperand operand = i.MemoryOperand(&mode, &index); \
521     Register value = i.InputRegister(index);             \
522     bool is_atomic = i.InputInt32(3);                    \
523     if (is_atomic) __ lwsync();                          \
524     if (mode == kMode_MRI) {                             \
525       __ asm_instr(value, operand);                      \
526     } else {                                             \
527       __ asm_instrx(value, operand);                     \
528     }                                                    \
529     if (is_atomic) __ sync();                            \
530     DCHECK_EQ(LeaveRC, i.OutputRCBit());                 \
531   } while (0)
532 
533 #define ASSEMBLE_STORE_INTEGER_RR(asm_instr)             \
534   do {                                                   \
535     size_t index = 0;                                    \
536     AddressingMode mode = kMode_None;                    \
537     MemOperand operand = i.MemoryOperand(&mode, &index); \
538     DCHECK_EQ(mode, kMode_MRR);                          \
539     Register value = i.InputRegister(index);             \
540     bool is_atomic = i.InputInt32(3);                    \
541     if (is_atomic) __ lwsync();                          \
542     __ asm_instr(value, operand);                        \
543     if (is_atomic) __ sync();                            \
544     DCHECK_EQ(LeaveRC, i.OutputRCBit());                 \
545   } while (0)
546 
547 #if V8_TARGET_ARCH_PPC64
548 // TODO(mbrandy): fix paths that produce garbage in offset's upper 32-bits.
549 #define CleanUInt32(x) __ ClearLeftImm(x, x, Operand(32))
550 #else
551 #define CleanUInt32(x)
552 #endif
553 
554 #define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(load_instr, store_instr)       \
555   do {                                                                  \
556     Label exchange;                                                     \
557     __ lwsync();                                                        \
558     __ bind(&exchange);                                                 \
559     __ load_instr(i.OutputRegister(0),                                  \
560                   MemOperand(i.InputRegister(0), i.InputRegister(1)));  \
561     __ store_instr(i.InputRegister(2),                                  \
562                    MemOperand(i.InputRegister(0), i.InputRegister(1))); \
563     __ bne(&exchange, cr0);                                             \
564     __ sync();                                                          \
565   } while (0)
566 
567 #define ASSEMBLE_ATOMIC_BINOP(bin_inst, _type)                               \
568   do {                                                                       \
569     auto bin_op = [&](Register dst, Register lhs, Register rhs) {            \
570       if (std::is_signed<_type>::value) {                                    \
571         switch (sizeof(_type)) {                                             \
572           case 1:                                                            \
573             __ extsb(dst, lhs);                                              \
574             break;                                                           \
575           case 2:                                                            \
576             __ extsh(dst, lhs);                                              \
577             break;                                                           \
578           case 4:                                                            \
579             __ extsw(dst, lhs);                                              \
580             break;                                                           \
581           case 8:                                                            \
582             break;                                                           \
583           default:                                                           \
584             UNREACHABLE();                                                   \
585         }                                                                    \
586         __ bin_inst(dst, dst, rhs);                                          \
587       } else {                                                               \
588         __ bin_inst(dst, lhs, rhs);                                          \
589       }                                                                      \
590     };                                                                       \
591     MemOperand dst_operand =                                                 \
592         MemOperand(i.InputRegister(0), i.InputRegister(1));                  \
593     __ AtomicOps<_type>(dst_operand, i.InputRegister(2), i.OutputRegister(), \
594                         kScratchReg, bin_op);                                \
595     break;                                                                   \
596   } while (false)
597 
AssembleDeconstructFrame()598 void CodeGenerator::AssembleDeconstructFrame() {
599   __ LeaveFrame(StackFrame::MANUAL);
600   unwinding_info_writer_.MarkFrameDeconstructed(__ pc_offset());
601 }
602 
AssemblePrepareTailCall()603 void CodeGenerator::AssemblePrepareTailCall() {
604   if (frame_access_state()->has_frame()) {
605     __ RestoreFrameStateForTailCall();
606   }
607   frame_access_state()->SetFrameAccessToSP();
608 }
609 
610 namespace {
611 
FlushPendingPushRegisters(TurboAssembler * tasm,FrameAccessState * frame_access_state,ZoneVector<Register> * pending_pushes)612 void FlushPendingPushRegisters(TurboAssembler* tasm,
613                                FrameAccessState* frame_access_state,
614                                ZoneVector<Register>* pending_pushes) {
615   switch (pending_pushes->size()) {
616     case 0:
617       break;
618     case 1:
619       tasm->Push((*pending_pushes)[0]);
620       break;
621     case 2:
622       tasm->Push((*pending_pushes)[0], (*pending_pushes)[1]);
623       break;
624     case 3:
625       tasm->Push((*pending_pushes)[0], (*pending_pushes)[1],
626                  (*pending_pushes)[2]);
627       break;
628     default:
629       UNREACHABLE();
630   }
631   frame_access_state->IncreaseSPDelta(pending_pushes->size());
632   pending_pushes->clear();
633 }
634 
AdjustStackPointerForTailCall(TurboAssembler * tasm,FrameAccessState * state,int new_slot_above_sp,ZoneVector<Register> * pending_pushes=nullptr,bool allow_shrinkage=true)635 void AdjustStackPointerForTailCall(
636     TurboAssembler* tasm, FrameAccessState* state, int new_slot_above_sp,
637     ZoneVector<Register>* pending_pushes = nullptr,
638     bool allow_shrinkage = true) {
639   int current_sp_offset = state->GetSPToFPSlotCount() +
640                           StandardFrameConstants::kFixedSlotCountAboveFp;
641   int stack_slot_delta = new_slot_above_sp - current_sp_offset;
642   if (stack_slot_delta > 0) {
643     if (pending_pushes != nullptr) {
644       FlushPendingPushRegisters(tasm, state, pending_pushes);
645     }
646     tasm->AddS64(sp, sp, Operand(-stack_slot_delta * kSystemPointerSize), r0);
647     state->IncreaseSPDelta(stack_slot_delta);
648   } else if (allow_shrinkage && stack_slot_delta < 0) {
649     if (pending_pushes != nullptr) {
650       FlushPendingPushRegisters(tasm, state, pending_pushes);
651     }
652     tasm->AddS64(sp, sp, Operand(-stack_slot_delta * kSystemPointerSize), r0);
653     state->IncreaseSPDelta(stack_slot_delta);
654   }
655 }
656 
657 }  // namespace
658 
AssembleTailCallBeforeGap(Instruction * instr,int first_unused_slot_offset)659 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
660                                               int first_unused_slot_offset) {
661   ZoneVector<MoveOperands*> pushes(zone());
662   GetPushCompatibleMoves(instr, kRegisterPush, &pushes);
663 
664   if (!pushes.empty() &&
665       (LocationOperand::cast(pushes.back()->destination()).index() + 1 ==
666        first_unused_slot_offset)) {
667     PPCOperandConverter g(this, instr);
668     ZoneVector<Register> pending_pushes(zone());
669     for (auto move : pushes) {
670       LocationOperand destination_location(
671           LocationOperand::cast(move->destination()));
672       InstructionOperand source(move->source());
673       AdjustStackPointerForTailCall(
674           tasm(), frame_access_state(),
675           destination_location.index() - pending_pushes.size(),
676           &pending_pushes);
677       // Pushes of non-register data types are not supported.
678       DCHECK(source.IsRegister());
679       LocationOperand source_location(LocationOperand::cast(source));
680       pending_pushes.push_back(source_location.GetRegister());
681       // TODO(arm): We can push more than 3 registers at once. Add support in
682       // the macro-assembler for pushing a list of registers.
683       if (pending_pushes.size() == 3) {
684         FlushPendingPushRegisters(tasm(), frame_access_state(),
685                                   &pending_pushes);
686       }
687       move->Eliminate();
688     }
689     FlushPendingPushRegisters(tasm(), frame_access_state(), &pending_pushes);
690   }
691   AdjustStackPointerForTailCall(tasm(), frame_access_state(),
692                                 first_unused_slot_offset, nullptr, false);
693 }
694 
AssembleTailCallAfterGap(Instruction * instr,int first_unused_slot_offset)695 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
696                                              int first_unused_slot_offset) {
697   AdjustStackPointerForTailCall(tasm(), frame_access_state(),
698                                 first_unused_slot_offset);
699 }
700 
701 // Check that {kJavaScriptCallCodeStartRegister} is correct.
AssembleCodeStartRegisterCheck()702 void CodeGenerator::AssembleCodeStartRegisterCheck() {
703   Register scratch = kScratchReg;
704   __ ComputeCodeStartAddress(scratch);
705   __ CmpS64(scratch, kJavaScriptCallCodeStartRegister);
706   __ Assert(eq, AbortReason::kWrongFunctionCodeStart);
707 }
708 
709 // Check if the code object is marked for deoptimization. If it is, then it
710 // jumps to the CompileLazyDeoptimizedCode builtin. In order to do this we need
711 // to:
712 //    1. read from memory the word that contains that bit, which can be found in
713 //       the flags in the referenced {CodeDataContainer} object;
714 //    2. test kMarkedForDeoptimizationBit in those flags; and
715 //    3. if it is not zero then it jumps to the builtin.
BailoutIfDeoptimized()716 void CodeGenerator::BailoutIfDeoptimized() {
717   if (FLAG_debug_code) {
718     // Check that {kJavaScriptCallCodeStartRegister} is correct.
719     __ ComputeCodeStartAddress(ip);
720     __ CmpS64(ip, kJavaScriptCallCodeStartRegister);
721     __ Assert(eq, AbortReason::kWrongFunctionCodeStart);
722   }
723 
724   int offset = Code::kCodeDataContainerOffset - Code::kHeaderSize;
725   __ LoadTaggedPointerField(
726       r11, MemOperand(kJavaScriptCallCodeStartRegister, offset), r0);
727   __ LoadS32(r11,
728              FieldMemOperand(r11, CodeDataContainer::kKindSpecificFlagsOffset),
729              r0);
730   __ TestBit(r11, Code::kMarkedForDeoptimizationBit);
731   __ Jump(BUILTIN_CODE(isolate(), CompileLazyDeoptimizedCode),
732           RelocInfo::CODE_TARGET, ne, cr0);
733 }
734 
735 // Assembles an instruction after register allocation, producing machine code.
AssembleArchInstruction(Instruction * instr)736 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
737     Instruction* instr) {
738   PPCOperandConverter i(this, instr);
739   ArchOpcode opcode = ArchOpcodeField::decode(instr->opcode());
740 
741   switch (opcode) {
742     case kArchCallCodeObject: {
743       v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
744           tasm());
745       if (HasRegisterInput(instr, 0)) {
746         Register reg = i.InputRegister(0);
747         DCHECK_IMPLIES(
748             instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
749             reg == kJavaScriptCallCodeStartRegister);
750         __ CallCodeObject(reg);
751       } else {
752         __ Call(i.InputCode(0), RelocInfo::CODE_TARGET);
753       }
754       RecordCallPosition(instr);
755       DCHECK_EQ(LeaveRC, i.OutputRCBit());
756       frame_access_state()->ClearSPDelta();
757       break;
758     }
759     case kArchCallBuiltinPointer: {
760       DCHECK(!instr->InputAt(0)->IsImmediate());
761       Register builtin_index = i.InputRegister(0);
762       __ CallBuiltinByIndex(builtin_index);
763       RecordCallPosition(instr);
764       frame_access_state()->ClearSPDelta();
765       break;
766     }
767 #if V8_ENABLE_WEBASSEMBLY
768     case kArchCallWasmFunction: {
769       // We must not share code targets for calls to builtins for wasm code, as
770       // they might need to be patched individually.
771       if (instr->InputAt(0)->IsImmediate()) {
772         Constant constant = i.ToConstant(instr->InputAt(0));
773 #ifdef V8_TARGET_ARCH_PPC64
774         Address wasm_code = static_cast<Address>(constant.ToInt64());
775 #else
776         Address wasm_code = static_cast<Address>(constant.ToInt32());
777 #endif
778         __ Call(wasm_code, constant.rmode());
779       } else {
780         __ Call(i.InputRegister(0));
781       }
782       RecordCallPosition(instr);
783       DCHECK_EQ(LeaveRC, i.OutputRCBit());
784       frame_access_state()->ClearSPDelta();
785       break;
786     }
787     case kArchTailCallWasm: {
788       // We must not share code targets for calls to builtins for wasm code, as
789       // they might need to be patched individually.
790       if (instr->InputAt(0)->IsImmediate()) {
791         Constant constant = i.ToConstant(instr->InputAt(0));
792 #ifdef V8_TARGET_ARCH_PPC64
793         Address wasm_code = static_cast<Address>(constant.ToInt64());
794 #else
795         Address wasm_code = static_cast<Address>(constant.ToInt32());
796 #endif
797         __ Jump(wasm_code, constant.rmode());
798       } else {
799         __ Jump(i.InputRegister(0));
800       }
801       DCHECK_EQ(LeaveRC, i.OutputRCBit());
802       frame_access_state()->ClearSPDelta();
803       frame_access_state()->SetFrameAccessToDefault();
804       break;
805     }
806 #endif  // V8_ENABLE_WEBASSEMBLY
807     case kArchTailCallCodeObject: {
808       if (HasRegisterInput(instr, 0)) {
809         Register reg = i.InputRegister(0);
810         DCHECK_IMPLIES(
811             instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
812             reg == kJavaScriptCallCodeStartRegister);
813         __ JumpCodeObject(reg);
814       } else {
815         // We cannot use the constant pool to load the target since
816         // we've already restored the caller's frame.
817         ConstantPoolUnavailableScope constant_pool_unavailable(tasm());
818         __ Jump(i.InputCode(0), RelocInfo::CODE_TARGET);
819       }
820       DCHECK_EQ(LeaveRC, i.OutputRCBit());
821       frame_access_state()->ClearSPDelta();
822       frame_access_state()->SetFrameAccessToDefault();
823       break;
824     }
825     case kArchTailCallAddress: {
826       CHECK(!instr->InputAt(0)->IsImmediate());
827       Register reg = i.InputRegister(0);
828       DCHECK_IMPLIES(
829           instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
830           reg == kJavaScriptCallCodeStartRegister);
831       __ Jump(reg);
832       frame_access_state()->ClearSPDelta();
833       frame_access_state()->SetFrameAccessToDefault();
834       break;
835     }
836     case kArchCallJSFunction: {
837       v8::internal::Assembler::BlockTrampolinePoolScope block_trampoline_pool(
838           tasm());
839       Register func = i.InputRegister(0);
840       if (FLAG_debug_code) {
841         // Check the function's context matches the context argument.
842         __ LoadTaggedPointerField(
843             kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset), r0);
844         __ CmpS64(cp, kScratchReg);
845         __ Assert(eq, AbortReason::kWrongFunctionContext);
846       }
847       static_assert(kJavaScriptCallCodeStartRegister == r5, "ABI mismatch");
848       __ LoadTaggedPointerField(
849           r5, FieldMemOperand(func, JSFunction::kCodeOffset), r0);
850       __ CallCodeObject(r5);
851       RecordCallPosition(instr);
852       DCHECK_EQ(LeaveRC, i.OutputRCBit());
853       frame_access_state()->ClearSPDelta();
854       break;
855     }
856     case kArchPrepareCallCFunction: {
857       int const num_gp_parameters = ParamField::decode(instr->opcode());
858       int const num_fp_parameters = FPParamField::decode(instr->opcode());
859       __ PrepareCallCFunction(num_gp_parameters + num_fp_parameters,
860                               kScratchReg);
861       // Frame alignment requires using FP-relative frame addressing.
862       frame_access_state()->SetFrameAccessToFP();
863       break;
864     }
865     case kArchSaveCallerRegisters: {
866       fp_mode_ =
867           static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode()));
868       DCHECK(fp_mode_ == SaveFPRegsMode::kIgnore ||
869              fp_mode_ == SaveFPRegsMode::kSave);
870       // kReturnRegister0 should have been saved before entering the stub.
871       int bytes = __ PushCallerSaved(fp_mode_, kReturnRegister0);
872       DCHECK(IsAligned(bytes, kSystemPointerSize));
873       DCHECK_EQ(0, frame_access_state()->sp_delta());
874       frame_access_state()->IncreaseSPDelta(bytes / kSystemPointerSize);
875       DCHECK(!caller_registers_saved_);
876       caller_registers_saved_ = true;
877       break;
878     }
879     case kArchRestoreCallerRegisters: {
880       DCHECK(fp_mode_ ==
881              static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode())));
882       DCHECK(fp_mode_ == SaveFPRegsMode::kIgnore ||
883              fp_mode_ == SaveFPRegsMode::kSave);
884       // Don't overwrite the returned value.
885       int bytes = __ PopCallerSaved(fp_mode_, kReturnRegister0);
886       frame_access_state()->IncreaseSPDelta(-(bytes / kSystemPointerSize));
887       DCHECK_EQ(0, frame_access_state()->sp_delta());
888       DCHECK(caller_registers_saved_);
889       caller_registers_saved_ = false;
890       break;
891     }
892     case kArchPrepareTailCall:
893       AssemblePrepareTailCall();
894       break;
895     case kArchComment:
896 #ifdef V8_TARGET_ARCH_PPC64
897       __ RecordComment(reinterpret_cast<const char*>(i.InputInt64(0)));
898 #else
899       __ RecordComment(reinterpret_cast<const char*>(i.InputInt32(0)));
900 #endif
901       break;
902     case kArchCallCFunction: {
903       int const num_gp_parameters = ParamField::decode(instr->opcode());
904       int const fp_param_field = FPParamField::decode(instr->opcode());
905       int num_fp_parameters = fp_param_field;
906       bool has_function_descriptor = false;
907       int offset = 20 * kInstrSize;
908 
909       if (instr->InputAt(0)->IsImmediate() &&
910           !FLAG_enable_embedded_constant_pool) {
911         // If loading an immediate without constant pool then 4 instructions get
912         // emitted instead of a single load (which makes it 3 extra).
913         offset = 23 * kInstrSize;
914       }
915       if (!instr->InputAt(0)->IsImmediate() && !ABI_CALL_VIA_IP) {
916         // On Linux and Sim, there will be an extra
917         // instruction to pass the input using the `ip` register. This
918         // instruction gets emitted under `CallCFunction` or
919         // `CallCFunctionHelper` depending on the type of the input (immediate
920         // or register). This extra move is only emitted on AIX if the input is
921         // an immediate and not a register.
922         offset -= kInstrSize;
923       }
924 #if ABI_USES_FUNCTION_DESCRIPTORS
925       // AIX/PPC64BE Linux uses a function descriptor
926       int kNumFPParametersMask = kHasFunctionDescriptorBitMask - 1;
927       num_fp_parameters = kNumFPParametersMask & fp_param_field;
928       has_function_descriptor =
929           (fp_param_field & kHasFunctionDescriptorBitMask) != 0;
930       // AIX may emit 2 extra Load instructions under CallCFunctionHelper
931       // due to having function descriptor.
932       if (has_function_descriptor) {
933         offset += 2 * kInstrSize;
934       }
935 #endif
936 #if V8_ENABLE_WEBASSEMBLY
937       Label start_call;
938       bool isWasmCapiFunction =
939           linkage()->GetIncomingDescriptor()->IsWasmCapiFunction();
940       if (isWasmCapiFunction) {
941         __ mflr(r0);
942         __ bind(&start_call);
943         __ LoadPC(kScratchReg);
944         __ addi(kScratchReg, kScratchReg, Operand(offset));
945         __ StoreU64(kScratchReg,
946                     MemOperand(fp, WasmExitFrameConstants::kCallingPCOffset));
947         __ mtlr(r0);
948       }
949 #endif  // V8_ENABLE_WEBASSEMBLY
950       if (instr->InputAt(0)->IsImmediate()) {
951         ExternalReference ref = i.InputExternalReference(0);
952         __ CallCFunction(ref, num_gp_parameters, num_fp_parameters,
953                          has_function_descriptor);
954       } else {
955         Register func = i.InputRegister(0);
956         __ CallCFunction(func, num_gp_parameters, num_fp_parameters,
957                          has_function_descriptor);
958       }
959       // TODO(miladfar): In the above block, kScratchReg must be populated with
960       // the strictly-correct PC, which is the return address at this spot. The
961       // offset is counted from where we are binding to the label and ends at
962       // this spot. If failed, replace it with the correct offset suggested.
963       // More info on f5ab7d3.
964 #if V8_ENABLE_WEBASSEMBLY
965       if (isWasmCapiFunction) {
966         CHECK_EQ(offset, __ SizeOfCodeGeneratedSince(&start_call));
967         RecordSafepoint(instr->reference_map());
968       }
969 #endif  // V8_ENABLE_WEBASSEMBLY
970       frame_access_state()->SetFrameAccessToDefault();
971       // Ideally, we should decrement SP delta to match the change of stack
972       // pointer in CallCFunction. However, for certain architectures (e.g.
973       // ARM), there may be more strict alignment requirement, causing old SP
974       // to be saved on the stack. In those cases, we can not calculate the SP
975       // delta statically.
976       frame_access_state()->ClearSPDelta();
977       if (caller_registers_saved_) {
978         // Need to re-sync SP delta introduced in kArchSaveCallerRegisters.
979         // Here, we assume the sequence to be:
980         //   kArchSaveCallerRegisters;
981         //   kArchCallCFunction;
982         //   kArchRestoreCallerRegisters;
983         int bytes =
984             __ RequiredStackSizeForCallerSaved(fp_mode_, kReturnRegister0);
985         frame_access_state()->IncreaseSPDelta(bytes / kSystemPointerSize);
986       }
987       break;
988     }
989     case kArchJmp:
990       AssembleArchJump(i.InputRpo(0));
991       DCHECK_EQ(LeaveRC, i.OutputRCBit());
992       break;
993     case kArchBinarySearchSwitch:
994       AssembleArchBinarySearchSwitch(instr);
995       break;
996     case kArchTableSwitch:
997       AssembleArchTableSwitch(instr);
998       DCHECK_EQ(LeaveRC, i.OutputRCBit());
999       break;
1000     case kArchAbortCSADcheck:
1001       DCHECK(i.InputRegister(0) == r4);
1002       {
1003         // We don't actually want to generate a pile of code for this, so just
1004         // claim there is a stack frame, without generating one.
1005         FrameScope scope(tasm(), StackFrame::NO_FRAME_TYPE);
1006         __ Call(isolate()->builtins()->code_handle(Builtin::kAbortCSADcheck),
1007                 RelocInfo::CODE_TARGET);
1008       }
1009       __ stop();
1010       break;
1011     case kArchDebugBreak:
1012       __ DebugBreak();
1013       break;
1014     case kArchNop:
1015     case kArchThrowTerminator:
1016       // don't emit code for nops.
1017       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1018       break;
1019     case kArchDeoptimize: {
1020       DeoptimizationExit* exit =
1021           BuildTranslation(instr, -1, 0, 0, OutputFrameStateCombine::Ignore());
1022       __ b(exit->label());
1023       break;
1024     }
1025     case kArchRet:
1026       AssembleReturn(instr->InputAt(0));
1027       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1028       break;
1029     case kArchFramePointer:
1030       __ mr(i.OutputRegister(), fp);
1031       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1032       break;
1033     case kArchParentFramePointer:
1034       if (frame_access_state()->has_frame()) {
1035         __ LoadU64(i.OutputRegister(), MemOperand(fp, 0));
1036       } else {
1037         __ mr(i.OutputRegister(), fp);
1038       }
1039       break;
1040     case kArchStackPointerGreaterThan: {
1041       // Potentially apply an offset to the current stack pointer before the
1042       // comparison to consider the size difference of an optimized frame versus
1043       // the contained unoptimized frames.
1044 
1045       Register lhs_register = sp;
1046       uint32_t offset;
1047 
1048       if (ShouldApplyOffsetToStackCheck(instr, &offset)) {
1049         lhs_register = i.TempRegister(0);
1050         __ SubS64(lhs_register, sp, Operand(offset), kScratchReg);
1051       }
1052 
1053       constexpr size_t kValueIndex = 0;
1054       DCHECK(instr->InputAt(kValueIndex)->IsRegister());
1055       __ CmpU64(lhs_register, i.InputRegister(kValueIndex), cr0);
1056       break;
1057     }
1058     case kArchStackCheckOffset:
1059       __ LoadSmiLiteral(i.OutputRegister(),
1060                         Smi::FromInt(GetStackCheckOffset()));
1061       break;
1062     case kArchTruncateDoubleToI:
1063       __ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(),
1064                            i.InputDoubleRegister(0), DetermineStubCallMode());
1065       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1066       break;
1067     case kArchStoreWithWriteBarrier: {
1068       RecordWriteMode mode =
1069           static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
1070       Register object = i.InputRegister(0);
1071       Register value = i.InputRegister(2);
1072       Register scratch0 = i.TempRegister(0);
1073       Register scratch1 = i.TempRegister(1);
1074       OutOfLineRecordWrite* ool;
1075 
1076       AddressingMode addressing_mode =
1077           AddressingModeField::decode(instr->opcode());
1078       if (addressing_mode == kMode_MRI) {
1079         int32_t offset = i.InputInt32(1);
1080         ool = zone()->New<OutOfLineRecordWrite>(
1081             this, object, offset, value, scratch0, scratch1, mode,
1082             DetermineStubCallMode(), &unwinding_info_writer_);
1083         __ StoreTaggedField(value, MemOperand(object, offset), r0);
1084       } else {
1085         DCHECK_EQ(kMode_MRR, addressing_mode);
1086         Register offset(i.InputRegister(1));
1087         ool = zone()->New<OutOfLineRecordWrite>(
1088             this, object, offset, value, scratch0, scratch1, mode,
1089             DetermineStubCallMode(), &unwinding_info_writer_);
1090         __ StoreTaggedField(value, MemOperand(object, offset), r0);
1091       }
1092       if (mode > RecordWriteMode::kValueIsPointer) {
1093         __ JumpIfSmi(value, ool->exit());
1094       }
1095       __ CheckPageFlag(object, scratch0,
1096                        MemoryChunk::kPointersFromHereAreInterestingMask, ne,
1097                        ool->entry());
1098       __ bind(ool->exit());
1099       break;
1100     }
1101     case kArchStackSlot: {
1102       FrameOffset offset =
1103           frame_access_state()->GetFrameOffset(i.InputInt32(0));
1104       __ AddS64(i.OutputRegister(), offset.from_stack_pointer() ? sp : fp,
1105                 Operand(offset.offset()), r0);
1106       break;
1107     }
1108     case kPPC_Peek: {
1109       int reverse_slot = i.InputInt32(0);
1110       int offset =
1111           FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot);
1112       if (instr->OutputAt(0)->IsFPRegister()) {
1113         LocationOperand* op = LocationOperand::cast(instr->OutputAt(0));
1114         if (op->representation() == MachineRepresentation::kFloat64) {
1115           __ LoadF64(i.OutputDoubleRegister(), MemOperand(fp, offset), r0);
1116         } else if (op->representation() == MachineRepresentation::kFloat32) {
1117           __ LoadF32(i.OutputFloatRegister(), MemOperand(fp, offset), r0);
1118         } else {
1119           DCHECK_EQ(MachineRepresentation::kSimd128, op->representation());
1120           __ mov(ip, Operand(offset));
1121           __ LoadSimd128(i.OutputSimd128Register(), MemOperand(fp, ip));
1122         }
1123       } else {
1124         __ LoadU64(i.OutputRegister(), MemOperand(fp, offset), r0);
1125       }
1126       break;
1127     }
1128     case kPPC_Sync: {
1129       __ sync();
1130       break;
1131     }
1132     case kPPC_And:
1133       if (HasRegisterInput(instr, 1)) {
1134         __ and_(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1135                 i.OutputRCBit());
1136       } else {
1137         __ andi(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
1138       }
1139       break;
1140     case kPPC_AndComplement:
1141       __ andc(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1142               i.OutputRCBit());
1143       break;
1144     case kPPC_Or:
1145       if (HasRegisterInput(instr, 1)) {
1146         __ orx(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1147                i.OutputRCBit());
1148       } else {
1149         __ ori(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
1150         DCHECK_EQ(LeaveRC, i.OutputRCBit());
1151       }
1152       break;
1153     case kPPC_OrComplement:
1154       __ orc(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1155              i.OutputRCBit());
1156       break;
1157     case kPPC_Xor:
1158       if (HasRegisterInput(instr, 1)) {
1159         __ xor_(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1160                 i.OutputRCBit());
1161       } else {
1162         __ xori(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
1163         DCHECK_EQ(LeaveRC, i.OutputRCBit());
1164       }
1165       break;
1166     case kPPC_ShiftLeft32:
1167       ASSEMBLE_BINOP_RC(ShiftLeftU32, ShiftLeftU32);
1168       break;
1169     case kPPC_ShiftLeft64:
1170       ASSEMBLE_BINOP_RC(ShiftLeftU64, ShiftLeftU64);
1171       break;
1172     case kPPC_ShiftRight32:
1173       ASSEMBLE_BINOP_RC(ShiftRightU32, ShiftRightU32);
1174       break;
1175     case kPPC_ShiftRight64:
1176       ASSEMBLE_BINOP_RC(ShiftRightU64, ShiftRightU64);
1177       break;
1178     case kPPC_ShiftRightAlg32:
1179       ASSEMBLE_BINOP_INT_RC(ShiftRightS32, ShiftRightS32);
1180       break;
1181     case kPPC_ShiftRightAlg64:
1182       ASSEMBLE_BINOP_INT_RC(ShiftRightS64, ShiftRightS64);
1183       break;
1184 #if !V8_TARGET_ARCH_PPC64
1185     case kPPC_AddPair:
1186       // i.InputRegister(0) ... left low word.
1187       // i.InputRegister(1) ... left high word.
1188       // i.InputRegister(2) ... right low word.
1189       // i.InputRegister(3) ... right high word.
1190       __ addc(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2));
1191       __ adde(i.OutputRegister(1), i.InputRegister(1), i.InputRegister(3));
1192       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1193       break;
1194     case kPPC_SubPair:
1195       // i.InputRegister(0) ... left low word.
1196       // i.InputRegister(1) ... left high word.
1197       // i.InputRegister(2) ... right low word.
1198       // i.InputRegister(3) ... right high word.
1199       __ subc(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2));
1200       __ sube(i.OutputRegister(1), i.InputRegister(1), i.InputRegister(3));
1201       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1202       break;
1203     case kPPC_MulPair:
1204       // i.InputRegister(0) ... left low word.
1205       // i.InputRegister(1) ... left high word.
1206       // i.InputRegister(2) ... right low word.
1207       // i.InputRegister(3) ... right high word.
1208       __ mullw(i.TempRegister(0), i.InputRegister(0), i.InputRegister(3));
1209       __ mullw(i.TempRegister(1), i.InputRegister(2), i.InputRegister(1));
1210       __ add(i.TempRegister(0), i.TempRegister(0), i.TempRegister(1));
1211       __ mullw(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2));
1212       __ mulhwu(i.OutputRegister(1), i.InputRegister(0), i.InputRegister(2));
1213       __ add(i.OutputRegister(1), i.OutputRegister(1), i.TempRegister(0));
1214       break;
1215     case kPPC_ShiftLeftPair: {
1216       Register second_output =
1217           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1218       if (instr->InputAt(2)->IsImmediate()) {
1219         __ ShiftLeftPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1220                          i.InputRegister(1), i.InputInt32(2));
1221       } else {
1222         __ ShiftLeftPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1223                          i.InputRegister(1), kScratchReg, i.InputRegister(2));
1224       }
1225       break;
1226     }
1227     case kPPC_ShiftRightPair: {
1228       Register second_output =
1229           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1230       if (instr->InputAt(2)->IsImmediate()) {
1231         __ ShiftRightPair(i.OutputRegister(0), second_output,
1232                           i.InputRegister(0), i.InputRegister(1),
1233                           i.InputInt32(2));
1234       } else {
1235         __ ShiftRightPair(i.OutputRegister(0), second_output,
1236                           i.InputRegister(0), i.InputRegister(1), kScratchReg,
1237                           i.InputRegister(2));
1238       }
1239       break;
1240     }
1241     case kPPC_ShiftRightAlgPair: {
1242       Register second_output =
1243           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1244       if (instr->InputAt(2)->IsImmediate()) {
1245         __ ShiftRightAlgPair(i.OutputRegister(0), second_output,
1246                              i.InputRegister(0), i.InputRegister(1),
1247                              i.InputInt32(2));
1248       } else {
1249         __ ShiftRightAlgPair(i.OutputRegister(0), second_output,
1250                              i.InputRegister(0), i.InputRegister(1),
1251                              kScratchReg, i.InputRegister(2));
1252       }
1253       break;
1254     }
1255 #endif
1256     case kPPC_RotRight32:
1257       if (HasRegisterInput(instr, 1)) {
1258         __ subfic(kScratchReg, i.InputRegister(1), Operand(32));
1259         __ rotlw(i.OutputRegister(), i.InputRegister(0), kScratchReg,
1260                  i.OutputRCBit());
1261       } else {
1262         int sh = i.InputInt32(1);
1263         __ rotrwi(i.OutputRegister(), i.InputRegister(0), sh, i.OutputRCBit());
1264       }
1265       break;
1266 #if V8_TARGET_ARCH_PPC64
1267     case kPPC_RotRight64:
1268       if (HasRegisterInput(instr, 1)) {
1269         __ subfic(kScratchReg, i.InputRegister(1), Operand(64));
1270         __ rotld(i.OutputRegister(), i.InputRegister(0), kScratchReg,
1271                  i.OutputRCBit());
1272       } else {
1273         int sh = i.InputInt32(1);
1274         __ rotrdi(i.OutputRegister(), i.InputRegister(0), sh, i.OutputRCBit());
1275       }
1276       break;
1277 #endif
1278     case kPPC_Not:
1279       __ notx(i.OutputRegister(), i.InputRegister(0), i.OutputRCBit());
1280       break;
1281     case kPPC_RotLeftAndMask32:
1282       __ rlwinm(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
1283                 31 - i.InputInt32(2), 31 - i.InputInt32(3), i.OutputRCBit());
1284       break;
1285 #if V8_TARGET_ARCH_PPC64
1286     case kPPC_RotLeftAndClear64:
1287       __ rldic(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
1288                63 - i.InputInt32(2), i.OutputRCBit());
1289       break;
1290     case kPPC_RotLeftAndClearLeft64:
1291       __ rldicl(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
1292                 63 - i.InputInt32(2), i.OutputRCBit());
1293       break;
1294     case kPPC_RotLeftAndClearRight64:
1295       __ rldicr(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
1296                 63 - i.InputInt32(2), i.OutputRCBit());
1297       break;
1298 #endif
1299     case kPPC_Add32:
1300 #if V8_TARGET_ARCH_PPC64
1301       if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
1302         ASSEMBLE_ADD_WITH_OVERFLOW();
1303       } else {
1304 #endif
1305         if (HasRegisterInput(instr, 1)) {
1306           __ add(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1307                  LeaveOE, i.OutputRCBit());
1308         } else {
1309           __ AddS64(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1),
1310                     r0, LeaveOE, i.OutputRCBit());
1311         }
1312         __ extsw(i.OutputRegister(), i.OutputRegister());
1313 #if V8_TARGET_ARCH_PPC64
1314       }
1315 #endif
1316       break;
1317 #if V8_TARGET_ARCH_PPC64
1318     case kPPC_Add64:
1319       if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
1320         ASSEMBLE_ADD_WITH_OVERFLOW();
1321       } else {
1322         if (HasRegisterInput(instr, 1)) {
1323           __ add(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1324                  LeaveOE, i.OutputRCBit());
1325         } else {
1326           __ AddS64(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1),
1327                     r0, LeaveOE, i.OutputRCBit());
1328         }
1329       }
1330       break;
1331 #endif
1332     case kPPC_AddWithOverflow32:
1333       ASSEMBLE_ADD_WITH_OVERFLOW32();
1334       break;
1335     case kPPC_AddDouble:
1336       ASSEMBLE_FLOAT_BINOP_RC(fadd, MiscField::decode(instr->opcode()));
1337       break;
1338     case kPPC_Sub:
1339 #if V8_TARGET_ARCH_PPC64
1340       if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
1341         ASSEMBLE_SUB_WITH_OVERFLOW();
1342       } else {
1343 #endif
1344         if (HasRegisterInput(instr, 1)) {
1345           __ sub(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1346                  LeaveOE, i.OutputRCBit());
1347         } else {
1348           __ SubS64(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1),
1349                     r0, LeaveOE, i.OutputRCBit());
1350         }
1351 #if V8_TARGET_ARCH_PPC64
1352       }
1353 #endif
1354       break;
1355     case kPPC_SubWithOverflow32:
1356       ASSEMBLE_SUB_WITH_OVERFLOW32();
1357       break;
1358     case kPPC_SubDouble:
1359       ASSEMBLE_FLOAT_BINOP_RC(fsub, MiscField::decode(instr->opcode()));
1360       break;
1361     case kPPC_Mul32:
1362       __ mullw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1363                LeaveOE, i.OutputRCBit());
1364       break;
1365 #if V8_TARGET_ARCH_PPC64
1366     case kPPC_Mul64:
1367       __ mulld(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1368                LeaveOE, i.OutputRCBit());
1369       break;
1370 #endif
1371 
1372     case kPPC_Mul32WithHigh32:
1373       if (i.OutputRegister(0) == i.InputRegister(0) ||
1374           i.OutputRegister(0) == i.InputRegister(1) ||
1375           i.OutputRegister(1) == i.InputRegister(0) ||
1376           i.OutputRegister(1) == i.InputRegister(1)) {
1377         __ mullw(kScratchReg, i.InputRegister(0), i.InputRegister(1));  // low
1378         __ mulhw(i.OutputRegister(1), i.InputRegister(0),
1379                  i.InputRegister(1));  // high
1380         __ mr(i.OutputRegister(0), kScratchReg);
1381       } else {
1382         __ mullw(i.OutputRegister(0), i.InputRegister(0),
1383                  i.InputRegister(1));  // low
1384         __ mulhw(i.OutputRegister(1), i.InputRegister(0),
1385                  i.InputRegister(1));  // high
1386       }
1387       break;
1388     case kPPC_MulHigh32:
1389       __ mulhw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1390                i.OutputRCBit());
1391       // High 32 bits are undefined and need to be cleared.
1392       CleanUInt32(i.OutputRegister());
1393       break;
1394     case kPPC_MulHighU32:
1395       __ mulhwu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1396                 i.OutputRCBit());
1397       // High 32 bits are undefined and need to be cleared.
1398       CleanUInt32(i.OutputRegister());
1399       break;
1400     case kPPC_MulDouble:
1401       ASSEMBLE_FLOAT_BINOP_RC(fmul, MiscField::decode(instr->opcode()));
1402       break;
1403     case kPPC_Div32:
1404       __ divw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1405       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1406       break;
1407 #if V8_TARGET_ARCH_PPC64
1408     case kPPC_Div64:
1409       __ divd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1410       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1411       break;
1412 #endif
1413     case kPPC_DivU32:
1414       __ divwu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1415       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1416       break;
1417 #if V8_TARGET_ARCH_PPC64
1418     case kPPC_DivU64:
1419       __ divdu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1420       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1421       break;
1422 #endif
1423     case kPPC_DivDouble:
1424       ASSEMBLE_FLOAT_BINOP_RC(fdiv, MiscField::decode(instr->opcode()));
1425       break;
1426     case kPPC_Mod32:
1427       if (CpuFeatures::IsSupported(PPC_9_PLUS)) {
1428         __ modsw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1429       } else {
1430         ASSEMBLE_MODULO(divw, mullw);
1431       }
1432       break;
1433 #if V8_TARGET_ARCH_PPC64
1434     case kPPC_Mod64:
1435       if (CpuFeatures::IsSupported(PPC_9_PLUS)) {
1436         __ modsd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1437       } else {
1438         ASSEMBLE_MODULO(divd, mulld);
1439       }
1440       break;
1441 #endif
1442     case kPPC_ModU32:
1443       if (CpuFeatures::IsSupported(PPC_9_PLUS)) {
1444         __ moduw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1445       } else {
1446         ASSEMBLE_MODULO(divwu, mullw);
1447       }
1448       break;
1449 #if V8_TARGET_ARCH_PPC64
1450     case kPPC_ModU64:
1451       if (CpuFeatures::IsSupported(PPC_9_PLUS)) {
1452         __ modud(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1453       } else {
1454         ASSEMBLE_MODULO(divdu, mulld);
1455       }
1456       break;
1457 #endif
1458     case kPPC_ModDouble:
1459       // TODO(bmeurer): We should really get rid of this special instruction,
1460       // and generate a CallAddress instruction instead.
1461       ASSEMBLE_FLOAT_MODULO();
1462       break;
1463     case kIeee754Float64Acos:
1464       ASSEMBLE_IEEE754_UNOP(acos);
1465       break;
1466     case kIeee754Float64Acosh:
1467       ASSEMBLE_IEEE754_UNOP(acosh);
1468       break;
1469     case kIeee754Float64Asin:
1470       ASSEMBLE_IEEE754_UNOP(asin);
1471       break;
1472     case kIeee754Float64Asinh:
1473       ASSEMBLE_IEEE754_UNOP(asinh);
1474       break;
1475     case kIeee754Float64Atan:
1476       ASSEMBLE_IEEE754_UNOP(atan);
1477       break;
1478     case kIeee754Float64Atan2:
1479       ASSEMBLE_IEEE754_BINOP(atan2);
1480       break;
1481     case kIeee754Float64Atanh:
1482       ASSEMBLE_IEEE754_UNOP(atanh);
1483       break;
1484     case kIeee754Float64Tan:
1485       ASSEMBLE_IEEE754_UNOP(tan);
1486       break;
1487     case kIeee754Float64Tanh:
1488       ASSEMBLE_IEEE754_UNOP(tanh);
1489       break;
1490     case kIeee754Float64Cbrt:
1491       ASSEMBLE_IEEE754_UNOP(cbrt);
1492       break;
1493     case kIeee754Float64Sin:
1494       ASSEMBLE_IEEE754_UNOP(sin);
1495       break;
1496     case kIeee754Float64Sinh:
1497       ASSEMBLE_IEEE754_UNOP(sinh);
1498       break;
1499     case kIeee754Float64Cos:
1500       ASSEMBLE_IEEE754_UNOP(cos);
1501       break;
1502     case kIeee754Float64Cosh:
1503       ASSEMBLE_IEEE754_UNOP(cosh);
1504       break;
1505     case kIeee754Float64Exp:
1506       ASSEMBLE_IEEE754_UNOP(exp);
1507       break;
1508     case kIeee754Float64Expm1:
1509       ASSEMBLE_IEEE754_UNOP(expm1);
1510       break;
1511     case kIeee754Float64Log:
1512       ASSEMBLE_IEEE754_UNOP(log);
1513       break;
1514     case kIeee754Float64Log1p:
1515       ASSEMBLE_IEEE754_UNOP(log1p);
1516       break;
1517     case kIeee754Float64Log2:
1518       ASSEMBLE_IEEE754_UNOP(log2);
1519       break;
1520     case kIeee754Float64Log10:
1521       ASSEMBLE_IEEE754_UNOP(log10);
1522       break;
1523     case kIeee754Float64Pow:
1524       ASSEMBLE_IEEE754_BINOP(pow);
1525       break;
1526     case kPPC_Neg:
1527       __ neg(i.OutputRegister(), i.InputRegister(0), LeaveOE, i.OutputRCBit());
1528       break;
1529     case kPPC_MaxDouble:
1530       __ MaxF64(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1531                 i.InputDoubleRegister(1), kScratchDoubleReg);
1532       break;
1533     case kPPC_MinDouble:
1534       __ MinF64(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1535                 i.InputDoubleRegister(1), kScratchDoubleReg);
1536       break;
1537     case kPPC_AbsDouble:
1538       ASSEMBLE_FLOAT_UNOP_RC(fabs, 0);
1539       break;
1540     case kPPC_SqrtDouble:
1541       ASSEMBLE_FLOAT_UNOP_RC(fsqrt, MiscField::decode(instr->opcode()));
1542       break;
1543     case kPPC_FloorDouble:
1544       ASSEMBLE_FLOAT_UNOP_RC(frim, MiscField::decode(instr->opcode()));
1545       break;
1546     case kPPC_CeilDouble:
1547       ASSEMBLE_FLOAT_UNOP_RC(frip, MiscField::decode(instr->opcode()));
1548       break;
1549     case kPPC_TruncateDouble:
1550       ASSEMBLE_FLOAT_UNOP_RC(friz, MiscField::decode(instr->opcode()));
1551       break;
1552     case kPPC_RoundDouble:
1553       ASSEMBLE_FLOAT_UNOP_RC(frin, MiscField::decode(instr->opcode()));
1554       break;
1555     case kPPC_NegDouble:
1556       ASSEMBLE_FLOAT_UNOP_RC(fneg, 0);
1557       break;
1558     case kPPC_Cntlz32:
1559       __ cntlzw(i.OutputRegister(), i.InputRegister(0));
1560       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1561       break;
1562 #if V8_TARGET_ARCH_PPC64
1563     case kPPC_Cntlz64:
1564       __ cntlzd(i.OutputRegister(), i.InputRegister(0));
1565       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1566       break;
1567 #endif
1568     case kPPC_Popcnt32:
1569       __ Popcnt32(i.OutputRegister(), i.InputRegister(0));
1570       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1571       break;
1572 #if V8_TARGET_ARCH_PPC64
1573     case kPPC_Popcnt64:
1574       __ Popcnt64(i.OutputRegister(), i.InputRegister(0));
1575       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1576       break;
1577 #endif
1578     case kPPC_Cmp32:
1579       ASSEMBLE_COMPARE(cmpw, cmplw);
1580       break;
1581 #if V8_TARGET_ARCH_PPC64
1582     case kPPC_Cmp64:
1583       ASSEMBLE_COMPARE(cmp, cmpl);
1584       break;
1585 #endif
1586     case kPPC_CmpDouble:
1587       ASSEMBLE_FLOAT_COMPARE(fcmpu);
1588       break;
1589     case kPPC_Tst32:
1590       if (HasRegisterInput(instr, 1)) {
1591         __ and_(r0, i.InputRegister(0), i.InputRegister(1), i.OutputRCBit());
1592       } else {
1593         __ andi(r0, i.InputRegister(0), i.InputImmediate(1));
1594       }
1595 #if V8_TARGET_ARCH_PPC64
1596       __ extsw(r0, r0, i.OutputRCBit());
1597 #endif
1598       DCHECK_EQ(SetRC, i.OutputRCBit());
1599       break;
1600 #if V8_TARGET_ARCH_PPC64
1601     case kPPC_Tst64:
1602       if (HasRegisterInput(instr, 1)) {
1603         __ and_(r0, i.InputRegister(0), i.InputRegister(1), i.OutputRCBit());
1604       } else {
1605         __ andi(r0, i.InputRegister(0), i.InputImmediate(1));
1606       }
1607       DCHECK_EQ(SetRC, i.OutputRCBit());
1608       break;
1609 #endif
1610     case kPPC_Float64SilenceNaN: {
1611       DoubleRegister value = i.InputDoubleRegister(0);
1612       DoubleRegister result = i.OutputDoubleRegister();
1613       __ CanonicalizeNaN(result, value);
1614       break;
1615     }
1616     case kPPC_Push: {
1617       int stack_decrement = i.InputInt32(0);
1618       int slots = stack_decrement / kSystemPointerSize;
1619       LocationOperand* op = LocationOperand::cast(instr->InputAt(1));
1620       MachineRepresentation rep = op->representation();
1621       int pushed_slots = ElementSizeInPointers(rep);
1622       // Slot-sized arguments are never padded but there may be a gap if
1623       // the slot allocator reclaimed other padding slots. Adjust the stack
1624       // here to skip any gap.
1625       __ AllocateStackSpace((slots - pushed_slots) * kSystemPointerSize);
1626       switch (rep) {
1627         case MachineRepresentation::kFloat32:
1628           __ StoreF32WithUpdate(i.InputDoubleRegister(1),
1629                                 MemOperand(sp, -kSystemPointerSize), r0);
1630           break;
1631         case MachineRepresentation::kFloat64:
1632           __ StoreF64WithUpdate(i.InputDoubleRegister(1),
1633                                 MemOperand(sp, -kDoubleSize), r0);
1634           break;
1635         case MachineRepresentation::kSimd128:
1636           __ addi(sp, sp, Operand(-kSimd128Size));
1637           __ StoreSimd128(i.InputSimd128Register(1), MemOperand(r0, sp));
1638           break;
1639         default:
1640           __ StoreU64WithUpdate(i.InputRegister(1),
1641                                 MemOperand(sp, -kSystemPointerSize), r0);
1642           break;
1643       }
1644       frame_access_state()->IncreaseSPDelta(slots);
1645       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1646       break;
1647     }
1648     case kPPC_PushFrame: {
1649       int num_slots = i.InputInt32(1);
1650       if (instr->InputAt(0)->IsFPRegister()) {
1651         LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
1652         if (op->representation() == MachineRepresentation::kFloat64) {
1653           __ StoreF64WithUpdate(i.InputDoubleRegister(0),
1654                                 MemOperand(sp, -num_slots * kSystemPointerSize),
1655                                 r0);
1656         } else {
1657           DCHECK_EQ(MachineRepresentation::kFloat32, op->representation());
1658           __ StoreF32WithUpdate(i.InputDoubleRegister(0),
1659                                 MemOperand(sp, -num_slots * kSystemPointerSize),
1660                                 r0);
1661         }
1662       } else {
1663         __ StoreU64WithUpdate(i.InputRegister(0),
1664                               MemOperand(sp, -num_slots * kSystemPointerSize),
1665                               r0);
1666       }
1667       break;
1668     }
1669     case kPPC_StoreToStackSlot: {
1670       int slot = i.InputInt32(1);
1671       if (instr->InputAt(0)->IsFPRegister()) {
1672         LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
1673         if (op->representation() == MachineRepresentation::kFloat64) {
1674           __ StoreF64(i.InputDoubleRegister(0),
1675                       MemOperand(sp, slot * kSystemPointerSize), r0);
1676         } else if (op->representation() == MachineRepresentation::kFloat32) {
1677           __ StoreF32(i.InputDoubleRegister(0),
1678                       MemOperand(sp, slot * kSystemPointerSize), r0);
1679         } else {
1680           DCHECK_EQ(MachineRepresentation::kSimd128, op->representation());
1681           __ mov(ip, Operand(slot * kSystemPointerSize));
1682           __ StoreSimd128(i.InputSimd128Register(0), MemOperand(ip, sp));
1683         }
1684       } else {
1685         __ StoreU64(i.InputRegister(0),
1686                     MemOperand(sp, slot * kSystemPointerSize), r0);
1687       }
1688       break;
1689     }
1690     case kPPC_ExtendSignWord8:
1691       __ extsb(i.OutputRegister(), i.InputRegister(0));
1692       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1693       break;
1694     case kPPC_ExtendSignWord16:
1695       __ extsh(i.OutputRegister(), i.InputRegister(0));
1696       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1697       break;
1698 #if V8_TARGET_ARCH_PPC64
1699     case kPPC_ExtendSignWord32:
1700       __ extsw(i.OutputRegister(), i.InputRegister(0));
1701       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1702       break;
1703     case kPPC_Uint32ToUint64:
1704       // Zero extend
1705       __ clrldi(i.OutputRegister(), i.InputRegister(0), Operand(32));
1706       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1707       break;
1708     case kPPC_Int64ToInt32:
1709       __ extsw(i.OutputRegister(), i.InputRegister(0));
1710       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1711       break;
1712     case kPPC_Int64ToFloat32:
1713       __ ConvertInt64ToFloat(i.InputRegister(0), i.OutputDoubleRegister());
1714       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1715       break;
1716     case kPPC_Int64ToDouble:
1717       __ ConvertInt64ToDouble(i.InputRegister(0), i.OutputDoubleRegister());
1718       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1719       break;
1720     case kPPC_Uint64ToFloat32:
1721       __ ConvertUnsignedInt64ToFloat(i.InputRegister(0),
1722                                      i.OutputDoubleRegister());
1723       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1724       break;
1725     case kPPC_Uint64ToDouble:
1726       __ ConvertUnsignedInt64ToDouble(i.InputRegister(0),
1727                                       i.OutputDoubleRegister());
1728       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1729       break;
1730 #endif
1731     case kPPC_Int32ToFloat32:
1732       __ ConvertIntToFloat(i.InputRegister(0), i.OutputDoubleRegister());
1733       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1734       break;
1735     case kPPC_Int32ToDouble:
1736       __ ConvertIntToDouble(i.InputRegister(0), i.OutputDoubleRegister());
1737       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1738       break;
1739     case kPPC_Uint32ToFloat32:
1740       __ ConvertUnsignedIntToFloat(i.InputRegister(0),
1741                                    i.OutputDoubleRegister());
1742       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1743       break;
1744     case kPPC_Uint32ToDouble:
1745       __ ConvertUnsignedIntToDouble(i.InputRegister(0),
1746                                     i.OutputDoubleRegister());
1747       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1748       break;
1749     case kPPC_Float32ToInt32: {
1750       bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
1751       if (set_overflow_to_min_i32) {
1752         __ mtfsb0(VXCVI);  // clear FPSCR:VXCVI bit
1753       }
1754       __ fctiwz(kScratchDoubleReg, i.InputDoubleRegister(0));
1755       __ MovDoubleLowToInt(i.OutputRegister(), kScratchDoubleReg);
1756       if (set_overflow_to_min_i32) {
1757         // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
1758         // because INT32_MIN allows easier out-of-bounds detection.
1759         CRegister cr = cr7;
1760         int crbit = v8::internal::Assembler::encode_crbit(
1761             cr, static_cast<CRBit>(VXCVI % CRWIDTH));
1762         __ mcrfs(cr, VXCVI);  // extract FPSCR field containing VXCVI into cr7
1763         __ li(kScratchReg, Operand(1));
1764         __ ShiftLeftU64(kScratchReg, kScratchReg,
1765                         Operand(31));  // generate INT32_MIN.
1766         __ isel(i.OutputRegister(0), kScratchReg, i.OutputRegister(0), crbit);
1767       }
1768       break;
1769     }
1770     case kPPC_Float32ToUint32: {
1771       bool set_overflow_to_min_u32 = MiscField::decode(instr->opcode());
1772       if (set_overflow_to_min_u32) {
1773         __ mtfsb0(VXCVI);  // clear FPSCR:VXCVI bit
1774       }
1775       __ fctiwuz(kScratchDoubleReg, i.InputDoubleRegister(0));
1776       __ MovDoubleLowToInt(i.OutputRegister(), kScratchDoubleReg);
1777       if (set_overflow_to_min_u32) {
1778         // Avoid UINT32_MAX as an overflow indicator and use 0 instead,
1779         // because 0 allows easier out-of-bounds detection.
1780         CRegister cr = cr7;
1781         int crbit = v8::internal::Assembler::encode_crbit(
1782             cr, static_cast<CRBit>(VXCVI % CRWIDTH));
1783         __ mcrfs(cr, VXCVI);  // extract FPSCR field containing VXCVI into cr7
1784         __ li(kScratchReg, Operand::Zero());
1785         __ isel(i.OutputRegister(0), kScratchReg, i.OutputRegister(0), crbit);
1786       }
1787       break;
1788     }
1789     case kPPC_DoubleToInt32:
1790     case kPPC_DoubleToUint32:
1791     case kPPC_DoubleToInt64: {
1792 #if V8_TARGET_ARCH_PPC64
1793       bool check_conversion =
1794           (opcode == kPPC_DoubleToInt64 && i.OutputCount() > 1);
1795         __ mtfsb0(VXCVI);  // clear FPSCR:VXCVI bit
1796 #endif
1797       __ ConvertDoubleToInt64(i.InputDoubleRegister(0),
1798 #if !V8_TARGET_ARCH_PPC64
1799                               kScratchReg,
1800 #endif
1801                               i.OutputRegister(0), kScratchDoubleReg);
1802 #if V8_TARGET_ARCH_PPC64
1803         CRegister cr = cr7;
1804         int crbit = v8::internal::Assembler::encode_crbit(
1805             cr, static_cast<CRBit>(VXCVI % CRWIDTH));
1806         __ mcrfs(cr, VXCVI);  // extract FPSCR field containing VXCVI into cr7
1807         // Handle conversion failures (such as overflow).
1808         if (CpuFeatures::IsSupported(PPC_7_PLUS)) {
1809           if (check_conversion) {
1810             __ li(i.OutputRegister(1), Operand(1));
1811             __ isel(i.OutputRegister(1), r0, i.OutputRegister(1), crbit);
1812           } else {
1813             __ isel(i.OutputRegister(0), r0, i.OutputRegister(0), crbit);
1814           }
1815         } else {
1816           if (check_conversion) {
1817             __ li(i.OutputRegister(1), Operand::Zero());
1818             __ bc(v8::internal::kInstrSize * 2, BT, crbit);
1819             __ li(i.OutputRegister(1), Operand(1));
1820           } else {
1821             __ mr(ip, i.OutputRegister(0));
1822             __ li(i.OutputRegister(0), Operand::Zero());
1823             __ bc(v8::internal::kInstrSize * 2, BT, crbit);
1824             __ mr(i.OutputRegister(0), ip);
1825           }
1826         }
1827 #endif
1828       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1829       break;
1830     }
1831 #if V8_TARGET_ARCH_PPC64
1832     case kPPC_DoubleToUint64: {
1833       bool check_conversion = (i.OutputCount() > 1);
1834       if (check_conversion) {
1835         __ mtfsb0(VXCVI);  // clear FPSCR:VXCVI bit
1836       }
1837       __ ConvertDoubleToUnsignedInt64(i.InputDoubleRegister(0),
1838                                       i.OutputRegister(0), kScratchDoubleReg);
1839       if (check_conversion) {
1840         // Set 2nd output to zero if conversion fails.
1841         CRegister cr = cr7;
1842         int crbit = v8::internal::Assembler::encode_crbit(
1843             cr, static_cast<CRBit>(VXCVI % CRWIDTH));
1844         __ mcrfs(cr, VXCVI);  // extract FPSCR field containing VXCVI into cr7
1845         if (CpuFeatures::IsSupported(PPC_7_PLUS)) {
1846           __ li(i.OutputRegister(1), Operand(1));
1847           __ isel(i.OutputRegister(1), r0, i.OutputRegister(1), crbit);
1848         } else {
1849           __ li(i.OutputRegister(1), Operand::Zero());
1850           __ bc(v8::internal::kInstrSize * 2, BT, crbit);
1851           __ li(i.OutputRegister(1), Operand(1));
1852         }
1853       }
1854       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1855       break;
1856     }
1857 #endif
1858     case kPPC_DoubleToFloat32:
1859       ASSEMBLE_FLOAT_UNOP_RC(frsp, 0);
1860       break;
1861     case kPPC_Float32ToDouble:
1862       // Nothing to do.
1863       __ Move(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1864       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1865       break;
1866     case kPPC_DoubleExtractLowWord32:
1867       __ MovDoubleLowToInt(i.OutputRegister(), i.InputDoubleRegister(0));
1868       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1869       break;
1870     case kPPC_DoubleExtractHighWord32:
1871       __ MovDoubleHighToInt(i.OutputRegister(), i.InputDoubleRegister(0));
1872       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1873       break;
1874     case kPPC_DoubleInsertLowWord32:
1875       __ InsertDoubleLow(i.OutputDoubleRegister(), i.InputRegister(1), r0);
1876       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1877       break;
1878     case kPPC_DoubleInsertHighWord32:
1879       __ InsertDoubleHigh(i.OutputDoubleRegister(), i.InputRegister(1), r0);
1880       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1881       break;
1882     case kPPC_DoubleConstruct:
1883 #if V8_TARGET_ARCH_PPC64
1884       __ MovInt64ComponentsToDouble(i.OutputDoubleRegister(),
1885                                     i.InputRegister(0), i.InputRegister(1), r0);
1886 #else
1887       __ MovInt64ToDouble(i.OutputDoubleRegister(), i.InputRegister(0),
1888                           i.InputRegister(1));
1889 #endif
1890       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1891       break;
1892     case kPPC_BitcastFloat32ToInt32:
1893       __ MovFloatToInt(i.OutputRegister(), i.InputDoubleRegister(0),
1894                        kScratchDoubleReg);
1895       break;
1896     case kPPC_BitcastInt32ToFloat32:
1897       __ MovIntToFloat(i.OutputDoubleRegister(), i.InputRegister(0), ip);
1898       break;
1899 #if V8_TARGET_ARCH_PPC64
1900     case kPPC_BitcastDoubleToInt64:
1901       __ MovDoubleToInt64(i.OutputRegister(), i.InputDoubleRegister(0));
1902       break;
1903     case kPPC_BitcastInt64ToDouble:
1904       __ MovInt64ToDouble(i.OutputDoubleRegister(), i.InputRegister(0));
1905       break;
1906 #endif
1907     case kPPC_LoadWordU8:
1908       ASSEMBLE_LOAD_INTEGER(lbz, lbzx);
1909       break;
1910     case kPPC_LoadWordS8:
1911       ASSEMBLE_LOAD_INTEGER(lbz, lbzx);
1912       __ extsb(i.OutputRegister(), i.OutputRegister());
1913       break;
1914     case kPPC_LoadWordU16:
1915       ASSEMBLE_LOAD_INTEGER(lhz, lhzx);
1916       break;
1917     case kPPC_LoadWordS16:
1918       ASSEMBLE_LOAD_INTEGER(lha, lhax);
1919       break;
1920     case kPPC_LoadWordU32:
1921       ASSEMBLE_LOAD_INTEGER(lwz, lwzx);
1922       break;
1923     case kPPC_LoadWordS32:
1924       ASSEMBLE_LOAD_INTEGER(lwa, lwax);
1925       break;
1926 #if V8_TARGET_ARCH_PPC64
1927     case kPPC_LoadWord64:
1928       ASSEMBLE_LOAD_INTEGER(ld, ldx);
1929       break;
1930 #endif
1931     case kPPC_LoadFloat32:
1932       ASSEMBLE_LOAD_FLOAT(lfs, lfsx);
1933       break;
1934     case kPPC_LoadDouble:
1935       ASSEMBLE_LOAD_FLOAT(lfd, lfdx);
1936       break;
1937     case kPPC_LoadSimd128: {
1938       Simd128Register result = i.OutputSimd128Register();
1939       AddressingMode mode = kMode_None;
1940       MemOperand operand = i.MemoryOperand(&mode);
1941       bool is_atomic = i.InputInt32(2);
1942       DCHECK_EQ(mode, kMode_MRR);
1943       __ LoadSimd128(result, operand);
1944       if (is_atomic) __ lwsync();
1945       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1946       break;
1947     }
1948     case kPPC_LoadReverseSimd128RR: {
1949       __ xxbrq(i.OutputSimd128Register(), i.InputSimd128Register(0));
1950       break;
1951     }
1952     case kPPC_StoreWord8:
1953       ASSEMBLE_STORE_INTEGER(stb, stbx);
1954       break;
1955     case kPPC_StoreWord16:
1956       ASSEMBLE_STORE_INTEGER(sth, sthx);
1957       break;
1958     case kPPC_StoreWord32:
1959       ASSEMBLE_STORE_INTEGER(stw, stwx);
1960       break;
1961 #if V8_TARGET_ARCH_PPC64
1962     case kPPC_StoreWord64:
1963       ASSEMBLE_STORE_INTEGER(std, stdx);
1964       break;
1965 #endif
1966     case kPPC_StoreFloat32:
1967       ASSEMBLE_STORE_FLOAT(stfs, stfsx);
1968       break;
1969     case kPPC_StoreDouble:
1970       ASSEMBLE_STORE_FLOAT(stfd, stfdx);
1971       break;
1972     case kPPC_StoreSimd128: {
1973       size_t index = 0;
1974       AddressingMode mode = kMode_None;
1975       MemOperand operand = i.MemoryOperand(&mode, &index);
1976       Simd128Register value = i.InputSimd128Register(index);
1977       bool is_atomic = i.InputInt32(3);
1978       if (is_atomic) __ lwsync();
1979       DCHECK_EQ(mode, kMode_MRR);
1980       __ StoreSimd128(value, operand);
1981       if (is_atomic) __ sync();
1982       DCHECK_EQ(LeaveRC, i.OutputRCBit());
1983       break;
1984     }
1985     case kAtomicLoadInt8:
1986     case kAtomicLoadInt16:
1987       UNREACHABLE();
1988     case kAtomicExchangeInt8:
1989       __ AtomicExchange<int8_t>(
1990           MemOperand(i.InputRegister(0), i.InputRegister(1)),
1991           i.InputRegister(2), i.OutputRegister());
1992       break;
1993     case kPPC_AtomicExchangeUint8:
1994       __ AtomicExchange<uint8_t>(
1995           MemOperand(i.InputRegister(0), i.InputRegister(1)),
1996           i.InputRegister(2), i.OutputRegister());
1997       break;
1998     case kAtomicExchangeInt16:
1999       __ AtomicExchange<int16_t>(
2000           MemOperand(i.InputRegister(0), i.InputRegister(1)),
2001           i.InputRegister(2), i.OutputRegister());
2002       break;
2003     case kPPC_AtomicExchangeUint16:
2004       __ AtomicExchange<uint16_t>(
2005           MemOperand(i.InputRegister(0), i.InputRegister(1)),
2006           i.InputRegister(2), i.OutputRegister());
2007       break;
2008     case kPPC_AtomicExchangeWord32:
2009       __ AtomicExchange<uint32_t>(
2010           MemOperand(i.InputRegister(0), i.InputRegister(1)),
2011           i.InputRegister(2), i.OutputRegister());
2012       break;
2013     case kPPC_AtomicExchangeWord64:
2014       __ AtomicExchange<uint64_t>(
2015           MemOperand(i.InputRegister(0), i.InputRegister(1)),
2016           i.InputRegister(2), i.OutputRegister());
2017       break;
2018     case kAtomicCompareExchangeInt8:
2019       __ AtomicCompareExchange<int8_t>(
2020           MemOperand(i.InputRegister(0), i.InputRegister(1)),
2021           i.InputRegister(2), i.InputRegister(3), i.OutputRegister(),
2022           kScratchReg);
2023       break;
2024     case kPPC_AtomicCompareExchangeUint8:
2025       __ AtomicCompareExchange<uint8_t>(
2026           MemOperand(i.InputRegister(0), i.InputRegister(1)),
2027           i.InputRegister(2), i.InputRegister(3), i.OutputRegister(),
2028           kScratchReg);
2029       break;
2030     case kAtomicCompareExchangeInt16:
2031       __ AtomicCompareExchange<int16_t>(
2032           MemOperand(i.InputRegister(0), i.InputRegister(1)),
2033           i.InputRegister(2), i.InputRegister(3), i.OutputRegister(),
2034           kScratchReg);
2035       break;
2036     case kPPC_AtomicCompareExchangeUint16:
2037       __ AtomicCompareExchange<uint16_t>(
2038           MemOperand(i.InputRegister(0), i.InputRegister(1)),
2039           i.InputRegister(2), i.InputRegister(3), i.OutputRegister(),
2040           kScratchReg);
2041       break;
2042     case kPPC_AtomicCompareExchangeWord32:
2043       __ AtomicCompareExchange<uint32_t>(
2044           MemOperand(i.InputRegister(0), i.InputRegister(1)),
2045           i.InputRegister(2), i.InputRegister(3), i.OutputRegister(),
2046           kScratchReg);
2047       break;
2048     case kPPC_AtomicCompareExchangeWord64:
2049       __ AtomicCompareExchange<uint64_t>(
2050           MemOperand(i.InputRegister(0), i.InputRegister(1)),
2051           i.InputRegister(2), i.InputRegister(3), i.OutputRegister(),
2052           kScratchReg);
2053       break;
2054 
2055 #define ATOMIC_BINOP_CASE(op, inst)        \
2056   case kPPC_Atomic##op##Int8:              \
2057     ASSEMBLE_ATOMIC_BINOP(inst, int8_t);   \
2058     break;                                 \
2059   case kPPC_Atomic##op##Uint8:             \
2060     ASSEMBLE_ATOMIC_BINOP(inst, uint8_t);  \
2061     break;                                 \
2062   case kPPC_Atomic##op##Int16:             \
2063     ASSEMBLE_ATOMIC_BINOP(inst, int16_t);  \
2064     break;                                 \
2065   case kPPC_Atomic##op##Uint16:            \
2066     ASSEMBLE_ATOMIC_BINOP(inst, uint16_t); \
2067     break;                                 \
2068   case kPPC_Atomic##op##Int32:             \
2069     ASSEMBLE_ATOMIC_BINOP(inst, int32_t);  \
2070     break;                                 \
2071   case kPPC_Atomic##op##Uint32:            \
2072     ASSEMBLE_ATOMIC_BINOP(inst, uint32_t); \
2073     break;                                 \
2074   case kPPC_Atomic##op##Int64:             \
2075   case kPPC_Atomic##op##Uint64:            \
2076     ASSEMBLE_ATOMIC_BINOP(inst, uint64_t); \
2077     break;
2078       ATOMIC_BINOP_CASE(Add, add)
2079       ATOMIC_BINOP_CASE(Sub, sub)
2080       ATOMIC_BINOP_CASE(And, and_)
2081       ATOMIC_BINOP_CASE(Or, orx)
2082       ATOMIC_BINOP_CASE(Xor, xor_)
2083 #undef ATOMIC_BINOP_CASE
2084 
2085     case kPPC_ByteRev32: {
2086       Register input = i.InputRegister(0);
2087       Register output = i.OutputRegister();
2088       Register temp1 = r0;
2089       if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
2090         __ brw(output, input);
2091         break;
2092       }
2093       __ rotlwi(temp1, input, 8);
2094       __ rlwimi(temp1, input, 24, 0, 7);
2095       __ rlwimi(temp1, input, 24, 16, 23);
2096       __ extsw(output, temp1);
2097       break;
2098     }
2099     case kPPC_LoadByteRev32: {
2100       ASSEMBLE_LOAD_INTEGER_RR(lwbrx);
2101       break;
2102     }
2103     case kPPC_StoreByteRev32: {
2104       ASSEMBLE_STORE_INTEGER_RR(stwbrx);
2105       break;
2106     }
2107     case kPPC_ByteRev64: {
2108       Register input = i.InputRegister(0);
2109       Register output = i.OutputRegister();
2110       Register temp1 = r0;
2111       Register temp2 = kScratchReg;
2112       Register temp3 = i.TempRegister(0);
2113       if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
2114         __ brd(output, input);
2115         break;
2116       }
2117       __ rldicl(temp1, input, 32, 32);
2118       __ rotlwi(temp2, input, 8);
2119       __ rlwimi(temp2, input, 24, 0, 7);
2120       __ rotlwi(temp3, temp1, 8);
2121       __ rlwimi(temp2, input, 24, 16, 23);
2122       __ rlwimi(temp3, temp1, 24, 0, 7);
2123       __ rlwimi(temp3, temp1, 24, 16, 23);
2124       __ rldicr(temp2, temp2, 32, 31);
2125       __ orx(output, temp2, temp3);
2126       break;
2127     }
2128     case kPPC_LoadByteRev64: {
2129       ASSEMBLE_LOAD_INTEGER_RR(ldbrx);
2130       break;
2131     }
2132     case kPPC_StoreByteRev64: {
2133       ASSEMBLE_STORE_INTEGER_RR(stdbrx);
2134       break;
2135     }
2136     case kPPC_F64x2Splat: {
2137       constexpr int lane_width_in_bytes = 8;
2138       Simd128Register dst = i.OutputSimd128Register();
2139       __ MovDoubleToInt64(kScratchReg, i.InputDoubleRegister(0));
2140       __ mtvsrd(dst, kScratchReg);
2141       __ vinsertd(dst, dst, Operand(1 * lane_width_in_bytes));
2142       break;
2143     }
2144     case kPPC_F32x4Splat: {
2145       Simd128Register dst = i.OutputSimd128Register();
2146       __ MovFloatToInt(kScratchReg, i.InputDoubleRegister(0),
2147                        kScratchDoubleReg);
2148       __ mtvsrd(dst, kScratchReg);
2149       __ vspltw(dst, dst, Operand(1));
2150       break;
2151     }
2152     case kPPC_I64x2Splat: {
2153       constexpr int lane_width_in_bytes = 8;
2154       Simd128Register dst = i.OutputSimd128Register();
2155       __ mtvsrd(dst, i.InputRegister(0));
2156       __ vinsertd(dst, dst, Operand(1 * lane_width_in_bytes));
2157       break;
2158     }
2159     case kPPC_I32x4Splat: {
2160       Simd128Register dst = i.OutputSimd128Register();
2161       __ mtvsrd(dst, i.InputRegister(0));
2162       __ vspltw(dst, dst, Operand(1));
2163       break;
2164     }
2165     case kPPC_I16x8Splat: {
2166       Simd128Register dst = i.OutputSimd128Register();
2167       __ mtvsrd(dst, i.InputRegister(0));
2168       __ vsplth(dst, dst, Operand(3));
2169       break;
2170     }
2171     case kPPC_I8x16Splat: {
2172       Simd128Register dst = i.OutputSimd128Register();
2173       __ mtvsrd(dst, i.InputRegister(0));
2174       __ vspltb(dst, dst, Operand(7));
2175       break;
2176     }
2177     case kPPC_F64x2ExtractLane: {
2178       constexpr int lane_width_in_bytes = 8;
2179       __ vextractd(kScratchSimd128Reg, i.InputSimd128Register(0),
2180                    Operand((1 - i.InputInt8(1)) * lane_width_in_bytes));
2181       __ mfvsrd(kScratchReg, kScratchSimd128Reg);
2182       __ MovInt64ToDouble(i.OutputDoubleRegister(), kScratchReg);
2183       break;
2184     }
2185     case kPPC_F32x4ExtractLane: {
2186       constexpr int lane_width_in_bytes = 4;
2187       __ vextractuw(kScratchSimd128Reg, i.InputSimd128Register(0),
2188                     Operand((3 - i.InputInt8(1)) * lane_width_in_bytes));
2189       __ mfvsrd(kScratchReg, kScratchSimd128Reg);
2190       __ MovIntToFloat(i.OutputDoubleRegister(), kScratchReg, ip);
2191       break;
2192     }
2193     case kPPC_I64x2ExtractLane: {
2194       constexpr int lane_width_in_bytes = 8;
2195       __ vextractd(kScratchSimd128Reg, i.InputSimd128Register(0),
2196                    Operand((1 - i.InputInt8(1)) * lane_width_in_bytes));
2197       __ mfvsrd(i.OutputRegister(), kScratchSimd128Reg);
2198       break;
2199     }
2200     case kPPC_I32x4ExtractLane: {
2201       constexpr int lane_width_in_bytes = 4;
2202       __ vextractuw(kScratchSimd128Reg, i.InputSimd128Register(0),
2203                     Operand((3 - i.InputInt8(1)) * lane_width_in_bytes));
2204       __ mfvsrd(i.OutputRegister(), kScratchSimd128Reg);
2205       break;
2206     }
2207     case kPPC_I16x8ExtractLaneU: {
2208       constexpr int lane_width_in_bytes = 2;
2209       __ vextractuh(kScratchSimd128Reg, i.InputSimd128Register(0),
2210                     Operand((7 - i.InputInt8(1)) * lane_width_in_bytes));
2211       __ mfvsrd(i.OutputRegister(), kScratchSimd128Reg);
2212       break;
2213     }
2214     case kPPC_I16x8ExtractLaneS: {
2215       constexpr int lane_width_in_bytes = 2;
2216       __ vextractuh(kScratchSimd128Reg, i.InputSimd128Register(0),
2217                     Operand((7 - i.InputInt8(1)) * lane_width_in_bytes));
2218       __ mfvsrd(kScratchReg, kScratchSimd128Reg);
2219       __ extsh(i.OutputRegister(), kScratchReg);
2220       break;
2221     }
2222     case kPPC_I8x16ExtractLaneU: {
2223       __ vextractub(kScratchSimd128Reg, i.InputSimd128Register(0),
2224                     Operand(15 - i.InputInt8(1)));
2225       __ mfvsrd(i.OutputRegister(), kScratchSimd128Reg);
2226       break;
2227     }
2228     case kPPC_I8x16ExtractLaneS: {
2229       __ vextractub(kScratchSimd128Reg, i.InputSimd128Register(0),
2230                     Operand(15 - i.InputInt8(1)));
2231       __ mfvsrd(kScratchReg, kScratchSimd128Reg);
2232       __ extsb(i.OutputRegister(), kScratchReg);
2233       break;
2234     }
2235     case kPPC_F64x2ReplaceLane: {
2236       DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
2237       constexpr int lane_width_in_bytes = 8;
2238       Simd128Register dst = i.OutputSimd128Register();
2239       __ MovDoubleToInt64(r0, i.InputDoubleRegister(2));
2240       if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
2241         __ vinsd(dst, r0, Operand((1 - i.InputInt8(1)) * lane_width_in_bytes));
2242       } else {
2243         __ mtvsrd(kScratchSimd128Reg, r0);
2244         __ vinsertd(dst, kScratchSimd128Reg,
2245                     Operand((1 - i.InputInt8(1)) * lane_width_in_bytes));
2246       }
2247       break;
2248     }
2249     case kPPC_F32x4ReplaceLane: {
2250       DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
2251       constexpr int lane_width_in_bytes = 4;
2252       Simd128Register dst = i.OutputSimd128Register();
2253       __ MovFloatToInt(r0, i.InputDoubleRegister(2), kScratchDoubleReg);
2254       if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
2255         __ vinsw(dst, r0, Operand((3 - i.InputInt8(1)) * lane_width_in_bytes));
2256       } else {
2257         __ mtvsrd(kScratchSimd128Reg, r0);
2258         __ vinsertw(dst, kScratchSimd128Reg,
2259                     Operand((3 - i.InputInt8(1)) * lane_width_in_bytes));
2260       }
2261       break;
2262     }
2263     case kPPC_I64x2ReplaceLane: {
2264       DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
2265       constexpr int lane_width_in_bytes = 8;
2266       Simd128Register dst = i.OutputSimd128Register();
2267       if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
2268         __ vinsd(dst, i.InputRegister(2),
2269                  Operand((1 - i.InputInt8(1)) * lane_width_in_bytes));
2270       } else {
2271         __ mtvsrd(kScratchSimd128Reg, i.InputRegister(2));
2272         __ vinsertd(dst, kScratchSimd128Reg,
2273                     Operand((1 - i.InputInt8(1)) * lane_width_in_bytes));
2274       }
2275       break;
2276     }
2277     case kPPC_I32x4ReplaceLane: {
2278       DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
2279       constexpr int lane_width_in_bytes = 4;
2280       Simd128Register dst = i.OutputSimd128Register();
2281       if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
2282         __ vinsw(dst, i.InputRegister(2),
2283                  Operand((3 - i.InputInt8(1)) * lane_width_in_bytes));
2284       } else {
2285         __ mtvsrd(kScratchSimd128Reg, i.InputRegister(2));
2286         __ vinsertw(dst, kScratchSimd128Reg,
2287                     Operand((3 - i.InputInt8(1)) * lane_width_in_bytes));
2288       }
2289       break;
2290     }
2291     case kPPC_I16x8ReplaceLane: {
2292       DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
2293       constexpr int lane_width_in_bytes = 2;
2294       Simd128Register dst = i.OutputSimd128Register();
2295       __ mtvsrd(kScratchSimd128Reg, i.InputRegister(2));
2296       __ vinserth(dst, kScratchSimd128Reg,
2297                   Operand((7 - i.InputInt8(1)) * lane_width_in_bytes));
2298       break;
2299     }
2300     case kPPC_I8x16ReplaceLane: {
2301       DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
2302       Simd128Register dst = i.OutputSimd128Register();
2303       __ mtvsrd(kScratchSimd128Reg, i.InputRegister(2));
2304       __ vinsertb(dst, kScratchSimd128Reg, Operand(15 - i.InputInt8(1)));
2305       break;
2306     }
2307     case kPPC_F64x2Add: {
2308       __ xvadddp(i.OutputSimd128Register(), i.InputSimd128Register(0),
2309                  i.InputSimd128Register(1));
2310       break;
2311     }
2312     case kPPC_F64x2Sub: {
2313       __ xvsubdp(i.OutputSimd128Register(), i.InputSimd128Register(0),
2314                  i.InputSimd128Register(1));
2315       break;
2316     }
2317     case kPPC_F64x2Mul: {
2318       __ xvmuldp(i.OutputSimd128Register(), i.InputSimd128Register(0),
2319                  i.InputSimd128Register(1));
2320       break;
2321     }
2322     case kPPC_F32x4Add: {
2323       __ vaddfp(i.OutputSimd128Register(), i.InputSimd128Register(0),
2324                 i.InputSimd128Register(1));
2325       break;
2326     }
2327     case kPPC_F32x4Sub: {
2328       __ vsubfp(i.OutputSimd128Register(), i.InputSimd128Register(0),
2329                 i.InputSimd128Register(1));
2330       break;
2331     }
2332     case kPPC_F32x4Mul: {
2333       __ xvmulsp(i.OutputSimd128Register(), i.InputSimd128Register(0),
2334                  i.InputSimd128Register(1));
2335       break;
2336     }
2337     case kPPC_I64x2Add: {
2338       __ vaddudm(i.OutputSimd128Register(), i.InputSimd128Register(0),
2339                  i.InputSimd128Register(1));
2340       break;
2341     }
2342     case kPPC_I64x2Sub: {
2343       __ vsubudm(i.OutputSimd128Register(), i.InputSimd128Register(0),
2344                  i.InputSimd128Register(1));
2345       break;
2346     }
2347     case kPPC_I64x2Mul: {
2348       constexpr int lane_width_in_bytes = 8;
2349       Simd128Register src0 = i.InputSimd128Register(0);
2350       Simd128Register src1 = i.InputSimd128Register(1);
2351       Simd128Register tempFPReg0 = i.ToSimd128Register(instr->TempAt(0));
2352       Register tempReg1 = i.ToRegister(instr->TempAt(2));
2353       Register scratch_0 = ip;
2354       Register scratch_1 = r0;
2355       Simd128Register dst = i.OutputSimd128Register();
2356       if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
2357         __ vmulld(dst, src0, src1);
2358       } else {
2359         for (int i = 0; i < 2; i++) {
2360           if (i > 0) {
2361             __ vextractd(kScratchSimd128Reg, src0,
2362                          Operand(1 * lane_width_in_bytes));
2363             __ vextractd(tempFPReg0, src1, Operand(1 * lane_width_in_bytes));
2364             src0 = kScratchSimd128Reg;
2365             src1 = tempFPReg0;
2366           }
2367           __ mfvsrd(scratch_0, src0);
2368           __ mfvsrd(scratch_1, src1);
2369           __ mulld(scratch_0, scratch_0, scratch_1);
2370           scratch_0 = r0;
2371           scratch_1 = tempReg1;
2372         }
2373         __ mtvsrdd(dst, ip, r0);
2374       }
2375       break;
2376     }
2377     case kPPC_I32x4Add: {
2378       __ vadduwm(i.OutputSimd128Register(), i.InputSimd128Register(0),
2379                  i.InputSimd128Register(1));
2380       break;
2381     }
2382     case kPPC_I32x4Sub: {
2383       __ vsubuwm(i.OutputSimd128Register(), i.InputSimd128Register(0),
2384                  i.InputSimd128Register(1));
2385       break;
2386     }
2387     case kPPC_I32x4Mul: {
2388       __ vmuluwm(i.OutputSimd128Register(), i.InputSimd128Register(0),
2389                  i.InputSimd128Register(1));
2390       break;
2391     }
2392     case kPPC_I16x8Add: {
2393       __ vadduhm(i.OutputSimd128Register(), i.InputSimd128Register(0),
2394                  i.InputSimd128Register(1));
2395       break;
2396     }
2397     case kPPC_I16x8Sub: {
2398       __ vsubuhm(i.OutputSimd128Register(), i.InputSimd128Register(0),
2399                  i.InputSimd128Register(1));
2400       break;
2401     }
2402     case kPPC_I16x8Mul: {
2403       Simd128Register src0 = i.InputSimd128Register(0);
2404       Simd128Register src1 = i.InputSimd128Register(1);
2405       Simd128Register dst = i.OutputSimd128Register();
2406       __ vxor(kScratchSimd128Reg, kScratchSimd128Reg, kScratchSimd128Reg);
2407       __ vmladduhm(dst, src0, src1, kScratchSimd128Reg);
2408       break;
2409     }
2410     case kPPC_I8x16Add: {
2411       __ vaddubm(i.OutputSimd128Register(), i.InputSimd128Register(0),
2412                  i.InputSimd128Register(1));
2413       break;
2414     }
2415     case kPPC_I8x16Sub: {
2416       __ vsububm(i.OutputSimd128Register(), i.InputSimd128Register(0),
2417                  i.InputSimd128Register(1));
2418       break;
2419     }
2420     case kPPC_I32x4MinS: {
2421       __ vminsw(i.OutputSimd128Register(), i.InputSimd128Register(0),
2422                 i.InputSimd128Register(1));
2423       break;
2424     }
2425     case kPPC_I32x4MinU: {
2426       __ vminuw(i.OutputSimd128Register(), i.InputSimd128Register(0),
2427                 i.InputSimd128Register(1));
2428       break;
2429     }
2430     case kPPC_I16x8MinS: {
2431       __ vminsh(i.OutputSimd128Register(), i.InputSimd128Register(0),
2432                 i.InputSimd128Register(1));
2433       break;
2434     }
2435     case kPPC_I16x8MinU: {
2436       __ vminuh(i.OutputSimd128Register(), i.InputSimd128Register(0),
2437                 i.InputSimd128Register(1));
2438       break;
2439     }
2440     case kPPC_I8x16MinS: {
2441       __ vminsb(i.OutputSimd128Register(), i.InputSimd128Register(0),
2442                 i.InputSimd128Register(1));
2443       break;
2444     }
2445     case kPPC_I8x16MinU: {
2446       __ vminub(i.OutputSimd128Register(), i.InputSimd128Register(0),
2447                 i.InputSimd128Register(1));
2448       break;
2449     }
2450     case kPPC_I32x4MaxS: {
2451       __ vmaxsw(i.OutputSimd128Register(), i.InputSimd128Register(0),
2452                 i.InputSimd128Register(1));
2453       break;
2454     }
2455     case kPPC_I32x4MaxU: {
2456       __ vmaxuw(i.OutputSimd128Register(), i.InputSimd128Register(0),
2457                 i.InputSimd128Register(1));
2458       break;
2459     }
2460     case kPPC_I16x8MaxS: {
2461       __ vmaxsh(i.OutputSimd128Register(), i.InputSimd128Register(0),
2462                 i.InputSimd128Register(1));
2463       break;
2464     }
2465     case kPPC_I16x8MaxU: {
2466       __ vmaxuh(i.OutputSimd128Register(), i.InputSimd128Register(0),
2467                 i.InputSimd128Register(1));
2468       break;
2469     }
2470     case kPPC_I8x16MaxS: {
2471       __ vmaxsb(i.OutputSimd128Register(), i.InputSimd128Register(0),
2472                 i.InputSimd128Register(1));
2473       break;
2474     }
2475     case kPPC_I8x16MaxU: {
2476       __ vmaxub(i.OutputSimd128Register(), i.InputSimd128Register(0),
2477                 i.InputSimd128Register(1));
2478       break;
2479     }
2480     case kPPC_F64x2Eq: {
2481       __ xvcmpeqdp(i.OutputSimd128Register(), i.InputSimd128Register(0),
2482                    i.InputSimd128Register(1));
2483       break;
2484     }
2485     case kPPC_F64x2Ne: {
2486       __ xvcmpeqdp(kScratchSimd128Reg, i.InputSimd128Register(0),
2487                    i.InputSimd128Register(1));
2488       __ vnor(i.OutputSimd128Register(), kScratchSimd128Reg,
2489               kScratchSimd128Reg);
2490       break;
2491     }
2492     case kPPC_F64x2Le: {
2493       __ xvcmpgedp(i.OutputSimd128Register(), i.InputSimd128Register(1),
2494                    i.InputSimd128Register(0));
2495       break;
2496     }
2497     case kPPC_F64x2Lt: {
2498       __ xvcmpgtdp(i.OutputSimd128Register(), i.InputSimd128Register(1),
2499                    i.InputSimd128Register(0));
2500       break;
2501     }
2502     case kPPC_F32x4Eq: {
2503       __ xvcmpeqsp(i.OutputSimd128Register(), i.InputSimd128Register(0),
2504                    i.InputSimd128Register(1));
2505       break;
2506     }
2507     case kPPC_I64x2Eq: {
2508       __ vcmpequd(i.OutputSimd128Register(), i.InputSimd128Register(0),
2509                   i.InputSimd128Register(1));
2510       break;
2511     }
2512     case kPPC_I32x4Eq: {
2513       __ vcmpequw(i.OutputSimd128Register(), i.InputSimd128Register(0),
2514                   i.InputSimd128Register(1));
2515       break;
2516     }
2517     case kPPC_I16x8Eq: {
2518       __ vcmpequh(i.OutputSimd128Register(), i.InputSimd128Register(0),
2519                   i.InputSimd128Register(1));
2520       break;
2521     }
2522     case kPPC_I8x16Eq: {
2523       __ vcmpequb(i.OutputSimd128Register(), i.InputSimd128Register(0),
2524                   i.InputSimd128Register(1));
2525       break;
2526     }
2527     case kPPC_F32x4Ne: {
2528       __ xvcmpeqsp(kScratchSimd128Reg, i.InputSimd128Register(0),
2529                    i.InputSimd128Register(1));
2530       __ vnor(i.OutputSimd128Register(), kScratchSimd128Reg,
2531               kScratchSimd128Reg);
2532       break;
2533     }
2534     case kPPC_I64x2Ne: {
2535       __ vcmpequd(kScratchSimd128Reg, i.InputSimd128Register(0),
2536                   i.InputSimd128Register(1));
2537       __ vnor(i.OutputSimd128Register(), kScratchSimd128Reg,
2538               kScratchSimd128Reg);
2539       break;
2540     }
2541     case kPPC_I32x4Ne: {
2542       __ vcmpequw(kScratchSimd128Reg, i.InputSimd128Register(0),
2543                   i.InputSimd128Register(1));
2544       __ vnor(i.OutputSimd128Register(), kScratchSimd128Reg,
2545               kScratchSimd128Reg);
2546       break;
2547     }
2548     case kPPC_I16x8Ne: {
2549       __ vcmpequh(kScratchSimd128Reg, i.InputSimd128Register(0),
2550                   i.InputSimd128Register(1));
2551       __ vnor(i.OutputSimd128Register(), kScratchSimd128Reg,
2552               kScratchSimd128Reg);
2553       break;
2554     }
2555     case kPPC_I8x16Ne: {
2556       __ vcmpequb(kScratchSimd128Reg, i.InputSimd128Register(0),
2557                   i.InputSimd128Register(1));
2558       __ vnor(i.OutputSimd128Register(), kScratchSimd128Reg,
2559               kScratchSimd128Reg);
2560       break;
2561     }
2562     case kPPC_F32x4Lt: {
2563       __ xvcmpgtsp(i.OutputSimd128Register(), i.InputSimd128Register(1),
2564                    i.InputSimd128Register(0));
2565       break;
2566     }
2567     case kPPC_F32x4Le: {
2568       __ xvcmpgesp(i.OutputSimd128Register(), i.InputSimd128Register(1),
2569                    i.InputSimd128Register(0));
2570       break;
2571     }
2572     case kPPC_I64x2GtS: {
2573       __ vcmpgtsd(i.OutputSimd128Register(), i.InputSimd128Register(0),
2574                   i.InputSimd128Register(1));
2575       break;
2576     }
2577     case kPPC_I32x4GtS: {
2578       __ vcmpgtsw(i.OutputSimd128Register(), i.InputSimd128Register(0),
2579                   i.InputSimd128Register(1));
2580       break;
2581     }
2582     case kPPC_I64x2GeS: {
2583       __ vcmpgtsd(kScratchSimd128Reg, i.InputSimd128Register(1),
2584                   i.InputSimd128Register(0));
2585       __ vnor(i.OutputSimd128Register(), kScratchSimd128Reg,
2586               kScratchSimd128Reg);
2587       break;
2588     }
2589     case kPPC_I32x4GeS: {
2590       __ vcmpgtsw(kScratchSimd128Reg, i.InputSimd128Register(1),
2591                   i.InputSimd128Register(0));
2592       __ vnor(i.OutputSimd128Register(), kScratchSimd128Reg,
2593               kScratchSimd128Reg);
2594       break;
2595     }
2596     case kPPC_I32x4GtU: {
2597       __ vcmpgtuw(i.OutputSimd128Register(), i.InputSimd128Register(0),
2598                   i.InputSimd128Register(1));
2599 
2600       break;
2601     }
2602     case kPPC_I32x4GeU: {
2603       __ vcmpequw(kScratchSimd128Reg, i.InputSimd128Register(0),
2604                   i.InputSimd128Register(1));
2605       __ vcmpgtuw(i.OutputSimd128Register(), i.InputSimd128Register(0),
2606                   i.InputSimd128Register(1));
2607       __ vor(i.OutputSimd128Register(), i.OutputSimd128Register(),
2608              kScratchSimd128Reg);
2609       break;
2610     }
2611     case kPPC_I16x8GtS: {
2612       __ vcmpgtsh(i.OutputSimd128Register(), i.InputSimd128Register(0),
2613                   i.InputSimd128Register(1));
2614       break;
2615     }
2616     case kPPC_I16x8GeS: {
2617       __ vcmpgtsh(kScratchSimd128Reg, i.InputSimd128Register(1),
2618                   i.InputSimd128Register(0));
2619       __ vnor(i.OutputSimd128Register(), kScratchSimd128Reg,
2620               kScratchSimd128Reg);
2621       break;
2622     }
2623     case kPPC_I16x8GtU: {
2624       __ vcmpgtuh(i.OutputSimd128Register(), i.InputSimd128Register(0),
2625                   i.InputSimd128Register(1));
2626       break;
2627     }
2628     case kPPC_I16x8GeU: {
2629       __ vcmpequh(kScratchSimd128Reg, i.InputSimd128Register(0),
2630                   i.InputSimd128Register(1));
2631       __ vcmpgtuh(i.OutputSimd128Register(), i.InputSimd128Register(0),
2632                   i.InputSimd128Register(1));
2633       __ vor(i.OutputSimd128Register(), i.OutputSimd128Register(),
2634              kScratchSimd128Reg);
2635       break;
2636     }
2637     case kPPC_I8x16GtS: {
2638       __ vcmpgtsb(i.OutputSimd128Register(), i.InputSimd128Register(0),
2639                   i.InputSimd128Register(1));
2640       break;
2641     }
2642     case kPPC_I8x16GeS: {
2643       __ vcmpgtsb(kScratchSimd128Reg, i.InputSimd128Register(1),
2644                   i.InputSimd128Register(0));
2645       __ vnor(i.OutputSimd128Register(), kScratchSimd128Reg,
2646               kScratchSimd128Reg);
2647       break;
2648     }
2649     case kPPC_I8x16GtU: {
2650       __ vcmpgtub(i.OutputSimd128Register(), i.InputSimd128Register(0),
2651                   i.InputSimd128Register(1));
2652       break;
2653     }
2654     case kPPC_I8x16GeU: {
2655       __ vcmpequb(kScratchSimd128Reg, i.InputSimd128Register(0),
2656                   i.InputSimd128Register(1));
2657       __ vcmpgtub(i.OutputSimd128Register(), i.InputSimd128Register(0),
2658                   i.InputSimd128Register(1));
2659       __ vor(i.OutputSimd128Register(), i.OutputSimd128Register(),
2660              kScratchSimd128Reg);
2661       break;
2662     }
2663 #define VECTOR_SHIFT(op)                                           \
2664   {                                                                \
2665     __ mtvsrd(kScratchSimd128Reg, i.InputRegister(1));             \
2666     __ vspltb(kScratchSimd128Reg, kScratchSimd128Reg, Operand(7)); \
2667     __ op(i.OutputSimd128Register(), i.InputSimd128Register(0),    \
2668           kScratchSimd128Reg);                                     \
2669   }
2670     case kPPC_I64x2Shl: {
2671       VECTOR_SHIFT(vsld)
2672       break;
2673     }
2674     case kPPC_I64x2ShrS: {
2675       VECTOR_SHIFT(vsrad)
2676       break;
2677     }
2678     case kPPC_I64x2ShrU: {
2679       VECTOR_SHIFT(vsrd)
2680       break;
2681     }
2682     case kPPC_I32x4Shl: {
2683       VECTOR_SHIFT(vslw)
2684       break;
2685     }
2686     case kPPC_I32x4ShrS: {
2687       VECTOR_SHIFT(vsraw)
2688       break;
2689     }
2690     case kPPC_I32x4ShrU: {
2691       VECTOR_SHIFT(vsrw)
2692       break;
2693     }
2694     case kPPC_I16x8Shl: {
2695       VECTOR_SHIFT(vslh)
2696       break;
2697     }
2698     case kPPC_I16x8ShrS: {
2699       VECTOR_SHIFT(vsrah)
2700       break;
2701     }
2702     case kPPC_I16x8ShrU: {
2703       VECTOR_SHIFT(vsrh)
2704       break;
2705     }
2706     case kPPC_I8x16Shl: {
2707       VECTOR_SHIFT(vslb)
2708       break;
2709     }
2710     case kPPC_I8x16ShrS: {
2711       VECTOR_SHIFT(vsrab)
2712       break;
2713     }
2714     case kPPC_I8x16ShrU: {
2715       VECTOR_SHIFT(vsrb)
2716       break;
2717     }
2718 #undef VECTOR_SHIFT
2719     case kPPC_S128And: {
2720       Simd128Register dst = i.OutputSimd128Register();
2721       Simd128Register src = i.InputSimd128Register(1);
2722       __ vand(dst, i.InputSimd128Register(0), src);
2723       break;
2724     }
2725     case kPPC_S128Or: {
2726       Simd128Register dst = i.OutputSimd128Register();
2727       Simd128Register src = i.InputSimd128Register(1);
2728       __ vor(dst, i.InputSimd128Register(0), src);
2729       break;
2730     }
2731     case kPPC_S128Xor: {
2732       Simd128Register dst = i.OutputSimd128Register();
2733       Simd128Register src = i.InputSimd128Register(1);
2734       __ vxor(dst, i.InputSimd128Register(0), src);
2735       break;
2736     }
2737     case kPPC_S128Const: {
2738       uint64_t low = make_uint64(i.InputUint32(1), i.InputUint32(0));
2739       uint64_t high = make_uint64(i.InputUint32(3), i.InputUint32(2));
2740       __ mov(r0, Operand(low));
2741       __ mov(ip, Operand(high));
2742       __ mtvsrdd(i.OutputSimd128Register(), ip, r0);
2743       break;
2744     }
2745     case kPPC_S128Zero: {
2746       Simd128Register dst = i.OutputSimd128Register();
2747       __ vxor(dst, dst, dst);
2748       break;
2749     }
2750     case kPPC_S128AllOnes: {
2751       Simd128Register dst = i.OutputSimd128Register();
2752       __ vcmpequb(dst, dst, dst);
2753       break;
2754     }
2755     case kPPC_S128Not: {
2756       Simd128Register dst = i.OutputSimd128Register();
2757       Simd128Register src = i.InputSimd128Register(0);
2758       __ vnor(dst, src, src);
2759       break;
2760     }
2761     case kPPC_S128Select: {
2762       Simd128Register dst = i.OutputSimd128Register();
2763       Simd128Register mask = i.InputSimd128Register(0);
2764       Simd128Register src1 = i.InputSimd128Register(1);
2765       Simd128Register src2 = i.InputSimd128Register(2);
2766       __ vsel(dst, src2, src1, mask);
2767       break;
2768     }
2769     case kPPC_F64x2Abs: {
2770       __ xvabsdp(i.OutputSimd128Register(), i.InputSimd128Register(0));
2771       break;
2772     }
2773     case kPPC_F64x2Neg: {
2774       __ xvnegdp(i.OutputSimd128Register(), i.InputSimd128Register(0));
2775       break;
2776     }
2777     case kPPC_F64x2Sqrt: {
2778       __ xvsqrtdp(i.OutputSimd128Register(), i.InputSimd128Register(0));
2779       break;
2780     }
2781     case kPPC_F32x4Abs: {
2782       __ xvabssp(i.OutputSimd128Register(), i.InputSimd128Register(0));
2783       break;
2784     }
2785     case kPPC_F32x4Neg: {
2786       __ xvnegsp(i.OutputSimd128Register(), i.InputSimd128Register(0));
2787       break;
2788     }
2789     case kPPC_F32x4RecipApprox: {
2790       __ xvresp(i.OutputSimd128Register(), i.InputSimd128Register(0));
2791       break;
2792     }
2793     case kPPC_F32x4RecipSqrtApprox: {
2794       __ xvrsqrtesp(i.OutputSimd128Register(), i.InputSimd128Register(0));
2795       break;
2796     }
2797     case kPPC_F32x4Sqrt: {
2798       __ xvsqrtsp(i.OutputSimd128Register(), i.InputSimd128Register(0));
2799       break;
2800     }
2801     case kPPC_I64x2Neg: {
2802       __ vnegd(i.OutputSimd128Register(), i.InputSimd128Register(0));
2803       break;
2804     }
2805     case kPPC_I32x4Neg: {
2806       __ vnegw(i.OutputSimd128Register(), i.InputSimd128Register(0));
2807       break;
2808     }
2809     case kPPC_I64x2Abs: {
2810       Simd128Register tempFPReg1 = i.ToSimd128Register(instr->TempAt(0));
2811       Simd128Register src = i.InputSimd128Register(0);
2812       constexpr int shift_bits = 63;
2813       __ xxspltib(kScratchSimd128Reg, Operand(shift_bits));
2814       __ vsrad(kScratchSimd128Reg, src, kScratchSimd128Reg);
2815       __ vxor(tempFPReg1, src, kScratchSimd128Reg);
2816       __ vsubudm(i.OutputSimd128Register(), tempFPReg1, kScratchSimd128Reg);
2817       break;
2818     }
2819     case kPPC_I32x4Abs: {
2820       Simd128Register tempFPReg1 = i.ToSimd128Register(instr->TempAt(0));
2821       Simd128Register src = i.InputSimd128Register(0);
2822       constexpr int shift_bits = 31;
2823       __ xxspltib(kScratchSimd128Reg, Operand(shift_bits));
2824       __ vsraw(kScratchSimd128Reg, src, kScratchSimd128Reg);
2825       __ vxor(tempFPReg1, src, kScratchSimd128Reg);
2826       __ vsubuwm(i.OutputSimd128Register(), tempFPReg1, kScratchSimd128Reg);
2827       break;
2828     }
2829     case kPPC_I16x8Neg: {
2830       Simd128Register tempFPReg1 = i.ToSimd128Register(instr->TempAt(0));
2831       __ vspltish(kScratchSimd128Reg, Operand(1));
2832       __ vnor(tempFPReg1, i.InputSimd128Register(0), i.InputSimd128Register(0));
2833       __ vadduhm(i.OutputSimd128Register(), kScratchSimd128Reg, tempFPReg1);
2834       break;
2835     }
2836     case kPPC_I16x8Abs: {
2837       Simd128Register tempFPReg1 = i.ToSimd128Register(instr->TempAt(0));
2838       Simd128Register src = i.InputSimd128Register(0);
2839       constexpr int shift_bits = 15;
2840       __ xxspltib(kScratchSimd128Reg, Operand(shift_bits));
2841       __ vsrah(kScratchSimd128Reg, src, kScratchSimd128Reg);
2842       __ vxor(tempFPReg1, src, kScratchSimd128Reg);
2843       __ vsubuhm(i.OutputSimd128Register(), tempFPReg1, kScratchSimd128Reg);
2844       break;
2845     }
2846     case kPPC_I8x16Neg: {
2847       Simd128Register tempFPReg1 = i.ToSimd128Register(instr->TempAt(0));
2848       __ xxspltib(kScratchSimd128Reg, Operand(1));
2849       __ vnor(tempFPReg1, i.InputSimd128Register(0), i.InputSimd128Register(0));
2850       __ vaddubm(i.OutputSimd128Register(), kScratchSimd128Reg, tempFPReg1);
2851       break;
2852     }
2853     case kPPC_I8x16Abs: {
2854       Simd128Register tempFPReg1 = i.ToSimd128Register(instr->TempAt(0));
2855       Simd128Register src = i.InputSimd128Register(0);
2856       constexpr int shift_bits = 7;
2857       __ xxspltib(kScratchSimd128Reg, Operand(shift_bits));
2858       __ vsrab(kScratchSimd128Reg, src, kScratchSimd128Reg);
2859       __ vxor(tempFPReg1, src, kScratchSimd128Reg);
2860       __ vsububm(i.OutputSimd128Register(), tempFPReg1, kScratchSimd128Reg);
2861       break;
2862     }
2863     case kPPC_V128AnyTrue: {
2864       Simd128Register src = i.InputSimd128Register(0);
2865       Register dst = i.OutputRegister();
2866       constexpr uint8_t fxm = 0x2;  // field mask.
2867       constexpr int bit_number = 24;
2868       __ li(r0, Operand(0));
2869       __ li(ip, Operand(1));
2870       // Check if both lanes are 0, if so then return false.
2871       __ vxor(kScratchSimd128Reg, kScratchSimd128Reg, kScratchSimd128Reg);
2872       __ mtcrf(r0, fxm);  // Clear cr6.
2873       __ vcmpequd(kScratchSimd128Reg, src, kScratchSimd128Reg, SetRC);
2874       __ isel(dst, r0, ip, bit_number);
2875       break;
2876     }
2877 #define SIMD_ALL_TRUE(opcode)                                          \
2878   Simd128Register src = i.InputSimd128Register(0);                     \
2879   Register dst = i.OutputRegister();                                   \
2880   constexpr uint8_t fxm = 0x2; /* field mask. */                       \
2881   constexpr int bit_number = 24;                                       \
2882   __ li(r0, Operand(0));                                               \
2883   __ li(ip, Operand(1));                                               \
2884   /* Check if all lanes > 0, if not then return false.*/               \
2885   __ vxor(kScratchSimd128Reg, kScratchSimd128Reg, kScratchSimd128Reg); \
2886   __ mtcrf(r0, fxm); /* Clear cr6.*/                                   \
2887   __ opcode(kScratchSimd128Reg, src, kScratchSimd128Reg, SetRC);       \
2888   __ isel(dst, ip, r0, bit_number);
2889     case kPPC_I64x2AllTrue: {
2890       SIMD_ALL_TRUE(vcmpgtud)
2891       break;
2892     }
2893     case kPPC_I32x4AllTrue: {
2894       SIMD_ALL_TRUE(vcmpgtuw)
2895       break;
2896     }
2897     case kPPC_I16x8AllTrue: {
2898       SIMD_ALL_TRUE(vcmpgtuh)
2899       break;
2900     }
2901     case kPPC_I8x16AllTrue: {
2902       SIMD_ALL_TRUE(vcmpgtub)
2903       break;
2904     }
2905 #undef SIMD_ALL_TRUE
2906     case kPPC_I32x4SConvertF32x4: {
2907       Simd128Register src = i.InputSimd128Register(0);
2908       // NaN to 0
2909       __ vor(kScratchSimd128Reg, src, src);
2910       __ xvcmpeqsp(kScratchSimd128Reg, kScratchSimd128Reg, kScratchSimd128Reg);
2911       __ vand(kScratchSimd128Reg, src, kScratchSimd128Reg);
2912       __ xvcvspsxws(i.OutputSimd128Register(), kScratchSimd128Reg);
2913       break;
2914     }
2915     case kPPC_I32x4UConvertF32x4: {
2916       __ xvcvspuxws(i.OutputSimd128Register(), i.InputSimd128Register(0));
2917       break;
2918     }
2919     case kPPC_F32x4SConvertI32x4: {
2920       __ xvcvsxwsp(i.OutputSimd128Register(), i.InputSimd128Register(0));
2921       break;
2922     }
2923     case kPPC_F32x4UConvertI32x4: {
2924       __ xvcvuxwsp(i.OutputSimd128Register(), i.InputSimd128Register(0));
2925       break;
2926     }
2927 
2928     case kPPC_I64x2SConvertI32x4Low: {
2929       __ vupklsw(i.OutputSimd128Register(), i.InputSimd128Register(0));
2930       break;
2931     }
2932     case kPPC_I64x2SConvertI32x4High: {
2933       __ vupkhsw(i.OutputSimd128Register(), i.InputSimd128Register(0));
2934       break;
2935     }
2936     case kPPC_I64x2UConvertI32x4Low: {
2937       constexpr int lane_width_in_bytes = 8;
2938       __ vupklsw(i.OutputSimd128Register(), i.InputSimd128Register(0));
2939       // Zero extend.
2940       __ mov(ip, Operand(0xFFFFFFFF));
2941       __ mtvsrd(kScratchSimd128Reg, ip);
2942       __ vinsertd(kScratchSimd128Reg, kScratchSimd128Reg,
2943                   Operand(1 * lane_width_in_bytes));
2944       __ vand(i.OutputSimd128Register(), kScratchSimd128Reg,
2945               i.OutputSimd128Register());
2946       break;
2947     }
2948     case kPPC_I64x2UConvertI32x4High: {
2949       constexpr int lane_width_in_bytes = 8;
2950       __ vupkhsw(i.OutputSimd128Register(), i.InputSimd128Register(0));
2951       // Zero extend.
2952       __ mov(ip, Operand(0xFFFFFFFF));
2953       __ mtvsrd(kScratchSimd128Reg, ip);
2954       __ vinsertd(kScratchSimd128Reg, kScratchSimd128Reg,
2955                   Operand(1 * lane_width_in_bytes));
2956       __ vand(i.OutputSimd128Register(), kScratchSimd128Reg,
2957               i.OutputSimd128Register());
2958       break;
2959     }
2960 
2961     case kPPC_I32x4SConvertI16x8Low: {
2962       __ vupklsh(i.OutputSimd128Register(), i.InputSimd128Register(0));
2963       break;
2964     }
2965     case kPPC_I32x4SConvertI16x8High: {
2966       __ vupkhsh(i.OutputSimd128Register(), i.InputSimd128Register(0));
2967       break;
2968     }
2969     case kPPC_I32x4UConvertI16x8Low: {
2970       __ vupklsh(i.OutputSimd128Register(), i.InputSimd128Register(0));
2971       // Zero extend.
2972       __ mov(ip, Operand(0xFFFF));
2973       __ mtvsrd(kScratchSimd128Reg, ip);
2974       __ vspltw(kScratchSimd128Reg, kScratchSimd128Reg, Operand(1));
2975       __ vand(i.OutputSimd128Register(), kScratchSimd128Reg,
2976               i.OutputSimd128Register());
2977       break;
2978     }
2979     case kPPC_I32x4UConvertI16x8High: {
2980       __ vupkhsh(i.OutputSimd128Register(), i.InputSimd128Register(0));
2981       // Zero extend.
2982       __ mov(ip, Operand(0xFFFF));
2983       __ mtvsrd(kScratchSimd128Reg, ip);
2984       __ vspltw(kScratchSimd128Reg, kScratchSimd128Reg, Operand(1));
2985       __ vand(i.OutputSimd128Register(), kScratchSimd128Reg,
2986               i.OutputSimd128Register());
2987       break;
2988     }
2989 
2990     case kPPC_I16x8SConvertI8x16Low: {
2991       __ vupklsb(i.OutputSimd128Register(), i.InputSimd128Register(0));
2992       break;
2993     }
2994     case kPPC_I16x8SConvertI8x16High: {
2995       __ vupkhsb(i.OutputSimd128Register(), i.InputSimd128Register(0));
2996       break;
2997     }
2998     case kPPC_I16x8UConvertI8x16Low: {
2999       __ vupklsb(i.OutputSimd128Register(), i.InputSimd128Register(0));
3000       // Zero extend.
3001       __ li(ip, Operand(0xFF));
3002       __ mtvsrd(kScratchSimd128Reg, ip);
3003       __ vsplth(kScratchSimd128Reg, kScratchSimd128Reg, Operand(3));
3004       __ vand(i.OutputSimd128Register(), kScratchSimd128Reg,
3005               i.OutputSimd128Register());
3006       break;
3007     }
3008     case kPPC_I16x8UConvertI8x16High: {
3009       __ vupkhsb(i.OutputSimd128Register(), i.InputSimd128Register(0));
3010       // Zero extend.
3011       __ li(ip, Operand(0xFF));
3012       __ mtvsrd(kScratchSimd128Reg, ip);
3013       __ vsplth(kScratchSimd128Reg, kScratchSimd128Reg, Operand(3));
3014       __ vand(i.OutputSimd128Register(), kScratchSimd128Reg,
3015               i.OutputSimd128Register());
3016       break;
3017     }
3018     case kPPC_I16x8SConvertI32x4: {
3019       __ vpkswss(i.OutputSimd128Register(), i.InputSimd128Register(1),
3020                  i.InputSimd128Register(0));
3021       break;
3022     }
3023     case kPPC_I16x8UConvertI32x4: {
3024       __ vpkswus(i.OutputSimd128Register(), i.InputSimd128Register(1),
3025                  i.InputSimd128Register(0));
3026       break;
3027     }
3028     case kPPC_I8x16SConvertI16x8: {
3029       __ vpkshss(i.OutputSimd128Register(), i.InputSimd128Register(1),
3030                  i.InputSimd128Register(0));
3031       break;
3032     }
3033     case kPPC_I8x16UConvertI16x8: {
3034       __ vpkshus(i.OutputSimd128Register(), i.InputSimd128Register(1),
3035                  i.InputSimd128Register(0));
3036       break;
3037     }
3038     case kPPC_I8x16Shuffle: {
3039       Simd128Register dst = i.OutputSimd128Register(),
3040                       src0 = i.InputSimd128Register(0),
3041                       src1 = i.InputSimd128Register(1);
3042       uint64_t low = make_uint64(i.InputUint32(3), i.InputUint32(2));
3043       uint64_t high = make_uint64(i.InputUint32(5), i.InputUint32(4));
3044       __ mov(r0, Operand(low));
3045       __ mov(ip, Operand(high));
3046       __ mtvsrdd(dst, ip, r0);
3047       __ vperm(dst, src0, src1, dst);
3048       break;
3049     }
3050     case kPPC_I16x8AddSatS: {
3051       __ vaddshs(i.OutputSimd128Register(), i.InputSimd128Register(0),
3052                  i.InputSimd128Register(1));
3053       break;
3054     }
3055     case kPPC_I16x8SubSatS: {
3056       __ vsubshs(i.OutputSimd128Register(), i.InputSimd128Register(0),
3057                  i.InputSimd128Register(1));
3058       break;
3059     }
3060     case kPPC_I16x8AddSatU: {
3061       __ vadduhs(i.OutputSimd128Register(), i.InputSimd128Register(0),
3062                  i.InputSimd128Register(1));
3063       break;
3064     }
3065     case kPPC_I16x8SubSatU: {
3066       __ vsubuhs(i.OutputSimd128Register(), i.InputSimd128Register(0),
3067                  i.InputSimd128Register(1));
3068       break;
3069     }
3070     case kPPC_I8x16AddSatS: {
3071       __ vaddsbs(i.OutputSimd128Register(), i.InputSimd128Register(0),
3072                  i.InputSimd128Register(1));
3073       break;
3074     }
3075     case kPPC_I8x16SubSatS: {
3076       __ vsubsbs(i.OutputSimd128Register(), i.InputSimd128Register(0),
3077                  i.InputSimd128Register(1));
3078       break;
3079     }
3080     case kPPC_I8x16AddSatU: {
3081       __ vaddubs(i.OutputSimd128Register(), i.InputSimd128Register(0),
3082                  i.InputSimd128Register(1));
3083       break;
3084     }
3085     case kPPC_I8x16SubSatU: {
3086       __ vsububs(i.OutputSimd128Register(), i.InputSimd128Register(0),
3087                  i.InputSimd128Register(1));
3088       break;
3089     }
3090     case kPPC_I8x16Swizzle: {
3091       Simd128Register dst = i.OutputSimd128Register(),
3092                       src0 = i.InputSimd128Register(0),
3093                       src1 = i.InputSimd128Register(1),
3094                       tempFPReg1 = i.ToSimd128Register(instr->TempAt(0));
3095       // Saturate the indices to 5 bits. Input indices more than 31 should
3096       // return 0.
3097       __ xxspltib(tempFPReg1, Operand(31));
3098       __ vminub(tempFPReg1, src1, tempFPReg1);
3099       //  input needs to be reversed.
3100       __ xxbrq(dst, src0);
3101       __ vxor(kScratchSimd128Reg, kScratchSimd128Reg, kScratchSimd128Reg);
3102       __ vperm(dst, dst, kScratchSimd128Reg, tempFPReg1);
3103       break;
3104     }
3105     case kPPC_F64x2Qfma: {
3106       Simd128Register src0 = i.InputSimd128Register(0);
3107       Simd128Register src1 = i.InputSimd128Register(1);
3108       Simd128Register src2 = i.InputSimd128Register(2);
3109       Simd128Register dst = i.OutputSimd128Register();
3110       __ vor(kScratchSimd128Reg, src1, src1);
3111       __ xvmaddmdp(kScratchSimd128Reg, src2, src0);
3112       __ vor(dst, kScratchSimd128Reg, kScratchSimd128Reg);
3113       break;
3114     }
3115     case kPPC_F64x2Qfms: {
3116       Simd128Register src0 = i.InputSimd128Register(0);
3117       Simd128Register src1 = i.InputSimd128Register(1);
3118       Simd128Register src2 = i.InputSimd128Register(2);
3119       Simd128Register dst = i.OutputSimd128Register();
3120       __ vor(kScratchSimd128Reg, src1, src1);
3121       __ xvnmsubmdp(kScratchSimd128Reg, src2, src0);
3122       __ vor(dst, kScratchSimd128Reg, kScratchSimd128Reg);
3123       break;
3124     }
3125     case kPPC_F32x4Qfma: {
3126       Simd128Register src0 = i.InputSimd128Register(0);
3127       Simd128Register src1 = i.InputSimd128Register(1);
3128       Simd128Register src2 = i.InputSimd128Register(2);
3129       Simd128Register dst = i.OutputSimd128Register();
3130       __ vor(kScratchSimd128Reg, src1, src1);
3131       __ xvmaddmsp(kScratchSimd128Reg, src2, src0);
3132       __ vor(dst, kScratchSimd128Reg, kScratchSimd128Reg);
3133       break;
3134     }
3135     case kPPC_F32x4Qfms: {
3136       Simd128Register src0 = i.InputSimd128Register(0);
3137       Simd128Register src1 = i.InputSimd128Register(1);
3138       Simd128Register src2 = i.InputSimd128Register(2);
3139       Simd128Register dst = i.OutputSimd128Register();
3140       __ vor(kScratchSimd128Reg, src1, src1);
3141       __ xvnmsubmsp(kScratchSimd128Reg, src2, src0);
3142       __ vor(dst, kScratchSimd128Reg, kScratchSimd128Reg);
3143       break;
3144     }
3145     case kPPC_I16x8RoundingAverageU: {
3146       __ vavguh(i.OutputSimd128Register(), i.InputSimd128Register(0),
3147                 i.InputSimd128Register(1));
3148       break;
3149     }
3150     case kPPC_I8x16RoundingAverageU: {
3151       __ vavgub(i.OutputSimd128Register(), i.InputSimd128Register(0),
3152                 i.InputSimd128Register(1));
3153       break;
3154     }
3155     case kPPC_S128AndNot: {
3156       Simd128Register dst = i.OutputSimd128Register();
3157       Simd128Register src = i.InputSimd128Register(0);
3158       __ vandc(dst, src, i.InputSimd128Register(1));
3159       break;
3160     }
3161     case kPPC_F64x2Div: {
3162       __ xvdivdp(i.OutputSimd128Register(), i.InputSimd128Register(0),
3163                  i.InputSimd128Register(1));
3164       break;
3165     }
3166 #define F64X2_MIN_MAX_NAN(result)                                       \
3167   Simd128Register tempFPReg1 = i.ToSimd128Register(instr->TempAt(0));   \
3168   __ xvcmpeqdp(tempFPReg1, i.InputSimd128Register(0),                   \
3169                i.InputSimd128Register(0));                              \
3170   __ vsel(result, i.InputSimd128Register(0), result, tempFPReg1);       \
3171   __ xvcmpeqdp(tempFPReg1, i.InputSimd128Register(1),                   \
3172                i.InputSimd128Register(1));                              \
3173   __ vsel(i.OutputSimd128Register(), i.InputSimd128Register(1), result, \
3174           tempFPReg1);                                                  \
3175   /* Use xvmindp to turn any selected SNANs to QNANs. */                \
3176   __ xvmindp(i.OutputSimd128Register(), i.OutputSimd128Register(),      \
3177              i.OutputSimd128Register());
3178     case kPPC_F64x2Min: {
3179       __ xvmindp(kScratchSimd128Reg, i.InputSimd128Register(0),
3180                  i.InputSimd128Register(1));
3181       // We need to check if an input is NAN and preserve it.
3182       F64X2_MIN_MAX_NAN(kScratchSimd128Reg)
3183       break;
3184     }
3185     case kPPC_F64x2Max: {
3186       __ xvmaxdp(kScratchSimd128Reg, i.InputSimd128Register(0),
3187                  i.InputSimd128Register(1));
3188       // We need to check if an input is NAN and preserve it.
3189       F64X2_MIN_MAX_NAN(kScratchSimd128Reg)
3190       break;
3191     }
3192 #undef F64X2_MIN_MAX_NAN
3193     case kPPC_F32x4Div: {
3194       __ xvdivsp(i.OutputSimd128Register(), i.InputSimd128Register(0),
3195                  i.InputSimd128Register(1));
3196       break;
3197     }
3198     case kPPC_F32x4Min: {
3199       __ vminfp(i.OutputSimd128Register(), i.InputSimd128Register(0),
3200                 i.InputSimd128Register(1));
3201       break;
3202     }
3203     case kPPC_F32x4Max: {
3204       __ vmaxfp(i.OutputSimd128Register(), i.InputSimd128Register(0),
3205                 i.InputSimd128Register(1));
3206       break;
3207     }
3208     case kPPC_F64x2Ceil: {
3209       __ xvrdpip(i.OutputSimd128Register(), i.InputSimd128Register(0));
3210       break;
3211     }
3212     case kPPC_F64x2Floor: {
3213       __ xvrdpim(i.OutputSimd128Register(), i.InputSimd128Register(0));
3214       break;
3215     }
3216     case kPPC_F64x2Trunc: {
3217       __ xvrdpiz(i.OutputSimd128Register(), i.InputSimd128Register(0));
3218       break;
3219     }
3220     case kPPC_F32x4Ceil: {
3221       __ xvrspip(i.OutputSimd128Register(), i.InputSimd128Register(0));
3222       break;
3223     }
3224     case kPPC_F32x4Floor: {
3225       __ xvrspim(i.OutputSimd128Register(), i.InputSimd128Register(0));
3226       break;
3227     }
3228     case kPPC_F32x4Trunc: {
3229       __ xvrspiz(i.OutputSimd128Register(), i.InputSimd128Register(0));
3230       break;
3231     }
3232     case kPPC_I64x2BitMask: {
3233       if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
3234         __ vextractdm(i.OutputRegister(), i.InputSimd128Register(0));
3235       } else {
3236         __ mov(kScratchReg,
3237                Operand(0x8080808080800040));  // Select 0 for the high bits.
3238         __ mtvsrd(kScratchSimd128Reg, kScratchReg);
3239         __ vbpermq(kScratchSimd128Reg, i.InputSimd128Register(0),
3240                    kScratchSimd128Reg);
3241         __ vextractub(kScratchSimd128Reg, kScratchSimd128Reg, Operand(6));
3242         __ mfvsrd(i.OutputRegister(), kScratchSimd128Reg);
3243       }
3244       break;
3245     }
3246     case kPPC_I32x4BitMask: {
3247       if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
3248         __ vextractwm(i.OutputRegister(), i.InputSimd128Register(0));
3249       } else {
3250         __ mov(kScratchReg,
3251                Operand(0x8080808000204060));  // Select 0 for the high bits.
3252         __ mtvsrd(kScratchSimd128Reg, kScratchReg);
3253         __ vbpermq(kScratchSimd128Reg, i.InputSimd128Register(0),
3254                    kScratchSimd128Reg);
3255         __ vextractub(kScratchSimd128Reg, kScratchSimd128Reg, Operand(6));
3256         __ mfvsrd(i.OutputRegister(), kScratchSimd128Reg);
3257       }
3258       break;
3259     }
3260     case kPPC_I16x8BitMask: {
3261       if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
3262         __ vextracthm(i.OutputRegister(), i.InputSimd128Register(0));
3263       } else {
3264         __ mov(kScratchReg, Operand(0x10203040506070));
3265         __ mtvsrd(kScratchSimd128Reg, kScratchReg);
3266         __ vbpermq(kScratchSimd128Reg, i.InputSimd128Register(0),
3267                    kScratchSimd128Reg);
3268         __ vextractub(kScratchSimd128Reg, kScratchSimd128Reg, Operand(6));
3269         __ mfvsrd(i.OutputRegister(), kScratchSimd128Reg);
3270       }
3271       break;
3272     }
3273     case kPPC_I8x16BitMask: {
3274       if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
3275         __ vextractbm(i.OutputRegister(), i.InputSimd128Register(0));
3276       } else {
3277         Register temp = i.ToRegister(instr->TempAt(0));
3278         __ mov(temp, Operand(0x8101820283038));
3279         __ mov(ip, Operand(0x4048505860687078));
3280         __ mtvsrdd(kScratchSimd128Reg, temp, ip);
3281         __ vbpermq(kScratchSimd128Reg, i.InputSimd128Register(0),
3282                    kScratchSimd128Reg);
3283         __ vextractuh(kScratchSimd128Reg, kScratchSimd128Reg, Operand(6));
3284         __ mfvsrd(i.OutputRegister(), kScratchSimd128Reg);
3285       }
3286       break;
3287     }
3288     case kPPC_I32x4DotI16x8S: {
3289       __ vxor(kScratchSimd128Reg, kScratchSimd128Reg, kScratchSimd128Reg);
3290       __ vmsumshm(i.OutputSimd128Register(), i.InputSimd128Register(0),
3291                   i.InputSimd128Register(1), kScratchSimd128Reg);
3292       break;
3293     }
3294     case kPPC_F32x4Pmin: {
3295       Simd128Register dst = i.OutputSimd128Register(),
3296                       src0 = i.InputSimd128Register(0),
3297                       src1 = i.InputSimd128Register(1);
3298       __ xvcmpgtsp(kScratchSimd128Reg, src0, src1);
3299       __ vsel(dst, src0, src1, kScratchSimd128Reg);
3300       break;
3301     }
3302     case kPPC_F32x4Pmax: {
3303       Simd128Register dst = i.OutputSimd128Register(),
3304                       src0 = i.InputSimd128Register(0),
3305                       src1 = i.InputSimd128Register(1);
3306       __ xvcmpgtsp(kScratchSimd128Reg, src1, src0);
3307       __ vsel(dst, src0, src1, kScratchSimd128Reg);
3308       break;
3309     }
3310     case kPPC_F64x2Pmin: {
3311       Simd128Register dst = i.OutputSimd128Register(),
3312                       src0 = i.InputSimd128Register(0),
3313                       src1 = i.InputSimd128Register(1);
3314       __ xvcmpgtdp(kScratchSimd128Reg, src0, src1);
3315       __ vsel(dst, src0, src1, kScratchSimd128Reg);
3316       break;
3317     }
3318     case kPPC_F64x2Pmax: {
3319       Simd128Register dst = i.OutputSimd128Register(),
3320                       src0 = i.InputSimd128Register(0),
3321                       src1 = i.InputSimd128Register(1);
3322       __ xvcmpgtdp(kScratchSimd128Reg, src1, src0);
3323       __ vsel(dst, src0, src1, kScratchSimd128Reg);
3324       break;
3325     }
3326 #define ASSEMBLE_LOAD_TRANSFORM(scratch, load_instr) \
3327   AddressingMode mode = kMode_None;                  \
3328   MemOperand operand = i.MemoryOperand(&mode);       \
3329   DCHECK_EQ(mode, kMode_MRR);                        \
3330   __ load_instr(scratch, operand);
3331     case kPPC_S128Load8Splat: {
3332       Simd128Register dst = i.OutputSimd128Register();
3333       ASSEMBLE_LOAD_TRANSFORM(kScratchSimd128Reg, lxsibzx)
3334       __ vspltb(dst, kScratchSimd128Reg, Operand(7));
3335       break;
3336     }
3337     case kPPC_S128Load16Splat: {
3338       Simd128Register dst = i.OutputSimd128Register();
3339       ASSEMBLE_LOAD_TRANSFORM(kScratchSimd128Reg, lxsihzx)
3340       __ vsplth(dst, kScratchSimd128Reg, Operand(3));
3341       break;
3342     }
3343     case kPPC_S128Load32Splat: {
3344       Simd128Register dst = i.OutputSimd128Register();
3345       ASSEMBLE_LOAD_TRANSFORM(kScratchSimd128Reg, lxsiwzx)
3346       __ vspltw(dst, kScratchSimd128Reg, Operand(1));
3347       break;
3348     }
3349     case kPPC_S128Load64Splat: {
3350       constexpr int lane_width_in_bytes = 8;
3351       Simd128Register dst = i.OutputSimd128Register();
3352       ASSEMBLE_LOAD_TRANSFORM(dst, lxsdx)
3353       __ vinsertd(dst, dst, Operand(1 * lane_width_in_bytes));
3354       break;
3355     }
3356     case kPPC_S128Load8x8S: {
3357       Simd128Register dst = i.OutputSimd128Register();
3358       ASSEMBLE_LOAD_TRANSFORM(kScratchSimd128Reg, lxsdx)
3359       __ vupkhsb(dst, kScratchSimd128Reg);
3360       break;
3361     }
3362     case kPPC_S128Load8x8U: {
3363       Simd128Register dst = i.OutputSimd128Register();
3364       ASSEMBLE_LOAD_TRANSFORM(kScratchSimd128Reg, lxsdx)
3365       __ vupkhsb(dst, kScratchSimd128Reg);
3366       // Zero extend.
3367       __ li(ip, Operand(0xFF));
3368       __ mtvsrd(kScratchSimd128Reg, ip);
3369       __ vsplth(kScratchSimd128Reg, kScratchSimd128Reg, Operand(3));
3370       __ vand(dst, kScratchSimd128Reg, dst);
3371       break;
3372     }
3373     case kPPC_S128Load16x4S: {
3374       Simd128Register dst = i.OutputSimd128Register();
3375       ASSEMBLE_LOAD_TRANSFORM(kScratchSimd128Reg, lxsdx)
3376       __ vupkhsh(dst, kScratchSimd128Reg);
3377       break;
3378     }
3379     case kPPC_S128Load16x4U: {
3380       Simd128Register dst = i.OutputSimd128Register();
3381       ASSEMBLE_LOAD_TRANSFORM(kScratchSimd128Reg, lxsdx)
3382       __ vupkhsh(dst, kScratchSimd128Reg);
3383       // Zero extend.
3384       __ mov(ip, Operand(0xFFFF));
3385       __ mtvsrd(kScratchSimd128Reg, ip);
3386       __ vspltw(kScratchSimd128Reg, kScratchSimd128Reg, Operand(1));
3387       __ vand(dst, kScratchSimd128Reg, dst);
3388 
3389       break;
3390     }
3391     case kPPC_S128Load32x2S: {
3392       Simd128Register dst = i.OutputSimd128Register();
3393       ASSEMBLE_LOAD_TRANSFORM(kScratchSimd128Reg, lxsdx)
3394       __ vupkhsw(dst, kScratchSimd128Reg);
3395       break;
3396     }
3397     case kPPC_S128Load32x2U: {
3398       constexpr int lane_width_in_bytes = 8;
3399       Simd128Register dst = i.OutputSimd128Register();
3400       ASSEMBLE_LOAD_TRANSFORM(kScratchSimd128Reg, lxsdx)
3401       __ vupkhsw(dst, kScratchSimd128Reg);
3402       // Zero extend.
3403       __ mov(ip, Operand(0xFFFFFFFF));
3404       __ mtvsrd(kScratchSimd128Reg, ip);
3405       __ vinsertd(kScratchSimd128Reg, kScratchSimd128Reg,
3406                   Operand(1 * lane_width_in_bytes));
3407       __ vand(dst, kScratchSimd128Reg, dst);
3408       break;
3409     }
3410     case kPPC_S128Load32Zero: {
3411       constexpr int lane_width_in_bytes = 4;
3412       Simd128Register dst = i.OutputSimd128Register();
3413       ASSEMBLE_LOAD_TRANSFORM(kScratchSimd128Reg, lxsiwzx)
3414       __ vxor(dst, dst, dst);
3415       __ vinsertw(dst, kScratchSimd128Reg, Operand(3 * lane_width_in_bytes));
3416       break;
3417     }
3418     case kPPC_S128Load64Zero: {
3419       constexpr int lane_width_in_bytes = 8;
3420       Simd128Register dst = i.OutputSimd128Register();
3421       ASSEMBLE_LOAD_TRANSFORM(kScratchSimd128Reg, lxsdx)
3422       __ vxor(dst, dst, dst);
3423       __ vinsertd(dst, kScratchSimd128Reg, Operand(1 * lane_width_in_bytes));
3424       break;
3425     }
3426 #undef ASSEMBLE_LOAD_TRANSFORM
3427     case kPPC_S128Load8Lane: {
3428       Simd128Register dst = i.OutputSimd128Register();
3429       DCHECK_EQ(dst, i.InputSimd128Register(0));
3430       AddressingMode mode = kMode_None;
3431       size_t index = 1;
3432       MemOperand operand = i.MemoryOperand(&mode, &index);
3433       DCHECK_EQ(mode, kMode_MRR);
3434       __ lxsibzx(kScratchSimd128Reg, operand);
3435       __ vinsertb(dst, kScratchSimd128Reg, Operand(15 - i.InputUint8(3)));
3436       break;
3437     }
3438     case kPPC_S128Load16Lane: {
3439       Simd128Register dst = i.OutputSimd128Register();
3440       DCHECK_EQ(dst, i.InputSimd128Register(0));
3441       constexpr int lane_width_in_bytes = 2;
3442       AddressingMode mode = kMode_None;
3443       size_t index = 1;
3444       MemOperand operand = i.MemoryOperand(&mode, &index);
3445       DCHECK_EQ(mode, kMode_MRR);
3446       __ lxsihzx(kScratchSimd128Reg, operand);
3447       __ vinserth(dst, kScratchSimd128Reg,
3448                   Operand((7 - i.InputUint8(3)) * lane_width_in_bytes));
3449       break;
3450     }
3451     case kPPC_S128Load32Lane: {
3452       Simd128Register dst = i.OutputSimd128Register();
3453       DCHECK_EQ(dst, i.InputSimd128Register(0));
3454       constexpr int lane_width_in_bytes = 4;
3455       AddressingMode mode = kMode_None;
3456       size_t index = 1;
3457       MemOperand operand = i.MemoryOperand(&mode, &index);
3458       DCHECK_EQ(mode, kMode_MRR);
3459       __ lxsiwzx(kScratchSimd128Reg, operand);
3460       __ vinsertw(dst, kScratchSimd128Reg,
3461                   Operand((3 - i.InputUint8(3)) * lane_width_in_bytes));
3462       break;
3463     }
3464     case kPPC_S128Load64Lane: {
3465       Simd128Register dst = i.OutputSimd128Register();
3466       DCHECK_EQ(dst, i.InputSimd128Register(0));
3467       constexpr int lane_width_in_bytes = 8;
3468       AddressingMode mode = kMode_None;
3469       size_t index = 1;
3470       MemOperand operand = i.MemoryOperand(&mode, &index);
3471       DCHECK_EQ(mode, kMode_MRR);
3472       __ lxsdx(kScratchSimd128Reg, operand);
3473       __ vinsertd(dst, kScratchSimd128Reg,
3474                   Operand((1 - i.InputUint8(3)) * lane_width_in_bytes));
3475       break;
3476     }
3477     case kPPC_S128Store8Lane: {
3478       AddressingMode mode = kMode_None;
3479       size_t index = 1;
3480       MemOperand operand = i.MemoryOperand(&mode, &index);
3481       DCHECK_EQ(mode, kMode_MRR);
3482       __ vextractub(kScratchSimd128Reg, i.InputSimd128Register(0),
3483                     Operand(15 - i.InputUint8(3)));
3484       __ stxsibx(kScratchSimd128Reg, operand);
3485       break;
3486     }
3487     case kPPC_S128Store16Lane: {
3488       AddressingMode mode = kMode_None;
3489       constexpr int lane_width_in_bytes = 2;
3490       size_t index = 1;
3491       MemOperand operand = i.MemoryOperand(&mode, &index);
3492       DCHECK_EQ(mode, kMode_MRR);
3493       __ vextractuh(kScratchSimd128Reg, i.InputSimd128Register(0),
3494                     Operand((7 - i.InputUint8(3)) * lane_width_in_bytes));
3495       __ stxsihx(kScratchSimd128Reg, operand);
3496       break;
3497     }
3498     case kPPC_S128Store32Lane: {
3499       AddressingMode mode = kMode_None;
3500       constexpr int lane_width_in_bytes = 4;
3501       size_t index = 1;
3502       MemOperand operand = i.MemoryOperand(&mode, &index);
3503       DCHECK_EQ(mode, kMode_MRR);
3504       __ vextractuw(kScratchSimd128Reg, i.InputSimd128Register(0),
3505                     Operand((3 - i.InputUint8(3)) * lane_width_in_bytes));
3506       __ stxsiwx(kScratchSimd128Reg, operand);
3507       break;
3508     }
3509     case kPPC_S128Store64Lane: {
3510       AddressingMode mode = kMode_None;
3511       constexpr int lane_width_in_bytes = 8;
3512       size_t index = 1;
3513       MemOperand operand = i.MemoryOperand(&mode, &index);
3514       DCHECK_EQ(mode, kMode_MRR);
3515       __ vextractd(kScratchSimd128Reg, i.InputSimd128Register(0),
3516                    Operand((1 - i.InputUint8(3)) * lane_width_in_bytes));
3517       __ stxsdx(kScratchSimd128Reg, operand);
3518       break;
3519     }
3520 #define EXT_ADD_PAIRWISE(mul_even, mul_odd, add)           \
3521   __ mul_even(tempFPReg1, src, kScratchSimd128Reg);        \
3522   __ mul_odd(kScratchSimd128Reg, src, kScratchSimd128Reg); \
3523   __ add(dst, tempFPReg1, kScratchSimd128Reg);
3524     case kPPC_I32x4ExtAddPairwiseI16x8S: {
3525       Simd128Register src = i.InputSimd128Register(0);
3526       Simd128Register dst = i.OutputSimd128Register();
3527       Simd128Register tempFPReg1 = i.ToSimd128Register(instr->TempAt(0));
3528       __ vspltish(kScratchSimd128Reg, Operand(1));
3529       EXT_ADD_PAIRWISE(vmulesh, vmulosh, vadduwm)
3530       break;
3531     }
3532     case kPPC_I32x4ExtAddPairwiseI16x8U: {
3533       Simd128Register src = i.InputSimd128Register(0);
3534       Simd128Register dst = i.OutputSimd128Register();
3535       Simd128Register tempFPReg1 = i.ToSimd128Register(instr->TempAt(0));
3536       __ vspltish(kScratchSimd128Reg, Operand(1));
3537       EXT_ADD_PAIRWISE(vmuleuh, vmulouh, vadduwm)
3538       break;
3539     }
3540 
3541     case kPPC_I16x8ExtAddPairwiseI8x16S: {
3542       Simd128Register src = i.InputSimd128Register(0);
3543       Simd128Register dst = i.OutputSimd128Register();
3544       Simd128Register tempFPReg1 = i.ToSimd128Register(instr->TempAt(0));
3545       __ xxspltib(kScratchSimd128Reg, Operand(1));
3546       EXT_ADD_PAIRWISE(vmulesb, vmulosb, vadduhm)
3547       break;
3548     }
3549     case kPPC_I16x8ExtAddPairwiseI8x16U: {
3550       Simd128Register src = i.InputSimd128Register(0);
3551       Simd128Register dst = i.OutputSimd128Register();
3552       Simd128Register tempFPReg1 = i.ToSimd128Register(instr->TempAt(0));
3553       __ xxspltib(kScratchSimd128Reg, Operand(1));
3554       EXT_ADD_PAIRWISE(vmuleub, vmuloub, vadduhm)
3555       break;
3556     }
3557 #undef EXT_ADD_PAIRWISE
3558     case kPPC_I16x8Q15MulRSatS: {
3559       __ vxor(kScratchSimd128Reg, kScratchSimd128Reg, kScratchSimd128Reg);
3560       __ vmhraddshs(i.OutputSimd128Register(), i.InputSimd128Register(0),
3561                     i.InputSimd128Register(1), kScratchSimd128Reg);
3562       break;
3563     }
3564 #define EXT_MUL(mul_even, mul_odd)                  \
3565   Simd128Register dst = i.OutputSimd128Register(),  \
3566                   src0 = i.InputSimd128Register(0), \
3567                   src1 = i.InputSimd128Register(1); \
3568   __ mul_even(dst, src0, src1);                     \
3569   __ mul_odd(kScratchSimd128Reg, src0, src1);
3570     case kPPC_I64x2ExtMulLowI32x4S: {
3571       constexpr int lane_width_in_bytes = 8;
3572       EXT_MUL(vmulesw, vmulosw)
3573       __ vextractd(dst, dst, Operand(1 * lane_width_in_bytes));
3574       __ vextractd(kScratchSimd128Reg, kScratchSimd128Reg,
3575                    Operand(1 * lane_width_in_bytes));
3576       __ vinsertd(dst, kScratchSimd128Reg, Operand(1 * lane_width_in_bytes));
3577       break;
3578     }
3579     case kPPC_I64x2ExtMulHighI32x4S: {
3580       constexpr int lane_width_in_bytes = 8;
3581       EXT_MUL(vmulesw, vmulosw)
3582       __ vinsertd(dst, kScratchSimd128Reg, Operand(1 * lane_width_in_bytes));
3583       break;
3584     }
3585     case kPPC_I64x2ExtMulLowI32x4U: {
3586       constexpr int lane_width_in_bytes = 8;
3587       EXT_MUL(vmuleuw, vmulouw)
3588       __ vextractd(dst, dst, Operand(1 * lane_width_in_bytes));
3589       __ vextractd(kScratchSimd128Reg, kScratchSimd128Reg,
3590                    Operand(1 * lane_width_in_bytes));
3591       __ vinsertd(dst, kScratchSimd128Reg, Operand(1 * lane_width_in_bytes));
3592       break;
3593     }
3594     case kPPC_I64x2ExtMulHighI32x4U: {
3595       constexpr int lane_width_in_bytes = 8;
3596       EXT_MUL(vmuleuw, vmulouw)
3597       __ vinsertd(dst, kScratchSimd128Reg, Operand(1 * lane_width_in_bytes));
3598       break;
3599     }
3600     case kPPC_I32x4ExtMulLowI16x8S: {
3601       EXT_MUL(vmulesh, vmulosh)
3602       __ vmrglw(dst, dst, kScratchSimd128Reg);
3603       break;
3604     }
3605     case kPPC_I32x4ExtMulHighI16x8S: {
3606       EXT_MUL(vmulesh, vmulosh)
3607       __ vmrghw(dst, dst, kScratchSimd128Reg);
3608       break;
3609     }
3610     case kPPC_I32x4ExtMulLowI16x8U: {
3611       EXT_MUL(vmuleuh, vmulouh)
3612       __ vmrglw(dst, dst, kScratchSimd128Reg);
3613       break;
3614     }
3615     case kPPC_I32x4ExtMulHighI16x8U: {
3616       EXT_MUL(vmuleuh, vmulouh)
3617       __ vmrghw(dst, dst, kScratchSimd128Reg);
3618       break;
3619     }
3620     case kPPC_I16x8ExtMulLowI8x16S: {
3621       EXT_MUL(vmulesb, vmulosb)
3622       __ vmrglh(dst, dst, kScratchSimd128Reg);
3623       break;
3624     }
3625     case kPPC_I16x8ExtMulHighI8x16S: {
3626       EXT_MUL(vmulesb, vmulosb)
3627       __ vmrghh(dst, dst, kScratchSimd128Reg);
3628       break;
3629     }
3630     case kPPC_I16x8ExtMulLowI8x16U: {
3631       EXT_MUL(vmuleub, vmuloub)
3632       __ vmrglh(dst, dst, kScratchSimd128Reg);
3633       break;
3634     }
3635     case kPPC_I16x8ExtMulHighI8x16U: {
3636       EXT_MUL(vmuleub, vmuloub)
3637       __ vmrghh(dst, dst, kScratchSimd128Reg);
3638       break;
3639     }
3640 #undef EXT_MUL
3641     case kPPC_F64x2ConvertLowI32x4S: {
3642       __ vupklsw(kScratchSimd128Reg, i.InputSimd128Register(0));
3643       __ xvcvsxddp(i.OutputSimd128Register(), kScratchSimd128Reg);
3644       break;
3645     }
3646     case kPPC_F64x2ConvertLowI32x4U: {
3647       Simd128Register dst = i.OutputSimd128Register();
3648       constexpr int lane_width_in_bytes = 8;
3649       __ vupklsw(dst, i.InputSimd128Register(0));
3650       // Zero extend.
3651       __ mov(ip, Operand(0xFFFFFFFF));
3652       __ mtvsrd(kScratchSimd128Reg, ip);
3653       __ vinsertd(kScratchSimd128Reg, kScratchSimd128Reg,
3654                   Operand(1 * lane_width_in_bytes));
3655       __ vand(dst, kScratchSimd128Reg, dst);
3656       __ xvcvuxddp(dst, dst);
3657       break;
3658     }
3659     case kPPC_F64x2PromoteLowF32x4: {
3660       constexpr int lane_number = 8;
3661       Simd128Register src = i.InputSimd128Register(0);
3662       Simd128Register dst = i.OutputSimd128Register();
3663       __ vextractd(kScratchSimd128Reg, src, Operand(lane_number));
3664       __ vinsertw(kScratchSimd128Reg, kScratchSimd128Reg, Operand(lane_number));
3665       __ xvcvspdp(dst, kScratchSimd128Reg);
3666       break;
3667     }
3668     case kPPC_F32x4DemoteF64x2Zero: {
3669       constexpr int lane_number = 8;
3670       Simd128Register src = i.InputSimd128Register(0);
3671       Simd128Register dst = i.OutputSimd128Register();
3672       __ xvcvdpsp(kScratchSimd128Reg, src);
3673       __ vextractuw(dst, kScratchSimd128Reg, Operand(lane_number));
3674       __ vinsertw(kScratchSimd128Reg, dst, Operand(4));
3675       __ vxor(dst, dst, dst);
3676       __ vinsertd(dst, kScratchSimd128Reg, Operand(lane_number));
3677       break;
3678     }
3679     case kPPC_I32x4TruncSatF64x2SZero: {
3680       constexpr int lane_number = 8;
3681       Simd128Register src = i.InputSimd128Register(0);
3682       Simd128Register dst = i.OutputSimd128Register();
3683       // NaN to 0.
3684       __ vor(kScratchSimd128Reg, src, src);
3685       __ xvcmpeqdp(kScratchSimd128Reg, kScratchSimd128Reg, kScratchSimd128Reg);
3686       __ vand(kScratchSimd128Reg, src, kScratchSimd128Reg);
3687       __ xvcvdpsxws(kScratchSimd128Reg, kScratchSimd128Reg);
3688       __ vextractuw(dst, kScratchSimd128Reg, Operand(lane_number));
3689       __ vinsertw(kScratchSimd128Reg, dst, Operand(4));
3690       __ vxor(dst, dst, dst);
3691       __ vinsertd(dst, kScratchSimd128Reg, Operand(lane_number));
3692       break;
3693     }
3694     case kPPC_I32x4TruncSatF64x2UZero: {
3695       constexpr int lane_number = 8;
3696       Simd128Register src = i.InputSimd128Register(0);
3697       Simd128Register dst = i.OutputSimd128Register();
3698       __ xvcvdpuxws(kScratchSimd128Reg, src);
3699       __ vextractuw(dst, kScratchSimd128Reg, Operand(lane_number));
3700       __ vinsertw(kScratchSimd128Reg, dst, Operand(4));
3701       __ vxor(dst, dst, dst);
3702       __ vinsertd(dst, kScratchSimd128Reg, Operand(lane_number));
3703       break;
3704     }
3705     case kPPC_I8x16Popcnt: {
3706       __ vpopcntb(i.OutputSimd128Register(), i.InputSimd128Register(0));
3707       break;
3708     }
3709     case kPPC_StoreCompressTagged: {
3710       ASSEMBLE_STORE_INTEGER(StoreTaggedField, StoreTaggedField);
3711       break;
3712     }
3713     case kPPC_LoadDecompressTaggedSigned: {
3714       CHECK(instr->HasOutput());
3715       ASSEMBLE_LOAD_INTEGER(lwz, lwzx);
3716       break;
3717     }
3718     case kPPC_LoadDecompressTaggedPointer: {
3719       CHECK(instr->HasOutput());
3720       ASSEMBLE_LOAD_INTEGER(lwz, lwzx);
3721       __ add(i.OutputRegister(), i.OutputRegister(), kRootRegister);
3722       break;
3723     }
3724     case kPPC_LoadDecompressAnyTagged: {
3725       CHECK(instr->HasOutput());
3726       ASSEMBLE_LOAD_INTEGER(lwz, lwzx);
3727       __ add(i.OutputRegister(), i.OutputRegister(), kRootRegister);
3728       break;
3729     }
3730     default:
3731       UNREACHABLE();
3732   }
3733   return kSuccess;
3734 }
3735 
3736 // Assembles branches after an instruction.
AssembleArchBranch(Instruction * instr,BranchInfo * branch)3737 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
3738   PPCOperandConverter i(this, instr);
3739   Label* tlabel = branch->true_label;
3740   Label* flabel = branch->false_label;
3741   ArchOpcode op = instr->arch_opcode();
3742   FlagsCondition condition = branch->condition;
3743   CRegister cr = cr0;
3744 
3745   Condition cond = FlagsConditionToCondition(condition, op);
3746   if (op == kPPC_CmpDouble) {
3747     // check for unordered if necessary
3748     if (cond == le) {
3749       __ bunordered(flabel, cr);
3750       // Unnecessary for eq/lt since only FU bit will be set.
3751     } else if (cond == gt) {
3752       __ bunordered(tlabel, cr);
3753       // Unnecessary for ne/ge since only FU bit will be set.
3754     }
3755   }
3756   __ b(cond, tlabel, cr);
3757   if (!branch->fallthru) __ b(flabel);  // no fallthru to flabel.
3758 }
3759 
AssembleArchDeoptBranch(Instruction * instr,BranchInfo * branch)3760 void CodeGenerator::AssembleArchDeoptBranch(Instruction* instr,
3761                                             BranchInfo* branch) {
3762   AssembleArchBranch(instr, branch);
3763 }
3764 
AssembleArchJump(RpoNumber target)3765 void CodeGenerator::AssembleArchJump(RpoNumber target) {
3766   if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
3767 }
3768 
3769 #if V8_ENABLE_WEBASSEMBLY
AssembleArchTrap(Instruction * instr,FlagsCondition condition)3770 void CodeGenerator::AssembleArchTrap(Instruction* instr,
3771                                      FlagsCondition condition) {
3772   class OutOfLineTrap final : public OutOfLineCode {
3773    public:
3774     OutOfLineTrap(CodeGenerator* gen, Instruction* instr)
3775         : OutOfLineCode(gen), instr_(instr), gen_(gen) {}
3776 
3777     void Generate() final {
3778       PPCOperandConverter i(gen_, instr_);
3779       TrapId trap_id =
3780           static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
3781       GenerateCallToTrap(trap_id);
3782     }
3783 
3784    private:
3785     void GenerateCallToTrap(TrapId trap_id) {
3786       if (trap_id == TrapId::kInvalid) {
3787         // We cannot test calls to the runtime in cctest/test-run-wasm.
3788         // Therefore we emit a call to C here instead of a call to the runtime.
3789         // We use the context register as the scratch register, because we do
3790         // not have a context here.
3791         __ PrepareCallCFunction(0, 0, cp);
3792         __ CallCFunction(
3793             ExternalReference::wasm_call_trap_callback_for_testing(), 0);
3794         __ LeaveFrame(StackFrame::WASM);
3795         auto call_descriptor = gen_->linkage()->GetIncomingDescriptor();
3796         int pop_count = static_cast<int>(call_descriptor->ParameterSlotCount());
3797         __ Drop(pop_count);
3798         __ Ret();
3799       } else {
3800         gen_->AssembleSourcePosition(instr_);
3801         // A direct call to a wasm runtime stub defined in this module.
3802         // Just encode the stub index. This will be patched when the code
3803         // is added to the native module and copied into wasm code space.
3804         __ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
3805         ReferenceMap* reference_map =
3806             gen_->zone()->New<ReferenceMap>(gen_->zone());
3807         gen_->RecordSafepoint(reference_map);
3808         if (FLAG_debug_code) {
3809           __ stop();
3810         }
3811       }
3812     }
3813 
3814     Instruction* instr_;
3815     CodeGenerator* gen_;
3816   };
3817   auto ool = zone()->New<OutOfLineTrap>(this, instr);
3818   Label* tlabel = ool->entry();
3819   Label end;
3820 
3821   ArchOpcode op = instr->arch_opcode();
3822   CRegister cr = cr0;
3823   Condition cond = FlagsConditionToCondition(condition, op);
3824   if (op == kPPC_CmpDouble) {
3825     // check for unordered if necessary
3826     if (cond == le) {
3827       __ bunordered(&end, cr);
3828       // Unnecessary for eq/lt since only FU bit will be set.
3829     } else if (cond == gt) {
3830       __ bunordered(tlabel, cr);
3831       // Unnecessary for ne/ge since only FU bit will be set.
3832     }
3833   }
3834   __ b(cond, tlabel, cr);
3835   __ bind(&end);
3836 }
3837 #endif  // V8_ENABLE_WEBASSEMBLY
3838 
3839 // Assembles boolean materializations after an instruction.
AssembleArchBoolean(Instruction * instr,FlagsCondition condition)3840 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
3841                                         FlagsCondition condition) {
3842   PPCOperandConverter i(this, instr);
3843   Label done;
3844   ArchOpcode op = instr->arch_opcode();
3845   CRegister cr = cr0;
3846   int reg_value = -1;
3847 
3848   // Materialize a full 32-bit 1 or 0 value. The result register is always the
3849   // last output of the instruction.
3850   DCHECK_NE(0u, instr->OutputCount());
3851   Register reg = i.OutputRegister(instr->OutputCount() - 1);
3852 
3853   Condition cond = FlagsConditionToCondition(condition, op);
3854   if (op == kPPC_CmpDouble) {
3855     // check for unordered if necessary
3856     if (cond == le) {
3857       reg_value = 0;
3858       __ li(reg, Operand::Zero());
3859       __ bunordered(&done, cr);
3860     } else if (cond == gt) {
3861       reg_value = 1;
3862       __ li(reg, Operand(1));
3863       __ bunordered(&done, cr);
3864     }
3865     // Unnecessary for eq/lt & ne/ge since only FU bit will be set.
3866   }
3867 
3868   if (CpuFeatures::IsSupported(PPC_7_PLUS)) {
3869     switch (cond) {
3870       case eq:
3871       case lt:
3872       case gt:
3873         if (reg_value != 1) __ li(reg, Operand(1));
3874         __ li(kScratchReg, Operand::Zero());
3875         __ isel(cond, reg, reg, kScratchReg, cr);
3876         break;
3877       case ne:
3878       case ge:
3879       case le:
3880         if (reg_value != 1) __ li(reg, Operand(1));
3881         // r0 implies logical zero in this form
3882         __ isel(NegateCondition(cond), reg, r0, reg, cr);
3883         break;
3884       default:
3885         UNREACHABLE();
3886     }
3887   } else {
3888     if (reg_value != 0) __ li(reg, Operand::Zero());
3889     __ b(NegateCondition(cond), &done, cr);
3890     __ li(reg, Operand(1));
3891   }
3892   __ bind(&done);
3893 }
3894 
AssembleArchBinarySearchSwitch(Instruction * instr)3895 void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
3896   PPCOperandConverter i(this, instr);
3897   Register input = i.InputRegister(0);
3898   std::vector<std::pair<int32_t, Label*>> cases;
3899   for (size_t index = 2; index < instr->InputCount(); index += 2) {
3900     cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
3901   }
3902   AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
3903                                       cases.data() + cases.size());
3904 }
3905 
AssembleArchTableSwitch(Instruction * instr)3906 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
3907   PPCOperandConverter i(this, instr);
3908   Register input = i.InputRegister(0);
3909   int32_t const case_count = static_cast<int32_t>(instr->InputCount() - 2);
3910   Label** cases = zone()->NewArray<Label*>(case_count);
3911   for (int32_t index = 0; index < case_count; ++index) {
3912     cases[index] = GetLabel(i.InputRpo(index + 2));
3913   }
3914   Label* const table = AddJumpTable(cases, case_count);
3915   __ CmpU64(input, Operand(case_count), r0);
3916   __ bge(GetLabel(i.InputRpo(1)));
3917   __ mov_label_addr(kScratchReg, table);
3918   __ ShiftLeftU64(r0, input, Operand(kSystemPointerSizeLog2));
3919   __ LoadU64(kScratchReg, MemOperand(kScratchReg, r0));
3920   __ Jump(kScratchReg);
3921 }
3922 
AssembleArchSelect(Instruction * instr,FlagsCondition condition)3923 void CodeGenerator::AssembleArchSelect(Instruction* instr,
3924                                        FlagsCondition condition) {
3925   UNIMPLEMENTED();
3926 }
3927 
FinishFrame(Frame * frame)3928 void CodeGenerator::FinishFrame(Frame* frame) {
3929   auto call_descriptor = linkage()->GetIncomingDescriptor();
3930   const RegList double_saves = call_descriptor->CalleeSavedFPRegisters();
3931 
3932   // Save callee-saved Double registers.
3933   if (double_saves != 0) {
3934     frame->AlignSavedCalleeRegisterSlots();
3935     DCHECK_EQ(kNumCalleeSavedDoubles,
3936               base::bits::CountPopulation(double_saves));
3937     frame->AllocateSavedCalleeRegisterSlots(kNumCalleeSavedDoubles *
3938                                             (kDoubleSize / kSystemPointerSize));
3939   }
3940   // Save callee-saved registers.
3941   const RegList saves = FLAG_enable_embedded_constant_pool
3942                             ? call_descriptor->CalleeSavedRegisters() &
3943                                   ~kConstantPoolRegister.bit()
3944                             : call_descriptor->CalleeSavedRegisters();
3945   if (saves != 0) {
3946     // register save area does not include the fp or constant pool pointer.
3947     const int num_saves =
3948         kNumCalleeSaved - 1 - (FLAG_enable_embedded_constant_pool ? 1 : 0);
3949     frame->AllocateSavedCalleeRegisterSlots(num_saves);
3950   }
3951 }
3952 
AssembleConstructFrame()3953 void CodeGenerator::AssembleConstructFrame() {
3954   auto call_descriptor = linkage()->GetIncomingDescriptor();
3955   if (frame_access_state()->has_frame()) {
3956     if (call_descriptor->IsCFunctionCall()) {
3957 #if V8_ENABLE_WEBASSEMBLY
3958       if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) {
3959         __ StubPrologue(StackFrame::C_WASM_ENTRY);
3960         // Reserve stack space for saving the c_entry_fp later.
3961         __ addi(sp, sp, Operand(-kSystemPointerSize));
3962 #else
3963       // For balance.
3964       if (false) {
3965 #endif  // V8_ENABLE_WEBASSEMBLY
3966       } else {
3967         __ mflr(r0);
3968         if (FLAG_enable_embedded_constant_pool) {
3969           __ Push(r0, fp, kConstantPoolRegister);
3970           // Adjust FP to point to saved FP.
3971           __ SubS64(fp, sp,
3972                     Operand(StandardFrameConstants::kConstantPoolOffset), r0);
3973         } else {
3974           __ Push(r0, fp);
3975           __ mr(fp, sp);
3976         }
3977       }
3978     } else if (call_descriptor->IsJSFunctionCall()) {
3979       __ Prologue();
3980     } else {
3981       StackFrame::Type type = info()->GetOutputStackFrameType();
3982       // TODO(mbrandy): Detect cases where ip is the entrypoint (for
3983       // efficient intialization of the constant pool pointer register).
3984       __ StubPrologue(type);
3985 #if V8_ENABLE_WEBASSEMBLY
3986       if (call_descriptor->IsWasmFunctionCall()) {
3987         __ Push(kWasmInstanceRegister);
3988       } else if (call_descriptor->IsWasmImportWrapper() ||
3989                  call_descriptor->IsWasmCapiFunction()) {
3990         // Wasm import wrappers are passed a tuple in the place of the instance.
3991         // Unpack the tuple into the instance and the target callable.
3992         // This must be done here in the codegen because it cannot be expressed
3993         // properly in the graph.
3994         __ LoadTaggedPointerField(
3995             kJSFunctionRegister,
3996             FieldMemOperand(kWasmInstanceRegister, Tuple2::kValue2Offset), r0);
3997         __ LoadTaggedPointerField(
3998             kWasmInstanceRegister,
3999             FieldMemOperand(kWasmInstanceRegister, Tuple2::kValue1Offset), r0);
4000         __ Push(kWasmInstanceRegister);
4001         if (call_descriptor->IsWasmCapiFunction()) {
4002           // Reserve space for saving the PC later.
4003           __ addi(sp, sp, Operand(-kSystemPointerSize));
4004         }
4005       }
4006 #endif  // V8_ENABLE_WEBASSEMBLY
4007     }
4008     unwinding_info_writer_.MarkFrameConstructed(__ pc_offset());
4009   }
4010 
4011   int required_slots =
4012       frame()->GetTotalFrameSlotCount() - frame()->GetFixedSlotCount();
4013   if (info()->is_osr()) {
4014     // TurboFan OSR-compiled functions cannot be entered directly.
4015     __ Abort(AbortReason::kShouldNotDirectlyEnterOsrFunction);
4016 
4017     // Unoptimized code jumps directly to this entrypoint while the unoptimized
4018     // frame is still on the stack. Optimized code uses OSR values directly from
4019     // the unoptimized frame. Thus, all that needs to be done is to allocate the
4020     // remaining stack slots.
4021     __ RecordComment("-- OSR entrypoint --");
4022     osr_pc_offset_ = __ pc_offset();
4023     required_slots -= osr_helper()->UnoptimizedFrameSlots();
4024   }
4025 
4026   const RegList saves_fp = call_descriptor->CalleeSavedFPRegisters();
4027   const RegList saves = FLAG_enable_embedded_constant_pool
4028                             ? call_descriptor->CalleeSavedRegisters() &
4029                                   ~kConstantPoolRegister.bit()
4030                             : call_descriptor->CalleeSavedRegisters();
4031 
4032   if (required_slots > 0) {
4033 #if V8_ENABLE_WEBASSEMBLY
4034     if (info()->IsWasm() && required_slots * kSystemPointerSize > 4 * KB) {
4035       // For WebAssembly functions with big frames we have to do the stack
4036       // overflow check before we construct the frame. Otherwise we may not
4037       // have enough space on the stack to call the runtime for the stack
4038       // overflow.
4039       Label done;
4040 
4041       // If the frame is bigger than the stack, we throw the stack overflow
4042       // exception unconditionally. Thereby we can avoid the integer overflow
4043       // check in the condition code.
4044       if (required_slots * kSystemPointerSize < FLAG_stack_size * KB) {
4045         Register scratch = ip;
4046         __ LoadU64(
4047             scratch,
4048             FieldMemOperand(kWasmInstanceRegister,
4049                             WasmInstanceObject::kRealStackLimitAddressOffset),
4050             r0);
4051         __ LoadU64(scratch, MemOperand(scratch), r0);
4052         __ AddS64(scratch, scratch,
4053                   Operand(required_slots * kSystemPointerSize), r0);
4054         __ CmpU64(sp, scratch);
4055         __ bge(&done);
4056       }
4057 
4058       __ Call(wasm::WasmCode::kWasmStackOverflow, RelocInfo::WASM_STUB_CALL);
4059       // The call does not return, hence we can ignore any references and just
4060       // define an empty safepoint.
4061       ReferenceMap* reference_map = zone()->New<ReferenceMap>(zone());
4062       RecordSafepoint(reference_map);
4063       if (FLAG_debug_code) __ stop();
4064 
4065       __ bind(&done);
4066     }
4067 #endif  // V8_ENABLE_WEBASSEMBLY
4068 
4069     // Skip callee-saved and return slots, which are pushed below.
4070     required_slots -= base::bits::CountPopulation(saves);
4071     required_slots -= frame()->GetReturnSlotCount();
4072     required_slots -= (kDoubleSize / kSystemPointerSize) *
4073                       base::bits::CountPopulation(saves_fp);
4074     __ AddS64(sp, sp, Operand(-required_slots * kSystemPointerSize), r0);
4075   }
4076 
4077   // Save callee-saved Double registers.
4078   if (saves_fp != 0) {
4079     __ MultiPushDoubles(saves_fp);
4080     DCHECK_EQ(kNumCalleeSavedDoubles, base::bits::CountPopulation(saves_fp));
4081   }
4082 
4083   // Save callee-saved registers.
4084   if (saves != 0) {
4085     __ MultiPush(saves);
4086     // register save area does not include the fp or constant pool pointer.
4087   }
4088 
4089   const int returns = frame()->GetReturnSlotCount();
4090   // Create space for returns.
4091   __ AllocateStackSpace(returns * kSystemPointerSize);
4092 }
4093 
4094 void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) {
4095   auto call_descriptor = linkage()->GetIncomingDescriptor();
4096 
4097   const int returns = frame()->GetReturnSlotCount();
4098   if (returns != 0) {
4099     // Create space for returns.
4100     __ AddS64(sp, sp, Operand(returns * kSystemPointerSize), r0);
4101   }
4102 
4103   // Restore registers.
4104   const RegList saves = FLAG_enable_embedded_constant_pool
4105                             ? call_descriptor->CalleeSavedRegisters() &
4106                                   ~kConstantPoolRegister.bit()
4107                             : call_descriptor->CalleeSavedRegisters();
4108   if (saves != 0) {
4109     __ MultiPop(saves);
4110   }
4111 
4112   // Restore double registers.
4113   const RegList double_saves = call_descriptor->CalleeSavedFPRegisters();
4114   if (double_saves != 0) {
4115     __ MultiPopDoubles(double_saves);
4116   }
4117 
4118   unwinding_info_writer_.MarkBlockWillExit();
4119 
4120   // We might need r6 for scratch.
4121   DCHECK_EQ(0u, call_descriptor->CalleeSavedRegisters() & r6.bit());
4122   PPCOperandConverter g(this, nullptr);
4123   const int parameter_slots =
4124       static_cast<int>(call_descriptor->ParameterSlotCount());
4125 
4126   // {aditional_pop_count} is only greater than zero if {parameter_slots = 0}.
4127   // Check RawMachineAssembler::PopAndReturn.
4128   if (parameter_slots != 0) {
4129     if (additional_pop_count->IsImmediate()) {
4130       DCHECK_EQ(g.ToConstant(additional_pop_count).ToInt32(), 0);
4131     } else if (FLAG_debug_code) {
4132       __ cmpi(g.ToRegister(additional_pop_count), Operand(0));
4133       __ Assert(eq, AbortReason::kUnexpectedAdditionalPopValue);
4134     }
4135   }
4136 
4137   Register argc_reg = r6;
4138   // Functions with JS linkage have at least one parameter (the receiver).
4139   // If {parameter_slots} == 0, it means it is a builtin with
4140   // kDontAdaptArgumentsSentinel, which takes care of JS arguments popping
4141   // itself.
4142   const bool drop_jsargs = parameter_slots != 0 &&
4143                            frame_access_state()->has_frame() &&
4144                            call_descriptor->IsJSFunctionCall();
4145 
4146   if (call_descriptor->IsCFunctionCall()) {
4147     AssembleDeconstructFrame();
4148   } else if (frame_access_state()->has_frame()) {
4149     // Canonicalize JSFunction return sites for now unless they have an variable
4150     // number of stack slot pops
4151     if (additional_pop_count->IsImmediate() &&
4152         g.ToConstant(additional_pop_count).ToInt32() == 0) {
4153       if (return_label_.is_bound()) {
4154         __ b(&return_label_);
4155         return;
4156       } else {
4157         __ bind(&return_label_);
4158       }
4159     }
4160     if (drop_jsargs) {
4161       // Get the actual argument count.
4162       DCHECK_EQ(0u, call_descriptor->CalleeSavedRegisters() & argc_reg.bit());
4163       __ LoadU64(argc_reg, MemOperand(fp, StandardFrameConstants::kArgCOffset));
4164     }
4165     AssembleDeconstructFrame();
4166   }
4167   // Constant pool is unavailable since the frame has been destructed
4168   ConstantPoolUnavailableScope constant_pool_unavailable(tasm());
4169   if (drop_jsargs) {
4170     // We must pop all arguments from the stack (including the receiver).
4171     // The number of arguments without the receiver is
4172     // max(argc_reg, parameter_slots-1), and the receiver is added in
4173     // DropArguments().
4174     if (parameter_slots > 1) {
4175       const int parameter_slots_without_receiver = parameter_slots - 1;
4176       Label skip;
4177       __ CmpS64(argc_reg, Operand(parameter_slots_without_receiver), r0);
4178       __ bgt(&skip);
4179       __ mov(argc_reg, Operand(parameter_slots_without_receiver));
4180       __ bind(&skip);
4181     }
4182     __ DropArguments(argc_reg, TurboAssembler::kCountIsInteger,
4183                      TurboAssembler::kCountExcludesReceiver);
4184   } else if (additional_pop_count->IsImmediate()) {
4185     int additional_count = g.ToConstant(additional_pop_count).ToInt32();
4186     __ Drop(parameter_slots + additional_count);
4187   } else if (parameter_slots == 0) {
4188     __ Drop(g.ToRegister(additional_pop_count));
4189   } else {
4190     // {additional_pop_count} is guaranteed to be zero if {parameter_slots !=
4191     // 0}. Check RawMachineAssembler::PopAndReturn.
4192     __ Drop(parameter_slots);
4193   }
4194   __ Ret();
4195 }
4196 
4197 void CodeGenerator::FinishCode() {}
4198 
4199 void CodeGenerator::PrepareForDeoptimizationExits(
4200     ZoneDeque<DeoptimizationExit*>* exits) {
4201   int total_size = 0;
4202   for (DeoptimizationExit* exit : deoptimization_exits_) {
4203     total_size += (exit->kind() == DeoptimizeKind::kLazy)
4204                       ? Deoptimizer::kLazyDeoptExitSize
4205                       : Deoptimizer::kNonLazyDeoptExitSize;
4206   }
4207 
4208   __ CheckTrampolinePoolQuick(total_size);
4209   DCHECK(Deoptimizer::kSupportsFixedDeoptExitSizes);
4210 }
4211 
4212 void CodeGenerator::AssembleMove(InstructionOperand* source,
4213                                  InstructionOperand* destination) {
4214   PPCOperandConverter g(this, nullptr);
4215   // Dispatch on the source and destination operand kinds.  Not all
4216   // combinations are possible.
4217   if (source->IsRegister()) {
4218     DCHECK(destination->IsRegister() || destination->IsStackSlot());
4219     Register src = g.ToRegister(source);
4220     if (destination->IsRegister()) {
4221       __ Move(g.ToRegister(destination), src);
4222     } else {
4223       __ StoreU64(src, g.ToMemOperand(destination), r0);
4224     }
4225   } else if (source->IsStackSlot()) {
4226     DCHECK(destination->IsRegister() || destination->IsStackSlot());
4227     MemOperand src = g.ToMemOperand(source);
4228     if (destination->IsRegister()) {
4229       __ LoadU64(g.ToRegister(destination), src, r0);
4230     } else {
4231       Register temp = kScratchReg;
4232       __ LoadU64(temp, src, r0);
4233       __ StoreU64(temp, g.ToMemOperand(destination), r0);
4234     }
4235   } else if (source->IsConstant()) {
4236     Constant src = g.ToConstant(source);
4237     if (destination->IsRegister() || destination->IsStackSlot()) {
4238       Register dst =
4239           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
4240       switch (src.type()) {
4241         case Constant::kInt32:
4242 #if V8_ENABLE_WEBASSEMBLY && !V8_TARGET_ARCH_PPC64
4243           if (RelocInfo::IsWasmReference(src.rmode())) {
4244             __ mov(dst, Operand(src.ToInt32(), src.rmode()));
4245             break;
4246           }
4247 #endif  // V8_ENABLE_WEBASSEMBLY && !V8_TARGET_ARCH_PPC64
4248           __ mov(dst, Operand(src.ToInt32()));
4249           break;
4250         case Constant::kInt64:
4251 #if V8_ENABLE_WEBASSEMBLY && V8_TARGET_ARCH_PPC64
4252           if (RelocInfo::IsWasmReference(src.rmode())) {
4253             __ mov(dst, Operand(src.ToInt64(), src.rmode()));
4254             break;
4255           }
4256 #endif  // V8_ENABLE_WEBASSEMBLY && V8_TARGET_ARCH_PPC64
4257           __ mov(dst, Operand(src.ToInt64()));
4258           break;
4259         case Constant::kFloat32:
4260           __ mov(dst, Operand::EmbeddedNumber(src.ToFloat32()));
4261           break;
4262         case Constant::kFloat64:
4263           __ mov(dst, Operand::EmbeddedNumber(src.ToFloat64().value()));
4264           break;
4265         case Constant::kExternalReference:
4266           __ Move(dst, src.ToExternalReference());
4267           break;
4268         case Constant::kDelayedStringConstant:
4269           __ mov(dst, Operand::EmbeddedStringConstant(
4270                           src.ToDelayedStringConstant()));
4271           break;
4272         case Constant::kHeapObject: {
4273           Handle<HeapObject> src_object = src.ToHeapObject();
4274           RootIndex index;
4275           if (IsMaterializableFromRoot(src_object, &index)) {
4276             __ LoadRoot(dst, index);
4277           } else {
4278             __ Move(dst, src_object);
4279           }
4280           break;
4281         }
4282         case Constant::kCompressedHeapObject: {
4283           Handle<HeapObject> src_object = src.ToHeapObject();
4284           RootIndex index;
4285           if (IsMaterializableFromRoot(src_object, &index)) {
4286             __ LoadRoot(dst, index);
4287           } else {
4288             // TODO(v8:7703, jyan@ca.ibm.com): Turn into a
4289             // COMPRESSED_EMBEDDED_OBJECT when the constant pool entry size is
4290             // tagged size.
4291             __ Move(dst, src_object, RelocInfo::FULL_EMBEDDED_OBJECT);
4292           }
4293           break;
4294         }
4295         case Constant::kRpoNumber:
4296           UNREACHABLE();  // TODO(dcarney): loading RPO constants on PPC.
4297       }
4298       if (destination->IsStackSlot()) {
4299         __ StoreU64(dst, g.ToMemOperand(destination), r0);
4300       }
4301     } else {
4302       DoubleRegister dst = destination->IsFPRegister()
4303                                ? g.ToDoubleRegister(destination)
4304                                : kScratchDoubleReg;
4305       base::Double value;
4306 #if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
4307       // casting double precision snan to single precision
4308       // converts it to qnan on ia32/x64
4309       if (src.type() == Constant::kFloat32) {
4310         uint32_t val = src.ToFloat32AsInt();
4311         if ((val & 0x7F800000) == 0x7F800000) {
4312           uint64_t dval = static_cast<uint64_t>(val);
4313           dval = ((dval & 0xC0000000) << 32) | ((dval & 0x40000000) << 31) |
4314                  ((dval & 0x40000000) << 30) | ((dval & 0x7FFFFFFF) << 29);
4315           value = base::Double(dval);
4316         } else {
4317           value = base::Double(static_cast<double>(src.ToFloat32()));
4318         }
4319       } else {
4320         value = base::Double(src.ToFloat64());
4321       }
4322 #else
4323       value = src.type() == Constant::kFloat32
4324                   ? base::Double(static_cast<double>(src.ToFloat32()))
4325                   : base::Double(src.ToFloat64());
4326 #endif
4327       __ LoadDoubleLiteral(dst, value, kScratchReg);
4328       if (destination->IsDoubleStackSlot()) {
4329         __ StoreF64(dst, g.ToMemOperand(destination), r0);
4330       } else if (destination->IsFloatStackSlot()) {
4331         __ StoreF32(dst, g.ToMemOperand(destination), r0);
4332       }
4333     }
4334   } else if (source->IsFPRegister()) {
4335     MachineRepresentation rep = LocationOperand::cast(source)->representation();
4336     if (rep == MachineRepresentation::kSimd128) {
4337       if (destination->IsSimd128Register()) {
4338         __ vor(g.ToSimd128Register(destination), g.ToSimd128Register(source),
4339                g.ToSimd128Register(source));
4340       } else {
4341         DCHECK(destination->IsSimd128StackSlot());
4342         MemOperand dst = g.ToMemOperand(destination);
4343         __ mov(ip, Operand(dst.offset()));
4344         __ StoreSimd128(g.ToSimd128Register(source), MemOperand(dst.ra(), ip));
4345       }
4346     } else {
4347       DoubleRegister src = g.ToDoubleRegister(source);
4348       if (destination->IsFPRegister()) {
4349         DoubleRegister dst = g.ToDoubleRegister(destination);
4350         __ Move(dst, src);
4351       } else {
4352         DCHECK(destination->IsFPStackSlot());
4353         LocationOperand* op = LocationOperand::cast(source);
4354         if (op->representation() == MachineRepresentation::kFloat64) {
4355           __ StoreF64(src, g.ToMemOperand(destination), r0);
4356         } else {
4357           __ StoreF32(src, g.ToMemOperand(destination), r0);
4358         }
4359       }
4360     }
4361   } else if (source->IsFPStackSlot()) {
4362     DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
4363     MemOperand src = g.ToMemOperand(source);
4364     if (destination->IsFPRegister()) {
4365       LocationOperand* op = LocationOperand::cast(source);
4366       if (op->representation() == MachineRepresentation::kFloat64) {
4367         __ LoadF64(g.ToDoubleRegister(destination), src, r0);
4368       } else if (op->representation() == MachineRepresentation::kFloat32) {
4369         __ LoadF32(g.ToDoubleRegister(destination), src, r0);
4370       } else {
4371         DCHECK_EQ(MachineRepresentation::kSimd128, op->representation());
4372         MemOperand src = g.ToMemOperand(source);
4373         __ mov(ip, Operand(src.offset()));
4374         __ LoadSimd128(g.ToSimd128Register(destination),
4375                        MemOperand(src.ra(), ip));
4376       }
4377     } else {
4378       LocationOperand* op = LocationOperand::cast(source);
4379       DoubleRegister temp = kScratchDoubleReg;
4380       if (op->representation() == MachineRepresentation::kFloat64) {
4381         __ LoadF64(temp, src, r0);
4382         __ StoreF64(temp, g.ToMemOperand(destination), r0);
4383       } else if (op->representation() == MachineRepresentation::kFloat32) {
4384         __ LoadF32(temp, src, r0);
4385         __ StoreF32(temp, g.ToMemOperand(destination), r0);
4386       } else {
4387         DCHECK_EQ(MachineRepresentation::kSimd128, op->representation());
4388         // push v0, to be used as scratch
4389         __ addi(sp, sp, Operand(-kSimd128Size));
4390         __ StoreSimd128(v0, MemOperand(r0, sp));
4391         MemOperand src = g.ToMemOperand(source);
4392         MemOperand dst = g.ToMemOperand(destination);
4393         __ mov(ip, Operand(src.offset()));
4394         __ LoadSimd128(v0, MemOperand(src.ra(), ip));
4395         __ mov(ip, Operand(dst.offset()));
4396         __ StoreSimd128(v0, MemOperand(dst.ra(), ip));
4397         // restore v0
4398         __ LoadSimd128(v0, MemOperand(r0, sp));
4399         __ addi(sp, sp, Operand(kSimd128Size));
4400       }
4401     }
4402   } else {
4403     UNREACHABLE();
4404   }
4405 }
4406 
4407 // Swaping contents in source and destination.
4408 // source and destination could be:
4409 //   Register,
4410 //   FloatRegister,
4411 //   DoubleRegister,
4412 //   StackSlot,
4413 //   FloatStackSlot,
4414 //   or DoubleStackSlot
4415 void CodeGenerator::AssembleSwap(InstructionOperand* source,
4416                                  InstructionOperand* destination) {
4417   PPCOperandConverter g(this, nullptr);
4418   if (source->IsRegister()) {
4419     Register src = g.ToRegister(source);
4420     if (destination->IsRegister()) {
4421       __ SwapP(src, g.ToRegister(destination), kScratchReg);
4422     } else {
4423       DCHECK(destination->IsStackSlot());
4424       __ SwapP(src, g.ToMemOperand(destination), kScratchReg);
4425     }
4426   } else if (source->IsStackSlot()) {
4427     DCHECK(destination->IsStackSlot());
4428     __ SwapP(g.ToMemOperand(source), g.ToMemOperand(destination), kScratchReg,
4429              r0);
4430   } else if (source->IsFloatRegister()) {
4431     DoubleRegister src = g.ToDoubleRegister(source);
4432     if (destination->IsFloatRegister()) {
4433       __ SwapFloat32(src, g.ToDoubleRegister(destination), kScratchDoubleReg);
4434     } else {
4435       DCHECK(destination->IsFloatStackSlot());
4436       __ SwapFloat32(src, g.ToMemOperand(destination), kScratchDoubleReg);
4437     }
4438   } else if (source->IsDoubleRegister()) {
4439     DoubleRegister src = g.ToDoubleRegister(source);
4440     if (destination->IsDoubleRegister()) {
4441       __ SwapDouble(src, g.ToDoubleRegister(destination), kScratchDoubleReg);
4442     } else {
4443       DCHECK(destination->IsDoubleStackSlot());
4444       __ SwapDouble(src, g.ToMemOperand(destination), kScratchDoubleReg);
4445     }
4446   } else if (source->IsFloatStackSlot()) {
4447     DCHECK(destination->IsFloatStackSlot());
4448     __ SwapFloat32(g.ToMemOperand(source), g.ToMemOperand(destination),
4449                    kScratchDoubleReg, d0);
4450   } else if (source->IsDoubleStackSlot()) {
4451     DCHECK(destination->IsDoubleStackSlot());
4452     __ SwapDouble(g.ToMemOperand(source), g.ToMemOperand(destination),
4453                   kScratchDoubleReg, d0);
4454 
4455   } else if (source->IsSimd128Register()) {
4456     Simd128Register src = g.ToSimd128Register(source);
4457     if (destination->IsSimd128Register()) {
4458       __ SwapSimd128(src, g.ToSimd128Register(destination), kScratchSimd128Reg);
4459     } else {
4460       DCHECK(destination->IsSimd128StackSlot());
4461       __ SwapSimd128(src, g.ToMemOperand(destination), kScratchSimd128Reg);
4462     }
4463   } else if (source->IsSimd128StackSlot()) {
4464     DCHECK(destination->IsSimd128StackSlot());
4465     __ SwapSimd128(g.ToMemOperand(source), g.ToMemOperand(destination),
4466                    kScratchSimd128Reg);
4467 
4468   } else {
4469     UNREACHABLE();
4470   }
4471 
4472   return;
4473 }
4474 
4475 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
4476   for (size_t index = 0; index < target_count; ++index) {
4477     __ emit_label_addr(targets[index]);
4478   }
4479 }
4480 
4481 #undef __
4482 
4483 }  // namespace compiler
4484 }  // namespace internal
4485 }  // namespace v8
4486