// 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.

// This file is specifically named spvtools_fuzz.proto so that the string
// 'spvtools_fuzz' appears in the names of global-scope symbols that protoc
// generates when targeting C++.  This is to reduce the potential for name
// clashes with other globally-scoped symbols.

syntax = "proto3";

package spvtools.fuzz.protobufs;

message FactSequence {
  repeated Fact fact = 1;
}

message Fact {
  // Currently there are no facts.
}

message TransformationSequence {
  repeated Transformation transformation = 1;
}

message Transformation {
  oneof transformation {
    // Order the transformation options by numeric id (rather than
    // alphabetically).
    TransformationMoveBlockDown move_block_down = 1;
    TransformationSplitBlock split_block = 2;
    TransformationAddConstantBoolean add_constant_boolean = 3;
    TransformationAddConstantScalar add_constant_scalar = 4;
    TransformationAddTypeBoolean add_type_boolean = 5;
    TransformationAddTypeFloat add_type_float = 6;
    TransformationAddTypeInt add_type_int = 7;
    TransformationAddDeadBreak add_dead_break = 8;
    // Add additional option using the next available number.
  }
}

// Keep transformation message types in alphabetical order:

message TransformationAddConstantBoolean {

  // Supports adding the constants true and false to a module, which may be
  // necessary in order to enable other transformations if they are not present.

  uint32 fresh_id = 1;
  bool is_true = 2;

}

message TransformationAddConstantScalar {

  // Adds a constant of the given scalar type

  // Id for the constant
  uint32 fresh_id = 1;

  // Id for the scalar type of the constant
  uint32 type_id = 2;

  // Value of the constant
  repeated uint32 word = 3;

}

message TransformationAddDeadBreak {

  // A transformation that turns a basic block that unconditionally branches to
  // its successor into a block that potentially breaks out of a structured
  // control flow construct, but in such a manner that the break cannot actually
  // be taken.

  // The block to break from
  uint32 from_block = 1;

  // The merge block to break to
  uint32 to_block = 2;

  // Determines whether the break condition is true or false
  bool break_condition_value = 3;

  // A sequence of ids suitable for extending OpPhi instructions as a result of
  // the new break edge
  repeated uint32 phi_id = 4;

}

message TransformationAddTypeBoolean {

  // Adds OpTypeBool to the module

  // Id to be used for the type
  uint32 fresh_id = 1;

}

message TransformationAddTypeFloat {

  // Adds OpTypeFloat to the module with the given width

  // Id to be used for the type
  uint32 fresh_id = 1;

  // Floating-point width
  uint32 width = 2;

}

message TransformationAddTypeInt {

  // Adds OpTypeInt to the module with the given width and signedness

  // Id to be used for the type
  uint32 fresh_id = 1;

  // Integer width
  uint32 width = 2;

  // True if and only if this is a signed type
  bool is_signed = 3;

}

message TransformationMoveBlockDown {

  // A transformation that moves a basic block to be one position lower in
  // program order.

  // The id of the block to move down.
  uint32 block_id = 1;

}

message TransformationSplitBlock {

  // A transformation that splits a basic block into two basic blocks.

  // The result id of an instruction.
  uint32 result_id = 1;

  // An offset, such that the block containing |result_id_| should be split
  // right before the instruction |offset_| instructions after |result_id_|.
  uint32 offset = 2;

  // An id that must not yet be used by the module to which this transformation
  // is applied.  Rather than having the transformation choose a suitable id on
  // application, we require the id to be given upfront in order to facilitate
  // reducing fuzzed shaders by removing transformations.  The reason is that
  // future transformations may refer to the fresh id introduced by this
  // transformation, and if we end up changing what that id is, due to removing
  // earlier transformations, it may inhibit later transformations from
  // applying.
  uint32 fresh_id = 3;

}
