diff --git a/third_party/spirv-tools/.github/dependabot.yml b/third_party/spirv-tools/.github/dependabot.yml new file mode 100644 index 0000000000..dca857a3de --- /dev/null +++ b/third_party/spirv-tools/.github/dependabot.yml @@ -0,0 +1,25 @@ +# Copyright 2023 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. + +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + groups: + github-actions: + patterns: + - "*" + open-pull-requests-limit: 3 diff --git a/third_party/spirv-tools/.github/workflows/autoroll.yml b/third_party/spirv-tools/.github/workflows/autoroll.yml new file mode 100644 index 0000000000..eb0b0feaa7 --- /dev/null +++ b/third_party/spirv-tools/.github/workflows/autoroll.yml @@ -0,0 +1,56 @@ +name: Update dependencies +permissions: + contents: read + +on: + schedule: + - cron: '0 2 * * *' + workflow_dispatch: + +jobs: + update-dependencies: + permissions: + contents: write + pull-requests: write + name: Update dependencies + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + # Checkout the depot tools they are needed by roll_deps.sh + - name: Checkout depot tools + run: git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git + + - name: Update PATH + run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH + + - name: Download dependencies + run: python3 utils/git-sync-deps + + - name: Setup git user information + run: | + git config user.name "GitHub Actions[bot]" + git config user.email "<>" + git checkout -b roll_deps + + - name: Update dependencies + run: | + utils/roll_deps.sh + if [[ `git diff HEAD..origin/main --name-only | wc -l` == 0 ]]; then + echo "changed=false" >> $GITHUB_OUTPUT + else + echo "changed=true" >> $GITHUB_OUTPUT + fi + id: update_dependencies + - name: Push changes and create PR + if: steps.update_dependencies.outputs.changed == 'true' + run: | + git push --force --set-upstream origin roll_deps + # Create a PR. If it aready exists, the command fails, so ignore the return code. + gh pr create --base main -f || true + # Add the 'kokoro:run' label so that the kokoro tests will be run. + gh pr edit --add-label 'kokoro:run' + gh pr merge --auto --squash + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/third_party/spirv-tools/.github/workflows/bazel.yml b/third_party/spirv-tools/.github/workflows/bazel.yml new file mode 100644 index 0000000000..22cfef1f56 --- /dev/null +++ b/third_party/spirv-tools/.github/workflows/bazel.yml @@ -0,0 +1,57 @@ +name: Build and Test with Bazel +permissions: + contents: read + +on: + push: + branches: + - 'main' + pull_request: + +jobs: + build: + timeout-minutes: 120 + strategy: + matrix: + os: [ubuntu-latest, windows-2025] + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: '0' + - name: Download dependencies + run: python3 utils/git-sync-deps + - name: Mount Bazel cache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: ~/.bazel/cache + key: bazel-cache-${{ runner.os }} + - name: Build All + run: bazel --output_user_root=~/.bazel/cache build //... + - name: Test All + run: bazel --output_user_root=~/.bazel/cache test --test_output=errors //... + + # iOS is 10x expensive to run on GitHub machines, so only run if we know something else passed + # The steps are unfortunately duplicated because github actions requires 2 jobs for a dependency + build-macos: + needs: build + timeout-minutes: 120 + runs-on: macos-latest + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: '0' + - name: Download dependencies + run: python3 utils/git-sync-deps + - name: Mount Bazel cache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: ~/.bazel/cache + key: bazel-cache-${{ runner.os }} + - name: Build All + run: bazel --output_user_root=~/.bazel/cache build //... + - name: Test All + run: bazel --output_user_root=~/.bazel/cache test --test_output=errors //... diff --git a/third_party/spirv-tools/.github/workflows/ios.yml b/third_party/spirv-tools/.github/workflows/ios.yml new file mode 100644 index 0000000000..aece8de231 --- /dev/null +++ b/third_party/spirv-tools/.github/workflows/ios.yml @@ -0,0 +1,33 @@ +name: iOS +permissions: + contents: read + +on: + workflow_run: + # iOS is 10x expensive to run on GitHub machines, so only run if we know something else passed + workflows: ["Wasm Build"] + types: + - completed + +jobs: + build: + runs-on: macos-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: lukka/get-cmake@6b3e96a9bc9976b8b546346fdd102effedae0ca8 # v4.02 + - name: Download dependencies + run: python3 utils/git-sync-deps + # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. + - name: Configure Universal Binary for iOS + run: | + cmake -S . -B build \ + -D CMAKE_BUILD_TYPE=Debug \ + -D CMAKE_SYSTEM_NAME=iOS \ + "-D CMAKE_OSX_ARCHITECTURES=arm64;x86_64" \ + -G Ninja + env: + # Linker warnings as errors + LDFLAGS: -Wl,-fatal_warnings + - run: cmake --build build + - run: cmake --install build --prefix /tmp diff --git a/third_party/spirv-tools/.github/workflows/release.yml b/third_party/spirv-tools/.github/workflows/release.yml new file mode 100644 index 0000000000..1e0d865a8e --- /dev/null +++ b/third_party/spirv-tools/.github/workflows/release.yml @@ -0,0 +1,25 @@ +name: Create a release branch from release tag +permissions: + contents: write + +on: + push: + tags: + - 'v[0-9]+.[0-9]+' + - 'vulkan-sdk-[0-9]+.[0-9]+.[0-9]+.[0-9]+' + - '!v[0-9]+.[0-9]+.rc*' + +jobs: + prepare-release-job: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Prepare CHANGELOG for version + run: | + python utils/generate_changelog.py CHANGES "${{ github.ref_name }}" VERSION_CHANGELOG + - name: Create release + run: | + gh release create -t "Release ${{ github.ref_name }}" -F VERSION_CHANGELOG "${{ github.ref_name }}" + env: + GITHUB_TOKEN: ${{ github.token }} + diff --git a/third_party/spirv-tools/.github/workflows/scorecard.yml b/third_party/spirv-tools/.github/workflows/scorecard.yml new file mode 100644 index 0000000000..d2e0eb6b62 --- /dev/null +++ b/third_party/spirv-tools/.github/workflows/scorecard.yml @@ -0,0 +1,53 @@ +name: Scorecard supply-chain security +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '36 17 * * 5' + push: + branches: [ "main" ] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + security-events: write # to upload the results to code-scanning dashboard + id-token: write # to publish results and get a badge + + steps: + - name: "Checkout code" + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 + with: + results_file: results.sarif + results_format: sarif + # To enable Branch-Protection uncomment the `repo_token` line below + # To create the Fine-grained PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-fine-grained-pat-optional. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + publish_results: true # allows the repo to include the Scorecard badge + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@181d5eefc20863364f96762470ba6f862bdef56b # v3.29.2 + with: + sarif_file: results.sarif diff --git a/third_party/spirv-tools/.github/workflows/wasm.yml b/third_party/spirv-tools/.github/workflows/wasm.yml new file mode 100644 index 0000000000..cbe21435a0 --- /dev/null +++ b/third_party/spirv-tools/.github/workflows/wasm.yml @@ -0,0 +1,18 @@ +name: Wasm Build +permissions: + contents: read + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: '0' + - name: Build web + run: docker compose -f source/wasm/docker-compose.yml --project-directory . up + - name: Run tests + run: node test/wasm/test.js diff --git a/third_party/spirv-tools/DEPS b/third_party/spirv-tools/DEPS index 7a67312dc4..7adadc959e 100644 --- a/third_party/spirv-tools/DEPS +++ b/third_party/spirv-tools/DEPS @@ -3,18 +3,18 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': '212fcb96c8a5218e652b8502f297d236d7fbe3af', + 'abseil_revision': '6cd1763d9fea309e83fe8bc20f997208d57cd476', 'effcee_revision': '8ce15c424e61a94ee27b5be0ec0ed036b158e6e3', - 'googletest_revision': '35b75a2cba6ef72b7ce2b6b94b05c54ca07df866', + 'googletest_revision': '3983f67e32fb3e9294487b9d4f9586efa6e5d088', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': 'c84a140c93352cdabbfb547c531be34515b12228', + 're2_revision': '8ea5841693c6c0b837c6ed2189217e8f8d6fee9c', - 'spirv_headers_revision': '2a611a970fdbc41ac2e3e328802aed9985352dca', + 'spirv_headers_revision': 'c8ad050fcb29e42a2f57d9f59e97488f465c436d', 'mimalloc_revision': '09a27098aa6e9286518bd9c74e6ffa7199c3f04e', } diff --git a/third_party/spirv-tools/README.md b/third_party/spirv-tools/README.md index adfb5a9185..248191bcdc 100644 --- a/third_party/spirv-tools/README.md +++ b/third_party/spirv-tools/README.md @@ -146,6 +146,7 @@ As of this writing, there are 67 transforms including examples such as: decorations. * Normalization * Compact IDs + * Canonicalize IDs * CFG cleanup * Flatten decorations * Merge returns diff --git a/third_party/spirv-tools/include/spirv-tools/libspirv.h b/third_party/spirv-tools/include/spirv-tools/libspirv.h index a2a032a07e..2a604e94d9 100644 --- a/third_party/spirv-tools/include/spirv-tools/libspirv.h +++ b/third_party/spirv-tools/include/spirv-tools/libspirv.h @@ -189,36 +189,24 @@ typedef enum spv_operand_type_t { SPV_OPERAND_TYPE_MEMORY_ACCESS, // SPIR-V Sec 3.26 SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE, // SPIR-V Sec 3.FSR -// NOTE: New concrete enum values should be added at the end. + // NOTE: New concrete enum values should be added at the end. -// The "optional" and "variable" operand types are only used internally by -// the assembler and the binary parser. -// There are two categories: -// Optional : expands to 0 or 1 operand, like ? in regular expressions. -// Variable : expands to 0, 1 or many operands or pairs of operands. -// This is similar to * in regular expressions. + // The "optional" and "variable" operand types are only used internally by + // the assembler and the binary parser. + // There are two categories: + // Optional : expands to 0 or 1 operand, like ? in regular expressions. + // Variable : expands to 0, 1 or many operands or pairs of operands. + // This is similar to * in regular expressions. -// NOTE: These FIRST_* and LAST_* enum values are DEPRECATED. -// The concept of "optional" and "variable" operand types are only intended -// for use as an implementation detail of parsing SPIR-V, either in text or -// binary form. Instead of using enum ranges, use characteristic function -// spvOperandIsConcrete. -// The use of enum value ranges in a public API makes it difficult to insert -// new values into a range without also breaking binary compatibility. -// -// Macros for defining bounds on optional and variable operand types. -// Any variable operand type is also optional. -// TODO(dneto): Remove SPV_OPERAND_TYPE_FIRST_* and SPV_OPERAND_TYPE_LAST_* -#define FIRST_OPTIONAL(ENUM) ENUM, SPV_OPERAND_TYPE_FIRST_OPTIONAL_TYPE = ENUM -#define FIRST_VARIABLE(ENUM) ENUM, SPV_OPERAND_TYPE_FIRST_VARIABLE_TYPE = ENUM -#define LAST_VARIABLE(ENUM) \ - ENUM, SPV_OPERAND_TYPE_LAST_VARIABLE_TYPE = ENUM, \ - SPV_OPERAND_TYPE_LAST_OPTIONAL_TYPE = ENUM + // Use characteristic function spvOperandIsConcrete to classify the + // operand types; when it returns false, the operand is optional or variable. + // + // Any variable operand type is also optional. // An optional operand represents zero or one logical operands. // In an instruction definition, this may only appear at the end of the // operand types. - FIRST_OPTIONAL(SPV_OPERAND_TYPE_OPTIONAL_ID), + SPV_OPERAND_TYPE_OPTIONAL_ID, // An optional image operand type. SPV_OPERAND_TYPE_OPTIONAL_IMAGE, // An optional memory access type. @@ -243,7 +231,7 @@ typedef enum spv_operand_type_t { // A variable operand represents zero or more logical operands. // In an instruction definition, this may only appear at the end of the // operand types. - FIRST_VARIABLE(SPV_OPERAND_TYPE_VARIABLE_ID), + SPV_OPERAND_TYPE_VARIABLE_ID, SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER, // A sequence of zero or more pairs of (typed literal integer, Id). // Expands to zero or more: @@ -251,7 +239,7 @@ typedef enum spv_operand_type_t { // where the literal number must always be an integer of some sort. SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID, // A sequence of zero or more pairs of (Id, Literal integer) - LAST_VARIABLE(SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER), + SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER, // The following are concrete enum types from the DebugInfo extended // instruction set. @@ -343,6 +331,10 @@ typedef enum spv_operand_type_t { SPV_OPERAND_TYPE_TENSOR_OPERANDS, SPV_OPERAND_TYPE_OPTIONAL_TENSOR_OPERANDS, + // SPV_INTEL_function_variants + SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY, + SPV_OPERAND_TYPE_VARIABLE_CAPABILITY, + // This is a sentinel value, and does not represent an operand type. // It should come last. SPV_OPERAND_TYPE_NUM_OPERAND_TYPES, diff --git a/third_party/spirv-tools/source/binary.cpp b/third_party/spirv-tools/source/binary.cpp index 180d0a9996..8e4d899f7d 100644 --- a/third_party/spirv-tools/source/binary.cpp +++ b/third_party/spirv-tools/source/binary.cpp @@ -636,6 +636,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset, } break; case SPV_OPERAND_TYPE_CAPABILITY: + case SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY: case SPV_OPERAND_TYPE_EXECUTION_MODEL: case SPV_OPERAND_TYPE_ADDRESSING_MODEL: case SPV_OPERAND_TYPE_MEMORY_MODEL: @@ -689,6 +690,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset, parsed_operand.type = SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT; if (type == SPV_OPERAND_TYPE_OPTIONAL_FPENCODING) parsed_operand.type = SPV_OPERAND_TYPE_FPENCODING; + if (type == SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY) + parsed_operand.type = SPV_OPERAND_TYPE_CAPABILITY; const spvtools::OperandDesc* entry = nullptr; if (spvtools::LookupOperand(type, word, &entry)) { diff --git a/third_party/spirv-tools/source/disassemble.cpp b/third_party/spirv-tools/source/disassemble.cpp index 2d9bb0ff02..4267333a00 100644 --- a/third_party/spirv-tools/source/disassemble.cpp +++ b/third_party/spirv-tools/source/disassemble.cpp @@ -907,6 +907,7 @@ void InstructionDisassembler::EmitOperand(std::ostream& stream, stream << '"'; } break; case SPV_OPERAND_TYPE_CAPABILITY: + case SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY: case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: case SPV_OPERAND_TYPE_EXECUTION_MODEL: case SPV_OPERAND_TYPE_ADDRESSING_MODEL: diff --git a/third_party/spirv-tools/source/operand.cpp b/third_party/spirv-tools/source/operand.cpp index c635c72d61..d7fc535ce2 100644 --- a/third_party/spirv-tools/source/operand.cpp +++ b/third_party/spirv-tools/source/operand.cpp @@ -111,6 +111,7 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { case SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO: return "kernel profiling info"; case SPV_OPERAND_TYPE_CAPABILITY: + case SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY: return "capability"; case SPV_OPERAND_TYPE_RAY_FLAGS: return "ray flags"; @@ -394,6 +395,7 @@ bool spvOperandIsOptional(spv_operand_type_t type) { case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS: case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING: case SPV_OPERAND_TYPE_OPTIONAL_TENSOR_OPERANDS: + case SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY: return true; default: break; @@ -408,6 +410,7 @@ bool spvOperandIsVariable(spv_operand_type_t type) { case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER: case SPV_OPERAND_TYPE_VARIABLE_LITERAL_INTEGER_ID: case SPV_OPERAND_TYPE_VARIABLE_ID_LITERAL_INTEGER: + case SPV_OPERAND_TYPE_VARIABLE_CAPABILITY: return true; default: break; @@ -439,6 +442,10 @@ bool spvExpandOperandSequenceOnce(spv_operand_type_t type, pattern->push_back(SPV_OPERAND_TYPE_LITERAL_INTEGER); pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_ID); return true; + case SPV_OPERAND_TYPE_VARIABLE_CAPABILITY: + pattern->push_back(type); + pattern->push_back(SPV_OPERAND_TYPE_OPTIONAL_CAPABILITY); + return true; default: break; } diff --git a/third_party/spirv-tools/source/opt/merge_return_pass.cpp b/third_party/spirv-tools/source/opt/merge_return_pass.cpp index c262ea073a..41734945e6 100644 --- a/third_party/spirv-tools/source/opt/merge_return_pass.cpp +++ b/third_party/spirv-tools/source/opt/merge_return_pass.cpp @@ -828,7 +828,8 @@ BasicBlock* MergeReturnPass::CreateContinueTarget(uint32_t header_label_id) { bool MergeReturnPass::CreateSingleCaseSwitch(BasicBlock* merge_target) { // Insert the switch before any code is run. We have to split the entry - // block to make sure the OpVariable instructions remain in the entry block. + // block to make sure the OpVariable instructions and DebugFunctionDefinition + // instructions remain in the entry block. BasicBlock* start_block = &*function_->begin(); auto split_pos = start_block->begin(); while (split_pos->opcode() == spv::Op::OpVariable) { @@ -838,6 +839,18 @@ bool MergeReturnPass::CreateSingleCaseSwitch(BasicBlock* merge_target) { BasicBlock* old_block = start_block->SplitBasicBlock(context(), TakeNextId(), split_pos); + // Find DebugFunctionDefinition inst in the old block, and if we can find it, + // move it to the entry block. Since DebugFunctionDefinition is not necessary + // after OpVariable inst, we have to traverse the whole block to find it. + for (auto pos = old_block->begin(); pos != old_block->end(); ++pos) { + if (pos->GetShader100DebugOpcode() == + NonSemanticShaderDebugInfo100DebugFunctionDefinition) { + start_block->AddInstruction(MakeUnique(*pos)); + pos.Erase(); + break; + } + } + // Add the switch to the end of the entry block. InstructionBuilder builder( context(), start_block, diff --git a/third_party/spirv-tools/source/opt/type_manager.cpp b/third_party/spirv-tools/source/opt/type_manager.cpp index be7dbc8f62..7eec9f337c 100644 --- a/third_party/spirv-tools/source/opt/type_manager.cpp +++ b/third_party/spirv-tools/source/opt/type_manager.cpp @@ -495,6 +495,36 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { {SPV_OPERAND_TYPE_ID, {coop_vec->components()}}}); break; } + case Type::kTensorARM: { + auto tensor_type = type->AsTensorARM(); + uint32_t const element_type = + GetTypeInstruction(tensor_type->element_type()); + if (element_type == 0) { + return 0; + } + if (tensor_type->rank_id() != 0) { + if (tensor_type->shape_id() != 0) { + typeInst = MakeUnique( + context(), spv::Op::OpTypeTensorARM, 0, id, + std::initializer_list{ + {SPV_OPERAND_TYPE_ID, {element_type}}, + {SPV_OPERAND_TYPE_ID, {tensor_type->rank_id()}}, + {SPV_OPERAND_TYPE_ID, {tensor_type->shape_id()}}}); + } else { + typeInst = MakeUnique( + context(), spv::Op::OpTypeTensorARM, 0, id, + std::initializer_list{ + {SPV_OPERAND_TYPE_ID, {element_type}}, + {SPV_OPERAND_TYPE_ID, {tensor_type->rank_id()}}}); + } + } else { + typeInst = + MakeUnique(context(), spv::Op::OpTypeTensorARM, 0, id, + std::initializer_list{ + {SPV_OPERAND_TYPE_ID, {element_type}}}); + } + break; + } default: assert(false && "Unexpected type"); break; @@ -754,6 +784,14 @@ Type* TypeManager::RebuildType(uint32_t type_id, const Type& type) { cv_type->components()); break; } + case Type::kTensorARM: { + const TensorARM* tensor_type = type.AsTensorARM(); + const Type* element_type = tensor_type->element_type(); + rebuilt_ty = MakeUnique( + RebuildType(GetId(element_type), *element_type), + tensor_type->rank_id(), tensor_type->shape_id()); + break; + } default: assert(false && "Unhandled type"); return nullptr; @@ -1036,6 +1074,23 @@ Type* TypeManager::RecordIfTypeDefinition(const Instruction& inst) { inst.GetSingleWordInOperand(1), perm); break; } + case spv::Op::OpTypeTensorARM: { + switch (inst.NumInOperands()) { + case 1: + type = new TensorARM(GetType(inst.GetSingleWordInOperand(0))); + break; + case 2: + type = new TensorARM(GetType(inst.GetSingleWordInOperand(0)), + inst.GetSingleWordInOperand(1)); + break; + case 3: + type = new TensorARM(GetType(inst.GetSingleWordInOperand(0)), + inst.GetSingleWordInOperand(1), + inst.GetSingleWordInOperand(2)); + break; + } + break; + } default: assert(false && "Type not handled by the type manager."); break; @@ -1067,7 +1122,11 @@ void TypeManager::AttachDecoration(const Instruction& inst, Type* type) { const auto count = inst.NumOperands(); std::vector data; for (uint32_t i = 1; i < count; ++i) { - data.push_back(inst.GetSingleWordOperand(i)); + // LinkageAttributes has a literal string as an operand, which is a + // varible length word. We cannot assume that all operands are single + // word. + const Operand::OperandData& words = inst.GetOperand(i).words; + data.insert(data.end(), words.begin(), words.end()); } type->AddDecoration(std::move(data)); } break; diff --git a/third_party/spirv-tools/source/opt/types.cpp b/third_party/spirv-tools/source/opt/types.cpp index bb761a4642..83e0534dbc 100644 --- a/third_party/spirv-tools/source/opt/types.cpp +++ b/third_party/spirv-tools/source/opt/types.cpp @@ -135,6 +135,7 @@ std::unique_ptr Type::Clone() const { DeclareKindCase(CooperativeVectorNV); DeclareKindCase(RayQueryKHR); DeclareKindCase(HitObjectNV); + DeclareKindCase(TensorARM); #undef DeclareKindCase default: assert(false && "Unhandled type"); @@ -187,6 +188,7 @@ bool Type::operator==(const Type& other) const { DeclareKindCase(HitObjectNV); DeclareKindCase(TensorLayoutNV); DeclareKindCase(TensorViewNV); + DeclareKindCase(TensorARM); #undef DeclareKindCase default: assert(false && "Unhandled type"); @@ -247,6 +249,7 @@ size_t Type::ComputeHashValue(size_t hash, SeenTypes* seen) const { DeclareKindCase(HitObjectNV); DeclareKindCase(TensorLayoutNV); DeclareKindCase(TensorViewNV); + DeclareKindCase(TensorARM); #undef DeclareKindCase default: assert(false && "Unhandled type"); @@ -899,6 +902,36 @@ bool CooperativeVectorNV::IsSameImpl(const Type* that, components_ == mt->components_ && HasSameDecorations(that); } +TensorARM::TensorARM(const Type* elty, const uint32_t rank, + const uint32_t shape) + : Type(kTensorARM), element_type_(elty), rank_id_(rank), shape_id_(shape) { + assert(elty != nullptr); + if (shape != 0) { + assert(rank != 0); + } +} + +std::string TensorARM::str() const { + std::ostringstream oss; + oss << "tensor<" << element_type_->str() << ", id(" << rank_id_ << "), id(" + << shape_id_ << ")>"; + return oss.str(); +} + +size_t TensorARM::ComputeExtraStateHash(size_t hash, SeenTypes* seen) const { + hash = hash_combine(hash, rank_id_); + hash = hash_combine(hash, shape_id_); + return element_type_->ComputeHashValue(hash, seen); +} + +bool TensorARM::IsSameImpl(const Type* that, IsSameCache* seen) const { + const TensorARM* tt = that->AsTensorARM(); + if (!tt) return false; + return element_type_->IsSameImpl(tt->element_type_, seen) && + rank_id_ == tt->rank_id_ && shape_id_ == tt->shape_id_ && + HasSameDecorations(that); +} + } // namespace analysis } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/source/opt/types.h b/third_party/spirv-tools/source/opt/types.h index 9b12d5f948..72acdb01d0 100644 --- a/third_party/spirv-tools/source/opt/types.h +++ b/third_party/spirv-tools/source/opt/types.h @@ -69,6 +69,7 @@ class RayQueryKHR; class HitObjectNV; class TensorLayoutNV; class TensorViewNV; +class TensorARM; // Abstract class for a SPIR-V type. It has a bunch of As() methods, // which is used as a way to probe the actual . @@ -114,6 +115,7 @@ class Type { kHitObjectNV, kTensorLayoutNV, kTensorViewNV, + kTensorARM, kLast }; @@ -220,6 +222,7 @@ class Type { DeclareCastMethod(HitObjectNV) DeclareCastMethod(TensorLayoutNV) DeclareCastMethod(TensorViewNV) + DeclareCastMethod(TensorARM) #undef DeclareCastMethod protected: @@ -774,6 +777,31 @@ class CooperativeVectorNV : public Type { const uint32_t components_; }; +class TensorARM : public Type { + public: + TensorARM(const Type* elty, const uint32_t rank = 0, + const uint32_t shape = 0); + TensorARM(const TensorARM&) = default; + + std::string str() const override; + + TensorARM* AsTensorARM() override { return this; } + const TensorARM* AsTensorARM() const override { return this; } + + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; + + const Type* element_type() const { return element_type_; } + uint32_t rank_id() const { return rank_id_; } + uint32_t shape_id() const { return shape_id_; } + + private: + bool IsSameImpl(const Type* that, IsSameCache*) const override; + + const Type* element_type_; + const uint32_t rank_id_; + const uint32_t shape_id_; +}; + #define DefineParameterlessType(type, name) \ class type : public Type { \ public: \ diff --git a/third_party/spirv-tools/source/val/validate_builtins.cpp b/third_party/spirv-tools/source/val/validate_builtins.cpp index 2c172647ad..549eac8a8c 100644 --- a/third_party/spirv-tools/source/val/validate_builtins.cpp +++ b/third_party/spirv-tools/source/val/validate_builtins.cpp @@ -2383,6 +2383,19 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference( referenced_from_inst, std::placeholders::_1)); } + if (!_.HasCapability(spv::Capability::MeshShadingEXT) && + !_.HasCapability(spv::Capability::MeshShadingNV) && + !_.HasCapability(spv::Capability::Geometry) && + !_.HasCapability(spv::Capability::Tessellation)) { + id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( + &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, 4333, + "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for " + "variables in the Fragment execution model unless it declares " + "Geometry, Tessellation, or MeshShader capabilities.", + spv::ExecutionModel::Fragment, decoration, built_in_inst, + referenced_from_inst, std::placeholders::_1)); + } + for (const spv::ExecutionModel execution_model : execution_models_) { switch (execution_model) { case spv::ExecutionModel::Fragment: diff --git a/third_party/spirv-tools/source/val/validate_decorations.cpp b/third_party/spirv-tools/source/val/validate_decorations.cpp index e94a9caf08..384f9c61bf 100644 --- a/third_party/spirv-tools/source/val/validate_decorations.cpp +++ b/third_party/spirv-tools/source/val/validate_decorations.cpp @@ -1767,14 +1767,19 @@ spv_result_t CheckFPRoundingModeForShaders(ValidationState_t& vstate, return SPV_SUCCESS; } -// Returns SPV_SUCCESS if validation rules are satisfied for the NonWritable +// Returns SPV_SUCCESS if validation rules are satisfied for the NonReadable or +// NonWritable // decoration. Otherwise emits a diagnostic and returns something other than // SPV_SUCCESS. The |inst| parameter is the object being decorated. This must // be called after TypePass and AnnotateCheckDecorationsOfBuffers are called. -spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate, - const Instruction& inst, - const Decoration& decoration) { +spv_result_t CheckNonReadableWritableDecorations(ValidationState_t& vstate, + const Instruction& inst, + const Decoration& decoration) { assert(inst.id() && "Parser ensures the target of the decoration has an ID"); + const bool is_non_writable = + decoration.dec_type() == spv::Decoration::NonWritable; + assert(is_non_writable || + decoration.dec_type() == spv::Decoration::NonReadable); if (decoration.struct_member_index() == Decoration::kInvalidMember) { // The target must be a memory object declaration. @@ -1786,7 +1791,10 @@ spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate, opcode != spv::Op::OpFunctionParameter && opcode != spv::Op::OpRawAccessChainNV) { return vstate.diag(SPV_ERROR_INVALID_ID, &inst) - << "Target of NonWritable decoration must be a memory object " + << "Target of " + << (is_non_writable ? "NonWritable" : "NonReadable") + << " decoration must be a " + "memory object " "declaration (a variable or a function parameter)"; } const auto var_storage_class = @@ -1797,7 +1805,8 @@ spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate, : spv::StorageClass::Max; if ((var_storage_class == spv::StorageClass::Function || var_storage_class == spv::StorageClass::Private) && - vstate.features().nonwritable_var_in_function_or_private) { + vstate.features().nonwritable_var_in_function_or_private && + is_non_writable) { // New permitted feature in SPIR-V 1.4. } else if (var_storage_class == spv::StorageClass::TileAttachmentQCOM) { } else if ( @@ -1805,12 +1814,18 @@ spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate, vstate.IsPointerToUniformBlock(type_id) || vstate.IsPointerToStorageBuffer(type_id) || vstate.IsPointerToStorageImage(type_id) || + vstate.IsPointerToTensor(type_id) || opcode == spv::Op::OpRawAccessChainNV) { } else { return vstate.diag(SPV_ERROR_INVALID_ID, &inst) - << "Target of NonWritable decoration is invalid: must point to a " - "storage image, uniform block, " - << (vstate.features().nonwritable_var_in_function_or_private + << "Target of " + << (is_non_writable ? "NonWritable" : "NonReadable") + << " decoration is invalid: " + "must point to a " + "storage image, tensor variable in UniformConstant storage " + "class, uniform block, " + << (vstate.features().nonwritable_var_in_function_or_private && + is_non_writable ? "storage buffer, or variable in Private or Function " "storage class" : "or storage buffer"); @@ -2098,8 +2113,10 @@ spv_result_t CheckDecorationsFromDecoration(ValidationState_t& vstate) { PASS_OR_BAIL( CheckFPRoundingModeForShaders(vstate, *inst, decoration)); break; + case spv::Decoration::NonReadable: case spv::Decoration::NonWritable: - PASS_OR_BAIL(CheckNonWritableDecoration(vstate, *inst, decoration)); + PASS_OR_BAIL( + CheckNonReadableWritableDecorations(vstate, *inst, decoration)); break; case spv::Decoration::Uniform: case spv::Decoration::UniformId: diff --git a/third_party/spirv-tools/source/val/validate_tensor.cpp b/third_party/spirv-tools/source/val/validate_tensor.cpp index 4906aa2cc9..0b54129054 100644 --- a/third_party/spirv-tools/source/val/validate_tensor.cpp +++ b/third_party/spirv-tools/source/val/validate_tensor.cpp @@ -83,8 +83,7 @@ spv_result_t ValidateTensorRead(ValidationState_t& _, const Instruction* inst) { auto op_coord = inst->word(4); auto inst_coord = _.FindDef(op_coord); auto tensor_rank = GetTensorTypeRank(_, inst_tensor->type_id()); - if (tensor_rank == 0 || - !_.IsIntArrayType(inst_coord->type_id(), tensor_rank)) { + if (!_.IsIntArrayType(inst_coord->type_id(), tensor_rank)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Coordinates to be an array whose Element Type is an " "integer type and whose Length is equal to the Rank of Tensor."; @@ -143,8 +142,7 @@ spv_result_t ValidateTensorWrite(ValidationState_t& _, auto op_coord = inst->word(2); auto inst_coord = _.FindDef(op_coord); auto tensor_rank = GetTensorTypeRank(_, inst_tensor->type_id()); - if (tensor_rank == 0 || - !_.IsIntArrayType(inst_coord->type_id(), tensor_rank)) { + if (!_.IsIntArrayType(inst_coord->type_id(), tensor_rank)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Coordinates to be an array whose Element Type is an " "integer type and whose Length is equal to the Rank of Tensor."; diff --git a/third_party/spirv-tools/source/val/validate_type.cpp b/third_party/spirv-tools/source/val/validate_type.cpp index 7a3105af34..709869cb13 100644 --- a/third_party/spirv-tools/source/val/validate_type.cpp +++ b/third_party/spirv-tools/source/val/validate_type.cpp @@ -562,6 +562,9 @@ spv_result_t ValidateTypePointer(ValidationState_t& _, // a storage image. if (sampled == 2) _.RegisterPointerToStorageImage(inst->id()); } + if (type->opcode() == spv::Op::OpTypeTensorARM) { + _.RegisterPointerToTensor(inst->id()); + } } if (!_.IsValidStorageClass(storage_class)) { diff --git a/third_party/spirv-tools/source/val/validation_state.cpp b/third_party/spirv-tools/source/val/validation_state.cpp index d4a8dda2bd..836e3316c5 100644 --- a/third_party/spirv-tools/source/val/validation_state.cpp +++ b/third_party/spirv-tools/source/val/validation_state.cpp @@ -2219,6 +2219,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-Position-Position-04321); case 4330: return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04330); + case 4333: + return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04333); case 4334: return VUID_WRAP(VUID-PrimitiveId-PrimitiveId-04334); case 4336: diff --git a/third_party/spirv-tools/source/val/validation_state.h b/third_party/spirv-tools/source/val/validation_state.h index cdbc18997c..0e402ef2b1 100644 --- a/third_party/spirv-tools/source/val/validation_state.h +++ b/third_party/spirv-tools/source/val/validation_state.h @@ -772,6 +772,16 @@ class ValidationState_t { pointer_to_storage_image_.insert(type_id); } + // Is the ID the type of a pointer to a tensor? That is, the pointee + // type is a tensor type. + bool IsPointerToTensor(uint32_t type_id) const { + return pointer_to_tensor_.find(type_id) != pointer_to_tensor_.cend(); + } + // Save the ID of a pointer to a tensor. + void RegisterPointerToTensor(uint32_t type_id) { + pointer_to_tensor_.insert(type_id); + } + // Tries to evaluate a any scalar integer OpConstant as uint64. // OpConstantNull is defined as zero for scalar int (will return true) // OpSpecConstant* return false since their values cannot be relied upon @@ -1036,6 +1046,9 @@ class ValidationState_t { // The IDs of types of pointers to storage images. This is populated in the // TypePass. std::unordered_set pointer_to_storage_image_; + // The IDs of types of pointers to tensors. This is populated in the + // TypePass. + std::unordered_set pointer_to_tensor_; /// Maps ids to friendly names. std::unique_ptr friendly_mapper_; diff --git a/third_party/spirv-tools/test/opt/pass_merge_return_test.cpp b/third_party/spirv-tools/test/opt/pass_merge_return_test.cpp index 494f2e95f0..c005d748bc 100644 --- a/third_party/spirv-tools/test/opt/pass_merge_return_test.cpp +++ b/third_party/spirv-tools/test/opt/pass_merge_return_test.cpp @@ -2598,6 +2598,70 @@ TEST_F(MergeReturnPassTest, OverflowTest1) { EXPECT_EQ(Pass::Status::Failure, std::get<1>(result)); } +TEST_F(MergeReturnPassTest, DebugFunctionDefinitionStillInEntryBlock) { + // Make sure that the DebugFunctionDefinition instruction is still in the + // entry block + const std::string text = + R"( +; CHECK: OpFunction +; CHECK: OpLabel +; CHECK: DebugFunctionDefinition +; CHECK: OpSelectionMerge +; CHECK: OpCompositeExtract +; CHECK: OpUGreaterThan + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + %2 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %entryPointParam_main %gl_GlobalInvocationID + %1 = OpString "test" + OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId + OpDecorate %entryPointParam_main Location 0 + %void = OpTypeVoid + %4 = OpExtInst %void %2 DebugSource %1 + %uint = OpTypeInt 32 0 + %uint_100 = OpConstant %uint 100 + %uint_5 = OpConstant %uint 5 + %uint_11 = OpConstant %uint 11 + %10 = OpExtInst %void %2 DebugCompilationUnit %uint_100 %uint_5 %4 %uint_11 + %12 = OpTypeFunction %void + %uint_0 = OpConstant %uint 0 + %14 = OpExtInst %void %2 DebugTypeFunction %uint_0 %void + %uint_2 = OpConstant %uint 2 + %16 = OpExtInst %void %2 DebugFunction %1 %14 %4 %uint_2 %uint_5 %10 %1 %uint_0 %uint_2 + %v3uint = OpTypeVector %uint 3 + %_ptr_Input_v3uint = OpTypePointer Input %v3uint + %bool = OpTypeBool + %uint_3 = OpConstant %uint 3 + %int = OpTypeInt 32 1 + %_ptr_Output_int = OpTypePointer Output %int + %int_1 = OpConstant %int 1 + %int_0 = OpConstant %int 0 + %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input ; BuiltIn GlobalInvocationId + %entryPointParam_main = OpVariable %_ptr_Output_int Output ; Location 0 + + ; Function main + %main = OpFunction %void None %12 + %13 = OpLabel + %20 = OpExtInst %void %2 DebugScope %16 + %29 = OpLoad %v3uint %gl_GlobalInvocationID + %37 = OpCompositeExtract %uint %29 0 + %39 = OpUGreaterThan %bool %37 %uint_3 + %19 = OpExtInst %void %2 DebugFunctionDefinition %16 %main + OpSelectionMerge %21 None + OpBranchConditional %39 %23 %21 + %21 = OpLabel + OpStore %entryPointParam_main %int_1 + OpReturn + %23 = OpLabel + OpStore %entryPointParam_main %int_0 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/third_party/spirv-tools/test/opt/type_manager_test.cpp b/third_party/spirv-tools/test/opt/type_manager_test.cpp index 0eca6e0652..86d6bc0645 100644 --- a/third_party/spirv-tools/test/opt/type_manager_test.cpp +++ b/third_party/spirv-tools/test/opt/type_manager_test.cpp @@ -182,6 +182,11 @@ std::vector> GenerateAllTypes() { // SPV_AMDX_shader_enqueue types.emplace_back(new NodePayloadArrayAMDX(sts32f32)); + // Tensors + types.emplace_back(new TensorARM(f32)); + types.emplace_back(new TensorARM(f32, 4)); + types.emplace_back(new TensorARM(f32, 4, 44)); + types.emplace_back(new TensorLayoutNV(1002, 1000)); types.emplace_back(new TensorViewNV(1002, 1003, {1000, 1001})); @@ -251,6 +256,11 @@ TEST(TypeManager, TypeStrings) { %id2 = OpConstant %u32 2 %cmkhr = OpTypeCooperativeMatrixKHR %f64 %id4 %id4 %id4 %id2 %untyped = OpTypeUntypedPointerKHR Uniform + ; ID 43 + %ts_shape = OpConstantComposite %a5u32 %id4 %id4 %id4 %id4 + %ts = OpTypeTensorARM %u32 + %tsr = OpTypeTensorARM %u32 %id4 + %tss = OpTypeTensorARM %u32 %id4 %ts_shape )"; std::vector> type_id_strs = { @@ -291,6 +301,10 @@ TEST(TypeManager, TypeStrings) { {39, ""}, {41, ""}, {42, "untyped_ptr 2*"}, // Include storage class number + // Id 43 is OpConstantComposite %a5u32 %id4 %id4 %id4 %id4 + {44, "tensor"}, + {45, "tensor"}, + {46, "tensor"}, }; std::unique_ptr context = @@ -1049,8 +1063,11 @@ TEST(TypeManager, GetTypeInstructionAllTypes) { ; CHECK: [[uniform_ptr:%\w+]] = OpTypePointer Uniform [[uint]] ; CHECK: [[uint2:%\w+]] = OpConstant [[uint]] 2 ; CHECK: [[uint8:%\w+]] = OpConstant [[uint]] 8 +; CHECK: [[uint4:%\w+]] = OpConstant [[uint]] 4 +; CHECK: [[uint_arr4:%\w+]] = OpTypeArray [[uint]] [[uint4]] ; CHECK: [[uint24:%\w+]] = OpConstant [[uint]] 24 ; CHECK: [[uint42:%\w+]] = OpConstant [[uint]] 42 +; CHECK: [[uint_arr4_44:%\w+]] = OpConstantComposite [[uint_arr4]] [[uint4]] [[uint4]] [[uint4]] [[uint4]] ; CHECK: [[uint100:%\w+]] = OpConstant [[uint]] 100 ; CHECK: [[void:%\w+]] = OpTypeVoid ; CHECK: [[bool:%\w+]] = OpTypeBool @@ -1107,6 +1124,9 @@ TEST(TypeManager, GetTypeInstructionAllTypes) { ; CHECK: OpTypeCooperativeMatrixKHR [[f32]] [[uint8]] [[uint8]] [[uint8]] [[uint2]] ; CHECK: OpTypeRayQueryKHR ; CHECK: OpTypeHitObjectNV +; CHECK: OpTypeTensorARM [[f32]] +; CHECK: OpTypeTensorARM [[f32]] [[uint4]] +; CHECK: OpTypeTensorARM [[f32]] [[uint4]] [[uint_arr4_44]] OpCapability Shader OpCapability Int64 OpCapability Linkage @@ -1118,8 +1138,11 @@ OpMemoryModel Logical GLSL450 %1001 = OpConstant %uint 1 %1002 = OpConstant %uint 2 %8 = OpConstant %uint 8 +%4 = OpConstant %uint 4 +%5 = OpTypeArray %uint %4 %24 = OpConstant %uint 24 %42 = OpConstant %uint 42 +%44 = OpConstantComposite %5 %4 %4 %4 %4 %100 = OpConstant %uint 100 %1003 = OpConstantFalse %bool )"; @@ -1248,6 +1271,35 @@ TEST(TypeManager, CircularPointerToStruct) { EXPECT_EQ(id, 1201); } +TEST(TypeManager, AttachLinkageDecoration) { + const std::string text = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + OpDecorate %1000 LinkageAttributes "_1000" Export + %800 = OpTypeInt 32 0 + %1000 = OpTypeStruct %800 + %1200 = OpTypeStruct %800 + )"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_5, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + TypeManager manager(nullptr, context.get()); + + constexpr uint32_t source_id = 1000u; + constexpr uint32_t target_id = 1200u; + std::vector decorations = + context->get_decoration_mgr()->GetDecorationsFor(source_id, true); + Type* type = context->get_type_mgr()->GetType(target_id); + for (auto dec : decorations) { + manager.AttachDecoration(*dec, type); + } + EXPECT_FALSE(type->decoration_empty()); + EXPECT_TRUE( + type->HasSameDecorations(context->get_type_mgr()->GetType(source_id))); +} + } // namespace } // namespace analysis } // namespace opt diff --git a/third_party/spirv-tools/test/text_to_binary.extension_test.cpp b/third_party/spirv-tools/test/text_to_binary.extension_test.cpp index 65079d1bf8..39accfc10f 100644 --- a/third_party/spirv-tools/test/text_to_binary.extension_test.cpp +++ b/third_party/spirv-tools/test/text_to_binary.extension_test.cpp @@ -1495,5 +1495,78 @@ INSTANTIATE_TEST_SUITE_P( SaturatedToLargestFloat8NormalConversionEXT)})}, }))); +// SPV_INTEL_function_variants +// https://github.com/intel/llvm/blob/sycl/sycl/doc/design/spirv-extensions/SPV_INTEL_function_variants.asciidoc +INSTANTIATE_TEST_SUITE_P( + SPV_INTEL_function_variants, ExtensionRoundTripTest, + Combine( + Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_6), + ValuesIn(std::vector{ + {"OpExtension \"SPV_INTEL_function_variants\"\n", + MakeInstruction(spv::Op::OpExtension, + MakeVector("SPV_INTEL_function_variants"))}, + {"OpCapability SpecConditionalINTEL\n", + MakeInstruction( + spv::Op::OpCapability, + {(uint32_t)spv::Capability::SpecConditionalINTEL})}, + {"OpCapability FunctionVariantsINTEL\n", + MakeInstruction( + spv::Op::OpCapability, + {(uint32_t)spv::Capability::FunctionVariantsINTEL})}, + {"OpDecorate %1 ConditionalINTEL %2\n", + MakeInstruction(spv::Op::OpDecorate, + {1, (uint32_t)spv::Decoration::ConditionalINTEL, + 2})}, + + {"OpConditionalExtensionINTEL %1 \"foo\"\n", + MakeInstruction(spv::Op::OpConditionalExtensionINTEL, {1}, + MakeVector("foo"))}, + + {"OpConditionalEntryPointINTEL %1 Kernel %2 \"foo\"\n", + MakeInstruction(spv::Op::OpConditionalEntryPointINTEL, + {1, (uint32_t)spv::ExecutionModel::Kernel, 2}, + MakeVector("foo"))}, + + {"OpConditionalCapabilityINTEL %1 Kernel\n", + MakeInstruction(spv::Op::OpConditionalCapabilityINTEL, + {1, (uint32_t)spv::ExecutionModel::Kernel})}, + + {"%2 = OpSpecConstantTargetINTEL %1 42\n", + MakeInstruction(spv::Op::OpSpecConstantTargetINTEL, {1, 2, 42})}, + + {"%2 = OpSpecConstantTargetINTEL %1 42 99\n", + MakeInstruction(spv::Op::OpSpecConstantTargetINTEL, + {1, 2, 42, 99})}, + + {"%2 = OpSpecConstantTargetINTEL %1 42 99 108\n", + MakeInstruction(spv::Op::OpSpecConstantTargetINTEL, + {1, 2, 42, 99, 108})}, + + {"%2 = OpSpecConstantArchitectureINTEL %1 42 99 108 72\n", + MakeInstruction(spv::Op::OpSpecConstantArchitectureINTEL, + {1, 2, 42, 99, 108, 72})}, + + {"%2 = OpSpecConstantCapabilitiesINTEL %1\n", + MakeInstruction(spv::Op::OpSpecConstantCapabilitiesINTEL, {1, 2})}, + + {"%2 = OpSpecConstantCapabilitiesINTEL %1 Kernel\n", + MakeInstruction(spv::Op::OpSpecConstantCapabilitiesINTEL, + {1, 2, (uint32_t)spv::Capability::Kernel})}, + + {"%2 = OpSpecConstantCapabilitiesINTEL %1 Kernel Shader\n", + MakeInstruction(spv::Op::OpSpecConstantCapabilitiesINTEL, + {1, 2, (uint32_t)spv::Capability::Kernel, + (uint32_t)spv::Capability::Shader})}, + + {"%2 = OpConditionalCopyObjectINTEL %1 %3 %4\n", + MakeInstruction(spv::Op::OpConditionalCopyObjectINTEL, + {1, 2, 3, 4})}, + + {"%2 = OpConditionalCopyObjectINTEL %1 %3 %4 %5 %6\n", + MakeInstruction(spv::Op::OpConditionalCopyObjectINTEL, + {1, 2, 3, 4, 5, 6})}, + + }))); + } // namespace } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_builtins_test.cpp b/third_party/spirv-tools/test/val/val_builtins_test.cpp index c194128cdf..1e5a948f1c 100644 --- a/third_party/spirv-tools/test/val/val_builtins_test.cpp +++ b/third_party/spirv-tools/test/val/val_builtins_test.cpp @@ -6516,6 +6516,40 @@ TEST_F(ValidateBuiltIns, BadVulkanBuiltinViewportIndexAsArrayOfIntSizeMeshEXT) { AnyVUID("VUID-ViewportIndex-ViewportIndex-10602")); } +TEST_F(ValidateBuiltIns, BadVulkanBuiltinPrimitiveIdFragmentWithRayTracing) { + const std::string text = R"( + OpCapability Shader + OpCapability RayTracingKHR + OpExtension "SPV_KHR_ray_tracing" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %outVar %gl_PrimitiveID + OpExecutionMode %main OriginUpperLeft + OpDecorate %outVar Location 0 + OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId + OpDecorate %gl_PrimitiveID Flat + %void = OpTypeVoid + %4 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %v4int = OpTypeVector %int 4 +%ptrOut = OpTypePointer Output %v4int +%outVar = OpVariable %ptrOut Output + %ptrIn = OpTypePointer Input %int +%gl_PrimitiveID = OpVariable %ptrIn Input + %main = OpFunction %void None %4 + %6 = OpLabel + %13 = OpLoad %int %gl_PrimitiveID + %14 = OpCompositeConstruct %v4int %13 %13 %13 %13 + OpStore %outVar %14 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-PrimitiveId-PrimitiveId-04333")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/third_party/spirv-tools/test/val/val_decoration_test.cpp b/third_party/spirv-tools/test/val/val_decoration_test.cpp index 087d416557..7a19df616a 100644 --- a/third_party/spirv-tools/test/val/val_decoration_test.cpp +++ b/third_party/spirv-tools/test/val/val_decoration_test.cpp @@ -6595,12 +6595,14 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); } -// NonWritable +// NonReadable/NonWritable // Returns a SPIR-V shader module with variables in various storage classes, -// parameterizable by which ID should be decorated as NonWritable. -std::string ShaderWithNonWritableTarget(const std::string& target, - bool member_decorate = false) { +// parameterizable by which ID should be decorated as NonReadable or +// NonWritable. +std::string ShaderWithNonReadableNonWritableTarget( + const std::string& target, bool member_decorate = false, + const std::string& decoration = "NonWritable") { const std::string decoration_inst = std::string(member_decorate ? "OpMemberDecorate " : "OpDecorate ") + target + (member_decorate ? " 0" : ""); @@ -6608,8 +6610,10 @@ std::string ShaderWithNonWritableTarget(const std::string& target, return std::string(R"( OpCapability Shader OpCapability RuntimeDescriptorArrayEXT + OpCapability TensorsARM OpExtension "SPV_EXT_descriptor_indexing" OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_ARM_tensors" OpMemoryModel Logical GLSL450 OpEntryPoint Vertex %main "main" OpName %label "label" @@ -6629,9 +6633,9 @@ std::string ShaderWithNonWritableTarget(const std::string& target, OpMemberDecorate %struct_b_rtarr 0 Offset 0 OpDecorate %rtarr ArrayStride 4 )") + decoration_inst + + " " + decoration + - R"( NonWritable - + R"( %void = OpTypeVoid %void_fn = OpTypeFunction %void %float = OpTypeFloat 32 @@ -6646,6 +6650,8 @@ std::string ShaderWithNonWritableTarget(const std::string& target, %imstor = OpTypeImage %float 2D 0 0 0 2 R32f ; sampled image %imsam = OpTypeImage %float 2D 0 0 0 1 R32f + ; tensor + %tensor = OpTypeTensorARM %float %int_2 %array_imstor = OpTypeArray %imstor %int_2 %rta_imstor = OpTypeRuntimeArray %imstor @@ -6659,6 +6665,7 @@ std::string ShaderWithNonWritableTarget(const std::string& target, %_ptr_imsam = OpTypePointer UniformConstant %imsam %_ptr_array_imstor = OpTypePointer UniformConstant %array_imstor %_ptr_rta_imstor = OpTypePointer UniformConstant %rta_imstor +%_ptr_tensor_UniformConstant = OpTypePointer UniformConstant %tensor %extra_fn = OpTypeFunction %void %float %_ptr_Private %_ptr_imstor @@ -6671,6 +6678,7 @@ std::string ShaderWithNonWritableTarget(const std::string& target, %var_imsam = OpVariable %_ptr_imsam UniformConstant %var_array_imstor = OpVariable %_ptr_array_imstor UniformConstant %var_rta_imstor = OpVariable %_ptr_rta_imstor UniformConstant +%var_tensor = OpVariable %_ptr_tensor_UniformConstant UniformConstant %helper = OpFunction %void None %extra_fn %param_f = OpFunctionParameter %float @@ -6690,7 +6698,7 @@ std::string ShaderWithNonWritableTarget(const std::string& target, } TEST_F(ValidateDecorations, NonWritableLabelTargetBad) { - std::string spirv = ShaderWithNonWritableTarget("%label"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%label"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); @@ -6699,7 +6707,7 @@ TEST_F(ValidateDecorations, NonWritableLabelTargetBad) { } TEST_F(ValidateDecorations, NonWritableTypeTargetBad) { - std::string spirv = ShaderWithNonWritableTarget("%void"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%void"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); @@ -6708,7 +6716,7 @@ TEST_F(ValidateDecorations, NonWritableTypeTargetBad) { } TEST_F(ValidateDecorations, NonWritableValueTargetBad) { - std::string spirv = ShaderWithNonWritableTarget("%float_0"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%float_0"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); @@ -6717,7 +6725,7 @@ TEST_F(ValidateDecorations, NonWritableValueTargetBad) { } TEST_F(ValidateDecorations, NonWritableValueParamBad) { - std::string spirv = ShaderWithNonWritableTarget("%param_f"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%param_f"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); @@ -6725,7 +6733,7 @@ TEST_F(ValidateDecorations, NonWritableValueParamBad) { } TEST_F(ValidateDecorations, NonWritablePointerParamButWrongTypeBad) { - std::string spirv = ShaderWithNonWritableTarget("%param_p"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%param_p"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); @@ -6733,12 +6741,13 @@ TEST_F(ValidateDecorations, NonWritablePointerParamButWrongTypeBad) { getDiagnosticString(), HasSubstr( "Target of NonWritable decoration is invalid: must " - "point to a storage image, uniform block, or storage " + "point to a storage image, tensor variable in UniformConstant " + "storage class, uniform block, or storage " "buffer\n %param_p = OpFunctionParameter %_ptr_Private_float")); } TEST_F(ValidateDecorations, NonWritablePointerParamStorageImageGood) { - std::string spirv = ShaderWithNonWritableTarget("%param_pimstor"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%param_pimstor"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); @@ -6746,7 +6755,7 @@ TEST_F(ValidateDecorations, NonWritablePointerParamStorageImageGood) { } TEST_F(ValidateDecorations, NonWritableVarStorageImageGood) { - std::string spirv = ShaderWithNonWritableTarget("%var_imstor"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_imstor"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); @@ -6754,18 +6763,20 @@ TEST_F(ValidateDecorations, NonWritableVarStorageImageGood) { } TEST_F(ValidateDecorations, NonWritableVarSampledImageBad) { - std::string spirv = ShaderWithNonWritableTarget("%var_imsam"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_imsam"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of NonWritable decoration is invalid: must " - "point to a storage image, uniform block, or storage " - "buffer\n %var_imsam")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, tensor variable in UniformConstant " + "storage class, uniform block, or storage " + "buffer\n %var_imsam")); } TEST_F(ValidateDecorations, NonWritableVarUboGood) { - std::string spirv = ShaderWithNonWritableTarget("%var_ubo"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_ubo"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); @@ -6798,7 +6809,7 @@ OpFunctionEnd } TEST_F(ValidateDecorations, NonWritableVarSsboInStorageBufferGood) { - std::string spirv = ShaderWithNonWritableTarget("%var_ssbo_sb"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_ssbo_sb"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); @@ -6806,7 +6817,8 @@ TEST_F(ValidateDecorations, NonWritableVarSsboInStorageBufferGood) { } TEST_F(ValidateDecorations, NonWritableMemberOfSsboInStorageBufferGood) { - std::string spirv = ShaderWithNonWritableTarget("%struct_b_rtarr", true); + std::string spirv = + ShaderWithNonReadableNonWritableTarget("%struct_b_rtarr", true); CompileSuccessfully(spirv); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); @@ -6814,59 +6826,99 @@ TEST_F(ValidateDecorations, NonWritableMemberOfSsboInStorageBufferGood) { } TEST_F(ValidateDecorations, NonWritableMemberOfStructGood) { - std::string spirv = ShaderWithNonWritableTarget("%simple_struct", true); + std::string spirv = + ShaderWithNonReadableNonWritableTarget("%simple_struct", true); CompileSuccessfully(spirv); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateDecorations, NonWritableTensorVarUniformConstantGood) { + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_tensor"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NonReadableTensorVarUniformConstantGood) { + std::string spirv = ShaderWithNonReadableNonWritableTarget( + "%var_tensor", false, "NonReadable"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + TEST_F(ValidateDecorations, NonWritableVarWorkgroupBad) { - std::string spirv = ShaderWithNonWritableTarget("%var_wg"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_wg"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of NonWritable decoration is invalid: must " - "point to a storage image, uniform block, or storage " - "buffer\n %var_wg")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, tensor variable in UniformConstant " + "storage class, uniform block, or storage " + "buffer\n %var_wg")); +} + +TEST_F(ValidateDecorations, NonReadableVarWorkgroupBad) { + std::string spirv = + ShaderWithNonReadableNonWritableTarget("%var_wg", false, "NonReadable"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Target of NonReadable decoration is invalid: must " + "point to a storage image, tensor variable in UniformConstant " + "storage class, uniform block, or storage " + "buffer\n %var_wg")); } TEST_F(ValidateDecorations, NonWritableVarWorkgroupV14Bad) { - std::string spirv = ShaderWithNonWritableTarget("%var_wg"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_wg"); CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of NonWritable decoration is invalid: must " - "point to a storage image, uniform block, storage " - "buffer, or variable in Private or Function storage " - "class\n %var_wg")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, tensor variable in UniformConstant " + "storage class, uniform block, storage " + "buffer, or variable in Private or Function storage class\n " + "%var_wg")); } TEST_F(ValidateDecorations, NonWritableVarPrivateBad) { - std::string spirv = ShaderWithNonWritableTarget("%var_priv"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_priv"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of NonWritable decoration is invalid: must " - "point to a storage image, uniform block, or storage " - "buffer\n %var_priv")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, tensor variable in UniformConstant " + "storage class, uniform block, or storage " + "buffer\n %var_priv")); } TEST_F(ValidateDecorations, NonWritableVarPrivateV13Bad) { - std::string spirv = ShaderWithNonWritableTarget("%var_priv"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_priv"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of NonWritable decoration is invalid: must " - "point to a storage image, uniform block, or storage " - "buffer\n %var_priv")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, tensor variable in UniformConstant " + "storage class, uniform block, or storage " + "buffer\n %var_priv")); } TEST_F(ValidateDecorations, NonWritableVarPrivateV14Good) { - std::string spirv = ShaderWithNonWritableTarget("%var_priv"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_priv"); CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); @@ -6874,36 +6926,41 @@ TEST_F(ValidateDecorations, NonWritableVarPrivateV14Good) { } TEST_F(ValidateDecorations, NonWritableVarPrivateV13TargetV14Bad) { - std::string spirv = ShaderWithNonWritableTarget("%var_priv"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_priv"); CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of NonWritable decoration is invalid: must " - "point to a storage image, uniform block, or storage " - "buffer\n %var_priv")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, tensor variable in UniformConstant " + "storage class, uniform block, or storage " + "buffer\n %var_priv")); } TEST_F(ValidateDecorations, NonWritableVarFunctionBad) { - std::string spirv = ShaderWithNonWritableTarget("%var_func"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_func"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of NonWritable decoration is invalid: must " - "point to a storage image, uniform block, or storage " - "buffer\n %var_func")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, tensor variable in UniformConstant " + "storage class, uniform block, or storage " + "buffer\n %var_func")); } TEST_F(ValidateDecorations, NonWritableArrayGood) { - std::string spirv = ShaderWithNonWritableTarget("%var_array_imstor"); + std::string spirv = + ShaderWithNonReadableNonWritableTarget("%var_array_imstor"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateDecorations, NonWritableRuntimeArrayGood) { - std::string spirv = ShaderWithNonWritableTarget("%var_rta_imstor"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_rta_imstor"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); @@ -6944,18 +7001,20 @@ INSTANTIATE_TEST_SUITE_P( "is not valid for the Vulkan execution environment.")))); TEST_F(ValidateDecorations, NonWritableVarFunctionV13Bad) { - std::string spirv = ShaderWithNonWritableTarget("%var_func"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_func"); CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of NonWritable decoration is invalid: must " - "point to a storage image, uniform block, or storage " - "buffer\n %var_func")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, tensor variable in UniformConstant " + "storage class, uniform block, or storage " + "buffer\n %var_func")); } TEST_F(ValidateDecorations, NonWritableVarFunctionV14Good) { - std::string spirv = ShaderWithNonWritableTarget("%var_func"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_func"); CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); @@ -6963,14 +7022,16 @@ TEST_F(ValidateDecorations, NonWritableVarFunctionV14Good) { } TEST_F(ValidateDecorations, NonWritableVarFunctionV13TargetV14Bad) { - std::string spirv = ShaderWithNonWritableTarget("%var_func"); + std::string spirv = ShaderWithNonReadableNonWritableTarget("%var_func"); CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Target of NonWritable decoration is invalid: must " - "point to a storage image, uniform block, or storage " - "buffer\n %var_func")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Target of NonWritable decoration is invalid: must " + "point to a storage image, tensor variable in UniformConstant " + "storage class, uniform block, or storage " + "buffer\n %var_func")); } TEST_F(ValidateDecorations, BufferBlockV13ValV14Good) { diff --git a/third_party/spirv-tools/test/val/val_tensor_test.cpp b/third_party/spirv-tools/test/val/val_tensor_test.cpp index a7d1a45067..19eec4e674 100644 --- a/third_party/spirv-tools/test/val/val_tensor_test.cpp +++ b/third_party/spirv-tools/test/val/val_tensor_test.cpp @@ -71,11 +71,14 @@ std::string GenerateModule(const std::string& body) { %uint_var_1 = OpVariable %uint_ptr_Private Private %uint_1 %var_uint_arr4_1_1_1_1 = OpVariable %uint_arr4_ptr_Private Private %uint_arr4_1_1_1_1 %tensor_uint_4 = OpTypeTensorARM %uint %uint_4 + %tensor_uint_spec = OpTypeTensorARM %uint %uint_0_spec %tensor_float = OpTypeTensorARM %float %tensor_uint_4_ptr_UniformConstant = OpTypePointer UniformConstant %tensor_uint_4 %tensor_var = OpVariable %tensor_uint_4_ptr_UniformConstant UniformConstant %tensor_float_ptr_UniformConstant = OpTypePointer UniformConstant %tensor_float %tensor_var_float_unranked = OpVariable %tensor_float_ptr_UniformConstant UniformConstant +%tensor_uint_spec_ptr_UniformConstant = OpTypePointer UniformConstant %tensor_uint_spec +%tensor_var_spec_rank = OpVariable %tensor_uint_spec_ptr_UniformConstant UniformConstant )"; const std::string footer = R"( %fnep = OpFunction %void None %fnty @@ -135,7 +138,8 @@ TEST_F(ValidateTensor, ValidTypeElementTypeAndRank) { TEST_F(ValidateTensor, ValidTypeElementTypeAndRankUsingSpecConstant) { const std::string src = R"( - %test_type = OpTypeTensorARM %uint %uint_0_spec + %rank_spec = OpSpecConstant %uint 0 + %test_type = OpTypeTensorARM %uint %rank_spec )"; std::string spvasm = GenerateModule(src); CompileSuccessfully(spvasm, SPVENV); @@ -563,6 +567,20 @@ TEST_F(ValidateTensor, ValidTensorReadArray) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV)); } +TEST_F(ValidateTensor, ValidTensorReadSpecConstantRank) { + const std::string src = R"( + %fn = OpFunction %void None %fnty + %label1 = OpLabel + %tensor = OpLoad %tensor_uint_spec %tensor_var_spec_rank + %val = OpTensorReadARM %uint %tensor %uint_arr4_1_1_1_1 + OpReturn + OpFunctionEnd +)"; + std::string spvasm = GenerateModule(src); + CompileSuccessfully(spvasm, SPVENV); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV)); +} + TEST_F(ValidateTensor, InvalidTensorReadResultTypeVoid) { const std::string src = R"( %fn = OpFunction %void None %fnty @@ -840,6 +858,20 @@ TEST_F(ValidateTensor, ValidTensorWriteArray) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV)); } +TEST_F(ValidateTensor, ValidTensorWriteSpecConstantRank) { + const std::string src = R"( + %fn = OpFunction %void None %fnty + %label1 = OpLabel + %tensor = OpLoad %tensor_uint_spec %tensor_var_spec_rank + OpTensorWriteARM %tensor %uint_arr4_1_1_1_1 %uint_1 + OpReturn + OpFunctionEnd +)"; + std::string spvasm = GenerateModule(src); + CompileSuccessfully(spvasm, SPVENV); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPVENV)); +} + TEST_F(ValidateTensor, InvalidTensorWriteObjectNotScalarOrArrayOfScalar) { const std::string src = R"( %fn = OpFunction %void None %fnty @@ -1069,12 +1101,9 @@ TEST_F(ValidateTensor, ValidTensorQuerySize) { TEST_F(ValidateTensor, ValidTensorQuerySizeSpecConstant) { const std::string src = R"( -%tensor_uint_4_spec = OpTypeTensorARM %uint %uint_0_spec -%tensor_uint_4_spec_ptr_UniformConstant = OpTypePointer UniformConstant %tensor_uint_4_spec -%tensor_var_spec = OpVariable %tensor_uint_4_spec_ptr_UniformConstant UniformConstant %fn = OpFunction %void None %fnty %label1 = OpLabel - %tensor = OpLoad %tensor_uint_4_spec %tensor_var_spec + %tensor = OpLoad %tensor_uint_spec %tensor_var_spec_rank %size = OpTensorQuerySizeARM %uint %tensor %uint_0_spec OpReturn OpFunctionEnd diff --git a/third_party/spirv-tools/tools/as/as.cpp b/third_party/spirv-tools/tools/as/as.cpp index 8e821701de..f857bac566 100644 --- a/third_party/spirv-tools/tools/as/as.cpp +++ b/third_party/spirv-tools/tools/as/as.cpp @@ -28,8 +28,10 @@ static const std::string kHelpText = Usage: %s [options] [] -The SPIR-V assembly text is read from . If no file is specified, -or if the filename is "-", then the assembly text is read from standard input. +The SPIR-V assembly text is read from . +Use "-" as the filename to read from standard input. +Use "./-" to read from the file named "-". + The SPIR-V binary module is written to file "out.spv", unless the -o option is used. diff --git a/third_party/spirv-tools/utils/ggt.py b/third_party/spirv-tools/utils/ggt.py index 258c1b002f..45262ba89c 100755 --- a/third_party/spirv-tools/utils/ggt.py +++ b/third_party/spirv-tools/utils/ggt.py @@ -242,7 +242,8 @@ class Grammar(): 'MatrixMultiplyAccumulateOperands', 'RawAccessChainOperands', 'FPEncoding', - 'TensorOperands'] + 'TensorOperands', + 'Capability'] def dump(self) -> None: self.context.dump()