Commit eb04aaab authored by Joey Gouly's avatar Joey Gouly Committed by Commit Bot

[arm64] Use PokePair when preparing arguments

v8_Default_embedded_blob_size from the generated file gen/embedded.S
Before: 4984544
 After: 4979200

This gives a 0.1% size decrease to the embedded builtins.

Change-Id: Ie21c4360bd520380c779fc417185a1e4049c60ba
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1601253Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Martyn Capewell <martyn.capewell@arm.com>
Cr-Commit-Position: refs/heads/master@{#61471}
parent e347e266
......@@ -1703,15 +1703,13 @@ void InstructionSelector::EmitPrepareArguments(
int claim_count = static_cast<int>(arguments->size());
int slot = claim_count - 1;
claim_count = RoundUp(claim_count, 2);
// Bump the stack pointer(s).
// Bump the stack pointer.
if (claim_count > 0) {
// TODO(titzer): claim and poke probably take small immediates.
// TODO(titzer): it would be better to bump the sp here only
// and emit paired stores with increment for non c frames.
Emit(kArm64Claim, g.NoOutput(), g.TempImmediate(claim_count));
}
if (claim_count > 0) {
// Store padding, which might be overwritten.
Emit(kArm64Poke, g.NoOutput(), g.UseImmediate(0),
g.TempImmediate(claim_count - 1));
......@@ -1719,18 +1717,23 @@ void InstructionSelector::EmitPrepareArguments(
// Poke the arguments into the stack.
while (slot >= 0) {
Node* input_node = (*arguments)[slot].node;
// Skip any alignment holes in pushed nodes.
if (input_node != nullptr) {
Emit(kArm64Poke, g.NoOutput(), g.UseRegister(input_node),
PushParameter input0 = (*arguments)[slot];
PushParameter input1 = slot > 0 ? (*arguments)[slot - 1] : PushParameter();
// Emit a poke-pair if consecutive parameters have the same type.
// TODO(arm): Support consecutive Simd128 parameters.
if (input0.node != nullptr && input1.node != nullptr &&
input0.location.GetType() == input1.location.GetType()) {
Emit(kArm64PokePair, g.NoOutput(), g.UseRegister(input0.node),
g.UseRegister(input1.node), g.TempImmediate(slot));
slot -= 2;
} else if (input0.node != nullptr) {
Emit(kArm64Poke, g.NoOutput(), g.UseRegister(input0.node),
g.TempImmediate(slot));
slot--;
} else {
// Skip any alignment holes in pushed nodes.
slot--;
}
slot--;
// TODO(ahaas): Poke arguments in pairs if two subsequent arguments have the
// same type.
// Emit(kArm64PokePair, g.NoOutput(), g.UseRegister((*arguments)[slot]),
// g.UseRegister((*arguments)[slot - 1]), g.TempImmediate(slot));
// slot -= 2;
}
}
......
......@@ -4620,6 +4620,206 @@ TEST_F(InstructionSelectorTest, ExternalReferenceLoad2) {
EXPECT_NE(kMode_Root, s[0]->addressing_mode());
}
namespace {
// Builds a call with the specified signature and nodes as arguments.
// Then checks that the correct number of kArm64Poke and kArm64PokePair were
// generated.
void TestPokePair(InstructionSelectorTest::StreamBuilder& m, Zone* zone,
MachineSignature::Builder& builder, Node* nodes[],
int num_nodes, int expected_poke_pair, int expected_poke) {
auto call_descriptor =
InstructionSelectorTest::StreamBuilder::MakeSimpleCallDescriptor(
zone, builder.Build());
m.CallN(call_descriptor, num_nodes, nodes);
m.Return(m.UndefinedConstant());
auto s = m.Build();
int num_poke_pair = 0;
int num_poke = 0;
for (size_t i = 0; i < s.size(); ++i) {
if (s[i]->arch_opcode() == kArm64PokePair) {
num_poke_pair++;
}
if (s[i]->arch_opcode() == kArm64Poke) {
num_poke++;
}
}
EXPECT_EQ(expected_poke_pair, num_poke_pair);
// Note: The `+ 1` here comes from the padding Poke in
// EmitPrepareArguments.
EXPECT_EQ(expected_poke + 1, num_poke);
}
} // namespace
TEST_F(InstructionSelectorTest, PokePairPrepareArgumentsInt32) {
{
MachineSignature::Builder builder(zone(), 0, 3);
builder.AddParam(MachineType::Int32());
builder.AddParam(MachineType::Int32());
builder.AddParam(MachineType::Int32());
StreamBuilder m(this, MachineType::AnyTagged());
Node* nodes[] = {
m.UndefinedConstant(),
m.Int32Constant(0),
m.Int32Constant(0),
m.Int32Constant(0),
};
const int expected_poke_pair = 1;
const int expected_poke = 1;
TestPokePair(m, zone(), builder, nodes, arraysize(nodes),
expected_poke_pair, expected_poke);
}
{
MachineSignature::Builder builder(zone(), 0, 4);
builder.AddParam(MachineType::Int32());
builder.AddParam(MachineType::Int32());
builder.AddParam(MachineType::Int32());
builder.AddParam(MachineType::Int32());
StreamBuilder m(this, MachineType::AnyTagged());
Node* nodes[] = {
m.UndefinedConstant(), m.Int32Constant(0), m.Int32Constant(0),
m.Int32Constant(0), m.Int32Constant(0),
};
const int expected_poke_pair = 2;
const int expected_poke = 0;
TestPokePair(m, zone(), builder, nodes, arraysize(nodes),
expected_poke_pair, expected_poke);
}
}
TEST_F(InstructionSelectorTest, PokePairPrepareArgumentsInt64) {
MachineSignature::Builder builder(zone(), 0, 4);
builder.AddParam(MachineType::Int64());
builder.AddParam(MachineType::Int64());
builder.AddParam(MachineType::Int64());
builder.AddParam(MachineType::Int64());
StreamBuilder m(this, MachineType::AnyTagged());
Node* nodes[] = {
m.UndefinedConstant(), m.Int64Constant(0), m.Int64Constant(0),
m.Int64Constant(0), m.Int64Constant(0),
};
const int expected_poke_pair = 2;
const int expected_poke = 0;
TestPokePair(m, zone(), builder, nodes, arraysize(nodes), expected_poke_pair,
expected_poke);
}
TEST_F(InstructionSelectorTest, PokePairPrepareArgumentsFloat32) {
MachineSignature::Builder builder(zone(), 0, 4);
builder.AddParam(MachineType::Float32());
builder.AddParam(MachineType::Float32());
builder.AddParam(MachineType::Float32());
builder.AddParam(MachineType::Float32());
StreamBuilder m(this, MachineType::AnyTagged());
Node* nodes[] = {
m.UndefinedConstant(), m.Float32Constant(0.0f), m.Float32Constant(0.0f),
m.Float32Constant(0.0f), m.Float32Constant(0.0f),
};
const int expected_poke_pair = 2;
const int expected_poke = 0;
TestPokePair(m, zone(), builder, nodes, arraysize(nodes), expected_poke_pair,
expected_poke);
}
TEST_F(InstructionSelectorTest, PokePairPrepareArgumentsFloat64) {
MachineSignature::Builder builder(zone(), 0, 4);
builder.AddParam(MachineType::Float64());
builder.AddParam(MachineType::Float64());
builder.AddParam(MachineType::Float64());
builder.AddParam(MachineType::Float64());
StreamBuilder m(this, MachineType::AnyTagged());
Node* nodes[] = {
m.UndefinedConstant(), m.Float64Constant(0.0f), m.Float64Constant(0.0f),
m.Float64Constant(0.0f), m.Float64Constant(0.0f),
};
const int expected_poke_pair = 2;
const int expected_poke = 0;
TestPokePair(m, zone(), builder, nodes, arraysize(nodes), expected_poke_pair,
expected_poke);
}
TEST_F(InstructionSelectorTest, PokePairPrepareArgumentsIntFloatMixed) {
{
MachineSignature::Builder builder(zone(), 0, 4);
builder.AddParam(MachineType::Int32());
builder.AddParam(MachineType::Float32());
builder.AddParam(MachineType::Int32());
builder.AddParam(MachineType::Float32());
StreamBuilder m(this, MachineType::AnyTagged());
Node* nodes[] = {
m.UndefinedConstant(), m.Int32Constant(0), m.Float32Constant(0.0f),
m.Int32Constant(0), m.Float32Constant(0.0f),
};
const int expected_poke_pair = 0;
const int expected_poke = 4;
TestPokePair(m, zone(), builder, nodes, arraysize(nodes),
expected_poke_pair, expected_poke);
}
{
MachineSignature::Builder builder(zone(), 0, 7);
builder.AddParam(MachineType::Float32());
builder.AddParam(MachineType::Int32());
builder.AddParam(MachineType::Int32());
builder.AddParam(MachineType::Float64());
builder.AddParam(MachineType::Int64());
builder.AddParam(MachineType::Float64());
builder.AddParam(MachineType::Float64());
StreamBuilder m(this, MachineType::AnyTagged());
Node* nodes[] = {m.UndefinedConstant(), m.Float32Constant(0.0f),
m.Int32Constant(0), m.Int32Constant(0),
m.Float64Constant(0.0f), m.Int64Constant(0),
m.Float64Constant(0.0f), m.Float64Constant(0.0f)};
const int expected_poke_pair = 2;
const int expected_poke = 3;
TestPokePair(m, zone(), builder, nodes, arraysize(nodes),
expected_poke_pair, expected_poke);
}
}
TEST_F(InstructionSelectorTest, PokePairPrepareArgumentsSimd128) {
MachineSignature::Builder builder(zone(), 0, 2);
builder.AddParam(MachineType::Simd128());
builder.AddParam(MachineType::Simd128());
StreamBuilder m(this, MachineType::AnyTagged());
Node* nodes[] = {m.UndefinedConstant(),
m.AddNode(m.machine()->I32x4Splat(), m.Int32Constant(0)),
m.AddNode(m.machine()->I32x4Splat(), m.Int32Constant(0))};
const int expected_poke_pair = 0;
const int expected_poke = 2;
// Using kArm64PokePair is not currently supported for Simd128.
TestPokePair(m, zone(), builder, nodes, arraysize(nodes), expected_poke_pair,
expected_poke);
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -88,6 +88,52 @@ class InstructionSelectorTest : public TestWithNativeContextAndZone {
const FrameStateFunctionInfo* GetFrameStateFunctionInfo(int parameter_count,
int local_count);
// Create a simple call descriptor for testing.
static CallDescriptor* MakeSimpleCallDescriptor(Zone* zone,
MachineSignature* msig) {
LocationSignature::Builder locations(zone, msig->return_count(),
msig->parameter_count());
// Add return location(s).
const int return_count = static_cast<int>(msig->return_count());
for (int i = 0; i < return_count; i++) {
locations.AddReturn(
LinkageLocation::ForCallerFrameSlot(-1 - i, msig->GetReturn(i)));
}
// Just put all parameters on the stack.
const int parameter_count = static_cast<int>(msig->parameter_count());
unsigned slot_index = -1;
for (int i = 0; i < parameter_count; i++) {
locations.AddParam(
LinkageLocation::ForCallerFrameSlot(slot_index, msig->GetParam(i)));
// Slots are kSystemPointerSize sized. This reserves enough for space
// for types that might be bigger, eg. Simd128.
slot_index -=
std::max(1, ElementSizeInBytes(msig->GetParam(i).representation()) /
kSystemPointerSize);
}
const RegList kCalleeSaveRegisters = 0;
const RegList kCalleeSaveFPRegisters = 0;
MachineType target_type = MachineType::Pointer();
LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
return new (zone) CallDescriptor( // --
CallDescriptor::kCallAddress, // kind
target_type, // target MachineType
target_loc, // target location
locations.Build(), // location_sig
0, // stack_parameter_count
Operator::kNoProperties, // properties
kCalleeSaveRegisters, // callee-saved registers
kCalleeSaveFPRegisters, // callee-saved fp regs
CallDescriptor::kCanUseRoots, // flags
"iselect-test-call");
}
private:
CallDescriptor* MakeCallDescriptor(Zone* zone, MachineType return_type) {
MachineSignature::Builder builder(zone, 1, 0);
......@@ -125,46 +171,7 @@ class InstructionSelectorTest : public TestWithNativeContextAndZone {
return MakeSimpleCallDescriptor(zone, builder.Build());
}
private:
InstructionSelectorTest* test_;
// Create a simple call descriptor for testing.
CallDescriptor* MakeSimpleCallDescriptor(Zone* zone,
MachineSignature* msig) {
LocationSignature::Builder locations(zone, msig->return_count(),
msig->parameter_count());
// Add return location(s).
const int return_count = static_cast<int>(msig->return_count());
for (int i = 0; i < return_count; i++) {
locations.AddReturn(
LinkageLocation::ForCallerFrameSlot(-1 - i, msig->GetReturn(i)));
}
// Just put all parameters on the stack.
const int parameter_count = static_cast<int>(msig->parameter_count());
for (int i = 0; i < parameter_count; i++) {
locations.AddParam(
LinkageLocation::ForCallerFrameSlot(-1 - i, msig->GetParam(i)));
}
const RegList kCalleeSaveRegisters = 0;
const RegList kCalleeSaveFPRegisters = 0;
MachineType target_type = MachineType::Pointer();
LinkageLocation target_loc = LinkageLocation::ForAnyRegister();
return new (zone) CallDescriptor( // --
CallDescriptor::kCallAddress, // kind
target_type, // target MachineType
target_loc, // target location
locations.Build(), // location_sig
0, // stack_parameter_count
Operator::kNoProperties, // properties
kCalleeSaveRegisters, // callee-saved registers
kCalleeSaveFPRegisters, // callee-saved fp regs
CallDescriptor::kCanUseRoots, // flags
"iselect-test-call");
}
};
class Stream final {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment