• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// This file is specifically named spvtools_fuzz.proto so that the string
16// 'spvtools_fuzz' appears in the names of global-scope symbols that protoc
17// generates when targeting C++.  This is to reduce the potential for name
18// clashes with other globally-scoped symbols.
19
20syntax = "proto3";
21
22package spvtools.fuzz.protobufs;
23
24message UInt32Pair {
25
26  // A pair of uint32s; useful for defining mappings.
27
28  uint32 first = 1;
29
30  uint32 second = 2;
31
32}
33
34message InstructionDescriptor {
35
36  // Describes an instruction in some block of a function with respect to a
37  // base instruction.
38
39  // The id of an instruction after which the instruction being described is
40  // believed to be located.  It might be the using instruction itself.
41  uint32 base_instruction_result_id = 1;
42
43  // The opcode for the instruction being described.
44  uint32 target_instruction_opcode = 2;
45
46  // The number of matching opcodes to skip over when searching from the base
47  // instruction to the instruction being described.
48  uint32 num_opcodes_to_ignore = 3;
49
50}
51
52message IdUseDescriptor {
53
54  // Describes a use of an id as an input operand to an instruction in some
55  // block of a function.
56
57  // Example:
58  //   - id_of_interest = 42
59  //   - enclosing_instruction = (
60  //         base_instruction_result_id = 50,
61  //         target_instruction_opcode = OpStore
62  //         num_opcodes_to_ignore = 7
63  //     )
64  //   - in_operand_index = 1
65  // represents a use of id 42 as input operand 1 to an OpStore instruction,
66  // such that the OpStore instruction can be found in the same basic block as
67  // the instruction with result id 50, and in particular is the 8th OpStore
68  // instruction found from instruction 50 onwards (i.e. 7 OpStore
69  // instructions are skipped).
70
71  // An id that we would like to be able to find a use of.
72  uint32 id_of_interest = 1;
73
74  // The input operand index at which the use is expected.
75  InstructionDescriptor enclosing_instruction = 2;
76
77  uint32 in_operand_index = 3;
78
79}
80
81message DataDescriptor {
82
83  // Represents a data element that can be accessed from an id, by walking the
84  // type hierarchy via a sequence of 0 or more indices.
85  //
86  // Very similar to a UniformBufferElementDescriptor, except that a
87  // DataDescriptor is rooted at the id of a scalar or composite.
88
89  // The object being accessed - a scalar or composite
90  uint32 object = 1;
91
92  // 0 or more indices, used to index into a composite object
93  repeated uint32 index = 2;
94
95}
96
97message UniformBufferElementDescriptor {
98
99  // Represents a data element inside a uniform buffer.  The element is
100  // specified via (a) the result id of a uniform variable in which the element
101  // is contained, and (b) a series of indices that need to be followed to get
102  // to the element (via fields and array/vector indices).
103  //
104  // Example: suppose there is a uniform variable with descriptor set 7 and
105  // binding 9, and that the uniform variable has the following type (using
106  // GLSL-like syntax):
107  //
108  // struct S {
109  //   float f;
110  //   vec3 g;
111  //   int4 h[10];
112  // };
113  //
114  // Then:
115  // - (7, 9, [0]) describes the 'f' field.
116  // - (7, 9, [1,1]) describes the y component of the 'g' field.
117  // - (7, 9, [2,7,3]) describes the w component of element 7 of the 'h' field
118
119  // The descriptor set and binding associated with a uniform variable.
120  uint32 descriptor_set = 1;
121  uint32 binding = 2;
122
123  // An ordered sequence of indices through composite structures in the
124  // uniform buffer.
125  repeated uint32 index = 3;
126
127}
128
129message InstructionOperand {
130
131  // Represents an operand to a SPIR-V instruction.
132
133  // The type of the operand.
134  uint32 operand_type = 1;
135
136  // The data associated with the operand.  For most operands (e.g. ids,
137  // storage classes and literals) this will be a single word.
138  repeated uint32 operand_data = 2;
139
140}
141
142message Instruction {
143
144  // Represents a SPIR-V instruction.
145
146  // The instruction's opcode (e.g. OpLabel).
147  uint32 opcode = 1;
148
149  // The id of the instruction's result type; 0 if there is no result type.
150  uint32 result_type_id = 2;
151
152  // The id of the instruction's result; 0 if there is no result.
153  uint32 result_id = 3;
154
155  // Zero or more input operands.
156  repeated InstructionOperand input_operand = 4;
157
158}
159
160message FactSequence {
161  repeated Fact fact = 1;
162}
163
164message Fact {
165  oneof fact {
166    // Order the fact options by numeric id (rather than alphabetically).
167    FactConstantUniform constant_uniform_fact = 1;
168    FactDataSynonym data_synonym_fact = 2;
169    FactBlockIsDead block_is_dead_fact = 3;
170    FactFunctionIsLivesafe function_is_livesafe_fact = 4;
171    FactPointeeValueIsIrrelevant pointee_value_is_irrelevant_fact = 5;
172    FactIdEquation id_equation_fact = 6;
173  }
174}
175
176// Keep fact message types in alphabetical order:
177
178message FactBlockIsDead {
179
180  // Records the fact that a block is guaranteed to be dynamically unreachable.
181  // This is useful because it informs the fuzzer that rather arbitrary changes
182  // can be made to this block.
183
184  uint32 block_id = 1;
185}
186
187message FactConstantUniform {
188
189  // Records the fact that a uniform buffer element is guaranteed to be equal
190  // to a particular constant value.  spirv-fuzz can use such guarantees to
191  // obfuscate code, e.g. to manufacture an expression that will (due to the
192  // guarantee) evaluate to a particular value at runtime but in a manner that
193  // cannot be predicted at compile-time.
194
195  // An element of a uniform buffer
196  UniformBufferElementDescriptor uniform_buffer_element_descriptor = 1;
197
198  // The words of the associated constant
199  repeated uint32 constant_word = 2;
200
201}
202
203message FactDataSynonym {
204
205  // Records the fact that the data held in two data descriptors are guaranteed
206  // to be equal.  spirv-fuzz can use this to replace uses of one piece of data
207  // with a known-to-be-equal piece of data.
208
209  // Data descriptors guaranteed to hold identical data.
210  DataDescriptor data1 = 1;
211
212  DataDescriptor data2 = 2;
213
214}
215
216message FactFunctionIsLivesafe {
217
218  // Records the fact that a function is guaranteed to be "livesafe", meaning
219  // that it will not make out-of-bounds accesses, does not contain reachable
220  // OpKill or OpUnreachable instructions, does not contain loops that will
221  // execute for large numbers of iterations, and only invokes other livesafe
222  // functions.
223
224  uint32 function_id = 1;
225}
226
227message FactIdEquation {
228
229  // Records the fact that the equation:
230  //
231  // lhs_id = opcode rhs_id[0] rhs_id[1] ... rhs_id[N-1]
232  //
233  // holds; e.g. that the equation:
234  //
235  // %12 = OpIAdd %13 %14
236  //
237  // holds in the case where lhs_id is 12, rhs_id is [13, 14], and the opcode is
238  // OpIAdd.
239
240  // The left-hand-side of the equation.
241  uint32 lhs_id = 1;
242
243  // A SPIR-V opcode, from a restricted set of instructions for which equation
244  // facts make sense.
245  uint32 opcode = 2;
246
247  // The operands to the right-hand-side of the equation.
248  repeated uint32 rhs_id = 3;
249
250}
251
252message FactPointeeValueIsIrrelevant {
253
254  // Records the fact that value of the data pointed to by a pointer id does
255  // not influence the observable behaviour of the module.  This means that
256  // arbitrary stores can be made through the pointer, and that nothing can be
257  // guaranteed about the values that are loaded via the pointer.
258
259  // A result id of pointer type
260  uint32 pointer_id = 1;
261}
262
263message AccessChainClampingInfo {
264
265  // When making a function livesafe it is necessary to clamp the indices that
266  // occur as operands to access chain instructions so that they are guaranteed
267  // to be in bounds.  This message type allows an access chain instruction to
268  // have an associated sequence of ids that are reserved for comparing an
269  // access chain index with a bound (e.g. an array size), and selecting
270  // between the access chain index (if it is within bounds) and the bound (if
271  // it is not).
272  //
273  // This allows turning an instruction of the form:
274  //
275  // %result = OpAccessChain %type %object ... %index ...
276  //
277  // into:
278  //
279  // %t1 = OpULessThanEqual %bool %index %bound_minus_one
280  // %t2 = OpSelect %int_type %t1 %index %bound_minus_one
281  // %result = OpAccessChain %type %object ... %t2 ...
282
283  // The result id of an OpAccessChain or OpInBoundsAccessChain instruction.
284  uint32 access_chain_id = 1;
285
286  // A series of pairs of fresh ids, one per access chain index, for the results
287  // of a compare instruction and a select instruction, serving the roles of %t1
288  // and %t2 in the above example.
289  repeated UInt32Pair compare_and_select_ids = 2;
290
291}
292
293message LoopLimiterInfo {
294
295  // Structure capturing the information required to manipulate a loop limiter
296  // at a loop header.
297
298  // The header for the loop.
299  uint32 loop_header_id = 1;
300
301  // A fresh id into which the loop limiter's current value can be loaded.
302  uint32 load_id = 2;
303
304  // A fresh id that can be used to increment the loaded value by 1.
305  uint32 increment_id = 3;
306
307  // A fresh id that can be used to compare the loaded value with the loop
308  // limit.
309  uint32 compare_id = 4;
310
311  // A fresh id that can be used to compute the conjunction or disjunction of
312  // an original loop exit condition with |compare_id|, if the loop's back edge
313  // block can conditionally exit the loop.
314  uint32 logical_op_id = 5;
315
316  // A sequence of ids suitable for extending OpPhi instructions of the loop
317  // merge block if it did not previously have an incoming edge from the loop
318  // back edge block.
319  repeated uint32 phi_id = 6;
320
321}
322
323message TransformationSequence {
324  repeated Transformation transformation = 1;
325}
326
327message Transformation {
328  oneof transformation {
329    // Order the transformation options by numeric id (rather than
330    // alphabetically).
331    TransformationMoveBlockDown move_block_down = 1;
332    TransformationSplitBlock split_block = 2;
333    TransformationAddConstantBoolean add_constant_boolean = 3;
334    TransformationAddConstantScalar add_constant_scalar = 4;
335    TransformationAddTypeBoolean add_type_boolean = 5;
336    TransformationAddTypeFloat add_type_float = 6;
337    TransformationAddTypeInt add_type_int = 7;
338    TransformationAddDeadBreak add_dead_break = 8;
339    TransformationReplaceBooleanConstantWithConstantBinary
340      replace_boolean_constant_with_constant_binary = 9;
341    TransformationAddTypePointer add_type_pointer = 10;
342    TransformationReplaceConstantWithUniform replace_constant_with_uniform = 11;
343    TransformationAddDeadContinue add_dead_continue = 12;
344    TransformationCopyObject copy_object = 13;
345    TransformationReplaceIdWithSynonym replace_id_with_synonym = 14;
346    TransformationSetSelectionControl set_selection_control = 15;
347    TransformationCompositeConstruct composite_construct = 16;
348    TransformationSetLoopControl set_loop_control = 17;
349    TransformationSetFunctionControl set_function_control = 18;
350    TransformationAddNoContractionDecoration add_no_contraction_decoration = 19;
351    TransformationSetMemoryOperandsMask set_memory_operands_mask = 20;
352    TransformationCompositeExtract composite_extract = 21;
353    TransformationVectorShuffle vector_shuffle = 22;
354    TransformationOutlineFunction outline_function = 23;
355    TransformationMergeBlocks merge_blocks = 24;
356    TransformationAddTypeVector add_type_vector = 25;
357    TransformationAddTypeArray add_type_array = 26;
358    TransformationAddTypeMatrix add_type_matrix = 27;
359    TransformationAddTypeStruct add_type_struct = 28;
360    TransformationAddTypeFunction add_type_function = 29;
361    TransformationAddConstantComposite add_constant_composite = 30;
362    TransformationAddGlobalVariable add_global_variable = 31;
363    TransformationAddGlobalUndef add_global_undef = 32;
364    TransformationAddFunction add_function = 33;
365    TransformationAddDeadBlock add_dead_block = 34;
366    TransformationAddLocalVariable add_local_variable = 35;
367    TransformationLoad load = 36;
368    TransformationStore store = 37;
369    TransformationFunctionCall function_call = 38;
370    TransformationAccessChain access_chain = 39;
371    TransformationEquationInstruction equation_instruction = 40;
372    TransformationSwapCommutableOperands swap_commutable_operands = 41;
373    TransformationPermuteFunctionParameters permute_function_parameters = 42;
374    TransformationToggleAccessChainInstruction toggle_access_chain_instruction = 43;
375    TransformationAddConstantNull add_constant_null = 44;
376    TransformationComputeDataSynonymFactClosure compute_data_synonym_fact_closure = 45;
377    // Add additional option using the next available number.
378  }
379}
380
381// Keep transformation message types in alphabetical order:
382
383message TransformationAccessChain {
384
385  // Adds an access chain instruction based on a given pointer and indices.
386
387  // Result id for the access chain
388  uint32 fresh_id = 1;
389
390  // The pointer from which the access chain starts
391  uint32 pointer_id = 2;
392
393  // Zero or more access chain indices
394  repeated uint32 index_id = 3;
395
396  // A descriptor for an instruction in a block before which the new
397  // OpAccessChain instruction should be inserted
398  InstructionDescriptor instruction_to_insert_before = 4;
399
400}
401
402message TransformationAddConstantBoolean {
403
404  // Supports adding the constants true and false to a module, which may be
405  // necessary in order to enable other transformations if they are not present.
406
407  uint32 fresh_id = 1;
408  bool is_true = 2;
409
410}
411
412message TransformationAddConstantComposite {
413
414  // Adds a constant of the given composite type to the module.
415
416  // Fresh id for the composite
417  uint32 fresh_id = 1;
418
419  // A composite type id
420  uint32 type_id = 2;
421
422  // Constituent ids for the composite
423  repeated uint32 constituent_id = 3;
424
425}
426
427message TransformationAddConstantNull {
428
429  // Adds a null constant.
430
431  // Id for the constant
432  uint32 fresh_id = 1;
433
434  // Type of the constant
435  uint32 type_id = 2;
436
437}
438
439message TransformationAddConstantScalar {
440
441  // Adds a constant of the given scalar type.
442
443  // Id for the constant
444  uint32 fresh_id = 1;
445
446  // Id for the scalar type of the constant
447  uint32 type_id = 2;
448
449  // Value of the constant
450  repeated uint32 word = 3;
451
452}
453
454message TransformationAddDeadBlock {
455
456  // Adds a new block to the module that is statically reachable from an
457  // existing block, but dynamically unreachable.
458
459  // Fresh id for the dead block
460  uint32 fresh_id = 1;
461
462  // Id of an existing block terminated with OpBranch, such that this OpBranch
463  // can be replaced with an OpBranchConditional to its exiting successor or
464  // the dead block
465  uint32 existing_block = 2;
466
467  // Determines whether the condition associated with the OpBranchConditional
468  // is true or false
469  bool condition_value = 3;
470
471}
472
473message TransformationAddDeadBreak {
474
475  // A transformation that turns a basic block that unconditionally branches to
476  // its successor into a block that potentially breaks out of a structured
477  // control flow construct, but in such a manner that the break cannot actually
478  // be taken.
479
480  // The block to break from
481  uint32 from_block = 1;
482
483  // The merge block to break to
484  uint32 to_block = 2;
485
486  // Determines whether the break condition is true or false
487  bool break_condition_value = 3;
488
489  // A sequence of ids suitable for extending OpPhi instructions as a result of
490  // the new break edge
491  repeated uint32 phi_id = 4;
492
493}
494
495message TransformationAddDeadContinue {
496
497  // A transformation that turns a basic block appearing in a loop and that
498  // unconditionally branches to its successor into a block that potentially
499  // branches to the continue target of the loop, but in such a manner that the
500  // continue branch cannot actually be taken.
501
502  // The block to continue from
503  uint32 from_block = 1;
504
505  // Determines whether the continue condition is true or false
506  bool continue_condition_value = 2;
507
508  // A sequence of ids suitable for extending OpPhi instructions as a result of
509  // the new break edge
510  repeated uint32 phi_id = 3;
511
512}
513
514message TransformationAddFunction {
515
516  // Adds a SPIR-V function to the module.
517
518  // The series of instructions that comprise the function.
519  repeated Instruction instruction = 1;
520
521  // True if and only if the given function should be made livesafe (see
522  // FactFunctionIsLivesafe for definition).
523  bool is_livesafe = 2;
524
525  // Fresh id for a new variable that will serve as a "loop limiter" for the
526  // function; only relevant if |is_livesafe| holds.
527  uint32 loop_limiter_variable_id = 3;
528
529  // Id of an existing unsigned integer constant providing the maximum value
530  // that the loop limiter can reach before the loop is broken from; only
531  // relevant if |is_livesafe| holds.
532  uint32 loop_limit_constant_id = 4;
533
534  // Fresh ids for each loop in the function that allow the loop limiter to be
535  // manipulated; only relevant if |is_livesafe| holds.
536  repeated LoopLimiterInfo loop_limiter_info = 5;
537
538  // Id of an existing global value with the same return type as the function
539  // that can be used to replace OpKill and OpReachable instructions with
540  // ReturnValue instructions.  Ignored if the function has void return type.
541  uint32 kill_unreachable_return_value_id = 6;
542
543  // A mapping (represented as a sequence) from every access chain result id in
544  // the function to the ids required to clamp its indices to ensure they are in
545  // bounds.
546  repeated AccessChainClampingInfo access_chain_clamping_info = 7;
547
548}
549
550message TransformationAddGlobalUndef {
551
552  // Adds an undefined value of a given type to the module at global scope.
553
554  // Fresh id for the undefined value
555  uint32 fresh_id = 1;
556
557  // The type of the undefined value
558  uint32 type_id = 2;
559
560}
561
562message TransformationAddGlobalVariable {
563
564  // Adds a global variable of the given type to the module, with Private or
565  // Workgroup storage class, and optionally (for the Private case) with an
566  // initializer.
567
568  // Fresh id for the global variable
569  uint32 fresh_id = 1;
570
571  // The type of the global variable
572  uint32 type_id = 2;
573
574  uint32 storage_class = 3;
575
576  // Initial value of the variable
577  uint32 initializer_id = 4;
578
579  // True if and only if the behaviour of the module should not depend on the
580  // value of the variable, in which case stores to the variable can be
581  // performed in an arbitrary fashion.
582  bool value_is_irrelevant = 5;
583
584}
585
586message TransformationAddLocalVariable {
587
588  // Adds a local variable of the given type (which must be a pointer with
589  // Function storage class) to the given function, initialized to the given
590  // id.
591
592  // Fresh id for the local variable
593  uint32 fresh_id = 1;
594
595  // The type of the local variable
596  uint32 type_id = 2;
597
598  // The id of the function to which the local variable should be added
599  uint32 function_id = 3;
600
601  // Initial value of the variable
602  uint32 initializer_id = 4;
603
604  // True if and only if the behaviour of the module should not depend on the
605  // value of the variable, in which case stores to the variable can be
606  // performed in an arbitrary fashion.
607  bool value_is_irrelevant = 5;
608
609}
610
611message TransformationAddNoContractionDecoration {
612
613  // Applies OpDecorate NoContraction to the given result id
614
615  // Result id to be decorated
616  uint32 result_id = 1;
617
618}
619
620message TransformationAddTypeArray {
621
622  // Adds an array type of the given element type and size to the module
623
624  // Fresh id for the array type
625  uint32 fresh_id = 1;
626
627  // The array's element type
628  uint32 element_type_id = 2;
629
630  // The array's size
631  uint32 size_id = 3;
632
633}
634
635message TransformationAddTypeBoolean {
636
637  // Adds OpTypeBool to the module
638
639  // Id to be used for the type
640  uint32 fresh_id = 1;
641
642}
643
644message TransformationAddTypeFloat {
645
646  // Adds OpTypeFloat to the module with the given width
647
648  // Id to be used for the type
649  uint32 fresh_id = 1;
650
651  // Floating-point width
652  uint32 width = 2;
653
654}
655
656message TransformationAddTypeFunction {
657
658  // Adds a function type to the module
659
660  // Fresh id for the function type
661  uint32 fresh_id = 1;
662
663  // The function's return type
664  uint32 return_type_id = 2;
665
666  // The function's argument types
667  repeated uint32 argument_type_id = 3;
668
669}
670
671message TransformationAddTypeInt {
672
673  // Adds OpTypeInt to the module with the given width and signedness
674
675  // Id to be used for the type
676  uint32 fresh_id = 1;
677
678  // Integer width
679  uint32 width = 2;
680
681  // True if and only if this is a signed type
682  bool is_signed = 3;
683
684}
685
686message TransformationAddTypeMatrix {
687
688  // Adds a matrix type to the module
689
690  // Fresh id for the matrix type
691  uint32 fresh_id = 1;
692
693  // The matrix's column type, which must be a floating-point vector (as per
694  // the "data rules" in the SPIR-V specification).
695  uint32 column_type_id = 2;
696
697  // The matrix's column count
698  uint32 column_count = 3;
699
700}
701
702message TransformationAddTypePointer {
703
704  // Adds OpTypePointer to the module, with the given storage class and base
705  // type
706
707  // Id to be used for the type
708  uint32 fresh_id = 1;
709
710  // Pointer storage class
711  uint32 storage_class = 2;
712
713  // Id of the base type for the pointer
714  uint32 base_type_id = 3;
715
716}
717
718message TransformationAddTypeStruct {
719
720  // Adds a struct type to the module
721
722  // Fresh id for the struct type
723  uint32 fresh_id = 1;
724
725  // The struct's member types
726  repeated uint32 member_type_id = 3;
727
728}
729
730message TransformationAddTypeVector {
731
732  // Adds a vector type to the module
733
734  // Fresh id for the vector type
735  uint32 fresh_id = 1;
736
737  // The vector's component type
738  uint32 component_type_id = 2;
739
740  // The vector's component count
741  uint32 component_count = 3;
742
743}
744
745message TransformationCompositeConstruct {
746
747  // A transformation that introduces an OpCompositeConstruct instruction to
748  // make a composite object.
749
750  // Id of the type of the composite that is to be constructed
751  uint32 composite_type_id = 1;
752
753  // Ids of the objects that will form the components of the composite
754  repeated uint32 component = 2;
755
756  // A descriptor for an instruction in a block before which the new
757  // OpCompositeConstruct instruction should be inserted
758  InstructionDescriptor instruction_to_insert_before = 3;
759
760  // A fresh id for the composite object
761  uint32 fresh_id = 4;
762
763}
764
765message TransformationCompositeExtract {
766
767  // A transformation that adds an instruction to extract an element from a
768  // composite.
769
770  // A descriptor for an instruction in a block before which the new
771  // OpCompositeExtract instruction should be inserted
772  InstructionDescriptor instruction_to_insert_before = 1;
773
774  // Result id for the extract operation.
775  uint32 fresh_id = 2;
776
777  // Id of the composite from which data is to be extracted.
778  uint32 composite_id = 3;
779
780  // Indices that indicate which part of the composite should be extracted.
781  repeated uint32 index = 4;
782
783}
784
785message TransformationComputeDataSynonymFactClosure {
786
787  // A transformation that impacts the fact manager only, forcing a computation
788  // of the closure of data synonym facts, so that e.g. if the components of
789  // vectors v and w are known to be pairwise synonymous, it is deduced that v
790  // and w are themselves synonymous.
791
792  // When searching equivalence classes for implied facts, equivalence classes
793  // larger than this size will be skipped.
794  uint32 maximum_equivalence_class_size = 1;
795
796}
797
798message TransformationCopyObject {
799
800  // A transformation that introduces an OpCopyObject instruction to make a
801  // copy of an object.
802
803  // Id of the object to be copied
804  uint32 object = 1;
805
806  // A descriptor for an instruction in a block before which the new
807  // OpCopyObject instruction should be inserted
808  InstructionDescriptor instruction_to_insert_before = 2;
809
810  // A fresh id for the copied object
811  uint32 fresh_id = 3;
812
813}
814
815message TransformationEquationInstruction {
816
817  // A transformation that adds an instruction to the module that defines an
818  // equation between its result id and input operand ids, such that the
819  // equation is guaranteed to hold at any program point where all ids involved
820  // are available (i.e. at any program point dominated by the instruction).
821
822  // The result id of the new instruction
823  uint32 fresh_id = 1;
824
825  // The instruction's opcode
826  uint32 opcode = 2;
827
828  // The input operands to the instruction
829  repeated uint32 in_operand_id = 3;
830
831  // A descriptor for an instruction in a block before which the new
832  // instruction should be inserted
833  InstructionDescriptor instruction_to_insert_before = 4;
834
835}
836
837message TransformationFunctionCall {
838
839  // A transformation that introduces an OpFunctionCall instruction.  The call
840  // must not make the module's call graph cyclic.  Beyond that, if the call
841  // is in a dead block it can be to any function with arbitrary suitably-typed
842  // arguments; otherwise it must be to a livesafe function, with injected
843  // variables as pointer arguments and arbitrary non-pointer arguments.
844
845  // A fresh id for the result of the call
846  uint32 fresh_id = 1;
847
848  // Id of the function to be called
849  uint32 callee_id = 2;
850
851  // Ids for arguments to the function
852  repeated uint32 argument_id = 3;
853
854  // A descriptor for an instruction in a block before which the new
855  // OpFunctionCall instruction should be inserted
856  InstructionDescriptor instruction_to_insert_before = 4;
857
858}
859
860message TransformationLoad {
861
862  // Transformation that adds an OpLoad instruction from a pointer into an id.
863
864  // The result of the load instruction
865  uint32 fresh_id = 1;
866
867  // The pointer to be loaded from
868  uint32 pointer_id = 2;
869
870  // A descriptor for an instruction in a block before which the new OpLoad
871  // instruction should be inserted
872  InstructionDescriptor instruction_to_insert_before = 3;
873
874}
875
876message TransformationMergeBlocks {
877
878  // A transformation that merges a block with its predecessor.
879
880  // The id of the block that is to be merged with its predecessor; the merged
881  // block will have the *predecessor's* id.
882  uint32 block_id = 1;
883
884}
885
886message TransformationMoveBlockDown {
887
888  // A transformation that moves a basic block to be one position lower in
889  // program order.
890
891  // The id of the block to move down.
892  uint32 block_id = 1;
893}
894
895message TransformationOutlineFunction {
896
897  // A transformation that outlines a single-entry single-exit region of a
898  // control flow graph into a separate function, and replaces the region with
899  // a call to that function.
900
901  // Id of the entry block of the single-entry single-exit region to be outlined
902  uint32 entry_block = 1;
903
904  // Id of the exit block of the single-entry single-exit region to be outlined
905  uint32 exit_block = 2;
906
907  // Id of a struct that will store the return values of the new function
908  uint32 new_function_struct_return_type_id = 3;
909
910  // A fresh id for the type of the outlined function
911  uint32 new_function_type_id = 4;
912
913  // A fresh id for the outlined function itself
914  uint32 new_function_id = 5;
915
916  // A fresh id to represent the block in the outlined function that represents
917  // the first block of the outlined region.
918  uint32 new_function_region_entry_block = 6;
919
920  // A fresh id for the result of the OpFunctionCall instruction that will call
921  // the outlined function
922  uint32 new_caller_result_id = 7;
923
924  // A fresh id to capture the return value of the outlined function - the
925  // argument to OpReturn
926  uint32 new_callee_result_id = 8;
927
928  // Ids defined outside the region and used inside the region will become
929  // parameters to the outlined function.  This is a mapping from used ids to
930  // fresh parameter ids.
931  repeated UInt32Pair input_id_to_fresh_id = 9;
932
933  // Ids defined inside the region and used outside the region will become
934  // fresh ids defined by the outlined function, which get copied into the
935  // function's struct return value and then copied into their destination ids
936  // by the caller.  This is a mapping from original ids to corresponding fresh
937  // ids.
938  repeated UInt32Pair output_id_to_fresh_id = 10;
939
940}
941
942message TransformationPermuteFunctionParameters {
943
944  // A transformation that, given a non-entry-point function taking n
945  // parameters and a permutation of the set [0, n-1]:
946  //   - Introduces a new function type that is the same as the original
947  //     function's type but with the order of arguments permuted
948  //     (only if it doesn't already exist)
949  //   - Changes the type of the function to this type
950  //   - Adjusts all calls to the function so that their arguments are permuted
951
952  // Function, whose parameters will be permuted
953  uint32 function_id = 1;
954
955  // |new_type_id| is a result id of a valid OpTypeFunction instruction.
956  // New type is valid if:
957  //   - it has the same number of operands as the old one
958  //   - function's result type is the same as the old one
959  //   - function's arguments are permuted according to |permutation| vector
960  uint32 new_type_id = 2;
961
962  // An array of size |n|, where |n| is a number of arguments to a function
963  // with |function_id|. For each i: 0 <= permutation[i] < n.
964  //
965  // i-th element of this array contains a position for an i-th
966  // function's argument (i.e. i-th argument will be permutation[i]-th
967  // after running this transformation)
968  repeated uint32 permutation = 3;
969
970}
971
972message TransformationReplaceBooleanConstantWithConstantBinary {
973
974  // A transformation to capture replacing a use of a boolean constant with
975  // binary operation on two constant values
976
977  // A descriptor for the boolean constant id we would like to replace
978  IdUseDescriptor id_use_descriptor = 1;
979
980  // Id for the constant to be used on the LHS of the comparision
981  uint32 lhs_id = 2;
982
983  // Id for the constant to be used on the RHS of the comparision
984  uint32 rhs_id = 3;
985
986  // Opcode for binary operator
987  uint32 opcode = 4;
988
989  // Id that will store the result of the binary operation instruction
990  uint32 fresh_id_for_binary_operation = 5;
991
992}
993
994message TransformationReplaceConstantWithUniform {
995
996  // Replaces a use of a constant id with the result of a load from an
997  // element of uniform buffer known to hold the same value as the constant
998
999  // A descriptor for the id we would like to replace
1000  IdUseDescriptor id_use_descriptor = 1;
1001
1002  // Uniform descriptor to identify which uniform value to choose
1003  UniformBufferElementDescriptor uniform_descriptor = 2;
1004
1005  // Id that will store the result of an access chain
1006  uint32 fresh_id_for_access_chain = 3;
1007
1008  // Id that will store the result of a load
1009  uint32 fresh_id_for_load = 4;
1010
1011}
1012
1013message TransformationReplaceIdWithSynonym {
1014
1015  // Replaces a use of an id with an id that is known to be synonymous, e.g.
1016  // because it was obtained via applying OpCopyObject
1017
1018  // The id use that is to be replaced
1019  IdUseDescriptor id_use_descriptor = 1;
1020
1021  // The synonymous id
1022  uint32 synonymous_id = 2;
1023
1024}
1025
1026message TransformationSetFunctionControl {
1027
1028  // A transformation that sets the function control operand of an OpFunction
1029  // instruction.
1030
1031  // The result id of an OpFunction instruction
1032  uint32 function_id = 1;
1033
1034  // The value to which the 'function control' operand should be set.
1035  uint32 function_control = 2;
1036
1037}
1038
1039message TransformationSetLoopControl {
1040
1041  // A transformation that sets the loop control operand of an OpLoopMerge
1042  // instruction.
1043
1044  // The id of a basic block that should contain OpLoopMerge
1045  uint32 block_id = 1;
1046
1047  // The value to which the 'loop control' operand should be set.
1048  // This must be a legal loop control mask.
1049  uint32 loop_control = 2;
1050
1051  // Provides a peel count value for the loop.  Used if and only if the
1052  // PeelCount bit is set.  Must be zero if the PeelCount bit is not set (can
1053  // still be zero if this bit is set).
1054  uint32 peel_count = 3;
1055
1056  // Provides a partial count value for the loop.  Used if and only if the
1057  // PartialCount bit is set.  Must be zero if the PartialCount bit is not set
1058  // (can still be zero if this bit is set).
1059  uint32 partial_count = 4;
1060
1061}
1062
1063message TransformationSetMemoryOperandsMask {
1064
1065  // A transformation that sets the memory operands mask of a memory access
1066  // instruction.
1067
1068  // A descriptor for a memory access instruction, e.g. an OpLoad
1069  InstructionDescriptor memory_access_instruction = 1;
1070
1071  // A mask of memory operands to be applied to the instruction.  It must be the
1072  // same as the original mask, except that Volatile can be added, and
1073  // Nontemporal can be added or removed.
1074  uint32 memory_operands_mask = 2;
1075
1076  // Some memory access instructions allow more than one mask to be specified;
1077  // this field indicates which mask should be set
1078  uint32 memory_operands_mask_index = 3;
1079
1080}
1081
1082message TransformationSetSelectionControl {
1083
1084  // A transformation that sets the selection control operand of an
1085  // OpSelectionMerge instruction.
1086
1087  // The id of a basic block that should contain OpSelectionMerge
1088  uint32 block_id = 1;
1089
1090  // The value to which the 'selection control' operand should be set.
1091  // Although technically 'selection control' is a literal mask that can be
1092  // some combination of 'None', 'Flatten' and 'DontFlatten', the combination
1093  // 'Flatten | DontFlatten' does not make sense and is not allowed here.
1094  uint32 selection_control = 2;
1095
1096}
1097
1098message TransformationSplitBlock {
1099
1100  // A transformation that splits a basic block into two basic blocks
1101
1102  // A descriptor for an instruction such that the block containing the
1103  // described instruction should be split right before the instruction.
1104  InstructionDescriptor instruction_to_split_before = 1;
1105
1106  // An id that must not yet be used by the module to which this transformation
1107  // is applied.  Rather than having the transformation choose a suitable id on
1108  // application, we require the id to be given upfront in order to facilitate
1109  // reducing fuzzed shaders by removing transformations.  The reason is that
1110  // future transformations may refer to the fresh id introduced by this
1111  // transformation, and if we end up changing what that id is, due to removing
1112  // earlier transformations, it may inhibit later transformations from
1113  // applying.
1114  uint32 fresh_id = 2;
1115
1116}
1117
1118message TransformationStore {
1119
1120  // Transformation that adds an OpStore instruction of an id to a pointer.
1121
1122  // The pointer to be stored to
1123  uint32 pointer_id = 1;
1124
1125  // The value to be stored
1126  uint32 value_id = 2;
1127
1128  // A descriptor for an instruction in a block before which the new OpStore
1129  // instruction should be inserted
1130  InstructionDescriptor instruction_to_insert_before = 3;
1131
1132}
1133
1134message TransformationSwapCommutableOperands {
1135
1136  // A transformation that swaps the operands of a commutative instruction.
1137
1138  // A descriptor for a commutative instruction
1139  InstructionDescriptor instruction_descriptor = 1;
1140
1141}
1142
1143message TransformationToggleAccessChainInstruction {
1144
1145  // A transformation that toggles an access chain instruction.
1146
1147  // A descriptor for an access chain instruction
1148  InstructionDescriptor instruction_descriptor = 1;
1149
1150}
1151
1152message TransformationVectorShuffle {
1153
1154  // A transformation that adds a vector shuffle instruction.
1155
1156  // A descriptor for an instruction in a block before which the new
1157  // OpVectorShuffle instruction should be inserted
1158  InstructionDescriptor instruction_to_insert_before = 1;
1159
1160  // Result id for the shuffle operation.
1161  uint32 fresh_id = 2;
1162
1163  // Id of the first vector operand.
1164  uint32 vector1 = 3;
1165
1166  // Id of the second vector operand.
1167  uint32 vector2 = 4;
1168
1169  // Indices that indicate which components of the input vectors should be used.
1170  repeated uint32 component = 5;
1171
1172}
1173