From b8fa5e79b1199111e2870efd8d424d6e19481f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Mon, 28 Oct 2019 19:53:59 -0700 Subject: [PATCH] Updated spirv-tools. --- .../include/generated/build-version.inc | 2 +- .../spirv-tools/source/fuzz/CMakeLists.txt | 6 +- .../spirv-tools/source/fuzz/fact_manager.cpp | 2 +- .../fuzz/fuzzer_pass_construct_composites.cpp | 4 +- .../spirv-tools/source/fuzz/fuzzer_util.cpp | 2 +- .../spirv-tools/source/fuzz/fuzzer_util.h | 2 +- .../source/fuzz/protobufs/spvtoolsfuzz.proto | 59 ++- .../source/fuzz/transformation.cpp | 12 +- ...=> transformation_composite_construct.cpp} | 24 +- ...h => transformation_composite_construct.h} | 16 +- .../fuzz/transformation_composite_extract.cpp | 123 ++++++ .../fuzz/transformation_composite_extract.h | 63 +++ ...transformation_replace_id_with_synonym.cpp | 33 +- .../spirv-tools/source/opt/folding_rules.cpp | 116 ++++++ .../source/opt/simplification_pass.cpp | 22 +- .../source/opt/simplification_pass.h | 8 + 3rdparty/spirv-tools/test/fuzz/CMakeLists.txt | 3 +- ...ansformation_composite_construct_test.cpp} | 90 ++-- .../transformation_composite_extract_test.cpp | 393 ++++++++++++++++++ 3rdparty/spirv-tools/test/opt/fold_test.cpp | 126 ++++++ .../test/opt/simplification_test.cpp | 35 ++ 3rdparty/spirv-tools/utils/vscode/.gitignore | 1 + 3rdparty/spirv-tools/utils/vscode/README.md | 7 + 3rdparty/spirv-tools/utils/vscode/install.sh | 26 ++ .../spirv-tools/utils/vscode/package.json | 33 ++ .../utils/vscode/spirv.configuration.json | 6 + 3rdparty/spirv-tools/utils/vscode/spirv.json | 212 ++++++++++ .../spirv-tools/utils/vscode/spirv.json.tmpl | 67 +++ .../utils/vscode/src/grammar/grammar.go | 75 ++++ .../utils/vscode/src/tools/gen-grammar.go | 167 ++++++++ 30 files changed, 1623 insertions(+), 112 deletions(-) rename 3rdparty/spirv-tools/source/fuzz/{transformation_construct_composite.cpp => transformation_composite_construct.cpp} (93%) rename 3rdparty/spirv-tools/source/fuzz/{transformation_construct_composite.h => transformation_composite_construct.h} (87%) create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.cpp create mode 100644 3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.h rename 3rdparty/spirv-tools/test/fuzz/{transformation_construct_composite_test.cpp => transformation_composite_construct_test.cpp} (95%) create mode 100644 3rdparty/spirv-tools/test/fuzz/transformation_composite_extract_test.cpp create mode 100644 3rdparty/spirv-tools/utils/vscode/.gitignore create mode 100644 3rdparty/spirv-tools/utils/vscode/README.md create mode 100755 3rdparty/spirv-tools/utils/vscode/install.sh create mode 100644 3rdparty/spirv-tools/utils/vscode/package.json create mode 100644 3rdparty/spirv-tools/utils/vscode/spirv.configuration.json create mode 100644 3rdparty/spirv-tools/utils/vscode/spirv.json create mode 100644 3rdparty/spirv-tools/utils/vscode/spirv.json.tmpl create mode 100644 3rdparty/spirv-tools/utils/vscode/src/grammar/grammar.go create mode 100644 3rdparty/spirv-tools/utils/vscode/src/tools/gen-grammar.go diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index 8ac84d22d..82989eae6 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2019.5-dev", "SPIRV-Tools v2019.5-dev v2019.4-140-g0dbd4e35" +"v2019.5-dev", "SPIRV-Tools v2019.5-dev v2019.4-144-g42f88523" diff --git a/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt b/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt index 3dce6047b..627fcba87 100644 --- a/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/fuzz/CMakeLists.txt @@ -68,7 +68,8 @@ if(SPIRV_BUILD_FUZZER) transformation_add_type_float.h transformation_add_type_int.h transformation_add_type_pointer.h - transformation_construct_composite.h + transformation_composite_construct.h + transformation_composite_extract.h transformation_copy_object.h transformation_move_block_down.h transformation_replace_boolean_constant_with_constant_binary.h @@ -119,7 +120,8 @@ if(SPIRV_BUILD_FUZZER) transformation_add_type_float.cpp transformation_add_type_int.cpp transformation_add_type_pointer.cpp - transformation_construct_composite.cpp + transformation_composite_construct.cpp + transformation_composite_extract.cpp transformation_copy_object.cpp transformation_move_block_down.cpp transformation_replace_boolean_constant_with_constant_binary.cpp diff --git a/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp b/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp index e99882750..59e50acdd 100644 --- a/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fact_manager.cpp @@ -283,7 +283,7 @@ bool FactManager::ConstantUniformFacts::AddFact( auto composite_type = should_be_uniform_pointer_instruction->GetSingleWordInOperand(1); - auto final_element_type_id = fuzzerutil::WalkCompositeIndices( + auto final_element_type_id = fuzzerutil::WalkCompositeTypeIndices( context, composite_type, fact.uniform_buffer_element_descriptor().index()); if (!final_element_type_id) { diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp index 2d4b0ca81..9eb56316c 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_pass_construct_composites.cpp @@ -18,7 +18,7 @@ #include #include "source/fuzz/fuzzer_util.h" -#include "source/fuzz/transformation_construct_composite.h" +#include "source/fuzz/transformation_composite_construct.h" #include "source/util/make_unique.h" namespace spvtools { @@ -140,7 +140,7 @@ void FuzzerPassConstructComposites::Apply() { assert(constructor_arguments != nullptr); // Make and apply a transformation. - TransformationConstructComposite transformation( + TransformationCompositeConstruct transformation( chosen_composite_type, *constructor_arguments, instruction_descriptor, GetFuzzerContext()->GetFreshId()); assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) && diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp index f0bd6f95a..feb9506ed 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.cpp @@ -330,7 +330,7 @@ bool IsCompositeType(const opt::analysis::Type* type) { type->AsVector()); } -uint32_t WalkCompositeIndices( +uint32_t WalkCompositeTypeIndices( opt::IRContext* context, uint32_t base_object_type_id, const google::protobuf::RepeatedField& indices) { uint32_t sub_object_type_id = base_object_type_id; diff --git a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.h b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.h index 8f27e407b..3599ff1e4 100644 --- a/3rdparty/spirv-tools/source/fuzz/fuzzer_util.h +++ b/3rdparty/spirv-tools/source/fuzz/fuzzer_util.h @@ -98,7 +98,7 @@ bool IsCompositeType(const opt::analysis::Type* type); // |indices| is suitable for indexing into this type. Returns the id of the // type of the final sub-object reached via the indices if they are valid, and // 0 otherwise. -uint32_t WalkCompositeIndices( +uint32_t WalkCompositeTypeIndices( opt::IRContext* context, uint32_t base_object_type_id, const google::protobuf::RepeatedField& indices); diff --git a/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto b/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto index cd1e77ad6..060a44d53 100644 --- a/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto +++ b/3rdparty/spirv-tools/source/fuzz/protobufs/spvtoolsfuzz.proto @@ -187,11 +187,12 @@ message Transformation { TransformationCopyObject copy_object = 13; TransformationReplaceIdWithSynonym replace_id_with_synonym = 14; TransformationSetSelectionControl set_selection_control = 15; - TransformationConstructComposite construct_composite = 16; + TransformationCompositeConstruct composite_construct = 16; TransformationSetLoopControl set_loop_control = 17; TransformationSetFunctionControl set_function_control = 18; TransformationAddNoContractionDecoration add_no_contraction_decoration = 19; TransformationSetMemoryOperandsMask set_memory_operands_mask = 20; + TransformationCompositeExtract composite_extract = 21; // Add additional option using the next available number. } } @@ -325,24 +326,7 @@ message TransformationAddTypePointer { } -message TransformationCopyObject { - - // A transformation that introduces an OpCopyObject instruction to make a - // copy of an object. - - // Id of the object to be copied - uint32 object = 1; - - // A descriptor for an instruction in a block before which the new - // OpCopyObject instruction should be inserted - InstructionDescriptor instruction_to_insert_before = 2; - - // A fresh id for the copied object - uint32 fresh_id = 3; - -} - -message TransformationConstructComposite { +message TransformationCompositeConstruct { // A transformation that introduces an OpCompositeConstruct instruction to // make a composite object. @@ -362,6 +346,43 @@ message TransformationConstructComposite { } +message TransformationCompositeExtract { + + // A transformation that adds an instruction to extract an element from a + // composite. + + // A descriptor for an instruction in a block before which the new + // OpCompositeExtract instruction should be inserted + InstructionDescriptor instruction_to_insert_before = 1; + + // Result id for the extract operation. + uint32 fresh_id = 2; + + // Id of the composite from which data is to be extracted. + uint32 composite_id = 3; + + // Indices that indicate which part of the composite should be extracted. + repeated uint32 index = 4; + +} + +message TransformationCopyObject { + + // A transformation that introduces an OpCopyObject instruction to make a + // copy of an object. + + // Id of the object to be copied + uint32 object = 1; + + // A descriptor for an instruction in a block before which the new + // OpCopyObject instruction should be inserted + InstructionDescriptor instruction_to_insert_before = 2; + + // A fresh id for the copied object + uint32 fresh_id = 3; + +} + message TransformationMoveBlockDown { // A transformation that moves a basic block to be one position lower in diff --git a/3rdparty/spirv-tools/source/fuzz/transformation.cpp b/3rdparty/spirv-tools/source/fuzz/transformation.cpp index ddc0b0795..ddfb2a88e 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation.cpp +++ b/3rdparty/spirv-tools/source/fuzz/transformation.cpp @@ -25,7 +25,8 @@ #include "source/fuzz/transformation_add_type_float.h" #include "source/fuzz/transformation_add_type_int.h" #include "source/fuzz/transformation_add_type_pointer.h" -#include "source/fuzz/transformation_construct_composite.h" +#include "source/fuzz/transformation_composite_construct.h" +#include "source/fuzz/transformation_composite_extract.h" #include "source/fuzz/transformation_copy_object.h" #include "source/fuzz/transformation_move_block_down.h" #include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h" @@ -71,9 +72,12 @@ std::unique_ptr Transformation::FromMessage( case protobufs::Transformation::TransformationCase::kAddTypePointer: return MakeUnique( message.add_type_pointer()); - case protobufs::Transformation::TransformationCase::kConstructComposite: - return MakeUnique( - message.construct_composite()); + case protobufs::Transformation::TransformationCase::kCompositeConstruct: + return MakeUnique( + message.composite_construct()); + case protobufs::Transformation::TransformationCase::kCompositeExtract: + return MakeUnique( + message.composite_extract()); case protobufs::Transformation::TransformationCase::kCopyObject: return MakeUnique(message.copy_object()); case protobufs::Transformation::TransformationCase::kMoveBlockDown: diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_composite_construct.cpp similarity index 93% rename from 3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.cpp rename to 3rdparty/spirv-tools/source/fuzz/transformation_composite_construct.cpp index 57d2bfdf4..fde3c9bf5 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.cpp +++ b/3rdparty/spirv-tools/source/fuzz/transformation_composite_construct.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/fuzz/transformation_construct_composite.h" +#include "source/fuzz/transformation_composite_construct.h" #include "source/fuzz/data_descriptor.h" #include "source/fuzz/fuzzer_util.h" @@ -22,11 +22,11 @@ namespace spvtools { namespace fuzz { -TransformationConstructComposite::TransformationConstructComposite( - const protobufs::TransformationConstructComposite& message) +TransformationCompositeConstruct::TransformationCompositeConstruct( + const protobufs::TransformationCompositeConstruct& message) : message_(message) {} -TransformationConstructComposite::TransformationConstructComposite( +TransformationCompositeConstruct::TransformationCompositeConstruct( uint32_t composite_type_id, std::vector component, const protobufs::InstructionDescriptor& instruction_to_insert_before, uint32_t fresh_id) { @@ -39,7 +39,7 @@ TransformationConstructComposite::TransformationConstructComposite( message_.set_fresh_id(fresh_id); } -bool TransformationConstructComposite::IsApplicable( +bool TransformationCompositeConstruct::IsApplicable( opt::IRContext* context, const FactManager& /*fact_manager*/) const { if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { // We require the id for the composite constructor to be unused. @@ -112,7 +112,7 @@ bool TransformationConstructComposite::IsApplicable( return true; } -void TransformationConstructComposite::Apply(opt::IRContext* context, +void TransformationCompositeConstruct::Apply(opt::IRContext* context, FactManager* fact_manager) const { // Use the base and offset information from the transformation to determine // where in the module a new instruction should be inserted. @@ -174,7 +174,7 @@ void TransformationConstructComposite::Apply(opt::IRContext* context, context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone); } -bool TransformationConstructComposite::ComponentsForArrayConstructionAreOK( +bool TransformationCompositeConstruct::ComponentsForArrayConstructionAreOK( opt::IRContext* context, const opt::analysis::Array& array_type) const { if (array_type.length_info().words[0] != opt::analysis::Array::LengthInfo::kConstant) { @@ -211,7 +211,7 @@ bool TransformationConstructComposite::ComponentsForArrayConstructionAreOK( return true; } -bool TransformationConstructComposite::ComponentsForMatrixConstructionAreOK( +bool TransformationCompositeConstruct::ComponentsForMatrixConstructionAreOK( opt::IRContext* context, const opt::analysis::Matrix& matrix_type) const { if (static_cast(message_.component().size()) != matrix_type.element_count()) { @@ -237,7 +237,7 @@ bool TransformationConstructComposite::ComponentsForMatrixConstructionAreOK( return true; } -bool TransformationConstructComposite::ComponentsForStructConstructionAreOK( +bool TransformationCompositeConstruct::ComponentsForStructConstructionAreOK( opt::IRContext* context, const opt::analysis::Struct& struct_type) const { if (static_cast(message_.component().size()) != struct_type.element_types().size()) { @@ -265,7 +265,7 @@ bool TransformationConstructComposite::ComponentsForStructConstructionAreOK( return true; } -bool TransformationConstructComposite::ComponentsForVectorConstructionAreOK( +bool TransformationCompositeConstruct::ComponentsForVectorConstructionAreOK( opt::IRContext* context, const opt::analysis::Vector& vector_type) const { uint32_t base_element_count = 0; auto element_type = vector_type.element_type(); @@ -295,9 +295,9 @@ bool TransformationConstructComposite::ComponentsForVectorConstructionAreOK( return base_element_count == vector_type.element_count(); } -protobufs::Transformation TransformationConstructComposite::ToMessage() const { +protobufs::Transformation TransformationCompositeConstruct::ToMessage() const { protobufs::Transformation result; - *result.mutable_construct_composite() = message_; + *result.mutable_composite_construct() = message_; return result; } diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.h b/3rdparty/spirv-tools/source/fuzz/transformation_composite_construct.h similarity index 87% rename from 3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.h rename to 3rdparty/spirv-tools/source/fuzz/transformation_composite_construct.h index 8eb019116..5369c4c89 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_construct_composite.h +++ b/3rdparty/spirv-tools/source/fuzz/transformation_composite_construct.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef SOURCE_FUZZ_TRANSFORMATION_CONSTRUCT_COMPOSITE_H_ -#define SOURCE_FUZZ_TRANSFORMATION_CONSTRUCT_COMPOSITE_H_ +#ifndef SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_CONSTRUCT_H_ +#define SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_CONSTRUCT_H_ #include "source/fuzz/fact_manager.h" #include "source/fuzz/protobufs/spirvfuzz_protobufs.h" @@ -23,12 +23,12 @@ namespace spvtools { namespace fuzz { -class TransformationConstructComposite : public Transformation { +class TransformationCompositeConstruct : public Transformation { public: - explicit TransformationConstructComposite( - const protobufs::TransformationConstructComposite& message); + explicit TransformationCompositeConstruct( + const protobufs::TransformationCompositeConstruct& message); - TransformationConstructComposite( + TransformationCompositeConstruct( uint32_t composite_type_id, std::vector component, const protobufs::InstructionDescriptor& instruction_to_insert_before, uint32_t fresh_id); @@ -79,10 +79,10 @@ class TransformationConstructComposite : public Transformation { bool ComponentsForVectorConstructionAreOK( opt::IRContext* context, const opt::analysis::Vector& vector_type) const; - protobufs::TransformationConstructComposite message_; + protobufs::TransformationCompositeConstruct message_; }; } // namespace fuzz } // namespace spvtools -#endif // SOURCE_FUZZ_TRANSFORMATION_CONSTRUCT_COMPOSITE_H_ +#endif // SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_CONSTRUCT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.cpp new file mode 100644 index 000000000..c5c694df5 --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.cpp @@ -0,0 +1,123 @@ +// Copyright (c) 2019 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 "source/fuzz/transformation_composite_extract.h" + +#include + +#include "source/fuzz/data_descriptor.h" +#include "source/fuzz/fuzzer_util.h" +#include "source/fuzz/instruction_descriptor.h" + +namespace spvtools { +namespace fuzz { + +TransformationCompositeExtract::TransformationCompositeExtract( + const spvtools::fuzz::protobufs::TransformationCompositeExtract& message) + : message_(message) {} + +TransformationCompositeExtract::TransformationCompositeExtract( + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id, uint32_t composite_id, std::vector&& index) { + *message_.mutable_instruction_to_insert_before() = + instruction_to_insert_before; + message_.set_fresh_id(fresh_id); + message_.set_composite_id(composite_id); + for (auto an_index : index) { + message_.add_index(an_index); + } +} + +bool TransformationCompositeExtract::IsApplicable( + opt::IRContext* context, + const spvtools::fuzz::FactManager& /*unused*/) const { + if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) { + return false; + } + auto instruction_to_insert_before = + FindInstruction(message_.instruction_to_insert_before(), context); + if (!instruction_to_insert_before) { + return false; + } + auto composite_instruction = + context->get_def_use_mgr()->GetDef(message_.composite_id()); + if (!composite_instruction) { + return false; + } + if (auto block = context->get_instr_block(composite_instruction)) { + if (composite_instruction == instruction_to_insert_before || + !context->GetDominatorAnalysis(block->GetParent()) + ->Dominates(composite_instruction, instruction_to_insert_before)) { + return false; + } + } + assert(composite_instruction->type_id() && + "An instruction in a block cannot have a result id but no type id."); + + auto composite_type = + context->get_type_mgr()->GetType(composite_instruction->type_id()); + if (!composite_type) { + return false; + } + + if (!fuzzerutil::CanInsertOpcodeBeforeInstruction( + SpvOpCompositeExtract, instruction_to_insert_before)) { + return false; + } + + return fuzzerutil::WalkCompositeTypeIndices( + context, composite_instruction->type_id(), message_.index()) != 0; +} + +void TransformationCompositeExtract::Apply( + opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const { + opt::Instruction::OperandList extract_operands; + extract_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.composite_id()}}); + for (auto an_index : message_.index()) { + extract_operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {an_index}}); + } + auto composite_instruction = + context->get_def_use_mgr()->GetDef(message_.composite_id()); + auto extracted_type = fuzzerutil::WalkCompositeTypeIndices( + context, composite_instruction->type_id(), message_.index()); + + FindInstruction(message_.instruction_to_insert_before(), context) + ->InsertBefore(MakeUnique( + context, SpvOpCompositeExtract, extracted_type, message_.fresh_id(), + extract_operands)); + + fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id()); + + // Add the fact that the id storing the extracted element is synonymous with + // the index into the structure. + std::vector indices; + for (auto an_index : message_.index()) { + indices.push_back(an_index); + } + protobufs::DataDescriptor data_descriptor_for_extracted_element = + MakeDataDescriptor(message_.composite_id(), std::move(indices), 1); + protobufs::DataDescriptor data_descriptor_for_result_id = + MakeDataDescriptor(message_.fresh_id(), {}, 1); + fact_manager->AddFactDataSynonym(data_descriptor_for_extracted_element, + data_descriptor_for_result_id); +} + +protobufs::Transformation TransformationCompositeExtract::ToMessage() const { + protobufs::Transformation result; + *result.mutable_composite_extract() = message_; + return result; +} + +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.h b/3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.h new file mode 100644 index 000000000..c4c9278cc --- /dev/null +++ b/3rdparty/spirv-tools/source/fuzz/transformation_composite_extract.h @@ -0,0 +1,63 @@ +// Copyright (c) 2019 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_COMPOSITE_EXTRACT_H_ +#define SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_H_ + +#include "source/fuzz/fact_manager.h" +#include "source/fuzz/protobufs/spirvfuzz_protobufs.h" +#include "source/fuzz/transformation.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace fuzz { + +class TransformationCompositeExtract : public Transformation { + public: + explicit TransformationCompositeExtract( + const protobufs::TransformationCompositeExtract& message); + + TransformationCompositeExtract( + const protobufs::InstructionDescriptor& instruction_to_insert_before, + uint32_t fresh_id, uint32_t composite_id, std::vector&& index); + + // - |message_.fresh_id| must be available + // - |message_.instruction_to_insert_before| must identify an instruction + // before which it is valid to place an OpCompositeExtract + // - |message_.composite_id| must be the id of an instruction that defines + // a composite object, and this id must be available at the instruction + // identified by |message_.instruction_to_insert_before| + // - |message_.index| must be a suitable set of indices for + // |message_.composite_id|, i.e. it must be possible to follow this chain + // of indices to reach a sub-object of |message_.composite_id| + bool IsApplicable(opt::IRContext* context, + const FactManager& fact_manager) const override; + + // Adds an OpCompositeConstruct instruction before the instruction identified + // by |message_.instruction_to_insert_before|, that extracts from + // |message_.composite_id| via indices |message_.index| into + // |message_.fresh_id|. Generates a data synonym fact relating + // |message_.fresh_id| to the extracted element. + void Apply(opt::IRContext* context, FactManager* fact_manager) const override; + + protobufs::Transformation ToMessage() const override; + + private: + protobufs::TransformationCompositeExtract message_; +}; + +} // namespace fuzz +} // namespace spvtools + +#endif // SOURCE_FUZZ_TRANSFORMATION_COMPOSITE_EXTRACT_H_ diff --git a/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp b/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp index 0720c154a..ec5081c18 100644 --- a/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp +++ b/3rdparty/spirv-tools/source/fuzz/transformation_replace_id_with_synonym.cpp @@ -275,22 +275,27 @@ bool TransformationReplaceIdWithSynonym::ReplacingUseWithSynonymIsOk( // We now need to check that replacing the use with the synonym will respect // dominance rules - i.e. the synonym needs to dominate the use. - auto dominator_analysis = context->GetDominatorAnalysis( - context->get_instr_block(use_instruction)->GetParent()); - if (use_instruction->opcode() == SpvOpPhi) { - // In the case where the use is an operand to OpPhi, it is actually the - // *parent* block associated with the operand that must be dominated by the - // synonym. - auto parent_block = - use_instruction->GetSingleWordInOperand(use_in_operand_index + 1); - if (!dominator_analysis->Dominates( - context->get_instr_block(defining_instruction)->id(), - parent_block)) { + // This is only relevant if the defining instruction is in a block; if it is + // not in a block then it is at global scope, and so replacing the use with it + // is fine. + if (context->get_instr_block(defining_instruction)) { + auto dominator_analysis = context->GetDominatorAnalysis( + context->get_instr_block(use_instruction)->GetParent()); + if (use_instruction->opcode() == SpvOpPhi) { + // In the case where the use is an operand to OpPhi, it is actually the + // *parent* block associated with the operand that must be dominated by + // the synonym. + auto parent_block = + use_instruction->GetSingleWordInOperand(use_in_operand_index + 1); + if (!dominator_analysis->Dominates( + context->get_instr_block(defining_instruction)->id(), + parent_block)) { + return false; + } + } else if (!dominator_analysis->Dominates(defining_instruction, + use_instruction)) { return false; } - } else if (!dominator_analysis->Dominates(defining_instruction, - use_instruction)) { - return false; } return true; } diff --git a/3rdparty/spirv-tools/source/opt/folding_rules.cpp b/3rdparty/spirv-tools/source/opt/folding_rules.cpp index e54a0cd56..eea723820 100644 --- a/3rdparty/spirv-tools/source/opt/folding_rules.cpp +++ b/3rdparty/spirv-tools/source/opt/folding_rules.cpp @@ -18,6 +18,7 @@ #include #include +#include "ir_builder.h" #include "source/latest_version_glsl_std_450_header.h" #include "source/opt/ir_context.h" @@ -1239,6 +1240,117 @@ FoldingRule MergeSubSubArithmetic() { }; } +// Helper function for MergeGenericAddSubArithmetic. If |addend| and +// subtrahend of |sub| is the same, merge to copy of minuend of |sub|. +bool MergeGenericAddendSub(uint32_t addend, uint32_t sub, Instruction* inst) { + IRContext* context = inst->context(); + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + Instruction* sub_inst = def_use_mgr->GetDef(sub); + if (sub_inst->opcode() != SpvOpFSub && sub_inst->opcode() != SpvOpISub) + return false; + if (sub_inst->opcode() == SpvOpFSub && + !sub_inst->IsFloatingPointFoldingAllowed()) + return false; + if (addend != sub_inst->GetSingleWordInOperand(1)) return false; + inst->SetOpcode(SpvOpCopyObject); + inst->SetInOperands( + {{SPV_OPERAND_TYPE_ID, {sub_inst->GetSingleWordInOperand(0)}}}); + context->UpdateDefUse(inst); + return true; +} + +// Folds addition of a subtraction where the subtrahend is equal to the +// other addend. Return a copy of the minuend. Accepts generic (const and +// non-const) operands. +// Cases: +// (a - b) + b = a +// b + (a - b) = a +FoldingRule MergeGenericAddSubArithmetic() { + return [](IRContext* context, Instruction* inst, + const std::vector&) { + assert(inst->opcode() == SpvOpFAdd || inst->opcode() == SpvOpIAdd); + const analysis::Type* type = + context->get_type_mgr()->GetType(inst->type_id()); + bool uses_float = HasFloatingPoint(type); + if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; + + uint32_t width = ElementWidth(type); + if (width != 32 && width != 64) return false; + + uint32_t add_op0 = inst->GetSingleWordInOperand(0); + uint32_t add_op1 = inst->GetSingleWordInOperand(1); + if (MergeGenericAddendSub(add_op0, add_op1, inst)) return true; + return MergeGenericAddendSub(add_op1, add_op0, inst); + }; +} + +// Helper function for FactorAddMuls. If |factor0_0| is the same as |factor1_0|, +// generate |factor0_0| * (|factor0_1| + |factor1_1|). +bool FactorAddMulsOpnds(uint32_t factor0_0, uint32_t factor0_1, + uint32_t factor1_0, uint32_t factor1_1, + Instruction* inst) { + IRContext* context = inst->context(); + if (factor0_0 != factor1_0) return false; + InstructionBuilder ir_builder( + context, inst, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + Instruction* new_add_inst = ir_builder.AddBinaryOp( + inst->type_id(), inst->opcode(), factor0_1, factor1_1); + inst->SetOpcode(inst->opcode() == SpvOpFAdd ? SpvOpFMul : SpvOpIMul); + inst->SetInOperands({{SPV_OPERAND_TYPE_ID, {factor0_0}}, + {SPV_OPERAND_TYPE_ID, {new_add_inst->result_id()}}}); + context->UpdateDefUse(inst); + return true; +} + +// Perform the following factoring identity, handling all operand order +// combinations: (a * b) + (a * c) = a * (b + c) +FoldingRule FactorAddMuls() { + return [](IRContext* context, Instruction* inst, + const std::vector&) { + assert(inst->opcode() == SpvOpFAdd || inst->opcode() == SpvOpIAdd); + const analysis::Type* type = + context->get_type_mgr()->GetType(inst->type_id()); + bool uses_float = HasFloatingPoint(type); + if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; + + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + uint32_t add_op0 = inst->GetSingleWordInOperand(0); + Instruction* add_op0_inst = def_use_mgr->GetDef(add_op0); + if (add_op0_inst->opcode() != SpvOpFMul && + add_op0_inst->opcode() != SpvOpIMul) + return false; + uint32_t add_op1 = inst->GetSingleWordInOperand(1); + Instruction* add_op1_inst = def_use_mgr->GetDef(add_op1); + if (add_op1_inst->opcode() != SpvOpFMul && + add_op1_inst->opcode() != SpvOpIMul) + return false; + + // Only perform this optimization if both of the muls only have one use. + // Otherwise this is a deoptimization in size and performance. + if (def_use_mgr->NumUses(add_op0_inst) > 1) return false; + if (def_use_mgr->NumUses(add_op1_inst) > 1) return false; + + if (add_op0_inst->opcode() == SpvOpFMul && + (!add_op0_inst->IsFloatingPointFoldingAllowed() || + !add_op1_inst->IsFloatingPointFoldingAllowed())) + return false; + + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + // Check if operand i in add_op0_inst matches operand j in add_op1_inst. + if (FactorAddMulsOpnds(add_op0_inst->GetSingleWordInOperand(i), + add_op0_inst->GetSingleWordInOperand(1 - i), + add_op1_inst->GetSingleWordInOperand(j), + add_op1_inst->GetSingleWordInOperand(1 - j), + inst)) + return true; + } + } + return false; + }; +} + FoldingRule IntMultipleBy1() { return [](IRContext*, Instruction* inst, const std::vector& constants) { @@ -2226,6 +2338,8 @@ void FoldingRules::AddFoldingRules() { rules_[SpvOpFAdd].push_back(MergeAddNegateArithmetic()); rules_[SpvOpFAdd].push_back(MergeAddAddArithmetic()); rules_[SpvOpFAdd].push_back(MergeAddSubArithmetic()); + rules_[SpvOpFAdd].push_back(MergeGenericAddSubArithmetic()); + rules_[SpvOpFAdd].push_back(FactorAddMuls()); rules_[SpvOpFDiv].push_back(RedundantFDiv()); rules_[SpvOpFDiv].push_back(ReciprocalFDiv()); @@ -2251,6 +2365,8 @@ void FoldingRules::AddFoldingRules() { rules_[SpvOpIAdd].push_back(MergeAddNegateArithmetic()); rules_[SpvOpIAdd].push_back(MergeAddAddArithmetic()); rules_[SpvOpIAdd].push_back(MergeAddSubArithmetic()); + rules_[SpvOpIAdd].push_back(MergeGenericAddSubArithmetic()); + rules_[SpvOpIAdd].push_back(FactorAddMuls()); rules_[SpvOpIMul].push_back(IntMultipleBy1()); rules_[SpvOpIMul].push_back(MergeMulMulArithmetic()); diff --git a/3rdparty/spirv-tools/source/opt/simplification_pass.cpp b/3rdparty/spirv-tools/source/opt/simplification_pass.cpp index 7b0887c55..001f35437 100644 --- a/3rdparty/spirv-tools/source/opt/simplification_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/simplification_pass.cpp @@ -32,6 +32,18 @@ Pass::Status SimplificationPass::Process() { return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange); } +void SimplificationPass::AddNewOperands( + Instruction* folded_inst, std::unordered_set* inst_seen, + std::vector* work_list) { + analysis::DefUseManager* def_use_mgr = get_def_use_mgr(); + folded_inst->ForEachInId( + [&inst_seen, &def_use_mgr, &work_list](uint32_t* iid) { + Instruction* iid_inst = def_use_mgr->GetDef(*iid); + if (!inst_seen->insert(iid_inst).second) return; + work_list->push_back(iid_inst); + }); +} + bool SimplificationPass::SimplifyFunction(Function* function) { bool modified = false; // Phase 1: Traverse all instructions in dominance order. @@ -44,13 +56,15 @@ bool SimplificationPass::SimplifyFunction(Function* function) { std::unordered_set process_phis; std::unordered_set inst_to_kill; std::unordered_set in_work_list; + std::unordered_set inst_seen; const InstructionFolder& folder = context()->get_instruction_folder(); cfg()->ForEachBlockInReversePostOrder( function->entry().get(), [&modified, &process_phis, &work_list, &in_work_list, &inst_to_kill, - &folder, this](BasicBlock* bb) { + &folder, &inst_seen, this](BasicBlock* bb) { for (Instruction* inst = &*bb->begin(); inst; inst = inst->NextNode()) { + inst_seen.insert(inst); if (inst->opcode() == SpvOpPhi) { process_phis.insert(inst); } @@ -70,6 +84,9 @@ bool SimplificationPass::SimplifyFunction(Function* function) { work_list.push_back(use); } }); + + AddNewOperands(inst, &inst_seen, &work_list); + if (inst->opcode() == SpvOpCopyObject) { context()->ReplaceAllUsesWithPredicate( inst->result_id(), inst->GetSingleWordInOperand(0), @@ -97,6 +114,7 @@ bool SimplificationPass::SimplifyFunction(Function* function) { for (size_t i = 0; i < work_list.size(); ++i) { Instruction* inst = work_list[i]; in_work_list.erase(inst); + inst_seen.insert(inst); bool is_foldable_copy = inst->opcode() == SpvOpCopyObject && @@ -114,6 +132,8 @@ bool SimplificationPass::SimplifyFunction(Function* function) { } }); + AddNewOperands(inst, &inst_seen, &work_list); + if (inst->opcode() == SpvOpCopyObject) { context()->ReplaceAllUsesWithPredicate( inst->result_id(), inst->GetSingleWordInOperand(0), diff --git a/3rdparty/spirv-tools/source/opt/simplification_pass.h b/3rdparty/spirv-tools/source/opt/simplification_pass.h index bcb88bfcd..149874b09 100644 --- a/3rdparty/spirv-tools/source/opt/simplification_pass.h +++ b/3rdparty/spirv-tools/source/opt/simplification_pass.h @@ -42,6 +42,14 @@ class SimplificationPass : public Pass { // instruction in |function| until nothing else in the function can be // simplified. bool SimplifyFunction(Function* function); + + // FactorAddMul can create |folded_inst| Mul of new Add. If Mul, push any Add + // operand not in |seen_inst| into |worklist|. This is heavily restricted to + // improve compile time but can be expanded for future simplifications which + // simiarly create new operations. + void AddNewOperands(Instruction* folded_inst, + std::unordered_set* inst_seen, + std::vector* work_list); }; } // namespace opt diff --git a/3rdparty/spirv-tools/test/fuzz/CMakeLists.txt b/3rdparty/spirv-tools/test/fuzz/CMakeLists.txt index 39aba9b4b..cfa89f94d 100644 --- a/3rdparty/spirv-tools/test/fuzz/CMakeLists.txt +++ b/3rdparty/spirv-tools/test/fuzz/CMakeLists.txt @@ -31,7 +31,8 @@ if (${SPIRV_BUILD_FUZZER}) transformation_add_type_float_test.cpp transformation_add_type_int_test.cpp transformation_add_type_pointer_test.cpp - transformation_construct_composite_test.cpp + transformation_composite_construct_test.cpp + transformation_composite_extract_test.cpp transformation_copy_object_test.cpp transformation_move_block_down_test.cpp transformation_replace_boolean_constant_with_constant_binary_test.cpp diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_construct_composite_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_composite_construct_test.cpp similarity index 95% rename from 3rdparty/spirv-tools/test/fuzz/transformation_construct_composite_test.cpp rename to 3rdparty/spirv-tools/test/fuzz/transformation_composite_construct_test.cpp index 51ee38972..7f1faf718 100644 --- a/3rdparty/spirv-tools/test/fuzz/transformation_construct_composite_test.cpp +++ b/3rdparty/spirv-tools/test/fuzz/transformation_composite_construct_test.cpp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/fuzz/transformation_construct_composite.h" +#include "source/fuzz/transformation_composite_construct.h" #include "source/fuzz/data_descriptor.h" #include "source/fuzz/instruction_descriptor.h" #include "test/fuzz/fuzz_test_util.h" @@ -36,7 +36,7 @@ bool SynonymFactHolds(const FactManager& fact_manager, uint32_t id, }) != synonyms.end(); } -TEST(TransformationConstructCompositeTest, ConstructArrays) { +TEST(TransformationCompositeConstructTest, ConstructArrays) { std::string shader = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -146,11 +146,11 @@ TEST(TransformationConstructCompositeTest, ConstructArrays) { FactManager fact_manager; // Make a vec2[3] - TransformationConstructComposite make_vec2_array_length_3( + TransformationCompositeConstruct make_vec2_array_length_3( 37, {41, 45, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0), 200); // Bad: there are too many components - TransformationConstructComposite make_vec2_array_length_3_bad( + TransformationCompositeConstruct make_vec2_array_length_3_bad( 37, {41, 45, 27, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0), 200); ASSERT_TRUE( @@ -164,10 +164,10 @@ TEST(TransformationConstructCompositeTest, ConstructArrays) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 27, 200, {2})); // Make a float[2] - TransformationConstructComposite make_float_array_length_2( + TransformationCompositeConstruct make_float_array_length_2( 9, {24, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201); // Bad: %41 does not have type float - TransformationConstructComposite make_float_array_length_2_bad( + TransformationCompositeConstruct make_float_array_length_2_bad( 9, {41, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201); ASSERT_TRUE( make_float_array_length_2.IsApplicable(context.get(), fact_manager)); @@ -179,11 +179,11 @@ TEST(TransformationConstructCompositeTest, ConstructArrays) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 40, 201, {1})); // Make a bool[3] - TransformationConstructComposite make_bool_array_length_3( + TransformationCompositeConstruct make_bool_array_length_3( 47, {33, 50, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0), 202); // Bad: %54 is not available at the desired program point. - TransformationConstructComposite make_bool_array_length_3_bad( + TransformationCompositeConstruct make_bool_array_length_3_bad( 47, {33, 54, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0), 202); ASSERT_TRUE( @@ -197,10 +197,10 @@ TEST(TransformationConstructCompositeTest, ConstructArrays) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 50, 202, {2})); // make a uvec3[2][2] - TransformationConstructComposite make_uvec3_array_length_2_2( + TransformationCompositeConstruct make_uvec3_array_length_2_2( 58, {69, 100}, MakeInstructionDescriptor(64, SpvOpStore, 0), 203); // Bad: Skip count 100 is too large. - TransformationConstructComposite make_uvec3_array_length_2_2_bad( + TransformationCompositeConstruct make_uvec3_array_length_2_2_bad( 58, {33, 54}, MakeInstructionDescriptor(64, SpvOpStore, 100), 203); ASSERT_TRUE( make_uvec3_array_length_2_2.IsApplicable(context.get(), fact_manager)); @@ -319,7 +319,7 @@ TEST(TransformationConstructCompositeTest, ConstructArrays) { ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); } -TEST(TransformationConstructCompositeTest, ConstructMatrices) { +TEST(TransformationCompositeConstructTest, ConstructMatrices) { std::string shader = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -399,10 +399,10 @@ TEST(TransformationConstructCompositeTest, ConstructMatrices) { FactManager fact_manager; // make a mat3x4 - TransformationConstructComposite make_mat34( + TransformationCompositeConstruct make_mat34( 32, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200); // Bad: %35 is mat4x3, not mat3x4. - TransformationConstructComposite make_mat34_bad( + TransformationCompositeConstruct make_mat34_bad( 35, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200); ASSERT_TRUE(make_mat34.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_mat34_bad.IsApplicable(context.get(), fact_manager)); @@ -413,10 +413,10 @@ TEST(TransformationConstructCompositeTest, ConstructMatrices) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 31, 200, {2})); // make a mat4x3 - TransformationConstructComposite make_mat43( + TransformationCompositeConstruct make_mat43( 35, {11, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201); // Bad: %25 does not match the matrix's column type. - TransformationConstructComposite make_mat43_bad( + TransformationCompositeConstruct make_mat43_bad( 35, {25, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201); ASSERT_TRUE(make_mat43.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_mat43_bad.IsApplicable(context.get(), fact_manager)); @@ -503,7 +503,7 @@ TEST(TransformationConstructCompositeTest, ConstructMatrices) { ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); } -TEST(TransformationConstructCompositeTest, ConstructStructs) { +TEST(TransformationCompositeConstructTest, ConstructStructs) { std::string shader = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -600,10 +600,10 @@ TEST(TransformationConstructCompositeTest, ConstructStructs) { FactManager fact_manager; // make an Inner - TransformationConstructComposite make_inner( + TransformationCompositeConstruct make_inner( 9, {25, 19}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200); // Bad: Too few fields to make the struct. - TransformationConstructComposite make_inner_bad( + TransformationCompositeConstruct make_inner_bad( 9, {25}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200); ASSERT_TRUE(make_inner.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_inner_bad.IsApplicable(context.get(), fact_manager)); @@ -613,11 +613,11 @@ TEST(TransformationConstructCompositeTest, ConstructStructs) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 19, 200, {1})); // make an Outer - TransformationConstructComposite make_outer( + TransformationCompositeConstruct make_outer( 33, {46, 200, 56}, MakeInstructionDescriptor(200, SpvOpAccessChain, 0), 201); // Bad: %200 is not available at the desired program point. - TransformationConstructComposite make_outer_bad( + TransformationCompositeConstruct make_outer_bad( 33, {46, 200, 56}, MakeInstructionDescriptor(200, SpvOpCompositeConstruct, 0), 201); ASSERT_TRUE(make_outer.IsApplicable(context.get(), fact_manager)); @@ -721,7 +721,7 @@ TEST(TransformationConstructCompositeTest, ConstructStructs) { ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); } -TEST(TransformationConstructCompositeTest, ConstructVectors) { +TEST(TransformationCompositeConstructTest, ConstructVectors) { std::string shader = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -913,10 +913,10 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { FactManager fact_manager; - TransformationConstructComposite make_vec2( + TransformationCompositeConstruct make_vec2( 7, {17, 11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200); // Bad: not enough data for a vec2 - TransformationConstructComposite make_vec2_bad( + TransformationCompositeConstruct make_vec2_bad( 7, {11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200); ASSERT_TRUE(make_vec2.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_vec2_bad.IsApplicable(context.get(), fact_manager)); @@ -925,11 +925,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 17, 200, {0})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 11, 200, {1})); - TransformationConstructComposite make_vec3( + TransformationCompositeConstruct make_vec3( 25, {12, 32}, MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0), 201); // Bad: too much data for a vec3 - TransformationConstructComposite make_vec3_bad( + TransformationCompositeConstruct make_vec3_bad( 25, {12, 32, 32}, MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0), 201); ASSERT_TRUE(make_vec3.IsApplicable(context.get(), fact_manager)); @@ -939,11 +939,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 12, 201, {0})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 32, 201, {2})); - TransformationConstructComposite make_vec4( + TransformationCompositeConstruct make_vec4( 44, {32, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0), 202); // Bad: id 48 is not available at the insertion points - TransformationConstructComposite make_vec4_bad( + TransformationCompositeConstruct make_vec4_bad( 44, {48, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0), 202); ASSERT_TRUE(make_vec4.IsApplicable(context.get(), fact_manager)); @@ -955,10 +955,10 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 10, 202, {2})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 11, 202, {3})); - TransformationConstructComposite make_ivec2( + TransformationCompositeConstruct make_ivec2( 51, {126, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203); // Bad: if 128 is not available at the instruction that defines 128 - TransformationConstructComposite make_ivec2_bad( + TransformationCompositeConstruct make_ivec2_bad( 51, {128, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203); ASSERT_TRUE(make_ivec2.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_ivec2_bad.IsApplicable(context.get(), fact_manager)); @@ -967,11 +967,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 126, 203, {0})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 120, 203, {1})); - TransformationConstructComposite make_ivec3( + TransformationCompositeConstruct make_ivec3( 114, {56, 117, 56}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0), 204); // Bad because 1300 is not an id - TransformationConstructComposite make_ivec3_bad( + TransformationCompositeConstruct make_ivec3_bad( 114, {56, 117, 1300}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0), 204); ASSERT_TRUE(make_ivec3.IsApplicable(context.get(), fact_manager)); @@ -982,11 +982,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 117, 204, {1})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 56, 204, {2})); - TransformationConstructComposite make_ivec4( + TransformationCompositeConstruct make_ivec4( 122, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0), 205); // Bad because 86 is the wrong type. - TransformationConstructComposite make_ivec4_bad( + TransformationCompositeConstruct make_ivec4_bad( 86, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0), 205); ASSERT_TRUE(make_ivec4.IsApplicable(context.get(), fact_manager)); @@ -998,9 +998,9 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 117, 205, {2})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 117, 205, {3})); - TransformationConstructComposite make_uvec2( + TransformationCompositeConstruct make_uvec2( 86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 0), 206); - TransformationConstructComposite make_uvec2_bad( + TransformationCompositeConstruct make_uvec2_bad( 86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 200), 206); ASSERT_TRUE(make_uvec2.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_uvec2_bad.IsApplicable(context.get(), fact_manager)); @@ -1009,10 +1009,10 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 18, 206, {0})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 38, 206, {1})); - TransformationConstructComposite make_uvec3( + TransformationCompositeConstruct make_uvec3( 59, {14, 18, 136}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207); // Bad because 1300 is not an id - TransformationConstructComposite make_uvec3_bad( + TransformationCompositeConstruct make_uvec3_bad( 59, {14, 18, 1300}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207); ASSERT_TRUE(make_uvec3.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_uvec3_bad.IsApplicable(context.get(), fact_manager)); @@ -1022,11 +1022,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 18, 207, {1})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 136, 207, {2})); - TransformationConstructComposite make_uvec4( + TransformationCompositeConstruct make_uvec4( 131, {14, 18, 136, 136}, MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208); // Bad because 86 is the wrong type. - TransformationConstructComposite make_uvec4_bad( + TransformationCompositeConstruct make_uvec4_bad( 86, {14, 18, 136, 136}, MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208); ASSERT_TRUE(make_uvec4.IsApplicable(context.get(), fact_manager)); @@ -1038,7 +1038,7 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 136, 208, {2})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 136, 208, {3})); - TransformationConstructComposite make_bvec2( + TransformationCompositeConstruct make_bvec2( 102, { 111, @@ -1046,7 +1046,7 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { }, MakeInstructionDescriptor(75, SpvOpAccessChain, 0), 209); // Bad because 0 is not a valid base instruction id - TransformationConstructComposite make_bvec2_bad( + TransformationCompositeConstruct make_bvec2_bad( 102, { 111, @@ -1060,10 +1060,10 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 111, 209, {0})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 41, 209, {1})); - TransformationConstructComposite make_bvec3( + TransformationCompositeConstruct make_bvec3( 93, {108, 73}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210); // Bad because there are too many components for a bvec3 - TransformationConstructComposite make_bvec3_bad( + TransformationCompositeConstruct make_bvec3_bad( 93, {108, 108}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210); ASSERT_TRUE(make_bvec3.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_bvec3_bad.IsApplicable(context.get(), fact_manager)); @@ -1072,10 +1072,10 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) { ASSERT_TRUE(SynonymFactHolds(fact_manager, 108, 210, {0})); ASSERT_TRUE(SynonymFactHolds(fact_manager, 73, 210, {2})); - TransformationConstructComposite make_bvec4( + TransformationCompositeConstruct make_bvec4( 70, {108, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211); // Bad because 21 is a type, not a result id - TransformationConstructComposite make_bvec4_bad( + TransformationCompositeConstruct make_bvec4_bad( 70, {21, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211); ASSERT_TRUE(make_bvec4.IsApplicable(context.get(), fact_manager)); ASSERT_FALSE(make_bvec4_bad.IsApplicable(context.get(), fact_manager)); diff --git a/3rdparty/spirv-tools/test/fuzz/transformation_composite_extract_test.cpp b/3rdparty/spirv-tools/test/fuzz/transformation_composite_extract_test.cpp new file mode 100644 index 000000000..30d912c0f --- /dev/null +++ b/3rdparty/spirv-tools/test/fuzz/transformation_composite_extract_test.cpp @@ -0,0 +1,393 @@ +// Copyright (c) 2019 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 "source/fuzz/transformation_composite_extract.h" +#include "source/fuzz/instruction_descriptor.h" +#include "test/fuzz/fuzz_test_util.h" + +namespace spvtools { +namespace fuzz { +namespace { + +bool IsSynonymous(const FactManager& fact_manager, uint32_t id, + uint32_t composite_id, std::vector&& indices) { + protobufs::DataDescriptor data_descriptor = + MakeDataDescriptor(composite_id, std::move(indices), 1); + return fact_manager.GetSynonymsForId(id).count(&data_descriptor) == 1; +} + +TEST(TransformationCompositeExtractTest, BasicTest) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "a" + OpName %10 "b" + OpName %17 "FunnyPoint" + OpMemberName %17 0 "x" + OpMemberName %17 1 "y" + OpMemberName %17 2 "z" + OpName %19 "p" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %12 = OpTypeBool + %16 = OpTypeFloat 32 + %17 = OpTypeStruct %16 %16 %6 + %81 = OpTypeStruct %17 %16 + %18 = OpTypePointer Function %17 + %20 = OpConstant %6 0 + %23 = OpTypePointer Function %16 + %26 = OpConstant %6 1 + %30 = OpConstant %6 2 + %80 = OpUndef %16 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %19 = OpVariable %18 Function + %9 = OpLoad %6 %8 + %11 = OpLoad %6 %10 + %100 = OpCompositeConstruct %17 %80 %80 %26 + %104 = OpCompositeConstruct %81 %100 %80 + %13 = OpIEqual %12 %9 %11 + OpSelectionMerge %15 None + OpBranchConditional %13 %14 %25 + %14 = OpLabel + %21 = OpLoad %6 %8 + %22 = OpConvertSToF %16 %21 + %101 = OpCompositeConstruct %17 %22 %80 %30 + %24 = OpAccessChain %23 %19 %20 + OpStore %24 %22 + OpBranch %15 + %25 = OpLabel + %27 = OpLoad %6 %10 + %28 = OpConvertSToF %16 %27 + %102 = OpCompositeConstruct %17 %80 %28 %27 + %29 = OpAccessChain %23 %19 %26 + OpStore %29 %28 + OpBranch %15 + %15 = OpLabel + %31 = OpAccessChain %23 %19 %20 + %32 = OpLoad %16 %31 + %33 = OpAccessChain %23 %19 %26 + %34 = OpLoad %16 %33 + %103 = OpCompositeConstruct %17 %34 %32 %9 + %35 = OpFAdd %16 %32 %34 + %36 = OpConvertFToS %6 %35 + %37 = OpAccessChain %7 %19 %30 + OpStore %37 %36 + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Instruction does not exist. + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(36, SpvOpIAdd, 0), 200, 101, {0}) + .IsApplicable(context.get(), fact_manager)); + + // Id for composite is not a composite. + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(36, SpvOpIAdd, 0), 200, 27, {}) + .IsApplicable(context.get(), fact_manager)); + + // Composite does not dominate instruction being inserted before. + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 200, 101, {0}) + .IsApplicable(context.get(), fact_manager)); + + // Too many indices for extraction from struct composite. + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(24, SpvOpAccessChain, 0), 200, 101, {0, 0}) + .IsApplicable(context.get(), fact_manager)); + + // Too many indices for extraction from struct composite. + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 0, 0}) + .IsApplicable(context.get(), fact_manager)); + + // Out of bounds index for extraction from struct composite. + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 3}) + .IsApplicable(context.get(), fact_manager)); + + // Result id already used. + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(35, SpvOpFAdd, 0), 80, 103, {0}) + .IsApplicable(context.get(), fact_manager)); + + TransformationCompositeExtract transformation_1( + MakeInstructionDescriptor(36, SpvOpConvertFToS, 0), 201, 100, {2}); + ASSERT_TRUE(transformation_1.IsApplicable(context.get(), fact_manager)); + transformation_1.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + TransformationCompositeExtract transformation_2( + MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 202, 104, {0, 2}); + ASSERT_TRUE(transformation_2.IsApplicable(context.get(), fact_manager)); + transformation_2.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + TransformationCompositeExtract transformation_3( + MakeInstructionDescriptor(29, SpvOpAccessChain, 0), 203, 104, {0}); + ASSERT_TRUE(transformation_3.IsApplicable(context.get(), fact_manager)); + transformation_3.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + TransformationCompositeExtract transformation_4( + MakeInstructionDescriptor(24, SpvOpStore, 0), 204, 101, {0}); + ASSERT_TRUE(transformation_4.IsApplicable(context.get(), fact_manager)); + transformation_4.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + TransformationCompositeExtract transformation_5( + MakeInstructionDescriptor(29, SpvOpBranch, 0), 205, 102, {2}); + ASSERT_TRUE(transformation_5.IsApplicable(context.get(), fact_manager)); + transformation_5.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + TransformationCompositeExtract transformation_6( + MakeInstructionDescriptor(37, SpvOpReturn, 0), 206, 103, {1}); + ASSERT_TRUE(transformation_6.IsApplicable(context.get(), fact_manager)); + transformation_6.Apply(context.get(), &fact_manager); + ASSERT_TRUE(IsValid(env, context.get())); + + ASSERT_TRUE(IsSynonymous(fact_manager, 201, 100, {2})); + ASSERT_TRUE(IsSynonymous(fact_manager, 202, 104, {0, 2})); + ASSERT_TRUE(IsSynonymous(fact_manager, 203, 104, {0})); + ASSERT_TRUE(IsSynonymous(fact_manager, 204, 101, {0})); + ASSERT_TRUE(IsSynonymous(fact_manager, 205, 102, {2})); + ASSERT_TRUE(IsSynonymous(fact_manager, 206, 103, {1})); + + std::string after_transformation = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "a" + OpName %10 "b" + OpName %17 "FunnyPoint" + OpMemberName %17 0 "x" + OpMemberName %17 1 "y" + OpMemberName %17 2 "z" + OpName %19 "p" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeInt 32 1 + %7 = OpTypePointer Function %6 + %12 = OpTypeBool + %16 = OpTypeFloat 32 + %17 = OpTypeStruct %16 %16 %6 + %81 = OpTypeStruct %17 %16 + %18 = OpTypePointer Function %17 + %20 = OpConstant %6 0 + %23 = OpTypePointer Function %16 + %26 = OpConstant %6 1 + %30 = OpConstant %6 2 + %80 = OpUndef %16 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %8 = OpVariable %7 Function + %10 = OpVariable %7 Function + %19 = OpVariable %18 Function + %9 = OpLoad %6 %8 + %11 = OpLoad %6 %10 + %100 = OpCompositeConstruct %17 %80 %80 %26 + %104 = OpCompositeConstruct %81 %100 %80 + %13 = OpIEqual %12 %9 %11 + OpSelectionMerge %15 None + OpBranchConditional %13 %14 %25 + %14 = OpLabel + %21 = OpLoad %6 %8 + %22 = OpConvertSToF %16 %21 + %101 = OpCompositeConstruct %17 %22 %80 %30 + %24 = OpAccessChain %23 %19 %20 + %204 = OpCompositeExtract %16 %101 0 + OpStore %24 %22 + OpBranch %15 + %25 = OpLabel + %27 = OpLoad %6 %10 + %28 = OpConvertSToF %16 %27 + %102 = OpCompositeConstruct %17 %80 %28 %27 + %203 = OpCompositeExtract %17 %104 0 + %29 = OpAccessChain %23 %19 %26 + OpStore %29 %28 + %205 = OpCompositeExtract %6 %102 2 + OpBranch %15 + %15 = OpLabel + %31 = OpAccessChain %23 %19 %20 + %32 = OpLoad %16 %31 + %33 = OpAccessChain %23 %19 %26 + %34 = OpLoad %16 %33 + %103 = OpCompositeConstruct %17 %34 %32 %9 + %35 = OpFAdd %16 %32 %34 + %201 = OpCompositeExtract %6 %100 2 + %36 = OpConvertFToS %6 %35 + %202 = OpCompositeExtract %6 %104 0 2 + %37 = OpAccessChain %7 %19 %30 + OpStore %37 %36 + %206 = OpCompositeExtract %16 %103 1 + OpReturn + OpFunctionEnd + )"; + ASSERT_TRUE(IsEqual(env, after_transformation, context.get())); +} + +TEST(TransformationCompositeExtractTest, IllegalInsertionPoints) { + std::string shader = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %51 %27 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %25 "buf" + OpMemberName %25 0 "value" + OpName %27 "" + OpName %51 "color" + OpMemberDecorate %25 0 Offset 0 + OpDecorate %25 Block + OpDecorate %27 DescriptorSet 0 + OpDecorate %27 Binding 0 + OpDecorate %51 Location 0 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 4 + %10 = OpConstant %6 0.300000012 + %11 = OpConstant %6 0.400000006 + %12 = OpConstant %6 0.5 + %13 = OpConstant %6 1 + %14 = OpConstantComposite %7 %10 %11 %12 %13 + %15 = OpTypeInt 32 1 + %18 = OpConstant %15 0 + %25 = OpTypeStruct %6 + %26 = OpTypePointer Uniform %25 + %27 = OpVariable %26 Uniform + %28 = OpTypePointer Uniform %6 + %32 = OpTypeBool + %103 = OpConstantTrue %32 + %34 = OpConstant %6 0.100000001 + %48 = OpConstant %15 1 + %50 = OpTypePointer Output %7 + %51 = OpVariable %50 Output + %100 = OpTypePointer Function %6 + %4 = OpFunction %2 None %3 + %5 = OpLabel + %101 = OpVariable %100 Function + %102 = OpVariable %100 Function + OpBranch %19 + %19 = OpLabel + %60 = OpPhi %7 %14 %5 %58 %20 + %59 = OpPhi %15 %18 %5 %49 %20 + %29 = OpAccessChain %28 %27 %18 + %30 = OpLoad %6 %29 + %31 = OpConvertFToS %15 %30 + %33 = OpSLessThan %32 %59 %31 + OpLoopMerge %21 %20 None + OpBranchConditional %33 %20 %21 + %20 = OpLabel + %39 = OpCompositeExtract %6 %60 0 + %40 = OpFAdd %6 %39 %34 + %55 = OpCompositeInsert %7 %40 %60 0 + %44 = OpCompositeExtract %6 %60 1 + %45 = OpFSub %6 %44 %34 + %58 = OpCompositeInsert %7 %45 %55 1 + %49 = OpIAdd %15 %59 %48 + OpBranch %19 + %21 = OpLabel + OpStore %51 %60 + OpSelectionMerge %105 None + OpBranchConditional %103 %104 %105 + %104 = OpLabel + OpBranch %105 + %105 = OpLabel + OpReturn + OpFunctionEnd + )"; + + const auto env = SPV_ENV_UNIVERSAL_1_4; + const auto consumer = nullptr; + const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); + ASSERT_TRUE(IsValid(env, context.get())); + + FactManager fact_manager; + + // Cannot insert before the OpVariables of a function. + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(101, SpvOpVariable, 0), 200, 14, {0}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(101, SpvOpVariable, 1), 200, 14, {1}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE( + TransformationCompositeExtract( + MakeInstructionDescriptor(102, SpvOpVariable, 0), 200, 14, {1}) + .IsApplicable(context.get(), fact_manager)); + // OK to insert right after the OpVariables. + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(102, SpvOpBranch, 1), 200, 14, {1}) + .IsApplicable(context.get(), fact_manager)); + + // Cannot insert before the OpPhis of a block. + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(60, SpvOpPhi, 0), 200, 14, {2}) + .IsApplicable(context.get(), fact_manager)); + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(59, SpvOpPhi, 0), 200, 14, {3}) + .IsApplicable(context.get(), fact_manager)); + // OK to insert after the OpPhis. + ASSERT_TRUE( + TransformationCompositeExtract( + MakeInstructionDescriptor(59, SpvOpAccessChain, 0), 200, 14, {3}) + .IsApplicable(context.get(), fact_manager)); + + // Cannot insert before OpLoopMerge + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(33, SpvOpBranchConditional, 0), + 200, 14, {3}) + .IsApplicable(context.get(), fact_manager)); + + // Cannot insert before OpSelectionMerge + ASSERT_FALSE(TransformationCompositeExtract( + MakeInstructionDescriptor(21, SpvOpBranchConditional, 0), + 200, 14, {2}) + .IsApplicable(context.get(), fact_manager)); +} + +} // namespace +} // namespace fuzz +} // namespace spvtools diff --git a/3rdparty/spirv-tools/test/opt/fold_test.cpp b/3rdparty/spirv-tools/test/opt/fold_test.cpp index cb81f1c4a..a6e75d8b1 100644 --- a/3rdparty/spirv-tools/test/opt/fold_test.cpp +++ b/3rdparty/spirv-tools/test/opt/fold_test.cpp @@ -5763,6 +5763,132 @@ INSTANTIATE_TEST_SUITE_P(MergeAddTest, MatchingInstructionFoldingTest, 4, true) )); +INSTANTIATE_TEST_SUITE_P(MergeGenericAddSub, MatchingInstructionFoldingTest, +::testing::Values( + // Test case 0: merge of add of sub + // (a - b) + b => a + InstructionFoldingCase( + Header() + + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + + "; CHECK: %6 = OpCopyObject [[float]] %3\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var0 = OpVariable %_ptr_float Function\n" + + "%var1 = OpVariable %_ptr_float Function\n" + + "%3 = OpLoad %float %var0\n" + + "%4 = OpLoad %float %var1\n" + + "%5 = OpFSub %float %3 %4\n" + + "%6 = OpFAdd %float %5 %4\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 6, true), + // Test case 1: merge of add of sub + // b + (a - b) => a + InstructionFoldingCase( + Header() + + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + + "; CHECK: %6 = OpCopyObject [[float]] %3\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var0 = OpVariable %_ptr_float Function\n" + + "%var1 = OpVariable %_ptr_float Function\n" + + "%3 = OpLoad %float %var0\n" + + "%4 = OpLoad %float %var1\n" + + "%5 = OpFSub %float %3 %4\n" + + "%6 = OpFAdd %float %4 %5\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 6, true) +)); + +INSTANTIATE_TEST_SUITE_P(FactorAddMul, MatchingInstructionFoldingTest, +::testing::Values( + // Test case 0: factor of add of muls + // (a * b) + (a * c) => a * (b + c) + InstructionFoldingCase( + Header() + + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + + "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" + + "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var0 = OpVariable %_ptr_float Function\n" + + "%var1 = OpVariable %_ptr_float Function\n" + + "%var2 = OpVariable %_ptr_float Function\n" + + "%4 = OpLoad %float %var0\n" + + "%5 = OpLoad %float %var1\n" + + "%6 = OpLoad %float %var2\n" + + "%7 = OpFMul %float %6 %4\n" + + "%8 = OpFMul %float %6 %5\n" + + "%9 = OpFAdd %float %7 %8\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true), + // Test case 1: factor of add of muls + // (b * a) + (a * c) => a * (b + c) + InstructionFoldingCase( + Header() + + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + + "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" + + "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var0 = OpVariable %_ptr_float Function\n" + + "%var1 = OpVariable %_ptr_float Function\n" + + "%var2 = OpVariable %_ptr_float Function\n" + + "%4 = OpLoad %float %var0\n" + + "%5 = OpLoad %float %var1\n" + + "%6 = OpLoad %float %var2\n" + + "%7 = OpFMul %float %4 %6\n" + + "%8 = OpFMul %float %6 %5\n" + + "%9 = OpFAdd %float %7 %8\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true), + // Test case 2: factor of add of muls + // (a * b) + (c * a) => a * (b + c) + InstructionFoldingCase( + Header() + + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + + "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" + + "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var0 = OpVariable %_ptr_float Function\n" + + "%var1 = OpVariable %_ptr_float Function\n" + + "%var2 = OpVariable %_ptr_float Function\n" + + "%4 = OpLoad %float %var0\n" + + "%5 = OpLoad %float %var1\n" + + "%6 = OpLoad %float %var2\n" + + "%7 = OpFMul %float %6 %4\n" + + "%8 = OpFMul %float %5 %6\n" + + "%9 = OpFAdd %float %7 %8\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true), + // Test case 3: factor of add of muls + // (b * a) + (c * a) => a * (b + c) + InstructionFoldingCase( + Header() + + "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" + + "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" + + "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%var0 = OpVariable %_ptr_float Function\n" + + "%var1 = OpVariable %_ptr_float Function\n" + + "%var2 = OpVariable %_ptr_float Function\n" + + "%4 = OpLoad %float %var0\n" + + "%5 = OpLoad %float %var1\n" + + "%6 = OpLoad %float %var2\n" + + "%7 = OpFMul %float %4 %6\n" + + "%8 = OpFMul %float %5 %6\n" + + "%9 = OpFAdd %float %7 %8\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true) +)); + INSTANTIATE_TEST_SUITE_P(MergeSubTest, MatchingInstructionFoldingTest, ::testing::Values( // Test case 0: merge sub of negate diff --git a/3rdparty/spirv-tools/test/opt/simplification_test.cpp b/3rdparty/spirv-tools/test/opt/simplification_test.cpp index e1f10a561..7a9696eab 100644 --- a/3rdparty/spirv-tools/test/opt/simplification_test.cpp +++ b/3rdparty/spirv-tools/test/opt/simplification_test.cpp @@ -71,6 +71,41 @@ TEST_F(SimplificationTest, StraightLineTest) { SinglePassRunAndMatch(text, false); } +TEST_F(SimplificationTest, NewInstructionTest) { + // Testing that new instructions are simplified. Specifically, + // that the new add instruction generated by FactorAddMul is + // further simplified by MergeGenericAddSub. + const std::string text = R"(OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 430 + OpName %main "main" + %void = OpTypeVoid + %4 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %_ptr_int = OpTypePointer Function %int +; CHECK: [[mul:%[a-zA-Z_\d]+]] = OpIMul %int %13 %11 + %main = OpFunction %void None %4 + %7 = OpLabel + %8 = OpVariable %_ptr_int Function + %9 = OpVariable %_ptr_int Function + %10 = OpVariable %_ptr_int Function + %11 = OpLoad %int %8 + %12 = OpLoad %int %9 + %13 = OpLoad %int %10 + %14 = OpISub %int %11 %12 + %15 = OpIMul %int %13 %11 + %16 = OpIMul %int %13 %12 + %17 = OpIAdd %int %14 %15 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + TEST_F(SimplificationTest, AcrossBasicBlocks) { // Testing that folding rules are combined across basic blocks. const std::string text = R"(OpCapability Shader diff --git a/3rdparty/spirv-tools/utils/vscode/.gitignore b/3rdparty/spirv-tools/utils/vscode/.gitignore new file mode 100644 index 000000000..e934adfd1 --- /dev/null +++ b/3rdparty/spirv-tools/utils/vscode/.gitignore @@ -0,0 +1 @@ +cache/ diff --git a/3rdparty/spirv-tools/utils/vscode/README.md b/3rdparty/spirv-tools/utils/vscode/README.md new file mode 100644 index 000000000..afbb24661 --- /dev/null +++ b/3rdparty/spirv-tools/utils/vscode/README.md @@ -0,0 +1,7 @@ +# Visual Studio Code extension for SPIR-V disassembly files + +This directory holds a Visual Studio Code extension adding syntax highlighting for SPIR-V disassembly files (.spirv) + +## Installing (macOS / Linux) + +Simply run `install.sh` diff --git a/3rdparty/spirv-tools/utils/vscode/install.sh b/3rdparty/spirv-tools/utils/vscode/install.sh new file mode 100755 index 000000000..354baf0f8 --- /dev/null +++ b/3rdparty/spirv-tools/utils/vscode/install.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Copyright (c) 2019 Google Inc. +# +# 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. + +set -e # Fail on any error. + +EXT_PATH=~/.vscode/extensions/google.spirvls-0.0.1 +ROOT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +go run ${ROOT_PATH}/src/tools/gen-grammar.go --cache ${ROOT_PATH}/cache --template ${ROOT_PATH}/spirv.json.tmpl --out ${ROOT_PATH}/spirv.json + +mkdir -p ${EXT_PATH} +cp ${ROOT_PATH}/package.json ${EXT_PATH} +cp ${ROOT_PATH}/spirv.configuration.json ${EXT_PATH} +cp ${ROOT_PATH}/spirv.json ${EXT_PATH} diff --git a/3rdparty/spirv-tools/utils/vscode/package.json b/3rdparty/spirv-tools/utils/vscode/package.json new file mode 100644 index 000000000..ccca687cc --- /dev/null +++ b/3rdparty/spirv-tools/utils/vscode/package.json @@ -0,0 +1,33 @@ +{ + "name": "spirv", + "description": "Language support for SPIR-V disassembly files", + "author": "Google", + "license": "Apache-2.0", + "version": "0.0.1", + "private": true, + "publisher": "Google", + "engines": { + "vscode": "^0.10.10" + }, + "categories": [ + "Programming Languages" + ], + "contributes": { + "languages": [ + { + "id": "spirv", + "configuration": "spirv.configuration.json", + "extensions": [ + "spirv" + ] + } + ], + "grammars": [ + { + "language": "spirv", + "scopeName": "source.spirv", + "path": "spirv.json" + } + ] + } +} diff --git a/3rdparty/spirv-tools/utils/vscode/spirv.configuration.json b/3rdparty/spirv-tools/utils/vscode/spirv.configuration.json new file mode 100644 index 000000000..652330f94 --- /dev/null +++ b/3rdparty/spirv-tools/utils/vscode/spirv.configuration.json @@ -0,0 +1,6 @@ +{ + "comments": { + "lineComment": ";" + }, + "wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)" +} diff --git a/3rdparty/spirv-tools/utils/vscode/spirv.json b/3rdparty/spirv-tools/utils/vscode/spirv.json new file mode 100644 index 000000000..30573d455 --- /dev/null +++ b/3rdparty/spirv-tools/utils/vscode/spirv.json @@ -0,0 +1,212 @@ +{ + "scopeName": "source.spirv", + "name": "SPIR-V", + "comment": "Generated by gen-grammar.go --template=../../spirv.json.tmpl --out=../../spirv.json. Do not modify this file directly.", + "patterns": [ + { "include": "#BitEnum_ImageOperands" }, + { "include": "#BitEnum_FPFastMathMode" }, + { "include": "#BitEnum_SelectionControl" }, + { "include": "#BitEnum_LoopControl" }, + { "include": "#BitEnum_FunctionControl" }, + { "include": "#BitEnum_MemorySemantics" }, + { "include": "#BitEnum_MemoryAccess" }, + { "include": "#BitEnum_KernelProfilingInfo" }, + { "include": "#ValueEnum_SourceLanguage" }, + { "include": "#ValueEnum_ExecutionModel" }, + { "include": "#ValueEnum_AddressingModel" }, + { "include": "#ValueEnum_MemoryModel" }, + { "include": "#ValueEnum_ExecutionMode" }, + { "include": "#ValueEnum_StorageClass" }, + { "include": "#ValueEnum_Dim" }, + { "include": "#ValueEnum_SamplerAddressingMode" }, + { "include": "#ValueEnum_SamplerFilterMode" }, + { "include": "#ValueEnum_ImageFormat" }, + { "include": "#ValueEnum_ImageChannelOrder" }, + { "include": "#ValueEnum_ImageChannelDataType" }, + { "include": "#ValueEnum_FPRoundingMode" }, + { "include": "#ValueEnum_LinkageType" }, + { "include": "#ValueEnum_AccessQualifier" }, + { "include": "#ValueEnum_FunctionParameterAttribute" }, + { "include": "#ValueEnum_Decoration" }, + { "include": "#ValueEnum_BuiltIn" }, + { "include": "#ValueEnum_Scope" }, + { "include": "#ValueEnum_GroupOperation" }, + { "include": "#ValueEnum_KernelEnqueueFlags" }, + { "include": "#ValueEnum_Capability" }, + { "include": "#opcode" }, + { "include": "#identifier" }, + { "include": "#number" }, + { "include": "#string" }, + { "include": "#comment" }, + { "include": "#operator" } + ], + "repository": { + "BitEnum_ImageOperands": { + "match": "\\b(None|Bias|Lod|Grad|ConstOffset|Offset|ConstOffsets|Sample|MinLod|MakeTexelAvailable|MakeTexelAvailableKHR|MakeTexelVisible|MakeTexelVisibleKHR|NonPrivateTexel|NonPrivateTexelKHR|VolatileTexel|VolatileTexelKHR|SignExtend|ZeroExtend)\\b", + "name": "keyword.spirv" + }, + "BitEnum_FPFastMathMode": { + "match": "\\b(None|NotNaN|NotInf|NSZ|AllowRecip|Fast)\\b", + "name": "keyword.spirv" + }, + "BitEnum_SelectionControl": { + "match": "\\b(None|Flatten|DontFlatten)\\b", + "name": "keyword.spirv" + }, + "BitEnum_LoopControl": { + "match": "\\b(None|Unroll|DontUnroll|DependencyInfinite|DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount)\\b", + "name": "keyword.spirv" + }, + "BitEnum_FunctionControl": { + "match": "\\b(None|Inline|DontInline|Pure|Const)\\b", + "name": "keyword.spirv" + }, + "BitEnum_MemorySemantics": { + "match": "\\b(Relaxed|None|Acquire|Release|AcquireRelease|SequentiallyConsistent|UniformMemory|SubgroupMemory|WorkgroupMemory|CrossWorkgroupMemory|AtomicCounterMemory|ImageMemory|OutputMemory|OutputMemoryKHR|MakeAvailable|MakeAvailableKHR|MakeVisible|MakeVisibleKHR|Volatile)\\b", + "name": "keyword.spirv" + }, + "BitEnum_MemoryAccess": { + "match": "\\b(None|Volatile|Aligned|Nontemporal|MakePointerAvailable|MakePointerAvailableKHR|MakePointerVisible|MakePointerVisibleKHR|NonPrivatePointer|NonPrivatePointerKHR)\\b", + "name": "keyword.spirv" + }, + "BitEnum_KernelProfilingInfo": { + "match": "\\b(None|CmdExecTime)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_SourceLanguage": { + "match": "\\b(Unknown|ESSL|GLSL|OpenCL_C|OpenCL_CPP|HLSL)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_ExecutionModel": { + "match": "\\b(Vertex|TessellationControl|TessellationEvaluation|Geometry|Fragment|GLCompute|Kernel|TaskNV|MeshNV|RayGenerationNV|IntersectionNV|AnyHitNV|ClosestHitNV|MissNV|CallableNV)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_AddressingModel": { + "match": "\\b(Logical|Physical32|Physical64|PhysicalStorageBuffer64|PhysicalStorageBuffer64EXT)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_MemoryModel": { + "match": "\\b(Simple|GLSL450|OpenCL|Vulkan|VulkanKHR)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_ExecutionMode": { + "match": "\\b(Invocations|SpacingEqual|SpacingFractionalEven|SpacingFractionalOdd|VertexOrderCw|VertexOrderCcw|PixelCenterInteger|OriginUpperLeft|OriginLowerLeft|EarlyFragmentTests|PointMode|Xfb|DepthReplacing|DepthGreater|DepthLess|DepthUnchanged|LocalSize|LocalSizeHint|InputPoints|InputLines|InputLinesAdjacency|Triangles|InputTrianglesAdjacency|Quads|Isolines|OutputVertices|OutputPoints|OutputLineStrip|OutputTriangleStrip|VecTypeHint|ContractionOff|Initializer|Finalizer|SubgroupSize|SubgroupsPerWorkgroup|SubgroupsPerWorkgroupId|LocalSizeId|LocalSizeHintId|PostDepthCoverage|DenormPreserve|DenormFlushToZero|SignedZeroInfNanPreserve|RoundingModeRTE|RoundingModeRTZ|StencilRefReplacingEXT|OutputLinesNV|OutputPrimitivesNV|DerivativeGroupQuadsNV|DerivativeGroupLinearNV|OutputTrianglesNV|PixelInterlockOrderedEXT|PixelInterlockUnorderedEXT|SampleInterlockOrderedEXT|SampleInterlockUnorderedEXT|ShadingRateInterlockOrderedEXT|ShadingRateInterlockUnorderedEXT)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_StorageClass": { + "match": "\\b(UniformConstant|Input|Uniform|Output|Workgroup|CrossWorkgroup|Private|Function|Generic|PushConstant|AtomicCounter|Image|StorageBuffer|CallableDataNV|IncomingCallableDataNV|RayPayloadNV|HitAttributeNV|IncomingRayPayloadNV|ShaderRecordBufferNV|PhysicalStorageBuffer|PhysicalStorageBufferEXT)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_Dim": { + "match": "\\b(1D|2D|3D|Cube|Rect|Buffer|SubpassData)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_SamplerAddressingMode": { + "match": "\\b(None|ClampToEdge|Clamp|Repeat|RepeatMirrored)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_SamplerFilterMode": { + "match": "\\b(Nearest|Linear)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_ImageFormat": { + "match": "\\b(Unknown|Rgba32f|Rgba16f|R32f|Rgba8|Rgba8Snorm|Rg32f|Rg16f|R11fG11fB10f|R16f|Rgba16|Rgb10A2|Rg16|Rg8|R16|R8|Rgba16Snorm|Rg16Snorm|Rg8Snorm|R16Snorm|R8Snorm|Rgba32i|Rgba16i|Rgba8i|R32i|Rg32i|Rg16i|Rg8i|R16i|R8i|Rgba32ui|Rgba16ui|Rgba8ui|R32ui|Rgb10a2ui|Rg32ui|Rg16ui|Rg8ui|R16ui|R8ui)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_ImageChannelOrder": { + "match": "\\b(R|A|RG|RA|RGB|RGBA|BGRA|ARGB|Intensity|Luminance|Rx|RGx|RGBx|Depth|DepthStencil|sRGB|sRGBx|sRGBA|sBGRA|ABGR)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_ImageChannelDataType": { + "match": "\\b(SnormInt8|SnormInt16|UnormInt8|UnormInt16|UnormShort565|UnormShort555|UnormInt101010|SignedInt8|SignedInt16|SignedInt32|UnsignedInt8|UnsignedInt16|UnsignedInt32|HalfFloat|Float|UnormInt24|UnormInt101010_2)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_FPRoundingMode": { + "match": "\\b(RTE|RTZ|RTP|RTN)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_LinkageType": { + "match": "\\b(Export|Import)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_AccessQualifier": { + "match": "\\b(ReadOnly|WriteOnly|ReadWrite)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_FunctionParameterAttribute": { + "match": "\\b(Zext|Sext|ByVal|Sret|NoAlias|NoCapture|NoWrite|NoReadWrite)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_Decoration": { + "match": "\\b(RelaxedPrecision|SpecId|Block|BufferBlock|RowMajor|ColMajor|ArrayStride|MatrixStride|GLSLShared|GLSLPacked|CPacked|BuiltIn|NoPerspective|Flat|Patch|Centroid|Sample|Invariant|Restrict|Aliased|Volatile|Constant|Coherent|NonWritable|NonReadable|Uniform|UniformId|SaturatedConversion|Stream|Location|Component|Index|Binding|DescriptorSet|Offset|XfbBuffer|XfbStride|FuncParamAttr|FPRoundingMode|FPFastMathMode|LinkageAttributes|NoContraction|InputAttachmentIndex|Alignment|MaxByteOffset|AlignmentId|MaxByteOffsetId|NoSignedWrap|NoUnsignedWrap|ExplicitInterpAMD|OverrideCoverageNV|PassthroughNV|ViewportRelativeNV|SecondaryViewportRelativeNV|PerPrimitiveNV|PerViewNV|PerTaskNV|PerVertexNV|NonUniform|NonUniformEXT|RestrictPointer|RestrictPointerEXT|AliasedPointer|AliasedPointerEXT|CounterBuffer|HlslCounterBufferGOOGLE|UserSemantic|HlslSemanticGOOGLE|UserTypeGOOGLE)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_BuiltIn": { + "match": "\\b(Position|PointSize|ClipDistance|CullDistance|VertexId|InstanceId|PrimitiveId|InvocationId|Layer|ViewportIndex|TessLevelOuter|TessLevelInner|TessCoord|PatchVertices|FragCoord|PointCoord|FrontFacing|SampleId|SamplePosition|SampleMask|FragDepth|HelperInvocation|NumWorkgroups|WorkgroupSize|WorkgroupId|LocalInvocationId|GlobalInvocationId|LocalInvocationIndex|WorkDim|GlobalSize|EnqueuedWorkgroupSize|GlobalOffset|GlobalLinearId|SubgroupSize|SubgroupMaxSize|NumSubgroups|NumEnqueuedSubgroups|SubgroupId|SubgroupLocalInvocationId|VertexIndex|InstanceIndex|SubgroupEqMask|SubgroupGeMask|SubgroupGtMask|SubgroupLeMask|SubgroupLtMask|SubgroupEqMaskKHR|SubgroupGeMaskKHR|SubgroupGtMaskKHR|SubgroupLeMaskKHR|SubgroupLtMaskKHR|BaseVertex|BaseInstance|DrawIndex|DeviceIndex|ViewIndex|BaryCoordNoPerspAMD|BaryCoordNoPerspCentroidAMD|BaryCoordNoPerspSampleAMD|BaryCoordSmoothAMD|BaryCoordSmoothCentroidAMD|BaryCoordSmoothSampleAMD|BaryCoordPullModelAMD|FragStencilRefEXT|ViewportMaskNV|SecondaryPositionNV|SecondaryViewportMaskNV|PositionPerViewNV|ViewportMaskPerViewNV|FullyCoveredEXT|TaskCountNV|PrimitiveCountNV|PrimitiveIndicesNV|ClipDistancePerViewNV|CullDistancePerViewNV|LayerPerViewNV|MeshViewCountNV|MeshViewIndicesNV|BaryCoordNV|BaryCoordNoPerspNV|FragSizeEXT|FragmentSizeNV|FragInvocationCountEXT|InvocationsPerPixelNV|LaunchIdNV|LaunchSizeNV|WorldRayOriginNV|WorldRayDirectionNV|ObjectRayOriginNV|ObjectRayDirectionNV|RayTminNV|RayTmaxNV|InstanceCustomIndexNV|ObjectToWorldNV|WorldToObjectNV|HitTNV|HitKindNV|IncomingRayFlagsNV|WarpsPerSMNV|SMCountNV|WarpIDNV|SMIDNV)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_Scope": { + "match": "\\b(CrossDevice|Device|Workgroup|Subgroup|Invocation|QueueFamily|QueueFamilyKHR)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_GroupOperation": { + "match": "\\b(Reduce|InclusiveScan|ExclusiveScan|ClusteredReduce|PartitionedReduceNV|PartitionedInclusiveScanNV|PartitionedExclusiveScanNV)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_KernelEnqueueFlags": { + "match": "\\b(NoWait|WaitKernel|WaitWorkGroup)\\b", + "name": "keyword.spirv" + }, + "ValueEnum_Capability": { + "match": "\\b(Matrix|Shader|Geometry|Tessellation|Addresses|Linkage|Kernel|Vector16|Float16Buffer|Float16|Float64|Int64|Int64Atomics|ImageBasic|ImageReadWrite|ImageMipmap|Pipes|Groups|DeviceEnqueue|LiteralSampler|AtomicStorage|Int16|TessellationPointSize|GeometryPointSize|ImageGatherExtended|StorageImageMultisample|UniformBufferArrayDynamicIndexing|SampledImageArrayDynamicIndexing|StorageBufferArrayDynamicIndexing|StorageImageArrayDynamicIndexing|ClipDistance|CullDistance|ImageCubeArray|SampleRateShading|ImageRect|SampledRect|GenericPointer|Int8|InputAttachment|SparseResidency|MinLod|Sampled1D|Image1D|SampledCubeArray|SampledBuffer|ImageBuffer|ImageMSArray|StorageImageExtendedFormats|ImageQuery|DerivativeControl|InterpolationFunction|TransformFeedback|GeometryStreams|StorageImageReadWithoutFormat|StorageImageWriteWithoutFormat|MultiViewport|SubgroupDispatch|NamedBarrier|PipeStorage|GroupNonUniform|GroupNonUniformVote|GroupNonUniformArithmetic|GroupNonUniformBallot|GroupNonUniformShuffle|GroupNonUniformShuffleRelative|GroupNonUniformClustered|GroupNonUniformQuad|ShaderLayer|ShaderViewportIndex|SubgroupBallotKHR|DrawParameters|SubgroupVoteKHR|StorageBuffer16BitAccess|StorageUniformBufferBlock16|UniformAndStorageBuffer16BitAccess|StorageUniform16|StoragePushConstant16|StorageInputOutput16|DeviceGroup|MultiView|VariablePointersStorageBuffer|VariablePointers|AtomicStorageOps|SampleMaskPostDepthCoverage|StorageBuffer8BitAccess|UniformAndStorageBuffer8BitAccess|StoragePushConstant8|DenormPreserve|DenormFlushToZero|SignedZeroInfNanPreserve|RoundingModeRTE|RoundingModeRTZ|Float16ImageAMD|ImageGatherBiasLodAMD|FragmentMaskAMD|StencilExportEXT|ImageReadWriteLodAMD|ShaderClockKHR|SampleMaskOverrideCoverageNV|GeometryShaderPassthroughNV|ShaderViewportIndexLayerEXT|ShaderViewportIndexLayerNV|ShaderViewportMaskNV|ShaderStereoViewNV|PerViewAttributesNV|FragmentFullyCoveredEXT|MeshShadingNV|ImageFootprintNV|FragmentBarycentricNV|ComputeDerivativeGroupQuadsNV|FragmentDensityEXT|ShadingRateNV|GroupNonUniformPartitionedNV|ShaderNonUniform|ShaderNonUniformEXT|RuntimeDescriptorArray|RuntimeDescriptorArrayEXT|InputAttachmentArrayDynamicIndexing|InputAttachmentArrayDynamicIndexingEXT|UniformTexelBufferArrayDynamicIndexing|UniformTexelBufferArrayDynamicIndexingEXT|StorageTexelBufferArrayDynamicIndexing|StorageTexelBufferArrayDynamicIndexingEXT|UniformBufferArrayNonUniformIndexing|UniformBufferArrayNonUniformIndexingEXT|SampledImageArrayNonUniformIndexing|SampledImageArrayNonUniformIndexingEXT|StorageBufferArrayNonUniformIndexing|StorageBufferArrayNonUniformIndexingEXT|StorageImageArrayNonUniformIndexing|StorageImageArrayNonUniformIndexingEXT|InputAttachmentArrayNonUniformIndexing|InputAttachmentArrayNonUniformIndexingEXT|UniformTexelBufferArrayNonUniformIndexing|UniformTexelBufferArrayNonUniformIndexingEXT|StorageTexelBufferArrayNonUniformIndexing|StorageTexelBufferArrayNonUniformIndexingEXT|RayTracingNV|VulkanMemoryModel|VulkanMemoryModelKHR|VulkanMemoryModelDeviceScope|VulkanMemoryModelDeviceScopeKHR|PhysicalStorageBufferAddresses|PhysicalStorageBufferAddressesEXT|ComputeDerivativeGroupLinearNV|CooperativeMatrixNV|FragmentShaderSampleInterlockEXT|FragmentShaderShadingRateInterlockEXT|ShaderSMBuiltinsNV|FragmentShaderPixelInterlockEXT|DemoteToHelperInvocationEXT|SubgroupShuffleINTEL|SubgroupBufferBlockIOINTEL|SubgroupImageBlockIOINTEL|SubgroupImageMediaBlockIOINTEL|IntegerFunctions2INTEL|SubgroupAvcMotionEstimationINTEL|SubgroupAvcMotionEstimationIntraINTEL|SubgroupAvcMotionEstimationChromaINTEL)\\b", + "name": "keyword.spirv" + }, + "opcode": { + "match": "(Op[a-zA-Z]+)", + "name": "entity.name.function.spirv" + }, + "identifier": { + "match": "%[a-zA-Z0-9_]+", + "name": "variable.spirv" + }, + "number": { + "match": "\\b[0-9]+.?[0-9]*\\b", + "name": "constant.numeric.spirv" + }, + "comment": { + "match": ";[^\n]*", + "name": "comment.line.spirv" + }, + "operator": { + "match": "=", + "name": "keyword.operator.spirv" + }, + "string": { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.spirv" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.spirv" + } + }, + "name": "string.quoted.double.spirv", + "patterns": [ { "include": "#string_escaped_char" } ] + }, + "string_escaped_char": { + "patterns": [ + { + "match": "\\\\([0-7]{3}|[abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})", + "name": "constant.character.escape.spirv" + }, { + "match": "\\\\[^0-7xuUabfnrtv\\'\"]", + "name": "invalid.illegal.unknown-escape.spirv" + } + ] + } + } +} diff --git a/3rdparty/spirv-tools/utils/vscode/spirv.json.tmpl b/3rdparty/spirv-tools/utils/vscode/spirv.json.tmpl new file mode 100644 index 000000000..8582d03fd --- /dev/null +++ b/3rdparty/spirv-tools/utils/vscode/spirv.json.tmpl @@ -0,0 +1,67 @@ +{ + "scopeName": "source.spirv", + "name": "SPIR-V", + "comment": "Generated by {{GenerateArguments}}. Do not modify this file directly.", + "patterns": [ +{{range $o := .OperandKinds}}{{if len $o.Enumerants}} { "include": "#{{$o.Category}}_{{$o.Kind}}" }, +{{end}}{{end}} { "include": "#opcode" }, + { "include": "#identifier" }, + { "include": "#number" }, + { "include": "#string" }, + { "include": "#comment" }, + { "include": "#operator" } + ], + "repository": { {{range $o := .OperandKinds}}{{if len $o.Enumerants}} + "{{$o.Category}}_{{$o.Kind}}": { + "match": "\\b({{OperandKindsMatch $o}})\\b", + "name": "keyword.spirv" + },{{end}}{{end}} + "opcode": { + "match": "(Op[a-zA-Z]+)", + "name": "entity.name.function.spirv" + }, + "identifier": { + "match": "%[a-zA-Z0-9_]+", + "name": "variable.spirv" + }, + "number": { + "match": "\\b[0-9]+.?[0-9]*\\b", + "name": "constant.numeric.spirv" + }, + "comment": { + "match": ";[^\n]*", + "name": "comment.line.spirv" + }, + "operator": { + "match": "=", + "name": "keyword.operator.spirv" + }, + "string": { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.spirv" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.spirv" + } + }, + "name": "string.quoted.double.spirv", + "patterns": [ { "include": "#string_escaped_char" } ] + }, + "string_escaped_char": { + "patterns": [ + { + "match": "\\\\([0-7]{3}|[abfnrtv\\\\'\"]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})", + "name": "constant.character.escape.spirv" + }, { + "match": "\\\\[^0-7xuUabfnrtv\\'\"]", + "name": "invalid.illegal.unknown-escape.spirv" + } + ] + } + } +} diff --git a/3rdparty/spirv-tools/utils/vscode/src/grammar/grammar.go b/3rdparty/spirv-tools/utils/vscode/src/grammar/grammar.go new file mode 100644 index 000000000..0d9ee0f1b --- /dev/null +++ b/3rdparty/spirv-tools/utils/vscode/src/grammar/grammar.go @@ -0,0 +1,75 @@ +// Copyright (C) 2019 Google Inc. +// +// 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. + +// Package grammar holds the JSON type definitions for the SPIR-V grammar schema. +// +// See https://www.khronos.org/registry/spir-v/specs/unified1/MachineReadableGrammar.html +// for more information. +package grammar + +// Root is the top-level structure of the JSON grammar. +type Root struct { + MagicNumber string `json:"magic_number"` + MajorVersion int `json:"major_version"` + MinorVersion int `json:"minor_version"` + Revision int `json:"revision"` + Instructions []Instruction `json:"instructions"` + OperandKinds []OperandKind `json:"operand_kinds"` +} + +// Instruction holds information about a specific SPIR-V instruction. +type Instruction struct { + Opname string `json:"opname"` + Class string `json:"class"` + Opcode int `json:"opcode"` + Operands []Operand `json:"operands"` +} + +// Operand contains information about a logical operand for an instruction. +type Operand struct { + Kind string `json:"kind"` + Name string `json:"name"` + Quantifier Quantifier `json:"quantifier"` +} + +// OperandKind contains information about a specific operand kind. +type OperandKind struct { + Category string `json:"category"` + Kind string `json:"kind"` + Enumerants []Enumerant `json:"enumerants"` + Bases []string `json:"bases"` +} + +// Enumerant contains information about an enumerant in an enum. +type Enumerant struct { + Enumerant string `json:"enumerant"` + Value interface{} `json:"value"` + Capabilities []string `json:"capabilities"` + Parameters []Parameter `json:"parameters"` + Version string `json:"version"` +} + +// Parameter contains information about a logical parameter for an enumerant. +type Parameter struct { + Kind string `json:"kind"` + Name string `json:"name"` +} + +type Quantifier string + +const ( + Once Quantifier = "" + ZeroOrOnce Quantifier = "?" + ZeroOrMany Quantifier = "*" +) diff --git a/3rdparty/spirv-tools/utils/vscode/src/tools/gen-grammar.go b/3rdparty/spirv-tools/utils/vscode/src/tools/gen-grammar.go new file mode 100644 index 000000000..f07dde0d6 --- /dev/null +++ b/3rdparty/spirv-tools/utils/vscode/src/tools/gen-grammar.go @@ -0,0 +1,167 @@ +// Copyright (C) 2019 Google Inc. +// +// 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. + +// gen-grammar generates the spirv.json grammar file from the official SPIR-V +// grammar JSON file. +package main + +import ( + "bytes" + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "runtime" + "strings" + "text/template" + + "github.com/pkg/errors" + + "../grammar" +) + +const ( + spirvGrammarURL = "https://raw.githubusercontent.com/KhronosGroup/SPIRV-Headers/master/include/spirv/unified1/spirv.core.grammar.json" + spirvGrammarName = "spirv.core.grammar.json" +) + +var ( + templatePath = flag.String("template", "", "Path to input template file (required)") + outputPath = flag.String("out", "", "Path to output generated file (required)") + cachePath = flag.String("cache", "", "Cache directory for downloaded files (optional)") + + thisDir = func() string { + _, file, _, _ := runtime.Caller(1) + return filepath.Dir(file) + }() +) + +func main() { + flag.Parse() + if *templatePath == "" || *outputPath == "" { + flag.Usage() + os.Exit(1) + } + if err := run(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func run() error { + tf, err := ioutil.ReadFile(*templatePath) + if err != nil { + return errors.Wrap(err, "Could not open template file") + } + t, err := template.New("tmpl"). + Funcs(template.FuncMap{ + "GenerateArguments": func() string { + relPath := func(path string) string { + rel, err := filepath.Rel(thisDir, path) + if err != nil { + return path + } + return rel + } + args := []string{ + "--template=" + relPath(*templatePath), + "--out=" + relPath(*outputPath), + } + return "gen-grammar.go " + strings.Join(args, " ") + }, + "OperandKindsMatch": func(k grammar.OperandKind) string { + sb := strings.Builder{} + for i, e := range k.Enumerants { + if i > 0 { + sb.WriteString("|") + } + sb.WriteString(e.Enumerant) + } + return sb.String() + }, + }).Parse(string(tf)) + if err != nil { + return errors.Wrap(err, "Failed to parse template") + } + + file, err := getOrDownload(spirvGrammarName, spirvGrammarURL) + if err != nil { + return errors.Wrap(err, "Failed to load grammar file") + } + + g := grammar.Root{} + if err := json.NewDecoder(bytes.NewReader(file)).Decode(&g); err != nil { + return errors.Wrap(err, "Failed to parse grammar file") + } + + buf := bytes.Buffer{} + if err := t.Execute(&buf, g); err != nil { + return errors.Wrap(err, "Failed to execute template") + } + + out := buf.String() + out = strings.ReplaceAll(out, "•", "") + + if err := ioutil.WriteFile(*outputPath, []byte(out), 0777); err != nil { + return errors.Wrap(err, "Failed to write output file") + } + + return nil +} + +// getOrDownload loads the specific file from the cache, or downloads the file +// from the given url. +func getOrDownload(name, url string) ([]byte, error) { + if *cachePath != "" { + if err := os.MkdirAll(*cachePath, 0777); err == nil { + path := filepath.Join(*cachePath, name) + if isFile(path) { + return ioutil.ReadFile(path) + } + } + } + resp, err := http.Get(url) + if err != nil { + return nil, err + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if *cachePath != "" { + ioutil.WriteFile(filepath.Join(*cachePath, name), data, 0777) + } + return data, nil +} + +// isFile returns true if path is a file. +func isFile(path string) bool { + s, err := os.Stat(path) + if err != nil { + return false + } + return !s.IsDir() +} + +// isDir returns true if path is a directory. +func isDir(path string) bool { + s, err := os.Stat(path) + if err != nil { + return false + } + return s.IsDir() +}