Бранимир Караџић 5 роки тому
батько
коміт
4979ee49ab
29 змінених файлів з 813 додано та 50 видалено
  1. 1 1
      3rdparty/spirv-tools/include/generated/build-version.inc
  2. 6 0
      3rdparty/spirv-tools/source/fuzz/CMakeLists.txt
  3. 8 0
      3rdparty/spirv-tools/source/fuzz/fuzzer.cpp
  4. 17 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_context.cpp
  5. 34 12
      3rdparty/spirv-tools/source/fuzz/fuzzer_context.h
  6. 133 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp
  7. 39 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h
  8. 64 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.cpp
  9. 40 0
      3rdparty/spirv-tools/source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h
  10. 28 0
      3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto
  11. 5 0
      3rdparty/spirv-tools/source/fuzz/transformation.cpp
  12. 275 0
      3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.cpp
  13. 67 0
      3rdparty/spirv-tools/source/fuzz/transformation_replace_linear_algebra_instruction.h
  14. 16 0
      3rdparty/spirv-tools/source/opcode.cpp
  15. 3 0
      3rdparty/spirv-tools/source/opcode.h
  16. 1 1
      3rdparty/spirv-tools/source/operand.cpp
  17. 5 5
      3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp
  18. 2 2
      3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.h
  19. 1 0
      3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.cpp
  20. 12 0
      3rdparty/spirv-tools/source/opt/function.h
  21. 10 0
      3rdparty/spirv-tools/source/opt/instruction_list.h
  22. 5 5
      3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.cpp
  23. 2 2
      3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.h
  24. 5 5
      3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.cpp
  25. 2 2
      3rdparty/spirv-tools/source/opt/local_single_block_elim_pass.h
  26. 5 5
      3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.cpp
  27. 3 3
      3rdparty/spirv-tools/source/opt/local_single_store_elim_pass.h
  28. 21 4
      3rdparty/spirv-tools/source/opt/loop_descriptor.cpp
  29. 3 3
      3rdparty/spirv-tools/utils/check_symbol_exports.py

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

@@ -1 +1 @@
-"v2020.4-dev", "SPIRV-Tools v2020.4-dev 2cdcab3215d654e18c3b6d5f12bd94e7e64fb8b1"
+"v2020.4-dev", "SPIRV-Tools v2020.4-dev 685eeed2529a1671c875d204406decacdff43cb3"

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

@@ -49,6 +49,7 @@ if(SPIRV_BUILD_FUZZER)
         fuzzer_pass_add_local_variables.h
         fuzzer_pass_add_no_contraction_decorations.h
         fuzzer_pass_add_stores.h
+        fuzzer_pass_add_vector_shuffle_instructions.h
         fuzzer_pass_adjust_branch_weights.h
         fuzzer_pass_adjust_function_controls.h
         fuzzer_pass_adjust_loop_controls.h
@@ -64,6 +65,7 @@ if(SPIRV_BUILD_FUZZER)
         fuzzer_pass_permute_blocks.h
         fuzzer_pass_permute_function_parameters.h
         fuzzer_pass_push_ids_through_variables.h
+        fuzzer_pass_replace_linear_algebra_instructions.h
         fuzzer_pass_split_blocks.h
         fuzzer_pass_swap_commutable_operands.h
         fuzzer_pass_toggle_access_chain_instruction.h
@@ -117,6 +119,7 @@ if(SPIRV_BUILD_FUZZER)
         transformation_replace_boolean_constant_with_constant_binary.h
         transformation_replace_constant_with_uniform.h
         transformation_replace_id_with_synonym.h
+        transformation_replace_linear_algebra_instruction.h
         transformation_set_function_control.h
         transformation_set_loop_control.h
         transformation_set_memory_operands_mask.h
@@ -148,6 +151,7 @@ if(SPIRV_BUILD_FUZZER)
         fuzzer_pass_add_local_variables.cpp
         fuzzer_pass_add_no_contraction_decorations.cpp
         fuzzer_pass_add_stores.cpp
+        fuzzer_pass_add_vector_shuffle_instructions.cpp
         fuzzer_pass_adjust_branch_weights.cpp
         fuzzer_pass_adjust_function_controls.cpp
         fuzzer_pass_adjust_loop_controls.cpp
@@ -163,6 +167,7 @@ if(SPIRV_BUILD_FUZZER)
         fuzzer_pass_permute_blocks.cpp
         fuzzer_pass_permute_function_parameters.cpp
         fuzzer_pass_push_ids_through_variables.cpp
+        fuzzer_pass_replace_linear_algebra_instructions.cpp
         fuzzer_pass_split_blocks.cpp
         fuzzer_pass_swap_commutable_operands.cpp
         fuzzer_pass_toggle_access_chain_instruction.cpp
@@ -215,6 +220,7 @@ if(SPIRV_BUILD_FUZZER)
         transformation_replace_boolean_constant_with_constant_binary.cpp
         transformation_replace_constant_with_uniform.cpp
         transformation_replace_id_with_synonym.cpp
+        transformation_replace_linear_algebra_instruction.cpp
         transformation_set_function_control.cpp
         transformation_set_loop_control.cpp
         transformation_set_memory_operands_mask.cpp

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

@@ -33,6 +33,7 @@
 #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_stores.h"
+#include "source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h"
 #include "source/fuzz/fuzzer_pass_adjust_branch_weights.h"
 #include "source/fuzz/fuzzer_pass_adjust_function_controls.h"
 #include "source/fuzz/fuzzer_pass_adjust_loop_controls.h"
@@ -47,6 +48,7 @@
 #include "source/fuzz/fuzzer_pass_permute_blocks.h"
 #include "source/fuzz/fuzzer_pass_permute_function_parameters.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_split_blocks.h"
 #include "source/fuzz/fuzzer_pass_swap_commutable_operands.h"
 #include "source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h"
@@ -223,6 +225,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
     MaybeAddPass<FuzzerPassAddStores>(&passes, ir_context.get(),
                                       &transformation_context, &fuzzer_context,
                                       transformation_sequence_out);
+    MaybeAddPass<FuzzerPassAddVectorShuffleInstructions>(
+        &passes, ir_context.get(), &transformation_context, &fuzzer_context,
+        transformation_sequence_out);
     MaybeAddPass<FuzzerPassApplyIdSynonyms>(
         &passes, ir_context.get(), &transformation_context, &fuzzer_context,
         transformation_sequence_out);
@@ -253,6 +258,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
     MaybeAddPass<FuzzerPassPushIdsThroughVariables>(
         &passes, ir_context.get(), &transformation_context, &fuzzer_context,
         transformation_sequence_out);
