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

void SimplificationPass::AddNewOperands(
    Instruction* folded_inst, std::unordered_set<Instruction*>* inst_seen,
    std::vector<Instruction*>* work_list) {
  analysis::DefUseManager* def_use_mgr = get_def_use_mgr();
  folded_inst->ForEachInId(
      [&inst_seen, &def_use_mgr, &work_list](uint32_t* iid) {
        Instruction* iid_inst = def_use_mgr->GetDef(*iid);
        if (!inst_seen->insert(iid_inst).second) return;
        work_list->push_back(iid_inst);
      });
}

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;
  std::unordered_set<Instruction*> inst_seen;
  const InstructionFolder& folder = context()->get_instruction_folder();

  cfg()->ForEachBlockInReversePostOrder(
      function->entry().get(),
      [&modified, &process_phis, &work_list, &in_work_list, &inst_to_kill,
       &folder, &inst_seen, this](BasicBlock* bb) {
        for (Instruction* inst = &*bb->begin(); inst; inst = inst->NextNode()) {
          inst_seen.insert(inst);
          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);
              }
            });

            AddNewOperands(inst, &inst_seen, &work_list);

            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);
    inst_seen.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, &in_work_list](Instruction* use) {
            if (!use->IsDecoration() && use->opcode() != SpvOpName &&
                in_work_list.insert(use).second) {
              work_list.push_back(use);
            }
          });

      AddNewOperands(inst, &inst_seen, &work_list);

      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
