// Copyright (c) 2020 Google LLC
//
// 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/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.h"

#include "source/fuzz/transformation_replace_opphi_id_from_dead_predecessor.h"

namespace spvtools {
namespace fuzz {

FuzzerPassReplaceOpPhiIdsFromDeadPredecessors::
    FuzzerPassReplaceOpPhiIdsFromDeadPredecessors(
        opt::IRContext* ir_context,
        TransformationContext* transformation_context,
        FuzzerContext* fuzzer_context,
        protobufs::TransformationSequence* transformations)
    : FuzzerPass(ir_context, transformation_context, fuzzer_context,
                 transformations) {}

FuzzerPassReplaceOpPhiIdsFromDeadPredecessors::
    ~FuzzerPassReplaceOpPhiIdsFromDeadPredecessors() = default;

void FuzzerPassReplaceOpPhiIdsFromDeadPredecessors::Apply() {
  // Keep a vector of the transformations to apply.
  std::vector<TransformationReplaceOpPhiIdFromDeadPredecessor> transformations;

  // Loop through the blocks in the module.
  for (auto& function : *GetIRContext()->module()) {
    for (auto& block : function) {
      // Only consider dead blocks.
      if (!GetTransformationContext()->GetFactManager()->BlockIsDead(
              block.id())) {
        continue;
      }

      // Find all the uses of the label id of the block inside OpPhi
      // instructions.
      GetIRContext()->get_def_use_mgr()->ForEachUse(
          block.id(), [this, &function, &block, &transformations](
                          opt::Instruction* instruction, uint32_t) {
            // Only consider OpPhi instructions.
            if (instruction->opcode() != SpvOpPhi) {
              return;
            }

            // Randomly decide whether to consider this use.
            if (!GetFuzzerContext()->ChoosePercentage(
                    GetFuzzerContext()
                        ->GetChanceOfReplacingOpPhiIdFromDeadPredecessor())) {
              return;
            }

            // Get the current id corresponding to the predecessor.
            uint32_t current_id = 0;
            for (uint32_t i = 1; i < instruction->NumInOperands(); i += 2) {
              if (instruction->GetSingleWordInOperand(i) == block.id()) {
                // The corresponding id is at the index of the block - 1.
                current_id = instruction->GetSingleWordInOperand(i - 1);
                break;
              }
            }
            assert(current_id != 0 &&
                   "The predecessor - and corresponding id - should always be "
                   "found.");

            uint32_t type_id = instruction->type_id();

            // Find all the suitable instructions to replace the id.
            const auto& candidates = FindAvailableInstructions(
                &function, &block, block.end(),
                [type_id, current_id](opt::IRContext* /* unused */,
                                      opt::Instruction* candidate) -> bool {
                  // Only consider instructions with a result id different from
                  // the currently-used one, and with the right type.
                  return candidate->HasResultId() &&
                         candidate->type_id() == type_id &&
                         candidate->result_id() != current_id;
                });

            // If there is no possible replacement, we cannot apply any
            // transformation.
            if (candidates.empty()) {
              return;
            }

            // Choose one of the candidates.
            uint32_t replacement_id =
                candidates[GetFuzzerContext()->RandomIndex(candidates)]
                    ->result_id();

            // Add a new transformation to the list of transformations to apply.
            transformations.emplace_back(
                TransformationReplaceOpPhiIdFromDeadPredecessor(
                    instruction->result_id(), block.id(), replacement_id));
          });
    }
  }

  // Apply all the transformations.
  for (const auto& transformation : transformations) {
    ApplyTransformation(transformation);
  }
}

}  // namespace fuzz
}  // namespace spvtools
