Бранимир Караџић 5 лет назад
Родитель
Сommit
add2440710

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

@@ -1 +1 @@
-"v2020.4-dev", "SPIRV-Tools v2020.4-dev 3e4a8382b6d054cbd8f0a04a4f83c4350dd803ea"
+"v2020.4-dev", "SPIRV-Tools v2020.4-dev 2cdcab3215d654e18c3b6d5f12bd94e7e64fb8b1"

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

@@ -90,6 +90,7 @@ if(SPIRV_BUILD_FUZZER)
         transformation_add_global_variable.h
         transformation_add_global_variable.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_spec_constant_op.h
         transformation_add_type_array.h
         transformation_add_type_array.h
         transformation_add_type_boolean.h
         transformation_add_type_boolean.h
         transformation_add_type_float.h
         transformation_add_type_float.h
@@ -187,6 +188,7 @@ if(SPIRV_BUILD_FUZZER)
         transformation_add_global_variable.cpp
         transformation_add_global_variable.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_spec_constant_op.cpp
         transformation_add_type_array.cpp
         transformation_add_type_array.cpp
         transformation_add_type_boolean.cpp
         transformation_add_type_boolean.cpp
         transformation_add_type_float.cpp
         transformation_add_type_float.cpp

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

@@ -813,8 +813,10 @@ void FactManager::DataSynonymAndIdEquationFacts::ComputeClosureOfFacts(
   struct DataDescriptorPairEquals {
   struct DataDescriptorPairEquals {
     bool operator()(const DataDescriptorPair& first,
     bool operator()(const DataDescriptorPair& first,
                     const DataDescriptorPair& second) const {
                     const DataDescriptorPair& second) const {
-      return DataDescriptorEquals()(&first.first, &second.first) &&
-             DataDescriptorEquals()(&first.second, &second.second);
+      return (DataDescriptorEquals()(&first.first, &second.first) &&
+              DataDescriptorEquals()(&first.second, &second.second)) ||
+             (DataDescriptorEquals()(&first.first, &second.second) &&
+              DataDescriptorEquals()(&first.second, &second.first));
     }
     }
   };
   };
 
 

+ 1 - 1
3rdparty/spirv-tools/source/fuzz/fuzzer_pass_adjust_memory_operands_masks.cpp

@@ -75,7 +75,7 @@ void FuzzerPassAdjustMemoryOperandsMasks::Apply() {
                   *inst_it, mask_index);
                   *inst_it, mask_index);
           auto existing_mask =
           auto existing_mask =
               existing_mask_in_operand_index < inst_it->NumInOperands()
               existing_mask_in_operand_index < inst_it->NumInOperands()
-                  ? inst_it->GetSingleWordOperand(
+                  ? inst_it->GetSingleWordInOperand(
                         existing_mask_in_operand_index)
                         existing_mask_in_operand_index)
                   : static_cast<uint32_t>(SpvMemoryAccessMaskNone);
                   : static_cast<uint32_t>(SpvMemoryAccessMaskNone);
 
 

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

@@ -27,6 +27,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_spec_constant_op.h"
 #include "source/fuzz/transformation_add_type_array.h"
 #include "source/fuzz/transformation_add_type_array.h"
 #include "source/fuzz/transformation_add_type_boolean.h"
 #include "source/fuzz/transformation_add_type_boolean.h"
 #include "source/fuzz/transformation_add_type_float.h"
 #include "source/fuzz/transformation_add_type_float.h"
@@ -413,14 +414,41 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
             argument_type_ids));
             argument_type_ids));
       }
       }
     } break;
     } break;
