Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(26)

Unified Diff: test/unittests/compiler/register-allocator-unittest.cc

Issue 700753003: [turbofan] add some registerallocator unittests (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/unittests/compiler/register-allocator-unittest.cc
diff --git a/test/unittests/compiler/register-allocator-unittest.cc b/test/unittests/compiler/register-allocator-unittest.cc
index db457c0d65a19cc00eb9837cf3ae1ae54bd12bf6..074789bae4ecc92fe8e39a000ec84f4d689796ad 100644
--- a/test/unittests/compiler/register-allocator-unittest.cc
+++ b/test/unittests/compiler/register-allocator-unittest.cc
@@ -14,8 +14,6 @@ namespace compiler {
typedef BasicBlock::RpoNumber Rpo;
-namespace {
-
static const char*
general_register_names_[RegisterConfiguration::kMaxGeneralRegisters];
static const char*
@@ -23,7 +21,6 @@ static const char*
static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters +
RegisterConfiguration::kMaxDoubleRegisters)];
-
static void InitializeRegisterNames() {
char* loc = register_names_;
for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) {
@@ -38,52 +35,107 @@ static void InitializeRegisterNames() {
}
}
-enum BlockCompletionType { kBlockEnd, kFallThrough, kBranch, kJump };
-struct BlockCompletion {
- BlockCompletionType type_;
- int vreg_;
- int offset_0_;
- int offset_1_;
-};
+class RegisterAllocatorTest : public TestWithZone {
+ public:
+ static const int kDefaultNRegs = 4;
+ static const int kNoValue = kMinInt;
-static const int kInvalidJumpOffset = kMinInt;
+ struct VReg {
+ VReg() : value_(kNoValue) {}
+ VReg(PhiInstruction* phi) : value_(phi->virtual_register()) {} // NOLINT
+ explicit VReg(int value) : value_(value) {}
+ int value_;
+ };
-BlockCompletion FallThrough() {
- BlockCompletion completion = {kFallThrough, -1, 1, kInvalidJumpOffset};
- return completion;
-}
+ enum TestOperandType {
+ kInvalid,
+ kSameAsFirst,
+ kRegister,
+ kFixedRegister,
+ kSlot,
+ kFixedSlot,
+ kImmediate,
+ kNone
+ };
+ struct TestOperand {
+ TestOperand() : type_(kInvalid), vreg_(), value_(kNoValue) {}
+ TestOperand(TestOperandType type, int imm)
+ : type_(type), vreg_(), value_(imm) {}
+ TestOperand(TestOperandType type, VReg vreg, int value = kNoValue)
+ : type_(type), vreg_(vreg), value_(value) {}
-BlockCompletion Jump(int offset) {
- BlockCompletion completion = {kJump, -1, offset, kInvalidJumpOffset};
- return completion;
-}
+ TestOperandType type_;
+ VReg vreg_;
+ int value_;
+ };
+ static TestOperand Same() { return TestOperand(kSameAsFirst, VReg()); }
-BlockCompletion Branch(int vreg, int left_offset, int right_offset) {
- BlockCompletion completion = {kBranch, vreg, left_offset, right_offset};
- return completion;
-}
+ static TestOperand Reg(VReg vreg, int index = kNoValue) {
+ TestOperandType type = kRegister;
+ if (index != kNoValue) type = kFixedRegister;
+ return TestOperand(type, vreg, index);
+ }
-} // namespace
+ static TestOperand Reg(int index = kNoValue) { return Reg(VReg(), index); }
+ static TestOperand Slot(VReg vreg, int index = kNoValue) {
+ TestOperandType type = kSlot;
+ if (index != kNoValue) type = kFixedSlot;
+ return TestOperand(type, vreg, index);
+ }
-class RegisterAllocatorTest : public TestWithZone {
- public:
- static const int kDefaultNRegs = 4;
+ static TestOperand Slot(int index = kNoValue) { return Slot(VReg(), index); }
+
+ static TestOperand Use(VReg vreg) { return TestOperand(kNone, vreg); }
+
+ static TestOperand Use() { return Use(VReg()); }
+
+ enum BlockCompletionType { kBlockEnd, kFallThrough, kBranch, kJump };
+
+ struct BlockCompletion {
+ BlockCompletionType type_;
+ TestOperand op_;
+ int offset_0_;
+ int offset_1_;
+ };
+
+ static BlockCompletion FallThrough() {
+ BlockCompletion completion = {kFallThrough, TestOperand(), 1, kNoValue};
+ return completion;
+ }
+
+ static BlockCompletion Jump(int offset) {
+ BlockCompletion completion = {kJump, TestOperand(), offset, kNoValue};
+ return completion;
+ }
+
+ static BlockCompletion Branch(TestOperand op, int left_offset,
+ int right_offset) {
+ BlockCompletion completion = {kBranch, op, left_offset, right_offset};
+ return completion;
+ }
+
+ static BlockCompletion Last() {
+ BlockCompletion completion = {kBlockEnd, TestOperand(), kNoValue, kNoValue};
+ return completion;
+ }
RegisterAllocatorTest()
: num_general_registers_(kDefaultNRegs),
num_double_registers_(kDefaultNRegs),
instruction_blocks_(zone()),
+ current_instruction_index_(-1),
current_block_(nullptr),
- is_last_block_(false),
block_returns_(false) {
InitializeRegisterNames();
}
void SetNumRegs(int num_general_registers, int num_double_registers) {
+ CHECK(config_.is_empty());
+ CHECK(instructions_.empty());
CHECK(instruction_blocks_.empty());
num_general_registers_ = num_general_registers;
num_double_registers_ = num_double_registers;
@@ -136,48 +188,41 @@ class RegisterAllocatorTest : public TestWithZone {
loop_blocks_.pop_back();
}
- void StartLastBlock() {
- CHECK(!is_last_block_);
- is_last_block_ = true;
- NewBlock();
- }
-
void StartBlock() {
- CHECK(!is_last_block_);
block_returns_ = false;
NewBlock();
}
- void EndBlock(BlockCompletion completion = FallThrough()) {
- completions_.push_back(completion);
+ int EndBlock(BlockCompletion completion = FallThrough()) {
+ int instruction_index = kMinInt;
+ if (block_returns_) {
+ CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough);
+ completion.type_ = kBlockEnd;
+ }
switch (completion.type_) {
case kBlockEnd:
- CHECK(false); // unreachable;
break;
case kFallThrough:
- if (is_last_block_ || block_returns_) {
- completions_.back().type_ = kBlockEnd;
- break;
- }
- EmitFallThrough();
+ instruction_index = EmitFallThrough();
break;
case kJump:
CHECK(!block_returns_);
- EmitJump();
+ instruction_index = EmitJump();
break;
case kBranch:
CHECK(!block_returns_);
- EmitBranch(completion.vreg_);
+ instruction_index = EmitBranch(completion.op_);
break;
}
+ completions_.push_back(completion);
CHECK(current_block_ != nullptr);
sequence()->EndBlock(current_block_->rpo_number());
current_block_ = nullptr;
+ return instruction_index;
}
void Allocate() {
CHECK_EQ(nullptr, current_block_);
- CHECK(is_last_block_);
WireBlocks();
RegisterAllocatorVerifier verifier(zone(), config(), sequence());
if (FLAG_trace_alloc || FLAG_trace_turbo) {
@@ -195,111 +240,110 @@ class RegisterAllocatorTest : public TestWithZone {
verifier.VerifyGapMoves();
}
- int NewReg() { return sequence()->NextVirtualRegister(); }
+ TestOperand Imm(int32_t imm = 0) {
+ int index = sequence()->AddImmediate(Constant(imm));
+ return TestOperand(kImmediate, index);
+ }
- int Parameter() {
- int vreg = NewReg();
- InstructionOperand* outputs[1]{UseRegister(vreg)};
- Emit(kArchNop, 1, outputs);
+ VReg Parameter(TestOperand output_op = Reg()) {
+ VReg vreg = NewReg();
+ InstructionOperand* outputs[1]{ConvertOutputOp(vreg, output_op)};
+ Emit(vreg.value_, kArchNop, 1, outputs);
return vreg;
}
- Instruction* Return(int vreg) {
+ int Return(TestOperand input_op_0) {
block_returns_ = true;
- InstructionOperand* inputs[1]{UseRegister(vreg)};
- return Emit(kArchRet, 0, nullptr, 1, inputs);
+ InstructionOperand* inputs[1]{ConvertInputOp(input_op_0)};
+ return Emit(NewIndex(), kArchRet, 0, nullptr, 1, inputs);
}
- PhiInstruction* Phi(int vreg) {
- PhiInstruction* phi = new (zone()) PhiInstruction(zone(), NewReg());
- phi->operands().push_back(vreg);
+ int Return(VReg vreg) { return Return(Reg(vreg, 0)); }
+
+ PhiInstruction* Phi(VReg incoming_vreg) {
+ PhiInstruction* phi = new (zone()) PhiInstruction(zone(), NewReg().value_);
+ phi->operands().push_back(incoming_vreg.value_);
current_block_->AddPhi(phi);
return phi;
}
- int DefineConstant(int32_t imm = 0) {
- int virtual_register = NewReg();
- sequence()->AddConstant(virtual_register, Constant(imm));
- InstructionOperand* outputs[1]{
- ConstantOperand::Create(virtual_register, zone())};
- Emit(kArchNop, 1, outputs);
- return virtual_register;
- }
-
- ImmediateOperand* Immediate(int32_t imm = 0) {
- int index = sequence()->AddImmediate(Constant(imm));
- return ImmediateOperand::Create(index, zone());
- }
-
- Instruction* EmitFRI(int output_vreg, int input_vreg_0) {
- InstructionOperand* outputs[1]{DefineSameAsFirst(output_vreg)};
- InstructionOperand* inputs[2]{UseRegister(input_vreg_0), Immediate()};
- return Emit(kArchNop, 1, outputs, 2, inputs);
+ PhiInstruction* Phi(VReg incoming_vreg_0, VReg incoming_vreg_1) {
+ auto phi = Phi(incoming_vreg_0);
+ Extend(phi, incoming_vreg_1);
+ return phi;
}
- Instruction* EmitFRU(int output_vreg, int input_vreg_0, int input_vreg_1) {
- InstructionOperand* outputs[1]{DefineSameAsFirst(output_vreg)};
- InstructionOperand* inputs[2]{UseRegister(input_vreg_0), Use(input_vreg_1)};
- return Emit(kArchNop, 1, outputs, 2, inputs);
+ static void Extend(PhiInstruction* phi, VReg vreg) {
+ phi->operands().push_back(vreg.value_);
}
- Instruction* EmitRRR(int output_vreg, int input_vreg_0, int input_vreg_1) {
- InstructionOperand* outputs[1]{UseRegister(output_vreg)};
- InstructionOperand* inputs[2]{UseRegister(input_vreg_0),
- UseRegister(input_vreg_1)};
- return Emit(kArchNop, 1, outputs, 2, inputs);
+ VReg DefineConstant(int32_t imm = 0) {
+ VReg vreg = NewReg();
+ sequence()->AddConstant(vreg.value_, Constant(imm));
+ InstructionOperand* outputs[1]{
+ ConstantOperand::Create(vreg.value_, zone())};
+ Emit(vreg.value_, kArchNop, 1, outputs);
+ return vreg;
}
- private:
- InstructionOperand* Unallocated(int vreg,
- UnallocatedOperand::ExtendedPolicy policy) {
- UnallocatedOperand* op = new (zone()) UnallocatedOperand(policy);
- op->set_virtual_register(vreg);
- return op;
+ VReg EmitOII(TestOperand output_op, TestOperand input_op_0,
+ TestOperand input_op_1) {
+ VReg output_vreg = NewReg();
+ InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
+ InstructionOperand* inputs[2]{ConvertInputOp(input_op_0),
+ ConvertInputOp(input_op_1)};
+ Emit(output_vreg.value_, kArchNop, 1, outputs, 2, inputs);
+ return output_vreg;
}
- InstructionOperand* Unallocated(int vreg,
- UnallocatedOperand::ExtendedPolicy policy,
- UnallocatedOperand::Lifetime lifetime) {
- UnallocatedOperand* op = new (zone()) UnallocatedOperand(policy, lifetime);
- op->set_virtual_register(vreg);
- return op;
+ VReg EmitCall(TestOperand output_op, size_t input_size, TestOperand* inputs) {
+ VReg output_vreg = NewReg();
+ InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
+ 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]);
+ }
+ Emit(output_vreg.value_, kArchCallCodeObject, 1, outputs, input_size,
+ mapped_inputs);
+ return output_vreg;
}
- InstructionOperand* UseRegister(int vreg) {
- return Unallocated(vreg, UnallocatedOperand::MUST_HAVE_REGISTER);
+ // Get defining instruction vreg or value returned at instruction creation
+ // time when there is no return value.
+ const Instruction* GetInstruction(int instruction_index) {
+ auto it = instructions_.find(instruction_index);
+ CHECK(it != instructions_.end());
+ return it->second;
}
- InstructionOperand* DefineSameAsFirst(int vreg) {
- return Unallocated(vreg, UnallocatedOperand::SAME_AS_FIRST_INPUT);
- }
+ private:
+ VReg NewReg() { return VReg(sequence()->NextVirtualRegister()); }
+ int NewIndex() { return current_instruction_index_--; }
- InstructionOperand* Use(int vreg) {
- return Unallocated(vreg, UnallocatedOperand::NONE,
- UnallocatedOperand::USED_AT_START);
- }
+ static TestOperand Invalid() { return TestOperand(kInvalid, VReg()); }
- void EmitBranch(int vreg) {
- InstructionOperand* inputs[4]{UseRegister(vreg), Immediate(), Immediate(),
- Immediate()};
+ int EmitBranch(TestOperand input_op) {
+ InstructionOperand* inputs[4]{ConvertInputOp(input_op),
+ ConvertInputOp(Imm()), ConvertInputOp(Imm()),
+ ConvertInputOp(Imm())};
InstructionCode opcode = kArchJmp | FlagsModeField::encode(kFlags_branch) |
FlagsConditionField::encode(kEqual);
- Instruction* instruction =
+ auto instruction =
NewInstruction(opcode, 0, nullptr, 4, inputs)->MarkAsControl();
- sequence()->AddInstruction(instruction);
+ return AddInstruction(NewIndex(), instruction);
}
- void EmitFallThrough() {
- Instruction* instruction =
- NewInstruction(kArchNop, 0, nullptr)->MarkAsControl();
- sequence()->AddInstruction(instruction);
+ int EmitFallThrough() {
+ auto instruction = NewInstruction(kArchNop, 0, nullptr)->MarkAsControl();
+ return AddInstruction(NewIndex(), instruction);
}
- void EmitJump() {
- InstructionOperand* inputs[1]{Immediate()};
- Instruction* instruction =
+ int EmitJump() {
+ InstructionOperand* inputs[1]{ConvertInputOp(Imm())};
+ auto instruction =
NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl();
- sequence()->AddInstruction(instruction);
+ return AddInstruction(NewIndex(), instruction);
}
Instruction* NewInstruction(InstructionCode code, size_t outputs_size,
@@ -313,21 +357,83 @@ class RegisterAllocatorTest : public TestWithZone {
inputs, temps_size, temps);
}
- Instruction* Emit(InstructionCode code, size_t outputs_size,
- InstructionOperand** outputs, size_t inputs_size = 0,
- InstructionOperand* *inputs = nullptr,
- size_t temps_size = 0,
- InstructionOperand* *temps = nullptr) {
- Instruction* instruction = NewInstruction(
- code, outputs_size, outputs, inputs_size, inputs, temps_size, temps);
- sequence()->AddInstruction(instruction);
- return instruction;
+ InstructionOperand* Unallocated(TestOperand op,
+ UnallocatedOperand::ExtendedPolicy policy) {
+ auto unallocated = new (zone()) UnallocatedOperand(policy);
+ unallocated->set_virtual_register(op.vreg_.value_);
+ return unallocated;
+ }
+
+ InstructionOperand* Unallocated(TestOperand op,
+ UnallocatedOperand::ExtendedPolicy policy,
+ UnallocatedOperand::Lifetime lifetime) {
+ auto unallocated = new (zone()) UnallocatedOperand(policy, lifetime);
+ unallocated->set_virtual_register(op.vreg_.value_);
+ return unallocated;
+ }
+
+ InstructionOperand* Unallocated(TestOperand op,
+ UnallocatedOperand::ExtendedPolicy policy,
+ int index) {
+ auto unallocated = new (zone()) UnallocatedOperand(policy, index);
+ unallocated->set_virtual_register(op.vreg_.value_);
+ return unallocated;
+ }
+
+ InstructionOperand* Unallocated(TestOperand op,
+ UnallocatedOperand::BasicPolicy policy,
+ int index) {
+ auto unallocated = new (zone()) UnallocatedOperand(policy, index);
+ unallocated->set_virtual_register(op.vreg_.value_);
+ return unallocated;
+ }
+
+ InstructionOperand* ConvertInputOp(TestOperand op) {
+ if (op.type_ == kImmediate) {
+ CHECK_EQ(op.vreg_.value_, kNoValue);
+ return ImmediateOperand::Create(op.value_, zone());
+ }
+ CHECK_NE(op.vreg_.value_, kNoValue);
+ switch (op.type_) {
+ case kNone:
+ return Unallocated(op, UnallocatedOperand::NONE,
+ UnallocatedOperand::USED_AT_START);
+ case kRegister:
+ return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER,
+ UnallocatedOperand::USED_AT_START);
+ case kFixedRegister:
+ CHECK(0 <= op.value_ && op.value_ < num_general_registers_);
+ return Unallocated(op, UnallocatedOperand::FIXED_REGISTER, op.value_);
+ default:
+ break;
+ }
+ CHECK(false);
+ return NULL;
+ }
+
+ InstructionOperand* ConvertOutputOp(VReg vreg, TestOperand op) {
+ CHECK_EQ(op.vreg_.value_, kNoValue);
+ op.vreg_ = vreg;
+ switch (op.type_) {
+ case kSameAsFirst:
+ return Unallocated(op, UnallocatedOperand::SAME_AS_FIRST_INPUT);
+ case kRegister:
+ return Unallocated(op, UnallocatedOperand::MUST_HAVE_REGISTER);
+ case kFixedSlot:
+ 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_);
+ default:
+ break;
+ }
+ CHECK(false);
+ return NULL;
}
InstructionBlock* NewBlock() {
CHECK(current_block_ == nullptr);
- BasicBlock::Id block_id =
- BasicBlock::Id::FromSize(instruction_blocks_.size());
+ auto block_id = BasicBlock::Id::FromSize(instruction_blocks_.size());
Rpo rpo = Rpo::FromInt(block_id.ToInt());
Rpo loop_header = Rpo::Invalid();
Rpo loop_end = Rpo::Invalid();
@@ -347,7 +453,7 @@ class RegisterAllocatorTest : public TestWithZone {
}
}
// Construct instruction block.
- InstructionBlock* instruction_block = new (zone()) InstructionBlock(
+ auto instruction_block = new (zone()) InstructionBlock(
zone(), block_id, rpo, rpo, loop_header, loop_end, false);
instruction_blocks_.push_back(instruction_block);
current_block_ = instruction_block;
@@ -380,17 +486,33 @@ class RegisterAllocatorTest : public TestWithZone {
block_offset + static_cast<size_t>(jump_offset);
CHECK(block_offset < instruction_blocks_.size());
CHECK(target_block_offset < instruction_blocks_.size());
- InstructionBlock* block = instruction_blocks_[block_offset];
- InstructionBlock* target = instruction_blocks_[target_block_offset];
+ auto block = instruction_blocks_[block_offset];
+ auto target = instruction_blocks_[target_block_offset];
block->successors().push_back(target->rpo_number());
target->predecessors().push_back(block->rpo_number());
}
+ int Emit(int instruction_index, InstructionCode code, size_t outputs_size,
+ InstructionOperand** outputs, size_t inputs_size = 0,
+ InstructionOperand* *inputs = nullptr, size_t temps_size = 0,
+ InstructionOperand* *temps = nullptr) {
+ auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size,
+ inputs, temps_size, temps);
+ return AddInstruction(instruction_index, instruction);
+ }
+
+ int AddInstruction(int instruction_index, Instruction* instruction) {
+ sequence()->AddInstruction(instruction);
+ return instruction_index;
+ }
+
struct LoopData {
Rpo loop_header_;
int expected_blocks_;
};
+
typedef std::vector<LoopData> LoopBlocks;
+ typedef std::map<int, const Instruction*> Instructions;
typedef std::vector<BlockCompletion> Completions;
SmartPointer<RegisterConfiguration> config_;
@@ -402,45 +524,42 @@ class RegisterAllocatorTest : public TestWithZone {
// Block building state.
InstructionBlocks instruction_blocks_;
+ Instructions instructions_;
+ int current_instruction_index_;
Completions completions_;
LoopBlocks loop_blocks_;
InstructionBlock* current_block_;
- bool is_last_block_;
bool block_returns_;
};
TEST_F(RegisterAllocatorTest, CanAllocateThreeRegisters) {
- StartLastBlock();
- int a_reg = Parameter();
- int b_reg = Parameter();
- int c_reg = NewReg();
- Instruction* res = EmitRRR(c_reg, a_reg, b_reg);
+ // return p0 + p1;
+ StartBlock();
+ auto a_reg = Parameter();
+ auto b_reg = Parameter();
+ auto c_reg = EmitOII(Reg(1), Reg(a_reg, 1), Reg(b_reg, 0));
Return(c_reg);
- EndBlock();
+ EndBlock(Last());
Allocate();
-
- ASSERT_TRUE(res->OutputAt(0)->IsRegister());
}
TEST_F(RegisterAllocatorTest, SimpleLoop) {
// i = K;
// while(true) { i++ }
-
StartBlock();
- int i_reg = DefineConstant();
+ auto i_reg = DefineConstant();
EndBlock();
{
StartLoop(1);
- StartLastBlock();
- PhiInstruction* phi = Phi(i_reg);
- int ipp = NewReg();
- EmitFRU(ipp, phi->virtual_register(), DefineConstant());
- phi->operands().push_back(ipp);
+ StartBlock();
+ auto phi = Phi(i_reg);
+ auto ipp = EmitOII(Same(), Reg(phi), Use(DefineConstant()));
+ Extend(phi, ipp);
EndBlock(Jump(0));
EndLoop();
@@ -453,15 +572,127 @@ TEST_F(RegisterAllocatorTest, SimpleLoop) {
TEST_F(RegisterAllocatorTest, SimpleBranch) {
// return i ? K1 : K2
StartBlock();
- int i_reg = DefineConstant();
- EndBlock(Branch(i_reg, 1, 2));
+ auto i = DefineConstant();
+ EndBlock(Branch(Reg(i), 1, 2));
StartBlock();
Return(DefineConstant());
- EndBlock();
+ EndBlock(Last());
- StartLastBlock();
+ StartBlock();
Return(DefineConstant());
+ EndBlock(Last());
+
+ Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, 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(RegisterAllocatorTest, 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(RegisterAllocatorTest, DiamondManyPhis) {
+ const int kPhis = kDefaultNRegs * 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(Reg(), kPhis, merged));
+ EndBlock();
+
+ Allocate();
+}
+
+
+TEST_F(RegisterAllocatorTest, DoubleDiamondManyRedundantPhis) {
+ const int kPhis = kDefaultNRegs * 2;
+
+ // First diamond.
+ StartBlock();
+ VReg vals[kPhis];
+ for (int i = 0; i < kPhis; ++i) {
+ vals[i] = Parameter(Slot(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(), kPhis, merged));
EndBlock();
Allocate();
@@ -471,14 +702,12 @@ TEST_F(RegisterAllocatorTest, SimpleBranch) {
TEST_F(RegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) {
const size_t kNumRegs = 3;
const size_t kParams = kNumRegs + 1;
- int parameters[kParams];
-
// Override number of registers.
SetNumRegs(kNumRegs, kNumRegs);
- // Initial block.
StartBlock();
- int constant = DefineConstant();
+ auto constant = DefineConstant();
+ VReg parameters[kParams];
for (size_t i = 0; i < arraysize(parameters); ++i) {
parameters[i] = DefineConstant();
}
@@ -498,12 +727,11 @@ TEST_F(RegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) {
// Perform some computations.
// something like phi[i] += const
for (size_t i = 0; i < arraysize(parameters); ++i) {
- int result = NewReg();
- EmitFRU(result, phis[i]->virtual_register(), constant);
- phis[i]->operands().push_back(result);
+ auto result = EmitOII(Same(), Reg(phis[i]), Use(constant));
+ Extend(phis[i], result);
}
- EndBlock(Branch(DefineConstant(), 1, 2));
+ EndBlock(Branch(Reg(DefineConstant()), 1, 2));
// Jump back to loop header.
StartBlock();
@@ -512,10 +740,7 @@ TEST_F(RegisterAllocatorTest, RegressionPhisNeedTooManyRegisters) {
EndLoop();
}
- // End block.
- StartLastBlock();
-
- // Return sum.
+ StartBlock();
Return(DefineConstant());
EndBlock();
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698