// Copyright (c) 2020 André Perez Maselco
//
// 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_push_id_through_variable.h"

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

namespace spvtools {
namespace fuzz {

TransformationPushIdThroughVariable::TransformationPushIdThroughVariable(
    const spvtools::fuzz::protobufs::TransformationPushIdThroughVariable&
        message)
    : message_(message) {}

TransformationPushIdThroughVariable::TransformationPushIdThroughVariable(
    uint32_t value_id, uint32_t value_synonym_id, uint32_t variable_id,
    uint32_t variable_storage_class, uint32_t initializer_id,
    const protobufs::InstructionDescriptor& instruction_descriptor) {
  message_.set_value_id(value_id);
  message_.set_value_synonym_id(value_synonym_id);
  message_.set_variable_id(variable_id);
  message_.set_variable_storage_class(variable_storage_class);
  message_.set_initializer_id(initializer_id);
  *message_.mutable_instruction_descriptor() = instruction_descriptor;
}

bool TransformationPushIdThroughVariable::IsApplicable(
    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
  // |message_.value_synonym_id| and |message_.variable_id| must be fresh.
  if (!fuzzerutil::IsFreshId(ir_context, message_.value_synonym_id()) ||
      !fuzzerutil::IsFreshId(ir_context, message_.variable_id())) {
    return false;
  }

  // The instruction to insert before must be defined.
  auto instruction_to_insert_before =
      FindInstruction(message_.instruction_descriptor(), ir_context);
  if (!instruction_to_insert_before) {
    return false;
  }

  // It must be valid to insert the OpStore and OpLoad instruction before it.
  if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
          SpvOpStore, instruction_to_insert_before) ||
      !fuzzerutil::CanInsertOpcodeBeforeInstruction(
          SpvOpLoad, instruction_to_insert_before)) {
    return false;
  }

  // The instruction to insert before must belong to a reachable block.
  auto basic_block = ir_context->get_instr_block(instruction_to_insert_before);
  if (!fuzzerutil::BlockIsReachableInItsFunction(ir_context, basic_block)) {
    return false;
  }

  // The value instruction must be defined and have a type.
  auto value_instruction =
      ir_context->get_def_use_mgr()->GetDef(message_.value_id());
  if (!value_instruction || !value_instruction->type_id()) {
    return false;
  }

  // A pointer type instruction pointing to the value type must be defined.
  auto pointer_type_id = fuzzerutil::MaybeGetPointerType(
      ir_context, value_instruction->type_id(),
      static_cast<SpvStorageClass>(message_.variable_storage_class()));
  if (!pointer_type_id) {
    return false;
  }

  // |message_.variable_storage_class| must be private or function.
  assert((message_.variable_storage_class() == SpvStorageClassPrivate ||
          message_.variable_storage_class() == SpvStorageClassFunction) &&
         "The variable storage class must be private or function.");

  // Check that initializer is valid.
  const auto* constant_inst =
      ir_context->get_def_use_mgr()->GetDef(message_.initializer_id());
  if (!constant_inst || !spvOpcodeIsConstant(constant_inst->opcode()) ||
      value_instruction->type_id() != constant_inst->type_id()) {
    return false;
  }

  // |message_.value_id| must be available at the insertion point.
  return fuzzerutil::IdIsAvailableBeforeInstruction(
      ir_context, instruction_to_insert_before, message_.value_id());
}

void TransformationPushIdThroughVariable::Apply(
    opt::IRContext* ir_context,
    TransformationContext* transformation_context) const {
  auto value_instruction =
      ir_context->get_def_use_mgr()->GetDef(message_.value_id());

  // A pointer type instruction pointing to the value type must be defined.
  auto pointer_type_id = fuzzerutil::MaybeGetPointerType(
      ir_context, value_instruction->type_id(),
      static_cast<SpvStorageClass>(message_.variable_storage_class()));
  assert(pointer_type_id && "The required pointer type must be available.");

  // Adds whether a global or local variable.
  if (message_.variable_storage_class() == SpvStorageClassPrivate) {
    fuzzerutil::AddGlobalVariable(ir_context, message_.variable_id(),
                                  pointer_type_id, SpvStorageClassPrivate,
                                  message_.initializer_id());
  } else {
    auto function_id = ir_context
                           ->get_instr_block(FindInstruction(
                               message_.instruction_descriptor(), ir_context))
                           ->GetParent()
                           ->result_id();
    fuzzerutil::AddLocalVariable(ir_context, message_.variable_id(),
                                 pointer_type_id, function_id,
                                 message_.initializer_id());
  }

  // First, insert the OpLoad instruction before |instruction_descriptor| and
  // then insert the OpStore instruction before the OpLoad instruction.
  fuzzerutil::UpdateModuleIdBound(ir_context, message_.value_synonym_id());
  FindInstruction(message_.instruction_descriptor(), ir_context)
      ->InsertBefore(MakeUnique<opt::Instruction>(
          ir_context, SpvOpLoad, value_instruction->type_id(),
          message_.value_synonym_id(),
          opt::Instruction::OperandList(
              {{SPV_OPERAND_TYPE_ID, {message_.variable_id()}}})))
      ->InsertBefore(MakeUnique<opt::Instruction>(
          ir_context, SpvOpStore, 0, 0,
          opt::Instruction::OperandList(
              {{SPV_OPERAND_TYPE_ID, {message_.variable_id()}},
               {SPV_OPERAND_TYPE_ID, {message_.value_id()}}})));

  ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);

  // We should be able to create a synonym of |value_id| if it's not irrelevant.
  if (fuzzerutil::CanMakeSynonymOf(ir_context, *transformation_context,
                                   value_instruction) &&
      !transformation_context->GetFactManager()->IdIsIrrelevant(
          message_.value_synonym_id())) {
    // Adds the fact that |message_.value_synonym_id|
    // and |message_.value_id| are synonymous.
    transformation_context->GetFactManager()->AddFactDataSynonym(
        MakeDataDescriptor(message_.value_synonym_id(), {}),
        MakeDataDescriptor(message_.value_id(), {}));
  }
}

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

std::unordered_set<uint32_t> TransformationPushIdThroughVariable::GetFreshIds()
    const {
  return {message_.value_synonym_id(), message_.variable_id()};
}

}  // namespace fuzz
}  // namespace spvtools
