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

Unified Diff: test/unittests/compiler/instruction-sequence-unittest.cc

Issue 750813004: [turbofan] add initial move optimizer (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: rebase 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
Index: test/unittests/compiler/instruction-sequence-unittest.cc
diff --git a/test/unittests/compiler/instruction-sequence-unittest.cc b/test/unittests/compiler/instruction-sequence-unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..05d3d0ae14a497f9bcbb3706a8d5b45909488a82
--- /dev/null
+++ b/test/unittests/compiler/instruction-sequence-unittest.cc
@@ -0,0 +1,452 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/base/utils/random-number-generator.h"
+#include "src/compiler/pipeline.h"
+#include "test/unittests/compiler/instruction-sequence-unittest.h"
+#include "test/unittests/test-utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+static const char*
+ general_register_names_[RegisterConfiguration::kMaxGeneralRegisters];
+static const char*
+ double_register_names_[RegisterConfiguration::kMaxDoubleRegisters];
+static char register_names_[10 * (RegisterConfiguration::kMaxGeneralRegisters +
+ RegisterConfiguration::kMaxDoubleRegisters)];
+
+
+static void InitializeRegisterNames() {
+ char* loc = register_names_;
+ for (int i = 0; i < RegisterConfiguration::kMaxGeneralRegisters; ++i) {
+ general_register_names_[i] = loc;
+ loc += base::OS::SNPrintF(loc, 100, "gp_%d", i);
+ *loc++ = 0;
+ }
+ for (int i = 0; i < RegisterConfiguration::kMaxDoubleRegisters; ++i) {
+ double_register_names_[i] = loc;
+ loc += base::OS::SNPrintF(loc, 100, "fp_%d", i) + 1;
+ *loc++ = 0;
+ }
+}
+
+
+InstructionSequenceTest::InstructionSequenceTest()
+ : sequence_(nullptr),
+ num_general_registers_(kDefaultNRegs),
+ num_double_registers_(kDefaultNRegs),
+ instruction_blocks_(zone()),
+ current_instruction_index_(-1),
+ current_block_(nullptr),
+ block_returns_(false) {
+ InitializeRegisterNames();
+}
+
+
+void InstructionSequenceTest::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;
+}
+
+
+RegisterConfiguration* InstructionSequenceTest::config() {
+ if (config_.is_empty()) {
+ config_.Reset(new RegisterConfiguration(
+ num_general_registers_, num_double_registers_, num_double_registers_,
+ general_register_names_, double_register_names_));
+ }
+ return config_.get();
+}
+
+
+InstructionSequence* InstructionSequenceTest::sequence() {
+ if (sequence_ == nullptr) {
+ sequence_ = new (zone()) InstructionSequence(zone(), &instruction_blocks_);
+ }
+ return sequence_;
+}
+
+
+void InstructionSequenceTest::StartLoop(int loop_blocks) {
+ CHECK(current_block_ == nullptr);
+ if (!loop_blocks_.empty()) {
+ CHECK(!loop_blocks_.back().loop_header_.IsValid());
+ }
+ LoopData loop_data = {Rpo::Invalid(), loop_blocks};
+ loop_blocks_.push_back(loop_data);
+}
+
+
+void InstructionSequenceTest::EndLoop() {
+ CHECK(current_block_ == nullptr);
+ CHECK(!loop_blocks_.empty());
+ CHECK_EQ(0, loop_blocks_.back().expected_blocks_);
+ loop_blocks_.pop_back();
+}
+
+
+void InstructionSequenceTest::StartBlock() {
+ block_returns_ = false;
+ NewBlock();
+}
+
+
+int InstructionSequenceTest::EndBlock(BlockCompletion completion) {
+ int instruction_index = kMinInt;
+ if (block_returns_) {
+ CHECK(completion.type_ == kBlockEnd || completion.type_ == kFallThrough);
+ completion.type_ = kBlockEnd;
+ }
+ switch (completion.type_) {
+ case kBlockEnd:
+ break;
+ case kFallThrough:
+ instruction_index = EmitFallThrough();
+ break;
+ case kJump:
+ CHECK(!block_returns_);
+ instruction_index = EmitJump();
+ break;
+ case kBranch:
+ CHECK(!block_returns_);
+ 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;
+}
+
+
+InstructionSequenceTest::TestOperand InstructionSequenceTest::Imm(int32_t imm) {
+ int index = sequence()->AddImmediate(Constant(imm));
+ return TestOperand(kImmediate, index);
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::Define(
+ TestOperand output_op) {
+ VReg vreg = NewReg();
+ InstructionOperand* outputs[1]{ConvertOutputOp(vreg, output_op)};
+ Emit(vreg.value_, kArchNop, 1, outputs);
+ return vreg;
+}
+
+
+int InstructionSequenceTest::Return(TestOperand input_op_0) {
+ block_returns_ = true;
+ InstructionOperand* inputs[1]{ConvertInputOp(input_op_0)};
+ return Emit(NewIndex(), kArchRet, 0, nullptr, 1, inputs);
+}
+
+
+PhiInstruction* InstructionSequenceTest::Phi(VReg incoming_vreg_0,
+ VReg incoming_vreg_1,
+ VReg incoming_vreg_2,
+ VReg incoming_vreg_3) {
+ auto phi = new (zone()) PhiInstruction(zone(), NewReg().value_, 10);
+ VReg inputs[] = {incoming_vreg_0, incoming_vreg_1, incoming_vreg_2,
+ incoming_vreg_3};
+ for (size_t i = 0; i < arraysize(inputs); ++i) {
+ if (inputs[i].value_ == kNoValue) break;
+ Extend(phi, inputs[i]);
+ }
+ current_block_->AddPhi(phi);
+ return phi;
+}
+
+
+void InstructionSequenceTest::Extend(PhiInstruction* phi, VReg vreg) {
+ phi->Extend(zone(), vreg.value_);
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::DefineConstant(
+ int32_t imm) {
+ 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;
+}
+
+
+int InstructionSequenceTest::EmitNop() { return Emit(NewIndex(), kArchNop); }
+
+
+int InstructionSequenceTest::EmitI(TestOperand input_op_0) {
+ InstructionOperand* inputs[1]{ConvertInputOp(input_op_0)};
+ return Emit(NewIndex(), kArchNop, 0, nullptr, 1, inputs);
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::EmitOI(
+ TestOperand output_op, TestOperand input_op_0) {
+ VReg output_vreg = NewReg();
+ InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
+ InstructionOperand* inputs[1]{ConvertInputOp(input_op_0)};
+ Emit(output_vreg.value_, kArchNop, 1, outputs, 1, inputs);
+ return output_vreg;
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::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;
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
+ TestOperand output_op, size_t input_size, TestOperand* inputs) {
+ VReg output_vreg = NewReg();
+ InstructionOperand* outputs[1]{ConvertOutputOp(output_vreg, output_op)};
+ CHECK(UnallocatedOperand::cast(outputs[0])->HasFixedPolicy());
+ 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, 0, nullptr, true);
+ return output_vreg;
+}
+
+
+InstructionSequenceTest::VReg InstructionSequenceTest::EmitCall(
+ TestOperand output_op, 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};
+ size_t size = 0;
+ for (; size < arraysize(inputs); ++size) {
+ if (inputs[size].type_ == kInvalid) break;
+ }
+ return EmitCall(output_op, size, inputs);
+}
+
+
+const Instruction* InstructionSequenceTest::GetInstruction(
+ int instruction_index) {
+ auto it = instructions_.find(instruction_index);
+ CHECK(it != instructions_.end());
+ return it->second;
+}
+
+
+int InstructionSequenceTest::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);
+ auto instruction =
+ NewInstruction(opcode, 0, nullptr, 4, inputs)->MarkAsControl();
+ return AddInstruction(NewIndex(), instruction);
+}
+
+
+int InstructionSequenceTest::EmitFallThrough() {
+ auto instruction = NewInstruction(kArchNop, 0, nullptr)->MarkAsControl();
+ return AddInstruction(NewIndex(), instruction);
+}
+
+
+int InstructionSequenceTest::EmitJump() {
+ InstructionOperand* inputs[1]{ConvertInputOp(Imm())};
+ auto instruction =
+ NewInstruction(kArchJmp, 0, nullptr, 1, inputs)->MarkAsControl();
+ return AddInstruction(NewIndex(), instruction);
+}
+
+
+Instruction* InstructionSequenceTest::NewInstruction(
+ InstructionCode code, size_t outputs_size, InstructionOperand** outputs,
+ size_t inputs_size, InstructionOperand** inputs, size_t temps_size,
+ InstructionOperand** temps) {
+ CHECK_NE(nullptr, current_block_);
+ return Instruction::New(zone(), code, outputs_size, outputs, inputs_size,
+ inputs, temps_size, temps);
+}
+
+
+InstructionOperand* InstructionSequenceTest::Unallocated(
+ TestOperand op, UnallocatedOperand::ExtendedPolicy policy) {
+ auto unallocated = new (zone()) UnallocatedOperand(policy);
+ unallocated->set_virtual_register(op.vreg_.value_);
+ return unallocated;
+}
+
+
+InstructionOperand* InstructionSequenceTest::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* InstructionSequenceTest::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* InstructionSequenceTest::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* InstructionSequenceTest::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_);
+ case kFixedSlot:
+ return Unallocated(op, UnallocatedOperand::FIXED_SLOT, op.value_);
+ default:
+ break;
+ }
+ CHECK(false);
+ return NULL;
+}
+
+
+InstructionOperand* InstructionSequenceTest::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* InstructionSequenceTest::NewBlock() {
+ CHECK(current_block_ == nullptr);
+ 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();
+ if (!loop_blocks_.empty()) {
+ auto& loop_data = loop_blocks_.back();
+ // This is a loop header.
+ if (!loop_data.loop_header_.IsValid()) {
+ loop_end = Rpo::FromInt(block_id.ToInt() + loop_data.expected_blocks_);
+ loop_data.expected_blocks_--;
+ loop_data.loop_header_ = rpo;
+ } else {
+ // This is a loop body.
+ CHECK_NE(0, loop_data.expected_blocks_);
+ // TODO(dcarney): handle nested loops.
+ loop_data.expected_blocks_--;
+ loop_header = loop_data.loop_header_;
+ }
+ }
+ // Construct instruction block.
+ 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;
+ sequence()->StartBlock(rpo);
+ return instruction_block;
+}
+
+
+void InstructionSequenceTest::WireBlocks() {
+ CHECK_EQ(nullptr, current_block());
+ CHECK(instruction_blocks_.size() == completions_.size());
+ size_t offset = 0;
+ for (const auto& completion : completions_) {
+ switch (completion.type_) {
+ case kBlockEnd:
+ break;
+ case kFallThrough: // Fallthrough.
+ case kJump:
+ WireBlock(offset, completion.offset_0_);
+ break;
+ case kBranch:
+ WireBlock(offset, completion.offset_0_);
+ WireBlock(offset, completion.offset_1_);
+ break;
+ }
+ ++offset;
+ }
+}
+
+
+void InstructionSequenceTest::WireBlock(size_t block_offset, int jump_offset) {
+ size_t target_block_offset = block_offset + static_cast<size_t>(jump_offset);
+ CHECK(block_offset < instruction_blocks_.size());
+ CHECK(target_block_offset < instruction_blocks_.size());
+ 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 InstructionSequenceTest::Emit(int instruction_index, InstructionCode code,
+ size_t outputs_size,
+ InstructionOperand** outputs,
+ size_t inputs_size,
+ InstructionOperand** inputs,
+ size_t temps_size, InstructionOperand** temps,
+ bool is_call) {
+ auto instruction = NewInstruction(code, outputs_size, outputs, inputs_size,
+ inputs, temps_size, temps);
+ if (is_call) instruction->MarkAsCall();
+ return AddInstruction(instruction_index, instruction);
+}
+
+
+int InstructionSequenceTest::AddInstruction(int instruction_index,
+ Instruction* instruction) {
+ sequence()->AddInstruction(instruction);
+ return instruction_index;
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
« no previous file with comments | « test/unittests/compiler/instruction-sequence-unittest.h ('k') | test/unittests/compiler/move-optimizer-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698