OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/base/adapters.h" | 5 #include "src/base/adapters.h" |
6 #include "src/compiler/instruction-selector-impl.h" | 6 #include "src/compiler/instruction-selector-impl.h" |
7 #include "src/compiler/node-matchers.h" | 7 #include "src/compiler/node-matchers.h" |
8 #include "src/compiler/node-properties.h" | 8 #include "src/compiler/node-properties.h" |
9 #include "src/s390/frames-s390.h" | 9 #include "src/s390/frames-s390.h" |
10 | 10 |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 case MachineRepresentation::kSimd1x4: // Fall through. | 310 case MachineRepresentation::kSimd1x4: // Fall through. |
311 case MachineRepresentation::kSimd1x8: // Fall through. | 311 case MachineRepresentation::kSimd1x8: // Fall through. |
312 case MachineRepresentation::kSimd1x16: // Fall through. | 312 case MachineRepresentation::kSimd1x16: // Fall through. |
313 case MachineRepresentation::kNone: | 313 case MachineRepresentation::kNone: |
314 default: | 314 default: |
315 UNREACHABLE(); | 315 UNREACHABLE(); |
316 } | 316 } |
317 return opcode; | 317 return opcode; |
318 } | 318 } |
319 | 319 |
320 bool AutoZeroExtendsWord32ToWord64(Node* node) { | 320 #define RESULT_IS_WORD32_LIST(V) \ |
| 321 /* Float unary op*/ \ |
| 322 V(BitcastFloat32ToInt32) \ |
| 323 /* V(TruncateFloat64ToWord32) */ \ |
| 324 /* V(RoundFloat64ToInt32) */ \ |
| 325 /* V(TruncateFloat32ToInt32) */ \ |
| 326 /* V(TruncateFloat32ToUint32) */ \ |
| 327 /* V(TruncateFloat64ToUint32) */ \ |
| 328 /* V(ChangeFloat64ToInt32) */ \ |
| 329 /* V(ChangeFloat64ToUint32) */ \ |
| 330 /* Word32 unary op */ \ |
| 331 V(Word32Clz) \ |
| 332 V(Word32Popcnt) \ |
| 333 /* Word32 bin op */ \ |
| 334 V(Int32Add) \ |
| 335 V(Int32Sub) \ |
| 336 V(Int32Mul) \ |
| 337 V(Int32AddWithOverflow) \ |
| 338 V(Int32SubWithOverflow) \ |
| 339 V(Int32MulWithOverflow) \ |
| 340 V(Int32MulHigh) \ |
| 341 V(Uint32MulHigh) \ |
| 342 V(Int32Div) \ |
| 343 V(Uint32Div) \ |
| 344 V(Int32Mod) \ |
| 345 V(Uint32Mod) \ |
| 346 V(Word32Ror) \ |
| 347 V(Word32And) \ |
| 348 V(Word32Or) \ |
| 349 V(Word32Xor) \ |
| 350 V(Word32Shl) \ |
| 351 V(Word32Shr) \ |
| 352 V(Word32Sar) |
| 353 |
| 354 bool ProduceWord32Result(Node* node) { |
321 #if !V8_TARGET_ARCH_S390X | 355 #if !V8_TARGET_ARCH_S390X |
322 return true; | 356 return true; |
323 #else | 357 #else |
324 switch (node->opcode()) { | 358 switch (node->opcode()) { |
325 case IrOpcode::kInt32Div: | 359 #define VISITOR(name) case IrOpcode::k##name: |
326 case IrOpcode::kUint32Div: | 360 RESULT_IS_WORD32_LIST(VISITOR) |
327 case IrOpcode::kInt32MulHigh: | 361 #undef VISITOR |
328 case IrOpcode::kUint32MulHigh: | 362 return true; |
329 case IrOpcode::kInt32Mod: | |
330 case IrOpcode::kUint32Mod: | |
331 case IrOpcode::kWord32Clz: | |
332 case IrOpcode::kWord32Popcnt: | |
333 case IrOpcode::kChangeUint32ToUint64: | |
334 return true; | |
335 default: | |
336 return false; | |
337 } | |
338 return false; | |
339 #endif | |
340 } | |
341 | |
342 bool ZeroExtendsWord32ToWord64(Node* node) { | |
343 #if !V8_TARGET_ARCH_S390X | |
344 return true; | |
345 #else | |
346 switch (node->opcode()) { | |
347 case IrOpcode::kInt32Add: | |
348 case IrOpcode::kInt32Sub: | |
349 case IrOpcode::kWord32And: | |
350 case IrOpcode::kWord32Or: | |
351 case IrOpcode::kWord32Xor: | |
352 case IrOpcode::kWord32Shl: | |
353 case IrOpcode::kWord32Shr: | |
354 case IrOpcode::kWord32Sar: | |
355 case IrOpcode::kInt32Mul: | |
356 case IrOpcode::kWord32Ror: | |
357 case IrOpcode::kInt32Div: | |
358 case IrOpcode::kUint32Div: | |
359 case IrOpcode::kInt32MulHigh: | |
360 case IrOpcode::kInt32Mod: | |
361 case IrOpcode::kUint32Mod: | |
362 case IrOpcode::kWord32Popcnt: | |
363 return true; | |
364 // TODO(john.yan): consider the following case to be valid | 363 // TODO(john.yan): consider the following case to be valid |
365 // case IrOpcode::kWord32Equal: | 364 // case IrOpcode::kWord32Equal: |
366 // case IrOpcode::kInt32LessThan: | 365 // case IrOpcode::kInt32LessThan: |
367 // case IrOpcode::kInt32LessThanOrEqual: | 366 // case IrOpcode::kInt32LessThanOrEqual: |
368 // case IrOpcode::kUint32LessThan: | 367 // case IrOpcode::kUint32LessThan: |
369 // case IrOpcode::kUint32LessThanOrEqual: | 368 // case IrOpcode::kUint32LessThanOrEqual: |
370 // case IrOpcode::kUint32MulHigh: | 369 // case IrOpcode::kUint32MulHigh: |
371 // // These 32-bit operations implicitly zero-extend to 64-bit on x64, so | 370 // // These 32-bit operations implicitly zero-extend to 64-bit on x64, so |
372 // the | 371 // the |
373 // // zero-extension is a no-op. | 372 // // zero-extension is a no-op. |
(...skipping 17 matching lines...) Expand all Loading... |
391 default: | 390 default: |
392 return false; | 391 return false; |
393 } | 392 } |
394 } | 393 } |
395 default: | 394 default: |
396 return false; | 395 return false; |
397 } | 396 } |
398 #endif | 397 #endif |
399 } | 398 } |
400 | 399 |
401 void VisitRR(InstructionSelector* selector, ArchOpcode opcode, Node* node) { | 400 static inline bool DoZeroExtForResult(Node* node) { |
402 S390OperandGenerator g(selector); | 401 #if V8_TARGET_ARCH_S390X |
403 selector->Emit(opcode, g.DefineAsRegister(node), | 402 return ProduceWord32Result(node); |
404 g.UseRegister(node->InputAt(0))); | 403 #else |
| 404 return false; |
| 405 #endif |
405 } | 406 } |
406 | 407 |
407 // TODO(john.yan): Create VisiteShift to match dst = src shift (R+I) | 408 // TODO(john.yan): Create VisiteShift to match dst = src shift (R+I) |
408 #if 0 | 409 #if 0 |
409 void VisitShift() { } | 410 void VisitShift() { } |
410 #endif | 411 #endif |
411 | 412 |
412 #if V8_TARGET_ARCH_S390X | 413 #if V8_TARGET_ARCH_S390X |
413 void VisitTryTruncateDouble(InstructionSelector* selector, ArchOpcode opcode, | 414 void VisitTryTruncateDouble(InstructionSelector* selector, ArchOpcode opcode, |
414 Node* node) { | 415 Node* node) { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
496 void VisitUnaryOp(InstructionSelector* selector, Node* node, | 497 void VisitUnaryOp(InstructionSelector* selector, Node* node, |
497 InstructionCode opcode, OperandModes operand_mode, | 498 InstructionCode opcode, OperandModes operand_mode, |
498 FlagsContinuation* cont, | 499 FlagsContinuation* cont, |
499 CanCombineWithLoad canCombineWithLoad); | 500 CanCombineWithLoad canCombineWithLoad); |
500 | 501 |
501 template <class CanCombineWithLoad> | 502 template <class CanCombineWithLoad> |
502 void VisitBinOp(InstructionSelector* selector, Node* node, | 503 void VisitBinOp(InstructionSelector* selector, Node* node, |
503 InstructionCode opcode, OperandModes operand_mode, | 504 InstructionCode opcode, OperandModes operand_mode, |
504 FlagsContinuation* cont, CanCombineWithLoad canCombineWithLoad); | 505 FlagsContinuation* cont, CanCombineWithLoad canCombineWithLoad); |
505 | 506 |
506 #define VISIT_OP_LIST(V) \ | 507 // Generate The following variations: |
507 V(Word64, Unary, \ | 508 // VisitWord32UnaryOp, VisitWord32BinOp, |
508 [](ArchOpcode opcode) { return opcode == kS390_LoadWord64; }) \ | 509 // VisitWord64UnaryOp, VisitWord64BinOp, |
509 V(Word64, Bin, [](ArchOpcode opcode) { return opcode == kS390_LoadWord64; }) \ | 510 // VisitFloat32UnaryOp, VisitFloat32BinOp, |
510 V(Float32, Unary, \ | 511 // VisitFloat64UnaryOp, VisitFloat64BinOp |
511 [](ArchOpcode opcode) { return opcode == kS390_LoadFloat32; }) \ | 512 #define VISIT_OP_LIST_32(V) \ |
512 V(Float64, Unary, \ | 513 V(Word32, Unary, [](ArchOpcode opcode) { \ |
513 [](ArchOpcode opcode) { return opcode == kS390_LoadDouble; }) \ | 514 return opcode == kS390_LoadWordS32 || opcode == kS390_LoadWordU32; \ |
514 V(Float32, Bin, \ | 515 }) \ |
515 [](ArchOpcode opcode) { return opcode == kS390_LoadFloat32; }) \ | 516 V(Float32, Unary, \ |
| 517 [](ArchOpcode opcode) { return opcode == kS390_LoadFloat32; }) \ |
| 518 V(Float64, Unary, \ |
| 519 [](ArchOpcode opcode) { return opcode == kS390_LoadDouble; }) \ |
| 520 V(Word32, Bin, [](ArchOpcode opcode) { \ |
| 521 return opcode == kS390_LoadWordS32 || opcode == kS390_LoadWordU32; \ |
| 522 }) \ |
| 523 V(Float32, Bin, \ |
| 524 [](ArchOpcode opcode) { return opcode == kS390_LoadFloat32; }) \ |
516 V(Float64, Bin, [](ArchOpcode opcode) { return opcode == kS390_LoadDouble; }) | 525 V(Float64, Bin, [](ArchOpcode opcode) { return opcode == kS390_LoadDouble; }) |
517 | 526 |
| 527 #if V8_TARGET_ARCH_S390X |
| 528 #define VISIT_OP_LIST(V) \ |
| 529 VISIT_OP_LIST_32(V) \ |
| 530 V(Word64, Unary, \ |
| 531 [](ArchOpcode opcode) { return opcode == kS390_LoadWord64; }) \ |
| 532 V(Word64, Bin, [](ArchOpcode opcode) { return opcode == kS390_LoadWord64; }) |
| 533 #else |
| 534 #define VISIT_OP_LIST VISIT_OP_LIST_32 |
| 535 #endif |
| 536 |
518 #define DECLARE_VISIT_HELPER_FUNCTIONS(type1, type2, canCombineWithLoad) \ | 537 #define DECLARE_VISIT_HELPER_FUNCTIONS(type1, type2, canCombineWithLoad) \ |
519 void Visit##type1##type2##Op( \ | 538 static inline void Visit##type1##type2##Op( \ |
520 InstructionSelector* selector, Node* node, InstructionCode opcode, \ | 539 InstructionSelector* selector, Node* node, InstructionCode opcode, \ |
521 OperandModes operand_mode, FlagsContinuation* cont) { \ | 540 OperandModes operand_mode, FlagsContinuation* cont) { \ |
522 Visit##type2##Op(selector, node, opcode, operand_mode, cont, \ | 541 Visit##type2##Op(selector, node, opcode, operand_mode, cont, \ |
523 canCombineWithLoad); \ | 542 canCombineWithLoad); \ |
524 } \ | 543 } \ |
525 void Visit##type1##type2##Op(InstructionSelector* selector, Node* node, \ | 544 static inline void Visit##type1##type2##Op( \ |
526 InstructionCode opcode, \ | 545 InstructionSelector* selector, Node* node, InstructionCode opcode, \ |
527 OperandModes operand_mode) { \ | 546 OperandModes operand_mode) { \ |
528 FlagsContinuation cont; \ | 547 FlagsContinuation cont; \ |
529 Visit##type1##type2##Op(selector, node, opcode, operand_mode, &cont); \ | 548 Visit##type1##type2##Op(selector, node, opcode, operand_mode, &cont); \ |
530 } | 549 } |
531 VISIT_OP_LIST(DECLARE_VISIT_HELPER_FUNCTIONS); | 550 VISIT_OP_LIST(DECLARE_VISIT_HELPER_FUNCTIONS); |
532 #undef DECLARE_VISIT_HELPER_FUNCTIONS | 551 #undef DECLARE_VISIT_HELPER_FUNCTIONS |
| 552 #undef VISIT_OP_LIST_32 |
| 553 #undef VISIT_OP_LIST |
533 | 554 |
534 template <class CanCombineWithLoad> | 555 template <class CanCombineWithLoad> |
535 void VisitUnaryOp(InstructionSelector* selector, Node* node, | 556 void VisitUnaryOp(InstructionSelector* selector, Node* node, |
536 InstructionCode opcode, OperandModes operand_mode, | 557 InstructionCode opcode, OperandModes operand_mode, |
537 FlagsContinuation* cont, | 558 FlagsContinuation* cont, |
538 CanCombineWithLoad canCombineWithLoad) { | 559 CanCombineWithLoad canCombineWithLoad) { |
539 // Just to get rid of unused function warning | |
540 #define USE_VISITOR(type1, type2, canCombineWithLoad) \ | |
541 { \ | |
542 VisiterType dummy = Visit##type1##type2##Op; \ | |
543 USE(dummy); \ | |
544 } | |
545 typedef void (*VisiterType)(InstructionSelector * selector, Node * node, | |
546 InstructionCode opcode, | |
547 OperandModes operand_mode); | |
548 VISIT_OP_LIST(USE_VISITOR); | |
549 #undef USE_VISITOR | |
550 | |
551 S390OperandGenerator g(selector); | 560 S390OperandGenerator g(selector); |
552 InstructionOperand inputs[8]; | 561 InstructionOperand inputs[8]; |
553 size_t input_count = 0; | 562 size_t input_count = 0; |
554 InstructionOperand outputs[2]; | 563 InstructionOperand outputs[2]; |
555 size_t output_count = 0; | 564 size_t output_count = 0; |
556 Node* input = node->InputAt(0); | 565 Node* input = node->InputAt(0); |
557 | 566 |
558 GenerateRightOperands(selector, node, input, opcode, operand_mode, inputs, | 567 GenerateRightOperands(selector, node, input, opcode, operand_mode, inputs, |
559 input_count, canCombineWithLoad); | 568 input_count, canCombineWithLoad); |
560 | 569 |
| 570 bool input_is_word32 = ProduceWord32Result(input); |
| 571 |
| 572 bool doZeroExt = DoZeroExtForResult(node); |
| 573 bool canEliminateZeroExt = input_is_word32; |
| 574 |
| 575 if (doZeroExt) { |
| 576 // Add zero-ext indication |
| 577 inputs[input_count++] = g.TempImmediate(!canEliminateZeroExt); |
| 578 } |
| 579 |
561 if (cont->IsBranch()) { | 580 if (cont->IsBranch()) { |
562 inputs[input_count++] = g.Label(cont->true_block()); | 581 inputs[input_count++] = g.Label(cont->true_block()); |
563 inputs[input_count++] = g.Label(cont->false_block()); | 582 inputs[input_count++] = g.Label(cont->false_block()); |
564 } | 583 } |
565 | 584 |
566 if (!cont->IsDeoptimize()) { | 585 if (!cont->IsDeoptimize()) { |
567 // If we can deoptimize as a result of the binop, we need to make sure | 586 // If we can deoptimize as a result of the binop, we need to make sure |
568 // that the deopt inputs are not overwritten by the binop result. One way | 587 // that the deopt inputs are not overwritten by the binop result. One way |
569 // to achieve that is to declare the output register as same-as-first. | 588 // to achieve that is to declare the output register as same-as-first. |
570 outputs[output_count++] = g.DefineAsRegister(node); | 589 if (doZeroExt && canEliminateZeroExt) { |
| 590 // we have to make sure result and left use the same register |
| 591 outputs[output_count++] = g.DefineSameAsFirst(node); |
| 592 } else { |
| 593 outputs[output_count++] = g.DefineAsRegister(node); |
| 594 } |
571 } else { | 595 } else { |
572 outputs[output_count++] = g.DefineSameAsFirst(node); | 596 outputs[output_count++] = g.DefineSameAsFirst(node); |
573 } | 597 } |
574 | 598 |
575 if (cont->IsSet()) { | 599 if (cont->IsSet()) { |
576 outputs[output_count++] = g.DefineAsRegister(cont->result()); | 600 outputs[output_count++] = g.DefineAsRegister(cont->result()); |
577 } | 601 } |
578 | 602 |
579 DCHECK_NE(0u, input_count); | 603 DCHECK_NE(0u, input_count); |
580 DCHECK_NE(0u, output_count); | 604 DCHECK_NE(0u, output_count); |
(...skipping 29 matching lines...) Expand all Loading... |
610 | 634 |
611 if (node->op()->HasProperty(Operator::kCommutative) && | 635 if (node->op()->HasProperty(Operator::kCommutative) && |
612 !g.CanBeImmediate(right, operand_mode) && | 636 !g.CanBeImmediate(right, operand_mode) && |
613 (g.CanBeBetterLeftOperand(right))) { | 637 (g.CanBeBetterLeftOperand(right))) { |
614 std::swap(left, right); | 638 std::swap(left, right); |
615 } | 639 } |
616 | 640 |
617 GenerateBinOpOperands(selector, node, left, right, opcode, operand_mode, | 641 GenerateBinOpOperands(selector, node, left, right, opcode, operand_mode, |
618 inputs, input_count, canCombineWithLoad); | 642 inputs, input_count, canCombineWithLoad); |
619 | 643 |
| 644 bool left_is_word32 = ProduceWord32Result(left); |
| 645 |
| 646 bool doZeroExt = DoZeroExtForResult(node); |
| 647 bool canEliminateZeroExt = left_is_word32; |
| 648 |
| 649 if (doZeroExt) { |
| 650 // Add zero-ext indication |
| 651 inputs[input_count++] = g.TempImmediate(!canEliminateZeroExt); |
| 652 } |
| 653 |
620 if (cont->IsBranch()) { | 654 if (cont->IsBranch()) { |
621 inputs[input_count++] = g.Label(cont->true_block()); | 655 inputs[input_count++] = g.Label(cont->true_block()); |
622 inputs[input_count++] = g.Label(cont->false_block()); | 656 inputs[input_count++] = g.Label(cont->false_block()); |
623 } | 657 } |
624 | 658 |
625 if ((operand_mode & OperandMode::kAllowDistinctOps) && | 659 if ((operand_mode & OperandMode::kAllowDistinctOps) && |
626 // If we can deoptimize as a result of the binop, we need to make sure | 660 // If we can deoptimize as a result of the binop, we need to make sure |
627 // that the deopt inputs are not overwritten by the binop result. One way | 661 // that the deopt inputs are not overwritten by the binop result. One way |
628 // to achieve that is to declare the output register as same-as-first. | 662 // to achieve that is to declare the output register as same-as-first. |
629 !cont->IsDeoptimize()) { | 663 !cont->IsDeoptimize()) { |
630 outputs[output_count++] = g.DefineAsRegister(node); | 664 if (doZeroExt && canEliminateZeroExt) { |
| 665 // we have to make sure result and left use the same register |
| 666 outputs[output_count++] = g.DefineSameAsFirst(node); |
| 667 } else { |
| 668 outputs[output_count++] = g.DefineAsRegister(node); |
| 669 } |
631 } else { | 670 } else { |
632 outputs[output_count++] = g.DefineSameAsFirst(node); | 671 outputs[output_count++] = g.DefineSameAsFirst(node); |
633 } | 672 } |
634 | |
635 if (cont->IsSet()) { | |
636 outputs[output_count++] = g.DefineAsRegister(cont->result()); | |
637 } | |
638 | |
639 DCHECK_NE(0u, input_count); | |
640 DCHECK_NE(0u, output_count); | |
641 DCHECK_GE(arraysize(inputs), input_count); | |
642 DCHECK_GE(arraysize(outputs), output_count); | |
643 | |
644 opcode = cont->Encode(opcode); | |
645 | |
646 if (cont->IsDeoptimize()) { | |
647 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs, | |
648 cont->kind(), cont->reason(), cont->frame_state()); | |
649 } else if (cont->IsTrap()) { | |
650 inputs[input_count++] = g.UseImmediate(cont->trap_id()); | |
651 selector->Emit(opcode, output_count, outputs, input_count, inputs); | |
652 } else { | |
653 selector->Emit(opcode, output_count, outputs, input_count, inputs); | |
654 } | |
655 } | |
656 | |
657 void VisitBin32op(InstructionSelector* selector, Node* node, | |
658 InstructionCode opcode, OperandModes operand_mode, | |
659 FlagsContinuation* cont) { | |
660 S390OperandGenerator g(selector); | |
661 Int32BinopMatcher m(node); | |
662 Node* left = m.left().node(); | |
663 Node* right = m.right().node(); | |
664 InstructionOperand inputs[8]; | |
665 size_t input_count = 0; | |
666 InstructionOperand outputs[2]; | |
667 size_t output_count = 0; | |
668 | |
669 // match left of TruncateInt64ToInt32 | |
670 if (m.left().IsTruncateInt64ToInt32() && selector->CanCover(node, left)) { | |
671 left = left->InputAt(0); | |
672 } | |
673 // match right of TruncateInt64ToInt32 | |
674 if (m.right().IsTruncateInt64ToInt32() && selector->CanCover(node, right)) { | |
675 right = right->InputAt(0); | |
676 } | |
677 | |
678 #if V8_TARGET_ARCH_S390X | |
679 if ((ZeroExtendsWord32ToWord64(right) || g.CanBeBetterLeftOperand(right)) && | |
680 node->op()->HasProperty(Operator::kCommutative) && | |
681 !g.CanBeImmediate(right, operand_mode)) { | |
682 std::swap(left, right); | |
683 } | |
684 #else | |
685 if (node->op()->HasProperty(Operator::kCommutative) && | |
686 !g.CanBeImmediate(right, operand_mode) && | |
687 (g.CanBeBetterLeftOperand(right))) { | |
688 std::swap(left, right); | |
689 } | |
690 #endif | |
691 | |
692 GenerateBinOpOperands(selector, node, left, right, opcode, operand_mode, | |
693 inputs, input_count, [](ArchOpcode opcode) { | |
694 return opcode == kS390_LoadWordU32 || | |
695 opcode == kS390_LoadWordS32; | |
696 }); | |
697 | |
698 bool doZeroExt = | |
699 AutoZeroExtendsWord32ToWord64(node) || !ZeroExtendsWord32ToWord64(left); | |
700 | |
701 inputs[input_count++] = | |
702 g.TempImmediate(doZeroExt && (!AutoZeroExtendsWord32ToWord64(node))); | |
703 | |
704 if (cont->IsBranch()) { | |
705 inputs[input_count++] = g.Label(cont->true_block()); | |
706 inputs[input_count++] = g.Label(cont->false_block()); | |
707 } | |
708 | |
709 if (doZeroExt && (operand_mode & OperandMode::kAllowDistinctOps) && | |
710 // If we can deoptimize as a result of the binop, we need to make sure | |
711 // that | |
712 // the deopt inputs are not overwritten by the binop result. One way | |
713 // to achieve that is to declare the output register as same-as-first. | |
714 !cont->IsDeoptimize()) { | |
715 outputs[output_count++] = g.DefineAsRegister(node); | |
716 } else { | |
717 outputs[output_count++] = g.DefineSameAsFirst(node); | |
718 } | |
719 | 673 |
720 if (cont->IsSet()) { | 674 if (cont->IsSet()) { |
721 outputs[output_count++] = g.DefineAsRegister(cont->result()); | 675 outputs[output_count++] = g.DefineAsRegister(cont->result()); |
722 } | 676 } |
723 | 677 |
724 DCHECK_NE(0u, input_count); | 678 DCHECK_NE(0u, input_count); |
725 DCHECK_NE(0u, output_count); | 679 DCHECK_NE(0u, output_count); |
726 DCHECK_GE(arraysize(inputs), input_count); | 680 DCHECK_GE(arraysize(inputs), input_count); |
727 DCHECK_GE(arraysize(outputs), output_count); | 681 DCHECK_GE(arraysize(outputs), output_count); |
728 | 682 |
729 opcode = cont->Encode(opcode); | 683 opcode = cont->Encode(opcode); |
730 | 684 |
731 if (cont->IsDeoptimize()) { | 685 if (cont->IsDeoptimize()) { |
732 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs, | 686 selector->EmitDeoptimize(opcode, output_count, outputs, input_count, inputs, |
733 cont->kind(), cont->reason(), cont->frame_state()); | 687 cont->kind(), cont->reason(), cont->frame_state()); |
734 } else if (cont->IsTrap()) { | 688 } else if (cont->IsTrap()) { |
735 inputs[input_count++] = g.UseImmediate(cont->trap_id()); | 689 inputs[input_count++] = g.UseImmediate(cont->trap_id()); |
736 selector->Emit(opcode, output_count, outputs, input_count, inputs); | 690 selector->Emit(opcode, output_count, outputs, input_count, inputs); |
737 } else { | 691 } else { |
738 selector->Emit(opcode, output_count, outputs, input_count, inputs); | 692 selector->Emit(opcode, output_count, outputs, input_count, inputs); |
739 } | 693 } |
740 } | 694 } |
741 | 695 |
742 void VisitBin32op(InstructionSelector* selector, Node* node, ArchOpcode opcode, | |
743 OperandModes operand_mode) { | |
744 FlagsContinuation cont; | |
745 VisitBin32op(selector, node, opcode, operand_mode, &cont); | |
746 } | |
747 #undef VISIT_OP_LIST | |
748 | |
749 } // namespace | 696 } // namespace |
750 | 697 |
751 void InstructionSelector::VisitLoad(Node* node) { | 698 void InstructionSelector::VisitLoad(Node* node) { |
752 S390OperandGenerator g(this); | 699 S390OperandGenerator g(this); |
753 ArchOpcode opcode = SelectLoadOpcode(node); | 700 ArchOpcode opcode = SelectLoadOpcode(node); |
754 InstructionOperand outputs[1]; | 701 InstructionOperand outputs[1]; |
755 outputs[0] = g.DefineAsRegister(node); | 702 outputs[0] = g.DefineAsRegister(node); |
756 InstructionOperand inputs[3]; | 703 InstructionOperand inputs[3]; |
757 size_t input_count = 0; | 704 size_t input_count = 0; |
758 AddressingMode mode = | 705 AddressingMode mode = |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1006 int mask_msb = base::bits::CountLeadingZeros64(value); | 953 int mask_msb = base::bits::CountLeadingZeros64(value); |
1007 int mask_lsb = base::bits::CountTrailingZeros64(value); | 954 int mask_lsb = base::bits::CountTrailingZeros64(value); |
1008 if ((mask_width == 0) || (mask_msb + mask_width + mask_lsb != 64)) | 955 if ((mask_width == 0) || (mask_msb + mask_width + mask_lsb != 64)) |
1009 return false; | 956 return false; |
1010 *mb = mask_lsb + mask_width - 1; | 957 *mb = mask_lsb + mask_width - 1; |
1011 *me = mask_lsb; | 958 *me = mask_lsb; |
1012 return true; | 959 return true; |
1013 } | 960 } |
1014 #endif | 961 #endif |
1015 | 962 |
1016 // TODO(john.yan): use list to simplify general instructions | |
1017 #define WORD32_BIN_OP_LIST(V) \ | |
1018 /* V(name, ArchOpcode, OperandModes) */ \ | |
1019 V(Word32And, kS390_And32, And32OperandMode) \ | |
1020 V(Word32Or, kS390_Or32, Or32OperandMode) \ | |
1021 V(Word32Xor, kS390_Xor32, Xor32OperandMode) \ | |
1022 V(Word32Shl, kS390_ShiftLeft32, Shift32OperandMode) \ | |
1023 V(Word32Shr, kS390_ShiftRight32, Shift32OperandMode) | |
1024 | |
1025 #define VISITOR(name, op, mode) \ | |
1026 void InstructionSelector::Visit##name(Node* node) { \ | |
1027 VisitBin32op(this, node, op, mode); \ | |
1028 } | |
1029 WORD32_BIN_OP_LIST(VISITOR); | |
1030 #undef VISITOR | |
1031 #undef WORD32_BIN_OP_LIST | |
1032 | |
1033 #if V8_TARGET_ARCH_S390X | 963 #if V8_TARGET_ARCH_S390X |
1034 void InstructionSelector::VisitWord64And(Node* node) { | 964 void InstructionSelector::VisitWord64And(Node* node) { |
1035 S390OperandGenerator g(this); | 965 S390OperandGenerator g(this); |
1036 Int64BinopMatcher m(node); | 966 Int64BinopMatcher m(node); |
1037 int mb = 0; | 967 int mb = 0; |
1038 int me = 0; | 968 int me = 0; |
1039 if (m.right().HasValue() && IsContiguousMask64(m.right().Value(), &mb, &me)) { | 969 if (m.right().HasValue() && IsContiguousMask64(m.right().Value(), &mb, &me)) { |
1040 int sh = 0; | 970 int sh = 0; |
1041 Node* left = m.left().node(); | 971 Node* left = m.left().node(); |
1042 if ((m.left().IsWord64Shr() || m.left().IsWord64Shl()) && | 972 if ((m.left().IsWord64Shr() || m.left().IsWord64Shl()) && |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1075 if (match && CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) { | 1005 if (match && CpuFeatures::IsSupported(GENERAL_INSTR_EXT)) { |
1076 Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left), | 1006 Emit(opcode, g.DefineAsRegister(node), g.UseRegister(left), |
1077 g.TempImmediate(sh), g.TempImmediate(mask)); | 1007 g.TempImmediate(sh), g.TempImmediate(mask)); |
1078 return; | 1008 return; |
1079 } | 1009 } |
1080 } | 1010 } |
1081 } | 1011 } |
1082 VisitWord64BinOp(this, node, kS390_And64, And64OperandMode); | 1012 VisitWord64BinOp(this, node, kS390_And64, And64OperandMode); |
1083 } | 1013 } |
1084 | 1014 |
1085 void InstructionSelector::VisitWord64Or(Node* node) { | |
1086 VisitWord64BinOp(this, node, kS390_Or64, Or64OperandMode); | |
1087 } | |
1088 | |
1089 void InstructionSelector::VisitWord64Xor(Node* node) { | |
1090 VisitWord64BinOp(this, node, kS390_Xor64, Xor64OperandMode); | |
1091 } | |
1092 | |
1093 void InstructionSelector::VisitWord64Shl(Node* node) { | 1015 void InstructionSelector::VisitWord64Shl(Node* node) { |
1094 S390OperandGenerator g(this); | 1016 S390OperandGenerator g(this); |
1095 Int64BinopMatcher m(node); | 1017 Int64BinopMatcher m(node); |
1096 // TODO(mbrandy): eliminate left sign extension if right >= 32 | 1018 // TODO(mbrandy): eliminate left sign extension if right >= 32 |
1097 if (m.left().IsWord64And() && m.right().IsInRange(0, 63)) { | 1019 if (m.left().IsWord64And() && m.right().IsInRange(0, 63)) { |
1098 Int64BinopMatcher mleft(m.left().node()); | 1020 Int64BinopMatcher mleft(m.left().node()); |
1099 int sh = m.right().Value(); | 1021 int sh = m.right().Value(); |
1100 int mb; | 1022 int mb; |
1101 int me; | 1023 int me; |
1102 if (mleft.right().HasValue() && | 1024 if (mleft.right().HasValue() && |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1164 g.TempImmediate(mask)); | 1086 g.TempImmediate(mask)); |
1165 return; | 1087 return; |
1166 } | 1088 } |
1167 } | 1089 } |
1168 } | 1090 } |
1169 } | 1091 } |
1170 VisitWord64BinOp(this, node, kS390_ShiftRight64, Shift64OperandMode); | 1092 VisitWord64BinOp(this, node, kS390_ShiftRight64, Shift64OperandMode); |
1171 } | 1093 } |
1172 #endif | 1094 #endif |
1173 | 1095 |
1174 void InstructionSelector::VisitWord32Sar(Node* node) { | 1096 static inline bool TryMatchSignExtInt16OrInt8FromWord32Sar( |
1175 S390OperandGenerator g(this); | 1097 InstructionSelector* selector, Node* node) { |
| 1098 S390OperandGenerator g(selector); |
1176 Int32BinopMatcher m(node); | 1099 Int32BinopMatcher m(node); |
1177 // Replace with sign extension for (x << K) >> K where K is 16 or 24. | 1100 if (selector->CanCover(node, m.left().node()) && m.left().IsWord32Shl()) { |
1178 if (CanCover(node, m.left().node()) && m.left().IsWord32Shl()) { | |
1179 Int32BinopMatcher mleft(m.left().node()); | 1101 Int32BinopMatcher mleft(m.left().node()); |
1180 if (mleft.right().Is(16) && m.right().Is(16)) { | 1102 if (mleft.right().Is(16) && m.right().Is(16)) { |
1181 bool doZeroExt = !ZeroExtendsWord32ToWord64(mleft.left().node()); | 1103 bool canEliminateZeroExt = ProduceWord32Result(mleft.left().node()); |
1182 Emit(kS390_ExtendSignWord16, | 1104 selector->Emit(kS390_ExtendSignWord16, |
1183 doZeroExt ? g.DefineAsRegister(node) : g.DefineSameAsFirst(node), | 1105 canEliminateZeroExt ? g.DefineSameAsFirst(node) |
1184 g.UseRegister(mleft.left().node()), g.TempImmediate(doZeroExt)); | 1106 : g.DefineAsRegister(node), |
1185 return; | 1107 g.UseRegister(mleft.left().node()), |
| 1108 g.TempImmediate(!canEliminateZeroExt)); |
| 1109 return true; |
1186 } else if (mleft.right().Is(24) && m.right().Is(24)) { | 1110 } else if (mleft.right().Is(24) && m.right().Is(24)) { |
1187 bool doZeroExt = !ZeroExtendsWord32ToWord64(mleft.left().node()); | 1111 bool canEliminateZeroExt = ProduceWord32Result(mleft.left().node()); |
1188 Emit(kS390_ExtendSignWord8, | 1112 selector->Emit(kS390_ExtendSignWord8, |
1189 doZeroExt ? g.DefineAsRegister(node) : g.DefineSameAsFirst(node), | 1113 canEliminateZeroExt ? g.DefineSameAsFirst(node) |
1190 g.UseRegister(mleft.left().node()), g.TempImmediate(doZeroExt)); | 1114 : g.DefineAsRegister(node), |
1191 return; | 1115 g.UseRegister(mleft.left().node()), |
| 1116 g.TempImmediate(!canEliminateZeroExt)); |
| 1117 return true; |
1192 } | 1118 } |
1193 } | 1119 } |
1194 VisitBin32op(this, node, kS390_ShiftRightArith32, Shift32OperandMode); | 1120 return false; |
1195 } | 1121 } |
1196 | 1122 |
1197 #if !V8_TARGET_ARCH_S390X | 1123 #if !V8_TARGET_ARCH_S390X |
1198 void VisitPairBinop(InstructionSelector* selector, InstructionCode opcode, | 1124 void VisitPairBinop(InstructionSelector* selector, InstructionCode opcode, |
1199 InstructionCode opcode2, Node* node) { | 1125 InstructionCode opcode2, Node* node) { |
1200 S390OperandGenerator g(selector); | 1126 S390OperandGenerator g(selector); |
1201 | 1127 |
1202 Node* projection1 = NodeProperties::FindProjection(node, 1); | 1128 Node* projection1 = NodeProperties::FindProjection(node, 1); |
1203 if (projection1) { | 1129 if (projection1) { |
1204 // We use UseUniqueRegister here to avoid register sharing with the output | 1130 // We use UseUniqueRegister here to avoid register sharing with the output |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1295 | 1221 |
1296 void InstructionSelector::VisitWord32PairShr(Node* node) { | 1222 void InstructionSelector::VisitWord32PairShr(Node* node) { |
1297 VisitPairShift(this, kS390_ShiftRightPair, node); | 1223 VisitPairShift(this, kS390_ShiftRightPair, node); |
1298 } | 1224 } |
1299 | 1225 |
1300 void InstructionSelector::VisitWord32PairSar(Node* node) { | 1226 void InstructionSelector::VisitWord32PairSar(Node* node) { |
1301 VisitPairShift(this, kS390_ShiftRightArithPair, node); | 1227 VisitPairShift(this, kS390_ShiftRightArithPair, node); |
1302 } | 1228 } |
1303 #endif | 1229 #endif |
1304 | 1230 |
1305 #if V8_TARGET_ARCH_S390X | |
1306 void InstructionSelector::VisitWord64Sar(Node* node) { | |
1307 VisitWord64BinOp(this, node, kS390_ShiftRightArith64, Shift64OperandMode); | |
1308 } | |
1309 #endif | |
1310 | |
1311 void InstructionSelector::VisitWord32Ror(Node* node) { | |
1312 // TODO(john): match dst = ror(src1, src2 + imm) | |
1313 VisitBin32op(this, node, kS390_RotRight32, | |
1314 OperandMode::kAllowRI | OperandMode::kAllowRRR | | |
1315 OperandMode::kAllowRRI | OperandMode::kShift32Imm); | |
1316 } | |
1317 | |
1318 #if V8_TARGET_ARCH_S390X | |
1319 void InstructionSelector::VisitWord64Ror(Node* node) { | |
1320 VisitWord64BinOp(this, node, kS390_RotRight64, Shift64OperandMode); | |
1321 } | |
1322 #endif | |
1323 | |
1324 void InstructionSelector::VisitWord32Clz(Node* node) { | |
1325 VisitRR(this, kS390_Cntlz32, node); | |
1326 } | |
1327 | |
1328 #if V8_TARGET_ARCH_S390X | |
1329 void InstructionSelector::VisitWord64Clz(Node* node) { | |
1330 S390OperandGenerator g(this); | |
1331 Emit(kS390_Cntlz64, g.DefineAsRegister(node), | |
1332 g.UseRegister(node->InputAt(0))); | |
1333 } | |
1334 #endif | |
1335 | |
1336 void InstructionSelector::VisitWord32Popcnt(Node* node) { | |
1337 S390OperandGenerator g(this); | |
1338 Node* value = node->InputAt(0); | |
1339 Emit(kS390_Popcnt32, g.DefineAsRegister(node), g.UseRegister(value)); | |
1340 } | |
1341 | |
1342 #if V8_TARGET_ARCH_S390X | |
1343 void InstructionSelector::VisitWord64Popcnt(Node* node) { | |
1344 S390OperandGenerator g(this); | |
1345 Emit(kS390_Popcnt64, g.DefineAsRegister(node), | |
1346 g.UseRegister(node->InputAt(0))); | |
1347 } | |
1348 #endif | |
1349 | |
1350 void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } | 1231 void InstructionSelector::VisitWord32Ctz(Node* node) { UNREACHABLE(); } |
1351 | 1232 |
1352 #if V8_TARGET_ARCH_S390X | 1233 #if V8_TARGET_ARCH_S390X |
1353 void InstructionSelector::VisitWord64Ctz(Node* node) { UNREACHABLE(); } | 1234 void InstructionSelector::VisitWord64Ctz(Node* node) { UNREACHABLE(); } |
1354 #endif | 1235 #endif |
1355 | 1236 |
1356 void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); } | 1237 void InstructionSelector::VisitWord32ReverseBits(Node* node) { UNREACHABLE(); } |
1357 | 1238 |
1358 #if V8_TARGET_ARCH_S390X | 1239 #if V8_TARGET_ARCH_S390X |
1359 void InstructionSelector::VisitWord64ReverseBits(Node* node) { UNREACHABLE(); } | 1240 void InstructionSelector::VisitWord64ReverseBits(Node* node) { UNREACHABLE(); } |
(...skipping 17 matching lines...) Expand all Loading... |
1377 // TODO(john.yan): one of the base and offset can be imm. | 1258 // TODO(john.yan): one of the base and offset can be imm. |
1378 g.DefineAsRegister(node), g.UseRegister(base), | 1259 g.DefineAsRegister(node), g.UseRegister(base), |
1379 g.UseRegister(offset)); | 1260 g.UseRegister(offset)); |
1380 return; | 1261 return; |
1381 } | 1262 } |
1382 } | 1263 } |
1383 Emit(kS390_LoadReverse32RR, g.DefineAsRegister(node), | 1264 Emit(kS390_LoadReverse32RR, g.DefineAsRegister(node), |
1384 g.UseRegister(node->InputAt(0))); | 1265 g.UseRegister(node->InputAt(0))); |
1385 } | 1266 } |
1386 | 1267 |
1387 void InstructionSelector::VisitInt32Add(Node* node) { | 1268 template <class Matcher, ArchOpcode neg_opcode> |
1388 VisitBin32op(this, node, kS390_Add32, AddOperandMode); | 1269 static inline bool TryMatchNegFromSub(InstructionSelector* selector, |
1389 } | 1270 Node* node) { |
1390 | 1271 S390OperandGenerator g(selector); |
1391 #if V8_TARGET_ARCH_S390X | 1272 Matcher m(node); |
1392 void InstructionSelector::VisitInt64Add(Node* node) { | 1273 static_assert(neg_opcode == kS390_Neg32 || neg_opcode == kS390_Neg64, |
1393 VisitWord64BinOp(this, node, kS390_Add64, AddOperandMode); | 1274 "Provided opcode is not a Neg opcode."); |
1394 } | |
1395 #endif | |
1396 | |
1397 void InstructionSelector::VisitInt32Sub(Node* node) { | |
1398 S390OperandGenerator g(this); | |
1399 Int32BinopMatcher m(node); | |
1400 if (m.left().Is(0)) { | 1275 if (m.left().Is(0)) { |
1401 Node* right = m.right().node(); | 1276 Node* value = m.right().node(); |
1402 bool doZeroExt = ZeroExtendsWord32ToWord64(right); | 1277 bool doZeroExt = DoZeroExtForResult(node); |
1403 Emit(kS390_Neg32, g.DefineAsRegister(node), g.UseRegister(right), | 1278 bool canEliminateZeroExt = ProduceWord32Result(value); |
1404 g.TempImmediate(doZeroExt)); | 1279 if (doZeroExt) { |
1405 } else { | 1280 selector->Emit(neg_opcode, |
1406 VisitBin32op(this, node, kS390_Sub32, SubOperandMode); | 1281 canEliminateZeroExt ? g.DefineSameAsFirst(node) |
1407 } | 1282 : g.DefineAsRegister(node), |
1408 } | 1283 g.UseRegister(value), |
1409 | 1284 g.TempImmediate(!canEliminateZeroExt)); |
1410 #if V8_TARGET_ARCH_S390X | 1285 } else { |
1411 void InstructionSelector::VisitInt64Sub(Node* node) { | 1286 selector->Emit(neg_opcode, g.DefineAsRegister(node), |
1412 S390OperandGenerator g(this); | 1287 g.UseRegister(value)); |
1413 Int64BinopMatcher m(node); | 1288 } |
1414 if (m.left().Is(0)) { | 1289 return true; |
1415 Emit(kS390_Neg64, g.DefineAsRegister(node), | 1290 } |
1416 g.UseRegister(m.right().node())); | 1291 return false; |
1417 } else { | 1292 } |
1418 VisitWord64BinOp(this, node, kS390_Sub64, SubOperandMode); | 1293 |
1419 } | 1294 template <class Matcher, ArchOpcode shift_op> |
1420 } | 1295 bool TryMatchShiftFromMul(InstructionSelector* selector, Node* node) { |
1421 #endif | 1296 S390OperandGenerator g(selector); |
1422 | 1297 Matcher m(node); |
1423 void InstructionSelector::VisitInt32MulWithOverflow(Node* node) { | |
1424 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { | |
1425 FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf); | |
1426 return VisitBin32op(this, node, kS390_Mul32WithOverflow, | |
1427 OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps, | |
1428 &cont); | |
1429 } | |
1430 VisitBin32op(this, node, kS390_Mul32, MulOperandMode); | |
1431 } | |
1432 | |
1433 void InstructionSelector::VisitInt32Mul(Node* node) { | |
1434 S390OperandGenerator g(this); | |
1435 Int32BinopMatcher m(node); | |
1436 Node* left = m.left().node(); | |
1437 Node* right = m.right().node(); | |
1438 if (g.CanBeImmediate(right, OperandMode::kInt32Imm) && | |
1439 base::bits::IsPowerOfTwo32(g.GetImmediate(right))) { | |
1440 int power = 31 - base::bits::CountLeadingZeros32(g.GetImmediate(right)); | |
1441 bool doZeroExt = !ZeroExtendsWord32ToWord64(left); | |
1442 InstructionOperand dst = | |
1443 (doZeroExt && CpuFeatures::IsSupported(DISTINCT_OPS)) | |
1444 ? g.DefineAsRegister(node) | |
1445 : g.DefineSameAsFirst(node); | |
1446 | |
1447 Emit(kS390_ShiftLeft32, dst, g.UseRegister(left), g.UseImmediate(power), | |
1448 g.TempImmediate(doZeroExt)); | |
1449 return; | |
1450 } | |
1451 VisitBin32op(this, node, kS390_Mul32, MulOperandMode); | |
1452 } | |
1453 | |
1454 #if V8_TARGET_ARCH_S390X | |
1455 void InstructionSelector::VisitInt64Mul(Node* node) { | |
1456 S390OperandGenerator g(this); | |
1457 Int64BinopMatcher m(node); | |
1458 Node* left = m.left().node(); | 1298 Node* left = m.left().node(); |
1459 Node* right = m.right().node(); | 1299 Node* right = m.right().node(); |
1460 if (g.CanBeImmediate(right, OperandMode::kInt32Imm) && | 1300 if (g.CanBeImmediate(right, OperandMode::kInt32Imm) && |
1461 base::bits::IsPowerOfTwo64(g.GetImmediate(right))) { | 1301 base::bits::IsPowerOfTwo64(g.GetImmediate(right))) { |
1462 int power = 63 - base::bits::CountLeadingZeros64(g.GetImmediate(right)); | 1302 int power = 63 - base::bits::CountLeadingZeros64(g.GetImmediate(right)); |
1463 Emit(kS390_ShiftLeft64, g.DefineSameAsFirst(node), g.UseRegister(left), | 1303 bool doZeroExt = DoZeroExtForResult(node); |
1464 g.UseImmediate(power)); | 1304 bool canEliminateZeroExt = ProduceWord32Result(left); |
1465 return; | 1305 InstructionOperand dst = (doZeroExt && !canEliminateZeroExt && |
1466 } | 1306 CpuFeatures::IsSupported(DISTINCT_OPS)) |
1467 VisitWord64BinOp(this, node, kS390_Mul64, MulOperandMode); | 1307 ? g.DefineAsRegister(node) |
| 1308 : g.DefineSameAsFirst(node); |
| 1309 |
| 1310 if (doZeroExt) { |
| 1311 selector->Emit(shift_op, dst, g.UseRegister(left), g.UseImmediate(power), |
| 1312 g.TempImmediate(!canEliminateZeroExt)); |
| 1313 } else { |
| 1314 selector->Emit(shift_op, dst, g.UseRegister(left), g.UseImmediate(power)); |
| 1315 } |
| 1316 return true; |
| 1317 } |
| 1318 return false; |
| 1319 } |
| 1320 |
| 1321 template <ArchOpcode opcode> |
| 1322 static inline bool TryMatchInt32OpWithOverflow(InstructionSelector* selector, |
| 1323 Node* node, OperandModes mode) { |
| 1324 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
| 1325 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); |
| 1326 VisitWord32BinOp(selector, node, opcode, mode, &cont); |
| 1327 return true; |
| 1328 } |
| 1329 return false; |
| 1330 } |
| 1331 |
| 1332 static inline bool TryMatchInt32AddWithOverflow(InstructionSelector* selector, |
| 1333 Node* node) { |
| 1334 return TryMatchInt32OpWithOverflow<kS390_Add32>(selector, node, |
| 1335 AddOperandMode); |
| 1336 } |
| 1337 |
| 1338 static inline bool TryMatchInt32SubWithOverflow(InstructionSelector* selector, |
| 1339 Node* node) { |
| 1340 return TryMatchInt32OpWithOverflow<kS390_Sub32>(selector, node, |
| 1341 SubOperandMode); |
| 1342 } |
| 1343 |
| 1344 static inline bool TryMatchInt32MulWithOverflow(InstructionSelector* selector, |
| 1345 Node* node) { |
| 1346 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
| 1347 FlagsContinuation cont = FlagsContinuation::ForSet(kNotEqual, ovf); |
| 1348 VisitWord32BinOp(selector, node, kS390_Mul32WithOverflow, |
| 1349 OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps, |
| 1350 &cont); |
| 1351 return true; |
| 1352 } |
| 1353 return TryMatchShiftFromMul<Int32BinopMatcher, kS390_ShiftLeft32>(selector, |
| 1354 node); |
| 1355 } |
| 1356 |
| 1357 #if V8_TARGET_ARCH_S390X |
| 1358 template <ArchOpcode opcode> |
| 1359 static inline bool TryMatchInt64OpWithOverflow(InstructionSelector* selector, |
| 1360 Node* node, OperandModes mode) { |
| 1361 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { |
| 1362 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); |
| 1363 VisitWord64BinOp(selector, node, opcode, mode, &cont); |
| 1364 return true; |
| 1365 } |
| 1366 return false; |
| 1367 } |
| 1368 |
| 1369 static inline bool TryMatchInt64AddWithOverflow(InstructionSelector* selector, |
| 1370 Node* node) { |
| 1371 return TryMatchInt64OpWithOverflow<kS390_Add64>(selector, node, |
| 1372 AddOperandMode); |
| 1373 } |
| 1374 |
| 1375 static inline bool TryMatchInt64SubWithOverflow(InstructionSelector* selector, |
| 1376 Node* node) { |
| 1377 return TryMatchInt64OpWithOverflow<kS390_Sub64>(selector, node, |
| 1378 SubOperandMode); |
1468 } | 1379 } |
1469 #endif | 1380 #endif |
1470 | 1381 |
1471 void InstructionSelector::VisitInt32MulHigh(Node* node) { | 1382 #define null ([]() { return false; }) |
1472 VisitBin32op(this, node, kS390_MulHigh32, | 1383 // TODO(john.yan): place kAllowRM where available |
1473 OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps); | 1384 #define FLOAT_UNARY_OP_LIST_32(V) \ |
1474 } | 1385 V(Float32, ChangeFloat32ToFloat64, kS390_Float32ToDouble, \ |
1475 | 1386 OperandMode::kAllowRM, null) \ |
1476 void InstructionSelector::VisitUint32MulHigh(Node* node) { | 1387 V(Float32, BitcastFloat32ToInt32, kS390_BitcastFloat32ToInt32, \ |
1477 VisitBin32op(this, node, kS390_MulHighU32, | 1388 OperandMode::kNone, null) \ |
1478 OperandMode::kAllowRRM | OperandMode::kAllowRRR); | 1389 V(Float64, TruncateFloat64ToFloat32, kS390_DoubleToFloat32, \ |
1479 } | 1390 OperandMode::kNone, null) \ |
1480 | 1391 V(Float64, TruncateFloat64ToWord32, kArchTruncateDoubleToI, \ |
1481 void InstructionSelector::VisitInt32Div(Node* node) { | 1392 OperandMode::kNone, null) \ |
1482 VisitBin32op(this, node, kS390_Div32, | 1393 V(Float64, RoundFloat64ToInt32, kS390_DoubleToInt32, OperandMode::kNone, \ |
1483 OperandMode::kAllowRRM | OperandMode::kAllowRRR); | 1394 null) \ |
1484 } | 1395 V(Float32, TruncateFloat32ToInt32, kS390_Float32ToInt32, OperandMode::kNone, \ |
| 1396 null) \ |
| 1397 V(Float32, TruncateFloat32ToUint32, kS390_Float32ToUint32, \ |
| 1398 OperandMode::kNone, null) \ |
| 1399 V(Float64, TruncateFloat64ToUint32, kS390_DoubleToUint32, \ |
| 1400 OperandMode::kNone, null) \ |
| 1401 V(Float64, ChangeFloat64ToInt32, kS390_DoubleToInt32, OperandMode::kNone, \ |
| 1402 null) \ |
| 1403 V(Float64, ChangeFloat64ToUint32, kS390_DoubleToUint32, OperandMode::kNone, \ |
| 1404 null) \ |
| 1405 V(Float64, Float64SilenceNaN, kS390_Float64SilenceNaN, OperandMode::kNone, \ |
| 1406 null) \ |
| 1407 V(Float32, Float32Abs, kS390_AbsFloat, OperandMode::kNone, null) \ |
| 1408 V(Float64, Float64Abs, kS390_AbsDouble, OperandMode::kNone, null) \ |
| 1409 V(Float32, Float32Sqrt, kS390_SqrtFloat, OperandMode::kNone, null) \ |
| 1410 V(Float64, Float64Sqrt, kS390_SqrtDouble, OperandMode::kNone, null) \ |
| 1411 V(Float32, Float32RoundDown, kS390_FloorFloat, OperandMode::kNone, null) \ |
| 1412 V(Float64, Float64RoundDown, kS390_FloorDouble, OperandMode::kNone, null) \ |
| 1413 V(Float32, Float32RoundUp, kS390_CeilFloat, OperandMode::kNone, null) \ |
| 1414 V(Float64, Float64RoundUp, kS390_CeilDouble, OperandMode::kNone, null) \ |
| 1415 V(Float32, Float32RoundTruncate, kS390_TruncateFloat, OperandMode::kNone, \ |
| 1416 null) \ |
| 1417 V(Float64, Float64RoundTruncate, kS390_TruncateDouble, OperandMode::kNone, \ |
| 1418 null) \ |
| 1419 V(Float64, Float64RoundTiesAway, kS390_RoundDouble, OperandMode::kNone, \ |
| 1420 null) \ |
| 1421 V(Float32, Float32Neg, kS390_NegFloat, OperandMode::kNone, null) \ |
| 1422 V(Float64, Float64Neg, kS390_NegDouble, OperandMode::kNone, null) |
| 1423 |
| 1424 #define FLOAT_BIN_OP_LIST(V) \ |
| 1425 V(Float32, Float32Add, kS390_AddFloat, OperandMode::kAllowRM, null) \ |
| 1426 V(Float64, Float64Add, kS390_AddDouble, OperandMode::kAllowRM, null) \ |
| 1427 V(Float32, Float32Sub, kS390_SubFloat, OperandMode::kAllowRM, null) \ |
| 1428 V(Float64, Float64Sub, kS390_SubDouble, OperandMode::kAllowRM, null) \ |
| 1429 V(Float32, Float32Mul, kS390_MulFloat, OperandMode::kAllowRM, null) \ |
| 1430 V(Float64, Float64Mul, kS390_MulDouble, OperandMode::kAllowRM, null) \ |
| 1431 V(Float32, Float32Div, kS390_DivFloat, OperandMode::kAllowRM, null) \ |
| 1432 V(Float64, Float64Div, kS390_DivDouble, OperandMode::kAllowRM, null) \ |
| 1433 V(Float32, Float32Max, kS390_MaxFloat, OperandMode::kNone, null) \ |
| 1434 V(Float64, Float64Max, kS390_MaxDouble, OperandMode::kNone, null) \ |
| 1435 V(Float32, Float32Min, kS390_MinFloat, OperandMode::kNone, null) \ |
| 1436 V(Float64, Float64Min, kS390_MinDouble, OperandMode::kNone, null) |
| 1437 |
| 1438 #define WORD32_UNARY_OP_LIST_32(V) \ |
| 1439 V(Word32, Word32Clz, kS390_Cntlz32, OperandMode::kNone, null) \ |
| 1440 V(Word32, Word32Popcnt, kS390_Popcnt32, OperandMode::kNone, null) \ |
| 1441 V(Word32, RoundInt32ToFloat32, kS390_Int32ToFloat32, OperandMode::kNone, \ |
| 1442 null) \ |
| 1443 V(Word32, RoundUint32ToFloat32, kS390_Uint32ToFloat32, OperandMode::kNone, \ |
| 1444 null) \ |
| 1445 V(Word32, ChangeInt32ToFloat64, kS390_Int32ToDouble, OperandMode::kNone, \ |
| 1446 null) \ |
| 1447 V(Word32, ChangeUint32ToFloat64, kS390_Uint32ToDouble, OperandMode::kNone, \ |
| 1448 null) \ |
| 1449 V(Word32, BitcastInt32ToFloat32, kS390_BitcastInt32ToFloat32, \ |
| 1450 OperandMode::kNone, null) |
| 1451 |
| 1452 #ifdef V8_TARGET_ARCH_S390X |
| 1453 #define FLOAT_UNARY_OP_LIST(V) \ |
| 1454 FLOAT_UNARY_OP_LIST_32(V) \ |
| 1455 V(Float64, ChangeFloat64ToUint64, kS390_DoubleToUint64, OperandMode::kNone, \ |
| 1456 null) \ |
| 1457 V(Float64, BitcastFloat64ToInt64, kS390_BitcastDoubleToInt64, \ |
| 1458 OperandMode::kNone, null) |
| 1459 #define WORD32_UNARY_OP_LIST(V) \ |
| 1460 WORD32_UNARY_OP_LIST_32(V) \ |
| 1461 V(Word32, ChangeInt32ToInt64, kS390_ExtendSignWord32, OperandMode::kNone, \ |
| 1462 null) \ |
| 1463 V(Word32, ChangeUint32ToUint64, kS390_Uint32ToUint64, OperandMode::kNone, \ |
| 1464 [&]() -> bool { \ |
| 1465 if (ProduceWord32Result(node->InputAt(0))) { \ |
| 1466 EmitIdentity(node); \ |
| 1467 return true; \ |
| 1468 } \ |
| 1469 return false; \ |
| 1470 }) |
| 1471 |
| 1472 #else |
| 1473 #define FLOAT_UNARY_OP_LIST(V) FLOAT_UNARY_OP_LIST_32(V) |
| 1474 #define WORD32_UNARY_OP_LIST(V) WORD32_UNARY_OP_LIST_32(V) |
| 1475 #endif |
| 1476 |
| 1477 #define WORD32_BIN_OP_LIST(V) \ |
| 1478 V(Word32, Int32Add, kS390_Add32, AddOperandMode, null) \ |
| 1479 V(Word32, Int32Sub, kS390_Sub32, SubOperandMode, ([&]() { \ |
| 1480 return TryMatchNegFromSub<Int32BinopMatcher, kS390_Neg32>(this, node); \ |
| 1481 })) \ |
| 1482 V(Word32, Int32Mul, kS390_Mul32, MulOperandMode, ([&]() { \ |
| 1483 return TryMatchShiftFromMul<Int32BinopMatcher, kS390_ShiftLeft32>(this, \ |
| 1484 node); \ |
| 1485 })) \ |
| 1486 V(Word32, Int32AddWithOverflow, kS390_Add32, AddOperandMode, \ |
| 1487 ([&]() { return TryMatchInt32AddWithOverflow(this, node); })) \ |
| 1488 V(Word32, Int32SubWithOverflow, kS390_Sub32, SubOperandMode, \ |
| 1489 ([&]() { return TryMatchInt32SubWithOverflow(this, node); })) \ |
| 1490 V(Word32, Int32MulWithOverflow, kS390_Mul32, MulOperandMode, \ |
| 1491 ([&]() { return TryMatchInt32MulWithOverflow(this, node); })) \ |
| 1492 V(Word32, Int32MulHigh, kS390_MulHigh32, \ |
| 1493 OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps, null) \ |
| 1494 V(Word32, Uint32MulHigh, kS390_MulHighU32, \ |
| 1495 OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
| 1496 V(Word32, Int32Div, kS390_Div32, \ |
| 1497 OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
| 1498 V(Word32, Uint32Div, kS390_DivU32, \ |
| 1499 OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
| 1500 V(Word32, Int32Mod, kS390_Mod32, \ |
| 1501 OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
| 1502 V(Word32, Uint32Mod, kS390_ModU32, \ |
| 1503 OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
| 1504 V(Word32, Word32Ror, kS390_RotRight32, \ |
| 1505 OperandMode::kAllowRI | OperandMode::kAllowRRR | OperandMode::kAllowRRI | \ |
| 1506 OperandMode::kShift32Imm, \ |
| 1507 null) \ |
| 1508 V(Word32, Word32And, kS390_And32, And32OperandMode, null) \ |
| 1509 V(Word32, Word32Or, kS390_Or32, Or32OperandMode, null) \ |
| 1510 V(Word32, Word32Xor, kS390_Xor32, Xor32OperandMode, null) \ |
| 1511 V(Word32, Word32Shl, kS390_ShiftLeft32, Shift32OperandMode, null) \ |
| 1512 V(Word32, Word32Shr, kS390_ShiftRight32, Shift32OperandMode, null) \ |
| 1513 V(Word32, Word32Sar, kS390_ShiftRightArith32, Shift32OperandMode, \ |
| 1514 [&]() { return TryMatchSignExtInt16OrInt8FromWord32Sar(this, node); }) |
| 1515 |
| 1516 #define WORD64_UNARY_OP_LIST(V) \ |
| 1517 V(Word64, Word64Popcnt, kS390_Popcnt64, OperandMode::kNone, null) \ |
| 1518 V(Word64, Word64Clz, kS390_Cntlz64, OperandMode::kNone, null) \ |
| 1519 V(Word64, TruncateInt64ToInt32, kS390_Int64ToInt32, OperandMode::kNone, \ |
| 1520 null) \ |
| 1521 V(Word64, RoundInt64ToFloat32, kS390_Int64ToFloat32, OperandMode::kNone, \ |
| 1522 null) \ |
| 1523 V(Word64, RoundInt64ToFloat64, kS390_Int64ToDouble, OperandMode::kNone, \ |
| 1524 null) \ |
| 1525 V(Word64, RoundUint64ToFloat32, kS390_Uint64ToFloat32, OperandMode::kNone, \ |
| 1526 null) \ |
| 1527 V(Word64, RoundUint64ToFloat64, kS390_Uint64ToDouble, OperandMode::kNone, \ |
| 1528 null) \ |
| 1529 V(Word64, BitcastInt64ToFloat64, kS390_BitcastInt64ToDouble, \ |
| 1530 OperandMode::kNone, null) |
| 1531 |
| 1532 #define WORD64_BIN_OP_LIST(V) \ |
| 1533 V(Word64, Int64Add, kS390_Add64, AddOperandMode, null) \ |
| 1534 V(Word64, Int64Sub, kS390_Sub64, SubOperandMode, ([&]() { \ |
| 1535 return TryMatchNegFromSub<Int64BinopMatcher, kS390_Neg64>(this, node); \ |
| 1536 })) \ |
| 1537 V(Word64, Int64AddWithOverflow, kS390_Add64, AddOperandMode, \ |
| 1538 ([&]() { return TryMatchInt64AddWithOverflow(this, node); })) \ |
| 1539 V(Word64, Int64SubWithOverflow, kS390_Sub64, SubOperandMode, \ |
| 1540 ([&]() { return TryMatchInt64SubWithOverflow(this, node); })) \ |
| 1541 V(Word64, Int64Mul, kS390_Mul64, MulOperandMode, ([&]() { \ |
| 1542 return TryMatchShiftFromMul<Int64BinopMatcher, kS390_ShiftLeft64>(this, \ |
| 1543 node); \ |
| 1544 })) \ |
| 1545 V(Word64, Int64Div, kS390_Div64, \ |
| 1546 OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
| 1547 V(Word64, Uint64Div, kS390_DivU64, \ |
| 1548 OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
| 1549 V(Word64, Int64Mod, kS390_Mod64, \ |
| 1550 OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
| 1551 V(Word64, Uint64Mod, kS390_ModU64, \ |
| 1552 OperandMode::kAllowRRM | OperandMode::kAllowRRR, null) \ |
| 1553 V(Word64, Word64Sar, kS390_ShiftRightArith64, Shift64OperandMode, null) \ |
| 1554 V(Word64, Word64Ror, kS390_RotRight64, Shift64OperandMode, null) \ |
| 1555 V(Word64, Word64Or, kS390_Or64, Or64OperandMode, null) \ |
| 1556 V(Word64, Word64Xor, kS390_Xor64, Xor64OperandMode, null) |
| 1557 |
| 1558 #define DECLARE_UNARY_OP(type, name, op, mode, try_extra) \ |
| 1559 void InstructionSelector::Visit##name(Node* node) { \ |
| 1560 if (std::function<bool()>(try_extra)()) return; \ |
| 1561 Visit##type##UnaryOp(this, node, op, mode); \ |
| 1562 } |
| 1563 |
| 1564 #define DECLARE_BIN_OP(type, name, op, mode, try_extra) \ |
| 1565 void InstructionSelector::Visit##name(Node* node) { \ |
| 1566 if (std::function<bool()>(try_extra)()) return; \ |
| 1567 Visit##type##BinOp(this, node, op, mode); \ |
| 1568 } |
| 1569 |
| 1570 WORD32_BIN_OP_LIST(DECLARE_BIN_OP); |
| 1571 WORD32_UNARY_OP_LIST(DECLARE_UNARY_OP); |
| 1572 FLOAT_UNARY_OP_LIST(DECLARE_UNARY_OP); |
| 1573 FLOAT_BIN_OP_LIST(DECLARE_BIN_OP); |
1485 | 1574 |
1486 #if V8_TARGET_ARCH_S390X | 1575 #if V8_TARGET_ARCH_S390X |
1487 void InstructionSelector::VisitInt64Div(Node* node) { | 1576 WORD64_UNARY_OP_LIST(DECLARE_UNARY_OP) |
1488 VisitWord64BinOp(this, node, kS390_Div64, | 1577 WORD64_BIN_OP_LIST(DECLARE_BIN_OP) |
1489 OperandMode::kAllowRRM | OperandMode::kAllowRRR); | |
1490 } | |
1491 #endif | 1578 #endif |
1492 | 1579 |
1493 void InstructionSelector::VisitUint32Div(Node* node) { | 1580 #undef DECLARE_BIN_OP |
1494 VisitBin32op(this, node, kS390_DivU32, | |
1495 OperandMode::kAllowRRM | OperandMode::kAllowRRR); | |
1496 } | |
1497 | |
1498 #if V8_TARGET_ARCH_S390X | |
1499 void InstructionSelector::VisitUint64Div(Node* node) { | |
1500 VisitWord64BinOp(this, node, kS390_DivU64, | |
1501 OperandMode::kAllowRRM | OperandMode::kAllowRRR); | |
1502 } | |
1503 #endif | |
1504 | |
1505 void InstructionSelector::VisitInt32Mod(Node* node) { | |
1506 VisitBin32op(this, node, kS390_Mod32, | |
1507 OperandMode::kAllowRRM | OperandMode::kAllowRRR); | |
1508 } | |
1509 | |
1510 #if V8_TARGET_ARCH_S390X | |
1511 void InstructionSelector::VisitInt64Mod(Node* node) { | |
1512 VisitWord64BinOp(this, node, kS390_Mod64, | |
1513 OperandMode::kAllowRRM | OperandMode::kAllowRRR); | |
1514 } | |
1515 #endif | |
1516 | |
1517 void InstructionSelector::VisitUint32Mod(Node* node) { | |
1518 VisitBin32op(this, node, kS390_ModU32, | |
1519 OperandMode::kAllowRRM | OperandMode::kAllowRRR); | |
1520 } | |
1521 | |
1522 #if V8_TARGET_ARCH_S390X | |
1523 void InstructionSelector::VisitUint64Mod(Node* node) { | |
1524 VisitWord64BinOp(this, node, kS390_ModU64, | |
1525 OperandMode::kAllowRRM | OperandMode::kAllowRRR); | |
1526 } | |
1527 #endif | |
1528 | |
1529 // TODO(john.yan): place kAllowRM where available | |
1530 #define VISIT_FLOAT_UNARY_OP_LIST(V) \ | |
1531 V(Float32, ChangeFloat32ToFloat64, kS390_Float32ToDouble, \ | |
1532 OperandMode::kAllowRM) \ | |
1533 V(Float32, BitcastFloat32ToInt32, kS390_BitcastFloat32ToInt32, \ | |
1534 OperandMode::kNone) \ | |
1535 V(Float64, TruncateFloat64ToFloat32, kS390_DoubleToFloat32, \ | |
1536 OperandMode::kNone) \ | |
1537 V(Float64, TruncateFloat64ToWord32, kArchTruncateDoubleToI, \ | |
1538 OperandMode::kNone) \ | |
1539 V(Float64, RoundFloat64ToInt32, kS390_DoubleToInt32, OperandMode::kNone) \ | |
1540 V(Float32, TruncateFloat32ToInt32, kS390_Float32ToInt32, OperandMode::kNone) \ | |
1541 V(Float32, TruncateFloat32ToUint32, kS390_Float32ToUint32, \ | |
1542 OperandMode::kNone) \ | |
1543 V(Float64, ChangeFloat64ToInt32, kS390_DoubleToInt32, OperandMode::kNone) \ | |
1544 V(Float64, ChangeFloat64ToUint32, kS390_DoubleToUint32, OperandMode::kNone) \ | |
1545 V(Float64, TruncateFloat64ToUint32, kS390_DoubleToUint32, \ | |
1546 OperandMode::kNone) \ | |
1547 V(Float64, Float64SilenceNaN, kS390_Float64SilenceNaN, OperandMode::kNone) \ | |
1548 V(Float32, Float32Abs, kS390_AbsFloat, OperandMode::kNone) \ | |
1549 V(Float64, Float64Abs, kS390_AbsDouble, OperandMode::kNone) \ | |
1550 V(Float32, Float32Sqrt, kS390_SqrtFloat, OperandMode::kNone) \ | |
1551 V(Float64, Float64Sqrt, kS390_SqrtDouble, OperandMode::kNone) \ | |
1552 V(Float32, Float32RoundDown, kS390_FloorFloat, OperandMode::kNone) \ | |
1553 V(Float64, Float64RoundDown, kS390_FloorDouble, OperandMode::kNone) \ | |
1554 V(Float32, Float32RoundUp, kS390_CeilFloat, OperandMode::kNone) \ | |
1555 V(Float64, Float64RoundUp, kS390_CeilDouble, OperandMode::kNone) \ | |
1556 V(Float32, Float32RoundTruncate, kS390_TruncateFloat, OperandMode::kNone) \ | |
1557 V(Float64, Float64RoundTruncate, kS390_TruncateDouble, OperandMode::kNone) \ | |
1558 V(Float64, Float64RoundTiesAway, kS390_RoundDouble, OperandMode::kNone) \ | |
1559 V(Float32, Float32Neg, kS390_NegFloat, OperandMode::kNone) \ | |
1560 V(Float64, Float64Neg, kS390_NegDouble, OperandMode::kNone) | |
1561 | |
1562 #define VISIT_WORD64_UNARY_OP_LIST(V) \ | |
1563 V(Word64, TruncateInt64ToInt32, kS390_Int64ToInt32, OperandMode::kNone) \ | |
1564 V(Word64, RoundInt64ToFloat32, kS390_Int64ToFloat32, OperandMode::kNone) \ | |
1565 V(Word64, RoundInt64ToFloat64, kS390_Int64ToDouble, OperandMode::kNone) \ | |
1566 V(Word64, RoundUint64ToFloat32, kS390_Uint64ToFloat32, OperandMode::kNone) \ | |
1567 V(Word64, RoundUint64ToFloat64, kS390_Uint64ToDouble, OperandMode::kNone) \ | |
1568 V(Word64, BitcastInt64ToFloat64, kS390_BitcastInt64ToDouble, \ | |
1569 OperandMode::kNone) \ | |
1570 V(Float64, BitcastFloat64ToInt64, kS390_BitcastDoubleToInt64, \ | |
1571 OperandMode::kNone) | |
1572 | |
1573 #define DECLARE_UNARY_OP(type, name, op, mode) \ | |
1574 void InstructionSelector::Visit##name(Node* node) { \ | |
1575 Visit##type##UnaryOp(this, node, op, mode); \ | |
1576 } | |
1577 | |
1578 VISIT_FLOAT_UNARY_OP_LIST(DECLARE_UNARY_OP); | |
1579 | |
1580 #if V8_TARGET_ARCH_S390X | |
1581 VISIT_WORD64_UNARY_OP_LIST(DECLARE_UNARY_OP) | |
1582 #endif | |
1583 | |
1584 #undef DECLARE_UNARY_OP | 1581 #undef DECLARE_UNARY_OP |
1585 #undef VISIT_WORD64_UNARY_OP_LIST | 1582 #undef WORD64_BIN_OP_LIST |
1586 #undef VISIT_FLOAT_UNARY_OP_LIST | 1583 #undef WORD64_UNARY_OP_LIST |
1587 | 1584 #undef WORD32_BIN_OP_LIST |
1588 void InstructionSelector::VisitRoundInt32ToFloat32(Node* node) { | 1585 #undef WORD32_UNARY_OP_LIST |
1589 VisitRR(this, kS390_Int32ToFloat32, node); | 1586 #undef FLOAT_UNARY_OP_LIST |
1590 } | 1587 #undef WORD32_UNARY_OP_LIST_32 |
1591 | 1588 #undef FLOAT_BIN_OP_LIST |
1592 void InstructionSelector::VisitRoundUint32ToFloat32(Node* node) { | 1589 #undef FLOAT_BIN_OP_LIST_32 |
1593 VisitRR(this, kS390_Uint32ToFloat32, node); | 1590 #undef null |
1594 } | |
1595 | |
1596 void InstructionSelector::VisitChangeInt32ToFloat64(Node* node) { | |
1597 VisitRR(this, kS390_Int32ToDouble, node); | |
1598 } | |
1599 | |
1600 void InstructionSelector::VisitChangeUint32ToFloat64(Node* node) { | |
1601 VisitRR(this, kS390_Uint32ToDouble, node); | |
1602 } | |
1603 | 1591 |
1604 #if V8_TARGET_ARCH_S390X | 1592 #if V8_TARGET_ARCH_S390X |
1605 void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) { | 1593 void InstructionSelector::VisitTryTruncateFloat32ToInt64(Node* node) { |
1606 VisitTryTruncateDouble(this, kS390_Float32ToInt64, node); | 1594 VisitTryTruncateDouble(this, kS390_Float32ToInt64, node); |
1607 } | 1595 } |
1608 | 1596 |
1609 void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) { | 1597 void InstructionSelector::VisitTryTruncateFloat64ToInt64(Node* node) { |
1610 VisitTryTruncateDouble(this, kS390_DoubleToInt64, node); | 1598 VisitTryTruncateDouble(this, kS390_DoubleToInt64, node); |
1611 } | 1599 } |
1612 | 1600 |
1613 void InstructionSelector::VisitTryTruncateFloat32ToUint64(Node* node) { | 1601 void InstructionSelector::VisitTryTruncateFloat32ToUint64(Node* node) { |
1614 VisitTryTruncateDouble(this, kS390_Float32ToUint64, node); | 1602 VisitTryTruncateDouble(this, kS390_Float32ToUint64, node); |
1615 } | 1603 } |
1616 | 1604 |
1617 void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) { | 1605 void InstructionSelector::VisitTryTruncateFloat64ToUint64(Node* node) { |
1618 VisitTryTruncateDouble(this, kS390_DoubleToUint64, node); | 1606 VisitTryTruncateDouble(this, kS390_DoubleToUint64, node); |
1619 } | 1607 } |
1620 | 1608 |
1621 void InstructionSelector::VisitChangeInt32ToInt64(Node* node) { | |
1622 // TODO(mbrandy): inspect input to see if nop is appropriate. | |
1623 VisitRR(this, kS390_ExtendSignWord32, node); | |
1624 } | |
1625 | |
1626 void InstructionSelector::VisitChangeUint32ToUint64(Node* node) { | |
1627 S390OperandGenerator g(this); | |
1628 Node* value = node->InputAt(0); | |
1629 if (ZeroExtendsWord32ToWord64(value)) { | |
1630 // These 32-bit operations implicitly zero-extend to 64-bit on x64, so the | |
1631 // zero-extension is a no-op. | |
1632 return EmitIdentity(node); | |
1633 } | |
1634 VisitRR(this, kS390_Uint32ToUint64, node); | |
1635 } | |
1636 | |
1637 void InstructionSelector::VisitChangeFloat64ToUint64(Node* node) { | |
1638 VisitRR(this, kS390_DoubleToUint64, node); | |
1639 } | |
1640 #endif | 1609 #endif |
1641 | 1610 |
1642 void InstructionSelector::VisitBitcastInt32ToFloat32(Node* node) { | |
1643 VisitRR(this, kS390_BitcastInt32ToFloat32, node); | |
1644 } | |
1645 | |
1646 void InstructionSelector::VisitFloat32Add(Node* node) { | |
1647 return VisitFloat32BinOp(this, node, kS390_AddFloat, OperandMode::kAllowRM); | |
1648 } | |
1649 | |
1650 void InstructionSelector::VisitFloat64Add(Node* node) { | |
1651 // TODO(mbrandy): detect multiply-add | |
1652 return VisitFloat64BinOp(this, node, kS390_AddDouble, OperandMode::kAllowRM); | |
1653 } | |
1654 | |
1655 void InstructionSelector::VisitFloat32Sub(Node* node) { | |
1656 return VisitFloat32BinOp(this, node, kS390_SubFloat, OperandMode::kAllowRM); | |
1657 } | |
1658 | |
1659 void InstructionSelector::VisitFloat64Sub(Node* node) { | |
1660 // TODO(mbrandy): detect multiply-subtract | |
1661 return VisitFloat64BinOp(this, node, kS390_SubDouble, OperandMode::kAllowRM); | |
1662 } | |
1663 | |
1664 void InstructionSelector::VisitFloat32Mul(Node* node) { | |
1665 return VisitFloat32BinOp(this, node, kS390_MulFloat, OperandMode::kAllowRM); | |
1666 } | |
1667 | |
1668 void InstructionSelector::VisitFloat64Mul(Node* node) { | |
1669 // TODO(mbrandy): detect negate | |
1670 return VisitFloat64BinOp(this, node, kS390_MulDouble, OperandMode::kAllowRM); | |
1671 } | |
1672 | |
1673 void InstructionSelector::VisitFloat32Div(Node* node) { | |
1674 return VisitFloat32BinOp(this, node, kS390_DivFloat, OperandMode::kAllowRM); | |
1675 } | |
1676 | |
1677 void InstructionSelector::VisitFloat64Div(Node* node) { | |
1678 return VisitFloat64BinOp(this, node, kS390_DivDouble, OperandMode::kAllowRM); | |
1679 } | |
1680 | |
1681 void InstructionSelector::VisitFloat64Mod(Node* node) { | 1611 void InstructionSelector::VisitFloat64Mod(Node* node) { |
1682 S390OperandGenerator g(this); | 1612 S390OperandGenerator g(this); |
1683 Emit(kS390_ModDouble, g.DefineAsFixed(node, d1), | 1613 Emit(kS390_ModDouble, g.DefineAsFixed(node, d1), |
1684 g.UseFixed(node->InputAt(0), d1), g.UseFixed(node->InputAt(1), d2)) | 1614 g.UseFixed(node->InputAt(0), d1), g.UseFixed(node->InputAt(1), d2)) |
1685 ->MarkAsCall(); | 1615 ->MarkAsCall(); |
1686 } | 1616 } |
1687 | 1617 |
1688 void InstructionSelector::VisitFloat32Max(Node* node) { | |
1689 return VisitFloat32BinOp(this, node, kS390_MaxFloat, OperandMode::kNone); | |
1690 } | |
1691 | |
1692 void InstructionSelector::VisitFloat64Max(Node* node) { | |
1693 return VisitFloat64BinOp(this, node, kS390_MaxDouble, OperandMode::kNone); | |
1694 } | |
1695 | |
1696 void InstructionSelector::VisitFloat32Min(Node* node) { | |
1697 return VisitFloat32BinOp(this, node, kS390_MinFloat, OperandMode::kNone); | |
1698 } | |
1699 | |
1700 void InstructionSelector::VisitFloat64Min(Node* node) { | |
1701 return VisitFloat64BinOp(this, node, kS390_MinDouble, OperandMode::kNone); | |
1702 } | |
1703 | |
1704 void InstructionSelector::VisitFloat64Ieee754Unop(Node* node, | 1618 void InstructionSelector::VisitFloat64Ieee754Unop(Node* node, |
1705 InstructionCode opcode) { | 1619 InstructionCode opcode) { |
1706 S390OperandGenerator g(this); | 1620 S390OperandGenerator g(this); |
1707 Emit(opcode, g.DefineAsFixed(node, d1), g.UseFixed(node->InputAt(0), d1)) | 1621 Emit(opcode, g.DefineAsFixed(node, d1), g.UseFixed(node->InputAt(0), d1)) |
1708 ->MarkAsCall(); | 1622 ->MarkAsCall(); |
1709 } | 1623 } |
1710 | 1624 |
1711 void InstructionSelector::VisitFloat64Ieee754Binop(Node* node, | 1625 void InstructionSelector::VisitFloat64Ieee754Binop(Node* node, |
1712 InstructionCode opcode) { | 1626 InstructionCode opcode) { |
1713 S390OperandGenerator g(this); | 1627 S390OperandGenerator g(this); |
1714 Emit(opcode, g.DefineAsFixed(node, d1), g.UseFixed(node->InputAt(0), d1), | 1628 Emit(opcode, g.DefineAsFixed(node, d1), g.UseFixed(node->InputAt(0), d1), |
1715 g.UseFixed(node->InputAt(1), d2)) | 1629 g.UseFixed(node->InputAt(1), d2)) |
1716 ->MarkAsCall(); | 1630 ->MarkAsCall(); |
1717 } | 1631 } |
1718 | 1632 |
1719 void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) { | 1633 void InstructionSelector::VisitFloat32RoundTiesEven(Node* node) { |
1720 UNREACHABLE(); | 1634 UNREACHABLE(); |
1721 } | 1635 } |
1722 | 1636 |
1723 void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) { | 1637 void InstructionSelector::VisitFloat64RoundTiesEven(Node* node) { |
1724 UNREACHABLE(); | 1638 UNREACHABLE(); |
1725 } | 1639 } |
1726 | 1640 |
1727 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { | |
1728 OperandModes mode = AddOperandMode; | |
1729 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { | |
1730 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); | |
1731 return VisitBin32op(this, node, kS390_Add32, mode, &cont); | |
1732 } | |
1733 FlagsContinuation cont; | |
1734 VisitBin32op(this, node, kS390_Add32, mode, &cont); | |
1735 } | |
1736 | |
1737 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { | |
1738 OperandModes mode = SubOperandMode; | |
1739 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { | |
1740 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); | |
1741 return VisitBin32op(this, node, kS390_Sub32, mode, &cont); | |
1742 } | |
1743 FlagsContinuation cont; | |
1744 VisitBin32op(this, node, kS390_Sub32, mode, &cont); | |
1745 } | |
1746 | |
1747 #if V8_TARGET_ARCH_S390X | |
1748 void InstructionSelector::VisitInt64AddWithOverflow(Node* node) { | |
1749 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { | |
1750 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); | |
1751 return VisitWord64BinOp(this, node, kS390_Add64, AddOperandMode, &cont); | |
1752 } | |
1753 VisitWord64BinOp(this, node, kS390_Add64, AddOperandMode); | |
1754 } | |
1755 | |
1756 void InstructionSelector::VisitInt64SubWithOverflow(Node* node) { | |
1757 if (Node* ovf = NodeProperties::FindProjection(node, 1)) { | |
1758 FlagsContinuation cont = FlagsContinuation::ForSet(kOverflow, ovf); | |
1759 return VisitWord64BinOp(this, node, kS390_Sub64, SubOperandMode, &cont); | |
1760 } | |
1761 VisitWord64BinOp(this, node, kS390_Sub64, SubOperandMode); | |
1762 } | |
1763 #endif | |
1764 | |
1765 static bool CompareLogical(FlagsContinuation* cont) { | 1641 static bool CompareLogical(FlagsContinuation* cont) { |
1766 switch (cont->condition()) { | 1642 switch (cont->condition()) { |
1767 case kUnsignedLessThan: | 1643 case kUnsignedLessThan: |
1768 case kUnsignedGreaterThanOrEqual: | 1644 case kUnsignedGreaterThanOrEqual: |
1769 case kUnsignedLessThanOrEqual: | 1645 case kUnsignedLessThanOrEqual: |
1770 case kUnsignedGreaterThan: | 1646 case kUnsignedGreaterThan: |
1771 return true; | 1647 return true; |
1772 default: | 1648 default: |
1773 return false; | 1649 return false; |
1774 } | 1650 } |
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2098 // unless the 0th projection (the use of the actual value of the | 1974 // unless the 0th projection (the use of the actual value of the |
2099 // <Operation> is either nullptr, which means there's no use of the | 1975 // <Operation> is either nullptr, which means there's no use of the |
2100 // actual value, or was already defined, which means it is scheduled | 1976 // actual value, or was already defined, which means it is scheduled |
2101 // *AFTER* this branch). | 1977 // *AFTER* this branch). |
2102 Node* const node = value->InputAt(0); | 1978 Node* const node = value->InputAt(0); |
2103 Node* const result = NodeProperties::FindProjection(node, 0); | 1979 Node* const result = NodeProperties::FindProjection(node, 0); |
2104 if (result == nullptr || selector->IsDefined(result)) { | 1980 if (result == nullptr || selector->IsDefined(result)) { |
2105 switch (node->opcode()) { | 1981 switch (node->opcode()) { |
2106 case IrOpcode::kInt32AddWithOverflow: | 1982 case IrOpcode::kInt32AddWithOverflow: |
2107 cont->OverwriteAndNegateIfEqual(kOverflow); | 1983 cont->OverwriteAndNegateIfEqual(kOverflow); |
2108 return VisitBin32op(selector, node, kS390_Add32, AddOperandMode, | 1984 return VisitWord32BinOp(selector, node, kS390_Add32, |
2109 cont); | 1985 AddOperandMode, cont); |
2110 case IrOpcode::kInt32SubWithOverflow: | 1986 case IrOpcode::kInt32SubWithOverflow: |
2111 cont->OverwriteAndNegateIfEqual(kOverflow); | 1987 cont->OverwriteAndNegateIfEqual(kOverflow); |
2112 return VisitBin32op(selector, node, kS390_Sub32, SubOperandMode, | 1988 return VisitWord32BinOp(selector, node, kS390_Sub32, |
2113 cont); | 1989 SubOperandMode, cont); |
2114 case IrOpcode::kInt32MulWithOverflow: | 1990 case IrOpcode::kInt32MulWithOverflow: |
2115 cont->OverwriteAndNegateIfEqual(kNotEqual); | 1991 cont->OverwriteAndNegateIfEqual(kNotEqual); |
2116 return VisitBin32op( | 1992 return VisitWord32BinOp( |
2117 selector, node, kS390_Mul32WithOverflow, | 1993 selector, node, kS390_Mul32WithOverflow, |
2118 OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps, | 1994 OperandMode::kInt32Imm | OperandMode::kAllowDistinctOps, |
2119 cont); | 1995 cont); |
2120 #if V8_TARGET_ARCH_S390X | 1996 #if V8_TARGET_ARCH_S390X |
2121 case IrOpcode::kInt64AddWithOverflow: | 1997 case IrOpcode::kInt64AddWithOverflow: |
2122 cont->OverwriteAndNegateIfEqual(kOverflow); | 1998 cont->OverwriteAndNegateIfEqual(kOverflow); |
2123 return VisitWord64BinOp(selector, node, kS390_Add64, | 1999 return VisitWord64BinOp(selector, node, kS390_Add64, |
2124 AddOperandMode, cont); | 2000 AddOperandMode, cont); |
2125 case IrOpcode::kInt64SubWithOverflow: | 2001 case IrOpcode::kInt64SubWithOverflow: |
2126 cont->OverwriteAndNegateIfEqual(kOverflow); | 2002 cont->OverwriteAndNegateIfEqual(kOverflow); |
(...skipping 22 matching lines...) Expand all Loading... |
2149 default: | 2025 default: |
2150 break; | 2026 break; |
2151 } | 2027 } |
2152 break; | 2028 break; |
2153 } | 2029 } |
2154 case IrOpcode::kInt32Add: | 2030 case IrOpcode::kInt32Add: |
2155 // can't handle overflow case. | 2031 // can't handle overflow case. |
2156 break; | 2032 break; |
2157 case IrOpcode::kWord32Or: | 2033 case IrOpcode::kWord32Or: |
2158 if (fc == kNotEqual || fc == kEqual) | 2034 if (fc == kNotEqual || fc == kEqual) |
2159 return VisitBin32op(selector, value, kS390_Or32, Or32OperandMode, | 2035 return VisitWord32BinOp(selector, value, kS390_Or32, Or32OperandMode, |
2160 cont); | 2036 cont); |
2161 break; | 2037 break; |
2162 case IrOpcode::kWord32Xor: | 2038 case IrOpcode::kWord32Xor: |
2163 if (fc == kNotEqual || fc == kEqual) | 2039 if (fc == kNotEqual || fc == kEqual) |
2164 return VisitBin32op(selector, value, kS390_Xor32, Xor32OperandMode, | 2040 return VisitWord32BinOp(selector, value, kS390_Xor32, |
2165 cont); | 2041 Xor32OperandMode, cont); |
2166 break; | 2042 break; |
2167 case IrOpcode::kWord32Sar: | 2043 case IrOpcode::kWord32Sar: |
2168 case IrOpcode::kWord32Shl: | 2044 case IrOpcode::kWord32Shl: |
2169 case IrOpcode::kWord32Shr: | 2045 case IrOpcode::kWord32Shr: |
2170 case IrOpcode::kWord32Ror: | 2046 case IrOpcode::kWord32Ror: |
2171 // doesn't generate cc, so ignore. | 2047 // doesn't generate cc, so ignore. |
2172 break; | 2048 break; |
2173 #if V8_TARGET_ARCH_S390X | 2049 #if V8_TARGET_ARCH_S390X |
2174 case IrOpcode::kInt64Sub: | 2050 case IrOpcode::kInt64Sub: |
2175 if (fc == kNotEqual || fc == kEqual) | 2051 if (fc == kNotEqual || fc == kEqual) |
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2574 // static | 2450 // static |
2575 MachineOperatorBuilder::AlignmentRequirements | 2451 MachineOperatorBuilder::AlignmentRequirements |
2576 InstructionSelector::AlignmentRequirements() { | 2452 InstructionSelector::AlignmentRequirements() { |
2577 return MachineOperatorBuilder::AlignmentRequirements:: | 2453 return MachineOperatorBuilder::AlignmentRequirements:: |
2578 FullUnalignedAccessSupport(); | 2454 FullUnalignedAccessSupport(); |
2579 } | 2455 } |
2580 | 2456 |
2581 } // namespace compiler | 2457 } // namespace compiler |
2582 } // namespace internal | 2458 } // namespace internal |
2583 } // namespace v8 | 2459 } // namespace v8 |
OLD | NEW |