| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 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/compiler/instruction-selector-impl.h" | 5 #include "src/compiler/instruction-selector-impl.h" |
| 6 #include "src/compiler/node-matchers.h" | 6 #include "src/compiler/node-matchers.h" |
| 7 | 7 |
| 8 namespace v8 { | 8 namespace v8 { |
| 9 namespace internal { | 9 namespace internal { |
| 10 namespace compiler { | 10 namespace compiler { |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, | 165 Emit(opcode | AddressingModeField::encode(kMode_MRI), NULL, |
| 166 g.UseRegister(base), g.UseImmediate(index), val); | 166 g.UseRegister(base), g.UseImmediate(index), val); |
| 167 } else { // store [%base + %index], %|#value | 167 } else { // store [%base + %index], %|#value |
| 168 Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL, | 168 Emit(opcode | AddressingModeField::encode(kMode_MR1I), NULL, |
| 169 g.UseRegister(base), g.UseRegister(index), val); | 169 g.UseRegister(base), g.UseRegister(index), val); |
| 170 } | 170 } |
| 171 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] | 171 // TODO(turbofan): addressing modes [r+r*{2,4,8}+K] |
| 172 } | 172 } |
| 173 | 173 |
| 174 | 174 |
| 175 // Shared routine for multiple binary operations. | |
| 176 static void VisitBinop(InstructionSelector* selector, Node* node, | 175 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 177 InstructionCode opcode, FlagsContinuation* cont) { | 176 InstructionCode opcode, FlagsContinuation* cont) { |
| 178 X64OperandGenerator g(selector); | 177 X64OperandGenerator g(selector); |
| 179 Int32BinopMatcher m(node); | 178 Int32BinopMatcher m(node); |
| 180 InstructionOperand* inputs[4]; | 179 InstructionOperand* inputs[4]; |
| 181 size_t input_count = 0; | 180 size_t input_count = 0; |
| 182 InstructionOperand* outputs[2]; | 181 InstructionOperand* outputs[2]; |
| 183 size_t output_count = 0; | 182 size_t output_count = 0; |
| 184 | 183 |
| 185 // TODO(turbofan): match complex addressing modes. | 184 // TODO(turbofan): match complex addressing modes. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 207 DCHECK_NE(0, output_count); | 206 DCHECK_NE(0, output_count); |
| 208 DCHECK_GE(ARRAY_SIZE(inputs), input_count); | 207 DCHECK_GE(ARRAY_SIZE(inputs), input_count); |
| 209 DCHECK_GE(ARRAY_SIZE(outputs), output_count); | 208 DCHECK_GE(ARRAY_SIZE(outputs), output_count); |
| 210 | 209 |
| 211 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count, | 210 Instruction* instr = selector->Emit(cont->Encode(opcode), output_count, |
| 212 outputs, input_count, inputs); | 211 outputs, input_count, inputs); |
| 213 if (cont->IsBranch()) instr->MarkAsControl(); | 212 if (cont->IsBranch()) instr->MarkAsControl(); |
| 214 } | 213 } |
| 215 | 214 |
| 216 | 215 |
| 217 // Shared routine for multiple binary operations. | |
| 218 static void VisitBinop(InstructionSelector* selector, Node* node, | 216 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 219 InstructionCode opcode) { | 217 InstructionCode opcode) { |
| 220 FlagsContinuation cont; | 218 FlagsContinuation cont; |
| 221 VisitBinop(selector, node, opcode, &cont); | 219 VisitBinop(selector, node, opcode, &cont); |
| 222 } | 220 } |
| 223 | 221 |
| 224 | 222 |
| 223 static void VisitBinop(InstructionSelector* selector, Node* node, |
| 224 InstructionCode opcode, |
| 225 FlagsCondition overflow_condition) { |
| 226 if (Node* overflow = node->FindProjection(1)) { |
| 227 FlagsContinuation cont(overflow_condition, overflow); |
| 228 return VisitBinop(selector, node, opcode, &cont); |
| 229 } |
| 230 FlagsContinuation cont; |
| 231 return VisitBinop(selector, node, opcode, &cont); |
| 232 } |
| 233 |
| 234 |
| 225 void InstructionSelector::VisitWord32And(Node* node) { | 235 void InstructionSelector::VisitWord32And(Node* node) { |
| 226 VisitBinop(this, node, kX64And32); | 236 VisitBinop(this, node, kX64And32); |
| 227 } | 237 } |
| 228 | 238 |
| 229 | 239 |
| 230 void InstructionSelector::VisitWord64And(Node* node) { | 240 void InstructionSelector::VisitWord64And(Node* node) { |
| 231 VisitBinop(this, node, kX64And); | 241 VisitBinop(this, node, kX64And); |
| 232 } | 242 } |
| 233 | 243 |
| 234 | 244 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 void InstructionSelector::VisitWord64Sar(Node* node) { | 356 void InstructionSelector::VisitWord64Sar(Node* node) { |
| 347 VisitWord64Shift(this, node, kX64Sar); | 357 VisitWord64Shift(this, node, kX64Sar); |
| 348 } | 358 } |
| 349 | 359 |
| 350 | 360 |
| 351 void InstructionSelector::VisitInt32Add(Node* node) { | 361 void InstructionSelector::VisitInt32Add(Node* node) { |
| 352 VisitBinop(this, node, kX64Add32); | 362 VisitBinop(this, node, kX64Add32); |
| 353 } | 363 } |
| 354 | 364 |
| 355 | 365 |
| 366 void InstructionSelector::VisitInt32AddWithOverflow(Node* node) { |
| 367 VisitBinop(this, node, kX64Add32, kOverflow); |
| 368 } |
| 369 |
| 370 |
| 371 void InstructionSelector::VisitUint32AddWithOverflow(Node* node) { |
| 372 VisitBinop(this, node, kX64Add32, kUnsignedLessThan); |
| 373 } |
| 374 |
| 375 |
| 356 void InstructionSelector::VisitInt64Add(Node* node) { | 376 void InstructionSelector::VisitInt64Add(Node* node) { |
| 357 VisitBinop(this, node, kX64Add); | 377 VisitBinop(this, node, kX64Add); |
| 358 } | 378 } |
| 359 | 379 |
| 360 | 380 |
| 361 template <typename T> | 381 template <typename T> |
| 362 static void VisitSub(InstructionSelector* selector, Node* node, | 382 static void VisitSub(InstructionSelector* selector, Node* node, |
| 363 ArchOpcode sub_opcode, ArchOpcode neg_opcode) { | 383 ArchOpcode sub_opcode, ArchOpcode neg_opcode) { |
| 364 X64OperandGenerator g(selector); | 384 X64OperandGenerator g(selector); |
| 365 BinopMatcher<IntMatcher<T>, IntMatcher<T> > m(node); | 385 BinopMatcher<IntMatcher<T>, IntMatcher<T> > m(node); |
| 366 if (m.left().Is(0)) { | 386 if (m.left().Is(0)) { |
| 367 selector->Emit(neg_opcode, g.DefineSameAsFirst(node), | 387 selector->Emit(neg_opcode, g.DefineSameAsFirst(node), |
| 368 g.Use(m.right().node())); | 388 g.Use(m.right().node())); |
| 369 } else { | 389 } else { |
| 370 VisitBinop(selector, node, sub_opcode); | 390 VisitBinop(selector, node, sub_opcode); |
| 371 } | 391 } |
| 372 } | 392 } |
| 373 | 393 |
| 374 | 394 |
| 375 void InstructionSelector::VisitInt32Sub(Node* node) { | 395 void InstructionSelector::VisitInt32Sub(Node* node) { |
| 376 VisitSub<int32_t>(this, node, kX64Sub32, kX64Neg32); | 396 VisitSub<int32_t>(this, node, kX64Sub32, kX64Neg32); |
| 377 } | 397 } |
| 378 | 398 |
| 379 | 399 |
| 400 void InstructionSelector::VisitInt32SubWithOverflow(Node* node) { |
| 401 VisitBinop(this, node, kX64Sub32, kOverflow); |
| 402 } |
| 403 |
| 404 |
| 405 void InstructionSelector::VisitUint32SubWithOverflow(Node* node) { |
| 406 VisitBinop(this, node, kX64Sub32, kUnsignedLessThan); |
| 407 } |
| 408 |
| 409 |
| 380 void InstructionSelector::VisitInt64Sub(Node* node) { | 410 void InstructionSelector::VisitInt64Sub(Node* node) { |
| 381 VisitSub<int64_t>(this, node, kX64Sub, kX64Neg); | 411 VisitSub<int64_t>(this, node, kX64Sub, kX64Neg); |
| 382 } | 412 } |
| 383 | 413 |
| 384 | 414 |
| 385 static void VisitMul(InstructionSelector* selector, Node* node, | 415 static void VisitMul(InstructionSelector* selector, Node* node, |
| 386 ArchOpcode opcode) { | 416 ArchOpcode opcode) { |
| 387 X64OperandGenerator g(selector); | 417 X64OperandGenerator g(selector); |
| 388 Node* left = node->InputAt(0); | 418 Node* left = node->InputAt(0); |
| 389 Node* right = node->InputAt(1); | 419 Node* right = node->InputAt(1); |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 550 | 580 |
| 551 | 581 |
| 552 void InstructionSelector::VisitConvertInt32ToInt64(Node* node) { | 582 void InstructionSelector::VisitConvertInt32ToInt64(Node* node) { |
| 553 X64OperandGenerator g(this); | 583 X64OperandGenerator g(this); |
| 554 // TODO(dcarney): other modes | 584 // TODO(dcarney): other modes |
| 555 Emit(kX64Int32ToInt64, g.DefineAsRegister(node), | 585 Emit(kX64Int32ToInt64, g.DefineAsRegister(node), |
| 556 g.UseRegister(node->InputAt(0))); | 586 g.UseRegister(node->InputAt(0))); |
| 557 } | 587 } |
| 558 | 588 |
| 559 | 589 |
| 560 void InstructionSelector::VisitInt32AddWithOverflow(Node* node, | |
| 561 FlagsContinuation* cont) { | |
| 562 VisitBinop(this, node, kX64Add32, cont); | |
| 563 } | |
| 564 | |
| 565 | |
| 566 void InstructionSelector::VisitInt32SubWithOverflow(Node* node, | |
| 567 FlagsContinuation* cont) { | |
| 568 VisitBinop(this, node, kX64Sub32, cont); | |
| 569 } | |
| 570 | |
| 571 | |
| 572 // Shared routine for multiple compare operations. | 590 // Shared routine for multiple compare operations. |
| 573 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, | 591 static void VisitCompare(InstructionSelector* selector, InstructionCode opcode, |
| 574 InstructionOperand* left, InstructionOperand* right, | 592 InstructionOperand* left, InstructionOperand* right, |
| 575 FlagsContinuation* cont) { | 593 FlagsContinuation* cont) { |
| 576 X64OperandGenerator g(selector); | 594 X64OperandGenerator g(selector); |
| 577 opcode = cont->Encode(opcode); | 595 opcode = cont->Encode(opcode); |
| 578 if (cont->IsBranch()) { | 596 if (cont->IsBranch()) { |
| 579 selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()), | 597 selector->Emit(opcode, NULL, left, right, g.Label(cont->true_block()), |
| 580 g.Label(cont->false_block()))->MarkAsControl(); | 598 g.Label(cont->false_block()))->MarkAsControl(); |
| 581 } else { | 599 } else { |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 650 void InstructionSelector::VisitFloat64Compare(Node* node, | 668 void InstructionSelector::VisitFloat64Compare(Node* node, |
| 651 FlagsContinuation* cont) { | 669 FlagsContinuation* cont) { |
| 652 X64OperandGenerator g(this); | 670 X64OperandGenerator g(this); |
| 653 Node* left = node->InputAt(0); | 671 Node* left = node->InputAt(0); |
| 654 Node* right = node->InputAt(1); | 672 Node* right = node->InputAt(1); |
| 655 VisitCompare(this, kSSEFloat64Cmp, g.UseDoubleRegister(left), g.Use(right), | 673 VisitCompare(this, kSSEFloat64Cmp, g.UseDoubleRegister(left), g.Use(right), |
| 656 cont); | 674 cont); |
| 657 } | 675 } |
| 658 | 676 |
| 659 | 677 |
| 678 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
| 679 BasicBlock* fbranch) { |
| 680 OperandGenerator g(this); |
| 681 Node* user = branch; |
| 682 Node* value = branch->InputAt(0); |
| 683 |
| 684 FlagsContinuation cont(kNotEqual, tbranch, fbranch); |
| 685 |
| 686 // If we can fall through to the true block, invert the branch. |
| 687 if (IsNextInAssemblyOrder(tbranch)) { |
| 688 cont.Negate(); |
| 689 cont.SwapBlocks(); |
| 690 } |
| 691 |
| 692 // Try to combine with comparisons against 0 by simply inverting the branch. |
| 693 while (CanCover(user, value)) { |
| 694 if (value->opcode() == IrOpcode::kWord32Equal) { |
| 695 Int32BinopMatcher m(value); |
| 696 if (m.right().Is(0)) { |
| 697 user = value; |
| 698 value = m.left().node(); |
| 699 cont.Negate(); |
| 700 } else { |
| 701 break; |
| 702 } |
| 703 } else if (value->opcode() == IrOpcode::kWord64Equal) { |
| 704 Int64BinopMatcher m(value); |
| 705 if (m.right().Is(0)) { |
| 706 user = value; |
| 707 value = m.left().node(); |
| 708 cont.Negate(); |
| 709 } else { |
| 710 break; |
| 711 } |
| 712 } else { |
| 713 break; |
| 714 } |
| 715 } |
| 716 |
| 717 // Try to combine the branch with a comparison. |
| 718 if (CanCover(user, value)) { |
| 719 switch (value->opcode()) { |
| 720 case IrOpcode::kWord32Equal: |
| 721 cont.OverwriteAndNegateIfEqual(kEqual); |
| 722 return VisitWord32Compare(value, &cont); |
| 723 case IrOpcode::kInt32LessThan: |
| 724 cont.OverwriteAndNegateIfEqual(kSignedLessThan); |
| 725 return VisitWord32Compare(value, &cont); |
| 726 case IrOpcode::kInt32LessThanOrEqual: |
| 727 cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); |
| 728 return VisitWord32Compare(value, &cont); |
| 729 case IrOpcode::kUint32LessThan: |
| 730 cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); |
| 731 return VisitWord32Compare(value, &cont); |
| 732 case IrOpcode::kUint32LessThanOrEqual: |
| 733 cont.OverwriteAndNegateIfEqual(kUnsignedLessThanOrEqual); |
| 734 return VisitWord32Compare(value, &cont); |
| 735 case IrOpcode::kWord64Equal: |
| 736 cont.OverwriteAndNegateIfEqual(kEqual); |
| 737 return VisitWord64Compare(value, &cont); |
| 738 case IrOpcode::kInt64LessThan: |
| 739 cont.OverwriteAndNegateIfEqual(kSignedLessThan); |
| 740 return VisitWord64Compare(value, &cont); |
| 741 case IrOpcode::kInt64LessThanOrEqual: |
| 742 cont.OverwriteAndNegateIfEqual(kSignedLessThanOrEqual); |
| 743 return VisitWord64Compare(value, &cont); |
| 744 case IrOpcode::kFloat64Equal: |
| 745 cont.OverwriteAndNegateIfEqual(kUnorderedEqual); |
| 746 return VisitFloat64Compare(value, &cont); |
| 747 case IrOpcode::kFloat64LessThan: |
| 748 cont.OverwriteAndNegateIfEqual(kUnorderedLessThan); |
| 749 return VisitFloat64Compare(value, &cont); |
| 750 case IrOpcode::kFloat64LessThanOrEqual: |
| 751 cont.OverwriteAndNegateIfEqual(kUnorderedLessThanOrEqual); |
| 752 return VisitFloat64Compare(value, &cont); |
| 753 case IrOpcode::kProjection: |
| 754 // Check if this is the overflow output projection of an |
| 755 // <Operation>WithOverflow node. |
| 756 if (OpParameter<int32_t>(value) == 1) { |
| 757 // We cannot combine the <Operation>WithOverflow with this branch |
| 758 // unless the 0th projection (the use of the actual value of the |
| 759 // <Operation> is either NULL, which means there's no use of the |
| 760 // actual value, or was already defined, which means it is scheduled |
| 761 // *AFTER* this branch). |
| 762 Node* node = value->InputAt(0); |
| 763 Node* result = node->FindProjection(0); |
| 764 if (result == NULL || IsDefined(result)) { |
| 765 switch (node->opcode()) { |
| 766 case IrOpcode::kInt32AddWithOverflow: |
| 767 cont.OverwriteAndNegateIfEqual(kOverflow); |
| 768 return VisitBinop(this, node, kX64Add32, &cont); |
| 769 case IrOpcode::kUint32AddWithOverflow: |
| 770 cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); |
| 771 return VisitBinop(this, node, kX64Add32, &cont); |
| 772 case IrOpcode::kInt32SubWithOverflow: |
| 773 cont.OverwriteAndNegateIfEqual(kOverflow); |
| 774 return VisitBinop(this, node, kX64Sub32, &cont); |
| 775 case IrOpcode::kUint32SubWithOverflow: |
| 776 cont.OverwriteAndNegateIfEqual(kUnsignedLessThan); |
| 777 return VisitBinop(this, node, kX64Sub32, &cont); |
| 778 default: |
| 779 break; |
| 780 } |
| 781 } |
| 782 } |
| 783 break; |
| 784 default: |
| 785 break; |
| 786 } |
| 787 } |
| 788 |
| 789 // Branch could not be combined with a compare, emit compare against 0. |
| 790 VisitWord32Test(value, &cont); |
| 791 } |
| 792 |
| 793 |
| 660 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation, | 794 void InstructionSelector::VisitCall(Node* call, BasicBlock* continuation, |
| 661 BasicBlock* deoptimization) { | 795 BasicBlock* deoptimization) { |
| 662 X64OperandGenerator g(this); | 796 X64OperandGenerator g(this); |
| 663 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call); | 797 CallDescriptor* descriptor = OpParameter<CallDescriptor*>(call); |
| 664 CallBuffer buffer(zone(), descriptor); // TODO(turbofan): temp zone here? | 798 CallBuffer buffer(zone(), descriptor); // TODO(turbofan): temp zone here? |
| 665 | 799 |
| 666 // Compute InstructionOperands for inputs and outputs. | 800 // Compute InstructionOperands for inputs and outputs. |
| 667 InitializeCallBuffer(call, &buffer, true, true, continuation, deoptimization); | 801 InitializeCallBuffer(call, &buffer, true, true, continuation, deoptimization); |
| 668 | 802 |
| 669 // TODO(dcarney): stack alignment for c calls. | 803 // TODO(dcarney): stack alignment for c calls. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 713 if (descriptor->kind() == CallDescriptor::kCallAddress && | 847 if (descriptor->kind() == CallDescriptor::kCallAddress && |
| 714 buffer.pushed_count > 0) { | 848 buffer.pushed_count > 0) { |
| 715 DCHECK(deoptimization == NULL && continuation == NULL); | 849 DCHECK(deoptimization == NULL && continuation == NULL); |
| 716 Emit(kPopStack | MiscField::encode(buffer.pushed_count), NULL); | 850 Emit(kPopStack | MiscField::encode(buffer.pushed_count), NULL); |
| 717 } | 851 } |
| 718 } | 852 } |
| 719 | 853 |
| 720 } // namespace compiler | 854 } // namespace compiler |
| 721 } // namespace internal | 855 } // namespace internal |
| 722 } // namespace v8 | 856 } // namespace v8 |
| OLD | NEW |