diff options
Diffstat (limited to 'deps/v8/test/unittests/interpreter/bytecode-register-optimizer-unittest.cc')
-rw-r--r-- | deps/v8/test/unittests/interpreter/bytecode-register-optimizer-unittest.cc | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/deps/v8/test/unittests/interpreter/bytecode-register-optimizer-unittest.cc b/deps/v8/test/unittests/interpreter/bytecode-register-optimizer-unittest.cc new file mode 100644 index 0000000000..ca69026fda --- /dev/null +++ b/deps/v8/test/unittests/interpreter/bytecode-register-optimizer-unittest.cc @@ -0,0 +1,219 @@ +// Copyright 2016 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/v8.h" + +#include "src/factory.h" +#include "src/interpreter/bytecode-label.h" +#include "src/interpreter/bytecode-register-optimizer.h" +#include "src/objects-inl.h" +#include "src/objects.h" +#include "test/unittests/test-utils.h" + +namespace v8 { +namespace internal { +namespace interpreter { + +class BytecodeRegisterOptimizerTest : public BytecodePipelineStage, + public TestWithIsolateAndZone { + public: + BytecodeRegisterOptimizerTest() {} + ~BytecodeRegisterOptimizerTest() override { delete register_allocator_; } + + void Initialize(int number_of_parameters, int number_of_locals) { + register_allocator_ = + new TemporaryRegisterAllocator(zone(), number_of_locals); + register_optimizer_ = new (zone()) BytecodeRegisterOptimizer( + zone(), register_allocator_, number_of_parameters, this); + } + + void Write(BytecodeNode* node) override { output_.push_back(*node); } + void WriteJump(BytecodeNode* node, BytecodeLabel* label) override { + output_.push_back(*node); + } + void BindLabel(BytecodeLabel* label) override {} + void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) override {} + Handle<BytecodeArray> ToBytecodeArray( + Isolate* isolate, int fixed_register_count, int parameter_count, + Handle<FixedArray> handle_table) override { + return Handle<BytecodeArray>(); + } + + TemporaryRegisterAllocator* allocator() { return register_allocator_; } + BytecodeRegisterOptimizer* optimizer() { return register_optimizer_; } + + Register NewTemporary() { + return Register(allocator()->BorrowTemporaryRegister()); + } + + void KillTemporary(Register reg) { + allocator()->ReturnTemporaryRegister(reg.index()); + } + + size_t write_count() const { return output_.size(); } + const BytecodeNode& last_written() const { return output_.back(); } + const std::vector<BytecodeNode>* output() { return &output_; } + + private: + TemporaryRegisterAllocator* register_allocator_; + BytecodeRegisterOptimizer* register_optimizer_; + + std::vector<BytecodeNode> output_; +}; + +// Sanity tests. + +TEST_F(BytecodeRegisterOptimizerTest, WriteNop) { + Initialize(1, 1); + BytecodeNode node(Bytecode::kNop); + optimizer()->Write(&node); + CHECK_EQ(write_count(), 1); + CHECK_EQ(node, last_written()); +} + +TEST_F(BytecodeRegisterOptimizerTest, WriteNopExpression) { + Initialize(1, 1); + BytecodeNode node(Bytecode::kNop); + node.source_info().MakeExpressionPosition(3); + optimizer()->Write(&node); + CHECK_EQ(write_count(), 1); + CHECK_EQ(node, last_written()); +} + +TEST_F(BytecodeRegisterOptimizerTest, WriteNopStatement) { + Initialize(1, 1); + BytecodeNode node(Bytecode::kNop); + node.source_info().MakeStatementPosition(3); + optimizer()->Write(&node); + CHECK_EQ(write_count(), 1); + CHECK_EQ(node, last_written()); +} + +TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForJump) { + Initialize(1, 1); + Register temp = NewTemporary(); + BytecodeNode node(Bytecode::kStar, temp.ToOperand()); + optimizer()->Write(&node); + CHECK_EQ(write_count(), 0); + BytecodeLabel label; + BytecodeNode jump(Bytecode::kJump, 0); + optimizer()->WriteJump(&jump, &label); + CHECK_EQ(write_count(), 2); + CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); + CHECK_EQ(output()->at(0).operand(0), temp.ToOperand()); + CHECK_EQ(output()->at(1).bytecode(), Bytecode::kJump); +} + +TEST_F(BytecodeRegisterOptimizerTest, TemporaryMaterializedForBind) { + Initialize(1, 1); + Register temp = NewTemporary(); + BytecodeNode node(Bytecode::kStar, temp.ToOperand()); + optimizer()->Write(&node); + CHECK_EQ(write_count(), 0); + BytecodeLabel label; + optimizer()->BindLabel(&label); + CHECK_EQ(write_count(), 1); + CHECK_EQ(output()->at(0).bytecode(), Bytecode::kStar); + CHECK_EQ(output()->at(0).operand(0), temp.ToOperand()); +} + +// Basic Register Optimizations + +TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) { + Initialize(3, 1); + Register parameter = Register::FromParameterIndex(1, 3); + BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand()); + optimizer()->Write(&node0); + CHECK_EQ(write_count(), 0); + Register temp = NewTemporary(); + BytecodeNode node1(Bytecode::kStar, NewTemporary().ToOperand()); + optimizer()->Write(&node1); + CHECK_EQ(write_count(), 0); + KillTemporary(temp); + CHECK_EQ(write_count(), 0); + BytecodeNode node2(Bytecode::kReturn); + optimizer()->Write(&node2); + CHECK_EQ(write_count(), 2); + CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdar); + CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand()); + CHECK_EQ(output()->at(1).bytecode(), Bytecode::kReturn); +} + +TEST_F(BytecodeRegisterOptimizerTest, StoresToLocalsImmediate) { + Initialize(3, 1); + Register parameter = Register::FromParameterIndex(1, 3); + BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand()); + optimizer()->Write(&node0); + CHECK_EQ(write_count(), 0); + Register local = Register(0); + BytecodeNode node1(Bytecode::kStar, local.ToOperand()); + optimizer()->Write(&node1); + CHECK_EQ(write_count(), 1); + CHECK_EQ(output()->at(0).bytecode(), Bytecode::kMov); + CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand()); + CHECK_EQ(output()->at(0).operand(1), local.ToOperand()); + + BytecodeNode node2(Bytecode::kReturn); + optimizer()->Write(&node2); + CHECK_EQ(write_count(), 3); + CHECK_EQ(output()->at(1).bytecode(), Bytecode::kLdar); + CHECK_EQ(output()->at(1).operand(0), local.ToOperand()); + CHECK_EQ(output()->at(2).bytecode(), Bytecode::kReturn); +} + +TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotMaterializedForInput) { + Initialize(3, 1); + Register parameter = Register::FromParameterIndex(1, 3); + Register temp0 = NewTemporary(); + Register temp1 = NewTemporary(); + BytecodeNode node0(Bytecode::kMov, parameter.ToOperand(), temp0.ToOperand()); + optimizer()->Write(&node0); + BytecodeNode node1(Bytecode::kMov, parameter.ToOperand(), temp1.ToOperand()); + optimizer()->Write(&node1); + CHECK_EQ(write_count(), 0); + BytecodeNode node2(Bytecode::kCallJSRuntime, 0, temp0.ToOperand(), 1); + optimizer()->Write(&node2); + CHECK_EQ(write_count(), 1); + CHECK_EQ(output()->at(0).bytecode(), Bytecode::kCallJSRuntime); + CHECK_EQ(output()->at(0).operand(0), 0); + CHECK_EQ(output()->at(0).operand(1), parameter.ToOperand()); + CHECK_EQ(output()->at(0).operand(2), 1); +} + +TEST_F(BytecodeRegisterOptimizerTest, RangeOfTemporariesMaterializedForInput) { + Initialize(3, 1); + Register parameter = Register::FromParameterIndex(1, 3); + Register temp0 = NewTemporary(); + Register temp1 = NewTemporary(); + BytecodeNode node0(Bytecode::kLdaSmi, 3); + optimizer()->Write(&node0); + CHECK_EQ(write_count(), 1); + BytecodeNode node1(Bytecode::kStar, temp0.ToOperand()); + optimizer()->Write(&node1); + BytecodeNode node2(Bytecode::kMov, parameter.ToOperand(), temp1.ToOperand()); + optimizer()->Write(&node2); + CHECK_EQ(write_count(), 1); + BytecodeNode node3(Bytecode::kCallJSRuntime, 0, temp0.ToOperand(), 2); + optimizer()->Write(&node3); + CHECK_EQ(write_count(), 4); + + CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdaSmi); + CHECK_EQ(output()->at(0).operand(0), 3); + + CHECK_EQ(output()->at(1).bytecode(), Bytecode::kStar); + CHECK_EQ(output()->at(1).operand(0), temp0.ToOperand()); + + CHECK_EQ(output()->at(2).bytecode(), Bytecode::kMov); + CHECK_EQ(output()->at(2).operand(0), parameter.ToOperand()); + CHECK_EQ(output()->at(2).operand(1), temp1.ToOperand()); + + CHECK_EQ(output()->at(3).bytecode(), Bytecode::kCallJSRuntime); + CHECK_EQ(output()->at(3).operand(0), 0); + CHECK_EQ(output()->at(3).operand(1), temp0.ToOperand()); + CHECK_EQ(output()->at(3).operand(2), 2); +} + +} // namespace interpreter +} // namespace internal +} // namespace v8 |