V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
code-generator-ppc.cc
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/compiler/backend/code-generator.h"
6 
7 #include "src/assembler-inl.h"
8 #include "src/callable.h"
9 #include "src/compiler/backend/code-generator-impl.h"
10 #include "src/compiler/backend/gap-resolver.h"
11 #include "src/compiler/node-matchers.h"
12 #include "src/compiler/osr.h"
13 #include "src/double.h"
14 #include "src/macro-assembler.h"
15 #include "src/optimized-compilation-info.h"
16 #include "src/wasm/wasm-code-manager.h"
17 #include "src/wasm/wasm-objects.h"
18 
19 namespace v8 {
20 namespace internal {
21 namespace compiler {
22 
23 #define __ tasm()->
24 
25 #define kScratchReg r11
26 
27 // Adds PPC-specific methods to convert InstructionOperands.
29  public:
31  : InstructionOperandConverter(gen, instr) {}
32 
33  size_t OutputCount() { return instr_->OutputCount(); }
34 
35  RCBit OutputRCBit() const {
36  switch (instr_->flags_mode()) {
37  case kFlags_branch:
38  case kFlags_branch_and_poison:
39  case kFlags_deoptimize:
40  case kFlags_deoptimize_and_poison:
41  case kFlags_set:
42  case kFlags_trap:
43  return SetRC;
44  case kFlags_none:
45  return LeaveRC;
46  }
47  UNREACHABLE();
48  }
49 
50  bool CompareLogical() const {
51  switch (instr_->flags_condition()) {
52  case kUnsignedLessThan:
53  case kUnsignedGreaterThanOrEqual:
54  case kUnsignedLessThanOrEqual:
55  case kUnsignedGreaterThan:
56  return true;
57  default:
58  return false;
59  }
60  UNREACHABLE();
61  }
62 
63  Operand InputImmediate(size_t index) {
64  Constant constant = ToConstant(instr_->InputAt(index));
65  switch (constant.type()) {
66  case Constant::kInt32:
67  return Operand(constant.ToInt32());
68  case Constant::kFloat32:
69  return Operand::EmbeddedNumber(constant.ToFloat32());
70  case Constant::kFloat64:
71  return Operand::EmbeddedNumber(constant.ToFloat64().value());
72  case Constant::kInt64:
73 #if V8_TARGET_ARCH_PPC64
74  return Operand(constant.ToInt64());
75 #endif
76  case Constant::kExternalReference:
77  return Operand(constant.ToExternalReference());
78  case Constant::kDelayedStringConstant:
79  return Operand::EmbeddedStringConstant(
80  constant.ToDelayedStringConstant());
81  case Constant::kHeapObject:
82  case Constant::kRpoNumber:
83  break;
84  }
85  UNREACHABLE();
86  }
87 
88  MemOperand MemoryOperand(AddressingMode* mode, size_t* first_index) {
89  const size_t index = *first_index;
90  *mode = AddressingModeField::decode(instr_->opcode());
91  switch (*mode) {
92  case kMode_None:
93  break;
94  case kMode_MRI:
95  *first_index += 2;
96  return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
97  case kMode_MRR:
98  *first_index += 2;
99  return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
100  }
101  UNREACHABLE();
102  }
103 
104  MemOperand MemoryOperand(AddressingMode* mode, size_t first_index = 0) {
105  return MemoryOperand(mode, &first_index);
106  }
107 
108  MemOperand ToMemOperand(InstructionOperand* op) const {
109  DCHECK_NOT_NULL(op);
110  DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
111  return SlotToMemOperand(AllocatedOperand::cast(op)->index());
112  }
113 
114  MemOperand SlotToMemOperand(int slot) const {
115  FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
116  return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
117  }
118 };
119 
120 static inline bool HasRegisterInput(Instruction* instr, size_t index) {
121  return instr->InputAt(index)->IsRegister();
122 }
123 
124 namespace {
125 
126 class OutOfLineRecordWrite final : public OutOfLineCode {
127  public:
128  OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register offset,
129  Register value, Register scratch0, Register scratch1,
130  RecordWriteMode mode, StubCallMode stub_mode)
131  : OutOfLineCode(gen),
132  object_(object),
133  offset_(offset),
134  offset_immediate_(0),
135  value_(value),
136  scratch0_(scratch0),
137  scratch1_(scratch1),
138  mode_(mode),
139  stub_mode_(stub_mode),
140  must_save_lr_(!gen->frame_access_state()->has_frame()),
141  zone_(gen->zone()) {}
142 
143  OutOfLineRecordWrite(CodeGenerator* gen, Register object, int32_t offset,
144  Register value, Register scratch0, Register scratch1,
145  RecordWriteMode mode, StubCallMode stub_mode)
146  : OutOfLineCode(gen),
147  object_(object),
148  offset_(no_reg),
149  offset_immediate_(offset),
150  value_(value),
151  scratch0_(scratch0),
152  scratch1_(scratch1),
153  mode_(mode),
154  stub_mode_(stub_mode),
155  must_save_lr_(!gen->frame_access_state()->has_frame()),
156  zone_(gen->zone()) {}
157 
158  void Generate() final {
159  ConstantPoolUnavailableScope constant_pool_unavailable(tasm());
160  if (mode_ > RecordWriteMode::kValueIsPointer) {
161  __ JumpIfSmi(value_, exit());
162  }
163  __ CheckPageFlag(value_, scratch0_,
164  MemoryChunk::kPointersToHereAreInterestingMask, eq,
165  exit());
166  if (offset_ == no_reg) {
167  __ addi(scratch1_, object_, Operand(offset_immediate_));
168  } else {
169  DCHECK_EQ(0, offset_immediate_);
170  __ add(scratch1_, object_, offset_);
171  }
172  RememberedSetAction const remembered_set_action =
173  mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
174  : OMIT_REMEMBERED_SET;
175  SaveFPRegsMode const save_fp_mode =
176  frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
177  if (must_save_lr_) {
178  // We need to save and restore lr if the frame was elided.
179  __ mflr(scratch0_);
180  __ Push(scratch0_);
181  }
182  if (stub_mode_ == StubCallMode::kCallWasmRuntimeStub) {
183  __ CallRecordWriteStub(object_, scratch1_, remembered_set_action,
184  save_fp_mode, wasm::WasmCode::kWasmRecordWrite);
185  } else {
186  __ CallRecordWriteStub(object_, scratch1_, remembered_set_action,
187  save_fp_mode);
188  }
189  if (must_save_lr_) {
190  // We need to save and restore lr if the frame was elided.
191  __ Pop(scratch0_);
192  __ mtlr(scratch0_);
193  }
194  }
195 
196  private:
197  Register const object_;
198  Register const offset_;
199  int32_t const offset_immediate_; // Valid if offset_ == no_reg.
200  Register const value_;
201  Register const scratch0_;
202  Register const scratch1_;
203  RecordWriteMode const mode_;
204  StubCallMode stub_mode_;
205  bool must_save_lr_;
206  Zone* zone_;
207 };
208 
209 Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) {
210  switch (condition) {
211  case kEqual:
212  return eq;
213  case kNotEqual:
214  return ne;
215  case kSignedLessThan:
216  case kUnsignedLessThan:
217  return lt;
218  case kSignedGreaterThanOrEqual:
219  case kUnsignedGreaterThanOrEqual:
220  return ge;
221  case kSignedLessThanOrEqual:
222  case kUnsignedLessThanOrEqual:
223  return le;
224  case kSignedGreaterThan:
225  case kUnsignedGreaterThan:
226  return gt;
227  case kOverflow:
228  // Overflow checked for add/sub only.
229  switch (op) {
230 #if V8_TARGET_ARCH_PPC64
231  case kPPC_Add32:
232  case kPPC_Add64:
233  case kPPC_Sub:
234 #endif
235  case kPPC_AddWithOverflow32:
236  case kPPC_SubWithOverflow32:
237  return lt;
238  default:
239  break;
240  }
241  break;
242  case kNotOverflow:
243  switch (op) {
244 #if V8_TARGET_ARCH_PPC64
245  case kPPC_Add32:
246  case kPPC_Add64:
247  case kPPC_Sub:
248 #endif
249  case kPPC_AddWithOverflow32:
250  case kPPC_SubWithOverflow32:
251  return ge;
252  default:
253  break;
254  }
255  break;
256  default:
257  break;
258  }
259  UNREACHABLE();
260 }
261 
262 void EmitWordLoadPoisoningIfNeeded(CodeGenerator* codegen, Instruction* instr,
263  PPCOperandConverter& i) {
264  const MemoryAccessMode access_mode =
265  static_cast<MemoryAccessMode>(MiscField::decode(instr->opcode()));
266  if (access_mode == kMemoryAccessPoisoned) {
267  Register value = i.OutputRegister();
268  codegen->tasm()->and_(value, value, kSpeculationPoisonRegister);
269  }
270 }
271 
272 } // namespace
273 
274 #define ASSEMBLE_FLOAT_UNOP_RC(asm_instr, round) \
275  do { \
276  __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
277  i.OutputRCBit()); \
278  if (round) { \
279  __ frsp(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \
280  } \
281  } while (0)
282 
283 #define ASSEMBLE_FLOAT_BINOP_RC(asm_instr, round) \
284  do { \
285  __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
286  i.InputDoubleRegister(1), i.OutputRCBit()); \
287  if (round) { \
288  __ frsp(i.OutputDoubleRegister(), i.OutputDoubleRegister()); \
289  } \
290  } while (0)
291 
292 #define ASSEMBLE_BINOP(asm_instr_reg, asm_instr_imm) \
293  do { \
294  if (HasRegisterInput(instr, 1)) { \
295  __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \
296  i.InputRegister(1)); \
297  } else { \
298  __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \
299  i.InputImmediate(1)); \
300  } \
301  } while (0)
302 
303 #define ASSEMBLE_BINOP_RC(asm_instr_reg, asm_instr_imm) \
304  do { \
305  if (HasRegisterInput(instr, 1)) { \
306  __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \
307  i.InputRegister(1), i.OutputRCBit()); \
308  } else { \
309  __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \
310  i.InputImmediate(1), i.OutputRCBit()); \
311  } \
312  } while (0)
313 
314 #define ASSEMBLE_BINOP_INT_RC(asm_instr_reg, asm_instr_imm) \
315  do { \
316  if (HasRegisterInput(instr, 1)) { \
317  __ asm_instr_reg(i.OutputRegister(), i.InputRegister(0), \
318  i.InputRegister(1), i.OutputRCBit()); \
319  } else { \
320  __ asm_instr_imm(i.OutputRegister(), i.InputRegister(0), \
321  i.InputInt32(1), i.OutputRCBit()); \
322  } \
323  } while (0)
324 
325 #define ASSEMBLE_ADD_WITH_OVERFLOW() \
326  do { \
327  if (HasRegisterInput(instr, 1)) { \
328  __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
329  i.InputRegister(1), kScratchReg, r0); \
330  } else { \
331  __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
332  i.InputInt32(1), kScratchReg, r0); \
333  } \
334  } while (0)
335 
336 #define ASSEMBLE_SUB_WITH_OVERFLOW() \
337  do { \
338  if (HasRegisterInput(instr, 1)) { \
339  __ SubAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
340  i.InputRegister(1), kScratchReg, r0); \
341  } else { \
342  __ AddAndCheckForOverflow(i.OutputRegister(), i.InputRegister(0), \
343  -i.InputInt32(1), kScratchReg, r0); \
344  } \
345  } while (0)
346 
347 #if V8_TARGET_ARCH_PPC64
348 #define ASSEMBLE_ADD_WITH_OVERFLOW32() \
349  do { \
350  ASSEMBLE_ADD_WITH_OVERFLOW(); \
351  __ extsw(kScratchReg, kScratchReg, SetRC); \
352  } while (0)
353 
354 #define ASSEMBLE_SUB_WITH_OVERFLOW32() \
355  do { \
356  ASSEMBLE_SUB_WITH_OVERFLOW(); \
357  __ extsw(kScratchReg, kScratchReg, SetRC); \
358  } while (0)
359 #else
360 #define ASSEMBLE_ADD_WITH_OVERFLOW32 ASSEMBLE_ADD_WITH_OVERFLOW
361 #define ASSEMBLE_SUB_WITH_OVERFLOW32 ASSEMBLE_SUB_WITH_OVERFLOW
362 #endif
363 
364 #define ASSEMBLE_COMPARE(cmp_instr, cmpl_instr) \
365  do { \
366  const CRegister cr = cr0; \
367  if (HasRegisterInput(instr, 1)) { \
368  if (i.CompareLogical()) { \
369  __ cmpl_instr(i.InputRegister(0), i.InputRegister(1), cr); \
370  } else { \
371  __ cmp_instr(i.InputRegister(0), i.InputRegister(1), cr); \
372  } \
373  } else { \
374  if (i.CompareLogical()) { \
375  __ cmpl_instr##i(i.InputRegister(0), i.InputImmediate(1), cr); \
376  } else { \
377  __ cmp_instr##i(i.InputRegister(0), i.InputImmediate(1), cr); \
378  } \
379  } \
380  DCHECK_EQ(SetRC, i.OutputRCBit()); \
381  } while (0)
382 
383 #define ASSEMBLE_FLOAT_COMPARE(cmp_instr) \
384  do { \
385  const CRegister cr = cr0; \
386  __ cmp_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1), cr); \
387  DCHECK_EQ(SetRC, i.OutputRCBit()); \
388  } while (0)
389 
390 #define ASSEMBLE_MODULO(div_instr, mul_instr) \
391  do { \
392  const Register scratch = kScratchReg; \
393  __ div_instr(scratch, i.InputRegister(0), i.InputRegister(1)); \
394  __ mul_instr(scratch, scratch, i.InputRegister(1)); \
395  __ sub(i.OutputRegister(), i.InputRegister(0), scratch, LeaveOE, \
396  i.OutputRCBit()); \
397  } while (0)
398 
399 #define ASSEMBLE_FLOAT_MODULO() \
400  do { \
401  FrameScope scope(tasm(), StackFrame::MANUAL); \
402  __ PrepareCallCFunction(0, 2, kScratchReg); \
403  __ MovToFloatParameters(i.InputDoubleRegister(0), \
404  i.InputDoubleRegister(1)); \
405  __ CallCFunction(ExternalReference::mod_two_doubles_operation(), 0, 2); \
406  __ MovFromFloatResult(i.OutputDoubleRegister()); \
407  DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
408  } while (0)
409 
410 #define ASSEMBLE_IEEE754_UNOP(name) \
411  do { \
412  /* TODO(bmeurer): We should really get rid of this special instruction, */ \
413  /* and generate a CallAddress instruction instead. */ \
414  FrameScope scope(tasm(), StackFrame::MANUAL); \
415  __ PrepareCallCFunction(0, 1, kScratchReg); \
416  __ MovToFloatParameter(i.InputDoubleRegister(0)); \
417  __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 1); \
418  /* Move the result in the double result register. */ \
419  __ MovFromFloatResult(i.OutputDoubleRegister()); \
420  DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
421  } while (0)
422 
423 #define ASSEMBLE_IEEE754_BINOP(name) \
424  do { \
425  /* TODO(bmeurer): We should really get rid of this special instruction, */ \
426  /* and generate a CallAddress instruction instead. */ \
427  FrameScope scope(tasm(), StackFrame::MANUAL); \
428  __ PrepareCallCFunction(0, 2, kScratchReg); \
429  __ MovToFloatParameters(i.InputDoubleRegister(0), \
430  i.InputDoubleRegister(1)); \
431  __ CallCFunction(ExternalReference::ieee754_##name##_function(), 0, 2); \
432  /* Move the result in the double result register. */ \
433  __ MovFromFloatResult(i.OutputDoubleRegister()); \
434  DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
435  } while (0)
436 
437 #define ASSEMBLE_FLOAT_MAX() \
438  do { \
439  DoubleRegister left_reg = i.InputDoubleRegister(0); \
440  DoubleRegister right_reg = i.InputDoubleRegister(1); \
441  DoubleRegister result_reg = i.OutputDoubleRegister(); \
442  Label check_nan_left, check_zero, return_left, return_right, done; \
443  __ fcmpu(left_reg, right_reg); \
444  __ bunordered(&check_nan_left); \
445  __ beq(&check_zero); \
446  __ bge(&return_left); \
447  __ b(&return_right); \
448  \
449  __ bind(&check_zero); \
450  __ fcmpu(left_reg, kDoubleRegZero); \
451  /* left == right != 0. */ \
452  __ bne(&return_left); \
453  /* At this point, both left and right are either 0 or -0. */ \
454  __ fadd(result_reg, left_reg, right_reg); \
455  __ b(&done); \
456  \
457  __ bind(&check_nan_left); \
458  __ fcmpu(left_reg, left_reg); \
459  /* left == NaN. */ \
460  __ bunordered(&return_left); \
461  __ bind(&return_right); \
462  if (right_reg != result_reg) { \
463  __ fmr(result_reg, right_reg); \
464  } \
465  __ b(&done); \
466  \
467  __ bind(&return_left); \
468  if (left_reg != result_reg) { \
469  __ fmr(result_reg, left_reg); \
470  } \
471  __ bind(&done); \
472  } while (0)
473 
474 #define ASSEMBLE_FLOAT_MIN() \
475  do { \
476  DoubleRegister left_reg = i.InputDoubleRegister(0); \
477  DoubleRegister right_reg = i.InputDoubleRegister(1); \
478  DoubleRegister result_reg = i.OutputDoubleRegister(); \
479  Label check_nan_left, check_zero, return_left, return_right, done; \
480  __ fcmpu(left_reg, right_reg); \
481  __ bunordered(&check_nan_left); \
482  __ beq(&check_zero); \
483  __ ble(&return_left); \
484  __ b(&return_right); \
485  \
486  __ bind(&check_zero); \
487  __ fcmpu(left_reg, kDoubleRegZero); \
488  /* left == right != 0. */ \
489  __ bne(&return_left); \
490  /* At this point, both left and right are either 0 or -0. */ \
491  /* Min: The algorithm is: -((-L) + (-R)), which in case of L and R */ \
492  /* being different registers is most efficiently expressed */ \
493  /* as -((-L) - R). */ \
494  __ fneg(kScratchDoubleReg, left_reg); \
495  if (kScratchDoubleReg == right_reg) { \
496  __ fadd(result_reg, kScratchDoubleReg, right_reg); \
497  } else { \
498  __ fsub(result_reg, kScratchDoubleReg, right_reg); \
499  } \
500  __ fneg(result_reg, result_reg); \
501  __ b(&done); \
502  \
503  __ bind(&check_nan_left); \
504  __ fcmpu(left_reg, left_reg); \
505  /* left == NaN. */ \
506  __ bunordered(&return_left); \
507  \
508  __ bind(&return_right); \
509  if (right_reg != result_reg) { \
510  __ fmr(result_reg, right_reg); \
511  } \
512  __ b(&done); \
513  \
514  __ bind(&return_left); \
515  if (left_reg != result_reg) { \
516  __ fmr(result_reg, left_reg); \
517  } \
518  __ bind(&done); \
519  } while (0)
520 
521 #define ASSEMBLE_LOAD_FLOAT(asm_instr, asm_instrx) \
522  do { \
523  DoubleRegister result = i.OutputDoubleRegister(); \
524  AddressingMode mode = kMode_None; \
525  MemOperand operand = i.MemoryOperand(&mode); \
526  bool is_atomic = i.InputInt32(2); \
527  if (mode == kMode_MRI) { \
528  __ asm_instr(result, operand); \
529  } else { \
530  __ asm_instrx(result, operand); \
531  } \
532  if (is_atomic) __ lwsync(); \
533  DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
534  } while (0)
535 
536 #define ASSEMBLE_LOAD_INTEGER(asm_instr, asm_instrx) \
537  do { \
538  Register result = i.OutputRegister(); \
539  AddressingMode mode = kMode_None; \
540  MemOperand operand = i.MemoryOperand(&mode); \
541  bool is_atomic = i.InputInt32(2); \
542  if (mode == kMode_MRI) { \
543  __ asm_instr(result, operand); \
544  } else { \
545  __ asm_instrx(result, operand); \
546  } \
547  if (is_atomic) __ lwsync(); \
548  DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
549  } while (0)
550 
551 #define ASSEMBLE_STORE_FLOAT(asm_instr, asm_instrx) \
552  do { \
553  size_t index = 0; \
554  AddressingMode mode = kMode_None; \
555  MemOperand operand = i.MemoryOperand(&mode, &index); \
556  DoubleRegister value = i.InputDoubleRegister(index); \
557  bool is_atomic = i.InputInt32(3); \
558  if (is_atomic) __ lwsync(); \
559  /* removed frsp as instruction-selector checked */ \
560  /* value to be kFloat32 */ \
561  if (mode == kMode_MRI) { \
562  __ asm_instr(value, operand); \
563  } else { \
564  __ asm_instrx(value, operand); \
565  } \
566  if (is_atomic) __ sync(); \
567  DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
568  } while (0)
569 
570 #define ASSEMBLE_STORE_INTEGER(asm_instr, asm_instrx) \
571  do { \
572  size_t index = 0; \
573  AddressingMode mode = kMode_None; \
574  MemOperand operand = i.MemoryOperand(&mode, &index); \
575  Register value = i.InputRegister(index); \
576  bool is_atomic = i.InputInt32(3); \
577  if (is_atomic) __ lwsync(); \
578  if (mode == kMode_MRI) { \
579  __ asm_instr(value, operand); \
580  } else { \
581  __ asm_instrx(value, operand); \
582  } \
583  if (is_atomic) __ sync(); \
584  DCHECK_EQ(LeaveRC, i.OutputRCBit()); \
585  } while (0)
586 
587 #if V8_TARGET_ARCH_PPC64
588 // TODO(mbrandy): fix paths that produce garbage in offset's upper 32-bits.
589 #define CleanUInt32(x) __ ClearLeftImm(x, x, Operand(32))
590 #else
591 #define CleanUInt32(x)
592 #endif
593 
594 #define ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(load_instr, store_instr) \
595  do { \
596  Label exchange; \
597  __ lwsync(); \
598  __ bind(&exchange); \
599  __ load_instr(i.OutputRegister(0), \
600  MemOperand(i.InputRegister(0), i.InputRegister(1))); \
601  __ store_instr(i.InputRegister(2), \
602  MemOperand(i.InputRegister(0), i.InputRegister(1))); \
603  __ bne(&exchange, cr0); \
604  __ sync(); \
605  } while (0)
606 
607 #define ASSEMBLE_ATOMIC_BINOP(bin_inst, load_inst, store_inst) \
608  do { \
609  MemOperand operand = MemOperand(i.InputRegister(0), i.InputRegister(1)); \
610  Label binop; \
611  __ lwsync(); \
612  __ bind(&binop); \
613  __ load_inst(i.OutputRegister(), operand); \
614  __ bin_inst(kScratchReg, i.OutputRegister(), i.InputRegister(2)); \
615  __ store_inst(kScratchReg, operand); \
616  __ bne(&binop, cr0); \
617  __ sync(); \
618  } while (false)
619 
620 #define ASSEMBLE_ATOMIC_BINOP_SIGN_EXT(bin_inst, load_inst, store_inst, \
621  ext_instr) \
622  do { \
623  MemOperand operand = MemOperand(i.InputRegister(0), i.InputRegister(1)); \
624  Label binop; \
625  __ lwsync(); \
626  __ bind(&binop); \
627  __ load_inst(i.OutputRegister(), operand); \
628  __ ext_instr(i.OutputRegister(), i.OutputRegister()); \
629  __ bin_inst(kScratchReg, i.OutputRegister(), i.InputRegister(2)); \
630  __ store_inst(kScratchReg, operand); \
631  __ bne(&binop, cr0); \
632  __ sync(); \
633  } while (false)
634 
635 #define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(cmp_inst, load_inst, store_inst) \
636  do { \
637  MemOperand operand = MemOperand(i.InputRegister(0), i.InputRegister(1)); \
638  Label loop; \
639  Label exit; \
640  __ lwsync(); \
641  __ bind(&loop); \
642  __ load_inst(i.OutputRegister(), operand); \
643  __ cmp_inst(i.OutputRegister(), i.InputRegister(2), cr0); \
644  __ bne(&exit, cr0); \
645  __ store_inst(i.InputRegister(3), operand); \
646  __ bne(&loop, cr0); \
647  __ bind(&exit); \
648  __ sync(); \
649  } while (false)
650 
651 #define ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_SIGN_EXT(cmp_inst, load_inst, \
652  store_inst, ext_instr) \
653  do { \
654  MemOperand operand = MemOperand(i.InputRegister(0), i.InputRegister(1)); \
655  Label loop; \
656  Label exit; \
657  __ lwsync(); \
658  __ bind(&loop); \
659  __ load_inst(i.OutputRegister(), operand); \
660  __ ext_instr(i.OutputRegister(), i.OutputRegister()); \
661  __ cmp_inst(i.OutputRegister(), i.InputRegister(2)); \
662  __ bne(&exit, cr0); \
663  __ store_inst(i.InputRegister(3), operand); \
664  __ bne(&loop, cr0); \
665  __ bind(&exit); \
666  __ sync(); \
667  } while (false)
668 
669 void CodeGenerator::AssembleDeconstructFrame() {
670  __ LeaveFrame(StackFrame::MANUAL);
671 }
672 
673 void CodeGenerator::AssemblePrepareTailCall() {
674  if (frame_access_state()->has_frame()) {
675  __ RestoreFrameStateForTailCall();
676  }
677  frame_access_state()->SetFrameAccessToSP();
678 }
679 
680 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
681  Register scratch1,
682  Register scratch2,
683  Register scratch3) {
684  DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
685  Label done;
686 
687  // Check if current frame is an arguments adaptor frame.
688  __ LoadP(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset));
689  __ cmpi(scratch1,
690  Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
691  __ bne(&done);
692 
693  // Load arguments count from current arguments adaptor frame (note, it
694  // does not include receiver).
695  Register caller_args_count_reg = scratch1;
696  __ LoadP(caller_args_count_reg,
697  MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
698  __ SmiUntag(caller_args_count_reg);
699 
700  ParameterCount callee_args_count(args_reg);
701  __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
702  scratch3);
703  __ bind(&done);
704 }
705 
706 namespace {
707 
708 void FlushPendingPushRegisters(TurboAssembler* tasm,
709  FrameAccessState* frame_access_state,
710  ZoneVector<Register>* pending_pushes) {
711  switch (pending_pushes->size()) {
712  case 0:
713  break;
714  case 1:
715  tasm->Push((*pending_pushes)[0]);
716  break;
717  case 2:
718  tasm->Push((*pending_pushes)[0], (*pending_pushes)[1]);
719  break;
720  case 3:
721  tasm->Push((*pending_pushes)[0], (*pending_pushes)[1],
722  (*pending_pushes)[2]);
723  break;
724  default:
725  UNREACHABLE();
726  break;
727  }
728  frame_access_state->IncreaseSPDelta(pending_pushes->size());
729  pending_pushes->clear();
730 }
731 
732 void AdjustStackPointerForTailCall(
733  TurboAssembler* tasm, FrameAccessState* state, int new_slot_above_sp,
734  ZoneVector<Register>* pending_pushes = nullptr,
735  bool allow_shrinkage = true) {
736  int current_sp_offset = state->GetSPToFPSlotCount() +
737  StandardFrameConstants::kFixedSlotCountAboveFp;
738  int stack_slot_delta = new_slot_above_sp - current_sp_offset;
739  if (stack_slot_delta > 0) {
740  if (pending_pushes != nullptr) {
741  FlushPendingPushRegisters(tasm, state, pending_pushes);
742  }
743  tasm->Add(sp, sp, -stack_slot_delta * kPointerSize, r0);
744  state->IncreaseSPDelta(stack_slot_delta);
745  } else if (allow_shrinkage && stack_slot_delta < 0) {
746  if (pending_pushes != nullptr) {
747  FlushPendingPushRegisters(tasm, state, pending_pushes);
748  }
749  tasm->Add(sp, sp, -stack_slot_delta * kPointerSize, r0);
750  state->IncreaseSPDelta(stack_slot_delta);
751  }
752 }
753 
754 } // namespace
755 
756 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
757  int first_unused_stack_slot) {
758  ZoneVector<MoveOperands*> pushes(zone());
759  GetPushCompatibleMoves(instr, kRegisterPush, &pushes);
760 
761  if (!pushes.empty() &&
762  (LocationOperand::cast(pushes.back()->destination()).index() + 1 ==
763  first_unused_stack_slot)) {
764  PPCOperandConverter g(this, instr);
765  ZoneVector<Register> pending_pushes(zone());
766  for (auto move : pushes) {
767  LocationOperand destination_location(
768  LocationOperand::cast(move->destination()));
769  InstructionOperand source(move->source());
770  AdjustStackPointerForTailCall(
771  tasm(), frame_access_state(),
772  destination_location.index() - pending_pushes.size(),
773  &pending_pushes);
774  // Pushes of non-register data types are not supported.
775  DCHECK(source.IsRegister());
776  LocationOperand source_location(LocationOperand::cast(source));
777  pending_pushes.push_back(source_location.GetRegister());
778  // TODO(arm): We can push more than 3 registers at once. Add support in
779  // the macro-assembler for pushing a list of registers.
780  if (pending_pushes.size() == 3) {
781  FlushPendingPushRegisters(tasm(), frame_access_state(),
782  &pending_pushes);
783  }
784  move->Eliminate();
785  }
786  FlushPendingPushRegisters(tasm(), frame_access_state(), &pending_pushes);
787  }
788  AdjustStackPointerForTailCall(tasm(), frame_access_state(),
789  first_unused_stack_slot, nullptr, false);
790 }
791 
792 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
793  int first_unused_stack_slot) {
794  AdjustStackPointerForTailCall(tasm(), frame_access_state(),
795  first_unused_stack_slot);
796 }
797 
798 // Check that {kJavaScriptCallCodeStartRegister} is correct.
799 void CodeGenerator::AssembleCodeStartRegisterCheck() {
800  Register scratch = kScratchReg;
801  __ ComputeCodeStartAddress(scratch);
802  __ cmp(scratch, kJavaScriptCallCodeStartRegister);
803  __ Assert(eq, AbortReason::kWrongFunctionCodeStart);
804 }
805 
806 // Check if the code object is marked for deoptimization. If it is, then it
807 // jumps to the CompileLazyDeoptimizedCode builtin. In order to do this we need
808 // to:
809 // 1. read from memory the word that contains that bit, which can be found in
810 // the flags in the referenced {CodeDataContainer} object;
811 // 2. test kMarkedForDeoptimizationBit in those flags; and
812 // 3. if it is not zero then it jumps to the builtin.
813 void CodeGenerator::BailoutIfDeoptimized() {
814  if (FLAG_debug_code) {
815  // Check that {kJavaScriptCallCodeStartRegister} is correct.
816  __ ComputeCodeStartAddress(ip);
817  __ cmp(ip, kJavaScriptCallCodeStartRegister);
818  __ Assert(eq, AbortReason::kWrongFunctionCodeStart);
819  }
820 
821  int offset = Code::kCodeDataContainerOffset - Code::kHeaderSize;
822  __ LoadP(r11, MemOperand(kJavaScriptCallCodeStartRegister, offset));
823  __ LoadWordArith(
824  r11, FieldMemOperand(r11, CodeDataContainer::kKindSpecificFlagsOffset));
825  __ TestBit(r11, Code::kMarkedForDeoptimizationBit);
826  // Ensure we're not serializing (otherwise we'd need to use an indirection to
827  // access the builtin below).
828  DCHECK(!isolate()->ShouldLoadConstantsFromRootList());
829  Handle<Code> code = isolate()->builtins()->builtin_handle(
830  Builtins::kCompileLazyDeoptimizedCode);
831  __ Jump(code, RelocInfo::CODE_TARGET, ne, cr0);
832 }
833 
834 void CodeGenerator::GenerateSpeculationPoisonFromCodeStartRegister() {
835  Register scratch = kScratchReg;
836 
837  __ ComputeCodeStartAddress(scratch);
838 
839  // Calculate a mask which has all bits set in the normal case, but has all
840  // bits cleared if we are speculatively executing the wrong PC.
841  __ cmp(kJavaScriptCallCodeStartRegister, scratch);
842  __ li(scratch, Operand::Zero());
843  __ notx(kSpeculationPoisonRegister, scratch);
844  __ isel(eq, kSpeculationPoisonRegister, kSpeculationPoisonRegister, scratch);
845 }
846 
847 void CodeGenerator::AssembleRegisterArgumentPoisoning() {
848  __ and_(kJSFunctionRegister, kJSFunctionRegister, kSpeculationPoisonRegister);
849  __ and_(kContextRegister, kContextRegister, kSpeculationPoisonRegister);
850  __ and_(sp, sp, kSpeculationPoisonRegister);
851 }
852 
853 // Assembles an instruction after register allocation, producing machine code.
854 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
855  Instruction* instr) {
856  PPCOperandConverter i(this, instr);
857  ArchOpcode opcode = ArchOpcodeField::decode(instr->opcode());
858 
859  switch (opcode) {
860  case kArchCallCodeObject: {
862  tasm());
863  if (HasRegisterInput(instr, 0)) {
864  Register reg = i.InputRegister(0);
865  DCHECK_IMPLIES(
866  HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister),
867  reg == kJavaScriptCallCodeStartRegister);
868  __ addi(reg, reg, Operand(Code::kHeaderSize - kHeapObjectTag));
869  __ Call(reg);
870  } else {
871  __ Call(i.InputCode(0), RelocInfo::CODE_TARGET);
872  }
873  RecordCallPosition(instr);
874  DCHECK_EQ(LeaveRC, i.OutputRCBit());
875  frame_access_state()->ClearSPDelta();
876  break;
877  }
878  case kArchCallWasmFunction: {
879  // We must not share code targets for calls to builtins for wasm code, as
880  // they might need to be patched individually.
881  if (instr->InputAt(0)->IsImmediate()) {
882  Constant constant = i.ToConstant(instr->InputAt(0));
883 #ifdef V8_TARGET_ARCH_PPC64
884  Address wasm_code = static_cast<Address>(constant.ToInt64());
885 #else
886  Address wasm_code = static_cast<Address>(constant.ToInt32());
887 #endif
888  __ Call(wasm_code, constant.rmode());
889  } else {
890  __ Call(i.InputRegister(0));
891  }
892  RecordCallPosition(instr);
893  DCHECK_EQ(LeaveRC, i.OutputRCBit());
894  frame_access_state()->ClearSPDelta();
895  break;
896  }
897  case kArchTailCallCodeObjectFromJSFunction:
898  case kArchTailCallCodeObject: {
899  if (opcode == kArchTailCallCodeObjectFromJSFunction) {
900  AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
901  i.TempRegister(0), i.TempRegister(1),
902  i.TempRegister(2));
903  }
904  if (HasRegisterInput(instr, 0)) {
905  Register reg = i.InputRegister(0);
906  DCHECK_IMPLIES(
907  HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister),
908  reg == kJavaScriptCallCodeStartRegister);
909  __ addi(reg, reg, Operand(Code::kHeaderSize - kHeapObjectTag));
910  __ Jump(reg);
911  } else {
912  // We cannot use the constant pool to load the target since
913  // we've already restored the caller's frame.
914  ConstantPoolUnavailableScope constant_pool_unavailable(tasm());
915  __ Jump(i.InputCode(0), RelocInfo::CODE_TARGET);
916  }
917  DCHECK_EQ(LeaveRC, i.OutputRCBit());
918  frame_access_state()->ClearSPDelta();
919  frame_access_state()->SetFrameAccessToDefault();
920  break;
921  }
922  case kArchTailCallWasm: {
923  // We must not share code targets for calls to builtins for wasm code, as
924  // they might need to be patched individually.
925  if (instr->InputAt(0)->IsImmediate()) {
926  Constant constant = i.ToConstant(instr->InputAt(0));
927 #ifdef V8_TARGET_ARCH_S390X
928  Address wasm_code = static_cast<Address>(constant.ToInt64());
929 #else
930  Address wasm_code = static_cast<Address>(constant.ToInt32());
931 #endif
932  __ Jump(wasm_code, constant.rmode());
933  } else {
934  __ Jump(i.InputRegister(0));
935  }
936  DCHECK_EQ(LeaveRC, i.OutputRCBit());
937  frame_access_state()->ClearSPDelta();
938  frame_access_state()->SetFrameAccessToDefault();
939  break;
940  }
941  case kArchTailCallAddress: {
942  CHECK(!instr->InputAt(0)->IsImmediate());
943  Register reg = i.InputRegister(0);
944  DCHECK_IMPLIES(
945  HasCallDescriptorFlag(instr, CallDescriptor::kFixedTargetRegister),
946  reg == kJavaScriptCallCodeStartRegister);
947  __ Jump(reg);
948  frame_access_state()->ClearSPDelta();
949  frame_access_state()->SetFrameAccessToDefault();
950  break;
951  }
952  case kArchCallJSFunction: {
954  tasm());
955  Register func = i.InputRegister(0);
956  if (FLAG_debug_code) {
957  // Check the function's context matches the context argument.
958  __ LoadP(kScratchReg,
959  FieldMemOperand(func, JSFunction::kContextOffset));
960  __ cmp(cp, kScratchReg);
961  __ Assert(eq, AbortReason::kWrongFunctionContext);
962  }
963  static_assert(kJavaScriptCallCodeStartRegister == r5, "ABI mismatch");
964  __ LoadP(r5, FieldMemOperand(func, JSFunction::kCodeOffset));
965  __ addi(r5, r5, Operand(Code::kHeaderSize - kHeapObjectTag));
966  __ Call(r5);
967  RecordCallPosition(instr);
968  DCHECK_EQ(LeaveRC, i.OutputRCBit());
969  frame_access_state()->ClearSPDelta();
970  break;
971  }
972  case kArchPrepareCallCFunction: {
973  int const num_parameters = MiscField::decode(instr->opcode());
974  __ PrepareCallCFunction(num_parameters, kScratchReg);
975  // Frame alignment requires using FP-relative frame addressing.
976  frame_access_state()->SetFrameAccessToFP();
977  break;
978  }
979  case kArchSaveCallerRegisters: {
980  fp_mode_ =
981  static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode()));
982  DCHECK(fp_mode_ == kDontSaveFPRegs || fp_mode_ == kSaveFPRegs);
983  // kReturnRegister0 should have been saved before entering the stub.
984  int bytes = __ PushCallerSaved(fp_mode_, kReturnRegister0);
985  DCHECK_EQ(0, bytes % kPointerSize);
986  DCHECK_EQ(0, frame_access_state()->sp_delta());
987  frame_access_state()->IncreaseSPDelta(bytes / kPointerSize);
988  DCHECK(!caller_registers_saved_);
989  caller_registers_saved_ = true;
990  break;
991  }
992  case kArchRestoreCallerRegisters: {
993  DCHECK(fp_mode_ ==
994  static_cast<SaveFPRegsMode>(MiscField::decode(instr->opcode())));
995  DCHECK(fp_mode_ == kDontSaveFPRegs || fp_mode_ == kSaveFPRegs);
996  // Don't overwrite the returned value.
997  int bytes = __ PopCallerSaved(fp_mode_, kReturnRegister0);
998  frame_access_state()->IncreaseSPDelta(-(bytes / kPointerSize));
999  DCHECK_EQ(0, frame_access_state()->sp_delta());
1000  DCHECK(caller_registers_saved_);
1001  caller_registers_saved_ = false;
1002  break;
1003  }
1004  case kArchPrepareTailCall:
1005  AssemblePrepareTailCall();
1006  break;
1007  case kArchComment:
1008 #ifdef V8_TARGET_ARCH_PPC64
1009  __ RecordComment(reinterpret_cast<const char*>(i.InputInt64(0)));
1010 #else
1011  __ RecordComment(reinterpret_cast<const char*>(i.InputInt32(0)));
1012 #endif
1013  break;
1014  case kArchCallCFunction: {
1015  int const num_parameters = MiscField::decode(instr->opcode());
1016  if (instr->InputAt(0)->IsImmediate()) {
1017  ExternalReference ref = i.InputExternalReference(0);
1018  __ CallCFunction(ref, num_parameters);
1019  } else {
1020  Register func = i.InputRegister(0);
1021  __ CallCFunction(func, num_parameters);
1022  }
1023  frame_access_state()->SetFrameAccessToDefault();
1024  // Ideally, we should decrement SP delta to match the change of stack
1025  // pointer in CallCFunction. However, for certain architectures (e.g.
1026  // ARM), there may be more strict alignment requirement, causing old SP
1027  // to be saved on the stack. In those cases, we can not calculate the SP
1028  // delta statically.
1029  frame_access_state()->ClearSPDelta();
1030  if (caller_registers_saved_) {
1031  // Need to re-sync SP delta introduced in kArchSaveCallerRegisters.
1032  // Here, we assume the sequence to be:
1033  // kArchSaveCallerRegisters;
1034  // kArchCallCFunction;
1035  // kArchRestoreCallerRegisters;
1036  int bytes =
1037  __ RequiredStackSizeForCallerSaved(fp_mode_, kReturnRegister0);
1038  frame_access_state()->IncreaseSPDelta(bytes / kPointerSize);
1039  }
1040  break;
1041  }
1042  case kArchJmp:
1043  AssembleArchJump(i.InputRpo(0));
1044  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1045  break;
1046  case kArchBinarySearchSwitch:
1047  AssembleArchBinarySearchSwitch(instr);
1048  break;
1049  case kArchLookupSwitch:
1050  AssembleArchLookupSwitch(instr);
1051  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1052  break;
1053  case kArchTableSwitch:
1054  AssembleArchTableSwitch(instr);
1055  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1056  break;
1057  case kArchDebugAbort:
1058  DCHECK(i.InputRegister(0) == r4);
1059  if (!frame_access_state()->has_frame()) {
1060  // We don't actually want to generate a pile of code for this, so just
1061  // claim there is a stack frame, without generating one.
1062  FrameScope scope(tasm(), StackFrame::NONE);
1063  __ Call(isolate()->builtins()->builtin_handle(Builtins::kAbortJS),
1064  RelocInfo::CODE_TARGET);
1065  } else {
1066  __ Call(isolate()->builtins()->builtin_handle(Builtins::kAbortJS),
1067  RelocInfo::CODE_TARGET);
1068  }
1069  __ stop("kArchDebugAbort");
1070  break;
1071  case kArchDebugBreak:
1072  __ stop("kArchDebugBreak");
1073  break;
1074  case kArchNop:
1075  case kArchThrowTerminator:
1076  // don't emit code for nops.
1077  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1078  break;
1079  case kArchDeoptimize: {
1080  int deopt_state_id =
1081  BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
1082  CodeGenResult result =
1083  AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
1084  if (result != kSuccess) return result;
1085  break;
1086  }
1087  case kArchRet:
1088  AssembleReturn(instr->InputAt(0));
1089  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1090  break;
1091  case kArchStackPointer:
1092  __ mr(i.OutputRegister(), sp);
1093  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1094  break;
1095  case kArchFramePointer:
1096  __ mr(i.OutputRegister(), fp);
1097  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1098  break;
1099  case kArchParentFramePointer:
1100  if (frame_access_state()->has_frame()) {
1101  __ LoadP(i.OutputRegister(), MemOperand(fp, 0));
1102  } else {
1103  __ mr(i.OutputRegister(), fp);
1104  }
1105  break;
1106  case kArchTruncateDoubleToI:
1107  __ TruncateDoubleToI(isolate(), zone(), i.OutputRegister(),
1108  i.InputDoubleRegister(0), DetermineStubCallMode());
1109  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1110  break;
1111  case kArchStoreWithWriteBarrier: {
1112  RecordWriteMode mode =
1113  static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
1114  Register object = i.InputRegister(0);
1115  Register value = i.InputRegister(2);
1116  Register scratch0 = i.TempRegister(0);
1117  Register scratch1 = i.TempRegister(1);
1118  OutOfLineRecordWrite* ool;
1119 
1120  AddressingMode addressing_mode =
1121  AddressingModeField::decode(instr->opcode());
1122  if (addressing_mode == kMode_MRI) {
1123  int32_t offset = i.InputInt32(1);
1124  ool = new (zone())
1125  OutOfLineRecordWrite(this, object, offset, value, scratch0,
1126  scratch1, mode, DetermineStubCallMode());
1127  __ StoreP(value, MemOperand(object, offset));
1128  } else {
1129  DCHECK_EQ(kMode_MRR, addressing_mode);
1130  Register offset(i.InputRegister(1));
1131  ool = new (zone())
1132  OutOfLineRecordWrite(this, object, offset, value, scratch0,
1133  scratch1, mode, DetermineStubCallMode());
1134  __ StorePX(value, MemOperand(object, offset));
1135  }
1136  __ CheckPageFlag(object, scratch0,
1137  MemoryChunk::kPointersFromHereAreInterestingMask, ne,
1138  ool->entry());
1139  __ bind(ool->exit());
1140  break;
1141  }
1142  case kArchStackSlot: {
1143  FrameOffset offset =
1144  frame_access_state()->GetFrameOffset(i.InputInt32(0));
1145  __ addi(i.OutputRegister(), offset.from_stack_pointer() ? sp : fp,
1146  Operand(offset.offset()));
1147  break;
1148  }
1149  case kArchWordPoisonOnSpeculation:
1150  __ and_(i.OutputRegister(), i.InputRegister(0),
1151  kSpeculationPoisonRegister);
1152  break;
1153  case kPPC_And:
1154  if (HasRegisterInput(instr, 1)) {
1155  __ and_(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1156  i.OutputRCBit());
1157  } else {
1158  __ andi(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
1159  }
1160  break;
1161  case kPPC_AndComplement:
1162  __ andc(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1163  i.OutputRCBit());
1164  break;
1165  case kPPC_Or:
1166  if (HasRegisterInput(instr, 1)) {
1167  __ orx(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1168  i.OutputRCBit());
1169  } else {
1170  __ ori(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
1171  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1172  }
1173  break;
1174  case kPPC_OrComplement:
1175  __ orc(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1176  i.OutputRCBit());
1177  break;
1178  case kPPC_Xor:
1179  if (HasRegisterInput(instr, 1)) {
1180  __ xor_(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1181  i.OutputRCBit());
1182  } else {
1183  __ xori(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
1184  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1185  }
1186  break;
1187  case kPPC_ShiftLeft32:
1188  ASSEMBLE_BINOP_RC(slw, slwi);
1189  break;
1190 #if V8_TARGET_ARCH_PPC64
1191  case kPPC_ShiftLeft64:
1192  ASSEMBLE_BINOP_RC(sld, sldi);
1193  break;
1194 #endif
1195  case kPPC_ShiftRight32:
1196  ASSEMBLE_BINOP_RC(srw, srwi);
1197  break;
1198 #if V8_TARGET_ARCH_PPC64
1199  case kPPC_ShiftRight64:
1200  ASSEMBLE_BINOP_RC(srd, srdi);
1201  break;
1202 #endif
1203  case kPPC_ShiftRightAlg32:
1204  ASSEMBLE_BINOP_INT_RC(sraw, srawi);
1205  break;
1206 #if V8_TARGET_ARCH_PPC64
1207  case kPPC_ShiftRightAlg64:
1208  ASSEMBLE_BINOP_INT_RC(srad, sradi);
1209  break;
1210 #endif
1211 #if !V8_TARGET_ARCH_PPC64
1212  case kPPC_AddPair:
1213  // i.InputRegister(0) ... left low word.
1214  // i.InputRegister(1) ... left high word.
1215  // i.InputRegister(2) ... right low word.
1216  // i.InputRegister(3) ... right high word.
1217  __ addc(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2));
1218  __ adde(i.OutputRegister(1), i.InputRegister(1), i.InputRegister(3));
1219  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1220  break;
1221  case kPPC_SubPair:
1222  // i.InputRegister(0) ... left low word.
1223  // i.InputRegister(1) ... left high word.
1224  // i.InputRegister(2) ... right low word.
1225  // i.InputRegister(3) ... right high word.
1226  __ subc(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2));
1227  __ sube(i.OutputRegister(1), i.InputRegister(1), i.InputRegister(3));
1228  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1229  break;
1230  case kPPC_MulPair:
1231  // i.InputRegister(0) ... left low word.
1232  // i.InputRegister(1) ... left high word.
1233  // i.InputRegister(2) ... right low word.
1234  // i.InputRegister(3) ... right high word.
1235  __ mullw(i.TempRegister(0), i.InputRegister(0), i.InputRegister(3));
1236  __ mullw(i.TempRegister(1), i.InputRegister(2), i.InputRegister(1));
1237  __ add(i.TempRegister(0), i.TempRegister(0), i.TempRegister(1));
1238  __ mullw(i.OutputRegister(0), i.InputRegister(0), i.InputRegister(2));
1239  __ mulhwu(i.OutputRegister(1), i.InputRegister(0), i.InputRegister(2));
1240  __ add(i.OutputRegister(1), i.OutputRegister(1), i.TempRegister(0));
1241  break;
1242  case kPPC_ShiftLeftPair: {
1243  Register second_output =
1244  instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1245  if (instr->InputAt(2)->IsImmediate()) {
1246  __ ShiftLeftPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1247  i.InputRegister(1), i.InputInt32(2));
1248  } else {
1249  __ ShiftLeftPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1250  i.InputRegister(1), kScratchReg, i.InputRegister(2));
1251  }
1252  break;
1253  }
1254  case kPPC_ShiftRightPair: {
1255  Register second_output =
1256  instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1257  if (instr->InputAt(2)->IsImmediate()) {
1258  __ ShiftRightPair(i.OutputRegister(0), second_output,
1259  i.InputRegister(0), i.InputRegister(1),
1260  i.InputInt32(2));
1261  } else {
1262  __ ShiftRightPair(i.OutputRegister(0), second_output,
1263  i.InputRegister(0), i.InputRegister(1), kScratchReg,
1264  i.InputRegister(2));
1265  }
1266  break;
1267  }
1268  case kPPC_ShiftRightAlgPair: {
1269  Register second_output =
1270  instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1271  if (instr->InputAt(2)->IsImmediate()) {
1272  __ ShiftRightAlgPair(i.OutputRegister(0), second_output,
1273  i.InputRegister(0), i.InputRegister(1),
1274  i.InputInt32(2));
1275  } else {
1276  __ ShiftRightAlgPair(i.OutputRegister(0), second_output,
1277  i.InputRegister(0), i.InputRegister(1),
1278  kScratchReg, i.InputRegister(2));
1279  }
1280  break;
1281  }
1282 #endif
1283  case kPPC_RotRight32:
1284  if (HasRegisterInput(instr, 1)) {
1285  __ subfic(kScratchReg, i.InputRegister(1), Operand(32));
1286  __ rotlw(i.OutputRegister(), i.InputRegister(0), kScratchReg,
1287  i.OutputRCBit());
1288  } else {
1289  int sh = i.InputInt32(1);
1290  __ rotrwi(i.OutputRegister(), i.InputRegister(0), sh, i.OutputRCBit());
1291  }
1292  break;
1293 #if V8_TARGET_ARCH_PPC64
1294  case kPPC_RotRight64:
1295  if (HasRegisterInput(instr, 1)) {
1296  __ subfic(kScratchReg, i.InputRegister(1), Operand(64));
1297  __ rotld(i.OutputRegister(), i.InputRegister(0), kScratchReg,
1298  i.OutputRCBit());
1299  } else {
1300  int sh = i.InputInt32(1);
1301  __ rotrdi(i.OutputRegister(), i.InputRegister(0), sh, i.OutputRCBit());
1302  }
1303  break;
1304 #endif
1305  case kPPC_Not:
1306  __ notx(i.OutputRegister(), i.InputRegister(0), i.OutputRCBit());
1307  break;
1308  case kPPC_RotLeftAndMask32:
1309  __ rlwinm(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
1310  31 - i.InputInt32(2), 31 - i.InputInt32(3), i.OutputRCBit());
1311  break;
1312 #if V8_TARGET_ARCH_PPC64
1313  case kPPC_RotLeftAndClear64:
1314  __ rldic(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
1315  63 - i.InputInt32(2), i.OutputRCBit());
1316  break;
1317  case kPPC_RotLeftAndClearLeft64:
1318  __ rldicl(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
1319  63 - i.InputInt32(2), i.OutputRCBit());
1320  break;
1321  case kPPC_RotLeftAndClearRight64:
1322  __ rldicr(i.OutputRegister(), i.InputRegister(0), i.InputInt32(1),
1323  63 - i.InputInt32(2), i.OutputRCBit());
1324  break;
1325 #endif
1326  case kPPC_Add32:
1327 #if V8_TARGET_ARCH_PPC64
1328  if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
1329  ASSEMBLE_ADD_WITH_OVERFLOW();
1330  } else {
1331 #endif
1332  if (HasRegisterInput(instr, 1)) {
1333  __ add(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1334  LeaveOE, i.OutputRCBit());
1335  } else {
1336  __ addi(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
1337  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1338  }
1339  __ extsw(i.OutputRegister(), i.OutputRegister());
1340 #if V8_TARGET_ARCH_PPC64
1341  }
1342 #endif
1343  break;
1344 #if V8_TARGET_ARCH_PPC64
1345  case kPPC_Add64:
1346  if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
1347  ASSEMBLE_ADD_WITH_OVERFLOW();
1348  } else {
1349  if (HasRegisterInput(instr, 1)) {
1350  __ add(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1351  LeaveOE, i.OutputRCBit());
1352  } else {
1353  __ addi(i.OutputRegister(), i.InputRegister(0), i.InputImmediate(1));
1354  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1355  }
1356  }
1357  break;
1358 #endif
1359  case kPPC_AddWithOverflow32:
1360  ASSEMBLE_ADD_WITH_OVERFLOW32();
1361  break;
1362  case kPPC_AddDouble:
1363  ASSEMBLE_FLOAT_BINOP_RC(fadd, MiscField::decode(instr->opcode()));
1364  break;
1365  case kPPC_Sub:
1366 #if V8_TARGET_ARCH_PPC64
1367  if (FlagsModeField::decode(instr->opcode()) != kFlags_none) {
1368  ASSEMBLE_SUB_WITH_OVERFLOW();
1369  } else {
1370 #endif
1371  if (HasRegisterInput(instr, 1)) {
1372  __ sub(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1373  LeaveOE, i.OutputRCBit());
1374  } else {
1375  if (is_int16(i.InputImmediate(1).immediate())) {
1376  __ subi(i.OutputRegister(), i.InputRegister(0),
1377  i.InputImmediate(1));
1378  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1379  } else {
1380  __ mov(kScratchReg, i.InputImmediate(1));
1381  __ sub(i.OutputRegister(), i.InputRegister(0), kScratchReg, LeaveOE,
1382  i.OutputRCBit());
1383  }
1384  }
1385 #if V8_TARGET_ARCH_PPC64
1386  }
1387 #endif
1388  break;
1389  case kPPC_SubWithOverflow32:
1390  ASSEMBLE_SUB_WITH_OVERFLOW32();
1391  break;
1392  case kPPC_SubDouble:
1393  ASSEMBLE_FLOAT_BINOP_RC(fsub, MiscField::decode(instr->opcode()));
1394  break;
1395  case kPPC_Mul32:
1396  __ mullw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1397  LeaveOE, i.OutputRCBit());
1398  break;
1399 #if V8_TARGET_ARCH_PPC64
1400  case kPPC_Mul64:
1401  __ mulld(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1402  LeaveOE, i.OutputRCBit());
1403  break;
1404 #endif
1405 
1406  case kPPC_Mul32WithHigh32:
1407  if (i.OutputRegister(0) == i.InputRegister(0) ||
1408  i.OutputRegister(0) == i.InputRegister(1) ||
1409  i.OutputRegister(1) == i.InputRegister(0) ||
1410  i.OutputRegister(1) == i.InputRegister(1)) {
1411  __ mullw(kScratchReg, i.InputRegister(0), i.InputRegister(1)); // low
1412  __ mulhw(i.OutputRegister(1), i.InputRegister(0),
1413  i.InputRegister(1)); // high
1414  __ mr(i.OutputRegister(0), kScratchReg);
1415  } else {
1416  __ mullw(i.OutputRegister(0), i.InputRegister(0),
1417  i.InputRegister(1)); // low
1418  __ mulhw(i.OutputRegister(1), i.InputRegister(0),
1419  i.InputRegister(1)); // high
1420  }
1421  break;
1422  case kPPC_MulHigh32:
1423  __ mulhw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1424  i.OutputRCBit());
1425  break;
1426  case kPPC_MulHighU32:
1427  __ mulhwu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
1428  i.OutputRCBit());
1429  break;
1430  case kPPC_MulDouble:
1431  ASSEMBLE_FLOAT_BINOP_RC(fmul, MiscField::decode(instr->opcode()));
1432  break;
1433  case kPPC_Div32:
1434  __ divw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1435  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1436  break;
1437 #if V8_TARGET_ARCH_PPC64
1438  case kPPC_Div64:
1439  __ divd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1440  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1441  break;
1442 #endif
1443  case kPPC_DivU32:
1444  __ divwu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1445  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1446  break;
1447 #if V8_TARGET_ARCH_PPC64
1448  case kPPC_DivU64:
1449  __ divdu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1450  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1451  break;
1452 #endif
1453  case kPPC_DivDouble:
1454  ASSEMBLE_FLOAT_BINOP_RC(fdiv, MiscField::decode(instr->opcode()));
1455  break;
1456  case kPPC_Mod32:
1457  if (CpuFeatures::IsSupported(MODULO)) {
1458  __ modsw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1459  } else {
1460  ASSEMBLE_MODULO(divw, mullw);
1461  }
1462  break;
1463 #if V8_TARGET_ARCH_PPC64
1464  case kPPC_Mod64:
1465  if (CpuFeatures::IsSupported(MODULO)) {
1466  __ modsd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1467  } else {
1468  ASSEMBLE_MODULO(divd, mulld);
1469  }
1470  break;
1471 #endif
1472  case kPPC_ModU32:
1473  if (CpuFeatures::IsSupported(MODULO)) {
1474  __ moduw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1475  } else {
1476  ASSEMBLE_MODULO(divwu, mullw);
1477  }
1478  break;
1479 #if V8_TARGET_ARCH_PPC64
1480  case kPPC_ModU64:
1481  if (CpuFeatures::IsSupported(MODULO)) {
1482  __ modud(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
1483  } else {
1484  ASSEMBLE_MODULO(divdu, mulld);
1485  }
1486  break;
1487 #endif
1488  case kPPC_ModDouble:
1489  // TODO(bmeurer): We should really get rid of this special instruction,
1490  // and generate a CallAddress instruction instead.
1491  ASSEMBLE_FLOAT_MODULO();
1492  break;
1493  case kIeee754Float64Acos:
1494  ASSEMBLE_IEEE754_UNOP(acos);
1495  break;
1496  case kIeee754Float64Acosh:
1497  ASSEMBLE_IEEE754_UNOP(acosh);
1498  break;
1499  case kIeee754Float64Asin:
1500  ASSEMBLE_IEEE754_UNOP(asin);
1501  break;
1502  case kIeee754Float64Asinh:
1503  ASSEMBLE_IEEE754_UNOP(asinh);
1504  break;
1505  case kIeee754Float64Atan:
1506  ASSEMBLE_IEEE754_UNOP(atan);
1507  break;
1508  case kIeee754Float64Atan2:
1509  ASSEMBLE_IEEE754_BINOP(atan2);
1510  break;
1511  case kIeee754Float64Atanh:
1512  ASSEMBLE_IEEE754_UNOP(atanh);
1513  break;
1514  case kIeee754Float64Tan:
1515  ASSEMBLE_IEEE754_UNOP(tan);
1516  break;
1517  case kIeee754Float64Tanh:
1518  ASSEMBLE_IEEE754_UNOP(tanh);
1519  break;
1520  case kIeee754Float64Cbrt:
1521  ASSEMBLE_IEEE754_UNOP(cbrt);
1522  break;
1523  case kIeee754Float64Sin:
1524  ASSEMBLE_IEEE754_UNOP(sin);
1525  break;
1526  case kIeee754Float64Sinh:
1527  ASSEMBLE_IEEE754_UNOP(sinh);
1528  break;
1529  case kIeee754Float64Cos:
1530  ASSEMBLE_IEEE754_UNOP(cos);
1531  break;
1532  case kIeee754Float64Cosh:
1533  ASSEMBLE_IEEE754_UNOP(cosh);
1534  break;
1535  case kIeee754Float64Exp:
1536  ASSEMBLE_IEEE754_UNOP(exp);
1537  break;
1538  case kIeee754Float64Expm1:
1539  ASSEMBLE_IEEE754_UNOP(expm1);
1540  break;
1541  case kIeee754Float64Log:
1542  ASSEMBLE_IEEE754_UNOP(log);
1543  break;
1544  case kIeee754Float64Log1p:
1545  ASSEMBLE_IEEE754_UNOP(log1p);
1546  break;
1547  case kIeee754Float64Log2:
1548  ASSEMBLE_IEEE754_UNOP(log2);
1549  break;
1550  case kIeee754Float64Log10:
1551  ASSEMBLE_IEEE754_UNOP(log10);
1552  break;
1553  case kIeee754Float64Pow: {
1554  __ Call(BUILTIN_CODE(isolate(), MathPowInternal), RelocInfo::CODE_TARGET);
1555  __ Move(d1, d3);
1556  break;
1557  }
1558  case kPPC_Neg:
1559  __ neg(i.OutputRegister(), i.InputRegister(0), LeaveOE, i.OutputRCBit());
1560  break;
1561  case kPPC_MaxDouble:
1562  ASSEMBLE_FLOAT_MAX();
1563  break;
1564  case kPPC_MinDouble:
1565  ASSEMBLE_FLOAT_MIN();
1566  break;
1567  case kPPC_AbsDouble:
1568  ASSEMBLE_FLOAT_UNOP_RC(fabs, 0);
1569  break;
1570  case kPPC_SqrtDouble:
1571  ASSEMBLE_FLOAT_UNOP_RC(fsqrt, MiscField::decode(instr->opcode()));
1572  break;
1573  case kPPC_FloorDouble:
1574  ASSEMBLE_FLOAT_UNOP_RC(frim, MiscField::decode(instr->opcode()));
1575  break;
1576  case kPPC_CeilDouble:
1577  ASSEMBLE_FLOAT_UNOP_RC(frip, MiscField::decode(instr->opcode()));
1578  break;
1579  case kPPC_TruncateDouble:
1580  ASSEMBLE_FLOAT_UNOP_RC(friz, MiscField::decode(instr->opcode()));
1581  break;
1582  case kPPC_RoundDouble:
1583  ASSEMBLE_FLOAT_UNOP_RC(frin, MiscField::decode(instr->opcode()));
1584  break;
1585  case kPPC_NegDouble:
1586  ASSEMBLE_FLOAT_UNOP_RC(fneg, 0);
1587  break;
1588  case kPPC_Cntlz32:
1589  __ cntlzw(i.OutputRegister(), i.InputRegister(0));
1590  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1591  break;
1592 #if V8_TARGET_ARCH_PPC64
1593  case kPPC_Cntlz64:
1594  __ cntlzd(i.OutputRegister(), i.InputRegister(0));
1595  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1596  break;
1597 #endif
1598  case kPPC_Popcnt32:
1599  __ popcntw(i.OutputRegister(), i.InputRegister(0));
1600  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1601  break;
1602 #if V8_TARGET_ARCH_PPC64
1603  case kPPC_Popcnt64:
1604  __ popcntd(i.OutputRegister(), i.InputRegister(0));
1605  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1606  break;
1607 #endif
1608  case kPPC_Cmp32:
1609  ASSEMBLE_COMPARE(cmpw, cmplw);
1610  break;
1611 #if V8_TARGET_ARCH_PPC64
1612  case kPPC_Cmp64:
1613  ASSEMBLE_COMPARE(cmp, cmpl);
1614  break;
1615 #endif
1616  case kPPC_CmpDouble:
1617  ASSEMBLE_FLOAT_COMPARE(fcmpu);
1618  break;
1619  case kPPC_Tst32:
1620  if (HasRegisterInput(instr, 1)) {
1621  __ and_(r0, i.InputRegister(0), i.InputRegister(1), i.OutputRCBit());
1622  } else {
1623  __ andi(r0, i.InputRegister(0), i.InputImmediate(1));
1624  }
1625 #if V8_TARGET_ARCH_PPC64
1626  __ extsw(r0, r0, i.OutputRCBit());
1627 #endif
1628  DCHECK_EQ(SetRC, i.OutputRCBit());
1629  break;
1630 #if V8_TARGET_ARCH_PPC64
1631  case kPPC_Tst64:
1632  if (HasRegisterInput(instr, 1)) {
1633  __ and_(r0, i.InputRegister(0), i.InputRegister(1), i.OutputRCBit());
1634  } else {
1635  __ andi(r0, i.InputRegister(0), i.InputImmediate(1));
1636  }
1637  DCHECK_EQ(SetRC, i.OutputRCBit());
1638  break;
1639 #endif
1640  case kPPC_Float64SilenceNaN: {
1641  DoubleRegister value = i.InputDoubleRegister(0);
1642  DoubleRegister result = i.OutputDoubleRegister();
1643  __ CanonicalizeNaN(result, value);
1644  break;
1645  }
1646  case kPPC_Push:
1647  if (instr->InputAt(0)->IsFPRegister()) {
1648  LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
1649  if (op->representation() == MachineRepresentation::kFloat64) {
1650  __ StoreDoubleU(i.InputDoubleRegister(0),
1651  MemOperand(sp, -kDoubleSize), r0);
1652  frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1653  } else {
1654  DCHECK_EQ(MachineRepresentation::kFloat32, op->representation());
1655  __ StoreSingleU(i.InputDoubleRegister(0),
1656  MemOperand(sp, -kPointerSize), r0);
1657  frame_access_state()->IncreaseSPDelta(1);
1658  }
1659  } else {
1660  __ StorePU(i.InputRegister(0), MemOperand(sp, -kPointerSize), r0);
1661  frame_access_state()->IncreaseSPDelta(1);
1662  }
1663  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1664  break;
1665  case kPPC_PushFrame: {
1666  int num_slots = i.InputInt32(1);
1667  if (instr->InputAt(0)->IsFPRegister()) {
1668  LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
1669  if (op->representation() == MachineRepresentation::kFloat64) {
1670  __ StoreDoubleU(i.InputDoubleRegister(0),
1671  MemOperand(sp, -num_slots * kPointerSize), r0);
1672  } else {
1673  DCHECK_EQ(MachineRepresentation::kFloat32, op->representation());
1674  __ StoreSingleU(i.InputDoubleRegister(0),
1675  MemOperand(sp, -num_slots * kPointerSize), r0);
1676  }
1677  } else {
1678  __ StorePU(i.InputRegister(0),
1679  MemOperand(sp, -num_slots * kPointerSize), r0);
1680  }
1681  break;
1682  }
1683  case kPPC_StoreToStackSlot: {
1684  int slot = i.InputInt32(1);
1685  if (instr->InputAt(0)->IsFPRegister()) {
1686  LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
1687  if (op->representation() == MachineRepresentation::kFloat64) {
1688  __ StoreDouble(i.InputDoubleRegister(0),
1689  MemOperand(sp, slot * kPointerSize), r0);
1690  } else {
1691  DCHECK_EQ(MachineRepresentation::kFloat32, op->representation());
1692  __ StoreSingle(i.InputDoubleRegister(0),
1693  MemOperand(sp, slot * kPointerSize), r0);
1694  }
1695  } else {
1696  __ StoreP(i.InputRegister(0), MemOperand(sp, slot * kPointerSize), r0);
1697  }
1698  break;
1699  }
1700  case kPPC_ExtendSignWord8:
1701  __ extsb(i.OutputRegister(), i.InputRegister(0));
1702  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1703  break;
1704  case kPPC_ExtendSignWord16:
1705  __ extsh(i.OutputRegister(), i.InputRegister(0));
1706  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1707  break;
1708 #if V8_TARGET_ARCH_PPC64
1709  case kPPC_ExtendSignWord32:
1710  __ extsw(i.OutputRegister(), i.InputRegister(0));
1711  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1712  break;
1713  case kPPC_Uint32ToUint64:
1714  // Zero extend
1715  __ clrldi(i.OutputRegister(), i.InputRegister(0), Operand(32));
1716  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1717  break;
1718  case kPPC_Int64ToInt32:
1719  __ extsw(i.OutputRegister(), i.InputRegister(0));
1720  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1721  break;
1722  case kPPC_Int64ToFloat32:
1723  __ ConvertInt64ToFloat(i.InputRegister(0), i.OutputDoubleRegister());
1724  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1725  break;
1726  case kPPC_Int64ToDouble:
1727  __ ConvertInt64ToDouble(i.InputRegister(0), i.OutputDoubleRegister());
1728  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1729  break;
1730  case kPPC_Uint64ToFloat32:
1731  __ ConvertUnsignedInt64ToFloat(i.InputRegister(0),
1732  i.OutputDoubleRegister());
1733  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1734  break;
1735  case kPPC_Uint64ToDouble:
1736  __ ConvertUnsignedInt64ToDouble(i.InputRegister(0),
1737  i.OutputDoubleRegister());
1738  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1739  break;
1740 #endif
1741  case kPPC_Int32ToFloat32:
1742  __ ConvertIntToFloat(i.InputRegister(0), i.OutputDoubleRegister());
1743  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1744  break;
1745  case kPPC_Int32ToDouble:
1746  __ ConvertIntToDouble(i.InputRegister(0), i.OutputDoubleRegister());
1747  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1748  break;
1749  case kPPC_Uint32ToFloat32:
1750  __ ConvertUnsignedIntToFloat(i.InputRegister(0),
1751  i.OutputDoubleRegister());
1752  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1753  break;
1754  case kPPC_Uint32ToDouble:
1755  __ ConvertUnsignedIntToDouble(i.InputRegister(0),
1756  i.OutputDoubleRegister());
1757  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1758  break;
1759  case kPPC_DoubleToInt32:
1760  case kPPC_DoubleToUint32:
1761  case kPPC_DoubleToInt64: {
1762 #if V8_TARGET_ARCH_PPC64
1763  bool check_conversion =
1764  (opcode == kPPC_DoubleToInt64 && i.OutputCount() > 1);
1765  if (check_conversion) {
1766  __ mtfsb0(VXCVI); // clear FPSCR:VXCVI bit
1767  }
1768 #endif
1769  __ ConvertDoubleToInt64(i.InputDoubleRegister(0),
1770 #if !V8_TARGET_ARCH_PPC64
1771  kScratchReg,
1772 #endif
1773  i.OutputRegister(0), kScratchDoubleReg);
1774 #if V8_TARGET_ARCH_PPC64
1775  if (check_conversion) {
1776  // Set 2nd output to zero if conversion fails.
1777  CRegister cr = cr7;
1778  int crbit = v8::internal::Assembler::encode_crbit(
1779  cr, static_cast<CRBit>(VXCVI % CRWIDTH));
1780  __ mcrfs(cr, VXCVI); // extract FPSCR field containing VXCVI into cr7
1781  if (CpuFeatures::IsSupported(ISELECT)) {
1782  __ li(i.OutputRegister(1), Operand(1));
1783  __ isel(i.OutputRegister(1), r0, i.OutputRegister(1), crbit);
1784  } else {
1785  __ li(i.OutputRegister(1), Operand::Zero());
1786  __ bc(v8::internal::kInstrSize * 2, BT, crbit);
1787  __ li(i.OutputRegister(1), Operand(1));
1788  }
1789  }
1790 #endif
1791  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1792  break;
1793  }
1794 #if V8_TARGET_ARCH_PPC64
1795  case kPPC_DoubleToUint64: {
1796  bool check_conversion = (i.OutputCount() > 1);
1797  if (check_conversion) {
1798  __ mtfsb0(VXCVI); // clear FPSCR:VXCVI bit
1799  }
1800  __ ConvertDoubleToUnsignedInt64(i.InputDoubleRegister(0),
1801  i.OutputRegister(0), kScratchDoubleReg);
1802  if (check_conversion) {
1803  // Set 2nd output to zero if conversion fails.
1804  CRegister cr = cr7;
1805  int crbit = v8::internal::Assembler::encode_crbit(
1806  cr, static_cast<CRBit>(VXCVI % CRWIDTH));
1807  __ mcrfs(cr, VXCVI); // extract FPSCR field containing VXCVI into cr7
1808  if (CpuFeatures::IsSupported(ISELECT)) {
1809  __ li(i.OutputRegister(1), Operand(1));
1810  __ isel(i.OutputRegister(1), r0, i.OutputRegister(1), crbit);
1811  } else {
1812  __ li(i.OutputRegister(1), Operand::Zero());
1813  __ bc(v8::internal::kInstrSize * 2, BT, crbit);
1814  __ li(i.OutputRegister(1), Operand(1));
1815  }
1816  }
1817  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1818  break;
1819  }
1820 #endif
1821  case kPPC_DoubleToFloat32:
1822  ASSEMBLE_FLOAT_UNOP_RC(frsp, 0);
1823  break;
1824  case kPPC_Float32ToDouble:
1825  // Nothing to do.
1826  __ Move(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1827  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1828  break;
1829  case kPPC_DoubleExtractLowWord32:
1830  __ MovDoubleLowToInt(i.OutputRegister(), i.InputDoubleRegister(0));
1831  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1832  break;
1833  case kPPC_DoubleExtractHighWord32:
1834  __ MovDoubleHighToInt(i.OutputRegister(), i.InputDoubleRegister(0));
1835  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1836  break;
1837  case kPPC_DoubleInsertLowWord32:
1838  __ InsertDoubleLow(i.OutputDoubleRegister(), i.InputRegister(1), r0);
1839  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1840  break;
1841  case kPPC_DoubleInsertHighWord32:
1842  __ InsertDoubleHigh(i.OutputDoubleRegister(), i.InputRegister(1), r0);
1843  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1844  break;
1845  case kPPC_DoubleConstruct:
1846 #if V8_TARGET_ARCH_PPC64
1847  __ MovInt64ComponentsToDouble(i.OutputDoubleRegister(),
1848  i.InputRegister(0), i.InputRegister(1), r0);
1849 #else
1850  __ MovInt64ToDouble(i.OutputDoubleRegister(), i.InputRegister(0),
1851  i.InputRegister(1));
1852 #endif
1853  DCHECK_EQ(LeaveRC, i.OutputRCBit());
1854  break;
1855  case kPPC_BitcastFloat32ToInt32:
1856  __ MovFloatToInt(i.OutputRegister(), i.InputDoubleRegister(0));
1857  break;
1858  case kPPC_BitcastInt32ToFloat32:
1859  __ MovIntToFloat(i.OutputDoubleRegister(), i.InputRegister(0));
1860  break;
1861 #if V8_TARGET_ARCH_PPC64
1862  case kPPC_BitcastDoubleToInt64:
1863  __ MovDoubleToInt64(i.OutputRegister(), i.InputDoubleRegister(0));
1864  break;
1865  case kPPC_BitcastInt64ToDouble:
1866  __ MovInt64ToDouble(i.OutputDoubleRegister(), i.InputRegister(0));
1867  break;
1868 #endif
1869  case kPPC_LoadWordU8:
1870  ASSEMBLE_LOAD_INTEGER(lbz, lbzx);
1871  EmitWordLoadPoisoningIfNeeded(this, instr, i);
1872  break;
1873  case kPPC_LoadWordS8:
1874  ASSEMBLE_LOAD_INTEGER(lbz, lbzx);
1875  __ extsb(i.OutputRegister(), i.OutputRegister());
1876  EmitWordLoadPoisoningIfNeeded(this, instr, i);
1877  break;
1878  case kPPC_LoadWordU16:
1879  ASSEMBLE_LOAD_INTEGER(lhz, lhzx);
1880  EmitWordLoadPoisoningIfNeeded(this, instr, i);
1881  break;
1882  case kPPC_LoadWordS16:
1883  ASSEMBLE_LOAD_INTEGER(lha, lhax);
1884  EmitWordLoadPoisoningIfNeeded(this, instr, i);
1885  break;
1886  case kPPC_LoadWordU32:
1887  ASSEMBLE_LOAD_INTEGER(lwz, lwzx);
1888  EmitWordLoadPoisoningIfNeeded(this, instr, i);
1889  break;
1890  case kPPC_LoadWordS32:
1891  ASSEMBLE_LOAD_INTEGER(lwa, lwax);
1892  EmitWordLoadPoisoningIfNeeded(this, instr, i);
1893  break;
1894 #if V8_TARGET_ARCH_PPC64
1895  case kPPC_LoadWord64:
1896  ASSEMBLE_LOAD_INTEGER(ld, ldx);
1897  EmitWordLoadPoisoningIfNeeded(this, instr, i);
1898  break;
1899 #endif
1900  case kPPC_LoadFloat32:
1901  ASSEMBLE_LOAD_FLOAT(lfs, lfsx);
1902  break;
1903  case kPPC_LoadDouble:
1904  ASSEMBLE_LOAD_FLOAT(lfd, lfdx);
1905  break;
1906  case kPPC_StoreWord8:
1907  ASSEMBLE_STORE_INTEGER(stb, stbx);
1908  break;
1909  case kPPC_StoreWord16:
1910  ASSEMBLE_STORE_INTEGER(sth, sthx);
1911  break;
1912  case kPPC_StoreWord32:
1913  ASSEMBLE_STORE_INTEGER(stw, stwx);
1914  break;
1915 #if V8_TARGET_ARCH_PPC64
1916  case kPPC_StoreWord64:
1917  ASSEMBLE_STORE_INTEGER(std, stdx);
1918  break;
1919 #endif
1920  case kPPC_StoreFloat32:
1921  ASSEMBLE_STORE_FLOAT(stfs, stfsx);
1922  break;
1923  case kPPC_StoreDouble:
1924  ASSEMBLE_STORE_FLOAT(stfd, stfdx);
1925  break;
1926  case kWord32AtomicLoadInt8:
1927  case kPPC_AtomicLoadUint8:
1928  case kWord32AtomicLoadInt16:
1929  case kPPC_AtomicLoadUint16:
1930  case kPPC_AtomicLoadWord32:
1931  case kPPC_AtomicLoadWord64:
1932  case kPPC_AtomicStoreUint8:
1933  case kPPC_AtomicStoreUint16:
1934  case kPPC_AtomicStoreWord32:
1935  case kPPC_AtomicStoreWord64:
1936  UNREACHABLE();
1937  break;
1938  case kWord32AtomicExchangeInt8:
1939  ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(lbarx, stbcx);
1940  __ extsb(i.OutputRegister(0), i.OutputRegister(0));
1941  break;
1942  case kPPC_AtomicExchangeUint8:
1943  ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(lbarx, stbcx);
1944  break;
1945  case kWord32AtomicExchangeInt16:
1946  ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(lharx, sthcx);
1947  __ extsh(i.OutputRegister(0), i.OutputRegister(0));
1948  break;
1949  case kPPC_AtomicExchangeUint16:
1950  ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(lharx, sthcx);
1951  break;
1952  case kPPC_AtomicExchangeWord32:
1953  ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(lwarx, stwcx);
1954  break;
1955  case kPPC_AtomicExchangeWord64:
1956  ASSEMBLE_ATOMIC_EXCHANGE_INTEGER(ldarx, stdcx);
1957  break;
1958  case kWord32AtomicCompareExchangeInt8:
1959  ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_SIGN_EXT(cmp, lbarx, stbcx, extsb);
1960  break;
1961  case kPPC_AtomicCompareExchangeUint8:
1962  ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(cmp, lbarx, stbcx);
1963  break;
1964  case kWord32AtomicCompareExchangeInt16:
1965  ASSEMBLE_ATOMIC_COMPARE_EXCHANGE_SIGN_EXT(cmp, lharx, sthcx, extsh);
1966  break;
1967  case kPPC_AtomicCompareExchangeUint16:
1968  ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(cmp, lharx, sthcx);
1969  break;
1970  case kPPC_AtomicCompareExchangeWord32:
1971  ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(cmpw, lwarx, stwcx);
1972  break;
1973  case kPPC_AtomicCompareExchangeWord64:
1974  ASSEMBLE_ATOMIC_COMPARE_EXCHANGE(cmp, ldarx, stdcx);
1975  break;
1976 
1977 #define ATOMIC_BINOP_CASE(op, inst) \
1978  case kPPC_Atomic##op##Int8: \
1979  ASSEMBLE_ATOMIC_BINOP_SIGN_EXT(inst, lbarx, stbcx, extsb); \
1980  break; \
1981  case kPPC_Atomic##op##Uint8: \
1982  ASSEMBLE_ATOMIC_BINOP(inst, lbarx, stbcx); \
1983  break; \
1984  case kPPC_Atomic##op##Int16: \
1985  ASSEMBLE_ATOMIC_BINOP_SIGN_EXT(inst, lharx, sthcx, extsh); \
1986  break; \
1987  case kPPC_Atomic##op##Uint16: \
1988  ASSEMBLE_ATOMIC_BINOP(inst, lharx, sthcx); \
1989  break; \
1990  case kPPC_Atomic##op##Int32: \
1991  ASSEMBLE_ATOMIC_BINOP_SIGN_EXT(inst, lwarx, stwcx, extsw); \
1992  break; \
1993  case kPPC_Atomic##op##Uint32: \
1994  ASSEMBLE_ATOMIC_BINOP(inst, lwarx, stwcx); \
1995  break; \
1996  case kPPC_Atomic##op##Int64: \
1997  case kPPC_Atomic##op##Uint64: \
1998  ASSEMBLE_ATOMIC_BINOP(inst, ldarx, stdcx); \
1999  break;
2000  ATOMIC_BINOP_CASE(Add, add)
2001  ATOMIC_BINOP_CASE(Sub, sub)
2002  ATOMIC_BINOP_CASE(And, and_)
2003  ATOMIC_BINOP_CASE(Or, orx)
2004  ATOMIC_BINOP_CASE(Xor, xor_)
2005 #undef ATOMIC_BINOP_CASE
2006 
2007  case kPPC_ByteRev32: {
2008  Register input = i.InputRegister(0);
2009  Register output = i.OutputRegister();
2010  Register temp1 = r0;
2011  __ rotlwi(temp1, input, 8);
2012  __ rlwimi(temp1, input, 24, 0, 7);
2013  __ rlwimi(temp1, input, 24, 16, 23);
2014  __ extsw(output, temp1);
2015  break;
2016  }
2017 #ifdef V8_TARGET_ARCH_PPC64
2018  case kPPC_ByteRev64: {
2019  Register input = i.InputRegister(0);
2020  Register output = i.OutputRegister();
2021  Register temp1 = r0;
2022  Register temp2 = kScratchReg;
2023  Register temp3 = i.TempRegister(0);
2024  __ rldicl(temp1, input, 32, 32);
2025  __ rotlwi(temp2, input, 8);
2026  __ rlwimi(temp2, input, 24, 0, 7);
2027  __ rotlwi(temp3, temp1, 8);
2028  __ rlwimi(temp2, input, 24, 16, 23);
2029  __ rlwimi(temp3, temp1, 24, 0, 7);
2030  __ rlwimi(temp3, temp1, 24, 16, 23);
2031  __ rldicr(temp2, temp2, 32, 31);
2032  __ orx(output, temp2, temp3);
2033  break;
2034  }
2035 #endif // V8_TARGET_ARCH_PPC64
2036  default:
2037  UNREACHABLE();
2038  break;
2039  }
2040  return kSuccess;
2041 } // NOLINT(readability/fn_size)
2042 
2043 // Assembles branches after an instruction.
2044 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
2045  PPCOperandConverter i(this, instr);
2046  Label* tlabel = branch->true_label;
2047  Label* flabel = branch->false_label;
2048  ArchOpcode op = instr->arch_opcode();
2049  FlagsCondition condition = branch->condition;
2050  CRegister cr = cr0;
2051 
2052  Condition cond = FlagsConditionToCondition(condition, op);
2053  if (op == kPPC_CmpDouble) {
2054  // check for unordered if necessary
2055  if (cond == le) {
2056  __ bunordered(flabel, cr);
2057  // Unnecessary for eq/lt since only FU bit will be set.
2058  } else if (cond == gt) {
2059  __ bunordered(tlabel, cr);
2060  // Unnecessary for ne/ge since only FU bit will be set.
2061  }
2062  }
2063  __ b(cond, tlabel, cr);
2064  if (!branch->fallthru) __ b(flabel); // no fallthru to flabel.
2065 }
2066 
2067 void CodeGenerator::AssembleBranchPoisoning(FlagsCondition condition,
2068  Instruction* instr) {
2069  // TODO(John) Handle float comparisons (kUnordered[Not]Equal).
2070  if (condition == kUnorderedEqual || condition == kUnorderedNotEqual ||
2071  condition == kOverflow || condition == kNotOverflow) {
2072  return;
2073  }
2074 
2075  ArchOpcode op = instr->arch_opcode();
2076  condition = NegateFlagsCondition(condition);
2077  __ li(kScratchReg, Operand::Zero());
2078  __ isel(FlagsConditionToCondition(condition, op), kSpeculationPoisonRegister,
2079  kScratchReg, kSpeculationPoisonRegister, cr0);
2080 }
2081 
2082 void CodeGenerator::AssembleArchDeoptBranch(Instruction* instr,
2083  BranchInfo* branch) {
2084  AssembleArchBranch(instr, branch);
2085 }
2086 
2087 void CodeGenerator::AssembleArchJump(RpoNumber target) {
2088  if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
2089 }
2090 
2091 void CodeGenerator::AssembleArchTrap(Instruction* instr,
2092  FlagsCondition condition) {
2093  class OutOfLineTrap final : public OutOfLineCode {
2094  public:
2095  OutOfLineTrap(CodeGenerator* gen, Instruction* instr)
2096  : OutOfLineCode(gen), instr_(instr), gen_(gen) {}
2097 
2098  void Generate() final {
2099  PPCOperandConverter i(gen_, instr_);
2100  TrapId trap_id =
2101  static_cast<TrapId>(i.InputInt32(instr_->InputCount() - 1));
2102  GenerateCallToTrap(trap_id);
2103  }
2104 
2105  private:
2106  void GenerateCallToTrap(TrapId trap_id) {
2107  if (trap_id == TrapId::kInvalid) {
2108  // We cannot test calls to the runtime in cctest/test-run-wasm.
2109  // Therefore we emit a call to C here instead of a call to the runtime.
2110  // We use the context register as the scratch register, because we do
2111  // not have a context here.
2112  __ PrepareCallCFunction(0, 0, cp);
2113  __ CallCFunction(
2114  ExternalReference::wasm_call_trap_callback_for_testing(), 0);
2115  __ LeaveFrame(StackFrame::WASM_COMPILED);
2116  auto call_descriptor = gen_->linkage()->GetIncomingDescriptor();
2117  int pop_count =
2118  static_cast<int>(call_descriptor->StackParameterCount());
2119  __ Drop(pop_count);
2120  __ Ret();
2121  } else {
2122  gen_->AssembleSourcePosition(instr_);
2123  // A direct call to a wasm runtime stub defined in this module.
2124  // Just encode the stub index. This will be patched when the code
2125  // is added to the native module and copied into wasm code space.
2126  __ Call(static_cast<Address>(trap_id), RelocInfo::WASM_STUB_CALL);
2127  ReferenceMap* reference_map =
2128  new (gen_->zone()) ReferenceMap(gen_->zone());
2129  gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
2130  Safepoint::kNoLazyDeopt);
2131  if (FLAG_debug_code) {
2132  __ stop(GetAbortReason(AbortReason::kUnexpectedReturnFromWasmTrap));
2133  }
2134  }
2135  }
2136 
2137  Instruction* instr_;
2138  CodeGenerator* gen_;
2139  };
2140  auto ool = new (zone()) OutOfLineTrap(this, instr);
2141  Label* tlabel = ool->entry();
2142  Label end;
2143 
2144  ArchOpcode op = instr->arch_opcode();
2145  CRegister cr = cr0;
2146  Condition cond = FlagsConditionToCondition(condition, op);
2147  if (op == kPPC_CmpDouble) {
2148  // check for unordered if necessary
2149  if (cond == le) {
2150  __ bunordered(&end, cr);
2151  // Unnecessary for eq/lt since only FU bit will be set.
2152  } else if (cond == gt) {
2153  __ bunordered(tlabel, cr);
2154  // Unnecessary for ne/ge since only FU bit will be set.
2155  }
2156  }
2157  __ b(cond, tlabel, cr);
2158  __ bind(&end);
2159 }
2160 
2161 // Assembles boolean materializations after an instruction.
2162 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
2163  FlagsCondition condition) {
2164  PPCOperandConverter i(this, instr);
2165  Label done;
2166  ArchOpcode op = instr->arch_opcode();
2167  CRegister cr = cr0;
2168  int reg_value = -1;
2169 
2170  // Materialize a full 32-bit 1 or 0 value. The result register is always the
2171  // last output of the instruction.
2172  DCHECK_NE(0u, instr->OutputCount());
2173  Register reg = i.OutputRegister(instr->OutputCount() - 1);
2174 
2175  Condition cond = FlagsConditionToCondition(condition, op);
2176  if (op == kPPC_CmpDouble) {
2177  // check for unordered if necessary
2178  if (cond == le) {
2179  reg_value = 0;
2180  __ li(reg, Operand::Zero());
2181  __ bunordered(&done, cr);
2182  } else if (cond == gt) {
2183  reg_value = 1;
2184  __ li(reg, Operand(1));
2185  __ bunordered(&done, cr);
2186  }
2187  // Unnecessary for eq/lt & ne/ge since only FU bit will be set.
2188  }
2189 
2190  if (CpuFeatures::IsSupported(ISELECT)) {
2191  switch (cond) {
2192  case eq:
2193  case lt:
2194  case gt:
2195  if (reg_value != 1) __ li(reg, Operand(1));
2196  __ li(kScratchReg, Operand::Zero());
2197  __ isel(cond, reg, reg, kScratchReg, cr);
2198  break;
2199  case ne:
2200  case ge:
2201  case le:
2202  if (reg_value != 1) __ li(reg, Operand(1));
2203  // r0 implies logical zero in this form
2204  __ isel(NegateCondition(cond), reg, r0, reg, cr);
2205  break;
2206  default:
2207  UNREACHABLE();
2208  break;
2209  }
2210  } else {
2211  if (reg_value != 0) __ li(reg, Operand::Zero());
2212  __ b(NegateCondition(cond), &done, cr);
2213  __ li(reg, Operand(1));
2214  }
2215  __ bind(&done);
2216 }
2217 
2218 void CodeGenerator::AssembleArchBinarySearchSwitch(Instruction* instr) {
2219  PPCOperandConverter i(this, instr);
2220  Register input = i.InputRegister(0);
2221  std::vector<std::pair<int32_t, Label*>> cases;
2222  for (size_t index = 2; index < instr->InputCount(); index += 2) {
2223  cases.push_back({i.InputInt32(index + 0), GetLabel(i.InputRpo(index + 1))});
2224  }
2225  AssembleArchBinarySearchSwitchRange(input, i.InputRpo(1), cases.data(),
2226  cases.data() + cases.size());
2227 }
2228 
2229 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
2230  PPCOperandConverter i(this, instr);
2231  Register input = i.InputRegister(0);
2232  for (size_t index = 2; index < instr->InputCount(); index += 2) {
2233  __ Cmpwi(input, Operand(i.InputInt32(index + 0)), r0);
2234  __ beq(GetLabel(i.InputRpo(index + 1)));
2235  }
2236  AssembleArchJump(i.InputRpo(1));
2237 }
2238 
2239 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
2240  PPCOperandConverter i(this, instr);
2241  Register input = i.InputRegister(0);
2242  int32_t const case_count = static_cast<int32_t>(instr->InputCount() - 2);
2243  Label** cases = zone()->NewArray<Label*>(case_count);
2244  for (int32_t index = 0; index < case_count; ++index) {
2245  cases[index] = GetLabel(i.InputRpo(index + 2));
2246  }
2247  Label* const table = AddJumpTable(cases, case_count);
2248  __ Cmpli(input, Operand(case_count), r0);
2249  __ bge(GetLabel(i.InputRpo(1)));
2250  __ mov_label_addr(kScratchReg, table);
2251  __ ShiftLeftImm(r0, input, Operand(kPointerSizeLog2));
2252  __ LoadPX(kScratchReg, MemOperand(kScratchReg, r0));
2253  __ Jump(kScratchReg);
2254 }
2255 
2256 void CodeGenerator::FinishFrame(Frame* frame) {
2257  auto call_descriptor = linkage()->GetIncomingDescriptor();
2258  const RegList double_saves = call_descriptor->CalleeSavedFPRegisters();
2259 
2260  // Save callee-saved Double registers.
2261  if (double_saves != 0) {
2262  frame->AlignSavedCalleeRegisterSlots();
2263  DCHECK_EQ(kNumCalleeSavedDoubles,
2264  base::bits::CountPopulation(double_saves));
2265  frame->AllocateSavedCalleeRegisterSlots(kNumCalleeSavedDoubles *
2266  (kDoubleSize / kPointerSize));
2267  }
2268  // Save callee-saved registers.
2269  const RegList saves = FLAG_enable_embedded_constant_pool
2270  ? call_descriptor->CalleeSavedRegisters() &
2271  ~kConstantPoolRegister.bit()
2272  : call_descriptor->CalleeSavedRegisters();
2273  if (saves != 0) {
2274  // register save area does not include the fp or constant pool pointer.
2275  const int num_saves =
2276  kNumCalleeSaved - 1 - (FLAG_enable_embedded_constant_pool ? 1 : 0);
2277  DCHECK(num_saves == base::bits::CountPopulation(saves));
2278  frame->AllocateSavedCalleeRegisterSlots(num_saves);
2279  }
2280 }
2281 
2282 void CodeGenerator::AssembleConstructFrame() {
2283  auto call_descriptor = linkage()->GetIncomingDescriptor();
2284  if (frame_access_state()->has_frame()) {
2285  if (call_descriptor->IsCFunctionCall()) {
2286  __ function_descriptor();
2287  __ mflr(r0);
2288  if (FLAG_enable_embedded_constant_pool) {
2289  __ Push(r0, fp, kConstantPoolRegister);
2290  // Adjust FP to point to saved FP.
2291  __ subi(fp, sp, Operand(StandardFrameConstants::kConstantPoolOffset));
2292  } else {
2293  __ Push(r0, fp);
2294  __ mr(fp, sp);
2295  }
2296  } else if (call_descriptor->IsJSFunctionCall()) {
2297  __ Prologue();
2298  if (call_descriptor->PushArgumentCount()) {
2299  __ Push(kJavaScriptCallArgCountRegister);
2300  }
2301  } else {
2302  StackFrame::Type type = info()->GetOutputStackFrameType();
2303  // TODO(mbrandy): Detect cases where ip is the entrypoint (for
2304  // efficient intialization of the constant pool pointer register).
2305  __ StubPrologue(type);
2306  if (call_descriptor->IsWasmFunctionCall()) {
2307  __ Push(kWasmInstanceRegister);
2308  } else if (call_descriptor->IsWasmImportWrapper()) {
2309  // WASM import wrappers are passed a tuple in the place of the instance.
2310  // Unpack the tuple into the instance and the target callable.
2311  // This must be done here in the codegen because it cannot be expressed
2312  // properly in the graph.
2313  __ LoadP(kJSFunctionRegister,
2314  FieldMemOperand(kWasmInstanceRegister, Tuple2::kValue2Offset));
2315  __ LoadP(kWasmInstanceRegister,
2316  FieldMemOperand(kWasmInstanceRegister, Tuple2::kValue1Offset));
2317  __ Push(kWasmInstanceRegister);
2318  }
2319  }
2320  }
2321 
2322  int shrink_slots = frame()->GetTotalFrameSlotCount() -
2323  call_descriptor->CalculateFixedFrameSize();
2324  if (info()->is_osr()) {
2325  // TurboFan OSR-compiled functions cannot be entered directly.
2326  __ Abort(AbortReason::kShouldNotDirectlyEnterOsrFunction);
2327 
2328  // Unoptimized code jumps directly to this entrypoint while the unoptimized
2329  // frame is still on the stack. Optimized code uses OSR values directly from
2330  // the unoptimized frame. Thus, all that needs to be done is to allocate the
2331  // remaining stack slots.
2332  if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
2333  osr_pc_offset_ = __ pc_offset();
2334  shrink_slots -= osr_helper()->UnoptimizedFrameSlots();
2335  ResetSpeculationPoison();
2336  }
2337 
2338  const RegList saves_fp = call_descriptor->CalleeSavedFPRegisters();
2339  const RegList saves = FLAG_enable_embedded_constant_pool
2340  ? call_descriptor->CalleeSavedRegisters() &
2341  ~kConstantPoolRegister.bit()
2342  : call_descriptor->CalleeSavedRegisters();
2343 
2344  if (shrink_slots > 0) {
2345  if (info()->IsWasm() && shrink_slots > 128) {
2346  // For WebAssembly functions with big frames we have to do the stack
2347  // overflow check before we construct the frame. Otherwise we may not
2348  // have enough space on the stack to call the runtime for the stack
2349  // overflow.
2350  Label done;
2351 
2352  // If the frame is bigger than the stack, we throw the stack overflow
2353  // exception unconditionally. Thereby we can avoid the integer overflow
2354  // check in the condition code.
2355  if ((shrink_slots * kPointerSize) < (FLAG_stack_size * 1024)) {
2356  Register scratch = ip;
2357  __ LoadP(
2358  scratch,
2359  FieldMemOperand(kWasmInstanceRegister,
2360  WasmInstanceObject::kRealStackLimitAddressOffset));
2361  __ LoadP(scratch, MemOperand(scratch), r0);
2362  __ Add(scratch, scratch, shrink_slots * kPointerSize, r0);
2363  __ cmpl(sp, scratch);
2364  __ bge(&done);
2365  }
2366 
2367  __ LoadP(r5,
2368  FieldMemOperand(kWasmInstanceRegister,
2369  WasmInstanceObject::kCEntryStubOffset),
2370  r0);
2371  __ Move(cp, Smi::zero());
2372  __ CallRuntimeWithCEntry(Runtime::kThrowWasmStackOverflow, r5);
2373  // We come from WebAssembly, there are no references for the GC.
2374  ReferenceMap* reference_map = new (zone()) ReferenceMap(zone());
2375  RecordSafepoint(reference_map, Safepoint::kSimple, 0,
2376  Safepoint::kNoLazyDeopt);
2377  if (FLAG_debug_code) {
2378  __ stop(GetAbortReason(AbortReason::kUnexpectedReturnFromThrow));
2379  }
2380 
2381  __ bind(&done);
2382  }
2383 
2384  // Skip callee-saved and return slots, which are pushed below.
2385  shrink_slots -= base::bits::CountPopulation(saves);
2386  shrink_slots -= frame()->GetReturnSlotCount();
2387  shrink_slots -=
2388  (kDoubleSize / kPointerSize) * base::bits::CountPopulation(saves_fp);
2389  __ Add(sp, sp, -shrink_slots * kPointerSize, r0);
2390  }
2391 
2392  // Save callee-saved Double registers.
2393  if (saves_fp != 0) {
2394  __ MultiPushDoubles(saves_fp);
2395  DCHECK_EQ(kNumCalleeSavedDoubles, base::bits::CountPopulation(saves_fp));
2396  }
2397 
2398  // Save callee-saved registers.
2399  if (saves != 0) {
2400  __ MultiPush(saves);
2401  // register save area does not include the fp or constant pool pointer.
2402  }
2403 
2404  const int returns = frame()->GetReturnSlotCount();
2405  if (returns != 0) {
2406  // Create space for returns.
2407  __ Add(sp, sp, -returns * kPointerSize, r0);
2408  }
2409 }
2410 
2411 void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
2412  auto call_descriptor = linkage()->GetIncomingDescriptor();
2413  int pop_count = static_cast<int>(call_descriptor->StackParameterCount());
2414 
2415  const int returns = frame()->GetReturnSlotCount();
2416  if (returns != 0) {
2417  // Create space for returns.
2418  __ Add(sp, sp, returns * kPointerSize, r0);
2419  }
2420 
2421  // Restore registers.
2422  const RegList saves = FLAG_enable_embedded_constant_pool
2423  ? call_descriptor->CalleeSavedRegisters() &
2424  ~kConstantPoolRegister.bit()
2425  : call_descriptor->CalleeSavedRegisters();
2426  if (saves != 0) {
2427  __ MultiPop(saves);
2428  }
2429 
2430  // Restore double registers.
2431  const RegList double_saves = call_descriptor->CalleeSavedFPRegisters();
2432  if (double_saves != 0) {
2433  __ MultiPopDoubles(double_saves);
2434  }
2435  PPCOperandConverter g(this, nullptr);
2436 
2437  if (call_descriptor->IsCFunctionCall()) {
2438  AssembleDeconstructFrame();
2439  } else if (frame_access_state()->has_frame()) {
2440  // Canonicalize JSFunction return sites for now unless they have an variable
2441  // number of stack slot pops
2442  if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) {
2443  if (return_label_.is_bound()) {
2444  __ b(&return_label_);
2445  return;
2446  } else {
2447  __ bind(&return_label_);
2448  AssembleDeconstructFrame();
2449  }
2450  } else {
2451  AssembleDeconstructFrame();
2452  }
2453  }
2454  // Constant pool is unavailable since the frame has been destructed
2455  ConstantPoolUnavailableScope constant_pool_unavailable(tasm());
2456  if (pop->IsImmediate()) {
2457  DCHECK(Constant::kInt32 == g.ToConstant(pop).type() ||
2458  Constant::kInt64 == g.ToConstant(pop).type());
2459  pop_count += g.ToConstant(pop).ToInt32();
2460  } else {
2461  __ Drop(g.ToRegister(pop));
2462  }
2463  __ Drop(pop_count);
2464  __ Ret();
2465 }
2466 
2467 void CodeGenerator::FinishCode() { __ EmitConstantPool(); }
2468 
2469 void CodeGenerator::AssembleMove(InstructionOperand* source,
2470  InstructionOperand* destination) {
2471  PPCOperandConverter g(this, nullptr);
2472  // Dispatch on the source and destination operand kinds. Not all
2473  // combinations are possible.
2474  if (source->IsRegister()) {
2475  DCHECK(destination->IsRegister() || destination->IsStackSlot());
2476  Register src = g.ToRegister(source);
2477  if (destination->IsRegister()) {
2478  __ Move(g.ToRegister(destination), src);
2479  } else {
2480  __ StoreP(src, g.ToMemOperand(destination), r0);
2481  }
2482  } else if (source->IsStackSlot()) {
2483  DCHECK(destination->IsRegister() || destination->IsStackSlot());
2484  MemOperand src = g.ToMemOperand(source);
2485  if (destination->IsRegister()) {
2486  __ LoadP(g.ToRegister(destination), src, r0);
2487  } else {
2488  Register temp = kScratchReg;
2489  __ LoadP(temp, src, r0);
2490  __ StoreP(temp, g.ToMemOperand(destination), r0);
2491  }
2492  } else if (source->IsConstant()) {
2493  Constant src = g.ToConstant(source);
2494  if (destination->IsRegister() || destination->IsStackSlot()) {
2495  Register dst =
2496  destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
2497  switch (src.type()) {
2498  case Constant::kInt32:
2499 #if V8_TARGET_ARCH_PPC64
2500  if (false) {
2501 #else
2502  if (RelocInfo::IsWasmReference(src.rmode())) {
2503 #endif
2504  __ mov(dst, Operand(src.ToInt32(), src.rmode()));
2505  } else {
2506  __ mov(dst, Operand(src.ToInt32()));
2507  }
2508  break;
2509  case Constant::kInt64:
2510 #if V8_TARGET_ARCH_PPC64
2511  if (RelocInfo::IsWasmReference(src.rmode())) {
2512  __ mov(dst, Operand(src.ToInt64(), src.rmode()));
2513  } else {
2514 #endif
2515  __ mov(dst, Operand(src.ToInt64()));
2516 #if V8_TARGET_ARCH_PPC64
2517  }
2518 #endif
2519  break;
2520  case Constant::kFloat32:
2521  __ mov(dst, Operand::EmbeddedNumber(src.ToFloat32()));
2522  break;
2523  case Constant::kFloat64:
2524  __ mov(dst, Operand::EmbeddedNumber(src.ToFloat64().value()));
2525  break;
2526  case Constant::kExternalReference:
2527  __ Move(dst, src.ToExternalReference());
2528  break;
2529  case Constant::kDelayedStringConstant:
2530  __ mov(dst, Operand::EmbeddedStringConstant(
2531  src.ToDelayedStringConstant()));
2532  break;
2533  case Constant::kHeapObject: {
2534  Handle<HeapObject> src_object = src.ToHeapObject();
2535  RootIndex index;
2536  if (IsMaterializableFromRoot(src_object, &index)) {
2537  __ LoadRoot(dst, index);
2538  } else {
2539  __ Move(dst, src_object);
2540  }
2541  break;
2542  }
2543  case Constant::kRpoNumber:
2544  UNREACHABLE(); // TODO(dcarney): loading RPO constants on PPC.
2545  break;
2546  }
2547  if (destination->IsStackSlot()) {
2548  __ StoreP(dst, g.ToMemOperand(destination), r0);
2549  }
2550  } else {
2551  DoubleRegister dst = destination->IsFPRegister()
2552  ? g.ToDoubleRegister(destination)
2553  : kScratchDoubleReg;
2554  Double value;
2555 #if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
2556  // casting double precision snan to single precision
2557  // converts it to qnan on ia32/x64
2558  if (src.type() == Constant::kFloat32) {
2559  uint32_t val = src.ToFloat32AsInt();
2560  if ((val & 0x7F800000) == 0x7F800000) {
2561  uint64_t dval = static_cast<uint64_t>(val);
2562  dval = ((dval & 0xC0000000) << 32) | ((dval & 0x40000000) << 31) |
2563  ((dval & 0x40000000) << 30) | ((dval & 0x7FFFFFFF) << 29);
2564  value = Double(dval);
2565  } else {
2566  value = Double(static_cast<double>(src.ToFloat32()));
2567  }
2568  } else {
2569  value = Double(src.ToFloat64());
2570  }
2571 #else
2572  value = src.type() == Constant::kFloat32
2573  ? Double(static_cast<double>(src.ToFloat32()))
2574  : Double(src.ToFloat64());
2575 #endif
2576  __ LoadDoubleLiteral(dst, value, kScratchReg);
2577  if (destination->IsDoubleStackSlot()) {
2578  __ StoreDouble(dst, g.ToMemOperand(destination), r0);
2579  } else if (destination->IsFloatStackSlot()) {
2580  __ StoreSingle(dst, g.ToMemOperand(destination), r0);
2581  }
2582  }
2583  } else if (source->IsFPRegister()) {
2584  DoubleRegister src = g.ToDoubleRegister(source);
2585  if (destination->IsFPRegister()) {
2586  DoubleRegister dst = g.ToDoubleRegister(destination);
2587  __ Move(dst, src);
2588  } else {
2589  DCHECK(destination->IsFPStackSlot());
2590  LocationOperand* op = LocationOperand::cast(source);
2591  if (op->representation() == MachineRepresentation::kFloat64) {
2592  __ StoreDouble(src, g.ToMemOperand(destination), r0);
2593  } else {
2594  __ StoreSingle(src, g.ToMemOperand(destination), r0);
2595  }
2596  }
2597  } else if (source->IsFPStackSlot()) {
2598  DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
2599  MemOperand src = g.ToMemOperand(source);
2600  if (destination->IsFPRegister()) {
2601  LocationOperand* op = LocationOperand::cast(source);
2602  if (op->representation() == MachineRepresentation::kFloat64) {
2603  __ LoadDouble(g.ToDoubleRegister(destination), src, r0);
2604  } else {
2605  __ LoadSingle(g.ToDoubleRegister(destination), src, r0);
2606  }
2607  } else {
2608  LocationOperand* op = LocationOperand::cast(source);
2609  DoubleRegister temp = kScratchDoubleReg;
2610  if (op->representation() == MachineRepresentation::kFloat64) {
2611  __ LoadDouble(temp, src, r0);
2612  __ StoreDouble(temp, g.ToMemOperand(destination), r0);
2613  } else {
2614  __ LoadSingle(temp, src, r0);
2615  __ StoreSingle(temp, g.ToMemOperand(destination), r0);
2616  }
2617  }
2618  } else {
2619  UNREACHABLE();
2620  }
2621 }
2622 
2623 // Swaping contents in source and destination.
2624 // source and destination could be:
2625 // Register,
2626 // FloatRegister,
2627 // DoubleRegister,
2628 // StackSlot,
2629 // FloatStackSlot,
2630 // or DoubleStackSlot
2631 void CodeGenerator::AssembleSwap(InstructionOperand* source,
2632  InstructionOperand* destination) {
2633  PPCOperandConverter g(this, nullptr);
2634  if (source->IsRegister()) {
2635  Register src = g.ToRegister(source);
2636  if (destination->IsRegister()) {
2637  __ SwapP(src, g.ToRegister(destination), kScratchReg);
2638  } else {
2639  DCHECK(destination->IsStackSlot());
2640  __ SwapP(src, g.ToMemOperand(destination), kScratchReg);
2641  }
2642  } else if (source->IsStackSlot()) {
2643  DCHECK(destination->IsStackSlot());
2644  __ SwapP(g.ToMemOperand(source), g.ToMemOperand(destination), kScratchReg,
2645  r0);
2646  } else if (source->IsFloatRegister()) {
2647  DoubleRegister src = g.ToDoubleRegister(source);
2648  if (destination->IsFloatRegister()) {
2649  __ SwapFloat32(src, g.ToDoubleRegister(destination), kScratchDoubleReg);
2650  } else {
2651  DCHECK(destination->IsFloatStackSlot());
2652  __ SwapFloat32(src, g.ToMemOperand(destination), kScratchDoubleReg);
2653  }
2654  } else if (source->IsDoubleRegister()) {
2655  DoubleRegister src = g.ToDoubleRegister(source);
2656  if (destination->IsDoubleRegister()) {
2657  __ SwapDouble(src, g.ToDoubleRegister(destination), kScratchDoubleReg);
2658  } else {
2659  DCHECK(destination->IsDoubleStackSlot());
2660  __ SwapDouble(src, g.ToMemOperand(destination), kScratchDoubleReg);
2661  }
2662  } else if (source->IsFloatStackSlot()) {
2663  DCHECK(destination->IsFloatStackSlot());
2664  __ SwapFloat32(g.ToMemOperand(source), g.ToMemOperand(destination),
2665  kScratchDoubleReg, d0);
2666  } else if (source->IsDoubleStackSlot()) {
2667  DCHECK(destination->IsDoubleStackSlot());
2668  __ SwapDouble(g.ToMemOperand(source), g.ToMemOperand(destination),
2669  kScratchDoubleReg, d0);
2670  } else if (source->IsSimd128Register()) {
2671  UNREACHABLE();
2672  } else {
2673  UNREACHABLE();
2674  }
2675 
2676  return;
2677 }
2678 
2679 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
2680  for (size_t index = 0; index < target_count; ++index) {
2681  __ emit_label_addr(targets[index]);
2682  }
2683 }
2684 
2685 #undef __
2686 
2687 } // namespace compiler
2688 } // namespace internal
2689 } // namespace v8
STL namespace.
Definition: libplatform.h:13