// 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& transformation_context) 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;
  }

  // |value_id| may not be an irrelevant id.
  if (transformation_context.GetFactManager()->IdIsIrrelevant(
          message_.value_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);

  // 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(), {}), ir_context);
}

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

}  // namespace fuzz
}  // namespace spvtools
