// Copyright 2019 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/decompression-elimination.h"
#include "src/compiler/node-properties.h"

namespace v8 {
namespace internal {
namespace compiler {

DecompressionElimination::DecompressionElimination(
    Editor* editor, Graph* graph, MachineOperatorBuilder* machine,
    CommonOperatorBuilder* common)
    : AdvancedReducer(editor),
      graph_(graph),
      machine_(machine),
      common_(common) {}

bool DecompressionElimination::IsReducibleConstantOpcode(
    IrOpcode::Value opcode) {
  switch (opcode) {
    case IrOpcode::kInt64Constant:
    case IrOpcode::kHeapConstant:
      return true;
    default:
      return false;
  }
}

bool DecompressionElimination::IsValidDecompress(
    IrOpcode::Value compressOpcode, IrOpcode::Value decompressOpcode) {
  switch (compressOpcode) {
    case IrOpcode::kChangeTaggedToCompressed:
      return IrOpcode::IsDecompressOpcode(decompressOpcode);
    case IrOpcode::kChangeTaggedSignedToCompressedSigned:
      return decompressOpcode ==
                 IrOpcode::kChangeCompressedSignedToTaggedSigned ||
             decompressOpcode == IrOpcode::kChangeCompressedToTagged;
    case IrOpcode::kChangeTaggedPointerToCompressedPointer:
      return decompressOpcode ==
                 IrOpcode::kChangeCompressedPointerToTaggedPointer ||
             decompressOpcode == IrOpcode::kChangeCompressedToTagged;
    default:
      UNREACHABLE();
  }
}

Node* DecompressionElimination::GetCompressedConstant(Node* constant) {
  switch (constant->opcode()) {
    case IrOpcode::kInt64Constant:
      return graph()->NewNode(common()->Int32Constant(
          static_cast<int32_t>(OpParameter<int64_t>(constant->op()))));
      break;
    case IrOpcode::kHeapConstant:
      return graph()->NewNode(
          common()->CompressedHeapConstant(HeapConstantOf(constant->op())));
    default:
      UNREACHABLE();
  }
}

Reduction DecompressionElimination::ReduceCompress(Node* node) {
  DCHECK(IrOpcode::IsCompressOpcode(node->opcode()));

  DCHECK_EQ(node->InputCount(), 1);
  Node* input_node = node->InputAt(0);
  IrOpcode::Value input_opcode = input_node->opcode();
  if (IrOpcode::IsDecompressOpcode(input_opcode)) {
    DCHECK(IsValidDecompress(node->opcode(), input_opcode));
    DCHECK_EQ(input_node->InputCount(), 1);
    return Replace(input_node->InputAt(0));
  } else if (IsReducibleConstantOpcode(input_opcode)) {
    return Replace(GetCompressedConstant(input_node));
  } else {
    return NoChange();
  }
}

Reduction DecompressionElimination::ReduceDecompress(Node* node) {
  DCHECK(IrOpcode::IsDecompressOpcode(node->opcode()));

  DCHECK_EQ(node->InputCount(), 1);
  Node* input_node = node->InputAt(0);
  IrOpcode::Value input_opcode = input_node->opcode();
  if (IrOpcode::IsCompressOpcode(input_opcode)) {
    DCHECK(IsValidDecompress(input_opcode, node->opcode()));
    DCHECK_EQ(input_node->InputCount(), 1);
    return Replace(input_node->InputAt(0));
  } else {
    return NoChange();
  }
}

Reduction DecompressionElimination::ReducePhi(Node* node) {
  DCHECK_EQ(node->opcode(), IrOpcode::kPhi);

  const int value_input_count = node->op()->ValueInputCount();

  // Check if all input are decompress nodes, and if all are the same.
  bool same_decompresses = true;
  IrOpcode::Value first_opcode = node->InputAt(0)->opcode();
  for (int i = 0; i < value_input_count; ++i) {
    Node* input = node->InputAt(i);
    if (IrOpcode::IsDecompressOpcode(input->opcode())) {
      same_decompresses &= first_opcode == input->opcode();
    } else {
      return NoChange();
    }
  }

  // By now, we know that all inputs are decompress nodes. If all are the same,
  // we can grab the first one to be used after the Phi. If we have different
  // Decompress nodes as inputs, we need to use a conservative decompression
  // after the Phi.
  const Operator* op;
  if (same_decompresses) {
    op = node->InputAt(0)->op();
  } else {
    op = machine()->ChangeCompressedToTagged();
  }

  // Rewire phi's inputs to be the compressed inputs.
  for (int i = 0; i < value_input_count; ++i) {
    Node* input = node->InputAt(i);
    DCHECK_EQ(input->InputCount(), 1);
    node->ReplaceInput(i, input->InputAt(0));
  }

  // Update the MachineRepresentation on the Phi.
  MachineRepresentation rep;
  switch (op->opcode()) {
    case IrOpcode::kChangeCompressedToTagged:
      rep = MachineRepresentation::kCompressed;
      break;
    case IrOpcode::kChangeCompressedSignedToTaggedSigned:
      rep = MachineRepresentation::kCompressedSigned;
      break;
    case IrOpcode::kChangeCompressedPointerToTaggedPointer:
      rep = MachineRepresentation::kCompressedPointer;
      break;
    default:
      UNREACHABLE();
  }
  NodeProperties::ChangeOp(node, common()->Phi(rep, value_input_count));

  // Add a decompress after the Phi. To do this, we need to replace the Phi with
  // "Phi <- Decompress".
  Node* decompress = graph()->NewNode(op, node);
  ReplaceWithValue(node, decompress);
  decompress->ReplaceInput(0, node);
  return Changed(node);
}

Reduction DecompressionElimination::ReduceTypedStateValues(Node* node) {
  DCHECK_EQ(node->opcode(), IrOpcode::kTypedStateValues);

  bool any_change = false;
  for (int i = 0; i < node->InputCount(); ++i) {
    Node* input = node->InputAt(i);
    if (IrOpcode::IsDecompressOpcode(input->opcode())) {
      DCHECK_EQ(input->InputCount(), 1);
      node->ReplaceInput(i, input->InputAt(0));
      any_change = true;
    }
  }
  return any_change ? Changed(node) : NoChange();
}

Reduction DecompressionElimination::ReduceWord64Equal(Node* node) {
  DCHECK_EQ(node->opcode(), IrOpcode::kWord64Equal);

  DCHECK_EQ(node->InputCount(), 2);
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

  bool lhs_is_decompress = IrOpcode::IsDecompressOpcode(lhs->opcode());
  bool rhs_is_decompress = IrOpcode::IsDecompressOpcode(rhs->opcode());

  // Case where both of its inputs are Decompress nodes.
  if (lhs_is_decompress && rhs_is_decompress) {
    DCHECK_EQ(lhs->InputCount(), 1);
    node->ReplaceInput(0, lhs->InputAt(0));
    DCHECK_EQ(rhs->InputCount(), 1);
    node->ReplaceInput(1, rhs->InputAt(0));
    NodeProperties::ChangeOp(node, machine()->Word32Equal());
    return Changed(node);
  }

  bool lhs_is_constant = IsReducibleConstantOpcode(lhs->opcode());
  bool rhs_is_constant = IsReducibleConstantOpcode(rhs->opcode());

  // Case where one input is a Decompress node and the other a constant.
  if ((lhs_is_decompress && rhs_is_constant) ||
      (lhs_is_constant && rhs_is_decompress)) {
    node->ReplaceInput(
        0, lhs_is_decompress ? lhs->InputAt(0) : GetCompressedConstant(lhs));
    node->ReplaceInput(
        1, lhs_is_decompress ? GetCompressedConstant(rhs) : rhs->InputAt(0));
    NodeProperties::ChangeOp(node, machine()->Word32Equal());
    return Changed(node);
  }

  return NoChange();
}

Reduction DecompressionElimination::Reduce(Node* node) {
  DisallowHeapAccess no_heap_access;

  switch (node->opcode()) {
    case IrOpcode::kChangeTaggedToCompressed:
    case IrOpcode::kChangeTaggedSignedToCompressedSigned:
    case IrOpcode::kChangeTaggedPointerToCompressedPointer:
      return ReduceCompress(node);
    case IrOpcode::kChangeCompressedToTagged:
    case IrOpcode::kChangeCompressedSignedToTaggedSigned:
    case IrOpcode::kChangeCompressedPointerToTaggedPointer:
      return ReduceDecompress(node);
    case IrOpcode::kPhi:
      return ReducePhi(node);
    case IrOpcode::kTypedStateValues:
      return ReduceTypedStateValues(node);
    case IrOpcode::kWord64Equal:
      return ReduceWord64Equal(node);
    default:
      break;
  }

  return NoChange();
}

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