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

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

Issue 1108563002: Detect simple tail calls (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Handle callers with args 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"
(...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 #endif 509 #endif
510 510
511 Node* input = block->control_input(); 511 Node* input = block->control_input();
512 switch (block->control()) { 512 switch (block->control()) {
513 case BasicBlock::kGoto: 513 case BasicBlock::kGoto:
514 return VisitGoto(block->SuccessorAt(0)); 514 return VisitGoto(block->SuccessorAt(0));
515 case BasicBlock::kCall: { 515 case BasicBlock::kCall: {
516 DCHECK_EQ(IrOpcode::kCall, input->opcode()); 516 DCHECK_EQ(IrOpcode::kCall, input->opcode());
517 BasicBlock* success = block->SuccessorAt(0); 517 BasicBlock* success = block->SuccessorAt(0);
518 BasicBlock* exception = block->SuccessorAt(1); 518 BasicBlock* exception = block->SuccessorAt(1);
519 return VisitCall(input, exception), VisitGoto(success); 519 return VisitCall(input, exception, NORMAL_CALL), VisitGoto(success);
520 } 520 }
521 case BasicBlock::kBranch: { 521 case BasicBlock::kBranch: {
522 DCHECK_EQ(IrOpcode::kBranch, input->opcode()); 522 DCHECK_EQ(IrOpcode::kBranch, input->opcode());
523 BasicBlock* tbranch = block->SuccessorAt(0); 523 BasicBlock* tbranch = block->SuccessorAt(0);
524 BasicBlock* fbranch = block->SuccessorAt(1); 524 BasicBlock* fbranch = block->SuccessorAt(1);
525 if (tbranch == fbranch) return VisitGoto(tbranch); 525 if (tbranch == fbranch) return VisitGoto(tbranch);
526 // Treat special Branch(Always, IfTrue, IfFalse) as Goto(IfTrue). 526 // Treat special Branch(Always, IfTrue, IfFalse) as Goto(IfTrue).
527 Node* const condition = input->InputAt(0); 527 Node* const condition = input->InputAt(0);
528 if (condition->opcode() == IrOpcode::kAlways) return VisitGoto(tbranch); 528 if (condition->opcode() == IrOpcode::kAlways) return VisitGoto(tbranch);
529 return VisitBranch(input, tbranch, fbranch); 529 return VisitBranch(input, tbranch, fbranch);
(...skipping 22 matching lines...) Expand all
552 DCHECK_LE(sw.min_value, sw.max_value); 552 DCHECK_LE(sw.min_value, sw.max_value);
553 // Note that {value_range} can be 0 if {min_value} is -2^31 and 553 // Note that {value_range} can be 0 if {min_value} is -2^31 and
554 // {max_value} 554 // {max_value}
555 // is 2^31-1, so don't assume that it's non-zero below. 555 // is 2^31-1, so don't assume that it's non-zero below.
556 sw.value_range = 1u + bit_cast<uint32_t>(sw.max_value) - 556 sw.value_range = 1u + bit_cast<uint32_t>(sw.max_value) -
557 bit_cast<uint32_t>(sw.min_value); 557 bit_cast<uint32_t>(sw.min_value);
558 return VisitSwitch(input, sw); 558 return VisitSwitch(input, sw);
559 } 559 }
560 case BasicBlock::kReturn: { 560 case BasicBlock::kReturn: {
561 DCHECK_EQ(IrOpcode::kReturn, input->opcode()); 561 DCHECK_EQ(IrOpcode::kReturn, input->opcode());
562 return VisitReturn(input->InputAt(0)); 562 return VisitReturn(input);
563 } 563 }
564 case BasicBlock::kDeoptimize: { 564 case BasicBlock::kDeoptimize: {
565 // If the result itself is a return, return its input. 565 // If the result itself is a return, return its input.
566 Node* value = 566 Node* value =
567 (input != nullptr && input->opcode() == IrOpcode::kDeoptimize) 567 (input != nullptr && input->opcode() == IrOpcode::kDeoptimize)
568 ? input->InputAt(0) 568 ? input->InputAt(0)
569 : input; 569 : input;
570 return VisitDeoptimize(value); 570 return VisitDeoptimize(value);
571 } 571 }
572 case BasicBlock::kThrow: 572 case BasicBlock::kThrow:
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 case IrOpcode::kFloat64Constant: 629 case IrOpcode::kFloat64Constant:
630 return MarkAsDouble(node), VisitConstant(node); 630 return MarkAsDouble(node), VisitConstant(node);
631 case IrOpcode::kHeapConstant: 631 case IrOpcode::kHeapConstant:
632 return MarkAsReference(node), VisitConstant(node); 632 return MarkAsReference(node), VisitConstant(node);
633 case IrOpcode::kNumberConstant: { 633 case IrOpcode::kNumberConstant: {
634 double value = OpParameter<double>(node); 634 double value = OpParameter<double>(node);
635 if (!IsSmiDouble(value)) MarkAsReference(node); 635 if (!IsSmiDouble(value)) MarkAsReference(node);
636 return VisitConstant(node); 636 return VisitConstant(node);
637 } 637 }
638 case IrOpcode::kCall: 638 case IrOpcode::kCall:
639 return VisitCall(node, nullptr); 639 return VisitCall(node, nullptr, NORMAL_CALL);
640 case IrOpcode::kFrameState: 640 case IrOpcode::kFrameState:
641 case IrOpcode::kStateValues: 641 case IrOpcode::kStateValues:
642 return; 642 return;
643 case IrOpcode::kLoad: { 643 case IrOpcode::kLoad: {
644 LoadRepresentation rep = OpParameter<LoadRepresentation>(node); 644 LoadRepresentation rep = OpParameter<LoadRepresentation>(node);
645 MarkAsRepresentation(rep, node); 645 MarkAsRepresentation(rep, node);
646 return VisitLoad(node); 646 return VisitLoad(node);
647 } 647 }
648 case IrOpcode::kStore: 648 case IrOpcode::kStore:
649 return VisitStore(node); 649 return VisitStore(node);
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after
1034 } 1034 }
1035 1035
1036 1036
1037 void InstructionSelector::VisitGoto(BasicBlock* target) { 1037 void InstructionSelector::VisitGoto(BasicBlock* target) {
1038 // jump to the next block. 1038 // jump to the next block.
1039 OperandGenerator g(this); 1039 OperandGenerator g(this);
1040 Emit(kArchJmp, g.NoOutput(), g.Label(target)); 1040 Emit(kArchJmp, g.NoOutput(), g.Label(target));
1041 } 1041 }
1042 1042
1043 1043
1044 void InstructionSelector::VisitReturn(Node* value) { 1044 // Returns the call node if the given return node is part of a tail call,
1045 // nullptr otherwise.
1046 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.
1047 // The value which is returned must be the result of a potential tail call,
1048 // there must be no try/catch/finally around the call, and there must be no
1049 // effects between the call and the return.
1050 Node* call = NodeProperties::GetValueInput(ret, 0);
1051 if (call->opcode() != IrOpcode::kCall ||
1052 !OpParameter<const CallDescriptor*>(call)->IsTailCallAllowed() ||
1053 NodeProperties::IsExceptionalCall(call) ||
1054 NodeProperties::GetEffectInput(ret, 0) != call) {
1055 return nullptr;
1056 }
1057 // Furthermore, control has to flow via an IfSuccess from the call (for calls
1058 // which can throw), or the return and the call have to use the same control
1059 // input (for calls which can't throw).
1060 Node* control = NodeProperties::GetControlInput(ret, 0);
1061 return ((control->opcode() == IrOpcode::kIfSuccess)
1062 ? (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
1063 : (control == NodeProperties::GetControlInput(call, 0)))
1064 ? call
1065 : nullptr;
1066 }
1067
1068
1069 void InstructionSelector::VisitReturn(Node* node) {
1070 if (FLAG_turbo_tail_calls) {
1071 Node* call = DetectTailCall(node);
1072 if (call != nullptr &&
1073 OpParameter<const CallDescriptor*>(call)->UsesOnlyRegisters()) {
1074 return VisitCall(call, nullptr, TAIL_CALL);
1075 }
1076 }
1077 Node* value = NodeProperties::GetValueInput(node, 0);
1045 DCHECK_NOT_NULL(value); 1078 DCHECK_NOT_NULL(value);
1046 OperandGenerator g(this); 1079 OperandGenerator g(this);
1047 Emit(kArchRet, g.NoOutput(), 1080 Emit(kArchRet, g.NoOutput(),
1048 g.UseLocation(value, linkage()->GetReturnLocation(), 1081 g.UseLocation(value, linkage()->GetReturnLocation(),
1049 linkage()->GetReturnType())); 1082 linkage()->GetReturnType()));
1050 } 1083 }
1051 1084
1052 1085
1053 void InstructionSelector::VisitDeoptimize(Node* value) { 1086 void InstructionSelector::VisitDeoptimize(Node* value) {
1054 OperandGenerator g(this); 1087 OperandGenerator g(this);
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
1192 MachineOperatorBuilder::Flags 1225 MachineOperatorBuilder::Flags
1193 InstructionSelector::SupportedMachineOperatorFlags() { 1226 InstructionSelector::SupportedMachineOperatorFlags() {
1194 return MachineOperatorBuilder::Flag::kNoFlags; 1227 return MachineOperatorBuilder::Flag::kNoFlags;
1195 } 1228 }
1196 1229
1197 #endif // !V8_TURBOFAN_BACKEND 1230 #endif // !V8_TURBOFAN_BACKEND
1198 1231
1199 } // namespace compiler 1232 } // namespace compiler
1200 } // namespace internal 1233 } // namespace internal
1201 } // namespace v8 1234 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698