// Copyright (c) 2020 Vasyl Teliman
//
// 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.

#ifndef SOURCE_FUZZ_TRANSFORMATION_MOVE_INSTRUCTION_DOWN_H_
#define SOURCE_FUZZ_TRANSFORMATION_MOVE_INSTRUCTION_DOWN_H_

#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h"
#include "source/fuzz/transformation_context.h"
#include "source/opt/ir_context.h"

namespace spvtools {
namespace fuzz {

class TransformationMoveInstructionDown : public Transformation {
 public:
  explicit TransformationMoveInstructionDown(
      const protobufs::TransformationMoveInstructionDown& message);

  explicit TransformationMoveInstructionDown(
      const protobufs::InstructionDescriptor& instruction);

  // - |instruction| should be a descriptor of a valid instruction in the module
  // - |instruction|'s opcode should be supported by this transformation
  // - neither |instruction| nor its successor may be the last instruction in
  //   the block
  // - |instruction|'s successor may not be dependent on the |instruction|
  // - it should be possible to insert |instruction|'s opcode after its
  //   successor
  bool IsApplicable(
      opt::IRContext* ir_context,
      const TransformationContext& transformation_context) const override;

  // Swaps |instruction| with its successor.
  void Apply(opt::IRContext* ir_context,
             TransformationContext* transformation_context) const override;

  protobufs::Transformation ToMessage() const override;

 private:
  // Returns true if the |inst| is supported by this transformation.
  static bool IsInstructionSupported(opt::IRContext* ir_context,
                                     const opt::Instruction& inst);

  // Returns true if |inst| represents a "simple" instruction. That is, it
  // neither reads from nor writes to the memory and is not a barrier.
  static bool IsSimpleInstruction(opt::IRContext* ir_context,
                                  const opt::Instruction& inst);

  // Returns true if |inst| reads from memory.
  static bool IsMemoryReadInstruction(opt::IRContext* ir_context,
                                      const opt::Instruction& inst);

  // Returns id being used by |inst| to read from. |inst| must be a memory read
  // instruction (see IsMemoryReadInstruction). Returned id is not guaranteed to
  // have pointer type.
  static uint32_t GetMemoryReadTarget(opt::IRContext* ir_context,
                                      const opt::Instruction& inst);

  // Returns true if |inst| that writes to the memory.
  static bool IsMemoryWriteInstruction(opt::IRContext* ir_context,
                                       const opt::Instruction& inst);

  // Returns id being used by |inst| to write into. |inst| must be a memory
  // write instruction (see IsMemoryWriteInstruction). Returned id is not
  // guaranteed to have pointer type.
  static uint32_t GetMemoryWriteTarget(opt::IRContext* ir_context,
                                       const opt::Instruction& inst);

  // Returns true if |inst| either reads from or writes to the memory
  // (see IsMemoryReadInstruction and IsMemoryWriteInstruction accordingly).
  static bool IsMemoryInstruction(opt::IRContext* ir_context,
                                  const opt::Instruction& inst);

  // Returns true if |inst| is a barrier instruction.
  static bool IsBarrierInstruction(const opt::Instruction& inst);

  // Returns true if it is possible to swap |a| and |b| without changing the
  // module's semantics. |a| and |b| are required to be supported instructions
  // (see IsInstructionSupported). In particular, if either |a| or |b| are
  // memory or barrier instructions, some checks are used to only say that they
  // can be swapped if the swap is definitely semantics-preserving.
  static bool CanSafelySwapInstructions(opt::IRContext* ir_context,
                                        const opt::Instruction& a,
                                        const opt::Instruction& b,
                                        const FactManager& fact_manager);

  protobufs::TransformationMoveInstructionDown message_;
};

}  // namespace fuzz
}  // namespace spvtools

#endif  // SOURCE_FUZZ_TRANSFORMATION_MOVE_INSTRUCTION_DOWN_H_
