Browse Source

Updated spirv-tools.

Бранимир Караџић 5 years ago
parent
commit
75bbd23e53
45 changed files with 2050 additions and 115 deletions
  1. 1 1
      3rdparty/spirv-tools/include/generated/build-version.inc
  2. 2 1
      3rdparty/spirv-tools/include/generated/generators.inc
  3. 10 0
      3rdparty/spirv-tools/source/fuzz/CMakeLists.txt
  4. 8 0
      3rdparty/spirv-tools/source/fuzz/fuzzer.cpp
  5. 12 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp
  6. 17 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_context.h
  7. 22 5
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.cpp
  8. 200 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp
  9. 41 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h
  10. 2 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp
  11. 92 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp
  12. 40 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.h
  13. 197 14
      3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp
  14. 45 5
      3rdparty/spirv-tools/source/fuzz/fuzzer_util.h
  15. 54 2
      3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto
  16. 15 0
      3rdparty/spirv-tools/source/fuzz/transformation.cpp
  17. 4 4
      3rdparty/spirv-tools/source/fuzz/transformation_add_dead_block.cpp
  18. 2 2
      3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.cpp
  19. 2 2
      3rdparty/spirv-tools/source/fuzz/transformation_add_dead_continue.cpp
  20. 0 2
      3rdparty/spirv-tools/source/fuzz/transformation_add_global_variable.cpp
  21. 117 0
      3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.cpp
  22. 57 0
      3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.h
  23. 0 2
      3rdparty/spirv-tools/source/fuzz/transformation_add_local_variable.cpp
  24. 0 2
      3rdparty/spirv-tools/source/fuzz/transformation_push_id_through_variable.cpp
  25. 107 0
      3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.cpp
  26. 59 0
      3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.h
  27. 283 3
      3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.cpp
  28. 8 0
      3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.h
  29. 245 0
      3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.cpp
  30. 67 0
      3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.h
  31. 20 0
      3rdparty/spirv-tools/source/opcode.cpp
  32. 3 0
      3rdparty/spirv-tools/source/opcode.h
  33. 57 0
      3rdparty/spirv-tools/source/opt/copy_prop_arrays.cpp
  34. 104 8
      3rdparty/spirv-tools/source/opt/debug_info_manager.cpp
  35. 16 0
      3rdparty/spirv-tools/source/opt/debug_info_manager.h
  36. 9 0
      3rdparty/spirv-tools/source/opt/instruction.h
  37. 9 2
      3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp
  38. 45 10
      3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp
  39. 3 2
      3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.h
  40. 0 4
      3rdparty/spirv-tools/source/opt/pass.h
  41. 3 2
      3rdparty/spirv-tools/source/opt/reduce_load_size.cpp
  42. 3 2
      3rdparty/spirv-tools/source/opt/ssa_rewrite_pass.cpp
  43. 60 38
      3rdparty/spirv-tools/source/opt/vector_dce.cpp
  44. 7 1
      3rdparty/spirv-tools/source/opt/vector_dce.h
  45. 2 1
      3rdparty/spirv-tools/utils/check_copyright.py

+ 1 - 1
3rdparty/spirv-tools/include/generated/build-version.inc

@@ -1 +1 @@
-"v2020.4-dev", "SPIRV-Tools v2020.4-dev 7efb218fd1272e44be3bc1e891ac153da59e9871"
+"v2020.4-dev", "SPIRV-Tools v2020.4-dev 38bba44706260cfb807097c58ca926c64c3a13d2"

+ 2 - 1
3rdparty/spirv-tools/include/generated/generators.inc

@@ -20,4 +20,5 @@
 {19, "Clay", "Clay Shader Compiler", "Clay Clay Shader Compiler"},
 {19, "Clay", "Clay Shader Compiler", "Clay Clay Shader Compiler"},
 {20, "W3C WebGPU Group", "WHLSL Shader Translator", "W3C WebGPU Group WHLSL Shader Translator"},
 {20, "W3C WebGPU Group", "WHLSL Shader Translator", "W3C WebGPU Group WHLSL Shader Translator"},
 {21, "Google", "Clspv", "Google Clspv"},
 {21, "Google", "Clspv", "Google Clspv"},
-{22, "Google", "MLIR SPIR-V Serializer", "Google MLIR SPIR-V Serializer"},
+{22, "Google", "MLIR SPIR-V Serializer", "Google MLIR SPIR-V Serializer"},
+{23, "Google", "Tint Compiler", "Google Tint Compiler"},

+ 10 - 0
3rdparty/spirv-tools/source/fuzz/CMakeLists.txt

@@ -46,6 +46,7 @@ if(SPIRV_BUILD_FUZZER)
         fuzzer_pass_add_equation_instructions.h
         fuzzer_pass_add_equation_instructions.h
         fuzzer_pass_add_function_calls.h
         fuzzer_pass_add_function_calls.h
         fuzzer_pass_add_global_variables.h
         fuzzer_pass_add_global_variables.h
+        fuzzer_pass_add_image_sample_unused_components.h
         fuzzer_pass_add_loads.h
         fuzzer_pass_add_loads.h
         fuzzer_pass_add_local_variables.h
         fuzzer_pass_add_local_variables.h
         fuzzer_pass_add_no_contraction_decorations.h
         fuzzer_pass_add_no_contraction_decorations.h
@@ -70,6 +71,7 @@ if(SPIRV_BUILD_FUZZER)
         fuzzer_pass_permute_phi_operands.h
         fuzzer_pass_permute_phi_operands.h
         fuzzer_pass_push_ids_through_variables.h
         fuzzer_pass_push_ids_through_variables.h
         fuzzer_pass_replace_linear_algebra_instructions.h
         fuzzer_pass_replace_linear_algebra_instructions.h
+        fuzzer_pass_replace_parameter_with_global.h
         fuzzer_pass_split_blocks.h
         fuzzer_pass_split_blocks.h
         fuzzer_pass_swap_commutable_operands.h
         fuzzer_pass_swap_commutable_operands.h
         fuzzer_pass_swap_conditional_branch_operands.h
         fuzzer_pass_swap_conditional_branch_operands.h
@@ -96,6 +98,7 @@ if(SPIRV_BUILD_FUZZER)
         transformation_add_function.h
         transformation_add_function.h
         transformation_add_global_undef.h
         transformation_add_global_undef.h
         transformation_add_global_variable.h
         transformation_add_global_variable.h
+        transformation_add_image_sample_unused_components.h
         transformation_add_local_variable.h
         transformation_add_local_variable.h
         transformation_add_no_contraction_decoration.h
         transformation_add_no_contraction_decoration.h
         transformation_add_parameter.h
         transformation_add_parameter.h
@@ -125,10 +128,12 @@ if(SPIRV_BUILD_FUZZER)
         transformation_permute_function_parameters.h
         transformation_permute_function_parameters.h
         transformation_permute_phi_operands.h
         transformation_permute_phi_operands.h
         transformation_push_id_through_variable.h
         transformation_push_id_through_variable.h
+        transformation_record_synonymous_constants.h
         transformation_replace_boolean_constant_with_constant_binary.h
         transformation_replace_boolean_constant_with_constant_binary.h
         transformation_replace_constant_with_uniform.h
         transformation_replace_constant_with_uniform.h
         transformation_replace_id_with_synonym.h
         transformation_replace_id_with_synonym.h
         transformation_replace_linear_algebra_instruction.h
         transformation_replace_linear_algebra_instruction.h
+        transformation_replace_parameter_with_global.h
         transformation_set_function_control.h
         transformation_set_function_control.h
         transformation_set_loop_control.h
         transformation_set_loop_control.h
         transformation_set_memory_operands_mask.h
         transformation_set_memory_operands_mask.h
@@ -158,6 +163,7 @@ if(SPIRV_BUILD_FUZZER)
         fuzzer_pass_add_equation_instructions.cpp
         fuzzer_pass_add_equation_instructions.cpp
         fuzzer_pass_add_function_calls.cpp
         fuzzer_pass_add_function_calls.cpp
         fuzzer_pass_add_global_variables.cpp
         fuzzer_pass_add_global_variables.cpp
+        fuzzer_pass_add_image_sample_unused_components.cpp
         fuzzer_pass_add_loads.cpp
         fuzzer_pass_add_loads.cpp
         fuzzer_pass_add_local_variables.cpp
         fuzzer_pass_add_local_variables.cpp
         fuzzer_pass_add_no_contraction_decorations.cpp
         fuzzer_pass_add_no_contraction_decorations.cpp
@@ -182,6 +188,7 @@ if(SPIRV_BUILD_FUZZER)
         fuzzer_pass_permute_phi_operands.cpp
         fuzzer_pass_permute_phi_operands.cpp
         fuzzer_pass_push_ids_through_variables.cpp
         fuzzer_pass_push_ids_through_variables.cpp
         fuzzer_pass_replace_linear_algebra_instructions.cpp
         fuzzer_pass_replace_linear_algebra_instructions.cpp
+        fuzzer_pass_replace_parameter_with_global.cpp
         fuzzer_pass_split_blocks.cpp
         fuzzer_pass_split_blocks.cpp
         fuzzer_pass_swap_commutable_operands.cpp
         fuzzer_pass_swap_commutable_operands.cpp
         fuzzer_pass_swap_conditional_branch_operands.cpp
         fuzzer_pass_swap_conditional_branch_operands.cpp
@@ -207,6 +214,7 @@ if(SPIRV_BUILD_FUZZER)
         transformation_add_function.cpp
         transformation_add_function.cpp
         transformation_add_global_undef.cpp
         transformation_add_global_undef.cpp
         transformation_add_global_variable.cpp
         transformation_add_global_variable.cpp
+        transformation_add_image_sample_unused_components.cpp
         transformation_add_local_variable.cpp
         transformation_add_local_variable.cpp
         transformation_add_no_contraction_decoration.cpp
         transformation_add_no_contraction_decoration.cpp
         transformation_add_parameter.cpp
         transformation_add_parameter.cpp
@@ -236,10 +244,12 @@ if(SPIRV_BUILD_FUZZER)
         transformation_permute_function_parameters.cpp
         transformation_permute_function_parameters.cpp
         transformation_permute_phi_operands.cpp
         transformation_permute_phi_operands.cpp
         transformation_push_id_through_variable.cpp
         transformation_push_id_through_variable.cpp
+        transformation_record_synonymous_constants.cpp
         transformation_replace_boolean_constant_with_constant_binary.cpp
         transformation_replace_boolean_constant_with_constant_binary.cpp
         transformation_replace_constant_with_uniform.cpp
         transformation_replace_constant_with_uniform.cpp
         transformation_replace_id_with_synonym.cpp
         transformation_replace_id_with_synonym.cpp
         transformation_replace_linear_algebra_instruction.cpp
         transformation_replace_linear_algebra_instruction.cpp
+        transformation_replace_parameter_with_global.cpp
         transformation_set_function_control.cpp
         transformation_set_function_control.cpp
         transformation_set_loop_control.cpp
         transformation_set_loop_control.cpp
         transformation_set_memory_operands_mask.cpp
         transformation_set_memory_operands_mask.cpp

+ 8 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer.cpp

@@ -30,6 +30,7 @@
 #include "source/fuzz/fuzzer_pass_add_equation_instructions.h"
 #include "source/fuzz/fuzzer_pass_add_equation_instructions.h"
 #include "source/fuzz/fuzzer_pass_add_function_calls.h"
 #include "source/fuzz/fuzzer_pass_add_function_calls.h"
 #include "source/fuzz/fuzzer_pass_add_global_variables.h"
 #include "source/fuzz/fuzzer_pass_add_global_variables.h"
+#include "source/fuzz/fuzzer_pass_add_image_sample_unused_components.h"
 #include "source/fuzz/fuzzer_pass_add_loads.h"
 #include "source/fuzz/fuzzer_pass_add_loads.h"
 #include "source/fuzz/fuzzer_pass_add_local_variables.h"
 #include "source/fuzz/fuzzer_pass_add_local_variables.h"
 #include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h"
 #include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h"
@@ -53,6 +54,7 @@
 #include "source/fuzz/fuzzer_pass_permute_phi_operands.h"
 #include "source/fuzz/fuzzer_pass_permute_phi_operands.h"
 #include "source/fuzz/fuzzer_pass_push_ids_through_variables.h"
 #include "source/fuzz/fuzzer_pass_push_ids_through_variables.h"
 #include "source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h"
 #include "source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h"
+#include "source/fuzz/fuzzer_pass_replace_parameter_with_global.h"
 #include "source/fuzz/fuzzer_pass_split_blocks.h"
 #include "source/fuzz/fuzzer_pass_split_blocks.h"
 #include "source/fuzz/fuzzer_pass_swap_commutable_operands.h"
 #include "source/fuzz/fuzzer_pass_swap_commutable_operands.h"
 #include "source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h"
 #include "source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h"
@@ -224,6 +226,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
     MaybeAddPass<FuzzerPassAddGlobalVariables>(
     MaybeAddPass<FuzzerPassAddGlobalVariables>(
         &passes, ir_context.get(), &transformation_context, &fuzzer_context,
         &passes, ir_context.get(), &transformation_context, &fuzzer_context,
         transformation_sequence_out);
         transformation_sequence_out);
+    MaybeAddPass<FuzzerPassAddImageSampleUnusedComponents>(
+        &passes, ir_context.get(), &transformation_context, &fuzzer_context,
+        transformation_sequence_out);
     MaybeAddPass<FuzzerPassAddLoads>(&passes, ir_context.get(),
     MaybeAddPass<FuzzerPassAddLoads>(&passes, ir_context.get(),
                                      &transformation_context, &fuzzer_context,
                                      &transformation_context, &fuzzer_context,
                                      transformation_sequence_out);
                                      transformation_sequence_out);
@@ -272,6 +277,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
     MaybeAddPass<FuzzerPassPushIdsThroughVariables>(
     MaybeAddPass<FuzzerPassPushIdsThroughVariables>(
         &passes, ir_context.get(), &transformation_context, &fuzzer_context,
         &passes, ir_context.get(), &transformation_context, &fuzzer_context,
         transformation_sequence_out);
         transformation_sequence_out);
+    MaybeAddPass<FuzzerPassReplaceParameterWithGlobal>(
+        &passes, ir_context.get(), &transformation_context, &fuzzer_context,
+        transformation_sequence_out);
     MaybeAddPass<FuzzerPassReplaceLinearAlgebraInstructions>(
     MaybeAddPass<FuzzerPassReplaceLinearAlgebraInstructions>(
         &passes, ir_context.get(), &transformation_context, &fuzzer_context,
         &passes, ir_context.get(), &transformation_context, &fuzzer_context,
         transformation_sequence_out);
         transformation_sequence_out);

+ 12 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp

@@ -34,6 +34,8 @@ const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadContinue = {5, 80};
 const std::pair<uint32_t, uint32_t> kChanceOfAddingEquationInstruction = {5,
 const std::pair<uint32_t, uint32_t> kChanceOfAddingEquationInstruction = {5,
                                                                           90};
                                                                           90};
 const std::pair<uint32_t, uint32_t> kChanceOfAddingGlobalVariable = {20, 90};
 const std::pair<uint32_t, uint32_t> kChanceOfAddingGlobalVariable = {20, 90};
+const std::pair<uint32_t, uint32_t> kChanceOfAddingImageSampleUnusedComponents =
+    {20, 90};
 const std::pair<uint32_t, uint32_t> kChanceOfAddingLoad = {5, 50};
 const std::pair<uint32_t, uint32_t> kChanceOfAddingLoad = {5, 50};
 const std::pair<uint32_t, uint32_t> kChanceOfAddingLocalVariable = {20, 90};
 const std::pair<uint32_t, uint32_t> kChanceOfAddingLocalVariable = {20, 90};
 const std::pair<uint32_t, uint32_t> kChanceOfAddingMatrixType = {20, 70};
 const std::pair<uint32_t, uint32_t> kChanceOfAddingMatrixType = {20, 70};
