Index: src/compiler/instruction-selector.cc |
diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc |
index 3d6c1fedf77201810e0f606dd3e577214a0dee8d..ed44ade1027dd52dee6b8e7451dd7778253cdd2f 100644 |
--- a/src/compiler/instruction-selector.cc |
+++ b/src/compiler/instruction-selector.cc |
@@ -463,7 +463,7 @@ void InstructionSelector::VisitControl(BasicBlock* block) { |
DCHECK_EQ(IrOpcode::kCall, input->opcode()); |
BasicBlock* success = block->SuccessorAt(0); |
BasicBlock* exception = block->SuccessorAt(1); |
- return VisitCall(input, exception), VisitGoto(success); |
+ return VisitCall(input, exception, NORMAL_CALL), VisitGoto(success); |
} |
case BasicBlock::kBranch: { |
DCHECK_EQ(IrOpcode::kBranch, input->opcode()); |
@@ -506,7 +506,7 @@ void InstructionSelector::VisitControl(BasicBlock* block) { |
} |
case BasicBlock::kReturn: { |
DCHECK_EQ(IrOpcode::kReturn, input->opcode()); |
- return VisitReturn(input->InputAt(0)); |
+ return VisitReturn(input); |
} |
case BasicBlock::kDeoptimize: { |
// If the result itself is a return, return its input. |
@@ -583,7 +583,7 @@ void InstructionSelector::VisitNode(Node* node) { |
return VisitConstant(node); |
} |
case IrOpcode::kCall: |
- return VisitCall(node, nullptr); |
+ return VisitCall(node, nullptr, NORMAL_CALL); |
case IrOpcode::kFrameState: |
case IrOpcode::kStateValues: |
return; |
@@ -988,7 +988,46 @@ void InstructionSelector::VisitGoto(BasicBlock* target) { |
} |
-void InstructionSelector::VisitReturn(Node* value) { |
+namespace { |
+ |
+// Returns the call node if the given return node is part of a tail call, |
+// nullptr otherwise. |
+Node* TryMatchTailCall(Node* ret) { |
+ // The value which is returned must be the result of a potential tail call, |
+ // there must be no try/catch/finally around the call, and there must be no |
+ // effects between the call and the return. |
+ Node* call = NodeProperties::GetValueInput(ret, 0); |
+ if (call->opcode() != IrOpcode::kCall || |
+ !OpParameter<const CallDescriptor*>(call)->SupportsTailCalls() || |
+ NodeProperties::IsExceptionalCall(call) || |
+ NodeProperties::GetEffectInput(ret, 0) != call) { |
+ return nullptr; |
+ } |
+ // Furthermore, control has to flow via an IfSuccess from the call (for calls |
+ // which can throw), or the return and the call have to use the same control |
+ // input (for calls which can't throw). |
+ Node* control = NodeProperties::GetControlInput(ret, 0); |
+ bool found = (control->opcode() == IrOpcode::kIfSuccess) |
+ ? (NodeProperties::GetControlInput(control, 0) == call) |
+ : (control == NodeProperties::GetControlInput(call, 0)); |
+ return found ? call : nullptr; |
+} |
+ |
+} // namespace |
+ |
+ |
+void InstructionSelector::VisitReturn(Node* node) { |
+ if (FLAG_turbo_tail_calls) { |
+ Node* call = TryMatchTailCall(node); |
+ if (call != nullptr) { |
+ const CallDescriptor* desc = OpParameter<const CallDescriptor*>(call); |
+ if (desc->UsesOnlyRegisters() && |
+ desc->HasSameReturnLocationsAs(linkage()->GetIncomingDescriptor())) { |
+ return VisitCall(call, nullptr, TAIL_CALL); |
+ } |
+ } |
+ } |
+ Node* value = NodeProperties::GetValueInput(node, 0); |
DCHECK_NOT_NULL(value); |
OperandGenerator g(this); |
Emit(kArchRet, g.NoOutput(), |
@@ -1119,7 +1158,8 @@ MACHINE_OP_LIST(DECLARE_UNIMPLEMENTED_SELECTOR) |
#undef DECLARE_UNIMPLEMENTED_SELECTOR |
-void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) { |
+void InstructionSelector::VisitCall(Node* node, BasicBlock* handler, |
+ CallMode call_mode) { |
UNIMPLEMENTED(); |
} |