blob: 8d05c526c3a0b1498442aa41e2ce98393cd788ca [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/compiler/common-operator.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006#include "src/compiler/graph.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007#include "src/compiler/node.h"
8#include "src/compiler/node-properties.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/compiler/operator.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "test/unittests/compiler/graph-reducer-unittest.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011#include "test/unittests/test-utils.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012
13using testing::_;
14using testing::DefaultValue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015using testing::ElementsAre;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016using testing::Return;
17using testing::Sequence;
18using testing::StrictMock;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019using testing::UnorderedElementsAre;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020
21namespace v8 {
22namespace internal {
23namespace compiler {
24
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000025namespace {
26
Emily Bernierd0a1eb72015-03-24 16:35:39 -040027struct TestOperator : public Operator {
28 TestOperator(Operator::Opcode opcode, Operator::Properties properties,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000029 const char* op_name, size_t value_in, size_t value_out)
30 : Operator(opcode, properties, op_name, value_in, 0, 0, value_out, 0, 0) {
31 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040032};
33
34
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035const uint8_t kOpcodeA0 = 10;
36const uint8_t kOpcodeA1 = 11;
37const uint8_t kOpcodeA2 = 12;
38const uint8_t kOpcodeB0 = 20;
39const uint8_t kOpcodeB1 = 21;
40const uint8_t kOpcodeB2 = 22;
41const uint8_t kOpcodeC0 = 30;
42const uint8_t kOpcodeC1 = 31;
43const uint8_t kOpcodeC2 = 32;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000044
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000045static TestOperator kOpA0(kOpcodeA0, Operator::kNoWrite, "opa1", 0, 1);
46static TestOperator kOpA1(kOpcodeA1, Operator::kNoProperties, "opa2", 1, 1);
47static TestOperator kOpA2(kOpcodeA2, Operator::kNoProperties, "opa3", 2, 1);
48static TestOperator kOpB0(kOpcodeB0, Operator::kNoWrite, "opa0", 0, 0);
49static TestOperator kOpB1(kOpcodeB1, Operator::kNoWrite, "opa1", 1, 0);
50static TestOperator kOpB2(kOpcodeB2, Operator::kNoWrite, "opa2", 2, 0);
51static TestOperator kOpC0(kOpcodeC0, Operator::kNoWrite, "opc0", 0, 0);
52static TestOperator kOpC1(kOpcodeC1, Operator::kNoWrite, "opc1", 1, 0);
53static TestOperator kOpC2(kOpcodeC2, Operator::kNoWrite, "opc2", 2, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054
55struct MockReducer : public Reducer {
56 MOCK_METHOD1(Reduce, Reduction(Node*));
57};
58
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059
60// Replaces all "A" operators with "B" operators without creating new nodes.
61class InPlaceABReducer final : public Reducer {
62 public:
63 Reduction Reduce(Node* node) final {
64 switch (node->op()->opcode()) {
65 case kOpcodeA0:
66 EXPECT_EQ(0, node->InputCount());
67 NodeProperties::ChangeOp(node, &kOpB0);
68 return Replace(node);
69 case kOpcodeA1:
70 EXPECT_EQ(1, node->InputCount());
71 NodeProperties::ChangeOp(node, &kOpB1);
72 return Replace(node);
73 case kOpcodeA2:
74 EXPECT_EQ(2, node->InputCount());
75 NodeProperties::ChangeOp(node, &kOpB2);
76 return Replace(node);
77 }
78 return NoChange();
79 }
80};
81
82
83// Replaces all "A" operators with "B" operators by allocating new nodes.
84class NewABReducer final : public Reducer {
85 public:
86 explicit NewABReducer(Graph* graph) : graph_(graph) {}
87
88 Reduction Reduce(Node* node) final {
89 switch (node->op()->opcode()) {
90 case kOpcodeA0:
91 EXPECT_EQ(0, node->InputCount());
92 return Replace(graph_->NewNode(&kOpB0));
93 case kOpcodeA1:
94 EXPECT_EQ(1, node->InputCount());
95 return Replace(graph_->NewNode(&kOpB1, node->InputAt(0)));
96 case kOpcodeA2:
97 EXPECT_EQ(2, node->InputCount());
98 return Replace(
99 graph_->NewNode(&kOpB2, node->InputAt(0), node->InputAt(1)));
100 }
101 return NoChange();
102 }
103
104 private:
105 Graph* const graph_;
106};
107
108
109// Wraps all "kOpA0" nodes in "kOpB1" operators by allocating new nodes.
110class A0Wrapper final : public Reducer {
111 public:
112 explicit A0Wrapper(Graph* graph) : graph_(graph) {}
113
114 Reduction Reduce(Node* node) final {
115 switch (node->op()->opcode()) {
116 case kOpcodeA0:
117 EXPECT_EQ(0, node->InputCount());
118 return Replace(graph_->NewNode(&kOpB1, node));
119 }
120 return NoChange();
121 }
122
123 private:
124 Graph* const graph_;
125};
126
127
128// Wraps all "kOpB0" nodes in two "kOpC1" operators by allocating new nodes.
129class B0Wrapper final : public Reducer {
130 public:
131 explicit B0Wrapper(Graph* graph) : graph_(graph) {}
132
133 Reduction Reduce(Node* node) final {
134 switch (node->op()->opcode()) {
135 case kOpcodeB0:
136 EXPECT_EQ(0, node->InputCount());
137 return Replace(graph_->NewNode(&kOpC1, graph_->NewNode(&kOpC1, node)));
138 }
139 return NoChange();
140 }
141
142 private:
143 Graph* const graph_;
144};
145
146
147// Replaces all "kOpA1" nodes with the first input.
148class A1Forwarder final : public Reducer {
149 public:
150 Reduction Reduce(Node* node) final {
151 switch (node->op()->opcode()) {
152 case kOpcodeA1:
153 EXPECT_EQ(1, node->InputCount());
154 return Replace(node->InputAt(0));
155 }
156 return NoChange();
157 }
158};
159
160
161// Replaces all "kOpB1" nodes with the first input.
162class B1Forwarder final : public Reducer {
163 public:
164 Reduction Reduce(Node* node) final {
165 switch (node->op()->opcode()) {
166 case kOpcodeB1:
167 EXPECT_EQ(1, node->InputCount());
168 return Replace(node->InputAt(0));
169 }
170 return NoChange();
171 }
172};
173
174
175// Replaces all "B" operators with "C" operators without creating new nodes.
176class InPlaceBCReducer final : public Reducer {
177 public:
178 Reduction Reduce(Node* node) final {
179 switch (node->op()->opcode()) {
180 case kOpcodeB0:
181 EXPECT_EQ(0, node->InputCount());
182 NodeProperties::ChangeOp(node, &kOpC0);
183 return Replace(node);
184 case kOpcodeB1:
185 EXPECT_EQ(1, node->InputCount());
186 NodeProperties::ChangeOp(node, &kOpC1);
187 return Replace(node);
188 case kOpcodeB2:
189 EXPECT_EQ(2, node->InputCount());
190 NodeProperties::ChangeOp(node, &kOpC2);
191 return Replace(node);
192 }
193 return NoChange();
194 }
195};
196
197
198// Swaps the inputs to "kOp2A" and "kOp2B" nodes based on ids.
199class AB2Sorter final : public Reducer {
200 public:
201 Reduction Reduce(Node* node) final {
202 switch (node->op()->opcode()) {
203 case kOpcodeA2:
204 case kOpcodeB2:
205 EXPECT_EQ(2, node->InputCount());
206 Node* x = node->InputAt(0);
207 Node* y = node->InputAt(1);
208 if (x->id() > y->id()) {
209 node->ReplaceInput(0, y);
210 node->ReplaceInput(1, x);
211 return Replace(node);
212 }
213 }
214 return NoChange();
215 }
216};
217
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000218} // namespace
219
220
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221class AdvancedReducerTest : public TestWithZone {
222 public:
223 AdvancedReducerTest() : graph_(zone()) {}
224
225 protected:
226 Graph* graph() { return &graph_; }
227
228 private:
229 Graph graph_;
230};
231
232
233TEST_F(AdvancedReducerTest, Replace) {
234 struct DummyReducer final : public AdvancedReducer {
235 explicit DummyReducer(Editor* editor) : AdvancedReducer(editor) {}
236 Reduction Reduce(Node* node) final {
237 Replace(node, node);
238 return NoChange();
239 }
240 };
241 StrictMock<MockAdvancedReducerEditor> e;
242 DummyReducer r(&e);
243 Node* node0 = graph()->NewNode(&kOpA0);
244 Node* node1 = graph()->NewNode(&kOpA1, node0);
245 EXPECT_CALL(e, Replace(node0, node0));
246 EXPECT_CALL(e, Replace(node1, node1));
247 EXPECT_FALSE(r.Reduce(node0).Changed());
248 EXPECT_FALSE(r.Reduce(node1).Changed());
249}
250
251
252TEST_F(AdvancedReducerTest, Revisit) {
253 struct DummyReducer final : public AdvancedReducer {
254 explicit DummyReducer(Editor* editor) : AdvancedReducer(editor) {}
255 Reduction Reduce(Node* node) final {
256 Revisit(node);
257 return NoChange();
258 }
259 };
260 StrictMock<MockAdvancedReducerEditor> e;
261 DummyReducer r(&e);
262 Node* node0 = graph()->NewNode(&kOpA0);
263 Node* node1 = graph()->NewNode(&kOpA1, node0);
264 EXPECT_CALL(e, Revisit(node0));
265 EXPECT_CALL(e, Revisit(node1));
266 EXPECT_FALSE(r.Reduce(node0).Changed());
267 EXPECT_FALSE(r.Reduce(node1).Changed());
268}
269
270
271namespace {
272
273struct ReplaceWithValueReducer final : public AdvancedReducer {
274 explicit ReplaceWithValueReducer(Editor* editor) : AdvancedReducer(editor) {}
275 Reduction Reduce(Node* node) final { return NoChange(); }
276 using AdvancedReducer::ReplaceWithValue;
277};
278
279const Operator kMockOperator(IrOpcode::kDead, Operator::kNoProperties,
280 "MockOperator", 0, 0, 0, 1, 0, 0);
281const Operator kMockOpEffect(IrOpcode::kDead, Operator::kNoProperties,
282 "MockOpEffect", 0, 1, 0, 1, 1, 0);
283const Operator kMockOpControl(IrOpcode::kDead, Operator::kNoProperties,
284 "MockOpControl", 0, 0, 1, 1, 0, 1);
285
286const IfExceptionHint kNoHint = IfExceptionHint::kLocallyCaught;
287
288} // namespace
289
290
291TEST_F(AdvancedReducerTest, ReplaceWithValue_ValueUse) {
292 CommonOperatorBuilder common(zone());
293 Node* node = graph()->NewNode(&kMockOperator);
294 Node* start = graph()->NewNode(common.Start(1));
295 Node* use_value = graph()->NewNode(common.Return(), node, start, start);
296 Node* replacement = graph()->NewNode(&kMockOperator);
297 GraphReducer graph_reducer(zone(), graph(), nullptr);
298 ReplaceWithValueReducer r(&graph_reducer);
299 r.ReplaceWithValue(node, replacement);
300 EXPECT_EQ(replacement, use_value->InputAt(0));
301 EXPECT_EQ(0, node->UseCount());
302 EXPECT_EQ(1, replacement->UseCount());
303 EXPECT_THAT(replacement->uses(), ElementsAre(use_value));
304}
305
306
307TEST_F(AdvancedReducerTest, ReplaceWithValue_EffectUse) {
308 CommonOperatorBuilder common(zone());
309 Node* start = graph()->NewNode(common.Start(1));
310 Node* node = graph()->NewNode(&kMockOpEffect, start);
311 Node* use_control = graph()->NewNode(common.Merge(1), start);
312 Node* use_effect = graph()->NewNode(common.EffectPhi(1), node, use_control);
313 Node* replacement = graph()->NewNode(&kMockOperator);
314 GraphReducer graph_reducer(zone(), graph(), nullptr);
315 ReplaceWithValueReducer r(&graph_reducer);
316 r.ReplaceWithValue(node, replacement);
317 EXPECT_EQ(start, use_effect->InputAt(0));
318 EXPECT_EQ(0, node->UseCount());
319 EXPECT_EQ(3, start->UseCount());
320 EXPECT_EQ(0, replacement->UseCount());
321 EXPECT_THAT(start->uses(),
322 UnorderedElementsAre(use_effect, use_control, node));
323}
324
325
326TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse1) {
327 CommonOperatorBuilder common(zone());
328 Node* start = graph()->NewNode(common.Start(1));
329 Node* node = graph()->NewNode(&kMockOpControl, start);
330 Node* success = graph()->NewNode(common.IfSuccess(), node);
331 Node* use_control = graph()->NewNode(common.Merge(1), success);
332 Node* replacement = graph()->NewNode(&kMockOperator);
333 GraphReducer graph_reducer(zone(), graph(), nullptr);
334 ReplaceWithValueReducer r(&graph_reducer);
335 r.ReplaceWithValue(node, replacement);
336 EXPECT_EQ(start, use_control->InputAt(0));
337 EXPECT_EQ(0, node->UseCount());
338 EXPECT_EQ(2, start->UseCount());
339 EXPECT_EQ(0, replacement->UseCount());
340 EXPECT_THAT(start->uses(), UnorderedElementsAre(use_control, node));
341}
342
343
344TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse2) {
345 CommonOperatorBuilder common(zone());
346 Node* start = graph()->NewNode(common.Start(1));
347 Node* effect = graph()->NewNode(&kMockOperator);
348 Node* dead = graph()->NewNode(&kMockOperator);
349 Node* node = graph()->NewNode(&kMockOpControl, start);
350 Node* success = graph()->NewNode(common.IfSuccess(), node);
351 Node* exception = graph()->NewNode(common.IfException(kNoHint), effect, node);
352 Node* use_control = graph()->NewNode(common.Merge(1), success);
353 Node* replacement = graph()->NewNode(&kMockOperator);
354 GraphReducer graph_reducer(zone(), graph(), dead);
355 ReplaceWithValueReducer r(&graph_reducer);
356 r.ReplaceWithValue(node, replacement);
357 EXPECT_EQ(start, use_control->InputAt(0));
358 EXPECT_EQ(dead, exception->InputAt(1));
359 EXPECT_EQ(0, node->UseCount());
360 EXPECT_EQ(2, start->UseCount());
361 EXPECT_EQ(1, dead->UseCount());
362 EXPECT_EQ(0, replacement->UseCount());
363 EXPECT_THAT(start->uses(), UnorderedElementsAre(use_control, node));
364 EXPECT_THAT(dead->uses(), ElementsAre(exception));
365}
366
367
368TEST_F(AdvancedReducerTest, ReplaceWithValue_ControlUse3) {
369 CommonOperatorBuilder common(zone());
370 Node* start = graph()->NewNode(common.Start(1));
371 Node* effect = graph()->NewNode(&kMockOperator);
372 Node* dead = graph()->NewNode(&kMockOperator);
373 Node* node = graph()->NewNode(&kMockOpControl, start);
374 Node* success = graph()->NewNode(common.IfSuccess(), node);
375 Node* exception = graph()->NewNode(common.IfException(kNoHint), effect, node);
376 Node* use_control = graph()->NewNode(common.Merge(1), success);
377 Node* replacement = graph()->NewNode(&kMockOperator);
378 GraphReducer graph_reducer(zone(), graph(), dead);
379 ReplaceWithValueReducer r(&graph_reducer);
380 r.ReplaceWithValue(node, replacement);
381 EXPECT_EQ(start, use_control->InputAt(0));
382 EXPECT_EQ(dead, exception->InputAt(1));
383 EXPECT_EQ(0, node->UseCount());
384 EXPECT_EQ(2, start->UseCount());
385 EXPECT_EQ(1, dead->UseCount());
386 EXPECT_EQ(0, replacement->UseCount());
387 EXPECT_THAT(start->uses(), UnorderedElementsAre(use_control, node));
388 EXPECT_THAT(dead->uses(), ElementsAre(exception));
389}
390
391
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000392class GraphReducerTest : public TestWithZone {
393 public:
394 GraphReducerTest() : graph_(zone()) {}
395
396 static void SetUpTestCase() {
397 TestWithZone::SetUpTestCase();
398 DefaultValue<Reduction>::Set(Reducer::NoChange());
399 }
400
401 static void TearDownTestCase() {
402 DefaultValue<Reduction>::Clear();
403 TestWithZone::TearDownTestCase();
404 }
405
406 protected:
407 void ReduceNode(Node* node, Reducer* r) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000408 GraphReducer reducer(zone(), graph());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000409 reducer.AddReducer(r);
410 reducer.ReduceNode(node);
411 }
412
413 void ReduceNode(Node* node, Reducer* r1, Reducer* r2) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000414 GraphReducer reducer(zone(), graph());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000415 reducer.AddReducer(r1);
416 reducer.AddReducer(r2);
417 reducer.ReduceNode(node);
418 }
419
420 void ReduceNode(Node* node, Reducer* r1, Reducer* r2, Reducer* r3) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000421 GraphReducer reducer(zone(), graph());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000422 reducer.AddReducer(r1);
423 reducer.AddReducer(r2);
424 reducer.AddReducer(r3);
425 reducer.ReduceNode(node);
426 }
427
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000428 void ReduceGraph(Reducer* r1) {
429 GraphReducer reducer(zone(), graph());
430 reducer.AddReducer(r1);
431 reducer.ReduceGraph();
432 }
433
434 void ReduceGraph(Reducer* r1, Reducer* r2) {
435 GraphReducer reducer(zone(), graph());
436 reducer.AddReducer(r1);
437 reducer.AddReducer(r2);
438 reducer.ReduceGraph();
439 }
440
441 void ReduceGraph(Reducer* r1, Reducer* r2, Reducer* r3) {
442 GraphReducer reducer(zone(), graph());
443 reducer.AddReducer(r1);
444 reducer.AddReducer(r2);
445 reducer.AddReducer(r3);
446 reducer.ReduceGraph();
447 }
448
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000449 Graph* graph() { return &graph_; }
450
451 private:
452 Graph graph_;
453};
454
455
456TEST_F(GraphReducerTest, NodeIsDeadAfterReplace) {
457 StrictMock<MockReducer> r;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000458 Node* node0 = graph()->NewNode(&kOpA0);
459 Node* node1 = graph()->NewNode(&kOpA1, node0);
460 Node* node2 = graph()->NewNode(&kOpA1, node0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400461 EXPECT_CALL(r, Reduce(node0)).WillOnce(Return(Reducer::NoChange()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000462 EXPECT_CALL(r, Reduce(node1)).WillOnce(Return(Reducer::Replace(node2)));
463 ReduceNode(node1, &r);
464 EXPECT_FALSE(node0->IsDead());
465 EXPECT_TRUE(node1->IsDead());
466 EXPECT_FALSE(node2->IsDead());
467}
468
469
470TEST_F(GraphReducerTest, ReduceOnceForEveryReducer) {
471 StrictMock<MockReducer> r1, r2;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000472 Node* node0 = graph()->NewNode(&kOpA0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000473 EXPECT_CALL(r1, Reduce(node0));
474 EXPECT_CALL(r2, Reduce(node0));
475 ReduceNode(node0, &r1, &r2);
476}
477
478
479TEST_F(GraphReducerTest, ReduceAgainAfterChanged) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400480 Sequence s1, s2, s3;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000481 StrictMock<MockReducer> r1, r2, r3;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000482 Node* node0 = graph()->NewNode(&kOpA0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000483 EXPECT_CALL(r1, Reduce(node0));
484 EXPECT_CALL(r2, Reduce(node0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400485 EXPECT_CALL(r3, Reduce(node0)).InSequence(s1, s2, s3).WillOnce(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000486 Return(Reducer::Changed(node0)));
487 EXPECT_CALL(r1, Reduce(node0)).InSequence(s1);
488 EXPECT_CALL(r2, Reduce(node0)).InSequence(s2);
489 ReduceNode(node0, &r1, &r2, &r3);
490}
491
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492
493TEST_F(GraphReducerTest, ReduceGraphFromEnd1) {
494 StrictMock<MockReducer> r1;
495 Node* n = graph()->NewNode(&kOpA0);
496 Node* end = graph()->NewNode(&kOpA1, n);
497 graph()->SetEnd(end);
498 Sequence s;
499 EXPECT_CALL(r1, Reduce(n));
500 EXPECT_CALL(r1, Reduce(end));
501 ReduceGraph(&r1);
502}
503
504
505TEST_F(GraphReducerTest, ReduceGraphFromEnd2) {
506 StrictMock<MockReducer> r1;
507 Node* n1 = graph()->NewNode(&kOpA0);
508 Node* n2 = graph()->NewNode(&kOpA1, n1);
509 Node* n3 = graph()->NewNode(&kOpA1, n1);
510 Node* end = graph()->NewNode(&kOpA2, n2, n3);
511 graph()->SetEnd(end);
512 Sequence s1, s2;
513 EXPECT_CALL(r1, Reduce(n1)).InSequence(s1, s2);
514 EXPECT_CALL(r1, Reduce(n2)).InSequence(s1);
515 EXPECT_CALL(r1, Reduce(n3)).InSequence(s2);
516 EXPECT_CALL(r1, Reduce(end)).InSequence(s1, s2);
517 ReduceGraph(&r1);
518}
519
520
521TEST_F(GraphReducerTest, ReduceInPlace1) {
522 Node* n1 = graph()->NewNode(&kOpA0);
523 Node* end = graph()->NewNode(&kOpA1, n1);
524 graph()->SetEnd(end);
525
526 // Tests A* => B* with in-place updates.
527 InPlaceABReducer r;
528 for (int i = 0; i < 3; i++) {
529 size_t before = graph()->NodeCount();
530 ReduceGraph(&r);
531 EXPECT_EQ(before, graph()->NodeCount());
532 EXPECT_EQ(&kOpB0, n1->op());
533 EXPECT_EQ(&kOpB1, end->op());
534 EXPECT_EQ(n1, end->InputAt(0));
535 }
536}
537
538
539TEST_F(GraphReducerTest, ReduceInPlace2) {
540 Node* n1 = graph()->NewNode(&kOpA0);
541 Node* n2 = graph()->NewNode(&kOpA1, n1);
542 Node* n3 = graph()->NewNode(&kOpA1, n1);
543 Node* end = graph()->NewNode(&kOpA2, n2, n3);
544 graph()->SetEnd(end);
545
546 // Tests A* => B* with in-place updates.
547 InPlaceABReducer r;
548 for (int i = 0; i < 3; i++) {
549 size_t before = graph()->NodeCount();
550 ReduceGraph(&r);
551 EXPECT_EQ(before, graph()->NodeCount());
552 EXPECT_EQ(&kOpB0, n1->op());
553 EXPECT_EQ(&kOpB1, n2->op());
554 EXPECT_EQ(n1, n2->InputAt(0));
555 EXPECT_EQ(&kOpB1, n3->op());
556 EXPECT_EQ(n1, n3->InputAt(0));
557 EXPECT_EQ(&kOpB2, end->op());
558 EXPECT_EQ(n2, end->InputAt(0));
559 EXPECT_EQ(n3, end->InputAt(1));
560 }
561}
562
563
564TEST_F(GraphReducerTest, ReduceNew1) {
565 Node* n1 = graph()->NewNode(&kOpA0);
566 Node* n2 = graph()->NewNode(&kOpA1, n1);
567 Node* n3 = graph()->NewNode(&kOpA1, n1);
568 Node* end = graph()->NewNode(&kOpA2, n2, n3);
569 graph()->SetEnd(end);
570
571 NewABReducer r(graph());
572 // Tests A* => B* while creating new nodes.
573 for (int i = 0; i < 3; i++) {
574 size_t before = graph()->NodeCount();
575 ReduceGraph(&r);
576 if (i == 0) {
577 EXPECT_NE(before, graph()->NodeCount());
578 } else {
579 EXPECT_EQ(before, graph()->NodeCount());
580 }
581 Node* nend = graph()->end();
582 EXPECT_NE(end, nend); // end() should be updated too.
583
584 Node* nn2 = nend->InputAt(0);
585 Node* nn3 = nend->InputAt(1);
586 Node* nn1 = nn2->InputAt(0);
587
588 EXPECT_EQ(nn1, nn3->InputAt(0));
589
590 EXPECT_EQ(&kOpB0, nn1->op());
591 EXPECT_EQ(&kOpB1, nn2->op());
592 EXPECT_EQ(&kOpB1, nn3->op());
593 EXPECT_EQ(&kOpB2, nend->op());
594 }
595}
596
597
598TEST_F(GraphReducerTest, Wrapping1) {
599 Node* end = graph()->NewNode(&kOpA0);
600 graph()->SetEnd(end);
601 EXPECT_EQ(1U, graph()->NodeCount());
602
603 A0Wrapper r(graph());
604
605 ReduceGraph(&r);
606 EXPECT_EQ(2U, graph()->NodeCount());
607
608 Node* nend = graph()->end();
609 EXPECT_NE(end, nend);
610 EXPECT_EQ(&kOpB1, nend->op());
611 EXPECT_EQ(1, nend->InputCount());
612 EXPECT_EQ(end, nend->InputAt(0));
613}
614
615
616TEST_F(GraphReducerTest, Wrapping2) {
617 Node* end = graph()->NewNode(&kOpB0);
618 graph()->SetEnd(end);
619 EXPECT_EQ(1U, graph()->NodeCount());
620
621 B0Wrapper r(graph());
622
623 ReduceGraph(&r);
624 EXPECT_EQ(3U, graph()->NodeCount());
625
626 Node* nend = graph()->end();
627 EXPECT_NE(end, nend);
628 EXPECT_EQ(&kOpC1, nend->op());
629 EXPECT_EQ(1, nend->InputCount());
630
631 Node* n1 = nend->InputAt(0);
632 EXPECT_NE(end, n1);
633 EXPECT_EQ(&kOpC1, n1->op());
634 EXPECT_EQ(1, n1->InputCount());
635 EXPECT_EQ(end, n1->InputAt(0));
636}
637
638
639TEST_F(GraphReducerTest, Forwarding1) {
640 Node* n1 = graph()->NewNode(&kOpA0);
641 Node* end = graph()->NewNode(&kOpA1, n1);
642 graph()->SetEnd(end);
643
644 A1Forwarder r;
645
646 // Tests A1(x) => x
647 for (int i = 0; i < 3; i++) {
648 size_t before = graph()->NodeCount();
649 ReduceGraph(&r);
650 EXPECT_EQ(before, graph()->NodeCount());
651 EXPECT_EQ(&kOpA0, n1->op());
652 EXPECT_EQ(n1, graph()->end());
653 }
654}
655
656
657TEST_F(GraphReducerTest, Forwarding2) {
658 Node* n1 = graph()->NewNode(&kOpA0);
659 Node* n2 = graph()->NewNode(&kOpA1, n1);
660 Node* n3 = graph()->NewNode(&kOpA1, n1);
661 Node* end = graph()->NewNode(&kOpA2, n2, n3);
662 graph()->SetEnd(end);
663
664 A1Forwarder r;
665
666 // Tests reducing A2(A1(x), A1(y)) => A2(x, y).
667 for (int i = 0; i < 3; i++) {
668 size_t before = graph()->NodeCount();
669 ReduceGraph(&r);
670 EXPECT_EQ(before, graph()->NodeCount());
671 EXPECT_EQ(&kOpA0, n1->op());
672 EXPECT_EQ(n1, end->InputAt(0));
673 EXPECT_EQ(n1, end->InputAt(1));
674 EXPECT_EQ(&kOpA2, end->op());
675 EXPECT_EQ(0, n2->UseCount());
676 EXPECT_EQ(0, n3->UseCount());
677 }
678}
679
680
681TEST_F(GraphReducerTest, Forwarding3) {
682 // Tests reducing a chain of A1(A1(A1(A1(x)))) => x.
683 for (int i = 0; i < 8; i++) {
684 Node* n1 = graph()->NewNode(&kOpA0);
685 Node* end = n1;
686 for (int j = 0; j < i; j++) {
687 end = graph()->NewNode(&kOpA1, end);
688 }
689 graph()->SetEnd(end);
690
691 A1Forwarder r;
692
693 for (size_t i = 0; i < 3; i++) {
694 size_t before = graph()->NodeCount();
695 ReduceGraph(&r);
696 EXPECT_EQ(before, graph()->NodeCount());
697 EXPECT_EQ(&kOpA0, n1->op());
698 EXPECT_EQ(n1, graph()->end());
699 }
700 }
701}
702
703
704TEST_F(GraphReducerTest, ReduceForward1) {
705 Node* n1 = graph()->NewNode(&kOpA0);
706 Node* n2 = graph()->NewNode(&kOpA1, n1);
707 Node* n3 = graph()->NewNode(&kOpA1, n1);
708 Node* end = graph()->NewNode(&kOpA2, n2, n3);
709 graph()->SetEnd(end);
710
711 InPlaceABReducer r;
712 B1Forwarder f;
713
714 // Tests first reducing A => B, then B1(x) => x.
715 for (size_t i = 0; i < 3; i++) {
716 size_t before = graph()->NodeCount();
717 ReduceGraph(&r, &f);
718 EXPECT_EQ(before, graph()->NodeCount());
719 EXPECT_EQ(&kOpB0, n1->op());
720 EXPECT_TRUE(n2->IsDead());
721 EXPECT_EQ(n1, end->InputAt(0));
722 EXPECT_TRUE(n3->IsDead());
723 EXPECT_EQ(n1, end->InputAt(0));
724 EXPECT_EQ(&kOpB2, end->op());
725 EXPECT_EQ(0, n2->UseCount());
726 EXPECT_EQ(0, n3->UseCount());
727 }
728}
729
730
731TEST_F(GraphReducerTest, Sorter1) {
732 AB2Sorter r;
733 for (int i = 0; i < 6; i++) {
734 Node* n1 = graph()->NewNode(&kOpA0);
735 Node* n2 = graph()->NewNode(&kOpA1, n1);
736 Node* n3 = graph()->NewNode(&kOpA1, n1);
737 Node* end = NULL; // Initialize to please the compiler.
738
739 if (i == 0) end = graph()->NewNode(&kOpA2, n2, n3);
740 if (i == 1) end = graph()->NewNode(&kOpA2, n3, n2);
741 if (i == 2) end = graph()->NewNode(&kOpA2, n2, n1);
742 if (i == 3) end = graph()->NewNode(&kOpA2, n1, n2);
743 if (i == 4) end = graph()->NewNode(&kOpA2, n3, n1);
744 if (i == 5) end = graph()->NewNode(&kOpA2, n1, n3);
745
746 graph()->SetEnd(end);
747
748 size_t before = graph()->NodeCount();
749 ReduceGraph(&r);
750 EXPECT_EQ(before, graph()->NodeCount());
751 EXPECT_EQ(&kOpA0, n1->op());
752 EXPECT_EQ(&kOpA1, n2->op());
753 EXPECT_EQ(&kOpA1, n3->op());
754 EXPECT_EQ(&kOpA2, end->op());
755 EXPECT_EQ(end, graph()->end());
756 EXPECT_LE(end->InputAt(0)->id(), end->InputAt(1)->id());
757 }
758}
759
760
761namespace {
762
763// Generate a node graph with the given permutations.
764void GenDAG(Graph* graph, int* p3, int* p2, int* p1) {
765 Node* level4 = graph->NewNode(&kOpA0);
766 Node* level3[] = {graph->NewNode(&kOpA1, level4),
767 graph->NewNode(&kOpA1, level4)};
768
769 Node* level2[] = {graph->NewNode(&kOpA1, level3[p3[0]]),
770 graph->NewNode(&kOpA1, level3[p3[1]]),
771 graph->NewNode(&kOpA1, level3[p3[0]]),
772 graph->NewNode(&kOpA1, level3[p3[1]])};
773
774 Node* level1[] = {graph->NewNode(&kOpA2, level2[p2[0]], level2[p2[1]]),
775 graph->NewNode(&kOpA2, level2[p2[2]], level2[p2[3]])};
776
777 Node* end = graph->NewNode(&kOpA2, level1[p1[0]], level1[p1[1]]);
778 graph->SetEnd(end);
779}
780
781} // namespace
782
783
784TEST_F(GraphReducerTest, SortForwardReduce) {
785 // Tests combined reductions on a series of DAGs.
786 for (int j = 0; j < 2; j++) {
787 int p3[] = {j, 1 - j};
788 for (int m = 0; m < 2; m++) {
789 int p1[] = {m, 1 - m};
790 for (int k = 0; k < 24; k++) { // All permutations of 0, 1, 2, 3
791 int p2[] = {-1, -1, -1, -1};
792 int n = k;
793 for (int d = 4; d >= 1; d--) { // Construct permutation.
794 int p = n % d;
795 for (int z = 0; z < 4; z++) {
796 if (p2[z] == -1) {
797 if (p == 0) p2[z] = d - 1;
798 p--;
799 }
800 }
801 n = n / d;
802 }
803
804 GenDAG(graph(), p3, p2, p1);
805
806 AB2Sorter r1;
807 A1Forwarder r2;
808 InPlaceABReducer r3;
809
810 ReduceGraph(&r1, &r2, &r3);
811
812 Node* end = graph()->end();
813 EXPECT_EQ(&kOpB2, end->op());
814 Node* n1 = end->InputAt(0);
815 Node* n2 = end->InputAt(1);
816 EXPECT_NE(n1, n2);
817 EXPECT_LT(n1->id(), n2->id());
818 EXPECT_EQ(&kOpB2, n1->op());
819 EXPECT_EQ(&kOpB2, n2->op());
820 Node* n4 = n1->InputAt(0);
821 EXPECT_EQ(&kOpB0, n4->op());
822 EXPECT_EQ(n4, n1->InputAt(1));
823 EXPECT_EQ(n4, n2->InputAt(0));
824 EXPECT_EQ(n4, n2->InputAt(1));
825 }
826 }
827 }
828}
829
830
831TEST_F(GraphReducerTest, Order) {
832 // Test that the order of reducers doesn't matter, as they should be
833 // rerun for changed nodes.
834 for (int i = 0; i < 2; i++) {
835 Node* n1 = graph()->NewNode(&kOpA0);
836 Node* end = graph()->NewNode(&kOpA1, n1);
837 graph()->SetEnd(end);
838
839 InPlaceABReducer abr;
840 InPlaceBCReducer bcr;
841
842 // Tests A* => C* with in-place updates.
843 for (size_t j = 0; j < 3; j++) {
844 size_t before = graph()->NodeCount();
845 if (i == 0) {
846 ReduceGraph(&abr, &bcr);
847 } else {
848 ReduceGraph(&bcr, &abr);
849 }
850
851 EXPECT_EQ(before, graph()->NodeCount());
852 EXPECT_EQ(&kOpC0, n1->op());
853 EXPECT_EQ(&kOpC1, end->op());
854 EXPECT_EQ(n1, end->InputAt(0));
855 }
856 }
857}
858
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000859} // namespace compiler
860} // namespace internal
861} // namespace v8