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