// Copyright (c) 2019 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/transformation_add_dead_continue.h"

#include "source/fuzz/fuzzer_util.h"

namespace spvtools {
namespace fuzz {

TransformationAddDeadContinue::TransformationAddDeadContinue(
    const spvtools::fuzz::protobufs::TransformationAddDeadContinue& message)
    : message_(message) {}

TransformationAddDeadContinue::TransformationAddDeadContinue(
    uint32_t from_block, bool continue_condition_value,
    std::vector<uint32_t> phi_id) {
  message_.set_from_block(from_block);
  message_.set_continue_condition_value(continue_condition_value);
  for (auto id : phi_id) {
    message_.add_phi_id(id);
  }
}

bool TransformationAddDeadContinue::IsApplicable(
    opt::IRContext* ir_context,
    const TransformationContext& transformation_context) const {
  // First, we check that a constant with the same value as
  // |message_.continue_condition_value| is present.
  if (!fuzzerutil::MaybeGetBoolConstant(ir_context, transformation_context,
                                        message_.continue_condition_value())) {
    // The required constant is not present, so the transformation cannot be
    // applied.
    return false;
  }

  // Check that |message_.from_block| really is a block id.
  opt::BasicBlock* bb_from =
      fuzzerutil::MaybeFindBlock(ir_context, message_.from_block());
  if (bb_from == nullptr) {
    return false;
  }

  // Check that |message_.from_block| ends with an unconditional branch.
  if (bb_from->terminator()->opcode() != SpvOpBranch) {
    // The block associated with the id does not end with an unconditional
    // branch.
    return false;
  }

  assert(bb_from != nullptr &&
         "We should have found a block if this line of code is reached.");
  assert(
      bb_from->id() == message_.from_block() &&
      "The id of the block we found should match the source id for the break.");

  // Get the header for the innermost loop containing |message_.from_block|.
  // Because the structured CFG analysis does not regard a loop header as part
  // of the loop it heads, we check first whether bb_from is a loop header
  // before using the structured CFG analysis.
  auto loop_header =
      bb_from->IsLoopHeader()
          ? message_.from_block()
          : ir_context->GetStructuredCFGAnalysis()->ContainingLoop(
                message_.from_block());
  if (!loop_header) {
    return false;
  }

  auto continue_block =
      ir_context->cfg()->block(loop_header)->ContinueBlockId();

  if (!fuzzerutil::BlockIsReachableInItsFunction(
          ir_context, ir_context->cfg()->block(continue_block))) {
    // If the loop's continue block is unreachable, we conservatively do not
    // allow adding a dead continue, to avoid the compilations that arise due to
    // the lack of sensible dominance information for unreachable blocks.
    return false;
  }

  if (fuzzerutil::BlockIsInLoopContinueConstruct(
          ir_context, message_.from_block(), loop_header)) {
    // We cannot jump to the continue target from the continue construct.
    return false;
  }

  if (ir_context->GetStructuredCFGAnalysis()->IsMergeBlock(continue_block)) {
    // A branch straight to the continue target that is also a merge block might
    // break the property that a construct header must dominate its merge block
    // (if the merge block is reachable).
    return false;
  }

  // Check whether the data passed to extend OpPhi instructions is appropriate.
  if (!fuzzerutil::PhiIdsOkForNewEdge(ir_context, bb_from,
                                      ir_context->cfg()->block(continue_block),
                                      message_.phi_id())) {
    return false;
  }

  // Adding the dead break is only valid if SPIR-V rules related to dominance
  // hold.  Rather than checking these rules explicitly, we defer to the
  // validator.  We make a clone of the module, apply the transformation to the
  // clone, and check whether the transformed clone is valid.
  //
  // In principle some of the above checks could be removed, with more reliance
  // being placed on the validator.  This should be revisited if we are sure
  // the validator is complete with respect to checking structured control flow
  // rules.
  auto cloned_context = fuzzerutil::CloneIRContext(ir_context);
  ApplyImpl(cloned_context.get(), transformation_context);
  return fuzzerutil::IsValid(cloned_context.get(),
                             transformation_context.GetValidatorOptions());
}

void TransformationAddDeadContinue::Apply(
    opt::IRContext* ir_context,
    TransformationContext* transformation_context) const {
  ApplyImpl(ir_context, *transformation_context);
  // Invalidate all analyses
  ir_context->InvalidateAnalysesExceptFor(
      opt::IRContext::Analysis::kAnalysisNone);
}

protobufs::Transformation TransformationAddDeadContinue::ToMessage() const {
  protobufs::Transformation result;
  *result.mutable_add_dead_continue() = message_;
  return result;
}

void TransformationAddDeadContinue::ApplyImpl(
    spvtools::opt::IRContext* ir_context,
    const TransformationContext& transformation_context) const {
  auto bb_from = ir_context->cfg()->block(message_.from_block());
  auto continue_block =
      bb_from->IsLoopHeader()
          ? bb_from->ContinueBlockId()
          : ir_context->GetStructuredCFGAnalysis()->LoopContinueBlock(
                message_.from_block());
  assert(continue_block && "message_.from_block must be in a loop.");
  fuzzerutil::AddUnreachableEdgeAndUpdateOpPhis(
      ir_context, bb_from, ir_context->cfg()->block(continue_block),
      fuzzerutil::MaybeGetBoolConstant(ir_context, transformation_context,
                                       message_.continue_condition_value()),
      message_.phi_id());
}

}  // namespace fuzz
}  // namespace spvtools