+    case SpvOpSpecConstantOp: {
+      new_result_id = GetFuzzerContext()->GetFreshId();
+      auto type_id = original_id_to_donated_id->at(type_or_value.type_id());
+      auto opcode = static_cast<SpvOp>(type_or_value.GetSingleWordInOperand(0));
+
+      // Make sure we take into account |original_id_to_donated_id| when
+      // computing operands for OpSpecConstantOp.
+      opt::Instruction::OperandList operands;
+      for (uint32_t i = 1; i < type_or_value.NumInOperands(); ++i) {
+        const auto& operand = type_or_value.GetInOperand(i);
+        auto data =
+            operand.type == SPV_OPERAND_TYPE_ID
+                ? opt::Operand::OperandData{original_id_to_donated_id->at(
+                      operand.words[0])}
+                : operand.words;
+
+        operands.push_back({operand.type, std::move(data)});
+      }
+
+      ApplyTransformation(TransformationAddSpecConstantOp(
+          new_result_id, type_id, opcode, std::move(operands)));
+    } break;
+    case SpvOpSpecConstantTrue:
+    case SpvOpSpecConstantFalse:
     case SpvOpConstantTrue:
     case SpvOpConstantTrue:
     case SpvOpConstantFalse: {
     case SpvOpConstantFalse: {
       // It is OK to have duplicate definitions of True and False, so add
       // It is OK to have duplicate definitions of True and False, so add
       // these to the module, using a remapped Bool type.
       // these to the module, using a remapped Bool type.
       new_result_id = GetFuzzerContext()->GetFreshId();
       new_result_id = GetFuzzerContext()->GetFreshId();
-      ApplyTransformation(TransformationAddConstantBoolean(
-          new_result_id, type_or_value.opcode() == SpvOpConstantTrue));
+      auto value = type_or_value.opcode() == SpvOpConstantTrue ||
+                   type_or_value.opcode() == SpvOpSpecConstantTrue;
+      ApplyTransformation(
+          TransformationAddConstantBoolean(new_result_id, value));
     } break;
     } break;
+    case SpvOpSpecConstant:
     case SpvOpConstant: {
     case SpvOpConstant: {
       // It is OK to have duplicate constant definitions, so add this to the
       // It is OK to have duplicate constant definitions, so add this to the
       // module using a remapped result type.
       // module using a remapped result type.
@@ -433,6 +461,7 @@ void FuzzerPassDonateModules::HandleTypeOrValue(
           new_result_id, original_id_to_donated_id->at(type_or_value.type_id()),
           new_result_id, original_id_to_donated_id->at(type_or_value.type_id()),
           data_words));
           data_words));
     } break;
     } break;
