Index: test/unittests/compiler/effect-control-linearizer-unittest.cc |
diff --git a/test/unittests/compiler/effect-control-linearizer-unittest.cc b/test/unittests/compiler/effect-control-linearizer-unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..95927df61dc2e7b0b0b8df0bacdf10f2c2d4f6ac |
--- /dev/null |
+++ b/test/unittests/compiler/effect-control-linearizer-unittest.cc |
@@ -0,0 +1,208 @@ |
+// Copyright 2015 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/compiler/effect-control-linearizer.h" |
+#include "src/compiler/access-builder.h" |
+#include "src/compiler/js-graph.h" |
+#include "src/compiler/node-properties.h" |
+#include "src/compiler/schedule.h" |
+#include "src/compiler/simplified-operator.h" |
+#include "test/unittests/compiler/graph-unittest.h" |
+#include "test/unittests/compiler/node-test-utils.h" |
+#include "test/unittests/test-utils.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+ |
+namespace v8 { |
+namespace internal { |
+namespace compiler { |
+ |
+class EffectControlLinearizerTest : public TypedGraphTest { |
+ public: |
+ EffectControlLinearizerTest() |
+ : TypedGraphTest(3), |
+ machine_(zone()), |
+ javascript_(zone()), |
+ simplified_(zone()), |
+ jsgraph_(isolate(), graph(), common(), &javascript_, &simplified_, |
+ &machine_) {} |
+ |
+ JSGraph* jsgraph() { return &jsgraph_; } |
+ SimplifiedOperatorBuilder* simplified() { return &simplified_; } |
+ |
+ private: |
+ MachineOperatorBuilder machine_; |
+ JSOperatorBuilder javascript_; |
+ SimplifiedOperatorBuilder simplified_; |
+ JSGraph jsgraph_; |
+}; |
+ |
+namespace { |
+ |
+BasicBlock* AddBlockToSchedule(Schedule* schedule) { |
+ BasicBlock* block = schedule->NewBasicBlock(); |
+ block->set_rpo_number(static_cast<int32_t>(schedule->rpo_order()->size())); |
+ schedule->rpo_order()->push_back(block); |
+ return block; |
+} |
+ |
+} // namespace |
+ |
+TEST_F(EffectControlLinearizerTest, SimpleLoad) { |
+ Schedule schedule(zone()); |
+ |
+ // Create the graph. |
+ Node* heap_number = NumberConstant(0.5); |
+ Node* load = graph()->NewNode( |
+ simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), heap_number, |
+ graph()->start(), graph()->start()); |
+ Node* ret = graph()->NewNode(common()->Return(), load, graph()->start(), |
+ graph()->start()); |
+ |
+ // Build the basic block structure. |
+ BasicBlock* start = schedule.start(); |
+ schedule.rpo_order()->push_back(start); |
+ start->set_rpo_number(0); |
+ |
+ // Populate the basic blocks with nodes. |
+ schedule.AddNode(start, graph()->start()); |
+ schedule.AddNode(start, heap_number); |
+ schedule.AddNode(start, load); |
+ schedule.AddReturn(start, ret); |
+ |
+ // Run the state effect introducer. |
+ EffectControlLinearizer introducer(jsgraph(), &schedule, zone()); |
+ introducer.Run(); |
+ |
+ EXPECT_THAT(load, |
+ IsLoadField(AccessBuilder::ForHeapNumberValue(), heap_number, |
+ graph()->start(), graph()->start())); |
+ // The return should have reconnected effect edge to the load. |
+ EXPECT_THAT(ret, IsReturn(load, load, graph()->start())); |
+} |
+ |
+TEST_F(EffectControlLinearizerTest, DiamondLoad) { |
+ Schedule schedule(zone()); |
+ |
+ // Create the graph. |
+ Node* branch = |
+ graph()->NewNode(common()->Branch(), Int32Constant(0), graph()->start()); |
+ |
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
+ Node* heap_number = NumberConstant(0.5); |
+ Node* vtrue = graph()->NewNode( |
+ simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), heap_number, |
+ graph()->start(), if_true); |
+ |
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
+ Node* vfalse = Float64Constant(2); |
+ |
+ Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); |
+ Node* phi = graph()->NewNode( |
+ common()->Phi(MachineRepresentation::kFloat64, 2), vtrue, vfalse, merge); |
+ |
+ Node* ret = |
+ graph()->NewNode(common()->Return(), phi, graph()->start(), merge); |
+ |
+ // Build the basic block structure. |
+ BasicBlock* start = schedule.start(); |
+ schedule.rpo_order()->push_back(start); |
+ start->set_rpo_number(0); |
+ |
+ BasicBlock* tblock = AddBlockToSchedule(&schedule); |
+ BasicBlock* fblock = AddBlockToSchedule(&schedule); |
+ BasicBlock* mblock = AddBlockToSchedule(&schedule); |
+ |
+ // Populate the basic blocks with nodes. |
+ schedule.AddNode(start, graph()->start()); |
+ schedule.AddBranch(start, branch, tblock, fblock); |
+ |
+ schedule.AddNode(tblock, if_true); |
+ schedule.AddNode(tblock, heap_number); |
+ schedule.AddNode(tblock, vtrue); |
+ schedule.AddGoto(tblock, mblock); |
+ |
+ schedule.AddNode(fblock, if_false); |
+ schedule.AddNode(fblock, vfalse); |
+ schedule.AddGoto(fblock, mblock); |
+ |
+ schedule.AddNode(mblock, merge); |
+ schedule.AddNode(mblock, phi); |
+ schedule.AddReturn(mblock, ret); |
+ |
+ // Run the state effect introducer. |
+ EffectControlLinearizer introducer(jsgraph(), &schedule, zone()); |
+ introducer.Run(); |
+ |
+ // The effect input to the return should be an effect phi with the |
+ // newly introduced effectful change operators. |
+ ASSERT_THAT( |
+ ret, IsReturn(phi, IsEffectPhi(vtrue, graph()->start(), merge), merge)); |
+} |
+ |
+TEST_F(EffectControlLinearizerTest, LoopLoad) { |
+ Schedule schedule(zone()); |
+ |
+ // Create the graph. |
+ Node* loop = graph()->NewNode(common()->Loop(1), graph()->start()); |
+ Node* effect_phi = |
+ graph()->NewNode(common()->EffectPhi(1), graph()->start(), loop); |
+ |
+ Node* cond = Int32Constant(0); |
+ Node* branch = graph()->NewNode(common()->Branch(), cond, loop); |
+ |
+ Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
+ |
+ Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
+ |
+ loop->AppendInput(zone(), if_false); |
+ NodeProperties::ChangeOp(loop, common()->Loop(2)); |
+ |
+ effect_phi->InsertInput(zone(), 1, effect_phi); |
+ NodeProperties::ChangeOp(effect_phi, common()->EffectPhi(2)); |
+ |
+ Node* heap_number = NumberConstant(0.5); |
+ Node* load = graph()->NewNode( |
+ simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), heap_number, |
+ graph()->start(), loop); |
+ |
+ Node* ret = graph()->NewNode(common()->Return(), load, effect_phi, if_true); |
+ |
+ // Build the basic block structure. |
+ BasicBlock* start = schedule.start(); |
+ schedule.rpo_order()->push_back(start); |
+ start->set_rpo_number(0); |
+ |
+ BasicBlock* lblock = AddBlockToSchedule(&schedule); |
+ BasicBlock* fblock = AddBlockToSchedule(&schedule); |
+ BasicBlock* rblock = AddBlockToSchedule(&schedule); |
+ |
+ // Populate the basic blocks with nodes. |
+ schedule.AddNode(start, graph()->start()); |
+ schedule.AddGoto(start, lblock); |
+ |
+ schedule.AddNode(lblock, loop); |
+ schedule.AddNode(lblock, effect_phi); |
+ schedule.AddNode(lblock, heap_number); |
+ schedule.AddNode(lblock, load); |
+ schedule.AddNode(lblock, cond); |
+ schedule.AddBranch(lblock, branch, rblock, fblock); |
+ |
+ schedule.AddNode(fblock, if_false); |
+ schedule.AddGoto(fblock, lblock); |
+ |
+ schedule.AddNode(rblock, if_true); |
+ schedule.AddReturn(rblock, ret); |
+ |
+ // Run the state effect introducer. |
+ EffectControlLinearizer introducer(jsgraph(), &schedule, zone()); |
+ introducer.Run(); |
+ |
+ ASSERT_THAT(ret, IsReturn(load, load, if_true)); |
+ EXPECT_THAT(load, IsLoadField(AccessBuilder::ForHeapNumberValue(), |
+ heap_number, effect_phi, loop)); |
+} |
+ |
+} // namespace compiler |
+} // namespace internal |
+} // namespace v8 |