| 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" |
| 11 #include "src/compiler/node-matchers.h" | 11 #include "src/compiler/node-matchers.h" |
| 12 #include "src/compiler/node-properties.h" | |
| 13 #include "src/compiler/pipeline.h" | 12 #include "src/compiler/pipeline.h" |
| 14 #include "src/compiler/schedule.h" | 13 #include "src/compiler/schedule.h" |
| 15 #include "src/compiler/state-values-utils.h" | 14 #include "src/compiler/state-values-utils.h" |
| 16 | 15 |
| 17 namespace v8 { | 16 namespace v8 { |
| 18 namespace internal { | 17 namespace internal { |
| 19 namespace compiler { | 18 namespace compiler { |
| 20 | 19 |
| 21 InstructionSelector::InstructionSelector( | 20 InstructionSelector::InstructionSelector( |
| 22 Zone* zone, size_t node_count, Linkage* linkage, | 21 Zone* zone, size_t node_count, Linkage* linkage, |
| (...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 instruction_args.reserve(input_count() + frame_state_value_count()); | 270 instruction_args.reserve(input_count() + frame_state_value_count()); |
| 272 } | 271 } |
| 273 | 272 |
| 274 | 273 |
| 275 // TODO(bmeurer): Get rid of the CallBuffer business and make | 274 // TODO(bmeurer): Get rid of the CallBuffer business and make |
| 276 // InstructionSelector::VisitCall platform independent instead. | 275 // InstructionSelector::VisitCall platform independent instead. |
| 277 void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer, | 276 void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer, |
| 278 bool call_code_immediate, | 277 bool call_code_immediate, |
| 279 bool call_address_immediate) { | 278 bool call_address_immediate) { |
| 280 OperandGenerator g(this); | 279 OperandGenerator g(this); |
| 281 DCHECK_EQ(call->op()->ValueOutputCount(), | 280 DCHECK_LE(call->op()->ValueOutputCount(), |
| 282 static_cast<int>(buffer->descriptor->ReturnCount())); | 281 static_cast<int>(buffer->descriptor->ReturnCount())); |
| 283 DCHECK_EQ( | 282 DCHECK_EQ( |
| 284 call->op()->ValueInputCount(), | 283 call->op()->ValueInputCount(), |
| 285 static_cast<int>(buffer->input_count() + buffer->frame_state_count())); | 284 static_cast<int>(buffer->input_count() + buffer->frame_state_count())); |
| 286 | 285 |
| 287 if (buffer->descriptor->ReturnCount() > 0) { | 286 if (buffer->descriptor->ReturnCount() > 0) { |
| 288 // Collect the projections that represent multiple outputs from this call. | 287 // Collect the projections that represent multiple outputs from this call. |
| 289 if (buffer->descriptor->ReturnCount() == 1) { | 288 if (buffer->descriptor->ReturnCount() == 1) { |
| 290 buffer->output_nodes.push_back(call); | 289 buffer->output_nodes.push_back(call); |
| 291 } else { | 290 } else { |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 457 #endif | 456 #endif |
| 458 | 457 |
| 459 Node* input = block->control_input(); | 458 Node* input = block->control_input(); |
| 460 switch (block->control()) { | 459 switch (block->control()) { |
| 461 case BasicBlock::kGoto: | 460 case BasicBlock::kGoto: |
| 462 return VisitGoto(block->SuccessorAt(0)); | 461 return VisitGoto(block->SuccessorAt(0)); |
| 463 case BasicBlock::kCall: { | 462 case BasicBlock::kCall: { |
| 464 DCHECK_EQ(IrOpcode::kCall, input->opcode()); | 463 DCHECK_EQ(IrOpcode::kCall, input->opcode()); |
| 465 BasicBlock* success = block->SuccessorAt(0); | 464 BasicBlock* success = block->SuccessorAt(0); |
| 466 BasicBlock* exception = block->SuccessorAt(1); | 465 BasicBlock* exception = block->SuccessorAt(1); |
| 467 return VisitCall(input, exception, NORMAL_CALL), VisitGoto(success); | 466 return VisitCall(input, exception), VisitGoto(success); |
| 467 } |
| 468 case BasicBlock::kTailCall: { |
| 469 DCHECK_EQ(IrOpcode::kTailCall, input->opcode()); |
| 470 return VisitTailCall(input); |
| 468 } | 471 } |
| 469 case BasicBlock::kBranch: { | 472 case BasicBlock::kBranch: { |
| 470 DCHECK_EQ(IrOpcode::kBranch, input->opcode()); | 473 DCHECK_EQ(IrOpcode::kBranch, input->opcode()); |
| 471 BasicBlock* tbranch = block->SuccessorAt(0); | 474 BasicBlock* tbranch = block->SuccessorAt(0); |
| 472 BasicBlock* fbranch = block->SuccessorAt(1); | 475 BasicBlock* fbranch = block->SuccessorAt(1); |
| 473 if (tbranch == fbranch) return VisitGoto(tbranch); | 476 if (tbranch == fbranch) return VisitGoto(tbranch); |
| 474 // Treat special Branch(Always, IfTrue, IfFalse) as Goto(IfTrue). | 477 // Treat special Branch(Always, IfTrue, IfFalse) as Goto(IfTrue). |
| 475 Node* const condition = input->InputAt(0); | 478 Node* const condition = input->InputAt(0); |
| 476 if (condition->opcode() == IrOpcode::kAlways) return VisitGoto(tbranch); | 479 if (condition->opcode() == IrOpcode::kAlways) return VisitGoto(tbranch); |
| 477 return VisitBranch(input, tbranch, fbranch); | 480 return VisitBranch(input, tbranch, fbranch); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 500 DCHECK_LE(sw.min_value, sw.max_value); | 503 DCHECK_LE(sw.min_value, sw.max_value); |
| 501 // Note that {value_range} can be 0 if {min_value} is -2^31 and | 504 // Note that {value_range} can be 0 if {min_value} is -2^31 and |
| 502 // {max_value} | 505 // {max_value} |
| 503 // is 2^31-1, so don't assume that it's non-zero below. | 506 // is 2^31-1, so don't assume that it's non-zero below. |
| 504 sw.value_range = 1u + bit_cast<uint32_t>(sw.max_value) - | 507 sw.value_range = 1u + bit_cast<uint32_t>(sw.max_value) - |
| 505 bit_cast<uint32_t>(sw.min_value); | 508 bit_cast<uint32_t>(sw.min_value); |
| 506 return VisitSwitch(input, sw); | 509 return VisitSwitch(input, sw); |
| 507 } | 510 } |
| 508 case BasicBlock::kReturn: { | 511 case BasicBlock::kReturn: { |
| 509 DCHECK_EQ(IrOpcode::kReturn, input->opcode()); | 512 DCHECK_EQ(IrOpcode::kReturn, input->opcode()); |
| 510 return VisitReturn(input); | 513 return VisitReturn(input->InputAt(0)); |
| 511 } | 514 } |
| 512 case BasicBlock::kDeoptimize: { | 515 case BasicBlock::kDeoptimize: { |
| 513 // If the result itself is a return, return its input. | 516 // If the result itself is a return, return its input. |
| 514 Node* value = | 517 Node* value = |
| 515 (input != nullptr && input->opcode() == IrOpcode::kDeoptimize) | 518 (input != nullptr && input->opcode() == IrOpcode::kDeoptimize) |
| 516 ? input->InputAt(0) | 519 ? input->InputAt(0) |
| 517 : input; | 520 : input; |
| 518 return VisitDeoptimize(value); | 521 return VisitDeoptimize(value); |
| 519 } | 522 } |
| 520 case BasicBlock::kThrow: | 523 case BasicBlock::kThrow: |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 577 case IrOpcode::kFloat64Constant: | 580 case IrOpcode::kFloat64Constant: |
| 578 return MarkAsFloat64(node), VisitConstant(node); | 581 return MarkAsFloat64(node), VisitConstant(node); |
| 579 case IrOpcode::kHeapConstant: | 582 case IrOpcode::kHeapConstant: |
| 580 return MarkAsReference(node), VisitConstant(node); | 583 return MarkAsReference(node), VisitConstant(node); |
| 581 case IrOpcode::kNumberConstant: { | 584 case IrOpcode::kNumberConstant: { |
| 582 double value = OpParameter<double>(node); | 585 double value = OpParameter<double>(node); |
| 583 if (!IsSmiDouble(value)) MarkAsReference(node); | 586 if (!IsSmiDouble(value)) MarkAsReference(node); |
| 584 return VisitConstant(node); | 587 return VisitConstant(node); |
| 585 } | 588 } |
| 586 case IrOpcode::kCall: | 589 case IrOpcode::kCall: |
| 587 return VisitCall(node, nullptr, NORMAL_CALL); | 590 return VisitCall(node); |
| 588 case IrOpcode::kFrameState: | 591 case IrOpcode::kFrameState: |
| 589 case IrOpcode::kStateValues: | 592 case IrOpcode::kStateValues: |
| 590 return; | 593 return; |
| 591 case IrOpcode::kLoad: { | 594 case IrOpcode::kLoad: { |
| 592 LoadRepresentation rep = OpParameter<LoadRepresentation>(node); | 595 LoadRepresentation rep = OpParameter<LoadRepresentation>(node); |
| 593 MarkAsRepresentation(rep, node); | 596 MarkAsRepresentation(rep, node); |
| 594 return VisitLoad(node); | 597 return VisitLoad(node); |
| 595 } | 598 } |
| 596 case IrOpcode::kStore: | 599 case IrOpcode::kStore: |
| 597 return VisitStore(node); | 600 return VisitStore(node); |
| (...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 982 } | 985 } |
| 983 | 986 |
| 984 | 987 |
| 985 void InstructionSelector::VisitGoto(BasicBlock* target) { | 988 void InstructionSelector::VisitGoto(BasicBlock* target) { |
| 986 // jump to the next block. | 989 // jump to the next block. |
| 987 OperandGenerator g(this); | 990 OperandGenerator g(this); |
| 988 Emit(kArchJmp, g.NoOutput(), g.Label(target)); | 991 Emit(kArchJmp, g.NoOutput(), g.Label(target)); |
| 989 } | 992 } |
| 990 | 993 |
| 991 | 994 |
| 992 namespace { | 995 void InstructionSelector::VisitReturn(Node* value) { |
| 993 | |
| 994 // Returns the call node if the given return node is part of a tail call, | |
| 995 // nullptr otherwise. | |
| 996 Node* TryMatchTailCall(Node* ret) { | |
| 997 // The value which is returned must be the result of a potential tail call, | |
| 998 // there must be no try/catch/finally around the call, and there must be no | |
| 999 // effects between the call and the return. | |
| 1000 Node* call = NodeProperties::GetValueInput(ret, 0); | |
| 1001 if (call->opcode() != IrOpcode::kCall || | |
| 1002 !OpParameter<const CallDescriptor*>(call)->SupportsTailCalls() || | |
| 1003 NodeProperties::IsExceptionalCall(call) || | |
| 1004 NodeProperties::GetEffectInput(ret, 0) != call) { | |
| 1005 return nullptr; | |
| 1006 } | |
| 1007 // Furthermore, control has to flow via an IfSuccess from the call (for calls | |
| 1008 // which can throw), or the return and the call have to use the same control | |
| 1009 // input (for calls which can't throw). | |
| 1010 Node* control = NodeProperties::GetControlInput(ret, 0); | |
| 1011 bool found = (control->opcode() == IrOpcode::kIfSuccess) | |
| 1012 ? (NodeProperties::GetControlInput(control, 0) == call) | |
| 1013 : (control == NodeProperties::GetControlInput(call, 0)); | |
| 1014 return found ? call : nullptr; | |
| 1015 } | |
| 1016 | |
| 1017 } // namespace | |
| 1018 | |
| 1019 | |
| 1020 void InstructionSelector::VisitReturn(Node* node) { | |
| 1021 if (FLAG_turbo_tail_calls) { | |
| 1022 Node* call = TryMatchTailCall(node); | |
| 1023 if (call != nullptr) { | |
| 1024 const CallDescriptor* desc = OpParameter<const CallDescriptor*>(call); | |
| 1025 if (desc->UsesOnlyRegisters() && | |
| 1026 desc->HasSameReturnLocationsAs(linkage()->GetIncomingDescriptor())) { | |
| 1027 return VisitCall(call, nullptr, TAIL_CALL); | |
| 1028 } | |
| 1029 } | |
| 1030 } | |
| 1031 Node* value = NodeProperties::GetValueInput(node, 0); | |
| 1032 DCHECK_NOT_NULL(value); | 996 DCHECK_NOT_NULL(value); |
| 1033 OperandGenerator g(this); | 997 OperandGenerator g(this); |
| 1034 Emit(kArchRet, g.NoOutput(), | 998 Emit(kArchRet, g.NoOutput(), |
| 1035 g.UseLocation(value, linkage()->GetReturnLocation(), | 999 g.UseLocation(value, linkage()->GetReturnLocation(), |
| 1036 linkage()->GetReturnType())); | 1000 linkage()->GetReturnType())); |
| 1037 } | 1001 } |
| 1038 | 1002 |
| 1039 | 1003 |
| 1040 void InstructionSelector::VisitDeoptimize(Node* value) { | 1004 void InstructionSelector::VisitDeoptimize(Node* value) { |
| 1041 OperandGenerator g(this); | 1005 OperandGenerator g(this); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1152 | 1116 |
| 1153 | 1117 |
| 1154 #if !V8_TURBOFAN_BACKEND | 1118 #if !V8_TURBOFAN_BACKEND |
| 1155 | 1119 |
| 1156 #define DECLARE_UNIMPLEMENTED_SELECTOR(x) \ | 1120 #define DECLARE_UNIMPLEMENTED_SELECTOR(x) \ |
| 1157 void InstructionSelector::Visit##x(Node* node) { UNIMPLEMENTED(); } | 1121 void InstructionSelector::Visit##x(Node* node) { UNIMPLEMENTED(); } |
| 1158 MACHINE_OP_LIST(DECLARE_UNIMPLEMENTED_SELECTOR) | 1122 MACHINE_OP_LIST(DECLARE_UNIMPLEMENTED_SELECTOR) |
| 1159 #undef DECLARE_UNIMPLEMENTED_SELECTOR | 1123 #undef DECLARE_UNIMPLEMENTED_SELECTOR |
| 1160 | 1124 |
| 1161 | 1125 |
| 1162 void InstructionSelector::VisitCall(Node* node, BasicBlock* handler, | 1126 void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { |
| 1163 CallMode call_mode) { | |
| 1164 UNIMPLEMENTED(); | 1127 UNIMPLEMENTED(); |
| 1165 } | 1128 } |
| 1166 | 1129 |
| 1167 | 1130 |
| 1131 void InstructionSelector::VisitTailCall(Node* node) { UNIMPLEMENTED(); } |
| 1132 |
| 1133 |
| 1168 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, | 1134 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch, |
| 1169 BasicBlock* fbranch) { | 1135 BasicBlock* fbranch) { |
| 1170 UNIMPLEMENTED(); | 1136 UNIMPLEMENTED(); |
| 1171 } | 1137 } |
| 1172 | 1138 |
| 1173 | 1139 |
| 1174 void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { | 1140 void InstructionSelector::VisitSwitch(Node* node, const SwitchInfo& sw) { |
| 1175 UNIMPLEMENTED(); | 1141 UNIMPLEMENTED(); |
| 1176 } | 1142 } |
| 1177 | 1143 |
| 1178 | 1144 |
| 1179 // static | 1145 // static |
| 1180 MachineOperatorBuilder::Flags | 1146 MachineOperatorBuilder::Flags |
| 1181 InstructionSelector::SupportedMachineOperatorFlags() { | 1147 InstructionSelector::SupportedMachineOperatorFlags() { |
| 1182 return MachineOperatorBuilder::Flag::kNoFlags; | 1148 return MachineOperatorBuilder::Flag::kNoFlags; |
| 1183 } | 1149 } |
| 1184 | 1150 |
| 1185 #endif // !V8_TURBOFAN_BACKEND | 1151 #endif // !V8_TURBOFAN_BACKEND |
| 1186 | 1152 |
| 1187 } // namespace compiler | 1153 } // namespace compiler |
| 1188 } // namespace internal | 1154 } // namespace internal |
| 1189 } // namespace v8 | 1155 } // namespace v8 |
| OLD | NEW |