+    case SpvOpSpecConstantComposite:
     case SpvOpConstantComposite: {
     case SpvOpConstantComposite: {
       assert(original_id_to_donated_id->count(type_or_value.type_id()) &&
       assert(original_id_to_donated_id->count(type_or_value.type_id()) &&
              "Composite types for which it is possible to create a constant "
              "Composite types for which it is possible to create a constant "

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

@@ -80,12 +80,21 @@ void FuzzerPassPushIdsThroughVariables::Apply() {
         std::vector<opt::Instruction*> value_instructions =
         std::vector<opt::Instruction*> value_instructions =
             FindAvailableInstructions(
             FindAvailableInstructions(
                 function, block, instruction_iterator,
                 function, block, instruction_iterator,
-                [basic_type_id](opt::IRContext* /*unused*/,
-                                opt::Instruction* instruction) -> bool {
+                [basic_type_id, instruction_descriptor](
+                    opt::IRContext* ir_context,
+                    opt::Instruction* instruction) -> bool {
                   if (!instruction->result_id() || !instruction->type_id()) {
                   if (!instruction->result_id() || !instruction->type_id()) {
                     return false;
                     return false;
                   }
                   }
-                  return instruction->type_id() == basic_type_id;
+
+                  if (instruction->type_id() != basic_type_id) {
+                    return false;
+                  }
+
+                  return fuzzerutil::IdIsAvailableBeforeInstruction(
+                      ir_context,
+                      FindInstruction(instruction_descriptor, ir_context),
+                      instruction->result_id());
                 });
                 });
 
 
         if (value_instructions.empty()) {
         if (value_instructions.empty()) {

+ 33 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp

@@ -550,6 +550,39 @@ bool IsNullConstantSupported(const opt::analysis::Type& type) {
          type.AsDeviceEvent() || type.AsReserveId() || type.AsQueue();
          type.AsDeviceEvent() || type.AsReserveId() || type.AsQueue();
 }
 }
 
 
+bool GlobalVariablesMustBeDeclaredInEntryPointInterfaces(
+    const opt::IRContext* ir_context) {
+  // TODO(afd): We capture the universal environments for which this requirement
+  //  holds.  The check should be refined on demand for other target
+  //  environments.
+  switch (ir_context->grammar().target_env()) {
+    case SPV_ENV_UNIVERSAL_1_0:
+    case SPV_ENV_UNIVERSAL_1_1:
+    case SPV_ENV_UNIVERSAL_1_2:
+    case SPV_ENV_UNIVERSAL_1_3:
+      return false;
+    default:
+      return true;
+  }
+}
+
+void AddVariableIdToEntryPointInterfaces(opt::IRContext* context, uint32_t id) {
+  if (GlobalVariablesMustBeDeclaredInEntryPointInterfaces(context)) {
+    // Conservatively add this global to the interface of every entry point in
+    // the module.  This means that the global is available for other
+    // transformations to use.
+    //
+    // A downside of this is that the global will be in the interface even if it
+    // ends up never being used.
+    //
+    // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3111) revisit
+    //  this if a more thorough approach to entry point interfaces is taken.
+    for (auto& entry_point : context->module()->entry_points()) {
+      entry_point.AddOperand({SPV_OPERAND_TYPE_ID, {id}});
+    }
+  }
+}
+
 }  // namespace fuzzerutil
 }  // namespace fuzzerutil
 
 
 }  // namespace fuzz
 }  // namespace fuzz

+ 11 - 0
3rdparty/spirv-tools/source/fuzz/fuzzer_util.h

@@ -215,6 +215,17 @@ uint32_t MaybeGetPointerType(opt::IRContext* context, uint32_t pointee_type_id,
 // to have an OpConstantNull value.
 // to have an OpConstantNull value.
 bool IsNullConstantSupported(const opt::analysis::Type& type);
 bool IsNullConstantSupported(const opt::analysis::Type& type);
 
 
+// Returns true if and only if the SPIR-V version being used requires that
+// global variables accessed in the static call graph of an entry point need
+// to be listed in that entry point's interface.
+bool GlobalVariablesMustBeDeclaredInEntryPointInterfaces(
+    const opt::IRContext* context);
+
+// Adds |id| into the interface of every entry point of the shader.
+// Does nothing if SPIR-V doesn't require global variables, that are accessed
+// from an entry point function, to be listed in that function's interface.
+void AddVariableIdToEntryPointInterfaces(opt::IRContext* context, uint32_t id);
+
 }  // namespace fuzzerutil
 }  // namespace fuzzerutil
 
 
 }  // namespace fuzz
 }  // namespace fuzz

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

@@ -376,6 +376,7 @@ message Transformation {
     TransformationComputeDataSynonymFactClosure compute_data_synonym_fact_closure = 45;
     TransformationComputeDataSynonymFactClosure compute_data_synonym_fact_closure = 45;
     TransformationAdjustBranchWeights adjust_branch_weights = 46;
     TransformationAdjustBranchWeights adjust_branch_weights = 46;
     TransformationPushIdThroughVariable push_id_through_variable = 47;
     TransformationPushIdThroughVariable push_id_through_variable = 47;
+    TransformationAddSpecConstantOp add_spec_constant_op = 48;
     // Add additional option using the next available number.
     // Add additional option using the next available number.
   }
   }
 }
 }
@@ -619,6 +620,24 @@ message TransformationAddNoContractionDecoration {
 
 
 }
 }
 
 
