Commit 88f3e031 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[TurboProp] Add support for Phis to fast reg alloc.

Adds support for Phis to be allocated to the fast register
allocator. Registers used for Phis are marked specially between
the point where the Phi is defined, and the gap-move's in the
predecessor blocks which populate the Phi value, since if the
Phi is spilled then all predecessor blocks must also spill the
Phi even if they were already allocated.

BUG=v8:9684

Change-Id: Iebe90495b83df655d3335a7d55874123f3b27f8d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2299366
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69139}
parent 3c6d9aac
......@@ -121,6 +121,8 @@ class MidTierRegisterAllocator final {
// Allocate registers operations.
void AllocateRegisters(const InstructionBlock* block);
void AllocatePhis(const InstructionBlock* block);
void AllocatePhiGapMoves(const InstructionBlock* block);
void UpdateSpillRangesForLoops();
bool IsFixedRegisterPolicy(const UnallocatedOperand* operand);
......
......@@ -45,6 +45,230 @@ TEST_F(MidTierRegisterAllocatorTest, CanAllocateFPRegisters) {
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, SimpleLoop) {
// i = K;
// while(true) { i++ }
StartBlock();
auto i_reg = DefineConstant();
// Add a branch around the loop to ensure the end-block
// is connected.
EndBlock(Branch(Reg(DefineConstant()), 3, 1));
StartBlock();
EndBlock();
{
StartLoop(1);
StartBlock();
auto phi = Phi(i_reg, 2);
auto ipp = EmitOI(Same(), Reg(phi), Use(DefineConstant()));
SetInput(phi, 1, ipp);
EndBlock(Jump(0));
EndLoop();
}
StartBlock();
EndBlock();
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, SimpleBranch) {
// return i ? K1 : K2
StartBlock();
auto i = DefineConstant();
EndBlock(Branch(Reg(i), 1, 2));
StartBlock();
Return(DefineConstant());
EndBlock(Last());
StartBlock();
Return(DefineConstant());
EndBlock(Last());
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, SimpleDiamond) {
// return p0 ? p0 : p0
StartBlock();
auto param = Parameter();
EndBlock(Branch(Reg(param), 1, 2));
StartBlock();
EndBlock(Jump(2));
StartBlock();
EndBlock(Jump(1));
StartBlock();
Return(param);
EndBlock();
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, SimpleDiamondPhi) {
// return i ? K1 : K2
StartBlock();
EndBlock(Branch(Reg(DefineConstant()), 1, 2));
StartBlock();
auto t_val = DefineConstant();
EndBlock(Jump(2));
StartBlock();
auto f_val = DefineConstant();
EndBlock(Jump(1));
StartBlock();
Return(Reg(Phi(t_val, f_val)));
EndBlock();
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, DiamondManyPhis) {
constexpr int kPhis = Register::kNumRegisters * 2;
StartBlock();
EndBlock(Branch(Reg(DefineConstant()), 1, 2));
StartBlock();
VReg t_vals[kPhis];
for (int i = 0; i < kPhis; ++i) {
t_vals[i] = DefineConstant();
}
EndBlock(Jump(2));
StartBlock();
VReg f_vals[kPhis];
for (int i = 0; i < kPhis; ++i) {
f_vals[i] = DefineConstant();
}
EndBlock(Jump(1));
StartBlock();
TestOperand merged[kPhis];
for (int i = 0; i < kPhis; ++i) {
merged[i] = Use(Phi(t_vals[i], f_vals[i]));
}
Return(EmitCall(Slot(-1), kPhis, merged));
EndBlock();
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, DoubleDiamondManyRedundantPhis) {
constexpr int kPhis = Register::kNumRegisters * 2;
// First diamond.
StartBlock();
VReg vals[kPhis];
for (int i = 0; i < kPhis; ++i) {
vals[i] = Parameter(Slot(-1 - i));
}
EndBlock(Branch(Reg(DefineConstant()), 1, 2));
StartBlock();
EndBlock(Jump(2));
StartBlock();
EndBlock(Jump(1));
// Second diamond.
StartBlock();
EndBlock(Branch(Reg(DefineConstant()), 1, 2));
StartBlock();
EndBlock(Jump(2));
StartBlock();
EndBlock(Jump(1));
StartBlock();
TestOperand merged[kPhis];
for (int i = 0; i < kPhis; ++i) {
merged[i] = Use(Phi(vals[i], vals[i]));
}
Return(EmitCall(Reg(0), kPhis, merged));
EndBlock();
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) {
const size_t kNumRegs = 3;
const size_t kParams = kNumRegs + 1;
// Override number of registers.
SetNumRegs(kNumRegs, kNumRegs);
StartBlock();
auto constant = DefineConstant();
VReg parameters[kParams];
for (size_t i = 0; i < arraysize(parameters); ++i) {
parameters[i] = DefineConstant();
}
EndBlock();
PhiInstruction* phis[kParams];
{
StartLoop(2);
// Loop header.
StartBlock();
for (size_t i = 0; i < arraysize(parameters); ++i) {
phis[i] = Phi(parameters[i], 2);
}
// Perform some computations.
// something like phi[i] += const
for (size_t i = 0; i < arraysize(parameters); ++i) {
auto result = EmitOI(Same(), Reg(phis[i]), Use(constant));
SetInput(phis[i], 1, result);
}
EndBlock(Branch(Reg(DefineConstant()), 1, 2));
// Jump back to loop header.
StartBlock();
EndBlock(Jump(-1));
EndLoop();
}
StartBlock();
Return(DefineConstant());
EndBlock();
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, SpillPhi) {
StartBlock();
EndBlock(Branch(Imm(), 1, 2));
StartBlock();
auto left = Define(Reg(0));
EndBlock(Jump(2));
StartBlock();
auto right = Define(Reg(0));
EndBlock();
StartBlock();
auto phi = Phi(left, right);
EmitCall(Slot(-1));
Return(Reg(phi));
EndBlock();
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, MoveLotsOfConstants) {
FLAG_trace_turbo = true;
StartBlock();
......@@ -114,6 +338,98 @@ TEST_F(MidTierRegisterAllocatorTest, SplitBeforeInstruction2) {
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, NestedDiamondPhiMerge) {
// Outer diamond.
StartBlock();
EndBlock(Branch(Imm(), 1, 5));
// Diamond 1
StartBlock();
EndBlock(Branch(Imm(), 1, 2));
StartBlock();
auto ll = Define(Reg());
EndBlock(Jump(2));
StartBlock();
auto lr = Define(Reg());
EndBlock();
StartBlock();
auto l_phi = Phi(ll, lr);
EndBlock(Jump(5));
// Diamond 2
StartBlock();
EndBlock(Branch(Imm(), 1, 2));
StartBlock();
auto rl = Define(Reg());
EndBlock(Jump(2));
StartBlock();
auto rr = Define(Reg());
EndBlock();
StartBlock();
auto r_phi = Phi(rl, rr);
EndBlock();
// Outer diamond merge.
StartBlock();
auto phi = Phi(l_phi, r_phi);
Return(Reg(phi));
EndBlock();
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, NestedDiamondPhiMergeDifferent) {
// Outer diamond.
StartBlock();
EndBlock(Branch(Imm(), 1, 5));
// Diamond 1
StartBlock();
EndBlock(Branch(Imm(), 1, 2));
StartBlock();
auto ll = Define(Reg(0));
EndBlock(Jump(2));
StartBlock();
auto lr = Define(Reg(1));
EndBlock();
StartBlock();
auto l_phi = Phi(ll, lr);
EndBlock(Jump(5));
// Diamond 2
StartBlock();
EndBlock(Branch(Imm(), 1, 2));
StartBlock();
auto rl = Define(Reg(2));
EndBlock(Jump(2));
StartBlock();
auto rr = Define(Reg(3));
EndBlock();
StartBlock();
auto r_phi = Phi(rl, rr);
EndBlock();
// Outer diamond merge.
StartBlock();
auto phi = Phi(l_phi, r_phi);
Return(Reg(phi));
EndBlock();
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, SplitBeforeAndMove) {
StartBlock();
......@@ -149,6 +465,80 @@ TEST_F(MidTierRegisterAllocatorTest, SpillTwice) {
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, RegressionLoadConstantBeforeSpill) {
StartBlock();
// Fill registers.
VReg values[Register::kNumRegisters];
for (size_t i = arraysize(values); i > 0; --i) {
values[i - 1] = Define(Reg(static_cast<int>(i - 1)));
}
auto c = DefineConstant();
auto to_spill = Define(Reg());
EndBlock(Jump(1));
{
StartLoop(1);
StartBlock();
// Create a use for c in second half of prev block's last gap
Phi(c);
for (size_t i = arraysize(values); i > 0; --i) {
Phi(values[i - 1]);
}
EndBlock(Jump(1));
EndLoop();
}
StartBlock();
// Force c to split within to_spill's definition.
EmitI(Reg(c));
EmitI(Reg(to_spill));
EndBlock(Last());
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, DiamondWithCallFirstBlock) {
StartBlock();
auto x = EmitOI(Reg(0));
EndBlock(Branch(Reg(x), 1, 2));
StartBlock();
EmitCall(Slot(-1));
auto occupy = EmitOI(Reg(0));
EndBlock(Jump(2));
StartBlock();
EndBlock(FallThrough());
StartBlock();
Use(occupy);
Return(Reg(x));
EndBlock();
Allocate();
}
TEST_F(MidTierRegisterAllocatorTest, DiamondWithCallSecondBlock) {
StartBlock();
auto x = EmitOI(Reg(0));
EndBlock(Branch(Reg(x), 1, 2));
StartBlock();
EndBlock(Jump(2));
StartBlock();
EmitCall(Slot(-1));
auto occupy = EmitOI(Reg(0));
EndBlock(FallThrough());
StartBlock();
Use(occupy);
Return(Reg(x));
EndBlock();
Allocate();
}
namespace {
enum class ParameterType { kFixedSlot, kSlot, kRegister, kFixedRegister };
......
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