+    MaybeAddPass<FuzzerPassReplaceLinearAlgebraInstructions>(
+        &passes, ir_context.get(), &transformation_context, &fuzzer_context,
+        transformation_sequence_out);
     MaybeAddPass<FuzzerPassSplitBlocks>(
         &passes, ir_context.get(), &transformation_context, &fuzzer_context,
         transformation_sequence_out);

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

@@ -40,6 +40,7 @@ const std::pair<uint32_t, uint32_t> kChanceOfAddingNoContractionDecoration = {
     5, 70};
 const std::pair<uint32_t, uint32_t> kChanceOfAddingStore = {5, 50};
 const std::pair<uint32_t, uint32_t> kChanceOfAddingVectorType = {20, 70};
+const std::pair<uint32_t, uint32_t> kChanceOfAddingVectorShuffle = {20, 70};
 const std::pair<uint32_t, uint32_t> kChanceOfAdjustingBranchWeights = {20, 90};
 const std::pair<uint32_t, uint32_t> kChanceOfAdjustingFunctionControl = {20,
                                                                          70};
@@ -64,6 +65,8 @@ const std::pair<uint32_t, uint32_t> kChanceOfOutliningFunction = {10, 90};
 const std::pair<uint32_t, uint32_t> kChanceOfPermutingParameters = {30, 90};
 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>
+    kChanceOfReplacingLinearAlgebraInstructions = {10, 90};
 const std::pair<uint32_t, uint32_t> kChanceOfSplittingBlock = {40, 95};
 const std::pair<uint32_t, uint32_t> kChanceOfTogglingAccessChainInstruction = {
     20, 90};
@@ -124,6 +127,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
   chance_of_adding_no_contraction_decoration_ =
       ChooseBetweenMinAndMax(kChanceOfAddingNoContractionDecoration);
   chance_of_adding_store_ = ChooseBetweenMinAndMax(kChanceOfAddingStore);
+  chance_of_adding_vector_shuffle_ =
+      ChooseBetweenMinAndMax(kChanceOfAddingVectorShuffle);
   chance_of_adding_vector_type_ =
       ChooseBetweenMinAndMax(kChanceOfAddingVectorType);
   chance_of_adjusting_branch_weights_ =
@@ -162,6 +167,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
       ChooseBetweenMinAndMax(kChanceOfPushingIdThroughVariable);
   chance_of_replacing_id_with_synonym_ =
       ChooseBetweenMinAndMax(kChanceOfReplacingIdWithSynonym);
+  chance_of_replacing_linear_algebra_instructions_ =
+      ChooseBetweenMinAndMax(kChanceOfReplacingLinearAlgebraInstructions);
   chance_of_splitting_block_ = ChooseBetweenMinAndMax(kChanceOfSplittingBlock);
   chance_of_toggling_access_chain_instruction_ =
       ChooseBetweenMinAndMax(kChanceOfTogglingAccessChainInstruction);
@@ -171,6 +178,16 @@ FuzzerContext::~FuzzerContext() = default;
 
 uint32_t FuzzerContext::GetFreshId() { return next_fresh_id_++; }
 
