v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
code-generator-ppc.cc
Go to the documentation of this file.
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
15#include "src/compiler/osr.h"
17
18#if V8_ENABLE_WEBASSEMBLY
21#endif // V8_ENABLE_WEBASSEMBLY
22
23namespace v8 {
24namespace internal {
25namespace compiler {
26
27#define __ masm()->
28
29#define kScratchReg r11
30
31// Adds PPC-specific methods to convert InstructionOperands.
33 public:
36
37 size_t OutputCount() { return instr_->OutputCount(); }
38
40 switch (instr_->flags_mode()) {
41 case kFlags_branch:
44 case kFlags_set:
46 case kFlags_trap:
47 case kFlags_select:
48 return SetRC;
49 case kFlags_none:
50 return LeaveRC;
51 }
53 }
54
55 bool CompareLogical() const {
56 switch (instr_->flags_condition()) {
61 return true;
62 default:
63 return false;
64 }
66 }
67
68 Operand InputImmediate(size_t index) {
69 Constant constant = ToConstant(instr_->InputAt(index));
70 switch (constant.type()) {
72 return Operand(constant.ToInt32());
74 return Operand::EmbeddedNumber(constant.ToFloat32());
76 return Operand::EmbeddedNumber(constant.ToFloat64().value());
78 return Operand(constant.ToInt64());
80 return Operand(constant.ToExternalReference());
82 RootIndex root_index;
83 if (gen_->isolate()->roots_table().IsRootHandle(constant.ToHeapObject(),
84 &root_index)) {
87 Tagged_t ptr =
89 return Operand(ptr);
90 }
91 return Operand(constant.ToHeapObject());
92 }
95 break;
96 }
98 }
99
100 MemOperand MemoryOperand(AddressingMode* mode, size_t* first_index) {
101 const size_t index = *first_index;
103 if (mode) *mode = addr_mode;
104 switch (addr_mode) {
105 case kMode_None:
106 break;
107 case kMode_MRI:
108 *first_index += 2;
109 return MemOperand(InputRegister(index + 0), InputInt64(index + 1));
110 case kMode_MRR:
111 *first_index += 2;
112 return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
113 case kMode_Root:
114 *first_index += 1;
115 return MemOperand(kRootRegister, InputRegister(index));
116 }
117 UNREACHABLE();
118 }
119
121 size_t first_index = 0) {
122 return MemoryOperand(mode, &first_index);
123 }
124
130
131 MemOperand SlotToMemOperand(int slot) const {
133 return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
134 }
135};
136
137static inline bool HasRegisterInput(Instruction* instr, size_t index) {
138 return instr->InputAt(index)->IsRegister();
139}
140
141namespace {
142
143class OutOfLineRecordWrite final : public OutOfLineCode {
144 public:
145 OutOfLineRecordWrite(
146 CodeGenerator* gen, Register object, Register offset, Register value,
147 Register scratch0, Register scratch1, RecordWriteMode mode,
148 StubCallMode stub_mode, UnwindingInfoWriter* unwinding_info_writer,
149 IndirectPointerTag indirect_pointer_tag = kIndirectPointerNullTag)
150 : OutOfLineCode(gen),
151 object_(object),
154 value_(value),
155 scratch0_(scratch0),
156 scratch1_(scratch1),
157 mode_(mode),
158#if V8_ENABLE_WEBASSEMBLY
159 stub_mode_(stub_mode),
160#endif // V8_ENABLE_WEBASSEMBLY
161 must_save_lr_(!gen->frame_access_state()->has_frame()),
162 unwinding_info_writer_(unwinding_info_writer),
163 zone_(gen->zone()),
164 indirect_pointer_tag_(indirect_pointer_tag) {
165 DCHECK(!AreAliased(object, offset, scratch0, scratch1));
166 DCHECK(!AreAliased(value, offset, scratch0, scratch1));
167 }
168
169 OutOfLineRecordWrite(
170 CodeGenerator* gen, Register object, int32_t offset, Register value,
171 Register scratch0, Register scratch1, RecordWriteMode mode,
172 StubCallMode stub_mode, UnwindingInfoWriter* unwinding_info_writer,
173 IndirectPointerTag indirect_pointer_tag = kIndirectPointerNullTag)
174 : OutOfLineCode(gen),
175 object_(object),
178 value_(value),
179 scratch0_(scratch0),
180 scratch1_(scratch1),
181 mode_(mode),
182#if V8_ENABLE_WEBASSEMBLY
183 stub_mode_(stub_mode),
184#endif // V8_ENABLE_WEBASSEMBLY
185 must_save_lr_(!gen->frame_access_state()->has_frame()),
186 unwinding_info_writer_(unwinding_info_writer),
187 zone_(gen->zone()),
188 indirect_pointer_tag_(indirect_pointer_tag) {
189 }
190
191 void Generate() final {
192 ConstantPoolUnavailableScope constant_pool_unavailable(masm());
193 // When storing an indirect pointer, the value will always be a
194 // full/decompressed pointer.
197 __ DecompressTagged(value_, value_);
198 }
199 __ CheckPageFlag(value_, scratch0_,
201 exit());
202 if (offset_ == no_reg) {
203 __ addi(scratch1_, object_, Operand(offset_immediate_));
204 } else {
206 __ add(scratch1_, object_, offset_);
207 }
208 SaveFPRegsMode const save_fp_mode = frame()->DidAllocateDoubleRegisters()
211 if (must_save_lr_) {
212 // We need to save and restore lr if the frame was elided.
213 __ mflr(scratch0_);
214 __ Push(scratch0_);
215 unwinding_info_writer_->MarkLinkRegisterOnTopOfStack(__ pc_offset());
216 }
218 __ CallEphemeronKeyBarrier(object_, scratch1_, save_fp_mode);
219 } else if (mode_ == RecordWriteMode::kValueIsIndirectPointer) {
221 __ CallIndirectPointerBarrier(object_, scratch1_, save_fp_mode,
223#if V8_ENABLE_WEBASSEMBLY
224 } else if (stub_mode_ == StubCallMode::kCallWasmRuntimeStub) {
225 __ CallRecordWriteStubSaveRegisters(object_, scratch1_, save_fp_mode,
226 StubCallMode::kCallWasmRuntimeStub);
227#endif // V8_ENABLE_WEBASSEMBLY
228 } else {
229 __ CallRecordWriteStubSaveRegisters(object_, scratch1_, save_fp_mode);
230 }
231 if (must_save_lr_) {
232 // We need to save and restore lr if the frame was elided.
233 __ Pop(scratch0_);
234 __ mtlr(scratch0_);
235 unwinding_info_writer_->MarkPopLinkRegisterFromTopOfStack(__ pc_offset());
236 }
237 }
238
239 private:
240 Register const object_;
241 Register const offset_;
242 int32_t const offset_immediate_; // Valid if offset_ == no_reg.
243 Register const value_;
244 Register const scratch0_;
245 Register const scratch1_;
247#if V8_ENABLE_WEBASSEMBLY
248 StubCallMode stub_mode_;
249#endif // V8_ENABLE_WEBASSEMBLY
251 UnwindingInfoWriter* const unwinding_info_writer_;
254};
255
257 switch (condition) {
258 case kEqual:
259 return eq;
260 case kNotEqual:
261 return ne;
262 case kSignedLessThan:
264 return lt;
267 return ge;
270 return le;
273 return gt;
274 case kOverflow:
275 // Overflow checked for add/sub only.
276 switch (op) {
277 case kPPC_Add32:
278 case kPPC_Add64:
279 case kPPC_Sub:
280 case kPPC_AddWithOverflow32:
281 case kPPC_SubWithOverflow32:
282 return lt;
283 default:
284 break;
285 }
286 break;
287 case kNotOverflow:
288 switch (op) {
289 case kPPC_Add32:
290 case kPPC_Add64:
291 case kPPC_Sub:
292 case kPPC_AddWithOverflow32:
293 case kPPC_SubWithOverflow32:
294 return ge;
295 default:
296 break;
297 }
298 break;
299 default:
300 break;
301 }
302 UNREACHABLE();
303}
304
305} // namespace
306
307#define ASSEMBLE_FLOAT_UNOP_RC(asm_instr, round) \
308 do { \
309 __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
310 i.OutputRCBit()); \
311 if (round) { \
312 __ frsp(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \
313 } \
314 } while (0)
315
316#define ASSEMBLE_FLOAT_BINOP_RC(asm_instr, round) \
317 do { \
318 __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
319 i.InputDoubleRegister(1), i.OutputRCBit()); \
320 if (round) { \
321 __ frsp(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \
322 } \
323 } while (0)
324
325#define ASSEMBLE_BINOP(asm_instr_reg, asm_instr_imm) \
326 do { \
327 if (HasRegisterInput(instr, 1)) { \
328 __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \
329 i.InputRegister(1)); \
330 } else { \
331 __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \
332 i.InputImmediate(1)); \
333 } \
334 } while (0)
335
336#define ASSEMBLE_BINOP_RC(asm_instr_reg, asm_instr_imm) \
337 do { \
338 if (HasRegisterInput(instr, 1)) { \
339 __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \
340 i.InputRegister(1), i.OutputRCBit()); \
341 } else { \
342 __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \
343 i.InputImmediate(1), i.OutputRCBit()); \
344 } \
345 } while (0)
346
347#define ASSEMBLE_BINOP_INT_RC(asm_instr_reg, asm_instr_imm) \
348 do { \
349 if (HasRegisterInput(instr, 1)) { \
350 __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \
351 i.InputRegister(1), i.OutputRCBit()); \
352 } else { \
353 __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \
354 i.InputImmediate(1), i.OutputRCBit()); \
355 } \
356 } while (0)
357
358#define ASSEMBLE_ADD_WITH_OVERFLOW() \
359 do { \
360 if (HasRegisterInput(instr, 1)) { \
361 __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
362 i.InputRegister(1), kScratchReg, r0); \
363 } else { \
364 __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
365 i.InputInt32(1), kScratchReg, r0); \
366 } \
367 } while (0)
368
369#define ASSEMBLE_SUB_WITH_OVERFLOW() \
370 do { \
371 if (HasRegisterInput(instr, 1)) { \
372 __ SubAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
373 i.InputRegister(1), kScratchReg, r0); \
374 } else { \
375 __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
376 -i.InputInt32(1), kScratchReg, r0); \
377 } \
378 } while (0)
379
380#define ASSEMBLE_ADD_WITH_OVERFLOW32() \
381 do { \
382 ASSEMBLE_ADD_WITH_OVERFLOW(); \
383 __ extsw(kScratchReg, kScratchReg, SetRC); \
384 } while (0)
385
386#define ASSEMBLE_SUB_WITH_OVERFLOW32() \
387 do { \
388 ASSEMBLE_SUB_WITH_OVERFLOW(); \
389 __ extsw(kScratchReg, kScratchReg, SetRC); \
390 } while (0)
391
392#define ASSEMBLE_COMPARE(cmp_instr, cmpl_instr) \
393 do { \
394 const CRegister cr = cr0; \
395 if (HasRegisterInput(instr, 1)) { \
396 if (i.CompareLogical()) { \
397 __ cmpl_instr(i.InputRegister(0), i.InputRegister(1), cr); \
398 } else { \
399 __ cmp_instr(i.InputRegister(0), i.InputRegister(1), cr); \
400 } \
401 } else { \
402 if (i.CompareLogical()) { \
403 __ cmpl_instr##i(i.InputRegister(0), i.InputImmediate(1), cr); \
404 } else { \
405 __ cmp_instr##i(i.InputRegister(0), i.InputImmediate(1), cr); \
406 } \
407 } \
408 DCHECK_EQ(SetRC, i.OutputRCBit()); \
409 } while (0)
410
411#define ASSEMBLE_FLOAT_COMPARE(cmp_instr) \
412 do { \
413 const CRegister cr = cr0; \
414 __ cmp_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1), cr); \
415 DCHECK_EQ(SetRC, i.OutputRCBit()); \
416 } while (0)
417
418#define ASSEMBLE_MODULO(div_instr, mul_instr) \
419 do { \
420 const Register scratch = kScratchReg; \
421 __ div_instr(scratch, i.InputRegister(0), i.InputRegister(1)); \
422 __ mul_instr(scratch, scratch, i.InputRegister(1)); \
423 __ sub(i.OutputRegister(), i.InputRegister(0), scratch, LeaveOE, \
424 i.OutputRCBit()); \
425 } while (0)
426
427#define ASSEMBLE_FLOAT_MODULO() \
428 do { \
429 FrameScope scope(masm(), StackFrame::MANUAL); \
430 __ PrepareCallCFunction(0, 2, kScratchReg); \
431 __ MovToFloatParameters(i.InputDoubleRegister(0), \
432 i.InputDoubleRegister(1)); \
433 __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2); \
434 __ MovFromFloatResult(i.OutputDoubleRegister()); \
435 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
436 } while (0)
437
438#define ASSEMBLE_IEEE754_UNOP(name) \
439 do { \
440 /* TODO(bmeurer): We should really get rid of this special instruction, */ \
441 /* and generate a CallAddress instruction instead. */ \
442 FrameScope scope(masm(), StackFrame::MANUAL); \
443 __ PrepareCallCFunction(0, 1, kScratchReg); \
444 __ MovToFloatParameter(i.InputDoubleRegister(0)); \
445 __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 1); \
446 /* Move the result in the double result register. */ \
447 __ MovFromFloatResult(i.OutputDoubleRegister()); \
448 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
449 } while (0)
450
451#define ASSEMBLE_IEEE754_BINOP(name) \
452 do { \
453 /* TODO(bmeurer): We should really get rid of this special instruction, */ \
454 /* and generate a CallAddress instruction instead. */ \
455 FrameScope scope(masm(), StackFrame::MANUAL); \
456 __ PrepareCallCFunction(0, 2, kScratchReg); \
457 __ MovToFloatParameters(i.InputDoubleRegister(0), \
458 i.InputDoubleRegister(1)); \
459 __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 2); \
460 /* Move the result in the double result register. */ \
461 __ MovFromFloatResult(i.OutputDoubleRegister()); \
462 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
463 } while (0)
464
465#define ASSEMBLE_LOAD_FLOAT(asm_instr, asm_instrp, asm_instrx) \
466 do { \
467 DoubleRegister result = i.OutputDoubleRegister(); \
468 size_t index = 0; \
469 AddressingMode mode = kMode_None; \
470 MemOperand operand = i.MemoryOperand(&mode, &index); \
471 bool is_atomic = i.InputInt32(index); \
472 if (mode == kMode_MRI) { \
473 intptr_t offset = operand.offset(); \
474 if (is_int16(offset)) { \
475 __ asm_instr(result, operand); \
476 } else { \
477 CHECK(CpuFeatures::IsSupported(PPC_10_PLUS)); \
478 __ asm_instrp(result, operand); \
479 } \
480 } else { \
481 __ asm_instrx(result, operand); \
482 } \
483 if (is_atomic) __ lwsync(); \
484 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
485 } while (0)
486
487#define ASSEMBLE_LOAD_INTEGER(asm_instr, asm_instrp, asm_instrx, \
488 must_be_aligned) \
489 do { \
490 Register result = i.OutputRegister(); \
491 size_t index = 0; \
492 AddressingMode mode = kMode_None; \
493 MemOperand operand = i.MemoryOperand(&mode, &index); \
494 bool is_atomic = i.InputInt32(index); \
495 if (mode == kMode_MRI) { \
496 intptr_t offset = operand.offset(); \
497 bool misaligned = offset & 3; \
498 if (is_int16(offset) && (!must_be_aligned || !misaligned)) { \
499 __ asm_instr(result, operand); \
500 } else { \
501 CHECK(CpuFeatures::IsSupported(PPC_10_PLUS)); \
502 __ asm_instrp(result, operand); \
503 } \
504 } else { \
505 __ asm_instrx(result, operand); \
506 } \
507 if (is_atomic) __ lwsync(); \
508 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
509 } while (0)
510
511#define ASSEMBLE_LOAD_INTEGER_RR(asm_instr) \
512 do { \
513 Register result = i.OutputRegister(); \
514 size_t index = 0; \
515 AddressingMode mode = kMode_None; \
516 MemOperand operand = i.MemoryOperand(&mode, &index); \
517 DCHECK_EQ(mode, kMode_MRR); \
518 bool is_atomic = i.InputInt32(index); \
519 __ asm_instr(result, operand); \
520 if (is_atomic) __ lwsync(); \
521 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
522 } while (0)
523
524#define ASSEMBLE_STORE_FLOAT(asm_instr, asm_instrp, asm_instrx) \
525 do { \
526 size_t index = 0; \
527 AddressingMode mode = kMode_None; \
528 MemOperand operand = i.MemoryOperand(&mode, &index); \
529 DoubleRegister value = i.InputDoubleRegister(index); \
530 bool is_atomic = i.InputInt32(3); \
531 if (is_atomic) __ lwsync(); \
532 /* removed frsp as instruction-selector checked */ \
533 /* value to be kFloat32 */ \
534 if (mode == kMode_MRI) { \
535 intptr_t offset = operand.offset(); \
536 if (is_int16(offset)) { \
537 __ asm_instr(value, operand); \
538 } else { \
539 CHECK(CpuFeatures::IsSupported(PPC_10_PLUS)); \
540 __ asm_instrp(value, operand); \
541 } \
542 } else { \
543 __ asm_instrx(value, operand); \
544 } \
545 if (is_atomic) __ sync(); \
546 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
547 } while (0)
548
549#define ASSEMBLE_STORE_INTEGER(asm_instr, asm_instrp, asm_instrx, \
550 must_be_aligned) \
551 do { \
552 size_t index = 0; \
553 AddressingMode mode = kMode_None; \
554 MemOperand operand = i.MemoryOperand(&mode, &index); \
555 Register value = i.InputRegister(index); \
556 bool is_atomic = i.InputInt32(index + 1); \
557 if (is_atomic) __ lwsync(); \
558 if (mode == kMode_MRI) { \
559 intptr_t offset = operand.offset(); \
560 bool misaligned = offset & 3; \
561 if (is_int16(offset) && (!must_be_aligned || !misaligned)) { \
562 __ asm_instr(value, operand); \
563 } else { \
564 CHECK(CpuFeatures::IsSupported(PPC_10_PLUS)); \
565 __ asm_instrp(value, operand); \
566 } \
567 } else { \
568 __ asm_instrx(value, operand); \
569 } \
570 if (is_atomic) __ sync(); \
571 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
572 } while (0)
573
574#define ASSEMBLE_STORE_INTEGER_RR(asm_instr) \
575 do { \
576 size_t index = 0; \
577 AddressingMode mode = kMode_None; \
578 MemOperand operand = i.MemoryOperand(&mode, &index); \
579 DCHECK_EQ(mode, kMode_MRR); \
580 Register value = i.InputRegister(index); \
581 bool is_atomic = i.InputInt32(index + 1); \
582 if (is_atomic) __ lwsync(); \
583 __ asm_instr(value, operand); \
584 if (is_atomic) __ sync(); \
585 DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
586 } while (0)
587
588// TODO(mbrandy): fix paths that produce garbage in offset's upper 32-bits.
589#define CleanUInt32(x) __ ClearLeftImm(x, x, Operand(32))
590
591#if V8_ENABLE_WEBASSEMBLY
592static inline bool is_wasm_on_be(bool IsWasm) {
593#if V8_TARGET_BIG_ENDIAN
594 return IsWasm;
595#else
596 return false;
597#endif
598}
599#endif
600
601#if V8_ENABLE_WEBASSEMBLY
602#define MAYBE_REVERSE_IF_WASM(dst, src, op, scratch, reset) \
603 if (is_wasm_on_be(info()->IsWasm())) { \
604 __ op(dst, src, scratch); \
605 if (reset) src = dst; \
606 }
607#else
608#define MAYBE_REVERSE_IF_WASM(dst, src, op, scratch, reset)
609#endif
610
611#define ASSEMBLE_ATOMIC_EXCHANGE(_type, reverse_op) \
612 do { \
613 Register val = i.InputRegister(2); \
614 Register dst = i.OutputRegister(); \
615 MAYBE_REVERSE_IF_WASM(ip, val, reverse_op, kScratchReg, true); \
616 __ AtomicExchange<_type>( \
617 MemOperand(i.InputRegister(0), i.InputRegister(1)), val, dst); \
618 MAYBE_REVERSE_IF_WASM(dst, dst, reverse_op, kScratchReg, false); \
619 } while (false)
620
621#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(_type, reverse_op) \
622 do { \
623 Register expected_val = i.InputRegister(2); \
624 Register new_val = i.InputRegister(3); \
625 Register dst = i.OutputRegister(); \
626 MAYBE_REVERSE_IF_WASM(ip, expected_val, reverse_op, kScratchReg, true); \
627 MAYBE_REVERSE_IF_WASM(r0, new_val, reverse_op, kScratchReg, true); \
628 __ AtomicCompareExchange<_type>( \
629 MemOperand(i.InputRegister(0), i.InputRegister(1)), expected_val, \
630 new_val, dst, kScratchReg); \
631 MAYBE_REVERSE_IF_WASM(dst, dst, reverse_op, kScratchReg, false); \
632 } while (false)
633
634#define ASSEMBLE_ATOMIC_BINOP_BYTE(bin_inst, _type) \
635 do { \
636 auto bin_op = [&](Register dst, Register lhs, Register rhs) { \
637 if (std::is_signed<_type>::value) { \
638 __ extsb(dst, lhs); \
639 __ bin_inst(dst, dst, rhs); \
640 } else { \
641 __ bin_inst(dst, lhs, rhs); \
642 } \
643 }; \
644 MemOperand dst_operand = \
645 MemOperand(i.InputRegister(0), i.InputRegister(1)); \
646 __ AtomicOps<_type>(dst_operand, i.InputRegister(2), i.OutputRegister(), \
647 kScratchReg, bin_op); \
648 break; \
649 } while (false)
650
651#define ASSEMBLE_ATOMIC_BINOP(bin_inst, _type, reverse_op, scratch) \
652 do { \
653 auto bin_op = [&](Register dst, Register lhs, Register rhs) { \
654 Register _lhs = lhs; \
655 MAYBE_REVERSE_IF_WASM(dst, _lhs, reverse_op, scratch, true); \
656 if (std::is_signed<_type>::value) { \
657 switch (sizeof(_type)) { \
658 case 1: \
659 UNREACHABLE(); \
660 break; \
661 case 2: \
662 __ extsh(dst, _lhs); \
663 break; \
664 case 4: \
665 __ extsw(dst, _lhs); \
666 break; \
667 case 8: \
668 break; \
669 default: \
670 UNREACHABLE(); \
671 } \
672 } \
673 __ bin_inst(dst, _lhs, rhs); \
674 MAYBE_REVERSE_IF_WASM(dst, dst, reverse_op, scratch, false); \
675 }; \
676 MemOperand dst_operand = \
677 MemOperand(i.InputRegister(0), i.InputRegister(1)); \
678 __ AtomicOps<_type>(dst_operand, i.InputRegister(2), i.OutputRegister(), \
679 kScratchReg, bin_op); \
680 MAYBE_REVERSE_IF_WASM(i.OutputRegister(), i.OutputRegister(), reverse_op, \
681 scratch, false); \
682 break; \
683 } while (false)
684
686 __ LeaveFrame(StackFrame::MANUAL);
688}
689
691 if (frame_access_state()->has_frame()) {
692 __ RestoreFrameStateForTailCall();
693 }
695}
696
697namespace {
698
699void FlushPendingPushRegisters(MacroAssembler* masm,
700 FrameAccessState* frame_access_state,
701 ZoneVector<Register>* pending_pushes) {
702 switch (pending_pushes->size()) {
703 case 0:
704 break;
705 case 1:
706 masm->Push((*pending_pushes)[0]);
707 break;
708 case 2:
709 masm->Push((*pending_pushes)[0], (*pending_pushes)[1]);
710 break;
711 case 3:
712 masm->Push((*pending_pushes)[0], (*pending_pushes)[1],
713 (*pending_pushes)[2]);
714 break;
715 default:
716 UNREACHABLE();
717 }
718 frame_access_state->IncreaseSPDelta(pending_pushes->size());
719 pending_pushes->clear();
720}
721
722void AdjustStackPointerForTailCall(
723 MacroAssembler* masm, FrameAccessState* state, int new_slot_above_sp,
724 ZoneVector<Register>* pending_pushes = nullptr,
725 bool allow_shrinkage = true) {
726 int current_sp_offset = state->GetSPToFPSlotCount() +
728 int stack_slot_delta = new_slot_above_sp - current_sp_offset;
729 if (stack_slot_delta > 0) {
730 if (pending_pushes != nullptr) {
731 FlushPendingPushRegisters(masm, state, pending_pushes);
732 }
733 masm->AddS64(sp, sp, Operand(-stack_slot_delta * kSystemPointerSize), r0);
734 state->IncreaseSPDelta(stack_slot_delta);
735 } else if (allow_shrinkage && stack_slot_delta < 0) {
736 if (pending_pushes != nullptr) {
737 FlushPendingPushRegisters(masm, state, pending_pushes);
738 }
739 masm->AddS64(sp, sp, Operand(-stack_slot_delta * kSystemPointerSize), r0);
740 state->IncreaseSPDelta(stack_slot_delta);
741 }
742}
743
744} // namespace
745
747 int first_unused_slot_offset) {
748 ZoneVector<MoveOperands*> pushes(zone());
750
751 if (!pushes.empty() &&
752 (LocationOperand::cast(pushes.back()->destination()).index() + 1 ==
753 first_unused_slot_offset)) {
754 PPCOperandConverter g(this, instr);
755 ZoneVector<Register> pending_pushes(zone());
756 for (auto move : pushes) {
757 LocationOperand destination_location(
758 LocationOperand::cast(move->destination()));
759 InstructionOperand source(move->source());
760 AdjustStackPointerForTailCall(
762 destination_location.index() - pending_pushes.size(),
763 &pending_pushes);
764 // Pushes of non-register data types are not supported.
765 DCHECK(source.IsRegister());
766 LocationOperand source_location(LocationOperand::cast(source));
767 pending_pushes.push_back(source_location.GetRegister());
768 // TODO(arm): We can push more than 3 registers at once. Add support in
769 // the macro-assembler for pushing a list of registers.
770 if (pending_pushes.size() == 3) {
771 FlushPendingPushRegisters(masm(), frame_access_state(),
772 &pending_pushes);
773 }
774 move->Eliminate();
775 }
776 FlushPendingPushRegisters(masm(), frame_access_state(), &pending_pushes);
777 }
778 AdjustStackPointerForTailCall(masm(), frame_access_state(),
779 first_unused_slot_offset, nullptr, false);
780}
781
783 int first_unused_slot_offset) {
784 AdjustStackPointerForTailCall(masm(), frame_access_state(),
785 first_unused_slot_offset);
786}
787
788// Check that {kJavaScriptCallCodeStartRegister} is correct.
790 Register scratch = kScratchReg;
791 __ ComputeCodeStartAddress(scratch);
792 __ CmpS64(scratch, kJavaScriptCallCodeStartRegister);
793 __ Assert(eq, AbortReason::kWrongFunctionCodeStart);
794}
795
796#ifdef V8_ENABLE_LEAPTIERING
797void CodeGenerator::AssembleDispatchHandleRegisterCheck() {
799}
800#endif // V8_ENABLE_LEAPTIERING
801
803
804// Assembles an instruction after register allocation, producing machine code.
806 Instruction* instr) {
807 PPCOperandConverter i(this, instr);
808 ArchOpcode opcode = ArchOpcodeField::decode(instr->opcode());
809
810 switch (opcode) {
811 case kArchCallCodeObject: {
813 masm());
814 if (HasRegisterInput(instr, 0)) {
815 Register reg = i.InputRegister(0);
817 instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
819 __ CallCodeObject(reg);
820 } else {
821 __ Call(i.InputCode(0), RelocInfo::CODE_TARGET);
822 }
824 DCHECK_EQ(LeaveRC, i.OutputRCBit());
826 break;
827 }
828 case kArchCallBuiltinPointer: {
829 DCHECK(!instr->InputAt(0)->IsImmediate());
830 Register builtin_index = i.InputRegister(0);
831 Register target =
832 instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister)
834 : builtin_index;
835 __ CallBuiltinByIndex(builtin_index, target);
838 break;
839 }
840#if V8_ENABLE_WEBASSEMBLY
841 case kArchCallWasmFunction:
842 case kArchCallWasmFunctionIndirect: {
843 // We must not share code targets for calls to builtins for wasm code, as
844 // they might need to be patched individually.
845 if (instr->InputAt(0)->IsImmediate()) {
846 DCHECK_EQ(opcode, kArchCallWasmFunction);
847 Constant constant = i.ToConstant(instr->InputAt(0));
848 Address wasm_code = static_cast<Address>(constant.ToInt64());
849 __ Call(wasm_code, constant.rmode());
850 } else if (opcode == kArchCallWasmFunctionIndirect) {
851 __ CallWasmCodePointer(i.InputRegister(0));
852 } else {
853 __ Call(i.InputRegister(0));
854 }
856 DCHECK_EQ(LeaveRC, i.OutputRCBit());
858 break;
859 }
860 case kArchTailCallWasm:
861 case kArchTailCallWasmIndirect: {
862 // We must not share code targets for calls to builtins for wasm code, as
863 // they might need to be patched individually.
864 if (instr->InputAt(0)->IsImmediate()) {
865 DCHECK_EQ(opcode, kArchTailCallWasm);
866 Constant constant = i.ToConstant(instr->InputAt(0));
867 Address wasm_code = static_cast<Address>(constant.ToInt64());
868 __ Jump(wasm_code, constant.rmode());
869 } else if (opcode == kArchTailCallWasmIndirect) {
870 __ CallWasmCodePointer(i.InputRegister(0), CallJumpMode::kTailCall);
871 } else {
872 __ Jump(i.InputRegister(0));
873 }
874 DCHECK_EQ(LeaveRC, i.OutputRCBit());
877 break;
878 }
879#endif // V8_ENABLE_WEBASSEMBLY
880 case kArchTailCallCodeObject: {
881 if (HasRegisterInput(instr, 0)) {
882 Register reg = i.InputRegister(0);
884 instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
886 __ JumpCodeObject(reg);
887 } else {
888 // We cannot use the constant pool to load the target since
889 // we've already restored the caller's frame.
890 ConstantPoolUnavailableScope constant_pool_unavailable(masm());
891 __ Jump(i.InputCode(0), RelocInfo::CODE_TARGET);
892 }
893 DCHECK_EQ(LeaveRC, i.OutputRCBit());
896 break;
897 }
898 case kArchTailCallAddress: {
899 CHECK(!instr->InputAt(0)->IsImmediate());
900 Register reg = i.InputRegister(0);
902 instr->HasCallDescriptorFlag(CallDescriptor::kFixedTargetRegister),
904 __ Jump(reg);
907 break;
908 }
909 case kArchCallJSFunction: {
911 masm());
912 Register func = i.InputRegister(0);
913 if (v8_flags.debug_code) {
914 // Check the function's context matches the context argument.
915 __ LoadTaggedField(
916 kScratchReg, FieldMemOperand(func, JSFunction::kContextOffset), r0);
917 __ CmpS64(cp, kScratchReg);
918 __ Assert(eq, AbortReason::kWrongFunctionContext);
919 }
920 uint32_t num_arguments =
921 i.InputUint32(instr->JSCallArgumentCountInputIndex());
922 __ CallJSFunction(func, num_arguments, kScratchReg);
924 DCHECK_EQ(LeaveRC, i.OutputRCBit());
926 break;
927 }
928 case kArchPrepareCallCFunction: {
929 int const num_gp_parameters = ParamField::decode(instr->opcode());
930 int const num_fp_parameters = FPParamField::decode(instr->opcode());
931 __ PrepareCallCFunction(num_gp_parameters + num_fp_parameters,
933 // Frame alignment requires using FP-relative frame addressing.
935 break;
936 }
937 case kArchSaveCallerRegisters: {
938 fp_mode_ =
939 static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode()));
942 // kReturnRegister0 should have been saved before entering the stub.
943 int bytes = __ PushCallerSaved(fp_mode_, ip, r0, kReturnRegister0);
945 DCHECK_EQ(0, frame_access_state()->sp_delta());
949 break;
950 }
951 case kArchRestoreCallerRegisters: {
953 static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode())));
956 // Don't overwrite the returned value.
957 int bytes = __ PopCallerSaved(fp_mode_, ip, r0, kReturnRegister0);
959 DCHECK_EQ(0, frame_access_state()->sp_delta());
962 break;
963 }
964 case kArchPrepareTailCall:
966 break;
967 case kArchComment:
968 __ RecordComment(reinterpret_cast<const char*>(i.InputInt64(0)),
970 break;
971 case kArchCallCFunctionWithFrameState:
972 case kArchCallCFunction: {
973 int const num_gp_parameters = ParamField::decode(instr->opcode());
974 int const fp_param_field = FPParamField::decode(instr->opcode());
975 int num_fp_parameters = fp_param_field;
976 bool has_function_descriptor = false;
977 SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes;
978#if ABI_USES_FUNCTION_DESCRIPTORS
979 // AIX/PPC64BE Linux uses a function descriptor
980 int kNumFPParametersMask = kHasFunctionDescriptorBitMask - 1;
981 num_fp_parameters = kNumFPParametersMask & fp_param_field;
982 has_function_descriptor =
983 (fp_param_field & kHasFunctionDescriptorBitMask) != 0;
984#endif
985#if V8_ENABLE_WEBASSEMBLY
986 Label start_call;
987 int start_pc_offset = 0;
988 bool isWasmCapiFunction =
989 linkage()->GetIncomingDescriptor()->IsWasmCapiFunction();
990 if (isWasmCapiFunction) {
991 __ mflr(r0);
992 __ LoadPC(kScratchReg);
993 __ bind(&start_call);
994 start_pc_offset = __ pc_offset();
995 // We are going to patch this instruction after emitting
996 // CallCFunction, using a zero offset here as placeholder for now.
997 // patch_pc_address assumes `addi` is used here to
998 // add the offset to pc.
1000 __ StoreU64(kScratchReg,
1001 MemOperand(fp, WasmExitFrameConstants::kCallingPCOffset));
1002 __ mtlr(r0);
1003 set_isolate_data_slots = SetIsolateDataSlots::kNo;
1004 }
1005#endif // V8_ENABLE_WEBASSEMBLY
1006 int pc_offset;
1007 if (instr->InputAt(0)->IsImmediate()) {
1008 ExternalReference ref = i.InputExternalReference(0);
1009 pc_offset =
1010 __ CallCFunction(ref, num_gp_parameters, num_fp_parameters,
1011 set_isolate_data_slots, has_function_descriptor);
1012 } else {
1013 Register func = i.InputRegister(0);
1014 pc_offset =
1015 __ CallCFunction(func, num_gp_parameters, num_fp_parameters,
1016 set_isolate_data_slots, has_function_descriptor);
1017 }
1018#if V8_ENABLE_WEBASSEMBLY
1019 if (isWasmCapiFunction) {
1020 int offset_since_start_call = pc_offset - start_pc_offset;
1021 // Here we are going to patch the `addi` instruction above to use the
1022 // correct offset.
1023 // LoadPC emits two instructions and pc is the address of its second
1024 // emitted instruction. Add one more to the offset to point to after the
1025 // Call.
1026 offset_since_start_call += kInstrSize;
1027 __ patch_pc_address(kScratchReg, start_pc_offset,
1028 offset_since_start_call);
1029 }
1030#endif // V8_ENABLE_WEBASSEMBLY
1031 RecordSafepoint(instr->reference_map(), pc_offset);
1032
1033 bool const needs_frame_state =
1034 (opcode == kArchCallCFunctionWithFrameState);
1035 if (needs_frame_state) {
1037 }
1038
1040 // Ideally, we should decrement SP delta to match the change of stack
1041 // pointer in CallCFunction. However, for certain architectures (e.g.
1042 // ARM), there may be more strict alignment requirement, causing old SP
1043 // to be saved on the stack. In those cases, we can not calculate the SP
1044 // delta statically.
1047 // Need to re-sync SP delta introduced in kArchSaveCallerRegisters.
1048 // Here, we assume the sequence to be:
1049 // kArchSaveCallerRegisters;
1050 // kArchCallCFunction;
1051 // kArchRestoreCallerRegisters;
1052 int bytes =
1053 __ RequiredStackSizeForCallerSaved(fp_mode_, kReturnRegister0);
1055 }
1056 break;
1057 }
1058 case kArchJmp:
1059 AssembleArchJump(i.InputRpo(0));
1060 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1061 break;
1062 case kArchBinarySearchSwitch:
1064 break;
1065 case kArchTableSwitch:
1067 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1068 break;
1069 case kArchAbortCSADcheck:
1070 DCHECK(i.InputRegister(0) == r4);
1071 {
1072 // We don't actually want to generate a pile of code for this, so just
1073 // claim there is a stack frame, without generating one.
1074 FrameScope scope(masm(), StackFrame::NO_FRAME_TYPE);
1075 __ CallBuiltin(Builtin::kAbortCSADcheck);
1076 }
1077 __ stop();
1078 break;
1079 case kArchDebugBreak:
1080 __ DebugBreak();
1081 break;
1082 case kArchNop:
1083 case kArchThrowTerminator:
1084 // don't emit code for nops.
1085 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1086 break;
1087 case kArchDeoptimize: {
1088 DeoptimizationExit* exit =
1090 __ b(exit->label());
1091 break;
1092 }
1093 case kArchRet:
1094 AssembleReturn(instr->InputAt(0));
1095 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1096 break;
1097 case kArchFramePointer:
1098 __ mr(i.OutputRegister(), fp);
1099 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1100 break;
1101 case kArchParentFramePointer:
1102 if (frame_access_state()->has_frame()) {
1103 __ LoadU64(i.OutputRegister(), MemOperand(fp, 0));
1104 } else {
1105 __ mr(i.OutputRegister(), fp);
1106 }
1107 break;
1108#if V8_ENABLE_WEBASSEMBLY
1109 case kArchStackPointer:
1110 __ mr(i.OutputRegister(), sp);
1111 break;
1112 case kArchSetStackPointer: {
1113 DCHECK(instr->InputAt(0)->IsRegister());
1114 __ mr(sp, i.InputRegister(0));
1115 break;
1116 }
1117#endif // V8_ENABLE_WEBASSEMBLY
1118 case kArchStackPointerGreaterThan: {
1119 // Potentially apply an offset to the current stack pointer before the
1120 // comparison to consider the size difference of an optimized frame versus
1121 // the contained unoptimized frames.
1122
1123 Register lhs_register = sp;
1124 uint32_t offset;
1125
1127 lhs_register = i.TempRegister(0);
1128 __ SubS64(lhs_register, sp, Operand(offset), kScratchReg);
1129 }
1130
1131 constexpr size_t kValueIndex = 0;
1132 DCHECK(instr->InputAt(kValueIndex)->IsRegister());
1133 __ CmpU64(lhs_register, i.InputRegister(kValueIndex), cr0);
1134 break;
1135 }
1136 case kArchStackCheckOffset:
1137 __ LoadSmiLiteral(i.OutputRegister(),
1139 break;
1140 case kArchTruncateDoubleToI:
1141 __ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(),
1142 i.InputDoubleRegister(0), DetermineStubCallMode());
1143 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1144 break;
1145 case kArchStoreWithWriteBarrier: {
1147 // Indirect pointer writes must use a different opcode.
1149 Register object = i.InputRegister(0);
1150 Register value = i.InputRegister(2);
1151 Register scratch0 = i.TempRegister(0);
1152 Register scratch1 = i.TempRegister(1);
1153 OutOfLineRecordWrite* ool;
1154
1155 if (v8_flags.debug_code) {
1156 // Checking that |value| is not a cleared weakref: our write barrier
1157 // does not support that for now.
1158 __ CmpS64(value, Operand(kClearedWeakHeapObjectLower32), kScratchReg);
1159 __ Check(ne, AbortReason::kOperandIsCleared);
1160 }
1161
1162 AddressingMode addressing_mode =
1164 if (addressing_mode == kMode_MRI) {
1165 int32_t offset = i.InputInt32(1);
1166 ool = zone()->New<OutOfLineRecordWrite>(
1167 this, object, offset, value, scratch0, scratch1, mode,
1169 __ StoreTaggedField(value, MemOperand(object, offset), r0);
1170 } else {
1171 DCHECK_EQ(kMode_MRR, addressing_mode);
1172 Register offset(i.InputRegister(1));
1173 ool = zone()->New<OutOfLineRecordWrite>(
1174 this, object, offset, value, scratch0, scratch1, mode,
1176 __ StoreTaggedField(value, MemOperand(object, offset), r0);
1177 }
1178 // Skip the write barrier if the value is a Smi. However, this is only
1179 // valid if the value isn't an indirect pointer. Otherwise the value will
1180 // be a pointer table index, which will always look like a Smi (but
1181 // actually reference a pointer in the pointer table).
1183 __ JumpIfSmi(value, ool->exit());
1184 }
1185 __ CheckPageFlag(object, scratch0,
1187 ool->entry());
1188 __ bind(ool->exit());
1189 break;
1190 }
1191 case kArchStoreIndirectWithWriteBarrier: {
1193 Register scratch0 = i.TempRegister(0);
1194 Register scratch1 = i.TempRegister(1);
1195 OutOfLineRecordWrite* ool;
1197 AddressingMode addressing_mode =
1199 Register object = i.InputRegister(0);
1200 Register value = i.InputRegister(2);
1201 IndirectPointerTag tag = static_cast<IndirectPointerTag>(i.InputInt64(3));
1203 if (addressing_mode == kMode_MRI) {
1204 uint64_t offset = i.InputInt64(1);
1205 ool = zone()->New<OutOfLineRecordWrite>(
1206 this, object, offset, value, scratch0, scratch1, mode,
1208 __ StoreIndirectPointerField(value, MemOperand(object, offset), r0);
1209 } else {
1210 DCHECK_EQ(addressing_mode, kMode_MRR);
1211 Register offset(i.InputRegister(1));
1212 ool = zone()->New<OutOfLineRecordWrite>(
1213 this, object, offset, value, scratch0, scratch1, mode,
1215 __ StoreIndirectPointerField(value, MemOperand(object, offset), r0);
1216 }
1217 __ CheckPageFlag(object, scratch0,
1219 ool->entry());
1220 __ bind(ool->exit());
1221 break;
1222 }
1223 case kArchStackSlot: {
1224 FrameOffset offset =
1225 frame_access_state()->GetFrameOffset(i.InputInt32(0));
1226 __ AddS64(i.OutputRegister(), offset.from_stack_pointer() ? sp : fp,
1227 Operand(offset.offset()), r0);
1228 break;
1229 }
1230 case kPPC_Peek: {
1231 int reverse_slot = i.InputInt32(0);
1232 int offset =
1233 FrameSlotToFPOffset(frame()->GetTotalFrameSlotCount() - reverse_slot);
1234 if (instr->OutputAt(0)->IsFPRegister()) {
1235 LocationOperand* op = LocationOperand::cast(instr->OutputAt(0));
1236 if (op->representation() == MachineRepresentation::kFloat64) {
1237 __ LoadF64(i.OutputDoubleRegister(), MemOperand(fp, offset), r0);
1238 } else if (op->representation() == MachineRepresentation::kFloat32) {
1239 __ LoadF32(i.OutputFloatRegister(), MemOperand(fp, offset), r0);
1240 } else {
1241 DCHECK_EQ(MachineRepresentation::kSimd128, op->representation());
1242 __ LoadSimd128(i.OutputSimd128Register(), MemOperand(fp, offset),
1243 kScratchReg);
1244 }
1245 } else {
1246 __ LoadU64(i.OutputRegister(), MemOperand(fp, offset), r0);
1247 }
1248 break;
1249 }
1250 case kPPC_Sync: {
1251 __ sync();
1252 break;
1253 }
1254 case kPPC_And:
1255 if (HasRegisterInput(instr, 1)) {
1256 __ and_(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1257 i.OutputRCBit());
1258 } else {
1259 __ andi(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
1260 }
1261 break;
1262 case kPPC_AndComplement:
1263 __ andc(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1264 i.OutputRCBit());
1265 break;
1266 case kPPC_Or:
1267 if (HasRegisterInput(instr, 1)) {
1268 __ orx(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1269 i.OutputRCBit());
1270 } else {
1271 __ ori(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
1272 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1273 }
1274 break;
1275 case kPPC_OrComplement:
1276 __ orc(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1277 i.OutputRCBit());
1278 break;
1279 case kPPC_Xor:
1280 if (HasRegisterInput(instr, 1)) {
1281 __ xor_(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1282 i.OutputRCBit());
1283 } else {
1284 __ xori(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
1285 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1286 }
1287 break;
1288 case kPPC_ShiftLeft32:
1289 ASSEMBLE_BINOP_RC(ShiftLeftU32, ShiftLeftU32);
1290 break;
1291 case kPPC_ShiftLeft64:
1292 ASSEMBLE_BINOP_RC(ShiftLeftU64, ShiftLeftU64);
1293 break;
1294 case kPPC_ShiftRight32:
1295 ASSEMBLE_BINOP_RC(ShiftRightU32, ShiftRightU32);
1296 break;
1297 case kPPC_ShiftRight64:
1298 ASSEMBLE_BINOP_RC(ShiftRightU64, ShiftRightU64);
1299 break;
1300 case kPPC_ShiftRightAlg32:
1301 ASSEMBLE_BINOP_INT_RC(ShiftRightS32, ShiftRightS32);
1302 break;
1303 case kPPC_ShiftRightAlg64:
1304 ASSEMBLE_BINOP_INT_RC(ShiftRightS64, ShiftRightS64);
1305 break;
1306 case kPPC_RotRight32:
1307 if (HasRegisterInput(instr, 1)) {
1308 __ subfic(kScratchReg, i.InputRegister(1), Operand(32));
1309 __ rotlw(i.OutputRegister(), i.InputRegister(0), kScratchReg,
1310 i.OutputRCBit());
1311 } else {
1312 int sh = i.InputInt32(1);
1313 __ rotrwi(i.OutputRegister(), i.InputRegister(0), sh, i.OutputRCBit());
1314 }
1315 break;
1316 case kPPC_RotRight64:
1317 if (HasRegisterInput(instr, 1)) {
1318 __ subfic(kScratchReg, i.InputRegister(1), Operand(64));
1319 __ rotld(i.OutputRegister(), i.InputRegister(0), kScratchReg,
1320 i.OutputRCBit());
1321 } else {
1322 int sh = i.InputInt32(1);
1323 __ rotrdi(i.OutputRegister(), i.InputRegister(0), sh, i.OutputRCBit());
1324 }
1325 break;
1326 case kPPC_Not:
1327 __ notx(i.OutputRegister(), i.InputRegister(0), i.OutputRCBit());
1328 break;
1329 case kPPC_RotLeftAndMask32:
1330 __ rlwinm(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
1331 31 - i.InputInt32(2), 31 - i.InputInt32(3), i.OutputRCBit());
1332 break;
1333 case kPPC_RotLeftAndClear64:
1334 __ rldic(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
1335 63 - i.InputInt32(2), i.OutputRCBit());
1336 break;
1337 case kPPC_RotLeftAndClearLeft64:
1338 __ rldicl(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
1339 63 - i.InputInt32(2), i.OutputRCBit());
1340 break;
1341 case kPPC_RotLeftAndClearRight64:
1342 __ rldicr(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
1343 63 - i.InputInt32(2), i.OutputRCBit());
1344 break;
1345 case kPPC_Add32:
1346 if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
1348 } else {
1349 if (HasRegisterInput(instr, 1)) {
1350 __ add(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1351 LeaveOE, i.OutputRCBit());
1352 } else {
1353 __ AddS64(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1),
1354 r0, LeaveOE, i.OutputRCBit());
1355 }
1356 __ extsw(i.OutputRegister(), i.OutputRegister());
1357 }
1358 break;
1359 case kPPC_Add64:
1360 if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
1362 } else {
1363 if (HasRegisterInput(instr, 1)) {
1364 __ add(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1365 LeaveOE, i.OutputRCBit());
1366 } else {
1367 __ AddS64(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1),
1368 r0, LeaveOE, i.OutputRCBit());
1369 }
1370 }
1371 break;
1372 case kPPC_AddWithOverflow32:
1374 break;
1375 case kPPC_AddDouble:
1377 break;
1378 case kPPC_Sub:
1379 if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
1381 } else {
1382 if (HasRegisterInput(instr, 1)) {
1383 __ sub(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1384 LeaveOE, i.OutputRCBit());
1385 } else {
1386 __ SubS64(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1),
1387 r0, LeaveOE, i.OutputRCBit());
1388 }
1389 }
1390 break;
1391 case kPPC_SubWithOverflow32:
1393 break;
1394 case kPPC_SubDouble:
1396 break;
1397 case kPPC_Mul32:
1398 __ mullw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1399 LeaveOE, i.OutputRCBit());
1400 break;
1401 case kPPC_Mul64:
1402 __ mulld(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1403 LeaveOE, i.OutputRCBit());
1404 break;
1405 case kPPC_Mul32WithHigh32:
1406 if (i.OutputRegister(0) == i.InputRegister(0) ||
1407 i.OutputRegister(0) == i.InputRegister(1) ||
1408 i.OutputRegister(1) == i.InputRegister(0) ||
1409 i.OutputRegister(1) == i.InputRegister(1)) {
1410 __ mullw(kScratchReg, i.InputRegister(0), i.InputRegister(1)); // low
1411 __ mulhw(i.OutputRegister(1), i.InputRegister(0),
1412 i.InputRegister(1)); // high
1413 __ mr(i.OutputRegister(0), kScratchReg);
1414 } else {
1415 __ mullw(i.OutputRegister(0), i.InputRegister(0),
1416 i.InputRegister(1)); // low
1417 __ mulhw(i.OutputRegister(1), i.InputRegister(0),
1418 i.InputRegister(1)); // high
1419 }
1420 break;
1421 case kPPC_MulHighS64:
1422 __ mulhd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1423 i.OutputRCBit());
1424 break;
1425 case kPPC_MulHighU64:
1426 __ mulhdu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1427 i.OutputRCBit());
1428 break;
1429 case kPPC_MulHigh32:
1430 __ mulhw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1431 i.OutputRCBit());
1432 // High 32 bits are undefined and need to be cleared.
1433 CleanUInt32(i.OutputRegister());
1434 break;
1435 case kPPC_MulHighU32:
1436 __ mulhwu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1437 i.OutputRCBit());
1438 // High 32 bits are undefined and need to be cleared.
1439 CleanUInt32(i.OutputRegister());
1440 break;
1441 case kPPC_MulDouble:
1443 break;
1444 case kPPC_Div32:
1445 __ divw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1446 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1447 break;
1448 case kPPC_Div64:
1449 __ divd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1450 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1451 break;
1452 case kPPC_DivU32:
1453 __ divwu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1454 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1455 break;
1456 case kPPC_DivU64:
1457 __ divdu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1458 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1459 break;
1460 case kPPC_DivDouble:
1462 break;
1463 case kPPC_Mod32:
1464 if (CpuFeatures::IsSupported(PPC_9_PLUS)) {
1465 __ modsw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1466 } else {
1467 ASSEMBLE_MODULO(divw, mullw);
1468 }
1469 break;
1470 case kPPC_Mod64:
1471 if (CpuFeatures::IsSupported(PPC_9_PLUS)) {
1472 __ modsd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1473 } else {
1474 ASSEMBLE_MODULO(divd, mulld);
1475 }
1476 break;
1477 case kPPC_ModU32:
1478 if (CpuFeatures::IsSupported(PPC_9_PLUS)) {
1479 __ moduw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1480 } else {
1481 ASSEMBLE_MODULO(divwu, mullw);
1482 }
1483 break;
1484 case kPPC_ModU64:
1485 if (CpuFeatures::IsSupported(PPC_9_PLUS)) {
1486 __ modud(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1487 } else {
1488 ASSEMBLE_MODULO(divdu, mulld);
1489 }
1490 break;
1491 case kPPC_ModDouble:
1492 // TODO(bmeurer): We should really get rid of this special instruction,
1493 // and generate a CallAddress instruction instead.
1495 break;
1496 case kIeee754Float64Acos:
1498 break;
1499 case kIeee754Float64Acosh:
1500 ASSEMBLE_IEEE754_UNOP(acosh);
1501 break;
1502 case kIeee754Float64Asin:
1504 break;
1505 case kIeee754Float64Asinh:
1506 ASSEMBLE_IEEE754_UNOP(asinh);
1507 break;
1508 case kIeee754Float64Atan:
1510 break;
1511 case kIeee754Float64Atan2:
1513 break;
1514 case kIeee754Float64Atanh:
1515 ASSEMBLE_IEEE754_UNOP(atanh);
1516 break;
1517 case kIeee754Float64Tan:
1519 break;
1520 case kIeee754Float64Tanh:
1522 break;
1523 case kIeee754Float64Cbrt:
1525 break;
1526 case kIeee754Float64Sin:
1528 break;
1529 case kIeee754Float64Sinh:
1531 break;
1532 case kIeee754Float64Cos:
1534 break;
1535 case kIeee754Float64Cosh:
1537 break;
1538 case kIeee754Float64Exp:
1540 break;
1541 case kIeee754Float64Expm1:
1542 ASSEMBLE_IEEE754_UNOP(expm1);
1543 break;
1544 case kIeee754Float64Log:
1546 break;
1547 case kIeee754Float64Log1p:
1548 ASSEMBLE_IEEE754_UNOP(log1p);
1549 break;
1550 case kIeee754Float64Log2:
1552 break;
1553 case kIeee754Float64Log10:
1554 ASSEMBLE_IEEE754_UNOP(log10);
1555 break;
1556 case kIeee754Float64Pow:
1558 break;
1559 case kPPC_Neg:
1560 __ neg(i.OutputRegister(), i.InputRegister(0), LeaveOE, i.OutputRCBit());
1561 break;
1562 case kPPC_MaxDouble:
1563 __ MaxF64(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1564 i.InputDoubleRegister(1), kScratchDoubleReg);
1565 break;
1566 case kPPC_MinDouble:
1567 __ MinF64(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1568 i.InputDoubleRegister(1), kScratchDoubleReg);
1569 break;
1570 case kPPC_AbsDouble:
1571 ASSEMBLE_FLOAT_UNOP_RC(fabs, 0);
1572 break;
1573 case kPPC_SqrtDouble:
1575 break;
1576 case kPPC_FloorDouble:
1578 break;
1579 case kPPC_CeilDouble:
1581 break;
1582 case kPPC_TruncateDouble:
1584 break;
1585 case kPPC_RoundDouble:
1587 break;
1588 case kPPC_NegDouble:
1589 ASSEMBLE_FLOAT_UNOP_RC(fneg, 0);
1590 break;
1591 case kPPC_Cntlz32:
1592 __ cntlzw(i.OutputRegister(), i.InputRegister(0));
1593 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1594 break;
1595 case kPPC_Cntlz64:
1596 __ cntlzd(i.OutputRegister(), i.InputRegister(0));
1597 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1598 break;
1599 case kPPC_Popcnt32:
1600 __ Popcnt32(i.OutputRegister(), i.InputRegister(0));
1601 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1602 break;
1603 case kPPC_Popcnt64:
1604 __ Popcnt64(i.OutputRegister(), i.InputRegister(0));
1605 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1606 break;
1607 case kPPC_Cmp32:
1608 ASSEMBLE_COMPARE(cmpw, cmplw);
1609 break;
1610 case kPPC_Cmp64:
1611 ASSEMBLE_COMPARE(cmp, cmpl);
1612 break;
1613 case kPPC_CmpDouble:
1615 break;
1616 case kPPC_Tst32:
1617 if (HasRegisterInput(instr, 1)) {
1618 __ and_(r0, i.InputRegister(0), i.InputRegister(1), i.OutputRCBit());
1619 } else {
1620 __ andi(r0, i.InputRegister(0), i.InputImmediate(1));
1621 }
1622 __ extsw(r0, r0, i.OutputRCBit());
1623 DCHECK_EQ(SetRC, i.OutputRCBit());
1624 break;
1625 case kPPC_Tst64:
1626 if (HasRegisterInput(instr, 1)) {
1627 __ and_(r0, i.InputRegister(0), i.InputRegister(1), i.OutputRCBit());
1628 } else {
1629 __ andi(r0, i.InputRegister(0), i.InputImmediate(1));
1630 }
1631 DCHECK_EQ(SetRC, i.OutputRCBit());
1632 break;
1633 case kPPC_Float64SilenceNaN: {
1634 DoubleRegister value = i.InputDoubleRegister(0);
1635 DoubleRegister result = i.OutputDoubleRegister();
1636 __ CanonicalizeNaN(result, value);
1637 break;
1638 }
1639 case kPPC_Push: {
1640 int stack_decrement = i.InputInt32(0);
1641 int slots = stack_decrement / kSystemPointerSize;
1642 LocationOperand* op = LocationOperand::cast(instr->InputAt(1));
1643 MachineRepresentation rep = op->representation();
1644 int pushed_slots = ElementSizeInPointers(rep);
1645 // Slot-sized arguments are never padded but there may be a gap if
1646 // the slot allocator reclaimed other padding slots. Adjust the stack
1647 // here to skip any gap.
1648 __ AllocateStackSpace((slots - pushed_slots) * kSystemPointerSize);
1649 switch (rep) {
1651 __ StoreF32WithUpdate(i.InputDoubleRegister(1),
1652 MemOperand(sp, -kSystemPointerSize), r0);
1653 break;
1655 __ StoreF64WithUpdate(i.InputDoubleRegister(1),
1656 MemOperand(sp, -kDoubleSize), r0);
1657 break;
1659 __ addi(sp, sp, Operand(-kSimd128Size));
1660 __ StoreSimd128(i.InputSimd128Register(1), MemOperand(r0, sp),
1661 kScratchReg);
1662 break;
1663 default:
1664 __ StoreU64WithUpdate(i.InputRegister(1),
1665 MemOperand(sp, -kSystemPointerSize), r0);
1666 break;
1667 }
1669 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1670 break;
1671 }
1672 case kPPC_PushFrame: {
1673 int num_slots = i.InputInt32(1);
1674 if (instr->InputAt(0)->IsFPRegister()) {
1675 LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
1676 if (op->representation() == MachineRepresentation::kFloat64) {
1677 __ StoreF64WithUpdate(i.InputDoubleRegister(0),
1678 MemOperand(sp, -num_slots * kSystemPointerSize),
1679 r0);
1680 } else {
1681 DCHECK_EQ(MachineRepresentation::kFloat32, op->representation());
1682 __ StoreF32WithUpdate(i.InputDoubleRegister(0),
1683 MemOperand(sp, -num_slots * kSystemPointerSize),
1684 r0);
1685 }
1686 } else {
1687 __ StoreU64WithUpdate(i.InputRegister(0),
1688 MemOperand(sp, -num_slots * kSystemPointerSize),
1689 r0);
1690 }
1691 break;
1692 }
1693 case kPPC_StoreToStackSlot: {
1694 int slot = i.InputInt32(1);
1695 if (instr->InputAt(0)->IsFPRegister()) {
1696 LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
1697 if (op->representation() == MachineRepresentation::kFloat64) {
1698 __ StoreF64(i.InputDoubleRegister(0),
1699 MemOperand(sp, slot * kSystemPointerSize), r0);
1700 } else if (op->representation() == MachineRepresentation::kFloat32) {
1701 __ StoreF32(i.InputDoubleRegister(0),
1702 MemOperand(sp, slot * kSystemPointerSize), r0);
1703 } else {
1704 DCHECK_EQ(MachineRepresentation::kSimd128, op->representation());
1705 __ StoreSimd128(i.InputSimd128Register(0),
1706 MemOperand(sp, slot * kSystemPointerSize),
1707 kScratchReg);
1708 }
1709 } else {
1710 __ StoreU64(i.InputRegister(0),
1711 MemOperand(sp, slot * kSystemPointerSize), r0);
1712 }
1713 break;
1714 }
1715 case kPPC_ExtendSignWord8:
1716 __ extsb(i.OutputRegister(), i.InputRegister(0));
1717 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1718 break;
1719 case kPPC_ExtendSignWord16:
1720 __ extsh(i.OutputRegister(), i.InputRegister(0));
1721 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1722 break;
1723 case kPPC_ExtendSignWord32:
1724 __ extsw(i.OutputRegister(), i.InputRegister(0));
1725 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1726 break;
1727 case kPPC_Uint32ToUint64:
1728 // Zero extend
1729 __ clrldi(i.OutputRegister(), i.InputRegister(0), Operand(32));
1730 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1731 break;
1732 case kPPC_Int64ToInt32:
1733 __ extsw(i.OutputRegister(), i.InputRegister(0));
1734 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1735 break;
1736 case kPPC_Int64ToFloat32:
1737 __ ConvertInt64ToFloat(i.InputRegister(0), i.OutputDoubleRegister());
1738 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1739 break;
1740 case kPPC_Int64ToDouble:
1741 __ ConvertInt64ToDouble(i.InputRegister(0), i.OutputDoubleRegister());
1742 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1743 break;
1744 case kPPC_Uint64ToFloat32:
1745 __ ConvertUnsignedInt64ToFloat(i.InputRegister(0),
1746 i.OutputDoubleRegister());
1747 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1748 break;
1749 case kPPC_Uint64ToDouble:
1750 __ ConvertUnsignedInt64ToDouble(i.InputRegister(0),
1751 i.OutputDoubleRegister());
1752 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1753 break;
1754 case kPPC_Int32ToFloat32:
1755 __ ConvertIntToFloat(i.InputRegister(0), i.OutputDoubleRegister());
1756 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1757 break;
1758 case kPPC_Int32ToDouble:
1759 __ ConvertIntToDouble(i.InputRegister(0), i.OutputDoubleRegister());
1760 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1761 break;
1762 case kPPC_Uint32ToFloat32:
1763 __ ConvertUnsignedIntToFloat(i.InputRegister(0),
1764 i.OutputDoubleRegister());
1765 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1766 break;
1767 case kPPC_Uint32ToDouble:
1768 __ ConvertUnsignedIntToDouble(i.InputRegister(0),
1769 i.OutputDoubleRegister());
1770 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1771 break;
1772 case kPPC_Float32ToInt32: {
1773 bool set_overflow_to_min_i32 = MiscField::decode(instr->opcode());
1774 if (set_overflow_to_min_i32) {
1775 __ mtfsb0(VXCVI); // clear FPSCR:VXCVI bit
1776 }
1777 __ fctiwz(kScratchDoubleReg, i.InputDoubleRegister(0));
1778 __ MovDoubleLowToInt(i.OutputRegister(), kScratchDoubleReg);
1779 if (set_overflow_to_min_i32) {
1780 // Avoid INT32_MAX as an overflow indicator and use INT32_MIN instead,
1781 // because INT32_MIN allows easier out-of-bounds detection.
1782 CRegister cr = cr0;
1784 cr, static_cast<CRBit>(VXCVI % CRWIDTH));
1785 __ mcrfs(cr, VXCVI); // extract FPSCR field containing VXCVI into cr0
1786 __ li(kScratchReg, Operand(1));
1787 __ ShiftLeftU64(kScratchReg, kScratchReg,
1788 Operand(31)); // generate INT32_MIN.
1789 __ isel(i.OutputRegister(0), kScratchReg, i.OutputRegister(0), crbit);
1790 }
1791 break;
1792 }
1793 case kPPC_Float32ToUint32: {
1794 bool set_overflow_to_min_u32 = MiscField::decode(instr->opcode());
1795 if (set_overflow_to_min_u32) {
1796 __ mtfsb0(VXCVI); // clear FPSCR:VXCVI bit
1797 }
1798 __ fctiwuz(kScratchDoubleReg, i.InputDoubleRegister(0));
1799 __ MovDoubleLowToInt(i.OutputRegister(), kScratchDoubleReg);
1800 if (set_overflow_to_min_u32) {
1801 // Avoid UINT32_MAX as an overflow indicator and use 0 instead,
1802 // because 0 allows easier out-of-bounds detection.
1803 CRegister cr = cr0;
1805 cr, static_cast<CRBit>(VXCVI % CRWIDTH));
1806 __ mcrfs(cr, VXCVI); // extract FPSCR field containing VXCVI into cr0
1808 __ isel(i.OutputRegister(0), kScratchReg, i.OutputRegister(0), crbit);
1809 }
1810 break;
1811 }
1812#define DOUBLE_TO_INT32(op) \
1813 bool check_conversion = i.OutputCount() > 1; \
1814 CRegister cr = cr0; \
1815 FPSCRBit fps_bit = VXCVI; \
1816 int cr_bit = v8::internal::Assembler::encode_crbit( \
1817 cr, static_cast<CRBit>(fps_bit % CRWIDTH)); \
1818 __ mtfsb0(fps_bit); /* clear FPSCR:VXCVI bit */ \
1819 __ op(kScratchDoubleReg, i.InputDoubleRegister(0)); \
1820 __ MovDoubleLowToInt(i.OutputRegister(0), kScratchDoubleReg); \
1821 __ mcrfs(cr, VXCVI); /* extract FPSCR field containing VXCVI into cr0 */ \
1822 if (check_conversion) { \
1823 __ li(i.OutputRegister(1), Operand(1)); \
1824 __ isel(i.OutputRegister(1), r0, i.OutputRegister(1), cr_bit); \
1825 } else { \
1826 __ isel(i.OutputRegister(0), r0, i.OutputRegister(0), cr_bit); \
1827 }
1828 case kPPC_DoubleToInt32: {
1829 DOUBLE_TO_INT32(fctiwz)
1830 break;
1831 }
1832 case kPPC_DoubleToUint32: {
1833 DOUBLE_TO_INT32(fctiwuz)
1834 break;
1835 }
1836#undef DOUBLE_TO_INT32
1837 case kPPC_DoubleToInt64: {
1838 bool check_conversion = i.OutputCount() > 1;
1839 __ mtfsb0(VXCVI); // clear FPSCR:VXCVI bit
1840 __ ConvertDoubleToInt64(i.InputDoubleRegister(0),
1841 i.OutputRegister(0), kScratchDoubleReg);
1842 CRegister cr = cr0;
1844 cr, static_cast<CRBit>(VXCVI % CRWIDTH));
1845 __ mcrfs(cr, VXCVI); // extract FPSCR field containing VXCVI into cr0
1846 // Handle conversion failures (such as overflow).
1847 if (check_conversion) {
1848 __ li(i.OutputRegister(1), Operand(1));
1849 __ isel(i.OutputRegister(1), r0, i.OutputRegister(1), crbit);
1850 } else {
1851 __ isel(i.OutputRegister(0), r0, i.OutputRegister(0), crbit);
1852 }
1853 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1854 break;
1855 }
1856 case kPPC_DoubleToUint64: {
1857 bool check_conversion = (i.OutputCount() > 1);
1858 if (check_conversion) {
1859 __ mtfsb0(VXCVI); // clear FPSCR:VXCVI bit
1860 }
1861 __ ConvertDoubleToUnsignedInt64(i.InputDoubleRegister(0),
1862 i.OutputRegister(0), kScratchDoubleReg);
1863 if (check_conversion) {
1864 // Set 2nd output to zero if conversion fails.
1865 CRegister cr = cr0;
1867 cr, static_cast<CRBit>(VXCVI % CRWIDTH));
1868 __ mcrfs(cr, VXCVI); // extract FPSCR field containing VXCVI into cr0
1869 __ li(i.OutputRegister(1), Operand(1));
1870 __ isel(i.OutputRegister(1), r0, i.OutputRegister(1), crbit);
1871 }
1872 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1873 break;
1874 }
1875 case kPPC_DoubleToFloat32:
1876 ASSEMBLE_FLOAT_UNOP_RC(frsp, 0);
1877 break;
1878 case kPPC_Float32ToDouble:
1879 // Nothing to do.
1880 __ Move(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1881 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1882 break;
1883 case kPPC_DoubleExtractLowWord32:
1884 __ MovDoubleLowToInt(i.OutputRegister(), i.InputDoubleRegister(0));
1885 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1886 break;
1887 case kPPC_DoubleExtractHighWord32:
1888 __ MovDoubleHighToInt(i.OutputRegister(), i.InputDoubleRegister(0));
1889 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1890 break;
1891 case kPPC_DoubleFromWord32Pair:
1892 __ clrldi(kScratchReg, i.InputRegister(1), Operand(32));
1893 __ ShiftLeftU64(i.TempRegister(0), i.InputRegister(0), Operand(32));
1894 __ OrU64(i.TempRegister(0), i.TempRegister(0), kScratchReg);
1895 __ MovInt64ToDouble(i.OutputDoubleRegister(), i.TempRegister(0));
1896 break;
1897 case kPPC_DoubleInsertLowWord32:
1898 __ InsertDoubleLow(i.OutputDoubleRegister(), i.InputRegister(1), r0);
1899 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1900 break;
1901 case kPPC_DoubleInsertHighWord32:
1902 __ InsertDoubleHigh(i.OutputDoubleRegister(), i.InputRegister(1), r0);
1903 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1904 break;
1905 case kPPC_DoubleConstruct:
1906 __ MovInt64ComponentsToDouble(i.OutputDoubleRegister(),
1907 i.InputRegister(0), i.InputRegister(1), r0);
1908 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1909 break;
1910 case kPPC_BitcastFloat32ToInt32:
1911 __ MovFloatToInt(i.OutputRegister(), i.InputDoubleRegister(0),
1913 break;
1914 case kPPC_BitcastInt32ToFloat32:
1915 __ MovIntToFloat(i.OutputDoubleRegister(), i.InputRegister(0), ip);
1916 break;
1917 case kPPC_BitcastDoubleToInt64:
1918 __ MovDoubleToInt64(i.OutputRegister(), i.InputDoubleRegister(0));
1919 break;
1920 case kPPC_BitcastInt64ToDouble:
1921 __ MovInt64ToDouble(i.OutputDoubleRegister(), i.InputRegister(0));
1922 break;
1923 case kPPC_LoadWordU8:
1924 ASSEMBLE_LOAD_INTEGER(lbz, plbz, lbzx, false);
1925 break;
1926 case kPPC_LoadWordS8:
1927 ASSEMBLE_LOAD_INTEGER(lbz, plbz, lbzx, false);
1928 __ extsb(i.OutputRegister(), i.OutputRegister());
1929 break;
1930 case kPPC_LoadWordU16:
1931 ASSEMBLE_LOAD_INTEGER(lhz, plhz, lhzx, false);
1932 break;
1933 case kPPC_LoadWordS16:
1934 ASSEMBLE_LOAD_INTEGER(lha, plha, lhax, false);
1935 break;
1936 case kPPC_LoadWordU32:
1937 ASSEMBLE_LOAD_INTEGER(lwz, plwz, lwzx, false);
1938 break;
1939 case kPPC_LoadWordS32:
1940 ASSEMBLE_LOAD_INTEGER(lwa, plwa, lwax, true);
1941 break;
1942 case kPPC_LoadWord64:
1943 ASSEMBLE_LOAD_INTEGER(ld, pld, ldx, true);
1944 break;
1945 case kPPC_LoadFloat32:
1946 ASSEMBLE_LOAD_FLOAT(lfs, plfs, lfsx);
1947 break;
1948 case kPPC_LoadDouble:
1949 ASSEMBLE_LOAD_FLOAT(lfd, plfd, lfdx);
1950 break;
1951 case kPPC_LoadSimd128: {
1952 Simd128Register result = i.OutputSimd128Register();
1953 AddressingMode mode = kMode_None;
1954 MemOperand operand = i.MemoryOperand(&mode);
1955 bool is_atomic = i.InputInt32(2);
1956 DCHECK_EQ(mode, kMode_MRR);
1957 __ LoadSimd128(result, operand, kScratchReg);
1958 if (is_atomic) __ lwsync();
1959 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1960 break;
1961 }
1962 case kPPC_LoadReverseSimd128RR: {
1963 __ xxbrq(i.OutputSimd128Register(), i.InputSimd128Register(0));
1964 break;
1965 }
1966 case kPPC_StoreWord8:
1967 ASSEMBLE_STORE_INTEGER(stb, pstb, stbx, false);
1968 break;
1969 case kPPC_StoreWord16:
1970 ASSEMBLE_STORE_INTEGER(sth, psth, sthx, false);
1971 break;
1972 case kPPC_StoreWord32:
1973 ASSEMBLE_STORE_INTEGER(stw, pstw, stwx, false);
1974 break;
1975 case kPPC_StoreWord64:
1976 ASSEMBLE_STORE_INTEGER(std, pstd, stdx, true);
1977 break;
1978 case kPPC_StoreFloat32:
1979 ASSEMBLE_STORE_FLOAT(stfs, pstfs, stfsx);
1980 break;
1981 case kPPC_StoreDouble:
1982 ASSEMBLE_STORE_FLOAT(stfd, pstfd, stfdx);
1983 break;
1984 case kPPC_StoreSimd128: {
1985 size_t index = 0;
1986 AddressingMode mode = kMode_None;
1987 MemOperand operand = i.MemoryOperand(&mode, &index);
1988 Simd128Register value = i.InputSimd128Register(index);
1989 bool is_atomic = i.InputInt32(3);
1990 if (is_atomic) __ lwsync();
1991 DCHECK_EQ(mode, kMode_MRR);
1992 __ StoreSimd128(value, operand, kScratchReg);
1993 if (is_atomic) __ sync();
1994 DCHECK_EQ(LeaveRC, i.OutputRCBit());
1995 break;
1996 }
1997 case kAtomicLoadInt8:
1998 case kAtomicLoadInt16:
1999 UNREACHABLE();
2000 case kAtomicExchangeInt8:
2001 __ AtomicExchange<int8_t>(
2002 MemOperand(i.InputRegister(0), i.InputRegister(1)),
2003 i.InputRegister(2), i.OutputRegister());
2004 break;
2005 case kPPC_AtomicExchangeUint8:
2006 __ AtomicExchange<uint8_t>(
2007 MemOperand(i.InputRegister(0), i.InputRegister(1)),
2008 i.InputRegister(2), i.OutputRegister());
2009 break;
2010 case kAtomicExchangeInt16: {
2011 ASSEMBLE_ATOMIC_EXCHANGE(int16_t, ByteReverseU16);
2012 __ extsh(i.OutputRegister(), i.OutputRegister());
2013 break;
2014 }
2015 case kPPC_AtomicExchangeUint16: {
2016 ASSEMBLE_ATOMIC_EXCHANGE(uint16_t, ByteReverseU16);
2017 break;
2018 }
2019 case kPPC_AtomicExchangeWord32: {
2020 ASSEMBLE_ATOMIC_EXCHANGE(uint32_t, ByteReverseU32);
2021 break;
2022 }
2023 case kPPC_AtomicExchangeWord64: {
2024 ASSEMBLE_ATOMIC_EXCHANGE(uint64_t, ByteReverseU64);
2025 break;
2026 }
2027 case kAtomicCompareExchangeInt8:
2028 __ AtomicCompareExchange<int8_t>(
2029 MemOperand(i.InputRegister(0), i.InputRegister(1)),
2030 i.InputRegister(2), i.InputRegister(3), i.OutputRegister(),
2031 kScratchReg);
2032 break;
2033 case kPPC_AtomicCompareExchangeUint8:
2034 __ AtomicCompareExchange<uint8_t>(
2035 MemOperand(i.InputRegister(0), i.InputRegister(1)),
2036 i.InputRegister(2), i.InputRegister(3), i.OutputRegister(),
2037 kScratchReg);
2038 break;
2039 case kAtomicCompareExchangeInt16: {
2040 ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(int16_t, ByteReverseU16);
2041 __ extsh(i.OutputRegister(), i.OutputRegister());
2042 break;
2043 }
2044 case kPPC_AtomicCompareExchangeUint16: {
2045 ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(uint16_t, ByteReverseU16);
2046 break;
2047 }
2048 case kPPC_AtomicCompareExchangeWord32: {
2049 ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(uint32_t, ByteReverseU32);
2050 break;
2051 }
2052 case kPPC_AtomicCompareExchangeWord64: {
2053 ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(uint64_t, ByteReverseU64);
2054 } break;
2055
2056#define ATOMIC_BINOP_CASE(op, inst) \
2057 case kPPC_Atomic##op##Int8: \
2058 ASSEMBLE_ATOMIC_BINOP_BYTE(inst, int8_t); \
2059 __ extsb(i.OutputRegister(), i.OutputRegister()); \
2060 break; \
2061 case kPPC_Atomic##op##Uint8: \
2062 ASSEMBLE_ATOMIC_BINOP_BYTE(inst, uint8_t); \
2063 break; \
2064 case kPPC_Atomic##op##Int16: \
2065 ASSEMBLE_ATOMIC_BINOP(inst, int16_t, ByteReverseU16, r0); \
2066 __ extsh(i.OutputRegister(), i.OutputRegister()); \
2067 break; \
2068 case kPPC_Atomic##op##Uint16: \
2069 ASSEMBLE_ATOMIC_BINOP(inst, uint16_t, ByteReverseU16, r0); \
2070 break; \
2071 case kPPC_Atomic##op##Int32: \
2072 ASSEMBLE_ATOMIC_BINOP(inst, int32_t, ByteReverseU32, r0); \
2073 __ extsw(i.OutputRegister(), i.OutputRegister()); \
2074 break; \
2075 case kPPC_Atomic##op##Uint32: \
2076 ASSEMBLE_ATOMIC_BINOP(inst, uint32_t, ByteReverseU32, r0); \
2077 break; \
2078 case kPPC_Atomic##op##Int64: \
2079 case kPPC_Atomic##op##Uint64: \
2080 ASSEMBLE_ATOMIC_BINOP(inst, uint64_t, ByteReverseU64, r0); \
2081 break;
2082 ATOMIC_BINOP_CASE(Add, add)
2083 ATOMIC_BINOP_CASE(Sub, sub)
2084 ATOMIC_BINOP_CASE(And, and_)
2085 ATOMIC_BINOP_CASE(Or, orx)
2086 ATOMIC_BINOP_CASE(Xor, xor_)
2087#undef ATOMIC_BINOP_CASE
2088
2089 case kPPC_ByteRev32: {
2090 Register input = i.InputRegister(0);
2091 Register output = i.OutputRegister();
2092 Register temp1 = r0;
2093 if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
2094 __ brw(output, input);
2095 __ extsw(output, output);
2096 break;
2097 }
2098 __ rotlwi(temp1, input, 8);
2099 __ rlwimi(temp1, input, 24, 0, 7);
2100 __ rlwimi(temp1, input, 24, 16, 23);
2101 __ extsw(output, temp1);
2102 break;
2103 }
2104 case kPPC_LoadByteRev32: {
2106 break;
2107 }
2108 case kPPC_StoreByteRev32: {
2110 break;
2111 }
2112 case kPPC_ByteRev64: {
2113 Register input = i.InputRegister(0);
2114 Register output = i.OutputRegister();
2115 Register temp1 = r0;
2116 Register temp2 = kScratchReg;
2117 Register temp3 = i.TempRegister(0);
2118 if (CpuFeatures::IsSupported(PPC_10_PLUS)) {
2119 __ brd(output, input);
2120 break;
2121 }
2122 __ rldicl(temp1, input, 32, 32);
2123 __ rotlwi(temp2, input, 8);
2124 __ rlwimi(temp2, input, 24, 0, 7);
2125 __ rotlwi(temp3, temp1, 8);
2126 __ rlwimi(temp2, input, 24, 16, 23);
2127 __ rlwimi(temp3, temp1, 24, 0, 7);
2128 __ rlwimi(temp3, temp1, 24, 16, 23);
2129 __ rldicr(temp2, temp2, 32, 31);
2130 __ orx(output, temp2, temp3);
2131 break;
2132 }
2133 case kPPC_LoadByteRev64: {
2135 break;
2136 }
2137 case kPPC_StoreByteRev64: {
2139 break;
2140 }
2141// Simd Support.
2142#define SIMD_BINOP_LIST(V) \
2143 V(F64x2Add) \
2144 V(F64x2Sub) \
2145 V(F64x2Mul) \
2146 V(F64x2Div) \
2147 V(F64x2Eq) \
2148 V(F64x2Lt) \
2149 V(F64x2Le) \
2150 V(F32x4Add) \
2151 V(F32x4Sub) \
2152 V(F32x4Mul) \
2153 V(F32x4Div) \
2154 V(F32x4Min) \
2155 V(F32x4Max) \
2156 V(F32x4Eq) \
2157 V(F32x4Lt) \
2158 V(F32x4Le) \
2159 V(I64x2Add) \
2160 V(I64x2Sub) \
2161 V(I64x2Eq) \
2162 V(I64x2GtS) \
2163 V(I32x4Add) \
2164 V(I32x4Sub) \
2165 V(I32x4Mul) \
2166 V(I32x4MinS) \
2167 V(I32x4MinU) \
2168 V(I32x4MaxS) \
2169 V(I32x4MaxU) \
2170 V(I32x4Eq) \
2171 V(I32x4GtS) \
2172 V(I32x4GtU) \
2173 V(I32x4DotI16x8S) \
2174 V(I16x8Add) \
2175 V(I16x8Sub) \
2176 V(I16x8Mul) \
2177 V(I16x8MinS) \
2178 V(I16x8MinU) \
2179 V(I16x8MaxS) \
2180 V(I16x8MaxU) \
2181 V(I16x8Eq) \
2182 V(I16x8GtS) \
2183 V(I16x8GtU) \
2184 V(I16x8AddSatS) \
2185 V(I16x8SubSatS) \
2186 V(I16x8AddSatU) \
2187 V(I16x8SubSatU) \
2188 V(I16x8SConvertI32x4) \
2189 V(I16x8UConvertI32x4) \
2190 V(I16x8RoundingAverageU) \
2191 V(I16x8Q15MulRSatS) \
2192 V(I8x16Add) \
2193 V(I8x16Sub) \
2194 V(I8x16MinS) \
2195 V(I8x16MinU) \
2196 V(I8x16MaxS) \
2197 V(I8x16MaxU) \
2198 V(I8x16Eq) \
2199 V(I8x16GtS) \
2200 V(I8x16GtU) \
2201 V(I8x16AddSatS) \
2202 V(I8x16SubSatS) \
2203 V(I8x16AddSatU) \
2204 V(I8x16SubSatU) \
2205 V(I8x16SConvertI16x8) \
2206 V(I8x16UConvertI16x8) \
2207 V(I8x16RoundingAverageU) \
2208 V(S128And) \
2209 V(S128Or) \
2210 V(S128Xor) \
2211 V(S128AndNot)
2212
2213#define EMIT_SIMD_BINOP(name) \
2214 case kPPC_##name: { \
2215 __ name(i.OutputSimd128Register(), i.InputSimd128Register(0), \
2216 i.InputSimd128Register(1)); \
2217 break; \
2218 }
2220#undef EMIT_SIMD_BINOP
2221#undef SIMD_BINOP_LIST
2222
2223#define SIMD_BINOP_WITH_SCRATCH_LIST(V) \
2224 V(F64x2Ne) \
2225 V(F64x2Pmin) \
2226 V(F64x2Pmax) \
2227 V(F32x4Ne) \
2228 V(F32x4Pmin) \
2229 V(F32x4Pmax) \
2230 V(I64x2Ne) \
2231 V(I64x2GeS) \
2232 V(I64x2ExtMulLowI32x4S) \
2233 V(I64x2ExtMulHighI32x4S) \
2234 V(I64x2ExtMulLowI32x4U) \
2235 V(I64x2ExtMulHighI32x4U) \
2236 V(I32x4Ne) \
2237 V(I32x4GeS) \
2238 V(I32x4GeU) \
2239 V(I32x4ExtMulLowI16x8S) \
2240 V(I32x4ExtMulHighI16x8S) \
2241 V(I32x4ExtMulLowI16x8U) \
2242 V(I32x4ExtMulHighI16x8U) \
2243 V(I16x8Ne) \
2244 V(I16x8GeS) \
2245 V(I16x8GeU) \
2246 V(I16x8ExtMulLowI8x16S) \
2247 V(I16x8ExtMulHighI8x16S) \
2248 V(I16x8ExtMulLowI8x16U) \
2249 V(I16x8ExtMulHighI8x16U) \
2250 V(I16x8DotI8x16S) \
2251 V(I8x16Ne) \
2252 V(I8x16GeS) \
2253 V(I8x16GeU) \
2254 V(I8x16Swizzle)
2255
2256#define EMIT_SIMD_BINOP_WITH_SCRATCH(name) \
2257 case kPPC_##name: { \
2258 __ name(i.OutputSimd128Register(), i.InputSimd128Register(0), \
2259 i.InputSimd128Register(1), kScratchSimd128Reg); \
2260 break; \
2261 }
2263#undef EMIT_SIMD_BINOP_WITH_SCRATCH
2264#undef SIMD_BINOP_WITH_SCRATCH_LIST
2265
2266#define SIMD_SHIFT_LIST(V) \
2267 V(I64x2Shl) \
2268 V(I64x2ShrS) \
2269 V(I64x2ShrU) \
2270 V(I32x4Shl) \
2271 V(I32x4ShrS) \
2272 V(I32x4ShrU) \
2273 V(I16x8Shl) \
2274 V(I16x8ShrS) \
2275 V(I16x8ShrU) \
2276 V(I8x16Shl) \
2277 V(I8x16ShrS) \
2278 V(I8x16ShrU)
2279
2280#define EMIT_SIMD_SHIFT(name) \
2281 case kPPC_##name: { \
2282 __ name(i.OutputSimd128Register(), i.InputSimd128Register(0), \
2283 i.InputRegister(1), kScratchSimd128Reg); \
2284 break; \
2285 }
2287#undef EMIT_SIMD_SHIFT
2288#undef SIMD_SHIFT_LIST
2289
2290#define SIMD_UNOP_LIST(V) \
2291 V(F64x2Abs) \
2292 V(F64x2Neg) \
2293 V(F64x2Sqrt) \
2294 V(F64x2Ceil) \
2295 V(F64x2Floor) \
2296 V(F64x2Trunc) \
2297 V(F64x2PromoteLowF32x4) \
2298 V(F32x4Abs) \
2299 V(F32x4Neg) \
2300 V(F32x4SConvertI32x4) \
2301 V(F32x4UConvertI32x4) \
2302 V(I64x2Neg) \
2303 V(I32x4Neg) \
2304 V(F32x4Sqrt) \
2305 V(F32x4Ceil) \
2306 V(F32x4Floor) \
2307 V(F32x4Trunc) \
2308 V(F64x2ConvertLowI32x4S) \
2309 V(I64x2SConvertI32x4Low) \
2310 V(I64x2SConvertI32x4High) \
2311 V(I32x4SConvertI16x8Low) \
2312 V(I32x4SConvertI16x8High) \
2313 V(I32x4UConvertF32x4) \
2314 V(I16x8SConvertI8x16Low) \
2315 V(I16x8SConvertI8x16High) \
2316 V(I8x16Popcnt) \
2317 V(S128Not)
2318
2319#define EMIT_SIMD_UNOP(name) \
2320 case kPPC_##name: { \
2321 __ name(i.OutputSimd128Register(), i.InputSimd128Register(0)); \
2322 break; \
2323 }
2325#undef EMIT_SIMD_UNOP
2326#undef SIMD_UNOP_LIST
2327
2328#define SIMD_UNOP_WITH_SCRATCH_LIST(V) \
2329 V(F32x4DemoteF64x2Zero) \
2330 V(I64x2Abs) \
2331 V(I32x4Abs) \
2332 V(I32x4SConvertF32x4) \
2333 V(I32x4TruncSatF64x2SZero) \
2334 V(I32x4TruncSatF64x2UZero) \
2335 V(I16x8Abs) \
2336 V(I16x8Neg) \
2337 V(I8x16Abs) \
2338 V(I8x16Neg)
2339
2340#define EMIT_SIMD_UNOP_WITH_SCRATCH(name) \
2341 case kPPC_##name: { \
2342 __ name(i.OutputSimd128Register(), i.InputSimd128Register(0), \
2343 kScratchSimd128Reg); \
2344 break; \
2345 }
2347#undef EMIT_SIMD_UNOP_WITH_SCRATCH
2348#undef SIMD_UNOP_WITH_SCRATCH_LIST
2349
2350#define SIMD_ALL_TRUE_LIST(V) \
2351 V(I64x2AllTrue) \
2352 V(I32x4AllTrue) \
2353 V(I16x8AllTrue) \
2354 V(I8x16AllTrue)
2355#define EMIT_SIMD_ALL_TRUE(name) \
2356 case kPPC_##name: { \
2357 __ name(i.OutputRegister(), i.InputSimd128Register(0), r0, ip, \
2358 kScratchSimd128Reg); \
2359 break; \
2360 }
2362#undef EMIT_SIMD_ALL_TRUE
2363#undef SIMD_ALL_TRUE_LIST
2364
2365#define SIMD_QFM_LIST(V) \
2366 V(F64x2Qfma) \
2367 V(F64x2Qfms) \
2368 V(F32x4Qfma) \
2369 V(F32x4Qfms)
2370#define EMIT_SIMD_QFM(name) \
2371 case kPPC_##name: { \
2372 __ name(i.OutputSimd128Register(), i.InputSimd128Register(0), \
2373 i.InputSimd128Register(1), i.InputSimd128Register(2), \
2374 kScratchSimd128Reg); \
2375 break; \
2376 }
2378#undef EMIT_SIMD_QFM
2379#undef SIMD_QFM_LIST
2380
2381#define SIMD_EXT_ADD_PAIRWISE_LIST(V) \
2382 V(I32x4ExtAddPairwiseI16x8S) \
2383 V(I32x4ExtAddPairwiseI16x8U) \
2384 V(I16x8ExtAddPairwiseI8x16S) \
2385 V(I16x8ExtAddPairwiseI8x16U)
2386#define EMIT_SIMD_EXT_ADD_PAIRWISE(name) \
2387 case kPPC_##name: { \
2388 __ name(i.OutputSimd128Register(), i.InputSimd128Register(0), \
2389 kScratchSimd128Reg, kScratchSimd128Reg2); \
2390 break; \
2391 }
2393#undef EMIT_SIMD_EXT_ADD_PAIRWISE
2394#undef SIMD_EXT_ADD_PAIRWISE_LIST
2395
2396#define SIMD_LOAD_LANE_LIST(V) \
2397 V(S128Load64Lane, LoadLane64LE) \
2398 V(S128Load32Lane, LoadLane32LE) \
2399 V(S128Load16Lane, LoadLane16LE) \
2400 V(S128Load8Lane, LoadLane8LE)
2401
2402#define EMIT_SIMD_LOAD_LANE(name, op) \
2403 case kPPC_##name: { \
2404 Simd128Register dst = i.OutputSimd128Register(); \
2405 DCHECK_EQ(dst, i.InputSimd128Register(0)); \
2406 AddressingMode mode = kMode_None; \
2407 size_t index = 1; \
2408 MemOperand operand = i.MemoryOperand(&mode, &index); \
2409 DCHECK_EQ(mode, kMode_MRR); \
2410 __ op(dst, operand, i.InputUint8(3), kScratchReg, kScratchSimd128Reg); \
2411 break; \
2412 }
2414#undef EMIT_SIMD_LOAD_LANE
2415#undef SIMD_LOAD_LANE_LIST
2416
2417#define SIMD_STORE_LANE_LIST(V) \
2418 V(S128Store64Lane, StoreLane64LE) \
2419 V(S128Store32Lane, StoreLane32LE) \
2420 V(S128Store16Lane, StoreLane16LE) \
2421 V(S128Store8Lane, StoreLane8LE)
2422
2423#define EMIT_SIMD_STORE_LANE(name, op) \
2424 case kPPC_##name: { \
2425 AddressingMode mode = kMode_None; \
2426 size_t index = 1; \
2427 MemOperand operand = i.MemoryOperand(&mode, &index); \
2428 DCHECK_EQ(mode, kMode_MRR); \
2429 __ op(i.InputSimd128Register(0), operand, i.InputUint8(3), kScratchReg, \
2430 kScratchSimd128Reg); \
2431 break; \
2432 }
2434#undef EMIT_SIMD_STORE_LANE
2435#undef SIMD_STORE_LANE_LIST
2436
2437#define SIMD_LOAD_SPLAT(V) \
2438 V(S128Load64Splat, LoadAndSplat64x2LE) \
2439 V(S128Load32Splat, LoadAndSplat32x4LE) \
2440 V(S128Load16Splat, LoadAndSplat16x8LE) \
2441 V(S128Load8Splat, LoadAndSplat8x16LE)
2442
2443#define EMIT_SIMD_LOAD_SPLAT(name, op) \
2444 case kPPC_##name: { \
2445 AddressingMode mode = kMode_None; \
2446 MemOperand operand = i.MemoryOperand(&mode); \
2447 DCHECK_EQ(mode, kMode_MRR); \
2448 __ op(i.OutputSimd128Register(), operand, kScratchReg); \
2449 break; \
2450 }
2452#undef EMIT_SIMD_LOAD_SPLAT
2453#undef SIMD_LOAD_SPLAT
2454
2455 case kPPC_FSplat: {
2456 int lane_size = LaneSizeField::decode(instr->opcode());
2457 switch (lane_size) {
2458 case 32: {
2459 __ F32x4Splat(i.OutputSimd128Register(), i.InputDoubleRegister(0),
2461 break;
2462 }
2463 case 64: {
2464 __ F64x2Splat(i.OutputSimd128Register(), i.InputDoubleRegister(0),
2465 kScratchReg);
2466 break;
2467 }
2468 default:
2469 UNREACHABLE();
2470 }
2471 break;
2472 }
2473 case kPPC_ISplat: {
2474 int lane_size = LaneSizeField::decode(instr->opcode());
2475 switch (lane_size) {
2476 case 8: {
2477 __ I8x16Splat(i.OutputSimd128Register(), i.InputRegister(0));
2478 break;
2479 }
2480 case 16: {
2481 __ I16x8Splat(i.OutputSimd128Register(), i.InputRegister(0));
2482 break;
2483 }
2484 case 32: {
2485 __ I32x4Splat(i.OutputSimd128Register(), i.InputRegister(0));
2486 break;
2487 }
2488 case 64: {
2489 __ I64x2Splat(i.OutputSimd128Register(), i.InputRegister(0));
2490 break;
2491 }
2492 default:
2493 UNREACHABLE();
2494 }
2495 break;
2496 }
2497 case kPPC_FExtractLane: {
2498 int lane_size = LaneSizeField::decode(instr->opcode());
2499 switch (lane_size) {
2500 case 32: {
2501 __ F32x4ExtractLane(i.OutputDoubleRegister(),
2502 i.InputSimd128Register(0), i.InputInt8(1),
2504 break;
2505 }
2506 case 64: {
2507 __ F64x2ExtractLane(i.OutputDoubleRegister(),
2508 i.InputSimd128Register(0), i.InputInt8(1),
2510 break;
2511 }
2512 default:
2513 UNREACHABLE();
2514 }
2515 break;
2516 }
2517 case kPPC_IExtractLane: {
2518 int lane_size = LaneSizeField::decode(instr->opcode());
2519 switch (lane_size) {
2520 case 32: {
2521 __ I32x4ExtractLane(i.OutputRegister(), i.InputSimd128Register(0),
2522 i.InputInt8(1), kScratchSimd128Reg);
2523 break;
2524 }
2525 case 64: {
2526 __ I64x2ExtractLane(i.OutputRegister(), i.InputSimd128Register(0),
2527 i.InputInt8(1), kScratchSimd128Reg);
2528 break;
2529 }
2530 default:
2531 UNREACHABLE();
2532 }
2533 break;
2534 }
2535 case kPPC_IExtractLaneU: {
2536 int lane_size = LaneSizeField::decode(instr->opcode());
2537 switch (lane_size) {
2538 case 8: {
2539 __ I8x16ExtractLaneU(i.OutputRegister(), i.InputSimd128Register(0),
2540 i.InputInt8(1), kScratchSimd128Reg);
2541 break;
2542 }
2543 case 16: {
2544 __ I16x8ExtractLaneU(i.OutputRegister(), i.InputSimd128Register(0),
2545 i.InputInt8(1), kScratchSimd128Reg);
2546 break;
2547 }
2548 default:
2549 UNREACHABLE();
2550 }
2551 break;
2552 }
2553 case kPPC_IExtractLaneS: {
2554 int lane_size = LaneSizeField::decode(instr->opcode());
2555 switch (lane_size) {
2556 case 8: {
2557 __ I8x16ExtractLaneS(i.OutputRegister(), i.InputSimd128Register(0),
2558 i.InputInt8(1), kScratchSimd128Reg);
2559 break;
2560 }
2561 case 16: {
2562 __ I16x8ExtractLaneS(i.OutputRegister(), i.InputSimd128Register(0),
2563 i.InputInt8(1), kScratchSimd128Reg);
2564 break;
2565 }
2566 default:
2567 UNREACHABLE();
2568 }
2569 break;
2570 }
2571 case kPPC_FReplaceLane: {
2572 DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
2573 int lane_size = LaneSizeField::decode(instr->opcode());
2574 switch (lane_size) {
2575 case 32: {
2576 __ F32x4ReplaceLane(
2577 i.OutputSimd128Register(), i.InputSimd128Register(0),
2578 i.InputDoubleRegister(2), i.InputInt8(1), kScratchReg,
2580 break;
2581 }
2582 case 64: {
2583 __ F64x2ReplaceLane(i.OutputSimd128Register(),
2584 i.InputSimd128Register(0),
2585 i.InputDoubleRegister(2), i.InputInt8(1),
2587 break;
2588 }
2589 default:
2590 UNREACHABLE();
2591 }
2592 break;
2593 }
2594 case kPPC_IReplaceLane: {
2595 DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
2596 int lane_size = LaneSizeField::decode(instr->opcode());
2597 switch (lane_size) {
2598 case 8: {
2599 __ I8x16ReplaceLane(i.OutputSimd128Register(),
2600 i.InputSimd128Register(0), i.InputRegister(2),
2601 i.InputInt8(1), kScratchSimd128Reg);
2602 break;
2603 }
2604 case 16: {
2605 __ I16x8ReplaceLane(i.OutputSimd128Register(),
2606 i.InputSimd128Register(0), i.InputRegister(2),
2607 i.InputInt8(1), kScratchSimd128Reg);
2608 break;
2609 }
2610 case 32: {
2611 __ I32x4ReplaceLane(i.OutputSimd128Register(),
2612 i.InputSimd128Register(0), i.InputRegister(2),
2613 i.InputInt8(1), kScratchSimd128Reg);
2614 break;
2615 }
2616 case 64: {
2617 __ I64x2ReplaceLane(i.OutputSimd128Register(),
2618 i.InputSimd128Register(0), i.InputRegister(2),
2619 i.InputInt8(1), kScratchSimd128Reg);
2620 break;
2621 }
2622 default:
2623 UNREACHABLE();
2624 }
2625 break;
2626 }
2627 case kPPC_I64x2Mul: {
2628 __ I64x2Mul(i.OutputSimd128Register(), i.InputSimd128Register(0),
2629 i.InputSimd128Register(1), ip, r0,
2630 i.ToRegister(instr->TempAt(0)), kScratchSimd128Reg);
2631 break;
2632 }
2633 case kPPC_F64x2Min: {
2634 __ F64x2Min(i.OutputSimd128Register(), i.InputSimd128Register(0),
2635 i.InputSimd128Register(1), kScratchSimd128Reg,
2637 break;
2638 }
2639 case kPPC_F64x2Max: {
2640 __ F64x2Max(i.OutputSimd128Register(), i.InputSimd128Register(0),
2641 i.InputSimd128Register(1), kScratchSimd128Reg,
2643 break;
2644 }
2645 case kPPC_S128Const: {
2646 uint64_t low = make_uint64(i.InputUint32(1), i.InputUint32(0));
2647 uint64_t high = make_uint64(i.InputUint32(3), i.InputUint32(2));
2648 __ S128Const(i.OutputSimd128Register(), high, low, r0, ip);
2649 break;
2650 }
2651 case kPPC_S128Zero: {
2652 Simd128Register dst = i.OutputSimd128Register();
2653 __ vxor(dst, dst, dst);
2654 break;
2655 }
2656 case kPPC_S128AllOnes: {
2657 Simd128Register dst = i.OutputSimd128Register();
2658 __ vcmpequb(dst, dst, dst);
2659 break;
2660 }
2661 case kPPC_S128Select: {
2662 Simd128Register dst = i.OutputSimd128Register();
2663 Simd128Register mask = i.InputSimd128Register(0);
2664 Simd128Register src1 = i.InputSimd128Register(1);
2665 Simd128Register src2 = i.InputSimd128Register(2);
2666 __ S128Select(dst, src1, src2, mask);
2667 break;
2668 }
2669 case kPPC_V128AnyTrue: {
2670 __ V128AnyTrue(i.OutputRegister(), i.InputSimd128Register(0), r0, ip,
2672 break;
2673 }
2674 case kPPC_F64x2ConvertLowI32x4U: {
2675 __ F64x2ConvertLowI32x4U(i.OutputSimd128Register(),
2676 i.InputSimd128Register(0), kScratchReg,
2678 break;
2679 }
2680 case kPPC_I64x2UConvertI32x4Low: {
2681 __ I64x2UConvertI32x4Low(i.OutputSimd128Register(),
2682 i.InputSimd128Register(0), kScratchReg,
2684 break;
2685 }
2686 case kPPC_I64x2UConvertI32x4High: {
2687 __ I64x2UConvertI32x4High(i.OutputSimd128Register(),
2688 i.InputSimd128Register(0), kScratchReg,
2690 break;
2691 }
2692 case kPPC_I32x4UConvertI16x8Low: {
2693 __ I32x4UConvertI16x8Low(i.OutputSimd128Register(),
2694 i.InputSimd128Register(0), kScratchReg,
2696 break;
2697 }
2698 case kPPC_I32x4UConvertI16x8High: {
2699 __ I32x4UConvertI16x8High(i.OutputSimd128Register(),
2700 i.InputSimd128Register(0), kScratchReg,
2702 break;
2703 }
2704 case kPPC_I16x8UConvertI8x16Low: {
2705 __ I16x8UConvertI8x16Low(i.OutputSimd128Register(),
2706 i.InputSimd128Register(0), kScratchReg,
2708 break;
2709 }
2710 case kPPC_I16x8UConvertI8x16High: {
2711 __ I16x8UConvertI8x16High(i.OutputSimd128Register(),
2712 i.InputSimd128Register(0), kScratchReg,
2714 break;
2715 }
2716 case kPPC_I8x16Shuffle: {
2717 uint64_t low = make_uint64(i.InputUint32(3), i.InputUint32(2));
2718 uint64_t high = make_uint64(i.InputUint32(5), i.InputUint32(4));
2719 __ I8x16Shuffle(i.OutputSimd128Register(), i.InputSimd128Register(0),
2720 i.InputSimd128Register(1), high, low, r0, ip,
2722 break;
2723 }
2724 case kPPC_I64x2BitMask: {
2725 __ I64x2BitMask(i.OutputRegister(), i.InputSimd128Register(0),
2727 break;
2728 }
2729 case kPPC_I32x4BitMask: {
2730 __ I32x4BitMask(i.OutputRegister(), i.InputSimd128Register(0),
2732 break;
2733 }
2734 case kPPC_I16x8BitMask: {
2735 __ I16x8BitMask(i.OutputRegister(), i.InputSimd128Register(0),
2737 break;
2738 }
2739 case kPPC_I8x16BitMask: {
2740 __ I8x16BitMask(i.OutputRegister(), i.InputSimd128Register(0), r0, ip,
2742 break;
2743 }
2744 case kPPC_I32x4DotI8x16AddS: {
2745 __ I32x4DotI8x16AddS(i.OutputSimd128Register(), i.InputSimd128Register(0),
2746 i.InputSimd128Register(1),
2747 i.InputSimd128Register(2));
2748 break;
2749 }
2750#define PREP_LOAD_EXTEND() \
2751 AddressingMode mode = kMode_None; \
2752 MemOperand operand = i.MemoryOperand(&mode); \
2753 DCHECK_EQ(mode, kMode_MRR);
2754 case kPPC_S128Load8x8S: {
2756 __ LoadAndExtend8x8SLE(i.OutputSimd128Register(), operand, kScratchReg);
2757 break;
2758 }
2759 case kPPC_S128Load8x8U: {
2761 __ LoadAndExtend8x8ULE(i.OutputSimd128Register(), operand, kScratchReg,
2763 break;
2764 }
2765 case kPPC_S128Load16x4S: {
2767 __ LoadAndExtend16x4SLE(i.OutputSimd128Register(), operand, kScratchReg);
2768 break;
2769 }
2770 case kPPC_S128Load16x4U: {
2772 __ LoadAndExtend16x4ULE(i.OutputSimd128Register(), operand, kScratchReg,
2774 break;
2775 }
2776 case kPPC_S128Load32x2S: {
2778 __ LoadAndExtend32x2SLE(i.OutputSimd128Register(), operand, kScratchReg);
2779 break;
2780 }
2781 case kPPC_S128Load32x2U: {
2783 __ LoadAndExtend32x2ULE(i.OutputSimd128Register(), operand, kScratchReg,
2785 break;
2786 }
2787 case kPPC_S128Load32Zero: {
2789 __ LoadV32ZeroLE(i.OutputSimd128Register(), operand, kScratchReg,
2791 break;
2792 }
2793 case kPPC_S128Load64Zero: {
2795 __ LoadV64ZeroLE(i.OutputSimd128Register(), operand, kScratchReg,
2797 break;
2798 }
2799#undef PREP_LOAD_EXTEND
2800 case kPPC_StoreCompressTagged: {
2801 size_t index = 0;
2802 AddressingMode mode = kMode_None;
2803 MemOperand operand = i.MemoryOperand(&mode, &index);
2804 Register value = i.InputRegister(index);
2805 bool is_atomic = i.InputInt32(index + 1);
2806 if (is_atomic) __ lwsync();
2807 __ StoreTaggedField(value, operand, r0);
2808 if (is_atomic) __ sync();
2809 DCHECK_EQ(LeaveRC, i.OutputRCBit());
2810 break;
2811 }
2812 case kPPC_StoreIndirectPointer: {
2813 size_t index = 0;
2814 AddressingMode mode = kMode_None;
2815 MemOperand mem = i.MemoryOperand(&mode, &index);
2816 Register value = i.InputRegister(index);
2817 bool is_atomic = i.InputInt32(index + 1);
2818 if (is_atomic) __ lwsync();
2819 __ StoreIndirectPointerField(value, mem, kScratchReg);
2820 if (is_atomic) __ sync();
2821 DCHECK_EQ(LeaveRC, i.OutputRCBit());
2822 break;
2823 }
2824 case kPPC_LoadDecodeSandboxedPointer: {
2825 size_t index = 0;
2826 AddressingMode mode = kMode_None;
2827 MemOperand mem = i.MemoryOperand(&mode, &index);
2828 bool is_atomic = i.InputInt32(index);
2829 __ LoadSandboxedPointerField(i.OutputRegister(), mem, kScratchReg);
2830 if (is_atomic) __ lwsync();
2831 DCHECK_EQ(LeaveRC, i.OutputRCBit());
2832 break;
2833 }
2834 case kPPC_StoreEncodeSandboxedPointer: {
2835 size_t index = 0;
2836 AddressingMode mode = kMode_None;
2837 MemOperand mem = i.MemoryOperand(&mode, &index);
2838 Register value = i.InputRegister(index);
2839 bool is_atomic = i.InputInt32(index + 1);
2840 if (is_atomic) __ lwsync();
2841 __ StoreSandboxedPointerField(value, mem, kScratchReg);
2842 if (is_atomic) __ sync();
2843 DCHECK_EQ(LeaveRC, i.OutputRCBit());
2844 break;
2845 }
2846 case kPPC_LoadDecompressTaggedSigned: {
2847 CHECK(instr->HasOutput());
2848 ASSEMBLE_LOAD_INTEGER(lwz, plwz, lwzx, false);
2849 break;
2850 }
2851 case kPPC_LoadDecompressTagged: {
2852 CHECK(instr->HasOutput());
2853 ASSEMBLE_LOAD_INTEGER(lwz, plwz, lwzx, false);
2854 __ add(i.OutputRegister(), i.OutputRegister(), kPtrComprCageBaseRegister);
2855 break;
2856 }
2857 default:
2858 UNREACHABLE();
2859 }
2860 return kSuccess;
2861}
2862
2863// Assembles branches after an instruction.
2864void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
2865 PPCOperandConverter i(this, instr);
2866 Label* tlabel = branch->true_label;
2867 Label* flabel = branch->false_label;
2868 ArchOpcode op = instr->arch_opcode();
2869 FlagsCondition condition = branch->condition;
2870 CRegister cr = cr0;
2871
2873 if (op == kPPC_CmpDouble) {
2874 // check for unordered if necessary
2875 if (cond == le) {
2876 __ bunordered(flabel, cr);
2877 // Unnecessary for eq/lt since only FU bit will be set.
2878 } else if (cond == gt) {
2879 __ bunordered(tlabel, cr);
2880 // Unnecessary for ne/ge since only FU bit will be set.
2881 }
2882 }
2883 __ b(cond, tlabel, cr);
2884 if (!branch->fallthru) __ b(flabel); // no fallthru to flabel.
2885}
2886
2888 BranchInfo* branch) {
2889 AssembleArchBranch(instr, branch);
2890}
2891
2893 RpoNumber target) {
2894 __ b(GetLabel(target));
2895}
2896
2897#if V8_ENABLE_WEBASSEMBLY
2898void CodeGenerator::AssembleArchTrap(Instruction* instr,
2900 class OutOfLineTrap final : public OutOfLineCode {
2901 public:
2902 OutOfLineTrap(CodeGenerator* gen, Instruction* instr)
2903 : OutOfLineCode(gen), instr_(instr), gen_(gen) {}
2904
2905 void Generate() final {
2906 PPCOperandConverter i(gen_, instr_);
2907 TrapId trap_id =
2908 static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
2909 GenerateCallToTrap(trap_id);
2910 }
2911
2912 private:
2913 void GenerateCallToTrap(TrapId trap_id) {
2914 gen_->AssembleSourcePosition(instr_);
2915 // A direct call to a wasm runtime stub defined in this module.
2916 // Just encode the stub index. This will be patched when the code
2917 // is added to the native module and copied into wasm code space.
2918 __ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
2919 ReferenceMap* reference_map =
2920 gen_->zone()->New<ReferenceMap>(gen_->zone());
2921 gen_->RecordSafepoint(reference_map);
2922 if (v8_flags.debug_code) {
2923 __ stop();
2924 }
2925 }
2926
2927 Instruction* instr_;
2928 CodeGenerator* gen_;
2929 };
2930 auto ool = zone()->New<OutOfLineTrap>(this, instr);
2931 Label* tlabel = ool->entry();
2932 Label end;
2933
2934 ArchOpcode op = instr->arch_opcode();
2935 CRegister cr = cr0;
2937 if (op == kPPC_CmpDouble) {
2938 // check for unordered if necessary
2939 if (cond == le) {
2940 __ bunordered(&end, cr);
2941 // Unnecessary for eq/lt since only FU bit will be set.
2942 } else if (cond == gt) {
2943 __ bunordered(tlabel, cr);
2944 // Unnecessary for ne/ge since only FU bit will be set.
2945 }
2946 }
2947 __ b(cond, tlabel, cr);
2948 __ bind(&end);
2949}
2950#endif // V8_ENABLE_WEBASSEMBLY
2951
2952// Assembles boolean materializations after an instruction.
2955 PPCOperandConverter i(this, instr);
2956 Label done;
2957 ArchOpcode op = instr->arch_opcode();
2958 CRegister cr = cr0;
2959 int reg_value = -1;
2960
2961 // Materialize a full 32-bit 1 or 0 value. The result register is always the
2962 // last output of the instruction.
2963 DCHECK_NE(0u, instr->OutputCount());
2964 Register reg = i.OutputRegister(instr->OutputCount() - 1);
2965
2967 if (op == kPPC_CmpDouble) {
2968 // check for unordered if necessary
2969 if (cond == le) {
2970 reg_value = 0;
2971 __ li(reg, Operand::Zero());
2972 __ bunordered(&done, cr);
2973 } else if (cond == gt) {
2974 reg_value = 1;
2975 __ li(reg, Operand(1));
2976 __ bunordered(&done, cr);
2977 }
2978 // Unnecessary for eq/lt & ne/ge since only FU bit will be set.
2979 }
2980 switch (cond) {
2981 case eq:
2982 case lt:
2983 case gt:
2984 if (reg_value != 1) __ li(reg, Operand(1));
2986 __ isel(cond, reg, reg, kScratchReg, cr);
2987 break;
2988 case ne:
2989 case ge:
2990 case le:
2991 if (reg_value != 1) __ li(reg, Operand(1));
2992 // r0 implies logical zero in this form
2993 __ isel(NegateCondition(cond), reg, r0, reg, cr);
2994 break;
2995 default:
2996 UNREACHABLE();
2997 }
2998 __ bind(&done);
2999}
3000
3002 UNREACHABLE();
3003}
3004
3006 BranchInfo* branch) {
3007 UNREACHABLE();
3008}
3009
3011 PPCOperandConverter i(this, instr);
3012 Register input = i.InputRegister(0);
3013 std::vector<std::pair<int32_t, Label*>> cases;
3014 for (size_t index = 2; index < instr->InputCount(); index += 2) {
3015 cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
3016 }
3017 AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
3018 cases.data() + cases.size());
3019}
3020
3022 PPCOperandConverter i(this, instr);
3023 Register input = i.InputRegister(0);
3024 int32_t const case_count = static_cast<int32_t>(instr->InputCount() - 2);
3025 base::Vector<Label*> cases = zone()->AllocateVector<Label*>(case_count);
3026 for (int32_t index = 0; index < case_count; ++index) {
3027 cases[index] = GetLabel(i.InputRpo(index + 2));
3028 }
3029 Label* const table = AddJumpTable(cases);
3030 __ CmpU64(input, Operand(case_count), r0);
3031 __ bge(GetLabel(i.InputRpo(1)));
3032 __ mov_label_addr(kScratchReg, table);
3033 __ ShiftLeftU64(r0, input, Operand(kSystemPointerSizeLog2));
3034 __ LoadU64(kScratchReg, MemOperand(kScratchReg, r0));
3035 __ Jump(kScratchReg);
3036}
3037
3040 UNIMPLEMENTED();
3041}
3042
3043void CodeGenerator::FinishFrame(Frame* frame) {
3044 auto call_descriptor = linkage()->GetIncomingDescriptor();
3045 const DoubleRegList double_saves = call_descriptor->CalleeSavedFPRegisters();
3046
3047 // Save callee-saved Double registers.
3048 if (!double_saves.is_empty()) {
3049 frame->AlignSavedCalleeRegisterSlots();
3050 DCHECK_EQ(kNumCalleeSavedDoubles, double_saves.Count());
3051 frame->AllocateSavedCalleeRegisterSlots(kNumCalleeSavedDoubles *
3053 }
3054 // Save callee-saved registers.
3055 const RegList saves =
3057 ? call_descriptor->CalleeSavedRegisters() - kConstantPoolRegister
3058 : call_descriptor->CalleeSavedRegisters();
3059 if (!saves.is_empty()) {
3060 // register save area does not include the fp or constant pool pointer.
3061 const int num_saves =
3063 frame->AllocateSavedCalleeRegisterSlots(num_saves);
3064 }
3065}
3066
3068 auto call_descriptor = linkage()->GetIncomingDescriptor();
3069 if (frame_access_state()->has_frame()) {
3070 if (call_descriptor->IsCFunctionCall()) {
3071#if V8_ENABLE_WEBASSEMBLY
3072 if (info()->GetOutputStackFrameType() == StackFrame::C_WASM_ENTRY) {
3073 __ StubPrologue(StackFrame::C_WASM_ENTRY);
3074 // Reserve stack space for saving the c_entry_fp later.
3075 __ addi(sp, sp, Operand(-kSystemPointerSize));
3076#else
3077 // For balance.
3078 if (false) {
3079#endif // V8_ENABLE_WEBASSEMBLY
3080 } else {
3081 __ mflr(r0);
3083 __ Push(r0, fp, kConstantPoolRegister);
3084 // Adjust FP to point to saved FP.
3085 __ SubS64(fp, sp,
3087 } else {
3088 __ Push(r0, fp);
3089 __ mr(fp, sp);
3090 }
3091 }
3092 } else if (call_descriptor->IsJSFunctionCall()) {
3093 __ Prologue();
3094 } else {
3096 // TODO(mbrandy): Detect cases where ip is the entrypoint (for
3097 // efficient initialization of the constant pool pointer register).
3098 __ StubPrologue(type);
3099#if V8_ENABLE_WEBASSEMBLY
3100 if (call_descriptor->IsAnyWasmFunctionCall() ||
3101 call_descriptor->IsWasmImportWrapper() ||
3102 call_descriptor->IsWasmCapiFunction()) {
3103 // For import wrappers and C-API functions, this stack slot is only used
3104 // for printing stack traces in V8. Also, it holds a WasmImportData
3105 // instead of the trusted instance data, which is taken care of in the
3106 // frames accessors.
3108 }
3109 if (call_descriptor->IsWasmCapiFunction()) {
3110 // Reserve space for saving the PC later.
3111 __ addi(sp, sp, Operand(-kSystemPointerSize));
3112 }
3113#endif // V8_ENABLE_WEBASSEMBLY
3114 }
3116 }
3117
3118 int required_slots =
3119 frame()->GetTotalFrameSlotCount() - frame()->GetFixedSlotCount();
3120 if (info()->is_osr()) {
3121 // TurboFan OSR-compiled functions cannot be entered directly.
3122 __ Abort(AbortReason::kShouldNotDirectlyEnterOsrFunction);
3123
3124 // Unoptimized code jumps directly to this entrypoint while the unoptimized
3125 // frame is still on the stack. Optimized code uses OSR values directly from
3126 // the unoptimized frame. Thus, all that needs to be done is to allocate the
3127 // remaining stack slots.
3128 __ RecordComment("-- OSR entrypoint --");
3130 required_slots -= osr_helper()->UnoptimizedFrameSlots();
3131 }
3132
3133 const DoubleRegList saves_fp = call_descriptor->CalleeSavedFPRegisters();
3134 const RegList saves =
3136 ? call_descriptor->CalleeSavedRegisters() - kConstantPoolRegister
3137 : call_descriptor->CalleeSavedRegisters();
3138
3139 if (required_slots > 0) {
3140#if V8_ENABLE_WEBASSEMBLY
3141 if (info()->IsWasm() && required_slots * kSystemPointerSize > 4 * KB) {
3142 // For WebAssembly functions with big frames we have to do the stack
3143 // overflow check before we construct the frame. Otherwise we may not
3144 // have enough space on the stack to call the runtime for the stack
3145 // overflow.
3146 Label done;
3147
3148 // If the frame is bigger than the stack, we throw the stack overflow
3149 // exception unconditionally. Thereby we can avoid the integer overflow
3150 // check in the condition code.
3151 if (required_slots * kSystemPointerSize < v8_flags.stack_size * KB) {
3152 Register stack_limit = ip;
3153 __ LoadStackLimit(stack_limit, StackLimitKind::kRealStackLimit, r0);
3154 __ AddS64(stack_limit, stack_limit,
3155 Operand(required_slots * kSystemPointerSize), r0);
3156 __ CmpU64(sp, stack_limit);
3157 __ bge(&done);
3158 }
3159
3160 if (v8_flags.experimental_wasm_growable_stacks) {
3163 regs_to_save.set(
3164 WasmHandleStackOverflowDescriptor::FrameBaseRegister());
3165 for (auto reg : wasm::kGpParamRegisters) regs_to_save.set(reg);
3166 __ MultiPush(regs_to_save);
3167 DoubleRegList fp_regs_to_save;
3168 for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg);
3169 __ MultiPushF64AndV128(fp_regs_to_save,
3170 Simd128RegList::FromBits(fp_regs_to_save.bits()),
3171 ip, r0);
3173 Operand(required_slots * kSystemPointerSize));
3174 __ AddS64(
3175 WasmHandleStackOverflowDescriptor::FrameBaseRegister(), fp,
3176 Operand(call_descriptor->ParameterSlotCount() * kSystemPointerSize +
3178 __ CallBuiltin(Builtin::kWasmHandleStackOverflow);
3179 __ MultiPopF64AndV128(fp_regs_to_save,
3180 Simd128RegList::FromBits(fp_regs_to_save.bits()),
3181 ip, r0);
3182 __ MultiPop(regs_to_save);
3183 } else {
3184 __ Call(static_cast<intptr_t>(Builtin::kWasmStackOverflow),
3186 // The call does not return, hence we can ignore any references and just
3187 // define an empty safepoint.
3188 ReferenceMap* reference_map = zone()->New<ReferenceMap>(zone());
3189 RecordSafepoint(reference_map);
3190 if (v8_flags.debug_code) __ stop();
3191 }
3192
3193 __ bind(&done);
3194 }
3195#endif // V8_ENABLE_WEBASSEMBLY
3196
3197 // Skip callee-saved and return slots, which are pushed below.
3198 required_slots -= saves.Count();
3199 required_slots -= frame()->GetReturnSlotCount();
3200 required_slots -= (kDoubleSize / kSystemPointerSize) * saves_fp.Count();
3201 __ AddS64(sp, sp, Operand(-required_slots * kSystemPointerSize), r0);
3202 }
3203
3204 // Save callee-saved Double registers.
3205 if (!saves_fp.is_empty()) {
3206 __ MultiPushDoubles(saves_fp);
3207 DCHECK_EQ(kNumCalleeSavedDoubles, saves_fp.Count());
3208 }
3209
3210 // Save callee-saved registers.
3211 if (!saves.is_empty()) {
3212 __ MultiPush(saves);
3213 // register save area does not include the fp or constant pool pointer.
3214 }
3215
3216 const int returns = frame()->GetReturnSlotCount();
3217 // Create space for returns.
3218 __ AllocateStackSpace(returns * kSystemPointerSize);
3219
3220 if (!frame()->tagged_slots().IsEmpty()) {
3221 __ mov(kScratchReg, Operand(0));
3222 for (int spill_slot : frame()->tagged_slots()) {
3223 FrameOffset offset = frame_access_state()->GetFrameOffset(spill_slot);
3224 DCHECK(offset.from_frame_pointer());
3225 __ StoreU64(kScratchReg, MemOperand(fp, offset.offset()));
3226 }
3227 }
3228}
3229
3230void CodeGenerator::AssembleReturn(InstructionOperand* additional_pop_count) {
3231 auto call_descriptor = linkage()->GetIncomingDescriptor();
3232
3233 const int returns = frame()->GetReturnSlotCount();
3234 if (returns != 0) {
3235 // Create space for returns.
3236 __ AddS64(sp, sp, Operand(returns * kSystemPointerSize), r0);
3237 }
3238
3239 // Restore registers.
3240 const RegList saves =
3242 ? call_descriptor->CalleeSavedRegisters() - kConstantPoolRegister
3243 : call_descriptor->CalleeSavedRegisters();
3244 if (!saves.is_empty()) {
3245 __ MultiPop(saves);
3246 }
3247
3248 // Restore double registers.
3249 const DoubleRegList double_saves = call_descriptor->CalleeSavedFPRegisters();
3250 if (!double_saves.is_empty()) {
3251 __ MultiPopDoubles(double_saves);
3252 }
3253
3255
3256 PPCOperandConverter g(this, nullptr);
3257 const int parameter_slots =
3258 static_cast<int>(call_descriptor->ParameterSlotCount());
3259
3260 // {aditional_pop_count} is only greater than zero if {parameter_slots = 0}.
3261 // Check RawMachineAssembler::PopAndReturn.
3262 if (parameter_slots != 0) {
3263 if (additional_pop_count->IsImmediate()) {
3264 DCHECK_EQ(g.ToConstant(additional_pop_count).ToInt32(), 0);
3265 } else if (v8_flags.debug_code) {
3266 __ cmpi(g.ToRegister(additional_pop_count), Operand(0));
3267 __ Assert(eq, AbortReason::kUnexpectedAdditionalPopValue);
3268 }
3269 }
3270
3271#if V8_ENABLE_WEBASSEMBLY
3272 if (call_descriptor->IsAnyWasmFunctionCall() &&
3273 v8_flags.experimental_wasm_growable_stacks) {
3274 {
3275 UseScratchRegisterScope temps{masm()};
3276 Register scratch = temps.Acquire();
3277 __ LoadU64(scratch,
3279 __ CmpU64(
3280 scratch,
3281 Operand(StackFrame::TypeToMarker(StackFrame::WASM_SEGMENT_START)),
3282 r0);
3283 }
3284 Label done;
3285 __ bne(&done);
3288 __ MultiPush(regs_to_save);
3289 DoubleRegList fp_regs_to_save;
3290 for (auto reg : wasm::kFpParamRegisters) fp_regs_to_save.set(reg);
3291 __ MultiPushF64AndV128(fp_regs_to_save,
3292 Simd128RegList::FromBits(fp_regs_to_save.bits()), ip,
3293 r0);
3295 __ PrepareCallCFunction(1, r0);
3296 __ CallCFunction(ExternalReference::wasm_shrink_stack(), 1);
3297 // Restore old FP. We don't need to restore old SP explicitly, because
3298 // it will be restored from FP in LeaveFrame before return.
3299 __ mr(fp, kReturnRegister0);
3300 __ MultiPopF64AndV128(fp_regs_to_save,
3301 Simd128RegList::FromBits(fp_regs_to_save.bits()), ip,
3302 r0);
3303 __ MultiPop(regs_to_save);
3304 __ bind(&done);
3305 }
3306#endif // V8_ENABLE_WEBASSEMBLY
3307
3308 Register argc_reg = r6;
3309 // Functions with JS linkage have at least one parameter (the receiver).
3310 // If {parameter_slots} == 0, it means it is a builtin with
3311 // kDontAdaptArgumentsSentinel, which takes care of JS arguments popping
3312 // itself.
3313 const bool drop_jsargs = parameter_slots != 0 &&
3315 call_descriptor->IsJSFunctionCall();
3316
3317 if (call_descriptor->IsCFunctionCall()) {
3319 } else if (frame_access_state()->has_frame()) {
3320 // Canonicalize JSFunction return sites for now unless they have an variable
3321 // number of stack slot pops
3322 if (additional_pop_count->IsImmediate() &&
3323 g.ToConstant(additional_pop_count).ToInt32() == 0) {
3324 if (return_label_.is_bound()) {
3325 __ b(&return_label_);
3326 return;
3327 } else {
3328 __ bind(&return_label_);
3329 }
3330 }
3331 if (drop_jsargs) {
3332 // Get the actual argument count.
3333 DCHECK(!call_descriptor->CalleeSavedRegisters().has(argc_reg));
3334 __ LoadU64(argc_reg, MemOperand(fp, StandardFrameConstants::kArgCOffset));
3335 }
3337 }
3338 // Constant pool is unavailable since the frame has been destructed
3339 ConstantPoolUnavailableScope constant_pool_unavailable(masm());
3340 if (drop_jsargs) {
3341 // We must pop all arguments from the stack (including the receiver).
3342 // The number of arguments without the receiver is
3343 // max(argc_reg, parameter_slots-1), and the receiver is added in
3344 // DropArguments().
3345 DCHECK(!call_descriptor->CalleeSavedRegisters().has(argc_reg));
3346 if (parameter_slots > 1) {
3347 Label skip;
3348 __ CmpS64(argc_reg, Operand(parameter_slots), r0);
3349 __ bgt(&skip);
3350 __ mov(argc_reg, Operand(parameter_slots));
3351 __ bind(&skip);
3352 }
3353 __ DropArguments(argc_reg);
3354 } else if (additional_pop_count->IsImmediate()) {
3355 int additional_count = g.ToConstant(additional_pop_count).ToInt32();
3356 __ Drop(parameter_slots + additional_count);
3357 } else if (parameter_slots == 0) {
3358 __ Drop(g.ToRegister(additional_pop_count));
3359 } else {
3360 // {additional_pop_count} is guaranteed to be zero if {parameter_slots !=
3361 // 0}. Check RawMachineAssembler::PopAndReturn.
3362 __ Drop(parameter_slots);
3363 }
3364 __ Ret();
3365}
3366
3368
3370 ZoneDeque<DeoptimizationExit*>* exits) {
3371 int total_size = 0;
3372 for (DeoptimizationExit* exit : deoptimization_exits_) {
3373 total_size += (exit->kind() == DeoptimizeKind::kLazy)
3376 }
3377
3378 __ CheckTrampolinePoolQuick(total_size);
3379}
3380
3381AllocatedOperand CodeGenerator::Push(InstructionOperand* source) {
3382 auto rep = LocationOperand::cast(source)->representation();
3383 int new_slots = ElementSizeInPointers(rep);
3384 PPCOperandConverter g(this, nullptr);
3385 int last_frame_slot_id =
3386 frame_access_state_->frame()->GetTotalFrameSlotCount() - 1;
3387 int sp_delta = frame_access_state_->sp_delta();
3388 int slot_id = last_frame_slot_id + sp_delta + new_slots;
3389 AllocatedOperand stack_slot(LocationOperand::STACK_SLOT, rep, slot_id);
3390 if (source->IsFloatStackSlot() || source->IsDoubleStackSlot()) {
3391 __ LoadU64(r0, g.ToMemOperand(source), r0);
3392 __ Push(r0);
3393 frame_access_state()->IncreaseSPDelta(new_slots);
3394 } else {
3395 // Bump the stack pointer and assemble the move.
3396 __ addi(sp, sp, Operand(-(new_slots * kSystemPointerSize)));
3397 frame_access_state()->IncreaseSPDelta(new_slots);
3398 AssembleMove(source, &stack_slot);
3399 }
3400 temp_slots_ += new_slots;
3401 return stack_slot;
3402}
3403
3404void CodeGenerator::Pop(InstructionOperand* dest, MachineRepresentation rep) {
3405 int dropped_slots = ElementSizeInPointers(rep);
3406 PPCOperandConverter g(this, nullptr);
3407 if (dest->IsFloatStackSlot() || dest->IsDoubleStackSlot()) {
3408 frame_access_state()->IncreaseSPDelta(-dropped_slots);
3409 UseScratchRegisterScope temps(masm());
3410 Register scratch = temps.Acquire();
3411 __ Pop(scratch);
3412 __ StoreU64(scratch, g.ToMemOperand(dest), r0);
3413 } else {
3414 int last_frame_slot_id =
3415 frame_access_state_->frame()->GetTotalFrameSlotCount() - 1;
3416 int sp_delta = frame_access_state_->sp_delta();
3417 int slot_id = last_frame_slot_id + sp_delta;
3418 AllocatedOperand stack_slot(LocationOperand::STACK_SLOT, rep, slot_id);
3419 AssembleMove(&stack_slot, dest);
3420 frame_access_state()->IncreaseSPDelta(-dropped_slots);
3421 __ addi(sp, sp, Operand(dropped_slots * kSystemPointerSize));
3422 }
3423 temp_slots_ -= dropped_slots;
3424}
3425
3427 if (temp_slots_ > 0) {
3429 __ addi(sp, sp, Operand(temp_slots_ * kSystemPointerSize));
3430 temp_slots_ = 0;
3431 }
3432}
3433
3434void CodeGenerator::MoveToTempLocation(InstructionOperand* source,
3436 // Must be kept in sync with {MoveTempLocationTo}.
3437 if (!IsFloatingPoint(rep) ||
3438 ((IsFloatingPoint(rep) &&
3440 // The scratch register for this rep is available.
3441 int scratch_reg_code;
3442 if (IsSimd128(rep)) {
3443 scratch_reg_code = kScratchSimd128Reg.code();
3444 } else if (IsFloatingPoint(rep)) {
3445 scratch_reg_code = kScratchDoubleReg.code();
3446 } else {
3447 scratch_reg_code = kScratchReg.code();
3448 }
3449 AllocatedOperand scratch(LocationOperand::REGISTER, rep, scratch_reg_code);
3450 DCHECK(!AreAliased(kScratchReg, r0, ip));
3451 AssembleMove(source, &scratch);
3452 } else {
3453 // The scratch register is blocked by pending moves. Use the stack instead.
3454 Push(source);
3455 }
3456}
3457
3458void CodeGenerator::MoveTempLocationTo(InstructionOperand* dest,
3460 if (!IsFloatingPoint(rep) ||
3461 ((IsFloatingPoint(rep) &&
3463 int scratch_reg_code =
3465 AllocatedOperand scratch(LocationOperand::REGISTER, rep, scratch_reg_code);
3466 DCHECK(!AreAliased(kScratchReg, r0, ip));
3467 AssembleMove(&scratch, dest);
3468 } else {
3469 Pop(dest, rep);
3470 }
3471 move_cycle_ = MoveCycleState();
3472}
3473
3474void CodeGenerator::SetPendingMove(MoveOperands* move) {
3475 if ((move->source().IsConstant() || move->source().IsFPStackSlot()) &&
3476 !move->destination().IsFPRegister()) {
3478 }
3479}
3480
3481void CodeGenerator::AssembleMove(InstructionOperand* source,
3482 InstructionOperand* destination) {
3483 PPCOperandConverter g(this, nullptr);
3484 // Dispatch on the source and destination operand kinds. Not all
3485 // combinations are possible.
3486 // If a move type needs the scratch register, this also needs to be recorded
3487 // in {SetPendingMove} to avoid conflicts with the gap resolver.
3488 if (source->IsRegister()) {
3489 DCHECK(destination->IsRegister() || destination->IsStackSlot());
3490 Register src = g.ToRegister(source);
3491 if (destination->IsRegister()) {
3492 __ Move(g.ToRegister(destination), src);
3493 } else {
3494 __ StoreU64(src, g.ToMemOperand(destination), r0);
3495 }
3496 } else if (source->IsStackSlot()) {
3497 DCHECK(destination->IsRegister() || destination->IsStackSlot());
3498 MemOperand src = g.ToMemOperand(source);
3499 if (destination->IsRegister()) {
3500 __ LoadU64(g.ToRegister(destination), src, r0);
3501 } else {
3502 Register temp = ip;
3503 __ LoadU64(temp, src, r0);
3504 __ StoreU64(temp, g.ToMemOperand(destination), r0);
3505 }
3506 } else if (source->IsConstant()) {
3507 Constant src = g.ToConstant(source);
3508 if (destination->IsRegister() || destination->IsStackSlot()) {
3509 Register dst = destination->IsRegister() ? g.ToRegister(destination) : ip;
3510 switch (src.type()) {
3511 case Constant::kInt32:
3512 __ mov(dst, Operand(src.ToInt32(), src.rmode()));
3513 break;
3514 case Constant::kInt64:
3515 __ mov(dst, Operand(src.ToInt64(), src.rmode()));
3516 break;
3517 case Constant::kFloat32:
3518 __ mov(dst, Operand::EmbeddedNumber(src.ToFloat32()));
3519 break;
3520 case Constant::kFloat64:
3521 __ mov(dst, Operand::EmbeddedNumber(src.ToFloat64().value()));
3522 break;
3524 __ Move(dst, src.ToExternalReference());
3525 break;
3526 case Constant::kHeapObject: {
3527 Handle<HeapObject> src_object = src.ToHeapObject();
3529 if (IsMaterializableFromRoot(src_object, &index)) {
3530 __ LoadRoot(dst, index);
3531 } else {
3532 __ Move(dst, src_object);
3533 }
3534 break;
3535 }
3537 Handle<HeapObject> src_object = src.ToHeapObject();
3539 if (IsMaterializableFromRoot(src_object, &index)) {
3540 __ LoadTaggedRoot(dst, index);
3541 } else {
3542 // TODO(v8:7703, jyan@ca.ibm.com): Turn into a
3543 // COMPRESSED_EMBEDDED_OBJECT when the constant pool entry size is
3544 // tagged size.
3545 __ Move(dst, src_object, RelocInfo::FULL_EMBEDDED_OBJECT);
3546 }
3547 break;
3548 }
3550 UNREACHABLE(); // TODO(dcarney): loading RPO constants on PPC.
3551 }
3552 if (destination->IsStackSlot()) {
3553 __ StoreU64(dst, g.ToMemOperand(destination), r0);
3554 }
3555 } else {
3556 DoubleRegister dst = destination->IsFPRegister()
3557 ? g.ToDoubleRegister(destination)
3559 base::Double value;
3560#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
3561 // casting double precision snan to single precision
3562 // converts it to qnan on ia32/x64
3563 if (src.type() == Constant::kFloat32) {
3564 uint32_t val = src.ToFloat32AsInt();
3565 if ((val & 0x7F800000) == 0x7F800000) {
3566 uint64_t dval = static_cast<uint64_t>(val);
3567 dval = ((dval & 0xC0000000) << 32) | ((dval & 0x40000000) << 31) |
3568 ((dval & 0x40000000) << 30) | ((dval & 0x7FFFFFFF) << 29);
3569 value = base::Double(dval);
3570 } else {
3571 value = base::Double(static_cast<double>(src.ToFloat32()));
3572 }
3573 } else {
3574 value = base::Double(src.ToFloat64());
3575 }
3576#else
3577 value = src.type() == Constant::kFloat32
3578 ? base::Double(static_cast<double>(src.ToFloat32()))
3579 : base::Double(src.ToFloat64());
3580#endif
3581 __ LoadDoubleLiteral(dst, value, r0);
3582 if (destination->IsDoubleStackSlot()) {
3583 __ StoreF64(dst, g.ToMemOperand(destination), r0);
3584 } else if (destination->IsFloatStackSlot()) {
3585 __ StoreF32(dst, g.ToMemOperand(destination), r0);
3586 }
3587 }
3588 } else if (source->IsFPRegister()) {
3591 if (destination->IsSimd128Register()) {
3592 __ vor(g.ToSimd128Register(destination), g.ToSimd128Register(source),
3593 g.ToSimd128Register(source));
3594 } else {
3595 DCHECK(destination->IsSimd128StackSlot());
3596 MemOperand dst = g.ToMemOperand(destination);
3597 __ StoreSimd128(g.ToSimd128Register(source), dst, r0);
3598 }
3599 } else {
3600 DoubleRegister src = g.ToDoubleRegister(source);
3601 if (destination->IsFPRegister()) {
3602 DoubleRegister dst = g.ToDoubleRegister(destination);
3603 __ Move(dst, src);
3604 } else {
3605 DCHECK(destination->IsFPStackSlot());
3606 LocationOperand* op = LocationOperand::cast(source);
3607 if (op->representation() == MachineRepresentation::kFloat64) {
3608 __ StoreF64(src, g.ToMemOperand(destination), r0);
3609 } else {
3610 __ StoreF32(src, g.ToMemOperand(destination), r0);
3611 }
3612 }
3613 }
3614 } else if (source->IsFPStackSlot()) {
3615 DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
3616 MemOperand src = g.ToMemOperand(source);
3617 if (destination->IsFPRegister()) {
3618 LocationOperand* op = LocationOperand::cast(source);
3619 if (op->representation() == MachineRepresentation::kFloat64) {
3620 __ LoadF64(g.ToDoubleRegister(destination), src, r0);
3621 } else if (op->representation() == MachineRepresentation::kFloat32) {
3622 __ LoadF32(g.ToDoubleRegister(destination), src, r0);
3623 } else {
3624 DCHECK_EQ(MachineRepresentation::kSimd128, op->representation());
3625 MemOperand src = g.ToMemOperand(source);
3626 __ LoadSimd128(g.ToSimd128Register(destination), src, r0);
3627 }
3628 } else {
3629 LocationOperand* op = LocationOperand::cast(source);
3631 if (op->representation() == MachineRepresentation::kFloat64) {
3632 __ LoadF64(temp, src, r0);
3633 __ StoreF64(temp, g.ToMemOperand(destination), r0);
3634 } else if (op->representation() == MachineRepresentation::kFloat32) {
3635 __ LoadF32(temp, src, r0);
3636 __ StoreF32(temp, g.ToMemOperand(destination), r0);
3637 } else {
3638 DCHECK_EQ(MachineRepresentation::kSimd128, op->representation());
3639 MemOperand src = g.ToMemOperand(source);
3640 MemOperand dst = g.ToMemOperand(destination);
3641 __ LoadSimd128(kScratchSimd128Reg, src, r0);
3642 __ StoreSimd128(kScratchSimd128Reg, dst, r0);
3643 }
3644 }
3645 } else {
3646 UNREACHABLE();
3647 }
3648}
3649
3650// Swaping contents in source and destination.
3651// source and destination could be:
3652// Register,
3653// FloatRegister,
3654// DoubleRegister,
3655// StackSlot,
3656// FloatStackSlot,
3657// or DoubleStackSlot
3658void CodeGenerator::AssembleSwap(InstructionOperand* source,
3659 InstructionOperand* destination) {
3660 PPCOperandConverter g(this, nullptr);
3661 if (source->IsRegister()) {
3662 Register src = g.ToRegister(source);
3663 if (destination->IsRegister()) {
3664 __ SwapP(src, g.ToRegister(destination), kScratchReg);
3665 } else {
3666 DCHECK(destination->IsStackSlot());
3667 __ SwapP(src, g.ToMemOperand(destination), kScratchReg);
3668 }
3669 } else if (source->IsStackSlot()) {
3670 DCHECK(destination->IsStackSlot());
3671 __ SwapP(g.ToMemOperand(source), g.ToMemOperand(destination), kScratchReg,
3672 r0);
3673 } else if (source->IsFloatRegister()) {
3674 DoubleRegister src = g.ToDoubleRegister(source);
3675 if (destination->IsFloatRegister()) {
3676 __ SwapFloat32(src, g.ToDoubleRegister(destination), kScratchDoubleReg);
3677 } else {
3678 DCHECK(destination->IsFloatStackSlot());
3679 __ SwapFloat32(src, g.ToMemOperand(destination), kScratchDoubleReg);
3680 }
3681 } else if (source->IsDoubleRegister()) {
3682 DoubleRegister src = g.ToDoubleRegister(source);
3683 if (destination->IsDoubleRegister()) {
3684 __ SwapDouble(src, g.ToDoubleRegister(destination), kScratchDoubleReg);
3685 } else {
3686 DCHECK(destination->IsDoubleStackSlot());
3687 __ SwapDouble(src, g.ToMemOperand(destination), kScratchDoubleReg);
3688 }
3689 } else if (source->IsFloatStackSlot()) {
3690 DCHECK(destination->IsFloatStackSlot());
3691 __ SwapFloat32(g.ToMemOperand(source), g.ToMemOperand(destination),
3692 kScratchDoubleReg, d0);
3693 } else if (source->IsDoubleStackSlot()) {
3694 DCHECK(destination->IsDoubleStackSlot());
3695 __ SwapDouble(g.ToMemOperand(source), g.ToMemOperand(destination),
3696 kScratchDoubleReg, d0);
3697
3698 } else if (source->IsSimd128Register()) {
3699 Simd128Register src = g.ToSimd128Register(source);
3700 if (destination->IsSimd128Register()) {
3701 __ SwapSimd128(src, g.ToSimd128Register(destination), kScratchSimd128Reg);
3702 } else {
3703 DCHECK(destination->IsSimd128StackSlot());
3704 __ SwapSimd128(src, g.ToMemOperand(destination), kScratchSimd128Reg,
3705 kScratchReg);
3706 }
3707 } else if (source->IsSimd128StackSlot()) {
3708 DCHECK(destination->IsSimd128StackSlot());
3709 __ SwapSimd128(g.ToMemOperand(source), g.ToMemOperand(destination),
3711
3712 } else {
3713 UNREACHABLE();
3714 }
3715
3716 return;
3717}
3718
3719void CodeGenerator::AssembleJumpTable(base::Vector<Label*> targets) {
3720 for (auto target : targets) {
3721 __ emit_label_addr(target);
3722 }
3723}
3724
3725#undef __
3726
3727} // namespace compiler
3728} // namespace internal
3729} // namespace v8
friend Zone
Definition asm-types.cc:195
#define Assert(condition)
static constexpr T decode(U value)
Definition bit-field.h:66
static int encode_crbit(const CRegister &cr, enum CRBit crbit)
static constexpr int kConstantPoolOffset
static constexpr int kFixedSlotCountAboveFp
static constexpr int kFixedFrameSizeAboveFp
static bool IsSupported(CpuFeature f)
static V8_EXPORT_PRIVATE const int kEagerDeoptExitSize
static V8_EXPORT_PRIVATE const int kLazyDeoptExitSize
static V8_EXPORT_PRIVATE ExternalReference isolate_address()
Bootstrapper * bootstrapper()
Definition isolate.h:1178
RootsTable & roots_table()
Definition isolate.h:1250
Tagged_t ReadOnlyRootPtr(RootIndex index)
static constexpr MainThreadFlags kPointersToHereAreInterestingMask
static constexpr MainThreadFlags kPointersFromHereAreInterestingMask
static Operand EmbeddedNumber(double number)
static V8_INLINE Operand Zero()
constexpr void set(RegisterT reg)
static constexpr RegListBase FromBits()
constexpr int8_t code() const
bool IsRootHandle(IndirectHandle< T > handle, RootIndex *index) const
Definition roots-inl.h:65
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static constexpr int32_t TypeToMarker(Type type)
Definition frames.h:196
static constexpr int kFrameTypeOffset
T * New(Args &&... args)
Definition zone.h:114
base::Vector< T > AllocateVector(size_t length)
Definition zone.h:136
void MoveToTempLocation(InstructionOperand *src, MachineRepresentation rep) final
void AssembleTailCallAfterGap(Instruction *instr, int first_unused_stack_slot)
void AssembleReturn(InstructionOperand *pop)
void AssembleTailCallBeforeGap(Instruction *instr, int first_unused_stack_slot)
FrameAccessState * frame_access_state() const
CodeGenResult AssembleArchInstruction(Instruction *instr)
DeoptimizationExit * BuildTranslation(Instruction *instr, int pc_offset, size_t frame_state_offset, size_t immediate_args_count, OutputFrameStateCombine state_combine)
void AssembleArchBinarySearchSwitch(Instruction *instr)
void AssembleArchJumpRegardlessOfAssemblyOrder(RpoNumber target)
static void GetPushCompatibleMoves(Instruction *instr, PushTypeFlags push_type, ZoneVector< MoveOperands * > *pushes)
void AssembleArchBoolean(Instruction *instr, FlagsCondition condition)
void AssembleJumpTable(base::Vector< Label * > targets)
void AssembleArchBranch(Instruction *instr, BranchInfo *branch)
void AssembleMove(InstructionOperand *source, InstructionOperand *destination) final
void SetPendingMove(MoveOperands *move) final
bool ShouldApplyOffsetToStackCheck(Instruction *instr, uint32_t *offset)
void RecordSafepoint(ReferenceMap *references, int pc_offset=0)
void AssembleArchBinarySearchSwitchRange(Register input, RpoNumber def_block, std::pair< int32_t, Label * > *begin, std::pair< int32_t, Label * > *end)
void PrepareForDeoptimizationExits(ZoneDeque< DeoptimizationExit * > *exits)
void AssembleArchTableSwitch(Instruction *instr)
bool IsMaterializableFromRoot(Handle< HeapObject > object, RootIndex *index_return)
ZoneDeque< DeoptimizationExit * > deoptimization_exits_
void AssembleArchConditionalBranch(Instruction *instr, BranchInfo *branch)
AllocatedOperand Push(InstructionOperand *src) final
void MoveTempLocationTo(InstructionOperand *dst, MachineRepresentation rep) final
void AssembleArchDeoptBranch(Instruction *instr, BranchInfo *branch)
void RecordCallPosition(Instruction *instr)
void AssembleSwap(InstructionOperand *source, InstructionOperand *destination) final
Label * AddJumpTable(base::Vector< Label * > targets)
void AssembleArchConditionalBoolean(Instruction *instr)
void RecordDeoptInfo(Instruction *instr, int pc_offset)
OptimizedCompilationInfo * info() const
void AssembleArchSelect(Instruction *instr, FlagsCondition condition)
void Pop(InstructionOperand *src, MachineRepresentation rep) final
FrameOffset GetFrameOffset(int spill_slot) const
Definition frame.cc:61
Constant ToConstant(InstructionOperand *op) const
InstructionCode opcode() const
const InstructionOperand * InputAt(size_t i) const
FlagsCondition flags_condition() const
CallDescriptor * GetIncomingDescriptor() const
Definition linkage.h:405
MachineRepresentation representation() const
static LocationOperand * cast(InstructionOperand *op)
static OutputFrameStateCombine Ignore()
PPCOperandConverter(CodeGenerator *gen, Instruction *instr)
MemOperand ToMemOperand(InstructionOperand *op) const
MemOperand MemoryOperand(AddressingMode *mode=NULL, size_t first_index=0)
MemOperand MemoryOperand(AddressingMode *mode, size_t *first_index)
IndirectPointerTag indirect_pointer_tag_
UnwindingInfoWriter *const unwinding_info_writer_
#define ATOMIC_BINOP_CASE(op, inst)
bool must_save_lr_
Zone * zone_
#define ASSEMBLE_IEEE754_UNOP(name)
Register const object_
Operand const offset_
#define ASSEMBLE_IEEE754_BINOP(name)
Register const value_
RecordWriteMode const mode_
Register const scratch1_
Register const scratch0_
#define ASSEMBLE_COMPARE(asm_instr)
#define EMIT_SIMD_BINOP_WITH_SCRATCH(name)
#define ASSEMBLE_STORE_FLOAT(asm_instr, asm_instrp, asm_instrx)
#define ASSEMBLE_ADD_WITH_OVERFLOW32()
#define ASSEMBLE_FLOAT_UNOP_RC(asm_instr, round)
#define EMIT_SIMD_UNOP(name)
#define EMIT_SIMD_QFM(name)
#define ASSEMBLE_FLOAT_COMPARE(cmp_instr)
#define ASSEMBLE_LOAD_FLOAT(asm_instr, asm_instrp, asm_instrx)
#define ASSEMBLE_BINOP_RC(asm_instr_reg, asm_instr_imm)
#define CleanUInt32(x)
#define ASSEMBLE_SUB_WITH_OVERFLOW()
#define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(_type, reverse_op)
#define ASSEMBLE_LOAD_INTEGER_RR(asm_instr)
int32_t const offset_immediate_
#define ASSEMBLE_LOAD_INTEGER(asm_instr, asm_instrp, asm_instrx, must_be_aligned)
#define EMIT_SIMD_STORE_LANE(name, op)
#define SIMD_LOAD_LANE_LIST(V)
#define ASSEMBLE_FLOAT_BINOP_RC(asm_instr, round)
#define EMIT_SIMD_LOAD_SPLAT(name, op)
#define PREP_LOAD_EXTEND()
#define ASSEMBLE_STORE_INTEGER_RR(asm_instr)
#define ASSEMBLE_FLOAT_MODULO()
#define ASSEMBLE_MODULO(div_instr, mul_instr)
#define DOUBLE_TO_INT32(op)
#define ASSEMBLE_BINOP_INT_RC(asm_instr_reg, asm_instr_imm)
#define EMIT_SIMD_ALL_TRUE(name)
#define ASSEMBLE_ATOMIC_EXCHANGE(_type, reverse_op)
#define EMIT_SIMD_BINOP(name)
#define EMIT_SIMD_EXT_ADD_PAIRWISE(name)
#define ASSEMBLE_ADD_WITH_OVERFLOW()
#define SIMD_STORE_LANE_LIST(V)
#define SIMD_LOAD_SPLAT(V)
#define EMIT_SIMD_SHIFT(name)
#define ASSEMBLE_STORE_INTEGER(asm_instr, asm_instrp, asm_instrx, must_be_aligned)
#define EMIT_SIMD_UNOP_WITH_SCRATCH(name)
#define ASSEMBLE_SUB_WITH_OVERFLOW32()
#define EMIT_SIMD_LOAD_LANE(name, op)
#define COMPRESS_POINTERS_BOOL
Definition globals.h:99
#define V8_EMBEDDED_CONSTANT_POOL_BOOL
Definition globals.h:81
#define V8_JS_LINKAGE_INCLUDES_DISPATCH_HANDLE_BOOL
Definition globals.h:161
#define CRWIDTH
int end
int32_t offset
Instruction * instr
ZoneVector< RpoNumber > & result
LiftoffRegister reg
int pc_offset
LiftoffRegList regs_to_save
uint32_t const mask
#define SIMD_UNOP_LIST(V)
#define SIMD_ALL_TRUE_LIST(V)
#define SIMD_BINOP_WITH_SCRATCH_LIST(V)
#define SIMD_BINOP_LIST(V)
#define SIMD_UNOP_WITH_SCRATCH_LIST(V)
#define SIMD_QFM_LIST(V)
#define SIMD_SHIFT_LIST(V)
#define SIMD_EXT_ADD_PAIRWISE_LIST(V)
SetIsolateDataSlots
InstructionOperand source
InstructionOperand destination
v8::SourceLocation SourceLocation
STL namespace.
int int32_t
Definition unicode.cc:40
uintptr_t Address
Definition memory.h:13
static bool HasRegisterInput(Instruction *instr, size_t index)
static Condition FlagsConditionToCondition(FlagsCondition condition)
static bool is_wasm_on_be(OptimizedCompilationInfo *info)
constexpr Register kGpParamRegisters[]
constexpr DoubleRegister kFpParamRegisters[]
uint32_t WasmInterpreterRuntime int64_t r0
constexpr Register kGpReturnRegisters[]
constexpr Register no_reg
constexpr Register kRootRegister
RegListBase< DoubleRegister > DoubleRegList
Definition reglist-arm.h:15
constexpr int kSimd128Size
Definition globals.h:706
V8_EXPORT_PRIVATE constexpr int ElementSizeInPointers(MachineRepresentation rep)
DwVfpRegister DoubleRegister
constexpr DoubleRegister kScratchDoubleReg
constexpr Simd128Register kScratchSimd128Reg
RegListBase< Register > RegList
Definition reglist-arm.h:14
V8_INLINE constexpr bool IsValidIndirectPointerTag(IndirectPointerTag tag)
Address Tagged_t
Definition globals.h:547
constexpr int kSystemPointerSizeLog2
Definition globals.h:494
constexpr Register kScratchReg
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats TracingFlags::gc_stats track native contexts that are expected to be garbage collected verify heap pointers before and after GC memory reducer runs GC with ReduceMemoryFootprint flag Maximum number of memory reducer GCs scheduled Old gen GC speed is computed directly from gc tracer counters Perform compaction on full GCs based on V8 s default heuristics Perform compaction on every full GC Perform code space compaction when finalizing a full GC with stack Stress GC compaction to flush out bugs with moving objects flush of baseline code when it has not been executed recently Use time base code flushing instead of age Use a progress bar to scan large objects in increments when incremental marking is active force incremental marking for small heaps and run it more often force marking at random points between and force scavenge at random points between and reclaim otherwise unreachable unmodified wrapper objects when possible less compaction in non memory reducing mode use high priority threads for concurrent Marking Test mode only flag It allows an unit test to select evacuation candidates use incremental marking for CppHeap cppheap_concurrent_marking c value for membalancer A special constant to balance between memory and space tradeoff The smaller the more memory it uses enable use of SSE4 instructions if available enable use of AVX VNNI instructions if available enable use of POPCNT instruction if available force all emitted branches to be in long mode(MIPS/PPC only)") DEFINE_BOOL(partial_constant_pool
constexpr Register kConstantPoolRegister
QwNeonRegister Simd128Register
MemOperand FieldMemOperand(Register object, int offset)
constexpr int kSystemPointerSize
Definition globals.h:410
constexpr bool IsFloatingPoint(MachineRepresentation rep)
constexpr Register kReturnRegister0
Condition NegateCondition(Condition cond)
constexpr Register kWasmImplicitArgRegister
V8_EXPORT_PRIVATE bool AreAliased(const CPURegister &reg1, const CPURegister &reg2, const CPURegister &reg3=NoReg, const CPURegister &reg4=NoReg, const CPURegister &reg5=NoReg, const CPURegister &reg6=NoReg, const CPURegister &reg7=NoReg, const CPURegister &reg8=NoReg)
const int kNumCalleeSavedDoubles
Definition reglist-ppc.h:59
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr bool IsSimd128(MachineRepresentation rep)
constexpr int kHasFunctionDescriptorBitMask
constexpr Register kJavaScriptCallCodeStartRegister
constexpr Register kPtrComprCageBaseRegister
return value
Definition map-inl.h:893
constexpr uint8_t kInstrSize
constexpr Register cp
constexpr Register kCArgRegs[]
constexpr int kDoubleSize
Definition globals.h:407
const int kNumCalleeSaved
Definition reglist-arm.h:48
constexpr Simd128Register kScratchSimd128Reg2
const uint32_t kClearedWeakHeapObjectLower32
Definition globals.h:981
static int FrameSlotToFPOffset(int slot)
BodyGen *const gen_
BodyGen * gen
ro::BitSet tagged_slots
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
constexpr bool IsAligned(T value, U alignment)
Definition macros.h:403
uint64_t make_uint64(uint32_t high, uint32_t low)
Definition macros.h:365
#define V8_STATIC_ROOTS_BOOL
Definition v8config.h:1001