• 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    // Add additional option using the next available number.
377  }
378}
379
380// Keep transformation message types in alphabetical order:
381
382message TransformationAccessChain {
383
384  // Adds an access chain instruction based on a given pointer and indices.
385
386  // Result id for the access chain
387  uint32 fresh_id = 1;
388
389  // The pointer from which the access chain starts
390  uint32 pointer_id = 2;
391
392  // Zero or more access chain indices
393  repeated uint32 index_id = 3;
394
395  // A descriptor for an instruction in a block before which the new
396  // OpAccessChain instruction should be inserted
397  InstructionDescriptor instruction_to_insert_before = 4;
398
399}
400
401message TransformationAddConstantBoolean {
402
403  // Supports adding the constants true and false to a module, which may be
404  // necessary in order to enable other transformations if they are not present.
405
406  uint32 fresh_id = 1;
407  bool is_true = 2;
408
409}
410
411message TransformationAddConstantComposite {
412
413  // Adds a constant of the given composite type to the module.
414
415  // Fresh id for the composite
416  uint32 fresh_id = 1;
417
418  // A composite type id
419  uint32 type_id = 2;
420
421  // Constituent ids for the composite
422  repeated uint32 constituent_id = 3;
423
424}
425
426message TransformationAddConstantNull {
427
428  // Adds a null constant.
429
430  // Id for the constant
431  uint32 fresh_id = 1;
432
433  // Type of the constant
434  uint32 type_id = 2;
435
436}
437
438message TransformationAddConstantScalar {
439
440  // Adds a constant of the given scalar type.
441
442  // Id for the constant
443  uint32 fresh_id = 1;
444
445  // Id for the scalar type of the constant
446  uint32 type_id = 2;
447
448  // Value of the constant
449  repeated uint32 word = 3;
450
451}
452
453message TransformationAddDeadBlock {
454
455  // Adds a new block to the module that is statically reachable from an
456  // existing block, but dynamically unreachable.
457
458  // Fresh id for the dead block
459  uint32 fresh_id = 1;
460
461  // Id of an existing block terminated with OpBranch, such that this OpBranch
462  // can be replaced with an OpBranchConditional to its exiting successor or
463  // the dead block
464  uint32 existing_block = 2;
465
466  // Determines whether the condition associated with the OpBranchConditional
467  // is true or false
468  bool condition_value = 3;
469
470}
471
472message TransformationAddDeadBreak {
473
474  // A transformation that turns a basic block that unconditionally branches to
475  // its successor into a block that potentially breaks out of a structured
476  // control flow construct, but in such a manner that the break cannot actually
477  // be taken.
478
479  // The block to break from
480  uint32 from_block = 1;
481
482  // The merge block to break to
483  uint32 to_block = 2;
484
485  // Determines whether the break condition is true or false
486  bool break_condition_value = 3;
487
488  // A sequence of ids suitable for extending OpPhi instructions as a result of
489  // the new break edge
490  repeated uint32 phi_id = 4;
491
492}
493
494message TransformationAddDeadContinue {
495
496  // A transformation that turns a basic block appearing in a loop and that
497  // unconditionally branches to its successor into a block that potentially
498  // branches to the continue target of the loop, but in such a manner that the
499  // continue branch cannot actually be taken.
500
501  // The block to continue from
502  uint32 from_block = 1;
503
504  // Determines whether the continue condition is true or false
505  bool continue_condition_value = 2;
506
507  // A sequence of ids suitable for extending OpPhi instructions as a result of
508  // the new break edge
509  repeated uint32 phi_id = 3;
510
511}
512
513message TransformationAddFunction {
514
515  // Adds a SPIR-V function to the module.
516
517  // The series of instructions that comprise the function.
518  repeated Instruction instruction = 1;
519
520  // True if and only if the given function should be made livesafe (see
521  // FactFunctionIsLivesafe for definition).
522  bool is_livesafe = 2;
523
524  // Fresh id for a new variable that will serve as a "loop limiter" for the
525  // function; only relevant if |is_livesafe| holds.
526  uint32 loop_limiter_variable_id = 3;
527
528  // Id of an existing unsigned integer constant providing the maximum value
529  // that the loop limiter can reach before the loop is broken from; only
530  // relevant if |is_livesafe| holds.
531  uint32 loop_limit_constant_id = 4;
532
533  // Fresh ids for each loop in the function that allow the loop limiter to be
534  // manipulated; only relevant if |is_livesafe| holds.
535  repeated LoopLimiterInfo loop_limiter_info = 5;
536
537  // Id of an existing global value with the same return type as the function
538  // that can be used to replace OpKill and OpReachable instructions with
539  // ReturnValue instructions.  Ignored if the function has void return type.
540  uint32 kill_unreachable_return_value_id = 6;
541
542  // A mapping (represented as a sequence) from every access chain result id in
543  // the function to the ids required to clamp its indices to ensure they are in
544  // bounds.
545  repeated AccessChainClampingInfo access_chain_clamping_info = 7;
546
547}
548
549message TransformationAddGlobalUndef {
550
551  // Adds an undefined value of a given type to the module at global scope.
552
553  // Fresh id for the undefined value
554  uint32 fresh_id = 1;
555
556  // The type of the undefined value
557  uint32 type_id = 2;
558
559}
560
561message TransformationAddGlobalVariable {
562
563  // Adds a global variable of the given type to the module, with Private or
564  // Workgroup storage class, and optionally (for the Private case) with an
565  // initializer.
566
567  // Fresh id for the global variable
568  uint32 fresh_id = 1;
569
570  // The type of the global variable
571  uint32 type_id = 2;
572
573  uint32 storage_class = 3;
574
575  // Initial value of the variable
576  uint32 initializer_id = 4;
577
578  // True if and only if the behaviour of the module should not depend on the
579  // value of the variable, in which case stores to the variable can be
580  // performed in an arbitrary fashion.
581  bool value_is_irrelevant = 5;
582
583}
584
585message TransformationAddLocalVariable {
586
587  // Adds a local variable of the given type (which must be a pointer with
588  // Function storage class) to the given function, initialized to the given
589  // id.
590
591  // Fresh id for the local variable
592  uint32 fresh_id = 1;
593
594  // The type of the local variable
595  uint32 type_id = 2;
596
597  // The id of the function to which the local variable should be added
598  uint32 function_id = 3;
599
600  // Initial value of the variable
601  uint32 initializer_id = 4;
602
603  // True if and only if the behaviour of the module should not depend on the
604  // value of the variable, in which case stores to the variable can be
605  // performed in an arbitrary fashion.
606  bool value_is_irrelevant = 5;
607
608}
609
610message TransformationAddNoContractionDecoration {
611
612  // Applies OpDecorate NoContraction to the given result id
613
614  // Result id to be decorated
615  uint32 result_id = 1;
616
617}
618
619message TransformationAddTypeArray {
620
621  // Adds an array type of the given element type and size to the module
622
623  // Fresh id for the array type
624  uint32 fresh_id = 1;
625
626  // The array's element type
627  uint32 element_type_id = 2;
628
629  // The array's size
630  uint32 size_id = 3;
631
632}
633
634message TransformationAddTypeBoolean {
635
636  // Adds OpTypeBool to the module
637
638  // Id to be used for the type
639  uint32 fresh_id = 1;
640
641}
642
643message TransformationAddTypeFloat {
644
645  // Adds OpTypeFloat to the module with the given width
646
647  // Id to be used for the type
648  uint32 fresh_id = 1;
649
650  // Floating-point width
651  uint32 width = 2;
652
653}
654
655message TransformationAddTypeFunction {
656
657  // Adds a function type to the module
658
659  // Fresh id for the function type
660  uint32 fresh_id = 1;
661
662  // The function's return type
663  uint32 return_type_id = 2;
664
665  // The function's argument types
666  repeated uint32 argument_type_id = 3;
667
668}
669
670message TransformationAddTypeInt {
671
672  // Adds OpTypeInt to the module with the given width and signedness
673
674  // Id to be used for the type
675  uint32 fresh_id = 1;
676
677  // Integer width
678  uint32 width = 2;
679
680  // True if and only if this is a signed type
681  bool is_signed = 3;
682
683}
684
685message TransformationAddTypeMatrix {
686
687  // Adds a matrix type to the module
688
689  // Fresh id for the matrix type
690  uint32 fresh_id = 1;
691
692  // The matrix's column type, which must be a floating-point vector (as per
693  // the "data rules" in the SPIR-V specification).
694  uint32 column_type_id = 2;
695
696  // The matrix's column count
697  uint32 column_count = 3;
698
699}
700
701message TransformationAddTypePointer {
702
703  // Adds OpTypePointer to the module, with the given storage class and base
704  // type
705
706  // Id to be used for the type
707  uint32 fresh_id = 1;
708
709  // Pointer storage class
710  uint32 storage_class = 2;
711
712  // Id of the base type for the pointer
713  uint32 base_type_id = 3;
714
715}
716
717message TransformationAddTypeStruct {
718
719  // Adds a struct type to the module
720
721  // Fresh id for the struct type
722  uint32 fresh_id = 1;
723
724  // The struct's member types
725  repeated uint32 member_type_id = 3;
726
727}
728
729message TransformationAddTypeVector {
730
731  // Adds a vector type to the module
732
733  // Fresh id for the vector type
734  uint32 fresh_id = 1;
735
736  // The vector's component type
737  uint32 component_type_id = 2;
738
739  // The vector's component count
740  uint32 component_count = 3;
741
742}
743
744message TransformationCompositeConstruct {
745
746  // A transformation that introduces an OpCompositeConstruct instruction to
747  // make a composite object.
748
749  // Id of the type of the composite that is to be constructed
750  uint32 composite_type_id = 1;
751
752  // Ids of the objects that will form the components of the composite
753  repeated uint32 component = 2;
754
755  // A descriptor for an instruction in a block before which the new
756  // OpCompositeConstruct instruction should be inserted
757  InstructionDescriptor instruction_to_insert_before = 3;
758
759  // A fresh id for the composite object
760  uint32 fresh_id = 4;
761
762}
763
764message TransformationCompositeExtract {
765
766  // A transformation that adds an instruction to extract an element from a
767  // composite.
768
769  // A descriptor for an instruction in a block before which the new
770  // OpCompositeExtract instruction should be inserted
771  InstructionDescriptor instruction_to_insert_before = 1;
772
773  // Result id for the extract operation.
774  uint32 fresh_id = 2;
775
776  // Id of the composite from which data is to be extracted.
777  uint32 composite_id = 3;
778
779  // Indices that indicate which part of the composite should be extracted.
780  repeated uint32 index = 4;
781
782}
783
784message TransformationCopyObject {
785
786  // A transformation that introduces an OpCopyObject instruction to make a
787  // copy of an object.
788
789  // Id of the object to be copied
790  uint32 object = 1;
791
792  // A descriptor for an instruction in a block before which the new
793  // OpCopyObject instruction should be inserted
794  InstructionDescriptor instruction_to_insert_before = 2;
795
796  // A fresh id for the copied object
797  uint32 fresh_id = 3;
798
799}
800
801message TransformationEquationInstruction {
802
803  // A transformation that adds an instruction to the module that defines an
804  // equation between its result id and input operand ids, such that the
805  // equation is guaranteed to hold at any program point where all ids involved
806  // are available (i.e. at any program point dominated by the instruction).
807
808  // The result id of the new instruction
809  uint32 fresh_id = 1;
810
811  // The instruction's opcode
812  uint32 opcode = 2;
813
814  // The input operands to the instruction
815  repeated uint32 in_operand_id = 3;
816
817  // A descriptor for an instruction in a block before which the new
818  // instruction should be inserted
819  InstructionDescriptor instruction_to_insert_before = 4;
820
821}
822
823message TransformationFunctionCall {
824
825  // A transformation that introduces an OpFunctionCall instruction.  The call
826  // must not make the module's call graph cyclic.  Beyond that, if the call
827  // is in a dead block it can be to any function with arbitrary suitably-typed
828  // arguments; otherwise it must be to a livesafe function, with injected
829  // variables as pointer arguments and arbitrary non-pointer arguments.
830
831  // A fresh id for the result of the call
832  uint32 fresh_id = 1;
833
834  // Id of the function to be called
835  uint32 callee_id = 2;
836
837  // Ids for arguments to the function
838  repeated uint32 argument_id = 3;
839
840  // A descriptor for an instruction in a block before which the new
841  // OpFunctionCall instruction should be inserted
842  InstructionDescriptor instruction_to_insert_before = 4;
843
844}
845
846message TransformationLoad {
847
848  // Transformation that adds an OpLoad instruction from a pointer into an id.
849
850  // The result of the load instruction
851  uint32 fresh_id = 1;
852
853  // The pointer to be loaded from
854  uint32 pointer_id = 2;
855
856  // A descriptor for an instruction in a block before which the new OpLoad
857  // instruction should be inserted
858  InstructionDescriptor instruction_to_insert_before = 3;
859
860}
861
862message TransformationMergeBlocks {
863
864  // A transformation that merges a block with its predecessor.
865
866  // The id of the block that is to be merged with its predecessor; the merged
867  // block will have the *predecessor's* id.
868  uint32 block_id = 1;
869
870}
871
872message TransformationMoveBlockDown {
873
874  // A transformation that moves a basic block to be one position lower in
875  // program order.
876
877  // The id of the block to move down.
878  uint32 block_id = 1;
879}
880
881message TransformationOutlineFunction {
882
883  // A transformation that outlines a single-entry single-exit region of a
884  // control flow graph into a separate function, and replaces the region with
885  // a call to that function.
886
887  // Id of the entry block of the single-entry single-exit region to be outlined
888  uint32 entry_block = 1;
889
890  // Id of the exit block of the single-entry single-exit region to be outlined
891  uint32 exit_block = 2;
892
893  // Id of a struct that will store the return values of the new function
894  uint32 new_function_struct_return_type_id = 3;
895
896  // A fresh id for the type of the outlined function
897  uint32 new_function_type_id = 4;
898
899  // A fresh id for the outlined function itself
900  uint32 new_function_id = 5;
901
902  // A fresh id to represent the block in the outlined function that represents
903  // the first block of the outlined region.
904  uint32 new_function_region_entry_block = 6;
905
906  // A fresh id for the result of the OpFunctionCall instruction that will call
907  // the outlined function
908  uint32 new_caller_result_id = 7;
909
910  // A fresh id to capture the return value of the outlined function - the
911  // argument to OpReturn
912  uint32 new_callee_result_id = 8;
913
914  // Ids defined outside the region and used inside the region will become
915  // parameters to the outlined function.  This is a mapping from used ids to
916  // fresh parameter ids.
917  repeated UInt32Pair input_id_to_fresh_id = 9;
918
919  // Ids defined inside the region and used outside the region will become
920  // fresh ids defined by the outlined function, which get copied into the
921  // function's struct return value and then copied into their destination ids
922  // by the caller.  This is a mapping from original ids to corresponding fresh
923  // ids.
924  repeated UInt32Pair output_id_to_fresh_id = 10;
925
926}
927
928message TransformationPermuteFunctionParameters {
929
930  // A transformation that, given a non-entry-point function taking n
931  // parameters and a permutation of the set [0, n-1]:
932  //   - Introduces a new function type that is the same as the original
933  //     function's type but with the order of arguments permuted
934  //     (only if it doesn't already exist)
935  //   - Changes the type of the function to this type
936  //   - Adjusts all calls to the function so that their arguments are permuted
937
938  // Function, whose parameters will be permuted
939  uint32 function_id = 1;
940
941  // |new_type_id| is a result id of a valid OpTypeFunction instruction.
942  // New type is valid if:
943  //   - it has the same number of operands as the old one
944  //   - function's result type is the same as the old one
945  //   - function's arguments are permuted according to |permutation| vector
946  uint32 new_type_id = 2;
947
948  // An array of size |n|, where |n| is a number of arguments to a function
949  // with |function_id|. For each i: 0 <= permutation[i] < n.
950  //
951  // i-th element of this array contains a position for an i-th
952  // function's argument (i.e. i-th argument will be permutation[i]-th
953  // after running this transformation)
954  repeated uint32 permutation = 3;
955
956}
957
958message TransformationReplaceBooleanConstantWithConstantBinary {
959
960  // A transformation to capture replacing a use of a boolean constant with
961  // binary operation on two constant values
962
963  // A descriptor for the boolean constant id we would like to replace
964  IdUseDescriptor id_use_descriptor = 1;
965
966  // Id for the constant to be used on the LHS of the comparision
967  uint32 lhs_id = 2;
968
969  // Id for the constant to be used on the RHS of the comparision
970  uint32 rhs_id = 3;
971
972  // Opcode for binary operator
973  uint32 opcode = 4;
974
975  // Id that will store the result of the binary operation instruction
976  uint32 fresh_id_for_binary_operation = 5;
977
978}
979
980message TransformationReplaceConstantWithUniform {
981
982  // Replaces a use of a constant id with the result of a load from an
983  // element of uniform buffer known to hold the same value as the constant
984
985  // A descriptor for the id we would like to replace
986  IdUseDescriptor id_use_descriptor = 1;
987
988  // Uniform descriptor to identify which uniform value to choose
989  UniformBufferElementDescriptor uniform_descriptor = 2;
990
991  // Id that will store the result of an access chain
992  uint32 fresh_id_for_access_chain = 3;
993
994  // Id that will store the result of a load
995  uint32 fresh_id_for_load = 4;
996
997}
998
999message TransformationReplaceIdWithSynonym {
1000
1001  // Replaces a use of an id with an id that is known to be synonymous, e.g.
1002  // because it was obtained via applying OpCopyObject
1003
1004  // The id use that is to be replaced
1005  IdUseDescriptor id_use_descriptor = 1;
1006
1007  // The synonymous id
1008  uint32 synonymous_id = 2;
1009
1010}
1011
1012message TransformationSetFunctionControl {
1013
1014  // A transformation that sets the function control operand of an OpFunction
1015  // instruction.
1016
1017  // The result id of an OpFunction instruction
1018  uint32 function_id = 1;
1019
1020  // The value to which the 'function control' operand should be set.
1021  uint32 function_control = 2;
1022
1023}
1024
1025message TransformationSetLoopControl {
1026
1027  // A transformation that sets the loop control operand of an OpLoopMerge
1028  // instruction.
1029
1030  // The id of a basic block that should contain OpLoopMerge
1031  uint32 block_id = 1;
1032
1033  // The value to which the 'loop control' operand should be set.
1034  // This must be a legal loop control mask.
1035  uint32 loop_control = 2;
1036
1037  // Provides a peel count value for the loop.  Used if and only if the
1038  // PeelCount bit is set.  Must be zero if the PeelCount bit is not set (can
1039  // still be zero if this bit is set).
1040  uint32 peel_count = 3;
1041
1042  // Provides a partial count value for the loop.  Used if and only if the
1043  // PartialCount bit is set.  Must be zero if the PartialCount bit is not set
1044  // (can still be zero if this bit is set).
1045  uint32 partial_count = 4;
1046
1047}
1048
1049message TransformationSetMemoryOperandsMask {
1050
1051  // A transformation that sets the memory operands mask of a memory access
1052  // instruction.
1053
1054  // A descriptor for a memory access instruction, e.g. an OpLoad
1055  InstructionDescriptor memory_access_instruction = 1;
1056
1057  // A mask of memory operands to be applied to the instruction.  It must be the
1058  // same as the original mask, except that Volatile can be added, and
1059  // Nontemporal can be added or removed.
1060  uint32 memory_operands_mask = 2;
1061
1062  // Some memory access instructions allow more than one mask to be specified;
1063  // this field indicates which mask should be set
1064  uint32 memory_operands_mask_index = 3;
1065
1066}
1067
1068message TransformationSetSelectionControl {
1069
1070  // A transformation that sets the selection control operand of an
1071  // OpSelectionMerge instruction.
1072
1073  // The id of a basic block that should contain OpSelectionMerge
1074  uint32 block_id = 1;
1075
1076  // The value to which the 'selection control' operand should be set.
1077  // Although technically 'selection control' is a literal mask that can be
1078  // some combination of 'None', 'Flatten' and 'DontFlatten', the combination
1079  // 'Flatten | DontFlatten' does not make sense and is not allowed here.
1080  uint32 selection_control = 2;
1081
1082}
1083
1084message TransformationSplitBlock {
1085
1086  // A transformation that splits a basic block into two basic blocks
1087
1088  // A descriptor for an instruction such that the block containing the
1089  // described instruction should be split right before the instruction.
1090  InstructionDescriptor instruction_to_split_before = 1;
1091
1092  // An id that must not yet be used by the module to which this transformation
1093  // is applied.  Rather than having the transformation choose a suitable id on
1094  // application, we require the id to be given upfront in order to facilitate
1095  // reducing fuzzed shaders by removing transformations.  The reason is that
1096  // future transformations may refer to the fresh id introduced by this
1097  // transformation, and if we end up changing what that id is, due to removing
1098  // earlier transformations, it may inhibit later transformations from
1099  // applying.
1100  uint32 fresh_id = 2;
1101
1102}
1103
1104message TransformationStore {
1105
1106  // Transformation that adds an OpStore instruction of an id to a pointer.
1107
1108  // The pointer to be stored to
1109  uint32 pointer_id = 1;
1110
1111  // The value to be stored
1112  uint32 value_id = 2;
1113
1114  // A descriptor for an instruction in a block before which the new OpStore
1115  // instruction should be inserted
1116  InstructionDescriptor instruction_to_insert_before = 3;
1117
1118}
1119
1120message TransformationSwapCommutableOperands {
1121
1122  // A transformation that swaps the operands of a commutative instruction.
1123
1124  // A descriptor for a commutative instruction
1125  InstructionDescriptor instruction_descriptor = 1;
1126
1127}
1128
1129message TransformationToggleAccessChainInstruction {
1130
1131  // A transformation that toggles an access chain instruction.
1132
1133  // A descriptor for an access chain instruction
1134  InstructionDescriptor instruction_descriptor = 1;
1135
1136}
1137
1138message TransformationVectorShuffle {
1139
1140  // A transformation that adds a vector shuffle instruction.
1141
1142  // A descriptor for an instruction in a block before which the new
1143  // OpVectorShuffle instruction should be inserted
1144  InstructionDescriptor instruction_to_insert_before = 1;
1145
1146  // Result id for the shuffle operation.
1147  uint32 fresh_id = 2;
1148
1149  // Id of the first vector operand.
1150  uint32 vector1 = 3;
1151
1152  // Id of the second vector operand.
1153  uint32 vector2 = 4;
1154
1155  // Indices that indicate which components of the input vectors should be used.
1156  repeated uint32 component = 5;
1157
1158}
1159