2015-07-22 18:27:16 +00:00
|
|
|
// Copyright 2014 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/common-operator.h"
|
|
|
|
#include "src/compiler/graph.h"
|
|
|
|
#include "src/compiler/linkage.h"
|
|
|
|
#include "src/compiler/node.h"
|
|
|
|
#include "test/unittests/test-utils.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace compiler {
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2015-12-10 09:03:30 +00:00
|
|
|
MachineType kMachineTypes[] = {
|
|
|
|
MachineType::AnyTagged(), MachineType::AnyTagged(),
|
|
|
|
MachineType::AnyTagged(), MachineType::AnyTagged(),
|
|
|
|
MachineType::AnyTagged(), MachineType::AnyTagged(),
|
|
|
|
MachineType::AnyTagged(), MachineType::AnyTagged()};
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class LinkageTailCall : public TestWithZone {
|
|
|
|
protected:
|
|
|
|
CallDescriptor* NewStandardCallDescriptor(LocationSignature* locations) {
|
|
|
|
DCHECK(arraysize(kMachineTypes) >=
|
|
|
|
locations->return_count() + locations->parameter_count());
|
2016-07-11 10:37:24 +00:00
|
|
|
return new (zone()) CallDescriptor(
|
|
|
|
CallDescriptor::kCallCodeObject, MachineType::AnyTagged(),
|
|
|
|
LinkageLocation::ForAnyRegister(MachineType::Pointer()),
|
|
|
|
locations, // location_sig
|
|
|
|
0, // js_parameter_count
|
|
|
|
Operator::kNoProperties, // properties
|
|
|
|
0, // callee-saved
|
|
|
|
0, // callee-saved fp
|
|
|
|
CallDescriptor::kNoFlags, // flags,
|
|
|
|
"");
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
2015-07-30 14:52:13 +00:00
|
|
|
LinkageLocation StackLocation(int loc) {
|
2016-07-11 10:37:24 +00:00
|
|
|
return LinkageLocation::ForCallerFrameSlot(-loc, MachineType::Pointer());
|
2015-07-30 14:52:13 +00:00
|
|
|
}
|
2015-07-22 18:27:16 +00:00
|
|
|
|
2015-07-30 14:52:13 +00:00
|
|
|
LinkageLocation RegisterLocation(int loc) {
|
2016-07-11 10:37:24 +00:00
|
|
|
return LinkageLocation::ForRegister(loc, MachineType::Pointer());
|
2015-07-30 14:52:13 +00:00
|
|
|
}
|
2015-07-22 18:27:16 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(LinkageTailCall, EmptyToEmpty) {
|
|
|
|
LocationSignature locations(0, 0, nullptr);
|
|
|
|
CallDescriptor* desc = NewStandardCallDescriptor(&locations);
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
|
|
const Operator* op = common.Call(desc);
|
|
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
2016-07-12 08:39:31 +00:00
|
|
|
EXPECT_TRUE(desc->CanTailCall(node));
|
|
|
|
const CallDescriptor* callee = CallDescriptorOf(node->op());
|
|
|
|
int stack_param_delta = callee->GetStackParameterDelta(desc);
|
2015-11-13 16:08:12 +00:00
|
|
|
EXPECT_EQ(0, stack_param_delta);
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(LinkageTailCall, SameReturn) {
|
|
|
|
// Caller
|
|
|
|
LinkageLocation location_array[] = {RegisterLocation(0)};
|
|
|
|
LocationSignature locations1(1, 0, location_array);
|
|
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
// Callee
|
|
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
|
|
const Operator* op = common.Call(desc2);
|
|
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
2016-07-12 08:39:31 +00:00
|
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
|
|
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
|
2015-11-13 16:08:12 +00:00
|
|
|
EXPECT_EQ(0, stack_param_delta);
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(LinkageTailCall, DifferingReturn) {
|
|
|
|
// Caller
|
|
|
|
LinkageLocation location_array1[] = {RegisterLocation(0)};
|
|
|
|
LocationSignature locations1(1, 0, location_array1);
|
|
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
// Callee
|
|
|
|
LinkageLocation location_array2[] = {RegisterLocation(1)};
|
|
|
|
LocationSignature locations2(1, 0, location_array2);
|
|
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
|
|
const Operator* op = common.Call(desc2);
|
|
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
2016-07-12 08:39:31 +00:00
|
|
|
EXPECT_TRUE(!desc1->CanTailCall(node));
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(LinkageTailCall, MoreRegisterParametersCallee) {
|
|
|
|
// Caller
|
|
|
|
LinkageLocation location_array1[] = {RegisterLocation(0)};
|
|
|
|
LocationSignature locations1(1, 0, location_array1);
|
|
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
// Callee
|
|
|
|
LinkageLocation location_array2[] = {RegisterLocation(0),
|
|
|
|
RegisterLocation(0)};
|
|
|
|
LocationSignature locations2(1, 1, location_array2);
|
|
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
|
|
const Operator* op = common.Call(desc2);
|
|
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
2016-07-12 08:39:31 +00:00
|
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
|
|
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
|
2015-11-13 16:08:12 +00:00
|
|
|
EXPECT_EQ(0, stack_param_delta);
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(LinkageTailCall, MoreRegisterParametersCaller) {
|
|
|
|
// Caller
|
|
|
|
LinkageLocation location_array1[] = {RegisterLocation(0),
|
|
|
|
RegisterLocation(0)};
|
|
|
|
LocationSignature locations1(1, 1, location_array1);
|
|
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
// Callee
|
|
|
|
LinkageLocation location_array2[] = {RegisterLocation(0)};
|
|
|
|
LocationSignature locations2(1, 0, location_array2);
|
|
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
|
|
const Operator* op = common.Call(desc2);
|
|
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
2016-07-12 08:39:31 +00:00
|
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
|
|
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
|
2015-11-13 16:08:12 +00:00
|
|
|
EXPECT_EQ(0, stack_param_delta);
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(LinkageTailCall, MoreRegisterAndStackParametersCallee) {
|
|
|
|
// Caller
|
|
|
|
LinkageLocation location_array1[] = {RegisterLocation(0)};
|
|
|
|
LocationSignature locations1(1, 0, location_array1);
|
|
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
// Callee
|
|
|
|
LinkageLocation location_array2[] = {RegisterLocation(0), RegisterLocation(0),
|
|
|
|
RegisterLocation(1), StackLocation(1)};
|
|
|
|
LocationSignature locations2(1, 3, location_array2);
|
|
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
|
|
const Operator* op = common.Call(desc2);
|
|
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
2016-07-12 08:39:31 +00:00
|
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
|
|
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
|
[turbofan]: Support using push instructions for setting up tail call parameters
This optimizes the passing of stack parameters in function calls.
For some architectures (ia32/x64), using pushes when possible instead
of bumping the stack and then storing parameters generates much
smaller code, and in some cases is faster (e.g. when a push of a memory
location can implement a memory-to-memory copy and thus elide an
intermediate load. On others (e.g. ARM), the benefit is smaller, where
it's only possible to elide direct stack pointer adjustment in certain cases
or combine multiple register stores into a single instruction in other limited
situations. On yet other platforms (ARM64, MIPS), there are no push instructions,
and this optimization isn't used at all.
Ideally, this mechanism would be used for both tail calls and normal calls,
but "normal" calls are currently pretty efficient, and tail calls are very
inefficient, so this CL sets the bar low for building a new mechanism to
handle parameter pushing that only needs to raise the bar on tail calls for now.
The key aspect of this change is that adjustment to the stack pointer
for tail calls (and perhaps later real calls) is an explicit step separate from
instruction selection and gap resolution, but aware of both, making it possible
to safely recognize gap moves that are actually pushes.
Review-Url: https://codereview.chromium.org/2082263002
Cr-Commit-Position: refs/heads/master@{#37477}
2016-07-01 11:28:00 +00:00
|
|
|
EXPECT_EQ(1, stack_param_delta);
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(LinkageTailCall, MoreRegisterAndStackParametersCaller) {
|
|
|
|
// Caller
|
|
|
|
LinkageLocation location_array[] = {RegisterLocation(0), RegisterLocation(0),
|
|
|
|
RegisterLocation(1), StackLocation(1)};
|
|
|
|
LocationSignature locations1(1, 3, location_array);
|
|
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
// Callee
|
|
|
|
LinkageLocation location_array2[] = {RegisterLocation(0)};
|
|
|
|
LocationSignature locations2(1, 0, location_array2);
|
|
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
|
|
const Operator* op = common.Call(desc2);
|
|
|
|
Node* const node = Node::New(zone(), 1, op, 0, nullptr, false);
|
2016-07-12 08:39:31 +00:00
|
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
|
|
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
|
[turbofan]: Support using push instructions for setting up tail call parameters
This optimizes the passing of stack parameters in function calls.
For some architectures (ia32/x64), using pushes when possible instead
of bumping the stack and then storing parameters generates much
smaller code, and in some cases is faster (e.g. when a push of a memory
location can implement a memory-to-memory copy and thus elide an
intermediate load. On others (e.g. ARM), the benefit is smaller, where
it's only possible to elide direct stack pointer adjustment in certain cases
or combine multiple register stores into a single instruction in other limited
situations. On yet other platforms (ARM64, MIPS), there are no push instructions,
and this optimization isn't used at all.
Ideally, this mechanism would be used for both tail calls and normal calls,
but "normal" calls are currently pretty efficient, and tail calls are very
inefficient, so this CL sets the bar low for building a new mechanism to
handle parameter pushing that only needs to raise the bar on tail calls for now.
The key aspect of this change is that adjustment to the stack pointer
for tail calls (and perhaps later real calls) is an explicit step separate from
instruction selection and gap resolution, but aware of both, making it possible
to safely recognize gap moves that are actually pushes.
Review-Url: https://codereview.chromium.org/2082263002
Cr-Commit-Position: refs/heads/master@{#37477}
2016-07-01 11:28:00 +00:00
|
|
|
EXPECT_EQ(-1, stack_param_delta);
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(LinkageTailCall, MatchingStackParameters) {
|
|
|
|
// Caller
|
|
|
|
LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
|
|
|
|
StackLocation(2), StackLocation(1)};
|
|
|
|
LocationSignature locations1(1, 3, location_array);
|
|
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
// Caller
|
|
|
|
LocationSignature locations2(1, 3, location_array);
|
|
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
|
|
Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
|
|
|
|
Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
|
|
|
|
Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
|
|
|
|
Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
|
|
|
|
Node* parameters[] = {p0, p1, p2, p3};
|
|
|
|
const Operator* op = common.Call(desc2);
|
|
|
|
Node* const node =
|
|
|
|
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
|
2016-07-12 08:39:31 +00:00
|
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
|
|
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
|
2015-11-13 16:08:12 +00:00
|
|
|
EXPECT_EQ(0, stack_param_delta);
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(LinkageTailCall, NonMatchingStackParameters) {
|
|
|
|
// Caller
|
|
|
|
LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
|
|
|
|
StackLocation(2), StackLocation(1)};
|
|
|
|
LocationSignature locations1(1, 3, location_array);
|
|
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
// Caller
|
|
|
|
LocationSignature locations2(1, 3, location_array);
|
|
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
|
|
Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
|
|
|
|
Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
|
|
|
|
Node* p2 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
|
|
|
|
Node* p3 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
|
|
|
|
Node* parameters[] = {p0, p1, p2, p3};
|
|
|
|
const Operator* op = common.Call(desc2);
|
|
|
|
Node* const node =
|
|
|
|
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
|
2016-07-12 08:39:31 +00:00
|
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
|
|
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
|
2015-11-13 16:08:12 +00:00
|
|
|
EXPECT_EQ(0, stack_param_delta);
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(LinkageTailCall, MatchingStackParametersExtraCallerRegisters) {
|
|
|
|
// Caller
|
|
|
|
LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
|
|
|
|
StackLocation(2), StackLocation(1),
|
|
|
|
RegisterLocation(0), RegisterLocation(1)};
|
|
|
|
LocationSignature locations1(1, 5, location_array);
|
|
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
// Caller
|
|
|
|
LocationSignature locations2(1, 3, location_array);
|
|
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
|
|
Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
|
|
|
|
Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
|
|
|
|
Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
|
|
|
|
Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
|
|
|
|
Node* parameters[] = {p0, p1, p2, p3};
|
|
|
|
const Operator* op = common.Call(desc2);
|
|
|
|
Node* const node =
|
|
|
|
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
|
2016-07-12 08:39:31 +00:00
|
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
|
|
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
|
2015-11-13 16:08:12 +00:00
|
|
|
EXPECT_EQ(0, stack_param_delta);
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(LinkageTailCall, MatchingStackParametersExtraCalleeRegisters) {
|
|
|
|
// Caller
|
|
|
|
LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
|
|
|
|
StackLocation(2), StackLocation(1),
|
|
|
|
RegisterLocation(0), RegisterLocation(1)};
|
|
|
|
LocationSignature locations1(1, 3, location_array);
|
|
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
// Caller
|
|
|
|
LocationSignature locations2(1, 5, location_array);
|
|
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
|
|
Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
|
|
|
|
Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
|
|
|
|
Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
|
|
|
|
Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
|
|
|
|
Node* p4 = Node::New(zone(), 0, common.Parameter(3), 0, nullptr, false);
|
|
|
|
Node* parameters[] = {p0, p1, p2, p3, p4};
|
|
|
|
const Operator* op = common.Call(desc2);
|
|
|
|
Node* const node =
|
|
|
|
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
|
2016-07-12 08:39:31 +00:00
|
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
|
|
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
|
2015-11-13 16:08:12 +00:00
|
|
|
EXPECT_EQ(0, stack_param_delta);
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(LinkageTailCall, MatchingStackParametersExtraCallerRegistersAndStack) {
|
|
|
|
// Caller
|
|
|
|
LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
|
|
|
|
StackLocation(2), StackLocation(1),
|
|
|
|
RegisterLocation(0), StackLocation(4)};
|
|
|
|
LocationSignature locations1(1, 5, location_array);
|
|
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
// Caller
|
|
|
|
LocationSignature locations2(1, 3, location_array);
|
|
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
|
|
Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
|
|
|
|
Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
|
|
|
|
Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
|
|
|
|
Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
|
|
|
|
Node* p4 = Node::New(zone(), 0, common.Parameter(3), 0, nullptr, false);
|
|
|
|
Node* parameters[] = {p0, p1, p2, p3, p4};
|
|
|
|
const Operator* op = common.Call(desc2);
|
|
|
|
Node* const node =
|
|
|
|
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
|
2016-07-12 08:39:31 +00:00
|
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
|
|
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
|
[turbofan]: Support using push instructions for setting up tail call parameters
This optimizes the passing of stack parameters in function calls.
For some architectures (ia32/x64), using pushes when possible instead
of bumping the stack and then storing parameters generates much
smaller code, and in some cases is faster (e.g. when a push of a memory
location can implement a memory-to-memory copy and thus elide an
intermediate load. On others (e.g. ARM), the benefit is smaller, where
it's only possible to elide direct stack pointer adjustment in certain cases
or combine multiple register stores into a single instruction in other limited
situations. On yet other platforms (ARM64, MIPS), there are no push instructions,
and this optimization isn't used at all.
Ideally, this mechanism would be used for both tail calls and normal calls,
but "normal" calls are currently pretty efficient, and tail calls are very
inefficient, so this CL sets the bar low for building a new mechanism to
handle parameter pushing that only needs to raise the bar on tail calls for now.
The key aspect of this change is that adjustment to the stack pointer
for tail calls (and perhaps later real calls) is an explicit step separate from
instruction selection and gap resolution, but aware of both, making it possible
to safely recognize gap moves that are actually pushes.
Review-Url: https://codereview.chromium.org/2082263002
Cr-Commit-Position: refs/heads/master@{#37477}
2016-07-01 11:28:00 +00:00
|
|
|
EXPECT_EQ(-1, stack_param_delta);
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TEST_F(LinkageTailCall, MatchingStackParametersExtraCalleeRegistersAndStack) {
|
|
|
|
// Caller
|
|
|
|
LinkageLocation location_array[] = {RegisterLocation(0), StackLocation(3),
|
|
|
|
StackLocation(2), RegisterLocation(0),
|
|
|
|
RegisterLocation(1), StackLocation(4)};
|
|
|
|
LocationSignature locations1(1, 3, location_array);
|
|
|
|
CallDescriptor* desc1 = NewStandardCallDescriptor(&locations1);
|
|
|
|
|
|
|
|
// Caller
|
|
|
|
LocationSignature locations2(1, 5, location_array);
|
|
|
|
CallDescriptor* desc2 = NewStandardCallDescriptor(&locations2);
|
|
|
|
|
|
|
|
CommonOperatorBuilder common(zone());
|
|
|
|
Node* p0 = Node::New(zone(), 0, nullptr, 0, nullptr, false);
|
|
|
|
Node* p1 = Node::New(zone(), 0, common.Parameter(0), 0, nullptr, false);
|
|
|
|
Node* p2 = Node::New(zone(), 0, common.Parameter(1), 0, nullptr, false);
|
|
|
|
Node* p3 = Node::New(zone(), 0, common.Parameter(2), 0, nullptr, false);
|
|
|
|
Node* p4 = Node::New(zone(), 0, common.Parameter(3), 0, nullptr, false);
|
|
|
|
Node* parameters[] = {p0, p1, p2, p3, p4};
|
|
|
|
const Operator* op = common.Call(desc2);
|
|
|
|
Node* const node =
|
|
|
|
Node::New(zone(), 1, op, arraysize(parameters), parameters, false);
|
2016-07-12 08:39:31 +00:00
|
|
|
EXPECT_TRUE(desc1->CanTailCall(node));
|
|
|
|
int stack_param_delta = desc2->GetStackParameterDelta(desc1);
|
[turbofan]: Support using push instructions for setting up tail call parameters
This optimizes the passing of stack parameters in function calls.
For some architectures (ia32/x64), using pushes when possible instead
of bumping the stack and then storing parameters generates much
smaller code, and in some cases is faster (e.g. when a push of a memory
location can implement a memory-to-memory copy and thus elide an
intermediate load. On others (e.g. ARM), the benefit is smaller, where
it's only possible to elide direct stack pointer adjustment in certain cases
or combine multiple register stores into a single instruction in other limited
situations. On yet other platforms (ARM64, MIPS), there are no push instructions,
and this optimization isn't used at all.
Ideally, this mechanism would be used for both tail calls and normal calls,
but "normal" calls are currently pretty efficient, and tail calls are very
inefficient, so this CL sets the bar low for building a new mechanism to
handle parameter pushing that only needs to raise the bar on tail calls for now.
The key aspect of this change is that adjustment to the stack pointer
for tail calls (and perhaps later real calls) is an explicit step separate from
instruction selection and gap resolution, but aware of both, making it possible
to safely recognize gap moves that are actually pushes.
Review-Url: https://codereview.chromium.org/2082263002
Cr-Commit-Position: refs/heads/master@{#37477}
2016-07-01 11:28:00 +00:00
|
|
|
EXPECT_EQ(1, stack_param_delta);
|
2015-07-22 18:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace compiler
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|