Merge V8 5.2.361.47  DO NOT MERGE

https://chromium.googlesource.com/v8/v8/+/5.2.361.47

FPIIM-449

Change-Id: Ibec421b85a9b88cb3a432ada642e469fe7e78346
(cherry picked from commit bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8)
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 0000000..417444e
--- /dev/null
+++ b/test/unittests/compiler/effect-control-linearizer-unittest.cc
@@ -0,0 +1,330 @@
+// 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/linkage.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, FloatingDiamondsControlWiring) {
+  Schedule schedule(zone());
+
+  // Create the graph and schedule. Roughly (omitting effects and unimportant
+  // nodes):
+  //
+  //            BLOCK 0:
+  //             r1: Start
+  //             c1: Call
+  //             b1: Branch(const0, s1)
+  //                |
+  //        +-------+------+
+  //        |              |
+  //   BLOCK 1:           BLOCK 2:
+  //    t1: IfTrue(b1)     f1: IfFalse(b1)
+  //        |              |
+  //        +-------+------+
+  //                |
+  //            BLOCK 3:
+  //             m1: Merge(t1, f1)
+  //             c2: IfSuccess(c1)
+  //             b2: Branch(const0 , s1)
+  //                |
+  //        +-------+------+
+  //        |              |
+  //   BLOCK 4:           BLOCK 5:
+  //    t2: IfTrue(b2)     f2:IfFalse(b2)
+  //        |              |
+  //        +-------+------+
+  //                |
+  //            BLOCK 6:
+  //             m2: Merge(t2, f2)
+  //             r1: Return(c1, c2)
+  MachineType kMachineSignature[] = {MachineType::AnyTagged(),
+                                     MachineType::AnyTagged()};
+  LinkageLocation kLocationSignature[] = {LinkageLocation::ForRegister(0),
+                                          LinkageLocation::ForRegister(1)};
+  const CallDescriptor* kCallDescriptor = new (zone()) CallDescriptor(
+      CallDescriptor::kCallCodeObject, MachineType::AnyTagged(),
+      LinkageLocation::ForRegister(0),
+      new (zone()) MachineSignature(1, 1, kMachineSignature),
+      new (zone()) LocationSignature(1, 1, kLocationSignature), 0,
+      Operator::kNoProperties, 0, 0, CallDescriptor::kNoFlags);
+  Node* p0 = Parameter(0);
+  Node* p1 = Parameter(1);
+  Node* const0 = Int32Constant(0);
+  Node* call = graph()->NewNode(common()->Call(kCallDescriptor), p0, p1,
+                                graph()->start(), graph()->start());
+  Node* if_success = graph()->NewNode(common()->IfSuccess(), call);
+
+  // First Floating diamond.
+  Node* branch1 =
+      graph()->NewNode(common()->Branch(), const0, graph()->start());
+  Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+  Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+  Node* merge1 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
+
+  // Second floating diamond.
+  Node* branch2 =
+      graph()->NewNode(common()->Branch(), const0, graph()->start());
+  Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
+  Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
+  Node* merge2 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
+
+  Node* ret =
+      graph()->NewNode(common()->Return(), call, graph()->start(), if_success);
+
+  // Build the basic block structure.
+  BasicBlock* start = schedule.start();
+  schedule.rpo_order()->push_back(start);
+  start->set_rpo_number(0);
+
+  BasicBlock* t1block = AddBlockToSchedule(&schedule);
+  BasicBlock* f1block = AddBlockToSchedule(&schedule);
+  BasicBlock* m1block = AddBlockToSchedule(&schedule);
+
+  BasicBlock* t2block = AddBlockToSchedule(&schedule);
+  BasicBlock* f2block = AddBlockToSchedule(&schedule);
+  BasicBlock* m2block = AddBlockToSchedule(&schedule);
+
+  // Populate the basic blocks with nodes.
+  schedule.AddNode(start, graph()->start());
+  schedule.AddNode(start, p0);
+  schedule.AddNode(start, p1);
+  schedule.AddNode(start, const0);
+  schedule.AddNode(start, call);
+  schedule.AddBranch(start, branch1, t1block, f1block);
+
+  schedule.AddNode(t1block, if_true1);
+  schedule.AddGoto(t1block, m1block);
+
+  schedule.AddNode(f1block, if_false1);
+  schedule.AddGoto(f1block, m1block);
+
+  schedule.AddNode(m1block, merge1);
+  // The scheduler does not always put the IfSuccess node to the corresponding
+  // call's block, simulate that here.
+  schedule.AddNode(m1block, if_success);
+  schedule.AddBranch(m1block, branch2, t2block, f2block);
+
+  schedule.AddNode(t2block, if_true2);
+  schedule.AddGoto(t2block, m2block);
+
+  schedule.AddNode(f2block, if_false2);
+  schedule.AddGoto(f2block, m2block);
+
+  schedule.AddNode(m2block, merge2);
+  schedule.AddReturn(m2block, 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(call, call, merge2));
+  ASSERT_THAT(branch2, IsBranch(const0, merge1));
+  ASSERT_THAT(branch1, IsBranch(const0, if_success));
+  ASSERT_THAT(if_success, IsIfSuccess(call));
+}
+
+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