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

Side by Side Diff: test/unittests/interpreter/bytecode-register-optimizer-unittest.cc

Issue 1997653002: [interpreter] Bytecode register optimizer. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Decouple a test from implementation. Created 4 years, 6 months 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #include "src/factory.h"
8 #include "src/interpreter/bytecode-register-optimizer.h"
9 #include "src/objects-inl.h"
10 #include "src/objects.h"
11 #include "test/unittests/test-utils.h"
12
13 namespace v8 {
14 namespace internal {
15 namespace interpreter {
16
17 class BytecodeRegisterOptimizerTest : public BytecodePipelineStage,
18 public TestWithIsolateAndZone {
19 public:
20 BytecodeRegisterOptimizerTest() {}
21 ~BytecodeRegisterOptimizerTest() override { delete register_allocator_; }
22
23 void Initialize(int number_of_parameters, int number_of_locals) {
24 register_allocator_ =
25 new TemporaryRegisterAllocator(zone(), number_of_locals);
26 register_optimizer_ = new (zone()) BytecodeRegisterOptimizer(
27 zone(), register_allocator_, number_of_parameters, this);
28 }
29
30 size_t FlushForOffset() override {
31 flush_for_offset_count_++;
32 return 0;
33 };
34
35 void FlushBasicBlock() override { flush_basic_block_count_++; }
36
37 void Write(BytecodeNode* node) override { output_.push_back(*node); }
38
39 TemporaryRegisterAllocator* allocator() { return register_allocator_; }
40 BytecodeRegisterOptimizer* optimizer() { return register_optimizer_; }
41
42 Register NewTemporary() {
43 return Register(allocator()->BorrowTemporaryRegister());
44 }
45
46 void KillTemporary(Register reg) {
47 allocator()->ReturnTemporaryRegister(reg.index());
48 }
49
50 int flush_for_offset_count() const { return flush_for_offset_count_; }
51 int flush_basic_block_count() const { return flush_basic_block_count_; }
52 size_t write_count() const { return output_.size(); }
53 const BytecodeNode& last_written() const { return output_.back(); }
54 const std::vector<BytecodeNode>* output() { return &output_; }
55
56 private:
57 TemporaryRegisterAllocator* register_allocator_;
58 BytecodeRegisterOptimizer* register_optimizer_;
59
60 int flush_for_offset_count_ = 0;
61 int flush_basic_block_count_ = 0;
62 std::vector<BytecodeNode> output_;
63 };
64
65 // Sanity tests.
66
67 TEST_F(BytecodeRegisterOptimizerTest, FlushForOffsetPassThrough) {
68 Initialize(1, 1);
69 CHECK_EQ(flush_for_offset_count(), 0);
70 CHECK_EQ(optimizer()->FlushForOffset(), 0);
71 CHECK_EQ(flush_for_offset_count(), 1);
72 }
73
74 TEST_F(BytecodeRegisterOptimizerTest, FlushForOffsetRightSize) {
75 Initialize(1, 1);
76 BytecodeNode node(Bytecode::kAdd, Register(0).ToOperand(),
77 OperandScale::kQuadruple);
78 optimizer()->Write(&node);
79 CHECK_EQ(optimizer()->FlushForOffset(), 0);
80 CHECK_EQ(flush_for_offset_count(), 1);
81 CHECK_EQ(write_count(), 1);
82 }
83
84 TEST_F(BytecodeRegisterOptimizerTest, FlushForOffsetNop) {
85 Initialize(1, 1);
86 BytecodeNode node(Bytecode::kNop);
87 optimizer()->Write(&node);
88 CHECK_EQ(optimizer()->FlushForOffset(), 0);
89 CHECK_EQ(flush_for_offset_count(), 1);
90 CHECK_EQ(write_count(), 1);
91 }
92
93 TEST_F(BytecodeRegisterOptimizerTest, FlushForOffsetNopExpression) {
94 Initialize(1, 1);
95 BytecodeNode node(Bytecode::kNop);
96 node.source_info().Update({3, false});
97 optimizer()->Write(&node);
98 CHECK_EQ(optimizer()->FlushForOffset(), 0);
99 CHECK_EQ(flush_for_offset_count(), 1);
100 CHECK_EQ(write_count(), 1);
101 }
102
103 TEST_F(BytecodeRegisterOptimizerTest, FlushForOffsetNopStatement) {
104 Initialize(1, 1);
105 BytecodeNode node(Bytecode::kNop);
106 node.source_info().Update({3, true});
107 optimizer()->Write(&node);
108 CHECK_EQ(optimizer()->FlushForOffset(), 0);
109 CHECK_EQ(flush_for_offset_count(), 1);
110 CHECK_EQ(write_count(), 1);
111 }
112
113 TEST_F(BytecodeRegisterOptimizerTest, FlushBasicBlockPassThrough) {
114 Initialize(1, 1);
115 CHECK_EQ(flush_basic_block_count(), 0);
116 optimizer()->FlushBasicBlock();
117 CHECK_EQ(flush_basic_block_count(), 1);
118 CHECK_EQ(write_count(), 0);
119 }
120
121 TEST_F(BytecodeRegisterOptimizerTest, WriteOneFlushBasicBlock) {
122 Initialize(1, 1);
123 BytecodeNode node(Bytecode::kAdd, Register(0).ToOperand(),
124 OperandScale::kQuadruple);
125 optimizer()->Write(&node);
126 CHECK_EQ(write_count(), 1);
127 optimizer()->FlushBasicBlock();
128 CHECK_EQ(write_count(), 1);
129 CHECK_EQ(node, last_written());
130 }
131
132 // Basic Register Optimizations
133
134 TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) {
135 Initialize(3, 1);
136 Register parameter = Register::FromParameterIndex(1, 3);
137 BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand(),
138 OperandScale::kSingle);
139 optimizer()->Write(&node0);
140 CHECK_EQ(write_count(), 0);
141 Register temp = NewTemporary();
142 BytecodeNode node1(Bytecode::kStar, NewTemporary().ToOperand(),
143 OperandScale::kSingle);
144 optimizer()->Write(&node1);
145 CHECK_EQ(write_count(), 0);
146 KillTemporary(temp);
147 CHECK_EQ(write_count(), 0);
148 BytecodeNode node2(Bytecode::kReturn);
149 optimizer()->Write(&node2);
150 CHECK_EQ(write_count(), 2);
151 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdar);
152 CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand());
153 CHECK_EQ(output()->at(0).operand_scale(), OperandScale::kSingle);
154 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kReturn);
155 }
156
157 TEST_F(BytecodeRegisterOptimizerTest, StoresToLocalsImmediate) {
158 Initialize(3, 1);
159 Register parameter = Register::FromParameterIndex(1, 3);
160 BytecodeNode node0(Bytecode::kLdar, parameter.ToOperand(),
161 OperandScale::kSingle);
162 optimizer()->Write(&node0);
163 CHECK_EQ(write_count(), 0);
164 Register local = Register(0);
165 BytecodeNode node1(Bytecode::kStar, local.ToOperand(), OperandScale::kSingle);
166 optimizer()->Write(&node1);
167 CHECK_EQ(write_count(), 1);
168 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kMov);
169 CHECK_EQ(output()->at(0).operand(0), parameter.ToOperand());
170 CHECK_EQ(output()->at(0).operand(1), local.ToOperand());
171 CHECK_EQ(output()->at(0).operand_scale(), OperandScale::kSingle);
172
173 BytecodeNode node2(Bytecode::kReturn);
174 optimizer()->Write(&node2);
175 CHECK_EQ(write_count(), 3);
176 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kLdar);
177 CHECK_EQ(output()->at(1).operand(0), local.ToOperand());
178 CHECK_EQ(output()->at(1).operand_scale(), OperandScale::kSingle);
179 CHECK_EQ(output()->at(2).bytecode(), Bytecode::kReturn);
180 }
181
182 TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotMaterializedForInput) {
183 Initialize(3, 1);
184 Register parameter = Register::FromParameterIndex(1, 3);
185 Register temp0 = NewTemporary();
186 Register temp1 = NewTemporary();
187 BytecodeNode node0(Bytecode::kMov, parameter.ToOperand(), temp0.ToOperand(),
188 OperandScale::kSingle);
189 optimizer()->Write(&node0);
190 BytecodeNode node1(Bytecode::kMov, parameter.ToOperand(), temp1.ToOperand(),
191 OperandScale::kSingle);
192 optimizer()->Write(&node1);
193 CHECK_EQ(write_count(), 0);
194 BytecodeNode node2(Bytecode::kCallJSRuntime, 0, temp0.ToOperand(), 1,
195 OperandScale::kSingle);
196 optimizer()->Write(&node2);
197 CHECK_EQ(write_count(), 1);
198 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kCallJSRuntime);
199 CHECK_EQ(output()->at(0).operand(0), 0);
200 CHECK_EQ(output()->at(0).operand(1), parameter.ToOperand());
201 CHECK_EQ(output()->at(0).operand(2), 1);
202 CHECK_EQ(output()->at(0).operand_scale(), OperandScale::kSingle);
203 }
204
205 TEST_F(BytecodeRegisterOptimizerTest, RangeOfTemporariesMaterializedForInput) {
206 Initialize(3, 1);
207 Register parameter = Register::FromParameterIndex(1, 3);
208 Register temp0 = NewTemporary();
209 Register temp1 = NewTemporary();
210 BytecodeNode node0(Bytecode::kLdaSmi, 3, OperandScale::kSingle);
211 optimizer()->Write(&node0);
212 CHECK_EQ(write_count(), 1);
213 BytecodeNode node1(Bytecode::kStar, temp0.ToOperand(), OperandScale::kSingle);
214 optimizer()->Write(&node1);
215 BytecodeNode node2(Bytecode::kMov, parameter.ToOperand(), temp1.ToOperand(),
216 OperandScale::kSingle);
217 optimizer()->Write(&node2);
218 CHECK_EQ(write_count(), 1);
219 BytecodeNode node3(Bytecode::kCallJSRuntime, 0, temp0.ToOperand(), 2,
220 OperandScale::kSingle);
221 optimizer()->Write(&node3);
222 CHECK_EQ(write_count(), 4);
223
224 CHECK_EQ(output()->at(0).bytecode(), Bytecode::kLdaSmi);
225 CHECK_EQ(output()->at(0).operand(0), 3);
226 CHECK_EQ(output()->at(0).operand_scale(), OperandScale::kSingle);
227
228 CHECK_EQ(output()->at(1).bytecode(), Bytecode::kStar);
229 CHECK_EQ(output()->at(1).operand(0), temp0.ToOperand());
230 CHECK_EQ(output()->at(1).operand_scale(), OperandScale::kSingle);
231
232 CHECK_EQ(output()->at(2).bytecode(), Bytecode::kMov);
233 CHECK_EQ(output()->at(2).operand(0), parameter.ToOperand());
234 CHECK_EQ(output()->at(2).operand(1), temp1.ToOperand());
235 CHECK_EQ(output()->at(2).operand_scale(), OperandScale::kSingle);
236
237 CHECK_EQ(output()->at(3).bytecode(), Bytecode::kCallJSRuntime);
238 CHECK_EQ(output()->at(3).operand(0), 0);
239 CHECK_EQ(output()->at(3).operand(1), temp0.ToOperand());
240 CHECK_EQ(output()->at(3).operand(2), 2);
241 CHECK_EQ(output()->at(3).operand_scale(), OperandScale::kSingle);
242 }
243
244 } // namespace interpreter
245 } // namespace internal
246 } // namespace v8
OLDNEW
« no previous file with comments | « test/unittests/interpreter/bytecode-array-iterator-unittest.cc ('k') | test/unittests/interpreter/bytecodes-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698