Commit 5c4298a0 authored by bbudge's avatar bbudge Committed by Commit bot

[Turbofan] Allow FP operands and vregs in InstructionSequenceTest.

- Adds an optional representation field to VReg and TestOperand structs.
- Adds a simple FP allocation test to register-allocator-unittest.cc.
- Adds some simple FP tests to move-optimizer-unittest.cc.

LOG=N
BUG=v8:4124

Review-Url: https://codereview.chromium.org/2400513002
Cr-Commit-Position: refs/heads/master@{#40117}
parent 749570ed
......@@ -41,7 +41,6 @@ static void InitializeRegisterNames() {
}
}
InstructionSequenceTest::InstructionSequenceTest()
: sequence_(nullptr),
num_general_registers_(kDefaultNRegs),
......@@ -62,6 +61,32 @@ void InstructionSequenceTest::SetNumRegs(int num_general_registers,
num_double_registers_ = num_double_registers;
}
int InstructionSequenceTest::GetNumRegs(MachineRepresentation rep) {
switch (rep) {
case MachineRepresentation::kFloat32:
return config()->num_float_registers();
case MachineRepresentation::kFloat64:
return config()->num_double_registers();
case MachineRepresentation::kSimd128:
return config()->num_simd128_registers();
default:
return config()->num_general_registers();
}
}
int InstructionSequenceTest::GetAllocatableCode(int index,
MachineRepresentation rep) {
switch (rep) {
case MachineRepresentation::kFloat32:
return config()->GetAllocatableFloatCode(index);
case MachineRepresentation::kFloat64:
return config()->GetAllocatableDoubleCode(index);
case MachineRepresentation::kSimd128:
return config()->GetAllocatableSimd128Code(index);
default:
return config()->GetAllocatableGeneralCode(index);
}
}
RegisterConfiguration* InstructionSequenceTest::config() {
if (!config_) {
......@@ -149,13 +174,12 @@ InstructionSequenceTest::TestOperand InstructionSequenceTest::Imm(int32_t imm) {
InstructionSequenceTest::VReg InstructionSequenceTest::Define(
TestOperand output_op) {
VReg vreg = NewReg();
VReg vreg = NewReg(output_op);
InstructionOperand outputs[1]{ConvertOutputOp(vreg, output_op)};
Emit(kArchNop, 1, outputs);
return vreg;
}
Instruction* InstructionSequenceTest::Return(TestOperand input_op_0) {
block_returns_ = true;
InstructionOperand inputs[1]{ConvertInputOp(input_op_0)};
......@@ -240,7 +264,7 @@ Instruction* InstructionSequenceTest::EmitI(TestOperand input_op_0,
InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
TestOperand output_op, size_t input_size, TestOperand* inputs) {
VReg output_vreg = NewReg();
VReg output_vreg = NewReg(output_op);
InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)};
InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
Emit(kArchNop, 1, outputs, input_size, mapped_inputs);
......@@ -259,7 +283,8 @@ InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI(
TestOperand output_op_0, TestOperand output_op_1, size_t input_size,
TestOperand* inputs) {
VRegPair output_vregs = std::make_pair(NewReg(), NewReg());
VRegPair output_vregs =
std::make_pair(NewReg(output_op_0), NewReg(output_op_1));
InstructionOperand outputs[2]{
ConvertOutputOp(output_vregs.first, output_op_0),
ConvertOutputOp(output_vregs.second, output_op_1)};
......@@ -280,7 +305,7 @@ InstructionSequenceTest::VRegPair InstructionSequenceTest::EmitOOI(
InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
TestOperand output_op, size_t input_size, TestOperand* inputs) {
VReg output_vreg = NewReg();
VReg output_vreg = NewReg(output_op);
InstructionOperand outputs[1]{ConvertOutputOp(output_vreg, output_op)};
CHECK(UnallocatedOperand::cast(outputs[0]).HasFixedPolicy());
InstructionOperand* mapped_inputs = ConvertInputs(input_size, inputs);
......@@ -387,11 +412,25 @@ InstructionOperand InstructionSequenceTest::ConvertInputOp(TestOperand op) {
case kSlot:
return Unallocated(op, UnallocatedOperand::MUST_HAVE_SLOT,
UnallocatedOperand::USED_AT_START);
case kFixedRegister:
CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
case kFixedRegister: {
MachineRepresentation rep = GetCanonicalRep(op);
CHECK(0 <= op.value_ && op.value_ < GetNumRegs(rep));
if (DoesRegisterAllocation()) {
auto extended_policy = IsFloatingPoint(rep)
? UnallocatedOperand::FIXED_FP_REGISTER
: UnallocatedOperand::FIXED_REGISTER;
return Unallocated(op, extended_policy, op.value_);
} else {
return AllocatedOperand(LocationOperand::REGISTER, rep, op.value_);
}
}
case kFixedSlot:
if (DoesRegisterAllocation()) {
return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
} else {
return AllocatedOperand(LocationOperand::STACK_SLOT,
GetCanonicalRep(op), op.value_);
}
default:
break;
}
......@@ -410,10 +449,24 @@ InstructionOperand InstructionSequenceTest::ConvertOutputOp(VReg vreg,
case kRegister:
return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
case kFixedSlot:
if (DoesRegisterAllocation()) {
return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
case kFixedRegister:
CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
} else {
return AllocatedOperand(LocationOperand::STACK_SLOT,
GetCanonicalRep(op), op.value_);
}
case kFixedRegister: {
MachineRepresentation rep = GetCanonicalRep(op);
CHECK(0 <= op.value_ && op.value_ < GetNumRegs(rep));
if (DoesRegisterAllocation()) {
auto extended_policy = IsFloatingPoint(rep)
? UnallocatedOperand::FIXED_FP_REGISTER
: UnallocatedOperand::FIXED_REGISTER;
return Unallocated(op, extended_policy, op.value_);
} else {
return AllocatedOperand(LocationOperand::REGISTER, rep, op.value_);
}
}
default:
break;
}
......
......@@ -19,14 +19,18 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
public:
static const int kDefaultNRegs = 8;
static const int kNoValue = kMinInt;
static const MachineRepresentation kNoRep = MachineRepresentation::kNone;
static const MachineRepresentation kFloat64 = MachineRepresentation::kFloat64;
typedef RpoNumber Rpo;
struct VReg {
VReg() : value_(kNoValue) {}
VReg(PhiInstruction* phi) : value_(phi->virtual_register()) {} // NOLINT
explicit VReg(int value) : value_(value) {}
explicit VReg(int value, MachineRepresentation rep = kNoRep)
: value_(value), rep_(rep) {}
int value_;
MachineRepresentation rep_ = kNoRep;
};
typedef std::pair<VReg, VReg> VRegPair;
......@@ -47,43 +51,64 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
};
struct TestOperand {
TestOperand() : type_(kInvalid), vreg_(), value_(kNoValue) {}
TestOperand(TestOperandType type, int imm)
: type_(type), vreg_(), value_(imm) {}
TestOperand() : type_(kInvalid), vreg_(), value_(kNoValue), rep_(kNoRep) {}
explicit TestOperand(TestOperandType type)
: type_(type), vreg_(), value_(kNoValue), rep_(kNoRep) {}
// For tests that do register allocation.
TestOperand(TestOperandType type, VReg vreg, int value = kNoValue)
: type_(type), vreg_(vreg), value_(value) {}
: type_(type), vreg_(vreg), value_(value), rep_(vreg.rep_) {}
// For immediates, constants, and tests that don't do register allocation.
TestOperand(TestOperandType type, int value,
MachineRepresentation rep = kNoRep)
: type_(type), vreg_(), value_(value), rep_(rep) {}
TestOperandType type_;
VReg vreg_;
int value_;
MachineRepresentation rep_;
};
static TestOperand Same() { return TestOperand(kSameAsFirst, VReg()); }
static TestOperand Same() { return TestOperand(kSameAsFirst); }
static TestOperand ExplicitReg(int index) {
TestOperandType type = kExplicit;
return TestOperand(type, VReg(), index);
return TestOperand(type, index);
}
static TestOperand ExplicitFPReg(int index,
MachineRepresentation rep = kFloat64) {
TestOperandType type = kExplicit;
return TestOperand(type, index, rep);
}
static TestOperand Reg(VReg vreg, int index = kNoValue) {
TestOperandType type = kRegister;
if (index != kNoValue) type = kFixedRegister;
TestOperandType type = (index == kNoValue) ? kRegister : kFixedRegister;
return TestOperand(type, vreg, index);
}
static TestOperand Reg(int index = kNoValue) { return Reg(VReg(), index); }
static TestOperand Reg(int index = kNoValue,
MachineRepresentation rep = kNoRep) {
return Reg(VReg(kNoValue, rep), index);
}
static TestOperand FPReg(int index = kNoValue,
MachineRepresentation rep = kFloat64) {
return Reg(index, rep);
}
static TestOperand Slot(VReg vreg, int index = kNoValue) {
TestOperandType type = kSlot;
if (index != kNoValue) type = kFixedSlot;
TestOperandType type = (index == kNoValue) ? kSlot : kFixedSlot;
return TestOperand(type, vreg, index);
}
static TestOperand Slot(int index = kNoValue) { return Slot(VReg(), index); }
static TestOperand Slot(int index = kNoValue,
MachineRepresentation rep = kNoRep) {
return Slot(VReg(kNoValue, rep), index);
}
static TestOperand Const(int index) {
CHECK_NE(kNoValue, index);
return TestOperand(kConstant, VReg(), index);
return TestOperand(kConstant, index);
}
static TestOperand Use(VReg vreg) { return TestOperand(kNone, vreg); }
......@@ -129,6 +154,8 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
InstructionSequenceTest();
void SetNumRegs(int num_general_registers, int num_double_registers);
int GetNumRegs(MachineRepresentation rep);
int GetAllocatableCode(int index, MachineRepresentation rep = kNoRep);
RegisterConfiguration* config();
InstructionSequence* sequence();
......@@ -140,6 +167,14 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
TestOperand Imm(int32_t imm = 0);
VReg Define(TestOperand output_op);
VReg Parameter(TestOperand output_op = Reg()) { return Define(output_op); }
VReg FPParameter(MachineRepresentation rep = kFloat64) {
return Parameter(FPReg(kNoValue, rep));
}
MachineRepresentation GetCanonicalRep(TestOperand op) {
return IsFloatingPoint(op.rep_) ? op.rep_
: sequence()->DefaultRepresentation();
}
Instruction* Return(TestOperand input_op_0);
Instruction* Return(VReg vreg) { return Return(Reg(vreg, 0)); }
......@@ -177,16 +212,21 @@ class InstructionSequenceTest : public TestWithIsolateAndZone {
TestOperand input_op_3 = TestOperand());
InstructionBlock* current_block() const { return current_block_; }
int num_general_registers() const { return num_general_registers_; }
int num_double_registers() const { return num_double_registers_; }
// Called after all instructions have been inserted.
void WireBlocks();
private:
VReg NewReg() { return VReg(sequence()->NextVirtualRegister()); }
virtual bool DoesRegisterAllocation() const { return true; }
VReg NewReg(TestOperand op = TestOperand()) {
int vreg = sequence()->NextVirtualRegister();
if (IsFloatingPoint(op.rep_))
sequence()->MarkAsRepresentation(op.rep_, vreg);
return VReg(vreg, op.rep_);
}
static TestOperand Invalid() { return TestOperand(kInvalid, VReg()); }
static TestOperand Invalid() { return TestOperand(kInvalid); }
Instruction* EmitBranch(TestOperand input_op);
Instruction* EmitFallThrough();
......
......@@ -61,6 +61,8 @@ class MoveOptimizerTest : public InstructionSequenceTest {
}
private:
bool DoesRegisterAllocation() const override { return false; }
InstructionOperand ConvertMoveArg(TestOperand op) {
CHECK_EQ(kNoValue, op.vreg_.value_);
CHECK_NE(kNoValue, op.value_);
......@@ -70,14 +72,16 @@ class MoveOptimizerTest : public InstructionSequenceTest {
case kFixedSlot:
return AllocatedOperand(LocationOperand::STACK_SLOT,
MachineRepresentation::kWord32, op.value_);
case kFixedRegister:
CHECK(0 <= op.value_ && op.value_ < num_general_registers());
return AllocatedOperand(LocationOperand::REGISTER,
MachineRepresentation::kWord32, op.value_);
case kExplicit:
CHECK(0 <= op.value_ && op.value_ < num_general_registers());
return ExplicitOperand(LocationOperand::REGISTER,
MachineRepresentation::kWord32, op.value_);
case kFixedRegister: {
MachineRepresentation rep = GetCanonicalRep(op);
CHECK(0 <= op.value_ && op.value_ < GetNumRegs(rep));
return AllocatedOperand(LocationOperand::REGISTER, rep, op.value_);
}
case kExplicit: {
MachineRepresentation rep = GetCanonicalRep(op);
CHECK(0 <= op.value_ && op.value_ < GetNumRegs(rep));
return ExplicitOperand(LocationOperand::REGISTER, rep, op.value_);
}
default:
break;
}
......@@ -90,31 +94,37 @@ class MoveOptimizerTest : public InstructionSequenceTest {
TEST_F(MoveOptimizerTest, RemovesRedundant) {
StartBlock();
auto first_instr = EmitNop();
AddMove(first_instr, Reg(0), Reg(1));
auto last_instr = EmitNop();
AddMove(first_instr, Reg(0), Reg(1));
AddMove(last_instr, Reg(1), Reg(0));
AddMove(first_instr, FPReg(0), FPReg(1));
AddMove(last_instr, FPReg(1), FPReg(0));
EndBlock(Last());
Optimize();
CHECK_EQ(0, NonRedundantSize(first_instr->parallel_moves()[0]));
auto move = last_instr->parallel_moves()[0];
CHECK_EQ(1, NonRedundantSize(move));
CHECK_EQ(2, NonRedundantSize(move));
CHECK(Contains(move, Reg(0), Reg(1)));
CHECK(Contains(move, FPReg(0), FPReg(1)));
}
TEST_F(MoveOptimizerTest, RemovesRedundantExplicit) {
int first_reg_index =
RegisterConfiguration::Turbofan()->GetAllocatableGeneralCode(0);
int second_reg_index =
RegisterConfiguration::Turbofan()->GetAllocatableGeneralCode(1);
int first_reg_index = GetAllocatableCode(0);
int second_reg_index = GetAllocatableCode(1);
StartBlock();
auto first_instr = EmitNop();
AddMove(first_instr, Reg(first_reg_index), ExplicitReg(second_reg_index));
auto last_instr = EmitNop();
AddMove(first_instr, Reg(first_reg_index), ExplicitReg(second_reg_index));
AddMove(last_instr, Reg(second_reg_index), Reg(first_reg_index));
EndBlock(Last());
Optimize();
......@@ -185,11 +195,16 @@ TEST_F(MoveOptimizerTest, SimpleMergeCycle) {
AddMove(gap_0, Reg(0), Reg(1));
AddMove(LastInstruction(), Reg(1), Reg(0));
AddMove(gap_0, FPReg(0), FPReg(1));
AddMove(LastInstruction(), FPReg(1), FPReg(0));
StartBlock();
EndBlock(Jump(1));
auto gap_1 = LastInstruction();
AddMove(gap_1, Reg(0), Reg(1));
AddMove(gap_1, Reg(1), Reg(0));
AddMove(gap_1, FPReg(0), FPReg(1));
AddMove(gap_1, FPReg(1), FPReg(0));
StartBlock();
EndBlock(Last());
......@@ -201,9 +216,11 @@ TEST_F(MoveOptimizerTest, SimpleMergeCycle) {
CHECK(gap_0->AreMovesRedundant());
CHECK(gap_1->AreMovesRedundant());
auto move = last->parallel_moves()[0];
CHECK_EQ(2, NonRedundantSize(move));
CHECK_EQ(4, NonRedundantSize(move));
CHECK(Contains(move, Reg(0), Reg(1)));
CHECK(Contains(move, Reg(1), Reg(0)));
CHECK(Contains(move, FPReg(0), FPReg(1)));
CHECK(Contains(move, FPReg(1), FPReg(0)));
}
......@@ -325,7 +342,8 @@ TEST_F(MoveOptimizerTest, ClobberedDestinationsAreEliminated) {
EmitNop();
Instruction* first_instr = LastInstruction();
AddMove(first_instr, Reg(0), Reg(1));
EmitOI(Reg(1), 0, nullptr);
AddMove(first_instr, FPReg(0), FPReg(1));
EmitOOI(Reg(1), FPReg(1), 0, nullptr);
Instruction* last_instr = LastInstruction();
EndBlock();
Optimize();
......
......@@ -101,6 +101,17 @@ TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) {
Allocate();
}
TEST_F(RegisterAllocatorTest, CanAllocateThreeFPRegisters) {
// return p0 + p1;
StartBlock();
VReg a_reg = FPParameter();
VReg b_reg = FPParameter();
VReg c_reg = EmitOI(FPReg(1), Reg(a_reg, 1), Reg(b_reg, 0));
Return(c_reg);
EndBlock(Last());
Allocate();
}
TEST_F(RegisterAllocatorTest, SimpleLoop) {
// i = K;
......
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