// Copyright (c) 2018 Google Inc.
//
// 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/reduce/remove_unused_instruction_reduction_opportunity_finder.h"

#include "source/opcode.h"
#include "source/opt/instruction.h"
#include "source/reduce/remove_instruction_reduction_opportunity.h"

namespace spvtools {
namespace reduce {

RemoveUnusedInstructionReductionOpportunityFinder::
    RemoveUnusedInstructionReductionOpportunityFinder(
        bool remove_constants_and_undefs)
    : remove_constants_and_undefs_(remove_constants_and_undefs) {}

std::vector<std::unique_ptr<ReductionOpportunity>>
RemoveUnusedInstructionReductionOpportunityFinder::GetAvailableOpportunities(
    opt::IRContext* context) const {
  std::vector<std::unique_ptr<ReductionOpportunity>> result;

  for (auto& inst : context->module()->debugs1()) {
    if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
      continue;
    }
    result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
  }

  for (auto& inst : context->module()->debugs2()) {
    if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
      continue;
    }
    result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
  }

  for (auto& inst : context->module()->debugs3()) {
    if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
      continue;
    }
    result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
  }

  for (auto& inst : context->module()->ext_inst_debuginfo()) {
    if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
      continue;
    }
    result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
  }

  for (auto& inst : context->module()->types_values()) {
    if (!remove_constants_and_undefs_ &&
        spvOpcodeIsConstantOrUndef(inst.opcode())) {
      continue;
    }
    if (!OnlyReferencedByIntimateDecorationOrEntryPointInterface(context,
                                                                 inst)) {
      continue;
    }
    result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
  }

  for (auto& inst : context->module()->annotations()) {
    if (context->get_def_use_mgr()->NumUsers(&inst) > 0) {
      continue;
    }
    if (!IsIndependentlyRemovableDecoration(inst)) {
      continue;
    }
    result.push_back(MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
  }

  for (auto& function : *context->module()) {
    for (auto& block : function) {
      for (auto& inst : block) {
        if (context->get_def_use_mgr()->NumUses(&inst) > 0) {
          continue;
        }
        if (!remove_constants_and_undefs_ &&
            spvOpcodeIsConstantOrUndef(inst.opcode())) {
          continue;
        }
        if (spvOpcodeIsBlockTerminator(inst.opcode()) ||
            inst.opcode() == SpvOpSelectionMerge ||
            inst.opcode() == SpvOpLoopMerge) {
          // In this reduction pass we do not want to affect static
          // control flow.
          continue;
        }
        // Given that we're in a block, we should only get here if
        // the instruction is not directly related to control flow;
        // i.e., it's some straightforward instruction with an
        // unused result, like an arithmetic operation or function
        // call.
        result.push_back(
            MakeUnique<RemoveInstructionReductionOpportunity>(&inst));
      }
    }
  }
  return result;
}

std::string RemoveUnusedInstructionReductionOpportunityFinder::GetName() const {
  return "RemoveUnusedInstructionReductionOpportunityFinder";
}

bool RemoveUnusedInstructionReductionOpportunityFinder::
    OnlyReferencedByIntimateDecorationOrEntryPointInterface(
        opt::IRContext* context, const opt::Instruction& inst) const {
  return context->get_def_use_mgr()->WhileEachUse(
      &inst, [this](opt::Instruction* user, uint32_t use_index) -> bool {
        return (user->IsDecoration() &&
                !IsIndependentlyRemovableDecoration(*user)) ||
               (user->opcode() == SpvOpEntryPoint && use_index > 2);
      });
}

bool RemoveUnusedInstructionReductionOpportunityFinder::
    IsIndependentlyRemovableDecoration(const opt::Instruction& inst) const {
  uint32_t decoration;
  switch (inst.opcode()) {
    case SpvOpDecorate:
    case SpvOpDecorateId:
    case SpvOpDecorateString:
      decoration = inst.GetSingleWordInOperand(1u);
      break;
    case SpvOpMemberDecorate:
    case SpvOpMemberDecorateString:
      decoration = inst.GetSingleWordInOperand(2u);
      break;
    default:
      // The instruction is not a decoration.  It is legitimate for this to be
      // reached: it allows the method to be invoked on arbitrary instructions.
      return false;
  }

  // We conservatively only remove specific decorations that we believe will
  // not change the shader interface, will not make the shader invalid, will
  // actually be found in practice, etc.

  switch (decoration) {
    case SpvDecorationRelaxedPrecision:
    case SpvDecorationNoSignedWrap:
    case SpvDecorationNoContraction:
    case SpvDecorationNoUnsignedWrap:
    case SpvDecorationUserSemantic:
      return true;
    default:
      return false;
  }
}

}  // namespace reduce
}  // namespace spvtools