+std::vector<uint32_t> FuzzerContext::GetFreshIds(const uint32_t count) {
+  std::vector<uint32_t> fresh_ids(count);
+
+  for (uint32_t& fresh_id : fresh_ids) {
+    fresh_id = next_fresh_id_++;
+  }
+
+  return fresh_ids;
+}
+
 bool FuzzerContext::ChooseEven() { return random_generator_->RandomBool(); }
 
 bool FuzzerContext::ChoosePercentage(uint32_t percentage_chance) {

+ 34 - 12
3rdparty/spirv-tools/source/fuzz/fuzzer_context.h

@@ -100,6 +100,9 @@ class FuzzerContext {
   // or to have been issued before.
   uint32_t GetFreshId();
 
+  // Returns a vector of |count| fresh ids.
+  std::vector<uint32_t> GetFreshIds(const uint32_t count);
+
   // Probabilities associated with applying various transformations.
   // Keep them in alphabetical order.
   uint32_t GetChanceOfAddingAccessChain() {
@@ -133,6 +136,9 @@ class FuzzerContext {
     return chance_of_adding_no_contraction_decoration_;
   }
   uint32_t GetChanceOfAddingStore() { return chance_of_adding_store_; }
+  uint32_t GetChanceOfAddingVectorShuffle() {
+    return chance_of_adding_vector_shuffle_;
+  }
   uint32_t GetChanceOfAddingVectorType() {
     return chance_of_adding_vector_type_;
   }
@@ -185,6 +191,9 @@ class FuzzerContext {
   uint32_t GetChanceOfReplacingIdWithSynonym() {
     return chance_of_replacing_id_with_synonym_;
   }
+  uint32_t GetChanceOfReplacingLinearAlgebraInstructions() {
+    return chance_of_replacing_linear_algebra_instructions_;
+  }
   uint32_t GetChanceOfSplittingBlock() { return chance_of_splitting_block_; }
   uint32_t GetChanceOfTogglingAccessChainInstruction() {
     return chance_of_toggling_access_chain_instruction_;
@@ -195,18 +204,6 @@ class FuzzerContext {
   uint32_t GetMaximumEquivalenceClassSizeForDataSynonymFactClosure() {
     return max_equivalence_class_size_for_data_synonym_fact_closure_;
   }
-  uint32_t GetRandomIndexForAccessChain(uint32_t composite_size_bound) {
-    return random_generator_->RandomUint32(composite_size_bound);
-  }
-  uint32_t GetRandomLoopControlPartialCount() {
-    return random_generator_->RandomUint32(max_loop_control_partial_count_);
-  }
-  uint32_t GetRandomLoopControlPeelCount() {
-    return random_generator_->RandomUint32(max_loop_control_peel_count_);
-  }
-  uint32_t GetRandomLoopLimit() {
-    return random_generator_->RandomUint32(max_loop_limit_);
-  }
   std::pair<uint32_t, uint32_t> GetRandomBranchWeights() {
     std::pair<uint32_t, uint32_t> branch_weights = {0, 0};
 
@@ -219,6 +216,29 @@ class FuzzerContext {
 
     return branch_weights;
   }
+  std::vector<uint32_t> GetRandomComponentsForVectorShuffle(
+      uint32_t max_component_index) {
+    // Component count must be in range [2, 4].
+    std::vector<uint32_t> components(random_generator_->RandomUint32(2) + 2);
+
+    for (uint32_t& component : components) {
+      component = random_generator_->RandomUint32(max_component_index);
+    }
+
+    return components;
+  }
+  uint32_t GetRandomIndexForAccessChain(uint32_t composite_size_bound) {
+    return random_generator_->RandomUint32(composite_size_bound);
+  }
+  uint32_t GetRandomLoopControlPartialCount() {
+    return random_generator_->RandomUint32(max_loop_control_partial_count_);
+  }
+  uint32_t GetRandomLoopControlPeelCount() {
+    return random_generator_->RandomUint32(max_loop_control_peel_count_);
+  }
+  uint32_t GetRandomLoopLimit() {
+    return random_generator_->RandomUint32(max_loop_limit_);
+  }
   uint32_t GetRandomSizeForNewArray() {
     // Ensure that the array size is non-zero.
     return random_generator_->RandomUint32(max_new_array_size_limit_ - 1) + 1;
@@ -248,6 +268,7 @@ class FuzzerContext {
   uint32_t chance_of_adding_matrix_type_;
   uint32_t chance_of_adding_no_contraction_decoration_;
   uint32_t chance_of_adding_store_;
+  uint32_t chance_of_adding_vector_shuffle_;
   uint32_t chance_of_adding_vector_type_;
   uint32_t chance_of_adjusting_branch_weights_;
   uint32_t chance_of_adjusting_function_control_;
@@ -268,6 +289,7 @@ class FuzzerContext {
   uint32_t chance_of_permuting_parameters_;
   uint32_t chance_of_pushing_id_through_variable_;
   uint32_t chance_of_replacing_id_with_synonym_;
+  uint32_t chance_of_replacing_linear_algebra_instructions_;
   uint32_t chance_of_splitting_block_;
   uint32_t chance_of_toggling_access_chain_instruction_;
 

+ 133 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.cpp

@@ -0,0 +1,133 @@
+// 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_vector_shuffle_instructions.h"
+
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "source/fuzz/transformation_vector_shuffle.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassAddVectorShuffleInstructions::FuzzerPassAddVectorShuffleInstructions(
+    opt::IRContext* ir_context, TransformationContext* transformation_context,
+    FuzzerContext* fuzzer_context,
+    protobufs::TransformationSequence* transformations)
+    : FuzzerPass(ir_context, transformation_context, fuzzer_context,
+                 transformations) {}
+
+FuzzerPassAddVectorShuffleInstructions::
+    ~FuzzerPassAddVectorShuffleInstructions() = default;
+
+void FuzzerPassAddVectorShuffleInstructions::Apply() {
+  ForEachInstructionWithInstructionDescriptor(
+      [this](opt::Function* function, opt::BasicBlock* block,
+             opt::BasicBlock::iterator instruction_iterator,
+             const protobufs::InstructionDescriptor& instruction_descriptor)
+          -> void {
+        assert(instruction_iterator->opcode() ==
+                   instruction_descriptor.target_instruction_opcode() &&
+               "The opcode of the instruction we might insert before must be "
+               "the same as the opcode in the descriptor for the instruction");
+
+        // Randomly decide whether to try adding an OpVectorShuffle instruction.
+        if (!GetFuzzerContext()->ChoosePercentage(
+                GetFuzzerContext()->GetChanceOfAddingVectorShuffle())) {
+          return;
+        }
+
+        // It must be valid to insert an OpVectorShuffle instruction
+        // before |instruction_iterator|.
+        if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
+                SpvOpVectorShuffle, instruction_iterator)) {
+          return;
+        }
+
+        // Looks for vectors that we might consider to use as OpVectorShuffle
+        // operands.
+        std::vector<opt::Instruction*> vector_instructions =
+            FindAvailableInstructions(
+                function, block, instruction_iterator,
+                [instruction_descriptor](
+                    opt::IRContext* ir_context,
+                    opt::Instruction* instruction) -> bool {
+                  if (!instruction->type_id()) {
+                    return false;
+                  }
+
+                  if (!ir_context->get_type_mgr()
+                           ->GetType(instruction->type_id())
+                           ->AsVector()) {
+                    return false;
+                  }
+
+                  return fuzzerutil::IdIsAvailableBeforeInstruction(
+                      ir_context,
+                      FindInstruction(instruction_descriptor, ir_context),
+                      instruction->result_id());
+                });
+
+        // If there are no vector instructions, then return.
+        if (vector_instructions.empty()) {
+          return;
+        }
+
+        auto vector_1_instruction =
+            vector_instructions[GetFuzzerContext()->RandomIndex(
+                vector_instructions)];
+        auto vector_1_type = GetIRContext()
+                                 ->get_type_mgr()
+                                 ->GetType(vector_1_instruction->type_id())
+                                 ->AsVector();
+
+        auto vector_2_instruction =
+            GetFuzzerContext()->RemoveAtRandomIndex(&vector_instructions);
+        auto vector_2_type = GetIRContext()
+                                 ->get_type_mgr()
+                                 ->GetType(vector_2_instruction->type_id())
+                                 ->AsVector();
+
+        // |vector_1| and |vector_2| must have the same element type as each
+        // other. The loop is guaranteed to terminate because each iteration
+        // removes on possible choice for |vector_2|, and there is at least one
+        // choice that will cause the loop to exit - namely |vector_1|.
+        while (vector_1_type->element_type() != vector_2_type->element_type()) {
+          vector_2_instruction =
+              GetFuzzerContext()->RemoveAtRandomIndex(&vector_instructions);
+          vector_2_type = GetIRContext()
+                              ->get_type_mgr()
+                              ->GetType(vector_2_instruction->type_id())
+                              ->AsVector();
+        }
+
+        // Gets components and creates the appropriate result vector type.
+        std::vector<uint32_t> components =
+            GetFuzzerContext()->GetRandomComponentsForVectorShuffle(
+                vector_1_type->element_count() +
+                vector_2_type->element_count());
+        FindOrCreateVectorType(GetIRContext()->get_type_mgr()->GetId(
+                                   vector_1_type->element_type()),
+                               static_cast<uint32_t>(components.size()));
+
+        // Applies the vector shuffle transformation.
+        ApplyTransformation(TransformationVectorShuffle(
+            instruction_descriptor, GetFuzzerContext()->GetFreshId(),
+            vector_1_instruction->result_id(),
+            vector_2_instruction->result_id(), components));
+      });
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 39 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h

@@ -0,0 +1,39 @@
+// 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_VECTOR_SHUFFLE_INSTRUCTIONS_H_
+#define SOURCE_FUZZ_FUZZER_PASS_ADD_VECTOR_SHUFFLE_INSTRUCTIONS_H_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// Adds OpVectorShuffle instructions to the module.
+class FuzzerPassAddVectorShuffleInstructions : public FuzzerPass {
+ public:
+  FuzzerPassAddVectorShuffleInstructions(
+      opt::IRContext* ir_context, TransformationContext* transformation_context,
+      FuzzerContext* fuzzer_context,
+      protobufs::TransformationSequence* transformations);
+
+  ~FuzzerPassAddVectorShuffleInstructions();
+
+  void Apply() override;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_FUZZER_PASS_ADD_VECTOR_SHUFFLE_INSTRUCTIONS_H_

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

@@ -0,0 +1,64 @@
+// 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_replace_linear_algebra_instructions.h"
+
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
+#include "source/fuzz/transformation_replace_linear_algebra_instruction.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPassReplaceLinearAlgebraInstructions::
+    FuzzerPassReplaceLinearAlgebraInstructions(
+        opt::IRContext* ir_context,
+        TransformationContext* transformation_context,
+        FuzzerContext* fuzzer_context,
+        protobufs::TransformationSequence* transformations)
+    : FuzzerPass(ir_context, transformation_context, fuzzer_context,
+                 transformations) {}
+
+FuzzerPassReplaceLinearAlgebraInstructions::
+    ~FuzzerPassReplaceLinearAlgebraInstructions() = default;
+
+void FuzzerPassReplaceLinearAlgebraInstructions::Apply() {
+  // For each instruction, checks whether it is a supported linear algebra
+  // instruction. In this case, the transformation is randomly applied.
+  GetIRContext()->module()->ForEachInst([this](opt::Instruction* instruction) {
+    // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3354):
+    // Right now we only support certain operations. When this issue is
+    // addressed the following conditional can use the function
+    // |spvOpcodeIsLinearAlgebra|.
+    if (instruction->opcode() != SpvOpVectorTimesScalar &&
+        instruction->opcode() != SpvOpDot) {
+      return;
+    }
+
+    if (!GetFuzzerContext()->ChoosePercentage(
+            GetFuzzerContext()
+                ->GetChanceOfReplacingLinearAlgebraInstructions())) {
+      return;
+    }
+
+    ApplyTransformation(TransformationReplaceLinearAlgebraInstruction(
+        GetFuzzerContext()->GetFreshIds(
+            TransformationReplaceLinearAlgebraInstruction::
+                GetRequiredFreshIdCount(GetIRContext(), instruction)),
+        MakeInstructionDescriptor(GetIRContext(), instruction)));
+  });
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

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

@@ -0,0 +1,40 @@
+// 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_REPLACE_LINEAR_ALGEBRA_INSTRUCTIONS_H_
+#define SOURCE_FUZZ_FUZZER_PASS_REPLACE_LINEAR_ALGEBRA_INSTRUCTIONS_H_
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// This fuzzer pass replaces linear algebra instructions with its mathematical
+// definition.
+class FuzzerPassReplaceLinearAlgebraInstructions : public FuzzerPass {
+ public:
+  FuzzerPassReplaceLinearAlgebraInstructions(
+      opt::IRContext* ir_context, TransformationContext* transformation_context,
+      FuzzerContext* fuzzer_context,
+      protobufs::TransformationSequence* transformations);
+
+  ~FuzzerPassReplaceLinearAlgebraInstructions();
+
+  void Apply() override;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_FUZZER_PASS_REPLACE_LINEAR_ALGEBRA_INSTRUCTIONS_H_

+ 28 - 0
3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto

@@ -377,6 +377,7 @@ message Transformation {
     TransformationAdjustBranchWeights adjust_branch_weights = 46;
     TransformationPushIdThroughVariable push_id_through_variable = 47;
     TransformationAddSpecConstantOp add_spec_constant_op = 48;
+    TransformationReplaceLinearAlgebraInstruction replace_linear_algebra_instruction = 49;
     // Add additional option using the next available number.
   }
 }
@@ -1081,6 +1082,33 @@ message TransformationReplaceIdWithSynonym {
 
 }
 
+message TransformationReplaceLinearAlgebraInstruction {
+
+  // Replaces a linear algebra instruction with its
+  // mathematical definition.
+
+  // The fresh ids needed to apply the transformation.
+  repeated uint32 fresh_ids = 1;
+
+  // A descriptor for a linear algebra instruction.
+  // This transformation is only applicable if the described instruction has one of the following opcodes.
+  // Supported:
+  //   OpVectorTimesScalar
+  //   OpDot
+  // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3354):
+  // Right now we only support certain operations. When this issue is addressed
+  // the supporting comments can be removed.
+  // To be supported in the future:
+  //   OpTranspose
+  //   OpMatrixTimesScalar
+  //   OpVectorTimesMatrix
+  //   OpMatrixTimesVector
+  //   OpMatrixTimesMatrix
+  //   OpOuterProduct
+  InstructionDescriptor instruction_descriptor = 2;
+
+}
+
 message TransformationSetFunctionControl {
 
   // A transformation that sets the function control operand of an OpFunction

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

@@ -56,6 +56,7 @@
 #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_id_with_synonym.h"
+#include "source/fuzz/transformation_replace_linear_algebra_instruction.h"
 #include "source/fuzz/transformation_set_function_control.h"
 #include "source/fuzz/transformation_set_loop_control.h"
 #include "source/fuzz/transformation_set_memory_operands_mask.h"
@@ -182,6 +183,10 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
     case protobufs::Transformation::TransformationCase::kReplaceIdWithSynonym:
       return MakeUnique<TransformationReplaceIdWithSynonym>(
           message.replace_id_with_synonym());
+    case protobufs::Transformation::TransformationCase::
+        kReplaceLinearAlgebraInstruction:
+      return MakeUnique<TransformationReplaceLinearAlgebraInstruction>(
+          message.replace_linear_algebra_instruction());
     case protobufs::Transformation::TransformationCase::kSetFunctionControl:
       return MakeUnique<TransformationSetFunctionControl>(
           message.set_function_control());

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

@@ -0,0 +1,275 @@
+// 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_replace_linear_algebra_instruction.h"
+
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/instruction_descriptor.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationReplaceLinearAlgebraInstruction::
+    TransformationReplaceLinearAlgebraInstruction(
+        const spvtools::fuzz::protobufs::
+            TransformationReplaceLinearAlgebraInstruction& message)
+    : message_(message) {}
+
+TransformationReplaceLinearAlgebraInstruction::
+    TransformationReplaceLinearAlgebraInstruction(
+        const std::vector<uint32_t>& fresh_ids,
+        const protobufs::InstructionDescriptor& instruction_descriptor) {
+  for (auto fresh_id : fresh_ids) {
+    message_.add_fresh_ids(fresh_id);
+  }
+  *message_.mutable_instruction_descriptor() = instruction_descriptor;
+}
+
+bool TransformationReplaceLinearAlgebraInstruction::IsApplicable(
+    opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
+  auto instruction =
+      FindInstruction(message_.instruction_descriptor(), ir_context);
+
+  // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3354):
+  // Right now we only support certain operations. When this issue is addressed
+  // the following conditional can use the function |spvOpcodeIsLinearAlgebra|.
+  // It must be a supported linear algebra instruction.
+  if (instruction->opcode() != SpvOpVectorTimesScalar &&
+      instruction->opcode() != SpvOpDot) {
+    return false;
+  }
+
+  // |message_.fresh_ids.size| must be the exact number of fresh ids needed to
+  // apply the transformation.
+  if (static_cast<uint32_t>(message_.fresh_ids().size()) !=
+      GetRequiredFreshIdCount(ir_context, instruction)) {
+    return false;
+  }
+
+  // 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))) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+void TransformationReplaceLinearAlgebraInstruction::Apply(
+    opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
+  auto linear_algebra_instruction =
+      FindInstruction(message_.instruction_descriptor(), ir_context);
+
+  switch (linear_algebra_instruction->opcode()) {
+    case SpvOpVectorTimesScalar:
+      ReplaceOpVectorTimesScalar(ir_context, linear_algebra_instruction);
+      break;
+    case SpvOpDot:
+      ReplaceOpDot(ir_context, linear_algebra_instruction);
+      break;
+    default:
+      assert(false && "Should be unreachable.");
+      break;
+  }
+
+  ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
+}
+
+protobufs::Transformation
+TransformationReplaceLinearAlgebraInstruction::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_replace_linear_algebra_instruction() = message_;
+  return result;
+}
+
+uint32_t TransformationReplaceLinearAlgebraInstruction::GetRequiredFreshIdCount(
+    opt::IRContext* ir_context, opt::Instruction* instruction) {
+  // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3354):
+  // Right now we only support certain operations.
+  switch (instruction->opcode()) {
+    case SpvOpVectorTimesScalar:
+      // For each vector component, 1 OpCompositeExtract and 1 OpFMul will be
+      // inserted.
+      return 2 *
+             ir_context->get_type_mgr()
+                 ->GetType(ir_context->get_def_use_mgr()
+                               ->GetDef(instruction->GetSingleWordInOperand(0))
+                               ->type_id())
+                 ->AsVector()
+                 ->element_count();
+    case SpvOpDot: {
+      // For each pair of vector components, 2 OpCompositeExtract and 1 OpFMul
+      // will be inserted. The first two OpFMul instructions will result the
+      // first OpFAdd instruction to be inserted. For each remaining OpFMul, 1
+      // OpFAdd will be inserted. The last OpFAdd instruction is got by changing
+      // the OpDot instruction.
+      return 4 * ir_context->get_type_mgr()
+                     ->GetType(
+                         ir_context->get_def_use_mgr()
+                             ->GetDef(instruction->GetSingleWordInOperand(0))
+                             ->type_id())
+                     ->AsVector()
+                     ->element_count() -
+             2;
+    }
+    default:
+      assert(false && "Unsupported linear algebra instruction.");
+      return 0;
+  }
+}
+
+void TransformationReplaceLinearAlgebraInstruction::ReplaceOpVectorTimesScalar(
+    opt::IRContext* ir_context,
+    opt::Instruction* linear_algebra_instruction) const {
+  // Gets OpVectorTimesScalar in operands.
+  auto vector = ir_context->get_def_use_mgr()->GetDef(
+      linear_algebra_instruction->GetSingleWordInOperand(0));
+  auto scalar = ir_context->get_def_use_mgr()->GetDef(
+      linear_algebra_instruction->GetSingleWordInOperand(1));
+
+  uint32_t vector_component_count = ir_context->get_type_mgr()
+                                        ->GetType(vector->type_id())
+                                        ->AsVector()
+                                        ->element_count();
+  std::vector<uint32_t> float_multiplication_ids(vector_component_count);
+  uint32_t fresh_id_index = 0;
+
+  for (uint32_t i = 0; i < vector_component_count; i++) {
+    // Extracts |vector| component.
+    uint32_t vector_extract_id = message_.fresh_ids(fresh_id_index++);
+    fuzzerutil::UpdateModuleIdBound(ir_context, vector_extract_id);
+    linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+        ir_context, SpvOpCompositeExtract, scalar->type_id(), vector_extract_id,
+        opt::Instruction::OperandList(
+            {{SPV_OPERAND_TYPE_ID, {vector->result_id()}},
+             {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
+
+    // Multiplies the |vector| component with the |scalar|.
+    uint32_t float_multiplication_id = message_.fresh_ids(fresh_id_index++);
+    float_multiplication_ids[i] = float_multiplication_id;
+    fuzzerutil::UpdateModuleIdBound(ir_context, float_multiplication_id);
+    linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+        ir_context, SpvOpFMul, scalar->type_id(), float_multiplication_id,
+        opt::Instruction::OperandList(
+            {{SPV_OPERAND_TYPE_ID, {vector_extract_id}},
+             {SPV_OPERAND_TYPE_ID, {scalar->result_id()}}})));
+  }
+
+  // The OpVectorTimesScalar instruction is changed to an OpCompositeConstruct
+  // instruction.
+  linear_algebra_instruction->SetOpcode(SpvOpCompositeConstruct);
+  linear_algebra_instruction->SetInOperand(0, {float_multiplication_ids[0]});
+  linear_algebra_instruction->SetInOperand(1, {float_multiplication_ids[1]});
+  for (uint32_t i = 2; i < float_multiplication_ids.size(); i++) {
+    linear_algebra_instruction->AddOperand(
+        {SPV_OPERAND_TYPE_ID, {float_multiplication_ids[i]}});
+  }
+}
+
+void TransformationReplaceLinearAlgebraInstruction::ReplaceOpDot(
+    opt::IRContext* ir_context,
+    opt::Instruction* linear_algebra_instruction) const {
+  // Gets OpDot in operands.
+  auto vector_1 = ir_context->get_def_use_mgr()->GetDef(
+      linear_algebra_instruction->GetSingleWordInOperand(0));
+  auto vector_2 = ir_context->get_def_use_mgr()->GetDef(
+      linear_algebra_instruction->GetSingleWordInOperand(1));
+
+  uint32_t vectors_component_count = ir_context->get_type_mgr()
+                                         ->GetType(vector_1->type_id())
+                                         ->AsVector()
+                                         ->element_count();
+  std::vector<uint32_t> float_multiplication_ids(vectors_component_count);
+  uint32_t fresh_id_index = 0;
+
+  for (uint32_t i = 0; i < vectors_component_count; i++) {
+    // Extracts |vector_1| component.
+    uint32_t vector_1_extract_id = message_.fresh_ids(fresh_id_index++);
+    fuzzerutil::UpdateModuleIdBound(ir_context, vector_1_extract_id);
+    linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+        ir_context, SpvOpCompositeExtract,
+        linear_algebra_instruction->type_id(), vector_1_extract_id,
+        opt::Instruction::OperandList(
+            {{SPV_OPERAND_TYPE_ID, {vector_1->result_id()}},
+             {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
+
+    // Extracts |vector_2| component.
+    uint32_t vector_2_extract_id = message_.fresh_ids(fresh_id_index++);
+    fuzzerutil::UpdateModuleIdBound(ir_context, vector_2_extract_id);
+    linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+        ir_context, SpvOpCompositeExtract,
+        linear_algebra_instruction->type_id(), vector_2_extract_id,
+        opt::Instruction::OperandList(
+            {{SPV_OPERAND_TYPE_ID, {vector_2->result_id()}},
+             {SPV_OPERAND_TYPE_LITERAL_INTEGER, {i}}})));
+
+    // Multiplies the pair of components.
+    float_multiplication_ids[i] = message_.fresh_ids(fresh_id_index++);
+    fuzzerutil::UpdateModuleIdBound(ir_context, float_multiplication_ids[i]);
+    linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+        ir_context, SpvOpFMul, linear_algebra_instruction->type_id(),
+        float_multiplication_ids[i],
+        opt::Instruction::OperandList(
+            {{SPV_OPERAND_TYPE_ID, {vector_1_extract_id}},
+             {SPV_OPERAND_TYPE_ID, {vector_2_extract_id}}})));
+  }
+
+  // If the vector has 2 components, then there will be 2 float multiplication
+  // instructions.
+  if (vectors_component_count == 2) {
+    linear_algebra_instruction->SetOpcode(SpvOpFAdd);
+    linear_algebra_instruction->SetInOperand(0, {float_multiplication_ids[0]});
+    linear_algebra_instruction->SetInOperand(1, {float_multiplication_ids[1]});
+  } else {
+    // The first OpFAdd instruction has as operands the first two OpFMul
+    // instructions.
+    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);
+    fuzzerutil::UpdateModuleIdBound(ir_context, float_add_id);
+    linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+        ir_context, SpvOpFAdd, linear_algebra_instruction->type_id(),
+        float_add_id,
+        opt::Instruction::OperandList(
+            {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[0]}},
+             {SPV_OPERAND_TYPE_ID, {float_multiplication_ids[1]}}})));
+
+    // The remaining OpFAdd instructions has as operands an OpFMul and an OpFAdd
+    // instruction.
+    for (uint32_t i = 2; i < float_multiplication_ids.size() - 1; i++) {
+      float_add_id = message_.fresh_ids(fresh_id_index++);
+      fuzzerutil::UpdateModuleIdBound(ir_context, float_add_id);
+      float_add_ids.push_back(float_add_id);
+      linear_algebra_instruction->InsertBefore(MakeUnique<opt::Instruction>(
+          ir_context, SpvOpFAdd, linear_algebra_instruction->type_id(),
+          float_add_id,
+          opt::Instruction::OperandList(
+              {{SPV_OPERAND_TYPE_ID, {float_multiplication_ids[i]}},
+               {SPV_OPERAND_TYPE_ID, {float_add_ids[i - 2]}}})));
+    }
+
+    // The last OpFAdd instruction is got by changing some of the OpDot
+    // instruction attributes.
+    linear_algebra_instruction->SetOpcode(SpvOpFAdd);
+    linear_algebra_instruction->SetInOperand(
+        0, {float_multiplication_ids[float_multiplication_ids.size() - 1]});
+    linear_algebra_instruction->SetInOperand(
+        1, {float_add_ids[float_add_ids.size() - 1]});
+  }
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

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

@@ -0,0 +1,67 @@
+// 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_REPLACE_LINEAR_ALGEBRA_INSTRUCTION_H_
+#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_LINEAR_ALGEBRA_INSTRUCTION_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 TransformationReplaceLinearAlgebraInstruction : public Transformation {
+ public:
+  explicit TransformationReplaceLinearAlgebraInstruction(
+      const protobufs::TransformationReplaceLinearAlgebraInstruction& message);
+
+  TransformationReplaceLinearAlgebraInstruction(
+      const std::vector<uint32_t>& fresh_ids,
+      const protobufs::InstructionDescriptor& instruction_descriptor);
+
+  // - |message_.fresh_ids| must be fresh ids needed to apply the
+  // transformation.
+  // - |message_.instruction_descriptor| must be a linear algebra instruction
+  bool IsApplicable(
+      opt::IRContext* ir_context,
+      const TransformationContext& transformation_context) const override;
+
+  // Replaces a linear algebra instruction.
+  void Apply(opt::IRContext* ir_context,
+             TransformationContext* transformation_context) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+  // Returns the number of ids needed to apply the transformation.
+  static uint32_t GetRequiredFreshIdCount(opt::IRContext* ir_context,
+                                          opt::Instruction* instruction);
+
+ private:
+  protobufs::TransformationReplaceLinearAlgebraInstruction message_;
+
+  // Replaces an OpVectorTimesScalar instruction.
+  void ReplaceOpVectorTimesScalar(opt::IRContext* ir_context,
+                                  opt::Instruction* instruction) const;
+
+  // Replaces an OpDot instruction.
+  void ReplaceOpDot(opt::IRContext* ir_context,
+                    opt::Instruction* instruction) const;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_TRANSFORMATION_REPLACE_LINEAR_ALGEBRA_INSTRUCTION_H_

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

@@ -650,6 +650,22 @@ bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode) {
   }
 }
 
+bool spvOpcodeIsLinearAlgebra(SpvOp opcode) {
+  switch (opcode) {
+    case SpvOpTranspose:
+    case SpvOpVectorTimesScalar:
+    case SpvOpMatrixTimesScalar:
+    case SpvOpVectorTimesMatrix:
+    case SpvOpMatrixTimesVector:
+    case SpvOpMatrixTimesMatrix:
+    case SpvOpOuterProduct:
+    case SpvOpDot:
+      return true;
+    default:
+      return false;
+  }
+}
+
 std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) {
   switch (opcode) {
     case SpvOpMemoryBarrier:

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

@@ -134,6 +134,9 @@ bool spvOpcodeIsDebug(SpvOp opcode);
 // where the order of the operands is irrelevant.
 bool spvOpcodeIsCommutativeBinaryOperator(SpvOp opcode);
 
+// Returns true for opcodes that represents linear algebra instructions.
+bool spvOpcodeIsLinearAlgebra(SpvOp opcode);
+
 // Returns a vector containing the indices of the memory semantics <id>
 // operands for |opcode|.
 std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode);

+ 1 - 1
3rdparty/spirv-tools/source/operand.cpp

@@ -455,7 +455,7 @@ bool spvIsInIdType(spv_operand_type_t type) {
     return false;
   }
   switch (type) {
-    // Blacklist non-input IDs.
+    // Deny non-input IDs.
     case SPV_OPERAND_TYPE_TYPE_ID:
     case SPV_OPERAND_TYPE_RESULT_ID:
       return false;

+ 5 - 5
3rdparty/spirv-tools/source/opt/aggressive_dead_code_elim_pass.cpp

@@ -131,11 +131,11 @@ void AggressiveDCEPass::AddStores(uint32_t ptrId) {
 }
 
 bool AggressiveDCEPass::AllExtensionsSupported() const {
-  // If any extension not in whitelist, return false
+  // If any extension not in allowlist, return false
   for (auto& ei : get_module()->extensions()) {
     const char* extName =
         reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
-    if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
+    if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
       return false;
   }
   return true;
@@ -882,14 +882,14 @@ bool AggressiveDCEPass::ProcessGlobalValues() {
 AggressiveDCEPass::AggressiveDCEPass() = default;
 
 Pass::Status AggressiveDCEPass::Process() {
-  // Initialize extensions whitelist
+  // Initialize extensions allowlist
   InitExtensions();
   return ProcessImpl();
 }
 
 void AggressiveDCEPass::InitExtensions() {
-  extensions_whitelist_.clear();
-  extensions_whitelist_.insert({
+  extensions_allowlist_.clear();
+  extensions_allowlist_.insert({
       "SPV_AMD_shader_explicit_vertex_parameter",
       "SPV_AMD_shader_trinary_minmax",
       "SPV_AMD_gcn_shader",

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

@@ -87,7 +87,7 @@ class AggressiveDCEPass : public MemPass {
   // to the live instruction worklist.
   void AddStores(uint32_t ptrId);
 
-  // Initialize extensions whitelist
+  // Initialize extensions allowlist
   void InitExtensions();
 
   // Return true if all extensions in this module are supported by this pass.
@@ -191,7 +191,7 @@ class AggressiveDCEPass : public MemPass {
   std::vector<Instruction*> to_kill_;
 
   // Extensions supported by this pass.
-  std::unordered_set<std::string> extensions_whitelist_;
+  std::unordered_set<std::string> extensions_allowlist_;
 };
 
 }  // namespace opt

+ 1 - 0
3rdparty/spirv-tools/source/opt/dead_branch_elim_pass.cpp

@@ -41,6 +41,7 @@ bool DeadBranchElimPass::GetConstCondition(uint32_t condId, bool* condVal) {
   bool condIsConst;
   Instruction* cInst = get_def_use_mgr()->GetDef(condId);
   switch (cInst->opcode()) {
+    case SpvOpConstantNull:
     case SpvOpConstantFalse: {
       *condVal = false;
       condIsConst = true;

+ 12 - 0
3rdparty/spirv-tools/source/opt/function.h

@@ -72,6 +72,10 @@ class Function {
   // Delete all basic blocks that contain no instructions.
   inline void RemoveEmptyBlocks();
 
+  // Removes a parameter from the function with result id equal to |id|.
+  // Does nothing if the function doesn't have such a parameter.
+  inline void RemoveParameter(uint32_t id);
+
   // Saves the given function end instruction.
   inline void SetFunctionEnd(std::unique_ptr<Instruction> end_inst);
 
@@ -219,6 +223,14 @@ inline void Function::RemoveEmptyBlocks() {
   blocks_.erase(first_empty, std::end(blocks_));
 }
 
+inline void Function::RemoveParameter(uint32_t id) {
+  params_.erase(std::remove_if(params_.begin(), params_.end(),
+                               [id](const std::unique_ptr<Instruction>& param) {
+                                 return param->result_id() == id;
+                               }),
+                params_.end());
+}
+
 inline void Function::SetFunctionEnd(std::unique_ptr<Instruction> end_inst) {
   end_inst_ = std::move(end_inst);
 }

+ 10 - 0
3rdparty/spirv-tools/source/opt/instruction_list.h

@@ -61,6 +61,16 @@ class InstructionList : public utils::IntrusiveList<Instruction> {
         : utils::IntrusiveList<Instruction>::iterator(i) {}
     iterator(Instruction* i) : utils::IntrusiveList<Instruction>::iterator(i) {}
 
+    iterator& operator++() {
+      utils::IntrusiveList<Instruction>::iterator::operator++();
+      return *this;
+    }
+
+    iterator& operator--() {
+      utils::IntrusiveList<Instruction>::iterator::operator--();
+      return *this;
+    }
+
     // DEPRECATED: Please use MoveBefore with an InstructionList instead.
     //
     // Moves the nodes in |list| to the list that |this| points to.  The

+ 5 - 5
3rdparty/spirv-tools/source/opt/local_access_chain_convert_pass.cpp

@@ -281,7 +281,7 @@ void LocalAccessChainConvertPass::Initialize() {
   // Initialize collections
   supported_ref_ptrs_.clear();
 
-  // Initialize extension whitelist
+  // Initialize extension allowlist
   InitExtensions();
 }
 
@@ -292,11 +292,11 @@ bool LocalAccessChainConvertPass::AllExtensionsSupported() const {
   if (context()->get_feature_mgr()->HasCapability(
           SpvCapabilityVariablePointers))
     return false;
-  // If any extension not in whitelist, return false
+  // If any extension not in allowlist, return false
   for (auto& ei : get_module()->extensions()) {
     const char* extName =
         reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
-    if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
+    if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
       return false;
   }
   return true;
@@ -336,8 +336,8 @@ Pass::Status LocalAccessChainConvertPass::Process() {
 }
 
 void LocalAccessChainConvertPass::InitExtensions() {
-  extensions_whitelist_.clear();
-  extensions_whitelist_.insert({
+  extensions_allowlist_.clear();
+  extensions_allowlist_.insert({
       "SPV_AMD_shader_explicit_vertex_parameter",
       "SPV_AMD_shader_trinary_minmax",
       "SPV_AMD_gcn_shader",

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

@@ -110,7 +110,7 @@ class LocalAccessChainConvertPass : public MemPass {
   // Returns a status to indicate success or failure, and change or no change.
   Status ConvertLocalAccessChains(Function* func);
 
-  // Initialize extensions whitelist
+  // Initialize extensions allowlist
   void InitExtensions();
 
   // Return true if all extensions in this module are allowed by this pass.
@@ -124,7 +124,7 @@ class LocalAccessChainConvertPass : public MemPass {
   std::unordered_set<uint32_t> supported_ref_ptrs_;
 
   // Extensions supported by this pass.
-  std::unordered_set<std::string> extensions_whitelist_;
+  std::unordered_set<std::string> extensions_allowlist_;
 };
 
 }  // namespace opt

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

@@ -168,16 +168,16 @@ void LocalSingleBlockLoadStoreElimPass::Initialize() {
   // Clear collections
   supported_ref_ptrs_.clear();
 
-  // Initialize extensions whitelist
+  // Initialize extensions allowlist
   InitExtensions();
 }
 
 bool LocalSingleBlockLoadStoreElimPass::AllExtensionsSupported() const {
-  // If any extension not in whitelist, return false
+  // If any extension not in allowlist, return false
   for (auto& ei : get_module()->extensions()) {
     const char* extName =
         reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
-    if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
+    if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
       return false;
   }
   return true;
@@ -214,8 +214,8 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::Process() {
 }
 
 void LocalSingleBlockLoadStoreElimPass::InitExtensions() {
-  extensions_whitelist_.clear();
-  extensions_whitelist_.insert({
+  extensions_allowlist_.clear();
+  extensions_allowlist_.insert({
       "SPV_AMD_shader_explicit_vertex_parameter",
       "SPV_AMD_shader_trinary_minmax",
       "SPV_AMD_gcn_shader",

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

@@ -63,7 +63,7 @@ class LocalSingleBlockLoadStoreElimPass : public MemPass {
   // where possible. Assumes logical addressing.
   bool LocalSingleBlockLoadStoreElim(Function* func);
 
-  // Initialize extensions whitelist
+  // Initialize extensions allowlist
   void InitExtensions();
 
   // Return true if all extensions in this module are supported by this pass.
@@ -94,7 +94,7 @@ class LocalSingleBlockLoadStoreElimPass : public MemPass {
   std::unordered_set<uint32_t> pinned_vars_;
 
   // Extensions supported by this pass.
-  std::unordered_set<std::string> extensions_whitelist_;
+  std::unordered_set<std::string> extensions_allowlist_;
 
   // Variables that are only referenced by supported operations for this
   // pass ie. loads and stores.

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

@@ -46,11 +46,11 @@ bool LocalSingleStoreElimPass::LocalSingleStoreElim(Function* func) {
 }
 
 bool LocalSingleStoreElimPass::AllExtensionsSupported() const {
-  // If any extension not in whitelist, return false
+  // If any extension not in allowlist, return false
   for (auto& ei : get_module()->extensions()) {
     const char* extName =
         reinterpret_cast<const char*>(&ei.GetInOperand(0).words[0]);
-    if (extensions_whitelist_.find(extName) == extensions_whitelist_.end())
+    if (extensions_allowlist_.find(extName) == extensions_allowlist_.end())
       return false;
   }
   return true;
@@ -74,12 +74,12 @@ Pass::Status LocalSingleStoreElimPass::ProcessImpl() {
 LocalSingleStoreElimPass::LocalSingleStoreElimPass() = default;
 
 Pass::Status LocalSingleStoreElimPass::Process() {
-  InitExtensionWhiteList();
+  InitExtensionAllowList();
   return ProcessImpl();
 }
 
-void LocalSingleStoreElimPass::InitExtensionWhiteList() {
-  extensions_whitelist_.insert({
+void LocalSingleStoreElimPass::InitExtensionAllowList() {
+  extensions_allowlist_.insert({
       "SPV_AMD_shader_explicit_vertex_parameter",
       "SPV_AMD_shader_trinary_minmax",
       "SPV_AMD_gcn_shader",

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

@@ -57,8 +57,8 @@ class LocalSingleStoreElimPass : public Pass {
   // any resulting dead code.
   bool LocalSingleStoreElim(Function* func);
 
-  // Initialize extensions whitelist
-  void InitExtensionWhiteList();
+  // Initialize extensions allowlist
+  void InitExtensionAllowList();
 
   // Return true if all extensions in this module are allowed by this pass.
   bool AllExtensionsSupported() const;
@@ -94,7 +94,7 @@ class LocalSingleStoreElimPass : public Pass {
                     const std::vector<Instruction*>& uses);
 
   // Extensions supported by this pass.
-  std::unordered_set<std::string> extensions_whitelist_;
+  std::unordered_set<std::string> extensions_allowlist_;
 };
 
 }  // namespace opt

+ 21 - 4
3rdparty/spirv-tools/source/opt/loop_descriptor.cpp

@@ -485,10 +485,27 @@ void Loop::ComputeLoopStructuredOrder(
 
   if (include_pre_header && GetPreHeaderBlock())
     ordered_loop_blocks->push_back(loop_preheader_);
-  cfg.ForEachBlockInReversePostOrder(
-      loop_header_, [ordered_loop_blocks, this](BasicBlock* bb) {
-        if (IsInsideLoop(bb)) ordered_loop_blocks->push_back(bb);
-      });
+
+  bool is_shader =
+      context_->get_feature_mgr()->HasCapability(SpvCapabilityShader);
+  if (!is_shader) {
+    cfg.ForEachBlockInReversePostOrder(
+        loop_header_, [ordered_loop_blocks, this](BasicBlock* bb) {
+          if (IsInsideLoop(bb)) ordered_loop_blocks->push_back(bb);
+        });
+  } else {
+    // If this is a shader, it is possible that there are unreachable merge and
+    // continue blocks that must be copied to retain the structured order.
+    // The structured order will include these.
+    std::list<BasicBlock*> order;
+    cfg.ComputeStructuredOrder(loop_header_->GetParent(), loop_header_, &order);
+    for (BasicBlock* bb : order) {
+      if (bb == GetMergeBlock()) {
+        break;
+      }
+      ordered_loop_blocks->push_back(bb);
+    }
+  }
   if (include_merge && GetMergeBlock())
     ordered_loop_blocks->push_back(loop_merge_);
 }

+ 3 - 3
3rdparty/spirv-tools/utils/check_symbol_exports.py

@@ -55,11 +55,11 @@ def check_library(library):
     #   _Z[0-9]+spv[A-Z_] :  C++ symbol starting with spv[A-Z_]
     symbol_ok_pattern = re.compile(r'^(spv[A-Z]|_ZN|_Z[0-9]+spv[A-Z_])')
 
-    # In addition, the following pattern whitelists global functions that are added
+    # In addition, the following pattern allowlists global functions that are added
     # by the protobuf compiler:
     #   - AddDescriptors_spvtoolsfuzz_2eproto()
     #   - InitDefaults_spvtoolsfuzz_2eproto()
-    symbol_whitelist_pattern = re.compile(r'_Z[0-9]+(InitDefaults|AddDescriptors)_spvtoolsfuzz_2eprotov')
+    symbol_allowlist_pattern = re.compile(r'_Z[0-9]+(InitDefaults|AddDescriptors)_spvtoolsfuzz_2eprotov')
 
     seen = set()
     result = 0
@@ -70,7 +70,7 @@ def check_library(library):
             if symbol not in seen:
                 seen.add(symbol)
                 #print("look at '{}'".format(symbol))
-                if not (symbol_whitelist_pattern.match(symbol) or symbol_ok_pattern.match(symbol)):
+                if not (symbol_allowlist_pattern.match(symbol) or symbol_ok_pattern.match(symbol)):
                     print('{}: error: Unescaped exported symbol: {}'.format(PROG, symbol))
                     result = 1
     return result