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 |