// Copyright (c) 2020 Vasyl Teliman
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "source/fuzz/transformation_propagate_instruction_up.h"

#include "source/fuzz/fuzzer_util.h"
#include "source/fuzz/instruction_descriptor.h"

namespace spvtools {
namespace fuzz {
namespace {

uint32_t GetResultIdFromLabelId(const opt::Instruction& phi_inst,
                                uint32_t label_id) {
  assert(phi_inst.opcode() == SpvOpPhi && "|phi_inst| is not an OpPhi");

  for (uint32_t i = 1; i < phi_inst.NumInOperands(); i += 2) {
    if (phi_inst.GetSingleWordInOperand(i) == label_id) {
      return phi_inst.GetSingleWordInOperand(i - 1);
    }
  }

  return 0;
}

bool ContainsPointers(const opt::analysis::Type& type) {
  switch (type.kind()) {
    case opt::analysis::Type::kPointer:
      return true;
    case opt::analysis::Type::kStruct:
      return std::any_of(type.AsStruct()->element_types().begin(),
                         type.AsStruct()->element_types().end(),
                         [](const opt::analysis::Type* element_type) {
                           return ContainsPointers(*element_type);
                         });
    default:
      return false;
  }
}

bool HasValidDependencies(opt::IRContext* ir_context, opt::Instruction* inst) {
  const auto* inst_block = ir_context->get_instr_block(inst);
  assert(inst_block &&
         "This function shouldn't be applied to global instructions or function"
         "parameters");

  for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
    const auto& operand = inst->GetInOperand(i);
    if (operand.type != SPV_OPERAND_TYPE_ID) {
      // Consider only <id> operands.
      continue;
    }

    auto* dependency = ir_context->get_def_use_mgr()->GetDef(operand.words[0]);
    assert(dependency && "Operand has invalid id");

    if (ir_context->get_instr_block(dependency) == inst_block &&
        dependency->opcode() != SpvOpPhi) {
      // |dependency| is "valid" if it's an OpPhi from the same basic block or
      // an instruction from a different basic block.
      return false;
    }
  }