+message TransformationAddSpecConstantOp {
+
+  // Adds OpSpecConstantOp into the module.
+
+  // Result id for the new instruction.
+  uint32 fresh_id = 1;
+
+  // Type id for the new instruction.
+  uint32 type_id = 2;
+
+  // Opcode operand of the OpSpecConstantOp instruction.
+  uint32 opcode = 3;
+
+  // Operands of the |opcode| instruction.
+  repeated InstructionOperand operand = 4;
+
+}
+
 message TransformationAddTypeArray {
 message TransformationAddTypeArray {
 
 
   // Adds an array type of the given element type and size to the module
   // Adds an array type of the given element type and size to the module

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

@@ -30,6 +30,7 @@
 #include "source/fuzz/transformation_add_global_variable.h"
 #include "source/fuzz/transformation_add_global_variable.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_spec_constant_op.h"
 #include "source/fuzz/transformation_add_type_array.h"
 #include "source/fuzz/transformation_add_type_array.h"
 #include "source/fuzz/transformation_add_type_boolean.h"
 #include "source/fuzz/transformation_add_type_boolean.h"
 #include "source/fuzz/transformation_add_type_float.h"
 #include "source/fuzz/transformation_add_type_float.h"
@@ -110,6 +111,9 @@ std::unique_ptr<Transformation> Transformation::FromMessage(
         kAddNoContractionDecoration:
         kAddNoContractionDecoration:
       return MakeUnique<TransformationAddNoContractionDecoration>(
       return MakeUnique<TransformationAddNoContractionDecoration>(
           message.add_no_contraction_decoration());
           message.add_no_contraction_decoration());
+    case protobufs::Transformation::TransformationCase::kAddSpecConstantOp:
+      return MakeUnique<TransformationAddSpecConstantOp>(
+          message.add_spec_constant_op());
     case protobufs::Transformation::TransformationCase::kAddTypeArray:
     case protobufs::Transformation::TransformationCase::kAddTypeArray:
       return MakeUnique<TransformationAddTypeArray>(message.add_type_array());
       return MakeUnique<TransformationAddTypeArray>(message.add_type_array());
     case protobufs::Transformation::TransformationCase::kAddTypeBoolean:
     case protobufs::Transformation::TransformationCase::kAddTypeBoolean:

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

@@ -105,20 +105,8 @@ void TransformationAddGlobalVariable::Apply(
       input_operands));
       input_operands));
   fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
   fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
 
 
-  if (GlobalVariablesMustBeDeclaredInEntryPointInterfaces(ir_context)) {
-    // Conservatively add this global to the interface of every entry point in
-    // the module.  This means that the global is available for other
-    // transformations to use.
-    //
-    // A downside of this is that the global will be in the interface even if it
-    // ends up never being used.
-    //
-    // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3111) revisit
-    //  this if a more thorough approach to entry point interfaces is taken.
-    for (auto& entry_point : ir_context->module()->entry_points()) {
-      entry_point.AddOperand({SPV_OPERAND_TYPE_ID, {message_.fresh_id()}});
-    }
-  }
+  fuzzerutil::AddVariableIdToEntryPointInterfaces(ir_context,
+                                                  message_.fresh_id());
 
 
   if (message_.value_is_irrelevant()) {
   if (message_.value_is_irrelevant()) {
     transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
     transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
@@ -137,22 +125,5 @@ protobufs::Transformation TransformationAddGlobalVariable::ToMessage() const {
   return result;
   return result;
 }
 }
 
 
-bool TransformationAddGlobalVariable::
-    GlobalVariablesMustBeDeclaredInEntryPointInterfaces(
-        opt::IRContext* ir_context) {
-  // TODO(afd): We capture the universal environments for which this requirement
-  //  holds.  The check should be refined on demand for other target
-  //  environments.
-  switch (ir_context->grammar().target_env()) {
-    case SPV_ENV_UNIVERSAL_1_0:
-    case SPV_ENV_UNIVERSAL_1_1:
-    case SPV_ENV_UNIVERSAL_1_2:
-    case SPV_ENV_UNIVERSAL_1_3:
-      return false;
-    default:
-      return true;
-  }
-}
-
 }  // namespace fuzz
 }  // namespace fuzz
 }  // namespace spvtools
 }  // namespace spvtools

+ 0 - 6
3rdparty/spirv-tools/source/fuzz/transformation_add_global_variable.h

@@ -58,12 +58,6 @@ class TransformationAddGlobalVariable : public Transformation {
   protobufs::Transformation ToMessage() const override;
   protobufs::Transformation ToMessage() const override;
 
 
  private:
  private:
-  // Returns true if and only if the SPIR-V version being used requires that
-  // global variables accessed in the static call graph of an entry point need
-  // to be listed in that entry point's interface.
-  static bool GlobalVariablesMustBeDeclaredInEntryPointInterfaces(
-      opt::IRContext* ir_context);
-
   protobufs::TransformationAddGlobalVariable message_;
   protobufs::TransformationAddGlobalVariable message_;
 };
 };
 
 

