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