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

Side by Side Diff: test/unittests/compiler/liveness-analyzer-unittest.cc

Issue 949743002: [turbofan] Variable liveness analysis for deopt (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Test tweaks Created 5 years, 10 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 2014 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/compiler/js-graph.h"
6 #include "src/compiler/linkage.h"
7 #include "src/compiler/liveness-analyzer.h"
8 #include "src/compiler/node-matchers.h"
9 #include "test/unittests/compiler/graph-unittest.h"
10 #include "test/unittests/compiler/node-test-utils.h"
11
12 using testing::MakeMatcher;
13 using testing::MatcherInterface;
14 using testing::MatchResultListener;
15 using testing::StringMatchResultListener;
16
17 namespace v8 {
18 namespace internal {
19 namespace compiler {
20
21 class LivenessAnalysisTest : public GraphTest {
22 public:
23 explicit LivenessAnalysisTest(int locals_count = 4)
24 : locals_count_(locals_count),
25 machine_(zone(), kRepWord32),
26 javascript_(zone()),
27 jsgraph_(isolate(), graph(), common(), &javascript_, &machine_),
28 analyzer_(locals_count, zone()),
29 empty_values_(graph()->NewNode(common()->StateValues(0), 0, nullptr)),
30 next_checkpoint_id_(0),
31 current_block_(nullptr) {}
32
33
34 protected:
35 JSGraph* jsgraph() { return &jsgraph_; }
36
37 LivenessAnalyzer* analyzer() { return &analyzer_; }
38 void Run() {
39 FrameStateRelaxer relaxer(&jsgraph_, jsgraph_.UndefinedConstant(),
40 analyzer()->local_count(), zone());
41 analyzer()->Run(&relaxer);
42 }
43
44 Node* Checkpoint() {
45 int ast_num = next_checkpoint_id_++;
46 int first_const = intconst_from_bailout_id(ast_num, locals_count_);
47
48 const Operator* locals_op = common()->StateValues(locals_count_);
49
50 ZoneVector<Node*> local_inputs(locals_count_, nullptr, zone());
51 for (int i = 0; i < locals_count_; i++) {
52 local_inputs[i] = jsgraph()->Int32Constant(i + first_const);
53 }
54 Node* locals =
55 graph()->NewNode(locals_op, locals_count_, &local_inputs.front());
56
57 const Operator* op = common()->FrameState(
58 JS_FRAME, BailoutId(ast_num), OutputFrameStateCombine::Ignore());
59 Node* result = graph()->NewNode(op, empty_values_, locals, empty_values_,
60 jsgraph()->UndefinedConstant(),
61 jsgraph()->UndefinedConstant());
62
63 current_block_->Checkpoint(result);
64 return result;
65 }
66
67 void Bind(int var) { current_block()->Bind(var); }
68 void Lookup(int var) { current_block()->Lookup(var); }
69
70 class CheckpointMatcher : public MatcherInterface<Node*> {
71 public:
72 explicit CheckpointMatcher(const char* liveness, Node* empty_values,
73 int locals_count, Node* replacement)
74 : liveness_(liveness),
75 empty_values_(empty_values),
76 locals_count_(locals_count),
77 replacement_(replacement) {}
78
79 void DescribeTo(std::ostream* os) const OVERRIDE {
80 *os << "is a frame state with '" << liveness_
81 << "' liveness, empty "
82 "parameters and empty expression stack";
83 }
84
85 bool MatchAndExplain(Node* frame_state,
86 MatchResultListener* listener) const OVERRIDE {
87 if (frame_state == NULL) {
88 *listener << "which is NULL";
89 return false;
90 }
91 DCHECK(frame_state->opcode() == IrOpcode::kFrameState);
92
93 FrameStateCallInfo state_info =
94 OpParameter<FrameStateCallInfo>(frame_state);
95 int ast_num = state_info.bailout_id().ToInt();
96 int first_const = intconst_from_bailout_id(ast_num, locals_count_);
97
98 if (empty_values_ != frame_state->InputAt(0)) {
99 *listener << "whose parameters are " << frame_state->InputAt(0)
100 << " but should have been " << empty_values_ << " (empty)";
101 return false;
102 }
103 if (empty_values_ != frame_state->InputAt(2)) {
104 *listener << "whose expression stack is " << frame_state->InputAt(2)
105 << " but should have been " << empty_values_ << " (empty)";
106 return false;
107 }
108 Node* locals = frame_state->InputAt(1);
109 DCHECK(locals->opcode() == IrOpcode::kStateValues);
110 if (locals_count_ != locals->InputCount()) {
111 *listener << "whose number of locals is " << locals->InputCount()
112 << " but should have been " << locals_count_;
113 return false;
114 }
115 for (int i = 0; i < locals_count_; i++) {
116 Node* value = locals->InputAt(i);
117 if (liveness_[i] == 'L') {
118 StringMatchResultListener value_listener;
119 if (value == replacement_) {
120 *listener << "whose local #" << i << " was " << value->opcode()
121 << " but should have been 'undefined'";
122 return false;
123 } else if (!IsInt32Constant(first_const + i)
124 .MatchAndExplain(value, &value_listener)) {
125 *listener << "whose local #" << i << " does not match";
126 if (value_listener.str() != "") {
127 *listener << ", " << value_listener.str();
128 }
129 return false;
130 }
131 } else if (liveness_[i] == '.') {
132 if (value != replacement_) {
133 *listener << "whose local #" << i << " is " << value
134 << " but should have been " << replacement_
135 << " (undefined)";
136 return false;
137 }
138 } else {
139 UNREACHABLE();
140 }
141 }
142 return true;
143 }
144
145 private:
146 const char* liveness_;
147 Node* empty_values_;
148 int locals_count_;
149 Node* replacement_;
150 };
151
152 Matcher<Node*> IsCheckpointModuloLiveness(const char* liveness) {
153 return MakeMatcher(new CheckpointMatcher(liveness, empty_values_,
154 locals_count_,
155 jsgraph()->UndefinedConstant()));
156 }
157
158 LivenessAnalyzerBlock* current_block() { return current_block_; }
159 void set_current_block(LivenessAnalyzerBlock* block) {
160 current_block_ = block;
161 }
162
163 private:
164 static int intconst_from_bailout_id(int ast_num, int locals_count) {
165 return (locals_count + 1) * ast_num + 1;
166 }
167
168 int locals_count_;
169 MachineOperatorBuilder machine_;
170 JSOperatorBuilder javascript_;
171 JSGraph jsgraph_;
172 LivenessAnalyzer analyzer_;
173 Node* empty_values_;
174 int next_checkpoint_id_;
175 LivenessAnalyzerBlock* current_block_;
176 };
177
178
179 TEST_F(LivenessAnalysisTest, EmptyBlock) {
180 set_current_block(analyzer()->New());
181
182 Node* c1 = Checkpoint();
183
184 Run();
185
186 // Nothing is live.
187 EXPECT_THAT(c1, IsCheckpointModuloLiveness("...."));
188 }
189
190
191 TEST_F(LivenessAnalysisTest, SimpleLookup) {
192 set_current_block(analyzer()->New());
193
194 Node* c1 = Checkpoint();
195 Lookup(1);
196 Node* c2 = Checkpoint();
197
198 Run();
199
200 EXPECT_THAT(c1, IsCheckpointModuloLiveness(".L.."));
201 EXPECT_THAT(c2, IsCheckpointModuloLiveness("...."));
202 }
203
204
205 TEST_F(LivenessAnalysisTest, DiamondLookups) {
206 // Start block.
207 LivenessAnalyzerBlock* start = analyzer()->New();
208 set_current_block(start);
209 Node* c1_start = Checkpoint();
210
211 // First branch.
212 LivenessAnalyzerBlock* b1 = analyzer()->New(start);
213 set_current_block(b1);
214
215 Node* c1_b1 = Checkpoint();
216 Lookup(1);
217 Node* c2_b1 = Checkpoint();
218 Lookup(3);
219 Node* c3_b1 = Checkpoint();
220
221 // Second branch.
222 LivenessAnalyzerBlock* b2 = analyzer()->New(start);
223 set_current_block(b2);
224
225 Node* c1_b2 = Checkpoint();
226 Lookup(3);
227 Node* c2_b2 = Checkpoint();
228 Lookup(2);
229 Node* c3_b2 = Checkpoint();
230
231 // Merge block.
232 LivenessAnalyzerBlock* m = analyzer()->New(b1);
233 m->AddPredecessor(b2);
234 set_current_block(m);
235 Node* c1_m = Checkpoint();
236 Lookup(0);
237 Node* c2_m = Checkpoint();
238
239 Run();
240
241 EXPECT_THAT(c1_start, IsCheckpointModuloLiveness("LLLL"));
242
243 EXPECT_THAT(c1_b1, IsCheckpointModuloLiveness("LL.L"));
244 EXPECT_THAT(c2_b1, IsCheckpointModuloLiveness("L..L"));
245 EXPECT_THAT(c3_b1, IsCheckpointModuloLiveness("L..."));
246
247 EXPECT_THAT(c1_b2, IsCheckpointModuloLiveness("L.LL"));
248 EXPECT_THAT(c2_b2, IsCheckpointModuloLiveness("L.L."));
249 EXPECT_THAT(c3_b2, IsCheckpointModuloLiveness("L..."));
250
251 EXPECT_THAT(c1_m, IsCheckpointModuloLiveness("L..."));
252 EXPECT_THAT(c2_m, IsCheckpointModuloLiveness("...."));
253 }
254
255
256 TEST_F(LivenessAnalysisTest, DiamondLookupsAndBinds) {
257 // Start block.
258 LivenessAnalyzerBlock* start = analyzer()->New();
259 set_current_block(start);
260 Node* c1_start = Checkpoint();
261 Bind(0);
262 Node* c2_start = Checkpoint();
263
264 // First branch.
265 LivenessAnalyzerBlock* b1 = analyzer()->New(start);
266 set_current_block(b1);
267
268 Node* c1_b1 = Checkpoint();
269 Bind(2);
270 Bind(1);
271 Node* c2_b1 = Checkpoint();
272 Bind(3);
273 Node* c3_b1 = Checkpoint();
274
275 // Second branch.
276 LivenessAnalyzerBlock* b2 = analyzer()->New(start);
277 set_current_block(b2);
278
279 Node* c1_b2 = Checkpoint();
280 Lookup(2);
281 Node* c2_b2 = Checkpoint();
282 Bind(2);
283 Bind(3);
284 Node* c3_b2 = Checkpoint();
285
286 // Merge block.
287 LivenessAnalyzerBlock* m = analyzer()->New(b1);
288 m->AddPredecessor(b2);
289 set_current_block(m);
290 Node* c1_m = Checkpoint();
291 Lookup(0);
292 Lookup(1);
293 Lookup(2);
294 Lookup(3);
295 Node* c2_m = Checkpoint();
296
297 Run();
298
299 EXPECT_THAT(c1_start, IsCheckpointModuloLiveness(".LL."));
300 EXPECT_THAT(c2_start, IsCheckpointModuloLiveness("LLL."));
301
302 EXPECT_THAT(c1_b1, IsCheckpointModuloLiveness("L..."));
303 EXPECT_THAT(c2_b1, IsCheckpointModuloLiveness("LLL."));
304 EXPECT_THAT(c3_b1, IsCheckpointModuloLiveness("LLLL"));
305
306 EXPECT_THAT(c1_b2, IsCheckpointModuloLiveness("LLL."));
307 EXPECT_THAT(c2_b2, IsCheckpointModuloLiveness("LL.."));
308 EXPECT_THAT(c3_b2, IsCheckpointModuloLiveness("LLLL"));
309
310 EXPECT_THAT(c1_m, IsCheckpointModuloLiveness("LLLL"));
311 EXPECT_THAT(c2_m, IsCheckpointModuloLiveness("...."));
312 }
313
314
315 TEST_F(LivenessAnalysisTest, SimpleLoop) {
316 // Start block.
317 LivenessAnalyzerBlock* start = analyzer()->New();
318 set_current_block(start);
319 Node* c1_start = Checkpoint();
320 Bind(0);
321 Bind(1);
322 Bind(2);
323 Bind(3);
324 Node* c2_start = Checkpoint();
325
326 // Loop header block.
327 LivenessAnalyzerBlock* header = analyzer()->New(start);
328 set_current_block(header);
329 Node* c1_header = Checkpoint();
330 Lookup(0);
331 Bind(2);
332 Node* c2_header = Checkpoint();
333
334 // Inside-loop block.
335 LivenessAnalyzerBlock* in_loop = analyzer()->New(header);
336 set_current_block(in_loop);
337 Node* c1_in_loop = Checkpoint();
338 Bind(0);
339 Lookup(3);
340 Node* c2_in_loop = Checkpoint();
341
342 // Add back edge.
343 header->AddPredecessor(in_loop);
344
345 // After-loop block.
346 LivenessAnalyzerBlock* end = analyzer()->New(header);
347 set_current_block(end);
348 Node* c1_end = Checkpoint();
349 Lookup(1);
350 Lookup(2);
351 Node* c2_end = Checkpoint();
352
353 Run();
354
355 EXPECT_THAT(c1_start, IsCheckpointModuloLiveness("...."));
356 EXPECT_THAT(c2_start, IsCheckpointModuloLiveness("LL.L"));
357
358 EXPECT_THAT(c1_header, IsCheckpointModuloLiveness("LL.L"));
359 EXPECT_THAT(c2_header, IsCheckpointModuloLiveness(".LLL"));
360
361 EXPECT_THAT(c1_in_loop, IsCheckpointModuloLiveness(".L.L"));
362 EXPECT_THAT(c2_in_loop, IsCheckpointModuloLiveness("LL.L"));
363
364 EXPECT_THAT(c1_end, IsCheckpointModuloLiveness(".LL."));
365 EXPECT_THAT(c2_end, IsCheckpointModuloLiveness("...."));
366 }
367
368 } // namespace compiler
369 } // namespace internal
370 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698