Chromium Code Reviews| 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.h" | 5 #include "src/compiler/instruction-selector.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "src/base/adapters.h" | 9 #include "src/base/adapters.h" |
| 10 #include "src/compiler/instruction-selector-impl.h" | 10 #include "src/compiler/instruction-selector-impl.h" |
| (...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 509 #endif | 509 #endif |
| 510 | 510 |
| 511 Node* input = block->control_input(); | 511 Node* input = block->control_input(); |
| 512 switch (block->control()) { | 512 switch (block->control()) { |
| 513 case BasicBlock::kGoto: | 513 case BasicBlock::kGoto: |
| 514 return VisitGoto(block->SuccessorAt(0)); | 514 return VisitGoto(block->SuccessorAt(0)); |
| 515 case BasicBlock::kCall: { | 515 case BasicBlock::kCall: { |
| 516 DCHECK_EQ(IrOpcode::kCall, input->opcode()); | 516 DCHECK_EQ(IrOpcode::kCall, input->opcode()); |
| 517 BasicBlock* success = block->SuccessorAt(0); | 517 BasicBlock* success = block->SuccessorAt(0); |
| 518 BasicBlock* exception = block->SuccessorAt(1); | 518 BasicBlock* exception = block->SuccessorAt(1); |
| 519 return VisitCall(input, exception), VisitGoto(success); | 519 return VisitCall(input, exception, NORMAL_CALL), VisitGoto(success); |
| 520 } | 520 } |
| 521 case BasicBlock::kBranch: { | 521 case BasicBlock::kBranch: { |
| 522 DCHECK_EQ(IrOpcode::kBranch, input->opcode()); | 522 DCHECK_EQ(IrOpcode::kBranch, input->opcode()); |
| 523 BasicBlock* tbranch = block->SuccessorAt(0); | 523 BasicBlock* tbranch = block->SuccessorAt(0); |
| 524 BasicBlock* fbranch = block->SuccessorAt(1); | 524 BasicBlock* fbranch = block->SuccessorAt(1); |
| 525 if (tbranch == fbranch) return VisitGoto(tbranch); | 525 if (tbranch == fbranch) return VisitGoto(tbranch); |
| 526 // Treat special Branch(Always, IfTrue, IfFalse) as Goto(IfTrue). | 526 // Treat special Branch(Always, IfTrue, IfFalse) as Goto(IfTrue). |
| 527 Node* const condition = input->InputAt(0); | 527 Node* const condition = input->InputAt(0); |
| 528 if (condition->opcode() == IrOpcode::kAlways) return VisitGoto(tbranch); | 528 if (condition->opcode() == IrOpcode::kAlways) return VisitGoto(tbranch); |
| 529 return VisitBranch(input, tbranch, fbranch); | 529 return VisitBranch(input, tbranch, fbranch); |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 552 DCHECK_LE(sw.min_value, sw.max_value); | 552 DCHECK_LE(sw.min_value, sw.max_value); |
| 553 // Note that {value_range} can be 0 if {min_value} is -2^31 and | 553 // Note that {value_range} can be 0 if {min_value} is -2^31 and |
| 554 // {max_value} | 554 // {max_value} |
| 555 // is 2^31-1, so don't assume that it's non-zero below. | 555 // is 2^31-1, so don't assume that it's non-zero below. |
| 556 sw.value_range = 1u + bit_cast<uint32_t>(sw.max_value) - | 556 sw.value_range = 1u + bit_cast<uint32_t>(sw.max_value) - |
| 557 bit_cast<uint32_t>(sw.min_value); | 557 bit_cast<uint32_t>(sw.min_value); |
| 558 return VisitSwitch(input, sw); | 558 return VisitSwitch(input, sw); |
| 559 } | 559 } |
| 560 case BasicBlock::kReturn: { | 560 case BasicBlock::kReturn: { |
| 561 DCHECK_EQ(IrOpcode::kReturn, input->opcode()); | 561 DCHECK_EQ(IrOpcode::kReturn, input->opcode()); |
| 562 return VisitReturn(input->InputAt(0)); | 562 return VisitReturn(input); |
| 563 } | 563 } |
| 564 case BasicBlock::kDeoptimize: { | 564 case BasicBlock::kDeoptimize: { |
| 565 // If the result itself is a return, return its input. | 565 // If the result itself is a return, return its input. |
| 566 Node* value = | 566 Node* value = |
| 567 (input != nullptr && input->opcode() == IrOpcode::kDeoptimize) | 567 (input != nullptr && input->opcode() == IrOpcode::kDeoptimize) |
| 568 ? input->InputAt(0) | 568 ? input->InputAt(0) |
| 569 : input; | 569 : input; |
| 570 return VisitDeoptimize(value); | 570 return VisitDeoptimize(value); |
| 571 } | 571 } |
| 572 case BasicBlock::kThrow: | 572 case BasicBlock::kThrow: |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 629 case IrOpcode::kFloat64Constant: | 629 case IrOpcode::kFloat64Constant: |
| 630 return MarkAsDouble(node), VisitConstant(node); | 630 return MarkAsDouble(node), VisitConstant(node); |
| 631 case IrOpcode::kHeapConstant: | 631 case IrOpcode::kHeapConstant: |
| 632 return MarkAsReference(node), VisitConstant(node); | 632 return MarkAsReference(node), VisitConstant(node); |
| 633 case IrOpcode::kNumberConstant: { | 633 case IrOpcode::kNumberConstant: { |
| 634 double value = OpParameter<double>(node); | 634 double value = OpParameter<double>(node); |
| 635 if (!IsSmiDouble(value)) MarkAsReference(node); | 635 if (!IsSmiDouble(value)) MarkAsReference(node); |
| 636 return VisitConstant(node); | 636 return VisitConstant(node); |
| 637 } | 637 } |
| 638 case IrOpcode::kCall: | 638 case IrOpcode::kCall: |
| 639 return VisitCall(node, nullptr); | 639 return VisitCall(node, nullptr, NORMAL_CALL); |
| 640 case IrOpcode::kFrameState: | 640 case IrOpcode::kFrameState: |
| 641 case IrOpcode::kStateValues: | 641 case IrOpcode::kStateValues: |
| 642 return; | 642 return; |
| 643 case IrOpcode::kLoad: { | 643 case IrOpcode::kLoad: { |
| 644 LoadRepresentation rep = OpParameter<LoadRepresentation>(node); | 644 LoadRepresentation rep = OpParameter<LoadRepresentation>(node); |
| 645 MarkAsRepresentation(rep, node); | 645 MarkAsRepresentation(rep, node); |
| 646 return VisitLoad(node); | 646 return VisitLoad(node); |
| 647 } | 647 } |
| 648 case IrOpcode::kStore: | 648 case IrOpcode::kStore: |
| 649 return VisitStore(node); | 649 return VisitStore(node); |
| (...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1034 } | 1034 } |
| 1035 | 1035 |
| 1036 | 1036 |
| 1037 void InstructionSelector::VisitGoto(BasicBlock* target) { | 1037 void InstructionSelector::VisitGoto(BasicBlock* target) { |
| 1038 // jump to the next block. | 1038 // jump to the next block. |
| 1039 OperandGenerator g(this); | 1039 OperandGenerator g(this); |
| 1040 Emit(kArchJmp, g.NoOutput(), g.Label(target)); | 1040 Emit(kArchJmp, g.NoOutput(), g.Label(target)); |
| 1041 } | 1041 } |
| 1042 | 1042 |
| 1043 | 1043 |
| 1044 void InstructionSelector::VisitReturn(Node* value) { | 1044 // Returns the call node if the given return node is part of a tail call, |
| 1045 // nullptr otherwise. | |
| 1046 static Node* DetectTailCall(Node* ret) { | |
|
Benedikt Meurer
2015/04/29 04:06:05
Nit: Use anonymous namespace instead of static, an
Sven Panne
2015/04/29 10:24:18
Done.
| |
| 1047 // The value which is returned must be the result of a potential tail call, | |
| 1048 // there must be no try/catch/finally around the call, and there must be no | |
| 1049 // effects between the call and the return. | |
| 1050 Node* call = NodeProperties::GetValueInput(ret, 0); | |
| 1051 if (call->opcode() != IrOpcode::kCall || | |
| 1052 !OpParameter<const CallDescriptor*>(call)->IsTailCallAllowed() || | |
| 1053 NodeProperties::IsExceptionalCall(call) || | |
| 1054 NodeProperties::GetEffectInput(ret, 0) != call) { | |
| 1055 return nullptr; | |
| 1056 } | |
| 1057 // Furthermore, control has to flow via an IfSuccess from the call (for calls | |
| 1058 // which can throw), or the return and the call have to use the same control | |
| 1059 // input (for calls which can't throw). | |
| 1060 Node* control = NodeProperties::GetControlInput(ret, 0); | |
| 1061 return ((control->opcode() == IrOpcode::kIfSuccess) | |
| 1062 ? (NodeProperties::GetControlInput(control, 0) == call) | |
|
Benedikt Meurer
2015/04/29 04:06:05
Urghs, can we please not nest tenary operators?
Sven Panne
2015/04/29 10:24:18
Booh! Functional programming FTW! ;-) Nevertheless
| |
| 1063 : (control == NodeProperties::GetControlInput(call, 0))) | |
| 1064 ? call | |
| 1065 : nullptr; | |
| 1066 } | |
| 1067 | |
| 1068 | |
| 1069 void InstructionSelector::VisitReturn(Node* node) { | |
| 1070 if (FLAG_turbo_tail_calls) { | |
| 1071 Node* call = DetectTailCall(node); | |
| 1072 if (call != nullptr && | |
| 1073 OpParameter<const CallDescriptor*>(call)->UsesOnlyRegisters()) { | |
| 1074 return VisitCall(call, nullptr, TAIL_CALL); | |
| 1075 } | |
| 1076 } | |
| 1077 Node* value = NodeProperties::GetValueInput(node, 0); | |
| 1045 DCHECK_NOT_NULL(value); | 1078 DCHECK_NOT_NULL(value); |
| 1046 OperandGenerator g(this); | 1079 OperandGenerator g(this); |
| 1047 Emit(kArchRet, g.NoOutput(), | 1080 Emit(kArchRet, g.NoOutput(), |
| 1048 g.UseLocation(value, linkage()->GetReturnLocation(), | 1081 g.UseLocation(value, linkage()->GetReturnLocation(), |
| 1049 linkage()->GetReturnType())); | 1082 linkage()->GetReturnType())); |
| 1050 } | 1083 } |
| 1051 | 1084 |
| 1052 | 1085 |
| 1053 void InstructionSelector::VisitDeoptimize(Node* value) { | 1086 void InstructionSelector::VisitDeoptimize(Node* value) { |
| 1054 OperandGenerator g(this); | 1087 OperandGenerator g(this); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1192 MachineOperatorBuilder::Flags | 1225 MachineOperatorBuilder::Flags |
| 1193 InstructionSelector::SupportedMachineOperatorFlags() { | 1226 InstructionSelector::SupportedMachineOperatorFlags() { |
| 1194 return MachineOperatorBuilder::Flag::kNoFlags; | 1227 return MachineOperatorBuilder::Flag::kNoFlags; |
| 1195 } | 1228 } |
| 1196 | 1229 |
| 1197 #endif // !V8_TURBOFAN_BACKEND | 1230 #endif // !V8_TURBOFAN_BACKEND |
| 1198 | 1231 |
| 1199 } // namespace compiler | 1232 } // namespace compiler |
| 1200 } // namespace internal | 1233 } // namespace internal |
| 1201 } // namespace v8 | 1234 } // namespace v8 |
| OLD | NEW |