@@ -54,6 +56,8 @@ const std::pair<uint32_t, uint32_t> kChanceOfAdjustingSelectionControl = {20,
 const std::pair<uint32_t, uint32_t> kChanceOfCallingFunction = {1, 10};
 const std::pair<uint32_t, uint32_t> kChanceOfCallingFunction = {1, 10};
 const std::pair<uint32_t, uint32_t> kChanceOfChoosingStructTypeVsArrayType = {
 const std::pair<uint32_t, uint32_t> kChanceOfChoosingStructTypeVsArrayType = {
     20, 80};
     20, 80};
+const std::pair<uint32_t, uint32_t> kChanceOfChoosingWorkgroupStorageClass = {
+    50, 50};
 const std::pair<uint32_t, uint32_t> kChanceOfConstructingComposite = {20, 50};
 const std::pair<uint32_t, uint32_t> kChanceOfConstructingComposite = {20, 50};
 const std::pair<uint32_t, uint32_t> kChanceOfCopyingObject = {20, 50};
 const std::pair<uint32_t, uint32_t> kChanceOfCopyingObject = {20, 50};
 const std::pair<uint32_t, uint32_t> kChanceOfDonatingAdditionalModule = {5, 50};
 const std::pair<uint32_t, uint32_t> kChanceOfDonatingAdditionalModule = {5, 50};
@@ -72,6 +76,8 @@ const std::pair<uint32_t, uint32_t> kChanceOfPushingIdThroughVariable = {5, 50};
 const std::pair<uint32_t, uint32_t> kChanceOfReplacingIdWithSynonym = {10, 90};
 const std::pair<uint32_t, uint32_t> kChanceOfReplacingIdWithSynonym = {10, 90};
 const std::pair<uint32_t, uint32_t>
 const std::pair<uint32_t, uint32_t>
     kChanceOfReplacingLinearAlgebraInstructions = {10, 90};
     kChanceOfReplacingLinearAlgebraInstructions = {10, 90};
+const std::pair<uint32_t, uint32_t> kChanceOfReplacingParametersWithGlobals = {
+    30, 70};
 const std::pair<uint32_t, uint32_t> kChanceOfSplittingBlock = {40, 95};
 const std::pair<uint32_t, uint32_t> kChanceOfSplittingBlock = {40, 95};
 const std::pair<uint32_t, uint32_t> kChanceOfSwappingConditionalBranchOperands =
 const std::pair<uint32_t, uint32_t> kChanceOfSwappingConditionalBranchOperands =
     {10, 70};
     {10, 70};
@@ -135,6 +141,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
   chance_of_adding_global_variable_ =
   chance_of_adding_global_variable_ =
       ChooseBetweenMinAndMax(kChanceOfAddingGlobalVariable);
       ChooseBetweenMinAndMax(kChanceOfAddingGlobalVariable);
   chance_of_adding_load_ = ChooseBetweenMinAndMax(kChanceOfAddingLoad);
   chance_of_adding_load_ = ChooseBetweenMinAndMax(kChanceOfAddingLoad);
+  chance_of_adding_image_sample_unused_components_ =
+      ChooseBetweenMinAndMax(kChanceOfAddingImageSampleUnusedComponents);
   chance_of_adding_local_variable_ =
   chance_of_adding_local_variable_ =
       ChooseBetweenMinAndMax(kChanceOfAddingLocalVariable);
       ChooseBetweenMinAndMax(kChanceOfAddingLocalVariable);
   chance_of_adding_matrix_type_ =
   chance_of_adding_matrix_type_ =
@@ -162,6 +170,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
       ChooseBetweenMinAndMax(kChanceOfCallingFunction);
       ChooseBetweenMinAndMax(kChanceOfCallingFunction);
   chance_of_choosing_struct_type_vs_array_type_ =
   chance_of_choosing_struct_type_vs_array_type_ =
       ChooseBetweenMinAndMax(kChanceOfChoosingStructTypeVsArrayType);
       ChooseBetweenMinAndMax(kChanceOfChoosingStructTypeVsArrayType);
+  chance_of_choosing_workgroup_storage_class_ =
+      ChooseBetweenMinAndMax(kChanceOfChoosingWorkgroupStorageClass);
   chance_of_constructing_composite_ =
   chance_of_constructing_composite_ =
       ChooseBetweenMinAndMax(kChanceOfConstructingComposite);
       ChooseBetweenMinAndMax(kChanceOfConstructingComposite);
   chance_of_copying_object_ = ChooseBetweenMinAndMax(kChanceOfCopyingObject);
   chance_of_copying_object_ = ChooseBetweenMinAndMax(kChanceOfCopyingObject);
@@ -190,6 +200,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
       ChooseBetweenMinAndMax(kChanceOfReplacingIdWithSynonym);
       ChooseBetweenMinAndMax(kChanceOfReplacingIdWithSynonym);
   chance_of_replacing_linear_algebra_instructions_ =
   chance_of_replacing_linear_algebra_instructions_ =
       ChooseBetweenMinAndMax(kChanceOfReplacingLinearAlgebraInstructions);
       ChooseBetweenMinAndMax(kChanceOfReplacingLinearAlgebraInstructions);
+  chance_of_replacing_parameters_with_globals_ =
+      ChooseBetweenMinAndMax(kChanceOfReplacingParametersWithGlobals);
   chance_of_splitting_block_ = ChooseBetweenMinAndMax(kChanceOfSplittingBlock);
   chance_of_splitting_block_ = ChooseBetweenMinAndMax(kChanceOfSplittingBlock);
   chance_of_swapping_conditional_branch_operands_ =
   chance_of_swapping_conditional_branch_operands_ =
       ChooseBetweenMinAndMax(kChanceOfSwappingConditionalBranchOperands);
       ChooseBetweenMinAndMax(kChanceOfSwappingConditionalBranchOperands);

+ 17 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_context.h

@@ -128,6 +128,9 @@ class FuzzerContext {
   uint32_t GetChanceOfAddingGlobalVariable() {
   uint32_t GetChanceOfAddingGlobalVariable() {
     return chance_of_adding_global_variable_;
     return chance_of_adding_global_variable_;
   }
   }
+  uint32_t GetChanceOfAddingImageSampleUnusedComponents() {
+    return chance_of_adding_image_sample_unused_components_;
+  }
   uint32_t GetChanceOfAddingLoad() { return chance_of_adding_load_; }
   uint32_t GetChanceOfAddingLoad() { return chance_of_adding_load_; }
   uint32_t GetChanceOfAddingLocalVariable() {
   uint32_t GetChanceOfAddingLocalVariable() {
     return chance_of_adding_local_variable_;
     return chance_of_adding_local_variable_;
@@ -165,6 +168,9 @@ class FuzzerContext {
   uint32_t GetChanceOfChoosingStructTypeVsArrayType() {
   uint32_t GetChanceOfChoosingStructTypeVsArrayType() {
     return chance_of_choosing_struct_type_vs_array_type_;
     return chance_of_choosing_struct_type_vs_array_type_;
   }
   }
+  uint32_t GetChanceOfChoosingWorkgroupStorageClass() {
+    return chance_of_choosing_workgroup_storage_class_;
+  }
   uint32_t GetChanceOfConstructingComposite() {
   uint32_t GetChanceOfConstructingComposite() {
     return chance_of_constructing_composite_;
     return chance_of_constructing_composite_;
   }
   }
@@ -204,6 +210,9 @@ class FuzzerContext {
   uint32_t GetChanceOfReplacingLinearAlgebraInstructions() {
   uint32_t GetChanceOfReplacingLinearAlgebraInstructions() {
     return chance_of_replacing_linear_algebra_instructions_;
     return chance_of_replacing_linear_algebra_instructions_;
   }
   }
+  uint32_t GetChanceOfReplacingParametersWithGlobals() {
+    return chance_of_replacing_parameters_with_globals_;
+  }
   uint32_t GetChanceOfSplittingBlock() { return chance_of_splitting_block_; }
   uint32_t GetChanceOfSplittingBlock() { return chance_of_splitting_block_; }
   uint32_t GetChanceOfSwappingConditionalBranchOperands() {
   uint32_t GetChanceOfSwappingConditionalBranchOperands() {
     return chance_of_swapping_conditional_branch_operands_;
     return chance_of_swapping_conditional_branch_operands_;
@@ -265,6 +274,11 @@ class FuzzerContext {
     // Ensure that the array size is non-zero.
     // Ensure that the array size is non-zero.
     return random_generator_->RandomUint32(max_new_array_size_limit_ - 1) + 1;
     return random_generator_->RandomUint32(max_new_array_size_limit_ - 1) + 1;
   }
   }
+  uint32_t GetRandomUnusedComponentCountForImageSample(
+      uint32_t max_unused_component_count) {
+    // Ensure that the number of unused components is non-zero.
+    return random_generator_->RandomUint32(max_unused_component_count) + 1;
+  }
   bool GoDeeperInConstantObfuscation(uint32_t depth) {
   bool GoDeeperInConstantObfuscation(uint32_t depth) {
     return go_deeper_in_constant_obfuscation_(depth, random_generator_);
     return go_deeper_in_constant_obfuscation_(depth, random_generator_);
   }
   }
@@ -286,6 +300,7 @@ class FuzzerContext {
   uint32_t chance_of_adding_dead_continue_;
   uint32_t chance_of_adding_dead_continue_;
   uint32_t chance_of_adding_equation_instruction_;
   uint32_t chance_of_adding_equation_instruction_;
   uint32_t chance_of_adding_global_variable_;
   uint32_t chance_of_adding_global_variable_;
+  uint32_t chance_of_adding_image_sample_unused_components_;
   uint32_t chance_of_adding_load_;
   uint32_t chance_of_adding_load_;
   uint32_t chance_of_adding_local_variable_;
   uint32_t chance_of_adding_local_variable_;
   uint32_t chance_of_adding_matrix_type_;
   uint32_t chance_of_adding_matrix_type_;
@@ -301,6 +316,7 @@ class FuzzerContext {
   uint32_t chance_of_adjusting_selection_control_;
   uint32_t chance_of_adjusting_selection_control_;
   uint32_t chance_of_calling_function_;
   uint32_t chance_of_calling_function_;
   uint32_t chance_of_choosing_struct_type_vs_array_type_;
   uint32_t chance_of_choosing_struct_type_vs_array_type_;
+  uint32_t chance_of_choosing_workgroup_storage_class_;
   uint32_t chance_of_constructing_composite_;
   uint32_t chance_of_constructing_composite_;
   uint32_t chance_of_copying_object_;
   uint32_t chance_of_copying_object_;
   uint32_t chance_of_donating_additional_module_;
   uint32_t chance_of_donating_additional_module_;
@@ -316,6 +332,7 @@ class FuzzerContext {
   uint32_t chance_of_pushing_id_through_variable_;
   uint32_t chance_of_pushing_id_through_variable_;
   uint32_t chance_of_replacing_id_with_synonym_;
   uint32_t chance_of_replacing_id_with_synonym_;
   uint32_t chance_of_replacing_linear_algebra_instructions_;
   uint32_t chance_of_replacing_linear_algebra_instructions_;
+  uint32_t chance_of_replacing_parameters_with_globals_;
   uint32_t chance_of_splitting_block_;
   uint32_t chance_of_splitting_block_;
   uint32_t chance_of_swapping_conditional_branch_operands_;
   uint32_t chance_of_swapping_conditional_branch_operands_;
   uint32_t chance_of_toggling_access_chain_instruction_;
   uint32_t chance_of_toggling_access_chain_instruction_;

+ 22 - 5
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_global_variables.cpp

@@ -30,8 +30,22 @@ FuzzerPassAddGlobalVariables::FuzzerPassAddGlobalVariables(
 FuzzerPassAddGlobalVariables::~FuzzerPassAddGlobalVariables() = default;
 FuzzerPassAddGlobalVariables::~FuzzerPassAddGlobalVariables() = default;
 
 
 void FuzzerPassAddGlobalVariables::Apply() {
 void FuzzerPassAddGlobalVariables::Apply() {
+  SpvStorageClass variable_storage_class = SpvStorageClassPrivate;
+  for (auto& entry_point : GetIRContext()->module()->entry_points()) {
+    // If the execution model of some entry point is GLCompute,
+    // then the variable storage class may be Workgroup.
+    if (entry_point.GetSingleWordInOperand(0) == SpvExecutionModelGLCompute) {
+      variable_storage_class =
+          GetFuzzerContext()->ChoosePercentage(
+              GetFuzzerContext()->GetChanceOfChoosingWorkgroupStorageClass())
+              ? SpvStorageClassWorkgroup
+              : SpvStorageClassPrivate;
+      break;
+    }
+  }
+
   auto basic_type_ids_and_pointers =
   auto basic_type_ids_and_pointers =
-      GetAvailableBasicTypesAndPointers(SpvStorageClassPrivate);
+      GetAvailableBasicTypesAndPointers(variable_storage_class);
 
 
   // These are the basic types that are available to this fuzzer pass.
   // These are the basic types that are available to this fuzzer pass.
   auto& basic_types = basic_type_ids_and_pointers.first;
   auto& basic_types = basic_type_ids_and_pointers.first;
@@ -59,18 +73,21 @@ void FuzzerPassAddGlobalVariables::Apply() {
       pointer_type_id = GetFuzzerContext()->GetFreshId();
       pointer_type_id = GetFuzzerContext()->GetFreshId();
       available_pointers_to_basic_type.push_back(pointer_type_id);
       available_pointers_to_basic_type.push_back(pointer_type_id);
       ApplyTransformation(TransformationAddTypePointer(
       ApplyTransformation(TransformationAddTypePointer(
-          pointer_type_id, SpvStorageClassPrivate, basic_type));
+          pointer_type_id, variable_storage_class, basic_type));
     } else {
     } else {
       // There is - grab one.
       // There is - grab one.
       pointer_type_id =
       pointer_type_id =
           available_pointers_to_basic_type[GetFuzzerContext()->RandomIndex(
           available_pointers_to_basic_type[GetFuzzerContext()->RandomIndex(
               available_pointers_to_basic_type)];
               available_pointers_to_basic_type)];
     }
     }
-    // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3274):  We could
-    //  add new variables with Workgroup storage class in compute shaders.
+
     ApplyTransformation(TransformationAddGlobalVariable(
     ApplyTransformation(TransformationAddGlobalVariable(
         GetFuzzerContext()->GetFreshId(), pointer_type_id,
         GetFuzzerContext()->GetFreshId(), pointer_type_id,
-        SpvStorageClassPrivate, FindOrCreateZeroConstant(basic_type), true));
+        variable_storage_class,
+        variable_storage_class == SpvStorageClassPrivate
+            ? FindOrCreateZeroConstant(basic_type)
+            : 0,
+        true));
   }
   }
 }
 }
 
 

+ 200 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.cpp

@@ -0,0 +1,200 @@
+// Copyright (c) 2020 André Perez Maselco
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/fuzzer_pass_add_image_sample_unused_components.h"
+
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "source/fuzz/transformation_add_image_sample_unused_components.h"
+#include "source/fuzz/transformation_composite_construct.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassAddImageSampleUnusedComponents::
+    FuzzerPassAddImageSampleUnusedComponents(
+        opt::IRContext* ir_context,
+        TransformationContext* transformation_context,
+        FuzzerContext* fuzzer_context,
+        protobufs::TransformationSequence* transformations)
+    : FuzzerPass(ir_context, transformation_context, fuzzer_context,
+                 transformations) {}
+
+FuzzerPassAddImageSampleUnusedComponents::
+    ~FuzzerPassAddImageSampleUnusedComponents() = default;
+
+void FuzzerPassAddImageSampleUnusedComponents::Apply() {
+  // SPIR-V module to help understand the transformation.
+  //
+  //       OpCapability Shader
+  //  %1 = OpExtInstImport "GLSL.std.450"
+  //       OpMemoryModel Logical GLSL450
+  //       OpEntryPoint Fragment %15 "main" %12 %14
+  //       OpExecutionMode %15 OriginUpperLeft
+  //
+  // ; Decorations
+  //        OpDecorate %12 Location 0 ; Input color variable location
+  //        OpDecorate %13 DescriptorSet 0 ; Image coordinate variable
+  //        descriptor set OpDecorate %13 Binding 0 ; Image coordinate
+  //        variable binding OpDecorate %14 Location 0 ; Fragment color
+  //        variable location
+  //
+  // ; Types
+  //  %2 = OpTypeVoid
+  //  %3 = OpTypeFunction %2
+  //  %4 = OpTypeFloat 32
+  //  %5 = OpTypeVector %4 2
+  //  %6 = OpTypeVector %4 4
+  //  %7 = OpTypeImage %4 2D 0 0 0 1 Rgba32f
+  //  %8 = OpTypeSampledImage %7
+  //  %9 = OpTypePointer Input %5
+  // %10 = OpTypePointer UniformConstant %8
+  // %11 = OpTypePointer Output %6
+  //
+  // ; Variables
+  // %12 = OpVariable %9 Input ; Input image coordinate variable
+  // %13 = OpVariable %10 UniformConstant ; Image variable
+  // %14 = OpVariable %11 Output ; Fragment color variable
+  //
+  // ; main function
+  // %15 = OpFunction %2 None %3
+  // %16 = OpLabel
+  // %17 = OpLoad %5 %12
+  // %18 = OpLoad %8 %13
+  // %19 = OpImageSampleImplicitLod %6 %18 %17
+  //       OpStore %14 %19
+  //       OpReturn
+  //       OpFunctionEnd
+
+  GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) {
+    // |instruction| %19 = OpImageSampleImplicitLod %6 %18 %17
+    if (!spvOpcodeIsImageSample(instruction->opcode())) {
+      return;
+    }
+
+    if (!GetFuzzerContext()->ChoosePercentage(
+            GetFuzzerContext()
+                ->GetChanceOfAddingImageSampleUnusedComponents())) {
+      return;
+    }
+
+    // Gets image sample coordinate information.
+    // |coordinate_instruction| %17 = OpLoad %5 %12
+    uint32_t coordinate_id = instruction->GetSingleWordInOperand(1);
+    auto coordinate_instruction =
+        GetIRContext()->get_def_use_mgr()->GetDef(coordinate_id);
+    auto coordinate_type = GetIRContext()->get_type_mgr()->GetType(
+        coordinate_instruction->type_id());
+
+    // If the coordinate is a 4-dimensional vector, then no unused components
+    // may be added.
+    if (coordinate_type->AsVector() &&
+        coordinate_type->AsVector()->element_count() == 4) {
+      return;
+    }
+
+    // If the coordinate is a scalar, then at most 3 unused components may be
+    // added. If the coordinate is a vector, then the maximum number of unused
+    // components depends on the vector size.
+    // For the sample module, the coordinate type instruction is %5 =
+    // OpTypeVector %4 2, thus |max_unused_component_count| = 4 - 2 = 2.
+    uint32_t max_unused_component_count =
+        coordinate_type->AsInteger() || coordinate_type->AsFloat()
+            ? 3
+            : 4 - coordinate_type->AsVector()->element_count();
+
+    // |unused_component_count| may be 1 or 2.
+    uint32_t unused_component_count =
+        GetFuzzerContext()->GetRandomUnusedComponentCountForImageSample(
+            max_unused_component_count);
+
+    // Gets a type for the zero-unused components.
+    uint32_t zero_constant_type_id;
+    switch (unused_component_count) {
+      case 1:
+        // If the coordinate is an integer or float, then the unused components
+        // type is the same as the coordinate. If the coordinate is a vector,
+        // then the unused components type is the same as the vector components
+        // type.
+        zero_constant_type_id =
+            coordinate_type->AsInteger() || coordinate_type->AsFloat()
+                ? coordinate_instruction->type_id()
+                : GetIRContext()->get_type_mgr()->GetId(
+                      coordinate_type->AsVector()->element_type());
+        break;
+      case 2:
+      case 3:
+        // If the coordinate is an integer or float, then the unused components
+        // type is the same as the coordinate. If the coordinate is a vector,
+        // then the unused components type is the same as the coordinate
+        // components type.
+        // |zero_constant_type_id| %5 = OpTypeVector %4 2
+        zero_constant_type_id =
+            coordinate_type->AsInteger() || coordinate_type->AsFloat()
+                ? FindOrCreateVectorType(coordinate_instruction->type_id(),
+                                         unused_component_count)
+                : FindOrCreateVectorType(
+                      GetIRContext()->get_type_mgr()->GetId(
+                          coordinate_type->AsVector()->element_type()),
+                      unused_component_count);
+        break;
+      default:
+        assert(false && "Should be unreachable.");
+        zero_constant_type_id = 0;
+        break;
+    }
+
+    // Gets |coordinate_type| again because the module may have changed due to
+    // the use of FindOrCreateVectorType above.
+    coordinate_type = GetIRContext()->get_type_mgr()->GetType(
+        coordinate_instruction->type_id());
+
+    // If the new vector type with unused components does not exist, then create
+    // it. |coordinate_with_unused_components_type_id| %6 = OpTypeVector %4 4
+    uint32_t coordinate_with_unused_components_type_id =
+        coordinate_type->AsInteger() || coordinate_type->AsFloat()
+            ? FindOrCreateVectorType(coordinate_instruction->type_id(),
+                                     1 + unused_component_count)
+            : FindOrCreateVectorType(
+                  GetIRContext()->get_type_mgr()->GetId(
+                      coordinate_type->AsVector()->element_type()),
+                  coordinate_type->AsVector()->element_count() +
+                      unused_component_count);
+
+    // Inserts an OpCompositeConstruct instruction which
+    // represents the coordinate with unused components.
+    // |coordinate_with_unused_components_id|
+    // %22 = OpCompositeConstruct %6 %17 %21
+    uint32_t coordinate_with_unused_components_id =
+        GetFuzzerContext()->GetFreshId();
+    ApplyTransformation(TransformationCompositeConstruct(
+        coordinate_with_unused_components_type_id,
+        {coordinate_instruction->result_id(),
+         // FindOrCreateZeroConstant
+         // %20 = OpConstant %4 0
+         // %21 = OpConstantComposite %5 %20 %20
+         FindOrCreateZeroConstant(zero_constant_type_id)},
+        MakeInstructionDescriptor(GetIRContext(), instruction),
+        coordinate_with_unused_components_id));
+
+    // Tries to add unused components to the image sample coordinate.
+    // %19 = OpImageSampleImplicitLod %6 %18 %22
+    ApplyTransformation(TransformationAddImageSampleUnusedComponents(
+        coordinate_with_unused_components_id,
+        MakeInstructionDescriptor(GetIRContext(), instruction)));
+  });
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 41 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_image_sample_unused_components.h

@@ -0,0 +1,41 @@
+// Copyright (c) 2020 André Perez Maselco
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_FUZZER_PASS_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_
+#define SOURCE_FUZZ_FUZZER_PASS_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// This fuzzer pass searches for image sample instructions in the module and
+// randomly applies the transformation to add unused components to the image
+// sample coordinate.
+class FuzzerPassAddImageSampleUnusedComponents : public FuzzerPass {
+ public:
+  FuzzerPassAddImageSampleUnusedComponents(
+      opt::IRContext* ir_context, TransformationContext* transformation_context,
+      FuzzerContext* fuzzer_context,
+      protobufs::TransformationSequence* transformations);
+
+  ~FuzzerPassAddImageSampleUnusedComponents();
+
+  void Apply() override;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_FUZZER_PASS_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_

+ 2 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp

@@ -43,6 +43,8 @@ void FuzzerPassReplaceLinearAlgebraInstructions::Apply() {
     // |spvOpcodeIsLinearAlgebra|.
     // |spvOpcodeIsLinearAlgebra|.
     if (instruction->opcode() != SpvOpVectorTimesScalar &&
     if (instruction->opcode() != SpvOpVectorTimesScalar &&
         instruction->opcode() != SpvOpMatrixTimesScalar &&
         instruction->opcode() != SpvOpMatrixTimesScalar &&
+        instruction->opcode() != SpvOpVectorTimesMatrix &&
+        instruction->opcode() != SpvOpMatrixTimesVector &&
         instruction->opcode() != SpvOpDot) {
         instruction->opcode() != SpvOpDot) {
       return;
       return;
     }
     }

+ 92 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.cpp

@@ -0,0 +1,92 @@
+// Copyright (c) 2020 Vasyl Teliman
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/fuzzer_pass_replace_parameter_with_global.h"
+
+#include <numeric>
+#include <vector>
+
+#include "source/fuzz/fuzzer_context.h"
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/transformation_replace_parameter_with_global.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassReplaceParameterWithGlobal::FuzzerPassReplaceParameterWithGlobal(
+    opt::IRContext* ir_context, TransformationContext* transformation_context,
+    FuzzerContext* fuzzer_context,
+    protobufs::TransformationSequence* transformations)
+    : FuzzerPass(ir_context, transformation_context, fuzzer_context,
+                 transformations) {}
+
+FuzzerPassReplaceParameterWithGlobal::~FuzzerPassReplaceParameterWithGlobal() =
+    default;
+
+void FuzzerPassReplaceParameterWithGlobal::Apply() {
+  for (const auto& function : *GetIRContext()->module()) {
+    if (fuzzerutil::FunctionIsEntryPoint(GetIRContext(),
+                                         function.result_id())) {
+      continue;
+    }
+
+    if (!GetFuzzerContext()->ChoosePercentage(
+            GetFuzzerContext()->GetChanceOfReplacingParametersWithGlobals())) {
+      continue;
+    }
+
+    auto params =
+        fuzzerutil::GetParameters(GetIRContext(), function.result_id());
+
+    // Make sure at least one parameter can be replaced. Also checks that the
+    // function has at least one parameter.
+    if (std::none_of(params.begin(), params.end(),
+                     [this](const opt::Instruction* param) {
+                       const auto* param_type =
+                           GetIRContext()->get_type_mgr()->GetType(
+                               param->type_id());
+                       assert(param_type && "Parameter has invalid type");
+                       return TransformationReplaceParameterWithGlobal::
+                           CanReplaceFunctionParameterType(*param_type);
+                     })) {
+      continue;
+    }
+
+    // Select id of a parameter to replace.
+    const opt::Instruction* replaced_param = nullptr;
+    const opt::analysis::Type* param_type = nullptr;
+    do {
+      replaced_param = GetFuzzerContext()->RemoveAtRandomIndex(&params);
+      param_type =
+          GetIRContext()->get_type_mgr()->GetType(replaced_param->type_id());
+      assert(param_type && "Parameter has invalid type");
+    } while (!TransformationReplaceParameterWithGlobal::
+                 CanReplaceFunctionParameterType(*param_type));
+
+    assert(replaced_param && "Unable to find a parameter to replace");
+
+    // Make sure type id for the global variable exists in the module.
+    FindOrCreatePointerType(replaced_param->type_id(), SpvStorageClassPrivate);
+
+    // Make sure initializer for the global variable exists in the module.
+    FindOrCreateZeroConstant(replaced_param->type_id());
+
+    ApplyTransformation(TransformationReplaceParameterWithGlobal(
+        GetFuzzerContext()->GetFreshId(), replaced_param->result_id(),
+        GetFuzzerContext()->GetFreshId()));
+  }
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 40 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_parameter_with_global.h

@@ -0,0 +1,40 @@
+// Copyright (c) 2020 Vasyl Teliman
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_FUZZER_PASS_REPLACE_PARAMETER_WITH_GLOBAL_H_
+#define SOURCE_FUZZ_FUZZER_PASS_REPLACE_PARAMETER_WITH_GLOBAL_H_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// Iterates over all non-entry-point functions in the module and randomly
+// replaces a parameter with a global variable.
+class FuzzerPassReplaceParameterWithGlobal : public FuzzerPass {
+ public:
+  FuzzerPassReplaceParameterWithGlobal(
+      opt::IRContext* ir_context, TransformationContext* transformation_context,
+      FuzzerContext* fuzzer_context,
+      protobufs::TransformationSequence* transformations);
+
+  ~FuzzerPassReplaceParameterWithGlobal() override;
+
+  void Apply() override;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_FUZZER_PASS_REPLACE_PARAMETER_WITH_GLOBAL_H_

+ 197 - 14
3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp

@@ -112,19 +112,6 @@ bool PhiIdsOkForNewEdge(
   return true;
   return true;
 }
 }
 
 
-uint32_t MaybeGetBoolConstantId(opt::IRContext* context, bool value) {
-  opt::analysis::Bool bool_type;
-  auto registered_bool_type =
-      context->get_type_mgr()->GetRegisteredType(&bool_type);
-  if (!registered_bool_type) {
-    return 0;
-  }
-  opt::analysis::BoolConstant bool_constant(registered_bool_type->AsBool(),
-                                            value);
-  return context->get_constant_mgr()->FindDeclaredConstant(
-      &bool_constant, context->get_type_mgr()->GetId(&bool_type));
-}
-
 void AddUnreachableEdgeAndUpdateOpPhis(
 void AddUnreachableEdgeAndUpdateOpPhis(
     opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to,
     opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to,
     bool condition_value,
     bool condition_value,
@@ -135,7 +122,7 @@ void AddUnreachableEdgeAndUpdateOpPhis(
          "Precondition on terminator of bb_from is not satisfied");
          "Precondition on terminator of bb_from is not satisfied");
 
 
   // Get the id of the boolean constant to be used as the condition.
   // Get the id of the boolean constant to be used as the condition.
-  uint32_t bool_id = MaybeGetBoolConstantId(context, condition_value);
+  uint32_t bool_id = MaybeGetBoolConstant(context, condition_value);
   assert(
   assert(
       bool_id &&
       bool_id &&
       "Precondition that condition value must be available is not satisfied");
       "Precondition that condition value must be available is not satisfied");
@@ -627,6 +614,7 @@ void AddGlobalVariable(opt::IRContext* context, uint32_t result_id,
       context, SpvOpVariable, type_id, result_id, std::move(operands)));
       context, SpvOpVariable, type_id, result_id, std::move(operands)));
 
 
   AddVariableIdToEntryPointInterfaces(context, result_id);
   AddVariableIdToEntryPointInterfaces(context, result_id);
+  UpdateModuleIdBound(context, result_id);
 }
 }
 
 
 void AddLocalVariable(opt::IRContext* context, uint32_t result_id,
 void AddLocalVariable(opt::IRContext* context, uint32_t result_id,
@@ -657,6 +645,8 @@ void AddLocalVariable(opt::IRContext* context, uint32_t result_id,
       opt::Instruction::OperandList{
       opt::Instruction::OperandList{
           {SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}},
           {SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassFunction}},
           {SPV_OPERAND_TYPE_ID, {initializer_id}}}));
           {SPV_OPERAND_TYPE_ID, {initializer_id}}}));
+
+  UpdateModuleIdBound(context, result_id);
 }
 }
 
 
 bool HasDuplicates(const std::vector<uint32_t>& arr) {
 bool HasDuplicates(const std::vector<uint32_t>& arr) {
@@ -771,6 +761,199 @@ uint32_t MaybeGetStructType(opt::IRContext* ir_context,
   return ir_context->get_type_mgr()->GetId(&type);
   return ir_context->get_type_mgr()->GetId(&type);
 }
 }
 
 
+uint32_t MaybeGetZeroConstant(opt::IRContext* ir_context,
+                              uint32_t scalar_or_composite_type_id) {
+  const auto* type =
+      ir_context->get_type_mgr()->GetType(scalar_or_composite_type_id);
+  assert(type && "|scalar_or_composite_type_id| is invalid");
+
+  switch (type->kind()) {
+    case opt::analysis::Type::kBool:
+      return MaybeGetBoolConstant(ir_context, false);
+    case opt::analysis::Type::kFloat:
+    case opt::analysis::Type::kInteger: {
+      std::vector<uint32_t> words = {0};
+      if ((type->AsInteger() && type->AsInteger()->width() > 32) ||
+          (type->AsFloat() && type->AsFloat()->width() > 32)) {
+        words.push_back(0);
+      }
+
+      return MaybeGetScalarConstant(ir_context, words,
+                                    scalar_or_composite_type_id);
+    }
+    case opt::analysis::Type::kStruct: {
+      std::vector<uint32_t> component_ids;
+      for (const auto* component_type : type->AsStruct()->element_types()) {
+        auto component_type_id =
+            ir_context->get_type_mgr()->GetId(component_type);
+        assert(component_type_id && "Component type is invalid");
+
+        auto component_id = MaybeGetZeroConstant(ir_context, component_type_id);
+        if (component_id == 0) {
+          return 0;
+        }
+
+        component_ids.push_back(component_id);
+      }
+
+      return MaybeGetCompositeConstant(ir_context, component_ids,
+                                       scalar_or_composite_type_id);
+    }
+    case opt::analysis::Type::kMatrix:
+    case opt::analysis::Type::kVector: {
+      const auto* component_type = type->AsVector()
+                                       ? type->AsVector()->element_type()
+                                       : type->AsMatrix()->element_type();
+      auto component_type_id =
+          ir_context->get_type_mgr()->GetId(component_type);
+      assert(component_type_id && "Component type is invalid");
+
+      if (auto component_id =
+              MaybeGetZeroConstant(ir_context, component_type_id)) {
+        auto component_count = type->AsVector()
+                                   ? type->AsVector()->element_count()
+                                   : type->AsMatrix()->element_count();
+        return MaybeGetCompositeConstant(
+            ir_context, std::vector<uint32_t>(component_count, component_id),
+            scalar_or_composite_type_id);
+      }
+
+      return 0;
+    }
+    case opt::analysis::Type::kArray: {
+      auto component_type_id =
+          ir_context->get_type_mgr()->GetId(type->AsArray()->element_type());
+      assert(component_type_id && "Component type is invalid");
+
+      if (auto component_id =
+              MaybeGetZeroConstant(ir_context, component_type_id)) {
+        auto type_id = ir_context->get_type_mgr()->GetId(type);
+        assert(type_id && "|type| is invalid");
+
+        const auto* type_inst = ir_context->get_def_use_mgr()->GetDef(type_id);
+        assert(type_inst && "Array's type id is invalid");
+
+        return MaybeGetCompositeConstant(
+            ir_context,
+            std::vector<uint32_t>(GetArraySize(*type_inst, ir_context),
+                                  component_id),
+            scalar_or_composite_type_id);
+      }
+
+      return 0;
+    }
+    default:
+      assert(false && "Type is not supported");
+      return 0;
+  }
+}
+
+uint32_t MaybeGetScalarConstant(opt::IRContext* ir_context,
+                                const std::vector<uint32_t>& words,
+                                uint32_t scalar_type_id) {
+  const auto* type = ir_context->get_type_mgr()->GetType(scalar_type_id);
+  assert(type && "|scalar_type_id| is invalid");
+
+  if (const auto* int_type = type->AsInteger()) {
+    return MaybeGetIntegerConstant(ir_context, words, int_type->width(),
+                                   int_type->IsSigned());
+  } else if (const auto* float_type = type->AsFloat()) {
+    return MaybeGetFloatConstant(ir_context, words, float_type->width());
+  } else {
+    assert(type->AsBool() && words.size() == 1 &&
+           "|scalar_type_id| doesn't represent a scalar type");
+    return MaybeGetBoolConstant(ir_context, words[0]);
+  }
+}
+
+uint32_t MaybeGetCompositeConstant(opt::IRContext* ir_context,
+                                   const std::vector<uint32_t>& component_ids,
+                                   uint32_t composite_type_id) {
+  std::vector<const opt::analysis::Constant*> constants;
+  for (auto id : component_ids) {
+    const auto* component_constant =
+        ir_context->get_constant_mgr()->FindDeclaredConstant(id);
+    assert(component_constant && "|id| is invalid");
+
+    constants.push_back(component_constant);
+  }
+
+  const auto* type = ir_context->get_type_mgr()->GetType(composite_type_id);
+  assert(type && "|composite_type_id| is invalid");
+
+  std::unique_ptr<opt::analysis::Constant> composite_constant;
+  switch (type->kind()) {
+    case opt::analysis::Type::kStruct:
+      composite_constant = MakeUnique<opt::analysis::StructConstant>(
+          type->AsStruct(), std::move(constants));
+      break;
+    case opt::analysis::Type::kVector:
+      composite_constant = MakeUnique<opt::analysis::VectorConstant>(
+          type->AsVector(), std::move(constants));
+      break;
+    case opt::analysis::Type::kMatrix:
+      composite_constant = MakeUnique<opt::analysis::MatrixConstant>(
+          type->AsMatrix(), std::move(constants));
+      break;
+    case opt::analysis::Type::kArray:
+      composite_constant = MakeUnique<opt::analysis::ArrayConstant>(
+          type->AsArray(), std::move(constants));
+      break;
+    default:
+      assert(false &&
+             "|composite_type_id| is not a result id of a composite type");
+      return 0;
+  }
+
+  return ir_context->get_constant_mgr()->FindDeclaredConstant(
+      composite_constant.get(), composite_type_id);
+}
+
+uint32_t MaybeGetIntegerConstant(opt::IRContext* ir_context,
+                                 const std::vector<uint32_t>& words,
+                                 uint32_t width, bool is_signed) {
+  auto type_id = MaybeGetIntegerType(ir_context, width, is_signed);
+  if (!type_id) {
+    return 0;
+  }
+
+  const auto* type = ir_context->get_type_mgr()->GetType(type_id);
+  assert(type && "|type_id| is invalid");
+
+  opt::analysis::IntConstant constant(type->AsInteger(), words);
+  return ir_context->get_constant_mgr()->FindDeclaredConstant(&constant,
+                                                              type_id);
+}
+
+uint32_t MaybeGetFloatConstant(opt::IRContext* ir_context,
+                               const std::vector<uint32_t>& words,
+                               uint32_t width) {
+  auto type_id = MaybeGetFloatType(ir_context, width);
+  if (!type_id) {
+    return 0;
+  }
+
+  const auto* type = ir_context->get_type_mgr()->GetType(type_id);
+  assert(type && "|type_id| is invalid");
+
+  opt::analysis::FloatConstant constant(type->AsFloat(), words);
+  return ir_context->get_constant_mgr()->FindDeclaredConstant(&constant,
+                                                              type_id);
+}
+
+uint32_t MaybeGetBoolConstant(opt::IRContext* context, bool value) {
+  opt::analysis::Bool bool_type;
+  auto registered_bool_type =
+      context->get_type_mgr()->GetRegisteredType(&bool_type);
+  if (!registered_bool_type) {
+    return 0;
+  }
+  opt::analysis::BoolConstant bool_constant(registered_bool_type->AsBool(),
+                                            value);
+  return context->get_constant_mgr()->FindDeclaredConstant(
+      &bool_constant, context->get_type_mgr()->GetId(&bool_type));
+}
+
 void AddIntegerType(opt::IRContext* ir_context, uint32_t result_id,
 void AddIntegerType(opt::IRContext* ir_context, uint32_t result_id,
                     uint32_t width, bool is_signed) {
                     uint32_t width, bool is_signed) {
   ir_context->module()->AddType(MakeUnique<opt::Instruction>(
   ir_context->module()->AddType(MakeUnique<opt::Instruction>(

+ 45 - 5
3rdparty/spirv-tools/source/fuzz/fuzzer_util.h

@@ -53,10 +53,6 @@ bool PhiIdsOkForNewEdge(
     opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to,
     opt::IRContext* context, opt::BasicBlock* bb_from, opt::BasicBlock* bb_to,
     const google::protobuf::RepeatedField<google::protobuf::uint32>& phi_ids);
     const google::protobuf::RepeatedField<google::protobuf::uint32>& phi_ids);
 
 
-// Returns the id of a boolean constant with value |value| if it exists in the
-// module, or 0 otherwise.
-uint32_t MaybeGetBoolConstantId(opt::IRContext* context, bool value);
-
 // Requires that a boolean constant with value |condition_value| is available,
 // Requires that a boolean constant with value |condition_value| is available,
 // that PhiIdsOkForNewEdge(context, bb_from, bb_to, phi_ids) holds, and that
 // that PhiIdsOkForNewEdge(context, bb_from, bb_to, phi_ids) holds, and that
 // bb_from ends with "OpBranch %some_block".  Turns OpBranch into
 // bb_from ends with "OpBranch %some_block".  Turns OpBranch into
@@ -229,7 +225,8 @@ void AddVariableIdToEntryPointInterfaces(opt::IRContext* context, uint32_t id);
 // Adds a global variable with storage class |storage_class| to the module, with
 // Adds a global variable with storage class |storage_class| to the module, with
 // type |type_id| and either no initializer or |initializer_id| as an
 // type |type_id| and either no initializer or |initializer_id| as an
 // initializer, depending on whether |initializer_id| is 0. The global variable
 // initializer, depending on whether |initializer_id| is 0. The global variable
-// has result id |result_id|.
+// has result id |result_id|. Updates module's id bound to accommodate for
+// |result_id|.
 //
 //
 // - |type_id| must be the id of a pointer type with the same storage class as
 // - |type_id| must be the id of a pointer type with the same storage class as
 //   |storage_class|.
 //   |storage_class|.
@@ -243,6 +240,7 @@ void AddGlobalVariable(opt::IRContext* context, uint32_t result_id,
 
 
 // Adds an instruction to the start of |function_id|, of the form:
 // Adds an instruction to the start of |function_id|, of the form:
 //   |result_id| = OpVariable |type_id| Function |initializer_id|.
 //   |result_id| = OpVariable |type_id| Function |initializer_id|.
+// Updates module's id bound to accommodate for |result_id|.
 //
 //
 // - |type_id| must be the id of a pointer type with Function storage class.
 // - |type_id| must be the id of a pointer type with Function storage class.
 // - |initializer_id| must be the id of a constant with the same type as the
 // - |initializer_id| must be the id of a constant with the same type as the
@@ -306,6 +304,48 @@ uint32_t MaybeGetVectorType(opt::IRContext* ir_context,
 uint32_t MaybeGetStructType(opt::IRContext* ir_context,
 uint32_t MaybeGetStructType(opt::IRContext* ir_context,
                             const std::vector<uint32_t>& component_type_ids);
                             const std::vector<uint32_t>& component_type_ids);
 
 
+// Recursive definition is the following:
+// - if |scalar_or_composite_type_id| is a result id of a scalar type - returns
+//   a result id of the following constants (depending on the type): int -> 0,
+//   float -> 0.0, bool -> false.
+// - otherwise, returns a result id of an OpConstantComposite instruction.
+//   Every component of the composite constant is looked up by calling this
+//   function with the type id of that component.
+// Returns 0 if no such instruction is present in the module.
+uint32_t MaybeGetZeroConstant(opt::IRContext* ir_context,
+                              uint32_t scalar_or_composite_type_id);
+
+// Returns the result id of an OpConstant instruction. |scalar_type_id| must be
+// a result id of a scalar type (i.e. int, float or bool). Returns 0 if no such
+// instruction is present in the module.
+uint32_t MaybeGetScalarConstant(opt::IRContext* ir_context,
+                                const std::vector<uint32_t>& words,
+                                uint32_t scalar_type_id);
+
+// Returns the result id of an OpConstantComposite instruction.
+// |composite_type_id| must be a result id of a composite type (i.e. vector,
+// matrix, struct or array). Returns 0 if no such instruction is present in the
+// module.
+uint32_t MaybeGetCompositeConstant(opt::IRContext* ir_context,
+                                   const std::vector<uint32_t>& component_ids,
+                                   uint32_t composite_type_id);
+
+// Returns the result id of an OpConstant instruction of integral type.
+// Returns 0 if no such instruction or type is present in the module.
+uint32_t MaybeGetIntegerConstant(opt::IRContext* ir_context,
+                                 const std::vector<uint32_t>& words,
+                                 uint32_t width, bool is_signed);
+
+// Returns the result id of an OpConstant instruction of floating-point type.
+// Returns 0 if no such instruction or type is present in the module.
+uint32_t MaybeGetFloatConstant(opt::IRContext* ir_context,
+                               const std::vector<uint32_t>& words,
+                               uint32_t width);
+
+// Returns the id of a boolean constant with value |value| if it exists in the
+// module, or 0 otherwise.
+uint32_t MaybeGetBoolConstant(opt::IRContext* context, bool value);
+
 // Creates a new OpTypeInt instruction in the module. Updates module's id bound
 // Creates a new OpTypeInt instruction in the module. Updates module's id bound
 // to accommodate for |result_id|.
 // to accommodate for |result_id|.
 void AddIntegerType(opt::IRContext* ir_context, uint32_t result_id,
 void AddIntegerType(opt::IRContext* ir_context, uint32_t result_id,

+ 54 - 2
3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto

@@ -383,6 +383,9 @@ message Transformation {
     TransformationAddParameter add_parameter = 52;
     TransformationAddParameter add_parameter = 52;
     TransformationAddCopyMemory add_copy_memory = 53;
     TransformationAddCopyMemory add_copy_memory = 53;
     TransformationInvertComparisonOperator invert_comparison_operator = 54;
     TransformationInvertComparisonOperator invert_comparison_operator = 54;
+    TransformationAddImageSampleUnusedComponents add_image_sample_unused_components = 55;
+    TransformationReplaceParameterWithGlobal replace_parameter_with_global = 56;
+    TransformationRecordSynonymousConstants record_synonymous_constants = 57;
     // Add additional option using the next available number.
     // Add additional option using the next available number.
   }
   }
 }
 }
@@ -616,6 +619,18 @@ message TransformationAddGlobalVariable {
 
 
 }
 }
 
 
+message TransformationAddImageSampleUnusedComponents {
+
+  // A transformation that adds unused components to an image sample coordinate.
+
+  // An vector id with the original coordinate and the unused components.
+  uint32 coordinate_with_unused_components_id = 1;
+
+  // A descriptor for an image sample instruction.
+  InstructionDescriptor instruction_descriptor = 2;
+
+}
+
 message TransformationAddLocalVariable {
 message TransformationAddLocalVariable {
 
 
   // Adds a local variable of the given type (which must be a pointer with
   // Adds a local variable of the given type (which must be a pointer with
@@ -1109,6 +1124,43 @@ message TransformationPushIdThroughVariable {
 
 
 }
 }
 
 
+message TransformationRecordSynonymousConstants {
+
+  // A transformation that, given the IDs to two synonymous constants,
+  // records the fact that they are synonymous. The module is not changed.
+  // Two constants are synonymous if:
+  // - they have the same type (ignoring the presence of integer sign)
+  // - they have the same opcode (one of OpConstant, OpConstantTrue,
+  //   OpConstantFalse, OpConstantNull)
+  // - they have the same value
+  // If the types are the same, OpConstantNull is equivalent to
+  // OpConstantFalse or OpConstant with value zero.
+
+  // The id of a constant
+  uint32 constant1_id = 1;
+
+  // The id of the synonym
+  uint32 constant2_id = 2;
+
+}
+
+message TransformationReplaceParameterWithGlobal {
+
+  // Removes parameter with result id |parameter_id| from its function
+  // and creates a global variable to pass its value to the function instead.
+
+  // Fresh id for a new function type. This might not be used if a required
+  // function type already exists or if we can change the old function type.
+  uint32 function_type_fresh_id = 2;
+
+  // Result id of the OpFunctionParameter instruction to remove.
+  uint32 parameter_id = 3;
+
+  // Fresh id of a global variable used to pass parameter's value to the function.
+  uint32 global_variable_fresh_id = 4;
+
+}
+
 message TransformationReplaceBooleanConstantWithConstantBinary {
 message TransformationReplaceBooleanConstantWithConstantBinary {
 
 
   // A transformation to capture replacing a use of a boolean constant with
   // A transformation to capture replacing a use of a boolean constant with
@@ -1176,14 +1228,14 @@ message TransformationReplaceLinearAlgebraInstruction {
   // Supported:
   // Supported:
   //   OpVectorTimesScalar
   //   OpVectorTimesScalar
   //   OpMatrixTimesScalar
   //   OpMatrixTimesScalar
+  //   OpVectorTimesMatrix
+  //   OpMatrixTimesVector
   //   OpDot
   //   OpDot
   // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3354):
   // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3354):
   // Right now we only support certain operations. When this issue is addressed
   // Right now we only support certain operations. When this issue is addressed
   // the supporting comments can be removed.
   // the supporting comments can be removed.
   // To be supported in the future:
   // To be supported in the future:
   //   OpTranspose
   //   OpTranspose
-  //   OpVectorTimesMatrix
-  //   OpMatrixTimesVector
   //   OpMatrixTimesMatrix
   //   OpMatrixTimesMatrix
   //   OpOuterProduct
   //   OpOuterProduct
   InstructionDescriptor instruction_descriptor = 2;
   InstructionDescriptor instruction_descriptor = 2;

+ 15 - 0
3rdparty/spirv-tools/source/fuzz/transformation.cpp

@@ -29,6 +29,7 @@
 #include "source/fuzz/transformation_add_function.h"
 #include "source/fuzz/transformation_add_function.h"
 #include "source/fuzz/transformation_add_global_undef.h"
 #include "source/fuzz/transformation_add_global_undef.h"
 #include "source/fuzz/transformation_add_global_variable.h"
 #include "source/fuzz/transformation_add_global_variable.h"
+#include "source/fuzz/transformation_add_image_sample_unused_components.h"
 #include "source/fuzz/transformation_add_local_variable.h"
 #include "source/fuzz/transformation_add_local_variable.h"
 #include "source/fuzz/transformation_add_no_contraction_decoration.h"
 #include "source/fuzz/transformation_add_no_contraction_decoration.h"
 #include "source/fuzz/transformation_add_parameter.h"
 #include "source/fuzz/transformation_add_parameter.h"
@@ -57,10 +58,12 @@
 #include "source/fuzz/transformation_permute_function_parameters.h"
 #include "source/fuzz/transformation_permute_function_parameters.h"
 #include "source/fuzz/transformation_permute_phi_operands.h"
 #include "source/fuzz/transformation_permute_phi_operands.h"
 #include "source/fuzz/transformation_push_id_through_variable.h"
 #include "source/fuzz/transformation_push_id_through_variable.h"
+#include "source/fuzz/transformation_record_synonymous_constants.h"
 #include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
 #include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
 #include "source/fuzz/transformation_replace_constant_with_uniform.h"
 #include "source/fuzz/transformation_replace_constant_with_uniform.h"
 #include "source/fuzz/transformation_replace_id_with_synonym.h"
 #include "source/fuzz/transformation_replace_id_with_synonym.h"
 #include "source/fuzz/transformation_replace_linear_algebra_instruction.h"
 #include "source/fuzz/transformation_replace_linear_algebra_instruction.h"
+#include "source/fuzz/transformation_replace_parameter_with_global.h"
 #include "source/fuzz/transformation_set_function_control.h"
 #include "source/fuzz/transformation_set_function_control.h"
 #include "source/fuzz/transformation_set_loop_control.h"
 #include "source/fuzz/transformation_set_loop_control.h"
 #include "source/fuzz/transformation_set_memory_operands_mask.h"
 #include "source/fuzz/transformation_set_memory_operands_mask.h"
@@ -112,6 +115,10 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
     case protobufs::Transformation::TransformationCase::kAddGlobalVariable:
     case protobufs::Transformation::TransformationCase::kAddGlobalVariable:
       return MakeUnique<TransformationAddGlobalVariable>(
       return MakeUnique<TransformationAddGlobalVariable>(
           message.add_global_variable());
           message.add_global_variable());
+    case protobufs::Transformation::TransformationCase::
+        kAddImageSampleUnusedComponents:
+      return MakeUnique<TransformationAddImageSampleUnusedComponents>(
+          message.add_image_sample_unused_components());
     case protobufs::Transformation::TransformationCase::kAddLocalVariable:
     case protobufs::Transformation::TransformationCase::kAddLocalVariable:
       return MakeUnique<TransformationAddLocalVariable>(
       return MakeUnique<TransformationAddLocalVariable>(
           message.add_local_variable());
           message.add_local_variable());
@@ -188,6 +195,14 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
     case protobufs::Transformation::TransformationCase::kPushIdThroughVariable:
     case protobufs::Transformation::TransformationCase::kPushIdThroughVariable:
       return MakeUnique<TransformationPushIdThroughVariable>(
       return MakeUnique<TransformationPushIdThroughVariable>(
           message.push_id_through_variable());
           message.push_id_through_variable());
+    case protobufs::Transformation::TransformationCase::
+        kRecordSynonymousConstants:
+      return MakeUnique<TransformationRecordSynonymousConstants>(
+          message.record_synonymous_constants());
+    case protobufs::Transformation::TransformationCase::
+        kReplaceParameterWithGlobal:
+      return MakeUnique<TransformationReplaceParameterWithGlobal>(
+          message.replace_parameter_with_global());
     case protobufs::Transformation::TransformationCase::
     case protobufs::Transformation::TransformationCase::
         kReplaceBooleanConstantWithConstantBinary:
         kReplaceBooleanConstantWithConstantBinary:
       return MakeUnique<TransformationReplaceBooleanConstantWithConstantBinary>(
       return MakeUnique<TransformationReplaceBooleanConstantWithConstantBinary>(

+ 4 - 4
3rdparty/spirv-tools/source/fuzz/transformation_add_dead_block.cpp

@@ -40,8 +40,8 @@ bool TransformationAddDeadBlock::IsApplicable(
 
 
   // First, we check that a constant with the same value as
   // First, we check that a constant with the same value as
   // |message_.condition_value| is present.
   // |message_.condition_value| is present.
-  if (!fuzzerutil::MaybeGetBoolConstantId(ir_context,
-                                          message_.condition_value())) {
+  if (!fuzzerutil::MaybeGetBoolConstant(ir_context,
+                                        message_.condition_value())) {
     // The required constant is not present, so the transformation cannot be
     // The required constant is not present, so the transformation cannot be
     // applied.
     // applied.
     return false;
     return false;
@@ -92,8 +92,8 @@ void TransformationAddDeadBlock::Apply(
       existing_block->terminator()->GetSingleWordInOperand(0);
       existing_block->terminator()->GetSingleWordInOperand(0);
 
 
   // Get the id of the boolean value that will be used as the branch condition.
   // Get the id of the boolean value that will be used as the branch condition.
-  auto bool_id = fuzzerutil::MaybeGetBoolConstantId(ir_context,
-                                                    message_.condition_value());
+  auto bool_id =
+      fuzzerutil::MaybeGetBoolConstant(ir_context, message_.condition_value());
 
 
   // Make a new block that unconditionally branches to the original successor
   // Make a new block that unconditionally branches to the original successor
   // block.
   // block.

+ 2 - 2
3rdparty/spirv-tools/source/fuzz/transformation_add_dead_break.cpp

@@ -112,8 +112,8 @@ bool TransformationAddDeadBreak::IsApplicable(
     const TransformationContext& transformation_context) const {
     const TransformationContext& transformation_context) const {
   // First, we check that a constant with the same value as
   // First, we check that a constant with the same value as
   // |message_.break_condition_value| is present.
   // |message_.break_condition_value| is present.
-  if (!fuzzerutil::MaybeGetBoolConstantId(ir_context,
-                                          message_.break_condition_value())) {
+  if (!fuzzerutil::MaybeGetBoolConstant(ir_context,
+                                        message_.break_condition_value())) {
     // The required constant is not present, so the transformation cannot be
     // The required constant is not present, so the transformation cannot be
     // applied.
     // applied.
     return false;
     return false;

+ 2 - 2
3rdparty/spirv-tools/source/fuzz/transformation_add_dead_continue.cpp

@@ -38,8 +38,8 @@ bool TransformationAddDeadContinue::IsApplicable(
     const TransformationContext& transformation_context) const {
     const TransformationContext& transformation_context) const {
   // First, we check that a constant with the same value as
   // First, we check that a constant with the same value as
   // |message_.continue_condition_value| is present.
   // |message_.continue_condition_value| is present.
-  if (!fuzzerutil::MaybeGetBoolConstantId(
-          ir_context, message_.continue_condition_value())) {
+  if (!fuzzerutil::MaybeGetBoolConstant(ir_context,
+                                        message_.continue_condition_value())) {
     // The required constant is not present, so the transformation cannot be
     // The required constant is not present, so the transformation cannot be
     // applied.
     // applied.
     return false;
     return false;

+ 0 - 2
3rdparty/spirv-tools/source/fuzz/transformation_add_global_variable.cpp

@@ -98,8 +98,6 @@ void TransformationAddGlobalVariable::Apply(
       static_cast<SpvStorageClass>(message_.storage_class()),
       static_cast<SpvStorageClass>(message_.storage_class()),
       message_.initializer_id());
       message_.initializer_id());
 
 
-  fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
-
   if (message_.value_is_irrelevant()) {
   if (message_.value_is_irrelevant()) {
     transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
     transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
         message_.fresh_id());
         message_.fresh_id());

+ 117 - 0
3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.cpp

@@ -0,0 +1,117 @@
+// Copyright (c) 2020 André Perez Maselco
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/transformation_add_image_sample_unused_components.h"
+
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationAddImageSampleUnusedComponents::
+    TransformationAddImageSampleUnusedComponents(
+        const spvtools::fuzz::protobufs::
+            TransformationAddImageSampleUnusedComponents& message)
+    : message_(message) {}
+
+TransformationAddImageSampleUnusedComponents::
+    TransformationAddImageSampleUnusedComponents(
+        uint32_t coordinate_with_unused_components_id,
+        const protobufs::InstructionDescriptor& instruction_descriptor) {
+  message_.set_coordinate_with_unused_components_id(
+      coordinate_with_unused_components_id);
+  *message_.mutable_instruction_descriptor() = instruction_descriptor;
+}
+
+bool TransformationAddImageSampleUnusedComponents::IsApplicable(
+    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
+  auto image_sample_instruction =
+      FindInstruction(message_.instruction_descriptor(), ir_context);
+
+  // The image sample instruction must be defined.
+  if (image_sample_instruction == nullptr) {
+    return false;
+  }
+
+  // The instruction must be an image sample instruction.
+  if (!spvOpcodeIsImageSample(image_sample_instruction->opcode())) {
+    return false;
+  }
+
+  uint32_t coordinate_id = image_sample_instruction->GetSingleWordInOperand(1);
+  auto coordinate_instruction =
+      ir_context->get_def_use_mgr()->GetDef(coordinate_id);
+  auto coordinate_type =
+      ir_context->get_type_mgr()->GetType(coordinate_instruction->type_id());
+
+  // It must be possible to add unused components.
+  if (coordinate_type->AsVector() &&
+      coordinate_type->AsVector()->element_count() == 4) {
+    return false;
+  }
+
+  auto coordinate_with_unused_components_instruction =
+      ir_context->get_def_use_mgr()->GetDef(
+          message_.coordinate_with_unused_components_id());
+
+  // The coordinate with unused components instruction must be defined.
+  if (coordinate_with_unused_components_instruction == nullptr) {
+    return false;
+  }
+
+  // It must be an OpCompositeConstruct instruction such that it can be checked
+  // that the original components are present.
+  if (coordinate_with_unused_components_instruction->opcode() !=
+      SpvOpCompositeConstruct) {
+    return false;
+  }
+
+  // The first constituent must be the original coordinate.
+  if (coordinate_with_unused_components_instruction->GetSingleWordInOperand(
+          0) != coordinate_id) {
+    return false;
+  }
+
+  auto coordinate_with_unused_components_type =
+      ir_context->get_type_mgr()->GetType(
+          coordinate_with_unused_components_instruction->type_id());
+
+  // |coordinate_with_unused_components_type| must be a vector.
+  if (!coordinate_with_unused_components_type->AsVector()) {
+    return false;
+  }
+
+  return true;
+}
+
+void TransformationAddImageSampleUnusedComponents::Apply(
+    opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
+  // Sets the coordinate operand.
+  auto image_sample_instruction =
+      FindInstruction(message_.instruction_descriptor(), ir_context);
+  image_sample_instruction->SetInOperand(
+      1, {message_.coordinate_with_unused_components_id()});
+  ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
+}
+
+protobufs::Transformation
+TransformationAddImageSampleUnusedComponents::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_add_image_sample_unused_components() = message_;
+  return result;
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 57 - 0
3rdparty/spirv-tools/source/fuzz/transformation_add_image_sample_unused_components.h

@@ -0,0 +1,57 @@
+// Copyright (c) 2020 André Perez Maselco
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_TRANSFORMATION_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_
+#define SOURCE_FUZZ_TRANSFORMATION_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_
+
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/fuzz/transformation_context.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationAddImageSampleUnusedComponents : public Transformation {
+ public:
+  explicit TransformationAddImageSampleUnusedComponents(
+      const protobufs::TransformationAddImageSampleUnusedComponents& message);
+
+  TransformationAddImageSampleUnusedComponents(
+      uint32_t coordinate_with_unused_components_id,
+      const protobufs::InstructionDescriptor& instruction_descriptor);
+
+  // - |coordinate_with_unused_components_id| must identify a vector such that
+  //   the first components match the components of the image sample coordinate.
+  // - |message_.instruction_descriptor| must identify an image sample
+  //   instruction
+  bool IsApplicable(
+      opt::IRContext* ir_context,
+      const TransformationContext& transformation_context) const override;
+
+  // Add unused components to an image sample coordinate by replacing the
+  // coordinate with |coordinate_with_unused_components_id|.
+  void Apply(opt::IRContext* ir_context,
+             TransformationContext* transformation_context) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  protobufs::TransformationAddImageSampleUnusedComponents message_;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_TRANSFORMATION_ADD_IMAGE_SAMPLE_UNUSED_COMPONENTS_H_

+ 0 - 2
3rdparty/spirv-tools/source/fuzz/transformation_add_local_variable.cpp

@@ -74,8 +74,6 @@ void TransformationAddLocalVariable::Apply(
                                message_.type_id(), message_.function_id(),
                                message_.type_id(), message_.function_id(),
                                message_.initializer_id());
                                message_.initializer_id());
 
 
-  fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
-
   if (message_.value_is_irrelevant()) {
   if (message_.value_is_irrelevant()) {
     transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
     transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
         message_.fresh_id());
         message_.fresh_id());

+ 0 - 2
3rdparty/spirv-tools/source/fuzz/transformation_push_id_through_variable.cpp

@@ -127,8 +127,6 @@ void TransformationPushIdThroughVariable::Apply(
                                  message_.initializer_id());
                                  message_.initializer_id());
   }
   }
 
 
-  fuzzerutil::UpdateModuleIdBound(ir_context, message_.variable_id());
-
   // Stores value id to variable id.
   // Stores value id to variable id.
   FindInstruction(message_.instruction_descriptor(), ir_context)
   FindInstruction(message_.instruction_descriptor(), ir_context)
       ->InsertBefore(MakeUnique<opt::Instruction>(
       ->InsertBefore(MakeUnique<opt::Instruction>(

+ 107 - 0
3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.cpp

@@ -0,0 +1,107 @@
+// Copyright (c) 2020 Stefano Milizia
+// Copyright (c) 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "transformation_record_synonymous_constants.h"
+
+namespace spvtools {
+namespace fuzz {
+
+namespace {
+bool IsScalarZeroConstant(const opt::analysis::Constant* constant) {
+  return constant->AsScalarConstant() && constant->IsZero();
+}
+}  // namespace
+
+TransformationRecordSynonymousConstants::
+    TransformationRecordSynonymousConstants(
+        const protobufs::TransformationRecordSynonymousConstants& message)
+    : message_(message) {}
+
+TransformationRecordSynonymousConstants::
+    TransformationRecordSynonymousConstants(uint32_t constant1_id,
+                                            uint32_t constant2_id) {
+  message_.set_constant1_id(constant1_id);
+  message_.set_constant2_id(constant2_id);
+}
+
+bool TransformationRecordSynonymousConstants::IsApplicable(
+    opt::IRContext* ir_context,
+    const TransformationContext& /* unused */) const {
+  // The ids must be different
+  if (message_.constant1_id() == message_.constant2_id()) {
+    return false;
+  }
+
+  auto constant1 = ir_context->get_constant_mgr()->FindDeclaredConstant(
+      message_.constant1_id());
+  auto constant2 = ir_context->get_constant_mgr()->FindDeclaredConstant(
+      message_.constant2_id());
+
+  // The constants must exist
+  if (constant1 == nullptr || constant2 == nullptr) {
+    return false;
+  }
+
+  // If the constants are equal, then they are equivalent
+  if (constant1 == constant2) {
+    return true;
+  }
+
+  // If the constants are two integers (signed or unsigned), they are equal
+  // if they have the same width and the same data words.
+  if (constant1->AsIntConstant() && constant2->AsIntConstant() &&
+      constant1->type()->AsInteger()->width() ==
+          constant2->type()->AsInteger()->width() &&
+      constant1->AsIntConstant()->words() ==
+          constant2->AsIntConstant()->words()) {
+    return true;
+  }
+
+  // The types must be the same
+  if (!constant1->type()->IsSame(constant2->type())) {
+    return false;
+  }
+
+  // The constants are equivalent if one is null and the other is a static
+  // constant with value 0.
+  return (constant1->AsNullConstant() && IsScalarZeroConstant(constant2)) ||
+         (IsScalarZeroConstant(constant1) && constant2->AsNullConstant());
+}
+
+void TransformationRecordSynonymousConstants::Apply(
+    opt::IRContext* ir_context,
+    TransformationContext* transformation_context) const {
+  protobufs::FactDataSynonym fact_data_synonym;
+  // Define the two equivalent data descriptors (just containing the ids)
+  *fact_data_synonym.mutable_data1() =
+      MakeDataDescriptor(message_.constant1_id(), {});
+  *fact_data_synonym.mutable_data2() =
+      MakeDataDescriptor(message_.constant2_id(), {});
+  protobufs::Fact fact;
+  *fact.mutable_data_synonym_fact() = fact_data_synonym;
+
+  // Add the fact to the fact manager
+  transformation_context->GetFactManager()->AddFact(fact, ir_context);
+}
+
+protobufs::Transformation TransformationRecordSynonymousConstants::ToMessage()
+    const {
+  protobufs::Transformation result;
+  *result.mutable_record_synonymous_constants() = message_;
+  return result;
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 59 - 0
3rdparty/spirv-tools/source/fuzz/transformation_record_synonymous_constants.h

@@ -0,0 +1,59 @@
+// Copyright (c) 2020 Stefano Milizia
+// Copyright (c) 2020 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_TRANSFORMATION_RECORD_SYNONYMOUS_CONSTANTS_H
+#define SOURCE_FUZZ_TRANSFORMATION_RECORD_SYNONYMOUS_CONSTANTS_H
+
+#include "source/fuzz/transformation.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationRecordSynonymousConstants : public Transformation {
+ public:
+  explicit TransformationRecordSynonymousConstants(
+      const protobufs::TransformationRecordSynonymousConstants& message);
+
+  TransformationRecordSynonymousConstants(uint32_t constant1_id,
+                                          uint32_t constant2_id);
+
+  // - |message_.constant_id| and |message_.synonym_id| are distinct ids
+  //   of constants
+  // - |message_.constant_id| and |message_.synonym_id| refer to constants
+  //   that are equal or equivalent.
+  //   Two integers with the same width and value are equal, even if one is
+  //   signed and the other is not.
+  //   Constants are equivalent if both of them represent zero-like scalar
+  //   values of the same type (for example OpConstant of type int and value
+  //   0 and OpConstantNull of type int).
+  bool IsApplicable(
+      opt::IRContext* ir_context,
+      const TransformationContext& transformation_context) const override;
+
+  // Adds the fact that |message_.constant_id| and |message_.synonym_id|
+  // are synonyms to the fact manager. The module is not changed.
+  void Apply(opt::IRContext* ir_context,
+             TransformationContext* transformation_context) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  protobufs::TransformationRecordSynonymousConstants message_;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_TRANSFORMATION_RECORD_SYNONYMOUS_CONSTANTS

+ 283 - 3
3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.cpp

@@ -47,6 +47,8 @@ bool TransformationReplaceLinearAlgebraInstruction::IsApplicable(
   // It must be a supported linear algebra instruction.
   // It must be a supported linear algebra instruction.
   if (instruction->opcode() != SpvOpVectorTimesScalar &&
   if (instruction->opcode() != SpvOpVectorTimesScalar &&
       instruction->opcode() != SpvOpMatrixTimesScalar &&
       instruction->opcode() != SpvOpMatrixTimesScalar &&
+      instruction->opcode() != SpvOpVectorTimesMatrix &&
+      instruction->opcode() != SpvOpMatrixTimesVector &&
       instruction->opcode() != SpvOpDot) {
       instruction->opcode() != SpvOpDot) {
     return false;
     return false;
   }
   }
@@ -59,9 +61,8 @@ bool TransformationReplaceLinearAlgebraInstruction::IsApplicable(
   }
   }
 
 
   // All ids in |message_.fresh_ids| must be fresh.
   // All ids in |message_.fresh_ids| must be fresh.
-  for (uint32_t i = 0; i < static_cast<uint32_t>(message_.fresh_ids().size());
-       i++) {
-    if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_ids(i))) {
+  for (uint32_t fresh_id : message_.fresh_ids()) {
+    if (!fuzzerutil::IsFreshId(ir_context, fresh_id)) {
       return false;
       return false;
     }
     }
   }
   }
@@ -81,6 +82,12 @@ void TransformationReplaceLinearAlgebraInstruction::Apply(
     case SpvOpMatrixTimesScalar:
     case SpvOpMatrixTimesScalar:
       ReplaceOpMatrixTimesScalar(ir_context, linear_algebra_instruction);
       ReplaceOpMatrixTimesScalar(ir_context, linear_algebra_instruction);
       break;
       break;
+    case SpvOpVectorTimesMatrix:
+      ReplaceOpVectorTimesMatrix(ir_context, linear_algebra_instruction);
+      break;
+    case SpvOpMatrixTimesVector:
+      ReplaceOpMatrixTimesVector(ir_context, linear_algebra_instruction);
+      break;
     case SpvOpDot:
     case SpvOpDot:
       ReplaceOpDot(ir_context, linear_algebra_instruction);
       ReplaceOpDot(ir_context, linear_algebra_instruction);
       break;
       break;
@@ -128,6 +135,49 @@ uint32_t TransformationReplaceLinearAlgebraInstruction::GetRequiredFreshIdCount(
                       ->AsVector()
                       ->AsVector()
                       ->element_count());
                       ->element_count());
     }
     }
+    case SpvOpVectorTimesMatrix: {
+      // For each vector component, 1 OpCompositeExtract instruction will be
+      // inserted. For each matrix column, |1 + vector_component_count|
+      // OpCompositeExtract, |vector_component_count| OpFMul and
+      // |vector_component_count - 1| OpFAdd instructions will be inserted.
+      auto vector_instruction = ir_context->get_def_use_mgr()->GetDef(
+          instruction->GetSingleWordInOperand(0));
+      auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef(
+          instruction->GetSingleWordInOperand(1));
+      uint32_t vector_component_count =
+          ir_context->get_type_mgr()
+              ->GetType(vector_instruction->type_id())
+              ->AsVector()
+              ->element_count();
+      uint32_t matrix_column_count =
+          ir_context->get_type_mgr()
+              ->GetType(matrix_instruction->type_id())
+              ->AsMatrix()
+              ->element_count();
+      return vector_component_count * (3 * matrix_column_count + 1);
+    }
+    case SpvOpMatrixTimesVector: {
+      // For each matrix column, |1 + matrix_row_count| OpCompositeExtract
+      // will be inserted. For each matrix row, |matrix_column_count| OpFMul and
+      // |matrix_column_count - 1| OpFAdd instructions will be inserted. For
+      // each vector component, 1 OpCompositeExtract instruction will be
+      // inserted.
+      auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef(
+          instruction->GetSingleWordInOperand(0));
+      uint32_t matrix_column_count =
+          ir_context->get_type_mgr()
+              ->GetType(matrix_instruction->type_id())
+              ->AsMatrix()
+              ->element_count();
+      uint32_t matrix_row_count = ir_context->get_type_mgr()
+                                      ->GetType(matrix_instruction->type_id())
+                                      ->AsMatrix()
+                                      ->element_type()
+                                      ->AsVector()
+                                      ->element_count();
+      return 3 * matrix_column_count * matrix_row_count +
+             2 * matrix_column_count - matrix_row_count;
+    }
     case SpvOpDot:
     case SpvOpDot:
       // For each pair of vector components, 2 OpCompositeExtract and 1 OpFMul
       // For each pair of vector components, 2 OpCompositeExtract and 1 OpFMul
       // will be inserted. The first two OpFMul instructions will result the
       // will be inserted. The first two OpFMul instructions will result the
@@ -280,6 +330,236 @@ void TransformationReplaceLinearAlgebraInstruction::ReplaceOpMatrixTimesScalar(
   }
   }
 }
 }
 
 
+void TransformationReplaceLinearAlgebraInstruction::ReplaceOpVectorTimesMatrix(
+    opt::IRContext* ir_context,
+    opt::Instruction* linear_algebra_instruction) const {
+  // Gets vector information.
+  auto vector_instruction = ir_context->get_def_use_mgr()->GetDef(
+      linear_algebra_instruction->GetSingleWordInOperand(0));
+  uint32_t vector_component_count = ir_context->get_type_mgr()
+                                        ->GetType(vector_instruction->type_id())
+                                        ->AsVector()
+                                        ->element_count();
+  auto vector_component_type = ir_context->get_type_mgr()
+                                   ->GetType(vector_instruction->type_id())
+                                   ->AsVector()
+                                   ->element_type();
+
+  // Extracts vector components.
+  uint32_t fresh_id_index = 0;
+  std::vector<uint32_t> vector_component_ids(vector_component_count);
+  for (uint32_t i = 0; i < vector_component_count; i++) {
+    vector_component_ids[i] = message_.fresh_ids(fresh_id_index++);
+    linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+        ir_context, SpvOpCompositeExtract,
+        ir_context->get_type_mgr()->GetId(vector_component_type),
+        vector_component_ids[i],
+        opt::Instruction::OperandList(
+            {{SPV_OPERAND_TYPE_ID, {vector_instruction->result_id()}},
+             {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
+  }
+
+  // Gets matrix information.
+  auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef(
+      linear_algebra_instruction->GetSingleWordInOperand(1));
+  uint32_t matrix_column_count = ir_context->get_type_mgr()
+                                     ->GetType(matrix_instruction->type_id())
+                                     ->AsMatrix()
+                                     ->element_count();
+  auto matrix_column_type = ir_context->get_type_mgr()
+                                ->GetType(matrix_instruction->type_id())
+                                ->AsMatrix()
+                                ->element_type();
+
+  std::vector<uint32_t> result_component_ids(matrix_column_count);
+  for (uint32_t i = 0; i < matrix_column_count; i++) {
+    // Extracts matrix column.
+    uint32_t matrix_extract_id = message_.fresh_ids(fresh_id_index++);
+    linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+        ir_context, SpvOpCompositeExtract,
+        ir_context->get_type_mgr()->GetId(matrix_column_type),
+        matrix_extract_id,
+        opt::Instruction::OperandList(
+            {{SPV_OPERAND_TYPE_ID, {matrix_instruction->result_id()}},
+             {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
+
+    std::vector<uint32_t> float_multiplication_ids(vector_component_count);
+    for (uint32_t j = 0; j < vector_component_count; j++) {
+      // Extracts column component.
+      uint32_t column_extract_id = message_.fresh_ids(fresh_id_index++);
+      linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+          ir_context, SpvOpCompositeExtract,
+          ir_context->get_type_mgr()->GetId(vector_component_type),
+          column_extract_id,
+          opt::Instruction::OperandList(
+              {{SPV_OPERAND_TYPE_ID, {matrix_extract_id}},
+               {SPV_OPERAND_TYPE_LITERAL_INTEGER, {j}}})));
+
+      // Multiplies corresponding vector and column components.
+      float_multiplication_ids[j] = message_.fresh_ids(fresh_id_index++);
+      linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+          ir_context, SpvOpFMul,
+          ir_context->get_type_mgr()->GetId(vector_component_type),
+          float_multiplication_ids[j],
+          opt::Instruction::OperandList(
+              {{SPV_OPERAND_TYPE_ID, {vector_component_ids[j]}},
+               {SPV_OPERAND_TYPE_ID, {column_extract_id}}})));
+    }
+
+    // Adds the multiplication results.
+    std::vector<uint32_t> float_add_ids;
+    uint32_t float_add_id = message_.fresh_ids(fresh_id_index++);
+    float_add_ids.push_back(float_add_id);
+    linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+        ir_context, SpvOpFAdd,
+        ir_context->get_type_mgr()->GetId(vector_component_type), float_add_id,
+        opt::Instruction::OperandList(
+            {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[0]}},
+             {SPV_OPERAND_TYPE_ID, {float_multiplication_ids[1]}}})));
+    for (uint32_t j = 2; j < float_multiplication_ids.size(); j++) {
+      float_add_id = message_.fresh_ids(fresh_id_index++);
+      float_add_ids.push_back(float_add_id);
+      linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+          ir_context, SpvOpFAdd,
+          ir_context->get_type_mgr()->GetId(vector_component_type),
+          float_add_id,
+          opt::Instruction::OperandList(
+              {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[j]}},
+               {SPV_OPERAND_TYPE_ID, {float_add_ids[j - 2]}}})));
+    }
+
+    result_component_ids[i] = float_add_ids.back();
+  }
+
+  // The OpVectorTimesMatrix instruction is changed to an OpCompositeConstruct
+  // instruction.
+  linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct);
+  linear_algebra_instruction->SetInOperand(0, {result_component_ids[0]});
+  linear_algebra_instruction->SetInOperand(1, {result_component_ids[1]});
+  for (uint32_t i = 2; i < result_component_ids.size(); i++) {
+    linear_algebra_instruction->AddOperand(
+        {SPV_OPERAND_TYPE_ID, {result_component_ids[i]}});
+  }
+
+  fuzzerutil::UpdateModuleIdBound(
+      ir_context, message_.fresh_ids(message_.fresh_ids().size() - 1));
+}
+
+void TransformationReplaceLinearAlgebraInstruction::ReplaceOpMatrixTimesVector(
+    opt::IRContext* ir_context,
+    opt::Instruction* linear_algebra_instruction) const {
+  // Gets matrix information.
+  auto matrix_instruction = ir_context->get_def_use_mgr()->GetDef(
+      linear_algebra_instruction->GetSingleWordInOperand(0));
+  uint32_t matrix_column_count = ir_context->get_type_mgr()
+                                     ->GetType(matrix_instruction->type_id())
+                                     ->AsMatrix()
+                                     ->element_count();
+  auto matrix_column_type = ir_context->get_type_mgr()
+                                ->GetType(matrix_instruction->type_id())
+                                ->AsMatrix()
+                                ->element_type();
+  uint32_t matrix_row_count = matrix_column_type->AsVector()->element_count();
+
+  // Extracts matrix columns.
+  uint32_t fresh_id_index = 0;
+  std::vector<uint32_t> matrix_column_ids(matrix_column_count);
+  for (uint32_t i = 0; i < matrix_column_count; i++) {
+    matrix_column_ids[i] = message_.fresh_ids(fresh_id_index++);
+    linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+        ir_context, SpvOpCompositeExtract,
+        ir_context->get_type_mgr()->GetId(matrix_column_type),
+        matrix_column_ids[i],
+        opt::Instruction::OperandList(
+            {{SPV_OPERAND_TYPE_ID, {matrix_instruction->result_id()}},
+             {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
+  }
+
+  // Gets vector information.
+  auto vector_instruction = ir_context->get_def_use_mgr()->GetDef(
+      linear_algebra_instruction->GetSingleWordInOperand(1));
+  auto vector_component_type = ir_context->get_type_mgr()
+                                   ->GetType(vector_instruction->type_id())
+                                   ->AsVector()
+                                   ->element_type();
+
+  // Extracts vector components.
+  std::vector<uint32_t> vector_component_ids(matrix_column_count);
+  for (uint32_t i = 0; i < matrix_column_count; i++) {
+    vector_component_ids[i] = message_.fresh_ids(fresh_id_index++);
+    linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+        ir_context, SpvOpCompositeExtract,
+        ir_context->get_type_mgr()->GetId(vector_component_type),
+        vector_component_ids[i],
+        opt::Instruction::OperandList(
+            {{SPV_OPERAND_TYPE_ID, {vector_instruction->result_id()}},
+             {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
+  }
+
+  std::vector<uint32_t> result_component_ids(matrix_row_count);
+  for (uint32_t i = 0; i < matrix_row_count; i++) {
+    std::vector<uint32_t> float_multiplication_ids(matrix_column_count);
+    for (uint32_t j = 0; j < matrix_column_count; j++) {
+      // Extracts column component.
+      uint32_t column_extract_id = message_.fresh_ids(fresh_id_index++);
+      linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+          ir_context, SpvOpCompositeExtract,
+          ir_context->get_type_mgr()->GetId(vector_component_type),
+          column_extract_id,
+          opt::Instruction::OperandList(
+              {{SPV_OPERAND_TYPE_ID, {matrix_column_ids[j]}},
+               {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
+
+      // Multiplies corresponding vector and column components.
+      float_multiplication_ids[j] = message_.fresh_ids(fresh_id_index++);
+      linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+          ir_context, SpvOpFMul,
+          ir_context->get_type_mgr()->GetId(vector_component_type),
+          float_multiplication_ids[j],
+          opt::Instruction::OperandList(
+              {{SPV_OPERAND_TYPE_ID, {column_extract_id}},
+               {SPV_OPERAND_TYPE_ID, {vector_component_ids[j]}}})));
+    }
+
+    // Adds the multiplication results.
+    std::vector<uint32_t> float_add_ids;
+    uint32_t float_add_id = message_.fresh_ids(fresh_id_index++);
+    float_add_ids.push_back(float_add_id);
+    linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+        ir_context, SpvOpFAdd,
+        ir_context->get_type_mgr()->GetId(vector_component_type), float_add_id,
+        opt::Instruction::OperandList(
+            {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[0]}},
+             {SPV_OPERAND_TYPE_ID, {float_multiplication_ids[1]}}})));
+    for (uint32_t j = 2; j < float_multiplication_ids.size(); j++) {
+      float_add_id = message_.fresh_ids(fresh_id_index++);
+      float_add_ids.push_back(float_add_id);
+      linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+          ir_context, SpvOpFAdd,
+          ir_context->get_type_mgr()->GetId(vector_component_type),
+          float_add_id,
+          opt::Instruction::OperandList(
+              {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[j]}},
+               {SPV_OPERAND_TYPE_ID, {float_add_ids[j - 2]}}})));
+    }
+
+    result_component_ids[i] = float_add_ids.back();
+  }
+
+  // The OpMatrixTimesVector instruction is changed to an OpCompositeConstruct
+  // instruction.
+  linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct);
+  linear_algebra_instruction->SetInOperand(0, {result_component_ids[0]});
+  linear_algebra_instruction->SetInOperand(1, {result_component_ids[1]});
+  for (uint32_t i = 2; i < result_component_ids.size(); i++) {
+    linear_algebra_instruction->AddOperand(
+        {SPV_OPERAND_TYPE_ID, {result_component_ids[i]}});
+  }
+
+  fuzzerutil::UpdateModuleIdBound(
+      ir_context, message_.fresh_ids(message_.fresh_ids().size() - 1));
+}
+
 void TransformationReplaceLinearAlgebraInstruction::ReplaceOpDot(
 void TransformationReplaceLinearAlgebraInstruction::ReplaceOpDot(
     opt::IRContext* ir_context,
     opt::IRContext* ir_context,
     opt::Instruction* linear_algebra_instruction) const {
     opt::Instruction* linear_algebra_instruction) const {

+ 8 - 0
3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.h

@@ -60,6 +60,14 @@ class TransformationReplaceLinearAlgebraInstruction : public Transformation {
   void ReplaceOpMatrixTimesScalar(opt::IRContext* ir_context,
   void ReplaceOpMatrixTimesScalar(opt::IRContext* ir_context,
                                   opt::Instruction* instruction) const;
                                   opt::Instruction* instruction) const;
 
 
+  // Replaces an OpVectorTimesMatrix instruction.
+  void ReplaceOpVectorTimesMatrix(opt::IRContext* ir_context,
+                                  opt::Instruction* instruction) const;
+
+  // Replaces an OpMatrixTimesVector instruction.
+  void ReplaceOpMatrixTimesVector(opt::IRContext* ir_context,
+                                  opt::Instruction* instruction) const;
+
   // Replaces an OpDot instruction.
   // Replaces an OpDot instruction.
   void ReplaceOpDot(opt::IRContext* ir_context,
   void ReplaceOpDot(opt::IRContext* ir_context,
                     opt::Instruction* instruction) const;
                     opt::Instruction* instruction) const;

+ 245 - 0
3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.cpp

@@ -0,0 +1,245 @@
+// Copyright (c) 2020 Vasyl Teliman
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "source/fuzz/transformation_replace_parameter_with_global.h"
+
+#include <vector>
+
+#include "source/fuzz/fuzzer_util.h"
+
+namespace spvtools {
+namespace fuzz {
+namespace {
+
+opt::Function* GetFunctionFromParameterId(opt::IRContext* ir_context,
+                                          uint32_t param_id) {
+  auto* param_inst = ir_context->get_def_use_mgr()->GetDef(param_id);
+  assert(param_inst && "Parameter id is invalid");
+
+  for (auto& function : *ir_context->module()) {
+    if (fuzzerutil::InstructionIsFunctionParameter(param_inst, &function)) {
+      return &function;
+    }
+  }
+
+  return nullptr;
+}
+
+}  // namespace
+
+TransformationReplaceParameterWithGlobal::
+    TransformationReplaceParameterWithGlobal(
+        const protobufs::TransformationReplaceParameterWithGlobal& message)
+    : message_(message) {}
+
+TransformationReplaceParameterWithGlobal::
+    TransformationReplaceParameterWithGlobal(
+        uint32_t function_type_fresh_id, uint32_t parameter_id,
+        uint32_t global_variable_fresh_id) {
+  message_.set_function_type_fresh_id(function_type_fresh_id);
+  message_.set_parameter_id(parameter_id);
+  message_.set_global_variable_fresh_id(global_variable_fresh_id);
+}
+
+bool TransformationReplaceParameterWithGlobal::IsApplicable(
+    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
+  // Check that |parameter_id| is valid.
+  const auto* param_inst =
+      ir_context->get_def_use_mgr()->GetDef(message_.parameter_id());
+  if (!param_inst || param_inst->opcode() != SpvOpFunctionParameter) {
+    return false;
+  }
+
+  // Check that function exists and is not an entry point.
+  const auto* function =
+      GetFunctionFromParameterId(ir_context, message_.parameter_id());
+  if (!function ||
+      fuzzerutil::FunctionIsEntryPoint(ir_context, function->result_id())) {
+    return false;
+  }
+
+  // We already know that the function has at least one parameter -
+  // |parameter_id|.
+
+  // Check that replaced parameter has valid type.
+  const auto* param_type =
+      ir_context->get_type_mgr()->GetType(param_inst->type_id());
+  assert(param_type && "Parameter has invalid type");
+  if (!CanReplaceFunctionParameterType(*param_type)) {
+    return false;
+  }
+
+  // Check that initializer for the global variable exists in the module.
+  if (fuzzerutil::MaybeGetZeroConstant(ir_context, param_inst->type_id()) ==
+      0) {
+    return false;
+  }
+
+  // Check that pointer type for the global variable exists in the module.
+  if (!fuzzerutil::MaybeGetPointerType(ir_context, param_inst->type_id(),
+                                       SpvStorageClassPrivate)) {
+    return false;
+  }
+
+  return fuzzerutil::IsFreshId(ir_context, message_.function_type_fresh_id()) &&
+         fuzzerutil::IsFreshId(ir_context,
+                               message_.global_variable_fresh_id()) &&
+         message_.function_type_fresh_id() !=
+             message_.global_variable_fresh_id();
+}
+
+void TransformationReplaceParameterWithGlobal::Apply(
+    opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
+  const auto* param_inst =
+      ir_context->get_def_use_mgr()->GetDef(message_.parameter_id());
+  assert(param_inst && "Parameter must exist");
+
+  // Create global variable to store parameter's value.
+  //
+  // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3177):
+  //  Mark the global variable's pointee as irrelevant if replaced parameter is
+  //  irrelevant.
+  fuzzerutil::AddGlobalVariable(
+      ir_context, message_.global_variable_fresh_id(),
+      fuzzerutil::MaybeGetPointerType(ir_context, param_inst->type_id(),
+                                      SpvStorageClassPrivate),
+      SpvStorageClassPrivate,
+      fuzzerutil::MaybeGetZeroConstant(ir_context, param_inst->type_id()));
+
+  auto* function =
+      GetFunctionFromParameterId(ir_context, message_.parameter_id());
+  assert(function && "Function must exist");
+
+  // Insert an OpLoad instruction right after OpVariable instructions.
+  auto it = function->begin()->begin();
+  while (it != function->begin()->end() &&
+         !fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, it)) {
+    ++it;
+  }
+
+  assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpLoad, it) &&
+         "Can't insert OpLoad or OpCopyMemory into the first basic block of "
+         "the function");
+
+  it.InsertBefore(MakeUnique<opt::Instruction>(
+      ir_context, SpvOpLoad, param_inst->type_id(), param_inst->result_id(),
+      opt::Instruction::OperandList{
+          {SPV_OPERAND_TYPE_ID, {message_.global_variable_fresh_id()}}}));
+
+  // Calculate the index of the replaced parameter (we need to know this to
+  // remove operands from the OpFunctionCall).
+  auto params = fuzzerutil::GetParameters(ir_context, function->result_id());
+  auto parameter_index = static_cast<uint32_t>(params.size());
+  for (uint32_t i = 0, n = static_cast<uint32_t>(params.size()); i < n; ++i) {
+    if (params[i]->result_id() == message_.parameter_id()) {
+      parameter_index = i;
+      break;
+    }
+  }
+
+  assert(parameter_index != params.size() &&
+         "Parameter must exist in the function");
+
+  // Update all relevant OpFunctionCall instructions.
+  ir_context->get_def_use_mgr()->ForEachUser(
+      function->result_id(),
+      [ir_context, parameter_index, this](opt::Instruction* inst) {
+        if (inst->opcode() != SpvOpFunctionCall) {
+          return;
+        }
+
+        assert(fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore, inst) &&
+               "Can't insert OpStore right before the function call");
+
+        // Insert an OpStore before the OpFunctionCall. +1 since the first
+        // operand of OpFunctionCall is an id of the function.
+        inst->InsertBefore(MakeUnique<opt::Instruction>(
+            ir_context, SpvOpStore, 0, 0,
+            opt::Instruction::OperandList{
+                {SPV_OPERAND_TYPE_ID, {message_.global_variable_fresh_id()}},
+                {SPV_OPERAND_TYPE_ID,
+                 {inst->GetSingleWordInOperand(parameter_index + 1)}}}));
+
+        // +1 since the first operand of OpFunctionCall is an id of the
+        // function.
+        inst->RemoveInOperand(parameter_index + 1);
+      });
+
+  // Remove the parameter from the function.
+  function->RemoveParameter(message_.parameter_id());
+
+  // Update function's type.
+  auto* old_function_type = fuzzerutil::GetFunctionType(ir_context, function);
+  assert(old_function_type && "Function has invalid type");
+
+  // Preemptively add function's return type id.
+  std::vector<uint32_t> type_ids = {
+      old_function_type->GetSingleWordInOperand(0)};
+
+  // +1 and -1 since the first operand is the return type id.
+  for (uint32_t i = 1; i < old_function_type->NumInOperands(); ++i) {
+    if (i - 1 != parameter_index) {
+      type_ids.push_back(old_function_type->GetSingleWordInOperand(i));
+    }
+  }
+
+  if (ir_context->get_def_use_mgr()->NumUsers(old_function_type) == 1) {
+    // Change the old type in place. +1 since the first operand is the result
+    // type id of the function.
+    old_function_type->RemoveInOperand(parameter_index + 1);
+  } else {
+    // Find an existing or create a new function type.
+    function->DefInst().SetInOperand(
+        1, {fuzzerutil::FindOrCreateFunctionType(
+               ir_context, message_.function_type_fresh_id(), type_ids)});
+  }
+
+  // Make sure our changes are analyzed
+  ir_context->InvalidateAnalysesExceptFor(
+      opt::IRContext::Analysis::kAnalysisNone);
+}
+
+protobufs::Transformation TransformationReplaceParameterWithGlobal::ToMessage()
+    const {
+  protobufs::Transformation result;
+  *result.mutable_replace_parameter_with_global() = message_;
+  return result;
+}
+
+bool TransformationReplaceParameterWithGlobal::CanReplaceFunctionParameterType(
+    const opt::analysis::Type& type) {
+  // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3403):
+  //  Think about other type instructions we can add here.
+  switch (type.kind()) {
+    case opt::analysis::Type::kBool:
+    case opt::analysis::Type::kInteger:
+    case opt::analysis::Type::kFloat:
+    case opt::analysis::Type::kArray:
+    case opt::analysis::Type::kMatrix:
+    case opt::analysis::Type::kVector:
+      return true;
+    case opt::analysis::Type::kStruct:
+      return std::all_of(
+          type.AsStruct()->element_types().begin(),
+          type.AsStruct()->element_types().end(),
+          [](const opt::analysis::Type* element_type) {
+            return CanReplaceFunctionParameterType(*element_type);
+          });
+    default:
+      return false;
+  }
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 67 - 0
3rdparty/spirv-tools/source/fuzz/transformation_replace_parameter_with_global.h

@@ -0,0 +1,67 @@
+// Copyright (c) 2020 Vasyl Teliman
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SOURCE_FUZZ_TRANSFORMATION_REPLACE_PARAMETER_WITH_GLOBAL_H_
+#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_PARAMETER_WITH_GLOBAL_H_
+
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation.h"
+#include "source/fuzz/transformation_context.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+class TransformationReplaceParameterWithGlobal : public Transformation {
+ public:
+  explicit TransformationReplaceParameterWithGlobal(
+      const protobufs::TransformationReplaceParameterWithGlobal& message);
+
+  TransformationReplaceParameterWithGlobal(uint32_t function_type_fresh_id,
+                                           uint32_t parameter_id,
+                                           uint32_t global_variable_fresh_id);
+
+  // - |function_type_fresh_id| is a fresh id.
+  // - |parameter_id| is the result id of the parameter to replace.
+  // - |global_variable_fresh_id| is a fresh id.
+  // - |function_type_fresh_id| is not equal to |global_variable_fresh_id|.
+  // - the function that contains |parameter_id| may not be an entry-point
+  //   function.
+  bool IsApplicable(
+      opt::IRContext* ir_context,
+      const TransformationContext& transformation_context) const override;
+
+  // - Removes parameter with result id |parameter_id| from its function
+  // - Adds a global variable to store the value for the parameter
+  // - Add an OpStore instruction before each function call to
+  //   store parameter's value into the variable
+  // - Adds OpLoad at the beginning of the function to load the
+  //   value from the variable into the old parameter's id
+  void Apply(opt::IRContext* ir_context,
+             TransformationContext* transformation_context) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+  // Returns true if the type of the parameter is supported by this
+  // transformation.
+  static bool CanReplaceFunctionParameterType(const opt::analysis::Type& type);
+
+ private:
+  protobufs::TransformationReplaceParameterWithGlobal message_;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_TRANSFORMATION_REPLACE_PARAMETER_WITH_GLOBAL_H_

+ 20 - 0
3rdparty/spirv-tools/source/opcode.cpp

@@ -666,6 +666,26 @@ bool spvOpcodeIsLinearAlgebra(SpvOp opcode) {
   }
   }
 }
 }
 
 
+bool spvOpcodeIsImageSample(const SpvOp opcode) {
+  switch (opcode) {
+    case SpvOpImageSampleImplicitLod:
+    case SpvOpImageSampleExplicitLod:
+    case SpvOpImageSampleDrefImplicitLod:
+    case SpvOpImageSampleDrefExplicitLod:
+    case SpvOpImageSampleProjImplicitLod:
+    case SpvOpImageSampleProjExplicitLod:
+    case SpvOpImageSampleProjDrefImplicitLod:
+    case SpvOpImageSampleProjDrefExplicitLod:
+    case SpvOpImageSparseSampleImplicitLod:
+    case SpvOpImageSparseSampleExplicitLod:
+    case SpvOpImageSparseSampleDrefImplicitLod:
+    case SpvOpImageSparseSampleDrefExplicitLod:
+      return true;
+    default:
+      return false;
+  }
+}
+
 std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) {
 std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) {
   switch (opcode) {
   switch (opcode) {
     case SpvOpMemoryBarrier:
     case SpvOpMemoryBarrier:

+ 3 - 0
3rdparty/spirv-tools/source/opcode.h

@@ -137,6 +137,9 @@ bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode);
 // Returns true for opcodes that represents linear algebra instructions.
 // Returns true for opcodes that represents linear algebra instructions.
 bool spvOpcodeIsLinearAlgebra(SpvOp opcode);
 bool spvOpcodeIsLinearAlgebra(SpvOp opcode);
 
 
+// Returns true for opcodes that represents an image sample instruction.
+bool spvOpcodeIsImageSample(SpvOp opcode);
+
 // Returns a vector containing the indices of the memory semantics <id>
 // Returns a vector containing the indices of the memory semantics <id>
 // operands for |opcode|.
 // operands for |opcode|.
 std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode);
 std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode);

+ 57 - 0
3rdparty/spirv-tools/source/opt/copy_prop_arrays.cpp

@@ -29,6 +29,12 @@ const uint32_t kCompositeExtractObjectInOperand = 0;
 const uint32_t kTypePointerStorageClassInIdx = 0;
 const uint32_t kTypePointerStorageClassInIdx = 0;
 const uint32_t kTypePointerPointeeInIdx = 1;
 const uint32_t kTypePointerPointeeInIdx = 1;
 
 
+bool IsOpenCL100DebugDeclareOrValue(Instruction* di) {
+  auto dbg_opcode = di->GetOpenCL100DebugOpcode();
+  return dbg_opcode == OpenCLDebugInfo100DebugDeclare ||
+         dbg_opcode == OpenCLDebugInfo100DebugValue;
+}
+
 }  // namespace
 }  // namespace
 
 
 Pass::Status CopyPropagateArrays::Process() {
 Pass::Status CopyPropagateArrays::Process() {
@@ -188,6 +194,8 @@ bool CopyPropagateArrays::HasValidReferencesOnly(Instruction* ptr_inst,
           return ptr_inst->opcode() == SpvOpVariable &&
           return ptr_inst->opcode() == SpvOpVariable &&
                  store_inst->GetSingleWordInOperand(kStorePointerInOperand) ==
                  store_inst->GetSingleWordInOperand(kStorePointerInOperand) ==
                      ptr_inst->result_id();
                      ptr_inst->result_id();
+        } else if (IsOpenCL100DebugDeclareOrValue(use)) {
+          return true;
         }
         }
         // Some other instruction.  Be conservative.
         // Some other instruction.  Be conservative.
         return false;
         return false;
@@ -492,6 +500,8 @@ bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst,
                                                        const_mgr,
                                                        const_mgr,
                                                        type](Instruction* use,
                                                        type](Instruction* use,
                                                              uint32_t) {
                                                              uint32_t) {
+    if (IsOpenCL100DebugDeclareOrValue(use)) return true;
+
     switch (use->opcode()) {
     switch (use->opcode()) {
       case SpvOpLoad: {
       case SpvOpLoad: {
         analysis::Pointer* pointer_type = type->AsPointer();
         analysis::Pointer* pointer_type = type->AsPointer();
@@ -565,6 +575,7 @@ bool CopyPropagateArrays::CanUpdateUses(Instruction* original_ptr_inst,
     }
     }
   });
   });
 }
 }
+
 void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
 void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
                                      Instruction* new_ptr_inst) {
                                      Instruction* new_ptr_inst) {
   analysis::TypeManager* type_mgr = context()->get_type_mgr();
   analysis::TypeManager* type_mgr = context()->get_type_mgr();
@@ -580,6 +591,52 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst,
   for (auto pair : uses) {
   for (auto pair : uses) {
     Instruction* use = pair.first;
     Instruction* use = pair.first;
     uint32_t index = pair.second;
     uint32_t index = pair.second;
+
+    if (use->IsOpenCL100DebugInstr()) {
+      switch (use->GetOpenCL100DebugOpcode()) {
+        case OpenCLDebugInfo100DebugDeclare: {
+          if (new_ptr_inst->opcode() == SpvOpVariable ||
+              new_ptr_inst->opcode() == SpvOpFunctionParameter) {
+            context()->ForgetUses(use);
+            use->SetOperand(index, {new_ptr_inst->result_id()});
+            context()->AnalyzeUses(use);
+          } else {
+            // Based on the spec, we cannot use a pointer other than OpVariable
+            // or OpFunctionParameter for DebugDeclare. We have to use
+            // DebugValue with Deref.
+
+            context()->ForgetUses(use);
+
+            // Change DebugDeclare to DebugValue.
+            use->SetOperand(
+                index - 2,
+                {static_cast<uint32_t>(OpenCLDebugInfo100DebugValue)});
+            use->SetOperand(index, {new_ptr_inst->result_id()});
+
+            // Add Deref operation.
+            Instruction* dbg_expr =
+                def_use_mgr->GetDef(use->GetSingleWordOperand(index + 1));
+            auto* deref_expr_instr =
+                context()->get_debug_info_mgr()->DerefDebugExpression(dbg_expr);
+            use->SetOperand(index + 1, {deref_expr_instr->result_id()});
+
+            context()->AnalyzeUses(deref_expr_instr);
+            context()->AnalyzeUses(use);
+          }
+          break;
+        }
+        case OpenCLDebugInfo100DebugValue:
+          context()->ForgetUses(use);
+          use->SetOperand(index, {new_ptr_inst->result_id()});
+          context()->AnalyzeUses(use);
+          break;
+        default:
+          assert(false && "Don't know how to rewrite instruction");
+          break;
+      }
+      continue;
+    }
+
     switch (use->opcode()) {
     switch (use->opcode()) {
       case SpvOpLoad: {
       case SpvOpLoad: {
         // Replace the actual use.
         // Replace the actual use.

+ 104 - 8
3rdparty/spirv-tools/source/opt/debug_info_manager.cpp

@@ -36,6 +36,7 @@ static const uint32_t kDebugValueOperandExpressionIndex = 6;
 static const uint32_t kDebugOperationOperandOperationIndex = 4;
 static const uint32_t kDebugOperationOperandOperationIndex = 4;
 static const uint32_t kOpVariableOperandStorageClassIndex = 2;
 static const uint32_t kOpVariableOperandStorageClassIndex = 2;
 static const uint32_t kDebugLocalVariableOperandParentIndex = 9;
 static const uint32_t kDebugLocalVariableOperandParentIndex = 9;
+static const uint32_t kDebugOperationOperandOpCodeIndex = 4;
 
 
 namespace spvtools {
 namespace spvtools {
 namespace opt {
 namespace opt {
@@ -244,6 +245,51 @@ uint32_t DebugInfoManager::BuildDebugInlinedAtChain(
   return chain_head_id;
   return chain_head_id;
 }
 }
 
 
+Instruction* DebugInfoManager::GetDebugOperationWithDeref() {
+  if (deref_operation_ != nullptr) return deref_operation_;
+
+  uint32_t result_id = context()->TakeNextId();
+  std::unique_ptr<Instruction> deref_operation(new Instruction(
+      context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
+      result_id,
+      {
+          {SPV_OPERAND_TYPE_ID,
+           {context()
+                ->get_feature_mgr()
+                ->GetExtInstImportId_OpenCL100DebugInfo()}},
+          {SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
+           {static_cast<uint32_t>(OpenCLDebugInfo100DebugOperation)}},
+          {SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_OPERATION,
+           {static_cast<uint32_t>(OpenCLDebugInfo100Deref)}},
+      }));
+
+  // Add to the front of |ext_inst_debuginfo_|.
+  deref_operation_ =
+      context()->module()->ext_inst_debuginfo_begin()->InsertBefore(
+          std::move(deref_operation));
+
+  RegisterDbgInst(deref_operation_);
+  if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
+    context()->get_def_use_mgr()->AnalyzeInstDefUse(deref_operation_);
+  return deref_operation_;
+}
+
+Instruction* DebugInfoManager::DerefDebugExpression(Instruction* dbg_expr) {
+  assert(dbg_expr->GetOpenCL100DebugOpcode() ==
+         OpenCLDebugInfo100DebugExpression);
+  std::unique_ptr<Instruction> deref_expr(dbg_expr->Clone(context()));
+  deref_expr->SetResultId(context()->TakeNextId());
+  deref_expr->InsertOperand(
+      kDebugExpressOperandOperationIndex,
+      {SPV_OPERAND_TYPE_ID, {GetDebugOperationWithDeref()->result_id()}});
+  auto* deref_expr_instr =
+      context()->ext_inst_debuginfo_end()->InsertBefore(std::move(deref_expr));
+  AnalyzeDebugInst(deref_expr_instr);
+  if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
+    context()->get_def_use_mgr()->AnalyzeInstDefUse(deref_expr_instr);
+  return deref_expr_instr;
+}
+
 Instruction* DebugInfoManager::GetDebugInfoNone() {
 Instruction* DebugInfoManager::GetDebugInfoNone() {
   if (debug_info_none_inst_ != nullptr) return debug_info_none_inst_;
   if (debug_info_none_inst_ != nullptr) return debug_info_none_inst_;
 
 
@@ -323,6 +369,29 @@ Instruction* DebugInfoManager::CloneDebugInlinedAt(uint32_t clone_inlined_at_id,
       std::move(new_inlined_at));
       std::move(new_inlined_at));
 }
 }
 
 
+bool DebugInfoManager::IsDebugDeclared(uint32_t variable_id) {
+  auto dbg_decl_itr = var_id_to_dbg_decl_.find(variable_id);
+  return dbg_decl_itr != var_id_to_dbg_decl_.end();
+}
+
+void DebugInfoManager::KillDebugDeclares(uint32_t variable_id) {
+  bool done = false;
+  while (!done) {
+    Instruction* kill_inst = nullptr;
+    auto dbg_decl_itr = var_id_to_dbg_decl_.find(variable_id);
+    if (dbg_decl_itr != var_id_to_dbg_decl_.end()) {
+      for (auto dbg_decl : dbg_decl_itr->second) {
+        kill_inst = dbg_decl;
+        break;
+      }
+    }
+    if (kill_inst)
+      context()->KillInst(kill_inst);
+    else
+      done = true;
+  }
+}
+
 uint32_t DebugInfoManager::GetParentScope(uint32_t child_scope) {
 uint32_t DebugInfoManager::GetParentScope(uint32_t child_scope) {
   auto dbg_scope_itr = id_to_dbg_inst_.find(child_scope);
   auto dbg_scope_itr = id_to_dbg_inst_.find(child_scope);
   assert(dbg_scope_itr != id_to_dbg_inst_.end());
   assert(dbg_scope_itr != id_to_dbg_inst_.end());
@@ -434,6 +503,11 @@ void DebugInfoManager::AddDebugValue(Instruction* scope_and_line,
     AnalyzeDebugInst(added_dbg_value);
     AnalyzeDebugInst(added_dbg_value);
     if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
     if (context()->AreAnalysesValid(IRContext::Analysis::kAnalysisDefUse))
       context()->get_def_use_mgr()->AnalyzeInstDefUse(added_dbg_value);
       context()->get_def_use_mgr()->AnalyzeInstDefUse(added_dbg_value);
+    if (context()->AreAnalysesValid(
+            IRContext::Analysis::kAnalysisInstrToBlockMapping)) {
+      auto insert_blk = context()->get_instr_block(insert_before);
+      context()->set_instr_block(added_dbg_value, insert_blk);
+    }
   }
   }
 }
 }
 
 
@@ -472,8 +546,7 @@ uint32_t DebugInfoManager::GetVariableIdOfDebugValueUsedForDeclare(
 }
 }
 
 
 void DebugInfoManager::AnalyzeDebugInst(Instruction* dbg_inst) {
 void DebugInfoManager::AnalyzeDebugInst(Instruction* dbg_inst) {
-  if (dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100InstructionsMax)
-    return;
+  if (!dbg_inst->IsOpenCL100DebugInstr()) return;
 
 
   RegisterDbgInst(dbg_inst);
   RegisterDbgInst(dbg_inst);
 
 
@@ -484,6 +557,13 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* dbg_inst) {
     RegisterDbgFunction(dbg_inst);
     RegisterDbgFunction(dbg_inst);
   }
   }
 
 
+  if (deref_operation_ == nullptr &&
+      dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugOperation &&
+      dbg_inst->GetSingleWordOperand(kDebugOperationOperandOpCodeIndex) ==
+          OpenCLDebugInfo100Deref) {
+    deref_operation_ = dbg_inst;
+  }
+
   if (debug_info_none_inst_ == nullptr &&
   if (debug_info_none_inst_ == nullptr &&
       dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) {
       dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) {
     debug_info_none_inst_ = dbg_inst;
     debug_info_none_inst_ = dbg_inst;
@@ -505,6 +585,7 @@ void DebugInfoManager::AnalyzeDebugInst(Instruction* dbg_inst) {
 }
 }
 
 
 void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
 void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
+  deref_operation_ = nullptr;
   debug_info_none_inst_ = nullptr;
   debug_info_none_inst_ = nullptr;
   empty_debug_expr_inst_ = nullptr;
   empty_debug_expr_inst_ = nullptr;
   module.ForEachInst([this](Instruction* cpi) { AnalyzeDebugInst(cpi); });
   module.ForEachInst([this](Instruction* cpi) { AnalyzeDebugInst(cpi); });
@@ -513,8 +594,7 @@ void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
   // list.
   // list.
   if (empty_debug_expr_inst_ != nullptr &&
   if (empty_debug_expr_inst_ != nullptr &&
       empty_debug_expr_inst_->PreviousNode() != nullptr &&
       empty_debug_expr_inst_->PreviousNode() != nullptr &&
-      empty_debug_expr_inst_->PreviousNode()->GetOpenCL100DebugOpcode() !=
-          OpenCLDebugInfo100InstructionsMax) {
+      empty_debug_expr_inst_->PreviousNode()->IsOpenCL100DebugInstr()) {
     empty_debug_expr_inst_->InsertBefore(
     empty_debug_expr_inst_->InsertBefore(
         &*context()->module()->ext_inst_debuginfo_begin());
         &*context()->module()->ext_inst_debuginfo_begin());
   }
   }
@@ -523,16 +603,14 @@ void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
   // list.
   // list.
   if (debug_info_none_inst_ != nullptr &&
   if (debug_info_none_inst_ != nullptr &&
       debug_info_none_inst_->PreviousNode() != nullptr &&
       debug_info_none_inst_->PreviousNode() != nullptr &&
-      debug_info_none_inst_->PreviousNode()->GetOpenCL100DebugOpcode() !=
-          OpenCLDebugInfo100InstructionsMax) {
+      debug_info_none_inst_->PreviousNode()->IsOpenCL100DebugInstr()) {
     debug_info_none_inst_->InsertBefore(
     debug_info_none_inst_->InsertBefore(
         &*context()->module()->ext_inst_debuginfo_begin());
         &*context()->module()->ext_inst_debuginfo_begin());
   }
   }
 }
 }
 
 
 void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
 void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
-  if (instr == nullptr ||
-      instr->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100InstructionsMax) {
+  if (instr == nullptr || !instr->IsOpenCL100DebugInstr()) {
     return;
     return;
   }
   }
 
 
@@ -554,6 +632,22 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
     }
     }
   }
   }
 
 
+  if (deref_operation_ == instr) {
+    deref_operation_ = nullptr;
+    for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
+         dbg_instr_itr != context()->module()->ext_inst_debuginfo_end();
+         ++dbg_instr_itr) {
+      if (instr != &*dbg_instr_itr &&
+          dbg_instr_itr->GetOpenCL100DebugOpcode() ==
+              OpenCLDebugInfo100DebugOperation &&
+          dbg_instr_itr->GetSingleWordOperand(
+              kDebugOperationOperandOpCodeIndex) == OpenCLDebugInfo100Deref) {
+        deref_operation_ = &*dbg_instr_itr;
+        break;
+      }
+    }
+  }
+
   if (debug_info_none_inst_ == instr) {
   if (debug_info_none_inst_ == instr) {
     debug_info_none_inst_ = nullptr;
     debug_info_none_inst_ = nullptr;
     for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
     for (auto dbg_instr_itr = context()->module()->ext_inst_debuginfo_begin();
@@ -563,6 +657,7 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
           dbg_instr_itr->GetOpenCL100DebugOpcode() ==
           dbg_instr_itr->GetOpenCL100DebugOpcode() ==
               OpenCLDebugInfo100DebugInfoNone) {
               OpenCLDebugInfo100DebugInfoNone) {
         debug_info_none_inst_ = &*dbg_instr_itr;
         debug_info_none_inst_ = &*dbg_instr_itr;
+        break;
       }
       }
     }
     }
   }
   }
@@ -574,6 +669,7 @@ void DebugInfoManager::ClearDebugInfo(Instruction* instr) {
          ++dbg_instr_itr) {
          ++dbg_instr_itr) {
       if (instr != &*dbg_instr_itr && IsEmptyDebugExpression(&*dbg_instr_itr)) {
       if (instr != &*dbg_instr_itr && IsEmptyDebugExpression(&*dbg_instr_itr)) {
         empty_debug_expr_inst_ = &*dbg_instr_itr;
         empty_debug_expr_inst_ = &*dbg_instr_itr;
+        break;
       }
       }
     }
     }
   }
   }

