Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(560)

Side by Side Diff: src/compiler/instruction-selector.cc

Issue 1114163005: [turbofan] Fix tail call optimization. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698