// 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/common-operator.h"
#include "src/compiler/node-properties.h"
#include "test/unittests/test-utils.h"
#include "testing/gmock/include/gmock/gmock.h"

using testing::AnyOf;
using testing::ElementsAre;
using testing::IsNull;

namespace v8 {
namespace internal {
namespace compiler {

class NodePropertiesTest : public TestWithZone {
 public:
  Node* NewMockNode(const Operator* op) {
    return Node::New(zone(), 0, op, 0, nullptr, false);
  }
  Node* NewMockNode(const Operator* op, Node* n1) {
    Node* nodes[] = {n1};
    return Node::New(zone(), 0, op, arraysize(nodes), nodes, false);
  }
  Node* NewMockNode(const Operator* op, Node* n1, Node* n2) {
    Node* nodes[] = {n1, n2};
    return Node::New(zone(), 0, op, arraysize(nodes), nodes, false);
  }
};

namespace {

const Operator kMockOperator(IrOpcode::kDead, Operator::kNoProperties,
                             "MockOperator", 0, 0, 0, 1, 1, 2);
const Operator kMockCallOperator(IrOpcode::kCall, Operator::kNoProperties,
                                 "MockCallOperator", 0, 0, 0, 0, 0, 2);

const IfExceptionHint kNoHint = IfExceptionHint::kLocallyCaught;

}  // namespace


TEST_F(NodePropertiesTest, ReplaceUses) {
  CommonOperatorBuilder common(zone());
  Node* node = NewMockNode(&kMockOperator);
  Node* effect = NewMockNode(&kMockOperator);
  Node* use_value = NewMockNode(common.Return(), node);
  Node* use_effect = NewMockNode(common.EffectPhi(1), node);
  Node* use_success = NewMockNode(common.IfSuccess(), node);
  Node* use_exception = NewMockNode(common.IfException(kNoHint), effect, node);
  Node* r_value = NewMockNode(&kMockOperator);
  Node* r_effect = NewMockNode(&kMockOperator);
  Node* r_success = NewMockNode(&kMockOperator);
  Node* r_exception = NewMockNode(&kMockOperator);
  NodeProperties::ReplaceUses(node, r_value, r_effect, r_success, r_exception);
  EXPECT_EQ(r_value, use_value->InputAt(0));
  EXPECT_EQ(r_effect, use_effect->InputAt(0));
  EXPECT_EQ(r_success, use_success->InputAt(0));
  EXPECT_EQ(r_exception, use_exception->InputAt(1));
  EXPECT_EQ(0, node->UseCount());
  EXPECT_EQ(1, r_value->UseCount());
  EXPECT_EQ(1, r_effect->UseCount());
  EXPECT_EQ(1, r_success->UseCount());
  EXPECT_EQ(1, r_exception->UseCount());
  EXPECT_THAT(r_value->uses(), ElementsAre(use_value));
  EXPECT_THAT(r_effect->uses(), ElementsAre(use_effect));
  EXPECT_THAT(r_success->uses(), ElementsAre(use_success));
  EXPECT_THAT(r_exception->uses(), ElementsAre(use_exception));
}


TEST_F(NodePropertiesTest, FindProjection) {
  CommonOperatorBuilder common(zone());
  Node* start = NewMockNode(common.Start(1));
  Node* proj0 = NewMockNode(common.Projection(0), start);
  Node* proj1 = NewMockNode(common.Projection(1), start);
  EXPECT_EQ(proj0, NodeProperties::FindProjection(start, 0));
  EXPECT_EQ(proj1, NodeProperties::FindProjection(start, 1));
  EXPECT_THAT(NodeProperties::FindProjection(start, 2), IsNull());
  EXPECT_THAT(NodeProperties::FindProjection(start, 1234567890), IsNull());
}


TEST_F(NodePropertiesTest, CollectControlProjections_Branch) {
  Node* result[2];
  CommonOperatorBuilder common(zone());
  Node* branch = NewMockNode(common.Branch());
  Node* if_false = NewMockNode(common.IfFalse(), branch);
  Node* if_true = NewMockNode(common.IfTrue(), branch);
  NodeProperties::CollectControlProjections(branch, result, arraysize(result));
  EXPECT_EQ(if_true, result[0]);
  EXPECT_EQ(if_false, result[1]);
}


TEST_F(NodePropertiesTest, CollectControlProjections_Call) {
  Node* result[2];
  CommonOperatorBuilder common(zone());
  Node* call = NewMockNode(&kMockCallOperator);
  Node* if_ex = NewMockNode(common.IfException(kNoHint), call, call);
  Node* if_ok = NewMockNode(common.IfSuccess(), call);
  NodeProperties::CollectControlProjections(call, result, arraysize(result));
  EXPECT_EQ(if_ok, result[0]);
  EXPECT_EQ(if_ex, result[1]);
}


TEST_F(NodePropertiesTest, CollectControlProjections_Switch) {
  Node* result[3];
  CommonOperatorBuilder common(zone());
  Node* sw = NewMockNode(common.Switch(3));
  Node* if_default = NewMockNode(common.IfDefault(), sw);
  Node* if_value1 = NewMockNode(common.IfValue(1), sw);
  Node* if_value2 = NewMockNode(common.IfValue(2), sw);
  NodeProperties::CollectControlProjections(sw, result, arraysize(result));
  EXPECT_THAT(result[0], AnyOf(if_value1, if_value2));
  EXPECT_THAT(result[1], AnyOf(if_value1, if_value2));
  EXPECT_EQ(if_default, result[2]);
}

}  // namespace compiler
}  // namespace internal
}  // namespace v8
