// 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(
    protobufs::TransformationPushIdThroughVariable message)
    : message_(std::move(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 (!ir_context->IsReachable(*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());

  opt::Instruction* insert_before =
      FindInstruction(message_.instruction_descriptor(), ir_context);
  opt::BasicBlock* enclosing_block = ir_context->get_instr_block(insert_before);

  // 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) {
    opt::Instruction* global_variable = fuzzerutil::AddGlobalVariable(
        ir_context, message_.variable_id(), pointer_type_id,
        SpvStorageClassPrivate, message_.initializer_id());
    ir_context->get_def_use_mgr()->AnalyzeInstDefUse(global_variable);
  } else {
    opt::Function* function =
        ir_context
            ->get_instr_block(
                FindInstruction(message_.instruction_descriptor(), ir_context))
            ->GetParent();
    opt::Instruction* local_variable = fuzzerutil::AddLocalVariable(
        ir_context, message_.variable_id(), pointer_type_id,
        function->result_id(), message_.initializer_id());
    ir_context->get_def_use_mgr()->AnalyzeInstDefUse(local_variable);
    ir_context->set_instr_block(local_variable, &*function->entry());
  }

  // 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());
  opt::Instruction* load_instruction =
      insert_before->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()}}})));
  opt::Instruction* store_instruction =
      load_instruction->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->get_def_use_mgr()->AnalyzeInstDefUse(store_instruction);
  ir_context->set_instr_block(store_instruction, enclosing_block);
  ir_context->get_def_use_mgr()->AnalyzeInstDefUse(load_instruction);
  ir_context->set_instr_block(load_instruction, enclosing_block);

  // 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