+ 84 - 0
3rdparty/spirv-tools/source/fuzz/transformation_add_spec_constant_op.cpp

@@ -0,0 +1,84 @@
+// 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 <utility>
+
+#include "source/fuzz/fuzzer_util.h"
+#include "source/fuzz/transformation_add_spec_constant_op.h"
+
+namespace spvtools {
+namespace fuzz {
+
+TransformationAddSpecConstantOp::TransformationAddSpecConstantOp(
+    spvtools::fuzz::protobufs::TransformationAddSpecConstantOp message)
+    : message_(std::move(message)) {}
+
+TransformationAddSpecConstantOp::TransformationAddSpecConstantOp(
+    uint32_t fresh_id, uint32_t type_id, SpvOp opcode,
+    const opt::Instruction::OperandList& operands) {
+  message_.set_fresh_id(fresh_id);
+  message_.set_type_id(type_id);
+  message_.set_opcode(opcode);
+  for (const auto& operand : operands) {
+    auto* op = message_.add_operand();
+    op->set_operand_type(operand.type);
+    for (auto word : operand.words) {
+      op->add_operand_data(word);
+    }
+  }
+}
+
+bool TransformationAddSpecConstantOp::IsApplicable(
+    opt::IRContext* ir_context,
+    const TransformationContext& transformation_context) const {
+  auto clone = fuzzerutil::CloneIRContext(ir_context);
+  ApplyImpl(clone.get());
+  return fuzzerutil::IsValid(clone.get(),
+                             transformation_context.GetValidatorOptions());
+}
+
+void TransformationAddSpecConstantOp::Apply(
+    opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
+  ApplyImpl(ir_context);
+  ir_context->InvalidateAnalysesExceptFor(
+      opt::IRContext::Analysis::kAnalysisNone);
+}
+
+void TransformationAddSpecConstantOp::ApplyImpl(
+    opt::IRContext* ir_context) const {
+  opt::Instruction::OperandList operands = {
+      {SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER, {message_.opcode()}}};
+
+  for (const auto& operand : message_.operand()) {
+    std::vector<uint32_t> words(operand.operand_data().begin(),
+                                operand.operand_data().end());
+    operands.push_back({static_cast<spv_operand_type_t>(operand.operand_type()),
+                        std::move(words)});
+  }
+
+  ir_context->AddGlobalValue(MakeUnique<opt::Instruction>(
+      ir_context, SpvOpSpecConstantOp, message_.type_id(), message_.fresh_id(),
+      std::move(operands)));
+
+  fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
+}
+
+protobufs::Transformation TransformationAddSpecConstantOp::ToMessage() const {
+  protobufs::Transformation result;
+  *result.mutable_add_spec_constant_op() = message_;
+  return result;
+}
+
+}  // namespace fuzz
+}  // namespace spvtools

+ 60 - 0
3rdparty/spirv-tools/source/fuzz/transformation_add_spec_constant_op.h

@@ -0,0 +1,60 @@
+// 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_ADD_SPEC_CONSTANT_OP_H_
+#define SOURCE_FUZZ_TRANSFORMATION_ADD_SPEC_CONSTANT_OP_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 TransformationAddSpecConstantOp : public Transformation {
+ public:
+  explicit TransformationAddSpecConstantOp(
+      protobufs::TransformationAddSpecConstantOp message);
+
+  TransformationAddSpecConstantOp(
+      uint32_t fresh_id, uint32_t type_id, SpvOp opcode,
+      const opt::Instruction::OperandList& operands);
+
+  // - |fresh_id| is a fresh result id in the module.
+  // - |type_id| is a valid result id of some OpType* instruction in the
+  // module. It is also a valid type id with respect to |opcode|.
+  // - |opcode| is one of the opcodes supported by OpSpecConstantOp.
+  // - |operands| are valid with respect to |opcode|
+  bool IsApplicable(
+      opt::IRContext* ir_context,
+      const TransformationContext& transformation_context) const override;
+
+  // |%fresh_id = OpSpecConstantOp %type_id opcode operands...| is added to the
+  // module.
+  void Apply(opt::IRContext* ir_context,
+             TransformationContext* transformation_context) const override;
+
+  protobufs::Transformation ToMessage() const override;
+
+ private:
+  void ApplyImpl(opt::IRContext* ir_context) const;
+
+  protobufs::TransformationAddSpecConstantOp message_;
+};
+
+}  // namespace fuzz
+}  // namespace spvtools
+
+#endif  // SOURCE_FUZZ_TRANSFORMATION_ADD_SPEC_CONSTANT_OP_H_

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