  return true;
}

}  // namespace

TransformationPropagateInstructionUp::TransformationPropagateInstructionUp(
    const protobufs::TransformationPropagateInstructionUp& message)
    : message_(message) {}

TransformationPropagateInstructionUp::TransformationPropagateInstructionUp(
    uint32_t block_id,
    const std::map<uint32_t, uint32_t>& predecessor_id_to_fresh_id) {
  message_.set_block_id(block_id);
  *message_.mutable_predecessor_id_to_fresh_id() =
      fuzzerutil::MapToRepeatedUInt32Pair(predecessor_id_to_fresh_id);
}

bool TransformationPropagateInstructionUp::IsApplicable(
    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
  // Check that we can apply this transformation to the |block_id|.
  if (!IsApplicableToBlock(ir_context, message_.block_id())) {
    return false;
  }

  const auto predecessor_id_to_fresh_id = fuzzerutil::RepeatedUInt32PairToMap(
      message_.predecessor_id_to_fresh_id());
  for (auto id : ir_context->cfg()->preds(message_.block_id())) {
    // Each predecessor must have a fresh id in the |predecessor_id_to_fresh_id|
    // map.
    if (!predecessor_id_to_fresh_id.count(id)) {
      return false;
    }
  }

  std::vector<uint32_t> maybe_fresh_ids;
  maybe_fresh_ids.reserve(predecessor_id_to_fresh_id.size());
  for (const auto& entry : predecessor_id_to_fresh_id) {
    maybe_fresh_ids.push_back(entry.second);
  }

  // All ids must be unique and fresh.
  return !fuzzerutil::HasDuplicates(maybe_fresh_ids) &&
         std::all_of(maybe_fresh_ids.begin(), maybe_fresh_ids.end(),
                     [ir_context](uint32_t id) {
                       return fuzzerutil::IsFreshId(ir_context, id);
                     });
}

void TransformationPropagateInstructionUp::Apply(
    opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
  auto* inst = GetInstructionToPropagate(ir_context, message_.block_id());
  assert(inst &&
         "The block must have at least one supported instruction to propagate");
  assert(inst->result_id() && inst->type_id() &&
         "|inst| must have a result id and a type id");

  opt::Instruction::OperandList op_phi_operands;
  const auto predecessor_id_to_fresh_id = fuzzerutil::RepeatedUInt32PairToMap(
      message_.predecessor_id_to_fresh_id());
  std::unordered_set<uint32_t> visited_predecessors;
  for (auto predecessor_id : ir_context->cfg()->preds(message_.block_id())) {
    // A block can have multiple identical predecessors.
    if (visited_predecessors.count(predecessor_id)) {
      continue;
    }

    visited_predecessors.insert(predecessor_id);

    auto new_result_id = predecessor_id_to_fresh_id.at(predecessor_id);

    // Compute InOperands for the OpPhi instruction to be inserted later.
    op_phi_operands.push_back({SPV_OPERAND_TYPE_ID, {new_result_id}});
    op_phi_operands.push_back({SPV_OPERAND_TYPE_ID, {predecessor_id}});

    // Create a clone of the |inst| to be inserted into the |predecessor_id|.
    std::unique_ptr<opt::Instruction> clone(inst->Clone(ir_context));
    clone->SetResultId(new_result_id);

    fuzzerutil::UpdateModuleIdBound(ir_context, new_result_id);

    // Adjust |clone|'s operands to account for possible dependencies on OpPhi
    // instructions from the same basic block.
    for (uint32_t i = 0; i < clone->NumInOperands(); ++i) {
      auto& operand = clone->GetInOperand(i);
      if (operand.type != SPV_OPERAND_TYPE_ID) {
        // Consider only ids.
        continue;
      }

      const auto* dependency_inst =
          ir_context->get_def_use_mgr()->GetDef(operand.words[0]);
      assert(dependency_inst && "|clone| depends on an invalid id");

      if (ir_context->get_instr_block(dependency_inst->result_id()) !=
          ir_context->cfg()->block(message_.block_id())) {
        // We don't need to adjust anything if |dependency_inst| is from a
        // different block, a global instruction or a function parameter.
        continue;
      }

      assert(dependency_inst->opcode() == SpvOpPhi &&
             "Propagated instruction can depend only on OpPhis from the same "
             "basic block or instructions from different basic blocks");

      auto new_id = GetResultIdFromLabelId(*dependency_inst, predecessor_id);
      assert(new_id && "OpPhi instruction is missing a predecessor");
      operand.words[0] = new_id;
    }

    auto* insert_before_inst = fuzzerutil::GetLastInsertBeforeInstruction(
        ir_context, predecessor_id, clone->opcode());
    assert(insert_before_inst && "Can't insert |clone| into |predecessor_id");

    insert_before_inst->InsertBefore(std::move(clone));
  }

  // Insert an OpPhi instruction into the basic block of |inst|.
  ir_context->get_instr_block(inst)->begin()->InsertBefore(
      MakeUnique<opt::Instruction>(ir_context, SpvOpPhi, inst->type_id(),
                                   inst->result_id(),
                                   std::move(op_phi_operands)));

  // Remove |inst| from the basic block.
  ir_context->KillInst(inst);

  // We have changed the module so most analyzes are now invalid.
  ir_context->InvalidateAnalysesExceptFor(
      opt::IRContext::Analysis::kAnalysisNone);
}

protobufs::Transformation TransformationPropagateInstructionUp::ToMessage()
    const {
  protobufs::Transformation result;
  *result.mutable_propagate_instruction_up() = message_;
  return result;
}

bool TransformationPropagateInstructionUp::IsOpcodeSupported(SpvOp opcode) {
  // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3605):
  //  We only support "simple" instructions that don't work with memory.
  //  We should extend this so that we support the ones that modify the memory
  //  too.
  switch (opcode) {
    case SpvOpUndef:
    case SpvOpAccessChain:
    case SpvOpInBoundsAccessChain:
    case SpvOpArrayLength:
    case SpvOpVectorExtractDynamic:
    case SpvOpVectorInsertDynamic:
    case SpvOpVectorShuffle:
    case SpvOpCompositeConstruct:
    case SpvOpCompositeExtract:
    case SpvOpCompositeInsert:
    case SpvOpCopyObject:
    case SpvOpTranspose:
    case SpvOpConvertFToU:
    case SpvOpConvertFToS:
    case SpvOpConvertSToF:
    case SpvOpConvertUToF:
    case SpvOpUConvert:
    case SpvOpSConvert:
    case SpvOpFConvert:
    case SpvOpQuantizeToF16:
    case SpvOpSatConvertSToU:
    case SpvOpSatConvertUToS:
    case SpvOpBitcast:
    case SpvOpSNegate:
    case SpvOpFNegate:
    case SpvOpIAdd:
    case SpvOpFAdd:
    case SpvOpISub:
    case SpvOpFSub:
    case SpvOpIMul:
    case SpvOpFMul:
    case SpvOpUDiv:
    case SpvOpSDiv:
    case SpvOpFDiv:
    case SpvOpUMod:
    case SpvOpSRem:
    case SpvOpSMod:
    case SpvOpFRem:
    case SpvOpFMod:
    case SpvOpVectorTimesScalar:
    case SpvOpMatrixTimesScalar:
    case SpvOpVectorTimesMatrix:
    case SpvOpMatrixTimesVector:
    case SpvOpMatrixTimesMatrix:
    case SpvOpOuterProduct:
    case SpvOpDot:
    case SpvOpIAddCarry:
    case SpvOpISubBorrow:
    case SpvOpUMulExtended:
    case SpvOpSMulExtended:
    case SpvOpAny:
    case SpvOpAll:
    case SpvOpIsNan:
    case SpvOpIsInf:
    case SpvOpIsFinite:
    case SpvOpIsNormal:
    case SpvOpSignBitSet:
    case SpvOpLessOrGreater:
    case SpvOpOrdered:
    case SpvOpUnordered:
    case SpvOpLogicalEqual:
    case SpvOpLogicalNotEqual:
    case SpvOpLogicalOr:
    case SpvOpLogicalAnd:
    case SpvOpLogicalNot:
    case SpvOpSelect:
    case SpvOpIEqual:
    case SpvOpINotEqual:
    case SpvOpUGreaterThan:
    case SpvOpSGreaterThan:
    case SpvOpUGreaterThanEqual:
    case SpvOpSGreaterThanEqual:
    case SpvOpULessThan:
    case SpvOpSLessThan:
    case SpvOpULessThanEqual:
    case SpvOpSLessThanEqual:
    case SpvOpFOrdEqual:
    case SpvOpFUnordEqual:
    case SpvOpFOrdNotEqual:
    case SpvOpFUnordNotEqual:
    case SpvOpFOrdLessThan:
    case SpvOpFUnordLessThan:
    case SpvOpFOrdGreaterThan:
    case SpvOpFUnordGreaterThan:
    case SpvOpFOrdLessThanEqual:
    case SpvOpFUnordLessThanEqual:
    case SpvOpFOrdGreaterThanEqual:
    case SpvOpFUnordGreaterThanEqual:
    case SpvOpShiftRightLogical:
    case SpvOpShiftRightArithmetic:
    case SpvOpShiftLeftLogical:
    case SpvOpBitwiseOr:
    case SpvOpBitwiseXor:
    case SpvOpBitwiseAnd:
    case SpvOpNot:
    case SpvOpBitFieldInsert:
    case SpvOpBitFieldSExtract:
    case SpvOpBitFieldUExtract:
    case SpvOpBitReverse:
    case SpvOpBitCount:
    case SpvOpCopyLogical:
    case SpvOpPtrEqual:
    case SpvOpPtrNotEqual:
      return true;
    default:
      return false;
  }
}

opt::Instruction*
TransformationPropagateInstructionUp::GetInstructionToPropagate(
    opt::IRContext* ir_context, uint32_t block_id) {
  auto* block = ir_context->cfg()->block(block_id);
  assert(block && "|block_id| is invalid");

  for (auto& inst : *block) {
    // We look for the first instruction in the block that satisfies the
    // following rules:
    // - it's not an OpPhi
    // - it must be supported by this transformation
    // - it may depend only on instructions from different basic blocks or on
    //   OpPhi instructions from the same basic block.
    if (inst.opcode() == SpvOpPhi || !IsOpcodeSupported(inst.opcode()) ||
        !inst.type_id() || !inst.result_id()) {
      continue;
    }

    const auto* inst_type = ir_context->get_type_mgr()->GetType(inst.type_id());
    assert(inst_type && "|inst| has invalid type");

    if (!ir_context->get_feature_mgr()->HasCapability(
            SpvCapabilityVariablePointersStorageBuffer) &&
        ContainsPointers(*inst_type)) {
      // OpPhi supports pointer operands only with VariablePointers or
      // VariablePointersStorageBuffer capabilities.
      //
      // Note that VariablePointers capability implicitly declares
      // VariablePointersStorageBuffer capability.
      continue;
    }

    if (!HasValidDependencies(ir_context, &inst)) {
      continue;
    }

    return &inst;
  }

  return nullptr;
}

bool TransformationPropagateInstructionUp::IsApplicableToBlock(
    opt::IRContext* ir_context, uint32_t block_id) {
  // Check that |block_id| is valid.
  const auto* label_inst = ir_context->get_def_use_mgr()->GetDef(block_id);
  if (!label_inst || label_inst->opcode() != SpvOpLabel) {
    return false;
  }

  // Check that |block| has predecessors.
  const auto& predecessors = ir_context->cfg()->preds(block_id);
  if (predecessors.empty()) {
    return false;
  }

  // The block must contain an instruction to propagate.
  const auto* inst_to_propagate =
      GetInstructionToPropagate(ir_context, block_id);
  if (!inst_to_propagate) {
    return false;
  }

  // We should be able to insert |inst_to_propagate| into every predecessor of
  // |block|.
  return std::all_of(predecessors.begin(), predecessors.end(),
                     [ir_context, inst_to_propagate](uint32_t predecessor_id) {
                       return fuzzerutil::GetLastInsertBeforeInstruction(
                                  ir_context, predecessor_id,
                                  inst_to_propagate->opcode()) != nullptr;
                     });
}

std::unordered_set<uint32_t> TransformationPropagateInstructionUp::GetFreshIds()
    const {
  std::unordered_set<uint32_t> result;
  for (auto& pair : message_.predecessor_id_to_fresh_id()) {
    result.insert(pair.second());
  }
  return result;
}

}  // namespace fuzz
}  // namespace spvtools