+ 16 - 0
3rdparty/spirv-tools/source/opt/debug_info_manager.h

@@ -95,6 +95,10 @@ class DebugInfoManager {
   uint32_t CreateDebugInlinedAt(const Instruction* line,
   uint32_t CreateDebugInlinedAt(const Instruction* line,
                                 const DebugScope& scope);
                                 const DebugScope& scope);
 
 
+  // Clones DebugExpress instruction |dbg_expr| and add Deref Operation
+  // in the front of the Operation list of |dbg_expr|.
+  Instruction* DerefDebugExpression(Instruction* dbg_expr);
+
   // Returns a DebugInfoNone instruction.
   // Returns a DebugInfoNone instruction.
   Instruction* GetDebugInfoNone();
   Instruction* GetDebugInfoNone();
 
 
@@ -129,6 +133,12 @@ class DebugInfoManager {
   uint32_t BuildDebugInlinedAtChain(uint32_t callee_inlined_at,
   uint32_t BuildDebugInlinedAtChain(uint32_t callee_inlined_at,
                                     DebugInlinedAtContext* inlined_at_ctx);
                                     DebugInlinedAtContext* inlined_at_ctx);
 
 
+  // Return true if |variable_id| has DebugDeclare or DebugVal.
+  bool IsDebugDeclared(uint32_t variable_id);
+
+  // Kill all DebugDeclares for |variable_id|
+  void KillDebugDeclares(uint32_t variable_id);
+
   // Generates a DebugValue instruction with value |value_id| for every local
   // Generates a DebugValue instruction with value |value_id| for every local
   // variable that is in the scope of |scope_and_line| and whose memory is
   // variable that is in the scope of |scope_and_line| and whose memory is
   // |variable_id| and inserts it after the instruction |insert_pos|.
   // |variable_id| and inserts it after the instruction |insert_pos|.
@@ -149,6 +159,9 @@ class DebugInfoManager {
   // does not exists.
   // does not exists.
   Instruction* GetDbgInst(uint32_t id);
   Instruction* GetDbgInst(uint32_t id);
 
 
+  // Returns a DebugOperation instruction with OpCode Deref.
+  Instruction* GetDebugOperationWithDeref();
+
   // Registers the debug instruction |inst| into |id_to_dbg_inst_| using id of
   // Registers the debug instruction |inst| into |id_to_dbg_inst_| using id of
   // |inst| as a key.
   // |inst| as a key.
   void RegisterDbgInst(Instruction* inst);
   void RegisterDbgInst(Instruction* inst);
@@ -197,6 +210,9 @@ class DebugInfoManager {
   std::unordered_map<uint32_t, std::unordered_set<Instruction*>>
   std::unordered_map<uint32_t, std::unordered_set<Instruction*>>
       var_id_to_dbg_decl_;
       var_id_to_dbg_decl_;
 
 
+  // DebugOperation whose OpCode is OpenCLDebugInfo100Deref.
+  Instruction* deref_operation_;
+
   // DebugInfoNone instruction. We need only a single DebugInfoNone.
   // DebugInfoNone instruction. We need only a single DebugInfoNone.
   // To reuse the existing one, we keep it using this member variable.
   // To reuse the existing one, we keep it using this member variable.
   Instruction* debug_info_none_inst_;
   Instruction* debug_info_none_inst_;

+ 9 - 0
3rdparty/spirv-tools/source/opt/instruction.h

@@ -306,6 +306,10 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
   void RemoveOperand(uint32_t index) {
   void RemoveOperand(uint32_t index) {
     operands_.erase(operands_.begin() + index);
     operands_.erase(operands_.begin() + index);
   }
   }
+  // Insert an operand before the |index|-th operand
+  void InsertOperand(uint32_t index, Operand&& operand) {
+    operands_.insert(operands_.begin() + index, operand);
+  }
 
 
   // The following methods are similar to the above, but are for in operands.
   // The following methods are similar to the above, but are for in operands.
   uint32_t NumInOperands() const {
   uint32_t NumInOperands() const {
@@ -535,6 +539,11 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
   // OpenCLDebugInfo100InstructionsMax.
   // OpenCLDebugInfo100InstructionsMax.
   OpenCLDebugInfo100Instructions GetOpenCL100DebugOpcode() const;
   OpenCLDebugInfo100Instructions GetOpenCL100DebugOpcode() const;
 
 
+  // Returns true if it is an OpenCL.DebugInfo.100 instruction.
+  bool IsOpenCL100DebugInstr() const {
+    return GetOpenCL100DebugOpcode() != OpenCLDebugInfo100InstructionsMax;
+  }
+
   // Dump this instruction on stderr.  Useful when running interactive
   // Dump this instruction on stderr.  Useful when running interactive
   // debuggers.
   // debuggers.
   void Dump() const;
   void Dump() const;

+ 9 - 2
3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp

@@ -31,6 +31,11 @@ const uint32_t kStoreValIdInIdx = 1;
 bool LocalSingleBlockLoadStoreElimPass::HasOnlySupportedRefs(uint32_t ptrId) {
 bool LocalSingleBlockLoadStoreElimPass::HasOnlySupportedRefs(uint32_t ptrId) {
   if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end()) return true;
   if (supported_ref_ptrs_.find(ptrId) != supported_ref_ptrs_.end()) return true;
   if (get_def_use_mgr()->WhileEachUser(ptrId, [this](Instruction* user) {
   if (get_def_use_mgr()->WhileEachUser(ptrId, [this](Instruction* user) {
+        auto dbg_op = user->GetOpenCL100DebugOpcode();
+        if (dbg_op == OpenCLDebugInfo100DebugDeclare ||
+            dbg_op == OpenCLDebugInfo100DebugValue) {
+          return true;
+        }
         SpvOp op = user->opcode();
         SpvOp op = user->opcode();
         if (IsNonPtrAccessChain(op) || op == SpvOpCopyObject) {
         if (IsNonPtrAccessChain(op) || op == SpvOpCopyObject) {
           if (!HasOnlySupportedRefs(user->result_id())) {
           if (!HasOnlySupportedRefs(user->result_id())) {
@@ -73,10 +78,12 @@ bool LocalSingleBlockLoadStoreElimPass::LocalSingleBlockLoadStoreElim(
           // variable.
           // variable.
           if (ptrInst->opcode() == SpvOpVariable) {
           if (ptrInst->opcode() == SpvOpVariable) {
             // If a previous store to same variable, mark the store
             // If a previous store to same variable, mark the store
-            // for deletion if not still used.
+            // for deletion if not still used. Don't delete store
+            // if debugging; let ssa-rewrite and DCE handle it
             auto prev_store = var2store_.find(varId);
             auto prev_store = var2store_.find(varId);
             if (prev_store != var2store_.end() &&
             if (prev_store != var2store_.end() &&
-                instructions_to_save.count(prev_store->second) == 0) {
+                instructions_to_save.count(prev_store->second) == 0 &&
+                !context()->get_debug_info_mgr()->IsDebugDeclared(varId)) {
               instructions_to_kill.push_back(prev_store->second);
               instructions_to_kill.push_back(prev_store->second);
               modified = true;
               modified = true;
             }
             }

+ 45 - 10
3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp

@@ -133,7 +133,27 @@ bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) {
     return false;
     return false;
   }
   }
 
 
-  return RewriteLoads(store_inst, users);
+  bool all_rewritten;
+  bool modified = RewriteLoads(store_inst, users, &all_rewritten);
+
+  // If all uses are rewritten and the variable has a DebugDeclare and the
+  // variable is not an aggregate, add a DebugValue after the store and remove
+  // the DebugDeclare.
+  uint32_t var_id = var_inst->result_id();
+  if (all_rewritten &&
+      context()->get_debug_info_mgr()->IsDebugDeclared(var_id)) {
+    const analysis::Type* var_type =
+        context()->get_type_mgr()->GetType(var_inst->type_id());
+    const analysis::Type* store_type = var_type->AsPointer()->pointee_type();
+    if (!(store_type->AsStruct() || store_type->AsArray())) {
+      context()->get_debug_info_mgr()->AddDebugValue(
+          store_inst, var_id, store_inst->GetSingleWordInOperand(1),
+          store_inst);
+      context()->get_debug_info_mgr()->KillDebugDeclares(var_id);
+    }
+  }
+
+  return modified;
 }
 }
 
 
 Instruction* LocalSingleStoreElimPass::FindSingleStoreAndCheckUses(
 Instruction* LocalSingleStoreElimPass::FindSingleStoreAndCheckUses(
@@ -172,6 +192,14 @@ Instruction* LocalSingleStoreElimPass::FindSingleStoreAndCheckUses(
       case SpvOpName:
       case SpvOpName:
       case SpvOpCopyObject:
       case SpvOpCopyObject:
         break;
         break;
+      case SpvOpExtInst: {
+        auto dbg_op = user->GetOpenCL100DebugOpcode();
+        if (dbg_op == OpenCLDebugInfo100DebugDeclare ||
+            dbg_op == OpenCLDebugInfo100DebugValue) {
+          break;
+        }
+        return nullptr;
+      }
       default:
       default:
         if (!user->IsDecoration()) {
         if (!user->IsDecoration()) {
           // Don't know if this instruction modifies the variable.
           // Don't know if this instruction modifies the variable.
@@ -218,7 +246,8 @@ bool LocalSingleStoreElimPass::FeedsAStore(Instruction* inst) const {
 }
 }
 
 
 bool LocalSingleStoreElimPass::RewriteLoads(
 bool LocalSingleStoreElimPass::RewriteLoads(
-    Instruction* store_inst, const std::vector<Instruction*>& uses) {
+    Instruction* store_inst, const std::vector<Instruction*>& uses,
+    bool* all_rewritten) {
   BasicBlock* store_block = context()->get_instr_block(store_inst);
   BasicBlock* store_block = context()->get_instr_block(store_inst);
   DominatorAnalysis* dominator_analysis =
   DominatorAnalysis* dominator_analysis =
       context()->GetDominatorAnalysis(store_block->GetParent());
       context()->GetDominatorAnalysis(store_block->GetParent());
@@ -229,16 +258,22 @@ bool LocalSingleStoreElimPass::RewriteLoads(
   else
   else
     stored_id = store_inst->GetSingleWordInOperand(kVariableInitIdInIdx);
     stored_id = store_inst->GetSingleWordInOperand(kVariableInitIdInIdx);
 
 
-  std::vector<Instruction*> uses_in_store_block;
+  *all_rewritten = true;
   bool modified = false;
   bool modified = false;
   for (Instruction* use : uses) {
   for (Instruction* use : uses) {
-    if (use->opcode() == SpvOpLoad) {
-      if (dominator_analysis->Dominates(store_inst, use)) {
-        modified = true;
-        context()->KillNamesAndDecorates(use->result_id());
-        context()->ReplaceAllUsesWith(use->result_id(), stored_id);
-        context()->KillInst(use);
-      }
+    if (use->opcode() == SpvOpStore) continue;
+    auto dbg_op = use->GetOpenCL100DebugOpcode();
+    if (dbg_op == OpenCLDebugInfo100DebugDeclare ||
+        dbg_op == OpenCLDebugInfo100DebugValue)
+      continue;
+    if (use->opcode() == SpvOpLoad &&
+        dominator_analysis->Dominates(store_inst, use)) {
+      modified = true;
+      context()->KillNamesAndDecorates(use->result_id());
+      context()->ReplaceAllUsesWith(use->result_id(), stored_id);
+      context()->KillInst(use);
+    } else {
+      *all_rewritten = false;
     }
     }
   }
   }
 
 

+ 3 - 2
3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.h

@@ -89,9 +89,10 @@ class LocalSingleStoreElimPass : public Pass {
   bool FeedsAStore(Instruction* inst) const;
   bool FeedsAStore(Instruction* inst) const;
 
 
   // Replaces all of the loads in |uses| by the value stored in |store_inst|.
   // Replaces all of the loads in |uses| by the value stored in |store_inst|.
-  // The load instructions are then killed.
+  // The load instructions are then killed. |all_rewritten| is true iff all
+  // uses have been rewritten.
   bool RewriteLoads(Instruction* store_inst,
   bool RewriteLoads(Instruction* store_inst,
-                    const std::vector<Instruction*>& uses);
+                    const std::vector<Instruction*>& uses, bool* all_rewritten);
 
 
   // Extensions supported by this pass.
   // Extensions supported by this pass.
   std::unordered_set<std::string> extensions_allowlist_;
   std::unordered_set<std::string> extensions_allowlist_;

+ 0 - 4
3rdparty/spirv-tools/source/opt/pass.h

@@ -71,10 +71,6 @@ class Pass {
     return context()->get_def_use_mgr();
     return context()->get_def_use_mgr();
   }
   }
 
 
-  analysis::DebugInfoManager* get_debug_info_mgr() const {
-    return context()->get_debug_info_mgr();
-  }
-
   analysis::DecorationManager* get_decoration_mgr() const {
   analysis::DecorationManager* get_decoration_mgr() const {
     return context()->get_decoration_mgr();
     return context()->get_decoration_mgr();
   }
   }

+ 3 - 2
3rdparty/spirv-tools/source/opt/reduce_load_size.cpp

@@ -112,10 +112,10 @@ bool ReduceLoadSize::ReplaceExtract(Instruction* inst) {
   Instruction* new_access_chain = ir_builder.AddAccessChain(
   Instruction* new_access_chain = ir_builder.AddAccessChain(
       pointer_to_result_type_id,
       pointer_to_result_type_id,
       composite_inst->GetSingleWordInOperand(kLoadPointerInIdx), ids);
       composite_inst->GetSingleWordInOperand(kLoadPointerInIdx), ids);
-  Instruction* new_laod =
+  Instruction* new_load =
       ir_builder.AddLoad(inst->type_id(), new_access_chain->result_id());
       ir_builder.AddLoad(inst->type_id(), new_access_chain->result_id());
 
 
-  context()->ReplaceAllUsesWith(inst->result_id(), new_laod->result_id());
+  context()->ReplaceAllUsesWith(inst->result_id(), new_load->result_id());
   context()->KillInst(inst);
   context()->KillInst(inst);
   return true;
   return true;
 }
 }
@@ -139,6 +139,7 @@ bool ReduceLoadSize::ShouldReplaceExtract(Instruction* inst) {
 
 
   all_elements_used =
   all_elements_used =
       !def_use_mgr->WhileEachUser(op_inst, [&elements_used](Instruction* use) {
       !def_use_mgr->WhileEachUser(op_inst, [&elements_used](Instruction* use) {
+        if (use->IsOpenCL100DebugInstr()) return true;
         if (use->opcode() != SpvOpCompositeExtract ||
         if (use->opcode() != SpvOpCompositeExtract ||
             use->NumInOperands() == 1) {
             use->NumInOperands() == 1) {
           return false;
           return false;

+ 3 - 2
3rdparty/spirv-tools/source/opt/ssa_rewrite_pass.cpp

@@ -307,7 +307,8 @@ void SSARewriter::ProcessStore(Instruction* inst, BasicBlock* bb) {
   }
   }
   if (pass_->IsTargetVar(var_id)) {
   if (pass_->IsTargetVar(var_id)) {
     WriteVariable(var_id, bb, val_id);
     WriteVariable(var_id, bb, val_id);
-    pass_->get_debug_info_mgr()->AddDebugValue(inst, var_id, val_id, inst);
+    pass_->context()->get_debug_info_mgr()->AddDebugValue(inst, var_id, val_id,
+                                                          inst);
 
 
 #if SSA_REWRITE_DEBUGGING_LEVEL > 1
 #if SSA_REWRITE_DEBUGGING_LEVEL > 1
     std::cerr << "\tFound store '%" << var_id << " = %" << val_id << "': "
     std::cerr << "\tFound store '%" << var_id << " = %" << val_id << "': "
@@ -490,7 +491,7 @@ bool SSARewriter::ApplyReplacements() {
 
 
     // Add DebugValue for the new OpPhi instruction.
     // Add DebugValue for the new OpPhi instruction.
     insert_it->SetDebugScope(local_var->GetDebugScope());
     insert_it->SetDebugScope(local_var->GetDebugScope());
-    pass_->get_debug_info_mgr()->AddDebugValue(
+    pass_->context()->get_debug_info_mgr()->AddDebugValue(
         &*insert_it, phi_candidate->var_id(), phi_candidate->result_id(),
         &*insert_it, phi_candidate->var_id(), phi_candidate->result_id(),
         &*insert_it);
         &*insert_it);
 
 

+ 60 - 38
3rdparty/spirv-tools/source/opt/vector_dce.cpp

@@ -52,6 +52,9 @@ void VectorDCE::FindLiveComponents(Function* function,
   // components are live because of arbitrary nesting of structs.
   // components are live because of arbitrary nesting of structs.
   function->ForEachInst(
   function->ForEachInst(
       [&work_list, this, live_components](Instruction* current_inst) {
       [&work_list, this, live_components](Instruction* current_inst) {
+        if (current_inst->IsOpenCL100DebugInstr()) {
+          return;
+        }
         if (!HasVectorOrScalarResult(current_inst) ||
         if (!HasVectorOrScalarResult(current_inst) ||
             !context()->IsCombinatorInstruction(current_inst)) {
             !context()->IsCombinatorInstruction(current_inst)) {
           MarkUsesAsLive(current_inst, all_components_live_, live_components,
           MarkUsesAsLive(current_inst, all_components_live_, live_components,
@@ -297,51 +300,60 @@ bool VectorDCE::HasScalarResult(const Instruction* inst) const {
 bool VectorDCE::RewriteInstructions(
 bool VectorDCE::RewriteInstructions(
     Function* function, const VectorDCE::LiveComponentMap& live_components) {
     Function* function, const VectorDCE::LiveComponentMap& live_components) {
   bool modified = false;
   bool modified = false;
-  function->ForEachInst(
-      [&modified, this, live_components](Instruction* current_inst) {
-        if (!context()->IsCombinatorInstruction(current_inst)) {
-          return;
-        }
 
 
-        auto live_component = live_components.find(current_inst->result_id());
-        if (live_component == live_components.end()) {
-          // If this instruction is not in live_components then it does not
-          // produce a vector, or it is never referenced and ADCE will remove
-          // it.  No point in trying to differentiate.
-          return;
-        }
+  // Kill DebugValue in the middle of the instruction iteration will result
+  // in accessing a dangling pointer. We keep dead DebugValue instructions
+  // in |dead_dbg_value| to kill them once after the iteration.
+  std::vector<Instruction*> dead_dbg_value;
 
 
-        // If no element in the current instruction is used replace it with an
-        // OpUndef.
-        if (live_component->second.Empty()) {
-          modified = true;
-          uint32_t undef_id = this->Type2Undef(current_inst->type_id());
-          context()->KillNamesAndDecorates(current_inst);
-          context()->ReplaceAllUsesWith(current_inst->result_id(), undef_id);
-          context()->KillInst(current_inst);
-          return;
-        }
+  function->ForEachInst([&modified, this, live_components,
+                         &dead_dbg_value](Instruction* current_inst) {
+    if (!context()->IsCombinatorInstruction(current_inst)) {
+      return;
+    }
 
 
-        switch (current_inst->opcode()) {
-          case SpvOpCompositeInsert:
-            modified |=
-                RewriteInsertInstruction(current_inst, live_component->second);
-            break;
-          case SpvOpCompositeConstruct:
-            // TODO: The members that are not live can be replaced by an undef
-            // or constant. This will remove uses of those values, and possibly
-            // create opportunities for ADCE.
-            break;
-          default:
-            // Do nothing.
-            break;
-        }
-      });
+    auto live_component = live_components.find(current_inst->result_id());
+    if (live_component == live_components.end()) {
+      // If this instruction is not in live_components then it does not
+      // produce a vector, or it is never referenced and ADCE will remove
+      // it.  No point in trying to differentiate.
+      return;
+    }
+
+    // If no element in the current instruction is used replace it with an
+    // OpUndef.
+    if (live_component->second.Empty()) {
+      modified = true;
+      MarkDebugValueUsesAsDead(current_inst, &dead_dbg_value);
+      uint32_t undef_id = this->Type2Undef(current_inst->type_id());
+      context()->KillNamesAndDecorates(current_inst);
+      context()->ReplaceAllUsesWith(current_inst->result_id(), undef_id);
+      context()->KillInst(current_inst);
+      return;
+    }
+
+    switch (current_inst->opcode()) {
+      case SpvOpCompositeInsert:
+        modified |= RewriteInsertInstruction(
+            current_inst, live_component->second, &dead_dbg_value);
+        break;
+      case SpvOpCompositeConstruct:
+        // TODO: The members that are not live can be replaced by an undef
+        // or constant. This will remove uses of those values, and possibly
+        // create opportunities for ADCE.
+        break;
+      default:
+        // Do nothing.
+        break;
+    }
+  });
+  for (auto* i : dead_dbg_value) context()->KillInst(i);
   return modified;
   return modified;
 }
 }
 
 
 bool VectorDCE::RewriteInsertInstruction(
 bool VectorDCE::RewriteInsertInstruction(
-    Instruction* current_inst, const utils::BitVector& live_components) {
+    Instruction* current_inst, const utils::BitVector& live_components,
+    std::vector<Instruction*>* dead_dbg_value) {
   // If the value being inserted is not live, then we can skip the insert.
   // If the value being inserted is not live, then we can skip the insert.
 
 
   if (current_inst->NumInOperands() == 2) {
   if (current_inst->NumInOperands() == 2) {
@@ -355,6 +367,7 @@ bool VectorDCE::RewriteInsertInstruction(
 
 
   uint32_t insert_index = current_inst->GetSingleWordInOperand(2);
   uint32_t insert_index = current_inst->GetSingleWordInOperand(2);
   if (!live_components.Get(insert_index)) {
   if (!live_components.Get(insert_index)) {
+    MarkDebugValueUsesAsDead(current_inst, dead_dbg_value);
     context()->KillNamesAndDecorates(current_inst->result_id());
     context()->KillNamesAndDecorates(current_inst->result_id());
     uint32_t composite_id =
     uint32_t composite_id =
         current_inst->GetSingleWordInOperand(kInsertCompositeIdInIdx);
         current_inst->GetSingleWordInOperand(kInsertCompositeIdInIdx);
@@ -377,6 +390,15 @@ bool VectorDCE::RewriteInsertInstruction(
   return false;
   return false;
 }
 }
 
 
+void VectorDCE::MarkDebugValueUsesAsDead(
+    Instruction* composite, std::vector<Instruction*>* dead_dbg_value) {
+  context()->get_def_use_mgr()->ForEachUser(
+      composite, [&dead_dbg_value](Instruction* use) {
+        if (use->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugValue)
+          dead_dbg_value->push_back(use);
+      });
+}
+
 void VectorDCE::AddItemToWorkListIfNeeded(
 void VectorDCE::AddItemToWorkListIfNeeded(
     WorkListItem work_item, VectorDCE::LiveComponentMap* live_components,
     WorkListItem work_item, VectorDCE::LiveComponentMap* live_components,
     std::vector<WorkListItem>* work_list) {
     std::vector<WorkListItem>* work_list) {

+ 7 - 1
3rdparty/spirv-tools/source/opt/vector_dce.h

@@ -73,6 +73,11 @@ class VectorDCE : public MemPass {
   bool RewriteInstructions(Function* function,
   bool RewriteInstructions(Function* function,
                            const LiveComponentMap& live_components);
                            const LiveComponentMap& live_components);
 
 
+  // Makrs all DebugValue instructions that use |composite| for their values as
+  // dead instructions by putting them into |dead_dbg_value|.
+  void MarkDebugValueUsesAsDead(Instruction* composite,
+                                std::vector<Instruction*>* dead_dbg_value);
+
   // Rewrites the OpCompositeInsert instruction |current_inst| to avoid
   // Rewrites the OpCompositeInsert instruction |current_inst| to avoid
   // unnecessary computes given that the only components of the result that are
   // unnecessary computes given that the only components of the result that are
   // live are |live_components|.
   // live are |live_components|.
@@ -83,7 +88,8 @@ class VectorDCE : public MemPass {
   // If the composite input to |current_inst| is not live, then it is replaced
   // If the composite input to |current_inst| is not live, then it is replaced
   // by and OpUndef in |current_inst|.
   // by and OpUndef in |current_inst|.
   bool RewriteInsertInstruction(Instruction* current_inst,
   bool RewriteInsertInstruction(Instruction* current_inst,
-                                const utils::BitVector& live_components);
+                                const utils::BitVector& live_components,
+                                std::vector<Instruction*>* dead_dbg_value);
 
 
   // Returns true if the result of |inst| is a vector or a scalar.
   // Returns true if the result of |inst| is a vector or a scalar.
   bool HasVectorOrScalarResult(const Instruction* inst) const;
   bool HasVectorOrScalarResult(const Instruction* inst) const;

+ 2 - 1
3rdparty/spirv-tools/utils/check_copyright.py

@@ -35,7 +35,8 @@ AUTHORS = ['The Khronos Group Inc.',
            'Samsung Inc',
            'Samsung Inc',
            'André Perez Maselco',
            'André Perez Maselco',
            'Vasyl Teliman',
            'Vasyl Teliman',
-           'Advanced Micro Devices, Inc.']
+           'Advanced Micro Devices, Inc.',
+           'Stefano Milizia']
 CURRENT_YEAR='2020'
 CURRENT_YEAR='2020'
 
 
 YEARS = '(2014-2016|2015-2016|2015-2020|2016|2016-2017|2017|2017-2019|2018|2019|2020)'
 YEARS = '(2014-2016|2015-2016|2015-2020|2016|2016-2017|2017|2017-2019|2018|2019|2020)'