// 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_add_spec_constant_op.h"

#include <utility>

#include "source/fuzz/fuzzer_util.h"

namespace spvtools {
namespace fuzz {

TransformationAddSpecConstantOp::TransformationAddSpecConstantOp(
    spvtools::fuzz::protobufs::TransformationAddSpecConstantOp message)
    : message_(std::move(message)) {}

TransformationAddSpecConstantOp::TransformationAddSpecConstantOp(
    uint32_t fresh_id, uint32_t type_id, SpvOp opcode,
    const opt::Instruction::OperandList& operands) {
  message_.set_fresh_id(fresh_id);
  message_.set_type_id(type_id);
  message_.set_opcode(opcode);
  for (const auto& operand : operands) {
    auto* op = message_.add_operand();
    op->set_operand_type(operand.type);
    for (auto word : operand.words) {
      op->add_operand_data(word);
    }
  }
}

bool TransformationAddSpecConstantOp::IsApplicable(
    opt::IRContext* ir_context,
    const TransformationContext& transformation_context) const {
  auto clone = fuzzerutil::CloneIRContext(ir_context);
  ApplyImpl(clone.get());
  return fuzzerutil::IsValid(clone.get(),
                             transformation_context.GetValidatorOptions());
}

void TransformationAddSpecConstantOp::Apply(
    opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
  ApplyImpl(ir_context);
  ir_context->InvalidateAnalysesExceptFor(
      opt::IRContext::Analysis::kAnalysisNone);
}

void TransformationAddSpecConstantOp::ApplyImpl(
    opt::IRContext* ir_context) const {
  opt::Instruction::OperandList operands = {
      {SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER, {message_.opcode()}}};

  for (const auto& operand : message_.operand()) {
    std::vector<uint32_t> words(operand.operand_data().begin(),
                                operand.operand_data().end());
    operands.push_back({static_cast<spv_operand_type_t>(operand.operand_type()),
                        std::move(words)});
  }

  ir_context->AddGlobalValue(MakeUnique<opt::Instruction>(
      ir_context, SpvOpSpecConstantOp, message_.type_id(), message_.fresh_id(),
      std::move(operands)));

  fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
}

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

std::unordered_set<uint32_t> TransformationAddSpecConstantOp::GetFreshIds()
    const {
  return {message_.fresh_id()};
}

}  // namespace fuzz
}  // namespace spvtools
