| // 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 UInt32Pair { |
| |
| // A pair of uint32s; useful for defining mappings. |
| |
| uint32 first = 1; |
| |
| uint32 second = 2; |
| |
| } |
| |
| message InstructionDescriptor { |
| |
| // Describes an instruction in some block of a function with respect to a |
| // base instruction. |
| |
| // The id of an instruction after which the instruction being described is |
| // believed to be located. It might be the using instruction itself. |
| uint32 base_instruction_result_id = 1; |
| |
| // The opcode for the instruction being described. |
| uint32 target_instruction_opcode = 2; |
| |
| // The number of matching opcodes to skip over when searching from the base |
| // instruction to the instruction being described. |
| uint32 num_opcodes_to_ignore = 3; |
| |
| } |
| |
| message IdUseDescriptor { |
| |
| // Describes a use of an id as an input operand to an instruction in some |
| // block of a function. |
| |
| // Example: |
| // - id_of_interest = 42 |
| // - enclosing_instruction = ( |
| // base_instruction_result_id = 50, |
| // target_instruction_opcode = OpStore |
| // num_opcodes_to_ignore = 7 |
| // ) |
| // - in_operand_index = 1 |
| // represents a use of id 42 as input operand 1 to an OpStore instruction, |
| // such that the OpStore instruction can be found in the same basic block as |
| // the instruction with result id 50, and in particular is the 8th OpStore |
| // instruction found from instruction 50 onwards (i.e. 7 OpStore |
| // instructions are skipped). |
| |
| // An id that we would like to be able to find a use of. |
| uint32 id_of_interest = 1; |
| |
| // The input operand index at which the use is expected. |
| InstructionDescriptor enclosing_instruction = 2; |
| |
| uint32 in_operand_index = 3; |
| |
| } |
| |
| message DataDescriptor { |
| |
| // Represents a data element that can be accessed from an id, by walking the |
| // type hierarchy via a sequence of 0 or more indices. |
| // |
| // Very similar to a UniformBufferElementDescriptor, except that a |
| // DataDescriptor is rooted at the id of a scalar or composite. |
| |
| // The object being accessed - a scalar or composite |
| uint32 object = 1; |
| |
| // 0 or more indices, used to index into a composite object |
| repeated uint32 index = 2; |
| |
| } |
| |
| message UniformBufferElementDescriptor { |
| |
| // Represents a data element inside a uniform buffer. The element is |
| // specified via (a) the result id of a uniform variable in which the element |
| // is contained, and (b) a series of indices that need to be followed to get |
| // to the element (via fields and array/vector indices). |
| // |
| // Example: suppose there is a uniform variable with descriptor set 7 and |
| // binding 9, and that the uniform variable has the following type (using |
| // GLSL-like syntax): |
| // |
| // struct S { |
| // float f; |
| // vec3 g; |
| // int4 h[10]; |
| // }; |
| // |
| // Then: |
| // - (7, 9, [0]) describes the 'f' field. |
| // - (7, 9, [1,1]) describes the y component of the 'g' field. |
| // - (7, 9, [2,7,3]) describes the w component of element 7 of the 'h' field |
| |
| // The descriptor set and binding associated with a uniform variable. |
| uint32 descriptor_set = 1; |
| uint32 binding = 2; |
| |
| // An ordered sequence of indices through composite structures in the |
| // uniform buffer. |
| repeated uint32 index = 3; |
| |
| } |
| |
| message InstructionOperand { |
| |
| // Represents an operand to a SPIR-V instruction. |
| |
| // The type of the operand. |
| uint32 operand_type = 1; |
| |
| // The data associated with the operand. For most operands (e.g. ids, |
| // storage classes and literals) this will be a single word. |
| repeated uint32 operand_data = 2; |
| |
| } |
| |
| message Instruction { |
| |
| // Represents a SPIR-V instruction. |
| |
| // The instruction's opcode (e.g. OpLabel). |
| uint32 opcode = 1; |
| |
| // The id of the instruction's result type; 0 if there is no result type. |
| uint32 result_type_id = 2; |
| |
| // The id of the instruction's result; 0 if there is no result. |
| uint32 result_id = 3; |
| |
| // Zero or more input operands. |
| repeated InstructionOperand input_operand = 4; |
| |
| } |
| |
| message FactSequence { |
| repeated Fact fact = 1; |
| } |
| |
| message Fact { |
| oneof fact { |
| // Order the fact options by numeric id (rather than alphabetically). |
| FactConstantUniform constant_uniform_fact = 1; |
| FactDataSynonym data_synonym_fact = 2; |
| FactBlockIsDead block_is_dead_fact = 3; |
| FactFunctionIsLivesafe function_is_livesafe_fact = 4; |
| FactPointeeValueIsIrrelevant pointee_value_is_irrelevant_fact = 5; |
| FactIdEquation id_equation_fact = 6; |
| FactIdIsIrrelevant id_is_irrelevant = 7; |
| } |
| } |
| |
| // Keep fact message types in alphabetical order: |
| |
| message FactBlockIsDead { |
| |
| // Records the fact that a block is guaranteed to be dynamically unreachable. |
| // This is useful because it informs the fuzzer that rather arbitrary changes |
| // can be made to this block. |
| |
| uint32 block_id = 1; |
| |
| } |
| |
| message FactConstantUniform { |
| |
| // Records the fact that a uniform buffer element is guaranteed to be equal |
| // to a particular constant value. spirv-fuzz can use such guarantees to |
| // obfuscate code, e.g. to manufacture an expression that will (due to the |
| // guarantee) evaluate to a particular value at runtime but in a manner that |
| // cannot be predicted at compile-time. |
| |
| // An element of a uniform buffer |
| UniformBufferElementDescriptor uniform_buffer_element_descriptor = 1; |
| |
| // The words of the associated constant |
| repeated uint32 constant_word = 2; |
| |
| } |
| |
| message FactDataSynonym { |
| |
| // Records the fact that the data held in two data descriptors are guaranteed |
| // to be equal. spirv-fuzz can use this to replace uses of one piece of data |
| // with a known-to-be-equal piece of data. |
| |
| // Data descriptors guaranteed to hold identical data. |
| DataDescriptor data1 = 1; |
| |
| DataDescriptor data2 = 2; |
| |
| } |
| |
| message FactFunctionIsLivesafe { |
| |
| // Records the fact that a function is guaranteed to be "livesafe", meaning |
| // that it will not make out-of-bounds accesses, does not contain reachable |
| // OpKill or OpUnreachable instructions, does not contain loops that will |
| // execute for large numbers of iterations, and only invokes other livesafe |
| // functions. |
| |
| uint32 function_id = 1; |
| |
| } |
| |
| message FactIdEquation { |
| |
| // Records the fact that the equation: |
| // |
| // lhs_id = opcode rhs_id[0] rhs_id[1] ... rhs_id[N-1] |
| // |
| // holds; e.g. that the equation: |
| // |
| // %12 = OpIAdd %13 %14 |
| // |
| // holds in the case where lhs_id is 12, rhs_id is [13, 14], and the opcode is |
| // OpIAdd. |
| |
| // The left-hand-side of the equation. |
| uint32 lhs_id = 1; |
| |
| // A SPIR-V opcode, from a restricted set of instructions for which equation |
| // facts make sense. |
| uint32 opcode = 2; |
| |
| // The operands to the right-hand-side of the equation. |
| repeated uint32 rhs_id = 3; |
| |
| } |
| |
| message FactIdIsIrrelevant { |
| |
| // Records a fact that |result_id| is irrelevant (i.e. it's usage doesn't |
| // change the semantics of the module). This implies that a use of this id |
| // can later be replaced with some other id of the same type, or the |
| // definition of |result_id| can be changed so that it yields a different value. |
| |
| // An irrelevant id. |
| uint32 result_id = 1; |
| |
| } |
| |
| message FactPointeeValueIsIrrelevant { |
| |
| // Records the fact that value of the data pointed to by a pointer id does |
| // not influence the observable behaviour of the module. This means that |
| // arbitrary stores can be made through the pointer, and that nothing can be |
| // guaranteed about the values that are loaded via the pointer. |
| |
| // A result id of pointer type |
| uint32 pointer_id = 1; |
| |
| } |
| |
| message AccessChainClampingInfo { |
| |
| // When making a function livesafe it is necessary to clamp the indices that |
| // occur as operands to access chain instructions so that they are guaranteed |
| // to be in bounds. This message type allows an access chain instruction to |
| // have an associated sequence of ids that are reserved for comparing an |
| // access chain index with a bound (e.g. an array size), and selecting |
| // between the access chain index (if it is within bounds) and the bound (if |
| // it is not). |
| // |
| // This allows turning an instruction of the form: |
| // |
| // %result = OpAccessChain %type %object ... %index ... |
| // |
| // into: |
| // |
| // %t1 = OpULessThanEqual %bool %index %bound_minus_one |
| // %t2 = OpSelect %int_type %t1 %index %bound_minus_one |
| // %result = OpAccessChain %type %object ... %t2 ... |
| |
| // The result id of an OpAccessChain or OpInBoundsAccessChain instruction. |
| uint32 access_chain_id = 1; |
| |
| // A series of pairs of fresh ids, one per access chain index, for the results |
| // of a compare instruction and a select instruction, serving the roles of %t1 |
| // and %t2 in the above example. |
| repeated UInt32Pair compare_and_select_ids = 2; |
| |
| } |
| |
| message LoopLimiterInfo { |
| |
| // Structure capturing the information required to manipulate a loop limiter |
| // at a loop header. |
| |
| // The header for the loop. |
| uint32 loop_header_id = 1; |
| |
| // A fresh id into which the loop limiter's current value can be loaded. |
| uint32 load_id = 2; |
| |
| // A fresh id that can be used to increment the loaded value by 1. |
| uint32 increment_id = 3; |
| |
| // A fresh id that can be used to compare the loaded value with the loop |
| // limit. |
| uint32 compare_id = 4; |
| |
| // A fresh id that can be used to compute the conjunction or disjunction of |
| // an original loop exit condition with |compare_id|, if the loop's back edge |
| // block can conditionally exit the loop. |
| uint32 logical_op_id = 5; |
| |
| // A sequence of ids suitable for extending OpPhi instructions of the loop |
| // merge block if it did not previously have an incoming edge from the loop |
| // back edge block. |
| repeated uint32 phi_id = 6; |
| |
| } |
| |
| 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; |
| TransformationReplaceBooleanConstantWithConstantBinary |
| replace_boolean_constant_with_constant_binary = 9; |
| TransformationAddTypePointer add_type_pointer = 10; |
| TransformationReplaceConstantWithUniform replace_constant_with_uniform = 11; |
| TransformationAddDeadContinue add_dead_continue = 12; |
| TransformationReplaceIdWithSynonym replace_id_with_synonym = 13; |
| TransformationSetSelectionControl set_selection_control = 14; |
| TransformationCompositeConstruct composite_construct = 15; |
| TransformationSetLoopControl set_loop_control = 16; |
| TransformationSetFunctionControl set_function_control = 17; |
| TransformationAddNoContractionDecoration add_no_contraction_decoration = 18; |
| TransformationSetMemoryOperandsMask set_memory_operands_mask = 19; |
| TransformationCompositeExtract composite_extract = 20; |
| TransformationVectorShuffle vector_shuffle = 21; |
| TransformationOutlineFunction outline_function = 22; |
| TransformationMergeBlocks merge_blocks = 23; |
| TransformationAddTypeVector add_type_vector = 24; |
| TransformationAddTypeArray add_type_array = 25; |
| TransformationAddTypeMatrix add_type_matrix = 26; |
| TransformationAddTypeStruct add_type_struct = 27; |
| TransformationAddTypeFunction add_type_function = 28; |
| TransformationAddConstantComposite add_constant_composite = 29; |
| TransformationAddGlobalVariable add_global_variable = 30; |
| TransformationAddGlobalUndef add_global_undef = 31; |
| TransformationAddFunction add_function = 32; |
| TransformationAddDeadBlock add_dead_block = 33; |
| TransformationAddLocalVariable add_local_variable = 34; |
| TransformationLoad load = 35; |
| TransformationStore store = 36; |
| TransformationFunctionCall function_call = 37; |
| TransformationAccessChain access_chain = 38; |
| TransformationEquationInstruction equation_instruction = 39; |
| TransformationSwapCommutableOperands swap_commutable_operands = 40; |
| TransformationPermuteFunctionParameters permute_function_parameters = 41; |
| TransformationToggleAccessChainInstruction toggle_access_chain_instruction = 42; |
| TransformationAddConstantNull add_constant_null = 43; |
| TransformationComputeDataSynonymFactClosure compute_data_synonym_fact_closure = 44; |
| TransformationAdjustBranchWeights adjust_branch_weights = 45; |
| TransformationPushIdThroughVariable push_id_through_variable = 46; |
| TransformationAddSpecConstantOp add_spec_constant_op = 47; |
| TransformationReplaceLinearAlgebraInstruction replace_linear_algebra_instruction = 48; |
| TransformationSwapConditionalBranchOperands swap_conditional_branch_operands = 49; |
| TransformationPermutePhiOperands permute_phi_operands = 50; |
| TransformationAddParameter add_parameter = 51; |
| TransformationAddCopyMemory add_copy_memory = 52; |
| TransformationInvertComparisonOperator invert_comparison_operator = 53; |
| TransformationAddImageSampleUnusedComponents add_image_sample_unused_components = 54; |
| TransformationReplaceParameterWithGlobal replace_parameter_with_global = 55; |
| TransformationRecordSynonymousConstants record_synonymous_constants = 56; |
| TransformationAddSynonym add_synonym = 57; |
| TransformationAddRelaxedDecoration add_relaxed_decoration = 58; |
| TransformationReplaceParamsWithStruct replace_params_with_struct = 59; |
| TransformationReplaceCopyObjectWithStoreLoad replace_copy_object_with_store_load = 60; |
| TransformationReplaceCopyMemoryWithLoadStore replace_copy_memory_with_load_store = 61; |
| TransformationReplaceLoadStoreWithCopyMemory replace_load_store_with_copy_memory = 62; |
| // Add additional option using the next available number. |
| } |
| } |
| |
| // Keep transformation message types in alphabetical order: |
| |
| message TransformationAccessChain { |
| |
| // Adds an access chain instruction based on a given pointer and indices. |
| |
| // When accessing a struct, the corresponding indices must be 32-bit integer constants. |
| // For any other composite, the indices can be any 32-bit integer, and the transformation |
| // adds two instructions for each such index to clamp it to the bound, as follows: |
| // |
| // %t1 = OpULessThanEqual %bool %index %bound_minus_one |
| // %t2 = OpSelect %int_type %t1 %index %bound_minus_one |
| |
| // Result id for the access chain |
| uint32 fresh_id = 1; |
| |
| // The pointer from which the access chain starts |
| uint32 pointer_id = 2; |
| |
| // Zero or more access chain indices |
| repeated uint32 index_id = 3; |
| |
| // A descriptor for an instruction in a block before which the new |
| // OpAccessChain instruction should be inserted |
| InstructionDescriptor instruction_to_insert_before = 4; |
| |
| // Additional fresh ids, required to clamp index variables. A pair is needed |
| // for each access to a non-struct composite. |
| repeated UInt32Pair fresh_ids_for_clamping = 5; |
| |
| } |
| |
| 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. |
| // Also, creates an IdIsIrrelevant fact about |fresh_id| if |is_irrelevant| is true. |
| |
| uint32 fresh_id = 1; |
| bool is_true = 2; |
| |
| // If the constant should be marked as irrelevant. |
| bool is_irrelevant = 3; |
| |
| } |
| |
| message TransformationAddConstantComposite { |
| |
| // Adds a constant of the given composite type to the module. |
| // Also, creates an IdIsIrrelevant fact about |fresh_id| if |
| // |is_irrelevant| is true. |
| |
| // Fresh id for the composite |
| uint32 fresh_id = 1; |
| |
| // A composite type id |
| uint32 type_id = 2; |
| |
| // Constituent ids for the composite |
| repeated uint32 constituent_id = 3; |
| |
| // If the constant should be marked as irrelevant. |
| bool is_irrelevant = 4; |
| |
| } |
| |
| message TransformationAddConstantNull { |
| |
| // Adds a null constant. |
| |
| // Id for the constant |
| uint32 fresh_id = 1; |
| |
| // Type of the constant |
| uint32 type_id = 2; |
| |
| } |
| |
| message TransformationAddConstantScalar { |
| |
| // Adds a constant of the given scalar type. |
| // Also, creates an IdIsIrrelevant fact about |
| // |fresh_id| if |is_irrelevant| is true. |
| |
| // 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; |
| |
| // If the constant should be marked as irrelevant. |
| bool is_irrelevant = 4; |
| |
| } |
| |
| message TransformationAddCopyMemory { |
| |
| // Adds an OpCopyMemory instruction into the module. |
| // Creates either a global or a local variable (based on |
| // |storage_class| field) to copy the target into. |
| |
| // OpCopyMemory will be inserted before this instruction. |
| InstructionDescriptor instruction_descriptor = 1; |
| |
| // Fresh id to copy memory into. |
| uint32 fresh_id = 2; |
| |
| // Source to copy memory from. |
| uint32 source_id = 3; |
| |
| // Storage class for the target variable. Can be either Function or Private. |
| uint32 storage_class = 4; |
| |
| // Result id for the variable's initializer operand. Its type must be equal to |
| // variable's pointee type. |
| uint32 initializer_id = 5; |
| |
| } |
| |
| message TransformationAddDeadBlock { |
| |
| // Adds a new block to the module that is statically reachable from an |
| // existing block, but dynamically unreachable. |
| |
| // Fresh id for the dead block |
| uint32 fresh_id = 1; |
| |
| // Id of an existing block terminated with OpBranch, such that this OpBranch |
| // can be replaced with an OpBranchConditional to its exiting successor or |
| // the dead block |
| uint32 existing_block = 2; |
| |
| // Determines whether the condition associated with the OpBranchConditional |
| // is true or false |
| bool condition_value = 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 TransformationAddDeadContinue { |
| |
| // A transformation that turns a basic block appearing in a loop and that |
| // unconditionally branches to its successor into a block that potentially |
| // branches to the continue target of the loop, but in such a manner that the |
| // continue branch cannot actually be taken. |
| |
| // The block to continue from |
| uint32 from_block = 1; |
| |
| // Determines whether the continue condition is true or false |
| bool continue_condition_value = 2; |
| |
| // A sequence of ids suitable for extending OpPhi instructions as a result of |
| // the new break edge |
| repeated uint32 phi_id = 3; |
| |
| } |
| |
| message TransformationAddFunction { |
| |
| // Adds a SPIR-V function to the module. |
| |
| // The series of instructions that comprise the function. |
| repeated Instruction instruction = 1; |
| |
| // True if and only if the given function should be made livesafe (see |
| // FactFunctionIsLivesafe for definition). |
| bool is_livesafe = 2; |
| |
| // Fresh id for a new variable that will serve as a "loop limiter" for the |
| // function; only relevant if |is_livesafe| holds. |
| uint32 loop_limiter_variable_id = 3; |
| |
| // Id of an existing unsigned integer constant providing the maximum value |
| // that the loop limiter can reach before the loop is broken from; only |
| // relevant if |is_livesafe| holds. |
| uint32 loop_limit_constant_id = 4; |
| |
| // Fresh ids for each loop in the function that allow the loop limiter to be |
| // manipulated; only relevant if |is_livesafe| holds. |
| repeated LoopLimiterInfo loop_limiter_info = 5; |
| |
| // Id of an existing global value with the same return type as the function |
| // that can be used to replace OpKill and OpReachable instructions with |
| // ReturnValue instructions. Ignored if the function has void return type. |
| uint32 kill_unreachable_return_value_id = 6; |
| |
| // A mapping (represented as a sequence) from every access chain result id in |
| // the function to the ids required to clamp its indices to ensure they are in |
| // bounds. |
| repeated AccessChainClampingInfo access_chain_clamping_info = 7; |
| |
| } |
| |
| message TransformationAddGlobalUndef { |
| |
| // Adds an undefined value of a given type to the module at global scope. |
| |
| // Fresh id for the undefined value |
| uint32 fresh_id = 1; |
| |
| // The type of the undefined value |
| uint32 type_id = 2; |
| |
| } |
| |
| message TransformationAddGlobalVariable { |
| |
| // Adds a global variable of the given type to the module, with Private or |
| // Workgroup storage class, and optionally (for the Private case) with an |
| // initializer. |
| |
| // Fresh id for the global variable |
| uint32 fresh_id = 1; |
| |
| // The type of the global variable |
| uint32 type_id = 2; |
| |
| uint32 storage_class = 3; |
| |
| // Initial value of the variable |
| uint32 initializer_id = 4; |
| |
| // True if and only if the behaviour of the module should not depend on the |
| // value of the variable, in which case stores to the variable can be |
| // performed in an arbitrary fashion. |
| bool value_is_irrelevant = 5; |
| |
| } |
| |
| message TransformationAddImageSampleUnusedComponents { |
| |
| // A transformation that adds unused components to an image sample coordinate. |
| |
| // An vector id with the original coordinate and the unused components. |
| uint32 coordinate_with_unused_components_id = 1; |
| |
| // A descriptor for an image sample instruction. |
| InstructionDescriptor instruction_descriptor = 2; |
| |
| } |
| |
| message TransformationAddLocalVariable { |
| |
| // Adds a local variable of the given type (which must be a pointer with |
| // Function storage class) to the given function, initialized to the given |
| // id. |
| |
| // Fresh id for the local variable |
| uint32 fresh_id = 1; |
| |
| // The type of the local variable |
| uint32 type_id = 2; |
| |
| // The id of the function to which the local variable should be added |
| uint32 function_id = 3; |
| |
| // Initial value of the variable |
| uint32 initializer_id = 4; |
| |
| // True if and only if the behaviour of the module should not depend on the |
| // value of the variable, in which case stores to the variable can be |
| // performed in an arbitrary fashion. |
| bool value_is_irrelevant = 5; |
| |
| } |
| |
| message TransformationAddNoContractionDecoration { |
| |
| // Applies OpDecorate NoContraction to the given result id |
| |
| // Result id to be decorated |
| uint32 result_id = 1; |
| |
| } |
| |
| message TransformationAddParameter { |
| |
| // Adds a new parameter into the function. |
| |
| // Result id of the function to add parameters to. |
| uint32 function_id = 1; |
| |
| // Fresh id for a new parameter. |
| uint32 parameter_fresh_id = 2; |
| |
| // Result id of the instruction, used to initializer new parameter |
| // in function calls. Type id of that instruction is the type id of the parameter. |
| // It may not be OpTypeVoid. |
| uint32 initializer_id = 3; |
| |
| // A fresh id for a new function type. This might not be used |
| // if a required function type already exists or if we can change |
| // the old function type. |
| uint32 function_type_fresh_id = 4; |
| |
| } |
| |
| message TransformationAddRelaxedDecoration { |
| |
| // Applies OpDecorate RelaxedPrecision to the given result id |
| |
| // Result id to be decorated |
| uint32 result_id = 1; |
| |
| } |
| |
| message TransformationAddSpecConstantOp { |
| |
| // Adds OpSpecConstantOp into the module. |
| |
| // Result id for the new instruction. |
| uint32 fresh_id = 1; |
| |
| // Type id for the new instruction. |
| uint32 type_id = 2; |
| |
| // Opcode operand of the OpSpecConstantOp instruction. |
| uint32 opcode = 3; |
| |
| // Operands of the |opcode| instruction. |
| repeated InstructionOperand operand = 4; |
| |
| } |
| |
| message TransformationAddSynonym { |
| |
| // Adds a |synonymous_instruction| before |insert_before| instruction with |
| // and creates a fact that |result_id| and the result id of |synonymous_instruction| |
| // are synonymous. |
| |
| // Result id of the first synonym. |
| uint32 result_id = 1; |
| |
| // Type of the synonym to apply. Some types might produce instructions |
| // with commutative operands. Such types do not specify the order of the |
| // operands since we have a special transformation to swap commutable operands. |
| // |
| // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3499): |
| // Consider adding more types here. |
| enum SynonymType { |
| // New synonym is derived by adding zero to the |result_id|. |
| ADD_ZERO = 0; |
| |
| // New synonym is derived by subtracting zero from the |result_id|. |
| SUB_ZERO = 1; |
| |
| // New synonym is derived by multiplying |result_id| by one. |
| MUL_ONE = 2; |
| |
| // New synonym is derived by applying OpCopyObject instruction to |result_id|. |
| COPY_OBJECT = 3; |
| |
| // New synonym is derived by applying OpLogicalOr to |result_id| with the second |
| // operand being 'false'. |
| LOGICAL_OR = 4; |
| |
| // New synonym is derived by applying OpLogicalAnd to |result_id| with the second |
| // operand being 'true'. |
| LOGICAL_AND = 5; |
| } |
| |
| // Type of the synonym to create. See SynonymType for more details. |
| SynonymType synonym_type = 2; |
| |
| // Fresh result id for a created synonym. |
| uint32 synonym_fresh_id = 3; |
| |
| // An instruction to insert a new synonym before. |
| InstructionDescriptor insert_before = 4; |
| |
| } |
| |
| message TransformationAddTypeArray { |
| |
| // Adds an array type of the given element type and size to the module |
| |
| // Fresh id for the array type |
| uint32 fresh_id = 1; |
| |
| // The array's element type |
| uint32 element_type_id = 2; |
| |
| // The array's size |
| uint32 size_id = 3; |
| |
| } |
| |
| 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 TransformationAddTypeFunction { |
| |
| // Adds a function type to the module |
| |
| // Fresh id for the function type |
| uint32 fresh_id = 1; |
| |
| // The function's return type |
| uint32 return_type_id = 2; |
| |
| // The function's argument types |
| repeated uint32 argument_type_id = 3; |
| |
| } |
| |
| 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 TransformationAddTypeMatrix { |
| |
| // Adds a matrix type to the module |
| |
| // Fresh id for the matrix type |
| uint32 fresh_id = 1; |
| |
| // The matrix's column type, which must be a floating-point vector (as per |
| // the "data rules" in the SPIR-V specification). |
| uint32 column_type_id = 2; |
| |
| // The matrix's column count |
| uint32 column_count = 3; |
| |
| } |
| |
| message TransformationAddTypePointer { |
| |
| // Adds OpTypePointer to the module, with the given storage class and base |
| // type |
| |
| // Id to be used for the type |
| uint32 fresh_id = 1; |
| |
| // Pointer storage class |
| uint32 storage_class = 2; |
| |
| // Id of the base type for the pointer |
| uint32 base_type_id = 3; |
| |
| } |
| |
| message TransformationAddTypeStruct { |
| |
| // Adds a struct type to the module |
| |
| // Fresh id for the struct type |
| uint32 fresh_id = 1; |
| |
| // The struct's member types |
| repeated uint32 member_type_id = 3; |
| |
| } |
| |
| message TransformationAddTypeVector { |
| |
| // Adds a vector type to the module |
| |
| // Fresh id for the vector type |
| uint32 fresh_id = 1; |
| |
| // The vector's component type |
| uint32 component_type_id = 2; |
| |
| // The vector's component count |
| uint32 component_count = 3; |
| |
| } |
| |
| message TransformationAdjustBranchWeights { |
| |
| // A transformation that adjusts the branch weights |
| // of a branch conditional instruction. |
| |
| // A descriptor for a branch conditional instruction. |
| InstructionDescriptor instruction_descriptor = 1; |
| |
| // Branch weights of a branch conditional instruction. |
| UInt32Pair branch_weights = 2; |
| |
| } |
| |
| message TransformationCompositeConstruct { |
| |
| // A transformation that introduces an OpCompositeConstruct instruction to |
| // make a composite object. |
| |
| // Id of the type of the composite that is to be constructed |
| uint32 composite_type_id = 1; |
| |
| // Ids of the objects that will form the components of the composite |
| repeated uint32 component = 2; |
| |
| // A descriptor for an instruction in a block before which the new |
| // OpCompositeConstruct instruction should be inserted |
| InstructionDescriptor instruction_to_insert_before = 3; |
| |
| // A fresh id for the composite object |
| uint32 fresh_id = 4; |
| |
| } |
| |
| message TransformationCompositeExtract { |
| |
| // A transformation that adds an instruction to extract an element from a |
| // composite. |
| |
| // A descriptor for an instruction in a block before which the new |
| // OpCompositeExtract instruction should be inserted |
| InstructionDescriptor instruction_to_insert_before = 1; |
| |
| // Result id for the extract operation. |
| uint32 fresh_id = 2; |
| |
| // Id of the composite from which data is to be extracted. |
| uint32 composite_id = 3; |
| |
| // Indices that indicate which part of the composite should be extracted. |
| repeated uint32 index = 4; |
| |
| } |
| |
| message TransformationComputeDataSynonymFactClosure { |
| |
| // A transformation that impacts the fact manager only, forcing a computation |
| // of the closure of data synonym facts, so that e.g. if the components of |
| // vectors v and w are known to be pairwise synonymous, it is deduced that v |
| // and w are themselves synonymous. |
| |
| // When searching equivalence classes for implied facts, equivalence classes |
| // larger than this size will be skipped. |
| uint32 maximum_equivalence_class_size = 1; |
| |
| } |
| |
| message TransformationEquationInstruction { |
| |
| // A transformation that adds an instruction to the module that defines an |
| // equation between its result id and input operand ids, such that the |
| // equation is guaranteed to hold at any program point where all ids involved |
| // are available (i.e. at any program point dominated by the instruction). |
| |
| // The result id of the new instruction |
| uint32 fresh_id = 1; |
| |
| // The instruction's opcode |
| uint32 opcode = 2; |
| |
| // The input operands to the instruction |
| repeated uint32 in_operand_id = 3; |
| |
| // A descriptor for an instruction in a block before which the new |
| // instruction should be inserted |
| InstructionDescriptor instruction_to_insert_before = 4; |
| |
| } |
| |
| message TransformationFunctionCall { |
| |
| // A transformation that introduces an OpFunctionCall instruction. The call |
| // must not make the module's call graph cyclic. Beyond that, if the call |
| // is in a dead block it can be to any function with arbitrary suitably-typed |
| // arguments; otherwise it must be to a livesafe function, with injected |
| // variables as pointer arguments and arbitrary non-pointer arguments. |
| |
| // A fresh id for the result of the call |
| uint32 fresh_id = 1; |
| |
| // Id of the function to be called |
| uint32 callee_id = 2; |
| |
| // Ids for arguments to the function |
| repeated uint32 argument_id = 3; |
| |
| // A descriptor for an instruction in a block before which the new |
| // OpFunctionCall instruction should be inserted |
| InstructionDescriptor instruction_to_insert_before = 4; |
| |
| } |
| |
| message TransformationInvertComparisonOperator { |
| |
| // For some instruction with result id |operator_id| that |
| // represents a binary comparison operator (e.g. <, >, <=), this transformation |
| // will replace that instruction's result id with |fresh_id|, |
| // invert the opcode (< will become >=) and insert OpLogicalNot |
| // instruction with result id |operator_id| below. |
| |
| // Result id of the instruction to invert. |
| uint32 operator_id = 1; |
| |
| // Fresh id that will be used by the operator after the inversion. |
| uint32 fresh_id = 2; |
| |
| } |
| |
| message TransformationLoad { |
| |
| // Transformation that adds an OpLoad instruction from a pointer into an id. |
| |
| // The result of the load instruction |
| uint32 fresh_id = 1; |
| |
| // The pointer to be loaded from |
| uint32 pointer_id = 2; |
| |
| // A descriptor for an instruction in a block before which the new OpLoad |
| // instruction should be inserted |
| InstructionDescriptor instruction_to_insert_before = 3; |
| |
| } |
| |
| message TransformationMergeBlocks { |
| |
| // A transformation that merges a block with its predecessor. |
| |
| // The id of the block that is to be merged with its predecessor; the merged |
| // block will have the *predecessor's* id. |
| uint32 block_id = 1; |
| |
| } |
| |
| 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 TransformationOutlineFunction { |
| |
| // A transformation that outlines a single-entry single-exit region of a |
| // control flow graph into a separate function, and replaces the region with |
| // a call to that function. |
| |
| // Id of the entry block of the single-entry single-exit region to be outlined |
| uint32 entry_block = 1; |
| |
| // Id of the exit block of the single-entry single-exit region to be outlined |
| uint32 exit_block = 2; |
| |
| // Id of a struct that will store the return values of the new function |
| uint32 new_function_struct_return_type_id = 3; |
| |
| // A fresh id for the type of the outlined function |
| uint32 new_function_type_id = 4; |
| |
| // A fresh id for the outlined function itself |
| uint32 new_function_id = 5; |
| |
| // A fresh id to represent the block in the outlined function that represents |
| // the first block of the outlined region. |
| uint32 new_function_region_entry_block = 6; |
| |
| // A fresh id for the result of the OpFunctionCall instruction that will call |
| // the outlined function |
| uint32 new_caller_result_id = 7; |
| |
| // A fresh id to capture the return value of the outlined function - the |
| // argument to OpReturn |
| uint32 new_callee_result_id = 8; |
| |
| // Ids defined outside the region and used inside the region will become |
| // parameters to the outlined function. This is a mapping from used ids to |
| // fresh parameter ids. |
| repeated UInt32Pair input_id_to_fresh_id = 9; |
| |
| // Ids defined inside the region and used outside the region will become |
| // fresh ids defined by the outlined function, which get copied into the |
| // function's struct return value and then copied into their destination ids |
| // by the caller. This is a mapping from original ids to corresponding fresh |
| // ids. |
| repeated UInt32Pair output_id_to_fresh_id = 10; |
| |
| } |
| |
| message TransformationPermuteFunctionParameters { |
| |
| // A transformation that, given a non-entry-point function taking n |
| // parameters and a permutation of the set [0, n-1]: |
| // - Introduces a new function type that is the same as the original |
| // function's type but with the order of arguments permuted |
| // (only if it doesn't already exist) |
| // - Changes the type of the function to this type |
| // - Adjusts all calls to the function so that their arguments are permuted |
| |
| // Function, whose parameters will be permuted |
| uint32 function_id = 1; |
| |
| // Fresh id for a new type of the function. This might not be used |
| // if a required function type already exists or if we can change |
| // the old function type. |
| uint32 function_type_fresh_id = 2; |
| |
| // An array of size |n|, where |n| is a number of arguments to a function |
| // with |function_id|. For each i: 0 <= permutation[i] < n. |
| // |
| // i-th element of this array contains a position for an i-th |
| // function's argument (i.e. i-th argument will be permutation[i]-th |
| // after running this transformation) |
| repeated uint32 permutation = 3; |
| |
| } |
| |
| message TransformationPermutePhiOperands { |
| |
| // Permutes operands of some OpPhi instruction. |
| |
| // Result id of the instruction to apply the transformation to. |
| uint32 result_id = 1; |
| |
| // A sequence of numbers in the range [0, n/2 - 1] where |n| is the number |
| // of operands of the OpPhi instruction with |result_id|. |
| repeated uint32 permutation = 2; |
| |
| } |
| |
| message TransformationPushIdThroughVariable { |
| |
| // A transformation that makes |value_synonym_id| and |value_id| to be |
| // synonymous by storing |value_id| into |variable_id| and |
| // loading |variable_id| to |value_synonym_id|. |
| |
| // The value to be stored. |
| uint32 value_id = 1; |
| |
| // A fresh id for the result of the load instruction. |
| uint32 value_synonym_id = 2; |
| |
| // A fresh id for the variable to be stored to. |
| uint32 variable_id = 3; |
| |
| // Constant to initialize the variable from. |
| uint32 initializer_id = 4; |
| |
| // The variable storage class (global or local). |
| uint32 variable_storage_class = 5; |
| |
| // A descriptor for an instruction which the new OpStore |
| // and OpLoad instructions might be inserted before. |
| InstructionDescriptor instruction_descriptor = 6; |
| |
| } |
| |
| message TransformationRecordSynonymousConstants { |
| |
| // A transformation that, given the IDs to two synonymous constants, |
| // records the fact that they are synonymous. The module is not changed. |
| // Two constants are synonymous if: |
| // - they have the same type (ignoring the presence of integer sign) |
| // - they have the same opcode (one of OpConstant, OpConstantTrue, |
| // OpConstantFalse, OpConstantNull) |
| // - they have the same value |
| // If the types are the same, OpConstantNull is equivalent to |
| // OpConstantFalse or OpConstant with value zero. |
| |
| // The id of a constant |
| uint32 constant1_id = 1; |
| |
| // The id of the synonym |
| uint32 constant2_id = 2; |
| |
| } |
| |
| message TransformationReplaceParameterWithGlobal { |
| |
| // Removes parameter with result id |parameter_id| from its function |
| // and creates a global variable to pass its value to the function instead. |
| |
| // Fresh id for a new function type. This might not be used if a required |
| // function type already exists or if we can change the old function type. |
| uint32 function_type_fresh_id = 2; |
| |
| // Result id of the OpFunctionParameter instruction to remove. |
| uint32 parameter_id = 3; |
| |
| // Fresh id of a global variable used to pass parameter's value to the function. |
| uint32 global_variable_fresh_id = 4; |
| |
| } |
| |
| message TransformationReplaceBooleanConstantWithConstantBinary { |
| |
| // A transformation to capture replacing a use of a boolean constant with |
| // binary operation on two constant values |
| |
| // A descriptor for the boolean constant id we would like to replace |
| IdUseDescriptor id_use_descriptor = 1; |
| |
| // Id for the constant to be used on the LHS of the comparision |
| uint32 lhs_id = 2; |
| |
| // Id for the constant to be used on the RHS of the comparision |
| uint32 rhs_id = 3; |
| |
| // Opcode for binary operator |
| uint32 opcode = 4; |
| |
| // Id that will store the result of the binary operation instruction |
| uint32 fresh_id_for_binary_operation = 5; |
| |
| } |
| |
| message TransformationReplaceConstantWithUniform { |
| |
| // Replaces a use of a constant id with the result of a load from an |
| // element of uniform buffer known to hold the same value as the constant |
| |
| // A descriptor for the id we would like to replace |
| IdUseDescriptor id_use_descriptor = 1; |
| |
| // Uniform descriptor to identify which uniform value to choose |
| UniformBufferElementDescriptor uniform_descriptor = 2; |
| |
| // Id that will store the result of an access chain |
| uint32 fresh_id_for_access_chain = 3; |
| |
| // Id that will store the result of a load |
| uint32 fresh_id_for_load = 4; |
| |
| } |
| |
| message TransformationReplaceCopyMemoryWithLoadStore { |
| |
| // A transformation that replaces instructions OpCopyMemory with loading |
| // the source variable to an intermediate value and storing this value into the |
| // target variable of the original OpCopyMemory instruction. |
| |
| // The intermediate value. |
| uint32 fresh_id = 1; |
| |
| // The instruction descriptor to OpCopyMemory. It is necessary, because |
| // OpCopyMemory doesn't have a result id. |
| InstructionDescriptor copy_memory_instruction_descriptor = 2; |
| } |
| |
| message TransformationReplaceCopyObjectWithStoreLoad { |
| |
| // A transformation that replaces instruction OpCopyObject with |
| // storing into a new variable and immediately loading from this |
| // variable to |result_id| of the original OpCopyObject instruction. |
| |
| // The result id of initial OpCopyObject instruction |
| uint32 copy_object_result_id = 1; |
| |
| // A fresh id for the variable to be stored to. |
| uint32 fresh_variable_id = 2; |
| |
| // The variable storage class (Function or Private). |
| uint32 variable_storage_class = 3; |
| |
| // Constant to initialize the variable with. |
| uint32 variable_initializer_id = 4; |
| } |
| |
| message TransformationReplaceIdWithSynonym { |
| |
| // Replaces a use of an id with an id that is known to be synonymous, e.g. |
| // because it was obtained via applying OpCopyObject |
| |
| // The id use that is to be replaced |
| IdUseDescriptor id_use_descriptor = 1; |
| |
| // The synonymous id |
| uint32 synonymous_id = 2; |
| |
| } |
| |
| message TransformationReplaceLinearAlgebraInstruction { |
| |
| // Replaces a linear algebra instruction with its |
| // mathematical definition. |
| |
| // The fresh ids needed to apply the transformation. |
| repeated uint32 fresh_ids = 1; |
| |
| // A descriptor for a linear algebra instruction. |
| // This transformation is only applicable if the described instruction has one of the following opcodes. |
| // Supported: |
| // OpVectorTimesScalar |
| // OpMatrixTimesScalar |
| // OpVectorTimesMatrix |
| // OpMatrixTimesVector |
| // OpMatrixTimesMatrix |
| // OpDot |
| // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3354): |
| // Right now we only support certain operations. When this issue is addressed |
| // the supporting comments can be removed. |
| // To be supported in the future: |
| // OpTranspose |
| // OpOuterProduct |
| InstructionDescriptor instruction_descriptor = 2; |
| |
| } |
| |
| message TransformationReplaceLoadStoreWithCopyMemory { |
| // A transformation that takes a pair of instruction descriptors |
| // to OpLoad and OpStore that have the same intermediate value |
| // and replaces the OpStore with an equivalent OpCopyMemory. |
| |
| // The instruction descriptor to OpLoad |
| InstructionDescriptor load_instruction_descriptor = 1; |
| |
| // The instruction descriptor to OpStore |
| InstructionDescriptor store_instruction_descriptor = 2; |
| } |
| |
| message TransformationReplaceParamsWithStruct { |
| |
| // Replaces parameters of the function with a struct containing |
| // values of those parameters. |
| |
| // Result ids of parameters to replace. |
| repeated uint32 parameter_id = 1; |
| |
| // Fresh id for a new function type. This might be unused if the required type |
| // already exists in the module or if we can change the old type. |
| uint32 fresh_function_type_id = 2; |
| |
| // Fresh id for a new struct function parameter to be used as a replacement. |
| uint32 fresh_parameter_id = 3; |
| |
| // Fresh ids for struct objects containing values of replaced parameters. |
| // This map contains a fresh id for at least every result id of a relevant |
| // OpFunctionCall instruction. |
| // |
| // While maps are not fully deterministic, the way this map is used does not |
| // exhibit nondeterminism. Change to repeated Uint32Pair if this changes. |
| map<uint32, uint32> caller_id_to_fresh_composite_id = 4; |
| |
| } |
| |
| message TransformationSetFunctionControl { |
| |
| // A transformation that sets the function control operand of an OpFunction |
| // instruction. |
| |
| // The result id of an OpFunction instruction |
| uint32 function_id = 1; |
| |
| // The value to which the 'function control' operand should be set. |
| uint32 function_control = 2; |
| |
| } |
| |
| message TransformationSetLoopControl { |
| |
| // A transformation that sets the loop control operand of an OpLoopMerge |
| // instruction. |
| |
| // The id of a basic block that should contain OpLoopMerge |
| uint32 block_id = 1; |
| |
| // The value to which the 'loop control' operand should be set. |
| // This must be a legal loop control mask. |
| uint32 loop_control = 2; |
| |
| // Provides a peel count value for the loop. Used if and only if the |
| // PeelCount bit is set. Must be zero if the PeelCount bit is not set (can |
| // still be zero if this bit is set). |
| uint32 peel_count = 3; |
| |
| // Provides a partial count value for the loop. Used if and only if the |
| // PartialCount bit is set. Must be zero if the PartialCount bit is not set |
| // (can still be zero if this bit is set). |
| uint32 partial_count = 4; |
| |
| } |
| |
| message TransformationSetMemoryOperandsMask { |
| |
| // A transformation that sets the memory operands mask of a memory access |
| // instruction. |
| |
| // A descriptor for a memory access instruction, e.g. an OpLoad |
| InstructionDescriptor memory_access_instruction = 1; |
| |
| // A mask of memory operands to be applied to the instruction. It must be the |
| // same as the original mask, except that Volatile can be added, and |
| // Nontemporal can be added or removed. |
| uint32 memory_operands_mask = 2; |
| |
| // Some memory access instructions allow more than one mask to be specified; |
| // this field indicates which mask should be set |
| uint32 memory_operands_mask_index = 3; |
| |
| } |
| |
| message TransformationSetSelectionControl { |
| |
| // A transformation that sets the selection control operand of an |
| // OpSelectionMerge instruction. |
| |
| // The id of a basic block that should contain OpSelectionMerge |
| uint32 block_id = 1; |
| |
| // The value to which the 'selection control' operand should be set. |
| // Although technically 'selection control' is a literal mask that can be |
| // some combination of 'None', 'Flatten' and 'DontFlatten', the combination |
| // 'Flatten | DontFlatten' does not make sense and is not allowed here. |
| uint32 selection_control = 2; |
| |
| } |
| |
| message TransformationSplitBlock { |
| |
| // A transformation that splits a basic block into two basic blocks |
| |
| // A descriptor for an instruction such that the block containing the |
| // described instruction should be split right before the instruction. |
| InstructionDescriptor instruction_to_split_before = 1; |
| |
| // 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 = 2; |
| |
| } |
| |
| message TransformationStore { |
| |
| // Transformation that adds an OpStore instruction of an id to a pointer. |
| |
| // The pointer to be stored to |
| uint32 pointer_id = 1; |
| |
| // The value to be stored |
| uint32 value_id = 2; |
| |
| // A descriptor for an instruction in a block before which the new OpStore |
| // instruction should be inserted |
| InstructionDescriptor instruction_to_insert_before = 3; |
| |
| } |
| |
| message TransformationSwapCommutableOperands { |
| |
| // A transformation that swaps the operands of a commutative instruction. |
| |
| // A descriptor for a commutative instruction |
| InstructionDescriptor instruction_descriptor = 1; |
| |
| } |
| |
| message TransformationSwapConditionalBranchOperands { |
| |
| // Swaps label ids in OpBranchConditional instruction. |
| // Additionally, inverts the guard and swaps branch weights |
| // if present. |
| |
| // Descriptor of the instruction to swap operands of. |
| InstructionDescriptor instruction_descriptor = 1; |
| |
| // Fresh result id for the OpLogicalNot instruction, used |
| // to invert the guard. |
| uint32 fresh_id = 2; |
| |
| } |
| |
| message TransformationToggleAccessChainInstruction { |
| |
| // A transformation that toggles an access chain instruction. |
| |
| // A descriptor for an access chain instruction |
| InstructionDescriptor instruction_descriptor = 1; |
| |
| } |
| |
| message TransformationVectorShuffle { |
| |
| // A transformation that adds a vector shuffle instruction. |
| |
| // A descriptor for an instruction in a block before which the new |
| // OpVectorShuffle instruction should be inserted |
| InstructionDescriptor instruction_to_insert_before = 1; |
| |
| // Result id for the shuffle operation. |
| uint32 fresh_id = 2; |
| |
| // Id of the first vector operand. |
| uint32 vector1 = 3; |
| |
| // Id of the second vector operand. |
| uint32 vector2 = 4; |
| |
| // Indices that indicate which components of the input vectors should be used. |
| repeated uint32 component = 5; |
| |
| } |