v8/test/unittests/compiler/tail-call-optimization-unittest.cc
Michael Starzinger 6fca2cfae2 [turbofan] Elide redundant {IfSuccess} control projections.
This changes the IR to no longer require single {IfSuccess} projection
nodes unless there is a corresponding {IfException} node that links the
potentially throwing call to an exception handler. This reduces graph
size as well as compilation time when exception handlers aren't present.

The new invariant for potentially throwing nodes is: Nodes that can
potentially throw either have both IfSuccess/IfException projections as
the only control uses and no direct control uses, or no projections at
all and solely direct control uses.

R=jarin@chromium.org

Change-Id: I3d9cd816d74ad5af13e0673da7ec7a98f1ecdc7e
Reviewed-on: https://chromium-review.googlesource.com/449715
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43814}
2017-03-15 09:26:18 +00:00

164 lines
7.1 KiB
C++

// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/compiler/linkage.h"
#include "src/compiler/tail-call-optimization.h"
#include "test/unittests/compiler/graph-unittest.h"
#include "test/unittests/compiler/node-test-utils.h"
namespace v8 {
namespace internal {
namespace compiler {
class TailCallOptimizationTest : public GraphTest {
public:
explicit TailCallOptimizationTest(int num_parameters = 1)
: GraphTest(num_parameters) {}
~TailCallOptimizationTest() override {}
protected:
Reduction Reduce(Node* node) {
TailCallOptimization tco(common(), graph());
return tco.Reduce(node);
}
};
TEST_F(TailCallOptimizationTest, CallCodeObject0) {
LinkageLocation kLocationSignature[] = {
LinkageLocation::ForRegister(0, MachineType::Pointer()),
LinkageLocation::ForRegister(1, MachineType::Pointer())};
const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
CallDescriptor::kCallCodeObject, MachineType::AnyTagged(),
LinkageLocation::ForRegister(0, MachineType::Pointer()),
new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
Operator::kNoProperties, 0, 0, CallDescriptor::kNoFlags);
Node* p0 = Parameter(0);
Node* p1 = Parameter(1);
Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
graph()->start(), graph()->start());
Node* zero = graph()->NewNode(common()->Int32Constant(0));
Node* ret = graph()->NewNode(common()->Return(), zero, call, call, call);
Reduction r = Reduce(ret);
ASSERT_FALSE(r.Changed());
}
TEST_F(TailCallOptimizationTest, CallCodeObject1) {
LinkageLocation kLocationSignature[] = {
LinkageLocation::ForRegister(0, MachineType::Pointer()),
LinkageLocation::ForRegister(1, MachineType::Pointer())};
const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
CallDescriptor::kCallCodeObject, MachineType::AnyTagged(),
LinkageLocation::ForRegister(0, MachineType::Pointer()),
new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls);
Node* p0 = Parameter(0);
Node* p1 = Parameter(1);
Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
graph()->start(), graph()->start());
Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
Node* if_exception = graph()->NewNode(common()->IfException(), call, call);
Node* zero = graph()->NewNode(common()->Int32Constant(0));
Node* ret =
graph()->NewNode(common()->Return(), zero, call, call, if_success);
Node* end = graph()->NewNode(common()->End(1), if_exception);
graph()->SetEnd(end);
Reduction r = Reduce(ret);
ASSERT_FALSE(r.Changed());
}
TEST_F(TailCallOptimizationTest, CallCodeObject2) {
LinkageLocation kLocationSignature[] = {
LinkageLocation::ForRegister(0, MachineType::Pointer()),
LinkageLocation::ForRegister(1, MachineType::Pointer())};
const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
CallDescriptor::kCallCodeObject, MachineType::AnyTagged(),
LinkageLocation::ForRegister(0, MachineType::Pointer()),
new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls);
Node* p0 = Parameter(0);
Node* p1 = Parameter(1);
Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
graph()->start(), graph()->start());
Node* zero = graph()->NewNode(common()->Int32Constant(0));
Node* ret = graph()->NewNode(common()->Return(), zero, call, call, call);
Reduction r = Reduce(ret);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsTailCall(kCallDescriptor, p0, p1,
graph()->start(), graph()->start()));
}
TEST_F(TailCallOptimizationTest, CallJSFunction0) {
LinkageLocation kLocationSignature[] = {
LinkageLocation::ForRegister(0, MachineType::Pointer()),
LinkageLocation::ForRegister(1, MachineType::Pointer())};
const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
CallDescriptor::kCallJSFunction, MachineType::AnyTagged(),
LinkageLocation::ForRegister(0, MachineType::Pointer()),
new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
Operator::kNoProperties, 0, 0, CallDescriptor::kNoFlags);
Node* p0 = Parameter(0);
Node* p1 = Parameter(1);
Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
graph()->start(), graph()->start());
Node* zero = graph()->NewNode(common()->Int32Constant(0));
Node* ret = graph()->NewNode(common()->Return(), zero, call, call, call);
Reduction r = Reduce(ret);
ASSERT_FALSE(r.Changed());
}
TEST_F(TailCallOptimizationTest, CallJSFunction1) {
LinkageLocation kLocationSignature[] = {
LinkageLocation::ForRegister(0, MachineType::Pointer()),
LinkageLocation::ForRegister(1, MachineType::Pointer())};
const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
CallDescriptor::kCallJSFunction, MachineType::AnyTagged(),
LinkageLocation::ForRegister(0),
new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls);
Node* p0 = Parameter(0);
Node* p1 = Parameter(1);
Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
graph()->start(), graph()->start());
Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
Node* if_exception = graph()->NewNode(common()->IfException(), call, call);
Node* zero = graph()->NewNode(common()->Int32Constant(0));
Node* ret =
graph()->NewNode(common()->Return(), zero, call, call, if_success);
Node* end = graph()->NewNode(common()->End(1), if_exception);
graph()->SetEnd(end);
Reduction r = Reduce(ret);
ASSERT_FALSE(r.Changed());
}
TEST_F(TailCallOptimizationTest, CallJSFunction2) {
LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
LinkageLocation::ForRegister(1)};
const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
CallDescriptor::kCallJSFunction, MachineType::AnyTagged(),
LinkageLocation::ForRegister(0),
new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
Operator::kNoProperties, 0, 0, CallDescriptor::kSupportsTailCalls);
Node* p0 = Parameter(0);
Node* p1 = Parameter(1);
Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
graph()->start(), graph()->start());
Node* zero = graph()->NewNode(common()->Int32Constant(0));
Node* ret = graph()->NewNode(common()->Return(), zero, call, call, call);
Reduction r = Reduce(ret);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsTailCall(kCallDescriptor, p0, p1,
graph()->start(), graph()->start()));
}
} // namespace compiler
} // namespace internal
} // namespace v8