Index: src/compiler/instruction-selector.cc |
diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc |
index 1e2ab974854fd563640ae20861be9871eb9dfceb..4f91bfa7877c45b5eb720006bfb63345ce4cc356 100644 |
--- a/src/compiler/instruction-selector.cc |
+++ b/src/compiler/instruction-selector.cc |
@@ -516,7 +516,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()); |
@@ -559,7 +559,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. |
@@ -636,7 +636,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; |
@@ -1041,7 +1041,40 @@ void InstructionSelector::VisitGoto(BasicBlock* target) { |
} |
-void InstructionSelector::VisitReturn(Node* value) { |
+// Returns the call node if the given return node is part of a tail call, |
+// nullptr otherwise. |
+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.
|
+ // 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)->IsTailCallAllowed() || |
+ 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); |
+ return ((control->opcode() == IrOpcode::kIfSuccess) |
+ ? (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
|
+ : (control == NodeProperties::GetControlInput(call, 0))) |
+ ? call |
+ : nullptr; |
+} |
+ |
+ |
+void InstructionSelector::VisitReturn(Node* node) { |
+ if (FLAG_turbo_tail_calls) { |
+ Node* call = DetectTailCall(node); |
+ if (call != nullptr && |
+ OpParameter<const CallDescriptor*>(call)->UsesOnlyRegisters()) { |
+ return VisitCall(call, nullptr, TAIL_CALL); |
+ } |
+ } |
+ Node* value = NodeProperties::GetValueInput(node, 0); |
DCHECK_NOT_NULL(value); |
OperandGenerator g(this); |
Emit(kArchRet, g.NoOutput(), |