OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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/effect-control-linearizer.h" |
| 6 #include "src/compiler/access-builder.h" |
| 7 #include "src/compiler/js-graph.h" |
| 8 #include "src/compiler/node-properties.h" |
| 9 #include "src/compiler/schedule.h" |
| 10 #include "src/compiler/simplified-operator.h" |
| 11 #include "test/unittests/compiler/graph-unittest.h" |
| 12 #include "test/unittests/compiler/node-test-utils.h" |
| 13 #include "test/unittests/test-utils.h" |
| 14 #include "testing/gmock/include/gmock/gmock.h" |
| 15 |
| 16 namespace v8 { |
| 17 namespace internal { |
| 18 namespace compiler { |
| 19 |
| 20 class EffectControlLinearizerTest : public TypedGraphTest { |
| 21 public: |
| 22 EffectControlLinearizerTest() |
| 23 : TypedGraphTest(3), |
| 24 machine_(zone()), |
| 25 javascript_(zone()), |
| 26 simplified_(zone()), |
| 27 jsgraph_(isolate(), graph(), common(), &javascript_, &simplified_, |
| 28 &machine_) {} |
| 29 |
| 30 JSGraph* jsgraph() { return &jsgraph_; } |
| 31 SimplifiedOperatorBuilder* simplified() { return &simplified_; } |
| 32 |
| 33 private: |
| 34 MachineOperatorBuilder machine_; |
| 35 JSOperatorBuilder javascript_; |
| 36 SimplifiedOperatorBuilder simplified_; |
| 37 JSGraph jsgraph_; |
| 38 }; |
| 39 |
| 40 namespace { |
| 41 |
| 42 BasicBlock* AddBlockToSchedule(Schedule* schedule) { |
| 43 BasicBlock* block = schedule->NewBasicBlock(); |
| 44 block->set_rpo_number(static_cast<int32_t>(schedule->rpo_order()->size())); |
| 45 schedule->rpo_order()->push_back(block); |
| 46 return block; |
| 47 } |
| 48 |
| 49 } // namespace |
| 50 |
| 51 TEST_F(EffectControlLinearizerTest, SimpleLoad) { |
| 52 Schedule schedule(zone()); |
| 53 |
| 54 // Create the graph. |
| 55 Node* heap_number = NumberConstant(0.5); |
| 56 Node* load = graph()->NewNode( |
| 57 simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), heap_number, |
| 58 graph()->start(), graph()->start()); |
| 59 Node* ret = graph()->NewNode(common()->Return(), load, graph()->start(), |
| 60 graph()->start()); |
| 61 |
| 62 // Build the basic block structure. |
| 63 BasicBlock* start = schedule.start(); |
| 64 schedule.rpo_order()->push_back(start); |
| 65 start->set_rpo_number(0); |
| 66 |
| 67 // Populate the basic blocks with nodes. |
| 68 schedule.AddNode(start, graph()->start()); |
| 69 schedule.AddNode(start, heap_number); |
| 70 schedule.AddNode(start, load); |
| 71 schedule.AddReturn(start, ret); |
| 72 |
| 73 // Run the state effect introducer. |
| 74 EffectControlLinearizer introducer(jsgraph(), &schedule, zone()); |
| 75 introducer.Run(); |
| 76 |
| 77 EXPECT_THAT(load, |
| 78 IsLoadField(AccessBuilder::ForHeapNumberValue(), heap_number, |
| 79 graph()->start(), graph()->start())); |
| 80 // The return should have reconnected effect edge to the load. |
| 81 EXPECT_THAT(ret, IsReturn(load, load, graph()->start())); |
| 82 } |
| 83 |
| 84 TEST_F(EffectControlLinearizerTest, DiamondLoad) { |
| 85 Schedule schedule(zone()); |
| 86 |
| 87 // Create the graph. |
| 88 Node* branch = |
| 89 graph()->NewNode(common()->Branch(), Int32Constant(0), graph()->start()); |
| 90 |
| 91 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 92 Node* heap_number = NumberConstant(0.5); |
| 93 Node* vtrue = graph()->NewNode( |
| 94 simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), heap_number, |
| 95 graph()->start(), if_true); |
| 96 |
| 97 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 98 Node* vfalse = Float64Constant(2); |
| 99 |
| 100 Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 101 Node* phi = graph()->NewNode( |
| 102 common()->Phi(MachineRepresentation::kFloat64, 2), vtrue, vfalse, merge); |
| 103 |
| 104 Node* ret = |
| 105 graph()->NewNode(common()->Return(), phi, graph()->start(), merge); |
| 106 |
| 107 // Build the basic block structure. |
| 108 BasicBlock* start = schedule.start(); |
| 109 schedule.rpo_order()->push_back(start); |
| 110 start->set_rpo_number(0); |
| 111 |
| 112 BasicBlock* tblock = AddBlockToSchedule(&schedule); |
| 113 BasicBlock* fblock = AddBlockToSchedule(&schedule); |
| 114 BasicBlock* mblock = AddBlockToSchedule(&schedule); |
| 115 |
| 116 // Populate the basic blocks with nodes. |
| 117 schedule.AddNode(start, graph()->start()); |
| 118 schedule.AddBranch(start, branch, tblock, fblock); |
| 119 |
| 120 schedule.AddNode(tblock, if_true); |
| 121 schedule.AddNode(tblock, heap_number); |
| 122 schedule.AddNode(tblock, vtrue); |
| 123 schedule.AddGoto(tblock, mblock); |
| 124 |
| 125 schedule.AddNode(fblock, if_false); |
| 126 schedule.AddNode(fblock, vfalse); |
| 127 schedule.AddGoto(fblock, mblock); |
| 128 |
| 129 schedule.AddNode(mblock, merge); |
| 130 schedule.AddNode(mblock, phi); |
| 131 schedule.AddReturn(mblock, ret); |
| 132 |
| 133 // Run the state effect introducer. |
| 134 EffectControlLinearizer introducer(jsgraph(), &schedule, zone()); |
| 135 introducer.Run(); |
| 136 |
| 137 // The effect input to the return should be an effect phi with the |
| 138 // newly introduced effectful change operators. |
| 139 ASSERT_THAT( |
| 140 ret, IsReturn(phi, IsEffectPhi(vtrue, graph()->start(), merge), merge)); |
| 141 } |
| 142 |
| 143 TEST_F(EffectControlLinearizerTest, LoopLoad) { |
| 144 Schedule schedule(zone()); |
| 145 |
| 146 // Create the graph. |
| 147 Node* loop = graph()->NewNode(common()->Loop(1), graph()->start()); |
| 148 Node* effect_phi = |
| 149 graph()->NewNode(common()->EffectPhi(1), graph()->start(), loop); |
| 150 |
| 151 Node* cond = Int32Constant(0); |
| 152 Node* branch = graph()->NewNode(common()->Branch(), cond, loop); |
| 153 |
| 154 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 155 |
| 156 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 157 |
| 158 loop->AppendInput(zone(), if_false); |
| 159 NodeProperties::ChangeOp(loop, common()->Loop(2)); |
| 160 |
| 161 effect_phi->InsertInput(zone(), 1, effect_phi); |
| 162 NodeProperties::ChangeOp(effect_phi, common()->EffectPhi(2)); |
| 163 |
| 164 Node* heap_number = NumberConstant(0.5); |
| 165 Node* load = graph()->NewNode( |
| 166 simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), heap_number, |
| 167 graph()->start(), loop); |
| 168 |
| 169 Node* ret = graph()->NewNode(common()->Return(), load, effect_phi, if_true); |
| 170 |
| 171 // Build the basic block structure. |
| 172 BasicBlock* start = schedule.start(); |
| 173 schedule.rpo_order()->push_back(start); |
| 174 start->set_rpo_number(0); |
| 175 |
| 176 BasicBlock* lblock = AddBlockToSchedule(&schedule); |
| 177 BasicBlock* fblock = AddBlockToSchedule(&schedule); |
| 178 BasicBlock* rblock = AddBlockToSchedule(&schedule); |
| 179 |
| 180 // Populate the basic blocks with nodes. |
| 181 schedule.AddNode(start, graph()->start()); |
| 182 schedule.AddGoto(start, lblock); |
| 183 |
| 184 schedule.AddNode(lblock, loop); |
| 185 schedule.AddNode(lblock, effect_phi); |
| 186 schedule.AddNode(lblock, heap_number); |
| 187 schedule.AddNode(lblock, load); |
| 188 schedule.AddNode(lblock, cond); |
| 189 schedule.AddBranch(lblock, branch, rblock, fblock); |
| 190 |
| 191 schedule.AddNode(fblock, if_false); |
| 192 schedule.AddGoto(fblock, lblock); |
| 193 |
| 194 schedule.AddNode(rblock, if_true); |
| 195 schedule.AddReturn(rblock, ret); |
| 196 |
| 197 // Run the state effect introducer. |
| 198 EffectControlLinearizer introducer(jsgraph(), &schedule, zone()); |
| 199 introducer.Run(); |
| 200 |
| 201 ASSERT_THAT(ret, IsReturn(load, load, if_true)); |
| 202 EXPECT_THAT(load, IsLoadField(AccessBuilder::ForHeapNumberValue(), |
| 203 heap_number, effect_phi, loop)); |
| 204 } |
| 205 |
| 206 } // namespace compiler |
| 207 } // namespace internal |
| 208 } // namespace v8 |
OLD | NEW |