// Copyright (c) 2018 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/opt/simplification_pass.h"

#include <set>
#include <unordered_set>
#include <vector>

#include "source/opt/fold.h"

namespace spvtools {
namespace opt {

Pass::Status SimplificationPass::Process() {
  bool modified = false;

  for (Function& function : *get_module()) {
    modified |= SimplifyFunction(&function);
  }
  return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
}

bool SimplificationPass::SimplifyFunction(Function* function) {
  bool modified = false;
  // Phase 1: Traverse all instructions in dominance order.
  // The second phase will only be on the instructions whose inputs have changed
  // after being processed during phase 1.  Since OpPhi instructions are the
  // only instructions whose inputs do not necessarily dominate the use, we keep
  // track of the OpPhi instructions already seen, and add them to the work list
  // for phase 2 when needed.
  std::vector<Instruction*> work_list;
  std::unordered_set<Instruction*> process_phis;
  std::unordered_set<Instruction*> inst_to_kill;
  std::unordered_set<Instruction*> in_work_list;
  const InstructionFolder& folder = context()->get_instruction_folder();

  cfg()->ForEachBlockInReversePostOrder(
      function->entry().get(),
      [&modified, &process_phis, &work_list, &in_work_list, &inst_to_kill,
       folder, this](BasicBlock* bb) {
        for (Instruction* inst = &*bb->begin(); inst; inst = inst->NextNode()) {
          if (inst->opcode() == SpvOpPhi) {
            process_phis.insert(inst);
          }

          bool is_foldable_copy =
              inst->opcode() == SpvOpCopyObject &&
              context()->get_decoration_mgr()->HaveSubsetOfDecorations(
                  inst->result_id(), inst->GetSingleWordInOperand(0));

          if (is_foldable_copy || folder.FoldInstruction(inst)) {
            modified = true;
            context()->AnalyzeUses(inst);
            get_def_use_mgr()->ForEachUser(inst, [&work_list, &process_phis,
                                                  &in_work_list](
                                                     Instruction* use) {
              if (process_phis.count(use) && in_work_list.insert(use).second) {
                work_list.push_back(use);
              }
            });
            if (inst->opcode() == SpvOpCopyObject) {
              context()->ReplaceAllUsesWithPredicate(
                  inst->result_id(), inst->GetSingleWordInOperand(0),
                  [](Instruction* user, uint32_t) {
                    const auto opcode = user->opcode();
                    if (!spvOpcodeIsDebug(opcode) &&
                        !spvOpcodeIsDecoration(opcode)) {
                      return true;
                    }
                    return false;
                  });
              inst_to_kill.insert(inst);
              in_work_list.insert(inst);
            } else if (inst->opcode() == SpvOpNop) {
              inst_to_kill.insert(inst);
              in_work_list.insert(inst);
            }
          }
        }
      });

  // Phase 2: process the instructions in the work list until all of the work is
  //          done.  This time we add all users to the work list because phase 1
  //          has already finished.
  for (size_t i = 0; i < work_list.size(); ++i) {
    Instruction* inst = work_list[i];
    in_work_list.erase(inst);

    bool is_foldable_copy =
        inst->opcode() == SpvOpCopyObject &&
        context()->get_decoration_mgr()->HaveSubsetOfDecorations(
            inst->result_id(), inst->GetSingleWordInOperand(0));

    if (is_foldable_copy || folder.FoldInstruction(inst)) {
      modified = true;
      context()->AnalyzeUses(inst);
      get_def_use_mgr()->ForEachUser(
          inst, [&work_list, &in_work_list](Instruction* use) {
            if (!use->IsDecoration() && use->opcode() != SpvOpName &&
                in_work_list.insert(use).second) {
              work_list.push_back(use);
            }
          });

      if (inst->opcode() == SpvOpCopyObject) {
        context()->ReplaceAllUsesWithPredicate(
            inst->result_id(), inst->GetSingleWordInOperand(0),
            [](Instruction* user, uint32_t) {
              const auto opcode = user->opcode();
              if (!spvOpcodeIsDebug(opcode) && !spvOpcodeIsDecoration(opcode)) {
                return true;
              }
              return false;
            });
        inst_to_kill.insert(inst);
        in_work_list.insert(inst);
      } else if (inst->opcode() == SpvOpNop) {
        inst_to_kill.insert(inst);
        in_work_list.insert(inst);
      }
    }
  }

  // Phase 3: Kill instructions we know are no longer needed.
  for (Instruction* inst : inst_to_kill) {
    context()->KillInst(inst);
  }

  return modified;
}

}  // namespace opt
}  // namespace spvtools
