• 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 #ifndef SOURCE_FUZZ_FUZZER_CONTEXT_H_
16 #define SOURCE_FUZZ_FUZZER_CONTEXT_H_
17 
18 #include <functional>
19 #include <utility>
20 
21 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
22 #include "source/fuzz/random_generator.h"
23 #include "source/opt/function.h"
24 #include "source/opt/ir_context.h"
25 
26 namespace spvtools {
27 namespace fuzz {
28 
29 // Encapsulates all parameters that control the fuzzing process, such as the
30 // source of randomness and the probabilities with which transformations are
31 // applied.
32 class FuzzerContext {
33  public:
34   // Constructs a fuzzer context with a given random generator and the minimum
35   // value that can be used for fresh ids.
36   FuzzerContext(std::unique_ptr<RandomGenerator> random_generator,
37                 uint32_t min_fresh_id, bool is_wgsl_compatible);
38 
39   ~FuzzerContext();
40 
41   // Returns a random boolean.
42   bool ChooseEven();
43 
44   // Returns true if and only if a randomly-chosen integer in the range [0, 100]
45   // is less than |percentage_chance|.
46   bool ChoosePercentage(uint32_t percentage_chance);
47 
48   // Returns a random index into |sequence|, which is expected to have a 'size'
49   // method, and which must be non-empty.  Typically 'HasSizeMethod' will be an
50   // std::vector.
51   template <typename HasSizeMethod>
RandomIndex(const HasSizeMethod & sequence)52   uint32_t RandomIndex(const HasSizeMethod& sequence) const {
53     assert(sequence.size() > 0);
54     return random_generator_->RandomUint32(
55         static_cast<uint32_t>(sequence.size()));
56   }
57 
58   // Selects a random index into |sequence|, removes the element at that index
59   // and returns it.
60   template <typename T>
RemoveAtRandomIndex(std::vector<T> * sequence)61   T RemoveAtRandomIndex(std::vector<T>* sequence) const {
62     uint32_t index = RandomIndex(*sequence);
63     T result = sequence->at(index);
64     sequence->erase(sequence->begin() + index);
65     return result;
66   }
67 
68   // Randomly shuffles a |sequence| between |lo| and |hi| indices inclusively.
69   // |lo| and |hi| must be valid indices to the |sequence|.
70   template <typename T>
Shuffle(std::vector<T> * sequence,size_t lo,size_t hi)71   void Shuffle(std::vector<T>* sequence, size_t lo, size_t hi) const {
72     auto& array = *sequence;
73 
74     if (array.empty()) {
75       return;
76     }
77 
78     assert(lo <= hi && hi < array.size() && "lo and/or hi indices are invalid");
79 
80     // i > lo to account for potential infinite loop when lo == 0
81     for (size_t i = hi; i > lo; --i) {
82       auto index =
83           random_generator_->RandomUint32(static_cast<uint32_t>(i - lo + 1));
84 
85       if (lo + index != i) {
86         // Introduce std::swap to the scope but don't use it
87         // directly since there might be a better overload
88         using std::swap;
89         swap(array[lo + index], array[i]);
90       }
91     }
92   }
93 
94   // Randomly shuffles a |sequence|.
95   template <typename T>
Shuffle(std::vector<T> * sequence)96   void Shuffle(std::vector<T>* sequence) const {
97     if (!sequence->empty()) {
98       Shuffle(sequence, 0, sequence->size() - 1);
99     }
100   }
101 
102   // Yields an id that is guaranteed not to be used in the module being fuzzed,
103   // or to have been issued before.
104   uint32_t GetFreshId();
105 
106   // Returns a vector of |count| fresh ids.
107   std::vector<uint32_t> GetFreshIds(uint32_t count);
108 
109   // A suggested limit on the id bound for the module being fuzzed.  This is
110   // useful for deciding when to stop the overall fuzzing process.  Furthermore,
111   // fuzzer passes that run the risk of spiralling out of control can
112   // periodically check this limit and terminate early if it has been reached.
113   uint32_t GetIdBoundLimit() const;
114 
115   // A suggested limit on the number of transformations that should be applied.
116   // Also useful to control the overall fuzzing process and rein in individual
117   // fuzzer passes.
118   uint32_t GetTransformationLimit() const;
119 
120   // Returns the minimum fresh id that can be used given the |ir_context|.
121   static uint32_t GetMinFreshId(opt::IRContext* ir_context);
122 
123   // Returns true if all transformations should be compatible with WGSL.
IsWgslCompatible()124   bool IsWgslCompatible() const {
125     return is_wgsl_compatible_;
126   }
127 
128   // Probabilities associated with applying various transformations.
129   // Keep them in alphabetical order.
GetChanceOfAcceptingRepeatedPassRecommendation()130   uint32_t GetChanceOfAcceptingRepeatedPassRecommendation() const {
131     return chance_of_accepting_repeated_pass_recommendation_;
132   }
GetChanceOfAddingAccessChain()133   uint32_t GetChanceOfAddingAccessChain() const {
134     return chance_of_adding_access_chain_;
135   }
GetChanceOfAddingAnotherPassToPassLoop()136   uint32_t GetChanceOfAddingAnotherPassToPassLoop() const {
137     return chance_of_adding_another_pass_to_pass_loop_;
138   }
GetChanceOfAddingAnotherStructField()139   uint32_t GetChanceOfAddingAnotherStructField() const {
140     return chance_of_adding_another_struct_field_;
141   }
GetChanceOfAddingArrayOrStructType()142   uint32_t GetChanceOfAddingArrayOrStructType() const {
143     return chance_of_adding_array_or_struct_type_;
144   }
GetChanceOfAddingAtomicLoad()145   uint32_t GetChanceOfAddingAtomicLoad() const {
146     return chance_of_adding_atomic_load_;
147   }
GetChanceOfAddingAtomicStore()148   uint32_t GetChanceOfAddingAtomicStore() const {
149     return chance_of_adding_atomic_store_;
150   }
GetChanceOfAddingBitInstructionSynonym()151   uint32_t GetChanceOfAddingBitInstructionSynonym() const {
152     return chance_of_adding_bit_instruction_synonym_;
153   }
GetChanceOfAddingBothBranchesWhenReplacingOpSelect()154   uint32_t GetChanceOfAddingBothBranchesWhenReplacingOpSelect() const {
155     return chance_of_adding_both_branches_when_replacing_opselect_;
156   }
GetChanceOfAddingCompositeExtract()157   uint32_t GetChanceOfAddingCompositeExtract() const {
158     return chance_of_adding_composite_extract_;
159   }
GetChanceOfAddingCompositeInsert()160   uint32_t GetChanceOfAddingCompositeInsert() const {
161     return chance_of_adding_composite_insert_;
162   }
GetChanceOfAddingCopyMemory()163   uint32_t GetChanceOfAddingCopyMemory() const {
164     return chance_of_adding_copy_memory_;
165   }
GetChanceOfAddingDeadBlock()166   uint32_t GetChanceOfAddingDeadBlock() const {
167     return chance_of_adding_dead_block_;
168   }
GetChanceOfAddingDeadBreak()169   uint32_t GetChanceOfAddingDeadBreak() const {
170     return chance_of_adding_dead_break_;
171   }
GetChanceOfAddingDeadContinue()172   uint32_t GetChanceOfAddingDeadContinue() const {
173     return chance_of_adding_dead_continue_;
174   }
GetChanceOfAddingEquationInstruction()175   uint32_t GetChanceOfAddingEquationInstruction() const {
176     return chance_of_adding_equation_instruction_;
177   }
GetChanceOfAddingGlobalVariable()178   uint32_t GetChanceOfAddingGlobalVariable() const {
179     return chance_of_adding_global_variable_;
180   }
GetChanceOfAddingImageSampleUnusedComponents()181   uint32_t GetChanceOfAddingImageSampleUnusedComponents() const {
182     return chance_of_adding_image_sample_unused_components_;
183   }
GetChanceOfAddingLoad()184   uint32_t GetChanceOfAddingLoad() const { return chance_of_adding_load_; }
GetChanceOfAddingLocalVariable()185   uint32_t GetChanceOfAddingLocalVariable() const {
186     return chance_of_adding_local_variable_;
187   }
GetChanceOfAddingLoopPreheader()188   uint32_t GetChanceOfAddingLoopPreheader() const {
189     return chance_of_adding_loop_preheader_;
190   }
GetChanceOfAddingMatrixType()191   uint32_t GetChanceOfAddingMatrixType() const {
192     return chance_of_adding_matrix_type_;
193   }
GetChanceOfAddingNoContractionDecoration()194   uint32_t GetChanceOfAddingNoContractionDecoration() const {
195     return chance_of_adding_no_contraction_decoration_;
196   }
GetChanceOfAddingOpPhiSynonym()197   uint32_t GetChanceOfAddingOpPhiSynonym() const {
198     return chance_of_adding_opphi_synonym_;
199   }
GetChanceOfAddingParameters()200   uint32_t GetChanceOfAddingParameters() const {
201     return chance_of_adding_parameters;
202   }
GetChanceOfAddingRelaxedDecoration()203   uint32_t GetChanceOfAddingRelaxedDecoration() const {
204     return chance_of_adding_relaxed_decoration_;
205   }
GetChanceOfAddingStore()206   uint32_t GetChanceOfAddingStore() const { return chance_of_adding_store_; }
GetChanceOfAddingSynonyms()207   uint32_t GetChanceOfAddingSynonyms() const {
208     return chance_of_adding_synonyms_;
209   }
GetChanceOfAddingTrueBranchWhenReplacingOpSelect()210   uint32_t GetChanceOfAddingTrueBranchWhenReplacingOpSelect() const {
211     return chance_of_adding_true_branch_when_replacing_opselect_;
212   }
GetChanceOfAddingVectorShuffle()213   uint32_t GetChanceOfAddingVectorShuffle() const {
214     return chance_of_adding_vector_shuffle_;
215   }
GetChanceOfAddingVectorType()216   uint32_t GetChanceOfAddingVectorType() const {
217     return chance_of_adding_vector_type_;
218   }
GetChanceOfAdjustingBranchWeights()219   uint32_t GetChanceOfAdjustingBranchWeights() const {
220     return chance_of_adjusting_branch_weights_;
221   }
GetChanceOfAdjustingFunctionControl()222   uint32_t GetChanceOfAdjustingFunctionControl() const {
223     return chance_of_adjusting_function_control_;
224   }
GetChanceOfAdjustingLoopControl()225   uint32_t GetChanceOfAdjustingLoopControl() const {
226     return chance_of_adjusting_loop_control_;
227   }
GetChanceOfAdjustingMemoryOperandsMask()228   uint32_t GetChanceOfAdjustingMemoryOperandsMask() const {
229     return chance_of_adjusting_memory_operands_mask_;
230   }
GetChanceOfAdjustingSelectionControl()231   uint32_t GetChanceOfAdjustingSelectionControl() const {
232     return chance_of_adjusting_selection_control_;
233   }
GetChanceOfCallingFunction()234   uint32_t GetChanceOfCallingFunction() const {
235     return chance_of_calling_function_;
236   }
GetChanceOfChoosingStructTypeVsArrayType()237   uint32_t GetChanceOfChoosingStructTypeVsArrayType() const {
238     return chance_of_choosing_struct_type_vs_array_type_;
239   }
GetChanceOfChoosingWorkgroupStorageClass()240   uint32_t GetChanceOfChoosingWorkgroupStorageClass() const {
241     return chance_of_choosing_workgroup_storage_class_;
242   }
GetChanceOfConstructingComposite()243   uint32_t GetChanceOfConstructingComposite() const {
244     return chance_of_constructing_composite_;
245   }
GetChanceOfCopyingObject()246   uint32_t GetChanceOfCopyingObject() const {
247     return chance_of_copying_object_;
248   }
GetChanceOfCreatingIntSynonymsUsingLoops()249   uint32_t GetChanceOfCreatingIntSynonymsUsingLoops() const {
250     return chance_of_creating_int_synonyms_using_loops_;
251   }
GetChanceOfDonatingAdditionalModule()252   uint32_t GetChanceOfDonatingAdditionalModule() const {
253     return chance_of_donating_additional_module_;
254   }
GetChanceOfDuplicatingRegionWithSelection()255   uint32_t GetChanceOfDuplicatingRegionWithSelection() const {
256     return chance_of_duplicating_region_with_selection_;
257   }
GetChanceOfExpandingVectorReduction()258   uint32_t GetChanceOfExpandingVectorReduction() const {
259     return chance_of_expanding_vector_reduction_;
260   }
GetChanceOfFlatteningConditionalBranch()261   uint32_t GetChanceOfFlatteningConditionalBranch() const {
262     return chance_of_flattening_conditional_branch_;
263   }
GetChanceOfGoingDeeperToExtractComposite()264   uint32_t GetChanceOfGoingDeeperToExtractComposite() const {
265     return chance_of_going_deeper_to_extract_composite_;
266   }
GetChanceOfGoingDeeperToInsertInComposite()267   uint32_t GetChanceOfGoingDeeperToInsertInComposite() const {
268     return chance_of_going_deeper_to_insert_in_composite_;
269   }
GetChanceOfGoingDeeperWhenMakingAccessChain()270   uint32_t GetChanceOfGoingDeeperWhenMakingAccessChain() const {
271     return chance_of_going_deeper_when_making_access_chain_;
272   }
GetChanceOfHavingTwoBlocksInLoopToCreateIntSynonym()273   uint32_t GetChanceOfHavingTwoBlocksInLoopToCreateIntSynonym() const {
274     return chance_of_having_two_blocks_in_loop_to_create_int_synonym_;
275   }
GetChanceOfInliningFunction()276   uint32_t GetChanceOfInliningFunction() const {
277     return chance_of_inlining_function_;
278   }
GetChanceOfInterchangingSignednessOfIntegerOperands()279   uint32_t GetChanceOfInterchangingSignednessOfIntegerOperands() const {
280     return chance_of_interchanging_signedness_of_integer_operands_;
281   }
GetChanceOfInterchangingZeroLikeConstants()282   uint32_t GetChanceOfInterchangingZeroLikeConstants() const {
283     return chance_of_interchanging_zero_like_constants_;
284   }
GetChanceOfInvertingComparisonOperators()285   uint32_t GetChanceOfInvertingComparisonOperators() const {
286     return chance_of_inverting_comparison_operators_;
287   }
ChanceOfMakingDonorLivesafe()288   uint32_t ChanceOfMakingDonorLivesafe() const {
289     return chance_of_making_donor_livesafe_;
290   }
GetChanceOfMakingVectorOperationDynamic()291   uint32_t GetChanceOfMakingVectorOperationDynamic() const {
292     return chance_of_making_vector_operation_dynamic_;
293   }
GetChanceOfMergingBlocks()294   uint32_t GetChanceOfMergingBlocks() const {
295     return chance_of_merging_blocks_;
296   }
GetChanceOfMergingFunctionReturns()297   uint32_t GetChanceOfMergingFunctionReturns() const {
298     return chance_of_merging_function_returns_;
299   }
GetChanceOfMovingBlockDown()300   uint32_t GetChanceOfMovingBlockDown() const {
301     return chance_of_moving_block_down_;
302   }
GetChanceOfMutatingPointer()303   uint32_t GetChanceOfMutatingPointer() const {
304     return chance_of_mutating_pointer_;
305   }
GetChanceOfObfuscatingConstant()306   uint32_t GetChanceOfObfuscatingConstant() const {
307     return chance_of_obfuscating_constant_;
308   }
GetChanceOfOutliningFunction()309   uint32_t GetChanceOfOutliningFunction() const {
310     return chance_of_outlining_function_;
311   }
GetChanceOfPermutingFunctionVariables()312   uint32_t GetChanceOfPermutingFunctionVariables() const {
313     return chance_of_permuting_function_variables_;
314   }
GetChanceOfPermutingInstructions()315   uint32_t GetChanceOfPermutingInstructions() const {
316     return chance_of_permuting_instructions_;
317   }
GetChanceOfPermutingParameters()318   uint32_t GetChanceOfPermutingParameters() const {
319     return chance_of_permuting_parameters_;
320   }
GetChanceOfPermutingPhiOperands()321   uint32_t GetChanceOfPermutingPhiOperands() const {
322     return chance_of_permuting_phi_operands_;
323   }
GetChanceOfPropagatingInstructionsDown()324   uint32_t GetChanceOfPropagatingInstructionsDown() const {
325     return chance_of_propagating_instructions_down_;
326   }
GetChanceOfPropagatingInstructionsUp()327   uint32_t GetChanceOfPropagatingInstructionsUp() const {
328     return chance_of_propagating_instructions_up_;
329   }
GetChanceOfPushingIdThroughVariable()330   uint32_t GetChanceOfPushingIdThroughVariable() const {
331     return chance_of_pushing_id_through_variable_;
332   }
GetChanceOfReplacingAddSubMulWithCarryingExtended()333   uint32_t GetChanceOfReplacingAddSubMulWithCarryingExtended() const {
334     return chance_of_replacing_add_sub_mul_with_carrying_extended_;
335   }
GetChanceOfReplacingBranchFromDeadBlockWithExit()336   uint32_t GetChanceOfReplacingBranchFromDeadBlockWithExit() const {
337     return chance_of_replacing_branch_from_dead_block_with_exit_;
338   }
GetChanceOfReplacingCopyMemoryWithLoadStore()339   uint32_t GetChanceOfReplacingCopyMemoryWithLoadStore() const {
340     return chance_of_replacing_copy_memory_with_load_store_;
341   }
GetChanceOfReplacingCopyObjectWithStoreLoad()342   uint32_t GetChanceOfReplacingCopyObjectWithStoreLoad() const {
343     return chance_of_replacing_copyobject_with_store_load_;
344   }
GetChanceOfReplacingIdWithSynonym()345   uint32_t GetChanceOfReplacingIdWithSynonym() const {
346     return chance_of_replacing_id_with_synonym_;
347   }
GetChanceOfReplacingIrrelevantId()348   uint32_t GetChanceOfReplacingIrrelevantId() const {
349     return chance_of_replacing_irrelevant_id_;
350   }
GetChanceOfReplacingLinearAlgebraInstructions()351   uint32_t GetChanceOfReplacingLinearAlgebraInstructions() const {
352     return chance_of_replacing_linear_algebra_instructions_;
353   }
GetChanceOfReplacingLoadStoreWithCopyMemory()354   uint32_t GetChanceOfReplacingLoadStoreWithCopyMemory() const {
355     return chance_of_replacing_load_store_with_copy_memory_;
356   }
GetChanceOfReplacingOpPhiIdFromDeadPredecessor()357   uint32_t GetChanceOfReplacingOpPhiIdFromDeadPredecessor() const {
358     return chance_of_replacing_opphi_id_from_dead_predecessor_;
359   }
GetChanceOfReplacingOpselectWithConditionalBranch()360   uint32_t GetChanceOfReplacingOpselectWithConditionalBranch() const {
361     return chance_of_replacing_opselect_with_conditional_branch_;
362   }
GetChanceOfReplacingParametersWithGlobals()363   uint32_t GetChanceOfReplacingParametersWithGlobals() const {
364     return chance_of_replacing_parameters_with_globals_;
365   }
GetChanceOfReplacingParametersWithStruct()366   uint32_t GetChanceOfReplacingParametersWithStruct() const {
367     return chance_of_replacing_parameters_with_struct_;
368   }
GetChanceOfSplittingBlock()369   uint32_t GetChanceOfSplittingBlock() const {
370     return chance_of_splitting_block_;
371   }
GetChanceOfSwappingAnotherPairOfFunctionVariables()372   uint32_t GetChanceOfSwappingAnotherPairOfFunctionVariables() const {
373     return chance_of_swapping_another_pair_of_function_variables_;
374   }
GetChanceOfSwappingConditionalBranchOperands()375   uint32_t GetChanceOfSwappingConditionalBranchOperands() const {
376     return chance_of_swapping_conditional_branch_operands_;
377   }
378 
GetChanceOfSwappingFunctions()379   uint32_t GetChanceOfSwappingFunctions() const {
380     return chance_of_swapping_functions_;
381   }
382 
GetChanceOfTogglingAccessChainInstruction()383   uint32_t GetChanceOfTogglingAccessChainInstruction() const {
384     return chance_of_toggling_access_chain_instruction_;
385   }
GetChanceOfWrappingRegionInSelection()386   uint32_t GetChanceOfWrappingRegionInSelection() const {
387     return chance_of_wrapping_region_in_selection_;
388   }
389 
GetChanceOfWrappingVectorSynonym()390   uint32_t GetChanceOfWrappingVectorSynonym() const {
391     return chance_of_wrapping_vector_synonym_;
392   }
393 
394   // Other functions to control transformations. Keep them in alphabetical
395   // order.
GetMaximumEquivalenceClassSizeForDataSynonymFactClosure()396   uint32_t GetMaximumEquivalenceClassSizeForDataSynonymFactClosure() const {
397     return max_equivalence_class_size_for_data_synonym_fact_closure_;
398   }
GetMaximumNumberOfFunctionParameters()399   uint32_t GetMaximumNumberOfFunctionParameters() const {
400     return max_number_of_function_parameters_;
401   }
GetMaximumNumberOfParametersReplacedWithStruct()402   uint32_t GetMaximumNumberOfParametersReplacedWithStruct() const {
403     return max_number_of_parameters_replaced_with_struct_;
404   }
GetRandomBranchWeights()405   std::pair<uint32_t, uint32_t> GetRandomBranchWeights() {
406     std::pair<uint32_t, uint32_t> branch_weights = {0, 0};
407 
408     while (branch_weights.first == 0 && branch_weights.second == 0) {
409       // Using INT32_MAX to do not overflow UINT32_MAX when the branch weights
410       // are added together.
411       branch_weights.first = random_generator_->RandomUint32(INT32_MAX);
412       branch_weights.second = random_generator_->RandomUint32(INT32_MAX);
413     }
414 
415     return branch_weights;
416   }
GetRandomComponentsForVectorShuffle(uint32_t max_component_index)417   std::vector<uint32_t> GetRandomComponentsForVectorShuffle(
418       uint32_t max_component_index) {
419     // Component count must be in range [2, 4].
420     std::vector<uint32_t> components(random_generator_->RandomUint32(2) + 2);
421 
422     for (uint32_t& component : components) {
423       component = random_generator_->RandomUint32(max_component_index);
424     }
425 
426     return components;
427   }
GetRandomCompositeExtractIndex(uint32_t number_of_members)428   uint32_t GetRandomCompositeExtractIndex(uint32_t number_of_members) {
429     assert(number_of_members > 0 && "Composite object must have some members");
430     return ChooseBetweenMinAndMax({0, number_of_members - 1});
431   }
GetRandomIndexForAccessChain(uint32_t composite_size_bound)432   uint32_t GetRandomIndexForAccessChain(uint32_t composite_size_bound) {
433     return random_generator_->RandomUint32(composite_size_bound);
434   }
GetRandomIndexForCompositeInsert(uint32_t number_of_components)435   uint32_t GetRandomIndexForCompositeInsert(uint32_t number_of_components) {
436     return random_generator_->RandomUint32(number_of_components);
437   }
GetRandomIndexForWrappingVector(uint32_t vector_width)438   uint32_t GetRandomIndexForWrappingVector(uint32_t vector_width) {
439     return random_generator_->RandomUint32(vector_width);
440   }
GetRandomValueForStepConstantInLoop()441   int64_t GetRandomValueForStepConstantInLoop() {
442     return random_generator_->RandomUint64(UINT64_MAX);
443   }
GetRandomLoopControlPartialCount()444   uint32_t GetRandomLoopControlPartialCount() {
445     return random_generator_->RandomUint32(max_loop_control_partial_count_);
446   }
GetRandomLoopControlPeelCount()447   uint32_t GetRandomLoopControlPeelCount() {
448     return random_generator_->RandomUint32(max_loop_control_peel_count_);
449   }
GetRandomLoopLimit()450   uint32_t GetRandomLoopLimit() {
451     return random_generator_->RandomUint32(max_loop_limit_);
452   }
GetRandomNumberOfLoopIterations(uint32_t max_num_iterations)453   uint32_t GetRandomNumberOfLoopIterations(uint32_t max_num_iterations) {
454     return ChooseBetweenMinAndMax({1, max_num_iterations});
455   }
GetRandomNumberOfNewParameters(uint32_t num_of_params)456   uint32_t GetRandomNumberOfNewParameters(uint32_t num_of_params) {
457     assert(num_of_params < GetMaximumNumberOfFunctionParameters());
458     return ChooseBetweenMinAndMax(
459         {1, std::min(max_number_of_new_parameters_,
460                      GetMaximumNumberOfFunctionParameters() - num_of_params)});
461   }
GetRandomNumberOfParametersReplacedWithStruct(uint32_t num_params)462   uint32_t GetRandomNumberOfParametersReplacedWithStruct(uint32_t num_params) {
463     assert(num_params != 0 && "A function must have parameters to replace");
464     return ChooseBetweenMinAndMax(
465         {1, std::min(num_params,
466                      GetMaximumNumberOfParametersReplacedWithStruct())});
467   }
GetRandomSizeForNewArray()468   uint32_t GetRandomSizeForNewArray() {
469     // Ensure that the array size is non-zero.
470     return random_generator_->RandomUint32(max_new_array_size_limit_ - 1) + 1;
471   }
472   protobufs::TransformationAddSynonym::SynonymType GetRandomSynonymType();
GetRandomUnusedComponentCountForImageSample(uint32_t max_unused_component_count)473   uint32_t GetRandomUnusedComponentCountForImageSample(
474       uint32_t max_unused_component_count) {
475     // Ensure that the number of unused components is non-zero.
476     return random_generator_->RandomUint32(max_unused_component_count) + 1;
477   }
GetWidthOfWrappingVector()478   uint32_t GetWidthOfWrappingVector() {
479     return 2 + random_generator_->RandomUint32(3);
480   }
GoDeeperInConstantObfuscation(uint32_t depth)481   bool GoDeeperInConstantObfuscation(uint32_t depth) {
482     return go_deeper_in_constant_obfuscation_(depth, random_generator_.get());
483   }
484 
485  private:
486   // The source of randomness.
487   std::unique_ptr<RandomGenerator> random_generator_;
488   // The next fresh id to be issued.
489   uint32_t next_fresh_id_;
490 
491   // True if all transformations should be compatible with WGSL spec.
492   bool is_wgsl_compatible_;
493 
494   // Probabilities associated with applying various transformations.
495   // Keep them in alphabetical order.
496   uint32_t chance_of_accepting_repeated_pass_recommendation_;
497   uint32_t chance_of_adding_access_chain_;
498   uint32_t chance_of_adding_another_pass_to_pass_loop_;
499   uint32_t chance_of_adding_another_struct_field_;
500   uint32_t chance_of_adding_array_or_struct_type_;
501   uint32_t chance_of_adding_atomic_load_;
502   uint32_t chance_of_adding_atomic_store_;
503   uint32_t chance_of_adding_bit_instruction_synonym_;
504   uint32_t chance_of_adding_both_branches_when_replacing_opselect_;
505   uint32_t chance_of_adding_composite_extract_;
506   uint32_t chance_of_adding_composite_insert_;
507   uint32_t chance_of_adding_copy_memory_;
508   uint32_t chance_of_adding_dead_block_;
509   uint32_t chance_of_adding_dead_break_;
510   uint32_t chance_of_adding_dead_continue_;
511   uint32_t chance_of_adding_equation_instruction_;
512   uint32_t chance_of_adding_global_variable_;
513   uint32_t chance_of_adding_image_sample_unused_components_;
514   uint32_t chance_of_adding_load_;
515   uint32_t chance_of_adding_local_variable_;
516   uint32_t chance_of_adding_loop_preheader_;
517   uint32_t chance_of_adding_matrix_type_;
518   uint32_t chance_of_adding_no_contraction_decoration_;
519   uint32_t chance_of_adding_opphi_synonym_;
520   uint32_t chance_of_adding_parameters;
521   uint32_t chance_of_adding_relaxed_decoration_;
522   uint32_t chance_of_adding_store_;
523   uint32_t chance_of_adding_synonyms_;
524   uint32_t chance_of_adding_true_branch_when_replacing_opselect_;
525   uint32_t chance_of_adding_vector_shuffle_;
526   uint32_t chance_of_adding_vector_type_;
527   uint32_t chance_of_adjusting_branch_weights_;
528   uint32_t chance_of_adjusting_function_control_;
529   uint32_t chance_of_adjusting_loop_control_;
530   uint32_t chance_of_adjusting_memory_operands_mask_;
531   uint32_t chance_of_adjusting_selection_control_;
532   uint32_t chance_of_calling_function_;
533   uint32_t chance_of_choosing_struct_type_vs_array_type_;
534   uint32_t chance_of_choosing_workgroup_storage_class_;
535   uint32_t chance_of_constructing_composite_;
536   uint32_t chance_of_copying_object_;
537   uint32_t chance_of_creating_int_synonyms_using_loops_;
538   uint32_t chance_of_donating_additional_module_;
539   uint32_t chance_of_duplicating_region_with_selection_;
540   uint32_t chance_of_expanding_vector_reduction_;
541   uint32_t chance_of_flattening_conditional_branch_;
542   uint32_t chance_of_going_deeper_to_extract_composite_;
543   uint32_t chance_of_going_deeper_to_insert_in_composite_;
544   uint32_t chance_of_going_deeper_when_making_access_chain_;
545   uint32_t chance_of_having_two_blocks_in_loop_to_create_int_synonym_;
546   uint32_t chance_of_inlining_function_;
547   uint32_t chance_of_interchanging_signedness_of_integer_operands_;
548   uint32_t chance_of_interchanging_zero_like_constants_;
549   uint32_t chance_of_inverting_comparison_operators_;
550   uint32_t chance_of_making_donor_livesafe_;
551   uint32_t chance_of_making_vector_operation_dynamic_;
552   uint32_t chance_of_merging_blocks_;
553   uint32_t chance_of_merging_function_returns_;
554   uint32_t chance_of_moving_block_down_;
555   uint32_t chance_of_mutating_pointer_;
556   uint32_t chance_of_obfuscating_constant_;
557   uint32_t chance_of_outlining_function_;
558   uint32_t chance_of_permuting_function_variables_;
559   uint32_t chance_of_permuting_instructions_;
560   uint32_t chance_of_permuting_parameters_;
561   uint32_t chance_of_permuting_phi_operands_;
562   uint32_t chance_of_propagating_instructions_down_;
563   uint32_t chance_of_propagating_instructions_up_;
564   uint32_t chance_of_pushing_id_through_variable_;
565   uint32_t chance_of_replacing_add_sub_mul_with_carrying_extended_;
566   uint32_t chance_of_replacing_branch_from_dead_block_with_exit_;
567   uint32_t chance_of_replacing_copy_memory_with_load_store_;
568   uint32_t chance_of_replacing_copyobject_with_store_load_;
569   uint32_t chance_of_replacing_id_with_synonym_;
570   uint32_t chance_of_replacing_irrelevant_id_;
571   uint32_t chance_of_replacing_linear_algebra_instructions_;
572   uint32_t chance_of_replacing_load_store_with_copy_memory_;
573   uint32_t chance_of_replacing_opphi_id_from_dead_predecessor_;
574   uint32_t chance_of_replacing_opselect_with_conditional_branch_;
575   uint32_t chance_of_replacing_parameters_with_globals_;
576   uint32_t chance_of_replacing_parameters_with_struct_;
577   uint32_t chance_of_splitting_block_;
578   uint32_t chance_of_swapping_another_pair_of_function_variables_;
579   uint32_t chance_of_swapping_conditional_branch_operands_;
580   uint32_t chance_of_swapping_functions_;
581   uint32_t chance_of_toggling_access_chain_instruction_;
582   uint32_t chance_of_wrapping_region_in_selection_;
583   uint32_t chance_of_wrapping_vector_synonym_;
584 
585   // Limits associated with various quantities for which random values are
586   // chosen during fuzzing.
587   // Keep them in alphabetical order.
588   uint32_t max_equivalence_class_size_for_data_synonym_fact_closure_;
589   uint32_t max_loop_control_partial_count_;
590   uint32_t max_loop_control_peel_count_;
591   uint32_t max_loop_limit_;
592   uint32_t max_new_array_size_limit_;
593   uint32_t max_number_of_function_parameters_;
594   uint32_t max_number_of_new_parameters_;
595   uint32_t max_number_of_parameters_replaced_with_struct_;
596 
597   // Functions to determine with what probability to go deeper when generating
598   // or mutating constructs recursively.
599   const std::function<bool(uint32_t, RandomGenerator*)>&
600       go_deeper_in_constant_obfuscation_;
601 
602   // Requires |min_max.first| <= |min_max.second|, and returns a value in the
603   // range [ |min_max.first|, |min_max.second| ]
604   uint32_t ChooseBetweenMinAndMax(const std::pair<uint32_t, uint32_t>& min_max);
605 };
606 
607 }  // namespace fuzz
608 }  // namespace spvtools
609 
610 #endif  // SOURCE_FUZZ_FUZZER_CONTEXT_H_
611