• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/compiler/code-generator.h"
6 
7 #include "src/compilation-info.h"
8 #include "src/compiler/code-generator-impl.h"
9 #include "src/compiler/gap-resolver.h"
10 #include "src/compiler/node-matchers.h"
11 #include "src/compiler/osr.h"
12 #include "src/s390/macro-assembler-s390.h"
13 
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17 
18 #define __ masm()->
19 
20 #define kScratchReg ip
21 
22 // Adds S390-specific methods to convert InstructionOperands.
23 class S390OperandConverter final : public InstructionOperandConverter {
24  public:
S390OperandConverter(CodeGenerator * gen,Instruction * instr)25   S390OperandConverter(CodeGenerator* gen, Instruction* instr)
26       : InstructionOperandConverter(gen, instr) {}
27 
OutputCount()28   size_t OutputCount() { return instr_->OutputCount(); }
29 
Is64BitOperand(int index)30   bool Is64BitOperand(int index) {
31     return LocationOperand::cast(instr_->InputAt(index))->representation() ==
32            MachineRepresentation::kWord64;
33   }
34 
Is32BitOperand(int index)35   bool Is32BitOperand(int index) {
36     return LocationOperand::cast(instr_->InputAt(index))->representation() ==
37            MachineRepresentation::kWord32;
38   }
39 
CompareLogical() const40   bool CompareLogical() const {
41     switch (instr_->flags_condition()) {
42       case kUnsignedLessThan:
43       case kUnsignedGreaterThanOrEqual:
44       case kUnsignedLessThanOrEqual:
45       case kUnsignedGreaterThan:
46         return true;
47       default:
48         return false;
49     }
50     UNREACHABLE();
51     return false;
52   }
53 
InputImmediate(size_t index)54   Operand InputImmediate(size_t index) {
55     Constant constant = ToConstant(instr_->InputAt(index));
56     switch (constant.type()) {
57       case Constant::kInt32:
58         return Operand(constant.ToInt32());
59       case Constant::kFloat32:
60         return Operand(
61             isolate()->factory()->NewNumber(constant.ToFloat32(), TENURED));
62       case Constant::kFloat64:
63         return Operand(
64             isolate()->factory()->NewNumber(constant.ToFloat64(), TENURED));
65       case Constant::kInt64:
66 #if V8_TARGET_ARCH_S390X
67         return Operand(constant.ToInt64());
68 #endif
69       case Constant::kExternalReference:
70       case Constant::kHeapObject:
71       case Constant::kRpoNumber:
72         break;
73     }
74     UNREACHABLE();
75     return Operand::Zero();
76   }
77 
MemoryOperand(AddressingMode * mode,size_t * first_index)78   MemOperand MemoryOperand(AddressingMode* mode, size_t* first_index) {
79     const size_t index = *first_index;
80     if (mode) *mode = AddressingModeField::decode(instr_->opcode());
81     switch (AddressingModeField::decode(instr_->opcode())) {
82       case kMode_None:
83         break;
84       case kMode_MR:
85         *first_index += 1;
86         return MemOperand(InputRegister(index + 0), 0);
87       case kMode_MRI:
88         *first_index += 2;
89         return MemOperand(InputRegister(index + 0), InputInt32(index + 1));
90       case kMode_MRR:
91         *first_index += 2;
92         return MemOperand(InputRegister(index + 0), InputRegister(index + 1));
93       case kMode_MRRI:
94         *first_index += 3;
95         return MemOperand(InputRegister(index + 0), InputRegister(index + 1),
96                           InputInt32(index + 2));
97     }
98     UNREACHABLE();
99     return MemOperand(r0);
100   }
101 
MemoryOperand(AddressingMode * mode=NULL,size_t first_index=0)102   MemOperand MemoryOperand(AddressingMode* mode = NULL,
103                            size_t first_index = 0) {
104     return MemoryOperand(mode, &first_index);
105   }
106 
ToMemOperand(InstructionOperand * op) const107   MemOperand ToMemOperand(InstructionOperand* op) const {
108     DCHECK_NOT_NULL(op);
109     DCHECK(op->IsStackSlot() || op->IsFPStackSlot());
110     return SlotToMemOperand(AllocatedOperand::cast(op)->index());
111   }
112 
SlotToMemOperand(int slot) const113   MemOperand SlotToMemOperand(int slot) const {
114     FrameOffset offset = frame_access_state()->GetFrameOffset(slot);
115     return MemOperand(offset.from_stack_pointer() ? sp : fp, offset.offset());
116   }
117 
InputStackSlot(size_t index)118   MemOperand InputStackSlot(size_t index) {
119     InstructionOperand* op = instr_->InputAt(index);
120     return SlotToMemOperand(AllocatedOperand::cast(op)->index());
121   }
122 
InputStackSlot32(size_t index)123   MemOperand InputStackSlot32(size_t index) {
124 #if V8_TARGET_ARCH_S390X && !V8_TARGET_LITTLE_ENDIAN
125     // We want to read the 32-bits directly from memory
126     MemOperand mem = InputStackSlot(index);
127     return MemOperand(mem.rb(), mem.rx(), mem.offset() + 4);
128 #else
129     return InputStackSlot(index);
130 #endif
131   }
132 };
133 
HasRegisterOutput(Instruction * instr,int index=0)134 static inline bool HasRegisterOutput(Instruction* instr, int index = 0) {
135   return instr->OutputCount() > 0 && instr->OutputAt(index)->IsRegister();
136 }
137 
HasRegisterInput(Instruction * instr,int index)138 static inline bool HasRegisterInput(Instruction* instr, int index) {
139   return instr->InputAt(index)->IsRegister();
140 }
141 
HasFPRegisterInput(Instruction * instr,int index)142 static inline bool HasFPRegisterInput(Instruction* instr, int index) {
143   return instr->InputAt(index)->IsFPRegister();
144 }
145 
HasImmediateInput(Instruction * instr,size_t index)146 static inline bool HasImmediateInput(Instruction* instr, size_t index) {
147   return instr->InputAt(index)->IsImmediate();
148 }
149 
HasStackSlotInput(Instruction * instr,size_t index)150 static inline bool HasStackSlotInput(Instruction* instr, size_t index) {
151   return instr->InputAt(index)->IsStackSlot();
152 }
153 
HasFPStackSlotInput(Instruction * instr,size_t index)154 static inline bool HasFPStackSlotInput(Instruction* instr, size_t index) {
155   return instr->InputAt(index)->IsFPStackSlot();
156 }
157 
158 namespace {
159 
160 class OutOfLineLoadNAN32 final : public OutOfLineCode {
161  public:
OutOfLineLoadNAN32(CodeGenerator * gen,DoubleRegister result)162   OutOfLineLoadNAN32(CodeGenerator* gen, DoubleRegister result)
163       : OutOfLineCode(gen), result_(result) {}
164 
Generate()165   void Generate() final {
166     __ LoadDoubleLiteral(result_, std::numeric_limits<float>::quiet_NaN(),
167                          kScratchReg);
168   }
169 
170  private:
171   DoubleRegister const result_;
172 };
173 
174 class OutOfLineLoadNAN64 final : public OutOfLineCode {
175  public:
OutOfLineLoadNAN64(CodeGenerator * gen,DoubleRegister result)176   OutOfLineLoadNAN64(CodeGenerator* gen, DoubleRegister result)
177       : OutOfLineCode(gen), result_(result) {}
178 
Generate()179   void Generate() final {
180     __ LoadDoubleLiteral(result_, std::numeric_limits<double>::quiet_NaN(),
181                          kScratchReg);
182   }
183 
184  private:
185   DoubleRegister const result_;
186 };
187 
188 class OutOfLineLoadZero final : public OutOfLineCode {
189  public:
OutOfLineLoadZero(CodeGenerator * gen,Register result)190   OutOfLineLoadZero(CodeGenerator* gen, Register result)
191       : OutOfLineCode(gen), result_(result) {}
192 
Generate()193   void Generate() final { __ LoadImmP(result_, Operand::Zero()); }
194 
195  private:
196   Register const result_;
197 };
198 
199 class OutOfLineRecordWrite final : public OutOfLineCode {
200  public:
OutOfLineRecordWrite(CodeGenerator * gen,Register object,Register offset,Register value,Register scratch0,Register scratch1,RecordWriteMode mode)201   OutOfLineRecordWrite(CodeGenerator* gen, Register object, Register offset,
202                        Register value, Register scratch0, Register scratch1,
203                        RecordWriteMode mode)
204       : OutOfLineCode(gen),
205         object_(object),
206         offset_(offset),
207         offset_immediate_(0),
208         value_(value),
209         scratch0_(scratch0),
210         scratch1_(scratch1),
211         mode_(mode),
212         must_save_lr_(!gen->frame_access_state()->has_frame()) {}
213 
OutOfLineRecordWrite(CodeGenerator * gen,Register object,int32_t offset,Register value,Register scratch0,Register scratch1,RecordWriteMode mode)214   OutOfLineRecordWrite(CodeGenerator* gen, Register object, int32_t offset,
215                        Register value, Register scratch0, Register scratch1,
216                        RecordWriteMode mode)
217       : OutOfLineCode(gen),
218         object_(object),
219         offset_(no_reg),
220         offset_immediate_(offset),
221         value_(value),
222         scratch0_(scratch0),
223         scratch1_(scratch1),
224         mode_(mode),
225         must_save_lr_(!gen->frame_access_state()->has_frame()) {}
226 
Generate()227   void Generate() final {
228     if (mode_ > RecordWriteMode::kValueIsPointer) {
229       __ JumpIfSmi(value_, exit());
230     }
231     __ CheckPageFlag(value_, scratch0_,
232                      MemoryChunk::kPointersToHereAreInterestingMask, eq,
233                      exit());
234     RememberedSetAction const remembered_set_action =
235         mode_ > RecordWriteMode::kValueIsMap ? EMIT_REMEMBERED_SET
236                                              : OMIT_REMEMBERED_SET;
237     SaveFPRegsMode const save_fp_mode =
238         frame()->DidAllocateDoubleRegisters() ? kSaveFPRegs : kDontSaveFPRegs;
239     if (must_save_lr_) {
240       // We need to save and restore r14 if the frame was elided.
241       __ Push(r14);
242     }
243     RecordWriteStub stub(isolate(), object_, scratch0_, scratch1_,
244                          remembered_set_action, save_fp_mode);
245     if (offset_.is(no_reg)) {
246       __ AddP(scratch1_, object_, Operand(offset_immediate_));
247     } else {
248       DCHECK_EQ(0, offset_immediate_);
249       __ AddP(scratch1_, object_, offset_);
250     }
251     __ CallStub(&stub);
252     if (must_save_lr_) {
253       // We need to save and restore r14 if the frame was elided.
254       __ Pop(r14);
255     }
256   }
257 
258  private:
259   Register const object_;
260   Register const offset_;
261   int32_t const offset_immediate_;  // Valid if offset_.is(no_reg).
262   Register const value_;
263   Register const scratch0_;
264   Register const scratch1_;
265   RecordWriteMode const mode_;
266   bool must_save_lr_;
267 };
268 
FlagsConditionToCondition(FlagsCondition condition,ArchOpcode op)269 Condition FlagsConditionToCondition(FlagsCondition condition, ArchOpcode op) {
270   switch (condition) {
271     case kEqual:
272       return eq;
273     case kNotEqual:
274       return ne;
275     case kUnsignedLessThan:
276       // unsigned number never less than 0
277       if (op == kS390_LoadAndTestWord32 || op == kS390_LoadAndTestWord64)
278         return CC_NOP;
279     // fall through
280     case kSignedLessThan:
281       return lt;
282     case kUnsignedGreaterThanOrEqual:
283       // unsigned number always greater than or equal 0
284       if (op == kS390_LoadAndTestWord32 || op == kS390_LoadAndTestWord64)
285         return CC_ALWAYS;
286     // fall through
287     case kSignedGreaterThanOrEqual:
288       return ge;
289     case kUnsignedLessThanOrEqual:
290       // unsigned number never less than 0
291       if (op == kS390_LoadAndTestWord32 || op == kS390_LoadAndTestWord64)
292         return CC_EQ;
293     // fall through
294     case kSignedLessThanOrEqual:
295       return le;
296     case kUnsignedGreaterThan:
297       // unsigned number always greater than or equal 0
298       if (op == kS390_LoadAndTestWord32 || op == kS390_LoadAndTestWord64)
299         return ne;
300     // fall through
301     case kSignedGreaterThan:
302       return gt;
303     case kOverflow:
304       // Overflow checked for AddP/SubP only.
305       switch (op) {
306         case kS390_Add32:
307         case kS390_Add64:
308         case kS390_Sub32:
309         case kS390_Sub64:
310           return overflow;
311         default:
312           break;
313       }
314       break;
315     case kNotOverflow:
316       switch (op) {
317         case kS390_Add32:
318         case kS390_Add64:
319         case kS390_Sub32:
320         case kS390_Sub64:
321           return nooverflow;
322         default:
323           break;
324       }
325       break;
326     default:
327       break;
328   }
329   UNREACHABLE();
330   return kNoCondition;
331 }
332 
333 typedef void (MacroAssembler::*RRTypeInstr)(Register, Register);
334 typedef void (MacroAssembler::*RMTypeInstr)(Register, const MemOperand&);
335 typedef void (MacroAssembler::*RITypeInstr)(Register, const Operand&);
336 typedef void (MacroAssembler::*RRRTypeInstr)(Register, Register, Register);
337 typedef void (MacroAssembler::*RRMTypeInstr)(Register, Register,
338                                              const MemOperand&);
339 typedef void (MacroAssembler::*RRITypeInstr)(Register, Register,
340                                              const Operand&);
341 
342 #define CHECK_AND_ZERO_EXT_OUTPUT(num)                                   \
343   {                                                                      \
344     CHECK(HasImmediateInput(instr, (num)));                              \
345     int doZeroExt = i.InputInt32(num);                                   \
346     if (doZeroExt) masm->LoadlW(i.OutputRegister(), i.OutputRegister()); \
347   }
348 
AssembleBinOp(S390OperandConverter & i,MacroAssembler * masm,Instruction * instr,RRTypeInstr rr_instr,RMTypeInstr rm_instr,RITypeInstr ri_instr)349 void AssembleBinOp(S390OperandConverter& i, MacroAssembler* masm,
350                    Instruction* instr, RRTypeInstr rr_instr,
351                    RMTypeInstr rm_instr, RITypeInstr ri_instr) {
352   CHECK(i.OutputRegister().is(i.InputRegister(0)));
353   AddressingMode mode = AddressingModeField::decode(instr->opcode());
354   int zeroExtIndex = 2;
355   if (mode != kMode_None) {
356     size_t first_index = 1;
357     MemOperand operand = i.MemoryOperand(&mode, &first_index);
358     zeroExtIndex = first_index;
359     CHECK(rm_instr != NULL);
360     (masm->*rm_instr)(i.OutputRegister(), operand);
361   } else if (HasRegisterInput(instr, 1)) {
362     (masm->*rr_instr)(i.OutputRegister(), i.InputRegister(1));
363   } else if (HasImmediateInput(instr, 1)) {
364     (masm->*ri_instr)(i.OutputRegister(), i.InputImmediate(1));
365   } else if (HasStackSlotInput(instr, 1)) {
366     (masm->*rm_instr)(i.OutputRegister(), i.InputStackSlot32(1));
367   } else {
368     UNREACHABLE();
369   }
370   CHECK_AND_ZERO_EXT_OUTPUT(zeroExtIndex);
371 }
372 
AssembleBinOp(S390OperandConverter & i,MacroAssembler * masm,Instruction * instr,RRRTypeInstr rrr_instr,RMTypeInstr rm_instr,RITypeInstr ri_instr)373 void AssembleBinOp(S390OperandConverter& i, MacroAssembler* masm,
374                    Instruction* instr, RRRTypeInstr rrr_instr,
375                    RMTypeInstr rm_instr, RITypeInstr ri_instr) {
376   AddressingMode mode = AddressingModeField::decode(instr->opcode());
377   int zeroExtIndex = 2;
378   if (mode != kMode_None) {
379     CHECK(i.OutputRegister().is(i.InputRegister(0)));
380     size_t first_index = 1;
381     MemOperand operand = i.MemoryOperand(&mode, &first_index);
382     zeroExtIndex = first_index;
383     CHECK(rm_instr != NULL);
384     (masm->*rm_instr)(i.OutputRegister(), operand);
385   } else if (HasRegisterInput(instr, 1)) {
386     (masm->*rrr_instr)(i.OutputRegister(), i.InputRegister(0),
387                        i.InputRegister(1));
388   } else if (HasImmediateInput(instr, 1)) {
389     CHECK(i.OutputRegister().is(i.InputRegister(0)));
390     (masm->*ri_instr)(i.OutputRegister(), i.InputImmediate(1));
391   } else if (HasStackSlotInput(instr, 1)) {
392     CHECK(i.OutputRegister().is(i.InputRegister(0)));
393     (masm->*rm_instr)(i.OutputRegister(), i.InputStackSlot32(1));
394   } else {
395     UNREACHABLE();
396   }
397   CHECK_AND_ZERO_EXT_OUTPUT(zeroExtIndex);
398 }
399 
AssembleBinOp(S390OperandConverter & i,MacroAssembler * masm,Instruction * instr,RRRTypeInstr rrr_instr,RMTypeInstr rm_instr,RRITypeInstr rri_instr)400 void AssembleBinOp(S390OperandConverter& i, MacroAssembler* masm,
401                    Instruction* instr, RRRTypeInstr rrr_instr,
402                    RMTypeInstr rm_instr, RRITypeInstr rri_instr) {
403   AddressingMode mode = AddressingModeField::decode(instr->opcode());
404   int zeroExtIndex = 2;
405   if (mode != kMode_None) {
406     CHECK(i.OutputRegister().is(i.InputRegister(0)));
407     size_t first_index = 1;
408     MemOperand operand = i.MemoryOperand(&mode, &first_index);
409     zeroExtIndex = first_index;
410     CHECK(rm_instr != NULL);
411     (masm->*rm_instr)(i.OutputRegister(), operand);
412   } else if (HasRegisterInput(instr, 1)) {
413     (masm->*rrr_instr)(i.OutputRegister(), i.InputRegister(0),
414                        i.InputRegister(1));
415   } else if (HasImmediateInput(instr, 1)) {
416     (masm->*rri_instr)(i.OutputRegister(), i.InputRegister(0),
417                        i.InputImmediate(1));
418   } else if (HasStackSlotInput(instr, 1)) {
419     CHECK(i.OutputRegister().is(i.InputRegister(0)));
420     (masm->*rm_instr)(i.OutputRegister(), i.InputStackSlot32(1));
421   } else {
422     UNREACHABLE();
423   }
424   CHECK_AND_ZERO_EXT_OUTPUT(zeroExtIndex);
425 }
426 
AssembleBinOp(S390OperandConverter & i,MacroAssembler * masm,Instruction * instr,RRRTypeInstr rrr_instr,RRMTypeInstr rrm_instr,RRITypeInstr rri_instr)427 void AssembleBinOp(S390OperandConverter& i, MacroAssembler* masm,
428                    Instruction* instr, RRRTypeInstr rrr_instr,
429                    RRMTypeInstr rrm_instr, RRITypeInstr rri_instr) {
430   AddressingMode mode = AddressingModeField::decode(instr->opcode());
431   int zeroExtIndex = 2;
432   if (mode != kMode_None) {
433     size_t first_index = 1;
434     MemOperand operand = i.MemoryOperand(&mode, &first_index);
435     zeroExtIndex = first_index;
436     CHECK(rrm_instr != NULL);
437     (masm->*rrm_instr)(i.OutputRegister(), i.InputRegister(0), operand);
438   } else if (HasRegisterInput(instr, 1)) {
439     (masm->*rrr_instr)(i.OutputRegister(), i.InputRegister(0),
440                        i.InputRegister(1));
441   } else if (HasImmediateInput(instr, 1)) {
442     (masm->*rri_instr)(i.OutputRegister(), i.InputRegister(0),
443                        i.InputImmediate(1));
444   } else if (HasStackSlotInput(instr, 1)) {
445     (masm->*rrm_instr)(i.OutputRegister(), i.InputRegister(0),
446                        i.InputStackSlot32(1));
447   } else {
448     UNREACHABLE();
449   }
450   CHECK_AND_ZERO_EXT_OUTPUT(zeroExtIndex);
451 }
452 
AssembleBinOp(S390OperandConverter & i,MacroAssembler * masm,Instruction * instr,RRRTypeInstr rrr_instr,RRITypeInstr rri_instr)453 void AssembleBinOp(S390OperandConverter& i, MacroAssembler* masm,
454                    Instruction* instr, RRRTypeInstr rrr_instr,
455                    RRITypeInstr rri_instr) {
456   AddressingMode mode = AddressingModeField::decode(instr->opcode());
457   CHECK(mode == kMode_None);
458   int zeroExtIndex = 2;
459   if (HasRegisterInput(instr, 1)) {
460     (masm->*rrr_instr)(i.OutputRegister(), i.InputRegister(0),
461                        i.InputRegister(1));
462   } else if (HasImmediateInput(instr, 1)) {
463     (masm->*rri_instr)(i.OutputRegister(), i.InputRegister(0),
464                        i.InputImmediate(1));
465   } else {
466     UNREACHABLE();
467   }
468   CHECK_AND_ZERO_EXT_OUTPUT(zeroExtIndex);
469 }
470 
AssembleBinOp(S390OperandConverter & i,MacroAssembler * masm,Instruction * instr,RRTypeInstr rr_instr,RITypeInstr ri_instr)471 void AssembleBinOp(S390OperandConverter& i, MacroAssembler* masm,
472                    Instruction* instr, RRTypeInstr rr_instr,
473                    RITypeInstr ri_instr) {
474   AddressingMode mode = AddressingModeField::decode(instr->opcode());
475   CHECK(mode == kMode_None);
476   CHECK(i.OutputRegister().is(i.InputRegister(0)));
477   int zeroExtIndex = 2;
478   if (HasRegisterInput(instr, 1)) {
479     (masm->*rr_instr)(i.OutputRegister(), i.InputRegister(1));
480   } else if (HasImmediateInput(instr, 1)) {
481     (masm->*ri_instr)(i.OutputRegister(), i.InputImmediate(1));
482   } else {
483     UNREACHABLE();
484   }
485   CHECK_AND_ZERO_EXT_OUTPUT(zeroExtIndex);
486 }
487 
488 #define ASSEMBLE_BIN_OP(instr1, instr2, instr3)            \
489   AssembleBinOp(i, masm(), instr, &MacroAssembler::instr1, \
490                 &MacroAssembler::instr2, &MacroAssembler::instr3)
491 
492 #undef CHECK_AND_ZERO_EXT_OUTPUT
493 
494 }  // namespace
495 
496 #define CHECK_AND_ZERO_EXT_OUTPUT(num)                                \
497   {                                                                   \
498     CHECK(HasImmediateInput(instr, (num)));                           \
499     int doZeroExt = i.InputInt32(num);                                \
500     if (doZeroExt) __ LoadlW(i.OutputRegister(), i.OutputRegister()); \
501   }
502 
503 #define ASSEMBLE_FLOAT_UNOP(asm_instr)                                \
504   do {                                                                \
505     __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0)); \
506   } while (0)
507 
508 #define ASSEMBLE_FLOAT_BINOP(asm_instr)                              \
509   do {                                                               \
510     __ asm_instr(i.OutputDoubleRegister(), i.InputDoubleRegister(0), \
511                  i.InputDoubleRegister(1));                          \
512   } while (0)
513 
514 #define ASSEMBLE_BINOP(asm_instr)                          \
515   do {                                                     \
516     if (HasRegisterInput(instr, 1)) {                      \
517       __ asm_instr(i.OutputRegister(), i.InputRegister(0), \
518                    i.InputRegister(1));                    \
519     } else if (HasImmediateInput(instr, 1)) {              \
520       __ asm_instr(i.OutputRegister(), i.InputRegister(0), \
521                    i.InputImmediate(1));                   \
522     } else {                                               \
523       UNIMPLEMENTED();                                     \
524     }                                                      \
525   } while (0)
526 
527 #define ASSEMBLE_COMPARE(cmp_instr, cmpl_instr)                         \
528   do {                                                                  \
529     AddressingMode mode = AddressingModeField::decode(instr->opcode()); \
530     if (mode != kMode_None) {                                           \
531       size_t first_index = 1;                                           \
532       MemOperand operand = i.MemoryOperand(&mode, &first_index);        \
533       if (i.CompareLogical()) {                                         \
534         __ cmpl_instr(i.InputRegister(0), operand);                     \
535       } else {                                                          \
536         __ cmp_instr(i.InputRegister(0), operand);                      \
537       }                                                                 \
538     } else if (HasRegisterInput(instr, 1)) {                            \
539       if (i.CompareLogical()) {                                         \
540         __ cmpl_instr(i.InputRegister(0), i.InputRegister(1));          \
541       } else {                                                          \
542         __ cmp_instr(i.InputRegister(0), i.InputRegister(1));           \
543       }                                                                 \
544     } else if (HasImmediateInput(instr, 1)) {                           \
545       if (i.CompareLogical()) {                                         \
546         __ cmpl_instr(i.InputRegister(0), i.InputImmediate(1));         \
547       } else {                                                          \
548         __ cmp_instr(i.InputRegister(0), i.InputImmediate(1));          \
549       }                                                                 \
550     } else {                                                            \
551       DCHECK(HasStackSlotInput(instr, 1));                              \
552       if (i.CompareLogical()) {                                         \
553         __ cmpl_instr(i.InputRegister(0), i.InputStackSlot(1));         \
554       } else {                                                          \
555         __ cmp_instr(i.InputRegister(0), i.InputStackSlot(1));          \
556       }                                                                 \
557     }                                                                   \
558   } while (0)
559 
560 #define ASSEMBLE_COMPARE32(cmp_instr, cmpl_instr)                       \
561   do {                                                                  \
562     AddressingMode mode = AddressingModeField::decode(instr->opcode()); \
563     if (mode != kMode_None) {                                           \
564       size_t first_index = 1;                                           \
565       MemOperand operand = i.MemoryOperand(&mode, &first_index);        \
566       if (i.CompareLogical()) {                                         \
567         __ cmpl_instr(i.InputRegister(0), operand);                     \
568       } else {                                                          \
569         __ cmp_instr(i.InputRegister(0), operand);                      \
570       }                                                                 \
571     } else if (HasRegisterInput(instr, 1)) {                            \
572       if (i.CompareLogical()) {                                         \
573         __ cmpl_instr(i.InputRegister(0), i.InputRegister(1));          \
574       } else {                                                          \
575         __ cmp_instr(i.InputRegister(0), i.InputRegister(1));           \
576       }                                                                 \
577     } else if (HasImmediateInput(instr, 1)) {                           \
578       if (i.CompareLogical()) {                                         \
579         __ cmpl_instr(i.InputRegister(0), i.InputImmediate(1));         \
580       } else {                                                          \
581         __ cmp_instr(i.InputRegister(0), i.InputImmediate(1));          \
582       }                                                                 \
583     } else {                                                            \
584       DCHECK(HasStackSlotInput(instr, 1));                              \
585       if (i.CompareLogical()) {                                         \
586         __ cmpl_instr(i.InputRegister(0), i.InputStackSlot32(1));       \
587       } else {                                                          \
588         __ cmp_instr(i.InputRegister(0), i.InputStackSlot32(1));        \
589       }                                                                 \
590     }                                                                   \
591   } while (0)
592 
593 #define ASSEMBLE_FLOAT_COMPARE(cmp_rr_instr, cmp_rm_instr, load_instr)     \
594   do {                                                                     \
595     AddressingMode mode = AddressingModeField::decode(instr->opcode());    \
596     if (mode != kMode_None) {                                              \
597       size_t first_index = 1;                                              \
598       MemOperand operand = i.MemoryOperand(&mode, &first_index);           \
599       __ cmp_rm_instr(i.InputDoubleRegister(0), operand);                  \
600     } else if (HasFPRegisterInput(instr, 1)) {                             \
601       __ cmp_rr_instr(i.InputDoubleRegister(0), i.InputDoubleRegister(1)); \
602     } else {                                                               \
603       USE(HasFPStackSlotInput);                                            \
604       DCHECK(HasFPStackSlotInput(instr, 1));                               \
605       MemOperand operand = i.InputStackSlot(1);                            \
606       if (operand.offset() >= 0) {                                         \
607         __ cmp_rm_instr(i.InputDoubleRegister(0), operand);                \
608       } else {                                                             \
609         __ load_instr(kScratchDoubleReg, operand);                         \
610         __ cmp_rr_instr(i.InputDoubleRegister(0), kScratchDoubleReg);      \
611       }                                                                    \
612     }                                                                      \
613   } while (0)
614 
615 // Divide instruction dr will implicity use register pair
616 // r0 & r1 below.
617 // R0:R1 = R1 / divisor - R0 remainder
618 // Copy remainder to output reg
619 #define ASSEMBLE_MODULO(div_instr, shift_instr) \
620   do {                                          \
621     __ LoadRR(r0, i.InputRegister(0));          \
622     __ shift_instr(r0, Operand(32));            \
623     __ div_instr(r0, i.InputRegister(1));       \
624     __ LoadlW(i.OutputRegister(), r0);          \
625   } while (0)
626 
627 #define ASSEMBLE_FLOAT_MODULO()                                               \
628   do {                                                                        \
629     FrameScope scope(masm(), StackFrame::MANUAL);                             \
630     __ PrepareCallCFunction(0, 2, kScratchReg);                               \
631     __ MovToFloatParameters(i.InputDoubleRegister(0),                         \
632                             i.InputDoubleRegister(1));                        \
633     __ CallCFunction(ExternalReference::mod_two_doubles_operation(isolate()), \
634                      0, 2);                                                   \
635     __ MovFromFloatResult(i.OutputDoubleRegister());                          \
636   } while (0)
637 
638 #define ASSEMBLE_IEEE754_UNOP(name)                                            \
639   do {                                                                         \
640     /* TODO(bmeurer): We should really get rid of this special instruction, */ \
641     /* and generate a CallAddress instruction instead. */                      \
642     FrameScope scope(masm(), StackFrame::MANUAL);                              \
643     __ PrepareCallCFunction(0, 1, kScratchReg);                                \
644     __ MovToFloatParameter(i.InputDoubleRegister(0));                          \
645     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()),  \
646                      0, 1);                                                    \
647     /* Move the result in the double result register. */                       \
648     __ MovFromFloatResult(i.OutputDoubleRegister());                           \
649   } while (0)
650 
651 #define ASSEMBLE_IEEE754_BINOP(name)                                           \
652   do {                                                                         \
653     /* TODO(bmeurer): We should really get rid of this special instruction, */ \
654     /* and generate a CallAddress instruction instead. */                      \
655     FrameScope scope(masm(), StackFrame::MANUAL);                              \
656     __ PrepareCallCFunction(0, 2, kScratchReg);                                \
657     __ MovToFloatParameters(i.InputDoubleRegister(0),                          \
658                             i.InputDoubleRegister(1));                         \
659     __ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()),  \
660                      0, 2);                                                    \
661     /* Move the result in the double result register. */                       \
662     __ MovFromFloatResult(i.OutputDoubleRegister());                           \
663   } while (0)
664 
665 #define ASSEMBLE_DOUBLE_MAX()                                          \
666   do {                                                                 \
667     DoubleRegister left_reg = i.InputDoubleRegister(0);                \
668     DoubleRegister right_reg = i.InputDoubleRegister(1);               \
669     DoubleRegister result_reg = i.OutputDoubleRegister();              \
670     Label check_nan_left, check_zero, return_left, return_right, done; \
671     __ cdbr(left_reg, right_reg);                                      \
672     __ bunordered(&check_nan_left, Label::kNear);                      \
673     __ beq(&check_zero);                                               \
674     __ bge(&return_left, Label::kNear);                                \
675     __ b(&return_right, Label::kNear);                                 \
676                                                                        \
677     __ bind(&check_zero);                                              \
678     __ lzdr(kDoubleRegZero);                                           \
679     __ cdbr(left_reg, kDoubleRegZero);                                 \
680     /* left == right != 0. */                                          \
681     __ bne(&return_left, Label::kNear);                                \
682     /* At this point, both left and right are either 0 or -0. */       \
683     /* N.B. The following works because +0 + -0 == +0 */               \
684     /* For max we want logical-and of sign bit: (L + R) */             \
685     __ ldr(result_reg, left_reg);                                      \
686     __ adbr(result_reg, right_reg);                                    \
687     __ b(&done, Label::kNear);                                         \
688                                                                        \
689     __ bind(&check_nan_left);                                          \
690     __ cdbr(left_reg, left_reg);                                       \
691     /* left == NaN. */                                                 \
692     __ bunordered(&return_left, Label::kNear);                         \
693                                                                        \
694     __ bind(&return_right);                                            \
695     if (!right_reg.is(result_reg)) {                                   \
696       __ ldr(result_reg, right_reg);                                   \
697     }                                                                  \
698     __ b(&done, Label::kNear);                                         \
699                                                                        \
700     __ bind(&return_left);                                             \
701     if (!left_reg.is(result_reg)) {                                    \
702       __ ldr(result_reg, left_reg);                                    \
703     }                                                                  \
704     __ bind(&done);                                                    \
705   } while (0)
706 
707 #define ASSEMBLE_DOUBLE_MIN()                                          \
708   do {                                                                 \
709     DoubleRegister left_reg = i.InputDoubleRegister(0);                \
710     DoubleRegister right_reg = i.InputDoubleRegister(1);               \
711     DoubleRegister result_reg = i.OutputDoubleRegister();              \
712     Label check_nan_left, check_zero, return_left, return_right, done; \
713     __ cdbr(left_reg, right_reg);                                      \
714     __ bunordered(&check_nan_left, Label::kNear);                      \
715     __ beq(&check_zero);                                               \
716     __ ble(&return_left, Label::kNear);                                \
717     __ b(&return_right, Label::kNear);                                 \
718                                                                        \
719     __ bind(&check_zero);                                              \
720     __ lzdr(kDoubleRegZero);                                           \
721     __ cdbr(left_reg, kDoubleRegZero);                                 \
722     /* left == right != 0. */                                          \
723     __ bne(&return_left, Label::kNear);                                \
724     /* At this point, both left and right are either 0 or -0. */       \
725     /* N.B. The following works because +0 + -0 == +0 */               \
726     /* For min we want logical-or of sign bit: -(-L + -R) */           \
727     __ lcdbr(left_reg, left_reg);                                      \
728     __ ldr(result_reg, left_reg);                                      \
729     if (left_reg.is(right_reg)) {                                      \
730       __ adbr(result_reg, right_reg);                                  \
731     } else {                                                           \
732       __ sdbr(result_reg, right_reg);                                  \
733     }                                                                  \
734     __ lcdbr(result_reg, result_reg);                                  \
735     __ b(&done, Label::kNear);                                         \
736                                                                        \
737     __ bind(&check_nan_left);                                          \
738     __ cdbr(left_reg, left_reg);                                       \
739     /* left == NaN. */                                                 \
740     __ bunordered(&return_left, Label::kNear);                         \
741                                                                        \
742     __ bind(&return_right);                                            \
743     if (!right_reg.is(result_reg)) {                                   \
744       __ ldr(result_reg, right_reg);                                   \
745     }                                                                  \
746     __ b(&done, Label::kNear);                                         \
747                                                                        \
748     __ bind(&return_left);                                             \
749     if (!left_reg.is(result_reg)) {                                    \
750       __ ldr(result_reg, left_reg);                                    \
751     }                                                                  \
752     __ bind(&done);                                                    \
753   } while (0)
754 
755 #define ASSEMBLE_FLOAT_MAX()                                           \
756   do {                                                                 \
757     DoubleRegister left_reg = i.InputDoubleRegister(0);                \
758     DoubleRegister right_reg = i.InputDoubleRegister(1);               \
759     DoubleRegister result_reg = i.OutputDoubleRegister();              \
760     Label check_nan_left, check_zero, return_left, return_right, done; \
761     __ cebr(left_reg, right_reg);                                      \
762     __ bunordered(&check_nan_left, Label::kNear);                      \
763     __ beq(&check_zero);                                               \
764     __ bge(&return_left, Label::kNear);                                \
765     __ b(&return_right, Label::kNear);                                 \
766                                                                        \
767     __ bind(&check_zero);                                              \
768     __ lzdr(kDoubleRegZero);                                           \
769     __ cebr(left_reg, kDoubleRegZero);                                 \
770     /* left == right != 0. */                                          \
771     __ bne(&return_left, Label::kNear);                                \
772     /* At this point, both left and right are either 0 or -0. */       \
773     /* N.B. The following works because +0 + -0 == +0 */               \
774     /* For max we want logical-and of sign bit: (L + R) */             \
775     __ ldr(result_reg, left_reg);                                      \
776     __ aebr(result_reg, right_reg);                                    \
777     __ b(&done, Label::kNear);                                         \
778                                                                        \
779     __ bind(&check_nan_left);                                          \
780     __ cebr(left_reg, left_reg);                                       \
781     /* left == NaN. */                                                 \
782     __ bunordered(&return_left, Label::kNear);                         \
783                                                                        \
784     __ bind(&return_right);                                            \
785     if (!right_reg.is(result_reg)) {                                   \
786       __ ldr(result_reg, right_reg);                                   \
787     }                                                                  \
788     __ b(&done, Label::kNear);                                         \
789                                                                        \
790     __ bind(&return_left);                                             \
791     if (!left_reg.is(result_reg)) {                                    \
792       __ ldr(result_reg, left_reg);                                    \
793     }                                                                  \
794     __ bind(&done);                                                    \
795   } while (0)
796 
797 #define ASSEMBLE_FLOAT_MIN()                                           \
798   do {                                                                 \
799     DoubleRegister left_reg = i.InputDoubleRegister(0);                \
800     DoubleRegister right_reg = i.InputDoubleRegister(1);               \
801     DoubleRegister result_reg = i.OutputDoubleRegister();              \
802     Label check_nan_left, check_zero, return_left, return_right, done; \
803     __ cebr(left_reg, right_reg);                                      \
804     __ bunordered(&check_nan_left, Label::kNear);                      \
805     __ beq(&check_zero);                                               \
806     __ ble(&return_left, Label::kNear);                                \
807     __ b(&return_right, Label::kNear);                                 \
808                                                                        \
809     __ bind(&check_zero);                                              \
810     __ lzdr(kDoubleRegZero);                                           \
811     __ cebr(left_reg, kDoubleRegZero);                                 \
812     /* left == right != 0. */                                          \
813     __ bne(&return_left, Label::kNear);                                \
814     /* At this point, both left and right are either 0 or -0. */       \
815     /* N.B. The following works because +0 + -0 == +0 */               \
816     /* For min we want logical-or of sign bit: -(-L + -R) */           \
817     __ lcebr(left_reg, left_reg);                                      \
818     __ ldr(result_reg, left_reg);                                      \
819     if (left_reg.is(right_reg)) {                                      \
820       __ aebr(result_reg, right_reg);                                  \
821     } else {                                                           \
822       __ sebr(result_reg, right_reg);                                  \
823     }                                                                  \
824     __ lcebr(result_reg, result_reg);                                  \
825     __ b(&done, Label::kNear);                                         \
826                                                                        \
827     __ bind(&check_nan_left);                                          \
828     __ cebr(left_reg, left_reg);                                       \
829     /* left == NaN. */                                                 \
830     __ bunordered(&return_left, Label::kNear);                         \
831                                                                        \
832     __ bind(&return_right);                                            \
833     if (!right_reg.is(result_reg)) {                                   \
834       __ ldr(result_reg, right_reg);                                   \
835     }                                                                  \
836     __ b(&done, Label::kNear);                                         \
837                                                                        \
838     __ bind(&return_left);                                             \
839     if (!left_reg.is(result_reg)) {                                    \
840       __ ldr(result_reg, left_reg);                                    \
841     }                                                                  \
842     __ bind(&done);                                                    \
843   } while (0)
844 //
845 // Only MRI mode for these instructions available
846 #define ASSEMBLE_LOAD_FLOAT(asm_instr)                \
847   do {                                                \
848     DoubleRegister result = i.OutputDoubleRegister(); \
849     AddressingMode mode = kMode_None;                 \
850     MemOperand operand = i.MemoryOperand(&mode);      \
851     __ asm_instr(result, operand);                    \
852   } while (0)
853 
854 #define ASSEMBLE_LOAD_INTEGER(asm_instr)         \
855   do {                                           \
856     Register result = i.OutputRegister();        \
857     AddressingMode mode = kMode_None;            \
858     MemOperand operand = i.MemoryOperand(&mode); \
859     __ asm_instr(result, operand);               \
860   } while (0)
861 
862 #define ASSEMBLE_LOADANDTEST64(asm_instr_rr, asm_instr_rm)              \
863   {                                                                     \
864     AddressingMode mode = AddressingModeField::decode(instr->opcode()); \
865     Register dst = HasRegisterOutput(instr) ? i.OutputRegister() : r0;  \
866     if (mode != kMode_None) {                                           \
867       size_t first_index = 0;                                           \
868       MemOperand operand = i.MemoryOperand(&mode, &first_index);        \
869       __ asm_instr_rm(dst, operand);                                    \
870     } else if (HasRegisterInput(instr, 0)) {                            \
871       __ asm_instr_rr(dst, i.InputRegister(0));                         \
872     } else {                                                            \
873       DCHECK(HasStackSlotInput(instr, 0));                              \
874       __ asm_instr_rm(dst, i.InputStackSlot(0));                        \
875     }                                                                   \
876   }
877 
878 #define ASSEMBLE_LOADANDTEST32(asm_instr_rr, asm_instr_rm)              \
879   {                                                                     \
880     AddressingMode mode = AddressingModeField::decode(instr->opcode()); \
881     Register dst = HasRegisterOutput(instr) ? i.OutputRegister() : r0;  \
882     if (mode != kMode_None) {                                           \
883       size_t first_index = 0;                                           \
884       MemOperand operand = i.MemoryOperand(&mode, &first_index);        \
885       __ asm_instr_rm(dst, operand);                                    \
886     } else if (HasRegisterInput(instr, 0)) {                            \
887       __ asm_instr_rr(dst, i.InputRegister(0));                         \
888     } else {                                                            \
889       DCHECK(HasStackSlotInput(instr, 0));                              \
890       __ asm_instr_rm(dst, i.InputStackSlot32(0));                      \
891     }                                                                   \
892   }
893 
894 #define ASSEMBLE_STORE_FLOAT32()                         \
895   do {                                                   \
896     size_t index = 0;                                    \
897     AddressingMode mode = kMode_None;                    \
898     MemOperand operand = i.MemoryOperand(&mode, &index); \
899     DoubleRegister value = i.InputDoubleRegister(index); \
900     __ StoreFloat32(value, operand);                     \
901   } while (0)
902 
903 #define ASSEMBLE_STORE_DOUBLE()                          \
904   do {                                                   \
905     size_t index = 0;                                    \
906     AddressingMode mode = kMode_None;                    \
907     MemOperand operand = i.MemoryOperand(&mode, &index); \
908     DoubleRegister value = i.InputDoubleRegister(index); \
909     __ StoreDouble(value, operand);                      \
910   } while (0)
911 
912 #define ASSEMBLE_STORE_INTEGER(asm_instr)                \
913   do {                                                   \
914     size_t index = 0;                                    \
915     AddressingMode mode = kMode_None;                    \
916     MemOperand operand = i.MemoryOperand(&mode, &index); \
917     Register value = i.InputRegister(index);             \
918     __ asm_instr(value, operand);                        \
919   } while (0)
920 
921 #define ASSEMBLE_CHECKED_LOAD_FLOAT(asm_instr, width)              \
922   do {                                                             \
923     DoubleRegister result = i.OutputDoubleRegister();              \
924     size_t index = 0;                                              \
925     AddressingMode mode = kMode_None;                              \
926     MemOperand operand = i.MemoryOperand(&mode, index);            \
927     Register offset = operand.rb();                                \
928     if (HasRegisterInput(instr, 2)) {                              \
929       __ CmpLogical32(offset, i.InputRegister(2));                 \
930     } else {                                                       \
931       __ CmpLogical32(offset, i.InputImmediate(2));                \
932     }                                                              \
933     auto ool = new (zone()) OutOfLineLoadNAN##width(this, result); \
934     __ bge(ool->entry());                                          \
935     __ CleanUInt32(offset);                                        \
936     __ asm_instr(result, operand);                                 \
937     __ bind(ool->exit());                                          \
938   } while (0)
939 
940 #define ASSEMBLE_CHECKED_LOAD_INTEGER(asm_instr)             \
941   do {                                                       \
942     Register result = i.OutputRegister();                    \
943     size_t index = 0;                                        \
944     AddressingMode mode = kMode_None;                        \
945     MemOperand operand = i.MemoryOperand(&mode, index);      \
946     Register offset = operand.rb();                          \
947     if (HasRegisterInput(instr, 2)) {                        \
948       __ CmpLogical32(offset, i.InputRegister(2));           \
949     } else {                                                 \
950       __ CmpLogical32(offset, i.InputImmediate(2));          \
951     }                                                        \
952     auto ool = new (zone()) OutOfLineLoadZero(this, result); \
953     __ bge(ool->entry());                                    \
954     __ CleanUInt32(offset);                                  \
955     __ asm_instr(result, operand);                           \
956     __ bind(ool->exit());                                    \
957   } while (0)
958 
959 #define ASSEMBLE_CHECKED_STORE_FLOAT32()                \
960   do {                                                  \
961     Label done;                                         \
962     size_t index = 0;                                   \
963     AddressingMode mode = kMode_None;                   \
964     MemOperand operand = i.MemoryOperand(&mode, index); \
965     Register offset = operand.rb();                     \
966     if (HasRegisterInput(instr, 2)) {                   \
967       __ CmpLogical32(offset, i.InputRegister(2));      \
968     } else {                                            \
969       __ CmpLogical32(offset, i.InputImmediate(2));     \
970     }                                                   \
971     __ bge(&done);                                      \
972     DoubleRegister value = i.InputDoubleRegister(3);    \
973     __ CleanUInt32(offset);                             \
974     __ StoreFloat32(value, operand);                    \
975     __ bind(&done);                                     \
976   } while (0)
977 
978 #define ASSEMBLE_CHECKED_STORE_DOUBLE()                 \
979   do {                                                  \
980     Label done;                                         \
981     size_t index = 0;                                   \
982     AddressingMode mode = kMode_None;                   \
983     MemOperand operand = i.MemoryOperand(&mode, index); \
984     DCHECK_EQ(kMode_MRR, mode);                         \
985     Register offset = operand.rb();                     \
986     if (HasRegisterInput(instr, 2)) {                   \
987       __ CmpLogical32(offset, i.InputRegister(2));      \
988     } else {                                            \
989       __ CmpLogical32(offset, i.InputImmediate(2));     \
990     }                                                   \
991     __ bge(&done);                                      \
992     DoubleRegister value = i.InputDoubleRegister(3);    \
993     __ CleanUInt32(offset);                             \
994     __ StoreDouble(value, operand);                     \
995     __ bind(&done);                                     \
996   } while (0)
997 
998 #define ASSEMBLE_CHECKED_STORE_INTEGER(asm_instr)       \
999   do {                                                  \
1000     Label done;                                         \
1001     size_t index = 0;                                   \
1002     AddressingMode mode = kMode_None;                   \
1003     MemOperand operand = i.MemoryOperand(&mode, index); \
1004     Register offset = operand.rb();                     \
1005     if (HasRegisterInput(instr, 2)) {                   \
1006       __ CmpLogical32(offset, i.InputRegister(2));      \
1007     } else {                                            \
1008       __ CmpLogical32(offset, i.InputImmediate(2));     \
1009     }                                                   \
1010     __ bge(&done);                                      \
1011     Register value = i.InputRegister(3);                \
1012     __ CleanUInt32(offset);                             \
1013     __ asm_instr(value, operand);                       \
1014     __ bind(&done);                                     \
1015   } while (0)
1016 
AssembleDeconstructFrame()1017 void CodeGenerator::AssembleDeconstructFrame() {
1018   __ LeaveFrame(StackFrame::MANUAL);
1019 }
1020 
AssemblePrepareTailCall()1021 void CodeGenerator::AssemblePrepareTailCall() {
1022   if (frame_access_state()->has_frame()) {
1023     __ RestoreFrameStateForTailCall();
1024   }
1025   frame_access_state()->SetFrameAccessToSP();
1026 }
1027 
AssemblePopArgumentsAdaptorFrame(Register args_reg,Register scratch1,Register scratch2,Register scratch3)1028 void CodeGenerator::AssemblePopArgumentsAdaptorFrame(Register args_reg,
1029                                                      Register scratch1,
1030                                                      Register scratch2,
1031                                                      Register scratch3) {
1032   DCHECK(!AreAliased(args_reg, scratch1, scratch2, scratch3));
1033   Label done;
1034 
1035   // Check if current frame is an arguments adaptor frame.
1036   __ LoadP(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset));
1037   __ CmpP(scratch1,
1038           Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
1039   __ bne(&done);
1040 
1041   // Load arguments count from current arguments adaptor frame (note, it
1042   // does not include receiver).
1043   Register caller_args_count_reg = scratch1;
1044   __ LoadP(caller_args_count_reg,
1045            MemOperand(fp, ArgumentsAdaptorFrameConstants::kLengthOffset));
1046   __ SmiUntag(caller_args_count_reg);
1047 
1048   ParameterCount callee_args_count(args_reg);
1049   __ PrepareForTailCall(callee_args_count, caller_args_count_reg, scratch2,
1050                         scratch3);
1051   __ bind(&done);
1052 }
1053 
1054 namespace {
1055 
FlushPendingPushRegisters(MacroAssembler * masm,FrameAccessState * frame_access_state,ZoneVector<Register> * pending_pushes)1056 void FlushPendingPushRegisters(MacroAssembler* masm,
1057                                FrameAccessState* frame_access_state,
1058                                ZoneVector<Register>* pending_pushes) {
1059   switch (pending_pushes->size()) {
1060     case 0:
1061       break;
1062     case 1:
1063       masm->Push((*pending_pushes)[0]);
1064       break;
1065     case 2:
1066       masm->Push((*pending_pushes)[0], (*pending_pushes)[1]);
1067       break;
1068     case 3:
1069       masm->Push((*pending_pushes)[0], (*pending_pushes)[1],
1070                  (*pending_pushes)[2]);
1071       break;
1072     default:
1073       UNREACHABLE();
1074       break;
1075   }
1076   frame_access_state->IncreaseSPDelta(pending_pushes->size());
1077   pending_pushes->resize(0);
1078 }
1079 
AddPendingPushRegister(MacroAssembler * masm,FrameAccessState * frame_access_state,ZoneVector<Register> * pending_pushes,Register reg)1080 void AddPendingPushRegister(MacroAssembler* masm,
1081                             FrameAccessState* frame_access_state,
1082                             ZoneVector<Register>* pending_pushes,
1083                             Register reg) {
1084   pending_pushes->push_back(reg);
1085   if (pending_pushes->size() == 3 || reg.is(ip)) {
1086     FlushPendingPushRegisters(masm, frame_access_state, pending_pushes);
1087   }
1088 }
AdjustStackPointerForTailCall(MacroAssembler * masm,FrameAccessState * state,int new_slot_above_sp,ZoneVector<Register> * pending_pushes=nullptr,bool allow_shrinkage=true)1089 void AdjustStackPointerForTailCall(
1090     MacroAssembler* masm, FrameAccessState* state, int new_slot_above_sp,
1091     ZoneVector<Register>* pending_pushes = nullptr,
1092     bool allow_shrinkage = true) {
1093   int current_sp_offset = state->GetSPToFPSlotCount() +
1094                           StandardFrameConstants::kFixedSlotCountAboveFp;
1095   int stack_slot_delta = new_slot_above_sp - current_sp_offset;
1096   if (stack_slot_delta > 0) {
1097     if (pending_pushes != nullptr) {
1098       FlushPendingPushRegisters(masm, state, pending_pushes);
1099     }
1100     masm->AddP(sp, sp, Operand(-stack_slot_delta * kPointerSize));
1101     state->IncreaseSPDelta(stack_slot_delta);
1102   } else if (allow_shrinkage && stack_slot_delta < 0) {
1103     if (pending_pushes != nullptr) {
1104       FlushPendingPushRegisters(masm, state, pending_pushes);
1105     }
1106     masm->AddP(sp, sp, Operand(-stack_slot_delta * kPointerSize));
1107     state->IncreaseSPDelta(stack_slot_delta);
1108   }
1109 }
1110 
1111 }  // namespace
1112 
AssembleTailCallBeforeGap(Instruction * instr,int first_unused_stack_slot)1113 void CodeGenerator::AssembleTailCallBeforeGap(Instruction* instr,
1114                                               int first_unused_stack_slot) {
1115   CodeGenerator::PushTypeFlags flags(kImmediatePush | kScalarPush);
1116   ZoneVector<MoveOperands*> pushes(zone());
1117   GetPushCompatibleMoves(instr, flags, &pushes);
1118 
1119   if (!pushes.empty() &&
1120       (LocationOperand::cast(pushes.back()->destination()).index() + 1 ==
1121        first_unused_stack_slot)) {
1122     S390OperandConverter g(this, instr);
1123     ZoneVector<Register> pending_pushes(zone());
1124     for (auto move : pushes) {
1125       LocationOperand destination_location(
1126           LocationOperand::cast(move->destination()));
1127       InstructionOperand source(move->source());
1128       AdjustStackPointerForTailCall(
1129           masm(), frame_access_state(),
1130           destination_location.index() - pending_pushes.size(),
1131           &pending_pushes);
1132       if (source.IsStackSlot()) {
1133         LocationOperand source_location(LocationOperand::cast(source));
1134         __ LoadP(ip, g.SlotToMemOperand(source_location.index()));
1135         AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes,
1136                                ip);
1137       } else if (source.IsRegister()) {
1138         LocationOperand source_location(LocationOperand::cast(source));
1139         AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes,
1140                                source_location.GetRegister());
1141       } else if (source.IsImmediate()) {
1142         AddPendingPushRegister(masm(), frame_access_state(), &pending_pushes,
1143                                ip);
1144       } else {
1145         // Pushes of non-scalar data types is not supported.
1146         UNIMPLEMENTED();
1147       }
1148       move->Eliminate();
1149     }
1150     FlushPendingPushRegisters(masm(), frame_access_state(), &pending_pushes);
1151   }
1152   AdjustStackPointerForTailCall(masm(), frame_access_state(),
1153                                 first_unused_stack_slot, nullptr, false);
1154 }
1155 
AssembleTailCallAfterGap(Instruction * instr,int first_unused_stack_slot)1156 void CodeGenerator::AssembleTailCallAfterGap(Instruction* instr,
1157                                              int first_unused_stack_slot) {
1158   AdjustStackPointerForTailCall(masm(), frame_access_state(),
1159                                 first_unused_stack_slot);
1160 }
1161 
1162 // Assembles an instruction after register allocation, producing machine code.
AssembleArchInstruction(Instruction * instr)1163 CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
1164     Instruction* instr) {
1165   S390OperandConverter i(this, instr);
1166   ArchOpcode opcode = ArchOpcodeField::decode(instr->opcode());
1167 
1168   switch (opcode) {
1169     case kArchComment: {
1170       Address comment_string = i.InputExternalReference(0).address();
1171       __ RecordComment(reinterpret_cast<const char*>(comment_string));
1172       break;
1173     }
1174     case kArchCallCodeObject: {
1175       EnsureSpaceForLazyDeopt();
1176       if (HasRegisterInput(instr, 0)) {
1177         __ AddP(ip, i.InputRegister(0),
1178                 Operand(Code::kHeaderSize - kHeapObjectTag));
1179         __ Call(ip);
1180       } else {
1181         __ Call(Handle<Code>::cast(i.InputHeapObject(0)),
1182                 RelocInfo::CODE_TARGET);
1183       }
1184       RecordCallPosition(instr);
1185       frame_access_state()->ClearSPDelta();
1186       break;
1187     }
1188     case kArchTailCallCodeObjectFromJSFunction:
1189     case kArchTailCallCodeObject: {
1190       if (opcode == kArchTailCallCodeObjectFromJSFunction) {
1191         AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
1192                                          i.TempRegister(0), i.TempRegister(1),
1193                                          i.TempRegister(2));
1194       }
1195       if (HasRegisterInput(instr, 0)) {
1196         __ AddP(ip, i.InputRegister(0),
1197                 Operand(Code::kHeaderSize - kHeapObjectTag));
1198         __ Jump(ip);
1199       } else {
1200         // We cannot use the constant pool to load the target since
1201         // we've already restored the caller's frame.
1202         ConstantPoolUnavailableScope constant_pool_unavailable(masm());
1203         __ Jump(Handle<Code>::cast(i.InputHeapObject(0)),
1204                 RelocInfo::CODE_TARGET);
1205       }
1206       frame_access_state()->ClearSPDelta();
1207       frame_access_state()->SetFrameAccessToDefault();
1208       break;
1209     }
1210     case kArchTailCallAddress: {
1211       CHECK(!instr->InputAt(0)->IsImmediate());
1212       __ Jump(i.InputRegister(0));
1213       frame_access_state()->ClearSPDelta();
1214       frame_access_state()->SetFrameAccessToDefault();
1215       break;
1216     }
1217     case kArchCallJSFunction: {
1218       EnsureSpaceForLazyDeopt();
1219       Register func = i.InputRegister(0);
1220       if (FLAG_debug_code) {
1221         // Check the function's context matches the context argument.
1222         __ LoadP(kScratchReg,
1223                  FieldMemOperand(func, JSFunction::kContextOffset));
1224         __ CmpP(cp, kScratchReg);
1225         __ Assert(eq, kWrongFunctionContext);
1226       }
1227       __ LoadP(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
1228       __ Call(ip);
1229       RecordCallPosition(instr);
1230       frame_access_state()->ClearSPDelta();
1231       break;
1232     }
1233     case kArchTailCallJSFunctionFromJSFunction: {
1234       Register func = i.InputRegister(0);
1235       if (FLAG_debug_code) {
1236         // Check the function's context matches the context argument.
1237         __ LoadP(kScratchReg,
1238                  FieldMemOperand(func, JSFunction::kContextOffset));
1239         __ CmpP(cp, kScratchReg);
1240         __ Assert(eq, kWrongFunctionContext);
1241       }
1242       AssemblePopArgumentsAdaptorFrame(kJavaScriptCallArgCountRegister,
1243                                        i.TempRegister(0), i.TempRegister(1),
1244                                        i.TempRegister(2));
1245       __ LoadP(ip, FieldMemOperand(func, JSFunction::kCodeEntryOffset));
1246       __ Jump(ip);
1247       frame_access_state()->ClearSPDelta();
1248       frame_access_state()->SetFrameAccessToDefault();
1249       break;
1250     }
1251     case kArchPrepareCallCFunction: {
1252       int const num_parameters = MiscField::decode(instr->opcode());
1253       __ PrepareCallCFunction(num_parameters, kScratchReg);
1254       // Frame alignment requires using FP-relative frame addressing.
1255       frame_access_state()->SetFrameAccessToFP();
1256       break;
1257     }
1258     case kArchPrepareTailCall:
1259       AssemblePrepareTailCall();
1260       break;
1261     case kArchCallCFunction: {
1262       int const num_parameters = MiscField::decode(instr->opcode());
1263       if (instr->InputAt(0)->IsImmediate()) {
1264         ExternalReference ref = i.InputExternalReference(0);
1265         __ CallCFunction(ref, num_parameters);
1266       } else {
1267         Register func = i.InputRegister(0);
1268         __ CallCFunction(func, num_parameters);
1269       }
1270       frame_access_state()->SetFrameAccessToDefault();
1271       frame_access_state()->ClearSPDelta();
1272       break;
1273     }
1274     case kArchJmp:
1275       AssembleArchJump(i.InputRpo(0));
1276       break;
1277     case kArchLookupSwitch:
1278       AssembleArchLookupSwitch(instr);
1279       break;
1280     case kArchTableSwitch:
1281       AssembleArchTableSwitch(instr);
1282       break;
1283     case kArchDebugBreak:
1284       __ stop("kArchDebugBreak");
1285       break;
1286     case kArchNop:
1287     case kArchThrowTerminator:
1288       // don't emit code for nops.
1289       break;
1290     case kArchDeoptimize: {
1291       int deopt_state_id =
1292           BuildTranslation(instr, -1, 0, OutputFrameStateCombine::Ignore());
1293       CodeGenResult result =
1294           AssembleDeoptimizerCall(deopt_state_id, current_source_position_);
1295       if (result != kSuccess) return result;
1296       break;
1297     }
1298     case kArchRet:
1299       AssembleReturn(instr->InputAt(0));
1300       break;
1301     case kArchStackPointer:
1302       __ LoadRR(i.OutputRegister(), sp);
1303       break;
1304     case kArchFramePointer:
1305       __ LoadRR(i.OutputRegister(), fp);
1306       break;
1307     case kArchParentFramePointer:
1308       if (frame_access_state()->has_frame()) {
1309         __ LoadP(i.OutputRegister(), MemOperand(fp, 0));
1310       } else {
1311         __ LoadRR(i.OutputRegister(), fp);
1312       }
1313       break;
1314     case kArchTruncateDoubleToI:
1315       // TODO(mbrandy): move slow call to stub out of line.
1316       __ TruncateDoubleToI(i.OutputRegister(), i.InputDoubleRegister(0));
1317       break;
1318     case kArchStoreWithWriteBarrier: {
1319       RecordWriteMode mode =
1320           static_cast<RecordWriteMode>(MiscField::decode(instr->opcode()));
1321       Register object = i.InputRegister(0);
1322       Register value = i.InputRegister(2);
1323       Register scratch0 = i.TempRegister(0);
1324       Register scratch1 = i.TempRegister(1);
1325       OutOfLineRecordWrite* ool;
1326 
1327       AddressingMode addressing_mode =
1328           AddressingModeField::decode(instr->opcode());
1329       if (addressing_mode == kMode_MRI) {
1330         int32_t offset = i.InputInt32(1);
1331         ool = new (zone()) OutOfLineRecordWrite(this, object, offset, value,
1332                                                 scratch0, scratch1, mode);
1333         __ StoreP(value, MemOperand(object, offset));
1334       } else {
1335         DCHECK_EQ(kMode_MRR, addressing_mode);
1336         Register offset(i.InputRegister(1));
1337         ool = new (zone()) OutOfLineRecordWrite(this, object, offset, value,
1338                                                 scratch0, scratch1, mode);
1339         __ StoreP(value, MemOperand(object, offset));
1340       }
1341       __ CheckPageFlag(object, scratch0,
1342                        MemoryChunk::kPointersFromHereAreInterestingMask, ne,
1343                        ool->entry());
1344       __ bind(ool->exit());
1345       break;
1346     }
1347     case kArchStackSlot: {
1348       FrameOffset offset =
1349           frame_access_state()->GetFrameOffset(i.InputInt32(0));
1350       __ AddP(i.OutputRegister(), offset.from_stack_pointer() ? sp : fp,
1351               Operand(offset.offset()));
1352       break;
1353     }
1354     case kS390_And32:
1355       if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
1356         ASSEMBLE_BIN_OP(nrk, And, nilf);
1357       } else {
1358         ASSEMBLE_BIN_OP(nr, And, nilf);
1359       }
1360       break;
1361     case kS390_And64:
1362       ASSEMBLE_BINOP(AndP);
1363       break;
1364     case kS390_Or32:
1365       if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
1366         ASSEMBLE_BIN_OP(ork, Or, oilf);
1367       } else {
1368         ASSEMBLE_BIN_OP(or_z, Or, oilf);
1369       }
1370       break;
1371     case kS390_Or64:
1372       ASSEMBLE_BINOP(OrP);
1373       break;
1374     case kS390_Xor32:
1375       if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
1376         ASSEMBLE_BIN_OP(xrk, Xor, xilf);
1377       } else {
1378         ASSEMBLE_BIN_OP(xr, Xor, xilf);
1379       }
1380       break;
1381     case kS390_Xor64:
1382       ASSEMBLE_BINOP(XorP);
1383       break;
1384     case kS390_ShiftLeft32:
1385       if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
1386         AssembleBinOp(i, masm(), instr, &MacroAssembler::ShiftLeft,
1387                       &MacroAssembler::ShiftLeft);
1388       } else {
1389         AssembleBinOp(i, masm(), instr, &MacroAssembler::sll,
1390                       &MacroAssembler::sll);
1391       }
1392       break;
1393 #if V8_TARGET_ARCH_S390X
1394     case kS390_ShiftLeft64:
1395       ASSEMBLE_BINOP(sllg);
1396       break;
1397 #endif
1398     case kS390_ShiftRight32:
1399       if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
1400         AssembleBinOp(i, masm(), instr, &MacroAssembler::srlk,
1401                       &MacroAssembler::srlk);
1402       } else {
1403         AssembleBinOp(i, masm(), instr, &MacroAssembler::srl,
1404                       &MacroAssembler::srl);
1405       }
1406       break;
1407 #if V8_TARGET_ARCH_S390X
1408     case kS390_ShiftRight64:
1409       ASSEMBLE_BINOP(srlg);
1410       break;
1411 #endif
1412     case kS390_ShiftRightArith32:
1413       if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
1414         AssembleBinOp(i, masm(), instr, &MacroAssembler::srak,
1415                       &MacroAssembler::srak);
1416       } else {
1417         AssembleBinOp(i, masm(), instr, &MacroAssembler::sra,
1418                       &MacroAssembler::sra);
1419       }
1420       break;
1421 #if V8_TARGET_ARCH_S390X
1422     case kS390_ShiftRightArith64:
1423       ASSEMBLE_BINOP(srag);
1424       break;
1425 #endif
1426 #if !V8_TARGET_ARCH_S390X
1427     case kS390_AddPair:
1428       // i.InputRegister(0) ... left low word.
1429       // i.InputRegister(1) ... left high word.
1430       // i.InputRegister(2) ... right low word.
1431       // i.InputRegister(3) ... right high word.
1432       __ AddLogical32(i.OutputRegister(0), i.InputRegister(0),
1433                       i.InputRegister(2));
1434       __ AddLogicalWithCarry32(i.OutputRegister(1), i.InputRegister(1),
1435                                i.InputRegister(3));
1436       break;
1437     case kS390_SubPair:
1438       // i.InputRegister(0) ... left low word.
1439       // i.InputRegister(1) ... left high word.
1440       // i.InputRegister(2) ... right low word.
1441       // i.InputRegister(3) ... right high word.
1442       __ SubLogical32(i.OutputRegister(0), i.InputRegister(0),
1443                       i.InputRegister(2));
1444       __ SubLogicalWithBorrow32(i.OutputRegister(1), i.InputRegister(1),
1445                                 i.InputRegister(3));
1446       break;
1447     case kS390_MulPair:
1448       // i.InputRegister(0) ... left low word.
1449       // i.InputRegister(1) ... left high word.
1450       // i.InputRegister(2) ... right low word.
1451       // i.InputRegister(3) ... right high word.
1452       __ sllg(r0, i.InputRegister(1), Operand(32));
1453       __ sllg(r1, i.InputRegister(3), Operand(32));
1454       __ lr(r0, i.InputRegister(0));
1455       __ lr(r1, i.InputRegister(2));
1456       __ msgr(r1, r0);
1457       __ lr(i.OutputRegister(0), r1);
1458       __ srag(i.OutputRegister(1), r1, Operand(32));
1459       break;
1460     case kS390_ShiftLeftPair: {
1461       Register second_output =
1462           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1463       if (instr->InputAt(2)->IsImmediate()) {
1464         __ ShiftLeftPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1465                          i.InputRegister(1), i.InputInt32(2));
1466       } else {
1467         __ ShiftLeftPair(i.OutputRegister(0), second_output, i.InputRegister(0),
1468                          i.InputRegister(1), kScratchReg, i.InputRegister(2));
1469       }
1470       break;
1471     }
1472     case kS390_ShiftRightPair: {
1473       Register second_output =
1474           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1475       if (instr->InputAt(2)->IsImmediate()) {
1476         __ ShiftRightPair(i.OutputRegister(0), second_output,
1477                           i.InputRegister(0), i.InputRegister(1),
1478                           i.InputInt32(2));
1479       } else {
1480         __ ShiftRightPair(i.OutputRegister(0), second_output,
1481                           i.InputRegister(0), i.InputRegister(1), kScratchReg,
1482                           i.InputRegister(2));
1483       }
1484       break;
1485     }
1486     case kS390_ShiftRightArithPair: {
1487       Register second_output =
1488           instr->OutputCount() >= 2 ? i.OutputRegister(1) : i.TempRegister(0);
1489       if (instr->InputAt(2)->IsImmediate()) {
1490         __ ShiftRightArithPair(i.OutputRegister(0), second_output,
1491                                i.InputRegister(0), i.InputRegister(1),
1492                                i.InputInt32(2));
1493       } else {
1494         __ ShiftRightArithPair(i.OutputRegister(0), second_output,
1495                                i.InputRegister(0), i.InputRegister(1),
1496                                kScratchReg, i.InputRegister(2));
1497       }
1498       break;
1499     }
1500 #endif
1501     case kS390_RotRight32: {
1502       if (HasRegisterInput(instr, 1)) {
1503         __ LoadComplementRR(kScratchReg, i.InputRegister(1));
1504         __ rll(i.OutputRegister(), i.InputRegister(0), kScratchReg);
1505       } else {
1506         __ rll(i.OutputRegister(), i.InputRegister(0),
1507                Operand(32 - i.InputInt32(1)));
1508       }
1509       CHECK_AND_ZERO_EXT_OUTPUT(2);
1510       break;
1511     }
1512 #if V8_TARGET_ARCH_S390X
1513     case kS390_RotRight64:
1514       if (HasRegisterInput(instr, 1)) {
1515         __ LoadComplementRR(kScratchReg, i.InputRegister(1));
1516         __ rllg(i.OutputRegister(), i.InputRegister(0), kScratchReg);
1517       } else {
1518         __ rllg(i.OutputRegister(), i.InputRegister(0),
1519                 Operand(64 - i.InputInt32(1)));
1520       }
1521       break;
1522     case kS390_RotLeftAndClear64:
1523       if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
1524         int shiftAmount = i.InputInt32(1);
1525         int endBit = 63 - shiftAmount;
1526         int startBit = 63 - i.InputInt32(2);
1527         __ risbg(i.OutputRegister(), i.InputRegister(0), Operand(startBit),
1528                  Operand(endBit), Operand(shiftAmount), true);
1529       } else {
1530         int shiftAmount = i.InputInt32(1);
1531         int clearBit = 63 - i.InputInt32(2);
1532         __ rllg(i.OutputRegister(), i.InputRegister(0), Operand(shiftAmount));
1533         __ sllg(i.OutputRegister(), i.OutputRegister(), Operand(clearBit));
1534         __ srlg(i.OutputRegister(), i.OutputRegister(),
1535                 Operand(clearBit + shiftAmount));
1536         __ sllg(i.OutputRegister(), i.OutputRegister(), Operand(shiftAmount));
1537       }
1538       break;
1539     case kS390_RotLeftAndClearLeft64:
1540       if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
1541         int shiftAmount = i.InputInt32(1);
1542         int endBit = 63;
1543         int startBit = 63 - i.InputInt32(2);
1544         __ risbg(i.OutputRegister(), i.InputRegister(0), Operand(startBit),
1545                  Operand(endBit), Operand(shiftAmount), true);
1546       } else {
1547         int shiftAmount = i.InputInt32(1);
1548         int clearBit = 63 - i.InputInt32(2);
1549         __ rllg(i.OutputRegister(), i.InputRegister(0), Operand(shiftAmount));
1550         __ sllg(i.OutputRegister(), i.OutputRegister(), Operand(clearBit));
1551         __ srlg(i.OutputRegister(), i.OutputRegister(), Operand(clearBit));
1552       }
1553       break;
1554     case kS390_RotLeftAndClearRight64:
1555       if (CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) {
1556         int shiftAmount = i.InputInt32(1);
1557         int endBit = 63 - i.InputInt32(2);
1558         int startBit = 0;
1559         __ risbg(i.OutputRegister(), i.InputRegister(0), Operand(startBit),
1560                  Operand(endBit), Operand(shiftAmount), true);
1561       } else {
1562         int shiftAmount = i.InputInt32(1);
1563         int clearBit = i.InputInt32(2);
1564         __ rllg(i.OutputRegister(), i.InputRegister(0), Operand(shiftAmount));
1565         __ srlg(i.OutputRegister(), i.OutputRegister(), Operand(clearBit));
1566         __ sllg(i.OutputRegister(), i.OutputRegister(), Operand(clearBit));
1567       }
1568       break;
1569 #endif
1570     case kS390_Add32: {
1571       if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
1572         ASSEMBLE_BIN_OP(ark, Add32, Add32_RRI);
1573       } else {
1574         ASSEMBLE_BIN_OP(ar, Add32, Add32_RI);
1575       }
1576       break;
1577     }
1578     case kS390_Add64:
1579       ASSEMBLE_BINOP(AddP);
1580       break;
1581     case kS390_AddFloat:
1582       // Ensure we don't clobber right/InputReg(1)
1583       if (i.OutputDoubleRegister().is(i.InputDoubleRegister(1))) {
1584         ASSEMBLE_FLOAT_UNOP(aebr);
1585       } else {
1586         if (!i.OutputDoubleRegister().is(i.InputDoubleRegister(0)))
1587           __ ldr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1588         __ aebr(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1589       }
1590       break;
1591     case kS390_AddDouble:
1592       // Ensure we don't clobber right/InputReg(1)
1593       if (i.OutputDoubleRegister().is(i.InputDoubleRegister(1))) {
1594         ASSEMBLE_FLOAT_UNOP(adbr);
1595       } else {
1596         if (!i.OutputDoubleRegister().is(i.InputDoubleRegister(0)))
1597           __ ldr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1598         __ adbr(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1599       }
1600       break;
1601     case kS390_Sub32:
1602       if (CpuFeatures::IsSupported(DISTINCT_OPS)) {
1603         ASSEMBLE_BIN_OP(srk, Sub32, Sub32_RRI);
1604       } else {
1605         ASSEMBLE_BIN_OP(sr, Sub32, Sub32_RI);
1606       }
1607       break;
1608     case kS390_Sub64:
1609       ASSEMBLE_BINOP(SubP);
1610       break;
1611     case kS390_SubFloat:
1612       // OutputDoubleReg() = i.InputDoubleRegister(0) - i.InputDoubleRegister(1)
1613       if (i.OutputDoubleRegister().is(i.InputDoubleRegister(1))) {
1614         __ ldr(kScratchDoubleReg, i.InputDoubleRegister(1));
1615         __ ldr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1616         __ sebr(i.OutputDoubleRegister(), kScratchDoubleReg);
1617       } else {
1618         if (!i.OutputDoubleRegister().is(i.InputDoubleRegister(0))) {
1619           __ ldr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1620         }
1621         __ sebr(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1622       }
1623       break;
1624     case kS390_SubDouble:
1625       // OutputDoubleReg() = i.InputDoubleRegister(0) - i.InputDoubleRegister(1)
1626       if (i.OutputDoubleRegister().is(i.InputDoubleRegister(1))) {
1627         __ ldr(kScratchDoubleReg, i.InputDoubleRegister(1));
1628         __ ldr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1629         __ sdbr(i.OutputDoubleRegister(), kScratchDoubleReg);
1630       } else {
1631         if (!i.OutputDoubleRegister().is(i.InputDoubleRegister(0))) {
1632           __ ldr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1633         }
1634         __ sdbr(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1635       }
1636       break;
1637     case kS390_Mul32:
1638       ASSEMBLE_BIN_OP(Mul32, Mul32, Mul32);
1639       break;
1640     case kS390_Mul32WithOverflow:
1641       ASSEMBLE_BIN_OP(Mul32WithOverflowIfCCUnequal,
1642                       Mul32WithOverflowIfCCUnequal,
1643                       Mul32WithOverflowIfCCUnequal);
1644       break;
1645     case kS390_Mul64:
1646       CHECK(i.OutputRegister().is(i.InputRegister(0)));
1647       if (HasRegisterInput(instr, 1)) {
1648         __ Mul64(i.InputRegister(0), i.InputRegister(1));
1649       } else if (HasImmediateInput(instr, 1)) {
1650         __ Mul64(i.InputRegister(0), i.InputImmediate(1));
1651       } else if (HasStackSlotInput(instr, 1)) {
1652         __ Mul64(i.InputRegister(0), i.InputStackSlot(1));
1653       } else {
1654         UNIMPLEMENTED();
1655       }
1656       break;
1657     case kS390_MulHigh32:
1658       ASSEMBLE_BIN_OP(MulHigh32, MulHigh32, MulHigh32);
1659       break;
1660     case kS390_MulHighU32:
1661       ASSEMBLE_BIN_OP(MulHighU32, MulHighU32, MulHighU32);
1662       break;
1663     case kS390_MulFloat:
1664       // Ensure we don't clobber right
1665       if (i.OutputDoubleRegister().is(i.InputDoubleRegister(1))) {
1666         ASSEMBLE_FLOAT_UNOP(meebr);
1667       } else {
1668         if (!i.OutputDoubleRegister().is(i.InputDoubleRegister(0)))
1669           __ ldr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1670         __ meebr(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1671       }
1672       break;
1673     case kS390_MulDouble:
1674       // Ensure we don't clobber right
1675       if (i.OutputDoubleRegister().is(i.InputDoubleRegister(1))) {
1676         ASSEMBLE_FLOAT_UNOP(mdbr);
1677       } else {
1678         if (!i.OutputDoubleRegister().is(i.InputDoubleRegister(0)))
1679           __ ldr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1680         __ mdbr(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1681       }
1682       break;
1683 #if V8_TARGET_ARCH_S390X
1684     case kS390_Div64:
1685       __ LoadRR(r1, i.InputRegister(0));
1686       __ dsgr(r0, i.InputRegister(1));  // R1: Dividend
1687       __ ltgr(i.OutputRegister(), r1);  // Copy R1: Quotient to output
1688       break;
1689 #endif
1690     case kS390_Div32: {
1691       ASSEMBLE_BIN_OP(Div32, Div32, Div32);
1692       break;
1693     }
1694 #if V8_TARGET_ARCH_S390X
1695     case kS390_DivU64:
1696       __ LoadRR(r1, i.InputRegister(0));
1697       __ LoadImmP(r0, Operand::Zero());
1698       __ dlgr(r0, i.InputRegister(1));  // R0:R1: Dividend
1699       __ ltgr(i.OutputRegister(), r1);  // Copy R1: Quotient to output
1700       break;
1701 #endif
1702     case kS390_DivU32: {
1703       ASSEMBLE_BIN_OP(DivU32, DivU32, DivU32);
1704       break;
1705     }
1706     case kS390_DivFloat:
1707       // InputDoubleRegister(1)=InputDoubleRegister(0)/InputDoubleRegister(1)
1708       if (i.OutputDoubleRegister().is(i.InputDoubleRegister(1))) {
1709         __ ldr(kScratchDoubleReg, i.InputDoubleRegister(1));
1710         __ ldr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1711         __ debr(i.OutputDoubleRegister(), kScratchDoubleReg);
1712       } else {
1713         if (!i.OutputDoubleRegister().is(i.InputDoubleRegister(0)))
1714           __ ldr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1715         __ debr(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1716       }
1717       break;
1718     case kS390_DivDouble:
1719       // InputDoubleRegister(1)=InputDoubleRegister(0)/InputDoubleRegister(1)
1720       if (i.OutputDoubleRegister().is(i.InputDoubleRegister(1))) {
1721         __ ldr(kScratchDoubleReg, i.InputDoubleRegister(1));
1722         __ ldr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1723         __ ddbr(i.OutputDoubleRegister(), kScratchDoubleReg);
1724       } else {
1725         if (!i.OutputDoubleRegister().is(i.InputDoubleRegister(0)))
1726           __ ldr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1727         __ ddbr(i.OutputDoubleRegister(), i.InputDoubleRegister(1));
1728       }
1729       break;
1730     case kS390_Mod32:
1731       ASSEMBLE_BIN_OP(Mod32, Mod32, Mod32);
1732       break;
1733     case kS390_ModU32:
1734       ASSEMBLE_BIN_OP(ModU32, ModU32, ModU32);
1735       break;
1736 #if V8_TARGET_ARCH_S390X
1737     case kS390_Mod64:
1738       __ LoadRR(r1, i.InputRegister(0));
1739       __ dsgr(r0, i.InputRegister(1));  // R1: Dividend
1740       __ ltgr(i.OutputRegister(), r0);  // Copy R0: Remainder to output
1741       break;
1742     case kS390_ModU64:
1743       __ LoadRR(r1, i.InputRegister(0));
1744       __ LoadImmP(r0, Operand::Zero());
1745       __ dlgr(r0, i.InputRegister(1));  // R0:R1: Dividend
1746       __ ltgr(i.OutputRegister(), r0);  // Copy R0: Remainder to output
1747       break;
1748 #endif
1749     case kS390_AbsFloat:
1750       __ lpebr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1751       break;
1752     case kS390_SqrtFloat:
1753       ASSEMBLE_FLOAT_UNOP(sqebr);
1754       break;
1755     case kS390_FloorFloat:
1756       __ fiebra(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1757                 v8::internal::Assembler::FIDBRA_ROUND_TOWARD_NEG_INF);
1758       break;
1759     case kS390_CeilFloat:
1760       __ fiebra(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1761                 v8::internal::Assembler::FIDBRA_ROUND_TOWARD_POS_INF);
1762       break;
1763     case kS390_TruncateFloat:
1764       __ fiebra(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1765                 v8::internal::Assembler::FIDBRA_ROUND_TOWARD_0);
1766       break;
1767     //  Double operations
1768     case kS390_ModDouble:
1769       ASSEMBLE_FLOAT_MODULO();
1770       break;
1771     case kIeee754Float64Acos:
1772       ASSEMBLE_IEEE754_UNOP(acos);
1773       break;
1774     case kIeee754Float64Acosh:
1775       ASSEMBLE_IEEE754_UNOP(acosh);
1776       break;
1777     case kIeee754Float64Asin:
1778       ASSEMBLE_IEEE754_UNOP(asin);
1779       break;
1780     case kIeee754Float64Asinh:
1781       ASSEMBLE_IEEE754_UNOP(asinh);
1782       break;
1783     case kIeee754Float64Atanh:
1784       ASSEMBLE_IEEE754_UNOP(atanh);
1785       break;
1786     case kIeee754Float64Atan:
1787       ASSEMBLE_IEEE754_UNOP(atan);
1788       break;
1789     case kIeee754Float64Atan2:
1790       ASSEMBLE_IEEE754_BINOP(atan2);
1791       break;
1792     case kIeee754Float64Tan:
1793       ASSEMBLE_IEEE754_UNOP(tan);
1794       break;
1795     case kIeee754Float64Tanh:
1796       ASSEMBLE_IEEE754_UNOP(tanh);
1797       break;
1798     case kIeee754Float64Cbrt:
1799       ASSEMBLE_IEEE754_UNOP(cbrt);
1800       break;
1801     case kIeee754Float64Sin:
1802       ASSEMBLE_IEEE754_UNOP(sin);
1803       break;
1804     case kIeee754Float64Sinh:
1805       ASSEMBLE_IEEE754_UNOP(sinh);
1806       break;
1807     case kIeee754Float64Cos:
1808       ASSEMBLE_IEEE754_UNOP(cos);
1809       break;
1810     case kIeee754Float64Cosh:
1811       ASSEMBLE_IEEE754_UNOP(cosh);
1812       break;
1813     case kIeee754Float64Exp:
1814       ASSEMBLE_IEEE754_UNOP(exp);
1815       break;
1816     case kIeee754Float64Expm1:
1817       ASSEMBLE_IEEE754_UNOP(expm1);
1818       break;
1819     case kIeee754Float64Log:
1820       ASSEMBLE_IEEE754_UNOP(log);
1821       break;
1822     case kIeee754Float64Log1p:
1823       ASSEMBLE_IEEE754_UNOP(log1p);
1824       break;
1825     case kIeee754Float64Log2:
1826       ASSEMBLE_IEEE754_UNOP(log2);
1827       break;
1828     case kIeee754Float64Log10:
1829       ASSEMBLE_IEEE754_UNOP(log10);
1830       break;
1831     case kIeee754Float64Pow: {
1832       MathPowStub stub(isolate(), MathPowStub::DOUBLE);
1833       __ CallStub(&stub);
1834       __ Move(d1, d3);
1835       break;
1836     }
1837     case kS390_Neg32:
1838       __ lcr(i.OutputRegister(), i.InputRegister(0));
1839       CHECK_AND_ZERO_EXT_OUTPUT(1);
1840       break;
1841     case kS390_Neg64:
1842       __ lcgr(i.OutputRegister(), i.InputRegister(0));
1843       break;
1844     case kS390_MaxFloat:
1845       ASSEMBLE_FLOAT_MAX();
1846       break;
1847     case kS390_MaxDouble:
1848       ASSEMBLE_DOUBLE_MAX();
1849       break;
1850     case kS390_MinFloat:
1851       ASSEMBLE_FLOAT_MIN();
1852       break;
1853     case kS390_MinDouble:
1854       ASSEMBLE_DOUBLE_MIN();
1855       break;
1856     case kS390_AbsDouble:
1857       __ lpdbr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
1858       break;
1859     case kS390_SqrtDouble:
1860       ASSEMBLE_FLOAT_UNOP(sqdbr);
1861       break;
1862     case kS390_FloorDouble:
1863       __ fidbra(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1864                 v8::internal::Assembler::FIDBRA_ROUND_TOWARD_NEG_INF);
1865       break;
1866     case kS390_CeilDouble:
1867       __ fidbra(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1868                 v8::internal::Assembler::FIDBRA_ROUND_TOWARD_POS_INF);
1869       break;
1870     case kS390_TruncateDouble:
1871       __ fidbra(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1872                 v8::internal::Assembler::FIDBRA_ROUND_TOWARD_0);
1873       break;
1874     case kS390_RoundDouble:
1875       __ fidbra(i.OutputDoubleRegister(), i.InputDoubleRegister(0),
1876                 v8::internal::Assembler::FIDBRA_ROUND_TO_NEAREST_AWAY_FROM_0);
1877       break;
1878     case kS390_NegFloat:
1879       ASSEMBLE_FLOAT_UNOP(lcebr);
1880       break;
1881     case kS390_NegDouble:
1882       ASSEMBLE_FLOAT_UNOP(lcdbr);
1883       break;
1884     case kS390_Cntlz32: {
1885       __ llgfr(i.OutputRegister(), i.InputRegister(0));
1886       __ flogr(r0, i.OutputRegister());
1887       __ Add32(i.OutputRegister(), r0, Operand(-32));
1888       // No need to zero-ext b/c llgfr is done already
1889       break;
1890     }
1891 #if V8_TARGET_ARCH_S390X
1892     case kS390_Cntlz64: {
1893       __ flogr(r0, i.InputRegister(0));
1894       __ LoadRR(i.OutputRegister(), r0);
1895       break;
1896     }
1897 #endif
1898     case kS390_Popcnt32:
1899       __ Popcnt32(i.OutputRegister(), i.InputRegister(0));
1900       break;
1901 #if V8_TARGET_ARCH_S390X
1902     case kS390_Popcnt64:
1903       __ Popcnt64(i.OutputRegister(), i.InputRegister(0));
1904       break;
1905 #endif
1906     case kS390_Cmp32:
1907       ASSEMBLE_COMPARE32(Cmp32, CmpLogical32);
1908       break;
1909 #if V8_TARGET_ARCH_S390X
1910     case kS390_Cmp64:
1911       ASSEMBLE_COMPARE(CmpP, CmpLogicalP);
1912       break;
1913 #endif
1914     case kS390_CmpFloat:
1915       ASSEMBLE_FLOAT_COMPARE(cebr, ceb, ley);
1916       // __ cebr(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
1917       break;
1918     case kS390_CmpDouble:
1919       ASSEMBLE_FLOAT_COMPARE(cdbr, cdb, ldy);
1920       // __ cdbr(i.InputDoubleRegister(0), i.InputDoubleRegister(1));
1921       break;
1922     case kS390_Tst32:
1923       if (HasRegisterInput(instr, 1)) {
1924         __ And(r0, i.InputRegister(0), i.InputRegister(1));
1925       } else {
1926         Operand opnd = i.InputImmediate(1);
1927         if (is_uint16(opnd.immediate())) {
1928           __ tmll(i.InputRegister(0), opnd);
1929         } else {
1930           __ lr(r0, i.InputRegister(0));
1931           __ nilf(r0, opnd);
1932         }
1933       }
1934       break;
1935     case kS390_Tst64:
1936       if (HasRegisterInput(instr, 1)) {
1937         __ AndP(r0, i.InputRegister(0), i.InputRegister(1));
1938       } else {
1939         Operand opnd = i.InputImmediate(1);
1940         if (is_uint16(opnd.immediate())) {
1941           __ tmll(i.InputRegister(0), opnd);
1942         } else {
1943           __ AndP(r0, i.InputRegister(0), opnd);
1944         }
1945       }
1946       break;
1947     case kS390_Float64SilenceNaN: {
1948       DoubleRegister value = i.InputDoubleRegister(0);
1949       DoubleRegister result = i.OutputDoubleRegister();
1950       __ CanonicalizeNaN(result, value);
1951       break;
1952     }
1953     case kS390_Push:
1954       if (instr->InputAt(0)->IsFPRegister()) {
1955         __ lay(sp, MemOperand(sp, -kDoubleSize));
1956         __ StoreDouble(i.InputDoubleRegister(0), MemOperand(sp));
1957         frame_access_state()->IncreaseSPDelta(kDoubleSize / kPointerSize);
1958       } else {
1959         __ Push(i.InputRegister(0));
1960         frame_access_state()->IncreaseSPDelta(1);
1961       }
1962       break;
1963     case kS390_PushFrame: {
1964       int num_slots = i.InputInt32(1);
1965       __ lay(sp, MemOperand(sp, -num_slots * kPointerSize));
1966       if (instr->InputAt(0)->IsFPRegister()) {
1967         LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
1968         if (op->representation() == MachineRepresentation::kFloat64) {
1969           __ StoreDouble(i.InputDoubleRegister(0), MemOperand(sp));
1970         } else {
1971           DCHECK(op->representation() == MachineRepresentation::kFloat32);
1972           __ StoreFloat32(i.InputDoubleRegister(0), MemOperand(sp));
1973         }
1974       } else {
1975         __ StoreP(i.InputRegister(0),
1976                   MemOperand(sp));
1977       }
1978       break;
1979     }
1980     case kS390_StoreToStackSlot: {
1981       int slot = i.InputInt32(1);
1982       if (instr->InputAt(0)->IsFPRegister()) {
1983         LocationOperand* op = LocationOperand::cast(instr->InputAt(0));
1984         if (op->representation() == MachineRepresentation::kFloat64) {
1985           __ StoreDouble(i.InputDoubleRegister(0),
1986                          MemOperand(sp, slot * kPointerSize));
1987         } else {
1988           DCHECK(op->representation() == MachineRepresentation::kFloat32);
1989           __ StoreFloat32(i.InputDoubleRegister(0),
1990                           MemOperand(sp, slot * kPointerSize));
1991         }
1992       } else {
1993         __ StoreP(i.InputRegister(0), MemOperand(sp, slot * kPointerSize));
1994       }
1995       break;
1996     }
1997     case kS390_ExtendSignWord8:
1998       __ lbr(i.OutputRegister(), i.InputRegister(0));
1999       CHECK_AND_ZERO_EXT_OUTPUT(1);
2000       break;
2001     case kS390_ExtendSignWord16:
2002       __ lhr(i.OutputRegister(), i.InputRegister(0));
2003       CHECK_AND_ZERO_EXT_OUTPUT(1);
2004       break;
2005 #if V8_TARGET_ARCH_S390X
2006     case kS390_ExtendSignWord32:
2007       __ lgfr(i.OutputRegister(), i.InputRegister(0));
2008       break;
2009     case kS390_Uint32ToUint64:
2010       // Zero extend
2011       __ llgfr(i.OutputRegister(), i.InputRegister(0));
2012       break;
2013     case kS390_Int64ToInt32:
2014       // sign extend
2015       __ lgfr(i.OutputRegister(), i.InputRegister(0));
2016       break;
2017     case kS390_Int64ToFloat32:
2018       __ ConvertInt64ToFloat(i.InputRegister(0), i.OutputDoubleRegister());
2019       break;
2020     case kS390_Int64ToDouble:
2021       __ ConvertInt64ToDouble(i.InputRegister(0), i.OutputDoubleRegister());
2022       break;
2023     case kS390_Uint64ToFloat32:
2024       __ ConvertUnsignedInt64ToFloat(i.InputRegister(0),
2025                                      i.OutputDoubleRegister());
2026       break;
2027     case kS390_Uint64ToDouble:
2028       __ ConvertUnsignedInt64ToDouble(i.InputRegister(0),
2029                                       i.OutputDoubleRegister());
2030       break;
2031 #endif
2032     case kS390_Int32ToFloat32:
2033       __ ConvertIntToFloat(i.InputRegister(0), i.OutputDoubleRegister());
2034       break;
2035     case kS390_Int32ToDouble:
2036       __ ConvertIntToDouble(i.InputRegister(0), i.OutputDoubleRegister());
2037       break;
2038     case kS390_Uint32ToFloat32:
2039       __ ConvertUnsignedIntToFloat(i.InputRegister(0),
2040                                    i.OutputDoubleRegister());
2041       break;
2042     case kS390_Uint32ToDouble:
2043       __ ConvertUnsignedIntToDouble(i.InputRegister(0),
2044                                     i.OutputDoubleRegister());
2045       break;
2046     case kS390_DoubleToInt32:
2047     case kS390_DoubleToUint32:
2048     case kS390_DoubleToInt64: {
2049 #if V8_TARGET_ARCH_S390X
2050       bool check_conversion =
2051           (opcode == kS390_DoubleToInt64 && i.OutputCount() > 1);
2052 #endif
2053       __ ConvertDoubleToInt64(i.InputDoubleRegister(0),
2054 #if !V8_TARGET_ARCH_S390X
2055                               kScratchReg,
2056 #endif
2057                               i.OutputRegister(0), kScratchDoubleReg);
2058 #if V8_TARGET_ARCH_S390X
2059       if (check_conversion) {
2060         Label conversion_done;
2061         __ LoadImmP(i.OutputRegister(1), Operand::Zero());
2062         __ b(Condition(1), &conversion_done);  // special case
2063         __ LoadImmP(i.OutputRegister(1), Operand(1));
2064         __ bind(&conversion_done);
2065       }
2066 #endif
2067       break;
2068     }
2069     case kS390_Float32ToInt32: {
2070       bool check_conversion = (i.OutputCount() > 1);
2071       __ ConvertFloat32ToInt32(i.InputDoubleRegister(0), i.OutputRegister(0),
2072                                kScratchDoubleReg, kRoundToZero);
2073       if (check_conversion) {
2074         Label conversion_done;
2075         __ LoadImmP(i.OutputRegister(1), Operand::Zero());
2076         __ b(Condition(1), &conversion_done);  // special case
2077         __ LoadImmP(i.OutputRegister(1), Operand(1));
2078         __ bind(&conversion_done);
2079       }
2080       break;
2081     }
2082     case kS390_Float32ToUint32: {
2083       bool check_conversion = (i.OutputCount() > 1);
2084       __ ConvertFloat32ToUnsignedInt32(i.InputDoubleRegister(0),
2085                                        i.OutputRegister(0), kScratchDoubleReg);
2086       if (check_conversion) {
2087         Label conversion_done;
2088         __ LoadImmP(i.OutputRegister(1), Operand::Zero());
2089         __ b(Condition(1), &conversion_done);  // special case
2090         __ LoadImmP(i.OutputRegister(1), Operand(1));
2091         __ bind(&conversion_done);
2092       }
2093       break;
2094     }
2095 #if V8_TARGET_ARCH_S390X
2096     case kS390_Float32ToUint64: {
2097       bool check_conversion = (i.OutputCount() > 1);
2098       __ ConvertFloat32ToUnsignedInt64(i.InputDoubleRegister(0),
2099                                        i.OutputRegister(0), kScratchDoubleReg);
2100       if (check_conversion) {
2101         Label conversion_done;
2102         __ LoadImmP(i.OutputRegister(1), Operand::Zero());
2103         __ b(Condition(1), &conversion_done);  // special case
2104         __ LoadImmP(i.OutputRegister(1), Operand(1));
2105         __ bind(&conversion_done);
2106       }
2107       break;
2108     }
2109 #endif
2110     case kS390_Float32ToInt64: {
2111 #if V8_TARGET_ARCH_S390X
2112       bool check_conversion =
2113           (opcode == kS390_Float32ToInt64 && i.OutputCount() > 1);
2114 #endif
2115       __ ConvertFloat32ToInt64(i.InputDoubleRegister(0),
2116 #if !V8_TARGET_ARCH_S390X
2117                                kScratchReg,
2118 #endif
2119                                i.OutputRegister(0), kScratchDoubleReg);
2120 #if V8_TARGET_ARCH_S390X
2121       if (check_conversion) {
2122         Label conversion_done;
2123         __ LoadImmP(i.OutputRegister(1), Operand::Zero());
2124         __ b(Condition(1), &conversion_done);  // special case
2125         __ LoadImmP(i.OutputRegister(1), Operand(1));
2126         __ bind(&conversion_done);
2127       }
2128 #endif
2129       break;
2130     }
2131 #if V8_TARGET_ARCH_S390X
2132     case kS390_DoubleToUint64: {
2133       bool check_conversion = (i.OutputCount() > 1);
2134       __ ConvertDoubleToUnsignedInt64(i.InputDoubleRegister(0),
2135                                       i.OutputRegister(0), kScratchDoubleReg);
2136       if (check_conversion) {
2137         Label conversion_done;
2138         __ LoadImmP(i.OutputRegister(1), Operand::Zero());
2139         __ b(Condition(1), &conversion_done);  // special case
2140         __ LoadImmP(i.OutputRegister(1), Operand(1));
2141         __ bind(&conversion_done);
2142       }
2143       break;
2144     }
2145 #endif
2146     case kS390_DoubleToFloat32:
2147       __ ledbr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
2148       break;
2149     case kS390_Float32ToDouble:
2150       __ ldebr(i.OutputDoubleRegister(), i.InputDoubleRegister(0));
2151       break;
2152     case kS390_DoubleExtractLowWord32:
2153       __ lgdr(i.OutputRegister(), i.InputDoubleRegister(0));
2154       __ llgfr(i.OutputRegister(), i.OutputRegister());
2155       break;
2156     case kS390_DoubleExtractHighWord32:
2157       __ lgdr(i.OutputRegister(), i.InputDoubleRegister(0));
2158       __ srlg(i.OutputRegister(), i.OutputRegister(), Operand(32));
2159       break;
2160     case kS390_DoubleInsertLowWord32:
2161       __ lgdr(kScratchReg, i.OutputDoubleRegister());
2162       __ lr(kScratchReg, i.InputRegister(1));
2163       __ ldgr(i.OutputDoubleRegister(), kScratchReg);
2164       break;
2165     case kS390_DoubleInsertHighWord32:
2166       __ sllg(kScratchReg, i.InputRegister(1), Operand(32));
2167       __ lgdr(r0, i.OutputDoubleRegister());
2168       __ lr(kScratchReg, r0);
2169       __ ldgr(i.OutputDoubleRegister(), kScratchReg);
2170       break;
2171     case kS390_DoubleConstruct:
2172       __ sllg(kScratchReg, i.InputRegister(0), Operand(32));
2173       __ lr(kScratchReg, i.InputRegister(1));
2174 
2175       // Bitwise convert from GPR to FPR
2176       __ ldgr(i.OutputDoubleRegister(), kScratchReg);
2177       break;
2178     case kS390_LoadWordS8:
2179       ASSEMBLE_LOAD_INTEGER(LoadlB);
2180 #if V8_TARGET_ARCH_S390X
2181       __ lgbr(i.OutputRegister(), i.OutputRegister());
2182 #else
2183       __ lbr(i.OutputRegister(), i.OutputRegister());
2184 #endif
2185       break;
2186     case kS390_BitcastFloat32ToInt32:
2187       __ MovFloatToInt(i.OutputRegister(), i.InputDoubleRegister(0));
2188       break;
2189     case kS390_BitcastInt32ToFloat32:
2190       __ MovIntToFloat(i.OutputDoubleRegister(), i.InputRegister(0));
2191       break;
2192 #if V8_TARGET_ARCH_S390X
2193     case kS390_BitcastDoubleToInt64:
2194       __ MovDoubleToInt64(i.OutputRegister(), i.InputDoubleRegister(0));
2195       break;
2196     case kS390_BitcastInt64ToDouble:
2197       __ MovInt64ToDouble(i.OutputDoubleRegister(), i.InputRegister(0));
2198       break;
2199 #endif
2200     case kS390_LoadWordU8:
2201       ASSEMBLE_LOAD_INTEGER(LoadlB);
2202       break;
2203     case kS390_LoadWordU16:
2204       ASSEMBLE_LOAD_INTEGER(LoadLogicalHalfWordP);
2205       break;
2206     case kS390_LoadWordS16:
2207       ASSEMBLE_LOAD_INTEGER(LoadHalfWordP);
2208       break;
2209     case kS390_LoadWordU32:
2210       ASSEMBLE_LOAD_INTEGER(LoadlW);
2211       break;
2212     case kS390_LoadWordS32:
2213       ASSEMBLE_LOAD_INTEGER(LoadW);
2214       break;
2215     case kS390_LoadReverse16:
2216       ASSEMBLE_LOAD_INTEGER(lrvh);
2217       break;
2218     case kS390_LoadReverse32:
2219       ASSEMBLE_LOAD_INTEGER(lrv);
2220       break;
2221     case kS390_LoadReverse64:
2222       ASSEMBLE_LOAD_INTEGER(lrvg);
2223       break;
2224     case kS390_LoadReverse16RR:
2225       __ lrvr(i.OutputRegister(), i.InputRegister(0));
2226       __ rll(i.OutputRegister(), i.OutputRegister(), Operand(16));
2227       break;
2228     case kS390_LoadReverse32RR:
2229       __ lrvr(i.OutputRegister(), i.InputRegister(0));
2230       break;
2231     case kS390_LoadReverse64RR:
2232       __ lrvgr(i.OutputRegister(), i.InputRegister(0));
2233       break;
2234 #if V8_TARGET_ARCH_S390X
2235     case kS390_LoadWord64:
2236       ASSEMBLE_LOAD_INTEGER(lg);
2237       break;
2238 #endif
2239     case kS390_LoadAndTestWord32: {
2240       ASSEMBLE_LOADANDTEST32(ltr, lt_z);
2241       break;
2242     }
2243     case kS390_LoadAndTestWord64: {
2244       ASSEMBLE_LOADANDTEST64(ltgr, ltg);
2245       break;
2246     }
2247     case kS390_LoadFloat32:
2248       ASSEMBLE_LOAD_FLOAT(LoadFloat32);
2249       break;
2250     case kS390_LoadDouble:
2251       ASSEMBLE_LOAD_FLOAT(LoadDouble);
2252       break;
2253     case kS390_StoreWord8:
2254       ASSEMBLE_STORE_INTEGER(StoreByte);
2255       break;
2256     case kS390_StoreWord16:
2257       ASSEMBLE_STORE_INTEGER(StoreHalfWord);
2258       break;
2259     case kS390_StoreWord32:
2260       ASSEMBLE_STORE_INTEGER(StoreW);
2261       break;
2262 #if V8_TARGET_ARCH_S390X
2263     case kS390_StoreWord64:
2264       ASSEMBLE_STORE_INTEGER(StoreP);
2265       break;
2266 #endif
2267     case kS390_StoreReverse16:
2268       ASSEMBLE_STORE_INTEGER(strvh);
2269       break;
2270     case kS390_StoreReverse32:
2271       ASSEMBLE_STORE_INTEGER(strv);
2272       break;
2273     case kS390_StoreReverse64:
2274       ASSEMBLE_STORE_INTEGER(strvg);
2275       break;
2276     case kS390_StoreFloat32:
2277       ASSEMBLE_STORE_FLOAT32();
2278       break;
2279     case kS390_StoreDouble:
2280       ASSEMBLE_STORE_DOUBLE();
2281       break;
2282     case kS390_Lay:
2283       __ lay(i.OutputRegister(), i.MemoryOperand());
2284       break;
2285     case kCheckedLoadInt8:
2286       ASSEMBLE_CHECKED_LOAD_INTEGER(LoadlB);
2287 #if V8_TARGET_ARCH_S390X
2288       __ lgbr(i.OutputRegister(), i.OutputRegister());
2289 #else
2290       __ lbr(i.OutputRegister(), i.OutputRegister());
2291 #endif
2292       break;
2293     case kCheckedLoadUint8:
2294       ASSEMBLE_CHECKED_LOAD_INTEGER(LoadlB);
2295       break;
2296     case kCheckedLoadInt16:
2297       ASSEMBLE_CHECKED_LOAD_INTEGER(LoadHalfWordP);
2298       break;
2299     case kCheckedLoadUint16:
2300       ASSEMBLE_CHECKED_LOAD_INTEGER(LoadLogicalHalfWordP);
2301       break;
2302     case kCheckedLoadWord32:
2303       ASSEMBLE_CHECKED_LOAD_INTEGER(LoadlW);
2304       break;
2305     case kCheckedLoadWord64:
2306 #if V8_TARGET_ARCH_S390X
2307       ASSEMBLE_CHECKED_LOAD_INTEGER(LoadP);
2308 #else
2309       UNREACHABLE();
2310 #endif
2311       break;
2312     case kCheckedLoadFloat32:
2313       ASSEMBLE_CHECKED_LOAD_FLOAT(LoadFloat32, 32);
2314       break;
2315     case kCheckedLoadFloat64:
2316       ASSEMBLE_CHECKED_LOAD_FLOAT(LoadDouble, 64);
2317       break;
2318     case kCheckedStoreWord8:
2319       ASSEMBLE_CHECKED_STORE_INTEGER(StoreByte);
2320       break;
2321     case kCheckedStoreWord16:
2322       ASSEMBLE_CHECKED_STORE_INTEGER(StoreHalfWord);
2323       break;
2324     case kCheckedStoreWord32:
2325       ASSEMBLE_CHECKED_STORE_INTEGER(StoreW);
2326       break;
2327     case kCheckedStoreWord64:
2328 #if V8_TARGET_ARCH_S390X
2329       ASSEMBLE_CHECKED_STORE_INTEGER(StoreP);
2330 #else
2331       UNREACHABLE();
2332 #endif
2333       break;
2334     case kCheckedStoreFloat32:
2335       ASSEMBLE_CHECKED_STORE_FLOAT32();
2336       break;
2337     case kCheckedStoreFloat64:
2338       ASSEMBLE_CHECKED_STORE_DOUBLE();
2339       break;
2340     case kAtomicLoadInt8:
2341       __ LoadB(i.OutputRegister(), i.MemoryOperand());
2342       break;
2343     case kAtomicLoadUint8:
2344       __ LoadlB(i.OutputRegister(), i.MemoryOperand());
2345       break;
2346     case kAtomicLoadInt16:
2347       __ LoadHalfWordP(i.OutputRegister(), i.MemoryOperand());
2348       break;
2349     case kAtomicLoadUint16:
2350       __ LoadLogicalHalfWordP(i.OutputRegister(), i.MemoryOperand());
2351       break;
2352     case kAtomicLoadWord32:
2353       __ LoadlW(i.OutputRegister(), i.MemoryOperand());
2354       break;
2355     case kAtomicStoreWord8:
2356       __ StoreByte(i.InputRegister(0), i.MemoryOperand(NULL, 1));
2357       break;
2358     case kAtomicStoreWord16:
2359       __ StoreHalfWord(i.InputRegister(0), i.MemoryOperand(NULL, 1));
2360       break;
2361     case kAtomicStoreWord32:
2362       __ StoreW(i.InputRegister(0), i.MemoryOperand(NULL, 1));
2363       break;
2364     default:
2365       UNREACHABLE();
2366       break;
2367   }
2368   return kSuccess;
2369 }  // NOLINT(readability/fn_size)
2370 
2371 // Assembles branches after an instruction.
AssembleArchBranch(Instruction * instr,BranchInfo * branch)2372 void CodeGenerator::AssembleArchBranch(Instruction* instr, BranchInfo* branch) {
2373   S390OperandConverter i(this, instr);
2374   Label* tlabel = branch->true_label;
2375   Label* flabel = branch->false_label;
2376   ArchOpcode op = instr->arch_opcode();
2377   FlagsCondition condition = branch->condition;
2378 
2379   Condition cond = FlagsConditionToCondition(condition, op);
2380   if (op == kS390_CmpDouble) {
2381     // check for unordered if necessary
2382     // Branching to flabel/tlabel according to what's expected by tests
2383     if (cond == le || cond == eq || cond == lt) {
2384       __ bunordered(flabel);
2385     } else if (cond == gt || cond == ne || cond == ge) {
2386       __ bunordered(tlabel);
2387     }
2388   }
2389   __ b(cond, tlabel);
2390   if (!branch->fallthru) __ b(flabel);  // no fallthru to flabel.
2391 }
2392 
AssembleArchJump(RpoNumber target)2393 void CodeGenerator::AssembleArchJump(RpoNumber target) {
2394   if (!IsNextInAssemblyOrder(target)) __ b(GetLabel(target));
2395 }
2396 
AssembleArchTrap(Instruction * instr,FlagsCondition condition)2397 void CodeGenerator::AssembleArchTrap(Instruction* instr,
2398                                      FlagsCondition condition) {
2399   class OutOfLineTrap final : public OutOfLineCode {
2400    public:
2401     OutOfLineTrap(CodeGenerator* gen, bool frame_elided, Instruction* instr)
2402         : OutOfLineCode(gen),
2403           frame_elided_(frame_elided),
2404           instr_(instr),
2405           gen_(gen) {}
2406 
2407     void Generate() final {
2408       S390OperandConverter i(gen_, instr_);
2409 
2410       Builtins::Name trap_id =
2411           static_cast<Builtins::Name>(i.InputInt32(instr_->InputCount() - 1));
2412       bool old_has_frame = __ has_frame();
2413       if (frame_elided_) {
2414         __ set_has_frame(true);
2415         __ EnterFrame(StackFrame::WASM_COMPILED);
2416       }
2417       GenerateCallToTrap(trap_id);
2418       if (frame_elided_) {
2419         __ set_has_frame(old_has_frame);
2420       }
2421     }
2422 
2423    private:
2424     void GenerateCallToTrap(Builtins::Name trap_id) {
2425       if (trap_id == Builtins::builtin_count) {
2426         // We cannot test calls to the runtime in cctest/test-run-wasm.
2427         // Therefore we emit a call to C here instead of a call to the runtime.
2428         // We use the context register as the scratch register, because we do
2429         // not have a context here.
2430         __ PrepareCallCFunction(0, 0, cp);
2431         __ CallCFunction(
2432             ExternalReference::wasm_call_trap_callback_for_testing(isolate()),
2433             0);
2434         __ LeaveFrame(StackFrame::WASM_COMPILED);
2435         __ Ret();
2436       } else {
2437         gen_->AssembleSourcePosition(instr_);
2438         __ Call(handle(isolate()->builtins()->builtin(trap_id), isolate()),
2439                 RelocInfo::CODE_TARGET);
2440         ReferenceMap* reference_map =
2441             new (gen_->zone()) ReferenceMap(gen_->zone());
2442         gen_->RecordSafepoint(reference_map, Safepoint::kSimple, 0,
2443                               Safepoint::kNoLazyDeopt);
2444         if (FLAG_debug_code) {
2445           __ stop(GetBailoutReason(kUnexpectedReturnFromWasmTrap));
2446         }
2447       }
2448     }
2449 
2450     bool frame_elided_;
2451     Instruction* instr_;
2452     CodeGenerator* gen_;
2453   };
2454   bool frame_elided = !frame_access_state()->has_frame();
2455   auto ool = new (zone()) OutOfLineTrap(this, frame_elided, instr);
2456   Label* tlabel = ool->entry();
2457   Label end;
2458 
2459   ArchOpcode op = instr->arch_opcode();
2460   Condition cond = FlagsConditionToCondition(condition, op);
2461   if (op == kS390_CmpDouble) {
2462     // check for unordered if necessary
2463     if (cond == le) {
2464       __ bunordered(&end);
2465       // Unnecessary for eq/lt since only FU bit will be set.
2466     } else if (cond == gt) {
2467       __ bunordered(tlabel);
2468       // Unnecessary for ne/ge since only FU bit will be set.
2469     }
2470   }
2471   __ b(cond, tlabel);
2472   __ bind(&end);
2473 }
2474 
2475 // Assembles boolean materializations after an instruction.
AssembleArchBoolean(Instruction * instr,FlagsCondition condition)2476 void CodeGenerator::AssembleArchBoolean(Instruction* instr,
2477                                         FlagsCondition condition) {
2478   S390OperandConverter i(this, instr);
2479   ArchOpcode op = instr->arch_opcode();
2480   bool check_unordered = (op == kS390_CmpDouble || op == kS390_CmpFloat);
2481 
2482   // Overflow checked for add/sub only.
2483   DCHECK((condition != kOverflow && condition != kNotOverflow) ||
2484          (op == kS390_Add32 || kS390_Add64 || op == kS390_Sub32 ||
2485           op == kS390_Sub64));
2486 
2487   // Materialize a full 32-bit 1 or 0 value. The result register is always the
2488   // last output of the instruction.
2489   DCHECK_NE(0u, instr->OutputCount());
2490   Register reg = i.OutputRegister(instr->OutputCount() - 1);
2491   Condition cond = FlagsConditionToCondition(condition, op);
2492   Label done;
2493   if (check_unordered) {
2494     __ LoadImmP(reg, (cond == eq || cond == le || cond == lt) ? Operand::Zero()
2495                                                               : Operand(1));
2496     __ bunordered(&done);
2497   }
2498   __ LoadImmP(reg, Operand::Zero());
2499   __ LoadImmP(kScratchReg, Operand(1));
2500   // locr is sufficient since reg's upper 32 is guarrantee to be 0
2501   __ locr(cond, reg, kScratchReg);
2502   __ bind(&done);
2503 }
2504 
AssembleArchLookupSwitch(Instruction * instr)2505 void CodeGenerator::AssembleArchLookupSwitch(Instruction* instr) {
2506   S390OperandConverter i(this, instr);
2507   Register input = i.InputRegister(0);
2508   for (size_t index = 2; index < instr->InputCount(); index += 2) {
2509     __ Cmp32(input, Operand(i.InputInt32(index + 0)));
2510     __ beq(GetLabel(i.InputRpo(index + 1)));
2511   }
2512   AssembleArchJump(i.InputRpo(1));
2513 }
2514 
AssembleArchTableSwitch(Instruction * instr)2515 void CodeGenerator::AssembleArchTableSwitch(Instruction* instr) {
2516   S390OperandConverter i(this, instr);
2517   Register input = i.InputRegister(0);
2518   int32_t const case_count = static_cast<int32_t>(instr->InputCount() - 2);
2519   Label** cases = zone()->NewArray<Label*>(case_count);
2520   for (int32_t index = 0; index < case_count; ++index) {
2521     cases[index] = GetLabel(i.InputRpo(index + 2));
2522   }
2523   Label* const table = AddJumpTable(cases, case_count);
2524   __ CmpLogicalP(input, Operand(case_count));
2525   __ bge(GetLabel(i.InputRpo(1)));
2526   __ larl(kScratchReg, table);
2527   __ ShiftLeftP(r1, input, Operand(kPointerSizeLog2));
2528   __ LoadP(kScratchReg, MemOperand(kScratchReg, r1));
2529   __ Jump(kScratchReg);
2530 }
2531 
AssembleDeoptimizerCall(int deoptimization_id,SourcePosition pos)2532 CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall(
2533     int deoptimization_id, SourcePosition pos) {
2534   DeoptimizeKind deoptimization_kind = GetDeoptimizationKind(deoptimization_id);
2535   DeoptimizeReason deoptimization_reason =
2536       GetDeoptimizationReason(deoptimization_id);
2537   Deoptimizer::BailoutType bailout_type =
2538       deoptimization_kind == DeoptimizeKind::kSoft ? Deoptimizer::SOFT
2539                                                    : Deoptimizer::EAGER;
2540   Address deopt_entry = Deoptimizer::GetDeoptimizationEntry(
2541       isolate(), deoptimization_id, bailout_type);
2542   // TODO(turbofan): We should be able to generate better code by sharing the
2543   // actual final call site and just bl'ing to it here, similar to what we do
2544   // in the lithium backend.
2545   if (deopt_entry == nullptr) return kTooManyDeoptimizationBailouts;
2546   __ RecordDeoptReason(deoptimization_reason, pos, deoptimization_id);
2547   __ Call(deopt_entry, RelocInfo::RUNTIME_ENTRY);
2548   return kSuccess;
2549 }
2550 
FinishFrame(Frame * frame)2551 void CodeGenerator::FinishFrame(Frame* frame) {
2552   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
2553   const RegList double_saves = descriptor->CalleeSavedFPRegisters();
2554 
2555   // Save callee-saved Double registers.
2556   if (double_saves != 0) {
2557     frame->AlignSavedCalleeRegisterSlots();
2558     DCHECK(kNumCalleeSavedDoubles ==
2559            base::bits::CountPopulation32(double_saves));
2560     frame->AllocateSavedCalleeRegisterSlots(kNumCalleeSavedDoubles *
2561                                             (kDoubleSize / kPointerSize));
2562   }
2563   // Save callee-saved registers.
2564   const RegList saves = descriptor->CalleeSavedRegisters();
2565   if (saves != 0) {
2566     // register save area does not include the fp or constant pool pointer.
2567     const int num_saves = kNumCalleeSaved - 1;
2568     DCHECK(num_saves == base::bits::CountPopulation32(saves));
2569     frame->AllocateSavedCalleeRegisterSlots(num_saves);
2570   }
2571 }
2572 
AssembleConstructFrame()2573 void CodeGenerator::AssembleConstructFrame() {
2574   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
2575 
2576   if (frame_access_state()->has_frame()) {
2577     if (descriptor->IsCFunctionCall()) {
2578       __ Push(r14, fp);
2579       __ LoadRR(fp, sp);
2580     } else if (descriptor->IsJSFunctionCall()) {
2581       __ Prologue(this->info()->GeneratePreagedPrologue(), ip);
2582       if (descriptor->PushArgumentCount()) {
2583         __ Push(kJavaScriptCallArgCountRegister);
2584       }
2585     } else {
2586       StackFrame::Type type = info()->GetOutputStackFrameType();
2587       // TODO(mbrandy): Detect cases where ip is the entrypoint (for
2588       // efficient intialization of the constant pool pointer register).
2589       __ StubPrologue(type);
2590     }
2591   }
2592 
2593   int shrink_slots =
2594       frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
2595   if (info()->is_osr()) {
2596     // TurboFan OSR-compiled functions cannot be entered directly.
2597     __ Abort(kShouldNotDirectlyEnterOsrFunction);
2598 
2599     // Unoptimized code jumps directly to this entrypoint while the unoptimized
2600     // frame is still on the stack. Optimized code uses OSR values directly from
2601     // the unoptimized frame. Thus, all that needs to be done is to allocate the
2602     // remaining stack slots.
2603     if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
2604     osr_pc_offset_ = __ pc_offset();
2605     shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
2606   }
2607 
2608   const RegList double_saves = descriptor->CalleeSavedFPRegisters();
2609   if (shrink_slots > 0) {
2610     __ lay(sp, MemOperand(sp, -shrink_slots * kPointerSize));
2611   }
2612 
2613   // Save callee-saved Double registers.
2614   if (double_saves != 0) {
2615     __ MultiPushDoubles(double_saves);
2616     DCHECK(kNumCalleeSavedDoubles ==
2617            base::bits::CountPopulation32(double_saves));
2618   }
2619 
2620   // Save callee-saved registers.
2621   const RegList saves = descriptor->CalleeSavedRegisters();
2622   if (saves != 0) {
2623     __ MultiPush(saves);
2624     // register save area does not include the fp or constant pool pointer.
2625   }
2626 }
2627 
AssembleReturn(InstructionOperand * pop)2628 void CodeGenerator::AssembleReturn(InstructionOperand* pop) {
2629   CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
2630   int pop_count = static_cast<int>(descriptor->StackParameterCount());
2631 
2632   // Restore registers.
2633   const RegList saves = descriptor->CalleeSavedRegisters();
2634   if (saves != 0) {
2635     __ MultiPop(saves);
2636   }
2637 
2638   // Restore double registers.
2639   const RegList double_saves = descriptor->CalleeSavedFPRegisters();
2640   if (double_saves != 0) {
2641     __ MultiPopDoubles(double_saves);
2642   }
2643 
2644   S390OperandConverter g(this, nullptr);
2645   if (descriptor->IsCFunctionCall()) {
2646     AssembleDeconstructFrame();
2647   } else if (frame_access_state()->has_frame()) {
2648     // Canonicalize JSFunction return sites for now unless they have an variable
2649     // number of stack slot pops
2650     if (pop->IsImmediate() && g.ToConstant(pop).ToInt32() == 0) {
2651       if (return_label_.is_bound()) {
2652         __ b(&return_label_);
2653         return;
2654       } else {
2655         __ bind(&return_label_);
2656         AssembleDeconstructFrame();
2657       }
2658     } else {
2659       AssembleDeconstructFrame();
2660     }
2661   }
2662   if (pop->IsImmediate()) {
2663     DCHECK_EQ(Constant::kInt32, g.ToConstant(pop).type());
2664     pop_count += g.ToConstant(pop).ToInt32();
2665   } else {
2666     __ Drop(g.ToRegister(pop));
2667   }
2668   __ Drop(pop_count);
2669   __ Ret();
2670 }
2671 
AssembleMove(InstructionOperand * source,InstructionOperand * destination)2672 void CodeGenerator::AssembleMove(InstructionOperand* source,
2673                                  InstructionOperand* destination) {
2674   S390OperandConverter g(this, nullptr);
2675   // Dispatch on the source and destination operand kinds.  Not all
2676   // combinations are possible.
2677   if (source->IsRegister()) {
2678     DCHECK(destination->IsRegister() || destination->IsStackSlot());
2679     Register src = g.ToRegister(source);
2680     if (destination->IsRegister()) {
2681       __ Move(g.ToRegister(destination), src);
2682     } else {
2683       __ StoreP(src, g.ToMemOperand(destination));
2684     }
2685   } else if (source->IsStackSlot()) {
2686     DCHECK(destination->IsRegister() || destination->IsStackSlot());
2687     MemOperand src = g.ToMemOperand(source);
2688     if (destination->IsRegister()) {
2689       __ LoadP(g.ToRegister(destination), src);
2690     } else {
2691       Register temp = kScratchReg;
2692       __ LoadP(temp, src, r0);
2693       __ StoreP(temp, g.ToMemOperand(destination));
2694     }
2695   } else if (source->IsConstant()) {
2696     Constant src = g.ToConstant(source);
2697     if (destination->IsRegister() || destination->IsStackSlot()) {
2698       Register dst =
2699           destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
2700       switch (src.type()) {
2701         case Constant::kInt32:
2702 #if V8_TARGET_ARCH_S390X
2703           if (RelocInfo::IsWasmSizeReference(src.rmode())) {
2704 #else
2705           if (RelocInfo::IsWasmReference(src.rmode())) {
2706 #endif
2707             __ mov(dst, Operand(src.ToInt32(), src.rmode()));
2708           } else {
2709             __ Load(dst, Operand(src.ToInt32()));
2710           }
2711           break;
2712         case Constant::kInt64:
2713 #if V8_TARGET_ARCH_S390X
2714           if (RelocInfo::IsWasmPtrReference(src.rmode())) {
2715             __ mov(dst, Operand(src.ToInt64(), src.rmode()));
2716           } else {
2717             DCHECK(!RelocInfo::IsWasmSizeReference(src.rmode()));
2718             __ Load(dst, Operand(src.ToInt64()));
2719           }
2720 #else
2721           __ mov(dst, Operand(src.ToInt64()));
2722 #endif  // V8_TARGET_ARCH_S390X
2723           break;
2724         case Constant::kFloat32:
2725           __ Move(dst,
2726                   isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
2727           break;
2728         case Constant::kFloat64:
2729           __ Move(dst,
2730                   isolate()->factory()->NewNumber(src.ToFloat64(), TENURED));
2731           break;
2732         case Constant::kExternalReference:
2733           __ mov(dst, Operand(src.ToExternalReference()));
2734           break;
2735         case Constant::kHeapObject: {
2736           Handle<HeapObject> src_object = src.ToHeapObject();
2737           Heap::RootListIndex index;
2738           if (IsMaterializableFromRoot(src_object, &index)) {
2739             __ LoadRoot(dst, index);
2740           } else {
2741             __ Move(dst, src_object);
2742           }
2743           break;
2744         }
2745         case Constant::kRpoNumber:
2746           UNREACHABLE();  // TODO(dcarney): loading RPO constants on S390.
2747           break;
2748       }
2749       if (destination->IsStackSlot()) {
2750         __ StoreP(dst, g.ToMemOperand(destination), r0);
2751       }
2752     } else {
2753       DoubleRegister dst = destination->IsFPRegister()
2754                                ? g.ToDoubleRegister(destination)
2755                                : kScratchDoubleReg;
2756       double value = (src.type() == Constant::kFloat32) ? src.ToFloat32()
2757                                                         : src.ToFloat64();
2758       if (src.type() == Constant::kFloat32) {
2759         __ LoadFloat32Literal(dst, src.ToFloat32(), kScratchReg);
2760       } else {
2761         __ LoadDoubleLiteral(dst, value, kScratchReg);
2762       }
2763 
2764       if (destination->IsFPStackSlot()) {
2765         __ StoreDouble(dst, g.ToMemOperand(destination));
2766       }
2767     }
2768   } else if (source->IsFPRegister()) {
2769     DoubleRegister src = g.ToDoubleRegister(source);
2770     if (destination->IsFPRegister()) {
2771       DoubleRegister dst = g.ToDoubleRegister(destination);
2772       __ Move(dst, src);
2773     } else {
2774       DCHECK(destination->IsFPStackSlot());
2775       LocationOperand* op = LocationOperand::cast(source);
2776       if (op->representation() == MachineRepresentation::kFloat64) {
2777         __ StoreDouble(src, g.ToMemOperand(destination));
2778       } else {
2779         __ StoreFloat32(src, g.ToMemOperand(destination));
2780       }
2781     }
2782   } else if (source->IsFPStackSlot()) {
2783     DCHECK(destination->IsFPRegister() || destination->IsFPStackSlot());
2784     MemOperand src = g.ToMemOperand(source);
2785     if (destination->IsFPRegister()) {
2786       LocationOperand* op = LocationOperand::cast(source);
2787       if (op->representation() == MachineRepresentation::kFloat64) {
2788         __ LoadDouble(g.ToDoubleRegister(destination), src);
2789       } else {
2790         __ LoadFloat32(g.ToDoubleRegister(destination), src);
2791       }
2792     } else {
2793       LocationOperand* op = LocationOperand::cast(source);
2794       DoubleRegister temp = kScratchDoubleReg;
2795       if (op->representation() == MachineRepresentation::kFloat64) {
2796         __ LoadDouble(temp, src);
2797         __ StoreDouble(temp, g.ToMemOperand(destination));
2798       } else {
2799         __ LoadFloat32(temp, src);
2800         __ StoreFloat32(temp, g.ToMemOperand(destination));
2801       }
2802     }
2803   } else {
2804     UNREACHABLE();
2805   }
2806 }
2807 
2808 void CodeGenerator::AssembleSwap(InstructionOperand* source,
2809                                  InstructionOperand* destination) {
2810   S390OperandConverter g(this, nullptr);
2811   // Dispatch on the source and destination operand kinds.  Not all
2812   // combinations are possible.
2813   if (source->IsRegister()) {
2814     // Register-register.
2815     Register temp = kScratchReg;
2816     Register src = g.ToRegister(source);
2817     if (destination->IsRegister()) {
2818       Register dst = g.ToRegister(destination);
2819       __ LoadRR(temp, src);
2820       __ LoadRR(src, dst);
2821       __ LoadRR(dst, temp);
2822     } else {
2823       DCHECK(destination->IsStackSlot());
2824       MemOperand dst = g.ToMemOperand(destination);
2825       __ LoadRR(temp, src);
2826       __ LoadP(src, dst);
2827       __ StoreP(temp, dst);
2828     }
2829 #if V8_TARGET_ARCH_S390X
2830   } else if (source->IsStackSlot() || source->IsFPStackSlot()) {
2831 #else
2832   } else if (source->IsStackSlot()) {
2833     DCHECK(destination->IsStackSlot());
2834 #endif
2835     Register temp_0 = kScratchReg;
2836     Register temp_1 = r0;
2837     MemOperand src = g.ToMemOperand(source);
2838     MemOperand dst = g.ToMemOperand(destination);
2839     __ LoadP(temp_0, src);
2840     __ LoadP(temp_1, dst);
2841     __ StoreP(temp_0, dst);
2842     __ StoreP(temp_1, src);
2843   } else if (source->IsFPRegister()) {
2844     DoubleRegister temp = kScratchDoubleReg;
2845     DoubleRegister src = g.ToDoubleRegister(source);
2846     if (destination->IsFPRegister()) {
2847       DoubleRegister dst = g.ToDoubleRegister(destination);
2848       __ ldr(temp, src);
2849       __ ldr(src, dst);
2850       __ ldr(dst, temp);
2851     } else {
2852       DCHECK(destination->IsFPStackSlot());
2853       MemOperand dst = g.ToMemOperand(destination);
2854       __ ldr(temp, src);
2855       __ LoadDouble(src, dst);
2856       __ StoreDouble(temp, dst);
2857     }
2858 #if !V8_TARGET_ARCH_S390X
2859   } else if (source->IsFPStackSlot()) {
2860     DCHECK(destination->IsFPStackSlot());
2861     DoubleRegister temp_0 = kScratchDoubleReg;
2862     DoubleRegister temp_1 = d0;
2863     MemOperand src = g.ToMemOperand(source);
2864     MemOperand dst = g.ToMemOperand(destination);
2865     // TODO(joransiu): MVC opportunity
2866     __ LoadDouble(temp_0, src);
2867     __ LoadDouble(temp_1, dst);
2868     __ StoreDouble(temp_0, dst);
2869     __ StoreDouble(temp_1, src);
2870 #endif
2871   } else {
2872     // No other combinations are possible.
2873     UNREACHABLE();
2874   }
2875 }
2876 
2877 void CodeGenerator::AssembleJumpTable(Label** targets, size_t target_count) {
2878   for (size_t index = 0; index < target_count; ++index) {
2879     __ emit_label_addr(targets[index]);
2880   }
2881 }
2882 
2883 void CodeGenerator::EnsureSpaceForLazyDeopt() {
2884   if (!info()->ShouldEnsureSpaceForLazyDeopt()) {
2885     return;
2886   }
2887 
2888   int space_needed = Deoptimizer::patch_size();
2889   // Ensure that we have enough space after the previous lazy-bailout
2890   // instruction for patching the code here.
2891   int current_pc = masm()->pc_offset();
2892   if (current_pc < last_lazy_deopt_pc_ + space_needed) {
2893     int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc;
2894     DCHECK_EQ(0, padding_size % 2);
2895     while (padding_size > 0) {
2896       __ nop();
2897       padding_size -= 2;
2898     }
2899   }
2900 }
2901 
2902 #undef __
2903 
2904 }  // namespace compiler
2905 }  // namespace internal
2906 }  // namespace v8
2907