@@ -109,6 +109,9 @@ void TransformationPushIdThroughVariable::Apply(
         ir_context, SpvOpVariable, pointer_type_id, message_.variable_id(),
         ir_context, SpvOpVariable, pointer_type_id, message_.variable_id(),
         opt::Instruction::OperandList(
         opt::Instruction::OperandList(
             {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassPrivate}}})));
             {{SPV_OPERAND_TYPE_STORAGE_CLASS, {SpvStorageClassPrivate}}})));
+
+    fuzzerutil::AddVariableIdToEntryPointInterfaces(ir_context,
+                                                    message_.variable_id());
   } else {
   } else {
     ir_context
     ir_context
         ->get_instr_block(
         ->get_instr_block(

+ 23 - 0
3rdparty/spirv-tools/source/fuzz/transformation_set_memory_operands_mask.cpp

@@ -101,6 +101,14 @@ void TransformationSetMemoryOperandsMask::Apply(
   // Either add a new operand, if no mask operand was already present, or
   // Either add a new operand, if no mask operand was already present, or
   // replace an existing mask operand.
   // replace an existing mask operand.
   if (original_mask_in_operand_index >= instruction->NumInOperands()) {
   if (original_mask_in_operand_index >= instruction->NumInOperands()) {
+    // Add first memory operand if it's missing.
+    if (message_.memory_operands_mask_index() == 1 &&
+        GetInOperandIndexForMask(*instruction, 0) >=
+            instruction->NumInOperands()) {
+      instruction->AddOperand(
+          {SPV_OPERAND_TYPE_MEMORY_ACCESS, {SpvMemoryAccessMaskNone}});
+    }
+
     instruction->AddOperand(
     instruction->AddOperand(
         {SPV_OPERAND_TYPE_MEMORY_ACCESS, {message_.memory_operands_mask()}});
         {SPV_OPERAND_TYPE_MEMORY_ACCESS, {message_.memory_operands_mask()}});
 
 
@@ -154,11 +162,26 @@ uint32_t TransformationSetMemoryOperandsMask::GetInOperandIndexForMask(
       break;
       break;
   }
   }
   // If we are looking for the input operand index of the first mask, return it.
   // If we are looking for the input operand index of the first mask, return it.
+  // This will also return a correct value if the operand is missing.
   if (mask_index == 0) {
   if (mask_index == 0) {
     return first_mask_in_operand_index;
     return first_mask_in_operand_index;
   }
   }
   assert(mask_index == 1 && "Memory operands mask index must be 0 or 1.");
   assert(mask_index == 1 && "Memory operands mask index must be 0 or 1.");
 
 
+  // Memory mask operands are optional. Thus, if the second operand exists,
+  // its index will be >= |first_mask_in_operand_index + 1|. We can reason as
+  // follows to separate the cases where the index of the second operand is
+  // equal to |first_mask_in_operand_index + 1|:
+  // - If the first memory operand doesn't exist, its value is equal to None.
+  //   This means that it doesn't have additional operands following it and the
+  //   condition in the if statement below will be satisfied.
+  // - If the first memory operand exists and has no additional memory operands
+  //   following it, the condition in the if statement below will be satisfied
+  //   and we will return the correct value from the function.
+  if (first_mask_in_operand_index + 1 >= instruction.NumInOperands()) {
+    return first_mask_in_operand_index + 1;
+  }
+
   // We are looking for the input operand index of the second mask.  This is a
   // We are looking for the input operand index of the second mask.  This is a
   // little complicated because, depending on the contents of the first mask,
   // little complicated because, depending on the contents of the first mask,
   // there may be some input operands separating the two masks.
   // there may be some input operands separating the two masks.