Commit 35951765 authored by dcarney's avatar dcarney Committed by Commit bot

[turbofan] improve register allocator testing framework

R=bmeurer@chromium.org

BUG=

Review URL: https://codereview.chromium.org/800493002

Cr-Commit-Position: refs/heads/master@{#25794}
parent 14409abc
...@@ -1049,7 +1049,9 @@ void Pipeline::AllocateRegisters(const RegisterConfiguration* config, ...@@ -1049,7 +1049,9 @@ void Pipeline::AllocateRegisters(const RegisterConfiguration* config,
Run<PopulatePointerMapsPhase>(); Run<PopulatePointerMapsPhase>();
Run<ConnectRangesPhase>(); Run<ConnectRangesPhase>();
Run<ResolveControlFlowPhase>(); Run<ResolveControlFlowPhase>();
if (FLAG_turbo_move_optimization) {
Run<OptimizeMovesPhase>(); Run<OptimizeMovesPhase>();
}
if (FLAG_trace_turbo_graph) { if (FLAG_trace_turbo_graph) {
OFStream os(stdout); OFStream os(stdout);
......
...@@ -406,6 +406,8 @@ DEFINE_BOOL(turbo_reuse_spill_slots, false, "reuse spill slots in TurboFan") ...@@ -406,6 +406,8 @@ DEFINE_BOOL(turbo_reuse_spill_slots, false, "reuse spill slots in TurboFan")
// TODO(dcarney): this is just for experimentation, remove when default. // TODO(dcarney): this is just for experimentation, remove when default.
DEFINE_BOOL(turbo_delay_ssa_decon, false, DEFINE_BOOL(turbo_delay_ssa_decon, false,
"delay ssa deconstruction in TurboFan register allocator") "delay ssa deconstruction in TurboFan register allocator")
// TODO(dcarney): this is just for debugging, remove eventually.
DEFINE_BOOL(turbo_move_optimization, true, "optimize gap moves in TurboFan")
DEFINE_BOOL(turbo_jt, true, "enable jump threading") DEFINE_BOOL(turbo_jt, true, "enable jump threading")
DEFINE_INT(typed_array_max_size_in_heap, 64, DEFINE_INT(typed_array_max_size_in_heap, 64,
......
...@@ -184,30 +184,46 @@ InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant( ...@@ -184,30 +184,46 @@ InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant(
int InstructionSequenceTest::EmitNop() { return Emit(NewIndex(), kArchNop); } int InstructionSequenceTest::EmitNop() { return Emit(NewIndex(), kArchNop); }
int InstructionSequenceTest::EmitI(TestOperand input_op_0) { static size_t CountInputs(size_t size,
InstructionOperand* inputs[1]{ConvertInputOp(input_op_0)}; InstructionSequenceTest::TestOperand* inputs) {
return Emit(NewIndex(), kArchNop, 0, nullptr, 1, inputs); size_t i = 0;
for (; i < size; ++i) {
if (inputs[i].type_ == InstructionSequenceTest::kInvalid) break;
}
return i;
}
int InstructionSequenceTest::EmitI(size_t input_size, TestOperand* inputs) {
InstructionOperand** mapped_inputs = ConvertInputs(input_size, inputs);
return Emit(NewIndex(), kArchNop, 0, nullptr, input_size, mapped_inputs);
}
int InstructionSequenceTest::EmitI(TestOperand input_op_0,
TestOperand input_op_1,
TestOperand input_op_2,
TestOperand input_op_3) {
TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
return EmitI(CountInputs(arraysize(inputs), inputs), inputs);
} }
InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI( InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
TestOperand output_op, TestOperand input_op_0) { TestOperand output_op, size_t input_size, TestOperand* inputs) {
VReg output_vreg = NewReg(); VReg output_vreg = NewReg();
InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)}; InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
InstructionOperand* inputs[1]{ConvertInputOp(input_op_0)}; InstructionOperand** mapped_inputs = ConvertInputs(input_size, inputs);
Emit(output_vreg.value_, kArchNop, 1, outputs, 1, inputs); Emit(output_vreg.value_, kArchNop, 1, outputs, input_size, mapped_inputs);
return output_vreg; return output_vreg;
} }
InstructionSequenceTest::VReg InstructionSequenceTest::EmitOII( InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1) { TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1,
VReg output_vreg = NewReg(); TestOperand input_op_2, TestOperand input_op_3) {
InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)}; TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
InstructionOperand* inputs[2]{ConvertInputOp(input_op_0), return EmitOI(output_op, CountInputs(arraysize(inputs), inputs), inputs);
ConvertInputOp(input_op_1)};
Emit(output_vreg.value_, kArchNop, 1, outputs, 2, inputs);
return output_vreg;
} }
...@@ -216,11 +232,7 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall( ...@@ -216,11 +232,7 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
VReg output_vreg = NewReg(); VReg output_vreg = NewReg();
InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)}; InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
CHECK(UnallocatedOperand::cast(outputs[0])->HasFixedPolicy()); CHECK(UnallocatedOperand::cast(outputs[0])->HasFixedPolicy());
InstructionOperand** mapped_inputs = InstructionOperand** mapped_inputs = ConvertInputs(input_size, inputs);
zone()->NewArray<InstructionOperand*>(static_cast<int>(input_size));
for (size_t i = 0; i < input_size; ++i) {
mapped_inputs[i] = ConvertInputOp(inputs[i]);
}
Emit(output_vreg.value_, kArchCallCodeObject, 1, outputs, input_size, Emit(output_vreg.value_, kArchCallCodeObject, 1, outputs, input_size,
mapped_inputs, 0, nullptr, true); mapped_inputs, 0, nullptr, true);
return output_vreg; return output_vreg;
...@@ -231,11 +243,7 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall( ...@@ -231,11 +243,7 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1, TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1,
TestOperand input_op_2, TestOperand input_op_3) { TestOperand input_op_2, TestOperand input_op_3) {
TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3}; TestOperand inputs[] = {input_op_0, input_op_1, input_op_2, input_op_3};
size_t size = 0; return EmitCall(output_op, CountInputs(arraysize(inputs), inputs), inputs);
for (; size < arraysize(inputs); ++size) {
if (inputs[size].type_ == kInvalid) break;
}
return EmitCall(output_op, size, inputs);
} }
...@@ -315,6 +323,17 @@ InstructionOperand* InstructionSequenceTest::Unallocated( ...@@ -315,6 +323,17 @@ InstructionOperand* InstructionSequenceTest::Unallocated(
} }
InstructionOperand** InstructionSequenceTest::ConvertInputs(
size_t input_size, TestOperand* inputs) {
InstructionOperand** mapped_inputs =
zone()->NewArray<InstructionOperand*>(static_cast<int>(input_size));
for (size_t i = 0; i < input_size; ++i) {
mapped_inputs[i] = ConvertInputOp(inputs[i]);
}
return mapped_inputs;
}
InstructionOperand* InstructionSequenceTest::ConvertInputOp(TestOperand op) { InstructionOperand* InstructionSequenceTest::ConvertInputOp(TestOperand op) {
if (op.type_ == kImmediate) { if (op.type_ == kImmediate) {
CHECK_EQ(op.vreg_.value_, kNoValue); CHECK_EQ(op.vreg_.value_, kNoValue);
...@@ -325,6 +344,10 @@ InstructionOperand* InstructionSequenceTest::ConvertInputOp(TestOperand op) { ...@@ -325,6 +344,10 @@ InstructionOperand* InstructionSequenceTest::ConvertInputOp(TestOperand op) {
case kNone: case kNone:
return Unallocated(op, UnallocatedOperand::NONE, return Unallocated(op, UnallocatedOperand::NONE,
UnallocatedOperand::USED_AT_START); UnallocatedOperand::USED_AT_START);
case kUnique:
return Unallocated(op, UnallocatedOperand::NONE);
case kUniqueRegister:
return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
case kRegister: case kRegister:
return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER, return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER,
UnallocatedOperand::USED_AT_START); UnallocatedOperand::USED_AT_START);
......
...@@ -36,7 +36,9 @@ class InstructionSequenceTest : public TestWithZone { ...@@ -36,7 +36,9 @@ class InstructionSequenceTest : public TestWithZone {
kFixedSlot, kFixedSlot,
kImmediate, kImmediate,
kNone, kNone,
kConstant kConstant,
kUnique,
kUniqueRegister
}; };
struct TestOperand { struct TestOperand {
...@@ -78,6 +80,12 @@ class InstructionSequenceTest : public TestWithZone { ...@@ -78,6 +80,12 @@ class InstructionSequenceTest : public TestWithZone {
static TestOperand Use() { return Use(VReg()); } static TestOperand Use() { return Use(VReg()); }
static TestOperand Unique(VReg vreg) { return TestOperand(kUnique, vreg); }
static TestOperand UniqueReg(VReg vreg) {
return TestOperand(kUniqueRegister, vreg);
}
enum BlockCompletionType { kBlockEnd, kFallThrough, kBranch, kJump }; enum BlockCompletionType { kBlockEnd, kFallThrough, kBranch, kJump };
struct BlockCompletion { struct BlockCompletion {
...@@ -134,10 +142,16 @@ class InstructionSequenceTest : public TestWithZone { ...@@ -134,10 +142,16 @@ class InstructionSequenceTest : public TestWithZone {
VReg DefineConstant(int32_t imm = 0); VReg DefineConstant(int32_t imm = 0);
int EmitNop(); int EmitNop();
int EmitI(TestOperand input_op_0); int EmitI(size_t input_size, TestOperand* inputs);
VReg EmitOI(TestOperand output_op, TestOperand input_op_0); int EmitI(TestOperand input_op_0 = TestOperand(),
VReg EmitOII(TestOperand output_op, TestOperand input_op_0, TestOperand input_op_1 = TestOperand(),
TestOperand input_op_1); TestOperand input_op_2 = TestOperand(),
TestOperand input_op_3 = TestOperand());
VReg EmitOI(TestOperand output_op, size_t input_size, TestOperand* inputs);
VReg EmitOI(TestOperand output_op, TestOperand input_op_0 = TestOperand(),
TestOperand input_op_1 = TestOperand(),
TestOperand input_op_2 = TestOperand(),
TestOperand input_op_3 = TestOperand());
VReg EmitCall(TestOperand output_op, size_t input_size, TestOperand* inputs); VReg EmitCall(TestOperand output_op, size_t input_size, TestOperand* inputs);
VReg EmitCall(TestOperand output_op, TestOperand input_op_0 = TestOperand(), VReg EmitCall(TestOperand output_op, TestOperand input_op_0 = TestOperand(),
TestOperand input_op_1 = TestOperand(), TestOperand input_op_1 = TestOperand(),
...@@ -181,6 +195,7 @@ class InstructionSequenceTest : public TestWithZone { ...@@ -181,6 +195,7 @@ class InstructionSequenceTest : public TestWithZone {
InstructionOperand* Unallocated(TestOperand op, InstructionOperand* Unallocated(TestOperand op,
UnallocatedOperand::BasicPolicy policy, UnallocatedOperand::BasicPolicy policy,
int index); int index);
InstructionOperand** ConvertInputs(size_t input_size, TestOperand* inputs);
InstructionOperand* ConvertInputOp(TestOperand op); InstructionOperand* ConvertInputOp(TestOperand op);
InstructionOperand* ConvertOutputOp(VReg vreg, TestOperand op); InstructionOperand* ConvertOutputOp(VReg vreg, TestOperand op);
InstructionBlock* NewBlock(); InstructionBlock* NewBlock();
......
...@@ -23,7 +23,7 @@ TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) { ...@@ -23,7 +23,7 @@ TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) {
StartBlock(); StartBlock();
auto a_reg = Parameter(); auto a_reg = Parameter();
auto b_reg = Parameter(); auto b_reg = Parameter();
auto c_reg = EmitOII(Reg(1), Reg(a_reg, 1), Reg(b_reg, 0)); auto c_reg = EmitOI(Reg(1), Reg(a_reg, 1), Reg(b_reg, 0));
Return(c_reg); Return(c_reg);
EndBlock(Last()); EndBlock(Last());
...@@ -43,7 +43,7 @@ TEST_F(RegisterAllocatorTest, SimpleLoop) { ...@@ -43,7 +43,7 @@ TEST_F(RegisterAllocatorTest, SimpleLoop) {
StartBlock(); StartBlock();
auto phi = Phi(i_reg); auto phi = Phi(i_reg);
auto ipp = EmitOII(Same(), Reg(phi), Use(DefineConstant())); auto ipp = EmitOI(Same(), Reg(phi), Use(DefineConstant()));
Extend(phi, ipp); Extend(phi, ipp);
EndBlock(Jump(0)); EndBlock(Jump(0));
...@@ -212,7 +212,7 @@ TEST_F(RegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) { ...@@ -212,7 +212,7 @@ TEST_F(RegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) {
// Perform some computations. // Perform some computations.
// something like phi[i] += const // something like phi[i] += const
for (size_t i = 0; i < arraysize(parameters); ++i) { for (size_t i = 0; i < arraysize(parameters); ++i) {
auto result = EmitOII(Same(), Reg(phis[i]), Use(constant)); auto result = EmitOI(Same(), Reg(phis[i]), Use(constant));
Extend(phis[i], result); Extend(phis[i], result);
} }
...@@ -274,6 +274,126 @@ TEST_F(RegisterAllocatorTest, MoveLotsOfConstants) { ...@@ -274,6 +274,126 @@ TEST_F(RegisterAllocatorTest, MoveLotsOfConstants) {
Allocate(); Allocate();
} }
TEST_F(RegisterAllocatorTest, SplitBeforeInstruction) {
const int kNumRegs = 6;
SetNumRegs(kNumRegs, kNumRegs);
StartBlock();
// Stack parameters/spilled values.
auto p_0 = Define(Slot(-1));
auto p_1 = Define(Slot(-2));
// Fill registers.
VReg values[kNumRegs];
for (size_t i = 0; i < arraysize(values); ++i) {
values[i] = Define(Reg(static_cast<int>(i)));
}
// values[0] will be split in the second half of this instruction.
// Models Intel mod instructions.
EmitOI(Reg(0), Reg(p_0, 1), UniqueReg(p_1));
EmitI(Reg(values[0], 0));
EndBlock(Last());
Allocate();
}
TEST_F(RegisterAllocatorTest, 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(RegisterAllocatorTest, 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();
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
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